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

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

View File

@@ -143,7 +143,7 @@ type
nkPragma, # a pragma statement
nkPragmaBlock, # a pragma with a block
nkIfStmt, # an if statement
nkWhenStmt, # a when statement
nkWhenStmt, # a when expression or statement
nkForStmt, # a for statement
nkWhileStmt, # a while statement
nkCaseStmt, # a case statement
@@ -243,8 +243,18 @@ const
sfFakeConst* = sfDeadCodeElim # const cannot be put into a data section
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
sfNoInit* = sfMainModule # don't generate code to init the variable
sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded
# 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
TTypeKind* = enum # order is important!
@@ -353,7 +363,8 @@ const
type
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,
mParseExprToAst, mParseStmtToAst, mExpandToAst,
mUnaryLt, mSucc,

View File

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

View File

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

View File

@@ -93,6 +93,10 @@ type
headerFiles*: TLinkedList # needed headers to include
typeInfoMarker*: TIntSet # needed for generating type information
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
dataCache*: TNodeTable
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 =
var s = n.sym
case s.kind
of skProc, skConverter, skMacro:
of skProc, skConverter, skMacro, skType:
result = n
#result = s.getBody
of skVar, skLet, skForVar, skTemp, skResult:
@@ -891,7 +891,24 @@ proc evalTemplate*(n: PNode, sym: PSym): PNode =
result = evalTemplateAux(sym.getBody, args, sym)
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 =
var
n = original.copyTree
@@ -941,6 +958,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mParseExprToAst: result = evalParseExpr(c, n)
of mParseStmtToAst: result = evalParseStmt(c, n)
of mExpandToAst: result = evalExpandToAst(c, n)
of mTypeTrait: result = evalTypeTrait(n, c.module)
of mNLen:
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return

View File

@@ -72,7 +72,7 @@ type
errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
errXNotAllowedHere, errInvalidControlFlowX, errATypeHasNoValue,
errXNotAllowedHere, errInvalidControlFlowX,
errXisNoType, errCircumNeedsPointer, errInvalidExpression,
errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,
errNamedExprNotAllowed, errXExpectsOneTypeParam,
@@ -275,7 +275,6 @@ const
errInvalidPragmaX: "invalid pragma: $1",
errXNotAllowedHere: "$1 not allowed here",
errInvalidControlFlowX: "invalid control flow: $1",
errATypeHasNoValue: "a type has no value",
errXisNoType: "invalid type: \'$1\'",
errCircumNeedsPointer: "'[]' needs a pointer or reference type",
errInvalidExpression: "invalid expression",
@@ -667,3 +666,6 @@ template AssertNotNil*(e: expr): expr =
if(e == nil): InternalError($InstantiationInfo())
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
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)
eat(p, endTok)
proc newDotExpr(p: var TParser, a: PNode): PNode =
proc dotExpr(p: var TParser, a: PNode): PNode =
getTok(p)
optInd(p, a)
result = newNodeI(nkDotExpr, a.info)
addSon(result, a)
addSon(result, parseSymbol(p))
case p.tok.tokType
of tkType:
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 =
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) =
getTok(p)
@@ -477,7 +487,7 @@ proc primary(p: var TParser): PNode =
exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result)
parseDoBlocks(p, result)
of tkDot:
result = newDotExpr(p, result)
result = dotExpr(p, result)
result = parseGStrLit(p, result)
of tkBracketLe:
result = indexExprList(p, result, nkBracketExpr, tkBracketRi)
@@ -506,8 +516,8 @@ proc lowestExprAux(p: var TParser, limit: int): PNode =
proc lowestExpr(p: var TParser): PNode =
result = lowestExprAux(p, -1)
proc parseIfExpr(p: var TParser): PNode =
result = newNodeP(nkIfExpr, p)
proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
result = newNodeP(kind, p)
while true:
getTok(p) # skip `if`, `elif`
var branch = newNodeP(nkElifExpr, p)
@@ -707,7 +717,8 @@ proc parseExpr(p: var TParser): PNode =
of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr)
of tkTuple: result = parseTuple(p)
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)
proc parseTypeDesc(p: var TParser): PNode =
@@ -718,7 +729,7 @@ proc isExprStart(p: TParser): bool =
case p.tok.tokType
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind,
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
tkTuple, tkType:
tkTuple, tkType, tkWhen:
result = true
else: result = false

View File

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

View File

@@ -349,7 +349,8 @@ proc lsub(n: PNode): int =
of nkBind: result = lsons(n) + len("bind_")
of nkBindStmt: result = lcomma(n) + len("bind_")
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:
result = lcomma(n, 0, - 3)
var L = sonsLen(n)
@@ -677,7 +678,17 @@ proc gident(g: var TSrcGen, n: PNode) =
t = tkOpr
put(g, t, s)
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) =
if isNil(n): return
var
@@ -804,14 +815,19 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gsub(g, n.sons[0])
of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref:
gsub(g, n.sons[0])
of nkLambda, nkDo: # XXX: nkDo is rendered as regular lambda
assert(n.sons[genericParamsPos].kind == nkEmpty)
putWithSpace(g, tkLambda, "lambda")
of nkLambda:
putWithSpace(g, tkLambda, "proc")
gsub(g, n.sons[paramsPos])
gsub(g, n.sons[pragmasPos])
put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=")
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:
gcomma(g, n, 0, - 3)
var L = sonsLen(n)
@@ -960,7 +976,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkIfStmt:
putWithSpace(g, tkIf, "if")
gif(g, n)
of nkWhenStmt, nkRecWhen:
of nkWhen, nkRecWhen:
putWithSpace(g, tkWhen, "when")
gif(g, n)
of nkWhileStmt: gwhile(g, n)

View File

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

View File

@@ -10,7 +10,16 @@
# this module does the semantic checking for expressions
# 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 =
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")
result = semExpr(c, s.ast)
of skType:
if efAllowType notin flags:
GlobalError(n.info, errATypeHasNoValue)
markUsed(n, s)
result = newSymNode(s, n.info)
result.typ = makeTypeDesc(c, s.typ)
else:
markUsed(n, s)
result = newSymNode(s, n.info)
@@ -206,7 +214,8 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
if sonsLen(n) != 2:
GlobalError(n.info, errXExpectsTypeOrValue, opToStr[m])
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)
case typ.Kind
of tySequence, tyString, tyOpenArray:
@@ -219,15 +228,21 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
result = n
proc semSizeof(c: PContext, n: PNode): PNode =
if sonsLen(n) != 2: GlobalError(n.info, errXExpectsTypeOrValue, "sizeof")
else: n.sons[1] = semExprWithType(c, n.sons[1], {efAllowType})
if sonsLen(n) != 2:
GlobalError(n.info, errXExpectsTypeOrValue, "sizeof")
else:
n.sons[1] = semExprWithType(c, n.sons[1])
restoreOldStyleType(n.sons[1])
n.typ = getSysType(tyInt)
result = n
proc semOf(c: PContext, n: PNode): PNode =
if sonsLen(n) == 3:
n.sons[1] = semExprWithType(c, n.sons[1], {efAllowType})
n.sons[2] = semExprWithType(c, n.sons[2], {efAllowType})
n.sons[1] = semExprWithType(c, n.sons[1])
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 b = skipTypes(n.sons[2].typ, abstractPtrs)
if b.kind != tyObject or a.kind != tyObject:
@@ -251,31 +266,16 @@ proc semIs(c: PContext, n: PNode): PNode =
else:
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) =
for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
var info = 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
else:
n.sons[i] = semExprOrTypedesc(c, a)
n.sons[i] = semExprWithType(c, a)
proc overloadedCallOpr(c: PContext, n: PNode): PNode =
# quick check if there is *any* () operator overloaded:
@@ -409,8 +409,10 @@ proc isAssignable(c: PContext, n: PNode): TAssignableResult =
of nkSym:
# don't list 'skLet' here:
if n.sym.kind in {skVar, skResult, skTemp}:
if c.p.owner.id == n.sym.owner.id: result = arLocalLValue
else: result = arLValue
if c.p.owner.id == n.sym.owner.id and sfGlobal notin n.sym.flags:
result = arLocalLValue
else:
result = arLValue
of nkDotExpr:
if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}:
result = arLValue
@@ -752,13 +754,15 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
return semSym(c, n, s, flags)
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 ty = n.sons[0].Typ
var ty = n.sons[0].typ
var f: PSym = nil
result = nil
if isTypeExpr(n.sons[0]):
if ty.kind == tyEnum:
case ty.kind
of tyEnum:
# look up if the identifier belongs to the enum:
while ty != nil:
f = getSymFromList(ty.n, i)
@@ -769,10 +773,22 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.info = n.info
result.typ = ty
markUsed(n, f)
return
elif efAllowType notin flags:
GlobalError(n.sons[0].info, errATypeHasNoValue)
return
of tyGenericInst:
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
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":
ty = n.sons[0].Typ
@@ -852,14 +868,14 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.add(x[0])
return
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})
case arr.kind
of tyArray, tyOpenArray, tyArrayConstr, tySequence, tyString, tyCString:
checkSonsLen(n, 2)
n.sons[0] = makeDeref(n.sons[0])
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 arg = IndexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1])
if arg != nil:
@@ -1280,9 +1296,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
nil
of nkNilLit:
result.typ = getSysType(tyNil)
of nkType:
if not (efAllowType in flags): GlobalError(n.info, errATypeHasNoValue)
n.typ = semTypeNode(c, n, nil)
of nkIntLit:
if result.typ == nil: result.typ = getSysType(tyInt)
of nkInt8Lit:
@@ -1312,11 +1325,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
Message(n.info, warnDeprecated, "bind")
result = semExpr(c, n.sons[0], flags)
of nkTypeOfExpr:
var typ = semTypeNode(c, n, nil)
if typ.sym == nil:
typ = copyType(typ, typ.owner, true)
typ.linkTo(newSym(skType, getIdent"typedesc", typ.owner))
result = newSymNode(typ.sym, n.info)
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
typ = makeTypedesc(c, typ)
var sym = newSym(skType, getIdent"TypeOfExpr", typ.owner).linkTo(typ)
sym.flags.incl(sfAnon)
result = newSymNode(sym, n.info)
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
# check if it is an expression macro:
checkMinSonsLen(n, 1)
@@ -1354,6 +1367,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semIndirectOp(c, n, flags)
of nkMacroStmt:
result = semMacroStmt(c, n)
of nkWhenExpr:
result = semWhen(c, n, false)
result = semExpr(c, result)
of nkBracketExpr:
checkMinSonsLen(n, 1)
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,
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
mParseExprToAst, mParseStmtToAst, mExpandToAst,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
mNLen..mNError, mEqRef:
nil
of mRand:

View File

@@ -8,6 +8,7 @@
#
# This include file implements the semantic checking for magics.
# included from sem.nim
proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
var r = isPartOf(n[1], n[2])
@@ -43,11 +44,21 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
result.add(filename)
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,
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:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
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):
var it = n.sons[i]
case it.kind
of nkElifBranch:
of nkElifBranch, nkElifExpr:
checkSonsLen(it, 2)
var e = semAndEvalConstExpr(c, it.sons[0])
if e.kind != nkIntLit: InternalError(n.info, "semWhen")
if e.intVal != 0 and result == nil:
setResult(it.sons[1])
of nkElse:
of nkElse, nkElseExpr:
checkSonsLen(it, 1)
if result == nil:
setResult(it.sons[0])

View File

@@ -181,7 +181,12 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
if result != nil:
markUsed(n, result)
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.typ.kind != tyGenericParam:
# XXX get rid of this hack!
@@ -583,8 +588,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
break addImplicitGeneric
var s = newSym(skType, paramTypId, getCurrOwner())
s.typ = typeClass
s.typ.sym = s
s.flags.incl(sfAnon)
s.linkTo(typeClass)
s.position = genericParams.len
genericParams.addSon(newSymNode(s))
endingType = typeClass

View File

@@ -372,6 +372,13 @@ proc rangeToStr(n: PNode): string =
assert(n.kind == nkRange)
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 =
const
typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
@@ -387,7 +394,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
var t = typ
result = ""
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
case t.Kind
of tyGenericBody, tyGenericInst, tyGenericInvokation:
@@ -396,6 +403,14 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
if i > 1: add(result, ", ")
add(result, typeToString(t.sons[i]))
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:
if t.sons[0].kind == tyRange:
result = "array[" & rangeToStr(t.sons[0].n) & ", " &

View File

@@ -58,7 +58,7 @@ type
wWatchPoint, wSubsChar,
wAcyclic, wShallow, wUnroll, wLinearScanEnd,
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame,
wImplicitStatic
wImplicitStatic, wGlobal
TSpecialWords* = set[TSpecialWord]
@@ -107,7 +107,7 @@ const
"watchpoint",
"subschar", "acyclic", "shallow", "unroll", "linearscanend",
"write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
"nostackframe", "implicitstatic"]
"nostackframe", "implicitstatic", "global"]
proc findStr*(a: openarray[string], s: string): int =
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
Register pragma
register pragma
---------------
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
@@ -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
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
-------------------

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 """
file: "ttypenoval.nim"
line: 38
errormsg: "a type has no value"
errormsg: "type mismatch: got (typedesc{int}) but expected 'int'"
"""
# A min-heap.

View File

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

View File

@@ -1,5 +1,4 @@
discard """
disabled: true
output: '''derived class 2
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:
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) =
template test(filename: expr): stmt =

View File

@@ -3,9 +3,30 @@
# result = "#! /bin/sh\n# Generated from niminst\n" &
# "# Template is in tools/buildsh.tmpl\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"
LINKER="gcc"
COMP_FLAGS="?{c.ccompiler.flags}"
COMP_FLAGS="?{c.ccompiler.flags}$extraBuildArgs"
LINK_FLAGS="?{c.linker.flags}"
# add(result, "# platform detection\n")
ucpu=`uname -m`

View File

@@ -71,6 +71,9 @@ Language Additions
- Added explicit ``static`` sections for enforced compile time evaluation.
- Added an alternative notation for lambdas with ``do``.
- ``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