more modules compile again

This commit is contained in:
Andreas Rumpf 2018-05-12 11:58:44 +02:00
commit 05724645f8
12 changed files with 260 additions and 236 deletions

View file

@ -34,10 +34,10 @@ proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
of nkOfBranch, nkElse: of nkOfBranch, nkElse:
result = isPartOfAux(lastSon(n.sons[i]), b, marker) result = isPartOfAux(lastSon(n.sons[i]), b, marker)
if result == arYes: return if result == arYes: return
else: internalError("isPartOfAux(record case branch)") else: discard "isPartOfAux(record case branch)"
of nkSym: of nkSym:
result = isPartOfAux(n.sym.typ, b, marker) result = isPartOfAux(n.sym.typ, b, marker)
else: internalError(n.info, "isPartOfAux()") else: discard
proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult = proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
result = arNo result = arNo

View file

@ -14,11 +14,12 @@ import
rodread rodread
type type
TemplCtx {.pure, final.} = object TemplCtx = object
owner, genSymOwner: PSym owner, genSymOwner: PSym
instLines: bool # use the instantiation lines numbers instLines: bool # use the instantiation lines numbers
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
# new symbol # new symbol
config: ConfigRef
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode = proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
result = copyNode(a) result = copyNode(a)
@ -42,7 +43,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam: s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam:
handleParam actual.sons[s.owner.typ.len + s.position - 1] handleParam actual.sons[s.owner.typ.len + s.position - 1]
else: else:
internalAssert sfGenSym in s.flags or s.kind == skType internalAssert c.config, sfGenSym in s.flags or s.kind == skType
var x = PSym(idTableGet(c.mapping, s)) var x = PSym(idTableGet(c.mapping, s))
if x == nil: if x == nil:
x = copySym(s, false) x = copySym(s, false)
@ -59,7 +60,12 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
evalTemplateAux(templ.sons[i], actual, c, res) evalTemplateAux(templ.sons[i], actual, c, res)
result.add res result.add res
proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = const
errWrongNumberOfArguments = "wrong number of arguments"
errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters"
errTemplateInstantiationTooNested = "template instantiation too nested"
proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode =
# if the template has zero arguments, it can be called without ``()`` # if the template has zero arguments, it can be called without ``()``
# `n` is then a nkSym or something similar # `n` is then a nkSym or something similar
var totalParams = case n.kind var totalParams = case n.kind
@ -82,10 +88,10 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
if givenRegularParams < 0: givenRegularParams = 0 if givenRegularParams < 0: givenRegularParams = 0
if totalParams > expectedRegularParams + genericParams: if totalParams > expectedRegularParams + genericParams:
globalError(n.info, errWrongNumberOfArguments) globalError(conf, n.info, errWrongNumberOfArguments)
if totalParams < genericParams: if totalParams < genericParams:
globalError(n.info, errMissingGenericParamsForTemplate, globalError(conf, n.info, errMissingGenericParamsForTemplate %
n.renderTree) n.renderTree)
result = newNodeI(nkArgList, n.info) result = newNodeI(nkArgList, n.info)
@ -97,7 +103,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
for i in givenRegularParams+1 .. expectedRegularParams: for i in givenRegularParams+1 .. expectedRegularParams:
let default = s.typ.n.sons[i].sym.ast let default = s.typ.n.sons[i].sym.ast
if default.isNil or default.kind == nkEmpty: if default.isNil or default.kind == nkEmpty:
localError(n.info, errWrongNumberOfArguments) localError(conf, n.info, errWrongNumberOfArguments)
addSon(result, ast.emptyNode) addSon(result, ast.emptyNode)
else: else:
addSon(result, default.copyTree) addSon(result, default.copyTree)
@ -132,17 +138,19 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
result.add res result.add res
result.typ = res.typ result.typ = res.typ
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode = proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
conf: ConfigRef; fromHlo=false): PNode =
inc(evalTemplateCounter) inc(evalTemplateCounter)
if evalTemplateCounter > evalTemplateLimit: if evalTemplateCounter > evalTemplateLimit:
globalError(n.info, errTemplateInstantiationTooNested) globalError(conf, n.info, errTemplateInstantiationTooNested)
result = n result = n
# replace each param by the corresponding node: # replace each param by the corresponding node:
var args = evalTemplateArgs(n, tmpl, fromHlo) var args = evalTemplateArgs(n, tmpl, conf, fromHlo)
var ctx: TemplCtx var ctx: TemplCtx
ctx.owner = tmpl ctx.owner = tmpl
ctx.genSymOwner = genSymOwner ctx.genSymOwner = genSymOwner
ctx.config = conf
initIdTable(ctx.mapping) initIdTable(ctx.mapping)
let body = tmpl.getBody let body = tmpl.getBody
@ -151,7 +159,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
evalTemplateAux(body, args, ctx, result) evalTemplateAux(body, args, ctx, result)
if result.len == 1: result = result.sons[0] if result.len == 1: result = result.sons[0]
else: else:
localError(result.info, errIllFormedAstX, localError(conf, result.info, "illformed AST: " &
renderTree(result, {renderNoComments})) renderTree(result, {renderNoComments}))
else: else:
result = copyNode(body) result = copyNode(body)

View file

@ -330,8 +330,8 @@ proc canon*(n: PNode; o: Operators): PNode =
result.sons[2] = y[1] result.sons[2] = y[1]
else: discard else: discard
#proc `+@`*(a: PNode; b: BiggestInt): PNode = proc buildAdd*(a: PNode; b: BiggestInt; o: Operators): PNode =
# canon(if b != 0: opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a) canon(if b != 0: o.opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a, o)
proc usefulFact(n: PNode; o: Operators): PNode = proc usefulFact(n: PNode; o: Operators): PNode =
case n.getMagic case n.getMagic

View file

@ -12,7 +12,7 @@
proc hlo(c: PContext, n: PNode): PNode proc hlo(c: PContext, n: PNode): PNode
proc evalPattern(c: PContext, n, orig: PNode): PNode = proc evalPattern(c: PContext, n, orig: PNode): PNode =
internalAssert n.kind == nkCall and n.sons[0].kind == nkSym internalAssert c.config, n.kind == nkCall and n.sons[0].kind == nkSym
# we need to ensure that the resulting AST is semchecked. However, it's # we need to ensure that the resulting AST is semchecked. However, it's
# aweful to semcheck before macro invocation, so we don't and treat # aweful to semcheck before macro invocation, so we don't and treat
# templates and macros as immediate in this context. # templates and macros as immediate in this context.

View file

@ -150,7 +150,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
of "*": result = matchNested(c, p, n, rpn=false) of "*": result = matchNested(c, p, n, rpn=false)
of "**": result = matchNested(c, p, n, rpn=true) of "**": result = matchNested(c, p, n, rpn=true)
of "~": result = not matches(c, p.sons[1], n) of "~": result = not matches(c, p.sons[1], n)
else: internalError(p.info, "invalid pattern") else: doAssert(false, "invalid pattern")
# template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) = # template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) =
# add(a, b) # add(a, b)
elif p.kind == nkCurlyExpr: elif p.kind == nkCurlyExpr:
@ -289,7 +289,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
# constraint not fulfilled: # constraint not fulfilled:
if not ok: return nil if not ok: return nil
markUsed(n.info, s, c.graph.usageSym) markUsed(c.config, n.info, s, c.graph.usageSym)
if ctx.subMatch: if ctx.subMatch:
assert m.len == 3 assert m.len == 3
m.sons[1] = result m.sons[1] = result

View file

@ -17,21 +17,21 @@ proc iterToProcImpl(c: PContext, n: PNode): PNode =
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
let iter = n[1] let iter = n[1]
if iter.kind != nkSym or iter.sym.kind != skIterator: if iter.kind != nkSym or iter.sym.kind != skIterator:
localError(iter.info, "first argument needs to be an iterator") localError(c.config, iter.info, "first argument needs to be an iterator")
return return
if n[2].typ.isNil: if n[2].typ.isNil:
localError(n[2].info, "second argument needs to be a type") localError(c.config, n[2].info, "second argument needs to be a type")
return return
if n[3].kind != nkIdent: if n[3].kind != nkIdent:
localError(n[3].info, "third argument needs to be an identifier") localError(c.config, n[3].info, "third argument needs to be an identifier")
return return
let t = n[2].typ.skipTypes({tyTypeDesc, tyGenericInst}) let t = n[2].typ.skipTypes({tyTypeDesc, tyGenericInst})
if t.kind notin {tyRef, tyPtr} or t.lastSon.kind != tyObject: if t.kind notin {tyRef, tyPtr} or t.lastSon.kind != tyObject:
localError(n[2].info, localError(c.config, n[2].info,
"type must be a non-generic ref|ptr to object with state field") "type must be a non-generic ref|ptr to object with state field")
return return
let body = liftIterToProc(iter.sym, iter.sym.getBody, t) let body = liftIterToProc(c.graph, iter.sym, iter.sym.getBody, t)
let prc = newSym(skProc, n[3].ident, iter.sym.owner, iter.sym.info) let prc = newSym(skProc, n[3].ident, iter.sym.owner, iter.sym.info)
prc.typ = copyType(iter.sym.typ, prc, false) prc.typ = copyType(iter.sym.typ, prc, false)

View file

