Merge branch 'devel' of github.com:nim-lang/Nim into devel
This commit is contained in:
commit
af94946517
32 changed files with 488 additions and 150 deletions
|
|
@ -678,7 +678,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||||
n[0] = ex
|
n[0] = ex
|
||||||
result.add(n)
|
result.add(n)
|
||||||
|
|
||||||
of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv:
|
||||||
var ns = false
|
var ns = false
|
||||||
for i in 0 ..< n.len:
|
for i in 0 ..< n.len:
|
||||||
n[i] = ctx.lowerStmtListExprs(n[i], ns)
|
n[i] = ctx.lowerStmtListExprs(n[i], ns)
|
||||||
|
|
@ -687,9 +687,9 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||||
needsSplit = true
|
needsSplit = true
|
||||||
result = newNodeI(nkStmtListExpr, n.info)
|
result = newNodeI(nkStmtListExpr, n.info)
|
||||||
result.typ = n.typ
|
result.typ = n.typ
|
||||||
let (st, ex) = exprToStmtList(n[1])
|
let (st, ex) = exprToStmtList(n[^1])
|
||||||
result.add(st)
|
result.add(st)
|
||||||
n[1] = ex
|
n[^1] = ex
|
||||||
result.add(n)
|
result.add(n)
|
||||||
|
|
||||||
of nkAsgn, nkFastAsgn:
|
of nkAsgn, nkFastAsgn:
|
||||||
|
|
@ -712,6 +712,25 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||||
|
|
||||||
result.add(n)
|
result.add(n)
|
||||||
|
|
||||||
|
of nkBracketExpr:
|
||||||
|
var lhsNeedsSplit = false
|
||||||
|
var rhsNeedsSplit = false
|
||||||
|
n[0] = ctx.lowerStmtListExprs(n[0], lhsNeedsSplit)
|
||||||
|
n[1] = ctx.lowerStmtListExprs(n[1], rhsNeedsSplit)
|
||||||
|
if lhsNeedsSplit or rhsNeedsSplit:
|
||||||
|
needsSplit = true
|
||||||
|
result = newNodeI(nkStmtListExpr, n.info)
|
||||||
|
if lhsNeedsSplit:
|
||||||
|
let (st, ex) = exprToStmtList(n[0])
|
||||||
|
result.add(st)
|
||||||
|
n[0] = ex
|
||||||
|
|
||||||
|
if rhsNeedsSplit:
|
||||||
|
let (st, ex) = exprToStmtList(n[1])
|
||||||
|
result.add(st)
|
||||||
|
n[1] = ex
|
||||||
|
result.add(n)
|
||||||
|
|
||||||
of nkWhileStmt:
|
of nkWhileStmt:
|
||||||
var ns = false
|
var ns = false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -658,15 +658,16 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
line(p, "}\L")
|
line(p, "}\L")
|
||||||
|
|
||||||
proc genRaiseStmt(p: PProc, n: PNode) =
|
proc genRaiseStmt(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
var a: TCompRes
|
var a: TCompRes
|
||||||
gen(p, n.sons[0], a)
|
gen(p, n.sons[0], a)
|
||||||
let typ = skipTypes(n.sons[0].typ, abstractPtrs)
|
let typ = skipTypes(n.sons[0].typ, abstractPtrs)
|
||||||
|
genLineDir(p, n)
|
||||||
useMagic(p, "raiseException")
|
useMagic(p, "raiseException")
|
||||||
lineF(p, "raiseException($1, $2);$n",
|
lineF(p, "raiseException($1, $2);$n",
|
||||||
[a.rdLoc, makeJSString(typ.sym.name.s)])
|
[a.rdLoc, makeJSString(typ.sym.name.s)])
|
||||||
else:
|
else:
|
||||||
|
genLineDir(p, n)
|
||||||
useMagic(p, "reraiseException")
|
useMagic(p, "reraiseException")
|
||||||
line(p, "reraiseException();\L")
|
line(p, "reraiseException();\L")
|
||||||
|
|
||||||
|
|
@ -764,11 +765,22 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
||||||
of nkSym:
|
of nkSym:
|
||||||
let v = it.sym
|
let v = it.sym
|
||||||
# for backwards compatibility we don't deref syms here :-(
|
# for backwards compatibility we don't deref syms here :-(
|
||||||
if v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
if false:
|
||||||
p.body.add mangleName(p.module, v)
|
discard
|
||||||
else:
|
else:
|
||||||
var r: TCompRes
|
var r: TCompRes
|
||||||
gen(p, it, r)
|
gen(p, it, r)
|
||||||
|
|
||||||
|
if it.typ.kind == tyPointer:
|
||||||
|
# A fat pointer is disguised as an array
|
||||||
|
r.res = r.address
|
||||||
|
r.address = nil
|
||||||
|
elif r.typ == etyBaseIndex:
|
||||||
|
# Deference first
|
||||||
|
r.res = "$1[$2]" % [r.address, r.res]
|
||||||
|
r.address = nil
|
||||||
|
r.typ = etyNone
|
||||||
|
|
||||||
p.body.add(r.rdLoc)
|
p.body.add(r.rdLoc)
|
||||||
else:
|
else:
|
||||||
var r: TCompRes
|
var r: TCompRes
|
||||||
|
|
@ -845,6 +857,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||||
else:
|
else:
|
||||||
gen(p, x, a)
|
gen(p, x, a)
|
||||||
|
|
||||||
|
genLineDir(p, y)
|
||||||
gen(p, y, b)
|
gen(p, y, b)
|
||||||
|
|
||||||
# we don't care if it's an etyBaseIndex (global) of a string, it's
|
# we don't care if it's an etyBaseIndex (global) of a string, it's
|
||||||
|
|
@ -881,11 +894,9 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||||
lineF(p, "$1 = $2;$n", [a.res, b.res])
|
lineF(p, "$1 = $2;$n", [a.res, b.res])
|
||||||
|
|
||||||
proc genAsgn(p: PProc, n: PNode) =
|
proc genAsgn(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
|
||||||
genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false)
|
genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false)
|
||||||
|
|
||||||
proc genFastAsgn(p: PProc, n: PNode) =
|
proc genFastAsgn(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
|
||||||
# 'shallowCopy' always produced 'noCopyNeeded = true' here but this is wrong
|
# 'shallowCopy' always produced 'noCopyNeeded = true' here but this is wrong
|
||||||
# for code like
|
# for code like
|
||||||
# while j >= pos:
|
# while j >= pos:
|
||||||
|
|
@ -1529,18 +1540,18 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar:
|
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar:
|
||||||
r.res.add("[$1].concat(" % [a.res])
|
r.res.add("[$1].concat(" % [a.res])
|
||||||
else:
|
else:
|
||||||
r.res.add("($1.slice(0,-1)).concat(" % [a.res])
|
r.res.add("($1).concat(" % [a.res])
|
||||||
|
|
||||||
for i in countup(2, sonsLen(n) - 2):
|
for i in countup(2, sonsLen(n) - 2):
|
||||||
gen(p, n.sons[i], a)
|
gen(p, n.sons[i], a)
|
||||||
if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
|
if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
|
||||||
r.res.add("[$1]," % [a.res])
|
r.res.add("[$1]," % [a.res])
|
||||||
else:
|
else:
|
||||||
r.res.add("$1.slice(0,-1)," % [a.res])
|
r.res.add("$1," % [a.res])
|
||||||
|
|
||||||
gen(p, n.sons[sonsLen(n) - 1], a)
|
gen(p, n.sons[sonsLen(n) - 1], a)
|
||||||
if skipTypes(n.sons[sonsLen(n) - 1].typ, abstractVarRange).kind == tyChar:
|
if skipTypes(n.sons[sonsLen(n) - 1].typ, abstractVarRange).kind == tyChar:
|
||||||
r.res.add("[$1, 0])" % [a.res])
|
r.res.add("[$1])" % [a.res])
|
||||||
else:
|
else:
|
||||||
r.res.add("$1)" % [a.res])
|
r.res.add("$1)" % [a.res])
|
||||||
|
|
||||||
|
|
@ -1647,13 +1658,13 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
|
else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
|
||||||
of mAppendStrCh:
|
of mAppendStrCh:
|
||||||
binaryExpr(p, n, r, "addChar",
|
binaryExpr(p, n, r, "addChar",
|
||||||
"if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
|
"if ($1 != null) { addChar($1, $2); } else { $1 = [$2]; }")
|
||||||
of mAppendStrStr:
|
of mAppendStrStr:
|
||||||
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
|
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
|
||||||
binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }")
|
binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }")
|
||||||
else:
|
else:
|
||||||
binaryExpr(p, n, r, "",
|
binaryExpr(p, n, r, "",
|
||||||
"if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
|
"if ($1 != null) { $1 = ($1).concat($2); } else { $1 = $2;}")
|
||||||
# XXX: make a copy of $2, because of Javascript's sucking semantics
|
# XXX: make a copy of $2, because of Javascript's sucking semantics
|
||||||
of mAppendSeqElem:
|
of mAppendSeqElem:
|
||||||
var x, y: TCompRes
|
var x, y: TCompRes
|
||||||
|
|
@ -1683,19 +1694,14 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do
|
of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do
|
||||||
of mOrd: genOrd(p, n, r)
|
of mOrd: genOrd(p, n, r)
|
||||||
of mLengthStr:
|
of mLengthStr:
|
||||||
if n.sons[1].typ.skipTypes(abstractInst).kind == tyCString:
|
|
||||||
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
|
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
|
||||||
else:
|
of mXLenStr:
|
||||||
unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)")
|
unaryExpr(p, n, r, "", "$1.length")
|
||||||
of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1")
|
|
||||||
of mLengthSeq, mLengthOpenArray, mLengthArray:
|
of mLengthSeq, mLengthOpenArray, mLengthArray:
|
||||||
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
|
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
|
||||||
of mXLenSeq:
|
of mXLenSeq:
|
||||||
unaryExpr(p, n, r, "", "$1.length")
|
unaryExpr(p, n, r, "", "$1.length")
|
||||||
of mHigh:
|
of mHigh:
|
||||||
if skipTypes(n.sons[1].typ, abstractVar).kind == tyString:
|
|
||||||
unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)")
|
|
||||||
else:
|
|
||||||
unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
|
unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
|
||||||
of mInc:
|
of mInc:
|
||||||
if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64:
|
if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64:
|
||||||
|
|
@ -1710,7 +1716,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
|
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
|
||||||
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
|
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
|
||||||
of mSetLengthStr:
|
of mSetLengthStr:
|
||||||
binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0")
|
binaryExpr(p, n, r, "", "$1.length = $2")
|
||||||
of mSetLengthSeq:
|
of mSetLengthSeq:
|
||||||
var x, y: TCompRes
|
var x, y: TCompRes
|
||||||
gen(p, n.sons[1], x)
|
gen(p, n.sons[1], x)
|
||||||
|
|
@ -1739,8 +1745,6 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
localError(p.config, n.info, errXMustBeCompileTime % n.sons[0].sym.name.s)
|
localError(p.config, n.info, errXMustBeCompileTime % n.sons[0].sym.name.s)
|
||||||
of mCopyStr:
|
of mCopyStr:
|
||||||
binaryExpr(p, n, r, "", "($1.slice($2))")
|
binaryExpr(p, n, r, "", "($1.slice($2))")
|
||||||
of mCopyStrLast:
|
|
||||||
ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
|
|
||||||
of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
|
of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
|
||||||
of mNewStringOfCap:
|
of mNewStringOfCap:
|
||||||
unaryExpr(p, n, r, "mnewString", "mnewString(0)")
|
unaryExpr(p, n, r, "mnewString", "mnewString(0)")
|
||||||
|
|
@ -2065,8 +2069,11 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
of nkStrLit..nkTripleStrLit:
|
of nkStrLit..nkTripleStrLit:
|
||||||
if skipTypes(n.typ, abstractVarRange).kind == tyString:
|
if skipTypes(n.typ, abstractVarRange).kind == tyString:
|
||||||
|
if n.strVal.len != 0:
|
||||||
useMagic(p, "makeNimstrLit")
|
useMagic(p, "makeNimstrLit")
|
||||||
r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)]
|
r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)]
|
||||||
|
else:
|
||||||
|
r.res = rope"[]"
|
||||||
else:
|
else:
|
||||||
r.res = makeJSString(n.strVal, false)
|
r.res = makeJSString(n.strVal, false)
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
|
||||||
|
|
@ -884,6 +884,42 @@ proc getOperator(L: var TLexer, tok: var TToken) =
|
||||||
if buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
|
if buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
|
||||||
tok.strongSpaceB = -1
|
tok.strongSpaceB = -1
|
||||||
|
|
||||||
|
proc getPrecedence*(tok: TToken, strongSpaces: bool): int =
|
||||||
|
## Calculates the precedence of the given token.
|
||||||
|
template considerStrongSpaces(x): untyped =
|
||||||
|
x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
|
||||||
|
|
||||||
|
case tok.tokType
|
||||||
|
of tkOpr:
|
||||||
|
let L = tok.ident.s.len
|
||||||
|
let relevantChar = tok.ident.s[0]
|
||||||
|
|
||||||
|
# arrow like?
|
||||||
|
if L > 1 and tok.ident.s[L-1] == '>' and
|
||||||
|
tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
|
||||||
|
|
||||||
|
template considerAsgn(value: untyped) =
|
||||||
|
result = if tok.ident.s[L-1] == '=': 1 else: value
|
||||||
|
|
||||||
|
case relevantChar
|
||||||
|
of '$', '^': considerAsgn(10)
|
||||||
|
of '*', '%', '/', '\\': considerAsgn(9)
|
||||||
|
of '~': result = 8
|
||||||
|
of '+', '-', '|': considerAsgn(8)
|
||||||
|
of '&': considerAsgn(7)
|
||||||
|
of '=', '<', '>', '!': result = 5
|
||||||
|
of '.': considerAsgn(6)
|
||||||
|
of '?': result = 2
|
||||||
|
else: considerAsgn(2)
|
||||||
|
of tkDiv, tkMod, tkShl, tkShr: result = 9
|
||||||
|
of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
|
||||||
|
of tkDotDot: result = 6
|
||||||
|
of tkAnd: result = 4
|
||||||
|
of tkOr, tkXor, tkPtr, tkRef: result = 3
|
||||||
|
else: return -10
|
||||||
|
result = considerStrongSpaces(result)
|
||||||
|
|
||||||
|
|
||||||
proc newlineFollows*(L: TLexer): bool =
|
proc newlineFollows*(L: TLexer): bool =
|
||||||
var pos = L.bufpos
|
var pos = L.bufpos
|
||||||
var buf = L.buf
|
var buf = L.buf
|
||||||
|
|
@ -1249,3 +1285,14 @@ proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
|
||||||
result = tok.indent
|
result = tok.indent
|
||||||
if result > 0 or tok.tokType == tkEof: break
|
if result > 0 or tok.tokType == tkEof: break
|
||||||
closeLexer(lex)
|
closeLexer(lex)
|
||||||
|
|
||||||
|
proc getPrecedence*(ident: PIdent): int =
|
||||||
|
## assumes ident is binary operator already
|
||||||
|
var tok: TToken
|
||||||
|
initToken(tok)
|
||||||
|
tok.ident = ident
|
||||||
|
tok.tokType =
|
||||||
|
if tok.ident.id in ord(tokKeywordLow) - ord(tkSymbol) .. ord(tokKeywordHigh) - ord(tkSymbol):
|
||||||
|
TTokType(tok.ident.id + ord(tkSymbol))
|
||||||
|
else: tkOpr
|
||||||
|
getPrecedence(tok, false)
|
||||||
|
|
|
||||||
|
|
@ -87,9 +87,9 @@ proc endsWithOpr*(x: string): bool =
|
||||||
result = x.endsWith(LineContinuationOprs)
|
result = x.endsWith(LineContinuationOprs)
|
||||||
|
|
||||||
proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
|
proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
|
||||||
result = inTripleString or
|
result = inTripleString or line.len > 0 and (
|
||||||
line[0] == ' ' or
|
line[0] == ' ' or
|
||||||
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs)
|
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs))
|
||||||
|
|
||||||
proc countTriples(s: string): int =
|
proc countTriples(s: string): int =
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
|
||||||
|
|
@ -252,41 +252,6 @@ proc isRightAssociative(tok: TToken): bool {.inline.} =
|
||||||
result = tok.tokType == tkOpr and tok.ident.s[0] == '^'
|
result = tok.tokType == tkOpr and tok.ident.s[0] == '^'
|
||||||
# or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
|
# or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
|
||||||
|
|
||||||
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
|
|
||||||
## Calculates the precedence of the given token.
|
|
||||||
template considerStrongSpaces(x): untyped =
|
|
||||||
x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
|
|
||||||
|
|
||||||
case tok.tokType
|
|
||||||
of tkOpr:
|
|
||||||
let L = tok.ident.s.len
|
|
||||||
let relevantChar = tok.ident.s[0]
|
|
||||||
|
|
||||||
# arrow like?
|
|
||||||
if L > 1 and tok.ident.s[L-1] == '>' and
|
|
||||||
tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
|
|
||||||
|
|
||||||
template considerAsgn(value: untyped) =
|
|
||||||
result = if tok.ident.s[L-1] == '=': 1 else: value
|
|
||||||
|
|
||||||
case relevantChar
|
|
||||||
of '$', '^': considerAsgn(10)
|
|
||||||
of '*', '%', '/', '\\': considerAsgn(9)
|
|
||||||
of '~': result = 8
|
|
||||||
of '+', '-', '|': considerAsgn(8)
|
|
||||||
of '&': considerAsgn(7)
|
|
||||||
of '=', '<', '>', '!': result = 5
|
|
||||||
of '.': considerAsgn(6)
|
|
||||||
of '?': result = 2
|
|
||||||
else: considerAsgn(2)
|
|
||||||
of tkDiv, tkMod, tkShl, tkShr: result = 9
|
|
||||||
of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
|
|
||||||
of tkDotDot: result = 6
|
|
||||||
of tkAnd: result = 4
|
|
||||||
of tkOr, tkXor, tkPtr, tkRef: result = 3
|
|
||||||
else: return -10
|
|
||||||
result = considerStrongSpaces(result)
|
|
||||||
|
|
||||||
proc isOperator(tok: TToken): bool =
|
proc isOperator(tok: TToken): bool =
|
||||||
## Determines if the given token is an operator type token.
|
## Determines if the given token is an operator type token.
|
||||||
tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
|
tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ const
|
||||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||||
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
||||||
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
||||||
wRaises, wLocks, wTags, wGcSafe}
|
wRaises, wLocks, wTags, wGcSafe, wCodegenDecl}
|
||||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||||
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wExtern, wShallow,
|
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wExtern, wShallow,
|
||||||
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
||||||
|
|
|
||||||
|
|
@ -307,14 +307,19 @@ proc lsub(g: TSrcGen; n: PNode): int
|
||||||
proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
|
proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
|
||||||
proc skip(t: PType): PType =
|
proc skip(t: PType): PType =
|
||||||
result = t
|
result = t
|
||||||
while result.kind in {tyGenericInst, tyRange, tyVar, tyLent, tyDistinct,
|
while result != nil and result.kind in {tyGenericInst, tyRange, tyVar, tyLent, tyDistinct,
|
||||||
tyOrdinal, tyAlias, tySink}:
|
tyOrdinal, tyAlias, tySink}:
|
||||||
result = lastSon(result)
|
result = lastSon(result)
|
||||||
if n.typ != nil and n.typ.skip.kind in {tyBool, tyEnum}:
|
let typ = n.typ.skip
|
||||||
let enumfields = n.typ.skip.n
|
if typ != nil and typ.kind in {tyBool, tyEnum}:
|
||||||
|
if sfPure in typ.sym.flags:
|
||||||
|
result = typ.sym.name.s & '.'
|
||||||
|
let enumfields = typ.n
|
||||||
# we need a slow linear search because of enums with holes:
|
# we need a slow linear search because of enums with holes:
|
||||||
for e in items(enumfields):
|
for e in items(enumfields):
|
||||||
if e.sym.position == x: return e.sym.name.s
|
if e.sym.position == x:
|
||||||
|
result &= e.sym.name.s
|
||||||
|
return
|
||||||
|
|
||||||
if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
|
if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
|
||||||
elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
|
elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
|
||||||
|
|
@ -861,6 +866,47 @@ proc isBracket*(n: PNode): bool =
|
||||||
of nkSym: result = n.sym.name.s == "[]"
|
of nkSym: result = n.sym.name.s == "[]"
|
||||||
else: result = false
|
else: result = false
|
||||||
|
|
||||||
|
proc skipHiddenNodes(n: PNode): PNode =
|
||||||
|
result = n
|
||||||
|
while result != nil:
|
||||||
|
if result.kind in {nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv} and result.len > 1:
|
||||||
|
result = result[1]
|
||||||
|
elif result.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString} and
|
||||||
|
result.len > 0:
|
||||||
|
result = result[0]
|
||||||
|
else: break
|
||||||
|
|
||||||
|
proc accentedName(g: var TSrcGen, n: PNode) =
|
||||||
|
if n == nil: return
|
||||||
|
let isOperator =
|
||||||
|
if n.kind == nkIdent and n.ident.s.len > 0 and n.ident.s[0] in OpChars: true
|
||||||
|
elif n.kind == nkSym and n.sym.name.s.len > 0 and n.sym.name.s[0] in OpChars: true
|
||||||
|
else: false
|
||||||
|
|
||||||
|
if isOperator:
|
||||||
|
put(g, tkAccent, "`")
|
||||||
|
gident(g, n)
|
||||||
|
put(g, tkAccent, "`")
|
||||||
|
else:
|
||||||
|
gsub(g, n)
|
||||||
|
|
||||||
|
proc infixArgument(g: var TSrcGen, n: PNode, i: int) =
|
||||||
|
if i >= n.len: return
|
||||||
|
|
||||||
|
var needsParenthesis = false
|
||||||
|
let n_next = n[i].skipHiddenNodes
|
||||||
|
if n_next.kind == nkInfix:
|
||||||
|
if n_next[0].kind in {nkSym, nkIdent} and n[0].kind in {nkSym, nkIdent}:
|
||||||
|
let nextId = if n_next[0].kind == nkSym: n_next[0].sym.name else: n_next[0].ident
|
||||||
|
let nnId = if n[0].kind == nkSym: n[0].sym.name else: n[0].ident
|
||||||
|
if getPrecedence(nextId) < getPrecedence(nnId):
|
||||||
|
needsParenthesis = true
|
||||||
|
if needsParenthesis:
|
||||||
|
put(g, tkParLe, "(")
|
||||||
|
gsub(g, n, i)
|
||||||
|
if needsParenthesis:
|
||||||
|
put(g, tkParRi, ")")
|
||||||
|
|
||||||
proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
if isNil(n): return
|
if isNil(n): return
|
||||||
var
|
var
|
||||||
|
|
@ -896,7 +942,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
gcomma(g, n, 2)
|
gcomma(g, n, 2)
|
||||||
put(g, tkBracketRi, "]")
|
put(g, tkBracketRi, "]")
|
||||||
elif n.len > 1 and n.lastSon.kind == nkStmtList:
|
elif n.len > 1 and n.lastSon.kind == nkStmtList:
|
||||||
gsub(g, n[0])
|
accentedName(g, n[0])
|
||||||
if n.len > 2:
|
if n.len > 2:
|
||||||
put(g, tkParLe, "(")
|
put(g, tkParLe, "(")
|
||||||
gcomma(g, n, 1, -2)
|
gcomma(g, n, 1, -2)
|
||||||
|
|
@ -904,16 +950,16 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
put(g, tkColon, ":")
|
put(g, tkColon, ":")
|
||||||
gsub(g, n, n.len-1)
|
gsub(g, n, n.len-1)
|
||||||
else:
|
else:
|
||||||
if sonsLen(n) >= 1: gsub(g, n.sons[0])
|
if sonsLen(n) >= 1: accentedName(g, n[0])
|
||||||
put(g, tkParLe, "(")
|
put(g, tkParLe, "(")
|
||||||
gcomma(g, n, 1)
|
gcomma(g, n, 1)
|
||||||
put(g, tkParRi, ")")
|
put(g, tkParRi, ")")
|
||||||
of nkCallStrLit:
|
of nkCallStrLit:
|
||||||
gsub(g, n, 0)
|
if n.len > 0: accentedName(g, n[0])
|
||||||
if n.len > 1 and n.sons[1].kind == nkRStrLit:
|
if n.len > 1 and n.sons[1].kind == nkRStrLit:
|
||||||
put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
|
put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
|
||||||
else:
|
else:
|
||||||
gsub(g, n.sons[1])
|
gsub(g, n, 1)
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv:
|
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv:
|
||||||
if n.len >= 2:
|
if n.len >= 2:
|
||||||
gsub(g, n.sons[1])
|
gsub(g, n.sons[1])
|
||||||
|
|
@ -951,7 +997,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
gsub(g, n, 0)
|
gsub(g, n, 0)
|
||||||
gcomma(g, n, 1)
|
gcomma(g, n, 1)
|
||||||
of nkCommand:
|
of nkCommand:
|
||||||
gsub(g, n, 0)
|
accentedName(g, n[0])
|
||||||
put(g, tkSpaces, Space)
|
put(g, tkSpaces, Space)
|
||||||
gcomma(g, n, 1)
|
gcomma(g, n, 1)
|
||||||
of nkExprEqExpr, nkAsgn, nkFastAsgn:
|
of nkExprEqExpr, nkAsgn, nkFastAsgn:
|
||||||
|
|
@ -1064,14 +1110,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
putWithSpace(g, tkColon, ":")
|
putWithSpace(g, tkColon, ":")
|
||||||
gsub(g, n, 1)
|
gsub(g, n, 1)
|
||||||
of nkInfix:
|
of nkInfix:
|
||||||
gsub(g, n, 1)
|
infixArgument(g, n, 1)
|
||||||
put(g, tkSpaces, Space)
|
put(g, tkSpaces, Space)
|
||||||
gsub(g, n, 0) # binary operator
|
gsub(g, n, 0) # binary operator
|
||||||
if not fits(g, lsub(g, n.sons[2]) + lsub(g, n.sons[0]) + 1):
|
if not fits(g, lsub(g, n.sons[2]) + lsub(g, n.sons[0]) + 1):
|
||||||
optNL(g, g.indent + longIndentWid)
|
optNL(g, g.indent + longIndentWid)
|
||||||
else:
|
else:
|
||||||
put(g, tkSpaces, Space)
|
put(g, tkSpaces, Space)
|
||||||
gsub(g, n, 2)
|
infixArgument(g, n, 2)
|
||||||
of nkPrefix:
|
of nkPrefix:
|
||||||
gsub(g, n, 0)
|
gsub(g, n, 0)
|
||||||
if n.len > 1:
|
if n.len > 1:
|
||||||
|
|
@ -1079,10 +1125,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
elif n[0].kind == nkSym: n[0].sym.name
|
elif n[0].kind == nkSym: n[0].sym.name
|
||||||
elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name
|
elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name
|
||||||
else: nil
|
else: nil
|
||||||
var n_next = n[1]
|
let n_next = skipHiddenNodes(n[1])
|
||||||
while n_next.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref,
|
|
||||||
nkStringToCString, nkCStringToString} and n_next.len > 0:
|
|
||||||
n_next = n_next[0]
|
|
||||||
if n_next.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
|
if n_next.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
|
||||||
put(g, tkSpaces, Space)
|
put(g, tkSpaces, Space)
|
||||||
if n_next.kind == nkInfix:
|
if n_next.kind == nkInfix:
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
|
||||||
if castDest.kind notin IntegralTypes+{tyRange}:
|
if castDest.kind notin IntegralTypes+{tyRange}:
|
||||||
result = convNotNeedeed
|
result = convNotNeedeed
|
||||||
return
|
return
|
||||||
|
# Save for later
|
||||||
var d = skipTypes(castDest, abstractVar)
|
var d = skipTypes(castDest, abstractVar)
|
||||||
var s = src
|
var s = src
|
||||||
if s.kind in tyUserTypeClasses and s.isResolvedUserTypeClass:
|
if s.kind in tyUserTypeClasses and s.isResolvedUserTypeClass:
|
||||||
|
|
@ -135,7 +136,7 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
|
||||||
# we use d, s here to speed up that operation a bit:
|
# we use d, s here to speed up that operation a bit:
|
||||||
case cmpTypes(c, d, s)
|
case cmpTypes(c, d, s)
|
||||||
of isNone, isGeneric:
|
of isNone, isGeneric:
|
||||||
if not compareTypes(castDest, src, dcEqIgnoreDistinct):
|
if not compareTypes(castDest.skipTypes(abstractVar), src, dcEqIgnoreDistinct):
|
||||||
result = convNotLegal
|
result = convNotLegal
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,24 @@ proc evalIs(n: PNode, lhs: PSym, g: ModuleGraph): PNode =
|
||||||
result = newIntNode(nkIntLit, ord(res))
|
result = newIntNode(nkIntLit, ord(res))
|
||||||
result.typ = n.typ
|
result.typ = n.typ
|
||||||
|
|
||||||
|
proc fitLiteral(c: ConfigRef, n: PNode): PNode =
|
||||||
|
# Trim the literal value in order to make it fit in the destination type
|
||||||
|
if n == nil:
|
||||||
|
# `n` may be nil if the overflow check kicks in
|
||||||
|
return
|
||||||
|
|
||||||
|
doAssert n.kind in {nkIntLit, nkCharLit}
|
||||||
|
|
||||||
|
result = n
|
||||||
|
|
||||||
|
let typ = n.typ.skipTypes(abstractRange)
|
||||||
|
if typ.kind in tyUInt..tyUint32:
|
||||||
|
result.intVal = result.intVal and lastOrd(c, typ, fixedUnsigned=true)
|
||||||
|
|
||||||
proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||||
|
template doAndFit(op: untyped): untyped =
|
||||||
|
# Implements wrap-around behaviour for unsigned types
|
||||||
|
fitLiteral(g.config, op)
|
||||||
# b and c may be nil
|
# b and c may be nil
|
||||||
result = nil
|
result = nil
|
||||||
case m
|
case m
|
||||||
|
|
@ -224,12 +241,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||||
of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g)
|
of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g)
|
||||||
of mNot: result = newIntNodeT(1 - getInt(a), n, g)
|
of mNot: result = newIntNodeT(1 - getInt(a), n, g)
|
||||||
of mCard: result = newIntNodeT(nimsets.cardSet(g.config, a), n, g)
|
of mCard: result = newIntNodeT(nimsets.cardSet(g.config, a), n, g)
|
||||||
of mBitnotI:
|
of mBitnotI: result = doAndFit(newIntNodeT(not getInt(a), n, g))
|
||||||
case skipTypes(n.typ, abstractRange).kind
|
|
||||||
of tyUInt..tyUInt64:
|
|
||||||
result = newIntNodeT((not getInt(a)) and lastOrd(g.config, a.typ, fixedUnsigned=true), n, g)
|
|
||||||
else:
|
|
||||||
result = newIntNodeT(not getInt(a), n, g)
|
|
||||||
of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g)
|
of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g)
|
||||||
of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
|
of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
|
||||||
if a.kind == nkNilLit:
|
if a.kind == nkNilLit:
|
||||||
|
|
@ -251,9 +263,9 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||||
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g)
|
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g)
|
||||||
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g)
|
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g)
|
||||||
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g)
|
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g)
|
||||||
of mUnaryLt: result = foldSub(getOrdValue(a), 1, n, g)
|
of mUnaryLt: result = doAndFit(foldSub(getOrdValue(a), 1, n, g))
|
||||||
of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g)
|
of mSucc: result = doAndFit(foldAdd(getOrdValue(a), getInt(b), n, g))
|
||||||
of mPred: result = foldSub(getOrdValue(a), getInt(b), n, g)
|
of mPred: result = doAndFit(foldSub(getOrdValue(a), getInt(b), n, g))
|
||||||
of mAddI: result = foldAdd(getInt(a), getInt(b), n, g)
|
of mAddI: result = foldAdd(getInt(a), getInt(b), n, g)
|
||||||
of mSubI: result = foldSub(getInt(a), getInt(b), n, g)
|
of mSubI: result = foldSub(getInt(a), getInt(b), n, g)
|
||||||
of mMulI: result = foldMul(getInt(a), getInt(b), n, g)
|
of mMulI: result = foldMul(getInt(a), getInt(b), n, g)
|
||||||
|
|
@ -271,7 +283,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||||
of tyInt64, tyInt:
|
of tyInt64, tyInt:
|
||||||
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)
|
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)
|
||||||
of tyUInt..tyUInt64:
|
of tyUInt..tyUInt64:
|
||||||
result = newIntNodeT(`shl`(getInt(a), getInt(b)) and lastOrd(g.config, a.typ, fixedUnsigned=true), n, g)
|
result = doAndFit(newIntNodeT(`shl`(getInt(a), getInt(b)), n, g))
|
||||||
else: internalError(g.config, n.info, "constant folding for shl")
|
else: internalError(g.config, n.info, "constant folding for shl")
|
||||||
of mShrI:
|
of mShrI:
|
||||||
case skipTypes(n.typ, abstractRange).kind
|
case skipTypes(n.typ, abstractRange).kind
|
||||||
|
|
@ -324,14 +336,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||||
result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g)
|
result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g)
|
||||||
of mLeU, mLeU64:
|
of mLeU, mLeU64:
|
||||||
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g)
|
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g)
|
||||||
of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n, g)
|
of mBitandI, mAnd: result = doAndFit(newIntNodeT(a.getInt and b.getInt, n, g))
|
||||||
of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n, g)
|
of mBitorI, mOr: result = doAndFit(newIntNodeT(getInt(a) or getInt(b), n, g))
|
||||||
of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n, g)
|
of mBitxorI, mXor: result = doAndFit(newIntNodeT(a.getInt xor b.getInt, n, g))
|
||||||
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n, g)
|
of mAddU: result = doAndFit(newIntNodeT(`+%`(getInt(a), getInt(b)), n, g))
|
||||||
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n, g)
|
of mSubU: result = doAndFit(newIntNodeT(`-%`(getInt(a), getInt(b)), n, g))
|
||||||
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n, g)
|
of mMulU: result = doAndFit(newIntNodeT(`*%`(getInt(a), getInt(b)), n, g))
|
||||||
of mModU: result = foldModU(getInt(a), getInt(b), n, g)
|
of mModU: result = doAndFit(foldModU(getInt(a), getInt(b), n, g))
|
||||||
of mDivU: result = foldDivU(getInt(a), getInt(b), n, g)
|
of mDivU: result = doAndFit(foldDivU(getInt(a), getInt(b), n, g))
|
||||||
of mLeSet: result = newIntNodeT(ord(containsSets(g.config, a, b)), n, g)
|
of mLeSet: result = newIntNodeT(ord(containsSets(g.config, a, b)), n, g)
|
||||||
of mEqSet: result = newIntNodeT(ord(equalSets(g.config, a, b)), n, g)
|
of mEqSet: result = newIntNodeT(ord(equalSets(g.config, a, b)), n, g)
|
||||||
of mLtSet:
|
of mLtSet:
|
||||||
|
|
@ -462,17 +474,24 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
|
||||||
result = newIntNodeT(int(getFloat(a)), n, g)
|
result = newIntNodeT(int(getFloat(a)), n, g)
|
||||||
of tyChar:
|
of tyChar:
|
||||||
result = newIntNodeT(getOrdValue(a), n, g)
|
result = newIntNodeT(getOrdValue(a), n, g)
|
||||||
of tyUInt8..tyUInt32, tyInt8..tyInt32:
|
of tyUInt..tyUInt64, tyInt..tyInt64:
|
||||||
let fromSigned = srcTyp.kind in tyInt..tyInt64
|
|
||||||
let toSigned = dstTyp.kind in tyInt..tyInt64
|
let toSigned = dstTyp.kind in tyInt..tyInt64
|
||||||
|
var val = a.getOrdValue
|
||||||
|
|
||||||
let mask = lastOrd(g.config, dstTyp, fixedUnsigned=true)
|
if dstTyp.kind in {tyInt, tyInt64, tyUint, tyUInt64}:
|
||||||
|
# No narrowing needed
|
||||||
var val =
|
discard
|
||||||
if toSigned:
|
elif dstTyp.kind in {tyInt..tyInt64}:
|
||||||
a.getOrdValue mod mask
|
# Signed type: Overflow check (if requested) and conversion
|
||||||
|
if check: rangeCheck(n, val, g)
|
||||||
|
let mask = (`shl`(1, getSize(g.config, dstTyp) * 8) - 1)
|
||||||
|
let valSign = val < 0
|
||||||
|
val = abs(val) and mask
|
||||||
|
if valSign: val = -val
|
||||||
else:
|
else:
|
||||||
a.getOrdValue and mask
|
# Unsigned type: Conversion
|
||||||
|
let mask = (`shl`(1, getSize(g.config, dstTyp) * 8) - 1)
|
||||||
|
val = val and mask
|
||||||
|
|
||||||
result = newIntNodeT(val, n, g)
|
result = newIntNodeT(val, n, g)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -624,7 +624,11 @@ proc transformCase(c: PTransf, n: PNode): PTransNode =
|
||||||
case it.kind
|
case it.kind
|
||||||
of nkElifBranch:
|
of nkElifBranch:
|
||||||
if ifs.PNode == nil:
|
if ifs.PNode == nil:
|
||||||
ifs = newTransNode(nkIfStmt, it.info, 0)
|
# Generate the right node depending on whether `n` is used as a stmt or
|
||||||
|
# as an expr
|
||||||
|
let kind = if n.typ != nil: nkIfExpr else: nkIfStmt
|
||||||
|
ifs = newTransNode(kind, it.info, 0)
|
||||||
|
ifs.PNode.typ = n.typ
|
||||||
ifs.add(e)
|
ifs.add(e)
|
||||||
of nkElse:
|
of nkElse:
|
||||||
if ifs.PNode == nil: result.add(e)
|
if ifs.PNode == nil: result.add(e)
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,10 @@ proc isFutureVoid(node: NimNode): bool =
|
||||||
node[1].kind == nnkIdent and $node[1] == "void"
|
node[1].kind == nnkIdent and $node[1] == "void"
|
||||||
|
|
||||||
proc generateJsasync(arg: NimNode): NimNode =
|
proc generateJsasync(arg: NimNode): NimNode =
|
||||||
assert arg.kind == nnkProcDef
|
if arg.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
|
||||||
|
error("Cannot transform this node kind into an async proc." &
|
||||||
|
" proc/method definition or lambda node expected.")
|
||||||
|
|
||||||
result = arg
|
result = arg
|
||||||
var isVoid = false
|
var isVoid = false
|
||||||
let jsResolve = ident("jsResolve")
|
let jsResolve = ident("jsResolve")
|
||||||
|
|
@ -108,7 +111,7 @@ proc generateJsasync(arg: NimNode): NimNode =
|
||||||
|
|
||||||
if len(code) > 0:
|
if len(code) > 0:
|
||||||
var awaitFunction = quote:
|
var awaitFunction = quote:
|
||||||
proc await[T](f: Future[T]): T {.importcpp: "(await #)".}
|
proc await[T](f: Future[T]): T {.importcpp: "(await #)", used.}
|
||||||
result.body.add(awaitFunction)
|
result.body.add(awaitFunction)
|
||||||
|
|
||||||
var resolve: NimNode
|
var resolve: NimNode
|
||||||
|
|
@ -117,7 +120,7 @@ proc generateJsasync(arg: NimNode): NimNode =
|
||||||
var `jsResolve` {.importcpp: "undefined".}: Future[void]
|
var `jsResolve` {.importcpp: "undefined".}: Future[void]
|
||||||
else:
|
else:
|
||||||
resolve = quote:
|
resolve = quote:
|
||||||
proc jsResolve[T](a: T): Future[T] {.importcpp: "#".}
|
proc jsResolve[T](a: T): Future[T] {.importcpp: "#", used.}
|
||||||
result.body.add(resolve)
|
result.body.add(resolve)
|
||||||
else:
|
else:
|
||||||
result.body = newEmptyNode()
|
result.body = newEmptyNode()
|
||||||
|
|
@ -137,7 +140,12 @@ proc generateJsasync(arg: NimNode): NimNode =
|
||||||
macro async*(arg: untyped): untyped =
|
macro async*(arg: untyped): untyped =
|
||||||
## Macro which converts normal procedures into
|
## Macro which converts normal procedures into
|
||||||
## javascript-compatible async procedures
|
## javascript-compatible async procedures
|
||||||
generateJsasync(arg)
|
if arg.kind == nnkStmtList:
|
||||||
|
result = newStmtList()
|
||||||
|
for oneProc in arg:
|
||||||
|
result.add generateJsasync(oneProc)
|
||||||
|
else:
|
||||||
|
result = generateJsasync(arg)
|
||||||
|
|
||||||
proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".}
|
proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".}
|
||||||
## A helper for wrapping callback-based functions
|
## A helper for wrapping callback-based functions
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,8 @@ __clang__
|
||||||
# define N_INLINE(rettype, name) rettype __inline name
|
# define N_INLINE(rettype, name) rettype __inline name
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define N_INLINE_PTR(rettype, name) rettype (*name)
|
||||||
|
|
||||||
#if defined(__POCC__)
|
#if defined(__POCC__)
|
||||||
# define NIM_CONST /* PCC is really picky with const modifiers */
|
# define NIM_CONST /* PCC is really picky with const modifiers */
|
||||||
# undef _MSC_VER /* Yeah, right PCC defines _MSC_VER even if it is
|
# undef _MSC_VER /* Yeah, right PCC defines _MSC_VER even if it is
|
||||||
|
|
|
||||||
|
|
@ -1536,7 +1536,11 @@ proc withTimeout*[T](fut: Future[T], timeout: int): Future[bool] =
|
||||||
var timeoutFuture = sleepAsync(timeout)
|
var timeoutFuture = sleepAsync(timeout)
|
||||||
fut.callback =
|
fut.callback =
|
||||||
proc () =
|
proc () =
|
||||||
if not retFuture.finished: retFuture.complete(true)
|
if not retFuture.finished:
|
||||||
|
if fut.failed:
|
||||||
|
retFuture.fail(fut.error)
|
||||||
|
else:
|
||||||
|
retFuture.complete(true)
|
||||||
timeoutFuture.callback =
|
timeoutFuture.callback =
|
||||||
proc () =
|
proc () =
|
||||||
if not retFuture.finished: retFuture.complete(false)
|
if not retFuture.finished: retFuture.complete(false)
|
||||||
|
|
|
||||||
|
|
@ -327,8 +327,8 @@ macro async*(prc: untyped): untyped =
|
||||||
## Macro which processes async procedures into the appropriate
|
## Macro which processes async procedures into the appropriate
|
||||||
## iterators and yield statements.
|
## iterators and yield statements.
|
||||||
if prc.kind == nnkStmtList:
|
if prc.kind == nnkStmtList:
|
||||||
for oneProc in prc:
|
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
|
for oneProc in prc:
|
||||||
result.add asyncSingleProc(oneProc)
|
result.add asyncSingleProc(oneProc)
|
||||||
else:
|
else:
|
||||||
result = asyncSingleProc(prc)
|
result = asyncSingleProc(prc)
|
||||||
|
|
|
||||||
|
|
@ -328,7 +328,6 @@ proc `$`*(ms: MemSlice): string {.inline.} =
|
||||||
## Return a Nim string built from a MemSlice.
|
## Return a Nim string built from a MemSlice.
|
||||||
var buf = newString(ms.size)
|
var buf = newString(ms.size)
|
||||||
copyMem(addr(buf[0]), ms.data, ms.size)
|
copyMem(addr(buf[0]), ms.data, ms.size)
|
||||||
buf[ms.size] = '\0'
|
|
||||||
result = buf
|
result = buf
|
||||||
|
|
||||||
iterator memSlices*(mfile: MemFile, delim='\l', eat='\r'): MemSlice {.inline.} =
|
iterator memSlices*(mfile: MemFile, delim='\l', eat='\r'): MemSlice {.inline.} =
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
##[
|
##[
|
||||||
This module contains a `scanf`:idx: macro that can be used for extracting
|
This module contains a `scanf`:idx: macro that can be used for extracting
|
||||||
substrings from an input string. This is often easier than regular expressions.
|
substrings from an input string. This is often easier than regular expressions.
|
||||||
Some examples as an apetizer:
|
Some examples as an appetizer:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
# check if input string matches a triple of integers:
|
# check if input string matches a triple of integers:
|
||||||
|
|
@ -308,7 +308,7 @@ proc buildUserCall(x: string; args: varargs[NimNode]): NimNode =
|
||||||
for i in 1..<y.len: result.add y[i]
|
for i in 1..<y.len: result.add y[i]
|
||||||
|
|
||||||
macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): bool =
|
macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): bool =
|
||||||
## See top level documentation of his module of how ``scanf`` works.
|
## See top level documentation of this module about how ``scanf`` works.
|
||||||
template matchBind(parser) {.dirty.} =
|
template matchBind(parser) {.dirty.} =
|
||||||
var resLen = genSym(nskLet, "resLen")
|
var resLen = genSym(nskLet, "resLen")
|
||||||
conds.add newLetStmt(resLen, newCall(bindSym(parser), inp, results[i], idx))
|
conds.add newLetStmt(resLen, newCall(bindSym(parser), inp, results[i], idx))
|
||||||
|
|
@ -469,7 +469,7 @@ template success*(x: int): bool = x != 0
|
||||||
template nxt*(input: string; idx, step: int = 1) = inc(idx, step)
|
template nxt*(input: string; idx, step: int = 1) = inc(idx, step)
|
||||||
|
|
||||||
macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
|
macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
|
||||||
## See top level documentation of his module of how ``scanf`` works.
|
## See top level documentation of this module about how ``scanp`` works.
|
||||||
type StmtTriple = tuple[init, cond, action: NimNode]
|
type StmtTriple = tuple[init, cond, action: NimNode]
|
||||||
|
|
||||||
template interf(x): untyped = bindSym(x, brForceOpen)
|
template interf(x): untyped = bindSym(x, brForceOpen)
|
||||||
|
|
|
||||||
|
|
@ -820,7 +820,7 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
|
||||||
# handle negative overflow
|
# handle negative overflow
|
||||||
if n == 0 and x < 0: n = -1
|
if n == 0 and x < 0: n = -1
|
||||||
|
|
||||||
proc toHex*[T](x: T): string =
|
proc toHex*[T: SomeInteger](x: T): string =
|
||||||
## Shortcut for ``toHex(x, T.sizeOf * 2)``
|
## Shortcut for ``toHex(x, T.sizeOf * 2)``
|
||||||
toHex(BiggestInt(x), T.sizeOf * 2)
|
toHex(BiggestInt(x), T.sizeOf * 2)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1552,7 +1552,7 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
|
||||||
defaultImpl()
|
defaultImpl()
|
||||||
else:
|
else:
|
||||||
when defined(js):
|
when defined(js):
|
||||||
{.emit: "`x`[`x`_Idx].splice(`i`, 1);".}
|
{.emit: "`x`.splice(`i`, 1);".}
|
||||||
else:
|
else:
|
||||||
defaultImpl()
|
defaultImpl()
|
||||||
|
|
||||||
|
|
@ -1574,7 +1574,7 @@ proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
|
||||||
else:
|
else:
|
||||||
when defined(js):
|
when defined(js):
|
||||||
var it : T
|
var it : T
|
||||||
{.emit: "`x`[`x`_Idx].splice(`i`, 0, `it`);".}
|
{.emit: "`x`.splice(`i`, 0, `it`);".}
|
||||||
else:
|
else:
|
||||||
defaultImpl()
|
defaultImpl()
|
||||||
x[i] = item
|
x[i] = item
|
||||||
|
|
@ -2741,12 +2741,11 @@ type
|
||||||
when defined(JS):
|
when defined(JS):
|
||||||
proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
|
proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
|
||||||
asm """
|
asm """
|
||||||
var len = `x`[0].length-1;
|
var len = `x`.length;
|
||||||
for (var i = 0; i < `y`.length; ++i) {
|
for (var i = 0; i < `y`.length; ++i) {
|
||||||
`x`[0][len] = `y`.charCodeAt(i);
|
`x`[len] = `y`.charCodeAt(i);
|
||||||
++len;
|
++len;
|
||||||
}
|
}
|
||||||
`x`[0][len] = 0
|
|
||||||
"""
|
"""
|
||||||
proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".}
|
proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -182,12 +182,10 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
|
||||||
proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
|
proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
|
||||||
{.emit: """
|
{.emit: """
|
||||||
var ln = `c`.length;
|
var ln = `c`.length;
|
||||||
var result = new Array(ln + 1);
|
var result = new Array(ln);
|
||||||
var i = 0;
|
for (var i = 0; i < ln; ++i) {
|
||||||
for (; i < ln; ++i) {
|
|
||||||
result[i] = `c`.charCodeAt(i);
|
result[i] = `c`.charCodeAt(i);
|
||||||
}
|
}
|
||||||
result[i] = 0; // terminating zero
|
|
||||||
return result;
|
return result;
|
||||||
""".}
|
""".}
|
||||||
|
|
||||||
|
|
@ -225,13 +223,12 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
|
||||||
}
|
}
|
||||||
++r;
|
++r;
|
||||||
}
|
}
|
||||||
result[r] = 0; // terminating zero
|
|
||||||
return result;
|
return result;
|
||||||
""".}
|
""".}
|
||||||
|
|
||||||
proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
|
proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
|
||||||
asm """
|
asm """
|
||||||
var len = `s`.length-1;
|
var len = `s`.length;
|
||||||
var asciiPart = new Array(len);
|
var asciiPart = new Array(len);
|
||||||
var fcc = String.fromCharCode;
|
var fcc = String.fromCharCode;
|
||||||
var nonAsciiPart = null;
|
var nonAsciiPart = null;
|
||||||
|
|
@ -262,10 +259,7 @@ proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
|
||||||
|
|
||||||
proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
|
proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
|
||||||
asm """
|
asm """
|
||||||
var result = new Array(`len`+1);
|
return new Array(`len`);
|
||||||
result[0] = 0;
|
|
||||||
result[`len`] = 0;
|
|
||||||
return result;
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
|
proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
|
||||||
|
|
@ -323,7 +317,7 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} =
|
||||||
if (`a` == `b`) return 0;
|
if (`a` == `b`) return 0;
|
||||||
if (!`a`) return -1;
|
if (!`a`) return -1;
|
||||||
if (!`b`) return 1;
|
if (!`b`) return 1;
|
||||||
for (var i = 0; i < `a`.length - 1 && i < `b`.length - 1; i++) {
|
for (var i = 0; i < `a`.length && i < `b`.length; i++) {
|
||||||
var result = `a`[i] - `b`[i];
|
var result = `a`[i] - `b`[i];
|
||||||
if (result != 0) return result;
|
if (result != 0) return result;
|
||||||
}
|
}
|
||||||
|
|
@ -651,9 +645,7 @@ proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} =
|
proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} =
|
||||||
asm """
|
asm "`x`.push(`c`);"
|
||||||
`x`[`x`.length-1] = `c`; `x`.push(0);
|
|
||||||
"""
|
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ B0
|
||||||
B1
|
B1
|
||||||
B2
|
B2
|
||||||
B3
|
B3
|
||||||
|
B4
|
||||||
|
B5
|
||||||
|
B6
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -14,6 +17,14 @@ template crossCheck(ty: untyped, exp: untyped) =
|
||||||
echo "Got ", ct
|
echo "Got ", ct
|
||||||
echo "Expected ", rt
|
echo "Expected ", rt
|
||||||
|
|
||||||
|
template add1(x: uint8): untyped = x + 1
|
||||||
|
template add1(x: uint16): untyped = x + 1
|
||||||
|
template add1(x: uint32): untyped = x + 1
|
||||||
|
|
||||||
|
template sub1(x: uint8): untyped = x - 1
|
||||||
|
template sub1(x: uint16): untyped = x - 1
|
||||||
|
template sub1(x: uint32): untyped = x - 1
|
||||||
|
|
||||||
block:
|
block:
|
||||||
when true:
|
when true:
|
||||||
echo "B0"
|
echo "B0"
|
||||||
|
|
@ -34,10 +45,34 @@ block:
|
||||||
crossCheck(uint64, (-1).uint64 + 5'u64)
|
crossCheck(uint64, (-1).uint64 + 5'u64)
|
||||||
|
|
||||||
echo "B3"
|
echo "B3"
|
||||||
crossCheck(int8, 0'u8 - 5'u8)
|
doAssert $sub1(0'u8) == "255"
|
||||||
crossCheck(int16, 0'u16 - 5'u16)
|
doAssert $sub1(0'u16) == "65535"
|
||||||
crossCheck(int32, 0'u32 - 5'u32)
|
doAssert $sub1(0'u32) == "4294967295"
|
||||||
crossCheck(int64, 0'u64 - 5'u64)
|
|
||||||
|
echo "B4"
|
||||||
|
doAssert $add1(255'u8) == "0"
|
||||||
|
doAssert $add1(65535'u16) == "0"
|
||||||
|
doAssert $add1(4294967295'u32) == "0"
|
||||||
|
|
||||||
|
echo "B5"
|
||||||
|
crossCheck(int32, high(int32))
|
||||||
|
crossCheck(int32, high(int32).int32)
|
||||||
|
crossCheck(int32, low(int32))
|
||||||
|
crossCheck(int32, low(int32).int32)
|
||||||
|
crossCheck(int64, high(int8).int16.int32.int64)
|
||||||
|
crossCheck(int64, low(int8).int16.int32.int64)
|
||||||
|
|
||||||
|
echo "B6"
|
||||||
|
crossCheck(int64, 0xFFFFFFFFFFFFFFFF'u64)
|
||||||
|
crossCheck(int32, 0xFFFFFFFFFFFFFFFF'u64)
|
||||||
|
crossCheck(int16, 0xFFFFFFFFFFFFFFFF'u64)
|
||||||
|
crossCheck(int8 , 0xFFFFFFFFFFFFFFFF'u64)
|
||||||
|
|
||||||
|
# Out of range conversion, caught for `let`s only
|
||||||
|
# crossCheck(int8, 0'u8 - 5'u8)
|
||||||
|
# crossCheck(int16, 0'u16 - 5'u16)
|
||||||
|
# crossCheck(int32, 0'u32 - 5'u32)
|
||||||
|
# crossCheck(int64, 0'u64 - 5'u64)
|
||||||
|
|
||||||
# crossCheck(int8, 0'u16 - 129'u16)
|
# crossCheck(int8, 0'u16 - 129'u16)
|
||||||
# crossCheck(uint8, 0'i16 + 257'i16)
|
# crossCheck(uint8, 0'i16 + 257'i16)
|
||||||
|
|
|
||||||
10
tests/ccgbugs/t5345.nim
Normal file
10
tests/ccgbugs/t5345.nim
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
discard """
|
||||||
|
output: true
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc cmpx(d: int): bool {.inline.} = d > 0
|
||||||
|
|
||||||
|
proc abc[C](cx: C, d: int) =
|
||||||
|
echo cx(d)
|
||||||
|
|
||||||
|
abc(cmpx, 10)
|
||||||
17
tests/ccgbugs/t5701.nim
Normal file
17
tests/ccgbugs/t5701.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
discard """
|
||||||
|
output: '''(Field0: 1, Field1: 1)
|
||||||
|
(Field0: 2, Field1: 2)
|
||||||
|
(Field0: 3, Field1: 3)
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
iterator zip[T1, T2](a: openarray[T1], b: openarray[T2]): iterator() {.inline.} =
|
||||||
|
let len = min(a.len, b.len)
|
||||||
|
for i in 0..<len:
|
||||||
|
echo (a[i], b[i])
|
||||||
|
|
||||||
|
proc foo(args: varargs[int]) =
|
||||||
|
for i in zip(args,args):
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo(1,2,3)
|
||||||
13
tests/ccgbugs/tcodegendecllambda.nim
Normal file
13
tests/ccgbugs/tcodegendecllambda.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
discard """
|
||||||
|
targets: "c cpp js"
|
||||||
|
ccodecheck: "'HELLO'"
|
||||||
|
"""
|
||||||
|
|
||||||
|
when defined(JS):
|
||||||
|
var foo = proc(): void{.codegenDecl: "/*HELLO*/function $2($3)".} =
|
||||||
|
echo "baa"
|
||||||
|
else:
|
||||||
|
var foo = proc(): void{.codegenDecl: "/*HELLO*/$1 $2 $3".} =
|
||||||
|
echo "baa"
|
||||||
|
|
||||||
|
foo()
|
||||||
|
|
@ -403,5 +403,41 @@ block: # yield in blockexpr
|
||||||
|
|
||||||
test(it, 1, 2, 3)
|
test(it, 1, 2, 3)
|
||||||
|
|
||||||
|
block: #8851
|
||||||
|
type
|
||||||
|
Foo = ref object of RootObj
|
||||||
|
template someFoo(): Foo =
|
||||||
|
var f: Foo
|
||||||
|
yield 1
|
||||||
|
f
|
||||||
|
iterator it(): int {.closure.} =
|
||||||
|
var o: RootRef
|
||||||
|
o = someFoo()
|
||||||
|
|
||||||
|
test(it, 1)
|
||||||
|
|
||||||
|
block: # 8243
|
||||||
|
iterator it(): int {.closure.} =
|
||||||
|
template yieldAndSeq: seq[int] =
|
||||||
|
yield 1
|
||||||
|
@[123, 5, 123]
|
||||||
|
|
||||||
|
checkpoint(yieldAndSeq[1])
|
||||||
|
|
||||||
|
test(it, 1, 5)
|
||||||
|
|
||||||
|
block:
|
||||||
|
iterator it(): int {.closure.} =
|
||||||
|
template yieldAndSeq: seq[int] =
|
||||||
|
yield 1
|
||||||
|
@[123, 5, 123]
|
||||||
|
|
||||||
|
template yieldAndNum: int =
|
||||||
|
yield 2
|
||||||
|
1
|
||||||
|
|
||||||
|
checkpoint(yieldAndSeq[yieldAndNum])
|
||||||
|
|
||||||
|
test(it, 1, 2, 5)
|
||||||
|
|
||||||
echo "ok"
|
echo "ok"
|
||||||
|
|
|
||||||
26
tests/js/t7224.nim
Normal file
26
tests/js/t7224.nim
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
discard """
|
||||||
|
cmd: "nim $target $options --stackTrace:on --lineTrace:on $file"
|
||||||
|
outputsub: '''
|
||||||
|
t7224.aaa, line: 21
|
||||||
|
t7224.bbb, line: 18
|
||||||
|
t7224.ccc, line: 15
|
||||||
|
t7224.ddd, line: 12
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc ddd() =
|
||||||
|
raise newException(IOError, "didn't do stuff")
|
||||||
|
|
||||||
|
proc ccc() =
|
||||||
|
ddd()
|
||||||
|
|
||||||
|
proc bbb() =
|
||||||
|
ccc()
|
||||||
|
|
||||||
|
proc aaa() =
|
||||||
|
bbb()
|
||||||
|
|
||||||
|
try:
|
||||||
|
aaa()
|
||||||
|
except IOError as e:
|
||||||
|
echo getStackTrace(e)
|
||||||
21
tests/js/t7249.nim
Normal file
21
tests/js/t7249.nim
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
a -> 2
|
||||||
|
a <- 2
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import jsffi
|
||||||
|
|
||||||
|
var a = JsAssoc[cstring, int]{a: 2}
|
||||||
|
|
||||||
|
for z, b in a:
|
||||||
|
echo z, " -> ", b
|
||||||
|
|
||||||
|
proc f =
|
||||||
|
var a = JsAssoc[cstring, int]{a: 2}
|
||||||
|
|
||||||
|
for z, b in a:
|
||||||
|
echo z, " <- ", b
|
||||||
|
|
||||||
|
f()
|
||||||
7
tests/js/t7534.nim
Normal file
7
tests/js/t7534.nim
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
proc f(x: int): int =
|
||||||
|
result = case x
|
||||||
|
of 1: 2
|
||||||
|
elif x == 2: 3
|
||||||
|
else: 1
|
||||||
|
|
||||||
|
doAssert 2 == f(f(f(f(1))))
|
||||||
12
tests/js/t8914.nim
Normal file
12
tests/js/t8914.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
@[42]
|
||||||
|
@[24, 42]
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
var x = @[42,4242]
|
||||||
|
x.delete(1)
|
||||||
|
echo x
|
||||||
|
x.insert(24)
|
||||||
|
echo x
|
||||||
|
|
@ -27,10 +27,10 @@ block:
|
||||||
var global = T(a: 11, b: "foo")
|
var global = T(a: 11, b: "foo")
|
||||||
proc test(): bool =
|
proc test(): bool =
|
||||||
var obj = T(a: 11, b: "foo")
|
var obj = T(a: 11, b: "foo")
|
||||||
{. emit: [result, " = (", obj.addr[], "[0].a == 11);"] .}
|
{. emit: [result, " = (", obj.addr[], ".a == 11);"] .}
|
||||||
{. emit: [result, " = ", result, " && (", obj.addr[], "[0].b == \"foo\");"] .}
|
{. emit: [result, " = ", result, " && (", obj.addr[], ".b == \"foo\");"] .}
|
||||||
{. emit: [result, " = ", result, " && (", global, "[0].a == 11);"] .}
|
{. emit: [result, " = ", result, " && (", global, ".a == 11);"] .}
|
||||||
{. emit: [result, " = ", result, " && (", global, "[0].b == \"foo\");"] .}
|
{. emit: [result, " = ", result, " && (", global, ".b == \"foo\");"] .}
|
||||||
echo test()
|
echo test()
|
||||||
|
|
||||||
# Test addr of field:
|
# Test addr of field:
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ block: # Test compile-time binary data generation, invalid unicode
|
||||||
block: # Test unicode strings
|
block: # Test unicode strings
|
||||||
const constStr = "Привет!"
|
const constStr = "Привет!"
|
||||||
var jsStr : cstring
|
var jsStr : cstring
|
||||||
{.emit: """`jsStr`[0] = "Привет!";""".}
|
{.emit: """`jsStr` = "Привет!";""".}
|
||||||
|
|
||||||
doAssert($jsStr == constStr)
|
doAssert($jsStr == constStr)
|
||||||
var runtimeStr = "При"
|
var runtimeStr = "При"
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@ macro repr_and_parse(fn: typed): typed =
|
||||||
echo fn_impl.repr
|
echo fn_impl.repr
|
||||||
result = parseStmt(fn_impl.repr)
|
result = parseStmt(fn_impl.repr)
|
||||||
|
|
||||||
|
macro repr_to_string(fn: typed): string =
|
||||||
|
let fn_impl = fn.getImpl
|
||||||
|
result = newStrLitNode(fn_impl.repr)
|
||||||
|
|
||||||
repr_and_parse(f)
|
repr_and_parse(f)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -70,8 +74,49 @@ proc test_cond_stmtlist(x, y: int): int =
|
||||||
result = x
|
result = x
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------
|
||||||
|
# bug #8762
|
||||||
|
proc t2(a, b: int): int =
|
||||||
|
`+`(a, b)
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------
|
||||||
|
# bug #8761
|
||||||
|
|
||||||
|
proc fn1(x, y: int):int =
|
||||||
|
2 * (x + y)
|
||||||
|
|
||||||
|
proc fn2(x, y: float): float =
|
||||||
|
(y + 2 * x) / (x - y)
|
||||||
|
|
||||||
|
proc fn3(x, y: int): bool =
|
||||||
|
(((x and 3) div 4) or (x mod (y xor -1))) == 0 or y notin [1,2]
|
||||||
|
|
||||||
|
static:
|
||||||
|
let fn1s = "proc fn1(x, y: int): int =\n result = 2 * (x + y)\n"
|
||||||
|
let fn2s = "proc fn2(x, y: float): float =\n result = (y + 2.0 * x) / (x - y)\n"
|
||||||
|
let fn3s = "proc fn3(x, y: int): bool =\n result = ((x and 3) div 4 or x mod (y xor -1)) == 0 or not contains([1, 2], y)\n"
|
||||||
|
doAssert fn1.repr_to_string == fn1s
|
||||||
|
doAssert fn2.repr_to_string == fn2s
|
||||||
|
doAssert fn3.repr_to_string == fn3s
|
||||||
|
|
||||||
|
#------------------------------------
|
||||||
|
# bug #8763
|
||||||
|
|
||||||
|
type
|
||||||
|
A {.pure.} = enum
|
||||||
|
X, Y
|
||||||
|
B {.pure.} = enum
|
||||||
|
X, Y
|
||||||
|
|
||||||
|
proc test_pure_enums(a: B) =
|
||||||
|
case a
|
||||||
|
of B.X: echo B.X
|
||||||
|
of B.Y: echo B.Y
|
||||||
|
|
||||||
repr_and_parse(one_if_proc)
|
repr_and_parse(one_if_proc)
|
||||||
repr_and_parse(test_block)
|
repr_and_parse(test_block)
|
||||||
repr_and_parse(test_cond_stmtlist)
|
repr_and_parse(test_cond_stmtlist)
|
||||||
|
repr_and_parse(t2)
|
||||||
|
repr_and_parse(test_pure_enums)
|
||||||
|
|
||||||
|
|
|
||||||
7
tests/typerel/t8905.nim
Normal file
7
tests/typerel/t8905.nim
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
type
|
||||||
|
Foo[T] = distinct seq[T]
|
||||||
|
Bar[T] = object
|
||||||
|
|
||||||
|
proc newFoo[T](): Foo[T] = Foo[T](newSeq[T]())
|
||||||
|
|
||||||
|
var x = newFoo[Bar[int]]()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue