move eqIdent to vm.nim (#7585)

* Strutils comment changes.

* fix typo
This commit is contained in:
Arne Döring
2018-04-15 23:38:43 +02:00
committed by Andreas Rumpf
parent c9f14ca9be
commit ed5b7cbac0
7 changed files with 132 additions and 41 deletions

View File

@@ -114,3 +114,4 @@ proc initDefines*() =
defineSymbol("nimNewDot")
defineSymbol("nimHasNilChecks")
defineSymbol("nimSymKind")
defineSymbol("nimVmEqIdent")

View File

@@ -37,7 +37,7 @@ proc resetIdentCache*() =
for i in low(legacy.buckets)..high(legacy.buckets):
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
var i = 0
var j = 0

View File

@@ -1392,10 +1392,36 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node.typ = n.typ
of opcEqIdent:
decodeBC(rkInt)
if regs[rb].node.kind == nkIdent and regs[rc].node.kind == nkIdent:
regs[ra].intVal = ord(regs[rb].node.ident.id == regs[rc].node.ident.id)
# aliases for shorter and easier to understand code below
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:
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:
decodeB(rkNode)
if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:

View File

@@ -1186,38 +1186,57 @@ proc copy*(node: NimNode): NimNode {.compileTime.} =
## An alias for copyNimTree().
return node.copyNimTree()
proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
proc toLower(c: char): char {.inline.} =
if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A')))
else: result = c
var i = 0
var j = 0
# first char is case sensitive
if a[0] != b[0]: return 1
while true:
while a[i] == '_': inc(i)
while b[j] == '_': inc(j) # BUGFIX: typo
var aa = toLower(a[i])
var bb = toLower(b[j])
result = ord(aa) - ord(bb)
if result != 0 or aa == '\0': break
inc(i)
inc(j)
when defined(nimVmEqIdent):
proc eqIdent*(a: string; b: string): bool {.magic: "EqIdent", noSideEffect.}
## Style insensitive comparison.
proc eqIdent*(a, b: string): bool = cmpIgnoreStyle(a, b) == 0
## Check if two idents are identical.
proc eqIdent*(a: NimNode; b: string): bool {.magic: "EqIdent", noSideEffect.}
## Style insensitive comparison.
## ``a`` can be an identifier or a symbol.
proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} =
## 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
## other ways like ``node.ident`` are much more error-prone, unfortunately.
case node.kind
of nnkSym, nnkIdent:
result = eqIdent(node.strVal, s)
of nnkOpenSymChoice, nnkClosedSymChoice:
result = eqIdent($node[0], s)
else:
result = false
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.} =
if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A')))
else: result = c
var i = 0
var j = 0
# first char is case sensitive
if a[0] != b[0]: return 1
while true:
while a[i] == '_': inc(i)
while b[j] == '_': inc(j) # BUGFIX: typo
var aa = toLower(a[i])
var bb = toLower(b[j])
result = ord(aa) - ord(bb)
if result != 0 or aa == '\0': break
inc(i)
inc(j)
proc eqIdent*(a, b: string): bool = cmpIgnoreStyle(a, b) == 0
## Check if two idents are identical.
proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} =
## 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
## other ways like ``node.ident`` are much more error-prone, unfortunately.
case node.kind
of nnkSym, nnkIdent:
result = eqIdent(node.strVal, s)
of nnkOpenSymChoice, nnkClosedSymChoice:
result = eqIdent($node[0], s)
else:
result = false
proc hasArgOfName*(params: NimNode; name: string): bool {.compiletime.}=
## Search nnkFormalParams for an argument.

View File

@@ -45,8 +45,10 @@ proc endsWith*(s, suffix: cstring): bool {.noSideEffect,
proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect,
rtl, extern: "csuCmpIgnoreStyle".} =
## Compares two strings normalized (i.e. case and
## underscores do not matter). Returns:
## Semantically the same as ``cmp(normalize($a), normalize($b))``. It
## 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

View File

@@ -385,8 +385,8 @@ proc normalize*(s: string): string {.noSideEffect, procvar,
rtl, extern: "nsuNormalize".} =
## Normalizes the string `s`.
##
## That means to convert it to lower case and remove any '_'. This is needed
## for Nim identifiers for example.
## That means to convert it to lower case and remove any '_'. This
## should NOT be used to normalize Nim identifier names.
result = newString(s.len)
var j = 0
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,
rtl, extern: "nsuCmpIgnoreStyle", procvar.} =
## Compares two strings normalized (i.e. case and
## underscores do not matter). Returns:
## Semantically the same as ``cmp(normalize(a), normalize(b))``. It
## 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
@@ -436,7 +438,6 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
inc(i)
inc(j)
proc strip*(s: string, leading = true, trailing = true,
chars: set[char] = Whitespace): string
{.noSideEffect, rtl, extern: "nsuStrip".} =

View File

@@ -18,5 +18,47 @@ macro test*(a: untyped): untyped =
t.b = true
t.z = 4.5
test:
"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))