Skip to content

Commit 6fe9281

Browse files
committed
tinker tinker
1 parent fc56f85 commit 6fe9281

File tree

9 files changed

+147
-157
lines changed

9 files changed

+147
-157
lines changed

Makefile

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,8 @@ SOURCE=$(shell find . -iname "*.go")
33

44

55

6-
dist/lib.wasm: $(SOURCE)
6+
web/src/assets/wasm/lib.wasm: $(SOURCE)
77
mkdir -p dist
88
rm -f dist/*
9-
cp "$(shell go env GOROOT)/misc/wasm/wasm_exec.js" dist/wasm_exec.js
10-
GOOS=js GOARCH=wasm go build -ldflags="-s -w" -o ./dist/lib.wasm cmd/wasm/main.go
11-
12-
web/wasm/lib.wasm: dist/lib.wasm
13-
mkdir -p web/wasm
14-
cp dist/lib.wasm web/wasm/lib.wasm
9+
cp "$(shell go env GOROOT)/misc/wasm/wasm_exec.js" web/src/assets/wasm/wasm_exec.js
10+
GOOS=js GOARCH=wasm go build -ldflags="-s -w" -o ./web/src/assets/wasm/lib.wasm cmd/wasm/main.go

pkg/jsonpath/ast.go

Lines changed: 25 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,50 @@ const (
99

1010
// Node represents a node in the JSONPath AST.
1111
type Node interface {
12-
Pos() TokenInfo // position of the first token belonging to the node
13-
End() TokenInfo // position of the first token immediately after the node
14-
String() string // print pretty.
12+
Kind() Kind // The Kind of the node
1513
}
1614

15+
type Segment = Node
16+
1717
// JSONPath expression built from segments that have
1818
// been syntactically restricted in a certain way (Section 2.3.5.1)
1919
type Query struct {
2020
RootNode TokenInfo
2121
Segments []Segment
2222
}
2323

24+
var _ Node = DescendantSegment{}
25+
26+
type DescendantKind int
27+
28+
const (
29+
DescendantWildcardSelector = iota
30+
DescendantDotNameSelector
31+
DescendantLongSelector
32+
)
33+
34+
var _ Segment = DescendantSegment{}
35+
36+
type DescendantSegment struct {
37+
SubKind DescendantKind
38+
LongFormInner Segment
39+
}
40+
41+
func (d DescendantSegment) Kind() Kind {
42+
return DescendantSegmentKind
43+
}
44+
2445
// One of the constructs that selects children ([<selectors>])
2546
// or descendants (..[<selectors>]) of an input value
2647
// segment = child-segment / descendant-segment
27-
type Segment struct {
28-
Kind Kind
29-
ChildSegment ChildSegment
30-
DescendantSegment DescendantSegment
31-
}
3248

3349
// child-segment = bracketed-selection /
3450
//
3551
// ("."
3652
// (wildcard-selector /
3753
// member-name-shorthand))
3854
type ChildSegment struct {
55+
Kind Kind
3956
}
4057

4158
// Expr represents a JSONPath expression.
@@ -60,110 +77,13 @@ type CurrentNode struct {
6077
At TokenInfo // position of "@"
6178
}
6279

63-
func (n *CurrentNode) Pos() TokenInfo { return n.At }
64-
func (n *CurrentNode) End() TokenInfo {
65-
return TokenInfo{Token: n.At.Token, Line: n.At.Line, Column: n.At.Column + 1}
66-
}
67-
func (n *CurrentNode) exprNode() {}
68-
69-
// IdentifierNode represents an identifier in a JSONPath expression.
70-
type IdentifierNode struct {
71-
Name TokenInfo // identifier name
72-
}
73-
74-
func (n *IdentifierNode) Pos() TokenInfo { return n.Name }
75-
func (n *IdentifierNode) End() TokenInfo {
76-
return TokenInfo{Token: n.Name.Token, Line: n.Name.Line, Column: n.Name.Column + len(n.Name.Literal)}
77-
}
78-
func (n *IdentifierNode) exprNode() {}
79-
80-
// WildcardNode represents a wildcard in a JSONPath expression.
81-
type WildcardNode struct {
82-
Star TokenInfo // position of "*"
83-
}
84-
85-
func (n *WildcardNode) Pos() TokenInfo { return n.Star }
86-
func (n *WildcardNode) End() TokenInfo {
87-
return TokenInfo{Token: n.Star.Token, Line: n.Star.Line, Column: n.Star.Column + 1}
88-
}
89-
func (n *WildcardNode) exprNode() {}
90-
91-
// RecursiveDescentNode represents a recursive descent operator in a JSONPath expression.
92-
type RecursiveDescentNode struct {
93-
DoubleDot TokenInfo // position of ".."
94-
}
95-
96-
func (n *RecursiveDescentNode) Pos() TokenInfo { return n.DoubleDot }
97-
func (n *RecursiveDescentNode) End() TokenInfo {
98-
return TokenInfo{Token: n.DoubleDot.Token, Line: n.DoubleDot.Line, Column: n.DoubleDot.Column + 2}
99-
}
100-
func (n *RecursiveDescentNode) exprNode() {}
101-
102-
// SubscriptNode represents a subscript operator in a JSONPath expression.
103-
type SubscriptNode struct {
104-
Lbrack TokenInfo // position of "["
105-
Index Expr // subscript index expression
106-
Rbrack TokenInfo // position of "]"
107-
}
108-
109-
func (n *SubscriptNode) Pos() TokenInfo { return n.Lbrack }
110-
func (n *SubscriptNode) End() TokenInfo {
111-
return TokenInfo{Token: n.Rbrack.Token, Line: n.Rbrack.Line, Column: n.Rbrack.Column + 1}
112-
}
113-
func (n *SubscriptNode) exprNode() {}
114-
115-
// SliceNode represents a slice operator in a JSONPath expression.
116-
type SliceNode struct {
117-
Lbrack TokenInfo // position of "["
118-
Start Expr // start index expression
119-
Colon1 TokenInfo // position of first ":"
120-
Finish Expr // end index expression
121-
Colon2 TokenInfo // position of second ":", if any
122-
Step Expr // step expression
123-
Rbrack TokenInfo // position of "]"
124-
}
125-
126-
func (n *SliceNode) Pos() TokenInfo { return n.Lbrack }
127-
func (n *SliceNode) End() TokenInfo {
128-
return TokenInfo{Token: n.Rbrack.Token, Line: n.Rbrack.Line, Column: n.Rbrack.Column + 1}
129-
}
130-
func (n *SliceNode) exprNode() {}
131-
132-
// UnionNode represents a union operator in a JSONPath expression.
133-
type UnionNode struct {
134-
Lhs Expr // left-hand side expression
135-
Comma TokenInfo // position of ","
136-
Rhs Expr // right-hand side expression
137-
}
138-
139-
func (n *UnionNode) Pos() TokenInfo { return n.Lhs.Pos() }
140-
func (n *UnionNode) End() TokenInfo { return n.Rhs.End() }
141-
func (n *UnionNode) exprNode() {}
142-
143-
// FilterNode represents a filter expression in a JSONPath expression.
144-
type FilterNode struct {
145-
Lbrack TokenInfo // position of "["
146-
Expr Expr // filter expression
147-
Rbrack TokenInfo // position of "]"
148-
}
149-
150-
func (n *FilterNode) Pos() TokenInfo { return n.Lbrack }
151-
func (n *FilterNode) End() TokenInfo {
152-
return TokenInfo{Token: n.Rbrack.Token, Line: n.Rbrack.Line, Column: n.Rbrack.Column + 1}
153-
}
154-
func (n *FilterNode) exprNode() {}
155-
15680
// ComparisonNode represents a comparison expression in a JSONPath filter.
15781
type ComparisonNode struct {
15882
Lhs Expr // left-hand side expression
15983
Operator TokenInfo // comparison operator
16084
Rhs Expr // right-hand side expression
16185
}
16286

163-
func (n *ComparisonNode) Pos() TokenInfo { return n.Lhs.Pos() }
164-
func (n *ComparisonNode) End() TokenInfo { return n.Rhs.End() }
165-
func (n *ComparisonNode) exprNode() {}
166-
16787
// BooleanNode represents a boolean literal in a JSONPath expression.
16888
type BooleanNode struct {
16989
Value TokenInfo // boolean value

pkg/jsonpath/parser.go

Lines changed: 77 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ var (
1313
type Parser struct {
1414
tokenizer *Tokenizer
1515
tokens []TokenInfo
16-
root Node
16+
segments []Segment
1717
current int
1818
}
1919

@@ -30,60 +30,65 @@ func (p *Parser) Parse() (Node, error) {
3030
return nil, fmt.Errorf("empty JSONPath expression")
3131
}
3232

33-
if p.root != nil {
34-
return p.root, nil
35-
}
36-
3733
if p.tokens[p.current].Token != ROOT {
3834
return nil, fmt.Errorf("%s: %w", p.tokenizer.ErrorString(p.tokens[p.current], fmt.Sprintf("unexpected token (expected '$')")), ParseError)
3935
}
40-
root, err := p.parseRoot()
36+
p.current++
37+
4138
for p.current < len(p.tokens) {
42-
p.parseSegment()
39+
segment, err := p.parseSegment()
40+
if err != nil {
41+
return nil, err
42+
}
43+
p.segments = append(p.segments, segment)
4344
}
4445

4546
if p.current < len(p.tokens) {
4647
return nil, fmt.Errorf(p.tokenizer.ErrorString(p.tokens[p.current], fmt.Sprintf("unexpected token")))
4748
}
48-
49-
p.root = root
50-
51-
return root, nil
52-
}
53-
54-
// parseRoot parses the root node.
55-
func (p *Parser) parseRoot() (*RootNode, error) {
56-
node := &RootNode{Dollar: p.tokens[p.current]}
57-
p.current++
58-
return node, nil
5949
}
6050

61-
// parseCurrent parses the current node.
62-
func (p *Parser) parseCurrent() (*CurrentNode, error) {
63-
node := &CurrentNode{At: p.tokens[p.current]}
64-
p.current++
65-
return node, nil
66-
}
51+
// parseDescendantSegment parses a descendant segment (preceded by "..").
52+
func (p *Parser) parseDescendantSegment() (*DescendantSegment, error) {
53+
if p.tokens[p.current].Token != RECURSIVE {
54+
return nil, p.parseFailure(p.tokens[p.current], "expected '..'")
55+
}
6756

68-
// parseIdentifier parses an identifier node.
69-
func (p *Parser) parseIdentifier() (*IdentifierNode, error) {
70-
node := &IdentifierNode{Name: p.tokens[p.current]}
71-
p.current++
72-
return node, nil
73-
}
57+
// three kinds of descendant segments
58+
// "..*" -> recursive wildcard
59+
// "..STRING_LITERAL" -> recursive hunt for an identifier
60+
// "..[INNER_SEGMENT]" -> recursive hunt for some inner expression (e.g. a filter expression)
61+
nextToken := p.tokens[p.current+1]
62+
if nextToken.Token == WILDCARD {
63+
node := &DescendantSegment{SubKind: DescendantWildcardSelector}
64+
p.current += 2
65+
return node, nil
66+
} else if nextToken.Token == STRING_LITERAL {
67+
node := &DescendantSegment{SubKind: DescendantDotNameSelector}
68+
p.current += 2
69+
return node, nil
70+
} else if nextToken.Token == BRACE_LEFT {
71+
node := &DescendantSegment{SubKind: DescendantLongSelector}
72+
previousCurrent := p.current
73+
p.current += 2
74+
innerSegment, err := p.parseSegment()
75+
node.LongFormInner = innerSegment
76+
if err != nil {
77+
p.current = previousCurrent
78+
return nil, err
79+
}
80+
if p.tokens[p.current].Token != BRACE_RIGHT {
81+
p.current = previousCurrent
82+
return nil, p.parseFailure(p.tokens[p.current], "expected ']'")
83+
}
84+
return node, nil
85+
}
7486

75-
// parseWildcard parses a wildcard node.
76-
func (p *Parser) parseWildcard() (*WildcardNode, error) {
77-
node := &WildcardNode{Star: p.tokens[p.current]}
78-
p.current++
79-
return node, nil
87+
return nil, p.parseFailure(nextToken, "unexpected descendant segment")
8088
}
8189

82-
// parseRecursiveDescent parses a recursive descent node.
83-
func (p *Parser) parseRecursiveDescent() (*RecursiveDescentNode, error) {
84-
node := &RecursiveDescentNode{DoubleDot: p.tokens[p.current]}
85-
p.current++
86-
return node, nil
90+
func (p *Parser) parseFailure(target TokenInfo, msg string) error {
91+
return errors.New(p.tokenizer.ErrorTokenString(target, msg))
8792
}
8893

8994
// parseSubscriptOrFilter parses a subscript or filter node.
@@ -289,3 +294,35 @@ func (p *Parser) expect(token Token) bool {
289294
func (p *Parser) isComparisonOperator(token Token) bool {
290295
return token == EQ || token == NE || token == GT || token == GE || token == LT || token == LE
291296
}
297+
298+
func (p *Parser) parseSegment() (Segment, error) {
299+
currentToken := p.tokens[p.current]
300+
if currentToken.Token == RECURSIVE {
301+
node, err := p.parseDescendantSegment()
302+
if err != nil {
303+
return nil, err
304+
}
305+
return node, nil
306+
}
307+
return p.parseChildSegment()
308+
}
309+
310+
func (p *Parser) parseChildSegment() (Segment, error) {
311+
firstToken := p.tokens[p.current]
312+
if firstToken.Token == DOT && p.tokens[p.current+1].Token == WILDCARD {
313+
p.current += 2
314+
return &ChildSegment{: firstToken, Star: p.tokens[p.current]}, nil
315+
} else if firstToken.Token == DOT && p.tokens[p.current+1].Token == STRING_LITERAL {
316+
p.current += 2
317+
return &DotNameSegment{Dot: firstToken, Name: p.tokens[p.current]}, nil
318+
} else if firstToken.Token == DOT && p.tokens[p.current+1].Token == BRACE_LEFT {
319+
p.current += 2
320+
innerSegment, err := p.parseSegment()
321+
if err != nil {
322+
return nil, err
323+
}
324+
if p.tokens[p.current].Token != BRACE_RIGHT {
325+
// .*
326+
// .STRING_LITERAL
327+
// []
328+
}

pkg/jsonpath/token.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,6 @@ func (t *Tokenizer) scanString(quote rune) {
493493
t.column += i - start + 1
494494
return
495495
}
496-
foo := "\f"
497496
if t.input[i] == '\\' {
498497
escaped = !escaped
499498
} else {

web/.eslintrc.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module.exports = {
1414
'react/jsx-uses-react': 'off',
1515
'react/react-in-jsx-scope': 'off',
1616
"no-unused-vars": "off",
17+
"no-undef": "off",
1718
"@typescript-eslint/no-unused-vars": ["error", {
1819
'argsIgnorePattern': '^_',
1920
'varsIgnorePattern': '^_',

web/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ yarn-debug.log*
66
yarn-error.log*
77
pnpm-debug.log*
88
lerna-debug.log*
9-
wasm/*
9+
src/assets/wasm/*
1010
node_modules
1111
dist
1212
dist-ssr

web/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>Vite + React + TS</title>
8+
<script src="/src/assets/wasm/wasm_exec.js"></script>
89
</head>
910
<body>
1011
<div id="root"></div>

0 commit comments

Comments
 (0)