Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
70c283ac64
17 changed files with 261 additions and 73 deletions
|
|
@ -371,7 +371,7 @@ type
|
||||||
TMagic* = enum # symbols that require compiler magic:
|
TMagic* = enum # symbols that require compiler magic:
|
||||||
mNone,
|
mNone,
|
||||||
mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
|
mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
|
||||||
mEcho, mShallowCopy, mSlurp,
|
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
||||||
mParseExprToAst, mParseStmtToAst, mExpandToAst,
|
mParseExprToAst, mParseStmtToAst, mExpandToAst,
|
||||||
mUnaryLt, mSucc,
|
mUnaryLt, mSucc,
|
||||||
mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
||||||
|
|
@ -542,6 +542,9 @@ type
|
||||||
# for easy generation of proper error messages
|
# for easy generation of proper error messages
|
||||||
# for variant record fields the discriminant
|
# for variant record fields the discriminant
|
||||||
# expression
|
# expression
|
||||||
|
# for modules, it's a placeholder for compiler
|
||||||
|
# generated code that will be appended to the
|
||||||
|
# module after the sem pass (see appendToModule)
|
||||||
options*: TOptions
|
options*: TOptions
|
||||||
position*: int # used for many different things:
|
position*: int # used for many different things:
|
||||||
# for enum fields its position;
|
# for enum fields its position;
|
||||||
|
|
@ -568,6 +571,9 @@ type
|
||||||
# for record types a nkRecord node
|
# for record types a nkRecord node
|
||||||
# for enum types a list of symbols
|
# for enum types a list of symbols
|
||||||
# else: unused
|
# else: unused
|
||||||
|
destructor*: PSym # destructor. warning: nil here may not necessary
|
||||||
|
# mean that there is no destructor.
|
||||||
|
# see instantiateDestructor in types.nim
|
||||||
owner*: PSym # the 'owner' of the type
|
owner*: PSym # the 'owner' of the type
|
||||||
sym*: PSym # types have the sym associated with them
|
sym*: PSym # types have the sym associated with them
|
||||||
# it is used for converting types to strings
|
# it is used for converting types to strings
|
||||||
|
|
@ -740,6 +746,16 @@ proc linkTo*(s: PSym, t: PType): PSym {.discardable.} =
|
||||||
s.typ = t
|
s.typ = t
|
||||||
result = s
|
result = s
|
||||||
|
|
||||||
|
proc appendToModule*(m: PSym, n: PNode) =
|
||||||
|
## The compiler will use this internally to add nodes that will be
|
||||||
|
## appended to the module after the sem pass
|
||||||
|
if m.ast == nil:
|
||||||
|
m.ast = newNode(nkStmtList)
|
||||||
|
m.ast.sons = @[n]
|
||||||
|
else:
|
||||||
|
assert m.ast.kind == nkStmtList
|
||||||
|
m.ast.sons.add(n)
|
||||||
|
|
||||||
const # for all kind of hash tables:
|
const # for all kind of hash tables:
|
||||||
GrowthFactor* = 2 # must be power of 2, > 0
|
GrowthFactor* = 2 # must be power of 2, > 0
|
||||||
StartSize* = 8 # must be power of 2, > 0
|
StartSize* = 8 # must be power of 2, > 0
|
||||||
|
|
|
||||||
|
|
@ -1437,6 +1437,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
of mArrToSeq: genArrToSeq(p, e, d)
|
of mArrToSeq: genArrToSeq(p, e, d)
|
||||||
of mNLen..mNError:
|
of mNLen..mNError:
|
||||||
localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s)
|
localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s)
|
||||||
|
of mSlurp, mStaticExec:
|
||||||
|
localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s)
|
||||||
else: internalError(e.info, "genMagicExpr: " & $op)
|
else: internalError(e.info, "genMagicExpr: " & $op)
|
||||||
|
|
||||||
proc genConstExpr(p: BProc, n: PNode): PRope
|
proc genConstExpr(p: BProc, n: PNode): PRope
|
||||||
|
|
|
||||||
|
|
@ -1173,6 +1173,8 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) =
|
||||||
localError(n.info, errCannotGenerateCodeForX, n.sons[0].sym.name.s)
|
localError(n.info, errCannotGenerateCodeForX, n.sons[0].sym.name.s)
|
||||||
of mNewSeq: binaryStmt(p, n, r, "", "$1 = new Array($2)")
|
of mNewSeq: binaryStmt(p, n, r, "", "$1 = new Array($2)")
|
||||||
of mEcho: genEcho(p, n, r)
|
of mEcho: genEcho(p, n, r)
|
||||||
|
of mSlurp, mStaticExec:
|
||||||
|
localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
|
||||||
else:
|
else:
|
||||||
genCall(p, n, r)
|
genCall(p, n, r)
|
||||||
#else internalError(e.info, 'genMagic: ' + magicToStr[op]);
|
#else internalError(e.info, 'genMagic: ' + magicToStr[op]);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
import
|
import
|
||||||
strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets,
|
strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets,
|
||||||
msgs, os, condsyms, idents, renderer, types, passes, semfold, transf,
|
msgs, os, condsyms, idents, renderer, types, passes, semfold, transf,
|
||||||
parser, ropes, rodread, idgen
|
parser, ropes, rodread, idgen, osproc, streams
|
||||||
|
|
||||||
type
|
type
|
||||||
PStackFrame* = ref TStackFrame
|
PStackFrame* = ref TStackFrame
|
||||||
|
|
@ -910,6 +910,43 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode =
|
||||||
else:
|
else:
|
||||||
internalAssert false
|
internalAssert false
|
||||||
|
|
||||||
|
proc expectString(n: PNode) =
|
||||||
|
if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
|
||||||
|
GlobalError(n.info, errStringLiteralExpected)
|
||||||
|
|
||||||
|
proc evalSlurp*(e: PNode, module: PSym): PNode =
|
||||||
|
expectString(e)
|
||||||
|
try:
|
||||||
|
var filename = e.strVal.FindFile
|
||||||
|
var content = readFile(filename)
|
||||||
|
result = newStrNode(nkStrLit, content)
|
||||||
|
result.typ = getSysType(tyString)
|
||||||
|
result.info = e.info
|
||||||
|
# we produce a fake include statement for every slurped filename, so that
|
||||||
|
# the module dependencies are accurate:
|
||||||
|
appendToModule(module, newNode(nkIncludeStmt, e.info, @[
|
||||||
|
newStrNode(nkStrLit, filename)]))
|
||||||
|
except EIO:
|
||||||
|
GlobalError(e.info, errCannotOpenFile, e.strVal)
|
||||||
|
|
||||||
|
proc readOutput(p: PProcess): string =
|
||||||
|
result = ""
|
||||||
|
var output = p.outputStream
|
||||||
|
discard p.waitForExit
|
||||||
|
while not output.atEnd:
|
||||||
|
result.add(output.readLine)
|
||||||
|
|
||||||
|
proc evalStaticExec*(cmd, input: PNode): PNode =
|
||||||
|
expectString(cmd)
|
||||||
|
var p = startCmd(cmd.strVal)
|
||||||
|
if input != nil:
|
||||||
|
expectString(input)
|
||||||
|
p.inputStream.write(input.strVal)
|
||||||
|
p.inputStream.close()
|
||||||
|
result = newStrNode(nkStrLit, p.readOutput)
|
||||||
|
result.typ = getSysType(tyString)
|
||||||
|
result.info = cmd.info
|
||||||
|
|
||||||
proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
|
proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
|
||||||
var
|
var
|
||||||
n = original.copyTree
|
n = original.copyTree
|
||||||
|
|
@ -960,6 +997,11 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||||
of mParseStmtToAst: result = evalParseStmt(c, n)
|
of mParseStmtToAst: result = evalParseStmt(c, n)
|
||||||
of mExpandToAst: result = evalExpandToAst(c, n)
|
of mExpandToAst: result = evalExpandToAst(c, n)
|
||||||
of mTypeTrait: result = evalTypeTrait(n, c.module)
|
of mTypeTrait: result = evalTypeTrait(n, c.module)
|
||||||
|
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
|
||||||
|
of mStaticExec:
|
||||||
|
let cmd = evalAux(c, n.sons[1], {})
|
||||||
|
let input = if n.sonsLen == 3: evalAux(c, n.sons[2], {}) else: nil
|
||||||
|
result = evalStaticExec(cmd, input)
|
||||||
of mNLen:
|
of mNLen:
|
||||||
result = evalAux(c, n.sons[1], {efLValue})
|
result = evalAux(c, n.sons[1], {efLValue})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ type
|
||||||
errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
|
errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
|
||||||
errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
|
errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
|
||||||
errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
|
errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
|
||||||
errXCannotBeClosure,
|
errXCannotBeClosure, errXMustBeCompileTime,
|
||||||
errUser,
|
errUser,
|
||||||
warnCannotOpenFile,
|
warnCannotOpenFile,
|
||||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||||
|
|
@ -327,6 +327,7 @@ const
|
||||||
errWrongSymbolX: "usage of \'$1\' is a user-defined error",
|
errWrongSymbolX: "usage of \'$1\' is a user-defined error",
|
||||||
errIllegalCaptureX: "illegal capture '$1'",
|
errIllegalCaptureX: "illegal capture '$1'",
|
||||||
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
|
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
|
||||||
|
errXMustBeCompileTime: "'$1' can only be used in compile-time context",
|
||||||
errUser: "$1",
|
errUser: "$1",
|
||||||
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
|
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
|
||||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
|
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,8 @@ proc optInd*(p: var TParser, n: PNode)
|
||||||
proc indAndComment*(p: var TParser, n: PNode)
|
proc indAndComment*(p: var TParser, n: PNode)
|
||||||
proc setBaseFlags*(n: PNode, base: TNumericalBase)
|
proc setBaseFlags*(n: PNode, base: TNumericalBase)
|
||||||
proc parseSymbol*(p: var TParser): PNode
|
proc parseSymbol*(p: var TParser): PNode
|
||||||
|
proc parseTry(p: var TParser): PNode
|
||||||
|
proc parseCase(p: var TParser): PNode
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
proc getTok(p: var TParser) =
|
proc getTok(p: var TParser) =
|
||||||
|
|
@ -468,6 +470,11 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result)
|
exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result)
|
||||||
parseDoBlocks(p, result)
|
parseDoBlocks(p, result)
|
||||||
|
of tkDo:
|
||||||
|
var a = result
|
||||||
|
result = newNodeP(nkCall, p)
|
||||||
|
addSon(result, a)
|
||||||
|
parseDoBlocks(p, result)
|
||||||
of tkDot:
|
of tkDot:
|
||||||
result = dotExpr(p, result)
|
result = dotExpr(p, result)
|
||||||
result = parseGStrLit(p, result)
|
result = parseGStrLit(p, result)
|
||||||
|
|
@ -704,6 +711,8 @@ proc parseExpr(p: var TParser): PNode =
|
||||||
case p.tok.tokType:
|
case p.tok.tokType:
|
||||||
of tkIf: result = parseIfExpr(p, nkIfExpr)
|
of tkIf: result = parseIfExpr(p, nkIfExpr)
|
||||||
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
|
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
|
||||||
|
of tkTry: result = parseTry(p)
|
||||||
|
of tkCase: result = parseCase(p)
|
||||||
else: result = lowestExpr(p)
|
else: result = lowestExpr(p)
|
||||||
|
|
||||||
proc primary(p: var TParser, skipSuffix = false): PNode =
|
proc primary(p: var TParser, skipSuffix = false): PNode =
|
||||||
|
|
@ -944,13 +953,19 @@ proc parseWhile(p: var TParser): PNode =
|
||||||
proc parseCase(p: var TParser): PNode =
|
proc parseCase(p: var TParser): PNode =
|
||||||
var
|
var
|
||||||
b: PNode
|
b: PNode
|
||||||
inElif: bool
|
inElif= false
|
||||||
|
wasIndented = false
|
||||||
result = newNodeP(nkCaseStmt, p)
|
result = newNodeP(nkCaseStmt, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
addSon(result, parseExpr(p))
|
addSon(result, parseExpr(p))
|
||||||
if p.tok.tokType == tkColon: getTok(p)
|
if p.tok.tokType == tkColon: getTok(p)
|
||||||
skipComment(p, result)
|
skipComment(p, result)
|
||||||
inElif = false
|
|
||||||
|
if p.tok.tokType == tkInd:
|
||||||
|
pushInd(p.lex, p.tok.indent)
|
||||||
|
getTok(p)
|
||||||
|
wasIndented = true
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
if p.tok.tokType == tkSad: getTok(p)
|
if p.tok.tokType == tkSad: getTok(p)
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
|
|
@ -975,6 +990,10 @@ proc parseCase(p: var TParser): PNode =
|
||||||
addSon(result, b)
|
addSon(result, b)
|
||||||
if b.kind == nkElse: break
|
if b.kind == nkElse: break
|
||||||
|
|
||||||
|
if wasIndented:
|
||||||
|
eat(p, tkDed)
|
||||||
|
popInd(p.lex)
|
||||||
|
|
||||||
proc parseTry(p: var TParser): PNode =
|
proc parseTry(p: var TParser): PNode =
|
||||||
result = newNodeP(nkTryStmt, p)
|
result = newNodeP(nkTryStmt, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -999,6 +1018,13 @@ proc parseTry(p: var TParser): PNode =
|
||||||
if b.kind == nkFinally: break
|
if b.kind == nkFinally: break
|
||||||
if b == nil: parMessage(p, errTokenExpected, "except")
|
if b == nil: parMessage(p, errTokenExpected, "except")
|
||||||
|
|
||||||
|
proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
|
||||||
|
result = newNodeP(kind, p)
|
||||||
|
getTok(p)
|
||||||
|
eat(p, tkColon)
|
||||||
|
skipComment(p, result)
|
||||||
|
addSon(result, parseStmt(p))
|
||||||
|
|
||||||
proc parseFor(p: var TParser): PNode =
|
proc parseFor(p: var TParser): PNode =
|
||||||
result = newNodeP(nkForStmt, p)
|
result = newNodeP(nkForStmt, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -1393,6 +1419,8 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
|
||||||
of tkWhile: result = parseWhile(p)
|
of tkWhile: result = parseWhile(p)
|
||||||
of tkCase: result = parseCase(p)
|
of tkCase: result = parseCase(p)
|
||||||
of tkTry: result = parseTry(p)
|
of tkTry: result = parseTry(p)
|
||||||
|
of tkFinally: result = parseExceptBlock(p, nkFinally)
|
||||||
|
of tkExcept: result = parseExceptBlock(p, nkExceptBranch)
|
||||||
of tkFor: result = parseFor(p)
|
of tkFor: result = parseFor(p)
|
||||||
of tkBlock: result = parseBlock(p)
|
of tkBlock: result = parseBlock(p)
|
||||||
of tkStatic: result = parseStatic(p)
|
of tkStatic: result = parseStatic(p)
|
||||||
|
|
|
||||||
|
|
@ -89,9 +89,6 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||||
return nil
|
return nil
|
||||||
result = evalTypedExpr(c, e)
|
result = evalTypedExpr(c, e)
|
||||||
|
|
||||||
proc semAndEvalConstExpr(c: PContext, n: PNode): PNode =
|
|
||||||
result = semConstExpr(c, n)
|
|
||||||
|
|
||||||
include seminst, semcall
|
include seminst, semcall
|
||||||
|
|
||||||
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
|
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
|
|
@ -219,12 +216,8 @@ proc myClose(context: PPassContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
InternalError(n.info, "n is not nil") #result := n;
|
InternalError(n.info, "n is not nil") #result := n;
|
||||||
addCodeForGenerics(c, result)
|
addCodeForGenerics(c, result)
|
||||||
# we produce a fake include statement for every slurped filename, so that
|
if c.module.ast != nil:
|
||||||
# the module dependencies are accurate:
|
result.add(c.module.ast)
|
||||||
var ics = newNode(nkIncludeStmt)
|
|
||||||
for s in items(c.slurpedFiles): ics.add(newStrNode(nkStrLit, s))
|
|
||||||
result.add(ics)
|
|
||||||
|
|
||||||
checkThreads(c)
|
checkThreads(c)
|
||||||
popOwner()
|
popOwner()
|
||||||
popProcCon(c)
|
popProcCon(c)
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,6 @@ type
|
||||||
filename*: string # the module's filename
|
filename*: string # the module's filename
|
||||||
userPragmas*: TStrTable
|
userPragmas*: TStrTable
|
||||||
evalContext*: PEvalContext
|
evalContext*: PEvalContext
|
||||||
slurpedFiles*: seq[string]
|
|
||||||
|
|
||||||
var
|
var
|
||||||
gGenericsCache: PGenericsCache # save for modularity
|
gGenericsCache: PGenericsCache # save for modularity
|
||||||
|
|
@ -153,7 +152,6 @@ proc newContext(module: PSym, nimfile: string): PContext =
|
||||||
result.filename = nimfile
|
result.filename = nimfile
|
||||||
result.includedFiles = initIntSet()
|
result.includedFiles = initIntSet()
|
||||||
initStrTable(result.userPragmas)
|
initStrTable(result.userPragmas)
|
||||||
result.slurpedFiles = @[]
|
|
||||||
if optSymbolFiles notin gGlobalOptions:
|
if optSymbolFiles notin gGlobalOptions:
|
||||||
# re-usage of generic instantiations across module boundaries is
|
# re-usage of generic instantiations across module boundaries is
|
||||||
# very nice for code size:
|
# very nice for code size:
|
||||||
|
|
|
||||||
|
|
@ -491,12 +491,6 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||||
skipTypes(t.sons[i], abstractInst).kind == tyVar:
|
skipTypes(t.sons[i], abstractInst).kind == tyVar:
|
||||||
n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
|
n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
|
||||||
|
|
||||||
|
|
||||||
proc expectStringArg(c: PContext, n: PNode, i: int): PNode =
|
|
||||||
result = c.semAndEvalConstExpr(n.sons[i+1])
|
|
||||||
if result.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
|
|
||||||
GlobalError(result.info, errStringLiteralExpected)
|
|
||||||
|
|
||||||
include semmagic
|
include semmagic
|
||||||
|
|
||||||
proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||||
|
|
@ -901,7 +895,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
n.sons[0] = makeDeref(n.sons[0])
|
n.sons[0] = makeDeref(n.sons[0])
|
||||||
# [] operator for tuples requires constant expression:
|
# [] operator for tuples requires constant expression:
|
||||||
n.sons[1] = semAndEvalConstExpr(c, n.sons[1])
|
n.sons[1] = semConstExpr(c, n.sons[1])
|
||||||
if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in
|
if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in
|
||||||
{tyInt..tyInt64}:
|
{tyInt..tyInt64}:
|
||||||
var idx = getOrdValue(n.sons[1])
|
var idx = getOrdValue(n.sons[1])
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||||
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
|
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
|
||||||
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
|
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
|
||||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
|
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
|
||||||
mNLen..mNError, mEqRef:
|
mNLen..mNError, mEqRef, mSlurp, mStaticExec:
|
||||||
nil
|
nil
|
||||||
of mRand:
|
of mRand:
|
||||||
result = newIntNodeT(math.random(a.getInt.int), n)
|
result = newIntNodeT(math.random(a.getInt.int), n)
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,6 @@ proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
var r = isPartOf(n[1], n[2])
|
var r = isPartOf(n[1], n[2])
|
||||||
result = newIntNodeT(ord(r), n)
|
result = newIntNodeT(ord(r), n)
|
||||||
|
|
||||||
proc semSlurp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|
||||||
assert sonsLen(n) == 2
|
|
||||||
var a = expectStringArg(c, n, 0)
|
|
||||||
try:
|
|
||||||
var filename = a.strVal.FindFile
|
|
||||||
var content = readFile(filename)
|
|
||||||
result = newStrNode(nkStrLit, content)
|
|
||||||
result.typ = getSysType(tyString)
|
|
||||||
result.info = n.info
|
|
||||||
c.slurpedFiles.add(a.strVal)
|
|
||||||
except EIO:
|
|
||||||
GlobalError(a.info, errCannotOpenFile, a.strVal)
|
|
||||||
|
|
||||||
proc expectIntLit(c: PContext, n: PNode): int =
|
proc expectIntLit(c: PContext, n: PNode): int =
|
||||||
let x = c.semConstExpr(c, n)
|
let x = c.semConstExpr(c, n)
|
||||||
case x.kind
|
case x.kind
|
||||||
|
|
@ -56,7 +43,6 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
|
||||||
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
flags: TExprFlags): PNode =
|
flags: TExprFlags): PNode =
|
||||||
case n[0].sym.magic
|
case n[0].sym.magic
|
||||||
of mSlurp: result = semSlurp(c, n, flags)
|
|
||||||
of mIsPartOf: result = semIsPartOf(c, n, flags)
|
of mIsPartOf: result = semIsPartOf(c, n, flags)
|
||||||
of mTypeTrait: result = semTypeTraits(c, n)
|
of mTypeTrait: result = semTypeTraits(c, n)
|
||||||
of mAstToStr:
|
of mAstToStr:
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||||
case it.kind
|
case it.kind
|
||||||
of nkElifBranch, nkElifExpr:
|
of nkElifBranch, nkElifExpr:
|
||||||
checkSonsLen(it, 2)
|
checkSonsLen(it, 2)
|
||||||
var e = semAndEvalConstExpr(c, it.sons[0])
|
var e = semConstExpr(c, it.sons[0])
|
||||||
if e.kind != nkIntLit: InternalError(n.info, "semWhen")
|
if e.kind != nkIntLit: InternalError(n.info, "semWhen")
|
||||||
if e.intVal != 0 and result == nil:
|
if e.intVal != 0 and result == nil:
|
||||||
setResult(it.sons[1])
|
setResult(it.sons[1])
|
||||||
|
|
@ -772,6 +772,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
incl(s.flags, sfForward)
|
incl(s.flags, sfForward)
|
||||||
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
||||||
sideEffectsCheck(c, s)
|
sideEffectsCheck(c, s)
|
||||||
|
if result.sons[namePos].sym.name.id == ord(wDestroy):
|
||||||
|
if s.typ.sons.len == 2:
|
||||||
|
let typ = s.typ.sons[1].skipTypes({tyVar})
|
||||||
|
typ.destructor = s
|
||||||
if s.typ.callConv == ccClosure and s.owner.kind == skModule:
|
if s.typ.callConv == ccClosure and s.owner.kind == skModule:
|
||||||
localError(s.info, errXCannotBeClosure, s.name.s)
|
localError(s.info, errXCannotBeClosure, s.name.s)
|
||||||
closeScope(c.tab) # close scope for parameters
|
closeScope(c.tab) # close scope for parameters
|
||||||
|
|
@ -860,6 +864,62 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
||||||
|
|
||||||
|
proc insertDestructors(c: PContext, varSection: PNode):
|
||||||
|
tuple[outer: PNode, inner: PNode] =
|
||||||
|
# Accepts a var or let section.
|
||||||
|
#
|
||||||
|
# When a var section has variables with destructors
|
||||||
|
# the var section is split up and finally blocks are inserted
|
||||||
|
# immediately after all "destructable" vars
|
||||||
|
#
|
||||||
|
# In case there were no destrucable variables, the proc returns
|
||||||
|
# (nil, nil) and the enclosing stmt-list requires no modifications.
|
||||||
|
#
|
||||||
|
# Otherwise, after the try blocks are created, the rest of the enclosing
|
||||||
|
# stmt-list should be inserted in the most `inner` such block (corresponding
|
||||||
|
# to the last variable).
|
||||||
|
#
|
||||||
|
# `outer` is a statement list that should replace the original var section.
|
||||||
|
# It will include the new truncated var section followed by the outermost
|
||||||
|
# try block.
|
||||||
|
let totalVars = varSection.sonsLen
|
||||||
|
for j in countup(0, totalVars - 1):
|
||||||
|
let
|
||||||
|
varId = varSection[j][0]
|
||||||
|
varTyp = varId.sym.typ
|
||||||
|
info = varId.info
|
||||||
|
|
||||||
|
if varTyp != nil and instantiateDestructor(varTyp):
|
||||||
|
var tryStmt = newNodeI(nkTryStmt, info)
|
||||||
|
|
||||||
|
if j < totalVars - 1:
|
||||||
|
var remainingVars = newNodeI(varSection.kind, info)
|
||||||
|
remainingVars.sons = varSection.sons[(j+1)..(-1)]
|
||||||
|
let (outer, inner) = insertDestructors(c, remainingVars)
|
||||||
|
if outer != nil:
|
||||||
|
tryStmt.addSon(outer)
|
||||||
|
result.inner = inner
|
||||||
|
else:
|
||||||
|
result.inner = newNodeI(nkStmtList, info)
|
||||||
|
result.inner.addSon(remainingVars)
|
||||||
|
tryStmt.addSon(result.inner)
|
||||||
|
else:
|
||||||
|
result.inner = newNodeI(nkStmtList, info)
|
||||||
|
tryStmt.addSon(result.inner)
|
||||||
|
|
||||||
|
tryStmt.addSon(
|
||||||
|
newNode(nkFinally, info, @[
|
||||||
|
semStmt(c, newNode(nkCall, info, @[
|
||||||
|
semSym(c, varId, varTyp.destructor, {}),
|
||||||
|
semSym(c, varId, varId.sym, {})]))]))
|
||||||
|
|
||||||
|
result.outer = newNodeI(nkStmtList, info)
|
||||||
|
varSection.sons.setLen(j+1)
|
||||||
|
result.outer.addSon(varSection)
|
||||||
|
result.outer.addSon(tryStmt)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
proc SemStmt(c: PContext, n: PNode): PNode =
|
proc SemStmt(c: PContext, n: PNode): PNode =
|
||||||
const # must be last statements in a block:
|
const # must be last statements in a block:
|
||||||
LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
|
LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
|
||||||
|
|
@ -876,12 +936,42 @@ proc SemStmt(c: PContext, n: PNode): PNode =
|
||||||
of nkStmtList:
|
of nkStmtList:
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
for i in countup(0, length - 1):
|
for i in countup(0, length - 1):
|
||||||
|
case n.sons[i].kind
|
||||||
|
of nkFinally, nkExceptBranch:
|
||||||
|
# stand-alone finally and except blocks are
|
||||||
|
# transformed into regular try blocks:
|
||||||
|
#
|
||||||
|
# var f = fopen("somefile") | var f = fopen("somefile")
|
||||||
|
# finally: fcsole(f) | try:
|
||||||
|
# ... | ...
|
||||||
|
# | finally:
|
||||||
|
# | fclose(f)
|
||||||
|
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
|
||||||
|
var body = newNodeI(nkStmtList, n.sons[i].info)
|
||||||
|
if i < n.sonsLen - 1:
|
||||||
|
body.sons = n.sons[(i+1)..(-1)]
|
||||||
|
tryStmt.addSon(body)
|
||||||
|
tryStmt.addSon(n.sons[i])
|
||||||
|
n.sons[i] = semTry(c, tryStmt)
|
||||||
|
n.sons.setLen(i+1)
|
||||||
|
return
|
||||||
|
else:
|
||||||
n.sons[i] = semStmt(c, n.sons[i])
|
n.sons[i] = semStmt(c, n.sons[i])
|
||||||
if n.sons[i].kind in LastBlockStmts:
|
case n.sons[i].kind
|
||||||
|
of nkVarSection, nkLetSection:
|
||||||
|
let (outer, inner) = insertDestructors(c, n.sons[i])
|
||||||
|
if outer != nil:
|
||||||
|
n.sons[i] = outer
|
||||||
|
for j in countup(i+1, length-1):
|
||||||
|
inner.addSon(SemStmt(c, n.sons[j]))
|
||||||
|
n.sons.setLen(i+1)
|
||||||
|
return
|
||||||
|
of LastBlockStmts:
|
||||||
for j in countup(i + 1, length - 1):
|
for j in countup(i + 1, length - 1):
|
||||||
case n.sons[j].kind
|
case n.sons[j].kind
|
||||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil
|
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil
|
||||||
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
||||||
|
else: nil
|
||||||
of nkRaiseStmt: result = semRaise(c, n)
|
of nkRaiseStmt: result = semRaise(c, n)
|
||||||
of nkVarSection: result = semVarOrLet(c, n, skVar)
|
of nkVarSection: result = semVarOrLet(c, n, skVar)
|
||||||
of nkLetSection: result = semVarOrLet(c, n, skLet)
|
of nkLetSection: result = semVarOrLet(c, n, skLet)
|
||||||
|
|
|
||||||
|
|
@ -1062,3 +1062,10 @@ proc getSize(typ: PType): biggestInt =
|
||||||
result = computeSize(typ)
|
result = computeSize(typ)
|
||||||
if result < 0: InternalError("getSize(" & $typ.kind & ')')
|
if result < 0: InternalError("getSize(" & $typ.kind & ')')
|
||||||
|
|
||||||
|
proc instantiateDestructor*(typ: PType): bool =
|
||||||
|
# return true if the type already had a user-defined
|
||||||
|
# destructor or if the compiler generated a default
|
||||||
|
# member-wise one
|
||||||
|
if typ.destructor != nil: return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ type
|
||||||
wColon, wColonColon, wEquals, wDot, wDotDot,
|
wColon, wColonColon, wEquals, wDot, wDotDot,
|
||||||
wStar, wMinus,
|
wStar, wMinus,
|
||||||
wMagic, wThread, wFinal, wProfiler, wObjChecks,
|
wMagic, wThread, wFinal, wProfiler, wObjChecks,
|
||||||
|
|
||||||
|
wDestroy,
|
||||||
|
|
||||||
wImmediate, wImportCpp, wImportObjC,
|
wImmediate, wImportCpp, wImportObjC,
|
||||||
wImportCompilerProc,
|
wImportCompilerProc,
|
||||||
wImportc, wExportc, wIncompleteStruct,
|
wImportc, wExportc, wIncompleteStruct,
|
||||||
|
|
@ -112,6 +115,8 @@ const
|
||||||
"*", "-",
|
"*", "-",
|
||||||
"magic", "thread", "final", "profiler", "objchecks",
|
"magic", "thread", "final", "profiler", "objchecks",
|
||||||
|
|
||||||
|
"destroy",
|
||||||
|
|
||||||
"immediate", "importcpp", "importobjc",
|
"immediate", "importcpp", "importobjc",
|
||||||
"importcompilerproc", "importc", "exportc", "incompletestruct",
|
"importcompilerproc", "importc", "exportc", "incompletestruct",
|
||||||
"align", "nodecl", "pure", "sideeffect",
|
"align", "nodecl", "pure", "sideeffect",
|
||||||
|
|
|
||||||
|
|
@ -1879,6 +1879,15 @@ handled, it is propagated through the call stack. This means that often
|
||||||
the rest of the procedure - that is not within a ``finally`` clause -
|
the rest of the procedure - that is not within a ``finally`` clause -
|
||||||
is not executed (if an exception occurs).
|
is not executed (if an exception occurs).
|
||||||
|
|
||||||
|
`except`:idx: and `finally`:idx: can also be used as a stand-alone statements.
|
||||||
|
Any statements following them in the current block will be considered to be
|
||||||
|
in an implicit try block:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
var f = fopen("numbers.txt", "r")
|
||||||
|
finally: fcsole(f)
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
Return statement
|
Return statement
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
|
||||||
|
|
@ -2168,10 +2168,22 @@ proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo".}
|
||||||
## the `typeinfo` module instead.
|
## the `typeinfo` module instead.
|
||||||
|
|
||||||
proc slurp*(filename: string): string {.magic: "Slurp".}
|
proc slurp*(filename: string): string {.magic: "Slurp".}
|
||||||
## compiletime ``readFile`` proc for easy `resource`:idx: embedding:
|
proc staticRead*(filename: string): string {.magic: "Slurp".}
|
||||||
|
## compile-time ``readFile`` proc for easy `resource`:idx: embedding:
|
||||||
## .. code-block:: nimrod
|
## .. code-block:: nimrod
|
||||||
##
|
##
|
||||||
## const myResource = slurp"mydatafile.bin"
|
## const myResource = staticRead"mydatafile.bin"
|
||||||
|
##
|
||||||
|
|
||||||
|
proc staticExec*(command: string, input = ""): string {.
|
||||||
|
magic: "StaticExec".} = nil
|
||||||
|
## executes an external process at compile-time.
|
||||||
|
## if `input` is not an empty string, it will be passed as a standard input
|
||||||
|
## to the executed program.
|
||||||
|
## .. code-block:: nimrod
|
||||||
|
##
|
||||||
|
## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") &
|
||||||
|
## "\nCompiled on " & staticExec("uname -v")
|
||||||
##
|
##
|
||||||
|
|
||||||
proc `+=`*[T](x, y: ordinal[T]) {.magic: "Inc", noSideEffect.}
|
proc `+=`*[T](x, y: ordinal[T]) {.magic: "Inc", noSideEffect.}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ Library Additions
|
||||||
assignments.
|
assignments.
|
||||||
- Added ``system.eval`` that can execute an anonymous block of code at
|
- Added ``system.eval`` that can execute an anonymous block of code at
|
||||||
compile time as if was a macro.
|
compile time as if was a macro.
|
||||||
|
- Added ``system.staticExec`` for compile-time execution of external programs
|
||||||
|
- Added ``system.staticRead`` as a synonym for slurp
|
||||||
- Added ``macros.emit`` that can emit an arbitrary computed string as nimrod
|
- Added ``macros.emit`` that can emit an arbitrary computed string as nimrod
|
||||||
code during compilation.
|
code during compilation.
|
||||||
- Added ``strutils.parseEnum``.
|
- Added ``strutils.parseEnum``.
|
||||||
|
|
@ -102,6 +104,7 @@ Language Additions
|
||||||
- ``when`` expressions are now allowed just like ``if`` expressions.
|
- ``when`` expressions are now allowed just like ``if`` expressions.
|
||||||
- The precedence for operators starting with ``@`` is different now
|
- The precedence for operators starting with ``@`` is different now
|
||||||
allowing for *sigil-like* operators.
|
allowing for *sigil-like* operators.
|
||||||
|
- Stand-alone ``finally`` and ``except`` blocks are now supported.
|
||||||
|
|
||||||
|
|
||||||
2012-02-09 Version 0.8.14 released
|
2012-02-09 Version 0.8.14 released
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue