Skip to content

Variable substitution#55

Merged
ehwan merged 5 commits into
mainfrom
macrotype
Jun 18, 2026
Merged

Variable substitution#55
ehwan merged 5 commits into
mainfrom
macrotype

Conversation

@ehwan

@ehwan ehwan commented Jun 18, 2026

Copy link
Copy Markdown
Owner

Description

This Pull Request introduces $filter variable substitution within RustCode blocks, simplifies the non-terminal substitution syntax to $NonTerminalName (replacing the bracketed $<NonTerminal> syntax), implements fallback preservation for unknown variables, and enhances compile-time diagnostics inside rusty_lr_buildscript.

Changes

1. Simplified Variable Substitution & Fallback Behavior

  • Non-Terminal Syntax Sugar: Changed the non-terminal variable syntax to $NonTerminalName instead of $<NonTerminal>. Updated substitute_stream in grammar.rs to support lookup directly.
  • Fallback for Unknown Variables: If a $ is followed by an unknown identifier, it is preserved in the token stream unchanged (along with a // TODO: 이거 워닝으로 내면 좋을듯 comment) instead of producing an error.
  • $filter Substitution: Resolved $filter to evaluate to the user-defined filter function if %filter is specified.

2. Diagnostics inside rusty_lr_buildscript

  • Added structural compile-time diagnostics for the following errors:
    • ArgError::MultipleLocationDefinition(locs)
    • ArgError::MultipleFilterDefinition(locs)
    • ParseError::CircularDependency { location, path }
    • ParseError::MaxSubstitutionDepthExceeded { location, max_depth }
    • ParseError::FilterNotDefined(loc)
  • For substitution errors (CircularDependency, MaxSubstitutionDepthExceeded, and FilterNotDefined), added warning notes containing links pointing directly to the #substitution-errors section in SYNTAX.md on GitHub.

3. Error Definition Cleanup & Documentation

  • Removed the dead LocationTypeNotDefined and TokenTypeNotDefined parse errors since their validations occur earlier inside argument checks.
  • Updated SYNTAX.md to document the new $filter variable, the simplified $NonTerminalName syntax, and the three variable substitution error types (CircularDependency, MaxSubstitutionDepthExceeded, and FilterNotDefined).

@ehwan ehwan self-assigned this Jun 18, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a variable substitution feature to the grammar parser, allowing the use of variables prefixed with $ inside RustCode blocks to reduce boilerplate. It also implements compile-time checks for circular dependencies, maximum recursion depth, and missing filter definitions. The review feedback highlights several performance optimization opportunities in the substitution resolution logic within rusty_lr_parser/src/grammar.rs, specifically focusing on reducing redundant heap allocations, caching formatted keys, and avoiding duplicate span manager lookups.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

});
}

if stack.contains(&name.to_string()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using stack.contains(&name.to_string()) performs a redundant heap allocation of a String on every lookup. Since stack is a Vec<String> and name is a &str, you can perform the lookup without any allocation by using stack.iter().any(|s| s == name).

Suggested change
if stack.contains(&name.to_string()) {
if stack.iter().any(|s| s == name) {

Comment thread rusty_lr_parser/src/grammar.rs Outdated
Comment on lines +600 to +628
} else if providers.contains_key(&format!("term:{}", ident_name)) {
iter.next();
let resolved = resolve_provider(
&format!("term:{}", ident_name),
providers,
span_manager,
stack,
depth,
max_depth,
ref_loc,
)?;
result.extend(resolved);
continue;
} else if providers.contains_key(&format!("nonterm:{}", ident_name)) {
iter.next();
let resolved = resolve_provider(
&format!("nonterm:{}", ident_name),
providers,
span_manager,
stack,
depth,
max_depth,
ref_loc,
)?;
result.extend(resolved);
continue;
} else {
// TODO: 이거 워닝으로 내면 좋을듯
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The keys format!("term:{}", ident_name) and format!("nonterm:{}", ident_name) are formatted twice: once for the contains_key check and once when calling resolve_provider. We can avoid these redundant string allocations by formatting the keys once into local variables and reusing them.

                            } else {
                                let term_key = format!("term:{}", ident_name);
                                if providers.contains_key(&term_key) {
                                    iter.next();
                                    let resolved = resolve_provider(
                                        &term_key,
                                        providers,
                                        span_manager,
                                        stack,
                                        depth,
                                        max_depth,
                                        ref_loc,
                                    )?;
                                    result.extend(resolved);
                                    continue;
                                }
                                let nonterm_key = format!("nonterm:{}", ident_name);
                                if providers.contains_key(&nonterm_key) {
                                    iter.next();
                                    let resolved = resolve_provider(
                                        &nonterm_key,
                                        providers,
                                        span_manager,
                                        stack,
                                        depth,
                                        max_depth,
                                        ref_loc,
                                    )?;
                                    result.extend(resolved);
                                    continue;
                                }
                                // TODO: 이거 워닝으로 내면 좋을듯
                            }

@ehwan ehwan merged commit 9a29824 into main Jun 18, 2026
@ehwan ehwan deleted the macrotype branch June 18, 2026 23:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant