fixes #1286; object case transitions are now sound

This commit is contained in:
Andreas Rumpf
2019-05-26 23:10:34 +02:00
parent 247fa431de
commit 49e686ab4e
14 changed files with 123 additions and 166 deletions

View File

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

View File

@@ -12,6 +12,7 @@ define:nimcore
@end @end
define:useStdoutAsStdmsg define:useStdoutAsStdmsg
define:nimOldCaseObjects
#define:useNodeIds #define:useNodeIds
#gc:markAndSweep #gc:markAndSweep

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1 @@
define:nimOldCaseObjects