Merge branch 'devel' into vm_float_casts

This commit is contained in:
Andrii Riabushenko
2018-10-24 22:16:25 +01:00
23 changed files with 251 additions and 53 deletions

0
bin/nim-gdb Normal file → Executable file
View File

View File

@@ -27,6 +27,9 @@
- Added `or` for `NimNode` in `macros`.
- Added `system.typeof` for more control over how `type` expressions
can be deduced.
### Library changes

View File

@@ -400,6 +400,16 @@ proc genGotoForCase(p: BProc; caseStmt: PNode) =
genStmts(p, it.lastSon)
endBlock(p)
iterator fieldValuePairs(n: PNode): tuple[memberSym, valueSym: PNode] =
assert(n.kind in {nkLetSection, nkVarSection})
for identDefs in n:
if identDefs.kind == nkIdentDefs:
let valueSym = identDefs[^1]
for i in 0 ..< identDefs.len-2:
let memberSym = identDefs[i]
yield((memberSym: memberSym, valueSym: valueSym))
proc genComputedGoto(p: BProc; n: PNode) =
# first pass: Generate array of computed labels:
var casePos = -1
@@ -429,22 +439,12 @@ proc genComputedGoto(p: BProc; n: PNode) =
let tmp = "TMP$1_" % [id.rope]
var gotoArray = "static void* $#[$#] = {" % [tmp, arraySize.rope]
for i in 1..arraySize-1:
gotoArray.addf("&&TMP$#_, ", [(id+i).rope])
gotoArray.addf("&&TMP$#_};$n", [(id+arraySize).rope])
gotoArray.addf("&&TMP$#_, ", [rope(id+i)])
gotoArray.addf("&&TMP$#_};$n", [rope(id+arraySize)])
line(p, cpsLocals, gotoArray)
let topBlock = p.blocks.len-1
let oldBody = p.blocks[topBlock].sections[cpsStmts]
p.blocks[topBlock].sections[cpsStmts] = nil
for j in casePos+1 ..< n.len: genStmts(p, n.sons[j])
let tailB = p.blocks[topBlock].sections[cpsStmts]
p.blocks[topBlock].sections[cpsStmts] = nil
for j in 0 .. casePos-1: genStmts(p, n.sons[j])
let tailA = p.blocks[topBlock].sections[cpsStmts]
p.blocks[topBlock].sections[cpsStmts] = oldBody & tailA
for j in 0 ..< casePos:
genStmts(p, n.sons[j])
let caseStmt = n.sons[casePos]
var a: TLoc
@@ -459,19 +459,40 @@ proc genComputedGoto(p: BProc; n: PNode) =
if it.sons[j].kind == nkRange:
localError(p.config, it.info, "range notation not available for computed goto")
return
let val = getOrdValue(it.sons[j])
lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(val+id+1)])
genStmts(p, it.lastSon)
#for j in casePos+1 ..< n.len: genStmts(p, n.sons[j]) # tailB
#for j in 0 .. casePos-1: genStmts(p, n.sons[j]) # tailA
add(p.s(cpsStmts), tailB)
add(p.s(cpsStmts), tailA)
for j in casePos+1 ..< n.sons.len:
genStmts(p, n.sons[j])
for j in 0 ..< casePos:
# prevent new local declarations
# compile declarations as assignments
let it = n.sons[j]
if it.kind in {nkLetSection, nkVarSection}:
let asgn = copyNode(it)
asgn.kind = nkAsgn
asgn.sons.setLen 2
for sym, value in it.fieldValuePairs:
if value.kind != nkEmpty:
asgn.sons[0] = sym
asgn.sons[1] = value
genStmts(p, asgn)
else:
genStmts(p, it)
var a: TLoc
initLocExpr(p, caseStmt.sons[0], a)
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
endBlock(p)
for j in casePos+1 ..< n.sons.len:
genStmts(p, n.sons[j])
proc genWhileStmt(p: BProc, t: PNode) =
# we don't generate labels here as for example GCC would produce
# significantly worse code
@@ -482,26 +503,26 @@ proc genWhileStmt(p: BProc, t: PNode) =
genLineDir(p, t)
preserveBreakIdx:
p.breakIdx = startBlock(p, "while (1) {$n")
p.blocks[p.breakIdx].isLoop = true
initLocExpr(p, t.sons[0], a)
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
let label = assignLabel(p.blocks[p.breakIdx])
lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
var loopBody = t.sons[1]
if loopBody.stmtsContainPragma(wComputedGoto) and
hasComputedGoto in CC[p.config.cCompiler].props:
# for closure support weird loop bodies are generated:
hasComputedGoto in CC[p.config.cCompiler].props:
# for closure support weird loop bodies are generated:
if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
loopBody = loopBody.sons[1]
genComputedGoto(p, loopBody)
genComputedGoto(p, loopBody) # TODO foobar
else:
p.breakIdx = startBlock(p, "while (1) {$n")
p.blocks[p.breakIdx].isLoop = true
initLocExpr(p, t.sons[0], a)
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
let label = assignLabel(p.blocks[p.breakIdx])
lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
genStmts(p, loopBody)
if optProfiler in p.options:
# invoke at loop body exit:
linefmt(p, cpsStmts, "#nimProfile();$n")
endBlock(p)
if optProfiler in p.options:
# invoke at loop body exit:
linefmt(p, cpsStmts, "#nimProfile();$n")
endBlock(p)
dec(p.withinLoop)

View File

@@ -84,6 +84,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimNoNilSeqs2")
defineSymbol("nimHasUserErrors")
defineSymbol("nimUncheckedArrayTyp")
defineSymbol("nimHasTypeof")
defineSymbol("nimHasNilSeqs")
for f in low(Feature)..high(Feature):

View File

@@ -268,9 +268,6 @@ proc patchHead(n: PNode) =
if sfFromGeneric in s.flags:
excl(s.flags, sfFromGeneric)
patchHead(s.getBody)
if n[1].typ.isNil:
# XXX toptree crashes without this workaround. Figure out why.
return
let t = n[1].typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink, tyInferred})
template patch(op, field) =
if s.name.s == op and field != nil and field != s:
@@ -296,6 +293,10 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
m.add c.graph.config $ c.otherRead.info
localError(c.graph.config, ri.info, errGenerated, m)
proc makePtrType(c: Con, baseType: PType): PType =
result = newType(tyPtr, c.owner)
addSonSkipIntLit(result, baseType)
template genOp(opr, opname, ri) =
let op = opr
if op == nil:
@@ -304,7 +305,9 @@ template genOp(opr, opname, ri) =
globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator is generic")
patchHead op
if sfError in op.flags: checkForErrorPragma(c, t, ri, opname)
result = newTree(nkCall, newSymNode(op), newTree(nkHiddenAddr, dest))
let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
addrExp.add(dest)
result = newTree(nkCall, newSymNode(op), addrExp)
proc genSink(c: Con; t: PType; dest, ri: PNode): PNode =
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})

View File

@@ -1118,6 +1118,7 @@ proc skip(L: var TLexer, tok: var TToken) =
tok.strongSpaceA = 0
when defined(nimpretty):
var hasComment = false
var commentIndent = L.currLineIndent
tok.commentOffsetA = L.offsetBase + pos
tok.commentOffsetB = tok.commentOffsetA
tok.line = -1
@@ -1139,13 +1140,18 @@ proc skip(L: var TLexer, tok: var TToken) =
inc(pos)
inc(indent)
elif buf[pos] == '#' and buf[pos+1] == '[':
when defined(nimpretty): hasComment = true
when defined(nimpretty):
hasComment = true
if tok.line < 0:
tok.line = L.lineNumber
skipMultiLineComment(L, tok, pos+2, false)
pos = L.bufpos
buf = L.buf
else:
break
tok.strongSpaceA = 0
when defined(nimpretty):
if buf[pos] == '#' and tok.line < 0: commentIndent = indent
if buf[pos] > ' ' and (buf[pos] != '#' or buf[pos+1] == '#'):
tok.indent = indent
L.currLineIndent = indent
@@ -1155,7 +1161,8 @@ proc skip(L: var TLexer, tok: var TToken) =
if buf[pos+1] == '#': break
when defined(nimpretty):
hasComment = true
if tok.line < 0: tok.line = L.lineNumber
if tok.line < 0:
tok.line = L.lineNumber
if buf[pos+1] == '[':
skipMultiLineComment(L, tok, pos+2, false)
@@ -1177,6 +1184,7 @@ proc skip(L: var TLexer, tok: var TToken) =
if hasComment:
tok.commentOffsetB = L.offsetBase + pos - 1
tok.tokType = tkComment
tok.indent = commentIndent
if gIndentationWidth <= 0:
gIndentationWidth = tok.indent

View File

@@ -1414,6 +1414,20 @@ proc semTypeof(c: PContext; n: PNode; prev: PType): PType =
fixupTypeOf(c, prev, t)
result = t.typ
proc semTypeof2(c: PContext; n: PNode; prev: PType): PType =
openScope(c)
var m = BiggestInt 1 # typeOfIter
if n.len == 3:
let mode = semConstExpr(c, n[2])
if mode.kind != nkIntLit:
localError(c.config, n.info, "typeof: cannot evaluate 'mode' parameter at compile-time")
else:
m = mode.intVal
let t = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
closeScope(c)
fixupTypeOf(c, prev, t)
result = t.typ
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil
inc c.inTypeContext
@@ -1494,6 +1508,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
elif op.id == ord(wType):
checkSonsLen(n, 2, c.config)
result = semTypeof(c, n[1], prev)
elif op.s == "typeof" and n[0].kind == nkSym and n[0].sym.magic == mTypeof:
result = semTypeOf2(c, n, prev)
else:
if c.inGenericContext > 0 and n.kind == nkCall:
result = makeTypeFromExpr(c, n.copyTree)

View File

@@ -73,6 +73,19 @@ path="$lib/pure"
opt:speed
@end
@if unix and mingw:
# Cross compile for Windows from Linux/OSX using MinGW
os = windows
i386.windows.gcc.path = "/usr/bin"
i386.windows.gcc.exe = "i686-w64-mingw32-gcc"
i386.windows.gcc.linkerexe = "i686-w64-mingw32-gcc"
amd64.windows.gcc.path = "/usr/bin"
amd64.windows.gcc.exe = "x86_64-w64-mingw32-gcc"
amd64.windows.gcc.linkerexe = "x86_64-w64-mingw32-gcc"
@end
@if unix:
@if not bsd or haiku:
# -fopenmp

View File

@@ -261,6 +261,21 @@ configuration file should contain something like::
arm.linux.gcc.exe = "arm-linux-gcc"
arm.linux.gcc.linkerexe = "arm-linux-gcc"
Cross compilation for Windows
=============================
To cross compile for Windows from Linux or OSX using the MinGW-w64 toolchain::
nim c -d:mingw myproject.nim
Use ``--cpu:i386`` or ``--cpu:amd64`` to switch the cpu arch.
The MinGW-w64 toolchain can be installed as follows::
Ubuntu: apt install mingw-w64
CentOS: yum install mingw32-gcc | mingw64-gcc - requires EPEL
OSX: brew install mingw-w64
Cross compilation for Nintendo Switch
=====================================

View File

@@ -407,13 +407,14 @@ proc temp(args: string) =
result[1].add " " & quoteShell(args[i])
inc i
var output = "compiler" / "nim".exe
var finalDest = "bin" / "nim_temp".exe
let d = getAppDir()
var output = d / "compiler" / "nim".exe
var finalDest = d / "bin" / "nim_temp".exe
# 125 is the magic number to tell git bisect to skip the current
# commit.
let (bootArgs, programArgs) = splitArgs(args)
let nimexec = findNim()
exec(nimexec & " c -d:debug --debugger:native " & bootArgs & " compiler" / "nim", 125)
exec(nimexec & " c -d:debug --debugger:native " & bootArgs & " " & (d / "compiler" / "nim"), 125)
copyExe(output, finalDest)
if programArgs.len > 0: exec(finalDest & " " & programArgs)

View File

@@ -673,10 +673,16 @@ template mapIt*(s: typed, op: untyped): untyped =
## nums = @[1, 2, 3, 4]
## strings = nums.mapIt($(4 * it))
## assert strings == @["4", "8", "12", "16"]
type outType = type((
block:
var it{.inject.}: type(items(s));
op))
when defined(nimHasTypeof):
type outType = typeof((
block:
var it{.inject.}: typeof(items(s), typeOfIter);
op), typeOfProc)
else:
type outType = type((
block:
var it{.inject.}: type(items(s));
op))
when compiles(s.len):
block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580
@@ -1135,5 +1141,13 @@ when isMainModule:
A, B
doAssert mapIt(X, $it) == @["A", "B"]
block:
# bug #9093
let inp = "a:b,c:d"
let outp = inp.split(",").mapIt(it.split(":"))
doAssert outp == @[@["a", "b"], @["c", "d"]]
when not defined(testing):
echo "Finished doc tests"

View File

@@ -278,7 +278,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
rtl, extern: "npuParseInt", noSideEffect.} =
## parses an integer starting at `start` and stores the value into `number`.
## Result is the number of processed chars or 0 if there is no integer.
## `EOverflow` is raised if an overflow occurs.
## `OverflowError` is raised if an overflow occurs.
var res: BiggestInt
result = parseBiggestInt(s, res, start)
if (sizeof(int) <= 4) and
@@ -289,7 +289,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
proc parseSaturatedNatural*(s: string, b: var int, start = 0): int =
## parses a natural number into ``b``. This cannot raise an overflow
## error. Instead of an ``Overflow`` exception ``high(int)`` is returned.
## error. ``high(int)`` is returned for an overflow.
## The number of processed character is returned.
## This is usually what you really want to use instead of `parseInt`:idx:.
## Example:

View File

@@ -180,6 +180,15 @@ else:
## Cannot be overloaded.
discard
when defined(nimHasTypeof):
type
TypeOfMode* = enum ## Possible modes of `typeof`.
typeOfProc, ## Prefer the interpretation that means `x` is a proc call.
typeOfIter ## Prefer the interpretation that means `x` is an iterator call.
proc typeof*(x: untyped; mode = typeOfIter): typeDesc {.magic: "TypeOf", noSideEffect, compileTime.} =
## Builtin 'typeof' operation for accessing the type of an expression. Since version 0.20.0.
discard
proc `not`*(x: bool): bool {.magic: "Not", noSideEffect.}
## Boolean not; returns true iff ``x == false``.

View File

@@ -15,12 +15,12 @@ when defined(develop):
else:
const nimp = "nimpretty"
proc test(infile, outfile: string) =
if execShellCmd("$# -o:$# --backup:off $#" % [nimp, outfile, infile]) != 0:
proc test(infile, ext: string) =
if execShellCmd("$# -o:$# --backup:off $#" % [nimp, infile.changeFileExt(ext), infile]) != 0:
quit("FAILURE")
let nimFile = splitFile(infile).name
let expected = dir / "expected" / nimFile & ".nim"
let produced = dir / nimFile & ".pretty"
let produced = dir / nimFile.changeFileExt(ext)
if strip(readFile(expected)) != strip(readFile(produced)):
echo "FAILURE: files differ: ", nimFile
discard execShellCmd("diff -uNdr " & expected & " " & produced)
@@ -29,8 +29,12 @@ proc test(infile, outfile: string) =
echo "SUCCESS: files identical: ", nimFile
for t in walkFiles(dir / "*.nim"):
let res = t.changeFileExt("pretty")
test(t, res)
removeFile(res)
test(t, "pretty")
# also test that pretty(pretty(x)) == pretty(x)
test(t.changeFileExt("pretty"), "pretty2")
removeFile(t.changeFileExt("pretty"))
removeFile(t.changeFileExt("pretty2"))
if failures > 0: quit($failures & " failures occurred.")

View File

@@ -1,4 +1,13 @@
var x: int = 2
echo x # bug #9144
echo x
# bug #9144
proc a() =
while true:
discard
# comment 1
# comment 2
discard

View File

@@ -7,3 +7,16 @@ proc fun*() =
echo "ok"
## doc comment
# regular comment
proc funB() =
echo "ok1"
# echo "ok2"
fun()
#[
bug #9483
]#
proc funE() =
echo "ok1"

View File

@@ -0,0 +1,9 @@
#[
foo bar
]#
proc fun() =
echo "ok1"

View File

@@ -3,3 +3,11 @@ var x: int = 2
echo x
# bug #9144
proc a() =
while true:
discard
# comment 1
# comment 2
discard

View File

@@ -7,3 +7,16 @@ proc fun*()=
echo "ok"
## doc comment
# regular comment
proc funB() =
echo "ok1"
# echo "ok2"
fun()
#[
bug #9483
]#
proc funE() =
echo "ok1"

View File

@@ -0,0 +1,9 @@
#[
foo bar
]#
proc fun() =
echo "ok1"

View File

@@ -1,16 +1,22 @@
discard """
output: '''
yeah A enumB
uneven
yeah A enumB
yeah CD enumD
uneven
yeah CD enumE
yeah A enumB
uneven
yeah CD enumE
yeah CD enumD
uneven
yeah A enumB
yeah B enumC
uneven
yeah A enumB
yeah A enumB
uneven
yeah A enumB
'''
"""
@@ -47,4 +53,7 @@ proc vm() =
of enumLast: discard
inc(pc)
if pc mod 2 == 1:
echo "uneven"
vm()

View File

@@ -1,5 +1,6 @@
discard """
errormsg: "type mismatch: got <Bar[system.int]>"
disabled: "true"
nimout: '''
t3330.nim(63, 4) Error: type mismatch: got <Bar[system.int]>
but expected one of:

View File

@@ -209,6 +209,25 @@ class NimStringPrinter:
else:
return ""
class NimRopePrinter:
pattern = re.compile(r'^tyObject_RopeObj_OFzf0kSiPTcNreUIeJgWVA \*$')
def __init__(self, val):
self.val = val
def display_hint(self):
return 'string'
def to_string(self):
if self.val:
left = NimRopePrinter(self.val["left"]).to_string()
data = NimStringPrinter(self.val["data"]).to_string()
right = NimRopePrinter(self.val["right"]).to_string()
return left + data + right
else:
return ""
################################################################################
# proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =