From 13b57dbc2f686ba9beb410ad9fef848926de38c5 Mon Sep 17 00:00:00 2001 From: Adam Strzelecki Date: Tue, 2 Jun 2015 21:29:28 +0200 Subject: Introduce {.noRewrite.} expr pragma disabling TR Term rewriting macros/templates are currently greedy and they will rewrite as long as there is a match. So there was no way to ensure some rewrite happens only once, eg. when rewriting term to same term plus extra content. With new macro we can actually prevent further rewriting on marked expr or stmts, eg. with given example echo(...) will be rewritten just once: template pwnEcho{echo(x)}(x: expr) = {.noRewrite.}: echo("pwned!") echo "ab" --- compiler/pragmas.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'compiler/pragmas.nim') 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) -- cgit 1.4.1-2-gfad0 From d3255f708c2b4f2251a23d7aa9e6cc0523e9806f Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 20 Jul 2015 13:43:59 +0200 Subject: small steps for making --symbolFiles:on work again --- compiler/pragmas.nim | 3 +- compiler/rodread.nim | 22 +++--- compiler/rodwrite.nim | 189 +++++++++++++++++++++++++------------------------- 3 files changed, 108 insertions(+), 106 deletions(-) (limited to 'compiler/pragmas.nim') diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 6f37fe756..c771155af 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -276,7 +276,8 @@ proc processNote(c: PContext, n: PNode) = if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and (n.sons[0].kind == nkBracketExpr) and (n.sons[0].sons[1].kind == nkIdent) and - (n.sons[0].sons[0].kind == nkIdent) and (n.sons[1].kind == nkIdent): + (n.sons[0].sons[0].kind == nkIdent): + #and (n.sons[1].kind == nkIdent): var nk: TNoteKind case whichKeyword(n.sons[0].sons[0].ident) of wHint: diff --git a/compiler/rodread.nim b/compiler/rodread.nim index 02e909aac..92ce00240 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -90,7 +90,7 @@ import os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, - ropes, idents, securehash, idgen, types, rodutils, memfiles + ropes, idents, securehash, idgen, types, rodutils, memfiles, tables type TReasonForRecompile* = enum ## all the reasons that can trigger recompilation @@ -136,7 +136,7 @@ type readerIndex: int line: int # only used for debugging, but is always in the code moduleID: int - syms: TIdTable # already processed symbols + syms: Table[int, PSym] # already processed symbols memfile: MemFile # unfortunately there is no point in time where we # can close this! XXX methods*: TSymSeq @@ -372,11 +372,11 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym = else: internalError(info, "decodeSym: no ident") #echo "decoding: {", ident.s - result = PSym(idTableGet(r.syms, id)) + result = r.syms[id] if result == nil: new(result) result.id = id - idTablePut(r.syms, result, result) + r.syms[result.id] = result if debugIds: registerID(result) elif result.id != id: internalError(info, "decodeSym: wrong id") @@ -481,7 +481,7 @@ proc processInterf(r: PRodReader, module: PSym) = var s = newStub(r, w, key) s.owner = module strTableAdd(module.tab, s) - idTablePut(r.syms, s, s) + r.syms[s.id] = s proc processCompilerProcs(r: PRodReader, module: PSym) = if r.compilerProcsIdx == 0: internalError("processCompilerProcs") @@ -491,11 +491,11 @@ proc processCompilerProcs(r: PRodReader, module: PSym) = inc(r.pos) var key = decodeVInt(r.s, r.pos) inc(r.pos) # #10 - var s = PSym(idTableGet(r.syms, key)) + var s = r.syms[key] if s == nil: s = newStub(r, w, key) s.owner = module - idTablePut(r.syms, s, s) + r.syms[s.id] = s strTableAdd(rodCompilerprocs, s) proc processIndex(r: PRodReader; idx: var TIndex; outf: File = nil) = @@ -667,7 +667,7 @@ proc newRodReader(modfilename: string, hash: SecureHash, r.line = 1 r.readerIndex = readerIndex r.filename = modfilename - initIdTable(r.syms) + r.syms = initTable[int, PSym]() # we terminate the file explicitly with ``\0``, so the cast to `cstring` # is safe: r.s = cast[cstring](r.memfile.mem) @@ -737,7 +737,7 @@ proc getReader(moduleId: int): PRodReader = return nil proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym = - result = PSym(idTableGet(r.syms, id)) + result = r.syms[id] if result == nil: # load the symbol: var d = iiTableGet(r.index.tab, id) @@ -802,7 +802,7 @@ proc getHash*(fileIdx: int32): SecureHash = if gMods[fileIdx].hashDone: return gMods[fileIdx].hash - result = secureHashFile(fileIdx.toFilename) + result = secureHashFile(fileIdx.toFullPath) gMods[fileIdx].hash = result template growCache*(cache, pos) = @@ -859,7 +859,7 @@ proc handleSymbolFile(module: PSym): PRodReader = result = gMods[fileIdx].rd if result != nil: module.id = result.moduleID - idTablePut(result.syms, module, module) + result.syms[module.id] = module processInterf(result, module) processCompilerProcs(result, module) loadConverters(result) diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 6f7000efc..d48a9ba40 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -11,14 +11,14 @@ # 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 +import intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, ropes, idents, securehash, rodread, passes, importer, idgen, rodutils # implementation -type +type TRodWriter = object of TPassContext module: PSym hash: SecureHash @@ -46,15 +46,15 @@ proc addInterfaceSym(w: PRodWriter, s: PSym) proc addStmt(w: PRodWriter, n: PNode) proc writeRod(w: PRodWriter) -proc getDefines(): string = +proc getDefines(): string = result = "" for d in definedSymbolNames(): 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: +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) @@ -63,7 +63,7 @@ proc fileIdx(w: PRodWriter, filename: string): int = template filename*(w: PRodWriter): string = w.module.filename -proc newRodWriter(hash: SecureHash, module: PSym): PRodWriter = +proc newRodWriter(hash: SecureHash, module: PSym): PRodWriter = new(result) result.sstack = @[] result.tstack = @[] @@ -85,12 +85,12 @@ proc newRodWriter(hash: SecureHash, module: PSym): PRodWriter = result.init = "" result.origFile = module.info.toFilename result.data = newStringOfCap(12_000) - + proc addModDep(w: PRodWriter, dep: string) = if w.modDeps.len != 0: add(w.modDeps, ' ') encodeVInt(fileIdx(w, dep), w.modDeps) -const +const rodNL = "\x0A" proc addInclDep(w: PRodWriter, dep: string) = @@ -110,18 +110,18 @@ proc pushSym(w: PRodWriter, s: PSym) = if iiTableGet(w.index.tab, s.id) == InvalidKey: w.sstack.add(s) -proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, - result: var string) = - if n == nil: +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) + 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: + if fInfo.fileIndex != n.info.fileIndex: result.add('?') encodeVInt(n.info.col, result) result.add(',') @@ -139,7 +139,7 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, # No need to output the file index, as this is the serialization of one # file. var f = n.flags * PersistentNodeFlags - if f != {}: + if f != {}: result.add('$') encodeVInt(cast[int32](f), result) if n.typ != nil: @@ -147,16 +147,16 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, encodeVInt(n.typ.id, result) pushType(w, n.typ) case n.kind - of nkCharLit..nkInt64Lit: + of nkCharLit..nkInt64Lit: if n.intVal != 0: result.add('!') encodeVBiggestInt(n.intVal, result) - of nkFloatLit..nkFloat64Lit: - if n.floatVal != 0.0: + of nkFloatLit..nkFloat64Lit: + if n.floatVal != 0.0: result.add('!') encodeStr($n.floatVal, result) of nkStrLit..nkTripleStrLit: - if n.strVal != "": + if n.strVal != "": result.add('!') encodeStr(n.strVal, result) of nkIdent: @@ -167,25 +167,25 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, encodeVInt(n.sym.id, result) pushSym(w, n.sym) else: - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): encodeNode(w, n.info, n.sons[i], result) add(result, ')') -proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = +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.s != low(loc.s): + if loc.s != low(loc.s): add(result, '*') encodeVInt(ord(loc.s), result) - if loc.flags != {}: + if loc.flags != {}: add(result, '$') encodeVInt(cast[int32](loc.flags), result) if loc.t != nil: add(result, '^') encodeVInt(cast[int32](loc.t.id), result) pushType(w, loc.t) - if loc.r != nil: + if loc.r != nil: add(result, '!') encodeStr($loc.r, result) if oldLen + 1 == result.len: @@ -193,9 +193,9 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = setLen(result, oldLen) else: add(result, '>') - -proc encodeType(w: PRodWriter, t: PType, result: var string) = - if t == nil: + +proc encodeType(w: PRodWriter, t: PType, result: var string) = + if t == nil: # nil nodes have to be stored too: result.add("[]") return @@ -207,38 +207,38 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) = encodeVInt(ord(t.kind), result) add(result, '+') encodeVInt(t.id, result) - if t.n != nil: + if t.n != nil: encodeNode(w, unknownLineInfo(), t.n, result) - if t.flags != {}: + if t.flags != {}: add(result, '$') encodeVInt(cast[int32](t.flags), result) - if t.callConv != low(t.callConv): + if t.callConv != low(t.callConv): add(result, '?') encodeVInt(ord(t.callConv), result) - if t.owner != nil: + if t.owner != nil: add(result, '*') encodeVInt(t.owner.id, result) pushSym(w, t.owner) - if t.sym != nil: + if t.sym != nil: add(result, '&') encodeVInt(t.sym.id, result) pushSym(w, t.sym) - if t.size != - 1: + if t.size != - 1: add(result, '/') encodeVBiggestInt(t.size, result) - if t.align != 2: + if t.align != 2: add(result, '=') encodeVInt(t.align, result) encodeLoc(w, t.loc, result) - for i in countup(0, sonsLen(t) - 1): - if t.sons[i] == nil: + for i in countup(0, sonsLen(t) - 1): + if t.sons[i] == nil: add(result, "^()") - else: - 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) = +proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) = add(result, '|') encodeVInt(ord(lib.kind), result) add(result, '|') @@ -277,10 +277,10 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) = if s.magic != mNone: result.add('@') encodeVInt(ord(s.magic), result) - if s.options != w.options: + if s.options != w.options: result.add('!') encodeVInt(cast[int32](s.options), result) - if s.position != 0: + if s.position != 0: result.add('%') encodeVInt(s.position, result) if s.offset != - 1: @@ -308,7 +308,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) = if codeAst != nil: # resore the AST: s.ast.sons[codePos] = codeAst - + 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 @@ -329,24 +329,25 @@ when debugWrittenIds: proc symStack(w: PRodWriter): int = var i = 0 - while i < len(w.sstack): + 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: internalError("symStack: module nil: " & s.name.s) - if (m.id == w.module.id) or (sfFromGeneric in s.flags): + if m == nil and s.kind != skPackage: + internalError("symStack: module nil: " & s.name.s) + if s.kind == skPackage or m.id == w.module.id or sfFromGeneric in s.flags: # put definition in here var L = w.data.len - addToIndex(w.index, s.id, L) + 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: + 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) @@ -362,26 +363,26 @@ proc symStack(w: PRodWriter): int = 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: + elif iiTableGet(w.imports.tab, s.id) == InvalidKey: addToIndex(w.imports, s.id, m.id) when debugWrittenIds: - if not Contains(debugWritten, s.id): + if not contains(debugWritten, s.id): echo(w.filename) debug(s) debug(s.owner) debug(m) - InternalError("Symbol referred to but never written") + internalError("Symbol referred to but never written") inc(i) setLen(w.sstack, result) -proc typeStack(w: PRodWriter): int = +proc typeStack(w: PRodWriter): int = var i = 0 - while i < len(w.tstack): + 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: + elif iiTableGet(w.index.tab, t.id) == InvalidKey: var L = w.data.len addToIndex(w.index, t.id, L) encodeType(w, t, w.data) @@ -401,24 +402,24 @@ proc processStacks(w: PRodWriter, finalPass: bool) = if finalPass and (oldS != 0 or oldT != 0): internalError("could not serialize some forwarded symbols/types") -proc rawAddInterfaceSym(w: PRodWriter, s: PSym) = +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 != {}: +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) = +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) = +proc writeRod(w: PRodWriter) = processStacks(w, true) var f: File if not open(f, completeGeneratedFilePath(changeFileExt( @@ -439,12 +440,12 @@ proc writeRod(w: PRodWriter) = 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) @@ -458,31 +459,31 @@ proc writeRod(w: PRodWriter) = var cmd = "CMD:" encodeVInt(cast[int32](gCmd), cmd) f.write(cmd) - f.write(rodNL) - + 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)): + 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) @@ -490,11 +491,11 @@ proc writeRod(w: PRodWriter) = 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) @@ -502,11 +503,11 @@ proc writeRod(w: PRodWriter) = 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) @@ -514,23 +515,23 @@ proc writeRod(w: PRodWriter) = # 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 = +proc process(c: PPassContext, n: PNode): PNode = result = n - if c == nil: return + 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, nkMethodDef, nkIteratorDef, nkConverterDef, - nkTemplateDef, nkMacroDef: + of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef, + nkTemplateDef, nkMacroDef: var s = n.sons[namePos].sym if s == nil: internalError(n.info, "rodwrite.process") if n.sons[bodyPos] == nil: @@ -539,17 +540,17 @@ proc process(c: PPassContext, n: PNode): PNode = sfForward notin s.flags: addInterfaceSym(w, s) of nkVarSection, nkLetSection, nkConstSection: - for i in countup(0, sonsLen(n) - 1): + 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): + of nkTypeSection: + for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] - if a.kind == nkCommentStmt: continue + if a.kind == nkCommentStmt: continue if a.sons[0].kind != nkSym: internalError(a.info, "rodwrite.process") var s = a.sons[0].sym - addInterfaceSym(w, s) + 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 @@ -557,20 +558,20 @@ proc process(c: PPassContext, n: PNode): PNode = # # 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 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(n.sons[i])) addStmt(w, n) - of nkFromStmt: + of nkFromStmt: addModDep(w, getModuleName(n.sons[0])) addStmt(w, n) - of nkIncludeStmt: + of nkIncludeStmt: for i in countup(0, sonsLen(n) - 1): addInclDep(w, getModuleName(n.sons[i])) - of nkPragma: + of nkPragma: addStmt(w, n) - else: + else: discard proc myOpen(module: PSym): PPassContext = @@ -579,7 +580,7 @@ proc myOpen(module: PSym): PPassContext = rawAddInterfaceSym(w, module) result = w -proc myClose(c: PPassContext, n: PNode): PNode = +proc myClose(c: PPassContext, n: PNode): PNode = result = process(c, n) var w = PRodWriter(c) writeRod(w) -- cgit 1.4.1-2-gfad0 From 626226efa40441d03b2f9121e2a73faaa44b2517 Mon Sep 17 00:00:00 2001 From: rku Date: Fri, 31 Jul 2015 15:57:10 +0300 Subject: {.compile.} pragma accepts paths relative to file pragma is in. --- compiler/pragmas.nim | 2 ++ 1 file changed, 2 insertions(+) (limited to 'compiler/pragmas.nim') diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index c771155af..650b0e195 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -395,6 +395,8 @@ proc processCompile(c: PContext, n: PNode) = var found = findFile(s) if found == "": found = s var trunc = changeFileExt(found, "") + if not isAbsolute(found): + found = parentDir(n.info.toFullPath) / found extccomp.addExternalFileToCompile(found) extccomp.addFileToLink(completeCFilePath(trunc, false)) -- cgit 1.4.1-2-gfad0 From bd786812e7fd1cbd1b7a8f038000ac06ad08505e Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 2 Aug 2015 00:35:02 +0200 Subject: fixes #3171 --- compiler/pragmas.nim | 544 ++++++++++++++++++++------------------- tests/pragmas/tsym_as_pragma.nim | 8 + 2 files changed, 281 insertions(+), 271 deletions(-) create mode 100644 tests/pragmas/tsym_as_pragma.nim (limited to 'compiler/pragmas.nim') diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index c771155af..128a90138 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -591,280 +591,282 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, validPragmas: TSpecialWords): bool = var it = n.sons[i] var key = if it.kind == nkExprColonExpr: it.sons[0] else: it - if key.kind == nkIdent: - var userPragma = strTableGet(c.userPragmas, key.ident) - if userPragma != nil: - inc c.instCounter - if c.instCounter > 100: - globalError(it.info, errRecursiveDependencyX, userPragma.name.s) - pragma(c, sym, userPragma.ast, validPragmas) - # ensure the pragma is also remember for generic instantiations in other - # modules: - n.sons[i] = userPragma.ast - dec c.instCounter - else: - var k = whichKeyword(key.ident) - if k in validPragmas: - case k - of wExportc: - makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info) - incl(sym.flags, sfUsed) # avoid wrong hints - of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1")) - of wImportCompilerProc: - processImportCompilerProc(sym, getOptionalStr(c, it, "$1")) - of wExtern: setExternName(sym, expectStrLit(c, it)) - of wImmediate: - if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate) - else: invalidPragma(it) - of wDirty: - if sym.kind == skTemplate: incl(sym.flags, sfDirty) - else: invalidPragma(it) - of wImportCpp: - processImportCpp(sym, getOptionalStr(c, it, "$1")) - of wImportObjC: - processImportObjC(sym, getOptionalStr(c, it, "$1")) - of wAlign: - if sym.typ == nil: invalidPragma(it) - var align = expectIntLit(c, it) - if (not isPowerOfTwo(align) and align != 0) or align >% high(int16): - localError(it.info, errPowerOfTwoExpected) - else: - sym.typ.align = align.int16 - of wSize: - if sym.typ == nil: invalidPragma(it) - var size = expectIntLit(c, it) - if not isPowerOfTwo(size) or size <= 0 or size > 8: - localError(it.info, errPowerOfTwoExpected) - else: - sym.typ.size = size - of wNodecl: - noVal(it) - incl(sym.loc.flags, lfNoDecl) - of wPure, wAsmNoStackFrame: - noVal(it) - if sym != nil: - if k == wPure and sym.kind in routineKinds: invalidPragma(it) - else: incl(sym.flags, sfPure) - of wVolatile: - noVal(it) - incl(sym.flags, sfVolatile) - of wRegister: - noVal(it) - incl(sym.flags, sfRegister) - of wThreadVar: - noVal(it) - incl(sym.flags, sfThread) - of wDeadCodeElim: pragmaDeadCodeElim(c, it) - of wNoForward: pragmaNoForward(c, it) - of wMagic: processMagic(c, it, sym) - of wCompileTime: - noVal(it) - incl(sym.flags, sfCompileTime) - incl(sym.loc.flags, lfNoDecl) - of wGlobal: - noVal(it) - incl(sym.flags, sfGlobal) - incl(sym.flags, sfPure) - of wMerge: - # only supported for backwards compat, doesn't do anything anymore - noVal(it) - of wConstructor: - noVal(it) - incl(sym.flags, sfConstructor) - of wHeader: - var lib = getLib(c, libHeader, getStrLitNode(c, it)) - addToLib(lib, sym) - incl(sym.flags, sfImportc) - incl(sym.loc.flags, lfHeader) - incl(sym.loc.flags, lfNoDecl) - # implies nodecl, because otherwise header would not make sense - if sym.loc.r == nil: sym.loc.r = rope(sym.name.s) - of wDestructor: - sym.flags.incl sfOverriden - if sym.name.s.normalize != "destroy": - localError(n.info, errGenerated, "destructor has to be named 'destroy'") - of wOverride: - sym.flags.incl sfOverriden - of wNosideeffect: - noVal(it) - incl(sym.flags, sfNoSideEffect) - if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect) - of wSideeffect: - noVal(it) - incl(sym.flags, sfSideEffect) - of wNoreturn: - noVal(it) - incl(sym.flags, sfNoReturn) - of wDynlib: - processDynLib(c, it, sym) - of wCompilerproc: - noVal(it) # compilerproc may not get a string! - if sfFromGeneric notin sym.flags: markCompilerProc(sym) - of wProcVar: - noVal(it) - incl(sym.flags, sfProcvar) - of wDeprecated: - if it.kind == nkExprColonExpr: deprecatedStmt(c, it) - elif sym != nil: incl(sym.flags, sfDeprecated) - else: incl(c.module.flags, sfDeprecated) - of wVarargs: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfVarargs) - of wBorrow: - if sym.kind == skType: - typeBorrow(sym, it) - else: - noVal(it) - incl(sym.flags, sfBorrow) - of wFinal: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfFinal) - of wInheritable: - noVal(it) - if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it) - else: incl(sym.typ.flags, tfInheritable) - of wAcyclic: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfAcyclic) - of wShallow: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfShallow) - of wThread: - noVal(it) - incl(sym.flags, sfThread) - incl(sym.flags, sfProcvar) - if sym.typ != nil: incl(sym.typ.flags, tfThread) - of wGcSafe: - noVal(it) - if sym.kind != skType: incl(sym.flags, sfThread) - if sym.typ != nil: incl(sym.typ.flags, tfGcSafe) - else: invalidPragma(it) - of wPacked: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfPacked) - of wHint: message(it.info, hintUser, expectStrLit(c, it)) - of wWarning: message(it.info, warnUser, expectStrLit(c, it)) - of wError: - if sym != nil and sym.isRoutine: - # This is subtle but correct: the error *statement* is only - # allowed for top level statements. Seems to be easier than - # distinguishing properly between - # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}`` - noVal(it) - incl(sym.flags, sfError) - else: - localError(it.info, errUser, expectStrLit(c, it)) - of wFatal: fatal(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(expectStrLit(c, it)) - of wPassc: extccomp.addCompileOption(expectStrLit(c, it)) - of wBreakpoint: pragmaBreakpoint(c, it) - of wWatchPoint: pragmaWatchpoint(c, it) - of wPush: - processPush(c, n, i + 1) - result = true - of wPop: processPop(c, it) - of wPragma: - processPragma(c, n, i) - result = true - of wDiscardable: - noVal(it) - if sym != nil: incl(sym.flags, sfDiscardable) - of wNoInit: - noVal(it) - if sym != nil: incl(sym.flags, sfNoInit) - of wCodegenDecl: processCodegenDecl(c, it, sym) - of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, - wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, - wLinedir, wStacktrace, wLinetrace, wOptimization, - wCallconv, - wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks, - wPatterns: - if processOption(c, it): - # calling conventions (boring...): - localError(it.info, errOptionExpected) - of FirstCallConv..LastCallConv: - assert(sym != nil) - if sym.typ == nil: invalidPragma(it) - else: sym.typ.callConv = wordToCallConv(k) - of wEmit: pragmaEmit(c, it) - of wUnroll: pragmaUnroll(c, it) - of wLinearScanEnd, wComputedGoto: noVal(it) - of wEffects: - # is later processed in effect analysis: - noVal(it) - of wIncompleteStruct: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfIncompleteStruct) - of wUnchecked: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfUncheckedArray) - of wUnion: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfUnion) - of wRequiresInit: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfNeedsInit) - of wByRef: - noVal(it) - if sym == nil or sym.typ == nil: - if processOption(c, it): localError(it.info, errOptionExpected) - else: - incl(sym.typ.flags, tfByRef) - of wByCopy: - noVal(it) - if sym.kind != skType or sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfByCopy) - of wInject, wGensym: - # We check for errors, but do nothing with these pragmas otherwise - # as they are handled directly in 'evalTemplate'. - noVal(it) - if sym == nil: invalidPragma(it) - of wLine: pragmaLine(c, it) - of wRaises, wTags: pragmaRaisesOrTags(c, it) - of wLocks: - if sym == nil: pragmaLockStmt(c, it) - elif sym.typ == nil: invalidPragma(it) - else: sym.typ.lockLevel = pragmaLocks(c, it) - of wGuard: - if sym == nil or sym.kind notin {skVar, skLet, skField}: - invalidPragma(it) - else: - sym.guard = pragmaGuard(c, it, sym.kind) - of wGoto: - if sym == nil or sym.kind notin {skVar, skLet}: - invalidPragma(it) - else: - sym.flags.incl sfGoto - of wInjectStmt: - if it.kind != nkExprColonExpr: - localError(it.info, errExprExpected) - else: - it.sons[1] = c.semExpr(c, it.sons[1]) - of wExperimental: - noVal(it) - if isTopLevel(c): - c.module.flags.incl sfExperimental - else: - localError(it.info, "'experimental' pragma only valid as toplevel statement") - of wNoRewrite: + if key.kind == nkBracketExpr: + processNote(c, it) + return + let ident = considerQuotedIdent(key) + var userPragma = strTableGet(c.userPragmas, ident) + if userPragma != nil: + inc c.instCounter + if c.instCounter > 100: + globalError(it.info, errRecursiveDependencyX, userPragma.name.s) + pragma(c, sym, userPragma.ast, validPragmas) + # ensure the pragma is also remember for generic instantiations in other + # modules: + n.sons[i] = userPragma.ast + dec c.instCounter + else: + var k = whichKeyword(ident) + if k in validPragmas: + case k + of wExportc: + makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info) + incl(sym.flags, sfUsed) # avoid wrong hints + of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1")) + of wImportCompilerProc: + processImportCompilerProc(sym, getOptionalStr(c, it, "$1")) + of wExtern: setExternName(sym, expectStrLit(c, it)) + of wImmediate: + if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate) + else: invalidPragma(it) + of wDirty: + if sym.kind == skTemplate: incl(sym.flags, sfDirty) + else: invalidPragma(it) + of wImportCpp: + processImportCpp(sym, getOptionalStr(c, it, "$1")) + of wImportObjC: + processImportObjC(sym, getOptionalStr(c, it, "$1")) + of wAlign: + if sym.typ == nil: invalidPragma(it) + var align = expectIntLit(c, it) + if (not isPowerOfTwo(align) and align != 0) or align >% high(int16): + localError(it.info, errPowerOfTwoExpected) + else: + sym.typ.align = align.int16 + of wSize: + if sym.typ == nil: invalidPragma(it) + var size = expectIntLit(c, it) + if not isPowerOfTwo(size) or size <= 0 or size > 8: + localError(it.info, errPowerOfTwoExpected) + else: + sym.typ.size = size + of wNodecl: + noVal(it) + incl(sym.loc.flags, lfNoDecl) + of wPure, wAsmNoStackFrame: + noVal(it) + if sym != nil: + if k == wPure and sym.kind in routineKinds: invalidPragma(it) + else: incl(sym.flags, sfPure) + of wVolatile: + noVal(it) + incl(sym.flags, sfVolatile) + of wRegister: + noVal(it) + incl(sym.flags, sfRegister) + of wThreadVar: + noVal(it) + incl(sym.flags, sfThread) + of wDeadCodeElim: pragmaDeadCodeElim(c, it) + of wNoForward: pragmaNoForward(c, it) + of wMagic: processMagic(c, it, sym) + of wCompileTime: + noVal(it) + incl(sym.flags, sfCompileTime) + incl(sym.loc.flags, lfNoDecl) + of wGlobal: + noVal(it) + incl(sym.flags, sfGlobal) + incl(sym.flags, sfPure) + of wMerge: + # only supported for backwards compat, doesn't do anything anymore + noVal(it) + of wConstructor: + noVal(it) + incl(sym.flags, sfConstructor) + of wHeader: + var lib = getLib(c, libHeader, getStrLitNode(c, it)) + addToLib(lib, sym) + incl(sym.flags, sfImportc) + incl(sym.loc.flags, lfHeader) + incl(sym.loc.flags, lfNoDecl) + # implies nodecl, because otherwise header would not make sense + if sym.loc.r == nil: sym.loc.r = rope(sym.name.s) + of wDestructor: + sym.flags.incl sfOverriden + if sym.name.s.normalize != "destroy": + localError(n.info, errGenerated, "destructor has to be named 'destroy'") + of wOverride: + sym.flags.incl sfOverriden + of wNosideeffect: + noVal(it) + incl(sym.flags, sfNoSideEffect) + if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect) + of wSideeffect: + noVal(it) + incl(sym.flags, sfSideEffect) + of wNoreturn: + noVal(it) + incl(sym.flags, sfNoReturn) + of wDynlib: + processDynLib(c, it, sym) + of wCompilerproc: + noVal(it) # compilerproc may not get a string! + if sfFromGeneric notin sym.flags: markCompilerProc(sym) + of wProcVar: + noVal(it) + incl(sym.flags, sfProcvar) + of wDeprecated: + if it.kind == nkExprColonExpr: deprecatedStmt(c, it) + elif sym != nil: incl(sym.flags, sfDeprecated) + else: incl(c.module.flags, sfDeprecated) + of wVarargs: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfVarargs) + of wBorrow: + if sym.kind == skType: + typeBorrow(sym, it) + else: noVal(it) + incl(sym.flags, sfBorrow) + of wFinal: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfFinal) + of wInheritable: + noVal(it) + if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it) + else: incl(sym.typ.flags, tfInheritable) + of wAcyclic: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfAcyclic) + of wShallow: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfShallow) + of wThread: + noVal(it) + incl(sym.flags, sfThread) + incl(sym.flags, sfProcvar) + if sym.typ != nil: incl(sym.typ.flags, tfThread) + of wGcSafe: + noVal(it) + if sym.kind != skType: incl(sym.flags, sfThread) + if sym.typ != nil: incl(sym.typ.flags, tfGcSafe) else: invalidPragma(it) + of wPacked: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfPacked) + of wHint: message(it.info, hintUser, expectStrLit(c, it)) + of wWarning: message(it.info, warnUser, expectStrLit(c, it)) + of wError: + if sym != nil and sym.isRoutine: + # This is subtle but correct: the error *statement* is only + # allowed for top level statements. Seems to be easier than + # distinguishing properly between + # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}`` + noVal(it) + incl(sym.flags, sfError) + else: + localError(it.info, errUser, expectStrLit(c, it)) + of wFatal: fatal(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(expectStrLit(c, it)) + of wPassc: extccomp.addCompileOption(expectStrLit(c, it)) + of wBreakpoint: pragmaBreakpoint(c, it) + of wWatchPoint: pragmaWatchpoint(c, it) + of wPush: + processPush(c, n, i + 1) + result = true + of wPop: processPop(c, it) + of wPragma: + processPragma(c, n, i) + result = true + of wDiscardable: + noVal(it) + if sym != nil: incl(sym.flags, sfDiscardable) + of wNoInit: + noVal(it) + if sym != nil: incl(sym.flags, sfNoInit) + of wCodegenDecl: processCodegenDecl(c, it, sym) + of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, + wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, + wLinedir, wStacktrace, wLinetrace, wOptimization, + wCallconv, + wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks, + wPatterns: + if processOption(c, it): + # calling conventions (boring...): + localError(it.info, errOptionExpected) + of FirstCallConv..LastCallConv: + assert(sym != nil) + if sym.typ == nil: invalidPragma(it) + else: sym.typ.callConv = wordToCallConv(k) + of wEmit: pragmaEmit(c, it) + of wUnroll: pragmaUnroll(c, it) + of wLinearScanEnd, wComputedGoto: noVal(it) + of wEffects: + # is later processed in effect analysis: + noVal(it) + of wIncompleteStruct: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfIncompleteStruct) + of wUnchecked: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfUncheckedArray) + of wUnion: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfUnion) + of wRequiresInit: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfNeedsInit) + of wByRef: + noVal(it) + if sym == nil or sym.typ == nil: + if processOption(c, it): localError(it.info, errOptionExpected) + else: + incl(sym.typ.flags, tfByRef) + of wByCopy: + noVal(it) + if sym.kind != skType or sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfByCopy) + of wInject, wGensym: + # We check for errors, but do nothing with these pragmas otherwise + # as they are handled directly in 'evalTemplate'. + noVal(it) + if sym == nil: invalidPragma(it) + of wLine: pragmaLine(c, it) + of wRaises, wTags: pragmaRaisesOrTags(c, it) + of wLocks: + if sym == nil: pragmaLockStmt(c, it) + elif sym.typ == nil: invalidPragma(it) + else: sym.typ.lockLevel = pragmaLocks(c, it) + of wGuard: + if sym == nil or sym.kind notin {skVar, skLet, skField}: + invalidPragma(it) + else: + sym.guard = pragmaGuard(c, it, sym.kind) + of wGoto: + if sym == nil or sym.kind notin {skVar, skLet}: + invalidPragma(it) + else: + sym.flags.incl sfGoto + of wInjectStmt: + if it.kind != nkExprColonExpr: + localError(it.info, errExprExpected) + else: + it.sons[1] = c.semExpr(c, it.sons[1]) + of wExperimental: + noVal(it) + if isTopLevel(c): + c.module.flags.incl sfExperimental + else: + localError(it.info, "'experimental' pragma only valid as toplevel statement") + of wNoRewrite: + noVal(it) else: invalidPragma(it) - else: processNote(c, it) + else: invalidPragma(it) proc implicitPragmas*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = diff --git a/tests/pragmas/tsym_as_pragma.nim b/tests/pragmas/tsym_as_pragma.nim new file mode 100644 index 000000000..f6ba44dc9 --- /dev/null +++ b/tests/pragmas/tsym_as_pragma.nim @@ -0,0 +1,8 @@ + +# bug #3171 + +template newDataWindow(): stmt = + let eventClosure = proc (closure: pointer): bool {.closure, cdecl.} = + discard + +newDataWindow() -- cgit 1.4.1-2-gfad0 From dc047931bbde432512053c91d0cb9b8a230a7574 Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 6 Sep 2015 02:29:30 +0200 Subject: fixes #2590; methods now require a .base annotation --- compiler/ast.nim | 1 + compiler/cgmeth.nim | 35 ++++++++++++++++++++++++++--------- compiler/msgs.nim | 4 ++-- compiler/pragmas.nim | 5 ++++- compiler/wordrecg.nim | 5 +++-- doc/manual/procs.txt | 9 +++++++-- tests/method/mmultim3.nim | 2 +- tests/method/temptybody.nim | 2 +- tests/method/tmethods1.nim | 6 +++--- tests/method/tmproto.nim | 2 +- tests/method/tmultim1.nim | 2 +- tests/method/tmultim2.nim | 2 +- tests/method/tmultim4.nim | 2 +- tests/method/tmultim6.nim | 2 +- tests/method/trecmeth.nim | 8 ++++---- todo.txt | 1 - web/news.txt | 13 ++++++++++++- 17 files changed, 69 insertions(+), 32 deletions(-) (limited to 'compiler/pragmas.nim') diff --git a/compiler/ast.nim b/compiler/ast.nim index aafe503dc..177b5c5c7 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -297,6 +297,7 @@ const sfGoto* = sfOverriden # var is used for 'goto' code generation sfWrittenTo* = sfBorrow # param is assigned to sfEscapes* = sfProcvar # param escapes + sfBase* = sfDiscriminant const # getting ready for the future expr/stmt merge diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index adb4f1f92..d2358b84a 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -47,8 +47,10 @@ proc methodCall*(n: PNode): PNode = var gMethods: seq[tuple[methods: TSymSeq, dispatcher: PSym]] = @[] -proc sameMethodBucket(a, b: PSym): bool = - result = false +type + MethodResult = enum No, Invalid, Yes + +proc sameMethodBucket(a, b: PSym): MethodResult = if a.name.id != b.name.id: return if sonsLen(a.typ) != sonsLen(b.typ): return # check for return type: @@ -64,13 +66,15 @@ proc sameMethodBucket(a, b: PSym): bool = bb = bb.lastSon else: break - if sameType(aa, bb) or - (aa.kind == tyObject) and (bb.kind == tyObject) and - (inheritanceDiff(bb, aa) < 0): - discard + if sameType(aa, bb): discard + elif aa.kind == tyObject and bb.kind == tyObject: + let diff = inheritanceDiff(bb, aa) + if diff < 0: discard "Ok" + elif diff != high(int): + result = Invalid else: - return - result = true + return No + if result != Invalid: result = Yes proc attachDispatcher(s: PSym, dispatcher: PNode) = var L = s.ast.len-1 @@ -133,18 +137,31 @@ proc fixupDispatcher(meth, disp: PSym) = proc methodDef*(s: PSym, fromCache: bool) = var L = len(gMethods) + var witness: PSym for i in countup(0, L - 1): var disp = gMethods[i].dispatcher - if sameMethodBucket(disp, s): + case sameMethodBucket(disp, s) + of Yes: add(gMethods[i].methods, s) attachDispatcher(s, lastSon(disp.ast)) fixupDispatcher(s, disp) when useEffectSystem: checkMethodEffects(disp, s) + if sfBase in s.flags and gMethods[i].methods[0] != s: + # already exists due to forwarding definition? + localError(s.info, "method is not a base") return + of No: discard + of Invalid: + if witness.isNil: witness = gMethods[i].methods[0] # create a new dispatcher: add(gMethods, (methods: @[s], dispatcher: createDispatcher(s))) if fromCache: internalError(s.info, "no method dispatcher found") + if witness != nil: + localError(s.info, "invalid declaration order; cannot attach '" & s.name.s & + "' to method defined here: " & $witness.info) + elif sfBase notin s.flags: + message(s.info, warnUseBase) proc relevantCol(methods: TSymSeq, col: int): bool = # returns true iff the position is relevant diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 1b1f0a76e..c815e0277 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -118,7 +118,7 @@ type warnUnknownSubstitutionX, warnLanguageXNotSupported, warnFieldXNotSupported, warnCommentXIgnored, warnNilStatement, warnTypelessParam, - warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode, + warnUseBase, warnWriteToForeignHeap, warnUnsafeCode, warnEachIdentIsTuple, warnShadowIdent, warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, @@ -391,7 +391,7 @@ const warnCommentXIgnored: "comment \'$1\' ignored", warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead", warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'", - warnDifferentHeaps: "possible inconsistency of thread local heaps", + 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", diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 5f317ed24..1c51251fe 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -27,7 +27,7 @@ const wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, wOverride, wConstructor} converterPragmas* = procPragmas - methodPragmas* = procPragmas + methodPragmas* = procPragmas+{wBase} templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty, wDelegator} macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc, @@ -867,6 +867,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, localError(it.info, "'experimental' pragma only valid as toplevel statement") of wNoRewrite: noVal(it) + of wBase: + noVal(it) + sym.flags.incl sfBase else: invalidPragma(it) else: invalidPragma(it) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index deb12536f..23f012ea5 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -45,7 +45,7 @@ type wImportc, wExportc, wIncompleteStruct, wRequiresInit, wAlign, wNodecl, wPure, wSideeffect, wHeader, wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib, - wCompilerproc, wProcVar, + wCompilerproc, wProcVar, wBase, wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wLink, wCompile, wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger, @@ -128,7 +128,8 @@ const "importcompilerproc", "importc", "exportc", "incompletestruct", "requiresinit", "align", "nodecl", "pure", "sideeffect", "header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib", - "compilerproc", "procvar", "fatal", "error", "warning", "hint", "line", + "compilerproc", "procvar", "base", + "fatal", "error", "warning", "hint", "line", "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", "link", "compile", "linksys", "deprecated", "varargs", "callconv", "breakpoint", "debugger", "nimcall", "stdcall", diff --git a/doc/manual/procs.txt b/doc/manual/procs.txt index bd86e4651..9d00b7e3c 100644 --- a/doc/manual/procs.txt +++ b/doc/manual/procs.txt @@ -385,7 +385,7 @@ dispatch. PlusExpr = ref object of Expression a, b: Expression - method eval(e: Expression): int = + method eval(e: Expression): int {.base.} = # override this base method quit "to override!" @@ -410,6 +410,11 @@ In the example the constructors ``newLit`` and ``newPlus`` are procs because they should use static binding, but ``eval`` is a method because it requires dynamic binding. +As can be seen in the example, base methods have to be annotated with +the `base`:idx: pragma. The ``base`` pragma also acts as a reminder for the +programmer that a base method ``m`` is used as the foundation to determine all +the effects that a call to ``m`` might cause. + In a multi-method all parameters that have an object type are used for the dispatching: @@ -419,7 +424,7 @@ dispatching: Unit = ref object of Thing x: int - method collide(a, b: Thing) {.inline.} = + method collide(a, b: Thing) {.base, inline.} = quit "to override!" method collide(a: Thing, b: Unit) {.inline.} = diff --git a/tests/method/mmultim3.nim b/tests/method/mmultim3.nim index 3139a8089..b391731be 100644 --- a/tests/method/mmultim3.nim +++ b/tests/method/mmultim3.nim @@ -3,7 +3,7 @@ type var myObj* : ref TObj -method test123(a : ref TObj) = +method test123(a : ref TObj) {.base.} = echo("Hi base!") proc testMyObj*() = diff --git a/tests/method/temptybody.nim b/tests/method/temptybody.nim index 26285d05b..aad945f81 100644 --- a/tests/method/temptybody.nim +++ b/tests/method/temptybody.nim @@ -2,7 +2,7 @@ type MyClass = ref object of RootObj -method HelloWorld*(obj: MyClass) = +method HelloWorld*(obj: MyClass) {.base.} = when defined(myPragma): echo("Hello World") # discard # with this line enabled it works diff --git a/tests/method/tmethods1.nim b/tests/method/tmethods1.nim index 461e2cb5e..cb4da5ef2 100644 --- a/tests/method/tmethods1.nim +++ b/tests/method/tmethods1.nim @@ -2,7 +2,7 @@ discard """ output: "do nothing" """ -method somethin(obj: TObject) = +method somethin(obj: RootObj) {.base.} = echo "do nothing" type @@ -14,9 +14,9 @@ type TSomethingElse = object PSomethingElse = ref TSomethingElse -method foo(a: PNode, b: PSomethingElse) = discard +method foo(a: PNode, b: PSomethingElse) {.base.} = discard method foo(a: PNodeFoo, b: PSomethingElse) = discard -var o: TObject +var o: RootObj o.somethin() diff --git a/tests/method/tmproto.nim b/tests/method/tmproto.nim index 5d75cff1a..087666ea0 100644 --- a/tests/method/tmproto.nim +++ b/tests/method/tmproto.nim @@ -2,7 +2,7 @@ type Obj1 = ref object {.inheritable.} Obj2 = ref object of Obj1 -method beta(x: Obj1): int +method beta(x: Obj1): int {.base.} proc delta(x: Obj2): int = beta(x) diff --git a/tests/method/tmultim1.nim b/tests/method/tmultim1.nim index c7027f4c0..010468a5b 100644 --- a/tests/method/tmultim1.nim +++ b/tests/method/tmultim1.nim @@ -11,7 +11,7 @@ type PlusExpr = ref object of Expression a, b: Expression -method eval(e: Expression): int = quit "to override!" +method eval(e: Expression): int {.base.} = quit "to override!" method eval(e: Literal): int = return e.x method eval(e: PlusExpr): int = return eval(e.a) + eval(e.b) diff --git a/tests/method/tmultim2.nim b/tests/method/tmultim2.nim index e695dd19b..98a08b1cb 100644 --- a/tests/method/tmultim2.nim +++ b/tests/method/tmultim2.nim @@ -14,7 +14,7 @@ type TParticle = object of TThing a, b: int -method collide(a, b: TThing) {.inline.} = +method collide(a, b: TThing) {.base, inline.} = echo "collide: thing, thing" method collide(a: TThing, b: TUnit) {.inline.} = diff --git a/tests/method/tmultim4.nim b/tests/method/tmultim4.nim index 54630fb41..eabf8d126 100644 --- a/tests/method/tmultim4.nim +++ b/tests/method/tmultim4.nim @@ -5,7 +5,7 @@ discard """ type Test = object of TObject -method doMethod(a: ref TObject) {.raises: [EIO].} = +method doMethod(a: ref TObject) {.base, raises: [EIO].} = quit "override" method doMethod(a: ref Test) = diff --git a/tests/method/tmultim6.nim b/tests/method/tmultim6.nim index 6c21f80d2..97ed2845c 100644 --- a/tests/method/tmultim6.nim +++ b/tests/method/tmultim6.nim @@ -10,7 +10,7 @@ type TParticle = object of TThing a, b: int -method collide(a, b: TThing) {.inline.} = +method collide(a, b: TThing) {.base, inline.} = quit "to override!" method collide[T](a: TThing, b: TUnit[T]) {.inline.} = diff --git a/tests/method/trecmeth.nim b/tests/method/trecmeth.nim index 32f620f15..ac0a1e977 100644 --- a/tests/method/trecmeth.nim +++ b/tests/method/trecmeth.nim @@ -2,12 +2,12 @@ # for recursive methods works, no code is being executed type - Obj = ref object of TObject + Obj = ref object of RootObj # Mutual recursion -method alpha(x: Obj) -method beta(x: Obj) +method alpha(x: Obj) {.base.} +method beta(x: Obj) {.base.} method alpha(x: Obj) = beta(x) @@ -17,6 +17,6 @@ method beta(x: Obj) = # Simple recursion -method gamma(x: Obj) = +method gamma(x: Obj) {.base.} = gamma(x) diff --git a/todo.txt b/todo.txt index 66a9d1f0f..1160000b0 100644 --- a/todo.txt +++ b/todo.txt @@ -13,7 +13,6 @@ version 0.11.4 - add "all threads are blocked" detection to 'spawn' - Deprecate ``immediate`` for templates and macros -- make people annotate .anchor methods version 1.0 diff --git a/web/news.txt b/web/news.txt index 823a10dfa..80983d33d 100644 --- a/web/news.txt +++ b/web/news.txt @@ -50,6 +50,9 @@ News and are now deprecated and will be removed from the language. Instead you have to insert type conversions like ``(proc (a, b: int) {.closure.})(myToplevelProc)`` if necessary. + - The modules ``libffi``, ``sdl``, ``windows``, ``zipfiles``, ``libzip``, + ``zlib``, ``zzip``, ``dialogs``, ``expat``, ``graphics``, ``libcurl``, + ``sphinx`` have been moved out of the stdlib and are Nimble packages now. - The constant fights between 32 and 64 bit DLLs on Windows have been put to an end: The standard distribution now ships with 32 and 64 bit versions of all the DLLs the standard library needs. This means that the following @@ -66,9 +69,11 @@ News was previously. Macros that generate nkPar nodes when object is expected are likely to break. Macros that expect nkPar nodes to which objects are passed are likely to break as well. + - Base methods now need to be annotated with the ``base`` pragma. This makes + multi methods less error-prone to use with the effect system. - Library additions + Library Additions ----------------- - The nre module has been added, providing a better interface to PCRE than re. @@ -81,6 +86,12 @@ News locale anymore and now take an optional ``decimalSep = '.'`` parameter. + Compiler Additions + ------------------ + + - The compiler now supports a new configuration system based on ``NimScript``. + + Language Additions ------------------ -- cgit 1.4.1-2-gfad0 From 5e9ce88dafbaa0bf72a7c7c3ce11a8d827ab3200 Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Mon, 28 Sep 2015 14:34:36 -0700 Subject: implement bitsize pragma for bitfields --- compiler/ast.nim | 1 + compiler/ccgtypes.nim | 2 ++ compiler/pragmas.nim | 7 ++++++- compiler/wordrecg.nim | 2 ++ tests/pragmas/tbitsize.nim | 7 +++++++ 5 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/pragmas/tbitsize.nim (limited to 'compiler/pragmas.nim') diff --git a/compiler/ast.nim b/compiler/ast.nim index 4001e896e..9db5a4e34 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -784,6 +784,7 @@ type tab*: TStrTable # interface table for modules of skLet, skVar, skField, skForVar: guard*: PSym + bitsize*: BiggestInt else: nil magic*: TMagic typ*: PType diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 84d02d1da..1ed9ce113 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -441,6 +441,8 @@ proc genRecordFieldsAux(m: BModule, n: PNode, elif fieldType.kind == tySequence: # we need to use a weak dependency here for trecursive_table. addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname]) + elif field.bitsize != 0: + addf(result, "$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check), sname, rope($field.bitsize)]) else: # don't use fieldType here because we need the # tyGenericInst for C++ template support diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 1c51251fe..ba05b2792 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -56,7 +56,7 @@ const wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, wBorrow, wGcSafe} fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, - wImportCpp, wImportObjC, wError, wGuard} + wImportCpp, wImportObjC, wError, wGuard, wBitsize} varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern, wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal, @@ -844,6 +844,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, if sym == nil: pragmaLockStmt(c, it) elif sym.typ == nil: invalidPragma(it) else: sym.typ.lockLevel = pragmaLocks(c, it) + of wBitsize: + if sym == nil or sym.kind != skField or it.kind != nkExprColonExpr: + invalidPragma(it) + else: + sym.bitsize = expectIntLit(c, it) of wGuard: if sym == nil or sym.kind notin {skVar, skLet, skField}: invalidPragma(it) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 23f012ea5..d1e5438f3 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -82,6 +82,7 @@ type wStdIn, wStdOut, wStdErr, wInOut, wByCopy, wByRef, wOneWay, + wBitsize, TSpecialWords* = set[TSpecialWord] @@ -168,6 +169,7 @@ const "stdin", "stdout", "stderr", "inout", "bycopy", "byref", "oneway", + "bitsize", ] proc findStr*(a: openArray[string], s: string): int = diff --git a/tests/pragmas/tbitsize.nim b/tests/pragmas/tbitsize.nim new file mode 100644 index 000000000..d2c646ef7 --- /dev/null +++ b/tests/pragmas/tbitsize.nim @@ -0,0 +1,7 @@ +type + bits* = object + flag* {.bitsize: 1.}: cint + opts* {.bitsize: 4.}: cint + +var b: bits +echo b.flag -- cgit 1.4.1-2-gfad0 From a2c040e3bd2a34bff889c22e4fb098b95b45fe53 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 3 Oct 2015 23:19:02 +0200 Subject: added undocumented exportNims pragma for Nimscript support --- compiler/magicsys.nim | 38 ++++++++++++++++++++++---------------- compiler/modules.nim | 7 +++++++ compiler/pragmas.nim | 18 +++++++++++------- compiler/vm.nim | 25 +++++++++++++++++++++++++ compiler/wordrecg.nim | 5 +++-- 5 files changed, 68 insertions(+), 25 deletions(-) (limited to 'compiler/pragmas.nim') diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 98a4b08bf..40e0728ae 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -14,22 +14,14 @@ import var systemModule*: PSym -proc registerSysType*(t: PType) - # magic symbols in the system module: -proc getSysType*(kind: TTypeKind): PType -proc getCompilerProc*(name: string): PSym -proc registerCompilerProc*(s: PSym) -proc finishSystem*(tab: TStrTable) -proc getSysSym*(name: string): PSym -# implementation - var gSysTypes: array[TTypeKind, PType] compilerprocs: TStrTable + exposed: TStrTable proc nilOrSysInt*: PType = gSysTypes[tyInt] -proc registerSysType(t: PType) = +proc registerSysType*(t: PType) = if gSysTypes[t.kind] == nil: gSysTypes[t.kind] = t proc newSysType(kind: TTypeKind, size: int): PType = @@ -37,7 +29,7 @@ proc newSysType(kind: TTypeKind, size: int): PType = result.size = size result.align = size.int16 -proc getSysSym(name: string): PSym = +proc getSysSym*(name: string): PSym = result = strTableGet(systemModule.tab, getIdent(name)) if result == nil: rawMessage(errSystemNeeds, name) @@ -61,7 +53,7 @@ proc getSysMagic*(name: string, m: TMagic): PSym = proc sysTypeFromName*(name: string): PType = result = getSysSym(name).typ -proc getSysType(kind: TTypeKind): PType = +proc getSysType*(kind: TTypeKind): PType = result = gSysTypes[kind] if result == nil: case kind @@ -97,6 +89,7 @@ var proc resetSysTypes* = systemModule = nil initStrTable(compilerprocs) + initStrTable(exposed) for i in low(gSysTypes)..high(gSysTypes): gSysTypes[i] = nil @@ -163,8 +156,8 @@ proc setIntLitType*(result: PNode) = result.typ = getSysType(tyInt64) else: internalError(result.info, "invalid int size") -proc getCompilerProc(name: string): PSym = - var ident = getIdent(name, hashIgnoreStyle(name)) +proc getCompilerProc*(name: string): PSym = + let ident = getIdent(name) result = strTableGet(compilerprocs, ident) if result == nil: result = strTableGet(rodCompilerprocs, ident) @@ -173,9 +166,22 @@ proc getCompilerProc(name: string): PSym = if result.kind == skStub: loadStub(result) if result.kind == skAlias: result = result.owner -proc registerCompilerProc(s: PSym) = +proc registerCompilerProc*(s: PSym) = strTableAdd(compilerprocs, s) -proc finishSystem(tab: TStrTable) = discard +proc registerNimScriptSymbol*(s: PSym) = + # Nimscript symbols must be al unique: + let conflict = strTableGet(exposed, s.name) + if conflict == nil: + strTableAdd(exposed, s) + else: + localError(s.info, "symbol conflicts with other .exportNims symbol at: " & + $conflict.info) + +proc getNimScriptSymbol*(name: string): PSym = + strTableGet(exposed, getIdent(name)) + +proc resetNimScriptSymbols*() = initStrTable(exposed) initStrTable(compilerprocs) +initStrTable(exposed) diff --git a/compiler/modules.nim b/compiler/modules.nim index 85c99c4ec..3893d377e 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -78,6 +78,13 @@ proc resetModule*(fileIdx: int32) = if fileIdx <% cgendata.gModules.len: cgendata.gModules[fileIdx] = nil +proc resetModule*(module: PSym) = + let conflict = getModule(module.position.int32) + if conflict == nil: return + doAssert conflict == module + resetModule(module.position.int32) + initStrTable(module.tab) + proc resetAllModules* = for i in 0..gCompiledModules.high: if gCompiledModules[i] != nil: diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index ba05b2792..79d7884fa 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -25,18 +25,19 @@ const wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl, wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, - wOverride, wConstructor} + wOverride, wConstructor, wExportNims} converterPragmas* = procPragmas methodPragmas* = procPragmas+{wBase} templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty, - wDelegator} + wDelegator, wExportNims} macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc, wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern, - wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator} + wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator, + wExportNims} iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises, - wTags, wLocks, wGcSafe} + wTags, wLocks, wGcSafe, wExportNims} exprPragmas* = {wLine, wLocks, wNoRewrite} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, @@ -54,15 +55,15 @@ const wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow, wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef, wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, - wBorrow, wGcSafe} + wBorrow, wGcSafe, wExportNims} fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, wImportCpp, wImportObjC, wError, wGuard, wBitsize} varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern, wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal, - wGensym, wInject, wCodegenDecl, wGuard, wGoto} + wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims} constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl, - wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject} + wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect, wThread, wRaises, wLocks, wTags, wGcSafe} @@ -859,6 +860,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, invalidPragma(it) else: sym.flags.incl sfGoto + of wExportNims: + if sym == nil: invalidPragma(it) + else: magicsys.registerNimScriptSymbol(sym) of wInjectStmt: if it.kind != nkExprColonExpr: localError(it.info, errExprExpected) diff --git a/compiler/vm.nim b/compiler/vm.nim index ad4aa1017..ded66d3d0 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1411,6 +1411,31 @@ proc execute(c: PCtx, start: int): PNode = newSeq(tos.slots, c.prc.maxSlots) result = rawExecute(c, start, tos).regToNode +proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = + if sym.kind in routineKinds: + if sym.typ.len-1 != args.len: + localError(sym.info, + "NimScript: expected $# arguments, but got $#" % [ + $(sym.typ.len-1), $args.len]) + else: + let start = genProc(c, sym) + + var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil) + let maxSlots = sym.offset + newSeq(tos.slots, maxSlots) + + # setup parameters: + if not isEmptyType(sym.typ.sons[0]) or sym.kind == skMacro: + putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info)) + # XXX We could perform some type checking here. + for i in 1..