Compare commits

...

3 commits

Author SHA1 Message Date
5e12af9f31 Extra marks, fields, whatnot 2024-09-05 06:32:28 -07:00
be8e017fd9 Fix regex generation, extras 2024-09-05 06:32:28 -07:00
94f5958087 Field propagation 2024-09-05 06:30:55 -07:00
3 changed files with 30 additions and 15 deletions

View file

@ -52,8 +52,8 @@ class FineGrammar(Grammar):
def class_declaration(self) -> Rule: def class_declaration(self) -> Rule:
return seq( return seq(
self.CLASS, self.CLASS,
mark(self.IDENTIFIER, highlight=highlight.entity.name.type), mark(self.IDENTIFIER, field="name", highlight=highlight.entity.name.type),
self._class_body, mark(self._class_body, field="body"),
) )
@rule @rule
@ -107,10 +107,10 @@ class FineGrammar(Grammar):
def function_declaration(self) -> Rule: def function_declaration(self) -> Rule:
return seq( return seq(
self.FUN, self.FUN,
mark(self.IDENTIFIER, highlight=highlight.entity.name.function), mark(self.IDENTIFIER, field="name", highlight=highlight.entity.name.function),
self.function_parameters, mark(self.function_parameters, field="parameters"),
opt(self.ARROW, self.type_expression), mark(opt(self.ARROW, self.type_expression), field="return_type"),
self.block, mark(self.block, field="body"),
) )
@rule("ParamList") @rule("ParamList")

View file

@ -2729,6 +2729,9 @@ class Grammar:
def terminals(self) -> list[Terminal]: def terminals(self) -> list[Terminal]:
return self._terminals return self._terminals
def trivia_terminals(self) -> list[Terminal]:
return self._trivia
def non_terminals(self) -> list[NonTerminal]: def non_terminals(self) -> list[NonTerminal]:
return [nt for _, nt in inspect.getmembers(self, lambda x: isinstance(x, NonTerminal))] return [nt for _, nt in inspect.getmembers(self, lambda x: isinstance(x, NonTerminal))]

View file

@ -99,6 +99,17 @@ def to_javascript_regex(re: parser.Re) -> str:
raise Exception(f"Regex node {re} not supported for tree-sitter") raise Exception(f"Regex node {re} not supported for tree-sitter")
def terminal_to_tree_sitter(rule: parser.Terminal) -> str:
if isinstance(rule.pattern, parser.Re):
regex = to_javascript_regex(rule.pattern)
regex = regex.replace("/", "\\/")
result = f"/{regex}/"
else:
string = to_js_string(rule.pattern)
result = f'"{string}"'
return result
def apply_precedence(js: str, name: str, grammar: parser.Grammar) -> str: def apply_precedence(js: str, name: str, grammar: parser.Grammar) -> str:
prec = grammar.get_precedence(name) prec = grammar.get_precedence(name)
if prec is not None: if prec is not None:
@ -119,14 +130,7 @@ def convert_to_tree_sitter(rule: parser.Rule, grammar: parser.Grammar) -> str:
return method(grammar) return method(grammar)
if isinstance(rule, parser.Terminal): if isinstance(rule, parser.Terminal):
if isinstance(rule.pattern, parser.Re): return terminal_to_tree_sitter(rule)
regex = to_javascript_regex(rule.pattern)
result = f"/{regex}/"
else:
string = to_js_string(rule.pattern)
result = f'"{string}"'
return result
elif isinstance(rule, parser.AlternativeRule): elif isinstance(rule, parser.AlternativeRule):
final = [] final = []
@ -205,7 +209,11 @@ def convert_to_tree_sitter(rule: parser.Rule, grammar: parser.Grammar) -> str:
return f"$['{target_name}']" return f"$['{target_name}']"
elif isinstance(rule, parser.MetadataRule): elif isinstance(rule, parser.MetadataRule):
return convert_to_tree_sitter(rule.rule, grammar) result = convert_to_tree_sitter(rule.rule, grammar)
field = rule.metadata.get("field")
if field is not None:
result = f"field('{field}', {result})"
return result
else: else:
raise ValueError(f"Rule {rule} not supported for tree-sitter") raise ValueError(f"Rule {rule} not supported for tree-sitter")
@ -221,6 +229,10 @@ def emit_tree_sitter_grammar(grammar: parser.Grammar, path: pathlib.Path | str):
f.write("\n") f.write("\n")
f.write("module.exports = grammar({\n") f.write("module.exports = grammar({\n")
f.write(f" name: '{grammar.name}',\n") f.write(f" name: '{grammar.name}',\n")
extras = ", ".join([terminal_to_tree_sitter(t) for t in grammar.trivia_terminals()])
f.write(f" extras: $ => [{extras}],\n")
f.write(" rules: {\n") f.write(" rules: {\n")
f.write(f" source_file: $ => $['{grammar.start}'],\n") f.write(f" source_file: $ => $['{grammar.start}'],\n")
for rule in grammar.non_terminals(): for rule in grammar.non_terminals():