diff options
-rw-r--r-- | compiler/cgen.nim | 2 | ||||
-rw-r--r-- | compiler/evals.nim | 19 | ||||
-rw-r--r-- | compiler/extccomp.nim | 8 | ||||
-rw-r--r-- | compiler/nimrod.ini | 12 | ||||
-rw-r--r-- | compiler/options.nim | 14 | ||||
-rw-r--r-- | compiler/parser.nim | 2 | ||||
-rw-r--r-- | compiler/rodread.nim | 2 | ||||
-rw-r--r-- | compiler/rodwrite.nim | 3 | ||||
-rw-r--r-- | compiler/vm.nim | 2 | ||||
-rw-r--r-- | doc/grammar.txt | 7 | ||||
-rw-r--r-- | doc/manual.txt | 62 | ||||
-rw-r--r-- | lib/core/macros.nim | 2 | ||||
-rw-r--r-- | todo.txt | 6 | ||||
-rw-r--r-- | tools/niminst/niminst.nim | 39 |
14 files changed, 132 insertions, 48 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim index f33de9df0..c82c3887c 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1210,7 +1210,7 @@ proc writeHeader(m: BModule) = writeRope(result, m.filename) proc getCFile(m: BModule): string = - result = changeFileExt(completeCFilePath(m.cfilename), cExt) + result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), cExt) proc myOpenCached(module: PSym, rd: PRodReader): PPassContext = assert optSymbolFiles in gGlobalOptions diff --git a/compiler/evals.nim b/compiler/evals.nim index f8336fce7..7e2c8a41d 100644 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -162,10 +162,11 @@ var gNestedEvals: int # count the recursive calls to ``evalAux`` to prevent # endless recursion -proc evalWhile(c: PEvalContext, n: PNode): PNode = - while true: +proc evalWhile(c: PEvalContext, n: PNode): PNode = + while true: evalX(n.sons[0], {}) - if getOrdValue(result) == 0: break + if getOrdValue(result) == 0: + result = emptyNode; break result = evalAux(c, n.sons[1], {}) case result.kind of nkBreakStmt: @@ -304,7 +305,7 @@ proc allocSlot(c: PStackFrame; sym: PSym): int = setLen(c.slots, max(result+1, c.slots.len)) proc setSlot(c: PStackFrame, sym: PSym, val: PNode) = - assert sym.owner == c.prc + assert sym.owner == c.prc or sfFromGeneric in sym.flags let idx = allocSlot(c, sym) c.slots[idx] = val @@ -377,7 +378,7 @@ proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode = #result = emptyNode proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode = - if sfCompileTime in s.flags or c.mode == emRepl: + if sfCompileTime in s.flags or c.mode == emRepl or s.kind == skForVar: result = IdNodeTableGet(c.globals, s) if result != nil: if not aliasNeeded(result, flags): @@ -549,7 +550,9 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = of skProc, skConverter, skMacro, skType: result = n #result = s.getBody - of skVar, skLet, skForVar, skTemp, skResult: + of skForVar: + result = evalGlobalVar(c, s, flags) + of skVar, skLet, skTemp, skResult: if sfGlobal notin s.flags: result = evalVariable(c.tos, s, flags) else: @@ -1396,7 +1399,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = of nkChckRangeF, nkChckRange64, nkChckRange: result = evalRangeChck(c, n) of nkStringToCString: result = evalConvStrToCStr(c, n) of nkCStringToString: result = evalConvCStrToStr(c, n) - of nkStmtListExpr, nkStmtList, nkModule: + of nkStmtListExpr, nkStmtList: for i in countup(0, sonsLen(n) - 1): result = evalAux(c, n.sons[i], flags) case result.kind @@ -1455,7 +1458,7 @@ proc evalConstExprAux*(p: PEvalContext, module, prc: PSym, e: PNode): PNode = proc setupMacroParam(x: PNode): PNode = result = x - if result.kind == nkHiddenStdConv: result = result.sons[1] + if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1] proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode = # XXX GlobalError() is ugly here, but I don't know a better solution for now diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 488ed18fb..89524bc53 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -298,13 +298,13 @@ const gpp()] const - hExt* = "h" + hExt* = ".h" var cCompiler* = ccGcc # the used compiler - cExt* = "c" # extension of generated C/C++ files - # (can be changed to .cpp later) + cExt* = ".c" # extension of generated C/C++ files + # (can be changed to .cpp later) cIncludes*: seq[string] = @[] # directories to search for included files cLibs*: seq[string] = @[] # directories to search for lib files @@ -518,7 +518,7 @@ proc footprint(filename: string): TCrc32 = getCompileCFileCmd(filename, true) proc externalFileChanged(filename: string): bool = - var crcFile = toGeneratedFile(filename, "crc") + var crcFile = toGeneratedFile(filename.withPackageName, "crc") var currentCrc = int(footprint(filename)) var f: TFile if open(f, crcFile, fmRead): diff --git a/compiler/nimrod.ini b/compiler/nimrod.ini index 22623993c..0dc44a7c9 100644 --- a/compiler/nimrod.ini +++ b/compiler/nimrod.ini @@ -1,8 +1,16 @@ [Project] Name: "Nimrod" Version: "$version" -OS: "windows;linux;macosx;solaris;freebsd;netbsd;openbsd" -CPU: "i386;amd64;powerpc64;arm" # ;sparc +Platforms: """ + windows: i386;amd64 + linux: i386;amd64;powerpc64;arm;sparc;mips + macosx: i386;amd64;powerpc64 + solaris: i386;amd64;sparc + freebsd: i386;amd64 + netbsd: i386;amd64 + openbsd: i386;amd64 + haiku: i386;amd64 +""" Authors: "Andreas Rumpf" Description: """This is the Nimrod Compiler. Nimrod is a new statically typed, diff --git a/compiler/options.nim b/compiler/options.nim index 3c91d4439..e50535b8e 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -208,7 +208,19 @@ proc removeTrailingDirSep*(path: string): string = proc getGeneratedPath: string = result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir / genSubDir - + +proc withPackageName*(path: string): string = + var x = path + while true: + x = parentDir(x) + if x.len == 0: break + case x.normalize + of "lib", "src", "source", "package", "pckg", "library": discard + else: + let (path, file, ext) = path.splitFile + return (path / (x & '_' & file)) & ext + result = path + proc toGeneratedFile*(path, ext: string): string = ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod" var (head, tail) = splitPath(path) diff --git a/compiler/parser.nim b/compiler/parser.nim index a2fe34849..6e2d0867b 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1440,7 +1440,7 @@ proc parseSection(p: var TParser, kind: TNodeKind, skipComment(p, result) while sameInd(p): case p.tok.tokType - of tkSymbol, tkAccent: + of tkSymbol, tkAccent, tkParLe: var a = defparser(p) skipComment(p, a) addSon(result, a) diff --git a/compiler/rodread.nim b/compiler/rodread.nim index 562eaebab..a2ec2b4af 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -818,7 +818,7 @@ proc checkDep(fileIdx: int32): TReasonForRecompile = gMods[fileIdx].reason = rrNone # we need to set it here to avoid cycles result = rrNone var r: PRodReader = nil - var rodfile = toGeneratedFile(filename, RodExt) + var rodfile = toGeneratedFile(filename.withPackageName, RodExt) r = newRodReader(rodfile, crc, fileIdx) if r == nil: result = (if ExistsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist) diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 496fa49cf..34e890fd9 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -421,7 +421,8 @@ proc addStmt(w: PRodWriter, n: PNode) = proc writeRod(w: PRodWriter) = processStacks(w, true) var f: TFile - if not open(f, completeGeneratedFilePath(changeFileExt(w.filename, "rod")), + if not open(f, completeGeneratedFilePath(changeFileExt( + w.filename.withPackageName, RodExt)), fmWrite): #echo "couldn't write rod file for: ", w.filename return diff --git a/compiler/vm.nim b/compiler/vm.nim index e13d91e77..d5a816e53 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -890,7 +890,7 @@ proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode = proc setupMacroParam(x: PNode): PNode = result = x - if result.kind == nkHiddenStdConv: result = result.sons[1] + if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1] proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode = # XXX GlobalError() is ugly here, but I don't know a better solution for now diff --git a/doc/grammar.txt b/doc/grammar.txt index 741e9b907..7fe2b56aa 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -104,11 +104,12 @@ exprStmt = simpleExpr | IND{=} 'except' exprList ':' stmt | IND{=} 'else' ':' stmt )* ))? -importStmt = 'import' optInd expr - ((comma expr)* +moduleName = expr ('as' expr)? +importStmt = 'import' optInd moduleName + ((comma moduleName)* / 'except' optInd (expr ^+ comma)) includeStmt = 'include' optInd expr ^+ comma -fromStmt = 'from' expr 'import' optInd expr (comma expr)* +fromStmt = 'from' moduleName 'import' optInd expr (comma expr)* returnStmt = 'return' optInd expr? raiseStmt = 'raise' optInd expr? yieldStmt = 'yield' optInd expr? diff --git a/doc/manual.txt b/doc/manual.txt index 095f25b30..905b80a18 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -2018,11 +2018,11 @@ Example: The `when`:idx: statement is almost identical to the ``if`` statement with some exceptions: -* Each ``expr`` has to be a constant expression (of type ``bool``). +* Each condition (``expr``) has to be a constant expression (of type ``bool``). * The statements do not open a new scope. * The statements that belong to the expression that evaluated to true are translated by the compiler, the other statements are not checked for - semantics! However, each ``expr`` is checked for semantics. + semantics! However, each condition is checked for semantics. The ``when`` statement enables conditional compilation techniques. As a special syntactic extension, the ``when`` construct is also available @@ -2268,7 +2268,7 @@ A `table constructor`:idx: is syntactic sugar for an array constructor: {"key1": "value1", "key2", "key3": "value2"} # is the same as: - [("key1", "value1"), ("key2", "value2"), ("key3", "value")] + [("key1", "value1"), ("key2", "value2"), ("key3", "value2")] The empty table can be written ``{:}`` (in contrast to the empty set @@ -2565,9 +2565,6 @@ Overloading of the subscript operator ------------------------------------- The ``[]`` subscript operator for arrays/openarrays/sequences can be overloaded. -Overloading support is only possible if the first parameter has no type that -already supports the built-in ``[]`` notation. Currently the compiler -does not check this restriction. Multi-methods @@ -3301,13 +3298,11 @@ Specifically, the type class will be matched if: a) all of the expressions within the body can be compiled for the tested type b) all statically evaluatable boolean expressions in the body must be true -Please note that the `is` operator allows you to easily verify the precise type +Please note that the ``is`` operator allows you to easily verify the precise type signatures of the required operations, but since type inference and default parameters are still applied in the provided block, it's also possible to encode usage protocols that doesn't reveal implementation details. -.. code-block:: nimrod - Much like generics, the user defined type classes will be instantiated exactly once for each tested type and any static code included within them will also be executed once. @@ -3327,7 +3322,7 @@ from the proc body. This is usually used with the ``auto`` type class: The return type will be treated as additional generic param and can be explicitly specified at call sites as any other generic param. -Future versions of nimrod may also support overloading based on the return type +Future versions of Nimrod may also support overloading based on the return type of the overloads. In such settings, the expected result type at call sites may also influence the inferred return type. @@ -3398,8 +3393,9 @@ templates: The "types" of templates can be the symbols ``expr`` (stands for *expression*), ``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type -description*). These are no real types, they just help the compiler parsing. -Real types can be used too; this implies that expressions are expected. +description*). These are "meta types", they can only be used in certain +contexts. Real types can be used too; this implies that expressions are +expected. Ordinary vs immediate templates @@ -3868,7 +3864,7 @@ values inside containers and so on. For example, here is how one can create a type-safe wrapper for the unsafe `printf` function from C: .. code-block:: nimrod - macro safePrintF(formatString: string{lit}, args: vararg[expr]): expr = + macro safePrintF(formatString: string{lit}, args: varargs[expr]): expr = var i = 0 for c in formatChars(formatString): var expectedType = case c @@ -4196,10 +4192,10 @@ implemented with term rewriting: template optP2{p(x, y, false)}(x, y: expr): expr = x - y -Example: hoisting +Example: Hoisting ----------------- -The following example how some form of hoisting can be implemented: +The following example shows how some form of hoisting can be implemented: .. code-block:: nimrod import pegs @@ -4267,7 +4263,7 @@ optimization for types that have copying semantics: var t: TTable # overloading resolution ensures that the optimized []= is called here: - t["abc"] = "xyz" + t[f()] = g() @@ -4326,6 +4322,36 @@ module name followed by an ``except`` to prevent some symbols to be imported: echo "$1" % "abc" +Module names in imports +~~~~~~~~~~~~~~~~~~~~~~~ + +A module alias can be introduced via the ``as`` keyword: + +.. code-block:: nimrod + import strutils as su, sequtils as qu + + echo su.format("$1", "lalelu") + +The original module name is then not accessible. The +notations ``path/to/module`` or ``path.to.module`` or ``"path/to/module"`` +can be used to refer to a module in subdirectories: + +.. code-block:: nimrod + import lib.pure.strutils, lib/pure/os, "lib/pure/times" + +Note that the module name is still ``strutils`` and not ``lib.pure.strutils`` +and so one **cannot** do: + +.. code-block:: nimrod + import lib.pure.strutils + echo lib.pure.strutils + +Likewise the following does not make sense as the name is ``strutils`` already: + +.. code-block:: nimrod + import lib.pure.strutils as strutils + + From import statement ~~~~~~~~~~~~~~~~~~~~~ @@ -5085,9 +5111,9 @@ string expressions in general: proc getDllName: string = result = "mylib.dll" - if ExistsFile(result): return + if existsFile(result): return result = "mylib2.dll" - if ExistsFile(result): return + if existsFile(result): return quit("could not load dynamic library") proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().} diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 92cd2d315..fc93a157d 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -38,7 +38,7 @@ type nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, nnkStringToCString, nnkCStringToString, nnkAsgn, nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit, - nnkModule, nnkProcDef, nnkMethodDef, nnkConverterDef, + nnkImportAs, nnkProcDef, nnkMethodDef, nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse, nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt, diff --git a/todo.txt b/todo.txt index e963a3ae4..a12d19236 100644 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,8 @@ version 0.9.4 ============= +- change search path algorithm to care about packages +- XXX how can 'lib_system' ever be generated? - new VM: - implement the glue to replace evals.nim - implement missing magics @@ -20,7 +22,6 @@ version 0.9.4 Bugs ==== -- 'quote' without 'do' doesn't work - compilation of niminst takes way too long. looks like a regression - simple closure iterator doesn't work - docgen: sometimes effects are listed twice @@ -46,6 +47,7 @@ version 0.9.x * test libffi on windows * test: times.format with the FFI - document NimMain and check whether it works for threading +- 'quote' without 'do' doesn't work: parser/grammar issue; could be supported version 0.9.X @@ -125,7 +127,7 @@ GC CGEN ==== - codegen should use "NIM_CAST" macro and respect aliasing rules for GCC -- ``restrict`` pragma + backend support; computed goto support +- ``restrict`` pragma + backend support - 'const' objects including case objects diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index 4da734d13..0feac6de8 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -1,7 +1,7 @@ # # # The Nimrod Installation Generator -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -52,10 +52,12 @@ type cat: array[TFileCategory, seq[string]] binPaths, authors, oses, cpus: seq[string] cfiles: array[1..maxOS, array[1..maxCPU, seq[string]]] + platforms: array[1..maxOS, array[1..maxCPU, bool]] ccompiler, linker, innosetup: tuple[path, flags: string] name, displayName, version, description, license, infile, outdir: string libpath: string innoSetupFlag, installScript, uninstallScript: bool + explicitPlatforms: bool vars: PStringTable app: TAppType nimrodArgs: string @@ -126,7 +128,7 @@ const Version = "0.9" Usage = "niminst - Nimrod Installation Generator Version " & version & """ - (c) 2012 Andreas Rumpf + (c) 2013 Andreas Rumpf Usage: niminst [options] command[;command2...] ini-file[.ini] [compile_options] Command: @@ -221,6 +223,23 @@ proc yesno(p: var TCfgParser, v: string): bool = result = false else: quit(errorStr(p, "unknown value; use: yes|no")) +proc incl(s: var seq[string], x: string): int = + for i in 0.. <s.len: + if cmpIgnoreStyle(s[i], x) == 0: return i + s.add(x) + result = s.len-1 + +proc platforms(c: var TConfigData, v: string) = + for line in splitLines(v): + let p = line.find(": ") + if p <= 1: continue + let os = line.substr(0, p-1).strip + let cpus = line.substr(p+1).strip + c.oses.add(os) + for cpu in cpus.split(';'): + let cpuIdx = c.cpus.incl(cpu) + c.platforms[c.oses.len][cpuIdx+1] = true + proc parseIniFile(c: var TConfigData) = var p: TCfgParser @@ -244,8 +263,19 @@ proc parseIniFile(c: var TConfigData) = of "name": c.name = v of "displayname": c.displayName = v of "version": c.version = v - of "os": c.oses = split(v, {';'}) - of "cpu": c.cpus = split(v, {';'}) + of "os": + c.oses = split(v, {';'}) + if c.explicitPlatforms: + quit(errorStr(p, "you cannot have both 'platforms' and 'os'")) + of "cpu": + c.cpus = split(v, {';'}) + 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: + quit(errorStr(p, "you cannot have both 'platforms' and 'os'")) of "authors": c.authors = split(v, {';'}) of "description": c.description = v of "app": @@ -409,6 +439,7 @@ proc srcdist(c: var TConfigData) = let osname = c.oses[osA-1] if osname.cmpIgnoreStyle("windows") == 0: winIndex = osA-1 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 |