@ -71,7 +71,7 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
if arg.typ.isNil: if arg.typ.isNil:
localError(arg.info, errExprXHasNoType, localError(c.config, arg.info, "expression has no type: " &
renderTree(arg, {renderNoComments})) renderTree(arg, {renderNoComments}))
# error correction: # error correction:
result = copyTree(arg) result = copyTree(arg)
@ -79,7 +79,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
else: else:
result = indexTypesMatch(c, formal, arg.typ, arg) result = indexTypesMatch(c, formal, arg.typ, arg)
if result == nil: if result == nil:
typeMismatch(info, formal, arg.typ) typeMismatch(c.config, info, formal, arg.typ)
# error correction: # error correction:
result = copyTree(arg) result = copyTree(arg)
result.typ = formal result.typ = formal
@ -180,7 +180,7 @@ proc commonType*(x: PType, y: PNode): PType =
commonType(x, y.typ) commonType(x, y.typ)
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info)
when defined(nimsuggest): when defined(nimsuggest):
suggestDecl(c, n, result) suggestDecl(c, n, result)
@ -192,7 +192,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# and sfGenSym in n.sym.flags: # and sfGenSym in n.sym.flags:
result = n.sym result = n.sym
if result.kind != kind: if result.kind != kind:
localError(n.info, "cannot use symbol of kind '" & localError(c.config, n.info, "cannot use symbol of kind '" &
$result.kind & "' as a '" & $kind & "'") $result.kind & "' as a '" & $kind & "'")
if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}: if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}:
# declarative context, so produce a fresh gensym: # declarative context, so produce a fresh gensym:
@ -204,7 +204,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# template; we must fix it here: see #909 # template; we must fix it here: see #909
result.owner = getCurrOwner(c) result.owner = getCurrOwner(c)
else: else:
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info)
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule: #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
# incl(result.flags, sfGlobal) # incl(result.flags, sfGlobal)
when defined(nimsuggest): when defined(nimsuggest):
@ -216,20 +216,20 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym allowed: TSymFlags): PSym
proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind; proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKind;
flags: TTypeAllowedFlags = {}) = flags: TTypeAllowedFlags = {}) =
let t = typeAllowed(typ, kind, flags) let t = typeAllowed(typ, kind, flags)
if t != nil: if t != nil:
if t == typ: if t == typ:
localError(info, "invalid type: '" & typeToString(typ) & localError(conf, info, "invalid type: '" & typeToString(typ) &
"' for " & substr($kind, 2).toLowerAscii) "' for " & substr($kind, 2).toLowerAscii)
else: else:
localError(info, "invalid type: '" & typeToString(t) & localError(conf, info, "invalid type: '" & typeToString(t) &
"' in this context: '" & typeToString(typ) & "' in this context: '" & typeToString(typ) &
"' for " & substr($kind, 2).toLowerAscii) "' for " & substr($kind, 2).toLowerAscii)
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} = proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
typeAllowedCheck(typ.n.info, typ, skProc) typeAllowedCheck(c.config, typ.n.info, typ, skProc)
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
@ -282,10 +282,10 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
result = evaluated result = evaluated
let expectedType = eOrig.typ.skipTypes({tyStatic}) let expectedType = eOrig.typ.skipTypes({tyStatic})
if hasCycle(result): if hasCycle(result):
globalError(eOrig.info, "the resulting AST is cyclic and cannot be processed further") globalError(c.config, eOrig.info, "the resulting AST is cyclic and cannot be processed further")
result = errorNode(c, eOrig) result = errorNode(c, eOrig)
else: else:
semmacrosanity.annotateType(result, expectedType) semmacrosanity.annotateType(result, expectedType, c.config)
else: else:
result = semExprWithType(c, evaluated) result = semExprWithType(c, evaluated)
#result = fitNode(c, e.typ, result) inlined with special case: #result = fitNode(c, e.typ, result) inlined with special case:
@ -302,18 +302,18 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n) var e = semExprWithType(c, n)
if e == nil: return if e == nil: return
result = getConstExpr(c.module, e) result = getConstExpr(c.module, e, c.graph)
if result != nil: return if result != nil: return
let oldErrorCount = msgs.gErrorCounter let oldErrorCount = c.config.errorCounter
let oldErrorMax = msgs.gErrorMax let oldErrorMax = c.config.errorMax
let oldErrorOutputs = errorOutputs let oldErrorOutputs = errorOutputs
errorOutputs = {} errorOutputs = {}
msgs.gErrorMax = high(int) c.config.errorMax = high(int)
try: try:
result = evalConstExpr(c.module, c.cache, c.graph.config, e) result = evalConstExpr(c.module, c.cache, c.graph, e)
if result == nil or result.kind == nkEmpty: if result == nil or result.kind == nkEmpty:
result = nil result = nil
else: else:
@ -322,26 +322,29 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
except ERecoverableError: except ERecoverableError:
result = nil result = nil
msgs.gErrorCounter = oldErrorCount c.config.errorCounter = oldErrorCount
msgs.gErrorMax = oldErrorMax c.config.errorMax = oldErrorMax
errorOutputs = oldErrorOutputs errorOutputs = oldErrorOutputs
const
errConstExprExpected = "constant expression expected"
proc semConstExpr(c: PContext, n: PNode): PNode = proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n) var e = semExprWithType(c, n)
if e == nil: if e == nil:
localError(n.info, errConstExprExpected) localError(c.config, n.info, errConstExprExpected)
return n return n
result = getConstExpr(c.module, e) result = getConstExpr(c.module, e, c.graph)
if result == nil: if result == nil:
#if e.kind == nkEmpty: globalError(n.info, errConstExprExpected) #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected)
result = evalConstExpr(c.module, c.cache, c.graph.config, e) result = evalConstExpr(c.module, c.cache, c.graph, e)
if result == nil or result.kind == nkEmpty: if result == nil or result.kind == nkEmpty:
if e.info != n.info: if e.info != n.info:
pushInfoContext(n.info) pushInfoContext(n.info)
localError(e.info, errConstExprExpected) localError(c.config, e.info, errConstExprExpected)
popInfoContext() popInfoContext()
else: else:
localError(e.info, errConstExprExpected) localError(c.config, e.info, errConstExprExpected)
# error correction: # error correction:
result = e result = e
else: else:
@ -356,7 +359,7 @@ proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags): PNode =
else: else:
result = semExprWithType(c, n, flags) result = semExprWithType(c, n, flags)
if efPreferStatic in flags: if efPreferStatic in flags:
var evaluated = getConstExpr(c.module, result) var evaluated = getConstExpr(c.module, result, c.graph)
if evaluated != nil: return evaluated if evaluated != nil: return evaluated
evaluated = evalAtCompileTime(c, result) evaluated = evalAtCompileTime(c, result)
if evaluated != nil: return evaluated if evaluated != nil: return evaluated

View file

@ -10,7 +10,7 @@
## Implements type sanity checking for ASTs resulting from macros. Lots of ## Implements type sanity checking for ASTs resulting from macros. Lots of
## room for improvement here. ## room for improvement here.
import ast, astalgo, msgs, types import ast, astalgo, msgs, types, options
proc ithField(n: PNode, field: var int): PSym = proc ithField(n: PNode, field: var int): PSym =
result = nil result = nil
@ -20,7 +20,7 @@ proc ithField(n: PNode, field: var int): PSym =
result = ithField(n.sons[i], field) result = ithField(n.sons[i], field)
if result != nil: return if result != nil: return
of nkRecCase: of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "ithField") if n.sons[0].kind != nkSym: return
result = ithField(n.sons[0], field) result = ithField(n.sons[0], field)
if result != nil: return if result != nil: return
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
@ -28,13 +28,13 @@ proc ithField(n: PNode, field: var int): PSym =
of nkOfBranch, nkElse: of nkOfBranch, nkElse:
result = ithField(lastSon(n.sons[i]), field) result = ithField(lastSon(n.sons[i]), field)
if result != nil: return if result != nil: return
else: internalError(n.info, "ithField(record case branch)") else: discard
of nkSym: of nkSym:
if field == 0: result = n.sym if field == 0: result = n.sym
else: dec(field) else: dec(field)
else: discard else: discard
proc annotateType*(n: PNode, t: PType) = proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
let x = t.skipTypes(abstractInst+{tyRange}) let x = t.skipTypes(abstractInst+{tyRange})
# Note: x can be unequal to t and we need to be careful to use 't' # Note: x can be unequal to t and we need to be careful to use 't'
# to not to skip tyGenericInst # to not to skip tyGenericInst
@ -46,50 +46,50 @@ proc annotateType*(n: PNode, t: PType) =
var j = i-1 var j = i-1
let field = x.n.ithField(j) let field = x.n.ithField(j)
if field.isNil: if field.isNil:
globalError n.info, "invalid field at index " & $i globalError conf, n.info, "invalid field at index " & $i
else: else:
internalAssert(n.sons[i].kind == nkExprColonExpr) internalAssert(conf, n.sons[i].kind == nkExprColonExpr)
annotateType(n.sons[i].sons[1], field.typ) annotateType(n.sons[i].sons[1], field.typ, conf)
of nkPar, nkTupleConstr: of nkPar, nkTupleConstr:
if x.kind == tyTuple: if x.kind == tyTuple:
n.typ = t n.typ = t
for i in 0 ..< n.len: for i in 0 ..< n.len:
if i >= x.len: globalError n.info, "invalid field at index " & $i if i >= x.len: globalError conf, n.info, "invalid field at index " & $i
else: annotateType(n.sons[i], x.sons[i]) else: annotateType(n.sons[i], x.sons[i], conf)
elif x.kind == tyProc and x.callConv == ccClosure: elif x.kind == tyProc and x.callConv == ccClosure:
n.typ = t n.typ = t
else: else:
globalError(n.info, "() must have a tuple type") globalError(conf, n.info, "() must have a tuple type")
of nkBracket: of nkBracket:
if x.kind in {tyArray, tySequence, tyOpenArray}: if x.kind in {tyArray, tySequence, tyOpenArray}:
n.typ = t n.typ = t
for m in n: annotateType(m, x.elemType) for m in n: annotateType(m, x.elemType, conf)
else: else:
globalError(n.info, "[] must have some form of array type") globalError(conf, n.info, "[] must have some form of array type")
of nkCurly: of nkCurly:
if x.kind in {tySet}: if x.kind in {tySet}:
n.typ = t n.typ = t
for m in n: annotateType(m, x.elemType) for m in n: annotateType(m, x.elemType, conf)
else: else:
globalError(n.info, "{} must have the set type") globalError(conf, n.info, "{} must have the set type")
of nkFloatLit..nkFloat128Lit: of nkFloatLit..nkFloat128Lit:
if x.kind in {tyFloat..tyFloat128}: if x.kind in {tyFloat..tyFloat128}:
n.typ = t n.typ = t
else: else:
globalError(n.info, "float literal must have some float type") globalError(conf, n.info, "float literal must have some float type")
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}: if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}:
n.typ = t n.typ = t
else: else:
globalError(n.info, "integer literal must have some int type") globalError(conf, n.info, "integer literal must have some int type")
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if x.kind in {tyString, tyCString}: if x.kind in {tyString, tyCString}:
n.typ = t n.typ = t
else: else:
globalError(n.info, "string literal must be of some string type") globalError(conf, n.info, "string literal must be of some string type")
of nkNilLit: of nkNilLit:
if x.kind in NilableTypes: if x.kind in NilableTypes:
n.typ = t n.typ = t
else: else:
globalError(n.info, "nil literal must be of some pointer type") globalError(conf, n.info, "nil literal must be of some pointer type")
else: discard else: discard

View file

@ -23,7 +23,8 @@
import import
ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs, ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs,
renderer, types renderer, types, modulegraphs, options
from trees import getMagic from trees import getMagic
from strutils import `%` from strutils import `%`
@ -73,12 +74,15 @@ type
# the 'parallel' section # the 'parallel' section
currentSpawnId: int currentSpawnId: int
inLoop: int inLoop: int
graph: ModuleGraph
proc initAnalysisCtx(): AnalysisCtx = proc initAnalysisCtx(g: ModuleGraph): AnalysisCtx =
result.locals = @[] result.locals = @[]
result.slices = @[] result.slices = @[]
result.args = @[] result.args = @[]
result.guards = @[] result.guards.s = @[]
result.guards.o = initOperators(g)
result.graph = g
proc lookupSlot(c: AnalysisCtx; s: PSym): int = proc lookupSlot(c: AnalysisCtx; s: PSym): int =
for i in 0..<c.locals.len: for i in 0..<c.locals.len:
@ -117,7 +121,7 @@ proc checkLocal(c: AnalysisCtx; n: PNode) =
if isLocal(n): if isLocal(n):
let s = c.lookupSlot(n.sym) let s = c.lookupSlot(n.sym)
if s >= 0 and c.locals[s].stride != nil: if s >= 0 and c.locals[s].stride != nil:
localError(n.info, "invalid usage of counter after increment") localError(c.graph.config, n.info, "invalid usage of counter after increment")
else: else:
for i in 0 ..< n.safeLen: checkLocal(c, n.sons[i]) for i in 0 ..< n.safeLen: checkLocal(c, n.sons[i])
@ -126,14 +130,14 @@ template `?`(x): untyped = x.renderTree
proc checkLe(c: AnalysisCtx; a, b: PNode) = proc checkLe(c: AnalysisCtx; a, b: PNode) =
case proveLe(c.guards, a, b) case proveLe(c.guards, a, b)
of impUnknown: of impUnknown:
localError(a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)") localError(c.graph.config, a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)")
of impYes: discard of impYes: discard
of impNo: of impNo:
localError(a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)") localError(c.graph.config, a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)")
proc checkBounds(c: AnalysisCtx; arr, idx: PNode) = proc checkBounds(c: AnalysisCtx; arr, idx: PNode) =
checkLe(c, arr.lowBound, idx) checkLe(c, arr.lowBound, idx)
checkLe(c, idx, arr.highBound) checkLe(c, idx, arr.highBound(c.guards.o))
proc addLowerBoundAsFacts(c: var AnalysisCtx) = proc addLowerBoundAsFacts(c: var AnalysisCtx) =
for v in c.locals: for v in c.locals:
@ -142,34 +146,34 @@ proc addLowerBoundAsFacts(c: var AnalysisCtx) =
proc addSlice(c: var AnalysisCtx; n: PNode; x, le, ri: PNode) = proc addSlice(c: var AnalysisCtx; n: PNode; x, le, ri: PNode) =
checkLocal(c, n) checkLocal(c, n)
let le = le.canon let le = le.canon(c.guards.o)
let ri = ri.canon let ri = ri.canon(c.guards.o)
# perform static bounds checking here; and not later! # perform static bounds checking here; and not later!
let oldState = c.guards.len let oldState = c.guards.s.len
addLowerBoundAsFacts(c) addLowerBoundAsFacts(c)
c.checkBounds(x, le) c.checkBounds(x, le)
c.checkBounds(x, ri) c.checkBounds(x, ri)
c.guards.setLen(oldState) c.guards.s.setLen(oldState)
c.slices.add((x, le, ri, c.currentSpawnId, c.inLoop > 0)) c.slices.add((x, le, ri, c.currentSpawnId, c.inLoop > 0))
proc overlap(m: TModel; x,y,c,d: PNode) = proc overlap(m: TModel; conf: ConfigRef; x,y,c,d: PNode) =
# X..Y and C..D overlap iff (X <= D and C <= Y) # X..Y and C..D overlap iff (X <= D and C <= Y)
case proveLe(m, c, y) case proveLe(m, c, y)
of impUnknown: of impUnknown:
case proveLe(m, x, d) case proveLe(m, x, d)
of impNo: discard of impNo: discard
of impUnknown, impYes: of impUnknown, impYes:
localError(x.info, localError(conf, x.info,
"cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" % "cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
[?c, ?y, ?x, ?y, ?c, ?d]) [?c, ?y, ?x, ?y, ?c, ?d])
of impYes: of impYes:
case proveLe(m, x, d) case proveLe(m, x, d)
of impUnknown: of impUnknown:
localError(x.info, localError(conf, x.info,
"cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" % "cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
[?x, ?d, ?x, ?y, ?c, ?d]) [?x, ?d, ?x, ?y, ?c, ?d])
of impYes: of impYes:
localError(x.info, "($#)..($#) not disjoint from ($#)..($#)" % localError(conf, x.info, "($#)..($#) not disjoint from ($#)..($#)" %
[?c, ?y, ?x, ?y, ?c, ?d]) [?c, ?y, ?x, ?y, ?c, ?d])
of impNo: discard of impNo: discard
of impNo: discard of impNo: discard
@ -187,7 +191,7 @@ proc subStride(c: AnalysisCtx; n: PNode): PNode =
if isLocal(n): if isLocal(n):
let s = c.lookupSlot(n.sym) let s = c.lookupSlot(n.sym)
if s >= 0 and c.locals[s].stride != nil: if s >= 0 and c.locals[s].stride != nil:
result = n +@ c.locals[s].stride.intVal result = buildAdd(n, c.locals[s].stride.intVal, c.guards.o)
else: else:
result = n result = n
elif n.safeLen > 0: elif n.safeLen > 0:
@ -203,7 +207,7 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) =
addLowerBoundAsFacts(c) addLowerBoundAsFacts(c)
# Every slice used in a loop needs to be disjoint with itself: # Every slice used in a loop needs to be disjoint with itself:
for x,a,b,id,inLoop in items(c.slices): for x,a,b,id,inLoop in items(c.slices):
if inLoop: overlap(c.guards, a,b, c.subStride(a), c.subStride(b)) if inLoop: overlap(c.guards, c.graph.config, a,b, c.subStride(a), c.subStride(b))
# Another tricky example is: # Another tricky example is:
# while true: # while true:
# spawn f(a[i]) # spawn f(a[i])
@ -231,21 +235,21 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) =
# XXX strictly speaking, 'or' is not correct here and it needs to # XXX strictly speaking, 'or' is not correct here and it needs to
# be 'and'. However this prevents too many obviously correct programs # be 'and'. However this prevents too many obviously correct programs
# like f(a[0..x]); for i in x+1 .. a.high: f(a[i]) # like f(a[0..x]); for i in x+1 .. a.high: f(a[i])
overlap(c.guards, x.a, x.b, y.a, y.b) overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b)
elif (let k = simpleSlice(x.a, x.b); let m = simpleSlice(y.a, y.b); elif (let k = simpleSlice(x.a, x.b); let m = simpleSlice(y.a, y.b);
k >= 0 and m >= 0): k >= 0 and m >= 0):
# ah I cannot resist the temptation and add another sweet heuristic: # ah I cannot resist the temptation and add another sweet heuristic:
# if both slices have the form (i+k)..(i+k) and (i+m)..(i+m) we # if both slices have the form (i+k)..(i+k) and (i+m)..(i+m) we
# check they are disjoint and k < stride and m < stride: # check they are disjoint and k < stride and m < stride:
overlap(c.guards, x.a, x.b, y.a, y.b) overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b)
let stride = min(c.stride(x.a), c.stride(y.a)) let stride = min(c.stride(x.a), c.stride(y.a))
if k < stride and m < stride: if k < stride and m < stride:
discard discard
else: else:
localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" % localError(c.graph.config, x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
[?x.a, ?x.b, ?y.a, ?y.b]) [?x.a, ?x.b, ?y.a, ?y.b])
else: else:
localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" % localError(c.graph.config, x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
[?x.a, ?x.b, ?y.a, ?y.b]) [?x.a, ?x.b, ?y.a, ?y.b])
proc analyse(c: var AnalysisCtx; n: PNode) proc analyse(c: var AnalysisCtx; n: PNode)
@ -292,31 +296,31 @@ proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
proc analyseCase(c: var AnalysisCtx; n: PNode) = proc analyseCase(c: var AnalysisCtx; n: PNode) =
analyse(c, n.sons[0]) analyse(c, n.sons[0])
let oldFacts = c.guards.len let oldFacts = c.guards.s.len
for i in 1..<n.len: for i in 1..<n.len:
let branch = n.sons[i] let branch = n.sons[i]
setLen(c.guards, oldFacts) setLen(c.guards.s, oldFacts)
addCaseBranchFacts(c.guards, n, i) addCaseBranchFacts(c.guards, n, i)
for i in 0 ..< branch.len: for i in 0 ..< branch.len:
analyse(c, branch.sons[i]) analyse(c, branch.sons[i])
setLen(c.guards, oldFacts) setLen(c.guards.s, oldFacts)
proc analyseIf(c: var AnalysisCtx; n: PNode) = proc analyseIf(c: var AnalysisCtx; n: PNode) =
analyse(c, n.sons[0].sons[0]) analyse(c, n.sons[0].sons[0])
let oldFacts = c.guards.len let oldFacts = c.guards.s.len
addFact(c.guards, canon(n.sons[0].sons[0])) addFact(c.guards, canon(n.sons[0].sons[0], c.guards.o))
analyse(c, n.sons[0].sons[1]) analyse(c, n.sons[0].sons[1])
for i in 1..<n.len: for i in 1..<n.len:
let branch = n.sons[i] let branch = n.sons[i]
setLen(c.guards, oldFacts) setLen(c.guards.s, oldFacts)
for j in 0..i-1: for j in 0..i-1:
addFactNeg(c.guards, canon(n.sons[j].sons[0])) addFactNeg(c.guards, canon(n.sons[j].sons[0], c.guards.o))
if branch.len > 1: if branch.len > 1:
addFact(c.guards, canon(branch.sons[0])) addFact(c.guards, canon(branch.sons[0], c.guards.o))
for i in 0 ..< branch.len: for i in 0 ..< branch.len:
analyse(c, branch.sons[i]) analyse(c, branch.sons[i])
setLen(c.guards, oldFacts) setLen(c.guards.s, oldFacts)
proc analyse(c: var AnalysisCtx; n: PNode) = proc analyse(c: var AnalysisCtx; n: PNode) =
case n.kind case n.kind
@ -349,7 +353,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
c.addSlice(n, n[0], n[1], n[1]) c.addSlice(n, n[0], n[1], n[1])
analyseSons(c, n) analyseSons(c, n)
of nkReturnStmt, nkRaiseStmt, nkTryStmt: of nkReturnStmt, nkRaiseStmt, nkTryStmt:
localError(n.info, "invalid control flow for 'parallel'") localError(c.graph.config, n.info, "invalid control flow for 'parallel'")
# 'break' that leaves the 'parallel' section is not valid either # 'break' that leaves the 'parallel' section is not valid either
# or maybe we should generate a 'try' XXX # or maybe we should generate a 'try' XXX
of nkVarSection, nkLetSection: of nkVarSection, nkLetSection:
@ -365,7 +369,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
if it[j].isLocal: if it[j].isLocal:
let slot = c.getSlot(it[j].sym) let slot = c.getSlot(it[j].sym)
if slot.lower.isNil: slot.lower = value if slot.lower.isNil: slot.lower = value
else: internalError(it.info, "slot already has a lower bound") else: internalError(c.graph.config, it.info, "slot already has a lower bound")
if not isSpawned: analyse(c, value) if not isSpawned: analyse(c, value)
of nkCaseStmt: analyseCase(c, n) of nkCaseStmt: analyseCase(c, n)
of nkWhen, nkIfStmt, nkIfExpr: analyseIf(c, n) of nkWhen, nkIfStmt, nkIfExpr: analyseIf(c, n)
@ -378,14 +382,14 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
else: else:
# loop may never execute: # loop may never execute:
let oldState = c.locals.len let oldState = c.locals.len
let oldFacts = c.guards.len let oldFacts = c.guards.s.len
addFact(c.guards, canon(n.sons[0])) addFact(c.guards, canon(n.sons[0], c.guards.o))
analyse(c, n.sons[1]) analyse(c, n.sons[1])
setLen(c.locals, oldState) setLen(c.locals, oldState)
setLen(c.guards, oldFacts) setLen(c.guards.s, oldFacts)
# we know after the loop the negation holds: # we know after the loop the negation holds:
if not hasSubnodeWith(n.sons[1], nkBreakStmt): if not hasSubnodeWith(n.sons[1], nkBreakStmt):
addFactNeg(c.guards, canon(n.sons[0])) addFactNeg(c.guards, canon(n.sons[0], c.guards.o))
dec c.inLoop dec c.inLoop
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef: nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef:
@ -393,13 +397,13 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
else: else:
analyseSons(c, n) analyseSons(c, n)
proc transformSlices(n: PNode): PNode = proc transformSlices(g: ModuleGraph; n: PNode): PNode =
if n.kind in nkCallKinds and n[0].kind == nkSym: if n.kind in nkCallKinds and n[0].kind == nkSym:
let op = n[0].sym let op = n[0].sym
if op.name.s == "[]" and op.fromSystem: if op.name.s == "[]" and op.fromSystem:
result = copyNode(n) result = copyNode(n)
let opSlice = newSymNode(createMagic("slice", mSlice)) let opSlice = newSymNode(createMagic(g, "slice", mSlice))
opSlice.typ = getSysType(tyInt) opSlice.typ = getSysType(g, n.info, tyInt)
result.add opSlice result.add opSlice
result.add n[1] result.add n[1]
let slice = n[2].skipStmtList let slice = n[2].skipStmtList
@ -409,49 +413,49 @@ proc transformSlices(n: PNode): PNode =
if n.safeLen > 0: if n.safeLen > 0:
result = shallowCopy(n) result = shallowCopy(n)
for i in 0 ..< n.len: for i in 0 ..< n.len:
result.sons[i] = transformSlices(n.sons[i]) result.sons[i] = transformSlices(g, n.sons[i])
else: else:
result = n result = n
proc transformSpawn(owner: PSym; n, barrier: PNode): PNode proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode
proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode = proc transformSpawnSons(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode =
result = shallowCopy(n) result = shallowCopy(n)
for i in 0 ..< n.len: for i in 0 ..< n.len:
result.sons[i] = transformSpawn(owner, n.sons[i], barrier) result.sons[i] = transformSpawn(g, owner, n.sons[i], barrier)
proc transformSpawn(owner: PSym; n, barrier: PNode): PNode = proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode =
case n.kind case n.kind
of nkVarSection, nkLetSection: of nkVarSection, nkLetSection:
result = nil result = nil
for it in n: for it in n:
let b = it.lastSon let b = it.lastSon
if getMagic(b) == mSpawn: if getMagic(b) == mSpawn:
if it.len != 3: localError(it.info, "invalid context for 'spawn'") if it.len != 3: localError(g.config, it.info, "invalid context for 'spawn'")
let m = transformSlices(b) let m = transformSlices(g, b)
if result.isNil: if result.isNil:
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
result.add n result.add n
let t = b[1][0].typ.sons[0] let t = b[1][0].typ.sons[0]
if spawnResult(t, true) == srByVar: if spawnResult(t, true) == srByVar:
result.add wrapProcForSpawn(owner, m, b.typ, barrier, it[0]) result.add wrapProcForSpawn(g, owner, m, b.typ, barrier, it[0])
it.sons[it.len-1] = emptyNode it.sons[it.len-1] = emptyNode
else: else:
it.sons[it.len-1] = wrapProcForSpawn(owner, m, b.typ, barrier, nil) it.sons[it.len-1] = wrapProcForSpawn(g, owner, m, b.typ, barrier, nil)
if result.isNil: result = n if result.isNil: result = n
of nkAsgn, nkFastAsgn: of nkAsgn, nkFastAsgn:
let b = n[1] let b = n[1]
if getMagic(b) == mSpawn and (let t = b[1][0].typ.sons[0]; if getMagic(b) == mSpawn and (let t = b[1][0].typ.sons[0];
spawnResult(t, true) == srByVar): spawnResult(t, true) == srByVar):
let m = transformSlices(b) let m = transformSlices(g, b)
return wrapProcForSpawn(owner, m, b.typ, barrier, n[0]) return wrapProcForSpawn(g, owner, m, b.typ, barrier, n[0])
result = transformSpawnSons(owner, n, barrier) result = transformSpawnSons(g, owner, n, barrier)
of nkCallKinds: of nkCallKinds:
if getMagic(n) == mSpawn: if getMagic(n) == mSpawn:
result = transformSlices(n) result = transformSlices(g, n)
return wrapProcForSpawn(owner, result, n.typ, barrier, nil) return wrapProcForSpawn(g, owner, result, n.typ, barrier, nil)
result = transformSpawnSons(owner, n, barrier) result = transformSpawnSons(g, owner, n, barrier)
elif n.safeLen > 0: elif n.safeLen > 0:
result = transformSpawnSons(owner, n, barrier) result = transformSpawnSons(g, owner, n, barrier)
else: else:
result = n result = n
@ -461,7 +465,7 @@ proc checkArgs(a: var AnalysisCtx; n: PNode) =
proc generateAliasChecks(a: AnalysisCtx; result: PNode) = proc generateAliasChecks(a: AnalysisCtx; result: PNode) =
discard "too implement" discard "too implement"
proc liftParallel*(owner: PSym; n: PNode): PNode = proc liftParallel*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
# this needs to be called after the 'for' loop elimination # this needs to be called after the 'for' loop elimination
# first pass: # first pass:
@ -470,17 +474,17 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
# - detect used arguments # - detect used arguments
#echo "PAR ", renderTree(n) #echo "PAR ", renderTree(n)
var a = initAnalysisCtx() var a = initAnalysisCtx(g)
let body = n.lastSon let body = n.lastSon
analyse(a, body) analyse(a, body)
if a.spawns == 0: if a.spawns == 0:
localError(n.info, "'parallel' section without 'spawn'") localError(g.config, n.info, "'parallel' section without 'spawn'")
checkSlicesAreDisjoint(a) checkSlicesAreDisjoint(a)
checkArgs(a, body) checkArgs(a, body)
var varSection = newNodeI(nkVarSection, n.info) var varSection = newNodeI(nkVarSection, n.info)
var temp = newSym(skTemp, getIdent"barrier", owner, n.info) var temp = newSym(skTemp, getIdent"barrier", owner, n.info)
temp.typ = magicsys.getCompilerProc("Barrier").typ temp.typ = magicsys.getCompilerProc(g, "Barrier").typ
incl(temp.flags, sfFromGeneric) incl(temp.flags, sfFromGeneric)
let tempNode = newSymNode(temp) let tempNode = newSymNode(temp)
varSection.addVar tempNode varSection.addVar tempNode
@ -489,6 +493,6 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
generateAliasChecks(a, result) generateAliasChecks(a, result)
result.add varSection result.add varSection
result.add callCodegenProc("openBarrier", barrier) result.add callCodegenProc(g, "openBarrier", barrier)
result.add transformSpawn(owner, body, barrier) result.add transformSpawn(g, owner, body, barrier)
result.add callCodegenProc("closeBarrier", barrier) result.add callCodegenProc(g, "closeBarrier", barrier)

View file

@ -19,7 +19,7 @@ import ast except getstr
import import
strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes,
parser, vmdeps, idents, trees, renderer, options, transf, parseutils, parser, vmdeps, idents, trees, renderer, options, transf, parseutils,
vmmarshal, gorgeimpl vmmarshal, gorgeimpl, configuration
from semfold import leValueConv, ordinalValToString from semfold import leValueConv, ordinalValToString
from evaltempl import evalTemplate from evaltempl import evalTemplate
@ -81,16 +81,16 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
msgWriteln(s) msgWriteln(s)
proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
msg: TMsgKind, arg = "", n: PNode = nil) = msg: string, n: PNode = nil) =
msgWriteln("stack trace: (most recent call last)") msgWriteln("stack trace: (most recent call last)")
stackTraceAux(c, tos, pc) stackTraceAux(c, tos, pc)
# XXX test if we want 'globalError' for every mode # XXX test if we want 'globalError' for every mode
let lineInfo = if n == nil: c.debug[pc] else: n.info let lineInfo = if n == nil: c.debug[pc] else: n.info
if c.mode == emRepl: globalError(lineInfo, msg, arg) if c.mode == emRepl: globalError(c.config, lineInfo, msg)
else: localError(lineInfo, msg, arg) else: localError(c.config, lineInfo, msg)
proc bailOut(c: PCtx; tos: PStackFrame) = proc bailOut(c: PCtx; tos: PStackFrame) =
stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX, stackTrace(c, tos, c.exceptionInstr, "unhandled exception: " &
c.currentExceptionA.sons[3].skipColon.strVal) c.currentExceptionA.sons[3].skipColon.strVal)
when not defined(nimComputedGoto): when not defined(nimComputedGoto):
@ -308,7 +308,7 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
return pc return pc
return -1 return -1
proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool = proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
if desttyp.kind == tyString: if desttyp.kind == tyString:
if dest.kind != rkNode: if dest.kind != rkNode:
myreset(dest) myreset(dest)
@ -323,7 +323,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
else: else:
for i in 0..<n.len: for i in 0..<n.len:
if n.sons[i].kind != nkSym: internalError("opConv for enum") if n.sons[i].kind != nkSym: internalError(c.config, "opConv for enum")
let f = n.sons[i].sym let f = n.sons[i].sym
if f.position == x: if f.position == x:
dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
@ -353,7 +353,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
of tyChar: of tyChar:
dest.node.strVal = $chr(src.intVal) dest.node.strVal = $chr(src.intVal)
else: else:
internalError("cannot convert to string " & desttyp.typeToString) internalError(c.config, "cannot convert to string " & desttyp.typeToString)
else: else:
case skipTypes(desttyp, abstractRange).kind case skipTypes(desttyp, abstractRange).kind
of tyInt..tyInt64: of tyInt..tyInt64:
@ -404,7 +404,7 @@ template handleJmpBack() {.dirty.} =
else: else:
msgWriteln("stack trace: (most recent call last)") msgWriteln("stack trace: (most recent call last)")
stackTraceAux(c, tos, pc) stackTraceAux(c, tos, pc)
globalError(c.debug[pc], errTooManyIterations) globalError(c.config, c.debug[pc], errTooManyIterations)
dec(c.loopIterations) dec(c.loopIterations)
proc recSetFlagIsRef(arg: PNode) = proc recSetFlagIsRef(arg: PNode) =
@ -434,6 +434,17 @@ proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) =
for i in oldLen ..< newLen: for i in oldLen ..< newLen:
node.sons[i] = newNodeI(typeKind, info) node.sons[i] = newNodeI(typeKind, info)
const
errIndexOutOfBounds = "index ouf of bounds"
errNilAccess = "attempt to access a nil address"
errOverOrUnderflow = "over- or underflow"
errConstantDivisionByZero = "division by zero"
errIllegalConvFromXtoY = "illegal conversion from '$1' to '$2'"
errTooManyIterations = "interpretation requires too many iterations; " &
"if you are sure this is not a bug in your code edit " &
"compiler/vmdef.MaxLoopIterations and rebuild the compiler"
errFieldXNotFound = "node lacks field: "
proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var pc = start var pc = start
var tos = tos var tos = tos
@ -447,7 +458,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
#if c.traceActive: #if c.traceActive:
when traceCode: when traceCode:
echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
# message(c.debug[pc], warnUser, "Trace") # message(c.config, c.debug[pc], warnUser, "Trace")
case instr.opcode case instr.opcode
of opcEof: return regs[ra] of opcEof: return regs[ra]
@ -580,7 +591,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[rb].kind == rkNode: if regs[rb].kind == rkNode:
regs[ra].nodeAddr = addr(regs[rb].node) regs[ra].nodeAddr = addr(regs[rb].node)
else: else:
stackTrace(c, tos, pc, errGenerated, "limited VM support for 'addr'") stackTrace(c, tos, pc, "limited VM support for 'addr'")
of opcLdDeref: of opcLdDeref:
# a = b[] # a = b[]
let ra = instr.regA let ra = instr.regA
@ -623,7 +634,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
stackTrace(c, tos, pc, errOverOrUnderflow) stackTrace(c, tos, pc, errOverOrUnderflow)
of opcAddImmInt: of opcAddImmInt:
decodeBImm(rkInt) decodeBImm(rkInt)
#message(c.debug[pc], warnUser, "came here") #message(c.config, c.debug[pc], warnUser, "came here")
#debug regs[rb].node #debug regs[rb].node
let let
bVal = regs[rb].intVal bVal = regs[rb].intVal
@ -892,7 +903,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit) regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
else: copyTree(a.sym.ast) else: copyTree(a.sym.ast)
else: else:
stackTrace(c, tos, pc, errGenerated, "node is not a symbol") stackTrace(c, tos, pc, "node is not a symbol")
of opcEcho: of opcEcho:
let rb = instr.regB let rb = instr.regB
if rb == 1: if rb == 1:
@ -931,8 +942,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let rc = instr.regC let rc = instr.regC
if not (leValueConv(regs[rb].regToNode, regs[ra].regToNode) and if not (leValueConv(regs[rb].regToNode, regs[ra].regToNode) and
leValueConv(regs[ra].regToNode, regs[rc].regToNode)): leValueConv(regs[ra].regToNode, regs[rc].regToNode)):
stackTrace(c, tos, pc, errGenerated, stackTrace(c, tos, pc,
msgKindToString(errIllegalConvFromXtoY) % [ errIllegalConvFromXtoY % [
$regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"]) $regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"])
of opcIndCall, opcIndCallAsgn: of opcIndCall, opcIndCallAsgn:
# dest = call regStart, n; where regStart = fn, arg1, ... # dest = call regStart, n; where regStart = fn, arg1, ...
@ -949,20 +960,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
currentLineInfo: c.debug[pc])) currentLineInfo: c.debug[pc]))
elif sfImportc in prc.flags: elif sfImportc in prc.flags:
if allowFFI notin c.features: if allowFFI notin c.features:
globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI") globalError(c.config, c.debug[pc], "VM not allowed to do FFI")
# we pass 'tos.slots' instead of 'regs' so that the compiler can keep # we pass 'tos.slots' instead of 'regs' so that the compiler can keep
# 'regs' in a register: # 'regs' in a register:
when hasFFI: when hasFFI:
let prcValue = c.globals.sons[prc.position-1] let prcValue = c.globals.sons[prc.position-1]
if prcValue.kind == nkEmpty: if prcValue.kind == nkEmpty:
globalError(c.debug[pc], errGenerated, "canot run " & prc.name.s) globalError(c.config, c.debug[pc], "canot run " & prc.name.s)
let newValue = callForeignFunction(prcValue, prc.typ, tos.slots, let newValue = callForeignFunction(prcValue, prc.typ, tos.slots,
rb+1, rc-1, c.debug[pc]) rb+1, rc-1, c.debug[pc])
if newValue.kind != nkEmpty: if newValue.kind != nkEmpty:
assert instr.opcode == opcIndCallAsgn assert instr.opcode == opcIndCallAsgn
putIntoReg(regs[ra], newValue) putIntoReg(regs[ra], newValue)
else: else:
globalError(c.debug[pc], errGenerated, "VM not built with FFI support") globalError(c.config, c.debug[pc], "VM not built with FFI support")
elif prc.kind != skTemplate: elif prc.kind != skTemplate:
let newPc = compile(c, prc) let newPc = compile(c, prc)
# tricky: a recursion is also a jump back, so we use the same # tricky: a recursion is also a jump back, so we use the same
@ -972,7 +983,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos) var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
newSeq(newFrame.slots, prc.offset+ord(isClosure)) newSeq(newFrame.slots, prc.offset+ord(isClosure))
if not isEmptyType(prc.typ.sons[0]) or prc.kind == skMacro: if not isEmptyType(prc.typ.sons[0]) or prc.kind == skMacro:
putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info)) putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info, c.config))
for i in 1 .. rc-1: for i in 1 .. rc-1:
newFrame.slots[i] = regs[rb+i] newFrame.slots[i] = regs[rb+i]
if isClosure: if isClosure:
@ -994,7 +1005,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let node = regs[rb+i].regToNode let node = regs[rb+i].regToNode
node.info = c.debug[pc] node.info = c.debug[pc]
macroCall.add(node) macroCall.add(node)
var a = evalTemplate(macroCall, prc, genSymOwner) var a = evalTemplate(macroCall, prc, genSymOwner, c.config)
if a.kind == nkStmtList and a.len == 1: a = a[0] if a.kind == nkStmtList and a.len == 1: a = a[0]
a.recSetFlagIsRef a.recSetFlagIsRef
ensureKind(rkNode) ensureKind(rkNode)
@ -1079,7 +1090,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcNew: of opcNew:
ensureKind(rkNode) ensureKind(rkNode)
let typ = c.types[instr.regBx - wordExcess] let typ = c.types[instr.regBx - wordExcess]
regs[ra].node = getNullValue(typ, c.debug[pc]) regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
regs[ra].node.flags.incl nfIsRef regs[ra].node.flags.incl nfIsRef
of opcNewSeq: of opcNewSeq:
let typ = c.types[instr.regBx - wordExcess] let typ = c.types[instr.regBx - wordExcess]
@ -1091,7 +1102,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node.typ = typ regs[ra].node.typ = typ
newSeq(regs[ra].node.sons, count) newSeq(regs[ra].node.sons, count)
for i in 0 ..< count: for i in 0 ..< count:
regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc]) regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc], c.config)
of opcNewStr: of opcNewStr:
decodeB(rkNode) decodeB(rkNode)
regs[ra].node = newNodeI(nkStrLit, c.debug[pc]) regs[ra].node = newNodeI(nkStrLit, c.debug[pc])
@ -1103,7 +1114,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcLdNull: of opcLdNull:
ensureKind(rkNode) ensureKind(rkNode)
let typ = c.types[instr.regBx - wordExcess] let typ = c.types[instr.regBx - wordExcess]
regs[ra].node = getNullValue(typ, c.debug[pc]) regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
# opcLdNull really is the gist of the VM's problems: should it load # opcLdNull really is the gist of the VM's problems: should it load
# a fresh null to regs[ra].node or to regs[ra].node[]? This really # a fresh null to regs[ra].node or to regs[ra].node[]? This really
# depends on whether regs[ra] represents the variable itself or wether # depends on whether regs[ra] represents the variable itself or wether
@ -1150,7 +1161,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node.strVal = renderTree(regs[rb].regToNode, {renderNoComments, renderDocComments}) regs[ra].node.strVal = renderTree(regs[rb].regToNode, {renderNoComments, renderDocComments})
of opcQuit: of opcQuit:
if c.mode in {emRepl, emStaticExpr, emStaticStmt}: if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
message(c.debug[pc], hintQuitCalled) message(c.config, c.debug[pc], hintQuitCalled)
msgQuit(int8(getOrdValue(regs[ra].regToNode))) msgQuit(int8(getOrdValue(regs[ra].regToNode)))
else: else:
return TFullReg(kind: rkNone) return TFullReg(kind: rkNone)
@ -1176,14 +1187,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess) if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess)
else: c.setLenSeq(regs[ra].node, newLen, c.debug[pc]) else: c.setLenSeq(regs[ra].node, newLen, c.debug[pc])
of opcReset: of opcReset:
internalError(c.debug[pc], "too implement") internalError(c.config, c.debug[pc], "too implement")
of opcNarrowS: of opcNarrowS:
decodeB(rkInt) decodeB(rkInt)
let min = -(1.BiggestInt shl (rb-1)) let min = -(1.BiggestInt shl (rb-1))
let max = (1.BiggestInt shl (rb-1))-1 let max = (1.BiggestInt shl (rb-1))-1
if regs[ra].intVal < min or regs[ra].intVal > max: if regs[ra].intVal < min or regs[ra].intVal > max:
stackTrace(c, tos, pc, errGenerated, stackTrace(c, tos, pc, "unhandled exception: value out of range")
msgKindToString(errUnhandledExceptionX) % "value out of range")
of opcNarrowU: of opcNarrowU:
decodeB(rkInt) decodeB(rkInt)
regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1) regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1)
@ -1217,7 +1227,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if u.kind notin {nkEmpty..nkNilLit}: if u.kind notin {nkEmpty..nkNilLit}:
u.add(regs[rc].node) u.add(regs[rc].node)
else: else:
stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind) stackTrace(c, tos, pc, "cannot add to node kind: " & $u.kind)
regs[ra].node = u regs[ra].node = u
of opcNAddMultiple: of opcNAddMultiple:
decodeBC(rkNode) decodeBC(rkNode)
@ -1227,7 +1237,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
# XXX can be optimized: # XXX can be optimized:
for i in 0..<x.len: u.add(x.sons[i]) for i in 0..<x.len: u.add(x.sons[i])
else: else:
stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind) stackTrace(c, tos, pc, "cannot add to node kind: " & $u.kind)
regs[ra].node = u regs[ra].node = u
of opcNKind: of opcNKind:
decodeB(rkInt) decodeB(rkInt)
@ -1239,34 +1249,34 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if a.kind == nkSym: if a.kind == nkSym:
regs[ra].intVal = ord(a.sym.kind) regs[ra].intVal = ord(a.sym.kind)
else: else:
stackTrace(c, tos, pc, errGenerated, "node is not a symbol") stackTrace(c, tos, pc, "node is not a symbol")
c.comesFromHeuristic = regs[rb].node.info c.comesFromHeuristic = regs[rb].node.info
of opcNIntVal: of opcNIntVal:
decodeB(rkInt) decodeB(rkInt)
let a = regs[rb].node let a = regs[rb].node
case a.kind case a.kind
of nkCharLit..nkUInt64Lit: regs[ra].intVal = a.intVal of nkCharLit..nkUInt64Lit: regs[ra].intVal = a.intVal
else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal") else: stackTrace(c, tos, pc, errFieldXNotFound & "intVal")
of opcNFloatVal: of opcNFloatVal:
decodeB(rkFloat) decodeB(rkFloat)
let a = regs[rb].node let a = regs[rb].node
case a.kind case a.kind
of nkFloatLit..nkFloat64Lit: regs[ra].floatVal = a.floatVal of nkFloatLit..nkFloat64Lit: regs[ra].floatVal = a.floatVal
else: stackTrace(c, tos, pc, errFieldXNotFound, "floatVal") else: stackTrace(c, tos, pc, errFieldXNotFound & "floatVal")
of opcNSymbol: of opcNSymbol:
decodeB(rkNode) decodeB(rkNode)
let a = regs[rb].node let a = regs[rb].node
if a.kind == nkSym: if a.kind == nkSym:
regs[ra].node = copyNode(a) regs[ra].node = copyNode(a)
else: else:
stackTrace(c, tos, pc, errFieldXNotFound, "symbol") stackTrace(c, tos, pc, errFieldXNotFound & "symbol")
of opcNIdent: of opcNIdent:
decodeB(rkNode) decodeB(rkNode)
let a = regs[rb].node let a = regs[rb].node
if a.kind == nkIdent: if a.kind == nkIdent:
regs[ra].node = copyNode(a) regs[ra].node = copyNode(a)
else: else:
stackTrace(c, tos, pc, errFieldXNotFound, "ident") stackTrace(c, tos, pc, errFieldXNotFound & "ident")
of opcNGetType: of opcNGetType:
let rb = instr.regB let rb = instr.regB
let rc = instr.regC let rc = instr.regC
@ -1277,28 +1287,28 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[rb].kind == rkNode and regs[rb].node.typ != nil: if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc]) regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
else: else:
stackTrace(c, tos, pc, errGenerated, "node has no type") stackTrace(c, tos, pc, "node has no type")
of 1: of 1:
# typeKind opcode: # typeKind opcode:
ensureKind(rkInt) ensureKind(rkInt)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil: if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].intVal = ord(regs[rb].node.typ.kind) regs[ra].intVal = ord(regs[rb].node.typ.kind)
#else: #else:
# stackTrace(c, tos, pc, errGenerated, "node has no type") # stackTrace(c, tos, pc, "node has no type")
of 2: of 2:
# getTypeInst opcode: # getTypeInst opcode:
ensureKind(rkNode) ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil: if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeInstToAst(regs[rb].node.typ, c.debug[pc]) regs[ra].node = opMapTypeInstToAst(regs[rb].node.typ, c.debug[pc])
else: else:
stackTrace(c, tos, pc, errGenerated, "node has no type") stackTrace(c, tos, pc, "node has no type")
else: else:
# getTypeImpl opcode: # getTypeImpl opcode:
ensureKind(rkNode) ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil: if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeImplToAst(regs[rb].node.typ, c.debug[pc]) regs[ra].node = opMapTypeImplToAst(regs[rb].node.typ, c.debug[pc])
else: else:
stackTrace(c, tos, pc, errGenerated, "node has no type") stackTrace(c, tos, pc, "node has no type")
of opcNStrVal: of opcNStrVal:
decodeB(rkNode) decodeB(rkNode)
createStr regs[ra] createStr regs[ra]
@ -1313,12 +1323,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of nkSym: of nkSym:
regs[ra].node.strVal = a.sym.name.s regs[ra].node.strVal = a.sym.name.s
else: else:
stackTrace(c, tos, pc, errFieldXNotFound, "strVal") stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
of opcSlurp: of opcSlurp:
decodeB(rkNode) decodeB(rkNode)
createStr regs[ra] createStr regs[ra]
regs[ra].node.strVal = opSlurp(regs[rb].node.strVal, c.debug[pc], regs[ra].node.strVal = opSlurp(regs[rb].node.strVal, c.debug[pc],
c.module) c.module, c.config)
of opcGorge: of opcGorge:
decodeBC(rkNode) decodeBC(rkNode)
inc pc inc pc
@ -1327,29 +1337,30 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
createStr regs[ra] createStr regs[ra]
regs[ra].node.strVal = opGorge(regs[rb].node.strVal, regs[ra].node.strVal = opGorge(regs[rb].node.strVal,
regs[rc].node.strVal, regs[rd].node.strVal, regs[rc].node.strVal, regs[rd].node.strVal,
c.debug[pc])[0] c.debug[pc], c.config)[0]
of opcNError: of opcNError:
decodeB(rkNode) decodeB(rkNode)
let a = regs[ra].node let a = regs[ra].node
let b = regs[rb].node let b = regs[rb].node
stackTrace(c, tos, pc, errUser, a.strVal, if b.kind == nkNilLit: nil else: b) stackTrace(c, tos, pc, a.strVal, if b.kind == nkNilLit: nil else: b)
of opcNWarning: of opcNWarning:
message(c.debug[pc], warnUser, regs[ra].node.strVal) message(c.config, c.debug[pc], warnUser, regs[ra].node.strVal)
of opcNHint: of opcNHint:
message(c.debug[pc], hintUser, regs[ra].node.strVal) message(c.config, c.debug[pc], hintUser, regs[ra].node.strVal)
of opcParseExprToAst: of opcParseExprToAst:
decodeB(rkNode) decodeB(rkNode)
# c.debug[pc].line.int - countLines(regs[rb].strVal) ? # c.debug[pc].line.int - countLines(regs[rb].strVal) ?
var error: string var error: string
let ast = parseString(regs[rb].node.strVal, c.cache, c.config, let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
c.debug[pc].toFullPath, c.debug[pc].line.int, c.debug[pc].toFullPath, c.debug[pc].line.int,
proc (info: TLineInfo; msg: TMsgKind; arg: string) = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
if error.isNil and msg <= msgs.errMax: if error.isNil and msg <= errMax:
error = formatMsg(info, msg, arg)) error = formatMsg(info, msg, arg))
if not error.isNil: if not error.isNil:
c.errorFlag = error c.errorFlag = error
elif sonsLen(ast) != 1: elif sonsLen(ast) != 1:
c.errorFlag = formatMsg(c.debug[pc], errExprExpected, "multiple statements") c.errorFlag = formatMsg(c.debug[pc], errGenerated,
"expected expression, but got multiple statements")
else: else:
regs[ra].node = ast.sons[0] regs[ra].node = ast.sons[0]
of opcParseStmtToAst: of opcParseStmtToAst:
@ -1357,8 +1368,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var error: string var error: string
let ast = parseString(regs[rb].node.strVal, c.cache, c.config, let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
c.debug[pc].toFullPath, c.debug[pc].line.int, c.debug[pc].toFullPath, c.debug[pc].line.int,
proc (info: TLineInfo; msg: TMsgKind; arg: string) = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
if error.isNil and msg <= msgs.errMax: if error.isNil and msg <= errMax:
error = formatMsg(info, msg, arg)) error = formatMsg(info, msg, arg))
if not error.isNil: if not error.isNil:
c.errorFlag = error c.errorFlag = error
@ -1371,7 +1382,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcCallSite: of opcCallSite:
ensureKind(rkNode) ensureKind(rkNode)
if c.callsite != nil: regs[ra].node = c.callsite if c.callsite != nil: regs[ra].node = c.callsite
else: stackTrace(c, tos, pc, errFieldXNotFound, "callsite") else: stackTrace(c, tos, pc, errFieldXNotFound & "callsite")
of opcNGetFile: of opcNGetFile:
decodeB(rkNode) decodeB(rkNode)
let n = regs[rb].node let n = regs[rb].node
@ -1433,13 +1444,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcStrToIdent: of opcStrToIdent:
decodeB(rkNode) decodeB(rkNode)
if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}: if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:
stackTrace(c, tos, pc, errFieldXNotFound, "strVal") stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
else: else:
regs[ra].node = newNodeI(nkIdent, c.debug[pc]) regs[ra].node = newNodeI(nkIdent, c.debug[pc])
regs[ra].node.ident = getIdent(regs[rb].node.strVal) regs[ra].node.ident = getIdent(regs[rb].node.strVal)
of opcSetType: of opcSetType:
if regs[ra].kind != rkNode: if regs[ra].kind != rkNode:
internalError(c.debug[pc], "cannot set type") internalError(c.config, c.debug[pc], "cannot set type")
regs[ra].node.typ = c.types[instr.regBx - wordExcess] regs[ra].node.typ = c.types[instr.regBx - wordExcess]
of opcConv: of opcConv:
let rb = instr.regB let rb = instr.regB
@ -1448,9 +1459,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
inc pc inc pc
let srctyp = c.types[c.code[pc].regBx - wordExcess] let srctyp = c.types[c.code[pc].regBx - wordExcess]
if opConv(regs[ra], regs[rb], desttyp, srctyp): if opConv(c, regs[ra], regs[rb], desttyp, srctyp):
stackTrace(c, tos, pc, errGenerated, stackTrace(c, tos, pc,
msgKindToString(errIllegalConvFromXtoY) % [ errIllegalConvFromXtoY % [
typeToString(srctyp), typeToString(desttyp)]) typeToString(srctyp), typeToString(desttyp)])
of opcCast: of opcCast:
let rb = instr.regB let rb = instr.regB
@ -1463,7 +1474,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let dest = fficast(regs[rb], desttyp) let dest = fficast(regs[rb], desttyp)
asgnRef(regs[ra], dest) asgnRef(regs[ra], dest)
else: else:
globalError(c.debug[pc], "cannot evaluate cast") globalError(c.config, c.debug[pc], "cannot evaluate cast")
of opcNSetIntVal: of opcNSetIntVal:
decodeB(rkNode) decodeB(rkNode)
var dest = regs[ra].node var dest = regs[ra].node
@ -1471,7 +1482,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[rb].kind in {rkInt}: regs[rb].kind in {rkInt}:
dest.intVal = regs[rb].intVal dest.intVal = regs[rb].intVal
else: else:
stackTrace(c, tos, pc, errFieldXNotFound, "intVal") stackTrace(c, tos, pc, errFieldXNotFound & "intVal")
of opcNSetFloatVal: of opcNSetFloatVal:
decodeB(rkNode) decodeB(rkNode)
var dest = regs[ra].node var dest = regs[ra].node
@ -1479,26 +1490,26 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[rb].kind in {rkFloat}: regs[rb].kind in {rkFloat}:
dest.floatVal = regs[rb].floatVal dest.floatVal = regs[rb].floatVal
else: else:
stackTrace(c, tos, pc, errFieldXNotFound, "floatVal") stackTrace(c, tos, pc, errFieldXNotFound & "floatVal")
of opcNSetSymbol: of opcNSetSymbol:
decodeB(rkNode) decodeB(rkNode)
var dest = regs[ra].node var dest = regs[ra].node
if dest.kind == nkSym and regs[rb].node.kind == nkSym: if dest.kind == nkSym and regs[rb].node.kind == nkSym:
dest.sym = regs[rb].node.sym dest.sym = regs[rb].node.sym
else: else:
stackTrace(c, tos, pc, errFieldXNotFound, "symbol") stackTrace(c, tos, pc, errFieldXNotFound & "symbol")
of opcNSetIdent: of opcNSetIdent:
decodeB(rkNode) decodeB(rkNode)
var dest = regs[ra].node var dest = regs[ra].node
if dest.kind == nkIdent and regs[rb].node.kind == nkIdent: if dest.kind == nkIdent and regs[rb].node.kind == nkIdent:
dest.ident = regs[rb].node.ident dest.ident = regs[rb].node.ident
else: else:
stackTrace(c, tos, pc, errFieldXNotFound, "ident") stackTrace(c, tos, pc, errFieldXNotFound & "ident")
of opcNSetType: of opcNSetType:
decodeB(rkNode) decodeB(rkNode)
let b = regs[rb].node let b = regs[rb].node
internalAssert b.kind == nkSym and b.sym.kind == skType internalAssert c.config, b.kind == nkSym and b.sym.kind == skType
internalAssert regs[ra].node != nil internalAssert c.config, regs[ra].node != nil
regs[ra].node.typ = b.sym.typ regs[ra].node.typ = b.sym.typ
of opcNSetStrVal: of opcNSetStrVal:
decodeB(rkNode) decodeB(rkNode)
@ -1509,12 +1520,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
elif dest.kind == nkCommentStmt and regs[rb].kind in {rkNode}: elif dest.kind == nkCommentStmt and regs[rb].kind in {rkNode}:
dest.comment = regs[rb].node.strVal dest.comment = regs[rb].node.strVal
else: else:
stackTrace(c, tos, pc, errFieldXNotFound, "strVal") stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
of opcNNewNimNode: of opcNNewNimNode:
decodeBC(rkNode) decodeBC(rkNode)
var k = regs[rb].intVal var k = regs[rb].intVal
if k < 0 or k > ord(high(TNodeKind)): if k < 0 or k > ord(high(TNodeKind)):
internalError(c.debug[pc], internalError(c.config, c.debug[pc],
"request to create a NimNode of invalid kind") "request to create a NimNode of invalid kind")
let cc = regs[rc].node let cc = regs[rc].node
@ -1548,7 +1559,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let name = if regs[rc].node.strVal.len == 0: ":tmp" let name = if regs[rc].node.strVal.len == 0: ":tmp"
else: regs[rc].node.strVal else: regs[rc].node.strVal
if k < 0 or k > ord(high(TSymKind)): if k < 0 or k > ord(high(TSymKind)):
internalError(c.debug[pc], "request to create symbol of invalid kind") internalError(c.config, c.debug[pc], "request to create symbol of invalid kind")
var sym = newSym(k.TSymKind, name.getIdent, c.module.owner, c.debug[pc]) var sym = newSym(k.TSymKind, name.getIdent, c.module.owner, c.debug[pc])
incl(sym.flags, sfGenSym) incl(sym.flags, sfGenSym)
regs[ra].node = newSymNode(sym) regs[ra].node = newSymNode(sym)
@ -1557,7 +1568,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
# type trait operation # type trait operation
decodeB(rkNode) decodeB(rkNode)
var typ = regs[rb].node.typ var typ = regs[rb].node.typ
internalAssert typ != nil internalAssert c.config, typ != nil
while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0] while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0]
createStr regs[ra] createStr regs[ra]
regs[ra].node.strVal = typ.typeToString(preferExported) regs[ra].node.strVal = typ.typeToString(preferExported)
@ -1566,14 +1577,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let rb = instr.regB let rb = instr.regB
inc pc inc pc
let typ = c.types[c.code[pc].regBx - wordExcess] let typ = c.types[c.code[pc].regBx - wordExcess]
putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ)) putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ, c.config))
of opcMarshalStore: of opcMarshalStore:
decodeB(rkNode) decodeB(rkNode)
inc pc inc pc
let typ = c.types[c.code[pc].regBx - wordExcess] let typ = c.types[c.code[pc].regBx - wordExcess]
createStrKeepNode(regs[ra]) createStrKeepNode(regs[ra])
if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000) if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000)
storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode) storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config)
of opcToNarrowInt: of opcToNarrowInt:
decodeBC(rkInt) decodeBC(rkInt)
let mask = (1'i64 shl rc) - 1 # 0xFF let mask = (1'i64 shl rc) - 1 # 0xFF
@ -1595,7 +1606,7 @@ proc execute(c: PCtx, start: int): PNode =
proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
if sym.kind in routineKinds: if sym.kind in routineKinds:
if sym.typ.len-1 != args.len: if sym.typ.len-1 != args.len:
localError(sym.info, localError(c.config, sym.info,
"NimScript: expected $# arguments, but got $#" % [ "NimScript: expected $# arguments, but got $#" % [
$(sym.typ.len-1), $args.len]) $(sym.typ.len-1), $args.len])
else: else:
@ -1607,18 +1618,18 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
# setup parameters: # setup parameters:
if not isEmptyType(sym.typ.sons[0]) or sym.kind == skMacro: if not isEmptyType(sym.typ.sons[0]) or sym.kind == skMacro:
putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info)) putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info, c.config))
# XXX We could perform some type checking here. # XXX We could perform some type checking here.
for i in 1..<sym.typ.len: for i in 1..<sym.typ.len:
putIntoReg(tos.slots[i], args[i-1]) putIntoReg(tos.slots[i], args[i-1])
result = rawExecute(c, start, tos).regToNode result = rawExecute(c, start, tos).regToNode
else: else:
localError(sym.info, localError(c.config, sym.info,
"NimScript: attempt to call non-routine: " & sym.name.s) "NimScript: attempt to call non-routine: " & sym.name.s)
proc evalStmt*(c: PCtx, n: PNode) = proc evalStmt*(c: PCtx, n: PNode) =
let n = transformExpr(c.module, n) let n = transformExpr(c.graph, c.module, n)
let start = genStmt(c, n) let start = genStmt(c, n)
# execute new instructions; this redundant opcEof check saves us lots # execute new instructions; this redundant opcEof check saves us lots
# of allocations in 'execute': # of allocations in 'execute':
@ -1626,13 +1637,13 @@ proc evalStmt*(c: PCtx, n: PNode) =
discard execute(c, start) discard execute(c, start)
proc evalExpr*(c: PCtx, n: PNode): PNode = proc evalExpr*(c: PCtx, n: PNode): PNode =
let n = transformExpr(c.module, n) let n = transformExpr(c.graph, c.module, n)
let start = genExpr(c, n) let start = genExpr(c, n)
assert c.code[start].opcode != opcEof assert c.code[start].opcode != opcEof
result = execute(c, start) result = execute(c, start)
proc getGlobalValue*(c: PCtx; s: PSym): PNode = proc getGlobalValue*(c: PCtx; s: PSym): PNode =
internalAssert s.kind in {skLet, skVar} and sfGlobal in s.flags internalAssert c.config, s.kind in {skLet, skVar} and sfGlobal in s.flags
result = c.globals.sons[s.position-1] result = c.globals.sons[s.position-1]
include vmops include vmops
@ -1643,9 +1654,9 @@ include vmops
var var
globalCtx*: PCtx globalCtx*: PCtx
proc setupGlobalCtx(module: PSym; cache: IdentCache; config: ConfigRef) = proc setupGlobalCtx(module: PSym; cache: IdentCache; graph: ModuleGraph) =
if globalCtx.isNil: if globalCtx.isNil:
globalCtx = newCtx(module, cache, config) globalCtx = newCtx(module, cache, graph)
registerAdditionalOps(globalCtx) registerAdditionalOps(globalCtx)
else: else:
refresh(globalCtx, module) refresh(globalCtx, module)
@ -1656,21 +1667,20 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
#pushStackFrame(c, newStackFrame()) #pushStackFrame(c, newStackFrame())
# XXX produce a new 'globals' environment here: # XXX produce a new 'globals' environment here:
setupGlobalCtx(module, cache, graph.config) setupGlobalCtx(module, cache, graph)
result = globalCtx result = globalCtx
when hasFFI: when hasFFI:
globalCtx.features = {allowFFI, allowCast} globalCtx.features = {allowFFI, allowCast}
var oldErrorCount: int
proc myProcess(c: PPassContext, n: PNode): PNode = proc myProcess(c: PPassContext, n: PNode): PNode =
let c = PCtx(c)
# don't eval errornous code: # don't eval errornous code:
if oldErrorCount == msgs.gErrorCounter: if c.oldErrorCount == c.config.errorCounter:
evalStmt(PCtx(c), n) evalStmt(PCtx(c), n)
result = emptyNode result = emptyNode
else: else:
result = n result = n
oldErrorCount = msgs.gErrorCounter c.oldErrorCount = c.config.errorCounter
proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
myProcess(c, n) myProcess(c, n)
@ -1678,10 +1688,10 @@ proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
const evalPass* = makePass(myOpen, nil, myProcess, myClose) const evalPass* = makePass(myOpen, nil, myProcess, myClose)
proc evalConstExprAux(module: PSym; cache: IdentCache; proc evalConstExprAux(module: PSym; cache: IdentCache;
config: ConfigRef; prc: PSym, n: PNode, g: ModuleGraph; prc: PSym, n: PNode,
mode: TEvalMode): PNode = mode: TEvalMode): PNode =
let n = transformExpr(module, n) let n = transformExpr(g, module, n)
setupGlobalCtx(module, cache, config) setupGlobalCtx(module, cache, g)
var c = globalCtx var c = globalCtx
let oldMode = c.mode let oldMode = c.mode
defer: c.mode = oldMode defer: c.mode = oldMode
@ -1696,17 +1706,17 @@ proc evalConstExprAux(module: PSym; cache: IdentCache;
result = rawExecute(c, start, tos).regToNode result = rawExecute(c, start, tos).regToNode
if result.info.col < 0: result.info = n.info if result.info.col < 0: result.info = n.info
proc evalConstExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode): PNode = proc evalConstExpr*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode): PNode =
result = evalConstExprAux(module, cache, config, nil, e, emConst) result = evalConstExprAux(module, cache, g, nil, e, emConst)
proc evalStaticExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym): PNode = proc evalStaticExpr*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode, prc: PSym): PNode =
result = evalConstExprAux(module, cache, config, prc, e, emStaticExpr) result = evalConstExprAux(module, cache, g, prc, e, emStaticExpr)
proc evalStaticStmt*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym) = proc evalStaticStmt*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode, prc: PSym) =
discard evalConstExprAux(module, cache, config, prc, e, emStaticStmt) discard evalConstExprAux(module, cache, g, prc, e, emStaticStmt)
proc setupCompileTimeVar*(module: PSym; cache: IdentCache, config: ConfigRef; n: PNode) = proc setupCompileTimeVar*(module: PSym; cache: IdentCache, g: ModuleGraph; n: PNode) =
discard evalConstExprAux(module, cache, config, nil, n, emStaticStmt) discard evalConstExprAux(module, cache, g, nil, n, emStaticStmt)
proc setupMacroParam(x: PNode, typ: PType): TFullReg = proc setupMacroParam(x: PNode, typ: PType): TFullReg =
case typ.kind case typ.kind
@ -1734,20 +1744,20 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
const evalMacroLimit = 1000 const evalMacroLimit = 1000
var evalMacroCounter: int var evalMacroCounter: int
proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef; proc evalMacroCall*(module: PSym; cache: IdentCache; g: ModuleGraph;
n, nOrig: PNode, sym: PSym): PNode = n, nOrig: PNode, sym: PSym): PNode =
# XXX globalError() is ugly here, but I don't know a better solution for now # XXX globalError() is ugly here, but I don't know a better solution for now
inc(evalMacroCounter) inc(evalMacroCounter)
if evalMacroCounter > evalMacroLimit: if evalMacroCounter > evalMacroLimit:
globalError(n.info, errMacroInstantiationTooNested) globalError(g.config, n.info, "macro instantiation too nested")
# immediate macros can bypass any type and arity checking so we check the # immediate macros can bypass any type and arity checking so we check the
# arity here too: # arity here too:
if sym.typ.len > n.safeLen and sym.typ.len > 1: if sym.typ.len > n.safeLen and sym.typ.len > 1:
globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [ globalError(g.config, n.info, "in call '$#' got $#, but expected $# argument(s)" % [
n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)]) n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)])
setupGlobalCtx(module, cache, config) setupGlobalCtx(module, cache, g)
var c = globalCtx var c = globalCtx
c.comesFromHeuristic.line = 0'u16 c.comesFromHeuristic.line = 0'u16
@ -1781,16 +1791,16 @@ proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef;
else: else:
dec(evalMacroCounter) dec(evalMacroCounter)
c.callsite = nil c.callsite = nil
localError(n.info, "expected " & $gp.len & localError(c.config, n.info, "expected " & $gp.len &
" generic parameter(s)") " generic parameter(s)")
elif gp[i].sym.typ.kind in {tyStatic, tyTypeDesc}: elif gp[i].sym.typ.kind in {tyStatic, tyTypeDesc}:
dec(evalMacroCounter) dec(evalMacroCounter)
c.callsite = nil c.callsite = nil
globalError(n.info, "static[T] or typedesc nor supported for .immediate macros") globalError(c.config, n.info, "static[T] or typedesc nor supported for .immediate macros")
# temporary storage: # temporary storage:
#for i in L ..< maxSlots: tos.slots[i] = newNode(nkEmpty) #for i in L ..< maxSlots: tos.slots[i] = newNode(nkEmpty)
result = rawExecute(c, start, tos).regToNode result = rawExecute(c, start, tos).regToNode
if result.info.line < 0: result.info = n.info if result.info.line < 0: result.info = n.info
if cyclicTree(result): globalError(n.info, errCyclicTree) if cyclicTree(result): globalError(c.config, n.info, "macro produced a cyclic tree")
dec(evalMacroCounter) dec(evalMacroCounter)
c.callsite = nil c.callsite = nil

View file

@ -208,6 +208,7 @@ type
cache*: IdentCache cache*: IdentCache
config*: ConfigRef config*: ConfigRef
graph*: ModuleGraph graph*: ModuleGraph
oldErrorCount*: int
TPosition* = distinct int TPosition* = distinct int

View file

@ -15,8 +15,6 @@ from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir
from options import gProjectPath
template mathop(op) {.dirty.} = template mathop(op) {.dirty.} =
registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`) registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`)
@ -77,15 +75,15 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode =
result.add newTree(nkTupleConstr, newIntNode(nkIntLit, k.ord), result.add newTree(nkTupleConstr, newIntNode(nkIntLit, k.ord),
newStrNode(nkStrLit, f)) newStrNode(nkStrLit, f))
proc gorgeExWrapper(a: VmArgs) {.nimcall.} = proc registerAdditionalOps*(c: PCtx) =
proc gorgeExWrapper(a: VmArgs) =
let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2), let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2),
a.currentLineInfo) a.currentLineInfo, c.config)
setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e)) setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e))
proc getProjectPathWrapper(a: VmArgs) {.nimcall.} = proc getProjectPathWrapper(a: VmArgs) =
setResult a, gProjectPath setResult a, c.config.projectPath
proc registerAdditionalOps*(c: PCtx) =
wrap1f_math(sqrt) wrap1f_math(sqrt)
wrap1f_math(ln) wrap1f_math(ln)
wrap1f_math(log10) wrap1f_math(log10)