Files
Nim/rod/sem.nim
2010-02-14 00:29:35 +01:00

197 lines
6.7 KiB
Nim

#
#
# The Nimrod Compiler
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This module implements the semantic checking pass.
import
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 = 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 = 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 =
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
liMessage(n.info, errTemplateInstantiationTooNested)
markUsed(n, sym)
var p = newEvalContext(c.module, "", false)
var 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", "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", "semexprs.nim", "semgnrc.nim", "semstmts.nim"
proc addCodeForGenerics(c: PContext, n: PNode) =
for i in countup(c.lastGenericIdx, sonsLen(c.generics) - 1):
var it = c.generics.sons[i].sons[1]
if it.kind != nkSym: InternalError("addCodeForGenerics")
var 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 semExprNoFlags(c: PContext, n: PNode): PNode =
result = semExpr(c, n, {})
proc myOpen(module: PSym, filename: string): PPassContext =
var c = newContext(module, filename)
if (c.p != nil): InternalError(module.info, "sem.myOpen")
c.semConstExpr = semConstExpr
c.semExpr = semExprNoFlags
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(myOpen(module, filename))
c.fromCache = true
result = c
proc myProcess(context: PPassContext, n: PNode): PNode =
result = nil
var c = PContext(context)
result = semStmt(c, n)
# BUGFIX: process newly generated generics here, not at the end!
if sonsLen(c.generics) > 0:
var 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(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