Merge branch 'devel' of https://github.com/Araq/Nim into devel

This commit is contained in:
Araq
2015-04-20 11:44:54 +02:00
18 changed files with 192 additions and 54 deletions

View File

@@ -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

View File

@@ -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:

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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'

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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)

View File

@@ -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 =

View File

@@ -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.

View 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]()

View 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]

View File

@@ -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

View File

@@ -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