1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
#
#
# The Nim Compiler
# (c) Copyright 2017 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
from strutils import toLowerAscii
type
PrefixMatch* {.pure.} = enum
None, ## no prefix detected
Abbrev ## prefix is an abbreviation of the symbol
Substr, ## prefix is a substring of the symbol
Prefix, ## prefix does match the symbol
proc prefixMatch*(p, s: string): PrefixMatch =
template eq(a, b): bool = a.toLowerAscii == b.toLowerAscii
if p.len > s.len: return PrefixMatch.None
var i = 0
let L = s.len
# check for prefix/contains:
while i < L:
if s[i] == '_': inc i
if eq(s[i], p[0]):
var ii = i+1
var jj = 1
while ii < L and jj < p.len:
if p[jj] == '_': inc jj
if s[ii] == '_': inc ii
if not eq(s[ii], p[jj]): break
inc ii
inc jj
if jj >= p.len:
if i == 0: return PrefixMatch.Prefix
else: return PrefixMatch.Substr
inc i
# check for abbrev:
if eq(s[0], p[0]):
i = 1
var j = 1
while i < s.len:
if s[i] == '_' and i < s.len-1:
if j < p.len and eq(p[j], s[i+1]): inc j
else: return PrefixMatch.None
if s[i] in {'A'..'Z'} and s[i-1] notin {'A'..'Z'}:
if j < p.len and eq(p[j], s[i]): inc j
else: return PrefixMatch.None
inc i
if j >= p.len:
return PrefixMatch.Abbrev
else:
return PrefixMatch.None
return PrefixMatch.None
when isMainModule:
import macros
macro check(val, body: untyped): untyped =
result = newStmtList()
expectKind body, nnkStmtList
for b in body:
expectKind b, nnkPar
expectLen b, 2
let p = b[0]
let s = b[1]
result.add quote do:
echo prefixMatch(`p`, `s`) == `val`
check PrefixMatch.Prefix:
("abc", "abc")
("a", "abc")
("xyz", "X_yzzzZe")
check PrefixMatch.Substr:
("b", "abc")
("abc", "fooabcabc")
("abC", "foo_AB_c")
check PrefixMatch.Abbrev:
("abc", "AxxxBxxxCxxx")
("xyz", "X_yabcZe")
check PrefixMatch.None:
("foobar", "afkslfjd_as")
("xyz", "X_yuuZuuZe")
("ru", "remotes")
|