Merge branch 'devel' into Fixes-7845

This commit is contained in:
cooldome
2018-06-26 23:33:34 +01:00
208 changed files with 8873 additions and 6312 deletions

View File

@@ -31,7 +31,6 @@ before_script:
- cd csources
- sh build.sh
- cd ..
- sed -i -e 's,cc = gcc,cc = clang,' config/nim.cfg
- export PATH=$(pwd)/bin${PATH:+:$PATH}
script:
- nim c koch
@@ -46,6 +45,8 @@ script:
- nimble install niminst
- nim c --taintMode:on -d:nimCoroutines tests/testament/tester
- tests/testament/tester --pedantic all -d:nimCoroutines
- nim c -o:bin/nimpretty nimpretty/nimpretty.nim
- nim c -r nimpretty/tester.nim
- ./koch web
- ./koch csource
- ./koch nimsuggest

View File

@@ -47,6 +47,8 @@ build_script:
- koch boot -d:release
- koch nimble
- nim e tests/test_nimscript.nims
- nim c -o:bin/nimpretty.exe nimpretty/nimpretty.nim
- nim c -r nimpretty/tester.nim
- nimble install zip -y
- nimble install opengl
- nimble install sdl1

View File

@@ -48,6 +48,10 @@
- For string inputs, ``strutils.isUpperAscii`` and ``strutils.isLowerAscii`` now
require a second mandatory parameter ``skipNonAlpha``.
- The procs ``parseHexInt`` and ``parseOctInt`` now fail on empty strings
and strings containing only valid prefixes, e.g. "0x" for hex integers.
#### Breaking changes in the compiler
- The undocumented ``#? braces`` parsing mode was removed.
@@ -72,6 +76,10 @@
- Added the procs ``math.floorMod`` and ``math.floorDiv`` for floor based integer division.
- Added the procs ``rationals.`div```, ``rationals.`mod```, ``rationals.floorDiv`` and ``rationals.floorMod`` for rationals.
- Added the proc ``math.prod`` for product of elements in openArray.
- Added the proc ``parseBinInt`` to parse a binary integer from a string, which returns the value.
- ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt``
- Added the proc ``flush`` for memory mapped files.
- Added the ``MemMapFileStream``.
### Library changes
@@ -91,10 +99,17 @@
- The `terminal` module now exports additional procs for generating ANSI color
codes as strings.
- 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.
- 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 ``pegs`` module now exports getters for the fields of its ``Peg`` and ``NonTerminal``
object types. ``Peg``s with child nodes now have the standard ``items`` and ``pairs``
iterators.
### Language additions
@@ -104,6 +119,13 @@
- In order to make ``for`` loops and iterators more flexible to use Nim now
supports so called "for-loop macros". See
the `manual <manual.html#macros-for-loop-macros>`_ for more details.
- the `typedesc` special type has been renamed to just `type`.
- `static` and `type` are now also modifiers similar to `ref` and `ptr`.
They denote the special types `static[T]` and `type[T]`.
- Forcing compile-time evaluation with `static` now supports specifying
the desired target type (as a concrete type or as a type class)
- The `type` operator now supports checking that the supplied expression
matches an expected type constraint.
### Language changes
@@ -131,6 +153,8 @@
- Nim now supports `except` clause in the export statement.
- Range float types, example `range[0.0 .. Inf]`. More details in language manual.
### Tool changes
- ``jsondoc2`` has been renamed ``jsondoc``, similar to how ``doc2`` was renamed

View File

@@ -10,7 +10,7 @@
# abstract syntax tree + symbol table
import
msgs, hashes, nversion, options, strutils, std / sha1, ropes, idents,
lineinfos, hashes, nversion, options, strutils, std / sha1, ropes, idents,
intsets, idgen
type
@@ -293,6 +293,10 @@ const
# the compiler will avoid printing such names
# in user messages.
sfHoisted* = sfForward
# an expression was hoised to an anonymous variable.
# the flag is applied to the var/let symbol
sfNoForward* = sfRegister
# forward declarations are not required (per module)
sfReorder* = sfForward
@@ -454,6 +458,9 @@ type
nfPreventCg # this node should be ignored by the codegen
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
nfFromTemplate # a top-level node returned from a template
nfDefaultParam # an automatically inserter default parameter
nfDefaultRefsParam # a default param value references another parameter
# the flag is applied to proc default values and to calls
TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: beyond that)
@@ -571,8 +578,8 @@ type
TMagic* = enum # symbols that require compiler magic:
mNone,
mDefined, mDefinedInScope, mCompiles, mArrGet, mArrPut, mAsgn,
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mPlugin,
mEcho, mShallowCopy, mSlurp, mStaticExec,
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mType, mTypeOf,
mRoof, mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mStatic,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
mUnaryLt, mInc, mDec, mOrd,
mNew, mNewFinalize, mNewSeq, mNewSeqOfCap,
@@ -634,14 +641,18 @@ type
mNaN, mInf, mNegInf,
mCompileOption, mCompileOptionArg,
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,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent,
mNBindSym, mLocals, mNCallSite,
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl,
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym,
mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo, mNGenSym,
mInstantiationInfo, mGetTypeInfo,
mNimvm, mIntDefine, mStrDefine, mRunnableExamples,
mException, mBuiltinType
@@ -967,7 +978,7 @@ const
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
nfDotSetter, nfDotField,
nfIsRef, nfPreventCg, nfLL,
nfFromTemplate}
nfFromTemplate, nfDefaultRefsParam}
namePos* = 0
patternPos* = 1 # empty except for term rewriting macros
genericParamsPos* = 2
@@ -998,8 +1009,8 @@ const
skMethod, skConverter}
var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
var
gMainPackageId*: int
#var
# gMainPackageId*: int
proc isCallExpr*(n: PNode): bool =
result = n.kind in nkCallKinds
@@ -1058,22 +1069,6 @@ proc newTree*(kind: TNodeKind; children: varargs[PNode]): PNode =
result.info = children[0].info
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 =
if t.sons.len > 1: t.lastSon else: nil
@@ -1095,9 +1090,6 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
# writeStacktrace()
# 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 =
return t.kind in tyMetaTypes or
(t.kind == tyStatic and t.n == nil) or
@@ -1224,18 +1216,35 @@ proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
result.info = info
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) =
assert son != nil
if isNil(father.sons): father.sons = @[]
add(father.sons, son)
var emptyParams = newNode(nkFormalParams)
emptyParams.addSon(emptyNode)
proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
params = emptyParams,
params,
name, pattern, genericParams,
pragmas, exceptions = ast.emptyNode): PNode =
pragmas, exceptions: PNode): PNode =
result = newNodeI(kind, info)
result.sons = @[name, pattern, genericParams, params,
pragmas, exceptions, body]
@@ -1702,7 +1711,7 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
result = true
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 =
if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil:
@@ -1727,3 +1736,5 @@ template incompleteType*(t: PType): bool =
template typeCompleted*(s: PSym) =
incl s.flags, sfNoForward
template getBody*(s: PSym): PNode = s.ast[bodyPos]

View File

@@ -12,81 +12,58 @@
# the data structures here are used in various places of the compiler.
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 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
# YAML code generator and it is invaluable for debugging purposes.
# If maxRecDepht <> -1 then it won't print the whole graph.
proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope
proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope
proc lineInfoToStr*(info: TLineInfo): Rope
proc typeToYaml*(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope
proc symToYaml*(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope
proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): Rope
# ----------------------- node sets: ---------------------------------------
proc objectSetContains*(t: TObjectSet, obj: RootRef): bool
# returns true whether n is in t
proc objectSetIncl*(t: var TObjectSet, obj: RootRef)
# include an element n in the table t
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool
# more are not needed ...
when declared(echo):
# 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; conf: ConfigRef = nil) {.deprecated.}
proc debug*(n: PType; conf: ConfigRef = nil) {.deprecated.}
proc debug*(n: PNode; conf: ConfigRef = nil) {.deprecated.}
# ----------------------- 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.} =
when compiles(c.module):
c.module.fileIdx.int32 == c.config.projectMainIdx
elif compiles(c.c.module):
c.c.module.fileIdx.int32 == c.c.config.projectMainIdx
elif compiles(m.c.module):
m.c.module.fileIdx.int32 == m.c.config.projectMainIdx
elif compiles(cl.c.module):
cl.c.module.fileIdx.int32 == cl.c.config.projectMainIdx
elif compiles(p):
when compiles(p.lex):
p.lex.fileIdx.int32 == p.lex.config.projectMainIdx
template debug*(x: PSym|PType|PNode) {.deprecated.} =
when compiles(c.config):
debug(c.config, x)
elif compiles(c.graph.config):
debug(c.graph.config, x)
else:
p.module.module.fileIdx.int32 == p.config.projectMainIdx
elif compiles(m.module.fileIdx):
m.module.fileIdx.int32 == m.config.projectMainIdx
elif compiles(L.fileIdx):
L.fileIdx.int32 == L.config.projectMainIdx
else:
error()
error()
template debug*(x: auto) {.deprecated.} =
echo x
template mdbg*: bool {.deprecated.} =
when compiles(c.graph):
c.module.fileIdx == c.graph.config.projectMainIdx
elif compiles(c.module):
c.module.fileIdx == c.config.projectMainIdx
elif compiles(c.c.module):
c.c.module.fileIdx == c.c.config.projectMainIdx
elif compiles(m.c.module):
m.c.module.fileIdx == m.c.config.projectMainIdx
elif compiles(cl.c.module):
cl.c.module.fileIdx == cl.c.config.projectMainIdx
elif compiles(p):
when compiles(p.lex):
p.lex.fileIdx == p.lex.config.projectMainIdx
else:
p.module.module.fileIdx == p.config.projectMainIdx
elif compiles(m.module.fileIdx):
m.module.fileIdx == m.config.projectMainIdx
elif compiles(L.fileIdx):
L.fileIdx == L.config.projectMainIdx
else:
error()
# --------------------------- ident tables ----------------------------------
proc idTableGet*(t: TIdTable, key: PIdObj): RootRef
@@ -102,7 +79,6 @@ proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym
proc lookupInRecord*(n: PNode, field: PIdent): PSym
proc getModule*(s: PSym): PSym
proc mustRehash*(length, counter: int): bool
proc nextTry*(h, maxHash: Hash): Hash {.inline.}
@@ -193,7 +169,7 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
if n.sym.name.id == field.id: result = n.sym
else: return nil
proc getModule(s: PSym): PSym =
proc getModule*(s: PSym): PSym =
result = s
assert((result.kind == skModule) or (result.owner != result))
while result != nil and result.kind != skModule: result = result.owner
@@ -250,16 +226,16 @@ proc flagsToStr[T](flags: set[T]): Rope =
add(result, makeYamlString($x))
result = "[" & result & "]"
proc lineInfoToStr(info: TLineInfo): Rope =
result = "[$1, $2, $3]" % [makeYamlString(toFilename(info)),
proc lineInfoToStr(conf: ConfigRef; info: TLineInfo): Rope =
result = "[$1, $2, $3]" % [makeYamlString(toFilename(conf, info)),
rope(toLinenumber(info)),
rope(toColumn(info))]
proc treeToYamlAux(n: PNode, marker: var IntSet,
proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet,
indent, maxRecDepth: int): Rope
proc symToYamlAux(n: PSym, marker: var IntSet,
proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet,
indent, maxRecDepth: int): Rope
proc typeToYamlAux(n: PType, marker: var IntSet,
proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet,
indent, maxRecDepth: int): Rope
proc ropeConstr(indent: int, c: openArray[Rope]): Rope =
@@ -273,7 +249,7 @@ proc ropeConstr(indent: int, c: openArray[Rope]): Rope =
inc(i, 2)
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 =
if n == nil:
result = rope("null")
@@ -281,20 +257,20 @@ proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
result = "\"$1 @$2\"" % [rope(n.name.s), rope(
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
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"),
makeYamlString($n.kind),
rope("name"), makeYamlString(n.name.s),
rope("typ"), typeToYamlAux(n.typ, marker,
rope("typ"), typeToYamlAux(conf, n.typ, marker,
indent + 2, maxRecDepth - 1),
rope("info"), lineInfoToStr(n.info),
rope("info"), lineInfoToStr(conf, n.info),
rope("flags"), flagsToStr(n.flags),
rope("magic"), makeYamlString($n.magic),
rope("ast"), ast, rope("options"),
flagsToStr(n.options), rope("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 =
if n == nil:
result = rope("null")
@@ -306,15 +282,15 @@ proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
result = rope("[")
for i in countup(0, sonsLen(n) - 1):
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)])
addf(result, "$N$1]", [rspaces(indent + 2)])
else:
result = rope("null")
result = ropeConstr(indent, [rope("kind"),
makeYamlString($n.kind),
rope("sym"), symToYamlAux(n.sym, marker,
indent + 2, maxRecDepth - 1), rope("n"), treeToYamlAux(n.n, marker,
rope("sym"), symToYamlAux(conf, n.sym, marker,
indent + 2, maxRecDepth - 1), rope("n"), treeToYamlAux(conf, n.n, marker,
indent + 2, maxRecDepth - 1), rope("flags"), flagsToStr(n.flags),
rope("callconv"),
makeYamlString(CallingConvToStr[n.callConv]),
@@ -322,7 +298,7 @@ proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
rope("align"), rope(n.align),
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 =
if n == nil:
result = rope("null")
@@ -330,7 +306,7 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
var istr = rspaces(indent + 2)
result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
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
of nkCharLit..nkInt64Lit:
addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
@@ -344,7 +320,7 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym:
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:
if n.ident != nil:
addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
@@ -355,27 +331,27 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
addf(result, ",$N$1\"sons\": [", [istr])
for i in countup(0, sonsLen(n) - 1):
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)])
addf(result, "$N$1]", [istr])
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)])
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()
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()
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()
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 debugType(n: PType, maxRecDepth=100): Rope =
proc debugTree*(conf: ConfigRef; n: PNode, indent: int, maxRecDepth: int; renderType=false): Rope
proc debugType(conf: ConfigRef; n: PType, maxRecDepth=100): Rope =
if n == nil:
result = rope("null")
else:
@@ -385,7 +361,7 @@ proc debugType(n: PType, maxRecDepth=100): Rope =
add(result, n.sym.name.s)
if n.kind in IntegralTypes and n.n != nil:
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:
add(result, "(")
for i in countup(0, sonsLen(n) - 1):
@@ -393,13 +369,13 @@ proc debugType(n: PType, maxRecDepth=100): Rope =
if n.sons[i] == nil:
add(result, "null")
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:
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, ")")
proc debugTree(n: PNode, indent: int, maxRecDepth: int;
proc debugTree(conf: ConfigRef; n: PNode, indent: int, maxRecDepth: int;
renderType=false): Rope =
if n == nil:
result = rope("null")
@@ -409,7 +385,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
[istr, makeYamlString($n.kind)]
when defined(useNodeIds):
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:
addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)])
case n.kind
@@ -429,7 +405,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
# [istr, symToYaml(n.sym, indent, maxRecDepth),
# rope(n.sym.id)])
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:
if n.ident != nil:
addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
@@ -440,27 +416,28 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
addf(result, ",$N$1\"sons\": [", [istr])
for i in countup(0, sonsLen(n) - 1):
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)])
addf(result, "$N$1]", [istr])
addf(result, "$N$1}", [rspaces(indent)])
proc debug(n: PSym) =
if n == nil:
echo("null")
elif n.kind == skUnknown:
echo("skUnknown")
else:
#writeLine(stdout, $symToYaml(n, 0, 1))
echo("$1_$2: $3, $4, $5, $6" % [
n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags),
$lineInfoToStr(n.info), $n.kind])
when declared(echo):
proc debug(n: PSym; conf: ConfigRef) =
if n == nil:
echo("null")
elif n.kind == skUnknown:
echo("skUnknown")
else:
#writeLine(stdout, $symToYaml(n, 0, 1))
echo("$1_$2: $3, $4, $5, $6" % [
n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags),
$lineInfoToStr(conf, n.info), $n.kind])
proc debug(n: PType) =
echo($debugType(n))
proc debug(n: PType; conf: ConfigRef) =
echo($debugType(conf, n))
proc debug(n: PNode) =
echo($debugTree(n, 0, 100))
proc debug(n: PNode; conf: ConfigRef) =
echo($debugTree(conf, n, 0, 100))
proc nextTry(h, maxHash: Hash): Hash =
result = ((5 * h) + 1) and maxHash
@@ -468,7 +445,7 @@ proc nextTry(h, maxHash: Hash): Hash =
# generates each int in range(maxHash) exactly once (see any text on
# 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
var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
while t.data[h] != nil:
@@ -492,12 +469,12 @@ proc objectSetEnlarge(t: var TObjectSet) =
if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
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)
objectSetRawInsert(t.data, obj)
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:
var h: Hash = hashNode(obj) and high(t.data)
while true:
@@ -515,7 +492,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
inc(t.counter)
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
while t.data[h] != nil:
if (t.data[h] == n):
@@ -571,7 +548,7 @@ proc strTableEnlarge(t: var TStrTable) =
if t.data[i] != nil: strTableRawInsert(n, t.data[i])
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)
strTableRawInsert(t.data, n)
inc(t.counter)
@@ -607,7 +584,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym; onConflictKeepOld=false): bool {.d
inc(t.counter)
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)
while true:
result = t.data[h]
@@ -615,13 +592,13 @@ proc strTableGet(t: TStrTable, name: PIdent): PSym =
if result.name.id == name.id: break
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 start = h
result = tab.data[h]
@@ -634,6 +611,12 @@ proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
result = tab.data[h]
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,
excluding: IntSet): PSym =
var h: Hash = ti.h and high(tab.data)
@@ -657,20 +640,33 @@ proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
if tab.counter == 0: result = nil
else: result = nextIdentExcluding(ti, tab, excluding)
proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym =
ti.h = 0 # we start by zero ...
if tab.counter == 0:
result = nil # FIX 1: removed endless loop
else:
result = nextIter(ti, tab)
type
TTabIter* = object
h: Hash
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
while (ti.h <= high(tab.data)):
result = tab.data[ti.h]
inc(ti.h) # ... and increment by one always
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 =
var it: TTabIter
var s = initTabIter(it, tab)

233
compiler/btrees.nim Normal file
View File

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

View File

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

View File

@@ -59,7 +59,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
else:
result = rope("NIM_NIL")
of nkStrLit..nkTripleStrLit:
case skipTypes(ty, abstractVarRange).kind
case skipTypes(ty, abstractVarRange + {tyStatic}).kind
of tyNil:
result = genNilStringLiteral(p.module, n.info)
of tyString:
@@ -114,8 +114,8 @@ proc genRawSetData(cs: TBitSet, size: int): Rope =
proc genSetNode(p: BProc, n: PNode): Rope =
var cs: TBitSet
var size = int(getSize(n.typ))
toBitSet(n, cs)
var size = int(getSize(p.config, n.typ))
toBitSet(p.config, n, cs)
if size > 8:
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
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)])
if canFormAcycle(dest.t):
linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n",
addrLoc(dest), rdLoc(src))
addrLoc(p.config, dest), rdLoc(src))
else:
linefmt(p, cpsStmts, "#asgnRefNoCycle((void**) $1, $2);$n",
addrLoc(dest), rdLoc(src))
addrLoc(p.config, dest), rdLoc(src))
else:
linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n",
addrLoc(dest), rdLoc(src))
addrLoc(p.config, dest), rdLoc(src))
proc asgnComplexity(n: PNode): int =
if n != nil:
@@ -260,13 +260,13 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
useStringh(p.module)
linefmt(p, cpsStmts,
"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:
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:
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) =
# 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)
else:
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))
of tyString:
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)
else:
linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
addrLoc(dest), rdLoc(src))
addrLoc(p.config, dest), rdLoc(src))
of tyProc:
if needsComplexAssignment(dest.t):
# optimize closure assignment:
@@ -346,7 +346,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if needsComplexAssignment(dest.t):
linefmt(p, cpsStmts, # XXX: is this correct for arrays?
"#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))
else:
useStringh(p.module)
@@ -356,10 +356,10 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
"$1 = $2;$n",
rdLoc(dest), rdLoc(src))
of tySet:
if mapType(ty) == ctArray:
if mapType(p.config, ty) == ctArray:
useStringh(p.module)
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:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString,
@@ -371,8 +371,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
#writeStackTrace()
#echo p.currLineInfo, " requesting"
linefmt(p, cpsStmts, "#memTrackerWrite((void*)$1, $2, $3, $4);$n",
addrLoc(dest), rope getSize(dest.t),
makeCString(p.currLineInfo.toFullPath),
addrLoc(p.config, dest), rope getSize(p.config, dest.t),
makeCString(toFullPath(p.config, p.currLineInfo)),
rope p.currLineInfo.safeLineNm)
proc genDeepCopy(p: BProc; dest, src: TLoc) =
@@ -381,31 +381,31 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
var tmp: TLoc
getTemp(p, a.t, tmp)
genAssignment(p, tmp, a, {})
addrLoc(tmp)
addrLoc(p.config, tmp)
else:
addrLoc(a)
addrLoc(p.config, a)
var ty = skipTypes(dest.t, abstractVarRange)
var ty = skipTypes(dest.t, abstractVarRange + {tyStatic})
case ty.kind
of tyPtr, tyRef, tyProc, tyTuple, tyObject, tyArray:
# XXX optimize this
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))
of tySequence, tyString:
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))
of tyOpenArray, tyVarargs:
linefmt(p, cpsStmts,
"#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))
of tySet:
if mapType(ty) == ctArray:
if mapType(p.config, ty) == ctArray:
useStringh(p.module)
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:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
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;
frmt: string): Rope =
var size = getSize(t)
let storage = if size < platform.intSize: rope("NI")
var size = getSize(p.config, t)
let storage = if size < p.config.target.intSize: rope("NI")
else: getTypeDesc(p.module, t)
result = getTempName(p.module)
linefmt(p, cpsLocals, "$1 $2;$n", storage, result)
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",
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) =
const
@@ -547,8 +547,8 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
t = skipTypes(e.typ, abstractRange)
if optOverflowCheck in p.options:
linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n",
rdLoc(a), intLiteral(firstOrd(t)))
putIntoDest(p, d, e, opr[m] % [rdLoc(a), rope(getSize(t) * 8)])
rdLoc(a), intLiteral(firstOrd(p.config, t)))
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) =
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[2], b)
# BUGFIX: cannot use result-type here, as it may be a boolean
s = max(getSize(a.t), getSize(b.t)) * 8
k = getSize(a.t) * 8
s = max(getSize(p.config, a.t), getSize(p.config, b.t)) * 8
k = getSize(p.config, a.t) * 8
putIntoDest(p, d, e,
binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s),
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)
t = skipTypes(e.typ, abstractRange)
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)])
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
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:
# XXX the amount of hacks for C's arrays is incredible, maybe we should
# 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)
putIntoDest(p, d, e, "&" & a.r, a.storage)
#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)
else:
var a: TLoc
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) =
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:
var a: TLoc
genRecordFieldAux(p, e.sons[0], d, a)
let ty = skipTypes(a.t, abstractInst)
let ty = skipTypes(a.t, abstractInst + tyUserTypeClasses)
var r = rdLoc(a)
let f = e.sons[0].sons[1].sym
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, y, b)
var ty = skipTypes(a.t, abstractVarRange + abstractPtrs + tyUserTypeClasses)
var first = intLiteral(firstOrd(ty))
var first = intLiteral(firstOrd(p.config, ty))
# emit range check:
if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
if not isConstExpr(y):
# semantic pass has already checked for const index expressions
if firstOrd(ty) == 0:
if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)):
if firstOrd(p.config, ty) == 0:
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",
rdCharLoc(b), intLiteral(lastOrd(ty)))
rdCharLoc(b), intLiteral(lastOrd(p.config, ty)))
else:
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:
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")
d.inheritLocation(a)
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",
rdLoc(a), rdLoc(b), rdLoc(arr))
of tyArray:
let first = intLiteral(firstOrd(ty))
let first = intLiteral(firstOrd(p.config, ty))
if tfUncheckedArray notin ty.flags:
linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " &
"($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:
linefmt(p, cpsStmts,
"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)``
# is threadsafe.
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
var args: Rope = nil
var a: TLoc
@@ -1007,7 +1007,7 @@ proc genEcho(p: BProc, n: PNode) =
when false:
p.module.includeHeader("<stdio.h>")
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")
proc gcUsage(conf: ConfigRef; n: PNode) =
@@ -1121,7 +1121,7 @@ proc genReset(p: BProc, n: PNode) =
var a: TLoc
initLocExpr(p, n.sons[1], a)
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(a),
addrLoc(p.config, a),
genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info))
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:
getTemp(p, n.typ, d)
# 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))
initLocExpr(p, n.sons[1], a)
# 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)
of tySet:
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:
var b: TLoc
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)
of tyArray:
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()")
putIntoDest(p, d, e,
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")
else:
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)
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)
of tyArray:
# YYY: length(sideeffect) is optimized away incorrectly?
if op == mHigh: putIntoDest(p, d, e, rope(lastOrd(typ)))
else: putIntoDest(p, d, e, rope(lengthOrd(typ)))
if op == mHigh: putIntoDest(p, d, e, rope(lastOrd(p.config, typ)))
else: putIntoDest(p, d, e, rope(lengthOrd(p.config, typ)))
else: internalError(p.config, e.info, "genArrayLen()")
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, 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
# before the set operation
result = rdCharLoc(a)
assert(setType.kind == tySet)
if firstOrd(setType) != 0:
result = "($1- $2)" % [result, rope(firstOrd(setType))]
if firstOrd(conf, setType) != 0:
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
# for constructing the set or generating a bunch of comparisons directly
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
elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}:
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
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) =
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 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)")
@@ -1572,11 +1572,11 @@ proc binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) =
assert(d.k == locNone)
initLocExpr(p, e.sons[1], a)
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) =
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:
# 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
@@ -1620,7 +1620,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
"&", "|", "& ~", "^"]
var a, b, i: TLoc
var setType = skipTypes(e.sons[1].typ, abstractVar)
var size = int(getSize(setType))
var size = int(getSize(p.config, setType))
case size
of 1, 2, 4, 8:
case op
@@ -1687,7 +1687,7 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
let etyp = skipTypes(e.typ, abstractRange)
if etyp.kind in ValueTypes and lfIndirect notin a.flags:
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:
putIntoDest(p, d, e, "(($1) ($2))" %
[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))
else:
if d.k == locNone: getTemp(p, e.typ, d)
if getSize(e.typ) > 8:
if getSize(p.config, e.typ) > 8:
# big set:
useStringh(p.module)
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)
lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
"$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:
initLocExpr(p, it, a)
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:
# 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)])
for it in e.sons:
if it.kind == nkRange:
@@ -1952,13 +1952,13 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, it.sons[1], b)
lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
"$2 |=((" & ts & ")(1)<<(($1)%(sizeof(" & ts & ")*8)));$n", [
rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ),
rdSetElemLoc(b, e.typ)])
rdLoc(idx), rdLoc(d), rdSetElemLoc(p.config, a, e.typ),
rdSetElemLoc(p.config, b, e.typ)])
else:
initLocExpr(p, it, a)
lineF(p, cpsStmts,
"$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) =
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)
else:
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) =
if p.module.compileToCpp:
@@ -2297,7 +2297,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
incl a.flags, lfSingleUse
genCall(p, ex, a)
if lfSingleUse notin a.flags:
line(p, cpsStmts, a.r & ";" & tnl)
line(p, cpsStmts, a.r & ";\L")
else:
initLocExpr(p, ex, a)
of nkAsmStmt: genAsmStmt(p, n)
@@ -2313,7 +2313,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
genTypeSection(p.module, n)
of nkCommentStmt, nkIteratorDef, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef:
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt:
discard
of nkPragma: genPragma(p, n)
of nkPragmaBlock: expr(p, n.lastSon, d)
@@ -2367,7 +2367,7 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
result.add "}"
of tyArray: result = rope"{}"
of tySet:
if mapType(t) == ctArray: result = rope"{}"
if mapType(p.config, t) == ctArray: result = rope"{}"
else: result = rope"0"
else:
globalError(p.config, info, "cannot create null element for: " & $t.kind)
@@ -2436,7 +2436,7 @@ proc genConstSimpleList(p: BProc, n: PNode): Rope =
addf(result, "}$n", [])
proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
var data = "{{$1, $1}" % [n.len.rope]
var data = "{{$1, $1 | NIM_STRLIT_FLAG}" % [n.len.rope]
if n.len > 0:
# array part needs extra curlies:
data.add(", {")
@@ -2464,8 +2464,8 @@ proc genConstExpr(p: BProc, n: PNode): Rope =
result = genConstExpr(p, n.sons[1])
of nkCurly:
var cs: TBitSet
toBitSet(n, cs)
result = genRawSetData(cs, int(getSize(n.typ)))
toBitSet(p.config, n, cs)
result = genRawSetData(cs, int(getSize(p.config, n.typ)))
of nkBracket, nkPar, nkTupleConstr, nkClosure:
var t = skipTypes(n.typ, abstractInst)
if t.kind == tySequence:

View File

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

View File

@@ -28,9 +28,9 @@ proc registerGcRoot(p: BProc, v: PSym) =
appcg(p.module, p.module.initProc.procSec(cpsInit),
"#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 isInvalidReturnType(n.typ):
if isInvalidReturnType(conf, n.typ):
# var v = f()
# is transformed into: var v; f(addr v)
# where 'f' **does not** initialize the result!
@@ -65,7 +65,7 @@ proc genVarTuple(p: BProc, n: PNode) =
registerGcRoot(p, v)
else:
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)
if t.kind == tyTuple:
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
@@ -205,7 +205,7 @@ proc genGotoState(p: BProc, n: PNode) =
howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlockLen)
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:
statesCounter = n[1].intVal
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)
else:
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
not containsHiddenPointer(v.typ):
# 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,
"case statement must be exhaustive for computed goto"); return
casePos = i
let aSize = lengthOrd(it.sons[0].typ)
let aSize = lengthOrd(p.config, it.sons[0].typ)
if aSize > 10_000:
localError(p.config, it.info,
"case statement has too many cases for computed goto"); return
arraySize = aSize.int
if firstOrd(it.sons[0].typ) != 0:
if firstOrd(p.config, it.sons[0].typ) != 0:
localError(p.config, it.info,
"case statement has to start at 0 for computed goto"); return
if casePos < 0:
@@ -480,7 +480,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
var loopBody = t.sons[1]
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:
if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
loopBody = loopBody.sons[1]
@@ -653,7 +653,7 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
assert(b.sons[i].kind != nkRange)
initLocExpr(p, b.sons[i], x)
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",
[rdLoc(e), rdLoc(x), labl])
@@ -706,7 +706,7 @@ proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
var stmtBlock = lastSon(branch)
if stmtBlock.stmtsContainPragma(wLinearScanEnd):
result = i
elif hasSwitchRange notin CC[cCompiler].props:
elif hasSwitchRange notin CC[p.config.cCompiler].props:
if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
result = i
@@ -714,7 +714,7 @@ proc genCaseRange(p: BProc, branch: PNode) =
var length = branch.len
for j in 0 .. length-2:
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", [
genLiteral(p, branch[j][0]),
genLiteral(p, branch[j][1])])
@@ -754,7 +754,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
hasDefault = true
exprBlock(p, branch.lastSon, d)
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, "}$n", [])
if lend != nil: fixLabel(p, lend)
@@ -975,21 +975,22 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
initLocExpr(p, it, a)
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):
var j = 0
while x[j] in {' ', '\t'}: inc(j)
if x[j] in {'"', ':'}:
# don't modify the line if already in quotes or
# some clobber register list:
add(result, x); add(result, tnl)
elif x[j] != '\0':
# ignore empty lines
add(result, "\"")
add(result, x)
add(result, "\\n\"\n")
while j < x.len and x[j] in {' ', '\t'}: inc(j)
if j < x.len:
if x[j] in {'"', ':'}:
# don't modify the line if already in quotes or
# some clobber register list:
add(result, x); add(result, "\L")
else:
# ignore empty lines
add(result, "\"")
add(result, x)
add(result, "\\n\"\n")
else:
res.add(tnl)
res.add("\L")
result = res.rope
proc genAsmStmt(p: BProc, t: PNode) =
@@ -1001,9 +1002,9 @@ proc genAsmStmt(p: BProc, t: PNode) =
# work:
if p.prc == nil:
# 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:
lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s])
lineF(p, cpsStmts, CC[p.config.cCompiler].asmStmtFrmt, [s])
proc determineSection(n: PNode): TCFileSection =
result = cfsProcHeaders
@@ -1036,7 +1037,7 @@ proc genBreakPoint(p: BProc, t: PNode) =
genLineDir(p, t) # BUGFIX
appcg(p.module, p.module.g.breakpoints,
"#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)])
proc genWatchpoint(p: BProc, n: PNode) =
@@ -1045,7 +1046,7 @@ proc genWatchpoint(p: BProc, n: PNode) =
initLocExpr(p, n.sons[1], a)
let typ = skipTypes(n.sons[1].typ, abstractVarRange)
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)])
proc genPragma(p: BProc, n: PNode) =
@@ -1076,7 +1077,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
var t = skipTypes(objtype, abstractVar)
assert t.kind == tyObject
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):
appcg(p.module, cfsVars, "extern $1",
discriminatorTableDecl(p.module, t, field))

View File

@@ -23,27 +23,14 @@ proc accessThreadLocalVar(p: BProc, s: PSym) =
add(p.procSec(cpsInit),
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) =
if emulatedThreadVars(m.config):
# we gather all thread locals var into a struct; we need to allocate
# storage for that somehow, can't use the thread local storage
# allocator for it :-(
if not containsOrIncl(nimtvDeclared, s.id):
nimtvDeps.add(s.loc.t)
addf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
if not containsOrIncl(m.g.nimtvDeclared, s.id):
m.g.nimtvDeps.add(s.loc.t)
addf(m.g.nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
else:
if isExtern: add(m.s[cfsVars], "extern ")
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])
proc generateThreadLocalStorage(m: BModule) =
if nimtv != nil and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
for t in items(nimtvDeps): discard getTypeDesc(m, t)
addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
if m.g.nimtv != nil and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
for t in items(m.g.nimtvDeps): discard getTypeDesc(m, t)
addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [m.g.nimtv])
proc generateThreadVarsSize(m: BModule) =
if nimtv != nil:
if m.g.nimtv != nil:
let externc = if m.config.cmd == cmdCompileToCpp or
sfCompileToCpp in m.module.flags: "extern \"C\" "
else: ""

View File

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

View File

@@ -50,7 +50,7 @@ proc mangleName(m: BModule; s: PSym): Rope =
result = s.name.s.mangle.rope
add(result, idOrSig(s, m.module.name.s, m.sigConflicts))
s.loc.r = result
writeMangledName(m.ndi, s)
writeMangledName(m.ndi, s, m.config)
proc mangleParamName(m: BModule; s: PSym): Rope =
## 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"
result = res.rope
s.loc.r = result
writeMangledName(m.ndi, s)
writeMangledName(m.ndi, s, m.config)
proc mangleLocalName(p: BProc; s: PSym): Rope =
assert s.kind in skLocalVars+{skTemp}
@@ -81,7 +81,7 @@ proc mangleLocalName(p: BProc; s: PSym): Rope =
result.add "_" & rope(counter+1)
p.sigConflicts.inc(key)
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) =
## 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
if result == nil: internalError(m.config, "getTypeName: " & $typ.kind)
proc mapSetType(typ: PType): TCTypeKind =
case int(getSize(typ))
proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
case int(getSize(conf, typ))
of 1: result = ctInt8
of 2: result = ctInt16
of 4: result = ctInt32
of 8: result = ctInt64
else: result = ctArray
proc mapType(typ: PType): TCTypeKind =
proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
## Maps a Nim type to a C type
case typ.kind
of tyNone, tyStmt: result = ctVoid
of tyBool: result = ctBool
of tyChar: result = ctChar
of tySet: result = mapSetType(typ)
of tySet: result = mapSetType(conf, typ)
of tyOpenArray, tyArray, tyVarargs: result = ctArray
of tyObject, tyTuple: result = ctStruct
of tyUserTypeClasses:
doAssert typ.isResolvedUserTypeClass
return mapType(typ.lastSon)
return mapType(conf, typ.lastSon)
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
tyTypeDesc, tyAlias, tySink, tyInferred:
result = mapType(lastSon(typ))
result = mapType(conf, lastSon(typ))
of tyEnum:
if firstOrd(typ) < 0:
if firstOrd(conf, typ) < 0:
result = ctInt32
else:
case int(getSize(typ))
case int(getSize(conf, typ))
of 1: result = ctUInt8
of 2: result = ctUInt16
of 4: result = ctInt32
of 8: result = ctInt64
else: result = ctInt32
of tyRange: result = mapType(typ.sons[0])
of tyRange: result = mapType(conf, typ.sons[0])
of tyPtr, tyVar, tyLent, tyRef, tyOptAsRef:
var base = skipTypes(typ.lastSon, typedescInst)
case base.kind
@@ -169,27 +169,20 @@ proc mapType(typ: PType): TCTypeKind =
else: result = ctPtr
of tyPointer: result = ctPtr
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 tyString: result = ctNimStr
of tyCString: result = ctCString
of tyInt..tyUInt64:
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
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")
proc mapReturnType(typ: PType): TCTypeKind =
proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind =
#if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
#else:
result = mapType(typ)
result = mapType(conf, typ)
proc isImportedType(t: PType): bool =
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
(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
# such a poor programming language.
# We exclude records with refs too. This enhances efficiency and
# is necessary for proper code generation of assignments.
if rettype == nil: result = true
else:
case mapType(rettype)
case mapType(conf, rettype)
of ctArray:
result = not (skipTypes(rettype, typedescInst).kind in
{tyVar, tyLent, tyRef, tyPtr})
@@ -240,9 +233,9 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
proc addAbiCheck(m: BModule, t: PType, name: Rope) =
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)
assert skResult != s.kind
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:
# forwarded objects are *always* passed by pointers for consistency!
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
elif (tfFinal in pt.flags) and (pt.sons[0] == nil):
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,
# otherwise casting doesn't work
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
proc fillResult(param: PNode) =
proc fillResult(conf: ConfigRef; param: PNode) =
fillLoc(param.sym.loc, locParam, param, ~"Result",
OnStack)
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)
param.sym.loc.storage = OnUnknown
@@ -364,12 +357,6 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
of tySequence:
result = getTypeForward(m, t, hashType(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:
result = getTypeDescAux(m, t, check)
@@ -384,7 +371,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
check: var IntSet, declareEnvironment=true;
weakDep=false) =
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"
else:
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, ~", ")
fillLoc(param.loc, locParam, t.n.sons[i], mangleParamName(m, param),
param.paramStorageLoc)
if ccgIntroducedPtr(param):
if ccgIntroducedPtr(m.config, param):
add(params, getTypeDescWeak(m, param.typ, check))
add(params, ~"*")
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])
inc(j)
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]
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, "*")
else:
@@ -471,13 +458,13 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
if tfPacked notin rectype.flags:
add(unionBody, "struct {")
else:
if hasAttribute in CC[cCompiler].props:
if hasAttribute in CC[m.config.cCompiler].props:
add(unionBody, "struct __attribute__((__packed__)){" )
else:
addf(unionBody, "#pragma pack(push, 1)$nstruct{", [])
add(unionBody, a)
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", [])
else:
add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
@@ -526,10 +513,10 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
var hasField = false
if tfPacked in typ.flags:
if hasAttribute in CC[cCompiler].props:
if hasAttribute in CC[m.config.cCompiler].props:
result = structOrUnion(typ) & " __attribute__((__packed__))"
else:
result = "#pragma pack(push, 1)" & tnl & structOrUnion(typ)
result = "#pragma pack(push, 1)\L" & structOrUnion(typ)
else:
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:
# generated function will be below declared Exception type and circular dependency
# 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
else:
appcg(m, result, " {$n $1 Sup;$n",
@@ -570,9 +557,9 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
addf(result, "char dummy;$n", [])
else:
add(result, desc)
add(result, "};" & tnl)
if tfPacked in typ.flags and hasAttribute notin CC[cCompiler].props:
result.add "#pragma pack(pop)" & tnl
add(result, "};\L")
if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props:
result.add "#pragma pack(pop)\L"
proc getTupleDesc(m: BModule, typ: PType, name: 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):
addf(desc, "$1 Field$2;$n",
[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)
add(result, "};" & tnl)
add(result, "};\L")
proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
# 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
m.typeCache[sig] = result
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 we have a strong dependency :-(
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)):
m.typeCache[sig] = result
var size: int
if firstOrd(t) < 0:
if firstOrd(m.config, t) < 0:
addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
size = 4
else:
size = int(getSize(t))
size = int(getSize(m.config, t))
case size
of 1: addf(m.s[cfsTypes], "typedef NU8 $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:
result = rope("TGenericSeq")
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:
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
result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result
@@ -791,8 +731,6 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
else: addAbiCheck(m, t, result)
of tyObject, tyTuple:
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)
var i = 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)
m.typeCache[sig] = result
if not isImportedType(t):
let s = int(getSize(t))
let s = int(getSize(m.config, t))
case s
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",
[result, rope(getSize(t))])
[result, rope(getSize(m.config, t))])
of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink,
tyUserTypeClass, tyUserTypeClassInst, tyInferred:
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
else: origType, preferName)
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",
[name, makeCstring typename])
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 =
discard cgsym(m, "TNimNode")
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;
info: TLineInfo) =
@@ -1030,7 +968,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
assert(n.sons[0].kind == nkSym)
var field = n.sons[0].sym
var tmp = discriminatorTableName(m, typ, field)
var L = lengthOrd(field.typ)
var L = lengthOrd(m.config, field.typ)
assert L > 0
if field.loc.r == nil: fillObjectFields(m, typ)
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))
else:
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:
addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
hasHoles = true
@@ -1166,7 +1104,7 @@ proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
genTypeInfoAux(m, typ, typ, name, info)
var tmp = getNimNode(m)
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) =
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 =
let origType = t
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
if t.kind == tyOpt:
return genTypeInfo(m, optLowering(t), info)
let sig = hashType(origType)
result = m.typeInfoMarker.getOrDefault(sig)

View File

@@ -27,9 +27,9 @@ proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
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!
if CPU[targetCPU].bit == 64:
if CPU[conf.target.targetCPU].bit == 64:
# we have to use the same bitwidth
# as the target CPU
var b = 0'i64
@@ -52,117 +52,12 @@ proc hashString*(s: string): BiggestInt =
a = a +% `shl`(a, 15'i32)
result = a
var
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")
template getUniqueType*(key: PType): PType = key
proc makeSingleLineCString*(s: string): string =
result = "\""
for c in items(s):
result.add(c.toCChar)
c.toCChar(result)
result.add('\"')
proc mangle*(name: string): string =
@@ -210,5 +105,3 @@ proc mangle*(name: string): string =
requiresUnderscore = true
if requiresUnderscore:
result.add "_"
initTypeTables()

View File

@@ -12,14 +12,15 @@
import
ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
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,
lowerings, semparallel, tables, sets, ndi
lowerings, semparallel, tables, sets, ndi, lineinfos
import strutils except `%` # collides with ropes.`%`
from modulegraphs import ModuleGraph
from configuration import warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated
from lineinfos import
warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated, errCannotOpenFile
import dynlib
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)
add(result, args[j-1])
of 'n':
if optLineDir notin m.config.options: add(result, rnl)
if optLineDir notin m.config.options: add(result, "\L")
inc(i)
of 'N':
add(result, rnl)
add(result, "\L")
inc(i)
else: internalError(m.config, "ropes: invalid format string $" & frmt[i])
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)])
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 =
if p.lastLineInfo.line != info.line or
@@ -203,27 +204,22 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
result = true
proc genLineDir(p: BProc, t: PNode) =
var tt = t
#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
let line = t.info.safeLineNm
if optEmbedOrigSrc in p.config.globalOptions:
add(p.s(cpsStmts), ~"//" & sourceLine(p.config, tt.info) & rnl)
genCLineDir(p.s(cpsStmts), tt.info.toFullPath, line, p.config)
add(p.s(cpsStmts), ~"//" & sourceLine(p.config, t.info) & "\L")
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config)
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
(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",
line.rope, makeCString(toFilename(tt.info)))
line.rope, makeCString(toFilename(p.config, t.info)))
elif ({optLineTrace, optStackTrace} * p.options ==
{optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex != InvalidFileIDX:
if freshLineInfo(p, tt.info):
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIDX:
if freshLineInfo(p, t.info):
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.} =
add(p.s(cpsStmts), p.module.injectStmt)
@@ -249,9 +245,9 @@ proc rdLoc(a: TLoc): Rope =
result = a.r
if lfIndirect in a.flags: result = "(*$1)" % [result]
proc addrLoc(a: TLoc): Rope =
proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
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 & ")"
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))
of frEmbedded:
# 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))
type
@@ -310,10 +306,10 @@ proc resetLoc(p: BProc, loc: var TLoc) =
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
else:
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:
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
# field, so disabling this should be safe:
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
# so we use getTypeDesc here rather than rdLoc(loc)
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
# on the bytes following the m_type field?
genObjectInit(p, cpsStmts, loc.t, loc, true)
@@ -339,7 +335,7 @@ proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
if not isImportedCppType(typ):
useStringh(p.module)
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)
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:
if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
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,
"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,
@@ -414,7 +410,7 @@ proc assignLocalVar(p: BProc, n: PNode) =
#assert(s.loc.k == locNone) # not yet assigned
# this need not be fulfilled for inline procs; they are regenerated
# 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
line(p, cpsLocals, decl)
localDebugInfo(p, n.sym)
@@ -651,33 +647,33 @@ proc cgsym(m: BModule, name: string): Rope =
result = sym.loc.r
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:
if it[0] == '#':
add(m.s[cfsHeaders], rope(it.replace('`', '"') & tnl))
add(m.s[cfsHeaders], rope(it.replace('`', '"') & "\L"))
elif it[0] notin {'\"', '<'}:
addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it)])
else:
addf(m.s[cfsHeaders], "#include $1$N", [rope(it)])
add(m.s[cfsHeaders], "#undef LANGUAGE_C" & tnl)
add(m.s[cfsHeaders], "#undef MIPSEB" & tnl)
add(m.s[cfsHeaders], "#undef MIPSEL" & tnl)
add(m.s[cfsHeaders], "#undef PPC" & tnl)
add(m.s[cfsHeaders], "#undef R3000" & tnl)
add(m.s[cfsHeaders], "#undef R4000" & tnl)
add(m.s[cfsHeaders], "#undef i386" & tnl)
add(m.s[cfsHeaders], "#undef linux" & tnl)
add(m.s[cfsHeaders], "#undef mips" & tnl)
add(m.s[cfsHeaders], "#undef near" & tnl)
add(m.s[cfsHeaders], "#undef powerpc" & tnl)
add(m.s[cfsHeaders], "#undef unix" & tnl)
add(m.s[cfsHeaders], "#undef LANGUAGE_C\L")
add(m.s[cfsHeaders], "#undef MIPSEB\L")
add(m.s[cfsHeaders], "#undef MIPSEL\L")
add(m.s[cfsHeaders], "#undef PPC\L")
add(m.s[cfsHeaders], "#undef R3000\L")
add(m.s[cfsHeaders], "#undef R4000\L")
add(m.s[cfsHeaders], "#undef i386\L")
add(m.s[cfsHeaders], "#undef linux\L")
add(m.s[cfsHeaders], "#undef mips\L")
add(m.s[cfsHeaders], "#undef near\L")
add(m.s[cfsHeaders], "#undef powerpc\L")
add(m.s[cfsHeaders], "#undef unix\L")
proc openNamespaceNim(): Rope =
result.add("namespace Nim {" & tnl)
result.add("namespace Nim {\L")
proc closeNamespaceNim(): Rope =
result.add("}" & tnl)
result.add("}\L")
proc closureSetup(p: BProc, prc: PSym) =
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")
let resNode = prc.ast.sons[resultPos]
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 and p.module.compileToCpp and (let val = easyResultAsgn(prc.getBody); val != nil):
var decl = localVarDecl(p, resNode)
@@ -741,7 +737,7 @@ proc genProcAux(m: BModule, prc: PSym) =
initLocalVar(p, res, immediateAsgn=false)
returnStmt = ropecg(p.module, "\treturn $1;$n", rdLoc(res.loc))
else:
fillResult(resNode)
fillResult(p.config, resNode)
assignParam(p, res)
if sfNoInit notin prc.flags: resetLoc(p, res.loc)
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.
var generatedProc: Rope
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
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
generatedProc = ropecg(p.module, "$N$1 {$n$2$3$4}$N$N",
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)))
elif not containsOrIncl(m.declaredProtos, sym.id):
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
if sym.typ.callConv != ccInline and requiresExternC(m, sym):
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))")
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))")
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])
proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} =
addf(result, "#define NIM_NEW_MANGLING_RULES" & tnl &
"#define NIM_INTBITS $1" & tnl, [
platform.CPU[targetCPU].intSize.rope])
if optUseNimNamespace in conf.globalOptions: result.add("#define USE_NIM_NAMESPACE" & tnl)
addf(result, "#define NIM_NEW_MANGLING_RULES\L" &
"#define NIM_INTBITS $1\L", [
platform.CPU[conf.target.targetCPU].intSize.rope])
if optUseNimNamespace in conf.globalOptions: result.add("#define USE_NIM_NAMESPACE\L")
proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope =
if optCompileOnly in conf.globalOptions:
@@ -936,9 +932,9 @@ proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope =
"/* Compiled for: $2, $3, $4 */$N" &
"/* Command for C compiler:$n $5 */$N") %
[rope(VersionAsString),
rope(platform.OS[targetOS].name),
rope(platform.CPU[targetCPU].name),
rope(extccomp.CC[extccomp.cCompiler].name),
rope(platform.OS[conf.target.targetOS].name),
rope(platform.CPU[conf.target.targetCPU].name),
rope(extccomp.CC[conf.cCompiler].name),
rope(getCompileCFileCmd(conf, cfile))]
proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
@@ -948,8 +944,8 @@ proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
proc genFilenames(m: BModule): Rope =
discard cgsym(m, "dbgRegisterFilename")
result = nil
for i in 0..<fileInfos.len:
result.addf("dbgRegisterFilename($1);$N", [fileInfos[i].projPath.makeCString])
for i in 0..<m.config.m.fileInfos.len:
result.addf("dbgRegisterFilename($1);$N", [m.config.m.fileInfos[i].projPath.makeCString])
proc genMainProc(m: BModule) =
const
@@ -1052,7 +1048,7 @@ proc genMainProc(m: BModule) =
"}$N$N"
var nimMain, otherMain: FormatStr
if platform.targetOS == osWindows and
if m.config.target.targetOS == osWindows and
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
if optGenGuiApp in m.config.globalOptions:
nimMain = WinNimMain
@@ -1061,14 +1057,14 @@ proc genMainProc(m: BModule) =
nimMain = WinNimDllMain
otherMain = WinCDllMain
m.includeHeader("<windows.h>")
elif platform.targetOS == osGenode:
elif m.config.target.targetOS == osGenode:
nimMain = GenodeNimMain
otherMain = ComponentConstruct
m.includeHeader("<libc/component.h>")
elif optGenDynLib in m.config.globalOptions:
nimMain = PosixNimDllMain
otherMain = PosixCDllMain
elif platform.targetOS == osStandalone:
elif m.config.target.targetOS == osStandalone:
nimMain = PosixNimMain
otherMain = StandaloneCMain
else:
@@ -1079,12 +1075,12 @@ proc genMainProc(m: BModule) =
m.g.breakpoints.add(m.genFilenames)
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")
inc(m.labels)
appcg(m, m.s[cfsProcs], PreMainBody, [
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")
else:
"".rope,
@@ -1094,7 +1090,7 @@ proc genMainProc(m: BModule) =
[m.g.mainModInit, initStackBottomCall, rope(m.labels)])
if optNoMain notin 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, [])
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)
let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi")
else: ""
open(result.ndi, ndiName)
open(result.ndi, ndiName, g.config)
proc nullify[T](arr: var T) =
for i in low(arr)..high(arr):
@@ -1305,13 +1301,15 @@ proc resetModule*(m: BModule) =
proc resetCgenModules*(g: BModuleList) =
for m in cgenModules(g): resetModule(m)
proc rawNewModule(g: BModuleList; module: PSym): BModule =
result = rawNewModule(g, module, module.position.FileIndex.toFullPath)
proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
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
result = rawNewModule(g, module)
growCache g.modules, module.position
result = rawNewModule(g, module, conf)
if module.position >= g.modules.len:
setLen(g.modules, module.position + 1)
#growCache g.modules, module.position
g.modules[module.position] = result
template injectG() {.dirty.} =
@@ -1319,9 +1317,9 @@ template injectG() {.dirty.} =
graph.backend = newModuleList(graph)
let g = BModuleList(graph.backend)
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
injectG()
result = newModule(g, module)
result = newModule(g, module, graph.config)
if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil:
let f = if graph.config.headerFile.len > 0: graph.config.headerFile
else: graph.config.projectFull
@@ -1353,7 +1351,8 @@ proc writeHeader(m: BModule) =
result.addf("N_CDECL(void, NimMain)(void);$n", [])
if optUseNimNamespace in m.config.globalOptions: result.add closeNamespaceNim()
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 =
let ext =
@@ -1362,11 +1361,12 @@ proc getCFile(m: BModule): string =
else: ".c"
result = changeFileExt(completeCFilePath(m.config, withPackageName(m.config, m.cfilename)), ext)
proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
injectG()
var m = newModule(g, module)
readMergeInfo(getCFile(m), m)
result = m
when false:
proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
injectG()
var m = newModule(g, module, graph.config)
readMergeInfo(getCFile(m), m)
result = m
proc myProcess(b: PPassContext, n: PNode): PNode =
result = n
@@ -1374,7 +1374,8 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
var m = BModule(b)
if passes.skipCodegen(m.config, n): return
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)
proc finishModule(m: BModule) =
@@ -1401,12 +1402,14 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
echo "diff ", cfile.cname, ".backup ", cfile.cname
else:
echo "new file ", cfile.cname
writeRope(code, cfile.cname)
if not writeRope(code, cfile.cname):
rawMessage(m.config, errCannotOpenFile, cfile.cname)
return
if existsFile(cfile.obj) and os.fileNewer(cfile.obj, cfile.cname):
result = false
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
# '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:
let cfile = getCFile(m)
if m.rd == nil or optForceFullMake in m.config.globalOptions:
if true or optForceFullMake in m.config.globalOptions:
genInitCode(m)
finishTypeDescriptions(m)
if sfMainModule in m.module.flags:
@@ -1441,7 +1444,8 @@ proc writeModule(m: BModule, pending: bool) =
genInitCode(m)
finishTypeDescriptions(m)
var code = genModule(m, cf)
writeRope(code, cfile)
if not writeRope(code, cfile):
rawMessage(m.config, errCannotOpenFile, cfile)
addFileToCompile(m.config, cf)
else:
# Consider: first compilation compiles ``system.nim`` and produces
@@ -1462,7 +1466,8 @@ proc updateCachedModule(m: BModule) =
finishTypeDescriptions(m)
var code = genModule(m, cf)
writeRope(code, cfile)
if not writeRope(code, cfile):
rawMessage(m.config, errCannotOpenFile, cfile)
else:
cf.flags = {CfileFlag.Cached}
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
# nor the dispatchers? But if the dispatchers changed?
# XXX emit the dispatchers into its own .c file?
if b.rd != nil: return
if n != nil:
m.initProc.options = initProcOptions(m)
genStmts(m.initProc, n)
@@ -1498,14 +1502,10 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
if g.generatedHeader != nil: finishModule(g.generatedHeader)
while g.forwardedProcsCounter > 0:
for m in cgenModules(g):
if m.rd == nil:
finishModule(m)
finishModule(m)
for m in cgenModules(g):
if m.rd != nil:
m.updateCachedModule
else:
m.writeModule(pending=true)
m.writeModule(pending=true)
writeMapping(config, g.mapping)
if g.generatedHeader != nil: writeHeader(g.generatedHeader)
const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
const cgenPass* = makePass(myOpen, myProcess, myClose)

View File

@@ -11,9 +11,8 @@
import
ast, astalgo, ropes, passes, options, intsets, platform, sighashes,
tables, ndi
tables, ndi, lineinfos
from msgs import TLineInfo
from modulegraphs import ModuleGraph
type
@@ -122,6 +121,17 @@ type
graph*: ModuleGraph
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
s*: TCFileSections # sections of the C file
flags*: set[Codegenflag]
@@ -180,7 +190,7 @@ proc newProc*(prc: PSym, module: BModule): BProc =
proc newModuleList*(g: ModuleGraph): BModuleList =
BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: g.config,
graph: g)
graph: g, nimtvDeps: @[], nimtvDeclared: initIntSet())
iterator cgenModules*(g: BModuleList): BModule =
for i in 0..high(g.modules):

View File

@@ -11,7 +11,7 @@
import
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 =
var dest = skipTypes(d, abstractPtrs)
@@ -115,7 +115,7 @@ proc createDispatcher(s: PSym): PSym =
# we can't inline the dispatcher itself (for now):
if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault
disp.ast = copyTree(s.ast)
disp.ast.sons[bodyPos] = ast.emptyNode
disp.ast.sons[bodyPos] = newNodeI(nkEmpty, s.info)
disp.loc.r = nil
if s.typ.sons[0] != nil:
if disp.ast.sonsLen > resultPos:
@@ -124,7 +124,7 @@ proc createDispatcher(s: PSym): PSym =
# We've encountered a method prototype without a filled-in
# resultPos slot. We put a placeholder in there that will
# be updated in fixupDispatcher().
disp.ast.addSon(ast.emptyNode)
disp.ast.addSon(newNodeI(nkEmpty, s.info))
attachDispatcher(s, newSymNode(disp))
# attach to itself to prevent bugs:
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
# against that of the method.
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])
# 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")
if witness != nil:
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:
message(g.config, s.info, warnUseBase)

View File

@@ -1,7 +1,7 @@
#
#
# The Nim Compiler
# (c) Copyright 2018 Andreas Rumpf
# (c) Copyright 2018 Nim Contributors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -132,7 +132,7 @@
import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, idents,
renderer, types, magicsys, rodread, lowerings, lambdalifting, modulegraphs
renderer, types, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos
type
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)))
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
assert(not typ.isNil)
@@ -190,7 +190,7 @@ proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
else:
let envParam = getEnvParam(ctx.fn)
# 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 =
if ctx.stateVarSym.isNil:
@@ -210,7 +210,7 @@ proc newUnrollFinallyAccess(ctx: var Ctx, info: TLineInfo): PNode =
proc newCurExcAccess(ctx: var Ctx): PNode =
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)
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)
let nextCond = newTree(nkCall,
newSymNode(g.getSysMagic(c.info, "of", mOf)),
g.callCodegenProc("getCurrentException", emptyNode),
g.callCodegenProc("getCurrentException", ctx.g.emptyNode),
c[i])
nextCond.typ = ctx.g.getSysType(c.info, tyBool)
nextCond.info = c.info
@@ -349,7 +349,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
if ifStmt.len != 0:
result = newTree(nkStmtList, ctx.newNullifyCurExc(n.info), ifStmt)
else:
result = emptyNode
result = ctx.g.emptyNode
proc addElseToExcept(ctx: var Ctx, n: PNode) =
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()
branchBody.add(newTree(nkAsgn,
ctx.newCurExcAccess(),
ctx.g.callCodegenProc("getCurrentException", emptyNode)))
ctx.g.callCodegenProc("getCurrentException", ctx.g.emptyNode)))
block: # goto 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)
n[1].add(elseBranch)
proc getFinallyNode(n: PNode): PNode =
proc getFinallyNode(ctx: var Ctx, n: PNode): PNode =
result = n[^1]
if result.kind == nkFinally:
result = result[0]
else:
result = emptyNode
result = ctx.g.emptyNode
proc hasYieldsInExpressions(n: PNode): bool =
case n.kind
@@ -725,7 +725,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if condNeedsSplit:
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 check = newTree(nkIfStmt, branch)
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)
let asgn = newTree(nkFastAsgn,
newSymNode(getClosureIterResult(ctx.fn), info),
newSymNode(getClosureIterResult(ctx.g, ctx.fn), info),
ctx.newTmpResultAccess())
let retStmt = newTree(nkReturnStmt, asgn)
let branch = newTree(nkElifBranch, cmp, retStmt)
# 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
let elseBranch = newTree(nkElse, raiseStmt)
@@ -922,7 +922,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
result = newNodeI(nkGotoState, n.info)
var tryBody = toStmtList(n[0])
var exceptBody = ctx.collectExceptState(n)
var finallyBody = newTree(nkStmtList, getFinallyNode(n))
var finallyBody = newTree(nkStmtList, getFinallyNode(ctx, n))
finallyBody = ctx.transformReturnsInTry(finallyBody)
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:
var a = newNodeI(nkAsgn, n[0].sons[0].info)
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)
retStmt.add(a)
else:
retStmt.add(emptyNode)
retStmt.add(ctx.g.emptyNode)
result.add(retStmt)
else:
@@ -1054,10 +1054,10 @@ proc tranformStateAssignments(ctx: var Ctx, n: PNode): PNode =
for i in 0 ..< n.len:
n[i] = ctx.tranformStateAssignments(n[i])
proc skipStmtList(n: PNode): PNode =
proc skipStmtList(ctx: Ctx; n: PNode): PNode =
result = n
while result.kind in {nkStmtList}:
if result.len == 0: return emptyNode
if result.len == 0: return ctx.g.emptyNode
result = result[0]
proc skipEmptyStates(ctx: Ctx, stateIdx: int): int =
@@ -1072,7 +1072,7 @@ proc skipEmptyStates(ctx: Ctx, stateIdx: int): int =
if label == -1:
newLabel = ctx.exitStateIdx
else:
let fs = ctx.states[label][1].skipStmtList()
let fs = skipStmtList(ctx, ctx.states[label][1])
if fs.kind == nkGotoState:
newLabel = fs[0].intVal.int
if label == newLabel: break
@@ -1148,7 +1148,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
newIntTypeNode(nkIntLit, 0, intTyp))
cond.typ = boolTyp
let raiseStmt = newTree(nkRaiseStmt, emptyNode)
let raiseStmt = newTree(nkRaiseStmt, ctx.g.emptyNode)
let ifBranch = newTree(nkElifBranch, cond, raiseStmt)
let ifStmt = newTree(nkIfStmt, ifBranch)
result.add(ifStmt)
@@ -1185,7 +1185,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
block:
result.add(newTree(nkAsgn,
ctx.newCurExcAccess(),
ctx.g.callCodegenProc("getCurrentException", emptyNode)))
ctx.g.callCodegenProc("getCurrentException", ctx.g.emptyNode)))
proc wrapIntoTryExcept(ctx: var Ctx, n: PNode): PNode {.inline.} =
let setupExc = newTree(nkCall,
@@ -1235,7 +1235,7 @@ proc deleteEmptyStates(ctx: var Ctx) =
# Apply new state indexes and mark unused states with -1
var iValid = 0
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:
# This is an empty state. Mark with -1.
s[0].intVal = -1
@@ -1244,7 +1244,7 @@ proc deleteEmptyStates(ctx: var Ctx) =
inc iValid
for i, s in ctx.states:
let body = s[1].skipStmtList()
let body = skipStmtList(ctx, s[1])
if body.kind != nkGotoState or i == 0:
discard ctx.skipThroughEmptyStates(s)
let excHandlState = ctx.exceptionTable[i]
@@ -1255,7 +1255,7 @@ proc deleteEmptyStates(ctx: var Ctx) =
var i = 0
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:
ctx.states.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
# be handled specially by lambda lifting. Local temp vars (if needed)
# 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.stateLoopLabel = newSym(skLabel, getIdent(":stateLoop"), fn, fn.info)
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info)
let n = n.toStmtList
discard ctx.newState(n, nil)

View File

@@ -26,7 +26,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
import
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.
bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
@@ -56,21 +56,21 @@ const
x
AdvancedUsage = slurp"../doc/advopt.txt".replace("//", "") % FeatureDesc
proc getCommandLineDesc(): string =
result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name, CompileDate]) &
proc getCommandLineDesc(conf: ConfigRef): string =
result = (HelpMessage % [VersionAsString, platform.OS[conf.target.hostOS].name,
CPU[conf.target.hostCPU].name, CompileDate]) &
Usage
proc helpOnError(conf: ConfigRef; pass: TCmdLinePass) =
if pass == passCmd1:
msgWriteln(conf, getCommandLineDesc(), {msgStdout})
msgWriteln(conf, getCommandLineDesc(conf), {msgStdout})
msgQuit(0)
proc writeAdvancedUsage(conf: ConfigRef; pass: TCmdLinePass) =
if pass == passCmd1:
msgWriteln(conf, (HelpMessage % [VersionAsString,
platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name, CompileDate]) &
platform.OS[conf.target.hostOS].name,
CPU[conf.target.hostCPU].name, CompileDate]) &
AdvancedUsage,
{msgStdout})
msgQuit(0)
@@ -78,8 +78,8 @@ proc writeAdvancedUsage(conf: ConfigRef; pass: TCmdLinePass) =
proc writeFullhelp(conf: ConfigRef; pass: TCmdLinePass) =
if pass == passCmd1:
msgWriteln(conf, `%`(HelpMessage, [VersionAsString,
platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name, CompileDate]) &
platform.OS[conf.target.hostOS].name,
CPU[conf.target.hostCPU].name, CompileDate]) &
Usage & AdvancedUsage,
{msgStdout})
msgQuit(0)
@@ -87,8 +87,8 @@ proc writeFullhelp(conf: ConfigRef; pass: TCmdLinePass) =
proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) =
if pass == passCmd1:
msgWriteln(conf, `%`(HelpMessage, [VersionAsString,
platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name, CompileDate]),
platform.OS[conf.target.hostOS].name,
CPU[conf.target.hostCPU].name, CompileDate]),
{msgStdout})
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) =
if not helpWritten:
msgWriteln(conf, getCommandLineDesc(), {msgStdout})
msgWriteln(conf, getCommandLineDesc(conf), {msgStdout})
helpWritten = true
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)
else: invalidCmdLineOption(conf, pass, orig, info)
if state == wHint:
let x = findStr(configuration.HintsToStr, id)
let x = findStr(lineinfos.HintsToStr, id)
if x >= 0: n = TNoteKind(x + ord(hintMin))
else: localError(conf, info, "unknown hint: " & id)
else:
let x = findStr(configuration.WarningsToStr, id)
let x = findStr(lineinfos.WarningsToStr, id)
if x >= 0: n = TNoteKind(x + ord(warnMin))
else: localError(conf, info, "unknown warning: " & id)
case substr(arg, i).normalize
@@ -289,14 +289,14 @@ proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
else:
conf.projectPath / path
try:
result = pathSubs(conf, p, info.toFullPath().splitFile().dir)
result = pathSubs(conf, p, toFullPath(conf, info).splitFile().dir)
except ValueError:
localError(conf, info, "invalid path: " & p)
result = p
proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): string =
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:
path
else:
@@ -322,9 +322,9 @@ proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) =
let dirtyOriginalIdx = fileInfoIdx(conf, a[1])
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) =
var a = arg.split(',')
@@ -334,7 +334,7 @@ proc track(conf: ConfigRef; arg: string, info: TLineInfo) =
localError(conf, info, errInvalidNumber % a[1])
if parseUtils.parseInt(a[2], column) <= 0:
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) =
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;
conf: ConfigRef) =
var
theOS: TSystemOS
cpu: TSystemCPU
key, val: string
case switch.normalize
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)
of "cincludes":
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":
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":
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":
if conf != nil: conf.headerFile = arg
incl(conf.globalOptions, optGenIndex)
@@ -592,23 +590,26 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "os":
expectArg(conf, switch, arg, pass, info)
if pass in {passCmd1, passPP}:
theOS = platform.nameToOS(arg)
let theOS = platform.nameToOS(arg)
if theOS == osNone: localError(conf, info, "unknown OS: '$1'" % arg)
elif theOS != platform.hostOS:
setTarget(theOS, targetCPU)
elif theOS != conf.target.hostOS:
setTarget(conf.target, theOS, conf.target.targetCPU)
of "cpu":
expectArg(conf, switch, arg, pass, info)
if pass in {passCmd1, passPP}:
cpu = platform.nameToCPU(arg)
let cpu = platform.nameToCPU(arg)
if cpu == cpuNone: localError(conf, info, "unknown CPU: '$1'" % arg)
elif cpu != platform.hostCPU:
setTarget(targetOS, cpu)
elif cpu != conf.target.hostCPU:
setTarget(conf.target, conf.target.targetOS, cpu)
of "run", "r":
expectNoArg(conf, switch, arg, pass, info)
incl(conf.globalOptions, optRun)
of "verbosity":
expectArg(conf, switch, arg, pass, info)
conf.verbosity = parseInt(arg)
let verbosity = parseInt(arg)
if verbosity notin {0..3}:
localError(conf, info, "invalid verbosity level: '$1'" % arg)
conf.verbosity = verbosity
conf.notes = NotesVerbosity[conf.verbosity]
incl(conf.notes, conf.enableNotes)
excl(conf.notes, conf.disableNotes)
@@ -628,9 +629,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "help", "h":
expectNoArg(conf, switch, arg, pass, info)
helpOnError(conf, pass)
of "symbolfiles":
of "symbolfiles", "incremental":
case arg.normalize
of "on": conf.symbolFiles = enabledSf
of "on": conf.symbolFiles = v2Sf
of "off": conf.symbolFiles = disabledSf
of "writeonly": conf.symbolFiles = writeOnlySf
of "readonly": conf.symbolFiles = readOnlySf
@@ -719,6 +720,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
doAssert(conf != nil)
incl(conf.features, destructor)
defineSymbol(conf.symbols, "nimNewRuntime")
of "nep1":
processOnOffSwitchG(conf, {optCheckNep1}, arg, pass, info)
of "cppcompiletonamespace":
expectNoArg(conf, switch, arg, pass, info)
incl conf.globalOptions, optUseNimNamespace

View File

@@ -44,6 +44,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimcomputedgoto")
defineSymbol("nimunion")
defineSymbol("nimnewshared")
defineSymbol("nimNewTypedesc")
defineSymbol("nimrequiresnimframe")
defineSymbol("nimparsebiggestfloatmagic")
defineSymbol("nimalias")
@@ -70,3 +71,4 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimNoNil")
defineSymbol("nimNoZeroTerminator")
defineSymbol("nimNotNil")
defineSymbol("nimVmExportFixed")

View File

@@ -1,360 +1,6 @@
#
#
# The Nim Compiler
# (c) Copyright 2018 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Use the module 'lineinfos' instead!
## This module contains the rather excessive configuration object that
## needs to be passed around to everything so that the compiler becomes
## more useful as a library.
{.deprecated.}
import 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,
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",
,
]#
import lineinfos
export lineinfos

View File

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

View File

@@ -116,8 +116,8 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently
import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
strutils, options, dfa, lowerings, rodread, tables, modulegraphs,
configuration
strutils, options, dfa, lowerings, tables, modulegraphs,
lineinfos
const
InterestingSyms = {skVar, skResult, skLet}
@@ -132,10 +132,11 @@ type
destroys, topLevelVars: PNode
toDropBit: Table[int, PSym]
graph: ModuleGraph
emptyNode: PNode
proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
# 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
rawAddField c.tmpObj, f
result = rawDirectAccess(c.tmp, f)
@@ -243,17 +244,17 @@ proc genDestroy(c: Con; t: PType; dest: PNode): PNode =
genOp(t.destructor, "=destroy")
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 =
result = c.toDropBit.getOrDefault(s.id)
assert result != nil
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)
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
# generate:
# 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)
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)
let tempAsNode = newSymNode(temp)
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
vpart.sons[0] = tempAsNode
vpart.sons[1] = ast.emptyNode
vpart.sons[1] = c.emptyNode
vpart.sons[2] = n
add(v, vpart)
@@ -427,13 +428,14 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
echo "injecting into ", n
var c: Con
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.tmp.typ = c.tmpObj
c.destroys = newNodeI(nkStmtList, n.info)
c.topLevelVars = newNodeI(nkVarSection, n.info)
c.toDropBit = initTable[int, PSym]()
c.graph = g
c.emptyNode = newNodeI(nkEmpty, n.info)
let cfg = constructCfg(owner, n)
shallowCopy(c.g, cfg)
c.jumpTargets = initIntSet()

View File

@@ -23,7 +23,7 @@
## "A GraphFree Approach to DataFlow Analysis" by Markus Mohnen.
## 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
InstrKind* = enum
@@ -54,7 +54,7 @@ type
blocks: seq[TBlock]
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) =
# for debugging purposes
@@ -87,7 +87,8 @@ proc echoCfg*(c: ControlFlowGraph; start=0; last = -1) {.deprecated.} =
## echos the ControlFlowGraph for debugging purposes.
var buf = ""
codeListing(c, buf, start, last)
echo buf
when declared(echo):
echo buf
proc forkI(c: var Con; n: PNode): TPosition =
result = TPosition(c.code.len)

View File

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

View File

@@ -11,7 +11,7 @@
# semantic checking.
import
os, options, ast, astalgo, msgs, ropes, idents, passes, docgen
os, options, ast, astalgo, msgs, ropes, idents, passes, docgen, lineinfos
from modulegraphs import ModuleGraph
@@ -25,7 +25,7 @@ template closeImpl(body: untyped) {.dirty.} =
var g = PGen(p)
let useWarning = sfMainModule notin g.module.flags
#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:
body
try:
@@ -35,11 +35,11 @@ template closeImpl(body: untyped) {.dirty.} =
proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
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 =
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 =
result = n
@@ -51,11 +51,11 @@ proc processNodeJson(c: PPassContext, n: PNode): PNode =
var g = PGen(c)
generateJson(g.doc, n)
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var g: PGen
new(g)
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
g.doc = d
result = g

View File

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

View File

@@ -11,7 +11,7 @@
import
strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
rodread
lineinfos
type
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
if default.isNil or default.kind == nkEmpty:
localError(conf, n.info, errWrongNumberOfArguments)
addSon(result, ast.emptyNode)
addSon(result, newNodeI(nkEmpty, n.info))
else:
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
const evalTemplateLimit* = 1000
var evalTemplateCounter* = 0 # XXX remove this global
proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
when true:
@@ -140,8 +139,8 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
conf: ConfigRef; fromHlo=false): PNode =
inc(evalTemplateCounter)
if evalTemplateCounter > evalTemplateLimit:
inc(conf.evalTemplateCounter)
if conf.evalTemplateCounter > evalTemplateLimit:
globalError(conf, n.info, errTemplateInstantiationTooNested)
result = n
@@ -170,5 +169,5 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
evalTemplateAux(body.sons[i], args, ctx, result)
result.flags.incl nfFromTemplate
result = wrapInComesFrom(n.info, tmpl, result)
dec(evalTemplateCounter)
dec(conf.evalTemplateCounter)

View File

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

View File

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

View File

@@ -9,7 +9,8 @@
## 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) =
result[0] = ""
@@ -22,7 +23,7 @@ proc readOutput(p: Process): (string, int) =
result[1] = p.waitForExit
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:
let h = secureHash(cmd & "\t" & input & "\t" & cache)
let filename = options.toGeneratedFile(conf, "gorge_" & $h, "txt")

View File

