* enable stricteffects * add gcsafe * fix tests * use func * fixes pegs tests * explicitly mark repr related procs with noSideEffect * add nimLegacyEffects * change URL * fixes docopt * add `raises: []` to repr * fixes weave * fixes nimyaml * fixes glob * fixes parsetoml * Apply suggestions from code review * Update testament/important_packages.nim * add legacy:laxEffects
This commit is contained in:
parent
0510a2be0d
commit
1e15f975b8
16 changed files with 38 additions and 39 deletions
|
|
@ -89,6 +89,9 @@
|
||||||
- ORC is now the default memory management strategy. Use
|
- ORC is now the default memory management strategy. Use
|
||||||
`--mm:refc` for a transition period.
|
`--mm:refc` for a transition period.
|
||||||
|
|
||||||
|
- `strictEffects` are no longer experimental.
|
||||||
|
Use `legacy:laxEffects` to keep backward compatibility.
|
||||||
|
|
||||||
- The `gorge`/`staticExec` calls will now return a descriptive message in the output
|
- The `gorge`/`staticExec` calls will now return a descriptive message in the output
|
||||||
if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`.
|
if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,6 @@ define:useStdoutAsStdmsg
|
||||||
warning[ObservableStores]: off
|
warning[ObservableStores]: off
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@if nimHasEffectsOf:
|
|
||||||
experimental:strictEffects
|
|
||||||
warningAsError:Effect:on
|
|
||||||
@end
|
|
||||||
|
|
||||||
@if nimHasWarningAsError:
|
@if nimHasWarningAsError:
|
||||||
warningAsError:GcUnsafe2:on
|
warningAsError:GcUnsafe2:on
|
||||||
@end
|
@end
|
||||||
|
|
|
||||||
|
|
@ -228,6 +228,8 @@ type
|
||||||
## Historically and especially in version 1.0.0 of the language
|
## Historically and especially in version 1.0.0 of the language
|
||||||
## conversions to unsigned numbers were checked. In 1.0.4 they
|
## conversions to unsigned numbers were checked. In 1.0.4 they
|
||||||
## are not anymore.
|
## are not anymore.
|
||||||
|
laxEffects
|
||||||
|
## Lax effects system prior to Nim 2.0.
|
||||||
|
|
||||||
SymbolFilesOption* = enum
|
SymbolFilesOption* = enum
|
||||||
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
|
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
|
||||||
|
|
|
||||||
|
|
@ -495,7 +495,7 @@ proc isIndirectCall(tracked: PEffects; n: PNode): bool =
|
||||||
if n.kind != nkSym:
|
if n.kind != nkSym:
|
||||||
result = true
|
result = true
|
||||||
elif n.sym.kind == skParam:
|
elif n.sym.kind == skParam:
|
||||||
if strictEffects in tracked.c.features:
|
if laxEffects notin tracked.c.config.legacyFeatures:
|
||||||
if tracked.owner == n.sym.owner and sfEffectsDelayed in n.sym.flags:
|
if tracked.owner == n.sym.owner and sfEffectsDelayed in n.sym.flags:
|
||||||
result = false # it is not a harmful call
|
result = false # it is not a harmful call
|
||||||
else:
|
else:
|
||||||
|
|
@ -581,7 +581,7 @@ proc isOwnedProcVar(tracked: PEffects; n: PNode): bool =
|
||||||
tracked.owner == n.sym.owner
|
tracked.owner == n.sym.owner
|
||||||
#if result and sfPolymorphic notin n.sym.flags:
|
#if result and sfPolymorphic notin n.sym.flags:
|
||||||
# echo tracked.config $ n.info, " different here!"
|
# echo tracked.config $ n.info, " different here!"
|
||||||
if strictEffects in tracked.c.features:
|
if laxEffects notin tracked.c.config.legacyFeatures:
|
||||||
result = result and sfEffectsDelayed in n.sym.flags
|
result = result and sfEffectsDelayed in n.sym.flags
|
||||||
|
|
||||||
proc isNoEffectList(n: PNode): bool {.inline.} =
|
proc isNoEffectList(n: PNode): bool {.inline.} =
|
||||||
|
|
@ -598,7 +598,7 @@ proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, formals: PType; ar
|
||||||
# assume indirect calls are taken here:
|
# assume indirect calls are taken here:
|
||||||
if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit and
|
if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit and
|
||||||
not isTrival(caller) and
|
not isTrival(caller) and
|
||||||
((param != nil and sfEffectsDelayed in param.flags) or strictEffects notin tracked.c.features):
|
((param != nil and sfEffectsDelayed in param.flags) or laxEffects in tracked.c.config.legacyFeatures):
|
||||||
|
|
||||||
internalAssert tracked.config, op.n[0].kind == nkEffectList
|
internalAssert tracked.config, op.n[0].kind == nkEffectList
|
||||||
var effectList = op.n[0]
|
var effectList = op.n[0]
|
||||||
|
|
@ -844,7 +844,7 @@ proc trackCall(tracked: PEffects; n: PNode) =
|
||||||
assumeTheWorst(tracked, n, op)
|
assumeTheWorst(tracked, n, op)
|
||||||
gcsafeAndSideeffectCheck()
|
gcsafeAndSideeffectCheck()
|
||||||
else:
|
else:
|
||||||
if strictEffects in tracked.c.features and a.kind == nkSym and
|
if laxEffects notin tracked.c.config.legacyFeatures and a.kind == nkSym and
|
||||||
a.sym.kind in routineKinds:
|
a.sym.kind in routineKinds:
|
||||||
propagateEffects(tracked, n, a.sym)
|
propagateEffects(tracked, n, a.sym)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -26,3 +26,4 @@ when defined(windows) and not defined(booting):
|
||||||
switch("define", "nimRawSetjmp")
|
switch("define", "nimRawSetjmp")
|
||||||
|
|
||||||
switch("define", "nimVersion:" & NimVersion)
|
switch("define", "nimVersion:" & NimVersion)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4952,8 +4952,7 @@ Effect system
|
||||||
=============
|
=============
|
||||||
|
|
||||||
**Note**: The rules for effect tracking changed with the release of version
|
**Note**: The rules for effect tracking changed with the release of version
|
||||||
1.6 of the Nim compiler. This section describes the new rules that are activated
|
1.6 of the Nim compiler.
|
||||||
via `--experimental:strictEffects`.
|
|
||||||
|
|
||||||
|
|
||||||
Exception tracking
|
Exception tracking
|
||||||
|
|
@ -5073,7 +5072,6 @@ conservative in its effect analysis:
|
||||||
|
|
||||||
```nim test = "nim c $1" status = 1
|
```nim test = "nim c $1" status = 1
|
||||||
{.push warningAsError[Effect]: on.}
|
{.push warningAsError[Effect]: on.}
|
||||||
{.experimental: "strictEffects".}
|
|
||||||
|
|
||||||
import algorithm
|
import algorithm
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -561,7 +561,7 @@ template matchOrParse(mopProc: untyped) =
|
||||||
# procs. For the former, *enter* and *leave* event handler code generators
|
# procs. For the former, *enter* and *leave* event handler code generators
|
||||||
# are provided which just return *discard*.
|
# are provided which just return *discard*.
|
||||||
|
|
||||||
proc mopProc(s: string, p: Peg, start: int, c: var Captures): int =
|
proc mopProc(s: string, p: Peg, start: int, c: var Captures): int {.gcsafe.} =
|
||||||
proc matchBackRef(s: string, p: Peg, start: int, c: var Captures): int =
|
proc matchBackRef(s: string, p: Peg, start: int, c: var Captures): int =
|
||||||
# Parse handler code must run in an *of* clause of its own for each
|
# Parse handler code must run in an *of* clause of its own for each
|
||||||
# *PegKind*, so we encapsulate the identical clause body for
|
# *PegKind*, so we encapsulate the identical clause body for
|
||||||
|
|
|
||||||
|
|
@ -1701,7 +1701,7 @@ proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
|
||||||
result = s[L]
|
result = s[L]
|
||||||
setLen(s, L)
|
setLen(s, L)
|
||||||
|
|
||||||
proc `==`*[T: tuple|object](x, y: T): bool =
|
func `==`*[T: tuple|object](x, y: T): bool =
|
||||||
## Generic `==` operator for tuples that is lifted from the components.
|
## Generic `==` operator for tuples that is lifted from the components.
|
||||||
## of `x` and `y`.
|
## of `x` and `y`.
|
||||||
for a, b in fields(x, y):
|
for a, b in fields(x, y):
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ proc repr*(x: bool): string {.magic: "BoolToStr", noSideEffect.}
|
||||||
## repr for a boolean argument. Returns `x`
|
## repr for a boolean argument. Returns `x`
|
||||||
## converted to the string "false" or "true".
|
## converted to the string "false" or "true".
|
||||||
|
|
||||||
proc repr*(x: char): string {.noSideEffect.} =
|
proc repr*(x: char): string {.noSideEffect, raises: [].} =
|
||||||
## repr for a character argument. Returns `x`
|
## repr for a character argument. Returns `x`
|
||||||
## converted to an escaped string.
|
## converted to an escaped string.
|
||||||
##
|
##
|
||||||
|
|
@ -47,7 +47,7 @@ proc repr*(x: char): string {.noSideEffect.} =
|
||||||
result.add x
|
result.add x
|
||||||
result.add '\''
|
result.add '\''
|
||||||
|
|
||||||
proc repr*(x: string | cstring): string {.noSideEffect.} =
|
proc repr*(x: string | cstring): string {.noSideEffect, raises: [].} =
|
||||||
## repr for a string argument. Returns `x`
|
## repr for a string argument. Returns `x`
|
||||||
## converted to a quoted and escaped string.
|
## converted to a quoted and escaped string.
|
||||||
result.add '\"'
|
result.add '\"'
|
||||||
|
|
@ -63,7 +63,7 @@ proc repr*(x: string | cstring): string {.noSideEffect.} =
|
||||||
result.add x[i]
|
result.add x[i]
|
||||||
result.add '\"'
|
result.add '\"'
|
||||||
|
|
||||||
proc repr*[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.}
|
proc repr*[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect, raises: [].}
|
||||||
## repr for an enumeration argument. This works for
|
## repr for an enumeration argument. This works for
|
||||||
## any enumeration type thanks to compiler magic.
|
## any enumeration type thanks to compiler magic.
|
||||||
##
|
##
|
||||||
|
|
@ -100,7 +100,7 @@ template repr*(x: distinct): string =
|
||||||
|
|
||||||
template repr*(t: typedesc): string = $t
|
template repr*(t: typedesc): string = $t
|
||||||
|
|
||||||
proc reprObject[T: tuple|object](res: var string, x: T) =
|
proc reprObject[T: tuple|object](res: var string, x: T) {.noSideEffect, raises: [].} =
|
||||||
res.add '('
|
res.add '('
|
||||||
var firstElement = true
|
var firstElement = true
|
||||||
const isNamed = T is object or isNamedTuple(T)
|
const isNamed = T is object or isNamedTuple(T)
|
||||||
|
|
@ -121,7 +121,7 @@ proc reprObject[T: tuple|object](res: var string, x: T) =
|
||||||
res.add(')')
|
res.add(')')
|
||||||
|
|
||||||
|
|
||||||
proc repr*[T: tuple|object](x: T): string =
|
proc repr*[T: tuple|object](x: T): string {.noSideEffect, raises: [].} =
|
||||||
## Generic `repr` operator for tuples that is lifted from the components
|
## Generic `repr` operator for tuples that is lifted from the components
|
||||||
## of `x`. Example:
|
## of `x`. Example:
|
||||||
##
|
##
|
||||||
|
|
@ -133,7 +133,7 @@ proc repr*[T: tuple|object](x: T): string =
|
||||||
result = $typeof(x)
|
result = $typeof(x)
|
||||||
reprObject(result, x)
|
reprObject(result, x)
|
||||||
|
|
||||||
proc repr*[T](x: ref T | ptr T): string =
|
proc repr*[T](x: ref T | ptr T): string {.noSideEffect, raises: [].} =
|
||||||
if isNil(x): return "nil"
|
if isNil(x): return "nil"
|
||||||
when T is object:
|
when T is object:
|
||||||
result = $typeof(x)
|
result = $typeof(x)
|
||||||
|
|
@ -142,7 +142,7 @@ proc repr*[T](x: ref T | ptr T): string =
|
||||||
result = when typeof(x) is ref: "ref " else: "ptr "
|
result = when typeof(x) is ref: "ref " else: "ptr "
|
||||||
result.add repr(x[])
|
result.add repr(x[])
|
||||||
|
|
||||||
proc collectionToRepr[T](x: T, prefix, separator, suffix: string): string =
|
proc collectionToRepr[T](x: T, prefix, separator, suffix: string): string {.noSideEffect, raises: [].} =
|
||||||
result = prefix
|
result = prefix
|
||||||
var firstElement = true
|
var firstElement = true
|
||||||
for value in items(x):
|
for value in items(x):
|
||||||
|
|
@ -189,4 +189,4 @@ proc repr*[T](x: openArray[T]): string =
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
## $(@[23, 45].toOpenArray(0, 1)) == "[23, 45]"
|
## $(@[23, 45].toOpenArray(0, 1)) == "[23, 45]"
|
||||||
collectionToRepr(x, "[", ", ", "]")
|
collectionToRepr(x, "[", ", ", "]")
|
||||||
|
|
@ -401,7 +401,7 @@ macro convertSexp*(x: untyped): untyped =
|
||||||
## `%` for every element.
|
## `%` for every element.
|
||||||
result = toSexp(x)
|
result = toSexp(x)
|
||||||
|
|
||||||
proc `==`* (a, b: SexpNode): bool {.noSideEffect.} =
|
func `==`* (a, b: SexpNode): bool =
|
||||||
## Check two nodes for equality
|
## Check two nodes for equality
|
||||||
if a.isNil:
|
if a.isNil:
|
||||||
if b.isNil: return true
|
if b.isNil: return true
|
||||||
|
|
|
||||||
|
|
@ -60,15 +60,15 @@ pkg "criterion", allowFailure = true # pending https://github.com/disruptek/crit
|
||||||
pkg "datamancer"
|
pkg "datamancer"
|
||||||
pkg "dashing", "nim c tests/functional.nim"
|
pkg "dashing", "nim c tests/functional.nim"
|
||||||
pkg "delaunay", url = "https://github.com/nim-lang/DelaunayNim", useHead = true
|
pkg "delaunay", url = "https://github.com/nim-lang/DelaunayNim", useHead = true
|
||||||
pkg "docopt"
|
pkg "docopt", url = "https://github.com/nim-lang/docopt.nim", useHead = true
|
||||||
pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl"
|
pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl"
|
||||||
pkg "elvis"
|
pkg "elvis"
|
||||||
pkg "fidget"
|
pkg "fidget"
|
||||||
pkg "fragments", "nim c -r fragments/dsl.nim", allowFailure = true # pending https://github.com/nim-lang/packages/issues/2115
|
pkg "fragments", "nim c -r fragments/dsl.nim", allowFailure = true # pending https://github.com/nim-lang/packages/issues/2115
|
||||||
pkg "fusion"
|
pkg "fusion"
|
||||||
pkg "gara"
|
pkg "gara"
|
||||||
pkg "glob"
|
pkg "glob", url = "https://github.com/nim-lang/glob", useHead = true
|
||||||
pkg "ggplotnim", "nim c -d:noCairo -r tests/tests.nim"
|
pkg "ggplotnim", "nim c -d:noCairo -r tests/tests.nim", url = "https://github.com/nim-lang/ggplotnim", useHead = true
|
||||||
pkg "gittyup", "nimble test", "https://github.com/disruptek/gittyup", allowFailure = true
|
pkg "gittyup", "nimble test", "https://github.com/disruptek/gittyup", allowFailure = true
|
||||||
pkg "gnuplot", "nim c gnuplot.nim"
|
pkg "gnuplot", "nim c gnuplot.nim"
|
||||||
# pkg "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram"
|
# pkg "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram"
|
||||||
|
|
@ -109,7 +109,7 @@ pkg "nimongo", "nimble test_ci", allowFailure = true
|
||||||
pkg "nimph", "nimble test", "https://github.com/disruptek/nimph", allowFailure = true
|
pkg "nimph", "nimble test", "https://github.com/disruptek/nimph", allowFailure = true
|
||||||
pkg "nimPNG", useHead = true
|
pkg "nimPNG", useHead = true
|
||||||
pkg "nimpy", "nim c -r tests/nimfrompy.nim"
|
pkg "nimpy", "nim c -r tests/nimfrompy.nim"
|
||||||
pkg "nimquery"
|
pkg "nimquery", url = "https://github.com/nim-lang/nimquery", useHead = true
|
||||||
pkg "nimsl"
|
pkg "nimsl"
|
||||||
pkg "nimsvg"
|
pkg "nimsvg"
|
||||||
pkg "nimterop", "nimble minitest"
|
pkg "nimterop", "nimble minitest"
|
||||||
|
|
@ -121,7 +121,7 @@ pkg "npeg", "nimble testarc"
|
||||||
pkg "numericalnim", "nimble nimCI"
|
pkg "numericalnim", "nimble nimCI"
|
||||||
pkg "optionsutils"
|
pkg "optionsutils"
|
||||||
pkg "ormin", "nim c -o:orminn ormin.nim"
|
pkg "ormin", "nim c -o:orminn ormin.nim"
|
||||||
pkg "parsetoml"
|
pkg "parsetoml", url = "https://github.com/nim-lang/parsetoml", useHead = true
|
||||||
pkg "patty"
|
pkg "patty"
|
||||||
pkg "pixie"
|
pkg "pixie"
|
||||||
pkg "plotly", "nim c examples/all.nim"
|
pkg "plotly", "nim c examples/all.nim"
|
||||||
|
|
@ -146,7 +146,7 @@ pkg "strslice"
|
||||||
pkg "strunicode", "nim c -r --mm:refc src/strunicode.nim"
|
pkg "strunicode", "nim c -r --mm:refc src/strunicode.nim"
|
||||||
pkg "supersnappy"
|
pkg "supersnappy"
|
||||||
pkg "synthesis"
|
pkg "synthesis"
|
||||||
pkg "telebot", "nim c -o:tbot -r src/telebot.nim"
|
pkg "telebot", "nim c -o:tbot -r src/telebot.nim", url = "https://github.com/nim-lang/telebot.nim", useHead = true
|
||||||
pkg "tempdir"
|
pkg "tempdir"
|
||||||
pkg "templates"
|
pkg "templates"
|
||||||
pkg "tensordsl", "nim c -r --mm:refc tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git"
|
pkg "tensordsl", "nim c -r --mm:refc tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git"
|
||||||
|
|
@ -158,11 +158,11 @@ pkg "tiny_sqlite"
|
||||||
pkg "unicodedb", "nim c -d:release -r tests/tests.nim"
|
pkg "unicodedb", "nim c -d:release -r tests/tests.nim"
|
||||||
pkg "unicodeplus", "nim c -d:release -r tests/tests.nim"
|
pkg "unicodeplus", "nim c -d:release -r tests/tests.nim"
|
||||||
pkg "unpack"
|
pkg "unpack"
|
||||||
pkg "weave", "nimble install -y cligen synthesis;nimble test_gc_arc"
|
pkg "weave", "nimble install -y cligen synthesis;nimble test_gc_arc", url = "https://github.com/nim-lang/weave", useHead = true
|
||||||
pkg "websocket", "nim c websocket.nim"
|
pkg "websocket", "nim c websocket.nim"
|
||||||
pkg "winim", "nim c winim.nim"
|
pkg "winim", "nim c winim.nim"
|
||||||
pkg "with"
|
pkg "with"
|
||||||
pkg "ws", allowFailure = true
|
pkg "ws", allowFailure = true
|
||||||
pkg "yaml", "nim c -r test/tserialization.nim"
|
pkg "yaml", "nim c -r test/tserialization.nim", url = "https://github.com/nim-lang/NimYAML", useHead = true
|
||||||
pkg "zero_functional", "nim c -r -d:nimNoLentIterators test.nim"
|
pkg "zero_functional", "nim c -r -d:nimNoLentIterators test.nim"
|
||||||
pkg "zippy"
|
pkg "zippy"
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ py
|
||||||
py
|
py
|
||||||
px
|
px
|
||||||
6
|
6
|
||||||
proc (){.closure, gcsafe.}
|
proc (){.closure, noSideEffect, gcsafe.}
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ createMenuItem(s, "Go to definition...",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
proc noRaise(x: proc()) {.raises: [].} =
|
proc noRaise(x: proc()) {.raises: [], effectsOf: x.} =
|
||||||
# unknown call that might raise anything, but valid:
|
# unknown call that might raise anything, but valid:
|
||||||
x()
|
x()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "'mainUnsafe' is not GC-safe"
|
errormsg: "'mainUnsafe' is not GC-safe as it performs an indirect call here"
|
||||||
line: 26
|
line: 26
|
||||||
cmd: "nim $target --hints:on --threads:on $options $file"
|
cmd: "nim $target --hints:on --threads:on $options $file"
|
||||||
"""
|
"""
|
||||||
|
|
@ -13,7 +13,7 @@ proc myproc(i: int) {.gcsafe.} =
|
||||||
if isNil(global_proc):
|
if isNil(global_proc):
|
||||||
return
|
return
|
||||||
|
|
||||||
proc mymap(x: proc ()) =
|
proc mymap(x: proc ()) {.effectsOf: x.} =
|
||||||
x()
|
x()
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
block: # `.noSideEffect`
|
block: # `.noSideEffect`
|
||||||
func foo(bar: proc(): int): int = bar()
|
func foo(bar: proc(): int): int {.effectsOf: bar.} = bar()
|
||||||
var count = 0
|
var count = 0
|
||||||
proc fn1(): int = 1
|
proc fn1(): int = 1
|
||||||
proc fn2(): int = (count.inc; count)
|
proc fn2(): int = (count.inc; count)
|
||||||
|
|
|
||||||
|
|
@ -106,9 +106,9 @@ block:
|
||||||
|
|
||||||
block:
|
block:
|
||||||
var
|
var
|
||||||
pStack: seq[string] = @[]
|
pStack {.threadvar.}: seq[string]
|
||||||
valStack: seq[float] = @[]
|
valStack {.threadvar.}: seq[float]
|
||||||
opStack = ""
|
opStack {.threadvar.}: string
|
||||||
let
|
let
|
||||||
parseArithExpr = pegAst.eventParser:
|
parseArithExpr = pegAst.eventParser:
|
||||||
pkNonTerminal:
|
pkNonTerminal:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue