Merge branch 'devel' into coroutines

This commit is contained in:
rku 2015-08-20 17:54:55 +03:00
commit 24ad2cb392
89 changed files with 2829 additions and 1405 deletions

View file

@ -102,7 +102,7 @@ proc assignLabel(b: var TBlock): Rope {.inline.} =
proc blockBody(b: var TBlock): Rope =
result = b.sections[cpsLocals]
if b.frameLen > 0:
result.addf("F.len+=$1;$n", [b.frameLen.rope])
result.addf("FR.len+=$1;$n", [b.frameLen.rope])
result.add(b.sections[cpsInit])
result.add(b.sections[cpsStmts])
@ -123,7 +123,7 @@ proc endBlock(p: BProc) =
~"}$n"
let frameLen = p.blocks[topBlock].frameLen
if frameLen > 0:
blockEnd.addf("F.len-=$1;$n", [frameLen.rope])
blockEnd.addf("FR.len-=$1;$n", [frameLen.rope])
endBlock(p, blockEnd)
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =

View file

@ -375,7 +375,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
var a = "&" & s.loc.r
if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
lineF(p, cpsInit,
"F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
"FR.s[$1].address = (void*)$3; FR.s[$1].typ = $4; FR.s[$1].name = $2;$n",
[p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
genTypeInfo(p.module, s.loc.t)])
inc(p.maxFrameLen)
@ -597,7 +597,7 @@ proc cgsym(m: BModule, name: string): Rope =
of skProc, skMethod, skConverter, skIterators: genProc(m, sym)
of skVar, skResult, skLet: genVarPrototype(m, sym)
of skType: discard getTypeDesc(m, sym.typ)
else: internalError("cgsym: " & name)
else: internalError("cgsym: " & name & ": " & $sym.kind)
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
@ -623,7 +623,7 @@ proc retIsNotVoid(s: PSym): bool =
proc initFrame(p: BProc, procname, filename: Rope): Rope =
discard cgsym(p.module, "nimFrame")
if p.maxFrameLen > 0:
discard cgsym(p.module, "TVarSlot")
discard cgsym(p.module, "VarSlot")
result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
procname, filename, p.maxFrameLen.rope,
p.blocks[0].frameLen.rope)
@ -1017,7 +1017,7 @@ proc genInitCode(m: BModule) =
var procname = makeCString(m.module.name.s)
add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
else:
add(prc, ~"\tTFrame F; F.len = 0;$N")
add(prc, ~"\tTFrame F; FR.len = 0;$N")
add(prc, genSectionStart(cpsInit))
add(prc, m.preInitProc.s(cpsInit))
@ -1329,4 +1329,3 @@ proc cgenWriteModules* =
if generatedHeader != nil: writeHeader(generatedHeader)
const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)

View file

@ -645,7 +645,7 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
proc processArgument*(pass: TCmdLinePass; p: OptParser;
argsCount: var int): bool =
if argsCount == 0:
options.command = p.key
if pass != passCmd2: options.command = p.key
else:
if pass == passCmd1: options.commandArgs.add p.key
if argsCount == 1:

View file

@ -90,3 +90,4 @@ proc initDefines*() =
defineSymbol("nimnode")
defineSymbol("nimnomagic64")
defineSymbol("nimvarargstyped")
defineSymbol("nimtypedescfixed")

View file

@ -25,16 +25,21 @@ proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
if ctx.instLines: result.info = b.info
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
template handleParam(param) =
let x = param
if x.kind == nkArgList:
for y in items(x): result.add(y)
else:
result.add copyTree(x)
case templ.kind
of nkSym:
var s = templ.sym
if s.owner.id == c.owner.id:
if s.kind == skParam and sfGenSym notin s.flags:
let x = actual.sons[s.position]
if x.kind == nkArgList:
for y in items(x): result.add(y)
else:
result.add copyTree(x)
handleParam actual.sons[s.position]
elif s.kind == skGenericParam:
handleParam actual.sons[s.owner.typ.len + s.position - 1]
else:
internalAssert sfGenSym in s.flags
var x = PSym(idTableGet(c.mapping, s))
@ -56,22 +61,45 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
proc evalTemplateArgs(n: PNode, s: PSym): PNode =
# if the template has zero arguments, it can be called without ``()``
# `n` is then a nkSym or something similar
var a: int
case n.kind
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
a = sonsLen(n)
else: a = 0
var f = s.typ.sonsLen
if a > f: globalError(n.info, errWrongNumberOfArguments)
var totalParams = case n.kind
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: <n.len
else: 0
var
# XXX: Since immediate templates are not subjected to the
# standard sigmatching algorithm, they will have a number
# of deficiencies when it comes to generic params:
# Type dependencies between the parameters won't be honoured
# and the bound generic symbols won't be resolvable within
# 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
else: s.ast[genericParamsPos].len
expectedRegularParams = <s.typ.len
givenRegularParams = totalParams - genericParams
if totalParams > expectedRegularParams + genericParams:
globalError(n.info, errWrongNumberOfArguments)
result = newNodeI(nkArgList, n.info)
for i in countup(1, f - 1):
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
if arg == nil or arg.kind == nkEmpty:
for i in 1 .. givenRegularParams:
result.addSon n.sons[i]
# handle parameters with default values, which were
# not supplied by the user
for i in givenRegularParams+1 .. expectedRegularParams:
let default = s.typ.n.sons[i].sym.ast
internalAssert default != nil
if default.kind == nkEmpty:
localError(n.info, errWrongNumberOfArguments)
addSon(result, ast.emptyNode)
else:
addSon(result, arg)
addSon(result, default.copyTree)
# add any generic paramaters
for i in 1 .. genericParams:
result.addSon n.sons[givenRegularParams + i]
var evalTemplateCounter* = 0
# to prevent endless recursion in templates instantiation

View file

