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
commit ed5b7cbac0
7 changed files with 132 additions and 41 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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".} =

View file

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