Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
c2b8669e04
25 changed files with 827 additions and 497 deletions
|
|
@ -350,6 +350,8 @@ type
|
||||||
# pass of semProcTypeNode performed after instantiation.
|
# pass of semProcTypeNode performed after instantiation.
|
||||||
# this won't be needed if we don't perform this redundant
|
# this won't be needed if we don't perform this redundant
|
||||||
# second pass (stay tuned).
|
# second pass (stay tuned).
|
||||||
|
tfRetType # marks return types in proc (used to detect type classes
|
||||||
|
# used as return types for return type inference)
|
||||||
tfAll, # type class requires all constraints to be met (default)
|
tfAll, # type class requires all constraints to be met (default)
|
||||||
tfAny, # type class requires any constraint to be met
|
tfAny, # type class requires any constraint to be met
|
||||||
tfCapturesEnv, # whether proc really captures some environment
|
tfCapturesEnv, # whether proc really captures some environment
|
||||||
|
|
@ -779,6 +781,11 @@ proc add*(father, son: PNode) =
|
||||||
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
||||||
result = n.sons[i]
|
result = n.sons[i]
|
||||||
|
|
||||||
|
# son access operators with support for negative indices
|
||||||
|
template `{}`*(n: PNode, i: int): expr = n[i -| n]
|
||||||
|
template `{}=`*(n: PNode, i: int, s: PNode): stmt =
|
||||||
|
n.sons[i -| n] = s
|
||||||
|
|
||||||
var emptyNode* = newNode(nkEmpty)
|
var emptyNode* = newNode(nkEmpty)
|
||||||
# There is a single empty node that is shared! Do not overwrite it!
|
# There is a single empty node that is shared! Do not overwrite it!
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ type
|
||||||
callsite: PNode # for 'callsite' magic
|
callsite: PNode # for 'callsite' magic
|
||||||
mode*: TEvalMode
|
mode*: TEvalMode
|
||||||
globals*: TIdNodeTable # state of global vars
|
globals*: TIdNodeTable # state of global vars
|
||||||
|
getType*: proc(n: PNode): PNode
|
||||||
|
|
||||||
PEvalContext* = ref TEvalContext
|
PEvalContext* = ref TEvalContext
|
||||||
|
|
||||||
|
|
@ -521,7 +522,7 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||||
else: result = nil
|
else: result = nil
|
||||||
if result == nil or {sfImportc, sfForward} * s.flags != {}:
|
if result == nil or {sfImportc, sfForward} * s.flags != {}:
|
||||||
result = raiseCannotEval(c, n.info)
|
result = raiseCannotEval(c, n.info)
|
||||||
|
|
||||||
proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode =
|
proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode =
|
||||||
result = evalAux(c, n.sons[1], {efLValue})
|
result = evalAux(c, n.sons[1], {efLValue})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
|
|
@ -875,6 +876,27 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode =
|
||||||
else:
|
else:
|
||||||
internalAssert false
|
internalAssert false
|
||||||
|
|
||||||
|
proc evalIsOp*(n: PNode): PNode =
|
||||||
|
InternalAssert n.sonsLen == 3 and
|
||||||
|
n[1].kind == nkSym and n[1].sym.kind == skType and
|
||||||
|
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
||||||
|
|
||||||
|
let t1 = n[1].sym.typ
|
||||||
|
|
||||||
|
if n[2].kind in {nkStrLit..nkTripleStrLit}:
|
||||||
|
case n[2].strVal.normalize
|
||||||
|
of "closure":
|
||||||
|
let t = skipTypes(t1, abstractRange)
|
||||||
|
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||||
|
t.callConv == ccClosure))
|
||||||
|
else:
|
||||||
|
let t2 = n[2].typ
|
||||||
|
var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1)
|
||||||
|
else: sameType(t1, t2)
|
||||||
|
result = newIntNode(nkIntLit, ord(match))
|
||||||
|
|
||||||
|
result.typ = n.typ
|
||||||
|
|
||||||
proc expectString(n: PNode) =
|
proc expectString(n: PNode) =
|
||||||
if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
|
if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
|
||||||
GlobalError(n.info, errStringLiteralExpected)
|
GlobalError(n.info, errStringLiteralExpected)
|
||||||
|
|
@ -968,6 +990,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||||
of mTypeTrait:
|
of mTypeTrait:
|
||||||
n.sons[1] = evalAux(c, n.sons[1], {})
|
n.sons[1] = evalAux(c, n.sons[1], {})
|
||||||
result = evalTypeTrait(n, c.module)
|
result = evalTypeTrait(n, c.module)
|
||||||
|
of mIs:
|
||||||
|
n.sons[1] = evalAux(c, n.sons[1], {})
|
||||||
|
result = evalIsOp(n)
|
||||||
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
|
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
|
||||||
of mStaticExec:
|
of mStaticExec:
|
||||||
let cmd = evalAux(c, n.sons[1], {})
|
let cmd = evalAux(c, n.sons[1], {})
|
||||||
|
|
@ -1067,7 +1092,10 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||||
result = evalAux(c, n.sons[1], {})
|
result = evalAux(c, n.sons[1], {})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
if result.kind != nkIdent: stackTrace(c, n, errFieldXNotFound, "ident")
|
if result.kind != nkIdent: stackTrace(c, n, errFieldXNotFound, "ident")
|
||||||
of mNGetType: result = evalAux(c, n.sons[1], {})
|
of mNGetType:
|
||||||
|
var ast = evalAux(c, n.sons[1], {})
|
||||||
|
InternalAssert c.getType != nil
|
||||||
|
result = c.getType(ast)
|
||||||
of mNStrVal:
|
of mNStrVal:
|
||||||
result = evalAux(c, n.sons[1], {})
|
result = evalAux(c, n.sons[1], {})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
|
|
@ -1128,7 +1156,8 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||||
var a = result
|
var a = result
|
||||||
result = evalAux(c, n.sons[2], {efLValue})
|
result = evalAux(c, n.sons[2], {efLValue})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
a.typ = result.typ # XXX: exception handling?
|
InternalAssert result.kind == nkSym and result.sym.kind == skType
|
||||||
|
a.typ = result.sym.typ
|
||||||
result = emptyNode
|
result = emptyNode
|
||||||
of mNSetStrVal:
|
of mNSetStrVal:
|
||||||
result = evalAux(c, n.sons[1], {efLValue})
|
result = evalAux(c, n.sons[1], {efLValue})
|
||||||
|
|
|
||||||
|
|
@ -575,19 +575,22 @@ proc inCheckpoint*(current: TLineInfo): TCheckPointResult =
|
||||||
type
|
type
|
||||||
TErrorHandling = enum doNothing, doAbort, doRaise
|
TErrorHandling = enum doNothing, doAbort, doRaise
|
||||||
|
|
||||||
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
|
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
|
||||||
if msg == errInternal:
|
template maybeTrace =
|
||||||
assert(false) # we want a stack trace here
|
if defined(debug) or gVerbosity >= 3:
|
||||||
|
writeStackTrace()
|
||||||
|
|
||||||
|
if msg == errInternal:
|
||||||
|
writeStackTrace() # we always want a stack trace here
|
||||||
if msg >= fatalMin and msg <= fatalMax:
|
if msg >= fatalMin and msg <= fatalMax:
|
||||||
if gVerbosity >= 3: assert(false)
|
maybeTrace()
|
||||||
quit(1)
|
quit(1)
|
||||||
if msg >= errMin and msg <= errMax:
|
if msg >= errMin and msg <= errMax:
|
||||||
if gVerbosity >= 3: assert(false)
|
maybeTrace()
|
||||||
inc(gErrorCounter)
|
inc(gErrorCounter)
|
||||||
options.gExitcode = 1'i8
|
options.gExitcode = 1'i8
|
||||||
if gErrorCounter >= gErrorMax or eh == doAbort:
|
if gErrorCounter >= gErrorMax or eh == doAbort:
|
||||||
if gVerbosity >= 3: assert(false)
|
quit(1) # one error stops the compiler
|
||||||
quit(1) # one error stops the compiler
|
|
||||||
elif eh == doRaise:
|
elif eh == doRaise:
|
||||||
raiseRecoverableError(s)
|
raiseRecoverableError(s)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -743,7 +743,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, tkWhen:
|
tkTuple, tkType, tkWhen, tkCase:
|
||||||
result = true
|
result = true
|
||||||
else: result = false
|
else: result = false
|
||||||
|
|
||||||
|
|
@ -763,9 +763,9 @@ proc parseExpr(p: var TParser): PNode =
|
||||||
case p.tok.tokType:
|
case p.tok.tokType:
|
||||||
of tkIf: result = parseIfExpr(p, nkIfExpr)
|
of tkIf: result = parseIfExpr(p, nkIfExpr)
|
||||||
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
|
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
|
||||||
|
of tkCase: result = parseCase(p)
|
||||||
else: result = lowestExpr(p)
|
else: result = lowestExpr(p)
|
||||||
# XXX needs proper support:
|
# XXX needs proper support:
|
||||||
#of tkCase: result = parseCase(p)
|
|
||||||
#of tkTry: result = parseTry(p)
|
#of tkTry: result = parseTry(p)
|
||||||
|
|
||||||
proc primary(p: var TParser, skipSuffix = false): PNode =
|
proc primary(p: var TParser, skipSuffix = false): PNode =
|
||||||
|
|
@ -1044,9 +1044,9 @@ proc parseCase(p: var TParser): PNode =
|
||||||
if b.kind == nkElse: break
|
if b.kind == nkElse: break
|
||||||
|
|
||||||
if wasIndented:
|
if wasIndented:
|
||||||
eat(p, tkDed)
|
if p.tok.tokType != tkEof: eat(p, tkDed)
|
||||||
popInd(p.lex)
|
popInd(p.lex)
|
||||||
|
|
||||||
proc parseTry(p: var TParser): PNode =
|
proc parseTry(p: var TParser): PNode =
|
||||||
result = newNodeP(nkTryStmt, p)
|
result = newNodeP(nkTryStmt, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
||||||
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind)
|
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind)
|
||||||
proc addResultNode(c: PContext, n: PNode)
|
proc addResultNode(c: PContext, n: PNode)
|
||||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
||||||
|
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||||
|
|
||||||
proc typeMismatch(n: PNode, formal, actual: PType) =
|
proc typeMismatch(n: PNode, formal, actual: PType) =
|
||||||
if formal.kind != tyError and actual.kind != tyError:
|
if formal.kind != tyError and actual.kind != tyError:
|
||||||
|
|
@ -156,8 +157,18 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||||
markUsed(n, sym)
|
markUsed(n, sym)
|
||||||
if sym == c.p.owner:
|
if sym == c.p.owner:
|
||||||
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
|
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
|
||||||
|
|
||||||
if c.evalContext == nil:
|
if c.evalContext == nil:
|
||||||
c.evalContext = newEvalContext(c.module, "", emStatic)
|
c.evalContext = newEvalContext(c.module, "", emStatic)
|
||||||
|
c.evalContext.getType = proc (n: PNode): PNode =
|
||||||
|
var e = tryExpr(c, n)
|
||||||
|
if e == nil:
|
||||||
|
result = symNodeFromType(c, errorType(c), n.info)
|
||||||
|
elif e.typ == nil:
|
||||||
|
result = newSymNode(getSysSym"void")
|
||||||
|
else:
|
||||||
|
result = symNodeFromType(c, e.typ, n.info)
|
||||||
|
|
||||||
result = evalMacroCall(c.evalContext, n, nOrig, sym)
|
result = evalMacroCall(c.evalContext, n, nOrig, sym)
|
||||||
if semCheck: result = semAfterMacroCall(c, result, sym)
|
if semCheck: result = semAfterMacroCall(c, result, sym)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -281,18 +281,29 @@ proc semOf(c: PContext, n: PNode): PNode =
|
||||||
n.typ = getSysType(tyBool)
|
n.typ = getSysType(tyBool)
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
proc semIs(c: PContext, n: PNode): PNode =
|
proc semIs(c: PContext, n: PNode): PNode =
|
||||||
if sonsLen(n) == 3:
|
if sonsLen(n) != 3:
|
||||||
n.typ = getSysType(tyBool)
|
|
||||||
let a = semTypeNode(c, n[1], nil)
|
|
||||||
n.sons[1] = newNodeIT(nkType, n[1].info, a)
|
|
||||||
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
|
|
||||||
let b = semTypeNode(c, n[2], nil)
|
|
||||||
n.sons[2] = newNodeIT(nkType, n[2].info, b)
|
|
||||||
else:
|
|
||||||
LocalError(n.info, errXExpectsTwoArguments, "is")
|
LocalError(n.info, errXExpectsTwoArguments, "is")
|
||||||
result = n
|
|
||||||
|
|
||||||
|
result = n
|
||||||
|
n.typ = getSysType(tyBool)
|
||||||
|
|
||||||
|
n.sons[1] = semExprWithType(c, n[1])
|
||||||
|
if n[1].typ.kind != tyTypeDesc:
|
||||||
|
LocalError(n[0].info, errTypeExpected)
|
||||||
|
|
||||||
|
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
|
||||||
|
let t2 = semTypeNode(c, n[2], nil)
|
||||||
|
n.sons[2] = newNodeIT(nkType, n[2].info, t2)
|
||||||
|
|
||||||
|
if n[1].typ.sonsLen == 0:
|
||||||
|
# this is a typedesc variable, leave for evals
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
let t1 = n[1].typ.sons[0]
|
||||||
|
# BUGFIX: don't evaluate this too early: ``T is void``
|
||||||
|
if not containsGenericType(t1): result = evalIsOp(n)
|
||||||
|
|
||||||
proc semOpAux(c: PContext, n: PNode, tailToExclude = 1) =
|
proc semOpAux(c: PContext, n: PNode, tailToExclude = 1) =
|
||||||
for i in countup(1, sonsLen(n) - tailToExclude):
|
for i in countup(1, sonsLen(n) - tailToExclude):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
|
|
@ -1048,8 +1059,20 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
||||||
localError(a.info, errXCannotBeAssignedTo,
|
localError(a.info, errXCannotBeAssignedTo,
|
||||||
renderTree(a, {renderNoComments}))
|
renderTree(a, {renderNoComments}))
|
||||||
else:
|
else:
|
||||||
n.sons[1] = semExprWithType(c, n.sons[1])
|
var
|
||||||
n.sons[1] = fitNode(c, le, n.sons[1])
|
rhs = semExprWithType(c, n.sons[1])
|
||||||
|
lhs = n.sons[0]
|
||||||
|
if lhs.kind == nkSym and lhs.sym.kind == skResult and
|
||||||
|
lhs.sym.typ.kind == tyGenericParam:
|
||||||
|
if matchTypeClass(lhs.typ, rhs.typ):
|
||||||
|
InternalAssert c.p.resultSym != nil
|
||||||
|
lhs.typ = rhs.typ
|
||||||
|
c.p.resultSym.typ = rhs.typ
|
||||||
|
c.p.owner.typ.sons[0] = rhs.typ
|
||||||
|
else:
|
||||||
|
typeMismatch(n, lhs.typ, rhs.typ)
|
||||||
|
|
||||||
|
n.sons[1] = fitNode(c, le, rhs)
|
||||||
fixAbstractType(c, n)
|
fixAbstractType(c, n)
|
||||||
asgnToResultVar(c, n, n.sons[0], n.sons[1])
|
asgnToResultVar(c, n, n.sons[0], n.sons[1])
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -1214,12 +1237,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
|
||||||
else:
|
else:
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags)
|
||||||
|
|
||||||
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
# we replace this node by a 'true' or 'false' node:
|
|
||||||
if sonsLen(n) != 2: return semDirectOp(c, n, flags)
|
|
||||||
result = newIntNode(nkIntLit, 0)
|
|
||||||
result.info = n.info
|
|
||||||
result.typ = getSysType(tyBool)
|
|
||||||
# watch out, hacks ahead:
|
# watch out, hacks ahead:
|
||||||
let oldErrorCount = msgs.gErrorCounter
|
let oldErrorCount = msgs.gErrorCounter
|
||||||
let oldErrorMax = msgs.gErrorMax
|
let oldErrorMax = msgs.gErrorMax
|
||||||
|
|
@ -1241,8 +1259,8 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
let oldProcCon = c.p
|
let oldProcCon = c.p
|
||||||
c.generics = newGenericsCache()
|
c.generics = newGenericsCache()
|
||||||
try:
|
try:
|
||||||
discard semExpr(c, n.sons[1])
|
result = semExpr(c, n, flags)
|
||||||
result.intVal = ord(msgs.gErrorCounter == oldErrorCount)
|
if msgs.gErrorCounter != oldErrorCount: result = nil
|
||||||
except ERecoverableError:
|
except ERecoverableError:
|
||||||
nil
|
nil
|
||||||
# undo symbol table changes (as far as it's possible):
|
# undo symbol table changes (as far as it's possible):
|
||||||
|
|
@ -1259,6 +1277,14 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
msgs.gErrorCounter = oldErrorCount
|
msgs.gErrorCounter = oldErrorCount
|
||||||
msgs.gErrorMax = oldErrorMax
|
msgs.gErrorMax = oldErrorMax
|
||||||
|
|
||||||
|
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
# we replace this node by a 'true' or 'false' node:
|
||||||
|
if sonsLen(n) != 2: return semDirectOp(c, n, flags)
|
||||||
|
|
||||||
|
result = newIntNode(nkIntLit, ord(tryExpr(c, n, flags) != nil))
|
||||||
|
result.info = n.info
|
||||||
|
result.typ = getSysType(tyBool)
|
||||||
|
|
||||||
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
if sonsLen(n) == 3:
|
if sonsLen(n) == 3:
|
||||||
# XXX ugh this is really a hack: shallowCopy() can be overloaded only
|
# XXX ugh this is really a hack: shallowCopy() can be overloaded only
|
||||||
|
|
@ -1352,19 +1378,28 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
|
||||||
m = fitNode(c, typ, n.sons[i])
|
m = fitNode(c, typ, n.sons[i])
|
||||||
addSon(result, m)
|
addSon(result, m)
|
||||||
|
|
||||||
proc semTableConstr(c: PContext, n: PNode): PNode =
|
proc semTableConstr(c: PContext, n: PNode): PNode =
|
||||||
# we simply transform ``{key: value, key2: value}`` to
|
# we simply transform ``{key: value, key2, key3: value}`` to
|
||||||
# ``[(key, value), (key2, value2)]``
|
# ``[(key, value), (key2, value2), (key3, value2)]``
|
||||||
result = newNodeI(nkBracket, n.info)
|
result = newNodeI(nkBracket, n.info)
|
||||||
|
var lastKey = 0
|
||||||
for i in 0..n.len-1:
|
for i in 0..n.len-1:
|
||||||
var x = n.sons[i]
|
var x = n.sons[i]
|
||||||
if x.kind == nkExprColonExpr and sonsLen(x) == 2:
|
if x.kind == nkExprColonExpr and sonsLen(x) == 2:
|
||||||
|
for j in countup(lastKey, i-1):
|
||||||
|
var pair = newNodeI(nkPar, x.info)
|
||||||
|
pair.add(n.sons[j])
|
||||||
|
pair.add(x[1])
|
||||||
|
result.add(pair)
|
||||||
|
|
||||||
var pair = newNodeI(nkPar, x.info)
|
var pair = newNodeI(nkPar, x.info)
|
||||||
pair.add(x[0])
|
pair.add(x[0])
|
||||||
pair.add(x[1])
|
pair.add(x[1])
|
||||||
result.add(pair)
|
result.add(pair)
|
||||||
else:
|
|
||||||
illFormedAst(x)
|
lastKey = i+1
|
||||||
|
|
||||||
|
if lastKey != n.len: illFormedAst(n)
|
||||||
result = semExpr(c, result)
|
result = semExpr(c, result)
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -1507,6 +1542,57 @@ proc semMacroStmt(c: PContext, n: PNode, flags: TExprFlags,
|
||||||
renderTree(a, {renderNoComments}))
|
renderTree(a, {renderNoComments}))
|
||||||
result = errorNode(c, n)
|
result = errorNode(c, n)
|
||||||
|
|
||||||
|
proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
|
||||||
|
# The case expression is simply rewritten to a StmtListExpr:
|
||||||
|
# var res {.noInit, genSym.}: type(values)
|
||||||
|
#
|
||||||
|
# case E
|
||||||
|
# of X: res = value1
|
||||||
|
# of Y: res = value2
|
||||||
|
#
|
||||||
|
# res
|
||||||
|
var
|
||||||
|
info = caseStmt.info
|
||||||
|
resVar = newSym(skVar, getIdent":res", getCurrOwner(), info)
|
||||||
|
resNode = newSymNode(resVar, info)
|
||||||
|
resType: PType
|
||||||
|
|
||||||
|
resVar.flags = { sfGenSym, sfNoInit }
|
||||||
|
|
||||||
|
for i in countup(1, caseStmt.len - 1):
|
||||||
|
var cs = caseStmt[i]
|
||||||
|
case cs.kind
|
||||||
|
of nkOfBranch, nkElifBranch, nkElse:
|
||||||
|
# the value is always the last son regardless of the branch kind
|
||||||
|
cs.checkMinSonsLen 1
|
||||||
|
var value = cs{-1}
|
||||||
|
if value.kind == nkStmtList: value.kind = nkStmtListExpr
|
||||||
|
|
||||||
|
value = semExprWithType(c, value)
|
||||||
|
if resType == nil:
|
||||||
|
resType = value.typ
|
||||||
|
elif not sameType(resType, value.typ):
|
||||||
|
# XXX: semeType is a bit too harsh.
|
||||||
|
# work on finding a common base type.
|
||||||
|
# this will be useful for arrays/seq too:
|
||||||
|
# [ref DerivedA, ref DerivedB, ref Base]
|
||||||
|
typeMismatch(cs, resType, value.typ)
|
||||||
|
|
||||||
|
cs{-1} = newNode(nkAsgn, cs.info, @[resNode, value])
|
||||||
|
else:
|
||||||
|
IllFormedAst(caseStmt)
|
||||||
|
|
||||||
|
result = newNode(nkStmtListExpr, info, @[
|
||||||
|
newNode(nkVarSection, info, @[
|
||||||
|
newNode(nkIdentDefs, info, @[
|
||||||
|
resNode,
|
||||||
|
symNodeFromType(c, resType, info),
|
||||||
|
emptyNode])]),
|
||||||
|
caseStmt,
|
||||||
|
resNode])
|
||||||
|
|
||||||
|
result = semStmtListExpr(c, result)
|
||||||
|
|
||||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result = n
|
result = n
|
||||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||||
|
|
@ -1686,7 +1772,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkTryStmt: result = semTry(c, n)
|
of nkTryStmt: result = semTry(c, n)
|
||||||
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
|
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
|
||||||
of nkForStmt, nkParForStmt: result = semFor(c, n)
|
of nkForStmt, nkParForStmt: result = semFor(c, n)
|
||||||
of nkCaseStmt: result = semCase(c, n)
|
of nkCaseStmt:
|
||||||
|
if efWantStmt in flags: result = semCase(c, n)
|
||||||
|
else: result = semCaseExpr(c, n)
|
||||||
of nkReturnStmt: result = semReturn(c, n)
|
of nkReturnStmt: result = semReturn(c, n)
|
||||||
of nkAsmStmt: result = semAsm(c, n)
|
of nkAsmStmt: result = semAsm(c, n)
|
||||||
of nkYieldStmt: result = semYield(c, n)
|
of nkYieldStmt: result = semYield(c, n)
|
||||||
|
|
|
||||||
|
|
@ -610,17 +610,6 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||||
result = newIntNodeT(sonsLen(a), n)
|
result = newIntNodeT(sonsLen(a), n)
|
||||||
else:
|
else:
|
||||||
result = magicCall(m, n)
|
result = magicCall(m, n)
|
||||||
of mIs:
|
|
||||||
# BUGFIX: don't evaluate this too early: ``T is void``
|
|
||||||
if not containsGenericType(n[1].typ):
|
|
||||||
if n[2].kind in {nkStrLit..nkTripleStrLit}:
|
|
||||||
case n[2].strVal.normalize
|
|
||||||
of "closure":
|
|
||||||
let t = skipTypes(n[1].typ, abstractRange)
|
|
||||||
result = newIntNodeT(ord(t.kind == tyProc and
|
|
||||||
t.callConv == ccClosure), n)
|
|
||||||
elif not containsGenericType(n[2].typ):
|
|
||||||
result = newIntNodeT(ord(sameType(n[1].typ, n[2].typ)), n)
|
|
||||||
of mAstToStr:
|
of mAstToStr:
|
||||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
|
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
|
||||||
of mConStrStr:
|
of mConStrStr:
|
||||||
|
|
|
||||||
|
|
@ -261,16 +261,16 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
else:
|
else:
|
||||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind)
|
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind)
|
||||||
of nkEnumTy:
|
of nkEnumTy:
|
||||||
checkMinSonsLen(n, 1)
|
if n.sonsLen > 0:
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
|
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
var a: PNode
|
var a: PNode
|
||||||
case n.sons[i].kind
|
case n.sons[i].kind
|
||||||
of nkEnumFieldDef: a = n.sons[i].sons[0]
|
of nkEnumFieldDef: a = n.sons[i].sons[0]
|
||||||
of nkIdent: a = n.sons[i]
|
of nkIdent: a = n.sons[i]
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
|
addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
|
||||||
of nkObjectTy, nkTupleTy:
|
of nkObjectTy, nkTupleTy:
|
||||||
nil
|
nil
|
||||||
of nkFormalParams:
|
of nkFormalParams:
|
||||||
|
|
@ -306,6 +306,9 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
n.sons[bodyPos] = semGenericStmtScope(c, body, flags, toBind)
|
n.sons[bodyPos] = semGenericStmtScope(c, body, flags, toBind)
|
||||||
closeScope(c.tab)
|
closeScope(c.tab)
|
||||||
of nkPragma, nkPragmaExpr: nil
|
of nkPragma, nkPragmaExpr: nil
|
||||||
|
of nkExprColonExpr:
|
||||||
|
checkMinSonsLen(n, 2)
|
||||||
|
result.sons[1] = semGenericStmt(c, n.sons[1], flags, toBind)
|
||||||
else:
|
else:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
result.sons[i] = semGenericStmt(c, n.sons[i], flags, toBind)
|
result.sons[i] = semGenericStmt(c, n.sons[i], flags, toBind)
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,13 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
||||||
var t = PType(IdTableGet(pt, q.typ))
|
var t = PType(IdTableGet(pt, q.typ))
|
||||||
if t == nil:
|
if t == nil:
|
||||||
LocalError(a.info, errCannotInstantiateX, s.name.s)
|
if tfRetType in q.typ.flags:
|
||||||
t = errorType(c)
|
# keep the generic type and allow the return type to be bound
|
||||||
|
# later by semAsgn in return type inference scenario
|
||||||
|
t = q.typ
|
||||||
|
else:
|
||||||
|
LocalError(a.info, errCannotInstantiateX, s.name.s)
|
||||||
|
t = errorType(c)
|
||||||
elif t.kind == tyGenericParam:
|
elif t.kind == tyGenericParam:
|
||||||
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
|
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
|
||||||
elif t.kind == tyGenericInvokation:
|
elif t.kind == tyGenericInvokation:
|
||||||
|
|
@ -163,7 +168,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
result.typ = newTypeS(tyProc, c)
|
result.typ = newTypeS(tyProc, c)
|
||||||
rawAddSon(result.typ, nil)
|
rawAddSon(result.typ, nil)
|
||||||
result.typ.callConv = fn.typ.callConv
|
result.typ.callConv = fn.typ.callConv
|
||||||
ParamsTypeCheck(c, result.typ)
|
|
||||||
var oldPrc = GenericCacheGet(c, entry)
|
var oldPrc = GenericCacheGet(c, entry)
|
||||||
if oldPrc == nil:
|
if oldPrc == nil:
|
||||||
c.generics.generics.add(entry)
|
c.generics.generics.add(entry)
|
||||||
|
|
@ -174,6 +178,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
if fn.kind != skTemplate:
|
if fn.kind != skTemplate:
|
||||||
instantiateBody(c, n, result)
|
instantiateBody(c, n, result)
|
||||||
sideEffectsCheck(c, result)
|
sideEffectsCheck(c, result)
|
||||||
|
ParamsTypeCheck(c, result.typ)
|
||||||
else:
|
else:
|
||||||
result = oldPrc
|
result = oldPrc
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
|
||||||
|
|
@ -584,22 +584,20 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
|
||||||
result.typ = newTypeS(tyTypeDesc, c)
|
result.typ = newTypeS(tyTypeDesc, c)
|
||||||
result.typ.sons = paramType.sons
|
result.typ.sons = paramType.sons
|
||||||
of tyDistinct:
|
of tyDistinct:
|
||||||
# type T1 = distinct expr
|
|
||||||
# type S1 = distinct Sortable
|
|
||||||
# proc x(a, b: T1, c, d: S1)
|
|
||||||
# This forces bindOnce behavior for the type class, equivalent to
|
|
||||||
# proc x[T, S](a, b: T, c, d: S)
|
|
||||||
result = paramTypeClass(c, paramType.lastSon, procKind)
|
result = paramTypeClass(c, paramType.lastSon, procKind)
|
||||||
result.id = paramType.sym.name
|
# disable the bindOnce behavior for the type class
|
||||||
|
result.id = nil
|
||||||
|
return
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
# type Foo[T] = object
|
# type Foo[T] = object
|
||||||
# proc x(a: Foo, b: Foo)
|
# proc x(a: Foo, b: Foo)
|
||||||
result.typ = newTypeS(tyTypeClass, c)
|
result.typ = newTypeS(tyTypeClass, c)
|
||||||
result.typ.addSonSkipIntLit(paramType)
|
result.typ.addSonSkipIntLit(paramType)
|
||||||
result.id = paramType.sym.name # bindOnce by default
|
|
||||||
of tyTypeClass:
|
of tyTypeClass:
|
||||||
result.typ = copyType(paramType, getCurrOwner(), false)
|
result.typ = copyType(paramType, getCurrOwner(), false)
|
||||||
else: nil
|
else: nil
|
||||||
|
# bindOnce by default
|
||||||
|
if paramType.sym != nil: result.id = paramType.sym.name
|
||||||
|
|
||||||
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
paramType: PType, paramName: string,
|
paramType: PType, paramName: string,
|
||||||
|
|
@ -619,7 +617,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
let s = SymtabGet(c.tab, paramTypId)
|
let s = SymtabGet(c.tab, paramTypId)
|
||||||
# tests/run/tinterf triggers this:
|
# tests/run/tinterf triggers this:
|
||||||
if s != nil: result = s.typ
|
if s != nil: result = s.typ
|
||||||
else:
|
else:
|
||||||
LocalError(info, errCannotInstantiateX, paramName)
|
LocalError(info, errCannotInstantiateX, paramName)
|
||||||
result = errorType(c)
|
result = errorType(c)
|
||||||
else:
|
else:
|
||||||
|
|
@ -684,8 +682,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
||||||
for j in countup(0, length-3):
|
for j in countup(0, length-3):
|
||||||
var arg = newSymG(skParam, a.sons[j], c)
|
var arg = newSymG(skParam, a.sons[j], c)
|
||||||
var finalType = liftParamType(c, kind, genericParams, typ, arg.name.s,
|
var finalType = liftParamType(c, kind, genericParams, typ,
|
||||||
arg.info).skipIntLit
|
arg.name.s, arg.info).skipIntLit
|
||||||
arg.typ = finalType
|
arg.typ = finalType
|
||||||
arg.position = counter
|
arg.position = counter
|
||||||
inc(counter)
|
inc(counter)
|
||||||
|
|
@ -703,6 +701,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||||
if r.sym == nil or sfAnon notin r.sym.flags:
|
if r.sym == nil or sfAnon notin r.sym.flags:
|
||||||
r = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info)
|
r = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info)
|
||||||
|
r.flags.incl tfRetType
|
||||||
result.sons[0] = skipIntLit(r)
|
result.sons[0] = skipIntLit(r)
|
||||||
res.typ = result.sons[0]
|
res.typ = result.sons[0]
|
||||||
|
|
||||||
|
|
@ -800,22 +799,25 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
LocalError(n.info, errTypeExpected)
|
LocalError(n.info, errTypeExpected)
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
let op = n.sons[0].ident
|
if n[0].kind == nkIdent:
|
||||||
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
|
let op = n.sons[0].ident
|
||||||
var
|
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
|
||||||
t1 = semTypeNode(c, n.sons[1], nil)
|
var
|
||||||
t2 = semTypeNode(c, n.sons[2], nil)
|
t1 = semTypeNode(c, n.sons[1], nil)
|
||||||
if t1 == nil:
|
t2 = semTypeNode(c, n.sons[2], nil)
|
||||||
LocalError(n.sons[1].info, errTypeExpected)
|
if t1 == nil:
|
||||||
result = newOrPrevType(tyError, prev, c)
|
LocalError(n.sons[1].info, errTypeExpected)
|
||||||
elif t2 == nil:
|
result = newOrPrevType(tyError, prev, c)
|
||||||
LocalError(n.sons[2].info, errTypeExpected)
|
elif t2 == nil:
|
||||||
result = newOrPrevType(tyError, prev, c)
|
LocalError(n.sons[2].info, errTypeExpected)
|
||||||
|
result = newOrPrevType(tyError, prev, c)
|
||||||
|
else:
|
||||||
|
result = newTypeS(tyTypeClass, c)
|
||||||
|
result.addSonSkipIntLit(t1)
|
||||||
|
result.addSonSkipIntLit(t2)
|
||||||
|
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
|
||||||
else:
|
else:
|
||||||
result = newTypeS(tyTypeClass, c)
|
result = semTypeExpr(c, n)
|
||||||
result.addSonSkipIntLit(t1)
|
|
||||||
result.addSonSkipIntLit(t2)
|
|
||||||
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
|
|
||||||
else:
|
else:
|
||||||
result = semTypeExpr(c, n)
|
result = semTypeExpr(c, n)
|
||||||
of nkCurlyExpr:
|
of nkCurlyExpr:
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ type
|
||||||
|
|
||||||
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
|
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
|
||||||
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
||||||
|
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode
|
||||||
|
|
||||||
proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
|
proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
|
|
@ -66,7 +67,7 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
|
||||||
for i in 0 .. safeLen(n)-1:
|
for i in 0 .. safeLen(n)-1:
|
||||||
# XXX HACK: ``f(a, b)``, avoid to instantiate `f`
|
# XXX HACK: ``f(a, b)``, avoid to instantiate `f`
|
||||||
if i == 0: result.add(n[i])
|
if i == 0: result.add(n[i])
|
||||||
else: result.add(prepareNode(cl, n[i]))
|
else: result.add(ReplaceTypeVarsN(cl, n[i]))
|
||||||
|
|
||||||
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
|
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
## the call to overloaded procs, generic procs and operators.
|
## the call to overloaded procs, generic procs and operators.
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
||||||
magicsys, condsyms, idents, lexer, options
|
magicsys, condsyms, idents, lexer, options
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -257,32 +257,6 @@ proc tupleRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
var y = a.n.sons[i].sym
|
var y = a.n.sons[i].sym
|
||||||
if x.name.id != y.name.id: return isNone
|
if x.name.id != y.name.id: return isNone
|
||||||
|
|
||||||
proc matchTypeClass(c: var TCandidate, typeClass, t: PType): TTypeRelation =
|
|
||||||
for i in countup(0, typeClass.sonsLen - 1):
|
|
||||||
let req = typeClass.sons[i]
|
|
||||||
var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
|
|
||||||
|
|
||||||
if not match:
|
|
||||||
case req.kind
|
|
||||||
of tyGenericBody:
|
|
||||||
if t.kind == tyGenericInst and t.sons[0] == req:
|
|
||||||
match = true
|
|
||||||
put(c.bindings, typeClass, t)
|
|
||||||
of tyTypeClass:
|
|
||||||
match = matchTypeClass(c, req, t) == isGeneric
|
|
||||||
else: nil
|
|
||||||
elif t.kind in {tyObject}:
|
|
||||||
match = sameType(t, req)
|
|
||||||
|
|
||||||
if tfAny in typeClass.flags:
|
|
||||||
if match: return isGeneric
|
|
||||||
else:
|
|
||||||
if not match: return isNone
|
|
||||||
|
|
||||||
# if the loop finished without returning, either all constraints matched
|
|
||||||
# or none of them matched.
|
|
||||||
result = if tfAny in typeClass.flags: isNone else: isGeneric
|
|
||||||
|
|
||||||
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
||||||
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
|
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
|
||||||
|
|
@ -325,6 +299,10 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
result = isNone
|
result = isNone
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
|
proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
|
result = if matchTypeClass(c.bindings, f, a): isGeneric
|
||||||
|
else: isNone
|
||||||
|
|
||||||
proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
# is a subtype of f?
|
# is a subtype of f?
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
|
||||||
|
|
@ -626,9 +626,9 @@ proc SameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
|
||||||
var c = initSameTypeClosure()
|
var c = initSameTypeClosure()
|
||||||
c.flags = flags
|
c.flags = flags
|
||||||
result = SameTypeAux(a, b, c)
|
result = SameTypeAux(a, b, c)
|
||||||
|
|
||||||
proc equalParam(a, b: PSym): TParamsEquality =
|
proc equalParam(a, b: PSym): TParamsEquality =
|
||||||
if SameTypeOrNil(a.typ, b.typ):
|
if SameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}):
|
||||||
if a.ast == b.ast:
|
if a.ast == b.ast:
|
||||||
result = paramsEqual
|
result = paramsEqual
|
||||||
elif a.ast != nil and b.ast != nil:
|
elif a.ast != nil and b.ast != nil:
|
||||||
|
|
@ -904,7 +904,38 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
|
||||||
if i >= a.sonslen or a.sons[i] == nil: return false
|
if i >= a.sonslen or a.sons[i] == nil: return false
|
||||||
a = a.sons[i]
|
a = a.sons[i]
|
||||||
result = a.kind == last
|
result = a.kind == last
|
||||||
|
|
||||||
|
proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
|
||||||
|
for i in countup(0, typeClass.sonsLen - 1):
|
||||||
|
let req = typeClass.sons[i]
|
||||||
|
var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
|
||||||
|
|
||||||
|
if not match:
|
||||||
|
case req.kind
|
||||||
|
of tyGenericBody:
|
||||||
|
if t.kind == tyGenericInst and t.sons[0] == req:
|
||||||
|
match = true
|
||||||
|
IdTablePut(bindings, typeClass, t)
|
||||||
|
of tyTypeClass:
|
||||||
|
match = matchTypeClass(bindings, req, t)
|
||||||
|
else: nil
|
||||||
|
elif t.kind in {tyObject}:
|
||||||
|
match = sameType(t, req)
|
||||||
|
|
||||||
|
if tfAny in typeClass.flags:
|
||||||
|
if match: return true
|
||||||
|
else:
|
||||||
|
if not match: return false
|
||||||
|
|
||||||
|
# if the loop finished without returning, either all constraints matched
|
||||||
|
# or none of them matched.
|
||||||
|
result = if tfAny in typeClass.flags: false else: true
|
||||||
|
|
||||||
|
proc matchTypeClass*(typeClass, typ: PType): bool =
|
||||||
|
var bindings: TIdTable
|
||||||
|
initIdTable(bindings)
|
||||||
|
result = matchTypeClass(bindings, typeClass, typ)
|
||||||
|
|
||||||
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
||||||
assert(kind in {skVar, skLet, skConst, skParam, skResult})
|
assert(kind in {skVar, skLet, skConst, skParam, skResult})
|
||||||
# if we have already checked the type, return true, because we stop the
|
# if we have already checked the type, return true, because we stop the
|
||||||
|
|
|
||||||
|
|
@ -2237,6 +2237,28 @@ An if expression always results in a value, so the ``else`` part is
|
||||||
required. ``Elif`` parts are also allowed (but unlikely to be good
|
required. ``Elif`` parts are also allowed (but unlikely to be good
|
||||||
style).
|
style).
|
||||||
|
|
||||||
|
When expression
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Just like an `if expression`, but corresponding to the when statement.
|
||||||
|
|
||||||
|
Case expression
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The `case expression` is again very similar to the case statement:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
var favoriteFood = case animal
|
||||||
|
of "dog": "bones"
|
||||||
|
of "cat": "mice"
|
||||||
|
elif animal.endsWith"whale": "plankton"
|
||||||
|
else:
|
||||||
|
echo "I'm not sure what to serve, but everybody loves ice cream"
|
||||||
|
"ice cream"
|
||||||
|
|
||||||
|
As seen in the above example, the case expression can also introduce side
|
||||||
|
effects. When multiple statements are given for a branch, Nimrod will use
|
||||||
|
the last expression as the result value, much like in an `expr` template.
|
||||||
|
|
||||||
Table constructor
|
Table constructor
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
@ -2244,10 +2266,10 @@ Table constructor
|
||||||
A `table constructor`:idx: is syntactic sugar for an array constructor:
|
A `table constructor`:idx: is syntactic sugar for an array constructor:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
{"key1": "value1", "key2": "value2"}
|
{"key1": "value1", "key2", "key3": "value2"}
|
||||||
|
|
||||||
# is the same as:
|
# is the same as:
|
||||||
[("key1", "value1"), ("key2", "value2")]
|
[("key1", "value1"), ("key2", "value2"), ("key3", "value")]
|
||||||
|
|
||||||
|
|
||||||
The empty table can be written ``{:}`` (in contrast to the empty set
|
The empty table can be written ``{:}`` (in contrast to the empty set
|
||||||
|
|
@ -2940,6 +2962,13 @@ from the proc body. This is usually used with the ``auto`` type class:
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc makePair(a, b): auto = (first: a, second: b)
|
proc makePair(a, b): auto = (first: a, second: b)
|
||||||
|
|
||||||
|
The return type will be treated as additional generic param and can be
|
||||||
|
explicitly specified at call sites as any other generic param.
|
||||||
|
|
||||||
|
Future versions of nimrod may also support overloading based on the return type
|
||||||
|
of the overloads. In such settings, the expected result type at call sites may
|
||||||
|
also influence the inferred return type.
|
||||||
|
|
||||||
Symbol lookup in generics
|
Symbol lookup in generics
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
@ -3431,7 +3460,7 @@ typedesc
|
||||||
|
|
||||||
`typedesc` is a special type allowing you to treat types as compile-time values
|
`typedesc` is a special type allowing you to treat types as compile-time values
|
||||||
(i.e. if types are compile-time values and all values have a type, then
|
(i.e. if types are compile-time values and all values have a type, then
|
||||||
typedesc must be their type).
|
typedesc must be their type).
|
||||||
|
|
||||||
When used as a regular proc param, typedesc acts as a type class. The proc
|
When used as a regular proc param, typedesc acts as a type class. The proc
|
||||||
will be instantiated for each unique type parameter and you can refer to the
|
will be instantiated for each unique type parameter and you can refer to the
|
||||||
|
|
@ -3457,15 +3486,14 @@ a type-safe wrapper for the unsafe `printf` function form C:
|
||||||
macro safePrintF(formatString: string{lit}, args: vararg[expr]): expr =
|
macro safePrintF(formatString: string{lit}, args: vararg[expr]): expr =
|
||||||
var i = 0
|
var i = 0
|
||||||
for c in formatChars(formatString):
|
for c in formatChars(formatString):
|
||||||
const FormatChars = {
|
var expectedType = case c
|
||||||
'c': char,
|
of 'c': char
|
||||||
'd', 'i', 'x', 'X': int,
|
of 'd', 'i', 'x', 'X': int
|
||||||
'f', 'e', 'E', 'g', 'G': float,
|
of 'f', 'e', 'E', 'g', 'G': float
|
||||||
's': string,
|
of 's': string
|
||||||
'p': pointer,
|
of 'p': pointer
|
||||||
}
|
else: EOutOfRange
|
||||||
|
|
||||||
var expectedType = find(FormatChars, c, EOutOfRange)
|
|
||||||
var actualType = args[i].getType
|
var actualType = args[i].getType
|
||||||
inc i
|
inc i
|
||||||
|
|
||||||
|
|
@ -3642,15 +3670,20 @@ proc with no side effects:
|
||||||
|
|
||||||
destructor pragma
|
destructor pragma
|
||||||
-----------------
|
-----------------
|
||||||
`RAII`:idx:
|
|
||||||
`automatic variables`:idx:
|
|
||||||
`destructors`:idx:
|
|
||||||
The `destructor` pragma is used to mark a proc to act as a type destructor.
|
The `destructor` pragma is used to mark a proc to act as a type destructor.
|
||||||
The proc must have a single parameter, having a concrete type.
|
The proc must have a single parameter with a concrete type (the name of a
|
||||||
|
generic type is allowed too).
|
||||||
|
|
||||||
Destructors will be automatically invoked when a local stack variable goes
|
Destructors will be automatically invoked when a local stack variable goes
|
||||||
out of scope. If a record type features a field with destructable type and
|
out of scope.
|
||||||
|
|
||||||
|
If a record type features a field with destructable type and
|
||||||
the user have not provided explicit implementation, Nimrod will automatically
|
the user have not provided explicit implementation, Nimrod will automatically
|
||||||
generate a destructor for the record type.
|
generate a destructor for the record type. Nimrod will automatically insert
|
||||||
|
calls to any base class destructors in both user-defined and generated
|
||||||
|
destructors.
|
||||||
|
|
||||||
|
|
||||||
procvar pragma
|
procvar pragma
|
||||||
--------------
|
--------------
|
||||||
|
|
@ -3658,7 +3691,6 @@ The `procvar`:idx: pragma is used to mark a proc that it can be passed to a
|
||||||
procedural variable.
|
procedural variable.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
compileTime pragma
|
compileTime pragma
|
||||||
------------------
|
------------------
|
||||||
The `compileTime`:idx: pragma is used to mark a proc to be used at compile
|
The `compileTime`:idx: pragma is used to mark a proc to be used at compile
|
||||||
|
|
|
||||||
|
|
@ -1,194 +1,188 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nimrod's Runtime Library
|
# Nimrod's Runtime Library
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
## This module contains the interface to the compiler's abstract syntax
|
## This module contains the interface to the compiler's abstract syntax
|
||||||
## tree (`AST`:idx:). Macros operate on this tree.
|
## tree (`AST`:idx:). Macros operate on this tree.
|
||||||
|
|
||||||
## .. include:: ../doc/astspec.txt
|
## .. include:: ../doc/astspec.txt
|
||||||
|
|
||||||
type
|
type
|
||||||
TNimrodNodeKind* = enum
|
TNimrodNodeKind* = enum
|
||||||
nnkNone, nnkEmpty, nnkIdent, nnkSym,
|
nnkNone, nnkEmpty, nnkIdent, nnkSym,
|
||||||
nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
|
nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
|
||||||
nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit,
|
nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit,
|
||||||
nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit,
|
nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit,
|
||||||
nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
|
nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
|
||||||
nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall,
|
nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall,
|
||||||
nnkCommand, nnkCall, nnkCallStrLit, nnkExprEqExpr,
|
nnkCommand, nnkCall, nnkCallStrLit, nnkExprEqExpr,
|
||||||
nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, nnkInfix,
|
nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, nnkInfix,
|
||||||
nnkPrefix, nnkPostfix, nnkPar, nnkCurly, nnkCurlyExpr,
|
nnkPrefix, nnkPostfix, nnkPar, nnkCurly, nnkCurlyExpr,
|
||||||
nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
|
nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
|
||||||
nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
|
nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
|
||||||
nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkAccQuoted,
|
nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkAccQuoted,
|
||||||
nnkTableConstr, nnkBind,
|
nnkTableConstr, nnkBind,
|
||||||
nnkClosedSymChoice,
|
nnkClosedSymChoice,
|
||||||
nnkOpenSymChoice,
|
nnkOpenSymChoice,
|
||||||
nnkHiddenStdConv,
|
nnkHiddenStdConv,
|
||||||
nnkHiddenSubConv, nnkHiddenCallConv, nnkConv, nnkCast, nnkStaticExpr,
|
nnkHiddenSubConv, nnkHiddenCallConv, nnkConv, nnkCast, nnkStaticExpr,
|
||||||
nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv,
|
nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv,
|
||||||
nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange,
|
nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange,
|
||||||
nnkStringToCString, nnkCStringToString, nnkAsgn,
|
nnkStringToCString, nnkCStringToString, nnkAsgn,
|
||||||
nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit,
|
nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit,
|
||||||
nnkModule, nnkProcDef, nnkMethodDef, nnkConverterDef,
|
nnkModule, nnkProcDef, nnkMethodDef, nnkConverterDef,
|
||||||
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
|
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
|
||||||
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
|
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
|
||||||
nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt,
|
nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt,
|
||||||
nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt,
|
nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt,
|
||||||
nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
|
nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
|
||||||
nnkConstDef, nnkTypeDef,
|
nnkConstDef, nnkTypeDef,
|
||||||
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
||||||
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
|
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
|
||||||
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
|
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
|
||||||
nnkIncludeStmt, nnkBindStmt, nnkMixinStmt,
|
nnkIncludeStmt, nnkBindStmt, nnkMixinStmt,
|
||||||
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
||||||
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
||||||
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
||||||
nnkRefTy, nnkPtrTy, nnkVarTy,
|
nnkRefTy, nnkPtrTy, nnkVarTy,
|
||||||
nnkConstTy, nnkMutableTy,
|
nnkConstTy, nnkMutableTy,
|
||||||
nnkDistinctTy,
|
nnkDistinctTy,
|
||||||
nnkProcTy, nnkEnumTy,
|
nnkProcTy, nnkEnumTy,
|
||||||
nnkEnumFieldDef,
|
nnkEnumFieldDef,
|
||||||
nnkArglist, nnkPattern
|
nnkArglist, nnkPattern
|
||||||
nnkReturnToken
|
nnkReturnToken
|
||||||
TNimNodeKinds* = set[TNimrodNodeKind]
|
TNimNodeKinds* = set[TNimrodNodeKind]
|
||||||
TNimrodTypeKind* = enum
|
TNimrodTypeKind* = enum
|
||||||
ntyNone, ntyBool, ntyChar, ntyEmpty,
|
ntyNone, ntyBool, ntyChar, ntyEmpty,
|
||||||
ntyArrayConstr, ntyNil, ntyExpr, ntyStmt,
|
ntyArrayConstr, ntyNil, ntyExpr, ntyStmt,
|
||||||
ntyTypeDesc, ntyGenericInvokation, ntyGenericBody, ntyGenericInst,
|
ntyTypeDesc, ntyGenericInvokation, ntyGenericBody, ntyGenericInst,
|
||||||
ntyGenericParam, ntyDistinct, ntyEnum, ntyOrdinal,
|
ntyGenericParam, ntyDistinct, ntyEnum, ntyOrdinal,
|
||||||
ntyArray, ntyObject, ntyTuple, ntySet,
|
ntyArray, ntyObject, ntyTuple, ntySet,
|
||||||
ntyRange, ntyPtr, ntyRef, ntyVar,
|
ntyRange, ntyPtr, ntyRef, ntyVar,
|
||||||
ntySequence, ntyProc, ntyPointer, ntyOpenArray,
|
ntySequence, ntyProc, ntyPointer, ntyOpenArray,
|
||||||
ntyString, ntyCString, ntyForward, ntyInt,
|
ntyString, ntyCString, ntyForward, ntyInt,
|
||||||
ntyInt8, ntyInt16, ntyInt32, ntyInt64,
|
ntyInt8, ntyInt16, ntyInt32, ntyInt64,
|
||||||
ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128
|
ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128
|
||||||
TNimTypeKinds* = set[TNimrodTypeKind]
|
TNimTypeKinds* = set[TNimrodTypeKind]
|
||||||
TNimrodSymKind* = enum
|
TNimrodSymKind* = enum
|
||||||
nskUnknown, nskConditional, nskDynLib, nskParam,
|
nskUnknown, nskConditional, nskDynLib, nskParam,
|
||||||
nskGenericParam, nskTemp, nskType, nskConst,
|
nskGenericParam, nskTemp, nskType, nskConst,
|
||||||
nskVar, nskProc, nskMethod, nskIterator,
|
nskVar, nskProc, nskMethod, nskIterator,
|
||||||
nskConverter, nskMacro, nskTemplate, nskField,
|
nskConverter, nskMacro, nskTemplate, nskField,
|
||||||
nskEnumField, nskForVar, nskModule, nskLabel,
|
nskEnumField, nskForVar, nskModule, nskLabel,
|
||||||
nskStub
|
nskStub
|
||||||
TNimSymKinds* = set[TNimrodSymKind]
|
TNimSymKinds* = set[TNimrodSymKind]
|
||||||
|
|
||||||
type
|
|
||||||
TNimrodIdent* = object of TObject
|
|
||||||
## represents a Nimrod identifier in the AST
|
|
||||||
|
|
||||||
TNimrodSymbol {.final.} = object # hidden
|
|
||||||
TNimrodType {.final.} = object # hidden
|
|
||||||
|
|
||||||
PNimrodType* {.compilerproc.} = ref TNimrodType
|
|
||||||
## represents a Nimrod type in the compiler; currently this is not very
|
|
||||||
## useful as there is no API to deal with Nimrod types.
|
|
||||||
|
|
||||||
PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol
|
|
||||||
## represents a Nimrod *symbol* in the compiler; a *symbol* is a looked-up
|
|
||||||
## *ident*.
|
|
||||||
|
|
||||||
const
|
|
||||||
nnkLiterals* = {nnkCharLit..nnkNilLit}
|
|
||||||
nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
|
|
||||||
nnkCallStrLit}
|
|
||||||
|
|
||||||
proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".}
|
|
||||||
## get `n`'s `i`'th child.
|
|
||||||
|
|
||||||
proc `[]=`*(n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild".}
|
|
||||||
## set `n`'s `i`'th child to `child`.
|
|
||||||
|
|
||||||
proc `!`*(s: string): TNimrodIdent {.magic: "StrToIdent".}
|
|
||||||
## constructs an identifier from the string `s`
|
|
||||||
|
|
||||||
proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".}
|
|
||||||
## converts a Nimrod identifier to a string
|
|
||||||
|
|
||||||
proc `$`*(s: PNimrodSymbol): string {.magic: "IdentToStr".}
|
|
||||||
## converts a Nimrod symbol to a string
|
|
||||||
|
|
||||||
proc `==`*(a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
|
type
|
||||||
## compares two Nimrod identifiers
|
TNimrodIdent* = object of TObject
|
||||||
|
## represents a Nimrod identifier in the AST
|
||||||
proc `==`*(a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
|
|
||||||
## compares two Nimrod nodes
|
TNimrodSymbol {.final.} = object # hidden
|
||||||
|
PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol
|
||||||
proc len*(n: PNimrodNode): int {.magic: "NLen".}
|
## represents a Nimrod *symbol* in the compiler; a *symbol* is a looked-up
|
||||||
## returns the number of children of `n`.
|
## *ident*.
|
||||||
|
|
||||||
proc add*(father, child: PNimrodNode) {.magic: "NAdd".}
|
const
|
||||||
## adds the `child` to the `father` node
|
nnkLiterals* = {nnkCharLit..nnkNilLit}
|
||||||
|
nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
|
||||||
proc add*(father: PNimrodNode, children: varargs[PNimrodNode]) {.
|
nnkCallStrLit}
|
||||||
magic: "NAddMultiple".}
|
|
||||||
## adds each child of `children` to the `father` node
|
proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".}
|
||||||
|
## get `n`'s `i`'th child.
|
||||||
proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel".}
|
|
||||||
## deletes `n` children of `father` starting at index `idx`.
|
proc `[]=`*(n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild".}
|
||||||
|
## set `n`'s `i`'th child to `child`.
|
||||||
proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind".}
|
|
||||||
## returns the `kind` of the node `n`.
|
proc `!`*(s: string): TNimrodIdent {.magic: "StrToIdent".}
|
||||||
|
## constructs an identifier from the string `s`
|
||||||
proc intVal*(n: PNimrodNode): biggestInt {.magic: "NIntVal".}
|
|
||||||
proc floatVal*(n: PNimrodNode): biggestFloat {.magic: "NFloatVal".}
|
proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".}
|
||||||
proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".}
|
## converts a Nimrod identifier to a string
|
||||||
proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".}
|
|
||||||
proc typ*(n: PNimrodNode): PNimrodType {.magic: "NGetType".}
|
proc `$`*(s: PNimrodSymbol): string {.magic: "IdentToStr".}
|
||||||
proc strVal*(n: PNimrodNode): string {.magic: "NStrVal".}
|
## converts a Nimrod symbol to a string
|
||||||
|
|
||||||
proc `intVal=`*(n: PNimrodNode, val: biggestInt) {.magic: "NSetIntVal".}
|
proc `==`*(a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
|
||||||
proc `floatVal=`*(n: PNimrodNode, val: biggestFloat) {.magic: "NSetFloatVal".}
|
## compares two Nimrod identifiers
|
||||||
proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".}
|
|
||||||
proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
|
proc `==`*(a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
|
||||||
proc `typ=`*(n: PNimrodNode, typ: PNimrodType) {.magic: "NSetType".}
|
## compares two Nimrod nodes
|
||||||
proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".}
|
|
||||||
|
proc len*(n: PNimrodNode): int {.magic: "NLen".}
|
||||||
proc newNimNode*(kind: TNimrodNodeKind,
|
## returns the number of children of `n`.
|
||||||
n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode".}
|
|
||||||
|
proc add*(father, child: PNimrodNode) {.magic: "NAdd".}
|
||||||
proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode".}
|
## adds the `child` to the `father` node
|
||||||
proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree".}
|
|
||||||
|
proc add*(father: PNimrodNode, children: varargs[PNimrodNode]) {.
|
||||||
proc error*(msg: string) {.magic: "NError".}
|
magic: "NAddMultiple".}
|
||||||
## writes an error message at compile time
|
## adds each child of `children` to the `father` node
|
||||||
|
|
||||||
proc warning*(msg: string) {.magic: "NWarning".}
|
proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel".}
|
||||||
## writes a warning message at compile time
|
## deletes `n` children of `father` starting at index `idx`.
|
||||||
|
|
||||||
proc hint*(msg: string) {.magic: "NHint".}
|
proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind".}
|
||||||
## writes a hint message at compile time
|
## returns the `kind` of the node `n`.
|
||||||
|
|
||||||
proc newStrLitNode*(s: string): PNimrodNode {.compileTime.} =
|
proc intVal*(n: PNimrodNode): biggestInt {.magic: "NIntVal".}
|
||||||
## creates a string literal node from `s`
|
proc floatVal*(n: PNimrodNode): biggestFloat {.magic: "NFloatVal".}
|
||||||
result = newNimNode(nnkStrLit)
|
proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".}
|
||||||
result.strVal = s
|
proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".}
|
||||||
|
proc typ*(n: PNimrodNode): typedesc {.magic: "NGetType".}
|
||||||
proc newIntLitNode*(i: biggestInt): PNimrodNode {.compileTime.} =
|
proc strVal*(n: PNimrodNode): string {.magic: "NStrVal".}
|
||||||
## creates a int literal node from `i`
|
|
||||||
result = newNimNode(nnkIntLit)
|
proc `intVal=`*(n: PNimrodNode, val: biggestInt) {.magic: "NSetIntVal".}
|
||||||
result.intVal = i
|
proc `floatVal=`*(n: PNimrodNode, val: biggestFloat) {.magic: "NSetFloatVal".}
|
||||||
|
proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".}
|
||||||
proc newFloatLitNode*(f: biggestFloat): PNimrodNode {.compileTime.} =
|
proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
|
||||||
## creates a float literal node from `f`
|
proc `typ=`*(n: PNimrodNode, typ: typedesc) {.magic: "NSetType".}
|
||||||
result = newNimNode(nnkFloatLit)
|
proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".}
|
||||||
result.floatVal = f
|
|
||||||
|
proc newNimNode*(kind: TNimrodNodeKind,
|
||||||
proc newIdentNode*(i: TNimrodIdent): PNimrodNode {.compileTime.} =
|
n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode".}
|
||||||
## creates an identifier node from `i`
|
|
||||||
result = newNimNode(nnkIdent)
|
proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode".}
|
||||||
result.ident = i
|
proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree".}
|
||||||
|
|
||||||
proc newIdentNode*(i: string): PNimrodNode {.compileTime.} =
|
proc error*(msg: string) {.magic: "NError".}
|
||||||
## creates an identifier node from `i`
|
## writes an error message at compile time
|
||||||
result = newNimNode(nnkIdent)
|
|
||||||
result.ident = !i
|
proc warning*(msg: string) {.magic: "NWarning".}
|
||||||
|
## writes a warning message at compile time
|
||||||
|
|
||||||
|
proc hint*(msg: string) {.magic: "NHint".}
|
||||||
|
## writes a hint message at compile time
|
||||||
|
|
||||||
|
proc newStrLitNode*(s: string): PNimrodNode {.compileTime.} =
|
||||||
|
## creates a string literal node from `s`
|
||||||
|
result = newNimNode(nnkStrLit)
|
||||||
|
result.strVal = s
|
||||||
|
|
||||||
|
proc newIntLitNode*(i: biggestInt): PNimrodNode {.compileTime.} =
|
||||||
|
## creates a int literal node from `i`
|
||||||
|
result = newNimNode(nnkIntLit)
|
||||||
|
result.intVal = i
|
||||||
|
|
||||||
|
proc newFloatLitNode*(f: biggestFloat): PNimrodNode {.compileTime.} =
|
||||||
|
## creates a float literal node from `f`
|
||||||
|
result = newNimNode(nnkFloatLit)
|
||||||
|
result.floatVal = f
|
||||||
|
|
||||||
|
proc newIdentNode*(i: TNimrodIdent): PNimrodNode {.compileTime.} =
|
||||||
|
## creates an identifier node from `i`
|
||||||
|
result = newNimNode(nnkIdent)
|
||||||
|
result.ident = i
|
||||||
|
|
||||||
|
proc newIdentNode*(i: string): PNimrodNode {.compileTime.} =
|
||||||
|
## creates an identifier node from `i`
|
||||||
|
result = newNimNode(nnkIdent)
|
||||||
|
result.ident = !i
|
||||||
|
|
||||||
type
|
type
|
||||||
TBindSymRule* = enum ## specifies how ``bindSym`` behaves
|
TBindSymRule* = enum ## specifies how ``bindSym`` behaves
|
||||||
|
|
@ -212,157 +206,157 @@ proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
|
||||||
## returned even if the symbol is not ambiguous.
|
## returned even if the symbol is not ambiguous.
|
||||||
|
|
||||||
proc callsite*(): PNimrodNode {.magic: "NCallSite".}
|
proc callsite*(): PNimrodNode {.magic: "NCallSite".}
|
||||||
## returns the AST if the invokation expression that invoked this macro.
|
## returns the AST if the invokation expression that invoked this macro.
|
||||||
|
|
||||||
proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
|
proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||||
## converts the AST `n` to the concrete Nimrod code and wraps that
|
## converts the AST `n` to the concrete Nimrod code and wraps that
|
||||||
## in a string literal node
|
## in a string literal node
|
||||||
return newStrLitNode(repr(n))
|
return newStrLitNode(repr(n))
|
||||||
|
|
||||||
proc lineinfo*(n: PNimrodNode): string {.magic: "NLineInfo".}
|
proc lineinfo*(n: PNimrodNode): string {.magic: "NLineInfo".}
|
||||||
## returns the position the node appears in the original source file
|
## returns the position the node appears in the original source file
|
||||||
## in the form filename(line, col)
|
## in the form filename(line, col)
|
||||||
|
|
||||||
proc parseExpr*(s: string): PNimrodNode {.magic: "ParseExprToAst".}
|
proc parseExpr*(s: string): PNimrodNode {.magic: "ParseExprToAst".}
|
||||||
## Compiles the passed string to its AST representation.
|
## Compiles the passed string to its AST representation.
|
||||||
## Expects a single expression.
|
## Expects a single expression.
|
||||||
|
|
||||||
proc parseStmt*(s: string): PNimrodNode {.magic: "ParseStmtToAst".}
|
proc parseStmt*(s: string): PNimrodNode {.magic: "ParseStmtToAst".}
|
||||||
## Compiles the passed string to its AST representation.
|
## Compiles the passed string to its AST representation.
|
||||||
## Expects one or more statements.
|
## Expects one or more statements.
|
||||||
|
|
||||||
proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst".}
|
proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst".}
|
||||||
## Obtains the AST nodes returned from a macro or template invocation.
|
## Obtains the AST nodes returned from a macro or template invocation.
|
||||||
## Example:
|
## Example:
|
||||||
##
|
##
|
||||||
## .. code-block:: nimrod
|
## .. code-block:: nimrod
|
||||||
##
|
##
|
||||||
## macro FooMacro() =
|
## macro FooMacro() =
|
||||||
## var ast = getAst(BarTemplate())
|
## var ast = getAst(BarTemplate())
|
||||||
|
|
||||||
template emit*(s: expr): stmt =
|
template emit*(s: expr): stmt =
|
||||||
## accepts a single string argument and treats it as nimrod code
|
## accepts a single string argument and treats it as nimrod code
|
||||||
## that should be inserted verbatim in the program
|
## that should be inserted verbatim in the program
|
||||||
## Example:
|
## Example:
|
||||||
##
|
##
|
||||||
## emit("echo " & '"' & "hello world".toUpper & '"')
|
## emit("echo " & '"' & "hello world".toUpper & '"')
|
||||||
##
|
##
|
||||||
block:
|
block:
|
||||||
const evaluated = s
|
const evaluated = s
|
||||||
eval: result = evaluated.parseStmt
|
eval: result = evaluated.parseStmt
|
||||||
|
|
||||||
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
|
|
||||||
## checks that `n` is of kind `k`. If this is not the case,
|
|
||||||
## compilation aborts with an error message. This is useful for writing
|
|
||||||
## macros that check the AST that is passed to them.
|
|
||||||
if n.kind != k: error("macro expects a node of kind: " & repr(k))
|
|
||||||
|
|
||||||
proc expectMinLen*(n: PNimrodNode, min: int) {.compileTime.} =
|
|
||||||
## checks that `n` has at least `min` children. If this is not the case,
|
|
||||||
## compilation aborts with an error message. This is useful for writing
|
|
||||||
## macros that check its number of arguments.
|
|
||||||
if n.len < min: error("macro expects a node with " & $min & " children")
|
|
||||||
|
|
||||||
proc expectLen*(n: PNimrodNode, len: int) {.compileTime.} =
|
|
||||||
## checks that `n` has exactly `len` children. If this is not the case,
|
|
||||||
## compilation aborts with an error message. This is useful for writing
|
|
||||||
## macros that check its number of arguments.
|
|
||||||
if n.len != len: error("macro expects a node with " & $len & " children")
|
|
||||||
|
|
||||||
proc newCall*(theProc: PNimrodNode,
|
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
|
||||||
args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
|
## checks that `n` is of kind `k`. If this is not the case,
|
||||||
## produces a new call node. `theProc` is the proc that is called with
|
## compilation aborts with an error message. This is useful for writing
|
||||||
## the arguments ``args[0..]``.
|
## macros that check the AST that is passed to them.
|
||||||
result = newNimNode(nnkCall)
|
if n.kind != k: error("macro expects a node of kind: " & repr(k))
|
||||||
result.add(theProc)
|
|
||||||
result.add(args)
|
proc expectMinLen*(n: PNimrodNode, min: int) {.compileTime.} =
|
||||||
|
## checks that `n` has at least `min` children. If this is not the case,
|
||||||
proc newCall*(theProc: TNimrodIdent,
|
## compilation aborts with an error message. This is useful for writing
|
||||||
args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
|
## macros that check its number of arguments.
|
||||||
## produces a new call node. `theProc` is the proc that is called with
|
if n.len < min: error("macro expects a node with " & $min & " children")
|
||||||
## the arguments ``args[0..]``.
|
|
||||||
result = newNimNode(nnkCall)
|
proc expectLen*(n: PNimrodNode, len: int) {.compileTime.} =
|
||||||
result.add(newIdentNode(theProc))
|
## checks that `n` has exactly `len` children. If this is not the case,
|
||||||
result.add(args)
|
## compilation aborts with an error message. This is useful for writing
|
||||||
|
## macros that check its number of arguments.
|
||||||
proc newCall*(theProc: string,
|
if n.len != len: error("macro expects a node with " & $len & " children")
|
||||||
args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
|
|
||||||
## produces a new call node. `theProc` is the proc that is called with
|
proc newCall*(theProc: PNimrodNode,
|
||||||
## the arguments ``args[0..]``.
|
args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
|
||||||
result = newNimNode(nnkCall)
|
## produces a new call node. `theProc` is the proc that is called with
|
||||||
result.add(newIdentNode(theProc))
|
## the arguments ``args[0..]``.
|
||||||
result.add(args)
|
result = newNimNode(nnkCall)
|
||||||
|
result.add(theProc)
|
||||||
proc nestList*(theProc: TNimrodIdent,
|
result.add(args)
|
||||||
x: PNimrodNode): PNimrodNode {.compileTime.} =
|
|
||||||
## nests the list `x` into a tree of call expressions:
|
proc newCall*(theProc: TNimrodIdent,
|
||||||
## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``.
|
args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
|
||||||
var L = x.len
|
## produces a new call node. `theProc` is the proc that is called with
|
||||||
result = newCall(theProc, x[L-2], x[L-1])
|
## the arguments ``args[0..]``.
|
||||||
var a = result
|
result = newNimNode(nnkCall)
|
||||||
for i in countdown(L-3, 0):
|
result.add(newIdentNode(theProc))
|
||||||
a = newCall(theProc, x[i], copyNimTree(a))
|
result.add(args)
|
||||||
|
|
||||||
proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
|
proc newCall*(theProc: string,
|
||||||
## Convert the AST `n` to a human-readable tree-like string.
|
args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
|
||||||
##
|
## produces a new call node. `theProc` is the proc that is called with
|
||||||
## See also `repr` and `lispRepr`.
|
## the arguments ``args[0..]``.
|
||||||
proc traverse(res: var string, level: int, n: PNimrodNode) =
|
result = newNimNode(nnkCall)
|
||||||
for i in 0..level-1: res.add " "
|
result.add(newIdentNode(theProc))
|
||||||
res.add(($n.kind).substr(3))
|
result.add(args)
|
||||||
|
|
||||||
case n.kind
|
proc nestList*(theProc: TNimrodIdent,
|
||||||
of nnkEmpty: nil # same as nil node in this representation
|
x: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||||
of nnkNilLit: res.add(" nil")
|
## nests the list `x` into a tree of call expressions:
|
||||||
of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
|
## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``.
|
||||||
of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
|
var L = x.len
|
||||||
of nnkStrLit..nnkTripleStrLit: res.add(" " & $n.strVal)
|
result = newCall(theProc, x[L-2], x[L-1])
|
||||||
of nnkIdent: res.add(" !\"" & $n.ident & '"')
|
var a = result
|
||||||
|
for i in countdown(L-3, 0):
|
||||||
|
a = newCall(theProc, x[i], copyNimTree(a))
|
||||||
|
|
||||||
|
proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
|
||||||
|
## Convert the AST `n` to a human-readable tree-like string.
|
||||||
|
##
|
||||||
|
## See also `repr` and `lispRepr`.
|
||||||
|
proc traverse(res: var string, level: int, n: PNimrodNode) =
|
||||||
|
for i in 0..level-1: res.add " "
|
||||||
|
res.add(($n.kind).substr(3))
|
||||||
|
|
||||||
|
case n.kind
|
||||||
|
of nnkEmpty: nil # same as nil node in this representation
|
||||||
|
of nnkNilLit: res.add(" nil")
|
||||||
|
of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
|
||||||
|
of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
|
||||||
|
of nnkStrLit..nnkTripleStrLit: res.add(" " & $n.strVal)
|
||||||
|
of nnkIdent: res.add(" !\"" & $n.ident & '"')
|
||||||
of nnkSym: res.add(" \"" & $n.symbol & '"')
|
of nnkSym: res.add(" \"" & $n.symbol & '"')
|
||||||
of nnkNone: assert false
|
of nnkNone: assert false
|
||||||
else:
|
else:
|
||||||
for j in 0..n.len-1:
|
for j in 0..n.len-1:
|
||||||
res.add "\n"
|
res.add "\n"
|
||||||
traverse(res, level + 1, n[j])
|
traverse(res, level + 1, n[j])
|
||||||
|
|
||||||
result = ""
|
result = ""
|
||||||
traverse(result, 0, n)
|
traverse(result, 0, n)
|
||||||
|
|
||||||
proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
|
proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
|
||||||
## Convert the AST `n` to a human-readable lisp-like string,
|
## Convert the AST `n` to a human-readable lisp-like string,
|
||||||
##
|
##
|
||||||
## See also `repr` and `treeRepr`.
|
## See also `repr` and `treeRepr`.
|
||||||
|
|
||||||
result = ($n.kind).substr(3)
|
result = ($n.kind).substr(3)
|
||||||
add(result, "(")
|
add(result, "(")
|
||||||
|
|
||||||
case n.kind
|
case n.kind
|
||||||
of nnkEmpty: nil # same as nil node in this representation
|
of nnkEmpty: nil # same as nil node in this representation
|
||||||
of nnkNilLit: add(result, "nil")
|
of nnkNilLit: add(result, "nil")
|
||||||
of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
|
of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
|
||||||
of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
|
of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
|
||||||
of nnkStrLit..nnkTripleStrLit: add(result, $n.strVal)
|
of nnkStrLit..nnkTripleStrLit: add(result, $n.strVal)
|
||||||
of nnkIdent: add(result, "!\"" & $n.ident & '"')
|
of nnkIdent: add(result, "!\"" & $n.ident & '"')
|
||||||
of nnkSym, nnkNone: assert false
|
of nnkSym, nnkNone: assert false
|
||||||
else:
|
else:
|
||||||
add(result, lispRepr(n[0]))
|
add(result, lispRepr(n[0]))
|
||||||
for j in 1..n.len-1:
|
for j in 1..n.len-1:
|
||||||
add(result, ", ")
|
add(result, ", ")
|
||||||
add(result, lispRepr(n[j]))
|
add(result, lispRepr(n[j]))
|
||||||
|
|
||||||
add(result, ")")
|
add(result, ")")
|
||||||
|
|
||||||
macro dumpTree*(s: stmt): stmt = echo s.treeRepr
|
macro dumpTree*(s: stmt): stmt = echo s.treeRepr
|
||||||
## Accepts a block of nimrod code and prints the parsed abstract syntax
|
## Accepts a block of nimrod code and prints the parsed abstract syntax
|
||||||
## tree using the `toTree` function. Printing is done *at compile time*.
|
## tree using the `toTree` function. Printing is done *at compile time*.
|
||||||
##
|
##
|
||||||
## You can use this as a tool to explore the Nimrod's abstract syntax
|
## You can use this as a tool to explore the Nimrod's abstract syntax
|
||||||
## tree and to discover what kind of nodes must be created to represent
|
## tree and to discover what kind of nodes must be created to represent
|
||||||
## a certain expression/statement.
|
## a certain expression/statement.
|
||||||
|
|
||||||
macro dumpLisp*(s: stmt): stmt = echo s.lispRepr
|
macro dumpLisp*(s: stmt): stmt = echo s.lispRepr
|
||||||
## Accepts a block of nimrod code and prints the parsed abstract syntax
|
## Accepts a block of nimrod code and prints the parsed abstract syntax
|
||||||
## tree using the `toLisp` function. Printing is done *at compile time*.
|
## tree using the `toLisp` function. Printing is done *at compile time*.
|
||||||
##
|
##
|
||||||
## See `dumpTree`.
|
## See `dumpTree`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ else: # UNIX-like operating system
|
||||||
FileSystemCaseSensitive* = true
|
FileSystemCaseSensitive* = true
|
||||||
ExeExt* = ""
|
ExeExt* = ""
|
||||||
ScriptExt* = ""
|
ScriptExt* = ""
|
||||||
DynlibFormat* = "lib$1.so"
|
DynlibFormat* = when defined(macosx): "lib$1.dylib" else: "lib$1.so"
|
||||||
|
|
||||||
when defined(macosx) or defined(bsd):
|
when defined(macosx) or defined(bsd):
|
||||||
var
|
var
|
||||||
|
|
|
||||||
|
|
@ -51,10 +51,11 @@ type
|
||||||
`nil` {.magic: "Nil".}
|
`nil` {.magic: "Nil".}
|
||||||
expr* {.magic: Expr.} ## meta type to denote an expression (for templates)
|
expr* {.magic: Expr.} ## meta type to denote an expression (for templates)
|
||||||
stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates)
|
stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates)
|
||||||
typeDesc* {.magic: TypeDesc.} ## meta type to denote
|
typeDesc* {.magic: TypeDesc.} ## meta type to denote a type description
|
||||||
## a type description (for templates)
|
void* {.magic: "VoidType".} ## meta type to denote the absense of any type
|
||||||
void* {.magic: "VoidType".} ## meta type to denote the absense of any type
|
auto* = expr
|
||||||
|
any* = distinct auto
|
||||||
|
|
||||||
TSignedInt* = int|int8|int16|int32|int64
|
TSignedInt* = int|int8|int16|int32|int64
|
||||||
## type class matching all signed integer types
|
## type class matching all signed integer types
|
||||||
|
|
||||||
|
|
@ -111,6 +112,11 @@ proc new*[T](a: var ref T) {.magic: "New", noSideEffect.}
|
||||||
## creates a new object of type ``T`` and returns a safe (traced)
|
## creates a new object of type ``T`` and returns a safe (traced)
|
||||||
## reference to it in ``a``.
|
## reference to it in ``a``.
|
||||||
|
|
||||||
|
proc new(T: typedesc): ref T =
|
||||||
|
## creates a new object of type ``T`` and returns a safe (traced)
|
||||||
|
## reference to it as result value
|
||||||
|
new(result)
|
||||||
|
|
||||||
proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
|
proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
|
||||||
## leaked implementation detail. Do not use.
|
## leaked implementation detail. Do not use.
|
||||||
|
|
||||||
|
|
@ -538,7 +544,7 @@ proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.}
|
||||||
## checking is turned on).
|
## checking is turned on).
|
||||||
|
|
||||||
type
|
type
|
||||||
IntMax32 = distinct int|int8|int16|int32
|
IntMax32 = int|int8|int16|int32
|
||||||
|
|
||||||
proc `+%` *(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.}
|
proc `+%` *(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.}
|
||||||
proc `+%` *(x, y: Int64): Int64 {.magic: "AddU", noSideEffect.}
|
proc `+%` *(x, y: Int64): Int64 {.magic: "AddU", noSideEffect.}
|
||||||
|
|
@ -1315,11 +1321,10 @@ iterator items*(a: cstring): char {.inline.} =
|
||||||
yield a[i]
|
yield a[i]
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
when not defined(booting):
|
iterator items*(E: typedesc[enum]): E =
|
||||||
iterator items*(E: typedesc[enum]): E =
|
## iterates over the values of the enum ``E``.
|
||||||
## iterates over the values of the enum ``E``.
|
for v in low(E)..high(E):
|
||||||
for v in low(E)..high(E):
|
yield v
|
||||||
yield v
|
|
||||||
|
|
||||||
iterator pairs*[T](a: openarray[T]): tuple[key: int, val: T] {.inline.} =
|
iterator pairs*[T](a: openarray[T]): tuple[key: int, val: T] {.inline.} =
|
||||||
## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
|
## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
|
||||||
|
|
@ -2111,7 +2116,7 @@ proc `/`*(x, y: int): float {.inline, noSideEffect.} =
|
||||||
## integer division that results in a float.
|
## integer division that results in a float.
|
||||||
result = toFloat(x) / toFloat(y)
|
result = toFloat(x) / toFloat(y)
|
||||||
|
|
||||||
template `-|`(b, s: expr): expr =
|
template `-|`*(b, s: expr): expr =
|
||||||
(if b >= 0: b else: s.len + b)
|
(if b >= 0: b else: s.len + b)
|
||||||
|
|
||||||
proc `[]`*(s: string, x: TSlice[int]): string {.inline.} =
|
proc `[]`*(s: string, x: TSlice[int]): string {.inline.} =
|
||||||
|
|
|
||||||
42
tests/compile/tisop.nim
Normal file
42
tests/compile/tisop.nim
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
type
|
||||||
|
TRecord = (tuple) or (object)
|
||||||
|
|
||||||
|
TFoo[T, U] = object
|
||||||
|
x: int
|
||||||
|
|
||||||
|
when T is string:
|
||||||
|
y: float
|
||||||
|
else:
|
||||||
|
y: string
|
||||||
|
|
||||||
|
when U is TRecord:
|
||||||
|
z: float
|
||||||
|
|
||||||
|
E = enum A, B, C
|
||||||
|
|
||||||
|
macro m(t: typedesc): typedesc =
|
||||||
|
if t is enum:
|
||||||
|
result = string
|
||||||
|
else:
|
||||||
|
result = int
|
||||||
|
|
||||||
|
var f: TFoo[int, int]
|
||||||
|
static: assert(f.y.type.name == "string")
|
||||||
|
|
||||||
|
when compiles(f.z):
|
||||||
|
{.error: "Foo should not have a `z` field".}
|
||||||
|
|
||||||
|
proc p(a, b) =
|
||||||
|
when a.type is int:
|
||||||
|
static: assert false
|
||||||
|
|
||||||
|
var f: TFoo[m(a.type), b.type]
|
||||||
|
static:
|
||||||
|
assert f.x.type.name == "int"
|
||||||
|
assert f.y.type.name == "float"
|
||||||
|
assert f.z.type.name == "float"
|
||||||
|
|
||||||
|
p(A, f)
|
||||||
|
|
||||||
12
tests/compile/tmacrotypes.nim
Normal file
12
tests/compile/tmacrotypes.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import macros, typetraits
|
||||||
|
|
||||||
|
macro checkType(ex, expected: expr): stmt {.immediate.} =
|
||||||
|
var t = ex.typ
|
||||||
|
assert t.name == expected.strVal
|
||||||
|
|
||||||
|
proc voidProc = echo "hello"
|
||||||
|
proc intProc(a, b): int = 10
|
||||||
|
|
||||||
|
checkType(voidProc(), "void")
|
||||||
|
checkType(intProc(10, 20.0), "int")
|
||||||
|
checkType(noproc(10, 20.0), "Error Type")
|
||||||
|
|
@ -2,8 +2,8 @@ type
|
||||||
TFoo[T] = object
|
TFoo[T] = object
|
||||||
val: T
|
val: T
|
||||||
|
|
||||||
T1 = distinct expr
|
T1 = expr
|
||||||
T2 = distinct expr
|
T2 = expr
|
||||||
|
|
||||||
proc takesExpr(x, y) =
|
proc takesExpr(x, y) =
|
||||||
echo x, y
|
echo x, y
|
||||||
|
|
|
||||||
30
tests/reject/tcaseexpr1.nim
Normal file
30
tests/reject/tcaseexpr1.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
discard """
|
||||||
|
file: "tcaseexpr1.nim"
|
||||||
|
|
||||||
|
line: 29
|
||||||
|
errormsg: "type mismatch: got (string) but expected 'int'"
|
||||||
|
|
||||||
|
line: 23
|
||||||
|
errormsg: "not all cases are covered"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
E = enum A, B, C
|
||||||
|
|
||||||
|
proc foo(x): auto =
|
||||||
|
return case x
|
||||||
|
of 1..9: "digit"
|
||||||
|
else: "number"
|
||||||
|
|
||||||
|
var r = foo(10)
|
||||||
|
|
||||||
|
var x = C
|
||||||
|
|
||||||
|
var t1 = case x:
|
||||||
|
of A: "a"
|
||||||
|
of B: "b"
|
||||||
|
|
||||||
|
var t2 = case x:
|
||||||
|
of A: 10
|
||||||
|
of B, C: "23"
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
file: "system.nim"
|
file: "system.nim"
|
||||||
line: 643
|
line: 649
|
||||||
errormsg: "type mismatch"
|
errormsg: "type mismatch"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
file: "tcasestm.nim"
|
file: "tcasestm.nim"
|
||||||
output: "ayyy"
|
output: "ayyydd"
|
||||||
"""
|
"""
|
||||||
# Test the case statement
|
# Test the case statement
|
||||||
|
|
||||||
|
|
@ -22,16 +22,18 @@ of "aa", "bb": write(stdout, "Du bist nicht mein Meister")
|
||||||
of "cc", "hash", "when": nil
|
of "cc", "hash", "when": nil
|
||||||
of "will", "it", "finally", "be", "generated": nil
|
of "will", "it", "finally", "be", "generated": nil
|
||||||
|
|
||||||
case i
|
var z = case i
|
||||||
of 1..5, 8, 9: nil
|
of 1..5, 8, 9: "aa"
|
||||||
of 6, 7: nil
|
of 6, 7: "bb"
|
||||||
elif x == "Ha":
|
elif x == "Ha":
|
||||||
nil
|
"cc"
|
||||||
elif x == "yyy":
|
elif x == "yyy":
|
||||||
write(stdout, x)
|
write(stdout, x)
|
||||||
else:
|
"dd"
|
||||||
nil
|
else:
|
||||||
|
"zz"
|
||||||
|
|
||||||
|
echo z
|
||||||
#OUT ayyy
|
#OUT ayyy
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
33
tests/run/trettypeinference.nim
Normal file
33
tests/run/trettypeinference.nim
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
discard """
|
||||||
|
msg: "instantiated for string\ninstantiated for int\ninstantiated for bool"
|
||||||
|
output: "int\nseq[string]\nA\nB\n100\ntrue"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
proc plus(a, b): auto = a + b
|
||||||
|
proc makePair(a, b): auto = (first: a, second: b)
|
||||||
|
|
||||||
|
proc `+`(a, b: string): seq[string] = @[a, b]
|
||||||
|
|
||||||
|
var i = plus(10, 20)
|
||||||
|
var s = plus("A", "B")
|
||||||
|
|
||||||
|
var p = makePair("key", 100)
|
||||||
|
static: assert p[0].type is string
|
||||||
|
|
||||||
|
echo i.type.name
|
||||||
|
echo s.type.name
|
||||||
|
|
||||||
|
proc inst(a): auto =
|
||||||
|
static: echo "instantiated for ", a.type.name
|
||||||
|
result = a
|
||||||
|
|
||||||
|
echo inst("A")
|
||||||
|
echo inst("B")
|
||||||
|
echo inst(100)
|
||||||
|
echo inst(true)
|
||||||
|
|
||||||
|
# XXX: [string, tyGenericParam] is cached instead of [string, string]
|
||||||
|
# echo inst[string, string]("C")
|
||||||
|
|
||||||
33
web/news.txt
33
web/news.txt
|
|
@ -2,6 +2,39 @@
|
||||||
News
|
News
|
||||||
====
|
====
|
||||||
|
|
||||||
|
2012-XX-XX Version 0.9.XX released
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Version 0.8.XX has been released! Get it `here <download.html>`_.
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Library Additions
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Changes affecting backwards compatibility
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Compiler Additions
|
||||||
|
------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Language Additions
|
||||||
|
------------------
|
||||||
|
|
||||||
|
- ``case expressions`` are now supported.
|
||||||
|
- table constructors now mimic more closely the syntax of case... of...
|
||||||
|
- Nimrod can now infer the return type of a proc from its body
|
||||||
|
|
||||||
|
|
||||||
2012-09-23 Version 0.9.0 released
|
2012-09-23 Version 0.9.0 released
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue