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

218
rod/sem.nim Executable file
View file

@ -0,0 +1,218 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This module implements the semantic checking pass.
import #var
# point: array [0..3] of int;
strutils, nhashes, lists, options, scanner, ast, astalgo, trees, treetab,
wordrecg, ropes, msgs, os, condsyms, idents, rnimsyn, types, platform, math,
magicsys, pnimsyn, nversion, nimsets, semdata, evals, semfold, importer,
procfind, lookups, rodread, pragmas, passes
proc semPass*(): TPass
# implementation
proc considerAcc(n: PNode): PIdent =
var x: PNode
x = n
if x.kind == nkAccQuoted: x = x.sons[0]
case x.kind
of nkIdent: result = x.ident
of nkSym: result = x.sym.name
else:
liMessage(n.info, errIdentifierExpected, renderTree(n))
result = nil
proc isTopLevel(c: PContext): bool =
result = c.tab.tos <= 2
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerAcc(n), getCurrOwner())
result.info = n.info
proc markUsed(n: PNode, s: PSym) =
incl(s.flags, sfUsed)
if sfDeprecated in s.flags: liMessage(n.info, warnDeprecated, s.name.s)
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym
# identifier with visability
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
proc semStmtScope(c: PContext, n: PNode): PNode
type
TExprFlag = enum
efAllowType, efLValue, efWantIterator
TExprFlags = set[TExprFlag]
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode
proc semLambda(c: PContext, n: PNode): PNode
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
proc semStmt(c: PContext, n: PNode): PNode
proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
proc addParams(c: PContext, n: PNode)
proc addResult(c: PContext, t: PType, info: TLineInfo)
proc addResultNode(c: PContext, n: PNode)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
proc semConstExpr(c: PContext, n: PNode): PNode =
result = semExprWithType(c, n)
if result == nil:
liMessage(n.info, errConstExprExpected)
return
result = getConstExpr(c.module, result)
if result == nil: liMessage(n.info, errConstExprExpected)
proc semAndEvalConstExpr(c: PContext, n: PNode): PNode =
var e: PNode
e = semExprWithType(c, n)
if e == nil:
liMessage(n.info, errConstExprExpected)
return nil
result = getConstExpr(c.module, e)
if result == nil:
#writeln(output, renderTree(n));
result = evalConstExpr(c.module, e)
if (result == nil) or (result.kind == nkEmpty):
liMessage(n.info, errConstExprExpected)
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
result = n
case s.typ.sons[0].kind
of tyExpr: result = semExprWithType(c, result)
of tyStmt: result = semStmt(c, result)
of tyTypeDesc: result.typ = semTypeNode(c, result, nil)
else: liMessage(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
include
"semtempl.nim"
proc semMacroExpr(c: PContext, n: PNode, sym: PSym, semCheck: bool = true): PNode =
var
p: PEvalContext
s: PStackFrame
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
liMessage(n.info, errTemplateInstantiationTooNested)
markUsed(n, sym)
p = newEvalContext(c.module, "", false)
s = newStackFrame()
s.call = n
setlen(s.params, 2)
s.params[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
s.params[1] = n
pushStackFrame(p, s)
discard eval(p, sym.ast.sons[codePos])
result = s.params[0]
popStackFrame(p)
if cyclicTree(result): liMessage(n.info, errCyclicTree)
if semCheck: result = semAfterMacroCall(c, result, sym)
dec(evalTemplateCounter)
include
"seminst.nim"
include
"sigmatch.nim"
proc CheckBool(t: PNode) =
if (t.Typ == nil) or
(skipTypes(t.Typ, {tyGenericInst, tyVar, tyOrdinal}).kind != tyBool):
liMessage(t.Info, errExprMustBeBool)
proc typeMismatch(n: PNode, formal, actual: PType) =
liMessage(n.Info, errGenerated, msgKindToString(errTypeMismatch) &
typeToString(actual) & ") " &
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
include
"semtypes.nim"
include
"semexprs.nim"
include
"semgnrc.nim"
include
"semstmts.nim"
proc addCodeForGenerics(c: PContext, n: PNode) =
var
prc: PSym
it: PNode
for i in countup(c.lastGenericIdx, sonsLen(c.generics) - 1):
it = c.generics.sons[i].sons[1]
if it.kind != nkSym: InternalError("addCodeForGenerics")
prc = it.sym
if (prc.kind in {skProc, skMethod, skConverter}) and (prc.magic == mNone):
if (prc.ast == nil) or (prc.ast.sons[codePos] == nil):
InternalError(prc.info, "no code for " & prc.name.s)
addSon(n, prc.ast)
c.lastGenericIdx = sonsLen(c.generics)
proc myOpen(module: PSym, filename: string): PPassContext =
var c: PContext
c = newContext(module, filename)
if (c.p != nil): InternalError(module.info, "sem.myOpen")
c.semConstExpr = semConstExpr
c.p = newProcCon(module)
pushOwner(c.module)
openScope(c.tab) # scope for imported symbols
SymTabAdd(c.tab, module) # a module knows itself
if sfSystemModule in module.flags:
magicsys.SystemModule = module # set global variable!
InitSystem(c.tab) # currently does nothing
else:
SymTabAdd(c.tab, magicsys.SystemModule) # import the "System" identifier
importAllSymbols(c, magicsys.SystemModule)
openScope(c.tab) # scope for the module's symbols
result = c
proc myOpenCached(module: PSym, filename: string, rd: PRodReader): PPassContext =
var c: PContext
c = PContext(myOpen(module, filename))
c.fromCache = true
result = c
proc myProcess(context: PPassContext, n: PNode): PNode =
var
c: PContext
a: PNode
result = nil
c = PContext(context)
result = semStmt(c, n) # BUGFIX: process newly generated generics here, not at the end!
if sonsLen(c.generics) > 0:
a = newNodeI(nkStmtList, n.info)
addCodeForGenerics(c, a)
if sonsLen(a) > 0:
# a generic has been added to `a`:
addSonIfNotNil(a, result)
result = a
proc myClose(context: PPassContext, n: PNode): PNode =
var c: PContext
c = PContext(context)
closeScope(c.tab) # close module's scope
rawCloseScope(c.tab) # imported symbols; don't check for unused ones!
if n == nil:
result = newNode(nkStmtList)
else:
InternalError(n.info, "n is not nil") #result := n;
addCodeForGenerics(c, result)
popOwner()
c.p = nil
proc semPass(): TPass =
initPass(result)
result.open = myOpen
result.openCached = myOpenCached
result.close = myClose
result.process = myProcess