Skip to content

Commit dfcf361

Browse files
committed
feat: Support escape delims in string
Change-Id: Idde50fd5af463368743c381cf555e2e382276d61
1 parent 48306eb commit dfcf361

File tree

4 files changed

+38
-11
lines changed

4 files changed

+38
-11
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ NOTE: **The `exprName` under the same struct field cannot be the same!**
109109
|`true` `false`|boolean|
110110
|`0` `0.0`|float64 "0"|
111111
|`''`|String|
112+
|`\\'`| Escape `'` delims in string|
113+
|`\"`| Escape `"` delims in string|
112114
|`nil`|nil, undefined|
113115
|`!`|not, suitable for `bool`, `string`, `float64`, `nil`, `$` and `()`|
114116
|`+`|Digital addition or string splicing|

spec_operand.go

+24-4
Original file line numberDiff line numberDiff line change
@@ -150,23 +150,43 @@ func readPairedSymbol(p *string, left, right rune) *string {
150150
var last1 = left
151151
var last2 rune
152152
var leftLevel, rightLevel int
153+
var escapeIndexes = make(map[int]bool)
154+
var realEqual, escapeEqual bool
153155
for i, r := range s {
154-
if r == right && (last1 != '\\' || last2 == '\\') {
156+
if realEqual, escapeEqual = equalRune(right, r, last1, last2); realEqual {
155157
if leftLevel == rightLevel {
156158
*p = s[i+1:]
157-
sub := s[:i]
158-
return &sub
159+
var sub = make([]rune, 0, i)
160+
for k, v := range s[:i] {
161+
if !escapeIndexes[k] {
162+
sub = append(sub, v)
163+
}
164+
}
165+
s = string(sub)
166+
return &s
159167
}
160168
rightLevel++
161-
} else if r == left && (last1 != '\\' || last2 == '\\') {
169+
} else if escapeEqual {
170+
escapeIndexes[i-1] = true
171+
} else if realEqual, escapeEqual = equalRune(left, r, last1, last2); realEqual {
162172
leftLevel++
173+
} else if escapeEqual {
174+
escapeIndexes[i-1] = true
163175
}
164176
last2 = last1
165177
last1 = r
166178
}
167179
return nil
168180
}
169181

182+
func equalRune(a, b, last1, last2 rune) (real, escape bool) {
183+
if a == b {
184+
real = last1 != '\\' || last2 == '\\'
185+
escape = last1 == '\\' && last2 != '\\'
186+
}
187+
return
188+
}
189+
170190
func getBoolOpposite(expr *string) (string, *bool) {
171191
last := strings.TrimLeft(*expr, "!")
172192
n := len(*expr) - len(last)

spec_test.go

+10-7
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,22 @@ import (
2222

2323
func TestReadPairedSymbol(t *testing.T) {
2424
var cases = []struct {
25-
expr string
26-
val string
27-
lastExprNode string
28-
left, right rune
25+
left, right rune
26+
expr, val, lastExprNode string
2927
}{
30-
{expr: "'true '+'a'", val: "true ", lastExprNode: "+'a'", left: '\'', right: '\''},
31-
{expr: "((0+1)/(2-1)*9)%2", val: "(0+1)/(2-1)*9", lastExprNode: "%2", left: '(', right: ')'},
28+
{left: '\'', right: '\'', expr: "'true '+'a'", val: "true ", lastExprNode: "+'a'"},
29+
{left: '(', right: ')', expr: "((0+1)/(2-1)*9)%2", val: "(0+1)/(2-1)*9", lastExprNode: "%2"},
30+
{left: '(', right: ')', expr: `(\)\(\))`, val: `)()`},
31+
{left: '\'', right: '\'', expr: `'\\'`, val: `\\`},
32+
{left: '\'', right: '\'', expr: `'\'\''`, val: `''`},
3233
}
3334
for _, c := range cases {
3435
t.Log(c.expr)
3536
expr := c.expr
3637
got := readPairedSymbol(&expr, c.left, c.right)
37-
if *got != c.val || expr != c.lastExprNode {
38+
if got == nil {
39+
t.Fatalf("expr: %q, got: %v, %q, want: %q, %q", c.expr, got, expr, c.val, c.lastExprNode)
40+
} else if *got != c.val || expr != c.lastExprNode {
3841
t.Fatalf("expr: %q, got: %q, %q, want: %q, %q", c.expr, *got, expr, c.val, c.lastExprNode)
3942
}
4043
}

validator/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ type T struct {
118118
|`true` `false`|boolean|
119119
|`0` `0.0`|float64 "0"|
120120
|`''`|String|
121+
|`\\'`| Escape `'` delims in string|
122+
|`\"`| Escape `"` delims in string|
121123
|`nil`|nil, undefined|
122124
|`!`|not, suitable for `bool`, `string`, `float64`, `nil`, `$` and `()`|
123125
|`+`|Digital addition or string splicing|

0 commit comments

Comments
 (0)