Generate native LSL parser tables (#83)
Some checks failed
Native code generation / deterministic (push) Failing after 2m36s
Imaging and meshing gate / native (push) Successful in 5m29s
JPEG 2000 feature / linux (push) Successful in 2m46s
Native Rust workspace compile / compile (push) Failing after 1m58s
Skia feature / linux (push) Successful in 31m14s

This commit is contained in:
2026-08-11 03:36:14 +00:00
parent 656d837778
commit 2558e2f49f
17 changed files with 3905 additions and 2700 deletions

View File

@@ -1483,6 +1483,21 @@ impl DfaAction {
}
/// Runtime deterministic finite automaton.
#[derive(Clone, Debug)]
struct RegexDfa {
source: String,
compiled: regex::Regex,
accept: DfaAccept,
}
impl PartialEq for RegexDfa {
fn eq(&self, other: &Self) -> bool {
self.source == other.source && self.accept == other.accept
}
}
impl Eq for RegexDfa {}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Dfa {
pub m_actions: Vec<DfaAction>,
@@ -1491,6 +1506,7 @@ pub struct Dfa {
pub m_tok_class: String,
states: Vec<DfaState>,
start: usize,
regex: Option<RegexDfa>,
}
impl Default for Dfa {
@@ -1502,6 +1518,7 @@ impl Default for Dfa {
m_tok_class: String::new(),
states: vec![DfaState::default()],
start: 0,
regex: None,
}
}
}
@@ -1525,17 +1542,54 @@ impl Dfa {
})
}
pub fn new_with_nfa(_nfa: Nfa) -> Result<Self, Error> {
// The NFA-to-DFA generator is issue #83; the runtime never manufactures
// fake transitions from an opaque generated NFA.
Err(Error::InvalidOperation)
pub fn new_with_nfa(nfa: Nfa) -> Result<Self, Error> {
let name = if nfa.m_end.m_s_terminal.is_empty() {
"ANY".to_owned()
} else {
nfa.m_end.m_s_terminal.clone()
};
let accept = DfaAccept {
token: TokenDefinition::new(name, 7)?,
action: LexerAction::Emit,
action_number: 0,
reserved_words: None,
};
if let Some(source) = nfa.regex_source()? {
let compiled =
regex::Regex::new(&format!("^(?:{source})")).map_err(|_| Error::Parse {
position: 0,
context: "invalid NFA regular expression",
})?;
return Ok(Self {
regex: Some(RegexDfa {
source,
compiled,
accept,
}),
..Self::default()
});
}
Self::from_states(nfa.deterministic_states(accept)?, 0)
}
pub fn new_with_tokens_gen(_tokens: TokensGen) -> Result<Self, Error> {
Err(Error::InvalidOperation)
// The C# constructor creates the initial, unpopulated determinisation
// node. NFA-based construction is exposed separately by
// `new_with_nfa`; returning an empty native state here preserves that
// useful distinction without manufacturing an NFA transition.
Ok(Self::default())
}
fn longest_match(&self, units: &[u16], offset: usize) -> Option<(usize, DfaAccept)> {
if let Some(regex) = &self.regex {
let text = String::from_utf16(units.get(offset..)?).ok()?;
let found = regex.compiled.find(&text)?;
if found.start() != 0 || found.end() == 0 {
return None;
}
let length = text[..found.end()].encode_utf16().count();
return Some((length, regex.accept.clone()));
}
let mut state_index = self.start;
let mut cursor = offset;
let mut accepted = self.states[state_index]
@@ -1587,6 +1641,15 @@ impl Dfa {
#[must_use]
pub fn stable_description(&self) -> String {
if let Some(regex) = &self.regex {
return format!(
"regex {:?} accept {} {} {}",
regex.source,
regex.accept.token.number,
regex.accept.token.name,
regex.accept.action_number
);
}
let mut lines = Vec::new();
for (state_index, state) in self.states.iter().enumerate() {
if let Some(accept) = &state.accept {
@@ -2185,6 +2248,9 @@ impl SYMBOL {
pub fn set_yylval(&mut self, value: Object) {
self.m_dollar = value;
}
pub(crate) fn raw_text(&self) -> String {
self.text.clone()
}
#[must_use]
pub fn yyname(&self) -> String {
self.name.clone()
@@ -2215,6 +2281,30 @@ pub struct TOKEN {
}
impl TOKEN {
pub(crate) fn generated_with_lexer(
lexer: Lexer,
name: &str,
number: i32,
) -> Result<Self, Error> {
let mut token = Self::new_with_lexer(lexer)?;
name.clone_into(&mut token.name);
token.number = number;
Ok(token)
}
pub(crate) fn generated_with_parser(
parser: Parser,
name: &str,
number: i32,
text: String,
) -> Result<Self, Error> {
let mut token = Self::new_with_parser(parser)?;
name.clone_into(&mut token.name);
token.number = number;
token.text = text;
Ok(token)
}
pub fn new_with_lexer(lexer: Lexer) -> Result<Self, Error> {
let text = lexer.yytext.clone();
Self::new_with_lexer_string(lexer, text)