diff options
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/ccgcalls.nim | 13 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 59 | ||||
-rw-r--r-- | compiler/msgs.nim | 3 | ||||
-rw-r--r-- | compiler/parser.nim | 3 | ||||
-rw-r--r-- | compiler/vmdeps.nim | 4 | ||||
-rw-r--r-- | doc/manual/lexing.txt | 2 | ||||
-rw-r--r-- | doc/manual/syntax.txt | 17 | ||||
-rw-r--r-- | doc/nimc.txt | 21 | ||||
-rw-r--r-- | lib/core/macros.nim | 4 | ||||
-rw-r--r-- | lib/impure/re.nim | 41 | ||||
-rw-r--r-- | lib/packages/docutils/rst.nim | 2 | ||||
-rw-r--r-- | lib/pure/osproc.nim | 14 | ||||
-rw-r--r-- | lib/system/atomics.nim | 2 | ||||
-rw-r--r-- | tests/cpp/get_subsystem.nim | 22 | ||||
-rw-r--r-- | tests/cpp/vector_iterator.nim | 19 | ||||
-rw-r--r-- | tests/parser/tstrongspaces.nim | 14 | ||||
-rw-r--r-- | web/news.txt | 4 |
18 files changed, 192 insertions, 54 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 55923b54c..4e22af287 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -796,8 +796,8 @@ type # for enum types a list of symbols # for tyInt it can be the int literal # for procs and tyGenericBody, it's the - # the body of the user-defined type class # formal param list + # for concepts, the concept body # else: unused owner*: PSym # the 'owner' of the type sym*: PSym # types have the sym associated with them diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 8f354d457..2dacc25e9 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -385,18 +385,11 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope = inc j inc i of '\'': - inc i - let stars = i - while pat[i] == '*': inc i - if pat[i] in Digits: - let j = pat[i].ord - '0'.ord - var t = typ.sons[j] - for k in 1..i-stars: - if t != nil and t.len > 0: - t = if t.kind == tyGenericInst: t.sons[1] else: t.elemType + var idx, stars: int + if scanCppGenericSlot(pat, i, idx, stars): + var t = resolveStarsInCppType(typ, idx, stars) if t == nil: result.add(~"void") else: result.add(getTypeDesc(p.module, t)) - inc i else: let start = i while i < pat.len: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 8fdabd6cc..60ebf591b 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -495,6 +495,33 @@ proc getTupleDesc(m: BModule, typ: PType, name: Rope, else: add(result, desc) add(result, "};" & tnl) +proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool = + # A helper proc for handling cppimport patterns, involving numeric + # placeholders for generic types (e.g. '0, '**2, etc). + # pre: the cursor must be placed at the ' symbol + # post: the cursor will be placed after the final digit + # false will returned if the input is not recognized as a placeholder + inc cursor + let begin = cursor + while pat[cursor] == '*': inc cursor + if pat[cursor] in Digits: + outIdx = pat[cursor].ord - '0'.ord + outStars = cursor - begin + inc cursor + return true + else: + return false + +proc resolveStarsInCppType(typ: PType, idx, stars: int): PType = + # XXX: we should catch this earlier and report it as a semantic error + if idx >= typ.len: internalError "invalid apostrophe type parameter index" + + result = typ.sons[idx] + for i in 1..stars: + if result != nil and result.len > 0: + result = if result.kind == tyGenericInst: result.sons[1] + else: result.elemType + proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = # returns only the type's name var t = getUniqueType(typ) @@ -597,11 +624,33 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = if isImportedCppType(t) and typ.kind == tyGenericInst: # for instantiated templates we do not go through the type cache as the # the type cache is not aware of 'tyGenericInst'. - result = getTypeName(t) & "<" - for i in 1 .. typ.len-2: - if i > 1: result.add(", ") - result.add(getTypeDescAux(m, typ.sons[i], check)) - result.add("> ") + let cppName = getTypeName(t) + var i = 0 + var chunkStart = 0 + while i < cppName.data.len: + if cppName.data[i] == '\'': + var chunkEnd = <i + var idx, stars: int + if scanCppGenericSlot(cppName.data, i, idx, stars): + result.add cppName.data.substr(chunkStart, chunkEnd) + chunkStart = i + + let typeInSlot = resolveStarsInCppType(typ, idx + 1, stars) + if typeInSlot == nil or typeInSlot.kind == tyEmpty: + result.add(~"void") + else: + result.add getTypeDescAux(m, typeInSlot, check) + else: + inc i + + if chunkStart != 0: + result.add cppName.data.substr(chunkStart) + else: + result = cppName & "<" + for i in 1 .. typ.len-2: + if i > 1: result.add(", ") + result.add(getTypeDescAux(m, typ.sons[i], check)) + result.add("> ") # always call for sideeffects: assert t.kind != tyTuple discard getRecordDesc(m, t, result, check) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 3f5c4763e..778b839f3 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -827,6 +827,9 @@ proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") = proc localError*(info: TLineInfo, arg: string) = liMessage(info, errGenerated, arg, doNothing) +proc localError*(info: TLineInfo, format: string, params: openarray[string]) = + localError(info, format % params) + proc message*(info: TLineInfo, msg: TMsgKind, arg = "") = liMessage(info, msg, arg, doNothing) diff --git a/compiler/parser.nim b/compiler/parser.nim index d600f0f85..7da2f0d22 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -212,7 +212,8 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int = let relevantChar = tok.ident.s[0] # arrow like? - if L > 1 and tok.ident.s[L-1] == '>': return considerStrongSpaces(1) + if L > 1 and tok.ident.s[L-1] == '>' and + tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1) template considerAsgn(value: expr) = result = if tok.ident.s[L-1] == '=': 1 else: value diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 6148ed319..21ee4967b 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -144,7 +144,9 @@ proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode = of tyIter: result = mapTypeToBracket("iter", t, info) of tyProxy: result = atomicType"error" of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info) - of tyUserTypeClass: result = mapTypeToBracket("userTypeClass", t, info) + of tyUserTypeClass: + result = mapTypeToBracket("concept", t, info) + result.add t.n.copyTree of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info) of tyAnd: result = mapTypeToBracket("and", t, info) of tyOr: result = mapTypeToBracket("or", t, info) diff --git a/doc/manual/lexing.txt b/doc/manual/lexing.txt index e2f006f04..df6d85636 100644 --- a/doc/manual/lexing.txt +++ b/doc/manual/lexing.txt @@ -289,7 +289,7 @@ Numerical constants are of a single type and have the form:: INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32' INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64' - UINT8_LIT = INT_LIT ['\''] ('u' | 'U') + UINT_LIT = INT_LIT ['\''] ('u' | 'U') UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8' UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16' UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32' diff --git a/doc/manual/syntax.txt b/doc/manual/syntax.txt index cf44eb588..24644bce2 100644 --- a/doc/manual/syntax.txt +++ b/doc/manual/syntax.txt @@ -15,8 +15,6 @@ Associativity Binary operators whose first character is ``^`` are right-associative, all other binary operators are left-associative. -Operators ending in ``>`` but longer than a single character are -called `arrow like`:idx:. Precedence @@ -33,9 +31,12 @@ as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``. For binary operators that are not keywords the precedence is determined by the following rules: +Operators ending in either ``->``, ``~>`` or ``=>`` are called +`arrow like`:idx:, and have the lowest precedence of all operators. + If the operator ends with ``=`` and its first character is none of ``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which -has the lowest precedence. +has the second lowest precedence. Otherwise precedence is determined by the first character. @@ -43,14 +44,14 @@ Otherwise precedence is determined by the first character. Precedence level Operators First character Terminal symbol ================ =============================================== ================== =============== 10 (highest) ``$ ^`` OP10 - 9 ``* / div mod shl shr %`` ``* % \ /`` OP9 - 8 ``+ -`` ``+ ~ |`` OP8 + 9 ``* / div mod shl shr %`` ``* % \ /`` OP9 + 8 ``+ -`` ``+ - ~ |`` OP8 7 ``&`` ``&`` OP7 6 ``..`` ``.`` OP6 - 5 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP5 + 5 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP5 4 ``and`` OP4 3 ``or xor`` OP3 - 2 ``@ : ?`` OP2 + 2 ``@ : ?`` OP2 1 *assignment operator* (like ``+=``, ``*=``) OP1 0 (lowest) *arrow like operator* (like ``->``, ``=>``) OP0 ================ =============================================== ================== =============== @@ -67,7 +68,7 @@ is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``: .. code-block:: nim #! strongSpaces - if foo+4 * 4 == 8 and b&c | 9 ++ + if foo+4 * 4 == 8 and b&c | 9 ++ bar: echo "" # is parsed as diff --git a/doc/nimc.txt b/doc/nimc.txt index 831fce567..cfbccc479 100644 --- a/doc/nimc.txt +++ b/doc/nimc.txt @@ -506,7 +506,7 @@ For example: .. code-block:: nim type Input {.importcpp: "System::Input".} = object - proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()".} + proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.} let x: ptr Input = getSubsystem[Input]() @@ -596,6 +596,25 @@ Produces: x[6] = 91.4; +- If more precise control is needed, the apostrophe ``'`` can be used in the + supplied pattern to denote the concrete type parameters of the generic type. + See the usage of the apostrophe operator in proc patterns for more details. + +.. code-block:: nim + + type + VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object + + var x: VectorIterator[cint] + + +Produces: + +.. code-block:: C + + std::vector<int>::iterator x; + + ImportObjC pragma ----------------- Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the diff --git a/lib/core/macros.nim b/lib/core/macros.nim index b78b94bd1..777d991d4 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -88,7 +88,9 @@ type ntyBigNum, ntyConst, ntyMutable, ntyVarargs, ntyIter, - ntyError + ntyError, + ntyBuiltinTypeClass, ntyConcept, ntyConceptInst, ntyComposite, + ntyAnd, ntyOr, ntyNot TNimTypeKinds* {.deprecated.} = set[NimTypeKind] NimSymKind* = enum diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 91381bda3..c2f93ce79 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -7,8 +7,11 @@ # distribution, for details about the copyright. # -## Regular expression support for Nim. Consider using the pegs module -## instead. +## Regular expression support for Nim. Consider using the pegs module instead. +## +## There is an alternative regular expressions library with a more unified API: +## `nre <https://github.com/flaviut/nre>`_. It may be added to the standard +## library in the future, instead of `re`. ## ## **Note:** The 're' proc defaults to the **extended regular expression ## syntax** which lets you use whitespace freely to make your regexes readable. @@ -413,22 +416,28 @@ proc escapeRe*(s: string): string = result.add(toHex(ord(c), 2)) const ## common regular expressions - reIdentifier* = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b" ## describes an identifier - reNatural* = r"\b\d+\b" ## describes a natural number - reInteger* = r"\b[-+]?\d+\b" ## describes an integer - reHex* = r"\b0[xX][0-9a-fA-F]+\b" ## describes a hexadecimal number - reBinary* = r"\b0[bB][01]+\b" ## describes a binary number (example: 0b11101) - reOctal* = r"\b0[oO][0-7]+\b" ## describes an octal number (example: 0o777) - reFloat* = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b" + reIdentifier* {.deprecated.} = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b" + ## describes an identifier + reNatural* {.deprecated.} = r"\b\d+\b" + ## describes a natural number + reInteger* {.deprecated.} = r"\b[-+]?\d+\b" + ## describes an integer + reHex* {.deprecated.} = r"\b0[xX][0-9a-fA-F]+\b" + ## describes a hexadecimal number + reBinary* {.deprecated.} = r"\b0[bB][01]+\b" + ## describes a binary number (example: 0b11101) + reOctal* {.deprecated.} = r"\b0[oO][0-7]+\b" + ## describes an octal number (example: 0o777) + reFloat* {.deprecated.} = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b" ## describes a floating point number - reEmail* = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" & - r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)" & - r"*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" & - r"(?:[a-zA-Z]{2}|com|org|" & - r"net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\b" + reEmail* {.deprecated.} = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" & + r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@" & + r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" & + r"(?:[a-zA-Z]{2}|com|org|net|gov|mil|biz|" & + r"info|mobi|name|aero|jobs|museum)\b" ## describes a common email address - reURL* = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms\-help):" & - r"((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b" + reURL* {.deprecated.} = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms-help)" & + r":((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b" ## describes an URL when isMainModule: diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index a4d095e68..2ee94ba13 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -564,7 +564,7 @@ proc fixupEmbeddedRef(n, a, b: PRstNode) = proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode = result = n - if isInlineMarkupEnd(p, "_"): + if isInlineMarkupEnd(p, "_") or isInlineMarkupEnd(p, "__"): inc(p.idx) if p.tok[p.idx-2].symbol == "`" and p.tok[p.idx-3].symbol == ">": var a = newRstNode(rnInner) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index eb7ad64bb..dce0673ba 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -174,7 +174,7 @@ proc terminate*(p: Process) {.rtl, extern: "nosp$1", tags: [].} proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## Kill the process `p`. On Posix OSes the procedure sends ``SIGKILL`` to ## the process. On Windows ``kill()`` is simply an alias for ``terminate()``. - + proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].} ## Returns true iff the process `p` is still running. Returns immediately. @@ -666,7 +666,7 @@ elif not defined(useNimRtl): data.workingDir = workingDir - when declared(posix_spawn) and not defined(useFork) and + when declared(posix_spawn) and not defined(useFork) and not defined(useClone) and not defined(linux): pid = startProcessAuxSpawn(data) else: @@ -823,7 +823,7 @@ elif not defined(useNimRtl): discard execvp(data.sysCommand, data.sysArgs) else: when defined(uClibc): - # uClibc environment (OpenWrt included) doesn't have the full execvpe + # uClibc environment (OpenWrt included) doesn't have the full execvpe discard execve(data.sysCommand, data.sysArgs, data.sysEnv) else: discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv) @@ -864,9 +864,9 @@ elif not defined(useNimRtl): raiseOsError(osLastError()) proc kill(p: Process) = - if kill(p.id, SIGKILL) != 0'i32: + if kill(p.id, SIGKILL) != 0'i32: raiseOsError(osLastError()) - + proc waitForExit(p: Process, timeout: int = -1): int = #if waitPid(p.id, p.exitCode, 0) == int(p.id): # ``waitPid`` fails if the process is not running anymore. But then @@ -883,7 +883,7 @@ elif not defined(useNimRtl): var ret = waitpid(p.id, p.exitCode, WNOHANG) var b = ret == int(p.id) if b: result = -1 - if p.exitCode == -3: result = -1 + if not WIFEXITED(p.exitCode): result = -1 else: result = p.exitCode.int shr 8 proc createStream(stream: var Stream, handle: var FileHandle, @@ -907,7 +907,7 @@ elif not defined(useNimRtl): createStream(p.errStream, p.errHandle, fmRead) return p.errStream - proc csystem(cmd: cstring): cint {.nodecl, importc: "system", + proc csystem(cmd: cstring): cint {.nodecl, importc: "system", header: "<stdlib.h>".} proc execCmd(command: string): int = diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim index 300fa85f3..c97d2fc7f 100644 --- a/lib/system/atomics.nim +++ b/lib/system/atomics.nim @@ -87,7 +87,7 @@ when someGcc and hasThreadSupport: proc atomicCompareExchange*[T: TAtomType](p, expected, desired: ptr T, weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {. - importc: "__atomic_compare_exchange_n ", nodecl.} + importc: "__atomic_compare_exchange", nodecl.} ## This proc implements the generic version of atomic_compare_exchange. ## The proc is virtually identical to atomic_compare_exchange_n, except the desired ## value is also a pointer. diff --git a/tests/cpp/get_subsystem.nim b/tests/cpp/get_subsystem.nim new file mode 100644 index 000000000..38593b03a --- /dev/null +++ b/tests/cpp/get_subsystem.nim @@ -0,0 +1,22 @@ +discard """ + cmd: "nim cpp $file" +""" + +{.emit: """ + +namespace System { + struct Input {}; +} + +struct SystemManager { + template <class T> + static T* getSubsystem() { return new T; } +}; + +""".} + +type Input {.importcpp: "System::Input".} = object +proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()".} + +let input: ptr Input = getSubsystem[Input]() + diff --git a/tests/cpp/vector_iterator.nim b/tests/cpp/vector_iterator.nim new file mode 100644 index 000000000..cb5ab33af --- /dev/null +++ b/tests/cpp/vector_iterator.nim @@ -0,0 +1,19 @@ +discard """ + cmd: "nim cpp $file" +""" + +{.emit: """ + +template <class T> +struct Vector { + struct Iterator {}; +}; + +""".} + +type + Vector {.importcpp: "Vector".} [T] = object + VectorIterator {.importcpp: "Vector<'0>::Iterator".} [T] = object + +var x: VectorIterator[void] + diff --git a/tests/parser/tstrongspaces.nim b/tests/parser/tstrongspaces.nim index 568abda4c..e70b91988 100644 --- a/tests/parser/tstrongspaces.nim +++ b/tests/parser/tstrongspaces.nim @@ -15,6 +15,10 @@ true tester args all all args +19 +-3 +false +-2 ''' """ @@ -67,3 +71,13 @@ const echo tester & " " & args|"all" echo "all" | tester & " " & args echo "all"|tester & " " & args + +# Test arrow like operators. See also tests/macros/tclosuremacro.nim +proc `+->`(a, b: int): int = a + b*4 +template `===>`(a, b: int): expr = a - b shr 1 + +echo 3 +-> 2 + 2 and 4 +var arrowed = 3+->2 + 2 and 4 # arrowed = 4 +echo arrowed ===> 15 +echo (2 * 3+->2) == (2*3 +-> 2) +echo arrowed ===> 2 + 3+->2 diff --git a/web/news.txt b/web/news.txt index af44f91a1..6b109aa1c 100644 --- a/web/news.txt +++ b/web/news.txt @@ -34,6 +34,10 @@ News should be used instead. - ``nim idetools`` has been replaced by a separate tool `nimsuggest`_. - *arrow like* operators are not right associative anymore. + - *arrow like* operators are now required to end with either ``->``, ``~>`` or + ``=>``, not just ``>``. Examples of operators still considered arrow like: + ``->``, ``==>``, ``+=>``. On the other hand, the following operators are now + considered regular operators again: ``|>``, ``-+>``, etc. - Typeless parameters are now only allowed in templates and macros. The old way turned out to be too error-prone. - The 'addr' and 'type' operators are now parsed as unary function |