proc bodies can be expressions with a type

This commit is contained in:
Araq 2012-09-22 22:43:36 +02:00
commit 759b3201ad
12 changed files with 75 additions and 13 deletions

View file

@ -176,6 +176,7 @@ type
nkFromStmt, # a from * import statement
nkIncludeStmt, # an include statement
nkBindStmt, # a bind statement
nkMixinStmt, # a mixin statement
nkCommentStmt, # a comment statement
nkStmtListExpr, # a statement list followed by an expr; this is used
# to allow powerful multi-line templates

View file

@ -1461,8 +1461,8 @@ proc parseVariable(p: var TParser): PNode =
else: result = parseIdentColonEquals(p, {withPragma})
indAndComment(p, result) # special extension!
proc parseBind(p: var TParser): PNode =
result = newNodeP(nkBindStmt, p)
proc parseBind(p: var TParser, k: TNodeKind): PNode =
result = newNodeP(k, p)
getTok(p)
optInd(p, result)
while true:
@ -1523,7 +1523,8 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
of tkLet: result = parseSection(p, nkLetSection, parseVariable)
of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
of tkBind: result = parseBind(p)
of tkBind: result = parseBind(p, nkBindStmt)
of tkMixin: result = parseBind(p, nkMixinStmt)
else: result = simpleStmt(p)
proc parseStmt(p: var TParser): PNode =

View file

@ -386,6 +386,7 @@ proc lsub(n: PNode): int =
of nkDotExpr: result = lsons(n) + 1
of nkBind: result = lsons(n) + len("bind_")
of nkBindStmt: result = lcomma(n) + len("bind_")
of nkMixinStmt: result = lcomma(n) + len("mixin_")
of nkCheckedFieldExpr: result = lsub(n.sons[0])
of nkLambda: result = lsons(n) + len("proc__=_")
of nkDo: result = lsons(n) + len("do__:_")
@ -1152,6 +1153,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkBindStmt:
putWithSpace(g, tkBind, "bind")
gcomma(g, n, c)
of nkMixinStmt:
putWithSpace(g, tkMixin, "mixin")
gcomma(g, n, c)
of nkElifBranch:
optNL(g)
putWithSpace(g, tkElif, "elif")

View file

@ -30,6 +30,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExprNoType(c: PContext, n: PNode): PNode
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semProcBody(c: PContext, n: PNode): PNode
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode
proc changeType(n: PNode, newType: PType)

View file

@ -706,11 +706,10 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
# and check 'arg' for semantics again:
addSon(result, semExpr(c, arg))
proc semExprNoType(c: PContext, n: PNode): PNode =
proc discardCheck(result: PNode) =
proc ImplicitelyDiscardable(n: PNode): bool {.inline.} =
result = isCallExpr(n) and n.sons[0].kind == nkSym and
sfDiscardable in n.sons[0].sym.flags
result = semExpr(c, n, {efWantStmt})
if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
if result.kind == nkNilLit:
# XXX too much work and fixing would break bootstrapping:
@ -718,7 +717,11 @@ proc semExprNoType(c: PContext, n: PNode): PNode =
result.typ = nil
elif not ImplicitelyDiscardable(result) and result.typ.kind != tyError and
gCmd != cmdInteractive:
localError(n.info, errDiscardValue)
localError(result.info, errDiscardValue)
proc semExprNoType(c: PContext, n: PNode): PNode =
result = semExpr(c, n, {efWantStmt})
discardCheck(result)
proc isTypeExpr(n: PNode): bool =
case n.kind
@ -1061,11 +1064,28 @@ proc SemReturn(c: PContext, n: PNode): PNode =
addSon(a, n.sons[0])
n.sons[0] = semAsgn(c, a)
# optimize away ``result = result``:
if n[0][1].kind == nkSym and n[0][1].sym.kind == skResult:
if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym:
n.sons[0] = ast.emptyNode
else:
LocalError(n.info, errNoReturnTypeDeclared)
proc semProcBody(c: PContext, n: PNode): PNode =
openScope(c.tab)
result = semExpr(c, n)
if c.p.resultSym != nil and not isEmptyType(result.typ):
# transform ``expr`` to ``result = expr``, but not if the expr is already
# ``result``:
if result.kind == nkSym and result.sym == c.p.resultSym:
nil
else:
var a = newNodeI(nkAsgn, n.info, 2)
a.sons[0] = newSymNode(c.p.resultSym)
a.sons[1] = result
result = semAsgn(c, a)
else:
discardCheck(result)
closeScope(c.tab)
proc SemYieldVarResult(c: PContext, n: PNode, restype: PType) =
var t = skipTypes(restype, {tyGenericInst})
case t.kind

View file

@ -93,7 +93,7 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
var symMap: TIdTable
InitIdTable symMap
freshGenSyms(b, result, symMap)
b = semStmtScope(c, b)
b = semProcBody(c, b)
b = hloBody(c, b)
n.sons[bodyPos] = transformBody(c.module, b, result)
#echo "code instantiated ", result.name.s

View file

@ -767,7 +767,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
addResult(c, s.typ.sons[0], n.info, kind)
if sfImportc notin s.flags:
# no semantic checking for importc:
let semBody = hloBody(c, semStmtScope(c, n.sons[bodyPos]))
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
# unfortunately we cannot skip this step when in 'system.compiles'
# context as it may even be evaluated in 'system.compiles':
n.sons[bodyPos] = transformBody(c.module, semBody, s)

View file

@ -90,6 +90,29 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
else:
illFormedAst(a)
result = newNodeI(nkNilLit, n.info)
when false:
# not active before 0.9.0 is out
proc semMixinStmt(c: PContext, n: PNode, toMixin: var TIntSet): PNode =
for i in 0 .. < n.len:
var a = n.sons[i]
# If 'a' is an overloaded symbol, we used to use the first symbol
# as a 'witness' and use the fact that subsequent lookups will yield
# the same symbol!
# This is however not true anymore for hygienic templates as semantic
# processing for them changes the symbol table...
let s = QualifiedLookUp(c, a)
if s != nil:
# we need to mark all symbols:
let sc = symChoice(c, n, s, scForceOpen)
if sc.kind == nkSym:
toMixin.incl(sc.sym.id)
else:
for x in items(sc): toMixin.incl(x.sym.id)
else:
# do nothing: identifiers are already not bound:
nil
result = newNodeI(nkNilLit, n.info)
proc replaceIdentBySym(n: var PNode, s: PNode) =
case n.kind