parent
c9f14ca9be
commit
ed5b7cbac0
7 changed files with 132 additions and 41 deletions
|
|
@ -114,3 +114,4 @@ proc initDefines*() =
|
||||||
defineSymbol("nimNewDot")
|
defineSymbol("nimNewDot")
|
||||||
defineSymbol("nimHasNilChecks")
|
defineSymbol("nimHasNilChecks")
|
||||||
defineSymbol("nimSymKind")
|
defineSymbol("nimSymKind")
|
||||||
|
defineSymbol("nimVmEqIdent")
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ proc resetIdentCache*() =
|
||||||
for i in low(legacy.buckets)..high(legacy.buckets):
|
for i in low(legacy.buckets)..high(legacy.buckets):
|
||||||
legacy.buckets[i] = nil
|
legacy.buckets[i] = nil
|
||||||
|
|
||||||
proc cmpIgnoreStyle(a, b: cstring, blen: int): int =
|
proc cmpIgnoreStyle*(a, b: cstring, blen: int): int =
|
||||||
if a[0] != b[0]: return 1
|
if a[0] != b[0]: return 1
|
||||||
var i = 0
|
var i = 0
|
||||||
var j = 0
|
var j = 0
|
||||||
|
|
|
||||||
|
|
@ -1392,10 +1392,36 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
regs[ra].node.typ = n.typ
|
regs[ra].node.typ = n.typ
|
||||||
of opcEqIdent:
|
of opcEqIdent:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
if regs[rb].node.kind == nkIdent and regs[rc].node.kind == nkIdent:
|
# aliases for shorter and easier to understand code below
|
||||||
regs[ra].intVal = ord(regs[rb].node.ident.id == regs[rc].node.ident.id)
|
let aNode = regs[rb].node
|
||||||
|
let bNode = regs[rc].node
|
||||||
|
# these are cstring to prevent string copy, and cmpIgnoreStyle from
|
||||||
|
# takes cstring arguments
|
||||||
|
var aStrVal: cstring
|
||||||
|
var bStrVal: cstring
|
||||||
|
# extract strVal from argument ``a``
|
||||||
|
case aNode.kind
|
||||||
|
of {nkStrLit..nkTripleStrLit}:
|
||||||
|
aStrVal = aNode.strVal.cstring
|
||||||
|
of nkIdent:
|
||||||
|
aStrVal = aNode.ident.s.cstring
|
||||||
|
of nkSym:
|
||||||
|
aStrVal = aNode.sym.name.s.cstring
|
||||||
else:
|
else:
|
||||||
regs[ra].intVal = 0
|
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
|
||||||
|
# extract strVal from argument ``b``
|
||||||
|
case bNode.kind
|
||||||
|
of {nkStrLit..nkTripleStrLit}:
|
||||||
|
bStrVal = bNode.strVal.cstring
|
||||||
|
of nkIdent:
|
||||||
|
bStrVal = bNode.ident.s.cstring
|
||||||
|
of nkSym:
|
||||||
|
bStrVal = bNode.sym.name.s.cstring
|
||||||
|
else:
|
||||||
|
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
|
||||||
|
# set result
|
||||||
|
regs[ra].intVal =
|
||||||
|
ord(idents.cmpIgnoreStyle(aStrVal,bStrVal,high(int)) == 0)
|
||||||
of opcStrToIdent:
|
of opcStrToIdent:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:
|
if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:
|
||||||
|
|
|
||||||
|
|
@ -1186,7 +1186,25 @@ proc copy*(node: NimNode): NimNode {.compileTime.} =
|
||||||
## An alias for copyNimTree().
|
## An alias for copyNimTree().
|
||||||
return node.copyNimTree()
|
return node.copyNimTree()
|
||||||
|
|
||||||
proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
|
when defined(nimVmEqIdent):
|
||||||
|
proc eqIdent*(a: string; b: string): bool {.magic: "EqIdent", noSideEffect.}
|
||||||
|
## Style insensitive comparison.
|
||||||
|
|
||||||
|
proc eqIdent*(a: NimNode; b: string): bool {.magic: "EqIdent", noSideEffect.}
|
||||||
|
## Style insensitive comparison.
|
||||||
|
## ``a`` can be an identifier or a symbol.
|
||||||
|
|
||||||
|
proc eqIdent*(a: string; b: NimNode): bool {.magic: "EqIdent", noSideEffect.}
|
||||||
|
## Style insensitive comparison.
|
||||||
|
## ``b`` can be an identifier or a symbol.
|
||||||
|
|
||||||
|
proc eqIdent*(a: NimNode; b: NimNode): bool {.magic: "EqIdent", noSideEffect.}
|
||||||
|
## Style insensitive comparison.
|
||||||
|
## ``a`` and ``b`` can be an identifier or a symbol.
|
||||||
|
|
||||||
|
else:
|
||||||
|
# this procedure is optimized for native code, it should not be compiled to nimVM bytecode.
|
||||||
|
proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
|
||||||
proc toLower(c: char): char {.inline.} =
|
proc toLower(c: char): char {.inline.} =
|
||||||
if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A')))
|
if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A')))
|
||||||
else: result = c
|
else: result = c
|
||||||
|
|
@ -1204,10 +1222,11 @@ proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
|
||||||
inc(i)
|
inc(i)
|
||||||
inc(j)
|
inc(j)
|
||||||
|
|
||||||
proc eqIdent*(a, b: string): bool = cmpIgnoreStyle(a, b) == 0
|
|
||||||
|
proc eqIdent*(a, b: string): bool = cmpIgnoreStyle(a, b) == 0
|
||||||
## Check if two idents are identical.
|
## Check if two idents are identical.
|
||||||
|
|
||||||
proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} =
|
proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} =
|
||||||
## Check if node is some identifier node (``nnkIdent``, ``nnkSym``, etc.)
|
## Check if node is some identifier node (``nnkIdent``, ``nnkSym``, etc.)
|
||||||
## is the same as ``s``. Note that this is the preferred way to check! Most
|
## is the same as ``s``. Note that this is the preferred way to check! Most
|
||||||
## other ways like ``node.ident`` are much more error-prone, unfortunately.
|
## other ways like ``node.ident`` are much more error-prone, unfortunately.
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,10 @@ proc endsWith*(s, suffix: cstring): bool {.noSideEffect,
|
||||||
|
|
||||||
proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect,
|
proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect,
|
||||||
rtl, extern: "csuCmpIgnoreStyle".} =
|
rtl, extern: "csuCmpIgnoreStyle".} =
|
||||||
## Compares two strings normalized (i.e. case and
|
## Semantically the same as ``cmp(normalize($a), normalize($b))``. It
|
||||||
## underscores do not matter). Returns:
|
## is just optimized to not allocate temporary strings. This should
|
||||||
|
## NOT be used to compare Nim identifier names. use `macros.eqIdent`
|
||||||
|
## for that. Returns:
|
||||||
##
|
##
|
||||||
## | 0 iff a == b
|
## | 0 iff a == b
|
||||||
## | < 0 iff a < b
|
## | < 0 iff a < b
|
||||||
|
|
|
||||||
|
|
@ -385,8 +385,8 @@ proc normalize*(s: string): string {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuNormalize".} =
|
rtl, extern: "nsuNormalize".} =
|
||||||
## Normalizes the string `s`.
|
## Normalizes the string `s`.
|
||||||
##
|
##
|
||||||
## That means to convert it to lower case and remove any '_'. This is needed
|
## That means to convert it to lower case and remove any '_'. This
|
||||||
## for Nim identifiers for example.
|
## should NOT be used to normalize Nim identifier names.
|
||||||
result = newString(s.len)
|
result = newString(s.len)
|
||||||
var j = 0
|
var j = 0
|
||||||
for i in 0..len(s) - 1:
|
for i in 0..len(s) - 1:
|
||||||
|
|
@ -418,8 +418,10 @@ proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
|
||||||
|
|
||||||
proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
|
proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
|
||||||
rtl, extern: "nsuCmpIgnoreStyle", procvar.} =
|
rtl, extern: "nsuCmpIgnoreStyle", procvar.} =
|
||||||
## Compares two strings normalized (i.e. case and
|
## Semantically the same as ``cmp(normalize(a), normalize(b))``. It
|
||||||
## underscores do not matter). Returns:
|
## is just optimized to not allocate temporary strings. This should
|
||||||
|
## NOT be used to compare Nim identifier names. use `macros.eqIdent`
|
||||||
|
## for that. Returns:
|
||||||
##
|
##
|
||||||
## | 0 iff a == b
|
## | 0 iff a == b
|
||||||
## | < 0 iff a < b
|
## | < 0 iff a < b
|
||||||
|
|
@ -436,7 +438,6 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
|
||||||
inc(i)
|
inc(i)
|
||||||
inc(j)
|
inc(j)
|
||||||
|
|
||||||
|
|
||||||
proc strip*(s: string, leading = true, trailing = true,
|
proc strip*(s: string, leading = true, trailing = true,
|
||||||
chars: set[char] = Whitespace): string
|
chars: set[char] = Whitespace): string
|
||||||
{.noSideEffect, rtl, extern: "nsuStrip".} =
|
{.noSideEffect, rtl, extern: "nsuStrip".} =
|
||||||
|
|
|
||||||
|
|
@ -18,5 +18,47 @@ macro test*(a: untyped): untyped =
|
||||||
t.b = true
|
t.b = true
|
||||||
t.z = 4.5
|
t.z = 4.5
|
||||||
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
"hi"
|
"hi"
|
||||||
|
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
template assertNot(arg: untyped): untyped =
|
||||||
|
assert(not(arg))
|
||||||
|
|
||||||
|
static:
|
||||||
|
## test eqIdent
|
||||||
|
let a = "abc_def"
|
||||||
|
let b = "abcDef"
|
||||||
|
let c = "AbcDef"
|
||||||
|
|
||||||
|
assert eqIdent( a , b )
|
||||||
|
assert eqIdent(newIdentNode(a), b )
|
||||||
|
assert eqIdent( a , newIdentNode(b))
|
||||||
|
assert eqIdent(newIdentNode(a), newIdentNode(b))
|
||||||
|
|
||||||
|
assert eqIdent( a , b )
|
||||||
|
assert eqIdent(genSym(nskLet, a), b )
|
||||||
|
assert eqIdent( a , genSym(nskLet, b))
|
||||||
|
assert eqIdent(genSym(nskLet, a), genSym(nskLet, b))
|
||||||
|
|
||||||
|
assert eqIdent(newIdentNode( a), newIdentNode( b))
|
||||||
|
assert eqIdent(genSym(nskLet, a), newIdentNode( b))
|
||||||
|
assert eqIdent(newIdentNode( a), genSym(nskLet, b))
|
||||||
|
assert eqIdent(genSym(nskLet, a), genSym(nskLet, b))
|
||||||
|
|
||||||
|
assertNot eqIdent( c , b )
|
||||||
|
assertNot eqIdent(newIdentNode(c), b )
|
||||||
|
assertNot eqIdent( c , newIdentNode(b))
|
||||||
|
assertNot eqIdent(newIdentNode(c), newIdentNode(b))
|
||||||
|
|
||||||
|
assertNot eqIdent( c , b )
|
||||||
|
assertNot eqIdent(genSym(nskLet, c), b )
|
||||||
|
assertNot eqIdent( c , genSym(nskLet, b))
|
||||||
|
assertNot eqIdent(genSym(nskLet, c), genSym(nskLet, b))
|
||||||
|
|
||||||
|
assertNot eqIdent(newIdentNode( c), newIdentNode( b))
|
||||||
|
assertNot eqIdent(genSym(nskLet, c), newIdentNode( b))
|
||||||
|
assertNot eqIdent(newIdentNode( c), genSym(nskLet, b))
|
||||||
|
assertNot eqIdent(genSym(nskLet, c), genSym(nskLet, b))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue