diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ccgstmts.nim | 2 | ||||
-rw-r--r-- | compiler/commands.nim | 3 | ||||
-rw-r--r-- | compiler/docgen.nim | 168 | ||||
-rw-r--r-- | compiler/hlo.nim | 3 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 72 | ||||
-rw-r--r-- | compiler/nimrod.nimrod.cfg | 1 | ||||
-rw-r--r-- | compiler/options.nim | 2 | ||||
-rw-r--r-- | compiler/renderer.nim | 28 | ||||
-rw-r--r-- | compiler/sem.nim | 19 | ||||
-rw-r--r-- | compiler/semdata.nim | 2 | ||||
-rw-r--r-- | compiler/semexprs.nim | 23 | ||||
-rw-r--r-- | compiler/semfold.nim | 18 | ||||
-rw-r--r-- | compiler/semgnrc.nim | 8 | ||||
-rw-r--r-- | compiler/semtempl.nim | 38 | ||||
-rw-r--r-- | compiler/semtypes.nim | 10 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 2 | ||||
-rw-r--r-- | compiler/transf.nim | 1 | ||||
-rw-r--r-- | compiler/types.nim | 4 | ||||
-rw-r--r-- | compiler/typesrenderer.nim | 113 | ||||
-rw-r--r-- | compiler/vm.nim | 92 | ||||
-rw-r--r-- | compiler/vmgen.nim | 17 |
21 files changed, 497 insertions, 129 deletions
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 990153fc7..311149cb3 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -138,7 +138,7 @@ proc genBreakState(p: BProc, n: PNode) = if n.sons[0].kind == nkClosure: # XXX this produces quite inefficient code! initLocExpr(p, n.sons[0].sons[1], a) - lineF(p, cpsStmts, "if (($1->Field0) < 0) break;$n", [rdLoc(a)]) + lineF(p, cpsStmts, "if (((NI*) $1)[0] < 0) break;$n", [rdLoc(a)]) else: initLocExpr(p, n.sons[0], a) # the environment is guaranteed to contain the 'state' field at offset 0: diff --git a/compiler/commands.nim b/compiler/commands.nim index 18bdb54d3..8339219ed 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -267,6 +267,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = of "out", "o": expectArg(switch, arg, pass, info) options.outFile = arg + of "docseesrcurl": + expectArg(switch, arg, pass, info) + options.docSeeSrcUrl = arg of "mainmodule", "m": expectArg(switch, arg, pass, info) optMainModule = arg diff --git a/compiler/docgen.nim b/compiler/docgen.nim index d8c439c9c..6948c4979 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -14,7 +14,7 @@ import ast, strutils, strtabs, options, msgs, os, ropes, idents, wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite, - importer, sempass2, json + importer, sempass2, json, xmltree, cgi, typesrenderer type TSections = array[TSymKind, PRope] @@ -23,8 +23,9 @@ type id: int # for generating IDs toc, section: TSections indexValFilename: string + seenSymbols: PStringTable # avoids duplicate symbol generation for HTML. - PDoc* = ref TDocumentor + PDoc* = ref TDocumentor ## Alias to type less. proc compilerMsgHandler(filename: string, line, col: int, msgKind: rst.TMsgKind, arg: string) {.procvar.} = @@ -59,6 +60,7 @@ proc newDocumentor*(filename: string, config: PStringTable): PDoc = initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex), options.gConfigVars, filename, {roSupportRawDirective}, docgenFindFile, compilerMsgHandler) + result.seenSymbols = newStringTable(modeCaseInsensitive) result.id = 100 proc dispA(dest: var PRope, xml, tex: string, args: openArray[PRope]) = @@ -144,6 +146,23 @@ proc genRecComment(d: PDoc, n: PNode): PRope = else: n.comment = nil +proc getPlainDocstring(n: PNode): string = + ## Gets the plain text docstring of a node non destructively. + ## + ## You need to call this before genRecComment, whose side effects are removal + ## of comments from the tree. The proc will recursively scan and return all + ## the concatenated ``##`` comments of the node. + result = "" + if n == nil: return + if n.comment != nil and startsWith(n.comment, "##"): + result = n.comment + if result.len < 1: + if n.kind notin {nkEmpty..nkNilLit}: + for i in countup(0, len(n)-1): + result = getPlainDocstring(n.sons[i]) + if result.len > 0: return + + proc findDocComment(n: PNode): PNode = if n == nil: return nil if not isNil(n.comment) and startsWith(n.comment, "##"): return n @@ -205,14 +224,111 @@ proc getRstName(n: PNode): PRstNode = internalError(n.info, "getRstName()") result = nil +proc newUniquePlainSymbol(d: PDoc, original: string): string = + ## Returns a new unique plain symbol made up from the original. + ## + ## When a collision is found in the seenSymbols table, new numerical variants + ## with underscore + number will be generated. + if not d.seenSymbols.hasKey(original): + result = original + d.seenSymbols[original] = "" + return + + # Iterate over possible numeric variants of the original name. + var count = 2 + + while true: + result = original & "_" & $count + if not d.seenSymbols.hasKey(result): + d.seenSymbols[result] = "" + break + count += 1 + + +proc complexName(k: TSymKind, n: PNode, baseName: string): string = + ## Builds a complex unique href name for the node. + ## + ## Pass as ``baseName`` the plain symbol obtained from the nodeName. The + ## format of the returned symbol will be ``baseName(.callable type)?,(param + ## type)?(,param type)*``. The callable type part will be added only if the + ## node is not a proc, as those are the common ones. The suffix will be a dot + ## and a single letter representing the type of the callable. The parameter + ## types will be added with a preceeding dash. Return types won't be added. + ## + ## If you modify the output of this proc, please update the anchor generation + ## section of ``doc/docgen.txt``. + result = baseName + case k: + of skProc: result.add(defaultParamSeparator) + of skMacro: result.add(".m" & defaultParamSeparator) + of skMethod: result.add(".e" & defaultParamSeparator) + of skIterator: result.add(".i" & defaultParamSeparator) + of skTemplate: result.add(".t" & defaultParamSeparator) + of skConverter: result.add(".c" & defaultParamSeparator) + else: discard + + if len(n) > paramsPos and n[paramsPos].kind == nkFormalParams: + result.add(renderParamTypes(n[paramsPos])) + + +proc isCallable(n: PNode): bool = + ## Returns true if `n` contains a callable node. + case n.kind + of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, + nkConverterDef: result = true + else: + result = false + + +proc docstringSummary(rstText: string): string = + ## Returns just the first line or a brief chunk of text from a rst string. + ## + ## Most docstrings will contain a one liner summary, so stripping at the + ## first newline is usually fine. If after that the content is still too big, + ## it is stripped at the first comma, colon or dot, usual english sentence + ## separators. + ## + ## No guarantees are made on the size of the output, but it should be small. + ## Also, we hope to not break the rst, but maybe we do. If there is any + ## trimming done, an ellipsis unicode char is added. + const maxDocstringChars = 100 + assert (rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#')) + result = rstText.substr(2).strip + var pos = result.find('\L') + if pos > 0: + result.delete(pos, result.len - 1) + result.add("…") + if pos < maxDocstringChars: + return + # Try to keep trimming at other natural boundaries. + pos = result.find({'.', ',', ':'}) + let last = result.len - 1 + if pos > 0 and pos < last: + result.delete(pos, last) + result.add("…") + + proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = if not isVisible(nameNode): return - var name = toRope(getName(d, nameNode)) + let + name = getName(d, nameNode) + nameRope = name.toRope + plainDocstring = getPlainDocstring(n) # call here before genRecComment! var result: PRope = nil - var literal = "" + var literal, plainName = "" var kind = tkEof var comm = genRecComment(d, n) # call this here for the side-effect! var r: TSrcGen + # Obtain the plain rendered string for hyperlink titles. + initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments, + renderNoPragmas, renderNoProcDefs}) + while true: + getNextTok(r, kind, literal) + if kind == tkEof: + break + plainName.add(literal) + + # Render the HTML hyperlink. initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments}) while true: getNextTok(r, kind, literal) @@ -253,13 +369,47 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}", [toRope(esc(d.target, literal))]) inc(d.id) + let + plainNameRope = toRope(xmltree.escape(plainName.strip)) + cleanPlainSymbol = renderPlainSymbolName(nameNode) + complexSymbol = complexName(k, n, cleanPlainSymbol) + plainSymbolRope = toRope(cleanPlainSymbol) + plainSymbolEncRope = toRope(URLEncode(cleanPlainSymbol)) + itemIDRope = toRope(d.id) + symbolOrId = d.newUniquePlainSymbol(complexSymbol) + symbolOrIdRope = symbolOrId.toRope + symbolOrIdEncRope = URLEncode(symbolOrId).toRope + + var seeSrcRope: PRope = nil + let docItemSeeSrc = getConfigVar("doc.item.seesrc") + if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0: + let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl, + ["path", "line"], [n.info.toFilename.toRope, toRope($n.info.line)]) + dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc, + ["path", "line", "url"], [n.info.toFilename.toRope, + toRope($n.info.line), urlRope])]) + app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"), - ["name", "header", "desc", "itemID"], - [name, result, comm, toRope(d.id)])) + ["name", "header", "desc", "itemID", "header_plain", "itemSym", + "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"], + [nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope, + symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope])) app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"), - ["name", "header", "desc", "itemID"], [ - toRope(getName(d, nameNode, d.splitAfter)), result, comm, toRope(d.id)])) - setIndexTerm(d[], $d.id, getName(d, nameNode)) + ["name", "header", "desc", "itemID", "header_plain", "itemSym", + "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc"], + [toRope(getName(d, nameNode, d.splitAfter)), result, comm, + itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope, + plainSymbolEncRope, symbolOrIdEncRope])) + + # Ironically for types the complexSymbol is *cleaner* than the plainName + # because it doesn't include object fields or documentation comments. So we + # use the plain one for callable elements, and the complex for the rest. + var linkTitle = changeFileExt(extractFilename(d.filename), "") & " : " + if n.isCallable: linkTitle.add(xmltree.escape(plainName.strip)) + else: linkTitle.add(xmltree.escape(complexSymbol.strip)) + + setIndexTerm(d[], symbolOrId, name, linkTitle, + xmltree.escape(plainDocstring.docstringSummary)) proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): PJsonNode = if not isVisible(nameNode): return diff --git a/compiler/hlo.nim b/compiler/hlo.nim index 7982d4aa1..c75d6519f 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -68,7 +68,8 @@ proc hlo(c: PContext, n: PNode): PNode = result = n else: if n.kind in {nkFastAsgn, nkAsgn, nkIdentDefs, nkVarTuple} and - n.sons[0].kind == nkSym and sfGlobal in n.sons[0].sym.flags: + n.sons[0].kind == nkSym and + {sfGlobal, sfPure} * n.sons[0].sym.flags == {sfGlobal, sfPure}: # do not optimize 'var g {.global} = re(...)' again! return n result = applyPatterns(c, n) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 6da156ba6..440468ac4 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -121,14 +121,14 @@ type capturedVars: seq[PSym] # captured variables in this environment deps: seq[TDep] # dependencies up: PEnv - tup: PType + obj: PType - TInnerContext {.final.} = object + TInnerContext = object fn: PSym closureParam: PSym localsToAccess: TIdNodeTable - TOuterContext {.final.} = object + TOuterContext = object fn: PSym # may also be a module! currentEnv: PEnv isIter: bool # first class iterator? @@ -139,8 +139,13 @@ type up: POuterContext closureParam, state, resultSym: PSym # only if isIter - tup: PType # only if isIter + obj: PType # only if isIter +proc createObj(owner: PSym, info: TLineInfo): PType = + result = newType(tyObject, owner) + rawAddSon(result, nil) + incl result.flags, tfFinal + result.n = newNodeI(nkRecList, info) proc getStateType(iter: PSym): PType = var n = newNodeI(nkRange, iter.info) @@ -185,13 +190,14 @@ proc getEnvParam(routine: PSym): PSym = if hidden.kind == nkSym and hidden.sym.name.s == paramName: result = hidden.sym -proc addField(tup: PType, s: PSym) = - var field = newSym(skField, s.name, s.owner, s.info) +proc addField(obj: PType; s: PSym) = + # because of 'gensym' support, we have to mangle the name with its ID. + # This is hacky but the clean solution is much more complex than it looks. + var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info) let t = skipIntLit(s.typ) field.typ = t - field.position = sonsLen(tup) - addSon(tup.n, newSymNode(field)) - rawAddSon(tup, t) + field.position = sonsLen(obj.n) + addSon(obj.n, newSymNode(field)) proc initIterContext(c: POuterContext, iter: PSym) = c.fn = iter @@ -199,25 +205,24 @@ proc initIterContext(c: POuterContext, iter: PSym) = var cp = getEnvParam(iter) if cp == nil: - c.tup = newType(tyTuple, iter) - c.tup.n = newNodeI(nkRecList, iter.info) + c.obj = createObj(iter, iter.info) cp = newSym(skParam, getIdent(paramName), iter, iter.info) incl(cp.flags, sfFromGeneric) cp.typ = newType(tyRef, iter) - rawAddSon(cp.typ, c.tup) + rawAddSon(cp.typ, c.obj) addHiddenParam(iter, cp) c.state = createStateField(iter) - addField(c.tup, c.state) + addField(c.obj, c.state) else: - c.tup = cp.typ.sons[0] - assert c.tup.kind == tyTuple - if c.tup.len > 0: - c.state = c.tup.n[0].sym + c.obj = cp.typ.sons[0] + assert c.obj.kind == tyObject + if c.obj.n.len > 0: + c.state = c.obj.n[0].sym else: c.state = createStateField(iter) - addField(c.tup, c.state) + addField(c.obj, c.state) c.closureParam = cp if iter.typ.sons[0] != nil: @@ -244,8 +249,7 @@ proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv = new(result) result.deps = @[] result.capturedVars = @[] - result.tup = newType(tyTuple, outerProc) - result.tup.n = newNodeI(nkRecList, outerProc.info) + result.obj = createObj(outerProc, outerProc.info) result.up = up result.attachedNode = n @@ -254,28 +258,28 @@ proc addCapturedVar(e: PEnv, v: PSym) = if x == v: return # XXX meh, just add the state field for every closure for now, it's too # hard to figure out if it comes from a closure iterator: - if e.tup.len == 0: addField(e.tup, createStateField(v.owner)) + if e.obj.n.len == 0: addField(e.obj, createStateField(v.owner)) e.capturedVars.add(v) - addField(e.tup, v) + addField(e.obj, v) proc addDep(e, d: PEnv, owner: PSym): PSym = for x, field in items(e.deps): if x == d: return field - var pos = sonsLen(e.tup) + var pos = sonsLen(e.obj.n) result = newSym(skField, getIdent(upName & $pos), owner, owner.info) result.typ = newType(tyRef, owner) result.position = pos - assert d.tup != nil - rawAddSon(result.typ, d.tup) - addField(e.tup, result) + assert d.obj != nil + rawAddSon(result.typ, d.obj) + addField(e.obj, result) e.deps.add((d, result)) proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode = # returns a[].b as a node var deref = newNodeI(nkHiddenDeref, info) deref.typ = a.typ.sons[0] - assert deref.typ.kind == tyTuple - let field = getSymFromList(deref.typ.n, b.name) + assert deref.typ.kind == tyObject + let field = getSymFromList(deref.typ.n, getIdent(b.name.s & $b.id)) assert field != nil, b.name.s addSon(deref, a) result = newNodeI(nkDotExpr, info) @@ -302,11 +306,11 @@ proc addClosureParam(i: PInnerContext, e: PEnv) = cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info) incl(cp.flags, sfFromGeneric) cp.typ = newType(tyRef, i.fn) - rawAddSon(cp.typ, e.tup) + rawAddSon(cp.typ, e.obj) addHiddenParam(i.fn, cp) else: - e.tup = cp.typ.sons[0] - assert e.tup.kind == tyTuple + e.obj = cp.typ.sons[0] + assert e.obj.kind == tyObject i.closureParam = cp #echo "closure param added for ", i.fn.name.s, " ", i.fn.id @@ -357,7 +361,7 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym, access = indirectAccess(access, addDep(e, it, i.fn), info) access = indirectAccess(access, local, info) if o.isIter: - if not containsOrIncl(o.capturedVars, local.id): addField(o.tup, local) + if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local) else: incl(o.capturedVars, local.id) idNodeTablePut(i.localsToAccess, local, access) @@ -543,7 +547,7 @@ proc newClosureCreationVar(o: POuterContext; e: PEnv): PSym = result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info) incl(result.flags, sfShadowed) result.typ = newType(tyRef, o.fn) - result.typ.rawAddSon(e.tup) + result.typ.rawAddSon(e.obj) proc getClosureVar(o: POuterContext; e: PEnv): PSym = if e.createdVar == nil: @@ -669,7 +673,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode = var local = n.sym if o.isIter and interestingIterVar(local) and o.fn.id == local.owner.id: - if not containsOrIncl(o.capturedVars, local.id): addField(o.tup, local) + if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local) return indirectAccess(newSymNode(o.closureParam), local, n.info) var closure = PEnv(idTableGet(o.lambdasToEnv, local)) diff --git a/compiler/nimrod.nimrod.cfg b/compiler/nimrod.nimrod.cfg index cc27d9f36..2c6e6f249 100644 --- a/compiler/nimrod.nimrod.cfg +++ b/compiler/nimrod.nimrod.cfg @@ -20,3 +20,4 @@ import:testability define:useStdoutAsStdmsg cs:partial +#define:useNodeIds diff --git a/compiler/options.nim b/compiler/options.nim index 102ebc386..fa8b77ead 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -100,6 +100,8 @@ var gSelectedGC* = gcRefc # the selected GC searchPaths*, lazyPaths*: TLinkedList outFile*: string = "" + docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \ + # The string uses the formatting variables `path` and `line`. headerFile*: string = "" gVerbosity* = 1 # how verbose the compiler is gNumberOfProcessors*: int # number of processors diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 2d2310914..fa119eba9 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -15,7 +15,7 @@ import type TRenderFlag* = enum renderNone, renderNoBody, renderNoComments, renderDocComments, - renderNoPragmas, renderIds + renderNoPragmas, renderIds, renderNoProcDefs TRenderFlags* = set[TRenderFlag] TRenderTok*{.final.} = object kind*: TTokType @@ -51,10 +51,17 @@ proc isKeyword*(s: string): bool = (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)): result = true -proc renderDefinitionName*(s: PSym): string = +proc renderDefinitionName*(s: PSym, noQuotes = false): string = + ## Returns the definition name of the symbol. + ## + ## If noQuotes is false the symbol may be returned in backticks. This will + ## happen if the name happens to be a keyword or the first character is not + ## part of the SymStartChars set. let x = s.name.s - if x[0] in SymStartChars and not renderer.isKeyword(x): result = x - else: result = '`' & x & '`' + if noQuotes or (x[0] in SymStartChars and not renderer.isKeyword(x)): + result = x + else: + result = '`' & x & '`' const IndentWidth = 2 @@ -1119,22 +1126,22 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = of nkStaticStmt: gstaticStmt(g, n) of nkAsmStmt: gasm(g, n) of nkProcDef: - putWithSpace(g, tkProc, "proc") + if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc") gproc(g, n) of nkConverterDef: - putWithSpace(g, tkConverter, "converter") + if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter") gproc(g, n) of nkMethodDef: - putWithSpace(g, tkMethod, "method") + if renderNoProcDefs notin g.flags: putWithSpace(g, tkMethod, "method") gproc(g, n) of nkIteratorDef: - putWithSpace(g, tkIterator, "iterator") + if renderNoProcDefs notin g.flags: putWithSpace(g, tkIterator, "iterator") gproc(g, n) of nkMacroDef: - putWithSpace(g, tkMacro, "macro") + if renderNoProcDefs notin g.flags: putWithSpace(g, tkMacro, "macro") gproc(g, n) of nkTemplateDef: - putWithSpace(g, tkTemplate, "template") + if renderNoProcDefs notin g.flags: putWithSpace(g, tkTemplate, "template") gproc(g, n) of nkTypeSection: gsection(g, n, emptyContext, tkType, "type") @@ -1336,4 +1343,3 @@ proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) = inc(r.idx) else: kind = tkEof - diff --git a/compiler/sem.nim b/compiler/sem.nim index c35cff027..b34972219 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -161,12 +161,13 @@ proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} = localError(typ.n.info, errXisNoType, typeToString(typ)) proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym -proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode proc isOpImpl(c: PContext, n: PNode): PNode +proc semTemplateExpr(c: PContext, n: PNode, s: PSym, + flags: TExprFlags = {}): PNode proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, - semCheck: bool = true): PNode + flags: TExprFlags = {}): PNode proc symFromType(t: PType, info: TLineInfo): PSym = if t.sym != nil: return t.sym @@ -265,7 +266,8 @@ proc semConstExpr(c: PContext, n: PNode): PNode = include hlo, seminst, semcall -proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = +proc semAfterMacroCall(c: PContext, n: PNode, s: PSym, + flags: TExprFlags): PNode = inc(evalTemplateCounter) if evalTemplateCounter > 100: globalError(s.info, errTemplateInstantiationTooNested) @@ -281,7 +283,7 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = # BUGFIX: we cannot expect a type here, because module aliases would not # work then (see the ``tmodulealias`` test) # semExprWithType(c, result) - result = semExpr(c, result) + result = semExpr(c, result, flags) of tyStmt: result = semStmt(c, result) of tyTypeDesc: @@ -290,14 +292,14 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = result.typ = makeTypeDesc(c, typ) #result = symNodeFromType(c, typ, n.info) else: - result = semExpr(c, result) + result = semExpr(c, result, flags) result = fitNode(c, s.typ.sons[0], result) #GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0])) dec(evalTemplateCounter) c.friendModule = oldFriend -proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, - semCheck: bool = true): PNode = +proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, + flags: TExprFlags = {}): PNode = markUsed(n, sym) if sym == c.p.owner: globalError(n.info, errRecursiveDependencyX, sym.name.s) @@ -306,7 +308,8 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, # c.evalContext = c.createEvalContext(emStatic) result = evalMacroCall(c.module, n, nOrig, sym) - if semCheck: result = semAfterMacroCall(c, result, sym) + if efNoSemCheck notin flags: + result = semAfterMacroCall(c, result, sym, flags) proc forceBool(c: PContext, n: PNode): PNode = result = fitNode(c, getSysType(tyBool), n) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index b46d83a92..4cb5ad38c 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -42,7 +42,7 @@ type TExprFlag* = enum efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType, - efAllowDestructor, efWantValue, efOperand + efAllowDestructor, efWantValue, efOperand, efNoSemCheck TExprFlags* = set[TExprFlag] PContext* = ref TContext diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 1fd9075e8..9b3b2d73e 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -10,11 +10,12 @@ # this module does the semantic checking for expressions # included from sem.nim -proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = +proc semTemplateExpr(c: PContext, n: PNode, s: PSym, + flags: TExprFlags = {}): PNode = markUsed(n, s) pushInfoContext(n.info) result = evalTemplate(n, s, getCurrOwner()) - if semCheck: result = semAfterMacroCall(c, result, s) + if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags) popInfoContext() proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode @@ -95,8 +96,8 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = else: result = newSymNode(s, n.info) else: result = newSymNode(s, n.info) - of skMacro: result = semMacroExpr(c, n, n, s) - of skTemplate: result = semTemplateExpr(c, n, s) + of skMacro: result = semMacroExpr(c, n, n, s, flags) + of skTemplate: result = semTemplateExpr(c, n, s, flags) of skVar, skLet, skResult, skParam, skForVar: markUsed(n, s) # if a proc accesses a global variable, it is not side effect free: @@ -793,8 +794,8 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode = result = n let callee = result.sons[0].sym case callee.kind - of skMacro: result = semMacroExpr(c, result, orig, callee) - of skTemplate: result = semTemplateExpr(c, result, callee) + of skMacro: result = semMacroExpr(c, result, orig, callee, flags) + of skTemplate: result = semTemplateExpr(c, result, callee, flags) else: semFinishOperands(c, result) activate(c, result) @@ -954,8 +955,10 @@ proc readTypeParameter(c: PContext, typ: PType, proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = ## returns nil if it's not a built-in field access checkSonsLen(n, 2) - # early exit for this; see tests/compile/tbindoverload.nim: - if isSymChoice(n.sons[1]): return + # tests/bind/tbindoverload.nim wants an early exit here, but seems to + # work without now. template/tsymchoicefield doesn't like an early exit + # here at all! + #if isSymChoice(n.sons[1]): return var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) if s != nil: @@ -1964,13 +1967,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semDirectOp(c, n, flags) else: var p = fixImmediateParams(n) - result = semMacroExpr(c, p, p, s) + result = semMacroExpr(c, p, p, s, flags) of skTemplate: if sfImmediate notin s.flags: result = semDirectOp(c, n, flags) else: var p = fixImmediateParams(n) - result = semTemplateExpr(c, p, s) + result = semTemplateExpr(c, p, s, flags) of skType: # XXX think about this more (``set`` procs) if n.len == 2: diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 925a80832..caaab2291 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -113,12 +113,18 @@ proc pickMaxInt(n: PNode): BiggestInt = internalError(n.info, "pickMaxInt") proc makeRange(typ: PType, first, last: BiggestInt): PType = - var n = newNode(nkRange) - addSon(n, newIntNode(nkIntLit, min(first, last))) - addSon(n, newIntNode(nkIntLit, max(first, last))) - result = newType(tyRange, typ.owner) - result.n = n - addSonSkipIntLit(result, skipTypes(typ, {tyRange})) + let minA = min(first, last) + let maxA = max(first, last) + let lowerNode = newIntNode(nkIntLit, minA) + if typ.kind == tyInt and minA == maxA: + result = getIntLitType(lowerNode) + else: + var n = newNode(nkRange) + addSon(n, lowerNode) + addSon(n, newIntNode(nkIntLit, maxA)) + result = newType(tyRange, typ.owner) + result.n = n + addSonSkipIntLit(result, skipTypes(typ, {tyRange})) proc makeRangeF(typ: PType, first, last: BiggestFloat): PType = var n = newNode(nkRange) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index ffc1a43b2..da4a2a132 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -47,12 +47,12 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode = of skTemplate: if macroToExpand(s): let n = fixImmediateParams(n) - result = semTemplateExpr(c, n, s, false) + result = semTemplateExpr(c, n, s, {efNoSemCheck}) else: result = symChoice(c, n, s, scOpen) of skMacro: if macroToExpand(s): - result = semMacroExpr(c, n, n, s, false) + result = semMacroExpr(c, n, n, s, {efNoSemCheck}) else: result = symChoice(c, n, s, scOpen) of skGenericParam: @@ -126,14 +126,14 @@ proc semGenericStmt(c: PContext, n: PNode, case s.kind of skMacro: if macroToExpand(s): - result = semMacroExpr(c, n, n, s, false) + result = semMacroExpr(c, n, n, s, {efNoSemCheck}) else: n.sons[0] = symChoice(c, n.sons[0], s, scOption) result = n of skTemplate: if macroToExpand(s): let n = fixImmediateParams(n) - result = semTemplateExpr(c, n, s, false) + result = semTemplateExpr(c, n, s, {efNoSemCheck}) else: n.sons[0] = symChoice(c, n.sons[0], s, scOption) result = n diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index b71198119..ad34eea65 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -138,6 +138,18 @@ proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode = result = semTemplBody(c, n) closeScope(c) +proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode = + result = n + if n.kind == nkIdent: + let s = qualifiedLookUp(c.c, n, {}) + if s != nil: + if s.owner == c.owner and s.kind == skParam: + incl(s.flags, sfUsed) + result = newSymNode(s, n.info) + else: + for i in 0 .. <n.safeLen: + result.sons[i] = onlyReplaceParams(c, n.sons[i]) + proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym = result = newSym(kind, considerAcc(n), c.owner, n.info) incl(result.flags, sfGenSym) @@ -154,7 +166,13 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = of nkPostfix: x = x[1] of nkPragmaExpr: x = x[0] of nkIdent: break - else: illFormedAst(x) + of nkAccQuoted: + # consider: type `T TemplParam` {.inject.} + # it suffices to return to treat it like 'inject': + n = onlyReplaceParams(c, n) + return + else: + illFormedAst(x) let ident = getIdentNode(c, x) if not isTemplParam(c, ident): c.toInject.incl(x.ident.id) @@ -232,18 +250,6 @@ proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind) = for j in countup(0, L-3): addLocalDecl(c, a.sons[j], symKind) -proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode = - result = n - if n.kind == nkIdent: - let s = qualifiedLookUp(c.c, n, {}) - if s != nil: - if s.owner == c.owner and s.kind == skParam: - incl(s.flags, sfUsed) - result = newSymNode(s, n.info) - else: - for i in 0 .. <n.safeLen: - result.sons[i] = onlyReplaceParams(c, n.sons[i]) - proc semPattern(c: PContext, n: PNode): PNode proc semTemplBody(c: var TemplCtx, n: PNode): PNode = result = n @@ -380,7 +386,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = of nkPragma: result = onlyReplaceParams(c, n) else: - # dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam', + # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam', # so we use the generic code for nkDotExpr too if n.kind == nkDotExpr or n.kind == nkAccQuoted: let s = qualifiedLookUp(c.c, n, {}) @@ -533,7 +539,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = elif contains(c.toBind, s.id): result = symChoice(c.c, n, s, scClosed) elif templToExpand(s): - result = semPatternBody(c, semTemplateExpr(c.c, n, s, false)) + result = semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck})) else: discard # we keep the ident unbound for matching instantiated symbols and @@ -578,7 +584,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = if s.owner == c.owner and s.kind == skParam: discard elif contains(c.toBind, s.id): discard elif templToExpand(s): - return semPatternBody(c, semTemplateExpr(c.c, n, s, false)) + return semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck})) if n.kind == nkInfix and n.sons[0].kind == nkIdent: # we interpret `*` and `|` only as pattern operators if they occur in diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index c53dc0f7d..a563cf06c 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -225,8 +225,16 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType = # properly filled-out in semtypinst (see how tyStaticExpr # is handled there). indx = makeRangeWithStaticExpr(c, e) - else: + elif e.kind == nkIdent: indx = e.typ.skipTypes({tyTypeDesc}) + else: + let x = semConstExpr(c, e) + if x.kind in {nkIntLit..nkUInt64Lit}: + indx = makeRangeType(c, 0, x.intVal-1, n.info, + x.typ.skipTypes({tyTypeDesc})) + else: + indx = x.typ.skipTypes({tyTypeDesc}) + #localError(n[1].info, errConstExprExpected) addSonSkipIntLit(result, indx) if indx.kind == tyGenericInst: indx = lastSon(indx) if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index b9fb0c957..b83c27d22 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -668,6 +668,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = isNone else: discard of tyOpenArray, tyVarargs: + # varargs[expr] is special + if f.kind == tyVarargs and f.sons[0].kind == tyExpr: return case a.kind of tyOpenArray, tyVarargs: result = typeRel(c, base(f), base(a)) diff --git a/compiler/transf.nim b/compiler/transf.nim index 7922acbe9..fb5e321b6 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -166,6 +166,7 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode = idNodeTablePut(c.transCon.mapping, it.sons[j].sym, newSymNode(newVar)) defs[j] = newSymNode(newVar).PTransNode assert(it.sons[L-2].kind == nkEmpty) + defs[L-2] = ast.emptyNode.PTransNode defs[L-1] = transform(c, it.sons[L-1]) result[i] = defs diff --git a/compiler/types.nim b/compiler/types.nim index ae31d24de..c80f6ff35 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -385,8 +385,8 @@ proc mutateType(t: PType, iter: TTypeMutator, closure: PObject): PType = proc valueToString(a: PNode): string = case a.kind - of nkCharLit..nkUInt64Lit: result = $(a.intVal) - of nkFloatLit..nkFloat128Lit: result = $(a.floatVal) + of nkCharLit..nkUInt64Lit: result = $a.intVal + of nkFloatLit..nkFloat128Lit: result = $a.floatVal of nkStrLit..nkTripleStrLit: result = a.strVal else: result = "<invalid value>" diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim new file mode 100644 index 000000000..ebb9b7e15 --- /dev/null +++ b/compiler/typesrenderer.nim @@ -0,0 +1,113 @@ +import renderer, strutils, ast, msgs, types + +const defaultParamSeparator* = "," + +proc renderPlainSymbolName*(n: PNode): string = + ## Returns the first non '*' nkIdent node from the tree. + ## + ## Use this on documentation name nodes to extract the *raw* symbol name, + ## without decorations, parameters, or anything. That can be used as the base + ## for the HTML hyperlinks. + result = "" + case n.kind + of nkPostfix: + for i in 0 .. <n.len: + result = renderPlainSymbolName(n[<n.len]) + if result.len > 0: + return + of nkIdent: + if n.ident.s != "*": + result = n.ident.s + of nkSym: + result = n.sym.renderDefinitionName(noQuotes = true) + of nkPragmaExpr: + result = renderPlainSymbolName(n[0]) + of nkAccQuoted: + result = renderPlainSymbolName(n[<n.len]) + else: + internalError(n.info, "renderPlainSymbolName() with " & $n.kind) + assert (not result.isNil) + +proc renderType(n: PNode): string = + ## Returns a string with the node type or the empty string. + case n.kind: + of nkIdent: result = n.ident.s + of nkSym: result = typeToString(n.sym.typ) + of nkVarTy: + assert len(n) == 1 + result = renderType(n[0]) + of nkRefTy: + assert len(n) == 1 + result = "ref." & renderType(n[0]) + of nkPtrTy: + assert len(n) == 1 + result = "ptr." & renderType(n[0]) + of nkProcTy: + assert len(n) > 1 + let params = n[0] + assert params.kind == nkFormalParams + assert len(params) > 0 + result = "proc(" + for i in 1 .. <len(params): result.add(renderType(params[i]) & ',') + result[<len(result)] = ')' + of nkIdentDefs: + assert len(n) >= 3 + let typePos = len(n) - 2 + let typeStr = renderType(n[typePos]) + result = typeStr + for i in 1 .. <typePos: + assert n[i].kind == nkIdent + result.add(',' & typeStr) + of nkTupleTy: + assert len(n) > 0 + result = "tuple[" + for i in 0 .. <len(n): result.add(renderType(n[i]) & ',') + result[<len(result)] = ']' + of nkBracketExpr: + assert len(n) >= 2 + result = renderType(n[0]) & '[' + for i in 1 .. <len(n): result.add(renderType(n[i]) & ',') + result[<len(result)] = ']' + else: result = "" + assert (not result.isNil) + + +proc renderParamTypes(found: var seq[string], n: PNode) = + ## Recursive helper, adds to `found` any types, or keeps diving the AST. + ## + ## The normal `doc` generator doesn't include .typ information, so the + ## function won't render types for parameters with default values. The `doc2` + ## generator does include the information. + case n.kind + of nkFormalParams: + for i in 1 .. <len(n): renderParamTypes(found, n[i]) + of nkIdentDefs: + # These are parameter names + type + default value node. + let typePos = len(n) - 2 + assert typePos > 0 + var typeStr = renderType(n[typePos]) + if typeStr.len < 1: + # Try with the last node, maybe its a default value. + assert n[typePos+1].kind != nkEmpty + let typ = n[typePos+1].typ + if not typ.isNil: typeStr = typeToString(typ, preferExported) + if typeStr.len < 1: + return + for i in 0 .. <typePos: + assert n[i].kind == nkIdent + found.add(typeStr) + else: + internalError(n.info, "renderParamTypes(found,n) with " & $n.kind) + +proc renderParamTypes*(n: PNode, sep = defaultParamSeparator): string = + ## Returns the types contained in `n` joined by `sep`. + ## + ## This proc expects to be passed as `n` the parameters of any callable. The + ## string output is meant for the HTML renderer. If there are no parameters, + ## the empty string is returned. The parameters will be joined by `sep` but + ## other characters may appear too, like ``[]`` or ``|``. + result = "" + var found: seq[string] = @[] + renderParamTypes(found, n) + if found.len > 0: + result = found.join(sep) diff --git a/compiler/vm.nim b/compiler/vm.nim index 0d5386502..fb8749250 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -48,9 +48,17 @@ type # XXX 'break' should perform cleanup actions # What does the C backend do for it? -proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int) = +proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) = if x != nil: - stackTraceAux(c, x.next, x.comesFrom) + if recursionLimit == 0: + var calls = 0 + var x = x + while x != nil: + inc calls + x = x.next + msgWriteln($calls & " calls omitted\n") + return + stackTraceAux(c, x.next, x.comesFrom, recursionLimit-1) var info = c.debug[pc] # we now use the same format as in system/except.nim var s = toFilename(info) @@ -222,13 +230,14 @@ proc pushSafePoint(f: PStackFrame; pc: int) = proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop() -proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: seq[TFullReg]): int = +proc cleanUpOnException(c: PCtx; tos: PStackFrame): + tuple[pc: int, f: PStackFrame] = let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs) var f = tos while true: while f.safePoints.isNil or f.safePoints.len == 0: f = f.next - if f.isNil: return -1 + if f.isNil: return (-1, nil) var pc2 = f.safePoints[f.safePoints.high] var nextExceptOrFinally = -1 @@ -244,13 +253,13 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: seq[TFullReg]): int = c.currentExceptionB = c.currentExceptionA c.currentExceptionA = nil # execute the corresponding handler: - return pc2 + return (pc2, f) inc pc2 if nextExceptOrFinally >= 0: pc2 = nextExceptOrFinally if c.code[pc2].opcode == opcFinally: # execute the corresponding handler, but don't quit walking the stack: - return pc2 + return (pc2, f) # not the right one: discard f.safePoints.pop @@ -495,18 +504,46 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = else: stackTrace(c, tos, pc, errNilAccess) of opcAddInt: decodeBC(rkInt) - regs[ra].intVal = regs[rb].intVal + regs[rc].intVal + let + bVal = regs[rb].intVal + cVal = regs[rc].intVal + sum = bVal +% cVal + if (sum xor bVal) >= 0 or (sum xor cVal) >= 0: + regs[ra].intVal = sum + else: + stackTrace(c, tos, pc, errOverOrUnderflow) of opcAddImmInt: decodeBImm(rkInt) #message(c.debug[pc], warnUser, "came here") #debug regs[rb].node - regs[ra].intVal = regs[rb].intVal + imm + let + bVal = regs[rb].intVal + cVal = imm + sum = bVal +% cVal + if (sum xor bVal) >= 0 or (sum xor cVal) >= 0: + regs[ra].intVal = sum + else: + stackTrace(c, tos, pc, errOverOrUnderflow) of opcSubInt: decodeBC(rkInt) - regs[ra].intVal = regs[rb].intVal - regs[rc].intVal + let + bVal = regs[rb].intVal + cVal = regs[rc].intVal + diff = bVal -% cVal + if (diff xor bVal) >= 0 or (diff xor not cVal) >= 0: + regs[ra].intVal = diff + else: + stackTrace(c, tos, pc, errOverOrUnderflow) of opcSubImmInt: decodeBImm(rkInt) - regs[ra].intVal = regs[rb].intVal - imm + let + bVal = regs[rb].intVal + cVal = imm + diff = bVal -% cVal + if (diff xor bVal) >= 0 or (diff xor not cVal) >= 0: + regs[ra].intVal = diff + else: + stackTrace(c, tos, pc, errOverOrUnderflow) of opcLenSeq: decodeBImm(rkInt) #assert regs[rb].kind == nkBracket @@ -539,7 +576,18 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = regs[ra].intVal = nimsets.cardSet(regs[rb].node) of opcMulInt: decodeBC(rkInt) - regs[ra].intVal = regs[rb].intVal * regs[rc].intVal + let + bVal = regs[rb].intVal + cVal = regs[rc].intVal + product = bVal *% cVal + floatProd = toBiggestFloat(bVal) * toBiggestFloat(cVal) + resAsFloat = toBiggestFloat(product) + if resAsFloat == floatProd: + regs[ra].intVal = product + elif 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd): + regs[ra].intVal = product + else: + stackTrace(c, tos, pc, errOverOrUnderflow) of opcDivInt: decodeBC(rkInt) if regs[rc].intVal == 0: stackTrace(c, tos, pc, errConstantDivisionByZero) @@ -632,7 +680,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcUnaryMinusInt: decodeB(rkInt) assert regs[rb].kind == rkInt - regs[ra].intVal = -regs[rb].intVal + let val = regs[rb].intVal + if val != int64.low: + regs[ra].intVal = -val + else: + stackTrace(c, tos, pc, errOverOrUnderflow) of opcUnaryMinusFloat: decodeB(rkFloat) assert regs[rb].kind == rkFloat @@ -826,19 +878,27 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcFinallyEnd: if c.currentExceptionA != nil: # we are in a cleanup run: - pc = cleanUpOnException(c, tos, regs)-1 - if pc < 0: + let (newPc, newTos) = cleanUpOnException(c, tos) + if newPc-1 < 0: bailOut(c, tos) return + pc = newPc-1 + if tos != newTos: + tos = newTos + move(regs, tos.slots) of opcRaise: let raised = regs[ra].node c.currentExceptionA = raised c.exceptionInstr = pc + let (newPc, newTos) = cleanUpOnException(c, tos) # -1 because of the following 'inc' - pc = cleanUpOnException(c, tos, regs) - 1 - if pc < 0: + if pc-1 < 0: bailOut(c, tos) return + pc = newPc -1 + if tos != newTos: + tos = newTos + move(regs, tos.slots) of opcNew: ensureKind(rkNode) let typ = c.types[instr.regBx - wordExcess] diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 3c0f8dbc9..7c0c3d4f5 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -328,6 +328,7 @@ proc canonValue*(n: PNode): PNode = proc rawGenLiteral(c: PCtx; n: PNode): int = result = c.constants.len + assert(n.kind != nkCall) c.constants.add n.canonValue internalAssert result < 0x7fff @@ -1033,6 +1034,7 @@ proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) = proc setSlot(c: PCtx; v: PSym) = # XXX generate type initialization here? if v.position == 0: + if c.prc.maxSlots == 0: c.prc.maxSlots = 1 v.position = c.prc.maxSlots c.prc.slots[v.position] = (inUse: true, kind: if v.kind == skLet: slotFixedLet else: slotFixedVar) @@ -1285,16 +1287,13 @@ proc genVarSection(c: PCtx; n: PNode) = if s.position == 0: if sfImportc in s.flags: c.importcSym(a.info, s) else: - let sa = if s.ast.isNil: getNullValue(s.typ, a.info) - else: canonValue(s.ast) + let sa = getNullValue(s.typ, a.info) + #if s.ast.isNil: getNullValue(s.typ, a.info) + #else: canonValue(s.ast) + assert sa.kind != nkCall c.globals.add(sa) s.position = c.globals.len - if a.sons[2].kind == nkEmpty: - when false: - withTemp(tmp, s.typ): - c.gABx(a, opcLdNull, tmp, c.genType(s.typ)) - c.gABx(a, whichAsgnOpc(a.sons[0], opcWrGlobal), tmp, s.position) - else: + if a.sons[2].kind != nkEmpty: let tmp = c.genx(a.sons[0], {gfAddrOf}) let val = c.genx(a.sons[2]) c.gABC(a, opcWrDeref, tmp, val) @@ -1502,7 +1501,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = else: localError(n.info, errGenerated, "VM is not allowed to 'cast'") else: - internalError n.info, "too implement " & $n.kind + internalError n.info, "cannot generate VM code for " & n.renderTree proc removeLastEof(c: PCtx) = let last = c.code.len-1 |