mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 05:50:30 +00:00
Merge branch 'devel' of https://github.com/Araq/Nim into devel
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
21
doc/nimc.txt
21
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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.
|
||||
|
||||
22
tests/cpp/get_subsystem.nim
Normal file
22
tests/cpp/get_subsystem.nim
Normal file
@@ -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]()
|
||||
|
||||
19
tests/cpp/vector_iterator.nim
Normal file
19
tests/cpp/vector_iterator.nim
Normal file
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user