diff options
Diffstat (limited to 'compiler')
39 files changed, 500 insertions, 539 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 3798410e8..c141352cb 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -423,6 +423,7 @@ type # but unfortunately it has measurable impact for compilation # efficiency nfTransf, # node has been transformed + nfNoRewrite # node should not be transformed anymore nfSem # node has been checked for semantics nfLL # node has gone through lambda lifting nfDotField # the call can use a dot operator @@ -842,7 +843,7 @@ type data*: TIdNodePairSeq TNodePair* = object - h*: THash # because it is expensive to compute! + h*: Hash # because it is expensive to compute! key*: PNode val*: int @@ -1198,23 +1199,11 @@ proc newSons*(father: PType, length: int) = else: setLen(father.sons, length) -proc sonsLen*(n: PType): int = - if isNil(n.sons): result = 0 - else: result = len(n.sons) - -proc len*(n: PType): int = - if isNil(n.sons): result = 0 - else: result = len(n.sons) - -proc sonsLen*(n: PNode): int = - if isNil(n.sons): result = 0 - else: result = len(n.sons) - -proc lastSon*(n: PNode): PNode = - result = n.sons[sonsLen(n) - 1] - -proc lastSon*(n: PType): PType = - result = n.sons[sonsLen(n) - 1] +proc sonsLen*(n: PType): int = n.sons.len +proc len*(n: PType): int = n.sons.len +proc sonsLen*(n: PNode): int = n.sons.len +proc lastSon*(n: PNode): PNode = n.sons[^1] +proc lastSon*(n: PType): PType = n.sons[^1] proc assignType*(dest, src: PType) = dest.kind = src.kind @@ -1357,7 +1346,7 @@ proc propagateToOwner*(owner, elem: PType) = owner.flags.incl tfHasAsgn if owner.kind notin {tyProc, tyGenericInst, tyGenericBody, - tyGenericInvocation}: + tyGenericInvocation, tyPtr}: let elemB = elem.skipTypes({tyGenericInst}) if elemB.isGCedMem or tfHasGCedMem in elemB.flags: # for simplicity, we propagate this flag even to generics. We then diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 1707718d7..5980edb27 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -14,7 +14,7 @@ import ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils -proc hashNode*(p: RootRef): THash +proc hashNode*(p: RootRef): Hash proc treeToYaml*(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. @@ -49,7 +49,7 @@ proc strTableGet*(t: TStrTable, name: PIdent): PSym type TTabIter*{.final.} = object # consider all fields here private - h*: THash # current hash + h*: Hash # current hash proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym @@ -65,7 +65,7 @@ proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym type TIdentIter*{.final.} = object # iterator over all syms with same identifier - h*: THash # current hash + h*: Hash # current hash name*: PIdent @@ -94,7 +94,7 @@ 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: THash): THash {.inline.} +proc nextTry*(h, maxHash: Hash): Hash {.inline.} # ------------- table[int, int] --------------------------------------------- const @@ -196,7 +196,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym = else: internalError(list.info, "getSymFromList") result = nil -proc hashNode(p: RootRef): THash = +proc hashNode(p: RootRef): Hash = result = hash(cast[pointer](p)) proc mustRehash(length, counter: int): bool = @@ -466,7 +466,7 @@ proc debug(n: PNode) = const EmptySeq = @[] -proc nextTry(h, maxHash: THash): THash = +proc nextTry(h, maxHash: Hash): Hash = result = ((5 * h) + 1) and maxHash # For any initial h in range(maxHash), repeating that maxHash times # generates each int in range(maxHash) exactly once (see any text on @@ -474,7 +474,7 @@ proc nextTry(h, maxHash: THash): THash = proc objectSetContains(t: TObjectSet, obj: RootRef): bool = # returns true whether n is in t - var h: THash = hashNode(obj) and high(t.data) # start with real hash value + var h: Hash = hashNode(obj) and high(t.data) # start with real hash value while t.data[h] != nil: if t.data[h] == obj: return true @@ -482,7 +482,7 @@ proc objectSetContains(t: TObjectSet, obj: RootRef): bool = result = false proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) = - var h: THash = hashNode(obj) and high(data) + var h: Hash = hashNode(obj) and high(data) while data[h] != nil: assert(data[h] != obj) h = nextTry(h, high(data)) @@ -503,7 +503,7 @@ proc objectSetIncl(t: var TObjectSet, obj: RootRef) = proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool = # returns true if obj is already in the string table: - var h: THash = hashNode(obj) and high(t.data) + var h: Hash = hashNode(obj) and high(t.data) while true: var it = t.data[h] if it == nil: break @@ -520,7 +520,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool = result = false proc tableRawGet(t: TTable, key: RootRef): int = - var h: THash = hashNode(key) and high(t.data) # start with real hash value + var h: Hash = hashNode(key) and high(t.data) # start with real hash value while t.data[h].key != nil: if t.data[h].key == key: return h @@ -529,7 +529,7 @@ proc tableRawGet(t: TTable, key: RootRef): int = proc tableSearch(t: TTable, key, closure: RootRef, comparator: TCmpProc): RootRef = - var h: THash = hashNode(key) and high(t.data) # start with real hash value + var h: Hash = hashNode(key) and high(t.data) # start with real hash value while t.data[h].key != nil: if t.data[h].key == key: if comparator(t.data[h].val, closure): @@ -544,7 +544,7 @@ proc tableGet(t: TTable, key: RootRef): RootRef = else: result = nil proc tableRawInsert(data: var TPairSeq, key, val: RootRef) = - var h: THash = hashNode(key) and high(data) + var h: Hash = hashNode(key) and high(data) while data[h].key != nil: assert(data[h].key != key) h = nextTry(h, high(data)) @@ -569,7 +569,7 @@ proc tablePut(t: var TTable, key, val: RootRef) = inc(t.counter) proc strTableContains(t: TStrTable, n: PSym): bool = - var h: THash = n.name.h and high(t.data) # start with real hash value + var h: Hash = n.name.h and high(t.data) # start with real hash value while t.data[h] != nil: if (t.data[h] == n): return true @@ -577,7 +577,7 @@ proc strTableContains(t: TStrTable, n: PSym): bool = result = false proc strTableRawInsert(data: var TSymSeq, n: PSym) = - var h: THash = n.name.h and high(data) + var h: Hash = n.name.h and high(data) if sfImmediate notin n.flags: # fast path: while data[h] != nil: @@ -606,7 +606,7 @@ proc strTableRawInsert(data: var TSymSeq, n: PSym) = proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) = assert prevSym.name.h == newSym.name.h - var h: THash = prevSym.name.h and high(data) + var h: Hash = prevSym.name.h and high(data) while data[h] != nil: if data[h] == prevSym: data[h] = newSym @@ -640,7 +640,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} = # It is essential that `n` is written nevertheless! # This way the newest redefinition is picked by the semantic analyses! assert n.name != nil - var h: THash = n.name.h and high(t.data) + var h: Hash = n.name.h and high(t.data) var replaceSlot = -1 while true: var it = t.data[h] @@ -666,7 +666,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} = result = false proc strTableGet(t: TStrTable, name: PIdent): PSym = - var h: THash = name.h and high(t.data) + var h: Hash = name.h and high(t.data) while true: result = t.data[h] if result == nil: break @@ -694,7 +694,7 @@ proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym = proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, excluding: IntSet): PSym = - var h: THash = ti.h and high(tab.data) + var h: Hash = ti.h and high(tab.data) var start = h result = tab.data[h] while result != nil: @@ -743,7 +743,7 @@ proc hasEmptySlot(data: TIdPairSeq): bool = result = false proc idTableRawGet(t: TIdTable, key: int): int = - var h: THash + var h: Hash h = key and high(t.data) # start with real hash value while t.data[h].key != nil: if t.data[h].key.id == key: @@ -772,7 +772,7 @@ iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] = yield (t.data[i].key.id, t.data[i].val) proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) = - var h: THash + var h: Hash h = key.id and high(data) while data[h].key != nil: assert(data[h].key.id != key.id) @@ -805,7 +805,7 @@ iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] = if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val) proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int = - var h: THash + var h: Hash h = key.id and high(t.data) # start with real hash value while t.data[h].key != nil: if t.data[h].key.id == key.id: @@ -824,7 +824,7 @@ proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode = result = idNodeTableGet(t, key) proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) = - var h: THash + var h: Hash h = key.id and high(data) while data[h].key != nil: assert(data[h].key.id != key.id) @@ -863,7 +863,7 @@ proc initIITable(x: var TIITable) = for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey proc iiTableRawGet(t: TIITable, key: int): int = - var h: THash + var h: Hash h = key and high(t.data) # start with real hash value while t.data[h].key != InvalidKey: if t.data[h].key == key: return h @@ -876,7 +876,7 @@ proc iiTableGet(t: TIITable, key: int): int = else: result = InvalidKey proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) = - var h: THash + var h: Hash h = key and high(data) while data[h].key != InvalidKey: assert(data[h].key != key) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 93a9dd65d..64902c3fc 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -964,8 +964,11 @@ proc genEcho(p: BProc, n: PNode) = var args: Rope = nil var a: TLoc for i in countup(0, n.len-1): - initLocExpr(p, n.sons[i], a) - addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)]) + if n.sons[i].skipConv.kind == nkNilLit: + add(args, ", \"nil\"") + else: + initLocExpr(p, n.sons[i], a) + addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)]) linefmt(p, cpsStmts, "printf($1$2);$n", makeCString(repeat("%s", n.len) & tnl), args) @@ -2147,7 +2150,7 @@ proc genNamedConstExpr(p: BProc, n: PNode): Rope = proc genConstSimpleList(p: BProc, n: PNode): Rope = var length = sonsLen(n) result = rope("{") - for i in countup(0, length - 2): + for i in countup(ord(n.kind == nkObjConstr), length - 2): addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])]) if length > 0: add(result, genNamedConstExpr(p, n.sons[length - 1])) addf(result, "}$n", []) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index da9c6f653..91877833a 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -676,8 +676,11 @@ proc genProcAux(m: BModule, prc: PSym) = closureSetup(p, prc) 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: + header = "__declspec(noreturn) " & header if sfPure in prc.flags: - if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props: + if hasDeclspec in extccomp.CC[extccomp.cCompiler].props: header = "__declspec(naked) " & header generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N", header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)) @@ -718,10 +721,14 @@ 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: + header = "__declspec(noreturn) " & header if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym): header = "extern \"C\" " & header - if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props: + if sfPure in sym.flags and hasAttribute in CC[cCompiler].props: header.add(" __attribute__((naked))") + if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props: + header.add(" __attribute__((noreturn))") add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header)) proc genProcNoForward(m: BModule, prc: PSym) = diff --git a/compiler/commands.nim b/compiler/commands.nim index b6ebb6bcb..d30d8326c 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -229,7 +229,8 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool = of "experimental": result = gExperimentalMode else: invalidCmdLineOption(passCmd1, switch, info) -proc processPath(path: string, notRelativeToProj = false): string = +proc processPath(path: string, notRelativeToProj = false, + cfginfo = unknownLineInfo()): string = let p = if notRelativeToProj or os.isAbsolute(path) or '$' in path or path[0] == '.': path @@ -239,6 +240,7 @@ proc processPath(path: string, notRelativeToProj = false): string = "nim", getPrefixDir(), "lib", libpath, "home", removeTrailingDirSep(os.getHomeDir()), + "config", cfginfo.toFullPath().splitFile().dir, "projectname", options.gProjectName, "projectpath", options.gProjectPath]) @@ -281,7 +283,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = case switch.normalize of "path", "p": expectArg(switch, arg, pass, info) - addPath(processPath(arg), info) + addPath(processPath(arg, cfginfo=info), info) of "nimblepath", "babelpath": # keep the old name for compat if pass in {passCmd2, passPP} and not options.gNoNimblePath: diff --git a/compiler/docgen.nim b/compiler/docgen.nim index f8489d825..4b52b1c92 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -18,7 +18,7 @@ import type TSections = array[TSymKind, Rope] - TDocumentor = object of rstgen.TRstGenerator + TDocumentor = object of rstgen.RstGenerator modDesc: Rope # module description id: int # for generating IDs toc, section: TSections @@ -29,7 +29,7 @@ type PDoc* = ref TDocumentor ## Alias to type less. proc compilerMsgHandler(filename: string, line, col: int, - msgKind: rst.TMsgKind, arg: string) {.procvar.} = + msgKind: rst.MsgKind, arg: string) {.procvar.} = # translate msg kind: var k: msgs.TMsgKind case msgKind @@ -53,7 +53,7 @@ proc docgenFindFile(s: string): string {.procvar.} = proc parseRst(text, filename: string, line, column: int, hasToc: var bool, - rstOptions: TRstParseOptions): PRstNode = + rstOptions: RstParseOptions): PRstNode = result = rstParse(text, filename, line, column, hasToc, rstOptions, docgenFindFile, compilerMsgHandler) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 26f0318ee..186a3884d 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -26,8 +26,8 @@ type hasAssume, # CC has __assume (Visual C extension) hasGcGuard, # CC supports GC_GUARD to keep stack roots hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax - hasNakedDeclspec, # CC has __declspec(naked) - hasNakedAttribute # CC has __attribute__((naked)) + hasDeclspec, # CC has __declspec(X) + hasAttribute, # CC has __attribute__((X)) TInfoCCProps* = set[TInfoCCProp] TInfoCC* = tuple[ name: string, # the short name of the compiler @@ -85,7 +85,7 @@ compiler gcc: structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name packedPragma: "__attribute__((__packed__))", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, - hasNakedAttribute}) + hasAttribute}) # LLVM Frontend for GCC/G++ compiler llvmGcc: @@ -127,7 +127,7 @@ compiler vcc: asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$3$n$1 $2", packedPragma: "#pragma pack(1)", - props: {hasCpp, hasAssume, hasNakedDeclspec}) + props: {hasCpp, hasAssume, hasDeclspec}) # Intel C/C++ Compiler compiler icl: @@ -668,7 +668,8 @@ proc callCCompiler*(projectfile: string) = it = PStrEntry(it.next) if optGenStaticLib in gGlobalOptions: - linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName), + let name = splitFile(gProjectName).name + linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % name), "objfiles", objfiles] else: var linkerExe = getConfigVar(c, ".linkerexe") diff --git a/compiler/idents.nim b/compiler/idents.nim index 0cca18929..6986800cf 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -12,7 +12,7 @@ # id. This module is essential for the compiler's performance. import - hashes, strutils + hashes, strutils, etcpriv type TIdObj* = object of RootObj @@ -23,7 +23,7 @@ type TIdent*{.acyclic.} = object of TIdObj s*: string next*: PIdent # for hash-table chaining - h*: THash # hash value of s + h*: Hash # hash value of s var firstCharIsCS*: bool = true var buckets*: array[0..4096 * 2 - 1, PIdent] @@ -37,6 +37,8 @@ proc cmpIgnoreStyle(a, b: cstring, blen: int): int = while j < blen: while a[i] == '_': inc(i) while b[j] == '_': inc(j) + while isMagicIdentSeparatorRune(a, i): inc(i, magicIdentSeparatorRuneByteWidth) + while isMagicIdentSeparatorRune(b, j): inc(j, magicIdentSeparatorRuneByteWidth) # tolower inlined: var aa = a[i] var bb = b[j] @@ -65,7 +67,7 @@ proc cmpExact(a, b: cstring, blen: int): int = var wordCounter = 1 -proc getIdent*(identifier: cstring, length: int, h: THash): PIdent = +proc getIdent*(identifier: cstring, length: int, h: Hash): PIdent = var idx = h and high(buckets) result = buckets[idx] var last: PIdent = nil @@ -99,7 +101,7 @@ proc getIdent*(identifier: string): PIdent = result = getIdent(cstring(identifier), len(identifier), hashIgnoreStyle(identifier)) -proc getIdent*(identifier: string, h: THash): PIdent = +proc getIdent*(identifier: string, h: Hash): PIdent = result = getIdent(cstring(identifier), len(identifier), h) proc identEq*(id: PIdent, name: string): bool = diff --git a/compiler/installer.ini b/compiler/installer.ini index 4ee50f2ff..821309a34 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -47,7 +47,7 @@ Start: "doc/overview.html" [Other] Files: "readme.txt;install.txt;contributors.txt;copying.txt" -Files: "configure;makefile" +Files: "makefile" Files: "*.ini" Files: "koch.nim" @@ -70,6 +70,10 @@ Files: "doc/*.nim" Files: "doc/*.cfg" Files: "compiler/nimfix/*.nim" Files: "compiler/nimfix/*.cfg" +Files: "compiler/nimsuggest/*.nim" +Files: "compiler/nimsuggest/*.cfg" +Files: "compiler/plugins/locals/*.nim" +Files: "compiler/plugins/active.nim" Files: "tools/*.nim" Files: "tools/*.cfg" Files: "tools/*.tmpl" @@ -97,13 +101,8 @@ Files: "lib/pure/concurrency/*.cfg" Files: "lib/impure/*.nim" Files: "lib/wrappers/*.nim" -Files: "lib/wrappers/cairo/*.nim" -Files: "lib/wrappers/gtk/*.nim" -Files: "lib/wrappers/lua/*.nim" -Files: "lib/wrappers/opengl/*.nim" Files: "lib/wrappers/readline/*.nim" Files: "lib/wrappers/sdl/*.nim" -Files: "lib/wrappers/x11/*.nim" Files: "lib/wrappers/zip/*.nim" Files: "lib/wrappers/zip/libzip_all.c" @@ -115,8 +114,6 @@ Files: "lib/packages/docutils/*.nim" [Other] Files: "examples/*.nim" -Files: "examples/gtk/*.nim" -Files: "examples/0mq/*.nim" Files: "examples/c++iface/*.nim" Files: "examples/objciface/*.nim" Files: "examples/cross_calculator/" @@ -206,7 +203,11 @@ Files: "tests/stdlib/*.nim" Files: "tests/system/*.nim" Files: "tests/template/*.nim" Files: "tests/testament/*.nim" -Files: "tests/testdata/*.nim" +Files: "tests/testdata/*.csv" +Files: "tests/testdata/*.html" +Files: "tests/testdata/*.json" +Files: "tests/testdata/*.txt" +Files: "tests/testdata/*.xml" Files: "tests/threads/*.nim" Files: "tests/threads/*.cfg" Files: "tests/trmacros/*.nim" @@ -239,7 +240,7 @@ BinPath: r"bin;dist\mingw\bin;dist" ; Section | dir | zipFile | size hint (in KB) | url | exe start menu entry Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|overview.html" Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip" -Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.3.0.zip|aporia\bin\aporia.exe" +Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.3.0.zip|aporia-0.3.0\bin\aporia.exe" ; for now only NSIS supports optional downloads [UnixBin] diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 704713243..2fdf14b76 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -880,7 +880,7 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) = if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple: r.res = "$1.Field$2" % [r.res, getFieldPosition(n.sons[1]).rope] else: - if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAddr") + if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess") var f = n.sons[1].sym if f.loc.r == nil: f.loc.r = mangleName(f) r.res = "$1.$2" % [r.res, f.loc.r] @@ -970,7 +970,10 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = of nkCheckedFieldExpr: genCheckedFieldAddr(p, n, r) of nkDotExpr: - genFieldAddr(p, n.sons[0], r) + if mapType(n.typ) == etyBaseIndex: + genFieldAddr(p, n.sons[0], r) + else: + genFieldAccess(p, n.sons[0], r) of nkBracketExpr: var ty = skipTypes(n.sons[0].typ, abstractVarRange) if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) @@ -983,6 +986,15 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $ty.kind & ')') else: internalError(n.sons[0].info, "genAddr") +proc genProcForSymIfNeeded(p: PProc, s: PSym) = + if not p.g.generatedSyms.containsOrIncl(s.id): + let newp = genProc(p, s) + var owner = p + while owner != nil and owner.prc != s.owner: + owner = owner.up + if owner != nil: add(owner.locals, newp) + else: add(p.g.code, newp) + proc genSym(p: PProc, n: PNode, r: var TCompRes) = var s = n.sym case s.kind @@ -1018,13 +1030,8 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) = discard elif sfForward in s.flags: p.g.forwarded.add(s) - elif not p.g.generatedSyms.containsOrIncl(s.id): - let newp = genProc(p, s) - var owner = p - while owner != nil and owner.prc != s.owner: - owner = owner.up - if owner != nil: add(owner.locals, newp) - else: add(p.g.code, newp) + else: + genProcForSymIfNeeded(p, s) else: if s.loc.r == nil: internalError(n.info, "symbol has no generated name: " & s.name.s) @@ -1052,11 +1059,13 @@ proc genArg(p: PProc, n: PNode, r: var TCompRes) = proc genArgs(p: PProc, n: PNode, r: var TCompRes) = add(r.res, "(") + var hasArgs = false for i in countup(1, sonsLen(n) - 1): let it = n.sons[i] if it.typ.isCompileTimeOnly: continue - if i > 1: add(r.res, ", ") + if hasArgs: add(r.res, ", ") genArg(p, it, r) + hasArgs = true add(r.res, ")") r.kind = resExpr @@ -1389,6 +1398,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mCopyStrLast: ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))") of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)") of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)") + of mDotDot: + genProcForSymIfNeeded(p, n.sons[0].sym) + genCall(p, n, r) else: genCall(p, n, r) #else internalError(e.info, 'genMagic: ' + magicToStr[op]); diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index c68bc352c..69b45c980 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -946,7 +946,11 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode = proc liftLambdas*(fn: PSym, body: PNode): PNode = # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs # the transformation even when compiling to JS ... - if body.kind == nkEmpty or gCmd == cmdCompileToJS or + + # However we can do lifting for the stuff which is *only* compiletime. + let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro + + if body.kind == nkEmpty or (gCmd == cmdCompileToJS and not isCompileTime) or fn.skipGenericOwner.kind != skModule: # ignore forward declaration: result = body diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 8080e0e8c..6b38ee062 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -17,7 +17,7 @@ import hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream, - wordrecg + wordrecg, etcpriv const MaxLineLength* = 80 # lines longer than this lead to a warning @@ -140,10 +140,12 @@ proc isKeyword*(kind: TTokType): bool = proc isNimIdentifier*(s: string): bool = if s[0] in SymStartChars: var i = 1 - while i < s.len: + var sLen = s.len + while i < sLen: if s[i] == '_': inc(i) - if s[i] notin SymChars: return + elif isMagicIdentSeparatorRune(cstring s, i): + inc(i, magicIdentSeparatorRuneByteWidth) if s[i] notin SymChars: return inc(i) result = true @@ -229,23 +231,6 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") = var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart) L.dispMessage(info, msg, arg) -proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) = - var pos = L.bufpos # use registers for pos, buf - var buf = L.buf - while true: - if buf[pos] in chars: - add(tok.literal, buf[pos]) - inc(pos) - else: - break - if buf[pos] == '_': - if buf[pos+1] notin chars: - lexMessage(L, errInvalidToken, "_") - break - add(tok.literal, '_') - inc(pos) - L.bufpos = pos - proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool = result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second) @@ -268,136 +253,195 @@ proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int = result = i - start {.pop.} # overflowChecks + +template eatChar(L: var TLexer, t: var TToken, replacementChar: char) = + add(t.literal, replacementChar) + inc(L.bufpos) + +template eatChar(L: var TLexer, t: var TToken) = + add(t.literal, L.buf[L.bufpos]) + inc(L.bufpos) + proc getNumber(L: var TLexer): TToken = var - pos, endpos: int + startpos, endpos: int xi: BiggestInt - # get the base: + const literalishChars = { 'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'c', + 'C', 'b', 'B', '_', '.', '\''} + const literalishCharsNoDot = literalishChars - {'.'} + + proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) = + var pos = L.bufpos # use registers for pos, buf + var buf = L.buf + while true: + if buf[pos] in chars: + add(tok.literal, buf[pos]) + inc(pos) + else: + break + if buf[pos] == '_': + if buf[pos+1] notin chars: + lexMessage(L, errInvalidToken, "_") + break + add(tok.literal, '_') + inc(pos) + L.bufpos = pos + + proc matchChars(L: var TLexer, tok: var TToken, chars: set[char]) = + var pos = L.bufpos # use registers for pos, buf + var buf = L.buf + while buf[pos] in chars: + add(tok.literal, buf[pos]) + inc(pos) + L.bufpos = pos + + proc lexMessageLitNum(L: var TLexer, msg: TMsgKind, startpos: int) = + # Used to get slightly human friendlier err messages. + # Note: the erroneous 'O' char in the character set is intentional + const literalishChars = {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'O', + 'c', 'C', 'b', 'B', '_', '.', '\'', 'd', 'i', 'u'} + var msgPos = L.bufpos + var t: TToken + t.literal = "" + L.bufpos = startpos # Use L.bufpos as pos because of matchChars + matchChars(L, t, literalishChars) + # We must verify +/- specifically so that we're not past the literal + if L.buf[L.bufpos] in {'+', '-'} and + L.buf[L.bufpos - 1] in {'e', 'E'}: + add(t.literal, L.buf[L.bufpos]) + inc(L.bufpos) + matchChars(L, t, literalishChars) + if L.buf[L.bufpos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}: + inc(L.bufpos) + add(t.literal, L.buf[L.bufpos]) + matchChars(L, t, {'0'..'9'}) + L.bufpos = msgPos + lexMessage(L, msg, t.literal) + result.tokType = tkIntLit # int literal until we know better result.literal = "" - result.base = base10 # BUGFIX - pos = L.bufpos # make sure the literal is correct for error messages: - var eallowed = false - if L.buf[pos] == '0' and L.buf[pos+1] in {'X', 'x'}: - matchUnderscoreChars(L, result, {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x'}) + result.base = base10 + startpos = L.bufpos + var isAFloatLiteral = false + # First stage: find out base, make verifications, build token literal string + if L.buf[L.bufpos] == '0' and + L.buf[L.bufpos + 1] in {'X', 'x', 'o', 'O', 'c', 'C', 'b', 'B'}: + eatChar(L, result, '0') + case L.buf[L.bufpos] + of 'O': + lexMessageLitNum(L, errInvalidNumberOctalCode, startpos) + of 'x', 'X': + eatChar(L, result, 'x') + matchUnderscoreChars(L, result, {'0'..'9', 'a'..'f', 'A'..'F'}) + of 'o', 'c', 'C': + eatChar(L, result, 'c') + matchUnderscoreChars(L, result, {'0'..'7'}) + of 'b', 'B': + eatChar(L, result, 'b') + matchUnderscoreChars(L, result, {'0'..'1'}) + else: + internalError(getLineInfo(L), "getNumber") else: - matchUnderscoreChars(L, result, {'0'..'9', 'b', 'B', 'o', 'c', 'C'}) - eallowed = true - if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}): - add(result.literal, '.') - inc(L.bufpos) - matchUnderscoreChars(L, result, {'0'..'9'}) - eallowed = true - if eallowed and L.buf[L.bufpos] in {'e', 'E'}: - add(result.literal, 'e') - inc(L.bufpos) - if L.buf[L.bufpos] in {'+', '-'}: - add(result.literal, L.buf[L.bufpos]) - inc(L.bufpos) matchUnderscoreChars(L, result, {'0'..'9'}) + if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}): + isAFloatLiteral = true + eatChar(L, result, '.') + matchUnderscoreChars(L, result, {'0'..'9'}) + if L.buf[L.bufpos] in {'e', 'E'}: + isAFloatLiteral = true + eatChar(L, result, 'e') + if L.buf[L.bufpos] in {'+', '-'}: + eatChar(L, result) + matchUnderscoreChars(L, result, {'0'..'9'}) endpos = L.bufpos - if L.buf[endpos] in {'\'', 'f', 'F', 'i', 'I', 'u', 'U'}: - if L.buf[endpos] == '\'': inc(endpos) - L.bufpos = pos # restore position - case L.buf[endpos] + # Second stage, find out if there's a datatype postfix and handle it + var postPos = endpos + if L.buf[postPos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}: + if L.buf[postPos] == '\'': + inc(postPos) + case L.buf[postPos] of 'f', 'F': - inc(endpos) - if (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'): + inc(postPos) + if (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'): result.tokType = tkFloat32Lit - inc(endpos, 2) - elif (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'): + inc(postPos, 2) + elif (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'): result.tokType = tkFloat64Lit - inc(endpos, 2) - elif (L.buf[endpos] == '1') and - (L.buf[endpos + 1] == '2') and - (L.buf[endpos + 2] == '8'): + inc(postPos, 2) + elif (L.buf[postPos] == '1') and + (L.buf[postPos + 1] == '2') and + (L.buf[postPos + 2] == '8'): result.tokType = tkFloat128Lit - inc(endpos, 3) - else: - lexMessage(L, errInvalidNumber, result.literal & "'f" & L.buf[endpos]) + inc(postPos, 3) + else: # "f" alone defaults to float32 + result.tokType = tkFloat32Lit + of 'd', 'D': # ad hoc convenience shortcut for f64 + inc(postPos) + result.tokType = tkFloat64Lit of 'i', 'I': - inc(endpos) - if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'): + inc(postPos) + if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'): result.tokType = tkInt64Lit - inc(endpos, 2) - elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'): + inc(postPos, 2) + elif (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'): result.tokType = tkInt32Lit - inc(endpos, 2) - elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'): + inc(postPos, 2) + elif (L.buf[postPos] == '1') and (L.buf[postPos + 1] == '6'): result.tokType = tkInt16Lit - inc(endpos, 2) - elif (L.buf[endpos] == '8'): + inc(postPos, 2) + elif (L.buf[postPos] == '8'): result.tokType = tkInt8Lit - inc(endpos) + inc(postPos) else: - lexMessage(L, errInvalidNumber, result.literal & "'i" & L.buf[endpos]) + lexMessageLitNum(L, errInvalidNumber, startpos) of 'u', 'U': - inc(endpos) - if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'): + inc(postPos) + if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'): result.tokType = tkUInt64Lit - inc(endpos, 2) - elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'): + inc(postPos, 2) + elif (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'): result.tokType = tkUInt32Lit - inc(endpos, 2) - elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'): + inc(postPos, 2) + elif (L.buf[postPos] == '1') and (L.buf[postPos + 1] == '6'): result.tokType = tkUInt16Lit - inc(endpos, 2) - elif (L.buf[endpos] == '8'): + inc(postPos, 2) + elif (L.buf[postPos] == '8'): result.tokType = tkUInt8Lit - inc(endpos) + inc(postPos) else: result.tokType = tkUIntLit - else: lexMessage(L, errInvalidNumber, result.literal & "'" & L.buf[endpos]) - else: - L.bufpos = pos # restore position + else: + lexMessageLitNum(L, errInvalidNumber, startpos) + # Is there still a literalish char awaiting? Then it's an error! + if L.buf[postPos] in literalishCharsNoDot or + (L.buf[postPos] == '.' and L.buf[postPos + 1] in {'0'..'9'}): + lexMessageLitNum(L, errInvalidNumber, startpos) + # Third stage, extract actual number + L.bufpos = startpos # restore position + var pos: int = startpos try: if (L.buf[pos] == '0') and (L.buf[pos + 1] in {'x', 'X', 'b', 'B', 'o', 'O', 'c', 'C'}): inc(pos, 2) - xi = 0 # it may be a base prefix + xi = 0 # it is a base prefix case L.buf[pos - 1] # now look at the optional type suffix: of 'b', 'B': result.base = base2 - while true: - case L.buf[pos] - of '2'..'9', '.': - lexMessage(L, errInvalidNumber, result.literal) - inc(pos) - of '_': - if L.buf[pos+1] notin {'0'..'1'}: - lexMessage(L, errInvalidToken, "_") - break - inc(pos) - of '0', '1': + while pos < endpos: + if L.buf[pos] != '_': xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0')) - inc(pos) - else: break + inc(pos) of 'o', 'c', 'C': result.base = base8 - while true: - case L.buf[pos] - of '8'..'9', '.': - lexMessage(L, errInvalidNumber, result.literal) - inc(pos) - of '_': - if L.buf[pos+1] notin {'0'..'7'}: - lexMessage(L, errInvalidToken, "_") - break - inc(pos) - of '0'..'7': + while pos < endpos: + if L.buf[pos] != '_': xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0')) - inc(pos) - else: break - of 'O': - lexMessage(L, errInvalidNumber, result.literal) + inc(pos) of 'x', 'X': result.base = base16 - while true: + while pos < endpos: case L.buf[pos] of '_': - if L.buf[pos+1] notin {'0'..'9', 'a'..'f', 'A'..'F'}: - lexMessage(L, errInvalidToken, "_") - break inc(pos) of '0'..'9': xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0')) @@ -408,8 +452,10 @@ proc getNumber(L: var TLexer): TToken = of 'A'..'F': xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10) inc(pos) - else: break - else: internalError(getLineInfo(L), "getNumber") + else: + break + else: + internalError(getLineInfo(L), "getNumber") case result.tokType of tkIntLit, tkInt64Lit: result.iNumber = xi of tkInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi)))) @@ -425,7 +471,7 @@ proc getNumber(L: var TLexer): TToken = # XXX: Test this on big endian machine! of tkFloat64Lit: result.fNumber = (cast[PFloat64](addr(xi)))[] else: internalError(getLineInfo(L), "getNumber") - elif isFloatLiteral(result.literal) or (result.tokType == tkFloat32Lit) or + elif isAFloatLiteral or (result.tokType == tkFloat32Lit) or (result.tokType == tkFloat64Lit): result.fNumber = parseFloat(result.literal) if result.tokType == tkIntLit: result.tokType = tkFloatLit @@ -441,18 +487,18 @@ proc getNumber(L: var TLexer): TToken = if result.tokType == tkIntLit: result.tokType = tkInt64Lit elif result.tokType in {tkInt8Lit, tkInt16Lit, tkInt32Lit}: - lexMessage(L, errNumberOutOfRange, result.literal) + lexMessageLitNum(L, errNumberOutOfRange, startpos) elif result.tokType == tkInt8Lit and (result.iNumber < int8.low or result.iNumber > int8.high): - lexMessage(L, errNumberOutOfRange, result.literal) + lexMessageLitNum(L, errNumberOutOfRange, startpos) elif result.tokType == tkInt16Lit and (result.iNumber < int16.low or result.iNumber > int16.high): - lexMessage(L, errNumberOutOfRange, result.literal) + lexMessageLitNum(L, errNumberOutOfRange, startpos) except ValueError: - lexMessage(L, errInvalidNumber, result.literal) + lexMessageLitNum(L, errInvalidNumber, startpos) except OverflowError, RangeError: - lexMessage(L, errNumberOutOfRange, result.literal) - L.bufpos = endpos + lexMessageLitNum(L, errNumberOutOfRange, startpos) + L.bufpos = postPos proc handleHexChar(L: var TLexer, xi: var int) = case L.buf[L.bufpos] @@ -625,23 +671,34 @@ proc getCharacter(L: var TLexer, tok: var TToken) = inc(L.bufpos) # skip ' proc getSymbol(L: var TLexer, tok: var TToken) = - var h: THash = 0 + var h: Hash = 0 var pos = L.bufpos var buf = L.buf while true: var c = buf[pos] case c of 'a'..'z', '0'..'9', '\x80'..'\xFF': - h = h !& ord(c) + if c == '\226' and + buf[pos+1] == '\128' and + buf[pos+2] == '\147': # It's a 'magic separator' en-dash Unicode + if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars: + lexMessage(L, errInvalidToken, "–") + break + inc(pos, magicIdentSeparatorRuneByteWidth) + else: + h = h !& ord(c) + inc(pos) of 'A'..'Z': c = chr(ord(c) + (ord('a') - ord('A'))) # toLower() h = h !& ord(c) + inc(pos) of '_': if buf[pos+1] notin SymChars: lexMessage(L, errInvalidToken, "_") break + inc(pos) + else: break - inc(pos) h = !$h tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h) L.bufpos = pos @@ -652,7 +709,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) = tok.tokType = TTokType(tok.ident.id + ord(tkSymbol)) proc endOperator(L: var TLexer, tok: var TToken, pos: int, - hash: THash) {.inline.} = + hash: Hash) {.inline.} = var h = !$hash tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h) if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr @@ -662,7 +719,7 @@ proc endOperator(L: var TLexer, tok: var TToken, pos: int, proc getOperator(L: var TLexer, tok: var TToken) = var pos = L.bufpos var buf = L.buf - var h: THash = 0 + var h: Hash = 0 while true: var c = buf[pos] if c notin OpChars: break diff --git a/compiler/main.nim b/compiler/main.nim index 0c80c19b7..a01b6fe4f 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -63,7 +63,7 @@ proc commandCompileToC = compileProject() cgenWriteModules() if gCmd != cmdRun: - extccomp.callCCompiler(if gProjectName == "-": "stdinfile" else: changeFileExt(gProjectFull, "")) + extccomp.callCCompiler(changeFileExt(gProjectFull, "")) if isServing: # caas will keep track only of the compilation commands diff --git a/compiler/modules.nim b/compiler/modules.nim index a2b739efc..2fa46f356 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -10,8 +10,8 @@ ## implements the module handling import - ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options, - idents, os, lexer, idgen, passes, syntaxes + ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options, + idents, os, lexer, idgen, passes, syntaxes, llstream type TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled @@ -39,12 +39,12 @@ template crc(x: PSym): expr = proc crcChanged(fileIdx: int32): bool = internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len - + template updateStatus = gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged else: crcNotChanged # echo "TESTING CRC: ", fileIdx.toFilename, " ", result - + case gMemCacheData[fileIdx].crcStatus: of crcHasChanged: result = true @@ -96,7 +96,7 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile = if optForceFullMake in gGlobalOptions or crcChanged(fileIdx): markDirty - + if gMemCacheData[fileIdx].deps != nil: gMemCacheData[fileIdx].needsRecompile = Probing for dep in gMemCacheData[fileIdx].deps: @@ -104,30 +104,30 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile = if d in {Yes, Recompiled}: # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d markDirty - + gMemCacheData[fileIdx].needsRecompile = No return No proc newModule(fileIdx: int32): PSym = # We cannot call ``newSym`` here, because we have to circumvent the ID - # mechanism, which we do in order to assign each module a persistent ID. + # mechanism, which we do in order to assign each module a persistent ID. new(result) result.id = - 1 # for better error checking result.kind = skModule let filename = fileIdx.toFullPath result.name = getIdent(splitFile(filename).name) - if result.name.s != "-" and not isNimIdentifier(result.name.s): + if not isNimIdentifier(result.name.s): rawMessage(errInvalidModuleName, result.name.s) - + result.info = newLineInfo(fileIdx, 1, 1) result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil, result.info) result.position = fileIdx - + growCache gMemCacheData, fileIdx growCache gCompiledModules, fileIdx gCompiledModules[result.position] = result - + incl(result.flags, sfUsed) initStrTable(result.tab) strTableAdd(result.tab, result) # a module knows itself @@ -143,12 +143,15 @@ proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym = result.flags = result.flags + flags if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}: rd = handleSymbolFile(result) - if result.id < 0: + if result.id < 0: internalError("handleSymbolFile should have set the module\'s ID") return else: result.id = getID() - processModule(result, nil, rd) + if sfMainModule in flags and gProjectIsStdin: + processModule(result, llStreamOpen(stdin), rd) + else: + processModule(result, nil, rd) if optCaasEnabled in gGlobalOptions: gMemCacheData[fileIdx].compiledAt = gLastCmdTime gMemCacheData[fileIdx].needsRecompile = Recompiled diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 041a181be..81a62371e 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -17,10 +17,9 @@ type errIntLiteralExpected, errInvalidCharacterConstant, errClosingTripleQuoteExpected, errClosingQuoteExpected, errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong, - errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter, - errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected, - errNewlineExpected, - errInvalidModuleName, + errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange, + errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote, + errIdentifierExpected, errNewlineExpected, errInvalidModuleName, errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected, errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected, errInvalidPragma, errUnknownPragma, errInvalidDirectiveX, @@ -35,7 +34,9 @@ type errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound, errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound, errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected, - errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected, + errExprExpected, errUndeclaredIdentifier, errUndeclaredField, + errUndeclaredRoutine, errUseQualifier, + errTypeExpected, errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable, errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue, errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous, @@ -143,6 +144,7 @@ const errInvalidToken: "invalid token: $1", errLineTooLong: "line too long", errInvalidNumber: "$1 is not a valid number", + errInvalidNumberOctalCode: "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.", errNumberOutOfRange: "number $1 out of valid range", errNnotAllowedInCharacter: "\\n not allowed in character literal", errClosingBracketExpected: "closing ']' expected, but end of file reached", @@ -190,6 +192,8 @@ const errColonOrEqualsExpected: "\':\' or \'=\' expected, but found \'$1\'", errExprExpected: "expression expected, but found \'$1\'", errUndeclaredIdentifier: "undeclared identifier: \'$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\'", diff --git a/compiler/nim.nim b/compiler/nim.nim index b8ba2c6da..89db22e8f 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -38,7 +38,12 @@ proc handleCmdLine() = else: # Process command line arguments: processCmdLine(passCmd1, "") - if gProjectName != "": + if gProjectName == "-": + gProjectName = "stdinfile" + gProjectFull = "stdinfile" + gProjectPath = getCurrentDir() + gProjectIsStdin = true + elif gProjectName != "": try: gProjectFull = canonicalizePath(gProjectName) except OSError: @@ -61,8 +66,6 @@ proc handleCmdLine() = if gCmd == cmdRun: tccgen.run(commands.arguments) if optRun in gGlobalOptions: - if gProjectName == "-": - gProjectFull = "stdinfile" if gCmd == cmdCompileToJS: var ex: string if options.outFile.len > 0: diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim index 8caa23ee3..3641aec36 100644 --- a/compiler/nimfix/nimfix.nim +++ b/compiler/nimfix/nimfix.nim @@ -10,8 +10,10 @@ ## Nimfix is a tool that helps to convert old-style Nimrod code to Nim code. import strutils, os, parseopt -import options, commands, modules, sem, passes, passaux, pretty, msgs, nimconf, - extccomp, condsyms, lists +import compiler/options, compiler/commands, compiler/modules, compiler/sem, + compiler/passes, compiler/passaux, compiler/nimfix/pretty, + compiler/msgs, compiler/nimconf, + compiler/extccomp, compiler/condsyms, compiler/lists const Usage = """ Nimfix - Tool to patch Nim code @@ -24,7 +26,7 @@ Options: --wholeProject overwrite every processed file. --checkExtern:on|off style check also extern names --styleCheck:on|off|auto performs style checking for identifiers - and suggests an alternative spelling; + and suggests an alternative spelling; 'auto' corrects the spelling. --bestEffort try to fix the code even when there are errors. @@ -48,11 +50,11 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) = var p = parseopt.initOptParser(cmd) var argsCount = 0 gOnlyMainfile = true - while true: + while true: parseopt.next(p) case p.kind - of cmdEnd: break - of cmdLongoption, cmdShortOption: + of cmdEnd: break + of cmdLongoption, cmdShortOption: case p.key.normalize of "overwritefiles": case p.val.normalize diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim index d2d5b5e83..1123afb9e 100644 --- a/compiler/nimfix/pretty.nim +++ b/compiler/nimfix/pretty.nim @@ -10,9 +10,11 @@ ## This module implements the code "prettifier". This is part of the toolchain ## to convert Nim code into a consistent style. -import - strutils, os, options, ast, astalgo, msgs, ropes, idents, - intsets, strtabs, semdata, prettybase +import + strutils, os, intsets, strtabs + +import compiler/options, compiler/ast, compiler/astalgo, compiler/msgs, + compiler/semdata, compiler/nimfix/prettybase, compiler/ropes, compiler/idents type StyleCheck* {.pure.} = enum None, Warn, Auto @@ -92,7 +94,7 @@ proc beautifyName(s: string, k: TSymKind): string = proc replaceInFile(info: TLineInfo; newName: string) = loadFile(info) - + let line = gSourceFiles[info.fileIndex].lines[info.line-1] var first = min(info.col.int, line.len) if first < 0: return @@ -100,18 +102,18 @@ proc replaceInFile(info: TLineInfo; newName: string) = while first > 0 and line[first-1] in prettybase.Letters: dec first if first < 0: return if line[first] == '`': inc first - + let last = first+identLen(line, first)-1 if differ(line, first, last, newName): - # last-first+1 != newName.len or - var x = line.substr(0, first-1) & newName & line.substr(last+1) + # last-first+1 != newName.len or + var x = line.substr(0, first-1) & newName & line.substr(last+1) system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x) gSourceFiles[info.fileIndex].dirty = true proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) = let beau = beautifyName(s, k) if s != beau: - if gStyleCheck == StyleCheck.Auto: + if gStyleCheck == StyleCheck.Auto: sym.name = getIdent(beau) replaceInFile(info, beau) else: @@ -137,7 +139,7 @@ proc styleCheckUseImpl(info: TLineInfo; s: PSym) = if info.fileIndex < 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: return diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim index 5130d1863..0f17cbcb1 100644 --- a/compiler/nimfix/prettybase.nim +++ b/compiler/nimfix/prettybase.nim @@ -7,7 +7,8 @@ # distribution, for details about the copyright. # -import ast, msgs, strutils, idents, lexbase, streams +import strutils, lexbase, streams +import compiler/ast, compiler/msgs, compiler/idents from os import splitFile type @@ -39,7 +40,7 @@ proc loadFile*(info: TLineInfo) = var pos = lex.bufpos while true: case lex.buf[pos] - of '\c': + of '\c': gSourceFiles[i].newline = "\c\L" break of '\L', '\0': @@ -70,7 +71,7 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) = while first > 0 and line[first-1] in Letters: dec first if first < 0: return if line[first] == '`': inc first - + 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) diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim index 8285d81d9..2be368d68 100644 --- a/compiler/nimsuggest/nimsuggest.nim +++ b/compiler/nimsuggest/nimsuggest.nim @@ -7,192 +7,6 @@ # distribution, for details about the copyright. # -## Nimsuggest is a tool that helps to give editors IDE like capabilities. +## Nimsuggest has been moved to https://github.com/nim-lang/nimsuggest -import strutils, os, parseopt, parseUtils -import options, commands, modules, sem, passes, passaux, msgs, nimconf, - extccomp, condsyms, lists, net, rdstdin - -const Usage = """ -Nimsuggest - Tool to give every editor IDE like capabilities for Nim -Usage: - nimsuggest [options] projectfile.nim - -Options: - --port:PORT port, by default 6000 - --address:HOST binds to that address, by default "" - --stdin read commands from stdin and write results to - stdout instead of using sockets - -The server then listens to the connection and takes line-based commands. - -In addition, all command line options of Nim that do not affect code generation -are supported. -""" - -var - gPort = 6000.Port - gAddress = "" - gUseStdin: bool - -const - seps = {':', ';', ' ', '\t'} - Help = "usage: sug|con|def|use file.nim[;dirtyfile.nim]:line:col\n"& - "type 'quit' to quit\n" & - "type 'debug' to toggle debug mode on/off\n" & - "type 'terse' to toggle terse mode on/off" - -proc parseQuoted(cmd: string; outp: var string; start: int): int = - var i = start - i += skipWhitespace(cmd, i) - if cmd[i] == '"': - i += parseUntil(cmd, outp, '"', i+1)+2 - else: - i += parseUntil(cmd, outp, seps, i) - result = i - -proc action(cmd: string) = - template toggle(sw) = - if sw in gGlobalOptions: - excl(gGlobalOptions, sw) - else: - incl(gGlobalOptions, sw) - return - - template err() = - echo Help - return - - var opc = "" - var i = parseIdent(cmd, opc, 0) - case opc.normalize - of "sug": gIdeCmd = ideSug - of "con": gIdeCmd = ideCon - of "def": gIdeCmd = ideDef - of "use": - modules.resetAllModules() - gIdeCmd = ideUse - of "quit": quit() - of "debug": toggle optIdeDebug - of "terse": toggle optIdeTerse - else: err() - var dirtyfile = "" - var orig = "" - i = parseQuoted(cmd, orig, i) - if cmd[i] == ';': - i = parseQuoted(cmd, dirtyfile, i+1) - i += skipWhile(cmd, seps, i) - var line = -1 - var col = 0 - i += parseInt(cmd, line, i) - i += skipWhile(cmd, seps, i) - i += parseInt(cmd, col, i) - - var isKnownFile = true - if orig.len == 0: err() - let dirtyIdx = orig.fileInfoIdx(isKnownFile) - - if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile) - else: msgs.setDirtyFile(dirtyIdx, nil) - - resetModule dirtyIdx - if dirtyIdx != gProjectMainIdx: - resetModule gProjectMainIdx - gTrackPos = newLineInfo(dirtyIdx, line, col-1) - #echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx - gErrorCounter = 0 - if not isKnownFile: - compileProject(dirtyIdx) - else: - compileProject() - -proc serve() = - # do not stop after the first error: - msgs.gErrorMax = high(int) - if gUseStdin: - echo Help - var line = "" - while readLineFromStdin("> ", line): - action line - echo "" - flushFile(stdout) - else: - var server = newSocket() - server.bindAddr(gPort, gAddress) - var inp = "".TaintedString - server.listen() - - while true: - var stdoutSocket = newSocket() - msgs.writelnHook = proc (line: string) = - stdoutSocket.send(line & "\c\L") - - accept(server, stdoutSocket) - - stdoutSocket.readLine(inp) - action inp.string - - stdoutSocket.send("\c\L") - stdoutSocket.close() - -proc mainCommand = - registerPass verbosePass - registerPass semPass - gCmd = cmdIdeTools - incl gGlobalOptions, optCaasEnabled - isServing = true - wantMainModule() - appendStr(searchPaths, options.libpath) - if gProjectFull.len != 0: - # current path is always looked first for modules - prependStr(searchPaths, gProjectPath) - - serve() - -proc processCmdLine*(pass: TCmdLinePass, cmd: string) = - var p = parseopt.initOptParser(cmd) - while true: - parseopt.next(p) - case p.kind - of cmdEnd: break - of cmdLongoption, cmdShortOption: - case p.key.normalize - of "port": gPort = parseInt(p.val).Port - of "address": gAddress = p.val - of "stdin": gUseStdin = true - else: processSwitch(pass, p) - of cmdArgument: - options.gProjectName = unixToNativePath(p.key) - # if processArgument(pass, p, argsCount): break - -proc handleCmdLine() = - if paramCount() == 0: - stdout.writeln(Usage) - else: - processCmdLine(passCmd1, "") - if gProjectName != "": - try: - gProjectFull = canonicalizePath(gProjectName) - except OSError: - gProjectFull = gProjectName - var p = splitFile(gProjectFull) - gProjectPath = p.dir - gProjectName = p.name - else: - gProjectPath = getCurrentDir() - loadConfigs(DefaultConfig) # load all config files - # now process command line arguments again, because some options in the - # command line can overwite the config file's settings - extccomp.initVars() - processCmdLine(passCmd2, "") - mainCommand() - -when false: - proc quitCalled() {.noconv.} = - writeStackTrace() - - addQuitProc(quitCalled) - -condsyms.initDefines() -defineSymbol "nimsuggest" -handleCmdline() +{.error: "This project has moved to the following repo: https://github.com/nim-lang/nimsuggest".} diff --git a/compiler/nimsuggest/nimsuggest.nim.cfg b/compiler/nimsuggest/nimsuggest.nim.cfg deleted file mode 100644 index acca17396..000000000 --- a/compiler/nimsuggest/nimsuggest.nim.cfg +++ /dev/null @@ -1,17 +0,0 @@ -# Special configuration file for the Nim project - -gc:markAndSweep - -hint[XDeclaredButNotUsed]:off -path:"$projectPath/../.." - -path:"$lib/packages/docutils" -path:"../../compiler" - -define:useStdoutAsStdmsg -define:nimsuggest - -cs:partial -#define:useNodeIds -define:booting -#define:noDocgen diff --git a/compiler/options.nim b/compiler/options.nim index 65250f519..b3060a180 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -1,7 +1,7 @@ # # # The Nim Compiler -# (c) Copyright 2013 Andreas Rumpf +# (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -83,11 +83,11 @@ type # please make sure we have under 32 options TGCMode* = enum # the selected GC gcNone, gcBoehm, gcMarkAndSweep, gcRefc, gcV2, gcGenerational - TIdeCmd* = enum + IdeCmd* = enum ideNone, ideSug, ideCon, ideDef, ideUse var - gIdeCmd*: TIdeCmd + gIdeCmd*: IdeCmd const ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck, @@ -149,6 +149,7 @@ var gProjectName* = "" # holds a name like 'nimrod' gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/ gProjectFull* = "" # projectPath/projectName + gProjectIsStdin* = false # whether we're compiling from stdin gProjectMainIdx*: int32 # the canonical path id of the main module nimcacheDir* = "" command* = "" # the main command (e.g. cc, check, scan, etc) @@ -395,3 +396,18 @@ template cnimdbg*: expr = p.module.module.fileIdx == gProjectMainIdx template pnimdbg*: expr = p.lex.fileIdx == gProjectMainIdx template lnimdbg*: expr = L.fileIdx == gProjectMainIdx +proc parseIdeCmd*(s: string): IdeCmd = + case s: + of "sug": ideSug + of "con": ideCon + of "def": ideDef + of "use": ideUse + else: ideNone + +proc `$`*(c: IdeCmd): string = + case c: + of ideSug: "sug" + of ideCon: "con" + of ideDef: "def" + of ideUse: "use" + of ideNone: "none" diff --git a/compiler/parser.nim b/compiler/parser.nim index 0d2ba7cfc..05b4df13d 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -64,6 +64,7 @@ proc setBaseFlags*(n: PNode, base: TNumericalBase) proc parseSymbol*(p: var TParser, allowNil = false): PNode proc parseTry(p: var TParser; isExpr: bool): PNode proc parseCase(p: var TParser): PNode +proc parseStmtPragma(p: var TParser): PNode # implementation proc getTok(p: var TParser) = @@ -499,10 +500,13 @@ proc parsePar(p: var TParser): PNode = #| parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try' #| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let' #| | 'when' | 'var' | 'mixin' - #| par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';' - #| | simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )? - #| | (':' expr)? (',' (exprColonEqExpr comma?)*)? )? - #| optPar ')' + #| par = '(' optInd + #| ( &parKeyw complexOrSimpleStmt ^+ ';' + #| | ';' complexOrSimpleStmt ^+ ';' + #| | pragmaStmt + #| | simpleExpr ( ('=' expr (';' complexOrSimpleStmt ^+ ';' )? ) + #| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) ) + #| optPar ')' # # unfortunately it's ambiguous: (expr: expr) vs (exprStmt); however a # leading ';' could be used to enforce a 'stmt' context ... @@ -521,6 +525,8 @@ proc parsePar(p: var TParser): PNode = getTok(p) optInd(p, result) semiStmtList(p, result) + elif p.tok.tokType == tkCurlyDotLe: + result.add(parseStmtPragma(p)) elif p.tok.tokType != tkParRi: var a = simpleExpr(p) if p.tok.tokType == tkEquals: diff --git a/compiler/passes.nim b/compiler/passes.nim index 129d8ad47..e031dae10 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -170,11 +170,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) = openPasses(a, module) if stream == nil: let filename = fileIdx.toFullPathConsiderDirty - if module.name.s == "-": - module.name.s = "stdinfile" - s = llStreamOpen(stdin) - else: - s = llStreamOpen(filename, fmRead) + s = llStreamOpen(filename, fmRead) if s == nil: rawMessage(errCannotOpenFile, filename) return diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 368b0b37b..3f8b05940 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -130,7 +130,9 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool = proc matches(c: PPatternContext, p, n: PNode): bool = # hidden conversions (?) - if isPatternParam(c, p): + if nfNoRewrite in n.flags: + result = false + elif isPatternParam(c, p): result = bindOrCheck(c, p.sym, n) elif n.kind == nkSym and p.kind == nkIdent: result = p.ident.id == n.sym.name.id diff --git a/compiler/plugins/locals/locals.nim b/compiler/plugins/locals/locals.nim index d89149f33..59e3d677d 100644 --- a/compiler/plugins/locals/locals.nim +++ b/compiler/plugins/locals/locals.nim @@ -9,7 +9,8 @@ ## The builtin 'system.locals' implemented as a plugin. -import plugins, ast, astalgo, magicsys, lookups, semdata, lowerings +import compiler/plugins, compiler/ast, compiler/astalgo, compiler/magicsys, + compiler/lookups, compiler/semdata, compiler/lowerings proc semLocals(c: PContext, n: PNode): PNode = var counter = 0 diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index c048d78e9..6f37fe756 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -37,7 +37,7 @@ const wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises, wTags, wLocks, wGcSafe} - exprPragmas* = {wLine, wLocks} + exprPragmas* = {wLine, wLocks, wNoRewrite} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, @@ -859,6 +859,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, c.module.flags.incl sfExperimental else: localError(it.info, "'experimental' pragma only valid as toplevel statement") + of wNoRewrite: + noVal(it) else: invalidPragma(it) else: invalidPragma(it) else: processNote(c, it) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index ffdb60696..376c0d6f7 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -767,7 +767,8 @@ proc gasm(g: var TSrcGen, n: PNode) = putWithSpace(g, tkAsm, "asm") gsub(g, n.sons[0]) gcoms(g) - gsub(g, n.sons[1]) + if n.sons.len > 1: + gsub(g, n.sons[1]) proc gident(g: var TSrcGen, n: PNode) = if g.checkAnon and n.kind == nkSym and sfAnon in n.sym.flags: return diff --git a/compiler/semcall.nim b/compiler/semcall.nim index c48e761e3..571504c3a 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -209,7 +209,10 @@ proc resolveOverloads(c: PContext, n, orig: PNode, pickBest(callOp) if overloadsState == csEmpty and result.state == csEmpty: - localError(n.info, errUndeclaredIdentifier, considerQuotedIdent(f).s) + if nfDotField in n.flags and nfExplicitCall notin n.flags: + localError(n.info, errUndeclaredField, considerQuotedIdent(f).s) + else: + localError(n.info, errUndeclaredRoutine, considerQuotedIdent(f).s) return elif result.state != csMatch: if nfExprCall in n.flags: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 21fc4ec40..cd6ba3753 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -535,7 +535,18 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = result.sons[i] = fitNode(c, typ, result.sons[i]) result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info) -template fixAbstractType(c: PContext, n: PNode) = +proc fixAbstractType(c: PContext, n: PNode) = + for i in 1 .. < n.len: + let it = n.sons[i] + # do not get rid of nkHiddenSubConv for OpenArrays, the codegen needs it: + if it.kind == nkHiddenSubConv and + skipTypes(it.typ, abstractVar).kind notin {tyOpenArray, tyVarargs}: + if skipTypes(it.sons[1].typ, abstractVar).kind in + {tyNil, tyArrayConstr, tyTuple, tySet}: + var s = skipTypes(it.typ, abstractVar) + if s.kind != tyExpr: + changeType(it.sons[1], s, check=true) + n.sons[i] = it.sons[1] when false: # XXX finally rewrite that crap! for i in countup(1, sonsLen(n) - 1): @@ -2042,7 +2053,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkEmpty, nkNone, nkCommentStmt: discard of nkNilLit: - result.typ = getSysType(tyNil) + if result.typ == nil: result.typ = getSysType(tyNil) of nkIntLit: if result.typ == nil: setIntLitType(result) of nkInt8Lit: diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 941d47bb4..da24005c2 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -286,10 +286,13 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of mNot: result = newIntNodeT(1 - getInt(a), n) of mCard: result = newIntNodeT(nimsets.cardSet(a), n) of mBitnotI, mBitnotI64: result = newIntNodeT(not getInt(a), n) - of mLengthStr, mXLenStr: result = newIntNodeT(len(getStr(a)), n) + of mLengthStr, mXLenStr: + if a.kind == nkNilLit: result = newIntNodeT(0, n) + else: result = newIntNodeT(len(getStr(a)), n) of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n) of mLengthSeq, mLengthOpenArray, mXLenSeq: - result = newIntNodeT(sonsLen(a), n) # BUGFIX + if a.kind == nkNilLit: result = newIntNodeT(0, n) + else: result = newIntNodeT(sonsLen(a), n) # BUGFIX of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away of mToFloat, mToBiggestFloat: result = newFloatNodeT(toFloat(int(getInt(a))), n) @@ -545,7 +548,7 @@ proc foldConv*(n, a: PNode; check = false): PNode = discard else: result = a - result.typ = takeType(n.typ, a.typ) + result.typ = n.typ proc getArrayConstr(m: PSym, n: PNode): PNode = if n.kind == nkBracket: @@ -652,7 +655,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode = result = copyNode(n) of nkIfExpr: result = getConstIfExpr(m, n) - of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix: + of nkCallKinds: if n.sons[0].kind != nkSym: return var s = n.sons[0].sym if s.kind != skProc: return diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index adf03be64..12c4a7c7b 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -207,9 +207,9 @@ proc markGcUnsafe(a: PEffects; reason: PNode) = a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"), a.owner, reason.info) -proc listGcUnsafety(s: PSym; onlyWarning: bool) = +proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) = let u = s.gcUnsafetyReason - if u != nil: + if u != nil and not cycleCheck.containsOrIncl(u.id): let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated if u.kind in {skLet, skVar}: message(s.info, msgKind, @@ -218,7 +218,7 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool) = elif u.kind in routineKinds: # recursive call *always* produces only a warning so the full error # message is printed: - listGcUnsafety(u, true) + listGcUnsafety(u, true, cycleCheck) message(s.info, msgKind, "'$#' is not GC-safe as it calls '$#'" % [s.name.s, u.name.s]) @@ -227,6 +227,10 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool) = message(u.info, msgKind, "'$#' is not GC-safe as it performs an indirect call here" % s.name.s) +proc listGcUnsafety(s: PSym; onlyWarning: bool) = + var cycleCheck = initIntSet() + listGcUnsafety(s, onlyWarning, cycleCheck) + proc useVar(a: PEffects, n: PNode) = let s = n.sym if isLocalVar(a, s): diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c355a5bf1..43cdca866 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1268,6 +1268,8 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode = of wLocks: result = n result.typ = n.sons[1].typ + of wNoRewrite: + incl(result.flags, nfNoRewrite) else: discard proc semStaticStmt(c: PContext, n: PNode): PNode = diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 2a9d15b5a..7ea2c3d6f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1281,7 +1281,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, result = implicitConv(nkHiddenStdConv, f, arg, m, c) of isSubtype: inc(m.subtypeMatches) - result = implicitConv(nkHiddenSubConv, f, arg, m, c) + if f.kind == tyTypeDesc: + result = arg + else: + result = implicitConv(nkHiddenSubConv, f, arg, m, c) of isSubrange: inc(m.subtypeMatches) if f.kind == tyVar: diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 6b168670c..659f1fa16 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -15,57 +15,79 @@ import algorithm, sequtils const sep = '\t' - sectionSuggest = "sug" - sectionDef = "def" - sectionContext = "con" - sectionUsage = "use" + +type + Suggest* = object + section*: IdeCmd + qualifiedPath*: seq[string] + filePath*: string + line*: int # Starts at 1 + column*: int # Starts at 0 + doc*: string # Not escaped (yet) + symkind*: TSymKind + forth*: string # XXX TODO object on symkind + +var + suggestionResultHook*: proc (result: Suggest) {.closure.} #template sectionSuggest(): expr = "##begin\n" & getStackTrace() & "##end\n" template origModuleName(m: PSym): string = m.name.s -proc symToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string = - result = section - result.add(sep) +proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo): Suggest = + result.section = parseIdeCmd(section) if optIdeTerse in gGlobalOptions: - if s.kind in routineKinds: - result.add renderTree(s.ast, {renderNoBody, renderNoComments, - renderDocComments, renderNoPragmas}) - else: - result.add s.name.s - result.add(sep) - result.add(toFullPath(li)) - result.add(sep) - result.add($toLinenumber(li)) - result.add(sep) - result.add($toColumn(li)) + result.symkind = s.kind + result.filePath = toFullPath(li) + result.line = toLinenumber(li) + result.column = toColumn(li) else: - result.add($s.kind) - result.add(sep) + result.symkind = s.kind + result.qualifiedPath = @[] if not isLocal and s.kind != skModule: let ow = s.owner if ow.kind != skModule and ow.owner != nil: let ow2 = ow.owner - result.add(ow2.origModuleName) - result.add('.') - result.add(ow.origModuleName) - result.add('.') - result.add(s.name.s) - result.add(sep) + result.qualifiedPath.add(ow2.origModuleName) + result.qualifiedPath.add(ow.origModuleName) + result.qualifiedPath.add(s.name.s) + if s.typ != nil: - result.add(typeToString(s.typ)) - result.add(sep) - result.add(toFullPath(li)) - result.add(sep) - result.add($toLinenumber(li)) - result.add(sep) - result.add($toColumn(li)) - result.add(sep) + result.forth = typeToString(s.typ) + else: + result.forth = "" + result.filePath = toFullPath(li) + result.line = toLinenumber(li) + result.column = toColumn(li) when not defined(noDocgen): - result.add(s.extractDocComment.escape) + result.doc = s.extractDocComment + +proc `$`(suggest: Suggest): string = + result = $suggest.section + result.add(sep) + result.add($suggest.symkind) + result.add(sep) + result.add(suggest.qualifiedPath.join(".")) + result.add(sep) + result.add(suggest.forth) + result.add(sep) + result.add(suggest.filePath) + result.add(sep) + result.add($suggest.line) + result.add(sep) + result.add($suggest.column) + result.add(sep) + when not defined(noDocgen): + result.add(suggest.doc.escape) -proc symToStr(s: PSym, isLocal: bool, section: string): string = - result = symToStr(s, isLocal, section, s.info) +proc symToSuggest(s: PSym, isLocal: bool, section: string): Suggest = + result = symToSuggest(s, isLocal, section, s.info) + +proc suggestResult(s: Suggest) = + if not isNil(suggestionResultHook): + suggestionResultHook(s) + else: + suggestWriteln($(s)) proc filterSym(s: PSym): bool {.inline.} = result = s.kind != skModule @@ -84,7 +106,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = proc suggestField(c: PContext, s: PSym, outputs: var int) = if filterSym(s) and fieldVisible(c, s): - suggestWriteln(symToStr(s, isLocal=true, sectionSuggest)) + suggestResult(symToSuggest(s, isLocal=true, $ideSug)) inc outputs template wholeSymTab(cond, section: expr) {.immediate.} = @@ -97,7 +119,7 @@ template wholeSymTab(cond, section: expr) {.immediate.} = for item in entries: let it {.inject.} = item if cond: - suggestWriteln(symToStr(it, isLocal = isLocal, section)) + suggestResult(symToSuggest(it, isLocal = isLocal, section)) inc outputs proc suggestSymList(c: PContext, list: PNode, outputs: var int) = @@ -140,7 +162,7 @@ proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool = proc suggestCall(c: PContext, n, nOrig: PNode, outputs: var int) = wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n, nOrig), - sectionContext) + $ideCon) proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = if s.typ != nil and sonsLen(s.typ) > 1 and s.typ.sons[1] != nil: @@ -157,7 +179,7 @@ proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = proc suggestOperations(c: PContext, n: PNode, typ: PType, outputs: var int) = assert typ != nil - wholeSymTab(filterSymNoOpr(it) and typeFits(c, it, typ), sectionSuggest) + wholeSymTab(filterSymNoOpr(it) and typeFits(c, it, typ), $ideSug) proc suggestEverything(c: PContext, n: PNode, outputs: var int) = # do not produce too many symbols: @@ -166,7 +188,7 @@ proc suggestEverything(c: PContext, n: PNode, outputs: var int) = if scope == c.topLevelScope: isLocal = false for it in items(scope.symbols): if filterSym(it): - suggestWriteln(symToStr(it, isLocal = isLocal, sectionSuggest)) + suggestResult(symToSuggest(it, isLocal = isLocal, $ideSug)) inc outputs if scope == c.topLevelScope: break @@ -181,12 +203,12 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) = # all symbols accessible, because we are in the current module: for it in items(c.topLevelScope.symbols): if filterSym(it): - suggestWriteln(symToStr(it, isLocal=false, sectionSuggest)) + suggestResult(symToSuggest(it, isLocal=false, $ideSug)) inc outputs else: for it in items(n.sym.tab): if filterSym(it): - suggestWriteln(symToStr(it, isLocal=false, sectionSuggest)) + suggestResult(symToSuggest(it, isLocal=false, $ideSug)) inc outputs else: # fallback: @@ -263,16 +285,16 @@ var proc findUsages(info: TLineInfo; s: PSym) = if usageSym == nil and isTracked(info, s.name.s.len): usageSym = s - suggestWriteln(symToStr(s, isLocal=false, sectionUsage)) + suggestResult(symToSuggest(s, isLocal=false, $ideUse)) elif s == usageSym: if lastLineInfo != info: - suggestWriteln(symToStr(s, isLocal=false, sectionUsage, info)) + suggestResult(symToSuggest(s, isLocal=false, $ideUse, info)) lastLineInfo = info proc findDefinition(info: TLineInfo; s: PSym) = if s.isNil: return if isTracked(info, s.name.s.len): - suggestWriteln(symToStr(s, isLocal=false, sectionDef)) + suggestResult(symToSuggest(s, isLocal=false, $ideDef)) suggestQuit() proc ensureIdx[T](x: var T, y: int) = diff --git a/compiler/transf.nim b/compiler/transf.nim index 3bdbdfadd..57547b682 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -716,8 +716,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = add(result, PTransNode(newSymNode(labl))) of nkBreakStmt: result = transformBreak(c, n) of nkWhileStmt: result = transformWhile(c, n) - of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, - nkCallStrLit: + of nkCallKinds: result = transformCall(c, n) of nkAddr, nkHiddenAddr: result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref) diff --git a/compiler/treetab.nim b/compiler/treetab.nim index 8d66d56c7..adfc7b2ce 100644 --- a/compiler/treetab.nim +++ b/compiler/treetab.nim @@ -12,7 +12,7 @@ import hashes, ast, astalgo, types -proc hashTree(n: PNode): THash = +proc hashTree(n: PNode): Hash = if n == nil: return result = ord(n.kind) case n.kind @@ -53,8 +53,8 @@ proc treesEquivalent(a, b: PNode): bool = result = true if result: result = sameTypeOrNil(a.typ, b.typ) -proc nodeTableRawGet(t: TNodeTable, k: THash, key: PNode): int = - var h: THash = k and high(t.data) +proc nodeTableRawGet(t: TNodeTable, k: Hash, key: PNode): int = + var h: Hash = k and high(t.data) while t.data[h].key != nil: if (t.data[h].h == k) and treesEquivalent(t.data[h].key, key): return h @@ -66,9 +66,9 @@ proc nodeTableGet*(t: TNodeTable, key: PNode): int = if index >= 0: result = t.data[index].val else: result = low(int) -proc nodeTableRawInsert(data: var TNodePairSeq, k: THash, key: PNode, +proc nodeTableRawInsert(data: var TNodePairSeq, k: Hash, key: PNode, val: int) = - var h: THash = k and high(data) + var h: Hash = k and high(data) while data[h].key != nil: h = nextTry(h, high(data)) assert(data[h].key == nil) data[h].h = k @@ -77,7 +77,7 @@ proc nodeTableRawInsert(data: var TNodePairSeq, k: THash, key: PNode, proc nodeTablePut*(t: var TNodeTable, key: PNode, val: int) = var n: TNodePairSeq - var k: THash = hashTree(key) + var k: Hash = hashTree(key) var index = nodeTableRawGet(t, k, key) if index >= 0: assert(t.data[index].key != nil) @@ -94,7 +94,7 @@ proc nodeTablePut*(t: var TNodeTable, key: PNode, val: int) = proc nodeTableTestOrSet*(t: var TNodeTable, key: PNode, val: int): int = var n: TNodePairSeq - var k: THash = hashTree(key) + var k: Hash = hashTree(key) var index = nodeTableRawGet(t, k, key) if index >= 0: assert(t.data[index].key != nil) diff --git a/compiler/vm.nim b/compiler/vm.nim index 1c6c9a30b..e49bed522 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1121,7 +1121,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeB(rkInt) let a = regs[rb].node case a.kind - of nkCharLit..nkInt64Lit: regs[ra].intVal = a.intVal + of nkCharLit..nkUInt64Lit: regs[ra].intVal = a.intVal else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal") of opcNFloatVal: decodeB(rkFloat) @@ -1276,7 +1276,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcNSetIntVal: decodeB(rkNode) var dest = regs[ra].node - if dest.kind in {nkCharLit..nkInt64Lit} and + if dest.kind in {nkCharLit..nkUInt64Lit} and regs[rb].kind in {rkInt}: dest.intVal = regs[rb].intVal else: diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 63fd995c4..deb12536f 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -55,7 +55,7 @@ type wFloatchecks, wNanChecks, wInfChecks, wAssertions, wPatterns, wWarnings, wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags, - wDeadCodeElim, wSafecode, wNoForward, + wDeadCodeElim, wSafecode, wNoForward, wNoRewrite, wPragma, wCompileTime, wNoInit, wPassc, wPassl, wBorrow, wDiscardable, @@ -139,7 +139,7 @@ const "assertions", "patterns", "warnings", "hints", "optimization", "raises", "writes", "reads", "size", "effects", "tags", - "deadcodeelim", "safecode", "noforward", + "deadcodeelim", "safecode", "noforward", "norewrite", "pragma", "compiletime", "noinit", "passc", "passl", "borrow", "discardable", "fieldchecks", |