'bind' as a declarative statement

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

View File

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

View File

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

View File

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

View File

@@ -239,9 +239,9 @@ const
asmStmtFrmt: "asm($1);$n",
props: {hasSwitchRange, hasComputedGoto, hasCpp})]
var ccompiler*: TSystemCC = ccGcc
var ccompiler*: TSystemCC = ccGcc # the used compiler
const # the used compiler
const
hExt* = "h"
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 =
result = parseExpr(p)
proc indexExprList(p: var TParser, first: PNode): PNode =
result = newNodeP(nkBracketExpr, p)
proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
endToken: TTokType): PNode =
result = newNodeP(k, p)
addSon(result, first)
getTok(p)
optInd(p, result)
while (p.tok.tokType != tkBracketRi) and (p.tok.tokType != tkEof) and
(p.tok.tokType != tkSad):
while p.tok.tokType notin {endToken, tkEof, tkSad}:
var a = indexExpr(p)
addSon(result, a)
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, a)
optPar(p)
eat(p, tkBracketRi)
eat(p, endToken)
proc exprColonEqExpr(p: var TParser, kind: TNodeKind, tok: TTokType): PNode =
var a = parseExpr(p)
@@ -460,13 +460,9 @@ proc primary(p: var TParser): PNode =
addSon(result, parseSymbol(p))
result = parseGStrLit(p, result)
of tkBracketLe:
result = indexExprList(p, result)
result = indexExprList(p, result, nkBracketExpr, tkBracketRi)
of tkCurlyLe:
var a = result
result = newNodeP(nkCurlyExpr, p)
var b = setOrTableConstr(p)
result.add(a)
for i in 0 .. <b.len: result.add(b.sons[i])
result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi)
else: break
proc lowestExprAux(p: var TParser, limit: int): PNode =
@@ -1291,6 +1287,18 @@ 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)
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 =
case p.tok.tokType
of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt)
@@ -1329,6 +1337,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
of tkLet: result = parseSection(p, nkLetSection, parseConstant)
of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
of tkBind: result = parseBind(p)
else: result = simpleStmt(p)
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 nkDotExpr: result = lsons(n) + 1
of nkBind: result = lsons(n) + len("bind_")
of nkBindStmt: result = lcomma(n) + len("bind_")
of nkCheckedFieldExpr: result = lsub(n.sons[0])
of nkLambda: result = lsons(n) + len("lambda__=_")
of nkConstDef, nkIdentDefs:
@@ -1027,6 +1028,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, lastSon(n), c)
of nkBindStmt:
putWithSpace(g, tkBind, "bind")
gcomma(g, n, c)
of nkElifBranch:
optNL(g)
putWithSpace(g, tkElif, "elif")

View File

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

View File

@@ -20,11 +20,13 @@ type
withinBind, withinTypeDesc
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,
flags: TSemGenericFlags): PNode =
flags: TSemGenericFlags,
toBind: var TIntSet): PNode =
openScope(c.tab)
result = semGenericStmt(c, n, flags)
result = semGenericStmt(c, n, flags, toBind)
closeScope(c.tab)
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
@@ -60,7 +62,7 @@ proc getIdentNode(n: PNode): PNode =
result = n
proc semGenericStmt(c: PContext, n: PNode,
flags: TSemGenericFlags): PNode =
flags: TSemGenericFlags, toBind: var TIntSet): PNode =
result = n
if gCmd == cmdIdeTools: suggestStmt(c, n)
case n.kind
@@ -68,10 +70,10 @@ proc semGenericStmt(c: PContext, n: PNode,
var s = SymtabGet(c.Tab, n.ident)
if s == nil:
# no error if symbol cannot be bound, unless in ``bind`` context:
if withinBind in flags:
if withinBind in flags:
localError(n.info, errUndeclaredIdentifier, n.ident.s)
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)
of nkDotExpr:
var s = QualifiedLookUp(c, n, {})
@@ -80,7 +82,9 @@ proc semGenericStmt(c: PContext, n: PNode,
of nkEmpty, nkSym..nkNilLit:
nil
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:
# check if it is an expression macro:
checkMinSonsLen(n, 1)
@@ -112,52 +116,53 @@ proc semGenericStmt(c: PContext, n: PNode,
result.sons[0] = newSymNode(s, n.sons[0].info)
first = 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:
result = semMacroStmt(c, n, false)
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:
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:
openScope(c.tab)
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)
of nkCaseStmt:
openScope(c.tab)
n.sons[0] = semGenericStmt(c, n.sons[0], flags)
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)
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+{withinTypeDesc})
a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags)
a.sons[j] = semGenericStmt(c, a.sons[j], flags, toBind)
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:
for i in countup(0, sonsLen(n) - 1):
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)
checkMinSonsLen(a, 3)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc})
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
toBind)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, toBind)
for j in countup(0, L-3):
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
of nkGenericParams:
@@ -175,7 +181,8 @@ proc semGenericStmt(c: PContext, n: PNode,
if (a.kind != nkIdentDefs): IllFormedAst(a)
checkMinSonsLen(a, 3)
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
for j in countup(0, L-3):
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)
checkSonsLen(a, 3)
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc})
a.sons[2] = semGenericStmt(c, a.sons[2], flags)
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, toBind)
a.sons[2] = semGenericStmt(c, a.sons[2], flags, toBind)
of nkTypeSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
@@ -202,15 +209,15 @@ proc semGenericStmt(c: PContext, n: PNode,
checkSonsLen(a, 3)
if a.sons[1].kind != nkEmpty:
openScope(c.tab)
a.sons[1] = semGenericStmt(c, a.sons[1], flags)
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc})
a.sons[1] = semGenericStmt(c, a.sons[1], flags, toBind)
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind)
closeScope(c.tab)
else:
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc})
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind)
of nkEnumTy:
checkMinSonsLen(n, 1)
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):
var a: PNode
case n.sons[i].kind
@@ -223,14 +230,15 @@ proc semGenericStmt(c: PContext, n: PNode,
of nkFormalParams:
checkMinSonsLen(n, 1)
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):
var a = n.sons[i]
if (a.kind != nkIdentDefs): IllFormedAst(a)
checkMinSonsLen(a, 3)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc})
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
toBind)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, toBind)
for j in countup(0, L-3):
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
@@ -238,15 +246,16 @@ proc semGenericStmt(c: PContext, n: PNode,
checkSonsLen(n, codePos + 1)
addDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c))
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].sons[0].kind != nkEmpty:
addDecl(c, newSym(skUnknown, getIdent("result"), nil))
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags)
n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags)
n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], flags)
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, toBind)
n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, toBind)
n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], flags, toBind)
closeScope(c.tab)
else:
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

@@ -700,9 +700,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if s.typ.sons[0] != nil and kind != skIterator: addResultNode(c, n)
popProcCon(c)
else:
if s.typ.sons[0] != nil and kind != skIterator:
addDecl(c, newSym(skUnknown, getIdent("result"), nil))
n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], {})
if s.typ.sons[0] != nil and kind != skIterator:
addDecl(c, newSym(skUnknown, getIdent"result", nil))
var toBind = initIntSet()
n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], {}, toBind)
fixupInstantiatedSymbols(c, s)
if sfImportc in s.flags:
# 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))
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,
toBind: var TIntSet): PNode =
var s: PSym
@@ -103,7 +116,7 @@ proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool,
of nkIdent:
if not withinBind and not Contains(toBind, n.ident.id):
s = SymTabLocalGet(c.Tab, n.ident)
if (s != nil):
if s != nil:
result = newSymNode(s)
result.info = n.info
else:
@@ -115,6 +128,8 @@ proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool,
result = n
of nkBind:
result = resolveTemplateParams(c, n.sons[0], true, toBind)
of nkBindStmt:
result = semBindStmt(c, n, toBind)
else:
result = n
for i in countup(0, sonsLen(n) - 1):

View File

@@ -33,7 +33,7 @@ primaryPrefix ::= (prefixOperator | 'bind') optInd
primarySuffix ::= '.' optInd symbol [generalizedLit]
| '(' optInd namedExprList optPar ')'
| '[' optInd [indexExpr (comma indexExpr)* [comma]] optPar ']'
| '{' optInd ':' | colonExprList optPar '}'
| '{' optInd [indexExpr (comma indexExpr)* [comma]] optPar '}'
| pragma
primary ::= primaryPrefix* (symbol [generalizedLit] |
@@ -98,7 +98,7 @@ complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt
| blockStmt | asmStmt
| procDecl | iteratorDecl | macroDecl | templateDecl | methodDecl
| constSection | letSection | varSection
| typeSection | whenStmt
| typeSection | whenStmt | bindStmt
indPush ::= IND # and push indentation onto the stack
indPop ::= # pop indentation from the stack
@@ -132,6 +132,7 @@ blockStmt ::= 'block' [symbol] ':' stmt
filename ::= symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
importStmt ::= 'import' filename (comma filename)*
includeStmt ::= 'include' filename (comma filename)*
bindStmt ::= 'bind' IDENT (comma IDENT)*
fromStmt ::= 'from' filename 'import' symbol (comma symbol)*
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'
Bind statement
~~~~~~~~~~~~~~
Syntax::
bindStmt ::= 'bind' IDENT (comma IDENT)*
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``
context are 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:
this case, a `bind`:idx: statement can be used: It declares all identifiers
that should be bound early (i.e. when the template is parsed):
.. code-block:: nimrod
# Module A
@@ -2601,7 +2607,8 @@ occurences are in no ``bind`` context:
lastId = 0
template genId*: expr =
inc(bind lastId)
bind lastId
inc(lastId)
lastId
.. code-block:: nimrod
@@ -2610,14 +2617,8 @@ occurences are in no ``bind`` context:
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
~~~~~~~~~~~~~~~~~~~~~~~
@@ -2740,6 +2741,14 @@ regular expressions:
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
-------

View File

@@ -42,7 +42,8 @@ type
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
nnkIncludeStmt, nnkBindStmt,
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
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
## tree and to discover what kind of nodes must be created to represent
## a certain expression/statement
if n == nil: return "nil"
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
- test the sort implementation again
- optional indentation for 'case' statement
- ``bind`` as a declaration
- document & test splicing; don't forget to test negative indexes
- thread local vs. global raiseHook()
@@ -106,6 +105,39 @@ Low priority
- 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
=========

View File

@@ -38,6 +38,7 @@ Changes affecting backwards compatibility
- The ``pure`` pragma for procs has been renamed to ``noStackFrame``.
- The threading API has been completely redesigned.
- The ``unidecode`` module is now thread-safe and its interface has changed.
- The ``bind`` expression is deprecated, use a ``bind`` declaration instead.
Language Additions
@@ -55,6 +56,8 @@ Language Additions
- 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
heart's content.
- ``bind`` (used for symbol binding in templates and generics) is now a
declarative statement.
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.
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?
-----------------------