@ -6,7 +6,7 @@ Name: "Nim"
Version: "$version"
Platforms: """
windows: i386;amd64
linux: i386;amd64;powerpc64;arm;sparc;mips;powerpc
linux: i386;amd64;powerpc64;arm;sparc;mips;mipsel;powerpc;powerpc64el;arm64
macosx: i386;amd64;powerpc64
solaris: i386;amd64;sparc
freebsd: i386;amd64

View file

@ -729,14 +729,13 @@ proc genBreakStmt(p: PProc, n: PNode) =
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
addf(p.body, "break L$1;$n" | "goto ::L$1::;$n", [rope(p.blocks[idx].id)])
proc genAsmStmt(p: PProc, n: PNode) =
proc genAsmOrEmitStmt(p: PProc, n: PNode) =
genLineDir(p, n)
assert(n.kind == nkAsmStmt)
for i in countup(0, sonsLen(n) - 1):
case n.sons[i].kind
of nkStrLit..nkTripleStrLit: add(p.body, n.sons[i].strVal)
of nkSym: add(p.body, mangleName(n.sons[i].sym))
else: internalError(n.sons[i].info, "jsgen: genAsmStmt()")
else: internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
proc genIf(p: PProc, n: PNode, r: var TCompRes) =
var cond, stmt: TCompRes
@ -1578,6 +1577,12 @@ proc genStmt(p: PProc, n: PNode) =
gen(p, n, r)
if r.res != nil: addf(p.body, "$#;$n", [r.res])
proc genPragma(p: PProc, n: PNode) =
for it in n.sons:
case whichPragma(it)
of wEmit: genAsmOrEmitStmt(p, it.sons[1])
else: discard
proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.typ = etyNone
r.kind = resNone
@ -1677,12 +1682,13 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
if n.sons[0].kind != nkEmpty:
genLineDir(p, n)
gen(p, n.sons[0], r)
of nkAsmStmt: genAsmStmt(p, n)
of nkAsmStmt: genAsmOrEmitStmt(p, n)
of nkTryStmt: genTry(p, n, r)
of nkRaiseStmt: genRaiseStmt(p, n)
of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: discard
nkFromStmt, nkTemplateDef, nkMacroDef: discard
of nkPragma: genPragma(p, n)
of nkProcDef, nkMethodDef, nkConverterDef:
var s = n.sons[namePos].sym
if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:

View file

@ -184,7 +184,7 @@ proc addHiddenParam(routine: PSym, param: PSym) =
var params = routine.ast.sons[paramsPos]
# -1 is correct here as param.position is 0 based but we have at position 0
# some nkEffect node:
param.position = params.len-1
param.position = routine.typ.n.len-1
addSon(params, newSymNode(param))
incl(routine.typ.flags, tfCapturesEnv)
assert sfFromGeneric in param.flags

View file

@ -116,7 +116,7 @@ proc interactivePasses =
#incl(gGlobalOptions, optSafeCode)
#setTarget(osNimrodVM, cpuNimrodVM)
initDefines()
defineSymbol("nimrodvm")
defineSymbol("nimscript")
when hasFFI: defineSymbol("nimffi")
registerPass(verbosePass)
registerPass(semPass)
@ -356,6 +356,7 @@ proc mainCommand* =
gGlobalOptions.incl(optCaasEnabled)
msgs.gErrorMax = high(int) # do not stop after first error
serve(mainCommand)
of "nop": discard
else:
rawMessage(errInvalidCommandX, command)

View file

@ -85,6 +85,15 @@ proc resetAllModules* =
resetPackageCache()
# for m in cgenModules(): echo "CGEN MODULE FOUND"
proc resetAllModulesHard* =
resetPackageCache()
gCompiledModules.setLen 0
gMemCacheData.setLen 0
magicsys.resetSysTypes()
# XXX
#gOwners = @[]
#rangeDestructorProc = nil
proc checkDepMem(fileIdx: int32): TNeedRecompile =
template markDirty =
resetModule(fileIdx)
@ -205,9 +214,8 @@ proc compileProject*(projectFileIdx = -1'i32) =
compileSystemModule()
discard compileModule(projectFile, {sfMainModule})
var stdinModule: PSym
proc makeStdinModule*(): PSym =
if stdinModule == nil:
stdinModule = newModule(fileInfoIdx"stdin")
stdinModule.id = getID()
result = stdinModule
proc makeModule*(filename: string): PSym =
result = newModule(fileInfoIdx filename)
result.id = getID()
proc makeStdinModule*(): PSym = makeModule"stdin"

View file

@ -82,7 +82,7 @@ type
errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,
errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,
errNoReturnTypeDeclared,
errInvalidCommandX, errXOnlyAtModuleScope,
errNoCommand, errInvalidCommandX, errXOnlyAtModuleScope,
errXNeedsParamObjectType,
errTemplateInstantiationTooNested, errInstantiationFrom,
errInvalidIndexValueForTuple, errCommandExpectsFilename,
@ -318,6 +318,7 @@ const
errIteratorNotAllowed: "iterators can only be defined at the module\'s top level",
errXNeedsReturnType: "$1 needs a return type",
errNoReturnTypeDeclared: "no return type declared",
errNoCommand: "no command given",
errInvalidCommandX: "invalid command: \'$1\'",
errXOnlyAtModuleScope: "\'$1\' is only allowed at top level",
errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",

View file

@ -1,7 +1,7 @@
#
#
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -16,7 +16,7 @@ when defined(gcc) and defined(windows):
import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, osproc, platform, main, parseopt, service,
nodejs
nodejs, scriptconfig
when hasTinyCBackend:
import tccgen
@ -54,10 +54,17 @@ proc handleCmdLine() =
else:
gProjectPath = getCurrentDir()
loadConfigs(DefaultConfig) # load all config files
let scriptFile = gProjectFull.changeFileExt("nims")
if fileExists(scriptFile):
runNimScript(scriptFile)
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
if scriptFile == gProjectFull: return
# now process command line arguments again, because some options in the
# command line can overwite the config file's settings
extccomp.initVars()
processCmdLine(passCmd2, "")
if options.command == "":
rawMessage(errNoCommand, command)
mainCommand()
if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics())
#echo(GC_getStatistics())

View file

@ -210,7 +210,7 @@ proc removeTrailingDirSep*(path: string): string =
else:
result = path
proc getGeneratedPath: string =
proc getNimcacheDir*: string =
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
genSubDir
@ -266,7 +266,7 @@ proc toGeneratedFile*(path, ext: string): string =
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
var (head, tail) = splitPath(path)
#if len(head) > 0: head = shortenDir(head & dirSep)
result = joinPath([getGeneratedPath(), changeFileExt(tail, ext)])
result = joinPath([getNimcacheDir(), changeFileExt(tail, ext)])
#echo "toGeneratedFile(", path, ", ", ext, ") = ", result
when noTimeMachine:
@ -294,7 +294,7 @@ when noTimeMachine:
proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
var (head, tail) = splitPath(f)
#if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
var subdir = getGeneratedPath() # / head
var subdir = getNimcacheDir() # / head
if createSubDir:
try:
createDir(subdir)

View file

@ -178,13 +178,14 @@ type
arDiscriminant, # is a discriminant
arStrange # it is a strange beast like 'typedesc[var T]'
proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult =
## 'owner' can be nil!
result = arNone
case n.kind
of nkSym:
# don't list 'skLet' here:
if n.sym.kind in {skVar, skResult, skTemp}:
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet}
else: {skVar, skResult, skTemp}
if n.sym.kind in kinds:
if owner != nil and owner.id == n.sym.owner.id and
sfGlobal notin n.sym.flags:
result = arLocalLValue
@ -200,7 +201,7 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
{tyVar, tyPtr, tyRef}:
result = arLValue
else:
result = isAssignable(owner, n.sons[0])
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
if result != arNone and sfDiscriminant in n.sons[1].sym.flags:
result = arDiscriminant
of nkBracketExpr:
@ -208,23 +209,24 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
{tyVar, tyPtr, tyRef}:
result = arLValue
else:
result = isAssignable(owner, n.sons[0])
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
# Object and tuple conversions are still addressable, so we skip them
# XXX why is 'tyOpenArray' allowed here?
if skipTypes(n.typ, abstractPtrs-{tyTypeDesc}).kind in
{tyOpenArray, tyTuple, tyObject}:
result = isAssignable(owner, n.sons[1])
result = isAssignable(owner, n.sons[1], isUnsafeAddr)
elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct):
# types that are equal modulo distinction preserve l-value:
result = isAssignable(owner, n.sons[1])
result = isAssignable(owner, n.sons[1], isUnsafeAddr)
of nkHiddenDeref, nkDerefExpr, nkHiddenAddr:
result = arLValue
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isAssignable(owner, n.sons[0])
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
of nkCallKinds:
# builtin slice keeps lvalue-ness:
if getMagic(n) == mSlice: result = isAssignable(owner, n.sons[1])
if getMagic(n) == mSlice:
result = isAssignable(owner, n.sons[1], isUnsafeAddr)
else:
discard

View file

@ -158,8 +158,8 @@ type
TSystemCPU* = enum # Also add CPU for in initialization section and
# alias conditionals to condsyms (end of module).
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuArm,
cpuJS, cpuNimrodVM, cpuAVR
cpuPowerpc64el, cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuMipsel,
cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR
type
TEndian* = enum
@ -175,12 +175,15 @@ const
(name: "alpha", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "powerpc", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
(name: "powerpc64", intSize: 64, endian: bigEndian, floatSize: 64,bit: 64),
(name: "powerpc64el", intSize: 64, endian: littleEndian, floatSize: 64,bit: 64),
(name: "sparc", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
(name: "vm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
(name: "ia64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "amd64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
(name: "mipsel", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
(name: "arm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
(name: "arm64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "js", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32),
(name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
(name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16)]

View file

@ -593,280 +593,282 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
validPragmas: TSpecialWords): bool =
var it = n.sons[i]
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
if key.kind == nkIdent:
var userPragma = strTableGet(c.userPragmas, key.ident)
if userPragma != nil:
inc c.instCounter
if c.instCounter > 100:
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
pragma(c, sym, userPragma.ast, validPragmas)
# ensure the pragma is also remember for generic instantiations in other
# modules:
n.sons[i] = userPragma.ast
dec c.instCounter
else:
var k = whichKeyword(key.ident)
if k in validPragmas:
case k
of wExportc:
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
incl(sym.flags, sfUsed) # avoid wrong hints
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
of wImportCompilerProc:
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"))
of wExtern: setExternName(sym, expectStrLit(c, it))
of wImmediate:
if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate)
else: invalidPragma(it)
of wDirty:
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
else: invalidPragma(it)
of wImportCpp:
processImportCpp(sym, getOptionalStr(c, it, "$1"))
of wImportObjC:
processImportObjC(sym, getOptionalStr(c, it, "$1"))
of wAlign:
if sym.typ == nil: invalidPragma(it)
var align = expectIntLit(c, it)
if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
localError(it.info, errPowerOfTwoExpected)
else:
sym.typ.align = align.int16
of wSize:
if sym.typ == nil: invalidPragma(it)
var size = expectIntLit(c, it)
if not isPowerOfTwo(size) or size <= 0 or size > 8:
localError(it.info, errPowerOfTwoExpected)
else:
sym.typ.size = size
of wNodecl:
noVal(it)
incl(sym.loc.flags, lfNoDecl)
of wPure, wAsmNoStackFrame:
noVal(it)
if sym != nil:
if k == wPure and sym.kind in routineKinds: invalidPragma(it)
else: incl(sym.flags, sfPure)
of wVolatile:
noVal(it)
incl(sym.flags, sfVolatile)
of wRegister:
noVal(it)
incl(sym.flags, sfRegister)
of wThreadVar:
noVal(it)
incl(sym.flags, sfThread)
of wDeadCodeElim: pragmaDeadCodeElim(c, it)
of wNoForward: pragmaNoForward(c, it)
of wMagic: processMagic(c, it, sym)
of wCompileTime:
noVal(it)
incl(sym.flags, sfCompileTime)
incl(sym.loc.flags, lfNoDecl)
of wGlobal:
noVal(it)
incl(sym.flags, sfGlobal)
incl(sym.flags, sfPure)
of wMerge:
# only supported for backwards compat, doesn't do anything anymore
noVal(it)
of wConstructor:
noVal(it)
incl(sym.flags, sfConstructor)
of wHeader:
var lib = getLib(c, libHeader, getStrLitNode(c, it))
addToLib(lib, sym)
incl(sym.flags, sfImportc)
incl(sym.loc.flags, lfHeader)
incl(sym.loc.flags, lfNoDecl)
# implies nodecl, because otherwise header would not make sense
if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
of wDestructor:
sym.flags.incl sfOverriden
if sym.name.s.normalize != "destroy":
localError(n.info, errGenerated, "destructor has to be named 'destroy'")
of wOverride:
sym.flags.incl sfOverriden
of wNosideeffect:
noVal(it)
incl(sym.flags, sfNoSideEffect)
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
of wSideeffect:
noVal(it)
incl(sym.flags, sfSideEffect)
of wNoreturn:
noVal(it)
incl(sym.flags, sfNoReturn)
of wDynlib:
processDynLib(c, it, sym)
of wCompilerproc:
noVal(it) # compilerproc may not get a string!
if sfFromGeneric notin sym.flags: markCompilerProc(sym)
of wProcVar:
noVal(it)
incl(sym.flags, sfProcvar)
of wDeprecated:
if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
elif sym != nil: incl(sym.flags, sfDeprecated)
else: incl(c.module.flags, sfDeprecated)
of wVarargs:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfVarargs)
of wBorrow:
if sym.kind == skType:
typeBorrow(sym, it)
else:
noVal(it)
incl(sym.flags, sfBorrow)
of wFinal:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfFinal)
of wInheritable:
noVal(it)
if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it)
else: incl(sym.typ.flags, tfInheritable)
of wAcyclic:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfAcyclic)
of wShallow:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfShallow)
of wThread:
noVal(it)
incl(sym.flags, sfThread)
incl(sym.flags, sfProcvar)
if sym.typ != nil: incl(sym.typ.flags, tfThread)
of wGcSafe:
noVal(it)
if sym.kind != skType: incl(sym.flags, sfThread)
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
else: invalidPragma(it)
of wPacked:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfPacked)
of wHint: message(it.info, hintUser, expectStrLit(c, it))
of wWarning: message(it.info, warnUser, expectStrLit(c, it))
of wError:
if sym != nil and sym.isRoutine:
# This is subtle but correct: the error *statement* is only
# allowed for top level statements. Seems to be easier than
# distinguishing properly between
# ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
noVal(it)
incl(sym.flags, sfError)
else:
localError(it.info, errUser, expectStrLit(c, it))
of wFatal: fatal(it.info, errUser, expectStrLit(c, it))
of wDefine: processDefine(c, it)
of wUndef: processUndef(c, it)
of wCompile: processCompile(c, it)
of wLink: processCommonLink(c, it, linkNormal)
of wLinksys: processCommonLink(c, it, linkSys)
of wPassl: extccomp.addLinkOption(expectStrLit(c, it))
of wPassc: extccomp.addCompileOption(expectStrLit(c, it))
of wBreakpoint: pragmaBreakpoint(c, it)
of wWatchPoint: pragmaWatchpoint(c, it)
of wPush:
processPush(c, n, i + 1)
result = true
of wPop: processPop(c, it)
of wPragma:
processPragma(c, n, i)
result = true
of wDiscardable:
noVal(it)
if sym != nil: incl(sym.flags, sfDiscardable)
of wNoInit:
noVal(it)
if sym != nil: incl(sym.flags, sfNoInit)
of wCodegenDecl: processCodegenDecl(c, it, sym)
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
wLinedir, wStacktrace, wLinetrace, wOptimization,
wCallconv,
wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
wPatterns:
if processOption(c, it):
# calling conventions (boring...):
localError(it.info, errOptionExpected)
of FirstCallConv..LastCallConv:
assert(sym != nil)
if sym.typ == nil: invalidPragma(it)
else: sym.typ.callConv = wordToCallConv(k)
of wEmit: pragmaEmit(c, it)
of wUnroll: pragmaUnroll(c, it)
of wLinearScanEnd, wComputedGoto: noVal(it)
of wEffects:
# is later processed in effect analysis:
noVal(it)
of wIncompleteStruct:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfIncompleteStruct)
of wUnchecked:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfUncheckedArray)
of wUnion:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfUnion)
of wRequiresInit:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfNeedsInit)
of wByRef:
noVal(it)
if sym == nil or sym.typ == nil:
if processOption(c, it): localError(it.info, errOptionExpected)
else:
incl(sym.typ.flags, tfByRef)
of wByCopy:
noVal(it)
if sym.kind != skType or sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfByCopy)
of wInject, wGensym:
# We check for errors, but do nothing with these pragmas otherwise
# as they are handled directly in 'evalTemplate'.
noVal(it)
if sym == nil: invalidPragma(it)
of wLine: pragmaLine(c, it)
of wRaises, wTags: pragmaRaisesOrTags(c, it)
of wLocks:
if sym == nil: pragmaLockStmt(c, it)
elif sym.typ == nil: invalidPragma(it)
else: sym.typ.lockLevel = pragmaLocks(c, it)
of wGuard:
if sym == nil or sym.kind notin {skVar, skLet, skField}:
invalidPragma(it)
else:
sym.guard = pragmaGuard(c, it, sym.kind)
of wGoto:
if sym == nil or sym.kind notin {skVar, skLet}:
invalidPragma(it)
else:
sym.flags.incl sfGoto
of wInjectStmt:
if it.kind != nkExprColonExpr:
localError(it.info, errExprExpected)
else:
it.sons[1] = c.semExpr(c, it.sons[1])
of wExperimental:
noVal(it)
if isTopLevel(c):
c.module.flags.incl sfExperimental
else:
localError(it.info, "'experimental' pragma only valid as toplevel statement")
of wNoRewrite:
noVal(it)
if key.kind == nkBracketExpr:
processNote(c, it)
return
let ident = considerQuotedIdent(key)
var userPragma = strTableGet(c.userPragmas, ident)
if userPragma != nil:
inc c.instCounter
if c.instCounter > 100:
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
pragma(c, sym, userPragma.ast, validPragmas)
# ensure the pragma is also remember for generic instantiations in other
# modules:
n.sons[i] = userPragma.ast
dec c.instCounter
else:
var k = whichKeyword(ident)
if k in validPragmas:
case k
of wExportc:
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
incl(sym.flags, sfUsed) # avoid wrong hints
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
of wImportCompilerProc:
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"))
of wExtern: setExternName(sym, expectStrLit(c, it))
of wImmediate:
if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate)
else: invalidPragma(it)
of wDirty:
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
else: invalidPragma(it)
of wImportCpp:
processImportCpp(sym, getOptionalStr(c, it, "$1"))
of wImportObjC:
processImportObjC(sym, getOptionalStr(c, it, "$1"))
of wAlign:
if sym.typ == nil: invalidPragma(it)
var align = expectIntLit(c, it)
if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
localError(it.info, errPowerOfTwoExpected)
else:
sym.typ.align = align.int16
of wSize:
if sym.typ == nil: invalidPragma(it)
var size = expectIntLit(c, it)
if not isPowerOfTwo(size) or size <= 0 or size > 8:
localError(it.info, errPowerOfTwoExpected)
else:
sym.typ.size = size
of wNodecl:
noVal(it)
incl(sym.loc.flags, lfNoDecl)
of wPure, wAsmNoStackFrame:
noVal(it)
if sym != nil:
if k == wPure and sym.kind in routineKinds: invalidPragma(it)
else: incl(sym.flags, sfPure)
of wVolatile:
noVal(it)
incl(sym.flags, sfVolatile)
of wRegister:
noVal(it)
incl(sym.flags, sfRegister)
of wThreadVar:
noVal(it)
incl(sym.flags, sfThread)
of wDeadCodeElim: pragmaDeadCodeElim(c, it)
of wNoForward: pragmaNoForward(c, it)
of wMagic: processMagic(c, it, sym)
of wCompileTime:
noVal(it)
incl(sym.flags, sfCompileTime)
incl(sym.loc.flags, lfNoDecl)
of wGlobal:
noVal(it)
incl(sym.flags, sfGlobal)
incl(sym.flags, sfPure)
of wMerge:
# only supported for backwards compat, doesn't do anything anymore
noVal(it)
of wConstructor:
noVal(it)
incl(sym.flags, sfConstructor)
of wHeader:
var lib = getLib(c, libHeader, getStrLitNode(c, it))
addToLib(lib, sym)
incl(sym.flags, sfImportc)
incl(sym.loc.flags, lfHeader)
incl(sym.loc.flags, lfNoDecl)
# implies nodecl, because otherwise header would not make sense
if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
of wDestructor:
sym.flags.incl sfOverriden
if sym.name.s.normalize != "destroy":
localError(n.info, errGenerated, "destructor has to be named 'destroy'")
of wOverride:
sym.flags.incl sfOverriden
of wNosideeffect:
noVal(it)
incl(sym.flags, sfNoSideEffect)
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
of wSideeffect:
noVal(it)
incl(sym.flags, sfSideEffect)
of wNoreturn:
noVal(it)
incl(sym.flags, sfNoReturn)
of wDynlib:
processDynLib(c, it, sym)
of wCompilerproc:
noVal(it) # compilerproc may not get a string!
if sfFromGeneric notin sym.flags: markCompilerProc(sym)
of wProcVar:
noVal(it)
incl(sym.flags, sfProcvar)
of wDeprecated:
if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
elif sym != nil: incl(sym.flags, sfDeprecated)
else: incl(c.module.flags, sfDeprecated)
of wVarargs:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfVarargs)
of wBorrow:
if sym.kind == skType:
typeBorrow(sym, it)
else:
noVal(it)
incl(sym.flags, sfBorrow)
of wFinal:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfFinal)
of wInheritable:
noVal(it)
if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it)
else: incl(sym.typ.flags, tfInheritable)
of wAcyclic:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfAcyclic)
of wShallow:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfShallow)
of wThread:
noVal(it)
incl(sym.flags, sfThread)
incl(sym.flags, sfProcvar)
if sym.typ != nil: incl(sym.typ.flags, tfThread)
of wGcSafe:
noVal(it)
if sym.kind != skType: incl(sym.flags, sfThread)
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
else: invalidPragma(it)
of wPacked:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfPacked)
of wHint: message(it.info, hintUser, expectStrLit(c, it))
of wWarning: message(it.info, warnUser, expectStrLit(c, it))
of wError:
if sym != nil and sym.isRoutine:
# This is subtle but correct: the error *statement* is only
# allowed for top level statements. Seems to be easier than
# distinguishing properly between
# ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
noVal(it)
incl(sym.flags, sfError)
else:
localError(it.info, errUser, expectStrLit(c, it))
of wFatal: fatal(it.info, errUser, expectStrLit(c, it))
of wDefine: processDefine(c, it)
of wUndef: processUndef(c, it)
of wCompile: processCompile(c, it)
of wLink: processCommonLink(c, it, linkNormal)
of wLinksys: processCommonLink(c, it, linkSys)
of wPassl: extccomp.addLinkOption(expectStrLit(c, it))
of wPassc: extccomp.addCompileOption(expectStrLit(c, it))
of wBreakpoint: pragmaBreakpoint(c, it)
of wWatchPoint: pragmaWatchpoint(c, it)
of wPush:
processPush(c, n, i + 1)
result = true
of wPop: processPop(c, it)
of wPragma:
processPragma(c, n, i)
result = true
of wDiscardable:
noVal(it)
if sym != nil: incl(sym.flags, sfDiscardable)
of wNoInit:
noVal(it)
if sym != nil: incl(sym.flags, sfNoInit)
of wCodegenDecl: processCodegenDecl(c, it, sym)
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
wLinedir, wStacktrace, wLinetrace, wOptimization,
wCallconv,
wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
wPatterns:
if processOption(c, it):
# calling conventions (boring...):
localError(it.info, errOptionExpected)
of FirstCallConv..LastCallConv:
assert(sym != nil)
if sym.typ == nil: invalidPragma(it)
else: sym.typ.callConv = wordToCallConv(k)
of wEmit: pragmaEmit(c, it)
of wUnroll: pragmaUnroll(c, it)
of wLinearScanEnd, wComputedGoto: noVal(it)
of wEffects:
# is later processed in effect analysis:
noVal(it)
of wIncompleteStruct:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfIncompleteStruct)
of wUnchecked:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfUncheckedArray)
of wUnion:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfUnion)
of wRequiresInit:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfNeedsInit)
of wByRef:
noVal(it)
if sym == nil or sym.typ == nil:
if processOption(c, it): localError(it.info, errOptionExpected)
else:
incl(sym.typ.flags, tfByRef)
of wByCopy:
noVal(it)
if sym.kind != skType or sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfByCopy)
of wInject, wGensym:
# We check for errors, but do nothing with these pragmas otherwise
# as they are handled directly in 'evalTemplate'.
noVal(it)
if sym == nil: invalidPragma(it)
of wLine: pragmaLine(c, it)
of wRaises, wTags: pragmaRaisesOrTags(c, it)
of wLocks:
if sym == nil: pragmaLockStmt(c, it)
elif sym.typ == nil: invalidPragma(it)
else: sym.typ.lockLevel = pragmaLocks(c, it)
of wGuard:
if sym == nil or sym.kind notin {skVar, skLet, skField}:
invalidPragma(it)
else:
sym.guard = pragmaGuard(c, it, sym.kind)
of wGoto:
if sym == nil or sym.kind notin {skVar, skLet}:
invalidPragma(it)
else:
sym.flags.incl sfGoto
of wInjectStmt:
if it.kind != nkExprColonExpr:
localError(it.info, errExprExpected)
else:
it.sons[1] = c.semExpr(c, it.sons[1])
of wExperimental:
noVal(it)
if isTopLevel(c):
c.module.flags.incl sfExperimental
else:
localError(it.info, "'experimental' pragma only valid as toplevel statement")
of wNoRewrite:
noVal(it)
else: invalidPragma(it)
else: processNote(c, it)
else: invalidPragma(it)
proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
validPragmas: TSpecialWords) =

View file

@ -898,6 +898,8 @@ proc getBody*(s: PSym): PNode =
## it may perform an expensive reload operation. Otherwise it's a simple
## accessor.
assert s.kind in routineKinds
# prevent crashes due to incorrect macro transformations (bug #2377)
if s.ast.isNil or bodyPos >= s.ast.len: return ast.emptyNode
result = s.ast.sons[bodyPos]
if result == nil:
assert s.offset != 0

119
compiler/scriptconfig.nim Normal file
View file

@ -0,0 +1,119 @@
#
#
# The Nim Compiler
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Implements the new configuration system for Nim. Uses Nim as a scripting
## language.
import
ast, modules, passes, passaux, condsyms,
options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs,
os, times
# we support 'cmpIgnoreStyle' natively for efficiency:
from strutils import cmpIgnoreStyle
proc listDirs(a: VmArgs, filter: set[PathComponent]) =
let dir = getString(a, 0)
var result: seq[string] = @[]
for kind, path in walkDir(dir):
if kind in filter: result.add path
setResult(a, result)
proc setupVM(module: PSym; scriptName: string): PEvalContext =
result = newCtx(module)
result.mode = emRepl
registerAdditionalOps(result)
# captured vars:
var errorMsg: string
var vthisDir = scriptName.splitFile.dir
template cbconf(name, body) {.dirty.} =
result.registerCallback "stdlib.system." & astToStr(name),
proc (a: VmArgs) =
body
template cbos(name, body) {.dirty.} =
result.registerCallback "stdlib.system." & astToStr(name),
proc (a: VmArgs) =
try:
body
except OSError:
errorMsg = getCurrentExceptionMsg()
# Idea: Treat link to file as a file, but ignore link to directory to prevent
# endless recursions out of the box.
cbos listFiles:
listDirs(a, {pcFile, pcLinkToFile})
cbos listDirs:
listDirs(a, {pcDir})
cbos removeDir:
os.removeDir getString(a, 0)
cbos removeFile:
os.removeFile getString(a, 0)
cbos createDir:
os.createDir getString(a, 0)
cbos getOsError:
setResult(a, errorMsg)
cbos setCurrentDir:
os.setCurrentDir getString(a, 0)
cbos getCurrentDir:
setResult(a, os.getCurrentDir())
cbos moveFile:
os.moveFile(getString(a, 0), getString(a, 1))
cbos getLastModificationTime:
setResult(a, toSeconds(getLastModificationTime(getString(a, 0))))
cbconf thisDir:
setResult(a, vthisDir)
cbconf put:
options.setConfigVar(getString(a, 0), getString(a, 1))
cbconf get:
setResult(a, options.getConfigVar(a.getString 0))
cbconf exists:
setResult(a, options.existsConfigVar(a.getString 0))
cbconf nimcacheDir:
setResult(a, options.getNimcacheDir())
cbconf paramStr:
setResult(a, os.paramStr(int a.getInt 0))
cbconf paramCount:
setResult(a, os.paramCount())
cbconf cmpIgnoreStyle:
setResult(a, strutils.cmpIgnoreStyle(a.getString 0, a.getString 1))
cbconf setCommand:
options.command = a.getString 0
cbconf getCommand:
setResult(a, options.command)
cbconf switch:
processSwitch(a.getString 0, a.getString 1, passPP, unknownLineInfo())
proc runNimScript*(scriptName: string) =
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
initDefines()
defineSymbol("nimscript")
defineSymbol("nimconfig")
registerPass(semPass)
registerPass(evalPass)
appendStr(searchPaths, options.libpath)
var m = makeModule(scriptName)
incl(m.flags, sfMainModule)
vm.globalCtx = setupVM(m, scriptName)
compileSystemModule()
processModule(m, llStreamOpen(scriptName, fmRead), nil)
# ensure we load 'system.nim' again for the real non-config stuff!
resetAllModulesHard()
vm.globalCtx = nil
initDefines()

View file

@ -171,11 +171,15 @@ proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLower
# like newSymS, but considers gensym'ed symbols
if n.kind == nkSym:
# and sfGenSym in n.sym.flags:
result = n.sym
internalAssert result.kind == kind
if result.kind != kind:
localError(n.info, "cannot use symbol of kind '" &
$result.kind & "' as a '" & $kind & "'")
# when there is a nested proc inside a template, semtmpl
# will assign a wrong owner during the first pass over the
# template; we must fix it here: see #909

View file

@ -305,8 +305,22 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
if containsGenericType(result.typ) or x.fauxMatch == tyUnknown:
result.typ = newTypeS(x.fauxMatch, c)
return
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
let gp = finalCallee.ast.sons[genericParamsPos]
if gp.kind != nkEmpty:
if x.calleeSym.kind notin {skMacro, skTemplate}:
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
else:
# For macros and templates, the resolved generic params
# are added as normal params.
for s in instantiateGenericParamList(c, gp, x.bindings):
case s.kind
of skConst:
x.call.add s.ast
of skType:
x.call.add newSymNode(s, n.info)
else:
internalAssert false
result = x.call
instGenericConvertersSons(c, result, x)
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)

View file

@ -177,6 +177,15 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
else:
return nil
proc createDestructorCall(c: PContext, s: PSym): PNode =
let varTyp = s.typ
if varTyp == nil or sfGlobal in s.flags: return
let destructableT = instantiateDestructor(c, varTyp)
if destructableT != nil:
let call = semStmt(c, newNode(nkCall, s.info, @[
useSym(destructableT.destructor), useSym(s)]))
result = newNode(nkDefer, s.info, @[call])
proc insertDestructors(c: PContext,
varSection: PNode): tuple[outer, inner: PNode] =
# Accepts a var or let section.

View file

@ -597,8 +597,8 @@ proc skipObjConv(n: PNode): PNode =
of nkObjUpConv, nkObjDownConv: result = n.sons[0]
else: result = n
proc isAssignable(c: PContext, n: PNode): TAssignableResult =
result = parampatterns.isAssignable(c.p.owner, n)
proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult =
result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or
@ -1700,7 +1700,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
case s.magic # magics that need special treatment
of mAddr:
checkSonsLen(n, 2)
result = semAddr(c, n.sons[1])
result = semAddr(c, n.sons[1], s.name.s == "unsafeAddr")
of mTypeOf:
checkSonsLen(n, 2)
result = semTypeOf(c, n.sons[1])
@ -1720,6 +1720,8 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
result.typ = getSysType(tyString)
of mParallel:
if not experimentalMode(c):
localError(n.info, "use the {.experimental.} pragma to enable 'parallel'")
result = setMs(n, s)
var x = n.lastSon
if x.kind == nkDo: x = x.sons[bodyPos]
@ -2259,7 +2261,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkStaticStmt:
result = semStaticStmt(c, n)
of nkDefer:
localError(n.info, errGenerated, "'defer' not allowed in this context")
n.sons[0] = semExpr(c, n.sons[0])
if not n.sons[0].typ.isEmptyType and not implicitlyDiscardable(n.sons[0]):
localError(n.info, errGenerated, "'defer' takes a 'void' expression")
#localError(n.info, errGenerated, "'defer' not allowed in this context")
else:
localError(n.info, errInvalidExpressionX,
renderTree(n, {renderNoComments}))

View file

@ -307,12 +307,12 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n)
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n)
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n)
of mUnaryLt: result = newIntNodeT(getOrdValue(a) - 1, n)
of mSucc: result = newIntNodeT(getOrdValue(a) + getInt(b), n)
of mPred: result = newIntNodeT(getOrdValue(a) - getInt(b), n)
of mAddI: result = newIntNodeT(getInt(a) + getInt(b), n)
of mSubI: result = newIntNodeT(getInt(a) - getInt(b), n)
of mMulI: result = newIntNodeT(getInt(a) * getInt(b), n)
of mUnaryLt: result = newIntNodeT(getOrdValue(a) |-| 1, n)
of mSucc: result = newIntNodeT(getOrdValue(a) |+| getInt(b), n)
of mPred: result = newIntNodeT(getOrdValue(a) |-| getInt(b), n)
of mAddI: result = newIntNodeT(getInt(a) |+| getInt(b), n)
of mSubI: result = newIntNodeT(getInt(a) |-| getInt(b), n)
of mMulI: result = newIntNodeT(getInt(a) |*| getInt(b), n)
of mMinI:
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
else: result = newIntNodeT(getInt(a), n)
@ -338,11 +338,11 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mDivI:
let y = getInt(b)
if y != 0:
result = newIntNodeT(getInt(a) div y, n)
result = newIntNodeT(`|div|`(getInt(a), y), n)
of mModI:
let y = getInt(b)
if y != 0:
result = newIntNodeT(getInt(a) mod y, n)
result = newIntNodeT(`|mod|`(getInt(a), y), n)
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)

View file

@ -39,9 +39,9 @@ type
proc semGenericStmt(c: PContext, n: PNode,
flags: TSemGenericFlags, ctx: var GenericCtx): PNode
proc semGenericStmtScope(c: PContext, n: PNode,
proc semGenericStmtScope(c: PContext, n: PNode,
flags: TSemGenericFlags,
ctx: var GenericCtx): PNode =
ctx: var GenericCtx): PNode =
openScope(c)
result = semGenericStmt(c, n, flags, ctx)
closeScope(c)
@ -57,7 +57,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
of skUnknown:
# Introduced in this pass! Leave it as an identifier.
result = n
of skProc, skMethod, skIterators, skConverter:
of skProc, skMethod, skIterators, skConverter, skModule:
result = symChoice(c, n, s, scOpen)
of skTemplate:
if macroToExpand(s):
@ -73,7 +73,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = semGenericStmt(c, result, {}, ctx)
else:
result = symChoice(c, n, s, scOpen)
of skGenericParam:
of skGenericParam:
if s.typ != nil and s.typ.kind == tyStatic:
if s.typ.n != nil:
result = s.typ.n
@ -85,18 +85,18 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
of skParam:
result = n
styleCheckUse(n.info, s)
of skType:
of skType:
if (s.typ != nil) and
(s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
result = newSymNodeTypeDesc(s, n.info)
else:
else:
result = n
styleCheckUse(n.info, s)
else:
result = newSymNode(s, n.info)
styleCheckUse(n.info, s)
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var GenericCtx): PNode =
result = n
let ident = considerQuotedIdent(n)
@ -118,13 +118,13 @@ proc newDot(n, b: PNode): PNode =
result.add(n.sons[0])
result.add(b)
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var GenericCtx; isMacro: var bool): PNode =
assert n.kind == nkDotExpr
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
var s = qualifiedLookUp(c, n, luf)
if s != nil:
result = semGenericStmtSymbol(c, n, s, ctx)
@ -141,18 +141,20 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
elif s.name.id in ctx.toMixin:
result = newDot(result, symChoice(c, n, s, scForceOpen))
else:
let sym = semGenericStmtSymbol(c, n, s, ctx)
if sym.kind == nkSym:
result = newDot(result, symChoice(c, n, s, scForceOpen))
let syms = semGenericStmtSymbol(c, n, s, ctx)
if syms.kind == nkSym:
let choice = symChoice(c, n, s, scForceOpen)
choice.kind = nkClosedSymChoice
result = newDot(result, choice)
else:
result = newDot(result, sym)
result = newDot(result, syms)
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
let s = newSymS(skUnknown, getIdentNode(n), c)
addPrelimDecl(c, s)
styleCheckDef(n.info, s, kind)
proc semGenericStmt(c: PContext, n: PNode,
proc semGenericStmt(c: PContext, n: PNode,
flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
result = n
#if gCmd == cmdIdeTools: suggestStmt(c, n)
@ -181,16 +183,16 @@ proc semGenericStmt(c: PContext, n: PNode,
result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx)
of nkMixinStmt:
result = semMixinStmt(c, n, ctx.toMixin)
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
# check if it is an expression macro:
checkMinSonsLen(n, 1)
let fn = n.sons[0]
var s = qualifiedLookUp(c, fn, {})
if s == nil and withinMixin notin flags and
fn.kind in {nkIdent, nkAccQuoted} and
fn.kind in {nkIdent, nkAccQuoted} and
considerQuotedIdent(fn).id notin ctx.toMixin:
localError(n.info, errUndeclaredIdentifier, fn.renderTree)
var first = 0
var mixinContext = false
if s != nil:
@ -220,19 +222,19 @@ proc semGenericStmt(c: PContext, n: PNode,
# we need to put the ``c`` in ``t(c)`` in a mixin context to prevent
# the famous "undeclared identifier: it" bug:
mixinContext = true
of skUnknown, skParam:
of skUnknown, skParam:
# Leave it as an identifier.
discard
of skProc, skMethod, skIterators, skConverter:
of skProc, skMethod, skIterators, skConverter, skModule:
result.sons[0] = symChoice(c, fn, s, scOption)
first = 1
of skGenericParam:
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
styleCheckUse(fn.info, s)
first = 1
of skType:
of skType:
# bad hack for generics:
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
styleCheckUse(fn.info, s)
first = 1
@ -244,34 +246,34 @@ proc semGenericStmt(c: PContext, n: PNode,
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
first = 1
# Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
# is not exported and yet the generic 'threadProcWrapper' works correctly.
let flags = if mixinContext: flags+{withinMixin} else: flags
for i in countup(first, sonsLen(result) - 1):
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
of nkIfStmt:
for i in countup(0, sonsLen(n)-1):
of nkIfStmt:
for i in countup(0, sonsLen(n)-1):
n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
of nkWhenStmt:
for i in countup(0, sonsLen(n)-1):
n.sons[i] = semGenericStmt(c, n.sons[i], flags+{withinMixin}, ctx)
of nkWhileStmt:
of nkWhileStmt:
openScope(c)
for i in countup(0, sonsLen(n)-1):
for i in countup(0, sonsLen(n)-1):
n.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
closeScope(c)
of nkCaseStmt:
of nkCaseStmt:
openScope(c)
n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
for i in countup(1, sonsLen(n)-1):
for i in countup(1, sonsLen(n)-1):
var a = n.sons[i]
checkMinSonsLen(a, 1)
var L = sonsLen(a)
for j in countup(0, L-2):
for j in countup(0, L-2):
a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx)
a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
closeScope(c)
of nkForStmt, nkParForStmt:
of nkForStmt, nkParForStmt:
var L = sonsLen(n)
openScope(c)
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
@ -279,27 +281,27 @@ proc semGenericStmt(c: PContext, n: PNode,
addTempDecl(c, n.sons[i], skForVar)
n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
closeScope(c)
of nkBlockStmt, nkBlockExpr, nkBlockType:
of nkBlockStmt, nkBlockExpr, nkBlockType:
checkSonsLen(n, 2)
openScope(c)
if n.sons[0].kind != nkEmpty:
if n.sons[0].kind != nkEmpty:
addTempDecl(c, n.sons[0], skLabel)
n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
closeScope(c)
of nkTryStmt:
of nkTryStmt:
checkMinSonsLen(n, 2)
n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx)
for i in countup(1, sonsLen(n)-1):
for i in countup(1, sonsLen(n)-1):
var a = n.sons[i]
checkMinSonsLen(a, 1)
var L = sonsLen(a)
for j in countup(0, L-2):
for j in countup(0, L-2):
a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx)
a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
of nkVarSection, nkLetSection:
for i in countup(0, sonsLen(n) - 1):
of nkVarSection, nkLetSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.kind == nkCommentStmt: continue
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
checkMinSonsLen(a, 3)
var L = sonsLen(a)
@ -307,49 +309,49 @@ proc semGenericStmt(c: PContext, n: PNode,
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
for j in countup(0, L-3):
addTempDecl(c, getIdentNode(a.sons[j]), skVar)
of nkGenericParams:
for i in countup(0, sonsLen(n) - 1):
of nkGenericParams:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if (a.kind != nkIdentDefs): illFormedAst(a)
checkMinSonsLen(a, 3)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
# do not perform symbol lookup for default expressions
for j in countup(0, L-3):
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
# do not perform symbol lookup for default expressions
for j in countup(0, L-3):
addTempDecl(c, getIdentNode(a.sons[j]), skType)
of nkConstSection:
for i in countup(0, sonsLen(n) - 1):
of nkConstSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.kind == nkCommentStmt: continue
if (a.kind != nkConstDef): illFormedAst(a)
checkSonsLen(a, 3)
addTempDecl(c, getIdentNode(a.sons[0]), skConst)
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
of nkTypeSection:
for i in countup(0, sonsLen(n) - 1):
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
addTempDecl(c, getIdentNode(a.sons[0]), skType)
for i in countup(0, sonsLen(n) - 1):
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
if a.sons[1].kind != nkEmpty:
if a.sons[1].kind != nkEmpty:
openScope(c)
a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx)
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
closeScope(c)
else:
else:
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
of nkEnumTy:
of nkEnumTy:
if n.sonsLen > 0:
if n.sons[0].kind != nkEmpty:
if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
for i in countup(1, sonsLen(n) - 1):
for i in countup(1, sonsLen(n) - 1):
var a: PNode
case n.sons[i].kind
of nkEnumFieldDef: a = n.sons[i].sons[0]
@ -360,26 +362,26 @@ proc semGenericStmt(c: PContext, n: PNode,
discard
of nkFormalParams:
checkMinSonsLen(n, 1)
if n.sons[0].kind != nkEmpty:
if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
for i in countup(1, sonsLen(n) - 1):
for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i]
if (a.kind != nkIdentDefs): illFormedAst(a)
checkMinSonsLen(a, 3)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
for j in countup(0, L-3):
for j in countup(0, L-3):
addTempDecl(c, getIdentNode(a.sons[j]), skParam)
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef, nkLambdaKinds:
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef, nkLambdaKinds:
checkSonsLen(n, bodyPos + 1)
if n.sons[namePos].kind != nkEmpty:
addTempDecl(c, getIdentNode(n.sons[0]), skProc)
openScope(c)
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
flags, ctx)
if n.sons[paramsPos].kind != nkEmpty:
if n.sons[paramsPos].kind != nkEmpty:
if n.sons[paramsPos].sons[0].kind != nkEmpty:
addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info))
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
@ -394,7 +396,7 @@ proc semGenericStmt(c: PContext, n: PNode,
checkMinSonsLen(n, 2)
result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
else:
for i in countup(0, sonsLen(n) - 1):
for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
proc semGenericStmt(c: PContext, n: PNode): PNode =

View file

@ -10,14 +10,10 @@
# This module implements the instantiation of generic procs.
# included from sem.nim
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
entry: var TInstantiation) =
if n.kind != nkGenericParams:
internalError(n.info, "instantiateGenericParamList; no generic params")
newSeq(entry.concreteTypes, n.len)
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
internalAssert n.kind == nkGenericParams
for i, a in n.pairs:
if a.kind != nkSym:
internalError(a.info, "instantiateGenericParamList; no symbol")
internalAssert a.kind == nkSym
var q = a.sym
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
continue
@ -42,8 +38,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
#t = ReplaceTypeVarsT(cl, t)
s.typ = t
if t.kind == tyStatic: s.ast = t.n
addDecl(c, s)
entry.concreteTypes[i] = t
yield s
proc sameInstantiation(a, b: TInstantiation): bool =
if a.concreteTypes.len == b.concreteTypes.len:
@ -217,7 +212,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
## The `pt` parameter is a type-unsafe mapping table used to link generic
## parameters to their concrete types within the generic instance.
# no need to instantiate generic templates/macros:
if fn.kind in {skTemplate, skMacro}: return fn
internalAssert fn.kind notin {skMacro, skTemplate}
# generates an instantiated proc
if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
inc(c.instCounter)
@ -226,20 +221,27 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
# NOTE: for access of private fields within generics from a different module
# we set the friend module:
c.friendModules.add(getModule(fn))
#let oldScope = c.currentScope
#c.currentScope = fn.scope
let oldScope = c.currentScope
while not isTopLevel(c): c.currentScope = c.currentScope.parent
result = copySym(fn, false)
incl(result.flags, sfFromGeneric)
result.owner = fn
result.ast = n
pushOwner(result)
openScope(c)
internalAssert n.sons[genericParamsPos].kind != nkEmpty
let gp = n.sons[genericParamsPos]
internalAssert gp.kind != nkEmpty
n.sons[namePos] = newSymNode(result)
pushInfoContext(info)
var entry = TInstantiation.new
entry.sym = result
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
newSeq(entry.concreteTypes, gp.len)
var i = 0
for s in instantiateGenericParamList(c, gp, pt):
addDecl(c, s)
entry.concreteTypes[i] = s.typ
inc i
pushProcCon(c, result)
instantiateProcType(c, pt, result, info)
n.sons[genericParamsPos] = ast.emptyNode
@ -264,7 +266,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
popInfoContext()
closeScope(c) # close scope for parameters
popOwner()
#c.currentScope = oldScope
c.currentScope = oldScope
discard c.friendModules.pop()
dec(c.instCounter)
if result.kind == skMethod: finishMethod(c, result)

View file

@ -10,10 +10,10 @@
# This include file implements the semantic checking for magics.
# included from sem.nim
proc semAddr(c: PContext; n: PNode): PNode =
proc semAddr(c: PContext; n: PNode; isUnsafeAddr=false): PNode =
result = newNodeI(nkAddr, n.info)
let x = semExprWithType(c, n)
if isAssignable(c, x) notin {arLValue, arLocalLValue}:
if isAssignable(c, x, isUnsafeAddr) notin {arLValue, arLocalLValue}:
localError(n.info, errExprHasNoAddress)
result.add x
result.typ = makePtrType(c, x.typ)
@ -119,7 +119,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
case n[0].sym.magic
of mAddr:
checkSonsLen(n, 2)
result = semAddr(c, n.sons[1])
result = semAddr(c, n.sons[1], n[0].sym.name.s == "unsafeAddr")
of mTypeOf:
checkSonsLen(n, 2)
result = semTypeOf(c, n.sons[1])

View file

@ -369,6 +369,15 @@ proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
else:
result.add identDefs
proc addDefer(c: PContext; result: var PNode; s: PSym) =
let deferDestructorCall = createDestructorCall(c, s)
if deferDestructorCall != nil:
if result.kind != nkStmtList:
let oldResult = result
result = newNodeI(nkStmtList, result.info)
result.add oldResult
result.add deferDestructorCall
proc isDiscardUnderscore(v: PSym): bool =
if v.name.s == "_":
v.flags.incl(sfGenSym)
@ -469,6 +478,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
if def.kind == nkPar: v.ast = def[j]
v.typ = tup.sons[j]
b.sons[j] = newSymNode(v)
addDefer(c, result, v)
checkNilable(v)
if sfCompileTime in v.flags: hasCompileTime = true
if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
@ -1210,6 +1220,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if n.sons[patternPos].kind != nkEmpty:
c.patterns.add(s)
if isAnon: result.typ = s.typ
if isTopLevel(c) and s.kind != skClosureIterator and
s.typ.callConv == ccClosure:
message(s.info, warnDeprecated, "top level '.closure' calling convention")
proc determineType(c: PContext, s: PSym) =
if s.typ != nil: return
@ -1371,7 +1384,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
for i in countup(0, length - 1):
let k = n.sons[i].kind
case k
of nkFinally, nkExceptBranch, nkDefer:
of nkFinally, nkExceptBranch:
# stand-alone finally and except blocks are
# transformed into regular try blocks:
#
@ -1424,21 +1437,13 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
n.typ = n.sons[i].typ
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
case n.sons[i].kind
of nkVarSection, nkLetSection:
let (outer, inner) = insertDestructors(c, n.sons[i])
if outer != nil:
n.sons[i] = outer
var rest = newNode(nkStmtList, n.info, n.sons[i+1 .. length-1])
inner.addSon(semStmtList(c, rest, flags))
n.sons.setLen(i+1)
return
of LastBlockStmts:
for j in countup(i + 1, length - 1):
case n.sons[j].kind
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
else: discard
if result.len == 1:
if result.len == 1 and result.sons[0].kind != nkDefer:
result = result.sons[0]
when defined(nimfix):
if result.kind == nkCommentStmt and not result.comment.isNil and

View file

@ -184,10 +184,25 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
else:
let ident = getIdentNode(c, n)
if not isTemplParam(c, ident):
let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local)
styleCheckDef(n.info, local)
replaceIdentBySym(n, newSymNode(local, n.info))
# fix #2670, consider:
#
# when b:
# var a = "hi"
# else:
# var a = 5
# echo a
#
# We need to ensure that both 'a' produce the same gensym'ed symbol.
# So we need only check the *current* scope.
let s = localSearchInScope(c.c, considerQuotedIdent ident)
if s != nil and s.owner == c.owner and sfGenSym in s.flags:
styleCheckUse(n.info, s)
replaceIdentBySym(n, newSymNode(s, n.info))
else:
let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local)
styleCheckDef(n.info, local)
replaceIdentBySym(n, newSymNode(local, n.info))
else:
replaceIdentBySym(n, ident)

View file

@ -23,6 +23,9 @@ proc newConstraint(c: PContext, k: TTypeKind): PType =
proc semEnum(c: PContext, n: PNode, prev: PType): PType =
if n.sonsLen == 0: return newConstraint(c, tyEnum)
elif n.sonsLen == 1:
# don't create an empty tyEnum; fixes #3052
return errorType(c)
var
counter, x: BiggestInt
e: PSym
@ -505,8 +508,9 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc})
if not isOrdinalType(typ):
localError(n.info, errSelectorMustBeOrdinal)
elif firstOrd(typ) < 0:
localError(n.info, errOrdXMustNotBeNegative, a.sons[0].sym.name.s)
elif firstOrd(typ) != 0:
localError(n.info, errGenerated, "low(" & $a.sons[0].sym.name.s &
") must be 0 for discriminant")
elif lengthOrd(typ) > 0x00007FFF:
localError(n.info, errLenXinvalid, a.sons[0].sym.name.s)
var chckCovered = true

View file

@ -16,6 +16,7 @@
# * converts "continue" to "break"; disambiguates "break"
# * introduces method dispatchers
# * performs lambda lifting for closure support
# * transforms 'defer' into a 'try finally' statement
import
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
@ -44,6 +45,7 @@ type
inlining: int # > 0 if we are in inlining context (copy vars)
nestedProcs: int # > 0 if we are in a nested proc
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
deferDetected: bool
PTransf = ref TTransfContext
proc newTransNode(a: PNode): PTransNode {.inline.} =
@ -680,6 +682,14 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
result = n
proc transform(c: PTransf, n: PNode): PTransNode =
when false:
var oldDeferAnchor: PNode
if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
nkElseExpr, nkElse, nkForStmt, nkWhileStmt, nkFinally,
nkBlockStmt, nkBlockExpr}:
oldDeferAnchor = c.deferAnchor
c.deferAnchor = n
case n.kind
of nkSym:
result = transformSym(c, n)
@ -712,13 +722,36 @@ proc transform(c: PTransf, n: PNode): PTransNode =
result = transformFor(c, n)
of nkParForStmt:
result = transformSons(c, n)
of nkCaseStmt: result = transformCase(c, n)
of nkCaseStmt:
result = transformCase(c, n)
of nkWhileStmt: result = transformWhile(c, n)
of nkBlockStmt, nkBlockExpr:
result = transformBlock(c, n)
of nkDefer:
c.deferDetected = true
result = transformSons(c, n)
when false:
let deferPart = newNodeI(nkFinally, n.info)
deferPart.add n.sons[0]
let tryStmt = newNodeI(nkTryStmt, n.info)
if c.deferAnchor.isNil:
tryStmt.add c.root
c.root = tryStmt
result = PTransNode(tryStmt)
else:
# modify the corresponding *action*, don't rely on nkStmtList:
let L = c.deferAnchor.len-1
tryStmt.add c.deferAnchor.sons[L]
c.deferAnchor.sons[L] = tryStmt
result = newTransNode(nkCommentStmt, n.info, 0)
tryStmt.addSon(deferPart)
# disable the original 'defer' statement:
n.kind = nkCommentStmt
of nkContinueStmt:
result = PTransNode(newNodeI(nkBreakStmt, n.info))
var labl = c.contSyms[c.contSyms.high]
add(result, PTransNode(newSymNode(labl)))
of nkBreakStmt: result = transformBreak(c, n)
of nkWhileStmt: result = transformWhile(c, n)
of nkCallKinds:
result = transformCall(c, n)
of nkAddr, nkHiddenAddr:
@ -754,8 +787,6 @@ proc transform(c: PTransf, n: PNode): PTransNode =
result = transformYield(c, n)
else:
result = transformSons(c, n)
of nkBlockStmt, nkBlockExpr:
result = transformBlock(c, n)
of nkIdentDefs, nkConstDef:
result = transformSons(c, n)
# XXX comment handling really sucks:
@ -764,6 +795,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
of nkClosure: return PTransNode(n)
else:
result = transformSons(c, n)
when false:
if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
var cnst = getConstExpr(c.module, PNode(result))
# we inline constants if they are not complex constants:
if cnst != nil and not dontInlineConstant(n, cnst):
@ -785,12 +818,52 @@ proc openTransf(module: PSym, filename: string): PTransf =
result.breakSyms = @[]
result.module = module
proc flattenStmts(n: PNode) =
var goOn = true
while goOn:
goOn = false
for i in 0..<n.len:
let it = n[i]
if it.kind in {nkStmtList, nkStmtListExpr}:
n.sons[i..i] = it.sons[0..<it.len]
goOn = true
proc liftDeferAux(n: PNode) =
if n.kind in {nkStmtList, nkStmtListExpr}:
flattenStmts(n)
var goOn = true
while goOn:
goOn = false
let last = n.len-1
for i in 0..last:
if n.sons[i].kind == nkDefer:
let deferPart = newNodeI(nkFinally, n.sons[i].info)
deferPart.add n.sons[i].sons[0]
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
var body = newNodeI(n.kind, n.sons[i].info)
if i < last:
body.sons = n.sons[(i+1)..last]
tryStmt.addSon(body)
tryStmt.addSon(deferPart)
n.sons[i] = tryStmt
n.sons.setLen(i+1)
n.typ = n.sons[i].typ
goOn = true
break
for i in 0..n.safeLen-1:
liftDeferAux(n.sons[i])
template liftDefer(c, root) =
if c.deferDetected:
liftDeferAux(root)
proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
if nfTransf in n.flags or prc.kind in {skTemplate}:
result = n
else:
var c = openTransf(module, "")
result = processTransf(c, n, prc)
liftDefer(c, result)
result = liftLambdas(prc, result)
#if prc.kind == skClosureIterator:
# result = lambdalifting.liftIterator(prc, result)
@ -805,6 +878,7 @@ proc transformStmt*(module: PSym, n: PNode): PNode =
else:
var c = openTransf(module, "")
result = processTransf(c, n, module)
liftDefer(c, result)
result = liftLambdasForTopLevel(module, result)
incl(result.flags, nfTransf)
when useEffectSystem: trackTopLevelStmt(module, result)
@ -815,4 +889,5 @@ proc transformExpr*(module: PSym, n: PNode): PNode =
else:
var c = openTransf(module, "")
result = processTransf(c, n, module)
liftDefer(c, result)
incl(result.flags, nfTransf)

View file

@ -120,10 +120,10 @@ template decodeBx(k: expr) {.immediate, dirty.} =
template move(a, b: expr) {.immediate, dirty.} = system.shallowCopy(a, b)
# XXX fix minor 'shallowCopy' overloading bug in compiler
proc createStrKeepNode(x: var TFullReg) =
proc createStrKeepNode(x: var TFullReg; keepNode=true) =
if x.node.isNil:
x.node = newNode(nkStrLit)
elif x.node.kind == nkNilLit:
elif x.node.kind == nkNilLit and keepNode:
when defined(useNodeIds):
let id = x.node.id
system.reset(x.node[])
@ -385,6 +385,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
#if c.traceActive:
# echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
# message(c.debug[pc], warnUser, "Trace")
case instr.opcode
of opcEof: return regs[ra]
of opcRet:
@ -407,8 +408,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
decodeB(rkInt)
regs[ra].intVal = regs[rb].intVal
of opcAsgnStr:
decodeB(rkNode)
createStrKeepNode regs[ra]
decodeBC(rkNode)
createStrKeepNode regs[ra], rc != 0
regs[ra].node.strVal = regs[rb].node.strVal
of opcAsgnFloat:
decodeB(rkFloat)
@ -431,7 +432,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
assert regs[rb].kind == rkNode
let nb = regs[rb].node
case nb.kind
of nkCharLit..nkInt64Lit:
of nkCharLit..nkUInt64Lit:
ensureKind(rkInt)
regs[ra].intVal = nb.intVal
of nkFloatLit..nkFloat64Lit:
@ -509,8 +510,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of rkNode:
if regs[rb].node.kind == nkNilLit:
stackTrace(c, tos, pc, errNilAccess)
assert regs[rb].node.kind == nkRefTy
regs[ra].node = regs[rb].node.sons[0]
if regs[rb].node.kind == nkRefTy:
regs[ra].node = regs[rb].node.sons[0]
else:
stackTrace(c, tos, pc, errGenerated, "limited VM support for 'ref'")
else:
stackTrace(c, tos, pc, errNilAccess)
of opcWrDeref:
@ -1404,7 +1407,7 @@ include vmops
# storing&loading the 'globals' environment to get what a component system
# requires.
var
globalCtx: PCtx
globalCtx*: PCtx
proc setupGlobalCtx(module: PSym) =
if globalCtx.isNil:
@ -1464,12 +1467,20 @@ proc evalStaticStmt*(module: PSym, e: PNode, prc: PSym) =
proc setupCompileTimeVar*(module: PSym, n: PNode) =
discard evalConstExprAux(module, nil, n, emStaticStmt)
proc setupMacroParam(x: PNode): PNode =
result = x
if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
result = canonValue(result)
result.flags.incl nfIsRef
result.typ = x.typ
proc setupMacroParam(x: PNode, typ: PType): TFullReg =
case typ.kind
of tyStatic:
putIntoReg(result, x)
of tyTypeDesc:
putIntoReg(result, x)
else:
result.kind = rkNode
var n = x
if n.kind in {nkHiddenSubConv, nkHiddenStdConv}: n = n.sons[1]
n = n.canonValue
n.flags.incl nfIsRef
n.typ = x.typ
result.node = n
var evalMacroCounter: int
@ -1505,10 +1516,17 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
# return value:
tos.slots[0].kind = rkNode
tos.slots[0].node = newNodeIT(nkEmpty, n.info, sym.typ.sons[0])
# setup parameters:
for i in 1 .. < min(tos.slots.len, L):
tos.slots[i].kind = rkNode
tos.slots[i].node = setupMacroParam(n.sons[i])
for i in 1.. <sym.typ.len:
tos.slots[i] = setupMacroParam(n.sons[i], sym.typ.sons[i])
if sfImmediate notin sym.flags:
let gp = sym.ast[genericParamsPos]
for i in 0 .. <gp.len:
let idx = sym.typ.len + i
tos.slots[idx] = setupMacroParam(n.sons[idx], gp[i].sym.typ)
# temporary storage:
#for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
result = rawExecute(c, start, tos).regToNode

View file

@ -30,7 +30,7 @@ proc opGorge*(cmd, input, cache: string): string =
return
var readSuccessful = false
try:
var p = startProcess(cmd, options={poEvalCommand})
var p = startProcess(cmd, options={poEvalCommand, poStderrToStdout})
if input.len != 0:
p.inputStream.write(input)
p.inputStream.close()
@ -41,7 +41,7 @@ proc opGorge*(cmd, input, cache: string): string =
if not readSuccessful: result = ""
else:
try:
var p = startProcess(cmd, options={poEvalCommand})
var p = startProcess(cmd, options={poEvalCommand, poStderrToStdout})
if input.len != 0:
p.inputStream.write(input)
p.inputStream.close()

View file

@ -74,8 +74,9 @@ proc codeListing(c: PCtx, result: var string, start=0; last = -1) =
result.addf("\t$#\tr$#, L$#", ($opc).substr(3), x.regA,
i+x.regBx-wordExcess)
elif opc in {opcLdConst, opcAsgnConst}:
result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA,
c.constants[x.regBx-wordExcess].renderTree)
let idx = x.regBx-wordExcess
result.addf("\t$#\tr$#, $# ($#)", ($opc).substr(3), x.regA,
c.constants[idx].renderTree, $idx)
elif opc in {opcMarshalLoad, opcMarshalStore}:
let y = c.code[i+1]
result.addf("\t$#\tr$#, r$#, $#", ($opc).substr(3), x.regA, x.regB,
@ -172,7 +173,8 @@ const
proc bestEffort(c: PCtx): TLineInfo =
(if c.prc == nil: c.module.info else: c.prc.sym.info)
proc getTemp(cc: PCtx; typ: PType): TRegister =
proc getTemp(cc: PCtx; tt: PType): TRegister =
let typ = tt.skipTypesOrNil({tyStatic})
let c = cc.prc
# we prefer the same slot kind here for efficiency. Unfortunately for
# discardable return types we may not know the desired type. This can happen
@ -184,7 +186,7 @@ proc getTemp(cc: PCtx; typ: PType): TRegister =
return TRegister(i)
# if register pressure is high, we re-use more aggressively:
if c.maxSlots >= HighRegisterPressure:
if c.maxSlots >= HighRegisterPressure and false:
for i in 0 .. c.maxSlots-1:
if not c.slots[i].inUse:
c.slots[i] = (inUse: true, kind: k)
@ -706,7 +708,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
if dest < 0: dest = c.getTemp(n.typ)
c.gABC(n, opc, dest, tmp)
c.gABx(n, opc, 0, genType(c, n.typ))
c.gABx(n, opc, 0, genType(c, arg.typ))
c.gABx(n, opc, 0, genType(c, arg.typ.skipTypes({tyStatic})))
c.freeTemp(tmp)
proc genCard(c: PCtx; n: PNode; dest: var TDest) =
@ -1073,6 +1075,7 @@ const
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64}
proc fitsRegister*(t: PType): bool =
assert t != nil
t.skipTypes(abstractInst-{tyTypeDesc}).kind in {
tyRange, tyEnum, tyBool, tyInt..tyUInt64, tyChar}
@ -1103,6 +1106,8 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
# nkAddr we must not use 'unneededIndirection', but for deref we use it.
if not isAddr and unneededIndirection(n.sons[0]):
gen(c, n.sons[0], dest, newflags)
if gfAddrOf notin flags and fitsRegister(n.typ):
c.gABC(n, opcNodeToReg, dest, dest)
elif isAddr and isGlobal(n.sons[0]):
gen(c, n.sons[0], dest, flags+{gfAddrOf})
else:
@ -1110,6 +1115,7 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
if dest < 0: dest = c.getTemp(n.typ)
if not isAddr:
gABC(c, n, opc, dest, tmp)
assert n.typ != nil
if gfAddrOf notin flags and fitsRegister(n.typ):
c.gABC(n, opcNodeToReg, dest, dest)
elif c.prc.slots[tmp].kind >= slotTempUnknown:
@ -1143,7 +1149,7 @@ proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode = opc
proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
let tmp = c.genx(ri)
assert dest >= 0
gABC(c, ri, whichAsgnOpc(ri), dest, tmp)
gABC(c, ri, whichAsgnOpc(ri), dest, tmp, 1-ord(requiresCopy))
c.freeTemp(tmp)
proc setSlot(c: PCtx; v: PSym) =
@ -1177,7 +1183,10 @@ proc checkCanEval(c: PCtx; n: PNode) =
let s = n.sym
if {sfCompileTime, sfGlobal} <= s.flags: return
if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
not s.isOwnedBy(c.prc.sym) and s.owner != c.module:
not s.isOwnedBy(c.prc.sym) and s.owner != c.module and c.mode != emRepl:
cannotEval(n)
elif s.kind in {skProc, skConverter, skMethod,
skIterator, skClosureIterator} and sfForward in s.flags:
cannotEval(n)
proc isTemp(c: PCtx; dest: TDest): bool =
@ -1194,9 +1203,10 @@ proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
# opcLdObj et al really means "load address". We sometimes have to create a
# copy in order to not introduce false aliasing:
# mylocal = a.b # needs a copy of the data!
assert n.typ != nil
if needsAdditionalCopy(n):
var cc = c.getTemp(n.typ)
c.gABC(n, whichAsgnOpc(n), cc, value)
c.gABC(n, whichAsgnOpc(n), cc, value, 0)
c.gABC(n, opc, dest, idx, cc)
c.freeTemp(cc)
else:
@ -1241,10 +1251,11 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
internalAssert s.position > 0 or (s.position == 0 and
s.kind in {skParam,skResult})
var dest: TRegister = s.position + ord(s.kind == skParam)
assert le.typ != nil
if needsAdditionalCopy(le) and s.kind in {skResult, skVar, skParam}:
var cc = c.getTemp(le.typ)
gen(c, ri, cc)
c.gABC(le, whichAsgnOpc(le), dest, cc)
c.gABC(le, whichAsgnOpc(le), dest, cc, 1)
c.freeTemp(cc)
else:
gen(c, ri, dest)
@ -1303,6 +1314,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
if sfImportc in s.flags: c.importcSym(n.info, s)
else: genGlobalInit(c, n, s)
if dest < 0: dest = c.getTemp(n.typ)
assert s.typ != nil
if gfAddrOf notin flags and fitsRegister(s.typ):
var cc = c.getTemp(n.typ)
c.gABx(n, opcLdGlobal, cc, s.position)
@ -1426,6 +1438,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
globalError(info, "cannot create null element for: " & $t.kind)
proc ldNullOpcode(t: PType): TOpcode =
assert t != nil
if fitsRegister(t): opcLdNullReg else: opcLdNull
proc genVarSection(c: PCtx; n: PNode) =
@ -1453,7 +1466,7 @@ proc genVarSection(c: PCtx; n: PNode) =
if a.sons[2].kind != nkEmpty:
let tmp = c.genx(a.sons[0], {gfAddrOf})
let val = c.genx(a.sons[2])
c.preventFalseAlias(a, opcWrDeref, tmp, 0, val)
c.preventFalseAlias(a.sons[2], opcWrDeref, tmp, 0, val)
c.freeTemp(val)
c.freeTemp(tmp)
else:
@ -1461,13 +1474,15 @@ proc genVarSection(c: PCtx; n: PNode) =
if a.sons[2].kind == nkEmpty:
c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
else:
assert s.typ != nil
if not fitsRegister(s.typ):
c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
let le = a.sons[0]
assert le.typ != nil
if not fitsRegister(le.typ) and s.kind in {skResult, skVar, skParam}:
var cc = c.getTemp(le.typ)
gen(c, a.sons[2], cc)
c.gABC(le, whichAsgnOpc(le), s.position.TRegister, cc)
c.gABC(le, whichAsgnOpc(le), s.position.TRegister, cc, 1)
c.freeTemp(cc)
else:
gen(c, a.sons[2], s.position.TRegister)
@ -1608,6 +1623,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
c.gABx(n, opcLdConst, dest, lit)
of skType:
genTypeLit(c, s.typ, dest)
of skGenericParam:
if c.prc.sym.kind == skMacro:
genRdVar(c, n, dest, flags)
else:
internalError(n.info, "cannot generate code for: " & s.name.s)
else:
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
of nkCallKinds:
@ -1694,7 +1714,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
c.freeTemp(tmp1)
c.freeTemp(tmp2)
if dest >= 0:
gABC(c, n, whichAsgnOpc(n), dest, tmp0)
gABC(c, n, whichAsgnOpc(n), dest, tmp0, 1)
c.freeTemp(tmp0)
else:
dest = tmp0
@ -1758,6 +1778,14 @@ proc finalJumpTarget(c: PCtx; pc, diff: int) =
c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
uint32(diff+wordExcess) shl 16'u32).TInstr
proc genGenericParams(c: PCtx; gp: PNode) =
var base = c.prc.maxSlots
for i in 0.. <gp.len:
var param = gp.sons[i].sym
param.position = base + i # XXX: fix this earlier; make it consistent with templates
c.prc.slots[base + i] = (inUse: true, kind: slotFixedLet)
c.prc.maxSlots = base + gp.len
proc optimizeJumps(c: PCtx; start: int) =
const maxIterations = 10
for i in start .. <c.code.len:
@ -1822,6 +1850,13 @@ proc genProc(c: PCtx; s: PSym): int =
c.prc = p
# iterate over the parameters and allocate space for them:
genParams(c, s.typ.n)
# allocate additional space for any generically bound parameters
if s.kind == skMacro and
sfImmediate notin s.flags and
s.ast[genericParamsPos].kind != nkEmpty:
genGenericParams(c, s.ast[genericParamsPos])
if tfCapturesEnv in s.typ.flags:
#let env = s.ast.sons[paramsPos].lastSon.sym
#assert env.position == 2

View file

@ -17,7 +17,7 @@ template setX(k, field) {.immediate, dirty.} =
proc setResult*(a: VmArgs; v: BiggestInt) = setX(rkInt, intVal)
proc setResult*(a: VmArgs; v: BiggestFloat) = setX(rkFloat, floatVal)
proc setResult*(a: VmArgs; v: bool) =
proc setResult*(a: VmArgs; v: bool) =
let v = v.ord
setX(rkInt, intVal)
@ -30,6 +30,16 @@ proc setResult*(a: VmArgs; v: string) =
s[a.ra].node = newNode(nkStrLit)
s[a.ra].node.strVal = v
proc setResult*(a: VmArgs; v: seq[string]) =
var s: seq[TFullReg]
move(s, cast[seq[TFullReg]](a.slots))
if s[a.ra].kind != rkNode:
myreset(s[a.ra])
s[a.ra].kind = rkNode
var n = newNode(nkBracket)
for x in v: n.add newStrNode(nkStrLit, x)
s[a.ra].node = n
template getX(k, field) {.immediate, dirty.} =
doAssert i < a.rc-1
let s = cast[seq[TFullReg]](a.slots)