version 0.8.5: added Nimrod version of the compiler

This commit is contained in:
Andreas Rumpf 2009-12-07 01:23:19 +01:00
commit e254741541
78 changed files with 35801 additions and 0 deletions

204
rod/semtempl.nim Executable file
View file

@ -0,0 +1,204 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
proc isExpr(n: PNode): bool =
# returns true if ``n`` looks like an expression
if n == nil:
return false
case n.kind
of nkIdent..nkNilLit:
result = true
of nkCall..nkPassAsOpenArray:
for i in countup(0, sonsLen(n) - 1):
if not isExpr(n.sons[i]):
return false
result = true
else: result = false
proc isTypeDesc(n: PNode): bool =
# returns true if ``n`` looks like a type desc
if n == nil:
return false
case n.kind
of nkIdent, nkSym, nkType:
result = true
of nkDotExpr, nkBracketExpr:
for i in countup(0, sonsLen(n) - 1):
if not isTypeDesc(n.sons[i]):
return false
result = true
of nkTypeOfExpr..nkEnumTy:
result = true
else: result = false
proc evalTemplateAux(c: PContext, templ, actual: PNode, sym: PSym): PNode =
var p: PSym
if templ == nil:
return nil
case templ.kind
of nkSym:
p = templ.sym
if (p.kind == skParam) and (p.owner.id == sym.id):
result = copyTree(actual.sons[p.position])
else:
result = copyNode(templ)
of nkNone..nkIdent, nkType..nkNilLit: # atom
result = copyNode(templ)
else:
result = copyNode(templ)
newSons(result, sonsLen(templ))
for i in countup(0, sonsLen(templ) - 1):
result.sons[i] = evalTemplateAux(c, templ.sons[i], actual, sym)
var evalTemplateCounter: int = 0
proc evalTemplateArgs(c: PContext, n: PNode, s: PSym): PNode =
# to prevend endless recursion in templates
# instantation
var
f, a: int
arg: PNode
f = sonsLen(s.typ) # if the template has zero arguments, it can be called without ``()``
# `n` is then a nkSym or something similar
case n.kind
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: a = sonsLen(
n)
else: a = 0
if a > f: liMessage(n.info, errWrongNumberOfArguments)
result = copyNode(n)
for i in countup(1, f - 1):
if i < a: arg = n.sons[i]
else: arg = copyTree(s.typ.n.sons[i].sym.ast)
if arg == nil: liMessage(n.info, errWrongNumberOfArguments)
if not (s.typ.sons[i].kind in {tyTypeDesc, tyStmt, tyExpr}):
# concrete type means semantic checking for argument:
arg = fitNode(c, s.typ.sons[i], semExprWithType(c, arg))
addSon(result, arg)
proc evalTemplate(c: PContext, n: PNode, sym: PSym): PNode =
var args: PNode
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
liMessage(n.info, errTemplateInstantiationTooNested) # replace each param by the corresponding node:
args = evalTemplateArgs(c, n, sym)
result = evalTemplateAux(c, sym.ast.sons[codePos], args, sym)
dec(evalTemplateCounter)
proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
var
a: PSym
o: TOverloadIter
i: int
i = 0
a = initOverloadIter(o, c, n)
while a != nil:
a = nextOverloadIter(o, c, n)
inc(i)
if i <= 1:
result = newSymNode(s)
result.info = n.info
markUsed(n, s)
else:
# semantic checking requires a type; ``fitNode`` deals with it
# appropriately
result = newNodeIT(nkSymChoice, n.info, newTypeS(tyNone, c))
a = initOverloadIter(o, c, n)
while a != nil:
addSon(result, newSymNode(a))
a = nextOverloadIter(o, c, n)
proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool,
toBind: var TIntSet): PNode =
var s: PSym
if n == nil:
return nil
case n.kind
of nkIdent:
if not withinBind and not IntSetContains(toBind, n.ident.id):
s = SymTabLocalGet(c.Tab, n.ident)
if (s != nil):
result = newSymNode(s)
result.info = n.info
else:
result = n
else:
IntSetIncl(toBind, n.ident.id)
result = symChoice(c, n, lookup(c, n))
of nkSym..nkNilLit: # atom
result = n
of nkBind:
result = resolveTemplateParams(c, n.sons[0], true, toBind)
else:
result = n
for i in countup(0, sonsLen(n) - 1):
result.sons[i] = resolveTemplateParams(c, n.sons[i], withinBind, toBind)
proc transformToExpr(n: PNode): PNode =
var realStmt: int
result = n
case n.kind
of nkStmtList:
realStmt = - 1
for i in countup(0, sonsLen(n) - 1):
case n.sons[i].kind
of nkCommentStmt, nkEmpty, nkNilLit:
nil
else:
if realStmt == - 1: realStmt = i
else: realStmt = - 2
if realStmt >= 0: result = transformToExpr(n.sons[realStmt])
else: n.kind = nkStmtListExpr
of nkBlockStmt:
n.kind = nkBlockExpr #nkIfStmt: n.kind := nkIfExpr; // this is not correct!
else:
nil
proc semTemplateDef(c: PContext, n: PNode): PNode =
var
s: PSym
toBind: TIntSet
if c.p.owner.kind == skModule:
s = semIdentVis(c, skTemplate, n.sons[0], {sfStar})
incl(s.flags, sfGlobal)
else:
s = semIdentVis(c, skTemplate, n.sons[0], {})
if sfStar in s.flags:
incl(s.flags, sfInInterface) # check parameter list:
pushOwner(s)
openScope(c.tab)
n.sons[namePos] = newSymNode(s) # check that no pragmas exist:
if n.sons[pragmasPos] != nil:
liMessage(n.info, errNoPragmasAllowedForX, "template") # check that no generic parameters exist:
if n.sons[genericParamsPos] != nil:
liMessage(n.info, errNoGenericParamsAllowedForX, "template")
if (n.sons[paramsPos] == nil):
# use ``stmt`` as implicit result type
s.typ = newTypeS(tyProc, c)
s.typ.n = newNodeI(nkFormalParams, n.info)
addSon(s.typ, newTypeS(tyStmt, c))
addSon(s.typ.n, newNodeIT(nkType, n.info, s.typ.sons[0]))
else:
semParamList(c, n.sons[ParamsPos], nil, s)
if n.sons[paramsPos].sons[0] == nil:
# use ``stmt`` as implicit result type
s.typ.sons[0] = newTypeS(tyStmt, c)
s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0])
addParams(c, s.typ.n) # resolve parameters:
IntSetInit(toBind)
n.sons[codePos] = resolveTemplateParams(c, n.sons[codePos], false, toBind)
if not (s.typ.sons[0].kind in {tyStmt, tyTypeDesc}):
n.sons[codePos] = transformToExpr(n.sons[codePos]) # only parameters are resolved, no type checking is performed
closeScope(c.tab)
popOwner()
s.ast = n
result = n
if n.sons[codePos] == nil:
liMessage(n.info, errImplOfXexpected, s.name.s) # add identifier of template as a last step to not allow
# recursive templates
addInterfaceDecl(c, s)