merge devel

This commit is contained in:
cooldome 2018-06-12 21:19:30 +01:00
commit 37aa488f99
136 changed files with 4276 additions and 5649 deletions

View file

@ -31,7 +31,6 @@ before_script:
- cd csources - cd csources
- sh build.sh - sh build.sh
- cd .. - cd ..
- sed -i -e 's,cc = gcc,cc = clang,' config/nim.cfg
- export PATH=$(pwd)/bin${PATH:+:$PATH} - export PATH=$(pwd)/bin${PATH:+:$PATH}
script: script:
- nim c koch - nim c koch

View file

@ -91,11 +91,16 @@
- The `terminal` module now exports additional procs for generating ANSI color - The `terminal` module now exports additional procs for generating ANSI color
codes as strings. codes as strings.
- Added the parameter ``val`` for the ``CritBitTree[int].inc`` proc. - Added the parameter ``val`` for the ``CritBitTree[int].inc`` proc.
- An exception raised from a ``test`` block of ``unittest`` now shows its type in
error message.
- The ``compiler/nimeval`` API was rewritten to simplify the "compiler as an
API". Using the Nim compiler and its VM as a scripting engine has never been
easier. See ``tests/compilerapi/tcompilerapi.nim`` for an example of how to
use the Nim VM in a native Nim application.
- Added the parameter ``val`` for the ``CritBitTree[T].incl`` proc. - Added the parameter ``val`` for the ``CritBitTree[T].incl`` proc.
- An exception raised from ``test`` block of ``unittest`` now shows its type in
the error message
- The proc ``tgamma`` was renamed to ``gamma``. ``tgamma`` is deprecated. - The proc ``tgamma`` was renamed to ``gamma``. ``tgamma`` is deprecated.
### Language additions ### Language additions
- Dot calls combined with explicit generic instantiations can now be written - Dot calls combined with explicit generic instantiations can now be written

View file

@ -10,7 +10,7 @@
# abstract syntax tree + symbol table # abstract syntax tree + symbol table
import import
msgs, hashes, nversion, options, strutils, std / sha1, ropes, idents, lineinfos, hashes, nversion, options, strutils, std / sha1, ropes, idents,
intsets, idgen intsets, idgen
type type
@ -634,14 +634,18 @@ type
mNaN, mInf, mNegInf, mNaN, mInf, mNegInf,
mCompileOption, mCompileOptionArg, mCompileOption, mCompileOptionArg,
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel,
mNKind, mNSymKind mNKind, mNSymKind,
mNccValue, mNccInc, mNcsAdd, mNcsIncl, mNcsLen, mNcsAt,
mNctPut, mNctLen, mNctGet, mNctHasNext, mNctNext,
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo, mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent,
mNBindSym, mLocals, mNCallSite, mNBindSym, mLocals, mNCallSite,
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym,
mNHint, mNWarning, mNError, mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo, mNGenSym, mInstantiationInfo, mGetTypeInfo,
mNimvm, mIntDefine, mStrDefine, mRunnableExamples, mNimvm, mIntDefine, mStrDefine, mRunnableExamples,
mException, mBuiltinType mException, mBuiltinType
@ -998,8 +1002,8 @@ const
skMethod, skConverter} skMethod, skConverter}
var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
var #var
gMainPackageId*: int # gMainPackageId*: int
proc isCallExpr*(n: PNode): bool = proc isCallExpr*(n: PNode): bool =
result = n.kind in nkCallKinds result = n.kind in nkCallKinds
@ -1058,22 +1062,6 @@ proc newTree*(kind: TNodeKind; children: varargs[PNode]): PNode =
result.info = children[0].info result.info = children[0].info
result.sons = @children result.sons = @children
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
result = newNode(kind)
result.intVal = intVal
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
result = newIntNode(kind, intVal)
result.typ = typ
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
result = newNode(kind)
result.floatVal = floatVal
proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
result = newNode(kind)
result.strVal = strVal
template previouslyInferred*(t: PType): PType = template previouslyInferred*(t: PType): PType =
if t.sons.len > 1: t.lastSon else: nil if t.sons.len > 1: t.lastSon else: nil
@ -1095,9 +1083,6 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
# writeStacktrace() # writeStacktrace()
# MessageOut(name.s & " has id: " & toString(result.id)) # MessageOut(name.s & " has id: " & toString(result.id))
var emptyNode* = newNode(nkEmpty) # XXX global variable here!
# There is a single empty node that is shared! Do not overwrite it!
proc isMetaType*(t: PType): bool = proc isMetaType*(t: PType): bool =
return t.kind in tyMetaTypes or return t.kind in tyMetaTypes or
(t.kind == tyStatic and t.n == nil) or (t.kind == tyStatic and t.n == nil) or
@ -1224,18 +1209,35 @@ proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
result.info = info result.info = info
result.typ = typ result.typ = typ
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
result = newNode(kind)
result.intVal = intVal
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
result = newIntNode(kind, intVal)
result.typ = typ
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
result = newNode(kind)
result.floatVal = floatVal
proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
result = newNode(kind)
result.strVal = strVal
proc newStrNode*(strVal: string; info: TLineInfo): PNode =
result = newNodeI(nkStrLit, info)
result.strVal = strVal
proc addSon*(father, son: PNode) = proc addSon*(father, son: PNode) =
assert son != nil assert son != nil
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
add(father.sons, son) add(father.sons, son)
var emptyParams = newNode(nkFormalParams)
emptyParams.addSon(emptyNode)
proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode, proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
params = emptyParams, params,
name, pattern, genericParams, name, pattern, genericParams,
pragmas, exceptions = ast.emptyNode): PNode = pragmas, exceptions: PNode): PNode =
result = newNodeI(kind, info) result = newNodeI(kind, info)
result.sons = @[name, pattern, genericParams, params, result.sons = @[name, pattern, genericParams, params,
pragmas, exceptions, body] pragmas, exceptions, body]
@ -1705,7 +1707,7 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
result = true result = true
proc isInfixAs*(n: PNode): bool = proc isInfixAs*(n: PNode): bool =
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.id == getIdent("as").id return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as"
proc findUnresolvedStatic*(n: PNode): PNode = proc findUnresolvedStatic*(n: PNode): PNode =
if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil: if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil:
@ -1730,3 +1732,5 @@ template incompleteType*(t: PType): bool =
template typeCompleted*(s: PSym) = template typeCompleted*(s: PSym) =
incl s.flags, sfNoForward incl s.flags, sfNoForward
template getBody*(s: PSym): PNode = s.ast[bodyPos]

View file

@ -12,79 +12,43 @@
# the data structures here are used in various places of the compiler. # the data structures here are used in various places of the compiler.
import import
ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils ast, hashes, intsets, strutils, options, lineinfos, ropes, idents, rodutils,
msgs
proc hashNode*(p: RootRef): Hash proc hashNode*(p: RootRef): Hash
proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope proc treeToYaml*(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
# Convert a tree into its YAML representation; this is used by the # Convert a tree into its YAML representation; this is used by the
# YAML code generator and it is invaluable for debugging purposes. # YAML code generator and it is invaluable for debugging purposes.
# If maxRecDepht <> -1 then it won't print the whole graph. # If maxRecDepht <> -1 then it won't print the whole graph.
proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope proc typeToYaml*(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope
proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope proc symToYaml*(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope
proc lineInfoToStr*(info: TLineInfo): Rope proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): Rope
# ----------------------- node sets: --------------------------------------- when declared(echo):
proc objectSetContains*(t: TObjectSet, obj: RootRef): bool # these are for debugging only: They are not really deprecated, but I want
# returns true whether n is in t # the warning so that release versions do not contain debugging statements:
proc objectSetIncl*(t: var TObjectSet, obj: RootRef) proc debug*(conf: ConfigRef; n: PSym) {.deprecated.}
# include an element n in the table t proc debug*(conf: ConfigRef; n: PType) {.deprecated.}
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool proc debug*(conf: ConfigRef; n: PNode) {.deprecated.}
# more are not needed ...
# ----------------------- str table -----------------------------------------
proc strTableContains*(t: TStrTable, n: PSym): bool
proc strTableAdd*(t: var TStrTable, n: PSym)
proc strTableGet*(t: TStrTable, name: PIdent): PSym
type
TTabIter*{.final.} = object # consider all fields here private
h*: Hash # current hash
proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
# usage:
# var
# i: TTabIter
# s: PSym
# s = InitTabIter(i, table)
# while s != nil:
# ...
# s = NextIter(i, table)
#
type
TIdentIter*{.final.} = object # iterator over all syms with same identifier
h*: Hash # current hash
name*: PIdent
proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym
proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym
# 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.}
template mdbg*: bool {.dirty.} = template mdbg*: bool {.dirty.} =
when compiles(c.module): when compiles(c.module):
c.module.fileIdx.int32 == c.config.projectMainIdx c.module.fileIdx == c.config.projectMainIdx
elif compiles(c.c.module): elif compiles(c.c.module):
c.c.module.fileIdx.int32 == c.c.config.projectMainIdx c.c.module.fileIdx == c.c.config.projectMainIdx
elif compiles(m.c.module): elif compiles(m.c.module):
m.c.module.fileIdx.int32 == m.c.config.projectMainIdx m.c.module.fileIdx == m.c.config.projectMainIdx
elif compiles(cl.c.module): elif compiles(cl.c.module):
cl.c.module.fileIdx.int32 == cl.c.config.projectMainIdx cl.c.module.fileIdx == cl.c.config.projectMainIdx
elif compiles(p): elif compiles(p):
when compiles(p.lex): when compiles(p.lex):
p.lex.fileIdx.int32 == p.lex.config.projectMainIdx p.lex.fileIdx == p.lex.config.projectMainIdx
else: else:
p.module.module.fileIdx.int32 == p.config.projectMainIdx p.module.module.fileIdx == p.config.projectMainIdx
elif compiles(m.module.fileIdx): elif compiles(m.module.fileIdx):
m.module.fileIdx.int32 == m.config.projectMainIdx m.module.fileIdx == m.config.projectMainIdx
elif compiles(L.fileIdx): elif compiles(L.fileIdx):
L.fileIdx.int32 == L.config.projectMainIdx L.fileIdx == L.config.projectMainIdx
else: else:
error() error()
@ -102,7 +66,6 @@ proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym
proc lookupInRecord*(n: PNode, field: PIdent): PSym proc lookupInRecord*(n: PNode, field: PIdent): PSym
proc getModule*(s: PSym): PSym
proc mustRehash*(length, counter: int): bool proc mustRehash*(length, counter: int): bool
proc nextTry*(h, maxHash: Hash): Hash {.inline.} proc nextTry*(h, maxHash: Hash): Hash {.inline.}
@ -193,7 +156,7 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
if n.sym.name.id == field.id: result = n.sym if n.sym.name.id == field.id: result = n.sym
else: return nil else: return nil
proc getModule(s: PSym): PSym = proc getModule*(s: PSym): PSym =
result = s result = s
assert((result.kind == skModule) or (result.owner != result)) assert((result.kind == skModule) or (result.owner != result))
while result != nil and result.kind != skModule: result = result.owner while result != nil and result.kind != skModule: result = result.owner
@ -250,16 +213,16 @@ proc flagsToStr[T](flags: set[T]): Rope =
add(result, makeYamlString($x)) add(result, makeYamlString($x))
result = "[" & result & "]" result = "[" & result & "]"
proc lineInfoToStr(info: TLineInfo): Rope = proc lineInfoToStr(conf: ConfigRef; info: TLineInfo): Rope =
result = "[$1, $2, $3]" % [makeYamlString(toFilename(info)), result = "[$1, $2, $3]" % [makeYamlString(toFilename(conf, info)),
rope(toLinenumber(info)), rope(toLinenumber(info)),
rope(toColumn(info))] rope(toColumn(info))]
proc treeToYamlAux(n: PNode, marker: var IntSet, proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet,
indent, maxRecDepth: int): Rope indent, maxRecDepth: int): Rope
proc symToYamlAux(n: PSym, marker: var IntSet, proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet,
indent, maxRecDepth: int): Rope indent, maxRecDepth: int): Rope
proc typeToYamlAux(n: PType, marker: var IntSet, proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet,
indent, maxRecDepth: int): Rope indent, maxRecDepth: int): Rope
proc ropeConstr(indent: int, c: openArray[Rope]): Rope = proc ropeConstr(indent: int, c: openArray[Rope]): Rope =
@ -273,7 +236,7 @@ proc ropeConstr(indent: int, c: openArray[Rope]): Rope =
inc(i, 2) inc(i, 2)
addf(result, "$N$1}", [rspaces(indent)]) addf(result, "$N$1}", [rspaces(indent)])
proc symToYamlAux(n: PSym, marker: var IntSet, indent: int, proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet, indent: int,
maxRecDepth: int): Rope = maxRecDepth: int): Rope =
if n == nil: if n == nil:
result = rope("null") result = rope("null")
@ -281,20 +244,20 @@ proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
result = "\"$1 @$2\"" % [rope(n.name.s), rope( result = "\"$1 @$2\"" % [rope(n.name.s), rope(
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))] strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
else: else:
var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1) var ast = treeToYamlAux(conf, n.ast, marker, indent + 2, maxRecDepth - 1)
result = ropeConstr(indent, [rope("kind"), result = ropeConstr(indent, [rope("kind"),
makeYamlString($n.kind), makeYamlString($n.kind),
rope("name"), makeYamlString(n.name.s), rope("name"), makeYamlString(n.name.s),
rope("typ"), typeToYamlAux(n.typ, marker, rope("typ"), typeToYamlAux(conf, n.typ, marker,
indent + 2, maxRecDepth - 1), indent + 2, maxRecDepth - 1),
rope("info"), lineInfoToStr(n.info), rope("info"), lineInfoToStr(conf, n.info),
rope("flags"), flagsToStr(n.flags), rope("flags"), flagsToStr(n.flags),
rope("magic"), makeYamlString($n.magic), rope("magic"), makeYamlString($n.magic),
rope("ast"), ast, rope("options"), rope("ast"), ast, rope("options"),
flagsToStr(n.options), rope("position"), flagsToStr(n.options), rope("position"),
rope(n.position)]) rope(n.position)])
proc typeToYamlAux(n: PType, marker: var IntSet, indent: int, proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
maxRecDepth: int): Rope = maxRecDepth: int): Rope =
if n == nil: if n == nil:
result = rope("null") result = rope("null")
@ -306,15 +269,15 @@ proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
result = rope("[") result = rope("[")
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: add(result, ",") if i > 0: add(result, ",")
addf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(n.sons[i], addf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, n.sons[i],
marker, indent + 4, maxRecDepth - 1)]) marker, indent + 4, maxRecDepth - 1)])
addf(result, "$N$1]", [rspaces(indent + 2)]) addf(result, "$N$1]", [rspaces(indent + 2)])
else: else:
result = rope("null") result = rope("null")
result = ropeConstr(indent, [rope("kind"), result = ropeConstr(indent, [rope("kind"),
makeYamlString($n.kind), makeYamlString($n.kind),
rope("sym"), symToYamlAux(n.sym, marker, rope("sym"), symToYamlAux(conf, n.sym, marker,
indent + 2, maxRecDepth - 1), rope("n"), treeToYamlAux(n.n, marker, indent + 2, maxRecDepth - 1), rope("n"), treeToYamlAux(conf, n.n, marker,
indent + 2, maxRecDepth - 1), rope("flags"), flagsToStr(n.flags), indent + 2, maxRecDepth - 1), rope("flags"), flagsToStr(n.flags),
rope("callconv"), rope("callconv"),
makeYamlString(CallingConvToStr[n.callConv]), makeYamlString(CallingConvToStr[n.callConv]),
@ -322,7 +285,7 @@ proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
rope("align"), rope(n.align), rope("align"), rope(n.align),
rope("sons"), result]) rope("sons"), result])
proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int, proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int,
maxRecDepth: int): Rope = maxRecDepth: int): Rope =
if n == nil: if n == nil:
result = rope("null") result = rope("null")
@ -330,7 +293,7 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
var istr = rspaces(indent + 2) var istr = rspaces(indent + 2)
result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)] result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
if maxRecDepth != 0: if maxRecDepth != 0:
addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
case n.kind case n.kind
of nkCharLit..nkInt64Lit: of nkCharLit..nkInt64Lit:
addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)]) addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
@ -344,7 +307,7 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym: of nkSym:
addf(result, ",$N$1\"sym\": $2", addf(result, ",$N$1\"sym\": $2",
[istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)]) [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth)])
of nkIdent: of nkIdent:
if n.ident != nil: if n.ident != nil:
addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)]) addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
@ -355,27 +318,27 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
addf(result, ",$N$1\"sons\": [", [istr]) addf(result, ",$N$1\"sons\": [", [istr])
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: add(result, ",") if i > 0: add(result, ",")
addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(n.sons[i], addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(conf, n.sons[i],
marker, indent + 4, maxRecDepth - 1)]) marker, indent + 4, maxRecDepth - 1)])
addf(result, "$N$1]", [istr]) addf(result, "$N$1]", [istr])
addf(result, ",$N$1\"typ\": $2", addf(result, ",$N$1\"typ\": $2",
[istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)]) [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth)])
addf(result, "$N$1}", [rspaces(indent)]) addf(result, "$N$1}", [rspaces(indent)])
proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope = proc treeToYaml(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet() var marker = initIntSet()
result = treeToYamlAux(n, marker, indent, maxRecDepth) result = treeToYamlAux(conf, n, marker, indent, maxRecDepth)
proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope = proc typeToYaml(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet() var marker = initIntSet()
result = typeToYamlAux(n, marker, indent, maxRecDepth) result = typeToYamlAux(conf, n, marker, indent, maxRecDepth)
proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope = proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet() var marker = initIntSet()
result = symToYamlAux(n, marker, indent, maxRecDepth) result = symToYamlAux(conf, n, marker, indent, maxRecDepth)
proc debugTree*(n: PNode, indent: int, maxRecDepth: int; renderType=false): Rope proc debugTree*(conf: ConfigRef; n: PNode, indent: int, maxRecDepth: int; renderType=false): Rope
proc debugType(n: PType, maxRecDepth=100): Rope = proc debugType(conf: ConfigRef; n: PType, maxRecDepth=100): Rope =
if n == nil: if n == nil:
result = rope("null") result = rope("null")
else: else:
@ -385,7 +348,7 @@ proc debugType(n: PType, maxRecDepth=100): Rope =
add(result, n.sym.name.s) add(result, n.sym.name.s)
if n.kind in IntegralTypes and n.n != nil: if n.kind in IntegralTypes and n.n != nil:
add(result, ", node: ") add(result, ", node: ")
add(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true)) add(result, debugTree(conf, n.n, 2, maxRecDepth-1, renderType=true))
if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0: if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0:
add(result, "(") add(result, "(")
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
@ -393,13 +356,13 @@ proc debugType(n: PType, maxRecDepth=100): Rope =
if n.sons[i] == nil: if n.sons[i] == nil:
add(result, "null") add(result, "null")
else: else:
add(result, debugType(n.sons[i], maxRecDepth-1)) add(result, debugType(conf, n.sons[i], maxRecDepth-1))
if n.kind == tyObject and n.n != nil: if n.kind == tyObject and n.n != nil:
add(result, ", node: ") add(result, ", node: ")
add(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true)) add(result, debugTree(conf, n.n, 2, maxRecDepth-1, renderType=true))
add(result, ")") add(result, ")")
proc debugTree(n: PNode, indent: int, maxRecDepth: int; proc debugTree(conf: ConfigRef; n: PNode, indent: int, maxRecDepth: int;
renderType=false): Rope = renderType=false): Rope =
if n == nil: if n == nil:
result = rope("null") result = rope("null")
@ -409,7 +372,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
[istr, makeYamlString($n.kind)] [istr, makeYamlString($n.kind)]
when defined(useNodeIds): when defined(useNodeIds):
addf(result, ",$N$1\"id\": $2", [istr, rope(n.id)]) addf(result, ",$N$1\"id\": $2", [istr, rope(n.id)])
addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
if maxRecDepth != 0: if maxRecDepth != 0:
addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)]) addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)])
case n.kind case n.kind
@ -429,7 +392,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
# [istr, symToYaml(n.sym, indent, maxRecDepth), # [istr, symToYaml(n.sym, indent, maxRecDepth),
# rope(n.sym.id)]) # rope(n.sym.id)])
if renderType and n.sym.typ != nil: if renderType and n.sym.typ != nil:
addf(result, ",$N$1\"typ\": $2", [istr, debugType(n.sym.typ, 2)]) addf(result, ",$N$1\"typ\": $2", [istr, debugType(conf, n.sym.typ, 2)])
of nkIdent: of nkIdent:
if n.ident != nil: if n.ident != nil:
addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)]) addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
@ -440,27 +403,28 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
addf(result, ",$N$1\"sons\": [", [istr]) addf(result, ",$N$1\"sons\": [", [istr])
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: add(result, ",") if i > 0: add(result, ",")
addf(result, "$N$1$2", [rspaces(indent + 4), debugTree(n.sons[i], addf(result, "$N$1$2", [rspaces(indent + 4), debugTree(conf, n.sons[i],
indent + 4, maxRecDepth - 1, renderType)]) indent + 4, maxRecDepth - 1, renderType)])
addf(result, "$N$1]", [istr]) addf(result, "$N$1]", [istr])
addf(result, "$N$1}", [rspaces(indent)]) addf(result, "$N$1}", [rspaces(indent)])
proc debug(n: PSym) = when declared(echo):
if n == nil: proc debug(conf: ConfigRef; n: PSym) =
echo("null") if n == nil:
elif n.kind == skUnknown: echo("null")
echo("skUnknown") elif n.kind == skUnknown:
else: echo("skUnknown")
#writeLine(stdout, $symToYaml(n, 0, 1)) else:
echo("$1_$2: $3, $4, $5, $6" % [ #writeLine(stdout, $symToYaml(n, 0, 1))
n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags), echo("$1_$2: $3, $4, $5, $6" % [
$lineInfoToStr(n.info), $n.kind]) n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags),
$lineInfoToStr(conf, n.info), $n.kind])
proc debug(n: PType) = proc debug(conf: ConfigRef; n: PType) =
echo($debugType(n)) echo($debugType(conf, n))
proc debug(n: PNode) = proc debug(conf: ConfigRef; n: PNode) =
echo($debugTree(n, 0, 100)) echo($debugTree(conf, n, 0, 100))
proc nextTry(h, maxHash: Hash): Hash = proc nextTry(h, maxHash: Hash): Hash =
result = ((5 * h) + 1) and maxHash result = ((5 * h) + 1) and maxHash
@ -468,7 +432,7 @@ proc nextTry(h, maxHash: Hash): Hash =
# generates each int in range(maxHash) exactly once (see any text on # generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof). # random-number generation for proof).
proc objectSetContains(t: TObjectSet, obj: RootRef): bool = proc objectSetContains*(t: TObjectSet, obj: RootRef): bool =
# returns true whether n is in t # returns true whether n is in t
var h: Hash = hashNode(obj) and high(t.data) # start with real hash value var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
while t.data[h] != nil: while t.data[h] != nil:
@ -492,12 +456,12 @@ proc objectSetEnlarge(t: var TObjectSet) =
if t.data[i] != nil: objectSetRawInsert(n, t.data[i]) if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
swap(t.data, n) swap(t.data, n)
proc objectSetIncl(t: var TObjectSet, obj: RootRef) = proc objectSetIncl*(t: var TObjectSet, obj: RootRef) =
if mustRehash(len(t.data), t.counter): objectSetEnlarge(t) if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
objectSetRawInsert(t.data, obj) objectSetRawInsert(t.data, obj)
inc(t.counter) inc(t.counter)
proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool = proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool =
# returns true if obj is already in the string table: # returns true if obj is already in the string table:
var h: Hash = hashNode(obj) and high(t.data) var h: Hash = hashNode(obj) and high(t.data)
while true: while true:
@ -515,7 +479,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
inc(t.counter) inc(t.counter)
result = false result = false
proc strTableContains(t: TStrTable, n: PSym): bool = proc strTableContains*(t: TStrTable, n: PSym): bool =
var h: Hash = n.name.h and high(t.data) # start with real hash value var h: Hash = n.name.h and high(t.data) # start with real hash value
while t.data[h] != nil: while t.data[h] != nil:
if (t.data[h] == n): if (t.data[h] == n):
@ -571,7 +535,7 @@ proc strTableEnlarge(t: var TStrTable) =
if t.data[i] != nil: strTableRawInsert(n, t.data[i]) if t.data[i] != nil: strTableRawInsert(n, t.data[i])
swap(t.data, n) swap(t.data, n)
proc strTableAdd(t: var TStrTable, n: PSym) = proc strTableAdd*(t: var TStrTable, n: PSym) =
if mustRehash(len(t.data), t.counter): strTableEnlarge(t) if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
strTableRawInsert(t.data, n) strTableRawInsert(t.data, n)
inc(t.counter) inc(t.counter)
@ -607,7 +571,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym; onConflictKeepOld=false): bool {.d
inc(t.counter) inc(t.counter)
result = false result = false
proc strTableGet(t: TStrTable, name: PIdent): PSym = proc strTableGet*(t: TStrTable, name: PIdent): PSym =
var h: Hash = name.h and high(t.data) var h: Hash = name.h and high(t.data)
while true: while true:
result = t.data[h] result = t.data[h]
@ -615,13 +579,13 @@ proc strTableGet(t: TStrTable, name: PIdent): PSym =
if result.name.id == name.id: break if result.name.id == name.id: break
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
ti.h = s.h
ti.name = s
if tab.counter == 0: result = nil
else: result = nextIdentIter(ti, tab)
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym = type
TIdentIter* = object # iterator over all syms with same identifier
h*: Hash # current hash
name*: PIdent
proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym =
var h = ti.h and high(tab.data) var h = ti.h and high(tab.data)
var start = h var start = h
result = tab.data[h] result = tab.data[h]
@ -634,6 +598,12 @@ proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
result = tab.data[h] result = tab.data[h]
ti.h = nextTry(h, high(tab.data)) ti.h = nextTry(h, high(tab.data))
proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
ti.h = s.h
ti.name = s
if tab.counter == 0: result = nil
else: result = nextIdentIter(ti, tab)
proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
excluding: IntSet): PSym = excluding: IntSet): PSym =
var h: Hash = ti.h and high(tab.data) var h: Hash = ti.h and high(tab.data)
@ -657,20 +627,33 @@ proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
if tab.counter == 0: result = nil if tab.counter == 0: result = nil
else: result = nextIdentExcluding(ti, tab, excluding) else: result = nextIdentExcluding(ti, tab, excluding)
proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym = type
ti.h = 0 # we start by zero ... TTabIter* = object
if tab.counter == 0: h: Hash
result = nil # FIX 1: removed endless loop
else:
result = nextIter(ti, tab)
proc nextIter(ti: var TTabIter, tab: TStrTable): PSym = proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym =
# usage:
# var
# i: TTabIter
# s: PSym
# s = InitTabIter(i, table)
# while s != nil:
# ...
# s = NextIter(i, table)
#
result = nil result = nil
while (ti.h <= high(tab.data)): while (ti.h <= high(tab.data)):
result = tab.data[ti.h] result = tab.data[ti.h]
inc(ti.h) # ... and increment by one always inc(ti.h) # ... and increment by one always
if result != nil: break if result != nil: break
proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym =
ti.h = 0
if tab.counter == 0:
result = nil
else:
result = nextIter(ti, tab)
iterator items*(tab: TStrTable): PSym = iterator items*(tab: TStrTable): PSym =
var it: TTabIter var it: TTabIter
var s = initTabIter(it, tab) var s = initTabIter(it, tab)

233
compiler/btrees.nim Normal file
View file

@ -0,0 +1,233 @@
#
#
# The Nim Compiler
# (c) Copyright 2018 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## BTree implementation with few features, but good enough for the
## Nim compiler's needs.
const
M = 512 # max children per B-tree node = M-1
# (must be even and greater than 2)
Mhalf = M div 2
type
Node[Key, Val] = ref object
entries: int
keys: array[M, Key]
case isInternal: bool
of false:
vals: array[M, Val]
of true:
links: array[M, Node[Key, Val]]
BTree*[Key, Val] = object
root: Node[Key, Val]
entries: int ## number of key-value pairs
proc initBTree*[Key, Val](): BTree[Key, Val] =
BTree[Key, Val](root: Node[Key, Val](entries: 0, isInternal: false))
template less(a, b): bool = cmp(a, b) < 0
template eq(a, b): bool = cmp(a, b) == 0
proc getOrDefault*[Key, Val](b: BTree[Key, Val], key: Key): Val =
var x = b.root
while x.isInternal:
for j in 0 ..< x.entries:
if j+1 == x.entries or less(key, x.keys[j+1]):
x = x.links[j]
break
assert(not x.isInternal)
for j in 0 ..< x.entries:
if eq(key, x.keys[j]): return x.vals[j]
proc contains*[Key, Val](b: BTree[Key, Val], key: Key): bool =
var x = b.root
while x.isInternal:
for j in 0 ..< x.entries:
if j+1 == x.entries or less(key, x.keys[j+1]):
x = x.links[j]
break
assert(not x.isInternal)
for j in 0 ..< x.entries:
if eq(key, x.keys[j]): return true
return false
proc copyHalf[Key, Val](h, result: Node[Key, Val]) =
for j in 0 ..< Mhalf:
result.keys[j] = h.keys[Mhalf + j]
if h.isInternal:
for j in 0 ..< Mhalf:
result.links[j] = h.links[Mhalf + j]
else:
for j in 0 ..< Mhalf:
shallowCopy(result.vals[j], h.vals[Mhalf + j])
proc split[Key, Val](h: Node[Key, Val]): Node[Key, Val] =
## split node in half
result = Node[Key, Val](entries: Mhalf, isInternal: h.isInternal)
h.entries = Mhalf
copyHalf(h, result)
proc insert[Key, Val](h: Node[Key, Val], key: Key, val: Val): Node[Key, Val] =
#var t = Entry(key: key, val: val, next: nil)
var newKey = key
var j = 0
if not h.isInternal:
while j < h.entries:
if less(key, h.keys[j]): break
inc j
for i in countdown(h.entries, j+1):
shallowCopy(h.vals[i], h.vals[i-1])
h.vals[j] = val
else:
var newLink: Node[Key, Val] = nil
while j < h.entries:
if j+1 == h.entries or less(key, h.keys[j+1]):
let u = insert(h.links[j], key, val)
inc j
if u == nil: return nil
newKey = u.keys[0]
newLink = u
break
inc j
for i in countdown(h.entries, j+1):
h.links[i] = h.links[i-1]
h.links[j] = newLink
for i in countdown(h.entries, j+1):
h.keys[i] = h.keys[i-1]
h.keys[j] = newKey
inc h.entries
return if h.entries < M: nil else: split(h)
proc add*[Key, Val](b: var BTree[Key, Val]; key: Key; val: Val) =
let u = insert(b.root, key, val)
inc b.entries
if u == nil: return
# need to split root
let t = Node[Key, Val](entries: 2, isInternal: true)
t.keys[0] = b.root.keys[0]
t.links[0] = b.root
t.keys[1] = u.keys[0]
t.links[1] = u
b.root = t
proc toString[Key, Val](h: Node[Key, Val], indent: string; result: var string) =
if not h.isInternal:
for j in 0..<h.entries:
result.add(indent)
result.add($h.keys[j] & " " & $h.vals[j] & "\n")
else:
for j in 0..<h.entries:
if j > 0: result.add(indent & "(" & $h.keys[j] & ")\n")
toString(h.links[j], indent & " ", result)
proc `$`[Key, Val](b: BTree[Key, Val]): string =
result = ""
toString(b.root, "", result)
proc hasNext*[Key, Val](b: BTree[Key, Val]; index: int): bool =
result = index < b.entries
proc countSubTree[Key, Val](it: Node[Key, Val]): int =
if it.isInternal:
result = 0
for k in 0..<it.entries:
inc result, countSubTree(it.links[k])
else:
result = it.entries
proc next*[Key, Val](b: BTree[Key, Val]; index: int): (Key, Val, int) =
var it = b.root
var i = index
# navigate to the right leaf:
while it.isInternal:
var sum = 0
for k in 0..<it.entries:
let c = countSubTree(it.links[k])
inc sum, c
if sum > i:
it = it.links[k]
dec i, (sum - c)
break
result = (it.keys[i], it.vals[i], index+1)
iterator pairs*[Key, Val](b: BTree[Key, Val]): (Key, Val) =
var i = 0
while hasNext(b, i):
let (k, v, i2) = next(b, i)
i = i2
yield (k, v)
proc len*[Key, Val](b: BTree[Key, Val]): int {.inline.} = b.entries
when isMainModule:
import random, tables
proc main =
var st = initBTree[string, string]()
st.add("www.cs.princeton.edu", "abc")
st.add("www.princeton.edu", "128.112.128.15")
st.add("www.yale.edu", "130.132.143.21")
st.add("www.simpsons.com", "209.052.165.60")
st.add("www.apple.com", "17.112.152.32")
st.add("www.amazon.com", "207.171.182.16")
st.add("www.ebay.com", "66.135.192.87")
st.add("www.cnn.com", "64.236.16.20")
st.add("www.google.com", "216.239.41.99")
st.add("www.nytimes.com", "199.239.136.200")
st.add("www.microsoft.com", "207.126.99.140")
st.add("www.dell.com", "143.166.224.230")
st.add("www.slashdot.org", "66.35.250.151")
st.add("www.espn.com", "199.181.135.201")
st.add("www.weather.com", "63.111.66.11")
st.add("www.yahoo.com", "216.109.118.65")
assert st.getOrDefault("www.cs.princeton.edu") == "abc"
assert st.getOrDefault("www.harvardsucks.com") == nil
assert st.getOrDefault("www.simpsons.com") == "209.052.165.60"
assert st.getOrDefault("www.apple.com") == "17.112.152.32"
assert st.getOrDefault("www.ebay.com") == "66.135.192.87"
assert st.getOrDefault("www.dell.com") == "143.166.224.230"
assert(st.entries == 16)
for k, v in st:
echo k, ": ", v
when false:
var b2 = initBTree[string, string]()
const iters = 10_000
for i in 1..iters:
b2.add($i, $(iters - i))
for i in 1..iters:
let x = b2.getOrDefault($i)
if x != $(iters - i):
echo "got ", x, ", but expected ", iters - i
echo b2.entries
when true:
var b2 = initBTree[int, string]()
var t2 = initTable[int, string]()
const iters = 100_000
for i in 1..iters:
let x = rand(high(int))
if not t2.hasKey(x):
doAssert b2.getOrDefault(x).len == 0, " what, tree has this element " & $x
t2[x] = $x
b2.add(x, $x)
doAssert b2.entries == t2.len
echo "unique entries ", b2.entries
for k, v in t2:
doAssert $k == v
doAssert b2.getOrDefault(k) == $k
main()

View file

@ -24,7 +24,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
# getUniqueType() is too expensive here: # getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst) var typ = skipTypes(ri.sons[0].typ, abstractInst)
if typ.sons[0] != nil: if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]): if isInvalidReturnType(p.config, typ.sons[0]):
if params != nil: pl.add(~", ") if params != nil: pl.add(~", ")
# beware of 'result = p(result)'. We may need to allocate a temporary: # beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri): if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
@ -33,13 +33,13 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
elif d.k notin {locTemp} and not hasNoInit(ri): elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var: # reset before pass as 'result' var:
discard "resetLoc(p, d)" discard "resetLoc(p, d)"
add(pl, addrLoc(d)) add(pl, addrLoc(p.config, d))
add(pl, ~");$n") add(pl, ~");$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ.sons[0], tmp, needsInit=true) getTemp(p, typ.sons[0], tmp, needsInit=true)
add(pl, addrLoc(tmp)) add(pl, addrLoc(p.config, tmp))
add(pl, ~");$n") add(pl, ~");$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
@ -101,7 +101,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
let ty = skipTypes(a.t, abstractVar+{tyPtr}) let ty = skipTypes(a.t, abstractVar+{tyPtr})
case ty.kind case ty.kind
of tyArray: of tyArray:
let first = firstOrd(ty) let first = firstOrd(p.config, ty)
if first == 0: if first == 0:
result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)] result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
else: else:
@ -128,13 +128,13 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
else: else:
result = "$1->data, ($1 ? $1->$2 : 0)" % [a.rdLoc, lenField(p)] result = "$1->data, ($1 ? $1->$2 : 0)" % [a.rdLoc, lenField(p)]
of tyArray: of tyArray:
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))] result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
of tyPtr, tyRef: of tyPtr, tyRef:
case lastSon(a.t).kind case lastSon(a.t).kind
of tyString, tySequence: of tyString, tySequence:
result = "(*$1)->data, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p)] result = "(*$1)->data, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p)]
of tyArray: of tyArray:
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))] result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))]
else: else:
internalError(p.config, "openArrayLoc: " & typeToString(a.t)) internalError(p.config, "openArrayLoc: " & typeToString(a.t))
else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) else: internalError(p.config, "openArrayLoc: " & typeToString(a.t))
@ -151,9 +151,9 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
var n = if n.kind != nkHiddenAddr: n else: n.sons[0] var n = if n.kind != nkHiddenAddr: n else: n.sons[0]
result = openArrayLoc(p, n) result = openArrayLoc(p, n)
elif ccgIntroducedPtr(param): elif ccgIntroducedPtr(p.config, param):
initLocExpr(p, n, a) initLocExpr(p, n, a)
result = addrLoc(a) result = addrLoc(p.config, a)
elif p.module.compileToCpp and param.typ.kind == tyVar and elif p.module.compileToCpp and param.typ.kind == tyVar and
n.kind == nkHiddenAddr: n.kind == nkHiddenAddr:
initLocExprSingleUse(p, n.sons[0], a) initLocExprSingleUse(p, n.sons[0], a)
@ -163,7 +163,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
if callee.kind == nkSym and if callee.kind == nkSym and
{sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and
{lfHeader, lfNoDecl} * callee.sym.loc.flags != {}: {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
result = addrLoc(a) result = addrLoc(p.config, a)
else: else:
result = rdLoc(a) result = rdLoc(a)
else: else:
@ -230,7 +230,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
let rawProc = getRawProcType(p, typ) let rawProc = getRawProcType(p, typ)
let callPattern = if tfIterator in typ.flags: PatIter else: PatProc let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
if typ.sons[0] != nil: if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]): if isInvalidReturnType(p.config, typ.sons[0]):
if sonsLen(ri) > 1: add(pl, ~", ") if sonsLen(ri) > 1: add(pl, ~", ")
# beware of 'result = p(result)'. We may need to allocate a temporary: # beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri): if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
@ -240,12 +240,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
elif d.k notin {locTemp} and not hasNoInit(ri): elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var: # reset before pass as 'result' var:
discard "resetLoc(p, d)" discard "resetLoc(p, d)"
add(pl, addrLoc(d)) add(pl, addrLoc(p.config, d))
genCallPattern() genCallPattern()
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ.sons[0], tmp, needsInit=true) getTemp(p, typ.sons[0], tmp, needsInit=true)
add(pl, addrLoc(tmp)) add(pl, addrLoc(p.config, tmp))
genCallPattern() genCallPattern()
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
else: else:
@ -508,20 +508,20 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
add(pl, ~": ") add(pl, ~": ")
add(pl, genArg(p, ri.sons[i], param, ri)) add(pl, genArg(p, ri.sons[i], param, ri))
if typ.sons[0] != nil: if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]): if isInvalidReturnType(p.config, typ.sons[0]):
if sonsLen(ri) > 1: add(pl, ~" ") if sonsLen(ri) > 1: add(pl, ~" ")
# beware of 'result = p(result)'. We always allocate a temporary: # beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}: if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it: # We already got a temp. Great, special case it:
if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true) if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
add(pl, ~"Result: ") add(pl, ~"Result: ")
add(pl, addrLoc(d)) add(pl, addrLoc(p.config, d))
add(pl, ~"];$n") add(pl, ~"];$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ.sons[0], tmp, needsInit=true) getTemp(p, typ.sons[0], tmp, needsInit=true)
add(pl, addrLoc(tmp)) add(pl, addrLoc(p.config, tmp))
add(pl, ~"];$n") add(pl, ~"];$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying

View file

@ -114,8 +114,8 @@ proc genRawSetData(cs: TBitSet, size: int): Rope =
proc genSetNode(p: BProc, n: PNode): Rope = proc genSetNode(p: BProc, n: PNode): Rope =
var cs: TBitSet var cs: TBitSet
var size = int(getSize(n.typ)) var size = int(getSize(p.config, n.typ))
toBitSet(n, cs) toBitSet(p.config, n, cs)
if size > 8: if size > 8:
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
result = p.module.tmpBase & rope(id) result = p.module.tmpBase & rope(id)
@ -185,13 +185,13 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# lineF(p, cpsStmts, '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]) # lineF(p, cpsStmts, '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
if canFormAcycle(dest.t): if canFormAcycle(dest.t):
linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n", linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n",
addrLoc(dest), rdLoc(src)) addrLoc(p.config, dest), rdLoc(src))
else: else:
linefmt(p, cpsStmts, "#asgnRefNoCycle((void**) $1, $2);$n", linefmt(p, cpsStmts, "#asgnRefNoCycle((void**) $1, $2);$n",
addrLoc(dest), rdLoc(src)) addrLoc(p.config, dest), rdLoc(src))
else: else:
linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n",
addrLoc(dest), rdLoc(src)) addrLoc(p.config, dest), rdLoc(src))
proc asgnComplexity(n: PNode): int = proc asgnComplexity(n: PNode): int =
if n != nil: if n != nil:
@ -260,13 +260,13 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
useStringh(p.module) useStringh(p.module)
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
addrLoc(dest), addrLoc(src), rdLoc(dest)) addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest))
else: else:
linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n", linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n",
addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t, dest.lode.info)) addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info))
else: else:
linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n", linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t, dest.lode.info)) addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info))
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# This function replaces all other methods for generating # This function replaces all other methods for generating
@ -284,7 +284,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
genRefAssign(p, dest, src, flags) genRefAssign(p, dest, src, flags)
else: else:
linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
addrLoc(dest), rdLoc(src), addrLoc(p.config, dest), rdLoc(src),
genTypeInfo(p.module, dest.t, dest.lode.info)) genTypeInfo(p.module, dest.t, dest.lode.info))
of tyString: of tyString:
if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode): if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
@ -301,7 +301,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", tmp.rdLoc) linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", tmp.rdLoc)
else: else:
linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n", linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
addrLoc(dest), rdLoc(src)) addrLoc(p.config, dest), rdLoc(src))
of tyProc: of tyProc:
if needsComplexAssignment(dest.t): if needsComplexAssignment(dest.t):
# optimize closure assignment: # optimize closure assignment:
@ -346,7 +346,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if needsComplexAssignment(dest.t): if needsComplexAssignment(dest.t):
linefmt(p, cpsStmts, # XXX: is this correct for arrays? linefmt(p, cpsStmts, # XXX: is this correct for arrays?
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
addrLoc(dest), addrLoc(src), addrLoc(p.config, dest), addrLoc(p.config, src),
genTypeInfo(p.module, dest.t, dest.lode.info)) genTypeInfo(p.module, dest.t, dest.lode.info))
else: else:
useStringh(p.module) useStringh(p.module)
@ -356,10 +356,10 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
"$1 = $2;$n", "$1 = $2;$n",
rdLoc(dest), rdLoc(src)) rdLoc(dest), rdLoc(src))
of tySet: of tySet:
if mapType(ty) == ctArray: if mapType(p.config, ty) == ctArray:
useStringh(p.module) useStringh(p.module)
linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n", linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n",
rdLoc(dest), rdLoc(src), rope(getSize(dest.t))) rdLoc(dest), rdLoc(src), rope(getSize(p.config, dest.t)))
else: else:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString, of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString,
@ -371,8 +371,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
#writeStackTrace() #writeStackTrace()
#echo p.currLineInfo, " requesting" #echo p.currLineInfo, " requesting"
linefmt(p, cpsStmts, "#memTrackerWrite((void*)$1, $2, $3, $4);$n", linefmt(p, cpsStmts, "#memTrackerWrite((void*)$1, $2, $3, $4);$n",
addrLoc(dest), rope getSize(dest.t), addrLoc(p.config, dest), rope getSize(p.config, dest.t),
makeCString(p.currLineInfo.toFullPath), makeCString(toFullPath(p.config, p.currLineInfo)),
rope p.currLineInfo.safeLineNm) rope p.currLineInfo.safeLineNm)
proc genDeepCopy(p: BProc; dest, src: TLoc) = proc genDeepCopy(p: BProc; dest, src: TLoc) =
@ -381,31 +381,31 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
var tmp: TLoc var tmp: TLoc
getTemp(p, a.t, tmp) getTemp(p, a.t, tmp)
genAssignment(p, tmp, a, {}) genAssignment(p, tmp, a, {})
addrLoc(tmp) addrLoc(p.config, tmp)
else: else:
addrLoc(a) addrLoc(p.config, a)
var ty = skipTypes(dest.t, abstractVarRange) var ty = skipTypes(dest.t, abstractVarRange)
case ty.kind case ty.kind
of tyPtr, tyRef, tyProc, tyTuple, tyObject, tyArray: of tyPtr, tyRef, tyProc, tyTuple, tyObject, tyArray:
# XXX optimize this # XXX optimize this
linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n",
addrLoc(dest), addrLocOrTemp(src), addrLoc(p.config, dest), addrLocOrTemp(src),
genTypeInfo(p.module, dest.t, dest.lode.info)) genTypeInfo(p.module, dest.t, dest.lode.info))
of tySequence, tyString: of tySequence, tyString:
linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n", linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n",
addrLoc(dest), rdLoc(src), addrLoc(p.config, dest), rdLoc(src),
genTypeInfo(p.module, dest.t, dest.lode.info)) genTypeInfo(p.module, dest.t, dest.lode.info))
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
addrLoc(dest), addrLocOrTemp(src), addrLoc(p.config, dest), addrLocOrTemp(src),
genTypeInfo(p.module, dest.t, dest.lode.info)) genTypeInfo(p.module, dest.t, dest.lode.info))
of tySet: of tySet:
if mapType(ty) == ctArray: if mapType(p.config, ty) == ctArray:
useStringh(p.module) useStringh(p.module)
linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n", linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n",
rdLoc(dest), rdLoc(src), rope(getSize(dest.t))) rdLoc(dest), rdLoc(src), rope(getSize(p.config, dest.t)))
else: else:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
of tyPointer, tyChar, tyBool, tyEnum, tyCString, of tyPointer, tyChar, tyBool, tyEnum, tyCString,
@ -491,15 +491,15 @@ proc unaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc; proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc;
frmt: string): Rope = frmt: string): Rope =
var size = getSize(t) var size = getSize(p.config, t)
let storage = if size < platform.intSize: rope("NI") let storage = if size < p.config.target.intSize: rope("NI")
else: getTypeDesc(p.module, t) else: getTypeDesc(p.module, t)
result = getTempName(p.module) result = getTempName(p.module)
linefmt(p, cpsLocals, "$1 $2;$n", storage, result) linefmt(p, cpsLocals, "$1 $2;$n", storage, result)
lineCg(p, cpsStmts, frmt, result, rdCharLoc(a), rdCharLoc(b)) lineCg(p, cpsStmts, frmt, result, rdCharLoc(a), rdCharLoc(b))
if size < platform.intSize or t.kind in {tyRange, tyEnum}: if size < p.config.target.intSize or t.kind in {tyRange, tyEnum}:
linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n", linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n",
result, intLiteral(firstOrd(t)), intLiteral(lastOrd(t))) result, intLiteral(firstOrd(p.config, t)), intLiteral(lastOrd(p.config, t)))
proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
const const
@ -547,8 +547,8 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
t = skipTypes(e.typ, abstractRange) t = skipTypes(e.typ, abstractRange)
if optOverflowCheck in p.options: if optOverflowCheck in p.options:
linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n", linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n",
rdLoc(a), intLiteral(firstOrd(t))) rdLoc(a), intLiteral(firstOrd(p.config, t)))
putIntoDest(p, d, e, opr[m] % [rdLoc(a), rope(getSize(t) * 8)]) putIntoDest(p, d, e, opr[m] % [rdLoc(a), rope(getSize(p.config, t) * 8)])
proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
const const
@ -604,8 +604,8 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
# BUGFIX: cannot use result-type here, as it may be a boolean # BUGFIX: cannot use result-type here, as it may be a boolean
s = max(getSize(a.t), getSize(b.t)) * 8 s = max(getSize(p.config, a.t), getSize(p.config, b.t)) * 8
k = getSize(a.t) * 8 k = getSize(p.config, a.t) * 8
putIntoDest(p, d, e, putIntoDest(p, d, e,
binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s), binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s),
getSimpleTypeDesc(p.module, e.typ), rope(k)]) getSimpleTypeDesc(p.module, e.typ), rope(k)])
@ -658,7 +658,7 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
t = skipTypes(e.typ, abstractRange) t = skipTypes(e.typ, abstractRange)
putIntoDest(p, d, e, putIntoDest(p, d, e,
unArithTab[op] % [rdLoc(a), rope(getSize(t) * 8), unArithTab[op] % [rdLoc(a), rope(getSize(p.config, t) * 8),
getSimpleTypeDesc(p.module, e.typ)]) getSimpleTypeDesc(p.module, e.typ)])
proc isCppRef(p: BProc; typ: PType): bool {.inline.} = proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
@ -667,7 +667,7 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
tfVarIsPtr notin skipTypes(typ, abstractInst).flags tfVarIsPtr notin skipTypes(typ, abstractInst).flags
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
let mt = mapType(e.sons[0].typ) let mt = mapType(p.config, e.sons[0].typ)
if mt in {ctArray, ctPtrToArray} and not enforceDeref: if mt in {ctArray, ctPtrToArray} and not enforceDeref:
# XXX the amount of hacks for C's arrays is incredible, maybe we should # XXX the amount of hacks for C's arrays is incredible, maybe we should
# simply wrap them in a struct? --> Losing auto vectorization then? # simply wrap them in a struct? --> Losing auto vectorization then?
@ -726,12 +726,12 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
putIntoDest(p, d, e, "&" & a.r, a.storage) putIntoDest(p, d, e, "&" & a.r, a.storage)
#Message(e.info, warnUser, "HERE NEW &") #Message(e.info, warnUser, "HERE NEW &")
elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ): elif mapType(p.config, e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ):
expr(p, e.sons[0], d) expr(p, e.sons[0], d)
else: else:
var a: TLoc var a: TLoc
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
putIntoDest(p, d, e, addrLoc(a), a.storage) putIntoDest(p, d, e, addrLoc(p.config, a), a.storage)
template inheritLocation(d: var TLoc, a: TLoc) = template inheritLocation(d: var TLoc, a: TLoc) =
if d.k == locNone: d.storage = a.storage if d.k == locNone: d.storage = a.storage
@ -828,7 +828,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
if optFieldCheck in p.options: if optFieldCheck in p.options:
var a: TLoc var a: TLoc
genRecordFieldAux(p, e.sons[0], d, a) genRecordFieldAux(p, e.sons[0], d, a)
let ty = skipTypes(a.t, abstractInst) let ty = skipTypes(a.t, abstractInst + tyUserTypeClasses)
var r = rdLoc(a) var r = rdLoc(a)
let f = e.sons[0].sons[1].sym let f = e.sons[0].sons[1].sym
let field = lookupFieldAgain(p, ty, f, r) let field = lookupFieldAgain(p, ty, f, r)
@ -846,21 +846,21 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
initLocExpr(p, x, a) initLocExpr(p, x, a)
initLocExpr(p, y, b) initLocExpr(p, y, b)
var ty = skipTypes(a.t, abstractVarRange + abstractPtrs + tyUserTypeClasses) var ty = skipTypes(a.t, abstractVarRange + abstractPtrs + tyUserTypeClasses)
var first = intLiteral(firstOrd(ty)) var first = intLiteral(firstOrd(p.config, ty))
# emit range check: # emit range check:
if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags: if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
if not isConstExpr(y): if not isConstExpr(y):
# semantic pass has already checked for const index expressions # semantic pass has already checked for const index expressions
if firstOrd(ty) == 0: if firstOrd(p.config, ty) == 0:
if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)): if (firstOrd(p.config, b.t) < firstOrd(p.config, ty)) or (lastOrd(p.config, b.t) > lastOrd(p.config, ty)):
linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError();$n", linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError();$n",
rdCharLoc(b), intLiteral(lastOrd(ty))) rdCharLoc(b), intLiteral(lastOrd(p.config, ty)))
else: else:
linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n", linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
rdCharLoc(b), first, intLiteral(lastOrd(ty))) rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)))
else: else:
let idx = getOrdValue(y) let idx = getOrdValue(y)
if idx < firstOrd(ty) or idx > lastOrd(ty): if idx < firstOrd(p.config, ty) or idx > lastOrd(p.config, ty):
localError(p.config, x.info, "index out of bounds") localError(p.config, x.info, "index out of bounds")
d.inheritLocation(a) d.inheritLocation(a)
putIntoDest(p, d, n, putIntoDest(p, d, n,
@ -884,12 +884,12 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
"((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))) #raiseIndexError();$n", "((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))) #raiseIndexError();$n",
rdLoc(a), rdLoc(b), rdLoc(arr)) rdLoc(a), rdLoc(b), rdLoc(arr))
of tyArray: of tyArray:
let first = intLiteral(firstOrd(ty)) let first = intLiteral(firstOrd(p.config, ty))
if tfUncheckedArray notin ty.flags: if tfUncheckedArray notin ty.flags:
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " & "if ($2-$1 != -1 && " &
"($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n", "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n",
rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(ty))) rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)))
of tySequence, tyString: of tySequence, tyString:
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " & "if ($2-$1 != -1 && " &
@ -985,7 +985,7 @@ proc genEcho(p: BProc, n: PNode) =
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)`` # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
# is threadsafe. # is threadsafe.
internalAssert p.config, n.kind == nkBracket internalAssert p.config, n.kind == nkBracket
if platform.targetOS == osGenode: if p.config.target.targetOS == osGenode:
# bypass libc and print directly to the Genode LOG session # bypass libc and print directly to the Genode LOG session
var args: Rope = nil var args: Rope = nil
var a: TLoc var a: TLoc
@ -1007,7 +1007,7 @@ proc genEcho(p: BProc, n: PNode) =
when false: when false:
p.module.includeHeader("<stdio.h>") p.module.includeHeader("<stdio.h>")
linefmt(p, cpsStmts, "printf($1$2);$n", linefmt(p, cpsStmts, "printf($1$2);$n",
makeCString(repeat("%s", n.len) & tnl), args) makeCString(repeat("%s", n.len) & "\L"), args)
linefmt(p, cpsStmts, "fflush(stdout);$n") linefmt(p, cpsStmts, "fflush(stdout);$n")
proc gcUsage(conf: ConfigRef; n: PNode) = proc gcUsage(conf: ConfigRef; n: PNode) =
@ -1121,7 +1121,7 @@ proc genReset(p: BProc, n: PNode) =
var a: TLoc var a: TLoc
initLocExpr(p, n.sons[1], a) initLocExpr(p, n.sons[1], a)
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(a), addrLoc(p.config, a),
genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)) genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info))
proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) = proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
@ -1306,7 +1306,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
if d.k == locNone: if d.k == locNone:
getTemp(p, n.typ, d) getTemp(p, n.typ, d)
# generate call to newSeq before adding the elements per hand: # generate call to newSeq before adding the elements per hand:
let L = int(lengthOrd(n.sons[1].typ)) let L = int(lengthOrd(p.config, n.sons[1].typ))
genNewSeqAux(p, d, intLiteral(L)) genNewSeqAux(p, d, intLiteral(L))
initLocExpr(p, n.sons[1], a) initLocExpr(p, n.sons[1], a)
# bug #5007; do not produce excessive C source code: # bug #5007; do not produce excessive C source code:
@ -1420,7 +1420,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage) putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage)
of tySet: of tySet:
putIntoDest(p, d, e, ropecg(p.module, "#reprSet($1, $2)", [ putIntoDest(p, d, e, ropecg(p.module, "#reprSet($1, $2)", [
addrLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage) addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]), a.storage)
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
var b: TLoc var b: TLoc
case a.t.kind case a.t.kind
@ -1431,7 +1431,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
"$1->data, ($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)], a.storage) "$1->data, ($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)], a.storage)
of tyArray: of tyArray:
putIntoDest(p, b, e, putIntoDest(p, b, e,
"$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))], a.storage) "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))], a.storage)
else: internalError(p.config, e.sons[0].info, "genRepr()") else: internalError(p.config, e.sons[0].info, "genRepr()")
putIntoDest(p, d, e, putIntoDest(p, d, e,
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b), ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
@ -1444,7 +1444,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
localError(p.config, e.info, "'repr' doesn't support 'void' type") localError(p.config, e.info, "'repr' doesn't support 'void' type")
else: else:
putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)", putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)",
[addrLoc(a), genTypeInfo(p.module, t, e.info)]), [addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]),
a.storage) a.storage)
gcUsage(p.config, e) gcUsage(p.config, e)
@ -1498,8 +1498,8 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
putIntoDest(p, d, e, tmp.r) putIntoDest(p, d, e, tmp.r)
of tyArray: of tyArray:
# YYY: length(sideeffect) is optimized away incorrectly? # YYY: length(sideeffect) is optimized away incorrectly?
if op == mHigh: putIntoDest(p, d, e, rope(lastOrd(typ))) if op == mHigh: putIntoDest(p, d, e, rope(lastOrd(p.config, typ)))
else: putIntoDest(p, d, e, rope(lengthOrd(typ))) else: putIntoDest(p, d, e, rope(lengthOrd(p.config, typ)))
else: internalError(p.config, e.info, "genArrayLen()") else: internalError(p.config, e.info, "genArrayLen()")
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
@ -1537,19 +1537,19 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) =
genAssignment(p, a, b, {}) genAssignment(p, a, b, {})
genAssignment(p, b, tmp, {}) genAssignment(p, b, tmp, {})
proc rdSetElemLoc(a: TLoc, setType: PType): Rope = proc rdSetElemLoc(conf: ConfigRef; a: TLoc, setType: PType): Rope =
# read a location of an set element; it may need a subtraction operation # read a location of an set element; it may need a subtraction operation
# before the set operation # before the set operation
result = rdCharLoc(a) result = rdCharLoc(a)
assert(setType.kind == tySet) assert(setType.kind == tySet)
if firstOrd(setType) != 0: if firstOrd(conf, setType) != 0:
result = "($1- $2)" % [result, rope(firstOrd(setType))] result = "($1- $2)" % [result, rope(firstOrd(conf, setType))]
proc fewCmps(s: PNode): bool = proc fewCmps(conf: ConfigRef; s: PNode): bool =
# this function estimates whether it is better to emit code # this function estimates whether it is better to emit code
# for constructing the set or generating a bunch of comparisons directly # for constructing the set or generating a bunch of comparisons directly
if s.kind != nkCurly: return false if s.kind != nkCurly: return false
if (getSize(s.typ) <= platform.intSize) and (nfAllConst in s.flags): if (getSize(conf, s.typ) <= conf.target.intSize) and (nfAllConst in s.flags):
result = false # it is better to emit the set generation code result = false # it is better to emit the set generation code
elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}: elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}:
result = true # better not emit the set if int is basetype! result = true # better not emit the set if int is basetype!
@ -1557,10 +1557,10 @@ proc fewCmps(s: PNode): bool =
result = sonsLen(s) <= 8 # 8 seems to be a good value result = sonsLen(s) <= 8 # 8 seems to be a good value
proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) = proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
putIntoDest(p, d, e, frmt % [rdLoc(a), rdSetElemLoc(b, a.t)]) putIntoDest(p, d, e, frmt % [rdLoc(a), rdSetElemLoc(p.config, b, a.t)])
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) = proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
case int(getSize(skipTypes(e.sons[1].typ, abstractVar))) case int(getSize(p.config, skipTypes(e.sons[1].typ, abstractVar)))
of 1: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&7U)))!=0)") of 1: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&7U)))!=0)")
of 2: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&15U)))!=0)") of 2: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&15U)))!=0)")
of 4: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&31U)))!=0)") of 4: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&31U)))!=0)")
@ -1572,11 +1572,11 @@ proc binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) =
assert(d.k == locNone) assert(d.k == locNone)
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
lineF(p, cpsStmts, frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]) lineF(p, cpsStmts, frmt, [rdLoc(a), rdSetElemLoc(p.config, b, a.t)])
proc genInOp(p: BProc, e: PNode, d: var TLoc) = proc genInOp(p: BProc, e: PNode, d: var TLoc) =
var a, b, x, y: TLoc var a, b, x, y: TLoc
if (e.sons[1].kind == nkCurly) and fewCmps(e.sons[1]): if (e.sons[1].kind == nkCurly) and fewCmps(p.config, e.sons[1]):
# a set constructor but not a constant set: # a set constructor but not a constant set:
# do not emit the set, but generate a bunch of comparisons; and if we do # do not emit the set, but generate a bunch of comparisons; and if we do
# so, we skip the unnecessary range check: This is a semantical extension # so, we skip the unnecessary range check: This is a semantical extension
@ -1620,7 +1620,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
"&", "|", "& ~", "^"] "&", "|", "& ~", "^"]
var a, b, i: TLoc var a, b, i: TLoc
var setType = skipTypes(e.sons[1].typ, abstractVar) var setType = skipTypes(e.sons[1].typ, abstractVar)
var size = int(getSize(setType)) var size = int(getSize(p.config, setType))
case size case size
of 1, 2, 4, 8: of 1, 2, 4, 8:
case op case op
@ -1687,7 +1687,7 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
let etyp = skipTypes(e.typ, abstractRange) let etyp = skipTypes(e.typ, abstractRange)
if etyp.kind in ValueTypes and lfIndirect notin a.flags: if etyp.kind in ValueTypes and lfIndirect notin a.flags:
putIntoDest(p, d, e, "(*($1*) ($2))" % putIntoDest(p, d, e, "(*($1*) ($2))" %
[getTypeDesc(p.module, e.typ), addrLoc(a)], a.storage) [getTypeDesc(p.module, e.typ), addrLoc(p.config, a)], a.storage)
elif etyp.kind == tyProc and etyp.callConv == ccClosure: elif etyp.kind == tyProc and etyp.callConv == ccClosure:
putIntoDest(p, d, e, "(($1) ($2))" % putIntoDest(p, d, e, "(($1) ($2))" %
[getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)], a.storage) [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)], a.storage)
@ -1924,7 +1924,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
putIntoDest(p, d, e, genSetNode(p, e)) putIntoDest(p, d, e, genSetNode(p, e))
else: else:
if d.k == locNone: getTemp(p, e.typ, d) if d.k == locNone: getTemp(p, e.typ, d)
if getSize(e.typ) > 8: if getSize(p.config, e.typ) > 8:
# big set: # big set:
useStringh(p.module) useStringh(p.module)
lineF(p, cpsStmts, "memset($1, 0, sizeof($2));$n", lineF(p, cpsStmts, "memset($1, 0, sizeof($2));$n",
@ -1936,14 +1936,14 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, it.sons[1], b) initLocExpr(p, it.sons[1], b)
lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" & lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
"$2[(NU)($1)>>3] |=(1U<<((NU)($1)&7U));$n", [rdLoc(idx), rdLoc(d), "$2[(NU)($1)>>3] |=(1U<<((NU)($1)&7U));$n", [rdLoc(idx), rdLoc(d),
rdSetElemLoc(a, e.typ), rdSetElemLoc(b, e.typ)]) rdSetElemLoc(p.config, a, e.typ), rdSetElemLoc(p.config, b, e.typ)])
else: else:
initLocExpr(p, it, a) initLocExpr(p, it, a)
lineF(p, cpsStmts, "$1[(NU)($2)>>3] |=(1U<<((NU)($2)&7U));$n", lineF(p, cpsStmts, "$1[(NU)($2)>>3] |=(1U<<((NU)($2)&7U));$n",
[rdLoc(d), rdSetElemLoc(a, e.typ)]) [rdLoc(d), rdSetElemLoc(p.config, a, e.typ)])
else: else:
# small set # small set
var ts = "NU" & $(getSize(e.typ) * 8) var ts = "NU" & $(getSize(p.config, e.typ) * 8)
lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(d)]) lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(d)])
for it in e.sons: for it in e.sons:
if it.kind == nkRange: if it.kind == nkRange:
@ -1952,13 +1952,13 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, it.sons[1], b) initLocExpr(p, it.sons[1], b)
lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" & lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
"$2 |=((" & ts & ")(1)<<(($1)%(sizeof(" & ts & ")*8)));$n", [ "$2 |=((" & ts & ")(1)<<(($1)%(sizeof(" & ts & ")*8)));$n", [
rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ), rdLoc(idx), rdLoc(d), rdSetElemLoc(p.config, a, e.typ),
rdSetElemLoc(b, e.typ)]) rdSetElemLoc(p.config, b, e.typ)])
else: else:
initLocExpr(p, it, a) initLocExpr(p, it, a)
lineF(p, cpsStmts, lineF(p, cpsStmts,
"$1 |=((" & ts & ")(1)<<(($2)%(sizeof(" & ts & ")*8)));$n", "$1 |=((" & ts & ")(1)<<(($2)%(sizeof(" & ts & ")*8)));$n",
[rdLoc(d), rdSetElemLoc(a, e.typ)]) [rdLoc(d), rdSetElemLoc(p.config, a, e.typ)])
proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
var rec: TLoc var rec: TLoc
@ -2076,7 +2076,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
"(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage)
else: else:
putIntoDest(p, d, n, "(*($1*) ($2))" % putIntoDest(p, d, n, "(*($1*) ($2))" %
[getTypeDesc(p.module, dest), addrLoc(a)], a.storage) [getTypeDesc(p.module, dest), addrLoc(p.config, a)], a.storage)
proc downConv(p: BProc, n: PNode, d: var TLoc) = proc downConv(p: BProc, n: PNode, d: var TLoc) =
if p.module.compileToCpp: if p.module.compileToCpp:
@ -2297,7 +2297,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
incl a.flags, lfSingleUse incl a.flags, lfSingleUse
genCall(p, ex, a) genCall(p, ex, a)
if lfSingleUse notin a.flags: if lfSingleUse notin a.flags:
line(p, cpsStmts, a.r & ";" & tnl) line(p, cpsStmts, a.r & ";\L")
else: else:
initLocExpr(p, ex, a) initLocExpr(p, ex, a)
of nkAsmStmt: genAsmStmt(p, n) of nkAsmStmt: genAsmStmt(p, n)
@ -2313,7 +2313,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
genTypeSection(p.module, n) genTypeSection(p.module, n)
of nkCommentStmt, nkIteratorDef, nkIncludeStmt, of nkCommentStmt, nkIteratorDef, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef: nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt:
discard discard
of nkPragma: genPragma(p, n) of nkPragma: genPragma(p, n)
of nkPragmaBlock: expr(p, n.lastSon, d) of nkPragmaBlock: expr(p, n.lastSon, d)
@ -2367,7 +2367,7 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
result.add "}" result.add "}"
of tyArray: result = rope"{}" of tyArray: result = rope"{}"
of tySet: of tySet:
if mapType(t) == ctArray: result = rope"{}" if mapType(p.config, t) == ctArray: result = rope"{}"
else: result = rope"0" else: result = rope"0"
else: else:
globalError(p.config, info, "cannot create null element for: " & $t.kind) globalError(p.config, info, "cannot create null element for: " & $t.kind)
@ -2464,8 +2464,8 @@ proc genConstExpr(p: BProc, n: PNode): Rope =
result = genConstExpr(p, n.sons[1]) result = genConstExpr(p, n.sons[1])
of nkCurly: of nkCurly:
var cs: TBitSet var cs: TBitSet
toBitSet(n, cs) toBitSet(p.config, n, cs)
result = genRawSetData(cs, int(getSize(n.typ))) result = genRawSetData(cs, int(getSize(p.config, n.typ)))
of nkBracket, nkPar, nkTupleConstr, nkClosure: of nkBracket, nkPar, nkTupleConstr, nkClosure:
var t = skipTypes(n.typ, abstractInst) var t = skipTypes(n.typ, abstractInst)
if t.kind == tySequence: if t.kind == tySequence:

View file

@ -47,34 +47,32 @@ const
proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope = proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf): if compilationCachePresent(conf):
result = rope(tnl) result = nil
add(result, "/*\t") add(result, "\n/*\t")
add(result, CFileSectionNames[fs]) add(result, CFileSectionNames[fs])
add(result, ":*/") add(result, ":*/\n")
add(result, tnl)
proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope = proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf): if compilationCachePresent(conf):
result = rope(NimMergeEndMark & tnl) result = rope(NimMergeEndMark & "\n")
proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope = proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf): if compilationCachePresent(conf):
result = rope(tnl) result = rope(nil)
add(result, "/*\t") add(result, "\n/*\t")
add(result, CProcSectionNames[ps]) add(result, CProcSectionNames[ps])
add(result, ":*/") add(result, ":*/\n")
add(result, tnl)
proc genSectionEnd*(ps: TCProcSection; conf: ConfigRef): Rope = proc genSectionEnd*(ps: TCProcSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf): if compilationCachePresent(conf):
result = rope(NimMergeEndMark & tnl) result = rope(NimMergeEndMark & "\n")
proc writeTypeCache(a: TypeCache, s: var string) = proc writeTypeCache(a: TypeCache, s: var string) =
var i = 0 var i = 0
for id, value in pairs(a): for id, value in pairs(a):
if i == 10: if i == 10:
i = 0 i = 0
s.add(tnl) s.add('\L')
else: else:
s.add(' ') s.add(' ')
encodeStr($id, s) encodeStr($id, s)
@ -88,7 +86,7 @@ proc writeIntSet(a: IntSet, s: var string) =
for x in items(a): for x in items(a):
if i == 10: if i == 10:
i = 0 i = 0
s.add(tnl) s.add('\L')
else: else:
s.add(' ') s.add(' ')
encodeVInt(x, s) encodeVInt(x, s)
@ -97,8 +95,7 @@ proc writeIntSet(a: IntSet, s: var string) =
proc genMergeInfo*(m: BModule): Rope = proc genMergeInfo*(m: BModule): Rope =
if not compilationCachePresent(m.config): return nil if not compilationCachePresent(m.config): return nil
var s = "/*\tNIM_merge_INFO:" var s = "/*\tNIM_merge_INFO:\n"
s.add(tnl)
s.add("typeCache:{") s.add("typeCache:{")
writeTypeCache(m.typeCache, s) writeTypeCache(m.typeCache, s)
s.add("declared:{") s.add("declared:{")
@ -110,8 +107,7 @@ proc genMergeInfo*(m: BModule): Rope =
encodeVInt(m.labels, s) encodeVInt(m.labels, s)
s.add(" flags:") s.add(" flags:")
encodeVInt(cast[int](m.flags), s) encodeVInt(cast[int](m.flags), s)
s.add(tnl) s.add("\n*/")
s.add("*/")
result = s.rope result = s.rope
template `^`(pos: int): untyped = L.buf[pos] template `^`(pos: int): untyped = L.buf[pos]
@ -155,11 +151,11 @@ proc readVerbatimSection(L: var TBaseLexer): Rope =
of CR: of CR:
pos = nimlexbase.handleCR(L, pos) pos = nimlexbase.handleCR(L, pos)
buf = L.buf buf = L.buf
r.add(tnl) r.add('\L')
of LF: of LF:
pos = nimlexbase.handleLF(L, pos) pos = nimlexbase.handleLF(L, pos)
buf = L.buf buf = L.buf
r.add(tnl) r.add('\L')
of '\0': of '\0':
doAssert(false, "ccgmerge: expected: " & NimMergeEndMark) doAssert(false, "ccgmerge: expected: " & NimMergeEndMark)
break break

View file

@ -28,9 +28,9 @@ proc registerGcRoot(p: BProc, v: PSym) =
appcg(p.module, p.module.initProc.procSec(cpsInit), appcg(p.module, p.module.initProc.procSec(cpsInit),
"#nimRegisterGlobalMarker($1);$n", [prc]) "#nimRegisterGlobalMarker($1);$n", [prc])
proc isAssignedImmediately(n: PNode): bool {.inline.} = proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
if n.kind == nkEmpty: return false if n.kind == nkEmpty: return false
if isInvalidReturnType(n.typ): if isInvalidReturnType(conf, n.typ):
# var v = f() # var v = f()
# is transformed into: var v; f(addr v) # is transformed into: var v; f(addr v)
# where 'f' **does not** initialize the result! # where 'f' **does not** initialize the result!
@ -65,7 +65,7 @@ proc genVarTuple(p: BProc, n: PNode) =
registerGcRoot(p, v) registerGcRoot(p, v)
else: else:
assignLocalVar(p, vn) assignLocalVar(p, vn)
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(n[L-1])) initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[L-1]))
initLoc(field, locExpr, vn, tup.storage) initLoc(field, locExpr, vn, tup.storage)
if t.kind == tyTuple: if t.kind == tyTuple:
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)] field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
@ -205,7 +205,7 @@ proc genGotoState(p: BProc, n: PNode) =
howManyTrys = p.nestedTryStmts.len, howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlockLen) howManyExcepts = p.inExceptBlockLen)
lineF(p, cpsStmts, " goto BeforeRet_;$n", []) lineF(p, cpsStmts, " goto BeforeRet_;$n", [])
var statesCounter = lastOrd(n.sons[0].typ) var statesCounter = lastOrd(p.config, n.sons[0].typ)
if n.len >= 2 and n[1].kind == nkIntLit: if n.len >= 2 and n[1].kind == nkIntLit:
statesCounter = n[1].intVal statesCounter = n[1].intVal
let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope
@ -264,7 +264,7 @@ proc genSingleVar(p: BProc, a: PNode) =
registerGcRoot(p, v) registerGcRoot(p, v)
else: else:
let value = a.sons[2] let value = a.sons[2]
let imm = isAssignedImmediately(value) let imm = isAssignedImmediately(p.config, value)
if imm and p.module.compileToCpp and p.splitDecls == 0 and if imm and p.module.compileToCpp and p.splitDecls == 0 and
not containsHiddenPointer(v.typ): not containsHiddenPointer(v.typ):
# C++ really doesn't like things like 'Foo f; f = x' as that invokes a # C++ really doesn't like things like 'Foo f; f = x' as that invokes a
@ -404,12 +404,12 @@ proc genComputedGoto(p: BProc; n: PNode) =
localError(p.config, it.info, localError(p.config, it.info,
"case statement must be exhaustive for computed goto"); return "case statement must be exhaustive for computed goto"); return
casePos = i casePos = i
let aSize = lengthOrd(it.sons[0].typ) let aSize = lengthOrd(p.config, it.sons[0].typ)
if aSize > 10_000: if aSize > 10_000:
localError(p.config, it.info, localError(p.config, it.info,
"case statement has too many cases for computed goto"); return "case statement has too many cases for computed goto"); return
arraySize = aSize.int arraySize = aSize.int
if firstOrd(it.sons[0].typ) != 0: if firstOrd(p.config, it.sons[0].typ) != 0:
localError(p.config, it.info, localError(p.config, it.info,
"case statement has to start at 0 for computed goto"); return "case statement has to start at 0 for computed goto"); return
if casePos < 0: if casePos < 0:
@ -480,7 +480,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label]) lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
var loopBody = t.sons[1] var loopBody = t.sons[1]
if loopBody.stmtsContainPragma(wComputedGoto) and if loopBody.stmtsContainPragma(wComputedGoto) and
hasComputedGoto in CC[cCompiler].props: hasComputedGoto in CC[p.config.cCompiler].props:
# for closure support weird loop bodies are generated: # for closure support weird loop bodies are generated:
if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty: if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
loopBody = loopBody.sons[1] loopBody = loopBody.sons[1]
@ -653,7 +653,7 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
assert(b.sons[i].kind != nkRange) assert(b.sons[i].kind != nkRange)
initLocExpr(p, b.sons[i], x) initLocExpr(p, b.sons[i], x)
assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit}) assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit})
var j = int(hashString(b.sons[i].strVal) and high(branches)) var j = int(hashString(p.config, b.sons[i].strVal) and high(branches))
appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n", appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n",
[rdLoc(e), rdLoc(x), labl]) [rdLoc(e), rdLoc(x), labl])
@ -706,7 +706,7 @@ proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
var stmtBlock = lastSon(branch) var stmtBlock = lastSon(branch)
if stmtBlock.stmtsContainPragma(wLinearScanEnd): if stmtBlock.stmtsContainPragma(wLinearScanEnd):
result = i result = i
elif hasSwitchRange notin CC[cCompiler].props: elif hasSwitchRange notin CC[p.config.cCompiler].props:
if branch.kind == nkOfBranch and branchHasTooBigRange(branch): if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
result = i result = i
@ -714,7 +714,7 @@ proc genCaseRange(p: BProc, branch: PNode) =
var length = branch.len var length = branch.len
for j in 0 .. length-2: for j in 0 .. length-2:
if branch[j].kind == nkRange: if branch[j].kind == nkRange:
if hasSwitchRange in CC[cCompiler].props: if hasSwitchRange in CC[p.config.cCompiler].props:
lineF(p, cpsStmts, "case $1 ... $2:$n", [ lineF(p, cpsStmts, "case $1 ... $2:$n", [
genLiteral(p, branch[j][0]), genLiteral(p, branch[j][0]),
genLiteral(p, branch[j][1])]) genLiteral(p, branch[j][1])])
@ -754,7 +754,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
hasDefault = true hasDefault = true
exprBlock(p, branch.lastSon, d) exprBlock(p, branch.lastSon, d)
lineF(p, cpsStmts, "break;$n", []) lineF(p, cpsStmts, "break;$n", [])
if (hasAssume in CC[cCompiler].props) and not hasDefault: if (hasAssume in CC[p.config.cCompiler].props) and not hasDefault:
lineF(p, cpsStmts, "default: __assume(0);$n", []) lineF(p, cpsStmts, "default: __assume(0);$n", [])
lineF(p, cpsStmts, "}$n", []) lineF(p, cpsStmts, "}$n", [])
if lend != nil: fixLabel(p, lend) if lend != nil: fixLabel(p, lend)
@ -975,21 +975,21 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
initLocExpr(p, it, a) initLocExpr(p, it, a)
res.add($a.rdLoc) res.add($a.rdLoc)
if isAsmStmt and hasGnuAsm in CC[cCompiler].props: if isAsmStmt and hasGnuAsm in CC[p.config.cCompiler].props:
for x in splitLines(res): for x in splitLines(res):
var j = 0 var j = 0
while x[j] in {' ', '\t'}: inc(j) while x[j] in {' ', '\t'}: inc(j)
if x[j] in {'"', ':'}: if x[j] in {'"', ':'}:
# don't modify the line if already in quotes or # don't modify the line if already in quotes or
# some clobber register list: # some clobber register list:
add(result, x); add(result, tnl) add(result, x); add(result, "\L")
elif x[j] != '\0': elif x[j] != '\0':
# ignore empty lines # ignore empty lines
add(result, "\"") add(result, "\"")
add(result, x) add(result, x)
add(result, "\\n\"\n") add(result, "\\n\"\n")
else: else:
res.add(tnl) res.add("\L")
result = res.rope result = res.rope
proc genAsmStmt(p: BProc, t: PNode) = proc genAsmStmt(p: BProc, t: PNode) =
@ -1001,9 +1001,9 @@ proc genAsmStmt(p: BProc, t: PNode) =
# work: # work:
if p.prc == nil: if p.prc == nil:
# top level asm statement? # top level asm statement?
addf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s]) addf(p.module.s[cfsProcHeaders], CC[p.config.cCompiler].asmStmtFrmt, [s])
else: else:
lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s]) lineF(p, cpsStmts, CC[p.config.cCompiler].asmStmtFrmt, [s])
proc determineSection(n: PNode): TCFileSection = proc determineSection(n: PNode): TCFileSection =
result = cfsProcHeaders result = cfsProcHeaders
@ -1036,7 +1036,7 @@ proc genBreakPoint(p: BProc, t: PNode) =
genLineDir(p, t) # BUGFIX genLineDir(p, t) # BUGFIX
appcg(p.module, p.module.g.breakpoints, appcg(p.module, p.module.g.breakpoints,
"#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [ "#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [
rope(toLinenumber(t.info)), makeCString(toFilename(t.info)), rope(toLinenumber(t.info)), makeCString(toFilename(p.config, t.info)),
makeCString(name)]) makeCString(name)])
proc genWatchpoint(p: BProc, n: PNode) = proc genWatchpoint(p: BProc, n: PNode) =
@ -1045,7 +1045,7 @@ proc genWatchpoint(p: BProc, n: PNode) =
initLocExpr(p, n.sons[1], a) initLocExpr(p, n.sons[1], a)
let typ = skipTypes(n.sons[1].typ, abstractVarRange) let typ = skipTypes(n.sons[1].typ, abstractVarRange)
lineCg(p, cpsStmts, "#dbgRegisterWatchpoint($1, (NCSTRING)$2, $3);$n", lineCg(p, cpsStmts, "#dbgRegisterWatchpoint($1, (NCSTRING)$2, $3);$n",
[a.addrLoc, makeCString(renderTree(n.sons[1])), [addrLoc(p.config, a), makeCString(renderTree(n.sons[1])),
genTypeInfo(p.module, typ, n.info)]) genTypeInfo(p.module, typ, n.info)])
proc genPragma(p: BProc, n: PNode) = proc genPragma(p: BProc, n: PNode) =
@ -1076,7 +1076,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
var t = skipTypes(objtype, abstractVar) var t = skipTypes(objtype, abstractVar)
assert t.kind == tyObject assert t.kind == tyObject
discard genTypeInfo(p.module, t, a.lode.info) discard genTypeInfo(p.module, t, a.lode.info)
var L = lengthOrd(field.typ) var L = lengthOrd(p.config, field.typ)
if not containsOrIncl(p.module.declaredThings, field.id): if not containsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1", appcg(p.module, cfsVars, "extern $1",
discriminatorTableDecl(p.module, t, field)) discriminatorTableDecl(p.module, t, field))

View file

@ -23,27 +23,14 @@ proc accessThreadLocalVar(p: BProc, s: PSym) =
add(p.procSec(cpsInit), add(p.procSec(cpsInit),
ropecg(p.module, "\tNimTV_ = (NimThreadVars*) #GetThreadLocalVars();$n")) ropecg(p.module, "\tNimTV_ = (NimThreadVars*) #GetThreadLocalVars();$n"))
var
nimtv: Rope # Nim thread vars; the struct body
nimtvDeps: seq[PType] = @[] # type deps: every module needs whole struct
nimtvDeclared = initIntSet() # so that every var/field exists only once
# in the struct
# 'nimtv' is incredibly hard to modularize! Best effort is to store all thread
# vars in a ROD section and with their type deps and load them
# unconditionally...
# nimtvDeps is VERY hard to cache because it's not a list of IDs nor can it be
# made to be one.
proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) = proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
if emulatedThreadVars(m.config): if emulatedThreadVars(m.config):
# we gather all thread locals var into a struct; we need to allocate # we gather all thread locals var into a struct; we need to allocate
# storage for that somehow, can't use the thread local storage # storage for that somehow, can't use the thread local storage
# allocator for it :-( # allocator for it :-(
if not containsOrIncl(nimtvDeclared, s.id): if not containsOrIncl(m.g.nimtvDeclared, s.id):
nimtvDeps.add(s.loc.t) m.g.nimtvDeps.add(s.loc.t)
addf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r]) addf(m.g.nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
else: else:
if isExtern: add(m.s[cfsVars], "extern ") if isExtern: add(m.s[cfsVars], "extern ")
if optThreads in m.config.globalOptions: add(m.s[cfsVars], "NIM_THREADVAR ") if optThreads in m.config.globalOptions: add(m.s[cfsVars], "NIM_THREADVAR ")
@ -51,12 +38,12 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
addf(m.s[cfsVars], " $1;$n", [s.loc.r]) addf(m.s[cfsVars], " $1;$n", [s.loc.r])
proc generateThreadLocalStorage(m: BModule) = proc generateThreadLocalStorage(m: BModule) =
if nimtv != nil and (usesThreadVars in m.flags or sfMainModule in m.module.flags): if m.g.nimtv != nil and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
for t in items(nimtvDeps): discard getTypeDesc(m, t) for t in items(m.g.nimtvDeps): discard getTypeDesc(m, t)
addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv]) addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [m.g.nimtv])
proc generateThreadVarsSize(m: BModule) = proc generateThreadVarsSize(m: BModule) =
if nimtv != nil: if m.g.nimtv != nil:
let externc = if m.config.cmd == cmdCompileToCpp or let externc = if m.config.cmd == cmdCompileToCpp or
sfCompileToCpp in m.module.flags: "extern \"C\" " sfCompileToCpp in m.module.flags: "extern \"C\" "
else: "" else: ""

View file

@ -70,7 +70,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
tySink: tySink:
genTraverseProc(c, accessor, lastSon(typ)) genTraverseProc(c, accessor, lastSon(typ))
of tyArray: of tyArray:
let arraySize = lengthOrd(typ.sons[0]) let arraySize = lengthOrd(c.p.config, typ.sons[0])
var i: TLoc var i: TLoc
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i) getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
let oldCode = p.s(cpsStmts) let oldCode = p.s(cpsStmts)
@ -122,7 +122,6 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
var p = newProc(nil, m) var p = newProc(nil, m)
result = "Marker_" & getTypeName(m, origTyp, sig) result = "Marker_" & getTypeName(m, origTyp, sig)
var typ = origTyp.skipTypes(abstractInst) var typ = origTyp.skipTypes(abstractInst)
if typ.kind == tyOpt: typ = optLowering(typ)
let header = "static N_NIMCALL(void, $1)(void* p, NI op)" % [result] let header = "static N_NIMCALL(void, $1)(void* p, NI op)" % [result]

View file

@ -50,7 +50,7 @@ proc mangleName(m: BModule; s: PSym): Rope =
result = s.name.s.mangle.rope result = s.name.s.mangle.rope
add(result, idOrSig(s, m.module.name.s, m.sigConflicts)) add(result, idOrSig(s, m.module.name.s, m.sigConflicts))
s.loc.r = result s.loc.r = result
writeMangledName(m.ndi, s) writeMangledName(m.ndi, s, m.config)
proc mangleParamName(m: BModule; s: PSym): Rope = proc mangleParamName(m: BModule; s: PSym): Rope =
## we cannot use 'sigConflicts' here since we have a BModule, not a BProc. ## we cannot use 'sigConflicts' here since we have a BModule, not a BProc.
@ -63,7 +63,7 @@ proc mangleParamName(m: BModule; s: PSym): Rope =
res.add "_0" res.add "_0"
result = res.rope result = res.rope
s.loc.r = result s.loc.r = result
writeMangledName(m.ndi, s) writeMangledName(m.ndi, s, m.config)
proc mangleLocalName(p: BProc; s: PSym): Rope = proc mangleLocalName(p: BProc; s: PSym): Rope =
assert s.kind in skLocalVars+{skTemp} assert s.kind in skLocalVars+{skTemp}
@ -81,7 +81,7 @@ proc mangleLocalName(p: BProc; s: PSym): Rope =
result.add "_" & rope(counter+1) result.add "_" & rope(counter+1)
p.sigConflicts.inc(key) p.sigConflicts.inc(key)
s.loc.r = result s.loc.r = result
if s.kind != skTemp: writeMangledName(p.module.ndi, s) if s.kind != skTemp: writeMangledName(p.module.ndi, s, p.config)
proc scopeMangledParam(p: BProc; param: PSym) = proc scopeMangledParam(p: BProc; param: PSym) =
## parameter generation only takes BModule, not a BProc, so we have to ## parameter generation only takes BModule, not a BProc, so we have to
@ -124,40 +124,40 @@ proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
result = typ.loc.r result = typ.loc.r
if result == nil: internalError(m.config, "getTypeName: " & $typ.kind) if result == nil: internalError(m.config, "getTypeName: " & $typ.kind)
proc mapSetType(typ: PType): TCTypeKind = proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
case int(getSize(typ)) case int(getSize(conf, typ))
of 1: result = ctInt8 of 1: result = ctInt8
of 2: result = ctInt16 of 2: result = ctInt16
of 4: result = ctInt32 of 4: result = ctInt32
of 8: result = ctInt64 of 8: result = ctInt64
else: result = ctArray else: result = ctArray
proc mapType(typ: PType): TCTypeKind = proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
## Maps a Nim type to a C type ## Maps a Nim type to a C type
case typ.kind case typ.kind
of tyNone, tyStmt: result = ctVoid of tyNone, tyStmt: result = ctVoid
of tyBool: result = ctBool of tyBool: result = ctBool
of tyChar: result = ctChar of tyChar: result = ctChar
of tySet: result = mapSetType(typ) of tySet: result = mapSetType(conf, typ)
of tyOpenArray, tyArray, tyVarargs: result = ctArray of tyOpenArray, tyArray, tyVarargs: result = ctArray
of tyObject, tyTuple: result = ctStruct of tyObject, tyTuple: result = ctStruct
of tyUserTypeClasses: of tyUserTypeClasses:
doAssert typ.isResolvedUserTypeClass doAssert typ.isResolvedUserTypeClass
return mapType(typ.lastSon) return mapType(conf, typ.lastSon)
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal, of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
tyTypeDesc, tyAlias, tySink, tyInferred: tyTypeDesc, tyAlias, tySink, tyInferred:
result = mapType(lastSon(typ)) result = mapType(conf, lastSon(typ))
of tyEnum: of tyEnum:
if firstOrd(typ) < 0: if firstOrd(conf, typ) < 0:
result = ctInt32 result = ctInt32
else: else:
case int(getSize(typ)) case int(getSize(conf, typ))
of 1: result = ctUInt8 of 1: result = ctUInt8
of 2: result = ctUInt16 of 2: result = ctUInt16
of 4: result = ctInt32 of 4: result = ctInt32
of 8: result = ctInt64 of 8: result = ctInt64
else: result = ctInt32 else: result = ctInt32
of tyRange: result = mapType(typ.sons[0]) of tyRange: result = mapType(conf, typ.sons[0])
of tyPtr, tyVar, tyLent, tyRef, tyOptAsRef: of tyPtr, tyVar, tyLent, tyRef, tyOptAsRef:
var base = skipTypes(typ.lastSon, typedescInst) var base = skipTypes(typ.lastSon, typedescInst)
case base.kind case base.kind
@ -169,27 +169,20 @@ proc mapType(typ: PType): TCTypeKind =
else: result = ctPtr else: result = ctPtr
of tyPointer: result = ctPtr of tyPointer: result = ctPtr
of tySequence: result = ctNimSeq of tySequence: result = ctNimSeq
of tyOpt:
case optKind(typ)
of oBool: result = ctStruct
of oNil, oPtr: result = ctPtr
of oEnum:
# The 'nil' value is always negative, so we always use a signed integer
result = if getSize(typ.sons[0]) == 8: ctInt64 else: ctInt32
of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct
of tyString: result = ctNimStr of tyString: result = ctNimStr
of tyCString: result = ctCString of tyCString: result = ctCString
of tyInt..tyUInt64: of tyInt..tyUInt64:
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
of tyStatic: of tyStatic:
if typ.n != nil: result = mapType(lastSon typ) if typ.n != nil: result = mapType(conf, lastSon typ)
else: doAssert(false, "mapType") else: doAssert(false, "mapType")
else: doAssert(false, "mapType") else: doAssert(false, "mapType")
proc mapReturnType(typ: PType): TCTypeKind = proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind =
#if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr #if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
#else: #else:
result = mapType(typ) result = mapType(conf, typ)
proc isImportedType(t: PType): bool = proc isImportedType(t: PType): bool =
result = t.sym != nil and sfImportc in t.sym.flags result = t.sym != nil and sfImportc in t.sym.flags
@ -207,14 +200,14 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} =
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
(typ.sons[0] == nil) or isPureObject(typ)) (typ.sons[0] == nil) or isPureObject(typ))
proc isInvalidReturnType(rettype: PType): bool = proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
# Arrays and sets cannot be returned by a C procedure, because C is # Arrays and sets cannot be returned by a C procedure, because C is
# such a poor programming language. # such a poor programming language.
# We exclude records with refs too. This enhances efficiency and # We exclude records with refs too. This enhances efficiency and
# is necessary for proper code generation of assignments. # is necessary for proper code generation of assignments.
if rettype == nil: result = true if rettype == nil: result = true
else: else:
case mapType(rettype) case mapType(conf, rettype)
of ctArray: of ctArray:
result = not (skipTypes(rettype, typedescInst).kind in result = not (skipTypes(rettype, typedescInst).kind in
{tyVar, tyLent, tyRef, tyPtr}) {tyVar, tyLent, tyRef, tyPtr})
@ -240,9 +233,9 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
proc addAbiCheck(m: BModule, t: PType, name: Rope) = proc addAbiCheck(m: BModule, t: PType, name: Rope) =
if isDefined(m.config, "checkabi"): if isDefined(m.config, "checkabi"):
addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [name, rope(getSize(t))]) addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [name, rope(getSize(m.config, t))])
proc ccgIntroducedPtr(s: PSym): bool = proc ccgIntroducedPtr(conf: ConfigRef; s: PSym): bool =
var pt = skipTypes(s.typ, typedescInst) var pt = skipTypes(s.typ, typedescInst)
assert skResult != s.kind assert skResult != s.kind
if tfByRef in pt.flags: return true if tfByRef in pt.flags: return true
@ -252,7 +245,7 @@ proc ccgIntroducedPtr(s: PSym): bool =
if s.typ.sym != nil and sfForward in s.typ.sym.flags: if s.typ.sym != nil and sfForward in s.typ.sym.flags:
# forwarded objects are *always* passed by pointers for consistency! # forwarded objects are *always* passed by pointers for consistency!
result = true result = true
elif (optByRef in s.options) or (getSize(pt) > platform.floatSize * 3): elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3):
result = true # requested anyway result = true # requested anyway
elif (tfFinal in pt.flags) and (pt.sons[0] == nil): elif (tfFinal in pt.flags) and (pt.sons[0] == nil):
result = false # no need, because no subtyping possible result = false # no need, because no subtyping possible
@ -260,14 +253,14 @@ proc ccgIntroducedPtr(s: PSym): bool =
result = true # ordinary objects are always passed by reference, result = true # ordinary objects are always passed by reference,
# otherwise casting doesn't work # otherwise casting doesn't work
of tyTuple: of tyTuple:
result = (getSize(pt) > platform.floatSize*3) or (optByRef in s.options) result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options)
else: result = false else: result = false
proc fillResult(param: PNode) = proc fillResult(conf: ConfigRef; param: PNode) =
fillLoc(param.sym.loc, locParam, param, ~"Result", fillLoc(param.sym.loc, locParam, param, ~"Result",
OnStack) OnStack)
let t = param.sym.typ let t = param.sym.typ
if mapReturnType(t) != ctArray and isInvalidReturnType(t): if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, t):
incl(param.sym.loc.flags, lfIndirect) incl(param.sym.loc.flags, lfIndirect)
param.sym.loc.storage = OnUnknown param.sym.loc.storage = OnUnknown
@ -364,12 +357,6 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
of tySequence: of tySequence:
result = getTypeForward(m, t, hashType(t)) & "*" result = getTypeForward(m, t, hashType(t)) & "*"
pushType(m, t) pushType(m, t)
of tyOpt:
if optKind(etB) == oPtr:
result = getTypeForward(m, t, hashType(t)) & "*"
pushType(m, t)
else:
result = getTypeDescAux(m, t, check)
else: else:
result = getTypeDescAux(m, t, check) result = getTypeDescAux(m, t, check)
@ -384,7 +371,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
check: var IntSet, declareEnvironment=true; check: var IntSet, declareEnvironment=true;
weakDep=false) = weakDep=false) =
params = nil params = nil
if t.sons[0] == nil or isInvalidReturnType(t.sons[0]): if t.sons[0] == nil or isInvalidReturnType(m.config, t.sons[0]):
rettype = ~"void" rettype = ~"void"
else: else:
rettype = getTypeDescAux(m, t.sons[0], check) rettype = getTypeDescAux(m, t.sons[0], check)
@ -395,7 +382,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
if params != nil: add(params, ~", ") if params != nil: add(params, ~", ")
fillLoc(param.loc, locParam, t.n.sons[i], mangleParamName(m, param), fillLoc(param.loc, locParam, t.n.sons[i], mangleParamName(m, param),
param.paramStorageLoc) param.paramStorageLoc)
if ccgIntroducedPtr(param): if ccgIntroducedPtr(m.config, param):
add(params, getTypeDescWeak(m, param.typ, check)) add(params, getTypeDescWeak(m, param.typ, check))
add(params, ~"*") add(params, ~"*")
incl(param.loc.flags, lfIndirect) incl(param.loc.flags, lfIndirect)
@ -417,10 +404,10 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
addf(params, ", NI $1Len_$2", [param.loc.r, j.rope]) addf(params, ", NI $1Len_$2", [param.loc.r, j.rope])
inc(j) inc(j)
arr = arr.sons[0] arr = arr.sons[0]
if t.sons[0] != nil and isInvalidReturnType(t.sons[0]): if t.sons[0] != nil and isInvalidReturnType(m.config, t.sons[0]):
var arr = t.sons[0] var arr = t.sons[0]
if params != nil: add(params, ", ") if params != nil: add(params, ", ")
if mapReturnType(t.sons[0]) != ctArray: if mapReturnType(m.config, t.sons[0]) != ctArray:
add(params, getTypeDescWeak(m, arr, check)) add(params, getTypeDescWeak(m, arr, check))
add(params, "*") add(params, "*")
else: else:
@ -471,13 +458,13 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
if tfPacked notin rectype.flags: if tfPacked notin rectype.flags:
add(unionBody, "struct {") add(unionBody, "struct {")
else: else:
if hasAttribute in CC[cCompiler].props: if hasAttribute in CC[m.config.cCompiler].props:
add(unionBody, "struct __attribute__((__packed__)){" ) add(unionBody, "struct __attribute__((__packed__)){" )
else: else:
addf(unionBody, "#pragma pack(push, 1)$nstruct{", []) addf(unionBody, "#pragma pack(push, 1)$nstruct{", [])
add(unionBody, a) add(unionBody, a)
addf(unionBody, "} $1;$n", [sname]) addf(unionBody, "} $1;$n", [sname])
if tfPacked in rectype.flags and hasAttribute notin CC[cCompiler].props: if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props:
addf(unionBody, "#pragma pack(pop)$n", []) addf(unionBody, "#pragma pack(pop)$n", [])
else: else:
add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check)) add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
@ -526,10 +513,10 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
var hasField = false var hasField = false
if tfPacked in typ.flags: if tfPacked in typ.flags:
if hasAttribute in CC[cCompiler].props: if hasAttribute in CC[m.config.cCompiler].props:
result = structOrUnion(typ) & " __attribute__((__packed__))" result = structOrUnion(typ) & " __attribute__((__packed__))"
else: else:
result = "#pragma pack(push, 1)" & tnl & structOrUnion(typ) result = "#pragma pack(push, 1)\L" & structOrUnion(typ)
else: else:
result = structOrUnion(typ) result = structOrUnion(typ)
@ -556,7 +543,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
# proper request to generate popCurrentExceptionEx not possible for 2 reasons: # proper request to generate popCurrentExceptionEx not possible for 2 reasons:
# generated function will be below declared Exception type and circular dependency # generated function will be below declared Exception type and circular dependency
# between Exception and popCurrentExceptionEx function # between Exception and popCurrentExceptionEx function
result = genProcHeader(m, magicsys.getCompilerProc(m.g.graph, "popCurrentExceptionEx")) & ";" & rnl & result result = genProcHeader(m, magicsys.getCompilerProc(m.g.graph, "popCurrentExceptionEx")) & ";" & result
hasField = true hasField = true
else: else:
appcg(m, result, " {$n $1 Sup;$n", appcg(m, result, " {$n $1 Sup;$n",
@ -570,9 +557,9 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
addf(result, "char dummy;$n", []) addf(result, "char dummy;$n", [])
else: else:
add(result, desc) add(result, desc)
add(result, "};" & tnl) add(result, "};\L")
if tfPacked in typ.flags and hasAttribute notin CC[cCompiler].props: if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props:
result.add "#pragma pack(pop)" & tnl result.add "#pragma pack(pop)\L"
proc getTupleDesc(m: BModule, typ: PType, name: Rope, proc getTupleDesc(m: BModule, typ: PType, name: Rope,
check: var IntSet): Rope = check: var IntSet): Rope =
@ -581,9 +568,9 @@ proc getTupleDesc(m: BModule, typ: PType, name: Rope,
for i in countup(0, sonsLen(typ) - 1): for i in countup(0, sonsLen(typ) - 1):
addf(desc, "$1 Field$2;$n", addf(desc, "$1 Field$2;$n",
[getTypeDescAux(m, typ.sons[i], check), rope(i)]) [getTypeDescAux(m, typ.sons[i], check), rope(i)])
if desc == nil: add(result, "char dummy;" & tnl) if desc == nil: add(result, "char dummy;\L")
else: add(result, desc) else: add(result, desc)
add(result, "};" & tnl) add(result, "};\L")
proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool = proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
# A helper proc for handling cppimport patterns, involving numeric # A helper proc for handling cppimport patterns, involving numeric
@ -657,21 +644,6 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
result = name & "*" & star result = name & "*" & star
m.typeCache[sig] = result m.typeCache[sig] = result
pushType(m, et) pushType(m, et)
of tyOpt:
if etB.sons[0].kind in {tyObject, tyTuple}:
let name = getTypeForward(m, et, hashType et)
result = name & "*" & star
m.typeCache[sig] = result
pushType(m, et)
elif optKind(etB) == oBool:
let name = getTypeForward(m, et, hashType et)
result = name & "*"
m.typeCache[sig] = result
pushType(m, et)
else:
# else we have a strong dependency :-(
result = getTypeDescAux(m, et, check) & star
m.typeCache[sig] = result
else: else:
# else we have a strong dependency :-( # else we have a strong dependency :-(
result = getTypeDescAux(m, et, check) & star result = getTypeDescAux(m, et, check) & star
@ -687,11 +659,11 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
(sfImportc in t.sym.flags and t.sym.magic == mNone)): (sfImportc in t.sym.flags and t.sym.magic == mNone)):
m.typeCache[sig] = result m.typeCache[sig] = result
var size: int var size: int
if firstOrd(t) < 0: if firstOrd(m.config, t) < 0:
addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result]) addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
size = 4 size = 4
else: else:
size = int(getSize(t)) size = int(getSize(m.config, t))
case size case size
of 1: addf(m.s[cfsTypes], "typedef NU8 $1;$n", [result]) of 1: addf(m.s[cfsTypes], "typedef NU8 $1;$n", [result])
of 2: addf(m.s[cfsTypes], "typedef NU16 $1;$n", [result]) of 2: addf(m.s[cfsTypes], "typedef NU16 $1;$n", [result])
@ -747,40 +719,8 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
else: else:
result = rope("TGenericSeq") result = rope("TGenericSeq")
add(result, "*") add(result, "*")
of tyOpt:
result = cacheGetType(m.typeCache, sig)
if result == nil:
case optKind(t)
of oBool:
result = cacheGetType(m.forwTypeCache, sig)
if result == nil:
result = getTypeName(m, origTyp, sig)
addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(t), result])
m.forwTypeCache[sig] = result
appcg(m, m.s[cfsSeqTypes], "struct $2 {$n" &
" NIM_BOOL Field0;$n" &
" $1 Field1;$n" &
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
of oPtr:
let et = t.sons[0]
if et.kind in {tyTuple, tyObject}:
let name = getTypeForward(m, et, hashType et)
result = name & "*"
pushType(m, et)
else:
result = getTypeDescAux(m, t.sons[0], check) & "*"
of oNil:
result = getTypeDescAux(m, t.sons[0], check)
of oEnum:
result = getTypeName(m, origTyp, sig)
if getSize(t.sons[0]) == 8:
addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result])
else:
addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
m.typeCache[sig] = result
of tyArray: of tyArray:
var n: BiggestInt = lengthOrd(t) var n: BiggestInt = lengthOrd(m.config, t)
if n <= 0: n = 1 # make an array of at least one element if n <= 0: n = 1 # make an array of at least one element
result = getTypeName(m, origTyp, sig) result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result m.typeCache[sig] = result
@ -791,8 +731,6 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
else: addAbiCheck(m, t, result) else: addAbiCheck(m, t, result)
of tyObject, tyTuple: of tyObject, tyTuple:
if isImportedCppType(t) and origTyp.kind == tyGenericInst: if isImportedCppType(t) and origTyp.kind == tyGenericInst:
# for instantiated templates we do not go through the type cache as the
# the type cache is not aware of 'tyGenericInst'.
let cppName = getTypeName(m, t, sig) let cppName = getTypeName(m, t, sig)
var i = 0 var i = 0
var chunkStart = 0 var chunkStart = 0
@ -866,11 +804,11 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
result = $t.kind & '_' & getTypeName(m, t.lastSon, hashType t.lastSon) result = $t.kind & '_' & getTypeName(m, t.lastSon, hashType t.lastSon)
m.typeCache[sig] = result m.typeCache[sig] = result
if not isImportedType(t): if not isImportedType(t):
let s = int(getSize(t)) let s = int(getSize(m.config, t))
case s case s
of 1, 2, 4, 8: addf(m.s[cfsTypes], "typedef NU$2 $1;$n", [result, rope(s*8)]) of 1, 2, 4, 8: addf(m.s[cfsTypes], "typedef NU$2 $1;$n", [result, rope(s*8)])
else: addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n", else: addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
[result, rope(getSize(t))]) [result, rope(getSize(m.config, t))])
of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink,
tyUserTypeClass, tyUserTypeClassInst, tyInferred: tyUserTypeClass, tyUserTypeClassInst, tyInferred:
result = getTypeDescAux(m, lastSon(t), check) result = getTypeDescAux(m, lastSon(t), check)
@ -972,7 +910,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
var typename = typeToString(if origType.typeInst != nil: origType.typeInst var typename = typeToString(if origType.typeInst != nil: origType.typeInst
else: origType, preferName) else: origType, preferName)
if typename == "ref object" and origType.skipTypes(skipPtrs).sym != nil: if typename == "ref object" and origType.skipTypes(skipPtrs).sym != nil:
typename = "anon ref object from " & $origType.skipTypes(skipPtrs).sym.info typename = "anon ref object from " & m.config$origType.skipTypes(skipPtrs).sym.info
addf(m.s[cfsTypeInit3], "$1.name = $2;$n", addf(m.s[cfsTypeInit3], "$1.name = $2;$n",
[name, makeCstring typename]) [name, makeCstring typename])
discard cgsym(m, "nimTypeRoot") discard cgsym(m, "nimTypeRoot")
@ -1006,7 +944,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope = proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
discard cgsym(m, "TNimNode") discard cgsym(m, "TNimNode")
var tmp = discriminatorTableName(m, objtype, d) var tmp = discriminatorTableName(m, objtype, d)
result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(d.typ)+1)] result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(m.config, d.typ)+1)]
proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope; proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
info: TLineInfo) = info: TLineInfo) =
@ -1030,7 +968,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
assert(n.sons[0].kind == nkSym) assert(n.sons[0].kind == nkSym)
var field = n.sons[0].sym var field = n.sons[0].sym
var tmp = discriminatorTableName(m, typ, field) var tmp = discriminatorTableName(m, typ, field)
var L = lengthOrd(field.typ) var L = lengthOrd(m.config, field.typ)
assert L > 0 assert L > 0
if field.loc.r == nil: fillObjectFields(m, typ) if field.loc.r == nil: fillObjectFields(m, typ)
if field.loc.t == nil: if field.loc.t == nil:
@ -1140,7 +1078,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
add(enumNames, makeCString(field.name.s)) add(enumNames, makeCString(field.name.s))
else: else:
add(enumNames, makeCString(field.ast.strVal)) add(enumNames, makeCString(field.ast.strVal))
if i < length - 1: add(enumNames, ", " & tnl) if i < length - 1: add(enumNames, ", \L")
if field.position != i or tfEnumHasHoles in typ.flags: if field.position != i or tfEnumHasHoles in typ.flags:
addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)]) addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
hasHoles = true hasHoles = true
@ -1166,7 +1104,7 @@ proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
genTypeInfoAux(m, typ, typ, name, info) genTypeInfoAux(m, typ, typ, name, info)
var tmp = getNimNode(m) var tmp = getNimNode(m)
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n", addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
[tmp, rope(firstOrd(typ)), name]) [tmp, rope(firstOrd(m.config, typ)), name])
proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1], info), info) genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1], info), info)
@ -1190,8 +1128,6 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
let origType = t let origType = t
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses) var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
if t.kind == tyOpt:
return genTypeInfo(m, optLowering(t), info)
let sig = hashType(origType) let sig = hashType(origType)
result = m.typeInfoMarker.getOrDefault(sig) result = m.typeInfoMarker.getOrDefault(sig)

View file

@ -27,9 +27,9 @@ proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool = proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
result = getPragmaStmt(n, w) != nil result = getPragmaStmt(n, w) != nil
proc hashString*(s: string): BiggestInt = proc hashString*(conf: ConfigRef; s: string): BiggestInt =
# has to be the same algorithm as system.hashString! # has to be the same algorithm as system.hashString!
if CPU[targetCPU].bit == 64: if CPU[conf.target.targetCPU].bit == 64:
# we have to use the same bitwidth # we have to use the same bitwidth
# as the target CPU # as the target CPU
var b = 0'i64 var b = 0'i64
@ -52,117 +52,12 @@ proc hashString*(s: string): BiggestInt =
a = a +% `shl`(a, 15'i32) a = a +% `shl`(a, 15'i32)
result = a result = a
var template getUniqueType*(key: PType): PType = key
gTypeTable: array[TTypeKind, TIdTable] # XXX globals here
gCanonicalTypes: array[TTypeKind, PType]
proc initTypeTables() =
for i in countup(low(TTypeKind), high(TTypeKind)): initIdTable(gTypeTable[i])
proc resetCaches* =
## XXX: fix that more properly
initTypeTables()
for i in low(gCanonicalTypes)..high(gCanonicalTypes):
gCanonicalTypes[i] = nil
when false:
proc echoStats*() =
for i in countup(low(TTypeKind), high(TTypeKind)):
echo i, " ", gTypeTable[i].counter
proc slowSearch(key: PType; k: TTypeKind): PType =
# tuples are quite horrible as C does not support them directly and
# tuple[string, string] is a (strange) subtype of
# tuple[nameA, nameB: string]. This bites us here, so we
# use 'sameBackendType' instead of 'sameType'.
if idTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameBackendType(t, key):
return t
idTablePut(gTypeTable[k], key, key)
result = key
proc getUniqueType*(key: PType): PType =
# this is a hotspot in the compiler!
result = key
when false:
if key == nil: return
var k = key.kind
case k
of tyBool, tyChar, tyInt..tyUInt64:
# no canonicalization for integral types, so that e.g. ``pid_t`` is
# produced instead of ``NI``.
result = key
of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
tyCString, tyNone, tyVoid:
result = gCanonicalTypes[k]
if result == nil:
gCanonicalTypes[k] = key
result = key
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr:
if key.isResolvedUserTypeClass:
return getUniqueType(lastSon(key))
if key.sym != nil:
internalError(key.sym.info, "metatype not eliminated")
else:
internalError("metatype not eliminated")
of tyDistinct:
if key.deepCopy != nil: result = key
else: result = getUniqueType(lastSon(key))
of tyGenericInst, tyOrdinal, tyStatic, tyAlias, tySink, tyInferred:
result = getUniqueType(lastSon(key))
#let obj = lastSon(key)
#if obj.sym != nil and obj.sym.name.s == "TOption":
# echo "for ", typeToString(key), " I returned "
# debug result
of tyPtr, tyRef, tyVar, tyLent:
let elemType = lastSon(key)
if elemType.kind in {tyBool, tyChar, tyInt..tyUInt64}:
# no canonicalization for integral types, so that e.g. ``ptr pid_t`` is
# produced instead of ``ptr NI``.
result = key
else:
result = slowSearch(key, k)
of tyGenericInvocation, tyGenericBody,
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
tySequence, tyForward, tyVarargs, tyProxy, tyOpt:
# we have to do a slow linear search because types may need
# to be compared by their structure:
result = slowSearch(key, k)
of tyObject:
if tfFromGeneric notin key.flags:
# fast case; lookup per id suffices:
result = PType(idTableGet(gTypeTable[k], key))
if result == nil:
idTablePut(gTypeTable[k], key, key)
result = key
else:
# ugly slow case: need to compare by structure
if idTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameBackendType(t, key):
return t
idTablePut(gTypeTable[k], key, key)
result = key
of tyEnum:
result = PType(idTableGet(gTypeTable[k], key))
if result == nil:
idTablePut(gTypeTable[k], key, key)
result = key
of tyProc:
if key.callConv != ccClosure:
result = key
else:
# ugh, we need the canon here:
result = slowSearch(key, k)
of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("getUniqueType")
proc makeSingleLineCString*(s: string): string = proc makeSingleLineCString*(s: string): string =
result = "\"" result = "\""
for c in items(s): for c in items(s):
result.add(c.toCChar) c.toCChar(result)
result.add('\"') result.add('\"')
proc mangle*(name: string): string = proc mangle*(name: string): string =
@ -210,5 +105,3 @@ proc mangle*(name: string): string =
requiresUnderscore = true requiresUnderscore = true
if requiresUnderscore: if requiresUnderscore:
result.add "_" result.add "_"
initTypeTables()

View file

@ -12,14 +12,15 @@
import import
ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets, ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
nversion, nimsets, msgs, std / sha1, bitsets, idents, types, nversion, nimsets, msgs, std / sha1, bitsets, idents, types,
ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
lowerings, semparallel, tables, sets, ndi lowerings, semparallel, tables, sets, ndi, lineinfos
import strutils except `%` # collides with ropes.`%` import strutils except `%` # collides with ropes.`%`
from modulegraphs import ModuleGraph from modulegraphs import ModuleGraph
from configuration import warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated from lineinfos import
warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated, errCannotOpenFile
import dynlib import dynlib
when not declared(dynlib.libCandidates): when not declared(dynlib.libCandidates):
@ -120,10 +121,10 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
internalError(m.config, "ropes: invalid format string $" & $j) internalError(m.config, "ropes: invalid format string $" & $j)
add(result, args[j-1]) add(result, args[j-1])
of 'n': of 'n':
if optLineDir notin m.config.options: add(result, rnl) if optLineDir notin m.config.options: add(result, "\L")
inc(i) inc(i)
of 'N': of 'N':
add(result, rnl) add(result, "\L")
inc(i) inc(i)
else: internalError(m.config, "ropes: invalid format string $" & frmt[i]) else: internalError(m.config, "ropes: invalid format string $" & frmt[i])
elif frmt[i] == '#' and frmt[i+1] in IdentStartChars: elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
@ -193,7 +194,7 @@ proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
[rope(makeSingleLineCString(filename)), rope(line)]) [rope(makeSingleLineCString(filename)), rope(line)])
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) = proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
genCLineDir(r, info.toFullPath, info.safeLineNm, conf) genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
proc freshLineInfo(p: BProc; info: TLineInfo): bool = proc freshLineInfo(p: BProc; info: TLineInfo): bool =
if p.lastLineInfo.line != info.line or if p.lastLineInfo.line != info.line or
@ -203,27 +204,22 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
result = true result = true
proc genLineDir(p: BProc, t: PNode) = proc genLineDir(p: BProc, t: PNode) =
var tt = t let line = t.info.safeLineNm
#while tt.kind in {nkStmtListExpr}+nkCallKinds:
# tt = tt.lastSon
if tt.kind in nkCallKinds and tt.len > 1:
tt = tt.sons[1]
let line = tt.info.safeLineNm
if optEmbedOrigSrc in p.config.globalOptions: if optEmbedOrigSrc in p.config.globalOptions:
add(p.s(cpsStmts), ~"//" & sourceLine(p.config, tt.info) & rnl) add(p.s(cpsStmts), ~"//" & sourceLine(p.config, t.info) & "\L")
genCLineDir(p.s(cpsStmts), tt.info.toFullPath, line, p.config) genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config)
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
(p.prc == nil or sfPure notin p.prc.flags): (p.prc == nil or sfPure notin p.prc.flags):
if freshLineInfo(p, tt.info): if freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "#endb($1, $2);$N", linefmt(p, cpsStmts, "#endb($1, $2);$N",
line.rope, makeCString(toFilename(tt.info))) line.rope, makeCString(toFilename(p.config, t.info)))
elif ({optLineTrace, optStackTrace} * p.options == elif ({optLineTrace, optStackTrace} * p.options ==
{optLineTrace, optStackTrace}) and {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex != InvalidFileIDX: (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIDX:
if freshLineInfo(p, tt.info): if freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "nimln_($1, $2);$n", linefmt(p, cpsStmts, "nimln_($1, $2);$n",
line.rope, quotedFilename(p.config, tt.info)) line.rope, quotedFilename(p.config, t.info))
proc postStmtActions(p: BProc) {.inline.} = proc postStmtActions(p: BProc) {.inline.} =
add(p.s(cpsStmts), p.module.injectStmt) add(p.s(cpsStmts), p.module.injectStmt)
@ -249,9 +245,9 @@ proc rdLoc(a: TLoc): Rope =
result = a.r result = a.r
if lfIndirect in a.flags: result = "(*$1)" % [result] if lfIndirect in a.flags: result = "(*$1)" % [result]
proc addrLoc(a: TLoc): Rope = proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
result = a.r result = a.r
if lfIndirect notin a.flags and mapType(a.t) != ctArray: if lfIndirect notin a.flags and mapType(conf, a.t) != ctArray:
result = "(&" & result & ")" result = "(&" & result & ")"
proc rdCharLoc(a: TLoc): Rope = proc rdCharLoc(a: TLoc): Rope =
@ -281,7 +277,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t, a.lode.info)) linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t, a.lode.info))
of frEmbedded: of frEmbedded:
# worst case for performance: # worst case for performance:
var r = if takeAddr: addrLoc(a) else: rdLoc(a) var r = if takeAddr: addrLoc(p.config, a) else: rdLoc(a)
linefmt(p, section, "#objectInit($1, $2);$n", r, genTypeInfo(p.module, t, a.lode.info)) linefmt(p, section, "#objectInit($1, $2);$n", r, genTypeInfo(p.module, t, a.lode.info))
type type
@ -310,10 +306,10 @@ proc resetLoc(p: BProc, loc: var TLoc) =
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc)) linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
else: else:
if optNilCheck in p.options: if optNilCheck in p.options:
linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", addrLoc(loc)) linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", addrLoc(p.config, loc))
if loc.storage != OnStack: if loc.storage != OnStack:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(loc), genTypeInfo(p.module, loc.t, loc.lode.info)) addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info))
# XXX: generated reset procs should not touch the m_type # XXX: generated reset procs should not touch the m_type
# field, so disabling this should be safe: # field, so disabling this should be safe:
genObjectInit(p, cpsStmts, loc.t, loc, true) genObjectInit(p, cpsStmts, loc.t, loc, true)
@ -322,7 +318,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
# array passed as argument decayed into pointer, bug #7332 # array passed as argument decayed into pointer, bug #7332
# so we use getTypeDesc here rather than rdLoc(loc) # so we use getTypeDesc here rather than rdLoc(loc)
linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n", linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
addrLoc(loc), getTypeDesc(p.module, loc.t)) addrLoc(p.config, loc), getTypeDesc(p.module, loc.t))
# XXX: We can be extra clever here and call memset only # XXX: We can be extra clever here and call memset only
# on the bytes following the m_type field? # on the bytes following the m_type field?
genObjectInit(p, cpsStmts, loc.t, loc, true) genObjectInit(p, cpsStmts, loc.t, loc, true)
@ -339,7 +335,7 @@ proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
if not isImportedCppType(typ): if not isImportedCppType(typ):
useStringh(p.module) useStringh(p.module)
linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n", linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
addrLoc(loc), getTypeDesc(p.module, typ)) addrLoc(p.config, loc), getTypeDesc(p.module, typ))
genObjectInit(p, cpsStmts, loc.t, loc, true) genObjectInit(p, cpsStmts, loc.t, loc, true)
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
@ -386,7 +382,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
# XXX work around a bug: No type information for open arrays possible: # XXX work around a bug: No type information for open arrays possible:
if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
var a = "&" & s.loc.r var a = "&" & s.loc.r
if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r if s.kind == skParam and ccgIntroducedPtr(p.config, s): a = s.loc.r
lineF(p, cpsInit, lineF(p, cpsInit,
"FR_.s[$1].address = (void*)$3; FR_.s[$1].typ = $4; FR_.s[$1].name = $2;$n", "FR_.s[$1].address = (void*)$3; FR_.s[$1].typ = $4; FR_.s[$1].name = $2;$n",
[p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a, [p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
@ -414,7 +410,7 @@ proc assignLocalVar(p: BProc, n: PNode) =
#assert(s.loc.k == locNone) # not yet assigned #assert(s.loc.k == locNone) # not yet assigned
# this need not be fulfilled for inline procs; they are regenerated # this need not be fulfilled for inline procs; they are regenerated
# for each module that uses them! # for each module that uses them!
let nl = if optLineDir in p.config.options: "" else: tnl let nl = if optLineDir in p.config.options: "" else: "\L"
let decl = localVarDecl(p, n) & ";" & nl let decl = localVarDecl(p, n) & ";" & nl
line(p, cpsLocals, decl) line(p, cpsLocals, decl)
localDebugInfo(p, n.sym) localDebugInfo(p, n.sym)
@ -651,33 +647,33 @@ proc cgsym(m: BModule, name: string): Rope =
result = sym.loc.r result = sym.loc.r
proc generateHeaders(m: BModule) = proc generateHeaders(m: BModule) =
add(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl) add(m.s[cfsHeaders], "\L#include \"nimbase.h\"\L")
for it in m.headerFiles: for it in m.headerFiles:
if it[0] == '#': if it[0] == '#':
add(m.s[cfsHeaders], rope(it.replace('`', '"') & tnl)) add(m.s[cfsHeaders], rope(it.replace('`', '"') & "\L"))
elif it[0] notin {'\"', '<'}: elif it[0] notin {'\"', '<'}:
addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it)]) addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it)])
else: else:
addf(m.s[cfsHeaders], "#include $1$N", [rope(it)]) addf(m.s[cfsHeaders], "#include $1$N", [rope(it)])
add(m.s[cfsHeaders], "#undef LANGUAGE_C" & tnl) add(m.s[cfsHeaders], "#undef LANGUAGE_C\L")
add(m.s[cfsHeaders], "#undef MIPSEB" & tnl) add(m.s[cfsHeaders], "#undef MIPSEB\L")
add(m.s[cfsHeaders], "#undef MIPSEL" & tnl) add(m.s[cfsHeaders], "#undef MIPSEL\L")
add(m.s[cfsHeaders], "#undef PPC" & tnl) add(m.s[cfsHeaders], "#undef PPC\L")
add(m.s[cfsHeaders], "#undef R3000" & tnl) add(m.s[cfsHeaders], "#undef R3000\L")
add(m.s[cfsHeaders], "#undef R4000" & tnl) add(m.s[cfsHeaders], "#undef R4000\L")
add(m.s[cfsHeaders], "#undef i386" & tnl) add(m.s[cfsHeaders], "#undef i386\L")
add(m.s[cfsHeaders], "#undef linux" & tnl) add(m.s[cfsHeaders], "#undef linux\L")
add(m.s[cfsHeaders], "#undef mips" & tnl) add(m.s[cfsHeaders], "#undef mips\L")
add(m.s[cfsHeaders], "#undef near" & tnl) add(m.s[cfsHeaders], "#undef near\L")
add(m.s[cfsHeaders], "#undef powerpc" & tnl) add(m.s[cfsHeaders], "#undef powerpc\L")
add(m.s[cfsHeaders], "#undef unix" & tnl) add(m.s[cfsHeaders], "#undef unix\L")
proc openNamespaceNim(): Rope = proc openNamespaceNim(): Rope =
result.add("namespace Nim {" & tnl) result.add("namespace Nim {\L")
proc closeNamespaceNim(): Rope = proc closeNamespaceNim(): Rope =
result.add("}" & tnl) result.add("}\L")
proc closureSetup(p: BProc, prc: PSym) = proc closureSetup(p: BProc, prc: PSym) =
if tfCapturesEnv notin prc.typ.flags: return if tfCapturesEnv notin prc.typ.flags: return
@ -727,7 +723,7 @@ proc genProcAux(m: BModule, prc: PSym) =
internalError(m.config, prc.info, "proc has no result symbol") internalError(m.config, prc.info, "proc has no result symbol")
let resNode = prc.ast.sons[resultPos] let resNode = prc.ast.sons[resultPos]
let res = resNode.sym # get result symbol let res = resNode.sym # get result symbol
if not isInvalidReturnType(prc.typ.sons[0]): if not isInvalidReturnType(m.config, prc.typ.sons[0]):
if sfNoInit in prc.flags: incl(res.flags, sfNoInit) if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(prc.getBody); val != nil): if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(prc.getBody); val != nil):
var decl = localVarDecl(p, resNode) var decl = localVarDecl(p, resNode)
@ -741,7 +737,7 @@ proc genProcAux(m: BModule, prc: PSym) =
initLocalVar(p, res, immediateAsgn=false) initLocalVar(p, res, immediateAsgn=false)
returnStmt = ropecg(p.module, "\treturn $1;$n", rdLoc(res.loc)) returnStmt = ropecg(p.module, "\treturn $1;$n", rdLoc(res.loc))
else: else:
fillResult(resNode) fillResult(p.config, resNode)
assignParam(p, res) assignParam(p, res)
if sfNoInit notin prc.flags: resetLoc(p, res.loc) if sfNoInit notin prc.flags: resetLoc(p, res.loc)
if skipTypes(res.typ, abstractInst).kind == tyArray: if skipTypes(res.typ, abstractInst).kind == tyArray:
@ -756,10 +752,10 @@ proc genProcAux(m: BModule, prc: PSym) =
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc. genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
var generatedProc: Rope var generatedProc: Rope
if sfNoReturn in prc.flags: if sfNoReturn in prc.flags:
if hasDeclspec in extccomp.CC[extccomp.cCompiler].props: if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
header = "__declspec(noreturn) " & header header = "__declspec(noreturn) " & header
if sfPure in prc.flags: if sfPure in prc.flags:
if hasDeclspec in extccomp.CC[extccomp.cCompiler].props: if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
header = "__declspec(naked) " & header header = "__declspec(naked) " & header
generatedProc = ropecg(p.module, "$N$1 {$n$2$3$4}$N$N", generatedProc = ropecg(p.module, "$N$1 {$n$2$3$4}$N$N",
header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)) header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
@ -803,13 +799,13 @@ proc genProcPrototype(m: BModule, sym: PSym) =
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym))) getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
elif not containsOrIncl(m.declaredProtos, sym.id): elif not containsOrIncl(m.declaredProtos, sym.id):
var header = genProcHeader(m, sym) var header = genProcHeader(m, sym)
if sfNoReturn in sym.flags and hasDeclspec in extccomp.CC[cCompiler].props: if sfNoReturn in sym.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
header = "__declspec(noreturn) " & header header = "__declspec(noreturn) " & header
if sym.typ.callConv != ccInline and requiresExternC(m, sym): if sym.typ.callConv != ccInline and requiresExternC(m, sym):
header = "extern \"C\" " & header header = "extern \"C\" " & header
if sfPure in sym.flags and hasAttribute in CC[cCompiler].props: if sfPure in sym.flags and hasAttribute in CC[m.config.cCompiler].props:
header.add(" __attribute__((naked))") header.add(" __attribute__((naked))")
if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props: if sfNoReturn in sym.flags and hasAttribute in CC[m.config.cCompiler].props:
header.add(" __attribute__((noreturn))") header.add(" __attribute__((noreturn))")
add(m.s[cfsProcHeaders], ropecg(m, "$1;$n", header)) add(m.s[cfsProcHeaders], ropecg(m, "$1;$n", header))
@ -918,10 +914,10 @@ proc genVarPrototype(m: BModule, n: PNode) =
addf(m.s[cfsVars], " $1;$n", [sym.loc.r]) addf(m.s[cfsVars], " $1;$n", [sym.loc.r])
proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} = proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} =
addf(result, "#define NIM_NEW_MANGLING_RULES" & tnl & addf(result, "#define NIM_NEW_MANGLING_RULES\L" &
"#define NIM_INTBITS $1" & tnl, [ "#define NIM_INTBITS $1\L", [
platform.CPU[targetCPU].intSize.rope]) platform.CPU[conf.target.targetCPU].intSize.rope])
if optUseNimNamespace in conf.globalOptions: result.add("#define USE_NIM_NAMESPACE" & tnl) if optUseNimNamespace in conf.globalOptions: result.add("#define USE_NIM_NAMESPACE\L")
proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope = proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope =
if optCompileOnly in conf.globalOptions: if optCompileOnly in conf.globalOptions:
@ -936,9 +932,9 @@ proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope =
"/* Compiled for: $2, $3, $4 */$N" & "/* Compiled for: $2, $3, $4 */$N" &
"/* Command for C compiler:$n $5 */$N") % "/* Command for C compiler:$n $5 */$N") %
[rope(VersionAsString), [rope(VersionAsString),
rope(platform.OS[targetOS].name), rope(platform.OS[conf.target.targetOS].name),
rope(platform.CPU[targetCPU].name), rope(platform.CPU[conf.target.targetCPU].name),
rope(extccomp.CC[extccomp.cCompiler].name), rope(extccomp.CC[conf.cCompiler].name),
rope(getCompileCFileCmd(conf, cfile))] rope(getCompileCFileCmd(conf, cfile))]
proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope = proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
@ -948,8 +944,8 @@ proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
proc genFilenames(m: BModule): Rope = proc genFilenames(m: BModule): Rope =
discard cgsym(m, "dbgRegisterFilename") discard cgsym(m, "dbgRegisterFilename")
result = nil result = nil
for i in 0..<fileInfos.len: for i in 0..<m.config.m.fileInfos.len:
result.addf("dbgRegisterFilename($1);$N", [fileInfos[i].projPath.makeCString]) result.addf("dbgRegisterFilename($1);$N", [m.config.m.fileInfos[i].projPath.makeCString])
proc genMainProc(m: BModule) = proc genMainProc(m: BModule) =
const const
@ -1052,7 +1048,7 @@ proc genMainProc(m: BModule) =
"}$N$N" "}$N$N"
var nimMain, otherMain: FormatStr var nimMain, otherMain: FormatStr
if platform.targetOS == osWindows and if m.config.target.targetOS == osWindows and
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
if optGenGuiApp in m.config.globalOptions: if optGenGuiApp in m.config.globalOptions:
nimMain = WinNimMain nimMain = WinNimMain
@ -1061,14 +1057,14 @@ proc genMainProc(m: BModule) =
nimMain = WinNimDllMain nimMain = WinNimDllMain
otherMain = WinCDllMain otherMain = WinCDllMain
m.includeHeader("<windows.h>") m.includeHeader("<windows.h>")
elif platform.targetOS == osGenode: elif m.config.target.targetOS == osGenode:
nimMain = GenodeNimMain nimMain = GenodeNimMain
otherMain = ComponentConstruct otherMain = ComponentConstruct
m.includeHeader("<libc/component.h>") m.includeHeader("<libc/component.h>")
elif optGenDynLib in m.config.globalOptions: elif optGenDynLib in m.config.globalOptions:
nimMain = PosixNimDllMain nimMain = PosixNimDllMain
otherMain = PosixCDllMain otherMain = PosixCDllMain
elif platform.targetOS == osStandalone: elif m.config.target.targetOS == osStandalone:
nimMain = PosixNimMain nimMain = PosixNimMain
otherMain = StandaloneCMain otherMain = StandaloneCMain
else: else:
@ -1079,12 +1075,12 @@ proc genMainProc(m: BModule) =
m.g.breakpoints.add(m.genFilenames) m.g.breakpoints.add(m.genFilenames)
let initStackBottomCall = let initStackBottomCall =
if platform.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope if m.config.target.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N") else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
inc(m.labels) inc(m.labels)
appcg(m, m.s[cfsProcs], PreMainBody, [ appcg(m, m.s[cfsProcs], PreMainBody, [
m.g.mainDatInit, m.g.breakpoints, m.g.otherModsInit, m.g.mainDatInit, m.g.breakpoints, m.g.otherModsInit,
if emulatedThreadVars(m.config) and platform.targetOS != osStandalone: if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
ropecg(m, "\t#initThreadVarsEmulation();$N") ropecg(m, "\t#initThreadVarsEmulation();$N")
else: else:
"".rope, "".rope,
@ -1094,7 +1090,7 @@ proc genMainProc(m: BModule) =
[m.g.mainModInit, initStackBottomCall, rope(m.labels)]) [m.g.mainModInit, initStackBottomCall, rope(m.labels)])
if optNoMain notin m.config.globalOptions: if optNoMain notin m.config.globalOptions:
if optUseNimNamespace in m.config.globalOptions: if optUseNimNamespace in m.config.globalOptions:
m.s[cfsProcs].add closeNamespaceNim() & "using namespace Nim;" & tnl m.s[cfsProcs].add closeNamespaceNim() & "using namespace Nim;\L"
appcg(m, m.s[cfsProcs], otherMain, []) appcg(m, m.s[cfsProcs], otherMain, [])
if optUseNimNamespace in m.config.globalOptions: m.s[cfsProcs].add openNamespaceNim() if optUseNimNamespace in m.config.globalOptions: m.s[cfsProcs].add openNamespaceNim()
@ -1255,7 +1251,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
excl(result.postInitProc.options, optStackTrace) excl(result.postInitProc.options, optStackTrace)
let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi") let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi")
else: "" else: ""
open(result.ndi, ndiName) open(result.ndi, ndiName, g.config)
proc nullify[T](arr: var T) = proc nullify[T](arr: var T) =
for i in low(arr)..high(arr): for i in low(arr)..high(arr):
@ -1305,13 +1301,15 @@ proc resetModule*(m: BModule) =
proc resetCgenModules*(g: BModuleList) = proc resetCgenModules*(g: BModuleList) =
for m in cgenModules(g): resetModule(m) for m in cgenModules(g): resetModule(m)
proc rawNewModule(g: BModuleList; module: PSym): BModule = proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
result = rawNewModule(g, module, module.position.FileIndex.toFullPath) result = rawNewModule(g, module, toFullPath(conf, module.position.FileIndex))
proc newModule(g: BModuleList; module: PSym): BModule = proc newModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
# we should create only one cgen module for each module sym # we should create only one cgen module for each module sym
result = rawNewModule(g, module) result = rawNewModule(g, module, conf)
growCache g.modules, module.position if module.position >= g.modules.len:
setLen(g.modules, module.position + 1)
#growCache g.modules, module.position
g.modules[module.position] = result g.modules[module.position] = result
template injectG() {.dirty.} = template injectG() {.dirty.} =
@ -1319,9 +1317,9 @@ template injectG() {.dirty.} =
graph.backend = newModuleList(graph) graph.backend = newModuleList(graph)
let g = BModuleList(graph.backend) let g = BModuleList(graph.backend)
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
injectG() injectG()
result = newModule(g, module) result = newModule(g, module, graph.config)
if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil: if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil:
let f = if graph.config.headerFile.len > 0: graph.config.headerFile let f = if graph.config.headerFile.len > 0: graph.config.headerFile
else: graph.config.projectFull else: graph.config.projectFull
@ -1353,7 +1351,8 @@ proc writeHeader(m: BModule) =
result.addf("N_CDECL(void, NimMain)(void);$n", []) result.addf("N_CDECL(void, NimMain)(void);$n", [])
if optUseNimNamespace in m.config.globalOptions: result.add closeNamespaceNim() if optUseNimNamespace in m.config.globalOptions: result.add closeNamespaceNim()
result.addf("#endif /* $1 */$n", [guard]) result.addf("#endif /* $1 */$n", [guard])
writeRope(result, m.filename) if not writeRope(result, m.filename):
rawMessage(m.config, errCannotOpenFile, m.filename)
proc getCFile(m: BModule): string = proc getCFile(m: BModule): string =
let ext = let ext =
@ -1362,11 +1361,12 @@ proc getCFile(m: BModule): string =
else: ".c" else: ".c"
result = changeFileExt(completeCFilePath(m.config, withPackageName(m.config, m.cfilename)), ext) result = changeFileExt(completeCFilePath(m.config, withPackageName(m.config, m.cfilename)), ext)
proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext = when false:
injectG() proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
var m = newModule(g, module) injectG()
readMergeInfo(getCFile(m), m) var m = newModule(g, module, graph.config)
result = m readMergeInfo(getCFile(m), m)
result = m
proc myProcess(b: PPassContext, n: PNode): PNode = proc myProcess(b: PPassContext, n: PNode): PNode =
result = n result = n
@ -1374,7 +1374,8 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
var m = BModule(b) var m = BModule(b)
if passes.skipCodegen(m.config, n): return if passes.skipCodegen(m.config, n): return
m.initProc.options = initProcOptions(m) m.initProc.options = initProcOptions(m)
softRnl = if optLineDir in m.config.options: noRnl else: rnl #softRnl = if optLineDir in m.config.options: noRnl else: rnl
# XXX replicate this logic!
genStmts(m.initProc, n) genStmts(m.initProc, n)
proc finishModule(m: BModule) = proc finishModule(m: BModule) =
@ -1401,12 +1402,14 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
echo "diff ", cfile.cname, ".backup ", cfile.cname echo "diff ", cfile.cname, ".backup ", cfile.cname
else: else:
echo "new file ", cfile.cname echo "new file ", cfile.cname
writeRope(code, cfile.cname) if not writeRope(code, cfile.cname):
rawMessage(m.config, errCannotOpenFile, cfile.cname)
return return
if existsFile(cfile.obj) and os.fileNewer(cfile.obj, cfile.cname): if existsFile(cfile.obj) and os.fileNewer(cfile.obj, cfile.cname):
result = false result = false
else: else:
writeRope(code, cfile.cname) if not writeRope(code, cfile.cname):
rawMessage(m.config, errCannotOpenFile, cfile.cname)
# We need 2 different logics here: pending modules (including # We need 2 different logics here: pending modules (including
# 'nim__dat') may require file merging for the combination of dead code # 'nim__dat') may require file merging for the combination of dead code
@ -1418,7 +1421,7 @@ proc writeModule(m: BModule, pending: bool) =
# generate code for the init statements of the module: # generate code for the init statements of the module:
let cfile = getCFile(m) let cfile = getCFile(m)
if m.rd == nil or optForceFullMake in m.config.globalOptions: if true or optForceFullMake in m.config.globalOptions:
genInitCode(m) genInitCode(m)
finishTypeDescriptions(m) finishTypeDescriptions(m)
if sfMainModule in m.module.flags: if sfMainModule in m.module.flags:
@ -1441,7 +1444,8 @@ proc writeModule(m: BModule, pending: bool) =
genInitCode(m) genInitCode(m)
finishTypeDescriptions(m) finishTypeDescriptions(m)
var code = genModule(m, cf) var code = genModule(m, cf)
writeRope(code, cfile) if not writeRope(code, cfile):
rawMessage(m.config, errCannotOpenFile, cfile)
addFileToCompile(m.config, cf) addFileToCompile(m.config, cf)
else: else:
# Consider: first compilation compiles ``system.nim`` and produces # Consider: first compilation compiles ``system.nim`` and produces
@ -1462,7 +1466,8 @@ proc updateCachedModule(m: BModule) =
finishTypeDescriptions(m) finishTypeDescriptions(m)
var code = genModule(m, cf) var code = genModule(m, cf)
writeRope(code, cfile) if not writeRope(code, cfile):
rawMessage(m.config, errCannotOpenFile, cfile)
else: else:
cf.flags = {CfileFlag.Cached} cf.flags = {CfileFlag.Cached}
addFileToCompile(m.config, cf) addFileToCompile(m.config, cf)
@ -1475,7 +1480,6 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
# if the module is cached, we don't regenerate the main proc # if the module is cached, we don't regenerate the main proc
# nor the dispatchers? But if the dispatchers changed? # nor the dispatchers? But if the dispatchers changed?
# XXX emit the dispatchers into its own .c file? # XXX emit the dispatchers into its own .c file?
if b.rd != nil: return
if n != nil: if n != nil:
m.initProc.options = initProcOptions(m) m.initProc.options = initProcOptions(m)
genStmts(m.initProc, n) genStmts(m.initProc, n)
@ -1498,14 +1502,10 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
if g.generatedHeader != nil: finishModule(g.generatedHeader) if g.generatedHeader != nil: finishModule(g.generatedHeader)
while g.forwardedProcsCounter > 0: while g.forwardedProcsCounter > 0:
for m in cgenModules(g): for m in cgenModules(g):
if m.rd == nil: finishModule(m)
finishModule(m)
for m in cgenModules(g): for m in cgenModules(g):
if m.rd != nil: m.writeModule(pending=true)
m.updateCachedModule
else:
m.writeModule(pending=true)
writeMapping(config, g.mapping) writeMapping(config, g.mapping)
if g.generatedHeader != nil: writeHeader(g.generatedHeader) if g.generatedHeader != nil: writeHeader(g.generatedHeader)
const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose) const cgenPass* = makePass(myOpen, myProcess, myClose)

View file

@ -11,9 +11,8 @@
import import
ast, astalgo, ropes, passes, options, intsets, platform, sighashes, ast, astalgo, ropes, passes, options, intsets, platform, sighashes,
tables, ndi tables, ndi, lineinfos
from msgs import TLineInfo
from modulegraphs import ModuleGraph from modulegraphs import ModuleGraph
type type
@ -122,6 +121,17 @@ type
graph*: ModuleGraph graph*: ModuleGraph
strVersion*, seqVersion*: int # version of the string/seq implementation to use strVersion*, seqVersion*: int # version of the string/seq implementation to use
nimtv*: Rope # Nim thread vars; the struct body
nimtvDeps*: seq[PType] # type deps: every module needs whole struct
nimtvDeclared*: IntSet # so that every var/field exists only once
# in the struct
# 'nimtv' is incredibly hard to modularize! Best
# effort is to store all thread vars in a ROD
# section and with their type deps and load them
# unconditionally...
# nimtvDeps is VERY hard to cache because it's
# not a list of IDs nor can it be made to be one.
TCGen = object of TPassContext # represents a C source file TCGen = object of TPassContext # represents a C source file
s*: TCFileSections # sections of the C file s*: TCFileSections # sections of the C file
flags*: set[Codegenflag] flags*: set[Codegenflag]
@ -180,7 +190,7 @@ proc newProc*(prc: PSym, module: BModule): BProc =
proc newModuleList*(g: ModuleGraph): BModuleList = proc newModuleList*(g: ModuleGraph): BModuleList =
BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: g.config, BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: g.config,
graph: g) graph: g, nimtvDeps: @[], nimtvDeclared: initIntSet())
iterator cgenModules*(g: BModuleList): BModule = iterator cgenModules*(g: BModuleList): BModule =
for i in 0..high(g.modules): for i in 0..high(g.modules):

View file

@ -11,7 +11,7 @@
import import
intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys, intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys,
sempass2, strutils, modulegraphs, configuration sempass2, strutils, modulegraphs, lineinfos
proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode = proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode =
var dest = skipTypes(d, abstractPtrs) var dest = skipTypes(d, abstractPtrs)
@ -115,7 +115,7 @@ proc createDispatcher(s: PSym): PSym =
# we can't inline the dispatcher itself (for now): # we can't inline the dispatcher itself (for now):
if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault
disp.ast = copyTree(s.ast) disp.ast = copyTree(s.ast)
disp.ast.sons[bodyPos] = ast.emptyNode disp.ast.sons[bodyPos] = newNodeI(nkEmpty, s.info)
disp.loc.r = nil disp.loc.r = nil
if s.typ.sons[0] != nil: if s.typ.sons[0] != nil:
if disp.ast.sonsLen > resultPos: if disp.ast.sonsLen > resultPos:
@ -124,7 +124,7 @@ proc createDispatcher(s: PSym): PSym =
# We've encountered a method prototype without a filled-in # We've encountered a method prototype without a filled-in
# resultPos slot. We put a placeholder in there that will # resultPos slot. We put a placeholder in there that will
# be updated in fixupDispatcher(). # be updated in fixupDispatcher().
disp.ast.addSon(ast.emptyNode) disp.ast.addSon(newNodeI(nkEmpty, s.info))
attachDispatcher(s, newSymNode(disp)) attachDispatcher(s, newSymNode(disp))
# attach to itself to prevent bugs: # attach to itself to prevent bugs:
attachDispatcher(disp, newSymNode(disp)) attachDispatcher(disp, newSymNode(disp))
@ -137,7 +137,7 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
# the lock level of the dispatcher needs to be updated/checked # the lock level of the dispatcher needs to be updated/checked
# against that of the method. # against that of the method.
if disp.ast.sonsLen > resultPos and meth.ast.sonsLen > resultPos and if disp.ast.sonsLen > resultPos and meth.ast.sonsLen > resultPos and
disp.ast.sons[resultPos] == ast.emptyNode: disp.ast.sons[resultPos].kind == nkEmpty:
disp.ast.sons[resultPos] = copyTree(meth.ast.sons[resultPos]) disp.ast.sons[resultPos] = copyTree(meth.ast.sons[resultPos])
# The following code works only with lock levels, so we disable # The following code works only with lock levels, so we disable
@ -184,7 +184,7 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
# internalError(s.info, "no method dispatcher found") # internalError(s.info, "no method dispatcher found")
if witness != nil: if witness != nil:
localError(g.config, s.info, "invalid declaration order; cannot attach '" & s.name.s & localError(g.config, s.info, "invalid declaration order; cannot attach '" & s.name.s &
"' to method defined here: " & $witness.info) "' to method defined here: " & g.config$witness.info)
elif sfBase notin s.flags: elif sfBase notin s.flags:
message(g.config, s.info, warnUseBase) message(g.config, s.info, warnUseBase)

View file

@ -1,7 +1,7 @@
# #
# #
# The Nim Compiler # The Nim Compiler
# (c) Copyright 2018 Andreas Rumpf # (c) Copyright 2018 Nim Contributors
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -132,7 +132,7 @@
import import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, idents, intsets, strutils, options, ast, astalgo, trees, treetab, msgs, idents,
renderer, types, magicsys, rodread, lowerings, lambdalifting, modulegraphs renderer, types, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos
type type
Ctx = object Ctx = object
@ -177,7 +177,7 @@ proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode =
ctx.newStateAssgn(newIntTypeNode(nkIntLit, stateNo, ctx.g.getSysType(TLineInfo(), tyInt))) ctx.newStateAssgn(newIntTypeNode(nkIntLit, stateNo, ctx.g.getSysType(TLineInfo(), tyInt)))
proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym = proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
result = newSym(skVar, getIdent(name), ctx.fn, ctx.fn.info) result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.fn, ctx.fn.info)
result.typ = typ result.typ = typ
assert(not typ.isNil) assert(not typ.isNil)
@ -190,7 +190,7 @@ proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
else: else:
let envParam = getEnvParam(ctx.fn) let envParam = getEnvParam(ctx.fn)
# let obj = envParam.typ.lastSon # let obj = envParam.typ.lastSon
result = addUniqueField(envParam.typ.lastSon, result) result = addUniqueField(envParam.typ.lastSon, result, ctx.g.cache)
proc newEnvVarAccess(ctx: Ctx, s: PSym): PNode = proc newEnvVarAccess(ctx: Ctx, s: PSym): PNode =
if ctx.stateVarSym.isNil: if ctx.stateVarSym.isNil:
@ -210,7 +210,7 @@ proc newUnrollFinallyAccess(ctx: var Ctx, info: TLineInfo): PNode =
proc newCurExcAccess(ctx: var Ctx): PNode = proc newCurExcAccess(ctx: var Ctx): PNode =
if ctx.curExcSym.isNil: if ctx.curExcSym.isNil:
ctx.curExcSym = ctx.newEnvVar(":curExc", ctx.g.callCodegenProc("getCurrentException", emptyNode).typ) ctx.curExcSym = ctx.newEnvVar(":curExc", ctx.g.callCodegenProc("getCurrentException", ctx.g.emptyNode).typ)
ctx.newEnvVarAccess(ctx.curExcSym) ctx.newEnvVarAccess(ctx.curExcSym)
proc newState(ctx: var Ctx, n, gotoOut: PNode): int = proc newState(ctx: var Ctx, n, gotoOut: PNode): int =
@ -324,7 +324,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
assert(c[i].kind == nkType) assert(c[i].kind == nkType)
let nextCond = newTree(nkCall, let nextCond = newTree(nkCall,
newSymNode(g.getSysMagic(c.info, "of", mOf)), newSymNode(g.getSysMagic(c.info, "of", mOf)),
g.callCodegenProc("getCurrentException", emptyNode), g.callCodegenProc("getCurrentException", ctx.g.emptyNode),
c[i]) c[i])
nextCond.typ = ctx.g.getSysType(c.info, tyBool) nextCond.typ = ctx.g.getSysType(c.info, tyBool)
nextCond.info = c.info nextCond.info = c.info
@ -349,7 +349,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
if ifStmt.len != 0: if ifStmt.len != 0:
result = newTree(nkStmtList, ctx.newNullifyCurExc(n.info), ifStmt) result = newTree(nkStmtList, ctx.newNullifyCurExc(n.info), ifStmt)
else: else:
result = emptyNode result = ctx.g.emptyNode
proc addElseToExcept(ctx: var Ctx, n: PNode) = proc addElseToExcept(ctx: var Ctx, n: PNode) =
if n.kind == nkStmtList and n[1].kind == nkIfStmt and n[1][^1].kind != nkElse: if n.kind == nkStmtList and n[1].kind == nkIfStmt and n[1][^1].kind != nkElse:
@ -364,7 +364,7 @@ proc addElseToExcept(ctx: var Ctx, n: PNode) =
block: # :curExc = getCurrentException() block: # :curExc = getCurrentException()
branchBody.add(newTree(nkAsgn, branchBody.add(newTree(nkAsgn,
ctx.newCurExcAccess(), ctx.newCurExcAccess(),
ctx.g.callCodegenProc("getCurrentException", emptyNode))) ctx.g.callCodegenProc("getCurrentException", ctx.g.emptyNode)))
block: # goto nearestFinally block: # goto nearestFinally
branchBody.add(newTree(nkGotoState, ctx.g.newIntLit(n.info, ctx.nearestFinally))) branchBody.add(newTree(nkGotoState, ctx.g.newIntLit(n.info, ctx.nearestFinally)))
@ -372,12 +372,12 @@ proc addElseToExcept(ctx: var Ctx, n: PNode) =
let elseBranch = newTree(nkElse, branchBody) let elseBranch = newTree(nkElse, branchBody)
n[1].add(elseBranch) n[1].add(elseBranch)
proc getFinallyNode(n: PNode): PNode = proc getFinallyNode(ctx: var Ctx, n: PNode): PNode =
result = n[^1] result = n[^1]
if result.kind == nkFinally: if result.kind == nkFinally:
result = result[0] result = result[0]
else: else:
result = emptyNode result = ctx.g.emptyNode
proc hasYieldsInExpressions(n: PNode): bool = proc hasYieldsInExpressions(n: PNode): bool =
case n.kind case n.kind
@ -725,7 +725,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if condNeedsSplit: if condNeedsSplit:
let (st, ex) = exprToStmtList(n[0]) let (st, ex) = exprToStmtList(n[0])
let brk = newTree(nkBreakStmt, emptyNode) let brk = newTree(nkBreakStmt, ctx.g.emptyNode)
let branch = newTree(nkElifBranch, ctx.g.newNotCall(ex), brk) let branch = newTree(nkElifBranch, ctx.g.newNotCall(ex), brk)
let check = newTree(nkIfStmt, branch) let check = newTree(nkIfStmt, branch)
let newBody = newTree(nkStmtList, st, check, n[1]) let newBody = newTree(nkStmtList, st, check, n[1])
@ -777,14 +777,14 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
cmp.typ = ctx.g.getSysType(info, tyBool) cmp.typ = ctx.g.getSysType(info, tyBool)
let asgn = newTree(nkFastAsgn, let asgn = newTree(nkFastAsgn,
newSymNode(getClosureIterResult(ctx.fn), info), newSymNode(getClosureIterResult(ctx.g, ctx.fn), info),
ctx.newTmpResultAccess()) ctx.newTmpResultAccess())
let retStmt = newTree(nkReturnStmt, asgn) let retStmt = newTree(nkReturnStmt, asgn)
let branch = newTree(nkElifBranch, cmp, retStmt) let branch = newTree(nkElifBranch, cmp, retStmt)
# The C++ backend requires `getCurrentException` here. # The C++ backend requires `getCurrentException` here.
let raiseStmt = newTree(nkRaiseStmt, ctx.g.callCodegenProc("getCurrentException", emptyNode)) let raiseStmt = newTree(nkRaiseStmt, ctx.g.callCodegenProc("getCurrentException", ctx.g.emptyNode))
raiseStmt.info = info raiseStmt.info = info
let elseBranch = newTree(nkElse, raiseStmt) let elseBranch = newTree(nkElse, raiseStmt)
@ -922,7 +922,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
result = newNodeI(nkGotoState, n.info) result = newNodeI(nkGotoState, n.info)
var tryBody = toStmtList(n[0]) var tryBody = toStmtList(n[0])
var exceptBody = ctx.collectExceptState(n) var exceptBody = ctx.collectExceptState(n)
var finallyBody = newTree(nkStmtList, getFinallyNode(n)) var finallyBody = newTree(nkStmtList, getFinallyNode(ctx, n))
finallyBody = ctx.transformReturnsInTry(finallyBody) finallyBody = ctx.transformReturnsInTry(finallyBody)
finallyBody.add(ctx.newEndFinallyNode(finallyBody.info)) finallyBody.add(ctx.newEndFinallyNode(finallyBody.info))
@ -1023,11 +1023,11 @@ proc tranformStateAssignments(ctx: var Ctx, n: PNode): PNode =
if n[0].sons[0].kind != nkEmpty: if n[0].sons[0].kind != nkEmpty:
var a = newNodeI(nkAsgn, n[0].sons[0].info) var a = newNodeI(nkAsgn, n[0].sons[0].info)
var retVal = n[0].sons[0] #liftCapturedVars(n.sons[0], owner, d, c) var retVal = n[0].sons[0] #liftCapturedVars(n.sons[0], owner, d, c)
addSon(a, newSymNode(getClosureIterResult(ctx.fn))) addSon(a, newSymNode(getClosureIterResult(ctx.g, ctx.fn)))
addSon(a, retVal) addSon(a, retVal)
retStmt.add(a) retStmt.add(a)
else: else:
retStmt.add(emptyNode) retStmt.add(ctx.g.emptyNode)
result.add(retStmt) result.add(retStmt)
else: else:
@ -1054,10 +1054,10 @@ proc tranformStateAssignments(ctx: var Ctx, n: PNode): PNode =
for i in 0 ..< n.len: for i in 0 ..< n.len:
n[i] = ctx.tranformStateAssignments(n[i]) n[i] = ctx.tranformStateAssignments(n[i])
proc skipStmtList(n: PNode): PNode = proc skipStmtList(ctx: Ctx; n: PNode): PNode =
result = n result = n
while result.kind in {nkStmtList}: while result.kind in {nkStmtList}:
if result.len == 0: return emptyNode if result.len == 0: return ctx.g.emptyNode
result = result[0] result = result[0]
proc skipEmptyStates(ctx: Ctx, stateIdx: int): int = proc skipEmptyStates(ctx: Ctx, stateIdx: int): int =
@ -1072,7 +1072,7 @@ proc skipEmptyStates(ctx: Ctx, stateIdx: int): int =
if label == -1: if label == -1:
newLabel = ctx.exitStateIdx newLabel = ctx.exitStateIdx
else: else:
let fs = ctx.states[label][1].skipStmtList() let fs = skipStmtList(ctx, ctx.states[label][1])
if fs.kind == nkGotoState: if fs.kind == nkGotoState:
newLabel = fs[0].intVal.int newLabel = fs[0].intVal.int
if label == newLabel: break if label == newLabel: break
@ -1148,7 +1148,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
newIntTypeNode(nkIntLit, 0, intTyp)) newIntTypeNode(nkIntLit, 0, intTyp))
cond.typ = boolTyp cond.typ = boolTyp
let raiseStmt = newTree(nkRaiseStmt, emptyNode) let raiseStmt = newTree(nkRaiseStmt, ctx.g.emptyNode)
let ifBranch = newTree(nkElifBranch, cond, raiseStmt) let ifBranch = newTree(nkElifBranch, cond, raiseStmt)
let ifStmt = newTree(nkIfStmt, ifBranch) let ifStmt = newTree(nkIfStmt, ifBranch)
result.add(ifStmt) result.add(ifStmt)
@ -1185,7 +1185,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
block: block:
result.add(newTree(nkAsgn, result.add(newTree(nkAsgn,
ctx.newCurExcAccess(), ctx.newCurExcAccess(),
ctx.g.callCodegenProc("getCurrentException", emptyNode))) ctx.g.callCodegenProc("getCurrentException", ctx.g.emptyNode)))
proc wrapIntoTryExcept(ctx: var Ctx, n: PNode): PNode {.inline.} = proc wrapIntoTryExcept(ctx: var Ctx, n: PNode): PNode {.inline.} =
let setupExc = newTree(nkCall, let setupExc = newTree(nkCall,
@ -1235,7 +1235,7 @@ proc deleteEmptyStates(ctx: var Ctx) =
# Apply new state indexes and mark unused states with -1 # Apply new state indexes and mark unused states with -1
var iValid = 0 var iValid = 0
for i, s in ctx.states: for i, s in ctx.states:
let body = s[1].skipStmtList() let body = skipStmtList(ctx, s[1])
if body.kind == nkGotoState and i != ctx.states.len - 1 and i != 0: if body.kind == nkGotoState and i != ctx.states.len - 1 and i != 0:
# This is an empty state. Mark with -1. # This is an empty state. Mark with -1.
s[0].intVal = -1 s[0].intVal = -1
@ -1244,7 +1244,7 @@ proc deleteEmptyStates(ctx: var Ctx) =
inc iValid inc iValid
for i, s in ctx.states: for i, s in ctx.states:
let body = s[1].skipStmtList() let body = skipStmtList(ctx, s[1])
if body.kind != nkGotoState or i == 0: if body.kind != nkGotoState or i == 0:
discard ctx.skipThroughEmptyStates(s) discard ctx.skipThroughEmptyStates(s)
let excHandlState = ctx.exceptionTable[i] let excHandlState = ctx.exceptionTable[i]
@ -1255,7 +1255,7 @@ proc deleteEmptyStates(ctx: var Ctx) =
var i = 0 var i = 0
while i < ctx.states.len - 1: while i < ctx.states.len - 1:
let fs = ctx.states[i][1].skipStmtList() let fs = skipStmtList(ctx, ctx.states[i][1])
if fs.kind == nkGotoState and i != 0: if fs.kind == nkGotoState and i != 0:
ctx.states.delete(i) ctx.states.delete(i)
ctx.exceptionTable.delete(i) ctx.exceptionTable.delete(i)
@ -1271,10 +1271,10 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
# Lambda lifting was not done yet. Use temporary :state sym, which # Lambda lifting was not done yet. Use temporary :state sym, which
# be handled specially by lambda lifting. Local temp vars (if needed) # be handled specially by lambda lifting. Local temp vars (if needed)
# should folllow the same logic. # should folllow the same logic.
ctx.stateVarSym = newSym(skVar, getIdent(":state"), fn, fn.info) ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), fn, fn.info)
ctx.stateVarSym.typ = g.createClosureIterStateType(fn) ctx.stateVarSym.typ = g.createClosureIterStateType(fn)
ctx.stateLoopLabel = newSym(skLabel, getIdent(":stateLoop"), fn, fn.info) ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info)
let n = n.toStmtList let n = n.toStmtList
discard ctx.newState(n, nil) discard ctx.newState(n, nil)

View file

@ -26,7 +26,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
import import
os, msgs, options, nversion, condsyms, strutils, extccomp, platform, os, msgs, options, nversion, condsyms, strutils, extccomp, platform,
wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils, configuration wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils, lineinfos
# but some have deps to imported modules. Yay. # but some have deps to imported modules. Yay.
bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
@ -56,21 +56,21 @@ const
x x
AdvancedUsage = slurp"../doc/advopt.txt".replace("//", "") % FeatureDesc AdvancedUsage = slurp"../doc/advopt.txt".replace("//", "") % FeatureDesc
proc getCommandLineDesc(): string = proc getCommandLineDesc(conf: ConfigRef): string =
result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, result = (HelpMessage % [VersionAsString, platform.OS[conf.target.hostOS].name,
CPU[platform.hostCPU].name, CompileDate]) & CPU[conf.target.hostCPU].name, CompileDate]) &
Usage Usage
proc helpOnError(conf: ConfigRef; pass: TCmdLinePass) = proc helpOnError(conf: ConfigRef; pass: TCmdLinePass) =
if pass == passCmd1: if pass == passCmd1:
msgWriteln(conf, getCommandLineDesc(), {msgStdout}) msgWriteln(conf, getCommandLineDesc(conf), {msgStdout})
msgQuit(0) msgQuit(0)
proc writeAdvancedUsage(conf: ConfigRef; pass: TCmdLinePass) = proc writeAdvancedUsage(conf: ConfigRef; pass: TCmdLinePass) =
if pass == passCmd1: if pass == passCmd1:
msgWriteln(conf, (HelpMessage % [VersionAsString, msgWriteln(conf, (HelpMessage % [VersionAsString,
platform.OS[platform.hostOS].name, platform.OS[conf.target.hostOS].name,
CPU[platform.hostCPU].name, CompileDate]) & CPU[conf.target.hostCPU].name, CompileDate]) &
AdvancedUsage, AdvancedUsage,
{msgStdout}) {msgStdout})
msgQuit(0) msgQuit(0)
@ -78,8 +78,8 @@ proc writeAdvancedUsage(conf: ConfigRef; pass: TCmdLinePass) =
proc writeFullhelp(conf: ConfigRef; pass: TCmdLinePass) = proc writeFullhelp(conf: ConfigRef; pass: TCmdLinePass) =
if pass == passCmd1: if pass == passCmd1:
msgWriteln(conf, `%`(HelpMessage, [VersionAsString, msgWriteln(conf, `%`(HelpMessage, [VersionAsString,
platform.OS[platform.hostOS].name, platform.OS[conf.target.hostOS].name,
CPU[platform.hostCPU].name, CompileDate]) & CPU[conf.target.hostCPU].name, CompileDate]) &
Usage & AdvancedUsage, Usage & AdvancedUsage,
{msgStdout}) {msgStdout})
msgQuit(0) msgQuit(0)
@ -87,8 +87,8 @@ proc writeFullhelp(conf: ConfigRef; pass: TCmdLinePass) =
proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) = proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) =
if pass == passCmd1: if pass == passCmd1:
msgWriteln(conf, `%`(HelpMessage, [VersionAsString, msgWriteln(conf, `%`(HelpMessage, [VersionAsString,
platform.OS[platform.hostOS].name, platform.OS[conf.target.hostOS].name,
CPU[platform.hostCPU].name, CompileDate]), CPU[conf.target.hostCPU].name, CompileDate]),
{msgStdout}) {msgStdout})
const gitHash = gorge("git log -n 1 --format=%H").strip const gitHash = gorge("git log -n 1 --format=%H").strip
@ -103,7 +103,7 @@ proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) =
proc writeCommandLineUsage*(conf: ConfigRef; helpWritten: var bool) = proc writeCommandLineUsage*(conf: ConfigRef; helpWritten: var bool) =
if not helpWritten: if not helpWritten:
msgWriteln(conf, getCommandLineDesc(), {msgStdout}) msgWriteln(conf, getCommandLineDesc(conf), {msgStdout})
helpWritten = true helpWritten = true
proc addPrefix(switch: string): string = proc addPrefix(switch: string): string =
@ -178,11 +178,11 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
if i < len(arg) and (arg[i] in {':', '='}): inc(i) if i < len(arg) and (arg[i] in {':', '='}): inc(i)
else: invalidCmdLineOption(conf, pass, orig, info) else: invalidCmdLineOption(conf, pass, orig, info)
if state == wHint: if state == wHint:
let x = findStr(configuration.HintsToStr, id) let x = findStr(lineinfos.HintsToStr, id)
if x >= 0: n = TNoteKind(x + ord(hintMin)) if x >= 0: n = TNoteKind(x + ord(hintMin))
else: localError(conf, info, "unknown hint: " & id) else: localError(conf, info, "unknown hint: " & id)
else: else:
let x = findStr(configuration.WarningsToStr, id) let x = findStr(lineinfos.WarningsToStr, id)
if x >= 0: n = TNoteKind(x + ord(warnMin)) if x >= 0: n = TNoteKind(x + ord(warnMin))
else: localError(conf, info, "unknown warning: " & id) else: localError(conf, info, "unknown warning: " & id)
case substr(arg, i).normalize case substr(arg, i).normalize
@ -289,14 +289,14 @@ proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
else: else:
conf.projectPath / path conf.projectPath / path
try: try:
result = pathSubs(conf, p, info.toFullPath().splitFile().dir) result = pathSubs(conf, p, toFullPath(conf, info).splitFile().dir)
except ValueError: except ValueError:
localError(conf, info, "invalid path: " & p) localError(conf, info, "invalid path: " & p)
result = p result = p
proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): string = proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): string =
let path = if path[0] == '"': strutils.unescape(path) else: path let path = if path[0] == '"': strutils.unescape(path) else: path
let basedir = info.toFullPath().splitFile().dir let basedir = toFullPath(conf, info).splitFile().dir
let p = if os.isAbsolute(path) or '$' in path: let p = if os.isAbsolute(path) or '$' in path:
path path
else: else:
@ -322,9 +322,9 @@ proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) =
let dirtyOriginalIdx = fileInfoIdx(conf, a[1]) let dirtyOriginalIdx = fileInfoIdx(conf, a[1])
if dirtyOriginalIdx.int32 >= 0: if dirtyOriginalIdx.int32 >= 0:
msgs.setDirtyFile(dirtyOriginalIdx, a[0]) msgs.setDirtyFile(conf, dirtyOriginalIdx, a[0])
gTrackPos = newLineInfo(dirtyOriginalIdx, line, column) conf.m.trackPos = newLineInfo(dirtyOriginalIdx, line, column)
proc track(conf: ConfigRef; arg: string, info: TLineInfo) = proc track(conf: ConfigRef; arg: string, info: TLineInfo) =
var a = arg.split(',') var a = arg.split(',')
@ -334,7 +334,7 @@ proc track(conf: ConfigRef; arg: string, info: TLineInfo) =
localError(conf, info, errInvalidNumber % a[1]) localError(conf, info, errInvalidNumber % a[1])
if parseUtils.parseInt(a[2], column) <= 0: if parseUtils.parseInt(a[2], column) <= 0:
localError(conf, info, errInvalidNumber % a[2]) localError(conf, info, errInvalidNumber % a[2])
gTrackPos = newLineInfo(conf, a[0], line, column) conf.m.trackPos = newLineInfo(conf, a[0], line, column)
proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if pass in {passCmd2, passPP}: if pass in {passCmd2, passPP}:
@ -344,8 +344,6 @@ proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, in
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf: ConfigRef) = conf: ConfigRef) =
var var
theOS: TSystemOS
cpu: TSystemCPU
key, val: string key, val: string
case switch.normalize case switch.normalize
of "path", "p": of "path", "p":
@ -565,13 +563,13 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(conf, arg) if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(conf, arg)
of "cincludes": of "cincludes":
expectArg(conf, switch, arg, pass, info) expectArg(conf, switch, arg, pass, info)
if pass in {passCmd2, passPP}: cIncludes.add processPath(conf, arg, info) if pass in {passCmd2, passPP}: conf.cIncludes.add processPath(conf, arg, info)
of "clibdir": of "clibdir":
expectArg(conf, switch, arg, pass, info) expectArg(conf, switch, arg, pass, info)
if pass in {passCmd2, passPP}: cLibs.add processPath(conf, arg, info) if pass in {passCmd2, passPP}: conf.cLibs.add processPath(conf, arg, info)
of "clib": of "clib":
expectArg(conf, switch, arg, pass, info) expectArg(conf, switch, arg, pass, info)
if pass in {passCmd2, passPP}: cLinkedLibs.add processPath(conf, arg, info) if pass in {passCmd2, passPP}: conf.cLinkedLibs.add processPath(conf, arg, info)
of "header": of "header":
if conf != nil: conf.headerFile = arg if conf != nil: conf.headerFile = arg
incl(conf.globalOptions, optGenIndex) incl(conf.globalOptions, optGenIndex)
@ -592,17 +590,17 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "os": of "os":
expectArg(conf, switch, arg, pass, info) expectArg(conf, switch, arg, pass, info)
if pass in {passCmd1, passPP}: if pass in {passCmd1, passPP}:
theOS = platform.nameToOS(arg) let theOS = platform.nameToOS(arg)
if theOS == osNone: localError(conf, info, "unknown OS: '$1'" % arg) if theOS == osNone: localError(conf, info, "unknown OS: '$1'" % arg)
elif theOS != platform.hostOS: elif theOS != conf.target.hostOS:
setTarget(theOS, targetCPU) setTarget(conf.target, theOS, conf.target.targetCPU)
of "cpu": of "cpu":
expectArg(conf, switch, arg, pass, info) expectArg(conf, switch, arg, pass, info)
if pass in {passCmd1, passPP}: if pass in {passCmd1, passPP}:
cpu = platform.nameToCPU(arg) let cpu = platform.nameToCPU(arg)
if cpu == cpuNone: localError(conf, info, "unknown CPU: '$1'" % arg) if cpu == cpuNone: localError(conf, info, "unknown CPU: '$1'" % arg)
elif cpu != platform.hostCPU: elif cpu != conf.target.hostCPU:
setTarget(targetOS, cpu) setTarget(conf.target, conf.target.targetOS, cpu)
of "run", "r": of "run", "r":
expectNoArg(conf, switch, arg, pass, info) expectNoArg(conf, switch, arg, pass, info)
incl(conf.globalOptions, optRun) incl(conf.globalOptions, optRun)
@ -628,9 +626,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "help", "h": of "help", "h":
expectNoArg(conf, switch, arg, pass, info) expectNoArg(conf, switch, arg, pass, info)
helpOnError(conf, pass) helpOnError(conf, pass)
of "symbolfiles": of "symbolfiles", "incremental":
case arg.normalize case arg.normalize
of "on": conf.symbolFiles = enabledSf of "on": conf.symbolFiles = v2Sf
of "off": conf.symbolFiles = disabledSf of "off": conf.symbolFiles = disabledSf
of "writeonly": conf.symbolFiles = writeOnlySf of "writeonly": conf.symbolFiles = writeOnlySf
of "readonly": conf.symbolFiles = readOnlySf of "readonly": conf.symbolFiles = readOnlySf

View file

@ -70,3 +70,4 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimNoNil") defineSymbol("nimNoNil")
defineSymbol("nimNoZeroTerminator") defineSymbol("nimNoZeroTerminator")
defineSymbol("nimNotNil") defineSymbol("nimNotNil")
defineSymbol("nimVmExportFixed")

View file

@ -1,360 +1,6 @@
# ## Use the module 'lineinfos' instead!
#
# The Nim Compiler
# (c) Copyright 2018 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module contains the rather excessive configuration object that {.deprecated.}
## needs to be passed around to everything so that the compiler becomes
## more useful as a library.
import tables import lineinfos
export lineinfos
const
explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
type
TMsgKind* = enum
errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile,
errXExpected,
errGridTableNotImplemented,
errGeneralParseError,
errNewSectionExpected,
errInvalidDirectiveX,
errGenerated,
errUser,
warnCannotOpenFile,
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
warnDeprecated, warnConfigDeprecated,
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
warnUnknownSubstitutionX, warnLanguageXNotSupported,
warnFieldXNotSupported, warnCommentXIgnored,
warnTypelessParam,
warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
warnEachIdentIsTuple, warnShadowIdent,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
warnInconsistentSpacing, warnUser,
hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
hintConditionAlwaysTrue, hintName, hintPattern,
hintExecuting, hintLinking, hintDependency,
hintSource, hintPerformance, hintStackTrace, hintGCStats,
hintUser, hintUserRaw
const
MsgKindToStr*: array[TMsgKind, string] = [
errUnknown: "unknown error",
errInternal: "internal error: $1",
errIllFormedAstX: "illformed AST: $1",
errCannotOpenFile: "cannot open '$1'",
errXExpected: "'$1' expected",
errGridTableNotImplemented: "grid table is not implemented",
errGeneralParseError: "general parse error",
errNewSectionExpected: "new section expected",
errInvalidDirectiveX: "invalid directive: '$1'",
errGenerated: "$1",
errUser: "$1",
warnCannotOpenFile: "cannot open '$1'",
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
warnXIsNeverRead: "'$1' is never read",
warnXmightNotBeenInit: "'$1' might not have been initialized",
warnDeprecated: "$1 is deprecated",
warnConfigDeprecated: "config file '$1' is deprecated",
warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)",
warnUnknownMagic: "unknown magic '$1' might crash the compiler",
warnRedefinitionOfLabel: "redefinition of label '$1'",
warnUnknownSubstitutionX: "unknown substitution '$1'",
warnLanguageXNotSupported: "language '$1' not supported",
warnFieldXNotSupported: "field '$1' not supported",
warnCommentXIgnored: "comment '$1' ignored",
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
warnWriteToForeignHeap: "write to foreign heap",
warnUnsafeCode: "unsafe code: '$1'",
warnEachIdentIsTuple: "each identifier is a tuple",
warnShadowIdent: "shadowed identifier: '$1'",
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.",
warnProveField: "cannot prove that field '$1' is accessible",
warnProveIndex: "cannot prove index '$1' is valid",
warnGcUnsafe: "not GC-safe: '$1'",
warnGcUnsafe2: "$1",
warnUninit: "'$1' might not have been initialized",
warnGcMem: "'$1' uses GC'ed memory",
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
warnLockLevel: "$1",
warnResultShadowed: "Special variable 'result' is shadowed.",
warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
warnUser: "$1",
hintSuccess: "operation successful",
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
hintLineTooLong: "line too long",
hintXDeclaredButNotUsed: "'$1' is declared but not used",
hintConvToBaseNotNeeded: "conversion to base object is not needed",
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
hintExprAlwaysX: "expression evaluates always to '$1'",
hintQuitCalled: "quit() called",
hintProcessing: "$1",
hintCodeBegin: "generated code listing:",
hintCodeEnd: "end of listing",
hintConf: "used config file '$1'",
hintPath: "added path: '$1'",
hintConditionAlwaysTrue: "condition is always true: '$1'",
hintName: "name should be: '$1'",
hintPattern: "$1",
hintExecuting: "$1",
hintLinking: "",
hintDependency: "$1",
hintSource: "$1",
hintPerformance: "$1",
hintStackTrace: "$1",
hintGCStats: "$1",
hintUser: "$1",
hintUserRaw: "$1"]
const
WarningsToStr* = ["CannotOpenFile", "OctalEscape",
"XIsNeverRead", "XmightNotBeenInit",
"Deprecated", "ConfigDeprecated",
"SmallLshouldNotBeUsed", "UnknownMagic",
"RedefinitionOfLabel", "UnknownSubstitutionX",
"LanguageXNotSupported", "FieldXNotSupported",
"CommentXIgnored",
"TypelessParam", "UseBase", "WriteToForeignHeap",
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
"Spacing", "User"]
HintsToStr* = ["Success", "SuccessX", "LineTooLong",
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
"Source", "Performance", "StackTrace", "GCStats",
"User", "UserRaw"]
const
fatalMin* = errUnknown
fatalMax* = errInternal
errMin* = errUnknown
errMax* = errUser
warnMin* = warnCannotOpenFile
warnMax* = pred(hintSuccess)
hintMin* = hintSuccess
hintMax* = high(TMsgKind)
static:
doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
type
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
TNoteKinds* = set[TNoteKind]
const
NotesVerbosity*: array[0..3, TNoteKinds] = [
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
warnProveField, warnProveIndex,
warnGcUnsafe,
hintSuccessX, hintPath, hintConf,
hintProcessing, hintPattern,
hintDependency,
hintExecuting, hintLinking,
hintCodeBegin, hintCodeEnd,
hintSource, hintStackTrace,
hintGCStats},
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
warnProveField, warnProveIndex,
warnGcUnsafe,
hintPath,
hintDependency,
hintCodeBegin, hintCodeEnd,
hintSource, hintStackTrace,
hintGCStats},
{low(TNoteKind)..high(TNoteKind)} - {hintStackTrace, warnUninit},
{low(TNoteKind)..high(TNoteKind)}]
const
errXMustBeCompileTime* = "'$1' can only be used in compile-time context"
errArgsNeedRunOption* = "arguments can only be given if the '--run' option is selected"
#[
errStringLiteralExpected: "string literal expected",
errIntLiteralExpected: "integer literal expected",
errIdentifierExpected: "identifier expected, but found '$1'",
errNewlineExpected: "newline expected, but found '$1'",
errInvalidModuleName: "invalid module name: '$1'",
errOnOrOffExpected: "'on' or 'off' expected",
errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected",
errInvalidPragma: "invalid pragma",
errUnknownPragma: "unknown pragma: '$1'",
errAtPopWithoutPush: "'pop' without a 'push' pragma",
errEmptyAsm: "empty asm statement",
errInvalidIndentation: "invalid indentation",
errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type",
errAttemptToRedefine: ,
errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma",
errStmtExpected: "statement expected",
errInvalidLabel: "'$1' is no label",
errInvalidCmdLineOption: "invalid command line option: '$1'",
errCmdLineArgExpected: "argument for command line option expected: '$1'",
errCmdLineNoArgExpected: "invalid argument for command line option: '$1'",
errInvalidVarSubstitution: "invalid variable substitution in '$1'",
errUnknownVar: "unknown variable: '$1'",
errUnknownCcompiler: "unknown C compiler: '$1'",
errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found",
errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found",
errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found",
,
errInvalidMultipleAsgn: "multiple assignment is not allowed",
errColonOrEqualsExpected: "':' or '=' expected, but found '$1'",
errUndeclaredField: "undeclared field: '$1'",
errUndeclaredRoutine: "attempting to call undeclared routine: '$1'",
errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier",
errTypeExpected: "type expected",
errSystemNeeds: "system module needs '$1'",
errExecutionOfProgramFailed: "execution of an external program failed: '$1'",
errNotOverloadable: ,
errInvalidArgForX: "invalid argument for '$1'",
errStmtHasNoEffect: "statement has no effect",
,
errXExpectsArrayType: "'$1' expects an array type",
errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
errExprXAmbiguous: "expression '$1' ambiguous in this context",
errConstantDivisionByZero: ,
errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
errOverOrUnderflow: ,
errCannotEvalXBecauseIncompletelyDefined: ,
errChrExpectsRange0_255: "'chr' expects an int in the range 0..255",
errDynlibRequiresExportc: "'dynlib' requires 'exportc'",
errNilAccess: "attempt to access a nil address",
errIndexOutOfBounds: "index out of bounds",
errIndexTypesDoNotMatch: "index types do not match",
errBracketsInvalidForType: "'[]' operator invalid for this type",
errValueOutOfSetBounds: "value out of set bounds",
errFieldNotInit: "field '$1' not initialized",
errExprXCannotBeCalled: "expression '$1' cannot be called",
errExprHasNoType: "expression has no type",
errExprXHasNoType:,
errCastNotInSafeMode: "'cast' not allowed in safe mode",
errExprCannotBeCastToX: ,
errCommaOrParRiExpected: "',' or ')' expected",
errCurlyLeOrParLeExpected: "'{' or '(' expected",
errSectionExpected: "section ('type', 'proc', etc.) expected",
errRangeExpected: "range expected",
errMagicOnlyInSystem: "'magic' only allowed in system module",
errPowerOfTwoExpected: "power of two expected",
errStringMayNotBeEmpty: "string literal may not be empty",
errCallConvExpected: "calling convention expected",
errProcOnlyOneCallConv: "a proc can only have one calling convention",
errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used",
errExprMustBeBool: "expression must be of type 'bool'",
errConstExprExpected: "constant expression expected",
errDuplicateCaseLabel: "duplicate case label",
errRangeIsEmpty: "range is empty",
,
errSelectorMustBeOrdinal: "selector must be of an ordinal type",
errOrdXMustNotBeNegative: "ord($1) must not be negative",
errLenXinvalid: "len($1) must be less than 32768",
errTypeXhasUnknownSize: "type '$1' has unknown size",
errConstNeedsConstExpr: "a constant can only be initialized with a constant expression",
errConstNeedsValue: "a constant needs a value",
errResultCannotBeOpenArray: "the result type cannot be on open array",
errSizeTooBig: "computing the type's size produced an overflow",
errInheritanceOnlyWithEnums: "inheritance only works with an enum",
errIllegalRecursionInTypeX:,
errCannotInstantiateX: "cannot instantiate: '$1'",
errTypeMismatch: "type mismatch: got <",
errButExpected: "but expected one of: ",
errButExpectedX: "but expected '$1'",
errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
errWrongNumberOfArguments: "wrong number of arguments",
errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
errXCannotBePassedToProcVar: ,
,
errImplOfXexpected: ,
errIllegalConvFromXtoY: ,
errCannotBindXTwice: "cannot bind parameter '$1' twice",
errInvalidOrderInArrayConstructor: ,
errInvalidOrderInEnumX: "invalid order in enum '$1'",
errEnumXHasHoles: "enum '$1' has holes",
errExceptExpected: "'except' or 'finally' expected",
errInvalidTry: "after catch all 'except' or 'finally' no section may follow",
errOptionExpected: ,
errXisNoLabel: "'$1' is not a label",
errNotAllCasesCovered: "not all cases are covered",
errUnknownSubstitionVar: "unknown substitution variable: '$1'",
errComplexStmtRequiresInd: "complex statement requires indentation",
errXisNotCallable: "'$1' is not callable",
errNoPragmasAllowedForX: "no pragmas allowed for $1",
,
errInvalidParamKindX: "invalid param kind: '$1'",
errDefaultArgumentInvalid: "default argument invalid",
errNamedParamHasToBeIdent: "named parameter has to be an identifier",
errNoReturnTypeForX: "no return type allowed for $1",
errConvNeedsOneArg: "a type conversion needs exactly one argument",
errInvalidPragmaX: ,
errXNotAllowedHere: "$1 not allowed here",
errXisNoType: "invalid type: '$1'",
errCircumNeedsPointer: "'[]' needs a pointer or reference type",
errInvalidExpression: "invalid expression",
errInvalidExpressionX: "invalid expression: '$1'",
errEnumHasNoValueX: "enum has no value '$1'",
,
errNoCommand: "no command given",
errInvalidCommandX: "invalid command: '$1'",
errXNeedsParamObjectType: ,
errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N",
errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N",
errInstantiationFrom: "template/generic instantiation from here",
errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
errCommandExpectsFilename: "command expects a filename argument",
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
errXExpected: "'$1' expected",
,
errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'",
errInvalidSectionStart: "invalid section start",
errGridTableNotImplemented: "grid table is not implemented",
errGeneralParseError: "general parse error",
errNewSectionExpected: "new section expected",
errWhitespaceExpected: "whitespace expected, got '$1'",
errXisNoValidIndexFile: "'$1' is no valid index file",
errCannotRenderX: "cannot render reStructuredText element '$1'",
errVarVarTypeNotAllowed: ,
errInstantiateXExplicitly: "instantiate '$1' explicitly",
errOnlyACallOpCanBeDelegator: ,
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
"because the parameter '$1' has a generic type",
errDestructorNotGenericEnough: "Destructor signature is too specific. " &
"A destructor must be associated will all instantiations of a generic type",
errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
"templates, macros and other inline iterators",
errXExpectsTwoArguments: "'$1' expects two arguments",
errXExpectsObjectTypes: "'$1' expects object types",
errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype",
errTooManyIterations: "interpretation requires too many iterations; " &
"if you are sure this is not a bug in your code edit " &
"compiler/vmdef.MaxLoopIterations and rebuild the compiler",
errFieldXNotFound: "field '$1' cannot be found",
errInvalidConversionFromTypeX: "invalid conversion from type '$1'",
errAssertionFailed: "assertion failed",
errCannotGenerateCodeForX: "cannot generate code for '$1'",
errXRequiresOneArgument: "$1 requires one parameter",
errUnhandledExceptionX: "unhandled exception: $1",
errCyclicTree: "macro returned a cyclic abstract syntax tree",
errXisNoMacroOrTemplate: "'$1' is no macro or template",
errXhasSideEffects: "'$1' can have side effects",
errWrongSymbolX:,
errIllegalCaptureX: "illegal capture '$1'",
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
,
]#

View file

@ -14,46 +14,51 @@ import
from modulegraphs import ModuleGraph from modulegraphs import ModuleGraph
proc generateDot*(project: string)
type type
TGen = object of TPassContext TGen = object of TPassContext
module*: PSym module: PSym
config: ConfigRef config: ConfigRef
graph: ModuleGraph
PGen = ref TGen PGen = ref TGen
var gDotGraph: Rope # the generated DOT file; we need a global variable Backend = ref object of RootRef
dotGraph: Rope
proc addDependencyAux(importing, imported: string) = proc addDependencyAux(b: Backend; importing, imported: string) =
addf(gDotGraph, "$1 -> \"$2\";$n", [rope(importing), rope(imported)]) addf(b.dotGraph, "$1 -> \"$2\";$n", [rope(importing), rope(imported)])
# s1 -> s2_4[label="[0-9]"]; # s1 -> s2_4[label="[0-9]"];
proc addDotDependency(c: PPassContext, n: PNode): PNode = proc addDotDependency(c: PPassContext, n: PNode): PNode =
result = n result = n
var g = PGen(c) let g = PGen(c)
let b = Backend(g.graph.backend)
case n.kind case n.kind
of nkImportStmt: of nkImportStmt:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var imported = getModuleName(g.config, n.sons[i]) var imported = getModuleName(g.config, n.sons[i])
addDependencyAux(g.module.name.s, imported) addDependencyAux(b, g.module.name.s, imported)
of nkFromStmt, nkImportExceptStmt: of nkFromStmt, nkImportExceptStmt:
var imported = getModuleName(g.config, n.sons[0]) var imported = getModuleName(g.config, n.sons[0])
addDependencyAux(g.module.name.s, imported) addDependencyAux(b, g.module.name.s, imported)
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr: of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i]) for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
else: else:
discard discard
proc generateDot(project: string) = proc generateDot*(graph: ModuleGraph; project: string) =
writeRope("digraph $1 {$n$2}$n" % [ let b = Backend(graph.backend)
rope(changeFileExt(extractFilename(project), "")), gDotGraph], discard writeRope("digraph $1 {$n$2}$n" % [
rope(changeFileExt(extractFilename(project), "")), b.dotGraph],
changeFileExt(project, "dot")) changeFileExt(project, "dot"))
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var g: PGen var g: PGen
new(g) new(g)
g.module = module g.module = module
g.config = graph.config g.config = graph.config
g.graph = graph
if graph.backend == nil:
graph.backend = Backend(dotGraph: nil)
result = g result = g
const gendependPass* = makePass(open = myOpen, process = addDotDependency) const gendependPass* = makePass(open = myOpen, process = addDotDependency)

View file

@ -116,8 +116,8 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently
import import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
strutils, options, dfa, lowerings, rodread, tables, modulegraphs, strutils, options, dfa, lowerings, tables, modulegraphs,
configuration lineinfos
const const
InterestingSyms = {skVar, skResult, skLet} InterestingSyms = {skVar, skResult, skLet}
@ -132,10 +132,11 @@ type
destroys, topLevelVars: PNode destroys, topLevelVars: PNode
toDropBit: Table[int, PSym] toDropBit: Table[int, PSym]
graph: ModuleGraph graph: ModuleGraph
emptyNode: PNode
proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
# XXX why are temps fields in an object here? # XXX why are temps fields in an object here?
let f = newSym(skField, getIdent(":d" & $c.tmpObj.n.len), c.owner, info) let f = newSym(skField, getIdent(c.graph.cache, ":d" & $c.tmpObj.n.len), c.owner, info)
f.typ = typ f.typ = typ
rawAddField c.tmpObj, f rawAddField c.tmpObj, f
result = rawDirectAccess(c.tmp, f) result = rawDirectAccess(c.tmp, f)
@ -243,17 +244,17 @@ proc genDestroy(c: Con; t: PType; dest: PNode): PNode =
genOp(t.destructor, "=destroy") genOp(t.destructor, "=destroy")
proc addTopVar(c: var Con; v: PNode) = proc addTopVar(c: var Con; v: PNode) =
c.topLevelVars.add newTree(nkIdentDefs, v, emptyNode, emptyNode) c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode)
proc dropBit(c: var Con; s: PSym): PSym = proc dropBit(c: var Con; s: PSym): PSym =
result = c.toDropBit.getOrDefault(s.id) result = c.toDropBit.getOrDefault(s.id)
assert result != nil assert result != nil
proc registerDropBit(c: var Con; s: PSym) = proc registerDropBit(c: var Con; s: PSym) =
let result = newSym(skTemp, getIdent(s.name.s & "_AliveBit"), c.owner, s.info) let result = newSym(skTemp, getIdent(c.graph.cache, s.name.s & "_AliveBit"), c.owner, s.info)
result.typ = getSysType(c.graph, s.info, tyBool) result.typ = getSysType(c.graph, s.info, tyBool)
let trueVal = newIntTypeNode(nkIntLit, 1, result.typ) let trueVal = newIntTypeNode(nkIntLit, 1, result.typ)
c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, emptyNode, trueVal) c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, c.emptyNode, trueVal)
c.toDropBit[s.id] = result c.toDropBit[s.id] = result
# generate: # generate:
# if not sinkParam_AliveBit: `=destroy`(sinkParam) # if not sinkParam_AliveBit: `=destroy`(sinkParam)
@ -322,13 +323,13 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode =
# generate: (let tmp = v; reset(v); tmp) # generate: (let tmp = v; reset(v); tmp)
result = newNodeIT(nkStmtListExpr, n.info, n.typ) result = newNodeIT(nkStmtListExpr, n.info, n.typ)
var temp = newSym(skLet, getIdent("blitTmp"), c.owner, n.info) var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.owner, n.info)
var v = newNodeI(nkLetSection, n.info) var v = newNodeI(nkLetSection, n.info)
let tempAsNode = newSymNode(temp) let tempAsNode = newSymNode(temp)
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3) var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
vpart.sons[0] = tempAsNode vpart.sons[0] = tempAsNode
vpart.sons[1] = ast.emptyNode vpart.sons[1] = c.emptyNode
vpart.sons[2] = n vpart.sons[2] = n
add(v, vpart) add(v, vpart)
@ -427,13 +428,14 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
echo "injecting into ", n echo "injecting into ", n
var c: Con var c: Con
c.owner = owner c.owner = owner
c.tmp = newSym(skTemp, getIdent":d", owner, n.info) c.tmp = newSym(skTemp, getIdent(g.cache, ":d"), owner, n.info)
c.tmpObj = createObj(g, owner, n.info) c.tmpObj = createObj(g, owner, n.info)
c.tmp.typ = c.tmpObj c.tmp.typ = c.tmpObj
c.destroys = newNodeI(nkStmtList, n.info) c.destroys = newNodeI(nkStmtList, n.info)
c.topLevelVars = newNodeI(nkVarSection, n.info) c.topLevelVars = newNodeI(nkVarSection, n.info)
c.toDropBit = initTable[int, PSym]() c.toDropBit = initTable[int, PSym]()
c.graph = g c.graph = g
c.emptyNode = newNodeI(nkEmpty, n.info)
let cfg = constructCfg(owner, n) let cfg = constructCfg(owner, n)
shallowCopy(c.g, cfg) shallowCopy(c.g, cfg)
c.jumpTargets = initIntSet() c.jumpTargets = initIntSet()

View file

@ -23,7 +23,7 @@
## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen. ## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen.
## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf ## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf
import ast, astalgo, types, intsets, tables, msgs, options import ast, astalgo, types, intsets, tables, msgs, options, lineinfos
type type
InstrKind* = enum InstrKind* = enum
@ -54,7 +54,7 @@ type
blocks: seq[TBlock] blocks: seq[TBlock]
proc debugInfo(info: TLineInfo): string = proc debugInfo(info: TLineInfo): string =
result = info.toFilename & ":" & $info.line result = $info.line #info.toFilename & ":" & $info.line
proc codeListing(c: ControlFlowGraph, result: var string, start=0; last = -1) = proc codeListing(c: ControlFlowGraph, result: var string, start=0; last = -1) =
# for debugging purposes # for debugging purposes
@ -87,7 +87,8 @@ proc echoCfg*(c: ControlFlowGraph; start=0; last = -1) {.deprecated.} =
## echos the ControlFlowGraph for debugging purposes. ## echos the ControlFlowGraph for debugging purposes.
var buf = "" var buf = ""
codeListing(c, buf, start, last) codeListing(c, buf, start, last)
echo buf when declared(echo):
echo buf
proc forkI(c: var Con; n: PNode): TPosition = proc forkI(c: var Con; n: PNode): TPosition =
result = TPosition(c.code.len) result = TPosition(c.code.len)

View file

@ -16,7 +16,7 @@ import
wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast, wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast,
packages/docutils/rst, packages/docutils/rstgen, times, packages/docutils/rst, packages/docutils/rstgen, times,
packages/docutils/highlite, sempass2, json, xmltree, cgi, packages/docutils/highlite, sempass2, json, xmltree, cgi,
typesrenderer, astalgo, modulepaths, configuration typesrenderer, astalgo, modulepaths, lineinfos
type type
TSections = array[TSymKind, Rope] TSections = array[TSymKind, Rope]
@ -30,6 +30,7 @@ type
types: TStrTable types: TStrTable
isPureRst: bool isPureRst: bool
conf*: ConfigRef conf*: ConfigRef
cache*: IdentCache
PDoc* = ref TDocumentor ## Alias to type less. PDoc* = ref TDocumentor ## Alias to type less.
@ -86,10 +87,11 @@ proc parseRst(text, filename: string,
result = rstParse(text, filename, line, column, hasToc, rstOptions, result = rstParse(text, filename, line, column, hasToc, rstOptions,
docgenFindFile, compilerMsgHandler) docgenFindFile, compilerMsgHandler)
proc newDocumentor*(filename: string, conf: ConfigRef): PDoc = proc newDocumentor*(filename: string; cache: IdentCache; conf: ConfigRef): PDoc =
declareClosures() declareClosures()
new(result) new(result)
result.conf = conf result.conf = conf
result.cache = cache
initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex), initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex),
conf.configVars, filename, {roSupportRawDirective}, conf.configVars, filename, {roSupportRawDirective},
docgenFindFile, compilerMsgHandler) docgenFindFile, compilerMsgHandler)
@ -190,7 +192,7 @@ proc genComment(d: PDoc, n: PNode): string =
result = "" result = ""
var dummyHasToc: bool var dummyHasToc: bool
if n.comment != nil: if n.comment != nil:
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info), renderRstToOut(d[], parseRst(n.comment, toFilename(d.conf, n.info),
toLinenumber(n.info), toColumn(n.info), toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options, d.conf), result) dummyHasToc, d.options, d.conf), result)
@ -307,13 +309,13 @@ when false:
result = findDocComment(n.sons[i]) result = findDocComment(n.sons[i])
if result != nil: return if result != nil: return
proc extractDocComment*(s: PSym, d: PDoc = nil): string = proc extractDocComment*(s: PSym, d: PDoc): string =
let n = findDocComment(s.ast) let n = findDocComment(s.ast)
result = "" result = ""
if not n.isNil: if not n.isNil:
if not d.isNil: if not d.isNil:
var dummyHasToc: bool var dummyHasToc: bool
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info), renderRstToOut(d[], parseRst(n.comment, toFilename(d.conf, n.info),
toLinenumber(n.info), toColumn(n.info), toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options + {roSkipPounds}), dummyHasToc, d.options + {roSkipPounds}),
result) result)
@ -349,18 +351,18 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
else: else:
result = "" result = ""
proc getNameIdent(n: PNode): PIdent = proc getNameIdent(cache: IdentCache; n: PNode): PIdent =
case n.kind case n.kind
of nkPostfix: result = getNameIdent(n.sons[1]) of nkPostfix: result = getNameIdent(cache, n.sons[1])
of nkPragmaExpr: result = getNameIdent(n.sons[0]) of nkPragmaExpr: result = getNameIdent(cache, n.sons[0])
of nkSym: result = n.sym.name of nkSym: result = n.sym.name
of nkIdent: result = n.ident of nkIdent: result = n.ident
of nkAccQuoted: of nkAccQuoted:
var r = "" var r = ""
for i in 0..<n.len: r.add(getNameIdent(n[i]).s) for i in 0..<n.len: r.add(getNameIdent(cache, n[i]).s)
result = getIdent(r) result = getIdent(cache, r)
of nkOpenSymChoice, nkClosedSymChoice: of nkOpenSymChoice, nkClosedSymChoice:
result = getNameIdent(n[0]) result = getNameIdent(cache, n[0])
else: else:
result = nil result = nil
@ -502,7 +504,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc") let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc")
if docItemSeeSrc.len > 0: if docItemSeeSrc.len > 0:
let cwd = canonicalizePath(d.conf, getCurrentDir()) let cwd = canonicalizePath(d.conf, getCurrentDir())
var path = n.info.toFullPath var path = toFullPath(d.conf, n.info)
if path.startsWith(cwd): if path.startsWith(cwd):
path = path[cwd.len+1 .. ^1].replace('\\', '/') path = path[cwd.len+1 .. ^1].replace('\\', '/')
let gitUrl = getConfigVar(d.conf, "git.url") let gitUrl = getConfigVar(d.conf, "git.url")
@ -586,21 +588,21 @@ proc generateDoc*(d: PDoc, n: PNode) =
case n.kind case n.kind
of nkCommentStmt: add(d.modDesc, genComment(d, n)) of nkCommentStmt: add(d.modDesc, genComment(d, n))
of nkProcDef: of nkProcDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
genItem(d, n, n.sons[namePos], skProc) genItem(d, n, n.sons[namePos], skProc)
of nkFuncDef: of nkFuncDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
genItem(d, n, n.sons[namePos], skFunc) genItem(d, n, n.sons[namePos], skFunc)
of nkMethodDef: of nkMethodDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
genItem(d, n, n.sons[namePos], skMethod) genItem(d, n, n.sons[namePos], skMethod)
of nkIteratorDef: of nkIteratorDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
genItem(d, n, n.sons[namePos], skIterator) genItem(d, n, n.sons[namePos], skIterator)
of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro) of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
of nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate) of nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate)
of nkConverterDef: of nkConverterDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
genItem(d, n, n.sons[namePos], skConverter) genItem(d, n, n.sons[namePos], skConverter)
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection: of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
@ -630,23 +632,23 @@ proc generateJson*(d: PDoc, n: PNode) =
d.add %{ "comment": %stripped, "line": %n.info.line.int, d.add %{ "comment": %stripped, "line": %n.info.line.int,
"col": %n.info.col } "col": %n.info.col }
of nkProcDef: of nkProcDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
d.add genJsonItem(d, n, n.sons[namePos], skProc) d.add genJsonItem(d, n, n.sons[namePos], skProc)
of nkFuncDef: of nkFuncDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
d.add genJsonItem(d, n, n.sons[namePos], skFunc) d.add genJsonItem(d, n, n.sons[namePos], skFunc)
of nkMethodDef: of nkMethodDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
d.add genJsonItem(d, n, n.sons[namePos], skMethod) d.add genJsonItem(d, n, n.sons[namePos], skMethod)
of nkIteratorDef: of nkIteratorDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
d.add genJsonItem(d, n, n.sons[namePos], skIterator) d.add genJsonItem(d, n, n.sons[namePos], skIterator)
of nkMacroDef: of nkMacroDef:
d.add genJsonItem(d, n, n.sons[namePos], skMacro) d.add genJsonItem(d, n, n.sons[namePos], skMacro)
of nkTemplateDef: of nkTemplateDef:
d.add genJsonItem(d, n, n.sons[namePos], skTemplate) d.add genJsonItem(d, n, n.sons[namePos], skTemplate)
of nkConverterDef: of nkConverterDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
d.add genJsonItem(d, n, n.sons[namePos], skConverter) d.add genJsonItem(d, n, n.sons[namePos], skConverter)
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection: of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
@ -673,23 +675,23 @@ proc generateTags*(d: PDoc, n: PNode, r: var Rope) =
let stripped = n.comment.substr(2).strip let stripped = n.comment.substr(2).strip
r.add stripped r.add stripped
of nkProcDef: of nkProcDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
r.add genTagsItem(d, n, n.sons[namePos], skProc) r.add genTagsItem(d, n, n.sons[namePos], skProc)
of nkFuncDef: of nkFuncDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
r.add genTagsItem(d, n, n.sons[namePos], skFunc) r.add genTagsItem(d, n, n.sons[namePos], skFunc)
of nkMethodDef: of nkMethodDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
r.add genTagsItem(d, n, n.sons[namePos], skMethod) r.add genTagsItem(d, n, n.sons[namePos], skMethod)
of nkIteratorDef: of nkIteratorDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
r.add genTagsItem(d, n, n.sons[namePos], skIterator) r.add genTagsItem(d, n, n.sons[namePos], skIterator)
of nkMacroDef: of nkMacroDef:
r.add genTagsItem(d, n, n.sons[namePos], skMacro) r.add genTagsItem(d, n, n.sons[namePos], skMacro)
of nkTemplateDef: of nkTemplateDef:
r.add genTagsItem(d, n, n.sons[namePos], skTemplate) r.add genTagsItem(d, n, n.sons[namePos], skTemplate)
of nkConverterDef: of nkConverterDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(d.cache, n)
r.add genTagsItem(d, n, n.sons[namePos], skConverter) r.add genTagsItem(d, n, n.sons[namePos], skConverter)
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection: of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
@ -777,10 +779,16 @@ proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string =
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) = proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
var content = genOutFile(d) var content = genOutFile(d)
var success = true
var filename: string
if optStdout in d.conf.globalOptions: if optStdout in d.conf.globalOptions:
writeRope(stdout, content) writeRope(stdout, content)
filename = "<stdout>"
else: else:
writeRope(content, getOutFile2(d.conf, filename, outExt, "htmldocs"), useWarning) filename = getOutFile2(d.conf, filename, outExt, "htmldocs")
success = writeRope(content, filename)
if not success:
rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, filename)
proc writeOutputJson*(d: PDoc, filename, outExt: string, proc writeOutputJson*(d: PDoc, filename, outExt: string,
useWarning = false) = useWarning = false) =
@ -798,18 +806,18 @@ proc writeOutputJson*(d: PDoc, filename, outExt: string,
else: else:
discard "fixme: error report" discard "fixme: error report"
proc commandDoc*(conf: ConfigRef) = proc commandDoc*(cache: IdentCache, conf: ConfigRef) =
var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf) var ast = parseFile(conf.projectMainIdx, cache, conf)
if ast == nil: return if ast == nil: return
var d = newDocumentor(conf.projectFull, conf) var d = newDocumentor(conf.projectFull, cache, conf)
d.hasToc = true d.hasToc = true
generateDoc(d, ast) generateDoc(d, ast)
writeOutput(d, conf.projectFull, HtmlExt) writeOutput(d, conf.projectFull, HtmlExt)
generateIndex(d) generateIndex(d)
proc commandRstAux(conf: ConfigRef; filename, outExt: string) = proc commandRstAux(cache: IdentCache, conf: ConfigRef; filename, outExt: string) =
var filen = addFileExt(filename, "txt") var filen = addFileExt(filename, "txt")
var d = newDocumentor(filen, conf) var d = newDocumentor(filen, cache, conf)
d.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; d.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string;
status: int; content: string) = status: int; content: string) =
var outp: string var outp: string
@ -841,17 +849,16 @@ proc commandRstAux(conf: ConfigRef; filename, outExt: string) =
writeOutput(d, filename, outExt) writeOutput(d, filename, outExt)
generateIndex(d) generateIndex(d)
proc commandRst2Html*(conf: ConfigRef) = proc commandRst2Html*(cache: IdentCache, conf: ConfigRef) =
commandRstAux(conf, conf.projectFull, HtmlExt) commandRstAux(cache, conf, conf.projectFull, HtmlExt)
proc commandRst2TeX*(conf: ConfigRef) = proc commandRst2TeX*(cache: IdentCache, conf: ConfigRef) =
splitter = "\\-" commandRstAux(cache, conf, conf.projectFull, TexExt)
commandRstAux(conf, conf.projectFull, TexExt)
proc commandJson*(conf: ConfigRef) = proc commandJson*(cache: IdentCache, conf: ConfigRef) =
var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf) var ast = parseFile(conf.projectMainIdx, cache, conf)
if ast == nil: return if ast == nil: return
var d = newDocumentor(conf.projectFull, conf) var d = newDocumentor(conf.projectFull, cache, conf)
d.hasToc = true d.hasToc = true
generateJson(d, ast) generateJson(d, ast)
let json = d.jArray let json = d.jArray
@ -861,12 +868,14 @@ proc commandJson*(conf: ConfigRef) =
writeRope(stdout, content) writeRope(stdout, content)
else: else:
#echo getOutFile(gProjectFull, JsonExt) #echo getOutFile(gProjectFull, JsonExt)
writeRope(content, getOutFile(conf, conf.projectFull, JsonExt), useWarning = false) let filename = getOutFile(conf, conf.projectFull, JsonExt)
if not writeRope(content, filename):
rawMessage(conf, errCannotOpenFile, filename)
proc commandTags*(conf: ConfigRef) = proc commandTags*(cache: IdentCache, conf: ConfigRef) =
var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf) var ast = parseFile(conf.projectMainIdx, cache, conf)
if ast == nil: return if ast == nil: return
var d = newDocumentor(conf.projectFull, conf) var d = newDocumentor(conf.projectFull, cache, conf)
d.hasToc = true d.hasToc = true
var var
content: Rope content: Rope
@ -876,9 +885,11 @@ proc commandTags*(conf: ConfigRef) =
writeRope(stdout, content) writeRope(stdout, content)
else: else:
#echo getOutFile(gProjectFull, TagsExt) #echo getOutFile(gProjectFull, TagsExt)
writeRope(content, getOutFile(conf, conf.projectFull, TagsExt), useWarning = false) let filename = getOutFile(conf, conf.projectFull, TagsExt)
if not writeRope(content, filename):
rawMessage(conf, errCannotOpenFile, filename)
proc commandBuildIndex*(conf: ConfigRef) = proc commandBuildIndex*(cache: IdentCache, conf: ConfigRef) =
var content = mergeIndexes(conf.projectFull).rope var content = mergeIndexes(conf.projectFull).rope
let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), ["title", let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), ["title",
@ -887,4 +898,6 @@ proc commandBuildIndex*(conf: ConfigRef) =
["Index".rope, nil, nil, rope(getDateStr()), ["Index".rope, nil, nil, rope(getDateStr()),
rope(getClockStr()), content, nil, nil, nil]) rope(getClockStr()), content, nil, nil, nil])
# no analytics because context is not available # no analytics because context is not available
writeRope(code, getOutFile(conf, "theindex", HtmlExt)) let filename = getOutFile(conf, "theindex", HtmlExt)
if not writeRope(code, filename):
rawMessage(conf, errCannotOpenFile, filename)

View file

@ -11,7 +11,7 @@
# semantic checking. # semantic checking.
import import
os, options, ast, astalgo, msgs, ropes, idents, passes, docgen os, options, ast, astalgo, msgs, ropes, idents, passes, docgen, lineinfos
from modulegraphs import ModuleGraph from modulegraphs import ModuleGraph
@ -25,7 +25,7 @@ template closeImpl(body: untyped) {.dirty.} =
var g = PGen(p) var g = PGen(p)
let useWarning = sfMainModule notin g.module.flags let useWarning = sfMainModule notin g.module.flags
#echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId #echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId
if (g.module.owner.id == gMainPackageId and optWholeProject in g.doc.conf.globalOptions) or if (g.module.owner.id == g.doc.conf.mainPackageId and optWholeProject in g.doc.conf.globalOptions) or
sfMainModule in g.module.flags: sfMainModule in g.module.flags:
body body
try: try:
@ -35,11 +35,11 @@ template closeImpl(body: untyped) {.dirty.} =
proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl: closeImpl:
writeOutput(g.doc, g.module.filename, HtmlExt, useWarning) writeOutput(g.doc, toFilename(graph.config, FileIndex g.module.position), HtmlExt, useWarning)
proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl: closeImpl:
writeOutputJson(g.doc, g.module.filename, ".json", useWarning) writeOutputJson(g.doc, toFilename(graph.config, FileIndex g.module.position), ".json", useWarning)
proc processNode(c: PPassContext, n: PNode): PNode = proc processNode(c: PPassContext, n: PNode): PNode =
result = n result = n
@ -51,11 +51,11 @@ proc processNodeJson(c: PPassContext, n: PNode): PNode =
var g = PGen(c) var g = PGen(c)
generateJson(g.doc, n) generateJson(g.doc, n)
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var g: PGen var g: PGen
new(g) new(g)
g.module = module g.module = module
var d = newDocumentor(module.filename, graph.config) var d = newDocumentor(toFilename(graph.config, FileIndex module.position), graph.cache, graph.config)
d.hasToc = true d.hasToc = true
g.doc = d g.doc = d
result = g result = g

View file

@ -442,7 +442,7 @@ proc callForeignFunction*(call: PNode): PNode =
libffi.call(cif, fn, retVal, args) libffi.call(cif, fn, retVal, args)
if retVal.isNil: if retVal.isNil:
result = emptyNode result = newNode(nkEmpty)
else: else:
result = unpack(retVal, typ.sons[0], nil) result = unpack(retVal, typ.sons[0], nil)
result.info = call.info result.info = call.info
@ -484,7 +484,7 @@ proc callForeignFunction*(fn: PNode, fntyp: PType,
libffi.call(cif, fn, retVal, cargs) libffi.call(cif, fn, retVal, cargs)
if retVal.isNil: if retVal.isNil:
result = emptyNode result = newNode(nkEmpty)
else: else:
result = unpack(retVal, fntyp.sons[0], nil) result = unpack(retVal, fntyp.sons[0], nil)
result.info = info result.info = info

View file

@ -11,7 +11,7 @@
import import
strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer, strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
rodread lineinfos
type type
TemplCtx = object TemplCtx = object
@ -104,7 +104,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode
let default = s.typ.n.sons[i].sym.ast let default = s.typ.n.sons[i].sym.ast
if default.isNil or default.kind == nkEmpty: if default.isNil or default.kind == nkEmpty:
localError(conf, n.info, errWrongNumberOfArguments) localError(conf, n.info, errWrongNumberOfArguments)
addSon(result, ast.emptyNode) addSon(result, newNodeI(nkEmpty, n.info))
else: else:
addSon(result, default.copyTree) addSon(result, default.copyTree)
@ -114,7 +114,6 @@ proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode
# to prevent endless recursion in template instantiation # to prevent endless recursion in template instantiation
const evalTemplateLimit* = 1000 const evalTemplateLimit* = 1000
var evalTemplateCounter* = 0 # XXX remove this global
proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode = proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
when true: when true:
@ -140,8 +139,8 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
conf: ConfigRef; fromHlo=false): PNode = conf: ConfigRef; fromHlo=false): PNode =
inc(evalTemplateCounter) inc(conf.evalTemplateCounter)
if evalTemplateCounter > evalTemplateLimit: if conf.evalTemplateCounter > evalTemplateLimit:
globalError(conf, n.info, errTemplateInstantiationTooNested) globalError(conf, n.info, errTemplateInstantiationTooNested)
result = n result = n
@ -170,5 +169,5 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
evalTemplateAux(body.sons[i], args, ctx, result) evalTemplateAux(body.sons[i], args, ctx, result)
result.flags.incl nfFromTemplate result.flags.incl nfFromTemplate
result = wrapInComesFrom(n.info, tmpl, result) result = wrapInComesFrom(n.info, tmpl, result)
dec(evalTemplateCounter) dec(conf.evalTemplateCounter)

View file

@ -9,19 +9,14 @@
# Module providing functions for calling the different external C compilers # Module providing functions for calling the different external C compilers
# Uses some hard-wired facts about each C/C++ compiler, plus options read # Uses some hard-wired facts about each C/C++ compiler, plus options read
# from a configuration file, to provide generalized procedures to compile # from a lineinfos file, to provide generalized procedures to compile
# nim files. # nim files.
import import
ropes, os, strutils, osproc, platform, condsyms, options, msgs, ropes, os, strutils, osproc, platform, condsyms, options, msgs,
configuration, std / sha1, streams lineinfos, std / sha1, streams
#from debuginfo import writeDebugInfo
type type
TSystemCC* = enum
ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
ccTcc, ccPcc, ccUcc, ccIcl, ccIcc
TInfoCCProp* = enum # properties of the C compiler: TInfoCCProp* = enum # properties of the C compiler:
hasSwitchRange, # CC allows ranges in switch statements (GNU C) hasSwitchRange, # CC allows ranges in switch statements (GNU C)
hasComputedGoto, # CC has computed goto (GNU C extension) hasComputedGoto, # CC has computed goto (GNU C extension)
@ -336,37 +331,8 @@ const
hExt* = ".h" hExt* = ".h"
var proc libNameTmpl(conf: ConfigRef): string {.inline.} =
cCompiler* = ccGcc # the used compiler result = if conf.target.targetOS == osWindows: "$1.lib" else: "lib$1.a"
gMixedMode*: bool # true if some module triggered C++ codegen
cIncludes*: seq[string] = @[] # directories to search for included files
cLibs*: seq[string] = @[] # directories to search for lib files
cLinkedLibs*: seq[string] = @[] # libraries to link
# implementation
proc libNameTmpl(): string {.inline.} =
result = if targetOS == osWindows: "$1.lib" else: "lib$1.a"
type
CfileFlag* {.pure.} = enum
Cached, ## no need to recompile this time
External ## file was introduced via .compile pragma
Cfile* = object
cname*, obj*: string
flags*: set[CFileFlag]
CfileList = seq[Cfile]
var
externalToLink: seq[string] = @[] # files to link in addition to the file
# we compiled
linkOptionsCmd: string = ""
compileOptionsCmd: seq[string] = @[]
linkOptions: string = ""
compileOptions: string = ""
ccompilerpath: string = ""
toCompile: CfileList = @[]
proc nameToCC*(name: string): TSystemCC = proc nameToCC*(name: string): TSystemCC =
## Returns the kind of compiler referred to by `name`, or ccNone ## Returns the kind of compiler referred to by `name`, or ccNone
@ -389,10 +355,10 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
else: else:
suffix suffix
if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and if (conf.target.hostOS != conf.target.targetOS or conf.target.hostCPU != conf.target.targetCPU) and
optCompileOnly notin conf.globalOptions: optCompileOnly notin conf.globalOptions:
let fullCCname = platform.CPU[targetCPU].name & '.' & let fullCCname = platform.CPU[conf.target.targetCPU].name & '.' &
platform.OS[targetOS].name & '.' & platform.OS[conf.target.targetOS].name & '.' &
CC[c].name & fullSuffix CC[c].name & fullSuffix
result = getConfigVar(conf, fullCCname) result = getConfigVar(conf, fullCCname)
if result.len == 0: if result.len == 0:
@ -402,40 +368,40 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
result = getConfigVar(conf, CC[c].name & fullSuffix) result = getConfigVar(conf, CC[c].name & fullSuffix)
proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) = proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) =
cCompiler = nameToCC(ccname) conf.cCompiler = nameToCC(ccname)
if cCompiler == ccNone: if conf.cCompiler == ccNone:
localError(conf, info, "unknown C compiler: '$1'" % ccname) localError(conf, info, "unknown C compiler: '$1'" % ccname)
compileOptions = getConfigVar(conf, cCompiler, ".options.always") conf.compileOptions = getConfigVar(conf, conf.cCompiler, ".options.always")
linkOptions = "" conf.linkOptions = ""
ccompilerpath = getConfigVar(conf, cCompiler, ".path") conf.ccompilerpath = getConfigVar(conf, conf.cCompiler, ".path")
for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name) for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name)
defineSymbol(conf.symbols, CC[cCompiler].name) defineSymbol(conf.symbols, CC[conf.cCompiler].name)
proc addOpt(dest: var string, src: string) = proc addOpt(dest: var string, src: string) =
if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ") if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
add(dest, src) add(dest, src)
proc addLinkOption*(conf: ConfigRef; option: string) = proc addLinkOption*(conf: ConfigRef; option: string) =
addOpt(linkOptions, option) addOpt(conf.linkOptions, option)
proc addCompileOption*(conf: ConfigRef; option: string) = proc addCompileOption*(conf: ConfigRef; option: string) =
if strutils.find(compileOptions, option, 0) < 0: if strutils.find(conf.compileOptions, option, 0) < 0:
addOpt(compileOptions, option) addOpt(conf.compileOptions, option)
proc addLinkOptionCmd*(conf: ConfigRef; option: string) = proc addLinkOptionCmd*(conf: ConfigRef; option: string) =
addOpt(linkOptionsCmd, option) addOpt(conf.linkOptionsCmd, option)
proc addCompileOptionCmd*(conf: ConfigRef; option: string) = proc addCompileOptionCmd*(conf: ConfigRef; option: string) =
compileOptionsCmd.add(option) conf.compileOptionsCmd.add(option)
proc initVars*(conf: ConfigRef) = proc initVars*(conf: ConfigRef) =
# we need to define the symbol here, because ``CC`` may have never been set! # we need to define the symbol here, because ``CC`` may have never been set!
for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name) for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name)
defineSymbol(conf.symbols, CC[cCompiler].name) defineSymbol(conf.symbols, CC[conf.cCompiler].name)
addCompileOption(conf, getConfigVar(conf, cCompiler, ".options.always")) addCompileOption(conf, getConfigVar(conf, conf.cCompiler, ".options.always"))
#addLinkOption(getConfigVar(cCompiler, ".options.linker")) #addLinkOption(getConfigVar(cCompiler, ".options.linker"))
if len(ccompilerpath) == 0: if len(conf.ccompilerpath) == 0:
ccompilerpath = getConfigVar(conf, cCompiler, ".path") conf.ccompilerpath = getConfigVar(conf, conf.cCompiler, ".path")
proc completeCFilePath*(conf: ConfigRef; cfile: string, createSubDir: bool = true): string = proc completeCFilePath*(conf: ConfigRef; cfile: string, createSubDir: bool = true): string =
result = completeGeneratedFilePath(conf, cfile, createSubDir) result = completeGeneratedFilePath(conf, cfile, createSubDir)
@ -445,21 +411,21 @@ proc toObjFile*(conf: ConfigRef; filename: string): string =
#if filename.endsWith(".cpp"): #if filename.endsWith(".cpp"):
# result = changeFileExt(filename, "cpp." & CC[cCompiler].objExt) # result = changeFileExt(filename, "cpp." & CC[cCompiler].objExt)
#else: #else:
result = changeFileExt(filename, CC[cCompiler].objExt) result = changeFileExt(filename, CC[conf.cCompiler].objExt)
proc addFileToCompile*(conf: ConfigRef; cf: Cfile) = proc addFileToCompile*(conf: ConfigRef; cf: Cfile) =
toCompile.add(cf) conf.toCompile.add(cf)
proc resetCompilationLists*(conf: ConfigRef) = proc resetCompilationLists*(conf: ConfigRef) =
toCompile.setLen 0 conf.toCompile.setLen 0
## XXX: we must associate these with their originating module ## XXX: we must associate these with their originating module
# when the module is loaded/unloaded it adds/removes its items # when the module is loaded/unloaded it adds/removes its items
# That's because we still need to hash check the external files # That's because we still need to hash check the external files
# Maybe we can do that in checkDep on the other hand? # Maybe we can do that in checkDep on the other hand?
externalToLink.setLen 0 conf.externalToLink.setLen 0
proc addExternalFileToLink*(conf: ConfigRef; filename: string) = proc addExternalFileToLink*(conf: ConfigRef; filename: string) =
externalToLink.insert(filename, 0) conf.externalToLink.insert(filename, 0)
proc execWithEcho(conf: ConfigRef; cmd: string, msg = hintExecuting): int = proc execWithEcho(conf: ConfigRef; cmd: string, msg = hintExecuting): int =
rawMessage(conf, msg, cmd) rawMessage(conf, msg, cmd)
@ -472,9 +438,12 @@ proc execExternalProgram*(conf: ConfigRef; cmd: string, msg = hintExecuting) =
proc generateScript(conf: ConfigRef; projectFile: string, script: Rope) = proc generateScript(conf: ConfigRef; projectFile: string, script: Rope) =
let (dir, name, ext) = splitFile(projectFile) let (dir, name, ext) = splitFile(projectFile)
writeRope(script, getNimcacheDir(conf) / addFileExt("compile_" & name, let filename = getNimcacheDir(conf) / addFileExt("compile_" & name,
platform.OS[targetOS].scriptExt)) platform.OS[conf.target.targetOS].scriptExt)
copyFile(conf.libpath / "nimbase.h", getNimcacheDir(conf) / "nimbase.h") if writeRope(script, filename):
copyFile(conf.libpath / "nimbase.h", getNimcacheDir(conf) / "nimbase.h")
else:
rawMessage(conf, errGenerated, "could not write to file: " & filename)
proc getOptSpeed(conf: ConfigRef; c: TSystemCC): string = proc getOptSpeed(conf: ConfigRef; c: TSystemCC): string =
result = getConfigVar(conf, c, ".options.speed") result = getConfigVar(conf, c, ".options.speed")
@ -499,8 +468,8 @@ proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} =
result = conf.globalOptions * {optGenScript, optGenMapping} != {} result = conf.globalOptions * {optGenScript, optGenMapping} != {}
proc cFileSpecificOptions(conf: ConfigRef; cfilename: string): string = proc cFileSpecificOptions(conf: ConfigRef; cfilename: string): string =
result = compileOptions result = conf.compileOptions
for option in compileOptionsCmd: for option in conf.compileOptionsCmd:
if strutils.find(result, option, 0) < 0: if strutils.find(result, option, 0) < 0:
addOpt(result, option) addOpt(result, option)
@ -508,15 +477,15 @@ proc cFileSpecificOptions(conf: ConfigRef; cfilename: string): string =
if optCDebug in conf.globalOptions: if optCDebug in conf.globalOptions:
let key = trunk & ".debug" let key = trunk & ".debug"
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
else: addOpt(result, getDebug(conf, cCompiler)) else: addOpt(result, getDebug(conf, conf.cCompiler))
if optOptimizeSpeed in conf.options: if optOptimizeSpeed in conf.options:
let key = trunk & ".speed" let key = trunk & ".speed"
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
else: addOpt(result, getOptSpeed(conf, cCompiler)) else: addOpt(result, getOptSpeed(conf, conf.cCompiler))
elif optOptimizeSize in conf.options: elif optOptimizeSize in conf.options:
let key = trunk & ".size" let key = trunk & ".size"
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
else: addOpt(result, getOptSize(conf, cCompiler)) else: addOpt(result, getOptSize(conf, conf.cCompiler))
let key = trunk & ".always" let key = trunk & ".always"
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
@ -524,15 +493,15 @@ proc getCompileOptions(conf: ConfigRef): string =
result = cFileSpecificOptions(conf, "__dummy__") result = cFileSpecificOptions(conf, "__dummy__")
proc getLinkOptions(conf: ConfigRef): string = proc getLinkOptions(conf: ConfigRef): string =
result = linkOptions & " " & linkOptionsCmd & " " result = conf.linkOptions & " " & conf.linkOptionsCmd & " "
for linkedLib in items(cLinkedLibs): for linkedLib in items(conf.cLinkedLibs):
result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell) result.add(CC[conf.cCompiler].linkLibCmd % linkedLib.quoteShell)
for libDir in items(cLibs): for libDir in items(conf.cLibs):
result.add(join([CC[cCompiler].linkDirCmd, libDir.quoteShell])) result.add(join([CC[conf.cCompiler].linkDirCmd, libDir.quoteShell]))
proc needsExeExt(conf: ConfigRef): bool {.inline.} = proc needsExeExt(conf: ConfigRef): bool {.inline.} =
result = (optGenScript in conf.globalOptions and targetOS == osWindows) or result = (optGenScript in conf.globalOptions and conf.target.targetOS == osWindows) or
(platform.hostOS == osWindows) (conf.target.hostOS == osWindows)
proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: string): string = proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: string): string =
result = if conf.cmd == cmdCompileToCpp and not cfile.endsWith(".c"): result = if conf.cmd == cmdCompileToCpp and not cfile.endsWith(".c"):
@ -546,18 +515,18 @@ proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: string): string
proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string = proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string =
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
elif gMixedMode and conf.cmd != cmdCompileToCpp: CC[compiler].cppCompiler elif optMixedMode in conf.globalOptions and conf.cmd != cmdCompileToCpp: CC[compiler].cppCompiler
else: getCompilerExe(conf, compiler, "") else: getCompilerExe(conf, compiler, "")
proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string = proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string =
var c = cCompiler var c = conf.cCompiler
var options = cFileSpecificOptions(conf, cfile.cname) var options = cFileSpecificOptions(conf, cfile.cname)
var exe = getConfigVar(conf, c, ".exe") var exe = getConfigVar(conf, c, ".exe")
if exe.len == 0: exe = getCompilerExe(conf, c, cfile.cname) if exe.len == 0: exe = getCompilerExe(conf, c, cfile.cname)
if needsExeExt(conf): exe = addFileExt(exe, "exe") if needsExeExt(conf): exe = addFileExt(exe, "exe")
if optGenDynLib in conf.globalOptions and if optGenDynLib in conf.globalOptions and
ospNeedsPIC in platform.OS[targetOS].props: ospNeedsPIC in platform.OS[conf.target.targetOS].props:
add(options, ' ' & CC[c].pic) add(options, ' ' & CC[c].pic)
var includeCmd, compilePattern: string var includeCmd, compilePattern: string
@ -565,10 +534,10 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string =
# compute include paths: # compute include paths:
includeCmd = CC[c].includeCmd & quoteShell(conf.libpath) includeCmd = CC[c].includeCmd & quoteShell(conf.libpath)
for includeDir in items(cIncludes): for includeDir in items(conf.cIncludes):
includeCmd.add(join([CC[c].includeCmd, includeDir.quoteShell])) includeCmd.add(join([CC[c].includeCmd, includeDir.quoteShell]))
compilePattern = joinPath(ccompilerpath, exe) compilePattern = joinPath(conf.ccompilerpath, exe)
else: else:
includeCmd = "" includeCmd = ""
compilePattern = getCompilerExe(conf, c, cfile.cname) compilePattern = getCompilerExe(conf, c, cfile.cname)
@ -604,9 +573,9 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string =
proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash = proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash =
result = secureHash( result = secureHash(
$secureHashFile(cfile.cname) & $secureHashFile(cfile.cname) &
platform.OS[targetOS].name & platform.OS[conf.target.targetOS].name &
platform.CPU[targetCPU].name & platform.CPU[conf.target.targetCPU].name &
extccomp.CC[extccomp.cCompiler].name & extccomp.CC[conf.cCompiler].name &
getCompileCFileCmd(conf, cfile)) getCompileCFileCmd(conf, cfile))
proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
@ -630,7 +599,7 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) = proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) =
if optForceFullMake notin conf.globalOptions and not externalFileChanged(conf, c): if optForceFullMake notin conf.globalOptions and not externalFileChanged(conf, c):
c.flags.incl CfileFlag.Cached c.flags.incl CfileFlag.Cached
toCompile.add(c) conf.toCompile.add(c)
proc addExternalFileToCompile*(conf: ConfigRef; filename: string) = proc addExternalFileToCompile*(conf: ConfigRef; filename: string) =
var c = Cfile(cname: filename, var c = Cfile(cname: filename,
@ -650,7 +619,7 @@ proc compileCFile(conf: ConfigRef; list: CFileList, script: var Rope, cmds: var
add(prettyCmds, "CC: " & name) add(prettyCmds, "CC: " & name)
if optGenScript in conf.globalOptions: if optGenScript in conf.globalOptions:
add(script, compileCmd) add(script, compileCmd)
add(script, tnl) add(script, "\n")
proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string = proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
if optGenStaticLib in conf.globalOptions: if optGenStaticLib in conf.globalOptions:
@ -660,24 +629,24 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
if not libname.isAbsolute(): if not libname.isAbsolute():
libname = getCurrentDir() / libname libname = getCurrentDir() / libname
else: else:
libname = (libNameTmpl() % splitFile(conf.projectName).name) libname = (libNameTmpl(conf) % splitFile(conf.projectName).name)
result = CC[cCompiler].buildLib % ["libfile", libname, result = CC[conf.cCompiler].buildLib % ["libfile", libname,
"objfiles", objfiles] "objfiles", objfiles]
else: else:
var linkerExe = getConfigVar(conf, cCompiler, ".linkerexe") var linkerExe = getConfigVar(conf, conf.cCompiler, ".linkerexe")
if len(linkerExe) == 0: linkerExe = getLinkerExe(conf, cCompiler) if len(linkerExe) == 0: linkerExe = getLinkerExe(conf, conf.cCompiler)
# bug #6452: We must not use ``quoteShell`` here for ``linkerExe`` # bug #6452: We must not use ``quoteShell`` here for ``linkerExe``
if needsExeExt(conf): linkerExe = addFileExt(linkerExe, "exe") if needsExeExt(conf): linkerExe = addFileExt(linkerExe, "exe")
if noAbsolutePaths(conf): result = linkerExe if noAbsolutePaths(conf): result = linkerExe
else: result = joinPath(ccompilerpath, linkerExe) else: result = joinPath(conf.cCompilerpath, linkerExe)
let buildgui = if optGenGuiApp in conf.globalOptions: CC[cCompiler].buildGui let buildgui = if optGenGuiApp in conf.globalOptions: CC[conf.cCompiler].buildGui
else: "" else: ""
var exefile, builddll: string var exefile, builddll: string
if optGenDynLib in conf.globalOptions: if optGenDynLib in conf.globalOptions:
exefile = platform.OS[targetOS].dllFrmt % splitFile(projectfile).name exefile = platform.OS[conf.target.targetOS].dllFrmt % splitFile(projectfile).name
builddll = CC[cCompiler].buildDll builddll = CC[conf.cCompiler].buildDll
else: else:
exefile = splitFile(projectfile).name & platform.OS[targetOS].exeExt exefile = splitFile(projectfile).name & platform.OS[conf.target.targetOS].exeExt
builddll = "" builddll = ""
if conf.outFile.len > 0: if conf.outFile.len > 0:
exefile = conf.outFile.expandTilde exefile = conf.outFile.expandTilde
@ -691,10 +660,10 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
writeDebugInfo(exefile.changeFileExt("ndb")) writeDebugInfo(exefile.changeFileExt("ndb"))
exefile = quoteShell(exefile) exefile = quoteShell(exefile)
let linkOptions = getLinkOptions(conf) & " " & let linkOptions = getLinkOptions(conf) & " " &
getConfigVar(conf, cCompiler, ".options.linker") getConfigVar(conf, conf.cCompiler, ".options.linker")
var linkTmpl = getConfigVar(conf, cCompiler, ".linkTmpl") var linkTmpl = getConfigVar(conf, conf.cCompiler, ".linkTmpl")
if linkTmpl.len == 0: if linkTmpl.len == 0:
linkTmpl = CC[cCompiler].linkTmpl linkTmpl = CC[conf.cCompiler].linkTmpl
result = quoteShell(result % ["builddll", builddll, result = quoteShell(result % ["builddll", builddll,
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
"exefile", exefile, "nim", getPrefixDir(conf), "lib", conf.libpath]) "exefile", exefile, "nim", getPrefixDir(conf), "lib", conf.libpath])
@ -765,19 +734,20 @@ proc callCCompiler*(conf: ConfigRef; projectfile: string) =
var cmds: TStringSeq = @[] var cmds: TStringSeq = @[]
var prettyCmds: TStringSeq = @[] var prettyCmds: TStringSeq = @[]
let prettyCb = proc (idx: int) = let prettyCb = proc (idx: int) =
echo prettyCmds[idx] when declared(echo):
compileCFile(conf, toCompile, script, cmds, prettyCmds) echo prettyCmds[idx]
compileCFile(conf, conf.toCompile, script, cmds, prettyCmds)
if optCompileOnly notin conf.globalOptions: if optCompileOnly notin conf.globalOptions:
execCmdsInParallel(conf, cmds, prettyCb) execCmdsInParallel(conf, cmds, prettyCb)
if optNoLinking notin conf.globalOptions: if optNoLinking notin conf.globalOptions:
# call the linker: # call the linker:
var objfiles = "" var objfiles = ""
for it in externalToLink: for it in conf.externalToLink:
let objFile = if noAbsolutePaths(conf): it.extractFilename else: it let objFile = if noAbsolutePaths(conf): it.extractFilename else: it
add(objfiles, ' ') add(objfiles, ' ')
add(objfiles, quoteShell( add(objfiles, quoteShell(
addFileExt(objFile, CC[cCompiler].objExt))) addFileExt(objFile, CC[conf.cCompiler].objExt)))
for x in toCompile: for x in conf.toCompile:
let objFile = if noAbsolutePaths(conf): x.obj.extractFilename else: x.obj let objFile = if noAbsolutePaths(conf): x.obj.extractFilename else: x.obj
add(objfiles, ' ') add(objfiles, ' ')
add(objfiles, quoteShell(objFile)) add(objfiles, quoteShell(objFile))
@ -789,7 +759,7 @@ proc callCCompiler*(conf: ConfigRef; projectfile: string) =
linkCmd = "" linkCmd = ""
if optGenScript in conf.globalOptions: if optGenScript in conf.globalOptions:
add(script, linkCmd) add(script, linkCmd)
add(script, tnl) add(script, "\n")
generateScript(conf, projectfile, script) generateScript(conf, projectfile, script)
#from json import escapeJson #from json import escapeJson
@ -824,7 +794,7 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
for it in llist: for it in llist:
let objfile = if noAbsolutePaths(conf): it.extractFilename let objfile = if noAbsolutePaths(conf): it.extractFilename
else: it else: it
let objstr = addFileExt(objfile, CC[cCompiler].objExt) let objstr = addFileExt(objfile, CC[conf.cCompiler].objExt)
add(objfiles, ' ') add(objfiles, ' ')
add(objfiles, objstr) add(objfiles, objstr)
if pastStart: lit ",\L" if pastStart: lit ",\L"
@ -848,11 +818,11 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
var f: File var f: File
if open(f, jsonFile, fmWrite): if open(f, jsonFile, fmWrite):
lit "{\"compile\":[\L" lit "{\"compile\":[\L"
cfiles(conf, f, buf, toCompile, false) cfiles(conf, f, buf, conf.toCompile, false)
lit "],\L\"link\":[\L" lit "],\L\"link\":[\L"
var objfiles = "" var objfiles = ""
# XXX add every file here that is to link # XXX add every file here that is to link
linkfiles(conf, f, buf, objfiles, toCompile, externalToLink) linkfiles(conf, f, buf, objfiles, conf.toCompile, conf.externalToLink)
lit "],\L\"linkcmd\": " lit "],\L\"linkcmd\": "
str getLinkCmd(conf, projectfile, objfiles) str getLinkCmd(conf, projectfile, objfiles)
@ -877,14 +847,16 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
add(prettyCmds, "CC: " & name) add(prettyCmds, "CC: " & name)
let prettyCb = proc (idx: int) = let prettyCb = proc (idx: int) =
echo prettyCmds[idx] when declared(echo):
echo prettyCmds[idx]
execCmdsInParallel(conf, cmds, prettyCb) execCmdsInParallel(conf, cmds, prettyCb)
let linkCmd = data["linkcmd"] let linkCmd = data["linkcmd"]
doAssert linkCmd.kind == JString doAssert linkCmd.kind == JString
execLinkCmd(conf, linkCmd.getStr) execLinkCmd(conf, linkCmd.getStr)
except: except:
echo getCurrentException().getStackTrace() when declared(echo):
echo getCurrentException().getStackTrace()
quit "error evaluating JSON file: " & jsonFile quit "error evaluating JSON file: " & jsonFile
proc genMappingFiles(conf: ConfigRef; list: CFileList): Rope = proc genMappingFiles(conf: ConfigRef; list: CFileList): Rope =
@ -894,16 +866,18 @@ proc genMappingFiles(conf: ConfigRef; list: CFileList): Rope =
proc writeMapping*(conf: ConfigRef; symbolMapping: Rope) = proc writeMapping*(conf: ConfigRef; symbolMapping: Rope) =
if optGenMapping notin conf.globalOptions: return if optGenMapping notin conf.globalOptions: return
var code = rope("[C_Files]\n") var code = rope("[C_Files]\n")
add(code, genMappingFiles(conf, toCompile)) add(code, genMappingFiles(conf, conf.toCompile))
add(code, "\n[C_Compiler]\nFlags=") add(code, "\n[C_Compiler]\nFlags=")
add(code, strutils.escape(getCompileOptions(conf))) add(code, strutils.escape(getCompileOptions(conf)))
add(code, "\n[Linker]\nFlags=") add(code, "\n[Linker]\nFlags=")
add(code, strutils.escape(getLinkOptions(conf) & " " & add(code, strutils.escape(getLinkOptions(conf) & " " &
getConfigVar(conf, cCompiler, ".options.linker"))) getConfigVar(conf, conf.cCompiler, ".options.linker")))
add(code, "\n[Environment]\nlibpath=") add(code, "\n[Environment]\nlibpath=")
add(code, strutils.escape(conf.libpath)) add(code, strutils.escape(conf.libpath))
addf(code, "\n[Symbols]$n$1", [symbolMapping]) addf(code, "\n[Symbols]$n$1", [symbolMapping])
writeRope(code, joinPath(conf.projectPath, "mapping.txt")) let filename = joinPath(conf.projectPath, "mapping.txt")
if not writeRope(code, filename):
rawMessage(conf, errGenerated, "could not write to file: " & filename)

View file

@ -11,7 +11,7 @@
import import
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
renderer, filters renderer, filters, lineinfos
type type
TParseState = enum TParseState = enum

View file

@ -9,7 +9,8 @@
## Module that implements ``gorge`` for the compiler. ## Module that implements ``gorge`` for the compiler.
import msgs, std / sha1, os, osproc, streams, strutils, options import msgs, std / sha1, os, osproc, streams, strutils, options,
lineinfos
proc readOutput(p: Process): (string, int) = proc readOutput(p: Process): (string, int) =
result[0] = "" result[0] = ""
@ -22,7 +23,7 @@ proc readOutput(p: Process): (string, int) =
result[1] = p.waitForExit result[1] = p.waitForExit
proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (string, int) = proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (string, int) =
let workingDir = parentDir(info.toFullPath) let workingDir = parentDir(toFullPath(conf, info))
if cache.len > 0:# and optForceFullMake notin gGlobalOptions: if cache.len > 0:# and optForceFullMake notin gGlobalOptions:
let h = secureHash(cmd & "\t" & input & "\t" & cache) let h = secureHash(cmd & "\t" & input & "\t" & cache)
let filename = options.toGeneratedFile(conf, "gorge_" & $h, "txt") let filename = options.toGeneratedFile(conf, "gorge_" & $h, "txt")

View file

@ -10,7 +10,7 @@
## This module implements the 'implies' relation for guards. ## This module implements the 'implies' relation for guards.
import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents, import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
saturate, modulegraphs, options, configuration saturate, modulegraphs, options, lineinfos
const const
someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
@ -131,8 +131,8 @@ proc neg(n: PNode; o: Operators): PNode =
let eAsNode = newIntNode(nkIntLit, e.sym.position) let eAsNode = newIntNode(nkIntLit, e.sym.position)
if not inSet(n.sons[1], eAsNode): s.add eAsNode if not inSet(n.sons[1], eAsNode): s.add eAsNode
result.sons[1] = s result.sons[1] = s
elif t.kind notin {tyString, tySequence} and lengthOrd(t) < 1000: #elif t.kind notin {tyString, tySequence} and lengthOrd(t) < 1000:
result.sons[1] = complement(n.sons[1]) # result.sons[1] = complement(n.sons[1])
else: else:
# not ({2, 3, 4}.contains(x)) x != 2 and x != 3 and x != 4 # not ({2, 3, 4}.contains(x)) x != 2 and x != 3 and x != 4
# XXX todo # XXX todo
@ -208,14 +208,14 @@ proc zero(): PNode = nkIntLit.newIntNode(0)
proc one(): PNode = nkIntLit.newIntNode(1) proc one(): PNode = nkIntLit.newIntNode(1)
proc minusOne(): PNode = nkIntLit.newIntNode(-1) proc minusOne(): PNode = nkIntLit.newIntNode(-1)
proc lowBound*(x: PNode): PNode = proc lowBound*(conf: ConfigRef; x: PNode): PNode =
result = nkIntLit.newIntNode(firstOrd(x.typ)) result = nkIntLit.newIntNode(firstOrd(conf, x.typ))
result.info = x.info result.info = x.info
proc highBound*(x: PNode; o: Operators): PNode = proc highBound*(conf: ConfigRef; x: PNode; o: Operators): PNode =
let typ = x.typ.skipTypes(abstractInst) let typ = x.typ.skipTypes(abstractInst)
result = if typ.kind == tyArray: result = if typ.kind == tyArray:
nkIntLit.newIntNode(lastOrd(typ)) nkIntLit.newIntNode(lastOrd(conf, typ))
elif typ.kind == tySequence and x.kind == nkSym and elif typ.kind == tySequence and x.kind == nkSym and
x.sym.kind == skConst: x.sym.kind == skConst:
nkIntLit.newIntNode(x.sym.ast.len-1) nkIntLit.newIntNode(x.sym.ast.len-1)
@ -503,7 +503,7 @@ proc leImpliesIn(x, c, aSet: PNode): TImplication =
# fact: x <= 4; question x in {56}? # fact: x <= 4; question x in {56}?
# --> true if every value <= 4 is in the set {56} # --> true if every value <= 4 is in the set {56}
# #
var value = newIntNode(c.kind, firstOrd(x.typ)) var value = newIntNode(c.kind, firstOrd(nil, x.typ))
# don't iterate too often: # don't iterate too often:
if c.intVal - value.intVal < 1000: if c.intVal - value.intVal < 1000:
var i, pos, neg: int var i, pos, neg: int
@ -520,7 +520,7 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication =
# --> true iff every value >= 4 is in the set {56} # --> true iff every value >= 4 is in the set {56}
# #
var value = newIntNode(c.kind, c.intVal) var value = newIntNode(c.kind, c.intVal)
let max = lastOrd(x.typ) let max = lastOrd(nil, x.typ)
# don't iterate too often: # don't iterate too often:
if max - value.intVal < 1000: if max - value.intVal < 1000:
var i, pos, neg: int var i, pos, neg: int
@ -532,8 +532,8 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication =
elif neg == i: result = impNo elif neg == i: result = impNo
proc compareSets(a, b: PNode): TImplication = proc compareSets(a, b: PNode): TImplication =
if equalSets(a, b): result = impYes if equalSets(nil, a, b): result = impYes
elif intersectSets(a, b).len == 0: result = impNo elif intersectSets(nil, a, b).len == 0: result = impNo
proc impliesIn(fact, loc, aSet: PNode): TImplication = proc impliesIn(fact, loc, aSet: PNode): TImplication =
case fact.sons[0].sym.magic case fact.sons[0].sym.magic
@ -799,10 +799,10 @@ proc ple(m: TModel; a, b: PNode): TImplication =
# use type information too: x <= 4 iff high(x) <= 4 # use type information too: x <= 4 iff high(x) <= 4
if b.isValue and a.typ != nil and a.typ.isOrdinalType: if b.isValue and a.typ != nil and a.typ.isOrdinalType:
if lastOrd(a.typ) <= b.intVal: return impYes if lastOrd(nil, a.typ) <= b.intVal: return impYes
# 3 <= x iff low(x) <= 3 # 3 <= x iff low(x) <= 3
if a.isValue and b.typ != nil and b.typ.isOrdinalType: if a.isValue and b.typ != nil and b.typ.isOrdinalType:
if firstOrd(b.typ) <= a.intVal: return impYes if firstOrd(nil, b.typ) <= a.intVal: return impYes
# x <= x # x <= x
if sameTree(a, b): return impYes if sameTree(a, b): return impYes

View file

@ -43,8 +43,8 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
if not isNil(x): if not isNil(x):
assert x.kind in {nkStmtList, nkCall} assert x.kind in {nkStmtList, nkCall}
# better be safe than sorry, so check evalTemplateCounter too: # better be safe than sorry, so check evalTemplateCounter too:
inc(evalTemplateCounter) inc(c.config.evalTemplateCounter)
if evalTemplateCounter > evalTemplateLimit: if c.config.evalTemplateCounter > evalTemplateLimit:
globalError(c.config, n.info, "template instantiation too nested") globalError(c.config, n.info, "template instantiation too nested")
# deactivate this pattern: # deactivate this pattern:
c.patterns[i] = nil c.patterns[i] = nil
@ -54,7 +54,7 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
result = flattenStmts(x) result = flattenStmts(x)
else: else:
result = evalPattern(c, x, result) result = evalPattern(c, x, result)
dec(evalTemplateCounter) dec(c.config.evalTemplateCounter)
# activate this pattern again: # activate this pattern again:
c.patterns[i] = pattern c.patterns[i] = pattern

View file

@ -30,12 +30,14 @@ type
wordCounter: int wordCounter: int
idAnon*, idDelegator*, emptyIdent*: PIdent idAnon*, idDelegator*, emptyIdent*: PIdent
var when false:
legacy: IdentCache var
legacy: IdentCache
proc resetIdentCache*() = proc resetIdentCache*() =
for i in low(legacy.buckets)..high(legacy.buckets): when false:
legacy.buckets[i] = nil for i in low(legacy.buckets)..high(legacy.buckets):
legacy.buckets[i] = nil
proc cmpIgnoreStyle*(a, b: cstring, blen: int): int = proc cmpIgnoreStyle*(a, b: cstring, blen: int): int =
if a[0] != b[0]: return 1 if a[0] != b[0]: return 1
@ -111,25 +113,15 @@ proc getIdent*(self: IdentCache; identifier: string, h: Hash): PIdent =
result = getIdent(cstring(identifier), len(identifier), h) result = getIdent(cstring(identifier), len(identifier), h)
proc newIdentCache*(): IdentCache = proc newIdentCache*(): IdentCache =
if legacy.isNil: result = IdentCache()
result = IdentCache() result.idAnon = result.getIdent":anonymous"
result.idAnon = result.getIdent":anonymous" result.wordCounter = 1
result.wordCounter = 1 result.idDelegator = result.getIdent":delegator"
result.idDelegator = result.getIdent":delegator" result.emptyIdent = result.getIdent("")
result.emptyIdent = result.getIdent("") # initialize the keywords:
# initialize the keywords: for s in countup(succ(low(specialWords)), high(specialWords)):
for s in countup(succ(low(specialWords)), high(specialWords)): result.getIdent(specialWords[s], hashIgnoreStyle(specialWords[s])).id = ord(s)
result.getIdent(specialWords[s], hashIgnoreStyle(specialWords[s])).id = ord(s)
legacy = result
else:
result = legacy
proc whichKeyword*(id: PIdent): TSpecialWord = proc whichKeyword*(id: PIdent): TSpecialWord =
if id.id < 0: result = wInvalid if id.id < 0: result = wInvalid
else: result = TSpecialWord(id.id) else: result = TSpecialWord(id.id)
proc getIdent*(identifier: string): PIdent =
## for backwards compatibility.
if legacy.isNil:
discard newIdentCache()
legacy.getIdent identifier

View file

@ -10,8 +10,8 @@
# This module implements the symbol importing mechanism. # This module implements the symbol importing mechanism.
import import
intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups, intsets, strutils, os, ast, astalgo, msgs, options, idents, lookups,
semdata, passes, renderer, modulepaths, sigmatch, configuration semdata, passes, renderer, modulepaths, sigmatch, lineinfos
proc evalImport*(c: PContext, n: PNode): PNode proc evalImport*(c: PContext, n: PNode): PNode
proc evalFrom*(c: PContext, n: PNode): PNode proc evalFrom*(c: PContext, n: PNode): PNode
@ -20,7 +20,7 @@ proc readExceptSet*(c: PContext, n: PNode): IntSet =
assert n.kind in {nkImportExceptStmt, nkExportExceptStmt} assert n.kind in {nkImportExceptStmt, nkExportExceptStmt}
result = initIntSet() result = initIntSet()
for i in 1 ..< n.len: for i in 1 ..< n.len:
let ident = lookups.considerQuotedIdent(c.config, n[i]) let ident = lookups.considerQuotedIdent(c, n[i])
result.incl(ident.id) result.incl(ident.id)
proc importPureEnumField*(c: PContext; s: PSym) = proc importPureEnumField*(c: PContext; s: PSym) =
@ -69,12 +69,13 @@ proc rawImportSymbol(c: PContext, s: PSym) =
if hasPattern(s): addPattern(c, s) if hasPattern(s): addPattern(c, s)
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) = proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
let ident = lookups.considerQuotedIdent(c.config, n) let ident = lookups.considerQuotedIdent(c, n)
let s = strTableGet(fromMod.tab, ident) let s = strTableGet(fromMod.tab, ident)
if s == nil: if s == nil:
errorUndeclaredIdentifier(c, n.info, ident.s) errorUndeclaredIdentifier(c, n.info, ident.s)
else: else:
if s.kind == skStub: loadStub(s) when false:
if s.kind == skStub: loadStub(s)
if s.kind notin ExportableSymKinds: if s.kind notin ExportableSymKinds:
internalError(c.config, n.info, "importSymbol: 2") internalError(c.config, n.info, "importSymbol: 2")
# for an enumeration we have to add all identifiers # for an enumeration we have to add all identifiers
@ -132,7 +133,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym =
result = createModuleAlias(realModule, n.sons[1].ident, realModule.info, result = createModuleAlias(realModule, n.sons[1].ident, realModule.info,
c.config.options) c.config.options)
proc myImportModule(c: PContext, n: PNode): PSym = proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym =
var f = checkModuleName(c.config, n) var f = checkModuleName(c.config, n)
if f != InvalidFileIDX: if f != InvalidFileIDX:
let L = c.graph.importStack.len let L = c.graph.importStack.len
@ -143,10 +144,10 @@ proc myImportModule(c: PContext, n: PNode): PSym =
var err = "" var err = ""
for i in countup(recursion, L-1): for i in countup(recursion, L-1):
if i > recursion: err.add "\n" if i > recursion: err.add "\n"
err.add toFullPath(c.graph.importStack[i]) & " imports " & err.add toFullPath(c.config, c.graph.importStack[i]) & " imports " &
toFullPath(c.graph.importStack[i+1]) toFullPath(c.config, c.graph.importStack[i+1])
c.recursiveDep = err c.recursiveDep = err
result = importModuleAs(c, n, gImportModule(c.graph, c.module, f, c.cache)) result = importModuleAs(c, n, c.graph.importModuleCallback(c.graph, c.module, f))
#echo "set back to ", L #echo "set back to ", L
c.graph.importStack.setLen(L) c.graph.importStack.setLen(L)
# we cannot perform this check reliably because of # we cannot perform this check reliably because of
@ -161,9 +162,10 @@ proc myImportModule(c: PContext, n: PNode): PSym =
else: else:
message(c.config, n.info, warnDeprecated, result.name.s) message(c.config, n.info, warnDeprecated, result.name.s)
suggestSym(c.config, n.info, result, c.graph.usageSym, false) suggestSym(c.config, n.info, result, c.graph.usageSym, false)
importStmtResult.add newStrNode(toFullPath(c.config, f), n.info)
proc impMod(c: PContext; it: PNode) = proc impMod(c: PContext; it: PNode; importStmtResult: PNode) =
let m = myImportModule(c, it) let m = myImportModule(c, it, importStmtResult)
if m != nil: if m != nil:
var emptySet: IntSet var emptySet: IntSet
# ``addDecl`` needs to be done before ``importAllSymbols``! # ``addDecl`` needs to be done before ``importAllSymbols``!
@ -172,7 +174,8 @@ proc impMod(c: PContext; it: PNode) =
#importForwarded(c, m.ast, emptySet) #importForwarded(c, m.ast, emptySet)
proc evalImport(c: PContext, n: PNode): PNode = proc evalImport(c: PContext, n: PNode): PNode =
result = n #result = n
result = newNodeI(nkImportStmt, n.info)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i] let it = n.sons[i]
if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket: if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
@ -184,14 +187,14 @@ proc evalImport(c: PContext, n: PNode): PNode =
a.add sep # dummy entry, replaced in the loop a.add sep # dummy entry, replaced in the loop
for x in it[2]: for x in it[2]:
a.sons[2] = x a.sons[2] = x
impMod(c, a) impMod(c, a, result)
else: else:
impMod(c, it) impMod(c, it, result)
proc evalFrom(c: PContext, n: PNode): PNode = proc evalFrom(c: PContext, n: PNode): PNode =
result = n result = newNodeI(nkImportStmt, n.info)
checkMinSonsLen(n, 2, c.config) checkMinSonsLen(n, 2, c.config)
var m = myImportModule(c, n.sons[0]) var m = myImportModule(c, n.sons[0], result)
if m != nil: if m != nil:
n.sons[0] = newSymNode(m) n.sons[0] = newSymNode(m)
addDecl(c, m, n.info) # add symbol to symbol table of module addDecl(c, m, n.info) # add symbol to symbol table of module
@ -200,9 +203,9 @@ proc evalFrom(c: PContext, n: PNode): PNode =
importSymbol(c, n.sons[i], m) importSymbol(c, n.sons[i], m)
proc evalImportExcept*(c: PContext, n: PNode): PNode = proc evalImportExcept*(c: PContext, n: PNode): PNode =
result = n result = newNodeI(nkImportStmt, n.info)
checkMinSonsLen(n, 2, c.config) checkMinSonsLen(n, 2, c.config)
var m = myImportModule(c, n.sons[0]) var m = myImportModule(c, n.sons[0], result)
if m != nil: if m != nil:
n.sons[0] = newSymNode(m) n.sons[0] = newSymNode(m)
addDecl(c, m, n.info) # add symbol to symbol table of module addDecl(c, m, n.info) # add symbol to symbol table of module

196
compiler/incremental.nim Normal file
View file

@ -0,0 +1,196 @@
#
#
# The Nim Compiler
# (c) Copyright 2018 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Basic type definitions the module graph needs in order to support
## incremental compilations.
const nimIncremental* = defined(nimIncremental)
import options, lineinfos
when nimIncremental:
import ast, msgs, intsets, btrees, db_sqlite, std / sha1
from strutils import parseInt
type
Writer* = object
sstack*: seq[PSym] # a stack of symbols to process
tstack*: seq[PType] # a stack of types to process
tmarks*, smarks*: IntSet
forwardedSyms*: seq[PSym]
Reader* = object
syms*: BTree[int, PSym]
types*: BTree[int, PType]
IncrementalCtx* = object
db*: DbConn
w*: Writer
r*: Reader
configChanged*: bool
proc init*(incr: var IncrementalCtx) =
incr.w.sstack = @[]
incr.w.tstack = @[]
incr.w.tmarks = initIntSet()
incr.w.smarks = initIntSet()
incr.w.forwardedSyms = @[]
incr.r.syms = initBTree[int, PSym]()
incr.r.types = initBTree[int, PType]()
proc hashFileCached*(conf: ConfigRef; fileIdx: FileIndex; fullpath: string): string =
result = msgs.getHash(conf, fileIdx)
if result.len == 0:
result = $secureHashFile(fullpath)
msgs.setHash(conf, fileIdx, result)
proc toDbFileId*(incr: var IncrementalCtx; conf: ConfigRef; fileIdx: FileIndex): int =
if fileIdx == FileIndex(-1): return -1
let fullpath = toFullPath(conf, fileIdx)
let row = incr.db.getRow(sql"select id, fullhash from filenames where fullpath = ?",
fullpath)
let id = row[0]
let fullhash = hashFileCached(conf, fileIdx, fullpath)
if id.len == 0:
result = int incr.db.insertID(sql"insert into filenames(fullpath, fullhash) values (?, ?)",
fullpath, fullhash)
else:
if row[1] != fullhash:
incr.db.exec(sql"update filenames set fullhash = ? where fullpath = ?", fullhash, fullpath)
result = parseInt(id)
proc fromDbFileId*(incr: var IncrementalCtx; conf: ConfigRef; dbId: int): FileIndex =
if dbId == -1: return FileIndex(-1)
let fullpath = incr.db.getValue(sql"select fullpath from filenames where id = ?", dbId)
doAssert fullpath.len > 0, "cannot find file name for DB ID " & $dbId
result = fileInfoIdx(conf, fullpath)
proc addModuleDep*(incr: var IncrementalCtx; conf: ConfigRef;
module, fileIdx: FileIndex;
isIncludeFile: bool) =
if conf.symbolFiles != v2Sf: return
let a = toDbFileId(incr, conf, module)
let b = toDbFileId(incr, conf, fileIdx)
incr.db.exec(sql"insert into deps(module, dependency, isIncludeFile) values (?, ?, ?)",
a, b, ord(isIncludeFile))
# --------------- Database model ---------------------------------------------
proc createDb*(db: DbConn) =
db.exec(sql"""
create table if not exists controlblock(
idgen integer not null
);
""")
db.exec(sql"""
create table if not exists config(
config varchar(8000) not null
);
""")
db.exec(sql"""
create table if not exists filenames(
id integer primary key,
fullpath varchar(8000) not null,
fullHash varchar(256) not null
);
""")
db.exec sql"create index if not exists FilenameIx on filenames(fullpath);"
db.exec(sql"""
create table if not exists modules(
id integer primary key,
nimid integer not null,
fullpath varchar(8000) not null,
interfHash varchar(256) not null,
fullHash varchar(256) not null,
created timestamp not null default (DATETIME('now'))
);""")
db.exec(sql"""create unique index if not exists SymNameIx on modules(fullpath);""")
db.exec(sql"""
create table if not exists deps(
id integer primary key,
module integer not null,
dependency integer not null,
isIncludeFile integer not null,
foreign key (module) references filenames(id),
foreign key (dependency) references filenames(id)
);""")
db.exec(sql"""create index if not exists DepsIx on deps(module);""")
db.exec(sql"""
create table if not exists types(
id integer primary key,
nimid integer not null,
module integer not null,
data blob not null,
foreign key (module) references module(id)
);
""")
db.exec sql"create index TypeByModuleIdx on types(module);"
db.exec sql"create index TypeByNimIdIdx on types(nimid);"
db.exec(sql"""
create table if not exists syms(
id integer primary key,
nimid integer not null,
module integer not null,
name varchar(256) not null,
data blob not null,
exported int not null,
foreign key (module) references module(id)
);
""")
db.exec sql"create index if not exists SymNameIx on syms(name);"
db.exec sql"create index SymByNameAndModuleIdx on syms(name, module);"
db.exec sql"create index SymByModuleIdx on syms(module);"
db.exec sql"create index SymByNimIdIdx on syms(nimid);"
db.exec(sql"""
create table if not exists toplevelstmts(
id integer primary key,
position integer not null,
module integer not null,
data blob not null,
foreign key (module) references module(id)
);
""")
db.exec sql"create index TopLevelStmtByModuleIdx on toplevelstmts(module);"
db.exec sql"create index TopLevelStmtByPositionIdx on toplevelstmts(position);"
db.exec(sql"""
create table if not exists statics(
id integer primary key,
module integer not null,
data blob not null,
foreign key (module) references module(id)
);
""")
db.exec sql"create index StaticsByModuleIdx on toplevelstmts(module);"
db.exec sql"insert into controlblock(idgen) values (0)"
else:
type
IncrementalCtx* = object
template init*(incr: IncrementalCtx) = discard
template addModuleDep*(incr: var IncrementalCtx; conf: ConfigRef;
module, fileIdx: FileIndex;
isIncludeFile: bool) =
discard

View file

@ -31,8 +31,8 @@ implements the required case distinction.
import import
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options, ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables, nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables,
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils, times, ropes, math, passes, ccgutils, wordrecg, renderer,
intsets, cgmeth, lowerings, sighashes, configuration intsets, cgmeth, lowerings, sighashes, lineinfos, rodutils
from modulegraphs import ModuleGraph from modulegraphs import ModuleGraph
@ -72,7 +72,7 @@ type
# has been used (i.e. the label should be emitted) # has been used (i.e. the label should be emitted)
isLoop: bool # whether it's a 'block' or 'while' isLoop: bool # whether it's a 'block' or 'while'
TGlobals = object PGlobals = ref object of RootObj
typeInfo, constants, code: Rope typeInfo, constants, code: Rope
forwarded: seq[PSym] forwarded: seq[PSym]
generatedSyms: IntSet generatedSyms: IntSet
@ -80,7 +80,6 @@ type
classes: seq[(PType, Rope)] classes: seq[(PType, Rope)]
unique: int # for temp identifier generation unique: int # for temp identifier generation
PGlobals = ref TGlobals
PProc = ref TProc PProc = ref TProc
TProc = object TProc = object
procDef: PNode procDef: PNode
@ -537,7 +536,7 @@ proc genLineDir(p: PProc, n: PNode) =
let line = toLinenumber(n.info) let line = toLinenumber(n.info)
if optLineDir in p.options: if optLineDir in p.options:
lineF(p, "// line $2 \"$1\"$n", lineF(p, "// line $2 \"$1\"$n",
[rope(toFilename(n.info)), rope(line)]) [rope(toFilename(p.config, n.info)), rope(line)])
if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
((p.prc == nil) or sfPure notin p.prc.flags): ((p.prc == nil) or sfPure notin p.prc.flags):
useMagic(p, "endb") useMagic(p, "endb")
@ -606,11 +605,11 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
var length = sonsLen(n) var length = sonsLen(n)
var catchBranchesExist = length > 1 and n.sons[i].kind == nkExceptBranch var catchBranchesExist = length > 1 and n.sons[i].kind == nkExceptBranch
if catchBranchesExist: if catchBranchesExist:
add(p.body, "++excHandler;" & tnl) add(p.body, "++excHandler;\L")
var tmpFramePtr = rope"F" var tmpFramePtr = rope"F"
if optStackTrace notin p.options: if optStackTrace notin p.options:
tmpFramePtr = p.getTemp(true) tmpFramePtr = p.getTemp(true)
line(p, tmpFramePtr & " = framePtr;" & tnl) line(p, tmpFramePtr & " = framePtr;\L")
lineF(p, "try {$n", []) lineF(p, "try {$n", [])
var a: TCompRes var a: TCompRes
gen(p, n.sons[0], a) gen(p, n.sons[0], a)
@ -648,15 +647,15 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
if catchBranchesExist: if catchBranchesExist:
if not generalCatchBranchExists: if not generalCatchBranchExists:
useMagic(p, "reraiseException") useMagic(p, "reraiseException")
line(p, "else {" & tnl) line(p, "else {\L")
line(p, "\treraiseException();" & tnl) line(p, "\treraiseException();\L")
line(p, "}" & tnl) line(p, "}\L")
addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar]) addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar])
line(p, "} finally {" & tnl) line(p, "} finally {\L")
line(p, "framePtr = $1;$n" % [tmpFramePtr]) line(p, "framePtr = $1;$n" % [tmpFramePtr])
if i < length and n.sons[i].kind == nkFinally: if i < length and n.sons[i].kind == nkFinally:
genStmt(p, n.sons[i].sons[0]) genStmt(p, n.sons[i].sons[0])
line(p, "}" & tnl) line(p, "}\L")
proc genRaiseStmt(p: PProc, n: PNode) = proc genRaiseStmt(p: PProc, n: PNode) =
genLineDir(p, n) genLineDir(p, n)
@ -669,7 +668,7 @@ proc genRaiseStmt(p: PProc, n: PNode) =
[a.rdLoc, makeJSString(typ.sym.name.s)]) [a.rdLoc, makeJSString(typ.sym.name.s)])
else: else:
useMagic(p, "reraiseException") useMagic(p, "reraiseException")
line(p, "reraiseException();" & tnl) line(p, "reraiseException();\L")
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
var var
@ -775,7 +774,7 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
var r: TCompRes var r: TCompRes
gen(p, it, r) gen(p, it, r)
p.body.add(r.rdLoc) p.body.add(r.rdLoc)
p.body.add tnl p.body.add "\L"
proc genIf(p: PProc, n: PNode, r: var TCompRes) = proc genIf(p: PProc, n: PNode, r: var TCompRes) =
var cond, stmt: TCompRes var cond, stmt: TCompRes
@ -798,7 +797,7 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
p.nested: gen(p, it.sons[0], stmt) p.nested: gen(p, it.sons[0], stmt)
moveInto(p, stmt, r) moveInto(p, stmt, r)
lineF(p, "}$n", []) lineF(p, "}$n", [])
line(p, repeat('}', toClose) & tnl) line(p, repeat('}', toClose) & "\L")
proc generateHeader(p: PProc, typ: PType): Rope = proc generateHeader(p: PProc, typ: PType): Rope =
result = nil result = nil
@ -969,7 +968,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
internalAssert p.config, a.typ != etyBaseIndex and b.typ != etyBaseIndex internalAssert p.config, a.typ != etyBaseIndex and b.typ != etyBaseIndex
r.address = a.res r.address = a.res
var typ = skipTypes(m.sons[0].typ, abstractPtrs) var typ = skipTypes(m.sons[0].typ, abstractPtrs)
if typ.kind == tyArray: first = firstOrd(typ.sons[0]) if typ.kind == tyArray: first = firstOrd(p.config, typ.sons[0])
else: first = 0 else: first = 0
if optBoundsCheck in p.options: if optBoundsCheck in p.options:
useMagic(p, "chckIndx") useMagic(p, "chckIndx")
@ -1366,7 +1365,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
of tyBool: of tyBool:
result = putToSeq("false", indirect) result = putToSeq("false", indirect)
of tyArray: of tyArray:
let length = int(lengthOrd(t)) let length = int(lengthOrd(p.config, t))
let e = elemType(t) let e = elemType(t)
let jsTyp = arrayTypeForElemType(e) let jsTyp = arrayTypeForElemType(e)
if not jsTyp.isNil: if not jsTyp.isNil:
@ -1680,7 +1679,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mIsNil: unaryExpr(p, n, r, "", "($1 === null)") of mIsNil: unaryExpr(p, n, r, "", "($1 === null)")
of mEnumToStr: genRepr(p, n, r) of mEnumToStr: genRepr(p, n, r)
of mNew, mNewFinalize: genNew(p, n) of mNew, mNewFinalize: genNew(p, n)
of mSizeOf: r.res = rope(getSize(n.sons[1].typ)) of mSizeOf: r.res = rope(getSize(p.config, n.sons[1].typ))
of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do
of mOrd: genOrd(p, n, r) of mOrd: genOrd(p, n, r)
of mLengthStr: of mLengthStr:
@ -1901,13 +1900,13 @@ proc frameCreate(p: PProc; procname, filename: Rope): Rope =
result.add p.indentLine(ropes.`%`("framePtr = F;$n", [])) result.add p.indentLine(ropes.`%`("framePtr = F;$n", []))
proc frameDestroy(p: PProc): Rope = proc frameDestroy(p: PProc): Rope =
result = p.indentLine rope(("framePtr = F.prev;") & tnl) result = p.indentLine rope(("framePtr = F.prev;") & "\L")
proc genProcBody(p: PProc, prc: PSym): Rope = proc genProcBody(p: PProc, prc: PSym): Rope =
if hasFrameInfo(p): if hasFrameInfo(p):
result = frameCreate(p, result = frameCreate(p,
makeJSString(prc.owner.name.s & '.' & prc.name.s), makeJSString(prc.owner.name.s & '.' & prc.name.s),
makeJSString(toFilename(prc.info))) makeJSString(toFilename(p.config, prc.info)))
else: else:
result = nil result = nil
if p.beforeRetNeeded: if p.beforeRetNeeded:
@ -1926,7 +1925,7 @@ proc optionaLine(p: Rope): Rope =
if p == nil: if p == nil:
return nil return nil
else: else:
return p & tnl return p & "\L"
proc genProc(oldProc: PProc, prc: PSym): Rope = proc genProc(oldProc: PProc, prc: PSym): Rope =
var var
@ -1968,7 +1967,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
optionaLine(genProcBody(p, prc)), optionaLine(genProcBody(p, prc)),
optionaLine(p.indentLine(returnStmt))] optionaLine(p.indentLine(returnStmt))]
else: else:
result = ~tnl result = ~"\L"
if optHotCodeReloading in p.config.options: if optHotCodeReloading in p.config.options:
# Here, we introduce thunks that create the equivalent of a jump table # Here, we introduce thunks that create the equivalent of a jump table
@ -2156,7 +2155,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkRaiseStmt: genRaiseStmt(p, n) of nkRaiseStmt: genRaiseStmt(p, n)
of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef: discard nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard
of nkPragma: genPragma(p, n) of nkPragma: genPragma(p, n)
of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef: of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
var s = n.sons[namePos].sym var s = n.sons[namePos].sym
@ -2170,14 +2169,14 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
discard "XXX to implement for better stack traces" discard "XXX to implement for better stack traces"
else: internalError(p.config, n.info, "gen: unknown node type: " & $n.kind) else: internalError(p.config, n.info, "gen: unknown node type: " & $n.kind)
var globals: PGlobals # XXX global variable here proc newModule(g: ModuleGraph; module: PSym): BModule =
proc newModule(module: PSym): BModule =
new(result) new(result)
result.module = module result.module = module
result.sigConflicts = initCountTable[SigHash]() result.sigConflicts = initCountTable[SigHash]()
if globals == nil: if g.backend == nil:
globals = newGlobals() g.backend = newGlobals()
result.graph = g
result.config = g.config
proc genHeader(): Rope = proc genHeader(): Rope =
result = ( result = (
@ -2200,7 +2199,7 @@ proc genModule(p: PProc, n: PNode) =
if optStackTrace in p.options: if optStackTrace in p.options:
add(p.body, frameCreate(p, add(p.body, frameCreate(p,
makeJSString("module " & p.module.module.name.s), makeJSString("module " & p.module.module.name.s),
makeJSString(toFilename(p.module.module.info)))) makeJSString(toFilename(p.config, p.module.module.info))))
genStmt(p, n) genStmt(p, n)
if optStackTrace in p.options: if optStackTrace in p.options:
add(p.body, frameDestroy(p)) add(p.body, frameDestroy(p))
@ -2210,6 +2209,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
let m = BModule(b) let m = BModule(b)
if passes.skipCodegen(m.config, n): return n if passes.skipCodegen(m.config, n): return n
if m.module == nil: internalError(m.config, n.info, "myProcess") if m.module == nil: internalError(m.config, n.info, "myProcess")
let globals = PGlobals(m.graph.backend)
var p = newProc(globals, m, nil, m.module.options) var p = newProc(globals, m, nil, m.module.options)
p.unique = globals.unique p.unique = globals.unique
genModule(p, n) genModule(p, n)
@ -2217,6 +2217,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
add(p.g.code, p.body) add(p.g.code, p.body)
proc wholeCode(graph: ModuleGraph; m: BModule): Rope = proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
let globals = PGlobals(graph.backend)
for prc in globals.forwarded: for prc in globals.forwarded:
if not globals.generatedSyms.containsOrIncl(prc.id): if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newProc(globals, m, nil, m.module.options) var p = newProc(globals, m, nil, m.module.options)
@ -2261,8 +2262,9 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
var m = BModule(b) var m = BModule(b)
if passes.skipCodegen(m.config, n): return n if passes.skipCodegen(m.config, n): return n
if sfMainModule in m.module.flags: if sfMainModule in m.module.flags:
let globals = PGlobals(graph.backend)
let ext = "js" let ext = "js"
let f = if globals.classes.len == 0: toFilename(FileIndex m.module.position) let f = if globals.classes.len == 0: toFilename(m.config, FileIndex m.module.position)
else: "nimsystem" else: "nimsystem"
let code = wholeCode(graph, m) let code = wholeCode(graph, m)
let outfile = let outfile =
@ -2275,15 +2277,8 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
for obj, content in items(globals.classes): for obj, content in items(globals.classes):
genClass(m.config, obj, content, ext) genClass(m.config, obj, content, ext)
proc myOpenCached(graph: ModuleGraph; s: PSym, rd: PRodReader): PPassContext = proc myOpen(graph: ModuleGraph; s: PSym): PPassContext =
internalError(graph.config, "symbol files are not possible with the JS code generator") result = newModule(graph, s)
result = nil
proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext = const JSgenPass* = makePass(myOpen, myProcess, myClose)
var r = newModule(s)
r.graph = graph
r.config = graph.config
result = r
const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)

View file

@ -25,7 +25,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
else: else:
s = nil s = nil
for i in countup(0, length - 1): for i in countup(0, length - 1):
if i > 0: add(s, ", " & tnl) if i > 0: add(s, ", \L")
add(s, genObjectFields(p, typ, n.sons[i])) add(s, genObjectFields(p, typ, n.sons[i]))
result = ("{kind: 2, len: $1, offset: 0, " & result = ("{kind: 2, len: $1, offset: 0, " &
"typ: null, name: null, sons: [$2]}") % [rope(length), s] "typ: null, name: null, sons: [$2]}") % [rope(length), s]
@ -56,15 +56,15 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
else: else:
add(u, rope(getOrdValue(b.sons[j]))) add(u, rope(getOrdValue(b.sons[j])))
of nkElse: of nkElse:
u = rope(lengthOrd(field.typ)) u = rope(lengthOrd(p.config, field.typ))
else: internalError(p.config, n.info, "genObjectFields(nkRecCase)") else: internalError(p.config, n.info, "genObjectFields(nkRecCase)")
if result != nil: add(result, ", " & tnl) if result != nil: add(result, ", \L")
addf(result, "[setConstr($1), $2]", addf(result, "[setConstr($1), $2]",
[u, genObjectFields(p, typ, lastSon(b))]) [u, genObjectFields(p, typ, lastSon(b))])
result = ("{kind: 3, offset: \"$1\", len: $3, " & result = ("{kind: 3, offset: \"$1\", len: $3, " &
"typ: $2, name: $4, sons: [$5]}") % [ "typ: $2, name: $4, sons: [$5]}") % [
mangleName(p.module, field), s, mangleName(p.module, field), s,
rope(lengthOrd(field.typ)), makeJSString(field.name.s), result] rope(lengthOrd(p.config, field.typ)), makeJSString(field.name.s), result]
else: internalError(p.config, n.info, "genObjectFields") else: internalError(p.config, n.info, "genObjectFields")
proc objHasTypeField(t: PType): bool {.inline.} = proc objHasTypeField(t: PType): bool {.inline.} =
@ -85,7 +85,7 @@ proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
proc genTupleFields(p: PProc, typ: PType): Rope = proc genTupleFields(p: PProc, typ: PType): Rope =
var s: Rope = nil var s: Rope = nil
for i in 0 ..< typ.len: for i in 0 ..< typ.len:
if i > 0: add(s, ", " & tnl) if i > 0: add(s, ", \L")
s.addf("{kind: 1, offset: \"Field$1\", len: 0, " & s.addf("{kind: 1, offset: \"Field$1\", len: 0, " &
"typ: $2, name: \"Field$1\", sons: null}", "typ: $2, name: \"Field$1\", sons: null}",
[i.rope, genTypeInfo(p, typ.sons[i])]) [i.rope, genTypeInfo(p, typ.sons[i])])
@ -106,7 +106,7 @@ proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
for i in countup(0, length - 1): for i in countup(0, length - 1):
if (typ.n.sons[i].kind != nkSym): internalError(p.config, typ.n.info, "genEnumInfo") if (typ.n.sons[i].kind != nkSym): internalError(p.config, typ.n.info, "genEnumInfo")
let field = typ.n.sons[i].sym let field = typ.n.sons[i].sym
if i > 0: add(s, ", " & tnl) if i > 0: add(s, ", \L")
let extName = if field.ast == nil: field.name.s else: field.ast.strVal let extName = if field.ast == nil: field.name.s else: field.ast.strVal
addf(s, "\"$1\": {kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}", addf(s, "\"$1\": {kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}",
[rope(field.position), name, makeJSString(extName)]) [rope(field.position), name, makeJSString(extName)])

View file

@ -11,7 +11,7 @@
import import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, intsets, strutils, options, ast, astalgo, trees, treetab, msgs,
idents, renderer, types, magicsys, rodread, lowerings, tables, modulegraphs idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos
discard """ discard """
The basic approach is that captured vars need to be put on the heap and The basic approach is that captured vars need to be put on the heap and
@ -136,7 +136,7 @@ proc createClosureIterStateType*(g: ModuleGraph; iter: PSym): PType =
rawAddSon(result, intType) rawAddSon(result, intType)
proc createStateField(g: ModuleGraph; iter: PSym): PSym = proc createStateField(g: ModuleGraph; iter: PSym): PSym =
result = newSym(skField, getIdent(":state"), iter, iter.info) result = newSym(skField, getIdent(g.cache, ":state"), iter, iter.info)
result.typ = createClosureIterStateType(g, iter) result.typ = createClosureIterStateType(g, iter)
proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType = proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType =
@ -145,12 +145,12 @@ proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType =
result = createObj(g, owner, info, final=false) result = createObj(g, owner, info, final=false)
rawAddField(result, createStateField(g, owner)) rawAddField(result, createStateField(g, owner))
proc getClosureIterResult*(iter: PSym): PSym = proc getClosureIterResult*(g: ModuleGraph; iter: PSym): PSym =
if resultPos < iter.ast.len: if resultPos < iter.ast.len:
result = iter.ast.sons[resultPos].sym result = iter.ast.sons[resultPos].sym
else: else:
# XXX a bit hacky: # XXX a bit hacky:
result = newSym(skResult, getIdent":result", iter, iter.info, {}) result = newSym(skResult, getIdent(g.cache, ":result"), iter, iter.info, {})
result.typ = iter.typ.sons[0] result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed) incl(result.flags, sfUsed)
iter.ast.add newSymNode(result) iter.ast.add newSymNode(result)
@ -244,7 +244,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
var env: PNode var env: PNode
if owner.isIterator: if owner.isIterator:
let it = getHiddenParam(g, owner) let it = getHiddenParam(g, owner)
addUniqueField(it.typ.sons[0], hp) addUniqueField(it.typ.sons[0], hp, g.cache)
env = indirectAccess(newSymNode(it), hp, hp.info) env = indirectAccess(newSymNode(it), hp, hp.info)
else: else:
let e = newSym(skLet, iter.name, owner, n.info) let e = newSym(skLet, iter.name, owner, n.info)
@ -261,7 +261,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode = proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode =
let envParam = getHiddenParam(g, owner) let envParam = getHiddenParam(g, owner)
let obj = envParam.typ.lastSon let obj = envParam.typ.lastSon
addField(obj, s) addField(obj, s, g.cache)
var access = newSymNode(envParam) var access = newSymNode(envParam)
assert obj.kind == tyObject assert obj.kind == tyObject
@ -278,7 +278,7 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
let s = n.sym let s = n.sym
if illegalCapture(s): if illegalCapture(s):
localError(g.config, n.info, "illegal capture '$1' of type <$2> which is declared here: $3" % localError(g.config, n.info, "illegal capture '$1' of type <$2> which is declared here: $3" %
[s.name.s, typeToString(s.typ), $s.info]) [s.name.s, typeToString(s.typ), g.config$s.info])
elif owner.typ.callConv notin {ccClosure, ccDefault}: elif owner.typ.callConv notin {ccClosure, ccDefault}:
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" % localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
[s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]]) [s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]])
@ -325,7 +325,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
if refObj == fieldType: if refObj == fieldType:
localError(c.graph.config, dep.info, "internal error: invalid up reference computed") localError(c.graph.config, dep.info, "internal error: invalid up reference computed")
let upIdent = getIdent(upName) let upIdent = getIdent(c.graph.cache, upName)
let upField = lookupInRecord(obj.n, upIdent) let upField = lookupInRecord(obj.n, upIdent)
if upField != nil: if upField != nil:
if upField.typ != fieldType: if upField.typ != fieldType:
@ -366,7 +366,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner
let t = c.getEnvTypeForOwner(owner, info) let t = c.getEnvTypeForOwner(owner, info)
if cp == nil: if cp == nil:
cp = newSym(skParam, getIdent(paramName), fn, fn.info) cp = newSym(skParam, getIdent(c.graph.cache, paramName), fn, fn.info)
incl(cp.flags, sfFromGeneric) incl(cp.flags, sfFromGeneric)
cp.typ = t cp.typ = t
addHiddenParam(fn, cp) addHiddenParam(fn, cp)
@ -400,10 +400,10 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
let obj = getHiddenParam(c.graph, owner).typ.lastSon let obj = getHiddenParam(c.graph, owner).typ.lastSon
#let obj = c.getEnvTypeForOwner(s.owner).lastSon #let obj = c.getEnvTypeForOwner(s.owner).lastSon
if s.name == getIdent(":state"): if s.name.id == getIdent(c.graph.cache, ":state").id:
obj.n[0].sym.id = -s.id obj.n[0].sym.id = -s.id
else: else:
addField(obj, s) addField(obj, s, c.graph.cache)
# but always return because the rest of the proc is only relevant when # but always return because the rest of the proc is only relevant when
# ow != owner: # ow != owner:
return return
@ -428,7 +428,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id): if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id):
let obj = c.getEnvTypeForOwner(ow, n.info).lastSon let obj = c.getEnvTypeForOwner(ow, n.info).lastSon
#getHiddenParam(owner).typ.lastSon #getHiddenParam(owner).typ.lastSon
addField(obj, s) addField(obj, s, c.graph.cache)
# create required upFields: # create required upFields:
var w = owner.skipGenericOwner var w = owner.skipGenericOwner
if isInnerProc(w) or owner.isIterator: if isInnerProc(w) or owner.isIterator:
@ -485,14 +485,14 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let field = getFieldFromObj(obj, s) let field = getFieldFromObj(obj, s)
if field != nil: if field != nil:
return rawIndirectAccess(access, field, n.info) return rawIndirectAccess(access, field, n.info)
let upField = lookupInRecord(obj.n, getIdent(upName)) let upField = lookupInRecord(obj.n, getIdent(g.cache, upName))
if upField == nil: break if upField == nil: break
access = rawIndirectAccess(access, upField, n.info) access = rawIndirectAccess(access, upField, n.info)
localError(g.config, n.info, "internal error: environment misses: " & s.name.s) localError(g.config, n.info, "internal error: environment misses: " & s.name.s)
result = n result = n
proc newEnvVar(owner: PSym; typ: PType): PNode = proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType): PNode =
var v = newSym(skVar, getIdent(envName), owner, owner.info) var v = newSym(skVar, getIdent(cache, envName), owner, owner.info)
incl(v.flags, sfShadowed) incl(v.flags, sfShadowed)
v.typ = typ v.typ = typ
result = newSymNode(v) result = newSymNode(v)
@ -513,14 +513,14 @@ proc setupEnvVar(owner: PSym; d: DetectionPass;
let envVarType = d.ownerToType.getOrDefault(owner.id) let envVarType = d.ownerToType.getOrDefault(owner.id)
if envVarType.isNil: if envVarType.isNil:
localError d.graph.config, owner.info, "internal error: could not determine closure type" localError d.graph.config, owner.info, "internal error: could not determine closure type"
result = newEnvVar(owner, envVarType) result = newEnvVar(d.graph.cache, owner, envVarType)
c.envVars[owner.id] = result c.envVars[owner.id] = result
proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode = proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode =
let p = getHiddenParam(g, owner) let p = getHiddenParam(g, owner)
result = p.newSymNode result = p.newSymNode
if owner.isIterator: if owner.isIterator:
let upField = lookupInRecord(p.typ.lastSon.n, getIdent(upName)) let upField = lookupInRecord(p.typ.lastSon.n, getIdent(g.cache, upName))
if upField == nil: if upField == nil:
localError(g.config, owner.info, "could not find up reference for closure iter") localError(g.config, owner.info, "could not find up reference for closure iter")
else: else:
@ -549,7 +549,7 @@ proc rawClosureCreation(owner: PSym;
# add ``env.param = param`` # add ``env.param = param``
result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info)) result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
let upField = lookupInRecord(env.typ.lastSon.n, getIdent(upName)) let upField = lookupInRecord(env.typ.lastSon.n, getIdent(d.graph.cache, upName))
if upField != nil: if upField != nil:
let up = getUpViaParam(d.graph, owner) let up = getUpViaParam(d.graph, owner)
if up != nil and upField.typ == up.typ: if up != nil and upField.typ == up.typ:
@ -565,13 +565,13 @@ proc closureCreationForIter(iter: PNode;
d: DetectionPass; c: var LiftingPass): PNode = d: DetectionPass; c: var LiftingPass): PNode =
result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ) result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ)
let owner = iter.sym.skipGenericOwner let owner = iter.sym.skipGenericOwner
var v = newSym(skVar, getIdent(envName), owner, iter.info) var v = newSym(skVar, getIdent(d.graph.cache, envName), owner, iter.info)
incl(v.flags, sfShadowed) incl(v.flags, sfShadowed)
v.typ = getHiddenParam(d.graph, iter.sym).typ v.typ = getHiddenParam(d.graph, iter.sym).typ
var vnode: PNode var vnode: PNode
if owner.isIterator: if owner.isIterator:
let it = getHiddenParam(d.graph, owner) let it = getHiddenParam(d.graph, owner)
addUniqueField(it.typ.sons[0], v) addUniqueField(it.typ.sons[0], v, d.graph.cache)
vnode = indirectAccess(newSymNode(it), v, v.info) vnode = indirectAccess(newSymNode(it), v, v.info)
else: else:
vnode = v.newSymNode vnode = v.newSymNode
@ -580,7 +580,7 @@ proc closureCreationForIter(iter: PNode;
result.add(vs) result.add(vs)
result.add(newCall(getSysSym(d.graph, iter.info, "internalNew"), vnode)) result.add(newCall(getSysSym(d.graph, iter.info, "internalNew"), vnode))
let upField = lookupInRecord(v.typ.lastSon.n, getIdent(upName)) let upField = lookupInRecord(v.typ.lastSon.n, getIdent(d.graph.cache, upName))
if upField != nil: if upField != nil:
let u = setupEnvVar(owner, d, c) let u = setupEnvVar(owner, d, c)
if u.typ == upField.typ: if u.typ == upField.typ:
@ -607,81 +607,6 @@ proc getStateField*(g: ModuleGraph; owner: PSym): PSym =
proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode c: var LiftingPass): PNode
proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode =
if c.inContainer > 0:
localError(d.graph.config, n.info, "invalid control flow: 'yield' within a constructor")
let state = getStateField(d.graph, owner)
assert state != nil
assert state.typ != nil
assert state.typ.n != nil
inc state.typ.n.sons[1].intVal
let stateNo = state.typ.n.sons[1].intVal
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)),
state, n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo,
getSysType(d.graph, n.info, tyInt)))
var retStmt = newNodeI(nkReturnStmt, n.info)
if n.sons[0].kind != nkEmpty:
var a = newNodeI(nkAsgn, n.sons[0].info)
var retVal = liftCapturedVars(n.sons[0], owner, d, c)
addSon(a, newSymNode(getClosureIterResult(owner)))
addSon(a, retVal)
retStmt.add(a)
else:
retStmt.add(emptyNode)
var stateLabelStmt = newNodeI(nkState, n.info)
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo,
getSysType(d.graph, n.info, tyInt)))
result = newNodeI(nkStmtList, n.info)
result.add(stateAsgnStmt)
result.add(retStmt)
result.add(stateLabelStmt)
proc transformReturn(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode =
let state = getStateField(d.graph, owner)
result = newNodeI(nkStmtList, n.info)
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)),
state, n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(d.graph, n.info, tyInt)))
result.add(stateAsgnStmt)
result.add(n)
proc wrapIterBody(g: ModuleGraph; n: PNode; owner: PSym): PNode =
if not owner.isIterator: return n
when false:
# unfortunately control flow is still convoluted and we can end up
# multiple times here for the very same iterator. We shield against this
# with some rather primitive check for now:
if n.kind == nkStmtList and n.len > 0:
if n.sons[0].kind == nkGotoState: return n
if n.len > 1 and n[1].kind == nkStmtList and n[1].len > 0 and
n[1][0].kind == nkGotoState:
return n
let info = n.info
result = newNodeI(nkStmtList, info)
var gs = newNodeI(nkGotoState, info)
gs.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)), getStateField(g, owner), info))
result.add(gs)
var state0 = newNodeI(nkState, info)
state0.add(newIntNode(nkIntLit, 0))
result.add(state0)
result.add(n)
var stateAsgnStmt = newNodeI(nkAsgn, info)
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)),
getStateField(g, owner), info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(g, info, tyInt)))
result.add(stateAsgnStmt)
proc symToClosure(n: PNode; owner: PSym; d: DetectionPass; proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode = c: var LiftingPass): PNode =
let s = n.sym let s = n.sym
@ -703,7 +628,7 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
if access.typ == wanted: if access.typ == wanted:
return makeClosure(d.graph, s, access, n.info) return makeClosure(d.graph, s, access, n.info)
let obj = access.typ.sons[0] let obj = access.typ.sons[0]
let upField = lookupInRecord(obj.n, getIdent(upName)) let upField = lookupInRecord(obj.n, getIdent(d.graph.cache, upName))
if upField == nil: if upField == nil:
localError(d.graph.config, n.info, "internal error: no environment found") localError(d.graph.config, n.info, "internal error: no environment found")
return n return n
@ -722,8 +647,6 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
let oldInContainer = c.inContainer let oldInContainer = c.inContainer
c.inContainer = 0 c.inContainer = 0
var body = liftCapturedVars(s.getBody, s, d, c) var body = liftCapturedVars(s.getBody, s, d, c)
if oldIterTransf in d.graph.config.features:
body = wrapIterBody(d.graph, body, s)
if c.envvars.getOrDefault(s.id).isNil: if c.envvars.getOrDefault(s.id).isNil:
s.ast.sons[bodyPos] = body s.ast.sons[bodyPos] = body
else: else:
@ -766,11 +689,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
if n[1].kind == nkClosure: result = n[1] if n[1].kind == nkClosure: result = n[1]
else: else:
if owner.isIterator: if owner.isIterator:
if oldIterTransf in d.graph.config.features and n.kind == nkYieldStmt: if nfLL in n.flags:
return transformYield(n, owner, d, c)
elif oldIterTransf in d.graph.config.features and n.kind == nkReturnStmt:
return transformReturn(n, owner, d, c)
elif nfLL in n.flags:
# special case 'when nimVm' due to bug #3636: # special case 'when nimVm' due to bug #3636:
n.sons[1] = liftCapturedVars(n[1], owner, d, c) n.sons[1] = liftCapturedVars(n[1], owner, d, c)
return return
@ -811,7 +730,7 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNo
fn.typ.callConv = ccClosure fn.typ.callConv = ccClosure
d.ownerToType[fn.id] = ptrType d.ownerToType[fn.id] = ptrType
detectCapturedVars(body, fn, d) detectCapturedVars(body, fn, d)
result = wrapIterBody(g, liftCapturedVars(body, fn, d, c), fn) result = liftCapturedVars(body, fn, d, c)
fn.kind = oldKind fn.kind = oldKind
fn.typ.callConv = oldCC fn.typ.callConv = oldCC
@ -840,9 +759,6 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PN
result = liftCapturedVars(body, fn, d, c) result = liftCapturedVars(body, fn, d, c)
if c.envvars.getOrDefault(fn.id) != nil: if c.envvars.getOrDefault(fn.id) != nil:
result = newTree(nkStmtList, rawClosureCreation(fn, d, c), result) result = newTree(nkStmtList, rawClosureCreation(fn, d, c), result)
if oldIterTransf in g.config.features:
result = wrapIterBody(g, result, fn)
else: else:
result = body result = body
#if fn.name.s == "get2": #if fn.name.s == "get2":
@ -932,7 +848,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
body[i].sym.kind = skLet body[i].sym.kind = skLet
addSon(vpart, body[i]) addSon(vpart, body[i])
addSon(vpart, ast.emptyNode) # no explicit type addSon(vpart, newNodeI(nkEmpty, body.info)) # no explicit type
if not env.isNil: if not env.isNil:
call.sons[0] = makeClosure(g, call.sons[0].sym, env.newSymNode, body.info) call.sons[0] = makeClosure(g, call.sons[0].sym, env.newSymNode, body.info)
addSon(vpart, call) addSon(vpart, call)
@ -942,12 +858,12 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
var bs = newNodeI(nkBreakState, body.info) var bs = newNodeI(nkBreakState, body.info)
bs.addSon(call.sons[0]) bs.addSon(call.sons[0])
let ibs = newNode(nkIfStmt) let ibs = newNodeI(nkIfStmt, body.info)
let elifBranch = newNode(nkElifBranch) let elifBranch = newNodeI(nkElifBranch, body.info)
elifBranch.add(bs) elifBranch.add(bs)
let br = newNode(nkBreakStmt) let br = newNodeI(nkBreakStmt, body.info)
br.add(emptyNode) br.add(g.emptyNode)
elifBranch.add(br) elifBranch.add(br)
ibs.add(elifBranch) ibs.add(elifBranch)

View file

@ -17,7 +17,7 @@
import import
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream, hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
wordrecg, configuration wordrecg, lineinfos
const const
MaxLineLength* = 80 # lines longer than this lead to a warning MaxLineLength* = 80 # lines longer than this lead to a warning
@ -273,10 +273,10 @@ template tokenBegin(tok, pos) {.dirty.} =
template tokenEnd(tok, pos) {.dirty.} = template tokenEnd(tok, pos) {.dirty.} =
when defined(nimsuggest): when defined(nimsuggest):
let colB = getColNumber(L, pos)+1 let colB = getColNumber(L, pos)+1
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and if L.fileIdx == L.config.m.trackPos.fileIndex and L.config.m.trackPos.col in colA..colB and
L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}: L.lineNumber == L.config.m.trackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
L.cursor = CursorPosition.InToken L.cursor = CursorPosition.InToken
gTrackPos.col = colA.int16 L.config.m.trackPos.col = colA.int16
colA = 0 colA = 0
when defined(nimpretty): when defined(nimpretty):
tok.offsetB = L.offsetBase + pos tok.offsetB = L.offsetBase + pos
@ -284,10 +284,10 @@ template tokenEnd(tok, pos) {.dirty.} =
template tokenEndIgnore(tok, pos) = template tokenEndIgnore(tok, pos) =
when defined(nimsuggest): when defined(nimsuggest):
let colB = getColNumber(L, pos) let colB = getColNumber(L, pos)
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and if L.fileIdx == L.config.m.trackPos.fileIndex and L.config.m.trackPos.col in colA..colB and
L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}: L.lineNumber == L.config.m.trackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
gTrackPos.fileIndex = trackPosInvalidFileIdx L.config.m.trackPos.fileIndex = trackPosInvalidFileIdx
gTrackPos.line = 0'u16 L.config.m.trackPos.line = 0'u16
colA = 0 colA = 0
when defined(nimpretty): when defined(nimpretty):
tok.offsetB = L.offsetBase + pos tok.offsetB = L.offsetBase + pos
@ -298,11 +298,11 @@ template tokenEndPrevious(tok, pos) =
# to the token that came before that, but only if we haven't detected # to the token that came before that, but only if we haven't detected
# the cursor in a string literal or comment: # the cursor in a string literal or comment:
let colB = getColNumber(L, pos) let colB = getColNumber(L, pos)
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and if L.fileIdx == L.config.m.trackPos.fileIndex and L.config.m.trackPos.col in colA..colB and
L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}: L.lineNumber == L.config.m.trackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
L.cursor = CursorPosition.BeforeToken L.cursor = CursorPosition.BeforeToken
gTrackPos = L.previousToken L.config.m.trackPos = L.previousToken
gTrackPosAttached = true L.config.m.trackPosAttached = true
colA = 0 colA = 0
when defined(nimpretty): when defined(nimpretty):
tok.offsetB = L.offsetBase + pos tok.offsetB = L.offsetBase + pos
@ -630,14 +630,14 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
if L.config.oldNewlines: if L.config.oldNewlines:
if tok.tokType == tkCharLit: if tok.tokType == tkCharLit:
lexMessage(L, errGenerated, "\\n not allowed in character literal") lexMessage(L, errGenerated, "\\n not allowed in character literal")
add(tok.literal, tnl) add(tok.literal, L.config.target.tnl)
else: else:
add(tok.literal, '\L') add(tok.literal, '\L')
inc(L.bufpos) inc(L.bufpos)
of 'p', 'P': of 'p', 'P':
if tok.tokType == tkCharLit: if tok.tokType == tkCharLit:
lexMessage(L, errGenerated, "\\p not allowed in character literal") lexMessage(L, errGenerated, "\\p not allowed in character literal")
add(tok.literal, tnl) add(tok.literal, L.config.target.tnl)
inc(L.bufpos) inc(L.bufpos)
of 'r', 'R', 'c', 'C': of 'r', 'R', 'c', 'C':
add(tok.literal, CR) add(tok.literal, CR)
@ -714,11 +714,6 @@ proc handleCRLF(L: var TLexer, pos: int): int =
if col > MaxLineLength: if col > MaxLineLength:
lexMessagePos(L, hintLineTooLong, pos) lexMessagePos(L, hintLineTooLong, pos)
if optEmbedOrigSrc in L.config.globalOptions:
let lineStart = cast[ByteAddress](L.buf) + L.lineStart
let line = newString(cast[cstring](lineStart), col)
addSourceLine(L.fileIdx, line)
case L.buf[pos] case L.buf[pos]
of CR: of CR:
registerLine() registerLine()
@ -1121,9 +1116,9 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
else: else:
tok.tokType = tkParLe tok.tokType = tkParLe
when defined(nimsuggest): when defined(nimsuggest):
if L.fileIdx == gTrackPos.fileIndex and tok.col < gTrackPos.col and if L.fileIdx == L.config.m.trackPos.fileIndex and tok.col < L.config.m.trackPos.col and
tok.line == gTrackPos.line.int and L.config.ideCmd == ideCon: tok.line == L.config.m.trackPos.line.int and L.config.ideCmd == ideCon:
gTrackPos.col = tok.col.int16 L.config.m.trackPos.col = tok.col.int16
of ')': of ')':
tok.tokType = tkParRi tok.tokType = tkParRi
inc(L.bufpos) inc(L.bufpos)
@ -1142,11 +1137,11 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
inc(L.bufpos) inc(L.bufpos)
of '.': of '.':
when defined(nimsuggest): when defined(nimsuggest):
if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and if L.fileIdx == L.config.m.trackPos.fileIndex and tok.col+1 == L.config.m.trackPos.col and
tok.line == gTrackPos.line.int and L.config.ideCmd == ideSug: tok.line == L.config.m.trackPos.line.int and L.config.ideCmd == ideSug:
tok.tokType = tkDot tok.tokType = tkDot
L.cursor = CursorPosition.InToken L.cursor = CursorPosition.InToken
gTrackPos.col = tok.col.int16 L.config.m.trackPos.col = tok.col.int16
inc(L.bufpos) inc(L.bufpos)
atTokenEnd() atTokenEnd()
return return

View file

@ -11,7 +11,7 @@
import import
intsets, strutils, options, ast, astalgo, msgs, intsets, strutils, options, ast, astalgo, msgs,
idents, renderer, types, lowerings idents, renderer, types, lowerings, lineinfos
from pragmas import getPragmaVal from pragmas import getPragmaVal
from wordrecg import wLiftLocals from wordrecg import wLiftLocals
@ -20,13 +20,14 @@ type
Ctx = object Ctx = object
partialParam: PSym partialParam: PSym
objType: PType objType: PType
cache: IdentCache
proc interestingVar(s: PSym): bool {.inline.} = proc interestingVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar, skResult} and result = s.kind in {skVar, skLet, skTemp, skForVar, skResult} and
sfGlobal notin s.flags sfGlobal notin s.flags
proc lookupOrAdd(c: var Ctx; s: PSym; info: TLineInfo): PNode = proc lookupOrAdd(c: var Ctx; s: PSym; info: TLineInfo): PNode =
let field = addUniqueField(c.objType, s) let field = addUniqueField(c.objType, s, c.cache)
var deref = newNodeI(nkHiddenDeref, info) var deref = newNodeI(nkHiddenDeref, info)
deref.typ = c.objType deref.typ = c.objType
add(deref, newSymNode(c.partialParam, info)) add(deref, newSymNode(c.partialParam, info))
@ -52,7 +53,7 @@ proc lookupParam(params, dest: PNode): PSym =
if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id: if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:
return params[i].sym return params[i].sym
proc liftLocalsIfRequested*(prc: PSym; n: PNode; conf: ConfigRef): PNode = proc liftLocalsIfRequested*(prc: PSym; n: PNode; cache: IdentCache; conf: ConfigRef): PNode =
let liftDest = getPragmaVal(prc.ast, wLiftLocals) let liftDest = getPragmaVal(prc.ast, wLiftLocals)
if liftDest == nil: return n if liftDest == nil: return n
let partialParam = lookupParam(prc.typ.n, liftDest) let partialParam = lookupParam(prc.typ.n, liftDest)
@ -64,7 +65,7 @@ proc liftLocalsIfRequested*(prc: PSym; n: PNode; conf: ConfigRef): PNode =
if objType.kind != tyObject or tfPartial notin objType.flags: if objType.kind != tyObject or tfPartial notin objType.flags:
localError(conf, liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest) localError(conf, liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest)
return n return n
var c = Ctx(partialParam: partialParam, objType: objType) var c = Ctx(partialParam: partialParam, objType: objType, cache: cache)
let w = newTree(nkStmtList, n) let w = newTree(nkStmtList, n)
liftLocals(w, 0, c) liftLocals(w, 0, c)
result = w[0] result = w[0]

267
compiler/lineinfos.nim Normal file
View file

@ -0,0 +1,267 @@
#
#
# The Nim Compiler
# (c) Copyright 2018 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module contains the ``TMsgKind`` enum as well as the
## ``TLineInfo`` object.
import ropes, tables
const
explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
type
TMsgKind* = enum
errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile,
errXExpected,
errGridTableNotImplemented,
errGeneralParseError,
errNewSectionExpected,
errInvalidDirectiveX,
errGenerated,
errUser,
warnCannotOpenFile,
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
warnDeprecated, warnConfigDeprecated,
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
warnUnknownSubstitutionX, warnLanguageXNotSupported,
warnFieldXNotSupported, warnCommentXIgnored,
warnTypelessParam,
warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
warnEachIdentIsTuple, warnShadowIdent,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
warnInconsistentSpacing, warnUser,
hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
hintConditionAlwaysTrue, hintName, hintPattern,
hintExecuting, hintLinking, hintDependency,
hintSource, hintPerformance, hintStackTrace, hintGCStats,
hintGlobalVar,
hintUser, hintUserRaw
const
MsgKindToStr*: array[TMsgKind, string] = [
errUnknown: "unknown error",
errInternal: "internal error: $1",
errIllFormedAstX: "illformed AST: $1",
errCannotOpenFile: "cannot open '$1'",
errXExpected: "'$1' expected",
errGridTableNotImplemented: "grid table is not implemented",
errGeneralParseError: "general parse error",
errNewSectionExpected: "new section expected",
errInvalidDirectiveX: "invalid directive: '$1'",
errGenerated: "$1",
errUser: "$1",
warnCannotOpenFile: "cannot open '$1'",
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
warnXIsNeverRead: "'$1' is never read",
warnXmightNotBeenInit: "'$1' might not have been initialized",
warnDeprecated: "$1 is deprecated",
warnConfigDeprecated: "config file '$1' is deprecated",
warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)",
warnUnknownMagic: "unknown magic '$1' might crash the compiler",
warnRedefinitionOfLabel: "redefinition of label '$1'",
warnUnknownSubstitutionX: "unknown substitution '$1'",
warnLanguageXNotSupported: "language '$1' not supported",
warnFieldXNotSupported: "field '$1' not supported",
warnCommentXIgnored: "comment '$1' ignored",
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
warnWriteToForeignHeap: "write to foreign heap",
warnUnsafeCode: "unsafe code: '$1'",
warnEachIdentIsTuple: "each identifier is a tuple",
warnShadowIdent: "shadowed identifier: '$1'",
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.",
warnProveField: "cannot prove that field '$1' is accessible",
warnProveIndex: "cannot prove index '$1' is valid",
warnGcUnsafe: "not GC-safe: '$1'",
warnGcUnsafe2: "$1",
warnUninit: "'$1' might not have been initialized",
warnGcMem: "'$1' uses GC'ed memory",
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
warnLockLevel: "$1",
warnResultShadowed: "Special variable 'result' is shadowed.",
warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
warnUser: "$1",
hintSuccess: "operation successful",
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
hintLineTooLong: "line too long",
hintXDeclaredButNotUsed: "'$1' is declared but not used",
hintConvToBaseNotNeeded: "conversion to base object is not needed",
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
hintExprAlwaysX: "expression evaluates always to '$1'",
hintQuitCalled: "quit() called",
hintProcessing: "$1",
hintCodeBegin: "generated code listing:",
hintCodeEnd: "end of listing",
hintConf: "used config file '$1'",
hintPath: "added path: '$1'",
hintConditionAlwaysTrue: "condition is always true: '$1'",
hintName: "name should be: '$1'",
hintPattern: "$1",
hintExecuting: "$1",
hintLinking: "",
hintDependency: "$1",
hintSource: "$1",
hintPerformance: "$1",
hintStackTrace: "$1",
hintGCStats: "$1",
hintGlobalVar: "global variable declared here",
hintUser: "$1",
hintUserRaw: "$1"]
const
WarningsToStr* = ["CannotOpenFile", "OctalEscape",
"XIsNeverRead", "XmightNotBeenInit",
"Deprecated", "ConfigDeprecated",
"SmallLshouldNotBeUsed", "UnknownMagic",
"RedefinitionOfLabel", "UnknownSubstitutionX",
"LanguageXNotSupported", "FieldXNotSupported",
"CommentXIgnored",
"TypelessParam", "UseBase", "WriteToForeignHeap",
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
"Spacing", "User"]
HintsToStr* = ["Success", "SuccessX", "LineTooLong",
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
"Source", "Performance", "StackTrace", "GCStats", "GlobalVar",
"User", "UserRaw"]
const
fatalMin* = errUnknown
fatalMax* = errInternal
errMin* = errUnknown
errMax* = errUser
warnMin* = warnCannotOpenFile
warnMax* = pred(hintSuccess)
hintMin* = hintSuccess
hintMax* = high(TMsgKind)
static:
doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
type
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
TNoteKinds* = set[TNoteKind]
const
NotesVerbosity*: array[0..3, TNoteKinds] = [
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
warnProveField, warnProveIndex,
warnGcUnsafe,
hintSuccessX, hintPath, hintConf,
hintProcessing, hintPattern,
hintDependency,
hintExecuting, hintLinking,
hintCodeBegin, hintCodeEnd,
hintSource, hintStackTrace,
hintGlobalVar, hintGCStats},
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
warnProveField, warnProveIndex,
warnGcUnsafe,
hintPath,
hintDependency,
hintCodeBegin, hintCodeEnd,
hintSource, hintStackTrace,
hintGlobalVar, hintGCStats},
{low(TNoteKind)..high(TNoteKind)} - {hintStackTrace, warnUninit},
{low(TNoteKind)..high(TNoteKind)}]
const
errXMustBeCompileTime* = "'$1' can only be used in compile-time context"
errArgsNeedRunOption* = "arguments can only be given if the '--run' option is selected"
type
TFileInfo* = object
fullPath*: string # This is a canonical full filesystem path
projPath*: string # This is relative to the project's root
shortName*: string # short name of the module
quotedName*: Rope # cached quoted short name for codegen
# purposes
quotedFullName*: Rope # cached quoted full name for codegen
# purposes
lines*: seq[string] # the source code of the module
# used for better error messages and
# embedding the original source in the
# generated code
dirtyfile*: string # the file that is actually read into memory
# and parsed; usually "" but is used
# for 'nimsuggest'
hash*: string # the checksum of the file
dirty*: bool # for 'nimfix' / 'nimpretty' like tooling
when defined(nimpretty):
fullContent*: string
FileIndex* = distinct int32
TLineInfo* = object # This is designed to be as small as possible,
# because it is used
# in syntax nodes. We save space here by using
# two int16 and an int32.
# On 64 bit and on 32 bit systems this is
# only 8 bytes.
line*: uint16
col*: int16
fileIndex*: FileIndex
when defined(nimpretty):
offsetA*, offsetB*: int
commentOffsetA*, commentOffsetB*: int
TErrorOutput* = enum
eStdOut
eStdErr
TErrorOutputs* = set[TErrorOutput]
ERecoverableError* = object of ValueError
ESuggestDone* = object of Exception
proc `==`*(a, b: FileIndex): bool {.borrow.}
const
InvalidFileIDX* = FileIndex(-1)
proc unknownLineInfo*(): TLineInfo =
result.line = uint16(0)
result.col = int16(-1)
result.fileIndex = InvalidFileIDX
type
Severity* {.pure.} = enum ## VS Code only supports these three
Hint, Warning, Error
const trackPosInvalidFileIdx* = FileIndex(-2) # special marker so that no suggestions
# are produced within comments and string literals
type
MsgConfig* = object ## does not need to be stored in the incremental cache
trackPos*: TLineInfo
trackPosAttached*: bool ## whether the tracking position was attached to
## some close token.
errorOutputs*: TErrorOutputs
msgContext*: seq[TLineInfo]
lastError*: TLineInfo
filenameToIndexTbl*: Table[string, FileIndex]
fileInfos*: seq[TFileInfo]
systemFileIdx*: FileIndex
proc initMsgConfig*(): MsgConfig =
result.msgContext = @[]
result.lastError = unknownLineInfo()
result.filenameToIndexTbl = initTable[string, FileIndex]()
result.fileInfos = @[]
result.errorOutputs = {eStdOut, eStdErr}

View file

@ -10,8 +10,8 @@
# This module implements lookup helpers. # This module implements lookup helpers.
import import
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread, intsets, ast, astalgo, idents, semdata, types, msgs, options,
renderer, wordrecg, idgen, nimfix.prettybase, configuration, strutils renderer, wordrecg, idgen, nimfix.prettybase, lineinfos, strutils
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
@ -22,13 +22,13 @@ proc noidentError(conf: ConfigRef; n, origin: PNode) =
m.add "identifier expected, but found '" & n.renderTree & "'" m.add "identifier expected, but found '" & n.renderTree & "'"
localError(conf, n.info, m) localError(conf, n.info, m)
proc considerQuotedIdent*(conf: ConfigRef; n: PNode, origin: PNode = nil): PIdent = proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent =
## Retrieve a PIdent from a PNode, taking into account accent nodes. ## Retrieve a PIdent from a PNode, taking into account accent nodes.
## ``origin`` can be nil. If it is not nil, it is used for a better ## ``origin`` can be nil. If it is not nil, it is used for a better
## error message. ## error message.
template handleError(n, origin: PNode) = template handleError(n, origin: PNode) =
noidentError(conf, n, origin) noidentError(c.config, n, origin)
result = getIdent"<Error>" result = getIdent(c.cache, "<Error>")
case n.kind case n.kind
of nkIdent: result = n.ident of nkIdent: result = n.ident
@ -36,7 +36,7 @@ proc considerQuotedIdent*(conf: ConfigRef; n: PNode, origin: PNode = nil): PIden
of nkAccQuoted: of nkAccQuoted:
case n.len case n.len
of 0: handleError(n, origin) of 0: handleError(n, origin)
of 1: result = considerQuotedIdent(conf, n.sons[0], origin) of 1: result = considerQuotedIdent(c, n.sons[0], origin)
else: else:
var id = "" var id = ""
for i in 0..<n.len: for i in 0..<n.len:
@ -46,7 +46,7 @@ proc considerQuotedIdent*(conf: ConfigRef; n: PNode, origin: PNode = nil): PIden
of nkSym: id.add(x.sym.name.s) of nkSym: id.add(x.sym.name.s)
of nkLiterals - nkFloatLiterals: id.add(x.renderTree) of nkLiterals - nkFloatLiterals: id.add(x.renderTree)
else: handleError(n, origin) else: handleError(n, origin)
result = getIdent(id) result = getIdent(c.cache, id)
of nkOpenSymChoice, nkClosedSymChoice: of nkOpenSymChoice, nkClosedSymChoice:
if n[0].kind == nkSym: if n[0].kind == nkSym:
result = n.sons[0].sym.name result = n.sons[0].sym.name
@ -86,7 +86,7 @@ proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym =
else: else:
result = s.owner result = s.owner
if conf.cmd == cmdPretty: if conf.cmd == cmdPretty:
prettybase.replaceDeprecated(n.info, s, result) prettybase.replaceDeprecated(conf, n.info, s, result)
else: else:
message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " & message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " &
s.name.s) s.name.s)
@ -100,15 +100,16 @@ proc searchInScopes*(c: PContext, s: PIdent): PSym =
if result != nil: return if result != nil: return
result = nil result = nil
proc debugScopes*(c: PContext; limit=0) {.deprecated.} = when declared(echo):
var i = 0 proc debugScopes*(c: PContext; limit=0) {.deprecated.} =
for scope in walkScopes(c.currentScope): var i = 0
echo "scope ", i for scope in walkScopes(c.currentScope):
for h in 0 .. high(scope.symbols.data): echo "scope ", i
if scope.symbols.data[h] != nil: for h in 0 .. high(scope.symbols.data):
echo scope.symbols.data[h].name.s if scope.symbols.data[h] != nil:
if i == limit: break echo scope.symbols.data[h].name.s
inc i if i == limit: break
inc i
proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym = proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
for scope in walkScopes(c.currentScope): for scope in walkScopes(c.currentScope):
@ -125,9 +126,9 @@ proc errorSym*(c: PContext, n: PNode): PSym =
# ensure that 'considerQuotedIdent' can't fail: # ensure that 'considerQuotedIdent' can't fail:
if m.kind == nkDotExpr: m = m.sons[1] if m.kind == nkDotExpr: m = m.sons[1]
let ident = if m.kind in {nkIdent, nkSym, nkAccQuoted}: let ident = if m.kind in {nkIdent, nkSym, nkAccQuoted}:
considerQuotedIdent(c.config, m) considerQuotedIdent(c, m)
else: else:
getIdent("err:" & renderTree(m)) getIdent(c.cache, "err:" & renderTree(m))
result = newSym(skError, ident, getCurrOwner(c), n.info, {}) result = newSym(skError, ident, getCurrOwner(c), n.info, {})
result.typ = errorType(c) result.typ = errorType(c)
incl(result.flags, sfDiscardable) incl(result.flags, sfDiscardable)
@ -139,7 +140,7 @@ type
TOverloadIterMode* = enum TOverloadIterMode* = enum
oimDone, oimNoQualifier, oimSelfModule, oimOtherModule, oimSymChoice, oimDone, oimNoQualifier, oimSelfModule, oimOtherModule, oimSymChoice,
oimSymChoiceLocalLookup oimSymChoiceLocalLookup
TOverloadIter*{.final.} = object TOverloadIter* = object
it*: TIdentIter it*: TIdentIter
m*: PSym m*: PSym
mode*: TOverloadIterMode mode*: TOverloadIterMode
@ -147,10 +148,10 @@ type
scope*: PScope scope*: PScope
inSymChoice: IntSet inSymChoice: IntSet
proc getSymRepr*(s: PSym): string = proc getSymRepr*(conf: ConfigRef; s: PSym): string =
case s.kind case s.kind
of skProc, skFunc, skMethod, skConverter, skIterator: of skProc, skFunc, skMethod, skConverter, skIterator:
result = getProcHeader(s) result = getProcHeader(conf, s)
else: else:
result = s.name.s result = s.name.s
@ -164,7 +165,8 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
# too many 'implementation of X' errors are annoying # too many 'implementation of X' errors are annoying
# and slow 'suggest' down: # and slow 'suggest' down:
if missingImpls == 0: if missingImpls == 0:
localError(c.config, s.info, "implementation of '$1' expected" % getSymRepr(s)) localError(c.config, s.info, "implementation of '$1' expected" %
getSymRepr(c.config, s))
inc missingImpls inc missingImpls
elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options: elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}: if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
@ -172,7 +174,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
# maybe they can be made skGenericParam as well. # maybe they can be made skGenericParam as well.
if s.typ != nil and tfImplicitTypeParam notin s.typ.flags and if s.typ != nil and tfImplicitTypeParam notin s.typ.flags and
s.typ.kind != tyGenericParam: s.typ.kind != tyGenericParam:
message(c.config, s.info, hintXDeclaredButNotUsed, getSymRepr(s)) message(c.config, s.info, hintXDeclaredButNotUsed, getSymRepr(c.config, s))
s = nextIter(it, scope.symbols) s = nextIter(it, scope.symbols)
proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string) = proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string) =
@ -275,7 +277,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
of nkSym: of nkSym:
result = n.sym result = n.sym
of nkAccQuoted: of nkAccQuoted:
var ident = considerQuotedIdent(c.config, n) var ident = considerQuotedIdent(c, n)
result = searchInScopes(c, ident).skipAlias(n, c.config) result = searchInScopes(c, ident).skipAlias(n, c.config)
if result == nil: if result == nil:
fixSpelling(n, ident, searchInScopes) fixSpelling(n, ident, searchInScopes)
@ -286,7 +288,8 @@ proc lookUp*(c: PContext, n: PNode): PSym =
return return
if contains(c.ambiguousSymbols, result.id): if contains(c.ambiguousSymbols, result.id):
errorUseQualifier(c, n.info, result) errorUseQualifier(c, n.info, result)
if result.kind == skStub: loadStub(result) when false:
if result.kind == skStub: loadStub(result)
type type
TLookupFlag* = enum TLookupFlag* = enum
@ -296,7 +299,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
const allExceptModule = {low(TSymKind)..high(TSymKind)}-{skModule,skPackage} const allExceptModule = {low(TSymKind)..high(TSymKind)}-{skModule,skPackage}
case n.kind case n.kind
of nkIdent, nkAccQuoted: of nkIdent, nkAccQuoted:
var ident = considerQuotedIdent(c.config, n) var ident = considerQuotedIdent(c, n)
if checkModule in flags: if checkModule in flags:
result = searchInScopes(c, ident).skipAlias(n, c.config) result = searchInScopes(c, ident).skipAlias(n, c.config)
else: else:
@ -322,7 +325,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
if n.sons[1].kind == nkIdent: if n.sons[1].kind == nkIdent:
ident = n.sons[1].ident ident = n.sons[1].ident
elif n.sons[1].kind == nkAccQuoted: elif n.sons[1].kind == nkAccQuoted:
ident = considerQuotedIdent(c.config, n.sons[1]) ident = considerQuotedIdent(c, n.sons[1])
if ident != nil: if ident != nil:
if m == c.module: if m == c.module:
result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config) result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config)
@ -341,12 +344,13 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
result = errorSym(c, n.sons[1]) result = errorSym(c, n.sons[1])
else: else:
result = nil result = nil
if result != nil and result.kind == skStub: loadStub(result) when false:
if result != nil and result.kind == skStub: loadStub(result)
proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
case n.kind case n.kind
of nkIdent, nkAccQuoted: of nkIdent, nkAccQuoted:
var ident = considerQuotedIdent(c.config, n) var ident = considerQuotedIdent(c, n)
o.scope = c.currentScope o.scope = c.currentScope
o.mode = oimNoQualifier o.mode = oimNoQualifier
while true: while true:
@ -367,7 +371,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if n.sons[1].kind == nkIdent: if n.sons[1].kind == nkIdent:
ident = n.sons[1].ident ident = n.sons[1].ident
elif n.sons[1].kind == nkAccQuoted: elif n.sons[1].kind == nkAccQuoted:
ident = considerQuotedIdent(c.config, n.sons[1], n) ident = considerQuotedIdent(c, n.sons[1], n)
if ident != nil: if ident != nil:
if o.m == c.module: if o.m == c.module:
# a module may access its private members: # a module may access its private members:
@ -390,7 +394,8 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.inSymChoice = initIntSet() o.inSymChoice = initIntSet()
incl(o.inSymChoice, result.id) incl(o.inSymChoice, result.id)
else: discard else: discard
if result != nil and result.kind == skStub: loadStub(result) when false:
if result != nil and result.kind == skStub: loadStub(result)
proc lastOverloadScope*(o: TOverloadIter): int = proc lastOverloadScope*(o: TOverloadIter): int =
case o.mode case o.mode
@ -441,7 +446,8 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = firstIdentExcluding(o.it, o.scope.symbols, result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config) n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
if result != nil and result.kind == skStub: loadStub(result) when false:
if result != nil and result.kind == skStub: loadStub(result)
proc pickSym*(c: PContext, n: PNode; kinds: set[TSymKind]; proc pickSym*(c: PContext, n: PNode; kinds: set[TSymKind];
flags: TSymFlags = {}): PSym = flags: TSymFlags = {}): PSym =

View file

@ -12,7 +12,8 @@
const const
genPrefix* = ":tmp" # prefix for generated names genPrefix* = ":tmp" # prefix for generated names
import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs,
lineinfos
from trees import getMagic from trees import getMagic
proc newDeref*(n: PNode): PNode {.inline.} = proc newDeref*(n: PNode): PNode {.inline.} =
@ -30,8 +31,8 @@ proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode =
proc addVar*(father, v: PNode) = proc addVar*(father, v: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info, 3) var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart.sons[0] = v vpart.sons[0] = v
vpart.sons[1] = ast.emptyNode vpart.sons[1] = newNodeI(nkEmpty, v.info)
vpart.sons[2] = ast.emptyNode vpart.sons[2] = vpart[1]
addSon(father, vpart) addSon(father, vpart)
proc newAsgnStmt(le, ri: PNode): PNode = proc newAsgnStmt(le, ri: PNode): PNode =
@ -49,7 +50,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let value = n.lastSon let value = n.lastSon
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info, g.config.options) var temp = newSym(skTemp, getIdent(g.cache, genPrefix), owner, value.info, g.config.options)
temp.typ = skipTypes(value.typ, abstractInst) temp.typ = skipTypes(value.typ, abstractInst)
incl(temp.flags, sfFromGeneric) incl(temp.flags, sfFromGeneric)
@ -73,17 +74,17 @@ proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
proc newTryFinally*(body, final: PNode): PNode = proc newTryFinally*(body, final: PNode): PNode =
result = newTree(nkTryStmt, body, newTree(nkFinally, final)) result = newTree(nkTryStmt, body, newTree(nkFinally, final))
proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode = proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let value = n.lastSon let value = n.lastSon
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
var temp = newSym(skLet, getIdent("_"), owner, value.info, owner.options) var temp = newSym(skLet, getIdent(g.cache, "_"), owner, value.info, owner.options)
var v = newNodeI(nkLetSection, value.info) var v = newNodeI(nkLetSection, value.info)
let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info) let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3) var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
vpart.sons[0] = tempAsNode vpart.sons[0] = tempAsNode
vpart.sons[1] = ast.emptyNode vpart.sons[1] = newNodeI(nkEmpty, value.info)
vpart.sons[2] = value vpart.sons[2] = value
addSon(v, vpart) addSon(v, vpart)
result.add(v) result.add(v)
@ -92,10 +93,10 @@ proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode =
for i in 0 .. lhs.len-1: for i in 0 .. lhs.len-1:
result.add newAsgnStmt(lhs.sons[i], newTupleAccessRaw(tempAsNode, i)) result.add newAsgnStmt(lhs.sons[i], newTupleAccessRaw(tempAsNode, i))
proc lowerSwap*(n: PNode; owner: PSym): PNode = proc lowerSwap*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
# note: cannot use 'skTemp' here cause we really need the copy for the VM :-( # note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
var temp = newSym(skVar, getIdent(genPrefix), owner, n.info, owner.options) var temp = newSym(skVar, getIdent(g.cache, genPrefix), owner, n.info, owner.options)
temp.typ = n.sons[1].typ temp.typ = n.sons[1].typ
incl(temp.flags, sfFromGeneric) incl(temp.flags, sfFromGeneric)
@ -104,7 +105,7 @@ proc lowerSwap*(n: PNode; owner: PSym): PNode =
var vpart = newNodeI(nkIdentDefs, v.info, 3) var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart.sons[0] = tempAsNode vpart.sons[0] = tempAsNode
vpart.sons[1] = ast.emptyNode vpart.sons[1] = newNodeI(nkEmpty, v.info)
vpart.sons[2] = n[1] vpart.sons[2] = n[1]
addSon(v, vpart) addSon(v, vpart)
@ -120,7 +121,7 @@ proc createObj*(g: ModuleGraph; owner: PSym, info: TLineInfo; final=true): PType
else: else:
rawAddSon(result, getCompilerProc(g, "RootObj").typ) rawAddSon(result, getCompilerProc(g, "RootObj").typ)
result.n = newNodeI(nkRecList, info) result.n = newNodeI(nkRecList, info)
let s = newSym(skType, getIdent("Env_" & info.toFilename), let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info)),
owner, info, owner.options) owner, info, owner.options)
incl s.flags, sfAnon incl s.flags, sfAnon
s.typ = result s.typ = result
@ -171,10 +172,10 @@ proc lookupInRecord(n: PNode, id: int): PSym =
if n.sym.id == -abs(id): result = n.sym if n.sym.id == -abs(id): result = n.sym
else: discard else: discard
proc addField*(obj: PType; s: PSym) = proc addField*(obj: PType; s: PSym; cache: IdentCache) =
# because of 'gensym' support, we have to mangle the name with its ID. # because of 'gensym' support, we have to mangle the name with its ID.
# This is hacky but the clean solution is much more complex than it looks. # This is hacky but the clean solution is much more complex than it looks.
var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info, var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), s.owner, s.info,
s.options) s.options)
field.id = -s.id field.id = -s.id
let t = skipIntLit(s.typ) let t = skipIntLit(s.typ)
@ -183,10 +184,10 @@ proc addField*(obj: PType; s: PSym) =
field.position = sonsLen(obj.n) field.position = sonsLen(obj.n)
addSon(obj.n, newSymNode(field)) addSon(obj.n, newSymNode(field))
proc addUniqueField*(obj: PType; s: PSym): PSym {.discardable.} = proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache): PSym {.discardable.} =
result = lookupInRecord(obj.n, s.id) result = lookupInRecord(obj.n, s.id)
if result == nil: if result == nil:
var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info, var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), s.owner, s.info,
s.options) s.options)
field.id = -s.id field.id = -s.id
let t = skipIntLit(s.typ) let t = skipIntLit(s.typ)
@ -227,13 +228,13 @@ proc indirectAccess*(a: PNode, b: int, info: TLineInfo): PNode =
addSon(result, newSymNode(field)) addSon(result, newSymNode(field))
result.typ = field.typ result.typ = field.typ
proc indirectAccess(a: PNode, b: string, info: TLineInfo): PNode = proc indirectAccess(a: PNode, b: string, info: TLineInfo; cache: IdentCache): PNode =
# returns a[].b as a node # returns a[].b as a node
var deref = newNodeI(nkHiddenDeref, info) var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.skipTypes(abstractInst).sons[0] deref.typ = a.typ.skipTypes(abstractInst).sons[0]
var t = deref.typ.skipTypes(abstractInst) var t = deref.typ.skipTypes(abstractInst)
var field: PSym var field: PSym
let bb = getIdent(b) let bb = getIdent(cache, b)
while true: while true:
assert t.kind == tyObject assert t.kind == tyObject
field = getSymFromList(t.n, bb) field = getSymFromList(t.n, bb)
@ -337,15 +338,15 @@ proc typeNeedsNoDeepCopy(t: PType): bool =
proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType; proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType;
v: PNode; useShallowCopy=false): PSym = v: PNode; useShallowCopy=false): PSym =
result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info, result = newSym(skTemp, getIdent(g.cache, genPrefix), owner, varSection.info,
owner.options) owner.options)
result.typ = typ result.typ = typ
incl(result.flags, sfFromGeneric) incl(result.flags, sfFromGeneric)
var vpart = newNodeI(nkIdentDefs, varSection.info, 3) var vpart = newNodeI(nkIdentDefs, varSection.info, 3)
vpart.sons[0] = newSymNode(result) vpart.sons[0] = newSymNode(result)
vpart.sons[1] = ast.emptyNode vpart.sons[1] = newNodeI(nkEmpty, varSection.info)
vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode vpart.sons[2] = if varInit.isNil: v else: vpart[1]
varSection.add vpart varSection.add vpart
if varInit != nil: if varInit != nil:
if useShallowCopy and typeNeedsNoDeepCopy(typ): if useShallowCopy and typeNeedsNoDeepCopy(typ):
@ -410,7 +411,7 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
# generate: # generate:
# fv.owner = threadParam # fv.owner = threadParam
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
"owner", fv.info), threadParam.newSymNode) "owner", fv.info, g.cache), threadParam.newSymNode)
body.add callCodegenProc(g, "nimArgsPassingDone", threadParam.newSymNode) body.add callCodegenProc(g, "nimArgsPassingDone", threadParam.newSymNode)
if spawnKind == srByVar: if spawnKind == srByVar:
@ -421,12 +422,12 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
localError(g.config, f.info, "cannot create a flowVar of type: " & localError(g.config, f.info, "cannot create a flowVar of type: " &
typeToString(fv.typ.sons[1])) typeToString(fv.typ.sons[1]))
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
if fk == fvGC: "data" else: "blob", fv.info), call) if fk == fvGC: "data" else: "blob", fv.info, g.cache), call)
if fk == fvGC: if fk == fvGC:
let incRefCall = newNodeI(nkCall, fv.info, 2) let incRefCall = newNodeI(nkCall, fv.info, 2)
incRefCall.sons[0] = newSymNode(getSysMagic(g, fv.info, "GCref", mGCref)) incRefCall.sons[0] = newSymNode(getSysMagic(g, fv.info, "GCref", mGCref))
incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode, incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode,
"data", fv.info) "data", fv.info, g.cache)
body.add incRefCall body.add incRefCall
if barrier == nil: if barrier == nil:
# by now 'fv' is shared and thus might have beeen overwritten! we need # by now 'fv' is shared and thus might have beeen overwritten! we need
@ -438,7 +439,7 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
body.add callCodegenProc(g, "barrierLeave", threadLocalBarrier.newSymNode) body.add callCodegenProc(g, "barrierLeave", threadLocalBarrier.newSymNode)
var params = newNodeI(nkFormalParams, f.info) var params = newNodeI(nkFormalParams, f.info)
params.add emptyNode params.add newNodeI(nkEmpty, f.info)
params.add threadParam.newSymNode params.add threadParam.newSymNode
params.add argsParam.newSymNode params.add argsParam.newSymNode
@ -452,14 +453,18 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
t.n.add argsParam.newSymNode t.n.add argsParam.newSymNode
let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper" let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper"
result = newSym(skProc, getIdent(name), argsParam.owner, f.info, result = newSym(skProc, getIdent(g.cache, name), argsParam.owner, f.info,
argsParam.options) argsParam.options)
result.ast = newProcNode(nkProcDef, f.info, body, params, newSymNode(result)) let emptyNode = newNodeI(nkEmpty, f.info)
result.ast = newProcNode(nkProcDef, f.info, body = body,
params = params, name = newSymNode(result), pattern = emptyNode,
genericParams = emptyNode, pragmas = emptyNode,
exceptions = emptyNode)
result.typ = t result.typ = t
proc createCastExpr(argsParam: PSym; objType: PType): PNode = proc createCastExpr(argsParam: PSym; objType: PType): PNode =
result = newNodeI(nkCast, argsParam.info) result = newNodeI(nkCast, argsParam.info)
result.add emptyNode result.add newNodeI(nkEmpty, argsParam.info)
result.add newSymNode(argsParam) result.add newSymNode(argsParam)
result.typ = newType(tyPtr, objType.owner) result.typ = newType(tyPtr, objType.owner)
result.typ.rawAddSon(objType) result.typ.rawAddSon(objType)
@ -468,7 +473,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchOb
castExpr, call, castExpr, call,
varSection, varInit, result: PNode) = varSection, varInit, result: PNode) =
let formals = n[0].typ.n let formals = n[0].typ.n
let tmpName = getIdent(genPrefix) let tmpName = getIdent(g.cache, genPrefix)
for i in 1 ..< n.len: for i in 1 ..< n.len:
# we pick n's type here, which hopefully is 'tyArray' and not # we pick n's type here, which hopefully is 'tyArray' and not
# 'tyOpenArray': # 'tyOpenArray':
@ -481,7 +486,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchOb
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options) var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options)
field.typ = argType field.typ = argType
objType.addField(field) objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i]) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
let temp = addLocalVar(g, varSection, varInit, objType.owner, argType, let temp = addLocalVar(g, varSection, varInit, objType.owner, argType,
@ -511,7 +516,7 @@ proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
proc genHigh*(g: ModuleGraph; n: PNode): PNode = proc genHigh*(g: ModuleGraph; n: PNode): PNode =
if skipTypes(n.typ, abstractVar).kind == tyArray: if skipTypes(n.typ, abstractVar).kind == tyArray:
result = newIntLit(g, n.info, lastOrd(skipTypes(n.typ, abstractVar))) result = newIntLit(g, n.info, lastOrd(g.config, skipTypes(n.typ, abstractVar)))
else: else:
result = newNodeI(nkCall, n.info, 2) result = newNodeI(nkCall, n.info, 2)
result.typ = getSysType(g, n.info, tyInt) result.typ = getSysType(g, n.info, tyInt)
@ -522,7 +527,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
castExpr, call, castExpr, call,
varSection, varInit, result: PNode) = varSection, varInit, result: PNode) =
let formals = n[0].typ.n let formals = n[0].typ.n
let tmpName = getIdent(genPrefix) let tmpName = getIdent(g.cache, genPrefix)
# we need to copy the foreign scratch object fields into local variables # we need to copy the foreign scratch object fields into local variables
# for correctness: These are called 'threadLocal' here. # for correctness: These are called 'threadLocal' here.
for i in 1 ..< n.len: for i in 1 ..< n.len:
@ -543,17 +548,17 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
slice.sons[0].typ = getSysType(g, n.info, tyInt) # fake type slice.sons[0].typ = getSysType(g, n.info, tyInt) # fake type
var fieldB = newSym(skField, tmpName, objType.owner, n.info, g.config.options) var fieldB = newSym(skField, tmpName, objType.owner, n.info, g.config.options)
fieldB.typ = getSysType(g, n.info, tyInt) fieldB.typ = getSysType(g, n.info, tyInt)
objType.addField(fieldB) objType.addField(fieldB, g.cache)
if getMagic(n) == mSlice: if getMagic(n) == mSlice:
let a = genAddrOf(n[1]) let a = genAddrOf(n[1])
field.typ = a.typ field.typ = a.typ
objType.addField(field) objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
var fieldA = newSym(skField, tmpName, objType.owner, n.info, g.config.options) var fieldA = newSym(skField, tmpName, objType.owner, n.info, g.config.options)
fieldA.typ = getSysType(g, n.info, tyInt) fieldA.typ = getSysType(g, n.info, tyInt)
objType.addField(fieldA) objType.addField(fieldA, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2]) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2])
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3]) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
@ -564,7 +569,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
else: else:
let a = genAddrOf(n) let a = genAddrOf(n)
field.typ = a.typ field.typ = a.typ
objType.addField(field) objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n)) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n))
@ -577,12 +582,12 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
useShallowCopy=true) useShallowCopy=true)
slice.sons[3] = threadLocal.newSymNode slice.sons[3] = threadLocal.newSymNode
call.add slice call.add slice
elif (let size = computeSize(argType); size < 0 or size > 16) and elif (let size = computeSize(g.config, argType); size < 0 or size > 16) and
n.getRoot != nil: n.getRoot != nil:
# it is more efficient to pass a pointer instead: # it is more efficient to pass a pointer instead:
let a = genAddrOf(n) let a = genAddrOf(n)
field.typ = a.typ field.typ = a.typ
objType.addField(field) objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
let threadLocal = addLocalVar(g, varSection,nil, objType.owner, field.typ, let threadLocal = addLocalVar(g, varSection,nil, objType.owner, field.typ,
indirectAccess(castExpr, field, n.info), indirectAccess(castExpr, field, n.info),
@ -591,7 +596,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
else: else:
# boring case # boring case
field.typ = argType field.typ = argType
objType.addField(field) objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
let threadLocal = addLocalVar(g, varSection, varInit, let threadLocal = addLocalVar(g, varSection, varInit,
objType.owner, field.typ, objType.owner, field.typ,
@ -623,8 +628,8 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P
if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}: if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}:
localError(g.config, n.info, "'spawn' takes a GC safe call expression") localError(g.config, n.info, "'spawn' takes a GC safe call expression")
var var
threadParam = newSym(skParam, getIdent"thread", owner, n.info, g.config.options) threadParam = newSym(skParam, getIdent(g.cache, "thread"), owner, n.info, g.config.options)
argsParam = newSym(skParam, getIdent"args", owner, n.info, g.config.options) argsParam = newSym(skParam, getIdent(g.cache, "args"), owner, n.info, g.config.options)
block: block:
let ptrType = getSysType(g, n.info, tyPointer) let ptrType = getSysType(g, n.info, tyPointer)
threadParam.typ = ptrType threadParam.typ = ptrType
@ -635,7 +640,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P
incl(objType.flags, tfFinal) incl(objType.flags, tfFinal)
let castExpr = createCastExpr(argsParam, objType) let castExpr = createCastExpr(argsParam, objType)
var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info, g.config.options) var scratchObj = newSym(skVar, getIdent(g.cache, "scratch"), owner, n.info, g.config.options)
block: block:
scratchObj.typ = objType scratchObj.typ = objType
incl(scratchObj.flags, sfFromGeneric) incl(scratchObj.flags, sfFromGeneric)
@ -653,9 +658,9 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P
skFunc, skMethod, skConverter}): skFunc, skMethod, skConverter}):
# for indirect calls we pass the function pointer in the scratchObj # for indirect calls we pass the function pointer in the scratchObj
var argType = n[0].typ.skipTypes(abstractInst) var argType = n[0].typ.skipTypes(abstractInst)
var field = newSym(skField, getIdent"fn", owner, n.info, g.config.options) var field = newSym(skField, getIdent(g.cache, "fn"), owner, n.info, g.config.options)
field.typ = argType field.typ = argType
objType.addField(field) objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0]) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0])
fn = indirectAccess(castExpr, field, n.info) fn = indirectAccess(castExpr, field, n.info)
elif fn.kind == nkSym and fn.sym.kind == skIterator: elif fn.kind == nkSym and fn.sym.kind == skIterator:
@ -677,17 +682,17 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P
if barrier != nil: if barrier != nil:
let typ = newType(tyPtr, owner) let typ = newType(tyPtr, owner)
typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ) typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ)
var field = newSym(skField, getIdent"barrier", owner, n.info, g.config.options) var field = newSym(skField, getIdent(g.cache, "barrier"), owner, n.info, g.config.options)
field.typ = typ field.typ = typ
objType.addField(field) objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier)
barrierAsExpr = indirectAccess(castExpr, field, n.info) barrierAsExpr = indirectAccess(castExpr, field, n.info)
var fvField, fvAsExpr: PNode = nil var fvField, fvAsExpr: PNode = nil
if spawnKind == srFlowVar: if spawnKind == srFlowVar:
var field = newSym(skField, getIdent"fv", owner, n.info, g.config.options) var field = newSym(skField, getIdent(g.cache, "fv"), owner, n.info, g.config.options)
field.typ = retType field.typ = retType
objType.addField(field) objType.addField(field, g.cache)
fvField = newDotExpr(scratchObj, field) fvField = newDotExpr(scratchObj, field)
fvAsExpr = indirectAccess(castExpr, field, n.info) fvAsExpr = indirectAccess(castExpr, field, n.info)
# create flowVar: # create flowVar:
@ -696,10 +701,10 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P
result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField) result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField)
elif spawnKind == srByVar: elif spawnKind == srByVar:
var field = newSym(skField, getIdent"fv", owner, n.info, g.config.options) var field = newSym(skField, getIdent(g.cache, "fv"), owner, n.info, g.config.options)
field.typ = newType(tyPtr, objType.owner) field.typ = newType(tyPtr, objType.owner)
field.typ.rawAddSon(retType) field.typ.rawAddSon(retType)
objType.addField(field) objType.addField(field, g.cache)
fvAsExpr = indirectAccess(castExpr, field, n.info) fvAsExpr = indirectAccess(castExpr, field, n.info)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest)) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest))

View file

@ -0,0 +1,79 @@
#
#
# The Nim Compiler
# (c) Copyright 2018 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements helpers for the macro cache.
import lineinfos, ast, modulegraphs, vmdef, magicsys
proc recordInc*(c: PCtx; info: TLineInfo; key: string; by: BiggestInt) =
var recorded = newNodeI(nkCommentStmt, info)
recorded.add newStrNode("inc", info)
recorded.add newStrNode(key, info)
recorded.add newIntNode(nkIntLit, by)
c.graph.recordStmt(c.graph, c.module, recorded)
proc recordPut*(c: PCtx; info: TLineInfo; key: string; k: string; val: PNode) =
var recorded = newNodeI(nkCommentStmt, info)
recorded.add newStrNode("put", info)
recorded.add newStrNode(key, info)
recorded.add newStrNode(k, info)
recorded.add copyTree(val)
c.graph.recordStmt(c.graph, c.module, recorded)
proc recordAdd*(c: PCtx; info: TLineInfo; key: string; val: PNode) =
var recorded = newNodeI(nkCommentStmt, info)
recorded.add newStrNode("add", info)
recorded.add newStrNode(key, info)
recorded.add copyTree(val)
c.graph.recordStmt(c.graph, c.module, recorded)
proc recordIncl*(c: PCtx; info: TLineInfo; key: string; val: PNode) =
var recorded = newNodeI(nkCommentStmt, info)
recorded.add newStrNode("incl", info)
recorded.add newStrNode(key, info)
recorded.add copyTree(val)
c.graph.recordStmt(c.graph, c.module, recorded)
when false:
proc genCall3(g: ModuleGraph; m: TMagic; s: string; a, b, c: PNode): PNode =
newTree(nkStaticStmt, newTree(nkCall, createMagic(g, s, m).newSymNode, a, b, c))
proc genCall2(g: ModuleGraph; m: TMagic; s: string; a, b: PNode): PNode =
newTree(nkStaticStmt, newTree(nkCall, createMagic(g, s, m).newSymNode, a, b))
template nodeFrom(s: string): PNode =
var res = newStrNode(s, info)
res.typ = getSysType(g, info, tyString)
res
template nodeFrom(i: BiggestInt): PNode =
var res = newIntNode(i, info)
res.typ = getSysType(g, info, tyInt)
res
template nodeFrom(n: PNode): PNode = copyTree(n)
template record(call) =
g.recordStmt(g, c.module, call)
proc recordInc*(c: PCtx; info: TLineInfo; key: string; by: BiggestInt) =
let g = c.graph
record genCall2(mNccInc, "inc", nodeFrom key, nodeFrom by)
proc recordPut*(c: PCtx; info: TLineInfo; key: string; k: string; val: PNode) =
let g = c.graph
record genCall3(mNctPut, "[]=", nodeFrom key, nodeFrom k, nodeFrom val)
proc recordAdd*(c: PCtx; info: TLineInfo; key: string; val: PNode) =
let g = c.graph
record genCall2(mNcsAdd, "add", nodeFrom key, nodeFrom val)
proc recordIncl*(c: PCtx; info: TLineInfo; key: string; val: PNode) =
let g = c.graph
record genCall2(mNcsIncl, "incl", nodeFrom key, nodeFrom val)

View file

@ -10,8 +10,8 @@
# Built-in types and compilerprocs are registered here. # Built-in types and compilerprocs are registered here.
import import
ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread, ast, astalgo, hashes, msgs, platform, nversion, times, idents,
modulegraphs modulegraphs, lineinfos
export createMagic export createMagic
@ -26,30 +26,18 @@ proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType =
result.align = size.int16 result.align = size.int16
proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym = proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
result = strTableGet(g.systemModule.tab, getIdent(name)) result = strTableGet(g.systemModule.tab, getIdent(g.cache, name))
if result == nil: if result == nil:
localError(g.config, info, "system module needs: " & name) localError(g.config, info, "system module needs: " & name)
result = newSym(skError, getIdent(name), g.systemModule, g.systemModule.info, {}) result = newSym(skError, getIdent(g.cache, name), g.systemModule, g.systemModule.info, {})
result.typ = newType(tyError, g.systemModule) result.typ = newType(tyError, g.systemModule)
if result.kind == skStub: loadStub(result)
if result.kind == skAlias: result = result.owner if result.kind == skAlias: result = result.owner
when false:
proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym =
result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
result.magic = m
when false:
let
opNot* = createMagic("not", mNot)
opContains* = createMagic("contains", mInSet)
proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym = proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
var ti: TIdentIter var ti: TIdentIter
let id = getIdent(name) let id = getIdent(g.cache, name)
var r = initIdentIter(ti, g.systemModule.tab, id) var r = initIdentIter(ti, g.systemModule.tab, id)
while r != nil: while r != nil:
if r.kind == skStub: loadStub(r)
if r.magic == m: if r.magic == m:
# prefer the tyInt variant: # prefer the tyInt variant:
if r.typ.sons[0] != nil and r.typ.sons[0].kind == tyInt: return r if r.typ.sons[0] != nil and r.typ.sons[0].kind == tyInt: return r
@ -87,7 +75,7 @@ proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType =
of tyString: result = sysTypeFromName("string") of tyString: result = sysTypeFromName("string")
of tyCString: result = sysTypeFromName("cstring") of tyCString: result = sysTypeFromName("cstring")
of tyPointer: result = sysTypeFromName("pointer") of tyPointer: result = sysTypeFromName("pointer")
of tyNil: result = newSysType(g, tyNil, ptrSize) of tyNil: result = newSysType(g, tyNil, g.config.target.ptrSize)
else: internalError(g.config, "request for typekind: " & $kind) else: internalError(g.config, "request for typekind: " & $kind)
g.sysTypes[kind] = result g.sysTypes[kind] = result
if result.kind != kind: if result.kind != kind:
@ -139,7 +127,7 @@ proc addSonSkipIntLit*(father, son: PType) =
proc setIntLitType*(g: ModuleGraph; result: PNode) = proc setIntLitType*(g: ModuleGraph; result: PNode) =
let i = result.intVal let i = result.intVal
case platform.intSize case g.config.target.intSize
of 8: result.typ = getIntLitType(g, result) of 8: result.typ = getIntLitType(g, result)
of 4: of 4:
if i >= low(int32) and i <= high(int32): if i >= low(int32) and i <= high(int32):
@ -167,15 +155,8 @@ proc setIntLitType*(g: ModuleGraph; result: PNode) =
internalError(g.config, result.info, "invalid int size") internalError(g.config, result.info, "invalid int size")
proc getCompilerProc*(g: ModuleGraph; name: string): PSym = proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
let ident = getIdent(name) let ident = getIdent(g.cache, name)
result = strTableGet(g.compilerprocs, ident) result = strTableGet(g.compilerprocs, ident)
when false:
if result == nil:
result = strTableGet(g.rodCompilerprocs, ident)
if result != nil:
strTableAdd(g.compilerprocs, result)
if result.kind == skStub: loadStub(result)
if result.kind == skAlias: result = result.owner
proc registerCompilerProc*(g: ModuleGraph; s: PSym) = proc registerCompilerProc*(g: ModuleGraph; s: PSym) =
strTableAdd(g.compilerprocs, s) strTableAdd(g.compilerprocs, s)
@ -187,9 +168,9 @@ proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) =
strTableAdd(g.exposed, s) strTableAdd(g.exposed, s)
else: else:
localError(g.config, s.info, localError(g.config, s.info,
"symbol conflicts with other .exportNims symbol at: " & $conflict.info) "symbol conflicts with other .exportNims symbol at: " & g.config$conflict.info)
proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym = proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
strTableGet(g.exposed, getIdent(name)) strTableGet(g.exposed, getIdent(g.cache, name))
proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed) proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)

View file

@ -9,74 +9,68 @@
# implements the command dispatcher and several commands # implements the command dispatcher and several commands
when not defined(nimcore):
{.error: "nimcore MUST be defined for Nim's core tooling".}
import import
llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs, llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
os, condsyms, rodread, rodwrite, times, os, condsyms, times,
wordrecg, sem, semdata, idents, passes, docgen, extccomp, wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, jsgen, json, nversion, cgen, jsgen, json, nversion,
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen, platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
docgen2, service, parser, modules, ccgutils, sigmatch, ropes, docgen2, parser, modules, ccgutils, sigmatch, ropes,
modulegraphs, tables, rod, configuration modulegraphs, tables, rod, lineinfos
from magicsys import resetSysTypes from magicsys import resetSysTypes
proc rodPass(g: ModuleGraph) = proc codegenPass(g: ModuleGraph) =
if g.config.symbolFiles in {enabledSf, writeOnlySf}: registerPass g, cgenPass
registerPass(rodwritePass)
proc codegenPass = proc semanticPasses(g: ModuleGraph) =
registerPass cgenPass registerPass g, verbosePass
registerPass g, semPass
proc semanticPasses =
registerPass verbosePass
registerPass semPass
proc writeDepsFile(g: ModuleGraph; project: string) = proc writeDepsFile(g: ModuleGraph; project: string) =
let f = open(changeFileExt(project, "deps"), fmWrite) let f = open(changeFileExt(project, "deps"), fmWrite)
for m in g.modules: for m in g.modules:
if m != nil: if m != nil:
f.writeLine(toFullPath(m.position.FileIndex)) f.writeLine(toFullPath(g.config, m.position.FileIndex))
for k in g.inclToMod.keys: for k in g.inclToMod.keys:
if g.getModule(k).isNil: # don't repeat includes which are also modules if g.getModule(k).isNil: # don't repeat includes which are also modules
f.writeLine(k.toFullPath) f.writeLine(toFullPath(g.config, k))
f.close() f.close()
proc commandGenDepend(graph: ModuleGraph; cache: IdentCache) = proc commandGenDepend(graph: ModuleGraph) =
semanticPasses() semanticPasses(graph)
registerPass(gendependPass) registerPass(graph, gendependPass)
#registerPass(cleanupPass) compileProject(graph)
compileProject(graph, cache)
let project = graph.config.projectFull let project = graph.config.projectFull
writeDepsFile(graph, project) writeDepsFile(graph, project)
generateDot(project) generateDot(graph, project)
execExternalProgram(graph.config, "dot -Tpng -o" & changeFileExt(project, "png") & execExternalProgram(graph.config, "dot -Tpng -o" & changeFileExt(project, "png") &
' ' & changeFileExt(project, "dot")) ' ' & changeFileExt(project, "dot"))
proc commandCheck(graph: ModuleGraph; cache: IdentCache) = proc commandCheck(graph: ModuleGraph) =
graph.config.errorMax = high(int) # do not stop after first error graph.config.errorMax = high(int) # do not stop after first error
defineSymbol(graph.config.symbols, "nimcheck") defineSymbol(graph.config.symbols, "nimcheck")
semanticPasses() # use an empty backend for semantic checking only semanticPasses(graph) # use an empty backend for semantic checking only
rodPass(graph) compileProject(graph)
compileProject(graph, cache)
proc commandDoc2(graph: ModuleGraph; cache: IdentCache; json: bool) = proc commandDoc2(graph: ModuleGraph; json: bool) =
graph.config.errorMax = high(int) # do not stop after first error graph.config.errorMax = high(int) # do not stop after first error
semanticPasses() semanticPasses(graph)
if json: registerPass(docgen2JsonPass) if json: registerPass(graph, docgen2JsonPass)
else: registerPass(docgen2Pass) else: registerPass(graph, docgen2Pass)
#registerPass(cleanupPass()) compileProject(graph)
compileProject(graph, cache)
finishDoc2Pass(graph.config.projectName) finishDoc2Pass(graph.config.projectName)
proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) = proc commandCompileToC(graph: ModuleGraph) =
let conf = graph.config let conf = graph.config
extccomp.initVars(conf) extccomp.initVars(conf)
semanticPasses() semanticPasses(graph)
registerPass(cgenPass) registerPass(graph, cgenPass)
rodPass(graph)
#registerPass(cleanupPass())
compileProject(graph, cache) compileProject(graph)
cgenWriteModules(graph.backend, conf) cgenWriteModules(graph.backend, conf)
if conf.cmd != cmdRun: if conf.cmd != cmdRun:
let proj = changeFileExt(conf.projectFull, "") let proj = changeFileExt(conf.projectFull, "")
@ -85,53 +79,51 @@ proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
if optGenScript in graph.config.globalOptions: if optGenScript in graph.config.globalOptions:
writeDepsFile(graph, toGeneratedFile(conf, proj, "")) writeDepsFile(graph, toGeneratedFile(conf, proj, ""))
proc commandJsonScript(graph: ModuleGraph; cache: IdentCache) = proc commandJsonScript(graph: ModuleGraph) =
let proj = changeFileExt(graph.config.projectFull, "") let proj = changeFileExt(graph.config.projectFull, "")
extccomp.runJsonBuildInstructions(graph.config, proj) extccomp.runJsonBuildInstructions(graph.config, proj)
proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) = proc commandCompileToJS(graph: ModuleGraph) =
#incl(gGlobalOptions, optSafeCode) #incl(gGlobalOptions, optSafeCode)
setTarget(osJS, cpuJS) setTarget(graph.config.target, osJS, cpuJS)
#initDefines() #initDefines()
defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility
defineSymbol(graph.config.symbols, "js") defineSymbol(graph.config.symbols, "js")
semanticPasses() semanticPasses(graph)
registerPass(JSgenPass) registerPass(graph, JSgenPass)
compileProject(graph, cache) compileProject(graph)
proc interactivePasses(graph: ModuleGraph; cache: IdentCache) = proc interactivePasses(graph: ModuleGraph) =
#incl(gGlobalOptions, optSafeCode)
#setTarget(osNimrodVM, cpuNimrodVM)
initDefines(graph.config.symbols) initDefines(graph.config.symbols)
defineSymbol(graph.config.symbols, "nimscript") defineSymbol(graph.config.symbols, "nimscript")
when hasFFI: defineSymbol(graph.config.symbols, "nimffi") when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
registerPass(verbosePass) registerPass(graph, verbosePass)
registerPass(semPass) registerPass(graph, semPass)
registerPass(evalPass) registerPass(graph, evalPass)
proc commandInteractive(graph: ModuleGraph; cache: IdentCache) = proc commandInteractive(graph: ModuleGraph) =
graph.config.errorMax = high(int) # do not stop after first error graph.config.errorMax = high(int) # do not stop after first error
interactivePasses(graph, cache) interactivePasses(graph)
compileSystemModule(graph, cache) compileSystemModule(graph)
if graph.config.commandArgs.len > 0: if graph.config.commandArgs.len > 0:
discard graph.compileModule(fileInfoIdx(graph.config, graph.config.projectFull), cache, {}) discard graph.compileModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
else: else:
var m = graph.makeStdinModule() var m = graph.makeStdinModule()
incl(m.flags, sfMainModule) incl(m.flags, sfMainModule)
processModule(graph, m, llStreamOpenStdIn(), nil, cache) processModule(graph, m, llStreamOpenStdIn())
const evalPasses = [verbosePass, semPass, evalPass] const evalPasses = [verbosePass, semPass, evalPass]
proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym; cache: IdentCache) = proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym) =
carryPasses(graph, nodes, module, cache, evalPasses) carryPasses(graph, nodes, module, evalPasses)
proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) = proc commandEval(graph: ModuleGraph; exp: string) =
if graph.systemModule == nil: if graph.systemModule == nil:
interactivePasses(graph, cache) interactivePasses(graph)
compileSystemModule(graph, cache) compileSystemModule(graph)
let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
evalNim(graph, echoExp.parseString(cache, graph.config), evalNim(graph, echoExp.parseString(graph.cache, graph.config),
makeStdinModule(graph), cache) makeStdinModule(graph))
proc commandScan(cache: IdentCache, config: ConfigRef) = proc commandScan(cache: IdentCache, config: ConfigRef) =
var f = addFileExt(mainCommandArg(config), NimExt) var f = addFileExt(mainCommandArg(config), NimExt)
@ -153,12 +145,13 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
const const
PrintRopeCacheStats = false PrintRopeCacheStats = false
proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = proc mainCommand*(graph: ModuleGraph) =
let conf = graph.config let conf = graph.config
let cache = graph.cache
setupModuleCache() setupModuleCache(graph)
# In "nim serve" scenario, each command must reset the registered passes # In "nim serve" scenario, each command must reset the registered passes
clearPasses() clearPasses(graph)
conf.lastCmdTime = epochTime() conf.lastCmdTime = epochTime()
conf.searchPaths.add(conf.libpath) conf.searchPaths.add(conf.libpath)
setId(100) setId(100)
@ -166,69 +159,69 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
of "c", "cc", "compile", "compiletoc": of "c", "cc", "compile", "compiletoc":
# compile means compileToC currently # compile means compileToC currently
conf.cmd = cmdCompileToC conf.cmd = cmdCompileToC
commandCompileToC(graph, cache) commandCompileToC(graph)
of "cpp", "compiletocpp": of "cpp", "compiletocpp":
conf.cmd = cmdCompileToCpp conf.cmd = cmdCompileToCpp
defineSymbol(graph.config.symbols, "cpp") defineSymbol(graph.config.symbols, "cpp")
commandCompileToC(graph, cache) commandCompileToC(graph)
of "objc", "compiletooc": of "objc", "compiletooc":
conf.cmd = cmdCompileToOC conf.cmd = cmdCompileToOC
defineSymbol(graph.config.symbols, "objc") defineSymbol(graph.config.symbols, "objc")
commandCompileToC(graph, cache) commandCompileToC(graph)
of "run": of "run":
conf.cmd = cmdRun conf.cmd = cmdRun
when hasTinyCBackend: when hasTinyCBackend:
extccomp.setCC("tcc") extccomp.setCC("tcc")
commandCompileToC(graph, cache) commandCompileToC(graph)
else: else:
rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc") rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc")
of "js", "compiletojs": of "js", "compiletojs":
conf.cmd = cmdCompileToJS conf.cmd = cmdCompileToJS
commandCompileToJS(graph, cache) commandCompileToJS(graph)
of "doc0": of "doc0":
wantMainModule(conf) wantMainModule(conf)
conf.cmd = cmdDoc conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf) loadConfigs(DocConfig, cache, conf)
commandDoc(conf) commandDoc(cache, conf)
of "doc2", "doc": of "doc2", "doc":
conf.cmd = cmdDoc conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf) loadConfigs(DocConfig, cache, conf)
defineSymbol(conf.symbols, "nimdoc") defineSymbol(conf.symbols, "nimdoc")
commandDoc2(graph, cache, false) commandDoc2(graph, false)
of "rst2html": of "rst2html":
conf.cmd = cmdRst2html conf.cmd = cmdRst2html
loadConfigs(DocConfig, cache, conf) loadConfigs(DocConfig, cache, conf)
commandRst2Html(conf) commandRst2Html(cache, conf)
of "rst2tex": of "rst2tex":
conf.cmd = cmdRst2tex conf.cmd = cmdRst2tex
loadConfigs(DocTexConfig, cache, conf) loadConfigs(DocTexConfig, cache, conf)
commandRst2TeX(conf) commandRst2TeX(cache, conf)
of "jsondoc0": of "jsondoc0":
wantMainModule(conf) wantMainModule(conf)
conf.cmd = cmdDoc conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf) loadConfigs(DocConfig, cache, conf)
wantMainModule(conf) wantMainModule(conf)
defineSymbol(conf.symbols, "nimdoc") defineSymbol(conf.symbols, "nimdoc")
commandJson(conf) commandJson(cache, conf)
of "jsondoc2", "jsondoc": of "jsondoc2", "jsondoc":
conf.cmd = cmdDoc conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf) loadConfigs(DocConfig, cache, conf)
wantMainModule(conf) wantMainModule(conf)
defineSymbol(conf.symbols, "nimdoc") defineSymbol(conf.symbols, "nimdoc")
commandDoc2(graph, cache, true) commandDoc2(graph, true)
of "ctags": of "ctags":
wantMainModule(conf) wantMainModule(conf)
conf.cmd = cmdDoc conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf) loadConfigs(DocConfig, cache, conf)
defineSymbol(conf.symbols, "nimdoc") defineSymbol(conf.symbols, "nimdoc")
commandTags(conf) commandTags(cache, conf)
of "buildindex": of "buildindex":
conf.cmd = cmdDoc conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf) loadConfigs(DocConfig, cache, conf)
commandBuildIndex(conf) commandBuildIndex(cache, conf)
of "gendepend": of "gendepend":
conf.cmd = cmdGenDepend conf.cmd = cmdGenDepend
commandGenDepend(graph, cache) commandGenDepend(graph)
of "dump": of "dump":
conf.cmd = cmdDump conf.cmd = cmdDump
if getConfigVar(conf, "dump.format") == "json": if getConfigVar(conf, "dump.format") == "json":
@ -257,11 +250,11 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
for it in conf.searchPaths: msgWriteln(conf, it) for it in conf.searchPaths: msgWriteln(conf, it)
of "check": of "check":
conf.cmd = cmdCheck conf.cmd = cmdCheck
commandCheck(graph, cache) commandCheck(graph)
of "parse": of "parse":
conf.cmd = cmdParse conf.cmd = cmdParse
wantMainModule(conf) wantMainModule(conf)
discard parseFile(FileIndex conf.projectMainIdx, cache, conf) discard parseFile(conf.projectMainIdx, cache, conf)
of "scan": of "scan":
conf.cmd = cmdScan conf.cmd = cmdScan
wantMainModule(conf) wantMainModule(conf)
@ -269,15 +262,15 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!") msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!")
of "secret": of "secret":
conf.cmd = cmdInteractive conf.cmd = cmdInteractive
commandInteractive(graph, cache) commandInteractive(graph)
of "e": of "e":
commandEval(graph, cache, mainCommandArg(conf)) commandEval(graph, mainCommandArg(conf))
of "nop", "help": of "nop", "help":
# prevent the "success" message: # prevent the "success" message:
conf.cmd = cmdDump conf.cmd = cmdDump
of "jsonscript": of "jsonscript":
conf.cmd = cmdJsonScript conf.cmd = cmdJsonScript
commandJsonScript(graph, cache) commandJsonScript(graph)
else: else:
rawMessage(conf, errGenerated, "invalid command: " & conf.command) rawMessage(conf, errGenerated, "invalid command: " & conf.command)
@ -302,5 +295,3 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
ffDecimal, 3) ffDecimal, 3)
resetAttributes(conf) resetAttributes(conf)
#proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache())

View file

@ -9,7 +9,7 @@
## This module implements the module graph data structure. The module graph ## This module implements the module graph data structure. The module graph
## represents a complete Nim project. Single modules can either be kept in RAM ## represents a complete Nim project. Single modules can either be kept in RAM
## or stored in a ROD file. The ROD file mechanism is not yet integrated here. ## or stored in a Sqlite database.
## ##
## The caching of modules is critical for 'nimsuggest' and is tricky to get ## The caching of modules is critical for 'nimsuggest' and is tricky to get
## right. If module E is being edited, we need autocompletion (and type ## right. If module E is being edited, we need autocompletion (and type
@ -25,7 +25,8 @@
## - Its dependent module stays the same. ## - Its dependent module stays the same.
## ##
import ast, intsets, tables, options, rod, msgs, hashes, idents import ast, intsets, tables, options, lineinfos, hashes, idents,
incremental, btrees
type type
ModuleGraph* = ref object ModuleGraph* = ref object
@ -40,16 +41,27 @@ type
# module dependencies. # module dependencies.
backend*: RootRef # minor hack so that a backend can extend this easily backend*: RootRef # minor hack so that a backend can extend this easily
config*: ConfigRef config*: ConfigRef
cache*: IdentCache
vm*: RootRef # unfortunately the 'vm' state is shared project-wise, this will
# be clarified in later compiler implementations.
doStopCompile*: proc(): bool {.closure.} doStopCompile*: proc(): bool {.closure.}
usageSym*: PSym # for nimsuggest usageSym*: PSym # for nimsuggest
owners*: seq[PSym] owners*: seq[PSym]
methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]] methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]] # needs serialization!
systemModule*: PSym systemModule*: PSym
sysTypes*: array[TTypeKind, PType] sysTypes*: array[TTypeKind, PType]
compilerprocs*: TStrTable compilerprocs*: TStrTable
exposed*: TStrTable exposed*: TStrTable
intTypeCache*: array[-5..64, PType] intTypeCache*: array[-5..64, PType]
opContains*, opNot*: PSym opContains*, opNot*: PSym
emptyNode*: PNode
incr*: IncrementalCtx
importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.}
includeFileCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PNode {.nimcall.}
recordStmt*: proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.}
cacheSeqs*: Table[string, PNode] # state that is shared to suppor the 'macrocache' API
cacheCounters*: Table[string, BiggestInt]
cacheTables*: Table[string, BTree[string, PNode]]
proc hash*(x: FileIndex): Hash {.borrow.} proc hash*(x: FileIndex): Hash {.borrow.}
@ -59,26 +71,31 @@ proc stopCompile*(g: ModuleGraph): bool {.inline.} =
result = doStopCompile != nil and doStopCompile() result = doStopCompile != nil and doStopCompile()
proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym =
result = newSym(skProc, getIdent(name), nil, unknownLineInfo(), {}) result = newSym(skProc, getIdent(g.cache, name), nil, unknownLineInfo(), {})
result.magic = m result.magic = m
proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph = proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
result = ModuleGraph() result = ModuleGraph()
initStrTable(result.packageSyms) initStrTable(result.packageSyms)
result.deps = initIntSet() result.deps = initIntSet()
result.modules = @[] result.modules = @[]
result.importStack = @[] result.importStack = @[]
result.inclToMod = initTable[FileIndex, FileIndex]() result.inclToMod = initTable[FileIndex, FileIndex]()
if config.isNil: result.config = config
result.config = newConfigRef() result.cache = cache
else:
result.config = config
result.owners = @[] result.owners = @[]
result.methods = @[] result.methods = @[]
initStrTable(result.compilerprocs) initStrTable(result.compilerprocs)
initStrTable(result.exposed) initStrTable(result.exposed)
result.opNot = createMagic(result, "not", mNot) result.opNot = createMagic(result, "not", mNot)
result.opContains = createMagic(result, "contains", mInSet) result.opContains = createMagic(result, "contains", mInSet)
result.emptyNode = newNode(nkEmpty)
init(result.incr)
result.recordStmt = proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.} =
discard
result.cacheSeqs = initTable[string, PNode]()
result.cacheCounters = initTable[string, BiggestInt]()
result.cacheTables = initTable[string, BTree[string, PNode]]()
proc resetAllModules*(g: ModuleGraph) = proc resetAllModules*(g: ModuleGraph) =
initStrTable(packageSyms) initStrTable(packageSyms)
@ -100,15 +117,15 @@ proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) = proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) =
assert m.position == m.info.fileIndex.int32 assert m.position == m.info.fileIndex.int32
addModuleDep(m.info.fileIndex, dep, isIncludeFile = false) addModuleDep(g.incr, g.config, m.info.fileIndex, dep, isIncludeFile = false)
if suggestMode: if suggestMode:
deps.incl m.position.dependsOn(dep.int) deps.incl m.position.dependsOn(dep.int)
# we compute the transitive closure later when quering the graph lazily. # we compute the transitive closure later when quering the graph lazily.
# this improve efficiency quite a lot: # this improves efficiency quite a lot:
#invalidTransitiveClosure = true #invalidTransitiveClosure = true
proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) = proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) =
addModuleDep(module, includeFile, isIncludeFile = true) addModuleDep(g.incr, g.config, module, includeFile, isIncludeFile = true)
discard hasKeyOrPut(inclToMod, includeFile, module) discard hasKeyOrPut(inclToMod, includeFile, module)
proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex = proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex =

View file

@ -7,7 +7,7 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
import ast, renderer, strutils, msgs, options, idents, os import ast, renderer, strutils, msgs, options, idents, os, lineinfos
import nimblecmd import nimblecmd
@ -120,7 +120,7 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
case n.kind case n.kind
of nkStrLit, nkRStrLit, nkTripleStrLit: of nkStrLit, nkRStrLit, nkTripleStrLit:
try: try:
result = pathSubs(conf, n.strVal, n.info.toFullPath().splitFile().dir) result = pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir)
except ValueError: except ValueError:
localError(conf, n.info, "invalid path: " & n.strVal) localError(conf, n.info, "invalid path: " & n.strVal)
result = n.strVal result = n.strVal
@ -131,7 +131,7 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
of nkInfix: of nkInfix:
let n0 = n[0] let n0 = n[0]
let n1 = n[1] let n1 = n[1]
if n0.kind == nkIdent and n0.ident.id == getIdent("as").id: if n0.kind == nkIdent and n0.ident.s == "as":
# XXX hack ahead: # XXX hack ahead:
n.kind = nkImportAs n.kind = nkImportAs
n.sons[0] = n.sons[1] n.sons[0] = n.sons[1]
@ -177,7 +177,7 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex = proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex =
# This returns the full canonical path for a given module import # This returns the full canonical path for a given module import
let modulename = getModuleName(conf, n) let modulename = getModuleName(conf, n)
let fullPath = findModule(conf, modulename, n.info.toFullPath) let fullPath = findModule(conf, modulename, toFullPath(conf, n.info))
if fullPath.len == 0: if fullPath.len == 0:
if doLocalError: if doLocalError:
let m = if modulename.len > 0: modulename else: $n let m = if modulename.len > 0: modulename else: $n

View file

@ -10,9 +10,9 @@
## Implements the module handling, including the caching of modules. ## Implements the module handling, including the caching of modules.
import import
ast, astalgo, magicsys, std / sha1, rodread, msgs, cgendata, sigmatch, options, ast, astalgo, magicsys, std / sha1, msgs, cgendata, sigmatch, options,
idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod, idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod,
configuration lineinfos
proc resetSystemArtifacts*(g: ModuleGraph) = proc resetSystemArtifacts*(g: ModuleGraph) =
magicsys.resetSysTypes(g) magicsys.resetSysTypes(g)
@ -23,8 +23,8 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
new(result) new(result)
result.id = -1 # for better error checking result.id = -1 # for better error checking
result.kind = skModule result.kind = skModule
let filename = fileIdx.toFullPath let filename = toFullPath(graph.config, fileIdx)
result.name = getIdent(splitFile(filename).name) result.name = getIdent(graph.cache, splitFile(filename).name)
if not isNimIdentifier(result.name.s): if not isNimIdentifier(result.name.s):
rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s) rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s)
@ -32,17 +32,19 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
let let
pck = getPackageName(graph.config, filename) pck = getPackageName(graph.config, filename)
pck2 = if pck.len > 0: pck else: "unknown" pck2 = if pck.len > 0: pck else: "unknown"
pack = getIdent(pck2) pack = getIdent(graph.cache, pck2)
var packSym = graph.packageSyms.strTableGet(pack) var packSym = graph.packageSyms.strTableGet(pack)
if packSym == nil: if packSym == nil:
packSym = newSym(skPackage, getIdent(pck2), nil, result.info) packSym = newSym(skPackage, getIdent(graph.cache, pck2), nil, result.info)
initStrTable(packSym.tab) initStrTable(packSym.tab)
graph.packageSyms.strTableAdd(packSym) graph.packageSyms.strTableAdd(packSym)
result.owner = packSym result.owner = packSym
result.position = int fileIdx result.position = int fileIdx
growCache graph.modules, int fileIdx if int(fileIdx) >= graph.modules.len:
setLen(graph.modules, int(fileIdx) + 1)
#growCache graph.modules, int fileIdx
graph.modules[result.position] = result graph.modules[result.position] = result
incl(result.flags, sfUsed) incl(result.flags, sfUsed)
@ -50,95 +52,76 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
strTableAdd(result.tab, result) # a module knows itself strTableAdd(result.tab, result) # a module knows itself
let existing = strTableGet(packSym.tab, result.name) let existing = strTableGet(packSym.tab, result.name)
if existing != nil and existing.info.fileIndex != result.info.fileIndex: if existing != nil and existing.info.fileIndex != result.info.fileIndex:
localError(graph.config, result.info, "module names need to be unique per Nimble package; module clashes with " & existing.info.fileIndex.toFullPath) localError(graph.config, result.info,
"module names need to be unique per Nimble package; module clashes with " &
toFullPath(graph.config, existing.info.fileIndex))
# strTableIncl() for error corrections: # strTableIncl() for error corrections:
discard strTableIncl(packSym.tab, result) discard strTableIncl(packSym.tab, result)
proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, flags: TSymFlags): PSym = proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): PSym =
result = graph.getModule(fileIdx) result = graph.getModule(fileIdx)
if result == nil: if result == nil:
#growCache gMemCacheData, fileIdx
#gMemCacheData[fileIdx].needsRecompile = Probing
result = newModule(graph, fileIdx) result = newModule(graph, fileIdx)
var rd: PRodReader
result.flags = result.flags + flags result.flags = result.flags + flags
if sfMainModule in result.flags: if sfMainModule in result.flags:
gMainPackageId = result.owner.id graph.config.mainPackageId = result.owner.id
when false: result.id = getModuleId(graph, fileIdx, toFullPath(graph.config, fileIdx))
if conf.cmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result, cache)
if result.id < 0:
internalError("handleSymbolFile should have set the module's ID")
return
else:
discard
result.id = getModuleId(fileIdx, toFullPath(fileIdx))
discard processModule(graph, result, discard processModule(graph, result,
if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil, if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil)
rd, cache)
#if optCaasEnabled in gGlobalOptions:
# gMemCacheData[fileIdx].needsRecompile = Recompiled
# if validFile: doHash fileIdx
elif graph.isDirty(result): elif graph.isDirty(result):
result.flags.excl sfDirty result.flags.excl sfDirty
# reset module fields: # reset module fields:
initStrTable(result.tab) initStrTable(result.tab)
result.ast = nil result.ast = nil
discard processModule(graph, result, discard processModule(graph, result,
if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil, if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil)
nil, cache)
graph.markClientsDirty(fileIdx) graph.markClientsDirty(fileIdx)
when false:
if checkDepMem(fileIdx) == Yes:
result = compileModule(fileIdx, cache, flags)
else:
result = gCompiledModules[fileIdx]
proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym {.procvar.} =
cache: IdentCache): PSym {.procvar.} =
# this is called by the semantic checking phase # this is called by the semantic checking phase
assert graph.config != nil assert graph.config != nil
result = compileModule(graph, fileIdx, cache, {}) result = compileModule(graph, fileIdx, {})
graph.addDep(s, fileIdx) graph.addDep(s, fileIdx)
#if sfSystemModule in result.flags: #if sfSystemModule in result.flags:
# localError(result.info, errAttemptToRedefine, result.name.s) # localError(result.info, errAttemptToRedefine, result.name.s)
# restore the notes for outer module: # restore the notes for outer module:
graph.config.notes = graph.config.notes =
if s.owner.id == gMainPackageId: graph.config.mainPackageNotes if s.owner.id == graph.config.mainPackageId: graph.config.mainPackageNotes
else: graph.config.foreignPackageNotes else: graph.config.foreignPackageNotes
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode {.procvar.} =
cache: IdentCache): PNode {.procvar.} = result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
result = syntaxes.parseFile(fileIdx, cache, graph.config)
graph.addDep(s, fileIdx) graph.addDep(s, fileIdx)
graph.addIncludeDep(s.position.FileIndex, fileIdx) graph.addIncludeDep(s.position.FileIndex, fileIdx)
proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) = proc connectCallbacks*(graph: ModuleGraph) =
graph.includeFileCallback = includeModule
graph.importModuleCallback = importModule
proc compileSystemModule*(graph: ModuleGraph) =
if graph.systemModule == nil: if graph.systemModule == nil:
systemFileIdx = fileInfoIdx(graph.config, graph.config.libpath / "system.nim") connectCallbacks(graph)
discard graph.compileModule(systemFileIdx, cache, {sfSystemModule}) graph.config.m.systemFileIdx = fileInfoIdx(graph.config, graph.config.libpath / "system.nim")
discard graph.compileModule(graph.config.m.systemFileIdx, {sfSystemModule})
proc wantMainModule*(conf: ConfigRef) = proc wantMainModule*(conf: ConfigRef) =
if conf.projectFull.len == 0: if conf.projectFull.len == 0:
fatal(conf, newLineInfo(conf, "command line", 1, 1), errGenerated, "command expects a filename") fatal(conf, newLineInfo(conf, "command line", 1, 1), errGenerated, "command expects a filename")
conf.projectMainIdx = int32 fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt)) conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt))
passes.gIncludeFile = includeModule proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIDX) =
passes.gImportModule = importModule connectCallbacks(graph)
proc compileProject*(graph: ModuleGraph; cache: IdentCache;
projectFileIdx = InvalidFileIDX) =
let conf = graph.config let conf = graph.config
wantMainModule(conf) wantMainModule(conf)
let systemFileIdx = fileInfoIdx(conf, conf.libpath / "system.nim") let systemFileIdx = fileInfoIdx(conf, conf.libpath / "system.nim")
let projectFile = if projectFileIdx == InvalidFileIDX: FileIndex(conf.projectMainIdx) else: projectFileIdx let projectFile = if projectFileIdx == InvalidFileIDX: conf.projectMainIdx else: projectFileIdx
graph.importStack.add projectFile graph.importStack.add projectFile
if projectFile == systemFileIdx: if projectFile == systemFileIdx:
discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule}) discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule})
else: else:
graph.compileSystemModule(cache) graph.compileSystemModule()
discard graph.compileModule(projectFile, cache, {sfMainModule}) discard graph.compileModule(projectFile, {sfMainModule})
proc makeModule*(graph: ModuleGraph; filename: string): PSym = proc makeModule*(graph: ModuleGraph; filename: string): PSym =
result = graph.newModule(fileInfoIdx(graph.config, filename)) result = graph.newModule(fileInfoIdx(graph.config, filename))

View file

@ -9,83 +9,28 @@
import import
options, strutils, os, tables, ropes, platform, terminal, macros, options, strutils, os, tables, ropes, platform, terminal, macros,
configuration lineinfos
#type proc toCChar*(c: char; result: var string) =
# MsgConfig* = ref object of RootObj
type
TFileInfo* = object
fullPath: string # This is a canonical full filesystem path
projPath*: string # This is relative to the project's root
shortName*: string # short name of the module
quotedName*: Rope # cached quoted short name for codegen
# purposes
quotedFullName*: Rope # cached quoted full name for codegen
# purposes
lines*: seq[Rope] # the source code of the module
# used for better error messages and
# embedding the original source in the
# generated code
dirtyfile: string # the file that is actually read into memory
# and parsed; usually 'nil' but is used
# for 'nimsuggest'
hash*: string # the checksum of the file
when defined(nimpretty):
fullContent*: string
FileIndex* = distinct int32
TLineInfo* = object # This is designed to be as small as possible,
# because it is used
# in syntax nodes. We save space here by using
# two int16 and an int32.
# On 64 bit and on 32 bit systems this is
# only 8 bytes.
line*: uint16
col*: int16
fileIndex*: FileIndex
when defined(nimpretty):
offsetA*, offsetB*: int
commentOffsetA*, commentOffsetB*: int
TErrorOutput* = enum
eStdOut
eStdErr
TErrorOutputs* = set[TErrorOutput]
ERecoverableError* = object of ValueError
ESuggestDone* = object of Exception
proc `==`*(a, b: FileIndex): bool {.borrow.}
const
InvalidFileIDX* = FileIndex(-1)
var
filenameToIndexTbl = initTable[string, FileIndex]()
fileInfos*: seq[TFileInfo] = @[]
systemFileIdx*: FileIndex
proc toCChar*(c: char): string =
case c case c
of '\0'..'\x1F', '\x7F'..'\xFF': result = '\\' & toOctal(c) of '\0'..'\x1F', '\x7F'..'\xFF':
of '\'', '\"', '\\', '?': result = '\\' & c result.add '\\'
else: result = $(c) result.add toOctal(c)
of '\'', '\"', '\\', '?':
result.add '\\'
result.add c
else:
result.add c
proc makeCString*(s: string): Rope = proc makeCString*(s: string): Rope =
const const MaxLineLength = 64
MaxLineLength = 64
result = nil result = nil
var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1) var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
add(res, "\"") add(res, "\"")
for i in countup(0, len(s) - 1): for i in countup(0, len(s) - 1):
if (i + 1) mod MaxLineLength == 0: if (i + 1) mod MaxLineLength == 0:
add(res, '\"') add(res, "\"\L\"")
add(res, tnl) toCChar(s[i], res)
add(res, '\"')
add(res, toCChar(s[i]))
add(res, '\"') add(res, '\"')
add(result, rope(res)) add(result, rope(res))
@ -110,8 +55,8 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
result.fullContent = "" result.fullContent = ""
when defined(nimpretty): when defined(nimpretty):
proc fileSection*(fid: FileIndex; a, b: int): string = proc fileSection*(conf: ConfigRef; fid: FileIndex; a, b: int): string =
substr(fileInfos[fid.int].fullContent, a, b) substr(conf.m.fileInfos[fid.int].fullContent, a, b)
proc fileInfoKnown*(conf: ConfigRef; filename: string): bool = proc fileInfoKnown*(conf: ConfigRef; filename: string): bool =
var var
@ -120,7 +65,7 @@ proc fileInfoKnown*(conf: ConfigRef; filename: string): bool =
canon = canonicalizePath(conf, filename) canon = canonicalizePath(conf, filename)
except: except:
canon = filename canon = filename
result = filenameToIndexTbl.hasKey(canon) result = conf.m.filenameToIndexTbl.hasKey(canon)
proc fileInfoIdx*(conf: ConfigRef; filename: string; isKnownFile: var bool): FileIndex = proc fileInfoIdx*(conf: ConfigRef; filename: string; isKnownFile: var bool): FileIndex =
var var
@ -136,14 +81,14 @@ proc fileInfoIdx*(conf: ConfigRef; filename: string; isKnownFile: var bool): Fil
# This flag indicates that we are working with such a path here # This flag indicates that we are working with such a path here
pseudoPath = true pseudoPath = true
if filenameToIndexTbl.hasKey(canon): if conf.m.filenameToIndexTbl.hasKey(canon):
result = filenameToIndexTbl[canon] result = conf.m.filenameToIndexTbl[canon]
else: else:
isKnownFile = false isKnownFile = false
result = fileInfos.len.FileIndex result = conf.m.fileInfos.len.FileIndex
fileInfos.add(newFileInfo(canon, if pseudoPath: filename conf.m.fileInfos.add(newFileInfo(canon, if pseudoPath: filename
else: shortenDir(conf, canon))) else: shortenDir(conf, canon)))
filenameToIndexTbl[canon] = result conf.m.filenameToIndexTbl[canon] = result
proc fileInfoIdx*(conf: ConfigRef; filename: string): FileIndex = proc fileInfoIdx*(conf: ConfigRef; filename: string): FileIndex =
var dummy: bool var dummy: bool
@ -157,34 +102,9 @@ proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
proc newLineInfo*(conf: ConfigRef; filename: string, line, col: int): TLineInfo {.inline.} = proc newLineInfo*(conf: ConfigRef; filename: string, line, col: int): TLineInfo {.inline.} =
result = newLineInfo(fileInfoIdx(conf, filename), line, col) result = newLineInfo(fileInfoIdx(conf, filename), line, col)
when false:
fileInfos.add(newFileInfo("", "command line"))
var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1)
fileInfos.add(newFileInfo("", "compilation artifact"))
var gCodegenLineInfo* = newLineInfo(FileIndex(1), 1, 1)
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} = proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
raise newException(ERecoverableError, msg) raise newException(ERecoverableError, msg)
proc sourceLine*(conf: ConfigRef; i: TLineInfo): Rope
proc unknownLineInfo*(): TLineInfo =
result.line = uint16(0)
result.col = int16(-1)
result.fileIndex = InvalidFileIDX
type
Severity* {.pure.} = enum ## VS Code only supports these three
Hint, Warning, Error
var
msgContext: seq[TLineInfo] = @[]
lastError = unknownLineInfo()
errorOutputs* = {eStdOut, eStdErr}
writelnHook*: proc (output: string) {.closure.}
structuredErrorHook*: proc (info: TLineInfo; msg: string; severity: Severity) {.closure.}
proc concat(strings: openarray[string]): string = proc concat(strings: openarray[string]): string =
var totalLen = 0 var totalLen = 0
@ -192,13 +112,13 @@ proc concat(strings: openarray[string]): string =
result = newStringOfCap totalLen result = newStringOfCap totalLen
for s in strings: result.add s for s in strings: result.add s
proc suggestWriteln*(s: string) = proc suggestWriteln*(conf: ConfigRef; s: string) =
if eStdOut in errorOutputs: if eStdOut in conf.m.errorOutputs:
if isNil(writelnHook): if isNil(conf.writelnHook):
writeLine(stdout, s) writeLine(stdout, s)
flushFile(stdout) flushFile(stdout)
else: else:
writelnHook(s) conf.writelnHook(s)
proc msgQuit*(x: int8) = quit x proc msgQuit*(x: int8) = quit x
proc msgQuit*(x: string) = quit x proc msgQuit*(x: string) = quit x
@ -219,61 +139,61 @@ const
HintTitle = "Hint: " HintTitle = "Hint: "
HintColor = fgGreen HintColor = fgGreen
proc getInfoContextLen*(): int = return msgContext.len proc getInfoContextLen*(conf: ConfigRef): int = return conf.m.msgContext.len
proc setInfoContextLen*(L: int) = setLen(msgContext, L) proc setInfoContextLen*(conf: ConfigRef; L: int) = setLen(conf.m.msgContext, L)
proc pushInfoContext*(info: TLineInfo) = proc pushInfoContext*(conf: ConfigRef; info: TLineInfo) =
msgContext.add(info) conf.m.msgContext.add(info)
proc popInfoContext*() = proc popInfoContext*(conf: ConfigRef) =
setLen(msgContext, len(msgContext) - 1) setLen(conf.m.msgContext, len(conf.m.msgContext) - 1)
proc getInfoContext*(index: int): TLineInfo = proc getInfoContext*(conf: ConfigRef; index: int): TLineInfo =
let L = msgContext.len let L = conf.m.msgContext.len
let i = if index < 0: L + index else: index let i = if index < 0: L + index else: index
if i >=% L: result = unknownLineInfo() if i >=% L: result = unknownLineInfo()
else: result = msgContext[i] else: result = conf.m.msgContext[i]
template toFilename*(fileIdx: FileIndex): string = template toFilename*(conf: ConfigRef; fileIdx: FileIndex): string =
(if fileIdx.int32 < 0: "???" else: fileInfos[fileIdx.int32].projPath) (if fileIdx.int32 < 0: "???" else: conf.m.fileInfos[fileIdx.int32].projPath)
proc toFullPath*(fileIdx: FileIndex): string = proc toFullPath*(conf: ConfigRef; fileIdx: FileIndex): string =
if fileIdx.int32 < 0: result = "???" if fileIdx.int32 < 0: result = "???"
else: result = fileInfos[fileIdx.int32].fullPath else: result = conf.m.fileInfos[fileIdx.int32].fullPath
proc setDirtyFile*(fileIdx: FileIndex; filename: string) = proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: string) =
assert fileIdx.int32 >= 0 assert fileIdx.int32 >= 0
fileInfos[fileIdx.int32].dirtyFile = filename conf.m.fileInfos[fileIdx.int32].dirtyFile = filename
proc setHash*(fileIdx: FileIndex; hash: string) = proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
assert fileIdx.int32 >= 0 assert fileIdx.int32 >= 0
shallowCopy(fileInfos[fileIdx.int32].hash, hash) shallowCopy(conf.m.fileInfos[fileIdx.int32].hash, hash)
proc getHash*(fileIdx: FileIndex): string = proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string =
assert fileIdx.int32 >= 0 assert fileIdx.int32 >= 0
shallowCopy(result, fileInfos[fileIdx.int32].hash) shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash)
proc toFullPathConsiderDirty*(fileIdx: FileIndex): string = proc toFullPathConsiderDirty*(conf: ConfigRef; fileIdx: FileIndex): string =
if fileIdx.int32 < 0: if fileIdx.int32 < 0:
result = "???" result = "???"
elif not fileInfos[fileIdx.int32].dirtyFile.isNil: elif not conf.m.fileInfos[fileIdx.int32].dirtyFile.isNil:
result = fileInfos[fileIdx.int32].dirtyFile result = conf.m.fileInfos[fileIdx.int32].dirtyFile
else: else:
result = fileInfos[fileIdx.int32].fullPath result = conf.m.fileInfos[fileIdx.int32].fullPath
template toFilename*(info: TLineInfo): string = template toFilename*(conf: ConfigRef; info: TLineInfo): string =
info.fileIndex.toFilename toFilename(conf, info.fileIndex)
template toFullPath*(info: TLineInfo): string = template toFullPath*(conf: ConfigRef; info: TLineInfo): string =
info.fileIndex.toFullPath toFullPath(conf, info.fileIndex)
proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string = proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
if info.fileIndex.int32 < 0: if info.fileIndex.int32 < 0:
result = "???" result = "???"
elif optListFullPaths in conf.globalOptions: elif optListFullPaths in conf.globalOptions:
result = fileInfos[info.fileIndex.int32].fullPath result = conf.m.fileInfos[info.fileIndex.int32].fullPath
else: else:
result = fileInfos[info.fileIndex.int32].projPath result = conf.m.fileInfos[info.fileIndex.int32].projPath
proc toLinenumber*(info: TLineInfo): int {.inline.} = proc toLinenumber*(info: TLineInfo): int {.inline.} =
result = int info.line result = int info.line
@ -281,23 +201,19 @@ proc toLinenumber*(info: TLineInfo): int {.inline.} =
proc toColumn*(info: TLineInfo): int {.inline.} = proc toColumn*(info: TLineInfo): int {.inline.} =
result = info.col result = info.col
proc toFileLine*(info: TLineInfo): string {.inline.} = proc toFileLine*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
result = info.toFilename & ":" & $info.line result = toFilename(conf, info) & ":" & $info.line
proc toFileLineCol*(info: TLineInfo): string {.inline.} = proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
result = info.toFilename & "(" & $info.line & ", " & $info.col & ")" result = toFilename(conf, info) & "(" & $info.line & ", " & $info.col & ")"
proc `$`*(info: TLineInfo): string = toFileLineCol(info) proc `$`*(conf: ConfigRef; info: TLineInfo): string = toFileLineCol(conf, info)
proc `??`* (info: TLineInfo, filename: string): bool = proc `$`*(info: TLineInfo): string {.error.} = discard
proc `??`* (conf: ConfigRef; info: TLineInfo, filename: string): bool =
# only for debugging purposes # only for debugging purposes
result = filename in info.toFilename result = filename in toFilename(conf, info)
const trackPosInvalidFileIdx* = FileIndex(-2) # special marker so that no suggestions
# are produced within comments and string literals
var gTrackPos*: TLineInfo
var gTrackPosAttached*: bool ## whether the tracking position was attached to some
## close token.
type type
MsgFlag* = enum ## flags altering msgWriteln behavior MsgFlag* = enum ## flags altering msgWriteln behavior
@ -315,14 +231,14 @@ proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) =
## support. ## support.
#if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return #if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
if not isNil(writelnHook) and msgSkipHook notin flags: if not isNil(conf.writelnHook) and msgSkipHook notin flags:
writelnHook(s) conf.writelnHook(s)
elif optStdout in conf.globalOptions or msgStdout in flags: elif optStdout in conf.globalOptions or msgStdout in flags:
if eStdOut in errorOutputs: if eStdOut in conf.m.errorOutputs:
writeLine(stdout, s) writeLine(stdout, s)
flushFile(stdout) flushFile(stdout)
else: else:
if eStdErr in errorOutputs: if eStdErr in conf.m.errorOutputs:
writeLine(stderr, s) writeLine(stderr, s)
# On Windows stderr is fully-buffered when piped, regardless of C std. # On Windows stderr is fully-buffered when piped, regardless of C std.
when defined(windows): when defined(windows):
@ -353,17 +269,17 @@ macro callStyledWriteLineStderr(args: varargs[typed]): untyped =
result.add(arg) result.add(arg)
template callWritelnHook(args: varargs[string, `$`]) = template callWritelnHook(args: varargs[string, `$`]) =
writelnHook concat(args) conf.writelnHook concat(args)
template styledMsgWriteln*(args: varargs[typed]) = template styledMsgWriteln*(args: varargs[typed]) =
if not isNil(writelnHook): if not isNil(conf.writelnHook):
callIgnoringStyle(callWritelnHook, nil, args) callIgnoringStyle(callWritelnHook, nil, args)
elif optStdout in conf.globalOptions: elif optStdout in conf.globalOptions:
if eStdOut in errorOutputs: if eStdOut in conf.m.errorOutputs:
callIgnoringStyle(writeLine, stdout, args) callIgnoringStyle(writeLine, stdout, args)
flushFile(stdout) flushFile(stdout)
else: else:
if eStdErr in errorOutputs: if eStdErr in conf.m.errorOutputs:
if optUseColors in conf.globalOptions: if optUseColors in conf.globalOptions:
callStyledWriteLineStderr(args) callStyledWriteLineStderr(args)
else: else:
@ -394,7 +310,7 @@ proc log*(s: string) {.procvar.} =
proc quit(conf: ConfigRef; msg: TMsgKind) = proc quit(conf: ConfigRef; msg: TMsgKind) =
if defined(debug) or msg == errInternal or hintStackTrace in conf.notes: if defined(debug) or msg == errInternal or hintStackTrace in conf.notes:
if stackTraceAvailable() and isNil(writelnHook): if stackTraceAvailable() and isNil(conf.writelnHook):
writeStackTrace() writeStackTrace()
else: else:
styledMsgWriteln(fgRed, "No stack traceback available\n" & styledMsgWriteln(fgRed, "No stack traceback available\n" &
@ -425,19 +341,19 @@ proc exactEquals*(a, b: TLineInfo): bool =
proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) = proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) =
const instantiationFrom = "template/generic instantiation from here" const instantiationFrom = "template/generic instantiation from here"
var info = lastinfo var info = lastinfo
for i in countup(0, len(msgContext) - 1): for i in 0 ..< len(conf.m.msgContext):
if msgContext[i] != lastinfo and msgContext[i] != info: if conf.m.msgContext[i] != lastinfo and conf.m.msgContext[i] != info:
if structuredErrorHook != nil: if conf.structuredErrorHook != nil:
structuredErrorHook(msgContext[i], instantiationFrom, conf.structuredErrorHook(conf, conf.m.msgContext[i], instantiationFrom,
Severity.Error) Severity.Error)
else: else:
styledMsgWriteln(styleBright, styledMsgWriteln(styleBright,
PosFormat % [toMsgFilename(conf, msgContext[i]), PosFormat % [toMsgFilename(conf, conf.m.msgContext[i]),
coordToStr(msgContext[i].line.int), coordToStr(conf.m.msgContext[i].line.int),
coordToStr(msgContext[i].col+1)], coordToStr(conf.m.msgContext[i].col+1)],
resetStyle, resetStyle,
instantiationFrom) instantiationFrom)
info = msgContext[i] info = conf.m.msgContext[i]
proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool = proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool =
msg >= errGenerated and conf.cmd == cmdIdeTools and optIdeDebug notin conf.globalOptions msg >= errGenerated and conf.cmd == cmdIdeTools and optIdeDebug notin conf.globalOptions
@ -473,8 +389,9 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) =
inc(conf.hintCounter) inc(conf.hintCounter)
let s = msgKindToString(msg) % args let s = msgKindToString(msg) % args
if structuredErrorHook != nil: if conf.structuredErrorHook != nil:
structuredErrorHook(unknownLineInfo(), s & (if kind != nil: KindFormat % kind else: ""), sev) conf.structuredErrorHook(conf, unknownLineInfo(),
s & (if kind != nil: KindFormat % kind else: ""), sev)
if not ignoreMsgBecauseOfIdeTools(conf, msg): if not ignoreMsgBecauseOfIdeTools(conf, msg):
if kind != nil: if kind != nil:
@ -491,6 +408,24 @@ proc resetAttributes*(conf: ConfigRef) =
if {optUseColors, optStdout} * conf.globalOptions == {optUseColors}: if {optUseColors, optStdout} * conf.globalOptions == {optUseColors}:
terminal.resetAttributes(stderr) terminal.resetAttributes(stderr)
proc addSourceLine(conf: ConfigRef; fileIdx: FileIndex, line: string) =
conf.m.fileInfos[fileIdx.int32].lines.add line
proc sourceLine*(conf: ConfigRef; i: TLineInfo): string =
if i.fileIndex.int32 < 0: return ""
if not optPreserveOrigSource(conf) and conf.m.fileInfos[i.fileIndex.int32].lines.len == 0:
try:
for line in lines(toFullPath(conf, i)):
addSourceLine conf, i.fileIndex, line.string
except IOError:
discard
assert i.fileIndex.int32 < conf.m.fileInfos.len
# can happen if the error points to EOF:
if i.line.int > conf.m.fileInfos[i.fileIndex.int32].lines.len: return ""
result = conf.m.fileInfos[i.fileIndex.int32].lines[i.line.int-1]
proc writeSurroundingSrc(conf: ConfigRef; info: TLineInfo) = proc writeSurroundingSrc(conf: ConfigRef; info: TLineInfo) =
const indent = " " const indent = " "
msgWriteln(conf, indent & $sourceLine(conf, info)) msgWriteln(conf, indent & $sourceLine(conf, info))
@ -523,7 +458,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
# we try to filter error messages so that not two error message # we try to filter error messages so that not two error message
# in the same file and line are produced: # in the same file and line are produced:
#ignoreMsg = lastError == info and eh != doAbort #ignoreMsg = lastError == info and eh != doAbort
lastError = info conf.m.lastError = info
of warnMin..warnMax: of warnMin..warnMax:
sev = Severity.Warning sev = Severity.Warning
ignoreMsg = optWarns notin conf.options or msg notin conf.notes ignoreMsg = optWarns notin conf.options or msg notin conf.notes
@ -547,8 +482,8 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
let s = getMessageStr(msg, arg) let s = getMessageStr(msg, arg)
if not ignoreMsg: if not ignoreMsg:
if structuredErrorHook != nil: if conf.structuredErrorHook != nil:
structuredErrorHook(info, s & (if kind != nil: KindFormat % kind else: ""), sev) conf.structuredErrorHook(conf, info, s & (if kind != nil: KindFormat % kind else: ""), sev)
if not ignoreMsgBecauseOfIdeTools(conf, msg): if not ignoreMsgBecauseOfIdeTools(conf, msg):
if kind != nil: if kind != nil:
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s, styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
@ -562,7 +497,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
proc fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = proc fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
# this fixes bug #7080 so that it is at least obvious 'fatal' # this fixes bug #7080 so that it is at least obvious 'fatal'
# was executed. # was executed.
errorOutputs = {eStdOut, eStdErr} conf.m.errorOutputs = {eStdOut, eStdErr}
liMessage(conf, info, msg, arg, doAbort) liMessage(conf, info, msg, arg, doAbort)
proc globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = proc globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
@ -584,12 +519,12 @@ proc message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doNothing) liMessage(conf, info, msg, arg, doNothing)
proc internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) = proc internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) =
if conf.cmd == cmdIdeTools and structuredErrorHook.isNil: return if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return
writeContext(conf, info) writeContext(conf, info)
liMessage(conf, info, errInternal, errMsg, doAbort) liMessage(conf, info, errInternal, errMsg, doAbort)
proc internalError*(conf: ConfigRef; errMsg: string) = proc internalError*(conf: ConfigRef; errMsg: string) =
if conf.cmd == cmdIdeTools and structuredErrorHook.isNil: return if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return
writeContext(conf, unknownLineInfo()) writeContext(conf, unknownLineInfo())
rawMessage(conf, errInternal, errMsg) rawMessage(conf, errInternal, errMsg)
@ -600,44 +535,19 @@ template assertNotNil*(conf: ConfigRef; e): untyped =
template internalAssert*(conf: ConfigRef, e: bool) = template internalAssert*(conf: ConfigRef, e: bool) =
if not e: internalError(conf, $instantiationInfo()) if not e: internalError(conf, $instantiationInfo())
proc addSourceLine*(fileIdx: FileIndex, line: string) =
fileInfos[fileIdx.int32].lines.add line.rope
proc sourceLine*(conf: ConfigRef; i: TLineInfo): Rope =
if i.fileIndex.int32 < 0: return nil
if not optPreserveOrigSource(conf) and fileInfos[i.fileIndex.int32].lines.len == 0:
try:
for line in lines(i.toFullPath):
addSourceLine i.fileIndex, line.string
except IOError:
discard
assert i.fileIndex.int32 < fileInfos.len
# can happen if the error points to EOF:
if i.line.int > fileInfos[i.fileIndex.int32].lines.len: return nil
result = fileInfos[i.fileIndex.int32].lines[i.line.int-1]
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope = proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
assert i.fileIndex.int32 >= 0 assert i.fileIndex.int32 >= 0
if optExcessiveStackTrace in conf.globalOptions: if optExcessiveStackTrace in conf.globalOptions:
result = fileInfos[i.fileIndex.int32].quotedFullName result = conf.m.fileInfos[i.fileIndex.int32].quotedFullName
else: else:
result = fileInfos[i.fileIndex.int32].quotedName result = conf.m.fileInfos[i.fileIndex.int32].quotedName
ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
case err
of rInvalidFormatStr:
internalError(newPartialConfigRef(), "ropes: invalid format string: " & msg)
of rCannotOpenFile:
rawMessage(newPartialConfigRef(), if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
proc listWarnings*(conf: ConfigRef) = proc listWarnings*(conf: ConfigRef) =
msgWriteln(conf, "Warnings:") msgWriteln(conf, "Warnings:")
for warn in warnMin..warnMax: for warn in warnMin..warnMax:
msgWriteln(conf, " [$1] $2" % [ msgWriteln(conf, " [$1] $2" % [
if warn in conf.notes: "x" else: " ", if warn in conf.notes: "x" else: " ",
configuration.WarningsToStr[ord(warn) - ord(warnMin)] lineinfos.WarningsToStr[ord(warn) - ord(warnMin)]
]) ])
proc listHints*(conf: ConfigRef) = proc listHints*(conf: ConfigRef) =
@ -645,5 +555,5 @@ proc listHints*(conf: ConfigRef) =
for hint in hintMin..hintMax: for hint in hintMin..hintMax:
msgWriteln(conf, " [$1] $2" % [ msgWriteln(conf, " [$1] $2" % [
if hint in conf.notes: "x" else: " ", if hint in conf.notes: "x" else: " ",
configuration.HintsToStr[ord(hint) - ord(hintMin)] lineinfos.HintsToStr[ord(hint) - ord(hintMin)]
]) ])

View file

@ -10,7 +10,7 @@
## This module implements the generation of ``.ndi`` files for better debugging ## This module implements the generation of ``.ndi`` files for better debugging
## support of Nim code. "ndi" stands for "Nim debug info". ## support of Nim code. "ndi" stands for "Nim debug info".
import ast, msgs, ropes import ast, msgs, ropes, options
type type
NdiFile* = object NdiFile* = object
@ -18,19 +18,19 @@ type
f: File f: File
buf: string buf: string
proc doWrite(f: var NdiFile; s: PSym) = proc doWrite(f: var NdiFile; s: PSym; conf: ConfigRef) =
f.buf.setLen 0 f.buf.setLen 0
f.buf.add s.info.line.int f.buf.add s.info.line.int
f.buf.add "\t" f.buf.add "\t"
f.buf.add s.info.col.int f.buf.add s.info.col.int
f.f.write(s.name.s, "\t") f.f.write(s.name.s, "\t")
f.f.writeRope(s.loc.r) f.f.writeRope(s.loc.r)
f.f.writeLine("\t", s.info.toFullPath, "\t", f.buf) f.f.writeLine("\t", toFullPath(conf, s.info), "\t", f.buf)
template writeMangledName*(f: NdiFile; s: PSym) = template writeMangledName*(f: NdiFile; s: PSym; conf: ConfigRef) =
if f.enabled: doWrite(f, s) if f.enabled: doWrite(f, s, conf)
proc open*(f: var NdiFile; filename: string) = proc open*(f: var NdiFile; filename: string; conf: ConfigRef) =
f.enabled = filename.len > 0 f.enabled = filename.len > 0
if f.enabled: if f.enabled:
f.f = open(filename, fmWrite, 8000) f.f = open(filename, fmWrite, 8000)

View file

@ -5,6 +5,8 @@ path:"llvm"
path:"$projectPath/.." path:"$projectPath/.."
define:booting define:booting
define:nimcore
#define:nimIncremental
#import:"$projectpath/testability" #import:"$projectpath/testability"
@if windows: @if windows:
@ -13,6 +15,5 @@ define:booting
define:useStdoutAsStdmsg define:useStdoutAsStdmsg
cs:partial
#define:useNodeIds #define:useNodeIds
#gc:markAndSweep #gc:markAndSweep

View file

@ -20,8 +20,8 @@ when defined(i386) and defined(windows) and defined(vcc):
import import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, osproc, platform, main, parseopt, service, extccomp, strutils, os, osproc, platform, main, parseopt,
nodejs, scriptconfig, idents, modulegraphs, configuration nodejs, scriptconfig, idents, modulegraphs, lineinfos
when hasTinyCBackend: when hasTinyCBackend:
import tccgen import tccgen
@ -37,6 +37,25 @@ proc prependCurDir(f: string): string =
else: else:
result = f result = f
proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
var p = parseopt.initOptParser(cmd)
var argsCount = 0
while true:
parseopt.next(p)
case p.kind
of cmdEnd: break
of cmdLongoption, cmdShortOption:
if p.key == " ":
p.key = "-"
if processArgument(pass, p, argsCount, config): break
else:
processSwitch(pass, p, config)
of cmdArgument:
if processArgument(pass, p, argsCount, config): break
if pass == passCmd2:
if optRun notin config.globalOptions and config.arguments.len > 0 and config.command.normalize != "run":
rawMessage(config, errGenerated, errArgsNeedRunOption)
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
condsyms.initDefines(conf.symbols) condsyms.initDefines(conf.symbols)
if paramCount() == 0: if paramCount() == 0:
@ -60,7 +79,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
conf.projectName = p.name conf.projectName = p.name
else: else:
conf.projectPath = canonicalizePath(conf, getCurrentDir()) conf.projectPath = canonicalizePath(conf, getCurrentDir())
loadConfigs(DefaultConfig, conf) # load all config files loadConfigs(DefaultConfig, cache, conf) # load all config files
let scriptFile = conf.projectFull.changeFileExt("nims") let scriptFile = conf.projectFull.changeFileExt("nims")
if fileExists(scriptFile): if fileExists(scriptFile):
runNimScript(cache, scriptFile, freshDefines=false, conf) runNimScript(cache, scriptFile, freshDefines=false, conf)
@ -75,7 +94,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
processCmdLine(passCmd2, "", conf) processCmdLine(passCmd2, "", conf)
if conf.command == "": if conf.command == "":
rawMessage(conf, errGenerated, "command missing") rawMessage(conf, errGenerated, "command missing")
mainCommand(newModuleGraph(conf), cache) mainCommand(newModuleGraph(cache, conf))
if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics()) if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics())
#echo(GC_getStatistics()) #echo(GC_getStatistics())
if conf.errorCounter == 0: if conf.errorCounter == 0:

View file

@ -10,7 +10,7 @@
## Implements some helper procs for Nimble (Nim's package manager) support. ## Implements some helper procs for Nimble (Nim's package manager) support.
import parseutils, strutils, strtabs, os, options, msgs, sequtils, import parseutils, strutils, strtabs, os, options, msgs, sequtils,
configuration lineinfos
proc addPath*(conf: ConfigRef; path: string, info: TLineInfo) = proc addPath*(conf: ConfigRef; path: string, info: TLineInfo) =
if not conf.searchPaths.contains(path): if not conf.searchPaths.contains(path):

View file

@ -11,7 +11,7 @@
import import
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer, llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
options, idents, wordrecg, strtabs, configuration options, idents, wordrecg, strtabs, lineinfos
# ---------------- configuration file parser ----------------------------- # ---------------- configuration file parser -----------------------------
# we use Nim's scanner here to save space and work # we use Nim's scanner here to save space and work
@ -233,7 +233,7 @@ proc getSystemConfigPath(conf: ConfigRef; filename: string): string =
proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) = proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
setDefaultLibpath(conf) setDefaultLibpath(conf)
var configFiles = newSeq[string]() var configFiles = newSeq[string]()
template readConfigFile(path: string) = template readConfigFile(path: string) =
@ -264,7 +264,3 @@ proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
for filename in configFiles: for filename in configFiles:
rawMessage(conf, hintConf, filename) rawMessage(conf, hintConf, filename)
proc loadConfigs*(cfg: string; conf: ConfigRef) =
# for backwards compatibility only.
loadConfigs(cfg, newIdentCache(), conf)

View file

@ -1,7 +1,7 @@
# #
# #
# The Nim Compiler # The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf # (c) Copyright 2018 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -9,27 +9,112 @@
## exposes the Nim VM to clients. ## exposes the Nim VM to clients.
import import
ast, modules, passes, passaux, condsyms, ast, astalgo, modules, passes, condsyms,
options, nimconf, sem, semdata, llstream, vm, modulegraphs, idents options, sem, semdata, llstream, vm, vmdef,
modulegraphs, idents, os
proc execute*(program: string) = type
passes.gIncludeFile = includeModule Interpreter* = ref object ## Use Nim as an interpreter with this object
passes.gImportModule = importModule mainModule: PSym
initDefines() graph: ModuleGraph
loadConfigs(DefaultConfig) scriptName: string
initDefines() iterator exportedSymbols*(i: Interpreter): PSym =
defineSymbol("nimrodvm") assert i != nil
defineSymbol("nimscript") assert i.mainModule != nil, "no main module selected"
when hasFFI: defineSymbol("nimffi") var it: TTabIter
registerPass(verbosePass) var s = initTabIter(it, i.mainModule.tab)
registerPass(semPass) while s != nil:
registerPass(evalPass) yield s
s = nextIter(it, i.mainModule.tab)
searchPaths.add options.libpath proc selectUniqueSymbol*(i: Interpreter; name: string;
var graph = newModuleGraph() symKinds: set[TSymKind] = {skLet, skVar}): PSym =
## Can be used to access a unique symbol of ``name`` and
## the given ``symKinds`` filter.
assert i != nil
assert i.mainModule != nil, "no main module selected"
let n = getIdent(i.graph.cache, name)
var it: TIdentIter
var s = initIdentIter(it, i.mainModule.tab, n)
result = nil
while s != nil:
if s.kind in symKinds:
if result == nil: result = s
else: return nil # ambiguous
s = nextIdentIter(it, i.mainModule.tab)
proc selectRoutine*(i: Interpreter; name: string): PSym =
## Selects a declared rountine (proc/func/etc) from the main module.
## The routine needs to have the export marker ``*``. The only matching
## routine is returned and ``nil`` if it is overloaded.
result = selectUniqueSymbol(i, name, {skTemplate, skMacro, skFunc,
skMethod, skProc, skConverter})
proc callRoutine*(i: Interpreter; routine: PSym; args: openArray[PNode]): PNode =
assert i != nil
result = vm.execProc(PCtx i.graph.vm, routine, args)
proc getGlobalValue*(i: Interpreter; letOrVar: PSym): PNode =
result = vm.getGlobalValue(PCtx i.graph.vm, letOrVar)
proc implementRoutine*(i: Interpreter; pkg, module, name: string;
impl: proc (a: VmArgs) {.closure, gcsafe.}) =
assert i != nil
let vm = PCtx(i.graph.vm)
vm.registerCallback(pkg & "." & module & "." & name, impl)
proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) =
## This can also be used to *reload* the script.
assert i != nil
assert i.mainModule != nil, "no main module selected"
initStrTable(i.mainModule.tab)
i.mainModule.ast = nil
let s = if scriptStream != nil: scriptStream
else: llStreamOpen(findFile(i.graph.config, i.scriptName), fmRead)
processModule(i.graph, i.mainModule, s)
proc findNimStdLib*(): string =
## Tries to find a path to a valid "system.nim" file.
## Returns "" on failure.
try:
let nimexe = os.findExe("nim")
if nimexe.len == 0: return ""
result = nimexe.splitPath()[0] /../ "lib"
if not fileExists(result / "system.nim"):
when defined(unix):
result = nimexe.expandSymlink.splitPath()[0] /../ "lib"
if not fileExists(result / "system.nim"): return ""
except OSError, ValueError:
return ""
proc createInterpreter*(scriptName: string;
searchPaths: openArray[string];
flags: TSandboxFlags = {}): Interpreter =
var conf = newConfigRef()
var cache = newIdentCache() var cache = newIdentCache()
var m = makeStdinModule(graph) var graph = newModuleGraph(cache, conf)
connectCallbacks(graph)
initDefines(conf.symbols)
defineSymbol(conf.symbols, "nimscript")
defineSymbol(conf.symbols, "nimconfig")
registerPass(graph, semPass)
registerPass(graph, evalPass)
for p in searchPaths:
conf.searchPaths.add(p)
if conf.libpath.len == 0: conf.libpath = p
var m = graph.makeModule(scriptName)
incl(m.flags, sfMainModule) incl(m.flags, sfMainModule)
compileSystemModule(graph,cache) var vm = newCtx(m, cache, graph)
processModule(graph,m, llStreamOpen(program), nil, cache) vm.mode = emRepl
vm.features = flags
graph.vm = vm
graph.compileSystemModule()
result = Interpreter(mainModule: m, graph: graph, scriptName: scriptName)
proc destroyInterpreter*(i: Interpreter) =
## destructor.
discard "currently nothing to do."

View file

@ -14,7 +14,7 @@ import
strutils, os, intsets, strtabs strutils, os, intsets, strtabs
import ".." / [options, ast, astalgo, msgs, semdata, ropes, idents, import ".." / [options, ast, astalgo, msgs, semdata, ropes, idents,
configuration] lineinfos]
import prettybase import prettybase
type type
@ -27,19 +27,19 @@ var
proc overwriteFiles*(conf: ConfigRef) = proc overwriteFiles*(conf: ConfigRef) =
let doStrip = options.getConfigVar(conf, "pretty.strip").normalize == "on" let doStrip = options.getConfigVar(conf, "pretty.strip").normalize == "on"
for i in 0 .. high(gSourceFiles): for i in 0 .. high(conf.m.fileInfos):
if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and if conf.m.fileInfos[i].dirty and
(not gOnlyMainfile or gSourceFiles[i].fileIdx == conf.projectMainIdx.FileIndex): (not gOnlyMainfile or FileIndex(i) == conf.projectMainIdx):
let newFile = if gOverWrite: gSourceFiles[i].fullpath let newFile = if gOverWrite: conf.m.fileInfos[i].fullpath
else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim") else: conf.m.fileInfos[i].fullpath.changeFileExt(".pretty.nim")
try: try:
var f = open(newFile, fmWrite) var f = open(newFile, fmWrite)
for line in gSourceFiles[i].lines: for line in conf.m.fileInfos[i].lines:
if doStrip: if doStrip:
f.write line.strip(leading = false, trailing = true) f.write line.strip(leading = false, trailing = true)
else: else:
f.write line f.write line
f.write(gSourceFiles[i].newline) f.write(conf.m.fileInfos[i], "\L")
f.close f.close
except IOError: except IOError:
rawMessage(conf, errGenerated, "cannot open file: " & newFile) rawMessage(conf, errGenerated, "cannot open file: " & newFile)
@ -93,10 +93,8 @@ proc beautifyName(s: string, k: TSymKind): string =
result.add s[i] result.add s[i]
inc i inc i
proc replaceInFile(info: TLineInfo; newName: string) = proc replaceInFile(conf: ConfigRef; info: TLineInfo; newName: string) =
loadFile(info) let line = conf.m.fileInfos[info.fileIndex.int].lines[info.line.int-1]
let line = gSourceFiles[info.fileIndex.int].lines[info.line.int-1]
var first = min(info.col.int, line.len) var first = min(info.col.int, line.len)
if first < 0: return if first < 0: return
#inc first, skipIgnoreCase(line, "proc ", first) #inc first, skipIgnoreCase(line, "proc ", first)
@ -108,35 +106,35 @@ proc replaceInFile(info: TLineInfo; newName: string) =
if differ(line, first, last, newName): if differ(line, first, last, newName):
# last-first+1 != newName.len or # last-first+1 != newName.len or
var x = line.substr(0, first-1) & newName & line.substr(last+1) var x = line.substr(0, first-1) & newName & line.substr(last+1)
system.shallowCopy(gSourceFiles[info.fileIndex.int].lines[info.line.int-1], x) system.shallowCopy(conf.m.fileInfos[info.fileIndex.int].lines[info.line.int-1], x)
gSourceFiles[info.fileIndex.int].dirty = true conf.m.fileInfos[info.fileIndex.int].dirty = true
proc checkStyle(conf: ConfigRef; info: TLineInfo, s: string, k: TSymKind; sym: PSym) = proc checkStyle(conf: ConfigRef; cache: IdentCache; info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
let beau = beautifyName(s, k) let beau = beautifyName(s, k)
if s != beau: if s != beau:
if gStyleCheck == StyleCheck.Auto: if gStyleCheck == StyleCheck.Auto:
sym.name = getIdent(beau) sym.name = getIdent(cache, beau)
replaceInFile(info, beau) replaceInFile(conf, info, beau)
else: else:
message(conf, info, hintName, beau) message(conf, info, hintName, beau)
proc styleCheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) = proc styleCheckDefImpl(conf: ConfigRef; cache: IdentCache; info: TLineInfo; s: PSym; k: TSymKind) =
# operators stay as they are: # operators stay as they are:
if k in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters: return if k in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters: return
if k in {skType, skGenericParam} and sfAnon in s.flags: return if k in {skType, skGenericParam} and sfAnon in s.flags: return
if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern: if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern:
checkStyle(conf, info, s.name.s, k, s) checkStyle(conf, cache, info, s.name.s, k, s)
template styleCheckDef*(info: TLineInfo; s: PSym; k: TSymKind) = template styleCheckDef*(info: TLineInfo; s: PSym; k: TSymKind) =
when defined(nimfix): when defined(nimfix):
if gStyleCheck != StyleCheck.None: styleCheckDefImpl(conf, info, s, k) if gStyleCheck != StyleCheck.None: styleCheckDefImpl(conf, cache, info, s, k)
template styleCheckDef*(info: TLineInfo; s: PSym) = template styleCheckDef*(info: TLineInfo; s: PSym) =
styleCheckDef(info, s, s.kind) styleCheckDef(info, s, s.kind)
template styleCheckDef*(s: PSym) = template styleCheckDef*(s: PSym) =
styleCheckDef(s.info, s, s.kind) styleCheckDef(s.info, s, s.kind)
proc styleCheckUseImpl(info: TLineInfo; s: PSym) = proc styleCheckUseImpl(conf: ConfigRef; cache: IdentCache; info: TLineInfo; s: PSym) =
if info.fileIndex.int < 0: return if info.fileIndex.int < 0: return
# we simply convert it to what it looks like in the definition # we simply convert it to what it looks like in the definition
# for consistency # for consistency
@ -147,9 +145,9 @@ proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
let newName = s.name.s let newName = s.name.s
replaceInFile(info, newName) replaceInFile(conf, info, newName)
#if newName == "File": writeStackTrace() #if newName == "File": writeStackTrace()
template styleCheckUse*(info: TLineInfo; s: PSym) = template styleCheckUse*(info: TLineInfo; s: PSym) =
when defined(nimfix): when defined(nimfix):
if gStyleCheck != StyleCheck.None: styleCheckUseImpl(conf, info, s) if gStyleCheck != StyleCheck.None: styleCheckUseImpl(conf, cache, info, s)

View file

@ -8,48 +8,9 @@
# #
import strutils, lexbase, streams import strutils, lexbase, streams
import ".." / [ast, msgs, idents] import ".." / [ast, msgs, lineinfos, idents, options]
from os import splitFile from os import splitFile
type
TSourceFile* = object
lines*: seq[string]
dirty*, isNimfixFile*: bool
fullpath*, newline*: string
fileIdx*: FileIndex
var
gSourceFiles*: seq[TSourceFile] = @[]
proc loadFile*(info: TLineInfo) =
let i = info.fileIndex.int
if i >= gSourceFiles.len:
gSourceFiles.setLen(i+1)
if gSourceFiles[i].lines.isNil:
gSourceFiles[i].fileIdx = info.fileIndex
gSourceFiles[i].lines = @[]
let path = info.toFullPath
gSourceFiles[i].fullpath = path
gSourceFiles[i].isNimfixFile = path.splitFile.ext == ".nimfix"
# we want to die here for IOError:
for line in lines(path):
gSourceFiles[i].lines.add(line)
# extract line ending of the file:
var lex: BaseLexer
open(lex, newFileStream(path, fmRead))
var pos = lex.bufpos
while true:
case lex.buf[pos]
of '\c':
gSourceFiles[i].newline = "\c\L"
break
of '\L', '\0':
gSourceFiles[i].newline = "\L"
break
else: discard
inc pos
close(lex)
const const
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'} Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
@ -61,10 +22,8 @@ proc differ*(line: string, a, b: int, x: string): bool =
let y = line[a..b] let y = line[a..b]
result = cmpIgnoreStyle(y, x) == 0 and y != x result = cmpIgnoreStyle(y, x) == 0 and y != x
proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) = proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PIdent) =
loadFile(info) let line = sourceLine(conf, info)
let line = gSourceFiles[info.fileIndex.int32].lines[info.line.int-1]
var first = min(info.col.int, line.len) var first = min(info.col.int, line.len)
if first < 0: return if first < 0: return
#inc first, skipIgnoreCase(line, "proc ", first) #inc first, skipIgnoreCase(line, "proc ", first)
@ -75,20 +34,18 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
let last = first+identLen(line, first)-1 let last = first+identLen(line, first)-1
if cmpIgnoreStyle(line[first..last], oldSym.s) == 0: if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
var x = line.substr(0, first-1) & newSym.s & line.substr(last+1) var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
system.shallowCopy(gSourceFiles[info.fileIndex.int32].lines[info.line.int-1], x) system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
gSourceFiles[info.fileIndex.int32].dirty = true conf.m.fileInfos[info.fileIndex.int32].dirty = true
#if newSym.s == "File": writeStackTrace() #if newSym.s == "File": writeStackTrace()
proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) = proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PSym) =
replaceDeprecated(info, oldSym.name, newSym.name) replaceDeprecated(conf, info, oldSym.name, newSym.name)
proc replaceComment*(info: TLineInfo) = proc replaceComment*(conf: ConfigRef; info: TLineInfo) =
loadFile(info) let line = sourceLine(conf, info)
let line = gSourceFiles[info.fileIndex.int32].lines[info.line.int-1]
var first = info.col.int var first = info.col.int
if line[first] != '#': inc first if line[first] != '#': inc first
var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
system.shallowCopy(gSourceFiles[info.fileIndex.int32].lines[info.line.int-1], x) system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
gSourceFiles[info.fileIndex.int32].dirty = true conf.m.fileInfos[info.fileIndex.int32].dirty = true

View file

@ -10,7 +10,8 @@
# this unit handles Nim sets; it implements symbolic sets # this unit handles Nim sets; it implements symbolic sets
import import
ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer ast, astalgo, trees, nversion, lineinfos, platform, bitsets, types, renderer,
options
proc inSet*(s: PNode, elem: PNode): bool = proc inSet*(s: PNode, elem: PNode): bool =
assert s.kind == nkCurly assert s.kind == nkCurly
@ -58,10 +59,10 @@ proc someInSet*(s: PNode, a, b: PNode): bool =
return true return true
result = false result = false
proc toBitSet*(s: PNode, b: var TBitSet) = proc toBitSet*(conf: ConfigRef; s: PNode, b: var TBitSet) =
var first, j: BiggestInt var first, j: BiggestInt
first = firstOrd(s.typ.sons[0]) first = firstOrd(conf, s.typ.sons[0])
bitSetInit(b, int(getSize(s.typ))) bitSetInit(b, int(getSize(conf, s.typ)))
for i in countup(0, sonsLen(s) - 1): for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange: if s.sons[i].kind == nkRange:
j = getOrdValue(s.sons[i].sons[0]) j = getOrdValue(s.sons[i].sons[0])
@ -71,13 +72,13 @@ proc toBitSet*(s: PNode, b: var TBitSet) =
else: else:
bitSetIncl(b, getOrdValue(s.sons[i]) - first) bitSetIncl(b, getOrdValue(s.sons[i]) - first)
proc toTreeSet*(s: TBitSet, settype: PType, info: TLineInfo): PNode = proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): PNode =
var var
a, b, e, first: BiggestInt # a, b are interval borders a, b, e, first: BiggestInt # a, b are interval borders
elemType: PType elemType: PType
n: PNode n: PNode
elemType = settype.sons[0] elemType = settype.sons[0]
first = firstOrd(elemType) first = firstOrd(conf, elemType)
result = newNodeI(nkCurly, info) result = newNodeI(nkCurly, info)
result.typ = settype result.typ = settype
result.info = info result.info = info
@ -107,42 +108,42 @@ proc toTreeSet*(s: TBitSet, settype: PType, info: TLineInfo): PNode =
template nodeSetOp(a, b: PNode, op: untyped) {.dirty.} = template nodeSetOp(a, b: PNode, op: untyped) {.dirty.} =
var x, y: TBitSet var x, y: TBitSet
toBitSet(a, x) toBitSet(conf, a, x)
toBitSet(b, y) toBitSet(conf, b, y)
op(x, y) op(x, y)
result = toTreeSet(x, a.typ, a.info) result = toTreeSet(conf, x, a.typ, a.info)
proc unionSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion) proc unionSets*(conf: ConfigRef; a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion)
proc diffSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff) proc diffSets*(conf: ConfigRef; a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff)
proc intersectSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect) proc intersectSets*(conf: ConfigRef; a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect)
proc symdiffSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff) proc symdiffSets*(conf: ConfigRef; a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
proc containsSets*(a, b: PNode): bool = proc containsSets*(conf: ConfigRef; a, b: PNode): bool =
var x, y: TBitSet var x, y: TBitSet
toBitSet(a, x) toBitSet(conf, a, x)
toBitSet(b, y) toBitSet(conf, b, y)
result = bitSetContains(x, y) result = bitSetContains(x, y)
proc equalSets*(a, b: PNode): bool = proc equalSets*(conf: ConfigRef; a, b: PNode): bool =
var x, y: TBitSet var x, y: TBitSet
toBitSet(a, x) toBitSet(conf, a, x)
toBitSet(b, y) toBitSet(conf, b, y)
result = bitSetEquals(x, y) result = bitSetEquals(x, y)
proc complement*(a: PNode): PNode = proc complement*(conf: ConfigRef; a: PNode): PNode =
var x: TBitSet var x: TBitSet
toBitSet(a, x) toBitSet(conf, a, x)
for i in countup(0, high(x)): x[i] = not x[i] for i in countup(0, high(x)): x[i] = not x[i]
result = toTreeSet(x, a.typ, a.info) result = toTreeSet(conf, x, a.typ, a.info)
proc deduplicate*(a: PNode): PNode = proc deduplicate*(conf: ConfigRef; a: PNode): PNode =
var x: TBitSet var x: TBitSet
toBitSet(a, x) toBitSet(conf, a, x)
result = toTreeSet(x, a.typ, a.info) result = toTreeSet(conf, x, a.typ, a.info)
proc cardSet*(a: PNode): BiggestInt = proc cardSet*(conf: ConfigRef; a: PNode): BiggestInt =
var x: TBitSet var x: TBitSet
toBitSet(a, x) toBitSet(conf, a, x)
result = bitSetCard(x) result = bitSetCard(x)
proc setHasRange*(s: PNode): bool = proc setHasRange*(s: PNode): bool =

View file

@ -15,6 +15,6 @@ const
VersionAsString* = system.NimVersion VersionAsString* = system.NimVersion
RodFileVersion* = "1223" # modify this if the rod-format changes! RodFileVersion* = "1223" # modify this if the rod-format changes!
NimCompilerApiVersion* = 1 ## Check for the existance of this before accessing it NimCompilerApiVersion* = 2 ## Check for the existance of this before accessing it
## as older versions of the compiler API do not ## as older versions of the compiler API do not
## declare this. ## declare this.

View file

@ -8,7 +8,8 @@
# #
import import
os, strutils, strtabs, osproc, sets, configuration, platform os, strutils, strtabs, osproc, sets, lineinfos, platform,
prefixmatches
from terminal import isatty from terminal import isatty
@ -73,6 +74,7 @@ type # please make sure we have under 32 options
optNoCppExceptions # use C exception handling even with CPP optNoCppExceptions # use C exception handling even with CPP
optExcessiveStackTrace # fully qualified module filenames optExcessiveStackTrace # fully qualified module filenames
optWholeProject # for 'doc2': output any dependency optWholeProject # for 'doc2': output any dependency
optMixedMode # true if some module triggered C++ codegen
optListFullPaths optListFullPaths
optNoNimblePath optNoNimblePath
optDynlibOverrideAll optDynlibOverrideAll
@ -116,26 +118,65 @@ type
callOperator, callOperator,
parallel, parallel,
destructor, destructor,
notnil, notnil
oldIterTransf
SymbolFilesOption* = enum SymbolFilesOption* = enum
disabledSf, enabledSf, writeOnlySf, readOnlySf, v2Sf disabledSf, writeOnlySf, readOnlySf, v2Sf
ConfigRef* = ref object ## eventually all global configuration should be moved here TSystemCC* = enum
ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
ccTcc, ccPcc, ccUcc, ccIcl, ccIcc
CfileFlag* {.pure.} = enum
Cached, ## no need to recompile this time
External ## file was introduced via .compile pragma
Cfile* = object
cname*, obj*: string
flags*: set[CFileFlag]
CfileList* = seq[Cfile]
Suggest* = ref object
section*: IdeCmd
qualifiedPath*: seq[string]
name*: ptr string # not used beyond sorting purposes; name is also
# part of 'qualifiedPath'
filePath*: string
line*: int # Starts at 1
column*: int # Starts at 0
doc*: string # Not escaped (yet)
forth*: string # type
quality*: range[0..100] # matching quality
isGlobal*: bool # is a global variable
contextFits*: bool # type/non-type context matches
prefix*: PrefixMatch
symkind*: byte
scope*, localUsages*, globalUsages*: int # more usages is better
tokenLen*: int
version*: int
Suggestions* = seq[Suggest]
ConfigRef* = ref object ## every global configuration
## fields marked with '*' are subject to
## the incremental compilation mechanisms
## (+) means "part of the dependency"
target*: Target # (+)
linesCompiled*: int # all lines that have been compiled linesCompiled*: int # all lines that have been compiled
options*: TOptions options*: TOptions # (+)
globalOptions*: TGlobalOptions globalOptions*: TGlobalOptions # (+)
m*: MsgConfig
evalTemplateCounter*: int
evalMacroCounter*: int
exitcode*: int8 exitcode*: int8
cmd*: TCommands # the command cmd*: TCommands # the command
selectedGC*: TGCMode # the selected GC selectedGC*: TGCMode # the selected GC (+)
verbosity*: int # how verbose the compiler is verbosity*: int # how verbose the compiler is
numberOfProcessors*: int # number of processors numberOfProcessors*: int # number of processors
evalExpr*: string # expression for idetools --eval evalExpr*: string # expression for idetools --eval
lastCmdTime*: float # when caas is enabled, we measure each command lastCmdTime*: float # when caas is enabled, we measure each command
symbolFiles*: SymbolFilesOption symbolFiles*: SymbolFilesOption
cppDefines*: HashSet[string] cppDefines*: HashSet[string] # (*)
headerFile*: string headerFile*: string
features*: set[Feature] features*: set[Feature]
arguments*: string ## the arguments to be passed to the program that arguments*: string ## the arguments to be passed to the program that
@ -143,11 +184,13 @@ type
helpWritten*: bool helpWritten*: bool
ideCmd*: IdeCmd ideCmd*: IdeCmd
oldNewlines*: bool oldNewlines*: bool
cCompiler*: TSystemCC
enableNotes*: TNoteKinds enableNotes*: TNoteKinds
disableNotes*: TNoteKinds disableNotes*: TNoteKinds
foreignPackageNotes*: TNoteKinds foreignPackageNotes*: TNoteKinds
notes*: TNoteKinds notes*: TNoteKinds
mainPackageNotes*: TNoteKinds mainPackageNotes*: TNoteKinds
mainPackageId*: int
errorCounter*: int errorCounter*: int
hintCounter*: int hintCounter*: int
warnCounter*: int warnCounter*: int
@ -165,7 +208,7 @@ type
projectPath*: string # holds a path like /home/alice/projects/nim/compiler/ projectPath*: string # holds a path like /home/alice/projects/nim/compiler/
projectFull*: string # projectPath/projectName projectFull*: string # projectPath/projectName
projectIsStdin*: bool # whether we're compiling from stdin projectIsStdin*: bool # whether we're compiling from stdin
projectMainIdx*: int32 # the canonical path id of the main module projectMainIdx*: FileIndex # the canonical path id of the main module
command*: string # the main command (e.g. cc, check, scan, etc) command*: string # the main command (e.g. cc, check, scan, etc)
commandArgs*: seq[string] # any arguments after the main command commandArgs*: seq[string] # any arguments after the main command
keepComments*: bool # whether the parser needs to keep comments keepComments*: bool # whether the parser needs to keep comments
@ -174,6 +217,33 @@ type
docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \ docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \
# The string uses the formatting variables `path` and `line`. # The string uses the formatting variables `path` and `line`.
# the used compiler
cIncludes*: seq[string] # directories to search for included files
cLibs*: seq[string] # directories to search for lib files
cLinkedLibs*: seq[string] # libraries to link
externalToLink*: seq[string] # files to link in addition to the file
# we compiled (*)
linkOptionsCmd*: string
compileOptionsCmd*: seq[string]
linkOptions*: string # (*)
compileOptions*: string # (*)
ccompilerpath*: string
toCompile*: CfileList # (*)
suggestionResultHook*: proc (result: Suggest) {.closure.}
suggestVersion*: int
suggestMaxResults*: int
lastLineInfo*: TLineInfo
writelnHook*: proc (output: string) {.closure.}
structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string;
severity: Severity) {.closure.}
template depConfigFields*(fn) {.dirty.} =
fn(target)
fn(options)
fn(globalOptions)
fn(selectedGC)
const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel}
const const
@ -196,9 +266,11 @@ template newPackageCache*(): untyped =
proc newConfigRef*(): ConfigRef = proc newConfigRef*(): ConfigRef =
result = ConfigRef( result = ConfigRef(
selectedGC: gcRefc, selectedGC: gcRefc,
cCompiler: ccGcc,
verbosity: 1, verbosity: 1,
options: DefaultOptions, options: DefaultOptions,
globalOptions: DefaultGlobalOptions, globalOptions: DefaultGlobalOptions,
m: initMsgConfig(),
evalExpr: "", evalExpr: "",
cppDefines: initSet[string](), cppDefines: initSet[string](),
headerFile: "", features: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic, headerFile: "", features: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic,
@ -216,15 +288,28 @@ proc newConfigRef*(): ConfigRef =
projectPath: "", # holds a path like /home/alice/projects/nim/compiler/ projectPath: "", # holds a path like /home/alice/projects/nim/compiler/
projectFull: "", # projectPath/projectName projectFull: "", # projectPath/projectName
projectIsStdin: false, # whether we're compiling from stdin projectIsStdin: false, # whether we're compiling from stdin
projectMainIdx: 0'i32, # the canonical path id of the main module projectMainIdx: FileIndex(0'i32), # the canonical path id of the main module
command: "", # the main command (e.g. cc, check, scan, etc) command: "", # the main command (e.g. cc, check, scan, etc)
commandArgs: @[], # any arguments after the main command commandArgs: @[], # any arguments after the main command
keepComments: true, # whether the parser needs to keep comments keepComments: true, # whether the parser needs to keep comments
implicitImports: @[], # modules that are to be implicitly imported implicitImports: @[], # modules that are to be implicitly imported
implicitIncludes: @[], # modules that are to be implicitly included implicitIncludes: @[], # modules that are to be implicitly included
docSeeSrcUrl: "", docSeeSrcUrl: "",
arguments: "" cIncludes: @[], # directories to search for included files
cLibs: @[], # directories to search for lib files
cLinkedLibs: @[], # libraries to link
externalToLink: @[],
linkOptionsCmd: "",
compileOptionsCmd: @[],
linkOptions: "",
compileOptions: "",
ccompilerpath: "",
toCompile: @[],
arguments: "",
suggestMaxResults: 10_000
) )
setTargetFromSystem(result.target)
# enable colors by default on terminals # enable colors by default on terminals
if terminal.isatty(stderr): if terminal.isatty(stderr):
incl(result.globalOptions, optUseColors) incl(result.globalOptions, optUseColors)
@ -246,39 +331,39 @@ proc cppDefine*(c: ConfigRef; define: string) =
proc isDefined*(conf: ConfigRef; symbol: string): bool = proc isDefined*(conf: ConfigRef; symbol: string): bool =
if conf.symbols.hasKey(symbol): if conf.symbols.hasKey(symbol):
result = conf.symbols[symbol] != "false" result = conf.symbols[symbol] != "false"
elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0: elif cmpIgnoreStyle(symbol, CPU[conf.target.targetCPU].name) == 0:
result = true result = true
elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0: elif cmpIgnoreStyle(symbol, platform.OS[conf.target.targetOS].name) == 0:
result = true result = true
else: else:
case symbol.normalize case symbol.normalize
of "x86": result = targetCPU == cpuI386 of "x86": result = conf.target.targetCPU == cpuI386
of "itanium": result = targetCPU == cpuIa64 of "itanium": result = conf.target.targetCPU == cpuIa64
of "x8664": result = targetCPU == cpuAmd64 of "x8664": result = conf.target.targetCPU == cpuAmd64
of "posix", "unix": of "posix", "unix":
result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos, result = conf.target.targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
osQnx, osAtari, osAix, osQnx, osAtari, osAix,
osHaiku, osVxWorks, osSolaris, osNetbsd, osHaiku, osVxWorks, osSolaris, osNetbsd,
osFreebsd, osOpenbsd, osDragonfly, osMacosx, osFreebsd, osOpenbsd, osDragonfly, osMacosx,
osAndroid} osAndroid}
of "linux": of "linux":
result = targetOS in {osLinux, osAndroid} result = conf.target.targetOS in {osLinux, osAndroid}
of "bsd": of "bsd":
result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly} result = conf.target.targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly}
of "emulatedthreadvars": of "emulatedthreadvars":
result = platform.OS[targetOS].props.contains(ospLacksThreadVars) result = platform.OS[conf.target.targetOS].props.contains(ospLacksThreadVars)
of "msdos": result = targetOS == osDos of "msdos": result = conf.target.targetOS == osDos
of "mswindows", "win32": result = targetOS == osWindows of "mswindows", "win32": result = conf.target.targetOS == osWindows
of "macintosh": result = targetOS in {osMacos, osMacosx} of "macintosh": result = conf.target.targetOS in {osMacos, osMacosx}
of "sunos": result = targetOS == osSolaris of "sunos": result = conf.target.targetOS == osSolaris
of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian of "littleendian": result = CPU[conf.target.targetCPU].endian == platform.littleEndian
of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian of "bigendian": result = CPU[conf.target.targetCPU].endian == platform.bigEndian
of "cpu8": result = CPU[targetCPU].bit == 8 of "cpu8": result = CPU[conf.target.targetCPU].bit == 8
of "cpu16": result = CPU[targetCPU].bit == 16 of "cpu16": result = CPU[conf.target.targetCPU].bit == 16
of "cpu32": result = CPU[targetCPU].bit == 32 of "cpu32": result = CPU[conf.target.targetCPU].bit == 32
of "cpu64": result = CPU[targetCPU].bit == 64 of "cpu64": result = CPU[conf.target.targetCPU].bit == 64
of "nimrawsetjmp": of "nimrawsetjmp":
result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd, result = conf.target.targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd,
osDragonfly, osMacosx} osDragonfly, osMacosx}
else: discard else: discard
@ -286,7 +371,7 @@ proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc,
proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
template compilationCachePresent*(conf: ConfigRef): untyped = template compilationCachePresent*(conf: ConfigRef): untyped =
conf.symbolFiles in {enabledSf, writeOnlySf} conf.symbolFiles in {v2Sf, writeOnlySf}
# {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {} # {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
template optPreserveOrigSource*(conf: ConfigRef): untyped = template optPreserveOrigSource*(conf: ConfigRef): untyped =

View file

@ -27,7 +27,7 @@ when isMainModule:
outp.close outp.close
import import
llstream, lexer, idents, strutils, ast, astalgo, msgs, options, configuration llstream, lexer, idents, strutils, ast, astalgo, msgs, options, lineinfos
type type
TParser* = object # A TParser object represents a file that TParser* = object # A TParser object represents a file that
@ -40,6 +40,7 @@ type
tok*: TToken # The current token tok*: TToken # The current token
inPragma*: int # Pragma level inPragma*: int # Pragma level
inSemiStmtList*: int inSemiStmtList*: int
emptyNode: PNode
SymbolMode = enum SymbolMode = enum
smNormal, smAllowNil, smAfterDot smNormal, smAllowNil, smAfterDot
@ -93,6 +94,7 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
getTok(p) # read the first token getTok(p) # read the first token
p.firstTok = true p.firstTok = true
p.strongSpaces = strongSpaces p.strongSpaces = strongSpaces
p.emptyNode = newNode(nkEmpty)
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream, proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
cache: IdentCache; config: ConfigRef; cache: IdentCache; config: ConfigRef;
@ -131,7 +133,7 @@ proc rawSkipComment(p: var TParser, node: PNode) =
if node.comment == nil: node.comment = "" if node.comment == nil: node.comment = ""
when defined(nimpretty): when defined(nimpretty):
if p.tok.commentOffsetB > p.tok.commentOffsetA: if p.tok.commentOffsetB > p.tok.commentOffsetA:
add node.comment, fileSection(p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB) add node.comment, fileSection(p.lex.config, p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB)
else: else:
add node.comment, p.tok.literal add node.comment, p.tok.literal
else: else:
@ -333,7 +335,7 @@ proc parseSymbol(p: var TParser, mode = smNormal): PNode =
getTok(p) getTok(p)
else: else:
parMessage(p, errIdentifierExpected, p.tok) parMessage(p, errIdentifierExpected, p.tok)
result = ast.emptyNode result = p.emptyNode
of tkAccent: of tkAccent:
result = newNodeP(nkAccQuoted, p) result = newNodeP(nkAccQuoted, p)
getTok(p) getTok(p)
@ -364,7 +366,7 @@ proc parseSymbol(p: var TParser, mode = smNormal): PNode =
# But: this really sucks for idetools and keywords, so we don't do it # But: this really sucks for idetools and keywords, so we don't do it
# if it is a keyword: # if it is a keyword:
#if not isKeyword(p.tok.tokType): getTok(p) #if not isKeyword(p.tok.tokType): getTok(p)
result = ast.emptyNode result = p.emptyNode
proc colonOrEquals(p: var TParser, a: PNode): PNode = proc colonOrEquals(p: var TParser, a: PNode): PNode =
if p.tok.tokType == tkColon: if p.tok.tokType == tkColon:
@ -703,7 +705,7 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
else: else:
parMessage(p, errExprExpected, p.tok) parMessage(p, errExprExpected, p.tok)
getTok(p) # we must consume a token here to prevend endless loops! getTok(p) # we must consume a token here to prevend endless loops!
result = ast.emptyNode result = p.emptyNode
proc namedParams(p: var TParser, callee: PNode, proc namedParams(p: var TParser, callee: PNode,
kind: TNodeKind, endTok: TTokType): PNode = kind: TNodeKind, endTok: TTokType): PNode =
@ -1015,7 +1017,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
#| paramListColon = paramList? (':' optInd typeDesc)? #| paramListColon = paramList? (':' optInd typeDesc)?
var a: PNode var a: PNode
result = newNodeP(nkFormalParams, p) result = newNodeP(nkFormalParams, p)
addSon(result, ast.emptyNode) # return type addSon(result, p.emptyNode) # return type
let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0 let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0
if hasParLe: if hasParLe:
getTok(p) getTok(p)
@ -1047,13 +1049,13 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
result.sons[0] = parseTypeDesc(p) result.sons[0] = parseTypeDesc(p)
elif not retColon and not hasParle: elif not retColon and not hasParle:
# Mark as "not there" in order to mark for deprecation in the semantic pass: # Mark as "not there" in order to mark for deprecation in the semantic pass:
result = ast.emptyNode result = p.emptyNode
proc optPragmas(p: var TParser): PNode = proc optPragmas(p: var TParser): PNode =
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)): if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
result = parsePragma(p) result = parsePragma(p)
else: else:
result = ast.emptyNode result = p.emptyNode
proc parseDoBlock(p: var TParser; info: TLineInfo): PNode = proc parseDoBlock(p: var TParser; info: TLineInfo): PNode =
#| doBlock = 'do' paramListArrow pragmas? colcom stmt #| doBlock = 'do' paramListArrow pragmas? colcom stmt
@ -1062,7 +1064,9 @@ proc parseDoBlock(p: var TParser; info: TLineInfo): PNode =
colcom(p, result) colcom(p, result)
result = parseStmt(p) result = parseStmt(p)
if params.kind != nkEmpty: if params.kind != nkEmpty:
result = newProcNode(nkDo, info, result, params = params, pragmas = pragmas) result = newProcNode(nkDo, info,
body = result, params = params, name = p.emptyNode, pattern = p.emptyNode,
genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode = proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode =
#| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)? #| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
@ -1075,9 +1079,9 @@ proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode =
if p.tok.tokType == tkEquals and isExpr: if p.tok.tokType == tkEquals and isExpr:
getTok(p) getTok(p)
skipComment(p, result) skipComment(p, result)
result = newProcNode(kind, info, parseStmt(p), result = newProcNode(kind, info, body = parseStmt(p),
params = params, params = params, name = p.emptyNode, pattern = p.emptyNode,
pragmas = pragmas) genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
else: else:
result = newNodeI(nkProcTy, info) result = newNodeI(nkProcTy, info)
if hasSignature: if hasSignature:
@ -1244,8 +1248,8 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
if p.tok.indent >= 0: return if p.tok.indent >= 0: return
var var
openingParams = emptyNode openingParams = p.emptyNode
openingPragmas = emptyNode openingPragmas = p.emptyNode
if p.tok.tokType == tkDo: if p.tok.tokType == tkDo:
getTok(p) getTok(p)
@ -1264,8 +1268,12 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
stmtList.flags.incl nfBlockArg stmtList.flags.incl nfBlockArg
if openingParams.kind != nkEmpty: if openingParams.kind != nkEmpty:
result.add newProcNode(nkDo, stmtList.info, stmtList, result.add newProcNode(nkDo, stmtList.info, body = stmtList,
params = openingParams, pragmas = openingPragmas) params = openingParams,
name = p.emptyNode, pattern = p.emptyNode,
genericParams = p.emptyNode,
pragmas = openingPragmas,
exceptions = p.emptyNode)
else: else:
result.add stmtList result.add stmtList
@ -1424,10 +1432,10 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
getTok(p) getTok(p)
if p.tok.tokType == tkComment: if p.tok.tokType == tkComment:
skipComment(p, result) skipComment(p, result)
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p): elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p):
# NL terminates: # NL terminates:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
else: else:
var e = parseExpr(p) var e = parseExpr(p)
e = postExprBlocks(p, e) e = postExprBlocks(p, e)
@ -1568,7 +1576,7 @@ proc parseBlock(p: var TParser): PNode =
#| blockExpr = 'block' symbol? colcom stmt #| blockExpr = 'block' symbol? colcom stmt
result = newNodeP(nkBlockStmt, p) result = newNodeP(nkBlockStmt, p)
getTokNoInd(p) getTokNoInd(p)
if p.tok.tokType == tkColon: addSon(result, ast.emptyNode) if p.tok.tokType == tkColon: addSon(result, p.emptyNode)
else: addSon(result, parseSymbol(p)) else: addSon(result, parseSymbol(p))
colcom(p, result) colcom(p, result)
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
@ -1586,7 +1594,7 @@ proc parseAsm(p: var TParser): PNode =
result = newNodeP(nkAsmStmt, p) result = newNodeP(nkAsmStmt, p)
getTokNoInd(p) getTokNoInd(p)
if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p)) if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p))
else: addSon(result, ast.emptyNode) else: addSon(result, p.emptyNode)
case p.tok.tokType case p.tok.tokType
of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p)) of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p))
of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p)) of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
@ -1594,7 +1602,7 @@ proc parseAsm(p: var TParser): PNode =
newStrNodeP(nkTripleStrLit, p.tok.literal, p)) newStrNodeP(nkTripleStrLit, p.tok.literal, p))
else: else:
parMessage(p, "the 'asm' statement takes a string literal") parMessage(p, "the 'asm' statement takes a string literal")
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
return return
getTok(p) getTok(p)
@ -1625,13 +1633,13 @@ proc parseGenericParam(p: var TParser): PNode =
optInd(p, result) optInd(p, result)
addSon(result, parseExpr(p)) addSon(result, parseExpr(p))
else: else:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
if p.tok.tokType == tkEquals: if p.tok.tokType == tkEquals:
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
addSon(result, parseExpr(p)) addSon(result, parseExpr(p))
else: else:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
proc parseGenericParamList(p: var TParser): PNode = proc parseGenericParamList(p: var TParser): PNode =
#| genericParamList = '[' optInd #| genericParamList = '[' optInd
@ -1667,22 +1675,22 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
optInd(p, result) optInd(p, result)
addSon(result, identVis(p)) addSon(result, identVis(p))
if p.tok.tokType == tkCurlyLe and p.validInd: addSon(result, p.parsePattern) if p.tok.tokType == tkCurlyLe and p.validInd: addSon(result, p.parsePattern)
else: addSon(result, ast.emptyNode) else: addSon(result, p.emptyNode)
if p.tok.tokType == tkBracketLe and p.validInd: if p.tok.tokType == tkBracketLe and p.validInd:
result.add(p.parseGenericParamList) result.add(p.parseGenericParamList)
else: else:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
addSon(result, p.parseParamList) addSon(result, p.parseParamList)
if p.tok.tokType == tkCurlyDotLe and p.validInd: addSon(result, p.parsePragma) if p.tok.tokType == tkCurlyDotLe and p.validInd: addSon(result, p.parsePragma)
else: addSon(result, ast.emptyNode) else: addSon(result, p.emptyNode)
# empty exception tracking: # empty exception tracking:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
if p.tok.tokType == tkEquals and p.validInd: if p.tok.tokType == tkEquals and p.validInd:
getTok(p) getTok(p)
skipComment(p, result) skipComment(p, result)
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
else: else:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
indAndComment(p, result) indAndComment(p, result)
proc newCommentStmt(p: var TParser): PNode = proc newCommentStmt(p: var TParser): PNode =
@ -1732,7 +1740,7 @@ proc parseConstant(p: var TParser): PNode =
optInd(p, result) optInd(p, result)
addSon(result, parseTypeDesc(p)) addSon(result, parseTypeDesc(p))
else: else:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
eat(p, tkEquals) eat(p, tkEquals)
optInd(p, result) optInd(p, result)
addSon(result, parseExpr(p)) addSon(result, parseExpr(p))
@ -1742,7 +1750,7 @@ proc parseEnum(p: var TParser): PNode =
#| enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+ #| enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+
result = newNodeP(nkEnumTy, p) result = newNodeP(nkEnumTy, p)
getTok(p) getTok(p)
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
optInd(p, result) optInd(p, result)
flexComment(p, result) flexComment(p, result)
# progress guaranteed # progress guaranteed
@ -1813,7 +1821,7 @@ proc parseObjectCase(p: var TParser): PNode =
addSon(a, identWithPragma(p)) addSon(a, identWithPragma(p))
eat(p, tkColon) eat(p, tkColon)
addSon(a, parseTypeDesc(p)) addSon(a, parseTypeDesc(p))
addSon(a, ast.emptyNode) addSon(a, p.emptyNode)
addSon(result, a) addSon(result, a)
if p.tok.tokType == tkColon: getTok(p) if p.tok.tokType == tkColon: getTok(p)
flexComment(p, result) flexComment(p, result)
@ -1872,7 +1880,7 @@ proc parseObjectPart(p: var TParser): PNode =
result = newNodeP(nkNilLit, p) result = newNodeP(nkNilLit, p)
getTok(p) getTok(p)
else: else:
result = ast.emptyNode result = p.emptyNode
proc parseObject(p: var TParser): PNode = proc parseObject(p: var TParser): PNode =
#| object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart #| object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
@ -1881,19 +1889,19 @@ proc parseObject(p: var TParser): PNode =
if p.tok.tokType == tkCurlyDotLe and p.validInd: if p.tok.tokType == tkCurlyDotLe and p.validInd:
addSon(result, parsePragma(p)) addSon(result, parsePragma(p))
else: else:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
if p.tok.tokType == tkOf and p.tok.indent < 0: if p.tok.tokType == tkOf and p.tok.indent < 0:
var a = newNodeP(nkOfInherit, p) var a = newNodeP(nkOfInherit, p)
getTok(p) getTok(p)
addSon(a, parseTypeDesc(p)) addSon(a, parseTypeDesc(p))
addSon(result, a) addSon(result, a)
else: else:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
if p.tok.tokType == tkComment: if p.tok.tokType == tkComment:
skipComment(p, result) skipComment(p, result)
# an initial IND{>} HAS to follow: # an initial IND{>} HAS to follow:
if not realInd(p): if not realInd(p):
addSon(result, emptyNode) addSon(result, p.emptyNode)
return return
addSon(result, parseObjectPart(p)) addSon(result, parseObjectPart(p))
@ -1928,7 +1936,7 @@ proc parseTypeClass(p: var TParser): PNode =
if p.tok.tokType == tkCurlyDotLe and p.validInd: if p.tok.tokType == tkCurlyDotLe and p.validInd:
addSon(result, parsePragma(p)) addSon(result, parsePragma(p))
else: else:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
if p.tok.tokType == tkOf and p.tok.indent < 0: if p.tok.tokType == tkOf and p.tok.indent < 0:
var a = newNodeP(nkOfInherit, p) var a = newNodeP(nkOfInherit, p)
getTok(p) getTok(p)
@ -1939,12 +1947,12 @@ proc parseTypeClass(p: var TParser): PNode =
getTok(p) getTok(p)
addSon(result, a) addSon(result, a)
else: else:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
if p.tok.tokType == tkComment: if p.tok.tokType == tkComment:
skipComment(p, result) skipComment(p, result)
# an initial IND{>} HAS to follow: # an initial IND{>} HAS to follow:
if not realInd(p): if not realInd(p):
addSon(result, emptyNode) addSon(result, p.emptyNode)
else: else:
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
@ -1957,14 +1965,14 @@ proc parseTypeDef(p: var TParser): PNode =
if p.tok.tokType == tkBracketLe and p.validInd: if p.tok.tokType == tkBracketLe and p.validInd:
addSon(result, parseGenericParamList(p)) addSon(result, parseGenericParamList(p))
else: else:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
if p.tok.tokType == tkEquals: if p.tok.tokType == tkEquals:
result.info = parLineInfo(p) result.info = parLineInfo(p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
addSon(result, parseTypeDefAux(p)) addSon(result, parseTypeDefAux(p))
else: else:
addSon(result, ast.emptyNode) addSon(result, p.emptyNode)
indAndComment(p, result) # special extension! indAndComment(p, result) # special extension!
proc parseVarTuple(p: var TParser): PNode = proc parseVarTuple(p: var TParser): PNode =
@ -1979,7 +1987,7 @@ proc parseVarTuple(p: var TParser): PNode =
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
skipComment(p, a) skipComment(p, a)
addSon(result, ast.emptyNode) # no type desc addSon(result, p.emptyNode) # no type desc
optPar(p) optPar(p)
eat(p, tkParRi) eat(p, tkParRi)
eat(p, tkEquals) eat(p, tkEquals)
@ -2040,7 +2048,7 @@ proc simpleStmt(p: var TParser): PNode =
of tkComment: result = newCommentStmt(p) of tkComment: result = newCommentStmt(p)
else: else:
if isExprStart(p): result = parseExprStmt(p) if isExprStart(p): result = parseExprStmt(p)
else: result = ast.emptyNode else: result = p.emptyNode
if result.kind notin {nkEmpty, nkCommentStmt}: skipComment(p, result) if result.kind notin {nkEmpty, nkCommentStmt}: skipComment(p, result)
proc complexOrSimpleStmt(p: var TParser): PNode = proc complexOrSimpleStmt(p: var TParser): PNode =
@ -2136,7 +2144,7 @@ proc parseStmt(p: var TParser): PNode =
of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkFunc, of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkFunc,
tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar: tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar:
parMessage(p, "complex statement requires indentation") parMessage(p, "complex statement requires indentation")
result = ast.emptyNode result = p.emptyNode
else: else:
if p.inSemiStmtList > 0: if p.inSemiStmtList > 0:
result = simpleStmt(p) result = simpleStmt(p)
@ -2173,7 +2181,7 @@ proc parseAll(p: var TParser): PNode =
proc parseTopLevelStmt(p: var TParser): PNode = proc parseTopLevelStmt(p: var TParser): PNode =
## Implements an iterator which, when called repeatedly, returns the next ## Implements an iterator which, when called repeatedly, returns the next
## top-level statement or emptyNode if end of stream. ## top-level statement or emptyNode if end of stream.
result = ast.emptyNode result = p.emptyNode
# progress guaranteed # progress guaranteed
while true: while true:
if p.tok.indent != 0: if p.tok.indent != 0:

View file

@ -10,7 +10,7 @@
## implements some little helper passes ## implements some little helper passes
import import
strutils, ast, astalgo, passes, idents, msgs, options, idgen, configuration strutils, ast, astalgo, passes, idents, msgs, options, idgen, lineinfos
from modulegraphs import ModuleGraph from modulegraphs import ModuleGraph
@ -18,7 +18,7 @@ type
VerboseRef = ref object of TPassContext VerboseRef = ref object of TPassContext
config: ConfigRef config: ConfigRef
proc verboseOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext = proc verboseOpen(graph: ModuleGraph; s: PSym): PPassContext =
#MessageOut('compiling ' + s.name.s); #MessageOut('compiling ' + s.name.s);
result = VerboseRef(config: graph.config) result = VerboseRef(config: graph.config)
rawMessage(graph.config, hintProcessing, s.name.s) rawMessage(graph.config, hintProcessing, s.name.s)

View file

@ -13,24 +13,20 @@
import import
strutils, options, ast, astalgo, llstream, msgs, platform, os, strutils, options, ast, astalgo, llstream, msgs, platform, os,
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
nimsets, syntaxes, times, rodread, idgen, modulegraphs, reorder, rod, nimsets, syntaxes, times, idgen, modulegraphs, reorder, rod,
configuration lineinfos
type type
TPassContext* = object of RootObj # the pass's context TPassContext* = object of RootObj # the pass's context
rd*: PRodReader # != nil if created by "openCached"
PPassContext* = ref TPassContext PPassContext* = ref TPassContext
TPassOpen* = proc (graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext {.nimcall.} TPassOpen* = proc (graph: ModuleGraph; module: PSym): PPassContext {.nimcall.}
TPassOpenCached* =
proc (graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext {.nimcall.}
TPassClose* = proc (graph: ModuleGraph; p: PPassContext, n: PNode): PNode {.nimcall.} TPassClose* = proc (graph: ModuleGraph; p: PPassContext, n: PNode): PNode {.nimcall.}
TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.} TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.}
TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached, TPass* = tuple[open: TPassOpen, process: TPassProcess, close: TPassClose,
process: TPassProcess, close: TPassClose,
isFrontend: bool] isFrontend: bool]
TPassData* = tuple[input: PNode, closeOutput: PNode] TPassData* = tuple[input: PNode, closeOutput: PNode]
@ -41,23 +37,14 @@ type
# This mechanism used to be used for the instantiation of generics. # This mechanism used to be used for the instantiation of generics.
proc makePass*(open: TPassOpen = nil, proc makePass*(open: TPassOpen = nil,
openCached: TPassOpenCached = nil,
process: TPassProcess = nil, process: TPassProcess = nil,
close: TPassClose = nil, close: TPassClose = nil,
isFrontend = false): TPass = isFrontend = false): TPass =
result.open = open result.open = open
result.openCached = openCached
result.close = close result.close = close
result.process = process result.process = process
result.isFrontend = isFrontend result.isFrontend = isFrontend
# the semantic checker needs these:
var
gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex; cache: IdentCache): PSym {.nimcall.}
gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.nimcall.}
# implementation
proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} = proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} =
# can be used by codegen passes to determine whether they should do # can be used by codegen passes to determine whether they should do
# something with `n`. Currently, this ignores `n` and uses the global # something with `n`. Currently, this ignores `n` and uses the global
@ -74,44 +61,34 @@ var
gPasses: array[0..maxPasses - 1, TPass] gPasses: array[0..maxPasses - 1, TPass]
gPassesLen*: int gPassesLen*: int
proc clearPasses* = proc clearPasses*(g: ModuleGraph) =
gPassesLen = 0 gPassesLen = 0
proc registerPass*(p: TPass) = proc registerPass*(g: ModuleGraph; p: TPass) =
gPasses[gPassesLen] = p gPasses[gPassesLen] = p
inc(gPassesLen) inc(gPassesLen)
proc carryPass*(g: ModuleGraph; p: TPass, module: PSym; cache: IdentCache; proc carryPass*(g: ModuleGraph; p: TPass, module: PSym;
m: TPassData): TPassData = m: TPassData): TPassData =
var c = p.open(g, module, cache) var c = p.open(g, module)
result.input = p.process(c, m.input) result.input = p.process(c, m.input)
result.closeOutput = if p.close != nil: p.close(g, c, m.closeOutput) result.closeOutput = if p.close != nil: p.close(g, c, m.closeOutput)
else: m.closeOutput else: m.closeOutput
proc carryPasses*(g: ModuleGraph; nodes: PNode, module: PSym; proc carryPasses*(g: ModuleGraph; nodes: PNode, module: PSym;
cache: IdentCache; passes: TPasses) = passes: TPasses) =
var passdata: TPassData var passdata: TPassData
passdata.input = nodes passdata.input = nodes
for pass in passes: for pass in passes:
passdata = carryPass(g, pass, module, cache, passdata) passdata = carryPass(g, pass, module, passdata)
proc openPasses(g: ModuleGraph; a: var TPassContextArray; proc openPasses(g: ModuleGraph; a: var TPassContextArray;
module: PSym; cache: IdentCache) = module: PSym) =
for i in countup(0, gPassesLen - 1): for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].open): if not isNil(gPasses[i].open):
a[i] = gPasses[i].open(g, module, cache) a[i] = gPasses[i].open(g, module)
else: a[i] = nil else: a[i] = nil
proc openPassesCached(g: ModuleGraph; a: var TPassContextArray, module: PSym,
rd: PRodReader) =
for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].openCached):
a[i] = gPasses[i].openCached(g, module, rd)
if a[i] != nil:
a[i].rd = rd
else:
a[i] = nil
proc closePasses(graph: ModuleGraph; a: var TPassContextArray) = proc closePasses(graph: ModuleGraph; a: var TPassContextArray) =
var m: PNode = nil var m: PNode = nil
for i in countup(0, gPassesLen - 1): for i in countup(0, gPassesLen - 1):
@ -127,19 +104,6 @@ proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool =
if isNil(m): return false if isNil(m): return false
result = true result = true
proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) =
# this implements the code transformation pipeline
var m = n
for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m)
proc closePassesCached(graph: ModuleGraph; a: var TPassContextArray) =
var m: PNode = nil
for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close):
m = gPasses[i].close(graph, a[i], m)
a[i] = nil # free the memory here
proc resolveMod(conf: ConfigRef; module, relativeTo: string): FileIndex = proc resolveMod(conf: ConfigRef; module, relativeTo: string): FileIndex =
let fullPath = findModule(conf, module, relativeTo) let fullPath = findModule(conf, module, relativeTo)
if fullPath.len == 0: if fullPath.len == 0:
@ -151,7 +115,7 @@ proc processImplicits(conf: ConfigRef; implicits: seq[string], nodeKind: TNodeKi
a: var TPassContextArray; m: PSym) = a: var TPassContextArray; m: PSym) =
# XXX fixme this should actually be relative to the config file! # XXX fixme this should actually be relative to the config file!
let gCmdLineInfo = newLineInfo(FileIndex(0), 1, 1) let gCmdLineInfo = newLineInfo(FileIndex(0), 1, 1)
let relativeTo = m.info.toFullPath let relativeTo = toFullPath(conf, m.info)
for module in items(implicits): for module in items(implicits):
# implicit imports should not lead to a module importing itself # implicit imports should not lead to a module importing itself
if m.position != resolveMod(conf, module, relativeTo).int32: if m.position != resolveMod(conf, module, relativeTo).int32:
@ -161,8 +125,7 @@ proc processImplicits(conf: ConfigRef; implicits: seq[string], nodeKind: TNodeKi
importStmt.addSon str importStmt.addSon str
if not processTopLevelStmt(importStmt, a): break if not processTopLevelStmt(importStmt, a): break
proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {.discardable.} =
rd: PRodReader; cache: IdentCache): bool {.discardable.} =
if graph.stopCompile(): return true if graph.stopCompile(): return true
var var
p: TParsers p: TParsers
@ -173,24 +136,17 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
# new module caching mechanism: # new module caching mechanism:
for i in 0..<gPassesLen: for i in 0..<gPassesLen:
if not isNil(gPasses[i].open) and not gPasses[i].isFrontend: if not isNil(gPasses[i].open) and not gPasses[i].isFrontend:
a[i] = gPasses[i].open(graph, module, cache) a[i] = gPasses[i].open(graph, module)
else: else:
a[i] = nil a[i] = nil
var stmtIndex = 0 if not graph.stopCompile():
var doContinue = true let n = loadNode(graph, module)
while doContinue:
let n = loadNode(module, stmtIndex)
if n == nil or graph.stopCompile(): break
#if n.kind == nkImportStmt:
# echo "yes and it's ", n
inc stmtIndex
var m = n var m = n
for i in 0..<gPassesLen: for i in 0..<gPassesLen:
if not isNil(gPasses[i].process) and not gPasses[i].isFrontend: if not isNil(gPasses[i].process) and not gPasses[i].isFrontend:
m = gPasses[i].process(a[i], m) m = gPasses[i].process(a[i], m)
if isNil(m): if isNil(m):
doContinue = false
break break
var m: PNode = nil var m: PNode = nil
@ -198,10 +154,10 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
if not isNil(gPasses[i].close) and not gPasses[i].isFrontend: if not isNil(gPasses[i].close) and not gPasses[i].isFrontend:
m = gPasses[i].close(graph, a[i], m) m = gPasses[i].close(graph, a[i], m)
a[i] = nil a[i] = nil
elif rd == nil: else:
openPasses(graph, a, module, cache) openPasses(graph, a, module)
if stream == nil: if stream == nil:
let filename = fileIdx.toFullPathConsiderDirty let filename = toFullPathConsiderDirty(graph.config, fileIdx)
s = llStreamOpen(filename, fmRead) s = llStreamOpen(filename, fmRead)
if s == nil: if s == nil:
rawMessage(graph.config, errCannotOpenFile, filename) rawMessage(graph.config, errCannotOpenFile, filename)
@ -209,7 +165,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
else: else:
s = stream s = stream
while true: while true:
openParsers(p, fileIdx, s, cache, graph.config) openParsers(p, fileIdx, s, graph.cache, graph.config)
if sfSystemModule notin module.flags: if sfSystemModule notin module.flags:
# XXX what about caching? no processing then? what if I change the # XXX what about caching? no processing then? what if I change the
@ -232,7 +188,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
if n.kind == nkEmpty: break if n.kind == nkEmpty: break
sl.add n sl.add n
if sfReorder in module.flags: if sfReorder in module.flags:
sl = reorder(graph, sl, module, cache) sl = reorder(graph, sl, module)
discard processTopLevelStmt(sl, a) discard processTopLevelStmt(sl, a)
break break
elif not processTopLevelStmt(n, a): break elif not processTopLevelStmt(n, a): break
@ -241,11 +197,4 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
closePasses(graph, a) closePasses(graph, a)
# id synchronization point for more consistent code generation: # id synchronization point for more consistent code generation:
idSynchronizationPoint(1000) idSynchronizationPoint(1000)
else:
openPassesCached(graph, a, module, rd)
var n = loadInitSection(rd)
for i in countup(0, sonsLen(n) - 1):
if graph.stopCompile(): break
processTopLevelStmtCached(n.sons[i], a)
closePassesCached(graph, a)
result = true result = true

View file

@ -77,7 +77,7 @@ proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
if isNil(n.typ): if isNil(n.typ):
result = p.typ.kind in {tyVoid, tyStmt} result = p.typ.kind in {tyVoid, tyStmt}
else: else:
result = sigmatch.argtypeMatches(c.c, p.typ, n.typ) result = sigmatch.argtypeMatches(c.c, p.typ, n.typ, fromHlo = true)
proc isPatternParam(c: PPatternContext, p: PNode): bool {.inline.} = proc isPatternParam(c: PPatternContext, p: PNode): bool {.inline.} =
result = p.kind == nkSym and p.sym.kind == skParam and p.sym.owner == c.owner result = p.kind == nkSym and p.sym.kind == skParam and p.sym.owner == c.owner

View file

@ -22,7 +22,7 @@ type
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris, osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx, osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx,
osAmiga, osAtari, osNetware, osMacos, osMacosx, osHaiku, osAndroid, osVxworks osAmiga, osAtari, osNetware, osMacos, osMacosx, osHaiku, osAndroid, osVxworks
osGenode, osJS, osNimrodVM, osStandalone osGenode, osJS, osNimVM, osStandalone
type type
TInfoOSProp* = enum TInfoOSProp* = enum
@ -162,7 +162,7 @@ const
pathSep: ":", dirSep: "/", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", scriptExt: ".sh", curDir: ".",
exeExt: "", extSep: ".", props: {}), exeExt: "", extSep: ".", props: {}),
(name: "NimrodVM", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", (name: "NimVM", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {}), scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {}),
(name: "Standalone", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", (name: "Standalone", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
@ -175,7 +175,7 @@ type
# alias conditionals to condsyms (end of module). # alias conditionals to condsyms (end of module).
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64, cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
cpuPowerpc64el, cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuMipsel, cpuPowerpc64el, cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuMipsel,
cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430, cpuSparc64, cpuArm, cpuArm64, cpuJS, cpuNimVM, cpuAVR, cpuMSP430, cpuSparc64,
cpuMips64, cpuMips64el, cpuRiscV64 cpuMips64, cpuMips64el, cpuRiscV64
type type
@ -202,7 +202,7 @@ const
(name: "arm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), (name: "arm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
(name: "arm64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), (name: "arm64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "js", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32), (name: "js", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32),
(name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32), (name: "nimvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
(name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16), (name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16),
(name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16), (name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16),
(name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64), (name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
@ -210,44 +210,40 @@ const
(name: "mips64el", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), (name: "mips64el", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "riscv64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64)] (name: "riscv64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64)]
var type
targetCPU*, hostCPU*: TSystemCPU Target* = object
targetOS*, hostOS*: TSystemOS targetCPU*, hostCPU*: TSystemCPU
targetOS*, hostOS*: TSystemOS
intSize*: int
floatSize*: int
ptrSize*: int
tnl*: string # target newline
proc nameToOS*(name: string): TSystemOS proc setTarget*(t: var Target; o: TSystemOS, c: TSystemCPU) =
proc nameToCPU*(name: string): TSystemCPU
var
intSize*: int
floatSize*: int
ptrSize*: int
tnl*: string # target newline
proc setTarget*(o: TSystemOS, c: TSystemCPU) =
assert(c != cpuNone) assert(c != cpuNone)
assert(o != osNone) assert(o != osNone)
#echo "new Target: OS: ", o, " CPU: ", c #echo "new Target: OS: ", o, " CPU: ", c
targetCPU = c t.targetCPU = c
targetOS = o t.targetOS = o
intSize = CPU[c].intSize div 8 # assume no cross-compiling
floatSize = CPU[c].floatSize div 8 t.hostCPU = c
ptrSize = CPU[c].bit div 8 t.hostOS = o
tnl = OS[o].newLine t.intSize = CPU[c].intSize div 8
t.floatSize = CPU[c].floatSize div 8
t.ptrSize = CPU[c].bit div 8
t.tnl = OS[o].newLine
proc nameToOS(name: string): TSystemOS = proc nameToOS*(name: string): TSystemOS =
for i in countup(succ(osNone), high(TSystemOS)): for i in countup(succ(osNone), high(TSystemOS)):
if cmpIgnoreStyle(name, OS[i].name) == 0: if cmpIgnoreStyle(name, OS[i].name) == 0:
return i return i
result = osNone result = osNone
proc nameToCPU(name: string): TSystemCPU = proc nameToCPU*(name: string): TSystemCPU =
for i in countup(succ(cpuNone), high(TSystemCPU)): for i in countup(succ(cpuNone), high(TSystemCPU)):
if cmpIgnoreStyle(name, CPU[i].name) == 0: if cmpIgnoreStyle(name, CPU[i].name) == 0:
return i return i
result = cpuNone result = cpuNone
hostCPU = nameToCPU(system.hostCPU) proc setTargetFromSystem*(t: var Target) =
hostOS = nameToOS(system.hostOS) t.setTarget(nameToOS(system.hostOS), nameToCPU(system.hostCPU))
setTarget(hostOS, hostCPU) # assume no cross-compiling

View file

@ -10,4 +10,15 @@
## Include file that imports all plugins that are active. ## Include file that imports all plugins that are active.
import import
locals / locals, itersgen "../compiler" / [pluginsupport, idents, ast], locals, itersgen
const
plugins: array[2, Plugin] = [
("stdlib", "system", "iterToProc", iterToProcImpl),
("stdlib", "system", "locals", semLocals)
]
proc getPlugin*(ic: IdentCache; fn: PSym): Transformation =
for p in plugins:
if pluginMatches(ic, p, fn): return p.t
return nil

View file

@ -9,11 +9,11 @@
## Plugin to transform an inline iterator into a data structure. ## Plugin to transform an inline iterator into a data structure.
import ".." / [pluginsupport, ast, astalgo, import ".." / [ast, astalgo,
magicsys, lookups, semdata, magicsys, lookups, semdata,
lambdalifting, rodread, msgs] lambdalifting, msgs]
proc iterToProcImpl(c: PContext, n: PNode): PNode = proc iterToProcImpl*(c: PContext, n: PNode): PNode =
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
let iter = n[1] let iter = n[1]
if iter.kind != nkSym or iter.sym.kind != skIterator: if iter.kind != nkSym or iter.sym.kind != skIterator:
@ -40,11 +40,9 @@ proc iterToProcImpl(c: PContext, n: PNode): PNode =
prc.typ.rawAddSon t prc.typ.rawAddSon t
let orig = iter.sym.ast let orig = iter.sym.ast
prc.ast = newProcNode(nkProcDef, n.info, prc.ast = newProcNode(nkProcDef, n.info,
name = newSymNode(prc), body = body, params = orig[paramsPos], name = newSymNode(prc),
params = orig[paramsPos], pattern = c.graph.emptyNode, genericParams = c.graph.emptyNode,
pragmas = orig[pragmasPos], pragmas = orig[pragmasPos], exceptions = c.graph.emptyNode)
body = body)
prc.ast.add iter.sym.ast.sons[resultPos] prc.ast.add iter.sym.ast.sons[resultPos]
addInterfaceDecl(c, prc) addInterfaceDecl(c, prc)
registerPlugin("stdlib", "system", "iterToProc", iterToProcImpl)

View file

@ -9,10 +9,10 @@
## The builtin 'system.locals' implemented as a plugin. ## The builtin 'system.locals' implemented as a plugin.
import "../../" / [pluginsupport, ast, astalgo, import ".." / [pluginsupport, ast, astalgo,
magicsys, lookups, semdata, lowerings] magicsys, lookups, semdata, lowerings]
proc semLocals(c: PContext, n: PNode): PNode = proc semLocals*(c: PContext, n: PNode): PNode =
var counter = 0 var counter = 0
var tupleType = newTypeS(tyTuple, c) var tupleType = newTypeS(tyTuple, c)
result = newNodeIT(nkPar, n.info, tupleType) result = newNodeIT(nkPar, n.info, tupleType)
@ -39,5 +39,3 @@ proc semLocals(c: PContext, n: PNode): PNode =
var a = newSymNode(it, result.info) var a = newSymNode(it, result.info)
if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a) if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a)
result.add(a) result.add(a)
registerPlugin("stdlib", "system", "locals", semLocals)

View file

@ -8,40 +8,26 @@
# #
## Plugin support for the Nim compiler. Right now plugins ## Plugin support for the Nim compiler. Right now plugins
## need to be built with the compiler only: plugins using ## need to be built with the compiler only: plugins using
## DLLs or the FFI will not work. ## DLLs or the FFI will not work.
import ast, semdata, idents import ast, semdata, idents
type type
Transformation* = proc (c: PContext; n: PNode): PNode {.nimcall.} Transformation* = proc (c: PContext; n: PNode): PNode {.nimcall.}
Plugin = ref object Plugin* = tuple
fn, module, package: PIdent package, module, fn: string
t: Transformation t: Transformation
next: Plugin
proc pluginMatches(p: Plugin; s: PSym): bool = proc pluginMatches*(ic: IdentCache; p: Plugin; s: PSym): bool =
if s.name.id != p.fn.id: if s.name.id != ic.getIdent(p.fn).id:
return false return false
let module = s.skipGenericOwner let module = s.skipGenericOwner
if module == nil or module.kind != skModule or if module == nil or module.kind != skModule or
module.name.id != p.module.id: module.name.id != ic.getIdent(p.module).id:
return false return false
let package = module.owner let package = module.owner
if package == nil or package.kind != skPackage or if package == nil or package.kind != skPackage or
package.name.id != p.package.id: package.name.id != ic.getIdent(p.package).id:
return false return false
return true return true
var head: Plugin
proc getPlugin*(fn: PSym): Transformation =
var it = head
while it != nil:
if pluginMatches(it, fn): return it.t
it = it.next
proc registerPlugin*(package, module, fn: string; t: Transformation) =
let oldHead = head
head = Plugin(fn: getIdent(fn), module: getIdent(module),
package: getIdent(package), t: t, next: oldHead)

View file

@ -12,7 +12,7 @@
import import
os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer, os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees, wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees,
rodread, types, lookups, configuration types, lookups, lineinfos
const const
FirstCallConv* = wNimcall FirstCallConv* = wNimcall
@ -24,8 +24,8 @@ const
wCompilerProc, wCore, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, wCompilerProc, wCore, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wCodegenDecl, wAsmNoStackFrame, wError, wDiscardable, wNoInit, wCodegenDecl,
wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, wOverride,
wOverride, wConstructor, wExportNims, wUsed, wLiftLocals} wConstructor, wExportNims, wUsed, wLiftLocals, wStacktrace, wLinetrace}
converterPragmas* = procPragmas converterPragmas* = procPragmas
methodPragmas* = procPragmas+{wBase}-{wImportCpp} methodPragmas* = procPragmas+{wBase}-{wImportCpp}
templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty, templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
@ -82,7 +82,13 @@ proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode =
return it[1] return it[1]
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
# implementation
proc recordPragma(c: PContext; n: PNode; key, val: string; val2 = "") =
var recorded = newNodeI(nkCommentStmt, n.info)
recorded.add newStrNode(key, n.info)
recorded.add newStrNode(val, n.info)
if val2.len > 0: recorded.add newStrNode(val2, n.info)
c.graph.recordStmt(c.graph, c.module, recorded)
const const
errStringLiteralExpected = "string literal expected" errStringLiteralExpected = "string literal expected"
@ -143,7 +149,7 @@ proc processImportCpp(c: PContext; s: PSym, extname: string, info: TLineInfo) =
if c.config.cmd == cmdCompileToC: if c.config.cmd == cmdCompileToC:
let m = s.getModule() let m = s.getModule()
incl(m.flags, sfCompileToCpp) incl(m.flags, sfCompileToCpp)
extccomp.gMixedMode = true incl c.config.globalOptions, optMixedMode
proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) = proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) =
setExternName(c, s, extname, info) setExternName(c, s, extname, info)
@ -227,7 +233,7 @@ proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
proc processCallConv(c: PContext, n: PNode) = proc processCallConv(c: PContext, n: PNode) =
if n.kind in nkPragmaCallKinds and n.len == 2 and n.sons[1].kind == nkIdent: if n.kind in nkPragmaCallKinds and n.len == 2 and n.sons[1].kind == nkIdent:
var sw = whichKeyword(n.sons[1].ident) let sw = whichKeyword(n.sons[1].ident)
case sw case sw
of FirstCallConv..LastCallConv: of FirstCallConv..LastCallConv:
c.optionStack[^1].defaultCC = wordToCallConv(sw) c.optionStack[^1].defaultCC = wordToCallConv(sw)
@ -408,7 +414,7 @@ proc relativeFile(c: PContext; n: PNode; ext=""): string =
var s = expectStrLit(c, n) var s = expectStrLit(c, n)
if ext.len > 0 and splitFile(s).ext == "": if ext.len > 0 and splitFile(s).ext == "":
s = addFileExt(s, ext) s = addFileExt(s, ext)
result = parentDir(n.info.toFullPath) / s result = parentDir(toFullPath(c.config, n.info)) / s
if not fileExists(result): if not fileExists(result):
if isAbsolute(s): result = s if isAbsolute(s): result = s
else: else:
@ -416,6 +422,10 @@ proc relativeFile(c: PContext; n: PNode; ext=""): string =
if result.len == 0: result = s if result.len == 0: result = s
proc processCompile(c: PContext, n: PNode) = proc processCompile(c: PContext, n: PNode) =
proc docompile(c: PContext; it: PNode; src, dest: string) =
var cf = Cfile(cname: src, obj: dest, flags: {CfileFlag.External})
extccomp.addExternalFileToCompile(c.config, cf)
recordPragma(c, it, "compile", src, dest)
proc getStrLit(c: PContext, n: PNode; i: int): string = proc getStrLit(c: PContext, n: PNode; i: int): string =
n.sons[i] = c.semConstExpr(c, n[i]) n.sons[i] = c.semConstExpr(c, n[i])
@ -430,30 +440,31 @@ proc processCompile(c: PContext, n: PNode) =
if it.kind in {nkPar, nkTupleConstr} and it.len == 2: if it.kind in {nkPar, nkTupleConstr} and it.len == 2:
let s = getStrLit(c, it, 0) let s = getStrLit(c, it, 0)
let dest = getStrLit(c, it, 1) let dest = getStrLit(c, it, 1)
var found = parentDir(n.info.toFullPath) / s var found = parentDir(toFullPath(c.config, n.info)) / s
for f in os.walkFiles(found): for f in os.walkFiles(found):
let nameOnly = extractFilename(f) let obj = completeCFilePath(c.config, dest % extractFilename(f))
var cf = Cfile(cname: f, docompile(c, it, f, obj)
obj: completeCFilePath(c.config, dest % nameOnly),
flags: {CfileFlag.External})
extccomp.addExternalFileToCompile(c.config, cf)
else: else:
let s = expectStrLit(c, n) let s = expectStrLit(c, n)
var found = parentDir(n.info.toFullPath) / s var found = parentDir(toFullPath(c.config, n.info)) / s
if not fileExists(found): if not fileExists(found):
if isAbsolute(s): found = s if isAbsolute(s): found = s
else: else:
found = findFile(c.config, s) found = findFile(c.config, s)
if found.len == 0: found = s if found.len == 0: found = s
extccomp.addExternalFileToCompile(c.config, found) let obj = toObjFile(c.config, completeCFilePath(c.config, changeFileExt(found, ""), false))
docompile(c, it, found, obj)
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) = proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
let found = relativeFile(c, n, CC[cCompiler].objExt) let found = relativeFile(c, n, CC[c.config.cCompiler].objExt)
case feature case feature
of linkNormal: extccomp.addExternalFileToLink(c.config, found) of linkNormal:
extccomp.addExternalFileToLink(c.config, found)
recordPragma(c, n, "link", found)
of linkSys: of linkSys:
extccomp.addExternalFileToLink(c.config, let dest = c.config.libpath / completeCFilePath(c.config, found, false)
c.config.libpath / completeCFilePath(c.config, found, false)) extccomp.addExternalFileToLink(c.config, dest)
recordPragma(c, n, "link", dest)
else: internalError(c.config, n.info, "processCommonLink") else: internalError(c.config, n.info, "processCommonLink")
proc pragmaBreakpoint(c: PContext, n: PNode) = proc pragmaBreakpoint(c: PContext, n: PNode) =
@ -484,9 +495,10 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
if c < 0: sub = substr(str, b + 1) if c < 0: sub = substr(str, b + 1)
else: sub = substr(str, b + 1, c - 1) else: sub = substr(str, b + 1, c - 1)
if sub != "": if sub != "":
var e = searchInScopes(con, getIdent(sub)) var e = searchInScopes(con, getIdent(con.cache, sub))
if e != nil: if e != nil:
if e.kind == skStub: loadStub(e) when false:
if e.kind == skStub: loadStub(e)
incl(e.flags, sfUsed) incl(e.flags, sfUsed)
addSon(result, newSymNode(e)) addSon(result, newSymNode(e))
else: else:
@ -553,7 +565,7 @@ proc pragmaLine(c: PContext, n: PNode) =
localError(c.config, n.info, "tuple expected") localError(c.config, n.info, "tuple expected")
else: else:
# sensible default: # sensible default:
n.info = getInfoContext(-1) n.info = getInfoContext(c.config, -1)
proc processPragma(c: PContext, n: PNode, i: int) = proc processPragma(c: PContext, n: PNode, i: int) =
let it = n[i] let it = n[i]
@ -638,7 +650,7 @@ proc deprecatedStmt(c: PContext; outerPragma: PNode) =
let dest = qualifiedLookUp(c, n[1], {checkUndeclared}) let dest = qualifiedLookUp(c, n[1], {checkUndeclared})
if dest == nil or dest.kind in routineKinds: if dest == nil or dest.kind in routineKinds:
localError(c.config, n.info, warnUser, "the .deprecated pragma is unreliable for routines") localError(c.config, n.info, warnUser, "the .deprecated pragma is unreliable for routines")
let src = considerQuotedIdent(c.config, n[0]) let src = considerQuotedIdent(c, n[0])
let alias = newSym(skAlias, src, dest, n[0].info, c.config.options) let alias = newSym(skAlias, src, dest, n[0].info, c.config.options)
incl(alias.flags, sfExported) incl(alias.flags, sfExported)
if sfCompilerProc in dest.flags: markCompilerProc(c, alias) if sfCompilerProc in dest.flags: markCompilerProc(c, alias)
@ -661,7 +673,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
# We return a dummy symbol; later passes over the type will repair it. # We return a dummy symbol; later passes over the type will repair it.
# Generic instantiation needs to know about this too. But we're lazy # Generic instantiation needs to know about this too. But we're lazy
# and perform the lookup on demand instead. # and perform the lookup on demand instead.
result = newSym(skUnknown, considerQuotedIdent(c.config, n), nil, n.info, result = newSym(skUnknown, considerQuotedIdent(c, n), nil, n.info,
c.config.options) c.config.options)
else: else:
result = qualifiedLookUp(c, n, {checkUndeclared}) result = qualifiedLookUp(c, n, {checkUndeclared})
@ -714,7 +726,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
elif key.kind notin nkIdentKinds: elif key.kind notin nkIdentKinds:
n.sons[i] = semCustomPragma(c, it) n.sons[i] = semCustomPragma(c, it)
return return
let ident = considerQuotedIdent(c.config, key) let ident = considerQuotedIdent(c, key)
var userPragma = strTableGet(c.userPragmas, ident) var userPragma = strTableGet(c.userPragmas, ident)
if userPragma != nil: if userPragma != nil:
# number of pragmas increase/decrease with user pragma expansion # number of pragmas increase/decrease with user pragma expansion
@ -727,7 +739,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty
dec c.instCounter dec c.instCounter
else: else:
var k = whichKeyword(ident) let k = whichKeyword(ident)
if k in validPragmas: if k in validPragmas:
case k case k
of wExportc: of wExportc:
@ -736,10 +748,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wImportc: of wImportc:
let name = getOptionalStr(c, it, "$1") let name = getOptionalStr(c, it, "$1")
cppDefine(c.config, name) cppDefine(c.config, name)
recordPragma(c, it, "cppdefine", name)
makeExternImport(c, sym, name, it.info) makeExternImport(c, sym, name, it.info)
of wImportCompilerProc: of wImportCompilerProc:
let name = getOptionalStr(c, it, "$1") let name = getOptionalStr(c, it, "$1")
cppDefine(c.config, name) cppDefine(c.config, name)
recordPragma(c, it, "cppdefine", name)
processImportCompilerProc(c, sym, name, it.info) processImportCompilerProc(c, sym, name, it.info)
of wExtern: setExternName(c, sym, expectStrLit(c, it), it.info) of wExtern: setExternName(c, sym, expectStrLit(c, it), it.info)
of wImmediate: of wImmediate:
@ -832,6 +846,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wCompilerProc, wCore: of wCompilerProc, wCore:
noVal(c, it) # compilerproc may not get a string! noVal(c, it) # compilerproc may not get a string!
cppDefine(c.graph.config, sym.name.s) cppDefine(c.graph.config, sym.name.s)
recordPragma(c, it, "cppdefine", sym.name.s)
if sfFromGeneric notin sym.flags: markCompilerProc(c, sym) if sfFromGeneric notin sym.flags: markCompilerProc(c, sym)
of wProcVar: of wProcVar:
noVal(c, it) noVal(c, it)
@ -894,8 +909,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
noVal(c, it) noVal(c, it)
if sym.typ == nil: invalidPragma(c, it) if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ.flags, tfPacked) else: incl(sym.typ.flags, tfPacked)
of wHint: message(c.config, it.info, hintUser, expectStrLit(c, it)) of wHint:
of wWarning: message(c.config, it.info, warnUser, expectStrLit(c, it)) let s = expectStrLit(c, it)
recordPragma(c, it, "hint", s)
message(c.config, it.info, hintUser, s)
of wWarning:
let s = expectStrLit(c, it)
recordPragma(c, it, "warning", s)
message(c.config, it.info, warnUser, s)
of wError: of wError:
if sym != nil and sym.isRoutine: if sym != nil and sym.isRoutine:
# This is subtle but correct: the error *statement* is only # This is subtle but correct: the error *statement* is only
@ -905,15 +926,23 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
noVal(c, it) noVal(c, it)
incl(sym.flags, sfError) incl(sym.flags, sfError)
else: else:
localError(c.config, it.info, errUser, expectStrLit(c, it)) let s = expectStrLit(c, it)
recordPragma(c, it, "error", s)
localError(c.config, it.info, errUser, s)
of wFatal: fatal(c.config, it.info, errUser, expectStrLit(c, it)) of wFatal: fatal(c.config, it.info, errUser, expectStrLit(c, it))
of wDefine: processDefine(c, it) of wDefine: processDefine(c, it)
of wUndef: processUndef(c, it) of wUndef: processUndef(c, it)
of wCompile: processCompile(c, it) of wCompile: processCompile(c, it)
of wLink: processCommonLink(c, it, linkNormal) of wLink: processCommonLink(c, it, linkNormal)
of wLinksys: processCommonLink(c, it, linkSys) of wLinksys: processCommonLink(c, it, linkSys)
of wPassl: extccomp.addLinkOption(c.config, expectStrLit(c, it)) of wPassl:
of wPassc: extccomp.addCompileOption(c.config, expectStrLit(c, it)) let s = expectStrLit(c, it)
extccomp.addLinkOption(c.config, s)
recordPragma(c, it, "passl", s)
of wPassc:
let s = expectStrLit(c, it)
extccomp.addCompileOption(c.config, s)
recordPragma(c, it, "passc", s)
of wBreakpoint: pragmaBreakpoint(c, it) of wBreakpoint: pragmaBreakpoint(c, it)
of wWatchPoint: pragmaWatchpoint(c, it) of wWatchPoint: pragmaWatchpoint(c, it)
of wPush: of wPush:
@ -1021,9 +1050,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
processExperimental(c, it, sym) processExperimental(c, it, sym)
of wThis: of wThis:
if it.kind in nkPragmaCallKinds and it.len == 2: if it.kind in nkPragmaCallKinds and it.len == 2:
c.selfName = considerQuotedIdent(c.config, it[1]) c.selfName = considerQuotedIdent(c, it[1])
elif it.kind == nkIdent or it.len == 1: elif it.kind == nkIdent or it.len == 1:
c.selfName = getIdent("self") c.selfName = getIdent(c.cache, "self")
else: else:
localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments") localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments")
of wNoRewrite: of wNoRewrite:
@ -1051,13 +1080,13 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
for it in c.optionStack: for it in c.optionStack:
let o = it.otherPragmas let o = it.otherPragmas
if not o.isNil: if not o.isNil:
pushInfoContext(n.info) pushInfoContext(c.config, n.info)
var i = 0 var i = 0
while i < o.len(): while i < o.len():
if singlePragma(c, sym, o, i, validPragmas): if singlePragma(c, sym, o, i, validPragmas):
internalError(c.config, n.info, "implicitPragmas") internalError(c.config, n.info, "implicitPragmas")
inc i inc i
popInfoContext() popInfoContext(c.config)
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags: if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
localError(c.config, n.info, ".dynlib requires .exportc") localError(c.config, n.info, ".dynlib requires .exportc")
@ -1069,8 +1098,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
if sym.loc.r == nil: sym.loc.r = rope(sym.name.s) if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool = proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
if n == nil or n.sons == nil: if n == nil: return false
return false
for p in n: for p in n:
var key = if p.kind in nkPragmaCallKinds and p.len > 1: p[0] else: p var key = if p.kind in nkPragmaCallKinds and p.len > 1: p[0] else: p
@ -1082,7 +1110,7 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
if n == nil: return if n == nil: return
var i = 0 var i = 0
while i < n.len(): while i < n.len:
if singlePragma(c, sym, n, i, validPragmas): break if singlePragma(c, sym, n, i, validPragmas): break
inc i inc i

View file

@ -24,7 +24,7 @@ proc prefixMatch*(p, s: string): PrefixMatch =
# check for prefix/contains: # check for prefix/contains:
while i < L: while i < L:
if s[i] == '_': inc i if s[i] == '_': inc i
if eq(s[i], p[0]): if i < L and eq(s[i], p[0]):
var ii = i+1 var ii = i+1
var jj = 1 var jj = 1
while ii < L and jj < p.len: while ii < L and jj < p.len:
@ -43,10 +43,10 @@ proc prefixMatch*(p, s: string): PrefixMatch =
i = 1 i = 1
var j = 1 var j = 1
while i < s.len: while i < s.len:
if s[i] == '_' and i < s.len-1: if i < s.len-1 and s[i] == '_':
if j < p.len and eq(p[j], s[i+1]): inc j if j < p.len and eq(p[j], s[i+1]): inc j
else: return PrefixMatch.None else: return PrefixMatch.None
if s[i] in {'A'..'Z'} and s[i-1] notin {'A'..'Z'}: if i < s.len and s[i] in {'A'..'Z'} and s[i-1] notin {'A'..'Z'}:
if j < p.len and eq(p[j], s[i]): inc j if j < p.len and eq(p[j], s[i]): inc j
else: return PrefixMatch.None else: return PrefixMatch.None
inc i inc i

View file

@ -73,7 +73,7 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
if (sfExported notin result.flags) and (sfExported in fn.flags): if (sfExported notin result.flags) and (sfExported in fn.flags):
let message = ("public implementation '$1' has non-public " & let message = ("public implementation '$1' has non-public " &
"forward declaration in $2") % "forward declaration in $2") %
[getProcHeader(result), $result.info] [getProcHeader(c.config, result), c.config$result.info]
localError(c.config, fn.info, message) localError(c.config, fn.info, message)
return return
of paramsIncompatible: of paramsIncompatible:

View file

@ -10,7 +10,7 @@
# This module implements the renderer of the standard Nim representation. # This module implements the renderer of the standard Nim representation.
import import
lexer, options, idents, strutils, ast, msgs, configuration lexer, options, idents, strutils, ast, msgs, lineinfos
type type
TRenderFlag* = enum TRenderFlag* = enum
@ -330,14 +330,15 @@ proc ulitAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
proc atom(g: TSrcGen; n: PNode): string = proc atom(g: TSrcGen; n: PNode): string =
when defined(nimpretty): when defined(nimpretty):
doAssert g.config != nil, "g.config not initialized!"
let comment = if n.info.commentOffsetA < n.info.commentOffsetB: let comment = if n.info.commentOffsetA < n.info.commentOffsetB:
" " & fileSection(g.fid, n.info.commentOffsetA, n.info.commentOffsetB) " " & fileSection(g.config, g.fid, n.info.commentOffsetA, n.info.commentOffsetB)
else: else:
"" ""
if n.info.offsetA <= n.info.offsetB: if n.info.offsetA <= n.info.offsetB:
# for some constructed tokens this can not be the case and we're better # for some constructed tokens this can not be the case and we're better
# off to not mess with the offset then. # off to not mess with the offset then.
return fileSection(g.fid, n.info.offsetA, n.info.offsetB) & comment return fileSection(g.config, g.fid, n.info.offsetA, n.info.offsetB) & comment
var f: float32 var f: float32
case n.kind case n.kind
of nkEmpty: result = "" of nkEmpty: result = ""
@ -811,8 +812,8 @@ proc gident(g: var TSrcGen, n: PNode) =
var t: TTokType var t: TTokType
var s = atom(g, n) var s = atom(g, n)
if (s[0] in lexer.SymChars): if s.len > 0 and s[0] in lexer.SymChars:
if (n.kind == nkIdent): if n.kind == nkIdent:
if (n.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or if (n.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
(n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)): (n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
t = tkSymbol t = tkSymbol

View file

@ -2,7 +2,7 @@
import import
intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils, intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils,
sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables, sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables,
configuration lineinfos
type type
DepN = ref object DepN = ref object
@ -11,11 +11,11 @@ type
onStack: bool onStack: bool
kids: seq[DepN] kids: seq[DepN]
hAQ, hIS, hB, hCmd: int hAQ, hIS, hB, hCmd: int
when not defined(release): when defined(debugReorder):
expls: seq[string] expls: seq[string]
DepG = seq[DepN] DepG = seq[DepN]
when not defined(release): when defined(debugReorder):
var idNames = newTable[int, string]() var idNames = newTable[int, string]()
proc newDepN(id: int, pnode: PNode): DepN = proc newDepN(id: int, pnode: PNode): DepN =
@ -30,10 +30,10 @@ proc newDepN(id: int, pnode: PNode): DepN =
result.hIS = -1 result.hIS = -1
result.hB = -1 result.hB = -1
result.hCmd = -1 result.hCmd = -1
when not defined(release): when defined(debugReorder):
result.expls = @[] result.expls = @[]
proc accQuoted(n: PNode): PIdent = proc accQuoted(cache: IdentCache; n: PNode): PIdent =
var id = "" var id = ""
for i in 0 ..< n.len: for i in 0 ..< n.len:
let x = n[i] let x = n[i]
@ -41,33 +41,33 @@ proc accQuoted(n: PNode): PIdent =
of nkIdent: id.add(x.ident.s) of nkIdent: id.add(x.ident.s)
of nkSym: id.add(x.sym.name.s) of nkSym: id.add(x.sym.name.s)
else: discard else: discard
result = getIdent(id) result = getIdent(cache, id)
proc addDecl(n: PNode; declares: var IntSet) = proc addDecl(cache: IdentCache; n: PNode; declares: var IntSet) =
case n.kind case n.kind
of nkPostfix: addDecl(n[1], declares) of nkPostfix: addDecl(cache, n[1], declares)
of nkPragmaExpr: addDecl(n[0], declares) of nkPragmaExpr: addDecl(cache, n[0], declares)
of nkIdent: of nkIdent:
declares.incl n.ident.id declares.incl n.ident.id
when not defined(release): when defined(debugReorder):
idNames[n.ident.id] = n.ident.s idNames[n.ident.id] = n.ident.s
of nkSym: of nkSym:
declares.incl n.sym.name.id declares.incl n.sym.name.id
when not defined(release): when defined(debugReorder):
idNames[n.sym.name.id] = n.sym.name.s idNames[n.sym.name.id] = n.sym.name.s
of nkAccQuoted: of nkAccQuoted:
let a = accQuoted(n) let a = accQuoted(cache, n)
declares.incl a.id declares.incl a.id
when not defined(release): when defined(debugReorder):
idNames[a.id] = a.s idNames[a.id] = a.s
of nkEnumFieldDef: of nkEnumFieldDef:
addDecl(n[0], declares) addDecl(cache, n[0], declares)
else: discard else: discard
proc computeDeps(n: PNode, declares, uses: var IntSet; topLevel: bool) = proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLevel: bool) =
template deps(n) = computeDeps(n, declares, uses, false) template deps(n) = computeDeps(cache, n, declares, uses, false)
template decl(n) = template decl(n) =
if topLevel: addDecl(n, declares) if topLevel: addDecl(cache, n, declares)
case n.kind case n.kind
of procDefs, nkMacroDef, nkTemplateDef: of procDefs, nkMacroDef, nkTemplateDef:
decl(n[0]) decl(n[0])
@ -93,11 +93,11 @@ proc computeDeps(n: PNode, declares, uses: var IntSet; topLevel: bool) =
deps(n[i]) deps(n[i])
of nkIdent: uses.incl n.ident.id of nkIdent: uses.incl n.ident.id
of nkSym: uses.incl n.sym.name.id of nkSym: uses.incl n.sym.name.id
of nkAccQuoted: uses.incl accQuoted(n).id of nkAccQuoted: uses.incl accQuoted(cache, n).id
of nkOpenSymChoice, nkClosedSymChoice: of nkOpenSymChoice, nkClosedSymChoice:
uses.incl n.sons[0].sym.name.id uses.incl n.sons[0].sym.name.id
of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt: of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
for i in 0..<len(n): computeDeps(n[i], declares, uses, topLevel) for i in 0..<len(n): computeDeps(cache, n[i], declares, uses, topLevel)
of nkPragma: of nkPragma:
let a = n.sons[0] let a = n.sons[0]
if a.kind == nkExprColonExpr and a.sons[0].kind == nkIdent and if a.kind == nkExprColonExpr and a.sons[0].kind == nkIdent and
@ -136,15 +136,13 @@ proc hasIncludes(n:PNode): bool =
if a.kind == nkIncludeStmt: if a.kind == nkIncludeStmt:
return true return true
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode {.procvar.} =
cache: IdentCache): PNode {.procvar.} = result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
result = syntaxes.parseFile(fileIdx, cache, graph.config)
graph.addDep(s, fileIdx) graph.addDep(s, fileIdx)
graph.addIncludeDep(FileIndex s.position, fileIdx) graph.addIncludeDep(FileIndex s.position, fileIdx)
proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode, proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
modulePath: string, includedFiles: var IntSet, modulePath: string, includedFiles: var IntSet): PNode =
cache: IdentCache): PNode =
# Parses includes and injects them in the current tree # Parses includes and injects them in the current tree
if not n.hasIncludes: if not n.hasIncludes:
return n return n
@ -155,11 +153,12 @@ proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
var f = checkModuleName(graph.config, a.sons[i]) var f = checkModuleName(graph.config, a.sons[i])
if f != InvalidFileIDX: if f != InvalidFileIDX:
if containsOrIncl(includedFiles, f.int): if containsOrIncl(includedFiles, f.int):
localError(graph.config, a.info, "recursive dependency: '$1'" % f.toFilename) localError(graph.config, a.info, "recursive dependency: '$1'" %
toFilename(graph.config, f))
else: else:
let nn = includeModule(graph, module, f, cache) let nn = includeModule(graph, module, f)
let nnn = expandIncludes(graph, module, nn, modulePath, let nnn = expandIncludes(graph, module, nn, modulePath,
includedFiles, cache) includedFiles)
excl(includedFiles, f.int) excl(includedFiles, f.int)
for b in nnn: for b in nnn:
result.add b result.add b
@ -215,7 +214,7 @@ proc mergeSections(conf: ConfigRef; comps: seq[seq[DepN]], res: PNode) =
# consecutive type and const sections # consecutive type and const sections
var wmsg = "Circular dependency detected. reorder pragma may not be able to" & var wmsg = "Circular dependency detected. reorder pragma may not be able to" &
" reorder some nodes properely" " reorder some nodes properely"
when not defined(release): when defined(debugReorder):
wmsg &= ":\n" wmsg &= ":\n"
for i in 0..<cs.len-1: for i in 0..<cs.len-1:
for j in i..<cs.len: for j in i..<cs.len:
@ -354,13 +353,13 @@ proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
if j < i and nj.hasCommand and niHasCmd: if j < i and nj.hasCommand and niHasCmd:
# Preserve order for commands and calls # Preserve order for commands and calls
ni.kids.add nj ni.kids.add nj
when not defined(release): when defined(debugReorder):
ni.expls.add "both have commands and one comes after the other" ni.expls.add "both have commands and one comes after the other"
elif j < i and nj.hasImportStmt: elif j < i and nj.hasImportStmt:
# Every node that comes after an import statement must # Every node that comes after an import statement must
# depend on that import # depend on that import
ni.kids.add nj ni.kids.add nj
when not defined(release): when defined(debugReorder):
ni.expls.add "parent is, or contains, an import statement and child comes after it" ni.expls.add "parent is, or contains, an import statement and child comes after it"
elif j < i and niHasBody and nj.hasAccQuotedDef: elif j < i and niHasBody and nj.hasAccQuotedDef:
# Every function, macro, template... with a body depends # Every function, macro, template... with a body depends
@ -368,13 +367,13 @@ proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
# That's because it is hard to detect the use of functions # That's because it is hard to detect the use of functions
# like "[]=", "[]", "or" ... in their bodies. # like "[]=", "[]", "or" ... in their bodies.
ni.kids.add nj ni.kids.add nj
when not defined(release): when defined(debugReorder):
ni.expls.add "one declares a quoted identifier and the other has a body and comes after it" ni.expls.add "one declares a quoted identifier and the other has a body and comes after it"
elif j < i and niHasBody and not nj.hasBody and elif j < i and niHasBody and not nj.hasBody and
intersects(deps[i][0], declares): intersects(deps[i][0], declares):
# Keep function declaration before function definition # Keep function declaration before function definition
ni.kids.add nj ni.kids.add nj
when not defined(release): when defined(debugReorder):
for dep in deps[i][0]: for dep in deps[i][0]:
if dep in declares: if dep in declares:
ni.expls.add "one declares \"" & idNames[dep] & "\" and the other defines it" ni.expls.add "one declares \"" & idNames[dep] & "\" and the other defines it"
@ -382,7 +381,7 @@ proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
for d in declares: for d in declares:
if uses.contains(d): if uses.contains(d):
ni.kids.add nj ni.kids.add nj
when not defined(release): when defined(debugReorder):
ni.expls.add "one declares \"" & idNames[d] & "\" and the other uses it" ni.expls.add "one declares \"" & idNames[d] & "\" and the other uses it"
proc strongConnect(v: var DepN, idx: var int, s: var seq[DepN], proc strongConnect(v: var DepN, idx: var int, s: var seq[DepN],
@ -426,19 +425,19 @@ proc hasForbiddenPragma(n: PNode): bool =
a[0].ident.s == "push": a[0].ident.s == "push":
return true return true
proc reorder*(graph: ModuleGraph, n: PNode, module: PSym, cache: IdentCache): PNode = proc reorder*(graph: ModuleGraph, n: PNode, module: PSym): PNode =
if n.hasForbiddenPragma: if n.hasForbiddenPragma:
return n return n
var includedFiles = initIntSet() var includedFiles = initIntSet()
let mpath = module.fileIdx.toFullPath let mpath = toFullPath(graph.config, module.fileIdx)
let n = expandIncludes(graph, module, n, mpath, let n = expandIncludes(graph, module, n, mpath,
includedFiles, cache).splitSections includedFiles).splitSections
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
var deps = newSeq[(IntSet, IntSet)](n.len) var deps = newSeq[(IntSet, IntSet)](n.len)
for i in 0..<n.len: for i in 0..<n.len:
deps[i][0] = initIntSet() deps[i][0] = initIntSet()
deps[i][1] = initIntSet() deps[i][1] = initIntSet()
computeDeps(n[i], deps[i][0], deps[i][1], true) computeDeps(graph.cache, n[i], deps[i][0], deps[i][1], true)
var g = buildGraph(n, deps) var g = buildGraph(n, deps)
let comps = getStrongComponents(g) let comps = getStrongComponents(g)

View file

@ -9,18 +9,21 @@
## This module implements the canonalization for the various caching mechanisms. ## This module implements the canonalization for the various caching mechanisms.
import ast, idgen, msgs import ast, idgen, lineinfos, msgs, incremental, modulegraphs
when not defined(nimSymbolfiles): when not nimIncremental:
template setupModuleCache* = discard template setupModuleCache*(g: ModuleGraph) = discard
template storeNode*(module: PSym; n: PNode) = discard template storeNode*(g: ModuleGraph; module: PSym; n: PNode) = discard
template loadNode*(module: PSym; index: var int): PNode = PNode(nil) template loadNode*(g: ModuleGraph; module: PSym): PNode = newNode(nkStmtList)
template getModuleId*(fileIdx: FileIndex; fullpath: string): int = getID() template getModuleId*(g: ModuleGraph; fileIdx: FileIndex; fullpath: string): int = getID()
template addModuleDep*(module, fileIdx: FileIndex; isIncludeFile: bool) = discard template addModuleDep*(g: ModuleGraph; module, fileIdx: FileIndex; isIncludeFile: bool) = discard
template storeRemaining*(module: PSym) = discard template storeRemaining*(g: ModuleGraph; module: PSym) = discard
else: else:
include rodimpl include rodimpl
# idea for testing all this logic: *Always* load the AST from the DB, whether
# we already have it in RAM or not!

View file

@ -10,59 +10,67 @@
## This module implements the new compilation cache. ## This module implements the new compilation cache.
import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types, import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types,
renderer, rodutils, std / sha1, idents, astalgo, magicsys renderer, rodutils, idents, astalgo, btrees, magicsys, cgmeth, extccomp,
btrees, trees, condsyms, nversion
## Todo: ## Todo:
## - Implement the 'import' replay logic so that the codegen runs over ## - Dependency computation should use *signature* hashes in order to
## dependent modules.
## - Make conditional symbols and the configuration part of a module's
## dependencies.
## - Test multi methods.
## - Implement the limited VM support based on sets.
## - Depencency computation should use signature hashes in order to
## avoid recompiling dependent modules. ## avoid recompiling dependent modules.
## - Patch the rest of the compiler to do lazy loading of proc bodies.
## - Patch the C codegen to cache proc bodies and maybe types.
var db: DbConn template db(): DbConn = g.incr.db
proc hashFileCached(fileIdx: int32; fullpath: string): string = proc encodeConfig(g: ModuleGraph): string =
result = msgs.getHash(fileIdx) result = newStringOfCap(100)
if result.len == 0: result.add RodFileVersion
result = $secureHashFile(fullpath) for d in definedSymbolNames(g.config.symbols):
msgs.setHash(fileIdx, result) result.add ' '
result.add d
proc needsRecompile(fileIdx: int32; fullpath: string; cycleCheck: var IntSet): bool = template serialize(field) =
result.add ' '
result.add($g.config.field)
depConfigFields(serialize)
proc needsRecompile(g: ModuleGraph; fileIdx: FileIndex; fullpath: string;
cycleCheck: var IntSet): bool =
let root = db.getRow(sql"select id, fullhash from filenames where fullpath = ?", let root = db.getRow(sql"select id, fullhash from filenames where fullpath = ?",
fullpath) fullpath)
if root[0].len == 0: return true if root[0].len == 0: return true
if root[1] != hashFileCached(fileIdx, fullpath): if root[1] != hashFileCached(g.config, fileIdx, fullpath):
return true return true
# cycle detection: assume "not changed" is correct. # cycle detection: assume "not changed" is correct.
if cycleCheck.containsOrIncl(fileIdx): if cycleCheck.containsOrIncl(int fileIdx):
return false return false
# check dependencies (recursively): # check dependencies (recursively):
for row in db.fastRows(sql"select fullpath from filenames where id in (select dependency from deps where module = ?)", for row in db.fastRows(sql"select fullpath from filenames where id in (select dependency from deps where module = ?)",
root[0]): root[0]):
let dep = row[0] let dep = row[0]
if needsRecompile(dep.fileInfoIdx, dep, cycleCheck): if needsRecompile(g, g.config.fileInfoIdx(dep), dep, cycleCheck):
return true return true
return false return false
proc getModuleId*(fileIdx: int32; fullpath: string): int = proc getModuleId*(g: ModuleGraph; fileIdx: FileIndex; fullpath: string): int =
if gSymbolFiles != v2Sf: return getID() if g.config.symbolFiles in {disabledSf, writeOnlySf} or
let module = db.getRow( g.incr.configChanged:
sql"select id, fullHash from modules where fullpath = ?", fullpath) return getID()
let currentFullhash = hashFileCached(fileIdx, fullpath) let module = g.incr.db.getRow(
sql"select id, fullHash, nimid from modules where fullpath = ?", fullpath)
let currentFullhash = hashFileCached(g.config, fileIdx, fullpath)
if module[0].len == 0: if module[0].len == 0:
result = int db.insertID(sql"insert into modules(fullpath, interfHash, fullHash) values (?, ?, ?)", result = getID()
fullpath, "", currentFullhash) db.exec(sql"insert into modules(fullpath, interfHash, fullHash, nimid) values (?, ?, ?, ?)",
fullpath, "", currentFullhash, result)
else: else:
result = parseInt(module[0]) result = parseInt(module[2])
if currentFullhash == module[1]: if currentFullhash == module[1]:
# not changed, so use the cached AST (even if it might be wrong # not changed, so use the cached AST:
# due to its dependencies):
doAssert(result != 0) doAssert(result != 0)
var cycleCheck = initIntSet() var cycleCheck = initIntSet()
if not needsRecompile(fileIdx, fullpath, cycleCheck): if not needsRecompile(g, fileIdx, fullpath, cycleCheck):
echo "cached successfully! ", fullpath
return -result return -result
db.exec(sql"update modules set fullHash = ? where id = ?", currentFullhash, module[0]) db.exec(sql"update modules set fullHash = ? where id = ?", currentFullhash, module[0])
db.exec(sql"delete from deps where module = ?", module[0]) db.exec(sql"delete from deps where module = ?", module[0])
@ -71,60 +79,17 @@ proc getModuleId*(fileIdx: int32; fullpath: string): int =
db.exec(sql"delete from toplevelstmts where module = ?", module[0]) db.exec(sql"delete from toplevelstmts where module = ?", module[0])
db.exec(sql"delete from statics where module = ?", module[0]) db.exec(sql"delete from statics where module = ?", module[0])
type proc pushType(w: var Writer, t: PType) =
TRodWriter = object
module: PSym
sstack: seq[PSym] # a stack of symbols to process
tstack: seq[PType] # a stack of types to process
tmarks, smarks: IntSet
forwardedSyms: seq[PSym]
PRodWriter = var TRodWriter
proc initRodWriter(module: PSym): TRodWriter =
result = TRodWriter(module: module, sstack: @[], tstack: @[],
tmarks: initIntSet(), smarks: initIntSet(), forwardedSyms: @[])
when false:
proc getDefines(): string =
result = ""
for d in definedSymbolNames():
if result.len != 0: add(result, " ")
add(result, d)
const
rodNL = "\L"
proc pushType(w: PRodWriter, t: PType) =
if not containsOrIncl(w.tmarks, t.id): if not containsOrIncl(w.tmarks, t.id):
w.tstack.add(t) w.tstack.add(t)
proc pushSym(w: PRodWriter, s: PSym) = proc pushSym(w: var Writer, s: PSym) =
if not containsOrIncl(w.smarks, s.id): if not containsOrIncl(w.smarks, s.id):
w.sstack.add(s) w.sstack.add(s)
proc toDbFileId(fileIdx: int32): int = template w: untyped = g.incr.w
if fileIdx == -1: return -1
let fullpath = fileIdx.toFullPath
let row = db.getRow(sql"select id, fullhash from filenames where fullpath = ?",
fullpath)
let id = row[0]
let fullhash = hashFileCached(fileIdx, fullpath)
if id.len == 0:
result = int db.insertID(sql"insert into filenames(fullpath, fullhash) values (?, ?)",
fullpath, fullhash)
else:
if row[1] != fullhash:
db.exec(sql"update filenames set fullhash = ? where fullpath = ?", fullhash, fullpath)
result = parseInt(id)
proc fromDbFileId(dbId: int): int32 = proc encodeNode(g: ModuleGraph; fInfo: TLineInfo, n: PNode,
if dbId == -1: return -1
let fullpath = db.getValue(sql"select fullpath from filenames where id = ?", dbId)
doAssert fullpath.len > 0, "cannot find file name for DB ID " & $dbId
result = fileInfoIdx(fullpath)
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
result: var string) = result: var string) =
if n == nil: if n == nil:
# nil nodes have to be stored too: # nil nodes have to be stored too:
@ -139,14 +104,14 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
result.add('?') result.add('?')
encodeVInt(n.info.col, result) encodeVInt(n.info.col, result)
result.add(',') result.add(',')
encodeVInt(n.info.line, result) encodeVInt(int n.info.line, result)
result.add(',') result.add(',')
encodeVInt(toDbFileId(n.info.fileIndex), result) encodeVInt(toDbFileId(g.incr, g.config, n.info.fileIndex), result)
elif fInfo.line != n.info.line: elif fInfo.line != n.info.line:
result.add('?') result.add('?')
encodeVInt(n.info.col, result) encodeVInt(n.info.col, result)
result.add(',') result.add(',')
encodeVInt(n.info.line, result) encodeVInt(int n.info.line, result)
elif fInfo.col != n.info.col: elif fInfo.col != n.info.col:
result.add('?') result.add('?')
encodeVInt(n.info.col, result) encodeVInt(n.info.col, result)
@ -182,10 +147,10 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
pushSym(w, n.sym) pushSym(w, n.sym)
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
encodeNode(w, n.info, n.sons[i], result) encodeNode(g, n.info, n.sons[i], result)
add(result, ')') add(result, ')')
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = proc encodeLoc(g: ModuleGraph; loc: TLoc, result: var string) =
var oldLen = result.len var oldLen = result.len
result.add('<') result.add('<')
if loc.k != low(loc.k): encodeVInt(ord(loc.k), result) if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
@ -197,9 +162,7 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
encodeVInt(cast[int32](loc.flags), result) encodeVInt(cast[int32](loc.flags), result)
if loc.lode != nil: if loc.lode != nil:
add(result, '^') add(result, '^')
encodeNode(w, unknownLineInfo(), loc.lode, result) encodeNode(g, unknownLineInfo(), loc.lode, result)
#encodeVInt(cast[int32](loc.t.id), result)
#pushType(w, loc.t)
if loc.r != nil: if loc.r != nil:
add(result, '!') add(result, '!')
encodeStr($loc.r, result) encodeStr($loc.r, result)
@ -209,13 +172,13 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
else: else:
add(result, '>') add(result, '>')
proc encodeType(w: PRodWriter, t: PType, result: var string) = proc encodeType(g: ModuleGraph, t: PType, result: var string) =
if t == nil: if t == nil:
# nil nodes have to be stored too: # nil nodes have to be stored too:
result.add("[]") result.add("[]")
return return
# we need no surrounding [] here because the type is in a line of its own # we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: internalError("encodeType: tyForward") if t.kind == tyForward: internalError(g.config, "encodeType: tyForward")
# for the new rodfile viewer we use a preceding [ so that the data section # for the new rodfile viewer we use a preceding [ so that the data section
# can easily be disambiguated: # can easily be disambiguated:
add(result, '[') add(result, '[')
@ -223,7 +186,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
add(result, '+') add(result, '+')
encodeVInt(t.id, result) encodeVInt(t.id, result)
if t.n != nil: if t.n != nil:
encodeNode(w, w.module.info, t.n, result) encodeNode(g, unknownLineInfo(), t.n, result)
if t.flags != {}: if t.flags != {}:
add(result, '$') add(result, '$')
encodeVInt(cast[int32](t.flags), result) encodeVInt(cast[int32](t.flags), result)
@ -269,7 +232,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
add(result, '\20') add(result, '\20')
encodeVInt(s.id, result) encodeVInt(s.id, result)
pushSym(w, s) pushSym(w, s)
encodeLoc(w, t.loc, result) encodeLoc(g, t.loc, result)
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
if t.sons[i] == nil: if t.sons[i] == nil:
add(result, "^()") add(result, "^()")
@ -278,15 +241,15 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
encodeVInt(t.sons[i].id, result) encodeVInt(t.sons[i].id, result)
pushType(w, t.sons[i]) pushType(w, t.sons[i])
proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) = proc encodeLib(g: ModuleGraph, lib: PLib, info: TLineInfo, result: var string) =
add(result, '|') add(result, '|')
encodeVInt(ord(lib.kind), result) encodeVInt(ord(lib.kind), result)
add(result, '|') add(result, '|')
encodeStr($lib.name, result) encodeStr($lib.name, result)
add(result, '|') add(result, '|')
encodeNode(w, info, lib.path, result) encodeNode(g, info, lib.path, result)
proc encodeInstantiations(w: PRodWriter; s: seq[PInstantiation]; proc encodeInstantiations(g: ModuleGraph; s: seq[PInstantiation];
result: var string) = result: var string) =
for t in s: for t in s:
result.add('\15') result.add('\15')
@ -299,7 +262,7 @@ proc encodeInstantiations(w: PRodWriter; s: seq[PInstantiation];
result.add('\20') result.add('\20')
encodeVInt(t.compilesId, result) encodeVInt(t.compilesId, result)
proc encodeSym(w: PRodWriter, s: PSym, result: var string) = proc encodeSym(g: ModuleGraph, s: PSym, result: var string) =
if s == nil: if s == nil:
# nil nodes have to be stored too: # nil nodes have to be stored too:
result.add("{}") result.add("{}")
@ -317,9 +280,9 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
result.add('?') result.add('?')
if s.info.col != -1'i16: encodeVInt(s.info.col, result) if s.info.col != -1'i16: encodeVInt(s.info.col, result)
result.add(',') result.add(',')
if s.info.line != -1'i16: encodeVInt(s.info.line, result) encodeVInt(int s.info.line, result)
result.add(',') result.add(',')
encodeVInt(toDbFileId(s.info.fileIndex), result) encodeVInt(toDbFileId(g.incr, g.config, s.info.fileIndex), result)
if s.owner != nil: if s.owner != nil:
result.add('*') result.add('*')
encodeVInt(s.owner.id, result) encodeVInt(s.owner.id, result)
@ -338,11 +301,11 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
if s.offset != - 1: if s.offset != - 1:
result.add('`') result.add('`')
encodeVInt(s.offset, result) encodeVInt(s.offset, result)
encodeLoc(w, s.loc, result) encodeLoc(g, s.loc, result)
if s.annex != nil: encodeLib(w, s.annex, s.info, result) if s.annex != nil: encodeLib(g, s.annex, s.info, result)
if s.constraint != nil: if s.constraint != nil:
add(result, '#') add(result, '#')
encodeNode(w, unknownLineInfo(), s.constraint, result) encodeNode(g, unknownLineInfo(), s.constraint, result)
case s.kind case s.kind
of skType, skGenericParam: of skType, skGenericParam:
for t in s.typeInstCache: for t in s.typeInstCache:
@ -350,13 +313,13 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
encodeVInt(t.id, result) encodeVInt(t.id, result)
pushType(w, t) pushType(w, t)
of routineKinds: of routineKinds:
encodeInstantiations(w, s.procInstCache, result) encodeInstantiations(g, s.procInstCache, result)
if s.gcUnsafetyReason != nil: if s.gcUnsafetyReason != nil:
result.add('\16') result.add('\16')
encodeVInt(s.gcUnsafetyReason.id, result) encodeVInt(s.gcUnsafetyReason.id, result)
pushSym(w, s.gcUnsafetyReason) pushSym(w, s.gcUnsafetyReason)
of skModule, skPackage: of skModule, skPackage:
encodeInstantiations(w, s.usedGenerics, result) encodeInstantiations(g, s.usedGenerics, result)
# we don't serialize: # we don't serialize:
#tab*: TStrTable # interface table for modules #tab*: TStrTable # interface table for modules
of skLet, skVar, skField, skForVar: of skLet, skVar, skField, skForVar:
@ -374,105 +337,93 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
# we used to attempt to save space here by only storing a dummy AST if # we used to attempt to save space here by only storing a dummy AST if
# it is not necessary, but Nim's heavy compile-time evaluation features # it is not necessary, but Nim's heavy compile-time evaluation features
# make that unfeasible nowadays: # make that unfeasible nowadays:
encodeNode(w, s.info, s.ast, result) encodeNode(g, s.info, s.ast, result)
proc storeSym(w: PRodWriter; s: PSym) = proc storeSym(g: ModuleGraph; s: PSym) =
if sfForward in s.flags and s.kind != skModule: if sfForward in s.flags and s.kind != skModule:
w.forwardedSyms.add s w.forwardedSyms.add s
return return
var buf = newStringOfCap(160) var buf = newStringOfCap(160)
encodeSym(w, s, buf) encodeSym(g, s, buf)
# XXX only store the name for exported symbols in order to speed up lookup # XXX only store the name for exported symbols in order to speed up lookup
# times once we enable the skStub logic. # times once we enable the skStub logic.
let m = getModule(s)
let mid = if m == nil: 0 else: abs(m.id)
db.exec(sql"insert into syms(nimid, module, name, data, exported) values (?, ?, ?, ?, ?)", db.exec(sql"insert into syms(nimid, module, name, data, exported) values (?, ?, ?, ?, ?)",
s.id, abs(w.module.id), s.name.s, buf, ord(sfExported in s.flags)) s.id, mid, s.name.s, buf, ord(sfExported in s.flags))
proc storeType(w: PRodWriter; t: PType) = proc storeType(g: ModuleGraph; t: PType) =
var buf = newStringOfCap(160) var buf = newStringOfCap(160)
encodeType(w, t, buf) encodeType(g, t, buf)
let m = if t.owner != nil: getModule(t.owner) else: nil
let mid = if m == nil: 0 else: abs(m.id)
db.exec(sql"insert into types(nimid, module, data) values (?, ?, ?)", db.exec(sql"insert into types(nimid, module, data) values (?, ?, ?)",
t.id, abs(w.module.id), buf) t.id, mid, buf)
var w = initRodWriter(nil) proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
if g.config.symbolFiles == disabledSf: return
proc storeNode*(module: PSym; n: PNode) =
if gSymbolFiles != v2Sf: return
w.module = module
var buf = newStringOfCap(160) var buf = newStringOfCap(160)
encodeNode(w, module.info, n, buf) encodeNode(g, module.info, n, buf)
db.exec(sql"insert into toplevelstmts(module, position, data) values (?, ?, ?)", db.exec(sql"insert into toplevelstmts(module, position, data) values (?, ?, ?)",
abs(module.id), module.offset, buf) abs(module.id), module.offset, buf)
inc module.offset inc module.offset
var i = 0 var i = 0
while true: while true:
if i > 10_000: if i > 10_000:
quit "loop never ends!" doAssert false, "loop never ends!"
if w.sstack.len > 0: if w.sstack.len > 0:
let s = w.sstack.pop() let s = w.sstack.pop()
when false: when false:
echo "popped ", s.name.s, " ", s.id echo "popped ", s.name.s, " ", s.id
storeSym(w, s) storeSym(g, s)
elif w.tstack.len > 0: elif w.tstack.len > 0:
let t = w.tstack.pop() let t = w.tstack.pop()
storeType(w, t) storeType(g, t)
when false: when false:
echo "popped type ", typeToString(t), " ", t.id echo "popped type ", typeToString(t), " ", t.id
else: else:
break break
inc i inc i
proc storeRemaining*(module: PSym) = proc recordStmt*(g: ModuleGraph; module: PSym; n: PNode) =
if gSymbolFiles != v2Sf: return storeNode(g, module, n)
w.module = module
proc storeRemaining*(g: ModuleGraph; module: PSym) =
if g.config.symbolFiles == disabledSf: return
var stillForwarded: seq[PSym] = @[]
for s in w.forwardedSyms: for s in w.forwardedSyms:
assert sfForward notin s.flags if sfForward notin s.flags:
storeSym(w, s) storeSym(g, s)
w.forwardedSyms.setLen 0 else:
stillForwarded.add s
swap w.forwardedSyms, stillForwarded
# ---------------- decoder ----------------------------------- # ---------------- decoder -----------------------------------
type type
TRodReader = object
module: PSym
#sstack: seq[(PSym, ptr PSym)] # a stack of symbols to process
#tstack: seq[(PType, ptr PType)] # a stack of types to process
#tmarks, smarks: IntSet
syms: Table[int, PSym] ## XXX make this more efficients
types: Table[int, PType]
cache: IdentCache
BlobReader = object BlobReader = object
s: string s: string
pos: int pos: int
PRodReader = var TRodReader
proc initRodReader(cache: IdentCache): TRodReader =
TRodReader(module: nil,
syms: initTable[int, PSym](), types: initTable[int, PType](),
cache: cache)
var gr = initRodReader(newIdentCache())
using using
r: PRodReader
b: var BlobReader b: var BlobReader
g: ModuleGraph
proc loadSym(r; id: int, info: TLineInfo): PSym proc loadSym(g; id: int, info: TLineInfo): PSym
proc loadType(r; id: int, info: TLineInfo): PType proc loadType(g; id: int, info: TLineInfo): PType
proc decodeLineInfo(r; b; info: var TLineInfo) = proc decodeLineInfo(g; b; info: var TLineInfo) =
if b.s[b.pos] == '?': if b.s[b.pos] == '?':
inc(b.pos) inc(b.pos)
if b.s[b.pos] == ',': info.col = -1'i16 if b.s[b.pos] == ',': info.col = -1'i16
else: info.col = int16(decodeVInt(b.s, b.pos)) else: info.col = int16(decodeVInt(b.s, b.pos))
if b.s[b.pos] == ',': if b.s[b.pos] == ',':
inc(b.pos) inc(b.pos)
if b.s[b.pos] == ',': info.line = -1'i16 if b.s[b.pos] == ',': info.line = 0'u16
else: info.line = int16(decodeVInt(b.s, b.pos)) else: info.line = uint16(decodeVInt(b.s, b.pos))
if b.s[b.pos] == ',': if b.s[b.pos] == ',':
inc(b.pos) inc(b.pos)
info.fileIndex = fromDbFileId(decodeVInt(b.s, b.pos)) info.fileIndex = fromDbFileId(g.incr, g.config, decodeVInt(b.s, b.pos))
proc skipNode(b) = proc skipNode(b) =
assert b.s[b.pos] == '(' assert b.s[b.pos] == '('
@ -488,7 +439,7 @@ proc skipNode(b) =
inc pos inc pos
b.pos = pos+1 # skip ')' b.pos = pos+1 # skip ')'
proc decodeNodeLazyBody(r; b; fInfo: TLineInfo, proc decodeNodeLazyBody(g; b; fInfo: TLineInfo,
belongsTo: PSym): PNode = belongsTo: PSym): PNode =
result = nil result = nil
if b.s[b.pos] == '(': if b.s[b.pos] == '(':
@ -497,14 +448,14 @@ proc decodeNodeLazyBody(r; b; fInfo: TLineInfo,
inc(b.pos) inc(b.pos)
return # nil node return # nil node
result = newNodeI(TNodeKind(decodeVInt(b.s, b.pos)), fInfo) result = newNodeI(TNodeKind(decodeVInt(b.s, b.pos)), fInfo)
decodeLineInfo(r, b, result.info) decodeLineInfo(g, b, result.info)
if b.s[b.pos] == '$': if b.s[b.pos] == '$':
inc(b.pos) inc(b.pos)
result.flags = cast[TNodeFlags](int32(decodeVInt(b.s, b.pos))) result.flags = cast[TNodeFlags](int32(decodeVInt(b.s, b.pos)))
if b.s[b.pos] == '^': if b.s[b.pos] == '^':
inc(b.pos) inc(b.pos)
var id = decodeVInt(b.s, b.pos) var id = decodeVInt(b.s, b.pos)
result.typ = loadType(r, id, result.info) result.typ = loadType(g, id, result.info)
case result.kind case result.kind
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
if b.s[b.pos] == '!': if b.s[b.pos] == '!':
@ -525,16 +476,16 @@ proc decodeNodeLazyBody(r; b; fInfo: TLineInfo,
if b.s[b.pos] == '!': if b.s[b.pos] == '!':
inc(b.pos) inc(b.pos)
var fl = decodeStr(b.s, b.pos) var fl = decodeStr(b.s, b.pos)
result.ident = r.cache.getIdent(fl) result.ident = g.cache.getIdent(fl)
else: else:
internalError(result.info, "decodeNode: nkIdent") internalError(g.config, result.info, "decodeNode: nkIdent")
of nkSym: of nkSym:
if b.s[b.pos] == '!': if b.s[b.pos] == '!':
inc(b.pos) inc(b.pos)
var id = decodeVInt(b.s, b.pos) var id = decodeVInt(b.s, b.pos)
result.sym = loadSym(r, id, result.info) result.sym = loadSym(g, id, result.info)
else: else:
internalError(result.info, "decodeNode: nkSym") internalError(g.config, result.info, "decodeNode: nkSym")
else: else:
var i = 0 var i = 0
while b.s[b.pos] != ')': while b.s[b.pos] != ')':
@ -545,17 +496,17 @@ proc decodeNodeLazyBody(r; b; fInfo: TLineInfo,
skipNode(b) skipNode(b)
else: else:
discard discard
addSonNilAllowed(result, decodeNodeLazyBody(r, b, result.info, nil)) addSonNilAllowed(result, decodeNodeLazyBody(g, b, result.info, nil))
inc i inc i
if b.s[b.pos] == ')': inc(b.pos) if b.s[b.pos] == ')': inc(b.pos)
else: internalError(result.info, "decodeNode: ')' missing") else: internalError(g.config, result.info, "decodeNode: ')' missing")
else: else:
internalError(fInfo, "decodeNode: '(' missing " & $b.pos) internalError(g.config, fInfo, "decodeNode: '(' missing " & $b.pos)
proc decodeNode(r; b; fInfo: TLineInfo): PNode = proc decodeNode(g; b; fInfo: TLineInfo): PNode =
result = decodeNodeLazyBody(r, b, fInfo, nil) result = decodeNodeLazyBody(g, b, fInfo, nil)
proc decodeLoc(r; b; loc: var TLoc, info: TLineInfo) = proc decodeLoc(g; b; loc: var TLoc, info: TLineInfo) =
if b.s[b.pos] == '<': if b.s[b.pos] == '<':
inc(b.pos) inc(b.pos)
if b.s[b.pos] in {'0'..'9', 'a'..'z', 'A'..'Z'}: if b.s[b.pos] in {'0'..'9', 'a'..'z', 'A'..'Z'}:
@ -574,7 +525,7 @@ proc decodeLoc(r; b; loc: var TLoc, info: TLineInfo) =
loc.flags = {} loc.flags = {}
if b.s[b.pos] == '^': if b.s[b.pos] == '^':
inc(b.pos) inc(b.pos)
loc.lode = decodeNode(r, b, info) loc.lode = decodeNode(g, b, info)
# rrGetType(b, decodeVInt(b.s, b.pos), info) # rrGetType(b, decodeVInt(b.s, b.pos), info)
else: else:
loc.lode = nil loc.lode = nil
@ -584,19 +535,21 @@ proc decodeLoc(r; b; loc: var TLoc, info: TLineInfo) =
else: else:
loc.r = nil loc.r = nil
if b.s[b.pos] == '>': inc(b.pos) if b.s[b.pos] == '>': inc(b.pos)
else: internalError(info, "decodeLoc " & b.s[b.pos]) else: internalError(g.config, info, "decodeLoc " & b.s[b.pos])
proc loadBlob(query: SqlQuery; id: int): BlobReader = proc loadBlob(g; query: SqlQuery; id: int): BlobReader =
let blob = db.getValue(query, id) let blob = db.getValue(query, id)
if blob.len == 0: if blob.len == 0:
internalError("symbolfiles: cannot find ID " & $ id) internalError(g.config, "symbolfiles: cannot find ID " & $ id)
result = BlobReader(pos: 0) result = BlobReader(pos: 0)
shallowCopy(result.s, blob) shallowCopy(result.s, blob)
# ensure we can read without index checks:
result.s.add '\0'
proc loadType(r; id: int; info: TLineInfo): PType = proc loadType(g; id: int; info: TLineInfo): PType =
result = r.types.getOrDefault(id) result = g.incr.r.types.getOrDefault(id)
if result != nil: return result if result != nil: return result
var b = loadBlob(sql"select data from types where nimid = ?", id) var b = loadBlob(g, sql"select data from types where nimid = ?", id)
if b.s[b.pos] == '[': if b.s[b.pos] == '[':
inc(b.pos) inc(b.pos)
@ -611,10 +564,10 @@ proc loadType(r; id: int; info: TLineInfo): PType =
setId(result.id) setId(result.id)
#if debugIds: registerID(result) #if debugIds: registerID(result)
else: else:
internalError(info, "decodeType: no id") internalError(g.config, info, "decodeType: no id")
# here this also avoids endless recursion for recursive type # here this also avoids endless recursion for recursive type
r.types[result.id] = result g.incr.r.types.add(result.id, result)
if b.s[b.pos] == '(': result.n = decodeNode(r, b, unknownLineInfo()) if b.s[b.pos] == '(': result.n = decodeNode(g, b, unknownLineInfo())
if b.s[b.pos] == '$': if b.s[b.pos] == '$':
inc(b.pos) inc(b.pos)
result.flags = cast[TTypeFlags](int32(decodeVInt(b.s, b.pos))) result.flags = cast[TTypeFlags](int32(decodeVInt(b.s, b.pos)))
@ -623,10 +576,10 @@ proc loadType(r; id: int; info: TLineInfo): PType =
result.callConv = TCallingConvention(decodeVInt(b.s, b.pos)) result.callConv = TCallingConvention(decodeVInt(b.s, b.pos))
if b.s[b.pos] == '*': if b.s[b.pos] == '*':
inc(b.pos) inc(b.pos)
result.owner = loadSym(r, decodeVInt(b.s, b.pos), info) result.owner = loadSym(g, decodeVInt(b.s, b.pos), info)
if b.s[b.pos] == '&': if b.s[b.pos] == '&':
inc(b.pos) inc(b.pos)
result.sym = loadSym(r, decodeVInt(b.s, b.pos), info) result.sym = loadSym(g, decodeVInt(b.s, b.pos), info)
if b.s[b.pos] == '/': if b.s[b.pos] == '/':
inc(b.pos) inc(b.pos)
result.size = decodeVInt(b.s, b.pos) result.size = decodeVInt(b.s, b.pos)
@ -646,65 +599,65 @@ proc loadType(r; id: int; info: TLineInfo): PType =
if b.s[b.pos] == '\15': if b.s[b.pos] == '\15':
inc(b.pos) inc(b.pos)
result.destructor = loadSym(r, decodeVInt(b.s, b.pos), info) result.destructor = loadSym(g, decodeVInt(b.s, b.pos), info)
if b.s[b.pos] == '\16': if b.s[b.pos] == '\16':
inc(b.pos) inc(b.pos)
result.deepCopy = loadSym(r, decodeVInt(b.s, b.pos), info) result.deepCopy = loadSym(g, decodeVInt(b.s, b.pos), info)
if b.s[b.pos] == '\17': if b.s[b.pos] == '\17':
inc(b.pos) inc(b.pos)
result.assignment = loadSym(r, decodeVInt(b.s, b.pos), info) result.assignment = loadSym(g, decodeVInt(b.s, b.pos), info)
if b.s[b.pos] == '\18': if b.s[b.pos] == '\18':
inc(b.pos) inc(b.pos)
result.sink = loadSym(r, decodeVInt(b.s, b.pos), info) result.sink = loadSym(g, decodeVInt(b.s, b.pos), info)
while b.s[b.pos] == '\19': while b.s[b.pos] == '\19':
inc(b.pos) inc(b.pos)
let x = decodeVInt(b.s, b.pos) let x = decodeVInt(b.s, b.pos)
doAssert b.s[b.pos] == '\20' doAssert b.s[b.pos] == '\20'
inc(b.pos) inc(b.pos)
let y = loadSym(r, decodeVInt(b.s, b.pos), info) let y = loadSym(g, decodeVInt(b.s, b.pos), info)
result.methods.safeAdd((x, y)) result.methods.safeAdd((x, y))
decodeLoc(r, b, result.loc, info) decodeLoc(g, b, result.loc, info)
while b.s[b.pos] == '^': while b.s[b.pos] == '^':
inc(b.pos) inc(b.pos)
if b.s[b.pos] == '(': if b.s[b.pos] == '(':
inc(b.pos) inc(b.pos)
if b.s[b.pos] == ')': inc(b.pos) if b.s[b.pos] == ')': inc(b.pos)
else: internalError(info, "decodeType ^(" & b.s[b.pos]) else: internalError(g.config, info, "decodeType ^(" & b.s[b.pos])
rawAddSon(result, nil) rawAddSon(result, nil)
else: else:
var d = decodeVInt(b.s, b.pos) let d = decodeVInt(b.s, b.pos)
rawAddSon(result, loadType(r, d, info)) rawAddSon(result, loadType(g, d, info))
proc decodeLib(r; b; info: TLineInfo): PLib = proc decodeLib(g; b; info: TLineInfo): PLib =
result = nil result = nil
if b.s[b.pos] == '|': if b.s[b.pos] == '|':
new(result) new(result)
inc(b.pos) inc(b.pos)
result.kind = TLibKind(decodeVInt(b.s, b.pos)) result.kind = TLibKind(decodeVInt(b.s, b.pos))
if b.s[b.pos] != '|': internalError("decodeLib: 1") if b.s[b.pos] != '|': internalError(g.config, "decodeLib: 1")
inc(b.pos) inc(b.pos)
result.name = rope(decodeStr(b.s, b.pos)) result.name = rope(decodeStr(b.s, b.pos))
if b.s[b.pos] != '|': internalError("decodeLib: 2") if b.s[b.pos] != '|': internalError(g.config, "decodeLib: 2")
inc(b.pos) inc(b.pos)
result.path = decodeNode(r, b, info) result.path = decodeNode(g, b, info)
proc decodeInstantiations(r; b; info: TLineInfo; proc decodeInstantiations(g; b; info: TLineInfo;
s: var seq[PInstantiation]) = s: var seq[PInstantiation]) =
while b.s[b.pos] == '\15': while b.s[b.pos] == '\15':
inc(b.pos) inc(b.pos)
var ii: PInstantiation var ii: PInstantiation
new ii new ii
ii.sym = loadSym(r, decodeVInt(b.s, b.pos), info) ii.sym = loadSym(g, decodeVInt(b.s, b.pos), info)
ii.concreteTypes = @[] ii.concreteTypes = @[]
while b.s[b.pos] == '\17': while b.s[b.pos] == '\17':
inc(b.pos) inc(b.pos)
ii.concreteTypes.add loadType(r, decodeVInt(b.s, b.pos), info) ii.concreteTypes.add loadType(g, decodeVInt(b.s, b.pos), info)
if b.s[b.pos] == '\20': if b.s[b.pos] == '\20':
inc(b.pos) inc(b.pos)
ii.compilesId = decodeVInt(b.s, b.pos) ii.compilesId = decodeVInt(b.s, b.pos)
s.safeAdd ii s.safeAdd ii
proc loadSymFromBlob(r; b; info: TLineInfo): PSym = proc loadSymFromBlob(g; b; info: TLineInfo): PSym =
if b.s[b.pos] == '{': if b.s[b.pos] == '{':
inc(b.pos) inc(b.pos)
if b.s[b.pos] == '}': if b.s[b.pos] == '}':
@ -717,26 +670,26 @@ proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
id = decodeVInt(b.s, b.pos) id = decodeVInt(b.s, b.pos)
setId(id) setId(id)
else: else:
internalError(info, "decodeSym: no id") internalError(g.config, info, "decodeSym: no id")
var ident: PIdent var ident: PIdent
if b.s[b.pos] == '&': if b.s[b.pos] == '&':
inc(b.pos) inc(b.pos)
ident = r.cache.getIdent(decodeStr(b.s, b.pos)) ident = g.cache.getIdent(decodeStr(b.s, b.pos))
else: else:
internalError(info, "decodeSym: no ident") internalError(g.config, info, "decodeSym: no ident")
#echo "decoding: {", ident.s #echo "decoding: {", ident.s
new(result) new(result)
result.id = id result.id = id
result.kind = k result.kind = k
result.name = ident # read the rest of the symbol description: result.name = ident # read the rest of the symbol description:
r.syms[result.id] = result g.incr.r.syms.add(result.id, result)
if b.s[b.pos] == '^': if b.s[b.pos] == '^':
inc(b.pos) inc(b.pos)
result.typ = loadType(r, decodeVInt(b.s, b.pos), info) result.typ = loadType(g, decodeVInt(b.s, b.pos), info)
decodeLineInfo(r, b, result.info) decodeLineInfo(g, b, result.info)
if b.s[b.pos] == '*': if b.s[b.pos] == '*':
inc(b.pos) inc(b.pos)
result.owner = loadSym(r, decodeVInt(b.s, b.pos), result.info) result.owner = loadSym(g, decodeVInt(b.s, b.pos), result.info)
if b.s[b.pos] == '$': if b.s[b.pos] == '$':
inc(b.pos) inc(b.pos)
result.flags = cast[TSymFlags](int32(decodeVInt(b.s, b.pos))) result.flags = cast[TSymFlags](int32(decodeVInt(b.s, b.pos)))
@ -746,8 +699,6 @@ proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
if b.s[b.pos] == '!': if b.s[b.pos] == '!':
inc(b.pos) inc(b.pos)
result.options = cast[TOptions](int32(decodeVInt(b.s, b.pos))) result.options = cast[TOptions](int32(decodeVInt(b.s, b.pos)))
else:
result.options = r.module.options
if b.s[b.pos] == '%': if b.s[b.pos] == '%':
inc(b.pos) inc(b.pos)
result.position = decodeVInt(b.s, b.pos) result.position = decodeVInt(b.s, b.pos)
@ -755,28 +706,28 @@ proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
inc(b.pos) inc(b.pos)
result.offset = decodeVInt(b.s, b.pos) result.offset = decodeVInt(b.s, b.pos)
else: else:
result.offset = - 1 result.offset = -1
decodeLoc(r, b, result.loc, result.info) decodeLoc(g, b, result.loc, result.info)
result.annex = decodeLib(r, b, info) result.annex = decodeLib(g, b, info)
if b.s[b.pos] == '#': if b.s[b.pos] == '#':
inc(b.pos) inc(b.pos)
result.constraint = decodeNode(r, b, unknownLineInfo()) result.constraint = decodeNode(g, b, unknownLineInfo())
case result.kind case result.kind
of skType, skGenericParam: of skType, skGenericParam:
while b.s[b.pos] == '\14': while b.s[b.pos] == '\14':
inc(b.pos) inc(b.pos)
result.typeInstCache.safeAdd loadType(r, decodeVInt(b.s, b.pos), result.info) result.typeInstCache.safeAdd loadType(g, decodeVInt(b.s, b.pos), result.info)
of routineKinds: of routineKinds:
decodeInstantiations(r, b, result.info, result.procInstCache) decodeInstantiations(g, b, result.info, result.procInstCache)
if b.s[b.pos] == '\16': if b.s[b.pos] == '\16':
inc(b.pos) inc(b.pos)
result.gcUnsafetyReason = loadSym(r, decodeVInt(b.s, b.pos), result.info) result.gcUnsafetyReason = loadSym(g, decodeVInt(b.s, b.pos), result.info)
of skModule, skPackage: of skModule, skPackage:
decodeInstantiations(r, b, result.info, result.usedGenerics) decodeInstantiations(g, b, result.info, result.usedGenerics)
of skLet, skVar, skField, skForVar: of skLet, skVar, skField, skForVar:
if b.s[b.pos] == '\18': if b.s[b.pos] == '\18':
inc(b.pos) inc(b.pos)
result.guard = loadSym(r, decodeVInt(b.s, b.pos), result.info) result.guard = loadSym(g, decodeVInt(b.s, b.pos), result.info)
if b.s[b.pos] == '\19': if b.s[b.pos] == '\19':
inc(b.pos) inc(b.pos)
result.bitsize = decodeVInt(b.s, b.pos).int16 result.bitsize = decodeVInt(b.s, b.pos).int16
@ -786,159 +737,146 @@ proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
#if result.kind in routineKinds: #if result.kind in routineKinds:
# result.ast = decodeNodeLazyBody(b, result.info, result) # result.ast = decodeNodeLazyBody(b, result.info, result)
#else: #else:
result.ast = decodeNode(r, b, result.info) result.ast = decodeNode(g, b, result.info)
if sfCompilerProc in result.flags: if sfCompilerProc in result.flags:
registerCompilerProc(result) registerCompilerProc(g, result)
#echo "loading ", result.name.s #echo "loading ", result.name.s
proc loadSym(r; id: int; info: TLineInfo): PSym = proc loadSym(g; id: int; info: TLineInfo): PSym =
result = r.syms.getOrDefault(id) result = g.incr.r.syms.getOrDefault(id)
if result != nil: return result if result != nil: return result
var b = loadBlob(sql"select data from syms where nimid = ?", id) var b = loadBlob(g, sql"select data from syms where nimid = ?", id)
result = loadSymFromBlob(r, b, info) result = loadSymFromBlob(g, b, info)
doAssert id == result.id, "symbol ID is not consistent!" doAssert id == result.id, "symbol ID is not consistent!"
proc loadModuleSymTab(r; module: PSym) = proc loadModuleSymTab(g; module: PSym) =
## goal: fill module.tab ## goal: fill module.tab
gr.syms[module.id] = module g.incr.r.syms.add(module.id, module)
for row in db.fastRows(sql"select nimid, data from syms where module = ? and exported = 1", abs(module.id)): for row in db.fastRows(sql"select nimid, data from syms where module = ? and exported = 1", abs(module.id)):
let id = parseInt(row[0]) let id = parseInt(row[0])
var s = r.syms.getOrDefault(id) var s = g.incr.r.syms.getOrDefault(id)
if s == nil: if s == nil:
var b = BlobReader(pos: 0) var b = BlobReader(pos: 0)
shallowCopy(b.s, row[1]) shallowCopy(b.s, row[1])
s = loadSymFromBlob(r, b, module.info) # ensure we can read without index checks:
b.s.add '\0'
s = loadSymFromBlob(g, b, module.info)
assert s != nil assert s != nil
strTableAdd(module.tab, s) strTableAdd(module.tab, s)
if sfSystemModule in module.flags: if sfSystemModule in module.flags:
magicsys.systemModule = module g.systemModule = module
proc loadNode*(module: PSym; index: int): PNode = proc replay(g: ModuleGraph; module: PSym; n: PNode) =
assert gSymbolFiles == v2Sf # XXX check if we need to replay nkStaticStmt here.
if index == 0: case n.kind
loadModuleSymTab(gr, module) #of nkStaticStmt:
#index = parseInt db.getValue( #evalStaticStmt(module, g, n[0], module)
# sql"select min(id) from toplevelstmts where module = ?", abs module.id) #of nkVarSection, nkLetSection:
var b = BlobReader(pos: 0) # nkVarSections are already covered by the vmgen which produces nkStaticStmt
b.s = db.getValue(sql"select data from toplevelstmts where position = ? and module = ?", of nkMethodDef:
index, abs module.id) methodDef(g, n[namePos].sym, fromCache=true)
if b.s.len == 0: of nkCommentStmt:
db.exec(sql"insert into controlblock(idgen) values (?)", gFrontEndId) # pragmas are complex and can be user-overriden via templates. So
return nil # end marker # instead of using the original ``nkPragma`` nodes, we rely on the
gr.module = module # fact that pragmas.nim was patched to produce specialized recorded
result = decodeNode(gr, b, module.info) # statements for us in the form of ``nkCommentStmt`` with (key, value)
# pairs. Ordinary nkCommentStmt nodes never have children so this is
# not ambiguous.
# Fortunately only a tiny subset of the available pragmas need to
# be replayed here. This is always a subset of ``pragmas.stmtPragmas``.
if n.len >= 2:
internalAssert g.config, n[0].kind == nkStrLit and n[1].kind == nkStrLit
case n[0].strVal
of "hint": message(g.config, n.info, hintUser, n[1].strVal)
of "warning": message(g.config, n.info, warnUser, n[1].strVal)
of "error": localError(g.config, n.info, errUser, n[1].strVal)
of "compile":
internalAssert g.config, n.len == 3 and n[2].kind == nkStrLit
var cf = Cfile(cname: n[1].strVal, obj: n[2].strVal,
flags: {CfileFlag.External})
extccomp.addExternalFileToCompile(g.config, cf)
of "link":
extccomp.addExternalFileToLink(g.config, n[1].strVal)
of "passl":
extccomp.addLinkOption(g.config, n[1].strVal)
of "passc":
extccomp.addCompileOption(g.config, n[1].strVal)
of "cppdefine":
options.cppDefine(g.config, n[1].strVal)
of "inc":
let destKey = n[1].strVal
let by = n[2].intVal
let v = getOrDefault(g.cacheCounters, destKey)
g.cacheCounters[destKey] = v+by
of "put":
let destKey = n[1].strVal
let key = n[2].strVal
let val = n[3]
if not contains(g.cacheTables, destKey):
g.cacheTables[destKey] = initBTree[string, PNode]()
if not contains(g.cacheTables[destKey], key):
g.cacheTables[destKey].add(key, val)
else:
internalError(g.config, n.info, "key already exists: " & key)
of "incl":
let destKey = n[1].strVal
let val = n[2]
if not contains(g.cacheSeqs, destKey):
g.cacheSeqs[destKey] = newTree(nkStmtList, val)
else:
block search:
for existing in g.cacheSeqs[destKey]:
if exprStructuralEquivalent(existing, val, strictSymEquality=true):
break search
g.cacheSeqs[destKey].add val
of "add":
let destKey = n[1].strVal
let val = n[2]
if not contains(g.cacheSeqs, destKey):
g.cacheSeqs[destKey] = newTree(nkStmtList, val)
else:
g.cacheSeqs[destKey].add val
else:
internalAssert g.config, false
of nkImportStmt:
for x in n:
internalAssert g.config, x.kind == nkStrLit
let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, n[0].strVal))
internalAssert g.config, imported.id < 0
of nkStmtList, nkStmtListExpr:
for x in n: replay(g, module, x)
else: discard "nothing to do for this node"
proc addModuleDep*(module, fileIdx: int32; isIncludeFile: bool) = proc loadNode*(g: ModuleGraph; module: PSym): PNode =
if gSymbolFiles != v2Sf: return loadModuleSymTab(g, module)
result = newNodeI(nkStmtList, module.info)
for row in db.rows(sql"select data from toplevelstmts where module = ? order by position asc",
abs module.id):
let a = toDbFileId(module) var b = BlobReader(pos: 0)
let b = toDbFileId(fileIdx) # ensure we can read without index checks:
b.s = row[0] & '\0'
result.add decodeNode(g, b, module.info)
db.exec(sql"insert into deps(module, dependency, isIncludeFile) values (?, ?, ?)", db.exec(sql"insert into controlblock(idgen) values (?)", gFrontEndId)
a, b, ord(isIncludeFile)) replay(g, module, result)
# --------------- Database model --------------------------------------------- proc setupModuleCache*(g: ModuleGraph) =
if g.config.symbolFiles == disabledSf: return
proc createDb() = g.recordStmt = recordStmt
db.exec(sql""" let dbfile = getNimcacheDir(g.config) / "rodfiles.db"
create table if not exists controlblock( if g.config.symbolFiles == writeOnlySf:
idgen integer not null removeFile(dbfile)
);
""")
db.exec(sql"""
create table if not exists filenames(
id integer primary key,
fullpath varchar(8000) not null,
fullHash varchar(256) not null
);
""")
db.exec sql"create index if not exists FilenameIx on filenames(fullpath);"
db.exec(sql"""
create table if not exists modules(
id integer primary key,
fullpath varchar(8000) not null,
interfHash varchar(256) not null,
fullHash varchar(256) not null,
created timestamp not null default (DATETIME('now'))
);""")
db.exec(sql"""create unique index if not exists SymNameIx on modules(fullpath);""")
db.exec(sql"""
create table if not exists deps(
id integer primary key,
module integer not null,
dependency integer not null,
isIncludeFile integer not null,
foreign key (module) references filenames(id),
foreign key (dependency) references filenames(id)
);""")
db.exec(sql"""create index if not exists DepsIx on deps(module);""")
db.exec(sql"""
create table if not exists types(
id integer primary key,
nimid integer not null,
module integer not null,
data blob not null,
foreign key (module) references module(id)
);
""")
db.exec sql"create index TypeByModuleIdx on types(module);"
db.exec sql"create index TypeByNimIdIdx on types(nimid);"
db.exec(sql"""
create table if not exists syms(
id integer primary key,
nimid integer not null,
module integer not null,
name varchar(256) not null,
data blob not null,
exported int not null,
foreign key (module) references module(id)
);
""")
db.exec sql"create index if not exists SymNameIx on syms(name);"
db.exec sql"create index SymByNameAndModuleIdx on syms(name, module);"
db.exec sql"create index SymByModuleIdx on syms(module);"
db.exec sql"create index SymByNimIdIdx on syms(nimid);"
db.exec(sql"""
create table if not exists toplevelstmts(
id integer primary key,
position integer not null,
module integer not null,
data blob not null,
foreign key (module) references module(id)
);
""")
db.exec sql"create index TopLevelStmtByModuleIdx on toplevelstmts(module);"
db.exec sql"create index TopLevelStmtByPositionIdx on toplevelstmts(position);"
db.exec(sql"""
create table if not exists statics(
id integer primary key,
module integer not null,
data blob not null,
foreign key (module) references module(id)
);
""")
db.exec sql"create index StaticsByModuleIdx on toplevelstmts(module);"
db.exec sql"insert into controlblock(idgen) values (0)"
proc setupModuleCache* =
if gSymbolFiles != v2Sf: return
let dbfile = getNimcacheDir() / "rodfiles.db"
if not fileExists(dbfile): if not fileExists(dbfile):
db = open(connection=dbfile, user="nim", password="", db = open(connection=dbfile, user="nim", password="",
database="nim") database="nim")
createDb() createDb(db)
db.exec(sql"insert into config(config) values (?)", encodeConfig(g))
else: else:
db = open(connection=dbfile, user="nim", password="", db = open(connection=dbfile, user="nim", password="",
database="nim") database="nim")
let oldConfig = db.getValue(sql"select config from config")
g.incr.configChanged = oldConfig != encodeConfig(g)
db.exec(sql"pragma journal_mode=off") db.exec(sql"pragma journal_mode=off")
db.exec(sql"pragma SYNCHRONOUS=off") db.exec(sql"pragma SYNCHRONOUS=off")
db.exec(sql"pragma LOCKING_MODE=exclusive") db.exec(sql"pragma LOCKING_MODE=exclusive")

File diff suppressed because it is too large Load diff

View file

@ -1,659 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This module is responsible for writing of rod files. Note that writing of
# rod files is a pass, reading of rod files is not! This is why reading and
# writing of rod files is split into two different modules.
import
intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
condsyms, ropes, idents, std / sha1, rodread, passes, idgen,
rodutils, modulepaths
from modulegraphs import ModuleGraph
type
TRodWriter = object of TPassContext
module: PSym
hash: SecureHash
options: TOptions
defines: string
inclDeps: string
modDeps: string
interf: string
compilerProcs: string
index, imports: TIndex
converters, methods: string
init: string
data: string
sstack: TSymSeq # a stack of symbols to process
tstack: TTypeSeq # a stack of types to process
files: TStringSeq
origFile: string
cache: IdentCache
config: ConfigRef
PRodWriter = ref TRodWriter
proc getDefines(conf: ConfigRef): string =
result = ""
for d in definedSymbolNames(conf.symbols):
if result.len != 0: add(result, " ")
add(result, d)
proc fileIdx(w: PRodWriter, filename: string): int =
for i in countup(0, high(w.files)):
if w.files[i] == filename:
return i
result = len(w.files)
setLen(w.files, result + 1)
w.files[result] = filename
template filename*(w: PRodWriter): string =
toFilename(FileIndex w.module.position)
proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache;
config: ConfigRef): PRodWriter =
new(result)
result.config = config
result.sstack = @[]
result.tstack = @[]
initIiTable(result.index.tab)
initIiTable(result.imports.tab)
result.index.r = ""
result.imports.r = ""
result.hash = hash
result.module = module
result.defines = getDefines(config)
result.options = config.options
result.files = @[]
result.inclDeps = ""
result.modDeps = ""
result.interf = newStringOfCap(2_000)
result.compilerProcs = ""
result.converters = ""
result.methods = ""
result.init = ""
result.origFile = module.info.toFullPath
result.data = newStringOfCap(12_000)
result.cache = cache
proc addModDep(w: PRodWriter, dep: string; info: TLineInfo) =
if w.modDeps.len != 0: add(w.modDeps, ' ')
let resolved = findModule(w.config, dep, info.toFullPath)
encodeVInt(fileIdx(w, resolved), w.modDeps)
const
rodNL = "\x0A"
proc addInclDep(w: PRodWriter, dep: string; info: TLineInfo) =
let resolved = findModule(w.config, dep, info.toFullPath)
encodeVInt(fileIdx(w, resolved), w.inclDeps)
add(w.inclDeps, " ")
encodeStr($secureHashFile(resolved), w.inclDeps)
add(w.inclDeps, rodNL)
proc pushType(w: PRodWriter, t: PType) =
# check so that the stack does not grow too large:
if iiTableGet(w.index.tab, t.id) == InvalidKey:
w.tstack.add(t)
proc pushSym(w: PRodWriter, s: PSym) =
# check so that the stack does not grow too large:
if iiTableGet(w.index.tab, s.id) == InvalidKey:
when false:
if s.kind == skMethod:
echo "encoding ", s.id, " ", s.name.s
writeStackTrace()
w.sstack.add(s)
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
result: var string) =
if n == nil:
# nil nodes have to be stored too:
result.add("()")
return
result.add('(')
encodeVInt(ord(n.kind), result)
# we do not write comments for now
# Line information takes easily 20% or more of the filesize! Therefore we
# omit line information if it is the same as the father's line information:
if fInfo.fileIndex != n.info.fileIndex:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(int n.info.line, result)
result.add(',')
encodeVInt(fileIdx(w, toFullPath(n.info)), result)
elif fInfo.line != n.info.line:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(int n.info.line, result)
elif fInfo.col != n.info.col:
result.add('?')
encodeVInt(n.info.col, result)
# No need to output the file index, as this is the serialization of one
# file.
var f = n.flags * PersistentNodeFlags
if f != {}:
result.add('$')
encodeVInt(cast[int32](f), result)
if n.typ != nil:
result.add('^')
encodeVInt(n.typ.id, result)
pushType(w, n.typ)
case n.kind
of nkCharLit..nkUInt64Lit:
if n.intVal != 0:
result.add('!')
encodeVBiggestInt(n.intVal, result)
of nkFloatLit..nkFloat64Lit:
if n.floatVal != 0.0:
result.add('!')
encodeStr($n.floatVal, result)
of nkStrLit..nkTripleStrLit:
if n.strVal != "":
result.add('!')
encodeStr(n.strVal, result)
of nkIdent:
result.add('!')
encodeStr(n.ident.s, result)
of nkSym:
result.add('!')
encodeVInt(n.sym.id, result)
pushSym(w, n.sym)
else:
for i in countup(0, sonsLen(n) - 1):
encodeNode(w, n.info, n.sons[i], result)
add(result, ')')
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
var oldLen = result.len
result.add('<')
if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
if loc.storage != low(loc.storage):
add(result, '*')
encodeVInt(ord(loc.storage), result)
if loc.flags != {}:
add(result, '$')
encodeVInt(cast[int32](loc.flags), result)
if loc.lode != nil:
add(result, '^')
encodeNode(w, unknownLineInfo(), loc.lode, result)
#encodeVInt(cast[int32](loc.t.id), result)
#pushType(w, loc.t)
if loc.r != nil:
add(result, '!')
encodeStr($loc.r, result)
if oldLen + 1 == result.len:
# no data was necessary, so remove the '<' again:
setLen(result, oldLen)
else:
add(result, '>')
proc encodeType(w: PRodWriter, t: PType, result: var string) =
if t == nil:
# nil nodes have to be stored too:
result.add("[]")
return
# we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: internalError(w.config, "encodeType: tyForward")
# for the new rodfile viewer we use a preceding [ so that the data section
# can easily be disambiguated:
add(result, '[')
encodeVInt(ord(t.kind), result)
add(result, '+')
encodeVInt(t.id, result)
if t.n != nil:
encodeNode(w, unknownLineInfo(), t.n, result)
if t.flags != {}:
add(result, '$')
encodeVInt(cast[int32](t.flags), result)
if t.callConv != low(t.callConv):
add(result, '?')
encodeVInt(ord(t.callConv), result)
if t.owner != nil:
add(result, '*')
encodeVInt(t.owner.id, result)
pushSym(w, t.owner)
if t.sym != nil:
add(result, '&')
encodeVInt(t.sym.id, result)
pushSym(w, t.sym)
if t.size != - 1:
add(result, '/')
encodeVBiggestInt(t.size, result)
if t.align != 2:
add(result, '=')
encodeVInt(t.align, result)
if t.lockLevel.ord != UnspecifiedLockLevel.ord:
add(result, '\14')
encodeVInt(t.lockLevel.int16, result)
if t.destructor != nil and t.destructor.id != 0:
add(result, '\15')
encodeVInt(t.destructor.id, result)
pushSym(w, t.destructor)
if t.deepCopy != nil:
add(result, '\16')
encodeVInt(t.deepcopy.id, result)
pushSym(w, t.deepcopy)
if t.assignment != nil:
add(result, '\17')
encodeVInt(t.assignment.id, result)
pushSym(w, t.assignment)
if t.sink != nil:
add(result, '\18')
encodeVInt(t.sink.id, result)
pushSym(w, t.sink)
for i, s in items(t.methods):
add(result, '\19')
encodeVInt(i, result)
add(result, '\20')
encodeVInt(s.id, result)
pushSym(w, s)
encodeLoc(w, t.loc, result)
for i in countup(0, sonsLen(t) - 1):
if t.sons[i] == nil:
add(result, "^()")
else:
add(result, '^')
encodeVInt(t.sons[i].id, result)
pushType(w, t.sons[i])
proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
add(result, '|')
encodeVInt(ord(lib.kind), result)
add(result, '|')
encodeStr($lib.name, result)
add(result, '|')
encodeNode(w, info, lib.path, result)
proc encodeInstantiations(w: PRodWriter; s: seq[PInstantiation];
result: var string) =
for t in s:
result.add('\15')
encodeVInt(t.sym.id, result)
pushSym(w, t.sym)
for tt in t.concreteTypes:
result.add('\17')
encodeVInt(tt.id, result)
pushType(w, tt)
result.add('\20')
encodeVInt(t.compilesId, result)
proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
if s == nil:
# nil nodes have to be stored too:
result.add("{}")
return
# we need no surrounding {} here because the symbol is in a line of its own
encodeVInt(ord(s.kind), result)
result.add('+')
encodeVInt(s.id, result)
result.add('&')
encodeStr(s.name.s, result)
if s.typ != nil:
result.add('^')
encodeVInt(s.typ.id, result)
pushType(w, s.typ)
result.add('?')
if s.info.col != -1'i16: encodeVInt(s.info.col, result)
result.add(',')
if s.info.line != 0'u16: encodeVInt(int s.info.line, result)
result.add(',')
encodeVInt(fileIdx(w, toFullPath(s.info)), result)
if s.owner != nil:
result.add('*')
encodeVInt(s.owner.id, result)
pushSym(w, s.owner)
if s.flags != {}:
result.add('$')
encodeVInt(cast[int32](s.flags), result)
if s.magic != mNone:
result.add('@')
encodeVInt(ord(s.magic), result)
if s.options != w.options:
result.add('!')
encodeVInt(cast[int32](s.options), result)
if s.position != 0:
result.add('%')
encodeVInt(s.position, result)
if s.offset != - 1:
result.add('`')
encodeVInt(s.offset, result)
encodeLoc(w, s.loc, result)
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
if s.constraint != nil:
add(result, '#')
encodeNode(w, unknownLineInfo(), s.constraint, result)
case s.kind
of skType, skGenericParam:
for t in s.typeInstCache:
result.add('\14')
encodeVInt(t.id, result)
pushType(w, t)
of routineKinds:
encodeInstantiations(w, s.procInstCache, result)
if s.gcUnsafetyReason != nil:
result.add('\16')
encodeVInt(s.gcUnsafetyReason.id, result)
pushSym(w, s.gcUnsafetyReason)
of skModule, skPackage:
encodeInstantiations(w, s.usedGenerics, result)
# we don't serialize:
#tab*: TStrTable # interface table for modules
of skLet, skVar, skField, skForVar:
if s.guard != nil:
result.add('\18')
encodeVInt(s.guard.id, result)
pushSym(w, s.guard)
if s.bitsize != 0:
result.add('\19')
encodeVInt(s.bitsize, result)
else: discard
# lazy loading will soon reload the ast lazily, so the ast needs to be
# the last entry of a symbol:
if s.ast != nil:
# we used to attempt to save space here by only storing a dummy AST if
# it is not necessary, but Nim's heavy compile-time evaluation features
# make that unfeasible nowadays:
encodeNode(w, s.info, s.ast, result)
proc addToIndex(w: var TIndex, key, val: int) =
if key - w.lastIdxKey == 1:
# we do not store a key-diff of 1 to safe space
encodeVInt(val - w.lastIdxVal, w.r)
else:
encodeVInt(key - w.lastIdxKey, w.r)
add(w.r, ' ')
encodeVInt(val - w.lastIdxVal, w.r)
add(w.r, rodNL)
w.lastIdxKey = key
w.lastIdxVal = val
iiTablePut(w.tab, key, val)
const debugWrittenIds = false
when debugWrittenIds:
var debugWritten = initIntSet()
proc symStack(w: PRodWriter): int =
var i = 0
while i < len(w.sstack):
var s = w.sstack[i]
if sfForward in s.flags:
w.sstack[result] = s
inc result
elif iiTableGet(w.index.tab, s.id) == InvalidKey:
var m = getModule(s)
#if m == nil and s.kind != skPackage and sfGenSym notin s.flags:
# internalError("symStack: module nil: " & s.name.s & " " & $s.kind & " ID " & $s.id)
if m == nil or s.kind == skPackage or {sfFromGeneric, sfGenSym} * s.flags != {} or m.id == w.module.id:
# put definition in here
var L = w.data.len
addToIndex(w.index, s.id, L)
when debugWrittenIds: incl(debugWritten, s.id)
encodeSym(w, s, w.data)
add(w.data, rodNL)
# put into interface section if appropriate:
if {sfExported, sfFromGeneric} * s.flags == {sfExported} and
s.kind in ExportableSymKinds:
encodeStr(s.name.s, w.interf)
add(w.interf, ' ')
encodeVInt(s.id, w.interf)
add(w.interf, rodNL)
if sfCompilerProc in s.flags:
encodeStr(s.name.s, w.compilerProcs)
add(w.compilerProcs, ' ')
encodeVInt(s.id, w.compilerProcs)
add(w.compilerProcs, rodNL)
if s.kind == skConverter or (s.ast != nil and hasPattern(s)):
if w.converters.len != 0: add(w.converters, ' ')
encodeVInt(s.id, w.converters)
if s.kind == skMethod and sfDispatcher notin s.flags:
if w.methods.len != 0: add(w.methods, ' ')
encodeVInt(s.id, w.methods)
elif iiTableGet(w.imports.tab, s.id) == InvalidKey:
addToIndex(w.imports, s.id, m.id)
when debugWrittenIds:
if not contains(debugWritten, s.id):
echo(w.filename)
debug(s)
debug(s.owner)
debug(m)
internalError("Symbol referred to but never written")
inc(i)
setLen(w.sstack, result)
proc typeStack(w: PRodWriter): int =
var i = 0
while i < len(w.tstack):
var t = w.tstack[i]
if t.kind == tyForward:
w.tstack[result] = t
inc result
elif iiTableGet(w.index.tab, t.id) == InvalidKey:
var L = w.data.len
addToIndex(w.index, t.id, L)
encodeType(w, t, w.data)
add(w.data, rodNL)
inc(i)
setLen(w.tstack, result)
proc processStacks(w: PRodWriter, finalPass: bool) =
var oldS = 0
var oldT = 0
while true:
var slen = symStack(w)
var tlen = typeStack(w)
if slen == oldS and tlen == oldT: break
oldS = slen
oldT = tlen
if finalPass and (oldS != 0 or oldT != 0):
internalError(w.config, "could not serialize some forwarded symbols/types")
proc rawAddInterfaceSym(w: PRodWriter, s: PSym) =
pushSym(w, s)
processStacks(w, false)
proc addInterfaceSym(w: PRodWriter, s: PSym) =
if w == nil: return
if s.kind in ExportableSymKinds and
{sfExported, sfCompilerProc} * s.flags != {}:
rawAddInterfaceSym(w, s)
proc addStmt(w: PRodWriter, n: PNode) =
encodeVInt(w.data.len, w.init)
add(w.init, rodNL)
encodeNode(w, unknownLineInfo(), n, w.data)
add(w.data, rodNL)
processStacks(w, false)
proc writeRod(w: PRodWriter) =
processStacks(w, true)
var f: File
if not open(f, completeGeneratedFilePath(w.config, changeFileExt(
withPackageName(w.config, w.filename), RodExt)),
fmWrite):
#echo "couldn't write rod file for: ", w.filename
return
# write header:
f.write("NIM:")
f.write(RodFileVersion)
f.write(rodNL)
var id = "ID:"
encodeVInt(w.module.id, id)
f.write(id)
f.write(rodNL)
var orig = "ORIGFILE:"
encodeStr(w.origFile, orig)
f.write(orig)
f.write(rodNL)
var hash = "HASH:"
encodeStr($w.hash, hash)
f.write(hash)
f.write(rodNL)
var options = "OPTIONS:"
encodeVInt(cast[int32](w.options), options)
f.write(options)
f.write(rodNL)
var goptions = "GOPTIONS:"
encodeVInt(cast[int32](w.config.globalOptions), goptions)
f.write(goptions)
f.write(rodNL)
var cmd = "CMD:"
encodeVInt(cast[int32](w.config.cmd), cmd)
f.write(cmd)
f.write(rodNL)
f.write("DEFINES:")
f.write(w.defines)
f.write(rodNL)
var files = "FILES(" & rodNL
for i in countup(0, high(w.files)):
encodeStr(w.files[i], files)
files.add(rodNL)
f.write(files)
f.write(')' & rodNL)
f.write("INCLUDES(" & rodNL)
f.write(w.inclDeps)
f.write(')' & rodNL)
f.write("DEPS:")
f.write(w.modDeps)
f.write(rodNL)
f.write("INTERF(" & rodNL)
f.write(w.interf)
f.write(')' & rodNL)
f.write("COMPILERPROCS(" & rodNL)
f.write(w.compilerProcs)
f.write(')' & rodNL)
f.write("INDEX(" & rodNL)
f.write(w.index.r)
f.write(')' & rodNL)
f.write("IMPORTS(" & rodNL)
f.write(w.imports.r)
f.write(')' & rodNL)
f.write("CONVERTERS:")
f.write(w.converters)
f.write(rodNL)
f.write("METHODS:")
f.write(w.methods)
f.write(rodNL)
f.write("INIT(" & rodNL)
f.write(w.init)
f.write(')' & rodNL)
f.write("DATA(" & rodNL)
f.write(w.data)
f.write(')' & rodNL)
# write trailing zero which is necessary because we use memory mapped files
# for reading:
f.write("\0")
f.close()
#echo "interf: ", w.interf.len
#echo "index: ", w.index.r.len
#echo "init: ", w.init.len
#echo "data: ", w.data.len
proc process(c: PPassContext, n: PNode): PNode =
result = n
if c == nil: return
var w = PRodWriter(c)
case n.kind
of nkStmtList:
for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i])
#var s = n.sons[namePos].sym
#addInterfaceSym(w, s)
of nkProcDef, nkFuncDef, nkIteratorDef, nkConverterDef,
nkTemplateDef, nkMacroDef:
let s = n.sons[namePos].sym
if s == nil: internalError(w.config, n.info, "rodwrite.process")
if n.sons[bodyPos] == nil:
internalError(w.config, n.info, "rodwrite.process: body is nil")
if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
sfForward notin s.flags:
addInterfaceSym(w, s)
of nkMethodDef:
let s = n.sons[namePos].sym
if s == nil: internalError(w.config, n.info, "rodwrite.process")
if n.sons[bodyPos] == nil:
internalError(w.config, n.info, "rodwrite.process: body is nil")
if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
sfForward notin s.flags:
pushSym(w, s)
processStacks(w, false)
of nkVarSection, nkLetSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
addInterfaceSym(w, a.sons[0].sym)
of nkTypeSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.sons[0].kind != nkSym: internalError(w.config, a.info, "rodwrite.process")
var s = a.sons[0].sym
addInterfaceSym(w, s)
# this takes care of enum fields too
# Note: The check for ``s.typ.kind = tyEnum`` is wrong for enum
# type aliasing! Otherwise the same enum symbol would be included
# several times!
#
# if (a.sons[2] <> nil) and (a.sons[2].kind = nkEnumTy) then begin
# a := s.typ.n;
# for j := 0 to sonsLen(a)-1 do
# addInterfaceSym(w, a.sons[j].sym);
# end
of nkImportStmt:
for i in countup(0, sonsLen(n) - 1):
addModDep(w, getModuleName(w.config, n.sons[i]), n.info)
addStmt(w, n)
of nkFromStmt, nkImportExceptStmt:
addModDep(w, getModuleName(w.config, n.sons[0]), n.info)
addStmt(w, n)
of nkIncludeStmt:
for i in countup(0, sonsLen(n) - 1):
addInclDep(w, getModuleName(w.config, n.sons[i]), n.info)
of nkPragma:
addStmt(w, n)
else:
discard
proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
if module.id < 0: internalError(g.config, "rodwrite: module ID not set")
var w = newRodWriter(rodread.getHash FileIndex module.position, module, cache, g.config)
rawAddInterfaceSym(w, module)
result = w
proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
result = process(c, n)
var w = PRodWriter(c)
writeRod(w)
idgen.saveMaxIds(graph.config, graph.config.projectPath / graph.config.projectName)
const rodwritePass* = makePass(open = myOpen, close = myClose, process = process)

View file

@ -56,7 +56,7 @@
# To cache them they are inserted in a `cache` array. # To cache them they are inserted in a `cache` array.
import import
platform, hashes hashes
type type
FormatStr* = string # later we may change it to CString for better FormatStr* = string # later we may change it to CString for better
@ -70,17 +70,6 @@ type
length*: int length*: int
data*: string # != nil if a leaf data*: string # != nil if a leaf
RopeSeq* = seq[Rope]
RopesError* = enum
rCannotOpenFile
rInvalidFormatStr
# implementation
var errorHandler*: proc(err: RopesError, msg: string, useWarning = false)
# avoid dependency on msgs.nim
proc len*(a: Rope): int = proc len*(a: Rope): int =
## the rope's length ## the rope's length
if a == nil: result = 0 if a == nil: result = 0
@ -102,7 +91,7 @@ proc freezeMutableRope*(r: Rope) {.inline.} =
r.length = r.data.len r.length = r.data.len
var var
cache: array[0..2048*2 - 1, Rope] cache: array[0..2048*2 - 1, Rope] # XXX Global here!
proc resetRopeCache* = proc resetRopeCache* =
for i in low(cache)..high(cache): for i in low(cache)..high(cache):
@ -204,13 +193,14 @@ proc writeRope*(f: File, r: Rope) =
## writes a rope to a file. ## writes a rope to a file.
for s in leaves(r): write(f, s) for s in leaves(r): write(f, s)
proc writeRope*(head: Rope, filename: string, useWarning = false) = proc writeRope*(head: Rope, filename: string): bool =
var f: File var f: File
if open(f, filename, fmWrite): if open(f, filename, fmWrite):
if head != nil: writeRope(f, head) if head != nil: writeRope(f, head)
close(f) close(f)
result = true
else: else:
errorHandler(rCannotOpenFile, filename, useWarning) result = false
proc `$`*(r: Rope): string = proc `$`*(r: Rope): string =
## converts a rope back to a string. ## converts a rope back to a string.
@ -225,11 +215,6 @@ proc ropeConcat*(a: varargs[Rope]): Rope =
proc prepend*(a: var Rope, b: Rope) = a = b & a proc prepend*(a: var Rope, b: Rope) = a = b & a
proc prepend*(a: var Rope, b: string) = a = b & a proc prepend*(a: var Rope, b: string) = a = b & a
var
rnl* = tnl.newRope
softRnl* = tnl.newRope
noRnl* = "".newRope
proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope = proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
var i = 0 var i = 0
var length = len(frmt) var length = len(frmt)
@ -254,7 +239,7 @@ proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
if i >= frmt.len or frmt[i] notin {'0'..'9'}: break if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
num = j num = j
if j > high(args) + 1: if j > high(args) + 1:
errorHandler(rInvalidFormatStr, $(j)) doAssert false, "invalid format string: " & frmt
else: else:
add(result, args[j-1]) add(result, args[j-1])
of '{': of '{':
@ -265,20 +250,21 @@ proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
inc(i) inc(i)
num = j num = j
if frmt[i] == '}': inc(i) if frmt[i] == '}': inc(i)
else: errorHandler(rInvalidFormatStr, $(frmt[i])) else:
doAssert false, "invalid format string: " & frmt
if j > high(args) + 1: if j > high(args) + 1:
errorHandler(rInvalidFormatStr, $(j)) doAssert false, "invalid format string: " & frmt
else: else:
add(result, args[j-1]) add(result, args[j-1])
of 'n': of 'n':
add(result, softRnl) add(result, "\n")
inc(i) inc(i)
of 'N': of 'N':
add(result, rnl) add(result, "\n")
inc(i) inc(i)
else: else:
errorHandler(rInvalidFormatStr, $(frmt[i])) doAssert false, "invalid format string: " & frmt
var start = i var start = i
while i < length: while i < length:
if frmt[i] != '$': inc(i) if frmt[i] != '$': inc(i)
@ -350,7 +336,6 @@ proc equalsFile*(r: Rope, filename: string): bool =
proc writeRopeIfNotEqual*(r: Rope, filename: string): bool = proc writeRopeIfNotEqual*(r: Rope, filename: string): bool =
# returns true if overwritten # returns true if overwritten
if not equalsFile(r, filename): if not equalsFile(r, filename):
writeRope(r, filename) result = writeRope(r, filename)
result = true
else: else:
result = false result = false

View file

@ -13,7 +13,7 @@
import import
ast, modules, idents, passes, passaux, condsyms, ast, modules, idents, passes, passaux, condsyms,
options, nimconf, sem, semdata, llstream, vm, vmdef, commands, msgs, options, nimconf, sem, semdata, llstream, vm, vmdef, commands, msgs,
os, times, osproc, wordrecg, strtabs, modulegraphs, configuration os, times, osproc, wordrecg, strtabs, modulegraphs, lineinfos
# we support 'cmpIgnoreStyle' natively for efficiency: # we support 'cmpIgnoreStyle' natively for efficiency:
from strutils import cmpIgnoreStyle, contains from strutils import cmpIgnoreStyle, contains
@ -152,28 +152,27 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
proc runNimScript*(cache: IdentCache; scriptName: string; proc runNimScript*(cache: IdentCache; scriptName: string;
freshDefines=true; conf: ConfigRef) = freshDefines=true; conf: ConfigRef) =
rawMessage(conf, hintConf, scriptName) rawMessage(conf, hintConf, scriptName)
passes.gIncludeFile = includeModule
passes.gImportModule = importModule let graph = newModuleGraph(cache, conf)
let graph = newModuleGraph(conf) connectCallbacks(graph)
if freshDefines: initDefines(conf.symbols) if freshDefines: initDefines(conf.symbols)
defineSymbol(conf.symbols, "nimscript") defineSymbol(conf.symbols, "nimscript")
defineSymbol(conf.symbols, "nimconfig") defineSymbol(conf.symbols, "nimconfig")
registerPass(semPass) registerPass(graph, semPass)
registerPass(evalPass) registerPass(graph, evalPass)
conf.searchPaths.add(conf.libpath) conf.searchPaths.add(conf.libpath)
var m = graph.makeModule(scriptName) var m = graph.makeModule(scriptName)
incl(m.flags, sfMainModule) incl(m.flags, sfMainModule)
vm.globalCtx = setupVM(m, cache, scriptName, graph) graph.vm = setupVM(m, cache, scriptName, graph)
graph.compileSystemModule(cache) graph.compileSystemModule()
discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache) discard graph.processModule(m, llStreamOpen(scriptName, fmRead))
# ensure we load 'system.nim' again for the real non-config stuff! # ensure we load 'system.nim' again for the real non-config stuff!
resetSystemArtifacts(graph) resetSystemArtifacts(graph)
vm.globalCtx = nil
# do not remove the defined symbols # do not remove the defined symbols
#initDefines() #initDefines()
undefSymbol(conf.symbols, "nimscript") undefSymbol(conf.symbols, "nimscript")

View file

@ -13,10 +13,10 @@ import
ast, strutils, hashes, options, lexer, astalgo, trees, treetab, ast, strutils, hashes, options, lexer, astalgo, trees, treetab,
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math, wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
magicsys, parser, nversion, nimsets, semfold, modulepaths, importer, magicsys, parser, nversion, nimsets, semfold, modulepaths, importer,
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch, procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch,
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity, evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
semparallel, lowerings, pluginsupport, plugins.active, rod, configuration semparallel, lowerings, pluginsupport, plugins.active, rod, lineinfos
from modulegraphs import ModuleGraph from modulegraphs import ModuleGraph
@ -53,10 +53,10 @@ proc isArrayConstr(n: PNode): bool {.inline.} =
result = n.kind == nkBracket and result = n.kind == nkBracket and
n.typ.skipTypes(abstractInst).kind == tyArray n.typ.skipTypes(abstractInst).kind == tyArray
template semIdeForTemplateOrGenericCheck(n, requiresCheck) = template semIdeForTemplateOrGenericCheck(conf, n, requiresCheck) =
# we check quickly if the node is where the cursor is # we check quickly if the node is where the cursor is
when defined(nimsuggest): when defined(nimsuggest):
if n.info.fileIndex == gTrackPos.fileIndex and n.info.line == gTrackPos.line: if n.info.fileIndex == conf.m.trackPos.fileIndex and n.info.line == conf.m.trackPos.line:
requiresCheck = true requiresCheck = true
template semIdeForTemplateOrGeneric(c: PContext; n: PNode; template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
@ -96,7 +96,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
proc inferWithMetatype(c: PContext, formal: PType, proc inferWithMetatype(c: PContext, formal: PType,
arg: PNode, coerceDistincts = false): PNode arg: PNode, coerceDistincts = false): PNode
var commonTypeBegin = PType(kind: tyExpr) template commonTypeBegin*(): PType = PType(kind: tyExpr)
proc commonType*(x, y: PType): PType = proc commonType*(x, y: PType): PType =
# new type relation that is used for array constructors, # new type relation that is used for array constructors,
@ -183,7 +183,7 @@ proc commonType*(x: PType, y: PNode): PType =
commonType(x, y.typ) commonType(x, y.typ)
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info) result = newSym(kind, considerQuotedIdent(c, n), getCurrOwner(c), n.info)
when defined(nimsuggest): when defined(nimsuggest):
suggestDecl(c, n, result) suggestDecl(c, n, result)
@ -207,7 +207,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# template; we must fix it here: see #909 # template; we must fix it here: see #909
result.owner = getCurrOwner(c) result.owner = getCurrOwner(c)
else: else:
result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info) result = newSym(kind, considerQuotedIdent(c, n), getCurrOwner(c), n.info)
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule: #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
# incl(result.flags, sfGlobal) # incl(result.flags, sfGlobal)
when defined(nimsuggest): when defined(nimsuggest):
@ -242,14 +242,14 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode flags: TExprFlags = {}): PNode
proc symFromType(t: PType, info: TLineInfo): PSym = proc symFromType(c: PContext; t: PType, info: TLineInfo): PSym =
if t.sym != nil: return t.sym if t.sym != nil: return t.sym
result = newSym(skType, getIdent"AnonType", t.owner, info) result = newSym(skType, getIdent(c.cache, "AnonType"), t.owner, info)
result.flags.incl sfAnon result.flags.incl sfAnon
result.typ = t result.typ = t
proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode = proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
result = newSymNode(symFromType(t, info), info) result = newSymNode(symFromType(c, t, info), info)
result.typ = makeTypeDesc(c, t) result.typ = makeTypeDesc(c, t)
when false: when false:
@ -310,13 +310,13 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
let oldErrorCount = c.config.errorCounter let oldErrorCount = c.config.errorCounter
let oldErrorMax = c.config.errorMax let oldErrorMax = c.config.errorMax
let oldErrorOutputs = errorOutputs let oldErrorOutputs = c.config.m.errorOutputs
errorOutputs = {} c.config.m.errorOutputs = {}
c.config.errorMax = high(int) c.config.errorMax = high(int)
try: try:
result = evalConstExpr(c.module, c.cache, c.graph, e) result = evalConstExpr(c.module, c.graph, e)
if result == nil or result.kind == nkEmpty: if result == nil or result.kind == nkEmpty:
result = nil result = nil
else: else:
@ -327,7 +327,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
c.config.errorCounter = oldErrorCount c.config.errorCounter = oldErrorCount
c.config.errorMax = oldErrorMax c.config.errorMax = oldErrorMax
errorOutputs = oldErrorOutputs c.config.m.errorOutputs = oldErrorOutputs
const const
errConstExprExpected = "constant expression expected" errConstExprExpected = "constant expression expected"
@ -340,12 +340,12 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
result = getConstExpr(c.module, e, c.graph) result = getConstExpr(c.module, e, c.graph)
if result == nil: if result == nil:
#if e.kind == nkEmpty: globalError(n.info, errConstExprExpected) #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected)
result = evalConstExpr(c.module, c.cache, c.graph, e) result = evalConstExpr(c.module, c.graph, e)
if result == nil or result.kind == nkEmpty: if result == nil or result.kind == nkEmpty:
if e.info != n.info: if e.info != n.info:
pushInfoContext(n.info) pushInfoContext(c.config, n.info)
localError(c.config, e.info, errConstExprExpected) localError(c.config, e.info, errConstExprExpected)
popInfoContext() popInfoContext(c.config)
else: else:
localError(c.config, e.info, errConstExprExpected) localError(c.config, e.info, errConstExprExpected)
# error correction: # error correction:
@ -383,8 +383,8 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
## coherence, making sure that variables declared with 'let' aren't ## coherence, making sure that variables declared with 'let' aren't
## reassigned, and binding the unbound identifiers that the macro output ## reassigned, and binding the unbound identifiers that the macro output
## contains. ## contains.
inc(evalTemplateCounter) inc(c.config.evalTemplateCounter)
if evalTemplateCounter > evalTemplateLimit: if c.config.evalTemplateCounter > evalTemplateLimit:
globalError(c.config, s.info, "template instantiation too nested") globalError(c.config, s.info, "template instantiation too nested")
c.friendModules.add(s.owner.getModule) c.friendModules.add(s.owner.getModule)
@ -423,8 +423,8 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
result = semExpr(c, result, flags) result = semExpr(c, result, flags)
result = fitNode(c, retType, result, result.info) result = fitNode(c, retType, result, result.info)
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0])) #globalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
dec(evalTemplateCounter) dec(c.config.evalTemplateCounter)
discard c.friendModules.pop() discard c.friendModules.pop()
const const
@ -432,7 +432,7 @@ const
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode = flags: TExprFlags = {}): PNode =
pushInfoContext(nOrig.info) pushInfoContext(c.config, nOrig.info)
markUsed(c.config, n.info, sym, c.graph.usageSym) markUsed(c.config, n.info, sym, c.graph.usageSym)
styleCheckUse(n.info, sym) styleCheckUse(n.info, sym)
@ -448,11 +448,11 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
#if c.evalContext == nil: #if c.evalContext == nil:
# c.evalContext = c.createEvalContext(emStatic) # c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.module, c.cache, c.graph, n, nOrig, sym) result = evalMacroCall(c.module, c.graph, n, nOrig, sym)
if efNoSemCheck notin flags: if efNoSemCheck notin flags:
result = semAfterMacroCall(c, n, result, sym, flags) result = semAfterMacroCall(c, n, result, sym, flags)
result = wrapInComesFrom(nOrig.info, sym, result) result = wrapInComesFrom(nOrig.info, sym, result)
popInfoContext() popInfoContext(c.config)
proc forceBool(c: PContext, n: PNode): PNode = proc forceBool(c: PContext, n: PNode): PNode =
result = fitNode(c, getSysType(c.graph, n.info, tyBool), n, n.info) result = fitNode(c, getSysType(c.graph, n.info, tyBool), n, n.info)
@ -484,8 +484,8 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
addSon(n, prc.ast) addSon(n, prc.ast)
c.lastGenericIdx = c.generics.len c.lastGenericIdx = c.generics.len
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var c = newContext(graph, module, cache) var c = newContext(graph, module)
if c.p != nil: internalError(graph.config, module.info, "sem.myOpen") if c.p != nil: internalError(graph.config, module.info, "sem.myOpen")
c.semConstExpr = semConstExpr c.semConstExpr = semConstExpr
c.semExpr = semExpr c.semExpr = semExpr
@ -507,19 +507,13 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
graph.systemModule = module graph.systemModule = module
c.topLevelScope = openScope(c) c.topLevelScope = openScope(c)
# don't be verbose unless the module belongs to the main package: # don't be verbose unless the module belongs to the main package:
if module.owner.id == gMainPackageId: if module.owner.id == graph.config.mainPackageId:
graph.config.notes = graph.config.mainPackageNotes graph.config.notes = graph.config.mainPackageNotes
else: else:
if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
graph.config.notes = graph.config.foreignPackageNotes graph.config.notes = graph.config.foreignPackageNotes
result = c result = c
proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext =
result = myOpen(graph, module, rd.cache)
proc replayMethodDefs(graph: ModuleGraph; rd: PRodReader) =
for m in items(rd.methods): methodDef(graph, m, true)
proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool = proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool =
if g.systemModule == nil: return false if g.systemModule == nil: return false
case n.kind case n.kind
@ -585,31 +579,31 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
if c.config.errorMax <= 1: if c.config.errorMax <= 1:
result = semStmtAndGenerateGenerics(c, n) result = semStmtAndGenerateGenerics(c, n)
else: else:
let oldContextLen = msgs.getInfoContextLen() let oldContextLen = msgs.getInfoContextLen(c.config)
let oldInGenericInst = c.inGenericInst let oldInGenericInst = c.inGenericInst
try: try:
result = semStmtAndGenerateGenerics(c, n) result = semStmtAndGenerateGenerics(c, n)
except ERecoverableError, ESuggestDone: except ERecoverableError, ESuggestDone:
recoverContext(c) recoverContext(c)
c.inGenericInst = oldInGenericInst c.inGenericInst = oldInGenericInst
msgs.setInfoContextLen(oldContextLen) msgs.setInfoContextLen(c.config, oldContextLen)
if getCurrentException() of ESuggestDone: if getCurrentException() of ESuggestDone:
c.suggestionsMade = true c.suggestionsMade = true
result = nil result = nil
else: else:
result = ast.emptyNode result = newNodeI(nkEmpty, n.info)
#if c.config.cmd == cmdIdeTools: findSuggest(c, n) #if c.config.cmd == cmdIdeTools: findSuggest(c, n)
rod.storeNode(c.module, result) rod.storeNode(c.graph, c.module, result)
proc testExamples(c: PContext) = proc testExamples(c: PContext) =
let inp = toFullPath(c.module.info) let inp = toFullPath(c.config, c.module.info)
let outp = inp.changeFileExt"" & "_examples.nim" let outp = inp.changeFileExt"" & "_examples.nim"
renderModule(c.runnableExamples, inp, outp) renderModule(c.runnableExamples, inp, outp)
let backend = if isDefined(c.config, "js"): "js" let backend = if isDefined(c.config, "js"): "js"
elif isDefined(c.config, "cpp"): "cpp" elif isDefined(c.config, "cpp"): "cpp"
elif isDefined(c.config, "objc"): "objc" elif isDefined(c.config, "objc"): "objc"
else: "c" else: "c"
if os.execShellCmd("nim " & backend & " -r " & outp) != 0: if os.execShellCmd(os.getAppFilename() & " " & backend & " -r " & outp) != 0:
quit "[Examples] failed" quit "[Examples] failed"
removeFile(outp) removeFile(outp)
@ -625,12 +619,10 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
addCodeForGenerics(c, result) addCodeForGenerics(c, result)
if c.module.ast != nil: if c.module.ast != nil:
result.add(c.module.ast) result.add(c.module.ast)
if c.rd != nil:
replayMethodDefs(graph, c.rd)
popOwner(c) popOwner(c)
popProcCon(c) popProcCon(c)
storeRemaining(c.module) storeRemaining(c.graph, c.module)
if c.runnableExamples != nil: testExamples(c) if c.runnableExamples != nil: testExamples(c)
const semPass* = makePass(myOpen, myOpenCached, myProcess, myClose, const semPass* = makePass(myOpen, myProcess, myClose,
isFrontend = true) isFrontend = true)

View file

@ -157,12 +157,12 @@ proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
proc addVar(father, v, value: PNode) = proc addVar(father, v, value: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info, 3) var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart.sons[0] = v vpart.sons[0] = v
vpart.sons[1] = ast.emptyNode vpart.sons[1] = newNodeI(nkEmpty, v.info)
vpart.sons[2] = value vpart.sons[2] = value
addSon(father, vpart) addSon(father, vpart)
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(lowerings.genPrefix), c.fn, c.info) var temp = newSym(skTemp, getIdent(c.c.cache, lowerings.genPrefix), c.fn, c.info)
temp.typ = getSysType(c.c.graph, body.info, tyInt) temp.typ = getSysType(c.c.graph, body.info, tyInt)
incl(temp.flags, sfFromGeneric) incl(temp.flags, sfFromGeneric)
@ -207,7 +207,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if t.kind == tySequence: if t.kind == tySequence:
# XXX add 'nil' handling here # XXX add 'nil' handling here
body.add newSeqCall(c.c, x, y) body.add newSeqCall(c.c, x, y)
let i = declareCounter(c, body, firstOrd(t)) let i = declareCounter(c, body, firstOrd(c.c.config, t))
let whileLoop = genWhileLoop(c, i, x) let whileLoop = genWhileLoop(c, i, x)
let elemType = t.lastSon let elemType = t.lastSon
liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType), liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
@ -268,17 +268,17 @@ proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp;
a.kind = kind a.kind = kind
let body = newNodeI(nkStmtList, info) let body = newNodeI(nkStmtList, info)
let procname = case kind let procname = case kind
of attachedAsgn: getIdent"=" of attachedAsgn: getIdent(c.cache, "=")
of attachedSink: getIdent"=sink" of attachedSink: getIdent(c.cache, "=sink")
of attachedDeepCopy: getIdent"=deepcopy" of attachedDeepCopy: getIdent(c.cache, "=deepcopy")
of attachedDestructor: getIdent"=destroy" of attachedDestructor: getIdent(c.cache, "=destroy")
result = newSym(skProc, procname, typ.owner, info) result = newSym(skProc, procname, typ.owner, info)
a.fn = result a.fn = result
a.asgnForType = typ a.asgnForType = typ
let dest = newSym(skParam, getIdent"dest", result, info) let dest = newSym(skParam, getIdent(c.cache, "dest"), result, info)
let src = newSym(skParam, getIdent"src", result, info) let src = newSym(skParam, getIdent(c.cache, "src"), result, info)
dest.typ = makeVarType(c, typ) dest.typ = makeVarType(c, typ)
src.typ = typ src.typ = typ
@ -297,7 +297,7 @@ proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp;
of attachedDestructor: typ.destructor = result of attachedDestructor: typ.destructor = result
var n = newNodeI(nkProcDef, info, bodyPos+1) var n = newNodeI(nkProcDef, info, bodyPos+1)
for i in 0 ..< n.len: n.sons[i] = emptyNode for i in 0 ..< n.len: n.sons[i] = newNodeI(nkEmpty, info)
n.sons[namePos] = newSymNode(result) n.sons[namePos] = newSymNode(result)
n.sons[paramsPos] = result.typ.n n.sons[paramsPos] = result.typ.n
n.sons[bodyPos] = body n.sons[bodyPos] = body

View file

@ -170,7 +170,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
add(candidates, renderTree(err.sym.ast, add(candidates, renderTree(err.sym.ast,
{renderNoBody, renderNoComments, renderNoPragmas})) {renderNoBody, renderNoComments, renderNoPragmas}))
else: else:
add(candidates, err.sym.getProcHeader(prefer)) add(candidates, getProcHeader(c.config, err.sym, prefer))
add(candidates, "\n") add(candidates, "\n")
if err.firstMismatch != 0 and n.len > 1: if err.firstMismatch != 0 and n.len > 1:
let cond = n.len > 2 let cond = n.len > 2
@ -213,7 +213,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
# Gives a detailed error message; this is separated from semOverloadedCall, # Gives a detailed error message; this is separated from semOverloadedCall,
# as semOverlodedCall is already pretty slow (and we need this information # as semOverlodedCall is already pretty slow (and we need this information
# only in case of an error). # only in case of an error).
if errorOutputs == {}: if c.config.m.errorOutputs == {}:
# fail fast: # fail fast:
globalError(c.config, n.info, "type mismatch") globalError(c.config, n.info, "type mismatch")
if errors.len == 0: if errors.len == 0:
@ -293,7 +293,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
orig.sons[0..1] = [nil, orig[1], f] orig.sons[0..1] = [nil, orig[1], f]
template tryOp(x) = template tryOp(x) =
let op = newIdentNode(getIdent(x), n.info) let op = newIdentNode(getIdent(c.cache, x), n.info)
n.sons[0] = op n.sons[0] = op
orig.sons[0] = op orig.sons[0] = op
pickBest(op) pickBest(op)
@ -306,17 +306,17 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
elif nfDotSetter in n.flags and f.kind == nkIdent and n.len == 3: elif nfDotSetter in n.flags and f.kind == nkIdent and n.len == 3:
# we need to strip away the trailing '=' here: # we need to strip away the trailing '=' here:
let calleeName = newIdentNode(getIdent(f.ident.s[0..f.ident.s.len-2]), n.info) let calleeName = newIdentNode(getIdent(c.cache, f.ident.s[0..f.ident.s.len-2]), n.info)
let callOp = newIdentNode(getIdent".=", n.info) let callOp = newIdentNode(getIdent(c.cache, ".="), n.info)
n.sons[0..1] = [callOp, n[1], calleeName] n.sons[0..1] = [callOp, n[1], calleeName]
orig.sons[0..1] = [callOp, orig[1], calleeName] orig.sons[0..1] = [callOp, orig[1], calleeName]
pickBest(callOp) pickBest(callOp)
if overloadsState == csEmpty and result.state == csEmpty: if overloadsState == csEmpty and result.state == csEmpty:
if nfDotField in n.flags and nfExplicitCall notin n.flags: if nfDotField in n.flags and nfExplicitCall notin n.flags:
localError(c.config, n.info, errUndeclaredField % considerQuotedIdent(c.config, f, n).s) localError(c.config, n.info, errUndeclaredField % considerQuotedIdent(c, f, n).s)
else: else:
localError(c.config, n.info, errUndeclaredRoutine % considerQuotedIdent(c.config, f, n).s) localError(c.config, n.info, errUndeclaredRoutine % considerQuotedIdent(c, f, n).s)
return return
elif result.state != csMatch: elif result.state != csMatch:
if nfExprCall in n.flags: if nfExprCall in n.flags:
@ -333,7 +333,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
internalAssert c.config, result.state == csMatch internalAssert c.config, result.state == csMatch
#writeMatches(result) #writeMatches(result)
#writeMatches(alt) #writeMatches(alt)
if errorOutputs == {}: if c.config.m.errorOutputs == {}:
# quick error message for performance of 'compiles' built-in: # quick error message for performance of 'compiles' built-in:
globalError(c.config, n.info, errGenerated, "ambiguous call") globalError(c.config, n.info, errGenerated, "ambiguous call")
elif c.config.errorCounter == 0: elif c.config.errorCounter == 0:
@ -345,7 +345,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
add(args, ")") add(args, ")")
localError(c.config, n.info, errAmbiguousCallXYZ % [ localError(c.config, n.info, errAmbiguousCallXYZ % [
getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym), getProcHeader(c.config, result.calleeSym),
getProcHeader(c.config, alt.calleeSym),
args]) args])
proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) = proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =

View file

@ -13,8 +13,8 @@ import
strutils, intsets, options, lexer, ast, astalgo, trees, treetab, strutils, intsets, options, lexer, ast, astalgo, trees, treetab,
wordrecg, wordrecg,
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef, magicsys, nversion, nimsets, parser, times, passes, vmdef,
modulegraphs, configuration modulegraphs, lineinfos
type type
TOptionEntry* = object # entries to put on a stack for pragma parsing TOptionEntry* = object # entries to put on a stack for pragma parsing
@ -75,6 +75,7 @@ type
PContext* = ref TContext PContext* = ref TContext
TContext* = object of TPassContext # a context represents a module TContext* = object of TPassContext # a context represents a module
enforceVoidContext*: PType
module*: PSym # the module sym belonging to the context module*: PSym # the module sym belonging to the context
currentScope*: PScope # current scope currentScope*: PScope # current scope
importTable*: PScope # scope for all imported symbols importTable*: PScope # scope for all imported symbols
@ -148,7 +149,7 @@ proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
proc filename*(c: PContext): string = proc filename*(c: PContext): string =
# the module's filename # the module's filename
return toFilename(FileIndex c.module.position) return toFilename(c.config, FileIndex c.module.position)
proc scopeDepth*(c: PContext): int {.inline.} = proc scopeDepth*(c: PContext): int {.inline.} =
result = if c.currentScope != nil: c.currentScope.depthLevel result = if c.currentScope != nil: c.currentScope.depthLevel
@ -210,8 +211,9 @@ proc newOptionEntry*(conf: ConfigRef): POptionEntry =
result.dynlib = nil result.dynlib = nil
result.notes = conf.notes result.notes = conf.notes
proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext = proc newContext*(graph: ModuleGraph; module: PSym): PContext =
new(result) new(result)
result.enforceVoidContext = PType(kind: tyStmt)
result.ambiguousSymbols = initIntSet() result.ambiguousSymbols = initIntSet()
result.optionStack = @[] result.optionStack = @[]
result.libs = @[] result.libs = @[]
@ -225,7 +227,7 @@ proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext
initStrTable(result.userPragmas) initStrTable(result.userPragmas)
result.generics = @[] result.generics = @[]
result.unknownIdents = initIntSet() result.unknownIdents = initIntSet()
result.cache = cache result.cache = graph.cache
result.graph = graph result.graph = graph
initStrTable(result.signatures) initStrTable(result.signatures)
result.typesWithOps = @[] result.typesWithOps = @[]

View file

@ -26,10 +26,13 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
flags: TExprFlags = {}): PNode = flags: TExprFlags = {}): PNode =
markUsed(c.config, n.info, s, c.graph.usageSym) markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s) styleCheckUse(n.info, s)
pushInfoContext(n.info) pushInfoContext(c.config, n.info)
result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags) result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags)
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
popInfoContext() popInfoContext(c.config)
# XXX: A more elaborate line info rewrite might be needed
result.info = n.info
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
@ -58,7 +61,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# do not produce another redundant error message: # do not produce another redundant error message:
#raiseRecoverableError("") #raiseRecoverableError("")
result = errorNode(c, n) result = errorNode(c, n)
if result.typ == nil or result.typ == enforceVoidContext: if result.typ == nil or result.typ == c.enforceVoidContext:
localError(c.config, n.info, errExprXHasNoType % localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments})) renderTree(result, {renderNoComments}))
result.typ = errorType(c) result.typ = errorType(c)
@ -137,7 +140,7 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
else: else:
discard discard
proc isCastable(dst, src: PType): bool = proc isCastable(conf: ConfigRef; dst, src: PType): bool =
## Checks whether the source type can be cast to the destination type. ## Checks whether the source type can be cast to the destination type.
## Casting is very unrestrictive; casts are allowed as long as ## Casting is very unrestrictive; casts are allowed as long as
## castDest.size >= src.size, and typeAllowed(dst, skParam) ## castDest.size >= src.size, and typeAllowed(dst, skParam)
@ -152,8 +155,8 @@ proc isCastable(dst, src: PType): bool =
return false return false
var dstSize, srcSize: BiggestInt var dstSize, srcSize: BiggestInt
dstSize = computeSize(dst) dstSize = computeSize(conf, dst)
srcSize = computeSize(src) srcSize = computeSize(conf, src)
if dstSize < 0: if dstSize < 0:
result = false result = false
elif srcSize < 0: elif srcSize < 0:
@ -167,7 +170,7 @@ proc isCastable(dst, src: PType): bool =
(skipTypes(dst, abstractInst).kind in IntegralTypes) or (skipTypes(dst, abstractInst).kind in IntegralTypes) or
(skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes) (skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
if result and src.kind == tyNil: if result and src.kind == tyNil:
result = dst.size <= platform.ptrSize result = dst.size <= conf.target.ptrSize
proc isSymChoice(n: PNode): bool {.inline.} = proc isSymChoice(n: PNode): bool {.inline.} =
result = n.kind in nkSymChoices result = n.kind in nkSymChoices
@ -251,7 +254,7 @@ proc semCast(c: PContext, n: PNode): PNode =
let castedExpr = semExprWithType(c, n.sons[1]) let castedExpr = semExprWithType(c, n.sons[1])
if tfHasMeta in targetType.flags: if tfHasMeta in targetType.flags:
localError(c.config, n.sons[0].info, "cannot cast to a non concrete type: '$1'" % $targetType) localError(c.config, n.sons[0].info, "cannot cast to a non concrete type: '$1'" % $targetType)
if not isCastable(targetType, castedExpr.typ): if not isCastable(c.config, targetType, castedExpr.typ):
let tar = $targetType let tar = $targetType
let alt = typeToString(targetType, preferDesc) let alt = typeToString(targetType, preferDesc)
let msg = if tar != alt: tar & "=" & alt else: tar let msg = if tar != alt: tar & "=" & alt else: tar
@ -353,7 +356,7 @@ proc semOpAux(c: PContext, n: PNode) =
var a = n.sons[i] var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2: if a.kind == nkExprEqExpr and sonsLen(a) == 2:
let info = a.sons[0].info let info = a.sons[0].info
a.sons[0] = newIdentNode(considerQuotedIdent(c.config, a.sons[0], a), info) a.sons[0] = newIdentNode(considerQuotedIdent(c, a.sons[0], a), info)
a.sons[1] = semExprWithType(c, a.sons[1], flags) a.sons[1] = semExprWithType(c, a.sons[1], flags)
a.typ = a.sons[1].typ a.typ = a.sons[1].typ
else: else:
@ -361,7 +364,7 @@ proc semOpAux(c: PContext, n: PNode) =
proc overloadedCallOpr(c: PContext, n: PNode): PNode = proc overloadedCallOpr(c: PContext, n: PNode): PNode =
# quick check if there is *any* () operator overloaded: # quick check if there is *any* () operator overloaded:
var par = getIdent("()") var par = getIdent(c.cache, "()")
if searchInScopes(c, par) == nil: if searchInScopes(c, par) == nil:
result = nil result = nil
else: else:
@ -407,7 +410,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
if check and n.kind != nkUInt64Lit: if check and n.kind != nkUInt64Lit:
let value = n.intVal let value = n.intVal
if value < firstOrd(newType) or value > lastOrd(newType): if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
localError(c.config, n.info, "cannot convert " & $value & localError(c.config, n.info, "cannot convert " & $value &
" to " & typeToString(newType)) " to " & typeToString(newType))
else: discard else: discard
@ -617,12 +620,12 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
call.add(a) call.add(a)
#echo "NOW evaluating at compile time: ", call.renderTree #echo "NOW evaluating at compile time: ", call.renderTree
if sfCompileTime in callee.flags: if sfCompileTime in callee.flags:
result = evalStaticExpr(c.module, c.cache, c.graph, call, c.p.owner) result = evalStaticExpr(c.module, c.graph, call, c.p.owner)
if result.isNil: if result.isNil:
localError(c.config, n.info, errCannotInterpretNodeX % renderTree(call)) localError(c.config, n.info, errCannotInterpretNodeX % renderTree(call))
else: result = fixupTypeAfterEval(c, result, n) else: result = fixupTypeAfterEval(c, result, n)
else: else:
result = evalConstExpr(c.module, c.cache, c.graph, call) result = evalConstExpr(c.module, c.graph, call)
if result.isNil: result = n if result.isNil: result = n
else: result = fixupTypeAfterEval(c, result, n) else: result = fixupTypeAfterEval(c, result, n)
#if result != n: #if result != n:
@ -631,10 +634,10 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
proc semStaticExpr(c: PContext, n: PNode): PNode = proc semStaticExpr(c: PContext, n: PNode): PNode =
let a = semExpr(c, n.sons[0]) let a = semExpr(c, n.sons[0])
if a.findUnresolvedStatic != nil: return a if a.findUnresolvedStatic != nil: return a
result = evalStaticExpr(c.module, c.cache, c.graph, a, c.p.owner) result = evalStaticExpr(c.module, c.graph, a, c.p.owner)
if result.isNil: if result.isNil:
localError(c.config, n.info, errCannotInterpretNodeX % renderTree(n)) localError(c.config, n.info, errCannotInterpretNodeX % renderTree(n))
result = emptyNode result = c.graph.emptyNode
else: else:
result = fixupTypeAfterEval(c, result, a) result = fixupTypeAfterEval(c, result, a)
@ -742,10 +745,10 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# This is a proc variable, apply normal overload resolution # This is a proc variable, apply normal overload resolution
let m = resolveIndirectCall(c, n, nOrig, t) let m = resolveIndirectCall(c, n, nOrig, t)
if m.state != csMatch: if m.state != csMatch:
if errorOutputs == {}: if c.config.m.errorOutputs == {}:
# speed up error generation: # speed up error generation:
globalError(c.config, n.info, "type mismatch") globalError(c.config, n.info, "type mismatch")
return emptyNode return c.graph.emptyNode
else: else:
var hasErrorType = false var hasErrorType = false
var msg = "type mismatch: got <" var msg = "type mismatch: got <"
@ -802,7 +805,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc buildEchoStmt(c: PContext, n: PNode): PNode = proc buildEchoStmt(c: PContext, n: PNode): PNode =
# we MUST not check 'n' for semantics again here! But for now we give up: # we MUST not check 'n' for semantics again here! But for now we give up:
result = newNodeI(nkCall, n.info) result = newNodeI(nkCall, n.info)
var e = strTableGet(c.graph.systemModule.tab, getIdent"echo") var e = strTableGet(c.graph.systemModule.tab, getIdent(c.cache, "echo"))
if e != nil: if e != nil:
add(result, newSymNode(e)) add(result, newSymNode(e))
else: else:
@ -866,7 +869,7 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
else: else:
if check == nil: if check == nil:
check = newNodeI(nkCheckedFieldExpr, n.info) check = newNodeI(nkCheckedFieldExpr, n.info)
addSon(check, ast.emptyNode) # make space for access node addSon(check, c.graph.emptyNode) # make space for access node
s = newNodeIT(nkCurly, n.info, setType) s = newNodeIT(nkCurly, n.info, setType)
for j in countup(0, sonsLen(it) - 2): addSon(s, copyTree(it.sons[j])) for j in countup(0, sonsLen(it) - 2): addSon(s, copyTree(it.sons[j]))
var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool)) var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool))
@ -881,7 +884,7 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
if result != nil: if result != nil:
if check == nil: if check == nil:
check = newNodeI(nkCheckedFieldExpr, n.info) check = newNodeI(nkCheckedFieldExpr, n.info)
addSon(check, ast.emptyNode) # make space for access node addSon(check, c.graph.emptyNode) # make space for access node
var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool)) var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool))
addSon(inExpr, newSymNode(c.graph.opContains, n.info)) addSon(inExpr, newSymNode(c.graph.opContains, n.info))
addSon(inExpr, s) addSon(inExpr, s)
@ -938,7 +941,7 @@ proc readTypeParameter(c: PContext, typ: PType,
if rawTyp.n != nil: if rawTyp.n != nil:
return rawTyp.n return rawTyp.n
else: else:
return emptyNode return c.graph.emptyNode
else: else:
let foundTyp = makeTypeDesc(c, rawTyp) let foundTyp = makeTypeDesc(c, rawTyp)
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info) return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
@ -1082,7 +1085,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
when defined(nimsuggest): when defined(nimsuggest):
if c.config.cmd == cmdIdeTools: if c.config.cmd == cmdIdeTools:
suggestExpr(c, n) suggestExpr(c, n)
if exactEquals(gTrackPos, n[1].info): suggestExprNoCheck(c, n) if exactEquals(c.config.m.trackPos, n[1].info): suggestExprNoCheck(c, n)
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule}) var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule})
if s != nil: if s != nil:
@ -1097,7 +1100,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType}) n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
#restoreOldStyleType(n.sons[0]) #restoreOldStyleType(n.sons[0])
var i = considerQuotedIdent(c.config, n.sons[1], n) var i = considerQuotedIdent(c, n.sons[1], n)
var ty = n.sons[0].typ var ty = n.sons[0].typ
var f: PSym = nil var f: PSym = nil
result = nil result = nil
@ -1106,7 +1109,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
case t.kind case t.kind
of tyTypeParamsHolders: of tyTypeParamsHolders:
result = readTypeParameter(c, t, i, n.info) result = readTypeParameter(c, t, i, n.info)
if result == emptyNode: if result == c.graph.emptyNode:
result = n result = n
n.typ = makeTypeFromExpr(c, n.copyTree) n.typ = makeTypeFromExpr(c, n.copyTree)
return return
@ -1217,7 +1220,7 @@ proc dotTransformation(c: PContext, n: PNode): PNode =
addSon(result, n.sons[1]) addSon(result, n.sons[1])
addSon(result, copyTree(n[0])) addSon(result, copyTree(n[0]))
else: else:
var i = considerQuotedIdent(c.config, n.sons[1], n) var i = considerQuotedIdent(c, n.sons[1], n)
result = newNodeI(nkDotCall, n.info) result = newNodeI(nkDotCall, n.info)
result.flags.incl nfDotField result.flags.incl nfDotField
addSon(result, newIdentNode(i, n[1].info)) addSon(result, newIdentNode(i, n[1].info))
@ -1328,11 +1331,11 @@ proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = semSubscript(c, n, flags) result = semSubscript(c, n, flags)
if result == nil: if result == nil:
# overloaded [] operator: # overloaded [] operator:
result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]")) result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "[]")))
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode = proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
var id = considerQuotedIdent(c.config, a[1], a) var id = considerQuotedIdent(c, a[1], a)
var setterId = newIdentNode(getIdent(id.s & '='), n.info) var setterId = newIdentNode(getIdent(c.cache, id.s & '='), n.info)
# a[0] is already checked for semantics, that does ``builtinFieldAccess`` # a[0] is already checked for semantics, that does ``builtinFieldAccess``
# this is ugly. XXX Semantic checking should use the ``nfSem`` flag for # this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
# nodes? # nodes?
@ -1409,7 +1412,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
# --> `[]=`(a, i, x) # --> `[]=`(a, i, x)
a = semSubscript(c, a, {efLValue}) a = semSubscript(c, a, {efLValue})
if a == nil: if a == nil:
result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=") result = buildOverloadedSubscripts(n.sons[0], getIdent(c.cache, "[]="))
add(result, n[1]) add(result, n[1])
if mode == noOverloadedSubscript: if mode == noOverloadedSubscript:
bracketNotFoundError(c, result) bracketNotFoundError(c, result)
@ -1419,7 +1422,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
return result return result
of nkCurlyExpr: of nkCurlyExpr:
# a{i} = x --> `{}=`(a, i, x) # a{i} = x --> `{}=`(a, i, x)
result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=") result = buildOverloadedSubscripts(n.sons[0], getIdent(c.cache, "{}="))
add(result, n[1]) add(result, n[1])
return semExprNoType(c, result) return semExprNoType(c, result)
of nkPar, nkTupleConstr: of nkPar, nkTupleConstr:
@ -1427,7 +1430,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
# unfortunately we need to rewrite ``(x, y) = foo()`` already here so # unfortunately we need to rewrite ``(x, y) = foo()`` already here so
# that overloading of the assignment operator still works. Usually we # that overloading of the assignment operator still works. Usually we
# prefer to do these rewritings in transf.nim: # prefer to do these rewritings in transf.nim:
return semStmt(c, lowerTupleUnpackingForAsgn(n, c.p.owner)) return semStmt(c, lowerTupleUnpackingForAsgn(c.graph, n, c.p.owner))
else: else:
a = semExprWithType(c, a, {efLValue}) a = semExprWithType(c, a, {efLValue})
else: else:
@ -1450,7 +1453,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
rhs = semExprWithType(c, n.sons[1], rhs = semExprWithType(c, n.sons[1],
if lhsIsResult: {efAllowDestructor} else: {}) if lhsIsResult: {efAllowDestructor} else: {})
if lhsIsResult: if lhsIsResult:
n.typ = enforceVoidContext n.typ = c.enforceVoidContext
if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ): if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ):
var rhsTyp = rhs.typ var rhsTyp = rhs.typ
if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass: if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass:
@ -1489,7 +1492,7 @@ proc semReturn(c: PContext, n: PNode): PNode =
n.sons[0] = semAsgn(c, a) n.sons[0] = semAsgn(c, a)
# optimize away ``result = result``: # optimize away ``result = result``:
if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym: if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym:
n.sons[0] = ast.emptyNode n.sons[0] = c.graph.emptyNode
else: else:
localError(c.config, n.info, errNoReturnTypeDeclared) localError(c.config, n.info, errNoReturnTypeDeclared)
else: else:
@ -1556,8 +1559,6 @@ proc semYield(c: PContext, n: PNode): PNode =
checkSonsLen(n, 1, c.config) checkSonsLen(n, 1, c.config)
if c.p.owner == nil or c.p.owner.kind != skIterator: if c.p.owner == nil or c.p.owner.kind != skIterator:
localError(c.config, n.info, errYieldNotAllowedHere) localError(c.config, n.info, errYieldNotAllowedHere)
elif oldIterTransf in c.features and c.p.inTryStmt > 0 and c.p.owner.typ.callConv != ccInline:
localError(c.config, n.info, errYieldNotAllowedInTryStmt)
elif n.sons[0].kind != nkEmpty: elif n.sons[0].kind != nkEmpty:
n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility: n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility:
var iterType = c.p.owner.typ var iterType = c.p.owner.typ
@ -1593,13 +1594,13 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
checkSonsLen(n, 2, c.config) checkSonsLen(n, 2, c.config)
var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope) var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope)
if m != nil and m.kind == skModule: if m != nil and m.kind == skModule:
let ident = considerQuotedIdent(c.config, n[1], n) let ident = considerQuotedIdent(c, n[1], n)
if m == c.module: if m == c.module:
result = strTableGet(c.topLevelScope.symbols, ident) result = strTableGet(c.topLevelScope.symbols, ident)
else: else:
result = strTableGet(m.tab, ident) result = strTableGet(m.tab, ident)
of nkAccQuoted: of nkAccQuoted:
result = lookUpForDefined(c, considerQuotedIdent(c.config, n), onlyCurrentScope) result = lookUpForDefined(c, considerQuotedIdent(c, n), onlyCurrentScope)
of nkSym: of nkSym:
result = n.sym result = n.sym
of nkOpenSymChoice, nkClosedSymChoice: of nkOpenSymChoice, nkClosedSymChoice:
@ -1612,11 +1613,9 @@ proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
checkSonsLen(n, 2, c.config) checkSonsLen(n, 2, c.config)
# we replace this node by a 'true' or 'false' node: # we replace this node by a 'true' or 'false' node:
result = newIntNode(nkIntLit, 0) result = newIntNode(nkIntLit, 0)
if not onlyCurrentScope and considerQuotedIdent(c.config, n[0], n).s == "defined": if not onlyCurrentScope and considerQuotedIdent(c, n[0], n).s == "defined":
if n.sons[1].kind != nkIdent: let d = considerQuotedIdent(c, n[1], n)
localError(c.config, n.info, "obsolete usage of 'defined', use 'declared' instead") result.intVal = ord isDefined(c.config, d.s)
elif isDefined(c.config, n.sons[1].ident.s):
result.intVal = 1
elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil: elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil:
result.intVal = 1 result.intVal = 1
result.info = n.info result.info = n.info
@ -1711,7 +1710,7 @@ proc processQuotations(c: PContext; n: var PNode, op: string,
ids: var seq[PNode]) = ids: var seq[PNode]) =
template returnQuote(q) = template returnQuote(q) =
quotes.add q quotes.add q
n = newIdentNode(getIdent($quotes.len), n.info) n = newIdentNode(getIdent(c.cache, $quotes.len), n.info)
ids.add n ids.add n
return return
@ -1722,7 +1721,7 @@ proc processQuotations(c: PContext; n: var PNode, op: string,
if examinedOp == op: if examinedOp == op:
returnQuote n[1] returnQuote n[1]
elif examinedOp.startsWith(op): elif examinedOp.startsWith(op):
n.sons[0] = newIdentNode(getIdent(examinedOp.substr(op.len)), n.info) n.sons[0] = newIdentNode(getIdent(c.cache, examinedOp.substr(op.len)), n.info)
elif n.kind == nkAccQuoted and op == "``": elif n.kind == nkAccQuoted and op == "``":
returnQuote n[0] returnQuote n[0]
@ -1748,14 +1747,17 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
processQuotations(c, quotedBlock, op, quotes, ids) processQuotations(c, quotedBlock, op, quotes, ids)
var dummyTemplate = newProcNode( var dummyTemplate = newProcNode(
nkTemplateDef, quotedBlock.info, quotedBlock, nkTemplateDef, quotedBlock.info, body = quotedBlock,
name = newAnonSym(c, skTemplate, n.info).newSymNode) params = c.graph.emptyNode,
name = newAnonSym(c, skTemplate, n.info).newSymNode,
pattern = c.graph.emptyNode, genericParams = c.graph.emptyNode,
pragmas = c.graph.emptyNode, exceptions = c.graph.emptyNode)
if ids.len > 0: if ids.len > 0:
dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info) dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "typed").newSymNode # return type dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "typed").newSymNode # return type
ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type
ids.add emptyNode # no default value ids.add c.graph.emptyNode # no default value
dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids) dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids)
var tmpl = semTemplateDef(c, dummyTemplate) var tmpl = semTemplateDef(c, dummyTemplate)
@ -1780,9 +1782,9 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
openScope(c) openScope(c)
let oldOwnerLen = len(c.graph.owners) let oldOwnerLen = len(c.graph.owners)
let oldGenerics = c.generics let oldGenerics = c.generics
let oldErrorOutputs = errorOutputs let oldErrorOutputs = c.config.m.errorOutputs
if efExplain notin flags: errorOutputs = {} if efExplain notin flags: c.config.m.errorOutputs = {}
let oldContextLen = msgs.getInfoContextLen() let oldContextLen = msgs.getInfoContextLen(c.config)
let oldInGenericContext = c.inGenericContext let oldInGenericContext = c.inGenericContext
let oldInUnrolledContext = c.inUnrolledContext let oldInUnrolledContext = c.inUnrolledContext
@ -1804,10 +1806,10 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
c.inGenericInst = oldInGenericInst c.inGenericInst = oldInGenericInst
c.inStaticContext = oldInStaticContext c.inStaticContext = oldInStaticContext
c.p = oldProcCon c.p = oldProcCon
msgs.setInfoContextLen(oldContextLen) msgs.setInfoContextLen(c.config, oldContextLen)
setLen(c.graph.owners, oldOwnerLen) setLen(c.graph.owners, oldOwnerLen)
c.currentScope = oldScope c.currentScope = oldScope
errorOutputs = oldErrorOutputs c.config.m.errorOutputs = oldErrorOutputs
c.config.errorCounter = oldErrorCount c.config.errorCounter = oldErrorCount
c.config.errorMax = oldErrorMax c.config.errorMax = oldErrorMax
@ -1913,7 +1915,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
result.typ = typ result.typ = typ
result.add instantiateCreateFlowVarCall(c, typ, n.info).newSymNode result.add instantiateCreateFlowVarCall(c, typ, n.info).newSymNode
else: else:
result.add emptyNode result.add c.graph.emptyNode
of mProcCall: of mProcCall:
result = setMs(n, s) result = setMs(n, s)
result.sons[1] = semExpr(c, n.sons[1]) result.sons[1] = semExpr(c, n.sons[1])
@ -1937,17 +1939,17 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
of mRunnableExamples: of mRunnableExamples:
if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList: if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList:
if sfMainModule in c.module.flags: if sfMainModule in c.module.flags:
let inp = toFullPath(c.module.info) let inp = toFullPath(c.config, c.module.info)
if c.runnableExamples == nil: if c.runnableExamples == nil:
c.runnableExamples = newTree(nkStmtList, c.runnableExamples = newTree(nkStmtList,
newTree(nkImportStmt, newStrNode(nkStrLit, expandFilename(inp)))) newTree(nkImportStmt, newStrNode(nkStrLit, expandFilename(inp))))
let imports = newTree(nkStmtList) let imports = newTree(nkStmtList)
extractImports(n.lastSon, imports) extractImports(n.lastSon, imports)
for imp in imports: c.runnableExamples.add imp for imp in imports: c.runnableExamples.add imp
c.runnableExamples.add newTree(nkBlockStmt, emptyNode, copyTree n.lastSon) c.runnableExamples.add newTree(nkBlockStmt, c.graph.emptyNode, copyTree n.lastSon)
result = setMs(n, s) result = setMs(n, s)
else: else:
result = emptyNode result = c.graph.emptyNode
else: else:
result = semDirectOp(c, n, flags) result = semDirectOp(c, n, flags)
@ -2040,7 +2042,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
if not isOrdinalType(typ): if not isOrdinalType(typ):
localError(c.config, n.info, errOrdinalTypeExpected) localError(c.config, n.info, errOrdinalTypeExpected)
typ = makeRangeType(c, 0, MaxSetElements-1, n.info) typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
elif lengthOrd(typ) > MaxSetElements: elif lengthOrd(c.config, typ) > MaxSetElements:
typ = makeRangeType(c, 0, MaxSetElements-1, n.info) typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
addSonSkipIntLit(result.typ, typ) addSonSkipIntLit(result.typ, typ)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
@ -2306,7 +2308,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# check if it is an expression macro: # check if it is an expression macro:
checkMinSonsLen(n, 1, c.config) checkMinSonsLen(n, 1, c.config)
#when defined(nimsuggest): #when defined(nimsuggest):
# if gIdeCmd == ideCon and gTrackPos == n.info: suggestExprNoCheck(c, n) # if gIdeCmd == ideCon and c.config.m.trackPos == n.info: suggestExprNoCheck(c, n)
let mode = if nfDotField in n.flags: {} else: {checkUndeclared} let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
var s = qualifiedLookUp(c, n.sons[0], mode) var s = qualifiedLookUp(c, n.sons[0], mode)
if s != nil: if s != nil:
@ -2363,12 +2365,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
checkMinSonsLen(n, 1, c.config) checkMinSonsLen(n, 1, c.config)
result = semArrayAccess(c, n, flags) result = semArrayAccess(c, n, flags)
of nkCurlyExpr: of nkCurlyExpr:
result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags) result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "{}")), flags)
of nkPragmaExpr: of nkPragmaExpr:
var var
expr = n[0] expr = n[0]
pragma = n[1] pragma = n[1]
pragmaName = considerQuotedIdent(c.config, pragma[0]) pragmaName = considerQuotedIdent(c, pragma[0])
flags = flags flags = flags
case whichKeyword(pragmaName) case whichKeyword(pragmaName)

View file

@ -23,10 +23,10 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n
of nkIdent, nkSym: of nkIdent, nkSym:
result = n result = n
let ident = considerQuotedIdent(c.c.config, n) let ident = considerQuotedIdent(c.c, n)
var L = sonsLen(forLoop) var L = sonsLen(forLoop)
if c.replaceByFieldName: if c.replaceByFieldName:
if ident.id == considerQuotedIdent(c.c.config, forLoop[0]).id: if ident.id == considerQuotedIdent(c.c, forLoop[0]).id:
let fieldName = if c.tupleType.isNil: c.field.name.s let fieldName = if c.tupleType.isNil: c.field.name.s
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
else: c.tupleType.n.sons[c.tupleIndex].sym.name.s else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
@ -34,7 +34,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
return return
# other fields: # other fields:
for i in ord(c.replaceByFieldName)..L-3: for i in ord(c.replaceByFieldName)..L-3:
if ident.id == considerQuotedIdent(c.c.config, forLoop[i]).id: if ident.id == considerQuotedIdent(c.c, forLoop[i]).id:
var call = forLoop.sons[L-2] var call = forLoop.sons[L-2]
var tupl = call.sons[i+1-ord(c.replaceByFieldName)] var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
if c.field.isNil: if c.field.isNil:
@ -107,10 +107,10 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
# so that 'break' etc. work as expected, we produce # so that 'break' etc. work as expected, we produce
# a 'while true: stmt; break' loop ... # a 'while true: stmt; break' loop ...
result = newNodeI(nkWhileStmt, n.info, 2) result = newNodeI(nkWhileStmt, n.info, 2)
var trueSymbol = strTableGet(c.graph.systemModule.tab, getIdent"true") var trueSymbol = strTableGet(c.graph.systemModule.tab, getIdent(c.cache, "true"))
if trueSymbol == nil: if trueSymbol == nil:
localError(c.config, n.info, "system needs: 'true'") localError(c.config, n.info, "system needs: 'true'")
trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(c), n.info) trueSymbol = newSym(skUnknown, getIdent(c.cache, "true"), getCurrOwner(c), n.info)
trueSymbol.typ = getSysType(c.graph, n.info, tyBool) trueSymbol.typ = getSysType(c.graph, n.info, tyBool)
result.sons[0] = newSymNode(trueSymbol, n.info) result.sons[0] = newSymNode(trueSymbol, n.info)
@ -162,7 +162,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
# we avoid it now if we can: # we avoid it now if we can:
if containsNode(stmts, {nkBreakStmt}): if containsNode(stmts, {nkBreakStmt}):
var b = newNodeI(nkBreakStmt, n.info) var b = newNodeI(nkBreakStmt, n.info)
b.add(ast.emptyNode) b.add(newNodeI(nkEmpty, n.info))
stmts.add(b) stmts.add(b)
else: else:
result = stmts result = stmts

View file

@ -13,7 +13,7 @@
import import
strutils, options, ast, astalgo, trees, treetab, nimsets, times, strutils, options, ast, astalgo, trees, treetab, nimsets, times,
nversion, platform, math, msgs, os, condsyms, idents, renderer, types, nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
commands, magicsys, modulegraphs, strtabs commands, magicsys, modulegraphs, strtabs, lineinfos
proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode = proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
case skipTypes(n.typ, abstractVarRange).kind case skipTypes(n.typ, abstractVarRange).kind
@ -53,24 +53,24 @@ proc getConstExpr*(m: PSym, n: PNode; g: ModuleGraph): PNode
# expression # expression
proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode
proc checkInRange(n: PNode, res: BiggestInt): bool = proc checkInRange(conf: ConfigRef; n: PNode, res: BiggestInt): bool =
if res in firstOrd(n.typ)..lastOrd(n.typ): if res in firstOrd(conf, n.typ)..lastOrd(conf, n.typ):
result = true result = true
proc foldAdd(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = proc foldAdd(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
let res = a +% b let res = a +% b
if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and
checkInRange(n, res): checkInRange(g.config, n, res):
result = newIntNodeT(res, n, g) result = newIntNodeT(res, n, g)
proc foldSub*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = proc foldSub*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
let res = a -% b let res = a -% b
if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and
checkInRange(n, res): checkInRange(g.config, n, res):
result = newIntNodeT(res, n, g) result = newIntNodeT(res, n, g)
proc foldAbs*(a: BiggestInt, n: PNode; g: ModuleGraph): PNode = proc foldAbs*(a: BiggestInt, n: PNode; g: ModuleGraph): PNode =
if a != firstOrd(n.typ): if a != firstOrd(g.config, n.typ):
result = newIntNodeT(a, n, g) result = newIntNodeT(a, n, g)
proc foldMod*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = proc foldMod*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
@ -82,7 +82,7 @@ proc foldModU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
result = newIntNodeT(a %% b, n, g) result = newIntNodeT(a %% b, n, g)
proc foldDiv*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = proc foldDiv*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
if b != 0'i64 and (a != firstOrd(n.typ) or b != -1'i64): if b != 0'i64 and (a != firstOrd(g.config, n.typ) or b != -1'i64):
result = newIntNodeT(a div b, n, g) result = newIntNodeT(a div b, n, g)
proc foldDivU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = proc foldDivU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
@ -96,7 +96,7 @@ proc foldMul*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
# Fast path for normal case: small multiplicands, and no info # Fast path for normal case: small multiplicands, and no info
# is lost in either method. # is lost in either method.
if resAsFloat == floatProd and checkInRange(n, res): if resAsFloat == floatProd and checkInRange(g.config, n, res):
return newIntNodeT(res, n, g) return newIntNodeT(res, n, g)
# Somebody somewhere lost info. Close enough, or way off? Note # Somebody somewhere lost info. Close enough, or way off? Note
@ -107,7 +107,7 @@ proc foldMul*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
# abs(diff)/abs(prod) <= 1/32 iff # abs(diff)/abs(prod) <= 1/32 iff
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough" # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and
checkInRange(n, res): checkInRange(g.config, n, res):
return newIntNodeT(res, n, g) return newIntNodeT(res, n, g)
proc ordinalValToString*(a: PNode; g: ModuleGraph): string = proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
@ -210,9 +210,9 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n, g) of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n, g)
of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g) of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g)
of mNot: result = newIntNodeT(1 - getInt(a), n, g) of mNot: result = newIntNodeT(1 - getInt(a), n, g)
of mCard: result = newIntNodeT(nimsets.cardSet(a), n, g) of mCard: result = newIntNodeT(nimsets.cardSet(g.config, a), n, g)
of mBitnotI: result = newIntNodeT(not getInt(a), n, g) of mBitnotI: result = newIntNodeT(not getInt(a), n, g)
of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n, g) of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g)
of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr: of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
if a.kind == nkNilLit: if a.kind == nkNilLit:
result = newIntNodeT(0, n, g) result = newIntNodeT(0, n, g)
@ -229,7 +229,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
of mAbsI: result = foldAbs(getInt(a), n, g) of mAbsI: result = foldAbs(getInt(a), n, g)
of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64: of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
# byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64 # byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n, g) result = newIntNodeT(getInt(a) and (`shl`(1, getSize(g.config, a.typ) * 8) - 1), n, g)
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g) of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g)
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g) of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g)
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g) of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g)
@ -304,21 +304,21 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n, g) of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n, g)
of mModU: result = foldModU(getInt(a), getInt(b), n, g) of mModU: result = foldModU(getInt(a), getInt(b), n, g)
of mDivU: result = foldDivU(getInt(a), getInt(b), n, g) of mDivU: result = foldDivU(getInt(a), getInt(b), n, g)
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n, g) of mLeSet: result = newIntNodeT(ord(containsSets(g.config, a, b)), n, g)
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n, g) of mEqSet: result = newIntNodeT(ord(equalSets(g.config, a, b)), n, g)
of mLtSet: of mLtSet:
result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n, g) result = newIntNodeT(ord(containsSets(g.config, a, b) and not equalSets(g.config, a, b)), n, g)
of mMulSet: of mMulSet:
result = nimsets.intersectSets(a, b) result = nimsets.intersectSets(g.config, a, b)
result.info = n.info result.info = n.info
of mPlusSet: of mPlusSet:
result = nimsets.unionSets(a, b) result = nimsets.unionSets(g.config, a, b)
result.info = n.info result.info = n.info
of mMinusSet: of mMinusSet:
result = nimsets.diffSets(a, b) result = nimsets.diffSets(g.config, a, b)
result.info = n.info result.info = n.info
of mSymDiffSet: of mSymDiffSet:
result = nimsets.symdiffSets(a, b) result = nimsets.symdiffSets(g.config, a, b)
result.info = n.info result.info = n.info
of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g) of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g)
of mInSet: result = newIntNodeT(ord(inSet(a, b)), n, g) of mInSet: result = newIntNodeT(ord(inSet(a, b)), n, g)
@ -415,9 +415,9 @@ proc getAppType(n: PNode; g: ModuleGraph): PNode =
proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) = proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
var err = false var err = false
if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}: if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
err = value <% firstOrd(n.typ) or value >% lastOrd(n.typ, fixedUnsigned=true) err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
else: else:
err = value < firstOrd(n.typ) or value > lastOrd(n.typ) err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
if err: if err:
localError(g.config, n.info, "cannot convert " & $value & localError(g.config, n.info, "cannot convert " & $value &
" to " & typeToString(n.typ)) " to " & typeToString(n.typ))
@ -472,7 +472,7 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
else: else:
localError(g.config, n.info, "index out of bounds: " & $n) localError(g.config, n.info, "index out of bounds: " & $n)
of nkBracket: of nkBracket:
idx = idx - x.typ.firstOrd idx = idx - firstOrd(g.config, x.typ)
if idx >= 0 and idx < x.len: result = x.sons[int(idx)] if idx >= 0 and idx < x.len: result = x.sons[int(idx)]
else: localError(g.config, n.info, "index out of bounds: " & $n) else: localError(g.config, n.info, "index out of bounds: " & $n)
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
@ -547,11 +547,11 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
"yyyy-MM-dd"), n, g) "yyyy-MM-dd"), n, g)
of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(), of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(),
"HH:mm:ss"), n, g) "HH:mm:ss"), n, g)
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n, g) of mCpuEndian: result = newIntNodeT(ord(CPU[g.config.target.targetCPU].endian), n, g)
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n, g) of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.targetOS].name), n, g)
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n, g) of mHostCPU: result = newStrNodeT(platform.CPU[g.config.target.targetCPU].name.toLowerAscii, n, g)
of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n, g) of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.hostOS].name), n, g)
of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n, g) of mBuildCPU: result = newStrNodeT(platform.CPU[g.config.target.hostCPU].name.toLowerAscii, n, g)
of mAppType: result = getAppType(n, g) of mAppType: result = getAppType(n, g)
of mNaN: result = newFloatNodeT(NaN, n, g) of mNaN: result = newFloatNodeT(NaN, n, g)
of mInf: result = newFloatNodeT(Inf, n, g) of mInf: result = newFloatNodeT(Inf, n, g)
@ -599,22 +599,22 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
return return
of mSizeOf: of mSizeOf:
var a = n.sons[1] var a = n.sons[1]
if computeSize(a.typ) < 0: if computeSize(g.config, a.typ) < 0:
localError(g.config, a.info, "cannot evaluate 'sizeof' because its type is not defined completely") localError(g.config, a.info, "cannot evaluate 'sizeof' because its type is not defined completely")
result = nil result = nil
elif skipTypes(a.typ, typedescInst+{tyRange}).kind in elif skipTypes(a.typ, typedescInst+{tyRange}).kind in
IntegralTypes+NilableTypes+{tySet}: IntegralTypes+NilableTypes+{tySet}:
#{tyArray,tyObject,tyTuple}: #{tyArray,tyObject,tyTuple}:
result = newIntNodeT(getSize(a.typ), n, g) result = newIntNodeT(getSize(g.config, a.typ), n, g)
else: else:
result = nil result = nil
# XXX: size computation for complex types is still wrong # XXX: size computation for complex types is still wrong
of mLow: of mLow:
result = newIntNodeT(firstOrd(n.sons[1].typ), n, g) result = newIntNodeT(firstOrd(g.config, n.sons[1].typ), n, g)
of mHigh: of mHigh:
if skipTypes(n.sons[1].typ, abstractVar).kind notin if skipTypes(n.sons[1].typ, abstractVar).kind notin
{tySequence, tyString, tyCString, tyOpenArray, tyVarargs}: {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n, g) result = newIntNodeT(lastOrd(g.config, skipTypes(n[1].typ, abstractVar)), n, g)
else: else:
var a = getArrayConstr(m, n.sons[1], g) var a = getArrayConstr(m, n.sons[1], g)
if a.kind == nkBracket: if a.kind == nkBracket:
@ -630,7 +630,7 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
of mLengthArray: of mLengthArray:
# It doesn't matter if the argument is const or not for mLengthArray. # It doesn't matter if the argument is const or not for mLengthArray.
# This fixes bug #544. # This fixes bug #544.
result = newIntNodeT(lengthOrd(n.sons[1].typ), n, g) result = newIntNodeT(lengthOrd(g.config, n.sons[1].typ), n, g)
of mAstToStr: of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g) result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g)
of mConStrStr: of mConStrStr:

View file

@ -55,7 +55,7 @@ template macroToExpandSym(s): untyped =
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
ctx: var GenericCtx; fromDotExpr=false): PNode = ctx: var GenericCtx; fromDotExpr=false): PNode =
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody) semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
case s.kind case s.kind
of skUnknown: of skUnknown:
@ -103,7 +103,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var GenericCtx): PNode = ctx: var GenericCtx): PNode =
result = n result = n
let ident = considerQuotedIdent(c.config, n) let ident = considerQuotedIdent(c, n)
var s = searchInScopes(c, ident).skipAlias(n, c.config) var s = searchInScopes(c, ident).skipAlias(n, c.config)
if s == nil: if s == nil:
s = strTableGet(c.pureEnumFields, ident) s = strTableGet(c.pureEnumFields, ident)
@ -129,7 +129,7 @@ proc newDot(n, b: PNode): PNode =
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var GenericCtx; isMacro: var bool): PNode = ctx: var GenericCtx; isMacro: var bool): PNode =
assert n.kind == nkDotExpr assert n.kind == nkDotExpr
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody) semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
let luf = if withinMixin notin flags: {checkUndeclared, checkModule} else: {checkModule} let luf = if withinMixin notin flags: {checkUndeclared, checkModule} else: {checkModule}
@ -140,7 +140,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx) n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
result = n result = n
let n = n[1] let n = n[1]
let ident = considerQuotedIdent(c.config, n) let ident = considerQuotedIdent(c, n)
var s = searchInScopes(c, ident).skipAlias(n, c.config) var s = searchInScopes(c, ident).skipAlias(n, c.config)
if s != nil and s.kind in routineKinds: if s != nil and s.kind in routineKinds:
isMacro = s.kind in {skTemplate, skMacro} isMacro = s.kind in {skTemplate, skMacro}
@ -170,7 +170,7 @@ proc semGenericStmt(c: PContext, n: PNode,
if withinTypeDesc in flags: inc c.inTypeContext if withinTypeDesc in flags: inc c.inTypeContext
#if conf.cmd == cmdIdeTools: suggestStmt(c, n) #if conf.cmd == cmdIdeTools: suggestStmt(c, n)
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody) semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
case n.kind case n.kind
of nkIdent, nkAccQuoted: of nkIdent, nkAccQuoted:
@ -207,7 +207,7 @@ proc semGenericStmt(c: PContext, n: PNode,
if s == nil and if s == nil and
{withinMixin, withinConcept}*flags == {} and {withinMixin, withinConcept}*flags == {} and
fn.kind in {nkIdent, nkAccQuoted} and fn.kind in {nkIdent, nkAccQuoted} and
considerQuotedIdent(c.config, fn).id notin ctx.toMixin: considerQuotedIdent(c, fn).id notin ctx.toMixin:
errorUndeclaredIdentifier(c, n.info, fn.renderTree) errorUndeclaredIdentifier(c, n.info, fn.renderTree)
var first = int ord(withinConcept in flags) var first = int ord(withinConcept in flags)
@ -275,12 +275,12 @@ proc semGenericStmt(c: PContext, n: PNode,
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx) result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
of nkCurlyExpr: of nkCurlyExpr:
result = newNodeI(nkCall, n.info) result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent("{}"), n.info) result.add newIdentNode(getIdent(c.cache, "{}"), n.info)
for i in 0 ..< n.len: result.add(n[i]) for i in 0 ..< n.len: result.add(n[i])
result = semGenericStmt(c, result, flags, ctx) result = semGenericStmt(c, result, flags, ctx)
of nkBracketExpr: of nkBracketExpr:
result = newNodeI(nkCall, n.info) result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent("[]"), n.info) result.add newIdentNode(getIdent(c.cache, "[]"), n.info)
for i in 0 ..< n.len: result.add(n[i]) for i in 0 ..< n.len: result.add(n[i])
withBracketExpr ctx, n.sons[0]: withBracketExpr ctx, n.sons[0]:
result = semGenericStmt(c, result, flags, ctx) result = semGenericStmt(c, result, flags, ctx)
@ -293,13 +293,13 @@ proc semGenericStmt(c: PContext, n: PNode,
case k case k
of nkCurlyExpr: of nkCurlyExpr:
result = newNodeI(nkCall, n.info) result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent("{}="), n.info) result.add newIdentNode(getIdent(c.cache, "{}="), n.info)
for i in 0 ..< a.len: result.add(a[i]) for i in 0 ..< a.len: result.add(a[i])
result.add(b) result.add(b)
result = semGenericStmt(c, result, flags, ctx) result = semGenericStmt(c, result, flags, ctx)
of nkBracketExpr: of nkBracketExpr:
result = newNodeI(nkCall, n.info) result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent("[]="), n.info) result.add newIdentNode(getIdent(c.cache, "[]="), n.info)
for i in 0 ..< a.len: result.add(a[i]) for i in 0 ..< a.len: result.add(a[i])
result.add(b) result.add(b)
withBracketExpr ctx, a.sons[0]: withBracketExpr ctx, a.sons[0]:
@ -448,7 +448,7 @@ proc semGenericStmt(c: PContext, n: PNode,
flags, ctx) flags, ctx)
if n.sons[paramsPos].kind != nkEmpty: if n.sons[paramsPos].kind != nkEmpty:
if n.sons[paramsPos].sons[0].kind != nkEmpty: if n.sons[paramsPos].sons[0].kind != nkEmpty:
addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info)) addPrelimDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nil, n.info))
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx) n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx) n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx)
var body: PNode var body: PNode

View file

@ -159,13 +159,13 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
var oldPrc = c.generics[i].inst.sym var oldPrc = c.generics[i].inst.sym
pushProcCon(c, oldPrc) pushProcCon(c, oldPrc)
pushOwner(c, oldPrc) pushOwner(c, oldPrc)
pushInfoContext(oldPrc.info) pushInfoContext(c.config, oldPrc.info)
openScope(c) openScope(c)
var n = oldPrc.ast var n = oldPrc.ast
n.sons[bodyPos] = copyTree(s.getBody) n.sons[bodyPos] = copyTree(s.getBody)
instantiateBody(c, n, oldPrc.typ.n, oldPrc, s) instantiateBody(c, n, oldPrc.typ.n, oldPrc, s)
closeScope(c) closeScope(c)
popInfoContext() popInfoContext(c.config)
popOwner(c) popOwner(c)
popProcCon(c) popProcCon(c)
@ -236,7 +236,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
# at this point semtypinst have to become part of sem, because it # at this point semtypinst have to become part of sem, because it
# will need to use openScope, addDecl, etc. # will need to use openScope, addDecl, etc.
#addDecl(c, prc) #addDecl(c, prc)
pushInfoContext(info) pushInfoContext(c.config, info)
var typeMap = initLayeredTypeMap(pt) var typeMap = initLayeredTypeMap(pt)
var cl = initTypeVars(c, addr(typeMap), info, nil) var cl = initTypeVars(c, addr(typeMap), info, nil)
var result = instCopyType(cl, prc.typ) var result = instCopyType(cl, prc.typ)
@ -278,7 +278,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
skipIntLiteralParams(result) skipIntLiteralParams(result)
prc.typ = result prc.typ = result
popInfoContext() popInfoContext(c.config)
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym = info: TLineInfo): PSym =
@ -309,7 +309,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
let gp = n.sons[genericParamsPos] let gp = n.sons[genericParamsPos]
internalAssert c.config, gp.kind != nkEmpty internalAssert c.config, gp.kind != nkEmpty
n.sons[namePos] = newSymNode(result) n.sons[namePos] = newSymNode(result)
pushInfoContext(info) pushInfoContext(c.config, info)
var entry = TInstantiation.new var entry = TInstantiation.new
entry.sym = result entry.sym = result
# we need to compare both the generic types and the concrete types: # we need to compare both the generic types and the concrete types:
@ -328,7 +328,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
inc i inc i
if tfTriggersCompileTime in result.typ.flags: if tfTriggersCompileTime in result.typ.flags:
incl(result.flags, sfCompileTime) incl(result.flags, sfCompileTime)
n.sons[genericParamsPos] = ast.emptyNode n.sons[genericParamsPos] = c.graph.emptyNode
var oldPrc = genericCacheGet(fn, entry[], c.compilesContextId) var oldPrc = genericCacheGet(fn, entry[], c.compilesContextId)
if oldPrc == nil: if oldPrc == nil:
# we MUST not add potentially wrong instantiations to the caching mechanism. # we MUST not add potentially wrong instantiations to the caching mechanism.
@ -353,7 +353,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
else: else:
result = oldPrc result = oldPrc
popProcCon(c) popProcCon(c)
popInfoContext() popInfoContext(c.config)
closeScope(c) # close scope for parameters closeScope(c) # close scope for parameters
popOwner(c) popOwner(c)
c.currentScope = oldScope c.currentScope = oldScope

View file

@ -41,7 +41,7 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
result = semSubscript(c, result, flags) result = semSubscript(c, result, flags)
if result.isNil: if result.isNil:
let x = copyTree(n) let x = copyTree(n)
x.sons[0] = newIdentNode(getIdent"[]", n.info) x.sons[0] = newIdentNode(getIdent(c.cache, "[]"), n.info)
bracketNotFoundError(c, x) bracketNotFoundError(c, x)
#localError(c.config, n.info, "could not resolve: " & $n) #localError(c.config, n.info, "could not resolve: " & $n)
result = n result = n
@ -76,9 +76,9 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
result = newNodeIT(nkTupleConstr, n.info, n.typ) result = newNodeIT(nkTupleConstr, n.info, n.typ)
let idx = expectIntLit(c, n.sons[1]) let idx = expectIntLit(c, n.sons[1])
let useFullPaths = expectIntLit(c, n.sons[2]) let useFullPaths = expectIntLit(c, n.sons[2])
let info = getInfoContext(idx) let info = getInfoContext(c.config, idx)
var filename = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString)) var filename = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
filename.strVal = if useFullPaths != 0: info.toFullPath else: info.toFilename filename.strVal = if useFullPaths != 0: toFullPath(c.config, info) else: toFilename(c.config, info)
var line = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt)) var line = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt))
line.intVal = toLinenumber(info) line.intVal = toLinenumber(info)
var column = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt)) var column = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt))
@ -154,7 +154,7 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
result = newIntNodeT(ord(not complexObj), traitCall, c.graph) result = newIntNodeT(ord(not complexObj), traitCall, c.graph)
else: else:
localError(c.config, traitCall.info, "unknown trait") localError(c.config, traitCall.info, "unknown trait")
result = emptyNode result = newNodeI(nkEmpty, traitCall.info)
proc semTypeTraits(c: PContext, n: PNode): PNode = proc semTypeTraits(c: PContext, n: PNode): PNode =
checkMinSonsLen(n, 2, c.config) checkMinSonsLen(n, 2, c.config)
@ -174,7 +174,7 @@ proc semOrd(c: PContext, n: PNode): PNode =
if isOrdinalType(parType): if isOrdinalType(parType):
discard discard
elif parType.kind == tySet: elif parType.kind == tySet:
result.typ = makeRangeType(c, firstOrd(parType), lastOrd(parType), n.info) result.typ = makeRangeType(c, firstOrd(c.config, parType), lastOrd(c.config, parType), n.info)
else: else:
localError(c.config, n.info, errOrdinalTypeExpected) localError(c.config, n.info, errOrdinalTypeExpected)
result.typ = errorType(c) result.typ = errorType(c)
@ -194,7 +194,7 @@ proc semBindSym(c: PContext, n: PNode): PNode =
localError(c.config, n.sons[2].info, errConstExprExpected) localError(c.config, n.sons[2].info, errConstExprExpected)
return errorNode(c, n) return errorNode(c, n)
let id = newIdentNode(getIdent(sl.strVal), n.info) let id = newIdentNode(getIdent(c.cache, sl.strVal), n.info)
let s = qualifiedLookUp(c, id, {checkUndeclared}) let s = qualifiedLookUp(c, id, {checkUndeclared})
if s != nil: if s != nil:
# we need to mark all symbols: # we need to mark all symbols:
@ -209,10 +209,6 @@ proc semBindSym(c: PContext, n: PNode): PNode =
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
proc isStrangeArray(t: PType): bool =
let t = t.skipTypes(abstractInst)
result = t.kind == tyArray and t.firstOrd != 0
proc semOf(c: PContext, n: PNode): PNode = proc semOf(c: PContext, n: PNode): PNode =
if sonsLen(n) == 3: if sonsLen(n) == 3:
n.sons[1] = semExprWithType(c, n.sons[1]) n.sons[1] = semExprWithType(c, n.sons[1])
@ -283,7 +279,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mRoof: of mRoof:
localError(c.config, n.info, "builtin roof operator is not supported anymore") localError(c.config, n.info, "builtin roof operator is not supported anymore")
of mPlugin: of mPlugin:
let plugin = getPlugin(n[0].sym) let plugin = getPlugin(c.cache, n[0].sym)
if plugin.isNil: if plugin.isNil:
localError(c.config, n.info, "cannot find plugin " & n[0].sym.name.s) localError(c.config, n.info, "cannot find plugin " & n[0].sym.name.s)
result = n result = n

View file

@ -54,7 +54,7 @@ proc locateFieldInInitExpr(c: PContext, field: PSym, initExpr: PNode): PNode =
invalidObjConstr(c, assignment) invalidObjConstr(c, assignment)
continue continue
if fieldId == considerQuotedIdent(c.config, assignment[0]).id: if fieldId == considerQuotedIdent(c, assignment[0]).id:
return assignment return assignment
proc semConstrField(c: PContext, flags: TExprFlags, proc semConstrField(c: PContext, flags: TExprFlags,
@ -295,11 +295,11 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
if field.kind != nkExprColonExpr: if field.kind != nkExprColonExpr:
invalidObjConstr(c, field) invalidObjConstr(c, field)
continue continue
let id = considerQuotedIdent(c.config, field[0]) let id = considerQuotedIdent(c, field[0])
# This node was not processed. There are two possible reasons: # This node was not processed. There are two possible reasons:
# 1) It was shadowed by a field with the same name on the left # 1) It was shadowed by a field with the same name on the left
for j in 1 ..< i: for j in 1 ..< i:
let prevId = considerQuotedIdent(c.config, result[j][0]) let prevId = considerQuotedIdent(c, result[j][0])
if prevId.id == id.id: if prevId.id == id.id:
localError(c.config, field.info, errFieldInitTwice % id.s) localError(c.config, field.info, errFieldInitTwice % id.s)
return return

View file

@ -136,8 +136,8 @@ proc checkLe(c: AnalysisCtx; a, b: PNode) =
localError(c.graph.config, a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)") localError(c.graph.config, a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)")
proc checkBounds(c: AnalysisCtx; arr, idx: PNode) = proc checkBounds(c: AnalysisCtx; arr, idx: PNode) =
checkLe(c, arr.lowBound, idx) checkLe(c, lowBound(c.graph.config, arr), idx)
checkLe(c, idx, arr.highBound(c.guards.o)) checkLe(c, idx, highBound(c.graph.config, arr, c.guards.o))
proc addLowerBoundAsFacts(c: var AnalysisCtx) = proc addLowerBoundAsFacts(c: var AnalysisCtx) =
for v in c.locals: for v in c.locals:
@ -438,7 +438,7 @@ proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode =
let t = b[1][0].typ.sons[0] let t = b[1][0].typ.sons[0]
if spawnResult(t, true) == srByVar: if spawnResult(t, true) == srByVar:
result.add wrapProcForSpawn(g, owner, m, b.typ, barrier, it[0]) result.add wrapProcForSpawn(g, owner, m, b.typ, barrier, it[0])
it.sons[it.len-1] = emptyNode it.sons[it.len-1] = newNodeI(nkEmpty, it.info)
else: else:
it.sons[it.len-1] = wrapProcForSpawn(g, owner, m, b.typ, barrier, nil) it.sons[it.len-1] = wrapProcForSpawn(g, owner, m, b.typ, barrier, nil)
if result.isNil: result = n if result.isNil: result = n
@ -483,7 +483,7 @@ proc liftParallel*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
checkArgs(a, body) checkArgs(a, body)
var varSection = newNodeI(nkVarSection, n.info) var varSection = newNodeI(nkVarSection, n.info)
var temp = newSym(skTemp, getIdent"barrier", owner, n.info) var temp = newSym(skTemp, getIdent(g.cache, "barrier"), owner, n.info)
temp.typ = magicsys.getCompilerProc(g, "Barrier").typ temp.typ = magicsys.getCompilerProc(g, "Barrier").typ
incl(temp.flags, sfFromGeneric) incl(temp.flags, sfFromGeneric)
let tempNode = newSymNode(temp) let tempNode = newSymNode(temp)

View file

@ -9,7 +9,7 @@
import import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
wordrecg, strutils, options, guards, writetracking, configuration, wordrecg, strutils, options, guards, writetracking, lineinfos,
modulegraphs modulegraphs
when defined(useDfa): when defined(useDfa):
@ -185,7 +185,7 @@ proc markGcUnsafe(a: PEffects; reason: PNode) =
if reason.kind == nkSym: if reason.kind == nkSym:
a.owner.gcUnsafetyReason = reason.sym a.owner.gcUnsafetyReason = reason.sym
else: else:
a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"), a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name,
a.owner, reason.info, {}) a.owner, reason.info, {})
when true: when true:
@ -410,7 +410,7 @@ proc effectSpec(n: PNode, effectType: TSpecialWord): PNode =
result.add(it.sons[1]) result.add(it.sons[1])
return return
proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int): PNode = proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
let spec = effectSpec(x, effectType) let spec = effectSpec(x, effectType)
if isNil(spec): if isNil(spec):
let s = n.sons[namePos].sym let s = n.sons[namePos].sym
@ -424,14 +424,14 @@ proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
for i in 0 ..< real.len: for i in 0 ..< real.len:
var t = typeToString(real[i].typ) var t = typeToString(real[i].typ)
if t.startsWith("ref "): t = substr(t, 4) if t.startsWith("ref "): t = substr(t, 4)
effects.sons[i] = newIdentNode(getIdent(t), n.info) effects.sons[i] = newIdentNode(getIdent(cache, t), n.info)
# set the type so that the following analysis doesn't screw up: # set the type so that the following analysis doesn't screw up:
effects.sons[i].typ = real[i].typ effects.sons[i].typ = real[i].typ
result = newNode(nkExprColonExpr, n.info, @[ result = newNode(nkExprColonExpr, n.info, @[
newIdentNode(getIdent(specialWords[effectType]), n.info), effects]) newIdentNode(getIdent(cache, specialWords[effectType]), n.info), effects])
proc documentWriteEffect(n: PNode; flag: TSymFlag; pragmaName: string): PNode = proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode =
let s = n.sons[namePos].sym let s = n.sons[namePos].sym
let params = s.typ.n let params = s.typ.n
@ -442,21 +442,21 @@ proc documentWriteEffect(n: PNode; flag: TSymFlag; pragmaName: string): PNode =
if effects.len > 0: if effects.len > 0:
result = newNode(nkExprColonExpr, n.info, @[ result = newNode(nkExprColonExpr, n.info, @[
newIdentNode(getIdent(pragmaName), n.info), effects]) newIdentNode(getIdent(cache, pragmaName), n.info), effects])
proc documentNewEffect(n: PNode): PNode = proc documentNewEffect(cache: IdentCache; n: PNode): PNode =
let s = n.sons[namePos].sym let s = n.sons[namePos].sym
if tfReturnsNew in s.typ.flags: if tfReturnsNew in s.typ.flags:
result = newIdentNode(getIdent("new"), n.info) result = newIdentNode(getIdent(cache, "new"), n.info)
proc documentRaises*(n: PNode) = proc documentRaises*(cache: IdentCache; n: PNode) =
if n.sons[namePos].kind != nkSym: return if n.sons[namePos].kind != nkSym: return
let pragmas = n.sons[pragmasPos] let pragmas = n.sons[pragmasPos]
let p1 = documentEffect(n, pragmas, wRaises, exceptionEffects) let p1 = documentEffect(cache, n, pragmas, wRaises, exceptionEffects)
let p2 = documentEffect(n, pragmas, wTags, tagEffects) let p2 = documentEffect(cache, n, pragmas, wTags, tagEffects)
let p3 = documentWriteEffect(n, sfWrittenTo, "writes") let p3 = documentWriteEffect(cache, n, sfWrittenTo, "writes")
let p4 = documentNewEffect(n) let p4 = documentNewEffect(cache, n)
let p5 = documentWriteEffect(n, sfEscapes, "escapes") let p5 = documentWriteEffect(cache, n, sfEscapes, "escapes")
if p1 != nil or p2 != nil or p3 != nil or p4 != nil or p5 != nil: if p1 != nil or p2 != nil or p3 != nil or p4 != nil or p5 != nil:
if pragmas.kind == nkEmpty: if pragmas.kind == nkEmpty:
@ -859,9 +859,9 @@ proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool
used.incl(s) used.incl(s)
break search break search
# XXX call graph analysis would be nice here! # XXX call graph analysis would be nice here!
pushInfoContext(spec.info) pushInfoContext(g.config, spec.info)
localError(g.config, r.info, errGenerated, msg & typeToString(r.typ)) localError(g.config, r.info, errGenerated, msg & typeToString(r.typ))
popInfoContext() popInfoContext(g.config)
# hint about unnecessarily listed exception types: # hint about unnecessarily listed exception types:
if hints: if hints:
for s in 0 ..< spec.len: for s in 0 ..< spec.len:
@ -915,8 +915,8 @@ proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects) =
newSeq(effects.sons, effectListLen) newSeq(effects.sons, effectListLen)
effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info) effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
effects.sons[tagEffects] = newNodeI(nkArgList, s.info) effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
effects.sons[usesEffects] = ast.emptyNode effects.sons[usesEffects] = g.emptyNode
effects.sons[writeEffects] = ast.emptyNode effects.sons[writeEffects] = g.emptyNode
t.exc = effects.sons[exceptionEffects] t.exc = effects.sons[exceptionEffects]
t.tags = effects.sons[tagEffects] t.tags = effects.sons[tagEffects]

View file

@ -36,8 +36,6 @@ const
errRecursiveDependencyX = "recursive dependency: '$1'" errRecursiveDependencyX = "recursive dependency: '$1'"
errPragmaOnlyInHeaderOfProcX = "pragmas are only allowed in the header of a proc; redefinition of $1" errPragmaOnlyInHeaderOfProcX = "pragmas are only allowed in the header of a proc; redefinition of $1"
var enforceVoidContext = PType(kind: tyStmt) # XXX global variable here
proc semDiscard(c: PContext, n: PNode): PNode = proc semDiscard(c: PContext, n: PNode): PNode =
result = n result = n
checkSonsLen(n, 1, c.config) checkSonsLen(n, 1, c.config)
@ -87,15 +85,15 @@ proc semWhile(c: PContext, n: PNode): PNode =
n.sons[1] = semStmt(c, n.sons[1]) n.sons[1] = semStmt(c, n.sons[1])
dec(c.p.nestedLoopCounter) dec(c.p.nestedLoopCounter)
closeScope(c) closeScope(c)
if n.sons[1].typ == enforceVoidContext: if n.sons[1].typ == c.enforceVoidContext:
result.typ = enforceVoidContext result.typ = c.enforceVoidContext
proc toCover(t: PType): BiggestInt = proc toCover(c: PContext, t: PType): BiggestInt =
var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc}) let t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
if t2.kind == tyEnum and enumHasHoles(t2): if t2.kind == tyEnum and enumHasHoles(t2):
result = sonsLen(t2.n) result = sonsLen(t2.n)
else: else:
result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc})) result = lengthOrd(c.config, skipTypes(t, abstractVar-{tyTypeDesc}))
proc semProc(c: PContext, n: PNode): PNode proc semProc(c: PContext, n: PNode): PNode
@ -146,7 +144,7 @@ proc discardCheck(c: PContext, result: PNode) =
result.typ.typeToString & "' and has to be discarded" result.typ.typeToString & "' and has to be discarded"
if result.info.line != n.info.line or if result.info.line != n.info.line or
result.info.fileIndex != n.info.fileIndex: result.info.fileIndex != n.info.fileIndex:
s.add "; start of expression here: " & $result.info s.add "; start of expression here: " & c.config$result.info
if result.typ.kind == tyProc: if result.typ.kind == tyProc:
s.add "; for a function call use ()" s.add "; for a function call use ()"
localError(c.config, n.info, s) localError(c.config, n.info, s)
@ -173,7 +171,7 @@ proc semIf(c: PContext, n: PNode): PNode =
for it in n: discardCheck(c, it.lastSon) for it in n: discardCheck(c, it.lastSon)
result.kind = nkIfStmt result.kind = nkIfStmt
# propagate any enforced VoidContext: # propagate any enforced VoidContext:
if typ == enforceVoidContext: result.typ = enforceVoidContext if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext
else: else:
for it in n: for it in n:
let j = it.len-1 let j = it.len-1
@ -203,7 +201,7 @@ proc semCase(c: PContext, n: PNode): PNode =
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
var x = n.sons[i] var x = n.sons[i]
when defined(nimsuggest): when defined(nimsuggest):
if c.config.ideCmd == ideSug and exactEquals(gTrackPos, x.info) and caseTyp.kind == tyEnum: if c.config.ideCmd == ideSug and exactEquals(c.config.m.trackPos, x.info) and caseTyp.kind == tyEnum:
suggestEnum(c, x, caseTyp) suggestEnum(c, x, caseTyp)
case x.kind case x.kind
of nkOfBranch: of nkOfBranch:
@ -230,7 +228,7 @@ proc semCase(c: PContext, n: PNode): PNode =
else: else:
illFormedAst(x, c.config) illFormedAst(x, c.config)
if chckCovered: if chckCovered:
if covered == toCover(n.sons[0].typ): if covered == toCover(c, n.sons[0].typ):
hasElse = true hasElse = true
else: else:
localError(c.config, n.info, "not all cases are covered") localError(c.config, n.info, "not all cases are covered")
@ -238,8 +236,8 @@ proc semCase(c: PContext, n: PNode): PNode =
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
# propagate any enforced VoidContext: # propagate any enforced VoidContext:
if typ == enforceVoidContext: if typ == c.enforceVoidContext:
result.typ = enforceVoidContext result.typ = c.enforceVoidContext
else: else:
for i in 1..n.len-1: for i in 1..n.len-1:
var it = n.sons[i] var it = n.sons[i]
@ -318,8 +316,8 @@ proc semTry(c: PContext, n: PNode): PNode =
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr}: if isEmptyType(typ) or typ.kind in {tyNil, tyExpr}:
discardCheck(c, n.sons[0]) discardCheck(c, n.sons[0])
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
if typ == enforceVoidContext: if typ == c.enforceVoidContext:
result.typ = enforceVoidContext result.typ = c.enforceVoidContext
else: else:
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon) if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon)
n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info) n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info)
@ -394,7 +392,7 @@ proc isDiscardUnderscore(v: PSym): bool =
result = true result = true
proc semUsing(c: PContext; n: PNode): PNode = proc semUsing(c: PContext; n: PNode): PNode =
result = ast.emptyNode result = c.graph.emptyNode
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "using") if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "using")
for i in countup(0, sonsLen(n)-1): for i in countup(0, sonsLen(n)-1):
var a = n.sons[i] var a = n.sons[i]
@ -442,10 +440,10 @@ proc makeDeref(n: PNode): PNode =
proc fillPartialObject(c: PContext; n: PNode; typ: PType) = proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
if n.len == 2: if n.len == 2:
let x = semExprWithType(c, n[0]) let x = semExprWithType(c, n[0])
let y = considerQuotedIdent(c.config, n[1]) let y = considerQuotedIdent(c, n[1])
let obj = x.typ.skipTypes(abstractPtrs) let obj = x.typ.skipTypes(abstractPtrs)
if obj.kind == tyObject and tfPartial in obj.flags: if obj.kind == tyObject and tfPartial in obj.flags:
let field = newSym(skField, getIdent(y.s), obj.sym, n[1].info) let field = newSym(skField, getIdent(c.cache, y.s), obj.sym, n[1].info)
field.typ = skipIntLit(typ) field.typ = skipIntLit(typ)
field.position = sonsLen(obj.n) field.position = sonsLen(obj.n)
addSon(obj.n, newSymNode(field)) addSon(obj.n, newSymNode(field))
@ -481,7 +479,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
typ = semTypeNode(c, a.sons[length-2], nil) typ = semTypeNode(c, a.sons[length-2], nil)
else: else:
typ = nil typ = nil
var def: PNode = ast.emptyNode var def: PNode = c.graph.emptyNode
if a.sons[length-1].kind != nkEmpty: if a.sons[length-1].kind != nkEmpty:
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor}) def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
if def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro: if def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
@ -571,8 +569,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
b.sons[j] = newSymNode(v) b.sons[j] = newSymNode(v)
checkNilable(c, v) checkNilable(c, v)
if sfCompileTime in v.flags: hasCompileTime = true if sfCompileTime in v.flags: hasCompileTime = true
if v.flags * {sfGlobal, sfThread} == {sfGlobal}:
message(c.config, v.info, hintGlobalVar)
if hasCompileTime: if hasCompileTime:
vm.setupCompileTimeVar(c.module, c.cache, c.graph, result) vm.setupCompileTimeVar(c.module, c.graph, result)
# handled by the VM codegen:
#c.graph.recordStmt(c.graph, c.module, result)
proc semConst(c: PContext, n: PNode): PNode = proc semConst(c: PContext, n: PNode): PNode =
result = copyNode(n) result = copyNode(n)
@ -664,7 +666,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
proc implicitIterator(c: PContext, it: string, arg: PNode): PNode = proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
result = newNodeI(nkCall, arg.info) result = newNodeI(nkCall, arg.info)
result.add(newIdentNode(it.getIdent, arg.info)) result.add(newIdentNode(getIdent(c.cache, it), arg.info))
if arg.typ != nil and arg.typ.kind in {tyVar, tyLent}: if arg.typ != nil and arg.typ.kind in {tyVar, tyLent}:
result.add newDeref(arg) result.add newDeref(arg)
else: else:
@ -698,7 +700,8 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode =
match = symx match = symx
else: else:
localError(c.config, n.info, errAmbiguousCallXYZ % [ localError(c.config, n.info, errAmbiguousCallXYZ % [
getProcHeader(match), getProcHeader(symx), $iterExpr]) getProcHeader(c.config, match),
getProcHeader(c.config, symx), $iterExpr])
symx = nextOverloadIter(o, c, headSymbol) symx = nextOverloadIter(o, c, headSymbol)
if match == nil: return if match == nil: return
@ -746,8 +749,8 @@ proc semFor(c: PContext, n: PNode): PNode =
else: else:
result = semForVars(c, n) result = semForVars(c, n)
# propagate any enforced VoidContext: # propagate any enforced VoidContext:
if n.sons[length-1].typ == enforceVoidContext: if n.sons[length-1].typ == c.enforceVoidContext:
result.typ = enforceVoidContext result.typ = c.enforceVoidContext
closeScope(c) closeScope(c)
proc semRaise(c: PContext, n: PNode): PNode = proc semRaise(c: PContext, n: PNode): PNode =
@ -795,8 +798,8 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
let name = a.sons[0] let name = a.sons[0]
var s: PSym var s: PSym
if name.kind == nkDotExpr and a[2].kind == nkObjectTy: if name.kind == nkDotExpr and a[2].kind == nkObjectTy:
let pkgName = considerQuotedIdent(c.config, name[0]) let pkgName = considerQuotedIdent(c, name[0])
let typName = considerQuotedIdent(c.config, name[1]) let typName = considerQuotedIdent(c, name[1])
let pkg = c.graph.packageSyms.strTableGet(pkgName) let pkg = c.graph.packageSyms.strTableGet(pkgName)
if pkg.isNil or pkg.kind != skPackage: if pkg.isNil or pkg.kind != skPackage:
localError(c.config, name.info, "unknown package name: " & pkgName.s) localError(c.config, name.info, "unknown package name: " & pkgName.s)
@ -834,7 +837,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
typsym.info = s.info typsym.info = s.info
else: else:
localError(c.config, name.info, "cannot complete type '" & s.name.s & "' twice; " & localError(c.config, name.info, "cannot complete type '" & s.name.s & "' twice; " &
"previous type completion was here: " & $typsym.info) "previous type completion was here: " & c.config$typsym.info)
s = typsym s = typsym
# add it here, so that recursive types are possible: # add it here, so that recursive types are possible:
if sfGenSym notin s.flags: addInterfaceDecl(c, s) if sfGenSym notin s.flags: addInterfaceDecl(c, s)
@ -988,7 +991,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
internalAssert c.config, st.kind in {tyPtr, tyRef} internalAssert c.config, st.kind in {tyPtr, tyRef}
internalAssert c.config, st.lastSon.sym == nil internalAssert c.config, st.lastSon.sym == nil
incl st.flags, tfRefsAnonObj incl st.flags, tfRefsAnonObj
let obj = newSym(skType, getIdent(s.name.s & ":ObjectType"), let obj = newSym(skType, getIdent(c.cache, s.name.s & ":ObjectType"),
getCurrOwner(c), s.info) getCurrOwner(c), s.info)
obj.typ = st.lastSon obj.typ = st.lastSon
st.lastSon.sym = obj st.lastSon.sym = obj
@ -1056,9 +1059,9 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
var f = checkModuleName(c.config, n.sons[i]) var f = checkModuleName(c.config, n.sons[i])
if f != InvalidFileIDX: if f != InvalidFileIDX:
if containsOrIncl(c.includedFiles, f.int): if containsOrIncl(c.includedFiles, f.int):
localError(c.config, n.info, errRecursiveDependencyX % f.toFilename) localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f))
else: else:
let code = gIncludeFile(c.graph, c.module, f, c.cache) let code = c.graph.includeFileCallback(c.graph, c.module, f)
gatherStmts c, code, result gatherStmts c, code, result
excl(c.includedFiles, f.int) excl(c.includedFiles, f.int)
of nkStmtList: of nkStmtList:
@ -1130,7 +1133,7 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) = proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
if t != nil: if t != nil:
var s = newSym(skResult, getIdent"result", getCurrOwner(c), info) var s = newSym(skResult, getIdent(c.cache, "result"), getCurrOwner(c), info)
s.typ = t s.typ = t
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
addParamOrResult(c, s, owner) addParamOrResult(c, s, owner)
@ -1149,7 +1152,7 @@ proc lookupMacro(c: PContext, n: PNode): PSym =
result = n.sym result = n.sym
if result.kind notin {skMacro, skTemplate}: result = nil if result.kind notin {skMacro, skTemplate}: result = nil
else: else:
result = searchInScopes(c, considerQuotedIdent(c.config, n), {skMacro, skTemplate}) result = searchInScopes(c, considerQuotedIdent(c, n), {skMacro, skTemplate})
proc semProcAnnotation(c: PContext, prc: PNode; proc semProcAnnotation(c: PContext, prc: PNode;
validPragmas: TSpecialWords): PNode = validPragmas: TSpecialWords): PNode =
@ -1161,7 +1164,7 @@ proc semProcAnnotation(c: PContext, prc: PNode;
let m = lookupMacro(c, key) let m = lookupMacro(c, key)
if m == nil: if m == nil:
if key.kind == nkIdent and key.ident.id == ord(wDelegator): if key.kind == nkIdent and key.ident.id == ord(wDelegator):
if considerQuotedIdent(c.config, prc.sons[namePos]).s == "()": if considerQuotedIdent(c, prc.sons[namePos]).s == "()":
prc.sons[namePos] = newIdentNode(c.cache.idDelegator, prc.info) prc.sons[namePos] = newIdentNode(c.cache.idDelegator, prc.info)
prc.sons[pragmasPos] = copyExcept(n, i) prc.sons[pragmasPos] = copyExcept(n, i)
else: else:
@ -1176,7 +1179,7 @@ proc semProcAnnotation(c: PContext, prc: PNode;
x.add(newSymNode(m)) x.add(newSymNode(m))
prc.sons[pragmasPos] = copyExcept(n, i) prc.sons[pragmasPos] = copyExcept(n, i)
if prc[pragmasPos].kind != nkEmpty and prc[pragmasPos].len == 0: if prc[pragmasPos].kind != nkEmpty and prc[pragmasPos].len == 0:
prc.sons[pragmasPos] = emptyNode prc.sons[pragmasPos] = c.graph.emptyNode
if it.kind in nkPragmaCallKinds and it.len > 1: if it.kind in nkPragmaCallKinds and it.len > 1:
# pass pragma arguments to the macro too: # pass pragma arguments to the macro too:
@ -1199,7 +1202,7 @@ proc setGenericParamsMisc(c: PContext; n: PNode): PNode =
# issue https://github.com/nim-lang/Nim/issues/1713 # issue https://github.com/nim-lang/Nim/issues/1713
result = semGenericParamList(c, orig) result = semGenericParamList(c, orig)
if n.sons[miscPos].kind == nkEmpty: if n.sons[miscPos].kind == nkEmpty:
n.sons[miscPos] = newTree(nkBracket, ast.emptyNode, orig) n.sons[miscPos] = newTree(nkBracket, c.graph.emptyNode, orig)
else: else:
n.sons[miscPos].sons[1] = orig n.sons[miscPos].sons[1] = orig
n.sons[genericParamsPos] = result n.sons[genericParamsPos] = result
@ -1270,7 +1273,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
result = n result = n
s.ast = result s.ast = result
n.sons[namePos].sym = s n.sons[namePos].sym = s
n.sons[genericParamsPos] = emptyNode n.sons[genericParamsPos] = c.graph.emptyNode
# for LL we need to avoid wrong aliasing # for LL we need to avoid wrong aliasing
let params = copyTree n.typ.n let params = copyTree n.typ.n
n.sons[paramsPos] = params n.sons[paramsPos] = params
@ -1397,14 +1400,14 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
localError(c.config, n.info, errGenerated, localError(c.config, n.info, errGenerated,
"'destroy' or 'deepCopy' expected for 'override'") "'destroy' or 'deepCopy' expected for 'override'")
proc cursorInProcAux(n: PNode): bool = proc cursorInProcAux(conf: ConfigRef; n: PNode): bool =
if inCheckpoint(n.info) != cpNone: return true if inCheckpoint(n.info, conf.m.trackPos) != cpNone: return true
for i in 0..<n.safeLen: for i in 0..<n.safeLen:
if cursorInProcAux(n[i]): return true if cursorInProcAux(conf, n[i]): return true
proc cursorInProc(n: PNode): bool = proc cursorInProc(conf: ConfigRef; n: PNode): bool =
if n.info.fileIndex == gTrackPos.fileIndex: if n.info.fileIndex == conf.m.trackPos.fileIndex:
result = cursorInProcAux(n) result = cursorInProcAux(conf, n)
type type
TProcCompilationSteps = enum TProcCompilationSteps = enum
@ -1486,6 +1489,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# before compiling the proc body, set as current the scope # before compiling the proc body, set as current the scope
# where the proc was declared # where the proc was declared
let oldScope = c.currentScope let oldScope = c.currentScope
let oldOptions = c.config.options
#c.currentScope = s.scope #c.currentScope = s.scope
pushOwner(c, s) pushOwner(c, s)
openScope(c) openScope(c)
@ -1543,7 +1547,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# linking names do agree: # linking names do agree:
if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags: if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags:
localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX % localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX %
("'" & proto.name.s & "' from " & $proto.info)) ("'" & proto.name.s & "' from " & c.config$proto.info))
if sfForward notin proto.flags: if sfForward notin proto.flags:
wrongRedefinition(c, n.info, proto.name.s) wrongRedefinition(c, n.info, proto.name.s)
excl(proto.flags, sfForward) excl(proto.flags, sfForward)
@ -1566,6 +1570,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
popOwner(c) popOwner(c)
pushOwner(c, s) pushOwner(c, s)
s.options = c.config.options s.options = c.config.options
c.config.options = oldOptions
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
if s.name.s[0] in {'.', '('}: if s.name.s[0] in {'.', '('}:
if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}: if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}:
@ -1584,7 +1590,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# only used for overload resolution (there is no instantiation of # only used for overload resolution (there is no instantiation of
# the symbol, so we must process the body now) # the symbol, so we must process the body now)
if not usePseudoGenerics and c.config.ideCmd in {ideSug, ideCon} and not if not usePseudoGenerics and c.config.ideCmd in {ideSug, ideCon} and not
cursorInProc(n.sons[bodyPos]): cursorInProc(c.config, n.sons[bodyPos]):
discard "speed up nimsuggest" discard "speed up nimsuggest"
if s.kind == skMethod: semMethodPrototype(c, s, n) if s.kind == skMethod: semMethodPrototype(c, s, n)
else: else:
@ -1604,7 +1610,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s) n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
else: else:
if s.typ.sons[0] != nil and kind != skIterator: if s.typ.sons[0] != nil and kind != skIterator:
addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info)) addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nil, n.info))
openScope(c) openScope(c)
n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos]) n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos])
@ -1613,7 +1619,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if s.kind == skMethod: semMethodPrototype(c, s, n) if s.kind == skMethod: semMethodPrototype(c, s, n)
if sfImportc in s.flags: if sfImportc in s.flags:
# so we just ignore the body after semantic checking for importc: # so we just ignore the body after semantic checking for importc:
n.sons[bodyPos] = ast.emptyNode n.sons[bodyPos] = c.graph.emptyNode
popProcCon(c) popProcCon(c)
else: else:
if s.kind == skMethod: semMethodPrototype(c, s, n) if s.kind == skMethod: semMethodPrototype(c, s, n)
@ -1692,7 +1698,7 @@ proc semMethod(c: PContext, n: PNode): PNode =
let ret = s.typ.sons[0] let ret = s.typ.sons[0]
disp.typ.sons[0] = ret disp.typ.sons[0] = ret
if disp.ast[resultPos].kind == nkSym: if disp.ast[resultPos].kind == nkSym:
if isEmptyType(ret): disp.ast.sons[resultPos] = emptyNode if isEmptyType(ret): disp.ast.sons[resultPos] = c.graph.emptyNode
else: disp.ast[resultPos].sym.typ = ret else: disp.ast[resultPos].sym.typ = ret
proc semConverterDef(c: PContext, n: PNode): PNode = proc semConverterDef(c: PContext, n: PNode): PNode =
@ -1738,9 +1744,9 @@ proc evalInclude(c: PContext, n: PNode): PNode =
var f = checkModuleName(c.config, n.sons[i]) var f = checkModuleName(c.config, n.sons[i])
if f != InvalidFileIDX: if f != InvalidFileIDX:
if containsOrIncl(c.includedFiles, f.int): if containsOrIncl(c.includedFiles, f.int):
localError(c.config, n.info, errRecursiveDependencyX % f.toFilename) localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f))
else: else:
addSon(result, semStmt(c, gIncludeFile(c.graph, c.module, f, c.cache))) addSon(result, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f)))
excl(c.includedFiles, f.int) excl(c.includedFiles, f.int)
proc setLine(n: PNode, info: TLineInfo) = proc setLine(n: PNode, info: TLineInfo) =
@ -1769,9 +1775,13 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
let a = semStmt(c, n.sons[0]) let a = semStmt(c, n.sons[0])
dec c.inStaticContext dec c.inStaticContext
n.sons[0] = a n.sons[0] = a
evalStaticStmt(c.module, c.cache, c.graph, a, c.p.owner) evalStaticStmt(c.module, c.graph, a, c.p.owner)
result = newNodeI(nkDiscardStmt, n.info, 1) when false:
result.sons[0] = emptyNode # for incremental replays, keep the AST as required for replays:
result = n
else:
result = newNodeI(nkDiscardStmt, n.info, 1)
result.sons[0] = c.graph.emptyNode
proc usesResult(n: PNode): bool = proc usesResult(n: PNode): bool =
# nkStmtList(expr) properly propagates the void context, # nkStmtList(expr) properly propagates the void context,
@ -1834,9 +1844,9 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
localError(c.config, result.info, "concept predicate failed") localError(c.config, result.info, "concept predicate failed")
of tyUnknown: continue of tyUnknown: continue
else: discard else: discard
if n.sons[i].typ == enforceVoidContext: #or usesResult(n.sons[i]): if n.sons[i].typ == c.enforceVoidContext: #or usesResult(n.sons[i]):
voidContext = true voidContext = true
n.typ = enforceVoidContext n.typ = c.enforceVoidContext
if i == last and (length == 1 or efWantValue in flags): if i == last and (length == 1 or efWantValue in flags):
n.typ = n.sons[i].typ n.typ = n.sons[i].typ
if not isEmptyType(n.typ): n.kind = nkStmtListExpr if not isEmptyType(n.typ): n.kind = nkStmtListExpr

View file

@ -99,7 +99,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode = proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
for i in 0 ..< n.len: for i in 0 ..< n.len:
toMixin.incl(considerQuotedIdent(c.config, n.sons[i]).id) toMixin.incl(considerQuotedIdent(c, n.sons[i]).id)
result = newNodeI(nkEmpty, n.info) result = newNodeI(nkEmpty, n.info)
proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) = proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) =
@ -166,7 +166,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
result.sons[i] = onlyReplaceParams(c, n.sons[i]) result.sons[i] = onlyReplaceParams(c, n.sons[i])
proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym = proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
result = newSym(kind, considerQuotedIdent(c.c.config, n), c.owner, n.info) result = newSym(kind, considerQuotedIdent(c.c, n), c.owner, n.info)
incl(result.flags, sfGenSym) incl(result.flags, sfGenSym)
incl(result.flags, sfShadowed) incl(result.flags, sfShadowed)
@ -206,7 +206,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
# #
# We need to ensure that both 'a' produce the same gensym'ed symbol. # We need to ensure that both 'a' produce the same gensym'ed symbol.
# So we need only check the *current* scope. # So we need only check the *current* scope.
let s = localSearchInScope(c.c, considerQuotedIdent(c.c.config, ident)) let s = localSearchInScope(c.c, considerQuotedIdent(c.c, ident))
if s != nil and s.owner == c.owner and sfGenSym in s.flags: if s != nil and s.owner == c.owner and sfGenSym in s.flags:
styleCheckUse(n.info, s) styleCheckUse(n.info, s)
replaceIdentBySym(c.c, n, newSymNode(s, n.info)) replaceIdentBySym(c.c, n, newSymNode(s, n.info))
@ -305,7 +305,7 @@ proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode =
proc semTemplBody(c: var TemplCtx, n: PNode): PNode = proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
result = n result = n
semIdeForTemplateOrGenericCheck(n, c.cursorInBody) semIdeForTemplateOrGenericCheck(c.c.config, n, c.cursorInBody)
case n.kind case n.kind
of nkIdent: of nkIdent:
if n.ident.id in c.toInject: return n if n.ident.id in c.toInject: return n
@ -460,14 +460,14 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
x.sons[1] = semTemplBody(c, x.sons[1]) x.sons[1] = semTemplBody(c, x.sons[1])
of nkBracketExpr: of nkBracketExpr:
result = newNodeI(nkCall, n.info) result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent("[]"), n.info) result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
for i in 0 ..< n.len: result.add(n[i]) for i in 0 ..< n.len: result.add(n[i])
let n0 = semTemplBody(c, n.sons[0]) let n0 = semTemplBody(c, n.sons[0])
withBracketExpr c, n0: withBracketExpr c, n0:
result = semTemplBodySons(c, result) result = semTemplBodySons(c, result)
of nkCurlyExpr: of nkCurlyExpr:
result = newNodeI(nkCall, n.info) result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent("{}"), n.info) result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
for i in 0 ..< n.len: result.add(n[i]) for i in 0 ..< n.len: result.add(n[i])
result = semTemplBodySons(c, result) result = semTemplBodySons(c, result)
of nkAsgn, nkFastAsgn: of nkAsgn, nkFastAsgn:
@ -479,7 +479,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
case k case k
of nkBracketExpr: of nkBracketExpr:
result = newNodeI(nkCall, n.info) result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent("[]="), n.info) result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
for i in 0 ..< a.len: result.add(a[i]) for i in 0 ..< a.len: result.add(a[i])
result.add(b) result.add(b)
let a0 = semTemplBody(c, a.sons[0]) let a0 = semTemplBody(c, a.sons[0])
@ -487,7 +487,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
result = semTemplBodySons(c, result) result = semTemplBodySons(c, result)
of nkCurlyExpr: of nkCurlyExpr:
result = newNodeI(nkCall, n.info) result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent("{}="), n.info) result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
for i in 0 ..< a.len: result.add(a[i]) for i in 0 ..< a.len: result.add(a[i])
result.add(b) result.add(b)
result = semTemplBodySons(c, result) result = semTemplBodySons(c, result)
@ -518,7 +518,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode = proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
result = n result = n
semIdeForTemplateOrGenericCheck(n, c.cursorInBody) semIdeForTemplateOrGenericCheck(c.c.config, n, c.cursorInBody)
case n.kind case n.kind
of nkIdent: of nkIdent:
let s = qualifiedLookUp(c.c, n, {}) let s = qualifiedLookUp(c.c, n, {})

View file

@ -66,7 +66,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
base = semTypeNode(c, n.sons[0].sons[0], nil) base = semTypeNode(c, n.sons[0].sons[0], nil)
if base.kind != tyEnum: if base.kind != tyEnum:
localError(c.config, n.sons[0].info, "inheritance only works with an enum") localError(c.config, n.sons[0].info, "inheritance only works with an enum")
counter = lastOrd(base) + 1 counter = lastOrd(c.config, base) + 1
rawAddSon(result, base) rawAddSon(result, base)
let isPure = result.sym != nil and sfPure in result.sym.flags let isPure = result.sym != nil and sfPure in result.sym.flags
var symbols: TStrTable var symbols: TStrTable
@ -133,7 +133,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
if base.kind != tyGenericParam: if base.kind != tyGenericParam:
if not isOrdinalType(base): if not isOrdinalType(base):
localError(c.config, n.info, errOrdinalTypeExpected) localError(c.config, n.info, errOrdinalTypeExpected)
elif lengthOrd(base) > MaxSetElements: elif lengthOrd(c.config, base) > MaxSetElements:
localError(c.config, n.info, errSetTooBig) localError(c.config, n.info, errSetTooBig)
else: else:
localError(c.config, n.info, errXExpectsOneTypeParam % "set") localError(c.config, n.info, errXExpectsOneTypeParam % "set")
@ -157,7 +157,7 @@ proc semVarargs(c: PContext, n: PNode, prev: PType): PType =
var base = semTypeNode(c, n.sons[1], nil) var base = semTypeNode(c, n.sons[1], nil)
addSonSkipIntLit(result, base) addSonSkipIntLit(result, base)
if sonsLen(n) == 3: if sonsLen(n) == 3:
result.n = newIdentNode(considerQuotedIdent(c.config, n.sons[2]), n.sons[2].info) result.n = newIdentNode(considerQuotedIdent(c, n.sons[2]), n.sons[2].info)
else: else:
localError(c.config, n.info, errXExpectsOneTypeParam % "varargs") localError(c.config, n.info, errXExpectsOneTypeParam % "varargs")
addSonSkipIntLit(result, errorType(c)) addSonSkipIntLit(result, errorType(c))
@ -267,7 +267,7 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
n.sons[1].floatVal < 0.0: n.sons[1].floatVal < 0.0:
incl(result.flags, tfNeedsInit) incl(result.flags, tfNeedsInit)
else: else:
if n[1].kind == nkInfix and considerQuotedIdent(c.config, n[1][0]).s == "..<": if n[1].kind == nkInfix and considerQuotedIdent(c, n[1][0]).s == "..<":
localError(c.config, n[0].info, "range types need to be constructed with '..', '..<' is not supported") localError(c.config, n[0].info, "range types need to be constructed with '..', '..<' is not supported")
else: else:
localError(c.config, n.sons[0].info, "expected range") localError(c.config, n.sons[0].info, "expected range")
@ -462,7 +462,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
# for gensym'ed identifiers the identifier may already have been # for gensym'ed identifiers the identifier may already have been
# transformed to a symbol and we need to use that here: # transformed to a symbol and we need to use that here:
result = newSymG(kind, n.sons[1], c) result = newSymG(kind, n.sons[1], c)
var v = considerQuotedIdent(c.config, n.sons[0]) var v = considerQuotedIdent(c, n.sons[0])
if sfExported in allowed and v.id == ord(wStar): if sfExported in allowed and v.id == ord(wStar):
incl(result.flags, sfExported) incl(result.flags, sfExported)
else: else:
@ -553,7 +553,7 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
inc(covered) inc(covered)
else: else:
if r.kind == nkCurly: if r.kind == nkCurly:
r = r.deduplicate r = deduplicate(c.config, r)
# first element is special and will overwrite: branch.sons[i]: # first element is special and will overwrite: branch.sons[i]:
branch.sons[i] = semCaseBranchSetElem(c, t, r[0], covered) branch.sons[i] = semCaseBranchSetElem(c, t, r[0], covered)
@ -584,10 +584,10 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc}) var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc})
if not isOrdinalType(typ): if not isOrdinalType(typ):
localError(c.config, n.info, "selector must be of an ordinal type") localError(c.config, n.info, "selector must be of an ordinal type")
elif firstOrd(typ) != 0: elif firstOrd(c.config, typ) != 0:
localError(c.config, n.info, "low(" & $a.sons[0].sym.name.s & localError(c.config, n.info, "low(" & $a.sons[0].sym.name.s &
") must be 0 for discriminant") ") must be 0 for discriminant")
elif lengthOrd(typ) > 0x00007FFF: elif lengthOrd(c.config, typ) > 0x00007FFF:
localError(c.config, n.info, "len($1) must be less than 32768" % a.sons[0].sym.name.s) localError(c.config, n.info, "len($1) must be less than 32768" % a.sons[0].sym.name.s)
var chckCovered = true var chckCovered = true
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
@ -603,7 +603,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
else: illFormedAst(n, c.config) else: illFormedAst(n, c.config)
delSon(b, sonsLen(b) - 1) delSon(b, sonsLen(b) - 1)
semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype) semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype)
if chckCovered and covered != lengthOrd(a.sons[0].typ): if chckCovered and covered != lengthOrd(c.config, a.sons[0].typ):
localError(c.config, a.info, "not all cases are covered") localError(c.config, a.info, "not all cases are covered")
addSon(father, a) addSon(father, a)
@ -658,7 +658,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
var length = sonsLen(n) var length = sonsLen(n)
var a: PNode var a: PNode
if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info) if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info)
else: a = ast.emptyNode else: a = newNodeI(nkEmpty, n.info)
if n.sons[length-1].kind != nkEmpty: if n.sons[length-1].kind != nkEmpty:
localError(c.config, n.sons[length-1].info, errInitHereNotAllowed) localError(c.config, n.sons[length-1].info, errInitHereNotAllowed)
var typ: PType var typ: PType
@ -770,7 +770,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
semRecordNodeAux(c, n.sons[2], check, pos, result.n, result) semRecordNodeAux(c, n.sons[2], check, pos, result.n, result)
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
# dummy symbol for `pragma`: # dummy symbol for `pragma`:
var s = newSymS(skType, newIdentNode(getIdent("dummy"), n.info), c) var s = newSymS(skType, newIdentNode(getIdent(c.cache, "dummy"), n.info), c)
s.typ = result s.typ = result
pragma(c, s, n.sons[0], typePragmas) pragma(c, s, n.sons[0], typePragmas)
if base == nil and tfInheritable notin result.flags: if base == nil and tfInheritable notin result.flags:
@ -804,8 +804,6 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
else: else:
if sfGenSym notin param.flags: addDecl(c, param) if sfGenSym notin param.flags: addDecl(c, param)
let typedescId = getIdent"typedesc"
template shouldHaveMeta(t) = template shouldHaveMeta(t) =
internalAssert c.config, tfHasMeta in t.flags internalAssert c.config, tfHasMeta in t.flags
# result.lastSon.flags.incl tfHasMeta # result.lastSon.flags.incl tfHasMeta
@ -815,13 +813,13 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
info: TLineInfo, anon = false): PType = info: TLineInfo, anon = false): PType =
if paramType == nil: return # (e.g. proc return type) if paramType == nil: return # (e.g. proc return type)
proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType = proc addImplicitGenericImpl(c: PContext; typeClass: PType, typId: PIdent): PType =
if genericParams == nil: if genericParams == nil:
# This happens with anonymous proc types appearing in signatures # This happens with anonymous proc types appearing in signatures
# XXX: we need to lift these earlier # XXX: we need to lift these earlier
return return
let finalTypId = if typId != nil: typId let finalTypId = if typId != nil: typId
else: getIdent(paramName & ":type") else: getIdent(c.cache, paramName & ":type")
# is this a bindOnce type class already present in the param list? # is this a bindOnce type class already present in the param list?
for i in countup(0, genericParams.len - 1): for i in countup(0, genericParams.len - 1):
if genericParams.sons[i].sym.name.id == finalTypId.id: if genericParams.sons[i].sym.name.id == finalTypId.id:
@ -852,11 +850,11 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
(if lifted != nil: lifted else: typ) (if lifted != nil: lifted else: typ)
template addImplicitGeneric(e): untyped = template addImplicitGeneric(e): untyped =
addImplicitGenericImpl(e, paramTypId) addImplicitGenericImpl(c, e, paramTypId)
case paramType.kind: case paramType.kind:
of tyAnything: of tyAnything:
result = addImplicitGenericImpl(newTypeS(tyGenericParam, c), nil) result = addImplicitGenericImpl(c, newTypeS(tyGenericParam, c), nil)
of tyStatic: of tyStatic:
# proc(a: expr{string}, b: expr{nkLambda}) # proc(a: expr{string}, b: expr{nkLambda})
@ -873,7 +871,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
if tfUnresolved notin paramType.flags: if tfUnresolved notin paramType.flags:
# naked typedescs are not bindOnce types # naked typedescs are not bindOnce types
if paramType.base.kind == tyNone and paramTypId != nil and if paramType.base.kind == tyNone and paramTypId != nil and
paramTypId.id == typedescId.id: paramTypId = nil paramTypId.id == getIdent(c.cache, "typedesc").id:
# XXX Why doesn't this check for tyTypeDesc instead?
paramTypId = nil
result = addImplicitGeneric( result = addImplicitGeneric(
c.newTypeWithSons(tyTypeDesc, @[paramType.base])) c.newTypeWithSons(tyTypeDesc, @[paramType.base]))
@ -1322,7 +1322,7 @@ proc semProcTypeWithScope(c: PContext, n: PNode,
# start with 'ccClosure', but of course pragmas can overwrite this: # start with 'ccClosure', but of course pragmas can overwrite this:
result.callConv = ccClosure result.callConv = ccClosure
# dummy symbol for `pragma`: # dummy symbol for `pragma`:
var s = newSymS(kind, newIdentNode(getIdent("dummy"), n.info), c) var s = newSymS(kind, newIdentNode(getIdent(c.cache, "dummy"), n.info), c)
s.typ = result s.typ = result
if n.sons[1].kind != nkEmpty and n.sons[1].len > 0: if n.sons[1].kind != nkEmpty and n.sons[1].len > 0:
pragma(c, s, n.sons[1], procTypePragmas) pragma(c, s, n.sons[1], procTypePragmas)
@ -1345,7 +1345,7 @@ proc fixupTypeOf(c: PContext, prev: PType, typExpr: PNode) =
proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym = proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym =
if n.kind == nkType: if n.kind == nkType:
result = symFromType(n.typ, n.info) result = symFromType(c, n.typ, n.info)
else: else:
localError(c.config, n.info, errTypeExpected) localError(c.config, n.info, errTypeExpected)
result = errorSym(c, n) result = errorSym(c, n)
@ -1393,7 +1393,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
elif n[0].kind notin nkIdentKinds: elif n[0].kind notin nkIdentKinds:
result = semTypeExpr(c, n, prev) result = semTypeExpr(c, n, prev)
else: else:
let op = considerQuotedIdent(c.config, n.sons[0]) let op = considerQuotedIdent(c, n.sons[0])
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|": if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
checkSonsLen(n, 3, c.config) checkSonsLen(n, 3, c.config)
var var
@ -1585,7 +1585,7 @@ when false:
result = semTypeNodeInner(c, n, prev) result = semTypeNodeInner(c, n, prev)
instAllTypeBoundOp(c, n.info) instAllTypeBoundOp(c, n.info)
proc setMagicType(m: PSym, kind: TTypeKind, size: int) = proc setMagicType(conf: ConfigRef; m: PSym, kind: TTypeKind, size: int) =
# source : https://en.wikipedia.org/wiki/Data_structure_alignment#x86 # source : https://en.wikipedia.org/wiki/Data_structure_alignment#x86
m.typ.kind = kind m.typ.kind = kind
m.typ.size = size m.typ.size = size
@ -1596,10 +1596,10 @@ proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
# FIXME: proper support for clongdouble should be added. # FIXME: proper support for clongdouble should be added.
# long double size can be 8, 10, 12, 16 bytes depending on platform & compiler # long double size can be 8, 10, 12, 16 bytes depending on platform & compiler
if targetCPU == cpuI386 and size == 8: if conf.target.targetCPU == cpuI386 and size == 8:
#on Linux/BSD i386, double are aligned to 4bytes (except with -malign-double) #on Linux/BSD i386, double are aligned to 4bytes (except with -malign-double)
if kind in {tyFloat64, tyFloat} and if kind in {tyFloat64, tyFloat} and
targetOS in {osLinux, osAndroid, osNetbsd, osFreebsd, osOpenbsd, osDragonfly}: conf.target.targetOS in {osLinux, osAndroid, osNetbsd, osFreebsd, osOpenbsd, osDragonfly}:
m.typ.align = 4 m.typ.align = 4
# on i386, all known compiler, 64bits ints are aligned to 4bytes (except with -malign-double) # on i386, all known compiler, 64bits ints are aligned to 4bytes (except with -malign-double)
elif kind in {tyInt, tyUInt, tyInt64, tyUInt64}: elif kind in {tyInt, tyUInt, tyInt64, tyUInt64}:
@ -1609,73 +1609,73 @@ proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
proc processMagicType(c: PContext, m: PSym) = proc processMagicType(c: PContext, m: PSym) =
case m.magic case m.magic
of mInt: setMagicType(m, tyInt, intSize) of mInt: setMagicType(c.config, m, tyInt, c.config.target.intSize)
of mInt8: setMagicType(m, tyInt8, 1) of mInt8: setMagicType(c.config, m, tyInt8, 1)
of mInt16: setMagicType(m, tyInt16, 2) of mInt16: setMagicType(c.config, m, tyInt16, 2)
of mInt32: setMagicType(m, tyInt32, 4) of mInt32: setMagicType(c.config, m, tyInt32, 4)
of mInt64: setMagicType(m, tyInt64, 8) of mInt64: setMagicType(c.config, m, tyInt64, 8)
of mUInt: setMagicType(m, tyUInt, intSize) of mUInt: setMagicType(c.config, m, tyUInt, c.config.target.intSize)
of mUInt8: setMagicType(m, tyUInt8, 1) of mUInt8: setMagicType(c.config, m, tyUInt8, 1)
of mUInt16: setMagicType(m, tyUInt16, 2) of mUInt16: setMagicType(c.config, m, tyUInt16, 2)
of mUInt32: setMagicType(m, tyUInt32, 4) of mUInt32: setMagicType(c.config, m, tyUInt32, 4)
of mUInt64: setMagicType(m, tyUInt64, 8) of mUInt64: setMagicType(c.config, m, tyUInt64, 8)
of mFloat: setMagicType(m, tyFloat, floatSize) of mFloat: setMagicType(c.config, m, tyFloat, c.config.target.floatSize)
of mFloat32: setMagicType(m, tyFloat32, 4) of mFloat32: setMagicType(c.config, m, tyFloat32, 4)
of mFloat64: setMagicType(m, tyFloat64, 8) of mFloat64: setMagicType(c.config, m, tyFloat64, 8)
of mFloat128: setMagicType(m, tyFloat128, 16) of mFloat128: setMagicType(c.config, m, tyFloat128, 16)
of mBool: setMagicType(m, tyBool, 1) of mBool: setMagicType(c.config, m, tyBool, 1)
of mChar: setMagicType(m, tyChar, 1) of mChar: setMagicType(c.config, m, tyChar, 1)
of mString: of mString:
setMagicType(m, tyString, ptrSize) setMagicType(c.config, m, tyString, c.config.target.ptrSize)
rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
of mCstring: of mCstring:
setMagicType(m, tyCString, ptrSize) setMagicType(c.config, m, tyCString, c.config.target.ptrSize)
rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
of mPointer: setMagicType(m, tyPointer, ptrSize) of mPointer: setMagicType(c.config, m, tyPointer, c.config.target.ptrSize)
of mEmptySet: of mEmptySet:
setMagicType(m, tySet, 1) setMagicType(c.config, m, tySet, 1)
rawAddSon(m.typ, newTypeS(tyEmpty, c)) rawAddSon(m.typ, newTypeS(tyEmpty, c))
of mIntSetBaseType: setMagicType(m, tyRange, intSize) of mIntSetBaseType: setMagicType(c.config, m, tyRange, c.config.target.intSize)
of mNil: setMagicType(m, tyNil, ptrSize) of mNil: setMagicType(c.config, m, tyNil, c.config.target.ptrSize)
of mExpr: of mExpr:
if m.name.s == "auto": if m.name.s == "auto":
setMagicType(m, tyAnything, 0) setMagicType(c.config, m, tyAnything, 0)
else: else:
setMagicType(m, tyExpr, 0) setMagicType(c.config, m, tyExpr, 0)
if m.name.s == "expr": m.typ.flags.incl tfOldSchoolExprStmt if m.name.s == "expr": m.typ.flags.incl tfOldSchoolExprStmt
of mStmt: of mStmt:
setMagicType(m, tyStmt, 0) setMagicType(c.config, m, tyStmt, 0)
if m.name.s == "stmt": m.typ.flags.incl tfOldSchoolExprStmt if m.name.s == "stmt": m.typ.flags.incl tfOldSchoolExprStmt
of mTypeDesc: of mTypeDesc:
setMagicType(m, tyTypeDesc, 0) setMagicType(c.config, m, tyTypeDesc, 0)
rawAddSon(m.typ, newTypeS(tyNone, c)) rawAddSon(m.typ, newTypeS(tyNone, c))
of mVoidType: of mVoidType:
setMagicType(m, tyVoid, 0) setMagicType(c.config, m, tyVoid, 0)
of mArray: of mArray:
setMagicType(m, tyArray, 0) setMagicType(c.config, m, tyArray, 0)
of mOpenArray: of mOpenArray:
setMagicType(m, tyOpenArray, 0) setMagicType(c.config, m, tyOpenArray, 0)
of mVarargs: of mVarargs:
setMagicType(m, tyVarargs, 0) setMagicType(c.config, m, tyVarargs, 0)
of mRange: of mRange:
setMagicType(m, tyRange, 0) setMagicType(c.config, m, tyRange, 0)
rawAddSon(m.typ, newTypeS(tyNone, c)) rawAddSon(m.typ, newTypeS(tyNone, c))
of mSet: of mSet:
setMagicType(m, tySet, 0) setMagicType(c.config, m, tySet, 0)
of mSeq: of mSeq:
setMagicType(m, tySequence, 0) setMagicType(c.config, m, tySequence, 0)
of mOpt: of mOpt:
setMagicType(m, tyOpt, 0) setMagicType(c.config, m, tyOpt, 0)
of mOrdinal: of mOrdinal:
setMagicType(m, tyOrdinal, 0) setMagicType(c.config, m, tyOrdinal, 0)
rawAddSon(m.typ, newTypeS(tyNone, c)) rawAddSon(m.typ, newTypeS(tyNone, c))
of mPNimrodNode: of mPNimrodNode:
incl m.typ.flags, tfTriggersCompileTime incl m.typ.flags, tfTriggersCompileTime
of mException: discard of mException: discard
of mBuiltinType: of mBuiltinType:
case m.name.s case m.name.s
of "lent": setMagicType(m, tyLent, ptrSize) of "lent": setMagicType(c.config, m, tyLent, c.config.target.ptrSize)
of "sink": setMagicType(m, tySink, 0) of "sink": setMagicType(c.config, m, tySink, 0)
else: localError(c.config, m.info, errTypeExpected) else: localError(c.config, m.info, errTypeExpected)
else: localError(c.config, m.info, errTypeExpected) else: localError(c.config, m.info, errTypeExpected)

View file

@ -9,7 +9,8 @@
# This module does the instantiation of generic types. # This module does the instantiation of generic types.
import ast, astalgo, msgs, types, magicsys, semdata, renderer, options import ast, astalgo, msgs, types, magicsys, semdata, renderer, options,
lineinfos
const const
tfInstClearedFlags = {tfHasMeta, tfUnresolved} tfInstClearedFlags = {tfHasMeta, tfUnresolved}
@ -27,7 +28,7 @@ proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
localError(conf, info, "invalid pragma: acyclic") localError(conf, info, "invalid pragma: acyclic")
elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}: elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
localError(conf, info, "type 'var var' is not allowed") localError(conf, info, "type 'var var' is not allowed")
elif computeSize(t) == szIllegalRecursion: elif computeSize(conf, t) == szIllegalRecursion:
localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'") localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'")
when false: when false:
if t.kind == tyObject and t.sons[0] != nil: if t.kind == tyObject and t.sons[0] != nil:
@ -568,35 +569,35 @@ proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
var typeMap = initLayeredTypeMap(pt) var typeMap = initLayeredTypeMap(pt)
var cl = initTypeVars(p, addr(typeMap), n.info, owner) var cl = initTypeVars(p, addr(typeMap), n.info, owner)
cl.allowMetaTypes = allowMetaTypes cl.allowMetaTypes = allowMetaTypes
pushInfoContext(n.info) pushInfoContext(p.config, n.info)
result = replaceTypeVarsN(cl, n) result = replaceTypeVarsN(cl, n)
popInfoContext() popInfoContext(p.config)
proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode; proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode;
original, new: PSym): PNode = original, new: PSym): PNode =
var typeMap = initLayeredTypeMap(pt) var typeMap = initLayeredTypeMap(pt)
var cl = initTypeVars(p, addr(typeMap), n.info, original) var cl = initTypeVars(p, addr(typeMap), n.info, original)
idTablePut(cl.symMap, original, new) idTablePut(cl.symMap, original, new)
pushInfoContext(n.info) pushInfoContext(p.config, n.info)
result = replaceTypeVarsN(cl, n) result = replaceTypeVarsN(cl, n)
popInfoContext() popInfoContext(p.config)
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo, proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
t: PType): PType = t: PType): PType =
var typeMap = initLayeredTypeMap(pt) var typeMap = initLayeredTypeMap(pt)
var cl = initTypeVars(p, addr(typeMap), info, nil) var cl = initTypeVars(p, addr(typeMap), info, nil)
pushInfoContext(info) pushInfoContext(p.config, info)
result = replaceTypeVarsT(cl, t) result = replaceTypeVarsT(cl, t)
popInfoContext() popInfoContext(p.config)
proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo, proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo,
t: PType): PType = t: PType): PType =
var typeMap = initLayeredTypeMap(pt) var typeMap = initLayeredTypeMap(pt)
var cl = initTypeVars(p, addr(typeMap), info, nil) var cl = initTypeVars(p, addr(typeMap), info, nil)
cl.allowMetaTypes = true cl.allowMetaTypes = true
pushInfoContext(info) pushInfoContext(p.config, info)
result = replaceTypeVarsT(cl, t) result = replaceTypeVarsT(cl, t)
popInfoContext() popInfoContext(p.config)
template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode, template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
t: PType): untyped = t: PType): untyped =

View file

@ -11,7 +11,7 @@
import import
times, commands, options, msgs, nimconf, times, commands, options, msgs, nimconf,
extccomp, strutils, os, platform, parseopt, idents, configuration extccomp, strutils, os, platform, parseopt, idents, lineinfos
when useCaas: when useCaas:
import net import net
@ -26,25 +26,6 @@ var
# in caas mode, the list of defines and options will be given at start-up? # in caas mode, the list of defines and options will be given at start-up?
# it's enough to check that the previous compilation command is the same? # it's enough to check that the previous compilation command is the same?
proc processCmdLine*(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
var p = parseopt.initOptParser(cmd)
var argsCount = 0
while true:
parseopt.next(p)
case p.kind
of cmdEnd: break
of cmdLongoption, cmdShortOption:
if p.key == " ":
p.key = "-"
if processArgument(pass, p, argsCount, config): break
else:
processSwitch(pass, p, config)
of cmdArgument:
if processArgument(pass, p, argsCount, config): break
if pass == passCmd2:
if optRun notin config.globalOptions and config.arguments.len > 0 and config.command.normalize != "run":
rawMessage(config, errGenerated, errArgsNeedRunOption)
proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; config: ConfigRef) = proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; config: ConfigRef) =
template execute(cmd) = template execute(cmd) =
curCaasCmd = cmd curCaasCmd = cmd
@ -71,7 +52,7 @@ proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; conf
var inp = "".TaintedString var inp = "".TaintedString
server.listen() server.listen()
var stdoutSocket = newSocket() var stdoutSocket = newSocket()
msgs.writelnHook = proc (line: string) = config.writelnHook = proc (line: string) =
stdoutSocket.send(line & "\c\L") stdoutSocket.send(line & "\c\L")
while true: while true:

View file

@ -12,7 +12,7 @@
import ast, md5, tables, ropes import ast, md5, tables, ropes
from hashes import Hash from hashes import Hash
from astalgo import debug from astalgo import debug
from types import typeToString, preferDesc import types
from strutils import startsWith, contains from strutils import startsWith, contains
when false: when false:
@ -148,19 +148,23 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
of tyGenericInvocation: of tyGenericInvocation:
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
c.hashType t.sons[i], flags c.hashType t.sons[i], flags
return
of tyDistinct: of tyDistinct:
if CoType in flags: if CoType in flags:
c.hashType t.lastSon, flags c.hashType t.lastSon, flags
else: else:
c.hashSym(t.sym) c.hashSym(t.sym)
return of tyGenericInst:
of tyAlias, tySink, tyGenericInst, tyUserTypeClasses: if sfInfixCall in t.base.sym.flags:
# This is an imported C++ generic type.
# We cannot trust the `lastSon` to hold a properly populated and unique
# value for each instantiation, so we hash the generic parameters here:
let normalizedType = t.skipGenericAlias
for i in 0 .. normalizedType.len - 2:
c.hashType t.sons[i], flags
else:
c.hashType t.lastSon, flags
of tyAlias, tySink, tyUserTypeClasses:
c.hashType t.lastSon, flags c.hashType t.lastSon, flags
return
else:
discard
case t.kind
of tyBool, tyChar, tyInt..tyUInt64: of tyBool, tyChar, tyInt..tyUInt64:
# no canonicalization for integral types, so that e.g. ``pid_t`` is # no canonicalization for integral types, so that e.g. ``pid_t`` is
# produced instead of ``NI``: # produced instead of ``NI``:
@ -168,11 +172,12 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}: if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}:
c.hashSym(t.sym) c.hashSym(t.sym)
of tyObject, tyEnum: of tyObject, tyEnum:
c &= char(t.kind)
if t.typeInst != nil: if t.typeInst != nil:
assert t.typeInst.kind == tyGenericInst assert t.typeInst.kind == tyGenericInst
for i in countup(1, sonsLen(t.typeInst) - 2): for i in countup(0, sonsLen(t.typeInst) - 2):
c.hashType t.typeInst.sons[i], flags c.hashType t.typeInst.sons[i], flags
return
c &= char(t.kind)
# Every cyclic type in Nim need to be constructed via some 't.sym', so this # Every cyclic type in Nim need to be constructed via some 't.sym', so this
# is actually safe without an infinite recursion check: # is actually safe without an infinite recursion check:
if t.sym != nil: if t.sym != nil:

Some files were not shown because too many files have changed in this diff Show more