mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-07 04:14:19 +00:00
Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
@@ -371,7 +371,7 @@ type
|
||||
TMagic* = enum # symbols that require compiler magic:
|
||||
mNone,
|
||||
mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
|
||||
mEcho, mShallowCopy, mSlurp,
|
||||
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst,
|
||||
mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
||||
@@ -542,6 +542,9 @@ type
|
||||
# for easy generation of proper error messages
|
||||
# for variant record fields the discriminant
|
||||
# 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
|
||||
position*: int # used for many different things:
|
||||
# for enum fields its position;
|
||||
@@ -568,6 +571,9 @@ type
|
||||
# for record types a nkRecord node
|
||||
# for enum types a list of symbols
|
||||
# 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
|
||||
sym*: PSym # types have the sym associated with them
|
||||
# it is used for converting types to strings
|
||||
@@ -740,6 +746,16 @@ proc linkTo*(s: PSym, t: PType): PSym {.discardable.} =
|
||||
s.typ = t
|
||||
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:
|
||||
GrowthFactor* = 2 # 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 mNLen..mNError:
|
||||
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)
|
||||
|
||||
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)
|
||||
of mNewSeq: binaryStmt(p, n, r, "", "$1 = new Array($2)")
|
||||
of mEcho: genEcho(p, n, r)
|
||||
of mSlurp, mStaticExec:
|
||||
localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
|
||||
else:
|
||||
genCall(p, n, r)
|
||||
#else internalError(e.info, 'genMagic: ' + magicToStr[op]);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import
|
||||
strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets,
|
||||
msgs, os, condsyms, idents, renderer, types, passes, semfold, transf,
|
||||
parser, ropes, rodread, idgen
|
||||
parser, ropes, rodread, idgen, osproc, streams
|
||||
|
||||
type
|
||||
PStackFrame* = ref TStackFrame
|
||||
@@ -910,6 +910,43 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode =
|
||||
else:
|
||||
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 =
|
||||
var
|
||||
n = original.copyTree
|
||||
@@ -960,6 +997,11 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
of mParseStmtToAst: result = evalParseStmt(c, n)
|
||||
of mExpandToAst: result = evalExpandToAst(c, n)
|
||||
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:
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
if isSpecial(result): return
|
||||
|
||||
@@ -94,7 +94,7 @@ type
|
||||
errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
|
||||
errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
|
||||
errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
|
||||
errXCannotBeClosure,
|
||||
errXCannotBeClosure, errXMustBeCompileTime,
|
||||
errUser,
|
||||
warnCannotOpenFile,
|
||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||
@@ -327,6 +327,7 @@ const
|
||||
errWrongSymbolX: "usage of \'$1\' is a user-defined error",
|
||||
errIllegalCaptureX: "illegal capture '$1'",
|
||||
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
|
||||
errXMustBeCompileTime: "'$1' can only be used in compile-time context",
|
||||
errUser: "$1",
|
||||
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
|
||||
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 setBaseFlags*(n: PNode, base: TNumericalBase)
|
||||
proc parseSymbol*(p: var TParser): PNode
|
||||
proc parseTry(p: var TParser): PNode
|
||||
proc parseCase(p: var TParser): PNode
|
||||
# implementation
|
||||
|
||||
proc getTok(p: var TParser) =
|
||||
@@ -468,6 +470,11 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||
addSon(result, a)
|
||||
exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result)
|
||||
parseDoBlocks(p, result)
|
||||
of tkDo:
|
||||
var a = result
|
||||
result = newNodeP(nkCall, p)
|
||||
addSon(result, a)
|
||||
parseDoBlocks(p, result)
|
||||
of tkDot:
|
||||
result = dotExpr(p, result)
|
||||
result = parseGStrLit(p, result)
|
||||
@@ -704,6 +711,8 @@ proc parseExpr(p: var TParser): PNode =
|
||||
case p.tok.tokType:
|
||||
of tkIf: result = parseIfExpr(p, nkIfExpr)
|
||||
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
|
||||
of tkTry: result = parseTry(p)
|
||||
of tkCase: result = parseCase(p)
|
||||
else: result = lowestExpr(p)
|
||||
|
||||
proc primary(p: var TParser, skipSuffix = false): PNode =
|
||||
@@ -944,13 +953,19 @@ proc parseWhile(p: var TParser): PNode =
|
||||
proc parseCase(p: var TParser): PNode =
|
||||
var
|
||||
b: PNode
|
||||
inElif: bool
|
||||
inElif= false
|
||||
wasIndented = false
|
||||
result = newNodeP(nkCaseStmt, p)
|
||||
getTok(p)
|
||||
addSon(result, parseExpr(p))
|
||||
if p.tok.tokType == tkColon: getTok(p)
|
||||
skipComment(p, result)
|
||||
inElif = false
|
||||
|
||||
if p.tok.tokType == tkInd:
|
||||
pushInd(p.lex, p.tok.indent)
|
||||
getTok(p)
|
||||
wasIndented = true
|
||||
|
||||
while true:
|
||||
if p.tok.tokType == tkSad: getTok(p)
|
||||
case p.tok.tokType
|
||||
@@ -973,8 +988,12 @@ proc parseCase(p: var TParser): PNode =
|
||||
skipComment(p, b)
|
||||
addSon(b, parseStmt(p))
|
||||
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 =
|
||||
result = newNodeP(nkTryStmt, p)
|
||||
getTok(p)
|
||||
@@ -998,7 +1017,14 @@ proc parseTry(p: var TParser): PNode =
|
||||
addSon(result, b)
|
||||
if b.kind == nkFinally: break
|
||||
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 =
|
||||
result = newNodeP(nkForStmt, p)
|
||||
getTok(p)
|
||||
@@ -1393,6 +1419,8 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
|
||||
of tkWhile: result = parseWhile(p)
|
||||
of tkCase: result = parseCase(p)
|
||||
of tkTry: result = parseTry(p)
|
||||
of tkFinally: result = parseExceptBlock(p, nkFinally)
|
||||
of tkExcept: result = parseExceptBlock(p, nkExceptBranch)
|
||||
of tkFor: result = parseFor(p)
|
||||
of tkBlock: result = parseBlock(p)
|
||||
of tkStatic: result = parseStatic(p)
|
||||
|
||||
@@ -89,9 +89,6 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||
return nil
|
||||
result = evalTypedExpr(c, e)
|
||||
|
||||
proc semAndEvalConstExpr(c: PContext, n: PNode): PNode =
|
||||
result = semConstExpr(c, n)
|
||||
|
||||
include seminst, semcall
|
||||
|
||||
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
|
||||
@@ -219,12 +216,8 @@ proc myClose(context: PPassContext, n: PNode): PNode =
|
||||
else:
|
||||
InternalError(n.info, "n is not nil") #result := n;
|
||||
addCodeForGenerics(c, result)
|
||||
# we produce a fake include statement for every slurped filename, so that
|
||||
# the module dependencies are accurate:
|
||||
var ics = newNode(nkIncludeStmt)
|
||||
for s in items(c.slurpedFiles): ics.add(newStrNode(nkStrLit, s))
|
||||
result.add(ics)
|
||||
|
||||
if c.module.ast != nil:
|
||||
result.add(c.module.ast)
|
||||
checkThreads(c)
|
||||
popOwner()
|
||||
popProcCon(c)
|
||||
|
||||
@@ -73,7 +73,6 @@ type
|
||||
filename*: string # the module's filename
|
||||
userPragmas*: TStrTable
|
||||
evalContext*: PEvalContext
|
||||
slurpedFiles*: seq[string]
|
||||
|
||||
var
|
||||
gGenericsCache: PGenericsCache # save for modularity
|
||||
@@ -153,7 +152,6 @@ proc newContext(module: PSym, nimfile: string): PContext =
|
||||
result.filename = nimfile
|
||||
result.includedFiles = initIntSet()
|
||||
initStrTable(result.userPragmas)
|
||||
result.slurpedFiles = @[]
|
||||
if optSymbolFiles notin gGlobalOptions:
|
||||
# re-usage of generic instantiations across module boundaries is
|
||||
# very nice for code size:
|
||||
|
||||
@@ -491,12 +491,6 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||
skipTypes(t.sons[i], abstractInst).kind == tyVar:
|
||||
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
|
||||
|
||||
proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||
@@ -901,7 +895,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
checkSonsLen(n, 2)
|
||||
n.sons[0] = makeDeref(n.sons[0])
|
||||
# [] 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
|
||||
{tyInt..tyInt64}:
|
||||
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,
|
||||
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
|
||||
mNLen..mNError, mEqRef:
|
||||
mNLen..mNError, mEqRef, mSlurp, mStaticExec:
|
||||
nil
|
||||
of mRand:
|
||||
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])
|
||||
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 =
|
||||
let x = c.semConstExpr(c, n)
|
||||
case x.kind
|
||||
@@ -56,7 +43,6 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
|
||||
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
flags: TExprFlags): PNode =
|
||||
case n[0].sym.magic
|
||||
of mSlurp: result = semSlurp(c, n, flags)
|
||||
of mIsPartOf: result = semIsPartOf(c, n, flags)
|
||||
of mTypeTrait: result = semTypeTraits(c, n)
|
||||
of mAstToStr:
|
||||
|
||||
@@ -27,7 +27,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
case it.kind
|
||||
of nkElifBranch, nkElifExpr:
|
||||
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.intVal != 0 and result == nil:
|
||||
setResult(it.sons[1])
|
||||
@@ -772,6 +772,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
incl(s.flags, sfForward)
|
||||
elif sfBorrow in s.flags: semBorrow(c, n, 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:
|
||||
localError(s.info, errXCannotBeClosure, s.name.s)
|
||||
closeScope(c.tab) # close scope for parameters
|
||||
@@ -860,6 +864,62 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||
if result.isNil:
|
||||
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 =
|
||||
const # must be last statements in a block:
|
||||
LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
|
||||
@@ -875,13 +935,43 @@ proc SemStmt(c: PContext, n: PNode): PNode =
|
||||
of nkBlockStmt: result = semBlock(c, n)
|
||||
of nkStmtList:
|
||||
var length = sonsLen(n)
|
||||
for i in countup(0, length - 1):
|
||||
n.sons[i] = semStmt(c, n.sons[i])
|
||||
if n.sons[i].kind in LastBlockStmts:
|
||||
for j in countup(i + 1, length - 1):
|
||||
case n.sons[j].kind
|
||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil
|
||||
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
||||
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])
|
||||
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):
|
||||
case n.sons[j].kind
|
||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil
|
||||
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
||||
else: nil
|
||||
of nkRaiseStmt: result = semRaise(c, n)
|
||||
of nkVarSection: result = semVarOrLet(c, n, skVar)
|
||||
of nkLetSection: result = semVarOrLet(c, n, skLet)
|
||||
|
||||
@@ -1061,4 +1061,11 @@ proc getReturnType*(s: PSym): PType =
|
||||
proc getSize(typ: PType): biggestInt =
|
||||
result = computeSize(typ)
|
||||
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,
|
||||
wStar, wMinus,
|
||||
wMagic, wThread, wFinal, wProfiler, wObjChecks,
|
||||
|
||||
wDestroy,
|
||||
|
||||
wImmediate, wImportCpp, wImportObjC,
|
||||
wImportCompilerProc,
|
||||
wImportc, wExportc, wIncompleteStruct,
|
||||
@@ -110,7 +113,9 @@ const
|
||||
|
||||
":", "::", "=", ".", "..",
|
||||
"*", "-",
|
||||
"magic", "thread", "final", "profiler", "objchecks",
|
||||
"magic", "thread", "final", "profiler", "objchecks",
|
||||
|
||||
"destroy",
|
||||
|
||||
"immediate", "importcpp", "importobjc",
|
||||
"importcompilerproc", "importc", "exportc", "incompletestruct",
|
||||
|
||||
@@ -388,37 +388,37 @@ indentation tokens is already described in the `Lexical Analysis`_ section.
|
||||
|
||||
Nimrod allows user-definable operators.
|
||||
Binary operators have 10 different levels of precedence.
|
||||
|
||||
Relevant character
|
||||
------------------
|
||||
|
||||
|
||||
Relevant character
|
||||
------------------
|
||||
|
||||
An operator symbol's *relevant character* is its first
|
||||
character unless the first character is ``\`` and its length is greater than 1
|
||||
then it is the second character.
|
||||
|
||||
This rule allows to escape operator symbols with ``\`` and keeps the operator's
|
||||
precedence and associativity; this is useful for meta programming.
|
||||
|
||||
|
||||
Associativity
|
||||
-------------
|
||||
|
||||
All binary operators are left-associative, except binary operators whose
|
||||
then it is the second character.
|
||||
|
||||
This rule allows to escape operator symbols with ``\`` and keeps the operator's
|
||||
precedence and associativity; this is useful for meta programming.
|
||||
|
||||
|
||||
Associativity
|
||||
-------------
|
||||
|
||||
All binary operators are left-associative, except binary operators whose
|
||||
relevant char is ``^``.
|
||||
|
||||
Precedence
|
||||
----------
|
||||
|
||||
Precedence
|
||||
----------
|
||||
|
||||
For operators that are not keywords the precedence is determined by the
|
||||
following rules:
|
||||
|
||||
If the operator ends with ``=`` and its relevant character is none of
|
||||
``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which
|
||||
has the lowest precedence.
|
||||
|
||||
If the operator's relevant character is ``@`` it is a `sigil-like`:idx:
|
||||
operator which binds stronger than a ``primarySuffix``: ``@x.abc`` is parsed
|
||||
as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``.
|
||||
has the lowest precedence.
|
||||
|
||||
If the operator's relevant character is ``@`` it is a `sigil-like`:idx:
|
||||
operator which binds stronger than a ``primarySuffix``: ``@x.abc`` is parsed
|
||||
as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``.
|
||||
|
||||
|
||||
Otherwise precedence is determined by the relevant character.
|
||||
@@ -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 -
|
||||
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
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -2168,10 +2168,22 @@ proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo".}
|
||||
## the `typeinfo` module instead.
|
||||
|
||||
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
|
||||
##
|
||||
## 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.}
|
||||
|
||||
@@ -27,6 +27,8 @@ Library Additions
|
||||
assignments.
|
||||
- Added ``system.eval`` that can execute an anonymous block of code at
|
||||
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
|
||||
code during compilation.
|
||||
- Added ``strutils.parseEnum``.
|
||||
@@ -102,6 +104,7 @@ Language Additions
|
||||
- ``when`` expressions are now allowed just like ``if`` expressions.
|
||||
- The precedence for operators starting with ``@`` is different now
|
||||
allowing for *sigil-like* operators.
|
||||
- Stand-alone ``finally`` and ``except`` blocks are now supported.
|
||||
|
||||
|
||||
2012-02-09 Version 0.8.14 released
|
||||
|
||||
Reference in New Issue
Block a user