mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-17 16:38:33 +00:00
Merge branch 'devel' into Fixes-7845
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
28
changelog.md
28
changelog.md
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
233
compiler/btrees.nim
Normal file
@@ -0,0 +1,233 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2018 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## BTree implementation with few features, but good enough for the
|
||||
## Nim compiler's needs.
|
||||
|
||||
const
|
||||
M = 512 # max children per B-tree node = M-1
|
||||
# (must be even and greater than 2)
|
||||
Mhalf = M div 2
|
||||
|
||||
type
|
||||
Node[Key, Val] = ref object
|
||||
entries: int
|
||||
keys: array[M, Key]
|
||||
case isInternal: bool
|
||||
of false:
|
||||
vals: array[M, Val]
|
||||
of true:
|
||||
links: array[M, Node[Key, Val]]
|
||||
BTree*[Key, Val] = object
|
||||
root: Node[Key, Val]
|
||||
entries: int ## number of key-value pairs
|
||||
|
||||
proc initBTree*[Key, Val](): BTree[Key, Val] =
|
||||
BTree[Key, Val](root: Node[Key, Val](entries: 0, isInternal: false))
|
||||
|
||||
template less(a, b): bool = cmp(a, b) < 0
|
||||
template eq(a, b): bool = cmp(a, b) == 0
|
||||
|
||||
proc getOrDefault*[Key, Val](b: BTree[Key, Val], key: Key): Val =
|
||||
var x = b.root
|
||||
while x.isInternal:
|
||||
for j in 0 ..< x.entries:
|
||||
if j+1 == x.entries or less(key, x.keys[j+1]):
|
||||
x = x.links[j]
|
||||
break
|
||||
assert(not x.isInternal)
|
||||
for j in 0 ..< x.entries:
|
||||
if eq(key, x.keys[j]): return x.vals[j]
|
||||
|
||||
proc contains*[Key, Val](b: BTree[Key, Val], key: Key): bool =
|
||||
var x = b.root
|
||||
while x.isInternal:
|
||||
for j in 0 ..< x.entries:
|
||||
if j+1 == x.entries or less(key, x.keys[j+1]):
|
||||
x = x.links[j]
|
||||
break
|
||||
assert(not x.isInternal)
|
||||
for j in 0 ..< x.entries:
|
||||
if eq(key, x.keys[j]): return true
|
||||
return false
|
||||
|
||||
proc copyHalf[Key, Val](h, result: Node[Key, Val]) =
|
||||
for j in 0 ..< Mhalf:
|
||||
result.keys[j] = h.keys[Mhalf + j]
|
||||
if h.isInternal:
|
||||
for j in 0 ..< Mhalf:
|
||||
result.links[j] = h.links[Mhalf + j]
|
||||
else:
|
||||
for j in 0 ..< Mhalf:
|
||||
shallowCopy(result.vals[j], h.vals[Mhalf + j])
|
||||
|
||||
proc split[Key, Val](h: Node[Key, Val]): Node[Key, Val] =
|
||||
## split node in half
|
||||
result = Node[Key, Val](entries: Mhalf, isInternal: h.isInternal)
|
||||
h.entries = Mhalf
|
||||
copyHalf(h, result)
|
||||
|
||||
proc insert[Key, Val](h: Node[Key, Val], key: Key, val: Val): Node[Key, Val] =
|
||||
#var t = Entry(key: key, val: val, next: nil)
|
||||
var newKey = key
|
||||
var j = 0
|
||||
if not h.isInternal:
|
||||
while j < h.entries:
|
||||
if less(key, h.keys[j]): break
|
||||
inc j
|
||||
for i in countdown(h.entries, j+1):
|
||||
shallowCopy(h.vals[i], h.vals[i-1])
|
||||
h.vals[j] = val
|
||||
else:
|
||||
var newLink: Node[Key, Val] = nil
|
||||
while j < h.entries:
|
||||
if j+1 == h.entries or less(key, h.keys[j+1]):
|
||||
let u = insert(h.links[j], key, val)
|
||||
inc j
|
||||
if u == nil: return nil
|
||||
newKey = u.keys[0]
|
||||
newLink = u
|
||||
break
|
||||
inc j
|
||||
for i in countdown(h.entries, j+1):
|
||||
h.links[i] = h.links[i-1]
|
||||
h.links[j] = newLink
|
||||
|
||||
for i in countdown(h.entries, j+1):
|
||||
h.keys[i] = h.keys[i-1]
|
||||
h.keys[j] = newKey
|
||||
inc h.entries
|
||||
return if h.entries < M: nil else: split(h)
|
||||
|
||||
proc add*[Key, Val](b: var BTree[Key, Val]; key: Key; val: Val) =
|
||||
let u = insert(b.root, key, val)
|
||||
inc b.entries
|
||||
if u == nil: return
|
||||
|
||||
# need to split root
|
||||
let t = Node[Key, Val](entries: 2, isInternal: true)
|
||||
t.keys[0] = b.root.keys[0]
|
||||
t.links[0] = b.root
|
||||
t.keys[1] = u.keys[0]
|
||||
t.links[1] = u
|
||||
b.root = t
|
||||
|
||||
proc toString[Key, Val](h: Node[Key, Val], indent: string; result: var string) =
|
||||
if not h.isInternal:
|
||||
for j in 0..<h.entries:
|
||||
result.add(indent)
|
||||
result.add($h.keys[j] & " " & $h.vals[j] & "\n")
|
||||
else:
|
||||
for j in 0..<h.entries:
|
||||
if j > 0: result.add(indent & "(" & $h.keys[j] & ")\n")
|
||||
toString(h.links[j], indent & " ", result)
|
||||
|
||||
proc `$`[Key, Val](b: BTree[Key, Val]): string =
|
||||
result = ""
|
||||
toString(b.root, "", result)
|
||||
|
||||
proc hasNext*[Key, Val](b: BTree[Key, Val]; index: int): bool =
|
||||
result = index < b.entries
|
||||
|
||||
proc countSubTree[Key, Val](it: Node[Key, Val]): int =
|
||||
if it.isInternal:
|
||||
result = 0
|
||||
for k in 0..<it.entries:
|
||||
inc result, countSubTree(it.links[k])
|
||||
else:
|
||||
result = it.entries
|
||||
|
||||
proc next*[Key, Val](b: BTree[Key, Val]; index: int): (Key, Val, int) =
|
||||
var it = b.root
|
||||
var i = index
|
||||
# navigate to the right leaf:
|
||||
while it.isInternal:
|
||||
var sum = 0
|
||||
for k in 0..<it.entries:
|
||||
let c = countSubTree(it.links[k])
|
||||
inc sum, c
|
||||
if sum > i:
|
||||
it = it.links[k]
|
||||
dec i, (sum - c)
|
||||
break
|
||||
result = (it.keys[i], it.vals[i], index+1)
|
||||
|
||||
iterator pairs*[Key, Val](b: BTree[Key, Val]): (Key, Val) =
|
||||
var i = 0
|
||||
while hasNext(b, i):
|
||||
let (k, v, i2) = next(b, i)
|
||||
i = i2
|
||||
yield (k, v)
|
||||
|
||||
proc len*[Key, Val](b: BTree[Key, Val]): int {.inline.} = b.entries
|
||||
|
||||
when isMainModule:
|
||||
|
||||
import random, tables
|
||||
|
||||
proc main =
|
||||
var st = initBTree[string, string]()
|
||||
st.add("www.cs.princeton.edu", "abc")
|
||||
st.add("www.princeton.edu", "128.112.128.15")
|
||||
st.add("www.yale.edu", "130.132.143.21")
|
||||
st.add("www.simpsons.com", "209.052.165.60")
|
||||
st.add("www.apple.com", "17.112.152.32")
|
||||
st.add("www.amazon.com", "207.171.182.16")
|
||||
st.add("www.ebay.com", "66.135.192.87")
|
||||
st.add("www.cnn.com", "64.236.16.20")
|
||||
st.add("www.google.com", "216.239.41.99")
|
||||
st.add("www.nytimes.com", "199.239.136.200")
|
||||
st.add("www.microsoft.com", "207.126.99.140")
|
||||
st.add("www.dell.com", "143.166.224.230")
|
||||
st.add("www.slashdot.org", "66.35.250.151")
|
||||
st.add("www.espn.com", "199.181.135.201")
|
||||
st.add("www.weather.com", "63.111.66.11")
|
||||
st.add("www.yahoo.com", "216.109.118.65")
|
||||
|
||||
assert st.getOrDefault("www.cs.princeton.edu") == "abc"
|
||||
assert st.getOrDefault("www.harvardsucks.com") == nil
|
||||
|
||||
assert st.getOrDefault("www.simpsons.com") == "209.052.165.60"
|
||||
assert st.getOrDefault("www.apple.com") == "17.112.152.32"
|
||||
assert st.getOrDefault("www.ebay.com") == "66.135.192.87"
|
||||
assert st.getOrDefault("www.dell.com") == "143.166.224.230"
|
||||
assert(st.entries == 16)
|
||||
|
||||
for k, v in st:
|
||||
echo k, ": ", v
|
||||
|
||||
when false:
|
||||
var b2 = initBTree[string, string]()
|
||||
const iters = 10_000
|
||||
for i in 1..iters:
|
||||
b2.add($i, $(iters - i))
|
||||
for i in 1..iters:
|
||||
let x = b2.getOrDefault($i)
|
||||
if x != $(iters - i):
|
||||
echo "got ", x, ", but expected ", iters - i
|
||||
echo b2.entries
|
||||
|
||||
when true:
|
||||
var b2 = initBTree[int, string]()
|
||||
var t2 = initTable[int, string]()
|
||||
const iters = 100_000
|
||||
for i in 1..iters:
|
||||
let x = rand(high(int))
|
||||
if not t2.hasKey(x):
|
||||
doAssert b2.getOrDefault(x).len == 0, " what, tree has this element " & $x
|
||||
t2[x] = $x
|
||||
b2.add(x, $x)
|
||||
|
||||
doAssert b2.entries == t2.len
|
||||
echo "unique entries ", b2.entries
|
||||
for k, v in t2:
|
||||
doAssert $k == v
|
||||
doAssert b2.getOrDefault(k) == $k
|
||||
|
||||
main()
|
||||
@@ -24,7 +24,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
# getUniqueType() is too expensive here:
|
||||
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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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: ""
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen.
|
||||
## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf
|
||||
|
||||
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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||
renderer, filters
|
||||
renderer, filters, lineinfos
|
||||
|
||||
type
|
||||
TParseState = enum
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
196
compiler/incremental.nim
Normal file
@@ -0,0 +1,196 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2018 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Basic type definitions the module graph needs in order to support
|
||||
## incremental compilations.
|
||||
|
||||
const nimIncremental* = defined(nimIncremental)
|
||||
|
||||
import options, lineinfos
|
||||
|
||||
when nimIncremental:
|
||||
import ast, msgs, intsets, btrees, db_sqlite, std / sha1
|
||||
from strutils import parseInt
|
||||
|
||||
type
|
||||
Writer* = object
|
||||
sstack*: seq[PSym] # a stack of symbols to process
|
||||
tstack*: seq[PType] # a stack of types to process
|
||||
tmarks*, smarks*: IntSet
|
||||
forwardedSyms*: seq[PSym]
|
||||
|
||||
Reader* = object
|
||||
syms*: BTree[int, PSym]
|
||||
types*: BTree[int, PType]
|
||||
|
||||
IncrementalCtx* = object
|
||||
db*: DbConn
|
||||
w*: Writer
|
||||
r*: Reader
|
||||
configChanged*: bool
|
||||
|
||||
proc init*(incr: var IncrementalCtx) =
|
||||
incr.w.sstack = @[]
|
||||
incr.w.tstack = @[]
|
||||
incr.w.tmarks = initIntSet()
|
||||
incr.w.smarks = initIntSet()
|
||||
incr.w.forwardedSyms = @[]
|
||||
incr.r.syms = initBTree[int, PSym]()
|
||||
incr.r.types = initBTree[int, PType]()
|
||||
|
||||
|
||||
proc hashFileCached*(conf: ConfigRef; fileIdx: FileIndex; fullpath: string): string =
|
||||
result = msgs.getHash(conf, fileIdx)
|
||||
if result.len == 0:
|
||||
result = $secureHashFile(fullpath)
|
||||
msgs.setHash(conf, fileIdx, result)
|
||||
|
||||
proc toDbFileId*(incr: var IncrementalCtx; conf: ConfigRef; fileIdx: FileIndex): int =
|
||||
if fileIdx == FileIndex(-1): return -1
|
||||
let fullpath = toFullPath(conf, fileIdx)
|
||||
let row = incr.db.getRow(sql"select id, fullhash from filenames where fullpath = ?",
|
||||
fullpath)
|
||||
let id = row[0]
|
||||
let fullhash = hashFileCached(conf, fileIdx, fullpath)
|
||||
if id.len == 0:
|
||||
result = int incr.db.insertID(sql"insert into filenames(fullpath, fullhash) values (?, ?)",
|
||||
fullpath, fullhash)
|
||||
else:
|
||||
if row[1] != fullhash:
|
||||
incr.db.exec(sql"update filenames set fullhash = ? where fullpath = ?", fullhash, fullpath)
|
||||
result = parseInt(id)
|
||||
|
||||
proc fromDbFileId*(incr: var IncrementalCtx; conf: ConfigRef; dbId: int): FileIndex =
|
||||
if dbId == -1: return FileIndex(-1)
|
||||
let fullpath = incr.db.getValue(sql"select fullpath from filenames where id = ?", dbId)
|
||||
doAssert fullpath.len > 0, "cannot find file name for DB ID " & $dbId
|
||||
result = fileInfoIdx(conf, fullpath)
|
||||
|
||||
|
||||
proc addModuleDep*(incr: var IncrementalCtx; conf: ConfigRef;
|
||||
module, fileIdx: FileIndex;
|
||||
isIncludeFile: bool) =
|
||||
if conf.symbolFiles != v2Sf: return
|
||||
|
||||
let a = toDbFileId(incr, conf, module)
|
||||
let b = toDbFileId(incr, conf, fileIdx)
|
||||
|
||||
incr.db.exec(sql"insert into deps(module, dependency, isIncludeFile) values (?, ?, ?)",
|
||||
a, b, ord(isIncludeFile))
|
||||
|
||||
# --------------- Database model ---------------------------------------------
|
||||
|
||||
proc createDb*(db: DbConn) =
|
||||
db.exec(sql"""
|
||||
create table if not exists controlblock(
|
||||
idgen integer not null
|
||||
);
|
||||
""")
|
||||
|
||||
db.exec(sql"""
|
||||
create table if not exists config(
|
||||
config varchar(8000) not null
|
||||
);
|
||||
""")
|
||||
|
||||
db.exec(sql"""
|
||||
create table if not exists filenames(
|
||||
id integer primary key,
|
||||
fullpath varchar(8000) not null,
|
||||
fullHash varchar(256) not null
|
||||
);
|
||||
""")
|
||||
db.exec sql"create index if not exists FilenameIx on filenames(fullpath);"
|
||||
|
||||
db.exec(sql"""
|
||||
create table if not exists modules(
|
||||
id integer primary key,
|
||||
nimid integer not null,
|
||||
fullpath varchar(8000) not null,
|
||||
interfHash varchar(256) not null,
|
||||
fullHash varchar(256) not null,
|
||||
|
||||
created timestamp not null default (DATETIME('now'))
|
||||
);""")
|
||||
db.exec(sql"""create unique index if not exists SymNameIx on modules(fullpath);""")
|
||||
|
||||
db.exec(sql"""
|
||||
create table if not exists deps(
|
||||
id integer primary key,
|
||||
module integer not null,
|
||||
dependency integer not null,
|
||||
isIncludeFile integer not null,
|
||||
foreign key (module) references filenames(id),
|
||||
foreign key (dependency) references filenames(id)
|
||||
);""")
|
||||
db.exec(sql"""create index if not exists DepsIx on deps(module);""")
|
||||
|
||||
db.exec(sql"""
|
||||
create table if not exists types(
|
||||
id integer primary key,
|
||||
nimid integer not null,
|
||||
module integer not null,
|
||||
data blob not null,
|
||||
foreign key (module) references module(id)
|
||||
);
|
||||
""")
|
||||
db.exec sql"create index TypeByModuleIdx on types(module);"
|
||||
db.exec sql"create index TypeByNimIdIdx on types(nimid);"
|
||||
|
||||
db.exec(sql"""
|
||||
create table if not exists syms(
|
||||
id integer primary key,
|
||||
nimid integer not null,
|
||||
module integer not null,
|
||||
name varchar(256) not null,
|
||||
data blob not null,
|
||||
exported int not null,
|
||||
foreign key (module) references module(id)
|
||||
);
|
||||
""")
|
||||
db.exec sql"create index if not exists SymNameIx on syms(name);"
|
||||
db.exec sql"create index SymByNameAndModuleIdx on syms(name, module);"
|
||||
db.exec sql"create index SymByModuleIdx on syms(module);"
|
||||
db.exec sql"create index SymByNimIdIdx on syms(nimid);"
|
||||
|
||||
|
||||
db.exec(sql"""
|
||||
create table if not exists toplevelstmts(
|
||||
id integer primary key,
|
||||
position integer not null,
|
||||
module integer not null,
|
||||
data blob not null,
|
||||
foreign key (module) references module(id)
|
||||
);
|
||||
""")
|
||||
db.exec sql"create index TopLevelStmtByModuleIdx on toplevelstmts(module);"
|
||||
db.exec sql"create index TopLevelStmtByPositionIdx on toplevelstmts(position);"
|
||||
|
||||
db.exec(sql"""
|
||||
create table if not exists statics(
|
||||
id integer primary key,
|
||||
module integer not null,
|
||||
data blob not null,
|
||||
foreign key (module) references module(id)
|
||||
);
|
||||
""")
|
||||
db.exec sql"create index StaticsByModuleIdx on toplevelstmts(module);"
|
||||
db.exec sql"insert into controlblock(idgen) values (0)"
|
||||
|
||||
|
||||
else:
|
||||
type
|
||||
IncrementalCtx* = object
|
||||
|
||||
template init*(incr: IncrementalCtx) = discard
|
||||
|
||||
template addModuleDep*(incr: var IncrementalCtx; conf: ConfigRef;
|
||||
module, fileIdx: FileIndex;
|
||||
isIncludeFile: bool) =
|
||||
discard
|
||||
@@ -31,8 +31,8 @@ implements the required case distinction.
|
||||
import
|
||||
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)
|
||||
|
||||
|
||||
@@ -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)])
|
||||
|
||||
@@ -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
274
compiler/layouter.nim
Normal 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(".}")
|
||||
@@ -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)
|
||||
|
||||
@@ -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
267
compiler/lineinfos.nim
Normal file
@@ -0,0 +1,267 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2018 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module contains the ``TMsgKind`` enum as well as the
|
||||
## ``TLineInfo`` object.
|
||||
|
||||
import ropes, tables
|
||||
|
||||
const
|
||||
explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
|
||||
|
||||
type
|
||||
TMsgKind* = enum
|
||||
errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile,
|
||||
errXExpected,
|
||||
errGridTableNotImplemented,
|
||||
errGeneralParseError,
|
||||
errNewSectionExpected,
|
||||
errInvalidDirectiveX,
|
||||
errGenerated,
|
||||
errUser,
|
||||
warnCannotOpenFile,
|
||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||
warnDeprecated, warnConfigDeprecated,
|
||||
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
|
||||
warnUnknownSubstitutionX, warnLanguageXNotSupported,
|
||||
warnFieldXNotSupported, warnCommentXIgnored,
|
||||
warnTypelessParam,
|
||||
warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
|
||||
warnEachIdentIsTuple, warnShadowIdent,
|
||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||
warnInconsistentSpacing, warnUser,
|
||||
hintSuccess, hintSuccessX,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||
hintConditionAlwaysTrue, hintName, hintPattern,
|
||||
hintExecuting, hintLinking, hintDependency,
|
||||
hintSource, hintPerformance, hintStackTrace, hintGCStats,
|
||||
hintGlobalVar,
|
||||
hintUser, hintUserRaw
|
||||
|
||||
const
|
||||
MsgKindToStr*: array[TMsgKind, string] = [
|
||||
errUnknown: "unknown error",
|
||||
errInternal: "internal error: $1",
|
||||
errIllFormedAstX: "illformed AST: $1",
|
||||
errCannotOpenFile: "cannot open '$1'",
|
||||
errXExpected: "'$1' expected",
|
||||
errGridTableNotImplemented: "grid table is not implemented",
|
||||
errGeneralParseError: "general parse error",
|
||||
errNewSectionExpected: "new section expected",
|
||||
errInvalidDirectiveX: "invalid directive: '$1'",
|
||||
errGenerated: "$1",
|
||||
errUser: "$1",
|
||||
warnCannotOpenFile: "cannot open '$1'",
|
||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
||||
warnXIsNeverRead: "'$1' is never read",
|
||||
warnXmightNotBeenInit: "'$1' might not have been initialized",
|
||||
warnDeprecated: "$1 is deprecated",
|
||||
warnConfigDeprecated: "config file '$1' is deprecated",
|
||||
warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)",
|
||||
warnUnknownMagic: "unknown magic '$1' might crash the compiler",
|
||||
warnRedefinitionOfLabel: "redefinition of label '$1'",
|
||||
warnUnknownSubstitutionX: "unknown substitution '$1'",
|
||||
warnLanguageXNotSupported: "language '$1' not supported",
|
||||
warnFieldXNotSupported: "field '$1' not supported",
|
||||
warnCommentXIgnored: "comment '$1' ignored",
|
||||
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
|
||||
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
|
||||
warnWriteToForeignHeap: "write to foreign heap",
|
||||
warnUnsafeCode: "unsafe code: '$1'",
|
||||
warnEachIdentIsTuple: "each identifier is a tuple",
|
||||
warnShadowIdent: "shadowed identifier: '$1'",
|
||||
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.",
|
||||
warnProveField: "cannot prove that field '$1' is accessible",
|
||||
warnProveIndex: "cannot prove index '$1' is valid",
|
||||
warnGcUnsafe: "not GC-safe: '$1'",
|
||||
warnGcUnsafe2: "$1",
|
||||
warnUninit: "'$1' might not have been initialized",
|
||||
warnGcMem: "'$1' uses GC'ed memory",
|
||||
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
|
||||
warnLockLevel: "$1",
|
||||
warnResultShadowed: "Special variable 'result' is shadowed.",
|
||||
warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
|
||||
warnUser: "$1",
|
||||
hintSuccess: "operation successful",
|
||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
|
||||
hintLineTooLong: "line too long",
|
||||
hintXDeclaredButNotUsed: "'$1' is declared but not used",
|
||||
hintConvToBaseNotNeeded: "conversion to base object is not needed",
|
||||
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
|
||||
hintExprAlwaysX: "expression evaluates always to '$1'",
|
||||
hintQuitCalled: "quit() called",
|
||||
hintProcessing: "$1",
|
||||
hintCodeBegin: "generated code listing:",
|
||||
hintCodeEnd: "end of listing",
|
||||
hintConf: "used config file '$1'",
|
||||
hintPath: "added path: '$1'",
|
||||
hintConditionAlwaysTrue: "condition is always true: '$1'",
|
||||
hintName: "name should be: '$1'",
|
||||
hintPattern: "$1",
|
||||
hintExecuting: "$1",
|
||||
hintLinking: "",
|
||||
hintDependency: "$1",
|
||||
hintSource: "$1",
|
||||
hintPerformance: "$1",
|
||||
hintStackTrace: "$1",
|
||||
hintGCStats: "$1",
|
||||
hintGlobalVar: "global variable declared here",
|
||||
hintUser: "$1",
|
||||
hintUserRaw: "$1"]
|
||||
|
||||
const
|
||||
WarningsToStr* = ["CannotOpenFile", "OctalEscape",
|
||||
"XIsNeverRead", "XmightNotBeenInit",
|
||||
"Deprecated", "ConfigDeprecated",
|
||||
"SmallLshouldNotBeUsed", "UnknownMagic",
|
||||
"RedefinitionOfLabel", "UnknownSubstitutionX",
|
||||
"LanguageXNotSupported", "FieldXNotSupported",
|
||||
"CommentXIgnored",
|
||||
"TypelessParam", "UseBase", "WriteToForeignHeap",
|
||||
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
|
||||
"Spacing", "User"]
|
||||
|
||||
HintsToStr* = ["Success", "SuccessX", "LineTooLong",
|
||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
|
||||
"Source", "Performance", "StackTrace", "GCStats", "GlobalVar",
|
||||
"User", "UserRaw"]
|
||||
|
||||
const
|
||||
fatalMin* = errUnknown
|
||||
fatalMax* = errInternal
|
||||
errMin* = errUnknown
|
||||
errMax* = errUser
|
||||
warnMin* = warnCannotOpenFile
|
||||
warnMax* = pred(hintSuccess)
|
||||
hintMin* = hintSuccess
|
||||
hintMax* = high(TMsgKind)
|
||||
|
||||
static:
|
||||
doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
|
||||
doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
|
||||
|
||||
type
|
||||
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
|
||||
TNoteKinds* = set[TNoteKind]
|
||||
|
||||
const
|
||||
NotesVerbosity*: array[0..3, TNoteKinds] = [
|
||||
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
|
||||
warnProveField, warnProveIndex,
|
||||
warnGcUnsafe,
|
||||
hintSuccessX, hintPath, hintConf,
|
||||
hintProcessing, hintPattern,
|
||||
hintDependency,
|
||||
hintExecuting, hintLinking,
|
||||
hintCodeBegin, hintCodeEnd,
|
||||
hintSource, hintStackTrace,
|
||||
hintGlobalVar, hintGCStats},
|
||||
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
|
||||
warnProveField, warnProveIndex,
|
||||
warnGcUnsafe,
|
||||
hintPath,
|
||||
hintDependency,
|
||||
hintCodeBegin, hintCodeEnd,
|
||||
hintSource, hintStackTrace,
|
||||
hintGlobalVar, hintGCStats},
|
||||
{low(TNoteKind)..high(TNoteKind)} - {hintStackTrace, warnUninit},
|
||||
{low(TNoteKind)..high(TNoteKind)}]
|
||||
|
||||
const
|
||||
errXMustBeCompileTime* = "'$1' can only be used in compile-time context"
|
||||
errArgsNeedRunOption* = "arguments can only be given if the '--run' option is selected"
|
||||
|
||||
type
|
||||
TFileInfo* = object
|
||||
fullPath*: string # This is a canonical full filesystem path
|
||||
projPath*: string # This is relative to the project's root
|
||||
shortName*: string # short name of the module
|
||||
quotedName*: Rope # cached quoted short name for codegen
|
||||
# purposes
|
||||
quotedFullName*: Rope # cached quoted full name for codegen
|
||||
# purposes
|
||||
|
||||
lines*: seq[string] # the source code of the module
|
||||
# used for better error messages and
|
||||
# embedding the original source in the
|
||||
# generated code
|
||||
dirtyfile*: string # the file that is actually read into memory
|
||||
# and parsed; usually "" but is used
|
||||
# for 'nimsuggest'
|
||||
hash*: string # the checksum of the file
|
||||
dirty*: bool # for 'nimfix' / 'nimpretty' like tooling
|
||||
when defined(nimpretty):
|
||||
fullContent*: string
|
||||
FileIndex* = distinct int32
|
||||
TLineInfo* = object # This is designed to be as small as possible,
|
||||
# because it is used
|
||||
# in syntax nodes. We save space here by using
|
||||
# two int16 and an int32.
|
||||
# On 64 bit and on 32 bit systems this is
|
||||
# only 8 bytes.
|
||||
line*: uint16
|
||||
col*: int16
|
||||
fileIndex*: FileIndex
|
||||
when defined(nimpretty):
|
||||
offsetA*, offsetB*: int
|
||||
commentOffsetA*, commentOffsetB*: int
|
||||
|
||||
TErrorOutput* = enum
|
||||
eStdOut
|
||||
eStdErr
|
||||
|
||||
TErrorOutputs* = set[TErrorOutput]
|
||||
|
||||
ERecoverableError* = object of ValueError
|
||||
ESuggestDone* = object of Exception
|
||||
|
||||
proc `==`*(a, b: FileIndex): bool {.borrow.}
|
||||
|
||||
const
|
||||
InvalidFileIDX* = FileIndex(-1)
|
||||
|
||||
proc unknownLineInfo*(): TLineInfo =
|
||||
result.line = uint16(0)
|
||||
result.col = int16(-1)
|
||||
result.fileIndex = InvalidFileIDX
|
||||
|
||||
type
|
||||
Severity* {.pure.} = enum ## VS Code only supports these three
|
||||
Hint, Warning, Error
|
||||
|
||||
const trackPosInvalidFileIdx* = FileIndex(-2) # special marker so that no suggestions
|
||||
# are produced within comments and string literals
|
||||
|
||||
type
|
||||
MsgConfig* = object ## does not need to be stored in the incremental cache
|
||||
trackPos*: TLineInfo
|
||||
trackPosAttached*: bool ## whether the tracking position was attached to
|
||||
## some close token.
|
||||
|
||||
errorOutputs*: TErrorOutputs
|
||||
msgContext*: seq[TLineInfo]
|
||||
lastError*: TLineInfo
|
||||
filenameToIndexTbl*: Table[string, FileIndex]
|
||||
fileInfos*: seq[TFileInfo]
|
||||
systemFileIdx*: FileIndex
|
||||
|
||||
|
||||
proc initMsgConfig*(): MsgConfig =
|
||||
result.msgContext = @[]
|
||||
result.lastError = unknownLineInfo()
|
||||
result.filenameToIndexTbl = initTable[string, FileIndex]()
|
||||
result.fileInfos = @[]
|
||||
result.errorOutputs = {eStdOut, eStdErr}
|
||||
@@ -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) =
|
||||
@@ -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 =
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
79
compiler/macrocacheimpl.nim
Normal file
79
compiler/macrocacheimpl.nim
Normal file
@@ -0,0 +1,79 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2018 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements helpers for the macro cache.
|
||||
|
||||
import lineinfos, ast, modulegraphs, vmdef, magicsys
|
||||
|
||||
proc recordInc*(c: PCtx; info: TLineInfo; key: string; by: BiggestInt) =
|
||||
var recorded = newNodeI(nkCommentStmt, info)
|
||||
recorded.add newStrNode("inc", info)
|
||||
recorded.add newStrNode(key, info)
|
||||
recorded.add newIntNode(nkIntLit, by)
|
||||
c.graph.recordStmt(c.graph, c.module, recorded)
|
||||
|
||||
proc recordPut*(c: PCtx; info: TLineInfo; key: string; k: string; val: PNode) =
|
||||
var recorded = newNodeI(nkCommentStmt, info)
|
||||
recorded.add newStrNode("put", info)
|
||||
recorded.add newStrNode(key, info)
|
||||
recorded.add newStrNode(k, info)
|
||||
recorded.add copyTree(val)
|
||||
c.graph.recordStmt(c.graph, c.module, recorded)
|
||||
|
||||
proc recordAdd*(c: PCtx; info: TLineInfo; key: string; val: PNode) =
|
||||
var recorded = newNodeI(nkCommentStmt, info)
|
||||
recorded.add newStrNode("add", info)
|
||||
recorded.add newStrNode(key, info)
|
||||
recorded.add copyTree(val)
|
||||
c.graph.recordStmt(c.graph, c.module, recorded)
|
||||
|
||||
proc recordIncl*(c: PCtx; info: TLineInfo; key: string; val: PNode) =
|
||||
var recorded = newNodeI(nkCommentStmt, info)
|
||||
recorded.add newStrNode("incl", info)
|
||||
recorded.add newStrNode(key, info)
|
||||
recorded.add copyTree(val)
|
||||
c.graph.recordStmt(c.graph, c.module, recorded)
|
||||
|
||||
when false:
|
||||
proc genCall3(g: ModuleGraph; m: TMagic; s: string; a, b, c: PNode): PNode =
|
||||
newTree(nkStaticStmt, newTree(nkCall, createMagic(g, s, m).newSymNode, a, b, c))
|
||||
|
||||
proc genCall2(g: ModuleGraph; m: TMagic; s: string; a, b: PNode): PNode =
|
||||
newTree(nkStaticStmt, newTree(nkCall, createMagic(g, s, m).newSymNode, a, b))
|
||||
|
||||
template nodeFrom(s: string): PNode =
|
||||
var res = newStrNode(s, info)
|
||||
res.typ = getSysType(g, info, tyString)
|
||||
res
|
||||
|
||||
template nodeFrom(i: BiggestInt): PNode =
|
||||
var res = newIntNode(i, info)
|
||||
res.typ = getSysType(g, info, tyInt)
|
||||
res
|
||||
|
||||
template nodeFrom(n: PNode): PNode = copyTree(n)
|
||||
|
||||
template record(call) =
|
||||
g.recordStmt(g, c.module, call)
|
||||
|
||||
proc recordInc*(c: PCtx; info: TLineInfo; key: string; by: BiggestInt) =
|
||||
let g = c.graph
|
||||
record genCall2(mNccInc, "inc", nodeFrom key, nodeFrom by)
|
||||
|
||||
proc recordPut*(c: PCtx; info: TLineInfo; key: string; k: string; val: PNode) =
|
||||
let g = c.graph
|
||||
record genCall3(mNctPut, "[]=", nodeFrom key, nodeFrom k, nodeFrom val)
|
||||
|
||||
proc recordAdd*(c: PCtx; info: TLineInfo; key: string; val: PNode) =
|
||||
let g = c.graph
|
||||
record genCall2(mNcsAdd, "add", nodeFrom key, nodeFrom val)
|
||||
|
||||
proc recordIncl*(c: PCtx; info: TLineInfo; key: string; val: PNode) =
|
||||
let g = c.graph
|
||||
record genCall2(mNcsIncl, "incl", nodeFrom key, nodeFrom val)
|
||||
@@ -10,8 +10,8 @@
|
||||
# Built-in types and compilerprocs are registered here.
|
||||
|
||||
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)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)]
|
||||
])
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -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")
|
||||
|
||||
1244
compiler/rodread.nim
1244
compiler/rodread.nim
File diff suppressed because it is too large
Load Diff
@@ -1,659 +0,0 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# This module is responsible for writing of rod files. Note that writing of
|
||||
# rod files is a pass, reading of rod files is not! This is why reading and
|
||||
# writing of rod files is split into two different modules.
|
||||
|
||||
import
|
||||
intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
|
||||
condsyms, ropes, idents, std / sha1, rodread, passes, idgen,
|
||||
rodutils, modulepaths
|
||||
|
||||
from modulegraphs import ModuleGraph
|
||||
|
||||
type
|
||||
TRodWriter = object of TPassContext
|
||||
module: PSym
|
||||
hash: SecureHash
|
||||
options: TOptions
|
||||
defines: string
|
||||
inclDeps: string
|
||||
modDeps: string
|
||||
interf: string
|
||||
compilerProcs: string
|
||||
index, imports: TIndex
|
||||
converters, methods: string
|
||||
init: string
|
||||
data: string
|
||||
sstack: TSymSeq # a stack of symbols to process
|
||||
tstack: TTypeSeq # a stack of types to process
|
||||
files: TStringSeq
|
||||
origFile: string
|
||||
cache: IdentCache
|
||||
config: ConfigRef
|
||||
|
||||
PRodWriter = ref TRodWriter
|
||||
|
||||
proc getDefines(conf: ConfigRef): string =
|
||||
result = ""
|
||||
for d in definedSymbolNames(conf.symbols):
|
||||
if result.len != 0: add(result, " ")
|
||||
add(result, d)
|
||||
|
||||
proc fileIdx(w: PRodWriter, filename: string): int =
|
||||
for i in countup(0, high(w.files)):
|
||||
if w.files[i] == filename:
|
||||
return i
|
||||
result = len(w.files)
|
||||
setLen(w.files, result + 1)
|
||||
w.files[result] = filename
|
||||
|
||||
template filename*(w: PRodWriter): string =
|
||||
toFilename(FileIndex w.module.position)
|
||||
|
||||
proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache;
|
||||
config: ConfigRef): PRodWriter =
|
||||
new(result)
|
||||
result.config = config
|
||||
result.sstack = @[]
|
||||
result.tstack = @[]
|
||||
initIiTable(result.index.tab)
|
||||
initIiTable(result.imports.tab)
|
||||
result.index.r = ""
|
||||
result.imports.r = ""
|
||||
result.hash = hash
|
||||
result.module = module
|
||||
result.defines = getDefines(config)
|
||||
result.options = config.options
|
||||
result.files = @[]
|
||||
result.inclDeps = ""
|
||||
result.modDeps = ""
|
||||
result.interf = newStringOfCap(2_000)
|
||||
result.compilerProcs = ""
|
||||
result.converters = ""
|
||||
result.methods = ""
|
||||
result.init = ""
|
||||
result.origFile = module.info.toFullPath
|
||||
result.data = newStringOfCap(12_000)
|
||||
result.cache = cache
|
||||
|
||||
proc addModDep(w: PRodWriter, dep: string; info: TLineInfo) =
|
||||
if w.modDeps.len != 0: add(w.modDeps, ' ')
|
||||
let resolved = findModule(w.config, dep, info.toFullPath)
|
||||
encodeVInt(fileIdx(w, resolved), w.modDeps)
|
||||
|
||||
const
|
||||
rodNL = "\x0A"
|
||||
|
||||
proc addInclDep(w: PRodWriter, dep: string; info: TLineInfo) =
|
||||
let resolved = findModule(w.config, dep, info.toFullPath)
|
||||
encodeVInt(fileIdx(w, resolved), w.inclDeps)
|
||||
add(w.inclDeps, " ")
|
||||
encodeStr($secureHashFile(resolved), w.inclDeps)
|
||||
add(w.inclDeps, rodNL)
|
||||
|
||||
proc pushType(w: PRodWriter, t: PType) =
|
||||
# check so that the stack does not grow too large:
|
||||
if iiTableGet(w.index.tab, t.id) == InvalidKey:
|
||||
w.tstack.add(t)
|
||||
|
||||
proc pushSym(w: PRodWriter, s: PSym) =
|
||||
# check so that the stack does not grow too large:
|
||||
if iiTableGet(w.index.tab, s.id) == InvalidKey:
|
||||
when false:
|
||||
if s.kind == skMethod:
|
||||
echo "encoding ", s.id, " ", s.name.s
|
||||
writeStackTrace()
|
||||
w.sstack.add(s)
|
||||
|
||||
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
||||
result: var string) =
|
||||
if n == nil:
|
||||
# nil nodes have to be stored too:
|
||||
result.add("()")
|
||||
return
|
||||
result.add('(')
|
||||
encodeVInt(ord(n.kind), result)
|
||||
# we do not write comments for now
|
||||
# Line information takes easily 20% or more of the filesize! Therefore we
|
||||
# omit line information if it is the same as the father's line information:
|
||||
if fInfo.fileIndex != n.info.fileIndex:
|
||||
result.add('?')
|
||||
encodeVInt(n.info.col, result)
|
||||
result.add(',')
|
||||
encodeVInt(int n.info.line, result)
|
||||
result.add(',')
|
||||
encodeVInt(fileIdx(w, toFullPath(n.info)), result)
|
||||
elif fInfo.line != n.info.line:
|
||||
result.add('?')
|
||||
encodeVInt(n.info.col, result)
|
||||
result.add(',')
|
||||
encodeVInt(int n.info.line, result)
|
||||
elif fInfo.col != n.info.col:
|
||||
result.add('?')
|
||||
encodeVInt(n.info.col, result)
|
||||
# No need to output the file index, as this is the serialization of one
|
||||
# file.
|
||||
var f = n.flags * PersistentNodeFlags
|
||||
if f != {}:
|
||||
result.add('$')
|
||||
encodeVInt(cast[int32](f), result)
|
||||
if n.typ != nil:
|
||||
result.add('^')
|
||||
encodeVInt(n.typ.id, result)
|
||||
pushType(w, n.typ)
|
||||
case n.kind
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
if n.intVal != 0:
|
||||
result.add('!')
|
||||
encodeVBiggestInt(n.intVal, result)
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if n.floatVal != 0.0:
|
||||
result.add('!')
|
||||
encodeStr($n.floatVal, result)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if n.strVal != "":
|
||||
result.add('!')
|
||||
encodeStr(n.strVal, result)
|
||||
of nkIdent:
|
||||
result.add('!')
|
||||
encodeStr(n.ident.s, result)
|
||||
of nkSym:
|
||||
result.add('!')
|
||||
encodeVInt(n.sym.id, result)
|
||||
pushSym(w, n.sym)
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
encodeNode(w, n.info, n.sons[i], result)
|
||||
add(result, ')')
|
||||
|
||||
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
||||
var oldLen = result.len
|
||||
result.add('<')
|
||||
if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
|
||||
if loc.storage != low(loc.storage):
|
||||
add(result, '*')
|
||||
encodeVInt(ord(loc.storage), result)
|
||||
if loc.flags != {}:
|
||||
add(result, '$')
|
||||
encodeVInt(cast[int32](loc.flags), result)
|
||||
if loc.lode != nil:
|
||||
add(result, '^')
|
||||
encodeNode(w, unknownLineInfo(), loc.lode, result)
|
||||
#encodeVInt(cast[int32](loc.t.id), result)
|
||||
#pushType(w, loc.t)
|
||||
if loc.r != nil:
|
||||
add(result, '!')
|
||||
encodeStr($loc.r, result)
|
||||
if oldLen + 1 == result.len:
|
||||
# no data was necessary, so remove the '<' again:
|
||||
setLen(result, oldLen)
|
||||
else:
|
||||
add(result, '>')
|
||||
|
||||
proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
||||
if t == nil:
|
||||
# nil nodes have to be stored too:
|
||||
result.add("[]")
|
||||
return
|
||||
# we need no surrounding [] here because the type is in a line of its own
|
||||
if t.kind == tyForward: internalError(w.config, "encodeType: tyForward")
|
||||
# for the new rodfile viewer we use a preceding [ so that the data section
|
||||
# can easily be disambiguated:
|
||||
add(result, '[')
|
||||
encodeVInt(ord(t.kind), result)
|
||||
add(result, '+')
|
||||
encodeVInt(t.id, result)
|
||||
if t.n != nil:
|
||||
encodeNode(w, unknownLineInfo(), t.n, result)
|
||||
if t.flags != {}:
|
||||
add(result, '$')
|
||||
encodeVInt(cast[int32](t.flags), result)
|
||||
if t.callConv != low(t.callConv):
|
||||
add(result, '?')
|
||||
encodeVInt(ord(t.callConv), result)
|
||||
if t.owner != nil:
|
||||
add(result, '*')
|
||||
encodeVInt(t.owner.id, result)
|
||||
pushSym(w, t.owner)
|
||||
if t.sym != nil:
|
||||
add(result, '&')
|
||||
encodeVInt(t.sym.id, result)
|
||||
pushSym(w, t.sym)
|
||||
if t.size != - 1:
|
||||
add(result, '/')
|
||||
encodeVBiggestInt(t.size, result)
|
||||
if t.align != 2:
|
||||
add(result, '=')
|
||||
encodeVInt(t.align, result)
|
||||
if t.lockLevel.ord != UnspecifiedLockLevel.ord:
|
||||
add(result, '\14')
|
||||
encodeVInt(t.lockLevel.int16, result)
|
||||
if t.destructor != nil and t.destructor.id != 0:
|
||||
add(result, '\15')
|
||||
encodeVInt(t.destructor.id, result)
|
||||
pushSym(w, t.destructor)
|
||||
if t.deepCopy != nil:
|
||||
add(result, '\16')
|
||||
encodeVInt(t.deepcopy.id, result)
|
||||
pushSym(w, t.deepcopy)
|
||||
if t.assignment != nil:
|
||||
add(result, '\17')
|
||||
encodeVInt(t.assignment.id, result)
|
||||
pushSym(w, t.assignment)
|
||||
if t.sink != nil:
|
||||
add(result, '\18')
|
||||
encodeVInt(t.sink.id, result)
|
||||
pushSym(w, t.sink)
|
||||
for i, s in items(t.methods):
|
||||
add(result, '\19')
|
||||
encodeVInt(i, result)
|
||||
add(result, '\20')
|
||||
encodeVInt(s.id, result)
|
||||
pushSym(w, s)
|
||||
encodeLoc(w, t.loc, result)
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
if t.sons[i] == nil:
|
||||
add(result, "^()")
|
||||
else:
|
||||
add(result, '^')
|
||||
encodeVInt(t.sons[i].id, result)
|
||||
pushType(w, t.sons[i])
|
||||
|
||||
proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
|
||||
add(result, '|')
|
||||
encodeVInt(ord(lib.kind), result)
|
||||
add(result, '|')
|
||||
encodeStr($lib.name, result)
|
||||
add(result, '|')
|
||||
encodeNode(w, info, lib.path, result)
|
||||
|
||||
proc encodeInstantiations(w: PRodWriter; s: seq[PInstantiation];
|
||||
result: var string) =
|
||||
for t in s:
|
||||
result.add('\15')
|
||||
encodeVInt(t.sym.id, result)
|
||||
pushSym(w, t.sym)
|
||||
for tt in t.concreteTypes:
|
||||
result.add('\17')
|
||||
encodeVInt(tt.id, result)
|
||||
pushType(w, tt)
|
||||
result.add('\20')
|
||||
encodeVInt(t.compilesId, result)
|
||||
|
||||
proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
||||
if s == nil:
|
||||
# nil nodes have to be stored too:
|
||||
result.add("{}")
|
||||
return
|
||||
# we need no surrounding {} here because the symbol is in a line of its own
|
||||
encodeVInt(ord(s.kind), result)
|
||||
result.add('+')
|
||||
encodeVInt(s.id, result)
|
||||
result.add('&')
|
||||
encodeStr(s.name.s, result)
|
||||
if s.typ != nil:
|
||||
result.add('^')
|
||||
encodeVInt(s.typ.id, result)
|
||||
pushType(w, s.typ)
|
||||
result.add('?')
|
||||
if s.info.col != -1'i16: encodeVInt(s.info.col, result)
|
||||
result.add(',')
|
||||
if s.info.line != 0'u16: encodeVInt(int s.info.line, result)
|
||||
result.add(',')
|
||||
encodeVInt(fileIdx(w, toFullPath(s.info)), result)
|
||||
if s.owner != nil:
|
||||
result.add('*')
|
||||
encodeVInt(s.owner.id, result)
|
||||
pushSym(w, s.owner)
|
||||
if s.flags != {}:
|
||||
result.add('$')
|
||||
encodeVInt(cast[int32](s.flags), result)
|
||||
if s.magic != mNone:
|
||||
result.add('@')
|
||||
encodeVInt(ord(s.magic), result)
|
||||
if s.options != w.options:
|
||||
result.add('!')
|
||||
encodeVInt(cast[int32](s.options), result)
|
||||
if s.position != 0:
|
||||
result.add('%')
|
||||
encodeVInt(s.position, result)
|
||||
if s.offset != - 1:
|
||||
result.add('`')
|
||||
encodeVInt(s.offset, result)
|
||||
encodeLoc(w, s.loc, result)
|
||||
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
|
||||
if s.constraint != nil:
|
||||
add(result, '#')
|
||||
encodeNode(w, unknownLineInfo(), s.constraint, result)
|
||||
case s.kind
|
||||
of skType, skGenericParam:
|
||||
for t in s.typeInstCache:
|
||||
result.add('\14')
|
||||
encodeVInt(t.id, result)
|
||||
pushType(w, t)
|
||||
of routineKinds:
|
||||
encodeInstantiations(w, s.procInstCache, result)
|
||||
if s.gcUnsafetyReason != nil:
|
||||
result.add('\16')
|
||||
encodeVInt(s.gcUnsafetyReason.id, result)
|
||||
pushSym(w, s.gcUnsafetyReason)
|
||||
of skModule, skPackage:
|
||||
encodeInstantiations(w, s.usedGenerics, result)
|
||||
# we don't serialize:
|
||||
#tab*: TStrTable # interface table for modules
|
||||
of skLet, skVar, skField, skForVar:
|
||||
if s.guard != nil:
|
||||
result.add('\18')
|
||||
encodeVInt(s.guard.id, result)
|
||||
pushSym(w, s.guard)
|
||||
if s.bitsize != 0:
|
||||
result.add('\19')
|
||||
encodeVInt(s.bitsize, result)
|
||||
else: discard
|
||||
# lazy loading will soon reload the ast lazily, so the ast needs to be
|
||||
# the last entry of a symbol:
|
||||
if s.ast != nil:
|
||||
# we used to attempt to save space here by only storing a dummy AST if
|
||||
# it is not necessary, but Nim's heavy compile-time evaluation features
|
||||
# make that unfeasible nowadays:
|
||||
encodeNode(w, s.info, s.ast, result)
|
||||
|
||||
proc addToIndex(w: var TIndex, key, val: int) =
|
||||
if key - w.lastIdxKey == 1:
|
||||
# we do not store a key-diff of 1 to safe space
|
||||
encodeVInt(val - w.lastIdxVal, w.r)
|
||||
else:
|
||||
encodeVInt(key - w.lastIdxKey, w.r)
|
||||
add(w.r, ' ')
|
||||
encodeVInt(val - w.lastIdxVal, w.r)
|
||||
add(w.r, rodNL)
|
||||
w.lastIdxKey = key
|
||||
w.lastIdxVal = val
|
||||
iiTablePut(w.tab, key, val)
|
||||
|
||||
const debugWrittenIds = false
|
||||
|
||||
when debugWrittenIds:
|
||||
var debugWritten = initIntSet()
|
||||
|
||||
proc symStack(w: PRodWriter): int =
|
||||
var i = 0
|
||||
while i < len(w.sstack):
|
||||
var s = w.sstack[i]
|
||||
if sfForward in s.flags:
|
||||
w.sstack[result] = s
|
||||
inc result
|
||||
elif iiTableGet(w.index.tab, s.id) == InvalidKey:
|
||||
var m = getModule(s)
|
||||
#if m == nil and s.kind != skPackage and sfGenSym notin s.flags:
|
||||
# internalError("symStack: module nil: " & s.name.s & " " & $s.kind & " ID " & $s.id)
|
||||
if m == nil or s.kind == skPackage or {sfFromGeneric, sfGenSym} * s.flags != {} or m.id == w.module.id:
|
||||
# put definition in here
|
||||
var L = w.data.len
|
||||
addToIndex(w.index, s.id, L)
|
||||
when debugWrittenIds: incl(debugWritten, s.id)
|
||||
encodeSym(w, s, w.data)
|
||||
add(w.data, rodNL)
|
||||
# put into interface section if appropriate:
|
||||
if {sfExported, sfFromGeneric} * s.flags == {sfExported} and
|
||||
s.kind in ExportableSymKinds:
|
||||
encodeStr(s.name.s, w.interf)
|
||||
add(w.interf, ' ')
|
||||
encodeVInt(s.id, w.interf)
|
||||
add(w.interf, rodNL)
|
||||
if sfCompilerProc in s.flags:
|
||||
encodeStr(s.name.s, w.compilerProcs)
|
||||
add(w.compilerProcs, ' ')
|
||||
encodeVInt(s.id, w.compilerProcs)
|
||||
add(w.compilerProcs, rodNL)
|
||||
if s.kind == skConverter or (s.ast != nil and hasPattern(s)):
|
||||
if w.converters.len != 0: add(w.converters, ' ')
|
||||
encodeVInt(s.id, w.converters)
|
||||
if s.kind == skMethod and sfDispatcher notin s.flags:
|
||||
if w.methods.len != 0: add(w.methods, ' ')
|
||||
encodeVInt(s.id, w.methods)
|
||||
elif iiTableGet(w.imports.tab, s.id) == InvalidKey:
|
||||
addToIndex(w.imports, s.id, m.id)
|
||||
when debugWrittenIds:
|
||||
if not contains(debugWritten, s.id):
|
||||
echo(w.filename)
|
||||
debug(s)
|
||||
debug(s.owner)
|
||||
debug(m)
|
||||
internalError("Symbol referred to but never written")
|
||||
inc(i)
|
||||
setLen(w.sstack, result)
|
||||
|
||||
proc typeStack(w: PRodWriter): int =
|
||||
var i = 0
|
||||
while i < len(w.tstack):
|
||||
var t = w.tstack[i]
|
||||
if t.kind == tyForward:
|
||||
w.tstack[result] = t
|
||||
inc result
|
||||
elif iiTableGet(w.index.tab, t.id) == InvalidKey:
|
||||
var L = w.data.len
|
||||
addToIndex(w.index, t.id, L)
|
||||
encodeType(w, t, w.data)
|
||||
add(w.data, rodNL)
|
||||
inc(i)
|
||||
setLen(w.tstack, result)
|
||||
|
||||
proc processStacks(w: PRodWriter, finalPass: bool) =
|
||||
var oldS = 0
|
||||
var oldT = 0
|
||||
while true:
|
||||
var slen = symStack(w)
|
||||
var tlen = typeStack(w)
|
||||
if slen == oldS and tlen == oldT: break
|
||||
oldS = slen
|
||||
oldT = tlen
|
||||
if finalPass and (oldS != 0 or oldT != 0):
|
||||
internalError(w.config, "could not serialize some forwarded symbols/types")
|
||||
|
||||
proc rawAddInterfaceSym(w: PRodWriter, s: PSym) =
|
||||
pushSym(w, s)
|
||||
processStacks(w, false)
|
||||
|
||||
proc addInterfaceSym(w: PRodWriter, s: PSym) =
|
||||
if w == nil: return
|
||||
if s.kind in ExportableSymKinds and
|
||||
{sfExported, sfCompilerProc} * s.flags != {}:
|
||||
rawAddInterfaceSym(w, s)
|
||||
|
||||
proc addStmt(w: PRodWriter, n: PNode) =
|
||||
encodeVInt(w.data.len, w.init)
|
||||
add(w.init, rodNL)
|
||||
encodeNode(w, unknownLineInfo(), n, w.data)
|
||||
add(w.data, rodNL)
|
||||
processStacks(w, false)
|
||||
|
||||
proc writeRod(w: PRodWriter) =
|
||||
processStacks(w, true)
|
||||
var f: File
|
||||
if not open(f, completeGeneratedFilePath(w.config, changeFileExt(
|
||||
withPackageName(w.config, w.filename), RodExt)),
|
||||
fmWrite):
|
||||
#echo "couldn't write rod file for: ", w.filename
|
||||
return
|
||||
# write header:
|
||||
f.write("NIM:")
|
||||
f.write(RodFileVersion)
|
||||
f.write(rodNL)
|
||||
var id = "ID:"
|
||||
encodeVInt(w.module.id, id)
|
||||
f.write(id)
|
||||
f.write(rodNL)
|
||||
|
||||
var orig = "ORIGFILE:"
|
||||
encodeStr(w.origFile, orig)
|
||||
f.write(orig)
|
||||
f.write(rodNL)
|
||||
|
||||
var hash = "HASH:"
|
||||
encodeStr($w.hash, hash)
|
||||
f.write(hash)
|
||||
f.write(rodNL)
|
||||
|
||||
var options = "OPTIONS:"
|
||||
encodeVInt(cast[int32](w.options), options)
|
||||
f.write(options)
|
||||
f.write(rodNL)
|
||||
|
||||
var goptions = "GOPTIONS:"
|
||||
encodeVInt(cast[int32](w.config.globalOptions), goptions)
|
||||
f.write(goptions)
|
||||
f.write(rodNL)
|
||||
|
||||
var cmd = "CMD:"
|
||||
encodeVInt(cast[int32](w.config.cmd), cmd)
|
||||
f.write(cmd)
|
||||
f.write(rodNL)
|
||||
|
||||
f.write("DEFINES:")
|
||||
f.write(w.defines)
|
||||
f.write(rodNL)
|
||||
|
||||
var files = "FILES(" & rodNL
|
||||
for i in countup(0, high(w.files)):
|
||||
encodeStr(w.files[i], files)
|
||||
files.add(rodNL)
|
||||
f.write(files)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
f.write("INCLUDES(" & rodNL)
|
||||
f.write(w.inclDeps)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
f.write("DEPS:")
|
||||
f.write(w.modDeps)
|
||||
f.write(rodNL)
|
||||
|
||||
f.write("INTERF(" & rodNL)
|
||||
f.write(w.interf)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
f.write("COMPILERPROCS(" & rodNL)
|
||||
f.write(w.compilerProcs)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
f.write("INDEX(" & rodNL)
|
||||
f.write(w.index.r)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
f.write("IMPORTS(" & rodNL)
|
||||
f.write(w.imports.r)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
f.write("CONVERTERS:")
|
||||
f.write(w.converters)
|
||||
f.write(rodNL)
|
||||
|
||||
f.write("METHODS:")
|
||||
f.write(w.methods)
|
||||
f.write(rodNL)
|
||||
|
||||
f.write("INIT(" & rodNL)
|
||||
f.write(w.init)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
f.write("DATA(" & rodNL)
|
||||
f.write(w.data)
|
||||
f.write(')' & rodNL)
|
||||
# write trailing zero which is necessary because we use memory mapped files
|
||||
# for reading:
|
||||
f.write("\0")
|
||||
f.close()
|
||||
|
||||
#echo "interf: ", w.interf.len
|
||||
#echo "index: ", w.index.r.len
|
||||
#echo "init: ", w.init.len
|
||||
#echo "data: ", w.data.len
|
||||
|
||||
proc process(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if c == nil: return
|
||||
var w = PRodWriter(c)
|
||||
case n.kind
|
||||
of nkStmtList:
|
||||
for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i])
|
||||
#var s = n.sons[namePos].sym
|
||||
#addInterfaceSym(w, s)
|
||||
of nkProcDef, nkFuncDef, nkIteratorDef, nkConverterDef,
|
||||
nkTemplateDef, nkMacroDef:
|
||||
let s = n.sons[namePos].sym
|
||||
if s == nil: internalError(w.config, n.info, "rodwrite.process")
|
||||
if n.sons[bodyPos] == nil:
|
||||
internalError(w.config, n.info, "rodwrite.process: body is nil")
|
||||
if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
|
||||
sfForward notin s.flags:
|
||||
addInterfaceSym(w, s)
|
||||
of nkMethodDef:
|
||||
let s = n.sons[namePos].sym
|
||||
if s == nil: internalError(w.config, n.info, "rodwrite.process")
|
||||
if n.sons[bodyPos] == nil:
|
||||
internalError(w.config, n.info, "rodwrite.process: body is nil")
|
||||
if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
|
||||
sfForward notin s.flags:
|
||||
pushSym(w, s)
|
||||
processStacks(w, false)
|
||||
|
||||
of nkVarSection, nkLetSection, nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
addInterfaceSym(w, a.sons[0].sym)
|
||||
of nkTypeSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.sons[0].kind != nkSym: internalError(w.config, a.info, "rodwrite.process")
|
||||
var s = a.sons[0].sym
|
||||
addInterfaceSym(w, s)
|
||||
# this takes care of enum fields too
|
||||
# Note: The check for ``s.typ.kind = tyEnum`` is wrong for enum
|
||||
# type aliasing! Otherwise the same enum symbol would be included
|
||||
# several times!
|
||||
#
|
||||
# if (a.sons[2] <> nil) and (a.sons[2].kind = nkEnumTy) then begin
|
||||
# a := s.typ.n;
|
||||
# for j := 0 to sonsLen(a)-1 do
|
||||
# addInterfaceSym(w, a.sons[j].sym);
|
||||
# end
|
||||
of nkImportStmt:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
addModDep(w, getModuleName(w.config, n.sons[i]), n.info)
|
||||
addStmt(w, n)
|
||||
of nkFromStmt, nkImportExceptStmt:
|
||||
addModDep(w, getModuleName(w.config, n.sons[0]), n.info)
|
||||
addStmt(w, n)
|
||||
of nkIncludeStmt:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
addInclDep(w, getModuleName(w.config, n.sons[i]), n.info)
|
||||
of nkPragma:
|
||||
addStmt(w, n)
|
||||
else:
|
||||
discard
|
||||
|
||||
proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
|
||||
if module.id < 0: internalError(g.config, "rodwrite: module ID not set")
|
||||
var w = newRodWriter(rodread.getHash FileIndex module.position, module, cache, g.config)
|
||||
rawAddInterfaceSym(w, module)
|
||||
result = w
|
||||
|
||||
proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
|
||||
result = process(c, n)
|
||||
var w = PRodWriter(c)
|
||||
writeRod(w)
|
||||
idgen.saveMaxIds(graph.config, graph.config.projectPath / graph.config.projectName)
|
||||
|
||||
const rodwritePass* = makePass(open = myOpen, close = myClose, process = process)
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
# To cache them they are inserted in a `cache` array.
|
||||
|
||||
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
|
||||
|
||||
@@ -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")
|
||||
|
||||
103
compiler/sem.nim
103
compiler/sem.nim
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user