From 94d1aa5109ebe022e6e51c7cd84033e2457b184f Mon Sep 17 00:00:00 2001 From: Jeff Ciesielski Date: Mon, 4 Jul 2016 18:11:25 -0400 Subject: [PATCH 1/4] Add the ability to pass a value with the -d flag This allows the end user to use the {.magic: "IntDefine"/"StrDefine"} pragmas to pass values into code at compile time. This has a nice side effect of also allowing/requiring a default value to be assigned in the code (see osalloc.nim/StandaloneHeapSize for an example) --- compiler/ast.nim | 2 +- compiler/commands.nim | 13 ++++++++++++- compiler/condsyms.nim | 9 +++++++-- compiler/semfold.nim | 6 ++++++ compiler/wordrecg.nim | 3 ++- doc/basicopt.txt | 3 ++- lib/system/osalloc.nim | 3 ++- 7 files changed, 32 insertions(+), 7 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index c3bb7cd622..34ffd6f583 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -610,7 +610,7 @@ type mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNHint, mNWarning, mNError, mInstantiationInfo, mGetTypeInfo, mNGenSym, - mNimvm + mNimvm, mIntDefine, mStrDefine # things that we can evaluate safely at compile time, even if not asked for it: const diff --git a/compiler/commands.nim b/compiler/commands.nim index b3edb5e149..640e07b1b7 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -122,6 +122,13 @@ proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1) else: invalidCmdLineOption(pass, switch, info) +proc hasKeyValuePair(arg: string): bool = + for i in 0..arg.high: + if arg[i] in {':', '='}: + return true + + return false + proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case whichKeyword(arg) @@ -342,7 +349,11 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = discard "allow for backwards compatibility, but don't do anything" of "define", "d": expectArg(switch, arg, pass, info) - defineSymbol(arg) + if hasKeyValuePair(arg): + splitSwitch(arg, key, val, pass, info) + defineSymbol(key, val) + else: + defineSymbol(arg) of "undef", "u": expectArg(switch, arg, pass, info) undefSymbol(arg) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 60e8f28262..02f7e764de 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -19,8 +19,8 @@ var gSymbols: StringTableRef const catNone = "false" -proc defineSymbol*(symbol: string) = - gSymbols[symbol] = "true" +proc defineSymbol*(symbol: string, value: string = "true") = + gSymbols[symbol] = value proc undefSymbol*(symbol: string) = gSymbols[symbol] = catNone @@ -62,6 +62,11 @@ proc isDefined*(symbol: string): bool = proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s) +proc lookupSymbol*(symbol: string): string = + result = if isDefined(symbol): gSymbols[symbol] else: nil + +proc lookupSymbol*(symbol: PIdent): string = lookupSymbol(symbol.s) + iterator definedSymbolNames*: string = for key, val in pairs(gSymbols): if val != catNone: yield key diff --git a/compiler/semfold.nim b/compiler/semfold.nim index feea6ce347..26d309cfdb 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -640,6 +640,12 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of mNaN: result = newFloatNodeT(NaN, n) of mInf: result = newFloatNodeT(Inf, n) of mNegInf: result = newFloatNodeT(NegInf, n) + of mIntDefine: + if isDefined(s.name): + result = newIntNodeT(lookupSymbol(s.name).parseInt, n) + of mStrDefine: + if isDefined(s.name): + result = newStrNodeT(lookupSymbol(s.name), n) else: if sfFakeConst notin s.flags: result = copyTree(s.ast) of {skProc, skMethod}: diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 3e0e05a948..b5ffd51c28 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -36,6 +36,7 @@ type wColon, wColonColon, wEquals, wDot, wDotDot, wStar, wMinus, wMagic, wThread, wFinal, wProfiler, wObjChecks, + wIntDefine, wStrDefine, wDestroy, @@ -121,7 +122,7 @@ const ":", "::", "=", ".", "..", "*", "-", - "magic", "thread", "final", "profiler", "objchecks", + "magic", "thread", "final", "profiler", "objchecks", "intdefine", "strdefine", "destroy", diff --git a/doc/basicopt.txt b/doc/basicopt.txt index 6a905bd538..c68d731e6c 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -11,7 +11,8 @@ Arguments: arguments are passed to the program being run (if --run option is selected) Options: -p, --path:PATH add path to search paths - -d, --define:SYMBOL define a conditional symbol + -d, --define:SYMBOL(:VAL) define a conditional symbol + (Optionally: Define the value for that symbol) -u, --undef:SYMBOL undefine a conditional symbol -f, --forceBuild force rebuilding of all modules --stackTrace:on|off turn stack tracing on|off diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index de26f52d96..cfa9ae18fb 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -150,8 +150,9 @@ elif defined(windows): #VirtualFree(p, size, MEM_DECOMMIT) elif hostOS == "standalone": + const StandaloneHeapSize {.magic: "IntDefine"}: int = 1024 * PageSize var - theHeap: array[1024*PageSize, float64] # 'float64' for alignment + theHeap: array[StandaloneHeapSize, float64] # 'float64' for alignment bumpPointer = cast[int](addr theHeap) proc osAllocPages(size: int): pointer {.inline.} = From 4f4aafda6c1cc13e1d8073e341344a49507e7174 Mon Sep 17 00:00:00 2001 From: Jeff Ciesielski Date: Mon, 4 Jul 2016 22:52:24 -0400 Subject: [PATCH 2/4] Plumb {.intdefine.} and {.strdefine.} pragmas. Shorthand so that users won't need to use the .magic pragma --- compiler/pragmas.nim | 7 ++++++- lib/system/osalloc.nim | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index dc618d9aa5..fffb69ca8d 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -63,7 +63,8 @@ const wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal, wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims} constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl, - wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims} + wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims, + wIntDefine, wStrDefine} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect, wThread, wRaises, wLocks, wTags, wGcSafe} @@ -898,6 +899,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, of wBase: noVal(it) sym.flags.incl sfBase + of wIntDefine: + sym.magic = mIntDefine + of wStrDefine: + sym.magic = mIntDefine else: invalidPragma(it) else: invalidPragma(it) diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index cfa9ae18fb..e864253b66 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -150,7 +150,7 @@ elif defined(windows): #VirtualFree(p, size, MEM_DECOMMIT) elif hostOS == "standalone": - const StandaloneHeapSize {.magic: "IntDefine"}: int = 1024 * PageSize + const StandaloneHeapSize {.intdefine.}: int = 1024 * PageSize var theHeap: array[StandaloneHeapSize, float64] # 'float64' for alignment bumpPointer = cast[int](addr theHeap) From 16f280843960d51cdde259e6bb25f223d5b14318 Mon Sep 17 00:00:00 2001 From: Jeff Ciesielski Date: Tue, 5 Jul 2016 07:58:26 -0400 Subject: [PATCH 3/4] Fix typo. Remove unnecessary proc --- compiler/commands.nim | 9 +-------- compiler/pragmas.nim | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 640e07b1b7..cf1e16b283 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -122,13 +122,6 @@ proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1) else: invalidCmdLineOption(pass, switch, info) -proc hasKeyValuePair(arg: string): bool = - for i in 0..arg.high: - if arg[i] in {':', '='}: - return true - - return false - proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case whichKeyword(arg) @@ -349,7 +342,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = discard "allow for backwards compatibility, but don't do anything" of "define", "d": expectArg(switch, arg, pass, info) - if hasKeyValuePair(arg): + if {':', '='} in arg: splitSwitch(arg, key, val, pass, info) defineSymbol(key, val) else: diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index fffb69ca8d..c15794b998 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -902,7 +902,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, of wIntDefine: sym.magic = mIntDefine of wStrDefine: - sym.magic = mIntDefine + sym.magic = mStrDefine else: invalidPragma(it) else: invalidPragma(it) From 11730e6c3b468621258f99539284d75fecafe276 Mon Sep 17 00:00:00 2001 From: Jeff Ciesielski Date: Tue, 5 Jul 2016 09:06:40 -0400 Subject: [PATCH 4/4] Update documentation and news --- doc/basicopt.txt | 3 ++- doc/manual/pragmas.txt | 27 +++++++++++++++++++++++++++ doc/nimc.rst | 10 +++++++++- web/news/version_0_15_released.rst | 6 ++++++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/doc/basicopt.txt b/doc/basicopt.txt index c68d731e6c..9a1cfd9565 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -11,7 +11,8 @@ Arguments: arguments are passed to the program being run (if --run option is selected) Options: -p, --path:PATH add path to search paths - -d, --define:SYMBOL(:VAL) define a conditional symbol + -d, --define:SYMBOL(:VAL) + define a conditional symbol (Optionally: Define the value for that symbol) -u, --undef:SYMBOL undefine a conditional symbol -f, --forceBuild force rebuilding of all modules diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt index 1a1f0b734a..88ddabef80 100644 --- a/doc/manual/pragmas.txt +++ b/doc/manual/pragmas.txt @@ -1011,3 +1011,30 @@ debugging: # ... complex code here that produces crashes ... +compile time define pragmas +--------------------------- + +The pragmas listed here can be used to optionally accept values from +the -d/--define option at compile time. + +The implementation currently provides the following possible options (various +others may be added later). + +=============== ============================================ +pragma description +=============== ============================================ +intdefine Reads in a build-time define as an integer +strdefine Reads in a build-time define as a string +=============== ============================================ + +.. code-block:: nim + const FooBar {.intdefine.}: int = 5 + echo FooBar + +.. code-block:: bash + nim c -d:FooBar=42 foobar.c + +In the above example, providing the -d flag causes the symbol +``FooBar`` to be overwritten at compile time, printing out 42. If the +``-d:FooBar=42`` were to be omitted, the default value of 5 would be +used. diff --git a/doc/nimc.rst b/doc/nimc.rst index 48dbaeb219..eb1beb549f 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -98,6 +98,11 @@ enable builds in release mode (``-d:release``) where certain safety checks are omitted for better performance. Another common use is the ``-d:ssl`` switch to activate `SSL sockets `_. +Additionally, you may pass a value along with the symbol: ``-d:x=y`` +which may be used in conjunction with the `compile time define +pragmas`_ +to override symbols during build time. + Configuration files ------------------- @@ -370,7 +375,10 @@ For example, to generate code for an `AVR`:idx: processor use this command:: For the ``standalone`` target one needs to provide a file ``panicoverride.nim``. See ``tests/manyloc/standalone/panicoverride.nim`` for an example -implementation. +implementation. Additionally, users should specify the +amount of heap space to use with the ``-d:StandaloneHeapSize=`` +command line switch. Note that the total heap size will be +`` * sizeof(float64)``. Nim for realtime systems diff --git a/web/news/version_0_15_released.rst b/web/news/version_0_15_released.rst index ecda59fcda..5c58e138b3 100644 --- a/web/news/version_0_15_released.rst +++ b/web/news/version_0_15_released.rst @@ -38,8 +38,14 @@ Library Additions Compiler Additions ------------------ +- The ``-d/--define`` flag can now optionally take a value to be used + by code at compile time. + Language Additions ------------------ +- Added ``{.intdefine.}`` and ``{.strdefine.}`` macros to make use of + (optional) compile time defines. + Bugfixes --------