Merge pull request #2239 from Maxdamantus/devel
interpret `tuple` as a class and `tuple[]` as the empty tuple, enable syntax for anonymous tuples
This commit is contained in:
commit
df0473d754
15 changed files with 210 additions and 18 deletions
|
|
@ -196,6 +196,7 @@ type
|
||||||
nkTypeOfExpr, # type(1+2)
|
nkTypeOfExpr, # type(1+2)
|
||||||
nkObjectTy, # object body
|
nkObjectTy, # object body
|
||||||
nkTupleTy, # tuple body
|
nkTupleTy, # tuple body
|
||||||
|
nkTupleClassTy, # tuple type class
|
||||||
nkTypeClassTy, # user-defined type class
|
nkTypeClassTy, # user-defined type class
|
||||||
nkStaticTy, # ``static[T]``
|
nkStaticTy, # ``static[T]``
|
||||||
nkRecList, # list of object parts
|
nkRecList, # list of object parts
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,7 @@ proc packObject(x: PNode, typ: PType, res: pointer) =
|
||||||
let field = getField(typ.n, i)
|
let field = getField(typ.n, i)
|
||||||
pack(it, field.typ, res +! field.offset)
|
pack(it, field.typ, res +! field.offset)
|
||||||
else:
|
else:
|
||||||
|
# XXX: todo
|
||||||
globalError(x.info, "cannot pack unnamed tuple")
|
globalError(x.info, "cannot pack unnamed tuple")
|
||||||
|
|
||||||
const maxPackDepth = 20
|
const maxPackDepth = 20
|
||||||
|
|
|
||||||
|
|
@ -865,6 +865,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
||||||
#| [' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
|
#| [' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
|
||||||
#| extTupleDecl = 'tuple'
|
#| extTupleDecl = 'tuple'
|
||||||
#| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
#| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
||||||
|
#| tupleClass = 'tuple'
|
||||||
result = newNodeP(nkTupleTy, p)
|
result = newNodeP(nkTupleTy, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
if p.tok.tokType == tkBracketLe:
|
if p.tok.tokType == tkBracketLe:
|
||||||
|
|
@ -894,6 +895,8 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
||||||
parMessage(p, errIdentifierExpected, p.tok)
|
parMessage(p, errIdentifierExpected, p.tok)
|
||||||
break
|
break
|
||||||
if not sameInd(p): break
|
if not sameInd(p): break
|
||||||
|
else:
|
||||||
|
result = newNodeP(nkTupleClassTy, p)
|
||||||
|
|
||||||
proc parseParamList(p: var TParser, retColon = true): PNode =
|
proc parseParamList(p: var TParser, retColon = true): PNode =
|
||||||
#| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
#| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
||||||
|
|
|
||||||
|
|
@ -395,6 +395,7 @@ proc lsub(n: PNode): int =
|
||||||
of nkClosedSymChoice, nkOpenSymChoice:
|
of nkClosedSymChoice, nkOpenSymChoice:
|
||||||
result = lsons(n) + len("()") + sonsLen(n) - 1
|
result = lsons(n) + len("()") + sonsLen(n) - 1
|
||||||
of nkTupleTy: result = lcomma(n) + len("tuple[]")
|
of nkTupleTy: result = lcomma(n) + len("tuple[]")
|
||||||
|
of nkTupleClassTy: result = len("tuple")
|
||||||
of nkDotExpr: result = lsons(n) + 1
|
of nkDotExpr: result = lsons(n) + 1
|
||||||
of nkBind: result = lsons(n) + len("bind_")
|
of nkBind: result = lsons(n) + len("bind_")
|
||||||
of nkBindStmt: result = lcomma(n) + len("bind_")
|
of nkBindStmt: result = lcomma(n) + len("bind_")
|
||||||
|
|
@ -1292,10 +1293,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
of nkTupleTy:
|
of nkTupleTy:
|
||||||
put(g, tkTuple, "tuple")
|
put(g, tkTuple, "tuple")
|
||||||
if sonsLen(n) > 0:
|
put(g, tkBracketLe, "[")
|
||||||
put(g, tkBracketLe, "[")
|
gcomma(g, n)
|
||||||
gcomma(g, n)
|
put(g, tkBracketRi, "]")
|
||||||
put(g, tkBracketRi, "]")
|
of nkTupleClassTy:
|
||||||
|
put(g, tkTuple, "tuple")
|
||||||
of nkMetaNode_Obsolete:
|
of nkMetaNode_Obsolete:
|
||||||
put(g, tkParLe, "(META|")
|
put(g, tkParLe, "(META|")
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
|
|
|
||||||
|
|
@ -1866,6 +1866,14 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
addSonSkipIntLit(typ, n.sons[i].typ)
|
addSonSkipIntLit(typ, n.sons[i].typ)
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
|
||||||
|
proc isTupleType(n: PNode): bool =
|
||||||
|
if n.len == 0:
|
||||||
|
return false # don't interpret () as type
|
||||||
|
for i in countup(0, n.len - 1):
|
||||||
|
if n[i].typ == nil or n[i].typ.kind != tyTypeDesc:
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
|
||||||
proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
|
proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkRecList:
|
of nkRecList:
|
||||||
|
|
@ -2055,7 +2063,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkBind:
|
of nkBind:
|
||||||
message(n.info, warnDeprecated, "bind")
|
message(n.info, warnDeprecated, "bind")
|
||||||
result = semExpr(c, n.sons[0], flags)
|
result = semExpr(c, n.sons[0], flags)
|
||||||
of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy, nkStaticTy:
|
of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy:
|
||||||
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
|
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
|
||||||
result.typ = makeTypeDesc(c, typ)
|
result.typ = makeTypeDesc(c, typ)
|
||||||
#result = symNodeFromType(c, typ, n.info)
|
#result = symNodeFromType(c, typ, n.info)
|
||||||
|
|
@ -2129,7 +2137,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkPar:
|
of nkPar:
|
||||||
case checkPar(n)
|
case checkPar(n)
|
||||||
of paNone: result = errorNode(c, n)
|
of paNone: result = errorNode(c, n)
|
||||||
of paTuplePositions: result = semTuplePositionsConstr(c, n, flags)
|
of paTuplePositions:
|
||||||
|
var tupexp = semTuplePositionsConstr(c, n, flags)
|
||||||
|
if isTupleType(tupexp):
|
||||||
|
# reinterpret as type
|
||||||
|
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
|
||||||
|
result.typ = makeTypeDesc(c, typ)
|
||||||
|
else:
|
||||||
|
result = tupexp
|
||||||
of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
|
of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
|
||||||
of paSingle: result = semExpr(c, n.sons[0], flags)
|
of paSingle: result = semExpr(c, n.sons[0], flags)
|
||||||
of nkCurly: result = semSetConstr(c, n)
|
of nkCurly: result = semSetConstr(c, n)
|
||||||
|
|
|
||||||
|
|
@ -356,7 +356,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
of nkIdent: a = n.sons[i]
|
of nkIdent: a = n.sons[i]
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
||||||
of nkObjectTy, nkTupleTy:
|
of nkObjectTy, nkTupleTy, nkTupleClassTy:
|
||||||
discard
|
discard
|
||||||
of nkFormalParams:
|
of nkFormalParams:
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
|
||||||
if g.kind == skUnknown:
|
if g.kind == skUnknown:
|
||||||
var field: PSym = nil
|
var field: PSym = nil
|
||||||
var ty = n.sons[0].typ.skipTypes(abstractPtrs)
|
var ty = n.sons[0].typ.skipTypes(abstractPtrs)
|
||||||
if ty.kind == tyTuple:
|
if ty.kind == tyTuple and not ty.n.isNil:
|
||||||
field = lookupInRecord(ty.n, g.name)
|
field = lookupInRecord(ty.n, g.name)
|
||||||
else:
|
else:
|
||||||
while ty != nil and ty.kind == tyObject:
|
while ty != nil and ty.kind == tyObject:
|
||||||
|
|
|
||||||
|
|
@ -692,7 +692,7 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
|
||||||
assignType(s.typ, t)
|
assignType(s.typ, t)
|
||||||
s.typ.id = t.id # same id
|
s.typ.id = t.id # same id
|
||||||
checkConstructedType(s.info, s.typ)
|
checkConstructedType(s.info, s.typ)
|
||||||
if s.typ.kind in {tyObject, tyTuple}:
|
if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
|
||||||
checkForMetaFields(s.typ.n)
|
checkForMetaFields(s.typ.n)
|
||||||
let aa = a.sons[2]
|
let aa = a.sons[2]
|
||||||
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
|
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
|
||||||
|
|
|
||||||
|
|
@ -345,8 +345,14 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
localError(n.info, errIdentifierExpected)
|
localError(n.info, errIdentifierExpected)
|
||||||
result = errorSym(c, n)
|
result = errorSym(c, n)
|
||||||
|
|
||||||
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if n.sonsLen == 0: return newConstraint(c, tyTuple)
|
if sonsLen(n) == 0:
|
||||||
|
localError(n.info, errTypeExpected)
|
||||||
|
result = newOrPrevType(tyTuple, prev, c)
|
||||||
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
|
addSonSkipIntLit(result, semTypeNode(c, n.sons[i], nil))
|
||||||
|
|
||||||
|
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||||
var typ: PType
|
var typ: PType
|
||||||
result = newOrPrevType(tyTuple, prev, c)
|
result = newOrPrevType(tyTuple, prev, c)
|
||||||
result.n = newNodeI(nkRecList, n.info)
|
result.n = newNodeI(nkRecList, n.info)
|
||||||
|
|
@ -1117,9 +1123,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
of nkPar:
|
of nkPar:
|
||||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||||
else:
|
else:
|
||||||
# XXX support anon tuple here
|
result = semAnonTuple(c, n, prev)
|
||||||
localError(n.info, errTypeExpected)
|
|
||||||
result = newOrPrevType(tyError, prev, c)
|
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
if isRange(n):
|
if isRange(n):
|
||||||
result = semRangeAux(c, n, prev)
|
result = semRangeAux(c, n, prev)
|
||||||
|
|
@ -1227,6 +1231,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
of nkObjectTy: result = semObjectNode(c, n, prev)
|
of nkObjectTy: result = semObjectNode(c, n, prev)
|
||||||
of nkTupleTy: result = semTuple(c, n, prev)
|
of nkTupleTy: result = semTuple(c, n, prev)
|
||||||
|
of nkTupleClassTy: result = newConstraint(c, tyTuple)
|
||||||
of nkTypeClassTy: result = semTypeClass(c, n, prev)
|
of nkTypeClassTy: result = semTypeClass(c, n, prev)
|
||||||
of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
|
of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
|
||||||
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
||||||
|
|
|
||||||
|
|
@ -341,6 +341,8 @@ proc skipIntLiteralParams*(t: PType) =
|
||||||
proc propagateFieldFlags(t: PType, n: PNode) =
|
proc propagateFieldFlags(t: PType, n: PNode) =
|
||||||
# This is meant for objects and tuples
|
# This is meant for objects and tuples
|
||||||
# The type must be fully instantiated!
|
# The type must be fully instantiated!
|
||||||
|
if n.isNil:
|
||||||
|
return
|
||||||
internalAssert n.kind != nkRecWhen
|
internalAssert n.kind != nkRecWhen
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
|
|
|
||||||
|
|
@ -507,18 +507,22 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
if prefer == preferModuleInfo: preferModuleInfo else: preferName)
|
if prefer == preferModuleInfo: preferModuleInfo else: preferName)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
# we iterate over t.sons here, because t.n may be nil
|
# we iterate over t.sons here, because t.n may be nil
|
||||||
result = "tuple["
|
|
||||||
if t.n != nil:
|
if t.n != nil:
|
||||||
|
result = "tuple["
|
||||||
assert(sonsLen(t.n) == sonsLen(t))
|
assert(sonsLen(t.n) == sonsLen(t))
|
||||||
for i in countup(0, sonsLen(t.n) - 1):
|
for i in countup(0, sonsLen(t.n) - 1):
|
||||||
assert(t.n.sons[i].kind == nkSym)
|
assert(t.n.sons[i].kind == nkSym)
|
||||||
add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i]))
|
add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i]))
|
||||||
if i < sonsLen(t.n) - 1: add(result, ", ")
|
if i < sonsLen(t.n) - 1: add(result, ", ")
|
||||||
|
add(result, ']')
|
||||||
|
elif sonsLen(t) == 0:
|
||||||
|
result = "tuple[]"
|
||||||
else:
|
else:
|
||||||
|
result = "("
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
add(result, typeToString(t.sons[i]))
|
add(result, typeToString(t.sons[i]))
|
||||||
if i < sonsLen(t) - 1: add(result, ", ")
|
if i < sonsLen(t) - 1: add(result, ", ")
|
||||||
add(result, ']')
|
add(result, ')')
|
||||||
of tyPtr, tyRef, tyVar, tyMutable, tyConst:
|
of tyPtr, tyRef, tyVar, tyMutable, tyConst:
|
||||||
result = typeToStr[t.kind]
|
result = typeToStr[t.kind]
|
||||||
if t.len >= 2:
|
if t.len >= 2:
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,6 @@ proc renderType(n: PNode): string =
|
||||||
assert n[i].kind == nkIdent
|
assert n[i].kind == nkIdent
|
||||||
result.add(',' & typeStr)
|
result.add(',' & typeStr)
|
||||||
of nkTupleTy:
|
of nkTupleTy:
|
||||||
assert len(n) > 0
|
|
||||||
result = "tuple["
|
result = "tuple["
|
||||||
for i in 0 .. <len(n): result.add(renderType(n[i]) & ',')
|
for i in 0 .. <len(n): result.add(renderType(n[i]) & ',')
|
||||||
result[<len(result)] = ']'
|
result[<len(result)] = ']'
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ type
|
||||||
nnkStmtListType, nnkBlockType,
|
nnkStmtListType, nnkBlockType,
|
||||||
nnkWith, nnkWithout,
|
nnkWith, nnkWithout,
|
||||||
nnkTypeOfExpr, nnkObjectTy,
|
nnkTypeOfExpr, nnkObjectTy,
|
||||||
nnkTupleTy, nnkTypeClassTy, nnkStaticTy,
|
nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
|
||||||
nnkRecList, nnkRecCase, nnkRecWhen,
|
nnkRecList, nnkRecCase, nnkRecWhen,
|
||||||
nnkRefTy, nnkPtrTy, nnkVarTy,
|
nnkRefTy, nnkPtrTy, nnkVarTy,
|
||||||
nnkConstTy, nnkMutableTy,
|
nnkConstTy, nnkMutableTy,
|
||||||
|
|
|
||||||
105
tests/misc/parsecomb.nim
Normal file
105
tests/misc/parsecomb.nim
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
type Input[T] = object
|
||||||
|
toks: seq[T]
|
||||||
|
index: int
|
||||||
|
|
||||||
|
type
|
||||||
|
ResultKind* = enum rkSuccess, rkFailure
|
||||||
|
Result*[T, O] = object
|
||||||
|
case kind*: ResultKind
|
||||||
|
of rkSuccess:
|
||||||
|
output*: O
|
||||||
|
input: Input[T]
|
||||||
|
of rkFailure:
|
||||||
|
nil
|
||||||
|
|
||||||
|
type
|
||||||
|
Parser*[T, O] = distinct proc (input: Input[T]): Result[T, O]
|
||||||
|
|
||||||
|
proc unit*[T, O](v: O): Parser[T, O] =
|
||||||
|
Parser(proc (inp: Input[T]): Result[T, O] =
|
||||||
|
Result[T, O](kind: rkSuccess, output: v, input: inp))
|
||||||
|
|
||||||
|
proc fail*[T, O](): Parser[T, O] =
|
||||||
|
Parser(proc (inp: Input[T]): Result[T, O] =
|
||||||
|
Result(kind: rkFailure))
|
||||||
|
|
||||||
|
method runInput[T, O](self: Parser[T, O], inp: Input[T]): Result[T, O] =
|
||||||
|
# hmmm ..
|
||||||
|
type tmp = proc (input: Input[T]): Result[T, O]
|
||||||
|
# XXX: above needed for now, as without the `tmp` bit below, it compiles to invalid C.
|
||||||
|
tmp(self)(inp)
|
||||||
|
|
||||||
|
method run*[T, O](self: Parser[T, O], toks: seq[T]): Result[T, O] =
|
||||||
|
self.runInput(Input[T](toks: toks, index: 0))
|
||||||
|
|
||||||
|
method chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2]): Parser[T, O2] =
|
||||||
|
Parser(proc (inp: Input[T]): Result[T, O2] =
|
||||||
|
let r = self.runInput(inp)
|
||||||
|
case r.kind:
|
||||||
|
of rkSuccess:
|
||||||
|
nextp(r.output).runInput(r.input)
|
||||||
|
of rkFailure:
|
||||||
|
Result[T, O2](kind: rkFailure))
|
||||||
|
|
||||||
|
method skip[T](self: Input[T], n: int): Input[T] =
|
||||||
|
Input[T](toks: self.toks, index: self.index + n)
|
||||||
|
|
||||||
|
proc pskip*[T](n: int): Parser[T, tuple[]] =
|
||||||
|
Parser(proc (inp: Input[T]): Result[T, tuple[]] =
|
||||||
|
if inp.index + n <= inp.toks.len:
|
||||||
|
Result[T, tuple[]](kind: rkSuccess, output: (), input: inp.skip(n))
|
||||||
|
else:
|
||||||
|
Result[T, tuple[]](kind: rkFailure))
|
||||||
|
|
||||||
|
proc tok*[T](t: T): Parser[T, T] =
|
||||||
|
Parser(proc (inp: Input[T]): Result[T, T] =
|
||||||
|
if inp.index < inp.toks.len and inp.toks[inp.index] == t:
|
||||||
|
pskip[T](1).then(unit[T, T](t)).runInput(inp)
|
||||||
|
else:
|
||||||
|
Result[T, T](kind: rkFailure))
|
||||||
|
|
||||||
|
proc `+`*[T, O](first: Parser[T, O], second: Parser[T, O]): Parser[T, O] =
|
||||||
|
Parser(proc (inp: Input[T]): Result[T, O] =
|
||||||
|
let r = first.runInput(inp)
|
||||||
|
case r.kind
|
||||||
|
of rkSuccess:
|
||||||
|
r
|
||||||
|
else:
|
||||||
|
second.runInput(inp))
|
||||||
|
|
||||||
|
# end of primitives (definitions involving Parser(..))
|
||||||
|
|
||||||
|
method map*[T, O1, O2](self: Parser[T, O1], p: proc (v: O1): O2): Parser[T, O2] =
|
||||||
|
self.chain(proc (v: O1): Parser[T, O2] =
|
||||||
|
unit[T, O2](p(v)))
|
||||||
|
|
||||||
|
method then*[T, O1, O2](self: Parser[T, O1], next: Parser[T, O2]): Parser[T, O2] =
|
||||||
|
self.chain(proc (v: O1): Parser[T, O2] =
|
||||||
|
next)
|
||||||
|
|
||||||
|
proc `*`*[T, O1, O2](first: Parser[T, O1], second: Parser[T, O2]): Parser[T, (O1, O2)] =
|
||||||
|
first.chain(proc (v1: O1): Parser[T, (O1, O2)] =
|
||||||
|
second.map(proc (v2: O2): (O1, O2) =
|
||||||
|
(v1, v2)))
|
||||||
|
|
||||||
|
proc repeat0*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] =
|
||||||
|
var nothing = unit[T, seq[O]](@[])
|
||||||
|
inner.chain(proc(v: O): Parser[T, seq[O]] =
|
||||||
|
repeat0(inner).map(proc(vs: seq[O]): seq[O] =
|
||||||
|
@[v] & vs)) + nothing
|
||||||
|
|
||||||
|
proc repeat1*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] =
|
||||||
|
inner.chain(proc(v: O): Parser[T, seq[O]] =
|
||||||
|
repeat0(inner).map(proc(vs: seq[O]): seq[O] =
|
||||||
|
@[v] & vs))
|
||||||
|
|
||||||
|
proc leftRec*[T, O, A](inner: Parser[T, O], after: Parser[T, A], fold: proc(i: O, a: A): O): Parser[T, O] =
|
||||||
|
(inner*repeat0(after)).map(proc(ias: (O, seq[A])): O =
|
||||||
|
var (i, asx) = ias
|
||||||
|
for a in asx:
|
||||||
|
i = fold(i, a)
|
||||||
|
i)
|
||||||
|
|
||||||
|
proc lazy*[T, O](inner: proc(): Parser[T, O]): Parser[T, O] =
|
||||||
|
unit[T, tuple[]](()).chain(proc(v: tuple[]): Parser[T, O] =
|
||||||
|
inner())
|
||||||
55
tests/misc/tparsecombnum.nim
Normal file
55
tests/misc/tparsecombnum.nim
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
import parsecomb
|
||||||
|
|
||||||
|
discard """
|
||||||
|
output: "-289096"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type Num = int
|
||||||
|
|
||||||
|
# forward stuff
|
||||||
|
var exp3: Parser[string, Num]
|
||||||
|
var exp = lazy(proc(): Parser[string, Num] = exp3)
|
||||||
|
|
||||||
|
var digit = (proc(): Parser[string, Num] =
|
||||||
|
result = tok("0").then(unit[string, Num](Num(0)))
|
||||||
|
for n in 1..9:
|
||||||
|
result = result + tok($n).then(unit[string, Num](Num(n)))
|
||||||
|
)()
|
||||||
|
|
||||||
|
var num = repeat1(digit).map(proc(ds: seq[Num]): Num =
|
||||||
|
result = 0
|
||||||
|
for d in ds:
|
||||||
|
result = result*10 + d)
|
||||||
|
|
||||||
|
type Op = proc(a, b: Num): Num
|
||||||
|
|
||||||
|
var plusOp = tok("+").then(unit[string, Op](proc(a, b: Num): Num = a + b))
|
||||||
|
var minusOp = tok("-").then(unit[string, Op](proc(a, b: Num): Num = a - b))
|
||||||
|
var timesOp = tok("*").then(unit[string, Op](proc(a, b: Num): Num = a*b))
|
||||||
|
var divideOp = tok("/").then(unit[string, Op](proc(a, b: Num): Num = a div b))
|
||||||
|
|
||||||
|
var paren = (tok("(") * exp * tok(")")).map(proc(ler: ((string, Num), string)): Num =
|
||||||
|
var (le, r) = ler
|
||||||
|
var (l, e) = le
|
||||||
|
e)
|
||||||
|
|
||||||
|
proc foldOp(a: Num, ob: (Op, Num)): Num =
|
||||||
|
var (o, b) = ob
|
||||||
|
o(a, b)
|
||||||
|
|
||||||
|
var exp0 = paren + num
|
||||||
|
var exp1 = exp0.leftRec((timesOp + divideOp)*exp0, foldOp)
|
||||||
|
var exp2 = exp1.leftRec((plusOp + minusOp)*exp1, foldOp)
|
||||||
|
exp3 = exp2
|
||||||
|
|
||||||
|
proc strsplit(s: string): seq[string] =
|
||||||
|
result = @[]
|
||||||
|
for i in 0 .. s.len - 1:
|
||||||
|
result.add($s[i])
|
||||||
|
|
||||||
|
var r = exp.run("523-(1243+411/744*1642/1323)*233".strsplit)
|
||||||
|
case r.kind:
|
||||||
|
of rkSuccess:
|
||||||
|
echo r.output
|
||||||
|
of rkFailure:
|
||||||
|
echo "failed"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue