mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
committed by
Andreas Rumpf
parent
c9f14ca9be
commit
ed5b7cbac0
@@ -114,3 +114,4 @@ proc initDefines*() =
|
||||
defineSymbol("nimNewDot")
|
||||
defineSymbol("nimHasNilChecks")
|
||||
defineSymbol("nimSymKind")
|
||||
defineSymbol("nimVmEqIdent")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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".} =
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user