Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq 2012-04-13 18:37:17 +02:00
commit 82813e58c4
31 changed files with 335 additions and 86 deletions

View file

@ -143,7 +143,7 @@ type
nkPragma, # a pragma statement nkPragma, # a pragma statement
nkPragmaBlock, # a pragma with a block nkPragmaBlock, # a pragma with a block
nkIfStmt, # an if statement nkIfStmt, # an if statement
nkWhenStmt, # a when statement nkWhenStmt, # a when expression or statement
nkForStmt, # a for statement nkForStmt, # a for statement
nkWhileStmt, # a while statement nkWhileStmt, # a while statement
nkCaseStmt, # a case statement nkCaseStmt, # a case statement
@ -243,8 +243,18 @@ const
sfFakeConst* = sfDeadCodeElim # const cannot be put into a data section sfFakeConst* = sfDeadCodeElim # const cannot be put into a data section
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
sfNoInit* = sfMainModule # don't generate code to init the variable sfNoInit* = sfMainModule # don't generate code to init the variable
sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded
# without considering any possible overloads # without considering any possible overloads
sfAnon* = sfCompilerProc # symbol name that was generated by the compiler
# the compiler will avoid printing such names
# in user messages.
const
# getting ready for the future expr/stmt merge
nkWhen* = nkWhenStmt
nkWhenExpr* = nkWhenStmt
type type
TTypeKind* = enum # order is important! TTypeKind* = enum # order is important!
@ -353,7 +363,8 @@ const
type type
TMagic* = enum # symbols that require compiler magic: TMagic* = enum # symbols that require compiler magic:
mNone, mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mIs, mOf, mNone,
mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
mEcho, mShallowCopy, mSlurp, mEcho, mShallowCopy, mSlurp,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mParseExprToAst, mParseStmtToAst, mExpandToAst,
mUnaryLt, mSucc, mUnaryLt, mSucc,

View file

@ -7,6 +7,8 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# included from cgen.nim
const const
RangeExpandLimit = 256 # do not generate ranges RangeExpandLimit = 256 # do not generate ranges
# over 'RangeExpandLimit' elements # over 'RangeExpandLimit' elements
@ -48,16 +50,20 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
proc genSingleVar(p: BProc, a: PNode) = proc genSingleVar(p: BProc, a: PNode) =
var v = a.sons[0].sym var v = a.sons[0].sym
if sfCompileTime in v.flags: return if sfCompileTime in v.flags: return
var targetProc = p
var immediateAsgn = a.sons[2].kind != nkEmpty var immediateAsgn = a.sons[2].kind != nkEmpty
if sfGlobal in v.flags: if sfGlobal in v.flags:
assignGlobalVar(p, v) if v.owner.kind != skModule:
genObjectInit(p, cpsInit, v.typ, v.loc, true) targetProc = p.module.preInitProc
assignGlobalVar(targetProc, v)
genObjectInit(targetProc, cpsInit, v.typ, v.loc, true)
else: else:
assignLocalVar(p, v) assignLocalVar(p, v)
initLocalVar(p, v, immediateAsgn) initLocalVar(p, v, immediateAsgn)
if immediateAsgn: if immediateAsgn:
genLineDir(p, a) genLineDir(targetProc, a)
loadInto(p, a.sons[0], a.sons[2], v.loc) loadInto(targetProc, a.sons[0], a.sons[2], v.loc)
proc genClosureVar(p: BProc, a: PNode) = proc genClosureVar(p: BProc, a: PNode) =
var immediateAsgn = a.sons[2].kind != nkEmpty var immediateAsgn = a.sons[2].kind != nkEmpty

View file

@ -859,6 +859,7 @@ proc genInitCode(m: BModule) =
app(prc, genSectionStart(cpsLocals)) app(prc, genSectionStart(cpsLocals))
app(prc, m.initProc.s[cpsLocals]) app(prc, m.initProc.s[cpsLocals])
app(prc, m.preInitProc.s[cpsLocals])
app(prc, genSectionEnd(cpsLocals)) app(prc, genSectionEnd(cpsLocals))
app(prc, genSectionStart(cfsTypeInit1)) app(prc, genSectionStart(cfsTypeInit1))
@ -875,10 +876,12 @@ proc genInitCode(m: BModule) =
app(prc, genSectionEnd(i)) app(prc, genSectionEnd(i))
app(prc, genSectionStart(cpsInit)) app(prc, genSectionStart(cpsInit))
app(prc, m.preInitProc.s[cpsInit])
app(prc, m.initProc.s[cpsInit]) app(prc, m.initProc.s[cpsInit])
app(prc, genSectionEnd(cpsInit)) app(prc, genSectionEnd(cpsInit))
app(prc, genSectionStart(cpsStmts)) app(prc, genSectionStart(cpsStmts))
app(prc, m.preInitProc.s[cpsStmts])
app(prc, m.initProc.s[cpsStmts]) app(prc, m.initProc.s[cpsStmts])
if optStackTrace in m.initProc.options and not m.PreventStackTrace: if optStackTrace in m.initProc.options and not m.PreventStackTrace:
app(prc, deinitFrame(m.initProc)) app(prc, deinitFrame(m.initProc))
@ -916,6 +919,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
result.typeInfoMarker = initIntSet() result.typeInfoMarker = initIntSet()
result.initProc = newProc(nil, result) result.initProc = newProc(nil, result)
result.initProc.options = gOptions result.initProc.options = gOptions
result.preInitProc = newProc(nil, result)
initNodeTable(result.dataCache) initNodeTable(result.dataCache)
result.typeStack = @[] result.typeStack = @[]
result.forwardedProcs = @[] result.forwardedProcs = @[]

View file

@ -93,6 +93,10 @@ type
headerFiles*: TLinkedList # needed headers to include headerFiles*: TLinkedList # needed headers to include
typeInfoMarker*: TIntSet # needed for generating type information typeInfoMarker*: TIntSet # needed for generating type information
initProc*: BProc # code for init procedure initProc*: BProc # code for init procedure
preInitProc*: BProc # code executed before the init proc
# used for initialization code for
# .global. variables
# (or instantiated generic variables)
typeStack*: TTypeSeq # used for type generation typeStack*: TTypeSeq # used for type generation
dataCache*: TNodeTable dataCache*: TNodeTable
forwardedProcs*: TSymSeq # keep forwarded procs here forwardedProcs*: TSymSeq # keep forwarded procs here

View file

@ -490,7 +490,7 @@ proc evalSwap(c: PEvalContext, n: PNode): PNode =
proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
var s = n.sym var s = n.sym
case s.kind case s.kind
of skProc, skConverter, skMacro: of skProc, skConverter, skMacro, skType:
result = n result = n
#result = s.getBody #result = s.getBody
of skVar, skLet, skForVar, skTemp, skResult: of skVar, skLet, skForVar, skTemp, skResult:
@ -891,7 +891,24 @@ proc evalTemplate*(n: PNode, sym: PSym): PNode =
result = evalTemplateAux(sym.getBody, args, sym) result = evalTemplateAux(sym.getBody, args, sym)
dec(evalTemplateCounter) dec(evalTemplateCounter)
proc evalTypeTrait*(n: PNode, context: PSym): PNode =
## XXX: This should be pretty much guaranteed to be true
# by the type traits procs' signitures, but until the
# code is more mature it doesn't hurt to be extra safe
internalAssert n.sons.len >= 2 and
n.sons[1].sym.typ.kind == tyTypeDesc
let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
case n.sons[0].sym.name.s
of "name":
result = newStrNode(nkStrLit, typ.typeToString)
result.typ = newType(tyString, context)
result.info = n.info
else:
internalAssert false
proc evalExpandToAst(c: PEvalContext, original: PNode): PNode = proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
var var
n = original.copyTree n = original.copyTree
@ -941,6 +958,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mParseExprToAst: result = evalParseExpr(c, n) of mParseExprToAst: result = evalParseExpr(c, n)
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 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

View file

@ -72,7 +72,7 @@ type
errNoPragmasAllowedForX, errNoGenericParamsAllowedForX, errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent, errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX, errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
errXNotAllowedHere, errInvalidControlFlowX, errATypeHasNoValue, errXNotAllowedHere, errInvalidControlFlowX,
errXisNoType, errCircumNeedsPointer, errInvalidExpression, errXisNoType, errCircumNeedsPointer, errInvalidExpression,
errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected, errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,
errNamedExprNotAllowed, errXExpectsOneTypeParam, errNamedExprNotAllowed, errXExpectsOneTypeParam,
@ -275,7 +275,6 @@ const
errInvalidPragmaX: "invalid pragma: $1", errInvalidPragmaX: "invalid pragma: $1",
errXNotAllowedHere: "$1 not allowed here", errXNotAllowedHere: "$1 not allowed here",
errInvalidControlFlowX: "invalid control flow: $1", errInvalidControlFlowX: "invalid control flow: $1",
errATypeHasNoValue: "a type has no value",
errXisNoType: "invalid type: \'$1\'", errXisNoType: "invalid type: \'$1\'",
errCircumNeedsPointer: "'[]' needs a pointer or reference type", errCircumNeedsPointer: "'[]' needs a pointer or reference type",
errInvalidExpression: "invalid expression", errInvalidExpression: "invalid expression",
@ -667,3 +666,6 @@ template AssertNotNil*(e: expr): expr =
if(e == nil): InternalError($InstantiationInfo()) if(e == nil): InternalError($InstantiationInfo())
e e
template InternalAssert*(e: bool): stmt =
if not e: InternalError($InstantiationInfo())

View file

@ -221,4 +221,4 @@ proc binaryStrSearch*(x: openarray[string], y: string): int =
# Can we keep this? I'm using it all the time # Can we keep this? I'm using it all the time
template nimdbg*: expr = c.filename.endsWith"nimdbg.nim" template nimdbg*: expr = c.filename.endsWith"nimdbg.nim"
template cnimdbg*: expr = p.module.filename.endsWith"nimdbg.nim"

View file

@ -264,16 +264,26 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
optInd(p, a) optInd(p, a)
eat(p, endTok) eat(p, endTok)
proc newDotExpr(p: var TParser, a: PNode): PNode = proc dotExpr(p: var TParser, a: PNode): PNode =
getTok(p) getTok(p)
optInd(p, a) optInd(p, a)
result = newNodeI(nkDotExpr, a.info) case p.tok.tokType
addSon(result, a) of tkType:
addSon(result, parseSymbol(p)) result = newNodeP(nkTypeOfExpr, p)
getTok(p)
addSon(result, a)
of tkAddr:
result = newNodeP(nkAddr, p)
getTok(p)
addSon(result, a)
else:
result = newNodeI(nkDotExpr, a.info)
addSon(result, a)
addSon(result, parseSymbol(p))
proc qualifiedIdent(p: var TParser): PNode = proc qualifiedIdent(p: var TParser): PNode =
result = parseSymbol(p) #optInd(p, result); result = parseSymbol(p) #optInd(p, result);
if p.tok.tokType == tkDot: result = newDotExpr(p, result) if p.tok.tokType == tkDot: result = dotExpr(p, result)
proc qualifiedIdentListAux(p: var TParser, endTok: TTokType, result: PNode) = proc qualifiedIdentListAux(p: var TParser, endTok: TTokType, result: PNode) =
getTok(p) getTok(p)
@ -477,7 +487,7 @@ proc primary(p: var TParser): PNode =
exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result) exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result)
parseDoBlocks(p, result) parseDoBlocks(p, result)
of tkDot: of tkDot:
result = newDotExpr(p, result) result = dotExpr(p, result)
result = parseGStrLit(p, result) result = parseGStrLit(p, result)
of tkBracketLe: of tkBracketLe:
result = indexExprList(p, result, nkBracketExpr, tkBracketRi) result = indexExprList(p, result, nkBracketExpr, tkBracketRi)
@ -506,8 +516,8 @@ proc lowestExprAux(p: var TParser, limit: int): PNode =
proc lowestExpr(p: var TParser): PNode = proc lowestExpr(p: var TParser): PNode =
result = lowestExprAux(p, -1) result = lowestExprAux(p, -1)
proc parseIfExpr(p: var TParser): PNode = proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
result = newNodeP(nkIfExpr, p) result = newNodeP(kind, p)
while true: while true:
getTok(p) # skip `if`, `elif` getTok(p) # skip `if`, `elif`
var branch = newNodeP(nkElifExpr, p) var branch = newNodeP(nkElifExpr, p)
@ -707,7 +717,8 @@ proc parseExpr(p: var TParser): PNode =
of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr) of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr)
of tkTuple: result = parseTuple(p) of tkTuple: result = parseTuple(p)
of tkProc: result = parseProcExpr(p, true) of tkProc: result = parseProcExpr(p, true)
of tkIf: result = parseIfExpr(p) of tkIf: result = parseIfExpr(p, nkIfExpr)
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
else: result = lowestExpr(p) else: result = lowestExpr(p)
proc parseTypeDesc(p: var TParser): PNode = proc parseTypeDesc(p: var TParser): PNode =
@ -718,7 +729,7 @@ proc isExprStart(p: TParser): bool =
case p.tok.tokType case p.tok.tokType
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind, of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind,
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr, tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
tkTuple, tkType: tkTuple, tkType, tkWhen:
result = true result = true
else: result = false else: result = false

View file

@ -51,7 +51,7 @@ const
wImportcpp, wImportobjc, wError} wImportcpp, wImportobjc, wError}
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern, wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern,
wImportcpp, wImportobjc, wError, wNoInit, wCompileTime} wImportcpp, wImportobjc, wError, wNoInit, wCompileTime, wGlobal}
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl, constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
wExtern, wImportcpp, wImportobjc, wError} wExtern, wImportcpp, wImportobjc, wError}
letPragmas* = varPragmas letPragmas* = varPragmas
@ -494,6 +494,9 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
noVal(it) noVal(it)
incl(sym.flags, sfCompileTime) incl(sym.flags, sfCompileTime)
incl(sym.loc.Flags, lfNoDecl) incl(sym.loc.Flags, lfNoDecl)
of wGlobal:
noVal(it)
incl(sym.flags, sfGlobal)
of wMerge: of wMerge:
noval(it) noval(it)
incl(sym.flags, sfMerge) incl(sym.flags, sfMerge)

View file

@ -349,7 +349,8 @@ proc lsub(n: PNode): int =
of nkBind: result = lsons(n) + len("bind_") of nkBind: result = lsons(n) + len("bind_")
of nkBindStmt: result = lcomma(n) + len("bind_") of nkBindStmt: result = lcomma(n) + len("bind_")
of nkCheckedFieldExpr: result = lsub(n.sons[0]) of nkCheckedFieldExpr: result = lsub(n.sons[0])
of nkLambda, nkDo: result = lsons(n) + len("lambda__=_") # XXX: render nkDo of nkLambda: result = lsons(n) + len("proc__=_")
of nkDo: result = lsons(n) + len("do__:_")
of nkConstDef, nkIdentDefs: of nkConstDef, nkIdentDefs:
result = lcomma(n, 0, - 3) result = lcomma(n, 0, - 3)
var L = sonsLen(n) var L = sonsLen(n)
@ -677,7 +678,17 @@ proc gident(g: var TSrcGen, n: PNode) =
t = tkOpr t = tkOpr
put(g, t, s) put(g, t, s)
if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id) if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id)
proc doParamsAux(g: var TSrcGen, params: PNode) =
if params.len > 1:
put(g, tkParLe, "(")
gcomma(g, params, 1)
put(g, tkParRi, ")")
if params.sons[0].kind != nkEmpty:
putWithSpace(g, tkOpr, "->")
gsub(g, params.sons[0])
proc gsub(g: var TSrcGen, n: PNode, c: TContext) = proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
if isNil(n): return if isNil(n): return
var var
@ -804,14 +815,19 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gsub(g, n.sons[0]) gsub(g, n.sons[0])
of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref:
gsub(g, n.sons[0]) gsub(g, n.sons[0])
of nkLambda, nkDo: # XXX: nkDo is rendered as regular lambda of nkLambda:
assert(n.sons[genericParamsPos].kind == nkEmpty) putWithSpace(g, tkLambda, "proc")
putWithSpace(g, tkLambda, "lambda")
gsub(g, n.sons[paramsPos]) gsub(g, n.sons[paramsPos])
gsub(g, n.sons[pragmasPos]) gsub(g, n.sons[pragmasPos])
put(g, tkSpaces, Space) put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=") putWithSpace(g, tkEquals, "=")
gsub(g, n.sons[bodyPos]) gsub(g, n.sons[bodyPos])
of nkDo:
putWithSpace(g, tkDo, "do")
doParamsAux(g, n.sons[paramsPos])
gsub(g, n.sons[pragmasPos])
put(g, tkColon, ":")
gsub(g, n.sons[bodyPos])
of nkConstDef, nkIdentDefs: of nkConstDef, nkIdentDefs:
gcomma(g, n, 0, - 3) gcomma(g, n, 0, - 3)
var L = sonsLen(n) var L = sonsLen(n)
@ -960,7 +976,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkIfStmt: of nkIfStmt:
putWithSpace(g, tkIf, "if") putWithSpace(g, tkIf, "if")
gif(g, n) gif(g, n)
of nkWhenStmt, nkRecWhen: of nkWhen, nkRecWhen:
putWithSpace(g, tkWhen, "when") putWithSpace(g, tkWhen, "when")
gif(g, n) gif(g, n)
of nkWhileStmt: gwhile(g, n) of nkWhileStmt: gwhile(g, n)

View file

@ -21,7 +21,7 @@ proc semPass*(): TPass
type type
TExprFlag = enum TExprFlag = enum
efAllowType, efLValue, efWantIterator, efInTypeof efLValue, efWantIterator, efInTypeof
TExprFlags = set[TExprFlag] TExprFlags = set[TExprFlag]
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode

View file

@ -10,7 +10,16 @@
# this module does the semantic checking for expressions # this module does the semantic checking for expressions
# included from sem.nim # included from sem.nim
proc semExprOrTypedesc(c: PContext, n: PNode): PNode proc restoreOldStyleType(n: PNode) =
# XXX: semExprWithType used to return the same type
# for nodes such as (100) or (int).
# This is inappropriate. The type of the first expression
# should be "int", while the type of the second one should
# be typedesc(int).
#
# This is strictly for backward compatibility until
# the transition to types as first-class values is complete.
n.typ = n.typ.skipTypes({tyTypeDesc})
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
markUsed(n, s) markUsed(n, s)
@ -108,10 +117,9 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
if s.ast == nil: InternalError(n.info, "no default for") if s.ast == nil: InternalError(n.info, "no default for")
result = semExpr(c, s.ast) result = semExpr(c, s.ast)
of skType: of skType:
if efAllowType notin flags:
GlobalError(n.info, errATypeHasNoValue)
markUsed(n, s) markUsed(n, s)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
result.typ = makeTypeDesc(c, s.typ)
else: else:
markUsed(n, s) markUsed(n, s)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
@ -206,7 +214,8 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
if sonsLen(n) != 2: if sonsLen(n) != 2:
GlobalError(n.info, errXExpectsTypeOrValue, opToStr[m]) GlobalError(n.info, errXExpectsTypeOrValue, opToStr[m])
else: else:
n.sons[1] = semExprWithType(c, n.sons[1], {efAllowType}) n.sons[1] = semExprWithType(c, n.sons[1])
restoreOldStyleType(n.sons[1])
var typ = skipTypes(n.sons[1].typ, abstractVarRange) var typ = skipTypes(n.sons[1].typ, abstractVarRange)
case typ.Kind case typ.Kind
of tySequence, tyString, tyOpenArray: of tySequence, tyString, tyOpenArray:
@ -219,15 +228,21 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
result = n result = n
proc semSizeof(c: PContext, n: PNode): PNode = proc semSizeof(c: PContext, n: PNode): PNode =
if sonsLen(n) != 2: GlobalError(n.info, errXExpectsTypeOrValue, "sizeof") if sonsLen(n) != 2:
else: n.sons[1] = semExprWithType(c, n.sons[1], {efAllowType}) GlobalError(n.info, errXExpectsTypeOrValue, "sizeof")
else:
n.sons[1] = semExprWithType(c, n.sons[1])
restoreOldStyleType(n.sons[1])
n.typ = getSysType(tyInt) n.typ = getSysType(tyInt)
result = n result = n
proc semOf(c: PContext, n: PNode): PNode = proc semOf(c: PContext, n: PNode): PNode =
if sonsLen(n) == 3: if sonsLen(n) == 3:
n.sons[1] = semExprWithType(c, n.sons[1], {efAllowType}) n.sons[1] = semExprWithType(c, n.sons[1])
n.sons[2] = semExprWithType(c, n.sons[2], {efAllowType}) n.sons[2] = semExprWithType(c, n.sons[2])
restoreOldStyleType(n.sons[1])
restoreOldStyleType(n.sons[2])
var a = skipTypes(n.sons[1].typ, abstractPtrs) var a = skipTypes(n.sons[1].typ, abstractPtrs)
var b = skipTypes(n.sons[2].typ, abstractPtrs) var b = skipTypes(n.sons[2].typ, abstractPtrs)
if b.kind != tyObject or a.kind != tyObject: if b.kind != tyObject or a.kind != tyObject:
@ -251,31 +266,16 @@ proc semIs(c: PContext, n: PNode): PNode =
else: else:
GlobalError(n.info, errXExpectsTwoArguments, "is") GlobalError(n.info, errXExpectsTwoArguments, "is")
proc semExprOrTypedesc(c: PContext, n: PNode): PNode =
# XXX: Currently, semExprWithType will return the same type
# for nodes such as (100) or (int).
# This is inappropriate. The type of the first expression
# should be "int", while the type of the second one should
# be typeDesc(int).
# Ideally, this should be fixed in semExpr, but right now
# there are probably users that depend on the present behavior.
# XXX: Investigate current uses of efAllowType and fix them to
# work with tyTypeDesc.
result = semExprWithType(c, n, {efAllowType})
if result.kind == nkSym and result.sym.kind == skType and
result.typ.kind != tyTypeDesc:
result.typ = makeTypeDesc(c, result.typ)
proc semOpAux(c: PContext, n: PNode) = proc semOpAux(c: PContext, n: PNode) =
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2: if a.kind == nkExprEqExpr and sonsLen(a) == 2:
var info = a.sons[0].info var info = a.sons[0].info
a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info) a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
a.sons[1] = semExprOrTypedesc(c, a.sons[1]) a.sons[1] = semExprWithType(c, a.sons[1])
a.typ = a.sons[1].typ a.typ = a.sons[1].typ
else: else:
n.sons[i] = semExprOrTypedesc(c, a) n.sons[i] = semExprWithType(c, a)
proc overloadedCallOpr(c: PContext, n: PNode): PNode = proc overloadedCallOpr(c: PContext, n: PNode): PNode =
# quick check if there is *any* () operator overloaded: # quick check if there is *any* () operator overloaded:
@ -409,8 +409,10 @@ proc isAssignable(c: PContext, n: PNode): TAssignableResult =
of nkSym: of nkSym:
# don't list 'skLet' here: # don't list 'skLet' here:
if n.sym.kind in {skVar, skResult, skTemp}: if n.sym.kind in {skVar, skResult, skTemp}:
if c.p.owner.id == n.sym.owner.id: result = arLocalLValue if c.p.owner.id == n.sym.owner.id and sfGlobal notin n.sym.flags:
else: result = arLValue result = arLocalLValue
else:
result = arLValue
of nkDotExpr: of nkDotExpr:
if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}: if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}:
result = arLValue result = arLValue
@ -752,13 +754,15 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
return semSym(c, n, s, flags) return semSym(c, n, s, flags)
checkSonsLen(n, 2) checkSonsLen(n, 2)
n.sons[0] = semExprWithType(c, n.sons[0], {efAllowType} + flags) n.sons[0] = semExprWithType(c, n.sons[0], flags)
restoreOldStyleType(n.sons[0])
var i = considerAcc(n.sons[1]) var i = considerAcc(n.sons[1])
var ty = n.sons[0].Typ var ty = n.sons[0].typ
var f: PSym = nil var f: PSym = nil
result = nil result = nil
if isTypeExpr(n.sons[0]): if isTypeExpr(n.sons[0]):
if ty.kind == tyEnum: case ty.kind
of tyEnum:
# look up if the identifier belongs to the enum: # look up if the identifier belongs to the enum:
while ty != nil: while ty != nil:
f = getSymFromList(ty.n, i) f = getSymFromList(ty.n, i)
@ -769,10 +773,22 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.info = n.info result.info = n.info
result.typ = ty result.typ = ty
markUsed(n, f) markUsed(n, f)
return return
elif efAllowType notin flags: of tyGenericInst:
GlobalError(n.sons[0].info, errATypeHasNoValue) assert ty.sons[0].kind == tyGenericBody
let tbody = ty.sons[0]
for s in countup(0, tbody.len-2):
let tParam = tbody.sons[s]
assert tParam.kind == tyGenericParam
if tParam.sym.name == i:
let foundTyp = makeTypeDesc(c, ty.sons[s + 1])
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info)
return return
else:
# echo "TYPE FIELD ACCESS"
# debug ty
return
# XXX: This is probably not relevant any more
# reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim": # reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
ty = n.sons[0].Typ ty = n.sons[0].Typ
@ -852,14 +868,14 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.add(x[0]) result.add(x[0])
return return
checkMinSonsLen(n, 2) checkMinSonsLen(n, 2)
n.sons[0] = semExprOrTypedesc(c, n.sons[0]) n.sons[0] = semExprWithType(c, n.sons[0])
var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef}) var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
case arr.kind case arr.kind
of tyArray, tyOpenArray, tyArrayConstr, tySequence, tyString, tyCString: of tyArray, tyOpenArray, tyArrayConstr, tySequence, tyString, tyCString:
checkSonsLen(n, 2) checkSonsLen(n, 2)
n.sons[0] = makeDeref(n.sons[0]) n.sons[0] = makeDeref(n.sons[0])
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
n.sons[i] = semExprWithType(c, n.sons[i], flags - {efAllowType}) n.sons[i] = semExprWithType(c, n.sons[i], flags)
var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(tyInt) var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(tyInt)
var arg = IndexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1]) var arg = IndexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1])
if arg != nil: if arg != nil:
@ -1280,9 +1296,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
nil nil
of nkNilLit: of nkNilLit:
result.typ = getSysType(tyNil) result.typ = getSysType(tyNil)
of nkType:
if not (efAllowType in flags): GlobalError(n.info, errATypeHasNoValue)
n.typ = semTypeNode(c, n, nil)
of nkIntLit: of nkIntLit:
if result.typ == nil: result.typ = getSysType(tyInt) if result.typ == nil: result.typ = getSysType(tyInt)
of nkInt8Lit: of nkInt8Lit:
@ -1312,11 +1325,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
Message(n.info, warnDeprecated, "bind") Message(n.info, warnDeprecated, "bind")
result = semExpr(c, n.sons[0], flags) result = semExpr(c, n.sons[0], flags)
of nkTypeOfExpr: of nkTypeOfExpr:
var typ = semTypeNode(c, n, nil) var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
if typ.sym == nil: typ = makeTypedesc(c, typ)
typ = copyType(typ, typ.owner, true) var sym = newSym(skType, getIdent"TypeOfExpr", typ.owner).linkTo(typ)
typ.linkTo(newSym(skType, getIdent"typedesc", typ.owner)) sym.flags.incl(sfAnon)
result = newSymNode(typ.sym, n.info) result = newSymNode(sym, n.info)
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
# check if it is an expression macro: # check if it is an expression macro:
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
@ -1354,6 +1367,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semIndirectOp(c, n, flags) result = semIndirectOp(c, n, flags)
of nkMacroStmt: of nkMacroStmt:
result = semMacroStmt(c, n) result = semMacroStmt(c, n)
of nkWhenExpr:
result = semWhen(c, n, false)
result = semExpr(c, result)
of nkBracketExpr: of nkBracketExpr:
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
var s = qualifiedLookup(c, n.sons[0], {checkUndeclared}) var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})

View file

@ -206,7 +206,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mNewString, mNewStringOfCap, of mNewString, mNewStringOfCap,
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, mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
mNLen..mNError, mEqRef: mNLen..mNError, mEqRef:
nil nil
of mRand: of mRand:

View file

@ -8,6 +8,7 @@
# #
# This include file implements the semantic checking for magics. # This include file implements the semantic checking for magics.
# included from sem.nim
proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
var r = isPartOf(n[1], n[2]) var r = isPartOf(n[1], n[2])
@ -43,11 +44,21 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
result.add(filename) result.add(filename)
result.add(line) result.add(line)
proc semTypeTraits(c: PContext, n: PNode): PNode =
checkMinSonsLen(n, 2)
internalAssert n.sons[1].kind == nkSym
if n.sons[1].sym.kind == skType:
result = evalTypeTrait(n, GetCurrOwner())
else:
# pass unmodified to evals
result = n
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 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 mAstToStr: of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
result.typ = getSysType(tyString) result.typ = getSysType(tyString)

View file

@ -25,13 +25,13 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i] var it = n.sons[i]
case it.kind case it.kind
of nkElifBranch: of nkElifBranch, nkElifExpr:
checkSonsLen(it, 2) checkSonsLen(it, 2)
var e = semAndEvalConstExpr(c, it.sons[0]) var e = semAndEvalConstExpr(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])
of nkElse: of nkElse, nkElseExpr:
checkSonsLen(it, 1) checkSonsLen(it, 1)
if result == nil: if result == nil:
setResult(it.sons[0]) setResult(it.sons[0])

View file

@ -181,7 +181,12 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
if result != nil: if result != nil:
markUsed(n, result) markUsed(n, result)
if result.kind == skParam and result.typ.kind == tyTypeDesc: if result.kind == skParam and result.typ.kind == tyTypeDesc:
return result.typ.sons[0].sym # This is a typedesc param. is it already bound?
# it's not bound when it's also used as return type for example
if result.typ.sonsLen > 0:
return result.typ.sons[0].sym
else:
return result.typ.sym
if result.kind != skType: GlobalError(n.info, errTypeExpected) if result.kind != skType: GlobalError(n.info, errTypeExpected)
if result.typ.kind != tyGenericParam: if result.typ.kind != tyGenericParam:
# XXX get rid of this hack! # XXX get rid of this hack!
@ -583,8 +588,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
break addImplicitGeneric break addImplicitGeneric
var s = newSym(skType, paramTypId, getCurrOwner()) var s = newSym(skType, paramTypId, getCurrOwner())
s.typ = typeClass s.flags.incl(sfAnon)
s.typ.sym = s s.linkTo(typeClass)
s.position = genericParams.len s.position = genericParams.len
genericParams.addSon(newSymNode(s)) genericParams.addSon(newSymNode(s))
endingType = typeClass endingType = typeClass

View file

@ -372,6 +372,13 @@ proc rangeToStr(n: PNode): string =
assert(n.kind == nkRange) assert(n.kind == nkRange)
result = ValueToString(n.sons[0]) & ".." & ValueToString(n.sons[1]) result = ValueToString(n.sons[0]) & ".." & ValueToString(n.sons[1])
proc constraintsToStr(t: PType): string =
let sep = if tfAny in t.flags: " or " else: " and "
result = ""
for i in countup(0, t.sons.len - 1):
if i > 0: result.add(sep)
result.add(t.sons[i].typeToString)
proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string = proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
const const
typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty", typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
@ -387,7 +394,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
var t = typ var t = typ
result = "" result = ""
if t == nil: return if t == nil: return
if prefer == preferName and t.sym != nil: if prefer == preferName and t.sym != nil and sfAnon notin t.sym.flags:
return t.sym.Name.s return t.sym.Name.s
case t.Kind case t.Kind
of tyGenericBody, tyGenericInst, tyGenericInvokation: of tyGenericBody, tyGenericInst, tyGenericInvokation:
@ -396,6 +403,14 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
if i > 1: add(result, ", ") if i > 1: add(result, ", ")
add(result, typeToString(t.sons[i])) add(result, typeToString(t.sons[i]))
add(result, ']') add(result, ']')
of tyTypeDesc:
if t.sons.len == 0: result = "typedesc"
else: result = "typedesc{" & constraintsToStr(t) & "}"
of tyTypeClass:
result = constraintsToStr(t)
of tyExpr:
if t.sons.len == 0: result = "expr"
else: result = "expr{" & constraintsToStr(t) & "}"
of tyArray: of tyArray:
if t.sons[0].kind == tyRange: if t.sons[0].kind == tyRange:
result = "array[" & rangeToStr(t.sons[0].n) & ", " & result = "array[" & rangeToStr(t.sons[0].n) & ", " &

View file

@ -58,7 +58,7 @@ type
wWatchPoint, wSubsChar, wWatchPoint, wSubsChar,
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wAcyclic, wShallow, wUnroll, wLinearScanEnd,
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame, wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame,
wImplicitStatic wImplicitStatic, wGlobal
TSpecialWords* = set[TSpecialWord] TSpecialWords* = set[TSpecialWord]
@ -107,7 +107,7 @@ const
"watchpoint", "watchpoint",
"subschar", "acyclic", "shallow", "unroll", "linearscanend", "subschar", "acyclic", "shallow", "unroll", "linearscanend",
"write", "putenv", "prependenv", "appendenv", "threadvar", "emit", "write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
"nostackframe", "implicitstatic"] "nostackframe", "implicitstatic", "global"]
proc findStr*(a: openarray[string], s: string): int = proc findStr*(a: openarray[string], s: string): int =
for i in countup(low(a), high(a)): for i in countup(low(a), high(a)):

View file

@ -3267,7 +3267,7 @@ but are used to override the settings temporarily. Example:
{.pop.} # restore old settings {.pop.} # restore old settings
Register pragma register pragma
--------------- ---------------
The `register`:idx: pragma is for variables only. It declares the variable as The `register`:idx: pragma is for variables only. It declares the variable as
``register``, giving the compiler a hint that the variable should be placed ``register``, giving the compiler a hint that the variable should be placed
@ -3277,6 +3277,22 @@ though and for good reasons: Often they do a better job without it anyway.
In highly specific cases (a dispatch loop of an bytecode interpreter for In highly specific cases (a dispatch loop of an bytecode interpreter for
example) it may provide benefits, though. example) it may provide benefits, though.
global pragma
---------------
The `global`:idx pragma can be applied to a variable within a proc to instruct
the compiler to store it in a global location and initialize it once at program
startup.
.. code-block:: nimrod
proc isHexNumber(s: string): bool =
var pattern {.global.} = re"[0-9a-fA-F]+"
result = s.match(pattern)
When used within a generic proc, a separate unique global variable will be
created for each instantiation of the proc. The order of initialization of
the created global variables within a module is not defined, but all of them
will be initialized after any top-level variables in their originating module
and before any variable in a module that imports it.
DeadCodeElim pragma DeadCodeElim pragma
------------------- -------------------

