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:
Andreas Rumpf 2015-03-07 17:35:14 +01:00
commit df0473d754
15 changed files with 210 additions and 18 deletions

View file

@ -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

View file

@ -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

View file

@ -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) ')'

View file

@ -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])

View file

@ -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)

View file

@ -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)

View file

@ -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:

View file

@ -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

View file

@ -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)

View file

@ -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:

View file

@ -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:

View file

@ -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)] = ']'

View file

@ -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
View 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())

View 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"