mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-22 08:51:21 +00:00
proc bodies can be expressions with a type
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -46,7 +46,7 @@ type
|
||||
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
||||
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
|
||||
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
|
||||
nnkIncludeStmt, nnkBindStmt,
|
||||
nnkIncludeStmt, nnkBindStmt, nnkMixinStmt,
|
||||
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
||||
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
||||
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
||||
|
||||
@@ -13,8 +13,11 @@ type
|
||||
valueC,
|
||||
valueD = (4, "abc")
|
||||
|
||||
# test the new "proc body can be an expr" feature:
|
||||
proc getValue: TMyEnum = valueD
|
||||
|
||||
# trick the optimizer with a variable:
|
||||
var x = valueD
|
||||
var x = getValue()
|
||||
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
|
||||
=============
|
||||
|
||||
- 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'
|
||||
- optimize genericAssign in the code generator
|
||||
|
||||
@@ -173,4 +178,6 @@ Version 2 and beyond
|
||||
|
||||
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.
|
||||
- Enums can be annotated with ``pure`` so that their field names do not pollute
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user