15
lib/pure/typetraits.nim Normal file
View file

@ -0,0 +1,15 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Nimrod Contributors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module defines compile-time reflection procs for
## working with types
proc name*(t: typedesc): string {.magic: "TypeTrait".}
## Returns the name of the given type

View file

@ -1,7 +1,7 @@
discard """ discard """
file: "ttypenoval.nim" file: "ttypenoval.nim"
line: 38 line: 38
errormsg: "a type has no value" errormsg: "type mismatch: got (typedesc{int}) but expected 'int'"
""" """
# A min-heap. # A min-heap.

View file

@ -1,5 +1,4 @@
discard """ discard """
disabled: true
output: '''derived class output: '''derived class
base class base class
''' '''

View file

@ -1,5 +1,4 @@
discard """ discard """
disabled: true
output: '''derived class 2 output: '''derived class 2
base class base class
''' '''

15
tests/run/globalaux.nim Normal file
View file

@ -0,0 +1,15 @@
type
TObj*[T] = object
val*: T
var
totalGlobals* = 0
proc makeObj[T](x: T): TObj[T] =
totalGlobals += 1
result.val = x
proc globalInstance*[T]: var TObj[T] =
var g {.global.} = when T is int: makeObj(10) else: makeObj("hello")
result = g

4
tests/run/globalaux2.nim Normal file
View file

@ -0,0 +1,4 @@
import globalaux
echo "in globalaux2: ", globalInstance[int]().val

14
tests/run/tenumitems.nim Normal file
View file

@ -0,0 +1,14 @@
discard """
output: "A\nB\nC"
"""
type TAlphabet = enum
A, B, C
iterator items(E: typedesc): E =
for v in low(E)..high(E):
yield v
for c in TAlphabet:
echo($c)

16
tests/run/tglobal.nim Normal file
View file

@ -0,0 +1,16 @@
discard """
file: "toop1.nim"
output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second"
"""
import globalaux, globalaux2
echo "total globals: ", totalGlobals
globalInstance[int]().val = 100
echo "int value: ", globalInstance[int]().val
globalInstance[string]().val = "first"
globalInstance[string]().val = "second"
echo "string value: ", globalInstance[string]().val

24
tests/run/ttypetraits.nim Normal file
View file

@ -0,0 +1,24 @@
discard """
msg: "int\nstring\nTBar[int]"
output: "int\nstring\nTBar[int]"
"""
import typetraits
proc foo(x) =
static:
var t = type(x)
echo t.name
echo x.type.name
type
TBar[U] = object
x: U
var bar: TBar[int]
foo 10
foo "test"
foo bar

View file

@ -22,7 +22,8 @@ proc delNimCache() =
except EOS: except EOS:
echo "[Warning] could not delete: ", dir echo "[Warning] could not delete: ", dir
proc plusCache(options: string): string = return options & " --symbolFiles:on" proc plusCache(options: string): string = return options &
" --symbolFiles:on --nimcache:./nimcache"
proc runRodFiles(r: var TResults, options: string) = proc runRodFiles(r: var TResults, options: string) =
template test(filename: expr): stmt = template test(filename: expr): stmt =

View file

@ -3,9 +3,30 @@
# result = "#! /bin/sh\n# Generated from niminst\n" & # result = "#! /bin/sh\n# Generated from niminst\n" &
# "# Template is in tools/buildsh.tmpl\n" & # "# Template is in tools/buildsh.tmpl\n" &
# "# To regenerate run ``niminst csource`` or ``koch csource``\n" # "# To regenerate run ``niminst csource`` or ``koch csource``\n"
while :
do
case "$1" in
--extraBuildArgs)
extraBuildArgs=" $2"
shift 2
;;
--) # End of all options
shift
break;
;;
-*)
echo "Error: Unknown option: $1" >&2
exit 1
;;
*) # No more options
break
;;
esac
done
CC="gcc" CC="gcc"
LINKER="gcc" LINKER="gcc"
COMP_FLAGS="?{c.ccompiler.flags}" COMP_FLAGS="?{c.ccompiler.flags}$extraBuildArgs"
LINK_FLAGS="?{c.linker.flags}" LINK_FLAGS="?{c.linker.flags}"
# add(result, "# platform detection\n") # add(result, "# platform detection\n")
ucpu=`uname -m` ucpu=`uname -m`

View file

@ -71,6 +71,9 @@ Language Additions
- Added explicit ``static`` sections for enforced compile time evaluation. - Added explicit ``static`` sections for enforced compile time evaluation.
- Added an alternative notation for lambdas with ``do``. - Added an alternative notation for lambdas with ``do``.
- ``addr`` is now treated like a prefix operator syntactically. - ``addr`` is now treated like a prefix operator syntactically.
- Added ``global`` pragma that can be used to introduce new global variables
from within procs.
- when expressions are now allowed just like if expressions
2012-02-09 Version 0.8.14 released 2012-02-09 Version 0.8.14 released