add proxy for the first part and try to develop the second part

This commit is contained in:
Pierre Geeraert
2025-12-03 12:08:56 +00:00
parent 6c34d510e5
commit 460f18d85a
1095 changed files with 358799 additions and 5 deletions
@@ -0,0 +1,197 @@
from __future__ import annotations
import re
from itertools import chain
from tatsu import grammars as model
from tatsu.ast import AST
def camel2py(name):
return re.sub(
r'([a-z0-9])([A-Z])',
lambda m: m.group(1) + '_' + m.group(2).lower(),
name,
)
class ANTLRSemantics:
def __init__(self, name):
self.name = name
self.tokens = {}
self.token_rules = {}
self.synthetic_rules = []
def grammar(self, ast):
return model.Grammar(
self.name,
[
r
for r in chain(ast.rules, self.synthetic_rules)
if r is not None
],
)
def rule(self, ast):
name = camel2py(ast.name)
exp = ast.exp
if name[0].isupper():
name = name.upper()
if isinstance(exp, model.Token):
if name in self.token_rules:
self.token_rules[
name
].exp = exp # it is a model._Decorator
else:
self.token_rules[name] = exp
return None
elif not ast.fragment and not isinstance(exp, model.Sequence):
ref = model.RuleRef(name.lower())
if name in self.token_rules:
self.token_rules[name].exp = ref
else:
self.token_rules[name] = ref
name = name.lower()
return model.Rule(ast, name, exp, ast.params, ast.kwparams)
def alternatives(self, ast):
options = [o for o in ast.options if o is not None]
if len(options) == 1:
return options[0]
else:
options = [model.Option(o) for o in options]
return model.Choice(options)
def elements(self, ast):
elements = [e for e in ast if e is not None]
if not elements:
return model.Void()
elif len(elements) == 1:
return elements[0]
else:
return model.Sequence(AST(sequence=elements))
def predicate_or_action(self, ast):
return None
def named(self, ast):
if ast.force_list:
return model.NamedList(ast)
else:
return model.Named(ast)
def syntactic_predicate(self, ast):
return None
def optional(self, ast):
if isinstance(ast, model.Group | model.Optional | model.Closure):
ast = ast.exp
return model.Optional(ast)
def closure(self, ast):
if isinstance(ast, model.Group | model.Optional):
ast = ast.exp
return model.Closure(ast)
def positive_closure(self, ast):
if isinstance(ast, model.Group):
ast = ast.exp
return model.PositiveClosure(ast)
def negative(self, ast):
neg = model.NegativeLookahead(ast)
any = model.Pattern('.')
return model.Sequence(AST(sequence=[neg, any]))
def subexp(self, ast):
return model.Group(ast)
def regexp(self, ast):
pattern = ''.join(ast)
re.compile(pattern)
return model.Pattern(pattern)
def charset_optional(self, ast):
return f'{ast}?'
def charset_closure(self, ast):
return f'{ast}*'
def charset_positive_closure(self, ast):
return f'{ast}+'
def charset_or(self, ast):
return '[{}]'.format(''.join(ast))
def charset_negative_or(self, ast):
return '[^{}]'.format(''.join(ast))
@staticmethod
def escape(s):
return ''.join('\\' + c if c in '[]().*+{}^$' else c for c in s)
def charset_atom(self, ast):
return ast
def charset_char(self, ast):
return ast
def charset_range(self, ast):
return f'{ast.first}-{ast.last}'
def newranges(self, ast):
pattern = ''.join(ast)
re.compile(pattern)
return model.Pattern(pattern)
def newrange(self, ast):
pattern = '[{}]{}'.format(ast.range, ast.repeat or '')
re.compile(pattern)
return pattern
def negative_newrange(self, ast):
pattern = '[^{}]{}'.format(ast.range, ast.repeat or '')
re.compile(pattern)
return pattern
def rule_ref(self, ast):
assert ast[0].islower()
return model.RuleRef(camel2py(ast))
def any(self, ast):
return model.Pattern(r'\w+|\S+')
def string(self, ast):
text = ast
if isinstance(text, list):
text = ''.join(text)
return model.Token(text)
def eof(self, ast):
return model.EOF()
def token(self, ast):
name = ast.name
if ast.value:
exp = model.Token(ast.value)
self.tokens[name] = exp
else:
exp = model.Fail()
rule = model.Rule(ast, name, exp, [], {})
self.synthetic_rules.append(rule)
return exp
def token_ref(self, ast):
name = camel2py(ast).upper()
value = self.tokens.get(name)
if value and isinstance(value, model.Model):
return value
if name in self.token_rules:
exp = self.token_rules[name]
else:
exp = model.Decorator(model.RuleRef(name))
self.token_rules[name] = exp
return exp