parent
f9c6cec90c
commit
fa332b7298
4 changed files with 102 additions and 21 deletions
|
|
@ -42,7 +42,8 @@ type
|
||||||
proc newStackFrame*(): PStackFrame
|
proc newStackFrame*(): PStackFrame
|
||||||
proc pushStackFrame*(c: PEvalContext, t: PStackFrame)
|
proc pushStackFrame*(c: PEvalContext, t: PStackFrame)
|
||||||
proc popStackFrame*(c: PEvalContext)
|
proc popStackFrame*(c: PEvalContext)
|
||||||
proc newEvalContext*(module: PSym, filename: string, optEval: bool): PEvalContext
|
proc newEvalContext*(module: PSym, filename: string,
|
||||||
|
optEval: bool): PEvalContext
|
||||||
proc eval*(c: PEvalContext, n: PNode): PNode
|
proc eval*(c: PEvalContext, n: PNode): PNode
|
||||||
# eval never returns nil! This simplifies the code a lot and
|
# eval never returns nil! This simplifies the code a lot and
|
||||||
# makes it faster too.
|
# makes it faster too.
|
||||||
|
|
@ -51,8 +52,11 @@ proc evalPass*(): TPass
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
const
|
const
|
||||||
evalMaxIterations = 10000000 # max iterations of all loops
|
evalMaxIterations = 500_000 # max iterations of all loops
|
||||||
evalMaxRecDepth = 100000 # max recursion depth for evaluation
|
evalMaxRecDepth = 10_000 # max recursion depth for evaluation
|
||||||
|
|
||||||
|
# Much better: use a timeout! -> Wether code compiles depends on the machine
|
||||||
|
# the compiler runs on then! Bad idea!
|
||||||
|
|
||||||
proc newStackFrame(): PStackFrame =
|
proc newStackFrame(): PStackFrame =
|
||||||
new(result)
|
new(result)
|
||||||
|
|
@ -87,7 +91,7 @@ proc stackTrace(c: PEvalContext, n: PNode, msg: TMsgKind, arg: string = "") =
|
||||||
stackTraceAux(c.tos)
|
stackTraceAux(c.tos)
|
||||||
Fatal(n.info, msg, arg)
|
Fatal(n.info, msg, arg)
|
||||||
|
|
||||||
proc isSpecial(n: PNode): bool =
|
proc isSpecial(n: PNode): bool {.inline.} =
|
||||||
result = (n.kind == nkExceptBranch)
|
result = (n.kind == nkExceptBranch)
|
||||||
# or (n.kind == nkEmpty)
|
# or (n.kind == nkEmpty)
|
||||||
# XXX this does not work yet! Better to compile too much than to compile to
|
# XXX this does not work yet! Better to compile too much than to compile to
|
||||||
|
|
@ -137,11 +141,10 @@ proc evalWhile(c: PEvalContext, n: PNode): PNode =
|
||||||
of nkBreakStmt:
|
of nkBreakStmt:
|
||||||
if result.sons[0].kind == nkEmpty:
|
if result.sons[0].kind == nkEmpty:
|
||||||
result = emptyNode # consume ``break`` token
|
result = emptyNode # consume ``break`` token
|
||||||
|
# Bugfix (see tmacro2): but break in any case!
|
||||||
break
|
break
|
||||||
of nkExceptBranch, nkReturnToken:
|
of nkExceptBranch, nkReturnToken: break
|
||||||
break
|
else: nil
|
||||||
else:
|
|
||||||
nil
|
|
||||||
dec(gWhileCounter)
|
dec(gWhileCounter)
|
||||||
if gWhileCounter <= 0:
|
if gWhileCounter <= 0:
|
||||||
stackTrace(c, n, errTooManyIterations)
|
stackTrace(c, n, errTooManyIterations)
|
||||||
|
|
@ -152,7 +155,7 @@ proc evalBlock(c: PEvalContext, n: PNode): PNode =
|
||||||
if result.kind == nkBreakStmt:
|
if result.kind == nkBreakStmt:
|
||||||
if result.sons[0] != nil:
|
if result.sons[0] != nil:
|
||||||
assert(result.sons[0].kind == nkSym)
|
assert(result.sons[0].kind == nkSym)
|
||||||
if n.sons[0].kind != nkempty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
assert(n.sons[0].kind == nkSym)
|
assert(n.sons[0].kind == nkSym)
|
||||||
if result.sons[0].sym.id == n.sons[0].sym.id: result = emptyNode
|
if result.sons[0].sym.id == n.sons[0].sym.id: result = emptyNode
|
||||||
else:
|
else:
|
||||||
|
|
@ -250,6 +253,7 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
|
||||||
assert(a.sons[0].kind == nkSym)
|
assert(a.sons[0].kind == nkSym)
|
||||||
var v = a.sons[0].sym
|
var v = a.sons[0].sym
|
||||||
if a.sons[2].kind != nkEmpty:
|
if a.sons[2].kind != nkEmpty:
|
||||||
|
#if a.sons[2].kind == nkNone: echo "Yep"
|
||||||
result = evalAux(c, a.sons[2], {})
|
result = evalAux(c, a.sons[2], {})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
else:
|
else:
|
||||||
|
|
@ -309,7 +313,9 @@ proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||||
result = emptyNode
|
result = emptyNode
|
||||||
case x.kind
|
case x.kind
|
||||||
of nkPar:
|
of nkPar:
|
||||||
if (idx >= 0) and (idx < sonsLen(x)): result = x.sons[int(idx)].sons[1]
|
if (idx >= 0) and (idx < sonsLen(x)):
|
||||||
|
result = x.sons[int(idx)]
|
||||||
|
if result.kind == nkExprColonExpr: result = result.sons[1]
|
||||||
else: stackTrace(c, n, errIndexOutOfBounds)
|
else: stackTrace(c, n, errIndexOutOfBounds)
|
||||||
if not aliasNeeded(result, flags): result = copyTree(result)
|
if not aliasNeeded(result, flags): result = copyTree(result)
|
||||||
of nkBracket, nkMetaNode:
|
of nkBracket, nkMetaNode:
|
||||||
|
|
@ -458,12 +464,25 @@ proc evalAnd(c: PEvalContext, n: PNode): PNode =
|
||||||
|
|
||||||
proc evalNoOpt(c: PEvalContext, n: PNode): PNode =
|
proc evalNoOpt(c: PEvalContext, n: PNode): PNode =
|
||||||
result = newNodeI(nkExceptBranch, n.info)
|
result = newNodeI(nkExceptBranch, n.info)
|
||||||
# creating a nkExceptBranch without sons means that it could not be evaluated
|
# creating a nkExceptBranch without sons
|
||||||
|
# means that it could not be evaluated
|
||||||
|
|
||||||
proc evalNew(c: PEvalContext, n: PNode): PNode =
|
proc evalNew(c: PEvalContext, n: PNode): PNode =
|
||||||
if c.optEval:
|
if c.optEval: return evalNoOpt(c, n)
|
||||||
result = evalNoOpt(c, n)
|
# we ignore the finalizer for now and most likely forever :-)
|
||||||
else:
|
result = evalAux(c, n.sons[1], {efLValue})
|
||||||
|
if isSpecial(result): return
|
||||||
|
var a = result
|
||||||
|
var t = skipTypes(n.sons[1].typ, abstractVar)
|
||||||
|
if a.kind == nkEmpty: InternalError(n.info, "first parameter is empty")
|
||||||
|
# changing the node kind is ugly and suggests deep problems:
|
||||||
|
a.kind = nkRefTy
|
||||||
|
a.info = n.info
|
||||||
|
a.typ = t
|
||||||
|
a.sons = nil
|
||||||
|
addSon(a, getNullValue(t.sons[0], n.info))
|
||||||
|
result = emptyNode
|
||||||
|
when false:
|
||||||
var t = skipTypes(n.sons[1].typ, abstractVar)
|
var t = skipTypes(n.sons[1].typ, abstractVar)
|
||||||
result = newNodeIT(nkRefTy, n.info, t)
|
result = newNodeIT(nkRefTy, n.info, t)
|
||||||
addSon(result, getNullValue(t.sons[0], n.info))
|
addSon(result, getNullValue(t.sons[0], n.info))
|
||||||
|
|
@ -522,8 +541,8 @@ proc evalRangeChck(c: PEvalContext, n: PNode): PNode =
|
||||||
result = x # a <= x and x <= b
|
result = x # a <= x and x <= b
|
||||||
result.typ = n.typ
|
result.typ = n.typ
|
||||||
else:
|
else:
|
||||||
stackTrace(c, n, errGenerated, `%`(msgKindToString(errIllegalConvFromXtoY), [
|
stackTrace(c, n, errGenerated, msgKindToString(errIllegalConvFromXtoY) % [
|
||||||
typeToString(n.sons[0].typ), typeToString(n.typ)]))
|
typeToString(n.sons[0].typ), typeToString(n.typ)])
|
||||||
|
|
||||||
proc evalConvStrToCStr(c: PEvalContext, n: PNode): PNode =
|
proc evalConvStrToCStr(c: PEvalContext, n: PNode): PNode =
|
||||||
result = evalAux(c, n.sons[0], {})
|
result = evalAux(c, n.sons[0], {})
|
||||||
|
|
@ -623,11 +642,15 @@ proc evalNewSeq(c: PEvalContext, n: PNode): PNode =
|
||||||
var b = result
|
var b = result
|
||||||
var t = skipTypes(n.sons[1].typ, abstractVar)
|
var t = skipTypes(n.sons[1].typ, abstractVar)
|
||||||
if a.kind == nkEmpty: InternalError(n.info, "first parameter is empty")
|
if a.kind == nkEmpty: InternalError(n.info, "first parameter is empty")
|
||||||
|
# changing the node kind is ugly and suggests deep problems:
|
||||||
a.kind = nkBracket
|
a.kind = nkBracket
|
||||||
a.info = n.info
|
a.info = n.info
|
||||||
a.typ = t
|
a.typ = t
|
||||||
for i in countup(0, int(getOrdValue(b)) - 1):
|
a.sons = nil
|
||||||
addSon(a, getNullValue(t.sons[0], n.info))
|
var L = int(getOrdValue(b))
|
||||||
|
newSeq(a.sons, L)
|
||||||
|
for i in countup(0, L-1):
|
||||||
|
a.sons[i] = getNullValue(t.sons[0], n.info)
|
||||||
result = emptyNode
|
result = emptyNode
|
||||||
|
|
||||||
proc evalAssert(c: PEvalContext, n: PNode): PNode =
|
proc evalAssert(c: PEvalContext, n: PNode): PNode =
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nimrod Compiler
|
||||||
# (c) Copyright 2010 Andreas Rumpf
|
# (c) Copyright 2011 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -81,7 +81,7 @@ proc HandleCmdLine() =
|
||||||
var prog = quoteIfContainsWhite(changeFileExt(filename, ""))
|
var prog = quoteIfContainsWhite(changeFileExt(filename, ""))
|
||||||
execExternalProgram(prog & ' ' & arguments)
|
execExternalProgram(prog & ' ' & arguments)
|
||||||
|
|
||||||
cmdLineInfo = newLineInfo("command line", - 1, - 1)
|
cmdLineInfo = newLineInfo("command line", -1, -1)
|
||||||
condsyms.InitDefines()
|
condsyms.InitDefines()
|
||||||
HandleCmdLine()
|
HandleCmdLine()
|
||||||
quit(options.gExitcode)
|
quit(options.gExitcode)
|
||||||
|
|
|
||||||
27
tests/accept/run/tmacro2.nim
Normal file
27
tests/accept/run/tmacro2.nim
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
discard """
|
||||||
|
output: "ta-da Your value sir: 'HE!!!!o Wor!!d'"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import macros, strutils
|
||||||
|
|
||||||
|
proc testBlock(): string {.compileTime.} =
|
||||||
|
block myBlock:
|
||||||
|
while true:
|
||||||
|
echo "inner block"
|
||||||
|
break myBlock
|
||||||
|
echo "outer block"
|
||||||
|
result = "ta-da"
|
||||||
|
|
||||||
|
macro mac(n: expr): expr =
|
||||||
|
expectKind(n, nnkCall)
|
||||||
|
expectLen(n, 2)
|
||||||
|
expectKind(n[1], nnkStrLit)
|
||||||
|
var s: string = n[1].strVal
|
||||||
|
s = s.replace("l", "!!")
|
||||||
|
result = newStrLitNode("Your value sir: '$#'" % [s])
|
||||||
|
|
||||||
|
const s = testBlock()
|
||||||
|
const t = mac("HEllo World")
|
||||||
|
echo s, " ", t
|
||||||
|
|
||||||
|
|
||||||
31
tests/accept/run/tmacro3.nim
Normal file
31
tests/accept/run/tmacro3.nim
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
discard """
|
||||||
|
output: ""
|
||||||
|
"""
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
type
|
||||||
|
TA = tuple[a: int]
|
||||||
|
PA = ref TA
|
||||||
|
|
||||||
|
macro test*(a: stmt): stmt =
|
||||||
|
var val: PA
|
||||||
|
new(val)
|
||||||
|
val.a = 4
|
||||||
|
|
||||||
|
test:
|
||||||
|
"hi"
|
||||||
|
|
||||||
|
macro test2*(a: stmt): stmt =
|
||||||
|
proc testproc(recurse: int) =
|
||||||
|
echo "Thats weird"
|
||||||
|
var o : PNimrodNode = nil
|
||||||
|
echo " no its not!"
|
||||||
|
o = newNimNode(nnkNone)
|
||||||
|
if recurse > 0:
|
||||||
|
testproc(recurse - 1)
|
||||||
|
testproc(5)
|
||||||
|
|
||||||
|
test2:
|
||||||
|
"hi"
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue