diff options
-rw-r--r-- | compiler/parser.nim | 9 | ||||
-rw-r--r-- | compiler/pretty.nim | 12 | ||||
-rw-r--r-- | examples/talk/dsl.nim | 33 | ||||
-rw-r--r-- | examples/talk/formatoptimizer.nim | 55 | ||||
-rw-r--r-- | examples/talk/hoisting.nim | 23 | ||||
-rw-r--r-- | examples/talk/lazyeval.nim | 12 | ||||
-rw-r--r-- | examples/talk/quasiquote.nim | 11 | ||||
-rw-r--r-- | examples/talk/tags.nim | 8 | ||||
-rw-r--r-- | lib/pure/sockets.nim | 4 | ||||
-rw-r--r-- | lib/system.nim | 21 | ||||
-rw-r--r-- | lib/system/gc.nim | 136 | ||||
-rw-r--r-- | lib/system/mmdisp.nim | 2 | ||||
-rw-r--r-- | tests/run/tindent1.nim (renamed from tests/compile/tindent1.nim) | 18 | ||||
-rw-r--r-- | tests/tester.nim | 1 | ||||
-rw-r--r-- | todo.txt | 3 | ||||
-rw-r--r-- | tools/niminst/niminst.nim | 13 |
16 files changed, 314 insertions, 47 deletions
diff --git a/compiler/parser.nim b/compiler/parser.nim index 6e2d0867b..e8439466a 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1798,7 +1798,9 @@ proc parseStmt(p: var TParser): PNode = if p.tok.indent == p.currInd: nil elif p.tok.tokType == tkSemicolon: - while p.tok.tokType == tkSemicolon: getTok(p) + getTok(p) + if p.tok.indent < 0 or p.tok.indent == p.currInd: discard + else: break else: if p.tok.indent > p.currInd: parMessage(p, errInvalidIndentation) @@ -1851,7 +1853,10 @@ proc parseTopLevelStmt(p: var TParser): PNode = else: parMessage(p, errInvalidIndentation) p.firstTok = false case p.tok.tokType - of tkSemicolon: getTok(p) + of tkSemicolon: + getTok(p) + if p.tok.indent <= 0: discard + else: parMessage(p, errInvalidIndentation) of tkEof: break else: result = complexOrSimpleStmt(p) diff --git a/compiler/pretty.nim b/compiler/pretty.nim index 4545e1c55..5036a16a3 100644 --- a/compiler/pretty.nim +++ b/compiler/pretty.nim @@ -55,6 +55,10 @@ proc overwriteFiles*() = except EIO: rawMessage(errCannotOpenFile, newFile) +proc `=~`(s: string, a: openArray[string]): bool = + for x in a: + if s.startsWith(x): return true + proc beautifyName(s: string, k: TSymKind): string = result = newStringOfCap(s.len) var i = 0 @@ -64,7 +68,13 @@ proc beautifyName(s: string, k: TSymKind): string = when removeTP: if s[0] == 'T' and s[1] in {'A'..'Z'}: i = 1 - result.add toUpper(s[i]) + if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string", + "char", "byte", "bool", "openArray", "seq", "array", "void", + "pointer", "float", "csize", "cdouble", "cchar", "cschar", + "cshort", "cu"]: + result.add s[i] + else: + result.add toUpper(s[i]) of skConst, skEnumField: # for 'const' we keep how it's spelt; either upper case or lower case: result.add s[0] diff --git a/examples/talk/dsl.nim b/examples/talk/dsl.nim new file mode 100644 index 000000000..4dfab5cd7 --- /dev/null +++ b/examples/talk/dsl.nim @@ -0,0 +1,33 @@ + +import strutils + +template html(name: expr, matter: stmt) {.immediate.} = + proc name(): string = + result = "<html>" + matter + result.add("</html>") + +template nestedTag(tag: expr) {.immediate.} = + template tag(matter: stmt) {.immediate.} = + result.add("<" & astToStr(tag) & ">") + matter + result.add("</" & astToStr(tag) & ">") + +template simpleTag(tag: expr) {.immediate.} = + template tag(matter: expr) {.immediate.} = + result.add("<$1>$2</$1>" % [astToStr(tag), matter]) + +nestedTag body +nestedTag head +nestedTag ul +simpleTag title +simpleTag li + +html mainPage: + head: + title "now look at this" + body: + ul: + li "Nimrod is quite capable" + +echo mainPage() diff --git a/examples/talk/formatoptimizer.nim b/examples/talk/formatoptimizer.nim new file mode 100644 index 000000000..db11d112d --- /dev/null +++ b/examples/talk/formatoptimizer.nim @@ -0,0 +1,55 @@ +## This is the example that optimizes a modified "hello world" + +import macros + +proc invalidFormatString() = + echo "invalidFormatString" + +template formatImpl(handleChar: expr) = + var i = 0 + while i < f.len: + if f[i] == '$': + case f[i+1] + of '1'..'9': + var j = 0 + i += 1 + while f[i] in {'0'..'9'}: + j = j * 10 + ord(f[i]) - ord('0') + i += 1 + result.add(a[j-1]) + else: + invalidFormatString() + else: + result.add(handleChar(f[i])) + i += 1 + +proc `%`*(f: string, a: openArray[string]): string = + template identity(x: expr): expr = x + result = "" + formatImpl(identity) + +macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): expr = + result = newNimNode(nnkBracket) + #newCall("&") + let f = f.strVal + formatImpl(newLit) + result = nestList(!"&", result) + +template optAdd1{x = y; add(x, z)}(x, y, z: string) = + x = y & z + +#template optAdd2{x.add(y); x.add(z)}(x, y, z: string) = +# x.add(y & z) + +proc `/&` [T: object](x: T): string = + result = "(" + for name, value in fieldPairs(x): + result.add("$1: $2\n" % [name, $value]) + result.add(")") + +type + MyObject = object + a, b: int + s: string +let obj = MyObject(a: 3, b: 4, s: "abc") +echo(/&obj) diff --git a/examples/talk/hoisting.nim b/examples/talk/hoisting.nim new file mode 100644 index 000000000..df13ba2cb --- /dev/null +++ b/examples/talk/hoisting.nim @@ -0,0 +1,23 @@ +type + Regex = distinct string + +const maxSubpatterns = 10 + +proc re(x: string): Regex = + result = Regex(x) + +proc match(s: string, pattern: Regex, captures: var openArray[string]): bool = + true + +template optRe{re(x)}(x: string{lit}): Regex = + var g {.global.} = re(x) + g + +template `=~`(s: string, pattern: Regex): bool = + when not definedInScope(matches): + var matches {.inject.}: array[maxSubPatterns, string] + match(s, pattern, matches) + +for line in lines("input.txt"): + if line =~ re"(\w+)=(\w+)": + echo "key-value pair; key: ", matches[0], " value: ", matches[1] diff --git a/examples/talk/lazyeval.nim b/examples/talk/lazyeval.nim new file mode 100644 index 000000000..77d963834 --- /dev/null +++ b/examples/talk/lazyeval.nim @@ -0,0 +1,12 @@ + +const + debug = true + +template log(msg: string) = + if debug: + echo msg +var + x = 1 + y = 2 + +log("x: " & $x & ", y: " & $y) diff --git a/examples/talk/quasiquote.nim b/examples/talk/quasiquote.nim new file mode 100644 index 000000000..df4003e6e --- /dev/null +++ b/examples/talk/quasiquote.nim @@ -0,0 +1,11 @@ + +import macros + +macro check(ex: expr): stmt = + var info = ex.lineinfo + var expString = ex.toStrLit + result = quote do: + if not `ex`: + echo `info`, ": Check failed: ", `expString` + +check 1 < 2 diff --git a/examples/talk/tags.nim b/examples/talk/tags.nim new file mode 100644 index 000000000..d47b09e07 --- /dev/null +++ b/examples/talk/tags.nim @@ -0,0 +1,8 @@ + +template htmlTag(tag: expr) {.immediate.} = + proc tag(): string = "<" & astToStr(tag) & ">" + +htmlTag(br) +htmlTag(html) + +echo br() diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index 73a189fee..fe4d3c2a4 100644 --- a/lib/pure/sockets.nim +++ b/lib/pure/sockets.nim @@ -11,11 +11,11 @@ ## of sockets. Sockets are buffered by default meaning that data will be ## received in ``BufferSize`` (4000) sized chunks, buffering ## behaviour can be disabled by setting the ``buffered`` parameter when calling -## the ``socket`` function to `False`. Be aware that some functions may not yet +## the ``socket`` function to `false`. Be aware that some functions may not yet ## support buffered sockets (mainly the recvFrom function). ## ## Most procedures raise EOS on error, but some may return ``-1`` or a boolean -## ``False``. +## ``false``. ## ## SSL is supported through the OpenSSL library. This support can be activated ## by compiling with the ``-d:ssl`` switch. When an SSL socket is used it will diff --git a/lib/system.nim b/lib/system.nim index 4ff1f1577..51f325997 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -77,17 +77,6 @@ type TNumber* = TInteger|TReal ## type class matching all number types - -type - ## helper types for writing implicitly generic procs - T1* = expr - T2* = expr - T3* = expr - T4* = expr - T5* = expr - type1* = typedesc - type2* = typedesc - type3* = typedesc proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.} ## Special compile-time procedure that checks whether `x` is @@ -2509,7 +2498,7 @@ proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.} ## converts the AST of `x` into a string representation. This is very useful ## for debugging. -proc InstantiationInfo*(index = -1, fullPaths = false): tuple[ +proc instantiationInfo*(index = -1, fullPaths = false): tuple[ filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.} ## provides access to the compiler's instantiation stack line information. ## @@ -2540,7 +2529,7 @@ proc InstantiationInfo*(index = -1, fullPaths = false): tuple[ ## testException(EInvalidIndex, tester(1)) ## # --> Test failure at example.nim:20 with 'tester(1)' -template CurrentSourcePath*: string = InstantiationInfo(-1, true).filename +template currentSourcePath*: string = instantiationInfo(-1, true).filename ## returns the full file-system path of the current source proc raiseAssert*(msg: string) {.noinline.} = @@ -2560,7 +2549,7 @@ template assert*(cond: bool, msg = "") = ## raises an ``EAssertionFailure`` exception. However, the compiler may ## not generate any code at all for ``assert`` if it is advised to do so. ## Use ``assert`` for debugging purposes only. - bind InstantiationInfo, hiddenRaiseAssert + bind instantiationInfo, hiddenRaiseAssert when compileOption("assertions"): {.line.}: if not cond: @@ -2569,8 +2558,8 @@ template assert*(cond: bool, msg = "") = template doAssert*(cond: bool, msg = "") = ## same as `assert` but is always turned on and not affected by the ## ``--assertions`` command line switch. - bind InstantiationInfo - {.line: InstantiationInfo().}: + bind instantiationInfo + {.line: instantiationInfo().}: if not cond: raiseAssert(astToStr(cond) & ' ' & msg) diff --git a/lib/system/gc.nim b/lib/system/gc.nim index f5b68b9db..c5d4d2aa2 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -25,6 +25,10 @@ const # reaches this threshold # this seems to be a good value withRealTime = defined(useRealtimeGC) + useMarkForDebug = defined(gcGenerational) + useBackupGc = false # use a simple M&S GC to collect + # cycles instead of the complex + # algorithm when withRealTime and not defined(getTicks): include "system/timers" @@ -42,8 +46,10 @@ const colorMask = 0b011 type TWalkOp = enum + waMarkGlobal, # part of the backup/debug mark&sweep + waMarkPrecise, # part of the backup/debug mark&sweep waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack, - waCollectWhite + waCollectWhite, TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall.} # A ref type can have a finalizer that is called before the object's @@ -71,6 +77,8 @@ type maxPause: TNanos # max allowed pause in nanoseconds; active if > 0 region: TMemRegion # garbage collected region stat: TGcStat + when useMarkForDebug or useBackupGc: + marked: TCellSet var gch {.rtlThreadVar.}: TGcHeap @@ -80,7 +88,7 @@ when not defined(useNimRtl): template acquire(gch: TGcHeap) = when hasThreadSupport and hasSharedHeap: - AcquireSys(HeapLock) + acquireSys(HeapLock) template release(gch: TGcHeap) = when hasThreadSupport and hasSharedHeap: @@ -128,7 +136,7 @@ template setColor(c, col) = else: c.refcount = c.refCount and not colorMask or col -proc writeCell(msg: CString, c: PCell) = +proc writeCell(msg: cstring, c: PCell) = var kind = -1 if c.typ != nil: kind = ord(c.typ.kind) when leakDetector: @@ -159,6 +167,8 @@ else: template `++`(x: expr): stmt = Inc(x, rcIncrement) proc prepareDealloc(cell: PCell) = + when useMarkForDebug: + gcAssert(cell notin gch.marked, "Cell still alive!") if cell.typ.finalizer != nil: # the finalizer could invoke something that # allocates memory; this could trigger a garbage @@ -172,21 +182,21 @@ proc prepareDealloc(cell: PCell) = proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = # we MUST access gch as a global here, because this crosses DLL boundaries! when hasThreadSupport and hasSharedHeap: - AcquireSys(HeapLock) + acquireSys(HeapLock) when cycleGC: if c.color != rcPurple: c.setColor(rcPurple) incl(gch.cycleRoots, c) when hasThreadSupport and hasSharedHeap: - ReleaseSys(HeapLock) + releaseSys(HeapLock) proc rtlAddZCT(c: PCell) {.rtl, inl.} = # we MUST access gch as a global here, because this crosses DLL boundaries! when hasThreadSupport and hasSharedHeap: - AcquireSys(HeapLock) + acquireSys(HeapLock) addZCT(gch.zct, c) when hasThreadSupport and hasSharedHeap: - ReleaseSys(HeapLock) + releaseSys(HeapLock) proc decRef(c: PCell) {.inline.} = gcAssert(isAllocatedPtr(gch.region, c), "decRef: interiorPtr") @@ -249,7 +259,7 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} = # unsureAsgnRef updates the reference counters only if dest is not on the # stack. It is used by the code generator if it cannot decide wether a # reference is in the stack or not (this can happen for var parameters). - if not IsOnStack(dest): + if not isOnStack(dest): if src != nil: incRef(usrToCell(src)) # XXX finally use assembler for the stack checking instead! # the test for '!= nil' is correct, but I got tired of the segfaults @@ -277,6 +287,27 @@ proc initGC() = init(gch.tempStack) init(gch.cycleRoots) init(gch.decStack) + when useMarkForDebug or useBackupGc: + init(gch.marked) + +when useMarkForDebug or useBackupGc: + type + TGlobalMarkerProc = proc () {.nimcall.} + var + globalMarkersLen: int + globalMarkers: array[0.. 7_000, TGlobalMarkerProc] + + proc nimRegisterGlobalMarker(markerProc: TGlobalMarkerProc) {.compilerProc.} = + if globalMarkersLen <= high(globalMarkers): + globalMarkers[globalMarkersLen] = markerProc + inc globalMarkersLen + else: + echo "[GC] cannot register global variable; too many global variables" + quit 1 + +proc cellsetReset(s: var TCellSet) = + deinit(s) + init(s) proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) = var d = cast[TAddress](dest) @@ -534,7 +565,7 @@ proc collectWhite(s: PCell) = forAllChildren(s, waCollectWhite) freeCyclicCell(gch, s) -proc MarkRoots(gch: var TGcHeap) = +proc markRoots(gch: var TGcHeap) = var tabSize = 0 for s in elements(gch.cycleRoots): #writeCell("markRoot", s) @@ -548,6 +579,38 @@ proc MarkRoots(gch: var TGcHeap) = freeCyclicCell(gch, s) gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, tabSize) +when useBackupGc: + proc sweep(gch: var TGcHeap) = + for x in allObjects(gch.region): + if isCell(x): + # cast to PCell is correct here: + var c = cast[PCell](x) + if c notin gch.marked: freeCyclicCell(gch, c) + +when useMarkForDebug or useBackupGc: + proc markS(gch: var TGcHeap, c: PCell) = + incl(gch.marked, c) + gcAssert gch.tempStack.len == 0, "stack not empty!" + forAllChildren(c, waMarkPrecise) + while gch.tempStack.len > 0: + dec gch.tempStack.len + var d = gch.tempStack.d[gch.tempStack.len] + if not containsOrIncl(gch.marked, d): + forAllChildren(d, waMarkPrecise) + + proc markGlobals(gch: var TGcHeap) = + for i in 0 .. < globalMarkersLen: globalMarkers[i]() + + proc stackMarkS(gch: var TGcHeap, p: pointer) {.inline.} = + # the addresses are not as cells on the stack, so turn them to cells: + var cell = usrToCell(p) + var c = cast[TAddress](cell) + if c >% PageSize: + # fast check: does it look like a cell? + var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell)) + if objStart != nil: + markS(gch, objStart) + proc doOperation(p: pointer, op: TWalkOp) = if p == nil: return var c: PCell = usrToCell(p) @@ -580,12 +643,26 @@ proc doOperation(p: pointer, op: TWalkOp) = if c.color != rcBlack: scanBlack(c) of waCollectWhite: collectWhite(c) + of waMarkGlobal: + when useMarkForDebug or useBackupGc: + when hasThreadSupport: + # could point to a cell which we don't own and don't want to touch/trace + if isAllocatedPtr(gch.region, c): + markS(gch, c) + else: + markS(gch, c) + of waMarkPrecise: + when useMarkForDebug or useBackupGc: + add(gch.tempStack, c) proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = doOperation(d, TWalkOp(op)) proc CollectZCT(gch: var TGcHeap): bool +when useMarkForDebug or useBackupGc: + proc markStackAndRegistersForSweep(gch: var TGcHeap) {.noinline, cdecl.} + proc collectRoots(gch: var TGcHeap) = for s in elements(gch.cycleRoots): excl(gch.cycleRoots, s) @@ -594,13 +671,18 @@ proc collectRoots(gch: var TGcHeap) = proc collectCycles(gch: var TGcHeap) = # ensure the ZCT 'color' is not used: while gch.zct.len > 0: discard collectZCT(gch) - markRoots(gch) - # scanRoots: - for s in elements(gch.cycleRoots): scan(s) - collectRoots(gch) + when useBackupGc: + cellsetReset(gch.marked) + markStackAndRegistersForSweep(gch) + markGlobals(gch) + sweep(gch) + else: + markRoots(gch) + # scanRoots: + for s in elements(gch.cycleRoots): scan(s) + collectRoots(gch) - Deinit(gch.cycleRoots) - Init(gch.cycleRoots) + cellsetReset(gch.cycleRoots) # alive cycles need to be kept in 'cycleRoots' if they are referenced # from the stack; otherwise the write barrier will add the cycle root again # anyway: @@ -695,7 +777,7 @@ when defined(sparc): # For SPARC architecture. var x = cast[TAddress](p) result = a <=% x and x <=% b - proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} = + template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} = when defined(sparcv9): asm """"flushw \n" """ else: @@ -731,7 +813,7 @@ elif stackIncreases: # a little hack to get the size of a TJmpBuf in the generated C code # in a platform independant way - proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} = + template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} = var registers: C_JmpBuf if c_setjmp(registers) == 0'i32: # To fill the C stack with registers. var max = cast[TAddress](gch.stackBottom) @@ -754,7 +836,7 @@ else: var x = cast[TAddress](p) result = a <=% x and x <=% b - proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} = + template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} = # We use a jmp_buf buffer that is in the C stack. # Used to traverse the stack and registers assuming # that 'setjmp' will save registers in the C stack. @@ -778,12 +860,19 @@ else: while sp <=% max: gcMark(gch, cast[ppointer](sp)[]) sp = sp +% sizeof(pointer) + +proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} = + forEachStackSlot(gch, gcMark) + +when useMarkForDebug or useBackupGc: + proc markStackAndRegistersForSweep(gch: var TGcHeap) = + forEachStackSlot(gch, stackMarkS) # ---------------------------------------------------------------------------- # end of non-portable code # ---------------------------------------------------------------------------- -proc CollectZCT(gch: var TGcHeap): bool = +proc collectZCT(gch: var TGcHeap): bool = # Note: Freeing may add child objects to the ZCT! So essentially we do # deep freeing, which is bad for incremental operation. In order to # avoid a deep stack, we move objects to keep the ZCT small. @@ -880,10 +969,19 @@ proc collectCTBody(gch: var TGcHeap) = if gch.maxPause > 0 and duration > gch.maxPause: c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration) +when useMarkForDebug or useBackupGc: + proc markForDebug(gch: var TGcHeap) = + markStackAndRegistersForSweep(gch) + markGlobals(gch) + proc collectCT(gch: var TGcHeap) = if (gch.zct.len >= ZctThreshold or (cycleGC and getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and gch.recGcLock == 0: + when useMarkForDebug: + prepareForInteriorPointerChecking(gch.region) + cellsetReset(gch.marked) + markForDebug(gch) collectCTBody(gch) when withRealtime: diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 9f37e95c1..c9801abad 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -313,7 +313,7 @@ else: # XXX use 'compileOption' here include "system/gc_ms" elif defined(gcGenerational): - include "system/gc_genms" + include "system/gc" else: include "system/gc" diff --git a/tests/compile/tindent1.nim b/tests/run/tindent1.nim index 0527b6e57..78a303783 100644 --- a/tests/compile/tindent1.nim +++ b/tests/run/tindent1.nim @@ -1,3 +1,6 @@ +discard """ + output: '''Success''' +""" const romanNumbers1 = [ @@ -22,3 +25,18 @@ const romanNumbers4 = [ ] +proc main = + var j = 0 + while j < 10: + inc(j); + + if j == 5: doAssert false + +var j = 0 +while j < 10: + inc(j); + +if j == 5: doAssert false + +main() +echo "Success" diff --git a/tests/tester.nim b/tests/tester.nim index e10b89761..fe21fc9ee 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -402,6 +402,7 @@ proc main() = compileExample(r, "lib/pure/*.nim", p.cmdLineRest.string) compileExample(r, "examples/*.nim", p.cmdLineRest.string) compileExample(r, "examples/gtk/*.nim", p.cmdLineRest.string) + compileExample(r, "examples/talk/*.nim", p.cmdLineRest.string) compileSpecialTests(r, p.cmdLineRest.string) writeResults(compileJson, r) of "run": diff --git a/todo.txt b/todo.txt index 302a5eeaf..da7585500 100644 --- a/todo.txt +++ b/todo.txt @@ -1,13 +1,11 @@ version 0.9.4 ============= -- add the code from the talk to examples or run tests - new VM: - implement the glue to replace evals.nim - implement missing magics - implement overflow checking - implement the FFI - - implement on the fly CSE - make 'bind' default for templates and introduce 'mixin' - special rule for ``[]=`` @@ -160,3 +158,4 @@ Optimizations even further write barrier specialization - inlining of first class functions - proc specialization in the code gen for write barrier specialization +- VM/optimizer: implement on the fly CSE diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index 0feac6de8..e93a895e5 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -244,6 +244,7 @@ proc parseIniFile(c: var TConfigData) = var p: TCfgParser section = "" + hasCpuOs = false var input = newFileStream(c.infile, fmRead) if input != nil: open(p, input, c.infile) @@ -265,16 +266,18 @@ proc parseIniFile(c: var TConfigData) = of "version": c.version = v of "os": c.oses = split(v, {';'}) + hasCpuOs = true if c.explicitPlatforms: quit(errorStr(p, "you cannot have both 'platforms' and 'os'")) of "cpu": c.cpus = split(v, {';'}) + hasCpuOs = true if c.explicitPlatforms: quit(errorStr(p, "you cannot have both 'platforms' and 'cpu'")) of "platforms": platforms(c, v) c.explicitPlatforms = true - if c.cpus.len > 0 or c.oses.len > 0: + if hasCpuOs: quit(errorStr(p, "you cannot have both 'platforms' and 'os'")) of "authors": c.authors = split(v, {';'}) of "description": c.description = v @@ -407,6 +410,8 @@ proc writeFile(filename, content, newline: string) = proc removeDuplicateFiles(c: var TConfigData) = for osA in countdown(c.oses.len, 1): for cpuA in countdown(c.cpus.len, 1): + if c.cfiles[osA][cpuA].isNil: c.cfiles[osA][cpuA] = @[] + if c.explicitPlatforms and not c.platforms[osA][cpuA]: continue for i in 0..c.cfiles[osA][cpuA].len-1: var dup = c.cfiles[osA][cpuA][i] var f = extractFilename(dup) @@ -437,12 +442,12 @@ proc srcdist(c: var TConfigData) = var intel64Index = -1 for osA in 1..c.oses.len: let osname = c.oses[osA-1] - if osname.cmpIgnoreStyle("windows") == 0: winIndex = osA-1 + if osname.cmpIgnoreStyle("windows") == 0: winIndex = osA for cpuA in 1..c.cpus.len: if c.explicitPlatforms and not c.platforms[osA][cpuA]: continue let cpuname = c.cpus[cpuA-1] - if cpuname.cmpIgnoreStyle("i386") == 0: intel32Index = cpuA-1 - elif cpuname.cmpIgnoreStyle("amd64") == 0: intel64Index = cpuA-1 + if cpuname.cmpIgnoreStyle("i386") == 0: intel32Index = cpuA + elif cpuname.cmpIgnoreStyle("amd64") == 0: intel64Index = cpuA var dir = getOutputDir(c) / buildDir(osA, cpuA) if existsDir(dir): removeDir(dir) createDir(dir) |