'bind' as a declarative statement

This commit is contained in:
Araq 2011-10-10 02:04:15 +02:00
commit 51e01879ba
18 changed files with 204 additions and 93 deletions

View file

@ -162,6 +162,7 @@ type
nkImportStmt, # an import statement nkImportStmt, # an import statement
nkFromStmt, # a from * import statement nkFromStmt, # a from * import statement
nkIncludeStmt, # an include statement nkIncludeStmt, # an include statement
nkBindStmt, # a bind 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

View file

@ -100,10 +100,12 @@ proc OpenScope*(tab: var TSymTab)
proc RawCloseScope*(tab: var TSymTab) proc RawCloseScope*(tab: var TSymTab)
# the real "closeScope" adds some # the real "closeScope" adds some
# checks in parsobj # checks in parsobj
# these are for debugging only:
proc debug*(n: PSym) # these are for debugging only: They are not really deprecated, but I want
proc debug*(n: PType) # the warning so that release versions do not contain debugging statements:
proc debug*(n: PNode) proc debug*(n: PSym) {.deprecated.}
proc debug*(n: PType) {.deprecated.}
proc debug*(n: PNode) {.deprecated.}
# --------------------------- ident tables ---------------------------------- # --------------------------- ident tables ----------------------------------
proc IdTableGet*(t: TIdTable, key: PIdObj): PObject proc IdTableGet*(t: TIdTable, key: PIdObj): PObject

View file

@ -822,7 +822,7 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
addSon(result, arg) addSon(result, arg)
var evalTemplateCounter = 0 var evalTemplateCounter = 0
# to prevend endless recursion in templates instantation # to prevent endless recursion in templates instantation
proc evalTemplate(n: PNode, sym: PSym): PNode = proc evalTemplate(n: PNode, sym: PSym): PNode =
inc(evalTemplateCounter) inc(evalTemplateCounter)

View file

@ -239,9 +239,9 @@ const
asmStmtFrmt: "asm($1);$n", asmStmtFrmt: "asm($1);$n",
props: {hasSwitchRange, hasComputedGoto, hasCpp})] props: {hasSwitchRange, hasComputedGoto, hasCpp})]
var ccompiler*: TSystemCC = ccGcc var ccompiler*: TSystemCC = ccGcc # the used compiler
const # the used compiler const
hExt* = "h" hExt* = "h"
var cExt*: string = "c" # extension of generated C/C++ files var cExt*: string = "c" # extension of generated C/C++ files

View file

@ -212,20 +212,20 @@ proc parseSymbol(p: var TParser): PNode =
proc indexExpr(p: var TParser): PNode = proc indexExpr(p: var TParser): PNode =
result = parseExpr(p) result = parseExpr(p)
proc indexExprList(p: var TParser, first: PNode): PNode = proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
result = newNodeP(nkBracketExpr, p) endToken: TTokType): PNode =
result = newNodeP(k, p)
addSon(result, first) addSon(result, first)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while (p.tok.tokType != tkBracketRi) and (p.tok.tokType != tkEof) and while p.tok.tokType notin {endToken, tkEof, tkSad}:
(p.tok.tokType != tkSad):
var a = indexExpr(p) var a = indexExpr(p)
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
optInd(p, a) optInd(p, a)
optPar(p) optPar(p)
eat(p, tkBracketRi) eat(p, endToken)
proc exprColonEqExpr(p: var TParser, kind: TNodeKind, tok: TTokType): PNode = proc exprColonEqExpr(p: var TParser, kind: TNodeKind, tok: TTokType): PNode =
var a = parseExpr(p) var a = parseExpr(p)
@ -460,13 +460,9 @@ proc primary(p: var TParser): PNode =
addSon(result, parseSymbol(p)) addSon(result, parseSymbol(p))
result = parseGStrLit(p, result) result = parseGStrLit(p, result)
of tkBracketLe: of tkBracketLe:
result = indexExprList(p, result) result = indexExprList(p, result, nkBracketExpr, tkBracketRi)
of tkCurlyLe: of tkCurlyLe:
var a = result result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi)
result = newNodeP(nkCurlyExpr, p)
var b = setOrTableConstr(p)
result.add(a)
for i in 0 .. <b.len: result.add(b.sons[i])
else: break else: break
proc lowestExprAux(p: var TParser, limit: int): PNode = proc lowestExprAux(p: var TParser, limit: int): PNode =
@ -1291,6 +1287,18 @@ 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 =
result = newNodeP(nkBindStmt, p)
getTok(p)
optInd(p, result)
while p.tok.tokType == tkSymbol:
var a = newIdentNodeP(p.tok.ident, p)
getTok(p)
addSon(result, a)
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, a)
proc simpleStmt(p: var TParser): PNode = proc simpleStmt(p: var TParser): PNode =
case p.tok.tokType case p.tok.tokType
of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt) of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt)
@ -1329,6 +1337,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
of tkLet: result = parseSection(p, nkLetSection, parseConstant) of tkLet: result = parseSection(p, nkLetSection, parseConstant)
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)
else: result = simpleStmt(p) else: result = simpleStmt(p)
proc parseStmt(p: var TParser): PNode = proc parseStmt(p: var TParser): PNode =

View file

@ -345,6 +345,7 @@ proc lsub(n: PNode): int =
of nkTupleTy: result = lcomma(n) + len("tuple[]") of nkTupleTy: result = lcomma(n) + 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 nkCheckedFieldExpr: result = lsub(n.sons[0]) of nkCheckedFieldExpr: result = lsub(n.sons[0])
of nkLambda: result = lsons(n) + len("lambda__=_") of nkLambda: result = lsons(n) + len("lambda__=_")
of nkConstDef, nkIdentDefs: of nkConstDef, nkIdentDefs:
@ -1027,6 +1028,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
putWithSpace(g, tkColon, ":") putWithSpace(g, tkColon, ":")
gcoms(g) gcoms(g)
gstmts(g, lastSon(n), c) gstmts(g, lastSon(n), c)
of nkBindStmt:
putWithSpace(g, tkBind, "bind")
gcomma(g, n, c)
of nkElifBranch: of nkElifBranch:
optNL(g) optNL(g)
putWithSpace(g, tkElif, "elif") putWithSpace(g, tkElif, "elif")

View file

@ -1208,6 +1208,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result.kind = nkCall result.kind = nkCall
result = semExpr(c, result, flags) result = semExpr(c, result, flags)
of nkBind: of nkBind:
Message(n.info, warnDeprecated, "bind")
result = semExpr(c, n.sons[0], flags) result = semExpr(c, n.sons[0], flags)
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
# check if it is an expression macro: # check if it is an expression macro:

View file

@ -20,11 +20,13 @@ type
withinBind, withinTypeDesc withinBind, withinTypeDesc
TSemGenericFlags = set[TSemGenericFlag] TSemGenericFlags = set[TSemGenericFlag]
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags): PNode proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
toBind: var TIntSet): PNode
proc semGenericStmtScope(c: PContext, n: PNode, proc semGenericStmtScope(c: PContext, n: PNode,
flags: TSemGenericFlags): PNode = flags: TSemGenericFlags,
toBind: var TIntSet): PNode =
openScope(c.tab) openScope(c.tab)
result = semGenericStmt(c, n, flags) result = semGenericStmt(c, n, flags, toBind)
closeScope(c.tab) closeScope(c.tab)
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode = proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
@ -60,7 +62,7 @@ proc getIdentNode(n: PNode): PNode =
result = n result = n
proc semGenericStmt(c: PContext, n: PNode, proc semGenericStmt(c: PContext, n: PNode,
flags: TSemGenericFlags): PNode = flags: TSemGenericFlags, toBind: var TIntSet): PNode =
result = n result = n
if gCmd == cmdIdeTools: suggestStmt(c, n) if gCmd == cmdIdeTools: suggestStmt(c, n)
case n.kind case n.kind
@ -71,7 +73,7 @@ proc semGenericStmt(c: PContext, n: PNode,
if withinBind in flags: if withinBind in flags:
localError(n.info, errUndeclaredIdentifier, n.ident.s) localError(n.info, errUndeclaredIdentifier, n.ident.s)
else: else:
if withinBind in flags: result = symChoice(c, n, s) if withinBind in flags or s.name.id in toBind: result = symChoice(c, n, s)
else: result = semGenericStmtSymbol(c, n, s) else: result = semGenericStmtSymbol(c, n, s)
of nkDotExpr: of nkDotExpr:
var s = QualifiedLookUp(c, n, {}) var s = QualifiedLookUp(c, n, {})
@ -80,7 +82,9 @@ proc semGenericStmt(c: PContext, n: PNode,
of nkEmpty, nkSym..nkNilLit: of nkEmpty, nkSym..nkNilLit:
nil nil
of nkBind: of nkBind:
result = semGenericStmt(c, n.sons[0], flags+{withinBind}) result = semGenericStmt(c, n.sons[0], flags+{withinBind}, toBind)
of nkBindStmt:
result = semBindStmt(c, n, toBind)
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
# check if it is an expression macro: # check if it is an expression macro:
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
@ -112,52 +116,53 @@ proc semGenericStmt(c: PContext, n: PNode,
result.sons[0] = newSymNode(s, n.sons[0].info) result.sons[0] = newSymNode(s, n.sons[0].info)
first = 1 first = 1
for i in countup(first, sonsLen(result) - 1): for i in countup(first, sonsLen(result) - 1):
result.sons[i] = semGenericStmt(c, result.sons[i], flags) result.sons[i] = semGenericStmt(c, result.sons[i], flags, toBind)
of nkMacroStmt: of nkMacroStmt:
result = semMacroStmt(c, n, false) result = semMacroStmt(c, n, false)
for i in countup(0, sonsLen(result)-1): for i in countup(0, sonsLen(result)-1):
result.sons[i] = semGenericStmt(c, result.sons[i], flags) result.sons[i] = semGenericStmt(c, result.sons[i], flags, toBind)
of nkIfStmt: of nkIfStmt:
for i in countup(0, sonsLen(n)-1): for i in countup(0, sonsLen(n)-1):
n.sons[i] = semGenericStmtScope(c, n.sons[i], flags) n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, toBind)
of nkWhileStmt: of nkWhileStmt:
openScope(c.tab) openScope(c.tab)
for i in countup(0, sonsLen(n)-1): for i in countup(0, sonsLen(n)-1):
n.sons[i] = semGenericStmt(c, n.sons[i], flags) n.sons[i] = semGenericStmt(c, n.sons[i], flags, toBind)
closeScope(c.tab) closeScope(c.tab)
of nkCaseStmt: of nkCaseStmt:
openScope(c.tab) openScope(c.tab)
n.sons[0] = semGenericStmt(c, n.sons[0], flags) n.sons[0] = semGenericStmt(c, n.sons[0], flags, toBind)
for i in countup(1, sonsLen(n)-1):
var a = n.sons[i]
checkMinSonsLen(a, 1)
var L = sonsLen(a)
for j in countup(0, L-2): a.sons[j] = semGenericStmt(c, a.sons[j], flags)
a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags)
closeScope(c.tab)
of nkForStmt:
var L = sonsLen(n)
openScope(c.tab)
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags)
for i in countup(0, L - 3): addDecl(c, newSymS(skUnknown, n.sons[i], c))
n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags)
closeScope(c.tab)
of nkBlockStmt, nkBlockExpr, nkBlockType:
checkSonsLen(n, 2)
openScope(c.tab)
if n.sons[0].kind != nkEmpty: addDecl(c, newSymS(skUnknown, n.sons[0], c))
n.sons[1] = semGenericStmt(c, n.sons[1], flags)
closeScope(c.tab)
of nkTryStmt:
checkMinSonsLen(n, 2)
n.sons[0] = semGenericStmtScope(c, n.sons[0], flags)
for i in countup(1, sonsLen(n)-1): for i in countup(1, sonsLen(n)-1):
var a = n.sons[i] var a = n.sons[i]
checkMinSonsLen(a, 1) checkMinSonsLen(a, 1)
var L = sonsLen(a) var L = sonsLen(a)
for j in countup(0, L-2): for j in countup(0, L-2):
a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}) a.sons[j] = semGenericStmt(c, a.sons[j], flags, toBind)
a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags) a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, toBind)
closeScope(c.tab)
of nkForStmt:
var L = sonsLen(n)
openScope(c.tab)
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, toBind)
for i in countup(0, L - 3): addDecl(c, newSymS(skUnknown, n.sons[i], c))
n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, toBind)
closeScope(c.tab)
of nkBlockStmt, nkBlockExpr, nkBlockType:
checkSonsLen(n, 2)
openScope(c.tab)
if n.sons[0].kind != nkEmpty: addDecl(c, newSymS(skUnknown, n.sons[0], c))
n.sons[1] = semGenericStmt(c, n.sons[1], flags, toBind)
closeScope(c.tab)
of nkTryStmt:
checkMinSonsLen(n, 2)
n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, toBind)
for i in countup(1, sonsLen(n)-1):
var a = n.sons[i]
checkMinSonsLen(a, 1)
var L = sonsLen(a)
for j in countup(0, L-2):
a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, toBind)
a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, toBind)
of nkVarSection: of nkVarSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
@ -165,8 +170,9 @@ proc semGenericStmt(c: PContext, n: PNode,
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): IllFormedAst(a) if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): IllFormedAst(a)
checkMinSonsLen(a, 3) checkMinSonsLen(a, 3)
var L = sonsLen(a) var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}) a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags) toBind)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, toBind)
for j in countup(0, L-3): for j in countup(0, L-3):
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)) addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
of nkGenericParams: of nkGenericParams:
@ -175,7 +181,8 @@ proc semGenericStmt(c: PContext, n: PNode,
if (a.kind != nkIdentDefs): IllFormedAst(a) if (a.kind != nkIdentDefs): IllFormedAst(a)
checkMinSonsLen(a, 3) checkMinSonsLen(a, 3)
var L = sonsLen(a) var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}) a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
toBind)
# do not perform symbol lookup for default expressions # do not perform symbol lookup for default expressions
for j in countup(0, L-3): for j in countup(0, L-3):
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)) addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
@ -186,8 +193,8 @@ proc semGenericStmt(c: PContext, n: PNode,
if (a.kind != nkConstDef): IllFormedAst(a) if (a.kind != nkConstDef): IllFormedAst(a)
checkSonsLen(a, 3) checkSonsLen(a, 3)
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c)) addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}) a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, toBind)
a.sons[2] = semGenericStmt(c, a.sons[2], flags) a.sons[2] = semGenericStmt(c, a.sons[2], flags, toBind)
of nkTypeSection: of nkTypeSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
@ -202,15 +209,15 @@ proc semGenericStmt(c: PContext, n: PNode,
checkSonsLen(a, 3) checkSonsLen(a, 3)
if a.sons[1].kind != nkEmpty: if a.sons[1].kind != nkEmpty:
openScope(c.tab) openScope(c.tab)
a.sons[1] = semGenericStmt(c, a.sons[1], flags) a.sons[1] = semGenericStmt(c, a.sons[1], flags, toBind)
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}) a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind)
closeScope(c.tab) closeScope(c.tab)
else: else:
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}) a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind)
of nkEnumTy: of nkEnumTy:
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}) n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
var a: PNode var a: PNode
case n.sons[i].kind case n.sons[i].kind
@ -223,14 +230,15 @@ proc semGenericStmt(c: PContext, n: PNode,
of nkFormalParams: of nkFormalParams:
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}) n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
if (a.kind != nkIdentDefs): IllFormedAst(a) if (a.kind != nkIdentDefs): IllFormedAst(a)
checkMinSonsLen(a, 3) checkMinSonsLen(a, 3)
var L = sonsLen(a) var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}) a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags) toBind)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, toBind)
for j in countup(0, L-3): for j in countup(0, L-3):
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)) addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
@ -238,15 +246,16 @@ proc semGenericStmt(c: PContext, n: PNode,
checkSonsLen(n, codePos + 1) checkSonsLen(n, codePos + 1)
addDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c)) addDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c))
openScope(c.tab) openScope(c.tab)
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos], flags) n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
flags, toBind)
if n.sons[paramsPos].kind != nkEmpty: if n.sons[paramsPos].kind != nkEmpty:
if n.sons[paramsPos].sons[0].kind != nkEmpty: if n.sons[paramsPos].sons[0].kind != nkEmpty:
addDecl(c, newSym(skUnknown, getIdent("result"), nil)) addDecl(c, newSym(skUnknown, getIdent("result"), nil))
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags) n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, toBind)
n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags) n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, toBind)
n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], flags) n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], flags, toBind)
closeScope(c.tab) closeScope(c.tab)
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semGenericStmt(c, n.sons[i], flags) result.sons[i] = semGenericStmt(c, n.sons[i], flags, toBind)

View file

@ -701,8 +701,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
popProcCon(c) popProcCon(c)
else: else:
if s.typ.sons[0] != nil and kind != skIterator: if s.typ.sons[0] != nil and kind != skIterator:
addDecl(c, newSym(skUnknown, getIdent("result"), nil)) addDecl(c, newSym(skUnknown, getIdent"result", nil))
n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], {}) var toBind = initIntSet()
n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], {}, toBind)
fixupInstantiatedSymbols(c, s) fixupInstantiatedSymbols(c, s)
if sfImportc in s.flags: if sfImportc in s.flags:
# so we just ignore the body after semantic checking for importc: # so we just ignore the body after semantic checking for importc:

View file

@ -96,6 +96,19 @@ proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
addSon(result, newSymNode(a)) addSon(result, newSymNode(a))
a = nextOverloadIter(o, c, n) a = nextOverloadIter(o, c, n)
proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
for i in 0 .. < n.len:
var a = n.sons[i]
if a.kind == nkIdent:
var s = SymtabGet(c.Tab, a.ident)
if s != nil:
toBind.incl(s.name.id)
else:
localError(a.info, errUndeclaredIdentifier, a.ident.s)
else:
illFormedAst(a)
result = newNodeI(nkEmpty, n.info)
proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool, proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool,
toBind: var TIntSet): PNode = toBind: var TIntSet): PNode =
var s: PSym var s: PSym
@ -103,7 +116,7 @@ proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool,
of nkIdent: of nkIdent:
if not withinBind and not Contains(toBind, n.ident.id): if not withinBind and not Contains(toBind, n.ident.id):
s = SymTabLocalGet(c.Tab, n.ident) s = SymTabLocalGet(c.Tab, n.ident)
if (s != nil): if s != nil:
result = newSymNode(s) result = newSymNode(s)
result.info = n.info result.info = n.info
else: else:
@ -115,6 +128,8 @@ proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool,
result = n result = n
of nkBind: of nkBind:
result = resolveTemplateParams(c, n.sons[0], true, toBind) result = resolveTemplateParams(c, n.sons[0], true, toBind)
of nkBindStmt:
result = semBindStmt(c, n, toBind)
else: else:
result = n result = n
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):

View file

@ -33,7 +33,7 @@ primaryPrefix ::= (prefixOperator | 'bind') optInd
primarySuffix ::= '.' optInd symbol [generalizedLit] primarySuffix ::= '.' optInd symbol [generalizedLit]
| '(' optInd namedExprList optPar ')' | '(' optInd namedExprList optPar ')'
| '[' optInd [indexExpr (comma indexExpr)* [comma]] optPar ']' | '[' optInd [indexExpr (comma indexExpr)* [comma]] optPar ']'
| '{' optInd ':' | colonExprList optPar '}' | '{' optInd [indexExpr (comma indexExpr)* [comma]] optPar '}'
| pragma | pragma
primary ::= primaryPrefix* (symbol [generalizedLit] | primary ::= primaryPrefix* (symbol [generalizedLit] |
@ -98,7 +98,7 @@ complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt
| blockStmt | asmStmt | blockStmt | asmStmt
| procDecl | iteratorDecl | macroDecl | templateDecl | methodDecl | procDecl | iteratorDecl | macroDecl | templateDecl | methodDecl
| constSection | letSection | varSection | constSection | letSection | varSection
| typeSection | whenStmt | typeSection | whenStmt | bindStmt
indPush ::= IND # and push indentation onto the stack indPush ::= IND # and push indentation onto the stack
indPop ::= # pop indentation from the stack indPop ::= # pop indentation from the stack
@ -132,6 +132,7 @@ blockStmt ::= 'block' [symbol] ':' stmt
filename ::= symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT filename ::= symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
importStmt ::= 'import' filename (comma filename)* importStmt ::= 'import' filename (comma filename)*
includeStmt ::= 'include' filename (comma filename)* includeStmt ::= 'include' filename (comma filename)*
bindStmt ::= 'bind' IDENT (comma IDENT)*
fromStmt ::= 'from' filename 'import' symbol (comma symbol)* fromStmt ::= 'from' filename 'import' symbol (comma symbol)*
pragma ::= '{.' optInd (colonExpr [comma])* optPar ('.}' | '}') pragma ::= '{.' optInd (colonExpr [comma])* optPar ('.}' | '}')

View file

@ -2589,11 +2589,17 @@ Symbol binding within templates happens after template instantation:
echo genId() # Error: undeclared identifier: 'lastId' echo genId() # Error: undeclared identifier: 'lastId'
Bind statement
~~~~~~~~~~~~~~
Syntax::
bindStmt ::= 'bind' IDENT (comma IDENT)*
Exporting a template is a often a leaky abstraction. However, to compensate for Exporting a template is a often a leaky abstraction. However, to compensate for
this case, the ``bind`` operator can be used: All identifiers within a ``bind`` this case, a `bind`:idx: statement can be used: It declares all identifiers
context are bound early (i.e. when the template is parsed). that should be bound early (i.e. when the template is parsed):
The affected identifiers are then always bound early even if the other
occurences are in no ``bind`` context:
.. code-block:: nimrod .. code-block:: nimrod
# Module A # Module A
@ -2601,7 +2607,8 @@ occurences are in no ``bind`` context:
lastId = 0 lastId = 0
template genId*: expr = template genId*: expr =
inc(bind lastId) bind lastId
inc(lastId)
lastId lastId
.. code-block:: nimrod .. code-block:: nimrod
@ -2610,14 +2617,8 @@ occurences are in no ``bind`` context:
echo genId() # Works echo genId() # Works
A ``bind`` statement can also be used in generics for the same purpose.
**Style note**: For code readability, it is the best idea to use the least
powerful programming construct that still suffices. So the "check list" is:
(1) Use an ordinary proc/iterator, if possible.
(2) Else: Use a generic proc/iterator, if possible.
(3) Else: Use a template, if possible.
(4) Else: Use a macro.
Identifier construction Identifier construction
~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
@ -2740,6 +2741,14 @@ regular expressions:
return tkUnknown return tkUnknown
**Style note**: For code readability, it is the best idea to use the least
powerful programming construct that still suffices. So the "check list" is:
(1) Use an ordinary proc/iterator, if possible.
(2) Else: Use a generic proc/iterator, if possible.
(3) Else: Use a template, if possible.
(4) Else: Use a macro.
Modules Modules
------- -------

View file

@ -42,7 +42,8 @@ type
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt, nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt, nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr, nnkIncludeStmt, nnkBindStmt,
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy, nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen, nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
nnkRefTy, nnkPtrTy, nnkVarTy, nnkRefTy, nnkPtrTy, nnkVarTy,
@ -195,6 +196,7 @@ proc toLisp*(n: PNimrodNode): string {.compileTime.} =
## You can use this as a tool to explore the Nimrod's abstract syntax ## You can use this as a tool to explore the Nimrod's abstract syntax
## tree and to discover what kind of nodes must be created to represent ## tree and to discover what kind of nodes must be created to represent
## a certain expression/statement ## a certain expression/statement
if n == nil: return "nil" if n == nil: return "nil"
result = $n.kind result = $n.kind

View file

@ -0,0 +1,10 @@
var
gx = 88
gy = 44
template templ*(): int =
bind gx, gy
gx + gy

View file

@ -0,0 +1,5 @@
import mtempl5
echo templ()

View file

@ -7,7 +7,6 @@ Version 0.8.14
- make threadvar efficient again on linux after testing - make threadvar efficient again on linux after testing
- test the sort implementation again - test the sort implementation again
- optional indentation for 'case' statement - optional indentation for 'case' statement
- ``bind`` as a declaration
- document & test splicing; don't forget to test negative indexes - document & test splicing; don't forget to test negative indexes
- thread local vs. global raiseHook() - thread local vs. global raiseHook()
@ -106,6 +105,39 @@ Low priority
- timeout for locks - timeout for locks
Super operators
===============
macro (pattern) [T](arg: array[T]) =
Patterns
--------
Patterns are PEGs over the Nimrod AST. Patterns consist of:
type
TPatternKind = enum
pkAny, ## any node (.)
pkNodeClass, ## set of node kinds
pkTerminal, ## 'xyz'
pkNonTerminal, ## a
pkSequence, ## a b c
pkOrderedChoice, ## a / b / c
pkGreedyRep, ## a*
## a+ --> (a a*)
pkOption, ## a?
pkAndPredicate, ## &a
pkNotPredicate, ## !a
pkCapture, ## {a}
pkBackRef, ## $i
pkSearch, ## @a
pkCapturedSearch, ## {@} a
pkRule, ## a <- b
pkGrammar, ## list of rules
Version 2 Version 2
========= =========

View file

@ -38,6 +38,7 @@ Changes affecting backwards compatibility
- The ``pure`` pragma for procs has been renamed to ``noStackFrame``. - The ``pure`` pragma for procs has been renamed to ``noStackFrame``.
- The threading API has been completely redesigned. - The threading API has been completely redesigned.
- The ``unidecode`` module is now thread-safe and its interface has changed. - The ``unidecode`` module is now thread-safe and its interface has changed.
- The ``bind`` expression is deprecated, use a ``bind`` declaration instead.
Language Additions Language Additions
@ -55,6 +56,8 @@ Language Additions
- There is a new user-definable syntactic construct ``a{i, ...}`` - There is a new user-definable syntactic construct ``a{i, ...}``
that has no semantics yet for built-in types and so can be overloaded to your that has no semantics yet for built-in types and so can be overloaded to your
heart's content. heart's content.
- ``bind`` (used for symbol binding in templates and generics) is now a
declarative statement.
Compiler Additions Compiler Additions

View file

@ -31,6 +31,13 @@ You have to find out for yourself. If you don't find a tongue-in-cheek
interpretation you will have to look harder. interpretation you will have to look harder.
Why yet another programming language?
-------------------------------------
Nimrod is one of the very few *programmable* strongly typed languages, and
one of the even fewer that will produce native binaries that require no
runtime or interpreter.
How is Nimrod licensed? How is Nimrod licensed?
----------------------- -----------------------