mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-30 03:03:57 +00:00
fixes #1286; object case transitions are now sound
This commit is contained in:
@@ -115,6 +115,9 @@
|
|||||||
ints and floats to string have been deprecated.
|
ints and floats to string have been deprecated.
|
||||||
Use `string.addInt(int)` and `string.addFloat(float)` instead.
|
Use `string.addInt(int)` and `string.addFloat(float)` instead.
|
||||||
|
|
||||||
|
- ``case object`` branch transitions via ``system.reset`` are deprecated.
|
||||||
|
Compile your code with ``-d:nimOldCaseObjects`` for a transition period.
|
||||||
|
|
||||||
|
|
||||||
#### Breaking changes in the compiler
|
#### Breaking changes in the compiler
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ define:nimcore
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
define:useStdoutAsStdmsg
|
define:useStdoutAsStdmsg
|
||||||
|
define:nimOldCaseObjects
|
||||||
|
|
||||||
#define:useNodeIds
|
#define:useNodeIds
|
||||||
#gc:markAndSweep
|
#gc:markAndSweep
|
||||||
|
|||||||
@@ -1538,10 +1538,23 @@ the ``case`` statement: The branches in a ``case`` section may be indented too.
|
|||||||
|
|
||||||
In the example the ``kind`` field is called the `discriminator`:idx:\: For
|
In the example the ``kind`` field is called the `discriminator`:idx:\: For
|
||||||
safety its address cannot be taken and assignments to it are restricted: The
|
safety its address cannot be taken and assignments to it are restricted: The
|
||||||
new value must not lead to a change of the active object branch. For an object
|
new value must not lead to a change of the active object branch. Also, when the
|
||||||
branch switch ``system.reset`` has to be used. Also, when the fields of a
|
fields of a particular branch are specified during object construction, the
|
||||||
particular branch are specified during object construction, the corresponding
|
corresponding discriminator value must be specified as a constant expression.
|
||||||
discriminator value must be specified as a constant expression.
|
|
||||||
|
Instead of changing the active object branch, replace the old object in memory
|
||||||
|
with a new one completely:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
var x = Node(kind: nkAdd, leftOp: Node(kind: nkInt, intVal: 4),
|
||||||
|
rightOp: Node(kind: nkInt, intVal: 2))
|
||||||
|
# change the node's contents:
|
||||||
|
x[] = NodeObj(kind: nkString, strVal: "abc")
|
||||||
|
|
||||||
|
|
||||||
|
Starting with version 0.20 ``system.reset`` cannot be used anymore to support
|
||||||
|
object branch changes as this never was completely memory safe.
|
||||||
|
|
||||||
As a special rule, the discriminator kind can also be bounded using a ``case``
|
As a special rule, the discriminator kind can also be bounded using a ``case``
|
||||||
statement. If possible values of the discriminator variable in a
|
statement. If possible values of the discriminator variable in a
|
||||||
|
|||||||
@@ -115,20 +115,16 @@ type
|
|||||||
AsyncSocketDesc = object
|
AsyncSocketDesc = object
|
||||||
fd: SocketHandle
|
fd: SocketHandle
|
||||||
closed: bool ## determines whether this socket has been closed
|
closed: bool ## determines whether this socket has been closed
|
||||||
case isBuffered: bool ## determines whether this socket is buffered.
|
isBuffered: bool ## determines whether this socket is buffered.
|
||||||
of true:
|
buffer: array[0..BufferSize, char]
|
||||||
buffer: array[0..BufferSize, char]
|
currPos: int # current index in buffer
|
||||||
currPos: int # current index in buffer
|
bufLen: int # current length of buffer
|
||||||
bufLen: int # current length of buffer
|
isSsl: bool
|
||||||
of false: nil
|
when defineSsl:
|
||||||
case isSsl: bool
|
sslHandle: SslPtr
|
||||||
of true:
|
sslContext: SslContext
|
||||||
when defineSsl:
|
bioIn: BIO
|
||||||
sslHandle: SslPtr
|
bioOut: BIO
|
||||||
sslContext: SslContext
|
|
||||||
bioIn: BIO
|
|
||||||
bioOut: BIO
|
|
||||||
of false: nil
|
|
||||||
domain: Domain
|
domain: Domain
|
||||||
sockType: SockType
|
sockType: SockType
|
||||||
protocol: Protocol
|
protocol: Protocol
|
||||||
|
|||||||
@@ -57,9 +57,7 @@ proc hasKey*[T](c: CritBitTree[T], key: string): bool {.inline.} =
|
|||||||
|
|
||||||
proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] =
|
proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] =
|
||||||
if c.root == nil:
|
if c.root == nil:
|
||||||
new c.root
|
c.root = Node[T](isleaf: true, key: key)
|
||||||
c.root.isleaf = true
|
|
||||||
c.root.key = key
|
|
||||||
result = c.root
|
result = c.root
|
||||||
else:
|
else:
|
||||||
var it = c.root
|
var it = c.root
|
||||||
@@ -89,9 +87,7 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] =
|
|||||||
|
|
||||||
var inner: Node[T]
|
var inner: Node[T]
|
||||||
new inner
|
new inner
|
||||||
new result
|
result = Node[T](isLeaf: true, key: key)
|
||||||
result.isLeaf = true
|
|
||||||
result.key = key
|
|
||||||
inner.otherBits = chr(newOtherBits)
|
inner.otherBits = chr(newOtherBits)
|
||||||
inner.byte = newByte
|
inner.byte = newByte
|
||||||
inner.child[1 - dir] = result
|
inner.child[1 - dir] = result
|
||||||
|
|||||||
@@ -188,48 +188,35 @@ type
|
|||||||
|
|
||||||
proc newJString*(s: string): JsonNode =
|
proc newJString*(s: string): JsonNode =
|
||||||
## Creates a new `JString JsonNode`.
|
## Creates a new `JString JsonNode`.
|
||||||
new(result)
|
result = JsonNode(kind: JString, str: s)
|
||||||
result.kind = JString
|
|
||||||
result.str = s
|
|
||||||
|
|
||||||
proc newJStringMove(s: string): JsonNode =
|
proc newJStringMove(s: string): JsonNode =
|
||||||
new(result)
|
result = JsonNode(kind: JString)
|
||||||
result.kind = JString
|
|
||||||
shallowCopy(result.str, s)
|
shallowCopy(result.str, s)
|
||||||
|
|
||||||
proc newJInt*(n: BiggestInt): JsonNode =
|
proc newJInt*(n: BiggestInt): JsonNode =
|
||||||
## Creates a new `JInt JsonNode`.
|
## Creates a new `JInt JsonNode`.
|
||||||
new(result)
|
result = JsonNode(kind: JInt, num: n)
|
||||||
result.kind = JInt
|
|
||||||
result.num = n
|
|
||||||
|
|
||||||
proc newJFloat*(n: float): JsonNode =
|
proc newJFloat*(n: float): JsonNode =
|
||||||
## Creates a new `JFloat JsonNode`.
|
## Creates a new `JFloat JsonNode`.
|
||||||
new(result)
|
result = JsonNode(kind: JFloat, fnum: n)
|
||||||
result.kind = JFloat
|
|
||||||
result.fnum = n
|
|
||||||
|
|
||||||
proc newJBool*(b: bool): JsonNode =
|
proc newJBool*(b: bool): JsonNode =
|
||||||
## Creates a new `JBool JsonNode`.
|
## Creates a new `JBool JsonNode`.
|
||||||
new(result)
|
result = JsonNode(kind: JBool, bval: b)
|
||||||
result.kind = JBool
|
|
||||||
result.bval = b
|
|
||||||
|
|
||||||
proc newJNull*(): JsonNode =
|
proc newJNull*(): JsonNode =
|
||||||
## Creates a new `JNull JsonNode`.
|
## Creates a new `JNull JsonNode`.
|
||||||
new(result)
|
result = JsonNode(kind: JNull)
|
||||||
|
|
||||||
proc newJObject*(): JsonNode =
|
proc newJObject*(): JsonNode =
|
||||||
## Creates a new `JObject JsonNode`
|
## Creates a new `JObject JsonNode`
|
||||||
new(result)
|
result = JsonNode(kind: JObject, fields: initOrderedTable[string, JsonNode](4))
|
||||||
result.kind = JObject
|
|
||||||
result.fields = initOrderedTable[string, JsonNode](4)
|
|
||||||
|
|
||||||
proc newJArray*(): JsonNode =
|
proc newJArray*(): JsonNode =
|
||||||
## Creates a new `JArray JsonNode`
|
## Creates a new `JArray JsonNode`
|
||||||
new(result)
|
result = JsonNode(kind: JArray, elems: @[])
|
||||||
result.kind = JArray
|
|
||||||
result.elems = @[]
|
|
||||||
|
|
||||||
proc getStr*(n: JsonNode, default: string = ""): string =
|
proc getStr*(n: JsonNode, default: string = ""): string =
|
||||||
## Retrieves the string value of a `JString JsonNode`.
|
## Retrieves the string value of a `JString JsonNode`.
|
||||||
@@ -309,45 +296,31 @@ proc add*(obj: JsonNode, key: string, val: JsonNode) =
|
|||||||
|
|
||||||
proc `%`*(s: string): JsonNode =
|
proc `%`*(s: string): JsonNode =
|
||||||
## Generic constructor for JSON data. Creates a new `JString JsonNode`.
|
## Generic constructor for JSON data. Creates a new `JString JsonNode`.
|
||||||
new(result)
|
result = JsonNode(kind: JString, str: s)
|
||||||
result.kind = JString
|
|
||||||
result.str = s
|
|
||||||
|
|
||||||
proc `%`*(n: uint): JsonNode =
|
proc `%`*(n: uint): JsonNode =
|
||||||
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
|
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
|
||||||
new(result)
|
result = JsonNode(kind: JInt, num: BiggestInt(n))
|
||||||
result.kind = JInt
|
|
||||||
result.num = BiggestInt(n)
|
|
||||||
|
|
||||||
proc `%`*(n: int): JsonNode =
|
proc `%`*(n: int): JsonNode =
|
||||||
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
|
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
|
||||||
new(result)
|
result = JsonNode(kind: JInt, num: n)
|
||||||
result.kind = JInt
|
|
||||||
result.num = n
|
|
||||||
|
|
||||||
proc `%`*(n: BiggestUInt): JsonNode =
|
proc `%`*(n: BiggestUInt): JsonNode =
|
||||||
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
|
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
|
||||||
new(result)
|
result = JsonNode(kind: JInt, num: BiggestInt(n))
|
||||||
result.kind = JInt
|
|
||||||
result.num = BiggestInt(n)
|
|
||||||
|
|
||||||
proc `%`*(n: BiggestInt): JsonNode =
|
proc `%`*(n: BiggestInt): JsonNode =
|
||||||
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
|
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
|
||||||
new(result)
|
result = JsonNode(kind: JInt, num: n)
|
||||||
result.kind = JInt
|
|
||||||
result.num = n
|
|
||||||
|
|
||||||
proc `%`*(n: float): JsonNode =
|
proc `%`*(n: float): JsonNode =
|
||||||
## Generic constructor for JSON data. Creates a new `JFloat JsonNode`.
|
## Generic constructor for JSON data. Creates a new `JFloat JsonNode`.
|
||||||
new(result)
|
result = JsonNode(kind: JFloat, fnum: n)
|
||||||
result.kind = JFloat
|
|
||||||
result.fnum = n
|
|
||||||
|
|
||||||
proc `%`*(b: bool): JsonNode =
|
proc `%`*(b: bool): JsonNode =
|
||||||
## Generic constructor for JSON data. Creates a new `JBool JsonNode`.
|
## Generic constructor for JSON data. Creates a new `JBool JsonNode`.
|
||||||
new(result)
|
result = JsonNode(kind: JBool, bval: b)
|
||||||
result.kind = JBool
|
|
||||||
result.bval = b
|
|
||||||
|
|
||||||
proc `%`*(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode =
|
proc `%`*(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode =
|
||||||
## Generic constructor for JSON data. Creates a new `JObject JsonNode`
|
## Generic constructor for JSON data. Creates a new `JObject JsonNode`
|
||||||
|
|||||||
@@ -117,21 +117,17 @@ const
|
|||||||
type
|
type
|
||||||
SocketImpl* = object ## socket type
|
SocketImpl* = object ## socket type
|
||||||
fd: SocketHandle
|
fd: SocketHandle
|
||||||
case isBuffered: bool # determines whether this socket is buffered.
|
isBuffered: bool # determines whether this socket is buffered.
|
||||||
of true:
|
buffer: array[0..BufferSize, char]
|
||||||
buffer: array[0..BufferSize, char]
|
currPos: int # current index in buffer
|
||||||
currPos: int # current index in buffer
|
bufLen: int # current length of buffer
|
||||||
bufLen: int # current length of buffer
|
|
||||||
of false: nil
|
|
||||||
when defineSsl:
|
when defineSsl:
|
||||||
case isSsl: bool
|
isSsl: bool
|
||||||
of true:
|
sslHandle: SSLPtr
|
||||||
sslHandle: SSLPtr
|
sslContext: SSLContext
|
||||||
sslContext: SSLContext
|
sslNoHandshake: bool # True if needs handshake.
|
||||||
sslNoHandshake: bool # True if needs handshake.
|
sslHasPeekChar: bool
|
||||||
sslHasPeekChar: bool
|
sslPeekChar: char
|
||||||
sslPeekChar: char
|
|
||||||
of false: nil
|
|
||||||
lastError: OSErrorCode ## stores the last error on this socket
|
lastError: OSErrorCode ## stores the last error on this socket
|
||||||
domain: Domain
|
domain: Domain
|
||||||
sockType: SockType
|
sockType: SockType
|
||||||
@@ -235,7 +231,7 @@ proc parseIPv4Address(addressStr: string): IpAddress =
|
|||||||
currentByte:uint16 = 0
|
currentByte:uint16 = 0
|
||||||
separatorValid = false
|
separatorValid = false
|
||||||
|
|
||||||
result.family = IpAddressFamily.IPv4
|
result = IpAddress(family: IpAddressFamily.IPv4)
|
||||||
|
|
||||||
for i in 0 .. high(addressStr):
|
for i in 0 .. high(addressStr):
|
||||||
if addressStr[i] in strutils.Digits: # Character is a number
|
if addressStr[i] in strutils.Digits: # Character is a number
|
||||||
@@ -264,7 +260,7 @@ proc parseIPv4Address(addressStr: string): IpAddress =
|
|||||||
proc parseIPv6Address(addressStr: string): IpAddress =
|
proc parseIPv6Address(addressStr: string): IpAddress =
|
||||||
## Parses IPv6 adresses
|
## Parses IPv6 adresses
|
||||||
## Raises ValueError on errors
|
## Raises ValueError on errors
|
||||||
result.family = IpAddressFamily.IPv6
|
result = IpAddress(family: IpAddressFamily.IPv6)
|
||||||
if addressStr.len < 2:
|
if addressStr.len < 2:
|
||||||
raise newException(ValueError, "Invalid IP Address")
|
raise newException(ValueError, "Invalid IP Address")
|
||||||
|
|
||||||
|
|||||||
@@ -391,29 +391,27 @@ proc ignoreMsg*(c: CfgParser, e: CfgEvent): string {.rtl, extern: "npc$1".} =
|
|||||||
|
|
||||||
proc getKeyValPair(c: var CfgParser, kind: CfgEventKind): CfgEvent =
|
proc getKeyValPair(c: var CfgParser, kind: CfgEventKind): CfgEvent =
|
||||||
if c.tok.kind == tkSymbol:
|
if c.tok.kind == tkSymbol:
|
||||||
|
result = CfgEvent(kind: cfgKeyValuePair, key: c.tok.literal, value: "")
|
||||||
result.kind = kind
|
result.kind = kind
|
||||||
result.key = c.tok.literal
|
|
||||||
result.value = ""
|
|
||||||
rawGetTok(c, c.tok)
|
rawGetTok(c, c.tok)
|
||||||
if c.tok.kind in {tkEquals, tkColon}:
|
if c.tok.kind in {tkEquals, tkColon}:
|
||||||
rawGetTok(c, c.tok)
|
rawGetTok(c, c.tok)
|
||||||
if c.tok.kind == tkSymbol:
|
if c.tok.kind == tkSymbol:
|
||||||
result.value = c.tok.literal
|
result.value = c.tok.literal
|
||||||
else:
|
else:
|
||||||
reset result
|
result = CfgEvent(kind: cfgError,
|
||||||
result.kind = cfgError
|
msg: errorStr(c, "symbol expected, but found: " & c.tok.literal))
|
||||||
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
|
|
||||||
rawGetTok(c, c.tok)
|
rawGetTok(c, c.tok)
|
||||||
else:
|
else:
|
||||||
result.kind = cfgError
|
result = CfgEvent(kind: cfgError,
|
||||||
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
|
msg: errorStr(c, "symbol expected, but found: " & c.tok.literal))
|
||||||
rawGetTok(c, c.tok)
|
rawGetTok(c, c.tok)
|
||||||
|
|
||||||
proc next*(c: var CfgParser): CfgEvent {.rtl, extern: "npc$1".} =
|
proc next*(c: var CfgParser): CfgEvent {.rtl, extern: "npc$1".} =
|
||||||
## retrieves the first/next event. This controls the parser.
|
## retrieves the first/next event. This controls the parser.
|
||||||
case c.tok.kind
|
case c.tok.kind
|
||||||
of tkEof:
|
of tkEof:
|
||||||
result.kind = cfgEof
|
result = CfgEvent(kind: cfgEof)
|
||||||
of tkDashDash:
|
of tkDashDash:
|
||||||
rawGetTok(c, c.tok)
|
rawGetTok(c, c.tok)
|
||||||
result = getKeyValPair(c, cfgOption)
|
result = getKeyValPair(c, cfgOption)
|
||||||
@@ -422,21 +420,19 @@ proc next*(c: var CfgParser): CfgEvent {.rtl, extern: "npc$1".} =
|
|||||||
of tkBracketLe:
|
of tkBracketLe:
|
||||||
rawGetTok(c, c.tok)
|
rawGetTok(c, c.tok)
|
||||||
if c.tok.kind == tkSymbol:
|
if c.tok.kind == tkSymbol:
|
||||||
result.kind = cfgSectionStart
|
result = CfgEvent(kind: cfgSectionStart, section: c.tok.literal)
|
||||||
result.section = c.tok.literal
|
|
||||||
else:
|
else:
|
||||||
result.kind = cfgError
|
result = CfgEvent(kind: cfgError,
|
||||||
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
|
msg: errorStr(c, "symbol expected, but found: " & c.tok.literal))
|
||||||
rawGetTok(c, c.tok)
|
rawGetTok(c, c.tok)
|
||||||
if c.tok.kind == tkBracketRi:
|
if c.tok.kind == tkBracketRi:
|
||||||
rawGetTok(c, c.tok)
|
rawGetTok(c, c.tok)
|
||||||
else:
|
else:
|
||||||
reset(result)
|
result = CfgEvent(kind: cfgError,
|
||||||
result.kind = cfgError
|
msg: errorStr(c, "']' expected, but found: " & c.tok.literal))
|
||||||
result.msg = errorStr(c, "']' expected, but found: " & c.tok.literal)
|
|
||||||
of tkInvalid, tkEquals, tkColon, tkBracketRi:
|
of tkInvalid, tkEquals, tkColon, tkBracketRi:
|
||||||
result.kind = cfgError
|
result = CfgEvent(kind: cfgError,
|
||||||
result.msg = errorStr(c, "invalid token: " & c.tok.literal)
|
msg: errorStr(c, "invalid token: " & c.tok.literal))
|
||||||
rawGetTok(c, c.tok)
|
rawGetTok(c, c.tok)
|
||||||
|
|
||||||
# ---------------- Configuration file related operations ----------------
|
# ---------------- Configuration file related operations ----------------
|
||||||
|
|||||||
@@ -554,17 +554,14 @@ type
|
|||||||
tok: Token
|
tok: Token
|
||||||
|
|
||||||
proc newNode*(k: SqlNodeKind): SqlNode =
|
proc newNode*(k: SqlNodeKind): SqlNode =
|
||||||
new(result)
|
result = SqlNode(kind: k)
|
||||||
result.kind = k
|
|
||||||
|
|
||||||
proc newNode*(k: SqlNodeKind, s: string): SqlNode =
|
proc newNode*(k: SqlNodeKind, s: string): SqlNode =
|
||||||
new(result)
|
result = SqlNode(kind: k)
|
||||||
result.kind = k
|
|
||||||
result.strVal = s
|
result.strVal = s
|
||||||
|
|
||||||
proc newNode*(k: SqlNodeKind, sons: seq[SqlNode]): SqlNode =
|
proc newNode*(k: SqlNodeKind, sons: seq[SqlNode]): SqlNode =
|
||||||
new(result)
|
result = SqlNode(kind: k)
|
||||||
result.kind = k
|
|
||||||
result.sons = sons
|
result.sons = sons
|
||||||
|
|
||||||
proc len*(n: SqlNode): int =
|
proc len*(n: SqlNode): int =
|
||||||
|
|||||||
@@ -142,34 +142,29 @@ proc rule*(nt: NonTerminal): Peg = nt.rule
|
|||||||
proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
|
proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
|
||||||
## constructs a PEG from a terminal string
|
## constructs a PEG from a terminal string
|
||||||
if t.len != 1:
|
if t.len != 1:
|
||||||
result.kind = pkTerminal
|
result = Peg(kind: pkTerminal, term: t)
|
||||||
result.term = t
|
|
||||||
else:
|
else:
|
||||||
result.kind = pkChar
|
result = Peg(kind: pkChar, ch: t[0])
|
||||||
result.ch = t[0]
|
|
||||||
|
|
||||||
proc termIgnoreCase*(t: string): Peg {.
|
proc termIgnoreCase*(t: string): Peg {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".} =
|
nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## constructs a PEG from a terminal string; ignore case for matching
|
## constructs a PEG from a terminal string; ignore case for matching
|
||||||
result.kind = pkTerminalIgnoreCase
|
result = Peg(kind: pkTerminalIgnoreCase, term: t)
|
||||||
result.term = t
|
|
||||||
|
|
||||||
proc termIgnoreStyle*(t: string): Peg {.
|
proc termIgnoreStyle*(t: string): Peg {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".} =
|
nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## constructs a PEG from a terminal string; ignore style for matching
|
## constructs a PEG from a terminal string; ignore style for matching
|
||||||
result.kind = pkTerminalIgnoreStyle
|
result = Peg(kind: pkTerminalIgnoreStyle, term: t)
|
||||||
result.term = t
|
|
||||||
|
|
||||||
proc term*(t: char): Peg {.nosideEffect, rtl, extern: "npegs$1Char".} =
|
proc term*(t: char): Peg {.nosideEffect, rtl, extern: "npegs$1Char".} =
|
||||||
## constructs a PEG from a terminal char
|
## constructs a PEG from a terminal char
|
||||||
assert t != '\0'
|
assert t != '\0'
|
||||||
result.kind = pkChar
|
result = Peg(kind: pkChar, ch: t)
|
||||||
result.ch = t
|
|
||||||
|
|
||||||
proc charSet*(s: set[char]): Peg {.nosideEffect, rtl, extern: "npegs$1".} =
|
proc charSet*(s: set[char]): Peg {.nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## constructs a PEG from a character set `s`
|
## constructs a PEG from a character set `s`
|
||||||
assert '\0' notin s
|
assert '\0' notin s
|
||||||
result.kind = pkCharChoice
|
result = Peg(kind: pkCharChoice)
|
||||||
new(result.charChoice)
|
new(result.charChoice)
|
||||||
result.charChoice[] = s
|
result.charChoice[] = s
|
||||||
|
|
||||||
@@ -189,8 +184,7 @@ proc addChoice(dest: var Peg, elem: Peg) =
|
|||||||
else: add(dest, elem)
|
else: add(dest, elem)
|
||||||
|
|
||||||
template multipleOp(k: PegKind, localOpt: untyped) =
|
template multipleOp(k: PegKind, localOpt: untyped) =
|
||||||
result.kind = k
|
result = Peg(kind: k, sons: @[])
|
||||||
result.sons = @[]
|
|
||||||
for x in items(a):
|
for x in items(a):
|
||||||
if x.kind == k:
|
if x.kind == k:
|
||||||
for y in items(x.sons):
|
for y in items(x.sons):
|
||||||
@@ -230,8 +224,7 @@ proc `?`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsOptional".} =
|
|||||||
# a? ? --> a?
|
# a? ? --> a?
|
||||||
result = a
|
result = a
|
||||||
else:
|
else:
|
||||||
result.kind = pkOption
|
result = Peg(kind: pkOption, sons: @[a])
|
||||||
result.sons = @[a]
|
|
||||||
|
|
||||||
proc `*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyRep".} =
|
proc `*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyRep".} =
|
||||||
## constructs a "greedy repetition" for the PEG `a`
|
## constructs a "greedy repetition" for the PEG `a`
|
||||||
@@ -240,27 +233,22 @@ proc `*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyRep".} =
|
|||||||
assert false
|
assert false
|
||||||
# produces endless loop!
|
# produces endless loop!
|
||||||
of pkChar:
|
of pkChar:
|
||||||
result.kind = pkGreedyRepChar
|
result = Peg(kind: pkGreedyRepChar, ch: a.ch)
|
||||||
result.ch = a.ch
|
|
||||||
of pkCharChoice:
|
of pkCharChoice:
|
||||||
result.kind = pkGreedyRepSet
|
result = Peg(kind: pkGreedyRepSet, charChoice: a.charChoice)
|
||||||
result.charChoice = a.charChoice # copying a reference suffices!
|
|
||||||
of pkAny, pkAnyRune:
|
of pkAny, pkAnyRune:
|
||||||
result.kind = pkGreedyAny
|
result = Peg(kind: pkGreedyAny)
|
||||||
else:
|
else:
|
||||||
result.kind = pkGreedyRep
|
result = Peg(kind: pkGreedyRep, sons: @[a])
|
||||||
result.sons = @[a]
|
|
||||||
|
|
||||||
proc `!*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsSearch".} =
|
proc `!*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsSearch".} =
|
||||||
## constructs a "search" for the PEG `a`
|
## constructs a "search" for the PEG `a`
|
||||||
result.kind = pkSearch
|
result = Peg(kind: pkSearch, sons: @[a])
|
||||||
result.sons = @[a]
|
|
||||||
|
|
||||||
proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
|
proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
|
||||||
extern: "npgegsCapturedSearch".} =
|
extern: "npgegsCapturedSearch".} =
|
||||||
## constructs a "captured search" for the PEG `a`
|
## constructs a "captured search" for the PEG `a`
|
||||||
result.kind = pkCapturedSearch
|
result = Peg(kind: pkCapturedSearch, sons: @[a])
|
||||||
result.sons = @[a]
|
|
||||||
|
|
||||||
proc `+`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
|
proc `+`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
|
||||||
## constructs a "greedy positive repetition" with the PEG `a`
|
## constructs a "greedy positive repetition" with the PEG `a`
|
||||||
@@ -268,50 +256,48 @@ proc `+`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
|
|||||||
|
|
||||||
proc `&`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
|
proc `&`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
|
||||||
## constructs an "and predicate" with the PEG `a`
|
## constructs an "and predicate" with the PEG `a`
|
||||||
result.kind = pkAndPredicate
|
result = Peg(kind: pkAndPredicate, sons: @[a])
|
||||||
result.sons = @[a]
|
|
||||||
|
|
||||||
proc `!`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsNotPredicate".} =
|
proc `!`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsNotPredicate".} =
|
||||||
## constructs a "not predicate" with the PEG `a`
|
## constructs a "not predicate" with the PEG `a`
|
||||||
result.kind = pkNotPredicate
|
result = Peg(kind: pkNotPredicate, sons: @[a])
|
||||||
result.sons = @[a]
|
|
||||||
|
|
||||||
proc any*: Peg {.inline.} =
|
proc any*: Peg {.inline.} =
|
||||||
## constructs the PEG `any character`:idx: (``.``)
|
## constructs the PEG `any character`:idx: (``.``)
|
||||||
result.kind = pkAny
|
result = Peg(kind: pkAny)
|
||||||
|
|
||||||
proc anyRune*: Peg {.inline.} =
|
proc anyRune*: Peg {.inline.} =
|
||||||
## constructs the PEG `any rune`:idx: (``_``)
|
## constructs the PEG `any rune`:idx: (``_``)
|
||||||
result.kind = pkAnyRune
|
result = Peg(kind: pkAnyRune)
|
||||||
|
|
||||||
proc newLine*: Peg {.inline.} =
|
proc newLine*: Peg {.inline.} =
|
||||||
## constructs the PEG `newline`:idx: (``\n``)
|
## constructs the PEG `newline`:idx: (``\n``)
|
||||||
result.kind = pkNewLine
|
result = Peg(kind: pkNewLine)
|
||||||
|
|
||||||
proc unicodeLetter*: Peg {.inline.} =
|
proc unicodeLetter*: Peg {.inline.} =
|
||||||
## constructs the PEG ``\letter`` which matches any Unicode letter.
|
## constructs the PEG ``\letter`` which matches any Unicode letter.
|
||||||
result.kind = pkLetter
|
result = Peg(kind: pkLetter)
|
||||||
|
|
||||||
proc unicodeLower*: Peg {.inline.} =
|
proc unicodeLower*: Peg {.inline.} =
|
||||||
## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
|
## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
|
||||||
result.kind = pkLower
|
result = Peg(kind: pkLower)
|
||||||
|
|
||||||
proc unicodeUpper*: Peg {.inline.} =
|
proc unicodeUpper*: Peg {.inline.} =
|
||||||
## constructs the PEG ``\upper`` which matches any Unicode uppercase letter.
|
## constructs the PEG ``\upper`` which matches any Unicode uppercase letter.
|
||||||
result.kind = pkUpper
|
result = Peg(kind: pkUpper)
|
||||||
|
|
||||||
proc unicodeTitle*: Peg {.inline.} =
|
proc unicodeTitle*: Peg {.inline.} =
|
||||||
## constructs the PEG ``\title`` which matches any Unicode title letter.
|
## constructs the PEG ``\title`` which matches any Unicode title letter.
|
||||||
result.kind = pkTitle
|
result = Peg(kind: pkTitle)
|
||||||
|
|
||||||
proc unicodeWhitespace*: Peg {.inline.} =
|
proc unicodeWhitespace*: Peg {.inline.} =
|
||||||
## constructs the PEG ``\white`` which matches any Unicode
|
## constructs the PEG ``\white`` which matches any Unicode
|
||||||
## whitespace character.
|
## whitespace character.
|
||||||
result.kind = pkWhitespace
|
result = Peg(kind: pkWhitespace)
|
||||||
|
|
||||||
proc startAnchor*: Peg {.inline.} =
|
proc startAnchor*: Peg {.inline.} =
|
||||||
## constructs the PEG ``^`` which matches the start of the input.
|
## constructs the PEG ``^`` which matches the start of the input.
|
||||||
result.kind = pkStartAnchor
|
result = Peg(kind: pkStartAnchor)
|
||||||
|
|
||||||
proc endAnchor*: Peg {.inline.} =
|
proc endAnchor*: Peg {.inline.} =
|
||||||
## constructs the PEG ``$`` which matches the end of the input.
|
## constructs the PEG ``$`` which matches the end of the input.
|
||||||
@@ -319,29 +305,25 @@ proc endAnchor*: Peg {.inline.} =
|
|||||||
|
|
||||||
proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
|
proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
|
||||||
## constructs a capture with the PEG `a`
|
## constructs a capture with the PEG `a`
|
||||||
result.kind = pkCapture
|
result = Peg(kind: pkCapture, sons: @[a])
|
||||||
result.sons = @[a]
|
|
||||||
|
|
||||||
proc backref*(index: range[1..MaxSubpatterns]): Peg {.
|
proc backref*(index: range[1..MaxSubpatterns]): Peg {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".} =
|
nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## constructs a back reference of the given `index`. `index` starts counting
|
## constructs a back reference of the given `index`. `index` starts counting
|
||||||
## from 1.
|
## from 1.
|
||||||
result.kind = pkBackRef
|
result = Peg(kind: pkBackRef, index: index-1)
|
||||||
result.index = index-1
|
|
||||||
|
|
||||||
proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): Peg {.
|
proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): Peg {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".} =
|
nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## constructs a back reference of the given `index`. `index` starts counting
|
## constructs a back reference of the given `index`. `index` starts counting
|
||||||
## from 1. Ignores case for matching.
|
## from 1. Ignores case for matching.
|
||||||
result.kind = pkBackRefIgnoreCase
|
result = Peg(kind: pkBackRefIgnoreCase, index: index-1)
|
||||||
result.index = index-1
|
|
||||||
|
|
||||||
proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): Peg {.
|
proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): Peg {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".}=
|
nosideEffect, rtl, extern: "npegs$1".}=
|
||||||
## constructs a back reference of the given `index`. `index` starts counting
|
## constructs a back reference of the given `index`. `index` starts counting
|
||||||
## from 1. Ignores style for matching.
|
## from 1. Ignores style for matching.
|
||||||
result.kind = pkBackRefIgnoreStyle
|
result = Peg(kind: pkBackRefIgnoreStyle, index: index-1)
|
||||||
result.index = index-1
|
|
||||||
|
|
||||||
proc spaceCost(n: Peg): int =
|
proc spaceCost(n: Peg): int =
|
||||||
case n.kind
|
case n.kind
|
||||||
@@ -366,16 +348,12 @@ proc nonterminal*(n: NonTerminal): Peg {.
|
|||||||
when false: echo "inlining symbol: ", n.name
|
when false: echo "inlining symbol: ", n.name
|
||||||
result = n.rule # inlining of rule enables better optimizations
|
result = n.rule # inlining of rule enables better optimizations
|
||||||
else:
|
else:
|
||||||
result.kind = pkNonTerminal
|
result = Peg(kind: pkNonTerminal, nt: n)
|
||||||
result.nt = n
|
|
||||||
|
|
||||||
proc newNonTerminal*(name: string, line, column: int): NonTerminal {.
|
proc newNonTerminal*(name: string, line, column: int): NonTerminal {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".} =
|
nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## constructs a nonterminal symbol
|
## constructs a nonterminal symbol
|
||||||
new(result)
|
result = NonTerminal(name: name, line: line, col: column)
|
||||||
result.name = name
|
|
||||||
result.line = line
|
|
||||||
result.col = column
|
|
||||||
|
|
||||||
template letters*: Peg =
|
template letters*: Peg =
|
||||||
## expands to ``charset({'A'..'Z', 'a'..'z'})``
|
## expands to ``charset({'A'..'Z', 'a'..'z'})``
|
||||||
@@ -585,8 +563,14 @@ template matchOrParse(mopProc: untyped) =
|
|||||||
if p.index >= c.ml: return -1
|
if p.index >= c.ml: return -1
|
||||||
var (a, b) = c.matches[p.index]
|
var (a, b) = c.matches[p.index]
|
||||||
var n: Peg
|
var n: Peg
|
||||||
n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef))
|
case p.kind
|
||||||
n.term = s.substr(a, b)
|
of pkBackRef:
|
||||||
|
n = Peg(kind: pkTerminal, term: s.substr(a, b))
|
||||||
|
of pkBackRefIgnoreStyle:
|
||||||
|
n = Peg(kind: pkTerminalIgnoreStyle, term: s.substr(a, b))
|
||||||
|
of pkBackRefIgnoreCase:
|
||||||
|
n = Peg(kind: pkTerminalIgnoreCase, term: s.substr(a, b))
|
||||||
|
else: assert(false, "impossible case")
|
||||||
mopProc(s, n, start, c)
|
mopProc(s, n, start, c)
|
||||||
|
|
||||||
case p.kind
|
case p.kind
|
||||||
|
|||||||
@@ -70,8 +70,7 @@ const
|
|||||||
|
|
||||||
proc newXmlNode(kind: XmlNodeKind): XmlNode =
|
proc newXmlNode(kind: XmlNodeKind): XmlNode =
|
||||||
## Creates a new ``XmlNode``.
|
## Creates a new ``XmlNode``.
|
||||||
new(result)
|
result = XmlNode(k: kind)
|
||||||
result.k = kind
|
|
||||||
|
|
||||||
proc newElement*(tag: string): XmlNode =
|
proc newElement*(tag: string): XmlNode =
|
||||||
## Creates a new ``XmlNode`` of kind ``xnElement`` with the given `tag`.
|
## Creates a new ``XmlNode`` of kind ``xnElement`` with the given `tag`.
|
||||||
|
|||||||
@@ -266,8 +266,6 @@ proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
|
|||||||
|
|
||||||
proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
|
proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
|
||||||
## Resets an object `obj` to its initial (binary zero) value.
|
## Resets an object `obj` to its initial (binary zero) value.
|
||||||
##
|
|
||||||
## This needs to be called before any possible `object branch transition`:idx:.
|
|
||||||
|
|
||||||
proc wasMoved*[T](obj: var T) {.magic: "WasMoved", noSideEffect.} =
|
proc wasMoved*[T](obj: var T) {.magic: "WasMoved", noSideEffect.} =
|
||||||
## Resets an object `obj` to its initial (binary zero) value to signify
|
## Resets an object `obj` to its initial (binary zero) value to signify
|
||||||
|
|||||||
@@ -232,5 +232,9 @@ proc FieldDiscriminantCheck(oldDiscVal, newDiscVal: int,
|
|||||||
L: int) {.compilerProc.} =
|
L: int) {.compilerProc.} =
|
||||||
var oldBranch = selectBranch(oldDiscVal, L, a)
|
var oldBranch = selectBranch(oldDiscVal, L, a)
|
||||||
var newBranch = selectBranch(newDiscVal, L, a)
|
var newBranch = selectBranch(newDiscVal, L, a)
|
||||||
if newBranch != oldBranch and oldDiscVal != 0:
|
when defined(nimOldCaseObjects):
|
||||||
sysFatal(FieldError, "assignment to discriminant changes object branch")
|
if newBranch != oldBranch and oldDiscVal != 0:
|
||||||
|
sysFatal(FieldError, "assignment to discriminant changes object branch")
|
||||||
|
else:
|
||||||
|
if newBranch != oldBranch:
|
||||||
|
sysFatal(FieldError, "assignment to discriminant changes object branch")
|
||||||
|
|||||||
1
tests/compilerapi/tcompilerapi.nim.cfg
Normal file
1
tests/compilerapi/tcompilerapi.nim.cfg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
define:nimOldCaseObjects
|
||||||
Reference in New Issue
Block a user