Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 28 additions & 16 deletions crates/plotnik-lib/src/compile/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ use crate::parser::ast::{self, Expr};
use super::Compiler;
use super::capture::CaptureEffects;
use super::navigation::{
check_trailing_anchor, inner_creates_scope, is_skippable_quantifier,
is_star_or_plus_quantifier, is_truly_empty_scope,
check_trailing_anchor, inner_creates_scope, is_star_or_plus_quantifier, is_truly_empty_scope,
};

impl Compiler<'_> {
Expand Down Expand Up @@ -73,39 +72,52 @@ impl Compiler<'_> {
);
}

// Check if first item is skippable - its skip path should bypass the Up.
// When a zero-match quantifier (? or *) is the first child with Down navigation,
// the skip path never descends, so executing Up would ascend too far.
let first_is_skippable = items
.first()
.and_then(|i| i.as_expr())
.is_some_and(is_skippable_quantifier);
// Split capture.post: Node/Text effects (and their Set) go on entry (need matched_node
// right after match), other effects go on final_exit (after children processing).
// Node/Text capture effects use matched_node which is only valid immediately after the match,
// before descending into children (which may clobber matched_node via backtracking).
use crate::bytecode::EffectOpcode;

// Find Node/Text effects and their following Set effects (they come in pairs: Node Set)
let mut entry_effects = Vec::new();
let mut exit_effects = Vec::new();
let mut iter = capture.post.into_iter().peekable();
while let Some(eff) = iter.next() {
if matches!(eff.opcode, EffectOpcode::Node | EffectOpcode::Text) {
entry_effects.push(eff);
// Take the following Set if present (Node/Text are always followed by Set)
if iter.peek().is_some_and(|e| e.opcode == EffectOpcode::Set) {
entry_effects.push(iter.next().unwrap());
}
} else {
exit_effects.push(eff);
}
}

// With items: nav → items → Up → [post_effects] → exit
// If first item is skippable: skip path → exit (bypass Up), match path → Up → exit
let final_exit = self.emit_post_effects_exit(exit, capture.post);
// With items: nav[entry_effects] → items → Up → [exit_effects] → exit
let final_exit = self.emit_post_effects_exit(exit, exit_effects);

let up_label = self.fresh_label();
let skip_exit = first_is_skippable.then_some(exit);
let items_entry = self.compile_seq_items_inner(
&items,
up_label,
true,
None,
CaptureEffects::default(),
skip_exit,
None, // No skip_exit bypass - all paths need Up
);

self.instructions
.push(MatchIR::epsilon(up_label, final_exit).nav(up_nav).into());

// Emit entry instruction into the node (only pre_effects here)
// Emit entry instruction with node_effects on post (executes right after match)
self.emit_match_with_cascade(
MatchIR::epsilon(entry, items_entry)
.nav(nav)
.node_type(node_type)
.neg_fields(neg_fields)
.pre_effects(capture.pre),
.pre_effects(capture.pre)
.post_effects(entry_effects),
);

entry
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,22 @@ Test:
06 ε 07
07 ! (object) 08
08 ε [Arr] 10
10 ε 39, 20
10 ε 37, 12
12 ε [EndArr Set(M5)] 14
14 △ _ 19
15 ε [EndObj Push] 17
17 ε 45, 12
17 ε 43, 12
19 ▶
20 ε [EndArr Set(M5)] 19
22 ε [Set(M4)] 15
24 ! [Enum(M2)] (pair) [Node Set(M0) EndEnum] 22
27 ! [Enum(M3)] (shorthand_property_identifier) [Node Set(M1) EndEnum] 22
30 ε 24, 27
32 ε [Obj] 30
34 ▷ _ 37
35 ε 34, 20
37 ε 32, 35
39 ▽ _ 37
40 ▷ _ 43
41 ε 40, 12
43 ε 32, 41
45 ▷ _ 43
20 ε [Set(M4)] 15
22 ! [Enum(M2)] (pair) [Node Set(M0) EndEnum] 20
25 ! [Enum(M3)] (shorthand_property_identifier) [Node Set(M1) EndEnum] 20
28 ε 22, 25
30 ε [Obj] 28
32 ▷ _ 35
33 ε 32, 12
35 ε 30, 33
37 ▽ _ 35
38 ▷ _ 41
39 ε 38, 12
41 ε 30, 39
43 ▷ _ 41
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,11 @@ _ObjWrap:

Test:
06 ε 07
07 ! (a) 08
08 ▽ (b) 09
09 ▽ (c) 10
10 ▽ (d) [Node Set(M3)] 12
12 △ _ 13
13 ε [Node Set(M2)] 15
07 ! (a) [Node Set(M0)] 09
09 ▽ (b) [Node Set(M1)] 11
11 ▽ (c) [Node Set(M2)] 13
13 ▽ (d) [Node Set(M3)] 15
15 △ _ 16
16 ε [Node Set(M1)] 18
18 △ _ 19
19 ε [Node Set(M0)] 21
21 ▶
16 △ _ 17
17 △ _ 18
18 ▶
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,9 @@ _ObjWrap:

Test:
06 ε 07
07 ! (a) 08
08 ▽ (b) 09
09 ▽ (c) [Node Set(M2)] 11
11 △ _ 12
12 ε [Node Set(M1)] 14
07 ! (a) [Node Set(M0)] 09
09 ▽ (b) [Node Set(M1)] 11
11 ▽ (c) [Node Set(M2)] 13
13 △ _ 14
14 △ _ 15
15 ε [Node Set(M0)] 17
17 ▶
15 ▶
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,22 @@ Outer:
12 ε 13
13 ! (parent) 14
14 ε [Arr] 16
16 ε 42, 26
16 ε 40, 18
18 ε [EndArr Set(M2)] 20
20 △ _ 25
21 ε [EndObj Push] 23
23 ε 48, 18
23 ε 46, 18
25 ▶
26 ε [EndArr Set(M2)] 25
28 ε [Set(M1)] 21
30 ε [EndObj] 28
32 ! (Inner) 06 : 30
33 ε [Obj] 32
35 ε [Obj] 33
37 ▷ _ 40
38 ε 37, 26
40 ε 35, 38
42 ▽ _ 40
43 ▷ _ 46
44 ε 43, 18
46 ε 35, 44
48 ▷ _ 46
26 ε [Set(M1)] 21
28 ε [EndObj] 26
30 ! (Inner) 06 : 28
31 ε [Obj] 30
33 ε [Obj] 31
35 ▷ _ 38
36 ε 35, 18
38 ε 33, 36
40 ▽ _ 38
41 ▷ _ 44
42 ε 41, 18
44 ε 33, 42
46 ▷ _ 44
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ _ObjWrap:
Test:
06 ε 07
07 ! (function_declaration) 08
08 ε 21, 14
10 ! (decorator) [Node Set(M0)] 12
12 _ 13
13
14 ε [Null Set(M0)] 13
16 _ 19
17 ε 16, 14
19 ε 10, 17
21 _ 19
08 ε 20, 13
10
11 ! (decorator) [Node Set(M0)] 21
13 ε [Null Set(M0)] 21
15 _ 18
16 ε 15, 13
18 ε 11, 16
20 _ 18
21 _ 10
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ _ObjWrap:
Test:
06 ε 07
07 ! (function_declaration) 08
08 ε 21, 14
10 ! (decorator) [Node Set(M0)] 12
12 _ 13
13
14 ε [Null Set(M0)] 13
16 _ 19
17 ε 16, 14
19 ε 10, 17
21 _ 19
08 ε 20, 13
10
11 ! (decorator) [Node Set(M0)] 21
13 ε [Null Set(M0)] 21
15 _ 18
16 ε 15, 13
18 ε 11, 16
20 _ 18
21 _ 10
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ _ObjWrap:
Test:
06 ε 07
07 ! (function_declaration) 08
08 ε 14, 21
10 ! (decorator) [Node Set(M0)] 12
12 _ 13
13
14 ε [Null Set(M0)] 13
16 _ 19
17 ε 14, 16
19 ε 17, 10
21 _ 19
08 ε 13, 20
10
11 ! (decorator) [Node Set(M0)] 21
13 ε [Null Set(M0)] 21
15 _ 18
16 ε 13, 15
18 ε 16, 11
20 _ 18
21 _ 10
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,17 @@ Test:
06 ε 07
07 ! (function_declaration) 08
08 ε [Arr] 10
10 ε 27, 20
10 ε 25, 12
12 ε [EndArr Set(M0)] 14
14 △ _ 19
15 ! (decorator) [Node Push] 17
17 ε 33, 12
17 ε 31, 12
19 ▶
20 ε [EndArr Set(M0)] 19
22 ▷ _ 25
23 ε 22, 20
25 ε 15, 23
27 ▽ _ 25
28 ▷ _ 31
29 ε 28, 12
31 ε 15, 29
33 ▷ _ 31
20 ▷ _ 23
21 ε 20, 12
23 ε 15, 21
25 ▽ _ 23
26 ▷ _ 29
27 ε 26, 12
29 ε 15, 27
31 ▷ _ 29
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,20 @@ Test:
06 ε 07
07 ! (array) 08
08 ε [Arr] 10
10 ε 33, 20
10 ε 31, 12
12 ε [EndArr Set(M2)] 14
14 △ _ 19
15 ε [EndObj Push] 17
17 ε 39, 12
17 ε 37, 12
19 ▶
20 ε [EndArr Set(M2)] 19
22 ▷ (number) [Node Set(M1)] 15
24 ! (identifier) [Node Set(M0)] 22
26 ε [Obj] 24
28 ▷ _ 31
29 ε 28, 20
31 ε 26, 29
33 ▽ _ 31
34 ▷ _ 37
35 ε 34, 12
37 ε 26, 35
39 ▷ _ 37
20 ▷ (number) [Node Set(M1)] 15
22 ! (identifier) [Node Set(M0)] 20
24 ε [Obj] 22
26 ▷ _ 29
27 ε 26, 12
29 ε 24, 27
31 ▽ _ 29
32 ▷ _ 35
33 ε 32, 12
35 ε 24, 33
37 ▷ _ 35
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,18 @@ Test:
06 ε 07
07 ! (parent) 08
08 ε [Arr] 10
10 ε 28, 20
10 ε 26, 12
12 ε [EndArr Set(M0)] 14
14 △ _ 19
15 ▷ (b) [Node Push] 17
17 ε 34, 12
17 ε 32, 12
19 ▶
20 ε [EndArr Set(M0)] 19
22 ! (a) 15
23 ▷ _ 26
24 ε 23, 20
26 ε 22, 24
28 ▽ _ 26
29 ▷ _ 32
30 ε 29, 12
32 ε 22, 30
34 ▷ _ 32
20 ! (a) 15
21 ▷ _ 24
22 ε 21, 12
24 ε 20, 22
26 ▽ _ 24
27 ▷ _ 30
28 ε 27, 12
30 ε 20, 28
32 ▷ _ 30
Loading