merge devel
This commit is contained in:
commit
37aa488f99
136 changed files with 4276 additions and 5649 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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
233
compiler/btrees.nim
Normal 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()
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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: ""
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -70,3 +70,4 @@ proc initDefines*(symbols: StringTableRef) =
|
||||||
defineSymbol("nimNoNil")
|
defineSymbol("nimNoNil")
|
||||||
defineSymbol("nimNoZeroTerminator")
|
defineSymbol("nimNoZeroTerminator")
|
||||||
defineSymbol("nimNotNil")
|
defineSymbol("nimNotNil")
|
||||||
|
defineSymbol("nimVmExportFixed")
|
||||||
|
|
|
||||||
|
|
@ -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",
|
|
||||||
,
|
|
||||||
]#
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
|
||||||
|
|
@ -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
196
compiler/incremental.nim
Normal 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
|
||||||
|
|
@ -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)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)])
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
267
compiler/lineinfos.nim
Normal 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}
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
||||||
79
compiler/macrocacheimpl.nim
Normal file
79
compiler/macrocacheimpl.nim
Normal 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)
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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())
|
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
])
|
])
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
|
||||||
|
|
@ -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."
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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!
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
1244
compiler/rodread.nim
1244
compiler/rodread.nim
File diff suppressed because it is too large
Load diff
|
|
@ -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)
|
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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) =
|
||||||
|
|
|
||||||
|
|
@ -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 = @[]
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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, {})
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue