diff options
Diffstat (limited to 'compiler')
38 files changed, 492 insertions, 176 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index fecbefd7e..7275aceb1 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -938,7 +938,7 @@ const genericParamsPos* = 2 paramsPos* = 3 pragmasPos* = 4 - optimizedCodePos* = 5 # will be used for exception tracking + miscPos* = 5 # used for undocumented and hacky stuff bodyPos* = 6 # position of body; use rodread.getBody() instead! resultPos* = 7 dispatcherPos* = 8 # caution: if method has no 'result' it can be position 7! @@ -961,6 +961,9 @@ const skMethod, skConverter} var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things +var + gMainPackageId*: int + gMainPackageNotes*: TNoteKinds proc isCallExpr*(n: PNode): bool = result = n.kind in nkCallKinds diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index f892a3128..9f4beda9e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1235,7 +1235,7 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope): Rope = # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we # have to call it here first: let ti = genTypeInfo(p.module, dest) - if tfFinal in dest.flags or (p.module.objHasKidsValid and + if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and tfObjHasKids notin dest.flags): result = "$1.m_type == $2" % [a, ti] else: diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index 2a37257b6..2e77cd2a6 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -107,8 +107,8 @@ proc genMergeInfo*(m: BModule): Rope = writeIntSet(m.typeInfoMarker, s) s.add("labels:") encodeVInt(m.labels, s) - s.add(" hasframe:") - encodeVInt(ord(m.frameDeclared), s) + s.add(" flags:") + encodeVInt(cast[int](m.flags), s) s.add(tnl) s.add("*/") result = s.rope @@ -222,7 +222,8 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) = of "declared": readIntSet(L, m.declaredThings) of "typeInfo": readIntSet(L, m.typeInfoMarker) of "labels": m.labels = decodeVInt(L.buf, L.bufpos) - of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0 + of "flags": + m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0) else: internalError("ccgmerge: unknown key: " & k) when not defined(nimhygiene): diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 988c923c8..61412ad67 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -16,7 +16,7 @@ const # above X strings a hash-switch for strings is generated proc registerGcRoot(p: BProc, v: PSym) = - if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2} and + if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and containsGarbageCollectedRef(v.loc.t): # we register a specialized marked proc here; this has the advantage # that it works out of the box for thread local storage then :-) diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index ab771d240..81af89249 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -18,7 +18,7 @@ proc emulatedThreadVars(): bool = proc accessThreadLocalVar(p: BProc, s: PSym) = if emulatedThreadVars() and not p.threadVarAccessed: p.threadVarAccessed = true - p.module.usesThreadVars = true + incl p.module.flags, usesThreadVars addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", []) add(p.procSec(cpsInit), ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n")) @@ -51,7 +51,7 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) = addf(m.s[cfsVars], " $1;$n", [s.loc.r]) proc generateThreadLocalStorage(m: BModule) = - if nimtv != nil and (m.usesThreadVars or sfMainModule in m.module.flags): + if nimtv != nil and (usesThreadVars in m.flags or sfMainModule in m.module.flags): for t in items(nimtvDeps): discard getTypeDesc(m, t) addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv]) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 700e6d148..6553deb66 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -752,7 +752,7 @@ proc genProcHeader(m: BModule, prc: PSym): Rope = genCLineDir(result, prc.info) # using static is needed for inline procs if lfExportLib in prc.loc.flags: - if m.isHeaderFile: + if isHeaderFile in m.flags: result.add "N_LIB_IMPORT " else: result.add "N_LIB_EXPORT " diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 0a8f89f2e..77be125b6 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -64,8 +64,8 @@ proc isSimpleConst(typ: PType): bool = (t.kind == tyProc and t.callConv == ccClosure) proc useStringh(m: BModule) = - if not m.includesStringh: - m.includesStringh = true + if includesStringh notin m.flags: + incl m.flags, includesStringh discard lists.includeStr(m.headerFiles, "<string.h>") proc useHeader(m: BModule, sym: PSym) = @@ -1011,11 +1011,11 @@ proc genInitCode(m: BModule) = add(prc, m.postInitProc.s(cpsLocals)) add(prc, genSectionEnd(cpsLocals)) - if optStackTrace in m.initProc.options and not m.frameDeclared: + if optStackTrace in m.initProc.options and frameDeclared notin m.flags: # BUT: the generated init code might depend on a current frame, so # declare it nevertheless: - m.frameDeclared = true - if not m.preventStackTrace: + incl m.flags, frameDeclared + if preventStackTrace notin m.flags: var procname = makeCString(m.module.name.s) add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename)) else: @@ -1032,7 +1032,7 @@ proc genInitCode(m: BModule) = add(prc, m.initProc.s(cpsStmts)) add(prc, m.postInitProc.s(cpsStmts)) add(prc, genSectionEnd(cpsStmts)) - if optStackTrace in m.initProc.options and not m.preventStackTrace: + if optStackTrace in m.initProc.options and preventStackTrace notin m.flags: add(prc, deinitFrame(m.initProc)) add(prc, deinitGCFrame(m.initProc)) addf(prc, "}$N$N", []) @@ -1105,7 +1105,7 @@ proc rawNewModule(module: PSym, filename: string): BModule = # no line tracing for the init sections of the system module so that we # don't generate a TFrame which can confuse the stack botton initialization: if sfSystemModule in module.flags: - result.preventStackTrace = true + incl result.flags, preventStackTrace excl(result.preInitProc.options, optStackTrace) excl(result.postInitProc.options, optStackTrace) @@ -1128,9 +1128,11 @@ proc resetModule*(m: BModule) = m.forwardedProcs = @[] m.typeNodesName = getTempName() m.nimTypesName = getTempName() - m.preventStackTrace = sfSystemModule in m.module.flags + if sfSystemModule in m.module.flags: + incl m.flags, preventStackTrace + else: + excl m.flags, preventStackTrace nullify m.s - m.usesThreadVars = false m.typeNodes = 0 m.nimTypes = 0 nullify m.extensionLoaders @@ -1175,7 +1177,7 @@ proc myOpen(module: PSym): PPassContext = let f = if headerFile.len > 0: headerFile else: gProjectFull generatedHeader = rawNewModule(module, changeFileExt(completeCFilePath(f), hExt)) - generatedHeader.isHeaderFile = true + incl generatedHeader.flags, isHeaderFile proc writeHeader(m: BModule) = var result = getCopyright(m.filename) @@ -1307,7 +1309,7 @@ proc myClose(b: PPassContext, n: PNode): PNode = registerModuleToMain(m.module) if sfMainModule in m.module.flags: - m.objHasKidsValid = true + incl m.flags, objHasKidsValid var disp = generateMethodDispatchers() for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym) genMainProc(m) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 187186373..c098902a6 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -92,17 +92,20 @@ type gcFrameType*: Rope # the struct {} we put the GC markers into TTypeSeq* = seq[PType] + + Codegenflag* = enum + preventStackTrace, # true if stack traces need to be prevented + usesThreadVars, # true if the module uses a thread var + frameDeclared, # hack for ROD support so that we don't declare + # a frame var twice in an init proc + isHeaderFile, # C source file is the header file + includesStringh, # C source file already includes ``<string.h>`` + objHasKidsValid # whether we can rely on tfObjHasKids TCGen = object of TPassContext # represents a C source file module*: PSym filename*: string s*: TCFileSections # sections of the C file - preventStackTrace*: bool # true if stack traces need to be prevented - usesThreadVars*: bool # true if the module uses a thread var - frameDeclared*: bool # hack for ROD support so that we don't declare - # a frame var twice in an init proc - isHeaderFile*: bool # C source file is the header file - includesStringh*: bool # C source file already includes ``<string.h>`` - objHasKidsValid*: bool # whether we can rely on tfObjHasKids + flags*: set[Codegenflag] cfilename*: string # filename of the module (including path, # without extension) typeCache*: TIdTable # cache the generated types diff --git a/compiler/commands.nim b/compiler/commands.nim index aa155ea88..3bc0b604a 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -213,6 +213,7 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool = of "size": result = contains(gOptions, optOptimizeSize) of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {} else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg) + of "verbosity": result = $gVerbosity == arg else: invalidCmdLineOption(passCmd1, switch, info) proc testCompileOption*(switch: string, info: TLineInfo): bool = @@ -261,13 +262,7 @@ proc processPath(path: string, info: TLineInfo, else: options.gProjectPath / path try: - result = unixToNativePath(p % ["nimrod", getPrefixDir(), - "nim", getPrefixDir(), - "lib", libpath, - "home", removeTrailingDirSep(os.getHomeDir()), - "config", info.toFullPath().splitFile().dir, - "projectname", options.gProjectName, - "projectpath", options.gProjectPath]) + result = pathSubs(p, info.toFullPath().splitFile().dir) except ValueError: localError(info, "invalid path: " & p) result = p @@ -321,6 +316,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = of "nonimblepath", "nobabelpath": expectNoArg(switch, arg, pass, info) options.gNoNimblePath = true + options.lazyPaths.head = nil + options.lazyPaths.tail = nil + options.lazyPaths.counter = 0 of "excludepath": expectArg(switch, arg, pass, info) let path = processPath(arg, info) diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index a5a132005..e136265da 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -59,7 +59,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = evalTemplateAux(templ.sons[i], actual, c, res) result.add res -proc evalTemplateArgs(n: PNode, s: PSym): PNode = +proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = # if the template has zero arguments, it can be called without ``()`` # `n` is then a nkSym or something similar var totalParams = case n.kind @@ -75,7 +75,7 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode = # their bodies. We could try to fix this, but it may be # wiser to just deprecate immediate templates and macros # now that we have working untyped parameters. - genericParams = if sfImmediate in s.flags: 0 + genericParams = if sfImmediate in s.flags or fromHlo: 0 else: s.ast[genericParamsPos].len expectedRegularParams = <s.typ.len givenRegularParams = totalParams - genericParams @@ -104,14 +104,14 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode = var evalTemplateCounter* = 0 # to prevent endless recursion in templates instantiation -proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode = +proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode = inc(evalTemplateCounter) if evalTemplateCounter > 100: globalError(n.info, errTemplateInstantiationTooNested) result = n # replace each param by the corresponding node: - var args = evalTemplateArgs(n, tmpl) + var args = evalTemplateArgs(n, tmpl, fromHlo) var ctx: TemplCtx ctx.owner = tmpl ctx.genSymOwner = genSymOwner diff --git a/compiler/hlo.nim b/compiler/hlo.nim index 6cc9567af..de0fa6216 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -24,7 +24,7 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode = of skMacro: result = semMacroExpr(c, n, orig, s) of skTemplate: - result = semTemplateExpr(c, n, s) + result = semTemplateExpr(c, n, s, {efFromHlo}) else: result = semDirectOp(c, n, {}) if optHints in gOptions and hintPattern in gNotes: diff --git a/compiler/importer.nim b/compiler/importer.nim index 86993358b..5ffe12728 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -22,7 +22,11 @@ proc getModuleName*(n: PNode): string = # The proc won't perform any checks that the path is actually valid case n.kind of nkStrLit, nkRStrLit, nkTripleStrLit: - result = unixToNativePath(n.strVal) + try: + result = pathSubs(n.strVal, n.info.toFullPath().splitFile().dir) + except ValueError: + localError(n.info, "invalid path: " & n.strVal) + result = n.strVal of nkIdent: result = n.ident.s of nkSym: diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 964752c16..124459306 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -71,7 +71,7 @@ type isLoop: bool # whether it's a 'block' or 'while' TGlobals = object - typeInfo, code: Rope + typeInfo, constants, code: Rope forwarded: seq[PSym] generatedSyms: IntSet typeInfoGenerated: IntSet @@ -237,7 +237,7 @@ proc useMagic(p: PProc, name: string) = internalAssert s.kind in {skProc, skMethod, skConverter} if not p.g.generatedSyms.containsOrIncl(s.id): let code = genProc(p, s) - add(p.g.code, code) + add(p.g.constants, code) else: # we used to exclude the system module from this check, but for DLL # generation support this sloppyness leads to hard to detect bugs, so @@ -1461,7 +1461,7 @@ proc genConstant(p: PProc, c: PSym) = p.body = nil #genLineDir(p, c.ast) genVarInit(p, c, c.ast) - add(p.g.code, p.body) + add(p.g.constants, p.body) p.body = oldBody proc genNew(p: PProc, n: PNode) = @@ -2137,7 +2137,7 @@ proc wholeCode*(m: BModule): Rope = var p = newProc(globals, m, nil, m.module.options) attachProc(p, prc) - result = globals.typeInfo & globals.code + result = globals.typeInfo & globals.constants & globals.code proc getClassName(t: PType): Rope = var s = t.sym diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 0a4c01ba8..8b201431e 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -138,6 +138,8 @@ proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} = proc isKeyword*(kind: TTokType): bool = result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh) +template ones(n: expr): expr = ((1 shl n)-1) # for utf-8 conversion + proc isNimIdentifier*(s: string): bool = if s[0] in SymStartChars: var i = 1 @@ -589,12 +591,29 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) = of '\\': add(tok.literal, '\\') inc(L.bufpos) - of 'x', 'X': + of 'x', 'X', 'u', 'U': + var tp = L.buf[L.bufpos] inc(L.bufpos) var xi = 0 handleHexChar(L, xi) handleHexChar(L, xi) - add(tok.literal, chr(xi)) + if tp in {'u', 'U'}: + handleHexChar(L, xi) + handleHexChar(L, xi) + # inlined toUTF-8 to avoid unicode and strutils dependencies. + if xi <=% 127: + add(tok.literal, xi.char ) + elif xi <=% 0x07FF: + add(tok.literal, ((xi shr 6) or 0b110_00000).char ) + add(tok.literal, ((xi and ones(6)) or 0b10_0000_00).char ) + elif xi <=% 0xFFFF: + add(tok.literal, (xi shr 12 or 0b1110_0000).char ) + add(tok.literal, (xi shr 6 and ones(6) or 0b10_0000_00).char ) + add(tok.literal, (xi and ones(6) or 0b10_0000_00).char ) + else: # value is 0xFFFF + add(tok.literal, "\xef\xbf\xbf" ) + else: + add(tok.literal, chr(xi)) of '0'..'9': if matchTwoChars(L, '0', {'0'..'9'}): lexMessage(L, warnOctalEscape) diff --git a/compiler/main.nim b/compiler/main.nim index ece21a817..b1b9006bd 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -41,6 +41,7 @@ proc commandGenDepend = proc commandCheck = msgs.gErrorMax = high(int) # do not stop after first error + defineSymbol("nimcheck") semanticPasses() # use an empty backend for semantic checking only rodPass() compileProject() @@ -241,7 +242,7 @@ proc mainCommand* = clearPasses() gLastCmdTime = epochTime() appendStr(searchPaths, options.libpath) - if gProjectFull.len != 0: + when false: # gProjectFull.len != 0: # current path is always looked first for modules prependStr(searchPaths, gProjectPath) setId(100) diff --git a/compiler/modules.nim b/compiler/modules.nim index ef727e200..8ac964321 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -156,6 +156,9 @@ proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym = #var rd = handleSymbolFile(result) var rd: PRodReader result.flags = result.flags + flags + if sfMainModule in result.flags: + gMainPackageId = result.owner.id + if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}: rd = handleSymbolFile(result) if result.id < 0: @@ -183,6 +186,9 @@ proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} = if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx) if sfSystemModule in result.flags: localError(result.info, errAttemptToRedefine, result.name.s) + # restore the notes for outer module: + gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes + else: ForeignPackageNotes proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} = result = syntaxes.parseFile(fileIdx) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index a556ad0c5..668d43bb3 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -500,12 +500,14 @@ type ESuggestDone* = object of Exception const + ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic, + hintQuitCalled} NotesVerbosity*: array[0..3, TNoteKinds] = [ {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit, warnProveField, warnProveIndex, warnGcUnsafe, hintSuccessX, hintPath, hintConf, - hintProcessing, + hintProcessing, hintPattern, hintDependency, hintExecuting, hintLinking, hintCodeBegin, hintCodeEnd, diff --git a/compiler/nim.cfg b/compiler/nim.cfg index 4f9962ea8..0ff128ba3 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -7,7 +7,7 @@ path:"$projectPath/.." path:"$lib/packages/docutils" define:booting -import:testability +#import:"$projectpath/testability" @if windows: cincludes: "$lib/wrappers/libffi/common" diff --git a/compiler/nim.nim b/compiler/nim.nim index b242052ec..a58afd593 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -56,12 +56,12 @@ proc handleCmdLine() = loadConfigs(DefaultConfig) # load all config files let scriptFile = gProjectFull.changeFileExt("nims") if fileExists(scriptFile): - runNimScript(scriptFile) + runNimScript(scriptFile, freshDefines=false) # 'nim foo.nims' means to just run the NimScript file and do nothing more: if scriptFile == gProjectFull: return elif fileExists(gProjectPath / "config.nims"): # directory wide NimScript file - runNimScript(gProjectPath / "config.nims") + runNimScript(gProjectPath / "config.nims", freshDefines=false) # now process command line arguments again, because some options in the # command line can overwite the config file's settings extccomp.initVars() diff --git a/compiler/options.nim b/compiler/options.nim index 2716a98d3..3ef6c6c46 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -242,6 +242,21 @@ proc getNimcacheDir*: string = result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir / genSubDir + +proc pathSubs*(p, config: string): string = + let home = removeTrailingDirSep(os.getHomeDir()) + result = unixToNativePath(p % [ + "nim", getPrefixDir(), + "lib", libpath, + "home", home, + "config", config, + "projectname", options.gProjectName, + "projectpath", options.gProjectPath, + "projectdir", options.gProjectPath, + "nimcache", getNimcacheDir()]) + if '~' in result: + result = result.replace("~", home) + template newPackageCache(): expr = newStringTable(when FileSystemCaseSensitive: modeCaseInsensitive diff --git a/compiler/parser.nim b/compiler/parser.nim index 1ba59b938..6132216e1 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -964,8 +964,9 @@ proc parseDoBlock(p: var TParser): PNode = proc parseDoBlocks(p: var TParser, call: PNode) = #| doBlocks = doBlock ^* IND{=} if p.tok.tokType == tkDo: - addSon(call, parseDoBlock(p)) - while sameInd(p) and p.tok.tokType == tkDo: + #withInd(p): + # addSon(call, parseDoBlock(p)) + while sameOrNoInd(p) and p.tok.tokType == tkDo: addSon(call, parseDoBlock(p)) proc parseProcExpr(p: var TParser, isExpr: bool): PNode = diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 38d17eb62..dc618d9aa 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -277,6 +277,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) = 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.len == 2) and (n.sons[0].sons[1].kind == nkIdent) and (n.sons[0].sons[0].kind == nkIdent): #and (n.sons[1].kind == nkIdent): @@ -392,21 +393,23 @@ type TLinkFeature = enum linkNormal, linkSys -proc processCompile(c: PContext, n: PNode) = +proc relativeFile(c: PContext; n: PNode; ext=""): string = var s = expectStrLit(c, n) - var found = findFile(s) - if found == "": found = s - var trunc = changeFileExt(found, "") - if not isAbsolute(found): - found = parentDir(n.info.toFullPath) / found + if ext.len > 0 and splitFile(s).ext == "": + s = addFileExt(s, ext) + result = parentDir(n.info.toFullPath) / s + if not fileExists(result): + if isAbsolute(s): result = s + else: result = findFile(s) + +proc processCompile(c: PContext, n: PNode) = + let found = relativeFile(c, n) + let trunc = found.changeFileExt("") extccomp.addExternalFileToCompile(found) extccomp.addFileToLink(completeCFilePath(trunc, false)) proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) = - var f = expectStrLit(c, n) - if splitFile(f).ext == "": f = addFileExt(f, CC[cCompiler].objExt) - var found = findFile(f) - if found == "": found = f # use the default + let found = relativeFile(c, n, CC[cCompiler].objExt) case feature of linkNormal: extccomp.addFileToLink(found) of linkSys: diff --git a/compiler/renderer.nim b/compiler/renderer.nim index f0ee137e9..e1db327f4 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -712,7 +712,11 @@ proc gproc(g: var TSrcGen, n: PNode) = gpattern(g, n.sons[patternPos]) let oldCheckAnon = g.checkAnon g.checkAnon = true - gsub(g, n.sons[genericParamsPos]) + if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and + n[miscPos][1].kind != nkEmpty: + gsub(g, n[miscPos][1]) + else: + gsub(g, n.sons[genericParamsPos]) g.checkAnon = oldCheckAnon gsub(g, n.sons[paramsPos]) gsub(g, n.sons[pragmasPos]) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 22cd282fd..d04fd5231 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -118,10 +118,10 @@ proc setupVM*(module: PSym; scriptName: string): PEvalContext = processSwitch(a.getString 0, a.getString 1, passPP, unknownLineInfo()) -proc runNimScript*(scriptName: string) = +proc runNimScript*(scriptName: string; freshDefines=true) = passes.gIncludeFile = includeModule passes.gImportModule = importModule - initDefines() + if freshDefines: initDefines() defineSymbol("nimscript") defineSymbol("nimconfig") diff --git a/compiler/sem.nim b/compiler/sem.nim index c29cbe384..a8ec2229f 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -354,7 +354,6 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, #if c.evalContext == nil: # c.evalContext = c.createEvalContext(emStatic) - result = evalMacroCall(c.module, n, nOrig, sym) if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, sym, flags) @@ -414,6 +413,12 @@ proc myOpen(module: PSym): PPassContext = c.importTable.addSym magicsys.systemModule # import the "System" identifier importAllSymbols(c, magicsys.systemModule) c.topLevelScope = openScope(c) + # don't be verbose unless the module belongs to the main package: + if module.owner.id == gMainPackageId: + gNotes = gMainPackageNotes + else: + if gMainPackageNotes == {}: gMainPackageNotes = gNotes + gNotes = ForeignPackageNotes result = c proc myOpenCached(module: PSym, rd: PRodReader): PPassContext = diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 17dd39595..65aa5fd58 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -129,7 +129,11 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = add(result, ')') var candidates = "" for err in errors: - add(candidates, err.getProcHeader(prefer)) + if err.kind in routineKinds and err.ast != nil: + add(candidates, renderTree(err.ast, + {renderNoBody, renderNoComments,renderNoPragmas})) + else: + add(candidates, err.getProcHeader(prefer)) add(candidates, "\n") if candidates != "": add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index a13f2c232..91a1ebf86 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -47,7 +47,7 @@ type efLValue, efWantIterator, efInTypeof, efWantStmt, efAllowStmt, efDetermineType, efAllowDestructor, efWantValue, efOperand, efNoSemCheck, - efNoProcvarCheck + efNoProcvarCheck, efNoEvaluateGeneric, efInCall, efFromHlo TExprFlags* = set[TExprFlag] TTypeAttachedOp* = enum diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5aac1c2ac..57fb3ceed 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -15,7 +15,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, markUsed(n.info, s) styleCheckUse(n.info, s) pushInfoContext(n.info) - result = evalTemplate(n, s, getCurrOwner()) + result = evalTemplate(n, s, getCurrOwner(), efFromHlo in flags) if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags) popInfoContext() @@ -717,6 +717,34 @@ proc resolveIndirectCall(c: PContext; n, nOrig: PNode; initCandidate(c, result, t) matches(c, n, nOrig, result) +proc bracketedMacro(n: PNode): PSym = + if n.len >= 1 and n[0].kind == nkSym: + result = n[0].sym + if result.kind notin {skMacro, skTemplate}: + result = nil + +proc semBracketedMacro(c: PContext; outer, inner: PNode; s: PSym; + flags: TExprFlags): PNode = + # We received untransformed bracket expression coming from macroOrTmpl[]. + # Transform it to macro or template call, where first come normal + # arguments, next come generic template arguments. + var sons = newSeq[PNode]() + sons.add inner.sons[0] + # Normal arguments: + for i in 1..<outer.len: + sons.add outer.sons[i] + # Generic template arguments from bracket expression: + for i in 1..<inner.len: + sons.add inner.sons[i] + shallowCopy(outer.sons, sons) + # FIXME: Shouldn't we check sfImmediate and call semDirectOp? + # However passing to semDirectOp doesn't work here. + case s.kind + of skMacro: result = semMacroExpr(c, outer, outer, s, flags) + of skTemplate: result = semTemplateExpr(c, outer, s, flags) + else: assert(false) + return + proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = result = nil checkMinSonsLen(n, 1) @@ -732,10 +760,15 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i]) return semExpr(c, result, flags) else: - n.sons[0] = semExpr(c, n.sons[0]) + n.sons[0] = semExpr(c, n.sons[0], {efInCall}) let t = n.sons[0].typ if t != nil and t.kind == tyVar: n.sons[0] = newDeref(n.sons[0]) + elif n.sons[0].kind == nkBracketExpr: + let s = bracketedMacro(n.sons[0]) + if s != nil: + return semBracketedMacro(c, n, n.sons[0], s, flags) + let nOrig = n.copyTree semOpAux(c, n) var t: PType = nil @@ -965,8 +998,20 @@ 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, flags) - of skTemplate: result = semTemplateExpr(c, n, s, flags) + of skMacro: + if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0: + markUsed(n.info, s) + styleCheckUse(n.info, s) + result = newSymNode(s, n.info) + else: + result = semMacroExpr(c, n, n, s, flags) + of skTemplate: + if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0: + markUsed(n.info, s) + styleCheckUse(n.info, s) + result = newSymNode(s, n.info) + else: + result = semTemplateExpr(c, n, s, flags) of skParam: markUsed(n.info, s) styleCheckUse(n.info, s) @@ -1193,7 +1238,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = result.add(x[0]) return checkMinSonsLen(n, 2) - n.sons[0] = semExprWithType(c, n.sons[0], {efNoProcvarCheck}) + # make sure we don't evaluate generic macros/templates + n.sons[0] = semExprWithType(c, n.sons[0], + {efNoProcvarCheck, efNoEvaluateGeneric}) let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef}) case arr.kind of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString, @@ -1236,12 +1283,30 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = let s = if n.sons[0].kind == nkSym: n.sons[0].sym elif n[0].kind in nkSymChoices: n.sons[0][0].sym else: nil - if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}: - # type parameters: partial generic specialization - n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s) - result = explicitGenericInstantiation(c, n, s) - elif s != nil and s.kind == skType: - result = symNodeFromType(c, semTypeNode(c, n, nil), n.info) + if s != nil: + case s.kind + of skProc, skMethod, skConverter, skIterator: + # type parameters: partial generic specialization + n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s) + result = explicitGenericInstantiation(c, n, s) + of skMacro, skTemplate: + if efInCall in flags: + # We are processing macroOrTmpl[] in macroOrTmpl[](...) call. + # Return as is, so it can be transformed into complete macro or + # template call in semIndirectOp caller. + result = n + else: + # We are processing macroOrTmpl[] not in call. Transform it to the + # macro or template call with generic arguments here. + n.kind = nkCall + case s.kind + of skMacro: result = semMacroExpr(c, n, n, s, flags) + of skTemplate: result = semTemplateExpr(c, n, s, flags) + else: discard + of skType: + result = symNodeFromType(c, semTypeNode(c, n, nil), n.info) + else: + c.p.bracketExpr = n.sons[0] else: c.p.bracketExpr = n.sons[0] @@ -1818,7 +1883,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = result = nil template setResult(e: expr) = - if semCheck: result = semStmt(c, e) # do not open a new scope! + if semCheck: result = semExpr(c, e) # do not open a new scope! else: result = e # Check if the node is "when nimvm" @@ -1827,6 +1892,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = # else: # ... var whenNimvm = false + var typ = commonTypeBegin if n.sons.len == 2 and n.sons[0].kind == nkElifBranch and n.sons[1].kind == nkElse: let exprNode = n.sons[0].sons[0] @@ -1843,7 +1909,8 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = checkSonsLen(it, 2) if whenNimvm: if semCheck: - it.sons[1] = semStmt(c, it.sons[1]) + it.sons[1] = semExpr(c, it.sons[1]) + typ = commonType(typ, it.sons[1].typ) result = n # when nimvm is not elimited until codegen else: var e = semConstExpr(c, it.sons[0]) @@ -1857,12 +1924,14 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = checkSonsLen(it, 1) if result == nil or whenNimvm: if semCheck: - it.sons[0] = semStmt(c, it.sons[0]) + it.sons[0] = semExpr(c, it.sons[0]) + typ = commonType(typ, it.sons[0].typ) if result == nil: result = it.sons[0] else: illFormedAst(n) if result == nil: result = newNodeI(nkEmpty, n.info) + if whenNimvm: result.typ = typ # The ``when`` statement implements the mechanism for platform dependent # code. Thus we try to ensure here consistent ID allocation after the # ``when`` statement. diff --git a/compiler/semfold.nim b/compiler/semfold.nim index c5a8cc2a2..feea6ce34 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -489,7 +489,7 @@ proc leValueConv(a, b: PNode): bool = of nkCharLit..nkUInt64Lit: case b.kind of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal - of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal) + of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int else: internalError(a.info, "leValueConv") of nkFloatLit..nkFloat128Lit: case b.kind diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 14631a590..e4ac56cd6 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -43,9 +43,11 @@ proc rawHandleSelf(c: PContext; owner: PSym) = if arg.name.id == c.selfName.id: c.p.selfSym = arg arg.flags.incl sfIsSelf - let t = c.p.selfSym.typ.skipTypes(abstractPtrs) - if t.kind == tyObject: + var t = c.p.selfSym.typ.skipTypes(abstractPtrs) + while t.kind == tyObject: addObjFieldsToLocalScope(c, t.n) + if t.sons[0] == nil: break + t = t.sons[0].skipTypes(abstractPtrs) proc pushProcCon*(c: PContext; owner: PSym) = rawPushProcCon(c, owner) diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index 150680af7..6cd5c4a3c 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -12,25 +12,26 @@ import ast, astalgo, msgs, types -proc ithField(n: PNode, field: int): PSym = +proc ithField(n: PNode, field: var int): PSym = result = nil case n.kind of nkRecList: for i in countup(0, sonsLen(n) - 1): - result = ithField(n.sons[i], field-i) + result = ithField(n.sons[i], field) if result != nil: return of nkRecCase: if n.sons[0].kind != nkSym: internalError(n.info, "ithField") - result = ithField(n.sons[0], field-1) + result = ithField(n.sons[0], field) if result != nil: return for i in countup(1, sonsLen(n) - 1): case n.sons[i].kind of nkOfBranch, nkElse: - result = ithField(lastSon(n.sons[i]), field-1) + result = ithField(lastSon(n.sons[i]), field) if result != nil: return else: internalError(n.info, "ithField(record case branch)") of nkSym: if field == 0: result = n.sym + else: dec(field) else: discard proc annotateType*(n: PNode, t: PType) = @@ -39,10 +40,13 @@ proc annotateType*(n: PNode, t: PType) = # to not to skip tyGenericInst case n.kind of nkObjConstr: + let x = t.skipTypes(abstractPtrs) n.typ = t for i in 1 .. <n.len: - let field = x.n.ithField(i - 1) - if field.isNil: globalError n.info, "invalid field at index " & $i + var j = i-1 + let field = x.n.ithField(j) + if field.isNil: + globalError n.info, "invalid field at index " & $i else: internalAssert(n.sons[i].kind == nkExprColonExpr) annotateType(n.sons[i].sons[1], field.typ) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f6bfca955..0b2343c10 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -17,7 +17,8 @@ proc semDiscard(c: PContext, n: PNode): PNode = checkSonsLen(n, 1) if n.sons[0].kind != nkEmpty: n.sons[0] = semExprWithType(c, n.sons[0]) - if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard) + if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone: + localError(n.info, errInvalidDiscard) proc semBreakOrContinue(c: PContext, n: PNode): PNode = result = n @@ -535,7 +536,7 @@ proc semConst(c: PContext, n: PNode): PNode = localError(a.sons[2].info, errConstExprExpected) continue if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit: - localError(a.info, errXisNoType, typeToString(typ)) + localError(a.info, "invalid type for const: " & typeToString(typ)) continue v.typ = typ v.ast = def # no need to copy @@ -781,9 +782,9 @@ proc typeSectionFinalPass(c: PContext, n: PNode) = var x = a[2] while x.kind in {nkStmtList, nkStmtListExpr} and x.len > 0: x = x.lastSon - if x.kind notin {nkObjectTy, nkDistinctTy, nkEnumTy, nkEmpty}: + if x.kind notin {nkObjectTy, nkDistinctTy, nkEnumTy, nkEmpty} and + s.typ.kind notin {tyObject, tyEnum}: # type aliases are hard: - #MessageOut('for type ' + typeToString(s.typ)); var t = semTypeNode(c, x, nil) assert t != nil if t.kind in {tyObject, tyEnum, tyDistinct}: @@ -929,6 +930,17 @@ proc semProcAnnotation(c: PContext, prc: PNode; pragma(c, result[namePos].sym, result[pragmasPos], validPragmas) return +proc setGenericParamsMisc(c: PContext; n: PNode): PNode = + let orig = n.sons[genericParamsPos] + # we keep the original params around for better error messages, see + # issue https://github.com/nim-lang/Nim/issues/1713 + result = semGenericParamList(c, orig) + if n.sons[miscPos].kind == nkEmpty: + n.sons[miscPos] = newTree(nkBracket, ast.emptyNode, orig) + else: + n.sons[miscPos].sons[1] = orig + n.sons[genericParamsPos] = result + proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = # XXX semProcAux should be good enough for this now, we will eventually # remove semLambda @@ -947,8 +959,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = openScope(c) var gp: PNode if n.sons[genericParamsPos].kind != nkEmpty: - n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos]) - gp = n.sons[genericParamsPos] + gp = setGenericParamsMisc(c, n) else: gp = newNodeI(nkGenericParams, n.info) @@ -1170,8 +1181,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, openScope(c) var gp: PNode if n.sons[genericParamsPos].kind != nkEmpty: - n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos]) - gp = n.sons[genericParamsPos] + gp = setGenericParamsMisc(c, n) else: gp = newNodeI(nkGenericParams, n.info) # process parameters: @@ -1250,7 +1260,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, c.p.wasForwarded = proto != nil maybeAddResult(c, s, n) - if sfImportc notin s.flags: + if lfDynamicLib notin s.loc.flags: # no semantic checking for importc: let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) # unfortunately we cannot skip this step when in 'system.compiles' @@ -1330,7 +1340,8 @@ proc finishMethod(c: PContext, s: PSym) = proc semMethod(c: PContext, n: PNode): PNode = if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method") result = semProcAux(c, n, skMethod, methodPragmas) - + # macros can transform methods to nothing: + if namePos >= result.safeLen: return result var s = result.sons[namePos].sym if not isGenericRoutine(s): # why check for the body? bug #2400 has none. Checking for sfForward makes @@ -1345,6 +1356,8 @@ proc semConverterDef(c: PContext, n: PNode): PNode = if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter") checkSonsLen(n, bodyPos + 1) result = semProcAux(c, n, skConverter, converterPragmas) + # macros can transform converters to nothing: + if namePos >= result.safeLen: return result var s = result.sons[namePos].sym var t = s.typ if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter") @@ -1354,6 +1367,8 @@ proc semConverterDef(c: PContext, n: PNode): PNode = proc semMacroDef(c: PContext, n: PNode): PNode = checkSonsLen(n, bodyPos + 1) result = semProcAux(c, n, skMacro, macroPragmas) + # macros can transform macros to nothing: + if namePos >= result.safeLen: return result var s = result.sons[namePos].sym var t = s.typ if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro") diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index ba17cc307..13b283fe5 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -398,15 +398,18 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym = # identifier with visibility if n.kind == nkPostfix: - if sonsLen(n) == 2 and n.sons[0].kind == nkIdent: + if sonsLen(n) == 2: # for gensym'ed identifiers the identifier may already have been # transformed to a symbol and we need to use that here: result = newSymG(kind, n.sons[1], c) - var v = n.sons[0].ident + var v = considerQuotedIdent(n.sons[0]) if sfExported in allowed and v.id == ord(wStar): incl(result.flags, sfExported) else: - localError(n.sons[0].info, errInvalidVisibilityX, v.s) + if not (sfExported in allowed): + localError(n.sons[0].info, errXOnlyAtModuleScope, "export") + else: + localError(n.sons[0].info, errInvalidVisibilityX, renderTree(n[0])) else: illFormedAst(n) else: @@ -1094,10 +1097,14 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = result = instGenericContainer(c, n.info, result, allowMetaTypes = false) -proc semTypeExpr(c: PContext, n: PNode): PType = +proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType = var n = semExprWithType(c, n, {efDetermineType}) if n.typ.kind == tyTypeDesc: result = n.typ.base + # fix types constructed by macros: + if prev != nil and prev.sym != nil and result.sym.isNil: + result.sym = prev.sym + result.sym.typ = result else: localError(n.info, errTypeExpected, n.renderTree) result = errorType(c) @@ -1177,7 +1184,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = else: localError(n.info, errGenerated, "invalid type") elif n[0].kind notin nkIdentKinds: - result = semTypeExpr(c, n) + result = semTypeExpr(c, n, prev) else: let op = considerQuotedIdent(n.sons[0]) if op.id in {ord(wAnd), ord(wOr)} or op.s == "|": @@ -1218,7 +1225,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = let typExpr = semExprWithType(c, n.sons[1], {efInTypeof}) result = typExpr.typ else: - result = semTypeExpr(c, n) + result = semTypeExpr(c, n, prev) of nkWhenStmt: var whenResult = semWhen(c, n, false) if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index ecef11d13..e72db45e7 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -242,6 +242,8 @@ proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string = for i in 1 .. <arg.len: result.add(" | ") result.add typeToString(arg[i].typ, prefer) + elif arg.typ == nil: + result = "void" else: result = arg.typ.typeToString(prefer) @@ -253,15 +255,15 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1; if n.sons[i].kind == nkExprEqExpr: add(result, renderTree(n.sons[i].sons[0])) add(result, ": ") - if arg.typ.isNil: + if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}: arg = c.semOperand(c, n.sons[i].sons[1]) n.sons[i].typ = arg.typ n.sons[i].sons[1] = arg else: - if arg.typ.isNil: + if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}: arg = c.semOperand(c, n.sons[i]) n.sons[i] = arg - if arg.typ.kind == tyError: return + if arg.typ != nil and arg.typ.kind == tyError: return add(result, argTypeToString(arg, prefer)) if i != sonsLen(n) - 1: add(result, ", ") diff --git a/compiler/vm.nim b/compiler/vm.nim index f799334d6..f275b7b9b 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1185,19 +1185,35 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcNGetType: let rb = instr.regB let rc = instr.regC - if rc == 0: + case rc: + of 0: + # getType opcode: ensureKind(rkNode) if regs[rb].kind == rkNode and regs[rb].node.typ != nil: regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc]) else: stackTrace(c, tos, pc, errGenerated, "node has no type") - else: + of 1: # typeKind opcode: ensureKind(rkInt) if regs[rb].kind == rkNode and regs[rb].node.typ != nil: regs[ra].intVal = ord(regs[rb].node.typ.kind) #else: # stackTrace(c, tos, pc, errGenerated, "node has no type") + of 2: + # getTypeInst opcode: + ensureKind(rkNode) + if regs[rb].kind == rkNode and regs[rb].node.typ != nil: + regs[ra].node = opMapTypeInstToAst(regs[rb].node.typ, c.debug[pc]) + else: + stackTrace(c, tos, pc, errGenerated, "node has no type") + else: + # getTypeImpl opcode: + ensureKind(rkNode) + if regs[rb].kind == rkNode and regs[rb].node.typ != nil: + regs[ra].node = opMapTypeImplToAst(regs[rb].node.typ, c.debug[pc]) + else: + stackTrace(c, tos, pc, errGenerated, "node has no type") of opcNStrVal: decodeB(rkNode) createStr regs[ra] diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index a4f02092d..678a765f4 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -import ast, types, msgs, osproc, streams, options, idents, securehash +import ast, types, msgs, os, osproc, streams, options, idents, securehash proc readOutput(p: Process): string = result = "" @@ -51,7 +51,9 @@ proc opGorge*(cmd, input, cache: string): string = proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = try: - let filename = file.findFile + var filename = parentDir(info.toFullPath) / file + if not fileExists(filename): + filename = file.findFile result = readFile(filename) # we produce a fake include statement for every slurped filename, so that # the module dependencies are accurate: @@ -67,9 +69,11 @@ proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode = result = newSymNode(sym) result.typ = t -proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode +proc mapTypeToAstX(t: PType; info: TLineInfo; + inst=false; allowRecursionX=false): PNode -proc mapTypeToBracket(name: string; t: PType; info: TLineInfo): PNode = +proc mapTypeToBracketX(name: string; t: PType; info: TLineInfo; + inst=false): PNode = result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) result.add atomicTypeX(name, t, info) for i in 0 .. < t.len: @@ -78,10 +82,39 @@ proc mapTypeToBracket(name: string; t: PType; info: TLineInfo): PNode = void.typ = newType(tyEmpty, t.owner) result.add void else: - result.add mapTypeToAst(t.sons[i], info) + result.add mapTypeToAstX(t.sons[i], info, inst) -proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode = +proc mapTypeToAstX(t: PType; info: TLineInfo; + inst=false; allowRecursionX=false): PNode = + var allowRecursion = allowRecursionX template atomicType(name): expr = atomicTypeX(name, t, info) + template mapTypeToAst(t,info): expr = mapTypeToAstX(t, info, inst) + template mapTypeToAstR(t,info): expr = mapTypeToAstX(t, info, inst, true) + template mapTypeToAst(t,i,info): expr = + if i<t.len and t.sons[i]!=nil: mapTypeToAstX(t.sons[i], info, inst) + else: ast.emptyNode + template mapTypeToBracket(name,t,info): expr = + mapTypeToBracketX(name, t, info, inst) + template newNodeX(kind):expr = + newNodeIT(kind, if t.n.isNil: info else: t.n.info, t) + template newIdent(s):expr = + var r = newNodeX(nkIdent) + r.add !s + r + template newIdentDefs(n,t):expr = + var id = newNodeX(nkIdentDefs) + id.add n # name + id.add mapTypeToAst(t, info) # type + id.add ast.emptyNode # no assigned value + id + template newIdentDefs(s):expr = newIdentDefs(s, s.typ) + + if inst: + if t.sym != nil: # if this node has a symbol + if allowRecursion: # getTypeImpl behavior: turn off recursion + allowRecursion = false + else: # getTypeInst behavior: return symbol + return atomicType(t.sym.name.s) case t.kind of tyNone: result = atomicType("none") @@ -94,7 +127,14 @@ proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode = of tyArrayConstr, tyArray: result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) result.add atomicType("array") - result.add mapTypeToAst(t.sons[0], info) + if inst and t.sons[0].kind == tyRange: + var rng = newNodeX(nkInfix) + rng.add newIdentNode(getIdent(".."), info) + rng.add t.sons[0].n.sons[0].copyTree + rng.add t.sons[0].n.sons[1].copyTree + result.add rng + else: + result.add mapTypeToAst(t.sons[0], info) result.add mapTypeToAst(t.sons[1], info) of tyTypeDesc: if t.base != nil: @@ -107,34 +147,95 @@ proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode = result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) for i in 0 .. < t.len: result.add mapTypeToAst(t.sons[i], info) - of tyGenericInst, tyGenericBody, tyOrdinal, tyUserTypeClassInst: + of tyGenericInst: + if inst: + if allowRecursion: + result = mapTypeToAstR(t.lastSon, info) + else: + result = newNodeX(nkBracketExpr) + result.add mapTypeToAst(t.lastSon, info) + for i in 1 .. < t.len-1: + result.add mapTypeToAst(t.sons[i], info) + else: + result = mapTypeToAst(t.lastSon, info) + of tyGenericBody, tyOrdinal, tyUserTypeClassInst: result = mapTypeToAst(t.lastSon, info) of tyDistinct: - if allowRecursion: - result = mapTypeToBracket("distinct", t, info) + if inst: + result = newNodeX(nkDistinctTy) + result.add mapTypeToAst(t.sons[0], info) else: - result = atomicType(t.sym.name.s) + if allowRecursion or t.sym==nil: + result = mapTypeToBracket("distinct", t, info) + else: + result = atomicType(t.sym.name.s) of tyGenericParam, tyForward: result = atomicType(t.sym.name.s) of tyObject: - if allowRecursion: - result = newNodeIT(nkObjectTy, if t.n.isNil: info else: t.n.info, t) - if t.sons[0] == nil: - result.add ast.emptyNode + if inst: + result = newNodeX(nkObjectTy) + result.add ast.emptyNode # pragmas not reconstructed yet + if t.sons[0]==nil: result.add ast.emptyNode # handle parent object + else: + var nn = newNodeX(nkOfInherit) + nn.add mapTypeToAst(t.sons[0], info) + result.add nn + if t.n.sons.len>0: + var rl = copyNode(t.n) # handle nkRecList + for s in t.n.sons: + rl.add newIdentDefs(s) + result.add rl else: - result.add mapTypeToAst(t.sons[0], info) - result.add copyTree(t.n) + result.add ast.emptyNode else: - result = atomicType(t.sym.name.s) + if allowRecursion or t.sym == nil: + result = newNodeIT(nkObjectTy, if t.n.isNil: info else: t.n.info, t) + result.add ast.emptyNode + if t.sons[0] == nil: + result.add ast.emptyNode + else: + result.add mapTypeToAst(t.sons[0], info) + result.add copyTree(t.n) + else: + result = atomicType(t.sym.name.s) of tyEnum: result = newNodeIT(nkEnumTy, if t.n.isNil: info else: t.n.info, t) result.add copyTree(t.n) - of tyTuple: result = mapTypeToBracket("tuple", t, info) + of tyTuple: + if inst: + result = newNodeX(nkTupleTy) + for s in t.n.sons: + result.add newIdentDefs(s) + else: + result = mapTypeToBracket("tuple", t, info) of tySet: result = mapTypeToBracket("set", t, info) - of tyPtr: result = mapTypeToBracket("ptr", t, info) - of tyRef: result = mapTypeToBracket("ref", t, info) + of tyPtr: + if inst: + result = newNodeX(nkPtrTy) + result.add mapTypeToAst(t.sons[0], info) + else: + result = mapTypeToBracket("ptr", t, info) + of tyRef: + if inst: + result = newNodeX(nkRefTy) + result.add mapTypeToAst(t.sons[0], info) + else: + result = mapTypeToBracket("ref", t, info) of tyVar: result = mapTypeToBracket("var", t, info) of tySequence: result = mapTypeToBracket("seq", t, info) - of tyProc: result = mapTypeToBracket("proc", t, info) + of tyProc: + if inst: + result = newNodeX(nkProcTy) + var fp = newNodeX(nkFormalParams) + if t.sons[0] == nil: + fp.add ast.emptyNode + else: + fp.add mapTypeToAst(t.sons[0], t.n[0].info) + for i in 1..<t.sons.len: + fp.add newIdentDefs(t.n[i], t.sons[i]) + result.add fp + result.add ast.emptyNode # pragmas aren't reconstructed yet + else: + result = mapTypeToBracket("proc", t, info) of tyOpenArray: result = mapTypeToBracket("openArray", t, info) of tyRange: result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) @@ -174,10 +275,24 @@ proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode = of tyNot: result = mapTypeToBracket("not", t, info) of tyAnything: result = atomicType"anything" of tyStatic, tyFromExpr, tyFieldAccessor: - result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) - result.add atomicType("static") - if t.n != nil: - result.add t.n.copyTree + if inst: + if t.n != nil: result = t.n.copyTree + else: result = atomicType "void" + else: + result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) + result.add atomicType "static" + if t.n != nil: + result.add t.n.copyTree proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode = - result = mapTypeToAst(t, info, true) + result = mapTypeToAstX(t, info, false, true) + +# the "Inst" version includes generic parameters in the resulting type tree +# and also tries to look like the corresponding Nim type declaration +proc opMapTypeInstToAst*(t: PType; info: TLineInfo): PNode = + result = mapTypeToAstX(t, info, true, false) + +# the "Impl" version includes generic parameters in the resulting type tree +# and also tries to look like the corresponding Nim type implementation +proc opMapTypeImplToAst*(t: PType; info: TLineInfo): PNode = + result = mapTypeToAstX(t, info, true, true) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index bd32ccc17..675fb2dc2 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -983,7 +983,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mNGetType: let tmp = c.genx(n.sons[1]) if dest < 0: dest = c.getTemp(n.typ) - c.gABC(n, opcNGetType, dest, tmp, if n[0].sym.name.s == "typeKind": 1 else: 0) + let rc = case n[0].sym.name.s: + of "getType": 0 + of "typeKind": 1 + of "getTypeInst": 2 + else: 3 # "getTypeImpl" + c.gABC(n, opcNGetType, dest, tmp, rc) c.freeTemp(tmp) #genUnaryABC(c, n, dest, opcNGetType) of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal) @@ -1882,8 +1887,8 @@ proc optimizeJumps(c: PCtx; start: int) = else: discard proc genProc(c: PCtx; s: PSym): int = - let x = s.ast.sons[optimizedCodePos] - if x.kind == nkEmpty: + var x = s.ast.sons[miscPos] + if x.kind == nkEmpty or x[0].kind == nkEmpty: #if s.name.s == "outterMacro" or s.name.s == "innerProc": # echo "GENERATING CODE FOR ", s.name.s let last = c.code.len-1 @@ -1894,7 +1899,11 @@ proc genProc(c: PCtx; s: PSym): int = c.debug.setLen(last) #c.removeLastEof result = c.code.len+1 # skip the jump instruction - s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result) + if x.kind == nkEmpty: + x = newTree(nkBracket, newIntNode(nkIntLit, result), ast.emptyNode) + else: + x.sons[0] = newIntNode(nkIntLit, result) + s.ast.sons[miscPos] = x # thanks to the jmp we can add top level statements easily and also nest # procs easily: let body = s.getBody @@ -1929,4 +1938,4 @@ proc genProc(c: PCtx; s: PSym): int = c.prc = oldPrc else: c.prc.maxSlots = s.offset - result = x.intVal.int + result = x[0].intVal.int diff --git a/compiler/vmops.nim b/compiler/vmops.nim index e40e05eff..d0b3119e2 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -24,22 +24,27 @@ template osop(op) {.immediate, dirty.} = template systemop(op) {.immediate, dirty.} = registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`) -template wrap1f(op) {.immediate, dirty.} = +template wrap1f_math(op) {.immediate, dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = setResult(a, op(getFloat(a, 0))) mathop op -template wrap2f(op) {.immediate, dirty.} = +template wrap2f_math(op) {.immediate, dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = setResult(a, op(getFloat(a, 0), getFloat(a, 1))) mathop op -template wrap1s(op) {.immediate, dirty.} = +template wrap1s_os(op) {.immediate, dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = setResult(a, op(getString(a, 0))) osop op -template wrap2svoid(op) {.immediate, dirty.} = +template wrap1s_system(op) {.immediate, dirty.} = + proc `op Wrapper`(a: VmArgs) {.nimcall.} = + setResult(a, op(getString(a, 0))) + systemop op + +template wrap2svoid_system(op) {.immediate, dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = op(getString(a, 0), getString(a, 1)) systemop op @@ -55,34 +60,35 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode = newStrNode(nkStrLit, f)) proc registerAdditionalOps*(c: PCtx) = - wrap1f(sqrt) - wrap1f(ln) - wrap1f(log10) - wrap1f(log2) - wrap1f(exp) - wrap1f(round) - wrap1f(arccos) - wrap1f(arcsin) - wrap1f(arctan) - wrap2f(arctan2) - wrap1f(cos) - wrap1f(cosh) - wrap2f(hypot) - wrap1f(sinh) - wrap1f(sin) - wrap1f(tan) - wrap1f(tanh) - wrap2f(pow) - wrap1f(trunc) - wrap1f(floor) - wrap1f(ceil) - wrap2f(fmod) + wrap1f_math(sqrt) + wrap1f_math(ln) + wrap1f_math(log10) + wrap1f_math(log2) + wrap1f_math(exp) + wrap1f_math(round) + wrap1f_math(arccos) + wrap1f_math(arcsin) + wrap1f_math(arctan) + wrap2f_math(arctan2) + wrap1f_math(cos) + wrap1f_math(cosh) + wrap2f_math(hypot) + wrap1f_math(sinh) + wrap1f_math(sin) + wrap1f_math(tan) + wrap1f_math(tanh) + wrap2f_math(pow) + wrap1f_math(trunc) + wrap1f_math(floor) + wrap1f_math(ceil) + wrap2f_math(fmod) - wrap1s(getEnv) - wrap1s(existsEnv) - wrap1s(dirExists) - wrap1s(fileExists) - wrap2svoid(writeFile) + wrap1s_os(getEnv) + wrap1s_os(existsEnv) + wrap1s_os(dirExists) + wrap1s_os(fileExists) + wrap2svoid_system(writeFile) + wrap1s_system(readFile) systemop getCurrentExceptionMsg registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} = setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1))) |