@@ -10,7 +10,7 @@
## This module implements the 'implies' relation for guards.
import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
saturate, modulegraphs, options, configuration
saturate, modulegraphs, options, lineinfos
const
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)
if not inSet(n.sons[1], eAsNode): s.add eAsNode
result.sons[1] = s
elif t.kind notin {tyString, tySequence} and lengthOrd(t) < 1000:
result.sons[1] = complement(n.sons[1])
#elif t.kind notin {tyString, tySequence} and lengthOrd(t) < 1000:
# result.sons[1] = complement(n.sons[1])
else:
# not ({2, 3, 4}.contains(x)) x != 2 and x != 3 and x != 4
# XXX todo
@@ -208,14 +208,14 @@ proc zero(): PNode = nkIntLit.newIntNode(0)
proc one(): PNode = nkIntLit.newIntNode(1)
proc minusOne(): PNode = nkIntLit.newIntNode(-1)
proc lowBound*(x: PNode): PNode =
result = nkIntLit.newIntNode(firstOrd(x.typ))
proc lowBound*(conf: ConfigRef; x: PNode): PNode =
result = nkIntLit.newIntNode(firstOrd(conf, x.typ))
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)
result = if typ.kind == tyArray:
nkIntLit.newIntNode(lastOrd(typ))
nkIntLit.newIntNode(lastOrd(conf, typ))
elif typ.kind == tySequence and x.kind == nkSym and
x.sym.kind == skConst:
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}?
# --> 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:
if c.intVal - value.intVal < 1000:
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}
#
var value = newIntNode(c.kind, c.intVal)
let max = lastOrd(x.typ)
let max = lastOrd(nil, x.typ)
# don't iterate too often:
if max - value.intVal < 1000:
var i, pos, neg: int
@@ -532,8 +532,8 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication =
elif neg == i: result = impNo
proc compareSets(a, b: PNode): TImplication =
if equalSets(a, b): result = impYes
elif intersectSets(a, b).len == 0: result = impNo
if equalSets(nil, a, b): result = impYes
elif intersectSets(nil, a, b).len == 0: result = impNo
proc impliesIn(fact, loc, aSet: PNode): TImplication =
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
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
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
if sameTree(a, b): return impYes

View File

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

View File

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

View File

@@ -10,8 +10,8 @@
# This module implements the symbol importing mechanism.
import
intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups,
semdata, passes, renderer, modulepaths, sigmatch, configuration
intsets, strutils, os, ast, astalgo, msgs, options, idents, lookups,
semdata, passes, renderer, modulepaths, sigmatch, lineinfos
proc evalImport*(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}
result = initIntSet()
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)
proc importPureEnumField*(c: PContext; s: PSym) =
@@ -69,12 +69,13 @@ proc rawImportSymbol(c: PContext, s: PSym) =
if hasPattern(s): addPattern(c, s)
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)
if s == nil:
errorUndeclaredIdentifier(c, n.info, ident.s)
else:
if s.kind == skStub: loadStub(s)
when false:
if s.kind == skStub: loadStub(s)
if s.kind notin ExportableSymKinds:
internalError(c.config, n.info, "importSymbol: 2")
# 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,
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)
if f != InvalidFileIDX:
let L = c.graph.importStack.len
@@ -143,10 +144,10 @@ proc myImportModule(c: PContext, n: PNode): PSym =
var err = ""
for i in countup(recursion, L-1):
if i > recursion: err.add "\n"
err.add toFullPath(c.graph.importStack[i]) & " imports " &
toFullPath(c.graph.importStack[i+1])
err.add toFullPath(c.config, c.graph.importStack[i]) & " imports " &
toFullPath(c.config, c.graph.importStack[i+1])
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
c.graph.importStack.setLen(L)
# we cannot perform this check reliably because of
@@ -161,9 +162,10 @@ proc myImportModule(c: PContext, n: PNode): PSym =
else:
message(c.config, n.info, warnDeprecated, result.name.s)
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) =
let m = myImportModule(c, it)
proc impMod(c: PContext; it: PNode; importStmtResult: PNode) =
let m = myImportModule(c, it, importStmtResult)
if m != nil:
var emptySet: IntSet
# ``addDecl`` needs to be done before ``importAllSymbols``!
@@ -172,7 +174,8 @@ proc impMod(c: PContext; it: PNode) =
#importForwarded(c, m.ast, emptySet)
proc evalImport(c: PContext, n: PNode): PNode =
result = n
#result = n
result = newNodeI(nkImportStmt, n.info)
for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i]
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
for x in it[2]:
a.sons[2] = x
impMod(c, a)
impMod(c, a, result)
else:
impMod(c, it)
impMod(c, it, result)
proc evalFrom(c: PContext, n: PNode): PNode =
result = n
result = newNodeI(nkImportStmt, n.info)
checkMinSonsLen(n, 2, c.config)
var m = myImportModule(c, n.sons[0])
var m = myImportModule(c, n.sons[0], result)
if m != nil:
n.sons[0] = newSymNode(m)
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)
proc evalImportExcept*(c: PContext, n: PNode): PNode =
result = n
result = newNodeI(nkImportStmt, n.info)
checkMinSonsLen(n, 2, c.config)
var m = myImportModule(c, n.sons[0])
var m = myImportModule(c, n.sons[0], result)
if m != nil:
n.sons[0] = newSymNode(m)
addDecl(c, m, n.info) # add symbol to symbol table of module

196
compiler/incremental.nim Normal file
View File

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

View File

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

View File

@@ -25,7 +25,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
else:
s = nil
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]))
result = ("{kind: 2, len: $1, offset: 0, " &
"typ: null, name: null, sons: [$2]}") % [rope(length), s]
@@ -56,15 +56,15 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
else:
add(u, rope(getOrdValue(b.sons[j])))
of nkElse:
u = rope(lengthOrd(field.typ))
u = rope(lengthOrd(p.config, field.typ))
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]",
[u, genObjectFields(p, typ, lastSon(b))])
result = ("{kind: 3, offset: \"$1\", len: $3, " &
"typ: $2, name: $4, sons: [$5]}") % [
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")
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 =
var s: Rope = nil
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, " &
"typ: $2, name: \"Field$1\", sons: null}",
[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):
if (typ.n.sons[i].kind != nkSym): internalError(p.config, typ.n.info, "genEnumInfo")
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
addf(s, "\"$1\": {kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}",
[rope(field.position), name, makeJSString(extName)])

View File

@@ -11,7 +11,7 @@
import
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 """
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)
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)
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)
rawAddField(result, createStateField(g, owner))
proc getClosureIterResult*(iter: PSym): PSym =
proc getClosureIterResult*(g: ModuleGraph; iter: PSym): PSym =
if resultPos < iter.ast.len:
result = iter.ast.sons[resultPos].sym
else:
# 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]
incl(result.flags, sfUsed)
iter.ast.add newSymNode(result)
@@ -244,7 +244,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
var env: PNode
if owner.isIterator:
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)
else:
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 =
let envParam = getHiddenParam(g, owner)
let obj = envParam.typ.lastSon
addField(obj, s)
addField(obj, s, g.cache)
var access = newSymNode(envParam)
assert obj.kind == tyObject
@@ -278,7 +278,7 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
let s = n.sym
if illegalCapture(s):
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}:
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]])
@@ -325,7 +325,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
if refObj == fieldType:
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)
if upField != nil:
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 t = c.getEnvTypeForOwner(owner, info)
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)
cp.typ = t
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 = 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
else:
addField(obj, s)
addField(obj, s, c.graph.cache)
# but always return because the rest of the proc is only relevant when
# ow != owner:
return
@@ -428,7 +428,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id):
let obj = c.getEnvTypeForOwner(ow, n.info).lastSon
#getHiddenParam(owner).typ.lastSon
addField(obj, s)
addField(obj, s, c.graph.cache)
# create required upFields:
var w = owner.skipGenericOwner
if isInnerProc(w) or owner.isIterator:
@@ -485,14 +485,14 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let field = getFieldFromObj(obj, s)
if field != nil:
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
access = rawIndirectAccess(access, upField, n.info)
localError(g.config, n.info, "internal error: environment misses: " & s.name.s)
result = n
proc newEnvVar(owner: PSym; typ: PType): PNode =
var v = newSym(skVar, getIdent(envName), owner, owner.info)
proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType): PNode =
var v = newSym(skVar, getIdent(cache, envName), owner, owner.info)
incl(v.flags, sfShadowed)
v.typ = typ
result = newSymNode(v)
@@ -513,14 +513,14 @@ proc setupEnvVar(owner: PSym; d: DetectionPass;
let envVarType = d.ownerToType.getOrDefault(owner.id)
if envVarType.isNil:
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
proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode =
let p = getHiddenParam(g, owner)
result = p.newSymNode
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:
localError(g.config, owner.info, "could not find up reference for closure iter")
else:
@@ -549,7 +549,7 @@ proc rawClosureCreation(owner: PSym;
# add ``env.param = param``
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:
let up = getUpViaParam(d.graph, owner)
if up != nil and upField.typ == up.typ:
@@ -565,13 +565,13 @@ proc closureCreationForIter(iter: PNode;
d: DetectionPass; c: var LiftingPass): PNode =
result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ)
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)
v.typ = getHiddenParam(d.graph, iter.sym).typ
var vnode: PNode
if owner.isIterator:
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)
else:
vnode = v.newSymNode
@@ -580,7 +580,7 @@ proc closureCreationForIter(iter: PNode;
result.add(vs)
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:
let u = setupEnvVar(owner, d, c)
if u.typ == upField.typ:
@@ -607,81 +607,6 @@ proc getStateField*(g: ModuleGraph; owner: PSym): PSym =
proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
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;
c: var LiftingPass): PNode =
let s = n.sym
@@ -703,7 +628,7 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
if access.typ == wanted:
return makeClosure(d.graph, s, access, n.info)
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:
localError(d.graph.config, n.info, "internal error: no environment found")
return n
@@ -722,8 +647,6 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
let oldInContainer = c.inContainer
c.inContainer = 0
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:
s.ast.sons[bodyPos] = body
else:
@@ -766,11 +689,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
if n[1].kind == nkClosure: result = n[1]
else:
if owner.isIterator:
if oldIterTransf in d.graph.config.features and n.kind == nkYieldStmt:
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:
if nfLL in n.flags:
# special case 'when nimVm' due to bug #3636:
n.sons[1] = liftCapturedVars(n[1], owner, d, c)
return
@@ -811,7 +730,7 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNo
fn.typ.callConv = ccClosure
d.ownerToType[fn.id] = ptrType
detectCapturedVars(body, fn, d)
result = wrapIterBody(g, liftCapturedVars(body, fn, d, c), fn)
result = liftCapturedVars(body, fn, d, c)
fn.kind = oldKind
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)
if c.envvars.getOrDefault(fn.id) != nil:
result = newTree(nkStmtList, rawClosureCreation(fn, d, c), result)
if oldIterTransf in g.config.features:
result = wrapIterBody(g, result, fn)
else:
result = body
#if fn.name.s == "get2":
@@ -932,7 +848,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
body[i].sym.kind = skLet
addSon(vpart, body[i])
addSon(vpart, ast.emptyNode) # no explicit type
addSon(vpart, newNodeI(nkEmpty, body.info)) # no explicit type
if not env.isNil:
call.sons[0] = makeClosure(g, call.sons[0].sym, env.newSymNode, body.info)
addSon(vpart, call)
@@ -942,12 +858,12 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
var bs = newNodeI(nkBreakState, body.info)
bs.addSon(call.sons[0])
let ibs = newNode(nkIfStmt)
let elifBranch = newNode(nkElifBranch)
let ibs = newNodeI(nkIfStmt, body.info)
let elifBranch = newNodeI(nkElifBranch, body.info)
elifBranch.add(bs)
let br = newNode(nkBreakStmt)
br.add(emptyNode)
let br = newNodeI(nkBreakStmt, body.info)
br.add(g.emptyNode)
elifBranch.add(br)
ibs.add(elifBranch)

274
compiler/layouter.nim Normal file
View File

@@ -0,0 +1,274 @@
#
#
# The Nim Compiler
# (c) Copyright 2018 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Layouter for nimpretty.
import idents, lexer, lineinfos, llstream, options, msgs, strutils
from os import changeFileExt
const
MaxLineLen = 80
LineCommentColumn = 30
type
SplitKind = enum
splitComma, splitParLe, splitAnd, splitOr, splitIn, splitBinary
SemicolonKind = enum
detectSemicolonKind, useSemicolon, dontTouch
Emitter* = object
config: ConfigRef
fid: FileIndex
lastTok: TTokType
inquote: bool
semicolons: SemicolonKind
col, lastLineNumber, lineSpan, indentLevel, indWidth: int
nested: int
doIndentMore*: int
content: string
indentStack: seq[int]
fixedUntil: int # marks where we must not go in the content
altSplitPos: array[SplitKind, int] # alternative split positions
proc openEmitter*(em: var Emitter, cache: IdentCache;
config: ConfigRef, fileIdx: FileIndex) =
let fullPath = config.toFullPath(fileIdx)
em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead),
cache, config)
if em.indWidth == 0: em.indWidth = 2
em.config = config
em.fid = fileIdx
em.lastTok = tkInvalid
em.inquote = false
em.col = 0
em.content = newStringOfCap(16_000)
em.indentStack = newSeqOfCap[int](30)
em.indentStack.add 0
proc closeEmitter*(em: var Emitter) =
var f = llStreamOpen(em.config.outFile, fmWrite)
if f == nil:
rawMessage(em.config, errGenerated, "cannot open file: " & em.config.outFile)
f.llStreamWrite em.content
llStreamClose(f)
proc countNewlines(s: string): int =
result = 0
for i in 0..<s.len:
if s[i] == '\L': inc result
proc calcCol(em: var Emitter; s: string) =
var i = s.len-1
em.col = 0
while i >= 0 and s[i] != '\L':
dec i
inc em.col
template wr(x) =
em.content.add x
inc em.col, x.len
template goodCol(col): bool = col in 40..MaxLineLen
const
openPars = {tkParLe, tkParDotLe,
tkBracketLe, tkBracketLeColon, tkCurlyDotLe,
tkCurlyLe}
splitters = openPars + {tkComma, tkSemicolon}
oprSet = {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor}
template rememberSplit(kind) =
if goodCol(em.col):
em.altSplitPos[kind] = em.content.len
template moreIndent(em): int =
(if em.doIndentMore > 0: em.indWidth*2 else: em.indWidth)
proc softLinebreak(em: var Emitter, lit: string) =
# XXX Use an algorithm that is outlined here:
# https://llvm.org/devmtg/2013-04/jasper-slides.pdf
# +2 because we blindly assume a comma or ' &' might follow
if not em.inquote and em.col+lit.len+2 >= MaxLineLen:
if em.lastTok in splitters:
while em.content.len > 0 and em.content[em.content.high] == ' ':
setLen(em.content, em.content.len-1)
wr("\L")
em.col = 0
for i in 1..em.indentLevel+moreIndent(em): wr(" ")
else:
# search backwards for a good split position:
for a in em.altSplitPos:
if a > em.fixedUntil:
var spaces = 0
while a+spaces < em.content.len and em.content[a+spaces] == ' ':
inc spaces
if spaces > 0: delete(em.content, a, a+spaces-1)
let ws = "\L" & repeat(' ',em.indentLevel+moreIndent(em))
em.col = em.content.len - a
em.content.insert(ws, a)
break
proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
template endsInWhite(em): bool =
em.content.len == 0 or em.content[em.content.high] in {' ', '\L'}
template endsInAlpha(em): bool =
em.content.len > 0 and em.content[em.content.high] in SymChars+{'_'}
proc emitComment(em: var Emitter; tok: TToken) =
let lit = strip fileSection(em.config, em.fid, tok.commentOffsetA, tok.commentOffsetB)
em.lineSpan = countNewlines(lit)
if em.lineSpan > 0: calcCol(em, lit)
if not endsInWhite(em):
wr(" ")
if em.lineSpan == 0 and max(em.col, LineCommentColumn) + lit.len <= MaxLineLen:
for i in 1 .. LineCommentColumn - em.col: wr(" ")
wr lit
var preventComment = false
if tok.tokType == tkComment and tok.line == em.lastLineNumber and tok.indent >= 0:
# we have an inline comment so handle it before the indentation token:
emitComment(em, tok)
preventComment = true
em.fixedUntil = em.content.high
elif tok.indent >= 0:
if em.lastTok in (splitters + oprSet):
em.indentLevel = tok.indent
else:
if tok.indent > em.indentStack[^1]:
em.indentStack.add tok.indent
else:
# dedent?
while em.indentStack.len > 1 and em.indentStack[^1] > tok.indent:
discard em.indentStack.pop()
em.indentLevel = em.indentStack.high * em.indWidth
#[ we only correct the indentation if it is not in an expression context,
so that code like
const splitters = {tkComma, tkSemicolon, tkParLe, tkParDotLe,
tkBracketLe, tkBracketLeColon, tkCurlyDotLe,
tkCurlyLe}
is not touched.
]#
# remove trailing whitespace:
while em.content.len > 0 and em.content[em.content.high] == ' ':
setLen(em.content, em.content.len-1)
wr("\L")
for i in 2..tok.line - em.lastLineNumber: wr("\L")
em.col = 0
for i in 1..em.indentLevel:
wr(" ")
em.fixedUntil = em.content.high
case tok.tokType
of tokKeywordLow..tokKeywordHigh:
if endsInAlpha(em):
wr(" ")
elif not em.inquote and not endsInWhite(em) and
em.lastTok notin openPars:
#and tok.tokType in oprSet
wr(" ")
if not em.inquote:
wr(TokTypeToStr[tok.tokType])
case tok.tokType
of tkAnd: rememberSplit(splitAnd)
of tkOr: rememberSplit(splitOr)
of tkIn, tkNotin:
rememberSplit(splitIn)
wr(" ")
else: discard
else:
# keywords in backticks are not normalized:
wr(tok.ident.s)
of tkColon:
wr(TokTypeToStr[tok.tokType])
wr(" ")
of tkSemicolon, tkComma:
wr(TokTypeToStr[tok.tokType])
rememberSplit(splitComma)
wr(" ")
of tkParDotLe, tkParLe, tkBracketDotLe, tkBracketLe,
tkCurlyLe, tkCurlyDotLe, tkBracketLeColon:
if tok.strongSpaceA > 0 and not em.endsInWhite:
wr(" ")
wr(TokTypeToStr[tok.tokType])
rememberSplit(splitParLe)
of tkParRi,
tkBracketRi, tkCurlyRi,
tkBracketDotRi,
tkCurlyDotRi,
tkParDotRi,
tkColonColon, tkDot:
wr(TokTypeToStr[tok.tokType])
of tkEquals:
if not em.inquote and not em.endsInWhite: wr(" ")
wr(TokTypeToStr[tok.tokType])
if not em.inquote: wr(" ")
of tkOpr, tkDotDot:
if tok.strongSpaceA == 0 and tok.strongSpaceB == 0:
# if not surrounded by whitespace, don't produce any whitespace either:
wr(tok.ident.s)
else:
if not em.endsInWhite: wr(" ")
wr(tok.ident.s)
template isUnary(tok): bool =
tok.strongSpaceB == 0 and tok.strongSpaceA > 0
if not isUnary(tok):
wr(" ")
rememberSplit(splitBinary)
of tkAccent:
if not em.inquote and endsInAlpha(em): wr(" ")
wr(TokTypeToStr[tok.tokType])
em.inquote = not em.inquote
of tkComment:
if not preventComment:
emitComment(em, tok)
of tkIntLit..tkStrLit, tkRStrLit, tkTripleStrLit, tkGStrLit, tkGTripleStrLit, tkCharLit:
let lit = fileSection(em.config, em.fid, tok.offsetA, tok.offsetB)
softLinebreak(em, lit)
if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wr(" ")
em.lineSpan = countNewlines(lit)
if em.lineSpan > 0: calcCol(em, lit)
wr lit
of tkEof: discard
else:
let lit = if tok.ident != nil: tok.ident.s else: tok.literal
softLinebreak(em, lit)
if endsInAlpha(em): wr(" ")
wr lit
em.lastTok = tok.tokType
em.lastLineNumber = tok.line + em.lineSpan
em.lineSpan = 0
proc starWasExportMarker*(em: var Emitter) =
if em.content.endsWith(" * "):
setLen(em.content, em.content.len-3)
em.content.add("*")
dec em.col, 2
proc commaWasSemicolon*(em: var Emitter) =
if em.semicolons == detectSemicolonKind:
em.semicolons = if em.content.endsWith(", "): dontTouch else: useSemicolon
if em.semicolons == useSemicolon and em.content.endsWith(", "):
setLen(em.content, em.content.len-2)
em.content.add("; ")
proc curlyRiWasPragma*(em: var Emitter) =
if em.content.endsWith("}"):
setLen(em.content, em.content.len-1)
em.content.add(".}")

View File

@@ -17,7 +17,7 @@
import
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
wordrecg, configuration
wordrecg, lineinfos
const
MaxLineLength* = 80 # lines longer than this lead to a warning
@@ -273,10 +273,10 @@ template tokenBegin(tok, pos) {.dirty.} =
template tokenEnd(tok, pos) {.dirty.} =
when defined(nimsuggest):
let colB = getColNumber(L, pos)+1
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
if L.fileIdx == L.config.m.trackPos.fileIndex and L.config.m.trackPos.col in colA..colB and
L.lineNumber == L.config.m.trackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
L.cursor = CursorPosition.InToken
gTrackPos.col = colA.int16
L.config.m.trackPos.col = colA.int16
colA = 0
when defined(nimpretty):
tok.offsetB = L.offsetBase + pos
@@ -284,10 +284,10 @@ template tokenEnd(tok, pos) {.dirty.} =
template tokenEndIgnore(tok, pos) =
when defined(nimsuggest):
let colB = getColNumber(L, pos)
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
gTrackPos.fileIndex = trackPosInvalidFileIdx
gTrackPos.line = 0'u16
if L.fileIdx == L.config.m.trackPos.fileIndex and L.config.m.trackPos.col in colA..colB and
L.lineNumber == L.config.m.trackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
L.config.m.trackPos.fileIndex = trackPosInvalidFileIdx
L.config.m.trackPos.line = 0'u16
colA = 0
when defined(nimpretty):
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
# the cursor in a string literal or comment:
let colB = getColNumber(L, pos)
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
if L.fileIdx == L.config.m.trackPos.fileIndex and L.config.m.trackPos.col in colA..colB and
L.lineNumber == L.config.m.trackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
L.cursor = CursorPosition.BeforeToken
gTrackPos = L.previousToken
gTrackPosAttached = true
L.config.m.trackPos = L.previousToken
L.config.m.trackPosAttached = true
colA = 0
when defined(nimpretty):
tok.offsetB = L.offsetBase + pos
@@ -630,14 +630,14 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
if L.config.oldNewlines:
if tok.tokType == tkCharLit:
lexMessage(L, errGenerated, "\\n not allowed in character literal")
add(tok.literal, tnl)
add(tok.literal, L.config.target.tnl)
else:
add(tok.literal, '\L')
inc(L.bufpos)
of 'p', 'P':
if tok.tokType == tkCharLit:
lexMessage(L, errGenerated, "\\p not allowed in character literal")
add(tok.literal, tnl)
add(tok.literal, L.config.target.tnl)
inc(L.bufpos)
of 'r', 'R', 'c', 'C':
add(tok.literal, CR)
@@ -714,11 +714,6 @@ proc handleCRLF(L: var TLexer, pos: int): int =
if col > MaxLineLength:
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]
of CR:
registerLine()
@@ -872,7 +867,7 @@ proc getOperator(L: var TLexer, tok: var TToken) =
if buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
tok.strongSpaceB = -1
proc newlineFollows*(L: var TLexer): bool =
proc newlineFollows*(L: TLexer): bool =
var pos = L.bufpos
var buf = L.buf
while true:
@@ -954,6 +949,8 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
if isDoc or defined(nimpretty): tok.literal.add buf[pos]
inc(pos)
L.bufpos = pos
when defined(nimpretty):
tok.commentOffsetB = L.offsetBase + pos - 1
proc scanComment(L: var TLexer, tok: var TToken) =
var pos = L.bufpos
@@ -962,6 +959,9 @@ proc scanComment(L: var TLexer, tok: var TToken) =
# iNumber contains the number of '\n' in the token
tok.iNumber = 0
assert buf[pos+1] == '#'
when defined(nimpretty):
tok.commentOffsetA = L.offsetBase + pos - 1
if buf[pos+2] == '[':
skipMultiLineComment(L, tok, pos+3, true)
return
@@ -1001,6 +1001,8 @@ proc scanComment(L: var TLexer, tok: var TToken) =
tokenEndIgnore(tok, pos)
break
L.bufpos = pos
when defined(nimpretty):
tok.commentOffsetB = L.offsetBase + pos - 1
proc skip(L: var TLexer, tok: var TToken) =
var pos = L.bufpos
@@ -1021,6 +1023,9 @@ proc skip(L: var TLexer, tok: var TToken) =
inc(pos)
of CR, LF:
tokenEndPrevious(tok, pos)
when defined(nimpretty):
# we are not yet in a comment, so update the comment token's line information:
if not hasComment: inc tok.line
pos = handleCRLF(L, pos)
buf = L.buf
var indent = 0
@@ -1060,7 +1065,7 @@ proc skip(L: var TLexer, tok: var TToken) =
L.bufpos = pos
when defined(nimpretty):
if hasComment:
tok.commentOffsetB = L.offsetBase + pos
tok.commentOffsetB = L.offsetBase + pos - 1
tok.tokType = tkComment
if gIndentationWidth <= 0:
gIndentationWidth = tok.indent
@@ -1121,9 +1126,9 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
else:
tok.tokType = tkParLe
when defined(nimsuggest):
if L.fileIdx == gTrackPos.fileIndex and tok.col < gTrackPos.col and
tok.line == gTrackPos.line.int and L.config.ideCmd == ideCon:
gTrackPos.col = tok.col.int16
if L.fileIdx == L.config.m.trackPos.fileIndex and tok.col < L.config.m.trackPos.col and
tok.line == L.config.m.trackPos.line.int and L.config.ideCmd == ideCon:
L.config.m.trackPos.col = tok.col.int16
of ')':
tok.tokType = tkParRi
inc(L.bufpos)
@@ -1142,11 +1147,11 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
inc(L.bufpos)
of '.':
when defined(nimsuggest):
if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and
tok.line == gTrackPos.line.int and L.config.ideCmd == ideSug:
if L.fileIdx == L.config.m.trackPos.fileIndex and tok.col+1 == L.config.m.trackPos.col and
tok.line == L.config.m.trackPos.line.int and L.config.ideCmd == ideSug:
tok.tokType = tkDot
L.cursor = CursorPosition.InToken
gTrackPos.col = tok.col.int16
L.config.m.trackPos.col = tok.col.int16
inc(L.bufpos)
atTokenEnd()
return
@@ -1215,3 +1220,15 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
lexMessage(L, errGenerated, "invalid token: " & c & " (\\" & $(ord(c)) & ')')
inc(L.bufpos)
atTokenEnd()
proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef): int =
var lex: TLexer
var tok: TToken
initToken(tok)
openLexer(lex, fileIdx, inputstream, cache, config)
while true:
rawGetTok(lex, tok)
result = tok.indent
if result > 0 or tok.tokType == tkEof: break
closeLexer(lex)

View File

@@ -11,7 +11,7 @@
import
intsets, strutils, options, ast, astalgo, msgs,
idents, renderer, types, lowerings
idents, renderer, types, lowerings, lineinfos
from pragmas import getPragmaVal
from wordrecg import wLiftLocals
@@ -20,13 +20,14 @@ type
Ctx = object
partialParam: PSym
objType: PType
cache: IdentCache
proc interestingVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar, skResult} and
sfGlobal notin s.flags
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)
deref.typ = c.objType
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:
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)
if liftDest == nil: return n
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:
localError(conf, liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest)
return n
var c = Ctx(partialParam: partialParam, objType: objType)
var c = Ctx(partialParam: partialParam, objType: objType, cache: cache)
let w = newTree(nkStmtList, n)
liftLocals(w, 0, c)
result = w[0]

267
compiler/lineinfos.nim Normal file
View File

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

View File

@@ -13,9 +13,18 @@
import
strutils, os, intsets, strtabs
import ".." / [options, ast, astalgo, msgs, semdata, ropes, idents,
configuration]
import prettybase
import options, ast, astalgo, msgs, semdata, ropes, idents,
lineinfos
const
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
proc identLen*(line: string, start: int): int =
while start+result < line.len and line[start+result] in Letters:
inc result
when false:
import prettybase
type
StyleCheck* {.pure.} = enum None, Warn, Auto
@@ -27,19 +36,19 @@ var
proc overwriteFiles*(conf: ConfigRef) =
let doStrip = options.getConfigVar(conf, "pretty.strip").normalize == "on"
for i in 0 .. high(gSourceFiles):
if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and
(not gOnlyMainfile or gSourceFiles[i].fileIdx == conf.projectMainIdx.FileIndex):
let newFile = if gOverWrite: gSourceFiles[i].fullpath
else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
for i in 0 .. high(conf.m.fileInfos):
if conf.m.fileInfos[i].dirty and
(not gOnlyMainfile or FileIndex(i) == conf.projectMainIdx):
let newFile = if gOverWrite: conf.m.fileInfos[i].fullpath
else: conf.m.fileInfos[i].fullpath.changeFileExt(".pretty.nim")
try:
var f = open(newFile, fmWrite)
for line in gSourceFiles[i].lines:
for line in conf.m.fileInfos[i].lines:
if doStrip:
f.write line.strip(leading = false, trailing = true)
else:
f.write line
f.write(gSourceFiles[i].newline)
f.write(conf.m.fileInfos[i], "\L")
f.close
except IOError:
rawMessage(conf, errGenerated, "cannot open file: " & newFile)
@@ -93,14 +102,16 @@ proc beautifyName(s: string, k: TSymKind): string =
result.add s[i]
inc i
proc replaceInFile(info: TLineInfo; newName: string) =
loadFile(info)
proc differ*(line: string, a, b: int, x: string): bool =
let y = line[a..b]
result = cmpIgnoreStyle(y, x) == 0 and y != x
let line = gSourceFiles[info.fileIndex.int].lines[info.line.int-1]
proc replaceInFile(conf: ConfigRef; info: TLineInfo; newName: string) =
let line = conf.m.fileInfos[info.fileIndex.int].lines[info.line.int-1]
var first = min(info.col.int, line.len)
if first < 0: return
#inc first, skipIgnoreCase(line, "proc ", first)
while first > 0 and line[first-1] in prettybase.Letters: dec first
while first > 0 and line[first-1] in Letters: dec first
if first < 0: return
if line[first] == '`': inc first
@@ -108,46 +119,56 @@ proc replaceInFile(info: TLineInfo; newName: string) =
if differ(line, first, last, newName):
# last-first+1 != newName.len or
var x = line.substr(0, first-1) & newName & line.substr(last+1)
system.shallowCopy(gSourceFiles[info.fileIndex.int].lines[info.line.int-1], x)
gSourceFiles[info.fileIndex.int].dirty = true
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int].lines[info.line.int-1], x)
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)
if s != beau:
if gStyleCheck == StyleCheck.Auto:
sym.name = getIdent(beau)
replaceInFile(info, beau)
sym.name = getIdent(cache, beau)
replaceInFile(conf, info, beau)
else:
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:
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 Letters: return
if k in {skType, skGenericParam} and sfAnon in s.flags: return
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) =
proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
# operators stay as they are:
if k in {skResult, skTemp} or s.name.s[0] notin Letters: return
if k in {skType, skGenericParam} and sfAnon in s.flags: return
let beau = beautifyName(s.name.s, k)
if s.name.s != beau:
message(conf, info, hintName, beau)
template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
if optCheckNep1 in conf.globalOptions:
nep1CheckDefImpl(conf, info, s, k)
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) =
styleCheckDef(info, s, s.kind)
template styleCheckDef*(s: PSym) =
styleCheckDef(s.info, s, s.kind)
template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym) =
styleCheckDef(conf, info, s, s.kind)
template styleCheckDef*(conf: ConfigRef; s: PSym) =
styleCheckDef(conf, s.info, s, s.kind)
proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
proc styleCheckUseImpl(conf: ConfigRef; info: TLineInfo; s: PSym) =
if info.fileIndex.int < 0: return
# we simply convert it to what it looks like in the definition
# for consistency
# operators stay as they are:
if s.kind in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters:
if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters:
return
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
let newName = s.name.s
replaceInFile(info, newName)
replaceInFile(conf, info, newName)
#if newName == "File": writeStackTrace()
template styleCheckUse*(info: TLineInfo; s: PSym) =

View File

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

View File

@@ -12,7 +12,8 @@
const
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
proc newDeref*(n: PNode): PNode {.inline.} =
@@ -30,8 +31,8 @@ proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode =
proc addVar*(father, v: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart.sons[0] = v
vpart.sons[1] = ast.emptyNode
vpart.sons[2] = ast.emptyNode
vpart.sons[1] = newNodeI(nkEmpty, v.info)
vpart.sons[2] = vpart[1]
addSon(father, vpart)
proc newAsgnStmt(le, ri: PNode): PNode =
@@ -49,7 +50,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let value = n.lastSon
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)
incl(temp.flags, sfFromGeneric)
@@ -73,17 +74,17 @@ proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
proc newTryFinally*(body, final: PNode): PNode =
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
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)
let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
vpart.sons[0] = tempAsNode
vpart.sons[1] = ast.emptyNode
vpart.sons[1] = newNodeI(nkEmpty, value.info)
vpart.sons[2] = value
addSon(v, vpart)
result.add(v)
@@ -92,10 +93,10 @@ proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode =
for i in 0 .. lhs.len-1:
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)
# 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
incl(temp.flags, sfFromGeneric)
@@ -104,7 +105,7 @@ proc lowerSwap*(n: PNode; owner: PSym): PNode =
var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart.sons[0] = tempAsNode
vpart.sons[1] = ast.emptyNode
vpart.sons[1] = newNodeI(nkEmpty, v.info)
vpart.sons[2] = n[1]
addSon(v, vpart)
@@ -120,7 +121,7 @@ proc createObj*(g: ModuleGraph; owner: PSym, info: TLineInfo; final=true): PType
else:
rawAddSon(result, getCompilerProc(g, "RootObj").typ)
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)
incl s.flags, sfAnon
s.typ = result
@@ -171,10 +172,10 @@ proc lookupInRecord(n: PNode, id: int): PSym =
if n.sym.id == -abs(id): result = n.sym
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.
# 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)
field.id = -s.id
let t = skipIntLit(s.typ)
@@ -183,10 +184,10 @@ proc addField*(obj: PType; s: PSym) =
field.position = sonsLen(obj.n)
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)
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)
field.id = -s.id
let t = skipIntLit(s.typ)
@@ -227,13 +228,13 @@ proc indirectAccess*(a: PNode, b: int, info: TLineInfo): PNode =
addSon(result, newSymNode(field))
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
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.skipTypes(abstractInst).sons[0]
var t = deref.typ.skipTypes(abstractInst)
var field: PSym
let bb = getIdent(b)
let bb = getIdent(cache, b)
while true:
assert t.kind == tyObject
field = getSymFromList(t.n, bb)
@@ -335,17 +336,29 @@ proc typeNeedsNoDeepCopy(t: PType): bool =
if t.kind in {tyVar, tyLent, tySequence}: t = t.lastSon
result = not containsGarbageCollectedRef(t)
proc hoistExpr*(varSection, expr: PNode, name: PIdent, owner: PSym): PSym =
result = newSym(skLet, name, owner, varSection.info, owner.options)
result.flags.incl sfHoisted
result.typ = expr.typ
var varDef = newNodeI(nkIdentDefs, varSection.info, 3)
varDef.sons[0] = newSymNode(result)
varDef.sons[1] = newNodeI(nkEmpty, varSection.info)
varDef.sons[2] = expr
varSection.add varDef
proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType;
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)
result.typ = typ
incl(result.flags, sfFromGeneric)
var vpart = newNodeI(nkIdentDefs, varSection.info, 3)
vpart.sons[0] = newSymNode(result)
vpart.sons[1] = ast.emptyNode
vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode
vpart.sons[1] = newNodeI(nkEmpty, varSection.info)
vpart.sons[2] = if varInit.isNil: v else: vpart[1]
varSection.add vpart
if varInit != nil:
if useShallowCopy and typeNeedsNoDeepCopy(typ):
@@ -410,7 +423,7 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
# generate:
# fv.owner = threadParam
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)
if spawnKind == srByVar:
@@ -421,12 +434,12 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
localError(g.config, f.info, "cannot create a flowVar of type: " &
typeToString(fv.typ.sons[1]))
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:
let incRefCall = newNodeI(nkCall, fv.info, 2)
incRefCall.sons[0] = newSymNode(getSysMagic(g, fv.info, "GCref", mGCref))
incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode,
"data", fv.info)
"data", fv.info, g.cache)
body.add incRefCall
if barrier == nil:
# by now 'fv' is shared and thus might have beeen overwritten! we need
@@ -438,7 +451,7 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
body.add callCodegenProc(g, "barrierLeave", threadLocalBarrier.newSymNode)
var params = newNodeI(nkFormalParams, f.info)
params.add emptyNode
params.add newNodeI(nkEmpty, f.info)
params.add threadParam.newSymNode
params.add argsParam.newSymNode
@@ -452,14 +465,18 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
t.n.add argsParam.newSymNode
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)
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
proc createCastExpr(argsParam: PSym; objType: PType): PNode =
result = newNodeI(nkCast, argsParam.info)
result.add emptyNode
result.add newNodeI(nkEmpty, argsParam.info)
result.add newSymNode(argsParam)
result.typ = newType(tyPtr, objType.owner)
result.typ.rawAddSon(objType)
@@ -468,7 +485,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchOb
castExpr, call,
varSection, varInit, result: PNode) =
let formals = n[0].typ.n
let tmpName = getIdent(genPrefix)
let tmpName = getIdent(g.cache, genPrefix)
for i in 1 ..< n.len:
# we pick n's type here, which hopefully is 'tyArray' and not
# 'tyOpenArray':
@@ -481,7 +498,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchOb
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options)
field.typ = argType
objType.addField(field)
objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
let temp = addLocalVar(g, varSection, varInit, objType.owner, argType,
@@ -511,7 +528,7 @@ proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
proc genHigh*(g: ModuleGraph; n: PNode): PNode =
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:
result = newNodeI(nkCall, n.info, 2)
result.typ = getSysType(g, n.info, tyInt)
@@ -522,7 +539,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
castExpr, call,
varSection, varInit, result: PNode) =
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
# for correctness: These are called 'threadLocal' here.
for i in 1 ..< n.len:
@@ -543,17 +560,17 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
slice.sons[0].typ = getSysType(g, n.info, tyInt) # fake type
var fieldB = newSym(skField, tmpName, objType.owner, n.info, g.config.options)
fieldB.typ = getSysType(g, n.info, tyInt)
objType.addField(fieldB)
objType.addField(fieldB, g.cache)
if getMagic(n) == mSlice:
let a = genAddrOf(n[1])
field.typ = a.typ
objType.addField(field)
objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
var fieldA = newSym(skField, tmpName, objType.owner, n.info, g.config.options)
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, fieldB), n[3])
@@ -564,7 +581,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
else:
let a = genAddrOf(n)
field.typ = a.typ
objType.addField(field)
objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n))
@@ -577,12 +594,12 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
useShallowCopy=true)
slice.sons[3] = threadLocal.newSymNode
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:
# it is more efficient to pass a pointer instead:
let a = genAddrOf(n)
field.typ = a.typ
objType.addField(field)
objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
let threadLocal = addLocalVar(g, varSection,nil, objType.owner, field.typ,
indirectAccess(castExpr, field, n.info),
@@ -591,7 +608,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
else:
# boring case
field.typ = argType
objType.addField(field)
objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
let threadLocal = addLocalVar(g, varSection, varInit,
objType.owner, field.typ,
@@ -623,8 +640,8 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P
if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}:
localError(g.config, n.info, "'spawn' takes a GC safe call expression")
var
threadParam = newSym(skParam, getIdent"thread", owner, n.info, g.config.options)
argsParam = newSym(skParam, getIdent"args", owner, n.info, g.config.options)
threadParam = newSym(skParam, getIdent(g.cache, "thread"), owner, n.info, g.config.options)
argsParam = newSym(skParam, getIdent(g.cache, "args"), owner, n.info, g.config.options)
block:
let ptrType = getSysType(g, n.info, tyPointer)
threadParam.typ = ptrType
@@ -635,7 +652,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P
incl(objType.flags, tfFinal)
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:
scratchObj.typ = objType
incl(scratchObj.flags, sfFromGeneric)
@@ -653,9 +670,9 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P
skFunc, skMethod, skConverter}):
# for indirect calls we pass the function pointer in the scratchObj
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
objType.addField(field)
objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0])
fn = indirectAccess(castExpr, field, n.info)
elif fn.kind == nkSym and fn.sym.kind == skIterator:
@@ -677,17 +694,17 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P
if barrier != nil:
let typ = newType(tyPtr, owner)
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
objType.addField(field)
objType.addField(field, g.cache)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier)
barrierAsExpr = indirectAccess(castExpr, field, n.info)
var fvField, fvAsExpr: PNode = nil
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
objType.addField(field)
objType.addField(field, g.cache)
fvField = newDotExpr(scratchObj, field)
fvAsExpr = indirectAccess(castExpr, field, n.info)
# create flowVar:
@@ -696,10 +713,10 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P
result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField)
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.rawAddSon(retType)
objType.addField(field)
objType.addField(field, g.cache)
fvAsExpr = indirectAccess(castExpr, field, n.info)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest))

View File

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

View File

@@ -10,8 +10,8 @@
# Built-in types and compilerprocs are registered here.
import
ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread,
modulegraphs
ast, astalgo, hashes, msgs, platform, nversion, times, idents,
modulegraphs, lineinfos
export createMagic
@@ -26,30 +26,18 @@ proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType =
result.align = size.int16
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:
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)
if result.kind == skStub: loadStub(result)
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 =
var ti: TIdentIter
let id = getIdent(name)
let id = getIdent(g.cache, name)
var r = initIdentIter(ti, g.systemModule.tab, id)
while r != nil:
if r.kind == skStub: loadStub(r)
if r.magic == m:
# prefer the tyInt variant:
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 tyCString: result = sysTypeFromName("cstring")
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)
g.sysTypes[kind] = result
if result.kind != kind:
@@ -139,7 +127,7 @@ proc addSonSkipIntLit*(father, son: PType) =
proc setIntLitType*(g: ModuleGraph; result: PNode) =
let i = result.intVal
case platform.intSize
case g.config.target.intSize
of 8: result.typ = getIntLitType(g, result)
of 4:
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")
proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
let ident = getIdent(name)
let ident = getIdent(g.cache, name)
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) =
strTableAdd(g.compilerprocs, s)
@@ -187,9 +168,9 @@ proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) =
strTableAdd(g.exposed, s)
else:
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 =
strTableGet(g.exposed, getIdent(name))
strTableGet(g.exposed, getIdent(g.cache, name))
proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)

View File

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

View File

@@ -9,7 +9,7 @@
## This module implements the module graph data structure. The module graph
## 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
## right. If module E is being edited, we need autocompletion (and type
@@ -25,7 +25,8 @@
## - 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
ModuleGraph* = ref object
@@ -40,16 +41,27 @@ type
# module dependencies.
backend*: RootRef # minor hack so that a backend can extend this easily
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.}
usageSym*: PSym # for nimsuggest
owners*: seq[PSym]
methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]]
methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]] # needs serialization!
systemModule*: PSym
sysTypes*: array[TTypeKind, PType]
compilerprocs*: TStrTable
exposed*: TStrTable
intTypeCache*: array[-5..64, PType]
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.}
@@ -59,26 +71,31 @@ proc stopCompile*(g: ModuleGraph): bool {.inline.} =
result = doStopCompile != nil and doStopCompile()
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
proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
result = ModuleGraph()
initStrTable(result.packageSyms)
result.deps = initIntSet()
result.modules = @[]
result.importStack = @[]
result.inclToMod = initTable[FileIndex, FileIndex]()
if config.isNil:
result.config = newConfigRef()
else:
result.config = config
result.config = config
result.cache = cache
result.owners = @[]
result.methods = @[]
initStrTable(result.compilerprocs)
initStrTable(result.exposed)
result.opNot = createMagic(result, "not", mNot)
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) =
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) =
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:
deps.incl m.position.dependsOn(dep.int)
# 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
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)
proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex =

View File

@@ -7,7 +7,7 @@
# 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
@@ -120,7 +120,7 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
case n.kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
try:
result = pathSubs(conf, n.strVal, n.info.toFullPath().splitFile().dir)
result = pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir)
except ValueError:
localError(conf, n.info, "invalid path: " & n.strVal)
result = n.strVal
@@ -131,7 +131,7 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
of nkInfix:
let n0 = n[0]
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:
n.kind = nkImportAs
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 =
# This returns the full canonical path for a given module import
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 doLocalError:
let m = if modulename.len > 0: modulename else: $n

View File

@@ -10,9 +10,9 @@
## Implements the module handling, including the caching of modules.
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,
configuration
lineinfos
proc resetSystemArtifacts*(g: ModuleGraph) =
magicsys.resetSysTypes(g)
@@ -23,8 +23,8 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
new(result)
result.id = -1 # for better error checking
result.kind = skModule
let filename = fileIdx.toFullPath
result.name = getIdent(splitFile(filename).name)
let filename = toFullPath(graph.config, fileIdx)
result.name = getIdent(graph.cache, splitFile(filename).name)
if not isNimIdentifier(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
pck = getPackageName(graph.config, filename)
pck2 = if pck.len > 0: pck else: "unknown"
pack = getIdent(pck2)
pack = getIdent(graph.cache, pck2)
var packSym = graph.packageSyms.strTableGet(pack)
if packSym == nil:
packSym = newSym(skPackage, getIdent(pck2), nil, result.info)
packSym = newSym(skPackage, getIdent(graph.cache, pck2), nil, result.info)
initStrTable(packSym.tab)
graph.packageSyms.strTableAdd(packSym)
result.owner = packSym
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
incl(result.flags, sfUsed)
@@ -50,95 +52,76 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
strTableAdd(result.tab, result) # a module knows itself
let existing = strTableGet(packSym.tab, result.name)
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:
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)
if result == nil:
#growCache gMemCacheData, fileIdx
#gMemCacheData[fileIdx].needsRecompile = Probing
result = newModule(graph, fileIdx)
var rd: PRodReader
result.flags = result.flags + flags
if sfMainModule in result.flags:
gMainPackageId = result.owner.id
graph.config.mainPackageId = result.owner.id
when false:
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))
result.id = getModuleId(graph, fileIdx, toFullPath(graph.config, fileIdx))
discard processModule(graph, result,
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
if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil)
elif graph.isDirty(result):
result.flags.excl sfDirty
# reset module fields:
initStrTable(result.tab)
result.ast = nil
discard processModule(graph, result,
if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil,
nil, cache)
if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil)
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;
cache: IdentCache): PSym {.procvar.} =
proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym {.procvar.} =
# this is called by the semantic checking phase
assert graph.config != nil
result = compileModule(graph, fileIdx, cache, {})
result = compileModule(graph, fileIdx, {})
graph.addDep(s, fileIdx)
#if sfSystemModule in result.flags:
# localError(result.info, errAttemptToRedefine, result.name.s)
# restore the notes for outer module:
graph.config.notes =
if s.owner.id == gMainPackageId: graph.config.mainPackageNotes
else: graph.config.foreignPackageNotes
if s.owner.id == graph.config.mainPackageId: graph.config.mainPackageNotes
else: graph.config.foreignPackageNotes
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
cache: IdentCache): PNode {.procvar.} =
result = syntaxes.parseFile(fileIdx, cache, graph.config)
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode {.procvar.} =
result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
graph.addDep(s, 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:
systemFileIdx = fileInfoIdx(graph.config, graph.config.libpath / "system.nim")
discard graph.compileModule(systemFileIdx, cache, {sfSystemModule})
connectCallbacks(graph)
graph.config.m.systemFileIdx = fileInfoIdx(graph.config, graph.config.libpath / "system.nim")
discard graph.compileModule(graph.config.m.systemFileIdx, {sfSystemModule})
proc wantMainModule*(conf: ConfigRef) =
if conf.projectFull.len == 0:
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
passes.gImportModule = importModule
proc compileProject*(graph: ModuleGraph; cache: IdentCache;
projectFileIdx = InvalidFileIDX) =
proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIDX) =
connectCallbacks(graph)
let conf = graph.config
wantMainModule(conf)
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
if projectFile == systemFileIdx:
discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule})
discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule})
else:
graph.compileSystemModule(cache)
discard graph.compileModule(projectFile, cache, {sfMainModule})
graph.compileSystemModule()
discard graph.compileModule(projectFile, {sfMainModule})
proc makeModule*(graph: ModuleGraph; filename: string): PSym =
result = graph.newModule(fileInfoIdx(graph.config, filename))

View File

@@ -9,83 +9,28 @@
import
options, strutils, os, tables, ropes, platform, terminal, macros,
configuration
lineinfos
#type
# 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 =
proc toCChar*(c: char; result: var string) =
case c
of '\0'..'\x1F', '\x7F'..'\xFF': result = '\\' & toOctal(c)
of '\'', '\"', '\\', '?': result = '\\' & c
else: result = $(c)
of '\0'..'\x1F', '\x7F'..'\xFF':
result.add '\\'
result.add toOctal(c)
of '\'', '\"', '\\', '?':
result.add '\\'
result.add c
else:
result.add c
proc makeCString*(s: string): Rope =
const
MaxLineLength = 64
const MaxLineLength = 64
result = nil
var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
add(res, "\"")
for i in countup(0, len(s) - 1):
if (i + 1) mod MaxLineLength == 0:
add(res, '\"')
add(res, tnl)
add(res, '\"')
add(res, toCChar(s[i]))
add(res, "\"\L\"")
toCChar(s[i], res)
add(res, '\"')
add(result, rope(res))
@@ -110,8 +55,8 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
result.fullContent = ""
when defined(nimpretty):
proc fileSection*(fid: FileIndex; a, b: int): string =
substr(fileInfos[fid.int].fullContent, a, b)
proc fileSection*(conf: ConfigRef; fid: FileIndex; a, b: int): string =
substr(conf.m.fileInfos[fid.int].fullContent, a, b)
proc fileInfoKnown*(conf: ConfigRef; filename: string): bool =
var
@@ -120,7 +65,7 @@ proc fileInfoKnown*(conf: ConfigRef; filename: string): bool =
canon = canonicalizePath(conf, filename)
except:
canon = filename
result = filenameToIndexTbl.hasKey(canon)
result = conf.m.filenameToIndexTbl.hasKey(canon)
proc fileInfoIdx*(conf: ConfigRef; filename: string; isKnownFile: var bool): FileIndex =
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
pseudoPath = true
if filenameToIndexTbl.hasKey(canon):
result = filenameToIndexTbl[canon]
if conf.m.filenameToIndexTbl.hasKey(canon):
result = conf.m.filenameToIndexTbl[canon]
else:
isKnownFile = false
result = fileInfos.len.FileIndex
fileInfos.add(newFileInfo(canon, if pseudoPath: filename
else: shortenDir(conf, canon)))
filenameToIndexTbl[canon] = result
result = conf.m.fileInfos.len.FileIndex
conf.m.fileInfos.add(newFileInfo(canon, if pseudoPath: filename
else: shortenDir(conf, canon)))
conf.m.filenameToIndexTbl[canon] = result
proc fileInfoIdx*(conf: ConfigRef; filename: string): FileIndex =
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.} =
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.} =
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 =
var totalLen = 0
@@ -192,13 +112,13 @@ proc concat(strings: openarray[string]): string =
result = newStringOfCap totalLen
for s in strings: result.add s
proc suggestWriteln*(s: string) =
if eStdOut in errorOutputs:
if isNil(writelnHook):
proc suggestWriteln*(conf: ConfigRef; s: string) =
if eStdOut in conf.m.errorOutputs:
if isNil(conf.writelnHook):
writeLine(stdout, s)
flushFile(stdout)
else:
writelnHook(s)
conf.writelnHook(s)
proc msgQuit*(x: int8) = quit x
proc msgQuit*(x: string) = quit x
@@ -219,61 +139,61 @@ const
HintTitle = "Hint: "
HintColor = fgGreen
proc getInfoContextLen*(): int = return msgContext.len
proc setInfoContextLen*(L: int) = setLen(msgContext, L)
proc getInfoContextLen*(conf: ConfigRef): int = return conf.m.msgContext.len
proc setInfoContextLen*(conf: ConfigRef; L: int) = setLen(conf.m.msgContext, L)
proc pushInfoContext*(info: TLineInfo) =
msgContext.add(info)
proc pushInfoContext*(conf: ConfigRef; info: TLineInfo) =
conf.m.msgContext.add(info)
proc popInfoContext*() =
setLen(msgContext, len(msgContext) - 1)
proc popInfoContext*(conf: ConfigRef) =
setLen(conf.m.msgContext, len(conf.m.msgContext) - 1)
proc getInfoContext*(index: int): TLineInfo =
let L = msgContext.len
proc getInfoContext*(conf: ConfigRef; index: int): TLineInfo =
let L = conf.m.msgContext.len
let i = if index < 0: L + index else: index
if i >=% L: result = unknownLineInfo()
else: result = msgContext[i]
else: result = conf.m.msgContext[i]
template toFilename*(fileIdx: FileIndex): string =
(if fileIdx.int32 < 0: "???" else: fileInfos[fileIdx.int32].projPath)
template toFilename*(conf: ConfigRef; fileIdx: FileIndex): string =
(if fileIdx.int32 < 0 or conf == nil: "???" else: conf.m.fileInfos[fileIdx.int32].projPath)
proc toFullPath*(fileIdx: FileIndex): string =
if fileIdx.int32 < 0: result = "???"
else: result = fileInfos[fileIdx.int32].fullPath
proc toFullPath*(conf: ConfigRef; fileIdx: FileIndex): string =
if fileIdx.int32 < 0 or conf == nil: result = "???"
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
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
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
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:
result = "???"
elif not fileInfos[fileIdx.int32].dirtyFile.isNil:
result = fileInfos[fileIdx.int32].dirtyFile
elif not conf.m.fileInfos[fileIdx.int32].dirtyFile.isNil:
result = conf.m.fileInfos[fileIdx.int32].dirtyFile
else:
result = fileInfos[fileIdx.int32].fullPath
result = conf.m.fileInfos[fileIdx.int32].fullPath
template toFilename*(info: TLineInfo): string =
info.fileIndex.toFilename
template toFilename*(conf: ConfigRef; info: TLineInfo): string =
toFilename(conf, info.fileIndex)
template toFullPath*(info: TLineInfo): string =
info.fileIndex.toFullPath
template toFullPath*(conf: ConfigRef; info: TLineInfo): string =
toFullPath(conf, info.fileIndex)
proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
if info.fileIndex.int32 < 0:
result = "???"
elif optListFullPaths in conf.globalOptions:
result = fileInfos[info.fileIndex.int32].fullPath
result = conf.m.fileInfos[info.fileIndex.int32].fullPath
else:
result = fileInfos[info.fileIndex.int32].projPath
result = conf.m.fileInfos[info.fileIndex.int32].projPath
proc toLinenumber*(info: TLineInfo): int {.inline.} =
result = int info.line
@@ -281,23 +201,19 @@ proc toLinenumber*(info: TLineInfo): int {.inline.} =
proc toColumn*(info: TLineInfo): int {.inline.} =
result = info.col
proc toFileLine*(info: TLineInfo): string {.inline.} =
result = info.toFilename & ":" & $info.line
proc toFileLine*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
result = toFilename(conf, info) & ":" & $info.line
proc toFileLineCol*(info: TLineInfo): string {.inline.} =
result = info.toFilename & "(" & $info.line & ", " & $info.col & ")"
proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
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
result = filename in info.toFilename
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.
result = filename in toFilename(conf, info)
type
MsgFlag* = enum ## flags altering msgWriteln behavior
@@ -315,14 +231,14 @@ proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) =
## support.
#if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
if not isNil(writelnHook) and msgSkipHook notin flags:
writelnHook(s)
if not isNil(conf.writelnHook) and msgSkipHook notin flags:
conf.writelnHook(s)
elif optStdout in conf.globalOptions or msgStdout in flags:
if eStdOut in errorOutputs:
if eStdOut in conf.m.errorOutputs:
writeLine(stdout, s)
flushFile(stdout)
else:
if eStdErr in errorOutputs:
if eStdErr in conf.m.errorOutputs:
writeLine(stderr, s)
# On Windows stderr is fully-buffered when piped, regardless of C std.
when defined(windows):
@@ -353,17 +269,17 @@ macro callStyledWriteLineStderr(args: varargs[typed]): untyped =
result.add(arg)
template callWritelnHook(args: varargs[string, `$`]) =
writelnHook concat(args)
conf.writelnHook concat(args)
template styledMsgWriteln*(args: varargs[typed]) =
if not isNil(writelnHook):
if not isNil(conf.writelnHook):
callIgnoringStyle(callWritelnHook, nil, args)
elif optStdout in conf.globalOptions:
if eStdOut in errorOutputs:
if eStdOut in conf.m.errorOutputs:
callIgnoringStyle(writeLine, stdout, args)
flushFile(stdout)
else:
if eStdErr in errorOutputs:
if eStdErr in conf.m.errorOutputs:
if optUseColors in conf.globalOptions:
callStyledWriteLineStderr(args)
else:
@@ -394,7 +310,7 @@ proc log*(s: string) {.procvar.} =
proc quit(conf: ConfigRef; msg: TMsgKind) =
if defined(debug) or msg == errInternal or hintStackTrace in conf.notes:
if stackTraceAvailable() and isNil(writelnHook):
if stackTraceAvailable() and isNil(conf.writelnHook):
writeStackTrace()
else:
styledMsgWriteln(fgRed, "No stack traceback available\n" &
@@ -425,19 +341,19 @@ proc exactEquals*(a, b: TLineInfo): bool =
proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) =
const instantiationFrom = "template/generic instantiation from here"
var info = lastinfo
for i in countup(0, len(msgContext) - 1):
if msgContext[i] != lastinfo and msgContext[i] != info:
if structuredErrorHook != nil:
structuredErrorHook(msgContext[i], instantiationFrom,
Severity.Error)
for i in 0 ..< len(conf.m.msgContext):
if conf.m.msgContext[i] != lastinfo and conf.m.msgContext[i] != info:
if conf.structuredErrorHook != nil:
conf.structuredErrorHook(conf, conf.m.msgContext[i], instantiationFrom,
Severity.Error)
else:
styledMsgWriteln(styleBright,
PosFormat % [toMsgFilename(conf, msgContext[i]),
coordToStr(msgContext[i].line.int),
coordToStr(msgContext[i].col+1)],
PosFormat % [toMsgFilename(conf, conf.m.msgContext[i]),
coordToStr(conf.m.msgContext[i].line.int),
coordToStr(conf.m.msgContext[i].col+1)],
resetStyle,
instantiationFrom)
info = msgContext[i]
info = conf.m.msgContext[i]
proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool =
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)
let s = msgKindToString(msg) % args
if structuredErrorHook != nil:
structuredErrorHook(unknownLineInfo(), s & (if kind != nil: KindFormat % kind else: ""), sev)
if conf.structuredErrorHook != nil:
conf.structuredErrorHook(conf, unknownLineInfo(),
s & (if kind != nil: KindFormat % kind else: ""), sev)
if not ignoreMsgBecauseOfIdeTools(conf, msg):
if kind != nil:
@@ -491,6 +408,24 @@ proc resetAttributes*(conf: ConfigRef) =
if {optUseColors, optStdout} * conf.globalOptions == {optUseColors}:
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) =
const indent = " "
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
# in the same file and line are produced:
#ignoreMsg = lastError == info and eh != doAbort
lastError = info
conf.m.lastError = info
of warnMin..warnMax:
sev = Severity.Warning
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)
if not ignoreMsg:
if structuredErrorHook != nil:
structuredErrorHook(info, s & (if kind != nil: KindFormat % kind else: ""), sev)
if conf.structuredErrorHook != nil:
conf.structuredErrorHook(conf, info, s & (if kind != nil: KindFormat % kind else: ""), sev)
if not ignoreMsgBecauseOfIdeTools(conf, msg):
if kind != nil:
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 = "") =
# this fixes bug #7080 so that it is at least obvious 'fatal'
# was executed.
errorOutputs = {eStdOut, eStdErr}
conf.m.errorOutputs = {eStdOut, eStdErr}
liMessage(conf, info, msg, arg, doAbort)
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)
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)
liMessage(conf, info, errInternal, errMsg, doAbort)
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())
rawMessage(conf, errInternal, errMsg)
@@ -600,44 +535,19 @@ template assertNotNil*(conf: ConfigRef; e): untyped =
template internalAssert*(conf: ConfigRef, e: bool) =
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 =
assert i.fileIndex.int32 >= 0
if optExcessiveStackTrace in conf.globalOptions:
result = fileInfos[i.fileIndex.int32].quotedFullName
result = conf.m.fileInfos[i.fileIndex.int32].quotedFullName
else:
result = 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)
result = conf.m.fileInfos[i.fileIndex.int32].quotedName
proc listWarnings*(conf: ConfigRef) =
msgWriteln(conf, "Warnings:")
for warn in warnMin..warnMax:
msgWriteln(conf, " [$1] $2" % [
if warn in conf.notes: "x" else: " ",
configuration.WarningsToStr[ord(warn) - ord(warnMin)]
lineinfos.WarningsToStr[ord(warn) - ord(warnMin)]
])
proc listHints*(conf: ConfigRef) =
@@ -645,5 +555,5 @@ proc listHints*(conf: ConfigRef) =
for hint in hintMin..hintMax:
msgWriteln(conf, " [$1] $2" % [
if hint in conf.notes: "x" else: " ",
configuration.HintsToStr[ord(hint) - ord(hintMin)]
lineinfos.HintsToStr[ord(hint) - ord(hintMin)]
])

View File

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

View File

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

View File

@@ -20,8 +20,8 @@ when defined(i386) and defined(windows) and defined(vcc):
import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, osproc, platform, main, parseopt, service,
nodejs, scriptconfig, idents, modulegraphs, configuration
extccomp, strutils, os, osproc, platform, main, parseopt,
nodejs, scriptconfig, idents, modulegraphs, lineinfos
when hasTinyCBackend:
import tccgen
@@ -37,6 +37,25 @@ proc prependCurDir(f: string): string =
else:
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) =
condsyms.initDefines(conf.symbols)
if paramCount() == 0:
@@ -60,7 +79,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
conf.projectName = p.name
else:
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")
if fileExists(scriptFile):
runNimScript(cache, scriptFile, freshDefines=false, conf)
@@ -75,7 +94,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
processCmdLine(passCmd2, "", conf)
if conf.command == "":
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())
#echo(GC_getStatistics())
if conf.errorCounter == 0:

View File

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

View File

@@ -11,7 +11,7 @@
import
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
options, idents, wordrecg, strtabs, configuration
options, idents, wordrecg, strtabs, lineinfos
# ---------------- configuration file parser -----------------------------
# 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) =
setDefaultLibpath(conf)
var configFiles = newSeq[string]()
template readConfigFile(path: string) =
@@ -264,7 +264,3 @@ proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
for filename in configFiles:
rawMessage(conf, hintConf, filename)
proc loadConfigs*(cfg: string; conf: ConfigRef) =
# for backwards compatibility only.
loadConfigs(cfg, newIdentCache(), conf)

View File

@@ -1,7 +1,7 @@
#
#
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2018 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -9,27 +9,112 @@
## exposes the Nim VM to clients.
import
ast, modules, passes, passaux, condsyms,
options, nimconf, sem, semdata, llstream, vm, modulegraphs, idents
ast, astalgo, modules, passes, condsyms,
options, sem, semdata, llstream, vm, vmdef,
modulegraphs, idents, os
proc execute*(program: string) =
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
initDefines()
loadConfigs(DefaultConfig)
type
Interpreter* = ref object ## Use Nim as an interpreter with this object
mainModule: PSym
graph: ModuleGraph
scriptName: string
initDefines()
defineSymbol("nimrodvm")
defineSymbol("nimscript")
when hasFFI: defineSymbol("nimffi")
registerPass(verbosePass)
registerPass(semPass)
registerPass(evalPass)
iterator exportedSymbols*(i: Interpreter): PSym =
assert i != nil
assert i.mainModule != nil, "no main module selected"
var it: TTabIter
var s = initTabIter(it, i.mainModule.tab)
while s != nil:
yield s
s = nextIter(it, i.mainModule.tab)
searchPaths.add options.libpath
var graph = newModuleGraph()
proc selectUniqueSymbol*(i: Interpreter; name: string;
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 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)
compileSystemModule(graph,cache)
processModule(graph,m, llStreamOpen(program), nil, cache)
var vm = newCtx(m, cache, graph)
vm.mode = emRepl
vm.features = flags
graph.vm = vm
graph.compileSystemModule()
result = Interpreter(mainModule: m, graph: graph, scriptName: scriptName)
proc destroyInterpreter*(i: Interpreter) =
## destructor.
discard "currently nothing to do."

View File

@@ -11,7 +11,7 @@
import strutils, os, parseopt
import compiler/[options, commands, modules, sem,
passes, passaux, nimfix/pretty,
passes, passaux, linter,
msgs, nimconf,
extccomp, condsyms,
modulegraphs, idents]

View File

@@ -7,64 +7,13 @@
# distribution, for details about the copyright.
#
import strutils, lexbase, streams
import ".." / [ast, msgs, idents]
import strutils except Letters
import lexbase, streams
import ".." / [ast, msgs, lineinfos, idents, options, linter]
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
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
proc identLen*(line: string, start: int): int =
while start+result < line.len and line[start+result] in Letters:
inc result
proc differ*(line: string, a, b: int, x: string): bool =
let y = line[a..b]
result = cmpIgnoreStyle(y, x) == 0 and y != x
proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
loadFile(info)
let line = gSourceFiles[info.fileIndex.int32].lines[info.line.int-1]
proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PIdent) =
let line = sourceLine(conf, info)
var first = min(info.col.int, line.len)
if first < 0: return
#inc first, skipIgnoreCase(line, "proc ", first)
@@ -75,20 +24,18 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
let last = first+identLen(line, first)-1
if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
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)
gSourceFiles[info.fileIndex.int32].dirty = true
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
conf.m.fileInfos[info.fileIndex.int32].dirty = true
#if newSym.s == "File": writeStackTrace()
proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
replaceDeprecated(info, oldSym.name, newSym.name)
proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PSym) =
replaceDeprecated(conf, info, oldSym.name, newSym.name)
proc replaceComment*(info: TLineInfo) =
loadFile(info)
let line = gSourceFiles[info.fileIndex.int32].lines[info.line.int-1]
proc replaceComment*(conf: ConfigRef; info: TLineInfo) =
let line = sourceLine(conf, info)
var first = info.col.int
if line[first] != '#': inc first
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)
gSourceFiles[info.fileIndex.int32].dirty = true
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
conf.m.fileInfos[info.fileIndex.int32].dirty = true

View File

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

View File

@@ -15,6 +15,6 @@ const
VersionAsString* = system.NimVersion
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
## declare this.

View File

@@ -8,7 +8,8 @@
#
import
os, strutils, strtabs, osproc, sets, configuration, platform
os, strutils, strtabs, osproc, sets, lineinfos, platform,
prefixmatches
from terminal import isatty
@@ -53,7 +54,7 @@ type # please make sure we have under 32 options
optGenScript, # generate a script file to compile the *.c files
optGenMapping, # generate a mapping file
optRun, # run the compiled project
optCaasEnabled # compiler-as-a-service is running
optCheckNep1, # check that the names adhere to NEP-1
optSkipConfigFile, # skip the general config file
optSkipProjConfigFile, # skip the project's config file
optSkipUserConfigFile, # skip the users's config file
@@ -73,6 +74,7 @@ type # please make sure we have under 32 options
optNoCppExceptions # use C exception handling even with CPP
optExcessiveStackTrace # fully qualified module filenames
optWholeProject # for 'doc2': output any dependency
optMixedMode # true if some module triggered C++ codegen
optListFullPaths
optNoNimblePath
optDynlibOverrideAll
@@ -116,26 +118,65 @@ type
callOperator,
parallel,
destructor,
notnil,
oldIterTransf
notnil
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
options*: TOptions
globalOptions*: TGlobalOptions
options*: TOptions # (+)
globalOptions*: TGlobalOptions # (+)
m*: MsgConfig
evalTemplateCounter*: int
evalMacroCounter*: int
exitcode*: int8
cmd*: TCommands # the command
selectedGC*: TGCMode # the selected GC
selectedGC*: TGCMode # the selected GC (+)
verbosity*: int # how verbose the compiler is
numberOfProcessors*: int # number of processors
evalExpr*: string # expression for idetools --eval
lastCmdTime*: float # when caas is enabled, we measure each command
symbolFiles*: SymbolFilesOption
cppDefines*: HashSet[string]
cppDefines*: HashSet[string] # (*)
headerFile*: string
features*: set[Feature]
arguments*: string ## the arguments to be passed to the program that
@@ -143,11 +184,13 @@ type
helpWritten*: bool
ideCmd*: IdeCmd
oldNewlines*: bool
cCompiler*: TSystemCC
enableNotes*: TNoteKinds
disableNotes*: TNoteKinds
foreignPackageNotes*: TNoteKinds
notes*: TNoteKinds
mainPackageNotes*: TNoteKinds
mainPackageId*: int
errorCounter*: int
hintCounter*: int
warnCounter*: int
@@ -165,7 +208,7 @@ type
projectPath*: string # holds a path like /home/alice/projects/nim/compiler/
projectFull*: string # projectPath/projectName
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)
commandArgs*: seq[string] # any arguments after the main command
keepComments*: bool # whether the parser needs to keep comments
@@ -174,6 +217,33 @@ type
docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \
# 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
@@ -196,9 +266,11 @@ template newPackageCache*(): untyped =
proc newConfigRef*(): ConfigRef =
result = ConfigRef(
selectedGC: gcRefc,
cCompiler: ccGcc,
verbosity: 1,
options: DefaultOptions,
globalOptions: DefaultGlobalOptions,
m: initMsgConfig(),
evalExpr: "",
cppDefines: initSet[string](),
headerFile: "", features: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic,
@@ -216,15 +288,28 @@ proc newConfigRef*(): ConfigRef =
projectPath: "", # holds a path like /home/alice/projects/nim/compiler/
projectFull: "", # projectPath/projectName
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)
commandArgs: @[], # any arguments after the main command
keepComments: true, # whether the parser needs to keep comments
implicitImports: @[], # modules that are to be implicitly imported
implicitIncludes: @[], # modules that are to be implicitly included
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
if terminal.isatty(stderr):
incl(result.globalOptions, optUseColors)
@@ -246,39 +331,39 @@ proc cppDefine*(c: ConfigRef; define: string) =
proc isDefined*(conf: ConfigRef; symbol: string): bool =
if conf.symbols.hasKey(symbol):
result = conf.symbols[symbol] != "false"
elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0:
elif cmpIgnoreStyle(symbol, CPU[conf.target.targetCPU].name) == 0:
result = true
elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0:
elif cmpIgnoreStyle(symbol, platform.OS[conf.target.targetOS].name) == 0:
result = true
else:
case symbol.normalize
of "x86": result = targetCPU == cpuI386
of "itanium": result = targetCPU == cpuIa64
of "x8664": result = targetCPU == cpuAmd64
of "x86": result = conf.target.targetCPU == cpuI386
of "itanium": result = conf.target.targetCPU == cpuIa64
of "x8664": result = conf.target.targetCPU == cpuAmd64
of "posix", "unix":
result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
result = conf.target.targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
osQnx, osAtari, osAix,
osHaiku, osVxWorks, osSolaris, osNetbsd,
osFreebsd, osOpenbsd, osDragonfly, osMacosx,
osAndroid}
of "linux":
result = targetOS in {osLinux, osAndroid}
result = conf.target.targetOS in {osLinux, osAndroid}
of "bsd":
result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly}
result = conf.target.targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly}
of "emulatedthreadvars":
result = platform.OS[targetOS].props.contains(ospLacksThreadVars)
of "msdos": result = targetOS == osDos
of "mswindows", "win32": result = targetOS == osWindows
of "macintosh": result = targetOS in {osMacos, osMacosx}
of "sunos": result = targetOS == osSolaris
of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian
of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian
of "cpu8": result = CPU[targetCPU].bit == 8
of "cpu16": result = CPU[targetCPU].bit == 16
of "cpu32": result = CPU[targetCPU].bit == 32
of "cpu64": result = CPU[targetCPU].bit == 64
result = platform.OS[conf.target.targetOS].props.contains(ospLacksThreadVars)
of "msdos": result = conf.target.targetOS == osDos
of "mswindows", "win32": result = conf.target.targetOS == osWindows
of "macintosh": result = conf.target.targetOS in {osMacos, osMacosx}
of "sunos": result = conf.target.targetOS == osSolaris
of "littleendian": result = CPU[conf.target.targetCPU].endian == platform.littleEndian
of "bigendian": result = CPU[conf.target.targetCPU].endian == platform.bigEndian
of "cpu8": result = CPU[conf.target.targetCPU].bit == 8
of "cpu16": result = CPU[conf.target.targetCPU].bit == 16
of "cpu32": result = CPU[conf.target.targetCPU].bit == 32
of "cpu64": result = CPU[conf.target.targetCPU].bit == 64
of "nimrawsetjmp":
result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd,
result = conf.target.targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd,
osDragonfly, osMacosx}
else: discard
@@ -286,8 +371,7 @@ proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc,
proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
template compilationCachePresent*(conf: ConfigRef): untyped =
conf.symbolFiles in {enabledSf, writeOnlySf}
# {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
conf.symbolFiles in {v2Sf, writeOnlySf}
template optPreserveOrigSource*(conf: ConfigRef): untyped =
optEmbedOrigSrc in conf.globalOptions
@@ -432,8 +516,10 @@ proc completeGeneratedFilePath*(conf: ConfigRef; f: string, createSubDir: bool =
result = joinPath(subdir, tail)
#echo "completeGeneratedFilePath(", f, ") = ", result
proc rawFindFile(conf: ConfigRef; f: string): string =
proc rawFindFile(conf: ConfigRef; f: string; suppressStdlib: bool): string =
for it in conf.searchPaths:
if suppressStdlib and it.startsWith(conf.libpath):
continue
result = joinPath(it, f)
if existsFile(result):
return canonicalizePath(conf, result)
@@ -457,13 +543,13 @@ template patchModule(conf: ConfigRef) {.dirty.} =
let ov = conf.moduleOverrides[key]
if ov.len > 0: result = ov
proc findFile*(conf: ConfigRef; f: string): string {.procvar.} =
proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): string {.procvar.} =
if f.isAbsolute:
result = if f.existsFile: f else: ""
else:
result = rawFindFile(conf, f)
result = rawFindFile(conf, f, suppressStdlib)
if result.len == 0:
result = rawFindFile(conf, f.toLowerAscii)
result = rawFindFile(conf, f.toLowerAscii, suppressStdlib)
if result.len == 0:
result = rawFindFile2(conf, f)
if result.len == 0:
@@ -472,21 +558,15 @@ proc findFile*(conf: ConfigRef; f: string): string {.procvar.} =
proc findModule*(conf: ConfigRef; modulename, currentModule: string): string =
# returns path to module
when defined(nimfix):
# '.nimfix' modules are preferred over '.nim' modules so that specialized
# versions can be kept for 'nimfix'.
block:
let m = addFileExt(modulename, "nimfix")
let currentPath = currentModule.splitFile.dir
result = currentPath / m
if not existsFile(result):
result = findFile(conf, m)
if existsFile(result): return result
const pkgPrefix = "pkg/"
let m = addFileExt(modulename, NimExt)
let currentPath = currentModule.splitFile.dir
result = currentPath / m
if not existsFile(result):
result = findFile(conf, m)
if m.startsWith(pkgPrefix):
result = findFile(conf, m.substr(pkgPrefix.len), suppressStdlib = true)
else:
let currentPath = currentModule.splitFile.dir
result = currentPath / m
if not existsFile(result):
result = findFile(conf, m)
patchModule(conf)
proc findProjectNimFile*(conf: ConfigRef; pkg: string): string =

View File

@@ -27,7 +27,10 @@ when isMainModule:
outp.close
import
llstream, lexer, idents, strutils, ast, astalgo, msgs, options, configuration
llstream, lexer, idents, strutils, ast, astalgo, msgs, options, lineinfos
when defined(nimpretty2):
import layouter
type
TParser* = object # A TParser object represents a file that
@@ -40,10 +43,16 @@ type
tok*: TToken # The current token
inPragma*: int # Pragma level
inSemiStmtList*: int
emptyNode: PNode
when defined(nimpretty2):
em: Emitter
SymbolMode = enum
smNormal, smAllowNil, smAfterDot
TPrimaryMode = enum
pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix
proc parseAll*(p: var TParser): PNode
proc closeParser*(p: var TParser)
proc parseTopLevelStmt*(p: var TParser): PNode
@@ -75,6 +84,9 @@ proc parsePragma(p: var TParser): PNode
proc postExprBlocks(p: var TParser, x: PNode): PNode
proc parseExprStmt(p: var TParser): PNode
proc parseBlock(p: var TParser): PNode
proc primary(p: var TParser, mode: TPrimaryMode): PNode
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode
# implementation
proc getTok(p: var TParser) =
@@ -82,6 +94,11 @@ proc getTok(p: var TParser) =
## `tok` member.
rawGetTok(p.lex, p.tok)
p.hasProgress = true
when defined(nimpretty2):
emitTok(p.em, p.lex, p.tok)
while p.tok.tokType == tkComment:
rawGetTok(p.lex, p.tok)
emitTok(p.em, p.lex, p.tok)
proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
cache: IdentCache; config: ConfigRef;
@@ -90,9 +107,12 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
##
initToken(p.tok)
openLexer(p.lex, fileIdx, inputStream, cache, config)
when defined(nimpretty2):
openEmitter(p.em, cache, config, fileIdx)
getTok(p) # read the first token
p.firstTok = true
p.strongSpaces = strongSpaces
p.emptyNode = newNode(nkEmpty)
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
cache: IdentCache; config: ConfigRef;
@@ -102,6 +122,8 @@ proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
proc closeParser(p: var TParser) =
## Close a parser, freeing up its resources.
closeLexer(p.lex)
when defined(nimpretty2):
closeEmitter(p.em)
proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
## Produce and emit the parser message `arg` to output.
@@ -131,7 +153,7 @@ proc rawSkipComment(p: var TParser, node: PNode) =
if node.comment == nil: node.comment = ""
when defined(nimpretty):
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:
add node.comment, p.tok.literal
else:
@@ -316,6 +338,8 @@ proc colcom(p: var TParser, n: PNode) =
eat(p, tkColon)
skipComment(p, n)
const tkBuiltInMagics = {tkType, tkStatic, tkAddr}
proc parseSymbol(p: var TParser, mode = smNormal): PNode =
#| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
#| | IDENT | KEYW
@@ -324,7 +348,7 @@ proc parseSymbol(p: var TParser, mode = smNormal): PNode =
result = newIdentNodeP(p.tok.ident, p)
getTok(p)
of tokKeywordLow..tokKeywordHigh:
if p.tok.tokType == tkAddr or p.tok.tokType == tkType or mode == smAfterDot:
if p.tok.tokType in tkBuiltInMagics or mode == smAfterDot:
# for backwards compatibility these 2 are always valid:
result = newIdentNodeP(p.tok.ident, p)
getTok(p)
@@ -333,7 +357,7 @@ proc parseSymbol(p: var TParser, mode = smNormal): PNode =
getTok(p)
else:
parMessage(p, errIdentifierExpected, p.tok)
result = ast.emptyNode
result = p.emptyNode
of tkAccent:
result = newNodeP(nkAccQuoted, p)
getTok(p)
@@ -364,7 +388,7 @@ proc parseSymbol(p: var TParser, mode = smNormal): PNode =
# But: this really sucks for idetools and keywords, so we don't do it
# if it is a keyword:
#if not isKeyword(p.tok.tokType): getTok(p)
result = ast.emptyNode
result = p.emptyNode
proc colonOrEquals(p: var TParser, a: PNode): PNode =
if p.tok.tokType == tkColon:
@@ -392,6 +416,8 @@ proc exprColonEqExpr(p: var TParser): PNode =
proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
#| exprList = expr ^+ comma
when defined(nimpretty2):
inc p.em.doIndentMore
getTok(p)
optInd(p, result)
# progress guaranteed
@@ -401,6 +427,8 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, a)
when defined(nimpretty2):
dec p.em.doIndentMore
proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
@@ -509,9 +537,6 @@ proc parseGStrLit(p: var TParser, a: PNode): PNode =
else:
result = a
type
TPrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix
proc complexOrSimpleStmt(p: var TParser): PNode
proc simpleExpr(p: var TParser, mode = pmNormal): PNode
@@ -609,7 +634,7 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
#| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
#| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
case p.tok.tokType
of tkSymbol, tkType, tkAddr:
of tkSymbol, tkBuiltInMagics:
result = newIdentNodeP(p.tok.ident, p)
getTok(p)
result = parseGStrLit(p, result)
@@ -703,7 +728,7 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
else:
parMessage(p, errExprExpected, p.tok)
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,
kind: TNodeKind, endTok: TTokType): PNode =
@@ -725,7 +750,12 @@ proc commandParam(p: var TParser, isFirstParam: var bool): PNode =
addSon(result, parseExpr(p))
isFirstParam = false
proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
const
tkTypeClasses = {tkRef, tkPtr, tkVar, tkStatic, tkType,
tkEnum, tkTuple, tkObject, tkProc}
proc primarySuffix(p: var TParser, r: PNode,
baseIndent: int, mode: TPrimaryMode): PNode =
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
#| | doBlocks
#| | '.' optInd symbol generalizedLit?
@@ -742,7 +772,14 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
case p.tok.tokType
of tkParLe:
# progress guaranteed
somePar()
if p.tok.strongSpaceA > 0:
# inside type sections, expressions such as `ref (int, bar)`
# are parsed as a nkCommand with a single tuple argument (nkPar)
if mode == pmTypeDef:
result = newNodeP(nkCommand, p)
result.addSon r
result.addSon primary(p, pmNormal)
break
result = namedParams(p, result, nkCall, tkParRi)
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
result.kind = nkObjConstr
@@ -758,8 +795,13 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
# progress guaranteed
somePar()
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType,
tkOpr, tkDotDot:
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast,
tkOpr, tkDotDot, tkTypeClasses - {tkRef, tkPtr}:
# XXX: In type sections we allow the free application of the
# command syntax, with the exception of expressions such as
# `foo ref` or `foo ptr`. Unfortunately, these two are also
# used as infix operators for the memory regions feature and
# the current parsing rules don't play well here.
if p.inPragma == 0 and (isUnary(p) or p.tok.tokType notin {tkOpr, tkDotDot}):
# actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
# solution, but pragmas.nim can't handle that
@@ -784,9 +826,6 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
else:
break
proc primary(p: var TParser, mode: TPrimaryMode): PNode
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode
proc parseOperators(p: var TParser, headNode: PNode,
limit: int, mode: TPrimaryMode): PNode =
result = headNode
@@ -821,7 +860,11 @@ proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
result = parseOperators(p, result, limit, mode)
proc simpleExpr(p: var TParser, mode = pmNormal): PNode =
when defined(nimpretty2):
inc p.em.doIndentMore
result = simpleExprAux(p, -1, mode)
when defined(nimpretty2):
dec p.em.doIndentMore
proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
#| condExpr = expr colcom expr optInd
@@ -896,8 +939,12 @@ proc parsePragma(p: var TParser): PNode =
getTok(p)
skipComment(p, a)
optPar(p)
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
else: parMessage(p, "expected '.}'")
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}:
when defined(nimpretty2):
if p.tok.tokType == tkCurlyRi: curlyRiWasPragma(p.em)
getTok(p)
else:
parMessage(p, "expected '.}'")
dec p.inPragma
proc identVis(p: var TParser; allowDot=false): PNode =
@@ -905,6 +952,8 @@ proc identVis(p: var TParser; allowDot=false): PNode =
#| identVisDot = symbol '.' optInd symbol opr?
var a = parseSymbol(p)
if p.tok.tokType == tkOpr:
when defined(nimpretty2):
starWasExportMarker(p.em)
result = newNodeP(nkPostfix, p)
addSon(result, newIdentNodeP(p.tok.ident, p))
addSon(result, a)
@@ -982,6 +1031,8 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
var a = parseIdentColonEquals(p, {})
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break
when defined(nimpretty2):
commaWasSemicolon(p.em)
getTok(p)
skipComment(p, a)
optPar(p)
@@ -1015,7 +1066,9 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
#| paramListColon = paramList? (':' optInd typeDesc)?
var a: PNode
result = newNodeP(nkFormalParams, p)
addSon(result, ast.emptyNode) # return type
addSon(result, p.emptyNode) # return type
when defined(nimpretty2):
inc p.em.doIndentMore
let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0
if hasParLe:
getTok(p)
@@ -1035,6 +1088,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
break
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break
when defined(nimpretty2):
commaWasSemicolon(p.em)
getTok(p)
skipComment(p, a)
optPar(p)
@@ -1047,13 +1102,15 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
result.sons[0] = parseTypeDesc(p)
elif not retColon and not hasParle:
# Mark as "not there" in order to mark for deprecation in the semantic pass:
result = ast.emptyNode
result = p.emptyNode
when defined(nimpretty2):
dec p.em.doIndentMore
proc optPragmas(p: var TParser): PNode =
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
result = parsePragma(p)
else:
result = ast.emptyNode
result = p.emptyNode
proc parseDoBlock(p: var TParser; info: TLineInfo): PNode =
#| doBlock = 'do' paramListArrow pragmas? colcom stmt
@@ -1062,7 +1119,9 @@ proc parseDoBlock(p: var TParser; info: TLineInfo): PNode =
colcom(p, result)
result = parseStmt(p)
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 =
#| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
@@ -1075,9 +1134,9 @@ proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode =
if p.tok.tokType == tkEquals and isExpr:
getTok(p)
skipComment(p, result)
result = newProcNode(kind, info, parseStmt(p),
params = params,
pragmas = pragmas)
result = newProcNode(kind, info, body = parseStmt(p),
params = params, name = p.emptyNode, pattern = p.emptyNode,
genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
else:
result = newNodeI(nkProcTy, info)
if hasSignature:
@@ -1087,9 +1146,9 @@ proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode =
proc isExprStart(p: TParser): bool =
case p.tok.tokType
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
tkProc, tkFunc, tkIterator, tkBind, tkAddr,
tkProc, tkFunc, tkIterator, tkBind, tkBuiltInMagics,
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
tkTuple, tkObject, tkType, tkWhen, tkCase, tkOut:
tkTuple, tkObject, tkWhen, tkCase, tkOut:
result = true
else: result = false
@@ -1150,7 +1209,6 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
#| | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
#| primary = typeKeyw typeDescK
#| / prefixOperator* identOrLiteral primarySuffix*
#| / 'static' primary
#| / 'bind' primary
if isOperator(p.tok):
let isSigil = isSigilLike(p.tok)
@@ -1163,7 +1221,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
#XXX prefix operators
let baseInd = p.lex.currLineIndent
addSon(result, primary(p, pmSkipSuffix))
result = primarySuffix(p, result, baseInd)
result = primarySuffix(p, result, baseInd, mode)
else:
addSon(result, primary(p, pmNormal))
return
@@ -1193,14 +1251,6 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
result = parseTypeClass(p)
else:
parMessage(p, "the 'concept' keyword is only valid in 'type' sections")
of tkStatic:
let info = parLineInfo(p)
getTokNoInd(p)
let next = primary(p, pmNormal)
if next.kind == nkBracket and next.sonsLen == 1:
result = newNode(nkStaticTy, info, @[next.sons[0]])
else:
result = newNode(nkStaticExpr, info, @[next])
of tkBind:
result = newNodeP(nkBind, p)
getTok(p)
@@ -1215,7 +1265,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
let baseInd = p.lex.currLineIndent
result = identOrLiteral(p, mode)
if mode != pmSkipSuffix:
result = primarySuffix(p, result, baseInd)
result = primarySuffix(p, result, baseInd, mode)
proc parseTypeDesc(p: var TParser): PNode =
#| typeDesc = simpleExpr
@@ -1244,8 +1294,8 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
if p.tok.indent >= 0: return
var
openingParams = emptyNode
openingPragmas = emptyNode
openingParams = p.emptyNode
openingPragmas = p.emptyNode
if p.tok.tokType == tkDo:
getTok(p)
@@ -1264,8 +1314,12 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
stmtList.flags.incl nfBlockArg
if openingParams.kind != nkEmpty:
result.add newProcNode(nkDo, stmtList.info, stmtList,
params = openingParams, pragmas = openingPragmas)
result.add newProcNode(nkDo, stmtList.info, body = stmtList,
params = openingParams,
name = p.emptyNode, pattern = p.emptyNode,
genericParams = p.emptyNode,
pragmas = openingPragmas,
exceptions = p.emptyNode)
else:
result.add stmtList
@@ -1424,10 +1478,10 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
getTok(p)
if p.tok.tokType == tkComment:
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):
# NL terminates:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
else:
var e = parseExpr(p)
e = postExprBlocks(p, e)
@@ -1568,7 +1622,7 @@ proc parseBlock(p: var TParser): PNode =
#| blockExpr = 'block' symbol? colcom stmt
result = newNodeP(nkBlockStmt, 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))
colcom(p, result)
addSon(result, parseStmt(p))
@@ -1586,7 +1640,7 @@ proc parseAsm(p: var TParser): PNode =
result = newNodeP(nkAsmStmt, p)
getTokNoInd(p)
if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p))
else: addSon(result, ast.emptyNode)
else: addSon(result, p.emptyNode)
case p.tok.tokType
of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p))
of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
@@ -1594,7 +1648,7 @@ proc parseAsm(p: var TParser): PNode =
newStrNodeP(nkTripleStrLit, p.tok.literal, p))
else:
parMessage(p, "the 'asm' statement takes a string literal")
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
return
getTok(p)
@@ -1625,13 +1679,13 @@ proc parseGenericParam(p: var TParser): PNode =
optInd(p, result)
addSon(result, parseExpr(p))
else:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
if p.tok.tokType == tkEquals:
getTok(p)
optInd(p, result)
addSon(result, parseExpr(p))
else:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
proc parseGenericParamList(p: var TParser): PNode =
#| genericParamList = '[' optInd
@@ -1644,6 +1698,8 @@ proc parseGenericParamList(p: var TParser): PNode =
var a = parseGenericParam(p)
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break
when defined(nimpretty2):
commaWasSemicolon(p.em)
getTok(p)
skipComment(p, a)
optPar(p)
@@ -1667,22 +1723,22 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
optInd(p, result)
addSon(result, identVis(p))
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:
result.add(p.parseGenericParamList)
else:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
addSon(result, p.parseParamList)
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:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
if p.tok.tokType == tkEquals and p.validInd:
getTok(p)
skipComment(p, result)
addSon(result, parseStmt(p))
else:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
indAndComment(p, result)
proc newCommentStmt(p: var TParser): PNode =
@@ -1732,7 +1788,7 @@ proc parseConstant(p: var TParser): PNode =
optInd(p, result)
addSon(result, parseTypeDesc(p))
else:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
eat(p, tkEquals)
optInd(p, result)
addSon(result, parseExpr(p))
@@ -1742,7 +1798,7 @@ proc parseEnum(p: var TParser): PNode =
#| enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+
result = newNodeP(nkEnumTy, p)
getTok(p)
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
optInd(p, result)
flexComment(p, result)
# progress guaranteed
@@ -1813,7 +1869,7 @@ proc parseObjectCase(p: var TParser): PNode =
addSon(a, identWithPragma(p))
eat(p, tkColon)
addSon(a, parseTypeDesc(p))
addSon(a, ast.emptyNode)
addSon(a, p.emptyNode)
addSon(result, a)
if p.tok.tokType == tkColon: getTok(p)
flexComment(p, result)
@@ -1872,7 +1928,7 @@ proc parseObjectPart(p: var TParser): PNode =
result = newNodeP(nkNilLit, p)
getTok(p)
else:
result = ast.emptyNode
result = p.emptyNode
proc parseObject(p: var TParser): PNode =
#| object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
@@ -1881,19 +1937,19 @@ proc parseObject(p: var TParser): PNode =
if p.tok.tokType == tkCurlyDotLe and p.validInd:
addSon(result, parsePragma(p))
else:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
if p.tok.tokType == tkOf and p.tok.indent < 0:
var a = newNodeP(nkOfInherit, p)
getTok(p)
addSon(a, parseTypeDesc(p))
addSon(result, a)
else:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
if p.tok.tokType == tkComment:
skipComment(p, result)
# an initial IND{>} HAS to follow:
if not realInd(p):
addSon(result, emptyNode)
addSon(result, p.emptyNode)
return
addSon(result, parseObjectPart(p))
@@ -1928,7 +1984,7 @@ proc parseTypeClass(p: var TParser): PNode =
if p.tok.tokType == tkCurlyDotLe and p.validInd:
addSon(result, parsePragma(p))
else:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
if p.tok.tokType == tkOf and p.tok.indent < 0:
var a = newNodeP(nkOfInherit, p)
getTok(p)
@@ -1939,12 +1995,12 @@ proc parseTypeClass(p: var TParser): PNode =
getTok(p)
addSon(result, a)
else:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
if p.tok.tokType == tkComment:
skipComment(p, result)
# an initial IND{>} HAS to follow:
if not realInd(p):
addSon(result, emptyNode)
addSon(result, p.emptyNode)
else:
addSon(result, parseStmt(p))
@@ -1957,14 +2013,14 @@ proc parseTypeDef(p: var TParser): PNode =
if p.tok.tokType == tkBracketLe and p.validInd:
addSon(result, parseGenericParamList(p))
else:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
if p.tok.tokType == tkEquals:
result.info = parLineInfo(p)
getTok(p)
optInd(p, result)
addSon(result, parseTypeDefAux(p))
else:
addSon(result, ast.emptyNode)
addSon(result, p.emptyNode)
indAndComment(p, result) # special extension!
proc parseVarTuple(p: var TParser): PNode =
@@ -1979,7 +2035,7 @@ proc parseVarTuple(p: var TParser): PNode =
if p.tok.tokType != tkComma: break
getTok(p)
skipComment(p, a)
addSon(result, ast.emptyNode) # no type desc
addSon(result, p.emptyNode) # no type desc
optPar(p)
eat(p, tkParRi)
eat(p, tkEquals)
@@ -2040,7 +2096,7 @@ proc simpleStmt(p: var TParser): PNode =
of tkComment: result = newCommentStmt(p)
else:
if isExprStart(p): result = parseExprStmt(p)
else: result = ast.emptyNode
else: result = p.emptyNode
if result.kind notin {nkEmpty, nkCommentStmt}: skipComment(p, result)
proc complexOrSimpleStmt(p: var TParser): PNode =
@@ -2136,7 +2192,7 @@ proc parseStmt(p: var TParser): PNode =
of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkFunc,
tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar:
parMessage(p, "complex statement requires indentation")
result = ast.emptyNode
result = p.emptyNode
else:
if p.inSemiStmtList > 0:
result = simpleStmt(p)
@@ -2173,7 +2229,7 @@ proc parseAll(p: var TParser): PNode =
proc parseTopLevelStmt(p: var TParser): PNode =
## Implements an iterator which, when called repeatedly, returns the next
## top-level statement or emptyNode if end of stream.
result = ast.emptyNode
result = p.emptyNode
# progress guaranteed
while true:
if p.tok.indent != 0:

View File

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

View File

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

View File

@@ -77,7 +77,7 @@ proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
if isNil(n.typ):
result = p.typ.kind in {tyVoid, tyStmt}
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.} =
result = p.kind == nkSym and p.sym.kind == skParam and p.sym.owner == c.owner

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,40 +8,26 @@
#
## 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.
import ast, semdata, idents
type
Transformation* = proc (c: PContext; n: PNode): PNode {.nimcall.}
Plugin = ref object
fn, module, package: PIdent
Plugin* = tuple
package, module, fn: string
t: Transformation
next: Plugin
proc pluginMatches(p: Plugin; s: PSym): bool =
if s.name.id != p.fn.id:
proc pluginMatches*(ic: IdentCache; p: Plugin; s: PSym): bool =
if s.name.id != ic.getIdent(p.fn).id:
return false
let module = s.skipGenericOwner
if module == nil or module.kind != skModule or
module.name.id != p.module.id:
module.name.id != ic.getIdent(p.module).id:
return false
let package = module.owner
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 true
var head: Plugin
proc getPlugin*(fn: PSym): Transformation =
var it = head
while it != nil:
if pluginMatches(it, fn): return it.t
it = it.next
proc registerPlugin*(package, module, fn: string; t: Transformation) =
let oldHead = head
head = Plugin(fn: getIdent(fn), module: getIdent(module),
package: getIdent(package), t: t, next: oldHead)

View File

@@ -12,7 +12,7 @@
import
os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees,
rodread, types, lookups, configuration
types, lookups, lineinfos
const
FirstCallConv* = wNimcall
@@ -24,8 +24,8 @@ const
wCompilerProc, wCore, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wCodegenDecl,
wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
wOverride, wConstructor, wExportNims, wUsed, wLiftLocals}
wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, wOverride,
wConstructor, wExportNims, wUsed, wLiftLocals, wStacktrace, wLinetrace}
converterPragmas* = procPragmas
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
@@ -82,7 +82,13 @@ proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode =
return it[1]
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
errStringLiteralExpected = "string literal expected"
@@ -143,7 +149,7 @@ proc processImportCpp(c: PContext; s: PSym, extname: string, info: TLineInfo) =
if c.config.cmd == cmdCompileToC:
let m = s.getModule()
incl(m.flags, sfCompileToCpp)
extccomp.gMixedMode = true
incl c.config.globalOptions, optMixedMode
proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) =
setExternName(c, s, extname, info)
@@ -217,9 +223,9 @@ proc isTurnedOn(c: PContext, n: PNode): bool =
if x.kind == nkIntLit: return x.intVal != 0
localError(c.config, n.info, "'on' or 'off' expected")
proc onOff(c: PContext, n: PNode, op: TOptions) =
if isTurnedOn(c, n): c.config.options = c.config.options + op
else: c.config.options = c.config.options - op
proc onOff(c: PContext, n: PNode, op: TOptions, resOptions: var TOptions) =
if isTurnedOn(c, n): resOptions = resOptions + op
else: resOptions = resOptions - op
proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
if isTurnedOn(c, n): incl(c.module.flags, flag)
@@ -227,7 +233,7 @@ proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
proc processCallConv(c: PContext, n: PNode) =
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
of FirstCallConv..LastCallConv:
c.optionStack[^1].defaultCC = wordToCallConv(sw)
@@ -307,54 +313,68 @@ proc processNote(c: PContext, n: PNode) =
else:
invalidPragma(c, n)
proc processOption(c: PContext, n: PNode): bool =
if n.kind notin nkPragmaCallKinds or n.len != 2: result = true
proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} =
case w
of wChecks: ChecksOptions
of wObjChecks: {optObjCheck}
of wFieldChecks: {optFieldCheck}
of wRangechecks: {optRangeCheck}
of wBoundchecks: {optBoundsCheck}
of wOverflowchecks: {optOverflowCheck}
of wNilchecks: {optNilCheck}
of wFloatchecks: {optNaNCheck, optInfCheck}
of wNanChecks: {optNaNCheck}
of wInfChecks: {optInfCheck}
of wMovechecks: {optMoveCheck}
of wAssertions: {optAssert}
of wWarnings: {optWarns}
of wHints: {optHints}
of wLinedir: {optLineDir}
of wStacktrace: {optStackTrace}
of wLinetrace: {optLineTrace}
of wDebugger: {optEndb}
of wProfiler: {optProfiler, optMemTracker}
of wMemTracker: {optMemTracker}
of wByRef: {optByRef}
of wImplicitStatic: {optImplicitStatic}
of wPatterns: {optPatterns}
else: {}
proc tryProcessOption(c: PContext, n: PNode, resOptions: var TOptions): bool =
result = true
if n.kind notin nkPragmaCallKinds or n.len != 2: result = false
elif n.sons[0].kind == nkBracketExpr: processNote(c, n)
elif n.sons[0].kind != nkIdent: result = true
elif n.sons[0].kind != nkIdent: result = false
else:
let sw = whichKeyword(n.sons[0].ident)
case sw
of wChecks: onOff(c, n, ChecksOptions)
of wObjChecks: onOff(c, n, {optObjCheck})
of wFieldChecks: onOff(c, n, {optFieldCheck})
of wRangechecks: onOff(c, n, {optRangeCheck})
of wBoundchecks: onOff(c, n, {optBoundsCheck})
of wOverflowchecks: onOff(c, n, {optOverflowCheck})
of wNilchecks: onOff(c, n, {optNilCheck})
of wFloatchecks: onOff(c, n, {optNaNCheck, optInfCheck})
of wNanChecks: onOff(c, n, {optNaNCheck})
of wInfChecks: onOff(c, n, {optInfCheck})
of wMovechecks: onOff(c, n, {optMoveCheck})
of wAssertions: onOff(c, n, {optAssert})
of wWarnings: onOff(c, n, {optWarns})
of wHints: onOff(c, n, {optHints})
of wCallconv: processCallConv(c, n)
of wLinedir: onOff(c, n, {optLineDir})
of wStacktrace: onOff(c, n, {optStackTrace})
of wLinetrace: onOff(c, n, {optLineTrace})
of wDebugger: onOff(c, n, {optEndb})
of wProfiler: onOff(c, n, {optProfiler, optMemTracker})
of wMemTracker: onOff(c, n, {optMemTracker})
of wByRef: onOff(c, n, {optByRef})
of wDynlib: processDynLib(c, n, nil)
of wOptimization:
if n.sons[1].kind != nkIdent:
invalidPragma(c, n)
else:
case n.sons[1].ident.s.normalize
of "speed":
incl(c.config.options, optOptimizeSpeed)
excl(c.config.options, optOptimizeSize)
of "size":
excl(c.config.options, optOptimizeSpeed)
incl(c.config.options, optOptimizeSize)
of "none":
excl(c.config.options, optOptimizeSpeed)
excl(c.config.options, optOptimizeSize)
else: localError(c.config, n.info, "'none', 'speed' or 'size' expected")
of wImplicitStatic: onOff(c, n, {optImplicitStatic})
of wPatterns: onOff(c, n, {optPatterns})
else: result = true
let opts = pragmaToOptions(sw)
if opts != {}:
onOff(c, n, opts, resOptions)
else:
case sw
of wCallconv: processCallConv(c, n)
of wDynlib: processDynLib(c, n, nil)
of wOptimization:
if n.sons[1].kind != nkIdent:
invalidPragma(c, n)
else:
case n.sons[1].ident.s.normalize
of "speed":
incl(resOptions, optOptimizeSpeed)
excl(resOptions, optOptimizeSize)
of "size":
excl(resOptions, optOptimizeSpeed)
incl(resOptions, optOptimizeSize)
of "none":
excl(resOptions, optOptimizeSpeed)
excl(resOptions, optOptimizeSize)
else: localError(c.config, n.info, "'none', 'speed' or 'size' expected")
else: result = false
proc processOption(c: PContext, n: PNode, resOptions: var TOptions) =
if not tryProcessOption(c, n, resOptions):
# calling conventions (boring...):
localError(c.config, n.info, "option expected")
proc processPush(c: PContext, n: PNode, start: int) =
if n.sons[start-1].kind in nkPragmaCallKinds:
@@ -367,7 +387,7 @@ proc processPush(c: PContext, n: PNode, start: int) =
x.notes = c.config.notes
c.optionStack.add(x)
for i in countup(start, sonsLen(n) - 1):
if processOption(c, n.sons[i]):
if not tryProcessOption(c, n.sons[i], c.config.options):
# simply store it somewhere:
if x.otherPragmas.isNil:
x.otherPragmas = newNodeI(nkPragma, n.info)
@@ -408,7 +428,7 @@ proc relativeFile(c: PContext; n: PNode; ext=""): string =
var s = expectStrLit(c, n)
if ext.len > 0 and splitFile(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 isAbsolute(s): result = s
else:
@@ -416,6 +436,10 @@ proc relativeFile(c: PContext; n: PNode; ext=""): string =
if result.len == 0: result = s
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 =
n.sons[i] = c.semConstExpr(c, n[i])
@@ -430,30 +454,31 @@ proc processCompile(c: PContext, n: PNode) =
if it.kind in {nkPar, nkTupleConstr} and it.len == 2:
let s = getStrLit(c, it, 0)
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):
let nameOnly = extractFilename(f)
var cf = Cfile(cname: f,
obj: completeCFilePath(c.config, dest % nameOnly),
flags: {CfileFlag.External})
extccomp.addExternalFileToCompile(c.config, cf)
let obj = completeCFilePath(c.config, dest % extractFilename(f))
docompile(c, it, f, obj)
else:
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 isAbsolute(s): found = s
else:
found = findFile(c.config, s)
if found.len == 0: found = s
extccomp.addExternalFileToCompile(c.config, found)
let obj = toObjFile(c.config, completeCFilePath(c.config, found, false))
docompile(c, it, found, obj)
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
of linkNormal: extccomp.addExternalFileToLink(c.config, found)
of linkNormal:
extccomp.addExternalFileToLink(c.config, found)
recordPragma(c, n, "link", found)
of linkSys:
extccomp.addExternalFileToLink(c.config,
c.config.libpath / completeCFilePath(c.config, found, false))
let dest = 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")
proc pragmaBreakpoint(c: PContext, n: PNode) =
@@ -484,9 +509,10 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
if c < 0: sub = substr(str, b + 1)
else: sub = substr(str, b + 1, c - 1)
if sub != "":
var e = searchInScopes(con, getIdent(sub))
var e = searchInScopes(con, getIdent(con.cache, sub))
if e != nil:
if e.kind == skStub: loadStub(e)
when false:
if e.kind == skStub: loadStub(e)
incl(e.flags, sfUsed)
addSon(result, newSymNode(e))
else:
@@ -553,7 +579,7 @@ proc pragmaLine(c: PContext, n: PNode) =
localError(c.config, n.info, "tuple expected")
else:
# sensible default:
n.info = getInfoContext(-1)
n.info = getInfoContext(c.config, -1)
proc processPragma(c: PContext, n: PNode, i: int) =
let it = n[i]
@@ -638,7 +664,7 @@ proc deprecatedStmt(c: PContext; outerPragma: PNode) =
let dest = qualifiedLookUp(c, n[1], {checkUndeclared})
if dest == nil or dest.kind in routineKinds:
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)
incl(alias.flags, sfExported)
if sfCompilerProc in dest.flags: markCompilerProc(c, alias)
@@ -661,7 +687,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
# 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
# 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)
else:
result = qualifiedLookUp(c, n, {checkUndeclared})
@@ -714,7 +740,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
elif key.kind notin nkIdentKinds:
n.sons[i] = semCustomPragma(c, it)
return
let ident = considerQuotedIdent(c.config, key)
let ident = considerQuotedIdent(c, key)
var userPragma = strTableGet(c.userPragmas, ident)
if userPragma != nil:
# number of pragmas increase/decrease with user pragma expansion
@@ -727,7 +753,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
dec c.instCounter
else:
var k = whichKeyword(ident)
let k = whichKeyword(ident)
if k in validPragmas:
case k
of wExportc:
@@ -736,10 +762,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wImportc:
let name = getOptionalStr(c, it, "$1")
cppDefine(c.config, name)
recordPragma(c, it, "cppdefine", name)
makeExternImport(c, sym, name, it.info)
of wImportCompilerProc:
let name = getOptionalStr(c, it, "$1")
cppDefine(c.config, name)
recordPragma(c, it, "cppdefine", name)
processImportCompilerProc(c, sym, name, it.info)
of wExtern: setExternName(c, sym, expectStrLit(c, it), it.info)
of wImmediate:
@@ -832,6 +860,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wCompilerProc, wCore:
noVal(c, it) # compilerproc may not get a string!
cppDefine(c.graph.config, sym.name.s)
recordPragma(c, it, "cppdefine", sym.name.s)
if sfFromGeneric notin sym.flags: markCompilerProc(c, sym)
of wProcVar:
noVal(c, it)
@@ -894,8 +923,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ.flags, tfPacked)
of wHint: message(c.config, it.info, hintUser, expectStrLit(c, it))
of wWarning: message(c.config, it.info, warnUser, expectStrLit(c, it))
of wHint:
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:
if sym != nil and sym.isRoutine:
# This is subtle but correct: the error *statement* is only
@@ -905,15 +940,23 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
noVal(c, it)
incl(sym.flags, sfError)
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 wDefine: processDefine(c, it)
of wUndef: processUndef(c, it)
of wCompile: processCompile(c, it)
of wLink: processCommonLink(c, it, linkNormal)
of wLinksys: processCommonLink(c, it, linkSys)
of wPassl: extccomp.addLinkOption(c.config, expectStrLit(c, it))
of wPassc: extccomp.addCompileOption(c.config, expectStrLit(c, it))
of wPassl:
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 wWatchPoint: pragmaWatchpoint(c, it)
of wPush:
@@ -935,13 +978,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wCodegenDecl: processCodegenDecl(c, it, sym)
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
wLinedir, wStacktrace, wLinetrace, wOptimization, wMovechecks,
wCallconv,
wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
wPatterns:
if processOption(c, it):
# calling conventions (boring...):
localError(c.config, it.info, "option expected")
wLinedir, wOptimization, wMovechecks, wCallconv, wDebugger, wProfiler,
wFloatchecks, wNanChecks, wInfChecks, wPatterns:
processOption(c, it, c.config.options)
of wStacktrace, wLinetrace:
if sym.kind in {skProc, skMethod, skConverter}:
processOption(c, it, sym.options)
else:
processOption(c, it, c.config.options)
of FirstCallConv..LastCallConv:
assert(sym != nil)
if sym.typ == nil: invalidPragma(c, it)
@@ -971,7 +1015,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wByRef:
noVal(c, it)
if sym == nil or sym.typ == nil:
if processOption(c, it): localError(c.config, it.info, "option expected")
processOption(c, it, c.config.options)
else:
incl(sym.typ.flags, tfByRef)
of wByCopy:
@@ -1021,9 +1065,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
processExperimental(c, it, sym)
of wThis:
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:
c.selfName = getIdent("self")
c.selfName = getIdent(c.cache, "self")
else:
localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments")
of wNoRewrite:
@@ -1051,13 +1095,13 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
for it in c.optionStack:
let o = it.otherPragmas
if not o.isNil:
pushInfoContext(n.info)
pushInfoContext(c.config, n.info)
var i = 0
while i < o.len():
if singlePragma(c, sym, o, i, validPragmas):
internalError(c.config, n.info, "implicitPragmas")
inc i
popInfoContext()
popInfoContext(c.config)
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
localError(c.config, n.info, ".dynlib requires .exportc")
@@ -1069,8 +1113,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
if n == nil or n.sons == nil:
return false
if n == nil: return false
for p in n:
var key = if p.kind in nkPragmaCallKinds and p.len > 1: p[0] else: p
@@ -1082,7 +1125,7 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
if n == nil: return
var i = 0
while i < n.len():
while i < n.len:
if singlePragma(c, sym, n, i, validPragmas): break
inc i

View File

@@ -24,7 +24,7 @@ proc prefixMatch*(p, s: string): PrefixMatch =
# check for prefix/contains:
while i < L:
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 jj = 1
while ii < L and jj < p.len:
@@ -43,10 +43,10 @@ proc prefixMatch*(p, s: string): PrefixMatch =
i = 1
var j = 1
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
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
else: return PrefixMatch.None
inc i

View File

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

View File

@@ -10,7 +10,7 @@
# This module implements the renderer of the standard Nim representation.
import
lexer, options, idents, strutils, ast, msgs, configuration
lexer, options, idents, strutils, ast, msgs, lineinfos
type
TRenderFlag* = enum
@@ -330,14 +330,15 @@ proc ulitAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
proc atom(g: TSrcGen; n: PNode): string =
when defined(nimpretty):
doAssert g.config != nil, "g.config not initialized!"
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:
""
if n.info.offsetA <= n.info.offsetB:
# for some constructed tokens this can not be the case and we're better
# 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
case n.kind
of nkEmpty: result = ""
@@ -386,8 +387,10 @@ proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
assert(theEnd < 0)
result = 0
for i in countup(start, sonsLen(n) + theEnd):
inc(result, lsub(g, n.sons[i]))
inc(result, 2) # for ``, ``
let param = n.sons[i]
if nfDefaultParam notin param.flags:
inc(result, lsub(g, param))
inc(result, 2) # for ``, ``
if result > 0:
dec(result, 2) # last does not get a comma!
@@ -811,8 +814,8 @@ proc gident(g: var TSrcGen, n: PNode) =
var t: TTokType
var s = atom(g, n)
if (s[0] in lexer.SymChars):
if (n.kind == nkIdent):
if s.len > 0 and s[0] in lexer.SymChars:
if n.kind == nkIdent:
if (n.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
(n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
t = tkSymbol
@@ -1452,11 +1455,12 @@ proc `$`*(n: PNode): string = n.renderTree
proc renderModule*(n: PNode, infile, outfile: string,
renderFlags: TRenderFlags = {};
fid = FileIndex(-1)) =
fid = FileIndex(-1);
conf: ConfigRef = nil) =
var
f: File
g: TSrcGen
initSrcGen(g, renderFlags, newPartialConfigRef())
initSrcGen(g, renderFlags, conf)
g.fid = fid
for i in countup(0, sonsLen(n) - 1):
gsub(g, n.sons[i])

View File

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

View File

@@ -9,18 +9,21 @@
## 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):
template setupModuleCache* = discard
template storeNode*(module: PSym; n: PNode) = discard
template loadNode*(module: PSym; index: var int): PNode = PNode(nil)
when not nimIncremental:
template setupModuleCache*(g: ModuleGraph) = discard
template storeNode*(g: ModuleGraph; module: PSym; n: PNode) = discard
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:
include rodimpl
# idea for testing all this logic: *Always* load the AST from the DB, whether
# we already have it in RAM or not!

View File

@@ -10,59 +10,67 @@
## This module implements the new compilation cache.
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:
## - Implement the 'import' replay logic so that the codegen runs over
## 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
## - Dependency computation should use *signature* hashes in order to
## 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 =
result = msgs.getHash(fileIdx)
if result.len == 0:
result = $secureHashFile(fullpath)
msgs.setHash(fileIdx, result)
proc encodeConfig(g: ModuleGraph): string =
result = newStringOfCap(100)
result.add RodFileVersion
for d in definedSymbolNames(g.config.symbols):
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 = ?",
fullpath)
if root[0].len == 0: return true
if root[1] != hashFileCached(fileIdx, fullpath):
if root[1] != hashFileCached(g.config, fileIdx, fullpath):
return true
# cycle detection: assume "not changed" is correct.
if cycleCheck.containsOrIncl(fileIdx):
if cycleCheck.containsOrIncl(int fileIdx):
return false
# check dependencies (recursively):
for row in db.fastRows(sql"select fullpath from filenames where id in (select dependency from deps where module = ?)",
root[0]):
let dep = row[0]
if needsRecompile(dep.fileInfoIdx, dep, cycleCheck):
if needsRecompile(g, g.config.fileInfoIdx(dep), dep, cycleCheck):
return true
return false
proc getModuleId*(fileIdx: int32; fullpath: string): int =
if gSymbolFiles != v2Sf: return getID()
let module = db.getRow(
sql"select id, fullHash from modules where fullpath = ?", fullpath)
let currentFullhash = hashFileCached(fileIdx, fullpath)
proc getModuleId*(g: ModuleGraph; fileIdx: FileIndex; fullpath: string): int =
if g.config.symbolFiles in {disabledSf, writeOnlySf} or
g.incr.configChanged:
return getID()
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:
result = int db.insertID(sql"insert into modules(fullpath, interfHash, fullHash) values (?, ?, ?)",
fullpath, "", currentFullhash)
result = getID()
db.exec(sql"insert into modules(fullpath, interfHash, fullHash, nimid) values (?, ?, ?, ?)",
fullpath, "", currentFullhash, result)
else:
result = parseInt(module[0])
result = parseInt(module[2])
if currentFullhash == module[1]:
# not changed, so use the cached AST (even if it might be wrong
# due to its dependencies):
# not changed, so use the cached AST:
doAssert(result != 0)
var cycleCheck = initIntSet()
if not needsRecompile(fileIdx, fullpath, cycleCheck):
if not needsRecompile(g, fileIdx, fullpath, cycleCheck):
echo "cached successfully! ", fullpath
return -result
db.exec(sql"update modules set fullHash = ? where id = ?", currentFullhash, 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 statics where module = ?", module[0])
type
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) =
proc pushType(w: var Writer, t: PType) =
if not containsOrIncl(w.tmarks, t.id):
w.tstack.add(t)
proc pushSym(w: PRodWriter, s: PSym) =
proc pushSym(w: var Writer, s: PSym) =
if not containsOrIncl(w.smarks, s.id):
w.sstack.add(s)
proc toDbFileId(fileIdx: int32): int =
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)
template w: untyped = g.incr.w
proc fromDbFileId(dbId: int): int32 =
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,
proc encodeNode(g: ModuleGraph; fInfo: TLineInfo, n: PNode,
result: var string) =
if n == nil:
# nil nodes have to be stored too:
@@ -139,14 +104,14 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
encodeVInt(int n.info.line, result)
result.add(',')
encodeVInt(toDbFileId(n.info.fileIndex), result)
encodeVInt(toDbFileId(g.incr, g.config, n.info.fileIndex), result)
elif fInfo.line != n.info.line:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
encodeVInt(int n.info.line, result)
elif fInfo.col != n.info.col:
result.add('?')
encodeVInt(n.info.col, result)
@@ -182,10 +147,10 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
pushSym(w, n.sym)
else:
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, ')')
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
proc encodeLoc(g: ModuleGraph; loc: TLoc, result: var string) =
var oldLen = result.len
result.add('<')
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)
if loc.lode != nil:
add(result, '^')
encodeNode(w, unknownLineInfo(), loc.lode, result)
#encodeVInt(cast[int32](loc.t.id), result)
#pushType(w, loc.t)
encodeNode(g, unknownLineInfo(), loc.lode, result)
if loc.r != nil:
add(result, '!')
encodeStr($loc.r, result)
@@ -209,13 +172,13 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
else:
add(result, '>')
proc encodeType(w: PRodWriter, t: PType, result: var string) =
proc encodeType(g: ModuleGraph, 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("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
# can easily be disambiguated:
add(result, '[')
@@ -223,7 +186,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
add(result, '+')
encodeVInt(t.id, result)
if t.n != nil:
encodeNode(w, w.module.info, t.n, result)
encodeNode(g, unknownLineInfo(), t.n, result)
if t.flags != {}:
add(result, '$')
encodeVInt(cast[int32](t.flags), result)
@@ -269,7 +232,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
add(result, '\20')
encodeVInt(s.id, result)
pushSym(w, s)
encodeLoc(w, t.loc, result)
encodeLoc(g, t.loc, result)
for i in countup(0, sonsLen(t) - 1):
if t.sons[i] == nil:
add(result, "^()")
@@ -278,15 +241,15 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
encodeVInt(t.sons[i].id, result)
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, '|')
encodeVInt(ord(lib.kind), result)
add(result, '|')
encodeStr($lib.name, 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) =
for t in s:
result.add('\15')
@@ -299,7 +262,7 @@ proc encodeInstantiations(w: PRodWriter; s: seq[PInstantiation];
result.add('\20')
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:
# nil nodes have to be stored too:
result.add("{}")
@@ -317,9 +280,9 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
result.add('?')
if s.info.col != -1'i16: encodeVInt(s.info.col, result)
result.add(',')
if s.info.line != -1'i16: encodeVInt(s.info.line, result)
encodeVInt(int s.info.line, result)
result.add(',')
encodeVInt(toDbFileId(s.info.fileIndex), result)
encodeVInt(toDbFileId(g.incr, g.config, s.info.fileIndex), result)
if s.owner != nil:
result.add('*')
encodeVInt(s.owner.id, result)
@@ -338,11 +301,11 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
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)
encodeLoc(g, s.loc, result)
if s.annex != nil: encodeLib(g, s.annex, s.info, result)
if s.constraint != nil:
add(result, '#')
encodeNode(w, unknownLineInfo(), s.constraint, result)
encodeNode(g, unknownLineInfo(), s.constraint, result)
case s.kind
of skType, skGenericParam:
for t in s.typeInstCache:
@@ -350,13 +313,13 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
encodeVInt(t.id, result)
pushType(w, t)
of routineKinds:
encodeInstantiations(w, s.procInstCache, result)
encodeInstantiations(g, 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)
encodeInstantiations(g, s.usedGenerics, result)
# we don't serialize:
#tab*: TStrTable # interface table for modules
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
# it is not necessary, but Nim's heavy compile-time evaluation features
# 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:
w.forwardedSyms.add s
return
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
# 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 (?, ?, ?, ?, ?)",
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)
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 (?, ?, ?)",
t.id, abs(w.module.id), buf)
t.id, mid, buf)
var w = initRodWriter(nil)
proc storeNode*(module: PSym; n: PNode) =
if gSymbolFiles != v2Sf: return
w.module = module
proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
if g.config.symbolFiles == disabledSf: return
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 (?, ?, ?)",
abs(module.id), module.offset, buf)
inc module.offset
var i = 0
while true:
if i > 10_000:
quit "loop never ends!"
doAssert false, "loop never ends!"
if w.sstack.len > 0:
let s = w.sstack.pop()
when false:
echo "popped ", s.name.s, " ", s.id
storeSym(w, s)
storeSym(g, s)
elif w.tstack.len > 0:
let t = w.tstack.pop()
storeType(w, t)
storeType(g, t)
when false:
echo "popped type ", typeToString(t), " ", t.id
else:
break
inc i
proc storeRemaining*(module: PSym) =
if gSymbolFiles != v2Sf: return
w.module = module
proc recordStmt*(g: ModuleGraph; module: PSym; n: PNode) =
storeNode(g, module, n)
proc storeRemaining*(g: ModuleGraph; module: PSym) =
if g.config.symbolFiles == disabledSf: return
var stillForwarded: seq[PSym] = @[]
for s in w.forwardedSyms:
assert sfForward notin s.flags
storeSym(w, s)
w.forwardedSyms.setLen 0
if sfForward notin s.flags:
storeSym(g, s)
else:
stillForwarded.add s
swap w.forwardedSyms, stillForwarded
# ---------------- decoder -----------------------------------
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
s: string
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
r: PRodReader
b: var BlobReader
g: ModuleGraph
proc loadSym(r; id: int, info: TLineInfo): PSym
proc loadType(r; id: int, info: TLineInfo): PType
proc loadSym(g; id: int, info: TLineInfo): PSym
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] == '?':
inc(b.pos)
if b.s[b.pos] == ',': info.col = -1'i16
else: info.col = int16(decodeVInt(b.s, b.pos))
if b.s[b.pos] == ',':
inc(b.pos)
if b.s[b.pos] == ',': info.line = -1'i16
else: info.line = int16(decodeVInt(b.s, b.pos))
if b.s[b.pos] == ',': info.line = 0'u16
else: info.line = uint16(decodeVInt(b.s, b.pos))
if b.s[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) =
assert b.s[b.pos] == '('
@@ -488,7 +439,7 @@ proc skipNode(b) =
inc pos
b.pos = pos+1 # skip ')'
proc decodeNodeLazyBody(r; b; fInfo: TLineInfo,
proc decodeNodeLazyBody(g; b; fInfo: TLineInfo,
belongsTo: PSym): PNode =
result = nil
if b.s[b.pos] == '(':
@@ -497,14 +448,14 @@ proc decodeNodeLazyBody(r; b; fInfo: TLineInfo,
inc(b.pos)
return # nil node
result = newNodeI(TNodeKind(decodeVInt(b.s, b.pos)), fInfo)
decodeLineInfo(r, b, result.info)
decodeLineInfo(g, b, result.info)
if b.s[b.pos] == '$':
inc(b.pos)
result.flags = cast[TNodeFlags](int32(decodeVInt(b.s, b.pos)))
if b.s[b.pos] == '^':
inc(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
of nkCharLit..nkUInt64Lit:
if b.s[b.pos] == '!':
@@ -525,16 +476,16 @@ proc decodeNodeLazyBody(r; b; fInfo: TLineInfo,
if b.s[b.pos] == '!':
inc(b.pos)
var fl = decodeStr(b.s, b.pos)
result.ident = r.cache.getIdent(fl)
result.ident = g.cache.getIdent(fl)
else:
internalError(result.info, "decodeNode: nkIdent")
internalError(g.config, result.info, "decodeNode: nkIdent")
of nkSym:
if b.s[b.pos] == '!':
inc(b.pos)
var id = decodeVInt(b.s, b.pos)
result.sym = loadSym(r, id, result.info)
result.sym = loadSym(g, id, result.info)
else:
internalError(result.info, "decodeNode: nkSym")
internalError(g.config, result.info, "decodeNode: nkSym")
else:
var i = 0
while b.s[b.pos] != ')':
@@ -545,17 +496,17 @@ proc decodeNodeLazyBody(r; b; fInfo: TLineInfo,
skipNode(b)
else:
discard
addSonNilAllowed(result, decodeNodeLazyBody(r, b, result.info, nil))
addSonNilAllowed(result, decodeNodeLazyBody(g, b, result.info, nil))
inc i
if b.s[b.pos] == ')': inc(b.pos)
else: internalError(result.info, "decodeNode: ')' missing")
else: internalError(g.config, result.info, "decodeNode: ')' missing")
else:
internalError(fInfo, "decodeNode: '(' missing " & $b.pos)
internalError(g.config, fInfo, "decodeNode: '(' missing " & $b.pos)
proc decodeNode(r; b; fInfo: TLineInfo): PNode =
result = decodeNodeLazyBody(r, b, fInfo, nil)
proc decodeNode(g; b; fInfo: TLineInfo): PNode =
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] == '<':
inc(b.pos)
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 = {}
if b.s[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)
else:
loc.lode = nil
@@ -584,19 +535,21 @@ proc decodeLoc(r; b; loc: var TLoc, info: TLineInfo) =
else:
loc.r = nil
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)
if blob.len == 0:
internalError("symbolfiles: cannot find ID " & $ id)
internalError(g.config, "symbolfiles: cannot find ID " & $ id)
result = BlobReader(pos: 0)
shallowCopy(result.s, blob)
# ensure we can read without index checks:
result.s.add '\0'
proc loadType(r; id: int; info: TLineInfo): PType =
result = r.types.getOrDefault(id)
proc loadType(g; id: int; info: TLineInfo): PType =
result = g.incr.r.types.getOrDefault(id)
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] == '[':
inc(b.pos)
@@ -611,10 +564,10 @@ proc loadType(r; id: int; info: TLineInfo): PType =
setId(result.id)
#if debugIds: registerID(result)
else:
internalError(info, "decodeType: no id")
internalError(g.config, info, "decodeType: no id")
# here this also avoids endless recursion for recursive type
r.types[result.id] = result
if b.s[b.pos] == '(': result.n = decodeNode(r, b, unknownLineInfo())
g.incr.r.types.add(result.id, result)
if b.s[b.pos] == '(': result.n = decodeNode(g, b, unknownLineInfo())
if b.s[b.pos] == '$':
inc(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))
if b.s[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] == '&':
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] == '/':
inc(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':
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':
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':
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':
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':
inc(b.pos)
let x = decodeVInt(b.s, b.pos)
doAssert b.s[b.pos] == '\20'
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))
decodeLoc(r, b, result.loc, info)
decodeLoc(g, b, result.loc, info)
while b.s[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)
else:
var d = decodeVInt(b.s, b.pos)
rawAddSon(result, loadType(r, d, info))
let d = decodeVInt(b.s, b.pos)
rawAddSon(result, loadType(g, d, info))
proc decodeLib(r; b; info: TLineInfo): PLib =
proc decodeLib(g; b; info: TLineInfo): PLib =
result = nil
if b.s[b.pos] == '|':
new(result)
inc(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)
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)
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]) =
while b.s[b.pos] == '\15':
inc(b.pos)
var ii: PInstantiation
new ii
ii.sym = loadSym(r, decodeVInt(b.s, b.pos), info)
ii.sym = loadSym(g, decodeVInt(b.s, b.pos), info)
ii.concreteTypes = @[]
while b.s[b.pos] == '\17':
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':
inc(b.pos)
ii.compilesId = decodeVInt(b.s, b.pos)
s.safeAdd ii
proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
proc loadSymFromBlob(g; b; info: TLineInfo): PSym =
if b.s[b.pos] == '{':
inc(b.pos)
if b.s[b.pos] == '}':
@@ -717,26 +670,26 @@ proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
id = decodeVInt(b.s, b.pos)
setId(id)
else:
internalError(info, "decodeSym: no id")
internalError(g.config, info, "decodeSym: no id")
var ident: PIdent
if b.s[b.pos] == '&':
inc(b.pos)
ident = r.cache.getIdent(decodeStr(b.s, b.pos))
ident = g.cache.getIdent(decodeStr(b.s, b.pos))
else:
internalError(info, "decodeSym: no ident")
internalError(g.config, info, "decodeSym: no ident")
#echo "decoding: {", ident.s
new(result)
result.id = id
result.kind = k
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] == '^':
inc(b.pos)
result.typ = loadType(r, decodeVInt(b.s, b.pos), info)
decodeLineInfo(r, b, result.info)
result.typ = loadType(g, decodeVInt(b.s, b.pos), info)
decodeLineInfo(g, b, result.info)
if b.s[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] == '$':
inc(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] == '!':
inc(b.pos)
result.options = cast[TOptions](int32(decodeVInt(b.s, b.pos)))
else:
result.options = r.module.options
if b.s[b.pos] == '%':
inc(b.pos)
result.position = decodeVInt(b.s, b.pos)
@@ -755,28 +706,28 @@ proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
inc(b.pos)
result.offset = decodeVInt(b.s, b.pos)
else:
result.offset = - 1
decodeLoc(r, b, result.loc, result.info)
result.annex = decodeLib(r, b, info)
result.offset = -1
decodeLoc(g, b, result.loc, result.info)
result.annex = decodeLib(g, b, info)
if b.s[b.pos] == '#':
inc(b.pos)
result.constraint = decodeNode(r, b, unknownLineInfo())
result.constraint = decodeNode(g, b, unknownLineInfo())
case result.kind
of skType, skGenericParam:
while b.s[b.pos] == '\14':
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:
decodeInstantiations(r, b, result.info, result.procInstCache)
decodeInstantiations(g, b, result.info, result.procInstCache)
if b.s[b.pos] == '\16':
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:
decodeInstantiations(r, b, result.info, result.usedGenerics)
decodeInstantiations(g, b, result.info, result.usedGenerics)
of skLet, skVar, skField, skForVar:
if b.s[b.pos] == '\18':
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':
inc(b.pos)
result.bitsize = decodeVInt(b.s, b.pos).int16
@@ -786,159 +737,146 @@ proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
#if result.kind in routineKinds:
# result.ast = decodeNodeLazyBody(b, result.info, result)
#else:
result.ast = decodeNode(r, b, result.info)
result.ast = decodeNode(g, b, result.info)
if sfCompilerProc in result.flags:
registerCompilerProc(result)
registerCompilerProc(g, result)
#echo "loading ", result.name.s
proc loadSym(r; id: int; info: TLineInfo): PSym =
result = r.syms.getOrDefault(id)
proc loadSym(g; id: int; info: TLineInfo): PSym =
result = g.incr.r.syms.getOrDefault(id)
if result != nil: return result
var b = loadBlob(sql"select data from syms where nimid = ?", id)
result = loadSymFromBlob(r, b, info)
var b = loadBlob(g, sql"select data from syms where nimid = ?", id)
result = loadSymFromBlob(g, b, info)
doAssert id == result.id, "symbol ID is not consistent!"
proc loadModuleSymTab(r; module: PSym) =
proc loadModuleSymTab(g; module: PSym) =
## 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)):
let id = parseInt(row[0])
var s = r.syms.getOrDefault(id)
var s = g.incr.r.syms.getOrDefault(id)
if s == nil:
var b = BlobReader(pos: 0)
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
strTableAdd(module.tab, s)
if sfSystemModule in module.flags:
magicsys.systemModule = module
g.systemModule = module
proc loadNode*(module: PSym; index: int): PNode =
assert gSymbolFiles == v2Sf
if index == 0:
loadModuleSymTab(gr, module)
#index = parseInt db.getValue(
# sql"select min(id) from toplevelstmts where module = ?", abs module.id)
var b = BlobReader(pos: 0)
b.s = db.getValue(sql"select data from toplevelstmts where position = ? and module = ?",
index, abs module.id)
if b.s.len == 0:
db.exec(sql"insert into controlblock(idgen) values (?)", gFrontEndId)
return nil # end marker
gr.module = module
result = decodeNode(gr, b, module.info)
proc replay(g: ModuleGraph; module: PSym; n: PNode) =
# XXX check if we need to replay nkStaticStmt here.
case n.kind
#of nkStaticStmt:
#evalStaticStmt(module, g, n[0], module)
#of nkVarSection, nkLetSection:
# nkVarSections are already covered by the vmgen which produces nkStaticStmt
of nkMethodDef:
methodDef(g, n[namePos].sym, fromCache=true)
of nkCommentStmt:
# pragmas are complex and can be user-overriden via templates. So
# instead of using the original ``nkPragma`` nodes, we rely on the
# fact that pragmas.nim was patched to produce specialized recorded
# 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) =
if gSymbolFiles != v2Sf: return
proc loadNode*(g: ModuleGraph; module: PSym): PNode =
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)
let b = toDbFileId(fileIdx)
var b = BlobReader(pos: 0)
# 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 (?, ?, ?)",
a, b, ord(isIncludeFile))
db.exec(sql"insert into controlblock(idgen) values (?)", gFrontEndId)
replay(g, module, result)
# --------------- Database model ---------------------------------------------
proc createDb() =
db.exec(sql"""
create table if not exists controlblock(
idgen integer 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,
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"
proc setupModuleCache*(g: ModuleGraph) =
if g.config.symbolFiles == disabledSf: return
g.recordStmt = recordStmt
let dbfile = getNimcacheDir(g.config) / "rodfiles.db"
if g.config.symbolFiles == writeOnlySf:
removeFile(dbfile)
if not fileExists(dbfile):
db = open(connection=dbfile, user="nim", password="",
database="nim")
createDb()
createDb(db)
db.exec(sql"insert into config(config) values (?)", encodeConfig(g))
else:
db = open(connection=dbfile, user="nim", password="",
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 SYNCHRONOUS=off")
db.exec(sql"pragma LOCKING_MODE=exclusive")

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -13,7 +13,7 @@
import
ast, modules, idents, passes, passaux, condsyms,
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:
from strutils import cmpIgnoreStyle, contains
@@ -152,28 +152,27 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
proc runNimScript*(cache: IdentCache; scriptName: string;
freshDefines=true; conf: ConfigRef) =
rawMessage(conf, hintConf, scriptName)
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
let graph = newModuleGraph(conf)
let graph = newModuleGraph(cache, conf)
connectCallbacks(graph)
if freshDefines: initDefines(conf.symbols)
defineSymbol(conf.symbols, "nimscript")
defineSymbol(conf.symbols, "nimconfig")
registerPass(semPass)
registerPass(evalPass)
registerPass(graph, semPass)
registerPass(graph, evalPass)
conf.searchPaths.add(conf.libpath)
var m = graph.makeModule(scriptName)
incl(m.flags, sfMainModule)
vm.globalCtx = setupVM(m, cache, scriptName, graph)
graph.vm = setupVM(m, cache, scriptName, graph)
graph.compileSystemModule(cache)
discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)
graph.compileSystemModule()
discard graph.processModule(m, llStreamOpen(scriptName, fmRead))
# ensure we load 'system.nim' again for the real non-config stuff!
resetSystemArtifacts(graph)
vm.globalCtx = nil
# do not remove the defined symbols
#initDefines()
undefSymbol(conf.symbols, "nimscript")

View File

@@ -13,10 +13,10 @@ import
ast, strutils, hashes, options, lexer, astalgo, trees, treetab,
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
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,
evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
semparallel, lowerings, pluginsupport, plugins.active, rod, configuration
evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
semparallel, lowerings, pluginsupport, plugins.active, rod, lineinfos
from modulegraphs import ModuleGraph
@@ -48,15 +48,18 @@ proc semQuoteAst(c: PContext, n: PNode): PNode
proc finishMethod(c: PContext, s: PSym)
proc evalAtCompileTime(c: PContext, n: PNode): PNode
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
proc semStaticExpr(c: PContext, n: PNode): PNode
proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType
proc semTypeOf(c: PContext; n: PNode): PNode
proc hasUnresolvedArgs(c: PContext, n: PNode): bool
proc isArrayConstr(n: PNode): bool {.inline.} =
result = n.kind == nkBracket and
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
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
template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
@@ -70,6 +73,16 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
# echo "passing to safeSemExpr: ", renderTree(n)
discard safeSemExpr(c, n)
proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode =
result = arg
let x = result.skipConv
if x.kind in {nkPar, nkTupleConstr} and formal.kind != tyExpr:
changeType(c, x, formal, check=true)
else:
result = skipHiddenSubConv(result)
#result.typ = takeType(formal, arg.typ)
#echo arg.info, " picked ", result.typ.typeToString
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
if arg.typ.isNil:
localError(c.config, arg.info, "expression has no type: " &
@@ -85,18 +98,12 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
result = copyTree(arg)
result.typ = formal
else:
let x = result.skipConv
if x.kind in {nkPar, nkTupleConstr} and formal.kind != tyExpr:
changeType(c, x, formal, check=true)
else:
result = skipHiddenSubConv(result)
#result.typ = takeType(formal, arg.typ)
#echo arg.info, " picked ", result.typ.typeToString
result = fitNodePostMatch(c, formal, result)
proc inferWithMetatype(c: PContext, formal: PType,
arg: PNode, coerceDistincts = false): PNode
var commonTypeBegin = PType(kind: tyExpr)
template commonTypeBegin*(): PType = PType(kind: tyExpr)
proc commonType*(x, y: PType): PType =
# new type relation that is used for array constructors,
@@ -183,7 +190,7 @@ proc commonType*(x: PType, y: PNode): PType =
commonType(x, y.typ)
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):
suggestDecl(c, n, result)
@@ -207,7 +214,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# template; we must fix it here: see #909
result.owner = getCurrOwner(c)
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:
# incl(result.flags, sfGlobal)
when defined(nimsuggest):
@@ -242,14 +249,14 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
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
result = newSym(skType, getIdent"AnonType", t.owner, info)
result = newSym(skType, getIdent(c.cache, "AnonType"), t.owner, info)
result.flags.incl sfAnon
result.typ = t
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)
when false:
@@ -310,13 +317,13 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
let oldErrorCount = c.config.errorCounter
let oldErrorMax = c.config.errorMax
let oldErrorOutputs = errorOutputs
let oldErrorOutputs = c.config.m.errorOutputs
errorOutputs = {}
c.config.m.errorOutputs = {}
c.config.errorMax = high(int)
try:
result = evalConstExpr(c.module, c.cache, c.graph, e)
result = evalConstExpr(c.module, c.graph, e)
if result == nil or result.kind == nkEmpty:
result = nil
else:
@@ -327,7 +334,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
c.config.errorCounter = oldErrorCount
c.config.errorMax = oldErrorMax
errorOutputs = oldErrorOutputs
c.config.m.errorOutputs = oldErrorOutputs
const
errConstExprExpected = "constant expression expected"
@@ -340,12 +347,12 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
result = getConstExpr(c.module, e, c.graph)
if result == nil:
#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 e.info != n.info:
pushInfoContext(n.info)
pushInfoContext(c.config, n.info)
localError(c.config, e.info, errConstExprExpected)
popInfoContext()
popInfoContext(c.config)
else:
localError(c.config, e.info, errConstExprExpected)
# error correction:
@@ -383,8 +390,8 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
## coherence, making sure that variables declared with 'let' aren't
## reassigned, and binding the unbound identifiers that the macro output
## contains.
inc(evalTemplateCounter)
if evalTemplateCounter > evalTemplateLimit:
inc(c.config.evalTemplateCounter)
if c.config.evalTemplateCounter > evalTemplateLimit:
globalError(c.config, s.info, "template instantiation too nested")
c.friendModules.add(s.owner.getModule)
@@ -423,8 +430,8 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
result = semExpr(c, result, flags)
result = fitNode(c, retType, result, result.info)
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
dec(evalTemplateCounter)
#globalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
dec(c.config.evalTemplateCounter)
discard c.friendModules.pop()
const
@@ -432,7 +439,7 @@ const
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode =
pushInfoContext(nOrig.info)
pushInfoContext(c.config, nOrig.info)
markUsed(c.config, n.info, sym, c.graph.usageSym)
styleCheckUse(n.info, sym)
@@ -448,11 +455,11 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
#if c.evalContext == nil:
# 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:
result = semAfterMacroCall(c, n, result, sym, flags)
result = wrapInComesFrom(nOrig.info, sym, result)
popInfoContext()
popInfoContext(c.config)
proc forceBool(c: PContext, n: PNode): PNode =
result = fitNode(c, getSysType(c.graph, n.info, tyBool), n, n.info)
@@ -484,8 +491,8 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
addSon(n, prc.ast)
c.lastGenericIdx = c.generics.len
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
var c = newContext(graph, module, cache)
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var c = newContext(graph, module)
if c.p != nil: internalError(graph.config, module.info, "sem.myOpen")
c.semConstExpr = semConstExpr
c.semExpr = semExpr
@@ -507,19 +514,13 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
graph.systemModule = module
c.topLevelScope = openScope(c)
# 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
else:
if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
graph.config.notes = graph.config.foreignPackageNotes
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 =
if g.systemModule == nil: return false
case n.kind
@@ -585,31 +586,31 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
if c.config.errorMax <= 1:
result = semStmtAndGenerateGenerics(c, n)
else:
let oldContextLen = msgs.getInfoContextLen()
let oldContextLen = msgs.getInfoContextLen(c.config)
let oldInGenericInst = c.inGenericInst
try:
result = semStmtAndGenerateGenerics(c, n)
except ERecoverableError, ESuggestDone:
recoverContext(c)
c.inGenericInst = oldInGenericInst
msgs.setInfoContextLen(oldContextLen)
msgs.setInfoContextLen(c.config, oldContextLen)
if getCurrentException() of ESuggestDone:
c.suggestionsMade = true
result = nil
else:
result = ast.emptyNode
result = newNodeI(nkEmpty, n.info)
#if c.config.cmd == cmdIdeTools: findSuggest(c, n)
rod.storeNode(c.module, result)
rod.storeNode(c.graph, c.module, result)
proc testExamples(c: PContext) =
let inp = toFullPath(c.module.info)
let inp = toFullPath(c.config, c.module.info)
let outp = inp.changeFileExt"" & "_examples.nim"
renderModule(c.runnableExamples, inp, outp)
let backend = if isDefined(c.config, "js"): "js"
elif isDefined(c.config, "cpp"): "cpp"
elif isDefined(c.config, "objc"): "objc"
else: "c"
if os.execShellCmd("nim " & backend & " -r " & outp) != 0:
if os.execShellCmd(os.getAppFilename() & " " & backend & " -r " & outp) != 0:
quit "[Examples] failed"
removeFile(outp)
@@ -625,12 +626,10 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
addCodeForGenerics(c, result)
if c.module.ast != nil:
result.add(c.module.ast)
if c.rd != nil:
replayMethodDefs(graph, c.rd)
popOwner(c)
popProcCon(c)
storeRemaining(c.module)
storeRemaining(c.graph, c.module)
if c.runnableExamples != nil: testExamples(c)
const semPass* = makePass(myOpen, myOpenCached, myProcess, myClose,
const semPass* = makePass(myOpen, myProcess, myClose,
isFrontend = true)

View File

@@ -157,12 +157,12 @@ proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
proc addVar(father, v, value: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart.sons[0] = v
vpart.sons[1] = ast.emptyNode
vpart.sons[1] = newNodeI(nkEmpty, v.info)
vpart.sons[2] = value
addSon(father, vpart)
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)
incl(temp.flags, sfFromGeneric)
@@ -207,7 +207,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if t.kind == tySequence:
# XXX add 'nil' handling here
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 elemType = t.lastSon
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
let body = newNodeI(nkStmtList, info)
let procname = case kind
of attachedAsgn: getIdent"="
of attachedSink: getIdent"=sink"
of attachedDeepCopy: getIdent"=deepcopy"
of attachedDestructor: getIdent"=destroy"
of attachedAsgn: getIdent(c.cache, "=")
of attachedSink: getIdent(c.cache, "=sink")
of attachedDeepCopy: getIdent(c.cache, "=deepcopy")
of attachedDestructor: getIdent(c.cache, "=destroy")
result = newSym(skProc, procname, typ.owner, info)
a.fn = result
a.asgnForType = typ
let dest = newSym(skParam, getIdent"dest", result, info)
let src = newSym(skParam, getIdent"src", result, info)
let dest = newSym(skParam, getIdent(c.cache, "dest"), result, info)
let src = newSym(skParam, getIdent(c.cache, "src"), result, info)
dest.typ = makeVarType(c, typ)
src.typ = typ
@@ -297,7 +297,7 @@ proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp;
of attachedDestructor: typ.destructor = result
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[paramsPos] = result.typ.n
n.sons[bodyPos] = body

View File

@@ -170,7 +170,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
add(candidates, renderTree(err.sym.ast,
{renderNoBody, renderNoComments, renderNoPragmas}))
else:
add(candidates, err.sym.getProcHeader(prefer))
add(candidates, getProcHeader(c.config, err.sym, prefer))
add(candidates, "\n")
if err.firstMismatch != 0 and n.len > 1:
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,
# as semOverlodedCall is already pretty slow (and we need this information
# only in case of an error).
if errorOutputs == {}:
if c.config.m.errorOutputs == {}:
# fail fast:
globalError(c.config, n.info, "type mismatch")
if errors.len == 0:
@@ -293,7 +293,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
orig.sons[0..1] = [nil, orig[1], f]
template tryOp(x) =
let op = newIdentNode(getIdent(x), n.info)
let op = newIdentNode(getIdent(c.cache, x), n.info)
n.sons[0] = op
orig.sons[0] = 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:
# we need to strip away the trailing '=' here:
let calleeName = newIdentNode(getIdent(f.ident.s[0..f.ident.s.len-2]), n.info)
let callOp = newIdentNode(getIdent".=", n.info)
let calleeName = newIdentNode(getIdent(c.cache, f.ident.s[0..f.ident.s.len-2]), n.info)
let callOp = newIdentNode(getIdent(c.cache, ".="), n.info)
n.sons[0..1] = [callOp, n[1], calleeName]
orig.sons[0..1] = [callOp, orig[1], calleeName]
pickBest(callOp)
if overloadsState == csEmpty and result.state == csEmpty:
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:
localError(c.config, n.info, errUndeclaredRoutine % considerQuotedIdent(c.config, f, n).s)
localError(c.config, n.info, errUndeclaredRoutine % considerQuotedIdent(c, f, n).s)
return
elif result.state != csMatch:
if nfExprCall in n.flags:
@@ -333,7 +333,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
internalAssert c.config, result.state == csMatch
#writeMatches(result)
#writeMatches(alt)
if errorOutputs == {}:
if c.config.m.errorOutputs == {}:
# quick error message for performance of 'compiles' built-in:
globalError(c.config, n.info, errGenerated, "ambiguous call")
elif c.config.errorCounter == 0:
@@ -345,7 +345,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
add(args, ")")
localError(c.config, n.info, errAmbiguousCallXYZ % [
getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym),
getProcHeader(c.config, result.calleeSym),
getProcHeader(c.config, alt.calleeSym),
args])
proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
@@ -390,7 +391,23 @@ proc inferWithMetatype(c: PContext, formal: PType,
result = copyTree(arg)
result.typ = formal
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
proc updateDefaultParams(call: PNode) =
# In generic procs, the default parameter may be unique for each
# instantiation (see tlateboundgenericparams).
# After a call is resolved, we need to re-assign any default value
# that was used during sigmatch. sigmatch is responsible for marking
# the default params with `nfDefaultParam` and `instantiateProcType`
# computes correctly the default values for each instantiation.
let calleeParams = call[0].sym.typ.n
for i in countdown(call.len - 1, 1):
if nfDefaultParam notin call[i].flags:
return
let def = calleeParams[i].sym.ast
if nfDefaultRefsParam in def.flags: call.flags.incl nfDefaultRefsParam
call[i] = def
proc semResolvedCall(c: PContext, x: TCandidate,
n: PNode, flags: TExprFlags): PNode =
assert x.state == csMatch
var finalCallee = x.calleeSym
markUsed(c.config, n.sons[0].info, finalCallee, c.graph.usageSym)
@@ -423,8 +440,9 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
result = x.call
instGenericConvertersSons(c, result, x)
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
result[0] = newSymNode(finalCallee, result[0].info)
result.typ = finalCallee.typ.sons[0]
updateDefaultParams(result)
proc canDeref(n: PNode): bool {.inline.} =
result = n.len >= 2 and (let t = n[1].typ;
@@ -446,7 +464,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
message(c.config, n.info, hintUserRaw,
"Non-matching candidates for " & renderTree(n) & "\n" &
candidates)
result = semResolvedCall(c, n, r)
result = semResolvedCall(c, r, n, flags)
elif implicitDeref in c.features and canDeref(n):
# try to deref the first argument and then try overloading resolution again:
#
@@ -457,7 +475,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
#
n.sons[1] = n.sons[1].tryDeref
var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
if r.state == csMatch: result = semResolvedCall(c, n, r)
if r.state == csMatch: result = semResolvedCall(c, r, n, flags)
else:
# get rid of the deref again for a better error message:
n.sons[1] = n.sons[1].sons[0]

View File

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

View File

@@ -26,10 +26,13 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
flags: TExprFlags = {}): PNode =
markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s)
pushInfoContext(n.info)
pushInfoContext(c.config, n.info)
result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in 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
@@ -58,7 +61,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# do not produce another redundant error message:
#raiseRecoverableError("")
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 %
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
@@ -137,7 +140,7 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
else:
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.
## Casting is very unrestrictive; casts are allowed as long as
## castDest.size >= src.size, and typeAllowed(dst, skParam)
@@ -152,8 +155,8 @@ proc isCastable(dst, src: PType): bool =
return false
var dstSize, srcSize: BiggestInt
dstSize = computeSize(dst)
srcSize = computeSize(src)
dstSize = computeSize(conf, dst)
srcSize = computeSize(conf, src)
if dstSize < 0:
result = false
elif srcSize < 0:
@@ -167,7 +170,7 @@ proc isCastable(dst, src: PType): bool =
(skipTypes(dst, abstractInst).kind in IntegralTypes) or
(skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
if result and src.kind == tyNil:
result = dst.size <= platform.ptrSize
result = dst.size <= conf.target.ptrSize
proc isSymChoice(n: PNode): bool {.inline.} =
result = n.kind in nkSymChoices
@@ -188,7 +191,25 @@ proc semConv(c: PContext, n: PNode): PNode =
return n
result = newNodeI(nkConv, n.info)
var targetType = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
var targetType = semTypeNode(c, n.sons[0], nil)
if targetType.kind == tyTypeDesc:
internalAssert c.config, targetType.len > 0
if targetType.base.kind == tyNone:
return semTypeOf(c, n[1])
else:
targetType = targetType.base
elif targetType.kind == tyStatic:
var evaluated = semStaticExpr(c, n[1])
if evaluated.kind == nkType or evaluated.typ.kind == tyTypeDesc:
result = n
result.typ = c.makeTypeDesc semStaticType(c, evaluated, nil)
return
elif targetType.base.kind == tyNone:
return evaluated
else:
targetType = targetType.base
maybeLiftType(targetType, c, n[0].info)
if targetType.kind in {tySink, tyLent}:
@@ -251,7 +272,7 @@ proc semCast(c: PContext, n: PNode): PNode =
let castedExpr = semExprWithType(c, n.sons[1])
if tfHasMeta in targetType.flags:
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 alt = typeToString(targetType, preferDesc)
let msg = if tar != alt: tar & "=" & alt else: tar
@@ -268,7 +289,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
localError(c.config, n.info, errXExpectsTypeOrValue % opToStr[m])
else:
n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc})
var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc, tyUserTypeClassInst})
case typ.kind
of tySequence, tyString, tyCString, tyOpenArray, tyVarargs:
n.typ = getSysType(c.graph, n.info, tyInt)
@@ -295,57 +316,98 @@ proc semSizeof(c: PContext, n: PNode): PNode =
n.typ = getSysType(c.graph, n.info, tyInt)
result = n
proc fixupStaticType(c: PContext, n: PNode) =
# This proc can be applied to evaluated expressions to assign
# them a static type.
#
# XXX: with implicit static, this should not be necessary,
# because the output type of operations such as `semConstExpr`
# should be a static type (as well as the type of any other
# expression that can be implicitly evaluated). For now, we
# apply this measure only in code that is enlightened to work
# with static types.
if n.typ.kind != tyStatic:
n.typ = newTypeWithSons(getCurrOwner(c), tyStatic, @[n.typ])
n.typ.n = n # XXX: cycles like the one here look dangerous.
# Consider using `n.copyTree`
proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
internalAssert c.config, n.sonsLen == 3 and
n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
internalAssert c.config,
n.sonsLen == 3 and
n[1].typ != nil and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = n[1].typ.skipTypes({tyTypeDesc})
var
res = false
t1 = n[1].typ
t2 = n[2].typ
if t1.kind == tyTypeDesc and t2.kind != tyTypeDesc:
t1 = t1.base
if n[2].kind in {nkStrLit..nkTripleStrLit}:
case n[2].strVal.normalize
of "closure":
let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and
tfIterator notin t.flags))
res = t.kind == tyProc and
t.callConv == ccClosure and
tfIterator notin t.flags
else:
result = newIntNode(nkIntLit, 0)
res = false
else:
var rhsOrigType = n[2].typ
var t2 = rhsOrigType.skipTypes({tyTypeDesc})
maybeLiftType(t2, c, n.info)
var m: TCandidate
initCandidate(c, m, t2)
if efExplain in flags:
m.diagnostics = @[]
m.diagnosticsEnabled = true
let match = typeRel(m, t2, t1) >= isSubtype # isNone
result = newIntNode(nkIntLit, ord(match))
res = typeRel(m, t2, t1) >= isSubtype # isNone
result = newIntNode(nkIntLit, ord(res))
result.typ = n.typ
proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
if sonsLen(n) != 3:
localError(c.config, n.info, "'is' operator takes 2 arguments")
let boolType = getSysType(c.graph, n.info, tyBool)
result = n
n.typ = getSysType(c.graph, n.info, tyBool)
n.typ = boolType
var liftLhs = true
n.sons[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator})
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
let t2 = semTypeNode(c, n[2], nil)
n.sons[2] = newNodeIT(nkType, n[2].info, t2)
if t2.kind == tyStatic:
let evaluated = tryConstExpr(c, n[1])
if evaluated != nil:
c.fixupStaticType(evaluated)
n[1] = evaluated
else:
result = newIntNode(nkIntLit, 0)
result.typ = boolType
return
elif t2.kind == tyTypeDesc and
(t2.base.kind == tyNone or tfExplicit in t2.flags):
# When the right-hand side is an explicit type, we must
# not allow regular values to be matched against the type:
liftLhs = false
let lhsType = n[1].typ
var lhsType = n[1].typ
if lhsType.kind != tyTypeDesc:
n.sons[1] = makeTypeSymNode(c, lhsType, n[1].info)
elif lhsType.base.kind == tyNone:
# this is a typedesc variable, leave for evals
return
if liftLhs:
n[1] = makeTypeSymNode(c, lhsType, n[1].info)
lhsType = n[1].typ
else:
if lhsType.base.kind == tyNone:
# this is a typedesc variable, leave for evals
return
if lhsType.base.containsGenericType:
# BUGFIX: don't evaluate this too early: ``T is void``
return
# BUGFIX: don't evaluate this too early: ``T is void``
if not n[1].typ.base.containsGenericType: result = isOpImpl(c, n, flags)
result = isOpImpl(c, n, flags)
proc semOpAux(c: PContext, n: PNode) =
const flags = {efDetermineType}
@@ -353,7 +415,7 @@ proc semOpAux(c: PContext, n: PNode) =
var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
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.typ = a.sons[1].typ
else:
@@ -361,7 +423,7 @@ proc semOpAux(c: PContext, n: PNode) =
proc overloadedCallOpr(c: PContext, n: PNode): PNode =
# quick check if there is *any* () operator overloaded:
var par = getIdent("()")
var par = getIdent(c.cache, "()")
if searchInScopes(c, par) == nil:
result = nil
else:
@@ -407,7 +469,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
of nkCharLit..nkUInt64Lit:
if check and n.kind != nkUInt64Lit:
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 &
" to " & typeToString(newType))
else: discard
@@ -480,6 +542,36 @@ proc fixAbstractType(c: PContext, n: PNode) =
proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult =
result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
proc isUnresolvedSym(s: PSym): bool =
return s.kind == skGenericParam or
tfInferrableStatic in s.typ.flags or
(s.kind == skParam and s.typ.isMetaType) or
(s.kind == skType and
s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
proc hasUnresolvedArgs(c: PContext, n: PNode): bool =
# Checks whether an expression depends on generic parameters that
# don't have bound values yet. E.g. this could happen in situations
# such as:
# type Slot[T] = array[T.size, byte]
# proc foo[T](x: default(T))
#
# Both static parameter and type parameters can be unresolved.
case n.kind
of nkSym:
return isUnresolvedSym(n.sym)
of nkIdent, nkAccQuoted:
let ident = considerQuotedIdent(c, n)
let sym = searchInScopes(c, ident)
if sym != nil:
return isUnresolvedSym(sym)
else:
return false
else:
for i in 0..<n.safeLen:
if hasUnresolvedArgs(c, n.sons[i]): return true
return false
proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
if n.kind == nkHiddenDeref and not (c.config.cmd == cmdCompileToCpp or
sfCompileToCpp in c.module.flags):
@@ -617,24 +709,24 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
call.add(a)
#echo "NOW evaluating at compile time: ", call.renderTree
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:
localError(c.config, n.info, errCannotInterpretNodeX % renderTree(call))
else: result = fixupTypeAfterEval(c, result, n)
else:
result = evalConstExpr(c.module, c.cache, c.graph, call)
result = evalConstExpr(c.module, c.graph, call)
if result.isNil: result = n
else: result = fixupTypeAfterEval(c, result, n)
#if result != n:
# echo "SUCCESS evaluated at compile time: ", call.renderTree
proc semStaticExpr(c: PContext, n: PNode): PNode =
let a = semExpr(c, n.sons[0])
let a = semExpr(c, n)
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:
localError(c.config, n.info, errCannotInterpretNodeX % renderTree(n))
result = emptyNode
result = c.graph.emptyNode
else:
result = fixupTypeAfterEval(c, result, a)
@@ -742,10 +834,10 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# This is a proc variable, apply normal overload resolution
let m = resolveIndirectCall(c, n, nOrig, t)
if m.state != csMatch:
if errorOutputs == {}:
if c.config.m.errorOutputs == {}:
# speed up error generation:
globalError(c.config, n.info, "type mismatch")
return emptyNode
return c.graph.emptyNode
else:
var hasErrorType = false
var msg = "type mismatch: got <"
@@ -765,6 +857,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
result = m.call
instGenericConvertersSons(c, result, m)
elif t != nil and t.kind == tyTypeDesc:
if n.len == 1: return semObjConstr(c, n, flags)
return semConv(c, n)
@@ -802,7 +895,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc buildEchoStmt(c: PContext, n: PNode): PNode =
# we MUST not check 'n' for semantics again here! But for now we give up:
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:
add(result, newSymNode(e))
else:
@@ -866,7 +959,7 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
else:
if check == nil:
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)
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))
@@ -881,7 +974,7 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
if result != nil:
if check == nil:
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))
addSon(inExpr, newSymNode(c.graph.opContains, n.info))
addSon(inExpr, s)
@@ -938,7 +1031,7 @@ proc readTypeParameter(c: PContext, typ: PType,
if rawTyp.n != nil:
return rawTyp.n
else:
return emptyNode
return c.graph.emptyNode
else:
let foundTyp = makeTypeDesc(c, rawTyp)
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
@@ -1031,7 +1124,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
of skType:
markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s)
if s.typ.kind == tyStatic and s.typ.n != nil:
if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
return s.typ.n
result = newSymNode(s, n.info)
result.typ = makeTypeDesc(c, s.typ)
@@ -1082,7 +1175,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
when defined(nimsuggest):
if c.config.cmd == cmdIdeTools:
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})
if s != nil:
@@ -1097,7 +1190,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
#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 f: PSym = nil
result = nil
@@ -1106,7 +1199,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
case t.kind
of tyTypeParamsHolders:
result = readTypeParameter(c, t, i, n.info)
if result == emptyNode:
if result == c.graph.emptyNode:
result = n
n.typ = makeTypeFromExpr(c, n.copyTree)
return
@@ -1217,7 +1310,7 @@ proc dotTransformation(c: PContext, n: PNode): PNode =
addSon(result, n.sons[1])
addSon(result, copyTree(n[0]))
else:
var i = considerQuotedIdent(c.config, n.sons[1], n)
var i = considerQuotedIdent(c, n.sons[1], n)
result = newNodeI(nkDotCall, n.info)
result.flags.incl nfDotField
addSon(result, newIdentNode(i, n[1].info))
@@ -1258,8 +1351,18 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
# make sure we don't evaluate generic macros/templates
n.sons[0] = semExprWithType(c, n.sons[0],
{efNoEvaluateGeneric})
let arr = skipTypes(n.sons[0].typ, {tyGenericInst,
var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyUserTypeClassInst,
tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink})
if arr.kind == tyStatic:
if arr.base.kind == tyNone:
result = n
result.typ = semStaticType(c, n[1], nil)
return
elif arr.n != nil:
return semSubscript(c, arr.n, flags)
else:
arr = arr.base
case arr.kind
of tyArray, tyOpenArray, tyVarargs, tySequence, tyString,
tyCString:
@@ -1328,11 +1431,11 @@ proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = semSubscript(c, n, flags)
if result == nil:
# 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 =
var id = considerQuotedIdent(c.config, a[1], a)
var setterId = newIdentNode(getIdent(id.s & '='), n.info)
var id = considerQuotedIdent(c, a[1], a)
var setterId = newIdentNode(getIdent(c.cache, id.s & '='), n.info)
# a[0] is already checked for semantics, that does ``builtinFieldAccess``
# this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
# nodes?
@@ -1409,7 +1512,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
# --> `[]=`(a, i, x)
a = semSubscript(c, a, {efLValue})
if a == nil:
result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
result = buildOverloadedSubscripts(n.sons[0], getIdent(c.cache, "[]="))
add(result, n[1])
if mode == noOverloadedSubscript:
bracketNotFoundError(c, result)
@@ -1419,7 +1522,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
return result
of nkCurlyExpr:
# a{i} = x --> `{}=`(a, i, x)
result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=")
result = buildOverloadedSubscripts(n.sons[0], getIdent(c.cache, "{}="))
add(result, n[1])
return semExprNoType(c, result)
of nkPar, nkTupleConstr:
@@ -1427,7 +1530,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
# unfortunately we need to rewrite ``(x, y) = foo()`` already here so
# that overloading of the assignment operator still works. Usually we
# 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:
a = semExprWithType(c, a, {efLValue})
else:
@@ -1450,7 +1553,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
rhs = semExprWithType(c, n.sons[1],
if lhsIsResult: {efAllowDestructor} else: {})
if lhsIsResult:
n.typ = enforceVoidContext
n.typ = c.enforceVoidContext
if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ):
var rhsTyp = rhs.typ
if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass:
@@ -1489,7 +1592,7 @@ proc semReturn(c: PContext, n: PNode): PNode =
n.sons[0] = semAsgn(c, a)
# optimize away ``result = result``:
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:
localError(c.config, n.info, errNoReturnTypeDeclared)
else:
@@ -1556,8 +1659,6 @@ proc semYield(c: PContext, n: PNode): PNode =
checkSonsLen(n, 1, c.config)
if c.p.owner == nil or c.p.owner.kind != skIterator:
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:
n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility:
var iterType = c.p.owner.typ
@@ -1593,13 +1694,13 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
checkSonsLen(n, 2, c.config)
var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope)
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:
result = strTableGet(c.topLevelScope.symbols, ident)
else:
result = strTableGet(m.tab, ident)
of nkAccQuoted:
result = lookUpForDefined(c, considerQuotedIdent(c.config, n), onlyCurrentScope)
result = lookUpForDefined(c, considerQuotedIdent(c, n), onlyCurrentScope)
of nkSym:
result = n.sym
of nkOpenSymChoice, nkClosedSymChoice:
@@ -1612,11 +1713,9 @@ proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
checkSonsLen(n, 2, c.config)
# we replace this node by a 'true' or 'false' node:
result = newIntNode(nkIntLit, 0)
if not onlyCurrentScope and considerQuotedIdent(c.config, n[0], n).s == "defined":
if n.sons[1].kind != nkIdent:
localError(c.config, n.info, "obsolete usage of 'defined', use 'declared' instead")
elif isDefined(c.config, n.sons[1].ident.s):
result.intVal = 1
if not onlyCurrentScope and considerQuotedIdent(c, n[0], n).s == "defined":
let d = considerQuotedIdent(c, n[1], n)
result.intVal = ord isDefined(c.config, d.s)
elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil:
result.intVal = 1
result.info = n.info
@@ -1711,7 +1810,7 @@ proc processQuotations(c: PContext; n: var PNode, op: string,
ids: var seq[PNode]) =
template returnQuote(q) =
quotes.add q
n = newIdentNode(getIdent($quotes.len), n.info)
n = newIdentNode(getIdent(c.cache, $quotes.len), n.info)
ids.add n
return
@@ -1722,7 +1821,7 @@ proc processQuotations(c: PContext; n: var PNode, op: string,
if examinedOp == op:
returnQuote n[1]
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 == "``":
returnQuote n[0]
@@ -1748,14 +1847,17 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
processQuotations(c, quotedBlock, op, quotes, ids)
var dummyTemplate = newProcNode(
nkTemplateDef, quotedBlock.info, quotedBlock,
name = newAnonSym(c, skTemplate, n.info).newSymNode)
nkTemplateDef, quotedBlock.info, body = quotedBlock,
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:
dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
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 emptyNode # no default value
ids.add c.graph.emptyNode # no default value
dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids)
var tmpl = semTemplateDef(c, dummyTemplate)
@@ -1780,9 +1882,9 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
openScope(c)
let oldOwnerLen = len(c.graph.owners)
let oldGenerics = c.generics
let oldErrorOutputs = errorOutputs
if efExplain notin flags: errorOutputs = {}
let oldContextLen = msgs.getInfoContextLen()
let oldErrorOutputs = c.config.m.errorOutputs
if efExplain notin flags: c.config.m.errorOutputs = {}
let oldContextLen = msgs.getInfoContextLen(c.config)
let oldInGenericContext = c.inGenericContext
let oldInUnrolledContext = c.inUnrolledContext
@@ -1804,10 +1906,10 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
c.inGenericInst = oldInGenericInst
c.inStaticContext = oldInStaticContext
c.p = oldProcCon
msgs.setInfoContextLen(oldContextLen)
msgs.setInfoContextLen(c.config, oldContextLen)
setLen(c.graph.owners, oldOwnerLen)
c.currentScope = oldScope
errorOutputs = oldErrorOutputs
c.config.m.errorOutputs = oldErrorOutputs
c.config.errorCounter = oldErrorCount
c.config.errorMax = oldErrorMax
@@ -1913,7 +2015,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
result.typ = typ
result.add instantiateCreateFlowVarCall(c, typ, n.info).newSymNode
else:
result.add emptyNode
result.add c.graph.emptyNode
of mProcCall:
result = setMs(n, s)
result.sons[1] = semExpr(c, n.sons[1])
@@ -1937,17 +2039,17 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
of mRunnableExamples:
if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList:
if sfMainModule in c.module.flags:
let inp = toFullPath(c.module.info)
let inp = toFullPath(c.config, c.module.info)
if c.runnableExamples == nil:
c.runnableExamples = newTree(nkStmtList,
newTree(nkImportStmt, newStrNode(nkStrLit, expandFilename(inp))))
let imports = newTree(nkStmtList)
extractImports(n.lastSon, imports)
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)
else:
result = emptyNode
result = c.graph.emptyNode
else:
result = semDirectOp(c, n, flags)
@@ -2040,7 +2142,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
if not isOrdinalType(typ):
localError(c.config, n.info, errOrdinalTypeExpected)
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)
addSonSkipIntLit(result.typ, typ)
for i in countup(0, sonsLen(n) - 1):
@@ -2159,7 +2261,7 @@ proc semBlock(c: PContext, n: PNode): PNode =
addDecl(c, labl)
n.sons[0] = newSymNode(labl, n.sons[0].info)
suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
styleCheckDef(labl)
styleCheckDef(c.config, labl)
n.sons[1] = semExpr(c, n.sons[1])
n.typ = n.sons[1].typ
if isEmptyType(n.typ): n.kind = nkBlockStmt
@@ -2306,7 +2408,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# check if it is an expression macro:
checkMinSonsLen(n, 1, c.config)
#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}
var s = qualifiedLookUp(c, n.sons[0], mode)
if s != nil:
@@ -2363,12 +2465,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
checkMinSonsLen(n, 1, c.config)
result = semArrayAccess(c, n, flags)
of nkCurlyExpr:
result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags)
result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "{}")), flags)
of nkPragmaExpr:
var
expr = n[0]
pragma = n[1]
pragmaName = considerQuotedIdent(c.config, pragma[0])
pragmaName = considerQuotedIdent(c, pragma[0])
flags = flags
case whichKeyword(pragmaName)
@@ -2424,8 +2526,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# handling of sym choices is context dependent
# the node is left intact for now
discard
of nkStaticExpr:
result = semStaticExpr(c, n)
of nkStaticExpr: result = semStaticExpr(c, n[0])
of nkAsgn: result = semAsgn(c, n)
of nkBlockStmt, nkBlockExpr: result = semBlock(c, n)
of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)

View File

@@ -23,10 +23,10 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n
of nkIdent, nkSym:
result = n
let ident = considerQuotedIdent(c.c.config, n)
let ident = considerQuotedIdent(c.c, n)
var L = sonsLen(forLoop)
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
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
@@ -34,7 +34,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
return
# other fields:
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 tupl = call.sons[i+1-ord(c.replaceByFieldName)]
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
# a 'while true: stmt; break' loop ...
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:
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)
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:
if containsNode(stmts, {nkBreakStmt}):
var b = newNodeI(nkBreakStmt, n.info)
b.add(ast.emptyNode)
b.add(newNodeI(nkEmpty, n.info))
stmts.add(b)
else:
result = stmts

View File

@@ -13,7 +13,7 @@
import
strutils, options, ast, astalgo, trees, treetab, nimsets, times,
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 =
case skipTypes(n.typ, abstractVarRange).kind
@@ -53,24 +53,24 @@ proc getConstExpr*(m: PSym, n: PNode; g: ModuleGraph): PNode
# expression
proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode
proc checkInRange(n: PNode, res: BiggestInt): bool =
if res in firstOrd(n.typ)..lastOrd(n.typ):
proc checkInRange(conf: ConfigRef; n: PNode, res: BiggestInt): bool =
if res in firstOrd(conf, n.typ)..lastOrd(conf, n.typ):
result = true
proc foldAdd(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
let res = a +% b
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)
proc foldSub*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
let res = a -% b
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)
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)
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)
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)
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
# 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)
# 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
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and
checkInRange(n, res):
checkInRange(g.config, n, res):
return newIntNodeT(res, n, g)
proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
@@ -210,9 +210,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n, g)
of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g)
of mNot: result = newIntNodeT(1 - getInt(a), n, g)
of mCard: result = newIntNodeT(nimsets.cardSet(a), n, g)
of mBitnotI: result = newIntNodeT(not getInt(a), n, g)
of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n, g)
of mCard: result = newIntNodeT(nimsets.cardSet(g.config, a), n, g)
of mBitnotI:
case skipTypes(n.typ, abstractRange).kind
of tyUInt..tyUInt64:
result = newIntNodeT((not getInt(a)) and lastOrd(g.config, a.typ, fixedUnsigned=true), n, g)
else:
result = newIntNodeT(not getInt(a), n, g)
of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g)
of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
if a.kind == nkNilLit:
result = newIntNodeT(0, n, g)
@@ -229,7 +234,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
of mAbsI: result = foldAbs(getInt(a), n, g)
of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
# 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 mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g)
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g)
@@ -250,8 +255,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n, g)
of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n, g)
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n, g)
of tyInt64, tyInt, tyUInt..tyUInt64:
of tyInt64, tyInt:
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)
of tyUInt..tyUInt64:
result = newIntNodeT(`shl`(getInt(a), getInt(b)) and lastOrd(g.config, a.typ, fixedUnsigned=true), n, g)
else: internalError(g.config, n.info, "constant folding for shl")
of mShrI:
case skipTypes(n.typ, abstractRange).kind
@@ -304,21 +311,21 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
of mMulU: result = newIntNodeT(`*%`(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 mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n, g)
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n, g)
of mLeSet: result = newIntNodeT(ord(containsSets(g.config, a, b)), n, g)
of mEqSet: result = newIntNodeT(ord(equalSets(g.config, a, b)), n, g)
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:
result = nimsets.intersectSets(a, b)
result = nimsets.intersectSets(g.config, a, b)
result.info = n.info
of mPlusSet:
result = nimsets.unionSets(a, b)
result = nimsets.unionSets(g.config, a, b)
result.info = n.info
of mMinusSet:
result = nimsets.diffSets(a, b)
result = nimsets.diffSets(g.config, a, b)
result.info = n.info
of mSymDiffSet:
result = nimsets.symdiffSets(a, b)
result = nimsets.symdiffSets(g.config, a, b)
result.info = n.info
of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g)
of mInSet: result = newIntNodeT(ord(inSet(a, b)), n, g)
@@ -415,9 +422,9 @@ proc getAppType(n: PNode; g: ModuleGraph): PNode =
proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
var err = false
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:
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:
localError(g.config, n.info, "cannot convert " & $value &
" to " & typeToString(n.typ))
@@ -472,7 +479,7 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
else:
localError(g.config, n.info, "index out of bounds: " & $n)
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)]
else: localError(g.config, n.info, "index out of bounds: " & $n)
of nkStrLit..nkTripleStrLit:
@@ -547,11 +554,11 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
"yyyy-MM-dd"), n, g)
of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(),
"HH:mm:ss"), n, g)
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n, g)
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n, g)
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n, g)
of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n, g)
of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n, g)
of mCpuEndian: result = newIntNodeT(ord(CPU[g.config.target.targetCPU].endian), n, g)
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.targetOS].name), n, g)
of mHostCPU: result = newStrNodeT(platform.CPU[g.config.target.targetCPU].name.toLowerAscii, n, g)
of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.hostOS].name), n, g)
of mBuildCPU: result = newStrNodeT(platform.CPU[g.config.target.hostCPU].name.toLowerAscii, n, g)
of mAppType: result = getAppType(n, g)
of mNaN: result = newFloatNodeT(NaN, n, g)
of mInf: result = newFloatNodeT(Inf, n, g)
@@ -599,22 +606,22 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
return
of mSizeOf:
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")
result = nil
elif skipTypes(a.typ, typedescInst+{tyRange}).kind in
IntegralTypes+NilableTypes+{tySet}:
#{tyArray,tyObject,tyTuple}:
result = newIntNodeT(getSize(a.typ), n, g)
result = newIntNodeT(getSize(g.config, a.typ), n, g)
else:
result = nil
# XXX: size computation for complex types is still wrong
of mLow:
result = newIntNodeT(firstOrd(n.sons[1].typ), n, g)
result = newIntNodeT(firstOrd(g.config, n.sons[1].typ), n, g)
of mHigh:
if skipTypes(n.sons[1].typ, abstractVar).kind notin
if skipTypes(n.sons[1].typ, abstractVar+{tyUserTypeClassInst}).kind notin
{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:
var a = getArrayConstr(m, n.sons[1], g)
if a.kind == nkBracket:
@@ -630,7 +637,7 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
of mLengthArray:
# It doesn't matter if the argument is const or not for mLengthArray.
# 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:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g)
of mConStrStr:

View File

@@ -32,9 +32,12 @@ type
cursorInBody: bool # only for nimsuggest
bracketExpr: PNode
type
TSemGenericFlag = enum
withinBind, withinTypeDesc, withinMixin, withinConcept
withinBind,
withinTypeDesc,
withinMixin,
withinConcept
TSemGenericFlags = set[TSemGenericFlag]
proc semGenericStmt(c: PContext, n: PNode,
@@ -53,9 +56,16 @@ template macroToExpand(s): untyped =
template macroToExpandSym(s): untyped =
s.kind in {skMacro, skTemplate} and (s.typ.len == 1) and not fromDotExpr
template isMixedIn(sym): bool =
let s = sym
s.name.id in ctx.toMixin or (withinConcept in flags and
s.magic == mNone and
s.kind in OverloadableSyms)
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
ctx: var GenericCtx; fromDotExpr=false): PNode =
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
ctx: var GenericCtx; flags: TSemGenericFlags,
fromDotExpr=false): PNode =
semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
incl(s.flags, sfUsed)
case s.kind
of skUnknown:
@@ -103,7 +113,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var GenericCtx): PNode =
result = n
let ident = considerQuotedIdent(c.config, n)
let ident = considerQuotedIdent(c, n)
var s = searchInScopes(c, ident).skipAlias(n, c.config)
if s == nil:
s = strTableGet(c.pureEnumFields, ident)
@@ -115,10 +125,10 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
else:
if withinBind in flags:
result = symChoice(c, n, s, scClosed)
elif s.name.id in ctx.toMixin:
elif s.isMixedIn:
result = symChoice(c, n, s, scForceOpen)
else:
result = semGenericStmtSymbol(c, n, s, ctx)
result = semGenericStmtSymbol(c, n, s, ctx, flags)
# else: leave as nkIdent
proc newDot(n, b: PNode): PNode =
@@ -129,27 +139,27 @@ proc newDot(n, b: PNode): PNode =
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var GenericCtx; isMacro: var bool): PNode =
assert n.kind == nkDotExpr
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
let luf = if withinMixin notin flags: {checkUndeclared, checkModule} else: {checkModule}
var s = qualifiedLookUp(c, n, luf)
if s != nil:
result = semGenericStmtSymbol(c, n, s, ctx)
result = semGenericStmtSymbol(c, n, s, ctx, flags)
else:
n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
result = n
let n = n[1]
let ident = considerQuotedIdent(c.config, n)
let ident = considerQuotedIdent(c, n)
var s = searchInScopes(c, ident).skipAlias(n, c.config)
if s != nil and s.kind in routineKinds:
isMacro = s.kind in {skTemplate, skMacro}
if withinBind in flags:
result = newDot(result, symChoice(c, n, s, scClosed))
elif s.name.id in ctx.toMixin:
elif s.isMixedIn:
result = newDot(result, symChoice(c, n, s, scForceOpen))
else:
let syms = semGenericStmtSymbol(c, n, s, ctx, fromDotExpr=true)
let syms = semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true)
if syms.kind == nkSym:
let choice = symChoice(c, n, s, scForceOpen)
choice.kind = nkClosedSymChoice
@@ -160,7 +170,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
let s = newSymS(skUnknown, getIdentNode(c, n), c)
addPrelimDecl(c, s)
styleCheckDef(n.info, s, kind)
styleCheckDef(c.config, n.info, s, kind)
proc semGenericStmt(c: PContext, n: PNode,
flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
@@ -170,7 +180,7 @@ proc semGenericStmt(c: PContext, n: PNode,
if withinTypeDesc in flags: inc c.inTypeContext
#if conf.cmd == cmdIdeTools: suggestStmt(c, n)
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
case n.kind
of nkIdent, nkAccQuoted:
@@ -207,7 +217,7 @@ proc semGenericStmt(c: PContext, n: PNode,
if s == nil and
{withinMixin, withinConcept}*flags == {} 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)
var first = int ord(withinConcept in flags)
@@ -215,8 +225,7 @@ proc semGenericStmt(c: PContext, n: PNode,
if s != nil:
incl(s.flags, sfUsed)
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
let sc = symChoice(c, fn, s,
if s.name.id in ctx.toMixin: scForceOpen else: scOpen)
let sc = symChoice(c, fn, s, if s.isMixedIn: scForceOpen else: scOpen)
case s.kind
of skMacro:
if macroToExpand(s) and sc.safeLen <= 1:
@@ -275,12 +284,12 @@ proc semGenericStmt(c: PContext, n: PNode,
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
of nkCurlyExpr:
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])
result = semGenericStmt(c, result, flags, ctx)
of nkBracketExpr:
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])
withBracketExpr ctx, n.sons[0]:
result = semGenericStmt(c, result, flags, ctx)
@@ -293,13 +302,13 @@ proc semGenericStmt(c: PContext, n: PNode,
case k
of nkCurlyExpr:
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])
result.add(b)
result = semGenericStmt(c, result, flags, ctx)
of nkBracketExpr:
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])
result.add(b)
withBracketExpr ctx, a.sons[0]:
@@ -448,7 +457,7 @@ proc semGenericStmt(c: PContext, n: PNode,
flags, ctx)
if n.sons[paramsPos].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[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx)
var body: PNode
@@ -472,7 +481,6 @@ proc semGenericStmt(c: PContext, n: PNode,
when defined(nimsuggest):
if withinTypeDesc in flags: dec c.inTypeContext
proc semGenericStmt(c: PContext, n: PNode): PNode =
var ctx: GenericCtx
ctx.toMixin = initIntset()
@@ -484,3 +492,4 @@ proc semConceptBody(c: PContext, n: PNode): PNode =
ctx.toMixin = initIntset()
result = semGenericStmt(c, n, {withinConcept}, ctx)
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)

View File

@@ -159,13 +159,13 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
var oldPrc = c.generics[i].inst.sym
pushProcCon(c, oldPrc)
pushOwner(c, oldPrc)
pushInfoContext(oldPrc.info)
pushInfoContext(c.config, oldPrc.info)
openScope(c)
var n = oldPrc.ast
n.sons[bodyPos] = copyTree(s.getBody)
instantiateBody(c, n, oldPrc.typ.n, oldPrc, s)
closeScope(c)
popInfoContext()
popInfoContext(c.config)
popOwner(c)
popProcCon(c)
@@ -220,6 +220,14 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
result = replaceTypeVarsT(cl, header)
closeScope(c)
proc referencesAnotherParam(n: PNode, p: PSym): bool =
if n.kind == nkSym:
return n.sym.kind == skParam and n.sym.owner == p
else:
for i in 0..<n.safeLen:
if referencesAnotherParam(n[i], p): return true
return false
proc instantiateProcType(c: PContext, pt: TIdTable,
prc: PSym, info: TLineInfo) =
# XXX: Instantiates a generic proc signature, while at the same
@@ -236,7 +244,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
# at this point semtypinst have to become part of sem, because it
# will need to use openScope, addDecl, etc.
#addDecl(c, prc)
pushInfoContext(info)
pushInfoContext(c.config, info)
var typeMap = initLayeredTypeMap(pt)
var cl = initTypeVars(c, addr(typeMap), info, nil)
var result = instCopyType(cl, prc.typ)
@@ -247,25 +255,56 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
if i > 1:
resetIdTable(cl.symMap)
resetIdTable(cl.localCache)
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
propagateToOwner(result, result.sons[i])
internalAssert c.config, originalParams[i].kind == nkSym
when true:
let oldParam = originalParams[i].sym
let param = copySym(oldParam)
param.owner = prc
param.typ = result.sons[i]
if oldParam.ast != nil:
param.ast = fitNode(c, param.typ, oldParam.ast, oldParam.ast.info)
# don't be lazy here and call replaceTypeVarsN(cl, originalParams[i])!
result.n.sons[i] = newSymNode(param)
addDecl(c, param)
else:
let param = replaceTypeVarsN(cl, originalParams[i])
result.n.sons[i] = param
param.sym.owner = prc
addDecl(c, result.n.sons[i].sym)
# take a note of the original type. If't a free type or static parameter
# we'll need to keep it unbound for the `fitNode` operation below...
var typeToFit = result[i]
let needsStaticSkipping = result[i].kind == tyFromExpr
result[i] = replaceTypeVarsT(cl, result[i])
if needsStaticSkipping:
result[i] = result[i].skipTypes({tyStatic})
# ...otherwise, we use the instantiated type in `fitNode`
if (typeToFit.kind != tyTypeDesc or typeToFit.base.kind != tyNone) and
(typeToFit.kind != tyStatic):
typeToFit = result[i]
internalAssert c.config, originalParams[i].kind == nkSym
let oldParam = originalParams[i].sym
let param = copySym(oldParam)
param.owner = prc
param.typ = result[i]
# The default value is instantiated and fitted against the final
# concrete param type. We avoid calling `replaceTypeVarsN` on the
# call head symbol, because this leads to infinite recursion.
if oldParam.ast != nil:
var def = oldParam.ast.copyTree
if def.kind == nkCall:
for i in 1 ..< def.len:
def[i] = replaceTypeVarsN(cl, def[i])
def = semExprWithType(c, def)
if def.referencesAnotherParam(getCurrOwner(c)):
def.flags.incl nfDefaultRefsParam
var converted = indexTypesMatch(c, typeToFit, def.typ, def)
if converted == nil:
# The default value doesn't match the final instantiated type.
# As an example of this, see:
# https://github.com/nim-lang/Nim/issues/1201
# We are replacing the default value with an error node in case
# the user calls an explicit instantiation of the proc (this is
# the only way the default value might be inserted).
param.ast = errorNode(c, def)
else:
param.ast = fitNodePostMatch(c, typeToFit, converted)
param.typ = result[i]
result.n[i] = newSymNode(param)
propagateToOwner(result, result[i])
addDecl(c, param)
resetIdTable(cl.symMap)
resetIdTable(cl.localCache)
@@ -278,7 +317,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
skipIntLiteralParams(result)
prc.typ = result
popInfoContext()
popInfoContext(c.config)
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym =
@@ -309,7 +348,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
let gp = n.sons[genericParamsPos]
internalAssert c.config, gp.kind != nkEmpty
n.sons[namePos] = newSymNode(result)
pushInfoContext(info)
pushInfoContext(c.config, info)
var entry = TInstantiation.new
entry.sym = result
# we need to compare both the generic types and the concrete types:
@@ -328,7 +367,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
inc i
if tfTriggersCompileTime in result.typ.flags:
incl(result.flags, sfCompileTime)
n.sons[genericParamsPos] = ast.emptyNode
n.sons[genericParamsPos] = c.graph.emptyNode
var oldPrc = genericCacheGet(fn, entry[], c.compilesContextId)
if oldPrc == nil:
# we MUST not add potentially wrong instantiations to the caching mechanism.
@@ -353,7 +392,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
else:
result = oldPrc
popProcCon(c)
popInfoContext()
popInfoContext(c.config)
closeScope(c) # close scope for parameters
popOwner(c)
c.currentScope = oldScope

View File

@@ -41,7 +41,7 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
result = semSubscript(c, result, flags)
if result.isNil:
let x = copyTree(n)
x.sons[0] = newIdentNode(getIdent"[]", n.info)
x.sons[0] = newIdentNode(getIdent(c.cache, "[]"), n.info)
bracketNotFoundError(c, x)
#localError(c.config, n.info, "could not resolve: " & $n)
result = n
@@ -76,9 +76,9 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
result = newNodeIT(nkTupleConstr, n.info, n.typ)
let idx = expectIntLit(c, n.sons[1])
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))
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))
line.intVal = toLinenumber(info)
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)
else:
localError(c.config, traitCall.info, "unknown trait")
result = emptyNode
result = newNodeI(nkEmpty, traitCall.info)
proc semTypeTraits(c: PContext, n: PNode): PNode =
checkMinSonsLen(n, 2, c.config)
@@ -174,7 +174,7 @@ proc semOrd(c: PContext, n: PNode): PNode =
if isOrdinalType(parType):
discard
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:
localError(c.config, n.info, errOrdinalTypeExpected)
result.typ = errorType(c)
@@ -194,7 +194,7 @@ proc semBindSym(c: PContext, n: PNode): PNode =
localError(c.config, n.sons[2].info, errConstExprExpected)
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})
if s != nil:
# 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 isStrangeArray(t: PType): bool =
let t = t.skipTypes(abstractInst)
result = t.kind == tyArray and t.firstOrd != 0
proc semOf(c: PContext, n: PNode): PNode =
if sonsLen(n) == 3:
n.sons[1] = semExprWithType(c, n.sons[1])
@@ -283,7 +279,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mRoof:
localError(c.config, n.info, "builtin roof operator is not supported anymore")
of mPlugin:
let plugin = getPlugin(n[0].sym)
let plugin = getPlugin(c.cache, n[0].sym)
if plugin.isNil:
localError(c.config, n.info, "cannot find plugin " & n[0].sym.name.s)
result = n

View File

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

View File

@@ -136,8 +136,8 @@ proc checkLe(c: AnalysisCtx; a, b: PNode) =
localError(c.graph.config, a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)")
proc checkBounds(c: AnalysisCtx; arr, idx: PNode) =
checkLe(c, arr.lowBound, idx)
checkLe(c, idx, arr.highBound(c.guards.o))
checkLe(c, lowBound(c.graph.config, arr), idx)
checkLe(c, idx, highBound(c.graph.config, arr, c.guards.o))
proc addLowerBoundAsFacts(c: var AnalysisCtx) =
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]
if spawnResult(t, true) == srByVar:
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:
it.sons[it.len-1] = wrapProcForSpawn(g, owner, m, b.typ, barrier, nil)
if result.isNil: result = n
@@ -483,7 +483,7 @@ proc liftParallel*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
checkArgs(a, body)
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
incl(temp.flags, sfFromGeneric)
let tempNode = newSymNode(temp)

View File

@@ -9,7 +9,7 @@
import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
wordrecg, strutils, options, guards, writetracking, configuration,
wordrecg, strutils, options, guards, writetracking, lineinfos,
modulegraphs
when defined(useDfa):
@@ -185,7 +185,7 @@ proc markGcUnsafe(a: PEffects; reason: PNode) =
if reason.kind == nkSym:
a.owner.gcUnsafetyReason = reason.sym
else:
a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name,
a.owner, reason.info, {})
when true:
@@ -410,7 +410,7 @@ proc effectSpec(n: PNode, effectType: TSpecialWord): PNode =
result.add(it.sons[1])
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)
if isNil(spec):
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:
var t = typeToString(real[i].typ)
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:
effects.sons[i].typ = real[i].typ
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 params = s.typ.n
@@ -442,21 +442,21 @@ proc documentWriteEffect(n: PNode; flag: TSymFlag; pragmaName: string): PNode =
if effects.len > 0:
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
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
let pragmas = n.sons[pragmasPos]
let p1 = documentEffect(n, pragmas, wRaises, exceptionEffects)
let p2 = documentEffect(n, pragmas, wTags, tagEffects)
let p3 = documentWriteEffect(n, sfWrittenTo, "writes")
let p4 = documentNewEffect(n)
let p5 = documentWriteEffect(n, sfEscapes, "escapes")
let p1 = documentEffect(cache, n, pragmas, wRaises, exceptionEffects)
let p2 = documentEffect(cache, n, pragmas, wTags, tagEffects)
let p3 = documentWriteEffect(cache, n, sfWrittenTo, "writes")
let p4 = documentNewEffect(cache, n)
let p5 = documentWriteEffect(cache, n, sfEscapes, "escapes")
if p1 != nil or p2 != nil or p3 != nil or p4 != nil or p5 != nil:
if pragmas.kind == nkEmpty:
@@ -859,9 +859,9 @@ proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool
used.incl(s)
break search
# 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))
popInfoContext()
popInfoContext(g.config)
# hint about unnecessarily listed exception types:
if hints:
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)
effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
effects.sons[usesEffects] = ast.emptyNode
effects.sons[writeEffects] = ast.emptyNode
effects.sons[usesEffects] = g.emptyNode
effects.sons[writeEffects] = g.emptyNode
t.exc = effects.sons[exceptionEffects]
t.tags = effects.sons[tagEffects]

View File

@@ -36,8 +36,6 @@ const
errRecursiveDependencyX = "recursive dependency: '$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 =
result = n
checkSonsLen(n, 1, c.config)
@@ -87,15 +85,15 @@ proc semWhile(c: PContext, n: PNode): PNode =
n.sons[1] = semStmt(c, n.sons[1])
dec(c.p.nestedLoopCounter)
closeScope(c)
if n.sons[1].typ == enforceVoidContext:
result.typ = enforceVoidContext
if n.sons[1].typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext
proc toCover(t: PType): BiggestInt =
var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
proc toCover(c: PContext, t: PType): BiggestInt =
let t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
if t2.kind == tyEnum and enumHasHoles(t2):
result = sonsLen(t2.n)
else:
result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
result = lengthOrd(c.config, skipTypes(t, abstractVar-{tyTypeDesc}))
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"
if result.info.line != n.info.line or
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:
s.add "; for a function call use ()"
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)
result.kind = nkIfStmt
# propagate any enforced VoidContext:
if typ == enforceVoidContext: result.typ = enforceVoidContext
if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext
else:
for it in n:
let j = it.len-1
@@ -203,7 +201,7 @@ proc semCase(c: PContext, n: PNode): PNode =
for i in countup(1, sonsLen(n) - 1):
var x = n.sons[i]
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)
case x.kind
of nkOfBranch:
@@ -230,7 +228,7 @@ proc semCase(c: PContext, n: PNode): PNode =
else:
illFormedAst(x, c.config)
if chckCovered:
if covered == toCover(n.sons[0].typ):
if covered == toCover(c, n.sons[0].typ):
hasElse = true
else:
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:
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
# propagate any enforced VoidContext:
if typ == enforceVoidContext:
result.typ = enforceVoidContext
if typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext
else:
for i in 1..n.len-1:
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}:
discardCheck(c, n.sons[0])
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
if typ == enforceVoidContext:
result.typ = enforceVoidContext
if typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext
else:
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon)
n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info)
@@ -366,7 +364,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
if result.owner.kind == skModule:
incl(result.flags, sfGlobal)
suggestSym(c.config, n.info, result, c.graph.usageSym)
styleCheckDef(result)
styleCheckDef(c.config, result)
proc checkNilable(c: PContext; v: PSym) =
if {sfGlobal, sfImportC} * v.flags == {sfGlobal} and
@@ -394,7 +392,7 @@ proc isDiscardUnderscore(v: PSym): bool =
result = true
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")
for i in countup(0, sonsLen(n)-1):
var a = n.sons[i]
@@ -442,10 +440,10 @@ proc makeDeref(n: PNode): PNode =
proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
if n.len == 2:
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)
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.position = sonsLen(obj.n)
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)
else:
typ = nil
var def: PNode = ast.emptyNode
var def: PNode = c.graph.emptyNode
if a.sons[length-1].kind != nkEmpty:
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
if def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
@@ -521,7 +519,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
localError(c.config, a.info, errWrongNumberOfVariables)
b = newNodeI(nkVarTuple, a.info)
newSons(b, length)
b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
# keep type desc for doc generator
# NOTE: at the moment this is always ast.emptyNode, see parser.nim
b.sons[length-2] = a.sons[length-2]
b.sons[length-1] = def
addToVarSection(c, result, n, b)
elif tup.kind == tyTuple and def.kind in {nkPar, nkTupleConstr} and
@@ -560,7 +560,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
# keep documentation information:
b.comment = a.comment
addSon(b, newSymNode(v))
addSon(b, a.sons[length-2]) # keep type desc for doc generator
# keep type desc for doc generator, but only if the user explicitly
# added it
if a.sons[length-2].kind != nkEmpty:
addSon(b, newNodeIT(nkType, a.info, typ))
else:
addSon(b, a.sons[length-2])
addSon(b, copyTree(def))
addToVarSection(c, result, n, b)
else:
@@ -571,8 +576,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
b.sons[j] = newSymNode(v)
checkNilable(c, v)
if sfCompileTime in v.flags: hasCompileTime = true
if v.flags * {sfGlobal, sfThread} == {sfGlobal}:
message(c.config, v.info, hintGlobalVar)
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 =
result = copyNode(n)
@@ -625,7 +634,7 @@ proc addForVarDecl(c: PContext, v: PSym) =
proc symForVar(c: PContext, n: PNode): PSym =
let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
result = newSymG(skForVar, m, c)
styleCheckDef(result)
styleCheckDef(c.config, result)
proc semForVars(c: PContext, n: PNode): PNode =
result = n
@@ -664,7 +673,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
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}:
result.add newDeref(arg)
else:
@@ -698,7 +707,8 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode =
match = symx
else:
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)
if match == nil: return
@@ -746,8 +756,8 @@ proc semFor(c: PContext, n: PNode): PNode =
else:
result = semForVars(c, n)
# propagate any enforced VoidContext:
if n.sons[length-1].typ == enforceVoidContext:
result.typ = enforceVoidContext
if n.sons[length-1].typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext
closeScope(c)
proc semRaise(c: PContext, n: PNode): PNode =
@@ -796,8 +806,8 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
let name = a.sons[0]
var s: PSym
if name.kind == nkDotExpr and a[2].kind == nkObjectTy:
let pkgName = considerQuotedIdent(c.config, name[0])
let typName = considerQuotedIdent(c.config, name[1])
let pkgName = considerQuotedIdent(c, name[0])
let typName = considerQuotedIdent(c, name[1])
let pkg = c.graph.packageSyms.strTableGet(pkgName)
if pkg.isNil or pkg.kind != skPackage:
localError(c.config, name.info, "unknown package name: " & pkgName.s)
@@ -835,7 +845,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
typsym.info = s.info
else:
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
# add it here, so that recursive types are possible:
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
@@ -989,7 +999,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
internalAssert c.config, st.kind in {tyPtr, tyRef}
internalAssert c.config, st.lastSon.sym == nil
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)
obj.typ = st.lastSon
st.lastSon.sym = obj
@@ -1057,9 +1067,9 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
var f = checkModuleName(c.config, n.sons[i])
if f != InvalidFileIDX:
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:
let code = gIncludeFile(c.graph, c.module, f, c.cache)
let code = c.graph.includeFileCallback(c.graph, c.module, f)
gatherStmts c, code, result
excl(c.includedFiles, f.int)
of nkStmtList:
@@ -1131,7 +1141,7 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
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
incl(s.flags, sfUsed)
addParamOrResult(c, s, owner)
@@ -1150,7 +1160,7 @@ proc lookupMacro(c: PContext, n: PNode): PSym =
result = n.sym
if result.kind notin {skMacro, skTemplate}: result = nil
else:
result = searchInScopes(c, considerQuotedIdent(c.config, n), {skMacro, skTemplate})
result = searchInScopes(c, considerQuotedIdent(c, n), {skMacro, skTemplate})
proc semProcAnnotation(c: PContext, prc: PNode;
validPragmas: TSpecialWords): PNode =
@@ -1162,7 +1172,7 @@ proc semProcAnnotation(c: PContext, prc: PNode;
let m = lookupMacro(c, key)
if m == nil:
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[pragmasPos] = copyExcept(n, i)
else:
@@ -1177,7 +1187,7 @@ proc semProcAnnotation(c: PContext, prc: PNode;
x.add(newSymNode(m))
prc.sons[pragmasPos] = copyExcept(n, i)
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:
# pass pragma arguments to the macro too:
@@ -1200,7 +1210,7 @@ proc setGenericParamsMisc(c: PContext; n: PNode): PNode =
# issue https://github.com/nim-lang/Nim/issues/1713
result = semGenericParamList(c, orig)
if n.sons[miscPos].kind == nkEmpty:
n.sons[miscPos] = newTree(nkBracket, ast.emptyNode, orig)
n.sons[miscPos] = newTree(nkBracket, c.graph.emptyNode, orig)
else:
n.sons[miscPos].sons[1] = orig
n.sons[genericParamsPos] = result
@@ -1271,7 +1281,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
result = n
s.ast = result
n.sons[namePos].sym = s
n.sons[genericParamsPos] = emptyNode
n.sons[genericParamsPos] = c.graph.emptyNode
# for LL we need to avoid wrong aliasing
let params = copyTree n.typ.n
n.sons[paramsPos] = params
@@ -1398,14 +1408,14 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
localError(c.config, n.info, errGenerated,
"'destroy' or 'deepCopy' expected for 'override'")
proc cursorInProcAux(n: PNode): bool =
if inCheckpoint(n.info) != cpNone: return true
proc cursorInProcAux(conf: ConfigRef; n: PNode): bool =
if inCheckpoint(n.info, conf.m.trackPos) != cpNone: return true
for i in 0..<n.safeLen:
if cursorInProcAux(n[i]): return true
if cursorInProcAux(conf, n[i]): return true
proc cursorInProc(n: PNode): bool =
if n.info.fileIndex == gTrackPos.fileIndex:
result = cursorInProcAux(n)
proc cursorInProc(conf: ConfigRef; n: PNode): bool =
if n.info.fileIndex == conf.m.trackPos.fileIndex:
result = cursorInProcAux(conf, n)
type
TProcCompilationSteps = enum
@@ -1484,6 +1494,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
s.ast = n
#s.scope = c.currentScope
s.options = c.config.options
# before compiling the proc body, set as current the scope
# where the proc was declared
let oldScope = c.currentScope
@@ -1544,7 +1556,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# linking names do agree:
if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags:
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:
wrongRedefinition(c, n.info, proto.name.s)
excl(proto.flags, sfForward)
@@ -1555,6 +1567,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
addParams(c, proto.typ.n, proto.kind)
proto.info = s.info # more accurate line information
s.typ = proto.typ
proto.options = s.options
s = proto
n.sons[genericParamsPos] = proto.ast.sons[genericParamsPos]
n.sons[paramsPos] = proto.ast.sons[paramsPos]
@@ -1566,7 +1579,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
proto.ast = n # needed for code generation
popOwner(c)
pushOwner(c, s)
s.options = c.config.options
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
if s.name.s[0] in {'.', '('}:
if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}:
@@ -1585,7 +1598,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# only used for overload resolution (there is no instantiation of
# the symbol, so we must process the body now)
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"
if s.kind == skMethod: semMethodPrototype(c, s, n)
else:
@@ -1605,7 +1618,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
else:
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)
n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos])
@@ -1614,7 +1627,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if s.kind == skMethod: semMethodPrototype(c, s, n)
if sfImportc in s.flags:
# so we just ignore the body after semantic checking for importc:
n.sons[bodyPos] = ast.emptyNode
n.sons[bodyPos] = c.graph.emptyNode
popProcCon(c)
else:
if s.kind == skMethod: semMethodPrototype(c, s, n)
@@ -1693,7 +1706,7 @@ proc semMethod(c: PContext, n: PNode): PNode =
let ret = s.typ.sons[0]
disp.typ.sons[0] = ret
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
proc semConverterDef(c: PContext, n: PNode): PNode =
@@ -1739,9 +1752,9 @@ proc evalInclude(c: PContext, n: PNode): PNode =
var f = checkModuleName(c.config, n.sons[i])
if f != InvalidFileIDX:
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:
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)
proc setLine(n: PNode, info: TLineInfo) =
@@ -1767,12 +1780,18 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
#echo "semStaticStmt"
#writeStackTrace()
inc c.inStaticContext
openScope(c)
let a = semStmt(c, n.sons[0])
closeScope(c)
dec c.inStaticContext
n.sons[0] = a
evalStaticStmt(c.module, c.cache, c.graph, a, c.p.owner)
result = newNodeI(nkDiscardStmt, n.info, 1)
result.sons[0] = emptyNode
evalStaticStmt(c.module, c.graph, a, c.p.owner)
when false:
# 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 =
# nkStmtList(expr) properly propagates the void context,
@@ -1835,9 +1854,9 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
localError(c.config, result.info, "concept predicate failed")
of tyUnknown: continue
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
n.typ = enforceVoidContext
n.typ = c.enforceVoidContext
if i == last and (length == 1 or efWantValue in flags):
n.typ = n.sons[i].typ
if not isEmptyType(n.typ): n.kind = nkStmtListExpr

View File

@@ -99,7 +99,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
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)
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])
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, sfShadowed)
@@ -206,14 +206,14 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
#
# We need to ensure that both 'a' produce the same gensym'ed symbol.
# 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:
styleCheckUse(n.info, s)
replaceIdentBySym(c.c, n, newSymNode(s, n.info))
else:
let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local)
styleCheckDef(n.info, local)
styleCheckDef(c.c.config, n.info, local)
replaceIdentBySym(c.c, n, newSymNode(local, n.info))
else:
replaceIdentBySym(c.c, n, ident)
@@ -260,7 +260,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
var s = newGenSym(k, ident, c)
s.ast = n
addPrelimDecl(c.c, s)
styleCheckDef(n.info, s)
styleCheckDef(c.c.config, n.info, s)
n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
else:
n.sons[namePos] = ident
@@ -305,7 +305,7 @@ proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode =
proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
result = n
semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
semIdeForTemplateOrGenericCheck(c.c.config, n, c.cursorInBody)
case n.kind
of nkIdent:
if n.ident.id in c.toInject: return n
@@ -382,7 +382,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
# labels are always 'gensym'ed:
let s = newGenSym(skLabel, n.sons[0], c)
addPrelimDecl(c.c, s)
styleCheckDef(s)
styleCheckDef(c.c.config, s)
n.sons[0] = newSymNode(s, n.sons[0].info)
n.sons[1] = semTemplBody(c, n.sons[1])
closeScope(c)
@@ -460,14 +460,14 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
x.sons[1] = semTemplBody(c, x.sons[1])
of nkBracketExpr:
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])
let n0 = semTemplBody(c, n.sons[0])
withBracketExpr c, n0:
result = semTemplBodySons(c, result)
of nkCurlyExpr:
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])
result = semTemplBodySons(c, result)
of nkAsgn, nkFastAsgn:
@@ -479,7 +479,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
case k
of nkBracketExpr:
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])
result.add(b)
let a0 = semTemplBody(c, a.sons[0])
@@ -487,7 +487,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
result = semTemplBodySons(c, result)
of nkCurlyExpr:
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])
result.add(b)
result = semTemplBodySons(c, result)
@@ -518,7 +518,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
result = n
semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
semIdeForTemplateOrGenericCheck(c.c.config, n, c.cursorInBody)
case n.kind
of nkIdent:
let s = qualifiedLookUp(c.c, n, {})
@@ -551,7 +551,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
incl(s.flags, sfGlobal)
else:
s = semIdentVis(c, skTemplate, n.sons[0], {})
styleCheckDef(s)
styleCheckDef(c.config, s)
# check parameter list:
#s.scope = c.currentScope
pushOwner(c, s)

View File

@@ -37,6 +37,12 @@ const
errNoGenericParamsAllowedForX = "no generic parameters allowed for $1"
errInOutFlagNotExtern = "the '$1' modifier can be used only with imported types"
const
mStaticTy = {mStatic}
mTypeTy = {mType, mTypeOf}
# XXX: This should be needed only temporarily until the C
# sources are rebuilt
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
if prev == nil:
result = newTypeS(kind, c)
@@ -66,7 +72,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
base = semTypeNode(c, n.sons[0].sons[0], nil)
if base.kind != tyEnum:
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)
let isPure = result.sym != nil and sfPure in result.sym.flags
var symbols: TStrTable
@@ -114,8 +120,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
incl(e.flags, sfExported)
if not isPure: strTableAdd(c.module.tab, e)
addSon(result.n, newSymNode(e))
let conf = c.config
styleCheckDef(e)
styleCheckDef(c.config, e)
if sfGenSym notin e.flags:
if not isPure: addDecl(c, e)
else: importPureEnumField(c, e)
@@ -133,7 +138,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
if base.kind != tyGenericParam:
if not isOrdinalType(base):
localError(c.config, n.info, errOrdinalTypeExpected)
elif lengthOrd(base) > MaxSetElements:
elif lengthOrd(c.config, base) > MaxSetElements:
localError(c.config, n.info, errSetTooBig)
else:
localError(c.config, n.info, errXExpectsOneTypeParam % "set")
@@ -157,7 +162,7 @@ proc semVarargs(c: PContext, n: PNode, prev: PType): PType =
var base = semTypeNode(c, n.sons[1], nil)
addSonSkipIntLit(result, base)
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:
localError(c.config, n.info, errXExpectsOneTypeParam % "varargs")
addSonSkipIntLit(result, errorType(c))
@@ -233,13 +238,13 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
if not hasUnknownTypes:
if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})):
localError(c.config, n.info, "type mismatch")
elif not rangeT[0].isOrdinalType:
localError(c.config, n.info, "ordinal type expected")
elif not rangeT[0].isOrdinalType and rangeT[0].kind notin tyFloat..tyFloat128:
localError(c.config, n.info, "ordinal or float type expected")
elif enumHasHoles(rangeT[0]):
localError(c.config, n.info, "enum '$1' has holes" % typeToString(rangeT[0]))
for i in 0..1:
if hasGenericArguments(range[i]):
if hasUnresolvedArgs(c, range[i]):
result.n.addSon makeStaticExpr(c, range[i])
result.flags.incl tfUnresolved
else:
@@ -267,7 +272,7 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
n.sons[1].floatVal < 0.0:
incl(result.flags, tfNeedsInit)
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")
else:
localError(c.config, n.sons[0].info, "expected range")
@@ -296,7 +301,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
localError(c.config, info, errOrdinalTypeExpected)
result = makeRangeWithStaticExpr(c, e)
if c.inGenericContext > 0: result.flags.incl tfUnresolved
elif e.kind in nkCallKinds and hasGenericArguments(e):
elif e.kind in (nkCallKinds + {nkBracketExpr}) and hasUnresolvedArgs(c, e):
if not isOrdinalType(e.typ):
localError(c.config, n[1].info, errOrdinalTypeExpected)
# This is an int returning call, depending on an
@@ -364,6 +369,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
if result != nil:
markUsed(c.config, n.info, result, c.graph.usageSym)
styleCheckUse(n.info, result)
if result.kind == skParam and result.typ.kind == tyTypeDesc:
# This is a typedesc param. is it already bound?
# it's not bound when it's used multiple times in the
@@ -389,8 +395,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
else:
localError(c.config, n.info, errTypeExpected)
return errorSym(c, n)
if result.kind != skType:
if result.kind != skType and result.magic notin (mStaticTy + mTypeTy):
# this implements the wanted ``var v: V, x: V`` feature ...
var ov: TOverloadIter
var amb = initOverloadIter(ov, c, n)
@@ -451,7 +456,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
else:
addSon(result.n, newSymNode(field))
addSonSkipIntLit(result, typ)
if c.config.cmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
styleCheckDef(c.config, a.sons[j].info, field)
if result.n.len == 0: result.n = nil
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
@@ -462,7 +467,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
# for gensym'ed identifiers the identifier may already have been
# transformed to a symbol and we need to use that here:
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):
incl(result.flags, sfExported)
else:
@@ -491,7 +496,7 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
else: discard
else:
result = semIdentVis(c, kind, n, allowed)
if c.config.cmd == cmdPretty: styleCheckDef(n.info, result)
styleCheckDef(c.config, n.info, result)
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
let ex = t[branchIndex][currentEx].skipConv
@@ -553,7 +558,7 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
inc(covered)
else:
if r.kind == nkCurly:
r = r.deduplicate
r = deduplicate(c.config, r)
# first element is special and will overwrite: branch.sons[i]:
branch.sons[i] = semCaseBranchSetElem(c, t, r[0], covered)
@@ -584,10 +589,10 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc})
if not isOrdinalType(typ):
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 &
") 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)
var chckCovered = true
for i in countup(1, sonsLen(n) - 1):
@@ -603,7 +608,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
else: illFormedAst(n, c.config)
delSon(b, sonsLen(b) - 1)
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")
addSon(father, a)
@@ -658,7 +663,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
var length = sonsLen(n)
var a: PNode
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:
localError(c.config, n.sons[length-1].info, errInitHereNotAllowed)
var typ: PType
@@ -685,7 +690,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
localError(c.config, n.sons[i].info, "attempt to redefine: '" & f.name.s & "'")
if a.kind == nkEmpty: addSon(father, newSymNode(f))
else: addSon(a, newSymNode(f))
styleCheckDef(f)
styleCheckDef(c.config, f)
if a.kind != nkEmpty: addSon(father, a)
of nkSym:
# This branch only valid during generic object
@@ -770,7 +775,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
semRecordNodeAux(c, n.sons[2], check, pos, result.n, result)
if n.sons[0].kind != nkEmpty:
# 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
pragma(c, s, n.sons[0], typePragmas)
if base == nil and tfInheritable notin result.flags:
@@ -804,8 +809,6 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
else:
if sfGenSym notin param.flags: addDecl(c, param)
let typedescId = getIdent"typedesc"
template shouldHaveMeta(t) =
internalAssert c.config, tfHasMeta in t.flags
# result.lastSon.flags.incl tfHasMeta
@@ -815,13 +818,13 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
info: TLineInfo, anon = false): PType =
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:
# This happens with anonymous proc types appearing in signatures
# XXX: we need to lift these earlier
return
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?
for i in countup(0, genericParams.len - 1):
if genericParams.sons[i].sym.name.id == finalTypId.id:
@@ -852,16 +855,16 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
(if lifted != nil: lifted else: typ)
template addImplicitGeneric(e): untyped =
addImplicitGenericImpl(e, paramTypId)
addImplicitGenericImpl(c, e, paramTypId)
case paramType.kind:
of tyAnything:
result = addImplicitGenericImpl(newTypeS(tyGenericParam, c), nil)
result = addImplicitGenericImpl(c, newTypeS(tyGenericParam, c), nil)
of tyStatic:
# proc(a: expr{string}, b: expr{nkLambda})
# overload on compile time values and AST trees
if paramType.n != nil: return # this is a concrete type
if paramType.base.kind != tyNone and paramType.n != nil:
# this is a concrete static value
return
if tfUnresolved in paramType.flags: return # already lifted
let base = paramType.base.maybeLift
if base.isMetaType and procKind == skMacro:
@@ -873,14 +876,19 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
if tfUnresolved notin paramType.flags:
# naked typedescs are not bindOnce types
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(
c.newTypeWithSons(tyTypeDesc, @[paramType.base]))
of tyDistinct:
if paramType.sonsLen == 1:
# disable the bindOnce behavior for the type class
result = liftingWalk(paramType.sons[0], true)
result = liftingWalk(paramType.base, true)
of tyAlias:
result = liftingWalk(paramType.base)
of tySequence, tySet, tyArray, tyOpenArray,
tyVar, tyLent, tyPtr, tyRef, tyProc:
@@ -997,13 +1005,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
prev: PType, kind: TSymKind; isType=false): PType =
# for historical reasons (code grows) this is invoked for parameter
# lists too and then 'isType' is false.
var cl: IntSet
checkMinSonsLen(n, 1, c.config)
result = newProcType(c, n.info, prev)
if genericParams != nil and sonsLen(genericParams) == 0:
cl = initIntSet()
var check = initIntSet()
var counter = 0
for i in countup(1, n.len - 1):
var a = n.sons[i]
if a.kind != nkIdentDefs:
@@ -1013,6 +1019,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
# pass over this instantiation:
if a.kind == nkSym and sfFromGeneric in a.sym.flags: continue
illFormedAst(a, c.config)
checkMinSonsLen(a, 3, c.config)
var
typ: PType = nil
@@ -1021,26 +1028,52 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
length = sonsLen(a)
hasType = a.sons[length-2].kind != nkEmpty
hasDefault = a.sons[length-1].kind != nkEmpty
if hasType:
typ = semParamType(c, a.sons[length-2], constraint)
if hasDefault:
def = semExprWithType(c, a.sons[length-1])
# check type compatibility between def.typ and typ:
def = a[^1]
block determineType:
if genericParams != nil and genericParams.len > 0:
def = semGenericStmt(c, def)
if hasUnresolvedArgs(c, def):
def.typ = makeTypeFromExpr(c, def.copyTree)
break determineType
def = semExprWithType(c, def, {efDetermineType})
if def.referencesAnotherParam(getCurrOwner(c)):
def.flags.incl nfDefaultRefsParam
if typ == nil:
typ = def.typ
elif def != nil:
# and def.typ != nil and def.typ.kind != tyNone:
if typ.kind == tyTypeDesc:
# consider a proc such as:
# proc takesType(T = int)
# a naive analysis may conclude that the proc type is type[int]
# which will prevent other types from matching - clearly a very
# surprising behavior. We must instead fix the expected type of
# the proc to be the unbound typedesc type:
typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)])
else:
# if def.typ != nil and def.typ.kind != tyNone:
# example code that triggers it:
# proc sort[T](cmp: proc(a, b: T): int = cmp)
if not containsGenericType(typ):
# check type compatibility between def.typ and typ:
def = fitNode(c, typ, def, def.info)
elif typ.kind == tyStatic:
def = semConstExpr(c, def)
def = fitNode(c, typ, def, def.info)
if not hasType and not hasDefault:
if isType: localError(c.config, a.info, "':' expected")
if kind in {skTemplate, skMacro}:
typ = newTypeS(tyExpr, c)
elif skipTypes(typ, {tyGenericInst, tyAlias, tySink}).kind == tyVoid:
continue
for j in countup(0, length-3):
var arg = newSymG(skParam, a.sons[j], c)
if not hasType and not hasDefault and kind notin {skTemplate, skMacro}:
@@ -1056,13 +1089,14 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
arg.position = counter
arg.constraint = constraint
inc(counter)
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
if def != nil and def.kind != nkEmpty:
arg.ast = copyTree(def)
if containsOrIncl(check, arg.name.id):
localError(c.config, a.sons[j].info, "attempt to redefine: '" & arg.name.s & "'")
addSon(result.n, newSymNode(arg))
rawAddSon(result, finalType)
addParamOrResult(c, arg, kind)
if c.config.cmd == cmdPretty: styleCheckDef(a.sons[j].info, arg)
styleCheckDef(c.config, a.sons[j].info, arg)
var r: PType
if n.sons[0].kind != nkEmpty:
@@ -1311,7 +1345,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
incl dummyParam.flags, sfUsed
addDecl(c, dummyParam)
result.n.sons[3] = semConceptBody(c, n[3])
result.n[3] = semConceptBody(c, n[3])
closeScope(c)
proc semProcTypeWithScope(c: PContext, n: PNode,
@@ -1322,7 +1356,7 @@ proc semProcTypeWithScope(c: PContext, n: PNode,
# start with 'ccClosure', but of course pragmas can overwrite this:
result.callConv = ccClosure
# 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
if n.sons[1].kind != nkEmpty and n.sons[1].len > 0:
pragma(c, s, n.sons[1], procTypePragmas)
@@ -1345,11 +1379,17 @@ proc fixupTypeOf(c: PContext, prev: PType, typExpr: PNode) =
proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym =
if n.kind == nkType:
result = symFromType(n.typ, n.info)
result = symFromType(c, n.typ, n.info)
else:
localError(c.config, n.info, errTypeExpected)
result = errorSym(c, n)
proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType =
result = newOrPrevType(tyStatic, prev, c)
var base = semTypeNode(c, childNode, nil).skipTypes({tyTypeDesc, tyAlias})
result.rawAddSon(base)
result.flags.incl tfHasStatic
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil
inc c.inTypeContext
@@ -1393,7 +1433,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
elif n[0].kind notin nkIdentKinds:
result = semTypeExpr(c, n, prev)
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 == "|":
checkSonsLen(n, 3, c.config)
var
@@ -1457,7 +1497,11 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of mSeq: result = semContainer(c, n, tySequence, "seq", prev)
of mOpt: result = semContainer(c, n, tyOpt, "opt", prev)
of mVarargs: result = semVarargs(c, n, prev)
of mTypeDesc: result = makeTypeDesc(c, semTypeNode(c, n[1], nil))
of mTypeDesc, mTypeTy:
result = makeTypeDesc(c, semTypeNode(c, n[1], nil))
result.flags.incl tfExplicit
of mStaticTy:
result = semStaticType(c, n[1], prev)
of mExpr:
result = semTypeNode(c, n.sons[0], nil)
if result != nil:
@@ -1546,11 +1590,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
of nkVarTy: result = semVarType(c, n, prev)
of nkDistinctTy: result = semDistinct(c, n, prev)
of nkStaticTy:
result = newOrPrevType(tyStatic, prev, c)
var base = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
result.rawAddSon(base)
result.flags.incl tfHasStatic
of nkStaticTy: result = semStaticType(c, n[0], prev)
of nkIteratorTy:
if n.sonsLen == 0:
result = newTypeS(tyBuiltInTypeClass, c)
@@ -1585,7 +1625,7 @@ when false:
result = semTypeNodeInner(c, n, prev)
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
m.typ.kind = kind
m.typ.size = size
@@ -1596,10 +1636,10 @@ proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
# FIXME: proper support for clongdouble should be added.
# 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)
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
# on i386, all known compiler, 64bits ints are aligned to 4bytes (except with -malign-double)
elif kind in {tyInt, tyUInt, tyInt64, tyUInt64}:
@@ -1609,73 +1649,76 @@ proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
proc processMagicType(c: PContext, m: PSym) =
case m.magic
of mInt: setMagicType(m, tyInt, intSize)
of mInt8: setMagicType(m, tyInt8, 1)
of mInt16: setMagicType(m, tyInt16, 2)
of mInt32: setMagicType(m, tyInt32, 4)
of mInt64: setMagicType(m, tyInt64, 8)
of mUInt: setMagicType(m, tyUInt, intSize)
of mUInt8: setMagicType(m, tyUInt8, 1)
of mUInt16: setMagicType(m, tyUInt16, 2)
of mUInt32: setMagicType(m, tyUInt32, 4)
of mUInt64: setMagicType(m, tyUInt64, 8)
of mFloat: setMagicType(m, tyFloat, floatSize)
of mFloat32: setMagicType(m, tyFloat32, 4)
of mFloat64: setMagicType(m, tyFloat64, 8)
of mFloat128: setMagicType(m, tyFloat128, 16)
of mBool: setMagicType(m, tyBool, 1)
of mChar: setMagicType(m, tyChar, 1)
of mInt: setMagicType(c.config, m, tyInt, c.config.target.intSize)
of mInt8: setMagicType(c.config, m, tyInt8, 1)
of mInt16: setMagicType(c.config, m, tyInt16, 2)
of mInt32: setMagicType(c.config, m, tyInt32, 4)
of mInt64: setMagicType(c.config, m, tyInt64, 8)
of mUInt: setMagicType(c.config, m, tyUInt, c.config.target.intSize)
of mUInt8: setMagicType(c.config, m, tyUInt8, 1)
of mUInt16: setMagicType(c.config, m, tyUInt16, 2)
of mUInt32: setMagicType(c.config, m, tyUInt32, 4)
of mUInt64: setMagicType(c.config, m, tyUInt64, 8)
of mFloat: setMagicType(c.config, m, tyFloat, c.config.target.floatSize)
of mFloat32: setMagicType(c.config, m, tyFloat32, 4)
of mFloat64: setMagicType(c.config, m, tyFloat64, 8)
of mFloat128: setMagicType(c.config, m, tyFloat128, 16)
of mBool: setMagicType(c.config, m, tyBool, 1)
of mChar: setMagicType(c.config, m, tyChar, 1)
of mString:
setMagicType(m, tyString, ptrSize)
setMagicType(c.config, m, tyString, c.config.target.ptrSize)
rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
of mCstring:
setMagicType(m, tyCString, ptrSize)
setMagicType(c.config, m, tyCString, c.config.target.ptrSize)
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:
setMagicType(m, tySet, 1)
setMagicType(c.config, m, tySet, 1)
rawAddSon(m.typ, newTypeS(tyEmpty, c))
of mIntSetBaseType: setMagicType(m, tyRange, intSize)
of mNil: setMagicType(m, tyNil, ptrSize)
of mIntSetBaseType: setMagicType(c.config, m, tyRange, c.config.target.intSize)
of mNil: setMagicType(c.config, m, tyNil, c.config.target.ptrSize)
of mExpr:
if m.name.s == "auto":
setMagicType(m, tyAnything, 0)
setMagicType(c.config, m, tyAnything, 0)
else:
setMagicType(m, tyExpr, 0)
setMagicType(c.config, m, tyExpr, 0)
if m.name.s == "expr": m.typ.flags.incl tfOldSchoolExprStmt
of mStmt:
setMagicType(m, tyStmt, 0)
setMagicType(c.config, m, tyStmt, 0)
if m.name.s == "stmt": m.typ.flags.incl tfOldSchoolExprStmt
of mTypeDesc:
setMagicType(m, tyTypeDesc, 0)
of mTypeDesc, mType:
setMagicType(c.config, m, tyTypeDesc, 0)
rawAddSon(m.typ, newTypeS(tyNone, c))
of mStatic:
setMagicType(c.config, m, tyStatic, 0)
rawAddSon(m.typ, newTypeS(tyNone, c))
of mVoidType:
setMagicType(m, tyVoid, 0)
setMagicType(c.config, m, tyVoid, 0)
of mArray:
setMagicType(m, tyArray, 0)
setMagicType(c.config, m, tyArray, 0)
of mOpenArray:
setMagicType(m, tyOpenArray, 0)
setMagicType(c.config, m, tyOpenArray, 0)
of mVarargs:
setMagicType(m, tyVarargs, 0)
setMagicType(c.config, m, tyVarargs, 0)
of mRange:
setMagicType(m, tyRange, 0)
setMagicType(c.config, m, tyRange, 0)
rawAddSon(m.typ, newTypeS(tyNone, c))
of mSet:
setMagicType(m, tySet, 0)
setMagicType(c.config, m, tySet, 0)
of mSeq:
setMagicType(m, tySequence, 0)
setMagicType(c.config, m, tySequence, 0)
of mOpt:
setMagicType(m, tyOpt, 0)
setMagicType(c.config, m, tyOpt, 0)
of mOrdinal:
setMagicType(m, tyOrdinal, 0)
setMagicType(c.config, m, tyOrdinal, 0)
rawAddSon(m.typ, newTypeS(tyNone, c))
of mPNimrodNode:
incl m.typ.flags, tfTriggersCompileTime
of mException: discard
of mBuiltinType:
case m.name.s
of "lent": setMagicType(m, tyLent, ptrSize)
of "sink": setMagicType(m, tySink, 0)
of "lent": setMagicType(c.config, m, tyLent, c.config.target.ptrSize)
of "sink": setMagicType(c.config, m, tySink, 0)
else: localError(c.config, m.info, errTypeExpected)
else: localError(c.config, m.info, errTypeExpected)

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