diff --git a/.gitea/workflows/rust-workspace.yml b/.gitea/workflows/rust-workspace.yml index ca42b65..ca53900 100644 --- a/.gitea/workflows/rust-workspace.yml +++ b/.gitea/workflows/rust-workspace.yml @@ -13,6 +13,7 @@ on: - "tools/check_milestone_10_issue_79.py" - "tools/check_milestone_10_issue_80.py" - "tools/check_milestone_10_issue_81.py" + - "tools/check_milestone_10_issue_82.py" - "**/*.rs" - "**/Cargo.toml" - "Cargo.lock" @@ -28,6 +29,7 @@ on: - "tools/check_milestone_10_issue_79.py" - "tools/check_milestone_10_issue_80.py" - "tools/check_milestone_10_issue_81.py" + - "tools/check_milestone_10_issue_82.py" - "**/*.rs" - "**/Cargo.toml" - "Cargo.lock" @@ -69,6 +71,7 @@ jobs: python3 tools/check_milestone_10_issue_79.py python3 tools/check_milestone_10_issue_80.py python3 tools/check_milestone_10_issue_81.py + python3 tools/check_milestone_10_issue_82.py - name: Test the complete native world milestone run: python3 tools/test_milestone_09.py - name: Compile every workspace target with bounded memory diff --git a/api/SHIM-COVERAGE.md b/api/SHIM-COVERAGE.md index befe03e..008629f 100644 --- a/api/SHIM-COVERAGE.md +++ b/api/SHIM-COVERAGE.md @@ -7,7 +7,7 @@ Generated by `python3 tools/generate_api_shims.py`; do not edit by hand. | `LibreMetaverse` | 2,711 | 27,281 | native implementation: 401 types / 17,025 members; remaining surface is callable failure-only shims | | `LibreMetaverse.Imaging.Abstractions` | 3 | 20 | native implementation: 3 types / 20 members; no generated shims remain | | `LibreMetaverse.Imaging.Skia` | 1 | 3 | native implementation: 1 type / 3 members; no generated shims remain | -| `LibreMetaverse.LslTools` | 164 | 768 | native implementation: 22 types / 188 members; remaining surface is callable failure-only shims | +| `LibreMetaverse.LslTools` | 164 | 768 | native implementation: 44 types / 403 members; remaining surface is callable failure-only shims | | `LibreMetaverse.PrimMesher` | 17 | 207 | native implementation: 15 types / 200 members; remaining surface is callable failure-only shims | | `LibreMetaverse.RLV` | 28 | 499 | native implementation: 17 types / 200 members; remaining surface is callable failure-only shims | | `LibreMetaverse.Rendering.MeshFoundry` | 1 | 14 | native implementation: 1 type / 14 members; no generated shims remain | diff --git a/crates/libremetaverse-lsl-tools/README.md b/crates/libremetaverse-lsl-tools/README.md index 6f7ae4a..789438a 100644 --- a/crates/libremetaverse-lsl-tools/README.md +++ b/crates/libremetaverse-lsl-tools/README.md @@ -4,9 +4,10 @@ parser-generator runtime in the pinned `LibreMetaverse.LslTools` assembly. The issue 81 boundary supplies source reading, comments, Unicode character sets, deterministic DFA execution, reserved words, terminal symbols, EOF, source -locations, diagnostics, and Rust iterators. Grammar productions, reductions, -and recovery are added by issue 82; deterministic generated grammar and token -tables are added by issue 83. +locations, diagnostics, and Rust iterators. The issue 82 boundary supplies +grammar productions, parser tables, precedence, reductions, and recovery. +Deterministic checked-in generated grammar and token tables are added by issue +83. ## Source and position contract @@ -53,6 +54,37 @@ after a diagnostic and never yield a fabricated token. Token and symbol tables and populate the supplied parser-entry priority. Missing or malformed table data is an explicit positioned error. +## Grammar and parser contract + +`Grammar` builds validated canonical LR(0) item sets with deterministic LALR(1) +lookahead propagation. Symbols and productions retain stable numeric +identities. Table construction rejects missing start/EOF declarations, +undeclared right-hand-side symbols, invalid precedence declarations, oversized +state sets, incomplete goto tables, and reduction underflow. Empty productions +and recursive nonterminals are supported. + +Shift/reduce conflicts use yacc-compatible rules: a declared higher precedence +wins, equal left precedence reduces, equal right precedence shifts, and equal +nonassociative precedence installs a rejecting table entry. Undeclared +shift/reduce conflicts shift; reduce/reduce conflicts select the lower +production number. `YyParser::conflicts` preserves every decision and `emit` +writes a byte-stable table description independent of hash iteration. + +`Parser` consumes the native lexer and returns a typed `ParseTree` through the +mapped `SYMBOL` semantic value. Syntax recovery uses the conventional terminal +number zero: it pops to a state that can shift `error`, shifts an explicit error +node, and discards input to the next valid lookahead. Diagnostics distinguish +the original syntax error from successful recovery. Parsing is bounded to +65,536 states, 1,048,576 live stack entries, 16,777,216 operations, and 1,000 +recovery attempts. + +Compatibility `SymbolSet` clones share deterministic FIRST/FOLLOW membership, +and cloned `CSymbol` values share registered production metadata. This retains +the observable reference behavior of the C# grammar model without unsafe code. +Parser-source serialization and the old `Builder`-driven generated-output +members return `InvalidOperation` explicitly until issue 83 supplies the +checked-in generator; they never report a false success. + ## Diagnostics and migration `ErrorHandler` collects structured `Diagnostic` values. Each diagnostic has a @@ -73,6 +105,9 @@ The principal API mapping is: | `Lexer._Enumerator` | `LexerEnumerator`; prefer `LexerIterator` | | `Charset`, `CatTest` | Same mapped names plus `DotNetUnicodeCategory` | | `CSToolsException`, `ErrorHandler` | Same mapped names plus structured `Diagnostic` | +| `CSymbol`, `SymbolSet`, `Production`, `Precedence` | Same mapped names plus typed `Grammar` builders | +| `YyParser`, parser entries | Deterministic native tables and conflict records | +| `Parser`, `ParseStackEntry`, `Error`, `recoveredError` | Bounded parsing, typed trees, and recovery | No C#, .NET runtime, dynamically loaded class, macOS-only API, platform code page, or runtime source generation is used by this boundary. @@ -87,8 +122,9 @@ CARGO_BUILD_JOBS=1 cargo check --manifest-path tests/api-compile/Cargo.toml --lo CARGO_BUILD_JOBS=1 cargo clippy -p libremetaverse-lsl-tools --all-targets --locked -- -D warnings RUSTDOCFLAGS='-D warnings' CARGO_BUILD_JOBS=1 cargo doc -p libremetaverse-lsl-tools --no-deps --locked python3 tools/check_milestone_10_issue_81.py +python3 tools/check_milestone_10_issue_82.py python3 tools/generate_api_shims.py --check ``` -The package contains 27 focused native and compatibility fixtures. The Gitea +The package contains 37 focused native and compatibility fixtures. The Gitea workflow runs the audit and workspace compile on `ubuntu-latest` only. diff --git a/crates/libremetaverse-lsl-tools/src/generated.rs b/crates/libremetaverse-lsl-tools/src/generated.rs index a154e71..8ab407f 100644 --- a/crates/libremetaverse-lsl-tools/src/generated.rs +++ b/crates/libremetaverse-lsl-tools/src/generated.rs @@ -303,128 +303,40 @@ pub use crate::lexer::CSToolsFatalException; pub use crate::lexer::CSToolsStopException; /// C# type: `T:LibreMetaverse.LslTools.CSymbol`. -pub struct CSymbol { - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_defined`. - pub m_defined: bool, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_emitted`. - pub m_emitted: bool, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_first`. - pub m_first: libremetaverse_lsl_tools::SymbolSet, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_follow`. - pub m_follow: libremetaverse_lsl_tools::SymbolSet, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_initialisation`. - pub m_initialisation: String, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_parser`. - pub m_parser: Box, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_prec`. - pub m_prec: libremetaverse_lsl_tools::Precedence, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_prod`. - pub m_prod: Box, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_prods`. - pub m_prods: libremetaverse_lsl_tools::ObjectList, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_refSymbol`. - pub m_ref_symbol: Box, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_symtype`. - pub m_symtype: libremetaverse_lsl_tools::CSymbolSymType, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_yynum`. - pub m_yynum: i32, -} -impl CSymbol { - /// C# member: `M:LibreMetaverse.LslTools.CSymbol.#ctor(LibreMetaverse.LslTools.Lexer)`. - pub fn new_with_lexer(yyl: libremetaverse_lsl_tools::Lexer) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.CSymbol.#ctor(LibreMetaverse.LslTools.Lexer)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.CSymbol.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. - pub fn new_with_symbols_gen( - yyp: libremetaverse_lsl_tools::SymbolsGen, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.CSymbol.#ctor(LibreMetaverse.LslTools.SymbolsGen)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.CSymbol.AddFollow(LibreMetaverse.LslTools.SymbolSet)`. - pub fn add_follow( - &self, - map: libremetaverse_lsl_tools::SymbolSet, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.CSymbol.AddFollow(LibreMetaverse.LslTools.SymbolSet)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.CSymbol.AddStartItems(LibreMetaverse.LslTools.ParseState,LibreMetaverse.LslTools.SymbolSet)`. - pub fn add_start_items( - &self, - pstate: libremetaverse_lsl_tools::ParseState, - follows: libremetaverse_lsl_tools::SymbolSet, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.CSymbol.AddStartItems(LibreMetaverse.LslTools.ParseState,LibreMetaverse.LslTools.SymbolSet)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.CSymbol.IsNullable`. - pub fn is_nullable(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.CSymbol.IsNullable") - } - /// C# member: `M:LibreMetaverse.LslTools.CSymbol.IsTerminal`. - pub fn is_terminal(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.CSymbol.IsTerminal") - } - /// C# member: `M:LibreMetaverse.LslTools.CSymbol.Matches(System.String)`. - pub fn matches(&self, s: String) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.CSymbol.Matches(System.String)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.CSymbol.Resolve`. - pub fn resolve(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.CSymbol.Resolve") - } - /// C# member: `M:LibreMetaverse.LslTools.CSymbol.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. - pub fn serialise( - o: libremetaverse_types::compat::Object, - s: libremetaverse_lsl_tools::Serialiser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.CSymbol.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.CSymbol.ShiftPrecedence(LibreMetaverse.LslTools.Production,LibreMetaverse.LslTools.ParseState)`. - pub fn shift_precedence( - &self, - prod: libremetaverse_lsl_tools::Production, - ps: libremetaverse_lsl_tools::ParseState, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.CSymbol.ShiftPrecedence(LibreMetaverse.LslTools.Production,LibreMetaverse.LslTools.ParseState)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.CSymbol.TypeStr`. - pub fn type_str(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.CSymbol.TypeStr") - } -} +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_defined`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_emitted`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_first`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_follow`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_initialisation`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_parser`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_prec`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_prod`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_prods`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_refSymbol`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_symtype`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.m_yynum`. +/// C# member: `M:LibreMetaverse.LslTools.CSymbol.#ctor(LibreMetaverse.LslTools.Lexer)`. +/// C# member: `M:LibreMetaverse.LslTools.CSymbol.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. +/// C# member: `M:LibreMetaverse.LslTools.CSymbol.AddFollow(LibreMetaverse.LslTools.SymbolSet)`. +/// C# member: `M:LibreMetaverse.LslTools.CSymbol.AddStartItems(LibreMetaverse.LslTools.ParseState,LibreMetaverse.LslTools.SymbolSet)`. +/// C# member: `M:LibreMetaverse.LslTools.CSymbol.IsNullable`. +/// C# member: `M:LibreMetaverse.LslTools.CSymbol.IsTerminal`. +/// C# member: `M:LibreMetaverse.LslTools.CSymbol.Matches(System.String)`. +/// C# member: `M:LibreMetaverse.LslTools.CSymbol.Resolve`. +/// C# member: `M:LibreMetaverse.LslTools.CSymbol.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. +/// C# member: `M:LibreMetaverse.LslTools.CSymbol.ShiftPrecedence(LibreMetaverse.LslTools.Production,LibreMetaverse.LslTools.ParseState)`. +/// C# member: `M:LibreMetaverse.LslTools.CSymbol.TypeStr`. +pub use crate::parser::CSymbol; /// C# type: `T:LibreMetaverse.LslTools.CSymbol.SymType`. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(i32)] -pub enum CSymbolSymType { - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.eofsymbol`. - Eofsymbol = 6, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.nodesymbol`. - Nodesymbol = 3, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.nonterminal`. - Nonterminal = 2, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.oldaction`. - Oldaction = 4, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.simpleaction`. - Simpleaction = 5, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.terminal`. - Terminal = 1, - /// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.unknown`. - Unknown = 0, -} +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.eofsymbol`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.nodesymbol`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.nonterminal`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.oldaction`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.simpleaction`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.terminal`. +/// C# member: `F:LibreMetaverse.LslTools.CSymbol.SymType.unknown`. +pub use crate::parser::CSymbolSymType; /// C# type: `T:LibreMetaverse.LslTools.Call`. pub struct Call; @@ -640,37 +552,13 @@ pub use crate::lexer::DfaAction; pub use crate::lexer::EOF; /// C# type: `T:LibreMetaverse.LslTools.Error`. -pub struct LslError { - /// C# member: `F:LibreMetaverse.LslTools.Error.state`. - pub state: i32, - /// C# member: `F:LibreMetaverse.LslTools.Error.sym`. - pub sym: libremetaverse_lsl_tools::SYMBOL, -} -impl LslError { - /// C# member: `M:LibreMetaverse.LslTools.Error.#ctor(LibreMetaverse.LslTools.Parser)`. - pub fn new_with_parser(yyp: libremetaverse_lsl_tools::Parser) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Error.#ctor(LibreMetaverse.LslTools.Parser)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Error.#ctor(LibreMetaverse.LslTools.Parser,LibreMetaverse.LslTools.ParseStackEntry)`. - pub fn new_with_parser_parse_stack_entry( - yyp: libremetaverse_lsl_tools::Parser, - s: libremetaverse_lsl_tools::ParseStackEntry, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Error.#ctor(LibreMetaverse.LslTools.Parser,LibreMetaverse.LslTools.ParseStackEntry)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Error.ToString`. - pub fn to_string(&self) -> String { - libremetaverse_types::unimplemented_api!("M:LibreMetaverse.LslTools.Error.ToString") - } - /// C# member: `P:LibreMetaverse.LslTools.Error.yyname`. - pub fn yyname(&self) -> String { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.LslTools.Error.yyname") - } -} +/// C# member: `F:LibreMetaverse.LslTools.Error.state`. +/// C# member: `F:LibreMetaverse.LslTools.Error.sym`. +/// C# member: `M:LibreMetaverse.LslTools.Error.#ctor(LibreMetaverse.LslTools.Parser)`. +/// C# member: `M:LibreMetaverse.LslTools.Error.#ctor(LibreMetaverse.LslTools.Parser,LibreMetaverse.LslTools.ParseStackEntry)`. +/// C# member: `M:LibreMetaverse.LslTools.Error.ToString`. +/// C# member: `P:LibreMetaverse.LslTools.Error.yyname`. +pub use crate::parser::LslError; /// C# type: `T:LibreMetaverse.LslTools.ErrorHandler`. /// C# member: `F:LibreMetaverse.LslTools.ErrorHandler.counter`. @@ -1471,41 +1359,12 @@ pub use crate::lexer::LineList; pub use crate::lexer::LineManager; /// C# type: `T:LibreMetaverse.LslTools.Literal`. -pub struct Literal; -impl Literal { - /// C# member: `M:LibreMetaverse.LslTools.Literal.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. - pub fn new(yyp: libremetaverse_lsl_tools::SymbolsGen) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Literal.#ctor(LibreMetaverse.LslTools.SymbolsGen)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Literal.CouldStart(LibreMetaverse.LslTools.CSymbol)`. - pub fn could_start( - &self, - nonterm: libremetaverse_lsl_tools::CSymbol, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Literal.CouldStart(LibreMetaverse.LslTools.CSymbol)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Literal.Resolve`. - pub fn resolve(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.Literal.Resolve") - } - /// C# member: `M:LibreMetaverse.LslTools.Literal.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. - pub fn serialise( - o: libremetaverse_types::compat::Object, - s: libremetaverse_lsl_tools::Serialiser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Literal.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Literal.TypeStr`. - pub fn type_str(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.Literal.TypeStr") - } -} +/// C# member: `M:LibreMetaverse.LslTools.Literal.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. +/// C# member: `M:LibreMetaverse.LslTools.Literal.CouldStart(LibreMetaverse.LslTools.CSymbol)`. +/// C# member: `M:LibreMetaverse.LslTools.Literal.Resolve`. +/// C# member: `M:LibreMetaverse.LslTools.Literal.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. +/// C# member: `M:LibreMetaverse.LslTools.Literal.TypeStr`. +pub use crate::parser::Literal; /// C# type: `T:LibreMetaverse.LslTools.NEW`. pub struct NEW; @@ -1747,486 +1606,111 @@ impl ObjectListOListEnumerator { } /// C# type: `T:LibreMetaverse.LslTools.ParseStackEntry`. -pub struct ParseStackEntry { - /// C# member: `F:LibreMetaverse.LslTools.ParseStackEntry.m_state`. - pub m_state: i32, - /// C# member: `F:LibreMetaverse.LslTools.ParseStackEntry.m_value`. - pub m_value: libremetaverse_lsl_tools::SYMBOL, - /// C# member: `F:LibreMetaverse.LslTools.ParseStackEntry.yyps`. - pub yyps: libremetaverse_lsl_tools::Parser, -} -impl ParseStackEntry { - /// C# member: `M:LibreMetaverse.LslTools.ParseStackEntry.#ctor(LibreMetaverse.LslTools.Parser)`. - pub fn new_with_parser(yyp: libremetaverse_lsl_tools::Parser) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParseStackEntry.#ctor(LibreMetaverse.LslTools.Parser)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParseStackEntry.#ctor(LibreMetaverse.LslTools.Parser,System.Int32,LibreMetaverse.LslTools.SYMBOL)`. - pub fn new_with_parser_int32_symbol( - yyp: libremetaverse_lsl_tools::Parser, - state: i32, - value: libremetaverse_lsl_tools::SYMBOL, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParseStackEntry.#ctor(LibreMetaverse.LslTools.Parser,System.Int32,LibreMetaverse.LslTools.SYMBOL)", - ) - } -} +/// C# member: `F:LibreMetaverse.LslTools.ParseStackEntry.m_state`. +/// C# member: `F:LibreMetaverse.LslTools.ParseStackEntry.m_value`. +/// C# member: `F:LibreMetaverse.LslTools.ParseStackEntry.yyps`. +/// C# member: `M:LibreMetaverse.LslTools.ParseStackEntry.#ctor(LibreMetaverse.LslTools.Parser)`. +/// C# member: `M:LibreMetaverse.LslTools.ParseStackEntry.#ctor(LibreMetaverse.LslTools.Parser,System.Int32,LibreMetaverse.LslTools.SYMBOL)`. +pub use crate::parser::ParseStackEntry; /// C# type: `T:LibreMetaverse.LslTools.ParseState`. -pub struct ParseState { - /// C# member: `F:LibreMetaverse.LslTools.ParseState.m_accessingSymbol`. - pub m_accessing_symbol: libremetaverse_lsl_tools::CSymbol, - /// C# member: `F:LibreMetaverse.LslTools.ParseState.m_sgen`. - pub m_sgen: Box, - /// C# member: `F:LibreMetaverse.LslTools.ParseState.m_state`. - pub m_state: i32, - /// C# member: `F:LibreMetaverse.LslTools.ParseState.m_transitions`. - pub m_transitions: libremetaverse_types::compat::Hashtable, -} -impl ParseState { - /// C# member: `M:LibreMetaverse.LslTools.ParseState.#ctor(LibreMetaverse.LslTools.SymbolsGen,LibreMetaverse.LslTools.CSymbol)`. - pub fn new( - syms: libremetaverse_lsl_tools::SymbolsGen, - acc: libremetaverse_lsl_tools::CSymbol, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParseState.#ctor(LibreMetaverse.LslTools.SymbolsGen,LibreMetaverse.LslTools.CSymbol)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.Accessor(LibreMetaverse.LslTools.CSymbol[])`. - pub fn accessor( - &self, - x: Vec, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParseState.Accessor(LibreMetaverse.LslTools.CSymbol[])", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.AddEntries`. - pub fn add_entries(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParseState.AddEntries") - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.CheckClosure(LibreMetaverse.LslTools.ProdItem)`. - pub fn check_closure( - &self, - item: libremetaverse_lsl_tools::ProdItem, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParseState.CheckClosure(LibreMetaverse.LslTools.ProdItem)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.CheckExists`. - pub fn check_exists(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParseState.CheckExists") - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.Closure`. - pub fn closure(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParseState.Closure") - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.GetTransition(LibreMetaverse.LslTools.CSymbol)`. - pub fn get_transition( - &self, - s: libremetaverse_lsl_tools::CSymbol, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParseState.GetTransition(LibreMetaverse.LslTools.CSymbol)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.Lookback(LibreMetaverse.LslTools.Production,LibreMetaverse.LslTools.ParseState)`. - pub fn lookback( - &self, - pr: libremetaverse_lsl_tools::Production, - p: libremetaverse_lsl_tools::ParseState, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParseState.Lookback(LibreMetaverse.LslTools.Production,LibreMetaverse.LslTools.ParseState)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.MaybeAdd(LibreMetaverse.LslTools.ProdItem)`. - pub fn maybe_add(&self, item: libremetaverse_lsl_tools::ProdItem) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParseState.MaybeAdd(LibreMetaverse.LslTools.ProdItem)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.Print`. - pub fn print(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParseState.Print") - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.Print0`. - pub fn print0(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParseState.Print0") - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.ReduceStates`. - pub fn reduce_states(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParseState.ReduceStates") - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.SameAs(LibreMetaverse.LslTools.ParseState)`. - pub fn same_as(&self, p: libremetaverse_lsl_tools::ParseState) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParseState.SameAs(LibreMetaverse.LslTools.ParseState)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParseState.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. - pub fn serialise( - o: libremetaverse_types::compat::Object, - s: libremetaverse_lsl_tools::Serialiser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParseState.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)", - ) - } -} +/// C# member: `F:LibreMetaverse.LslTools.ParseState.m_accessingSymbol`. +/// C# member: `F:LibreMetaverse.LslTools.ParseState.m_sgen`. +/// C# member: `F:LibreMetaverse.LslTools.ParseState.m_state`. +/// C# member: `F:LibreMetaverse.LslTools.ParseState.m_transitions`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.#ctor(LibreMetaverse.LslTools.SymbolsGen,LibreMetaverse.LslTools.CSymbol)`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.Accessor(LibreMetaverse.LslTools.CSymbol[])`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.AddEntries`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.CheckClosure(LibreMetaverse.LslTools.ProdItem)`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.CheckExists`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.Closure`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.GetTransition(LibreMetaverse.LslTools.CSymbol)`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.Lookback(LibreMetaverse.LslTools.Production,LibreMetaverse.LslTools.ParseState)`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.MaybeAdd(LibreMetaverse.LslTools.ProdItem)`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.Print`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.Print0`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.ReduceStates`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.SameAs(LibreMetaverse.LslTools.ParseState)`. +/// C# member: `M:LibreMetaverse.LslTools.ParseState.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. +pub use crate::parser::ParseState; /// C# type: `T:LibreMetaverse.LslTools.Parser`. -pub struct Parser { - /// C# member: `F:LibreMetaverse.LslTools.Parser.m_debug`. - pub m_debug: bool, - /// C# member: `F:LibreMetaverse.LslTools.Parser.m_lexer`. - pub m_lexer: libremetaverse_lsl_tools::Lexer, - /// C# member: `F:LibreMetaverse.LslTools.Parser.m_stkdebug`. - pub m_stkdebug: bool, - /// C# member: `F:LibreMetaverse.LslTools.Parser.m_symbols`. - pub m_symbols: libremetaverse_lsl_tools::YyParser, -} -impl Parser { - /// C# member: `M:LibreMetaverse.LslTools.Parser.#ctor(LibreMetaverse.LslTools.YyParser,LibreMetaverse.LslTools.Lexer)`. - pub fn new( - syms: libremetaverse_lsl_tools::YyParser, - lexer: libremetaverse_lsl_tools::Lexer, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Parser.#ctor(LibreMetaverse.LslTools.YyParser,LibreMetaverse.LslTools.Lexer)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Parser.Error(System.Int32,LibreMetaverse.LslTools.SYMBOL,System.String)`. - pub fn error( - &self, - n: i32, - sym: libremetaverse_lsl_tools::SYMBOL, - s: String, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Parser.Error(System.Int32,LibreMetaverse.LslTools.SYMBOL,System.String)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Parser.NextSym`. - pub fn next_sym(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.Parser.NextSym") - } - /// C# member: `M:LibreMetaverse.LslTools.Parser.Parse(LibreMetaverse.LslTools.CsReader)`. - pub fn parse_with_cs_reader( - &self, - in_file: libremetaverse_lsl_tools::CsReader, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Parser.Parse(LibreMetaverse.LslTools.CsReader)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Parser.Parse(System.IO.StreamReader)`. - pub fn parse_with_stream_reader( - &self, - input: libremetaverse_types::compat::StreamReader, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Parser.Parse(System.IO.StreamReader)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Parser.Parse(System.String)`. - pub fn parse_with_string( - &self, - buf: String, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Parser.Parse(System.String)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Parser.StackAt(System.Int32)`. - pub fn stack_at( - &self, - ix: i32, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Parser.StackAt(System.Int32)", - ) - } -} +/// C# member: `F:LibreMetaverse.LslTools.Parser.m_debug`. +/// C# member: `F:LibreMetaverse.LslTools.Parser.m_lexer`. +/// C# member: `F:LibreMetaverse.LslTools.Parser.m_stkdebug`. +/// C# member: `F:LibreMetaverse.LslTools.Parser.m_symbols`. +/// C# member: `M:LibreMetaverse.LslTools.Parser.#ctor(LibreMetaverse.LslTools.YyParser,LibreMetaverse.LslTools.Lexer)`. +/// C# member: `M:LibreMetaverse.LslTools.Parser.Error(System.Int32,LibreMetaverse.LslTools.SYMBOL,System.String)`. +/// C# member: `M:LibreMetaverse.LslTools.Parser.NextSym`. +/// C# member: `M:LibreMetaverse.LslTools.Parser.Parse(LibreMetaverse.LslTools.CsReader)`. +/// C# member: `M:LibreMetaverse.LslTools.Parser.Parse(System.IO.StreamReader)`. +/// C# member: `M:LibreMetaverse.LslTools.Parser.Parse(System.String)`. +/// C# member: `M:LibreMetaverse.LslTools.Parser.StackAt(System.Int32)`. +pub use crate::parser::Parser; /// C# type: `T:LibreMetaverse.LslTools.ParserAction`. -pub struct ParserAction { - /// C# member: `F:LibreMetaverse.LslTools.ParserAction.m_len`. - pub m_len: i32, - /// C# member: `F:LibreMetaverse.LslTools.ParserAction.m_sym`. - pub m_sym: libremetaverse_lsl_tools::CSymbol, -} -impl ParserAction { - /// C# member: `M:LibreMetaverse.LslTools.ParserAction.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. - pub fn new(yyp: libremetaverse_lsl_tools::SymbolsGen) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserAction.#ctor(LibreMetaverse.LslTools.SymbolsGen)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParserAction.ActNum`. - pub fn act_num(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParserAction.ActNum") - } - /// C# member: `M:LibreMetaverse.LslTools.ParserAction.Action(LibreMetaverse.LslTools.Parser)`. - pub fn action( - &self, - yyp: libremetaverse_lsl_tools::Parser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserAction.Action(LibreMetaverse.LslTools.Parser)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParserAction.IsAction`. - pub fn is_action(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParserAction.IsAction") - } - /// C# member: `M:LibreMetaverse.LslTools.ParserAction.Print`. - pub fn print(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParserAction.Print") - } - /// C# member: `M:LibreMetaverse.LslTools.ParserAction.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. - pub fn serialise( - o: libremetaverse_types::compat::Object, - s: libremetaverse_lsl_tools::Serialiser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserAction.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)", - ) - } -} +/// C# member: `F:LibreMetaverse.LslTools.ParserAction.m_len`. +/// C# member: `F:LibreMetaverse.LslTools.ParserAction.m_sym`. +/// C# member: `M:LibreMetaverse.LslTools.ParserAction.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. +/// C# member: `M:LibreMetaverse.LslTools.ParserAction.ActNum`. +/// C# member: `M:LibreMetaverse.LslTools.ParserAction.Action(LibreMetaverse.LslTools.Parser)`. +/// C# member: `M:LibreMetaverse.LslTools.ParserAction.IsAction`. +/// C# member: `M:LibreMetaverse.LslTools.ParserAction.Print`. +/// C# member: `M:LibreMetaverse.LslTools.ParserAction.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. +pub use crate::parser::ParserAction; /// C# type: `T:LibreMetaverse.LslTools.ParserEntry`. -pub struct ParserEntry { - /// C# member: `F:LibreMetaverse.LslTools.ParserEntry.m_action`. - pub m_action: libremetaverse_lsl_tools::ParserAction, - /// C# member: `F:LibreMetaverse.LslTools.ParserEntry.m_priority`. - pub m_priority: i32, -} -impl ParserEntry { - /// C# member: `M:LibreMetaverse.LslTools.ParserEntry.IsReduce`. - pub fn is_reduce(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParserEntry.IsReduce") - } - /// C# member: `M:LibreMetaverse.LslTools.ParserEntry.Pass(LibreMetaverse.LslTools.ParseStackEntry@)`. - pub fn pass_( - &self, - top: &mut libremetaverse_lsl_tools::ParseStackEntry, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserEntry.Pass(LibreMetaverse.LslTools.ParseStackEntry@)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParserEntry.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. - pub fn serialise( - o: libremetaverse_types::compat::Object, - s: libremetaverse_lsl_tools::Serialiser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserEntry.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)", - ) - } - /// C# member: `P:LibreMetaverse.LslTools.ParserEntry.str`. - pub fn str(&self) -> String { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.LslTools.ParserEntry.str") - } -} +/// C# member: `F:LibreMetaverse.LslTools.ParserEntry.m_action`. +/// C# member: `F:LibreMetaverse.LslTools.ParserEntry.m_priority`. +/// C# member: `M:LibreMetaverse.LslTools.ParserEntry.IsReduce`. +/// C# member: `M:LibreMetaverse.LslTools.ParserEntry.Pass(LibreMetaverse.LslTools.ParseStackEntry@)`. +/// C# member: `M:LibreMetaverse.LslTools.ParserEntry.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. +/// C# member: `P:LibreMetaverse.LslTools.ParserEntry.str`. +pub use crate::parser::ParserEntry; /// C# type: `T:LibreMetaverse.LslTools.ParserOldAction`. -pub struct ParserOldAction { - /// C# member: `F:LibreMetaverse.LslTools.ParserOldAction.m_action`. - pub m_action: i32, -} -impl ParserOldAction { - /// C# member: `M:LibreMetaverse.LslTools.ParserOldAction.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. - pub fn new(yyp: libremetaverse_lsl_tools::SymbolsGen) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserOldAction.#ctor(LibreMetaverse.LslTools.SymbolsGen)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParserOldAction.ActNum`. - pub fn act_num(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParserOldAction.ActNum") - } - /// C# member: `M:LibreMetaverse.LslTools.ParserOldAction.Action(LibreMetaverse.LslTools.Parser)`. - pub fn action( - &self, - yyp: libremetaverse_lsl_tools::Parser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserOldAction.Action(LibreMetaverse.LslTools.Parser)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParserOldAction.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. - pub fn serialise( - o: libremetaverse_types::compat::Object, - s: libremetaverse_lsl_tools::Serialiser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserOldAction.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)", - ) - } -} +/// C# member: `F:LibreMetaverse.LslTools.ParserOldAction.m_action`. +/// C# member: `M:LibreMetaverse.LslTools.ParserOldAction.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. +/// C# member: `M:LibreMetaverse.LslTools.ParserOldAction.ActNum`. +/// C# member: `M:LibreMetaverse.LslTools.ParserOldAction.Action(LibreMetaverse.LslTools.Parser)`. +/// C# member: `M:LibreMetaverse.LslTools.ParserOldAction.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. +pub use crate::parser::ParserOldAction; /// C# type: `T:LibreMetaverse.LslTools.ParserReduce`. -pub struct ParserReduce { - /// C# member: `F:LibreMetaverse.LslTools.ParserReduce.m_depth`. - pub m_depth: i32, - /// C# member: `F:LibreMetaverse.LslTools.ParserReduce.m_lookAhead`. - pub m_look_ahead: libremetaverse_lsl_tools::SymbolSet, - /// C# member: `F:LibreMetaverse.LslTools.ParserReduce.m_prod`. - pub m_prod: libremetaverse_lsl_tools::Production, -} -impl ParserReduce { - /// C# member: `M:LibreMetaverse.LslTools.ParserReduce.#ctor(LibreMetaverse.LslTools.ParserAction,System.Int32,LibreMetaverse.LslTools.Production)`. - pub fn new( - action: libremetaverse_lsl_tools::ParserAction, - depth: i32, - prod: libremetaverse_lsl_tools::Production, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserReduce.#ctor(LibreMetaverse.LslTools.ParserAction,System.Int32,LibreMetaverse.LslTools.Production)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParserReduce.BuildLookback(LibreMetaverse.LslTools.Transition)`. - pub fn build_lookback( - &self, - a: libremetaverse_lsl_tools::Transition, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserReduce.BuildLookback(LibreMetaverse.LslTools.Transition)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParserReduce.IsReduce`. - pub fn is_reduce(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParserReduce.IsReduce") - } - /// C# member: `M:LibreMetaverse.LslTools.ParserReduce.Pass(LibreMetaverse.LslTools.ParseStackEntry@)`. - pub fn pass_( - &self, - top: &mut libremetaverse_lsl_tools::ParseStackEntry, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserReduce.Pass(LibreMetaverse.LslTools.ParseStackEntry@)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParserReduce.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. - pub fn serialise( - o: libremetaverse_types::compat::Object, - s: libremetaverse_lsl_tools::Serialiser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserReduce.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)", - ) - } - /// C# member: `P:LibreMetaverse.LslTools.ParserReduce.str`. - pub fn str(&self) -> String { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.LslTools.ParserReduce.str") - } -} +/// C# member: `F:LibreMetaverse.LslTools.ParserReduce.m_depth`. +/// C# member: `F:LibreMetaverse.LslTools.ParserReduce.m_lookAhead`. +/// C# member: `F:LibreMetaverse.LslTools.ParserReduce.m_prod`. +/// C# member: `M:LibreMetaverse.LslTools.ParserReduce.#ctor(LibreMetaverse.LslTools.ParserAction,System.Int32,LibreMetaverse.LslTools.Production)`. +/// C# member: `M:LibreMetaverse.LslTools.ParserReduce.BuildLookback(LibreMetaverse.LslTools.Transition)`. +/// C# member: `M:LibreMetaverse.LslTools.ParserReduce.IsReduce`. +/// C# member: `M:LibreMetaverse.LslTools.ParserReduce.Pass(LibreMetaverse.LslTools.ParseStackEntry@)`. +/// C# member: `M:LibreMetaverse.LslTools.ParserReduce.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. +/// C# member: `P:LibreMetaverse.LslTools.ParserReduce.str`. +pub use crate::parser::ParserReduce; /// C# type: `T:LibreMetaverse.LslTools.ParserShift`. -pub struct ParserShift { - /// C# member: `F:LibreMetaverse.LslTools.ParserShift.m_next`. - pub m_next: libremetaverse_lsl_tools::ParseState, -} -impl ParserShift { - /// C# member: `M:LibreMetaverse.LslTools.ParserShift.#ctor`. - pub fn new_with_constructor() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParserShift.#ctor") - } - /// C# member: `M:LibreMetaverse.LslTools.ParserShift.#ctor(LibreMetaverse.LslTools.ParserAction,LibreMetaverse.LslTools.ParseState)`. - pub fn new_with_parser_action_parse_state( - action: libremetaverse_lsl_tools::ParserAction, - next: libremetaverse_lsl_tools::ParseState, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserShift.#ctor(LibreMetaverse.LslTools.ParserAction,LibreMetaverse.LslTools.ParseState)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParserShift.Pass(LibreMetaverse.LslTools.ParseStackEntry@)`. - pub fn pass_( - &self, - top: &mut libremetaverse_lsl_tools::ParseStackEntry, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserShift.Pass(LibreMetaverse.LslTools.ParseStackEntry@)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParserShift.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. - pub fn serialise( - o: libremetaverse_types::compat::Object, - s: libremetaverse_lsl_tools::Serialiser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserShift.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)", - ) - } - /// C# member: `P:LibreMetaverse.LslTools.ParserShift.str`. - pub fn str(&self) -> String { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.LslTools.ParserShift.str") - } -} +/// C# member: `F:LibreMetaverse.LslTools.ParserShift.m_next`. +/// C# member: `M:LibreMetaverse.LslTools.ParserShift.#ctor`. +/// C# member: `M:LibreMetaverse.LslTools.ParserShift.#ctor(LibreMetaverse.LslTools.ParserAction,LibreMetaverse.LslTools.ParseState)`. +/// C# member: `M:LibreMetaverse.LslTools.ParserShift.Pass(LibreMetaverse.LslTools.ParseStackEntry@)`. +/// C# member: `M:LibreMetaverse.LslTools.ParserShift.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. +/// C# member: `P:LibreMetaverse.LslTools.ParserShift.str`. +pub use crate::parser::ParserShift; /// C# type: `T:LibreMetaverse.LslTools.ParserSimpleAction`. -pub struct ParserSimpleAction; -impl ParserSimpleAction { - /// C# member: `M:LibreMetaverse.LslTools.ParserSimpleAction.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. - pub fn new(yyp: libremetaverse_lsl_tools::SymbolsGen) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserSimpleAction.#ctor(LibreMetaverse.LslTools.SymbolsGen)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParserSimpleAction.Print`. - pub fn print(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ParserSimpleAction.Print") - } - /// C# member: `M:LibreMetaverse.LslTools.ParserSimpleAction.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. - pub fn serialise( - o: libremetaverse_types::compat::Object, - s: libremetaverse_lsl_tools::Serialiser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserSimpleAction.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParserSimpleAction.TypeStr`. - pub fn type_str(&self) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParserSimpleAction.TypeStr", - ) - } -} +/// C# member: `M:LibreMetaverse.LslTools.ParserSimpleAction.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. +/// C# member: `M:LibreMetaverse.LslTools.ParserSimpleAction.Print`. +/// C# member: `M:LibreMetaverse.LslTools.ParserSimpleAction.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. +/// C# member: `M:LibreMetaverse.LslTools.ParserSimpleAction.TypeStr`. +pub use crate::parser::ParserSimpleAction; /// C# type: `T:LibreMetaverse.LslTools.ParsingInfo`. -pub struct ParsingInfo { - /// C# member: `F:LibreMetaverse.LslTools.ParsingInfo.m_name`. - pub m_name: String, - /// C# member: `F:LibreMetaverse.LslTools.ParsingInfo.m_parsetable`. - pub m_parsetable: libremetaverse_types::compat::Hashtable, - /// C# member: `F:LibreMetaverse.LslTools.ParsingInfo.m_yynum`. - pub m_yynum: i32, -} -impl ParsingInfo { - /// C# member: `M:LibreMetaverse.LslTools.ParsingInfo.#ctor(System.String,System.Int32)`. - pub fn new(name: String, num: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParsingInfo.#ctor(System.String,System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ParsingInfo.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. - pub fn serialise( - o: libremetaverse_types::compat::Object, - s: libremetaverse_lsl_tools::Serialiser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ParsingInfo.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)", - ) - } -} +/// C# member: `F:LibreMetaverse.LslTools.ParsingInfo.m_name`. +/// C# member: `F:LibreMetaverse.LslTools.ParsingInfo.m_parsetable`. +/// C# member: `F:LibreMetaverse.LslTools.ParsingInfo.m_yynum`. +/// C# member: `M:LibreMetaverse.LslTools.ParsingInfo.#ctor(System.String,System.Int32)`. +/// C# member: `M:LibreMetaverse.LslTools.ParsingInfo.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. +pub use crate::parser::ParsingInfo; /// C# type: `T:LibreMetaverse.LslTools.Path`. pub struct Path { @@ -2270,194 +1754,51 @@ impl Path { } /// C# type: `T:LibreMetaverse.LslTools.Precedence`. -pub struct Precedence { - /// C# member: `F:LibreMetaverse.LslTools.Precedence.m_next`. - pub m_next: Box, - /// C# member: `F:LibreMetaverse.LslTools.Precedence.m_prec`. - pub m_prec: i32, - /// C# member: `F:LibreMetaverse.LslTools.Precedence.m_type`. - pub m_type: libremetaverse_lsl_tools::PrecedencePrecType, -} -impl Precedence { - /// C# member: `M:LibreMetaverse.LslTools.Precedence.#ctor(LibreMetaverse.LslTools.Precedence.PrecType,System.Int32,LibreMetaverse.LslTools.Precedence)`. - pub fn new( - t: libremetaverse_lsl_tools::PrecedencePrecType, - p: i32, - next: libremetaverse_lsl_tools::Precedence, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Precedence.#ctor(LibreMetaverse.LslTools.Precedence.PrecType,System.Int32,LibreMetaverse.LslTools.Precedence)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Precedence.Check(LibreMetaverse.LslTools.CSymbol,LibreMetaverse.LslTools.Production,System.Int32)`. - pub fn check_with_c_symbol_production_int32( - s: libremetaverse_lsl_tools::CSymbol, - p: libremetaverse_lsl_tools::Production, - d: i32, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Precedence.Check(LibreMetaverse.LslTools.CSymbol,LibreMetaverse.LslTools.Production,System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Precedence.Check(LibreMetaverse.LslTools.Precedence,LibreMetaverse.LslTools.Precedence.PrecType,System.Int32)`. - pub fn check_with_precedence_prec_type_int32( - p: libremetaverse_lsl_tools::Precedence, - t: libremetaverse_lsl_tools::PrecedencePrecType, - d: i32, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Precedence.Check(LibreMetaverse.LslTools.Precedence,LibreMetaverse.LslTools.Precedence.PrecType,System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Precedence.Check(LibreMetaverse.LslTools.Production)`. - pub fn check_with_production( - p: libremetaverse_lsl_tools::Production, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Precedence.Check(LibreMetaverse.LslTools.Production)", - ) - } -} +/// C# member: `F:LibreMetaverse.LslTools.Precedence.m_next`. +/// C# member: `F:LibreMetaverse.LslTools.Precedence.m_prec`. +/// C# member: `F:LibreMetaverse.LslTools.Precedence.m_type`. +/// C# member: `M:LibreMetaverse.LslTools.Precedence.#ctor(LibreMetaverse.LslTools.Precedence.PrecType,System.Int32,LibreMetaverse.LslTools.Precedence)`. +/// C# member: `M:LibreMetaverse.LslTools.Precedence.Check(LibreMetaverse.LslTools.CSymbol,LibreMetaverse.LslTools.Production,System.Int32)`. +/// C# member: `M:LibreMetaverse.LslTools.Precedence.Check(LibreMetaverse.LslTools.Precedence,LibreMetaverse.LslTools.Precedence.PrecType,System.Int32)`. +/// C# member: `M:LibreMetaverse.LslTools.Precedence.Check(LibreMetaverse.LslTools.Production)`. +pub use crate::parser::Precedence; /// C# type: `T:LibreMetaverse.LslTools.Precedence.PrecType`. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(i32)] -pub enum PrecedencePrecType { - /// C# member: `F:LibreMetaverse.LslTools.Precedence.PrecType.after`. - After = 4, - /// C# member: `F:LibreMetaverse.LslTools.Precedence.PrecType.before`. - Before = 3, - /// C# member: `F:LibreMetaverse.LslTools.Precedence.PrecType.left`. - Left = 0, - /// C# member: `F:LibreMetaverse.LslTools.Precedence.PrecType.nonassoc`. - Nonassoc = 2, - /// C# member: `F:LibreMetaverse.LslTools.Precedence.PrecType.right`. - Right = 1, -} +/// C# member: `F:LibreMetaverse.LslTools.Precedence.PrecType.after`. +/// C# member: `F:LibreMetaverse.LslTools.Precedence.PrecType.before`. +/// C# member: `F:LibreMetaverse.LslTools.Precedence.PrecType.left`. +/// C# member: `F:LibreMetaverse.LslTools.Precedence.PrecType.nonassoc`. +/// C# member: `F:LibreMetaverse.LslTools.Precedence.PrecType.right`. +pub use crate::parser::PrecedencePrecType; /// C# type: `T:LibreMetaverse.LslTools.ProdItem`. -pub struct ProdItem { - /// C# member: `F:LibreMetaverse.LslTools.ProdItem.m_done`. - pub m_done: bool, - /// C# member: `F:LibreMetaverse.LslTools.ProdItem.m_pos`. - pub m_pos: i32, - /// C# member: `F:LibreMetaverse.LslTools.ProdItem.m_prod`. - pub m_prod: libremetaverse_lsl_tools::Production, -} -impl ProdItem { - /// C# member: `M:LibreMetaverse.LslTools.ProdItem.#ctor`. - pub fn new_with_constructor() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ProdItem.#ctor") - } - /// C# member: `M:LibreMetaverse.LslTools.ProdItem.#ctor(LibreMetaverse.LslTools.Production,System.Int32)`. - pub fn new_with_production_int32( - prod: libremetaverse_lsl_tools::Production, - pos: i32, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ProdItem.#ctor(LibreMetaverse.LslTools.Production,System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ProdItem.FirstOfRest(LibreMetaverse.LslTools.SymbolsGen)`. - pub fn first_of_rest( - &self, - syms: libremetaverse_lsl_tools::SymbolsGen, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.ProdItem.FirstOfRest(LibreMetaverse.LslTools.SymbolsGen)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.ProdItem.IsReducingAction`. - pub fn is_reducing_action(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ProdItem.IsReducingAction") - } - /// C# member: `M:LibreMetaverse.LslTools.ProdItem.Next`. - pub fn next(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ProdItem.Next") - } - /// C# member: `M:LibreMetaverse.LslTools.ProdItem.Print`. - pub fn print(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.ProdItem.Print") - } -} +/// C# member: `F:LibreMetaverse.LslTools.ProdItem.m_done`. +/// C# member: `F:LibreMetaverse.LslTools.ProdItem.m_pos`. +/// C# member: `F:LibreMetaverse.LslTools.ProdItem.m_prod`. +/// C# member: `M:LibreMetaverse.LslTools.ProdItem.#ctor`. +/// C# member: `M:LibreMetaverse.LslTools.ProdItem.#ctor(LibreMetaverse.LslTools.Production,System.Int32)`. +/// C# member: `M:LibreMetaverse.LslTools.ProdItem.FirstOfRest(LibreMetaverse.LslTools.SymbolsGen)`. +/// C# member: `M:LibreMetaverse.LslTools.ProdItem.IsReducingAction`. +/// C# member: `M:LibreMetaverse.LslTools.ProdItem.Next`. +/// C# member: `M:LibreMetaverse.LslTools.ProdItem.Print`. +pub use crate::parser::ProdItem; /// C# type: `T:LibreMetaverse.LslTools.Production`. -pub struct Production { - /// C# member: `F:LibreMetaverse.LslTools.Production.m_actionsOnly`. - pub m_actions_only: bool, - /// C# member: `F:LibreMetaverse.LslTools.Production.m_alias`. - pub m_alias: libremetaverse_types::compat::Hashtable, - /// C# member: `F:LibreMetaverse.LslTools.Production.m_lhs`. - pub m_lhs: libremetaverse_lsl_tools::CSymbol, - /// C# member: `F:LibreMetaverse.LslTools.Production.m_pno`. - pub m_pno: i32, - /// C# member: `F:LibreMetaverse.LslTools.Production.m_prec`. - pub m_prec: i32, - /// C# member: `F:LibreMetaverse.LslTools.Production.m_rhs`. - pub m_rhs: libremetaverse_lsl_tools::ObjectList, -} -impl Production { - /// C# member: `M:LibreMetaverse.LslTools.Production.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. - pub fn new_with_symbols_gen( - syms: libremetaverse_lsl_tools::SymbolsGen, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Production.#ctor(LibreMetaverse.LslTools.SymbolsGen)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Production.#ctor(LibreMetaverse.LslTools.SymbolsGen,LibreMetaverse.LslTools.CSymbol)`. - pub fn new_with_symbols_gen_c_symbol( - syms: libremetaverse_lsl_tools::SymbolsGen, - lhs: libremetaverse_lsl_tools::CSymbol, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Production.#ctor(LibreMetaverse.LslTools.SymbolsGen,LibreMetaverse.LslTools.CSymbol)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Production.AddFirst(LibreMetaverse.LslTools.CSymbol,System.Int32)`. - pub fn add_first( - &self, - s: libremetaverse_lsl_tools::CSymbol, - j: i32, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Production.AddFirst(LibreMetaverse.LslTools.CSymbol,System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Production.AddToRhs(LibreMetaverse.LslTools.CSymbol)`. - pub fn add_to_rhs(&self, s: libremetaverse_lsl_tools::CSymbol) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Production.AddToRhs(LibreMetaverse.LslTools.CSymbol)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Production.CouldBeEmpty(System.Int32)`. - pub fn could_be_empty(&self, j: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Production.CouldBeEmpty(System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Production.Prefix(System.Int32)`. - pub fn prefix(&self, i: i32) -> Result, crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Production.Prefix(System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Production.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. - pub fn serialise( - o: libremetaverse_types::compat::Object, - s: libremetaverse_lsl_tools::Serialiser, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Production.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Production.StackRef(System.String@,System.Int32,System.Int32)`. - pub fn stack_ref(&self, str: &mut String, ch: i32, ix: i32) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Production.StackRef(System.String@,System.Int32,System.Int32)", - ) - } -} +/// C# member: `F:LibreMetaverse.LslTools.Production.m_actionsOnly`. +/// C# member: `F:LibreMetaverse.LslTools.Production.m_alias`. +/// C# member: `F:LibreMetaverse.LslTools.Production.m_lhs`. +/// C# member: `F:LibreMetaverse.LslTools.Production.m_pno`. +/// C# member: `F:LibreMetaverse.LslTools.Production.m_prec`. +/// C# member: `F:LibreMetaverse.LslTools.Production.m_rhs`. +/// C# member: `M:LibreMetaverse.LslTools.Production.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. +/// C# member: `M:LibreMetaverse.LslTools.Production.#ctor(LibreMetaverse.LslTools.SymbolsGen,LibreMetaverse.LslTools.CSymbol)`. +/// C# member: `M:LibreMetaverse.LslTools.Production.AddFirst(LibreMetaverse.LslTools.CSymbol,System.Int32)`. +/// C# member: `M:LibreMetaverse.LslTools.Production.AddToRhs(LibreMetaverse.LslTools.CSymbol)`. +/// C# member: `M:LibreMetaverse.LslTools.Production.CouldBeEmpty(System.Int32)`. +/// C# member: `M:LibreMetaverse.LslTools.Production.Prefix(System.Int32)`. +/// C# member: `M:LibreMetaverse.LslTools.Production.Serialise(System.Object,LibreMetaverse.LslTools.Serialiser)`. +/// C# member: `M:LibreMetaverse.LslTools.Production.StackRef(System.String@,System.Int32,System.Int32)`. +pub use crate::parser::Production; /// C# type: `T:LibreMetaverse.LslTools.RBRACE`. pub struct RBRACE; @@ -2879,88 +2220,21 @@ impl Stuff_4_1 { } /// C# type: `T:LibreMetaverse.LslTools.SymbolSet`. -pub struct SymbolSet { - /// C# member: `F:LibreMetaverse.LslTools.SymbolSet.m_next`. - pub m_next: Box, - /// C# member: `F:LibreMetaverse.LslTools.SymbolSet.m_symbols`. - pub m_symbols: Box, -} -impl SymbolSet { - /// C# member: `M:LibreMetaverse.LslTools.SymbolSet.#ctor(LibreMetaverse.LslTools.SymbolSet)`. - pub fn new_with_symbol_set( - s: libremetaverse_lsl_tools::SymbolSet, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.SymbolSet.#ctor(LibreMetaverse.LslTools.SymbolSet)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.SymbolSet.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. - pub fn new_with_symbols_gen( - syms: libremetaverse_lsl_tools::SymbolsGen, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.SymbolSet.#ctor(LibreMetaverse.LslTools.SymbolsGen)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.SymbolSet.Add(LibreMetaverse.LslTools.SymbolSet)`. - pub fn add_with_symbol_set( - &self, - s: libremetaverse_lsl_tools::SymbolSet, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.SymbolSet.Add(LibreMetaverse.LslTools.SymbolSet)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.SymbolSet.AddIn(LibreMetaverse.LslTools.CSymbol)`. - pub fn add_in(&self, t: libremetaverse_lsl_tools::CSymbol) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.SymbolSet.AddIn(LibreMetaverse.LslTools.CSymbol)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.SymbolSet.CheckIn(LibreMetaverse.LslTools.CSymbol)`. - pub fn check_in(&self, a: libremetaverse_lsl_tools::CSymbol) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.SymbolSet.CheckIn(LibreMetaverse.LslTools.CSymbol)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.SymbolSet.Contains(LibreMetaverse.LslTools.CSymbol)`. - pub fn contains(&self, a: libremetaverse_lsl_tools::CSymbol) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.SymbolSet.Contains(LibreMetaverse.LslTools.CSymbol)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.SymbolSet.GetEnumerator`. - pub fn get_enumerator( - &self, - ) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.SymbolSet.GetEnumerator") - } - /// C# member: `M:LibreMetaverse.LslTools.SymbolSet.Print`. - pub fn print(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.SymbolSet.Print") - } - /// C# member: `M:LibreMetaverse.LslTools.SymbolSet.Resolve`. - pub fn resolve(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.SymbolSet.Resolve") - } - /// C# member: `M:LibreMetaverse.LslTools.SymbolSet.op_Addition(LibreMetaverse.LslTools.SymbolSet,LibreMetaverse.LslTools.SymbolSet)`. - pub fn add_with_symbol_set_symbol_set( - s: libremetaverse_lsl_tools::SymbolSet, - t: libremetaverse_lsl_tools::SymbolSet, - ) -> libremetaverse_lsl_tools::SymbolSet { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.LslTools.SymbolSet.op_Addition(LibreMetaverse.LslTools.SymbolSet,LibreMetaverse.LslTools.SymbolSet)" - ) - } - /// C# member: `P:LibreMetaverse.LslTools.SymbolSet.Count`. - pub fn count(&self) -> i32 { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.LslTools.SymbolSet.Count") - } - /// C# member: `P:LibreMetaverse.LslTools.SymbolSet.Keys`. - pub fn keys(&self) -> libremetaverse_types::compat::ICollection { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.LslTools.SymbolSet.Keys") - } -} +/// C# member: `F:LibreMetaverse.LslTools.SymbolSet.m_next`. +/// C# member: `F:LibreMetaverse.LslTools.SymbolSet.m_symbols`. +/// C# member: `M:LibreMetaverse.LslTools.SymbolSet.#ctor(LibreMetaverse.LslTools.SymbolSet)`. +/// C# member: `M:LibreMetaverse.LslTools.SymbolSet.#ctor(LibreMetaverse.LslTools.SymbolsGen)`. +/// C# member: `M:LibreMetaverse.LslTools.SymbolSet.Add(LibreMetaverse.LslTools.SymbolSet)`. +/// C# member: `M:LibreMetaverse.LslTools.SymbolSet.AddIn(LibreMetaverse.LslTools.CSymbol)`. +/// C# member: `M:LibreMetaverse.LslTools.SymbolSet.CheckIn(LibreMetaverse.LslTools.CSymbol)`. +/// C# member: `M:LibreMetaverse.LslTools.SymbolSet.Contains(LibreMetaverse.LslTools.CSymbol)`. +/// C# member: `M:LibreMetaverse.LslTools.SymbolSet.GetEnumerator`. +/// C# member: `M:LibreMetaverse.LslTools.SymbolSet.Print`. +/// C# member: `M:LibreMetaverse.LslTools.SymbolSet.Resolve`. +/// C# member: `M:LibreMetaverse.LslTools.SymbolSet.op_Addition(LibreMetaverse.LslTools.SymbolSet,LibreMetaverse.LslTools.SymbolSet)`. +/// C# member: `P:LibreMetaverse.LslTools.SymbolSet.Count`. +/// C# member: `P:LibreMetaverse.LslTools.SymbolSet.Keys`. +pub use crate::parser::SymbolSet; /// C# type: `T:LibreMetaverse.LslTools.SymbolType`. pub struct SymbolType; @@ -3236,143 +2510,29 @@ impl TokensGen { } /// C# type: `T:LibreMetaverse.LslTools.Transition`. -pub struct Transition { - /// C# member: `F:LibreMetaverse.LslTools.Transition.m_A`. - pub m_a: libremetaverse_lsl_tools::CSymbol, - /// C# member: `F:LibreMetaverse.LslTools.Transition.m_next`. - pub m_next: libremetaverse_lsl_tools::ParserShift, - /// C# member: `F:LibreMetaverse.LslTools.Transition.m_ps`. - pub m_ps: libremetaverse_lsl_tools::ParseState, - /// C# member: `F:LibreMetaverse.LslTools.Transition.m_reduce`. - pub m_reduce: libremetaverse_types::compat::Hashtable, - /// C# member: `F:LibreMetaverse.LslTools.Transition.m_tno`. - pub m_tno: i32, -} -impl Transition { - /// C# member: `M:LibreMetaverse.LslTools.Transition.#ctor(LibreMetaverse.LslTools.ParseState,LibreMetaverse.LslTools.CSymbol)`. - pub fn new( - p: libremetaverse_lsl_tools::ParseState, - a: libremetaverse_lsl_tools::CSymbol, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.#ctor(LibreMetaverse.LslTools.ParseState,LibreMetaverse.LslTools.CSymbol)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.AddToFollow(LibreMetaverse.LslTools.Transition,LibreMetaverse.LslTools.SymbolSet)`. - pub fn add_to_follow( - a: libremetaverse_lsl_tools::Transition, - s: libremetaverse_lsl_tools::SymbolSet, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.AddToFollow(LibreMetaverse.LslTools.Transition,LibreMetaverse.LslTools.SymbolSet)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.AddToRead(LibreMetaverse.LslTools.Transition,LibreMetaverse.LslTools.SymbolSet)`. - pub fn add_to_read( - a: libremetaverse_lsl_tools::Transition, - s: libremetaverse_lsl_tools::SymbolSet, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.AddToRead(LibreMetaverse.LslTools.Transition,LibreMetaverse.LslTools.SymbolSet)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.BuildDR(LibreMetaverse.LslTools.Transition)`. - pub fn build_dr(t: libremetaverse_lsl_tools::Transition) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.BuildDR(LibreMetaverse.LslTools.Transition)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.BuildIncludes(LibreMetaverse.LslTools.Transition)`. - pub fn build_includes(t: libremetaverse_lsl_tools::Transition) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.BuildIncludes(LibreMetaverse.LslTools.Transition)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.BuildLA(LibreMetaverse.LslTools.Transition)`. - pub fn build_la(t: libremetaverse_lsl_tools::Transition) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.BuildLA(LibreMetaverse.LslTools.Transition)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.BuildLookback(LibreMetaverse.LslTools.Transition)`. - pub fn build_lookback(t: libremetaverse_lsl_tools::Transition) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.BuildLookback(LibreMetaverse.LslTools.Transition)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.BuildParseTable(LibreMetaverse.LslTools.Transition)`. - pub fn build_parse_table(t: libremetaverse_lsl_tools::Transition) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.BuildParseTable(LibreMetaverse.LslTools.Transition)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.BuildReads(LibreMetaverse.LslTools.Transition)`. - pub fn build_reads(t: libremetaverse_lsl_tools::Transition) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.BuildReads(LibreMetaverse.LslTools.Transition)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.DR(LibreMetaverse.LslTools.Transition)`. - pub fn dr( - a: libremetaverse_lsl_tools::Transition, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.DR(LibreMetaverse.LslTools.Transition)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.Final(LibreMetaverse.LslTools.Transition)`. - pub fn final_(t: libremetaverse_lsl_tools::Transition) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.Final(LibreMetaverse.LslTools.Transition)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.Follow(LibreMetaverse.LslTools.Transition)`. - pub fn follow( - a: libremetaverse_lsl_tools::Transition, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.Follow(LibreMetaverse.LslTools.Transition)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.Print(LibreMetaverse.LslTools.SymbolSet,System.String)`. - pub fn print( - &self, - x: libremetaverse_lsl_tools::SymbolSet, - s: String, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.Print(LibreMetaverse.LslTools.SymbolSet,System.String)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.Print0`. - pub fn print0(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.Transition.Print0") - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.Read(LibreMetaverse.LslTools.Transition)`. - pub fn read( - a: libremetaverse_lsl_tools::Transition, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.Read(LibreMetaverse.LslTools.Transition)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.includes(LibreMetaverse.LslTools.Transition)`. - pub fn includes( - a: libremetaverse_lsl_tools::Transition, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.includes(LibreMetaverse.LslTools.Transition)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.Transition.reads(LibreMetaverse.LslTools.Transition)`. - pub fn reads( - a: libremetaverse_lsl_tools::Transition, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.Transition.reads(LibreMetaverse.LslTools.Transition)", - ) - } -} +/// C# member: `F:LibreMetaverse.LslTools.Transition.m_A`. +/// C# member: `F:LibreMetaverse.LslTools.Transition.m_next`. +/// C# member: `F:LibreMetaverse.LslTools.Transition.m_ps`. +/// C# member: `F:LibreMetaverse.LslTools.Transition.m_reduce`. +/// C# member: `F:LibreMetaverse.LslTools.Transition.m_tno`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.#ctor(LibreMetaverse.LslTools.ParseState,LibreMetaverse.LslTools.CSymbol)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.AddToFollow(LibreMetaverse.LslTools.Transition,LibreMetaverse.LslTools.SymbolSet)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.AddToRead(LibreMetaverse.LslTools.Transition,LibreMetaverse.LslTools.SymbolSet)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.BuildDR(LibreMetaverse.LslTools.Transition)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.BuildIncludes(LibreMetaverse.LslTools.Transition)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.BuildLA(LibreMetaverse.LslTools.Transition)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.BuildLookback(LibreMetaverse.LslTools.Transition)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.BuildParseTable(LibreMetaverse.LslTools.Transition)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.BuildReads(LibreMetaverse.LslTools.Transition)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.DR(LibreMetaverse.LslTools.Transition)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.Final(LibreMetaverse.LslTools.Transition)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.Follow(LibreMetaverse.LslTools.Transition)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.Print(LibreMetaverse.LslTools.SymbolSet,System.String)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.Print0`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.Read(LibreMetaverse.LslTools.Transition)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.includes(LibreMetaverse.LslTools.Transition)`. +/// C# member: `M:LibreMetaverse.LslTools.Transition.reads(LibreMetaverse.LslTools.Transition)`. +pub use crate::parser::Transition; /// C# type: `T:LibreMetaverse.LslTools.YyLexer`. /// C# member: `F:LibreMetaverse.LslTools.YyLexer.cats`. @@ -3395,110 +2555,29 @@ impl Transition { pub use crate::lexer::YyLexer; /// C# type: `T:LibreMetaverse.LslTools.YyParser`. -pub struct YyParser { - /// C# member: `F:LibreMetaverse.LslTools.YyParser.EOFSymbol`. - pub eof_symbol: libremetaverse_lsl_tools::CSymbol, - /// C# member: `F:LibreMetaverse.LslTools.YyParser.Special`. - pub special: libremetaverse_lsl_tools::CSymbol, - /// C# member: `F:LibreMetaverse.LslTools.YyParser.arr`. - pub arr: Vec, - /// C# member: `F:LibreMetaverse.LslTools.YyParser.erh`. - pub erh: libremetaverse_lsl_tools::ErrorHandler, - /// C# member: `F:LibreMetaverse.LslTools.YyParser.literals`. - pub literals: libremetaverse_types::compat::Hashtable, - /// C# member: `F:LibreMetaverse.LslTools.YyParser.m_accept`. - pub m_accept: libremetaverse_lsl_tools::ParseState, - /// C# member: `F:LibreMetaverse.LslTools.YyParser.m_concrete`. - pub m_concrete: bool, - /// C# member: `F:LibreMetaverse.LslTools.YyParser.m_startSymbol`. - pub m_start_symbol: libremetaverse_lsl_tools::CSymbol, - /// C# member: `F:LibreMetaverse.LslTools.YyParser.m_states`. - pub m_states: libremetaverse_types::compat::Hashtable, - /// C# member: `F:LibreMetaverse.LslTools.YyParser.symbolInfo`. - pub symbol_info: libremetaverse_types::compat::Hashtable, - /// C# member: `F:LibreMetaverse.LslTools.YyParser.symbols`. - pub symbols: libremetaverse_types::compat::Hashtable, - /// C# member: `F:LibreMetaverse.LslTools.YyParser.types`. - pub types: libremetaverse_types::compat::Hashtable, -} -impl YyParser { - /// C# member: `M:LibreMetaverse.LslTools.YyParser.#ctor`. - pub fn new() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.YyParser.#ctor") - } - /// C# member: `M:LibreMetaverse.LslTools.YyParser.Action(LibreMetaverse.LslTools.Parser,LibreMetaverse.LslTools.SYMBOL,System.Int32)`. - pub fn action( - &self, - yyp: libremetaverse_lsl_tools::Parser, - yysym: libremetaverse_lsl_tools::SYMBOL, - yyact: i32, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.YyParser.Action(LibreMetaverse.LslTools.Parser,LibreMetaverse.LslTools.SYMBOL,System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.YyParser.ClassInit(LibreMetaverse.LslTools.SymbolsGen)`. - pub fn class_init( - &self, - yyp: libremetaverse_lsl_tools::SymbolsGen, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.YyParser.ClassInit(LibreMetaverse.LslTools.SymbolsGen)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.YyParser.Emit(System.IO.TextWriter)`. - pub fn emit(&self, m_out_file: Box) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.YyParser.Emit(System.IO.TextWriter)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.YyParser.GetEOF(LibreMetaverse.LslTools.Lexer)`. - pub fn get_eof(&self, yyl: libremetaverse_lsl_tools::Lexer) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.YyParser.GetEOF(LibreMetaverse.LslTools.Lexer)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.YyParser.GetParser(LibreMetaverse.LslTools.Lexer)`. - pub fn get_parser(&self, m_lexer: libremetaverse_lsl_tools::Lexer) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.YyParser.GetParser(LibreMetaverse.LslTools.Lexer)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.YyParser.GetSymbolInfo(System.String,System.Int32)`. - pub fn get_symbol_info( - &self, - name: String, - num: i32, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.YyParser.GetSymbolInfo(System.String,System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.YyParser.PrintTransitions(LibreMetaverse.LslTools.Func,System.String)`. - pub fn print_transitions( - &self, - f: libremetaverse_lsl_tools::Func, - s: String, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.YyParser.PrintTransitions(LibreMetaverse.LslTools.Func,System.String)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.YyParser.Transitions(LibreMetaverse.LslTools.Builder)`. - pub fn transitions(&self, b: libremetaverse_lsl_tools::Builder) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.YyParser.Transitions(LibreMetaverse.LslTools.Builder)", - ) - } - /// C# member: `P:LibreMetaverse.LslTools.YyParser.StartSymbol`. - pub fn start_symbol(&self) -> String { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.LslTools.YyParser.StartSymbol") - } - /// Setter for C# member: `P:LibreMetaverse.LslTools.YyParser.StartSymbol`. - pub fn set_start_symbol(&mut self, value: String) { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.LslTools.YyParser.StartSymbol") - } -} +/// C# member: `F:LibreMetaverse.LslTools.YyParser.EOFSymbol`. +/// C# member: `F:LibreMetaverse.LslTools.YyParser.Special`. +/// C# member: `F:LibreMetaverse.LslTools.YyParser.arr`. +/// C# member: `F:LibreMetaverse.LslTools.YyParser.erh`. +/// C# member: `F:LibreMetaverse.LslTools.YyParser.literals`. +/// C# member: `F:LibreMetaverse.LslTools.YyParser.m_accept`. +/// C# member: `F:LibreMetaverse.LslTools.YyParser.m_concrete`. +/// C# member: `F:LibreMetaverse.LslTools.YyParser.m_startSymbol`. +/// C# member: `F:LibreMetaverse.LslTools.YyParser.m_states`. +/// C# member: `F:LibreMetaverse.LslTools.YyParser.symbolInfo`. +/// C# member: `F:LibreMetaverse.LslTools.YyParser.symbols`. +/// C# member: `F:LibreMetaverse.LslTools.YyParser.types`. +/// C# member: `M:LibreMetaverse.LslTools.YyParser.#ctor`. +/// C# member: `M:LibreMetaverse.LslTools.YyParser.Action(LibreMetaverse.LslTools.Parser,LibreMetaverse.LslTools.SYMBOL,System.Int32)`. +/// C# member: `M:LibreMetaverse.LslTools.YyParser.ClassInit(LibreMetaverse.LslTools.SymbolsGen)`. +/// C# member: `M:LibreMetaverse.LslTools.YyParser.Emit(System.IO.TextWriter)`. +/// C# member: `M:LibreMetaverse.LslTools.YyParser.GetEOF(LibreMetaverse.LslTools.Lexer)`. +/// C# member: `M:LibreMetaverse.LslTools.YyParser.GetParser(LibreMetaverse.LslTools.Lexer)`. +/// C# member: `M:LibreMetaverse.LslTools.YyParser.GetSymbolInfo(System.String,System.Int32)`. +/// C# member: `M:LibreMetaverse.LslTools.YyParser.PrintTransitions(LibreMetaverse.LslTools.Func,System.String)`. +/// C# member: `M:LibreMetaverse.LslTools.YyParser.Transitions(LibreMetaverse.LslTools.Builder)`. +/// C# member: `P:LibreMetaverse.LslTools.YyParser.StartSymbol`. +pub use crate::parser::YyParser; /// C# type: `T:LibreMetaverse.LslTools.cs0syntax`. pub struct Cs0syntax { @@ -3564,34 +2643,11 @@ impl Cs0tokens { } /// C# type: `T:LibreMetaverse.LslTools.recoveredError`. -pub struct RecoveredError; -impl RecoveredError { - /// C# member: `M:LibreMetaverse.LslTools.recoveredError.#ctor(LibreMetaverse.LslTools.Parser,LibreMetaverse.LslTools.ParseStackEntry)`. - pub fn new( - yyp: libremetaverse_lsl_tools::Parser, - s: libremetaverse_lsl_tools::ParseStackEntry, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.recoveredError.#ctor(LibreMetaverse.LslTools.Parser,LibreMetaverse.LslTools.ParseStackEntry)", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.recoveredError.ConcreteSyntaxTree`. - pub fn concrete_syntax_tree(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LslTools.recoveredError.ConcreteSyntaxTree", - ) - } - /// C# member: `M:LibreMetaverse.LslTools.recoveredError.Print`. - pub fn print(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LslTools.recoveredError.Print") - } - /// C# member: `M:LibreMetaverse.LslTools.recoveredError.ToString`. - pub fn to_string(&self) -> String { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.LslTools.recoveredError.ToString" - ) - } -} +/// C# member: `M:LibreMetaverse.LslTools.recoveredError.#ctor(LibreMetaverse.LslTools.Parser,LibreMetaverse.LslTools.ParseStackEntry)`. +/// C# member: `M:LibreMetaverse.LslTools.recoveredError.ConcreteSyntaxTree`. +/// C# member: `M:LibreMetaverse.LslTools.recoveredError.Print`. +/// C# member: `M:LibreMetaverse.LslTools.recoveredError.ToString`. +pub use crate::parser::RecoveredError; /// C# type: `T:LibreMetaverse.LslTools.yycs0syntax`. pub struct Yycs0syntax; diff --git a/crates/libremetaverse-lsl-tools/src/lexer.rs b/crates/libremetaverse-lsl-tools/src/lexer.rs index 1495568..4a74e71 100644 --- a/crates/libremetaverse-lsl-tools/src/lexer.rs +++ b/crates/libremetaverse-lsl-tools/src/lexer.rs @@ -543,7 +543,7 @@ impl LineManager { } /// Source location compatible with `SourceLineInfo`. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct SourceLineInfo { pub char_position: i32, pub end_of_line: i32, @@ -638,7 +638,10 @@ pub enum DiagnosticCategory { Encoding, InvalidCharacter, InvalidState, + ParserRecovery, + ParserStackLimit, Source, + Syntax, TokenTooLong, UnknownCharacterSet, UnexpectedEof, @@ -986,7 +989,7 @@ impl ErrorHandler { std::mem::take(&mut self.diagnostics) } - fn push(&mut self, diagnostic: Diagnostic) -> Result<(), Error> { + pub(crate) fn push(&mut self, diagnostic: Diagnostic) -> Result<(), Error> { self.counter = self.counter.checked_add(1).ok_or(Error::IndexOutOfRange)?; if self.throw_exceptions { return Err(Error::InvalidOperation); @@ -2007,6 +2010,24 @@ pub struct SYMBOL { pub pos_with_field: i32, pub yylx: Option>, pub yyps: Option>, + name: String, + number: i32, + text: String, +} + +impl Clone for SYMBOL { + fn clone(&self) -> Self { + Self { + kids: self.kids.clone(), + m_dollar: self.m_dollar.clone(), + pos_with_field: self.pos_with_field, + yylx: self.yylx.clone(), + yyps: self.yyps.clone(), + name: self.name.clone(), + number: self.number, + text: self.text.clone(), + } + } } impl fmt::Debug for SYMBOL { @@ -2018,6 +2039,9 @@ impl fmt::Debug for SYMBOL { .field("pos", &self.pos_with_field) .field("has_lexer", &self.yylx.is_some()) .field("has_parser", &self.yyps.is_some()) + .field("name", &self.name) + .field("number", &self.number) + .field("text", &self.text) .finish() } } @@ -2030,6 +2054,9 @@ impl SYMBOL { pos_with_field: lexer.yypos(), yylx: Some(Box::new(lexer)), yyps: None, + name: "SYMBOL".to_owned(), + number: 0, + text: String::new(), }) } @@ -2040,9 +2067,32 @@ impl SYMBOL { pos_with_field: 0, yylx: None, yyps: Some(Box::new(parser)), + name: "SYMBOL".to_owned(), + number: 0, + text: String::new(), }) } + pub(crate) fn parser_symbol( + name: String, + number: i32, + text: String, + pos: i32, + value: Object, + kids: ObjectList, + ) -> Self { + Self { + kids, + m_dollar: value, + pos_with_field: pos, + yylx: None, + yyps: None, + name, + number, + text, + } + } + fn location(&self) -> Result { self.yylx .as_deref() @@ -2074,8 +2124,8 @@ impl SYMBOL { pub fn is_terminal(&self) -> Result { Ok(false) } - pub fn matches(&self, _value: String) -> Result { - Ok(false) + pub fn matches(&self, value: String) -> Result { + Ok(self.text == value) } pub fn pass_( @@ -2093,7 +2143,11 @@ impl SYMBOL { } #[must_use] pub fn to_string(&self) -> String { - self.yyname() + if self.text.is_empty() { + self.yyname() + } else { + format!("{}<{}>", self.yyname(), self.text) + } } pub fn from(symbol: SYMBOL) -> i32 { @@ -2133,11 +2187,11 @@ impl SYMBOL { } #[must_use] pub fn yyname(&self) -> String { - "SYMBOL".to_owned() + self.name.clone() } #[must_use] pub const fn yynum(&self) -> i32 { - 0 + self.number } } @@ -2297,6 +2351,10 @@ fn lookup_parser_entry( state: i32, entry: &mut ParserEntry, ) -> Result { + if let Some(native) = symbols.lookup_entry(number, state)? { + *entry = native; + return Ok(true); + } let Some(info) = symbols.symbol_info.0.get(&Object::Integer(number)) else { return Err(Error::Parse { position: 0, @@ -2392,7 +2450,7 @@ impl Null { } /// Rust replacement for the C# cons-list, backed by contiguous storage. -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct ObjectList { values: VecDeque, count_override: Option, diff --git a/crates/libremetaverse-lsl-tools/src/lib.rs b/crates/libremetaverse-lsl-tools/src/lib.rs index f4614b4..61cadeb 100644 --- a/crates/libremetaverse-lsl-tools/src/lib.rs +++ b/crates/libremetaverse-lsl-tools/src/lib.rs @@ -4,6 +4,7 @@ extern crate self as libremetaverse_lsl_tools; mod generated; mod lexer; +mod parser; pub use generated::*; pub use lexer::{ @@ -12,3 +13,7 @@ pub use lexer::{ MAX_TOKEN_UNITS, TokenDefinition, UnicodeClass, }; pub use libremetaverse_types::Error; +pub use parser::{ + Associativity, ERROR_TOKEN, Grammar, GrammarProduction, GrammarSymbol, MAX_PARSER_STACK, + MAX_PARSER_STATES, MAX_PARSER_STEPS, MAX_RECOVERY_ERRORS, ParseTree, ParserConflict, +}; diff --git a/crates/libremetaverse-lsl-tools/src/parser.rs b/crates/libremetaverse-lsl-tools/src/parser.rs new file mode 100644 index 0000000..f5260ae --- /dev/null +++ b/crates/libremetaverse-lsl-tools/src/parser.rs @@ -0,0 +1,3019 @@ +//! Deterministic native grammar tables and bounded shift/reduce parsing. + +#![allow(clippy::inherent_to_string_shadow_display)] +#![allow(clippy::inherent_to_string)] +#![allow(clippy::missing_fields_in_debug)] +#![allow(clippy::missing_errors_doc)] +#![allow(clippy::must_use_candidate)] +#![allow(clippy::needless_pass_by_value)] +#![allow(clippy::too_many_lines)] + +use std::collections::{BTreeMap, BTreeSet, VecDeque}; +use std::fmt; +use std::fmt::Write as _; +use std::io::Write; +use std::sync::{Arc, Mutex, Weak}; + +use libremetaverse_types::compat::{ + Hashtable, ICollection, IDictionaryEnumerator, Object, StreamReader, +}; + +use crate::lexer::{ + Diagnostic, DiagnosticCategory, DiagnosticSeverity, ObjectList, SYMBOL, SourceLineInfo, TOKEN, +}; +use crate::{Builder, CsReader, Error, Func, Lexer, Serialiser, SymbolsGen}; + +/// Maximum number of parser states accepted from one grammar. +pub const MAX_PARSER_STATES: usize = 65_536; +/// Maximum live stack depth of the parser. +pub const MAX_PARSER_STACK: usize = 1_048_576; +/// Maximum number of shift/reduce/recovery operations in one parse. +pub const MAX_PARSER_STEPS: usize = 16_777_216; +/// Compatibility limit used by the reference error recovery loop. +pub const MAX_RECOVERY_ERRORS: usize = 1_000; +/// Conventional yacc error terminal number. +pub const ERROR_TOKEN: i32 = 0; + +/// Associativity used to resolve equal-precedence shift/reduce conflicts. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum Associativity { + Left, + Right, + Nonassoc, +} + +/// One grammar symbol supplied to [`Grammar`]. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct GrammarSymbol { + pub name: String, + pub number: i32, + pub terminal: bool, +} + +/// One grammar production, numbered in insertion order. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct GrammarProduction { + pub lhs: i32, + pub rhs: Vec, + pub precedence: Option, +} + +/// Deterministic grammar input for the native table builder. +#[derive(Clone, Debug)] +pub struct Grammar { + start: i32, + eof: i32, + symbols: BTreeMap, + productions: Vec, + precedence: BTreeMap, + literals: BTreeMap, +} + +impl Grammar { + /// Creates a grammar with explicit start and end-of-input symbols. + pub fn new(start: i32, eof: i32) -> Result { + if start == eof || start == ERROR_TOKEN { + return Err(Error::Argument); + } + Ok(Self { + start, + eof, + symbols: BTreeMap::new(), + productions: Vec::new(), + precedence: BTreeMap::new(), + literals: BTreeMap::new(), + }) + } + + /// Adds a terminal or nonterminal. Numbers are stable parser identities. + pub fn add_symbol( + &mut self, + name: impl Into, + number: i32, + terminal: bool, + ) -> Result<(), Error> { + let name = name.into(); + if name.is_empty() || self.symbols.contains_key(&number) { + return Err(Error::Argument); + } + self.symbols.insert( + number, + GrammarSymbol { + name, + number, + terminal, + }, + ); + Ok(()) + } + + /// Associates lexer literal text with a terminal number. + pub fn add_literal(&mut self, text: impl Into, terminal: i32) -> Result<(), Error> { + let text = text.into(); + if text.is_empty() + || !self + .symbols + .get(&terminal) + .is_some_and(|symbol| symbol.terminal) + { + return Err(Error::Argument); + } + self.literals.insert(text, terminal); + Ok(()) + } + + /// Adds a precedence declaration for a terminal. + pub fn set_precedence( + &mut self, + terminal: i32, + level: i32, + associativity: Associativity, + ) -> Result<(), Error> { + if level <= 0 + || !self + .symbols + .get(&terminal) + .is_some_and(|symbol| symbol.terminal) + { + return Err(Error::Argument); + } + self.precedence.insert(terminal, (level, associativity)); + Ok(()) + } + + /// Adds a production and returns its stable zero-based production number. + pub fn add_production(&mut self, lhs: i32, rhs: Vec) -> Result { + self.add_production_with_precedence(lhs, rhs, None) + } + + /// Adds a production with an explicit precedence terminal override. + pub fn add_production_with_precedence( + &mut self, + lhs: i32, + rhs: Vec, + precedence: Option, + ) -> Result { + if self.symbols.get(&lhs).is_none_or(|symbol| symbol.terminal) + || rhs.iter().any(|symbol| !self.symbols.contains_key(symbol)) + || precedence.is_some_and(|symbol| !self.precedence.contains_key(&symbol)) + { + return Err(Error::Argument); + } + let number = self.productions.len(); + self.productions.push(GrammarProduction { + lhs, + rhs, + precedence, + }); + Ok(number) + } + + /// Builds canonical LR(0) item sets with SLR lookahead propagation. + pub fn build(self) -> Result { + ParserMachine::build(self).map(YyParser::from_machine) + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum TableAction { + Shift(usize), + Reduce(usize), + Accept, + Reject, +} + +/// One table conflict and the deterministic compatibility decision. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ParserConflict { + pub state: usize, + pub lookahead: i32, + pub existing: String, + pub incoming: String, + pub chosen: String, +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +struct Item { + production: usize, + dot: usize, +} + +#[derive(Clone, Debug)] +struct RuntimeProduction { + lhs: i32, + rhs: Vec, + precedence: Option<(i32, Associativity)>, +} + +#[derive(Clone, Debug)] +struct ParserMachine { + start: i32, + eof: i32, + symbols: BTreeMap, + literals: BTreeMap, + productions: Vec, + actions: BTreeMap<(usize, i32), TableAction>, + gotos: BTreeMap<(usize, i32), usize>, + conflicts: Vec, + states: Vec>, +} + +impl ParserMachine { + fn build(grammar: Grammar) -> Result { + if grammar + .symbols + .get(&grammar.start) + .is_none_or(|symbol| symbol.terminal) + || grammar + .symbols + .get(&grammar.eof) + .is_none_or(|symbol| !symbol.terminal) + || grammar.productions.is_empty() + || !grammar + .productions + .iter() + .any(|production| production.lhs == grammar.start) + { + return Err(Error::Argument); + } + + if grammar.symbols.len() >= MAX_PARSER_STATES + || grammar.productions.len() >= MAX_PARSER_STACK + { + return Err(Error::Parse { + position: grammar.symbols.len().max(grammar.productions.len()), + context: "parser grammar exceeds the table-input limit", + }); + } + let augmented = (0..=grammar.symbols.len()) + .filter_map(|offset| i32::try_from(offset).ok()) + .filter_map(|offset| i32::MIN.checked_add(offset)) + .find(|value| *value != ERROR_TOKEN && !grammar.symbols.contains_key(value)) + .ok_or(Error::IndexOutOfRange)?; + let mut productions = vec![RuntimeProduction { + lhs: augmented, + rhs: vec![grammar.start], + precedence: None, + }]; + productions.extend(grammar.productions.iter().map(|production| { + let terminal = production.precedence.or_else(|| { + production.rhs.iter().rev().copied().find(|symbol| { + grammar.symbols.get(symbol).is_some_and(|value| { + value.terminal && grammar.precedence.contains_key(symbol) + }) + }) + }); + RuntimeProduction { + lhs: production.lhs, + rhs: production.rhs.clone(), + precedence: terminal.and_then(|symbol| grammar.precedence.get(&symbol).copied()), + } + })); + + let by_lhs = Self::productions_by_lhs(&productions); + let first = Self::first_sets(&grammar.symbols, &productions); + let nullable = Self::nullable(&grammar.symbols, &productions); + let initial = Self::closure( + BTreeSet::from([Item { + production: 0, + dot: 0, + }]), + &productions, + &by_lhs, + ); + let mut states = vec![initial]; + let mut state_ids = BTreeMap::from([(states[0].clone(), 0usize)]); + let mut transitions = BTreeMap::new(); + let mut queue = VecDeque::from([0usize]); + while let Some(state) = queue.pop_front() { + let symbols = states[state] + .iter() + .filter_map(|item| productions[item.production].rhs.get(item.dot).copied()) + .collect::>(); + for symbol in symbols { + let target = Self::goto(&states[state], symbol, &productions, &by_lhs); + if target.is_empty() { + continue; + } + let target_state = if let Some(existing) = state_ids.get(&target) { + *existing + } else { + if states.len() >= MAX_PARSER_STATES { + return Err(Error::Parse { + position: states.len(), + context: "parser grammar exceeds the state limit", + }); + } + let index = states.len(); + state_ids.insert(target.clone(), index); + states.push(target); + queue.push_back(index); + index + }; + transitions.insert((state, symbol), target_state); + } + } + + let lookaheads = Self::lalr_lookaheads( + &states, + &transitions, + &productions, + &by_lhs, + &first, + &nullable, + grammar.eof, + )?; + + let mut machine = Self { + start: grammar.start, + eof: grammar.eof, + symbols: grammar.symbols, + literals: grammar.literals, + productions, + actions: BTreeMap::new(), + gotos: BTreeMap::new(), + conflicts: Vec::new(), + states, + }; + for ((state, symbol), target) in transitions { + if machine + .symbols + .get(&symbol) + .is_some_and(|value| value.terminal) + { + machine.insert_action( + state, + symbol, + TableAction::Shift(target), + &grammar.precedence, + ); + } else { + machine.gotos.insert((state, symbol), target); + } + } + for state in 0..machine.states.len() { + let items = machine.states[state].clone(); + for item in items { + let production = &machine.productions[item.production]; + if item.dot != production.rhs.len() { + continue; + } + if item.production == 0 { + machine.insert_action( + state, + machine.eof, + TableAction::Accept, + &grammar.precedence, + ); + continue; + } + if let Some(item_lookaheads) = lookaheads.get(&(state, item)) { + for lookahead in item_lookaheads { + machine.insert_action( + state, + *lookahead, + TableAction::Reduce(item.production - 1), + &grammar.precedence, + ); + } + } + } + } + Ok(machine) + } + + fn productions_by_lhs(productions: &[RuntimeProduction]) -> BTreeMap> { + let mut result = BTreeMap::>::new(); + for (index, production) in productions.iter().enumerate() { + result.entry(production.lhs).or_default().push(index); + } + result + } + + fn nullable( + _symbols: &BTreeMap, + productions: &[RuntimeProduction], + ) -> BTreeSet { + let mut nullable = BTreeSet::new(); + loop { + let before = nullable.len(); + for production in productions { + if production + .rhs + .iter() + .all(|symbol| nullable.contains(symbol)) + { + nullable.insert(production.lhs); + } + } + if nullable.len() == before { + break; + } + } + nullable + } + + fn first_sets( + symbols: &BTreeMap, + productions: &[RuntimeProduction], + ) -> BTreeMap> { + let mut first = symbols + .iter() + .map(|(number, symbol)| { + let set = if symbol.terminal { + BTreeSet::from([*number]) + } else { + BTreeSet::new() + }; + (*number, set) + }) + .collect::>(); + let nullable = Self::nullable(symbols, productions); + loop { + let snapshot = first.clone(); + for production in productions { + for symbol in &production.rhs { + if let Some(values) = snapshot.get(symbol) { + first.entry(production.lhs).or_default().extend(values); + } + if !nullable.contains(symbol) { + break; + } + } + } + if first == snapshot { + break; + } + } + first + } + + fn lalr_lookaheads( + states: &[BTreeSet], + transitions: &BTreeMap<(usize, i32), usize>, + productions: &[RuntimeProduction], + by_lhs: &BTreeMap>, + first: &BTreeMap>, + nullable: &BTreeSet, + eof: i32, + ) -> Result>, Error> { + let initial = Item { + production: 0, + dot: 0, + }; + let mut lookaheads = BTreeMap::from([((0, initial), BTreeSet::from([eof]))]); + let mut passes = 0usize; + loop { + passes = passes.checked_add(1).ok_or(Error::IndexOutOfRange)?; + if passes > MAX_PARSER_STEPS { + return Err(Error::Parse { + position: passes, + context: "parser lookahead propagation exceeded the step limit", + }); + } + let snapshot = lookaheads.clone(); + for (state, items) in states.iter().enumerate() { + for item in items { + let current = snapshot.get(&(state, *item)).cloned().unwrap_or_default(); + if current.is_empty() { + continue; + } + let production = &productions[item.production]; + let Some(symbol) = production.rhs.get(item.dot) else { + continue; + }; + + if let Some(target) = transitions.get(&(state, *symbol)) { + lookaheads + .entry(( + *target, + Item { + production: item.production, + dot: item.dot + 1, + }, + )) + .or_default() + .extend(¤t); + } + + let Some(indices) = by_lhs.get(symbol) else { + continue; + }; + let rest = &production.rhs[item.dot + 1..]; + let mut closure_lookaheads = BTreeSet::new(); + for following in rest { + if let Some(values) = first.get(following) { + closure_lookaheads.extend(values); + } + if !nullable.contains(following) { + break; + } + } + if rest.iter().all(|following| nullable.contains(following)) { + closure_lookaheads.extend(¤t); + } + for production in indices { + lookaheads + .entry(( + state, + Item { + production: *production, + dot: 0, + }, + )) + .or_default() + .extend(&closure_lookaheads); + } + } + } + if lookaheads == snapshot { + break; + } + } + Ok(lookaheads) + } + + fn closure( + mut items: BTreeSet, + productions: &[RuntimeProduction], + by_lhs: &BTreeMap>, + ) -> BTreeSet { + loop { + let before = items.len(); + let snapshot = items.clone(); + for item in snapshot { + let Some(symbol) = productions[item.production].rhs.get(item.dot) else { + continue; + }; + if let Some(indices) = by_lhs.get(symbol) { + items.extend(indices.iter().map(|production| Item { + production: *production, + dot: 0, + })); + } + } + if items.len() == before { + return items; + } + } + } + + fn goto( + items: &BTreeSet, + symbol: i32, + productions: &[RuntimeProduction], + by_lhs: &BTreeMap>, + ) -> BTreeSet { + let advanced = items + .iter() + .filter(|item| productions[item.production].rhs.get(item.dot) == Some(&symbol)) + .map(|item| Item { + production: item.production, + dot: item.dot + 1, + }) + .collect::>(); + Self::closure(advanced, productions, by_lhs) + } + + fn insert_action( + &mut self, + state: usize, + lookahead: i32, + incoming: TableAction, + precedence: &BTreeMap, + ) { + let key = (state, lookahead); + let Some(existing) = self.actions.get(&key).copied() else { + self.actions.insert(key, incoming); + return; + }; + if existing == incoming { + return; + } + let chosen = match (existing, incoming) { + (TableAction::Shift(_), TableAction::Reduce(production)) => { + self.resolve_shift_reduce(existing, production, lookahead, precedence) + } + (TableAction::Reduce(production), TableAction::Shift(_)) => { + self.resolve_shift_reduce(incoming, production, lookahead, precedence) + } + (TableAction::Reduce(left), TableAction::Reduce(right)) => { + TableAction::Reduce(left.min(right)) + } + (TableAction::Accept, _) | (_, TableAction::Accept) => TableAction::Accept, + _ => existing, + }; + self.conflicts.push(ParserConflict { + state, + lookahead, + existing: Self::action_text(existing), + incoming: Self::action_text(incoming), + chosen: Self::action_text(chosen), + }); + self.actions.insert(key, chosen); + } + + fn resolve_shift_reduce( + &self, + shift: TableAction, + production: usize, + lookahead: i32, + precedence: &BTreeMap, + ) -> TableAction { + let token_precedence = precedence.get(&lookahead).copied(); + let production_precedence = self.productions[production + 1].precedence; + match (token_precedence, production_precedence) { + (Some((token, associativity)), Some((reduce, _))) if token == reduce => { + match associativity { + Associativity::Left => TableAction::Reduce(production), + Associativity::Right => shift, + Associativity::Nonassoc => TableAction::Reject, + } + } + (Some((token, _)), Some((reduce, _))) if reduce > token => { + TableAction::Reduce(production) + } + _ => shift, + } + } + + fn action_text(action: TableAction) -> String { + match action { + TableAction::Shift(state) => format!("shift {state}"), + TableAction::Reduce(production) => format!("reduce {production}"), + TableAction::Accept => "accept".to_owned(), + TableAction::Reject => "reject".to_owned(), + } + } + + fn stable_description(&self) -> String { + let mut lines = vec![format!( + "LSLPARSER 1 start {} eof {} states {} productions {}", + self.start, + self.eof, + self.states.len(), + self.productions.len().saturating_sub(1) + )]; + for ((state, token), action) in &self.actions { + lines.push(format!( + "action {state} {token} {}", + Self::action_text(*action) + )); + } + for ((state, symbol), target) in &self.gotos { + lines.push(format!("goto {state} {symbol} {target}")); + } + for (index, production) in self.productions.iter().skip(1).enumerate() { + let rhs = production + .rhs + .iter() + .map(i32::to_string) + .collect::>() + .join(" "); + lines.push(format!("production {index} {} -> {rhs}", production.lhs)); + } + lines.join("\n") + } +} + +/// Immutable syntax tree produced by the native parser. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ParseTree { + pub name: String, + pub number: i32, + pub text: Option, + pub start: i32, + pub end: i32, + pub children: Vec, +} + +impl ParseTree { + fn token(token: &TOKEN, number: i32) -> Self { + Self { + name: token.yyname(), + number, + text: Some(token.yytext()), + start: token.pos, + end: token.end, + children: Vec::new(), + } + } + + fn error(position: i32) -> Self { + Self { + name: "Error".to_owned(), + number: ERROR_TOKEN, + text: None, + start: position, + end: position, + children: Vec::new(), + } + } +} + +/// Mapped C# symbol categories. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(i32)] +pub enum CSymbolSymType { + Unknown = 0, + Terminal = 1, + Nonterminal = 2, + Nodesymbol = 3, + Oldaction = 4, + Simpleaction = 5, + Eofsymbol = 6, +} + +#[derive(Clone, Debug)] +struct SymbolRef { + name: String, + number: i32, + symbol_type: CSymbolSymType, + productions: Weak>>>>, +} + +impl SymbolRef { + fn is_nullable(&self, visiting: &mut BTreeSet<(i32, String)>) -> bool { + if matches!( + self.symbol_type, + CSymbolSymType::Oldaction | CSymbolSymType::Simpleaction + ) { + return true; + } + if self.symbol_type != CSymbolSymType::Nonterminal { + return false; + } + let key = (self.number, self.name.clone()); + if !visiting.insert(key.clone()) { + return false; + } + let nullable = self + .productions + .upgrade() + .and_then(|productions| { + productions + .lock() + .ok() + .map(|values| values.iter().cloned().collect::>()) + }) + .is_some_and(|productions| { + productions.iter().any(|production| { + production.lock().ok().is_some_and(|value| { + value.rhs.iter().all(|symbol| symbol.is_nullable(visiting)) + }) + }) + }); + visiting.remove(&key); + nullable + } + + fn to_symbol(&self) -> CSymbol { + let mut symbol = CSymbol::placeholder(); + symbol.text.clone_from(&self.name); + symbol.m_yynum = self.number; + symbol.m_symtype = self.symbol_type; + symbol.m_defined = true; + if let Some(productions) = self.productions.upgrade() { + symbol.productions = productions; + } + symbol + } +} + +#[derive(Debug)] +struct ProductionRecord { + number: i32, + actions_only: bool, + precedence: i32, + rhs: Vec, +} + +/// Grammar symbol metadata used by production and precedence construction. +#[derive(Clone)] +pub struct CSymbol { + pub m_defined: bool, + pub m_emitted: bool, + pub m_first: SymbolSet, + pub m_follow: SymbolSet, + pub m_initialisation: String, + pub m_parser: Option>, + pub m_prec: Option>, + pub m_prod: Option>, + pub m_prods: ObjectList, + pub m_ref_symbol: Option>, + pub m_symtype: CSymbolSymType, + pub m_yynum: i32, + text: String, + productions: Arc>>>>, +} + +impl fmt::Debug for CSymbol { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("CSymbol") + .field("text", &self.text) + .field("number", &self.m_yynum) + .field("type", &self.m_symtype) + .field( + "productions", + &self.productions.lock().map_or(0, |values| values.len()), + ) + .finish() + } +} + +impl CSymbol { + fn placeholder() -> Self { + Self { + m_defined: false, + m_emitted: false, + m_first: SymbolSet::empty(), + m_follow: SymbolSet::empty(), + m_initialisation: String::new(), + m_parser: None, + m_prec: None, + m_prod: None, + m_prods: ObjectList::default(), + m_ref_symbol: None, + m_symtype: CSymbolSymType::Unknown, + m_yynum: -1, + text: String::new(), + productions: Arc::new(Mutex::new(Vec::new())), + } + } + + /// Constructs symbol metadata without generator state. + pub fn native( + name: impl Into, + number: i32, + symbol_type: CSymbolSymType, + ) -> Result { + let name = name.into(); + if name.is_empty() || number < ERROR_TOKEN { + return Err(Error::Argument); + } + let mut symbol = Self::placeholder(); + symbol.text = name; + symbol.m_yynum = number; + symbol.m_symtype = symbol_type; + symbol.m_defined = true; + if matches!( + symbol_type, + CSymbolSymType::Terminal | CSymbolSymType::Eofsymbol + ) { + symbol.m_first.add_in(symbol.clone())?; + } + Ok(symbol) + } + + pub fn new_with_lexer(lexer: Lexer) -> Result { + let mut symbol = Self::placeholder(); + symbol.text.clone_from(&lexer.yytext); + Ok(symbol) + } + + pub fn new_with_symbols_gen(symbols: SymbolsGen) -> Result { + let mut symbol = Self::placeholder(); + symbol.m_parser = Some(Arc::new(symbols)); + Ok(symbol) + } + + pub fn add_follow(&mut self, map: SymbolSet) -> Result { + let before = self.m_follow.count(); + self.m_follow.add_with_symbol_set(map)?; + Ok(self.m_follow.count() != before) + } + + pub fn add_start_items(&self, mut state: ParseState, follows: SymbolSet) -> Result<(), Error> { + for production in self.registered_productions()? { + let mut item = ProdItem::new_with_production_int32(production, 0)?; + item.follow = Some(follows.clone()); + state.maybe_add(item)?; + } + Ok(()) + } + + pub fn is_nullable(&self) -> Result { + Ok(self.symbol_ref().is_nullable(&mut BTreeSet::new())) + } + + pub fn is_terminal(&self) -> Result { + Ok(matches!( + self.m_symtype, + CSymbolSymType::Terminal | CSymbolSymType::Eofsymbol + )) + } + + pub fn matches(&self, value: String) -> Result { + Ok(self.text == value) + } + + pub fn resolve(&self) -> Result { + Ok(self.clone()) + } + + pub fn serialise(o: Object, _serializer: Serialiser) -> Result { + let _ = o; + Err(Error::InvalidOperation) + } + + pub fn shift_precedence( + &self, + production: Production, + _state: ParseState, + ) -> Result { + let Some(precedence) = self.m_prec.as_deref() else { + return Ok(PrecedencePrecType::Left); + }; + if precedence.m_type == PrecedencePrecType::Nonassoc { + return Ok(PrecedencePrecType::Nonassoc); + } + let comparison = + Precedence::check_with_c_symbol_production_int32(self.clone(), production, 0)?; + match comparison.cmp(&0) { + std::cmp::Ordering::Greater => Ok(PrecedencePrecType::Left), + std::cmp::Ordering::Less => Ok(PrecedencePrecType::Right), + std::cmp::Ordering::Equal => Ok(precedence.m_type), + } + } + + pub fn type_str(&self) -> Result { + Ok(self.text.clone()) + } + + #[must_use] + pub fn yytext(&self) -> &str { + &self.text + } + + fn symbol_ref(&self) -> SymbolRef { + SymbolRef { + name: self.text.clone(), + number: self.m_yynum, + symbol_type: self.m_symtype, + productions: Arc::downgrade(&self.productions), + } + } + + fn register_production( + &mut self, + production: Arc>, + ) -> Result<(), Error> { + let mut productions = self + .productions + .lock() + .map_err(|_| Error::InvalidOperation)?; + if !productions + .iter() + .any(|candidate| Arc::ptr_eq(candidate, &production)) + { + productions.push(production); + } + Ok(()) + } + + fn registered_productions(&self) -> Result, Error> { + self.productions + .lock() + .map_err(|_| Error::InvalidOperation)? + .iter() + .map(|record| Production::from_record(self.clone(), record.clone())) + .collect() + } +} + +/// Deduplicated deterministic grammar-symbol set. +#[derive(Clone)] +pub struct SymbolSet { + pub m_next: Option>, + pub m_symbols: Option>, + members: Arc>>, +} + +impl fmt::Debug for SymbolSet { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + let members = self.members.lock().map_err(|_| fmt::Error)?; + formatter.debug_set().entries(members.keys()).finish() + } +} + +impl SymbolSet { + fn empty() -> Self { + Self { + m_next: None, + m_symbols: None, + members: Arc::new(Mutex::new(BTreeMap::new())), + } + } + + /// Creates an empty set independent of generator state. + #[must_use] + pub fn native() -> Self { + Self::empty() + } + + pub fn new_with_symbol_set(set: SymbolSet) -> Result { + Ok(set) + } + + pub fn new_with_symbols_gen(symbols: SymbolsGen) -> Result { + Ok(Self { + m_symbols: Some(Arc::new(symbols)), + ..Self::empty() + }) + } + + pub fn add_with_symbol_set(&mut self, set: SymbolSet) -> Result<(), Error> { + let symbols = set.values()?; + for symbol in symbols { + self.add_in(symbol)?; + } + Ok(()) + } + + pub fn add_in(&mut self, symbol: CSymbol) -> Result<(), Error> { + self.members + .lock() + .map_err(|_| Error::InvalidOperation)? + .insert((symbol.m_yynum, symbol.text.clone()), symbol.symbol_ref()); + Ok(()) + } + + pub fn check_in(&mut self, symbol: CSymbol) -> Result { + let key = (symbol.m_yynum, symbol.text.clone()); + let mut members = self.members.lock().map_err(|_| Error::InvalidOperation)?; + if members.contains_key(&key) { + return Ok(false); + } + members.insert(key, symbol.symbol_ref()); + Ok(true) + } + + pub fn contains(&self, symbol: CSymbol) -> Result { + Ok(self + .members + .lock() + .map_err(|_| Error::InvalidOperation)? + .contains_key(&(symbol.m_yynum, symbol.text.clone()))) + } + + pub fn get_enumerator(&self) -> Result { + Ok(IDictionaryEnumerator) + } + + pub fn print(&self) -> Result<(), Error> { + println!( + "[{}]", + self.members + .lock() + .map_err(|_| Error::InvalidOperation)? + .values() + .map(|symbol| symbol.name.replace('\n', "\\n")) + .collect::>() + .join(",") + ); + Ok(()) + } + + pub fn resolve(&self) -> Result { + Ok(self.clone()) + } + + pub fn add_with_symbol_set_symbol_set(mut left: SymbolSet, right: SymbolSet) -> SymbolSet { + let _ = left.add_with_symbol_set(right); + left + } + + #[must_use] + pub fn count(&self) -> i32 { + self.members.lock().map_or(0, |members| { + i32::try_from(members.len()).unwrap_or(i32::MAX) + }) + } + + #[must_use] + pub const fn keys(&self) -> ICollection { + ICollection + } + + pub fn values(&self) -> Result, Error> { + Ok(self + .members + .lock() + .map_err(|_| Error::InvalidOperation)? + .values() + .map(SymbolRef::to_symbol) + .collect()) + } +} + +/// Mapped precedence declaration kinds. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(i32)] +pub enum PrecedencePrecType { + Left = 0, + Right = 1, + Nonassoc = 2, + Before = 3, + After = 4, +} + +/// Linked compatibility precedence declaration. +#[derive(Clone, Debug)] +pub struct Precedence { + pub m_next: Option>, + pub m_prec: i32, + pub m_type: PrecedencePrecType, +} + +impl Precedence { + pub fn new( + type_: PrecedencePrecType, + precedence: i32, + next: Precedence, + ) -> Result { + if precedence < 0 { + return Err(Error::Argument); + } + Ok(Self { + m_next: Some(Box::new(next)), + m_prec: precedence, + m_type: type_, + }) + } + + /// Constructs the first declaration in a linked precedence list. + pub fn first(type_: PrecedencePrecType, precedence: i32) -> Result { + if precedence < 0 { + return Err(Error::Argument); + } + Ok(Self { + m_next: None, + m_prec: precedence, + m_type: type_, + }) + } + + pub fn check_with_c_symbol_production_int32( + symbol: CSymbol, + production: Production, + depth: i32, + ) -> Result { + if depth < 0 { + return Err(Error::Argument); + } + let Some(precedence) = symbol.m_prec.as_deref() else { + return Ok(0); + }; + let after = Self::check_type(Some(precedence), PrecedencePrecType::After); + let infix = Self::check_type(Some(precedence), PrecedencePrecType::Left); + Ok(after.max(infix) - production.m_prec) + } + + pub fn check_with_precedence_prec_type_int32( + precedence: Precedence, + type_: PrecedencePrecType, + depth: i32, + ) -> Result { + if depth < 0 { + return Err(Error::Argument); + } + Ok(Self::check_exact(Some(&precedence), type_)) + } + + pub fn check_with_production(mut production: Production) -> Result<(), Error> { + let mut count = production.rhs.len(); + while count > 1 + && matches!( + production.rhs[count - 1].m_symtype, + CSymbolSymType::Oldaction | CSymbolSymType::Simpleaction + ) + { + count -= 1; + } + match count { + 2 if production.rhs[0].m_yynum == production.m_lhs.m_yynum => { + let precedence = Self::check_exact( + production.rhs[1].m_prec.as_deref(), + PrecedencePrecType::After, + ); + production.set_precedence(precedence)?; + } + 2 if production.rhs[1].m_yynum == production.m_lhs.m_yynum => { + let precedence = Self::check_exact( + production.rhs[0].m_prec.as_deref(), + PrecedencePrecType::Before, + ); + production.set_precedence(precedence)?; + } + 3 if production.rhs[2].m_yynum == production.m_lhs.m_yynum => { + let precedence = Self::check_type( + production.rhs[1].m_prec.as_deref(), + PrecedencePrecType::Left, + ); + production.set_precedence(precedence)?; + } + _ => {} + } + Ok(()) + } + + fn check_exact(mut value: Option<&Precedence>, type_: PrecedencePrecType) -> i32 { + while let Some(precedence) = value { + if precedence.m_type == type_ { + return precedence.m_prec; + } + value = precedence.m_next.as_deref(); + } + 0 + } + + fn check_type(mut value: Option<&Precedence>, type_: PrecedencePrecType) -> i32 { + while let Some(precedence) = value { + if precedence.m_type == type_ + || (precedence.m_type as i32 <= PrecedencePrecType::Nonassoc as i32 + && type_ as i32 <= PrecedencePrecType::Nonassoc as i32) + { + return precedence.m_prec; + } + value = precedence.m_next.as_deref(); + } + 0 + } +} + +/// Compatibility production with a typed native right-hand side. +#[derive(Clone)] +pub struct Production { + pub m_actions_only: bool, + pub m_alias: Hashtable, + pub m_lhs: CSymbol, + pub m_pno: i32, + pub m_prec: i32, + pub m_rhs: ObjectList, + rhs: Vec, + record: Arc>, +} + +impl fmt::Debug for Production { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("Production") + .field("number", &self.m_pno) + .field("lhs", &self.m_lhs) + .field("rhs", &self.rhs) + .field("precedence", &self.m_prec) + .field("actions_only", &self.m_actions_only) + .field("aliases", &self.m_alias) + .field("mapped_rhs", &self.m_rhs) + .finish() + } +} + +impl Production { + pub fn new_with_symbols_gen(symbols: SymbolsGen) -> Result { + let number = symbols.pno; + let mut lhs = CSymbol::placeholder(); + lhs.m_parser = Some(Arc::new(symbols)); + Self::empty(number, lhs) + } + + pub fn new_with_symbols_gen_c_symbol(symbols: SymbolsGen, lhs: CSymbol) -> Result { + Self::empty(symbols.pno, lhs) + } + + /// Creates a production independent of the generator facade. + pub fn native(number: i32, lhs: CSymbol, rhs: Vec) -> Result { + if number < 0 || lhs.is_terminal()? { + return Err(Error::Argument); + } + let mut result = Self::empty(number, lhs)?; + for symbol in rhs { + result.add_to_rhs(symbol)?; + } + Ok(result) + } + + fn empty(number: i32, mut lhs: CSymbol) -> Result { + let record = Arc::new(Mutex::new(ProductionRecord { + number, + actions_only: true, + precedence: 0, + rhs: Vec::new(), + })); + lhs.register_production(record.clone())?; + Ok(Self { + m_actions_only: true, + m_alias: Hashtable::default(), + m_lhs: lhs, + m_pno: number, + m_prec: 0, + m_rhs: ObjectList::default(), + rhs: Vec::new(), + record, + }) + } + + fn from_record(lhs: CSymbol, record: Arc>) -> Result { + let value = record.lock().map_err(|_| Error::InvalidOperation)?; + let rhs = value + .rhs + .iter() + .map(SymbolRef::to_symbol) + .collect::>(); + let mut mapped_rhs = ObjectList::default(); + for symbol in &rhs { + let mut metadata = std::collections::HashMap::new(); + metadata.insert("name".to_owned(), Object::String(symbol.text.clone())); + metadata.insert("number".to_owned(), Object::Integer(symbol.m_yynum)); + mapped_rhs.add(Object::Map(metadata))?; + } + Ok(Self { + m_actions_only: value.actions_only, + m_alias: Hashtable::default(), + m_lhs: lhs, + m_pno: value.number, + m_prec: value.precedence, + m_rhs: mapped_rhs, + rhs, + record: record.clone(), + }) + } + + pub fn add_first(&self, symbol: CSymbol, position: i32) -> Result<(), Error> { + let position = usize::try_from(position).map_err(|_| Error::Argument)?; + if position > self.rhs.len() { + return Err(Error::IndexOutOfRange); + } + let mut merged = symbol.m_follow.clone(); + for item in &self.rhs[position..] { + merged.add_with_symbol_set(item.m_first.clone())?; + if !item.is_nullable()? { + break; + } + } + Ok(()) + } + + pub fn add_to_rhs(&mut self, symbol: CSymbol) -> Result<(), Error> { + self.m_actions_only &= matches!( + symbol.m_symtype, + CSymbolSymType::Oldaction | CSymbolSymType::Simpleaction + ); + let mut metadata = std::collections::HashMap::new(); + metadata.insert("name".to_owned(), Object::String(symbol.text.clone())); + metadata.insert("number".to_owned(), Object::Integer(symbol.m_yynum)); + self.m_rhs.add(Object::Map(metadata))?; + self.rhs.push(symbol); + let mut record = self.record.lock().map_err(|_| Error::InvalidOperation)?; + record.actions_only = self.m_actions_only; + record.rhs = self.rhs.iter().map(CSymbol::symbol_ref).collect(); + Ok(()) + } + + pub fn could_be_empty(&self, position: i32) -> Result { + let position = usize::try_from(position).map_err(|_| Error::Argument)?; + if position > self.rhs.len() { + return Err(Error::IndexOutOfRange); + } + for symbol in &self.rhs[position..] { + if !symbol.is_nullable()? { + return Ok(false); + } + } + Ok(true) + } + + pub fn prefix(&self, length: i32) -> Result, Error> { + let length = usize::try_from(length).map_err(|_| Error::Argument)?; + if length > self.rhs.len() { + return Err(Error::IndexOutOfRange); + } + Ok(self.rhs[..length].to_vec()) + } + + pub fn serialise(o: Object, _serializer: Serialiser) -> Result { + let _ = o; + Err(Error::InvalidOperation) + } + + pub fn stack_ref(&self, text: &mut String, _character: i32, index: i32) -> Result<(), Error> { + let index = usize::try_from(index.checked_sub(1).ok_or(Error::Argument)?) + .map_err(|_| Error::Argument)?; + let symbol = self.rhs.get(index).ok_or(Error::IndexOutOfRange)?; + let depth = self + .rhs + .len() + .checked_sub(index + 2) + .ok_or(Error::IndexOutOfRange)?; + write!( + text, + "\n\t(({})(yyq.StackAt({depth}).m_value))\n\t", + symbol.type_str()? + ) + .map_err(|_| Error::InvalidOperation)?; + Ok(()) + } + + fn set_precedence(&mut self, precedence: i32) -> Result<(), Error> { + self.m_prec = precedence; + self.record + .lock() + .map_err(|_| Error::InvalidOperation)? + .precedence = precedence; + Ok(()) + } +} + +/// One dotted production used while constructing LR item sets. +#[derive(Clone, Debug)] +pub struct ProdItem { + pub m_done: bool, + pub m_pos: i32, + pub m_prod: Production, + follow: Option, +} + +impl ProdItem { + pub fn new_with_constructor() -> Result { + Ok(Self { + m_done: false, + m_pos: 0, + m_prod: Production::empty(0, CSymbol::placeholder())?, + follow: None, + }) + } + + pub fn new_with_production_int32(production: Production, position: i32) -> Result { + if position < 0 + || usize::try_from(position).map_or(true, |value| value > production.rhs.len()) + { + return Err(Error::Argument); + } + Ok(Self { + m_done: false, + m_pos: position, + m_prod: production, + follow: None, + }) + } + + pub fn first_of_rest(&self, symbols: SymbolsGen) -> Result { + if let Some(follow) = &self.follow { + return Ok(follow.clone()); + } + let mut result = SymbolSet::new_with_symbols_gen(symbols)?; + let start = usize::try_from(self.m_pos + 1).map_err(|_| Error::Argument)?; + let mut nullable = true; + for symbol in self.m_prod.rhs.get(start..).unwrap_or_default() { + result.add_with_symbol_set(symbol.m_first.clone())?; + if !symbol.is_nullable()? { + nullable = false; + break; + } + } + if nullable { + result.add_with_symbol_set(self.m_prod.m_lhs.m_follow.clone())?; + } + Ok(result) + } + + pub fn is_reducing_action(&self) -> Result { + let position = usize::try_from(self.m_pos).map_err(|_| Error::Argument)?; + Ok(position + 1 == self.m_prod.rhs.len() + && self.m_prod.rhs.get(position).is_some_and(|symbol| { + matches!( + symbol.m_symtype, + CSymbolSymType::Oldaction | CSymbolSymType::Simpleaction + ) + })) + } + + pub fn next(&self) -> Result { + let position = usize::try_from(self.m_pos).map_err(|_| Error::Argument)?; + self.m_prod + .rhs + .get(position) + .cloned() + .ok_or(Error::IndexOutOfRange) + } + + pub fn print(&self) -> Result<(), Error> { + let mut rhs = Vec::new(); + for (index, symbol) in self.m_prod.rhs.iter().enumerate() { + if index == usize::try_from(self.m_pos).unwrap_or(usize::MAX) { + rhs.push("_".to_owned()); + } + rhs.push(symbol.text.replace('\n', "\\n")); + } + if usize::try_from(self.m_pos).ok() == Some(self.m_prod.rhs.len()) { + rhs.push("_".to_owned()); + } + println!( + "{} {} : {}", + self.m_prod.m_pno, + self.m_prod.m_lhs.text, + rhs.join(" ") + ); + Ok(()) + } +} + +/// Quoted grammar literal with deterministic C-style escape decoding. +#[derive(Clone, Debug)] +pub struct Literal { + symbol: CSymbol, +} + +impl Literal { + pub fn new(symbols: SymbolsGen) -> Result { + let mut symbol = CSymbol::new_with_symbols_gen(symbols)?; + symbol.m_symtype = CSymbolSymType::Terminal; + Ok(Self { symbol }) + } + + /// Creates and decodes a quoted literal without generator state. + pub fn native(text: &str, number: i32) -> Result { + let decoded = decode_grammar_literal(text)?; + Ok(Self { + symbol: CSymbol::native(decoded, number, CSymbolSymType::Terminal)?, + }) + } + + pub fn could_start(&self, nonterminal: CSymbol) -> Result { + nonterminal.m_first.contains(self.symbol.clone()) + } + + pub fn resolve(&self) -> Result { + Ok(self.symbol.clone()) + } + + pub fn serialise(o: Object, _serializer: Serialiser) -> Result { + let _ = o; + Err(Error::InvalidOperation) + } + + pub fn type_str(&self) -> Result { + Ok("TOKEN".to_owned()) + } +} + +fn decode_grammar_literal(text: &str) -> Result { + let units = text.chars().collect::>(); + if units.len() < 2 || units.first() != units.last() || !matches!(units[0], '\'' | '"') { + return Err(Error::Parse { + position: 0, + context: "grammar literal must be quoted", + }); + } + let mut output = String::new(); + let mut index = 1; + while index + 1 < units.len() { + let mut value = units[index]; + if value == '\\' { + index += 1; + if index + 1 >= units.len() { + return Err(Error::Parse { + position: index, + context: "grammar literal has a trailing escape", + }); + } + value = units[index]; + if ('0'..='7').contains(&value) { + let start = index; + let mut number = 0u32; + let mut digits = 0; + while index + 1 < units.len() && digits < 3 && ('0'..='7').contains(&units[index]) { + number = number * 8 + units[index].to_digit(8).unwrap_or(0); + index += 1; + digits += 1; + } + let character = char::from_u32(number).ok_or(Error::Parse { + position: start, + context: "grammar literal escape is invalid", + })?; + output.push(character); + continue; + } + value = match value { + 'n' => '\n', + 'r' => '\r', + 't' => '\t', + other => other, + }; + } + output.push(value); + index += 1; + } + Ok(output) +} + +/// Lightweight mapped parse-state descriptor. +#[derive(Clone)] +pub struct ParseState { + pub m_accessing_symbol: CSymbol, + pub m_sgen: Option>, + pub m_state: i32, + pub m_transitions: Hashtable, + items: Arc>>, +} + +impl fmt::Debug for ParseState { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("ParseState") + .field("state", &self.m_state) + .field("accessing_symbol", &self.m_accessing_symbol) + .field( + "items", + &self + .items + .lock() + .map_or_else(|_| Vec::new(), |items| items.keys().copied().collect()), + ) + .finish() + } +} + +impl ParseState { + fn numbered(state: i32) -> Self { + Self { + m_accessing_symbol: CSymbol::placeholder(), + m_sgen: None, + m_state: state, + m_transitions: Hashtable::default(), + items: Arc::new(Mutex::new(BTreeMap::new())), + } + } + + pub fn new(symbols: SymbolsGen, accessing: CSymbol) -> Result { + Ok(Self { + m_accessing_symbol: accessing, + m_sgen: Some(Arc::new(symbols)), + ..Self::numbered(0) + }) + } + + pub fn accessor(&self, symbols: Vec) -> Result { + Ok(symbols + .last() + .is_some_and(|symbol| symbol.m_yynum == self.m_accessing_symbol.m_yynum)) + } + + pub fn add_entries(&self) -> Result<(), Error> { + Err(Error::InvalidOperation) + } + + pub fn check_closure(&mut self, item: ProdItem) -> Result<(), Error> { + self.maybe_add(item) + } + + pub fn check_exists(&self) -> Result { + Ok(self.clone()) + } + + pub fn closure(&mut self) -> Result<(), Error> { + let mut pending = self + .items + .lock() + .map_err(|_| Error::InvalidOperation)? + .values() + .cloned() + .collect::>(); + while let Some(item) = pending.pop_front() { + let Ok(symbol) = item.next() else { + continue; + }; + for production in symbol.registered_productions()? { + let candidate = ProdItem::new_with_production_int32(production, 0)?; + let key = (candidate.m_prod.m_pno, candidate.m_pos); + let mut items = self.items.lock().map_err(|_| Error::InvalidOperation)?; + if let std::collections::btree_map::Entry::Vacant(entry) = items.entry(key) { + entry.insert(candidate.clone()); + pending.push_back(candidate); + } + } + } + Ok(()) + } + + pub fn get_transition(&self, symbol: CSymbol) -> Result { + let Some(value) = self + .m_transitions + .0 + .get(&Object::String(symbol.text.clone())) + else { + return Err(Error::InvalidOperation); + }; + value + .downcast_ref::() + .cloned() + .ok_or(Error::InvalidOperation) + } + + pub fn lookback(&self, production: Production, state: ParseState) -> Result { + Ok(self.m_state == state.m_state + && self + .items + .lock() + .map_err(|_| Error::InvalidOperation)? + .contains_key(&( + production.m_pno, + i32::try_from(production.rhs.len()).unwrap_or(i32::MAX), + ))) + } + + pub fn maybe_add(&mut self, item: ProdItem) -> Result<(), Error> { + self.items + .lock() + .map_err(|_| Error::InvalidOperation)? + .entry((item.m_prod.m_pno, item.m_pos)) + .or_insert(item); + Ok(()) + } + + pub fn print(&self) -> Result<(), Error> { + println!("{}", self.stable_text()); + Ok(()) + } + + pub fn print0(&self) -> Result<(), Error> { + self.print() + } + + pub fn reduce_states(&self) -> Result<(), Error> { + Err(Error::InvalidOperation) + } + + pub fn same_as(&self, other: ParseState) -> Result { + let left = self + .items + .lock() + .map_err(|_| Error::InvalidOperation)? + .keys() + .copied() + .collect::>(); + let right = other + .items + .lock() + .map_err(|_| Error::InvalidOperation)? + .keys() + .copied() + .collect::>(); + Ok(left == right) + } + + pub fn serialise(o: Object, _serializer: Serialiser) -> Result { + let _ = o; + Err(Error::InvalidOperation) + } + + fn stable_text(&self) -> String { + let item_count = self.items.lock().map_or(0, |items| items.len()); + format!( + "state {} items {} transitions {}", + self.m_state, + item_count, + self.m_transitions.0.len() + ) + } +} + +/// Parser table metadata for one symbol. +#[derive(Clone, Debug)] +pub struct ParsingInfo { + pub m_name: String, + pub m_parsetable: Hashtable, + pub m_yynum: i32, +} + +impl ParsingInfo { + pub fn new(name: String, number: i32) -> Result { + if name.is_empty() || number < ERROR_TOKEN { + return Err(Error::Argument); + } + Ok(Self { + m_name: name, + m_parsetable: Hashtable::default(), + m_yynum: number, + }) + } + + pub fn serialise(o: Object, _serializer: Serialiser) -> Result { + let _ = o; + Err(Error::InvalidOperation) + } +} + +/// Executable parser table corresponding to the mapped `YyParser` concept. +#[derive(Clone)] +pub struct YyParser { + pub eof_symbol: CSymbol, + pub special: CSymbol, + pub arr: Vec, + pub erh: crate::ErrorHandler, + pub literals: Hashtable, + pub m_accept: ParseState, + pub m_concrete: bool, + pub m_start_symbol: CSymbol, + pub m_states: Hashtable, + pub symbol_info: Hashtable, + pub symbols: Hashtable, + pub types: Hashtable, + machine: Option>, +} + +impl fmt::Debug for YyParser { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("YyParser") + .field("start", &self.start_symbol()) + .field( + "states", + &self + .machine + .as_ref() + .map_or(0, |machine| machine.states.len()), + ) + .finish() + } +} + +impl YyParser { + pub fn new() -> Result { + Ok(Self::empty()) + } + + fn empty() -> Self { + Self { + eof_symbol: CSymbol::native("EOF", 2, CSymbolSymType::Eofsymbol) + .unwrap_or_else(|_| CSymbol::placeholder()), + special: CSymbol::native("S'", 0, CSymbolSymType::Nonterminal) + .unwrap_or_else(|_| CSymbol::placeholder()), + arr: Vec::new(), + erh: crate::ErrorHandler::default(), + literals: Hashtable::default(), + m_accept: ParseState::numbered(0), + m_concrete: false, + m_start_symbol: CSymbol::placeholder(), + m_states: Hashtable::default(), + symbol_info: Hashtable::default(), + symbols: Hashtable::default(), + types: Hashtable::default(), + machine: None, + } + } + + fn from_machine(machine: ParserMachine) -> Self { + let mut parser = Self::empty(); + let start = machine + .symbols + .get(&machine.start) + .cloned() + .unwrap_or(GrammarSymbol { + name: "".to_owned(), + number: machine.start, + terminal: false, + }); + parser.m_start_symbol = CSymbol::native( + start.name.clone(), + start.number, + CSymbolSymType::Nonterminal, + ) + .unwrap_or_else(|_| CSymbol::placeholder()); + let eof = machine + .symbols + .get(&machine.eof) + .cloned() + .unwrap_or(GrammarSymbol { + name: "EOF".to_owned(), + number: machine.eof, + terminal: true, + }); + parser.eof_symbol = CSymbol::native(eof.name, eof.number, CSymbolSymType::Eofsymbol) + .unwrap_or_else(|_| CSymbol::placeholder()); + parser.m_accept = ParseState::numbered( + machine + .actions + .iter() + .find_map(|((state, token), action)| { + (*token == machine.eof && *action == TableAction::Accept) + .then_some(i32::try_from(*state).unwrap_or(i32::MAX)) + }) + .unwrap_or(0), + ); + for symbol in machine.symbols.values() { + parser.symbols.0.insert( + Object::String(symbol.name.clone()), + Object::Integer(symbol.number), + ); + let mut states = std::collections::HashMap::new(); + for ((state, number), action) in &machine.actions { + if *number == symbol.number { + let mut metadata = std::collections::HashMap::new(); + metadata.insert("priority".to_owned(), Object::Integer(0)); + metadata.insert( + "action".to_owned(), + Object::String(ParserMachine::action_text(*action)), + ); + states.insert(state.to_string(), Object::Map(metadata)); + } + } + parser + .symbol_info + .0 + .insert(Object::Integer(symbol.number), Object::Map(states)); + } + for (literal, number) in &machine.literals { + parser + .literals + .0 + .insert(Object::String(literal.clone()), Object::Integer(*number)); + } + parser.machine = Some(Arc::new(machine)); + parser + } + + pub fn action(&self, _parser: Parser, symbol: SYMBOL, _action: i32) -> Result { + Ok(symbol.m_dollar) + } + + pub fn class_init(&mut self, _symbols: SymbolsGen) -> Result<(), Error> { + self.special = CSymbol::native("S'", 0, CSymbolSymType::Nonterminal)?; + self.eof_symbol = CSymbol::native("EOF", 2, CSymbolSymType::Eofsymbol)?; + Ok(()) + } + + pub fn emit(&self, mut output: Box) -> Result<(), Error> { + let machine = self.machine.as_deref().ok_or(Error::InvalidOperation)?; + output + .write_all(machine.stable_description().as_bytes()) + .map_err(|_| Error::InvalidOperation)?; + output.write_all(b"\n").map_err(|_| Error::InvalidOperation) + } + + pub fn get_eof(&mut self, _lexer: Lexer) -> Result<(), Error> { + if self.eof_symbol.m_yynum < 0 { + let eof = self.machine.as_deref().map_or(2, |machine| machine.eof); + self.eof_symbol = CSymbol::native("EOF", eof, CSymbolSymType::Eofsymbol)?; + } + Ok(()) + } + + pub fn get_parser(&self, _lexer: Lexer) -> Result<(), Error> { + self.machine + .as_ref() + .map(|_| ()) + .ok_or(Error::InvalidOperation) + } + + pub fn get_symbol_info(&mut self, name: String, number: i32) -> Result { + let mut info = ParsingInfo::new(name, number)?; + if let Some(Object::Map(states)) = self.symbol_info.0.get(&Object::Integer(number)) { + for (state, value) in states { + info.m_parsetable + .0 + .insert(Object::String(state.clone()), value.clone()); + } + } + Ok(info) + } + + pub fn print_transitions(&self, _function: Func, suffix: String) -> Result<(), Error> { + let machine = self.machine.as_deref().ok_or(Error::InvalidOperation)?; + for ((state, symbol), target) in &machine.gotos { + println!("{state} --{symbol}--> {target}{suffix}"); + } + Ok(()) + } + + pub fn transitions(&self, _builder: Builder) -> Result<(), Error> { + Err(Error::InvalidOperation) + } + + #[must_use] + pub fn start_symbol(&self) -> String { + if self.m_start_symbol.text.is_empty() { + "".to_owned() + } else { + self.m_start_symbol.text.clone() + } + } + + pub fn set_start_symbol(&mut self, value: String) { + if let Some(machine) = &self.machine + && let Some(symbol) = machine + .symbols + .values() + .find(|symbol| symbol.name == value && !symbol.terminal) + && let Ok(native) = CSymbol::native( + symbol.name.clone(), + symbol.number, + CSymbolSymType::Nonterminal, + ) + { + self.m_start_symbol = native; + } + } + + pub fn conflicts(&self) -> &[ParserConflict] { + self.machine + .as_deref() + .map_or(&[], |machine| machine.conflicts.as_slice()) + } + + pub(crate) fn lookup_entry( + &self, + number: i32, + state: i32, + ) -> Result, Error> { + let state = usize::try_from(state).map_err(|_| Error::Argument)?; + let Some(machine) = &self.machine else { + return Ok(None); + }; + Ok(machine + .actions + .get(&(state, number)) + .copied() + .map(ParserEntry::from_table_action)) + } +} + +#[derive(Clone, Debug, Default)] +struct ParserRuntime { + stack: Vec, + ungot: Option, + diagnostics: Vec, + recovered: usize, +} + +/// Bounded table-driven parser retaining the mapped C# entry points. +#[derive(Clone)] +pub struct Parser { + pub m_debug: bool, + pub m_lexer: Lexer, + pub m_stkdebug: bool, + pub m_symbols: YyParser, + runtime: Arc>, +} + +impl fmt::Debug for Parser { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("Parser") + .field("debug", &self.m_debug) + .field("stack_debug", &self.m_stkdebug) + .field("symbols", &self.m_symbols) + .finish() + } +} + +impl Parser { + pub fn new(symbols: YyParser, lexer: Lexer) -> Result { + if symbols.machine.is_none() { + return Err(Error::InvalidOperation); + } + Ok(Self { + m_debug: false, + m_lexer: lexer, + m_stkdebug: false, + m_symbols: symbols, + runtime: Arc::new(Mutex::new(ParserRuntime::default())), + }) + } + + pub fn error(&mut self, number: i32, symbol: SYMBOL, message: String) -> Result<(), Error> { + let position = usize::try_from(symbol.pos_with_field).unwrap_or(0); + let location = self + .m_lexer + .source_line_info(symbol.pos_with_field) + .unwrap_or_else(|_| SourceLineInfo::default()); + self.record(Diagnostic { + code: number, + category: DiagnosticCategory::Syntax, + severity: DiagnosticSeverity::Error, + message, + location, + input: symbol.to_string(), + })?; + Err(Error::Parse { + position, + context: "parser semantic action reported an error", + }) + } + + pub fn next_sym(&mut self) -> Result { + if let Some(symbol) = self.runtime_lock()?.ungot.take() { + return Ok(symbol); + } + match self.m_lexer.next_token()? { + Some(token) => Ok(self.symbol_from_token(token)), + None => Ok(SYMBOL::parser_symbol( + self.m_symbols.eof_symbol.text.clone(), + self.m_symbols.eof_symbol.m_yynum, + "EOF".to_owned(), + self.m_lexer.yypos(), + Object::Undefined, + ObjectList::default(), + )), + } + } + + pub fn parse_with_cs_reader(&mut self, input: CsReader) -> Result { + self.m_lexer.start_with_cs_reader(input)?; + self.parse_started() + } + + pub fn parse_with_stream_reader(&mut self, input: StreamReader) -> Result { + self.m_lexer.start_with_stream_reader(input)?; + self.parse_started() + } + + pub fn parse_with_string(&mut self, input: String) -> Result { + self.m_lexer.start_with_string(input)?; + self.parse_started() + } + + pub fn stack_at(&self, index: i32) -> Result { + let index = usize::try_from(index).map_err(|_| Error::Argument)?; + let runtime = self.runtime_lock()?; + let position = runtime + .stack + .len() + .checked_sub(index + 1) + .ok_or(Error::IndexOutOfRange)?; + runtime + .stack + .get(position) + .cloned() + .ok_or(Error::IndexOutOfRange) + } + + pub fn diagnostics(&self) -> Result, Error> { + Ok(self.runtime_lock()?.diagnostics.clone()) + } + + fn parse_started(&mut self) -> Result { + let machine = self + .m_symbols + .machine + .clone() + .ok_or(Error::InvalidOperation)?; + { + let mut runtime = self.runtime_lock()?; + runtime.stack.clear(); + runtime.ungot = None; + runtime.diagnostics.clear(); + runtime.recovered = 0; + } + let mut states = vec![0usize]; + let mut nodes = Vec::::new(); + let mut token = self.m_lexer.next_token()?; + let mut steps = 0usize; + loop { + steps = steps.checked_add(1).ok_or(Error::IndexOutOfRange)?; + if steps > MAX_PARSER_STEPS { + self.record_limit_diagnostic(token.as_ref(), "parser step limit exceeded")?; + return Err(Error::Parse { + position: token + .as_ref() + .map_or(0, |value| usize::try_from(value.pos).unwrap_or(0)), + context: "parser step limit exceeded", + }); + } + if states.len() > MAX_PARSER_STACK { + self.record_limit_diagnostic(token.as_ref(), "parser stack limit exceeded")?; + return Err(Error::Parse { + position: token + .as_ref() + .map_or(0, |value| usize::try_from(value.pos).unwrap_or(0)), + context: "parser stack limit exceeded", + }); + } + let raw_number = token.as_ref().map_or(machine.eof, TOKEN::yynum); + let number = if raw_number == 1 { + token + .as_ref() + .and_then(|value| machine.literals.get(&value.yytext())) + .copied() + .unwrap_or(raw_number) + } else { + raw_number + }; + let state = *states.last().ok_or(Error::InvalidOperation)?; + match machine.actions.get(&(state, number)).copied() { + Some(TableAction::Shift(target)) => { + let value = token.take().ok_or(Error::InvalidOperation)?; + nodes.push(ParseTree::token(&value, number)); + states.push(target); + token = self.m_lexer.next_token()?; + } + Some(TableAction::Reduce(production_number)) => { + let production = machine + .productions + .get(production_number + 1) + .ok_or(Error::InvalidOperation)?; + let count = production.rhs.len(); + if count >= states.len() || count > nodes.len() { + return Err(Error::Parse { + position: token + .as_ref() + .map_or(0, |value| usize::try_from(value.pos).unwrap_or(0)), + context: "parser reduction underflow", + }); + } + let children = nodes.split_off(nodes.len() - count); + states.truncate(states.len() - count); + let source = machine + .symbols + .get(&production.lhs) + .ok_or(Error::InvalidOperation)?; + let start = children.first().map_or_else( + || token.as_ref().map_or(0, |value| value.pos), + |value| value.start, + ); + let end = children.last().map_or(start, |value| value.end); + let node = ParseTree { + name: source.name.clone(), + number: source.number, + text: None, + start, + end, + children, + }; + let base = *states.last().ok_or(Error::InvalidOperation)?; + let target = machine.gotos.get(&(base, production.lhs)).copied().ok_or( + Error::Parse { + position: usize::try_from(start).unwrap_or(0), + context: "parser goto table is incomplete", + }, + )?; + nodes.push(node); + states.push(target); + } + Some(TableAction::Accept) => { + let tree = nodes.pop().ok_or(Error::InvalidOperation)?; + let recovered = self.runtime_lock()?.recovered; + let name = if recovered == 0 { + tree.name.clone() + } else { + "recoveredError".to_owned() + }; + let mut kids = ObjectList::default(); + for child in &tree.children { + kids.add(Object::opaque(child.clone()))?; + } + return Ok(SYMBOL::parser_symbol( + name, + tree.number, + String::new(), + tree.start, + Object::opaque(tree), + kids, + )); + } + Some(TableAction::Reject) | None => { + if !self.recover(&machine, &mut states, &mut nodes, &mut token)? { + return Err(Error::Parse { + position: token + .as_ref() + .map_or(0, |value| usize::try_from(value.pos).unwrap_or(0)), + context: "syntax error", + }); + } + } + } + } + } + + fn recover( + &mut self, + machine: &ParserMachine, + states: &mut Vec, + nodes: &mut Vec, + token: &mut Option, + ) -> Result { + let position = token + .as_ref() + .map_or(self.m_lexer.yypos(), |value| value.pos); + let input = token + .as_ref() + .map_or_else(|| "EOF".to_owned(), TOKEN::yytext); + let location = self + .m_lexer + .source_line_info(position) + .unwrap_or_else(|_| SourceLineInfo::default()); + self.record(Diagnostic { + code: 13, + category: DiagnosticCategory::Syntax, + severity: DiagnosticSeverity::Error, + message: "syntax error".to_owned(), + location, + input, + })?; + { + let mut runtime = self.runtime_lock()?; + runtime.recovered += 1; + if runtime.recovered > MAX_RECOVERY_ERRORS { + return Ok(false); + } + } + + let recovery_state = loop { + let state = *states.last().ok_or(Error::InvalidOperation)?; + if let Some(TableAction::Shift(target)) = machine.actions.get(&(state, ERROR_TOKEN)) { + break Some(*target); + } + if states.len() <= 1 { + break None; + } + states.pop(); + nodes.pop(); + }; + let Some(recovery_state) = recovery_state else { + return Ok(false); + }; + nodes.push(ParseTree::error(position)); + states.push(recovery_state); + loop { + let state = *states.last().ok_or(Error::InvalidOperation)?; + let raw_number = token.as_ref().map_or(machine.eof, TOKEN::yynum); + let number = if raw_number == 1 { + token + .as_ref() + .and_then(|value| machine.literals.get(&value.yytext())) + .copied() + .unwrap_or(raw_number) + } else { + raw_number + }; + if machine + .actions + .get(&(state, number)) + .is_some_and(|action| *action != TableAction::Reject) + { + let location = self + .m_lexer + .source_line_info(position) + .unwrap_or_else(|_| SourceLineInfo::default()); + self.record(Diagnostic { + code: 13, + category: DiagnosticCategory::ParserRecovery, + severity: DiagnosticSeverity::Warning, + message: "parser recovered at a valid lookahead".to_owned(), + location, + input: token + .as_ref() + .map_or_else(|| "EOF".to_owned(), TOKEN::yytext), + })?; + return Ok(true); + } + if token.is_none() { + return Ok(false); + } + *token = self.m_lexer.next_token()?; + } + } + + fn symbol_from_token(&self, token: TOKEN) -> SYMBOL { + let number = if token.yynum() == 1 { + self.m_symbols + .machine + .as_deref() + .and_then(|machine| machine.literals.get(&token.yytext())) + .copied() + .unwrap_or(1) + } else { + token.yynum() + }; + SYMBOL::parser_symbol( + token.yyname(), + number, + token.yytext(), + token.pos, + token.yylval(), + ObjectList::default(), + ) + } + + fn record(&mut self, diagnostic: Diagnostic) -> Result<(), Error> { + self.m_symbols.erh.push(diagnostic.clone())?; + self.runtime_lock()?.diagnostics.push(diagnostic); + Ok(()) + } + + fn record_limit_diagnostic( + &mut self, + token: Option<&TOKEN>, + message: &str, + ) -> Result<(), Error> { + let position = token.map_or(self.m_lexer.yypos(), |value| value.pos); + let location = self + .m_lexer + .source_line_info(position) + .unwrap_or_else(|_| SourceLineInfo::default()); + self.record(Diagnostic { + code: 14, + category: DiagnosticCategory::ParserStackLimit, + severity: DiagnosticSeverity::Fatal, + message: message.to_owned(), + location, + input: token.map_or_else(|| "EOF".to_owned(), TOKEN::yytext), + }) + } + + fn runtime_lock(&self) -> Result, Error> { + self.runtime.lock().map_err(|_| Error::InvalidOperation) + } +} + +/// Mapped parser stack entry. Parser clones share their runtime stack. +#[derive(Clone, Debug)] +pub struct ParseStackEntry { + pub m_state: i32, + pub m_value: SYMBOL, + pub yyps: Parser, +} + +impl ParseStackEntry { + pub fn new_with_parser(parser: Parser) -> Result { + Ok(Self { + m_state: 0, + m_value: SYMBOL::parser_symbol( + "Null".to_owned(), + -1, + String::new(), + 0, + Object::Undefined, + ObjectList::default(), + ), + yyps: parser, + }) + } + + pub fn new_with_parser_int32_symbol( + parser: Parser, + state: i32, + value: SYMBOL, + ) -> Result { + if state < 0 { + return Err(Error::Argument); + } + Ok(Self { + m_state: state, + m_value: value, + yyps: parser, + }) + } +} + +/// Semantic action metadata attached to a shift or reduction. +#[derive(Clone, Debug)] +pub struct ParserAction { + pub m_len: i32, + pub m_sym: CSymbol, +} + +impl ParserAction { + pub fn new(_symbols: SymbolsGen) -> Result { + Ok(Self { + m_len: 0, + m_sym: CSymbol::placeholder(), + }) + } + + pub fn native(symbol: CSymbol, length: i32) -> Result { + if length < 0 { + return Err(Error::Argument); + } + Ok(Self { + m_len: length, + m_sym: symbol, + }) + } + + pub fn act_num(&self) -> Result { + Ok(0) + } + + pub fn action(&self, parser: Parser) -> Result { + let source = if self.m_len == 0 { + None + } else { + parser + .stack_at(self.m_len - 1) + .ok() + .map(|entry| entry.m_value) + }; + Ok(SYMBOL::parser_symbol( + self.m_sym.text.clone(), + self.m_sym.m_yynum, + String::new(), + source.as_ref().map_or(0, |symbol| symbol.pos_with_field), + source.map_or(Object::Undefined, |symbol| symbol.m_dollar), + ObjectList::default(), + )) + } + + pub fn is_action(&self) -> Result { + Ok(true) + } + + pub fn print(&self) -> Result<(), Error> { + print!("{}", self.m_sym.text); + Ok(()) + } + + pub fn serialise(o: Object, _serializer: Serialiser) -> Result { + let _ = o; + Err(Error::InvalidOperation) + } +} + +/// Executable action kind stored in one parse-table cell. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum EntryKind { + Error, + Shift(usize), + Reduce(usize), + Accept, + Reject, +} + +/// Base mapped parser entry and native table-cell representation. +#[derive(Clone, Debug)] +pub struct ParserEntry { + pub m_action: Option, + pub m_priority: i32, + kind: EntryKind, +} + +impl Default for ParserEntry { + fn default() -> Self { + Self { + m_action: None, + m_priority: 0, + kind: EntryKind::Error, + } + } +} + +impl ParserEntry { + fn from_table_action(action: TableAction) -> Self { + let kind = match action { + TableAction::Shift(state) => EntryKind::Shift(state), + TableAction::Reduce(production) => EntryKind::Reduce(production), + TableAction::Accept => EntryKind::Accept, + TableAction::Reject => EntryKind::Reject, + }; + Self { + m_action: None, + m_priority: 0, + kind, + } + } + + pub fn is_reduce(&self) -> Result { + Ok(matches!(self.kind, EntryKind::Reduce(_))) + } + + pub fn pass_(&self, top: &mut ParseStackEntry) -> Result<(), Error> { + match self.kind { + EntryKind::Shift(state) => { + top.yyps.runtime_lock()?.stack.push(top.clone()); + top.m_state = i32::try_from(state).map_err(|_| Error::IndexOutOfRange)?; + top.m_value = top.yyps.next_sym()?; + Ok(()) + } + EntryKind::Accept => Ok(()), + EntryKind::Reduce(_) | EntryKind::Reject | EntryKind::Error => { + Err(Error::InvalidOperation) + } + } + } + + pub fn serialise(o: Object, _serializer: Serialiser) -> Result { + let _ = o; + Err(Error::InvalidOperation) + } + + #[must_use] + pub fn str(&self) -> String { + match self.kind { + EntryKind::Error => String::new(), + EntryKind::Shift(state) => format!("shift {state}"), + EntryKind::Reduce(production) => format!("reduce {production}"), + EntryKind::Accept => "accept".to_owned(), + EntryKind::Reject => "nonassociative conflict".to_owned(), + } + } +} + +/// Mapped shift entry. +#[derive(Clone, Debug)] +pub struct ParserShift { + pub m_next: Option>, + action: Option, +} + +impl ParserShift { + pub fn new_with_constructor() -> Result { + Ok(Self { + m_next: None, + action: None, + }) + } + + pub fn new_with_parser_action_parse_state( + action: ParserAction, + next: ParseState, + ) -> Result { + Ok(Self { + m_next: Some(Box::new(next)), + action: Some(action), + }) + } + + pub fn pass_(&self, top: &mut ParseStackEntry) -> Result<(), Error> { + let target = self + .m_next + .as_deref() + .ok_or(Error::InvalidOperation)? + .m_state; + if let Some(action) = &self.action { + let symbol = action.action(top.yyps.clone())?; + top.yyps.runtime_lock()?.stack.push(ParseStackEntry { + m_state: top.m_state, + m_value: symbol, + yyps: top.yyps.clone(), + }); + top.m_state = target; + } else { + top.yyps.runtime_lock()?.stack.push(top.clone()); + top.m_state = target; + top.m_value = top.yyps.next_sym()?; + } + Ok(()) + } + + pub fn serialise(o: Object, _serializer: Serialiser) -> Result { + let _ = o; + Err(Error::InvalidOperation) + } + + #[must_use] + pub fn str(&self) -> String { + self.m_next.as_deref().map_or_else( + || "?? null shift".to_owned(), + |state| format!("shift {}", state.m_state), + ) + } +} + +/// Mapped reduction entry. +#[derive(Clone, Debug)] +pub struct ParserReduce { + pub m_depth: i32, + pub m_look_ahead: SymbolSet, + pub m_prod: Production, + action: ParserAction, +} + +impl ParserReduce { + pub fn new(action: ParserAction, depth: i32, production: Production) -> Result { + if depth < 0 { + return Err(Error::Argument); + } + Ok(Self { + m_depth: depth, + m_look_ahead: SymbolSet::empty(), + m_prod: production, + action, + }) + } + + pub fn build_lookback(&mut self, transition: Transition) -> Result<(), Error> { + self.m_look_ahead = Transition::follow(transition)?; + Ok(()) + } + + pub fn is_reduce(&self) -> Result { + Ok(true) + } + + pub fn pass_(&self, top: &mut ParseStackEntry) -> Result<(), Error> { + let symbol = self.action.action(top.yyps.clone())?; + let depth = usize::try_from(self.m_depth).map_err(|_| Error::Argument)?; + let mut runtime = top.yyps.runtime_lock()?; + if depth > runtime.stack.len() { + return Err(Error::Parse { + position: usize::try_from(top.m_value.pos_with_field).unwrap_or(0), + context: "parser reduction underflow", + }); + } + runtime.ungot = Some(top.m_value.clone()); + for _ in 0..depth { + if let Some(entry) = runtime.stack.pop() { + top.m_state = entry.m_state; + } + } + top.m_value = symbol; + Ok(()) + } + + pub fn serialise(o: Object, _serializer: Serialiser) -> Result { + let _ = o; + Err(Error::InvalidOperation) + } + + #[must_use] + pub fn str(&self) -> String { + format!("reduce {}", self.m_prod.m_pno) + } +} + +/// Old-style numbered semantic action. +#[derive(Clone, Debug)] +pub struct ParserOldAction { + pub m_action: i32, + base: ParserAction, +} + +impl ParserOldAction { + pub fn new(symbols: SymbolsGen) -> Result { + let action = symbols.action; + Ok(Self { + m_action: action, + base: ParserAction::new(symbols)?, + }) + } + + pub fn act_num(&self) -> Result { + Ok(self.m_action) + } + + pub fn action(&self, parser: Parser) -> Result { + let mut symbol = self.base.action(parser.clone())?; + let value = parser + .m_symbols + .clone() + .action(parser, symbol.clone(), self.m_action)?; + if !matches!(value, Object::Undefined) { + symbol.m_dollar = value; + } + Ok(symbol) + } + + pub fn serialise(o: Object, _serializer: Serialiser) -> Result { + let _ = o; + Err(Error::InvalidOperation) + } +} + +/// Simple grammar action that only constructs its declared symbol. +#[derive(Clone, Debug)] +pub struct ParserSimpleAction { + base: ParserAction, +} + +impl ParserSimpleAction { + pub fn new(symbols: SymbolsGen) -> Result { + Ok(Self { + base: ParserAction::new(symbols)?, + }) + } + + pub fn print(&self) -> Result<(), Error> { + print!(" %{}", self.base.m_sym.text); + Ok(()) + } + + pub fn serialise(o: Object, _serializer: Serialiser) -> Result { + let _ = o; + Err(Error::InvalidOperation) + } + + pub fn type_str(&self) -> Result { + Ok(self.base.m_sym.text.clone()) + } +} + +#[derive(Clone, Debug)] +struct TransitionCore { + direct_reads: SymbolSet, + reads: Hashtable, + includes: Hashtable, + follow: SymbolSet, +} + +/// Mapped LALR transition relations backed by shared native relation state. +#[derive(Clone, Debug)] +pub struct Transition { + pub m_a: CSymbol, + pub m_next: ParserShift, + pub m_ps: Box, + pub m_reduce: Hashtable, + pub m_tno: i32, + core: Arc>, +} + +impl Transition { + pub fn new(state: ParseState, symbol: CSymbol) -> Result { + let number = state.m_state; + Ok(Self { + m_a: symbol, + m_next: ParserShift::new_with_constructor()?, + m_ps: Box::new(state), + m_reduce: Hashtable::default(), + m_tno: number, + core: Arc::new(Mutex::new(TransitionCore { + direct_reads: SymbolSet::empty(), + reads: Hashtable::default(), + includes: Hashtable::default(), + follow: SymbolSet::empty(), + })), + }) + } + + pub fn add_to_follow(transition: Transition, set: SymbolSet) -> Result<(), Error> { + transition.core_lock()?.follow.add_with_symbol_set(set) + } + + pub fn add_to_read(transition: Transition, set: SymbolSet) -> Result<(), Error> { + transition + .core_lock()? + .direct_reads + .add_with_symbol_set(set) + } + + pub fn build_dr(transition: Transition) -> Result<(), Error> { + let symbol = transition.m_a.clone(); + if symbol.is_terminal()? { + transition.core_lock()?.direct_reads.add_in(symbol)?; + } + Ok(()) + } + + pub fn build_includes(transition: Transition) -> Result<(), Error> { + let key = Object::Integer(transition.m_tno); + transition + .core_lock()? + .includes + .0 + .insert(key, Object::Boolean(true)); + Ok(()) + } + + pub fn build_la(transition: Transition) -> Result<(), Error> { + let direct = transition.core_lock()?.direct_reads.clone(); + transition.core_lock()?.follow.add_with_symbol_set(direct) + } + + pub fn build_lookback(transition: Transition) -> Result<(), Error> { + Self::build_includes(transition) + } + + pub fn build_parse_table(transition: Transition) -> Result<(), Error> { + let _ = transition; + Err(Error::InvalidOperation) + } + + pub fn build_reads(transition: Transition) -> Result<(), Error> { + let key = Object::Integer(transition.m_tno); + transition + .core_lock()? + .reads + .0 + .insert(key, Object::Boolean(true)); + Ok(()) + } + + pub fn dr(transition: Transition) -> Result { + Ok(transition.core_lock()?.direct_reads.clone()) + } + + pub fn final_(transition: Transition) -> Result<(), Error> { + Self::build_la(transition) + } + + pub fn follow(transition: Transition) -> Result { + Ok(transition.core_lock()?.follow.clone()) + } + + pub fn print(&self, set: SymbolSet, suffix: String) -> Result<(), Error> { + println!( + "transition {} {} -> [{}]{}", + self.m_tno, + self.m_a.text, + set.values()? + .iter() + .map(|symbol| symbol.text.as_str()) + .collect::>() + .join(","), + suffix + ); + Ok(()) + } + + pub fn print0(&self) -> Result<(), Error> { + self.print(self.core_lock()?.follow.clone(), String::new()) + } + + pub fn read(transition: Transition) -> Result { + Self::dr(transition) + } + + pub fn includes(transition: Transition) -> Result { + Ok(transition.core_lock()?.includes.clone()) + } + + pub fn reads(transition: Transition) -> Result { + Ok(transition.core_lock()?.reads.clone()) + } + + fn core_lock(&self) -> Result, Error> { + self.core.lock().map_err(|_| Error::InvalidOperation) + } +} + +/// Syntax error symbol preserving the state and offending symbol. +#[derive(Clone, Debug)] +pub struct LslError { + pub state: i32, + pub sym: SYMBOL, +} + +impl LslError { + pub fn new_with_parser(parser: Parser) -> Result { + Ok(Self { + state: 0, + sym: SYMBOL::new_with_parser(parser)?, + }) + } + + pub fn new_with_parser_parse_stack_entry( + _parser: Parser, + entry: ParseStackEntry, + ) -> Result { + Ok(Self { + state: entry.m_state, + sym: entry.m_value, + }) + } + + #[must_use] + pub fn to_string(&self) -> String { + if self.sym.yyname() == "TOKEN" { + format!( + "syntax error occurred in state {} on input token {}", + self.state, + self.sym.to_string() + ) + } else if self.sym.yyname().is_empty() { + format!("syntax error occurred in state {}", self.state) + } else { + format!( + "syntax error occurred in state {} on symbol {}", + self.state, + self.sym.yyname() + ) + } + } + + #[must_use] + pub fn yyname(&self) -> String { + "Error".to_owned() + } +} + +/// Result wrapper returned after successful error recovery. +#[derive(Clone, Debug)] +pub struct RecoveredError { + error: LslError, + count: i32, +} + +impl RecoveredError { + pub fn new(parser: Parser, entry: ParseStackEntry) -> Result { + let count = parser.m_symbols.erh.counter; + Ok(Self { + error: LslError::new_with_parser_parse_stack_entry(parser, entry)?, + count, + }) + } + + pub fn concrete_syntax_tree(&self) -> Result<(), Error> { + println!("{}", self.to_string()); + self.error.sym.concrete_syntax_tree() + } + + pub fn print(&self) -> Result<(), Error> { + println!("{}", self.to_string()); + self.error.sym.print() + } + + #[must_use] + pub fn to_string(&self) -> String { + format!("Parse contained {} errors", self.count) + } +} diff --git a/crates/libremetaverse-lsl-tools/tests/parser_compat.rs b/crates/libremetaverse-lsl-tools/tests/parser_compat.rs new file mode 100644 index 0000000..b18d03d --- /dev/null +++ b/crates/libremetaverse-lsl-tools/tests/parser_compat.rs @@ -0,0 +1,474 @@ +//! Focused compatibility fixtures for the native issue #82 parser boundary. + +use std::sync::{Arc, Mutex}; + +use libremetaverse_lsl_tools::{ + Associativity, CSymbol, CSymbolSymType, CharacterMatcher, Dfa, DfaAccept, DfaState, + DiagnosticCategory, Error, ErrorHandler, Grammar, Lexer, LexerAction, LslError, ParseTree, + Parser, ParserEntry, Precedence, PrecedencePrecType, Production, ResWds, SymbolSet, + TokenDefinition, YyLexer, +}; + +const EOF: i32 = 2; +const ID: i32 = 3; +const INTEGER: i32 = 4; +const PLUS: i32 = 5; +const STAR: i32 = 6; +const MINUS: i32 = 7; +const LPAREN: i32 = 8; +const RPAREN: i32 = 9; +const SEMICOLON: i32 = 10; +const COMMA: i32 = 11; +const STRING: i32 = 12; +const LBRACE: i32 = 13; +const RBRACE: i32 = 14; +const EQUAL: i32 = 15; +const DEFAULT: i32 = 20; +const STATE_ENTRY: i32 = 21; + +fn definition(name: &str, number: i32) -> TokenDefinition { + TokenDefinition::new(name, number).expect("valid token") +} + +fn accept(name: &str, number: i32, action: LexerAction) -> DfaAccept { + DfaAccept { + token: definition(name, number), + action, + action_number: number, + reserved_words: (number == ID).then(|| "keywords".to_owned()), + } +} + +fn parser_lexer(source: &str) -> Lexer { + use libremetaverse_lsl_tools::DotNetUnicodeCategory as Category; + + let letters = vec![ + Category::UppercaseLetter, + Category::LowercaseLetter, + Category::TitlecaseLetter, + Category::ModifierLetter, + Category::OtherLetter, + ]; + let whitespace = vec![ + Category::Control, + Category::SpaceSeparator, + Category::LineSeparator, + Category::ParagraphSeparator, + ]; + let states = vec![ + DfaState::default() + .transition(CharacterMatcher::Categories(letters.clone()), 1) + .transition(CharacterMatcher::Exact(b'_'.into()), 1) + .transition(CharacterMatcher::Category(Category::DecimalDigitNumber), 2) + .transition(CharacterMatcher::Categories(whitespace.clone()), 3) + .transition(CharacterMatcher::Exact(b'+'.into()), 4) + .transition(CharacterMatcher::Exact(b'*'.into()), 5) + .transition(CharacterMatcher::Exact(b'-'.into()), 6) + .transition(CharacterMatcher::Exact(b'('.into()), 7) + .transition(CharacterMatcher::Exact(b')'.into()), 8) + .transition(CharacterMatcher::Exact(b';'.into()), 9) + .transition(CharacterMatcher::Exact(b','.into()), 10) + .transition(CharacterMatcher::Exact(b'{'.into()), 11) + .transition(CharacterMatcher::Exact(b'}'.into()), 12) + .transition(CharacterMatcher::Exact(b'"'.into()), 13) + .transition(CharacterMatcher::Exact(b'='.into()), 15), + DfaState::default() + .transition(CharacterMatcher::Categories(letters.clone()), 1) + .transition(CharacterMatcher::Exact(b'_'.into()), 1) + .transition(CharacterMatcher::Category(Category::DecimalDigitNumber), 1) + .accepting(accept("ID", ID, LexerAction::Emit)), + DfaState::default() + .transition(CharacterMatcher::Category(Category::DecimalDigitNumber), 2) + .accepting(accept("INTEGER", INTEGER, LexerAction::Emit)), + DfaState::default() + .transition(CharacterMatcher::Categories(whitespace), 3) + .accepting(accept("WS", 30, LexerAction::Skip)), + DfaState::default().accepting(accept("PLUS", PLUS, LexerAction::Emit)), + DfaState::default().accepting(accept("STAR", STAR, LexerAction::Emit)), + DfaState::default().accepting(accept("MINUS", MINUS, LexerAction::Emit)), + DfaState::default().accepting(accept("LPAREN", LPAREN, LexerAction::Emit)), + DfaState::default().accepting(accept("RPAREN", RPAREN, LexerAction::Emit)), + DfaState::default().accepting(accept("SEMICOLON", SEMICOLON, LexerAction::Emit)), + DfaState::default().accepting(accept("COMMA", COMMA, LexerAction::Emit)), + DfaState::default().accepting(accept("LBRACE", LBRACE, LexerAction::Emit)), + DfaState::default().accepting(accept("RBRACE", RBRACE, LexerAction::Emit)), + DfaState::default() + .transition(CharacterMatcher::Categories(letters), 13) + .transition(CharacterMatcher::Exact(b' '.into()), 13) + .transition(CharacterMatcher::Exact(b'"'.into()), 14), + DfaState::default().accepting(accept("STRING", STRING, LexerAction::Emit)), + DfaState::default().accepting(accept("EQUAL", EQUAL, LexerAction::Emit)), + ]; + let mut table = YyLexer::new(ErrorHandler::default()).expect("lexer table"); + table.using_eof = true; + table + .set_start_dfa("YYINITIAL", Dfa::from_states(states, 0).expect("dfa")) + .expect("start state"); + table + .set_reserved_words( + "keywords", + ResWds::from_pairs( + [ + ("default", definition("DEFAULT", DEFAULT)), + ("state_entry", definition("STATE_ENTRY", STATE_ENTRY)), + ], + false, + ) + .expect("reserved words"), + ) + .expect("reserved table"); + let mut lexer = Lexer::new(table).expect("lexer"); + lexer.start_with_string(source.to_owned()).expect("source"); + lexer +} + +fn add_common_terminals(grammar: &mut Grammar) { + for (name, number) in [ + ("EOF", EOF), + ("ID", ID), + ("INTEGER", INTEGER), + ("PLUS", PLUS), + ("STAR", STAR), + ("MINUS", MINUS), + ("LPAREN", LPAREN), + ("RPAREN", RPAREN), + ("SEMICOLON", SEMICOLON), + ("COMMA", COMMA), + ("STRING", STRING), + ("LBRACE", LBRACE), + ("RBRACE", RBRACE), + ("EQUAL", EQUAL), + ("DEFAULT", DEFAULT), + ("STATE_ENTRY", STATE_ENTRY), + ("Error", 0), + ] { + grammar.add_symbol(name, number, true).expect("terminal"); + } +} + +fn expression_parser(source: &str) -> Parser { + const EXPRESSION: i32 = 100; + let mut grammar = Grammar::new(EXPRESSION, EOF).expect("grammar"); + add_common_terminals(&mut grammar); + grammar + .add_symbol("Expression", EXPRESSION, false) + .expect("nonterminal"); + grammar + .set_precedence(PLUS, 1, Associativity::Left) + .expect("plus precedence"); + grammar + .set_precedence(STAR, 2, Associativity::Left) + .expect("star precedence"); + grammar + .set_precedence(MINUS, 3, Associativity::Right) + .expect("minus precedence"); + grammar + .add_production(EXPRESSION, vec![EXPRESSION, PLUS, EXPRESSION]) + .expect("plus"); + grammar + .add_production(EXPRESSION, vec![EXPRESSION, STAR, EXPRESSION]) + .expect("multiply"); + grammar + .add_production_with_precedence(EXPRESSION, vec![MINUS, EXPRESSION], Some(MINUS)) + .expect("unary"); + grammar + .add_production(EXPRESSION, vec![LPAREN, EXPRESSION, RPAREN]) + .expect("parentheses"); + grammar + .add_production(EXPRESSION, vec![ID]) + .expect("identifier"); + Parser::new(grammar.build().expect("table"), parser_lexer(source)).expect("parser") +} + +fn tree(symbol: &libremetaverse_lsl_tools::SYMBOL) -> &ParseTree { + symbol + .m_dollar + .downcast_ref::() + .expect("parse tree") +} + +#[test] +fn precedence_and_associativity_choose_the_reference_tree() { + let mut parser = expression_parser("a + b * c + d"); + let result = parser + .parse_with_string("a + b * c + d".to_owned()) + .expect("parse"); + let root = tree(&result); + assert_eq!(root.name, "Expression"); + assert_eq!(root.children[1].number, PLUS); + assert_eq!(root.children[0].children[1].number, PLUS); + assert_eq!(root.children[0].children[2].children[1].number, STAR); + assert!(!parser.m_symbols.conflicts().is_empty()); +} + +#[test] +fn right_associative_unary_precedence_is_deterministic() { + let mut parser = expression_parser("- - a"); + let result = parser.parse_with_string("- - a".to_owned()).expect("parse"); + let root = tree(&result); + assert_eq!(root.children[0].number, MINUS); + assert_eq!(root.children[1].children[0].number, MINUS); +} + +#[test] +fn nonassociative_conflict_rejects_a_chained_operator() { + const EXPRESSION: i32 = 100; + let mut grammar = Grammar::new(EXPRESSION, EOF).expect("grammar"); + add_common_terminals(&mut grammar); + grammar + .add_symbol("Expression", EXPRESSION, false) + .expect("nonterminal"); + grammar + .set_precedence(PLUS, 1, Associativity::Nonassoc) + .expect("precedence"); + grammar + .add_production(EXPRESSION, vec![EXPRESSION, PLUS, EXPRESSION]) + .expect("binary"); + grammar + .add_production(EXPRESSION, vec![ID]) + .expect("identifier"); + let mut parser = + Parser::new(grammar.build().expect("table"), parser_lexer("a+a+a")).expect("parser"); + assert!(matches!( + parser.parse_with_string("a+a+a".to_owned()), + Err(Error::Parse { + context: "syntax error", + .. + }) + )); + assert_eq!( + parser.diagnostics().expect("diagnostics")[0].category, + DiagnosticCategory::Syntax + ); +} + +#[test] +fn empty_production_accepts_an_empty_input() { + const START: i32 = 100; + const ITEMS: i32 = 101; + let mut grammar = Grammar::new(START, EOF).expect("grammar"); + add_common_terminals(&mut grammar); + grammar.add_symbol("Start", START, false).expect("start"); + grammar.add_symbol("Items", ITEMS, false).expect("items"); + grammar.add_production(START, vec![ITEMS]).expect("root"); + grammar.add_production(ITEMS, vec![]).expect("empty"); + let mut parser = + Parser::new(grammar.build().expect("table"), parser_lexer("")).expect("parser"); + let result = parser.parse_with_string(String::new()).expect("parse"); + assert_eq!(tree(&result).children[0].name, "Items"); +} + +#[test] +fn lalr_lookaheads_avoid_the_classic_slr_assignment_conflict() { + const START: i32 = 100; + const LEFT: i32 = 101; + const RIGHT: i32 = 102; + let mut grammar = Grammar::new(START, EOF).expect("grammar"); + add_common_terminals(&mut grammar); + for (name, number) in [("Start", START), ("Left", LEFT), ("Right", RIGHT)] { + grammar + .add_symbol(name, number, false) + .expect("nonterminal"); + } + grammar + .add_production(START, vec![LEFT, EQUAL, RIGHT]) + .expect("assignment"); + grammar.add_production(START, vec![RIGHT]).expect("value"); + grammar + .add_production(LEFT, vec![STAR, RIGHT]) + .expect("dereference"); + grammar.add_production(LEFT, vec![ID]).expect("name"); + grammar.add_production(RIGHT, vec![LEFT]).expect("right"); + let table = grammar.build().expect("LALR table"); + assert!(table.conflicts().is_empty()); + for source in ["a = b", "* a = b"] { + let mut parser = Parser::new(table.clone(), parser_lexer(source)).expect("parser"); + let result = parser + .parse_with_string(source.to_owned()) + .expect("assignment parse"); + assert_eq!(tree(&result).name, "Start"); + } +} + +#[test] +fn error_token_recovery_discards_input_and_returns_recovered_tree() { + const START: i32 = 100; + const LIST: i32 = 101; + const STATEMENT: i32 = 102; + let mut grammar = Grammar::new(START, EOF).expect("grammar"); + add_common_terminals(&mut grammar); + for (name, number) in [("Start", START), ("List", LIST), ("Statement", STATEMENT)] { + grammar + .add_symbol(name, number, false) + .expect("nonterminal"); + } + grammar.add_production(START, vec![LIST]).expect("start"); + grammar + .add_production(LIST, vec![LIST, STATEMENT]) + .expect("list"); + grammar + .add_production(LIST, vec![STATEMENT]) + .expect("single"); + grammar + .add_production(STATEMENT, vec![ID, SEMICOLON]) + .expect("statement"); + grammar + .add_production(STATEMENT, vec![0, ID, SEMICOLON]) + .expect("recovery"); + let mut parser = + Parser::new(grammar.build().expect("table"), parser_lexer("a; + b;")).expect("parser"); + let result = parser + .parse_with_string("a; + b;".to_owned()) + .expect("recovered parse"); + assert_eq!(result.yyname(), "recoveredError"); + let diagnostics = parser.diagnostics().expect("diagnostics"); + assert_eq!(diagnostics[0].category, DiagnosticCategory::Syntax); + assert_eq!(diagnostics[1].category, DiagnosticCategory::ParserRecovery); +} + +#[test] +fn representative_lsl_script_parses_to_expected_model() { + const SCRIPT: i32 = 100; + const EVENT: i32 = 101; + const CALL: i32 = 102; + let source = r#"default { state_entry() { llSay(0, "hello"); } }"#; + let mut grammar = Grammar::new(SCRIPT, EOF).expect("grammar"); + add_common_terminals(&mut grammar); + for (name, number) in [("Script", SCRIPT), ("Event", EVENT), ("Call", CALL)] { + grammar + .add_symbol(name, number, false) + .expect("nonterminal"); + } + grammar + .add_production(SCRIPT, vec![DEFAULT, LBRACE, EVENT, RBRACE]) + .expect("script"); + grammar + .add_production( + EVENT, + vec![STATE_ENTRY, LPAREN, RPAREN, LBRACE, CALL, SEMICOLON, RBRACE], + ) + .expect("event"); + grammar + .add_production(CALL, vec![ID, LPAREN, INTEGER, COMMA, STRING, RPAREN]) + .expect("call"); + let mut parser = + Parser::new(grammar.build().expect("table"), parser_lexer(source)).expect("parser"); + let result = parser + .parse_with_string(source.to_owned()) + .expect("LSL source"); + let root = tree(&result); + assert_eq!(root.name, "Script"); + assert_eq!(root.children[2].name, "Event"); + assert_eq!(root.children[2].children[4].name, "Call"); + assert_eq!( + root.children[2].children[4].children[0].text.as_deref(), + Some("llSay") + ); +} + +#[test] +fn parser_table_emission_is_byte_deterministic() { + let parser = expression_parser("a"); + let first = Arc::new(Mutex::new(Vec::new())); + parser + .m_symbols + .emit(Box::new(SharedWriter(first.clone()))) + .expect("first"); + let second = Arc::new(Mutex::new(Vec::new())); + parser + .m_symbols + .emit(Box::new(SharedWriter(second.clone()))) + .expect("second"); + assert_eq!( + first.lock().expect("first output").as_slice(), + second.lock().expect("second output").as_slice() + ); +} + +struct SharedWriter(Arc>>); + +impl std::io::Write for SharedWriter { + fn write(&mut self, bytes: &[u8]) -> std::io::Result { + self.0 + .lock() + .map_err(|_| std::io::Error::other("poisoned output"))? + .extend_from_slice(bytes); + Ok(bytes.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +#[test] +fn malformed_corpus_terminates_without_panics_or_unbounded_growth() { + for source in ["+", "a +", "((a", "a * * b", "-", "a )", "@"] { + let mut parser = expression_parser(source); + let _ = parser.parse_with_string(source.to_owned()); + assert!(parser.diagnostics().expect("diagnostics").len() <= 2); + } +} + +#[test] +fn mapped_symbol_set_production_precedence_and_entry_apis_are_live() { + let terminal = CSymbol::native("PLUS", PLUS, CSymbolSymType::Terminal).expect("terminal"); + let nonterminal = + CSymbol::native("Expression", 100, CSymbolSymType::Nonterminal).expect("nonterminal"); + let mut set = SymbolSet::native(); + assert!(set.check_in(terminal.clone()).expect("insert")); + assert!(!set.check_in(terminal.clone()).expect("deduplicate")); + assert!(set.contains(terminal.clone()).expect("contains")); + assert!(terminal.matches("PLUS".to_owned()).expect("symbol text")); + + let mut followed = nonterminal.clone(); + assert!( + followed + .add_follow(terminal.m_first.clone()) + .expect("first follow insertion") + ); + assert_eq!(nonterminal.m_follow.count(), 1); + + let nullable = + CSymbol::native("Optional", 101, CSymbolSymType::Nonterminal).expect("nullable symbol"); + let _empty = Production::native(8, nullable.clone(), vec![]).expect("empty production"); + assert!(nullable.is_nullable().expect("registered empty production")); + + let mut production = Production::native(7, nonterminal.clone(), vec![]).expect("production"); + production.add_to_rhs(nonterminal.clone()).expect("lhs"); + production.add_to_rhs(terminal.clone()).expect("operator"); + assert_eq!(production.prefix(1).expect("prefix")[0].m_yynum, 100); + let target = CSymbol::native("Target", 102, CSymbolSymType::Nonterminal).expect("target"); + production + .add_first(target.clone(), 1) + .expect("FIRST/FOLLOW propagation"); + assert!( + target + .m_follow + .contains(terminal.clone()) + .expect("shared follow mutation") + ); + + let precedence = Precedence::first(PrecedencePrecType::Left, 5).expect("precedence"); + assert_eq!( + Precedence::check_with_precedence_prec_type_int32(precedence, PrecedencePrecType::Left, 0,), + Ok(5) + ); + + let parser = expression_parser("a"); + let mut lexer = parser.m_lexer.clone(); + let symbol = lexer.next_token().expect("lexing").expect("token"); + let mut entry = ParserEntry::default(); + assert_eq!( + symbol.pass_(parser.m_symbols.clone(), 0, &mut entry), + Ok(true) + ); + assert_eq!(entry.str(), "shift 1"); + + let lsl_error = LslError { + state: 4, + sym: libremetaverse_lsl_tools::SYMBOL::new_with_lexer(parser.m_lexer.clone()) + .expect("symbol"), + }; + assert!(lsl_error.to_string().contains("state 4")); +} diff --git a/tests/compat/tests/extension_shims.rs b/tests/compat/tests/extension_shims.rs index 100ff36..060c5cc 100644 --- a/tests/compat/tests/extension_shims.rs +++ b/tests/compat/tests/extension_shims.rs @@ -26,7 +26,7 @@ async fn compile_rlv_calls( .await; } -fn compile_parser_call(parser: &Parser) { +fn compile_parser_call(parser: &mut Parser) { let _ = parser.parse_with_string(String::new()); } @@ -65,11 +65,8 @@ fn extension_flows_have_typed_callable_signatures() { } #[test] -fn extension_constructors_fail_with_catalog_ids() { - assert_eq!( - member_id(YyParser::new()), - "M:LibreMetaverse.LslTools.YyParser.#ctor" - ); +fn extension_constructors_have_expected_native_or_failure_behavior() { + assert!(YyParser::new().is_ok()); assert_eq!( member_id(RlvActionCallbacksDefault::new()), "M:LibreMetaverse.RLV.RlvActionCallbacksDefault.#ctor" diff --git a/tools/check_milestone_10_issue_82.py b/tools/check_milestone_10_issue_82.py new file mode 100644 index 0000000..ac39c92 --- /dev/null +++ b/tools/check_milestone_10_issue_82.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +"""Audit issue 82's native grammar, parser-table, and recovery boundary.""" + +from __future__ import annotations + +import json +import re +from pathlib import Path + +import generate_api_shims + + +ROOT = Path(__file__).resolve().parents[1] +SOURCE = ROOT / "crates" / "libremetaverse-lsl-tools" / "src" / "parser.rs" +GENERATED = ROOT / "crates" / "libremetaverse-lsl-tools" / "src" / "generated.rs" +TESTS = ROOT / "crates" / "libremetaverse-lsl-tools" / "tests" / "parser_compat.rs" +EXTENSION_TESTS = ROOT / "tests" / "compat" / "tests" / "extension_shims.rs" +DOC = ROOT / "crates" / "libremetaverse-lsl-tools" / "README.md" +WORKFLOW = ROOT / ".gitea" / "workflows" / "rust-workspace.yml" +CATALOG = ROOT / "api" / "public-api.json" +STUB_RE = re.compile( + r"\b(?:not_implemented|unimplemented_api)\b|\b(?:todo|unimplemented)!\s*\(" +) + +TYPES = { + "T:LibreMetaverse.LslTools.CSymbol": "crate::parser::CSymbol", + "T:LibreMetaverse.LslTools.CSymbol.SymType": "crate::parser::CSymbolSymType", + "T:LibreMetaverse.LslTools.Error": "crate::parser::LslError", + "T:LibreMetaverse.LslTools.Literal": "crate::parser::Literal", + "T:LibreMetaverse.LslTools.ParseStackEntry": "crate::parser::ParseStackEntry", + "T:LibreMetaverse.LslTools.ParseState": "crate::parser::ParseState", + "T:LibreMetaverse.LslTools.Parser": "crate::parser::Parser", + "T:LibreMetaverse.LslTools.ParserAction": "crate::parser::ParserAction", + "T:LibreMetaverse.LslTools.ParserEntry": "crate::parser::ParserEntry", + "T:LibreMetaverse.LslTools.ParserOldAction": "crate::parser::ParserOldAction", + "T:LibreMetaverse.LslTools.ParserReduce": "crate::parser::ParserReduce", + "T:LibreMetaverse.LslTools.ParserShift": "crate::parser::ParserShift", + "T:LibreMetaverse.LslTools.ParserSimpleAction": "crate::parser::ParserSimpleAction", + "T:LibreMetaverse.LslTools.ParsingInfo": "crate::parser::ParsingInfo", + "T:LibreMetaverse.LslTools.Precedence": "crate::parser::Precedence", + "T:LibreMetaverse.LslTools.Precedence.PrecType": "crate::parser::PrecedencePrecType", + "T:LibreMetaverse.LslTools.ProdItem": "crate::parser::ProdItem", + "T:LibreMetaverse.LslTools.Production": "crate::parser::Production", + "T:LibreMetaverse.LslTools.SymbolSet": "crate::parser::SymbolSet", + "T:LibreMetaverse.LslTools.Transition": "crate::parser::Transition", + "T:LibreMetaverse.LslTools.YyParser": "crate::parser::YyParser", + "T:LibreMetaverse.LslTools.recoveredError": "crate::parser::RecoveredError", +} + + +def require_markers(path: Path, markers: tuple[str, ...]) -> None: + text = path.read_text() + missing = [marker for marker in markers if marker not in text] + if missing: + raise SystemExit(f"{path.name}: audit evidence missing: " + ", ".join(missing)) + + +def catalog_member_count() -> int: + catalog = json.loads(CATALOG.read_text()) + assembly = next( + value for value in catalog["assemblies"] + if value["identity"]["name"] == "LibreMetaverse.LslTools" + ) + return sum( + len(api_type["members"]) + for api_type in assembly["types"] + if api_type["doc_id"] in TYPES + ) + + +def generated_type_block(text: str, doc_id: str) -> str: + marker = f"/// C# type: `{doc_id}`." + start = text.find(marker) + if start < 0: + raise SystemExit(f"generated declaration is missing for {doc_id}") + next_type = text.find("/// C# type:", start + len(marker)) + return text[start:] if next_type < 0 else text[start:next_type] + + +def main() -> None: + for api_type, declaration in TYPES.items(): + if generate_api_shims.NATIVE_TYPES.get(api_type) != declaration: + raise SystemExit(f"issue 82 native type mapping is missing for {api_type}") + if catalog_member_count() != 215: + raise SystemExit("issue 82 expected 215 mapped parser members") + + source = SOURCE.read_text() + if STUB_RE.search(source): + raise SystemExit("issue 82 owned Rust stubs remain in parser.rs") + if re.search(r"unsafe\s*\{|unsafe\s+impl|target_os\s*=\s*\"macos\"", source): + raise SystemExit("parser.rs contains an unsafe or macOS-only implementation") + generated = GENERATED.read_text() + for api_type in TYPES: + if STUB_RE.search(generated_type_block(generated, api_type)): + raise SystemExit(f"issue 82 owned generated stubs remain for {api_type}") + + require_markers(SOURCE, ( + "pub struct Grammar", "pub struct GrammarProduction", "struct ParserMachine", + "fn first_sets", "fn lalr_lookaheads", "fn resolve_shift_reduce", "TableAction::Reject", + "pub struct ParserConflict", "MAX_PARSER_STATES", "MAX_PARSER_STACK", + "MAX_PARSER_STEPS", "MAX_RECOVERY_ERRORS", "pub struct ParseTree", + "pub struct CSymbol", "pub struct SymbolSet", "pub struct Production", + "pub struct Precedence", "pub struct ParseState", "pub struct Transition", + "pub struct YyParser", "pub struct Parser", "fn parse_started", "fn recover", + "DiagnosticCategory::ParserRecovery", "Error::InvalidOperation", + )) + require_markers(TESTS, ( + "precedence_and_associativity_choose_the_reference_tree", + "right_associative_unary_precedence_is_deterministic", + "nonassociative_conflict_rejects_a_chained_operator", + "empty_production_accepts_an_empty_input", + "lalr_lookaheads_avoid_the_classic_slr_assignment_conflict", + "error_token_recovery_discards_input_and_returns_recovered_tree", + "representative_lsl_script_parses_to_expected_model", + "parser_table_emission_is_byte_deterministic", + "malformed_corpus_terminates_without_panics_or_unbounded_growth", + "mapped_symbol_set_production_precedence_and_entry_apis_are_live", + "shared follow mutation", "registered empty production", + )) + if TESTS.read_text().count("#[test]") != 10: + raise SystemExit("issue 82 expected 10 focused parser fixtures") + require_markers(EXTENSION_TESTS, ("assert!(YyParser::new().is_ok())",)) + require_markers(DOC, ( + "canonical LR(0)", "deterministic LALR(1)", "Shift/reduce conflicts", + "nonassociative", "1,048,576", "16,777,216", "37 focused", + "issue 83", "ubuntu-latest", + )) + require_markers(WORKFLOW, ("python3 tools/check_milestone_10_issue_82.py",)) + print( + "issue 82 audit: 22 native mapped parser types and 215 members, deterministic " + "LALR tables, precedence conflicts, bounded shifts/reductions, error-token " + "recovery, shared compatibility grammar state, 10 focused fixtures, docs, and " + "ubuntu-only CI are present" + ) + + +if __name__ == "__main__": + main() diff --git a/tools/generate_api_shims.py b/tools/generate_api_shims.py index 96d34cb..348bb65 100644 --- a/tools/generate_api_shims.py +++ b/tools/generate_api_shims.py @@ -43,23 +43,45 @@ NATIVE_TYPES = { "T:LibreMetaverse.LslTools.CSToolsStopException": "crate::lexer::CSToolsStopException", "T:LibreMetaverse.LslTools.CatTest": "crate::lexer::CatTest", "T:LibreMetaverse.LslTools.Charset": "crate::lexer::Charset", + "T:LibreMetaverse.LslTools.CSymbol": "crate::parser::CSymbol", + "T:LibreMetaverse.LslTools.CSymbol.SymType": "crate::parser::CSymbolSymType", "T:LibreMetaverse.LslTools.CommentList": "crate::lexer::CommentList", "T:LibreMetaverse.LslTools.CsReader": "crate::lexer::CsReader", "T:LibreMetaverse.LslTools.Dfa": "crate::lexer::Dfa", "T:LibreMetaverse.LslTools.Dfa.Action": "crate::lexer::DfaAction", "T:LibreMetaverse.LslTools.EOF": "crate::lexer::EOF", "T:LibreMetaverse.LslTools.ErrorHandler": "crate::lexer::ErrorHandler", + "T:LibreMetaverse.LslTools.Error": "crate::parser::LslError", "T:LibreMetaverse.LslTools.Lexer": "crate::lexer::Lexer", "T:LibreMetaverse.LslTools.Lexer._Enumerator": "crate::lexer::LexerEnumerator", "T:LibreMetaverse.LslTools.LineList": "crate::lexer::LineList", "T:LibreMetaverse.LslTools.LineManager": "crate::lexer::LineManager", + "T:LibreMetaverse.LslTools.Literal": "crate::parser::Literal", "T:LibreMetaverse.LslTools.Null": "crate::lexer::Null", "T:LibreMetaverse.LslTools.ObjectList": "crate::lexer::ObjectList", + "T:LibreMetaverse.LslTools.ParseStackEntry": "crate::parser::ParseStackEntry", + "T:LibreMetaverse.LslTools.ParseState": "crate::parser::ParseState", + "T:LibreMetaverse.LslTools.Parser": "crate::parser::Parser", + "T:LibreMetaverse.LslTools.ParserAction": "crate::parser::ParserAction", + "T:LibreMetaverse.LslTools.ParserEntry": "crate::parser::ParserEntry", + "T:LibreMetaverse.LslTools.ParserOldAction": "crate::parser::ParserOldAction", + "T:LibreMetaverse.LslTools.ParserReduce": "crate::parser::ParserReduce", + "T:LibreMetaverse.LslTools.ParserShift": "crate::parser::ParserShift", + "T:LibreMetaverse.LslTools.ParserSimpleAction": "crate::parser::ParserSimpleAction", + "T:LibreMetaverse.LslTools.ParsingInfo": "crate::parser::ParsingInfo", + "T:LibreMetaverse.LslTools.Precedence": "crate::parser::Precedence", + "T:LibreMetaverse.LslTools.Precedence.PrecType": "crate::parser::PrecedencePrecType", + "T:LibreMetaverse.LslTools.ProdItem": "crate::parser::ProdItem", + "T:LibreMetaverse.LslTools.Production": "crate::parser::Production", "T:LibreMetaverse.LslTools.ResWds": "crate::lexer::ResWds", "T:LibreMetaverse.LslTools.SYMBOL": "crate::lexer::SYMBOL", "T:LibreMetaverse.LslTools.SourceLineInfo": "crate::lexer::SourceLineInfo", + "T:LibreMetaverse.LslTools.SymbolSet": "crate::parser::SymbolSet", "T:LibreMetaverse.LslTools.TOKEN": "crate::lexer::TOKEN", + "T:LibreMetaverse.LslTools.Transition": "crate::parser::Transition", "T:LibreMetaverse.LslTools.YyLexer": "crate::lexer::YyLexer", + "T:LibreMetaverse.LslTools.YyParser": "crate::parser::YyParser", + "T:LibreMetaverse.LslTools.recoveredError": "crate::parser::RecoveredError", "T:LibreMetaverse.RLV.AttachmentRequest": "crate::service::AttachmentRequest", "T:LibreMetaverse.RLV.RlvActionCallbacksDefault": "crate::service::RlvActionCallbacksDefault", "T:LibreMetaverse.RLV.RlvCallbacksDefault": "crate::service::RlvCallbacksDefault",