Skip to content

Commit 55de490

Browse files
committed
perf: selector ast
1 parent 76a3a32 commit 55de490

File tree

8 files changed

+57
-66
lines changed

8 files changed

+57
-66
lines changed

selector/src/commonMain/kotlin/li/songe/selector/Exception.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ sealed class GkdException(override val message: String) : Exception(message) {
1313
}
1414

1515
@JsExport
16-
data class SyntaxException(override val message: String) : GkdException(message)
16+
data class SyntaxException(
17+
override val message: String,
18+
val expectedValue: String,
19+
val index: Int
20+
) : GkdException(message)
1721

1822
@JsExport
1923
sealed class TypeException(override val message: String) : GkdException(message)

selector/src/commonMain/kotlin/li/songe/selector/connect/PolynomialExpression.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package li.songe.selector.connect
22

3-
import li.songe.selector.SyntaxException
43
import kotlin.js.JsExport
54

65
/**
@@ -43,7 +42,7 @@ data class PolynomialExpression(val a: Int = 0, val b: Int = 1) : ConnectExpress
4342
}
4443

4544
private fun invalidValue(): Nothing {
46-
throw SyntaxException("invalid Polynomial: a=$a, b=$b")
45+
error("invalid Polynomial: a=$a, b=$b")
4746
}
4847

4948
override val minOffset = if (a > 0) {

selector/src/commonMain/kotlin/li/songe/selector/parser/AstNode.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ data class AstNode<T : Any>(
1515
val outChildren by lazy { children.toTypedArray() }
1616

1717
val name: String
18-
get() = value.let { it::class.simpleName }.toString()
18+
get() = value::class.simpleName.toString()
1919

2020
override fun stringify(): String {
2121
if (children.isEmpty()) {

selector/src/commonMain/kotlin/li/songe/selector/parser/AstParser.kt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,9 @@ internal class AstParser(override val source: String) : SelectorParser(source) {
167167
}
168168

169169
override fun mergeCallExpression(expression: ValueExpression.CallExpression) {
170-
if (source[i - 1] != ')') {
171-
errorExpect("CallExpression End")
172-
}
170+
// [lastToken, (, ...arguments, ',', )]
173171
val children = tempAstContext.children.subList(
174-
tempAstContext.children.size - expression.arguments.size - 1,
172+
tempAstContext.children.indexOfFirst { it.value === expression.callee },
175173
tempAstContext.children.size
176174
).toMutableList()
177175
repeat(children.size) {
@@ -223,9 +221,7 @@ internal class AstParser(override val source: String) : SelectorParser(source) {
223221

224222
override fun readString() = createAstNode { super.readString() }
225223

226-
override fun readUnitSelectorExpression() = createAstNode {
227-
super.readUnitSelectorExpression()
228-
}
224+
override fun readUnitSelectorExpression() = createAstNode { super.readUnitSelectorExpression() }
229225

230226
override fun readValueExpression() = createAstNode { super.readValueExpression() }
231227

@@ -241,4 +237,10 @@ internal class AstParser(override val source: String) : SelectorParser(source) {
241237

242238
override fun readTupleExpression() = createAstNode { super.readTupleExpression() }
243239

240+
override fun readPlainChar(v: Char) {
241+
createAstNode {
242+
super.readPlainChar(v)
243+
v.toString()
244+
}
245+
}
244246
}

selector/src/commonMain/kotlin/li/songe/selector/parser/BaseParser.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,20 +171,23 @@ internal sealed interface BaseParser {
171171
return false
172172
}
173173

174-
fun <T: Any> readBracketExpression(block: () -> T): T {
175-
expectChar('(')
174+
fun readPlainChar(v: Char) {
175+
expectChar(v)
176176
i++
177+
}
178+
179+
fun <T : Any> readBracketExpression(block: () -> T): T {
180+
readPlainChar('(')
177181
readWhiteSpace()
178182
return block().apply {
179183
readWhiteSpace()
180-
expectChar(')')
181-
i++
184+
readPlainChar(')')
182185
}
183186
}
184187
}
185188

186189
internal fun BaseParser.errorExpect(name: String): Nothing {
187-
throw SyntaxException("Expect $name, got ${char.escapeString()} at index $i")
190+
throw SyntaxException("Expect $name, got ${char.escapeString()} at index $i", name, i)
188191
}
189192

190193
internal fun BaseParser.expectOneOfChar(v: String, name: String? = null): Char {

selector/src/commonMain/kotlin/li/songe/selector/parser/ConnectParser.kt

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package li.songe.selector.parser
22

3-
import li.songe.selector.SyntaxException
43
import li.songe.selector.connect.ConnectExpression
54
import li.songe.selector.connect.ConnectOperator
65
import li.songe.selector.connect.ConnectSegment
@@ -82,8 +81,7 @@ internal sealed interface ConnectParser : BaseParser {
8281

8382
// (1,2,3)
8483
fun readTupleExpression(): TupleExpression {
85-
expectChar('(')
86-
i++
84+
readPlainChar('(')
8785
readWhiteSpace()
8886
val numbers = mutableListOf<Int>()
8987
expectOneOfChar(POSITIVE_DIGIT_CHAR, "POSITIVE_DIGIT_CHAR")
@@ -99,12 +97,11 @@ internal sealed interface ConnectParser : BaseParser {
9997
numbers.add(v)
10098
readWhiteSpace()
10199
if (char == ',') {
102-
i++
100+
readPlainChar(',')
103101
readWhiteSpace()
104102
}
105103
}
106-
expectChar(')')
107-
i++
104+
readPlainChar(')')
108105
return TupleExpression(numbers)
109106
}
110107

@@ -114,7 +111,7 @@ internal sealed interface ConnectParser : BaseParser {
114111
val start = i
115112
val monomials = mutableListOf<Monomial>()
116113
if (char == '(') {
117-
i++
114+
readPlainChar('(')
118115
readWhiteSpace()
119116
while (true) {
120117
if (monomials.isNotEmpty()) {
@@ -135,8 +132,7 @@ internal sealed interface ConnectParser : BaseParser {
135132
break
136133
}
137134
}
138-
expectChar(')')
139-
i++
135+
readPlainChar(')')
140136
} else {
141137
monomials.add(readMonomial())
142138
}
@@ -146,7 +142,7 @@ internal sealed interface ConnectParser : BaseParser {
146142
a = monomials.find { it.power == 1 }?.coefficient ?: 0,
147143
b = monomials.find { it.power == 0 }?.coefficient ?: 0
148144
)
149-
} catch (_: SyntaxException) {
145+
} catch (_: Throwable) {
150146
i = start
151147
errorExpect("valid an+b polynomial")
152148
}

selector/src/commonMain/kotlin/li/songe/selector/parser/PropertyParser.kt

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,14 @@ internal sealed interface PropertyParser : BaseParser {
8888
if (lastToken !is ValueExpression.Variable) {
8989
errorExpect("Variable End")
9090
}
91-
i++
91+
readPlainChar('.')
9292
readWhiteSpace()
9393
lastToken = ValueExpression.MemberExpression(
9494
lastToken,
9595
readVariableName()
9696
).apply { mergeMemberExpression(this) }
9797
} else if (c == '(') {
98-
i++
98+
readPlainChar('(')
9999
readWhiteSpace()
100100
if (lastToken != null) {
101101
// 暂不支持 object()()
@@ -106,22 +106,20 @@ internal sealed interface PropertyParser : BaseParser {
106106
while (char.inStr(VALUE_START_CHAR)) {
107107
arguments.add(readValueExpression())
108108
if (char == ',') {
109-
i++
109+
readPlainChar(',')
110110
readWhiteSpace()
111111
}
112112
}
113113
readWhiteSpace()
114-
expectChar(')')
115-
i++
114+
readPlainChar(')')
116115
lastToken = ValueExpression.CallExpression(
117116
lastToken,
118117
arguments
119118
).apply { mergeCallExpression(this) }
120119
} else {
121120
return readValueExpression().apply {
122121
readWhiteSpace()
123-
expectChar(')')
124-
i++
122+
readPlainChar(')')
125123
}
126124
}
127125
} else {
@@ -145,8 +143,8 @@ internal sealed interface PropertyParser : BaseParser {
145143
if (it is ValueExpression.StringLiteral && (operator == CompareOperator.Matches || operator == CompareOperator.NotMatches)) {
146144
val matches = try {
147145
it.value.toMatches()
148-
} catch (_: Exception) {
149-
i = regexIndex
146+
} catch (_: Throwable) {// support kotlin js
147+
i = regexIndex + 1
150148
errorExpect("valid regex string")
151149
}
152150
it.copy(matches = matches)
@@ -162,16 +160,10 @@ internal sealed interface PropertyParser : BaseParser {
162160
}
163161

164162
fun readNotExpression(): NotExpression {
165-
expectChar('!')
166-
i++
167-
expectChar('(')
168-
i++
169-
readWhiteSpace()
170-
return NotExpression(readExpression()).apply {
171-
readWhiteSpace()
172-
expectChar(')')
173-
i++
174-
}
163+
readPlainChar('!')
164+
return NotExpression(readBracketExpression {
165+
readExpression()
166+
})
175167
}
176168

177169
fun mergeLogicalExpression(expression: LogicalExpression) {}
@@ -213,6 +205,9 @@ internal sealed interface PropertyParser : BaseParser {
213205
readWhiteSpace()
214206
}
215207
rollbackWhiteSpace()
208+
if (tokens.isEmpty()) {
209+
errorExpect("EXP_START_CHAR")
210+
}
216211
if (tokens.size == 1) {
217212
return tokens.first() as Expression
218213
}
@@ -282,21 +277,19 @@ internal sealed interface PropertyParser : BaseParser {
282277

283278
// [a=b||c=d]
284279
fun readPropertyUnit(): PropertyUnit {
285-
expectChar('[')
286-
i++
280+
readPlainChar('[')
287281
readWhiteSpace()
288282
return PropertyUnit(readExpression()).apply {
289283
readWhiteSpace()
290-
expectChar(']')
291-
i++
284+
readPlainChar(']')
292285
}
293286
}
294287

295288
// @a[a=b||c=d]
296289
fun readPropertySegment(): PropertySegment {
297290
val at = char == '@'
298291
if (at) {
299-
i++
292+
readPlainChar('@')
300293
}
301294
val name = if (char == '[') {
302295
""

selector/src/commonMain/kotlin/li/songe/selector/parser/SelectorParser.kt

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,10 @@ internal open class SelectorParser(
5151

5252
// !(A > B)
5353
open fun readNotSelectorExpression(): NotSelectorExpression {
54-
expectChar('!')
55-
i++
56-
expectChar('(')
57-
i++
58-
readWhiteSpace()
59-
return NotSelectorExpression(readSelectorExpression()).apply {
60-
readWhiteSpace()
61-
expectChar(')')
62-
i++
63-
}
54+
readPlainChar('!')
55+
return NotSelectorExpression(readBracketExpression {
56+
readSelectorExpression()
57+
})
6458
}
6559

6660
// (A + B) || (A - B)
@@ -100,12 +94,8 @@ internal open class SelectorParser(
10094
break
10195
}
10296
} else if (c == '(') {
103-
i++
104-
readWhiteSpace()
105-
readSelectorExpression().apply {
106-
readWhiteSpace()
107-
expectChar(')')
108-
i++
97+
readBracketExpression {
98+
readSelectorExpression()
10999
}
110100
} else if (c == '!') {
111101
readNotSelectorExpression()
@@ -117,6 +107,10 @@ internal open class SelectorParser(
117107
tokens.add(token)
118108
readWhiteSpace()
119109
}
110+
rollbackWhiteSpace()
111+
if (tokens.isEmpty()) {
112+
errorExpect("selector")
113+
}
120114
if (tokens.size == 1) {
121115
return tokens.first() as SelectorExpression
122116
}

0 commit comments

Comments
 (0)