Skip to content

Commit

Permalink
fixes #13; fixes #18
Browse files Browse the repository at this point in the history
  • Loading branch information
Araq committed Mar 8, 2011
1 parent fc274df commit 6d46609
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 21 deletions.
61 changes: 42 additions & 19 deletions rod/evals.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,21 @@ type
proc newStackFrame*(): PStackFrame
proc pushStackFrame*(c: PEvalContext, t: PStackFrame)
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
# eval never returns nil! This simplifies the code a lot and
# makes it faster too.
proc evalConstExpr*(module: PSym, e: PNode): PNode
proc evalPass*(): TPass
# implementation

const
evalMaxIterations = 10000000 # max iterations of all loops
evalMaxRecDepth = 100000 # max recursion depth for evaluation
const
evalMaxIterations = 500_000 # max iterations of all loops
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 =
new(result)
Expand Down Expand Up @@ -87,7 +91,7 @@ proc stackTrace(c: PEvalContext, n: PNode, msg: TMsgKind, arg: string = "") =
stackTraceAux(c.tos)
Fatal(n.info, msg, arg)

proc isSpecial(n: PNode): bool =
proc isSpecial(n: PNode): bool {.inline.} =
result = (n.kind == nkExceptBranch)
# or (n.kind == nkEmpty)
# XXX this does not work yet! Better to compile too much than to compile to
Expand Down Expand Up @@ -137,11 +141,10 @@ proc evalWhile(c: PEvalContext, n: PNode): PNode =
of nkBreakStmt:
if result.sons[0].kind == nkEmpty:
result = emptyNode # consume ``break`` token
break
of nkExceptBranch, nkReturnToken:
# Bugfix (see tmacro2): but break in any case!
break
else:
nil
of nkExceptBranch, nkReturnToken: break
else: nil
dec(gWhileCounter)
if gWhileCounter <= 0:
stackTrace(c, n, errTooManyIterations)
Expand All @@ -152,7 +155,7 @@ proc evalBlock(c: PEvalContext, n: PNode): PNode =
if result.kind == nkBreakStmt:
if result.sons[0] != nil:
assert(result.sons[0].kind == nkSym)
if n.sons[0].kind != nkempty:
if n.sons[0].kind != nkEmpty:
assert(n.sons[0].kind == nkSym)
if result.sons[0].sym.id == n.sons[0].sym.id: result = emptyNode
else:
Expand Down Expand Up @@ -250,6 +253,7 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
assert(a.sons[0].kind == nkSym)
var v = a.sons[0].sym
if a.sons[2].kind != nkEmpty:
#if a.sons[2].kind == nkNone: echo "Yep"
result = evalAux(c, a.sons[2], {})
if isSpecial(result): return
else:
Expand Down Expand Up @@ -309,7 +313,9 @@ proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = emptyNode
case x.kind
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)
if not aliasNeeded(result, flags): result = copyTree(result)
of nkBracket, nkMetaNode:
Expand Down Expand Up @@ -458,12 +464,25 @@ proc evalAnd(c: PEvalContext, n: PNode): PNode =

proc evalNoOpt(c: PEvalContext, n: PNode): PNode =
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 =
if c.optEval:
result = evalNoOpt(c, n)
else:
if c.optEval: return evalNoOpt(c, n)
# we ignore the finalizer for now and most likely forever :-)
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)
result = newNodeIT(nkRefTy, n.info, t)
addSon(result, getNullValue(t.sons[0], n.info))
Expand Down Expand Up @@ -522,8 +541,8 @@ proc evalRangeChck(c: PEvalContext, n: PNode): PNode =
result = x # a <= x and x <= b
result.typ = n.typ
else:
stackTrace(c, n, errGenerated, `%`(msgKindToString(errIllegalConvFromXtoY), [
typeToString(n.sons[0].typ), typeToString(n.typ)]))
stackTrace(c, n, errGenerated, msgKindToString(errIllegalConvFromXtoY) % [
typeToString(n.sons[0].typ), typeToString(n.typ)])

proc evalConvStrToCStr(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[0], {})
Expand Down Expand Up @@ -623,11 +642,15 @@ proc evalNewSeq(c: PEvalContext, n: PNode): PNode =
var b = 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 = nkBracket
a.info = n.info
a.typ = t
for i in countup(0, int(getOrdValue(b)) - 1):
addSon(a, getNullValue(t.sons[0], n.info))
a.sons = nil
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

proc evalAssert(c: PEvalContext, n: PNode): PNode =
Expand Down
4 changes: 2 additions & 2 deletions rod/nimrod.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2010 Andreas Rumpf
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
Expand Down Expand Up @@ -81,7 +81,7 @@ proc HandleCmdLine() =
var prog = quoteIfContainsWhite(changeFileExt(filename, ""))
execExternalProgram(prog & ' ' & arguments)

cmdLineInfo = newLineInfo("command line", - 1, - 1)
cmdLineInfo = newLineInfo("command line", -1, -1)
condsyms.InitDefines()
HandleCmdLine()
quit(options.gExitcode)
27 changes: 27 additions & 0 deletions tests/accept/run/tmacro2.nim
Original file line number Diff line number Diff line change
@@ -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 changes: 31 additions & 0 deletions tests/accept/run/tmacro3.nim
Original file line number Diff line number Diff line change
@@ -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"

0 comments on commit 6d46609

Please sign in to comment.