diff options
-rw-r--r-- | compiler/nimrod.ini | 2 | ||||
-rw-r--r-- | lib/core/macros.nim | 6 | ||||
-rw-r--r-- | lib/impure/fenv.nim | 113 | ||||
-rw-r--r-- | lib/posix/posix.nim | 42 | ||||
-rw-r--r-- | lib/pure/future.nim | 57 | ||||
-rw-r--r-- | lib/pure/json.nim | 631 | ||||
-rw-r--r-- | lib/pure/math.nim | 13 | ||||
-rw-r--r-- | tools/niminst/nsis.tmpl | 13 |
8 files changed, 721 insertions, 156 deletions
diff --git a/compiler/nimrod.ini b/compiler/nimrod.ini index ae1c6053f..7135b3490 100644 --- a/compiler/nimrod.ini +++ b/compiler/nimrod.ini @@ -126,7 +126,7 @@ Files: "start.bat" BinPath: r"bin;dist\mingw\bin;dist" ; Section | dir | zipFile | size hint (in KB) | url | exe start menu entry -Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip" +Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|doc\overview.html" Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip" Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.1.3.zip|aporia\bin\aporia.exe" ; for now only NSIS supports optional downloads diff --git a/lib/core/macros.nim b/lib/core/macros.nim index e290cce32..455f99c9e 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -620,6 +620,8 @@ proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} = someProc[high(someProc)] = val else: badNodeKind someProc.kind, "body=" + +proc basename*(a: PNimrodNode): PNimrodNode {.compiletime.} proc `$`*(node: PNimrodNode): string {.compileTime.} = @@ -627,6 +629,8 @@ proc `$`*(node: PNimrodNode): string {.compileTime.} = case node.kind of nnkIdent: result = $node.ident + of nnkPostfix: + result = $node.basename.ident & "*" of nnkStrLit..nnkTripleStrLit: result = node.strVal else: @@ -669,7 +673,7 @@ proc insert*(a: PNimrodNode; pos: int; b: PNimrodNode) {.compileTime.} = a[i + 1] = a[i] a[pos] = b -proc basename*(a: PNimrodNode): PNimrodNode {.compiletime.} = +proc basename*(a: PNimrodNode): PNimrodNode = ## Pull an identifier from prefix/postfix expressions case a.kind of nnkIdent: return a diff --git a/lib/impure/fenv.nim b/lib/impure/fenv.nim new file mode 100644 index 000000000..9d7c8809b --- /dev/null +++ b/lib/impure/fenv.nim @@ -0,0 +1,113 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Floating-point environment. Handling of floating-point rounding and +## exceptions (overflow, zero-devide, etc.). + +{.deadCodeElim:on.} + +when defined(Posix) and not defined(haiku): + {.passl: "-lm".} + +var + FE_DIVBYZERO* {.importc, header: "<fenv.h>".}: cint + ## division by zero + FE_INEXACT* {.importc, header: "<fenv.h>".}: cint + ## inexact result + FE_INVALID* {.importc, header: "<fenv.h>".}: cint + ## invalid operation + FE_OVERFLOW* {.importc, header: "<fenv.h>".}: cint + ## result not representable due to overflow + FE_UNDERFLOW* {.importc, header: "<fenv.h>".}: cint + ## result not representable due to underflow + FE_ALL_EXCEPT* {.importc, header: "<fenv.h>".}: cint + ## bitwise OR of all supported exceptions + FE_DOWNWARD* {.importc, header: "<fenv.h>".}: cint + ## round toward -Inf + FE_TONEAREST* {.importc, header: "<fenv.h>".}: cint + ## round to nearest + FE_TOWARDZERO* {.importc, header: "<fenv.h>".}: cint + ## round toward 0 + FE_UPWARD* {.importc, header: "<fenv.h>".}: cint + ## round toward +Inf + FE_DFL_ENV* {.importc, header: "<fenv.h>".}: cint + ## macro of type pointer to fenv_t to be used as the argument + ## to functions taking an argument of type fenv_t; in this + ## case the default environment will be used + +type + TFloatClass* = enum ## describes the class a floating point value belongs to. + ## This is the type that is returned by `classify`. + fcNormal, ## value is an ordinary nonzero floating point value + fcSubnormal, ## value is a subnormal (a very small) floating point value + fcZero, ## value is zero + fcNegZero, ## value is the negative zero + fcNan, ## value is Not-A-Number (NAN) + fcInf, ## value is positive infinity + fcNegInf ## value is negative infinity + + Tfenv* {.importc: "fenv_t", header: "<fenv.h>", final, pure.} = + object ## Represents the entire floating-point environment. The + ## floating-point environment refers collectively to any + ## floating-point status flags and control modes supported + ## by the implementation. + Tfexcept* {.importc: "fexcept_t", header: "<fenv.h>", final, pure.} = + object ## Represents the floating-point status flags collectively, + ## including any status the implementation associates with the + ## flags. A floating-point status flag is a system variable + ## whose value is set (but never cleared) when a floating-point + ## exception is raised, which occurs as a side effect of + ## exceptional floating-point arithmetic to provide auxiliary + ## information. A floating-point control mode is a system variable + ## whose value may be set by the user to affect the subsequent + ## behavior of floating-point arithmetic. + +proc feclearexcept*(excepts: cint): cint {.importc, header: "<fenv.h>".} + ## Clear the supported exceptions represented by `excepts`. + +proc fegetexceptflag*(flagp: ptr Tfexcept, excepts: cint): cint {. + importc, header: "<fenv.h>".} + ## Store implementation-defined representation of the exception flags + ## indicated by `excepts` in the object pointed to by `flagp`. + +proc feraiseexcept*(excepts: cint): cint {.importc, header: "<fenv.h>".} + ## Raise the supported exceptions represented by `excepts`. + +proc fesetexceptflag*(flagp: ptr Tfexcept, excepts: cint): cint {. + importc, header: "<fenv.h>".} + ## Set complete status for exceptions indicated by `excepts` according to + ## the representation in the object pointed to by `flagp`. + +proc fetestexcept*(excepts: cint): cint {.importc, header: "<fenv.h>".} + ## Determine which of subset of the exceptions specified by `excepts` are + ## currently set. + +proc fegetround*(): cint {.importc, header: "<fenv.h>".} + ## Get current rounding direction. + +proc fesetround*(roundingDirection: cint): cint {.importc, header: "<fenv.h>".} + ## Establish the rounding direction represented by `roundingDirection`. + +proc fegetenv*(envp: ptr Tfenv): cint {.importc, header: "<fenv.h>".} + ## Store the current floating-point environment in the object pointed + ## to by `envp`. + +proc feholdexcept*(envp: ptr Tfenv): cint {.importc, header: "<fenv.h>".} + ## Save the current environment in the object pointed to by `envp`, clear + ## exception flags and install a non-stop mode (if available) for all + ## exceptions. + +proc fesetenv*(a1: ptr Tfenv): cint {.importc, header: "<fenv.h>".} + ## Establish the floating-point environment represented by the object + ## pointed to by `envp`. + +proc feupdateenv*(envp: ptr Tfenv): cint {.importc, header: "<fenv.h>".} + ## Save current exceptions in temporary storage, install environment + ## represented by object pointed to by `envp` and raise exceptions + ## according to saved exceptions. diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index e1bcd9dfc..9334ceeae 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -99,22 +99,6 @@ type l_pid*: TPid ## Process ID of the process holding the lock; ## returned with F_GETLK. - Tfenv* {.importc: "fenv_t", header: "<fenv.h>", final, pure.} = - object ## Represents the entire floating-point environment. The - ## floating-point environment refers collectively to any - ## floating-point status flags and control modes supported - ## by the implementation. - Tfexcept* {.importc: "fexcept_t", header: "<fenv.h>", final, pure.} = - object ## Represents the floating-point status flags collectively, - ## including any status the implementation associates with the - ## flags. A floating-point status flag is a system variable - ## whose value is set (but never cleared) when a floating-point - ## exception is raised, which occurs as a side effect of - ## exceptional floating-point arithmetic to provide auxiliary - ## information. A floating-point control mode is a system variable - ## whose value may be set by the user to affect the subsequent - ## behavior of floating-point arithmetic. - TFTW* {.importc: "struct FTW", header: "<ftw.h>", final, pure.} = object base*: cint level*: cint @@ -834,18 +818,6 @@ var ## The application expects to access the specified data once and ## then not reuse it thereafter. - FE_DIVBYZERO* {.importc, header: "<fenv.h>".}: cint - FE_INEXACT* {.importc, header: "<fenv.h>".}: cint - FE_INVALID* {.importc, header: "<fenv.h>".}: cint - FE_OVERFLOW* {.importc, header: "<fenv.h>".}: cint - FE_UNDERFLOW* {.importc, header: "<fenv.h>".}: cint - FE_ALL_EXCEPT* {.importc, header: "<fenv.h>".}: cint - FE_DOWNWARD* {.importc, header: "<fenv.h>".}: cint - FE_TONEAREST* {.importc, header: "<fenv.h>".}: cint - FE_TOWARDZERO* {.importc, header: "<fenv.h>".}: cint - FE_UPWARD* {.importc, header: "<fenv.h>".}: cint - FE_DFL_ENV* {.importc, header: "<fenv.h>".}: cint - when not defined(haiku) and not defined(OpenBSD): var MM_HARD* {.importc, header: "<fmtmsg.h>".}: cint @@ -1821,20 +1793,6 @@ proc posix_fadvise*(a1: cint, a2, a3: TOff, a4: cint): cint {. proc posix_fallocate*(a1: cint, a2, a3: TOff): cint {. importc, header: "<fcntl.h>".} -proc feclearexcept*(a1: cint): cint {.importc, header: "<fenv.h>".} -proc fegetexceptflag*(a1: ptr Tfexcept, a2: cint): cint {. - importc, header: "<fenv.h>".} -proc feraiseexcept*(a1: cint): cint {.importc, header: "<fenv.h>".} -proc fesetexceptflag*(a1: ptr Tfexcept, a2: cint): cint {. - importc, header: "<fenv.h>".} -proc fetestexcept*(a1: cint): cint {.importc, header: "<fenv.h>".} -proc fegetround*(): cint {.importc, header: "<fenv.h>".} -proc fesetround*(a1: cint): cint {.importc, header: "<fenv.h>".} -proc fegetenv*(a1: ptr Tfenv): cint {.importc, header: "<fenv.h>".} -proc feholdexcept*(a1: ptr Tfenv): cint {.importc, header: "<fenv.h>".} -proc fesetenv*(a1: ptr Tfenv): cint {.importc, header: "<fenv.h>".} -proc feupdateenv*(a1: ptr Tfenv): cint {.importc, header: "<fenv.h>".} - when not defined(haiku) and not defined(OpenBSD): proc fmtmsg*(a1: int, a2: cstring, a3: cint, a4, a5, a6: cstring): cint {.importc, header: "<fmtmsg.h>".} diff --git a/lib/pure/future.nim b/lib/pure/future.nim index b7df05207..480ee2b0d 100644 --- a/lib/pure/future.nim +++ b/lib/pure/future.nim @@ -115,3 +115,60 @@ macro `->`*(p, b: expr): expr {.immediate.} = ## f(2, 2) result = createProcType(p, b) + +type ListComprehension = object +var lc*: ListComprehension + +macro `[]`*(lc: ListComprehension, comp, typ: expr): expr = + ## List comprehension, returns a sequence. `comp` is the actual list + ## comprehension, for example ``x | (x <- 1..10, x mod 2 == 0)``. `typ` is + ## the type that will be stored inside the result seq. + ## + ## .. code-block:: nimrod + ## + ## echo lc[x | (x <- 1..10, x mod 2 == 0), int] + ## + ## const n = 20 + ## echo lc[(x,y,z) | (x <- 1..n, y <- x..n, z <- y..n, x*x + y*y == z*z), + ## tuple[a,b,c: int]] + + expectLen(comp, 3) + expectKind(comp, nnkInfix) + expectKind(comp[0], nnkIdent) + assert($comp[0].ident == "|") + + result = newCall( + newDotExpr( + newIdentNode("result"), + newIdentNode("add")), + comp[1]) + + for i in countdown(comp[2].len-1, 0): + let x = comp[2][i] + expectKind(x, nnkInfix) + expectMinLen(x, 1) + if x[0].kind == nnkIdent and $x[0].ident == "<-": + expectLen(x, 3) + result = newNimNode(nnkForStmt).add(x[1], x[2], result) + else: + result = newIfStmt((x, result)) + + result = newNimNode(nnkCall).add( + newNimNode(nnkPar).add( + newNimNode(nnkLambda).add( + newEmptyNode(), + newEmptyNode(), + newEmptyNode(), + newNimNode(nnkFormalParams).add( + newNimNode(nnkBracketExpr).add( + newIdentNode("seq"), + typ)), + newEmptyNode(), + newEmptyNode(), + newStmtList( + newAssignment( + newIdentNode("result"), + newNimNode(nnkPrefix).add( + newIdentNode("@"), + newNimNode(nnkBracket))), + result)))) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index a45900f29..5d51c2d87 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -7,47 +7,71 @@ # distribution, for details about the copyright. # -## This module implements a simple high performance `JSON`:idx: -## parser. JSON (JavaScript Object Notation) is a lightweight -## data-interchange format that is easy for humans to read and write -## (unlike XML). It is easy for machines to parse and generate. -## JSON is based on a subset of the JavaScript Programming Language, -## Standard ECMA-262 3rd Edition - December 1999. +## This module implements a simple high performance `JSON`:idx: parser. `JSON +## (JavaScript Object Notation) <http://www.json.org>`_ is a lightweight +## data-interchange format that is easy for humans to read and write (unlike +## XML). It is easy for machines to parse and generate. JSON is based on a +## subset of the JavaScript Programming Language, `Standard ECMA-262 3rd +## Edition - December 1999 +## <http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf>`_. ## -## Usage example: +## Parsing small values quickly can be done with the convenience `parseJson() +## <#parseJson,string>`_ proc which returns the whole JSON tree. If you are +## parsing very big JSON inputs or want to skip most of the items in them you +## can initialize your own `TJsonParser <#TJsonParser>`_ with the `open() +## <#open>`_ proc and call `next() <#next>`_ in a loop to process the +## individual parsing events. +## +## If you need to create JSON objects from your Nimrod types you can call procs +## like `newJObject() <#newJObject>`_ (or their equivalent `%() +## <#%,openArray[tuple[string,PJsonNode]]>`_ generic constructor). For +## consistency you can provide your own ``%`` operators for custom object +## types: ## ## .. code-block:: nimrod -## let -## small_json = """{"test": 1.3, "key2": true}""" -## jobj = parseJson(small_json) -## assert (jobj.kind == JObject) -## echo($jobj["test"].fnum) -## echo($jobj["key2"].bval) +## type +## Person = object ## Generic person record. +## age: int ## The age of the person. +## name: string ## The name of the person. ## -## Results in: +## proc `%`(p: Person): PJsonNode = +## ## Converts a Person into a PJsonNode. +## result = %[("age", %p.age), ("name", %p.name)] ## -## .. code-block:: nimrod +## proc test() = +## # Tests making some jsons. +## var p: Person +## p.age = 24 +## p.name = "Minah" +## echo(%p) # { "age": 24, "name": "Minah"} +## +## p.age = 33 +## p.name = "Sojin" +## echo(%p) # { "age": 33, "name": "Sojin"} ## -## 1.3000000000000000e+00 -## true +## If you don't need special logic in your Nimrod objects' serialization code +## you can also use the `marshal module <marshal.html>`_ which converts objects +## directly to JSON. import hashes, strutils, lexbase, streams, unicode type - TJsonEventKind* = enum ## enumeration of all events that may occur when parsing - jsonError, ## an error ocurred during parsing - jsonEof, ## end of file reached - jsonString, ## a string literal - jsonInt, ## an integer literal - jsonFloat, ## a float literal - jsonTrue, ## the value ``true`` - jsonFalse, ## the value ``false`` - jsonNull, ## the value ``null`` - jsonObjectStart, ## start of an object: the ``{`` token - jsonObjectEnd, ## end of an object: the ``}`` token - jsonArrayStart, ## start of an array: the ``[`` token - jsonArrayEnd ## start of an array: the ``]`` token + TJsonEventKind* = enum ## Events that may occur when parsing. \ + ## + ## You compare these values agains the result of the `kind() proc <#kind>`_. + jsonError, ## An error ocurred during parsing. + jsonEof, ## End of file reached. + jsonString, ## A string literal. + jsonInt, ## An integer literal. + jsonFloat, ## A float literal. + jsonTrue, ## The value ``true``. + jsonFalse, ## The value ``false``. + jsonNull, ## The value ``null``. + jsonObjectStart, ## Start of an object: the ``{`` token. + jsonObjectEnd, ## End of an object: the ``}`` token. + jsonArrayStart, ## Start of an array: the ``[`` token. + jsonArrayEnd ## Start of an array: the ``]`` token. TTokKind = enum # must be synchronized with TJsonEventKind! tkError, @@ -65,7 +89,7 @@ type tkColon, tkComma - TJsonError* = enum ## enumeration that lists all errors that can occur + TJsonError = enum ## enumeration that lists all errors that can occur errNone, ## no error errInvalidToken, ## invalid token errStringExpected, ## string expected @@ -82,7 +106,9 @@ type stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma, stateExpectObjectComma, stateExpectColon, stateExpectValue - TJsonParser* = object of TBaseLexer ## the parser object. + TJsonParser* = object of TBaseLexer ## The JSON parser object. \ + ## + ## Create a variable of this type and use `open() <#open>`_ on it. a: string tok: TTokKind kind: TJsonEventKind @@ -117,59 +143,129 @@ const ] proc open*(my: var TJsonParser, input: PStream, filename: string) = - ## initializes the parser with an input stream. `Filename` is only used - ## for nice error messages. - lexbase.open(my, input) + ## Initializes the JSON parser with an `input stream <streams.html>`_. + ## + ## The `filename` parameter is not strictly required and is used only for + ## nice error messages. You can pass ``nil`` as long as you never use procs + ## like `errorMsg() <#errorMsg>`_ or `errorMsgExpected() + ## <#errorMsgExpected>`_ but passing a dummy filename like ``<input string>`` + ## is safer and more user friendly. Example: + ## + ## .. code-block:: nimrod + ## import json, streams + ## + ## var + ## s = newStringStream("some valid json") + ## p: TJsonParser + ## p.open(s, "<input string>") + ## + ## Once opened, you can process JSON parsing events with the `next() + ## <#next>`_ proc. my.filename = filename my.state = @[stateStart] my.kind = jsonError my.a = "" -proc close*(my: var TJsonParser) {.inline.} = - ## closes the parser `my` and its associated input stream. +proc close*(my: var TJsonParser) {.inline.} = + ## Closes the parser `my` and its associated input stream. + ## + ## Example: + ## + ## .. code-block:: nimrod + ## var + ## s = newStringStream("some valid json") + ## p: TJsonParser + ## p.open(s, "<input string>") + ## finally: p.close + ## # write here parsing of input lexbase.close(my) proc str*(my: TJsonParser): string {.inline.} = - ## returns the character data for the events: ``jsonInt``, ``jsonFloat``, - ## ``jsonString`` + ## Returns the character data for the `events <#TJsonEventKind>`_ + ## ``jsonInt``, ``jsonFloat`` and ``jsonString``. + ## + ## This proc will `assert <system.html#assert>`_ in debug builds when used + ## with other event types. See `next() <#next>`_ for an usage example. assert(my.kind in {jsonInt, jsonFloat, jsonString}) return my.a proc getInt*(my: TJsonParser): BiggestInt {.inline.} = - ## returns the number for the event: ``jsonInt`` + ## Returns the number for the `jsonInt <#TJsonEventKind>`_ event. + ## + ## This proc will `assert <system.html#assert>`_ in debug builds when used + ## with other event types. See `next() <#next>`_ for an usage example. assert(my.kind == jsonInt) return parseBiggestInt(my.a) proc getFloat*(my: TJsonParser): float {.inline.} = - ## returns the number for the event: ``jsonFloat`` + ## Returns the number for the `jsonFloat <#TJsonEventKind>`_ event. + ## + ## This proc will `assert <system.html#assert>`_ in debug builds when used + ## with other event types. See `next() <#next>`_ for an usage example. assert(my.kind == jsonFloat) return parseFloat(my.a) proc kind*(my: TJsonParser): TJsonEventKind {.inline.} = - ## returns the current event type for the JSON parser + ## Returns the current event type for the `JSON parser <#TJsonParser>`_. + ## + ## Call this proc just after `next() <#next>`_ to act on the new event. return my.kind proc getColumn*(my: TJsonParser): int {.inline.} = - ## get the current column the parser has arrived at. + ## Get the current column the parser has arrived at. + ## + ## While this is mostly used by procs like `errorMsg() <#errorMsg>`_ you can + ## use it as well to show user warnings if you are validating JSON values + ## during parsing. See `next() <#next>`_ for the full example: + ## + ## .. code-block:: nimrod + ## case parser.kind + ## ... + ## of jsonString: + ## let inputValue = parser.str + ## if previousValues.contains(inputValue): + ## echo "$1($2, $3) Warning: repeated value '$4'" % [ + ## parser.getFilename, $parser.getLine, $parser.getColumn, + ## inputValue] + ## ... result = getColNumber(my, my.bufpos) proc getLine*(my: TJsonParser): int {.inline.} = - ## get the current line the parser has arrived at. + ## Get the current line the parser has arrived at. + ## + ## While this is mostly used by procs like `errorMsg() <#errorMsg>`_ you can + ## use it as well to indicate user warnings if you are validating JSON values + ## during parsing. See `next() <#next>`_ and `getColumn() <#getColumn>`_ for + ## examples. result = my.lineNumber proc getFilename*(my: TJsonParser): string {.inline.} = - ## get the filename of the file that the parser processes. + ## Get the filename of the file that the parser is processing. + ## + ## This is the value you pass to the `open() <#open>`_ proc. While this is + ## mostly used by procs like `errorMsg() <#errorMsg>`_ you can use it as well + ## to indicate user warnings if you are validating JSON values during + ## parsing. See `next() <#next>`_ and `getColumn() <#getColumn>`_ for + ## examples. result = my.filename proc errorMsg*(my: TJsonParser): string = - ## returns a helpful error message for the event ``jsonError`` + ## Returns a helpful error message for the `jsonError <#TJsonEventKind>`_ + ## event. + ## + ## This proc will `assert <system.html#assert>`_ in debug builds when used + ## with other event types. See `next() <#next>`_ for an usage example. assert(my.kind == jsonError) result = "$1($2, $3) Error: $4" % [ my.filename, $getLine(my), $getColumn(my), errorMessages[my.err]] proc errorMsgExpected*(my: TJsonParser, e: string): string = - ## returns an error message "`e` expected" in the same format as the - ## other error messages + ## Returns an error message "`e` expected". + ## + ## The message is in the same format as the other error messages which + ## include the parser filename, line and column values. This is used by + ## `raiseParseErr() <#raiseParseErr>`_ to raise an `EJsonParsingError + ## <#EJsonParsingError>`_. result = "$1($2, $3) Error: $4" % [ my.filename, $getLine(my), $getColumn(my), e & " expected"] @@ -382,7 +478,32 @@ proc getTok(my: var TJsonParser): TTokKind = my.tok = result proc next*(my: var TJsonParser) = - ## retrieves the first/next event. This controls the parser. + ## Retrieves the first/next event for the `JSON parser <#TJsonParser>`_. + ## + ## You are meant to call this method inside an infinite loop. After each + ## call, check the result of the `kind() <#kind>`_ proc to know what has to + ## be done next (eg. break out due to end of file). Here is a basic example + ## which simply echoes all found elements by the parser: + ## + ## .. code-block:: nimrod + ## parser.open(stream, "<input string>") + ## while true: + ## parser.next + ## case parser.kind + ## of jsonError: + ## echo parser.errorMsg + ## break + ## of jsonEof: break + ## of jsonString: echo parser.str + ## of jsonInt: echo parser.getInt + ## of jsonFloat: echo parser.getFloat + ## of jsonTrue: echo "true" + ## of jsonFalse: echo "false" + ## of jsonNull: echo "null" + ## of jsonObjectStart: echo "{" + ## of jsonObjectEnd: echo "}" + ## of jsonArrayStart: echo "[" + ## of jsonArrayEnd: echo "]" var tk = getTok(my) var i = my.state.len-1 # the following code is a state machine. If we had proper coroutines, @@ -502,7 +623,16 @@ proc next*(my: var TJsonParser) = # ------------- higher level interface --------------------------------------- type - TJsonNodeKind* = enum ## possible JSON node types + TJsonNodeKind* = enum ## Possible `JSON node <#TJsonNodeKind>`_ types. \ + ## + ## To build nodes use the helper procs + ## `newJNull() <#newJNull>`_, + ## `newJBool() <#newJBool>`_, + ## `newJInt() <#newJInt>`_, + ## `newJFloat() <#newJFloat>`_, + ## `newJString() <#newJString>`_, + ## `newJObject() <#newJObject>`_ and + ## `newJArray() <#newJArray>`_. JNull, JBool, JInt, @@ -511,8 +641,9 @@ type JObject, JArray - PJsonNode* = ref TJsonNode ## JSON node - TJsonNode* {.final, pure, acyclic.} = object + PJsonNode* = ref TJsonNode ## Reference to a `JSON node <#TJsonNode>`_. + TJsonNode* {.final, pure, acyclic.} = object ## `Object variant \ + ## <manual.html#object-variants>`_ wrapping all possible JSON types. case kind*: TJsonNodeKind of JString: str*: string @@ -529,14 +660,36 @@ type of JArray: elems*: seq[PJsonNode] - EJsonParsingError* = object of EInvalidValue ## is raised for a JSON error + EJsonParsingError* = object of EInvalidValue ## Raised during JSON parsing. \ + ## + ## Example: + ## + ## .. code-block:: nimrod + ## let smallJson = """{"test: 1.3, "key2": true}""" + ## try: + ## discard parseJson(smallJson) + ## # --> Bad JSON! input(1, 18) Error: : expected + ## except EJsonParsingError: + ## echo "Bad JSON! " & getCurrentExceptionMsg() proc raiseParseErr*(p: TJsonParser, msg: string) {.noinline, noreturn.} = - ## raises an `EJsonParsingError` exception. + ## Raises an `EJsonParsingError <#EJsonParsingError>`_ exception. + ## + ## The message for the exception will be built passing the `msg` parameter to + ## the `errorMsgExpected() <#errorMsgExpected>`_ proc. raise newException(EJsonParsingError, errorMsgExpected(p, msg)) proc newJString*(s: string): PJsonNode = - ## Creates a new `JString PJsonNode`. + ## Creates a new `JString PJsonNode <#TJsonNodeKind>`_. + ## + ## Example: + ## + ## .. code-block:: nimrod + ## var node = newJString("A string") + ## echo node + ## # --> "A string" + ## + ## Or you can use the shorter `%() proc <#%,string>`_. new(result) result.kind = JString result.str = s @@ -547,80 +700,206 @@ proc newJStringMove(s: string): PJsonNode = shallowCopy(result.str, s) proc newJInt*(n: BiggestInt): PJsonNode = - ## Creates a new `JInt PJsonNode`. + ## Creates a new `JInt PJsonNode <#TJsonNodeKind>`_. + ## + ## Example: + ## + ## .. code-block:: nimrod + ## var node = newJInt(900_100_200_300) + ## echo node + ## # --> 900100200300 + ## + ## Or you can use the shorter `%() proc <#%,BiggestInt>`_. new(result) result.kind = JInt result.num = n proc newJFloat*(n: float): PJsonNode = - ## Creates a new `JFloat PJsonNode`. + ## Creates a new `JFloat PJsonNode <#TJsonNodeKind>`_. + ## + ## Example: + ## + ## .. code-block:: nimrod + ## var node = newJFloat(3.14) + ## echo node + ## # --> 3.14 + ## + ## Or you can use the shorter `%() proc <#%,float>`_. new(result) result.kind = JFloat result.fnum = n proc newJBool*(b: bool): PJsonNode = - ## Creates a new `JBool PJsonNode`. + ## Creates a new `JBool PJsonNode <#TJsonNodeKind>`_. + ## + ## Example: + ## + ## .. code-block:: nimrod + ## var node = newJBool(true) + ## echo node + ## # --> true + ## + ## Or you can use the shorter `%() proc <#%,bool>`_. new(result) result.kind = JBool result.bval = b proc newJNull*(): PJsonNode = - ## Creates a new `JNull PJsonNode`. + ## Creates a new `JNull PJsonNode <#TJsonNodeKind>`_. + ## + ## Example: + ## + ## .. code-block:: nimrod + ## var node = newJNull() + ## echo node + ## # --> null new(result) proc newJObject*(): PJsonNode = - ## Creates a new `JObject PJsonNode` + ## Creates a new `JObject PJsonNode <#TJsonNodeKind>`_. + ## + ## The `PJsonNode <#PJsonNode>`_ will be initialized with an empty ``fields`` + ## sequence to which you can add new elements. Example: + ## + ## .. code-block:: nimrod + ## var node = newJObject() + ## node.add("age", newJInt(24)) + ## node.add("name", newJString("Minah")) + ## echo node + ## # --> { "age": 24, "name": "Minah"} + ## + ## Or you can use the shorter `%() proc + ## <#%,openArray[tuple[string,PJsonNode]]>`_. new(result) result.kind = JObject result.fields = @[] proc newJArray*(): PJsonNode = - ## Creates a new `JArray PJsonNode` + ## Creates a new `JArray PJsonNode <#TJsonNodeKind>`_. + ## + ## The `PJsonNode <#PJsonNode>`_ will be initialized with an empty ``elems`` + ## sequence to which you can add new elements. Example: + ## + ## .. code-block:: nimrod + ## var node = newJArray() + ## node.add(newJString("Mixing types")) + ## node.add(newJInt(42)) + ## node.add(newJString("is madness")) + ## node.add(newJFloat(3.14)) + ## echo node + ## # --> [ "Mixing types", 42, "is madness", 3.14] + ## + ## Or you can use the shorter `%() proc <#%,openArray[PJsonNode]>`_. new(result) result.kind = JArray result.elems = @[] proc `%`*(s: string): PJsonNode = - ## Generic constructor for JSON data. Creates a new `JString PJsonNode`. + ## Creates a new `JString PJsonNode <#TJsonNodeKind>`_. + ## + ## Example: + ## + ## .. code-block:: nimrod + ## var node = %"A string" + ## echo node + ## # --> "A string" + ## + ## This generic constructor is equivalent to the `newJString() + ## <#newJString>`_ proc. new(result) result.kind = JString result.str = s proc `%`*(n: BiggestInt): PJsonNode = - ## Generic constructor for JSON data. Creates a new `JInt PJsonNode`. + ## Creates a new `JInt PJsonNode <#TJsonNodeKind>`_. + ## + ## Example: + ## + ## .. code-block:: nimrod + ## var node = %900_100_200_300 + ## echo node + ## # --> 900100200300 + ## + ## This generic constructor is equivalent to the `newJInt() <#newJInt>`_ + ## proc. new(result) result.kind = JInt result.num = n proc `%`*(n: float): PJsonNode = - ## Generic constructor for JSON data. Creates a new `JFloat PJsonNode`. + ## Creates a new `JFloat PJsonNode <#TJsonNodeKind>`_. + ## + ## Example: + ## + ## .. code-block:: nimrod + ## var node = %3.14 + ## echo node + ## # --> 3.14 + ## + ## This generic constructor is equivalent to the `newJFloat() <#newJFloat>`_ + ## proc. new(result) result.kind = JFloat result.fnum = n proc `%`*(b: bool): PJsonNode = - ## Generic constructor for JSON data. Creates a new `JBool PJsonNode`. + ## Creates a new `JBool PJsonNode <#TJsonNodeKind>`_. + ## + ## Example: + ## + ## .. code-block:: nimrod + ## var node = %true + ## echo node + ## # --> true + ## + ## This generic constructor is equivalent to the `newJBool() <#newJBool>`_ + ## proc. new(result) result.kind = JBool result.bval = b proc `%`*(keyVals: openArray[tuple[key: string, val: PJsonNode]]): PJsonNode = - ## Generic constructor for JSON data. Creates a new `JObject PJsonNode` + ## Creates a new `JObject PJsonNode <#TJsonNodeKind>`_. + ## + ## Unlike the `newJObject() <#newJObject>`_ proc, which returns an object + ## that has to be further manipulated, you can use this generic constructor + ## to create JSON objects with all their fields in one go. Example: + ## + ## .. code-block:: nimrod + ## let node = %[("age", %24), ("name", %"Minah")] + ## echo node + ## # --> { "age": 24, "name": "Minah"} new(result) result.kind = JObject newSeq(result.fields, keyVals.len) for i, p in pairs(keyVals): result.fields[i] = p proc `%`*(elements: openArray[PJsonNode]): PJsonNode = - ## Generic constructor for JSON data. Creates a new `JArray PJsonNode` + ## Creates a new `JArray PJsonNode <#TJsonNodeKind>`_. + ## + ## Unlike the `newJArray() <#newJArray>`_ proc, which returns an object + ## that has to be further manipulated, you can use this generic constructor + ## to create JSON arrays with all their values in one go. Example: + ## + ## .. code-block:: nimrod + ## let node = %[%"Mixing types", %42, + ## %"is madness", %3.14,] + ## echo node + ## # --> [ "Mixing types", 42, "is madness", 3.14] new(result) result.kind = JArray newSeq(result.elems, elements.len) for i, p in pairs(elements): result.elems[i] = p proc `==`* (a,b: PJsonNode): bool = - ## Check two nodes for equality + ## Check two `PJsonNode <#PJsonNode>`_ nodes for equality. + ## + ## Example: + ## + ## .. code-block:: nimrod + ## assert(%1 == %1) + ## assert(%1 != %2) if a.isNil: if b.isNil: return true return false @@ -644,7 +923,21 @@ proc `==`* (a,b: PJsonNode): bool = a.fields == b.fields proc hash* (n:PJsonNode): THash = - ## Compute the hash for a JSON node + ## Computes the hash for a JSON node. + ## + ## The `THash <hashes.html#THash>`_ allows JSON nodes to be used as keys for + ## `sets <sets.html>`_ or `tables <tables.html>`_. Example: + ## + ## .. code-block:: nimrod + ## import json, sets + ## + ## var + ## uniqueValues = initSet[PJsonNode]() + ## values = %[%1, %2, %1, %2, %3] + ## for value in values.elems: + ## discard uniqueValues.containsOrIncl(value) + ## echo uniqueValues + ## # --> {1, 2, 3} case n.kind of JArray: result = hash(n.elems) @@ -662,17 +955,40 @@ proc hash* (n:PJsonNode): THash = result = hash(0) proc len*(n: PJsonNode): int = - ## If `n` is a `JArray`, it returns the number of elements. - ## If `n` is a `JObject`, it returns the number of pairs. - ## Else it returns 0. + ## Returns the number of children items for this `PJsonNode <#PJsonNode>`_. + ## + ## If `n` is a `JArray <#TJsonNodeKind>`_, it will return the number of + ## elements. If `n` is a `JObject <#TJsonNodeKind>`_, it will return the + ## number of key-value pairs. For all other types this proc returns zero. + ## Example: + ## + ## .. code-block:: nimrod + ## let + ## n1 = %[("age", %33), ("name", %"Sojin")] + ## n2 = %[%1, %2, %3, %4, %5, %6, %7] + ## n3 = %"Some odd string we have here" + ## echo n1.len # --> 2 + ## echo n2.len # --> 7 + ## echo n3.len # --> 0 + ## case n.kind of JArray: result = n.elems.len of JObject: result = n.fields.len else: discard proc `[]`*(node: PJsonNode, name: string): PJsonNode = - ## Gets a field from a `JObject`, which must not be nil. - ## If the value at `name` does not exist, returns nil + ## Gets a named field from a `JObject <#TJsonNodeKind>`_ `PJsonNode + ## <#PJsonNode>`_. + ## + ## Returns the value for `name` or nil if `node` doesn't contain such a + ## field. This proc will `assert <system.html#assert>`_ in debug builds if + ## `name` is ``nil`` or `node` is not a ``JObject``. On release builds it + ## will likely crash. Example: + ## + ## .. code-block:: nimrod + ## let node = %[("age", %40), ("name", %"Britney")] + ## echo node["name"] + ## # --> "Britney" assert(not isNil(node)) assert(node.kind == JObject) for key, item in items(node.fields): @@ -681,35 +997,92 @@ proc `[]`*(node: PJsonNode, name: string): PJsonNode = return nil proc `[]`*(node: PJsonNode, index: int): PJsonNode = - ## Gets the node at `index` in an Array. Result is undefined if `index` - ## is out of bounds + ## Gets the `index` item from a `JArray <#TJsonNodeKind>`_ `PJsonNode + ## <#PJsonNode>`_. + ## + ## Returns the specified item. Result is undefined if `index` is out of + ## bounds. This proc will `assert <system.html#assert>`_ in debug builds if + ## `node` is ``nil`` or not a ``JArray``. Example: + ## + ## .. code-block:: nimrod + ## let node = %[%"Mixing types", %42, + ## %"is madness", %3.14,] + ## echo node[2] + ## # --> "is madness" assert(not isNil(node)) assert(node.kind == JArray) return node.elems[index] proc hasKey*(node: PJsonNode, key: string): bool = - ## Checks if `key` exists in `node`. + ## Returns `true` if `key` exists in a `JObject <#TJsonNodeKind>`_ `PJsonNode + ## <#PJsonNode>`_. + ## + ## This proc will `assert <system.html#assert>`_ in debug builds if `node` is + ## not a ``JObject``. On release builds it will likely crash. Example: + ## + ## .. code-block:: nimrod + ## let node = %[("age", %40), ("name", %"Britney")] + ## echo node.hasKey("email") + ## # --> false assert(node.kind == JObject) for k, item in items(node.fields): if k == key: return true proc existsKey*(node: PJsonNode, key: string): bool {.deprecated.} = node.hasKey(key) - ## Deprecated for `hasKey` + ## Deprecated for `hasKey() <#hasKey>`_. proc add*(father, child: PJsonNode) = - ## Adds `child` to a JArray node `father`. + ## Adds `child` to a `JArray <#TJsonNodeKind>`_ `PJsonNode <#PJsonNode>`_ + ## `father` node. + ## + ## This proc will `assert <system.html#assert>`_ in debug builds if `node` is + ## not a ``JArray``. On release builds it will likely crash. Example: + ## + ## .. code-block:: nimrod + ## var node = %[%"Mixing types", %42] + ## node.add(%"is madness") + ## echo node + ## # --> false assert father.kind == JArray father.elems.add(child) proc add*(obj: PJsonNode, key: string, val: PJsonNode) = - ## Adds ``(key, val)`` pair to the JObject node `obj`. For speed - ## reasons no check for duplicate keys is performed! - ## But ``[]=`` performs the check. + ## Adds ``(key, val)`` pair to a `JObject <#TJsonNodeKind>`_ `PJsonNode + ## <#PJsonNode>`_ `obj` node. + ## + ## For speed reasons no check for duplicate keys is performed! But ``[]=`` + ## performs the check. + ## + ## This proc will `assert <system.html#assert>`_ in debug builds if `node` is + ## not a ``JObject``. On release builds it will likely crash. Example: + ## + ## .. code-block:: nimrod + ## var node = newJObject() + ## node.add("age", newJInt(12)) + ## # This is wrong! But we need speed… + ## node.add("age", newJInt(24)) + ## echo node + ## # --> { "age": 12, "age": 24} assert obj.kind == JObject obj.fields.add((key, val)) proc `[]=`*(obj: PJsonNode, key: string, val: PJsonNode) = - ## Sets a field from a `JObject`. Performs a check for duplicate keys. + ## Sets a field from a `JObject <#TJsonNodeKind>`_ `PJsonNode + ## <#PJsonNode>`_ `obj` node. + ## + ## Unlike the `add() <#add,PJsonNode,string,PJsonNode>`_ proc this will + ## perform a check for duplicate keys and replace existing values. + ## + ## This proc will `assert <system.html#assert>`_ in debug builds if `node` is + ## not a ``JObject``. On release builds it will likely crash. Example: + ## + ## .. code-block:: nimrod + ## var node = newJObject() + ## node["age"] = %12 + ## # The new value replaces the previous one. + ## node["age"] = %24 + ## echo node + ## # --> { "age": 24} assert(obj.kind == JObject) for i in 0..obj.fields.len-1: if obj.fields[i].key == key: @@ -736,6 +1109,18 @@ proc `{}=`*(node: PJsonNode, names: varargs[string], value: PJsonNode) = proc delete*(obj: PJsonNode, key: string) = ## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs. + ## + ## If `key` doesn't exist in `obj` ``EInvalidIndex`` will be raised. This + ## proc will `assert <system.html#assert>`_ in debug builds if `node` is not + ## a ``JObject``. On release builds it will likely crash. Example: + ## + ## .. code-block:: nimrod + ## var node = %[("age", %37), ("name", %"Chris"), ("male", %false)] + ## echo node + ## # --> { "age": 37, "name": "Chris", "male": false} + ## node.delete("age") + ## echo node + ## # --> { "name": "Chris", "male": false} assert(obj.kind == JObject) for i in 0..obj.fields.len-1: if obj.fields[i].key == key: @@ -744,7 +1129,9 @@ proc delete*(obj: PJsonNode, key: string) = raise newException(EInvalidIndex, "key not in object") proc copy*(p: PJsonNode): PJsonNode = - ## Performs a deep copy of `a`. + ## Performs a deep copy of `p`. + ## + ## Modifications to the copy won't affect the original. case p.kind of JString: result = newJString(p.str) @@ -779,6 +1166,12 @@ proc nl(s: var string, ml: bool) = proc escapeJson*(s: string): string = ## Converts a string `s` to its JSON representation. + ## + ## Example: + ## + ## .. code-block:: nimrod + ## echo """name: "Torbjørn"""".escapeJson + ## # --> "name: \"Torbj\u00F8rn\"" result = newStringOfCap(s.len + s.len shr 3) result.add("\"") for x in runes(s): @@ -850,24 +1243,58 @@ proc toPretty(result: var string, node: PJsonNode, indent = 2, ml = true, result.add("null") proc pretty*(node: PJsonNode, indent = 2): string = - ## Converts `node` to its JSON Representation, with indentation and - ## on multiple lines. + ## Converts `node` to a pretty JSON representation. + ## + ## The representation will have indentation use multiple lines. Example: + ## + ## .. code-block:: nimrod + ## let node = %[("age", %33), ("name", %"Sojin")] + ## echo node + ## # --> { "age": 33, "name": "Sojin"} + ## echo node.pretty + ## # --> { + ## # "age": 33, + ## # "name": "Sojin" + ## # } result = "" toPretty(result, node, indent) proc `$`*(node: PJsonNode): string = - ## Converts `node` to its JSON Representation on one line. + ## Converts `node` to its JSON representation on one line. result = "" toPretty(result, node, 1, false) iterator items*(node: PJsonNode): PJsonNode = - ## Iterator for the items of `node`. `node` has to be a JArray. + ## Iterator for the items of `node`. + ## + ## This proc will `assert <system.html#assert>`_ in debug builds if `node` is + ## not a `JArray <#TJsonNodeKind>`_. On release builds it will likely crash. + ## Example: + ## + ## .. code-block:: nimrod + ## let numbers = %[%1, %2, %3] + ## for n in numbers.items: + ## echo "Number ", n + ## ## --> Number 1 + ## ## Number 2 + ## ## Number 3 assert node.kind == JArray for i in items(node.elems): yield i iterator pairs*(node: PJsonNode): tuple[key: string, val: PJsonNode] = - ## Iterator for the child elements of `node`. `node` has to be a JObject. + ## Iterator for the child elements of `node`. + ## + ## This proc will `assert <system.html#assert>`_ in debug builds if `node` is + ## not a `JObject <#TJsonNodeKind>`_. On release builds it will likely crash. + ## Example: + ## + ## .. code-block:: nimrod + ## var node = %[("age", %37), ("name", %"Chris")] + ## for key, value in node.pairs: + ## echo "Key: ", key, ", value: ", value + ## # --> Key: age, value: 37 + ## # Key: name, value: "Chris" assert node.kind == JObject for key, val in items(node.fields): yield (key, val) @@ -926,8 +1353,12 @@ proc parseJson(p: var TJsonParser): PJsonNode = when not defined(js): proc parseJson*(s: PStream, filename: string): PJsonNode = - ## Parses from a stream `s` into a `PJsonNode`. `filename` is only needed - ## for nice error messages. + ## Generic convenience proc to parse stream `s` into a `PJsonNode`. + ## + ## This wraps around `open() <#open>`_ and `next() <#next>`_ to return the + ## full JSON DOM. Errors will be raised as exceptions, this requires the + ## `filename` parameter to not be ``nil`` to avoid crashes. + assert(not isNil(filename)) var p: TJsonParser p.open(s, filename) discard getTok(p) # read first token @@ -936,10 +1367,28 @@ when not defined(js): proc parseJson*(buffer: string): PJsonNode = ## Parses JSON from `buffer`. + ## + ## Specialized version around `parseJson(PStream, string) + ## <#parseJson,PStream,string>`_. Example: + ## + ## .. code-block:: nimrod + ## let + ## smallJson = """{"test": 1.3, "key2": true}""" + ## jobj = parseJson(smallJson) + ## assert jobj.kind == JObject + ## + ## assert jobj["test"].kind == JFloat + ## echo jobj["test"].fnum # --> 1.3 + ## + ## assert jobj["key2"].kind == JBool + ## echo jobj["key2"].bval # --> true result = parseJson(newStringStream(buffer), "input") proc parseFile*(filename: string): PJsonNode = ## Parses `file` into a `PJsonNode`. + ## + ## Specialized version around `parseJson(PStream, string) + ## <#parseJson,PStream,string>`_. var stream = newFileStream(filename, fmRead) if stream == nil: raise newException(EIO, "cannot read from file: " & filename) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 8af09114b..0f6a07f13 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -14,7 +14,7 @@ ## <backends.html#the-javascript-target>`_. include "system/inclrtl" - +import "impure/fenv" {.push debugger:off .} # the user does not want to trace a part # of the standard library! @@ -40,17 +40,6 @@ const ## after the decimal point ## for Nimrod's ``float`` type. -type - TFloatClass* = enum ## describes the class a floating point value belongs to. - ## This is the type that is returned by `classify`. - fcNormal, ## value is an ordinary nonzero floating point value - fcSubnormal, ## value is a subnormal (a very small) floating point value - fcZero, ## value is zero - fcNegZero, ## value is the negative zero - fcNan, ## value is Not-A-Number (NAN) - fcInf, ## value is positive infinity - fcNegInf ## value is negative infinity - proc classify*(x: float): TFloatClass = ## classifies a floating point value. Returns `x`'s class as specified by ## `TFloatClass`. diff --git a/tools/niminst/nsis.tmpl b/tools/niminst/nsis.tmpl index 14b1e7d77..40e171d41 100644 --- a/tools/niminst/nsis.tmpl +++ b/tools/niminst/nsis.tmpl @@ -149,11 +149,6 @@ CreateShortCut "$DESKTOP\?{c.displayName}.lnk" "$INSTDIR\?{c.name}.exe" #end if - ; Add shortcuts for the documentation - #for f in items(c.cat[fcDocStart]): - CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{splitFile(f).name}.lnk" "$INSTDIR\?{f.toWin}" - #end for - ; Write the shortcut to the uninstaller CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" "$INSTDIR\uninstaller.exe" !insertmacro MUI_STARTMENU_WRITE_END @@ -204,15 +199,15 @@ abort ${EndIf} + ; Shortcuts # if d.len >= 6: # let startMenuEntry = d[5] # let e = splitFile(startMenuEntry).name.capitalize - CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{e}.lnk" "$INSTDIR\?dir\?{startMenuEntry.toWin}" - # end if - - ; Shortcuts !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{e}.lnk" "$INSTDIR\?dir\?{startMenuEntry.toWin}" !insertmacro MUI_STARTMENU_WRITE_END + # end if + ignore: SectionEnd #end |