Merge branch 'devel' of github.com:nim-lang/Nim into devel

This commit is contained in:
Andreas Rumpf 2018-09-11 16:41:34 +02:00
commit af94946517
32 changed files with 488 additions and 150 deletions

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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:

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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.} =

View file

@ -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)

View file

@ -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)

View file

@ -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".}

View file

@ -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.}

View file

@ -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
View 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
View 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)

View 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()

View file

@ -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
View 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
View 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
View 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
View file

@ -0,0 +1,12 @@
discard """
output: '''
@[42]
@[24, 42]
'''
"""
var x = @[42,4242]
x.delete(1)
echo x
x.insert(24)
echo x

View file

@ -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:

View file

@ -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 = "При"

View file

@ -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
View 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]]()