Skip to content

Commit a0c085b

Browse files
committed
Return an error when trying to inline a token
Fixes tree-sitter#1420
1 parent 4e2e059 commit a0c085b

File tree

2 files changed

+73
-27
lines changed

2 files changed

+73
-27
lines changed

cli/src/generate/prepare_grammar/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub(crate) fn prepare_grammar(
6565
let mut syntax_grammar = flatten_grammar(syntax_grammar)?;
6666
let lexical_grammar = expand_tokens(lexical_grammar)?;
6767
let default_aliases = extract_default_aliases(&mut syntax_grammar, &lexical_grammar);
68-
let inlines = process_inlines(&syntax_grammar);
68+
let inlines = process_inlines(&syntax_grammar, &lexical_grammar)?;
6969
Ok((syntax_grammar, lexical_grammar, inlines, default_aliases))
7070
}
7171

cli/src/generate/prepare_grammar/process_inlines.rs

Lines changed: 72 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use crate::generate::grammars::{InlinedProductionMap, Production, ProductionStep, SyntaxGrammar};
1+
use crate::generate::{
2+
grammars::{InlinedProductionMap, LexicalGrammar, Production, ProductionStep, SyntaxGrammar},
3+
rules::SymbolType,
4+
};
5+
use anyhow::{anyhow, Result};
26
use std::collections::HashMap;
37

48
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -181,29 +185,46 @@ impl InlinedProductionMapBuilder {
181185
}
182186
}
183187

184-
pub(super) fn process_inlines(grammar: &SyntaxGrammar) -> InlinedProductionMap {
185-
InlinedProductionMapBuilder {
188+
pub(super) fn process_inlines(
189+
grammar: &SyntaxGrammar,
190+
lexical_grammar: &LexicalGrammar,
191+
) -> Result<InlinedProductionMap> {
192+
for symbol in &grammar.variables_to_inline {
193+
match symbol.kind {
194+
SymbolType::External => {
195+
return Err(anyhow!(
196+
"External token `{}` cannot be inlined",
197+
grammar.external_tokens[symbol.index].name
198+
))
199+
}
200+
SymbolType::Terminal => {
201+
return Err(anyhow!(
202+
"Token `{}` cannot be inlined",
203+
lexical_grammar.variables[symbol.index].name,
204+
))
205+
}
206+
_ => {}
207+
}
208+
}
209+
210+
Ok(InlinedProductionMapBuilder {
186211
productions: Vec::new(),
187212
production_indices_by_step_id: HashMap::new(),
188213
}
189-
.build(grammar)
214+
.build(grammar))
190215
}
191216

192217
#[cfg(test)]
193218
mod tests {
194219
use super::*;
195-
use crate::generate::grammars::{ProductionStep, SyntaxVariable, VariableType};
220+
use crate::generate::grammars::{
221+
LexicalVariable, ProductionStep, SyntaxVariable, VariableType,
222+
};
196223
use crate::generate::rules::{Associativity, Precedence, Symbol};
197224

198225
#[test]
199226
fn test_basic_inlining() {
200227
let grammar = SyntaxGrammar {
201-
word_token: None,
202-
extra_symbols: vec![],
203-
external_tokens: vec![],
204-
supertype_symbols: vec![],
205-
expected_conflicts: vec![],
206-
precedence_orderings: vec![],
207228
variables_to_inline: vec![Symbol::non_terminal(1)],
208229
variables: vec![
209230
SyntaxVariable {
@@ -236,8 +257,10 @@ mod tests {
236257
],
237258
},
238259
],
260+
..Default::default()
239261
};
240-
let inline_map = process_inlines(&grammar);
262+
263+
let inline_map = process_inlines(&grammar, &Default::default()).unwrap();
241264

242265
// Nothing to inline at step 0.
243266
assert!(inline_map
@@ -330,14 +353,10 @@ mod tests {
330353
Symbol::non_terminal(2),
331354
Symbol::non_terminal(3),
332355
],
333-
extra_symbols: vec![],
334-
external_tokens: vec![],
335-
supertype_symbols: vec![],
336-
expected_conflicts: vec![],
337-
precedence_orderings: vec![],
338-
word_token: None,
356+
..Default::default()
339357
};
340-
let inline_map = process_inlines(&grammar);
358+
359+
let inline_map = process_inlines(&grammar, &Default::default()).unwrap();
341360

342361
let productions: Vec<&Production> = inline_map
343362
.inlined_productions(&grammar.variables[0].productions[0], 1)
@@ -433,15 +452,10 @@ mod tests {
433452
}],
434453
},
435454
],
436-
extra_symbols: vec![],
437-
external_tokens: vec![],
438-
supertype_symbols: vec![],
439-
expected_conflicts: vec![],
440-
precedence_orderings: vec![],
441-
word_token: None,
455+
..Default::default()
442456
};
443457

444-
let inline_map = process_inlines(&grammar);
458+
let inline_map = process_inlines(&grammar, &Default::default()).unwrap();
445459

446460
let productions: Vec<_> = inline_map
447461
.inlined_productions(&grammar.variables[0].productions[0], 0)
@@ -490,4 +504,36 @@ mod tests {
490504
}],
491505
);
492506
}
507+
508+
#[test]
509+
fn test_error_when_inlining_tokens() {
510+
let lexical_grammar = LexicalGrammar {
511+
variables: vec![LexicalVariable {
512+
name: "something".to_string(),
513+
kind: VariableType::Named,
514+
implicit_precedence: 0,
515+
start_state: 0,
516+
}],
517+
..Default::default()
518+
};
519+
520+
let grammar = SyntaxGrammar {
521+
variables_to_inline: vec![Symbol::terminal(0)],
522+
variables: vec![SyntaxVariable {
523+
name: "non-terminal-0".to_string(),
524+
kind: VariableType::Named,
525+
productions: vec![Production {
526+
dynamic_precedence: 0,
527+
steps: vec![ProductionStep::new(Symbol::terminal(0))],
528+
}],
529+
}],
530+
..Default::default()
531+
};
532+
533+
if let Err(error) = process_inlines(&grammar, &lexical_grammar) {
534+
assert_eq!(error.to_string(), "Token `something` cannot be inlined");
535+
} else {
536+
panic!("expected an error, but got none");
537+
}
538+
}
493539
}

0 commit comments

Comments
 (0)