mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 04:02:41 +00:00
197 lines
6.7 KiB
Nim
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
|