proc bodies can be expressions with a type
This commit is contained in:
parent
3ef146b0ea
commit
759b3201ad
12 changed files with 75 additions and 13 deletions
|
|
@ -176,6 +176,7 @@ type
|
||||||
nkFromStmt, # a from * import statement
|
nkFromStmt, # a from * import statement
|
||||||
nkIncludeStmt, # an include statement
|
nkIncludeStmt, # an include statement
|
||||||
nkBindStmt, # a bind statement
|
nkBindStmt, # a bind statement
|
||||||
|
nkMixinStmt, # a mixin statement
|
||||||
nkCommentStmt, # a comment statement
|
nkCommentStmt, # a comment statement
|
||||||
nkStmtListExpr, # a statement list followed by an expr; this is used
|
nkStmtListExpr, # a statement list followed by an expr; this is used
|
||||||
# to allow powerful multi-line templates
|
# to allow powerful multi-line templates
|
||||||
|
|
|
||||||
|
|
@ -1461,8 +1461,8 @@ proc parseVariable(p: var TParser): PNode =
|
||||||
else: result = parseIdentColonEquals(p, {withPragma})
|
else: result = parseIdentColonEquals(p, {withPragma})
|
||||||
indAndComment(p, result) # special extension!
|
indAndComment(p, result) # special extension!
|
||||||
|
|
||||||
proc parseBind(p: var TParser): PNode =
|
proc parseBind(p: var TParser, k: TNodeKind): PNode =
|
||||||
result = newNodeP(nkBindStmt, p)
|
result = newNodeP(k, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -1523,7 +1523,8 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
|
||||||
of tkLet: result = parseSection(p, nkLetSection, parseVariable)
|
of tkLet: result = parseSection(p, nkLetSection, parseVariable)
|
||||||
of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
|
of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
|
||||||
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
|
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)
|
else: result = simpleStmt(p)
|
||||||
|
|
||||||
proc parseStmt(p: var TParser): PNode =
|
proc parseStmt(p: var TParser): PNode =
|
||||||
|
|
|
||||||
|
|
@ -386,6 +386,7 @@ proc lsub(n: PNode): int =
|
||||||
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_")
|
||||||
|
of nkMixinStmt: result = lcomma(n) + len("mixin_")
|
||||||
of nkCheckedFieldExpr: result = lsub(n.sons[0])
|
of nkCheckedFieldExpr: result = lsub(n.sons[0])
|
||||||
of nkLambda: result = lsons(n) + len("proc__=_")
|
of nkLambda: result = lsons(n) + len("proc__=_")
|
||||||
of nkDo: result = lsons(n) + len("do__:_")
|
of nkDo: result = lsons(n) + len("do__:_")
|
||||||
|
|
@ -1152,6 +1153,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
of nkBindStmt:
|
of nkBindStmt:
|
||||||
putWithSpace(g, tkBind, "bind")
|
putWithSpace(g, tkBind, "bind")
|
||||||
gcomma(g, n, c)
|
gcomma(g, n, c)
|
||||||
|
of nkMixinStmt:
|
||||||
|
putWithSpace(g, tkMixin, "mixin")
|
||||||
|
gcomma(g, n, c)
|
||||||
of nkElifBranch:
|
of nkElifBranch:
|
||||||
optNL(g)
|
optNL(g)
|
||||||
putWithSpace(g, tkElif, "elif")
|
putWithSpace(g, tkElif, "elif")
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||||
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||||
proc semExprNoType(c: PContext, n: PNode): PNode
|
proc semExprNoType(c: PContext, n: PNode): PNode
|
||||||
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): 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 fitNode(c: PContext, formal: PType, arg: PNode): PNode
|
||||||
proc changeType(n: PNode, newType: PType)
|
proc changeType(n: PNode, newType: PType)
|
||||||
|
|
|
||||||
|
|
@ -706,11 +706,10 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
|
||||||
# and check 'arg' for semantics again:
|
# and check 'arg' for semantics again:
|
||||||
addSon(result, semExpr(c, arg))
|
addSon(result, semExpr(c, arg))
|
||||||
|
|
||||||
proc semExprNoType(c: PContext, n: PNode): PNode =
|
proc discardCheck(result: PNode) =
|
||||||
proc ImplicitelyDiscardable(n: PNode): bool {.inline.} =
|
proc ImplicitelyDiscardable(n: PNode): bool {.inline.} =
|
||||||
result = isCallExpr(n) and n.sons[0].kind == nkSym and
|
result = isCallExpr(n) and n.sons[0].kind == nkSym and
|
||||||
sfDiscardable in n.sons[0].sym.flags
|
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.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
|
||||||
if result.kind == nkNilLit:
|
if result.kind == nkNilLit:
|
||||||
# XXX too much work and fixing would break bootstrapping:
|
# XXX too much work and fixing would break bootstrapping:
|
||||||
|
|
@ -718,7 +717,11 @@ proc semExprNoType(c: PContext, n: PNode): PNode =
|
||||||
result.typ = nil
|
result.typ = nil
|
||||||
elif not ImplicitelyDiscardable(result) and result.typ.kind != tyError and
|
elif not ImplicitelyDiscardable(result) and result.typ.kind != tyError and
|
||||||
gCmd != cmdInteractive:
|
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 =
|
proc isTypeExpr(n: PNode): bool =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -1061,11 +1064,28 @@ proc SemReturn(c: PContext, n: PNode): PNode =
|
||||||
addSon(a, n.sons[0])
|
addSon(a, n.sons[0])
|
||||||
n.sons[0] = semAsgn(c, a)
|
n.sons[0] = semAsgn(c, a)
|
||||||
# optimize away ``result = result``:
|
# 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
|
n.sons[0] = ast.emptyNode
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errNoReturnTypeDeclared)
|
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) =
|
proc SemYieldVarResult(c: PContext, n: PNode, restype: PType) =
|
||||||
var t = skipTypes(restype, {tyGenericInst})
|
var t = skipTypes(restype, {tyGenericInst})
|
||||||
case t.kind
|
case t.kind
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
||||||
var symMap: TIdTable
|
var symMap: TIdTable
|
||||||
InitIdTable symMap
|
InitIdTable symMap
|
||||||
freshGenSyms(b, result, symMap)
|
freshGenSyms(b, result, symMap)
|
||||||
b = semStmtScope(c, b)
|
b = semProcBody(c, b)
|
||||||
b = hloBody(c, b)
|
b = hloBody(c, b)
|
||||||
n.sons[bodyPos] = transformBody(c.module, b, result)
|
n.sons[bodyPos] = transformBody(c.module, b, result)
|
||||||
#echo "code instantiated ", result.name.s
|
#echo "code instantiated ", result.name.s
|
||||||
|
|
|
||||||
|
|
@ -767,7 +767,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
addResult(c, s.typ.sons[0], n.info, kind)
|
addResult(c, s.typ.sons[0], n.info, kind)
|
||||||
if sfImportc notin s.flags:
|
if sfImportc notin s.flags:
|
||||||
# no semantic checking for importc:
|
# 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'
|
# unfortunately we cannot skip this step when in 'system.compiles'
|
||||||
# context as it may even be evaluated in 'system.compiles':
|
# context as it may even be evaluated in 'system.compiles':
|
||||||
n.sons[bodyPos] = transformBody(c.module, semBody, s)
|
n.sons[bodyPos] = transformBody(c.module, semBody, s)
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,29 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
|
||||||
else:
|
else:
|
||||||
illFormedAst(a)
|
illFormedAst(a)
|
||||||
result = newNodeI(nkNilLit, n.info)
|
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) =
|
proc replaceIdentBySym(n: var PNode, s: PNode) =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ type
|
||||||
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
||||||
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
|
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
|
||||||
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
|
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
|
||||||
nnkIncludeStmt, nnkBindStmt,
|
nnkIncludeStmt, nnkBindStmt, nnkMixinStmt,
|
||||||
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
||||||
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
||||||
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,11 @@ type
|
||||||
valueC,
|
valueC,
|
||||||
valueD = (4, "abc")
|
valueD = (4, "abc")
|
||||||
|
|
||||||
|
# test the new "proc body can be an expr" feature:
|
||||||
|
proc getValue: TMyEnum = valueD
|
||||||
|
|
||||||
# trick the optimizer with a variable:
|
# trick the optimizer with a variable:
|
||||||
var x = valueD
|
var x = getValue()
|
||||||
echo valueA, ord(valueA), valueB, ord(valueB), valueC, valueD, ord(valueD), x
|
echo valueA, ord(valueA), valueB, ord(valueB), valueC, valueD, ord(valueD), x
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
11
todo.txt
11
todo.txt
|
|
@ -1,8 +1,13 @@
|
||||||
version 0.9.0
|
version 0.9.0
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- make 'bind' default for templates and introduce 'mixin'
|
- fix tirc capture of 'result'
|
||||||
|
|
||||||
|
|
||||||
|
version 0.9.2
|
||||||
|
=============
|
||||||
|
|
||||||
|
- make 'bind' default for templates and introduce 'mixin'
|
||||||
- implicit deref for parameter matching; overloading based on 'var T'
|
- implicit deref for parameter matching; overloading based on 'var T'
|
||||||
- optimize genericAssign in the code generator
|
- optimize genericAssign in the code generator
|
||||||
|
|
||||||
|
|
@ -173,4 +178,6 @@ Version 2 and beyond
|
||||||
|
|
||||||
case x with `=~`
|
case x with `=~`
|
||||||
|
|
||||||
- implement ``partial`` pragma for partial evaluation
|
- implement ``partial`` pragma for partial evaluation: easily done with AST
|
||||||
|
overloading
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,8 @@ Language Additions
|
||||||
comment pieces don't have to align on the same column.
|
comment pieces don't have to align on the same column.
|
||||||
- Enums can be annotated with ``pure`` so that their field names do not pollute
|
- Enums can be annotated with ``pure`` so that their field names do not pollute
|
||||||
the current scope.
|
the current scope.
|
||||||
|
- A proc body can consist of an expression that has a type. This is rewritten
|
||||||
|
to ``result = expression`` then.
|
||||||
|
|
||||||
|
|
||||||
2012-02-09 Version 0.8.14 released
|
2012-02-09 Version 0.8.14 released
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue