diff --git a/Cargo.toml b/Cargo.toml index 77d193d..8a170a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,64 @@ [workspace] resolver = "2" members = [ - "opslang-ast", + "structure/type-registry", + "structure/opslang-ast", + "structure/opslang-ast/macro", + "opslang-diag", + "structure/opslang-ir", + "structure/opslang-ir/macro", "opslang-parser", + "opslang-printer", + "ty/opslang-ty", + "ty/opslang-typeck", + "ty/opslang-module", + "opslang-visitor", + "opslang-visitor/macro", + "opslang-visitor-macro-helper", + "tools/opslang-migration", + "tools/opslang-formatter", ] [workspace.package] version = "0.4.0" +edition = "2024" +license = "MPL-2.0" [workspace.dependencies] -opslang-ast = { path = "opslang-ast" } -opslang-parser = { path = "opslang-parser" } +anyhow = "1.0.100" +chrono = "0.4.42" +typed-arena = "2.0.2" +thiserror = "2.0.17" + +clap = { version = "4.5.48", features = ["derive"] } +walkdir = "2.5.0" +toml = "0.9.7" + +serde = { version = "1.0.228", features = ["derive"] } + +syn = { version = "2.0.106", features = ["visit-mut", "full", "derive"] } +proc-macro2 = "1.0.101" +quote = "1.0.41" +synstructure = "0.13.2" +convert_case = "0.8.0" + +peg = "0.8.1" +parol = "3.0.1" +parol_runtime = "3.0.0" + +opslang-type-registry = { path = "./structure/type-registry", version = "=0.4.0" } +opslang-ast = { path = "./structure/opslang-ast", version = "=0.4.0" } +opslang-ast-macro = { path = "./structure/opslang-ast/macro", version = "=0.4.0" } +opslang-ir = { path = "./structure/opslang-ir", version = "=0.4.0" } +opslang-ir-macro = { path = "./structure/opslang-ir/macro", version = "=0.4.0" } +opslang-diag = { path = "./opslang-diag", version = "=0.4.0" } +opslang-parser = { path = "./opslang-parser", version = "=0.4.0" } +opslang-printer = { path = "./opslang-printer", version = "=0.4.0" } +opslang-ty = { path = "./ty/opslang-ty", version = "=0.4.0" } +opslang-typeck = { path = "./ty/opslang-typeck", version = "=0.4.0" } +opslang-module = { path = "./ty/opslang-module", version = "=0.4.0" } +opslang-visitor = { path = "./opslang-visitor", version = "=0.4.0" } +opslang-visitor-macro = { path = "./opslang-visitor/macro", version = "=0.4.0" } +opslang-visitor-macro-helper = { path = "./opslang-visitor-macro-helper", version = "=0.4.0" } +opslang-migration = { path = "./tools/opslang-migration", version = "=0.4.0" } +opslang-formatter = { path = "./tools/opslang-formatter", version = "=0.4.0" } diff --git a/opslang-ast/Cargo.toml b/opslang-ast/Cargo.toml deleted file mode 100644 index 7f43b2b..0000000 --- a/opslang-ast/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "opslang-ast" -version.workspace = true -edition = "2021" -license = "MPL-2.0" -description = "ops file language AST" - -[dependencies] -chrono = "0.4.33" diff --git a/opslang-diag/Cargo.toml b/opslang-diag/Cargo.toml new file mode 100644 index 0000000..47ae773 --- /dev/null +++ b/opslang-diag/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "opslang-diag" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] diff --git a/opslang-diag/src/lib.rs b/opslang-diag/src/lib.rs new file mode 100644 index 0000000..0647bf2 --- /dev/null +++ b/opslang-diag/src/lib.rs @@ -0,0 +1,105 @@ +use std::cell::RefCell; + +pub struct DiagContext { + emitter: RefCell>, +} + +impl DiagContext { + pub fn new(emitter: Box) -> Self { + Self { + emitter: RefCell::new(emitter), + } + } + + fn emit_diagnostic(&self, diag: DiagInner) { + self.emitter.borrow_mut().emit_diagnostic(diag); + } + + #[track_caller] + pub fn create_err(&self, err: impl Diagnostic) -> Diag<'_> { + err.into_diag(self, Level::Error) + } + + #[track_caller] + pub fn emit_err(&self, err: impl Diagnostic) { + self.create_err(err).emit() + } +} + +pub trait DiagEmitter { + fn emit_diagnostic(&mut self, diag: DiagInner); +} + +pub trait Diagnostic { + fn into_diag(self, dcx: &DiagContext, level: Level) -> Diag<'_>; +} + +pub struct DiagInner { + pub(crate) level: Level, + pub message: String, +} + +impl DiagInner { + pub fn level(&self) -> &Level { + &self.level + } +} + +pub enum Level { + Bug, + Error, + Warning, + Info, + Lint, +} + +pub struct Diag<'dcx> { + pub dcx: &'dcx DiagContext, + inner: Option>, +} + +impl Drop for Diag<'_> { + fn drop(&mut self) { + if let Some(diag) = self.inner.take() { + self.dcx.emit_diagnostic(DiagInner::new( + Level::Bug, + String::from("the following error was constructed but not emitted"), + )); + self.dcx.emit_diagnostic(*diag); + panic!("error was constructed but not emitted"); + } + } +} + +impl Diag<'_> { + pub fn emit(mut self) { + self.dcx.emit_diagnostic(*self.inner.take().unwrap()); + } + + pub fn cancel(mut self) { + self.inner.take(); + } +} + +// constructors + +impl DiagInner { + fn new(level: Level, message: String) -> Self { + Self { level, message } + } +} + +impl<'dcx> Diag<'dcx> { + #[track_caller] + pub fn new(dcx: &'dcx DiagContext, level: Level, message: String) -> Self { + Self::new_diagnostic(dcx, DiagInner::new(level, message)) + } + + #[track_caller] + pub(crate) fn new_diagnostic(dcx: &'dcx DiagContext, diag: DiagInner) -> Self { + Self { + dcx, + inner: Some(Box::new(diag)), + } + } +} diff --git a/opslang-parser/Cargo.toml b/opslang-parser/Cargo.toml index 4544704..40f0c1f 100644 --- a/opslang-parser/Cargo.toml +++ b/opslang-parser/Cargo.toml @@ -1,13 +1,35 @@ [package] name = "opslang-parser" version.workspace = true -edition = "2021" -license = "MPL-2.0" +edition.workspace = true +license.workspace = true description = "ops file language parser" +[features] +v0 = ["dep:peg"] +v1 = ["build-parol", "dep:typed-arena"] +build-parol = ["dep:parol", "dep:parol_runtime"] +default = ["v0", "v1"] + [dependencies] -peg = "0.8.1" -thiserror = "1.0.48" -anyhow = "1.0.75" -opslang-ast = "0.4.0" -chrono = "0.4.33" +opslang-ast.workspace = true +opslang-diag.workspace = true + +peg.workspace = true +peg.optional = true +parol.workspace = true +parol.optional = true +parol_runtime.workspace = true +parol_runtime.optional = true +typed-arena.workspace = true +typed-arena.optional = true + +thiserror.workspace = true +anyhow.workspace = true +chrono.workspace = true + +[build-dependencies] +parol.workspace = true +parol.optional = true +parol_runtime.workspace = true +parol_runtime.optional = true diff --git a/opslang-parser/build.rs b/opslang-parser/build.rs new file mode 100644 index 0000000..2653b9c --- /dev/null +++ b/opslang-parser/build.rs @@ -0,0 +1,141 @@ +#[cfg(feature = "build-parol")] +fn build_parol() { + use std::path::PathBuf; + use std::process; + + use parol::{ParolErrorReporter, build::Builder}; + use parol_runtime::Report; + + #[allow(unused_mut, unused_variables)] + let mut versions = Vec::new(); + + { + #[cfg(feature = "v1")] + versions.push("v1"); + } + + let mut has_error = false; + + mod name { + pub struct Path { + pub path: &'static str, + } + impl AsRef for Path { + fn as_ref(&self) -> &std::path::Path { + self.path.as_ref() + } + } + #[derive(PartialEq)] + pub struct RustFile { + pub path: &'static str, + pub module: &'static str, + } + impl AsRef for RustFile { + fn as_ref(&self) -> &std::path::Path { + self.path.as_ref() + } + } + + pub const ACTION_MOD: &str = "parse"; + pub const USER_TYPE: &str = "Action"; + pub const GENERATED: &str = "generated"; + pub const GRAMMAR: Path = Path { + path: "grammar.par", + }; + pub const EXPANDED_GRAMMAR: Path = Path { + path: "grammar-exp.par", + }; + pub const PARSER: RustFile = RustFile { + path: "parser.rs", + module: "parser", + }; + pub const TRAIT: RustFile = RustFile { + path: "grammar_trait.rs", + module: "grammar_trait", + }; + } + + for v in versions { + let input = { + let mut path = PathBuf::from("src"); + path.push("version"); + path.push(v); + path + }; + let generated = { + let mut path = PathBuf::from("src"); + path.push("version"); + path.push(v); + path.push(name::GENERATED); + path + }; + std::fs::create_dir_all(&generated).unwrap(); + + let grammar_file = input.join(name::GRAMMAR.path); + if let Err(err) = Builder::with_explicit_output_dir(".") + .grammar_file(&grammar_file) + .expanded_grammar_output_file(generated.join(name::EXPANDED_GRAMMAR)) + .parser_output_file(generated.join(name::PARSER)) + .actions_output_file(generated.join(name::TRAIT)) + .user_trait_module_name(&format!("version::{v}::{path}", path = name::ACTION_MOD)) + .user_type_name(name::USER_TYPE) + .trim_parse_tree() + .generate_parser() + { + ParolErrorReporter::report_error(&err, &grammar_file).unwrap_or_default(); + has_error = true; + } + + // Generate `generated.rs` + let mut f = std::fs::File::create(generated.join("../generated.rs")).unwrap(); + { + use name::*; + use std::io::Write; + writeln!(f, "// This file is generated by `build.rs`.").unwrap(); + writeln!(f, "// Do not edit it manually.").unwrap(); + writeln!(f).unwrap(); + for file in [TRAIT, PARSER] { + if file == TRAIT { + writeln!(f, "#[allow(clippy::all)]").unwrap(); + } + let module_name = file.module; + writeln!(f, "pub mod {module_name};").unwrap(); + } + } + } + + if has_error { + process::exit(1); + } + + // Generate `src/parol_macro.rs` + let mut f = std::fs::File::create("src/parol_macro.rs").unwrap(); + { + use name::*; + use std::io::Write; + writeln!(f, "// This file is generated by `build.rs`.").unwrap(); + writeln!(f, "// Do not edit it manually.").unwrap(); + writeln!(f).unwrap(); + let action = TRAIT.module; + writeln!( + f, + r#"#[macro_export] +/// Redirect due to `actions_output_file` depending on `user_trait_module_name` in fact. +/// +/// This macro is generated by `build.rs`. +macro_rules! redirect_parol {{ + () => {{ + mod {ACTION_MOD}_trait {{ + pub use super::{GENERATED}::{action}::{USER_TYPE}Auto; + }} + }}; +}}"# + ) + .unwrap(); + } +} + +fn main() { + #[cfg(feature = "build-parol")] + build_parol(); +} diff --git a/opslang-parser/src/lib.rs b/opslang-parser/src/lib.rs index cf3e8ed..dbf1828 100644 --- a/opslang-parser/src/lib.rs +++ b/opslang-parser/src/lib.rs @@ -1,476 +1,188 @@ -use opslang_ast::Row; -use peg::str::LineCol; +pub mod version; use thiserror::Error; +pub use version::*; -pub mod parser { - pub use crate::ops_parser::{row as parse_row, statements as parse_statements}; -} - -peg::parser! { - grammar ops_parser() for str { - use opslang_ast::*; - rule file_path() -> FilePath - = full_name:(file_path_section() ** (_ "/" _)) - { FilePath { full_name: full_name.join("/") } } - - rule file_path_section_ident() -> &'input str - = quiet!{ - e:$( [c if c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.']+) - {? if e.chars().all(|c| c == '.') { Err("") } else { Ok(e) } } - } - - rule file_path_section() -> &'input str - = file_path_section_ident() - / ".." { ".." } - / "." { "." } - - rule variable_path() -> VariablePath - = raw:ident() - { VariablePath { raw: raw.to_owned() } } - - rule tlm_ref() -> VariablePath - = "$" raw:ident() - { VariablePath { raw: raw.to_owned() } } - - rule ident() -> &'input str - = quiet!{$( - [c if c.is_ascii_alphabetic()] - [c if c.is_ascii_alphanumeric() || c == '_' || c == '/' || c == '.' || c == '-']* - )} / expected!("ident") - - rule alphanum_underscore() -> &'input str - = quiet!{$([c if c.is_ascii_alphanumeric() || c == '_']*)} / expected!("alphanum_underscore") - - rule receiver() -> ReceiverComponent - = exec_method:alphanum_underscore() "." name:alphanum_underscore() - { ReceiverComponent { name: name.to_owned(), exec_method: exec_method.to_owned() } } - rule executor() -> ExecutorComponent - = name:alphanum_underscore() - { ExecutorComponent { name: name.to_owned() } } - - rule time_indicator() -> Expr - = e:expr() ":" { e } // TODO: これで大丈夫か検討 - - rule destination_spec() -> DestinationSpec - = receiver_component:("@" r:receiver() { r })? _ - time_indicator:time_indicator()? _ - executor_component:("@@" e:executor() { e })? - { DestinationSpec { receiver_component, time_indicator, executor_component } } - - pub(crate) rule command() -> Command - = destination:destination_spec() _ name:command_name() _ args:(e:expr() _ {e})* - { Command { destination, name: name.to_owned(), args } } - - rule command_name() -> &'input str - = quiet!{$( - [c if c.is_ascii_alphabetic()] - [c if c.is_ascii_alphanumeric() || c == '_']* - )} / expected!("command name") - - pub(crate) rule expr() -> Expr - = precedence!{ - x:@ _ "||" _ y:(@) { Expr::BinOp(BinOpKind::Or, Box::new(x), Box::new(y)) } - x:@ _ "if" __ y:(@) { Expr::BinOp(BinOpKind::If, Box::new(x), Box::new(y)) } - -- - x:@ _ "&&" __ y:(@) { Expr::BinOp(BinOpKind::And, Box::new(x), Box::new(y)) } - -- - x:(@) _ e:eq_binop_kind() _ y:@ {Expr::BinOp(BinOpKind::Compare(e), Box::new(x), Box::new(y)) } - -- - x:(@) _ "in" __ y:@ { Expr::BinOp(BinOpKind::In, Box::new(x), Box::new(y)) } - x:(@) _ c:compare_binop_kind() _ y:@ { Expr::BinOp(BinOpKind::Compare(c), Box::new(x), Box::new(y)) } - -- - x:(@) _ "+" _ y:@ { Expr::BinOp(BinOpKind::Add, Box::new(x), Box::new(y)) } - x:(@) _ "-" _ y:@ { Expr::BinOp(BinOpKind::Sub, Box::new(x), Box::new(y)) } - "-" _ v:@ { Expr::UnOp(UnOpKind::Neg, Box::new(v)) } - -- - x:(@) _ "*" _ y:@ { Expr::BinOp(BinOpKind::Mul, Box::new(x), Box::new(y)) } - x:(@) _ "/" _ y:@ { Expr::BinOp(BinOpKind::Div, Box::new(x), Box::new(y)) } - x:(@) _ "%" _ y:@ { Expr::BinOp(BinOpKind::Mod, Box::new(x), Box::new(y)) } - -- - x:@ "(" _ v:(expr() ** (_ "," _)) _ ")" { Expr::FunCall(Box::new(x), v) } - -- - "(" _ v:expr() _ ")" { v } - n:literal() { Expr::Literal(n) } - v:variable_path() { Expr::Variable(v) } - v:tlm_ref() { Expr::TlmRef(v) } - } - - pub(crate) rule numeric() -> Numeric - = quiet!{"0x" i:$(['a'..='f' | 'A'..='F' | '0'..='9' | '_']+) - { Numeric::Integer(i.to_owned(), IntegerPrefix::Hexadecimal) } - / "0o" i:$(['0'..='7' | '_']+) - { Numeric::Integer(i.to_owned(), IntegerPrefix::Octal) } - / "0b" i:$(['0' | '1' | '_']+) - { Numeric::Integer(i.to_owned(), IntegerPrefix::Binary) } - / i:$(['0'..='9']['0'..='9' | '_']*) !['.' | 'e' | 'E'] - { Numeric::Integer(i.to_owned(), IntegerPrefix::Decimal) } - / f:$(['0'..='9']['0'..='9' | '_']* - "."? (['0'..='9']['0'..='9' | '_']*)? - (['e' | 'E']['+' | '-']['0'..='9' | '_']*)? - ) { Numeric::Float(f.to_owned()) }} / expected!("numeric") - - rule hex_digit() -> u8 - = quiet!{ - s:$(['a'..='f' | 'A'..='F' | '0'..='9']) {? - let c = s.chars().next().unwrap(); - match c { - '0'..='9' => Ok(c as u8 - '0' as u8), - 'a'..='f' => Ok(c as u8 - 'a' as u8 + 10), - 'A'..='F' => Ok(c as u8 - 'A' as u8 + 10), - _ => Err("invalid hex digit") - } - } - } / expected!("hexadecimal digit") - - rule hex_byte() -> u8 - = quiet!{ - high:(hex_digit()) low:(hex_digit()) {? - Ok(high << 4 | low) - } - } / expected!("hexadecimal byte") - - rule hex_bytes() -> Vec - = quiet!{ s:(hex_byte()*) } - - rule numeric_suffix() -> NumericSuffix - = "s" ![c if c.is_alphanumeric()] { NumericSuffix::Second } - - rule literal() -> Literal - = "[" _ v:(expr() ** (_ "," _)) _ "]" { Literal::Array(v) } - / "\"" s:$([c if c != '"']*) "\"" { Literal::String(s.to_owned()) } - / n:numeric() s:numeric_suffix()? { Literal::Numeric(n, s) } - / "time!" _ "(" _ content:$([c if c != ')']*) _ ")" {? - let datetime = chrono::DateTime::parse_from_rfc3339(content).map_err(|_| "valid datetime")?; - Ok(Literal::DateTime(datetime.into())) - } - / "tlmid!" _ "(" _ content:$([c if c != ')']*) _ ")" {? - Ok(Literal::TlmId(content.to_owned())) - } - / "hex_bytes!" _ "(" _ content:hex_bytes() _ ")" {? - Ok(Literal::Bytes(content)) - } - - rule compare_binop_kind() -> CompareBinOpKind - = ">=" { CompareBinOpKind::GreaterEq } - / "<=" { CompareBinOpKind::LessEq } - / ">" { CompareBinOpKind::Greater } - / "<" { CompareBinOpKind::Less } - - rule eq_binop_kind() -> CompareBinOpKind - = "!=" { CompareBinOpKind::NotEqual } - / "==" { CompareBinOpKind::Equal } - - pub(crate) rule call() -> Call - = "call" __ path:file_path() - { Call { path } } - - pub(crate) rule wait() -> Wait - = "wait" __ condition:expr() - { Wait { condition } } - - pub(crate) rule wait_inc() -> WaitInc - = "wait_inc" __ condition:expr() - { WaitInc { condition } } - - pub(crate) rule assert() -> Assert - = "assert" __ condition:expr() - { Assert { condition } } - - pub(crate) rule assert_eq() -> AssertEq - = "assert_eq" __ left:expr() _ right:expr() - { AssertEq { left, right, tolerance: None } } - - pub(crate) rule assert_approx_eq() -> AssertEq - = "assert_approx_eq" __ left:expr() _ right:expr() _ tolerance:expr() - { AssertEq { left, right, tolerance: Some(tolerance) } } - - pub(crate) rule let_bind() -> Let - = "let" __ raw:ident() _ "=" _ rhs:expr() - { Let { variable: Ident { raw: raw.to_owned()}, rhs } } - - pub(crate) rule print() -> Print - = "print" __ arg:expr() - { Print { arg } } +use std::{marker::PhantomData, path::PathBuf}; - pub(crate) rule return_() -> () - = "return" { } +pub(crate) mod parol_macro; - pub(crate) rule set() -> Set - = "set" __ name:variable_path() _ "=" _ expr:expr() - { Set { name, expr } } +/// A syntax element that can be parsed from a specific format. +/// +/// # Parameters +/// +/// - `Parser`: The type that distinguishes the parser. This is used to +/// differentiate between different parsing strategies or contexts. +pub trait ParseOps: Sized { + type Context; + type Error; - rule reserved_control() -> SingleStatement - = call:call() { SingleStatement::Call(call) } - / wait:wait() { SingleStatement::Wait(wait) } - / assert:assert() { SingleStatement::Assert(assert) } - / assert_eq:assert_eq() { SingleStatement::AssertEq(assert_eq) } - / assert_eq:assert_approx_eq() { SingleStatement::AssertEq(assert_eq) } - / let_bind:let_bind() { SingleStatement::Let(let_bind) } - / print:print() { SingleStatement::Print(print) } - / _:return_() { SingleStatement::Return } - / set:set() { SingleStatement::Set(set) } - / command:command() { SingleStatement::Command(command) } - - rule comment() -> Comment - = "#" _ s:$([c if c != '\n']*) { Comment(s.to_owned()) } - - pub rule row_() -> Row - = _ breaks:"."? _ r:( - content:reserved_control() _ comment_trailing:comment()? - { Row { breaks, content: Some(content), comment_trailing } } - / comment_trailing:comment()? - { Row { breaks, content: None, comment_trailing } } - ) { r } - - pub rule row() -> SRow - = spanned() - - rule block_delay() -> Expr - = "delay" _ "=" _ e:expr() { e } - - - rule row_line() -> SRow - = row:row() _ newline() { row } - - pub rule block_() -> Block - = _ default_receiver_component:("@" r:receiver(){r})? _ delay:block_delay()? - _ "{" _ comment_first:comment()? newline() - rows:(row_line()*) - _ "}" _ comment_last:comment()? - { Block { default_receiver_component, delay, rows, comment_first, comment_last } } - - pub rule block() -> SBlock - = spanned() + fn parse(from: Format, context: Self::Context) -> Result; +} - pub rule statement() -> Statement - = block:block() { Statement::Block(block) } - / row:row() { Statement::Single(row) } +/// A marker trait for input formats. +#[diagnostic::on_unimplemented( + message = "the type `{Self}` is not a valid input format", + label = "this type does not implement the `InputFormat` trait" +)] +pub trait InputFormat {} + +/// An input structure for the parser. +pub struct ParserInput<'a> { + /// The string content to be parsed. + pub content: &'a str, + + /// The name of the file from which the content was read. + /// + /// FIXME: This is specific to V1 and not used for accessing the content. + pub file_name: PathBuf, +} - pub rule statements() -> Vec - = s:statement() ** (_ newline()) { s } +impl<'a> ParserInput<'a> { + /// Assumes that the input is in the format of the inferred grammar version. + pub fn assume_inferred(self) -> Versioned { + Versioned::assume_inferred(self) + } +} - rule ws() = quiet!{[c if c.is_whitespace() && c != '\n']} - rule _() = ws()* - rule __() = ![c if c.is_alphanumeric()] _ - rule newline() = "\n" +/// A wrapper type for a value that is assumed to be in the specific format. +pub struct Versioned(pub T, PhantomData); +impl InputFormat for Versioned {} +impl Versioned { + /// Creates a [`Versioned`] instance with the given value. + /// + /// This is useful when the type system already knows the version of the value. + pub fn assume_inferred(value: T) -> Self { + Self(value, PhantomData) + } - // cf. https://github.com/kevinmehall/rust-peg/issues/283#issuecomment-1014858352 - rule spanned(inner : rule) -> Spanned - = b:position!() value:inner() e:position!() { Spanned { span: b..e, value } } + /// Creates a [`Versioned`] instance with an assumed version and the given value. + /// + /// This is useful when you want to explicitly specify the version at the point of parsing, not just at the type level. + /// If the type system already knows the version, you can use [`Versioned::assume_inferred`]. + pub fn assume_version(version: Version, value: T) -> Self { + let _ = version; + Self(value, PhantomData) } } #[derive(Debug, Error)] -pub enum Error { - #[error("parse failed: {0}")] - ParseError(#[from] peg::error::ParseError), +/// An error type that is thrown when the self-describing parser encounters an error. +pub enum SelfDescribingError<'a, E> { + /// An error that occurred while parsing the shebang line. + #[error(transparent)] + ShebangSearchError(ShebangSearchError<'a>), + #[error("version mismatch: expected '{expected}', found '{found}'")] + VersionMismatch { + /// The expected version of the parser. + expected: &'static str, + /// The found version in the input. + found: &'a str, + }, + #[error(transparent)] + Other(#[from] E), } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_numeric() { - let r = ops_parser::numeric("5e-3"); - dbg!(r.unwrap()); - let r = ops_parser::numeric("0"); - dbg!(r.unwrap()); - let r = ops_parser::numeric("10"); - dbg!(r.unwrap()); - let r = ops_parser::numeric("0.1"); - dbg!(r.unwrap()); - } - #[test] - fn test_expr() { - let r = ops_parser::expr("a + b * c"); - dbg!(r.unwrap()); - let r = ops_parser::expr("a * b + c"); - dbg!(r.unwrap()); - let r = ops_parser::expr("1 + (a.a * (0xB_C))"); - dbg!(r.unwrap()); - let r = ops_parser::expr("a((c), d) + b"); - dbg!(r.unwrap()); - let r = ops_parser::expr("ABC.DEF == 0xabcdef || 5s"); - dbg!(r.unwrap()); - let r = ops_parser::expr(r#"time!(2021-01-01T00:00:00.00Z)"#); - dbg!(r.unwrap()); - let r = ops_parser::expr(r#"time!(2021-01-01T00:00:00.00+09:00)"#); - dbg!(r.unwrap()); - let r = ops_parser::expr(r#"tlmid!(AB.CD.EF)"#); - dbg!(r.unwrap()); - let r = ops_parser::expr(r#"hex_bytes!(0123456789abcdefABCDEF)"#); - dbg!(r.unwrap()); - } - - #[test] - fn test_space() { - fn differ( - f: impl Fn(&'static str) -> Result, - l: &'static str, - r: &'static str, - ) { - let l = f(l).unwrap(); - let r = f(r).unwrap(); - assert_ne!(l, r); - } - fn not_differ( - f: impl Fn(&'static str) -> Result, - l: &'static str, - r: &'static str, - ) { - let l = f(l).unwrap(); - let r = f(r).unwrap(); - assert_eq!(l, r); +pub struct SelfDescribingParser(PhantomData); + +impl<'a> InputFormat for ParserInput<'a> {} +impl< + 'a, + Version: ParserVersion, + T: ParseOps>, Version> + opslang_ast::version::Versioned, +> ParseOps, SelfDescribingParser> for T +{ + type Context = T::Context; + + type Error = SelfDescribingError<'a, T::Error>; + + fn parse(from: ParserInput<'a>, context: Self::Context) -> Result { + // parse version from the input content + let version_found = Shebang::parse(from.content) + .map_err(SelfDescribingError::ShebangSearchError)? + .lang; + // check if the version matches the expected version + if version_found != T::version() { + return Err(SelfDescribingError::VersionMismatch { + expected: T::version(), + found: version_found, + }); } - differ( - ops_parser::expr, - "EXAMPLE.VARIABLE.NAME/s", - "EXAMPLE.VARIBLAE.NAME / s", - ); - not_differ( - ops_parser::assert, - "assert x in [ 100, 200 ]", - "assert x in[ 100,200]", - ); - not_differ(ops_parser::let_bind, "let variable=0", "let variable = 0"); - } - #[test] - fn test_error_msg() { - let r = ops_parser::let_bind("let !"); - assert!(r.unwrap_err().to_string().contains("ident")); - } - #[test] - fn test_fun_call() { - let r = ops_parser::let_bind( - "let result_of_test_fun = Test.fun2(Test.fun1([P.VEC.X, P.VEC.Y, P.VEC.Z]))", - ); - dbg!(r.unwrap()); - } - #[test] - fn test_call() { - let r = ops_parser::call("call OTHER_FILE.ops"); - dbg!(r.unwrap()); - let r = ops_parser::call("call ./OTHER_FILE.ops"); - dbg!(r.unwrap()); - let r = ops_parser::call("call ../.another_dir/../x.y.z"); - dbg!(r.unwrap()); - let r = ops_parser::call("call x/.../fail"); - assert!(r.is_err()); - } - #[test] - fn test_wait() { - let r = ops_parser::wait("wait 12s"); - dbg!(r.unwrap()); - let r = ops_parser::wait("wait 0.1s"); - dbg!(r.unwrap()); - let r = ops_parser::wait("wait 1 == 1"); - dbg!(r.unwrap()); - let r = ops_parser::wait("wait HEX.VALUE == 0x0123cdef || 5s"); - dbg!(r.unwrap()); - let r = ops_parser::wait("wait SOME.CONDITION.TO.BE.TESTED == FALSE"); - dbg!(r.unwrap()); - } - #[test] - fn test_assert() { - let r = ops_parser::assert("assert TEST.VAR1 < 0.05"); - dbg!(r.unwrap()); - let r = ops_parser::assert("assert TEST.VAR2.X in [ 0.01, 0.04 ]"); - dbg!(r.unwrap()); - let r = ops_parser::assert(r#"assert TEST.VAR_3 == "OFF""#); - dbg!(r.unwrap()); - let r = ops_parser::assert(r#"assert TEST.VAR_4.X in [ 0, 0.07 ] if TEST.Var5 == "OFF""#); - dbg!(r.unwrap()); + // parse the input using the versioned format + T::parse(Versioned::assume_inferred(from), context).map_err(SelfDescribingError::Other) } +} - #[test] - fn test_return() { - let r = ops_parser::return_("return"); - dbg!(r.unwrap()); - let r = ops_parser::return_("return 0"); - assert!(r.is_err()); - } - #[test] - fn test_let() { - let r = ops_parser::let_bind("let relative_x = relative_x + 9"); - dbg!(r.unwrap()); - let r = ops_parser::let_bind("let HYPHEN-IS_VALID = 1"); - dbg!(r.unwrap()); - } - #[test] - fn test_print() { - let r = ops_parser::print("print abc_xyz"); - dbg!(r.unwrap()); - let r = ops_parser::print("print $A.B"); - dbg!(r.unwrap()); - } - #[test] - fn test_set() { - let r = ops_parser::set("set A.B = 1"); - dbg!(r.unwrap()); - } - #[test] - fn test_command() { - let r = ops_parser::command("DO_IT"); - dbg!(r.unwrap()); - let r = ops_parser::command("@ABC.DEF DO_IT"); - dbg!(r.unwrap()); - let r = ops_parser::command("@ABC.DEF CMD_WITH_ARGS some_value 0xaa 0xbb 2"); - dbg!(r.unwrap()); - let r = ops_parser::command("@ABC.DEF @@G CMD_WITH_ARGS relative_x 0xcc 0xdd 0xee 0xff"); - dbg!(r.unwrap()); - } - #[test] - fn test_block() { - let r = ops_parser::block( - r#"{ #comment - let x = 2 - . call OTHER_FILE.ops - . #hello -}"#, - ); - dbg!(r.unwrap()); +pub struct Shebang<'a> { + pub lang: &'a str, +} - let r = ops_parser::block( - r#"delay=1s { - let x = 2 - @AB.CD @@GH DO_IT -} #comment"#, - ); - dbg!(r.unwrap()); - let r = ops_parser::block( - r#" @AB.CD delay=1s { - 0: DO_IT - 0 + 1: @@EF DO_IT 1 2 3 - 2: DO_IT x y z - @XY.ZW FOO_BAR tlmid!(AB.CD) - wait 1 == 1 -}"#, - ); - dbg!(r.unwrap()); - } +#[derive(Debug, Error)] +pub enum ShebangSearchError<'a> { + /// The content is empty, so no shebang line can be found. + #[error("the file is empty, no shebang line found")] + FileIsEmpty, + + /// The shebang line was not found in the first line of the content. + #[error("the first line is not a shebang line")] + FirstLineIsNotShebang, + + /// An syntax error occurred while parsing the shebang line. + #[error("syntax error in shebang line: expected {expected}, found '{found}'")] + SyntaxError { + expected: &'static str, + found: &'a str, + }, +} - #[test] - fn test_file() { - let s = include_str!("../tests/test.ops"); - let r = ops_parser::statements(s); - dbg!(r.unwrap()); - } - #[test] - fn test_rows() { - let s = r#".# ****** # - .set X.Y=2 - .let CURRENT_EXAMPLE_TLM_VALUE = FOO.BAR.EXAMPLE_TLM.VALUE - .@@DEF DO_IT - wait $FOO.BAR.EXAMPLE_TLM.VALUE > CURRENT_EXAMPLE_TLM_VALUE || 5s - let foobar = $FOO.BAR - wait foobar.EXAMPLE_TLM.VALUE > CURRENT_EXAMPLE_TLM_VALUE || 5s - return - "#; - for l in s.lines() { - let r = ops_parser::row(l); - dbg!(r.unwrap()); +impl<'a> Shebang<'a> { + pub fn parse(content: &'a str) -> Result> { + // currently, we assume the version is at the start of the content + let Some(first_line) = content.lines().next() else { + return Err(ShebangSearchError::FileIsEmpty); + }; + let trimmed = first_line.trim(); + let Some(shebang) = trimmed.strip_prefix("#!") else { + return Err(ShebangSearchError::FirstLineIsNotShebang); + }; + + // handwritten parser for the shebang line + // parses shebangs like: "#! lang=v1" + let mut shebang_input = shebang.trim(); + + if let Some(next) = shebang_input.strip_prefix("lang") { + shebang_input = next.trim(); + let Some(next) = shebang_input.strip_prefix("=") else { + return Err(ShebangSearchError::SyntaxError { + expected: "`=` after `lang`", + found: shebang_input, + }); + }; + shebang_input = next.trim(); + + let (value, next) = shebang_input + .split_once(|c: char| !c.is_ascii_alphanumeric()) + .unwrap_or((shebang_input, "")); + + if value.is_empty() { + return Err(ShebangSearchError::SyntaxError { + expected: "identifier after `=`", + found: shebang_input, + }); + }; + shebang_input = next.trim(); + if !shebang_input.is_empty() { + return Err(ShebangSearchError::SyntaxError { + expected: "end of line after identifier", + found: shebang_input, + }); + } + Ok(Shebang { lang: value }) + } else { + Err(ShebangSearchError::SyntaxError { + expected: "`lang` in the shebang line", + found: shebang_input, + }) } } } diff --git a/opslang-parser/src/parol_macro.rs b/opslang-parser/src/parol_macro.rs new file mode 100644 index 0000000..f58d65a --- /dev/null +++ b/opslang-parser/src/parol_macro.rs @@ -0,0 +1,14 @@ +// This file is generated by `build.rs`. +// Do not edit it manually. + +#[macro_export] +/// Redirect due to `actions_output_file` depending on `user_trait_module_name` in fact. +/// +/// This macro is generated by `build.rs`. +macro_rules! redirect_parol { + () => { + mod parse_trait { + pub use super::generated::grammar_trait::ActionAuto; + } + }; +} diff --git a/opslang-parser/src/version.rs b/opslang-parser/src/version.rs new file mode 100644 index 0000000..482d4ba --- /dev/null +++ b/opslang-parser/src/version.rs @@ -0,0 +1,42 @@ +/// A marker trait for parser versions. +pub trait ParserVersion {} + +/// A macro to declare parser versions and their associated modules. +/// +/// Note that this macro **re-exports** the types from the module. +macro_rules! declare_versions { + ( + $( + $([$current:vis])? $path:ident, $ty:ident; + )* + ) => { + $( + pub mod $path; + pub struct $ty; + impl ParserVersion for $ty {} + + $( + /// Type alias for the default version of the parser. + $current type Default = $ty; + + // Re-export the types from the module + $current use $path::*; + )? + )* + + // assert that `[pub]` is used only once + + /// Assertion that [`Default`] type alias exists at this scope. + /// + /// This is a compile-time check that will fail if [`Default`] is not defined. + #[allow(dead_code)] + const _: () = { + let _: Default; + }; + } +} + +declare_versions! { + [pub] v0, V0; + v1, V1; +} diff --git a/opslang-parser/src/version/v0.rs b/opslang-parser/src/version/v0.rs new file mode 100644 index 0000000..b8c7ea2 --- /dev/null +++ b/opslang-parser/src/version/v0.rs @@ -0,0 +1,494 @@ +use opslang_ast::v0::Row; + +use crate::{ParseOps, Versioned}; + +type This = super::V0; + +pub type AssumeV0Format = Versioned; + +impl<'a> ParseOps, This> for opslang_ast::v0::SRow { + type Context = (); + + type Error = peg::error::ParseError<::PositionRepr>; + + fn parse(from: AssumeV0Format<&'a str>, _context: Self::Context) -> Result { + ops_parser::row(from.0) + } +} + +impl<'a> ParseOps, This> for Vec { + type Context = (); + + type Error = peg::error::ParseError<::PositionRepr>; + + fn parse(from: AssumeV0Format<&'a str>, _context: Self::Context) -> Result { + ops_parser::statements(from.0) + } +} + +pub mod parser { + pub use super::ops_parser::{row as parse_row, statements as parse_statements}; +} + +peg::parser! { + grammar ops_parser() for str { + use opslang_ast::v0::*; + rule file_path() -> FilePath + = full_name:(file_path_section() ** (_ "/" _)) + { FilePath { full_name: full_name.join("/") } } + + rule file_path_section_ident() -> &'input str + = quiet!{ + e:$( [c if c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.']+) + {? if e.chars().all(|c| c == '.') { Err("") } else { Ok(e) } } + } + + rule file_path_section() -> &'input str + = file_path_section_ident() + / ".." { ".." } + / "." { "." } + + rule variable_path() -> VariablePath + = raw:ident() + { VariablePath { raw: raw.to_owned() } } + + rule tlm_ref() -> VariablePath + = "$" raw:ident() + { VariablePath { raw: raw.to_owned() } } + + rule ident() -> &'input str + = quiet!{$( + [c if c.is_ascii_alphabetic()] + [c if c.is_ascii_alphanumeric() || c == '_' || c == '/' || c == '.' || c == '-']* + )} / expected!("ident") + + rule alphanum_underscore() -> &'input str + = quiet!{$([c if c.is_ascii_alphanumeric() || c == '_']*)} / expected!("alphanum_underscore") + + rule receiver() -> ReceiverComponent + = exec_method:alphanum_underscore() "." name:alphanum_underscore() + { ReceiverComponent { name: name.to_owned(), exec_method: exec_method.to_owned() } } + rule executor() -> ExecutorComponent + = name:alphanum_underscore() + { ExecutorComponent { name: name.to_owned() } } + + rule time_indicator() -> Expr + = e:expr() ":" { e } // TODO: これで大丈夫か検討 + + rule destination_spec() -> DestinationSpec + = receiver_component:("@" r:receiver() { r })? _ + time_indicator:time_indicator()? _ + executor_component:("@@" e:executor() { e })? + { DestinationSpec { receiver_component, time_indicator, executor_component } } + + pub(crate) rule command() -> Command + = destination:destination_spec() _ name:command_name() _ args:(e:expr() _ {e})* + { Command { destination, name: name.to_owned(), args } } + + rule command_name() -> &'input str + = quiet!{$( + [c if c.is_ascii_alphabetic()] + [c if c.is_ascii_alphanumeric() || c == '_']* + )} / expected!("command name") + + pub(crate) rule expr() -> Expr + = precedence!{ + x:@ _ "||" _ y:(@) { Expr::BinOp(BinOpKind::Or, Box::new(x), Box::new(y)) } + x:@ _ "if" __ y:(@) { Expr::BinOp(BinOpKind::If, Box::new(x), Box::new(y)) } + -- + x:@ _ "&&" __ y:(@) { Expr::BinOp(BinOpKind::And, Box::new(x), Box::new(y)) } + -- + x:(@) _ e:eq_binop_kind() _ y:@ {Expr::BinOp(BinOpKind::Compare(e), Box::new(x), Box::new(y)) } + -- + x:(@) _ "in" __ y:@ { Expr::BinOp(BinOpKind::In, Box::new(x), Box::new(y)) } + x:(@) _ c:compare_binop_kind() _ y:@ { Expr::BinOp(BinOpKind::Compare(c), Box::new(x), Box::new(y)) } + -- + x:(@) _ "+" _ y:@ { Expr::BinOp(BinOpKind::Add, Box::new(x), Box::new(y)) } + x:(@) _ "-" _ y:@ { Expr::BinOp(BinOpKind::Sub, Box::new(x), Box::new(y)) } + "-" _ v:@ { Expr::UnOp(UnOpKind::Neg, Box::new(v)) } + -- + x:(@) _ "*" _ y:@ { Expr::BinOp(BinOpKind::Mul, Box::new(x), Box::new(y)) } + x:(@) _ "/" _ y:@ { Expr::BinOp(BinOpKind::Div, Box::new(x), Box::new(y)) } + x:(@) _ "%" _ y:@ { Expr::BinOp(BinOpKind::Mod, Box::new(x), Box::new(y)) } + -- + x:@ "(" _ v:(expr() ** (_ "," _)) _ ")" { Expr::FunCall(Box::new(x), v) } + -- + "(" _ v:expr() _ ")" { v } + n:literal() { Expr::Literal(n) } + v:variable_path() { Expr::Variable(v) } + v:tlm_ref() { Expr::TlmRef(v) } + } + + pub(crate) rule numeric() -> Numeric + = quiet!{"0x" i:$(['a'..='f' | 'A'..='F' | '0'..='9' | '_']+) + { Numeric::Integer(i.to_owned(), IntegerPrefix::Hexadecimal) } + / "0o" i:$(['0'..='7' | '_']+) + { Numeric::Integer(i.to_owned(), IntegerPrefix::Octal) } + / "0b" i:$(['0' | '1' | '_']+) + { Numeric::Integer(i.to_owned(), IntegerPrefix::Binary) } + / i:$(['0'..='9']['0'..='9' | '_']*) !['.' | 'e' | 'E'] + { Numeric::Integer(i.to_owned(), IntegerPrefix::Decimal) } + / f:$(['0'..='9']['0'..='9' | '_']* + "."? (['0'..='9']['0'..='9' | '_']*)? + (['e' | 'E']['+' | '-']['0'..='9' | '_']*)? + ) { Numeric::Float(f.to_owned()) }} / expected!("numeric") + + rule hex_digit() -> u8 + = quiet!{ + s:$(['a'..='f' | 'A'..='F' | '0'..='9']) {? + let c = s.chars().next().unwrap(); + match c { + '0'..='9' => Ok(c as u8 - b'0'), + 'a'..='f' => Ok(c as u8 - b'a' + 10), + 'A'..='F' => Ok(c as u8 - b'A' + 10), + _ => Err("invalid hex digit") + } + } + } / expected!("hexadecimal digit") + + rule hex_byte() -> u8 + = quiet!{ + high:(hex_digit()) low:(hex_digit()) {? + Ok(high << 4 | low) + } + } / expected!("hexadecimal byte") + + rule hex_bytes() -> Vec + = quiet!{ s:(hex_byte()*) } + + rule numeric_suffix() -> NumericSuffix + = "s" ![c if c.is_alphanumeric()] { NumericSuffix::Second } + + rule literal() -> Literal + = "[" _ v:(expr() ** (_ "," _)) _ "]" { Literal::Array(v) } + / "\"" s:$([c if c != '"']*) "\"" { Literal::String(s.to_owned()) } + / n:numeric() s:numeric_suffix()? { Literal::Numeric(n, s) } + / "time!" _ "(" _ content:$([c if c != ')']*) _ ")" {? + let datetime = chrono::DateTime::parse_from_rfc3339(content).map_err(|_| "valid datetime")?; + Ok(Literal::DateTime(datetime.into())) + } + / "tlmid!" _ "(" _ content:$([c if c != ')']*) _ ")" {? + Ok(Literal::TlmId(content.to_owned())) + } + / "hex_bytes!" _ "(" _ content:hex_bytes() _ ")" {? + Ok(Literal::Bytes(content)) + } + + rule compare_binop_kind() -> CompareBinOpKind + = ">=" { CompareBinOpKind::GreaterEq } + / "<=" { CompareBinOpKind::LessEq } + / ">" { CompareBinOpKind::Greater } + / "<" { CompareBinOpKind::Less } + + rule eq_binop_kind() -> CompareBinOpKind + = "!=" { CompareBinOpKind::NotEqual } + / "==" { CompareBinOpKind::Equal } + + pub(crate) rule call() -> Call + = "call" __ path:file_path() + { Call { path } } + + pub(crate) rule wait() -> Wait + = "wait" __ condition:expr() + { Wait { condition } } + + pub(crate) rule wait_inc() -> WaitInc + = "wait_inc" __ condition:expr() + { WaitInc { condition } } + + pub(crate) rule assert() -> Assert + = "assert" __ condition:expr() + { Assert { condition } } + + pub(crate) rule assert_eq() -> AssertEq + = "assert_eq" __ left:expr() _ right:expr() + { AssertEq { left, right, tolerance: None } } + + pub(crate) rule assert_approx_eq() -> AssertEq + = "assert_approx_eq" __ left:expr() _ right:expr() _ tolerance:expr() + { AssertEq { left, right, tolerance: Some(tolerance) } } + + pub(crate) rule let_bind() -> Let + = "let" __ raw:ident() _ "=" _ rhs:expr() + { Let { variable: Ident { raw: raw.to_owned()}, rhs } } + + pub(crate) rule print() -> Print + = "print" __ arg:expr() + { Print { arg } } + + pub(crate) rule return_() -> () + = "return" { } + + pub(crate) rule set() -> Set + = "set" __ name:variable_path() _ "=" _ expr:expr() + { Set { name, expr } } + + rule reserved_control() -> SingleStatement + = call:call() { SingleStatement::Call(call) } + / wait:wait() { SingleStatement::Wait(wait) } + / assert:assert() { SingleStatement::Assert(assert) } + / assert_eq:assert_eq() { SingleStatement::AssertEq(assert_eq) } + / assert_eq:assert_approx_eq() { SingleStatement::AssertEq(assert_eq) } + / let_bind:let_bind() { SingleStatement::Let(let_bind) } + / print:print() { SingleStatement::Print(print) } + / _:return_() { SingleStatement::Return } + / set:set() { SingleStatement::Set(set) } + / command:command() { SingleStatement::Command(command) } + + rule comment() -> Comment + = "#" s:$([c if c != '\n']*) { Comment(s.to_owned()) } + + pub rule row_() -> Row + = _ breaks:"."? _ r:( + content:reserved_control() _ comment_trailing:comment()? + { Row { breaks, content: Some(content), comment_trailing } } + / comment_trailing:comment()? + { Row { breaks, content: None, comment_trailing } } + ) { r } + + pub rule row() -> SRow + = spanned() + + rule block_delay() -> Expr + = "delay" _ "=" _ e:expr() { e } + + + rule row_line() -> SRow + = row:row() _ newline() { row } + + pub rule block_() -> Block + = _ default_receiver_component:("@" r:receiver(){r})? _ delay:block_delay()? + _ "{" _ comment_first:comment()? newline() + rows:(row_line()*) + _ "}" _ comment_last:comment()? + { Block { default_receiver_component, delay, rows, comment_first, comment_last } } + + pub rule block() -> SBlock + = spanned() + + pub rule statement() -> Statement + = block:block() { Statement::Block(block) } + / row:row() { Statement::Single(row) } + + pub rule statements() -> Vec + = s:statement() ** (_ newline()) { s } + + rule ws() = quiet!{[c if c.is_whitespace() && c != '\n']} + rule _() = ws()* + rule __() = ![c if c.is_alphanumeric()] _ + rule newline() = "\n" + + + // cf. https://github.com/kevinmehall/rust-peg/issues/283#issuecomment-1014858352 + rule spanned(inner : rule) -> Spanned + = b:position!() value:inner() e:position!() { Spanned { span: b..e, value } } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_numeric() { + let r = ops_parser::numeric("5e-3"); + dbg!(r.unwrap()); + let r = ops_parser::numeric("0"); + dbg!(r.unwrap()); + let r = ops_parser::numeric("10"); + dbg!(r.unwrap()); + let r = ops_parser::numeric("0.1"); + dbg!(r.unwrap()); + } + #[test] + fn test_expr() { + let r = ops_parser::expr("a + b * c"); + dbg!(r.unwrap()); + let r = ops_parser::expr("a * b + c"); + dbg!(r.unwrap()); + let r = ops_parser::expr("1 + (a.a * (0xB_C))"); + dbg!(r.unwrap()); + let r = ops_parser::expr("a((c), d) + b"); + dbg!(r.unwrap()); + let r = ops_parser::expr("ABC.DEF == 0xabcdef || 5s"); + dbg!(r.unwrap()); + let r = ops_parser::expr(r#"time!(2021-01-01T00:00:00.00Z)"#); + dbg!(r.unwrap()); + let r = ops_parser::expr(r#"time!(2021-01-01T00:00:00.00+09:00)"#); + dbg!(r.unwrap()); + let r = ops_parser::expr(r#"tlmid!(AB.CD.EF)"#); + dbg!(r.unwrap()); + let r = ops_parser::expr(r#"hex_bytes!(0123456789abcdefABCDEF)"#); + dbg!(r.unwrap()); + } + + #[test] + fn test_space() { + fn differ( + f: impl Fn(&'static str) -> Result, + l: &'static str, + r: &'static str, + ) { + let l = f(l).unwrap(); + let r = f(r).unwrap(); + assert_ne!(l, r); + } + fn not_differ( + f: impl Fn(&'static str) -> Result, + l: &'static str, + r: &'static str, + ) { + let l = f(l).unwrap(); + let r = f(r).unwrap(); + assert_eq!(l, r); + } + differ( + ops_parser::expr, + "EXAMPLE.VARIABLE.NAME/s", + "EXAMPLE.VARIBLAE.NAME / s", + ); + not_differ( + ops_parser::assert, + "assert x in [ 100, 200 ]", + "assert x in[ 100,200]", + ); + not_differ(ops_parser::let_bind, "let variable=0", "let variable = 0"); + } + #[test] + fn test_error_msg() { + let r = ops_parser::let_bind("let !"); + assert!(r.unwrap_err().to_string().contains("ident")); + } + #[test] + fn test_fun_call() { + let r = ops_parser::let_bind( + "let result_of_test_fun = Test.fun2(Test.fun1([P.VEC.X, P.VEC.Y, P.VEC.Z]))", + ); + dbg!(r.unwrap()); + } + #[test] + fn test_call() { + let r = ops_parser::call("call OTHER_FILE.ops"); + dbg!(r.unwrap()); + let r = ops_parser::call("call ./OTHER_FILE.ops"); + dbg!(r.unwrap()); + let r = ops_parser::call("call ../.another_dir/../x.y.z"); + dbg!(r.unwrap()); + let r = ops_parser::call("call x/.../fail"); + assert!(r.is_err()); + } + #[test] + fn test_wait() { + let r = ops_parser::wait("wait 12s"); + dbg!(r.unwrap()); + let r = ops_parser::wait("wait 0.1s"); + dbg!(r.unwrap()); + let r = ops_parser::wait("wait 1 == 1"); + dbg!(r.unwrap()); + let r = ops_parser::wait("wait HEX.VALUE == 0x0123cdef || 5s"); + dbg!(r.unwrap()); + let r = ops_parser::wait("wait SOME.CONDITION.TO.BE.TESTED == FALSE"); + dbg!(r.unwrap()); + } + #[test] + fn test_assert() { + let r = ops_parser::assert("assert TEST.VAR1 < 0.05"); + dbg!(r.unwrap()); + let r = ops_parser::assert("assert TEST.VAR2.X in [ 0.01, 0.04 ]"); + dbg!(r.unwrap()); + let r = ops_parser::assert(r#"assert TEST.VAR_3 == "OFF""#); + dbg!(r.unwrap()); + let r = ops_parser::assert(r#"assert TEST.VAR_4.X in [ 0, 0.07 ] if TEST.Var5 == "OFF""#); + dbg!(r.unwrap()); + } + + #[test] + fn test_return() { + let r = ops_parser::return_("return"); + dbg!(r.unwrap()); + let r = ops_parser::return_("return 0"); + assert!(r.is_err()); + } + #[test] + fn test_let() { + let r = ops_parser::let_bind("let relative_x = relative_x + 9"); + dbg!(r.unwrap()); + let r = ops_parser::let_bind("let HYPHEN-IS_VALID = 1"); + dbg!(r.unwrap()); + } + #[test] + fn test_print() { + let r = ops_parser::print("print abc_xyz"); + dbg!(r.unwrap()); + let r = ops_parser::print("print $A.B"); + dbg!(r.unwrap()); + } + #[test] + fn test_set() { + let r = ops_parser::set("set A.B = 1"); + dbg!(r.unwrap()); + } + #[test] + fn test_command() { + let r = ops_parser::command("DO_IT"); + dbg!(r.unwrap()); + let r = ops_parser::command("@ABC.DEF DO_IT"); + dbg!(r.unwrap()); + let r = ops_parser::command("@ABC.DEF CMD_WITH_ARGS some_value 0xaa 0xbb 2"); + dbg!(r.unwrap()); + let r = ops_parser::command("@ABC.DEF @@G CMD_WITH_ARGS relative_x 0xcc 0xdd 0xee 0xff"); + dbg!(r.unwrap()); + } + #[test] + fn test_block() { + let r = ops_parser::block( + r#"{ #comment + let x = 2 + . call OTHER_FILE.ops + . #hello +}"#, + ); + dbg!(r.unwrap()); + + let r = ops_parser::block( + r#"delay=1s { + let x = 2 + @AB.CD @@GH DO_IT +} #comment"#, + ); + dbg!(r.unwrap()); + let r = ops_parser::block( + r#" @AB.CD delay=1s { + 0: DO_IT + 0 + 1: @@EF DO_IT 1 2 3 + 2: DO_IT x y z + @XY.ZW FOO_BAR tlmid!(AB.CD) + wait 1 == 1 +}"#, + ); + dbg!(r.unwrap()); + } + + #[test] + fn test_file() { + let s = include_str!("../../tests/test.ops"); + let r = ops_parser::statements(s); + dbg!(r.unwrap()); + } + #[test] + fn test_rows() { + let s = r#".# ****** # + .set X.Y=2 + .let CURRENT_EXAMPLE_TLM_VALUE = FOO.BAR.EXAMPLE_TLM.VALUE + .@@DEF DO_IT + wait $FOO.BAR.EXAMPLE_TLM.VALUE > CURRENT_EXAMPLE_TLM_VALUE || 5s + let foobar = $FOO.BAR + wait foobar.EXAMPLE_TLM.VALUE > CURRENT_EXAMPLE_TLM_VALUE || 5s + return + "#; + for l in s.lines() { + let r = ops_parser::row(l); + dbg!(r.unwrap()); + } + } +} diff --git a/opslang-parser/src/version/v1.rs b/opslang-parser/src/version/v1.rs new file mode 100644 index 0000000..d45d317 --- /dev/null +++ b/opslang-parser/src/version/v1.rs @@ -0,0 +1,167 @@ +mod generated; +mod parse; + +crate::redirect_parol!(); + +use opslang_ast::v1::context::Context; + +use crate::{ParseOps, ParserInput, Versioned}; + +type This = super::V1; + +pub type AssumeV1Format = Versioned; + +impl<'cx> ParseOps>, This> for opslang_ast::v1::Program<'cx> { + type Context = &'cx Context<'cx>; + + type Error = parol_runtime::ParolError; + + fn parse( + Versioned(ParserInput { content, file_name }, _): AssumeV1Format>, + context: Self::Context, + ) -> Result { + let mut action = parse::Action::new(context); + let _ = generated::parser::parse(content, file_name, &mut action)?; + Ok(action.finish()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_file() { + let input_str = include_str!("../../tests/test_v1.ops"); + // input method 1 + let input = ParserInput { + content: input_str, + file_name: "test_v1.ops".into(), + } + .assume_inferred(); + let context = Context::new(); + let result = opslang_ast::v1::Program::parse(input, &context); + assert!( + result.is_ok(), + "Failed to parse test_v1.ops: {:?}", + result.err() + ); + + // input method 2 + let input = ParserInput { + content: input_str, + file_name: "test_v1.ops".into(), + }; + let context = Context::new(); + let result = opslang_ast::v1::Program::parse(input, &context); + assert!( + result.is_ok(), + "Failed to parse test_v1.ops: {:?}", + result.err() + ); + } + + #[test] + fn test_parse_integer_literals_with_suffixes() { + let source = r#"#! lang=v1 +prc main() { + let i8_val = 42i8; + let i16_val = 1000i16; + let i32_val = 50000i32; + let i64_val = 1234567890i64; + + let u8_val = 255u8; + let u16_val = 65535u16; + let u32_val = 4294967295u32; + let u64_val = 18446744073709551615u64; + return; +} +"#; + + let input = ParserInput { + content: source, + file_name: "test_integer_literals.ops".into(), + }; + let context = Context::new(); + let result = opslang_ast::v1::Program::parse(input, &context); + assert!( + result.is_ok(), + "Failed to parse integer literals: {:?}", + result.err() + ); + } + + #[test] + fn test_parse_float_literals_with_suffixes() { + let source = r#"#! lang=v1 +prc main() { + let f32_val = 3.14f32; + let f64_val = 2.71828f64; + let float_var = 1.0f; + return; +} +"#; + + let input = ParserInput { + content: source, + file_name: "test_float_literals.ops".into(), + }; + let context = Context::new(); + let result = opslang_ast::v1::Program::parse(input, &context); + assert!( + result.is_ok(), + "Failed to parse float literals: {:?}", + result.err() + ); + } + + #[test] + fn test_parse_duration_literals() { + let source = r#"#! lang=v1 +prc main() { + let seconds = 30s; + let milliseconds = 500ms; + let microseconds = 1000us; + let nanoseconds = 123456ns; + return; +} +"#; + + let input = ParserInput { + content: source, + file_name: "test_duration_literals.ops".into(), + }; + let context = Context::new(); + let result = opslang_ast::v1::Program::parse(input, &context); + assert!( + result.is_ok(), + "Failed to parse duration literals: {:?}", + result.err() + ); + } + + #[test] + fn test_parse_numeric_literals_without_suffixes() { + let source = r#"#! lang=v1 +prc main() { + let int_val = 42; + let float_val = 3.14; + let sum = 10 + 20; + let product = 2.5 * 4.0; + return; +} +"#; + + let input = ParserInput { + content: source, + file_name: "test_numeric_literals.ops".into(), + }; + let context = Context::new(); + let result = opslang_ast::v1::Program::parse(input, &context); + assert!( + result.is_ok(), + "Failed to parse numeric literals without suffixes: {:?}", + result.err() + ); + } +} diff --git a/opslang-parser/src/version/v1/generated.rs b/opslang-parser/src/version/v1/generated.rs new file mode 100644 index 0000000..101fae3 --- /dev/null +++ b/opslang-parser/src/version/v1/generated.rs @@ -0,0 +1,6 @@ +// This file is generated by `build.rs`. +// Do not edit it manually. + +#[allow(clippy::all)] +pub mod grammar_trait; +pub mod parser; diff --git a/opslang-parser/src/version/v1/generated/grammar-exp.par b/opslang-parser/src/version/v1/generated/grammar-exp.par new file mode 100644 index 0000000..e7798df --- /dev/null +++ b/opslang-parser/src/version/v1/generated/grammar-exp.par @@ -0,0 +1,169 @@ +%start Program0 +%title "opslang v1 grammar" +%grammar_type 'lalr(1)' +%auto_newline_off +%on Hash %enter Cmnt + +%scanner Cmnt { + %auto_newline_off + %auto_ws_off + %on EndOfLine %enter INITIAL +} + +%% + +/* 0 */ Program0: Program; +/* 1 */ EndOfLine: /\r?\n|\r/; +/* 2 */ Comment: Hash CommentOpt /* Option */; +/* 3 */ CommentOpt /* Option::Some */: CommentContent; +/* 4 */ CommentOpt /* Option::None */: ; +/* 5 */ Hash: '#'; +/* 6 */ CommentContent: /[^\r\n]*/; +/* 7 */ Program: Definition EndOfLine Program; +/* 8 */ Program: Definition; +/* 9 */ Definition: DefinitionOpt /* Option */ DefinitionOpt0 /* Option */; +/* 10 */ DefinitionOpt0 /* Option::Some */: Comment; +/* 11 */ DefinitionOpt0 /* Option::None */: ; +/* 12 */ DefinitionOpt /* Option::Some */: DefinitionOptGroup; +/* 13 */ DefinitionOptGroup: FunctionDef; +/* 14 */ DefinitionOptGroup: ConstantDef; +/* 15 */ DefinitionOpt /* Option::None */: ; +/* 16 */ FunctionDef: 'prc' Ident '(' FunctionDefOpt /* Option */ ')' FunctionDefOpt0 /* Option */ Block; +/* 17 */ FunctionDefOpt0 /* Option::Some */: '->' Path; +/* 18 */ FunctionDefOpt0 /* Option::None */: ; +/* 19 */ FunctionDefOpt /* Option::Some */: ParameterList; +/* 20 */ FunctionDefOpt /* Option::None */: ; +/* 21 */ ParameterList: Parameter ParameterListOpt /* Option */; +/* 22 */ ParameterListOpt /* Option::Some */: CommaParameterList; +/* 23 */ ParameterListOpt /* Option::None */: ; +/* 24 */ CommaParameterList: ',' CommaParameterListOpt /* Option */; +/* 25 */ CommaParameterListOpt /* Option::Some */: ParameterList; +/* 26 */ CommaParameterListOpt /* Option::None */: ; +/* 27 */ Parameter: Ident ':' Path; +/* 28 */ ConstantDef: 'const' Ident ':' Path '=' Expr Semi; +/* 29 */ Scope: ScopeContent ScopeOpt /* Option */; +/* 30 */ ScopeOpt /* Option::Some */: EndOfLine Scope; +/* 31 */ ScopeOpt /* Option::None */: ; +/* 32 */ ScopeContent: ScopeContentOpt /* Option */ ScopeContentOpt0 /* Option */ ScopeContentOpt1 /* Option */; +/* 33 */ ScopeContentOpt1 /* Option::Some */: Comment; +/* 34 */ ScopeContentOpt1 /* Option::None */: ; +/* 35 */ ScopeContentOpt0 /* Option::Some */: ScopeContentKind; +/* 36 */ ScopeContentOpt0 /* Option::None */: ; +/* 37 */ ScopeContentOpt /* Option::Some */: Break; +/* 38 */ ScopeContentOpt /* Option::None */: ; +/* 39 */ ScopeContentKind: Statement; +/* 40 */ ScopeContentKind: Block; +/* 41 */ Statement: StatementKind Semi; +/* 42 */ Break: '.'; +/* 43 */ Semi: ';'; +/* 44 */ StatementKind: LetStmt; +/* 45 */ StatementKind: Expr; +/* 46 */ StatementKind: ReturnStmt; +/* 47 */ ReturnStmt: 'return'; +/* 48 */ LetStmt: 'let' Ident '=' Expr; +/* 49 */ Expr: SetExpr; +/* 50 */ SetExpr: LogicalOrExpr SetExprOpt /* Option */; +/* 51 */ SetExprOpt /* Option::Some */: ':=' LogicalOrExpr; +/* 52 */ SetExprOpt /* Option::None */: ; +/* 53 */ LogicalOrExpr: LogicalOrExprList /* Vec */ LogicalAndExpr; +/* 54 */ LogicalOrExprList /* Vec::Push */: LogicalOrExprList LogicalAndExpr '||'; +/* 55 */ LogicalOrExprList /* Vec::New */: ; +/* 56 */ LogicalAndExpr: LogicalAndExprList /* Vec */ CompareExpr; +/* 57 */ LogicalAndExprList /* Vec::Push */: LogicalAndExprList CompareExpr '&&'; +/* 58 */ LogicalAndExprList /* Vec::New */: ; +/* 59 */ CompareExpr: ArithmeticExpr CompareExprList /* Vec */; +/* 60 */ CompareExprList /* Vec::Push */: CompareExprList CompareOp ArithmeticExpr; +/* 61 */ CompareExprList /* Vec::New */: ; +/* 62 */ CompareOp: '>='; +/* 63 */ CompareOp: '<='; +/* 64 */ CompareOp: '>'; +/* 65 */ CompareOp: '<'; +/* 66 */ CompareOp: '!='; +/* 67 */ CompareOp: '/='; +/* 68 */ CompareOp: '=='; +/* 69 */ ArithmeticExpr: ArithmeticExprList /* Vec */ FactorExpr; +/* 70 */ ArithmeticExprList /* Vec::Push */: ArithmeticExprList FactorExpr ArithmeticOp; +/* 71 */ ArithmeticExprList /* Vec::New */: ; +/* 72 */ ArithmeticOp: '+'; +/* 73 */ ArithmeticOp: '-'; +/* 74 */ FactorExpr: FactorExprList /* Vec */ CastExpr; +/* 75 */ FactorExprList /* Vec::Push */: FactorExprList CastExpr FactorOp; +/* 76 */ FactorExprList /* Vec::New */: ; +/* 77 */ FactorOp: '*'; +/* 78 */ FactorOp: '/'; +/* 79 */ FactorOp: '%'; +/* 80 */ CastExpr: PrefixExpr CastExprOpt /* Option */; +/* 81 */ CastExprOpt /* Option::Some */: 'as' Path; +/* 82 */ CastExprOpt /* Option::None */: ; +/* 83 */ PrefixExpr: '-' ApplyExpr; +/* 84 */ PrefixExpr: PrefixExprList /* Vec */ ApplyExpr; +/* 85 */ PrefixExprList /* Vec::Push */: PrefixExprList Qualif; +/* 86 */ PrefixExprList /* Vec::New */: ; +/* 87 */ PrefixExpr: 'wait' ApplyExpr; +/* 88 */ PrefixExpr: 'call' ApplyExpr; +/* 89 */ ApplyExpr: LowerPrefixExpr ApplyExprList /* Vec */; +/* 90 */ ApplyExprList /* Vec::Push */: ApplyExprList AtomicExpr; +/* 91 */ ApplyExprList /* Vec::New */: ; +/* 92 */ LowerPrefixExpr: LowerPrefixExprOpt /* Option */ Callable; +/* 93 */ LowerPrefixExprOpt /* Option::Some */: LowerPrefixOp; +/* 94 */ LowerPrefixExprOpt /* Option::None */: ; +/* 95 */ LowerPrefixOp: '&'; +/* 96 */ LowerPrefixOp: '$'; +/* 97 */ Callable: Path; +/* 98 */ Callable: Literal CallableOpt /* Option */; +/* 99 */ Callable: '(' Expr ')'; +/* 100 */ Callable: IfExpr; +/* 101 */ Callable: SelectExpr; +/* 102 */ CallableOpt /* Option::Some */: '?' Path; +/* 103 */ CallableOpt /* Option::None */: ; +/* 104 */ AtomicExpr: Qualif; +/* 105 */ AtomicExpr: LowerPrefixExpr; +/* 106 */ IfExpr: 'if' Expr Block IfExprOpt /* Option */; +/* 107 */ IfExprOpt /* Option::Some */: 'else' Block; +/* 108 */ IfExprOpt /* Option::None */: ; +/* 109 */ SelectExpr: 'select' '{' SelectScope '}'; +/* 110 */ SelectScope: SelectScopeOpt /* Option */ SelectScopeOpt0 /* Option */; +/* 111 */ SelectScopeOpt0 /* Option::Some */: EndOfLine SelectScope; +/* 112 */ SelectScopeOpt0 /* Option::None */: ; +/* 113 */ SelectScopeOpt /* Option::Some */: SelectScopeContent; +/* 114 */ SelectScopeOpt /* Option::None */: ; +/* 115 */ SelectScopeContent: Expr '=>' Block; +/* 116 */ Qualif: Modifier; +/* 117 */ Qualif: DefaultModifier; +/* 118 */ DefaultModifier: '~' Path; +/* 119 */ Modifier: '@' Path ModifierOpt /* Option */; +/* 120 */ ModifierOpt /* Option::Some */: KindArg; +/* 121 */ ModifierOpt /* Option::None */: ; +/* 122 */ KindArg: ':' Callable; +/* 123 */ Path: Ident PathList /* Vec */; +/* 124 */ PathList /* Vec::Push */: PathList '.' Ident; +/* 125 */ PathList /* Vec::New */: ; +/* 126 */ Ident: /[_a-zA-Z](\w|[\/-])*/; +/* 127 */ Literal: Array; +/* 128 */ Literal: String; +/* 129 */ Literal: ByteLiteral; +/* 130 */ Literal: HexByteLiteral; +/* 131 */ Literal: Numeric; +/* 132 */ Literal: Rfc3339DateTime; +/* 133 */ Array: '[' ArrayOpt /* Option */ ']'; +/* 134 */ ArrayOpt /* Option::Some */: CommaSepElements; +/* 135 */ ArrayOpt /* Option::None */: ; +/* 136 */ CommaSepElements: Expr CommaSepElementsOpt /* Option */; +/* 137 */ CommaSepElementsOpt /* Option::Some */: CommaExprList; +/* 138 */ CommaSepElementsOpt /* Option::None */: ; +/* 139 */ CommaExprList: ',' CommaExprListOpt /* Option */; +/* 140 */ CommaExprListOpt /* Option::Some */: CommaSepElements; +/* 141 */ CommaExprListOpt /* Option::None */: ; +/* 142 */ String: /"(\\.|[^"])*"/; +/* 143 */ ByteLiteral: /b"(\\.|[^"])*"/; +/* 144 */ HexByteLiteral: /bx"[0-9a-fA-F_]*"/; +/* 145 */ Numeric: BinaryInteger; +/* 146 */ Numeric: OctalInteger; +/* 147 */ Numeric: HexadecimalInteger; +/* 148 */ Numeric: Ieee754Float; +/* 149 */ BinaryInteger: /0b[01_]+([a-zA-Z](\w|[\/-])*)?/; +/* 150 */ OctalInteger: /0o[0-7_]+([a-zA-Z](\w|[\/-])*)?/; +/* 151 */ HexadecimalInteger: /0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?/; +/* 152 */ Ieee754Float: /[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?/; +/* 153 */ Rfc3339DateTime: /\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})/; +/* 154 */ Block: '{' Scope '}'; diff --git a/opslang-parser/src/version/v1/generated/grammar_trait.rs b/opslang-parser/src/version/v1/generated/grammar_trait.rs new file mode 100644 index 0000000..2172c6b --- /dev/null +++ b/opslang-parser/src/version/v1/generated/grammar_trait.rs @@ -0,0 +1,5332 @@ +// --------------------------------------------------------- +// This file was generated by parol. +// It is not intended for manual editing and changes will be +// lost after next build. +// --------------------------------------------------------- + +// Disable clippy warnings that can result in the way how parol generates code. +#![allow(clippy::enum_variant_names)] +#![allow(clippy::large_enum_variant)] +#![allow(clippy::upper_case_acronyms)] + +use parol_runtime::derive_builder::Builder; +use parol_runtime::log::trace; +#[allow(unused_imports)] +use parol_runtime::parol_macros::{pop_and_reverse_item, pop_item}; +use parol_runtime::parser::{ParseTreeType, UserActionsTrait}; +use parol_runtime::{ParserError, Result, Token}; + +/// Semantic actions trait generated for the user grammar +/// All functions have default implementations. +pub trait ActionTrait<'t> { + /// Semantic action for non-terminal 'EndOfLine' + fn end_of_line(&mut self, _arg: &EndOfLine<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Comment' + fn comment(&mut self, _arg: &Comment<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Hash' + fn hash(&mut self, _arg: &Hash<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'CommentContent' + fn comment_content(&mut self, _arg: &CommentContent<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Program' + fn program(&mut self, _arg: &Program<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Definition' + fn definition(&mut self, _arg: &Definition<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'FunctionDef' + fn function_def(&mut self, _arg: &FunctionDef<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'ParameterList' + fn parameter_list(&mut self, _arg: &ParameterList<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'CommaParameterList' + fn comma_parameter_list(&mut self, _arg: &CommaParameterList<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Parameter' + fn parameter(&mut self, _arg: &Parameter<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'ConstantDef' + fn constant_def(&mut self, _arg: &ConstantDef<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Scope' + fn scope(&mut self, _arg: &Scope<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'ScopeContent' + fn scope_content(&mut self, _arg: &ScopeContent<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'ScopeContentKind' + fn scope_content_kind(&mut self, _arg: &ScopeContentKind<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Statement' + fn statement(&mut self, _arg: &Statement<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Break' + fn r#break(&mut self, _arg: &Break<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Semi' + fn semi(&mut self, _arg: &Semi<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'StatementKind' + fn statement_kind(&mut self, _arg: &StatementKind<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'ReturnStmt' + fn return_stmt(&mut self, _arg: &ReturnStmt<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'LetStmt' + fn let_stmt(&mut self, _arg: &LetStmt<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Expr' + fn expr(&mut self, _arg: &Expr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'SetExpr' + fn set_expr(&mut self, _arg: &SetExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'LogicalOrExpr' + fn logical_or_expr(&mut self, _arg: &LogicalOrExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'LogicalAndExpr' + fn logical_and_expr(&mut self, _arg: &LogicalAndExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'CompareExpr' + fn compare_expr(&mut self, _arg: &CompareExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'CompareOp' + fn compare_op(&mut self, _arg: &CompareOp<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'ArithmeticExpr' + fn arithmetic_expr(&mut self, _arg: &ArithmeticExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'ArithmeticOp' + fn arithmetic_op(&mut self, _arg: &ArithmeticOp<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'FactorExpr' + fn factor_expr(&mut self, _arg: &FactorExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'FactorOp' + fn factor_op(&mut self, _arg: &FactorOp<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'CastExpr' + fn cast_expr(&mut self, _arg: &CastExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'PrefixExpr' + fn prefix_expr(&mut self, _arg: &PrefixExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'ApplyExpr' + fn apply_expr(&mut self, _arg: &ApplyExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'LowerPrefixExpr' + fn lower_prefix_expr(&mut self, _arg: &LowerPrefixExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'LowerPrefixOp' + fn lower_prefix_op(&mut self, _arg: &LowerPrefixOp<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Callable' + fn callable(&mut self, _arg: &Callable<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'AtomicExpr' + fn atomic_expr(&mut self, _arg: &AtomicExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'IfExpr' + fn if_expr(&mut self, _arg: &IfExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'SelectExpr' + fn select_expr(&mut self, _arg: &SelectExpr<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'SelectScope' + fn select_scope(&mut self, _arg: &SelectScope<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'SelectScopeContent' + fn select_scope_content(&mut self, _arg: &SelectScopeContent<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Qualif' + fn qualif(&mut self, _arg: &Qualif<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'DefaultModifier' + fn default_modifier(&mut self, _arg: &DefaultModifier<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Modifier' + fn modifier(&mut self, _arg: &Modifier<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'KindArg' + fn kind_arg(&mut self, _arg: &KindArg<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Path' + fn path(&mut self, _arg: &Path<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Ident' + fn ident(&mut self, _arg: &Ident<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Literal' + fn literal(&mut self, _arg: &Literal<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Array' + fn array(&mut self, _arg: &Array<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'CommaSepElements' + fn comma_sep_elements(&mut self, _arg: &CommaSepElements<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'CommaExprList' + fn comma_expr_list(&mut self, _arg: &CommaExprList<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'String' + fn string(&mut self, _arg: &String<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'ByteLiteral' + fn byte_literal(&mut self, _arg: &ByteLiteral<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'HexByteLiteral' + fn hex_byte_literal(&mut self, _arg: &HexByteLiteral<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Numeric' + fn numeric(&mut self, _arg: &Numeric<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'BinaryInteger' + fn binary_integer(&mut self, _arg: &BinaryInteger<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'OctalInteger' + fn octal_integer(&mut self, _arg: &OctalInteger<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'HexadecimalInteger' + fn hexadecimal_integer(&mut self, _arg: &HexadecimalInteger<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Ieee754Float' + fn ieee754_float(&mut self, _arg: &Ieee754Float<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Rfc3339DateTime' + fn rfc3339_date_time(&mut self, _arg: &Rfc3339DateTime<'t>) -> Result<()> { + Ok(()) + } + + /// Semantic action for non-terminal 'Block' + fn block(&mut self, _arg: &Block<'t>) -> Result<()> { + Ok(()) + } + + /// This method provides skipped language comments. + /// If you need comments please provide your own implementation of this method. + fn on_comment(&mut self, _token: Token<'t>) {} +} + +// ------------------------------------------------------------------------------------------------- +// +// Output Types of productions deduced from the structure of the transformed grammar +// + +/// +/// Type derived for production 7 +/// +/// `Program: Definition EndOfLine Program;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ProgramDefinitionEndOfLineProgram<'t> { + pub definition: Box>, + pub end_of_line: Box>, + pub program: Box>, +} + +/// +/// Type derived for production 8 +/// +/// `Program: Definition;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ProgramDefinition<'t> { + pub definition: Box>, +} + +/// +/// Type derived for production 13 +/// +/// `DefinitionOptGroup: FunctionDef;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct DefinitionOptGroupFunctionDef<'t> { + pub function_def: Box>, +} + +/// +/// Type derived for production 14 +/// +/// `DefinitionOptGroup: ConstantDef;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct DefinitionOptGroupConstantDef<'t> { + pub constant_def: Box>, +} + +/// +/// Type derived for production 39 +/// +/// `ScopeContentKind: Statement;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ScopeContentKindStatement<'t> { + pub statement: Box>, +} + +/// +/// Type derived for production 40 +/// +/// `ScopeContentKind: Block;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ScopeContentKindBlock<'t> { + pub block: Box>, +} + +/// +/// Type derived for production 44 +/// +/// `StatementKind: LetStmt;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct StatementKindLetStmt<'t> { + pub let_stmt: Box>, +} + +/// +/// Type derived for production 45 +/// +/// `StatementKind: Expr;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct StatementKindExpr<'t> { + pub expr: Box>, +} + +/// +/// Type derived for production 46 +/// +/// `StatementKind: ReturnStmt;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct StatementKindReturnStmt<'t> { + pub return_stmt: Box>, +} + +/// +/// Type derived for production 62 +/// +/// `CompareOp: '>=';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CompareOpGTEqu<'t> { + pub g_t_equ: Token<'t>, /* >= */ +} + +/// +/// Type derived for production 63 +/// +/// `CompareOp: '<=';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CompareOpLTEqu<'t> { + pub l_t_equ: Token<'t>, /* <= */ +} + +/// +/// Type derived for production 64 +/// +/// `CompareOp: '>';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CompareOpGT<'t> { + pub g_t: Token<'t>, /* > */ +} + +/// +/// Type derived for production 65 +/// +/// `CompareOp: '<';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CompareOpLT<'t> { + pub l_t: Token<'t>, /* < */ +} + +/// +/// Type derived for production 66 +/// +/// `CompareOp: '!=';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CompareOpBangEqu<'t> { + pub bang_equ: Token<'t>, /* != */ +} + +/// +/// Type derived for production 67 +/// +/// `CompareOp: '/=';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CompareOpSlashEqu<'t> { + pub slash_equ: Token<'t>, /* /= */ +} + +/// +/// Type derived for production 68 +/// +/// `CompareOp: '==';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CompareOpEquEqu<'t> { + pub equ_equ: Token<'t>, /* == */ +} + +/// +/// Type derived for production 72 +/// +/// `ArithmeticOp: '+';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ArithmeticOpPlus<'t> { + pub plus: Token<'t>, /* + */ +} + +/// +/// Type derived for production 73 +/// +/// `ArithmeticOp: '-';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ArithmeticOpMinus<'t> { + pub minus: Token<'t>, /* - */ +} + +/// +/// Type derived for production 77 +/// +/// `FactorOp: '*';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct FactorOpStar<'t> { + pub star: Token<'t>, /* * */ +} + +/// +/// Type derived for production 78 +/// +/// `FactorOp: '/';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct FactorOpSlash<'t> { + pub slash: Token<'t>, /* / */ +} + +/// +/// Type derived for production 79 +/// +/// `FactorOp: '%';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct FactorOpPercent<'t> { + pub percent: Token<'t>, /* % */ +} + +/// +/// Type derived for production 83 +/// +/// `PrefixExpr: '-' ApplyExpr;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct PrefixExprMinusApplyExpr<'t> { + pub minus: Token<'t>, /* - */ + pub apply_expr: Box>, +} + +/// +/// Type derived for production 84 +/// +/// `PrefixExpr: PrefixExprList /* Vec */ ApplyExpr;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct PrefixExprPrefixExprListApplyExpr<'t> { + pub prefix_expr_list: Vec>, + pub apply_expr: Box>, +} + +/// +/// Type derived for production 87 +/// +/// `PrefixExpr: 'wait' ApplyExpr;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct PrefixExprWaitApplyExpr<'t> { + pub wait: Token<'t>, /* wait */ + pub apply_expr: Box>, +} + +/// +/// Type derived for production 88 +/// +/// `PrefixExpr: 'call' ApplyExpr;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct PrefixExprCallApplyExpr<'t> { + pub call: Token<'t>, /* call */ + pub apply_expr: Box>, +} + +/// +/// Type derived for production 95 +/// +/// `LowerPrefixOp: '&';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LowerPrefixOpAmp<'t> { + pub amp: Token<'t>, /* & */ +} + +/// +/// Type derived for production 96 +/// +/// `LowerPrefixOp: '$';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LowerPrefixOpDollar<'t> { + pub dollar: Token<'t>, /* $ */ +} + +/// +/// Type derived for production 97 +/// +/// `Callable: Path;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CallablePath<'t> { + pub path: Box>, +} + +/// +/// Type derived for production 98 +/// +/// `Callable: Literal CallableOpt /* Option */;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CallableLiteralCallableOpt<'t> { + pub literal: Box>, + pub callable_opt: Option>, +} + +/// +/// Type derived for production 99 +/// +/// `Callable: '(' Expr ')';` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CallableLParenExprRParen<'t> { + pub l_paren: Token<'t>, /* ( */ + pub expr: Box>, + pub r_paren: Token<'t>, /* ) */ +} + +/// +/// Type derived for production 100 +/// +/// `Callable: IfExpr;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CallableIfExpr<'t> { + pub if_expr: Box>, +} + +/// +/// Type derived for production 101 +/// +/// `Callable: SelectExpr;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CallableSelectExpr<'t> { + pub select_expr: Box>, +} + +/// +/// Type derived for production 104 +/// +/// `AtomicExpr: Qualif;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct AtomicExprQualif<'t> { + pub qualif: Box>, +} + +/// +/// Type derived for production 105 +/// +/// `AtomicExpr: LowerPrefixExpr;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct AtomicExprLowerPrefixExpr<'t> { + pub lower_prefix_expr: Box>, +} + +/// +/// Type derived for production 116 +/// +/// `Qualif: Modifier;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct QualifModifier<'t> { + pub modifier: Box>, +} + +/// +/// Type derived for production 117 +/// +/// `Qualif: DefaultModifier;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct QualifDefaultModifier<'t> { + pub default_modifier: Box>, +} + +/// +/// Type derived for production 127 +/// +/// `Literal: Array;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LiteralArray<'t> { + pub array: Box>, +} + +/// +/// Type derived for production 128 +/// +/// `Literal: String;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LiteralString<'t> { + pub string: Box>, +} + +/// +/// Type derived for production 129 +/// +/// `Literal: ByteLiteral;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LiteralByteLiteral<'t> { + pub byte_literal: Box>, +} + +/// +/// Type derived for production 130 +/// +/// `Literal: HexByteLiteral;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LiteralHexByteLiteral<'t> { + pub hex_byte_literal: Box>, +} + +/// +/// Type derived for production 131 +/// +/// `Literal: Numeric;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LiteralNumeric<'t> { + pub numeric: Box>, +} + +/// +/// Type derived for production 132 +/// +/// `Literal: Rfc3339DateTime;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LiteralRfc3339DateTime<'t> { + pub rfc3339_date_time: Box>, +} + +/// +/// Type derived for production 145 +/// +/// `Numeric: BinaryInteger;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct NumericBinaryInteger<'t> { + pub binary_integer: Box>, +} + +/// +/// Type derived for production 146 +/// +/// `Numeric: OctalInteger;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct NumericOctalInteger<'t> { + pub octal_integer: Box>, +} + +/// +/// Type derived for production 147 +/// +/// `Numeric: HexadecimalInteger;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct NumericHexadecimalInteger<'t> { + pub hexadecimal_integer: Box>, +} + +/// +/// Type derived for production 148 +/// +/// `Numeric: Ieee754Float;` +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct NumericIeee754Float<'t> { + pub ieee754_float: Box>, +} + +// ------------------------------------------------------------------------------------------------- +// +// Types of non-terminals deduced from the structure of the transformed grammar +// + +/// +/// Type derived for non-terminal ApplyExpr +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ApplyExpr<'t> { + pub lower_prefix_expr: Box>, + pub apply_expr_list: Vec>, +} + +/// +/// Type derived for non-terminal ApplyExprList +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ApplyExprList<'t> { + pub atomic_expr: Box>, +} + +/// +/// Type derived for non-terminal ArithmeticExpr +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ArithmeticExpr<'t> { + pub arithmetic_expr_list: Vec>, + pub factor_expr: Box>, +} + +/// +/// Type derived for non-terminal ArithmeticExprList +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ArithmeticExprList<'t> { + pub factor_expr: Box>, + pub arithmetic_op: Box>, +} + +/// +/// Type derived for non-terminal ArithmeticOp +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum ArithmeticOp<'t> { + Plus(ArithmeticOpPlus<'t>), + Minus(ArithmeticOpMinus<'t>), +} + +/// +/// Type derived for non-terminal Array +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Array<'t> { + pub l_bracket: Token<'t>, /* [ */ + pub array_opt: Option>, + pub r_bracket: Token<'t>, /* ] */ +} + +/// +/// Type derived for non-terminal ArrayOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ArrayOpt<'t> { + pub comma_sep_elements: Box>, +} + +/// +/// Type derived for non-terminal AtomicExpr +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum AtomicExpr<'t> { + Qualif(AtomicExprQualif<'t>), + LowerPrefixExpr(AtomicExprLowerPrefixExpr<'t>), +} + +/// +/// Type derived for non-terminal BinaryInteger +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct BinaryInteger<'t> { + pub binary_integer: Token<'t>, /* 0b[01_]+([a-zA-Z](\w|[\/-])*)? */ +} + +/// +/// Type derived for non-terminal Block +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Block<'t> { + pub l_brace: Token<'t>, /* { */ + pub scope: Box>, + pub r_brace: Token<'t>, /* } */ +} + +/// +/// Type derived for non-terminal Break +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Break<'t> { + pub r#break: Token<'t>, /* . */ +} + +/// +/// Type derived for non-terminal ByteLiteral +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ByteLiteral<'t> { + pub byte_literal: Token<'t>, /* b"(\\.|[^"])*" */ +} + +/// +/// Type derived for non-terminal Callable +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum Callable<'t> { + Path(CallablePath<'t>), + LiteralCallableOpt(CallableLiteralCallableOpt<'t>), + LParenExprRParen(CallableLParenExprRParen<'t>), + IfExpr(CallableIfExpr<'t>), + SelectExpr(CallableSelectExpr<'t>), +} + +/// +/// Type derived for non-terminal CallableOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CallableOpt<'t> { + pub quest: Token<'t>, /* ? */ + pub path: Box>, +} + +/// +/// Type derived for non-terminal CastExpr +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CastExpr<'t> { + pub prefix_expr: Box>, + pub cast_expr_opt: Option>, +} + +/// +/// Type derived for non-terminal CastExprOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CastExprOpt<'t> { + pub r#as: Token<'t>, /* as */ + pub path: Box>, +} + +/// +/// Type derived for non-terminal CommaExprList +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CommaExprList<'t> { + pub comma: Token<'t>, /* , */ + pub comma_expr_list_opt: Option>, +} + +/// +/// Type derived for non-terminal CommaExprListOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CommaExprListOpt<'t> { + pub comma_sep_elements: Box>, +} + +/// +/// Type derived for non-terminal CommaParameterList +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CommaParameterList<'t> { + pub comma: Token<'t>, /* , */ + pub comma_parameter_list_opt: Option>, +} + +/// +/// Type derived for non-terminal CommaParameterListOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CommaParameterListOpt<'t> { + pub parameter_list: Box>, +} + +/// +/// Type derived for non-terminal CommaSepElements +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CommaSepElements<'t> { + pub expr: Box>, + pub comma_sep_elements_opt: Option>, +} + +/// +/// Type derived for non-terminal CommaSepElementsOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CommaSepElementsOpt<'t> { + pub comma_expr_list: Box>, +} + +/// +/// Type derived for non-terminal Comment +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Comment<'t> { + pub hash: Box>, + pub comment_opt: Option>, +} + +/// +/// Type derived for non-terminal CommentContent +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CommentContent<'t> { + pub comment_content: Token<'t>, /* [^\r\n]* */ +} + +/// +/// Type derived for non-terminal CommentOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CommentOpt<'t> { + pub comment_content: Box>, +} + +/// +/// Type derived for non-terminal CompareExpr +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CompareExpr<'t> { + pub arithmetic_expr: Box>, + pub compare_expr_list: Vec>, +} + +/// +/// Type derived for non-terminal CompareExprList +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct CompareExprList<'t> { + pub compare_op: Box>, + pub arithmetic_expr: Box>, +} + +/// +/// Type derived for non-terminal CompareOp +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum CompareOp<'t> { + GTEqu(CompareOpGTEqu<'t>), + LTEqu(CompareOpLTEqu<'t>), + GT(CompareOpGT<'t>), + LT(CompareOpLT<'t>), + BangEqu(CompareOpBangEqu<'t>), + SlashEqu(CompareOpSlashEqu<'t>), + EquEqu(CompareOpEquEqu<'t>), +} + +/// +/// Type derived for non-terminal ConstantDef +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ConstantDef<'t> { + pub r#const: Token<'t>, /* const */ + pub ident: Box>, + pub colon: Token<'t>, /* : */ + pub path: Box>, + pub equ: Token<'t>, /* = */ + pub expr: Box>, + pub semi: Box>, +} + +/// +/// Type derived for non-terminal DefaultModifier +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct DefaultModifier<'t> { + pub tilde: Token<'t>, /* ~ */ + pub path: Box>, +} + +/// +/// Type derived for non-terminal Definition +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Definition<'t> { + pub definition_opt: Option>, + pub definition_opt0: Option>, +} + +/// +/// Type derived for non-terminal DefinitionOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct DefinitionOpt<'t> { + pub definition_opt_group: Box>, +} + +/// +/// Type derived for non-terminal DefinitionOpt0 +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct DefinitionOpt0<'t> { + pub comment: Box>, +} + +/// +/// Type derived for non-terminal DefinitionOptGroup +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum DefinitionOptGroup<'t> { + FunctionDef(DefinitionOptGroupFunctionDef<'t>), + ConstantDef(DefinitionOptGroupConstantDef<'t>), +} + +/// +/// Type derived for non-terminal EndOfLine +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct EndOfLine<'t> { + pub end_of_line: Token<'t>, /* \r?\n|\r */ +} + +/// +/// Type derived for non-terminal Expr +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Expr<'t> { + pub set_expr: Box>, +} + +/// +/// Type derived for non-terminal FactorExpr +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct FactorExpr<'t> { + pub factor_expr_list: Vec>, + pub cast_expr: Box>, +} + +/// +/// Type derived for non-terminal FactorExprList +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct FactorExprList<'t> { + pub cast_expr: Box>, + pub factor_op: Box>, +} + +/// +/// Type derived for non-terminal FactorOp +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum FactorOp<'t> { + Star(FactorOpStar<'t>), + Slash(FactorOpSlash<'t>), + Percent(FactorOpPercent<'t>), +} + +/// +/// Type derived for non-terminal FunctionDef +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct FunctionDef<'t> { + pub prc: Token<'t>, /* prc */ + pub ident: Box>, + pub l_paren: Token<'t>, /* ( */ + pub function_def_opt: Option>, + pub r_paren: Token<'t>, /* ) */ + pub function_def_opt0: Option>, + pub block: Box>, +} + +/// +/// Type derived for non-terminal FunctionDefOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct FunctionDefOpt<'t> { + pub parameter_list: Box>, +} + +/// +/// Type derived for non-terminal FunctionDefOpt0 +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct FunctionDefOpt0<'t> { + pub minus_g_t: Token<'t>, /* -> */ + pub path: Box>, +} + +/// +/// Type derived for non-terminal Hash +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Hash<'t> { + pub hash: Token<'t>, /* # */ +} + +/// +/// Type derived for non-terminal HexByteLiteral +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct HexByteLiteral<'t> { + pub hex_byte_literal: Token<'t>, /* bx"[0-9a-fA-F_]*" */ +} + +/// +/// Type derived for non-terminal HexadecimalInteger +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct HexadecimalInteger<'t> { + pub hexadecimal_integer: Token<'t>, /* 0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)? */ +} + +/// +/// Type derived for non-terminal Ident +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Ident<'t> { + pub ident: Token<'t>, /* [_a-zA-Z](\w|[\/-])* */ +} + +/// +/// Type derived for non-terminal Ieee754Float +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Ieee754Float<'t> { + pub ieee754_float: Token<'t>, /* [-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)? */ +} + +/// +/// Type derived for non-terminal IfExpr +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct IfExpr<'t> { + pub r#if: Token<'t>, /* if */ + pub expr: Box>, + pub block: Box>, + pub if_expr_opt: Option>, +} + +/// +/// Type derived for non-terminal IfExprOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct IfExprOpt<'t> { + pub r#else: Token<'t>, /* else */ + pub block: Box>, +} + +/// +/// Type derived for non-terminal KindArg +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct KindArg<'t> { + pub colon: Token<'t>, /* : */ + pub callable: Box>, +} + +/// +/// Type derived for non-terminal LetStmt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LetStmt<'t> { + pub r#let: Token<'t>, /* let */ + pub ident: Box>, + pub equ: Token<'t>, /* = */ + pub expr: Box>, +} + +/// +/// Type derived for non-terminal Literal +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum Literal<'t> { + Array(LiteralArray<'t>), + String(LiteralString<'t>), + ByteLiteral(LiteralByteLiteral<'t>), + HexByteLiteral(LiteralHexByteLiteral<'t>), + Numeric(LiteralNumeric<'t>), + Rfc3339DateTime(LiteralRfc3339DateTime<'t>), +} + +/// +/// Type derived for non-terminal LogicalAndExpr +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LogicalAndExpr<'t> { + pub logical_and_expr_list: Vec>, + pub compare_expr: Box>, +} + +/// +/// Type derived for non-terminal LogicalAndExprList +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LogicalAndExprList<'t> { + pub compare_expr: Box>, + pub amp_amp: Token<'t>, /* && */ +} + +/// +/// Type derived for non-terminal LogicalOrExpr +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LogicalOrExpr<'t> { + pub logical_or_expr_list: Vec>, + pub logical_and_expr: Box>, +} + +/// +/// Type derived for non-terminal LogicalOrExprList +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LogicalOrExprList<'t> { + pub logical_and_expr: Box>, + pub or_or: Token<'t>, /* || */ +} + +/// +/// Type derived for non-terminal LowerPrefixExpr +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LowerPrefixExpr<'t> { + pub lower_prefix_expr_opt: Option>, + pub callable: Box>, +} + +/// +/// Type derived for non-terminal LowerPrefixExprOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct LowerPrefixExprOpt<'t> { + pub lower_prefix_op: Box>, +} + +/// +/// Type derived for non-terminal LowerPrefixOp +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum LowerPrefixOp<'t> { + Amp(LowerPrefixOpAmp<'t>), + Dollar(LowerPrefixOpDollar<'t>), +} + +/// +/// Type derived for non-terminal Modifier +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Modifier<'t> { + pub at: Token<'t>, /* @ */ + pub path: Box>, + pub modifier_opt: Option>, +} + +/// +/// Type derived for non-terminal ModifierOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ModifierOpt<'t> { + pub kind_arg: Box>, +} + +/// +/// Type derived for non-terminal Numeric +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum Numeric<'t> { + BinaryInteger(NumericBinaryInteger<'t>), + OctalInteger(NumericOctalInteger<'t>), + HexadecimalInteger(NumericHexadecimalInteger<'t>), + Ieee754Float(NumericIeee754Float<'t>), +} + +/// +/// Type derived for non-terminal OctalInteger +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct OctalInteger<'t> { + pub octal_integer: Token<'t>, /* 0o[0-7_]+([a-zA-Z](\w|[\/-])*)? */ +} + +/// +/// Type derived for non-terminal Parameter +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Parameter<'t> { + pub ident: Box>, + pub colon: Token<'t>, /* : */ + pub path: Box>, +} + +/// +/// Type derived for non-terminal ParameterList +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ParameterList<'t> { + pub parameter: Box>, + pub parameter_list_opt: Option>, +} + +/// +/// Type derived for non-terminal ParameterListOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ParameterListOpt<'t> { + pub comma_parameter_list: Box>, +} + +/// +/// Type derived for non-terminal Path +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Path<'t> { + pub ident: Box>, + pub path_list: Vec>, +} + +/// +/// Type derived for non-terminal PathList +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct PathList<'t> { + pub r#break: Token<'t>, /* . */ + pub ident: Box>, +} + +/// +/// Type derived for non-terminal PrefixExpr +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum PrefixExpr<'t> { + MinusApplyExpr(PrefixExprMinusApplyExpr<'t>), + PrefixExprListApplyExpr(PrefixExprPrefixExprListApplyExpr<'t>), + WaitApplyExpr(PrefixExprWaitApplyExpr<'t>), + CallApplyExpr(PrefixExprCallApplyExpr<'t>), +} + +/// +/// Type derived for non-terminal PrefixExprList +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct PrefixExprList<'t> { + pub qualif: Box>, +} + +/// +/// Type derived for non-terminal Program +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum Program<'t> { + DefinitionEndOfLineProgram(ProgramDefinitionEndOfLineProgram<'t>), + Definition(ProgramDefinition<'t>), +} + +/// +/// Type derived for non-terminal Program0 +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Program0<'t> { + pub program: Box>, +} + +/// +/// Type derived for non-terminal Qualif +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum Qualif<'t> { + Modifier(QualifModifier<'t>), + DefaultModifier(QualifDefaultModifier<'t>), +} + +/// +/// Type derived for non-terminal ReturnStmt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ReturnStmt<'t> { + pub return_stmt: Token<'t>, /* return */ +} + +/// +/// Type derived for non-terminal Rfc3339DateTime +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Rfc3339DateTime<'t> { + pub rfc3339_date_time: Token<'t>, /* \d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2}) */ +} + +/// +/// Type derived for non-terminal Scope +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Scope<'t> { + pub scope_content: Box>, + pub scope_opt: Option>, +} + +/// +/// Type derived for non-terminal ScopeContent +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ScopeContent<'t> { + pub scope_content_opt: Option>, + pub scope_content_opt0: Option>, + pub scope_content_opt1: Option>, +} + +/// +/// Type derived for non-terminal ScopeContentKind +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum ScopeContentKind<'t> { + Statement(ScopeContentKindStatement<'t>), + Block(ScopeContentKindBlock<'t>), +} + +/// +/// Type derived for non-terminal ScopeContentOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ScopeContentOpt<'t> { + pub r#break: Box>, +} + +/// +/// Type derived for non-terminal ScopeContentOpt0 +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ScopeContentOpt0<'t> { + pub scope_content_kind: Box>, +} + +/// +/// Type derived for non-terminal ScopeContentOpt1 +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ScopeContentOpt1<'t> { + pub comment: Box>, +} + +/// +/// Type derived for non-terminal ScopeOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct ScopeOpt<'t> { + pub end_of_line: Box>, + pub scope: Box>, +} + +/// +/// Type derived for non-terminal SelectExpr +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct SelectExpr<'t> { + pub select: Token<'t>, /* select */ + pub l_brace: Token<'t>, /* { */ + pub select_scope: Box>, + pub r_brace: Token<'t>, /* } */ +} + +/// +/// Type derived for non-terminal SelectScope +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct SelectScope<'t> { + pub select_scope_opt: Option>, + pub select_scope_opt0: Option>, +} + +/// +/// Type derived for non-terminal SelectScopeContent +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct SelectScopeContent<'t> { + pub expr: Box>, + pub equ_g_t: Token<'t>, /* => */ + pub block: Box>, +} + +/// +/// Type derived for non-terminal SelectScopeOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct SelectScopeOpt<'t> { + pub select_scope_content: Box>, +} + +/// +/// Type derived for non-terminal SelectScopeOpt0 +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct SelectScopeOpt0<'t> { + pub end_of_line: Box>, + pub select_scope: Box>, +} + +/// +/// Type derived for non-terminal Semi +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Semi<'t> { + pub semi: Token<'t>, /* ; */ +} + +/// +/// Type derived for non-terminal SetExpr +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct SetExpr<'t> { + pub logical_or_expr: Box>, + pub set_expr_opt: Option>, +} + +/// +/// Type derived for non-terminal SetExprOpt +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct SetExprOpt<'t> { + pub colon_equ: Token<'t>, /* := */ + pub logical_or_expr: Box>, +} + +/// +/// Type derived for non-terminal Statement +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct Statement<'t> { + pub statement_kind: Box>, + pub semi: Box>, +} + +/// +/// Type derived for non-terminal StatementKind +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum StatementKind<'t> { + LetStmt(StatementKindLetStmt<'t>), + Expr(StatementKindExpr<'t>), + ReturnStmt(StatementKindReturnStmt<'t>), +} + +/// +/// Type derived for non-terminal String +/// +#[allow(dead_code)] +#[derive(Builder, Debug, Clone)] +#[builder(crate = "parol_runtime::derive_builder")] +pub struct String<'t> { + pub string: Token<'t>, /* "(\\.|[^"])*" */ +} + +// ------------------------------------------------------------------------------------------------- + +/// +/// Deduced ASTType of expanded grammar +/// +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum ASTType<'t> { + ApplyExpr(ApplyExpr<'t>), + ApplyExprList(Vec>), + ArithmeticExpr(ArithmeticExpr<'t>), + ArithmeticExprList(Vec>), + ArithmeticOp(ArithmeticOp<'t>), + Array(Array<'t>), + ArrayOpt(Option>), + AtomicExpr(AtomicExpr<'t>), + BinaryInteger(BinaryInteger<'t>), + Block(Block<'t>), + Break(Break<'t>), + ByteLiteral(ByteLiteral<'t>), + Callable(Callable<'t>), + CallableOpt(Option>), + CastExpr(CastExpr<'t>), + CastExprOpt(Option>), + CommaExprList(CommaExprList<'t>), + CommaExprListOpt(Option>), + CommaParameterList(CommaParameterList<'t>), + CommaParameterListOpt(Option>), + CommaSepElements(CommaSepElements<'t>), + CommaSepElementsOpt(Option>), + Comment(Comment<'t>), + CommentContent(CommentContent<'t>), + CommentOpt(Option>), + CompareExpr(CompareExpr<'t>), + CompareExprList(Vec>), + CompareOp(CompareOp<'t>), + ConstantDef(ConstantDef<'t>), + DefaultModifier(DefaultModifier<'t>), + Definition(Definition<'t>), + DefinitionOpt(Option>), + DefinitionOpt0(Option>), + DefinitionOptGroup(DefinitionOptGroup<'t>), + EndOfLine(EndOfLine<'t>), + Expr(Expr<'t>), + FactorExpr(FactorExpr<'t>), + FactorExprList(Vec>), + FactorOp(FactorOp<'t>), + FunctionDef(FunctionDef<'t>), + FunctionDefOpt(Option>), + FunctionDefOpt0(Option>), + Hash(Hash<'t>), + HexByteLiteral(HexByteLiteral<'t>), + HexadecimalInteger(HexadecimalInteger<'t>), + Ident(Ident<'t>), + Ieee754Float(Ieee754Float<'t>), + IfExpr(IfExpr<'t>), + IfExprOpt(Option>), + KindArg(KindArg<'t>), + LetStmt(LetStmt<'t>), + Literal(Literal<'t>), + LogicalAndExpr(LogicalAndExpr<'t>), + LogicalAndExprList(Vec>), + LogicalOrExpr(LogicalOrExpr<'t>), + LogicalOrExprList(Vec>), + LowerPrefixExpr(LowerPrefixExpr<'t>), + LowerPrefixExprOpt(Option>), + LowerPrefixOp(LowerPrefixOp<'t>), + Modifier(Modifier<'t>), + ModifierOpt(Option>), + Numeric(Numeric<'t>), + OctalInteger(OctalInteger<'t>), + Parameter(Parameter<'t>), + ParameterList(ParameterList<'t>), + ParameterListOpt(Option>), + Path(Path<'t>), + PathList(Vec>), + PrefixExpr(PrefixExpr<'t>), + PrefixExprList(Vec>), + Program(Program<'t>), + Program0(Program0<'t>), + Qualif(Qualif<'t>), + ReturnStmt(ReturnStmt<'t>), + Rfc3339DateTime(Rfc3339DateTime<'t>), + Scope(Scope<'t>), + ScopeContent(ScopeContent<'t>), + ScopeContentKind(ScopeContentKind<'t>), + ScopeContentOpt(Option>), + ScopeContentOpt0(Option>), + ScopeContentOpt1(Option>), + ScopeOpt(Option>), + SelectExpr(SelectExpr<'t>), + SelectScope(SelectScope<'t>), + SelectScopeContent(SelectScopeContent<'t>), + SelectScopeOpt(Option>), + SelectScopeOpt0(Option>), + Semi(Semi<'t>), + SetExpr(SetExpr<'t>), + SetExprOpt(Option>), + Statement(Statement<'t>), + StatementKind(StatementKind<'t>), + String(String<'t>), +} + +/// Auto-implemented adapter grammar +/// +/// The lifetime parameter `'t` refers to the lifetime of the scanned text. +/// The lifetime parameter `'u` refers to the lifetime of user grammar object. +/// +#[allow(dead_code)] +pub struct ActionAuto<'t, 'u> +where + 't: 'u, +{ + // Mutable reference of the actual user grammar to be able to call the semantic actions on it + user_grammar: &'u mut dyn ActionTrait<'t>, + // Stack to construct the AST on it + item_stack: Vec>, +} + +/// +/// The `ActionAuto` impl is automatically generated for the +/// given grammar. +/// +impl<'t, 'u> ActionAuto<'t, 'u> { + pub fn new(user_grammar: &'u mut dyn ActionTrait<'t>) -> Self { + Self { + user_grammar, + item_stack: Vec::new(), + } + } + + #[allow(dead_code)] + fn push(&mut self, item: ASTType<'t>, context: &str) { + trace!("push {}: {:?}", context, item); + self.item_stack.push(item) + } + + #[allow(dead_code)] + fn pop(&mut self, context: &str) -> Option> { + let item = self.item_stack.pop(); + if let Some(ref item) = item { + trace!("pop {}: {:?}", context, item); + } + item + } + + #[allow(dead_code)] + // Use this function for debugging purposes: + // trace!("{}", self.trace_item_stack(context)); + fn trace_item_stack(&self, context: &str) -> std::string::String { + format!( + "Item stack at {}:\n{}", + context, + self.item_stack + .iter() + .rev() + .map(|s| format!(" {:?}", s)) + .collect::>() + .join("\n") + ) + } + + /// Semantic action for production 0: + /// + /// `Program0: Program;` + /// + #[parol_runtime::function_name::named] + fn program0(&mut self, _program: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let program = pop_item!(self, program, Program, context); + let program0_built = Program0 { + program: Box::new(program), + }; + self.push(ASTType::Program0(program0_built), context); + Ok(()) + } + + /// Semantic action for production 1: + /// + /// `EndOfLine: /\r?\n|\r/;` + /// + #[parol_runtime::function_name::named] + fn end_of_line(&mut self, end_of_line: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let end_of_line = end_of_line.token()?.clone(); + let end_of_line_built = EndOfLine { end_of_line }; + // Calling user action here + self.user_grammar.end_of_line(&end_of_line_built)?; + self.push(ASTType::EndOfLine(end_of_line_built), context); + Ok(()) + } + + /// Semantic action for production 2: + /// + /// `Comment: Hash CommentOpt /* Option */;` + /// + #[parol_runtime::function_name::named] + fn comment( + &mut self, + _hash: &ParseTreeType<'t>, + _comment_opt: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let comment_opt = pop_item!(self, comment_opt, CommentOpt, context); + let hash = pop_item!(self, hash, Hash, context); + let comment_built = Comment { + hash: Box::new(hash), + comment_opt, + }; + // Calling user action here + self.user_grammar.comment(&comment_built)?; + self.push(ASTType::Comment(comment_built), context); + Ok(()) + } + + /// Semantic action for production 3: + /// + /// `CommentOpt /* Option::Some */: CommentContent;` + /// + #[parol_runtime::function_name::named] + fn comment_opt_0(&mut self, _comment_content: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let comment_content = pop_item!(self, comment_content, CommentContent, context); + let comment_opt_0_built = CommentOpt { + comment_content: Box::new(comment_content), + }; + self.push(ASTType::CommentOpt(Some(comment_opt_0_built)), context); + Ok(()) + } + + /// Semantic action for production 4: + /// + /// `CommentOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn comment_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::CommentOpt(None), context); + Ok(()) + } + + /// Semantic action for production 5: + /// + /// `Hash: '#';` + /// + #[parol_runtime::function_name::named] + fn hash(&mut self, hash: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let hash = hash.token()?.clone(); + let hash_built = Hash { hash }; + // Calling user action here + self.user_grammar.hash(&hash_built)?; + self.push(ASTType::Hash(hash_built), context); + Ok(()) + } + + /// Semantic action for production 6: + /// + /// `CommentContent: /[^\r\n]*/;` + /// + #[parol_runtime::function_name::named] + fn comment_content(&mut self, comment_content: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let comment_content = comment_content.token()?.clone(); + let comment_content_built = CommentContent { comment_content }; + // Calling user action here + self.user_grammar.comment_content(&comment_content_built)?; + self.push(ASTType::CommentContent(comment_content_built), context); + Ok(()) + } + + /// Semantic action for production 7: + /// + /// `Program: Definition EndOfLine Program;` + /// + #[parol_runtime::function_name::named] + fn program_0( + &mut self, + _definition: &ParseTreeType<'t>, + _end_of_line: &ParseTreeType<'t>, + _program: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let program = pop_item!(self, program, Program, context); + let end_of_line = pop_item!(self, end_of_line, EndOfLine, context); + let definition = pop_item!(self, definition, Definition, context); + let program_0_built = ProgramDefinitionEndOfLineProgram { + definition: Box::new(definition), + end_of_line: Box::new(end_of_line), + program: Box::new(program), + }; + let program_0_built = Program::DefinitionEndOfLineProgram(program_0_built); + // Calling user action here + self.user_grammar.program(&program_0_built)?; + self.push(ASTType::Program(program_0_built), context); + Ok(()) + } + + /// Semantic action for production 8: + /// + /// `Program: Definition;` + /// + #[parol_runtime::function_name::named] + fn program_1(&mut self, _definition: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let definition = pop_item!(self, definition, Definition, context); + let program_1_built = ProgramDefinition { + definition: Box::new(definition), + }; + let program_1_built = Program::Definition(program_1_built); + // Calling user action here + self.user_grammar.program(&program_1_built)?; + self.push(ASTType::Program(program_1_built), context); + Ok(()) + } + + /// Semantic action for production 9: + /// + /// `Definition: DefinitionOpt /* Option */ DefinitionOpt0 /* Option */;` + /// + #[parol_runtime::function_name::named] + fn definition( + &mut self, + _definition_opt: &ParseTreeType<'t>, + _definition_opt0: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let definition_opt0 = pop_item!(self, definition_opt0, DefinitionOpt0, context); + let definition_opt = pop_item!(self, definition_opt, DefinitionOpt, context); + let definition_built = Definition { + definition_opt, + definition_opt0, + }; + // Calling user action here + self.user_grammar.definition(&definition_built)?; + self.push(ASTType::Definition(definition_built), context); + Ok(()) + } + + /// Semantic action for production 10: + /// + /// `DefinitionOpt0 /* Option::Some */: Comment;` + /// + #[parol_runtime::function_name::named] + fn definition_opt0_0(&mut self, _comment: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let comment = pop_item!(self, comment, Comment, context); + let definition_opt0_0_built = DefinitionOpt0 { + comment: Box::new(comment), + }; + self.push( + ASTType::DefinitionOpt0(Some(definition_opt0_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 11: + /// + /// `DefinitionOpt0 /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn definition_opt0_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::DefinitionOpt0(None), context); + Ok(()) + } + + /// Semantic action for production 12: + /// + /// `DefinitionOpt /* Option::Some */: DefinitionOptGroup;` + /// + #[parol_runtime::function_name::named] + fn definition_opt_0(&mut self, _definition_opt_group: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let definition_opt_group = + pop_item!(self, definition_opt_group, DefinitionOptGroup, context); + let definition_opt_0_built = DefinitionOpt { + definition_opt_group: Box::new(definition_opt_group), + }; + self.push( + ASTType::DefinitionOpt(Some(definition_opt_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 13: + /// + /// `DefinitionOptGroup: FunctionDef;` + /// + #[parol_runtime::function_name::named] + fn definition_opt_group_0(&mut self, _function_def: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let function_def = pop_item!(self, function_def, FunctionDef, context); + let definition_opt_group_0_built = DefinitionOptGroupFunctionDef { + function_def: Box::new(function_def), + }; + let definition_opt_group_0_built = + DefinitionOptGroup::FunctionDef(definition_opt_group_0_built); + self.push( + ASTType::DefinitionOptGroup(definition_opt_group_0_built), + context, + ); + Ok(()) + } + + /// Semantic action for production 14: + /// + /// `DefinitionOptGroup: ConstantDef;` + /// + #[parol_runtime::function_name::named] + fn definition_opt_group_1(&mut self, _constant_def: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let constant_def = pop_item!(self, constant_def, ConstantDef, context); + let definition_opt_group_1_built = DefinitionOptGroupConstantDef { + constant_def: Box::new(constant_def), + }; + let definition_opt_group_1_built = + DefinitionOptGroup::ConstantDef(definition_opt_group_1_built); + self.push( + ASTType::DefinitionOptGroup(definition_opt_group_1_built), + context, + ); + Ok(()) + } + + /// Semantic action for production 15: + /// + /// `DefinitionOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn definition_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::DefinitionOpt(None), context); + Ok(()) + } + + /// Semantic action for production 16: + /// + /// `FunctionDef: 'prc' Ident '(' FunctionDefOpt /* Option */ ')' FunctionDefOpt0 /* Option */ Block;` + /// + #[parol_runtime::function_name::named] + fn function_def( + &mut self, + prc: &ParseTreeType<'t>, + _ident: &ParseTreeType<'t>, + l_paren: &ParseTreeType<'t>, + _function_def_opt: &ParseTreeType<'t>, + r_paren: &ParseTreeType<'t>, + _function_def_opt0: &ParseTreeType<'t>, + _block: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let prc = prc.token()?.clone(); + let l_paren = l_paren.token()?.clone(); + let r_paren = r_paren.token()?.clone(); + let block = pop_item!(self, block, Block, context); + let function_def_opt0 = pop_item!(self, function_def_opt0, FunctionDefOpt0, context); + let function_def_opt = pop_item!(self, function_def_opt, FunctionDefOpt, context); + let ident = pop_item!(self, ident, Ident, context); + let function_def_built = FunctionDef { + prc, + ident: Box::new(ident), + l_paren, + function_def_opt, + r_paren, + function_def_opt0, + block: Box::new(block), + }; + // Calling user action here + self.user_grammar.function_def(&function_def_built)?; + self.push(ASTType::FunctionDef(function_def_built), context); + Ok(()) + } + + /// Semantic action for production 17: + /// + /// `FunctionDefOpt0 /* Option::Some */: '->' Path;` + /// + #[parol_runtime::function_name::named] + fn function_def_opt0_0( + &mut self, + minus_g_t: &ParseTreeType<'t>, + _path: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let minus_g_t = minus_g_t.token()?.clone(); + let path = pop_item!(self, path, Path, context); + let function_def_opt0_0_built = FunctionDefOpt0 { + minus_g_t, + path: Box::new(path), + }; + self.push( + ASTType::FunctionDefOpt0(Some(function_def_opt0_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 18: + /// + /// `FunctionDefOpt0 /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn function_def_opt0_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::FunctionDefOpt0(None), context); + Ok(()) + } + + /// Semantic action for production 19: + /// + /// `FunctionDefOpt /* Option::Some */: ParameterList;` + /// + #[parol_runtime::function_name::named] + fn function_def_opt_0(&mut self, _parameter_list: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let parameter_list = pop_item!(self, parameter_list, ParameterList, context); + let function_def_opt_0_built = FunctionDefOpt { + parameter_list: Box::new(parameter_list), + }; + self.push( + ASTType::FunctionDefOpt(Some(function_def_opt_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 20: + /// + /// `FunctionDefOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn function_def_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::FunctionDefOpt(None), context); + Ok(()) + } + + /// Semantic action for production 21: + /// + /// `ParameterList: Parameter ParameterListOpt /* Option */;` + /// + #[parol_runtime::function_name::named] + fn parameter_list( + &mut self, + _parameter: &ParseTreeType<'t>, + _parameter_list_opt: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let parameter_list_opt = pop_item!(self, parameter_list_opt, ParameterListOpt, context); + let parameter = pop_item!(self, parameter, Parameter, context); + let parameter_list_built = ParameterList { + parameter: Box::new(parameter), + parameter_list_opt, + }; + // Calling user action here + self.user_grammar.parameter_list(¶meter_list_built)?; + self.push(ASTType::ParameterList(parameter_list_built), context); + Ok(()) + } + + /// Semantic action for production 22: + /// + /// `ParameterListOpt /* Option::Some */: CommaParameterList;` + /// + #[parol_runtime::function_name::named] + fn parameter_list_opt_0(&mut self, _comma_parameter_list: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let comma_parameter_list = + pop_item!(self, comma_parameter_list, CommaParameterList, context); + let parameter_list_opt_0_built = ParameterListOpt { + comma_parameter_list: Box::new(comma_parameter_list), + }; + self.push( + ASTType::ParameterListOpt(Some(parameter_list_opt_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 23: + /// + /// `ParameterListOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn parameter_list_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::ParameterListOpt(None), context); + Ok(()) + } + + /// Semantic action for production 24: + /// + /// `CommaParameterList: ',' CommaParameterListOpt /* Option */;` + /// + #[parol_runtime::function_name::named] + fn comma_parameter_list( + &mut self, + comma: &ParseTreeType<'t>, + _comma_parameter_list_opt: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let comma = comma.token()?.clone(); + let comma_parameter_list_opt = pop_item!( + self, + comma_parameter_list_opt, + CommaParameterListOpt, + context + ); + let comma_parameter_list_built = CommaParameterList { + comma, + comma_parameter_list_opt, + }; + // Calling user action here + self.user_grammar + .comma_parameter_list(&comma_parameter_list_built)?; + self.push( + ASTType::CommaParameterList(comma_parameter_list_built), + context, + ); + Ok(()) + } + + /// Semantic action for production 25: + /// + /// `CommaParameterListOpt /* Option::Some */: ParameterList;` + /// + #[parol_runtime::function_name::named] + fn comma_parameter_list_opt_0(&mut self, _parameter_list: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let parameter_list = pop_item!(self, parameter_list, ParameterList, context); + let comma_parameter_list_opt_0_built = CommaParameterListOpt { + parameter_list: Box::new(parameter_list), + }; + self.push( + ASTType::CommaParameterListOpt(Some(comma_parameter_list_opt_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 26: + /// + /// `CommaParameterListOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn comma_parameter_list_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::CommaParameterListOpt(None), context); + Ok(()) + } + + /// Semantic action for production 27: + /// + /// `Parameter: Ident ':' Path;` + /// + #[parol_runtime::function_name::named] + fn parameter( + &mut self, + _ident: &ParseTreeType<'t>, + colon: &ParseTreeType<'t>, + _path: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let colon = colon.token()?.clone(); + let path = pop_item!(self, path, Path, context); + let ident = pop_item!(self, ident, Ident, context); + let parameter_built = Parameter { + ident: Box::new(ident), + colon, + path: Box::new(path), + }; + // Calling user action here + self.user_grammar.parameter(¶meter_built)?; + self.push(ASTType::Parameter(parameter_built), context); + Ok(()) + } + + /// Semantic action for production 28: + /// + /// `ConstantDef: 'const' Ident ':' Path '=' Expr Semi;` + /// + #[parol_runtime::function_name::named] + fn constant_def( + &mut self, + r#const: &ParseTreeType<'t>, + _ident: &ParseTreeType<'t>, + colon: &ParseTreeType<'t>, + _path: &ParseTreeType<'t>, + equ: &ParseTreeType<'t>, + _expr: &ParseTreeType<'t>, + _semi: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let r#const = r#const.token()?.clone(); + let colon = colon.token()?.clone(); + let equ = equ.token()?.clone(); + let semi = pop_item!(self, semi, Semi, context); + let expr = pop_item!(self, expr, Expr, context); + let path = pop_item!(self, path, Path, context); + let ident = pop_item!(self, ident, Ident, context); + let constant_def_built = ConstantDef { + r#const, + ident: Box::new(ident), + colon, + path: Box::new(path), + equ, + expr: Box::new(expr), + semi: Box::new(semi), + }; + // Calling user action here + self.user_grammar.constant_def(&constant_def_built)?; + self.push(ASTType::ConstantDef(constant_def_built), context); + Ok(()) + } + + /// Semantic action for production 29: + /// + /// `Scope: ScopeContent ScopeOpt /* Option */;` + /// + #[parol_runtime::function_name::named] + fn scope( + &mut self, + _scope_content: &ParseTreeType<'t>, + _scope_opt: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let scope_opt = pop_item!(self, scope_opt, ScopeOpt, context); + let scope_content = pop_item!(self, scope_content, ScopeContent, context); + let scope_built = Scope { + scope_content: Box::new(scope_content), + scope_opt, + }; + // Calling user action here + self.user_grammar.scope(&scope_built)?; + self.push(ASTType::Scope(scope_built), context); + Ok(()) + } + + /// Semantic action for production 30: + /// + /// `ScopeOpt /* Option::Some */: EndOfLine Scope;` + /// + #[parol_runtime::function_name::named] + fn scope_opt_0( + &mut self, + _end_of_line: &ParseTreeType<'t>, + _scope: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let scope = pop_item!(self, scope, Scope, context); + let end_of_line = pop_item!(self, end_of_line, EndOfLine, context); + let scope_opt_0_built = ScopeOpt { + end_of_line: Box::new(end_of_line), + scope: Box::new(scope), + }; + self.push(ASTType::ScopeOpt(Some(scope_opt_0_built)), context); + Ok(()) + } + + /// Semantic action for production 31: + /// + /// `ScopeOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn scope_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::ScopeOpt(None), context); + Ok(()) + } + + /// Semantic action for production 32: + /// + /// `ScopeContent: ScopeContentOpt /* Option */ ScopeContentOpt0 /* Option */ ScopeContentOpt1 /* Option */;` + /// + #[parol_runtime::function_name::named] + fn scope_content( + &mut self, + _scope_content_opt: &ParseTreeType<'t>, + _scope_content_opt0: &ParseTreeType<'t>, + _scope_content_opt1: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let scope_content_opt1 = pop_item!(self, scope_content_opt1, ScopeContentOpt1, context); + let scope_content_opt0 = pop_item!(self, scope_content_opt0, ScopeContentOpt0, context); + let scope_content_opt = pop_item!(self, scope_content_opt, ScopeContentOpt, context); + let scope_content_built = ScopeContent { + scope_content_opt, + scope_content_opt0, + scope_content_opt1, + }; + // Calling user action here + self.user_grammar.scope_content(&scope_content_built)?; + self.push(ASTType::ScopeContent(scope_content_built), context); + Ok(()) + } + + /// Semantic action for production 33: + /// + /// `ScopeContentOpt1 /* Option::Some */: Comment;` + /// + #[parol_runtime::function_name::named] + fn scope_content_opt1_0(&mut self, _comment: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let comment = pop_item!(self, comment, Comment, context); + let scope_content_opt1_0_built = ScopeContentOpt1 { + comment: Box::new(comment), + }; + self.push( + ASTType::ScopeContentOpt1(Some(scope_content_opt1_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 34: + /// + /// `ScopeContentOpt1 /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn scope_content_opt1_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::ScopeContentOpt1(None), context); + Ok(()) + } + + /// Semantic action for production 35: + /// + /// `ScopeContentOpt0 /* Option::Some */: ScopeContentKind;` + /// + #[parol_runtime::function_name::named] + fn scope_content_opt0_0(&mut self, _scope_content_kind: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let scope_content_kind = pop_item!(self, scope_content_kind, ScopeContentKind, context); + let scope_content_opt0_0_built = ScopeContentOpt0 { + scope_content_kind: Box::new(scope_content_kind), + }; + self.push( + ASTType::ScopeContentOpt0(Some(scope_content_opt0_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 36: + /// + /// `ScopeContentOpt0 /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn scope_content_opt0_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::ScopeContentOpt0(None), context); + Ok(()) + } + + /// Semantic action for production 37: + /// + /// `ScopeContentOpt /* Option::Some */: Break;` + /// + #[parol_runtime::function_name::named] + fn scope_content_opt_0(&mut self, _break: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let r#break = pop_item!(self, r#break, Break, context); + let scope_content_opt_0_built = ScopeContentOpt { + r#break: Box::new(r#break), + }; + self.push( + ASTType::ScopeContentOpt(Some(scope_content_opt_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 38: + /// + /// `ScopeContentOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn scope_content_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::ScopeContentOpt(None), context); + Ok(()) + } + + /// Semantic action for production 39: + /// + /// `ScopeContentKind: Statement;` + /// + #[parol_runtime::function_name::named] + fn scope_content_kind_0(&mut self, _statement: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let statement = pop_item!(self, statement, Statement, context); + let scope_content_kind_0_built = ScopeContentKindStatement { + statement: Box::new(statement), + }; + let scope_content_kind_0_built = ScopeContentKind::Statement(scope_content_kind_0_built); + // Calling user action here + self.user_grammar + .scope_content_kind(&scope_content_kind_0_built)?; + self.push( + ASTType::ScopeContentKind(scope_content_kind_0_built), + context, + ); + Ok(()) + } + + /// Semantic action for production 40: + /// + /// `ScopeContentKind: Block;` + /// + #[parol_runtime::function_name::named] + fn scope_content_kind_1(&mut self, _block: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let block = pop_item!(self, block, Block, context); + let scope_content_kind_1_built = ScopeContentKindBlock { + block: Box::new(block), + }; + let scope_content_kind_1_built = ScopeContentKind::Block(scope_content_kind_1_built); + // Calling user action here + self.user_grammar + .scope_content_kind(&scope_content_kind_1_built)?; + self.push( + ASTType::ScopeContentKind(scope_content_kind_1_built), + context, + ); + Ok(()) + } + + /// Semantic action for production 41: + /// + /// `Statement: StatementKind Semi;` + /// + #[parol_runtime::function_name::named] + fn statement( + &mut self, + _statement_kind: &ParseTreeType<'t>, + _semi: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let semi = pop_item!(self, semi, Semi, context); + let statement_kind = pop_item!(self, statement_kind, StatementKind, context); + let statement_built = Statement { + statement_kind: Box::new(statement_kind), + semi: Box::new(semi), + }; + // Calling user action here + self.user_grammar.statement(&statement_built)?; + self.push(ASTType::Statement(statement_built), context); + Ok(()) + } + + /// Semantic action for production 42: + /// + /// `Break: '.';` + /// + #[parol_runtime::function_name::named] + fn r#break(&mut self, r#break: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let r#break = r#break.token()?.clone(); + let r#break_built = Break { r#break }; + // Calling user action here + self.user_grammar.r#break(&r#break_built)?; + self.push(ASTType::Break(r#break_built), context); + Ok(()) + } + + /// Semantic action for production 43: + /// + /// `Semi: ';';` + /// + #[parol_runtime::function_name::named] + fn semi(&mut self, semi: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let semi = semi.token()?.clone(); + let semi_built = Semi { semi }; + // Calling user action here + self.user_grammar.semi(&semi_built)?; + self.push(ASTType::Semi(semi_built), context); + Ok(()) + } + + /// Semantic action for production 44: + /// + /// `StatementKind: LetStmt;` + /// + #[parol_runtime::function_name::named] + fn statement_kind_0(&mut self, _let_stmt: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let let_stmt = pop_item!(self, let_stmt, LetStmt, context); + let statement_kind_0_built = StatementKindLetStmt { + let_stmt: Box::new(let_stmt), + }; + let statement_kind_0_built = StatementKind::LetStmt(statement_kind_0_built); + // Calling user action here + self.user_grammar.statement_kind(&statement_kind_0_built)?; + self.push(ASTType::StatementKind(statement_kind_0_built), context); + Ok(()) + } + + /// Semantic action for production 45: + /// + /// `StatementKind: Expr;` + /// + #[parol_runtime::function_name::named] + fn statement_kind_1(&mut self, _expr: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let expr = pop_item!(self, expr, Expr, context); + let statement_kind_1_built = StatementKindExpr { + expr: Box::new(expr), + }; + let statement_kind_1_built = StatementKind::Expr(statement_kind_1_built); + // Calling user action here + self.user_grammar.statement_kind(&statement_kind_1_built)?; + self.push(ASTType::StatementKind(statement_kind_1_built), context); + Ok(()) + } + + /// Semantic action for production 46: + /// + /// `StatementKind: ReturnStmt;` + /// + #[parol_runtime::function_name::named] + fn statement_kind_2(&mut self, _return_stmt: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let return_stmt = pop_item!(self, return_stmt, ReturnStmt, context); + let statement_kind_2_built = StatementKindReturnStmt { + return_stmt: Box::new(return_stmt), + }; + let statement_kind_2_built = StatementKind::ReturnStmt(statement_kind_2_built); + // Calling user action here + self.user_grammar.statement_kind(&statement_kind_2_built)?; + self.push(ASTType::StatementKind(statement_kind_2_built), context); + Ok(()) + } + + /// Semantic action for production 47: + /// + /// `ReturnStmt: 'return';` + /// + #[parol_runtime::function_name::named] + fn return_stmt(&mut self, return_stmt: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let return_stmt = return_stmt.token()?.clone(); + let return_stmt_built = ReturnStmt { return_stmt }; + // Calling user action here + self.user_grammar.return_stmt(&return_stmt_built)?; + self.push(ASTType::ReturnStmt(return_stmt_built), context); + Ok(()) + } + + /// Semantic action for production 48: + /// + /// `LetStmt: 'let' Ident '=' Expr;` + /// + #[parol_runtime::function_name::named] + fn let_stmt( + &mut self, + r#let: &ParseTreeType<'t>, + _ident: &ParseTreeType<'t>, + equ: &ParseTreeType<'t>, + _expr: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let r#let = r#let.token()?.clone(); + let equ = equ.token()?.clone(); + let expr = pop_item!(self, expr, Expr, context); + let ident = pop_item!(self, ident, Ident, context); + let let_stmt_built = LetStmt { + r#let, + ident: Box::new(ident), + equ, + expr: Box::new(expr), + }; + // Calling user action here + self.user_grammar.let_stmt(&let_stmt_built)?; + self.push(ASTType::LetStmt(let_stmt_built), context); + Ok(()) + } + + /// Semantic action for production 49: + /// + /// `Expr: SetExpr;` + /// + #[parol_runtime::function_name::named] + fn expr(&mut self, _set_expr: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let set_expr = pop_item!(self, set_expr, SetExpr, context); + let expr_built = Expr { + set_expr: Box::new(set_expr), + }; + // Calling user action here + self.user_grammar.expr(&expr_built)?; + self.push(ASTType::Expr(expr_built), context); + Ok(()) + } + + /// Semantic action for production 50: + /// + /// `SetExpr: LogicalOrExpr SetExprOpt /* Option */;` + /// + #[parol_runtime::function_name::named] + fn set_expr( + &mut self, + _logical_or_expr: &ParseTreeType<'t>, + _set_expr_opt: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let set_expr_opt = pop_item!(self, set_expr_opt, SetExprOpt, context); + let logical_or_expr = pop_item!(self, logical_or_expr, LogicalOrExpr, context); + let set_expr_built = SetExpr { + logical_or_expr: Box::new(logical_or_expr), + set_expr_opt, + }; + // Calling user action here + self.user_grammar.set_expr(&set_expr_built)?; + self.push(ASTType::SetExpr(set_expr_built), context); + Ok(()) + } + + /// Semantic action for production 51: + /// + /// `SetExprOpt /* Option::Some */: ':=' LogicalOrExpr;` + /// + #[parol_runtime::function_name::named] + fn set_expr_opt_0( + &mut self, + colon_equ: &ParseTreeType<'t>, + _logical_or_expr: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let colon_equ = colon_equ.token()?.clone(); + let logical_or_expr = pop_item!(self, logical_or_expr, LogicalOrExpr, context); + let set_expr_opt_0_built = SetExprOpt { + colon_equ, + logical_or_expr: Box::new(logical_or_expr), + }; + self.push(ASTType::SetExprOpt(Some(set_expr_opt_0_built)), context); + Ok(()) + } + + /// Semantic action for production 52: + /// + /// `SetExprOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn set_expr_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::SetExprOpt(None), context); + Ok(()) + } + + /// Semantic action for production 53: + /// + /// `LogicalOrExpr: LogicalOrExprList /* Vec */ LogicalAndExpr;` + /// + #[parol_runtime::function_name::named] + fn logical_or_expr( + &mut self, + _logical_or_expr_list: &ParseTreeType<'t>, + _logical_and_expr: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let logical_and_expr = pop_item!(self, logical_and_expr, LogicalAndExpr, context); + let logical_or_expr_list = + pop_item!(self, logical_or_expr_list, LogicalOrExprList, context); + let logical_or_expr_built = LogicalOrExpr { + logical_or_expr_list, + logical_and_expr: Box::new(logical_and_expr), + }; + // Calling user action here + self.user_grammar.logical_or_expr(&logical_or_expr_built)?; + self.push(ASTType::LogicalOrExpr(logical_or_expr_built), context); + Ok(()) + } + + /// Semantic action for production 54: + /// + /// `LogicalOrExprList /* Vec::Push */: LogicalOrExprList LogicalAndExpr '||';` + /// + #[parol_runtime::function_name::named] + fn logical_or_expr_list_0( + &mut self, + _logical_or_expr_list: &ParseTreeType<'t>, + _logical_and_expr: &ParseTreeType<'t>, + or_or: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let or_or = or_or.token()?.clone(); + let logical_and_expr = pop_item!(self, logical_and_expr, LogicalAndExpr, context); + let mut logical_or_expr_list = + pop_item!(self, logical_or_expr_list, LogicalOrExprList, context); + let logical_or_expr_list_0_built = LogicalOrExprList { + or_or, + logical_and_expr: Box::new(logical_and_expr), + }; + // Add an element to the vector + logical_or_expr_list.push(logical_or_expr_list_0_built); + self.push(ASTType::LogicalOrExprList(logical_or_expr_list), context); + Ok(()) + } + + /// Semantic action for production 55: + /// + /// `LogicalOrExprList /* Vec::New */: ;` + /// + #[parol_runtime::function_name::named] + fn logical_or_expr_list_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let logical_or_expr_list_1_built = Vec::new(); + self.push( + ASTType::LogicalOrExprList(logical_or_expr_list_1_built), + context, + ); + Ok(()) + } + + /// Semantic action for production 56: + /// + /// `LogicalAndExpr: LogicalAndExprList /* Vec */ CompareExpr;` + /// + #[parol_runtime::function_name::named] + fn logical_and_expr( + &mut self, + _logical_and_expr_list: &ParseTreeType<'t>, + _compare_expr: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let compare_expr = pop_item!(self, compare_expr, CompareExpr, context); + let logical_and_expr_list = + pop_item!(self, logical_and_expr_list, LogicalAndExprList, context); + let logical_and_expr_built = LogicalAndExpr { + logical_and_expr_list, + compare_expr: Box::new(compare_expr), + }; + // Calling user action here + self.user_grammar + .logical_and_expr(&logical_and_expr_built)?; + self.push(ASTType::LogicalAndExpr(logical_and_expr_built), context); + Ok(()) + } + + /// Semantic action for production 57: + /// + /// `LogicalAndExprList /* Vec::Push */: LogicalAndExprList CompareExpr '&&';` + /// + #[parol_runtime::function_name::named] + fn logical_and_expr_list_0( + &mut self, + _logical_and_expr_list: &ParseTreeType<'t>, + _compare_expr: &ParseTreeType<'t>, + amp_amp: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let amp_amp = amp_amp.token()?.clone(); + let compare_expr = pop_item!(self, compare_expr, CompareExpr, context); + let mut logical_and_expr_list = + pop_item!(self, logical_and_expr_list, LogicalAndExprList, context); + let logical_and_expr_list_0_built = LogicalAndExprList { + amp_amp, + compare_expr: Box::new(compare_expr), + }; + // Add an element to the vector + logical_and_expr_list.push(logical_and_expr_list_0_built); + self.push(ASTType::LogicalAndExprList(logical_and_expr_list), context); + Ok(()) + } + + /// Semantic action for production 58: + /// + /// `LogicalAndExprList /* Vec::New */: ;` + /// + #[parol_runtime::function_name::named] + fn logical_and_expr_list_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let logical_and_expr_list_1_built = Vec::new(); + self.push( + ASTType::LogicalAndExprList(logical_and_expr_list_1_built), + context, + ); + Ok(()) + } + + /// Semantic action for production 59: + /// + /// `CompareExpr: ArithmeticExpr CompareExprList /* Vec */;` + /// + #[parol_runtime::function_name::named] + fn compare_expr( + &mut self, + _arithmetic_expr: &ParseTreeType<'t>, + _compare_expr_list: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let compare_expr_list = pop_item!(self, compare_expr_list, CompareExprList, context); + let arithmetic_expr = pop_item!(self, arithmetic_expr, ArithmeticExpr, context); + let compare_expr_built = CompareExpr { + arithmetic_expr: Box::new(arithmetic_expr), + compare_expr_list, + }; + // Calling user action here + self.user_grammar.compare_expr(&compare_expr_built)?; + self.push(ASTType::CompareExpr(compare_expr_built), context); + Ok(()) + } + + /// Semantic action for production 60: + /// + /// `CompareExprList /* Vec::Push */: CompareExprList CompareOp ArithmeticExpr;` + /// + #[parol_runtime::function_name::named] + fn compare_expr_list_0( + &mut self, + _compare_expr_list: &ParseTreeType<'t>, + _compare_op: &ParseTreeType<'t>, + _arithmetic_expr: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let arithmetic_expr = pop_item!(self, arithmetic_expr, ArithmeticExpr, context); + let compare_op = pop_item!(self, compare_op, CompareOp, context); + let mut compare_expr_list = pop_item!(self, compare_expr_list, CompareExprList, context); + let compare_expr_list_0_built = CompareExprList { + arithmetic_expr: Box::new(arithmetic_expr), + compare_op: Box::new(compare_op), + }; + // Add an element to the vector + compare_expr_list.push(compare_expr_list_0_built); + self.push(ASTType::CompareExprList(compare_expr_list), context); + Ok(()) + } + + /// Semantic action for production 61: + /// + /// `CompareExprList /* Vec::New */: ;` + /// + #[parol_runtime::function_name::named] + fn compare_expr_list_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let compare_expr_list_1_built = Vec::new(); + self.push(ASTType::CompareExprList(compare_expr_list_1_built), context); + Ok(()) + } + + /// Semantic action for production 62: + /// + /// `CompareOp: '>=';` + /// + #[parol_runtime::function_name::named] + fn compare_op_0(&mut self, g_t_equ: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let g_t_equ = g_t_equ.token()?.clone(); + let compare_op_0_built = CompareOpGTEqu { g_t_equ }; + let compare_op_0_built = CompareOp::GTEqu(compare_op_0_built); + // Calling user action here + self.user_grammar.compare_op(&compare_op_0_built)?; + self.push(ASTType::CompareOp(compare_op_0_built), context); + Ok(()) + } + + /// Semantic action for production 63: + /// + /// `CompareOp: '<=';` + /// + #[parol_runtime::function_name::named] + fn compare_op_1(&mut self, l_t_equ: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let l_t_equ = l_t_equ.token()?.clone(); + let compare_op_1_built = CompareOpLTEqu { l_t_equ }; + let compare_op_1_built = CompareOp::LTEqu(compare_op_1_built); + // Calling user action here + self.user_grammar.compare_op(&compare_op_1_built)?; + self.push(ASTType::CompareOp(compare_op_1_built), context); + Ok(()) + } + + /// Semantic action for production 64: + /// + /// `CompareOp: '>';` + /// + #[parol_runtime::function_name::named] + fn compare_op_2(&mut self, g_t: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let g_t = g_t.token()?.clone(); + let compare_op_2_built = CompareOpGT { g_t }; + let compare_op_2_built = CompareOp::GT(compare_op_2_built); + // Calling user action here + self.user_grammar.compare_op(&compare_op_2_built)?; + self.push(ASTType::CompareOp(compare_op_2_built), context); + Ok(()) + } + + /// Semantic action for production 65: + /// + /// `CompareOp: '<';` + /// + #[parol_runtime::function_name::named] + fn compare_op_3(&mut self, l_t: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let l_t = l_t.token()?.clone(); + let compare_op_3_built = CompareOpLT { l_t }; + let compare_op_3_built = CompareOp::LT(compare_op_3_built); + // Calling user action here + self.user_grammar.compare_op(&compare_op_3_built)?; + self.push(ASTType::CompareOp(compare_op_3_built), context); + Ok(()) + } + + /// Semantic action for production 66: + /// + /// `CompareOp: '!=';` + /// + #[parol_runtime::function_name::named] + fn compare_op_4(&mut self, bang_equ: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let bang_equ = bang_equ.token()?.clone(); + let compare_op_4_built = CompareOpBangEqu { bang_equ }; + let compare_op_4_built = CompareOp::BangEqu(compare_op_4_built); + // Calling user action here + self.user_grammar.compare_op(&compare_op_4_built)?; + self.push(ASTType::CompareOp(compare_op_4_built), context); + Ok(()) + } + + /// Semantic action for production 67: + /// + /// `CompareOp: '/=';` + /// + #[parol_runtime::function_name::named] + fn compare_op_5(&mut self, slash_equ: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let slash_equ = slash_equ.token()?.clone(); + let compare_op_5_built = CompareOpSlashEqu { slash_equ }; + let compare_op_5_built = CompareOp::SlashEqu(compare_op_5_built); + // Calling user action here + self.user_grammar.compare_op(&compare_op_5_built)?; + self.push(ASTType::CompareOp(compare_op_5_built), context); + Ok(()) + } + + /// Semantic action for production 68: + /// + /// `CompareOp: '==';` + /// + #[parol_runtime::function_name::named] + fn compare_op_6(&mut self, equ_equ: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let equ_equ = equ_equ.token()?.clone(); + let compare_op_6_built = CompareOpEquEqu { equ_equ }; + let compare_op_6_built = CompareOp::EquEqu(compare_op_6_built); + // Calling user action here + self.user_grammar.compare_op(&compare_op_6_built)?; + self.push(ASTType::CompareOp(compare_op_6_built), context); + Ok(()) + } + + /// Semantic action for production 69: + /// + /// `ArithmeticExpr: ArithmeticExprList /* Vec */ FactorExpr;` + /// + #[parol_runtime::function_name::named] + fn arithmetic_expr( + &mut self, + _arithmetic_expr_list: &ParseTreeType<'t>, + _factor_expr: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let factor_expr = pop_item!(self, factor_expr, FactorExpr, context); + let arithmetic_expr_list = + pop_item!(self, arithmetic_expr_list, ArithmeticExprList, context); + let arithmetic_expr_built = ArithmeticExpr { + arithmetic_expr_list, + factor_expr: Box::new(factor_expr), + }; + // Calling user action here + self.user_grammar.arithmetic_expr(&arithmetic_expr_built)?; + self.push(ASTType::ArithmeticExpr(arithmetic_expr_built), context); + Ok(()) + } + + /// Semantic action for production 70: + /// + /// `ArithmeticExprList /* Vec::Push */: ArithmeticExprList FactorExpr ArithmeticOp;` + /// + #[parol_runtime::function_name::named] + fn arithmetic_expr_list_0( + &mut self, + _arithmetic_expr_list: &ParseTreeType<'t>, + _factor_expr: &ParseTreeType<'t>, + _arithmetic_op: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let arithmetic_op = pop_item!(self, arithmetic_op, ArithmeticOp, context); + let factor_expr = pop_item!(self, factor_expr, FactorExpr, context); + let mut arithmetic_expr_list = + pop_item!(self, arithmetic_expr_list, ArithmeticExprList, context); + let arithmetic_expr_list_0_built = ArithmeticExprList { + arithmetic_op: Box::new(arithmetic_op), + factor_expr: Box::new(factor_expr), + }; + // Add an element to the vector + arithmetic_expr_list.push(arithmetic_expr_list_0_built); + self.push(ASTType::ArithmeticExprList(arithmetic_expr_list), context); + Ok(()) + } + + /// Semantic action for production 71: + /// + /// `ArithmeticExprList /* Vec::New */: ;` + /// + #[parol_runtime::function_name::named] + fn arithmetic_expr_list_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let arithmetic_expr_list_1_built = Vec::new(); + self.push( + ASTType::ArithmeticExprList(arithmetic_expr_list_1_built), + context, + ); + Ok(()) + } + + /// Semantic action for production 72: + /// + /// `ArithmeticOp: '+';` + /// + #[parol_runtime::function_name::named] + fn arithmetic_op_0(&mut self, plus: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let plus = plus.token()?.clone(); + let arithmetic_op_0_built = ArithmeticOpPlus { plus }; + let arithmetic_op_0_built = ArithmeticOp::Plus(arithmetic_op_0_built); + // Calling user action here + self.user_grammar.arithmetic_op(&arithmetic_op_0_built)?; + self.push(ASTType::ArithmeticOp(arithmetic_op_0_built), context); + Ok(()) + } + + /// Semantic action for production 73: + /// + /// `ArithmeticOp: '-';` + /// + #[parol_runtime::function_name::named] + fn arithmetic_op_1(&mut self, minus: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let minus = minus.token()?.clone(); + let arithmetic_op_1_built = ArithmeticOpMinus { minus }; + let arithmetic_op_1_built = ArithmeticOp::Minus(arithmetic_op_1_built); + // Calling user action here + self.user_grammar.arithmetic_op(&arithmetic_op_1_built)?; + self.push(ASTType::ArithmeticOp(arithmetic_op_1_built), context); + Ok(()) + } + + /// Semantic action for production 74: + /// + /// `FactorExpr: FactorExprList /* Vec */ CastExpr;` + /// + #[parol_runtime::function_name::named] + fn factor_expr( + &mut self, + _factor_expr_list: &ParseTreeType<'t>, + _cast_expr: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let cast_expr = pop_item!(self, cast_expr, CastExpr, context); + let factor_expr_list = pop_item!(self, factor_expr_list, FactorExprList, context); + let factor_expr_built = FactorExpr { + factor_expr_list, + cast_expr: Box::new(cast_expr), + }; + // Calling user action here + self.user_grammar.factor_expr(&factor_expr_built)?; + self.push(ASTType::FactorExpr(factor_expr_built), context); + Ok(()) + } + + /// Semantic action for production 75: + /// + /// `FactorExprList /* Vec::Push */: FactorExprList CastExpr FactorOp;` + /// + #[parol_runtime::function_name::named] + fn factor_expr_list_0( + &mut self, + _factor_expr_list: &ParseTreeType<'t>, + _cast_expr: &ParseTreeType<'t>, + _factor_op: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let factor_op = pop_item!(self, factor_op, FactorOp, context); + let cast_expr = pop_item!(self, cast_expr, CastExpr, context); + let mut factor_expr_list = pop_item!(self, factor_expr_list, FactorExprList, context); + let factor_expr_list_0_built = FactorExprList { + factor_op: Box::new(factor_op), + cast_expr: Box::new(cast_expr), + }; + // Add an element to the vector + factor_expr_list.push(factor_expr_list_0_built); + self.push(ASTType::FactorExprList(factor_expr_list), context); + Ok(()) + } + + /// Semantic action for production 76: + /// + /// `FactorExprList /* Vec::New */: ;` + /// + #[parol_runtime::function_name::named] + fn factor_expr_list_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let factor_expr_list_1_built = Vec::new(); + self.push(ASTType::FactorExprList(factor_expr_list_1_built), context); + Ok(()) + } + + /// Semantic action for production 77: + /// + /// `FactorOp: '*';` + /// + #[parol_runtime::function_name::named] + fn factor_op_0(&mut self, star: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let star = star.token()?.clone(); + let factor_op_0_built = FactorOpStar { star }; + let factor_op_0_built = FactorOp::Star(factor_op_0_built); + // Calling user action here + self.user_grammar.factor_op(&factor_op_0_built)?; + self.push(ASTType::FactorOp(factor_op_0_built), context); + Ok(()) + } + + /// Semantic action for production 78: + /// + /// `FactorOp: '/';` + /// + #[parol_runtime::function_name::named] + fn factor_op_1(&mut self, slash: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let slash = slash.token()?.clone(); + let factor_op_1_built = FactorOpSlash { slash }; + let factor_op_1_built = FactorOp::Slash(factor_op_1_built); + // Calling user action here + self.user_grammar.factor_op(&factor_op_1_built)?; + self.push(ASTType::FactorOp(factor_op_1_built), context); + Ok(()) + } + + /// Semantic action for production 79: + /// + /// `FactorOp: '%';` + /// + #[parol_runtime::function_name::named] + fn factor_op_2(&mut self, percent: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let percent = percent.token()?.clone(); + let factor_op_2_built = FactorOpPercent { percent }; + let factor_op_2_built = FactorOp::Percent(factor_op_2_built); + // Calling user action here + self.user_grammar.factor_op(&factor_op_2_built)?; + self.push(ASTType::FactorOp(factor_op_2_built), context); + Ok(()) + } + + /// Semantic action for production 80: + /// + /// `CastExpr: PrefixExpr CastExprOpt /* Option */;` + /// + #[parol_runtime::function_name::named] + fn cast_expr( + &mut self, + _prefix_expr: &ParseTreeType<'t>, + _cast_expr_opt: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let cast_expr_opt = pop_item!(self, cast_expr_opt, CastExprOpt, context); + let prefix_expr = pop_item!(self, prefix_expr, PrefixExpr, context); + let cast_expr_built = CastExpr { + prefix_expr: Box::new(prefix_expr), + cast_expr_opt, + }; + // Calling user action here + self.user_grammar.cast_expr(&cast_expr_built)?; + self.push(ASTType::CastExpr(cast_expr_built), context); + Ok(()) + } + + /// Semantic action for production 81: + /// + /// `CastExprOpt /* Option::Some */: 'as' Path;` + /// + #[parol_runtime::function_name::named] + fn cast_expr_opt_0( + &mut self, + r#as: &ParseTreeType<'t>, + _path: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let r#as = r#as.token()?.clone(); + let path = pop_item!(self, path, Path, context); + let cast_expr_opt_0_built = CastExprOpt { + r#as, + path: Box::new(path), + }; + self.push(ASTType::CastExprOpt(Some(cast_expr_opt_0_built)), context); + Ok(()) + } + + /// Semantic action for production 82: + /// + /// `CastExprOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn cast_expr_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::CastExprOpt(None), context); + Ok(()) + } + + /// Semantic action for production 83: + /// + /// `PrefixExpr: '-' ApplyExpr;` + /// + #[parol_runtime::function_name::named] + fn prefix_expr_0( + &mut self, + minus: &ParseTreeType<'t>, + _apply_expr: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let minus = minus.token()?.clone(); + let apply_expr = pop_item!(self, apply_expr, ApplyExpr, context); + let prefix_expr_0_built = PrefixExprMinusApplyExpr { + minus, + apply_expr: Box::new(apply_expr), + }; + let prefix_expr_0_built = PrefixExpr::MinusApplyExpr(prefix_expr_0_built); + // Calling user action here + self.user_grammar.prefix_expr(&prefix_expr_0_built)?; + self.push(ASTType::PrefixExpr(prefix_expr_0_built), context); + Ok(()) + } + + /// Semantic action for production 84: + /// + /// `PrefixExpr: PrefixExprList /* Vec */ ApplyExpr;` + /// + #[parol_runtime::function_name::named] + fn prefix_expr_1( + &mut self, + _prefix_expr_list: &ParseTreeType<'t>, + _apply_expr: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let apply_expr = pop_item!(self, apply_expr, ApplyExpr, context); + let prefix_expr_list = pop_item!(self, prefix_expr_list, PrefixExprList, context); + let prefix_expr_1_built = PrefixExprPrefixExprListApplyExpr { + prefix_expr_list, + apply_expr: Box::new(apply_expr), + }; + let prefix_expr_1_built = PrefixExpr::PrefixExprListApplyExpr(prefix_expr_1_built); + // Calling user action here + self.user_grammar.prefix_expr(&prefix_expr_1_built)?; + self.push(ASTType::PrefixExpr(prefix_expr_1_built), context); + Ok(()) + } + + /// Semantic action for production 85: + /// + /// `PrefixExprList /* Vec::Push */: PrefixExprList Qualif;` + /// + #[parol_runtime::function_name::named] + fn prefix_expr_list_0( + &mut self, + _prefix_expr_list: &ParseTreeType<'t>, + _qualif: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let qualif = pop_item!(self, qualif, Qualif, context); + let mut prefix_expr_list = pop_item!(self, prefix_expr_list, PrefixExprList, context); + let prefix_expr_list_0_built = PrefixExprList { + qualif: Box::new(qualif), + }; + // Add an element to the vector + prefix_expr_list.push(prefix_expr_list_0_built); + self.push(ASTType::PrefixExprList(prefix_expr_list), context); + Ok(()) + } + + /// Semantic action for production 86: + /// + /// `PrefixExprList /* Vec::New */: ;` + /// + #[parol_runtime::function_name::named] + fn prefix_expr_list_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let prefix_expr_list_1_built = Vec::new(); + self.push(ASTType::PrefixExprList(prefix_expr_list_1_built), context); + Ok(()) + } + + /// Semantic action for production 87: + /// + /// `PrefixExpr: 'wait' ApplyExpr;` + /// + #[parol_runtime::function_name::named] + fn prefix_expr_2( + &mut self, + wait: &ParseTreeType<'t>, + _apply_expr: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let wait = wait.token()?.clone(); + let apply_expr = pop_item!(self, apply_expr, ApplyExpr, context); + let prefix_expr_2_built = PrefixExprWaitApplyExpr { + wait, + apply_expr: Box::new(apply_expr), + }; + let prefix_expr_2_built = PrefixExpr::WaitApplyExpr(prefix_expr_2_built); + // Calling user action here + self.user_grammar.prefix_expr(&prefix_expr_2_built)?; + self.push(ASTType::PrefixExpr(prefix_expr_2_built), context); + Ok(()) + } + + /// Semantic action for production 88: + /// + /// `PrefixExpr: 'call' ApplyExpr;` + /// + #[parol_runtime::function_name::named] + fn prefix_expr_3( + &mut self, + call: &ParseTreeType<'t>, + _apply_expr: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let call = call.token()?.clone(); + let apply_expr = pop_item!(self, apply_expr, ApplyExpr, context); + let prefix_expr_3_built = PrefixExprCallApplyExpr { + call, + apply_expr: Box::new(apply_expr), + }; + let prefix_expr_3_built = PrefixExpr::CallApplyExpr(prefix_expr_3_built); + // Calling user action here + self.user_grammar.prefix_expr(&prefix_expr_3_built)?; + self.push(ASTType::PrefixExpr(prefix_expr_3_built), context); + Ok(()) + } + + /// Semantic action for production 89: + /// + /// `ApplyExpr: LowerPrefixExpr ApplyExprList /* Vec */;` + /// + #[parol_runtime::function_name::named] + fn apply_expr( + &mut self, + _lower_prefix_expr: &ParseTreeType<'t>, + _apply_expr_list: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let apply_expr_list = pop_item!(self, apply_expr_list, ApplyExprList, context); + let lower_prefix_expr = pop_item!(self, lower_prefix_expr, LowerPrefixExpr, context); + let apply_expr_built = ApplyExpr { + lower_prefix_expr: Box::new(lower_prefix_expr), + apply_expr_list, + }; + // Calling user action here + self.user_grammar.apply_expr(&apply_expr_built)?; + self.push(ASTType::ApplyExpr(apply_expr_built), context); + Ok(()) + } + + /// Semantic action for production 90: + /// + /// `ApplyExprList /* Vec::Push */: ApplyExprList AtomicExpr;` + /// + #[parol_runtime::function_name::named] + fn apply_expr_list_0( + &mut self, + _apply_expr_list: &ParseTreeType<'t>, + _atomic_expr: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let atomic_expr = pop_item!(self, atomic_expr, AtomicExpr, context); + let mut apply_expr_list = pop_item!(self, apply_expr_list, ApplyExprList, context); + let apply_expr_list_0_built = ApplyExprList { + atomic_expr: Box::new(atomic_expr), + }; + // Add an element to the vector + apply_expr_list.push(apply_expr_list_0_built); + self.push(ASTType::ApplyExprList(apply_expr_list), context); + Ok(()) + } + + /// Semantic action for production 91: + /// + /// `ApplyExprList /* Vec::New */: ;` + /// + #[parol_runtime::function_name::named] + fn apply_expr_list_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let apply_expr_list_1_built = Vec::new(); + self.push(ASTType::ApplyExprList(apply_expr_list_1_built), context); + Ok(()) + } + + /// Semantic action for production 92: + /// + /// `LowerPrefixExpr: LowerPrefixExprOpt /* Option */ Callable;` + /// + #[parol_runtime::function_name::named] + fn lower_prefix_expr( + &mut self, + _lower_prefix_expr_opt: &ParseTreeType<'t>, + _callable: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let callable = pop_item!(self, callable, Callable, context); + let lower_prefix_expr_opt = + pop_item!(self, lower_prefix_expr_opt, LowerPrefixExprOpt, context); + let lower_prefix_expr_built = LowerPrefixExpr { + lower_prefix_expr_opt, + callable: Box::new(callable), + }; + // Calling user action here + self.user_grammar + .lower_prefix_expr(&lower_prefix_expr_built)?; + self.push(ASTType::LowerPrefixExpr(lower_prefix_expr_built), context); + Ok(()) + } + + /// Semantic action for production 93: + /// + /// `LowerPrefixExprOpt /* Option::Some */: LowerPrefixOp;` + /// + #[parol_runtime::function_name::named] + fn lower_prefix_expr_opt_0(&mut self, _lower_prefix_op: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let lower_prefix_op = pop_item!(self, lower_prefix_op, LowerPrefixOp, context); + let lower_prefix_expr_opt_0_built = LowerPrefixExprOpt { + lower_prefix_op: Box::new(lower_prefix_op), + }; + self.push( + ASTType::LowerPrefixExprOpt(Some(lower_prefix_expr_opt_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 94: + /// + /// `LowerPrefixExprOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn lower_prefix_expr_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::LowerPrefixExprOpt(None), context); + Ok(()) + } + + /// Semantic action for production 95: + /// + /// `LowerPrefixOp: '&';` + /// + #[parol_runtime::function_name::named] + fn lower_prefix_op_0(&mut self, amp: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let amp = amp.token()?.clone(); + let lower_prefix_op_0_built = LowerPrefixOpAmp { amp }; + let lower_prefix_op_0_built = LowerPrefixOp::Amp(lower_prefix_op_0_built); + // Calling user action here + self.user_grammar + .lower_prefix_op(&lower_prefix_op_0_built)?; + self.push(ASTType::LowerPrefixOp(lower_prefix_op_0_built), context); + Ok(()) + } + + /// Semantic action for production 96: + /// + /// `LowerPrefixOp: '$';` + /// + #[parol_runtime::function_name::named] + fn lower_prefix_op_1(&mut self, dollar: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let dollar = dollar.token()?.clone(); + let lower_prefix_op_1_built = LowerPrefixOpDollar { dollar }; + let lower_prefix_op_1_built = LowerPrefixOp::Dollar(lower_prefix_op_1_built); + // Calling user action here + self.user_grammar + .lower_prefix_op(&lower_prefix_op_1_built)?; + self.push(ASTType::LowerPrefixOp(lower_prefix_op_1_built), context); + Ok(()) + } + + /// Semantic action for production 97: + /// + /// `Callable: Path;` + /// + #[parol_runtime::function_name::named] + fn callable_0(&mut self, _path: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let path = pop_item!(self, path, Path, context); + let callable_0_built = CallablePath { + path: Box::new(path), + }; + let callable_0_built = Callable::Path(callable_0_built); + // Calling user action here + self.user_grammar.callable(&callable_0_built)?; + self.push(ASTType::Callable(callable_0_built), context); + Ok(()) + } + + /// Semantic action for production 98: + /// + /// `Callable: Literal CallableOpt /* Option */;` + /// + #[parol_runtime::function_name::named] + fn callable_1( + &mut self, + _literal: &ParseTreeType<'t>, + _callable_opt: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let callable_opt = pop_item!(self, callable_opt, CallableOpt, context); + let literal = pop_item!(self, literal, Literal, context); + let callable_1_built = CallableLiteralCallableOpt { + literal: Box::new(literal), + callable_opt, + }; + let callable_1_built = Callable::LiteralCallableOpt(callable_1_built); + // Calling user action here + self.user_grammar.callable(&callable_1_built)?; + self.push(ASTType::Callable(callable_1_built), context); + Ok(()) + } + + /// Semantic action for production 99: + /// + /// `Callable: '(' Expr ')';` + /// + #[parol_runtime::function_name::named] + fn callable_2( + &mut self, + l_paren: &ParseTreeType<'t>, + _expr: &ParseTreeType<'t>, + r_paren: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let l_paren = l_paren.token()?.clone(); + let r_paren = r_paren.token()?.clone(); + let expr = pop_item!(self, expr, Expr, context); + let callable_2_built = CallableLParenExprRParen { + l_paren, + expr: Box::new(expr), + r_paren, + }; + let callable_2_built = Callable::LParenExprRParen(callable_2_built); + // Calling user action here + self.user_grammar.callable(&callable_2_built)?; + self.push(ASTType::Callable(callable_2_built), context); + Ok(()) + } + + /// Semantic action for production 100: + /// + /// `Callable: IfExpr;` + /// + #[parol_runtime::function_name::named] + fn callable_3(&mut self, _if_expr: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let if_expr = pop_item!(self, if_expr, IfExpr, context); + let callable_3_built = CallableIfExpr { + if_expr: Box::new(if_expr), + }; + let callable_3_built = Callable::IfExpr(callable_3_built); + // Calling user action here + self.user_grammar.callable(&callable_3_built)?; + self.push(ASTType::Callable(callable_3_built), context); + Ok(()) + } + + /// Semantic action for production 101: + /// + /// `Callable: SelectExpr;` + /// + #[parol_runtime::function_name::named] + fn callable_4(&mut self, _select_expr: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let select_expr = pop_item!(self, select_expr, SelectExpr, context); + let callable_4_built = CallableSelectExpr { + select_expr: Box::new(select_expr), + }; + let callable_4_built = Callable::SelectExpr(callable_4_built); + // Calling user action here + self.user_grammar.callable(&callable_4_built)?; + self.push(ASTType::Callable(callable_4_built), context); + Ok(()) + } + + /// Semantic action for production 102: + /// + /// `CallableOpt /* Option::Some */: '?' Path;` + /// + #[parol_runtime::function_name::named] + fn callable_opt_0( + &mut self, + quest: &ParseTreeType<'t>, + _path: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let quest = quest.token()?.clone(); + let path = pop_item!(self, path, Path, context); + let callable_opt_0_built = CallableOpt { + quest, + path: Box::new(path), + }; + self.push(ASTType::CallableOpt(Some(callable_opt_0_built)), context); + Ok(()) + } + + /// Semantic action for production 103: + /// + /// `CallableOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn callable_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::CallableOpt(None), context); + Ok(()) + } + + /// Semantic action for production 104: + /// + /// `AtomicExpr: Qualif;` + /// + #[parol_runtime::function_name::named] + fn atomic_expr_0(&mut self, _qualif: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let qualif = pop_item!(self, qualif, Qualif, context); + let atomic_expr_0_built = AtomicExprQualif { + qualif: Box::new(qualif), + }; + let atomic_expr_0_built = AtomicExpr::Qualif(atomic_expr_0_built); + // Calling user action here + self.user_grammar.atomic_expr(&atomic_expr_0_built)?; + self.push(ASTType::AtomicExpr(atomic_expr_0_built), context); + Ok(()) + } + + /// Semantic action for production 105: + /// + /// `AtomicExpr: LowerPrefixExpr;` + /// + #[parol_runtime::function_name::named] + fn atomic_expr_1(&mut self, _lower_prefix_expr: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let lower_prefix_expr = pop_item!(self, lower_prefix_expr, LowerPrefixExpr, context); + let atomic_expr_1_built = AtomicExprLowerPrefixExpr { + lower_prefix_expr: Box::new(lower_prefix_expr), + }; + let atomic_expr_1_built = AtomicExpr::LowerPrefixExpr(atomic_expr_1_built); + // Calling user action here + self.user_grammar.atomic_expr(&atomic_expr_1_built)?; + self.push(ASTType::AtomicExpr(atomic_expr_1_built), context); + Ok(()) + } + + /// Semantic action for production 106: + /// + /// `IfExpr: 'if' Expr Block IfExprOpt /* Option */;` + /// + #[parol_runtime::function_name::named] + fn if_expr( + &mut self, + r#if: &ParseTreeType<'t>, + _expr: &ParseTreeType<'t>, + _block: &ParseTreeType<'t>, + _if_expr_opt: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let r#if = r#if.token()?.clone(); + let if_expr_opt = pop_item!(self, if_expr_opt, IfExprOpt, context); + let block = pop_item!(self, block, Block, context); + let expr = pop_item!(self, expr, Expr, context); + let if_expr_built = IfExpr { + r#if, + expr: Box::new(expr), + block: Box::new(block), + if_expr_opt, + }; + // Calling user action here + self.user_grammar.if_expr(&if_expr_built)?; + self.push(ASTType::IfExpr(if_expr_built), context); + Ok(()) + } + + /// Semantic action for production 107: + /// + /// `IfExprOpt /* Option::Some */: 'else' Block;` + /// + #[parol_runtime::function_name::named] + fn if_expr_opt_0( + &mut self, + r#else: &ParseTreeType<'t>, + _block: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let r#else = r#else.token()?.clone(); + let block = pop_item!(self, block, Block, context); + let if_expr_opt_0_built = IfExprOpt { + r#else, + block: Box::new(block), + }; + self.push(ASTType::IfExprOpt(Some(if_expr_opt_0_built)), context); + Ok(()) + } + + /// Semantic action for production 108: + /// + /// `IfExprOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn if_expr_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::IfExprOpt(None), context); + Ok(()) + } + + /// Semantic action for production 109: + /// + /// `SelectExpr: 'select' '{' SelectScope '}';` + /// + #[parol_runtime::function_name::named] + fn select_expr( + &mut self, + select: &ParseTreeType<'t>, + l_brace: &ParseTreeType<'t>, + _select_scope: &ParseTreeType<'t>, + r_brace: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let select = select.token()?.clone(); + let l_brace = l_brace.token()?.clone(); + let r_brace = r_brace.token()?.clone(); + let select_scope = pop_item!(self, select_scope, SelectScope, context); + let select_expr_built = SelectExpr { + select, + l_brace, + select_scope: Box::new(select_scope), + r_brace, + }; + // Calling user action here + self.user_grammar.select_expr(&select_expr_built)?; + self.push(ASTType::SelectExpr(select_expr_built), context); + Ok(()) + } + + /// Semantic action for production 110: + /// + /// `SelectScope: SelectScopeOpt /* Option */ SelectScopeOpt0 /* Option */;` + /// + #[parol_runtime::function_name::named] + fn select_scope( + &mut self, + _select_scope_opt: &ParseTreeType<'t>, + _select_scope_opt0: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let select_scope_opt0 = pop_item!(self, select_scope_opt0, SelectScopeOpt0, context); + let select_scope_opt = pop_item!(self, select_scope_opt, SelectScopeOpt, context); + let select_scope_built = SelectScope { + select_scope_opt, + select_scope_opt0, + }; + // Calling user action here + self.user_grammar.select_scope(&select_scope_built)?; + self.push(ASTType::SelectScope(select_scope_built), context); + Ok(()) + } + + /// Semantic action for production 111: + /// + /// `SelectScopeOpt0 /* Option::Some */: EndOfLine SelectScope;` + /// + #[parol_runtime::function_name::named] + fn select_scope_opt0_0( + &mut self, + _end_of_line: &ParseTreeType<'t>, + _select_scope: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let select_scope = pop_item!(self, select_scope, SelectScope, context); + let end_of_line = pop_item!(self, end_of_line, EndOfLine, context); + let select_scope_opt0_0_built = SelectScopeOpt0 { + end_of_line: Box::new(end_of_line), + select_scope: Box::new(select_scope), + }; + self.push( + ASTType::SelectScopeOpt0(Some(select_scope_opt0_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 112: + /// + /// `SelectScopeOpt0 /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn select_scope_opt0_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::SelectScopeOpt0(None), context); + Ok(()) + } + + /// Semantic action for production 113: + /// + /// `SelectScopeOpt /* Option::Some */: SelectScopeContent;` + /// + #[parol_runtime::function_name::named] + fn select_scope_opt_0(&mut self, _select_scope_content: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let select_scope_content = + pop_item!(self, select_scope_content, SelectScopeContent, context); + let select_scope_opt_0_built = SelectScopeOpt { + select_scope_content: Box::new(select_scope_content), + }; + self.push( + ASTType::SelectScopeOpt(Some(select_scope_opt_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 114: + /// + /// `SelectScopeOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn select_scope_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::SelectScopeOpt(None), context); + Ok(()) + } + + /// Semantic action for production 115: + /// + /// `SelectScopeContent: Expr '=>' Block;` + /// + #[parol_runtime::function_name::named] + fn select_scope_content( + &mut self, + _expr: &ParseTreeType<'t>, + equ_g_t: &ParseTreeType<'t>, + _block: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let equ_g_t = equ_g_t.token()?.clone(); + let block = pop_item!(self, block, Block, context); + let expr = pop_item!(self, expr, Expr, context); + let select_scope_content_built = SelectScopeContent { + expr: Box::new(expr), + equ_g_t, + block: Box::new(block), + }; + // Calling user action here + self.user_grammar + .select_scope_content(&select_scope_content_built)?; + self.push( + ASTType::SelectScopeContent(select_scope_content_built), + context, + ); + Ok(()) + } + + /// Semantic action for production 116: + /// + /// `Qualif: Modifier;` + /// + #[parol_runtime::function_name::named] + fn qualif_0(&mut self, _modifier: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let modifier = pop_item!(self, modifier, Modifier, context); + let qualif_0_built = QualifModifier { + modifier: Box::new(modifier), + }; + let qualif_0_built = Qualif::Modifier(qualif_0_built); + // Calling user action here + self.user_grammar.qualif(&qualif_0_built)?; + self.push(ASTType::Qualif(qualif_0_built), context); + Ok(()) + } + + /// Semantic action for production 117: + /// + /// `Qualif: DefaultModifier;` + /// + #[parol_runtime::function_name::named] + fn qualif_1(&mut self, _default_modifier: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let default_modifier = pop_item!(self, default_modifier, DefaultModifier, context); + let qualif_1_built = QualifDefaultModifier { + default_modifier: Box::new(default_modifier), + }; + let qualif_1_built = Qualif::DefaultModifier(qualif_1_built); + // Calling user action here + self.user_grammar.qualif(&qualif_1_built)?; + self.push(ASTType::Qualif(qualif_1_built), context); + Ok(()) + } + + /// Semantic action for production 118: + /// + /// `DefaultModifier: '~' Path;` + /// + #[parol_runtime::function_name::named] + fn default_modifier( + &mut self, + tilde: &ParseTreeType<'t>, + _path: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let tilde = tilde.token()?.clone(); + let path = pop_item!(self, path, Path, context); + let default_modifier_built = DefaultModifier { + tilde, + path: Box::new(path), + }; + // Calling user action here + self.user_grammar + .default_modifier(&default_modifier_built)?; + self.push(ASTType::DefaultModifier(default_modifier_built), context); + Ok(()) + } + + /// Semantic action for production 119: + /// + /// `Modifier: '@' Path ModifierOpt /* Option */;` + /// + #[parol_runtime::function_name::named] + fn modifier( + &mut self, + at: &ParseTreeType<'t>, + _path: &ParseTreeType<'t>, + _modifier_opt: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let at = at.token()?.clone(); + let modifier_opt = pop_item!(self, modifier_opt, ModifierOpt, context); + let path = pop_item!(self, path, Path, context); + let modifier_built = Modifier { + at, + path: Box::new(path), + modifier_opt, + }; + // Calling user action here + self.user_grammar.modifier(&modifier_built)?; + self.push(ASTType::Modifier(modifier_built), context); + Ok(()) + } + + /// Semantic action for production 120: + /// + /// `ModifierOpt /* Option::Some */: KindArg;` + /// + #[parol_runtime::function_name::named] + fn modifier_opt_0(&mut self, _kind_arg: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let kind_arg = pop_item!(self, kind_arg, KindArg, context); + let modifier_opt_0_built = ModifierOpt { + kind_arg: Box::new(kind_arg), + }; + self.push(ASTType::ModifierOpt(Some(modifier_opt_0_built)), context); + Ok(()) + } + + /// Semantic action for production 121: + /// + /// `ModifierOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn modifier_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::ModifierOpt(None), context); + Ok(()) + } + + /// Semantic action for production 122: + /// + /// `KindArg: ':' Callable;` + /// + #[parol_runtime::function_name::named] + fn kind_arg(&mut self, colon: &ParseTreeType<'t>, _callable: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let colon = colon.token()?.clone(); + let callable = pop_item!(self, callable, Callable, context); + let kind_arg_built = KindArg { + colon, + callable: Box::new(callable), + }; + // Calling user action here + self.user_grammar.kind_arg(&kind_arg_built)?; + self.push(ASTType::KindArg(kind_arg_built), context); + Ok(()) + } + + /// Semantic action for production 123: + /// + /// `Path: Ident PathList /* Vec */;` + /// + #[parol_runtime::function_name::named] + fn path(&mut self, _ident: &ParseTreeType<'t>, _path_list: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let path_list = pop_item!(self, path_list, PathList, context); + let ident = pop_item!(self, ident, Ident, context); + let path_built = Path { + ident: Box::new(ident), + path_list, + }; + // Calling user action here + self.user_grammar.path(&path_built)?; + self.push(ASTType::Path(path_built), context); + Ok(()) + } + + /// Semantic action for production 124: + /// + /// `PathList /* Vec::Push */: PathList '.' Ident;` + /// + #[parol_runtime::function_name::named] + fn path_list_0( + &mut self, + _path_list: &ParseTreeType<'t>, + r#break: &ParseTreeType<'t>, + _ident: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let r#break = r#break.token()?.clone(); + let ident = pop_item!(self, ident, Ident, context); + let mut path_list = pop_item!(self, path_list, PathList, context); + let path_list_0_built = PathList { + ident: Box::new(ident), + r#break, + }; + // Add an element to the vector + path_list.push(path_list_0_built); + self.push(ASTType::PathList(path_list), context); + Ok(()) + } + + /// Semantic action for production 125: + /// + /// `PathList /* Vec::New */: ;` + /// + #[parol_runtime::function_name::named] + fn path_list_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let path_list_1_built = Vec::new(); + self.push(ASTType::PathList(path_list_1_built), context); + Ok(()) + } + + /// Semantic action for production 126: + /// + /// `Ident: /[_a-zA-Z](\w|[\/-])*/;` + /// + #[parol_runtime::function_name::named] + fn ident(&mut self, ident: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let ident = ident.token()?.clone(); + let ident_built = Ident { ident }; + // Calling user action here + self.user_grammar.ident(&ident_built)?; + self.push(ASTType::Ident(ident_built), context); + Ok(()) + } + + /// Semantic action for production 127: + /// + /// `Literal: Array;` + /// + #[parol_runtime::function_name::named] + fn literal_0(&mut self, _array: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let array = pop_item!(self, array, Array, context); + let literal_0_built = LiteralArray { + array: Box::new(array), + }; + let literal_0_built = Literal::Array(literal_0_built); + // Calling user action here + self.user_grammar.literal(&literal_0_built)?; + self.push(ASTType::Literal(literal_0_built), context); + Ok(()) + } + + /// Semantic action for production 128: + /// + /// `Literal: String;` + /// + #[parol_runtime::function_name::named] + fn literal_1(&mut self, _string: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let string = pop_item!(self, string, String, context); + let literal_1_built = LiteralString { + string: Box::new(string), + }; + let literal_1_built = Literal::String(literal_1_built); + // Calling user action here + self.user_grammar.literal(&literal_1_built)?; + self.push(ASTType::Literal(literal_1_built), context); + Ok(()) + } + + /// Semantic action for production 129: + /// + /// `Literal: ByteLiteral;` + /// + #[parol_runtime::function_name::named] + fn literal_2(&mut self, _byte_literal: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let byte_literal = pop_item!(self, byte_literal, ByteLiteral, context); + let literal_2_built = LiteralByteLiteral { + byte_literal: Box::new(byte_literal), + }; + let literal_2_built = Literal::ByteLiteral(literal_2_built); + // Calling user action here + self.user_grammar.literal(&literal_2_built)?; + self.push(ASTType::Literal(literal_2_built), context); + Ok(()) + } + + /// Semantic action for production 130: + /// + /// `Literal: HexByteLiteral;` + /// + #[parol_runtime::function_name::named] + fn literal_3(&mut self, _hex_byte_literal: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let hex_byte_literal = pop_item!(self, hex_byte_literal, HexByteLiteral, context); + let literal_3_built = LiteralHexByteLiteral { + hex_byte_literal: Box::new(hex_byte_literal), + }; + let literal_3_built = Literal::HexByteLiteral(literal_3_built); + // Calling user action here + self.user_grammar.literal(&literal_3_built)?; + self.push(ASTType::Literal(literal_3_built), context); + Ok(()) + } + + /// Semantic action for production 131: + /// + /// `Literal: Numeric;` + /// + #[parol_runtime::function_name::named] + fn literal_4(&mut self, _numeric: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let numeric = pop_item!(self, numeric, Numeric, context); + let literal_4_built = LiteralNumeric { + numeric: Box::new(numeric), + }; + let literal_4_built = Literal::Numeric(literal_4_built); + // Calling user action here + self.user_grammar.literal(&literal_4_built)?; + self.push(ASTType::Literal(literal_4_built), context); + Ok(()) + } + + /// Semantic action for production 132: + /// + /// `Literal: Rfc3339DateTime;` + /// + #[parol_runtime::function_name::named] + fn literal_5(&mut self, _rfc3339_date_time: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let rfc3339_date_time = pop_item!(self, rfc3339_date_time, Rfc3339DateTime, context); + let literal_5_built = LiteralRfc3339DateTime { + rfc3339_date_time: Box::new(rfc3339_date_time), + }; + let literal_5_built = Literal::Rfc3339DateTime(literal_5_built); + // Calling user action here + self.user_grammar.literal(&literal_5_built)?; + self.push(ASTType::Literal(literal_5_built), context); + Ok(()) + } + + /// Semantic action for production 133: + /// + /// `Array: '[' ArrayOpt /* Option */ ']';` + /// + #[parol_runtime::function_name::named] + fn array( + &mut self, + l_bracket: &ParseTreeType<'t>, + _array_opt: &ParseTreeType<'t>, + r_bracket: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let l_bracket = l_bracket.token()?.clone(); + let r_bracket = r_bracket.token()?.clone(); + let array_opt = pop_item!(self, array_opt, ArrayOpt, context); + let array_built = Array { + l_bracket, + array_opt, + r_bracket, + }; + // Calling user action here + self.user_grammar.array(&array_built)?; + self.push(ASTType::Array(array_built), context); + Ok(()) + } + + /// Semantic action for production 134: + /// + /// `ArrayOpt /* Option::Some */: CommaSepElements;` + /// + #[parol_runtime::function_name::named] + fn array_opt_0(&mut self, _comma_sep_elements: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let comma_sep_elements = pop_item!(self, comma_sep_elements, CommaSepElements, context); + let array_opt_0_built = ArrayOpt { + comma_sep_elements: Box::new(comma_sep_elements), + }; + self.push(ASTType::ArrayOpt(Some(array_opt_0_built)), context); + Ok(()) + } + + /// Semantic action for production 135: + /// + /// `ArrayOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn array_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::ArrayOpt(None), context); + Ok(()) + } + + /// Semantic action for production 136: + /// + /// `CommaSepElements: Expr CommaSepElementsOpt /* Option */;` + /// + #[parol_runtime::function_name::named] + fn comma_sep_elements( + &mut self, + _expr: &ParseTreeType<'t>, + _comma_sep_elements_opt: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let comma_sep_elements_opt = + pop_item!(self, comma_sep_elements_opt, CommaSepElementsOpt, context); + let expr = pop_item!(self, expr, Expr, context); + let comma_sep_elements_built = CommaSepElements { + expr: Box::new(expr), + comma_sep_elements_opt, + }; + // Calling user action here + self.user_grammar + .comma_sep_elements(&comma_sep_elements_built)?; + self.push(ASTType::CommaSepElements(comma_sep_elements_built), context); + Ok(()) + } + + /// Semantic action for production 137: + /// + /// `CommaSepElementsOpt /* Option::Some */: CommaExprList;` + /// + #[parol_runtime::function_name::named] + fn comma_sep_elements_opt_0(&mut self, _comma_expr_list: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let comma_expr_list = pop_item!(self, comma_expr_list, CommaExprList, context); + let comma_sep_elements_opt_0_built = CommaSepElementsOpt { + comma_expr_list: Box::new(comma_expr_list), + }; + self.push( + ASTType::CommaSepElementsOpt(Some(comma_sep_elements_opt_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 138: + /// + /// `CommaSepElementsOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn comma_sep_elements_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::CommaSepElementsOpt(None), context); + Ok(()) + } + + /// Semantic action for production 139: + /// + /// `CommaExprList: ',' CommaExprListOpt /* Option */;` + /// + #[parol_runtime::function_name::named] + fn comma_expr_list( + &mut self, + comma: &ParseTreeType<'t>, + _comma_expr_list_opt: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let comma = comma.token()?.clone(); + let comma_expr_list_opt = pop_item!(self, comma_expr_list_opt, CommaExprListOpt, context); + let comma_expr_list_built = CommaExprList { + comma, + comma_expr_list_opt, + }; + // Calling user action here + self.user_grammar.comma_expr_list(&comma_expr_list_built)?; + self.push(ASTType::CommaExprList(comma_expr_list_built), context); + Ok(()) + } + + /// Semantic action for production 140: + /// + /// `CommaExprListOpt /* Option::Some */: CommaSepElements;` + /// + #[parol_runtime::function_name::named] + fn comma_expr_list_opt_0(&mut self, _comma_sep_elements: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let comma_sep_elements = pop_item!(self, comma_sep_elements, CommaSepElements, context); + let comma_expr_list_opt_0_built = CommaExprListOpt { + comma_sep_elements: Box::new(comma_sep_elements), + }; + self.push( + ASTType::CommaExprListOpt(Some(comma_expr_list_opt_0_built)), + context, + ); + Ok(()) + } + + /// Semantic action for production 141: + /// + /// `CommaExprListOpt /* Option::None */: ;` + /// + #[parol_runtime::function_name::named] + fn comma_expr_list_opt_1(&mut self) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + self.push(ASTType::CommaExprListOpt(None), context); + Ok(()) + } + + /// Semantic action for production 142: + /// + /// `String: /"(\\.|[^"])*"/;` + /// + #[parol_runtime::function_name::named] + fn string(&mut self, string: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let string = string.token()?.clone(); + let string_built = String { string }; + // Calling user action here + self.user_grammar.string(&string_built)?; + self.push(ASTType::String(string_built), context); + Ok(()) + } + + /// Semantic action for production 143: + /// + /// `ByteLiteral: /b"(\\.|[^"])*"/;` + /// + #[parol_runtime::function_name::named] + fn byte_literal(&mut self, byte_literal: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let byte_literal = byte_literal.token()?.clone(); + let byte_literal_built = ByteLiteral { byte_literal }; + // Calling user action here + self.user_grammar.byte_literal(&byte_literal_built)?; + self.push(ASTType::ByteLiteral(byte_literal_built), context); + Ok(()) + } + + /// Semantic action for production 144: + /// + /// `HexByteLiteral: /bx"[0-9a-fA-F_]*"/;` + /// + #[parol_runtime::function_name::named] + fn hex_byte_literal(&mut self, hex_byte_literal: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let hex_byte_literal = hex_byte_literal.token()?.clone(); + let hex_byte_literal_built = HexByteLiteral { hex_byte_literal }; + // Calling user action here + self.user_grammar + .hex_byte_literal(&hex_byte_literal_built)?; + self.push(ASTType::HexByteLiteral(hex_byte_literal_built), context); + Ok(()) + } + + /// Semantic action for production 145: + /// + /// `Numeric: BinaryInteger;` + /// + #[parol_runtime::function_name::named] + fn numeric_0(&mut self, _binary_integer: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let binary_integer = pop_item!(self, binary_integer, BinaryInteger, context); + let numeric_0_built = NumericBinaryInteger { + binary_integer: Box::new(binary_integer), + }; + let numeric_0_built = Numeric::BinaryInteger(numeric_0_built); + // Calling user action here + self.user_grammar.numeric(&numeric_0_built)?; + self.push(ASTType::Numeric(numeric_0_built), context); + Ok(()) + } + + /// Semantic action for production 146: + /// + /// `Numeric: OctalInteger;` + /// + #[parol_runtime::function_name::named] + fn numeric_1(&mut self, _octal_integer: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let octal_integer = pop_item!(self, octal_integer, OctalInteger, context); + let numeric_1_built = NumericOctalInteger { + octal_integer: Box::new(octal_integer), + }; + let numeric_1_built = Numeric::OctalInteger(numeric_1_built); + // Calling user action here + self.user_grammar.numeric(&numeric_1_built)?; + self.push(ASTType::Numeric(numeric_1_built), context); + Ok(()) + } + + /// Semantic action for production 147: + /// + /// `Numeric: HexadecimalInteger;` + /// + #[parol_runtime::function_name::named] + fn numeric_2(&mut self, _hexadecimal_integer: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let hexadecimal_integer = pop_item!(self, hexadecimal_integer, HexadecimalInteger, context); + let numeric_2_built = NumericHexadecimalInteger { + hexadecimal_integer: Box::new(hexadecimal_integer), + }; + let numeric_2_built = Numeric::HexadecimalInteger(numeric_2_built); + // Calling user action here + self.user_grammar.numeric(&numeric_2_built)?; + self.push(ASTType::Numeric(numeric_2_built), context); + Ok(()) + } + + /// Semantic action for production 148: + /// + /// `Numeric: Ieee754Float;` + /// + #[parol_runtime::function_name::named] + fn numeric_3(&mut self, _ieee754_float: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let ieee754_float = pop_item!(self, ieee754_float, Ieee754Float, context); + let numeric_3_built = NumericIeee754Float { + ieee754_float: Box::new(ieee754_float), + }; + let numeric_3_built = Numeric::Ieee754Float(numeric_3_built); + // Calling user action here + self.user_grammar.numeric(&numeric_3_built)?; + self.push(ASTType::Numeric(numeric_3_built), context); + Ok(()) + } + + /// Semantic action for production 149: + /// + /// `BinaryInteger: /0b[01_]+([a-zA-Z](\w|[\/-])*)?/;` + /// + #[parol_runtime::function_name::named] + fn binary_integer(&mut self, binary_integer: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let binary_integer = binary_integer.token()?.clone(); + let binary_integer_built = BinaryInteger { binary_integer }; + // Calling user action here + self.user_grammar.binary_integer(&binary_integer_built)?; + self.push(ASTType::BinaryInteger(binary_integer_built), context); + Ok(()) + } + + /// Semantic action for production 150: + /// + /// `OctalInteger: /0o[0-7_]+([a-zA-Z](\w|[\/-])*)?/;` + /// + #[parol_runtime::function_name::named] + fn octal_integer(&mut self, octal_integer: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let octal_integer = octal_integer.token()?.clone(); + let octal_integer_built = OctalInteger { octal_integer }; + // Calling user action here + self.user_grammar.octal_integer(&octal_integer_built)?; + self.push(ASTType::OctalInteger(octal_integer_built), context); + Ok(()) + } + + /// Semantic action for production 151: + /// + /// `HexadecimalInteger: /0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?/;` + /// + #[parol_runtime::function_name::named] + fn hexadecimal_integer(&mut self, hexadecimal_integer: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let hexadecimal_integer = hexadecimal_integer.token()?.clone(); + let hexadecimal_integer_built = HexadecimalInteger { + hexadecimal_integer, + }; + // Calling user action here + self.user_grammar + .hexadecimal_integer(&hexadecimal_integer_built)?; + self.push( + ASTType::HexadecimalInteger(hexadecimal_integer_built), + context, + ); + Ok(()) + } + + /// Semantic action for production 152: + /// + /// `Ieee754Float: /[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?/;` + /// + #[parol_runtime::function_name::named] + fn ieee754_float(&mut self, ieee754_float: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let ieee754_float = ieee754_float.token()?.clone(); + let ieee754_float_built = Ieee754Float { ieee754_float }; + // Calling user action here + self.user_grammar.ieee754_float(&ieee754_float_built)?; + self.push(ASTType::Ieee754Float(ieee754_float_built), context); + Ok(()) + } + + /// Semantic action for production 153: + /// + /// `Rfc3339DateTime: /\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})/;` + /// + #[parol_runtime::function_name::named] + fn rfc3339_date_time(&mut self, rfc3339_date_time: &ParseTreeType<'t>) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let rfc3339_date_time = rfc3339_date_time.token()?.clone(); + let rfc3339_date_time_built = Rfc3339DateTime { rfc3339_date_time }; + // Calling user action here + self.user_grammar + .rfc3339_date_time(&rfc3339_date_time_built)?; + self.push(ASTType::Rfc3339DateTime(rfc3339_date_time_built), context); + Ok(()) + } + + /// Semantic action for production 154: + /// + /// `Block: '{' Scope '}';` + /// + #[parol_runtime::function_name::named] + fn block( + &mut self, + l_brace: &ParseTreeType<'t>, + _scope: &ParseTreeType<'t>, + r_brace: &ParseTreeType<'t>, + ) -> Result<()> { + let context = function_name!(); + trace!("{}", self.trace_item_stack(context)); + let l_brace = l_brace.token()?.clone(); + let r_brace = r_brace.token()?.clone(); + let scope = pop_item!(self, scope, Scope, context); + let block_built = Block { + l_brace, + scope: Box::new(scope), + r_brace, + }; + // Calling user action here + self.user_grammar.block(&block_built)?; + self.push(ASTType::Block(block_built), context); + Ok(()) + } +} + +impl<'t> UserActionsTrait<'t> for ActionAuto<'t, '_> { + /// + /// This function is implemented automatically for the user's item Action. + /// + fn call_semantic_action_for_production_number( + &mut self, + prod_num: usize, + children: &[ParseTreeType<'t>], + ) -> Result<()> { + match prod_num { + 0 => self.program0(&children[0]), + 1 => self.end_of_line(&children[0]), + 2 => self.comment(&children[0], &children[1]), + 3 => self.comment_opt_0(&children[0]), + 4 => self.comment_opt_1(), + 5 => self.hash(&children[0]), + 6 => self.comment_content(&children[0]), + 7 => self.program_0(&children[0], &children[1], &children[2]), + 8 => self.program_1(&children[0]), + 9 => self.definition(&children[0], &children[1]), + 10 => self.definition_opt0_0(&children[0]), + 11 => self.definition_opt0_1(), + 12 => self.definition_opt_0(&children[0]), + 13 => self.definition_opt_group_0(&children[0]), + 14 => self.definition_opt_group_1(&children[0]), + 15 => self.definition_opt_1(), + 16 => self.function_def( + &children[0], + &children[1], + &children[2], + &children[3], + &children[4], + &children[5], + &children[6], + ), + 17 => self.function_def_opt0_0(&children[0], &children[1]), + 18 => self.function_def_opt0_1(), + 19 => self.function_def_opt_0(&children[0]), + 20 => self.function_def_opt_1(), + 21 => self.parameter_list(&children[0], &children[1]), + 22 => self.parameter_list_opt_0(&children[0]), + 23 => self.parameter_list_opt_1(), + 24 => self.comma_parameter_list(&children[0], &children[1]), + 25 => self.comma_parameter_list_opt_0(&children[0]), + 26 => self.comma_parameter_list_opt_1(), + 27 => self.parameter(&children[0], &children[1], &children[2]), + 28 => self.constant_def( + &children[0], + &children[1], + &children[2], + &children[3], + &children[4], + &children[5], + &children[6], + ), + 29 => self.scope(&children[0], &children[1]), + 30 => self.scope_opt_0(&children[0], &children[1]), + 31 => self.scope_opt_1(), + 32 => self.scope_content(&children[0], &children[1], &children[2]), + 33 => self.scope_content_opt1_0(&children[0]), + 34 => self.scope_content_opt1_1(), + 35 => self.scope_content_opt0_0(&children[0]), + 36 => self.scope_content_opt0_1(), + 37 => self.scope_content_opt_0(&children[0]), + 38 => self.scope_content_opt_1(), + 39 => self.scope_content_kind_0(&children[0]), + 40 => self.scope_content_kind_1(&children[0]), + 41 => self.statement(&children[0], &children[1]), + 42 => self.r#break(&children[0]), + 43 => self.semi(&children[0]), + 44 => self.statement_kind_0(&children[0]), + 45 => self.statement_kind_1(&children[0]), + 46 => self.statement_kind_2(&children[0]), + 47 => self.return_stmt(&children[0]), + 48 => self.let_stmt(&children[0], &children[1], &children[2], &children[3]), + 49 => self.expr(&children[0]), + 50 => self.set_expr(&children[0], &children[1]), + 51 => self.set_expr_opt_0(&children[0], &children[1]), + 52 => self.set_expr_opt_1(), + 53 => self.logical_or_expr(&children[0], &children[1]), + 54 => self.logical_or_expr_list_0(&children[0], &children[1], &children[2]), + 55 => self.logical_or_expr_list_1(), + 56 => self.logical_and_expr(&children[0], &children[1]), + 57 => self.logical_and_expr_list_0(&children[0], &children[1], &children[2]), + 58 => self.logical_and_expr_list_1(), + 59 => self.compare_expr(&children[0], &children[1]), + 60 => self.compare_expr_list_0(&children[0], &children[1], &children[2]), + 61 => self.compare_expr_list_1(), + 62 => self.compare_op_0(&children[0]), + 63 => self.compare_op_1(&children[0]), + 64 => self.compare_op_2(&children[0]), + 65 => self.compare_op_3(&children[0]), + 66 => self.compare_op_4(&children[0]), + 67 => self.compare_op_5(&children[0]), + 68 => self.compare_op_6(&children[0]), + 69 => self.arithmetic_expr(&children[0], &children[1]), + 70 => self.arithmetic_expr_list_0(&children[0], &children[1], &children[2]), + 71 => self.arithmetic_expr_list_1(), + 72 => self.arithmetic_op_0(&children[0]), + 73 => self.arithmetic_op_1(&children[0]), + 74 => self.factor_expr(&children[0], &children[1]), + 75 => self.factor_expr_list_0(&children[0], &children[1], &children[2]), + 76 => self.factor_expr_list_1(), + 77 => self.factor_op_0(&children[0]), + 78 => self.factor_op_1(&children[0]), + 79 => self.factor_op_2(&children[0]), + 80 => self.cast_expr(&children[0], &children[1]), + 81 => self.cast_expr_opt_0(&children[0], &children[1]), + 82 => self.cast_expr_opt_1(), + 83 => self.prefix_expr_0(&children[0], &children[1]), + 84 => self.prefix_expr_1(&children[0], &children[1]), + 85 => self.prefix_expr_list_0(&children[0], &children[1]), + 86 => self.prefix_expr_list_1(), + 87 => self.prefix_expr_2(&children[0], &children[1]), + 88 => self.prefix_expr_3(&children[0], &children[1]), + 89 => self.apply_expr(&children[0], &children[1]), + 90 => self.apply_expr_list_0(&children[0], &children[1]), + 91 => self.apply_expr_list_1(), + 92 => self.lower_prefix_expr(&children[0], &children[1]), + 93 => self.lower_prefix_expr_opt_0(&children[0]), + 94 => self.lower_prefix_expr_opt_1(), + 95 => self.lower_prefix_op_0(&children[0]), + 96 => self.lower_prefix_op_1(&children[0]), + 97 => self.callable_0(&children[0]), + 98 => self.callable_1(&children[0], &children[1]), + 99 => self.callable_2(&children[0], &children[1], &children[2]), + 100 => self.callable_3(&children[0]), + 101 => self.callable_4(&children[0]), + 102 => self.callable_opt_0(&children[0], &children[1]), + 103 => self.callable_opt_1(), + 104 => self.atomic_expr_0(&children[0]), + 105 => self.atomic_expr_1(&children[0]), + 106 => self.if_expr(&children[0], &children[1], &children[2], &children[3]), + 107 => self.if_expr_opt_0(&children[0], &children[1]), + 108 => self.if_expr_opt_1(), + 109 => self.select_expr(&children[0], &children[1], &children[2], &children[3]), + 110 => self.select_scope(&children[0], &children[1]), + 111 => self.select_scope_opt0_0(&children[0], &children[1]), + 112 => self.select_scope_opt0_1(), + 113 => self.select_scope_opt_0(&children[0]), + 114 => self.select_scope_opt_1(), + 115 => self.select_scope_content(&children[0], &children[1], &children[2]), + 116 => self.qualif_0(&children[0]), + 117 => self.qualif_1(&children[0]), + 118 => self.default_modifier(&children[0], &children[1]), + 119 => self.modifier(&children[0], &children[1], &children[2]), + 120 => self.modifier_opt_0(&children[0]), + 121 => self.modifier_opt_1(), + 122 => self.kind_arg(&children[0], &children[1]), + 123 => self.path(&children[0], &children[1]), + 124 => self.path_list_0(&children[0], &children[1], &children[2]), + 125 => self.path_list_1(), + 126 => self.ident(&children[0]), + 127 => self.literal_0(&children[0]), + 128 => self.literal_1(&children[0]), + 129 => self.literal_2(&children[0]), + 130 => self.literal_3(&children[0]), + 131 => self.literal_4(&children[0]), + 132 => self.literal_5(&children[0]), + 133 => self.array(&children[0], &children[1], &children[2]), + 134 => self.array_opt_0(&children[0]), + 135 => self.array_opt_1(), + 136 => self.comma_sep_elements(&children[0], &children[1]), + 137 => self.comma_sep_elements_opt_0(&children[0]), + 138 => self.comma_sep_elements_opt_1(), + 139 => self.comma_expr_list(&children[0], &children[1]), + 140 => self.comma_expr_list_opt_0(&children[0]), + 141 => self.comma_expr_list_opt_1(), + 142 => self.string(&children[0]), + 143 => self.byte_literal(&children[0]), + 144 => self.hex_byte_literal(&children[0]), + 145 => self.numeric_0(&children[0]), + 146 => self.numeric_1(&children[0]), + 147 => self.numeric_2(&children[0]), + 148 => self.numeric_3(&children[0]), + 149 => self.binary_integer(&children[0]), + 150 => self.octal_integer(&children[0]), + 151 => self.hexadecimal_integer(&children[0]), + 152 => self.ieee754_float(&children[0]), + 153 => self.rfc3339_date_time(&children[0]), + 154 => self.block(&children[0], &children[1], &children[2]), + _ => Err(ParserError::InternalError(format!( + "Unhandled production number: {}", + prod_num + )) + .into()), + } + } + + fn on_comment(&mut self, token: Token<'t>) { + self.user_grammar.on_comment(token) + } +} diff --git a/opslang-parser/src/version/v1/generated/parser.rs b/opslang-parser/src/version/v1/generated/parser.rs new file mode 100644 index 0000000..373361b --- /dev/null +++ b/opslang-parser/src/version/v1/generated/parser.rs @@ -0,0 +1,5512 @@ +// --------------------------------------------------------- +// This file was generated by parol. +// It is not intended for manual editing and changes will be +// lost after next build. +// --------------------------------------------------------- + +use parol_runtime::lr_parser::{LR1State, LRAction, LRParseTable, LRParser, LRProduction}; +use parol_runtime::once_cell::sync::Lazy; +#[allow(unused_imports)] +use parol_runtime::parser::{ParseTreeType, ParseType, Production, Trans}; +use parol_runtime::{ParolError, ParseTree, TerminalIndex}; +use parol_runtime::{ScannerConfig, TokenStream, Tokenizer}; +use std::path::Path; + +use crate::version::v1::parse::Action; +use crate::version::v1::parse_trait::ActionAuto; + +use parol_runtime::lexer::tokenizer::{ERROR_TOKEN, UNMATCHABLE_TOKEN, WHITESPACE_TOKEN}; + +pub const TERMINALS: &[(&str, Option<(bool, &str)>); 61] = &[ + /* 0 */ (UNMATCHABLE_TOKEN, None), + /* 1 */ (UNMATCHABLE_TOKEN, None), + /* 2 */ (UNMATCHABLE_TOKEN, None), + /* 3 */ (UNMATCHABLE_TOKEN, None), + /* 4 */ (UNMATCHABLE_TOKEN, None), + /* 5 */ (r"\r?\n|\r", None), + /* 6 */ (r"\#", None), + /* 7 */ (r"[^\r\n]*", None), + /* 8 */ (r"prc", None), + /* 9 */ (r"\(", None), + /* 10 */ (r"\)", None), + /* 11 */ (r"\->", None), + /* 12 */ (r",", None), + /* 13 */ (r":", None), + /* 14 */ (r"const", None), + /* 15 */ (r"=", None), + /* 16 */ (r"\.", None), + /* 17 */ (r";", None), + /* 18 */ (r"return", None), + /* 19 */ (r"let", None), + /* 20 */ (r":=", None), + /* 21 */ (r"\|\|", None), + /* 22 */ (r"\&\&", None), + /* 23 */ (r">=", None), + /* 24 */ (r"<=", None), + /* 25 */ (r">", None), + /* 26 */ (r"<", None), + /* 27 */ (r"!=", None), + /* 28 */ (r"/=", None), + /* 29 */ (r"==", None), + /* 30 */ (r"\+", None), + /* 31 */ (r"\-", None), + /* 32 */ (r"\*", None), + /* 33 */ (r"/", None), + /* 34 */ (r"%", None), + /* 35 */ (r"as", None), + /* 36 */ (r"wait", None), + /* 37 */ (r"call", None), + /* 38 */ (r"\&", None), + /* 39 */ (r"\$", None), + /* 40 */ (r"\?", None), + /* 41 */ (r"if", None), + /* 42 */ (r"else", None), + /* 43 */ (r"select", None), + /* 44 */ (r"\{", None), + /* 45 */ (r"\}", None), + /* 46 */ (r"=>", None), + /* 47 */ (r"\~", None), + /* 48 */ (r"@", None), + /* 49 */ (r"[_a-zA-Z](\w|[\/-])*", None), + /* 50 */ (r"\[", None), + /* 51 */ (r"\]", None), + /* 52 */ (r#""(\\.|[^"])*""#, None), + /* 53 */ (r#"b"(\\.|[^"])*""#, None), + /* 54 */ (r#"bx"[0-9a-fA-F_]*""#, None), + /* 55 */ (r"0b[01_]+([a-zA-Z](\w|[\/-])*)?", None), + /* 56 */ (r"0o[0-7_]+([a-zA-Z](\w|[\/-])*)?", None), + /* 57 */ (r"0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?", None), + /* 58 */ + ( + r"[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?", + None, + ), + /* 59 */ + ( + r"\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})", + None, + ), + /* 60 */ (ERROR_TOKEN, None), +]; + +pub const TERMINAL_NAMES: &[&str; 61] = &[ + /* 0 */ "EndOfInput", + /* 1 */ "Newline", + /* 2 */ "Whitespace", + /* 3 */ "LineComment", + /* 4 */ "BlockComment", + /* 5 */ "EndOfLine", + /* 6 */ "Hash", + /* 7 */ "CommentContent", + /* 8 */ "Prc", + /* 9 */ "LParen", + /* 10 */ "RParen", + /* 11 */ "MinusGT", + /* 12 */ "Comma", + /* 13 */ "Colon", + /* 14 */ "Const", + /* 15 */ "Equ", + /* 16 */ "Break", + /* 17 */ "Semi", + /* 18 */ "ReturnStmt", + /* 19 */ "Let", + /* 20 */ "ColonEqu", + /* 21 */ "OrOr", + /* 22 */ "AmpAmp", + /* 23 */ "GTEqu", + /* 24 */ "LTEqu", + /* 25 */ "GT", + /* 26 */ "LT", + /* 27 */ "BangEqu", + /* 28 */ "SlashEqu", + /* 29 */ "EquEqu", + /* 30 */ "Plus", + /* 31 */ "Minus", + /* 32 */ "Star", + /* 33 */ "Slash", + /* 34 */ "Percent", + /* 35 */ "As", + /* 36 */ "Wait", + /* 37 */ "Call", + /* 38 */ "Amp", + /* 39 */ "Dollar", + /* 40 */ "Quest", + /* 41 */ "If", + /* 42 */ "Else", + /* 43 */ "Select", + /* 44 */ "LBrace", + /* 45 */ "RBrace", + /* 46 */ "EquGT", + /* 47 */ "Tilde", + /* 48 */ "At", + /* 49 */ "Ident", + /* 50 */ "LBracket", + /* 51 */ "RBracket", + /* 52 */ "String", + /* 53 */ "ByteLiteral", + /* 54 */ "HexByteLiteral", + /* 55 */ "BinaryInteger", + /* 56 */ "OctalInteger", + /* 57 */ "HexadecimalInteger", + /* 58 */ "Ieee754Float", + /* 59 */ "Rfc3339DateTime", + /* 60 */ "Error", +]; + +/* SCANNER_0: "INITIAL" */ +const SCANNER_0: (&[&str; 5], &[TerminalIndex; 54]) = ( + &[ + /* 0 */ UNMATCHABLE_TOKEN, + /* 1 */ UNMATCHABLE_TOKEN, + /* 2 */ WHITESPACE_TOKEN, + /* 3 */ UNMATCHABLE_TOKEN, + /* 4 */ UNMATCHABLE_TOKEN, + ], + &[ + 5, /* EndOfLine */ + 6, /* Hash */ + 8, /* Prc */ + 9, /* LParen */ + 10, /* RParen */ + 11, /* MinusGT */ + 12, /* Comma */ + 13, /* Colon */ + 14, /* Const */ + 15, /* Equ */ + 16, /* Break */ + 17, /* Semi */ + 18, /* ReturnStmt */ + 19, /* Let */ + 20, /* ColonEqu */ + 21, /* OrOr */ + 22, /* AmpAmp */ + 23, /* GTEqu */ + 24, /* LTEqu */ + 25, /* GT */ + 26, /* LT */ + 27, /* BangEqu */ + 28, /* SlashEqu */ + 29, /* EquEqu */ + 30, /* Plus */ + 31, /* Minus */ + 32, /* Star */ + 33, /* Slash */ + 34, /* Percent */ + 35, /* As */ + 36, /* Wait */ + 37, /* Call */ + 38, /* Amp */ + 39, /* Dollar */ + 40, /* Quest */ + 41, /* If */ + 42, /* Else */ + 43, /* Select */ + 44, /* LBrace */ + 45, /* RBrace */ + 46, /* EquGT */ + 47, /* Tilde */ + 48, /* At */ + 49, /* Ident */ + 50, /* LBracket */ + 51, /* RBracket */ + 52, /* String */ + 53, /* ByteLiteral */ + 54, /* HexByteLiteral */ + 55, /* BinaryInteger */ + 56, /* OctalInteger */ + 57, /* HexadecimalInteger */ + 58, /* Ieee754Float */ + 59, /* Rfc3339DateTime */ + ], +); + +/* SCANNER_1: "Cmnt" */ +const SCANNER_1: (&[&str; 5], &[TerminalIndex; 2]) = ( + &[ + /* 0 */ UNMATCHABLE_TOKEN, + /* 1 */ UNMATCHABLE_TOKEN, + /* 2 */ UNMATCHABLE_TOKEN, + /* 3 */ UNMATCHABLE_TOKEN, + /* 4 */ UNMATCHABLE_TOKEN, + ], + &[5 /* EndOfLine */, 7 /* CommentContent */], +); + +pub const NON_TERMINALS: &[&str; 93] = &[ + /* 0 */ "ApplyExpr", + /* 1 */ "ApplyExprList", + /* 2 */ "ArithmeticExpr", + /* 3 */ "ArithmeticExprList", + /* 4 */ "ArithmeticOp", + /* 5 */ "Array", + /* 6 */ "ArrayOpt", + /* 7 */ "AtomicExpr", + /* 8 */ "BinaryInteger", + /* 9 */ "Block", + /* 10 */ "Break", + /* 11 */ "ByteLiteral", + /* 12 */ "Callable", + /* 13 */ "CallableOpt", + /* 14 */ "CastExpr", + /* 15 */ "CastExprOpt", + /* 16 */ "CommaExprList", + /* 17 */ "CommaExprListOpt", + /* 18 */ "CommaParameterList", + /* 19 */ "CommaParameterListOpt", + /* 20 */ "CommaSepElements", + /* 21 */ "CommaSepElementsOpt", + /* 22 */ "Comment", + /* 23 */ "CommentContent", + /* 24 */ "CommentOpt", + /* 25 */ "CompareExpr", + /* 26 */ "CompareExprList", + /* 27 */ "CompareOp", + /* 28 */ "ConstantDef", + /* 29 */ "DefaultModifier", + /* 30 */ "Definition", + /* 31 */ "DefinitionOpt", + /* 32 */ "DefinitionOpt0", + /* 33 */ "DefinitionOptGroup", + /* 34 */ "EndOfLine", + /* 35 */ "Expr", + /* 36 */ "FactorExpr", + /* 37 */ "FactorExprList", + /* 38 */ "FactorOp", + /* 39 */ "FunctionDef", + /* 40 */ "FunctionDefOpt", + /* 41 */ "FunctionDefOpt0", + /* 42 */ "Hash", + /* 43 */ "HexByteLiteral", + /* 44 */ "HexadecimalInteger", + /* 45 */ "Ident", + /* 46 */ "Ieee754Float", + /* 47 */ "IfExpr", + /* 48 */ "IfExprOpt", + /* 49 */ "KindArg", + /* 50 */ "LetStmt", + /* 51 */ "Literal", + /* 52 */ "LogicalAndExpr", + /* 53 */ "LogicalAndExprList", + /* 54 */ "LogicalOrExpr", + /* 55 */ "LogicalOrExprList", + /* 56 */ "LowerPrefixExpr", + /* 57 */ "LowerPrefixExprOpt", + /* 58 */ "LowerPrefixOp", + /* 59 */ "Modifier", + /* 60 */ "ModifierOpt", + /* 61 */ "Numeric", + /* 62 */ "OctalInteger", + /* 63 */ "Parameter", + /* 64 */ "ParameterList", + /* 65 */ "ParameterListOpt", + /* 66 */ "Path", + /* 67 */ "PathList", + /* 68 */ "PrefixExpr", + /* 69 */ "PrefixExprList", + /* 70 */ "Program", + /* 71 */ "Program0", + /* 72 */ "Qualif", + /* 73 */ "ReturnStmt", + /* 74 */ "Rfc3339DateTime", + /* 75 */ "Scope", + /* 76 */ "ScopeContent", + /* 77 */ "ScopeContentKind", + /* 78 */ "ScopeContentOpt", + /* 79 */ "ScopeContentOpt0", + /* 80 */ "ScopeContentOpt1", + /* 81 */ "ScopeOpt", + /* 82 */ "SelectExpr", + /* 83 */ "SelectScope", + /* 84 */ "SelectScopeContent", + /* 85 */ "SelectScopeOpt", + /* 86 */ "SelectScopeOpt0", + /* 87 */ "Semi", + /* 88 */ "SetExpr", + /* 89 */ "SetExprOpt", + /* 90 */ "Statement", + /* 91 */ "StatementKind", + /* 92 */ "String", +]; + +static PARSE_TABLE: LRParseTable = LRParseTable { + actions: &[ + /* 0 */ LRAction::Shift(1), + /* 1 */ LRAction::Shift(2), + /* 2 */ LRAction::Shift(9), + /* 3 */ LRAction::Shift(12), + /* 4 */ LRAction::Shift(14), + /* 5 */ LRAction::Shift(18), + /* 6 */ LRAction::Shift(19), + /* 7 */ LRAction::Shift(21), + /* 8 */ LRAction::Shift(30), + /* 9 */ LRAction::Shift(31), + /* 10 */ LRAction::Shift(32), + /* 11 */ LRAction::Shift(36), + /* 12 */ LRAction::Shift(37), + /* 13 */ LRAction::Shift(42), + /* 14 */ LRAction::Shift(48), + /* 15 */ LRAction::Shift(51), + /* 16 */ LRAction::Shift(53), + /* 17 */ LRAction::Shift(57), + /* 18 */ LRAction::Shift(63), + /* 19 */ LRAction::Shift(67), + /* 20 */ LRAction::Shift(70), + /* 21 */ LRAction::Shift(71), + /* 22 */ LRAction::Shift(83), + /* 23 */ LRAction::Shift(89), + /* 24 */ LRAction::Shift(90), + /* 25 */ LRAction::Shift(91), + /* 26 */ LRAction::Shift(92), + /* 27 */ LRAction::Shift(93), + /* 28 */ LRAction::Shift(94), + /* 29 */ LRAction::Shift(95), + /* 30 */ LRAction::Shift(97), + /* 31 */ LRAction::Shift(98), + /* 32 */ LRAction::Shift(100), + /* 33 */ LRAction::Shift(101), + /* 34 */ LRAction::Shift(102), + /* 35 */ LRAction::Shift(106), + /* 36 */ LRAction::Shift(108), + /* 37 */ LRAction::Shift(109), + /* 38 */ LRAction::Shift(116), + /* 39 */ LRAction::Shift(117), + /* 40 */ LRAction::Shift(118), + /* 41 */ LRAction::Shift(120), + /* 42 */ LRAction::Shift(122), + /* 43 */ LRAction::Shift(123), + /* 44 */ LRAction::Shift(130), + /* 45 */ LRAction::Shift(131), + /* 46 */ LRAction::Shift(132), + /* 47 */ LRAction::Shift(133), + /* 48 */ LRAction::Shift(134), + /* 49 */ LRAction::Shift(135), + /* 50 */ LRAction::Shift(136), + /* 51 */ LRAction::Shift(137), + /* 52 */ LRAction::Shift(138), + /* 53 */ LRAction::Shift(139), + /* 54 */ LRAction::Shift(140), + /* 55 */ LRAction::Shift(141), + /* 56 */ LRAction::Shift(165), + /* 57 */ LRAction::Shift(169), + /* 58 */ LRAction::Shift(171), + /* 59 */ LRAction::Shift(174), + /* 60 */ LRAction::Shift(180), + /* 61 */ LRAction::Shift(181), + /* 62 */ LRAction::Shift(186), + /* 63 */ LRAction::Shift(188), + /* 64 */ LRAction::Shift(189), + /* 65 */ LRAction::Reduce(0 /* ApplyExpr */, 89), + /* 66 */ LRAction::Reduce(1 /* ApplyExprList */, 90), + /* 67 */ LRAction::Reduce(1 /* ApplyExprList */, 91), + /* 68 */ LRAction::Reduce(2 /* ArithmeticExpr */, 69), + /* 69 */ LRAction::Reduce(3 /* ArithmeticExprList */, 70), + /* 70 */ LRAction::Reduce(3 /* ArithmeticExprList */, 71), + /* 71 */ LRAction::Reduce(4 /* ArithmeticOp */, 72), + /* 72 */ LRAction::Reduce(4 /* ArithmeticOp */, 73), + /* 73 */ LRAction::Reduce(5 /* Array */, 133), + /* 74 */ LRAction::Reduce(6 /* ArrayOpt */, 134), + /* 75 */ LRAction::Reduce(6 /* ArrayOpt */, 135), + /* 76 */ LRAction::Reduce(7 /* AtomicExpr */, 104), + /* 77 */ LRAction::Reduce(7 /* AtomicExpr */, 105), + /* 78 */ LRAction::Reduce(8 /* BinaryInteger */, 149), + /* 79 */ LRAction::Reduce(9 /* Block */, 154), + /* 80 */ LRAction::Reduce(10 /* Break */, 42), + /* 81 */ LRAction::Reduce(11 /* ByteLiteral */, 143), + /* 82 */ LRAction::Reduce(12 /* Callable */, 97), + /* 83 */ LRAction::Reduce(12 /* Callable */, 98), + /* 84 */ LRAction::Reduce(12 /* Callable */, 99), + /* 85 */ LRAction::Reduce(12 /* Callable */, 100), + /* 86 */ LRAction::Reduce(12 /* Callable */, 101), + /* 87 */ LRAction::Reduce(13 /* CallableOpt */, 102), + /* 88 */ LRAction::Reduce(13 /* CallableOpt */, 103), + /* 89 */ LRAction::Reduce(14 /* CastExpr */, 80), + /* 90 */ LRAction::Reduce(15 /* CastExprOpt */, 81), + /* 91 */ LRAction::Reduce(15 /* CastExprOpt */, 82), + /* 92 */ LRAction::Reduce(16 /* CommaExprList */, 139), + /* 93 */ LRAction::Reduce(17 /* CommaExprListOpt */, 140), + /* 94 */ LRAction::Reduce(17 /* CommaExprListOpt */, 141), + /* 95 */ LRAction::Reduce(18 /* CommaParameterList */, 24), + /* 96 */ LRAction::Reduce(19 /* CommaParameterListOpt */, 25), + /* 97 */ LRAction::Reduce(19 /* CommaParameterListOpt */, 26), + /* 98 */ LRAction::Reduce(20 /* CommaSepElements */, 136), + /* 99 */ LRAction::Reduce(21 /* CommaSepElementsOpt */, 137), + /* 100 */ LRAction::Reduce(21 /* CommaSepElementsOpt */, 138), + /* 101 */ LRAction::Reduce(22 /* Comment */, 2), + /* 102 */ LRAction::Reduce(23 /* CommentContent */, 6), + /* 103 */ LRAction::Reduce(24 /* CommentOpt */, 3), + /* 104 */ LRAction::Reduce(24 /* CommentOpt */, 4), + /* 105 */ LRAction::Reduce(25 /* CompareExpr */, 59), + /* 106 */ LRAction::Reduce(26 /* CompareExprList */, 60), + /* 107 */ LRAction::Reduce(26 /* CompareExprList */, 61), + /* 108 */ LRAction::Reduce(27 /* CompareOp */, 62), + /* 109 */ LRAction::Reduce(27 /* CompareOp */, 63), + /* 110 */ LRAction::Reduce(27 /* CompareOp */, 64), + /* 111 */ LRAction::Reduce(27 /* CompareOp */, 65), + /* 112 */ LRAction::Reduce(27 /* CompareOp */, 66), + /* 113 */ LRAction::Reduce(27 /* CompareOp */, 67), + /* 114 */ LRAction::Reduce(27 /* CompareOp */, 68), + /* 115 */ LRAction::Reduce(28 /* ConstantDef */, 28), + /* 116 */ LRAction::Reduce(29 /* DefaultModifier */, 118), + /* 117 */ LRAction::Reduce(30 /* Definition */, 9), + /* 118 */ LRAction::Reduce(31 /* DefinitionOpt */, 12), + /* 119 */ LRAction::Reduce(31 /* DefinitionOpt */, 15), + /* 120 */ LRAction::Reduce(32 /* DefinitionOpt0 */, 10), + /* 121 */ LRAction::Reduce(32 /* DefinitionOpt0 */, 11), + /* 122 */ LRAction::Reduce(33 /* DefinitionOptGroup */, 13), + /* 123 */ LRAction::Reduce(33 /* DefinitionOptGroup */, 14), + /* 124 */ LRAction::Reduce(34 /* EndOfLine */, 1), + /* 125 */ LRAction::Reduce(35 /* Expr */, 49), + /* 126 */ LRAction::Reduce(36 /* FactorExpr */, 74), + /* 127 */ LRAction::Reduce(37 /* FactorExprList */, 75), + /* 128 */ LRAction::Reduce(37 /* FactorExprList */, 76), + /* 129 */ LRAction::Reduce(38 /* FactorOp */, 77), + /* 130 */ LRAction::Reduce(38 /* FactorOp */, 78), + /* 131 */ LRAction::Reduce(38 /* FactorOp */, 79), + /* 132 */ LRAction::Reduce(39 /* FunctionDef */, 16), + /* 133 */ LRAction::Reduce(40 /* FunctionDefOpt */, 19), + /* 134 */ LRAction::Reduce(40 /* FunctionDefOpt */, 20), + /* 135 */ LRAction::Reduce(41 /* FunctionDefOpt0 */, 17), + /* 136 */ LRAction::Reduce(41 /* FunctionDefOpt0 */, 18), + /* 137 */ LRAction::Reduce(42 /* Hash */, 5), + /* 138 */ LRAction::Reduce(43 /* HexByteLiteral */, 144), + /* 139 */ LRAction::Reduce(44 /* HexadecimalInteger */, 151), + /* 140 */ LRAction::Reduce(45 /* Ident */, 126), + /* 141 */ LRAction::Reduce(46 /* Ieee754Float */, 152), + /* 142 */ LRAction::Reduce(47 /* IfExpr */, 106), + /* 143 */ LRAction::Reduce(48 /* IfExprOpt */, 107), + /* 144 */ LRAction::Reduce(48 /* IfExprOpt */, 108), + /* 145 */ LRAction::Reduce(49 /* KindArg */, 122), + /* 146 */ LRAction::Reduce(50 /* LetStmt */, 48), + /* 147 */ LRAction::Reduce(51 /* Literal */, 127), + /* 148 */ LRAction::Reduce(51 /* Literal */, 128), + /* 149 */ LRAction::Reduce(51 /* Literal */, 129), + /* 150 */ LRAction::Reduce(51 /* Literal */, 130), + /* 151 */ LRAction::Reduce(51 /* Literal */, 131), + /* 152 */ LRAction::Reduce(51 /* Literal */, 132), + /* 153 */ LRAction::Reduce(52 /* LogicalAndExpr */, 56), + /* 154 */ LRAction::Reduce(53 /* LogicalAndExprList */, 57), + /* 155 */ LRAction::Reduce(53 /* LogicalAndExprList */, 58), + /* 156 */ LRAction::Reduce(54 /* LogicalOrExpr */, 53), + /* 157 */ LRAction::Reduce(55 /* LogicalOrExprList */, 54), + /* 158 */ LRAction::Reduce(55 /* LogicalOrExprList */, 55), + /* 159 */ LRAction::Reduce(56 /* LowerPrefixExpr */, 92), + /* 160 */ LRAction::Reduce(57 /* LowerPrefixExprOpt */, 93), + /* 161 */ LRAction::Reduce(57 /* LowerPrefixExprOpt */, 94), + /* 162 */ LRAction::Reduce(58 /* LowerPrefixOp */, 95), + /* 163 */ LRAction::Reduce(58 /* LowerPrefixOp */, 96), + /* 164 */ LRAction::Reduce(59 /* Modifier */, 119), + /* 165 */ LRAction::Reduce(60 /* ModifierOpt */, 120), + /* 166 */ LRAction::Reduce(60 /* ModifierOpt */, 121), + /* 167 */ LRAction::Reduce(61 /* Numeric */, 145), + /* 168 */ LRAction::Reduce(61 /* Numeric */, 146), + /* 169 */ LRAction::Reduce(61 /* Numeric */, 147), + /* 170 */ LRAction::Reduce(61 /* Numeric */, 148), + /* 171 */ LRAction::Reduce(62 /* OctalInteger */, 150), + /* 172 */ LRAction::Reduce(63 /* Parameter */, 27), + /* 173 */ LRAction::Reduce(64 /* ParameterList */, 21), + /* 174 */ LRAction::Reduce(65 /* ParameterListOpt */, 22), + /* 175 */ LRAction::Reduce(65 /* ParameterListOpt */, 23), + /* 176 */ LRAction::Reduce(66 /* Path */, 123), + /* 177 */ LRAction::Reduce(67 /* PathList */, 124), + /* 178 */ LRAction::Reduce(67 /* PathList */, 125), + /* 179 */ LRAction::Reduce(68 /* PrefixExpr */, 83), + /* 180 */ LRAction::Reduce(68 /* PrefixExpr */, 84), + /* 181 */ LRAction::Reduce(68 /* PrefixExpr */, 87), + /* 182 */ LRAction::Reduce(68 /* PrefixExpr */, 88), + /* 183 */ LRAction::Reduce(69 /* PrefixExprList */, 85), + /* 184 */ LRAction::Reduce(69 /* PrefixExprList */, 86), + /* 185 */ LRAction::Reduce(70 /* Program */, 7), + /* 186 */ LRAction::Reduce(70 /* Program */, 8), + /* 187 */ LRAction::Reduce(72 /* Qualif */, 116), + /* 188 */ LRAction::Reduce(72 /* Qualif */, 117), + /* 189 */ LRAction::Reduce(73 /* ReturnStmt */, 47), + /* 190 */ LRAction::Reduce(74 /* Rfc3339DateTime */, 153), + /* 191 */ LRAction::Reduce(75 /* Scope */, 29), + /* 192 */ LRAction::Reduce(76 /* ScopeContent */, 32), + /* 193 */ LRAction::Reduce(77 /* ScopeContentKind */, 39), + /* 194 */ LRAction::Reduce(77 /* ScopeContentKind */, 40), + /* 195 */ LRAction::Reduce(78 /* ScopeContentOpt */, 37), + /* 196 */ LRAction::Reduce(78 /* ScopeContentOpt */, 38), + /* 197 */ LRAction::Reduce(79 /* ScopeContentOpt0 */, 35), + /* 198 */ LRAction::Reduce(79 /* ScopeContentOpt0 */, 36), + /* 199 */ LRAction::Reduce(80 /* ScopeContentOpt1 */, 33), + /* 200 */ LRAction::Reduce(80 /* ScopeContentOpt1 */, 34), + /* 201 */ LRAction::Reduce(81 /* ScopeOpt */, 30), + /* 202 */ LRAction::Reduce(81 /* ScopeOpt */, 31), + /* 203 */ LRAction::Reduce(82 /* SelectExpr */, 109), + /* 204 */ LRAction::Reduce(83 /* SelectScope */, 110), + /* 205 */ LRAction::Reduce(84 /* SelectScopeContent */, 115), + /* 206 */ LRAction::Reduce(85 /* SelectScopeOpt */, 113), + /* 207 */ LRAction::Reduce(85 /* SelectScopeOpt */, 114), + /* 208 */ LRAction::Reduce(86 /* SelectScopeOpt0 */, 111), + /* 209 */ LRAction::Reduce(86 /* SelectScopeOpt0 */, 112), + /* 210 */ LRAction::Reduce(87 /* Semi */, 43), + /* 211 */ LRAction::Reduce(88 /* SetExpr */, 50), + /* 212 */ LRAction::Reduce(89 /* SetExprOpt */, 51), + /* 213 */ LRAction::Reduce(89 /* SetExprOpt */, 52), + /* 214 */ LRAction::Reduce(90 /* Statement */, 41), + /* 215 */ LRAction::Reduce(91 /* StatementKind */, 44), + /* 216 */ LRAction::Reduce(91 /* StatementKind */, 45), + /* 217 */ LRAction::Reduce(91 /* StatementKind */, 46), + /* 218 */ LRAction::Reduce(92 /* String */, 142), + /* 219 */ LRAction::Accept, + ], + states: &[ + // State 0 + LR1State { + actions: &[ + (0, 119), /* '<$>' => LRAction::Reduce(DefinitionOpt, 15) */ + (5, 119), /* '\r?\n|\r' => LRAction::Reduce(DefinitionOpt, 15) */ + (6, 119), /* '#' => LRAction::Reduce(DefinitionOpt, 15) */ + (8, 0), /* 'prc' => LRAction::Shift(1) */ + (14, 1), /* 'const' => LRAction::Shift(2) */ + ], + gotos: &[ + (28, 3), /* ConstantDef => 3 */ + (30, 4), /* Definition => 4 */ + (31, 5), /* DefinitionOpt => 5 */ + (33, 6), /* DefinitionOptGroup => 6 */ + (39, 7), /* FunctionDef => 7 */ + (70, 8), /* Program => 8 */ + ], + }, + // State 1 + LR1State { + actions: &[ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[(45, 10) /* Ident => 10 */], + }, + // State 2 + LR1State { + actions: &[ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[(45, 11) /* Ident => 11 */], + }, + // State 3 + LR1State { + actions: &[ + (0, 123), /* '<$>' => LRAction::Reduce(DefinitionOptGroup, 14) */ + (5, 123), /* '\r?\n|\r' => LRAction::Reduce(DefinitionOptGroup, 14) */ + (6, 123), /* '#' => LRAction::Reduce(DefinitionOptGroup, 14) */ + ], + gotos: &[], + }, + // State 4 + LR1State { + actions: &[ + (0, 186), /* '<$>' => LRAction::Reduce(Program, 8) */ + (5, 3), /* '\r?\n|\r' => LRAction::Shift(12) */ + ], + gotos: &[(34, 13) /* EndOfLine => 13 */], + }, + // State 5 + LR1State { + actions: &[ + (0, 121), /* '<$>' => LRAction::Reduce(DefinitionOpt0, 11) */ + (5, 121), /* '\r?\n|\r' => LRAction::Reduce(DefinitionOpt0, 11) */ + (6, 4), /* '#' => LRAction::Shift(14) */ + ], + gotos: &[ + (22, 15), /* Comment => 15 */ + (32, 16), /* DefinitionOpt0 => 16 */ + (42, 17), /* Hash => 17 */ + ], + }, + // State 6 + LR1State { + actions: &[ + (0, 118), /* '<$>' => LRAction::Reduce(DefinitionOpt, 12) */ + (5, 118), /* '\r?\n|\r' => LRAction::Reduce(DefinitionOpt, 12) */ + (6, 118), /* '#' => LRAction::Reduce(DefinitionOpt, 12) */ + ], + gotos: &[], + }, + // State 7 + LR1State { + actions: &[ + (0, 122), /* '<$>' => LRAction::Reduce(DefinitionOptGroup, 13) */ + (5, 122), /* '\r?\n|\r' => LRAction::Reduce(DefinitionOptGroup, 13) */ + (6, 122), /* '#' => LRAction::Reduce(DefinitionOptGroup, 13) */ + ], + gotos: &[], + }, + // State 8 + LR1State { + actions: &[(0, 219) /* '<$>' => LRAction::Accept */], + gotos: &[], + }, + // State 9 + LR1State { + actions: &[ + (9, 140), /* '(' => LRAction::Reduce(Ident, 126) */ + (10, 140), /* ')' => LRAction::Reduce(Ident, 126) */ + (12, 140), /* ',' => LRAction::Reduce(Ident, 126) */ + (13, 140), /* ':' => LRAction::Reduce(Ident, 126) */ + (15, 140), /* '=' => LRAction::Reduce(Ident, 126) */ + (16, 140), /* '.' => LRAction::Reduce(Ident, 126) */ + (17, 140), /* ';' => LRAction::Reduce(Ident, 126) */ + (20, 140), /* ':=' => LRAction::Reduce(Ident, 126) */ + (21, 140), /* '||' => LRAction::Reduce(Ident, 126) */ + (22, 140), /* '&&' => LRAction::Reduce(Ident, 126) */ + (23, 140), /* '>=' => LRAction::Reduce(Ident, 126) */ + (24, 140), /* '<=' => LRAction::Reduce(Ident, 126) */ + (25, 140), /* '>' => LRAction::Reduce(Ident, 126) */ + (26, 140), /* '<' => LRAction::Reduce(Ident, 126) */ + (27, 140), /* '!=' => LRAction::Reduce(Ident, 126) */ + (28, 140), /* '/=' => LRAction::Reduce(Ident, 126) */ + (29, 140), /* '==' => LRAction::Reduce(Ident, 126) */ + (30, 140), /* '+' => LRAction::Reduce(Ident, 126) */ + (31, 140), /* '-' => LRAction::Reduce(Ident, 126) */ + (32, 140), /* '*' => LRAction::Reduce(Ident, 126) */ + (33, 140), /* '/' => LRAction::Reduce(Ident, 126) */ + (34, 140), /* '%' => LRAction::Reduce(Ident, 126) */ + (35, 140), /* 'as' => LRAction::Reduce(Ident, 126) */ + (38, 140), /* '&' => LRAction::Reduce(Ident, 126) */ + (39, 140), /* '$' => LRAction::Reduce(Ident, 126) */ + (41, 140), /* 'if' => LRAction::Reduce(Ident, 126) */ + (43, 140), /* 'select' => LRAction::Reduce(Ident, 126) */ + (44, 140), /* '{' => LRAction::Reduce(Ident, 126) */ + (46, 140), /* '=>' => LRAction::Reduce(Ident, 126) */ + (47, 140), /* '~' => LRAction::Reduce(Ident, 126) */ + (48, 140), /* '@' => LRAction::Reduce(Ident, 126) */ + (49, 140), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Ident, 126) */ + (50, 140), /* '[' => LRAction::Reduce(Ident, 126) */ + (51, 140), /* ']' => LRAction::Reduce(Ident, 126) */ + (52, 140), /* '"(\\.|[^"])*"' => LRAction::Reduce(Ident, 126) */ + (53, 140), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Ident, 126) */ + (54, 140), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Ident, 126) */ + (55, 140), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Ident, 126) */ + (56, 140), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Ident, 126) */ + (57, 140), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Ident, 126) */ + (58, 140), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Ident, 126) */ + (59, 140), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Ident, 126) */ + ], + gotos: &[], + }, + // State 10 + LR1State { + actions: &[(9, 5) /* '(' => LRAction::Shift(18) */], + gotos: &[], + }, + // State 11 + LR1State { + actions: &[(13, 6) /* ':' => LRAction::Shift(19) */], + gotos: &[], + }, + // State 12 + LR1State { + actions: &[ + (0, 124), /* '<$>' => LRAction::Reduce(EndOfLine, 1) */ + (5, 124), /* '\r?\n|\r' => LRAction::Reduce(EndOfLine, 1) */ + (6, 124), /* '#' => LRAction::Reduce(EndOfLine, 1) */ + (8, 124), /* 'prc' => LRAction::Reduce(EndOfLine, 1) */ + (9, 124), /* '(' => LRAction::Reduce(EndOfLine, 1) */ + (14, 124), /* 'const' => LRAction::Reduce(EndOfLine, 1) */ + (16, 124), /* '.' => LRAction::Reduce(EndOfLine, 1) */ + (18, 124), /* 'return' => LRAction::Reduce(EndOfLine, 1) */ + (19, 124), /* 'let' => LRAction::Reduce(EndOfLine, 1) */ + (31, 124), /* '-' => LRAction::Reduce(EndOfLine, 1) */ + (36, 124), /* 'wait' => LRAction::Reduce(EndOfLine, 1) */ + (37, 124), /* 'call' => LRAction::Reduce(EndOfLine, 1) */ + (38, 124), /* '&' => LRAction::Reduce(EndOfLine, 1) */ + (39, 124), /* '$' => LRAction::Reduce(EndOfLine, 1) */ + (41, 124), /* 'if' => LRAction::Reduce(EndOfLine, 1) */ + (43, 124), /* 'select' => LRAction::Reduce(EndOfLine, 1) */ + (44, 124), /* '{' => LRAction::Reduce(EndOfLine, 1) */ + (45, 124), /* '}' => LRAction::Reduce(EndOfLine, 1) */ + (47, 124), /* '~' => LRAction::Reduce(EndOfLine, 1) */ + (48, 124), /* '@' => LRAction::Reduce(EndOfLine, 1) */ + (49, 124), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(EndOfLine, 1) */ + (50, 124), /* '[' => LRAction::Reduce(EndOfLine, 1) */ + (52, 124), /* '"(\\.|[^"])*"' => LRAction::Reduce(EndOfLine, 1) */ + (53, 124), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(EndOfLine, 1) */ + (54, 124), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(EndOfLine, 1) */ + (55, 124), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(EndOfLine, 1) */ + (56, 124), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(EndOfLine, 1) */ + (57, 124), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(EndOfLine, 1) */ + (58, 124), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(EndOfLine, 1) */ + (59, 124), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(EndOfLine, 1) */ + ], + gotos: &[], + }, + // State 13 + LR1State { + actions: &[ + (0, 119), /* '<$>' => LRAction::Reduce(DefinitionOpt, 15) */ + (5, 119), /* '\r?\n|\r' => LRAction::Reduce(DefinitionOpt, 15) */ + (6, 119), /* '#' => LRAction::Reduce(DefinitionOpt, 15) */ + (8, 0), /* 'prc' => LRAction::Shift(1) */ + (14, 1), /* 'const' => LRAction::Shift(2) */ + ], + gotos: &[ + (28, 3), /* ConstantDef => 3 */ + (30, 4), /* Definition => 4 */ + (31, 5), /* DefinitionOpt => 5 */ + (33, 6), /* DefinitionOptGroup => 6 */ + (39, 7), /* FunctionDef => 7 */ + (70, 20), /* Program => 20 */ + ], + }, + // State 14 + LR1State { + actions: &[ + (0, 137), /* '<$>' => LRAction::Reduce(Hash, 5) */ + (5, 137), /* '\r?\n|\r' => LRAction::Reduce(Hash, 5) */ + (7, 137), /* '[^\r\n]*' => LRAction::Reduce(Hash, 5) */ + (45, 137), /* '}' => LRAction::Reduce(Hash, 5) */ + ], + gotos: &[], + }, + // State 15 + LR1State { + actions: &[ + (0, 120), /* '<$>' => LRAction::Reduce(DefinitionOpt0, 10) */ + (5, 120), /* '\r?\n|\r' => LRAction::Reduce(DefinitionOpt0, 10) */ + ], + gotos: &[], + }, + // State 16 + LR1State { + actions: &[ + (0, 117), /* '<$>' => LRAction::Reduce(Definition, 9) */ + (5, 117), /* '\r?\n|\r' => LRAction::Reduce(Definition, 9) */ + ], + gotos: &[], + }, + // State 17 + LR1State { + actions: &[ + (0, 104), /* '<$>' => LRAction::Reduce(CommentOpt, 4) */ + (5, 104), /* '\r?\n|\r' => LRAction::Reduce(CommentOpt, 4) */ + (7, 7), /* '[^\r\n]*' => LRAction::Shift(21) */ + (45, 104), /* '}' => LRAction::Reduce(CommentOpt, 4) */ + ], + gotos: &[ + (23, 22), /* CommentContent => 22 */ + (24, 23), /* CommentOpt => 23 */ + ], + }, + // State 18 + LR1State { + actions: &[ + (10, 134), /* ')' => LRAction::Reduce(FunctionDefOpt, 20) */ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[ + (40, 24), /* FunctionDefOpt => 24 */ + (45, 25), /* Ident => 25 */ + (63, 26), /* Parameter => 26 */ + (64, 27), /* ParameterList => 27 */ + ], + }, + // State 19 + LR1State { + actions: &[ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[ + (45, 28), /* Ident => 28 */ + (66, 29), /* Path => 29 */ + ], + }, + // State 20 + LR1State { + actions: &[(0, 185) /* '<$>' => LRAction::Reduce(Program, 7) */], + gotos: &[], + }, + // State 21 + LR1State { + actions: &[ + (0, 102), /* '<$>' => LRAction::Reduce(CommentContent, 6) */ + (5, 102), /* '\r?\n|\r' => LRAction::Reduce(CommentContent, 6) */ + (45, 102), /* '}' => LRAction::Reduce(CommentContent, 6) */ + ], + gotos: &[], + }, + // State 22 + LR1State { + actions: &[ + (0, 103), /* '<$>' => LRAction::Reduce(CommentOpt, 3) */ + (5, 103), /* '\r?\n|\r' => LRAction::Reduce(CommentOpt, 3) */ + (45, 103), /* '}' => LRAction::Reduce(CommentOpt, 3) */ + ], + gotos: &[], + }, + // State 23 + LR1State { + actions: &[ + (0, 101), /* '<$>' => LRAction::Reduce(Comment, 2) */ + (5, 101), /* '\r?\n|\r' => LRAction::Reduce(Comment, 2) */ + (45, 101), /* '}' => LRAction::Reduce(Comment, 2) */ + ], + gotos: &[], + }, + // State 24 + LR1State { + actions: &[(10, 8) /* ')' => LRAction::Shift(30) */], + gotos: &[], + }, + // State 25 + LR1State { + actions: &[(13, 9) /* ':' => LRAction::Shift(31) */], + gotos: &[], + }, + // State 26 + LR1State { + actions: &[ + (10, 175), /* ')' => LRAction::Reduce(ParameterListOpt, 23) */ + (12, 10), /* ',' => LRAction::Shift(32) */ + ], + gotos: &[ + (18, 33), /* CommaParameterList => 33 */ + (65, 34), /* ParameterListOpt => 34 */ + ], + }, + // State 27 + LR1State { + actions: &[ + (10, 133), /* ')' => LRAction::Reduce(FunctionDefOpt, 19) */ + ], + gotos: &[], + }, + // State 28 + LR1State { + actions: &[ + (9, 178), /* '(' => LRAction::Reduce(PathList, 125) */ + (10, 178), /* ')' => LRAction::Reduce(PathList, 125) */ + (12, 178), /* ',' => LRAction::Reduce(PathList, 125) */ + (13, 178), /* ':' => LRAction::Reduce(PathList, 125) */ + (15, 178), /* '=' => LRAction::Reduce(PathList, 125) */ + (16, 178), /* '.' => LRAction::Reduce(PathList, 125) */ + (17, 178), /* ';' => LRAction::Reduce(PathList, 125) */ + (20, 178), /* ':=' => LRAction::Reduce(PathList, 125) */ + (21, 178), /* '||' => LRAction::Reduce(PathList, 125) */ + (22, 178), /* '&&' => LRAction::Reduce(PathList, 125) */ + (23, 178), /* '>=' => LRAction::Reduce(PathList, 125) */ + (24, 178), /* '<=' => LRAction::Reduce(PathList, 125) */ + (25, 178), /* '>' => LRAction::Reduce(PathList, 125) */ + (26, 178), /* '<' => LRAction::Reduce(PathList, 125) */ + (27, 178), /* '!=' => LRAction::Reduce(PathList, 125) */ + (28, 178), /* '/=' => LRAction::Reduce(PathList, 125) */ + (29, 178), /* '==' => LRAction::Reduce(PathList, 125) */ + (30, 178), /* '+' => LRAction::Reduce(PathList, 125) */ + (31, 178), /* '-' => LRAction::Reduce(PathList, 125) */ + (32, 178), /* '*' => LRAction::Reduce(PathList, 125) */ + (33, 178), /* '/' => LRAction::Reduce(PathList, 125) */ + (34, 178), /* '%' => LRAction::Reduce(PathList, 125) */ + (35, 178), /* 'as' => LRAction::Reduce(PathList, 125) */ + (38, 178), /* '&' => LRAction::Reduce(PathList, 125) */ + (39, 178), /* '$' => LRAction::Reduce(PathList, 125) */ + (41, 178), /* 'if' => LRAction::Reduce(PathList, 125) */ + (43, 178), /* 'select' => LRAction::Reduce(PathList, 125) */ + (44, 178), /* '{' => LRAction::Reduce(PathList, 125) */ + (46, 178), /* '=>' => LRAction::Reduce(PathList, 125) */ + (47, 178), /* '~' => LRAction::Reduce(PathList, 125) */ + (48, 178), /* '@' => LRAction::Reduce(PathList, 125) */ + (49, 178), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(PathList, 125) */ + (50, 178), /* '[' => LRAction::Reduce(PathList, 125) */ + (51, 178), /* ']' => LRAction::Reduce(PathList, 125) */ + (52, 178), /* '"(\\.|[^"])*"' => LRAction::Reduce(PathList, 125) */ + (53, 178), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(PathList, 125) */ + (54, 178), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(PathList, 125) */ + (55, 178), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(PathList, 125) */ + (56, 178), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(PathList, 125) */ + (57, 178), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(PathList, 125) */ + (58, 178), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(PathList, 125) */ + (59, 178), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(PathList, 125) */ + ], + gotos: &[(67, 35) /* PathList => 35 */], + }, + // State 29 + LR1State { + actions: &[(15, 11) /* '=' => LRAction::Shift(36) */], + gotos: &[], + }, + // State 30 + LR1State { + actions: &[ + (11, 12), /* '->' => LRAction::Shift(37) */ + (44, 136), /* '{' => LRAction::Reduce(FunctionDefOpt0, 18) */ + ], + gotos: &[(41, 38) /* FunctionDefOpt0 => 38 */], + }, + // State 31 + LR1State { + actions: &[ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[ + (45, 28), /* Ident => 28 */ + (66, 39), /* Path => 39 */ + ], + }, + // State 32 + LR1State { + actions: &[ + (10, 97), /* ')' => LRAction::Reduce(CommaParameterListOpt, 26) */ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[ + (19, 40), /* CommaParameterListOpt => 40 */ + (45, 25), /* Ident => 25 */ + (63, 26), /* Parameter => 26 */ + (64, 41), /* ParameterList => 41 */ + ], + }, + // State 33 + LR1State { + actions: &[ + (10, 174), /* ')' => LRAction::Reduce(ParameterListOpt, 22) */ + ], + gotos: &[], + }, + // State 34 + LR1State { + actions: &[ + (10, 173), /* ')' => LRAction::Reduce(ParameterList, 21) */ + ], + gotos: &[], + }, + // State 35 + LR1State { + actions: &[ + (9, 176), /* '(' => LRAction::Reduce(Path, 123) */ + (10, 176), /* ')' => LRAction::Reduce(Path, 123) */ + (12, 176), /* ',' => LRAction::Reduce(Path, 123) */ + (13, 176), /* ':' => LRAction::Reduce(Path, 123) */ + (15, 176), /* '=' => LRAction::Reduce(Path, 123) */ + (16, 13), /* '.' => LRAction::Shift(42) */ + (17, 176), /* ';' => LRAction::Reduce(Path, 123) */ + (20, 176), /* ':=' => LRAction::Reduce(Path, 123) */ + (21, 176), /* '||' => LRAction::Reduce(Path, 123) */ + (22, 176), /* '&&' => LRAction::Reduce(Path, 123) */ + (23, 176), /* '>=' => LRAction::Reduce(Path, 123) */ + (24, 176), /* '<=' => LRAction::Reduce(Path, 123) */ + (25, 176), /* '>' => LRAction::Reduce(Path, 123) */ + (26, 176), /* '<' => LRAction::Reduce(Path, 123) */ + (27, 176), /* '!=' => LRAction::Reduce(Path, 123) */ + (28, 176), /* '/=' => LRAction::Reduce(Path, 123) */ + (29, 176), /* '==' => LRAction::Reduce(Path, 123) */ + (30, 176), /* '+' => LRAction::Reduce(Path, 123) */ + (31, 176), /* '-' => LRAction::Reduce(Path, 123) */ + (32, 176), /* '*' => LRAction::Reduce(Path, 123) */ + (33, 176), /* '/' => LRAction::Reduce(Path, 123) */ + (34, 176), /* '%' => LRAction::Reduce(Path, 123) */ + (35, 176), /* 'as' => LRAction::Reduce(Path, 123) */ + (38, 176), /* '&' => LRAction::Reduce(Path, 123) */ + (39, 176), /* '$' => LRAction::Reduce(Path, 123) */ + (41, 176), /* 'if' => LRAction::Reduce(Path, 123) */ + (43, 176), /* 'select' => LRAction::Reduce(Path, 123) */ + (44, 176), /* '{' => LRAction::Reduce(Path, 123) */ + (46, 176), /* '=>' => LRAction::Reduce(Path, 123) */ + (47, 176), /* '~' => LRAction::Reduce(Path, 123) */ + (48, 176), /* '@' => LRAction::Reduce(Path, 123) */ + (49, 176), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Path, 123) */ + (50, 176), /* '[' => LRAction::Reduce(Path, 123) */ + (51, 176), /* ']' => LRAction::Reduce(Path, 123) */ + (52, 176), /* '"(\\.|[^"])*"' => LRAction::Reduce(Path, 123) */ + (53, 176), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Path, 123) */ + (54, 176), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Path, 123) */ + (55, 176), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Path, 123) */ + (56, 176), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Path, 123) */ + (57, 176), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Path, 123) */ + (58, 176), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Path, 123) */ + (59, 176), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Path, 123) */ + ], + gotos: &[], + }, + // State 36 + LR1State { + actions: &[ + (9, 158), /* '(' => LRAction::Reduce(LogicalOrExprList, 55) */ + (31, 158), /* '-' => LRAction::Reduce(LogicalOrExprList, 55) */ + (36, 158), /* 'wait' => LRAction::Reduce(LogicalOrExprList, 55) */ + (37, 158), /* 'call' => LRAction::Reduce(LogicalOrExprList, 55) */ + (38, 158), /* '&' => LRAction::Reduce(LogicalOrExprList, 55) */ + (39, 158), /* '$' => LRAction::Reduce(LogicalOrExprList, 55) */ + (41, 158), /* 'if' => LRAction::Reduce(LogicalOrExprList, 55) */ + (43, 158), /* 'select' => LRAction::Reduce(LogicalOrExprList, 55) */ + (47, 158), /* '~' => LRAction::Reduce(LogicalOrExprList, 55) */ + (48, 158), /* '@' => LRAction::Reduce(LogicalOrExprList, 55) */ + (49, 158), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalOrExprList, 55) */ + (50, 158), /* '[' => LRAction::Reduce(LogicalOrExprList, 55) */ + (52, 158), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (53, 158), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (54, 158), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (55, 158), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (56, 158), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (57, 158), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (58, 158), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (59, 158), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalOrExprList, 55) */ + ], + gotos: &[ + (35, 43), /* Expr => 43 */ + (54, 44), /* LogicalOrExpr => 44 */ + (55, 45), /* LogicalOrExprList => 45 */ + (88, 46), /* SetExpr => 46 */ + ], + }, + // State 37 + LR1State { + actions: &[ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[ + (45, 28), /* Ident => 28 */ + (66, 47), /* Path => 47 */ + ], + }, + // State 38 + LR1State { + actions: &[(44, 14) /* '{' => LRAction::Shift(48) */], + gotos: &[(9, 49) /* Block => 49 */], + }, + // State 39 + LR1State { + actions: &[ + (10, 172), /* ')' => LRAction::Reduce(Parameter, 27) */ + (12, 172), /* ',' => LRAction::Reduce(Parameter, 27) */ + ], + gotos: &[], + }, + // State 40 + LR1State { + actions: &[ + (10, 95), /* ')' => LRAction::Reduce(CommaParameterList, 24) */ + ], + gotos: &[], + }, + // State 41 + LR1State { + actions: &[ + (10, 96), /* ')' => LRAction::Reduce(CommaParameterListOpt, 25) */ + ], + gotos: &[], + }, + // State 42 + LR1State { + actions: &[ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[(45, 50) /* Ident => 50 */], + }, + // State 43 + LR1State { + actions: &[(17, 15) /* ';' => LRAction::Shift(51) */], + gotos: &[(87, 52) /* Semi => 52 */], + }, + // State 44 + LR1State { + actions: &[ + (10, 213), /* ')' => LRAction::Reduce(SetExprOpt, 52) */ + (12, 213), /* ',' => LRAction::Reduce(SetExprOpt, 52) */ + (17, 213), /* ';' => LRAction::Reduce(SetExprOpt, 52) */ + (20, 16), /* ':=' => LRAction::Shift(53) */ + (44, 213), /* '{' => LRAction::Reduce(SetExprOpt, 52) */ + (46, 213), /* '=>' => LRAction::Reduce(SetExprOpt, 52) */ + (51, 213), /* ']' => LRAction::Reduce(SetExprOpt, 52) */ + ], + gotos: &[(89, 54) /* SetExprOpt => 54 */], + }, + // State 45 + LR1State { + actions: &[ + (9, 155), /* '(' => LRAction::Reduce(LogicalAndExprList, 58) */ + (31, 155), /* '-' => LRAction::Reduce(LogicalAndExprList, 58) */ + (36, 155), /* 'wait' => LRAction::Reduce(LogicalAndExprList, 58) */ + (37, 155), /* 'call' => LRAction::Reduce(LogicalAndExprList, 58) */ + (38, 155), /* '&' => LRAction::Reduce(LogicalAndExprList, 58) */ + (39, 155), /* '$' => LRAction::Reduce(LogicalAndExprList, 58) */ + (41, 155), /* 'if' => LRAction::Reduce(LogicalAndExprList, 58) */ + (43, 155), /* 'select' => LRAction::Reduce(LogicalAndExprList, 58) */ + (47, 155), /* '~' => LRAction::Reduce(LogicalAndExprList, 58) */ + (48, 155), /* '@' => LRAction::Reduce(LogicalAndExprList, 58) */ + (49, 155), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalAndExprList, 58) */ + (50, 155), /* '[' => LRAction::Reduce(LogicalAndExprList, 58) */ + (52, 155), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalAndExprList, 58) */ + (53, 155), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalAndExprList, 58) */ + (54, 155), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalAndExprList, 58) */ + (55, 155), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalAndExprList, 58) */ + (56, 155), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalAndExprList, 58) */ + (57, 155), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalAndExprList, 58) */ + (58, 155), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalAndExprList, 58) */ + (59, 155), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalAndExprList, 58) */ + ], + gotos: &[ + (52, 55), /* LogicalAndExpr => 55 */ + (53, 56), /* LogicalAndExprList => 56 */ + ], + }, + // State 46 + LR1State { + actions: &[ + (10, 125), /* ')' => LRAction::Reduce(Expr, 49) */ + (12, 125), /* ',' => LRAction::Reduce(Expr, 49) */ + (17, 125), /* ';' => LRAction::Reduce(Expr, 49) */ + (44, 125), /* '{' => LRAction::Reduce(Expr, 49) */ + (46, 125), /* '=>' => LRAction::Reduce(Expr, 49) */ + (51, 125), /* ']' => LRAction::Reduce(Expr, 49) */ + ], + gotos: &[], + }, + // State 47 + LR1State { + actions: &[ + (44, 135), /* '{' => LRAction::Reduce(FunctionDefOpt0, 17) */ + ], + gotos: &[], + }, + // State 48 + LR1State { + actions: &[ + (5, 196), /* '\r?\n|\r' => LRAction::Reduce(ScopeContentOpt, 38) */ + (6, 196), /* '#' => LRAction::Reduce(ScopeContentOpt, 38) */ + (9, 196), /* '(' => LRAction::Reduce(ScopeContentOpt, 38) */ + (16, 17), /* '.' => LRAction::Shift(57) */ + (18, 196), /* 'return' => LRAction::Reduce(ScopeContentOpt, 38) */ + (19, 196), /* 'let' => LRAction::Reduce(ScopeContentOpt, 38) */ + (31, 196), /* '-' => LRAction::Reduce(ScopeContentOpt, 38) */ + (36, 196), /* 'wait' => LRAction::Reduce(ScopeContentOpt, 38) */ + (37, 196), /* 'call' => LRAction::Reduce(ScopeContentOpt, 38) */ + (38, 196), /* '&' => LRAction::Reduce(ScopeContentOpt, 38) */ + (39, 196), /* '$' => LRAction::Reduce(ScopeContentOpt, 38) */ + (41, 196), /* 'if' => LRAction::Reduce(ScopeContentOpt, 38) */ + (43, 196), /* 'select' => LRAction::Reduce(ScopeContentOpt, 38) */ + (44, 196), /* '{' => LRAction::Reduce(ScopeContentOpt, 38) */ + (45, 196), /* '}' => LRAction::Reduce(ScopeContentOpt, 38) */ + (47, 196), /* '~' => LRAction::Reduce(ScopeContentOpt, 38) */ + (48, 196), /* '@' => LRAction::Reduce(ScopeContentOpt, 38) */ + (49, 196), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ScopeContentOpt, 38) */ + (50, 196), /* '[' => LRAction::Reduce(ScopeContentOpt, 38) */ + (52, 196), /* '"(\\.|[^"])*"' => LRAction::Reduce(ScopeContentOpt, 38) */ + (53, 196), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ScopeContentOpt, 38) */ + (54, 196), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ScopeContentOpt, 38) */ + (55, 196), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ScopeContentOpt, 38) */ + (56, 196), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ScopeContentOpt, 38) */ + (57, 196), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ScopeContentOpt, 38) */ + (58, 196), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ScopeContentOpt, 38) */ + (59, 196), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ScopeContentOpt, 38) */ + ], + gotos: &[ + (10, 58), /* Break => 58 */ + (75, 59), /* Scope => 59 */ + (76, 60), /* ScopeContent => 60 */ + (78, 61), /* ScopeContentOpt => 61 */ + ], + }, + // State 49 + LR1State { + actions: &[ + (0, 132), /* '<$>' => LRAction::Reduce(FunctionDef, 16) */ + (5, 132), /* '\r?\n|\r' => LRAction::Reduce(FunctionDef, 16) */ + (6, 132), /* '#' => LRAction::Reduce(FunctionDef, 16) */ + ], + gotos: &[], + }, + // State 50 + LR1State { + actions: &[ + (9, 177), /* '(' => LRAction::Reduce(PathList, 124) */ + (10, 177), /* ')' => LRAction::Reduce(PathList, 124) */ + (12, 177), /* ',' => LRAction::Reduce(PathList, 124) */ + (13, 177), /* ':' => LRAction::Reduce(PathList, 124) */ + (15, 177), /* '=' => LRAction::Reduce(PathList, 124) */ + (16, 177), /* '.' => LRAction::Reduce(PathList, 124) */ + (17, 177), /* ';' => LRAction::Reduce(PathList, 124) */ + (20, 177), /* ':=' => LRAction::Reduce(PathList, 124) */ + (21, 177), /* '||' => LRAction::Reduce(PathList, 124) */ + (22, 177), /* '&&' => LRAction::Reduce(PathList, 124) */ + (23, 177), /* '>=' => LRAction::Reduce(PathList, 124) */ + (24, 177), /* '<=' => LRAction::Reduce(PathList, 124) */ + (25, 177), /* '>' => LRAction::Reduce(PathList, 124) */ + (26, 177), /* '<' => LRAction::Reduce(PathList, 124) */ + (27, 177), /* '!=' => LRAction::Reduce(PathList, 124) */ + (28, 177), /* '/=' => LRAction::Reduce(PathList, 124) */ + (29, 177), /* '==' => LRAction::Reduce(PathList, 124) */ + (30, 177), /* '+' => LRAction::Reduce(PathList, 124) */ + (31, 177), /* '-' => LRAction::Reduce(PathList, 124) */ + (32, 177), /* '*' => LRAction::Reduce(PathList, 124) */ + (33, 177), /* '/' => LRAction::Reduce(PathList, 124) */ + (34, 177), /* '%' => LRAction::Reduce(PathList, 124) */ + (35, 177), /* 'as' => LRAction::Reduce(PathList, 124) */ + (38, 177), /* '&' => LRAction::Reduce(PathList, 124) */ + (39, 177), /* '$' => LRAction::Reduce(PathList, 124) */ + (41, 177), /* 'if' => LRAction::Reduce(PathList, 124) */ + (43, 177), /* 'select' => LRAction::Reduce(PathList, 124) */ + (44, 177), /* '{' => LRAction::Reduce(PathList, 124) */ + (46, 177), /* '=>' => LRAction::Reduce(PathList, 124) */ + (47, 177), /* '~' => LRAction::Reduce(PathList, 124) */ + (48, 177), /* '@' => LRAction::Reduce(PathList, 124) */ + (49, 177), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(PathList, 124) */ + (50, 177), /* '[' => LRAction::Reduce(PathList, 124) */ + (51, 177), /* ']' => LRAction::Reduce(PathList, 124) */ + (52, 177), /* '"(\\.|[^"])*"' => LRAction::Reduce(PathList, 124) */ + (53, 177), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(PathList, 124) */ + (54, 177), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(PathList, 124) */ + (55, 177), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(PathList, 124) */ + (56, 177), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(PathList, 124) */ + (57, 177), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(PathList, 124) */ + (58, 177), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(PathList, 124) */ + (59, 177), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(PathList, 124) */ + ], + gotos: &[], + }, + // State 51 + LR1State { + actions: &[ + (0, 210), /* '<$>' => LRAction::Reduce(Semi, 43) */ + (5, 210), /* '\r?\n|\r' => LRAction::Reduce(Semi, 43) */ + (6, 210), /* '#' => LRAction::Reduce(Semi, 43) */ + (45, 210), /* '}' => LRAction::Reduce(Semi, 43) */ + ], + gotos: &[], + }, + // State 52 + LR1State { + actions: &[ + (0, 115), /* '<$>' => LRAction::Reduce(ConstantDef, 28) */ + (5, 115), /* '\r?\n|\r' => LRAction::Reduce(ConstantDef, 28) */ + (6, 115), /* '#' => LRAction::Reduce(ConstantDef, 28) */ + ], + gotos: &[], + }, + // State 53 + LR1State { + actions: &[ + (9, 158), /* '(' => LRAction::Reduce(LogicalOrExprList, 55) */ + (31, 158), /* '-' => LRAction::Reduce(LogicalOrExprList, 55) */ + (36, 158), /* 'wait' => LRAction::Reduce(LogicalOrExprList, 55) */ + (37, 158), /* 'call' => LRAction::Reduce(LogicalOrExprList, 55) */ + (38, 158), /* '&' => LRAction::Reduce(LogicalOrExprList, 55) */ + (39, 158), /* '$' => LRAction::Reduce(LogicalOrExprList, 55) */ + (41, 158), /* 'if' => LRAction::Reduce(LogicalOrExprList, 55) */ + (43, 158), /* 'select' => LRAction::Reduce(LogicalOrExprList, 55) */ + (47, 158), /* '~' => LRAction::Reduce(LogicalOrExprList, 55) */ + (48, 158), /* '@' => LRAction::Reduce(LogicalOrExprList, 55) */ + (49, 158), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalOrExprList, 55) */ + (50, 158), /* '[' => LRAction::Reduce(LogicalOrExprList, 55) */ + (52, 158), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (53, 158), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (54, 158), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (55, 158), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (56, 158), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (57, 158), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (58, 158), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (59, 158), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalOrExprList, 55) */ + ], + gotos: &[ + (54, 62), /* LogicalOrExpr => 62 */ + (55, 45), /* LogicalOrExprList => 45 */ + ], + }, + // State 54 + LR1State { + actions: &[ + (10, 211), /* ')' => LRAction::Reduce(SetExpr, 50) */ + (12, 211), /* ',' => LRAction::Reduce(SetExpr, 50) */ + (17, 211), /* ';' => LRAction::Reduce(SetExpr, 50) */ + (44, 211), /* '{' => LRAction::Reduce(SetExpr, 50) */ + (46, 211), /* '=>' => LRAction::Reduce(SetExpr, 50) */ + (51, 211), /* ']' => LRAction::Reduce(SetExpr, 50) */ + ], + gotos: &[], + }, + // State 55 + LR1State { + actions: &[ + (10, 156), /* ')' => LRAction::Reduce(LogicalOrExpr, 53) */ + (12, 156), /* ',' => LRAction::Reduce(LogicalOrExpr, 53) */ + (17, 156), /* ';' => LRAction::Reduce(LogicalOrExpr, 53) */ + (20, 156), /* ':=' => LRAction::Reduce(LogicalOrExpr, 53) */ + (21, 18), /* '||' => LRAction::Shift(63) */ + (44, 156), /* '{' => LRAction::Reduce(LogicalOrExpr, 53) */ + (46, 156), /* '=>' => LRAction::Reduce(LogicalOrExpr, 53) */ + (51, 156), /* ']' => LRAction::Reduce(LogicalOrExpr, 53) */ + ], + gotos: &[], + }, + // State 56 + LR1State { + actions: &[ + (9, 70), /* '(' => LRAction::Reduce(ArithmeticExprList, 71) */ + (31, 70), /* '-' => LRAction::Reduce(ArithmeticExprList, 71) */ + (36, 70), /* 'wait' => LRAction::Reduce(ArithmeticExprList, 71) */ + (37, 70), /* 'call' => LRAction::Reduce(ArithmeticExprList, 71) */ + (38, 70), /* '&' => LRAction::Reduce(ArithmeticExprList, 71) */ + (39, 70), /* '$' => LRAction::Reduce(ArithmeticExprList, 71) */ + (41, 70), /* 'if' => LRAction::Reduce(ArithmeticExprList, 71) */ + (43, 70), /* 'select' => LRAction::Reduce(ArithmeticExprList, 71) */ + (47, 70), /* '~' => LRAction::Reduce(ArithmeticExprList, 71) */ + (48, 70), /* '@' => LRAction::Reduce(ArithmeticExprList, 71) */ + (49, 70), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ArithmeticExprList, 71) */ + (50, 70), /* '[' => LRAction::Reduce(ArithmeticExprList, 71) */ + (52, 70), /* '"(\\.|[^"])*"' => LRAction::Reduce(ArithmeticExprList, 71) */ + (53, 70), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ArithmeticExprList, 71) */ + (54, 70), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ArithmeticExprList, 71) */ + (55, 70), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticExprList, 71) */ + (56, 70), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticExprList, 71) */ + (57, 70), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticExprList, 71) */ + (58, 70), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticExprList, 71) */ + (59, 70), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ArithmeticExprList, 71) */ + ], + gotos: &[ + (2, 64), /* ArithmeticExpr => 64 */ + (3, 65), /* ArithmeticExprList => 65 */ + (25, 66), /* CompareExpr => 66 */ + ], + }, + // State 57 + LR1State { + actions: &[ + (5, 80), /* '\r?\n|\r' => LRAction::Reduce(Break, 42) */ + (6, 80), /* '#' => LRAction::Reduce(Break, 42) */ + (9, 80), /* '(' => LRAction::Reduce(Break, 42) */ + (18, 80), /* 'return' => LRAction::Reduce(Break, 42) */ + (19, 80), /* 'let' => LRAction::Reduce(Break, 42) */ + (31, 80), /* '-' => LRAction::Reduce(Break, 42) */ + (36, 80), /* 'wait' => LRAction::Reduce(Break, 42) */ + (37, 80), /* 'call' => LRAction::Reduce(Break, 42) */ + (38, 80), /* '&' => LRAction::Reduce(Break, 42) */ + (39, 80), /* '$' => LRAction::Reduce(Break, 42) */ + (41, 80), /* 'if' => LRAction::Reduce(Break, 42) */ + (43, 80), /* 'select' => LRAction::Reduce(Break, 42) */ + (44, 80), /* '{' => LRAction::Reduce(Break, 42) */ + (45, 80), /* '}' => LRAction::Reduce(Break, 42) */ + (47, 80), /* '~' => LRAction::Reduce(Break, 42) */ + (48, 80), /* '@' => LRAction::Reduce(Break, 42) */ + (49, 80), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Break, 42) */ + (50, 80), /* '[' => LRAction::Reduce(Break, 42) */ + (52, 80), /* '"(\\.|[^"])*"' => LRAction::Reduce(Break, 42) */ + (53, 80), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Break, 42) */ + (54, 80), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Break, 42) */ + (55, 80), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Break, 42) */ + (56, 80), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Break, 42) */ + (57, 80), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Break, 42) */ + (58, 80), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Break, 42) */ + (59, 80), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Break, 42) */ + ], + gotos: &[], + }, + // State 58 + LR1State { + actions: &[ + (5, 195), /* '\r?\n|\r' => LRAction::Reduce(ScopeContentOpt, 37) */ + (6, 195), /* '#' => LRAction::Reduce(ScopeContentOpt, 37) */ + (9, 195), /* '(' => LRAction::Reduce(ScopeContentOpt, 37) */ + (18, 195), /* 'return' => LRAction::Reduce(ScopeContentOpt, 37) */ + (19, 195), /* 'let' => LRAction::Reduce(ScopeContentOpt, 37) */ + (31, 195), /* '-' => LRAction::Reduce(ScopeContentOpt, 37) */ + (36, 195), /* 'wait' => LRAction::Reduce(ScopeContentOpt, 37) */ + (37, 195), /* 'call' => LRAction::Reduce(ScopeContentOpt, 37) */ + (38, 195), /* '&' => LRAction::Reduce(ScopeContentOpt, 37) */ + (39, 195), /* '$' => LRAction::Reduce(ScopeContentOpt, 37) */ + (41, 195), /* 'if' => LRAction::Reduce(ScopeContentOpt, 37) */ + (43, 195), /* 'select' => LRAction::Reduce(ScopeContentOpt, 37) */ + (44, 195), /* '{' => LRAction::Reduce(ScopeContentOpt, 37) */ + (45, 195), /* '}' => LRAction::Reduce(ScopeContentOpt, 37) */ + (47, 195), /* '~' => LRAction::Reduce(ScopeContentOpt, 37) */ + (48, 195), /* '@' => LRAction::Reduce(ScopeContentOpt, 37) */ + (49, 195), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ScopeContentOpt, 37) */ + (50, 195), /* '[' => LRAction::Reduce(ScopeContentOpt, 37) */ + (52, 195), /* '"(\\.|[^"])*"' => LRAction::Reduce(ScopeContentOpt, 37) */ + (53, 195), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ScopeContentOpt, 37) */ + (54, 195), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ScopeContentOpt, 37) */ + (55, 195), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ScopeContentOpt, 37) */ + (56, 195), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ScopeContentOpt, 37) */ + (57, 195), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ScopeContentOpt, 37) */ + (58, 195), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ScopeContentOpt, 37) */ + (59, 195), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ScopeContentOpt, 37) */ + ], + gotos: &[], + }, + // State 59 + LR1State { + actions: &[(45, 19) /* '}' => LRAction::Shift(67) */], + gotos: &[], + }, + // State 60 + LR1State { + actions: &[ + (5, 3), /* '\r?\n|\r' => LRAction::Shift(12) */ + (45, 202), /* '}' => LRAction::Reduce(ScopeOpt, 31) */ + ], + gotos: &[ + (34, 68), /* EndOfLine => 68 */ + (81, 69), /* ScopeOpt => 69 */ + ], + }, + // State 61 + LR1State { + actions: &[ + (5, 198), /* '\r?\n|\r' => LRAction::Reduce(ScopeContentOpt0, 36) */ + (6, 198), /* '#' => LRAction::Reduce(ScopeContentOpt0, 36) */ + (9, 158), /* '(' => LRAction::Reduce(LogicalOrExprList, 55) */ + (18, 20), /* 'return' => LRAction::Shift(70) */ + (19, 21), /* 'let' => LRAction::Shift(71) */ + (31, 158), /* '-' => LRAction::Reduce(LogicalOrExprList, 55) */ + (36, 158), /* 'wait' => LRAction::Reduce(LogicalOrExprList, 55) */ + (37, 158), /* 'call' => LRAction::Reduce(LogicalOrExprList, 55) */ + (38, 158), /* '&' => LRAction::Reduce(LogicalOrExprList, 55) */ + (39, 158), /* '$' => LRAction::Reduce(LogicalOrExprList, 55) */ + (41, 158), /* 'if' => LRAction::Reduce(LogicalOrExprList, 55) */ + (43, 158), /* 'select' => LRAction::Reduce(LogicalOrExprList, 55) */ + (44, 14), /* '{' => LRAction::Shift(48) */ + (45, 198), /* '}' => LRAction::Reduce(ScopeContentOpt0, 36) */ + (47, 158), /* '~' => LRAction::Reduce(LogicalOrExprList, 55) */ + (48, 158), /* '@' => LRAction::Reduce(LogicalOrExprList, 55) */ + (49, 158), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalOrExprList, 55) */ + (50, 158), /* '[' => LRAction::Reduce(LogicalOrExprList, 55) */ + (52, 158), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (53, 158), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (54, 158), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (55, 158), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (56, 158), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (57, 158), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (58, 158), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (59, 158), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalOrExprList, 55) */ + ], + gotos: &[ + (9, 72), /* Block => 72 */ + (35, 73), /* Expr => 73 */ + (50, 74), /* LetStmt => 74 */ + (54, 44), /* LogicalOrExpr => 44 */ + (55, 45), /* LogicalOrExprList => 45 */ + (73, 75), /* ReturnStmt => 75 */ + (77, 76), /* ScopeContentKind => 76 */ + (79, 77), /* ScopeContentOpt0 => 77 */ + (88, 46), /* SetExpr => 46 */ + (90, 78), /* Statement => 78 */ + (91, 79), /* StatementKind => 79 */ + ], + }, + // State 62 + LR1State { + actions: &[ + (10, 212), /* ')' => LRAction::Reduce(SetExprOpt, 51) */ + (12, 212), /* ',' => LRAction::Reduce(SetExprOpt, 51) */ + (17, 212), /* ';' => LRAction::Reduce(SetExprOpt, 51) */ + (44, 212), /* '{' => LRAction::Reduce(SetExprOpt, 51) */ + (46, 212), /* '=>' => LRAction::Reduce(SetExprOpt, 51) */ + (51, 212), /* ']' => LRAction::Reduce(SetExprOpt, 51) */ + ], + gotos: &[], + }, + // State 63 + LR1State { + actions: &[ + (9, 157), /* '(' => LRAction::Reduce(LogicalOrExprList, 54) */ + (31, 157), /* '-' => LRAction::Reduce(LogicalOrExprList, 54) */ + (36, 157), /* 'wait' => LRAction::Reduce(LogicalOrExprList, 54) */ + (37, 157), /* 'call' => LRAction::Reduce(LogicalOrExprList, 54) */ + (38, 157), /* '&' => LRAction::Reduce(LogicalOrExprList, 54) */ + (39, 157), /* '$' => LRAction::Reduce(LogicalOrExprList, 54) */ + (41, 157), /* 'if' => LRAction::Reduce(LogicalOrExprList, 54) */ + (43, 157), /* 'select' => LRAction::Reduce(LogicalOrExprList, 54) */ + (47, 157), /* '~' => LRAction::Reduce(LogicalOrExprList, 54) */ + (48, 157), /* '@' => LRAction::Reduce(LogicalOrExprList, 54) */ + (49, 157), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalOrExprList, 54) */ + (50, 157), /* '[' => LRAction::Reduce(LogicalOrExprList, 54) */ + (52, 157), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 54) */ + (53, 157), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 54) */ + (54, 157), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalOrExprList, 54) */ + (55, 157), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 54) */ + (56, 157), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 54) */ + (57, 157), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 54) */ + (58, 157), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 54) */ + (59, 157), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalOrExprList, 54) */ + ], + gotos: &[], + }, + // State 64 + LR1State { + actions: &[ + (10, 107), /* ')' => LRAction::Reduce(CompareExprList, 61) */ + (12, 107), /* ',' => LRAction::Reduce(CompareExprList, 61) */ + (17, 107), /* ';' => LRAction::Reduce(CompareExprList, 61) */ + (20, 107), /* ':=' => LRAction::Reduce(CompareExprList, 61) */ + (21, 107), /* '||' => LRAction::Reduce(CompareExprList, 61) */ + (22, 107), /* '&&' => LRAction::Reduce(CompareExprList, 61) */ + (23, 107), /* '>=' => LRAction::Reduce(CompareExprList, 61) */ + (24, 107), /* '<=' => LRAction::Reduce(CompareExprList, 61) */ + (25, 107), /* '>' => LRAction::Reduce(CompareExprList, 61) */ + (26, 107), /* '<' => LRAction::Reduce(CompareExprList, 61) */ + (27, 107), /* '!=' => LRAction::Reduce(CompareExprList, 61) */ + (28, 107), /* '/=' => LRAction::Reduce(CompareExprList, 61) */ + (29, 107), /* '==' => LRAction::Reduce(CompareExprList, 61) */ + (44, 107), /* '{' => LRAction::Reduce(CompareExprList, 61) */ + (46, 107), /* '=>' => LRAction::Reduce(CompareExprList, 61) */ + (51, 107), /* ']' => LRAction::Reduce(CompareExprList, 61) */ + ], + gotos: &[(26, 80) /* CompareExprList => 80 */], + }, + // State 65 + LR1State { + actions: &[ + (9, 128), /* '(' => LRAction::Reduce(FactorExprList, 76) */ + (31, 128), /* '-' => LRAction::Reduce(FactorExprList, 76) */ + (36, 128), /* 'wait' => LRAction::Reduce(FactorExprList, 76) */ + (37, 128), /* 'call' => LRAction::Reduce(FactorExprList, 76) */ + (38, 128), /* '&' => LRAction::Reduce(FactorExprList, 76) */ + (39, 128), /* '$' => LRAction::Reduce(FactorExprList, 76) */ + (41, 128), /* 'if' => LRAction::Reduce(FactorExprList, 76) */ + (43, 128), /* 'select' => LRAction::Reduce(FactorExprList, 76) */ + (47, 128), /* '~' => LRAction::Reduce(FactorExprList, 76) */ + (48, 128), /* '@' => LRAction::Reduce(FactorExprList, 76) */ + (49, 128), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(FactorExprList, 76) */ + (50, 128), /* '[' => LRAction::Reduce(FactorExprList, 76) */ + (52, 128), /* '"(\\.|[^"])*"' => LRAction::Reduce(FactorExprList, 76) */ + (53, 128), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(FactorExprList, 76) */ + (54, 128), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(FactorExprList, 76) */ + (55, 128), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorExprList, 76) */ + (56, 128), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorExprList, 76) */ + (57, 128), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorExprList, 76) */ + (58, 128), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorExprList, 76) */ + (59, 128), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(FactorExprList, 76) */ + ], + gotos: &[ + (36, 81), /* FactorExpr => 81 */ + (37, 82), /* FactorExprList => 82 */ + ], + }, + // State 66 + LR1State { + actions: &[ + (10, 153), /* ')' => LRAction::Reduce(LogicalAndExpr, 56) */ + (12, 153), /* ',' => LRAction::Reduce(LogicalAndExpr, 56) */ + (17, 153), /* ';' => LRAction::Reduce(LogicalAndExpr, 56) */ + (20, 153), /* ':=' => LRAction::Reduce(LogicalAndExpr, 56) */ + (21, 153), /* '||' => LRAction::Reduce(LogicalAndExpr, 56) */ + (22, 22), /* '&&' => LRAction::Shift(83) */ + (44, 153), /* '{' => LRAction::Reduce(LogicalAndExpr, 56) */ + (46, 153), /* '=>' => LRAction::Reduce(LogicalAndExpr, 56) */ + (51, 153), /* ']' => LRAction::Reduce(LogicalAndExpr, 56) */ + ], + gotos: &[], + }, + // State 67 + LR1State { + actions: &[ + (0, 79), /* '<$>' => LRAction::Reduce(Block, 154) */ + (5, 79), /* '\r?\n|\r' => LRAction::Reduce(Block, 154) */ + (6, 79), /* '#' => LRAction::Reduce(Block, 154) */ + (9, 79), /* '(' => LRAction::Reduce(Block, 154) */ + (10, 79), /* ')' => LRAction::Reduce(Block, 154) */ + (12, 79), /* ',' => LRAction::Reduce(Block, 154) */ + (17, 79), /* ';' => LRAction::Reduce(Block, 154) */ + (20, 79), /* ':=' => LRAction::Reduce(Block, 154) */ + (21, 79), /* '||' => LRAction::Reduce(Block, 154) */ + (22, 79), /* '&&' => LRAction::Reduce(Block, 154) */ + (23, 79), /* '>=' => LRAction::Reduce(Block, 154) */ + (24, 79), /* '<=' => LRAction::Reduce(Block, 154) */ + (25, 79), /* '>' => LRAction::Reduce(Block, 154) */ + (26, 79), /* '<' => LRAction::Reduce(Block, 154) */ + (27, 79), /* '!=' => LRAction::Reduce(Block, 154) */ + (28, 79), /* '/=' => LRAction::Reduce(Block, 154) */ + (29, 79), /* '==' => LRAction::Reduce(Block, 154) */ + (30, 79), /* '+' => LRAction::Reduce(Block, 154) */ + (31, 79), /* '-' => LRAction::Reduce(Block, 154) */ + (32, 79), /* '*' => LRAction::Reduce(Block, 154) */ + (33, 79), /* '/' => LRAction::Reduce(Block, 154) */ + (34, 79), /* '%' => LRAction::Reduce(Block, 154) */ + (35, 79), /* 'as' => LRAction::Reduce(Block, 154) */ + (38, 79), /* '&' => LRAction::Reduce(Block, 154) */ + (39, 79), /* '$' => LRAction::Reduce(Block, 154) */ + (41, 79), /* 'if' => LRAction::Reduce(Block, 154) */ + (42, 79), /* 'else' => LRAction::Reduce(Block, 154) */ + (43, 79), /* 'select' => LRAction::Reduce(Block, 154) */ + (44, 79), /* '{' => LRAction::Reduce(Block, 154) */ + (45, 79), /* '}' => LRAction::Reduce(Block, 154) */ + (46, 79), /* '=>' => LRAction::Reduce(Block, 154) */ + (47, 79), /* '~' => LRAction::Reduce(Block, 154) */ + (48, 79), /* '@' => LRAction::Reduce(Block, 154) */ + (49, 79), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Block, 154) */ + (50, 79), /* '[' => LRAction::Reduce(Block, 154) */ + (51, 79), /* ']' => LRAction::Reduce(Block, 154) */ + (52, 79), /* '"(\\.|[^"])*"' => LRAction::Reduce(Block, 154) */ + (53, 79), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Block, 154) */ + (54, 79), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Block, 154) */ + (55, 79), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Block, 154) */ + (56, 79), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Block, 154) */ + (57, 79), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Block, 154) */ + (58, 79), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Block, 154) */ + (59, 79), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Block, 154) */ + ], + gotos: &[], + }, + // State 68 + LR1State { + actions: &[ + (5, 196), /* '\r?\n|\r' => LRAction::Reduce(ScopeContentOpt, 38) */ + (6, 196), /* '#' => LRAction::Reduce(ScopeContentOpt, 38) */ + (9, 196), /* '(' => LRAction::Reduce(ScopeContentOpt, 38) */ + (16, 17), /* '.' => LRAction::Shift(57) */ + (18, 196), /* 'return' => LRAction::Reduce(ScopeContentOpt, 38) */ + (19, 196), /* 'let' => LRAction::Reduce(ScopeContentOpt, 38) */ + (31, 196), /* '-' => LRAction::Reduce(ScopeContentOpt, 38) */ + (36, 196), /* 'wait' => LRAction::Reduce(ScopeContentOpt, 38) */ + (37, 196), /* 'call' => LRAction::Reduce(ScopeContentOpt, 38) */ + (38, 196), /* '&' => LRAction::Reduce(ScopeContentOpt, 38) */ + (39, 196), /* '$' => LRAction::Reduce(ScopeContentOpt, 38) */ + (41, 196), /* 'if' => LRAction::Reduce(ScopeContentOpt, 38) */ + (43, 196), /* 'select' => LRAction::Reduce(ScopeContentOpt, 38) */ + (44, 196), /* '{' => LRAction::Reduce(ScopeContentOpt, 38) */ + (45, 196), /* '}' => LRAction::Reduce(ScopeContentOpt, 38) */ + (47, 196), /* '~' => LRAction::Reduce(ScopeContentOpt, 38) */ + (48, 196), /* '@' => LRAction::Reduce(ScopeContentOpt, 38) */ + (49, 196), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ScopeContentOpt, 38) */ + (50, 196), /* '[' => LRAction::Reduce(ScopeContentOpt, 38) */ + (52, 196), /* '"(\\.|[^"])*"' => LRAction::Reduce(ScopeContentOpt, 38) */ + (53, 196), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ScopeContentOpt, 38) */ + (54, 196), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ScopeContentOpt, 38) */ + (55, 196), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ScopeContentOpt, 38) */ + (56, 196), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ScopeContentOpt, 38) */ + (57, 196), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ScopeContentOpt, 38) */ + (58, 196), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ScopeContentOpt, 38) */ + (59, 196), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ScopeContentOpt, 38) */ + ], + gotos: &[ + (10, 58), /* Break => 58 */ + (75, 84), /* Scope => 84 */ + (76, 60), /* ScopeContent => 60 */ + (78, 61), /* ScopeContentOpt => 61 */ + ], + }, + // State 69 + LR1State { + actions: &[(45, 191) /* '}' => LRAction::Reduce(Scope, 29) */], + gotos: &[], + }, + // State 70 + LR1State { + actions: &[(17, 189) /* ';' => LRAction::Reduce(ReturnStmt, 47) */], + gotos: &[], + }, + // State 71 + LR1State { + actions: &[ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[(45, 85) /* Ident => 85 */], + }, + // State 72 + LR1State { + actions: &[ + (5, 194), /* '\r?\n|\r' => LRAction::Reduce(ScopeContentKind, 40) */ + (6, 194), /* '#' => LRAction::Reduce(ScopeContentKind, 40) */ + (45, 194), /* '}' => LRAction::Reduce(ScopeContentKind, 40) */ + ], + gotos: &[], + }, + // State 73 + LR1State { + actions: &[ + (17, 216), /* ';' => LRAction::Reduce(StatementKind, 45) */ + ], + gotos: &[], + }, + // State 74 + LR1State { + actions: &[ + (17, 215), /* ';' => LRAction::Reduce(StatementKind, 44) */ + ], + gotos: &[], + }, + // State 75 + LR1State { + actions: &[ + (17, 217), /* ';' => LRAction::Reduce(StatementKind, 46) */ + ], + gotos: &[], + }, + // State 76 + LR1State { + actions: &[ + (5, 197), /* '\r?\n|\r' => LRAction::Reduce(ScopeContentOpt0, 35) */ + (6, 197), /* '#' => LRAction::Reduce(ScopeContentOpt0, 35) */ + (45, 197), /* '}' => LRAction::Reduce(ScopeContentOpt0, 35) */ + ], + gotos: &[], + }, + // State 77 + LR1State { + actions: &[ + (5, 200), /* '\r?\n|\r' => LRAction::Reduce(ScopeContentOpt1, 34) */ + (6, 4), /* '#' => LRAction::Shift(14) */ + (45, 200), /* '}' => LRAction::Reduce(ScopeContentOpt1, 34) */ + ], + gotos: &[ + (22, 86), /* Comment => 86 */ + (42, 17), /* Hash => 17 */ + (80, 87), /* ScopeContentOpt1 => 87 */ + ], + }, + // State 78 + LR1State { + actions: &[ + (5, 193), /* '\r?\n|\r' => LRAction::Reduce(ScopeContentKind, 39) */ + (6, 193), /* '#' => LRAction::Reduce(ScopeContentKind, 39) */ + (45, 193), /* '}' => LRAction::Reduce(ScopeContentKind, 39) */ + ], + gotos: &[], + }, + // State 79 + LR1State { + actions: &[(17, 15) /* ';' => LRAction::Shift(51) */], + gotos: &[(87, 88) /* Semi => 88 */], + }, + // State 80 + LR1State { + actions: &[ + (10, 105), /* ')' => LRAction::Reduce(CompareExpr, 59) */ + (12, 105), /* ',' => LRAction::Reduce(CompareExpr, 59) */ + (17, 105), /* ';' => LRAction::Reduce(CompareExpr, 59) */ + (20, 105), /* ':=' => LRAction::Reduce(CompareExpr, 59) */ + (21, 105), /* '||' => LRAction::Reduce(CompareExpr, 59) */ + (22, 105), /* '&&' => LRAction::Reduce(CompareExpr, 59) */ + (23, 23), /* '>=' => LRAction::Shift(89) */ + (24, 24), /* '<=' => LRAction::Shift(90) */ + (25, 25), /* '>' => LRAction::Shift(91) */ + (26, 26), /* '<' => LRAction::Shift(92) */ + (27, 27), /* '!=' => LRAction::Shift(93) */ + (28, 28), /* '/=' => LRAction::Shift(94) */ + (29, 29), /* '==' => LRAction::Shift(95) */ + (44, 105), /* '{' => LRAction::Reduce(CompareExpr, 59) */ + (46, 105), /* '=>' => LRAction::Reduce(CompareExpr, 59) */ + (51, 105), /* ']' => LRAction::Reduce(CompareExpr, 59) */ + ], + gotos: &[(27, 96) /* CompareOp => 96 */], + }, + // State 81 + LR1State { + actions: &[ + (10, 68), /* ')' => LRAction::Reduce(ArithmeticExpr, 69) */ + (12, 68), /* ',' => LRAction::Reduce(ArithmeticExpr, 69) */ + (17, 68), /* ';' => LRAction::Reduce(ArithmeticExpr, 69) */ + (20, 68), /* ':=' => LRAction::Reduce(ArithmeticExpr, 69) */ + (21, 68), /* '||' => LRAction::Reduce(ArithmeticExpr, 69) */ + (22, 68), /* '&&' => LRAction::Reduce(ArithmeticExpr, 69) */ + (23, 68), /* '>=' => LRAction::Reduce(ArithmeticExpr, 69) */ + (24, 68), /* '<=' => LRAction::Reduce(ArithmeticExpr, 69) */ + (25, 68), /* '>' => LRAction::Reduce(ArithmeticExpr, 69) */ + (26, 68), /* '<' => LRAction::Reduce(ArithmeticExpr, 69) */ + (27, 68), /* '!=' => LRAction::Reduce(ArithmeticExpr, 69) */ + (28, 68), /* '/=' => LRAction::Reduce(ArithmeticExpr, 69) */ + (29, 68), /* '==' => LRAction::Reduce(ArithmeticExpr, 69) */ + (30, 30), /* '+' => LRAction::Shift(97) */ + (31, 31), /* '-' => LRAction::Shift(98) */ + (44, 68), /* '{' => LRAction::Reduce(ArithmeticExpr, 69) */ + (46, 68), /* '=>' => LRAction::Reduce(ArithmeticExpr, 69) */ + (51, 68), /* ']' => LRAction::Reduce(ArithmeticExpr, 69) */ + ], + gotos: &[(4, 99) /* ArithmeticOp => 99 */], + }, + // State 82 + LR1State { + actions: &[ + (9, 184), /* '(' => LRAction::Reduce(PrefixExprList, 86) */ + (31, 32), /* '-' => LRAction::Shift(100) */ + (36, 33), /* 'wait' => LRAction::Shift(101) */ + (37, 34), /* 'call' => LRAction::Shift(102) */ + (38, 184), /* '&' => LRAction::Reduce(PrefixExprList, 86) */ + (39, 184), /* '$' => LRAction::Reduce(PrefixExprList, 86) */ + (41, 184), /* 'if' => LRAction::Reduce(PrefixExprList, 86) */ + (43, 184), /* 'select' => LRAction::Reduce(PrefixExprList, 86) */ + (47, 184), /* '~' => LRAction::Reduce(PrefixExprList, 86) */ + (48, 184), /* '@' => LRAction::Reduce(PrefixExprList, 86) */ + (49, 184), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(PrefixExprList, 86) */ + (50, 184), /* '[' => LRAction::Reduce(PrefixExprList, 86) */ + (52, 184), /* '"(\\.|[^"])*"' => LRAction::Reduce(PrefixExprList, 86) */ + (53, 184), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(PrefixExprList, 86) */ + (54, 184), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(PrefixExprList, 86) */ + (55, 184), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(PrefixExprList, 86) */ + (56, 184), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(PrefixExprList, 86) */ + (57, 184), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(PrefixExprList, 86) */ + (58, 184), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(PrefixExprList, 86) */ + (59, 184), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(PrefixExprList, 86) */ + ], + gotos: &[ + (14, 103), /* CastExpr => 103 */ + (68, 104), /* PrefixExpr => 104 */ + (69, 105), /* PrefixExprList => 105 */ + ], + }, + // State 83 + LR1State { + actions: &[ + (9, 154), /* '(' => LRAction::Reduce(LogicalAndExprList, 57) */ + (31, 154), /* '-' => LRAction::Reduce(LogicalAndExprList, 57) */ + (36, 154), /* 'wait' => LRAction::Reduce(LogicalAndExprList, 57) */ + (37, 154), /* 'call' => LRAction::Reduce(LogicalAndExprList, 57) */ + (38, 154), /* '&' => LRAction::Reduce(LogicalAndExprList, 57) */ + (39, 154), /* '$' => LRAction::Reduce(LogicalAndExprList, 57) */ + (41, 154), /* 'if' => LRAction::Reduce(LogicalAndExprList, 57) */ + (43, 154), /* 'select' => LRAction::Reduce(LogicalAndExprList, 57) */ + (47, 154), /* '~' => LRAction::Reduce(LogicalAndExprList, 57) */ + (48, 154), /* '@' => LRAction::Reduce(LogicalAndExprList, 57) */ + (49, 154), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalAndExprList, 57) */ + (50, 154), /* '[' => LRAction::Reduce(LogicalAndExprList, 57) */ + (52, 154), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalAndExprList, 57) */ + (53, 154), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalAndExprList, 57) */ + (54, 154), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalAndExprList, 57) */ + (55, 154), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalAndExprList, 57) */ + (56, 154), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalAndExprList, 57) */ + (57, 154), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalAndExprList, 57) */ + (58, 154), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalAndExprList, 57) */ + (59, 154), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalAndExprList, 57) */ + ], + gotos: &[], + }, + // State 84 + LR1State { + actions: &[(45, 201) /* '}' => LRAction::Reduce(ScopeOpt, 30) */], + gotos: &[], + }, + // State 85 + LR1State { + actions: &[(15, 35) /* '=' => LRAction::Shift(106) */], + gotos: &[], + }, + // State 86 + LR1State { + actions: &[ + (5, 199), /* '\r?\n|\r' => LRAction::Reduce(ScopeContentOpt1, 33) */ + (45, 199), /* '}' => LRAction::Reduce(ScopeContentOpt1, 33) */ + ], + gotos: &[], + }, + // State 87 + LR1State { + actions: &[ + (5, 192), /* '\r?\n|\r' => LRAction::Reduce(ScopeContent, 32) */ + (45, 192), /* '}' => LRAction::Reduce(ScopeContent, 32) */ + ], + gotos: &[], + }, + // State 88 + LR1State { + actions: &[ + (5, 214), /* '\r?\n|\r' => LRAction::Reduce(Statement, 41) */ + (6, 214), /* '#' => LRAction::Reduce(Statement, 41) */ + (45, 214), /* '}' => LRAction::Reduce(Statement, 41) */ + ], + gotos: &[], + }, + // State 89 + LR1State { + actions: &[ + (9, 108), /* '(' => LRAction::Reduce(CompareOp, 62) */ + (31, 108), /* '-' => LRAction::Reduce(CompareOp, 62) */ + (36, 108), /* 'wait' => LRAction::Reduce(CompareOp, 62) */ + (37, 108), /* 'call' => LRAction::Reduce(CompareOp, 62) */ + (38, 108), /* '&' => LRAction::Reduce(CompareOp, 62) */ + (39, 108), /* '$' => LRAction::Reduce(CompareOp, 62) */ + (41, 108), /* 'if' => LRAction::Reduce(CompareOp, 62) */ + (43, 108), /* 'select' => LRAction::Reduce(CompareOp, 62) */ + (47, 108), /* '~' => LRAction::Reduce(CompareOp, 62) */ + (48, 108), /* '@' => LRAction::Reduce(CompareOp, 62) */ + (49, 108), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(CompareOp, 62) */ + (50, 108), /* '[' => LRAction::Reduce(CompareOp, 62) */ + (52, 108), /* '"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 62) */ + (53, 108), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 62) */ + (54, 108), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(CompareOp, 62) */ + (55, 108), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 62) */ + (56, 108), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 62) */ + (57, 108), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 62) */ + (58, 108), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 62) */ + (59, 108), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(CompareOp, 62) */ + ], + gotos: &[], + }, + // State 90 + LR1State { + actions: &[ + (9, 109), /* '(' => LRAction::Reduce(CompareOp, 63) */ + (31, 109), /* '-' => LRAction::Reduce(CompareOp, 63) */ + (36, 109), /* 'wait' => LRAction::Reduce(CompareOp, 63) */ + (37, 109), /* 'call' => LRAction::Reduce(CompareOp, 63) */ + (38, 109), /* '&' => LRAction::Reduce(CompareOp, 63) */ + (39, 109), /* '$' => LRAction::Reduce(CompareOp, 63) */ + (41, 109), /* 'if' => LRAction::Reduce(CompareOp, 63) */ + (43, 109), /* 'select' => LRAction::Reduce(CompareOp, 63) */ + (47, 109), /* '~' => LRAction::Reduce(CompareOp, 63) */ + (48, 109), /* '@' => LRAction::Reduce(CompareOp, 63) */ + (49, 109), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(CompareOp, 63) */ + (50, 109), /* '[' => LRAction::Reduce(CompareOp, 63) */ + (52, 109), /* '"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 63) */ + (53, 109), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 63) */ + (54, 109), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(CompareOp, 63) */ + (55, 109), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 63) */ + (56, 109), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 63) */ + (57, 109), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 63) */ + (58, 109), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 63) */ + (59, 109), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(CompareOp, 63) */ + ], + gotos: &[], + }, + // State 91 + LR1State { + actions: &[ + (9, 110), /* '(' => LRAction::Reduce(CompareOp, 64) */ + (31, 110), /* '-' => LRAction::Reduce(CompareOp, 64) */ + (36, 110), /* 'wait' => LRAction::Reduce(CompareOp, 64) */ + (37, 110), /* 'call' => LRAction::Reduce(CompareOp, 64) */ + (38, 110), /* '&' => LRAction::Reduce(CompareOp, 64) */ + (39, 110), /* '$' => LRAction::Reduce(CompareOp, 64) */ + (41, 110), /* 'if' => LRAction::Reduce(CompareOp, 64) */ + (43, 110), /* 'select' => LRAction::Reduce(CompareOp, 64) */ + (47, 110), /* '~' => LRAction::Reduce(CompareOp, 64) */ + (48, 110), /* '@' => LRAction::Reduce(CompareOp, 64) */ + (49, 110), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(CompareOp, 64) */ + (50, 110), /* '[' => LRAction::Reduce(CompareOp, 64) */ + (52, 110), /* '"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 64) */ + (53, 110), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 64) */ + (54, 110), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(CompareOp, 64) */ + (55, 110), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 64) */ + (56, 110), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 64) */ + (57, 110), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 64) */ + (58, 110), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 64) */ + (59, 110), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(CompareOp, 64) */ + ], + gotos: &[], + }, + // State 92 + LR1State { + actions: &[ + (9, 111), /* '(' => LRAction::Reduce(CompareOp, 65) */ + (31, 111), /* '-' => LRAction::Reduce(CompareOp, 65) */ + (36, 111), /* 'wait' => LRAction::Reduce(CompareOp, 65) */ + (37, 111), /* 'call' => LRAction::Reduce(CompareOp, 65) */ + (38, 111), /* '&' => LRAction::Reduce(CompareOp, 65) */ + (39, 111), /* '$' => LRAction::Reduce(CompareOp, 65) */ + (41, 111), /* 'if' => LRAction::Reduce(CompareOp, 65) */ + (43, 111), /* 'select' => LRAction::Reduce(CompareOp, 65) */ + (47, 111), /* '~' => LRAction::Reduce(CompareOp, 65) */ + (48, 111), /* '@' => LRAction::Reduce(CompareOp, 65) */ + (49, 111), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(CompareOp, 65) */ + (50, 111), /* '[' => LRAction::Reduce(CompareOp, 65) */ + (52, 111), /* '"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 65) */ + (53, 111), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 65) */ + (54, 111), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(CompareOp, 65) */ + (55, 111), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 65) */ + (56, 111), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 65) */ + (57, 111), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 65) */ + (58, 111), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 65) */ + (59, 111), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(CompareOp, 65) */ + ], + gotos: &[], + }, + // State 93 + LR1State { + actions: &[ + (9, 112), /* '(' => LRAction::Reduce(CompareOp, 66) */ + (31, 112), /* '-' => LRAction::Reduce(CompareOp, 66) */ + (36, 112), /* 'wait' => LRAction::Reduce(CompareOp, 66) */ + (37, 112), /* 'call' => LRAction::Reduce(CompareOp, 66) */ + (38, 112), /* '&' => LRAction::Reduce(CompareOp, 66) */ + (39, 112), /* '$' => LRAction::Reduce(CompareOp, 66) */ + (41, 112), /* 'if' => LRAction::Reduce(CompareOp, 66) */ + (43, 112), /* 'select' => LRAction::Reduce(CompareOp, 66) */ + (47, 112), /* '~' => LRAction::Reduce(CompareOp, 66) */ + (48, 112), /* '@' => LRAction::Reduce(CompareOp, 66) */ + (49, 112), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(CompareOp, 66) */ + (50, 112), /* '[' => LRAction::Reduce(CompareOp, 66) */ + (52, 112), /* '"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 66) */ + (53, 112), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 66) */ + (54, 112), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(CompareOp, 66) */ + (55, 112), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 66) */ + (56, 112), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 66) */ + (57, 112), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 66) */ + (58, 112), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 66) */ + (59, 112), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(CompareOp, 66) */ + ], + gotos: &[], + }, + // State 94 + LR1State { + actions: &[ + (9, 113), /* '(' => LRAction::Reduce(CompareOp, 67) */ + (31, 113), /* '-' => LRAction::Reduce(CompareOp, 67) */ + (36, 113), /* 'wait' => LRAction::Reduce(CompareOp, 67) */ + (37, 113), /* 'call' => LRAction::Reduce(CompareOp, 67) */ + (38, 113), /* '&' => LRAction::Reduce(CompareOp, 67) */ + (39, 113), /* '$' => LRAction::Reduce(CompareOp, 67) */ + (41, 113), /* 'if' => LRAction::Reduce(CompareOp, 67) */ + (43, 113), /* 'select' => LRAction::Reduce(CompareOp, 67) */ + (47, 113), /* '~' => LRAction::Reduce(CompareOp, 67) */ + (48, 113), /* '@' => LRAction::Reduce(CompareOp, 67) */ + (49, 113), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(CompareOp, 67) */ + (50, 113), /* '[' => LRAction::Reduce(CompareOp, 67) */ + (52, 113), /* '"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 67) */ + (53, 113), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 67) */ + (54, 113), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(CompareOp, 67) */ + (55, 113), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 67) */ + (56, 113), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 67) */ + (57, 113), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 67) */ + (58, 113), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 67) */ + (59, 113), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(CompareOp, 67) */ + ], + gotos: &[], + }, + // State 95 + LR1State { + actions: &[ + (9, 114), /* '(' => LRAction::Reduce(CompareOp, 68) */ + (31, 114), /* '-' => LRAction::Reduce(CompareOp, 68) */ + (36, 114), /* 'wait' => LRAction::Reduce(CompareOp, 68) */ + (37, 114), /* 'call' => LRAction::Reduce(CompareOp, 68) */ + (38, 114), /* '&' => LRAction::Reduce(CompareOp, 68) */ + (39, 114), /* '$' => LRAction::Reduce(CompareOp, 68) */ + (41, 114), /* 'if' => LRAction::Reduce(CompareOp, 68) */ + (43, 114), /* 'select' => LRAction::Reduce(CompareOp, 68) */ + (47, 114), /* '~' => LRAction::Reduce(CompareOp, 68) */ + (48, 114), /* '@' => LRAction::Reduce(CompareOp, 68) */ + (49, 114), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(CompareOp, 68) */ + (50, 114), /* '[' => LRAction::Reduce(CompareOp, 68) */ + (52, 114), /* '"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 68) */ + (53, 114), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(CompareOp, 68) */ + (54, 114), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(CompareOp, 68) */ + (55, 114), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 68) */ + (56, 114), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 68) */ + (57, 114), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 68) */ + (58, 114), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(CompareOp, 68) */ + (59, 114), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(CompareOp, 68) */ + ], + gotos: &[], + }, + // State 96 + LR1State { + actions: &[ + (9, 70), /* '(' => LRAction::Reduce(ArithmeticExprList, 71) */ + (31, 70), /* '-' => LRAction::Reduce(ArithmeticExprList, 71) */ + (36, 70), /* 'wait' => LRAction::Reduce(ArithmeticExprList, 71) */ + (37, 70), /* 'call' => LRAction::Reduce(ArithmeticExprList, 71) */ + (38, 70), /* '&' => LRAction::Reduce(ArithmeticExprList, 71) */ + (39, 70), /* '$' => LRAction::Reduce(ArithmeticExprList, 71) */ + (41, 70), /* 'if' => LRAction::Reduce(ArithmeticExprList, 71) */ + (43, 70), /* 'select' => LRAction::Reduce(ArithmeticExprList, 71) */ + (47, 70), /* '~' => LRAction::Reduce(ArithmeticExprList, 71) */ + (48, 70), /* '@' => LRAction::Reduce(ArithmeticExprList, 71) */ + (49, 70), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ArithmeticExprList, 71) */ + (50, 70), /* '[' => LRAction::Reduce(ArithmeticExprList, 71) */ + (52, 70), /* '"(\\.|[^"])*"' => LRAction::Reduce(ArithmeticExprList, 71) */ + (53, 70), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ArithmeticExprList, 71) */ + (54, 70), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ArithmeticExprList, 71) */ + (55, 70), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticExprList, 71) */ + (56, 70), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticExprList, 71) */ + (57, 70), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticExprList, 71) */ + (58, 70), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticExprList, 71) */ + (59, 70), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ArithmeticExprList, 71) */ + ], + gotos: &[ + (2, 107), /* ArithmeticExpr => 107 */ + (3, 65), /* ArithmeticExprList => 65 */ + ], + }, + // State 97 + LR1State { + actions: &[ + (9, 71), /* '(' => LRAction::Reduce(ArithmeticOp, 72) */ + (31, 71), /* '-' => LRAction::Reduce(ArithmeticOp, 72) */ + (36, 71), /* 'wait' => LRAction::Reduce(ArithmeticOp, 72) */ + (37, 71), /* 'call' => LRAction::Reduce(ArithmeticOp, 72) */ + (38, 71), /* '&' => LRAction::Reduce(ArithmeticOp, 72) */ + (39, 71), /* '$' => LRAction::Reduce(ArithmeticOp, 72) */ + (41, 71), /* 'if' => LRAction::Reduce(ArithmeticOp, 72) */ + (43, 71), /* 'select' => LRAction::Reduce(ArithmeticOp, 72) */ + (47, 71), /* '~' => LRAction::Reduce(ArithmeticOp, 72) */ + (48, 71), /* '@' => LRAction::Reduce(ArithmeticOp, 72) */ + (49, 71), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ArithmeticOp, 72) */ + (50, 71), /* '[' => LRAction::Reduce(ArithmeticOp, 72) */ + (52, 71), /* '"(\\.|[^"])*"' => LRAction::Reduce(ArithmeticOp, 72) */ + (53, 71), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ArithmeticOp, 72) */ + (54, 71), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ArithmeticOp, 72) */ + (55, 71), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticOp, 72) */ + (56, 71), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticOp, 72) */ + (57, 71), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticOp, 72) */ + (58, 71), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticOp, 72) */ + (59, 71), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ArithmeticOp, 72) */ + ], + gotos: &[], + }, + // State 98 + LR1State { + actions: &[ + (9, 72), /* '(' => LRAction::Reduce(ArithmeticOp, 73) */ + (31, 72), /* '-' => LRAction::Reduce(ArithmeticOp, 73) */ + (36, 72), /* 'wait' => LRAction::Reduce(ArithmeticOp, 73) */ + (37, 72), /* 'call' => LRAction::Reduce(ArithmeticOp, 73) */ + (38, 72), /* '&' => LRAction::Reduce(ArithmeticOp, 73) */ + (39, 72), /* '$' => LRAction::Reduce(ArithmeticOp, 73) */ + (41, 72), /* 'if' => LRAction::Reduce(ArithmeticOp, 73) */ + (43, 72), /* 'select' => LRAction::Reduce(ArithmeticOp, 73) */ + (47, 72), /* '~' => LRAction::Reduce(ArithmeticOp, 73) */ + (48, 72), /* '@' => LRAction::Reduce(ArithmeticOp, 73) */ + (49, 72), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ArithmeticOp, 73) */ + (50, 72), /* '[' => LRAction::Reduce(ArithmeticOp, 73) */ + (52, 72), /* '"(\\.|[^"])*"' => LRAction::Reduce(ArithmeticOp, 73) */ + (53, 72), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ArithmeticOp, 73) */ + (54, 72), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ArithmeticOp, 73) */ + (55, 72), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticOp, 73) */ + (56, 72), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticOp, 73) */ + (57, 72), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticOp, 73) */ + (58, 72), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticOp, 73) */ + (59, 72), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ArithmeticOp, 73) */ + ], + gotos: &[], + }, + // State 99 + LR1State { + actions: &[ + (9, 69), /* '(' => LRAction::Reduce(ArithmeticExprList, 70) */ + (31, 69), /* '-' => LRAction::Reduce(ArithmeticExprList, 70) */ + (36, 69), /* 'wait' => LRAction::Reduce(ArithmeticExprList, 70) */ + (37, 69), /* 'call' => LRAction::Reduce(ArithmeticExprList, 70) */ + (38, 69), /* '&' => LRAction::Reduce(ArithmeticExprList, 70) */ + (39, 69), /* '$' => LRAction::Reduce(ArithmeticExprList, 70) */ + (41, 69), /* 'if' => LRAction::Reduce(ArithmeticExprList, 70) */ + (43, 69), /* 'select' => LRAction::Reduce(ArithmeticExprList, 70) */ + (47, 69), /* '~' => LRAction::Reduce(ArithmeticExprList, 70) */ + (48, 69), /* '@' => LRAction::Reduce(ArithmeticExprList, 70) */ + (49, 69), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ArithmeticExprList, 70) */ + (50, 69), /* '[' => LRAction::Reduce(ArithmeticExprList, 70) */ + (52, 69), /* '"(\\.|[^"])*"' => LRAction::Reduce(ArithmeticExprList, 70) */ + (53, 69), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ArithmeticExprList, 70) */ + (54, 69), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ArithmeticExprList, 70) */ + (55, 69), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticExprList, 70) */ + (56, 69), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticExprList, 70) */ + (57, 69), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticExprList, 70) */ + (58, 69), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ArithmeticExprList, 70) */ + (59, 69), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ArithmeticExprList, 70) */ + ], + gotos: &[], + }, + // State 100 + LR1State { + actions: &[ + (9, 161), /* '(' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (38, 36), /* '&' => LRAction::Shift(108) */ + (39, 37), /* '$' => LRAction::Shift(109) */ + (41, 161), /* 'if' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (43, 161), /* 'select' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (49, 161), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (50, 161), /* '[' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (52, 161), /* '"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (53, 161), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (54, 161), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (55, 161), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (56, 161), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (57, 161), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (58, 161), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (59, 161), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + ], + gotos: &[ + (0, 110), /* ApplyExpr => 110 */ + (56, 111), /* LowerPrefixExpr => 111 */ + (57, 112), /* LowerPrefixExprOpt => 112 */ + (58, 113), /* LowerPrefixOp => 113 */ + ], + }, + // State 101 + LR1State { + actions: &[ + (9, 161), /* '(' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (38, 36), /* '&' => LRAction::Shift(108) */ + (39, 37), /* '$' => LRAction::Shift(109) */ + (41, 161), /* 'if' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (43, 161), /* 'select' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (49, 161), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (50, 161), /* '[' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (52, 161), /* '"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (53, 161), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (54, 161), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (55, 161), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (56, 161), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (57, 161), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (58, 161), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (59, 161), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + ], + gotos: &[ + (0, 114), /* ApplyExpr => 114 */ + (56, 111), /* LowerPrefixExpr => 111 */ + (57, 112), /* LowerPrefixExprOpt => 112 */ + (58, 113), /* LowerPrefixOp => 113 */ + ], + }, + // State 102 + LR1State { + actions: &[ + (9, 161), /* '(' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (38, 36), /* '&' => LRAction::Shift(108) */ + (39, 37), /* '$' => LRAction::Shift(109) */ + (41, 161), /* 'if' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (43, 161), /* 'select' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (49, 161), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (50, 161), /* '[' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (52, 161), /* '"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (53, 161), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (54, 161), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (55, 161), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (56, 161), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (57, 161), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (58, 161), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (59, 161), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + ], + gotos: &[ + (0, 115), /* ApplyExpr => 115 */ + (56, 111), /* LowerPrefixExpr => 111 */ + (57, 112), /* LowerPrefixExprOpt => 112 */ + (58, 113), /* LowerPrefixOp => 113 */ + ], + }, + // State 103 + LR1State { + actions: &[ + (10, 126), /* ')' => LRAction::Reduce(FactorExpr, 74) */ + (12, 126), /* ',' => LRAction::Reduce(FactorExpr, 74) */ + (17, 126), /* ';' => LRAction::Reduce(FactorExpr, 74) */ + (20, 126), /* ':=' => LRAction::Reduce(FactorExpr, 74) */ + (21, 126), /* '||' => LRAction::Reduce(FactorExpr, 74) */ + (22, 126), /* '&&' => LRAction::Reduce(FactorExpr, 74) */ + (23, 126), /* '>=' => LRAction::Reduce(FactorExpr, 74) */ + (24, 126), /* '<=' => LRAction::Reduce(FactorExpr, 74) */ + (25, 126), /* '>' => LRAction::Reduce(FactorExpr, 74) */ + (26, 126), /* '<' => LRAction::Reduce(FactorExpr, 74) */ + (27, 126), /* '!=' => LRAction::Reduce(FactorExpr, 74) */ + (28, 126), /* '/=' => LRAction::Reduce(FactorExpr, 74) */ + (29, 126), /* '==' => LRAction::Reduce(FactorExpr, 74) */ + (30, 126), /* '+' => LRAction::Reduce(FactorExpr, 74) */ + (31, 126), /* '-' => LRAction::Reduce(FactorExpr, 74) */ + (32, 38), /* '*' => LRAction::Shift(116) */ + (33, 39), /* '/' => LRAction::Shift(117) */ + (34, 40), /* '%' => LRAction::Shift(118) */ + (44, 126), /* '{' => LRAction::Reduce(FactorExpr, 74) */ + (46, 126), /* '=>' => LRAction::Reduce(FactorExpr, 74) */ + (51, 126), /* ']' => LRAction::Reduce(FactorExpr, 74) */ + ], + gotos: &[(38, 119) /* FactorOp => 119 */], + }, + // State 104 + LR1State { + actions: &[ + (10, 91), /* ')' => LRAction::Reduce(CastExprOpt, 82) */ + (12, 91), /* ',' => LRAction::Reduce(CastExprOpt, 82) */ + (17, 91), /* ';' => LRAction::Reduce(CastExprOpt, 82) */ + (20, 91), /* ':=' => LRAction::Reduce(CastExprOpt, 82) */ + (21, 91), /* '||' => LRAction::Reduce(CastExprOpt, 82) */ + (22, 91), /* '&&' => LRAction::Reduce(CastExprOpt, 82) */ + (23, 91), /* '>=' => LRAction::Reduce(CastExprOpt, 82) */ + (24, 91), /* '<=' => LRAction::Reduce(CastExprOpt, 82) */ + (25, 91), /* '>' => LRAction::Reduce(CastExprOpt, 82) */ + (26, 91), /* '<' => LRAction::Reduce(CastExprOpt, 82) */ + (27, 91), /* '!=' => LRAction::Reduce(CastExprOpt, 82) */ + (28, 91), /* '/=' => LRAction::Reduce(CastExprOpt, 82) */ + (29, 91), /* '==' => LRAction::Reduce(CastExprOpt, 82) */ + (30, 91), /* '+' => LRAction::Reduce(CastExprOpt, 82) */ + (31, 91), /* '-' => LRAction::Reduce(CastExprOpt, 82) */ + (32, 91), /* '*' => LRAction::Reduce(CastExprOpt, 82) */ + (33, 91), /* '/' => LRAction::Reduce(CastExprOpt, 82) */ + (34, 91), /* '%' => LRAction::Reduce(CastExprOpt, 82) */ + (35, 41), /* 'as' => LRAction::Shift(120) */ + (44, 91), /* '{' => LRAction::Reduce(CastExprOpt, 82) */ + (46, 91), /* '=>' => LRAction::Reduce(CastExprOpt, 82) */ + (51, 91), /* ']' => LRAction::Reduce(CastExprOpt, 82) */ + ], + gotos: &[(15, 121) /* CastExprOpt => 121 */], + }, + // State 105 + LR1State { + actions: &[ + (9, 161), /* '(' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (38, 36), /* '&' => LRAction::Shift(108) */ + (39, 37), /* '$' => LRAction::Shift(109) */ + (41, 161), /* 'if' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (43, 161), /* 'select' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (47, 42), /* '~' => LRAction::Shift(122) */ + (48, 43), /* '@' => LRAction::Shift(123) */ + (49, 161), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (50, 161), /* '[' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (52, 161), /* '"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (53, 161), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (54, 161), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (55, 161), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (56, 161), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (57, 161), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (58, 161), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (59, 161), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + ], + gotos: &[ + (0, 124), /* ApplyExpr => 124 */ + (29, 125), /* DefaultModifier => 125 */ + (56, 111), /* LowerPrefixExpr => 111 */ + (57, 112), /* LowerPrefixExprOpt => 112 */ + (58, 113), /* LowerPrefixOp => 113 */ + (59, 126), /* Modifier => 126 */ + (72, 127), /* Qualif => 127 */ + ], + }, + // State 106 + LR1State { + actions: &[ + (9, 158), /* '(' => LRAction::Reduce(LogicalOrExprList, 55) */ + (31, 158), /* '-' => LRAction::Reduce(LogicalOrExprList, 55) */ + (36, 158), /* 'wait' => LRAction::Reduce(LogicalOrExprList, 55) */ + (37, 158), /* 'call' => LRAction::Reduce(LogicalOrExprList, 55) */ + (38, 158), /* '&' => LRAction::Reduce(LogicalOrExprList, 55) */ + (39, 158), /* '$' => LRAction::Reduce(LogicalOrExprList, 55) */ + (41, 158), /* 'if' => LRAction::Reduce(LogicalOrExprList, 55) */ + (43, 158), /* 'select' => LRAction::Reduce(LogicalOrExprList, 55) */ + (47, 158), /* '~' => LRAction::Reduce(LogicalOrExprList, 55) */ + (48, 158), /* '@' => LRAction::Reduce(LogicalOrExprList, 55) */ + (49, 158), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalOrExprList, 55) */ + (50, 158), /* '[' => LRAction::Reduce(LogicalOrExprList, 55) */ + (52, 158), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (53, 158), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (54, 158), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (55, 158), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (56, 158), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (57, 158), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (58, 158), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (59, 158), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalOrExprList, 55) */ + ], + gotos: &[ + (35, 128), /* Expr => 128 */ + (54, 44), /* LogicalOrExpr => 44 */ + (55, 45), /* LogicalOrExprList => 45 */ + (88, 46), /* SetExpr => 46 */ + ], + }, + // State 107 + LR1State { + actions: &[ + (10, 106), /* ')' => LRAction::Reduce(CompareExprList, 60) */ + (12, 106), /* ',' => LRAction::Reduce(CompareExprList, 60) */ + (17, 106), /* ';' => LRAction::Reduce(CompareExprList, 60) */ + (20, 106), /* ':=' => LRAction::Reduce(CompareExprList, 60) */ + (21, 106), /* '||' => LRAction::Reduce(CompareExprList, 60) */ + (22, 106), /* '&&' => LRAction::Reduce(CompareExprList, 60) */ + (23, 106), /* '>=' => LRAction::Reduce(CompareExprList, 60) */ + (24, 106), /* '<=' => LRAction::Reduce(CompareExprList, 60) */ + (25, 106), /* '>' => LRAction::Reduce(CompareExprList, 60) */ + (26, 106), /* '<' => LRAction::Reduce(CompareExprList, 60) */ + (27, 106), /* '!=' => LRAction::Reduce(CompareExprList, 60) */ + (28, 106), /* '/=' => LRAction::Reduce(CompareExprList, 60) */ + (29, 106), /* '==' => LRAction::Reduce(CompareExprList, 60) */ + (44, 106), /* '{' => LRAction::Reduce(CompareExprList, 60) */ + (46, 106), /* '=>' => LRAction::Reduce(CompareExprList, 60) */ + (51, 106), /* ']' => LRAction::Reduce(CompareExprList, 60) */ + ], + gotos: &[], + }, + // State 108 + LR1State { + actions: &[ + (9, 162), /* '(' => LRAction::Reduce(LowerPrefixOp, 95) */ + (41, 162), /* 'if' => LRAction::Reduce(LowerPrefixOp, 95) */ + (43, 162), /* 'select' => LRAction::Reduce(LowerPrefixOp, 95) */ + (49, 162), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LowerPrefixOp, 95) */ + (50, 162), /* '[' => LRAction::Reduce(LowerPrefixOp, 95) */ + (52, 162), /* '"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixOp, 95) */ + (53, 162), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixOp, 95) */ + (54, 162), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LowerPrefixOp, 95) */ + (55, 162), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixOp, 95) */ + (56, 162), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixOp, 95) */ + (57, 162), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixOp, 95) */ + (58, 162), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixOp, 95) */ + (59, 162), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LowerPrefixOp, 95) */ + ], + gotos: &[], + }, + // State 109 + LR1State { + actions: &[ + (9, 163), /* '(' => LRAction::Reduce(LowerPrefixOp, 96) */ + (41, 163), /* 'if' => LRAction::Reduce(LowerPrefixOp, 96) */ + (43, 163), /* 'select' => LRAction::Reduce(LowerPrefixOp, 96) */ + (49, 163), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LowerPrefixOp, 96) */ + (50, 163), /* '[' => LRAction::Reduce(LowerPrefixOp, 96) */ + (52, 163), /* '"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixOp, 96) */ + (53, 163), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixOp, 96) */ + (54, 163), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LowerPrefixOp, 96) */ + (55, 163), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixOp, 96) */ + (56, 163), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixOp, 96) */ + (57, 163), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixOp, 96) */ + (58, 163), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixOp, 96) */ + (59, 163), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LowerPrefixOp, 96) */ + ], + gotos: &[], + }, + // State 110 + LR1State { + actions: &[ + (10, 179), /* ')' => LRAction::Reduce(PrefixExpr, 83) */ + (12, 179), /* ',' => LRAction::Reduce(PrefixExpr, 83) */ + (17, 179), /* ';' => LRAction::Reduce(PrefixExpr, 83) */ + (20, 179), /* ':=' => LRAction::Reduce(PrefixExpr, 83) */ + (21, 179), /* '||' => LRAction::Reduce(PrefixExpr, 83) */ + (22, 179), /* '&&' => LRAction::Reduce(PrefixExpr, 83) */ + (23, 179), /* '>=' => LRAction::Reduce(PrefixExpr, 83) */ + (24, 179), /* '<=' => LRAction::Reduce(PrefixExpr, 83) */ + (25, 179), /* '>' => LRAction::Reduce(PrefixExpr, 83) */ + (26, 179), /* '<' => LRAction::Reduce(PrefixExpr, 83) */ + (27, 179), /* '!=' => LRAction::Reduce(PrefixExpr, 83) */ + (28, 179), /* '/=' => LRAction::Reduce(PrefixExpr, 83) */ + (29, 179), /* '==' => LRAction::Reduce(PrefixExpr, 83) */ + (30, 179), /* '+' => LRAction::Reduce(PrefixExpr, 83) */ + (31, 179), /* '-' => LRAction::Reduce(PrefixExpr, 83) */ + (32, 179), /* '*' => LRAction::Reduce(PrefixExpr, 83) */ + (33, 179), /* '/' => LRAction::Reduce(PrefixExpr, 83) */ + (34, 179), /* '%' => LRAction::Reduce(PrefixExpr, 83) */ + (35, 179), /* 'as' => LRAction::Reduce(PrefixExpr, 83) */ + (44, 179), /* '{' => LRAction::Reduce(PrefixExpr, 83) */ + (46, 179), /* '=>' => LRAction::Reduce(PrefixExpr, 83) */ + (51, 179), /* ']' => LRAction::Reduce(PrefixExpr, 83) */ + ], + gotos: &[], + }, + // State 111 + LR1State { + actions: &[ + (9, 67), /* '(' => LRAction::Reduce(ApplyExprList, 91) */ + (10, 67), /* ')' => LRAction::Reduce(ApplyExprList, 91) */ + (12, 67), /* ',' => LRAction::Reduce(ApplyExprList, 91) */ + (17, 67), /* ';' => LRAction::Reduce(ApplyExprList, 91) */ + (20, 67), /* ':=' => LRAction::Reduce(ApplyExprList, 91) */ + (21, 67), /* '||' => LRAction::Reduce(ApplyExprList, 91) */ + (22, 67), /* '&&' => LRAction::Reduce(ApplyExprList, 91) */ + (23, 67), /* '>=' => LRAction::Reduce(ApplyExprList, 91) */ + (24, 67), /* '<=' => LRAction::Reduce(ApplyExprList, 91) */ + (25, 67), /* '>' => LRAction::Reduce(ApplyExprList, 91) */ + (26, 67), /* '<' => LRAction::Reduce(ApplyExprList, 91) */ + (27, 67), /* '!=' => LRAction::Reduce(ApplyExprList, 91) */ + (28, 67), /* '/=' => LRAction::Reduce(ApplyExprList, 91) */ + (29, 67), /* '==' => LRAction::Reduce(ApplyExprList, 91) */ + (30, 67), /* '+' => LRAction::Reduce(ApplyExprList, 91) */ + (31, 67), /* '-' => LRAction::Reduce(ApplyExprList, 91) */ + (32, 67), /* '*' => LRAction::Reduce(ApplyExprList, 91) */ + (33, 67), /* '/' => LRAction::Reduce(ApplyExprList, 91) */ + (34, 67), /* '%' => LRAction::Reduce(ApplyExprList, 91) */ + (35, 67), /* 'as' => LRAction::Reduce(ApplyExprList, 91) */ + (38, 67), /* '&' => LRAction::Reduce(ApplyExprList, 91) */ + (39, 67), /* '$' => LRAction::Reduce(ApplyExprList, 91) */ + (41, 67), /* 'if' => LRAction::Reduce(ApplyExprList, 91) */ + (43, 67), /* 'select' => LRAction::Reduce(ApplyExprList, 91) */ + (44, 67), /* '{' => LRAction::Reduce(ApplyExprList, 91) */ + (46, 67), /* '=>' => LRAction::Reduce(ApplyExprList, 91) */ + (47, 67), /* '~' => LRAction::Reduce(ApplyExprList, 91) */ + (48, 67), /* '@' => LRAction::Reduce(ApplyExprList, 91) */ + (49, 67), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ApplyExprList, 91) */ + (50, 67), /* '[' => LRAction::Reduce(ApplyExprList, 91) */ + (51, 67), /* ']' => LRAction::Reduce(ApplyExprList, 91) */ + (52, 67), /* '"(\\.|[^"])*"' => LRAction::Reduce(ApplyExprList, 91) */ + (53, 67), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ApplyExprList, 91) */ + (54, 67), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ApplyExprList, 91) */ + (55, 67), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ApplyExprList, 91) */ + (56, 67), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ApplyExprList, 91) */ + (57, 67), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ApplyExprList, 91) */ + (58, 67), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ApplyExprList, 91) */ + (59, 67), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ApplyExprList, 91) */ + ], + gotos: &[(1, 129) /* ApplyExprList => 129 */], + }, + // State 112 + LR1State { + actions: &[ + (9, 44), /* '(' => LRAction::Shift(130) */ + (41, 45), /* 'if' => LRAction::Shift(131) */ + (43, 46), /* 'select' => LRAction::Shift(132) */ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + (50, 47), /* '[' => LRAction::Shift(133) */ + (52, 48), /* '"(\\.|[^"])*"' => LRAction::Shift(134) */ + (53, 49), /* 'b"(\\.|[^"])*"' => LRAction::Shift(135) */ + (54, 50), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Shift(136) */ + (55, 51), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Shift(137) */ + (56, 52), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Shift(138) */ + (57, 53), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Shift(139) */ + (58, 54), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Shift(140) */ + (59, 55), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Shift(141) */ + ], + gotos: &[ + (5, 142), /* Array => 142 */ + (8, 143), /* BinaryInteger => 143 */ + (11, 144), /* ByteLiteral => 144 */ + (12, 145), /* Callable => 145 */ + (43, 146), /* HexByteLiteral => 146 */ + (44, 147), /* HexadecimalInteger => 147 */ + (45, 28), /* Ident => 28 */ + (46, 148), /* Ieee754Float => 148 */ + (47, 149), /* IfExpr => 149 */ + (51, 150), /* Literal => 150 */ + (61, 151), /* Numeric => 151 */ + (62, 152), /* OctalInteger => 152 */ + (66, 153), /* Path => 153 */ + (74, 154), /* Rfc3339DateTime => 154 */ + (82, 155), /* SelectExpr => 155 */ + (92, 156), /* String => 156 */ + ], + }, + // State 113 + LR1State { + actions: &[ + (9, 160), /* '(' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + (41, 160), /* 'if' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + (43, 160), /* 'select' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + (49, 160), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + (50, 160), /* '[' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + (52, 160), /* '"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + (53, 160), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + (54, 160), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + (55, 160), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + (56, 160), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + (57, 160), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + (58, 160), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + (59, 160), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LowerPrefixExprOpt, 93) */ + ], + gotos: &[], + }, + // State 114 + LR1State { + actions: &[ + (10, 181), /* ')' => LRAction::Reduce(PrefixExpr, 87) */ + (12, 181), /* ',' => LRAction::Reduce(PrefixExpr, 87) */ + (17, 181), /* ';' => LRAction::Reduce(PrefixExpr, 87) */ + (20, 181), /* ':=' => LRAction::Reduce(PrefixExpr, 87) */ + (21, 181), /* '||' => LRAction::Reduce(PrefixExpr, 87) */ + (22, 181), /* '&&' => LRAction::Reduce(PrefixExpr, 87) */ + (23, 181), /* '>=' => LRAction::Reduce(PrefixExpr, 87) */ + (24, 181), /* '<=' => LRAction::Reduce(PrefixExpr, 87) */ + (25, 181), /* '>' => LRAction::Reduce(PrefixExpr, 87) */ + (26, 181), /* '<' => LRAction::Reduce(PrefixExpr, 87) */ + (27, 181), /* '!=' => LRAction::Reduce(PrefixExpr, 87) */ + (28, 181), /* '/=' => LRAction::Reduce(PrefixExpr, 87) */ + (29, 181), /* '==' => LRAction::Reduce(PrefixExpr, 87) */ + (30, 181), /* '+' => LRAction::Reduce(PrefixExpr, 87) */ + (31, 181), /* '-' => LRAction::Reduce(PrefixExpr, 87) */ + (32, 181), /* '*' => LRAction::Reduce(PrefixExpr, 87) */ + (33, 181), /* '/' => LRAction::Reduce(PrefixExpr, 87) */ + (34, 181), /* '%' => LRAction::Reduce(PrefixExpr, 87) */ + (35, 181), /* 'as' => LRAction::Reduce(PrefixExpr, 87) */ + (44, 181), /* '{' => LRAction::Reduce(PrefixExpr, 87) */ + (46, 181), /* '=>' => LRAction::Reduce(PrefixExpr, 87) */ + (51, 181), /* ']' => LRAction::Reduce(PrefixExpr, 87) */ + ], + gotos: &[], + }, + // State 115 + LR1State { + actions: &[ + (10, 182), /* ')' => LRAction::Reduce(PrefixExpr, 88) */ + (12, 182), /* ',' => LRAction::Reduce(PrefixExpr, 88) */ + (17, 182), /* ';' => LRAction::Reduce(PrefixExpr, 88) */ + (20, 182), /* ':=' => LRAction::Reduce(PrefixExpr, 88) */ + (21, 182), /* '||' => LRAction::Reduce(PrefixExpr, 88) */ + (22, 182), /* '&&' => LRAction::Reduce(PrefixExpr, 88) */ + (23, 182), /* '>=' => LRAction::Reduce(PrefixExpr, 88) */ + (24, 182), /* '<=' => LRAction::Reduce(PrefixExpr, 88) */ + (25, 182), /* '>' => LRAction::Reduce(PrefixExpr, 88) */ + (26, 182), /* '<' => LRAction::Reduce(PrefixExpr, 88) */ + (27, 182), /* '!=' => LRAction::Reduce(PrefixExpr, 88) */ + (28, 182), /* '/=' => LRAction::Reduce(PrefixExpr, 88) */ + (29, 182), /* '==' => LRAction::Reduce(PrefixExpr, 88) */ + (30, 182), /* '+' => LRAction::Reduce(PrefixExpr, 88) */ + (31, 182), /* '-' => LRAction::Reduce(PrefixExpr, 88) */ + (32, 182), /* '*' => LRAction::Reduce(PrefixExpr, 88) */ + (33, 182), /* '/' => LRAction::Reduce(PrefixExpr, 88) */ + (34, 182), /* '%' => LRAction::Reduce(PrefixExpr, 88) */ + (35, 182), /* 'as' => LRAction::Reduce(PrefixExpr, 88) */ + (44, 182), /* '{' => LRAction::Reduce(PrefixExpr, 88) */ + (46, 182), /* '=>' => LRAction::Reduce(PrefixExpr, 88) */ + (51, 182), /* ']' => LRAction::Reduce(PrefixExpr, 88) */ + ], + gotos: &[], + }, + // State 116 + LR1State { + actions: &[ + (9, 129), /* '(' => LRAction::Reduce(FactorOp, 77) */ + (31, 129), /* '-' => LRAction::Reduce(FactorOp, 77) */ + (36, 129), /* 'wait' => LRAction::Reduce(FactorOp, 77) */ + (37, 129), /* 'call' => LRAction::Reduce(FactorOp, 77) */ + (38, 129), /* '&' => LRAction::Reduce(FactorOp, 77) */ + (39, 129), /* '$' => LRAction::Reduce(FactorOp, 77) */ + (41, 129), /* 'if' => LRAction::Reduce(FactorOp, 77) */ + (43, 129), /* 'select' => LRAction::Reduce(FactorOp, 77) */ + (47, 129), /* '~' => LRAction::Reduce(FactorOp, 77) */ + (48, 129), /* '@' => LRAction::Reduce(FactorOp, 77) */ + (49, 129), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(FactorOp, 77) */ + (50, 129), /* '[' => LRAction::Reduce(FactorOp, 77) */ + (52, 129), /* '"(\\.|[^"])*"' => LRAction::Reduce(FactorOp, 77) */ + (53, 129), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(FactorOp, 77) */ + (54, 129), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(FactorOp, 77) */ + (55, 129), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorOp, 77) */ + (56, 129), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorOp, 77) */ + (57, 129), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorOp, 77) */ + (58, 129), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorOp, 77) */ + (59, 129), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(FactorOp, 77) */ + ], + gotos: &[], + }, + // State 117 + LR1State { + actions: &[ + (9, 130), /* '(' => LRAction::Reduce(FactorOp, 78) */ + (31, 130), /* '-' => LRAction::Reduce(FactorOp, 78) */ + (36, 130), /* 'wait' => LRAction::Reduce(FactorOp, 78) */ + (37, 130), /* 'call' => LRAction::Reduce(FactorOp, 78) */ + (38, 130), /* '&' => LRAction::Reduce(FactorOp, 78) */ + (39, 130), /* '$' => LRAction::Reduce(FactorOp, 78) */ + (41, 130), /* 'if' => LRAction::Reduce(FactorOp, 78) */ + (43, 130), /* 'select' => LRAction::Reduce(FactorOp, 78) */ + (47, 130), /* '~' => LRAction::Reduce(FactorOp, 78) */ + (48, 130), /* '@' => LRAction::Reduce(FactorOp, 78) */ + (49, 130), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(FactorOp, 78) */ + (50, 130), /* '[' => LRAction::Reduce(FactorOp, 78) */ + (52, 130), /* '"(\\.|[^"])*"' => LRAction::Reduce(FactorOp, 78) */ + (53, 130), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(FactorOp, 78) */ + (54, 130), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(FactorOp, 78) */ + (55, 130), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorOp, 78) */ + (56, 130), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorOp, 78) */ + (57, 130), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorOp, 78) */ + (58, 130), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorOp, 78) */ + (59, 130), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(FactorOp, 78) */ + ], + gotos: &[], + }, + // State 118 + LR1State { + actions: &[ + (9, 131), /* '(' => LRAction::Reduce(FactorOp, 79) */ + (31, 131), /* '-' => LRAction::Reduce(FactorOp, 79) */ + (36, 131), /* 'wait' => LRAction::Reduce(FactorOp, 79) */ + (37, 131), /* 'call' => LRAction::Reduce(FactorOp, 79) */ + (38, 131), /* '&' => LRAction::Reduce(FactorOp, 79) */ + (39, 131), /* '$' => LRAction::Reduce(FactorOp, 79) */ + (41, 131), /* 'if' => LRAction::Reduce(FactorOp, 79) */ + (43, 131), /* 'select' => LRAction::Reduce(FactorOp, 79) */ + (47, 131), /* '~' => LRAction::Reduce(FactorOp, 79) */ + (48, 131), /* '@' => LRAction::Reduce(FactorOp, 79) */ + (49, 131), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(FactorOp, 79) */ + (50, 131), /* '[' => LRAction::Reduce(FactorOp, 79) */ + (52, 131), /* '"(\\.|[^"])*"' => LRAction::Reduce(FactorOp, 79) */ + (53, 131), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(FactorOp, 79) */ + (54, 131), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(FactorOp, 79) */ + (55, 131), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorOp, 79) */ + (56, 131), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorOp, 79) */ + (57, 131), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorOp, 79) */ + (58, 131), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorOp, 79) */ + (59, 131), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(FactorOp, 79) */ + ], + gotos: &[], + }, + // State 119 + LR1State { + actions: &[ + (9, 127), /* '(' => LRAction::Reduce(FactorExprList, 75) */ + (31, 127), /* '-' => LRAction::Reduce(FactorExprList, 75) */ + (36, 127), /* 'wait' => LRAction::Reduce(FactorExprList, 75) */ + (37, 127), /* 'call' => LRAction::Reduce(FactorExprList, 75) */ + (38, 127), /* '&' => LRAction::Reduce(FactorExprList, 75) */ + (39, 127), /* '$' => LRAction::Reduce(FactorExprList, 75) */ + (41, 127), /* 'if' => LRAction::Reduce(FactorExprList, 75) */ + (43, 127), /* 'select' => LRAction::Reduce(FactorExprList, 75) */ + (47, 127), /* '~' => LRAction::Reduce(FactorExprList, 75) */ + (48, 127), /* '@' => LRAction::Reduce(FactorExprList, 75) */ + (49, 127), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(FactorExprList, 75) */ + (50, 127), /* '[' => LRAction::Reduce(FactorExprList, 75) */ + (52, 127), /* '"(\\.|[^"])*"' => LRAction::Reduce(FactorExprList, 75) */ + (53, 127), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(FactorExprList, 75) */ + (54, 127), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(FactorExprList, 75) */ + (55, 127), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorExprList, 75) */ + (56, 127), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorExprList, 75) */ + (57, 127), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorExprList, 75) */ + (58, 127), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(FactorExprList, 75) */ + (59, 127), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(FactorExprList, 75) */ + ], + gotos: &[], + }, + // State 120 + LR1State { + actions: &[ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[ + (45, 28), /* Ident => 28 */ + (66, 157), /* Path => 157 */ + ], + }, + // State 121 + LR1State { + actions: &[ + (10, 89), /* ')' => LRAction::Reduce(CastExpr, 80) */ + (12, 89), /* ',' => LRAction::Reduce(CastExpr, 80) */ + (17, 89), /* ';' => LRAction::Reduce(CastExpr, 80) */ + (20, 89), /* ':=' => LRAction::Reduce(CastExpr, 80) */ + (21, 89), /* '||' => LRAction::Reduce(CastExpr, 80) */ + (22, 89), /* '&&' => LRAction::Reduce(CastExpr, 80) */ + (23, 89), /* '>=' => LRAction::Reduce(CastExpr, 80) */ + (24, 89), /* '<=' => LRAction::Reduce(CastExpr, 80) */ + (25, 89), /* '>' => LRAction::Reduce(CastExpr, 80) */ + (26, 89), /* '<' => LRAction::Reduce(CastExpr, 80) */ + (27, 89), /* '!=' => LRAction::Reduce(CastExpr, 80) */ + (28, 89), /* '/=' => LRAction::Reduce(CastExpr, 80) */ + (29, 89), /* '==' => LRAction::Reduce(CastExpr, 80) */ + (30, 89), /* '+' => LRAction::Reduce(CastExpr, 80) */ + (31, 89), /* '-' => LRAction::Reduce(CastExpr, 80) */ + (32, 89), /* '*' => LRAction::Reduce(CastExpr, 80) */ + (33, 89), /* '/' => LRAction::Reduce(CastExpr, 80) */ + (34, 89), /* '%' => LRAction::Reduce(CastExpr, 80) */ + (44, 89), /* '{' => LRAction::Reduce(CastExpr, 80) */ + (46, 89), /* '=>' => LRAction::Reduce(CastExpr, 80) */ + (51, 89), /* ']' => LRAction::Reduce(CastExpr, 80) */ + ], + gotos: &[], + }, + // State 122 + LR1State { + actions: &[ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[ + (45, 28), /* Ident => 28 */ + (66, 158), /* Path => 158 */ + ], + }, + // State 123 + LR1State { + actions: &[ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[ + (45, 28), /* Ident => 28 */ + (66, 159), /* Path => 159 */ + ], + }, + // State 124 + LR1State { + actions: &[ + (10, 180), /* ')' => LRAction::Reduce(PrefixExpr, 84) */ + (12, 180), /* ',' => LRAction::Reduce(PrefixExpr, 84) */ + (17, 180), /* ';' => LRAction::Reduce(PrefixExpr, 84) */ + (20, 180), /* ':=' => LRAction::Reduce(PrefixExpr, 84) */ + (21, 180), /* '||' => LRAction::Reduce(PrefixExpr, 84) */ + (22, 180), /* '&&' => LRAction::Reduce(PrefixExpr, 84) */ + (23, 180), /* '>=' => LRAction::Reduce(PrefixExpr, 84) */ + (24, 180), /* '<=' => LRAction::Reduce(PrefixExpr, 84) */ + (25, 180), /* '>' => LRAction::Reduce(PrefixExpr, 84) */ + (26, 180), /* '<' => LRAction::Reduce(PrefixExpr, 84) */ + (27, 180), /* '!=' => LRAction::Reduce(PrefixExpr, 84) */ + (28, 180), /* '/=' => LRAction::Reduce(PrefixExpr, 84) */ + (29, 180), /* '==' => LRAction::Reduce(PrefixExpr, 84) */ + (30, 180), /* '+' => LRAction::Reduce(PrefixExpr, 84) */ + (31, 180), /* '-' => LRAction::Reduce(PrefixExpr, 84) */ + (32, 180), /* '*' => LRAction::Reduce(PrefixExpr, 84) */ + (33, 180), /* '/' => LRAction::Reduce(PrefixExpr, 84) */ + (34, 180), /* '%' => LRAction::Reduce(PrefixExpr, 84) */ + (35, 180), /* 'as' => LRAction::Reduce(PrefixExpr, 84) */ + (44, 180), /* '{' => LRAction::Reduce(PrefixExpr, 84) */ + (46, 180), /* '=>' => LRAction::Reduce(PrefixExpr, 84) */ + (51, 180), /* ']' => LRAction::Reduce(PrefixExpr, 84) */ + ], + gotos: &[], + }, + // State 125 + LR1State { + actions: &[ + (9, 188), /* '(' => LRAction::Reduce(Qualif, 117) */ + (10, 188), /* ')' => LRAction::Reduce(Qualif, 117) */ + (12, 188), /* ',' => LRAction::Reduce(Qualif, 117) */ + (17, 188), /* ';' => LRAction::Reduce(Qualif, 117) */ + (20, 188), /* ':=' => LRAction::Reduce(Qualif, 117) */ + (21, 188), /* '||' => LRAction::Reduce(Qualif, 117) */ + (22, 188), /* '&&' => LRAction::Reduce(Qualif, 117) */ + (23, 188), /* '>=' => LRAction::Reduce(Qualif, 117) */ + (24, 188), /* '<=' => LRAction::Reduce(Qualif, 117) */ + (25, 188), /* '>' => LRAction::Reduce(Qualif, 117) */ + (26, 188), /* '<' => LRAction::Reduce(Qualif, 117) */ + (27, 188), /* '!=' => LRAction::Reduce(Qualif, 117) */ + (28, 188), /* '/=' => LRAction::Reduce(Qualif, 117) */ + (29, 188), /* '==' => LRAction::Reduce(Qualif, 117) */ + (30, 188), /* '+' => LRAction::Reduce(Qualif, 117) */ + (31, 188), /* '-' => LRAction::Reduce(Qualif, 117) */ + (32, 188), /* '*' => LRAction::Reduce(Qualif, 117) */ + (33, 188), /* '/' => LRAction::Reduce(Qualif, 117) */ + (34, 188), /* '%' => LRAction::Reduce(Qualif, 117) */ + (35, 188), /* 'as' => LRAction::Reduce(Qualif, 117) */ + (38, 188), /* '&' => LRAction::Reduce(Qualif, 117) */ + (39, 188), /* '$' => LRAction::Reduce(Qualif, 117) */ + (41, 188), /* 'if' => LRAction::Reduce(Qualif, 117) */ + (43, 188), /* 'select' => LRAction::Reduce(Qualif, 117) */ + (44, 188), /* '{' => LRAction::Reduce(Qualif, 117) */ + (46, 188), /* '=>' => LRAction::Reduce(Qualif, 117) */ + (47, 188), /* '~' => LRAction::Reduce(Qualif, 117) */ + (48, 188), /* '@' => LRAction::Reduce(Qualif, 117) */ + (49, 188), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Qualif, 117) */ + (50, 188), /* '[' => LRAction::Reduce(Qualif, 117) */ + (51, 188), /* ']' => LRAction::Reduce(Qualif, 117) */ + (52, 188), /* '"(\\.|[^"])*"' => LRAction::Reduce(Qualif, 117) */ + (53, 188), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Qualif, 117) */ + (54, 188), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Qualif, 117) */ + (55, 188), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Qualif, 117) */ + (56, 188), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Qualif, 117) */ + (57, 188), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Qualif, 117) */ + (58, 188), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Qualif, 117) */ + (59, 188), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Qualif, 117) */ + ], + gotos: &[], + }, + // State 126 + LR1State { + actions: &[ + (9, 187), /* '(' => LRAction::Reduce(Qualif, 116) */ + (10, 187), /* ')' => LRAction::Reduce(Qualif, 116) */ + (12, 187), /* ',' => LRAction::Reduce(Qualif, 116) */ + (17, 187), /* ';' => LRAction::Reduce(Qualif, 116) */ + (20, 187), /* ':=' => LRAction::Reduce(Qualif, 116) */ + (21, 187), /* '||' => LRAction::Reduce(Qualif, 116) */ + (22, 187), /* '&&' => LRAction::Reduce(Qualif, 116) */ + (23, 187), /* '>=' => LRAction::Reduce(Qualif, 116) */ + (24, 187), /* '<=' => LRAction::Reduce(Qualif, 116) */ + (25, 187), /* '>' => LRAction::Reduce(Qualif, 116) */ + (26, 187), /* '<' => LRAction::Reduce(Qualif, 116) */ + (27, 187), /* '!=' => LRAction::Reduce(Qualif, 116) */ + (28, 187), /* '/=' => LRAction::Reduce(Qualif, 116) */ + (29, 187), /* '==' => LRAction::Reduce(Qualif, 116) */ + (30, 187), /* '+' => LRAction::Reduce(Qualif, 116) */ + (31, 187), /* '-' => LRAction::Reduce(Qualif, 116) */ + (32, 187), /* '*' => LRAction::Reduce(Qualif, 116) */ + (33, 187), /* '/' => LRAction::Reduce(Qualif, 116) */ + (34, 187), /* '%' => LRAction::Reduce(Qualif, 116) */ + (35, 187), /* 'as' => LRAction::Reduce(Qualif, 116) */ + (38, 187), /* '&' => LRAction::Reduce(Qualif, 116) */ + (39, 187), /* '$' => LRAction::Reduce(Qualif, 116) */ + (41, 187), /* 'if' => LRAction::Reduce(Qualif, 116) */ + (43, 187), /* 'select' => LRAction::Reduce(Qualif, 116) */ + (44, 187), /* '{' => LRAction::Reduce(Qualif, 116) */ + (46, 187), /* '=>' => LRAction::Reduce(Qualif, 116) */ + (47, 187), /* '~' => LRAction::Reduce(Qualif, 116) */ + (48, 187), /* '@' => LRAction::Reduce(Qualif, 116) */ + (49, 187), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Qualif, 116) */ + (50, 187), /* '[' => LRAction::Reduce(Qualif, 116) */ + (51, 187), /* ']' => LRAction::Reduce(Qualif, 116) */ + (52, 187), /* '"(\\.|[^"])*"' => LRAction::Reduce(Qualif, 116) */ + (53, 187), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Qualif, 116) */ + (54, 187), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Qualif, 116) */ + (55, 187), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Qualif, 116) */ + (56, 187), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Qualif, 116) */ + (57, 187), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Qualif, 116) */ + (58, 187), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Qualif, 116) */ + (59, 187), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Qualif, 116) */ + ], + gotos: &[], + }, + // State 127 + LR1State { + actions: &[ + (9, 183), /* '(' => LRAction::Reduce(PrefixExprList, 85) */ + (38, 183), /* '&' => LRAction::Reduce(PrefixExprList, 85) */ + (39, 183), /* '$' => LRAction::Reduce(PrefixExprList, 85) */ + (41, 183), /* 'if' => LRAction::Reduce(PrefixExprList, 85) */ + (43, 183), /* 'select' => LRAction::Reduce(PrefixExprList, 85) */ + (47, 183), /* '~' => LRAction::Reduce(PrefixExprList, 85) */ + (48, 183), /* '@' => LRAction::Reduce(PrefixExprList, 85) */ + (49, 183), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(PrefixExprList, 85) */ + (50, 183), /* '[' => LRAction::Reduce(PrefixExprList, 85) */ + (52, 183), /* '"(\\.|[^"])*"' => LRAction::Reduce(PrefixExprList, 85) */ + (53, 183), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(PrefixExprList, 85) */ + (54, 183), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(PrefixExprList, 85) */ + (55, 183), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(PrefixExprList, 85) */ + (56, 183), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(PrefixExprList, 85) */ + (57, 183), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(PrefixExprList, 85) */ + (58, 183), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(PrefixExprList, 85) */ + (59, 183), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(PrefixExprList, 85) */ + ], + gotos: &[], + }, + // State 128 + LR1State { + actions: &[(17, 146) /* ';' => LRAction::Reduce(LetStmt, 48) */], + gotos: &[], + }, + // State 129 + LR1State { + actions: &[ + (9, 161), /* '(' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (10, 65), /* ')' => LRAction::Reduce(ApplyExpr, 89) */ + (12, 65), /* ',' => LRAction::Reduce(ApplyExpr, 89) */ + (17, 65), /* ';' => LRAction::Reduce(ApplyExpr, 89) */ + (20, 65), /* ':=' => LRAction::Reduce(ApplyExpr, 89) */ + (21, 65), /* '||' => LRAction::Reduce(ApplyExpr, 89) */ + (22, 65), /* '&&' => LRAction::Reduce(ApplyExpr, 89) */ + (23, 65), /* '>=' => LRAction::Reduce(ApplyExpr, 89) */ + (24, 65), /* '<=' => LRAction::Reduce(ApplyExpr, 89) */ + (25, 65), /* '>' => LRAction::Reduce(ApplyExpr, 89) */ + (26, 65), /* '<' => LRAction::Reduce(ApplyExpr, 89) */ + (27, 65), /* '!=' => LRAction::Reduce(ApplyExpr, 89) */ + (28, 65), /* '/=' => LRAction::Reduce(ApplyExpr, 89) */ + (29, 65), /* '==' => LRAction::Reduce(ApplyExpr, 89) */ + (30, 65), /* '+' => LRAction::Reduce(ApplyExpr, 89) */ + (31, 65), /* '-' => LRAction::Reduce(ApplyExpr, 89) */ + (32, 65), /* '*' => LRAction::Reduce(ApplyExpr, 89) */ + (33, 65), /* '/' => LRAction::Reduce(ApplyExpr, 89) */ + (34, 65), /* '%' => LRAction::Reduce(ApplyExpr, 89) */ + (35, 65), /* 'as' => LRAction::Reduce(ApplyExpr, 89) */ + (38, 36), /* '&' => LRAction::Shift(108) */ + (39, 37), /* '$' => LRAction::Shift(109) */ + (41, 161), /* 'if' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (43, 161), /* 'select' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (44, 65), /* '{' => LRAction::Reduce(ApplyExpr, 89) */ + (46, 65), /* '=>' => LRAction::Reduce(ApplyExpr, 89) */ + (47, 42), /* '~' => LRAction::Shift(122) */ + (48, 43), /* '@' => LRAction::Shift(123) */ + (49, 161), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (50, 161), /* '[' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (51, 65), /* ']' => LRAction::Reduce(ApplyExpr, 89) */ + (52, 161), /* '"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (53, 161), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (54, 161), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (55, 161), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (56, 161), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (57, 161), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (58, 161), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + (59, 161), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LowerPrefixExprOpt, 94) */ + ], + gotos: &[ + (7, 160), /* AtomicExpr => 160 */ + (29, 125), /* DefaultModifier => 125 */ + (56, 161), /* LowerPrefixExpr => 161 */ + (57, 112), /* LowerPrefixExprOpt => 112 */ + (58, 113), /* LowerPrefixOp => 113 */ + (59, 126), /* Modifier => 126 */ + (72, 162), /* Qualif => 162 */ + ], + }, + // State 130 + LR1State { + actions: &[ + (9, 158), /* '(' => LRAction::Reduce(LogicalOrExprList, 55) */ + (31, 158), /* '-' => LRAction::Reduce(LogicalOrExprList, 55) */ + (36, 158), /* 'wait' => LRAction::Reduce(LogicalOrExprList, 55) */ + (37, 158), /* 'call' => LRAction::Reduce(LogicalOrExprList, 55) */ + (38, 158), /* '&' => LRAction::Reduce(LogicalOrExprList, 55) */ + (39, 158), /* '$' => LRAction::Reduce(LogicalOrExprList, 55) */ + (41, 158), /* 'if' => LRAction::Reduce(LogicalOrExprList, 55) */ + (43, 158), /* 'select' => LRAction::Reduce(LogicalOrExprList, 55) */ + (47, 158), /* '~' => LRAction::Reduce(LogicalOrExprList, 55) */ + (48, 158), /* '@' => LRAction::Reduce(LogicalOrExprList, 55) */ + (49, 158), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalOrExprList, 55) */ + (50, 158), /* '[' => LRAction::Reduce(LogicalOrExprList, 55) */ + (52, 158), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (53, 158), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (54, 158), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (55, 158), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (56, 158), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (57, 158), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (58, 158), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (59, 158), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalOrExprList, 55) */ + ], + gotos: &[ + (35, 163), /* Expr => 163 */ + (54, 44), /* LogicalOrExpr => 44 */ + (55, 45), /* LogicalOrExprList => 45 */ + (88, 46), /* SetExpr => 46 */ + ], + }, + // State 131 + LR1State { + actions: &[ + (9, 158), /* '(' => LRAction::Reduce(LogicalOrExprList, 55) */ + (31, 158), /* '-' => LRAction::Reduce(LogicalOrExprList, 55) */ + (36, 158), /* 'wait' => LRAction::Reduce(LogicalOrExprList, 55) */ + (37, 158), /* 'call' => LRAction::Reduce(LogicalOrExprList, 55) */ + (38, 158), /* '&' => LRAction::Reduce(LogicalOrExprList, 55) */ + (39, 158), /* '$' => LRAction::Reduce(LogicalOrExprList, 55) */ + (41, 158), /* 'if' => LRAction::Reduce(LogicalOrExprList, 55) */ + (43, 158), /* 'select' => LRAction::Reduce(LogicalOrExprList, 55) */ + (47, 158), /* '~' => LRAction::Reduce(LogicalOrExprList, 55) */ + (48, 158), /* '@' => LRAction::Reduce(LogicalOrExprList, 55) */ + (49, 158), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalOrExprList, 55) */ + (50, 158), /* '[' => LRAction::Reduce(LogicalOrExprList, 55) */ + (52, 158), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (53, 158), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (54, 158), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (55, 158), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (56, 158), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (57, 158), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (58, 158), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (59, 158), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalOrExprList, 55) */ + ], + gotos: &[ + (35, 164), /* Expr => 164 */ + (54, 44), /* LogicalOrExpr => 44 */ + (55, 45), /* LogicalOrExprList => 45 */ + (88, 46), /* SetExpr => 46 */ + ], + }, + // State 132 + LR1State { + actions: &[(44, 56) /* '{' => LRAction::Shift(165) */], + gotos: &[], + }, + // State 133 + LR1State { + actions: &[ + (9, 158), /* '(' => LRAction::Reduce(LogicalOrExprList, 55) */ + (31, 158), /* '-' => LRAction::Reduce(LogicalOrExprList, 55) */ + (36, 158), /* 'wait' => LRAction::Reduce(LogicalOrExprList, 55) */ + (37, 158), /* 'call' => LRAction::Reduce(LogicalOrExprList, 55) */ + (38, 158), /* '&' => LRAction::Reduce(LogicalOrExprList, 55) */ + (39, 158), /* '$' => LRAction::Reduce(LogicalOrExprList, 55) */ + (41, 158), /* 'if' => LRAction::Reduce(LogicalOrExprList, 55) */ + (43, 158), /* 'select' => LRAction::Reduce(LogicalOrExprList, 55) */ + (47, 158), /* '~' => LRAction::Reduce(LogicalOrExprList, 55) */ + (48, 158), /* '@' => LRAction::Reduce(LogicalOrExprList, 55) */ + (49, 158), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalOrExprList, 55) */ + (50, 158), /* '[' => LRAction::Reduce(LogicalOrExprList, 55) */ + (51, 75), /* ']' => LRAction::Reduce(ArrayOpt, 135) */ + (52, 158), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (53, 158), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (54, 158), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (55, 158), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (56, 158), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (57, 158), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (58, 158), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (59, 158), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalOrExprList, 55) */ + ], + gotos: &[ + (6, 166), /* ArrayOpt => 166 */ + (20, 167), /* CommaSepElements => 167 */ + (35, 168), /* Expr => 168 */ + (54, 44), /* LogicalOrExpr => 44 */ + (55, 45), /* LogicalOrExprList => 45 */ + (88, 46), /* SetExpr => 46 */ + ], + }, + // State 134 + LR1State { + actions: &[ + (9, 218), /* '(' => LRAction::Reduce(String, 142) */ + (10, 218), /* ')' => LRAction::Reduce(String, 142) */ + (12, 218), /* ',' => LRAction::Reduce(String, 142) */ + (17, 218), /* ';' => LRAction::Reduce(String, 142) */ + (20, 218), /* ':=' => LRAction::Reduce(String, 142) */ + (21, 218), /* '||' => LRAction::Reduce(String, 142) */ + (22, 218), /* '&&' => LRAction::Reduce(String, 142) */ + (23, 218), /* '>=' => LRAction::Reduce(String, 142) */ + (24, 218), /* '<=' => LRAction::Reduce(String, 142) */ + (25, 218), /* '>' => LRAction::Reduce(String, 142) */ + (26, 218), /* '<' => LRAction::Reduce(String, 142) */ + (27, 218), /* '!=' => LRAction::Reduce(String, 142) */ + (28, 218), /* '/=' => LRAction::Reduce(String, 142) */ + (29, 218), /* '==' => LRAction::Reduce(String, 142) */ + (30, 218), /* '+' => LRAction::Reduce(String, 142) */ + (31, 218), /* '-' => LRAction::Reduce(String, 142) */ + (32, 218), /* '*' => LRAction::Reduce(String, 142) */ + (33, 218), /* '/' => LRAction::Reduce(String, 142) */ + (34, 218), /* '%' => LRAction::Reduce(String, 142) */ + (35, 218), /* 'as' => LRAction::Reduce(String, 142) */ + (38, 218), /* '&' => LRAction::Reduce(String, 142) */ + (39, 218), /* '$' => LRAction::Reduce(String, 142) */ + (40, 218), /* '?' => LRAction::Reduce(String, 142) */ + (41, 218), /* 'if' => LRAction::Reduce(String, 142) */ + (43, 218), /* 'select' => LRAction::Reduce(String, 142) */ + (44, 218), /* '{' => LRAction::Reduce(String, 142) */ + (46, 218), /* '=>' => LRAction::Reduce(String, 142) */ + (47, 218), /* '~' => LRAction::Reduce(String, 142) */ + (48, 218), /* '@' => LRAction::Reduce(String, 142) */ + (49, 218), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(String, 142) */ + (50, 218), /* '[' => LRAction::Reduce(String, 142) */ + (51, 218), /* ']' => LRAction::Reduce(String, 142) */ + (52, 218), /* '"(\\.|[^"])*"' => LRAction::Reduce(String, 142) */ + (53, 218), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(String, 142) */ + (54, 218), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(String, 142) */ + (55, 218), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(String, 142) */ + (56, 218), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(String, 142) */ + (57, 218), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(String, 142) */ + (58, 218), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(String, 142) */ + (59, 218), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(String, 142) */ + ], + gotos: &[], + }, + // State 135 + LR1State { + actions: &[ + (9, 81), /* '(' => LRAction::Reduce(ByteLiteral, 143) */ + (10, 81), /* ')' => LRAction::Reduce(ByteLiteral, 143) */ + (12, 81), /* ',' => LRAction::Reduce(ByteLiteral, 143) */ + (17, 81), /* ';' => LRAction::Reduce(ByteLiteral, 143) */ + (20, 81), /* ':=' => LRAction::Reduce(ByteLiteral, 143) */ + (21, 81), /* '||' => LRAction::Reduce(ByteLiteral, 143) */ + (22, 81), /* '&&' => LRAction::Reduce(ByteLiteral, 143) */ + (23, 81), /* '>=' => LRAction::Reduce(ByteLiteral, 143) */ + (24, 81), /* '<=' => LRAction::Reduce(ByteLiteral, 143) */ + (25, 81), /* '>' => LRAction::Reduce(ByteLiteral, 143) */ + (26, 81), /* '<' => LRAction::Reduce(ByteLiteral, 143) */ + (27, 81), /* '!=' => LRAction::Reduce(ByteLiteral, 143) */ + (28, 81), /* '/=' => LRAction::Reduce(ByteLiteral, 143) */ + (29, 81), /* '==' => LRAction::Reduce(ByteLiteral, 143) */ + (30, 81), /* '+' => LRAction::Reduce(ByteLiteral, 143) */ + (31, 81), /* '-' => LRAction::Reduce(ByteLiteral, 143) */ + (32, 81), /* '*' => LRAction::Reduce(ByteLiteral, 143) */ + (33, 81), /* '/' => LRAction::Reduce(ByteLiteral, 143) */ + (34, 81), /* '%' => LRAction::Reduce(ByteLiteral, 143) */ + (35, 81), /* 'as' => LRAction::Reduce(ByteLiteral, 143) */ + (38, 81), /* '&' => LRAction::Reduce(ByteLiteral, 143) */ + (39, 81), /* '$' => LRAction::Reduce(ByteLiteral, 143) */ + (40, 81), /* '?' => LRAction::Reduce(ByteLiteral, 143) */ + (41, 81), /* 'if' => LRAction::Reduce(ByteLiteral, 143) */ + (43, 81), /* 'select' => LRAction::Reduce(ByteLiteral, 143) */ + (44, 81), /* '{' => LRAction::Reduce(ByteLiteral, 143) */ + (46, 81), /* '=>' => LRAction::Reduce(ByteLiteral, 143) */ + (47, 81), /* '~' => LRAction::Reduce(ByteLiteral, 143) */ + (48, 81), /* '@' => LRAction::Reduce(ByteLiteral, 143) */ + (49, 81), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ByteLiteral, 143) */ + (50, 81), /* '[' => LRAction::Reduce(ByteLiteral, 143) */ + (51, 81), /* ']' => LRAction::Reduce(ByteLiteral, 143) */ + (52, 81), /* '"(\\.|[^"])*"' => LRAction::Reduce(ByteLiteral, 143) */ + (53, 81), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ByteLiteral, 143) */ + (54, 81), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ByteLiteral, 143) */ + (55, 81), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ByteLiteral, 143) */ + (56, 81), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ByteLiteral, 143) */ + (57, 81), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ByteLiteral, 143) */ + (58, 81), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ByteLiteral, 143) */ + (59, 81), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ByteLiteral, 143) */ + ], + gotos: &[], + }, + // State 136 + LR1State { + actions: &[ + (9, 138), /* '(' => LRAction::Reduce(HexByteLiteral, 144) */ + (10, 138), /* ')' => LRAction::Reduce(HexByteLiteral, 144) */ + (12, 138), /* ',' => LRAction::Reduce(HexByteLiteral, 144) */ + (17, 138), /* ';' => LRAction::Reduce(HexByteLiteral, 144) */ + (20, 138), /* ':=' => LRAction::Reduce(HexByteLiteral, 144) */ + (21, 138), /* '||' => LRAction::Reduce(HexByteLiteral, 144) */ + (22, 138), /* '&&' => LRAction::Reduce(HexByteLiteral, 144) */ + (23, 138), /* '>=' => LRAction::Reduce(HexByteLiteral, 144) */ + (24, 138), /* '<=' => LRAction::Reduce(HexByteLiteral, 144) */ + (25, 138), /* '>' => LRAction::Reduce(HexByteLiteral, 144) */ + (26, 138), /* '<' => LRAction::Reduce(HexByteLiteral, 144) */ + (27, 138), /* '!=' => LRAction::Reduce(HexByteLiteral, 144) */ + (28, 138), /* '/=' => LRAction::Reduce(HexByteLiteral, 144) */ + (29, 138), /* '==' => LRAction::Reduce(HexByteLiteral, 144) */ + (30, 138), /* '+' => LRAction::Reduce(HexByteLiteral, 144) */ + (31, 138), /* '-' => LRAction::Reduce(HexByteLiteral, 144) */ + (32, 138), /* '*' => LRAction::Reduce(HexByteLiteral, 144) */ + (33, 138), /* '/' => LRAction::Reduce(HexByteLiteral, 144) */ + (34, 138), /* '%' => LRAction::Reduce(HexByteLiteral, 144) */ + (35, 138), /* 'as' => LRAction::Reduce(HexByteLiteral, 144) */ + (38, 138), /* '&' => LRAction::Reduce(HexByteLiteral, 144) */ + (39, 138), /* '$' => LRAction::Reduce(HexByteLiteral, 144) */ + (40, 138), /* '?' => LRAction::Reduce(HexByteLiteral, 144) */ + (41, 138), /* 'if' => LRAction::Reduce(HexByteLiteral, 144) */ + (43, 138), /* 'select' => LRAction::Reduce(HexByteLiteral, 144) */ + (44, 138), /* '{' => LRAction::Reduce(HexByteLiteral, 144) */ + (46, 138), /* '=>' => LRAction::Reduce(HexByteLiteral, 144) */ + (47, 138), /* '~' => LRAction::Reduce(HexByteLiteral, 144) */ + (48, 138), /* '@' => LRAction::Reduce(HexByteLiteral, 144) */ + (49, 138), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(HexByteLiteral, 144) */ + (50, 138), /* '[' => LRAction::Reduce(HexByteLiteral, 144) */ + (51, 138), /* ']' => LRAction::Reduce(HexByteLiteral, 144) */ + (52, 138), /* '"(\\.|[^"])*"' => LRAction::Reduce(HexByteLiteral, 144) */ + (53, 138), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(HexByteLiteral, 144) */ + (54, 138), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(HexByteLiteral, 144) */ + (55, 138), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(HexByteLiteral, 144) */ + (56, 138), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(HexByteLiteral, 144) */ + (57, 138), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(HexByteLiteral, 144) */ + (58, 138), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(HexByteLiteral, 144) */ + (59, 138), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(HexByteLiteral, 144) */ + ], + gotos: &[], + }, + // State 137 + LR1State { + actions: &[ + (9, 78), /* '(' => LRAction::Reduce(BinaryInteger, 149) */ + (10, 78), /* ')' => LRAction::Reduce(BinaryInteger, 149) */ + (12, 78), /* ',' => LRAction::Reduce(BinaryInteger, 149) */ + (17, 78), /* ';' => LRAction::Reduce(BinaryInteger, 149) */ + (20, 78), /* ':=' => LRAction::Reduce(BinaryInteger, 149) */ + (21, 78), /* '||' => LRAction::Reduce(BinaryInteger, 149) */ + (22, 78), /* '&&' => LRAction::Reduce(BinaryInteger, 149) */ + (23, 78), /* '>=' => LRAction::Reduce(BinaryInteger, 149) */ + (24, 78), /* '<=' => LRAction::Reduce(BinaryInteger, 149) */ + (25, 78), /* '>' => LRAction::Reduce(BinaryInteger, 149) */ + (26, 78), /* '<' => LRAction::Reduce(BinaryInteger, 149) */ + (27, 78), /* '!=' => LRAction::Reduce(BinaryInteger, 149) */ + (28, 78), /* '/=' => LRAction::Reduce(BinaryInteger, 149) */ + (29, 78), /* '==' => LRAction::Reduce(BinaryInteger, 149) */ + (30, 78), /* '+' => LRAction::Reduce(BinaryInteger, 149) */ + (31, 78), /* '-' => LRAction::Reduce(BinaryInteger, 149) */ + (32, 78), /* '*' => LRAction::Reduce(BinaryInteger, 149) */ + (33, 78), /* '/' => LRAction::Reduce(BinaryInteger, 149) */ + (34, 78), /* '%' => LRAction::Reduce(BinaryInteger, 149) */ + (35, 78), /* 'as' => LRAction::Reduce(BinaryInteger, 149) */ + (38, 78), /* '&' => LRAction::Reduce(BinaryInteger, 149) */ + (39, 78), /* '$' => LRAction::Reduce(BinaryInteger, 149) */ + (40, 78), /* '?' => LRAction::Reduce(BinaryInteger, 149) */ + (41, 78), /* 'if' => LRAction::Reduce(BinaryInteger, 149) */ + (43, 78), /* 'select' => LRAction::Reduce(BinaryInteger, 149) */ + (44, 78), /* '{' => LRAction::Reduce(BinaryInteger, 149) */ + (46, 78), /* '=>' => LRAction::Reduce(BinaryInteger, 149) */ + (47, 78), /* '~' => LRAction::Reduce(BinaryInteger, 149) */ + (48, 78), /* '@' => LRAction::Reduce(BinaryInteger, 149) */ + (49, 78), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(BinaryInteger, 149) */ + (50, 78), /* '[' => LRAction::Reduce(BinaryInteger, 149) */ + (51, 78), /* ']' => LRAction::Reduce(BinaryInteger, 149) */ + (52, 78), /* '"(\\.|[^"])*"' => LRAction::Reduce(BinaryInteger, 149) */ + (53, 78), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(BinaryInteger, 149) */ + (54, 78), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(BinaryInteger, 149) */ + (55, 78), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(BinaryInteger, 149) */ + (56, 78), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(BinaryInteger, 149) */ + (57, 78), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(BinaryInteger, 149) */ + (58, 78), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(BinaryInteger, 149) */ + (59, 78), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(BinaryInteger, 149) */ + ], + gotos: &[], + }, + // State 138 + LR1State { + actions: &[ + (9, 171), /* '(' => LRAction::Reduce(OctalInteger, 150) */ + (10, 171), /* ')' => LRAction::Reduce(OctalInteger, 150) */ + (12, 171), /* ',' => LRAction::Reduce(OctalInteger, 150) */ + (17, 171), /* ';' => LRAction::Reduce(OctalInteger, 150) */ + (20, 171), /* ':=' => LRAction::Reduce(OctalInteger, 150) */ + (21, 171), /* '||' => LRAction::Reduce(OctalInteger, 150) */ + (22, 171), /* '&&' => LRAction::Reduce(OctalInteger, 150) */ + (23, 171), /* '>=' => LRAction::Reduce(OctalInteger, 150) */ + (24, 171), /* '<=' => LRAction::Reduce(OctalInteger, 150) */ + (25, 171), /* '>' => LRAction::Reduce(OctalInteger, 150) */ + (26, 171), /* '<' => LRAction::Reduce(OctalInteger, 150) */ + (27, 171), /* '!=' => LRAction::Reduce(OctalInteger, 150) */ + (28, 171), /* '/=' => LRAction::Reduce(OctalInteger, 150) */ + (29, 171), /* '==' => LRAction::Reduce(OctalInteger, 150) */ + (30, 171), /* '+' => LRAction::Reduce(OctalInteger, 150) */ + (31, 171), /* '-' => LRAction::Reduce(OctalInteger, 150) */ + (32, 171), /* '*' => LRAction::Reduce(OctalInteger, 150) */ + (33, 171), /* '/' => LRAction::Reduce(OctalInteger, 150) */ + (34, 171), /* '%' => LRAction::Reduce(OctalInteger, 150) */ + (35, 171), /* 'as' => LRAction::Reduce(OctalInteger, 150) */ + (38, 171), /* '&' => LRAction::Reduce(OctalInteger, 150) */ + (39, 171), /* '$' => LRAction::Reduce(OctalInteger, 150) */ + (40, 171), /* '?' => LRAction::Reduce(OctalInteger, 150) */ + (41, 171), /* 'if' => LRAction::Reduce(OctalInteger, 150) */ + (43, 171), /* 'select' => LRAction::Reduce(OctalInteger, 150) */ + (44, 171), /* '{' => LRAction::Reduce(OctalInteger, 150) */ + (46, 171), /* '=>' => LRAction::Reduce(OctalInteger, 150) */ + (47, 171), /* '~' => LRAction::Reduce(OctalInteger, 150) */ + (48, 171), /* '@' => LRAction::Reduce(OctalInteger, 150) */ + (49, 171), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(OctalInteger, 150) */ + (50, 171), /* '[' => LRAction::Reduce(OctalInteger, 150) */ + (51, 171), /* ']' => LRAction::Reduce(OctalInteger, 150) */ + (52, 171), /* '"(\\.|[^"])*"' => LRAction::Reduce(OctalInteger, 150) */ + (53, 171), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(OctalInteger, 150) */ + (54, 171), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(OctalInteger, 150) */ + (55, 171), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(OctalInteger, 150) */ + (56, 171), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(OctalInteger, 150) */ + (57, 171), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(OctalInteger, 150) */ + (58, 171), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(OctalInteger, 150) */ + (59, 171), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(OctalInteger, 150) */ + ], + gotos: &[], + }, + // State 139 + LR1State { + actions: &[ + (9, 139), /* '(' => LRAction::Reduce(HexadecimalInteger, 151) */ + (10, 139), /* ')' => LRAction::Reduce(HexadecimalInteger, 151) */ + (12, 139), /* ',' => LRAction::Reduce(HexadecimalInteger, 151) */ + (17, 139), /* ';' => LRAction::Reduce(HexadecimalInteger, 151) */ + (20, 139), /* ':=' => LRAction::Reduce(HexadecimalInteger, 151) */ + (21, 139), /* '||' => LRAction::Reduce(HexadecimalInteger, 151) */ + (22, 139), /* '&&' => LRAction::Reduce(HexadecimalInteger, 151) */ + (23, 139), /* '>=' => LRAction::Reduce(HexadecimalInteger, 151) */ + (24, 139), /* '<=' => LRAction::Reduce(HexadecimalInteger, 151) */ + (25, 139), /* '>' => LRAction::Reduce(HexadecimalInteger, 151) */ + (26, 139), /* '<' => LRAction::Reduce(HexadecimalInteger, 151) */ + (27, 139), /* '!=' => LRAction::Reduce(HexadecimalInteger, 151) */ + (28, 139), /* '/=' => LRAction::Reduce(HexadecimalInteger, 151) */ + (29, 139), /* '==' => LRAction::Reduce(HexadecimalInteger, 151) */ + (30, 139), /* '+' => LRAction::Reduce(HexadecimalInteger, 151) */ + (31, 139), /* '-' => LRAction::Reduce(HexadecimalInteger, 151) */ + (32, 139), /* '*' => LRAction::Reduce(HexadecimalInteger, 151) */ + (33, 139), /* '/' => LRAction::Reduce(HexadecimalInteger, 151) */ + (34, 139), /* '%' => LRAction::Reduce(HexadecimalInteger, 151) */ + (35, 139), /* 'as' => LRAction::Reduce(HexadecimalInteger, 151) */ + (38, 139), /* '&' => LRAction::Reduce(HexadecimalInteger, 151) */ + (39, 139), /* '$' => LRAction::Reduce(HexadecimalInteger, 151) */ + (40, 139), /* '?' => LRAction::Reduce(HexadecimalInteger, 151) */ + (41, 139), /* 'if' => LRAction::Reduce(HexadecimalInteger, 151) */ + (43, 139), /* 'select' => LRAction::Reduce(HexadecimalInteger, 151) */ + (44, 139), /* '{' => LRAction::Reduce(HexadecimalInteger, 151) */ + (46, 139), /* '=>' => LRAction::Reduce(HexadecimalInteger, 151) */ + (47, 139), /* '~' => LRAction::Reduce(HexadecimalInteger, 151) */ + (48, 139), /* '@' => LRAction::Reduce(HexadecimalInteger, 151) */ + (49, 139), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(HexadecimalInteger, 151) */ + (50, 139), /* '[' => LRAction::Reduce(HexadecimalInteger, 151) */ + (51, 139), /* ']' => LRAction::Reduce(HexadecimalInteger, 151) */ + (52, 139), /* '"(\\.|[^"])*"' => LRAction::Reduce(HexadecimalInteger, 151) */ + (53, 139), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(HexadecimalInteger, 151) */ + (54, 139), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(HexadecimalInteger, 151) */ + (55, 139), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(HexadecimalInteger, 151) */ + (56, 139), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(HexadecimalInteger, 151) */ + (57, 139), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(HexadecimalInteger, 151) */ + (58, 139), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(HexadecimalInteger, 151) */ + (59, 139), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(HexadecimalInteger, 151) */ + ], + gotos: &[], + }, + // State 140 + LR1State { + actions: &[ + (9, 141), /* '(' => LRAction::Reduce(Ieee754Float, 152) */ + (10, 141), /* ')' => LRAction::Reduce(Ieee754Float, 152) */ + (12, 141), /* ',' => LRAction::Reduce(Ieee754Float, 152) */ + (17, 141), /* ';' => LRAction::Reduce(Ieee754Float, 152) */ + (20, 141), /* ':=' => LRAction::Reduce(Ieee754Float, 152) */ + (21, 141), /* '||' => LRAction::Reduce(Ieee754Float, 152) */ + (22, 141), /* '&&' => LRAction::Reduce(Ieee754Float, 152) */ + (23, 141), /* '>=' => LRAction::Reduce(Ieee754Float, 152) */ + (24, 141), /* '<=' => LRAction::Reduce(Ieee754Float, 152) */ + (25, 141), /* '>' => LRAction::Reduce(Ieee754Float, 152) */ + (26, 141), /* '<' => LRAction::Reduce(Ieee754Float, 152) */ + (27, 141), /* '!=' => LRAction::Reduce(Ieee754Float, 152) */ + (28, 141), /* '/=' => LRAction::Reduce(Ieee754Float, 152) */ + (29, 141), /* '==' => LRAction::Reduce(Ieee754Float, 152) */ + (30, 141), /* '+' => LRAction::Reduce(Ieee754Float, 152) */ + (31, 141), /* '-' => LRAction::Reduce(Ieee754Float, 152) */ + (32, 141), /* '*' => LRAction::Reduce(Ieee754Float, 152) */ + (33, 141), /* '/' => LRAction::Reduce(Ieee754Float, 152) */ + (34, 141), /* '%' => LRAction::Reduce(Ieee754Float, 152) */ + (35, 141), /* 'as' => LRAction::Reduce(Ieee754Float, 152) */ + (38, 141), /* '&' => LRAction::Reduce(Ieee754Float, 152) */ + (39, 141), /* '$' => LRAction::Reduce(Ieee754Float, 152) */ + (40, 141), /* '?' => LRAction::Reduce(Ieee754Float, 152) */ + (41, 141), /* 'if' => LRAction::Reduce(Ieee754Float, 152) */ + (43, 141), /* 'select' => LRAction::Reduce(Ieee754Float, 152) */ + (44, 141), /* '{' => LRAction::Reduce(Ieee754Float, 152) */ + (46, 141), /* '=>' => LRAction::Reduce(Ieee754Float, 152) */ + (47, 141), /* '~' => LRAction::Reduce(Ieee754Float, 152) */ + (48, 141), /* '@' => LRAction::Reduce(Ieee754Float, 152) */ + (49, 141), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Ieee754Float, 152) */ + (50, 141), /* '[' => LRAction::Reduce(Ieee754Float, 152) */ + (51, 141), /* ']' => LRAction::Reduce(Ieee754Float, 152) */ + (52, 141), /* '"(\\.|[^"])*"' => LRAction::Reduce(Ieee754Float, 152) */ + (53, 141), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Ieee754Float, 152) */ + (54, 141), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Ieee754Float, 152) */ + (55, 141), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Ieee754Float, 152) */ + (56, 141), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Ieee754Float, 152) */ + (57, 141), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Ieee754Float, 152) */ + (58, 141), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Ieee754Float, 152) */ + (59, 141), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Ieee754Float, 152) */ + ], + gotos: &[], + }, + // State 141 + LR1State { + actions: &[ + (9, 190), /* '(' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (10, 190), /* ')' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (12, 190), /* ',' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (17, 190), /* ';' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (20, 190), /* ':=' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (21, 190), /* '||' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (22, 190), /* '&&' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (23, 190), /* '>=' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (24, 190), /* '<=' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (25, 190), /* '>' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (26, 190), /* '<' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (27, 190), /* '!=' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (28, 190), /* '/=' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (29, 190), /* '==' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (30, 190), /* '+' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (31, 190), /* '-' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (32, 190), /* '*' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (33, 190), /* '/' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (34, 190), /* '%' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (35, 190), /* 'as' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (38, 190), /* '&' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (39, 190), /* '$' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (40, 190), /* '?' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (41, 190), /* 'if' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (43, 190), /* 'select' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (44, 190), /* '{' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (46, 190), /* '=>' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (47, 190), /* '~' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (48, 190), /* '@' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (49, 190), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (50, 190), /* '[' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (51, 190), /* ']' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (52, 190), /* '"(\\.|[^"])*"' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (53, 190), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (54, 190), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (55, 190), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (56, 190), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (57, 190), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (58, 190), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Rfc3339DateTime, 153) */ + (59, 190), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Rfc3339DateTime, 153) */ + ], + gotos: &[], + }, + // State 142 + LR1State { + actions: &[ + (9, 147), /* '(' => LRAction::Reduce(Literal, 127) */ + (10, 147), /* ')' => LRAction::Reduce(Literal, 127) */ + (12, 147), /* ',' => LRAction::Reduce(Literal, 127) */ + (17, 147), /* ';' => LRAction::Reduce(Literal, 127) */ + (20, 147), /* ':=' => LRAction::Reduce(Literal, 127) */ + (21, 147), /* '||' => LRAction::Reduce(Literal, 127) */ + (22, 147), /* '&&' => LRAction::Reduce(Literal, 127) */ + (23, 147), /* '>=' => LRAction::Reduce(Literal, 127) */ + (24, 147), /* '<=' => LRAction::Reduce(Literal, 127) */ + (25, 147), /* '>' => LRAction::Reduce(Literal, 127) */ + (26, 147), /* '<' => LRAction::Reduce(Literal, 127) */ + (27, 147), /* '!=' => LRAction::Reduce(Literal, 127) */ + (28, 147), /* '/=' => LRAction::Reduce(Literal, 127) */ + (29, 147), /* '==' => LRAction::Reduce(Literal, 127) */ + (30, 147), /* '+' => LRAction::Reduce(Literal, 127) */ + (31, 147), /* '-' => LRAction::Reduce(Literal, 127) */ + (32, 147), /* '*' => LRAction::Reduce(Literal, 127) */ + (33, 147), /* '/' => LRAction::Reduce(Literal, 127) */ + (34, 147), /* '%' => LRAction::Reduce(Literal, 127) */ + (35, 147), /* 'as' => LRAction::Reduce(Literal, 127) */ + (38, 147), /* '&' => LRAction::Reduce(Literal, 127) */ + (39, 147), /* '$' => LRAction::Reduce(Literal, 127) */ + (40, 147), /* '?' => LRAction::Reduce(Literal, 127) */ + (41, 147), /* 'if' => LRAction::Reduce(Literal, 127) */ + (43, 147), /* 'select' => LRAction::Reduce(Literal, 127) */ + (44, 147), /* '{' => LRAction::Reduce(Literal, 127) */ + (46, 147), /* '=>' => LRAction::Reduce(Literal, 127) */ + (47, 147), /* '~' => LRAction::Reduce(Literal, 127) */ + (48, 147), /* '@' => LRAction::Reduce(Literal, 127) */ + (49, 147), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Literal, 127) */ + (50, 147), /* '[' => LRAction::Reduce(Literal, 127) */ + (51, 147), /* ']' => LRAction::Reduce(Literal, 127) */ + (52, 147), /* '"(\\.|[^"])*"' => LRAction::Reduce(Literal, 127) */ + (53, 147), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Literal, 127) */ + (54, 147), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Literal, 127) */ + (55, 147), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 127) */ + (56, 147), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 127) */ + (57, 147), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 127) */ + (58, 147), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 127) */ + (59, 147), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Literal, 127) */ + ], + gotos: &[], + }, + // State 143 + LR1State { + actions: &[ + (9, 167), /* '(' => LRAction::Reduce(Numeric, 145) */ + (10, 167), /* ')' => LRAction::Reduce(Numeric, 145) */ + (12, 167), /* ',' => LRAction::Reduce(Numeric, 145) */ + (17, 167), /* ';' => LRAction::Reduce(Numeric, 145) */ + (20, 167), /* ':=' => LRAction::Reduce(Numeric, 145) */ + (21, 167), /* '||' => LRAction::Reduce(Numeric, 145) */ + (22, 167), /* '&&' => LRAction::Reduce(Numeric, 145) */ + (23, 167), /* '>=' => LRAction::Reduce(Numeric, 145) */ + (24, 167), /* '<=' => LRAction::Reduce(Numeric, 145) */ + (25, 167), /* '>' => LRAction::Reduce(Numeric, 145) */ + (26, 167), /* '<' => LRAction::Reduce(Numeric, 145) */ + (27, 167), /* '!=' => LRAction::Reduce(Numeric, 145) */ + (28, 167), /* '/=' => LRAction::Reduce(Numeric, 145) */ + (29, 167), /* '==' => LRAction::Reduce(Numeric, 145) */ + (30, 167), /* '+' => LRAction::Reduce(Numeric, 145) */ + (31, 167), /* '-' => LRAction::Reduce(Numeric, 145) */ + (32, 167), /* '*' => LRAction::Reduce(Numeric, 145) */ + (33, 167), /* '/' => LRAction::Reduce(Numeric, 145) */ + (34, 167), /* '%' => LRAction::Reduce(Numeric, 145) */ + (35, 167), /* 'as' => LRAction::Reduce(Numeric, 145) */ + (38, 167), /* '&' => LRAction::Reduce(Numeric, 145) */ + (39, 167), /* '$' => LRAction::Reduce(Numeric, 145) */ + (40, 167), /* '?' => LRAction::Reduce(Numeric, 145) */ + (41, 167), /* 'if' => LRAction::Reduce(Numeric, 145) */ + (43, 167), /* 'select' => LRAction::Reduce(Numeric, 145) */ + (44, 167), /* '{' => LRAction::Reduce(Numeric, 145) */ + (46, 167), /* '=>' => LRAction::Reduce(Numeric, 145) */ + (47, 167), /* '~' => LRAction::Reduce(Numeric, 145) */ + (48, 167), /* '@' => LRAction::Reduce(Numeric, 145) */ + (49, 167), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Numeric, 145) */ + (50, 167), /* '[' => LRAction::Reduce(Numeric, 145) */ + (51, 167), /* ']' => LRAction::Reduce(Numeric, 145) */ + (52, 167), /* '"(\\.|[^"])*"' => LRAction::Reduce(Numeric, 145) */ + (53, 167), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Numeric, 145) */ + (54, 167), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Numeric, 145) */ + (55, 167), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 145) */ + (56, 167), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 145) */ + (57, 167), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 145) */ + (58, 167), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 145) */ + (59, 167), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Numeric, 145) */ + ], + gotos: &[], + }, + // State 144 + LR1State { + actions: &[ + (9, 149), /* '(' => LRAction::Reduce(Literal, 129) */ + (10, 149), /* ')' => LRAction::Reduce(Literal, 129) */ + (12, 149), /* ',' => LRAction::Reduce(Literal, 129) */ + (17, 149), /* ';' => LRAction::Reduce(Literal, 129) */ + (20, 149), /* ':=' => LRAction::Reduce(Literal, 129) */ + (21, 149), /* '||' => LRAction::Reduce(Literal, 129) */ + (22, 149), /* '&&' => LRAction::Reduce(Literal, 129) */ + (23, 149), /* '>=' => LRAction::Reduce(Literal, 129) */ + (24, 149), /* '<=' => LRAction::Reduce(Literal, 129) */ + (25, 149), /* '>' => LRAction::Reduce(Literal, 129) */ + (26, 149), /* '<' => LRAction::Reduce(Literal, 129) */ + (27, 149), /* '!=' => LRAction::Reduce(Literal, 129) */ + (28, 149), /* '/=' => LRAction::Reduce(Literal, 129) */ + (29, 149), /* '==' => LRAction::Reduce(Literal, 129) */ + (30, 149), /* '+' => LRAction::Reduce(Literal, 129) */ + (31, 149), /* '-' => LRAction::Reduce(Literal, 129) */ + (32, 149), /* '*' => LRAction::Reduce(Literal, 129) */ + (33, 149), /* '/' => LRAction::Reduce(Literal, 129) */ + (34, 149), /* '%' => LRAction::Reduce(Literal, 129) */ + (35, 149), /* 'as' => LRAction::Reduce(Literal, 129) */ + (38, 149), /* '&' => LRAction::Reduce(Literal, 129) */ + (39, 149), /* '$' => LRAction::Reduce(Literal, 129) */ + (40, 149), /* '?' => LRAction::Reduce(Literal, 129) */ + (41, 149), /* 'if' => LRAction::Reduce(Literal, 129) */ + (43, 149), /* 'select' => LRAction::Reduce(Literal, 129) */ + (44, 149), /* '{' => LRAction::Reduce(Literal, 129) */ + (46, 149), /* '=>' => LRAction::Reduce(Literal, 129) */ + (47, 149), /* '~' => LRAction::Reduce(Literal, 129) */ + (48, 149), /* '@' => LRAction::Reduce(Literal, 129) */ + (49, 149), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Literal, 129) */ + (50, 149), /* '[' => LRAction::Reduce(Literal, 129) */ + (51, 149), /* ']' => LRAction::Reduce(Literal, 129) */ + (52, 149), /* '"(\\.|[^"])*"' => LRAction::Reduce(Literal, 129) */ + (53, 149), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Literal, 129) */ + (54, 149), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Literal, 129) */ + (55, 149), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 129) */ + (56, 149), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 129) */ + (57, 149), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 129) */ + (58, 149), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 129) */ + (59, 149), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Literal, 129) */ + ], + gotos: &[], + }, + // State 145 + LR1State { + actions: &[ + (9, 159), /* '(' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (10, 159), /* ')' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (12, 159), /* ',' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (17, 159), /* ';' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (20, 159), /* ':=' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (21, 159), /* '||' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (22, 159), /* '&&' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (23, 159), /* '>=' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (24, 159), /* '<=' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (25, 159), /* '>' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (26, 159), /* '<' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (27, 159), /* '!=' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (28, 159), /* '/=' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (29, 159), /* '==' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (30, 159), /* '+' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (31, 159), /* '-' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (32, 159), /* '*' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (33, 159), /* '/' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (34, 159), /* '%' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (35, 159), /* 'as' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (38, 159), /* '&' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (39, 159), /* '$' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (41, 159), /* 'if' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (43, 159), /* 'select' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (44, 159), /* '{' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (46, 159), /* '=>' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (47, 159), /* '~' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (48, 159), /* '@' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (49, 159), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (50, 159), /* '[' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (51, 159), /* ']' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (52, 159), /* '"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (53, 159), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (54, 159), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (55, 159), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (56, 159), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (57, 159), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (58, 159), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LowerPrefixExpr, 92) */ + (59, 159), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LowerPrefixExpr, 92) */ + ], + gotos: &[], + }, + // State 146 + LR1State { + actions: &[ + (9, 150), /* '(' => LRAction::Reduce(Literal, 130) */ + (10, 150), /* ')' => LRAction::Reduce(Literal, 130) */ + (12, 150), /* ',' => LRAction::Reduce(Literal, 130) */ + (17, 150), /* ';' => LRAction::Reduce(Literal, 130) */ + (20, 150), /* ':=' => LRAction::Reduce(Literal, 130) */ + (21, 150), /* '||' => LRAction::Reduce(Literal, 130) */ + (22, 150), /* '&&' => LRAction::Reduce(Literal, 130) */ + (23, 150), /* '>=' => LRAction::Reduce(Literal, 130) */ + (24, 150), /* '<=' => LRAction::Reduce(Literal, 130) */ + (25, 150), /* '>' => LRAction::Reduce(Literal, 130) */ + (26, 150), /* '<' => LRAction::Reduce(Literal, 130) */ + (27, 150), /* '!=' => LRAction::Reduce(Literal, 130) */ + (28, 150), /* '/=' => LRAction::Reduce(Literal, 130) */ + (29, 150), /* '==' => LRAction::Reduce(Literal, 130) */ + (30, 150), /* '+' => LRAction::Reduce(Literal, 130) */ + (31, 150), /* '-' => LRAction::Reduce(Literal, 130) */ + (32, 150), /* '*' => LRAction::Reduce(Literal, 130) */ + (33, 150), /* '/' => LRAction::Reduce(Literal, 130) */ + (34, 150), /* '%' => LRAction::Reduce(Literal, 130) */ + (35, 150), /* 'as' => LRAction::Reduce(Literal, 130) */ + (38, 150), /* '&' => LRAction::Reduce(Literal, 130) */ + (39, 150), /* '$' => LRAction::Reduce(Literal, 130) */ + (40, 150), /* '?' => LRAction::Reduce(Literal, 130) */ + (41, 150), /* 'if' => LRAction::Reduce(Literal, 130) */ + (43, 150), /* 'select' => LRAction::Reduce(Literal, 130) */ + (44, 150), /* '{' => LRAction::Reduce(Literal, 130) */ + (46, 150), /* '=>' => LRAction::Reduce(Literal, 130) */ + (47, 150), /* '~' => LRAction::Reduce(Literal, 130) */ + (48, 150), /* '@' => LRAction::Reduce(Literal, 130) */ + (49, 150), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Literal, 130) */ + (50, 150), /* '[' => LRAction::Reduce(Literal, 130) */ + (51, 150), /* ']' => LRAction::Reduce(Literal, 130) */ + (52, 150), /* '"(\\.|[^"])*"' => LRAction::Reduce(Literal, 130) */ + (53, 150), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Literal, 130) */ + (54, 150), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Literal, 130) */ + (55, 150), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 130) */ + (56, 150), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 130) */ + (57, 150), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 130) */ + (58, 150), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 130) */ + (59, 150), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Literal, 130) */ + ], + gotos: &[], + }, + // State 147 + LR1State { + actions: &[ + (9, 169), /* '(' => LRAction::Reduce(Numeric, 147) */ + (10, 169), /* ')' => LRAction::Reduce(Numeric, 147) */ + (12, 169), /* ',' => LRAction::Reduce(Numeric, 147) */ + (17, 169), /* ';' => LRAction::Reduce(Numeric, 147) */ + (20, 169), /* ':=' => LRAction::Reduce(Numeric, 147) */ + (21, 169), /* '||' => LRAction::Reduce(Numeric, 147) */ + (22, 169), /* '&&' => LRAction::Reduce(Numeric, 147) */ + (23, 169), /* '>=' => LRAction::Reduce(Numeric, 147) */ + (24, 169), /* '<=' => LRAction::Reduce(Numeric, 147) */ + (25, 169), /* '>' => LRAction::Reduce(Numeric, 147) */ + (26, 169), /* '<' => LRAction::Reduce(Numeric, 147) */ + (27, 169), /* '!=' => LRAction::Reduce(Numeric, 147) */ + (28, 169), /* '/=' => LRAction::Reduce(Numeric, 147) */ + (29, 169), /* '==' => LRAction::Reduce(Numeric, 147) */ + (30, 169), /* '+' => LRAction::Reduce(Numeric, 147) */ + (31, 169), /* '-' => LRAction::Reduce(Numeric, 147) */ + (32, 169), /* '*' => LRAction::Reduce(Numeric, 147) */ + (33, 169), /* '/' => LRAction::Reduce(Numeric, 147) */ + (34, 169), /* '%' => LRAction::Reduce(Numeric, 147) */ + (35, 169), /* 'as' => LRAction::Reduce(Numeric, 147) */ + (38, 169), /* '&' => LRAction::Reduce(Numeric, 147) */ + (39, 169), /* '$' => LRAction::Reduce(Numeric, 147) */ + (40, 169), /* '?' => LRAction::Reduce(Numeric, 147) */ + (41, 169), /* 'if' => LRAction::Reduce(Numeric, 147) */ + (43, 169), /* 'select' => LRAction::Reduce(Numeric, 147) */ + (44, 169), /* '{' => LRAction::Reduce(Numeric, 147) */ + (46, 169), /* '=>' => LRAction::Reduce(Numeric, 147) */ + (47, 169), /* '~' => LRAction::Reduce(Numeric, 147) */ + (48, 169), /* '@' => LRAction::Reduce(Numeric, 147) */ + (49, 169), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Numeric, 147) */ + (50, 169), /* '[' => LRAction::Reduce(Numeric, 147) */ + (51, 169), /* ']' => LRAction::Reduce(Numeric, 147) */ + (52, 169), /* '"(\\.|[^"])*"' => LRAction::Reduce(Numeric, 147) */ + (53, 169), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Numeric, 147) */ + (54, 169), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Numeric, 147) */ + (55, 169), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 147) */ + (56, 169), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 147) */ + (57, 169), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 147) */ + (58, 169), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 147) */ + (59, 169), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Numeric, 147) */ + ], + gotos: &[], + }, + // State 148 + LR1State { + actions: &[ + (9, 170), /* '(' => LRAction::Reduce(Numeric, 148) */ + (10, 170), /* ')' => LRAction::Reduce(Numeric, 148) */ + (12, 170), /* ',' => LRAction::Reduce(Numeric, 148) */ + (17, 170), /* ';' => LRAction::Reduce(Numeric, 148) */ + (20, 170), /* ':=' => LRAction::Reduce(Numeric, 148) */ + (21, 170), /* '||' => LRAction::Reduce(Numeric, 148) */ + (22, 170), /* '&&' => LRAction::Reduce(Numeric, 148) */ + (23, 170), /* '>=' => LRAction::Reduce(Numeric, 148) */ + (24, 170), /* '<=' => LRAction::Reduce(Numeric, 148) */ + (25, 170), /* '>' => LRAction::Reduce(Numeric, 148) */ + (26, 170), /* '<' => LRAction::Reduce(Numeric, 148) */ + (27, 170), /* '!=' => LRAction::Reduce(Numeric, 148) */ + (28, 170), /* '/=' => LRAction::Reduce(Numeric, 148) */ + (29, 170), /* '==' => LRAction::Reduce(Numeric, 148) */ + (30, 170), /* '+' => LRAction::Reduce(Numeric, 148) */ + (31, 170), /* '-' => LRAction::Reduce(Numeric, 148) */ + (32, 170), /* '*' => LRAction::Reduce(Numeric, 148) */ + (33, 170), /* '/' => LRAction::Reduce(Numeric, 148) */ + (34, 170), /* '%' => LRAction::Reduce(Numeric, 148) */ + (35, 170), /* 'as' => LRAction::Reduce(Numeric, 148) */ + (38, 170), /* '&' => LRAction::Reduce(Numeric, 148) */ + (39, 170), /* '$' => LRAction::Reduce(Numeric, 148) */ + (40, 170), /* '?' => LRAction::Reduce(Numeric, 148) */ + (41, 170), /* 'if' => LRAction::Reduce(Numeric, 148) */ + (43, 170), /* 'select' => LRAction::Reduce(Numeric, 148) */ + (44, 170), /* '{' => LRAction::Reduce(Numeric, 148) */ + (46, 170), /* '=>' => LRAction::Reduce(Numeric, 148) */ + (47, 170), /* '~' => LRAction::Reduce(Numeric, 148) */ + (48, 170), /* '@' => LRAction::Reduce(Numeric, 148) */ + (49, 170), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Numeric, 148) */ + (50, 170), /* '[' => LRAction::Reduce(Numeric, 148) */ + (51, 170), /* ']' => LRAction::Reduce(Numeric, 148) */ + (52, 170), /* '"(\\.|[^"])*"' => LRAction::Reduce(Numeric, 148) */ + (53, 170), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Numeric, 148) */ + (54, 170), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Numeric, 148) */ + (55, 170), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 148) */ + (56, 170), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 148) */ + (57, 170), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 148) */ + (58, 170), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 148) */ + (59, 170), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Numeric, 148) */ + ], + gotos: &[], + }, + // State 149 + LR1State { + actions: &[ + (9, 85), /* '(' => LRAction::Reduce(Callable, 100) */ + (10, 85), /* ')' => LRAction::Reduce(Callable, 100) */ + (12, 85), /* ',' => LRAction::Reduce(Callable, 100) */ + (17, 85), /* ';' => LRAction::Reduce(Callable, 100) */ + (20, 85), /* ':=' => LRAction::Reduce(Callable, 100) */ + (21, 85), /* '||' => LRAction::Reduce(Callable, 100) */ + (22, 85), /* '&&' => LRAction::Reduce(Callable, 100) */ + (23, 85), /* '>=' => LRAction::Reduce(Callable, 100) */ + (24, 85), /* '<=' => LRAction::Reduce(Callable, 100) */ + (25, 85), /* '>' => LRAction::Reduce(Callable, 100) */ + (26, 85), /* '<' => LRAction::Reduce(Callable, 100) */ + (27, 85), /* '!=' => LRAction::Reduce(Callable, 100) */ + (28, 85), /* '/=' => LRAction::Reduce(Callable, 100) */ + (29, 85), /* '==' => LRAction::Reduce(Callable, 100) */ + (30, 85), /* '+' => LRAction::Reduce(Callable, 100) */ + (31, 85), /* '-' => LRAction::Reduce(Callable, 100) */ + (32, 85), /* '*' => LRAction::Reduce(Callable, 100) */ + (33, 85), /* '/' => LRAction::Reduce(Callable, 100) */ + (34, 85), /* '%' => LRAction::Reduce(Callable, 100) */ + (35, 85), /* 'as' => LRAction::Reduce(Callable, 100) */ + (38, 85), /* '&' => LRAction::Reduce(Callable, 100) */ + (39, 85), /* '$' => LRAction::Reduce(Callable, 100) */ + (41, 85), /* 'if' => LRAction::Reduce(Callable, 100) */ + (43, 85), /* 'select' => LRAction::Reduce(Callable, 100) */ + (44, 85), /* '{' => LRAction::Reduce(Callable, 100) */ + (46, 85), /* '=>' => LRAction::Reduce(Callable, 100) */ + (47, 85), /* '~' => LRAction::Reduce(Callable, 100) */ + (48, 85), /* '@' => LRAction::Reduce(Callable, 100) */ + (49, 85), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Callable, 100) */ + (50, 85), /* '[' => LRAction::Reduce(Callable, 100) */ + (51, 85), /* ']' => LRAction::Reduce(Callable, 100) */ + (52, 85), /* '"(\\.|[^"])*"' => LRAction::Reduce(Callable, 100) */ + (53, 85), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Callable, 100) */ + (54, 85), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Callable, 100) */ + (55, 85), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 100) */ + (56, 85), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 100) */ + (57, 85), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 100) */ + (58, 85), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 100) */ + (59, 85), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Callable, 100) */ + ], + gotos: &[], + }, + // State 150 + LR1State { + actions: &[ + (9, 88), /* '(' => LRAction::Reduce(CallableOpt, 103) */ + (10, 88), /* ')' => LRAction::Reduce(CallableOpt, 103) */ + (12, 88), /* ',' => LRAction::Reduce(CallableOpt, 103) */ + (17, 88), /* ';' => LRAction::Reduce(CallableOpt, 103) */ + (20, 88), /* ':=' => LRAction::Reduce(CallableOpt, 103) */ + (21, 88), /* '||' => LRAction::Reduce(CallableOpt, 103) */ + (22, 88), /* '&&' => LRAction::Reduce(CallableOpt, 103) */ + (23, 88), /* '>=' => LRAction::Reduce(CallableOpt, 103) */ + (24, 88), /* '<=' => LRAction::Reduce(CallableOpt, 103) */ + (25, 88), /* '>' => LRAction::Reduce(CallableOpt, 103) */ + (26, 88), /* '<' => LRAction::Reduce(CallableOpt, 103) */ + (27, 88), /* '!=' => LRAction::Reduce(CallableOpt, 103) */ + (28, 88), /* '/=' => LRAction::Reduce(CallableOpt, 103) */ + (29, 88), /* '==' => LRAction::Reduce(CallableOpt, 103) */ + (30, 88), /* '+' => LRAction::Reduce(CallableOpt, 103) */ + (31, 88), /* '-' => LRAction::Reduce(CallableOpt, 103) */ + (32, 88), /* '*' => LRAction::Reduce(CallableOpt, 103) */ + (33, 88), /* '/' => LRAction::Reduce(CallableOpt, 103) */ + (34, 88), /* '%' => LRAction::Reduce(CallableOpt, 103) */ + (35, 88), /* 'as' => LRAction::Reduce(CallableOpt, 103) */ + (38, 88), /* '&' => LRAction::Reduce(CallableOpt, 103) */ + (39, 88), /* '$' => LRAction::Reduce(CallableOpt, 103) */ + (40, 57), /* '?' => LRAction::Shift(169) */ + (41, 88), /* 'if' => LRAction::Reduce(CallableOpt, 103) */ + (43, 88), /* 'select' => LRAction::Reduce(CallableOpt, 103) */ + (44, 88), /* '{' => LRAction::Reduce(CallableOpt, 103) */ + (46, 88), /* '=>' => LRAction::Reduce(CallableOpt, 103) */ + (47, 88), /* '~' => LRAction::Reduce(CallableOpt, 103) */ + (48, 88), /* '@' => LRAction::Reduce(CallableOpt, 103) */ + (49, 88), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(CallableOpt, 103) */ + (50, 88), /* '[' => LRAction::Reduce(CallableOpt, 103) */ + (51, 88), /* ']' => LRAction::Reduce(CallableOpt, 103) */ + (52, 88), /* '"(\\.|[^"])*"' => LRAction::Reduce(CallableOpt, 103) */ + (53, 88), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(CallableOpt, 103) */ + (54, 88), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(CallableOpt, 103) */ + (55, 88), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CallableOpt, 103) */ + (56, 88), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CallableOpt, 103) */ + (57, 88), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(CallableOpt, 103) */ + (58, 88), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(CallableOpt, 103) */ + (59, 88), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(CallableOpt, 103) */ + ], + gotos: &[(13, 170) /* CallableOpt => 170 */], + }, + // State 151 + LR1State { + actions: &[ + (9, 151), /* '(' => LRAction::Reduce(Literal, 131) */ + (10, 151), /* ')' => LRAction::Reduce(Literal, 131) */ + (12, 151), /* ',' => LRAction::Reduce(Literal, 131) */ + (17, 151), /* ';' => LRAction::Reduce(Literal, 131) */ + (20, 151), /* ':=' => LRAction::Reduce(Literal, 131) */ + (21, 151), /* '||' => LRAction::Reduce(Literal, 131) */ + (22, 151), /* '&&' => LRAction::Reduce(Literal, 131) */ + (23, 151), /* '>=' => LRAction::Reduce(Literal, 131) */ + (24, 151), /* '<=' => LRAction::Reduce(Literal, 131) */ + (25, 151), /* '>' => LRAction::Reduce(Literal, 131) */ + (26, 151), /* '<' => LRAction::Reduce(Literal, 131) */ + (27, 151), /* '!=' => LRAction::Reduce(Literal, 131) */ + (28, 151), /* '/=' => LRAction::Reduce(Literal, 131) */ + (29, 151), /* '==' => LRAction::Reduce(Literal, 131) */ + (30, 151), /* '+' => LRAction::Reduce(Literal, 131) */ + (31, 151), /* '-' => LRAction::Reduce(Literal, 131) */ + (32, 151), /* '*' => LRAction::Reduce(Literal, 131) */ + (33, 151), /* '/' => LRAction::Reduce(Literal, 131) */ + (34, 151), /* '%' => LRAction::Reduce(Literal, 131) */ + (35, 151), /* 'as' => LRAction::Reduce(Literal, 131) */ + (38, 151), /* '&' => LRAction::Reduce(Literal, 131) */ + (39, 151), /* '$' => LRAction::Reduce(Literal, 131) */ + (40, 151), /* '?' => LRAction::Reduce(Literal, 131) */ + (41, 151), /* 'if' => LRAction::Reduce(Literal, 131) */ + (43, 151), /* 'select' => LRAction::Reduce(Literal, 131) */ + (44, 151), /* '{' => LRAction::Reduce(Literal, 131) */ + (46, 151), /* '=>' => LRAction::Reduce(Literal, 131) */ + (47, 151), /* '~' => LRAction::Reduce(Literal, 131) */ + (48, 151), /* '@' => LRAction::Reduce(Literal, 131) */ + (49, 151), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Literal, 131) */ + (50, 151), /* '[' => LRAction::Reduce(Literal, 131) */ + (51, 151), /* ']' => LRAction::Reduce(Literal, 131) */ + (52, 151), /* '"(\\.|[^"])*"' => LRAction::Reduce(Literal, 131) */ + (53, 151), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Literal, 131) */ + (54, 151), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Literal, 131) */ + (55, 151), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 131) */ + (56, 151), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 131) */ + (57, 151), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 131) */ + (58, 151), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 131) */ + (59, 151), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Literal, 131) */ + ], + gotos: &[], + }, + // State 152 + LR1State { + actions: &[ + (9, 168), /* '(' => LRAction::Reduce(Numeric, 146) */ + (10, 168), /* ')' => LRAction::Reduce(Numeric, 146) */ + (12, 168), /* ',' => LRAction::Reduce(Numeric, 146) */ + (17, 168), /* ';' => LRAction::Reduce(Numeric, 146) */ + (20, 168), /* ':=' => LRAction::Reduce(Numeric, 146) */ + (21, 168), /* '||' => LRAction::Reduce(Numeric, 146) */ + (22, 168), /* '&&' => LRAction::Reduce(Numeric, 146) */ + (23, 168), /* '>=' => LRAction::Reduce(Numeric, 146) */ + (24, 168), /* '<=' => LRAction::Reduce(Numeric, 146) */ + (25, 168), /* '>' => LRAction::Reduce(Numeric, 146) */ + (26, 168), /* '<' => LRAction::Reduce(Numeric, 146) */ + (27, 168), /* '!=' => LRAction::Reduce(Numeric, 146) */ + (28, 168), /* '/=' => LRAction::Reduce(Numeric, 146) */ + (29, 168), /* '==' => LRAction::Reduce(Numeric, 146) */ + (30, 168), /* '+' => LRAction::Reduce(Numeric, 146) */ + (31, 168), /* '-' => LRAction::Reduce(Numeric, 146) */ + (32, 168), /* '*' => LRAction::Reduce(Numeric, 146) */ + (33, 168), /* '/' => LRAction::Reduce(Numeric, 146) */ + (34, 168), /* '%' => LRAction::Reduce(Numeric, 146) */ + (35, 168), /* 'as' => LRAction::Reduce(Numeric, 146) */ + (38, 168), /* '&' => LRAction::Reduce(Numeric, 146) */ + (39, 168), /* '$' => LRAction::Reduce(Numeric, 146) */ + (40, 168), /* '?' => LRAction::Reduce(Numeric, 146) */ + (41, 168), /* 'if' => LRAction::Reduce(Numeric, 146) */ + (43, 168), /* 'select' => LRAction::Reduce(Numeric, 146) */ + (44, 168), /* '{' => LRAction::Reduce(Numeric, 146) */ + (46, 168), /* '=>' => LRAction::Reduce(Numeric, 146) */ + (47, 168), /* '~' => LRAction::Reduce(Numeric, 146) */ + (48, 168), /* '@' => LRAction::Reduce(Numeric, 146) */ + (49, 168), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Numeric, 146) */ + (50, 168), /* '[' => LRAction::Reduce(Numeric, 146) */ + (51, 168), /* ']' => LRAction::Reduce(Numeric, 146) */ + (52, 168), /* '"(\\.|[^"])*"' => LRAction::Reduce(Numeric, 146) */ + (53, 168), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Numeric, 146) */ + (54, 168), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Numeric, 146) */ + (55, 168), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 146) */ + (56, 168), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 146) */ + (57, 168), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 146) */ + (58, 168), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Numeric, 146) */ + (59, 168), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Numeric, 146) */ + ], + gotos: &[], + }, + // State 153 + LR1State { + actions: &[ + (9, 82), /* '(' => LRAction::Reduce(Callable, 97) */ + (10, 82), /* ')' => LRAction::Reduce(Callable, 97) */ + (12, 82), /* ',' => LRAction::Reduce(Callable, 97) */ + (17, 82), /* ';' => LRAction::Reduce(Callable, 97) */ + (20, 82), /* ':=' => LRAction::Reduce(Callable, 97) */ + (21, 82), /* '||' => LRAction::Reduce(Callable, 97) */ + (22, 82), /* '&&' => LRAction::Reduce(Callable, 97) */ + (23, 82), /* '>=' => LRAction::Reduce(Callable, 97) */ + (24, 82), /* '<=' => LRAction::Reduce(Callable, 97) */ + (25, 82), /* '>' => LRAction::Reduce(Callable, 97) */ + (26, 82), /* '<' => LRAction::Reduce(Callable, 97) */ + (27, 82), /* '!=' => LRAction::Reduce(Callable, 97) */ + (28, 82), /* '/=' => LRAction::Reduce(Callable, 97) */ + (29, 82), /* '==' => LRAction::Reduce(Callable, 97) */ + (30, 82), /* '+' => LRAction::Reduce(Callable, 97) */ + (31, 82), /* '-' => LRAction::Reduce(Callable, 97) */ + (32, 82), /* '*' => LRAction::Reduce(Callable, 97) */ + (33, 82), /* '/' => LRAction::Reduce(Callable, 97) */ + (34, 82), /* '%' => LRAction::Reduce(Callable, 97) */ + (35, 82), /* 'as' => LRAction::Reduce(Callable, 97) */ + (38, 82), /* '&' => LRAction::Reduce(Callable, 97) */ + (39, 82), /* '$' => LRAction::Reduce(Callable, 97) */ + (41, 82), /* 'if' => LRAction::Reduce(Callable, 97) */ + (43, 82), /* 'select' => LRAction::Reduce(Callable, 97) */ + (44, 82), /* '{' => LRAction::Reduce(Callable, 97) */ + (46, 82), /* '=>' => LRAction::Reduce(Callable, 97) */ + (47, 82), /* '~' => LRAction::Reduce(Callable, 97) */ + (48, 82), /* '@' => LRAction::Reduce(Callable, 97) */ + (49, 82), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Callable, 97) */ + (50, 82), /* '[' => LRAction::Reduce(Callable, 97) */ + (51, 82), /* ']' => LRAction::Reduce(Callable, 97) */ + (52, 82), /* '"(\\.|[^"])*"' => LRAction::Reduce(Callable, 97) */ + (53, 82), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Callable, 97) */ + (54, 82), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Callable, 97) */ + (55, 82), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 97) */ + (56, 82), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 97) */ + (57, 82), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 97) */ + (58, 82), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 97) */ + (59, 82), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Callable, 97) */ + ], + gotos: &[], + }, + // State 154 + LR1State { + actions: &[ + (9, 152), /* '(' => LRAction::Reduce(Literal, 132) */ + (10, 152), /* ')' => LRAction::Reduce(Literal, 132) */ + (12, 152), /* ',' => LRAction::Reduce(Literal, 132) */ + (17, 152), /* ';' => LRAction::Reduce(Literal, 132) */ + (20, 152), /* ':=' => LRAction::Reduce(Literal, 132) */ + (21, 152), /* '||' => LRAction::Reduce(Literal, 132) */ + (22, 152), /* '&&' => LRAction::Reduce(Literal, 132) */ + (23, 152), /* '>=' => LRAction::Reduce(Literal, 132) */ + (24, 152), /* '<=' => LRAction::Reduce(Literal, 132) */ + (25, 152), /* '>' => LRAction::Reduce(Literal, 132) */ + (26, 152), /* '<' => LRAction::Reduce(Literal, 132) */ + (27, 152), /* '!=' => LRAction::Reduce(Literal, 132) */ + (28, 152), /* '/=' => LRAction::Reduce(Literal, 132) */ + (29, 152), /* '==' => LRAction::Reduce(Literal, 132) */ + (30, 152), /* '+' => LRAction::Reduce(Literal, 132) */ + (31, 152), /* '-' => LRAction::Reduce(Literal, 132) */ + (32, 152), /* '*' => LRAction::Reduce(Literal, 132) */ + (33, 152), /* '/' => LRAction::Reduce(Literal, 132) */ + (34, 152), /* '%' => LRAction::Reduce(Literal, 132) */ + (35, 152), /* 'as' => LRAction::Reduce(Literal, 132) */ + (38, 152), /* '&' => LRAction::Reduce(Literal, 132) */ + (39, 152), /* '$' => LRAction::Reduce(Literal, 132) */ + (40, 152), /* '?' => LRAction::Reduce(Literal, 132) */ + (41, 152), /* 'if' => LRAction::Reduce(Literal, 132) */ + (43, 152), /* 'select' => LRAction::Reduce(Literal, 132) */ + (44, 152), /* '{' => LRAction::Reduce(Literal, 132) */ + (46, 152), /* '=>' => LRAction::Reduce(Literal, 132) */ + (47, 152), /* '~' => LRAction::Reduce(Literal, 132) */ + (48, 152), /* '@' => LRAction::Reduce(Literal, 132) */ + (49, 152), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Literal, 132) */ + (50, 152), /* '[' => LRAction::Reduce(Literal, 132) */ + (51, 152), /* ']' => LRAction::Reduce(Literal, 132) */ + (52, 152), /* '"(\\.|[^"])*"' => LRAction::Reduce(Literal, 132) */ + (53, 152), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Literal, 132) */ + (54, 152), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Literal, 132) */ + (55, 152), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 132) */ + (56, 152), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 132) */ + (57, 152), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 132) */ + (58, 152), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 132) */ + (59, 152), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Literal, 132) */ + ], + gotos: &[], + }, + // State 155 + LR1State { + actions: &[ + (9, 86), /* '(' => LRAction::Reduce(Callable, 101) */ + (10, 86), /* ')' => LRAction::Reduce(Callable, 101) */ + (12, 86), /* ',' => LRAction::Reduce(Callable, 101) */ + (17, 86), /* ';' => LRAction::Reduce(Callable, 101) */ + (20, 86), /* ':=' => LRAction::Reduce(Callable, 101) */ + (21, 86), /* '||' => LRAction::Reduce(Callable, 101) */ + (22, 86), /* '&&' => LRAction::Reduce(Callable, 101) */ + (23, 86), /* '>=' => LRAction::Reduce(Callable, 101) */ + (24, 86), /* '<=' => LRAction::Reduce(Callable, 101) */ + (25, 86), /* '>' => LRAction::Reduce(Callable, 101) */ + (26, 86), /* '<' => LRAction::Reduce(Callable, 101) */ + (27, 86), /* '!=' => LRAction::Reduce(Callable, 101) */ + (28, 86), /* '/=' => LRAction::Reduce(Callable, 101) */ + (29, 86), /* '==' => LRAction::Reduce(Callable, 101) */ + (30, 86), /* '+' => LRAction::Reduce(Callable, 101) */ + (31, 86), /* '-' => LRAction::Reduce(Callable, 101) */ + (32, 86), /* '*' => LRAction::Reduce(Callable, 101) */ + (33, 86), /* '/' => LRAction::Reduce(Callable, 101) */ + (34, 86), /* '%' => LRAction::Reduce(Callable, 101) */ + (35, 86), /* 'as' => LRAction::Reduce(Callable, 101) */ + (38, 86), /* '&' => LRAction::Reduce(Callable, 101) */ + (39, 86), /* '$' => LRAction::Reduce(Callable, 101) */ + (41, 86), /* 'if' => LRAction::Reduce(Callable, 101) */ + (43, 86), /* 'select' => LRAction::Reduce(Callable, 101) */ + (44, 86), /* '{' => LRAction::Reduce(Callable, 101) */ + (46, 86), /* '=>' => LRAction::Reduce(Callable, 101) */ + (47, 86), /* '~' => LRAction::Reduce(Callable, 101) */ + (48, 86), /* '@' => LRAction::Reduce(Callable, 101) */ + (49, 86), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Callable, 101) */ + (50, 86), /* '[' => LRAction::Reduce(Callable, 101) */ + (51, 86), /* ']' => LRAction::Reduce(Callable, 101) */ + (52, 86), /* '"(\\.|[^"])*"' => LRAction::Reduce(Callable, 101) */ + (53, 86), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Callable, 101) */ + (54, 86), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Callable, 101) */ + (55, 86), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 101) */ + (56, 86), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 101) */ + (57, 86), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 101) */ + (58, 86), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 101) */ + (59, 86), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Callable, 101) */ + ], + gotos: &[], + }, + // State 156 + LR1State { + actions: &[ + (9, 148), /* '(' => LRAction::Reduce(Literal, 128) */ + (10, 148), /* ')' => LRAction::Reduce(Literal, 128) */ + (12, 148), /* ',' => LRAction::Reduce(Literal, 128) */ + (17, 148), /* ';' => LRAction::Reduce(Literal, 128) */ + (20, 148), /* ':=' => LRAction::Reduce(Literal, 128) */ + (21, 148), /* '||' => LRAction::Reduce(Literal, 128) */ + (22, 148), /* '&&' => LRAction::Reduce(Literal, 128) */ + (23, 148), /* '>=' => LRAction::Reduce(Literal, 128) */ + (24, 148), /* '<=' => LRAction::Reduce(Literal, 128) */ + (25, 148), /* '>' => LRAction::Reduce(Literal, 128) */ + (26, 148), /* '<' => LRAction::Reduce(Literal, 128) */ + (27, 148), /* '!=' => LRAction::Reduce(Literal, 128) */ + (28, 148), /* '/=' => LRAction::Reduce(Literal, 128) */ + (29, 148), /* '==' => LRAction::Reduce(Literal, 128) */ + (30, 148), /* '+' => LRAction::Reduce(Literal, 128) */ + (31, 148), /* '-' => LRAction::Reduce(Literal, 128) */ + (32, 148), /* '*' => LRAction::Reduce(Literal, 128) */ + (33, 148), /* '/' => LRAction::Reduce(Literal, 128) */ + (34, 148), /* '%' => LRAction::Reduce(Literal, 128) */ + (35, 148), /* 'as' => LRAction::Reduce(Literal, 128) */ + (38, 148), /* '&' => LRAction::Reduce(Literal, 128) */ + (39, 148), /* '$' => LRAction::Reduce(Literal, 128) */ + (40, 148), /* '?' => LRAction::Reduce(Literal, 128) */ + (41, 148), /* 'if' => LRAction::Reduce(Literal, 128) */ + (43, 148), /* 'select' => LRAction::Reduce(Literal, 128) */ + (44, 148), /* '{' => LRAction::Reduce(Literal, 128) */ + (46, 148), /* '=>' => LRAction::Reduce(Literal, 128) */ + (47, 148), /* '~' => LRAction::Reduce(Literal, 128) */ + (48, 148), /* '@' => LRAction::Reduce(Literal, 128) */ + (49, 148), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Literal, 128) */ + (50, 148), /* '[' => LRAction::Reduce(Literal, 128) */ + (51, 148), /* ']' => LRAction::Reduce(Literal, 128) */ + (52, 148), /* '"(\\.|[^"])*"' => LRAction::Reduce(Literal, 128) */ + (53, 148), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Literal, 128) */ + (54, 148), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Literal, 128) */ + (55, 148), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 128) */ + (56, 148), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 128) */ + (57, 148), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 128) */ + (58, 148), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Literal, 128) */ + (59, 148), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Literal, 128) */ + ], + gotos: &[], + }, + // State 157 + LR1State { + actions: &[ + (10, 90), /* ')' => LRAction::Reduce(CastExprOpt, 81) */ + (12, 90), /* ',' => LRAction::Reduce(CastExprOpt, 81) */ + (17, 90), /* ';' => LRAction::Reduce(CastExprOpt, 81) */ + (20, 90), /* ':=' => LRAction::Reduce(CastExprOpt, 81) */ + (21, 90), /* '||' => LRAction::Reduce(CastExprOpt, 81) */ + (22, 90), /* '&&' => LRAction::Reduce(CastExprOpt, 81) */ + (23, 90), /* '>=' => LRAction::Reduce(CastExprOpt, 81) */ + (24, 90), /* '<=' => LRAction::Reduce(CastExprOpt, 81) */ + (25, 90), /* '>' => LRAction::Reduce(CastExprOpt, 81) */ + (26, 90), /* '<' => LRAction::Reduce(CastExprOpt, 81) */ + (27, 90), /* '!=' => LRAction::Reduce(CastExprOpt, 81) */ + (28, 90), /* '/=' => LRAction::Reduce(CastExprOpt, 81) */ + (29, 90), /* '==' => LRAction::Reduce(CastExprOpt, 81) */ + (30, 90), /* '+' => LRAction::Reduce(CastExprOpt, 81) */ + (31, 90), /* '-' => LRAction::Reduce(CastExprOpt, 81) */ + (32, 90), /* '*' => LRAction::Reduce(CastExprOpt, 81) */ + (33, 90), /* '/' => LRAction::Reduce(CastExprOpt, 81) */ + (34, 90), /* '%' => LRAction::Reduce(CastExprOpt, 81) */ + (44, 90), /* '{' => LRAction::Reduce(CastExprOpt, 81) */ + (46, 90), /* '=>' => LRAction::Reduce(CastExprOpt, 81) */ + (51, 90), /* ']' => LRAction::Reduce(CastExprOpt, 81) */ + ], + gotos: &[], + }, + // State 158 + LR1State { + actions: &[ + (9, 116), /* '(' => LRAction::Reduce(DefaultModifier, 118) */ + (10, 116), /* ')' => LRAction::Reduce(DefaultModifier, 118) */ + (12, 116), /* ',' => LRAction::Reduce(DefaultModifier, 118) */ + (17, 116), /* ';' => LRAction::Reduce(DefaultModifier, 118) */ + (20, 116), /* ':=' => LRAction::Reduce(DefaultModifier, 118) */ + (21, 116), /* '||' => LRAction::Reduce(DefaultModifier, 118) */ + (22, 116), /* '&&' => LRAction::Reduce(DefaultModifier, 118) */ + (23, 116), /* '>=' => LRAction::Reduce(DefaultModifier, 118) */ + (24, 116), /* '<=' => LRAction::Reduce(DefaultModifier, 118) */ + (25, 116), /* '>' => LRAction::Reduce(DefaultModifier, 118) */ + (26, 116), /* '<' => LRAction::Reduce(DefaultModifier, 118) */ + (27, 116), /* '!=' => LRAction::Reduce(DefaultModifier, 118) */ + (28, 116), /* '/=' => LRAction::Reduce(DefaultModifier, 118) */ + (29, 116), /* '==' => LRAction::Reduce(DefaultModifier, 118) */ + (30, 116), /* '+' => LRAction::Reduce(DefaultModifier, 118) */ + (31, 116), /* '-' => LRAction::Reduce(DefaultModifier, 118) */ + (32, 116), /* '*' => LRAction::Reduce(DefaultModifier, 118) */ + (33, 116), /* '/' => LRAction::Reduce(DefaultModifier, 118) */ + (34, 116), /* '%' => LRAction::Reduce(DefaultModifier, 118) */ + (35, 116), /* 'as' => LRAction::Reduce(DefaultModifier, 118) */ + (38, 116), /* '&' => LRAction::Reduce(DefaultModifier, 118) */ + (39, 116), /* '$' => LRAction::Reduce(DefaultModifier, 118) */ + (41, 116), /* 'if' => LRAction::Reduce(DefaultModifier, 118) */ + (43, 116), /* 'select' => LRAction::Reduce(DefaultModifier, 118) */ + (44, 116), /* '{' => LRAction::Reduce(DefaultModifier, 118) */ + (46, 116), /* '=>' => LRAction::Reduce(DefaultModifier, 118) */ + (47, 116), /* '~' => LRAction::Reduce(DefaultModifier, 118) */ + (48, 116), /* '@' => LRAction::Reduce(DefaultModifier, 118) */ + (49, 116), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(DefaultModifier, 118) */ + (50, 116), /* '[' => LRAction::Reduce(DefaultModifier, 118) */ + (51, 116), /* ']' => LRAction::Reduce(DefaultModifier, 118) */ + (52, 116), /* '"(\\.|[^"])*"' => LRAction::Reduce(DefaultModifier, 118) */ + (53, 116), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(DefaultModifier, 118) */ + (54, 116), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(DefaultModifier, 118) */ + (55, 116), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(DefaultModifier, 118) */ + (56, 116), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(DefaultModifier, 118) */ + (57, 116), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(DefaultModifier, 118) */ + (58, 116), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(DefaultModifier, 118) */ + (59, 116), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(DefaultModifier, 118) */ + ], + gotos: &[], + }, + // State 159 + LR1State { + actions: &[ + (9, 166), /* '(' => LRAction::Reduce(ModifierOpt, 121) */ + (10, 166), /* ')' => LRAction::Reduce(ModifierOpt, 121) */ + (12, 166), /* ',' => LRAction::Reduce(ModifierOpt, 121) */ + (13, 58), /* ':' => LRAction::Shift(171) */ + (17, 166), /* ';' => LRAction::Reduce(ModifierOpt, 121) */ + (20, 166), /* ':=' => LRAction::Reduce(ModifierOpt, 121) */ + (21, 166), /* '||' => LRAction::Reduce(ModifierOpt, 121) */ + (22, 166), /* '&&' => LRAction::Reduce(ModifierOpt, 121) */ + (23, 166), /* '>=' => LRAction::Reduce(ModifierOpt, 121) */ + (24, 166), /* '<=' => LRAction::Reduce(ModifierOpt, 121) */ + (25, 166), /* '>' => LRAction::Reduce(ModifierOpt, 121) */ + (26, 166), /* '<' => LRAction::Reduce(ModifierOpt, 121) */ + (27, 166), /* '!=' => LRAction::Reduce(ModifierOpt, 121) */ + (28, 166), /* '/=' => LRAction::Reduce(ModifierOpt, 121) */ + (29, 166), /* '==' => LRAction::Reduce(ModifierOpt, 121) */ + (30, 166), /* '+' => LRAction::Reduce(ModifierOpt, 121) */ + (31, 166), /* '-' => LRAction::Reduce(ModifierOpt, 121) */ + (32, 166), /* '*' => LRAction::Reduce(ModifierOpt, 121) */ + (33, 166), /* '/' => LRAction::Reduce(ModifierOpt, 121) */ + (34, 166), /* '%' => LRAction::Reduce(ModifierOpt, 121) */ + (35, 166), /* 'as' => LRAction::Reduce(ModifierOpt, 121) */ + (38, 166), /* '&' => LRAction::Reduce(ModifierOpt, 121) */ + (39, 166), /* '$' => LRAction::Reduce(ModifierOpt, 121) */ + (41, 166), /* 'if' => LRAction::Reduce(ModifierOpt, 121) */ + (43, 166), /* 'select' => LRAction::Reduce(ModifierOpt, 121) */ + (44, 166), /* '{' => LRAction::Reduce(ModifierOpt, 121) */ + (46, 166), /* '=>' => LRAction::Reduce(ModifierOpt, 121) */ + (47, 166), /* '~' => LRAction::Reduce(ModifierOpt, 121) */ + (48, 166), /* '@' => LRAction::Reduce(ModifierOpt, 121) */ + (49, 166), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ModifierOpt, 121) */ + (50, 166), /* '[' => LRAction::Reduce(ModifierOpt, 121) */ + (51, 166), /* ']' => LRAction::Reduce(ModifierOpt, 121) */ + (52, 166), /* '"(\\.|[^"])*"' => LRAction::Reduce(ModifierOpt, 121) */ + (53, 166), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ModifierOpt, 121) */ + (54, 166), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ModifierOpt, 121) */ + (55, 166), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ModifierOpt, 121) */ + (56, 166), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ModifierOpt, 121) */ + (57, 166), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ModifierOpt, 121) */ + (58, 166), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ModifierOpt, 121) */ + (59, 166), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ModifierOpt, 121) */ + ], + gotos: &[ + (49, 172), /* KindArg => 172 */ + (60, 173), /* ModifierOpt => 173 */ + ], + }, + // State 160 + LR1State { + actions: &[ + (9, 66), /* '(' => LRAction::Reduce(ApplyExprList, 90) */ + (10, 66), /* ')' => LRAction::Reduce(ApplyExprList, 90) */ + (12, 66), /* ',' => LRAction::Reduce(ApplyExprList, 90) */ + (17, 66), /* ';' => LRAction::Reduce(ApplyExprList, 90) */ + (20, 66), /* ':=' => LRAction::Reduce(ApplyExprList, 90) */ + (21, 66), /* '||' => LRAction::Reduce(ApplyExprList, 90) */ + (22, 66), /* '&&' => LRAction::Reduce(ApplyExprList, 90) */ + (23, 66), /* '>=' => LRAction::Reduce(ApplyExprList, 90) */ + (24, 66), /* '<=' => LRAction::Reduce(ApplyExprList, 90) */ + (25, 66), /* '>' => LRAction::Reduce(ApplyExprList, 90) */ + (26, 66), /* '<' => LRAction::Reduce(ApplyExprList, 90) */ + (27, 66), /* '!=' => LRAction::Reduce(ApplyExprList, 90) */ + (28, 66), /* '/=' => LRAction::Reduce(ApplyExprList, 90) */ + (29, 66), /* '==' => LRAction::Reduce(ApplyExprList, 90) */ + (30, 66), /* '+' => LRAction::Reduce(ApplyExprList, 90) */ + (31, 66), /* '-' => LRAction::Reduce(ApplyExprList, 90) */ + (32, 66), /* '*' => LRAction::Reduce(ApplyExprList, 90) */ + (33, 66), /* '/' => LRAction::Reduce(ApplyExprList, 90) */ + (34, 66), /* '%' => LRAction::Reduce(ApplyExprList, 90) */ + (35, 66), /* 'as' => LRAction::Reduce(ApplyExprList, 90) */ + (38, 66), /* '&' => LRAction::Reduce(ApplyExprList, 90) */ + (39, 66), /* '$' => LRAction::Reduce(ApplyExprList, 90) */ + (41, 66), /* 'if' => LRAction::Reduce(ApplyExprList, 90) */ + (43, 66), /* 'select' => LRAction::Reduce(ApplyExprList, 90) */ + (44, 66), /* '{' => LRAction::Reduce(ApplyExprList, 90) */ + (46, 66), /* '=>' => LRAction::Reduce(ApplyExprList, 90) */ + (47, 66), /* '~' => LRAction::Reduce(ApplyExprList, 90) */ + (48, 66), /* '@' => LRAction::Reduce(ApplyExprList, 90) */ + (49, 66), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ApplyExprList, 90) */ + (50, 66), /* '[' => LRAction::Reduce(ApplyExprList, 90) */ + (51, 66), /* ']' => LRAction::Reduce(ApplyExprList, 90) */ + (52, 66), /* '"(\\.|[^"])*"' => LRAction::Reduce(ApplyExprList, 90) */ + (53, 66), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ApplyExprList, 90) */ + (54, 66), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ApplyExprList, 90) */ + (55, 66), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ApplyExprList, 90) */ + (56, 66), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ApplyExprList, 90) */ + (57, 66), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ApplyExprList, 90) */ + (58, 66), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ApplyExprList, 90) */ + (59, 66), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ApplyExprList, 90) */ + ], + gotos: &[], + }, + // State 161 + LR1State { + actions: &[ + (9, 77), /* '(' => LRAction::Reduce(AtomicExpr, 105) */ + (10, 77), /* ')' => LRAction::Reduce(AtomicExpr, 105) */ + (12, 77), /* ',' => LRAction::Reduce(AtomicExpr, 105) */ + (17, 77), /* ';' => LRAction::Reduce(AtomicExpr, 105) */ + (20, 77), /* ':=' => LRAction::Reduce(AtomicExpr, 105) */ + (21, 77), /* '||' => LRAction::Reduce(AtomicExpr, 105) */ + (22, 77), /* '&&' => LRAction::Reduce(AtomicExpr, 105) */ + (23, 77), /* '>=' => LRAction::Reduce(AtomicExpr, 105) */ + (24, 77), /* '<=' => LRAction::Reduce(AtomicExpr, 105) */ + (25, 77), /* '>' => LRAction::Reduce(AtomicExpr, 105) */ + (26, 77), /* '<' => LRAction::Reduce(AtomicExpr, 105) */ + (27, 77), /* '!=' => LRAction::Reduce(AtomicExpr, 105) */ + (28, 77), /* '/=' => LRAction::Reduce(AtomicExpr, 105) */ + (29, 77), /* '==' => LRAction::Reduce(AtomicExpr, 105) */ + (30, 77), /* '+' => LRAction::Reduce(AtomicExpr, 105) */ + (31, 77), /* '-' => LRAction::Reduce(AtomicExpr, 105) */ + (32, 77), /* '*' => LRAction::Reduce(AtomicExpr, 105) */ + (33, 77), /* '/' => LRAction::Reduce(AtomicExpr, 105) */ + (34, 77), /* '%' => LRAction::Reduce(AtomicExpr, 105) */ + (35, 77), /* 'as' => LRAction::Reduce(AtomicExpr, 105) */ + (38, 77), /* '&' => LRAction::Reduce(AtomicExpr, 105) */ + (39, 77), /* '$' => LRAction::Reduce(AtomicExpr, 105) */ + (41, 77), /* 'if' => LRAction::Reduce(AtomicExpr, 105) */ + (43, 77), /* 'select' => LRAction::Reduce(AtomicExpr, 105) */ + (44, 77), /* '{' => LRAction::Reduce(AtomicExpr, 105) */ + (46, 77), /* '=>' => LRAction::Reduce(AtomicExpr, 105) */ + (47, 77), /* '~' => LRAction::Reduce(AtomicExpr, 105) */ + (48, 77), /* '@' => LRAction::Reduce(AtomicExpr, 105) */ + (49, 77), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(AtomicExpr, 105) */ + (50, 77), /* '[' => LRAction::Reduce(AtomicExpr, 105) */ + (51, 77), /* ']' => LRAction::Reduce(AtomicExpr, 105) */ + (52, 77), /* '"(\\.|[^"])*"' => LRAction::Reduce(AtomicExpr, 105) */ + (53, 77), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(AtomicExpr, 105) */ + (54, 77), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(AtomicExpr, 105) */ + (55, 77), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(AtomicExpr, 105) */ + (56, 77), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(AtomicExpr, 105) */ + (57, 77), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(AtomicExpr, 105) */ + (58, 77), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(AtomicExpr, 105) */ + (59, 77), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(AtomicExpr, 105) */ + ], + gotos: &[], + }, + // State 162 + LR1State { + actions: &[ + (9, 76), /* '(' => LRAction::Reduce(AtomicExpr, 104) */ + (10, 76), /* ')' => LRAction::Reduce(AtomicExpr, 104) */ + (12, 76), /* ',' => LRAction::Reduce(AtomicExpr, 104) */ + (17, 76), /* ';' => LRAction::Reduce(AtomicExpr, 104) */ + (20, 76), /* ':=' => LRAction::Reduce(AtomicExpr, 104) */ + (21, 76), /* '||' => LRAction::Reduce(AtomicExpr, 104) */ + (22, 76), /* '&&' => LRAction::Reduce(AtomicExpr, 104) */ + (23, 76), /* '>=' => LRAction::Reduce(AtomicExpr, 104) */ + (24, 76), /* '<=' => LRAction::Reduce(AtomicExpr, 104) */ + (25, 76), /* '>' => LRAction::Reduce(AtomicExpr, 104) */ + (26, 76), /* '<' => LRAction::Reduce(AtomicExpr, 104) */ + (27, 76), /* '!=' => LRAction::Reduce(AtomicExpr, 104) */ + (28, 76), /* '/=' => LRAction::Reduce(AtomicExpr, 104) */ + (29, 76), /* '==' => LRAction::Reduce(AtomicExpr, 104) */ + (30, 76), /* '+' => LRAction::Reduce(AtomicExpr, 104) */ + (31, 76), /* '-' => LRAction::Reduce(AtomicExpr, 104) */ + (32, 76), /* '*' => LRAction::Reduce(AtomicExpr, 104) */ + (33, 76), /* '/' => LRAction::Reduce(AtomicExpr, 104) */ + (34, 76), /* '%' => LRAction::Reduce(AtomicExpr, 104) */ + (35, 76), /* 'as' => LRAction::Reduce(AtomicExpr, 104) */ + (38, 76), /* '&' => LRAction::Reduce(AtomicExpr, 104) */ + (39, 76), /* '$' => LRAction::Reduce(AtomicExpr, 104) */ + (41, 76), /* 'if' => LRAction::Reduce(AtomicExpr, 104) */ + (43, 76), /* 'select' => LRAction::Reduce(AtomicExpr, 104) */ + (44, 76), /* '{' => LRAction::Reduce(AtomicExpr, 104) */ + (46, 76), /* '=>' => LRAction::Reduce(AtomicExpr, 104) */ + (47, 76), /* '~' => LRAction::Reduce(AtomicExpr, 104) */ + (48, 76), /* '@' => LRAction::Reduce(AtomicExpr, 104) */ + (49, 76), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(AtomicExpr, 104) */ + (50, 76), /* '[' => LRAction::Reduce(AtomicExpr, 104) */ + (51, 76), /* ']' => LRAction::Reduce(AtomicExpr, 104) */ + (52, 76), /* '"(\\.|[^"])*"' => LRAction::Reduce(AtomicExpr, 104) */ + (53, 76), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(AtomicExpr, 104) */ + (54, 76), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(AtomicExpr, 104) */ + (55, 76), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(AtomicExpr, 104) */ + (56, 76), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(AtomicExpr, 104) */ + (57, 76), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(AtomicExpr, 104) */ + (58, 76), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(AtomicExpr, 104) */ + (59, 76), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(AtomicExpr, 104) */ + ], + gotos: &[], + }, + // State 163 + LR1State { + actions: &[(10, 59) /* ')' => LRAction::Shift(174) */], + gotos: &[], + }, + // State 164 + LR1State { + actions: &[(44, 14) /* '{' => LRAction::Shift(48) */], + gotos: &[(9, 175) /* Block => 175 */], + }, + // State 165 + LR1State { + actions: &[ + (5, 207), /* '\r?\n|\r' => LRAction::Reduce(SelectScopeOpt, 114) */ + (9, 158), /* '(' => LRAction::Reduce(LogicalOrExprList, 55) */ + (31, 158), /* '-' => LRAction::Reduce(LogicalOrExprList, 55) */ + (36, 158), /* 'wait' => LRAction::Reduce(LogicalOrExprList, 55) */ + (37, 158), /* 'call' => LRAction::Reduce(LogicalOrExprList, 55) */ + (38, 158), /* '&' => LRAction::Reduce(LogicalOrExprList, 55) */ + (39, 158), /* '$' => LRAction::Reduce(LogicalOrExprList, 55) */ + (41, 158), /* 'if' => LRAction::Reduce(LogicalOrExprList, 55) */ + (43, 158), /* 'select' => LRAction::Reduce(LogicalOrExprList, 55) */ + (45, 207), /* '}' => LRAction::Reduce(SelectScopeOpt, 114) */ + (47, 158), /* '~' => LRAction::Reduce(LogicalOrExprList, 55) */ + (48, 158), /* '@' => LRAction::Reduce(LogicalOrExprList, 55) */ + (49, 158), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalOrExprList, 55) */ + (50, 158), /* '[' => LRAction::Reduce(LogicalOrExprList, 55) */ + (52, 158), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (53, 158), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (54, 158), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (55, 158), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (56, 158), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (57, 158), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (58, 158), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (59, 158), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalOrExprList, 55) */ + ], + gotos: &[ + (35, 176), /* Expr => 176 */ + (54, 44), /* LogicalOrExpr => 44 */ + (55, 45), /* LogicalOrExprList => 45 */ + (83, 177), /* SelectScope => 177 */ + (84, 178), /* SelectScopeContent => 178 */ + (85, 179), /* SelectScopeOpt => 179 */ + (88, 46), /* SetExpr => 46 */ + ], + }, + // State 166 + LR1State { + actions: &[(51, 60) /* ']' => LRAction::Shift(180) */], + gotos: &[], + }, + // State 167 + LR1State { + actions: &[(51, 74) /* ']' => LRAction::Reduce(ArrayOpt, 134) */], + gotos: &[], + }, + // State 168 + LR1State { + actions: &[ + (12, 61), /* ',' => LRAction::Shift(181) */ + (51, 100), /* ']' => LRAction::Reduce(CommaSepElementsOpt, 138) */ + ], + gotos: &[ + (16, 182), /* CommaExprList => 182 */ + (21, 183), /* CommaSepElementsOpt => 183 */ + ], + }, + // State 169 + LR1State { + actions: &[ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + ], + gotos: &[ + (45, 28), /* Ident => 28 */ + (66, 184), /* Path => 184 */ + ], + }, + // State 170 + LR1State { + actions: &[ + (9, 83), /* '(' => LRAction::Reduce(Callable, 98) */ + (10, 83), /* ')' => LRAction::Reduce(Callable, 98) */ + (12, 83), /* ',' => LRAction::Reduce(Callable, 98) */ + (17, 83), /* ';' => LRAction::Reduce(Callable, 98) */ + (20, 83), /* ':=' => LRAction::Reduce(Callable, 98) */ + (21, 83), /* '||' => LRAction::Reduce(Callable, 98) */ + (22, 83), /* '&&' => LRAction::Reduce(Callable, 98) */ + (23, 83), /* '>=' => LRAction::Reduce(Callable, 98) */ + (24, 83), /* '<=' => LRAction::Reduce(Callable, 98) */ + (25, 83), /* '>' => LRAction::Reduce(Callable, 98) */ + (26, 83), /* '<' => LRAction::Reduce(Callable, 98) */ + (27, 83), /* '!=' => LRAction::Reduce(Callable, 98) */ + (28, 83), /* '/=' => LRAction::Reduce(Callable, 98) */ + (29, 83), /* '==' => LRAction::Reduce(Callable, 98) */ + (30, 83), /* '+' => LRAction::Reduce(Callable, 98) */ + (31, 83), /* '-' => LRAction::Reduce(Callable, 98) */ + (32, 83), /* '*' => LRAction::Reduce(Callable, 98) */ + (33, 83), /* '/' => LRAction::Reduce(Callable, 98) */ + (34, 83), /* '%' => LRAction::Reduce(Callable, 98) */ + (35, 83), /* 'as' => LRAction::Reduce(Callable, 98) */ + (38, 83), /* '&' => LRAction::Reduce(Callable, 98) */ + (39, 83), /* '$' => LRAction::Reduce(Callable, 98) */ + (41, 83), /* 'if' => LRAction::Reduce(Callable, 98) */ + (43, 83), /* 'select' => LRAction::Reduce(Callable, 98) */ + (44, 83), /* '{' => LRAction::Reduce(Callable, 98) */ + (46, 83), /* '=>' => LRAction::Reduce(Callable, 98) */ + (47, 83), /* '~' => LRAction::Reduce(Callable, 98) */ + (48, 83), /* '@' => LRAction::Reduce(Callable, 98) */ + (49, 83), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Callable, 98) */ + (50, 83), /* '[' => LRAction::Reduce(Callable, 98) */ + (51, 83), /* ']' => LRAction::Reduce(Callable, 98) */ + (52, 83), /* '"(\\.|[^"])*"' => LRAction::Reduce(Callable, 98) */ + (53, 83), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Callable, 98) */ + (54, 83), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Callable, 98) */ + (55, 83), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 98) */ + (56, 83), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 98) */ + (57, 83), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 98) */ + (58, 83), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 98) */ + (59, 83), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Callable, 98) */ + ], + gotos: &[], + }, + // State 171 + LR1State { + actions: &[ + (9, 44), /* '(' => LRAction::Shift(130) */ + (41, 45), /* 'if' => LRAction::Shift(131) */ + (43, 46), /* 'select' => LRAction::Shift(132) */ + (49, 2), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Shift(9) */ + (50, 47), /* '[' => LRAction::Shift(133) */ + (52, 48), /* '"(\\.|[^"])*"' => LRAction::Shift(134) */ + (53, 49), /* 'b"(\\.|[^"])*"' => LRAction::Shift(135) */ + (54, 50), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Shift(136) */ + (55, 51), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Shift(137) */ + (56, 52), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Shift(138) */ + (57, 53), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Shift(139) */ + (58, 54), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Shift(140) */ + (59, 55), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Shift(141) */ + ], + gotos: &[ + (5, 142), /* Array => 142 */ + (8, 143), /* BinaryInteger => 143 */ + (11, 144), /* ByteLiteral => 144 */ + (12, 185), /* Callable => 185 */ + (43, 146), /* HexByteLiteral => 146 */ + (44, 147), /* HexadecimalInteger => 147 */ + (45, 28), /* Ident => 28 */ + (46, 148), /* Ieee754Float => 148 */ + (47, 149), /* IfExpr => 149 */ + (51, 150), /* Literal => 150 */ + (61, 151), /* Numeric => 151 */ + (62, 152), /* OctalInteger => 152 */ + (66, 153), /* Path => 153 */ + (74, 154), /* Rfc3339DateTime => 154 */ + (82, 155), /* SelectExpr => 155 */ + (92, 156), /* String => 156 */ + ], + }, + // State 172 + LR1State { + actions: &[ + (9, 165), /* '(' => LRAction::Reduce(ModifierOpt, 120) */ + (10, 165), /* ')' => LRAction::Reduce(ModifierOpt, 120) */ + (12, 165), /* ',' => LRAction::Reduce(ModifierOpt, 120) */ + (17, 165), /* ';' => LRAction::Reduce(ModifierOpt, 120) */ + (20, 165), /* ':=' => LRAction::Reduce(ModifierOpt, 120) */ + (21, 165), /* '||' => LRAction::Reduce(ModifierOpt, 120) */ + (22, 165), /* '&&' => LRAction::Reduce(ModifierOpt, 120) */ + (23, 165), /* '>=' => LRAction::Reduce(ModifierOpt, 120) */ + (24, 165), /* '<=' => LRAction::Reduce(ModifierOpt, 120) */ + (25, 165), /* '>' => LRAction::Reduce(ModifierOpt, 120) */ + (26, 165), /* '<' => LRAction::Reduce(ModifierOpt, 120) */ + (27, 165), /* '!=' => LRAction::Reduce(ModifierOpt, 120) */ + (28, 165), /* '/=' => LRAction::Reduce(ModifierOpt, 120) */ + (29, 165), /* '==' => LRAction::Reduce(ModifierOpt, 120) */ + (30, 165), /* '+' => LRAction::Reduce(ModifierOpt, 120) */ + (31, 165), /* '-' => LRAction::Reduce(ModifierOpt, 120) */ + (32, 165), /* '*' => LRAction::Reduce(ModifierOpt, 120) */ + (33, 165), /* '/' => LRAction::Reduce(ModifierOpt, 120) */ + (34, 165), /* '%' => LRAction::Reduce(ModifierOpt, 120) */ + (35, 165), /* 'as' => LRAction::Reduce(ModifierOpt, 120) */ + (38, 165), /* '&' => LRAction::Reduce(ModifierOpt, 120) */ + (39, 165), /* '$' => LRAction::Reduce(ModifierOpt, 120) */ + (41, 165), /* 'if' => LRAction::Reduce(ModifierOpt, 120) */ + (43, 165), /* 'select' => LRAction::Reduce(ModifierOpt, 120) */ + (44, 165), /* '{' => LRAction::Reduce(ModifierOpt, 120) */ + (46, 165), /* '=>' => LRAction::Reduce(ModifierOpt, 120) */ + (47, 165), /* '~' => LRAction::Reduce(ModifierOpt, 120) */ + (48, 165), /* '@' => LRAction::Reduce(ModifierOpt, 120) */ + (49, 165), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(ModifierOpt, 120) */ + (50, 165), /* '[' => LRAction::Reduce(ModifierOpt, 120) */ + (51, 165), /* ']' => LRAction::Reduce(ModifierOpt, 120) */ + (52, 165), /* '"(\\.|[^"])*"' => LRAction::Reduce(ModifierOpt, 120) */ + (53, 165), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(ModifierOpt, 120) */ + (54, 165), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(ModifierOpt, 120) */ + (55, 165), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ModifierOpt, 120) */ + (56, 165), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(ModifierOpt, 120) */ + (57, 165), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(ModifierOpt, 120) */ + (58, 165), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(ModifierOpt, 120) */ + (59, 165), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(ModifierOpt, 120) */ + ], + gotos: &[], + }, + // State 173 + LR1State { + actions: &[ + (9, 164), /* '(' => LRAction::Reduce(Modifier, 119) */ + (10, 164), /* ')' => LRAction::Reduce(Modifier, 119) */ + (12, 164), /* ',' => LRAction::Reduce(Modifier, 119) */ + (17, 164), /* ';' => LRAction::Reduce(Modifier, 119) */ + (20, 164), /* ':=' => LRAction::Reduce(Modifier, 119) */ + (21, 164), /* '||' => LRAction::Reduce(Modifier, 119) */ + (22, 164), /* '&&' => LRAction::Reduce(Modifier, 119) */ + (23, 164), /* '>=' => LRAction::Reduce(Modifier, 119) */ + (24, 164), /* '<=' => LRAction::Reduce(Modifier, 119) */ + (25, 164), /* '>' => LRAction::Reduce(Modifier, 119) */ + (26, 164), /* '<' => LRAction::Reduce(Modifier, 119) */ + (27, 164), /* '!=' => LRAction::Reduce(Modifier, 119) */ + (28, 164), /* '/=' => LRAction::Reduce(Modifier, 119) */ + (29, 164), /* '==' => LRAction::Reduce(Modifier, 119) */ + (30, 164), /* '+' => LRAction::Reduce(Modifier, 119) */ + (31, 164), /* '-' => LRAction::Reduce(Modifier, 119) */ + (32, 164), /* '*' => LRAction::Reduce(Modifier, 119) */ + (33, 164), /* '/' => LRAction::Reduce(Modifier, 119) */ + (34, 164), /* '%' => LRAction::Reduce(Modifier, 119) */ + (35, 164), /* 'as' => LRAction::Reduce(Modifier, 119) */ + (38, 164), /* '&' => LRAction::Reduce(Modifier, 119) */ + (39, 164), /* '$' => LRAction::Reduce(Modifier, 119) */ + (41, 164), /* 'if' => LRAction::Reduce(Modifier, 119) */ + (43, 164), /* 'select' => LRAction::Reduce(Modifier, 119) */ + (44, 164), /* '{' => LRAction::Reduce(Modifier, 119) */ + (46, 164), /* '=>' => LRAction::Reduce(Modifier, 119) */ + (47, 164), /* '~' => LRAction::Reduce(Modifier, 119) */ + (48, 164), /* '@' => LRAction::Reduce(Modifier, 119) */ + (49, 164), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Modifier, 119) */ + (50, 164), /* '[' => LRAction::Reduce(Modifier, 119) */ + (51, 164), /* ']' => LRAction::Reduce(Modifier, 119) */ + (52, 164), /* '"(\\.|[^"])*"' => LRAction::Reduce(Modifier, 119) */ + (53, 164), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Modifier, 119) */ + (54, 164), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Modifier, 119) */ + (55, 164), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Modifier, 119) */ + (56, 164), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Modifier, 119) */ + (57, 164), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Modifier, 119) */ + (58, 164), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Modifier, 119) */ + (59, 164), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Modifier, 119) */ + ], + gotos: &[], + }, + // State 174 + LR1State { + actions: &[ + (9, 84), /* '(' => LRAction::Reduce(Callable, 99) */ + (10, 84), /* ')' => LRAction::Reduce(Callable, 99) */ + (12, 84), /* ',' => LRAction::Reduce(Callable, 99) */ + (17, 84), /* ';' => LRAction::Reduce(Callable, 99) */ + (20, 84), /* ':=' => LRAction::Reduce(Callable, 99) */ + (21, 84), /* '||' => LRAction::Reduce(Callable, 99) */ + (22, 84), /* '&&' => LRAction::Reduce(Callable, 99) */ + (23, 84), /* '>=' => LRAction::Reduce(Callable, 99) */ + (24, 84), /* '<=' => LRAction::Reduce(Callable, 99) */ + (25, 84), /* '>' => LRAction::Reduce(Callable, 99) */ + (26, 84), /* '<' => LRAction::Reduce(Callable, 99) */ + (27, 84), /* '!=' => LRAction::Reduce(Callable, 99) */ + (28, 84), /* '/=' => LRAction::Reduce(Callable, 99) */ + (29, 84), /* '==' => LRAction::Reduce(Callable, 99) */ + (30, 84), /* '+' => LRAction::Reduce(Callable, 99) */ + (31, 84), /* '-' => LRAction::Reduce(Callable, 99) */ + (32, 84), /* '*' => LRAction::Reduce(Callable, 99) */ + (33, 84), /* '/' => LRAction::Reduce(Callable, 99) */ + (34, 84), /* '%' => LRAction::Reduce(Callable, 99) */ + (35, 84), /* 'as' => LRAction::Reduce(Callable, 99) */ + (38, 84), /* '&' => LRAction::Reduce(Callable, 99) */ + (39, 84), /* '$' => LRAction::Reduce(Callable, 99) */ + (41, 84), /* 'if' => LRAction::Reduce(Callable, 99) */ + (43, 84), /* 'select' => LRAction::Reduce(Callable, 99) */ + (44, 84), /* '{' => LRAction::Reduce(Callable, 99) */ + (46, 84), /* '=>' => LRAction::Reduce(Callable, 99) */ + (47, 84), /* '~' => LRAction::Reduce(Callable, 99) */ + (48, 84), /* '@' => LRAction::Reduce(Callable, 99) */ + (49, 84), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Callable, 99) */ + (50, 84), /* '[' => LRAction::Reduce(Callable, 99) */ + (51, 84), /* ']' => LRAction::Reduce(Callable, 99) */ + (52, 84), /* '"(\\.|[^"])*"' => LRAction::Reduce(Callable, 99) */ + (53, 84), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Callable, 99) */ + (54, 84), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Callable, 99) */ + (55, 84), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 99) */ + (56, 84), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 99) */ + (57, 84), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 99) */ + (58, 84), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Callable, 99) */ + (59, 84), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Callable, 99) */ + ], + gotos: &[], + }, + // State 175 + LR1State { + actions: &[ + (9, 144), /* '(' => LRAction::Reduce(IfExprOpt, 108) */ + (10, 144), /* ')' => LRAction::Reduce(IfExprOpt, 108) */ + (12, 144), /* ',' => LRAction::Reduce(IfExprOpt, 108) */ + (17, 144), /* ';' => LRAction::Reduce(IfExprOpt, 108) */ + (20, 144), /* ':=' => LRAction::Reduce(IfExprOpt, 108) */ + (21, 144), /* '||' => LRAction::Reduce(IfExprOpt, 108) */ + (22, 144), /* '&&' => LRAction::Reduce(IfExprOpt, 108) */ + (23, 144), /* '>=' => LRAction::Reduce(IfExprOpt, 108) */ + (24, 144), /* '<=' => LRAction::Reduce(IfExprOpt, 108) */ + (25, 144), /* '>' => LRAction::Reduce(IfExprOpt, 108) */ + (26, 144), /* '<' => LRAction::Reduce(IfExprOpt, 108) */ + (27, 144), /* '!=' => LRAction::Reduce(IfExprOpt, 108) */ + (28, 144), /* '/=' => LRAction::Reduce(IfExprOpt, 108) */ + (29, 144), /* '==' => LRAction::Reduce(IfExprOpt, 108) */ + (30, 144), /* '+' => LRAction::Reduce(IfExprOpt, 108) */ + (31, 144), /* '-' => LRAction::Reduce(IfExprOpt, 108) */ + (32, 144), /* '*' => LRAction::Reduce(IfExprOpt, 108) */ + (33, 144), /* '/' => LRAction::Reduce(IfExprOpt, 108) */ + (34, 144), /* '%' => LRAction::Reduce(IfExprOpt, 108) */ + (35, 144), /* 'as' => LRAction::Reduce(IfExprOpt, 108) */ + (38, 144), /* '&' => LRAction::Reduce(IfExprOpt, 108) */ + (39, 144), /* '$' => LRAction::Reduce(IfExprOpt, 108) */ + (41, 144), /* 'if' => LRAction::Reduce(IfExprOpt, 108) */ + (42, 62), /* 'else' => LRAction::Shift(186) */ + (43, 144), /* 'select' => LRAction::Reduce(IfExprOpt, 108) */ + (44, 144), /* '{' => LRAction::Reduce(IfExprOpt, 108) */ + (46, 144), /* '=>' => LRAction::Reduce(IfExprOpt, 108) */ + (47, 144), /* '~' => LRAction::Reduce(IfExprOpt, 108) */ + (48, 144), /* '@' => LRAction::Reduce(IfExprOpt, 108) */ + (49, 144), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(IfExprOpt, 108) */ + (50, 144), /* '[' => LRAction::Reduce(IfExprOpt, 108) */ + (51, 144), /* ']' => LRAction::Reduce(IfExprOpt, 108) */ + (52, 144), /* '"(\\.|[^"])*"' => LRAction::Reduce(IfExprOpt, 108) */ + (53, 144), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(IfExprOpt, 108) */ + (54, 144), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(IfExprOpt, 108) */ + (55, 144), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(IfExprOpt, 108) */ + (56, 144), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(IfExprOpt, 108) */ + (57, 144), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(IfExprOpt, 108) */ + (58, 144), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(IfExprOpt, 108) */ + (59, 144), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(IfExprOpt, 108) */ + ], + gotos: &[(48, 187) /* IfExprOpt => 187 */], + }, + // State 176 + LR1State { + actions: &[(46, 63) /* '=>' => LRAction::Shift(188) */], + gotos: &[], + }, + // State 177 + LR1State { + actions: &[(45, 64) /* '}' => LRAction::Shift(189) */], + gotos: &[], + }, + // State 178 + LR1State { + actions: &[ + (5, 206), /* '\r?\n|\r' => LRAction::Reduce(SelectScopeOpt, 113) */ + (45, 206), /* '}' => LRAction::Reduce(SelectScopeOpt, 113) */ + ], + gotos: &[], + }, + // State 179 + LR1State { + actions: &[ + (5, 3), /* '\r?\n|\r' => LRAction::Shift(12) */ + (45, 209), /* '}' => LRAction::Reduce(SelectScopeOpt0, 112) */ + ], + gotos: &[ + (34, 190), /* EndOfLine => 190 */ + (86, 191), /* SelectScopeOpt0 => 191 */ + ], + }, + // State 180 + LR1State { + actions: &[ + (9, 73), /* '(' => LRAction::Reduce(Array, 133) */ + (10, 73), /* ')' => LRAction::Reduce(Array, 133) */ + (12, 73), /* ',' => LRAction::Reduce(Array, 133) */ + (17, 73), /* ';' => LRAction::Reduce(Array, 133) */ + (20, 73), /* ':=' => LRAction::Reduce(Array, 133) */ + (21, 73), /* '||' => LRAction::Reduce(Array, 133) */ + (22, 73), /* '&&' => LRAction::Reduce(Array, 133) */ + (23, 73), /* '>=' => LRAction::Reduce(Array, 133) */ + (24, 73), /* '<=' => LRAction::Reduce(Array, 133) */ + (25, 73), /* '>' => LRAction::Reduce(Array, 133) */ + (26, 73), /* '<' => LRAction::Reduce(Array, 133) */ + (27, 73), /* '!=' => LRAction::Reduce(Array, 133) */ + (28, 73), /* '/=' => LRAction::Reduce(Array, 133) */ + (29, 73), /* '==' => LRAction::Reduce(Array, 133) */ + (30, 73), /* '+' => LRAction::Reduce(Array, 133) */ + (31, 73), /* '-' => LRAction::Reduce(Array, 133) */ + (32, 73), /* '*' => LRAction::Reduce(Array, 133) */ + (33, 73), /* '/' => LRAction::Reduce(Array, 133) */ + (34, 73), /* '%' => LRAction::Reduce(Array, 133) */ + (35, 73), /* 'as' => LRAction::Reduce(Array, 133) */ + (38, 73), /* '&' => LRAction::Reduce(Array, 133) */ + (39, 73), /* '$' => LRAction::Reduce(Array, 133) */ + (40, 73), /* '?' => LRAction::Reduce(Array, 133) */ + (41, 73), /* 'if' => LRAction::Reduce(Array, 133) */ + (43, 73), /* 'select' => LRAction::Reduce(Array, 133) */ + (44, 73), /* '{' => LRAction::Reduce(Array, 133) */ + (46, 73), /* '=>' => LRAction::Reduce(Array, 133) */ + (47, 73), /* '~' => LRAction::Reduce(Array, 133) */ + (48, 73), /* '@' => LRAction::Reduce(Array, 133) */ + (49, 73), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(Array, 133) */ + (50, 73), /* '[' => LRAction::Reduce(Array, 133) */ + (51, 73), /* ']' => LRAction::Reduce(Array, 133) */ + (52, 73), /* '"(\\.|[^"])*"' => LRAction::Reduce(Array, 133) */ + (53, 73), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(Array, 133) */ + (54, 73), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(Array, 133) */ + (55, 73), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Array, 133) */ + (56, 73), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(Array, 133) */ + (57, 73), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(Array, 133) */ + (58, 73), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(Array, 133) */ + (59, 73), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(Array, 133) */ + ], + gotos: &[], + }, + // State 181 + LR1State { + actions: &[ + (9, 158), /* '(' => LRAction::Reduce(LogicalOrExprList, 55) */ + (31, 158), /* '-' => LRAction::Reduce(LogicalOrExprList, 55) */ + (36, 158), /* 'wait' => LRAction::Reduce(LogicalOrExprList, 55) */ + (37, 158), /* 'call' => LRAction::Reduce(LogicalOrExprList, 55) */ + (38, 158), /* '&' => LRAction::Reduce(LogicalOrExprList, 55) */ + (39, 158), /* '$' => LRAction::Reduce(LogicalOrExprList, 55) */ + (41, 158), /* 'if' => LRAction::Reduce(LogicalOrExprList, 55) */ + (43, 158), /* 'select' => LRAction::Reduce(LogicalOrExprList, 55) */ + (47, 158), /* '~' => LRAction::Reduce(LogicalOrExprList, 55) */ + (48, 158), /* '@' => LRAction::Reduce(LogicalOrExprList, 55) */ + (49, 158), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalOrExprList, 55) */ + (50, 158), /* '[' => LRAction::Reduce(LogicalOrExprList, 55) */ + (51, 94), /* ']' => LRAction::Reduce(CommaExprListOpt, 141) */ + (52, 158), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (53, 158), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (54, 158), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (55, 158), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (56, 158), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (57, 158), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (58, 158), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (59, 158), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalOrExprList, 55) */ + ], + gotos: &[ + (17, 192), /* CommaExprListOpt => 192 */ + (20, 193), /* CommaSepElements => 193 */ + (35, 168), /* Expr => 168 */ + (54, 44), /* LogicalOrExpr => 44 */ + (55, 45), /* LogicalOrExprList => 45 */ + (88, 46), /* SetExpr => 46 */ + ], + }, + // State 182 + LR1State { + actions: &[ + (51, 99), /* ']' => LRAction::Reduce(CommaSepElementsOpt, 137) */ + ], + gotos: &[], + }, + // State 183 + LR1State { + actions: &[ + (51, 98), /* ']' => LRAction::Reduce(CommaSepElements, 136) */ + ], + gotos: &[], + }, + // State 184 + LR1State { + actions: &[ + (9, 87), /* '(' => LRAction::Reduce(CallableOpt, 102) */ + (10, 87), /* ')' => LRAction::Reduce(CallableOpt, 102) */ + (12, 87), /* ',' => LRAction::Reduce(CallableOpt, 102) */ + (17, 87), /* ';' => LRAction::Reduce(CallableOpt, 102) */ + (20, 87), /* ':=' => LRAction::Reduce(CallableOpt, 102) */ + (21, 87), /* '||' => LRAction::Reduce(CallableOpt, 102) */ + (22, 87), /* '&&' => LRAction::Reduce(CallableOpt, 102) */ + (23, 87), /* '>=' => LRAction::Reduce(CallableOpt, 102) */ + (24, 87), /* '<=' => LRAction::Reduce(CallableOpt, 102) */ + (25, 87), /* '>' => LRAction::Reduce(CallableOpt, 102) */ + (26, 87), /* '<' => LRAction::Reduce(CallableOpt, 102) */ + (27, 87), /* '!=' => LRAction::Reduce(CallableOpt, 102) */ + (28, 87), /* '/=' => LRAction::Reduce(CallableOpt, 102) */ + (29, 87), /* '==' => LRAction::Reduce(CallableOpt, 102) */ + (30, 87), /* '+' => LRAction::Reduce(CallableOpt, 102) */ + (31, 87), /* '-' => LRAction::Reduce(CallableOpt, 102) */ + (32, 87), /* '*' => LRAction::Reduce(CallableOpt, 102) */ + (33, 87), /* '/' => LRAction::Reduce(CallableOpt, 102) */ + (34, 87), /* '%' => LRAction::Reduce(CallableOpt, 102) */ + (35, 87), /* 'as' => LRAction::Reduce(CallableOpt, 102) */ + (38, 87), /* '&' => LRAction::Reduce(CallableOpt, 102) */ + (39, 87), /* '$' => LRAction::Reduce(CallableOpt, 102) */ + (41, 87), /* 'if' => LRAction::Reduce(CallableOpt, 102) */ + (43, 87), /* 'select' => LRAction::Reduce(CallableOpt, 102) */ + (44, 87), /* '{' => LRAction::Reduce(CallableOpt, 102) */ + (46, 87), /* '=>' => LRAction::Reduce(CallableOpt, 102) */ + (47, 87), /* '~' => LRAction::Reduce(CallableOpt, 102) */ + (48, 87), /* '@' => LRAction::Reduce(CallableOpt, 102) */ + (49, 87), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(CallableOpt, 102) */ + (50, 87), /* '[' => LRAction::Reduce(CallableOpt, 102) */ + (51, 87), /* ']' => LRAction::Reduce(CallableOpt, 102) */ + (52, 87), /* '"(\\.|[^"])*"' => LRAction::Reduce(CallableOpt, 102) */ + (53, 87), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(CallableOpt, 102) */ + (54, 87), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(CallableOpt, 102) */ + (55, 87), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CallableOpt, 102) */ + (56, 87), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(CallableOpt, 102) */ + (57, 87), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(CallableOpt, 102) */ + (58, 87), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(CallableOpt, 102) */ + (59, 87), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(CallableOpt, 102) */ + ], + gotos: &[], + }, + // State 185 + LR1State { + actions: &[ + (9, 145), /* '(' => LRAction::Reduce(KindArg, 122) */ + (10, 145), /* ')' => LRAction::Reduce(KindArg, 122) */ + (12, 145), /* ',' => LRAction::Reduce(KindArg, 122) */ + (17, 145), /* ';' => LRAction::Reduce(KindArg, 122) */ + (20, 145), /* ':=' => LRAction::Reduce(KindArg, 122) */ + (21, 145), /* '||' => LRAction::Reduce(KindArg, 122) */ + (22, 145), /* '&&' => LRAction::Reduce(KindArg, 122) */ + (23, 145), /* '>=' => LRAction::Reduce(KindArg, 122) */ + (24, 145), /* '<=' => LRAction::Reduce(KindArg, 122) */ + (25, 145), /* '>' => LRAction::Reduce(KindArg, 122) */ + (26, 145), /* '<' => LRAction::Reduce(KindArg, 122) */ + (27, 145), /* '!=' => LRAction::Reduce(KindArg, 122) */ + (28, 145), /* '/=' => LRAction::Reduce(KindArg, 122) */ + (29, 145), /* '==' => LRAction::Reduce(KindArg, 122) */ + (30, 145), /* '+' => LRAction::Reduce(KindArg, 122) */ + (31, 145), /* '-' => LRAction::Reduce(KindArg, 122) */ + (32, 145), /* '*' => LRAction::Reduce(KindArg, 122) */ + (33, 145), /* '/' => LRAction::Reduce(KindArg, 122) */ + (34, 145), /* '%' => LRAction::Reduce(KindArg, 122) */ + (35, 145), /* 'as' => LRAction::Reduce(KindArg, 122) */ + (38, 145), /* '&' => LRAction::Reduce(KindArg, 122) */ + (39, 145), /* '$' => LRAction::Reduce(KindArg, 122) */ + (41, 145), /* 'if' => LRAction::Reduce(KindArg, 122) */ + (43, 145), /* 'select' => LRAction::Reduce(KindArg, 122) */ + (44, 145), /* '{' => LRAction::Reduce(KindArg, 122) */ + (46, 145), /* '=>' => LRAction::Reduce(KindArg, 122) */ + (47, 145), /* '~' => LRAction::Reduce(KindArg, 122) */ + (48, 145), /* '@' => LRAction::Reduce(KindArg, 122) */ + (49, 145), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(KindArg, 122) */ + (50, 145), /* '[' => LRAction::Reduce(KindArg, 122) */ + (51, 145), /* ']' => LRAction::Reduce(KindArg, 122) */ + (52, 145), /* '"(\\.|[^"])*"' => LRAction::Reduce(KindArg, 122) */ + (53, 145), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(KindArg, 122) */ + (54, 145), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(KindArg, 122) */ + (55, 145), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(KindArg, 122) */ + (56, 145), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(KindArg, 122) */ + (57, 145), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(KindArg, 122) */ + (58, 145), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(KindArg, 122) */ + (59, 145), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(KindArg, 122) */ + ], + gotos: &[], + }, + // State 186 + LR1State { + actions: &[(44, 14) /* '{' => LRAction::Shift(48) */], + gotos: &[(9, 194) /* Block => 194 */], + }, + // State 187 + LR1State { + actions: &[ + (9, 142), /* '(' => LRAction::Reduce(IfExpr, 106) */ + (10, 142), /* ')' => LRAction::Reduce(IfExpr, 106) */ + (12, 142), /* ',' => LRAction::Reduce(IfExpr, 106) */ + (17, 142), /* ';' => LRAction::Reduce(IfExpr, 106) */ + (20, 142), /* ':=' => LRAction::Reduce(IfExpr, 106) */ + (21, 142), /* '||' => LRAction::Reduce(IfExpr, 106) */ + (22, 142), /* '&&' => LRAction::Reduce(IfExpr, 106) */ + (23, 142), /* '>=' => LRAction::Reduce(IfExpr, 106) */ + (24, 142), /* '<=' => LRAction::Reduce(IfExpr, 106) */ + (25, 142), /* '>' => LRAction::Reduce(IfExpr, 106) */ + (26, 142), /* '<' => LRAction::Reduce(IfExpr, 106) */ + (27, 142), /* '!=' => LRAction::Reduce(IfExpr, 106) */ + (28, 142), /* '/=' => LRAction::Reduce(IfExpr, 106) */ + (29, 142), /* '==' => LRAction::Reduce(IfExpr, 106) */ + (30, 142), /* '+' => LRAction::Reduce(IfExpr, 106) */ + (31, 142), /* '-' => LRAction::Reduce(IfExpr, 106) */ + (32, 142), /* '*' => LRAction::Reduce(IfExpr, 106) */ + (33, 142), /* '/' => LRAction::Reduce(IfExpr, 106) */ + (34, 142), /* '%' => LRAction::Reduce(IfExpr, 106) */ + (35, 142), /* 'as' => LRAction::Reduce(IfExpr, 106) */ + (38, 142), /* '&' => LRAction::Reduce(IfExpr, 106) */ + (39, 142), /* '$' => LRAction::Reduce(IfExpr, 106) */ + (41, 142), /* 'if' => LRAction::Reduce(IfExpr, 106) */ + (43, 142), /* 'select' => LRAction::Reduce(IfExpr, 106) */ + (44, 142), /* '{' => LRAction::Reduce(IfExpr, 106) */ + (46, 142), /* '=>' => LRAction::Reduce(IfExpr, 106) */ + (47, 142), /* '~' => LRAction::Reduce(IfExpr, 106) */ + (48, 142), /* '@' => LRAction::Reduce(IfExpr, 106) */ + (49, 142), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(IfExpr, 106) */ + (50, 142), /* '[' => LRAction::Reduce(IfExpr, 106) */ + (51, 142), /* ']' => LRAction::Reduce(IfExpr, 106) */ + (52, 142), /* '"(\\.|[^"])*"' => LRAction::Reduce(IfExpr, 106) */ + (53, 142), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(IfExpr, 106) */ + (54, 142), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(IfExpr, 106) */ + (55, 142), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(IfExpr, 106) */ + (56, 142), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(IfExpr, 106) */ + (57, 142), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(IfExpr, 106) */ + (58, 142), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(IfExpr, 106) */ + (59, 142), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(IfExpr, 106) */ + ], + gotos: &[], + }, + // State 188 + LR1State { + actions: &[(44, 14) /* '{' => LRAction::Shift(48) */], + gotos: &[(9, 195) /* Block => 195 */], + }, + // State 189 + LR1State { + actions: &[ + (9, 203), /* '(' => LRAction::Reduce(SelectExpr, 109) */ + (10, 203), /* ')' => LRAction::Reduce(SelectExpr, 109) */ + (12, 203), /* ',' => LRAction::Reduce(SelectExpr, 109) */ + (17, 203), /* ';' => LRAction::Reduce(SelectExpr, 109) */ + (20, 203), /* ':=' => LRAction::Reduce(SelectExpr, 109) */ + (21, 203), /* '||' => LRAction::Reduce(SelectExpr, 109) */ + (22, 203), /* '&&' => LRAction::Reduce(SelectExpr, 109) */ + (23, 203), /* '>=' => LRAction::Reduce(SelectExpr, 109) */ + (24, 203), /* '<=' => LRAction::Reduce(SelectExpr, 109) */ + (25, 203), /* '>' => LRAction::Reduce(SelectExpr, 109) */ + (26, 203), /* '<' => LRAction::Reduce(SelectExpr, 109) */ + (27, 203), /* '!=' => LRAction::Reduce(SelectExpr, 109) */ + (28, 203), /* '/=' => LRAction::Reduce(SelectExpr, 109) */ + (29, 203), /* '==' => LRAction::Reduce(SelectExpr, 109) */ + (30, 203), /* '+' => LRAction::Reduce(SelectExpr, 109) */ + (31, 203), /* '-' => LRAction::Reduce(SelectExpr, 109) */ + (32, 203), /* '*' => LRAction::Reduce(SelectExpr, 109) */ + (33, 203), /* '/' => LRAction::Reduce(SelectExpr, 109) */ + (34, 203), /* '%' => LRAction::Reduce(SelectExpr, 109) */ + (35, 203), /* 'as' => LRAction::Reduce(SelectExpr, 109) */ + (38, 203), /* '&' => LRAction::Reduce(SelectExpr, 109) */ + (39, 203), /* '$' => LRAction::Reduce(SelectExpr, 109) */ + (41, 203), /* 'if' => LRAction::Reduce(SelectExpr, 109) */ + (43, 203), /* 'select' => LRAction::Reduce(SelectExpr, 109) */ + (44, 203), /* '{' => LRAction::Reduce(SelectExpr, 109) */ + (46, 203), /* '=>' => LRAction::Reduce(SelectExpr, 109) */ + (47, 203), /* '~' => LRAction::Reduce(SelectExpr, 109) */ + (48, 203), /* '@' => LRAction::Reduce(SelectExpr, 109) */ + (49, 203), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(SelectExpr, 109) */ + (50, 203), /* '[' => LRAction::Reduce(SelectExpr, 109) */ + (51, 203), /* ']' => LRAction::Reduce(SelectExpr, 109) */ + (52, 203), /* '"(\\.|[^"])*"' => LRAction::Reduce(SelectExpr, 109) */ + (53, 203), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(SelectExpr, 109) */ + (54, 203), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(SelectExpr, 109) */ + (55, 203), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(SelectExpr, 109) */ + (56, 203), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(SelectExpr, 109) */ + (57, 203), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(SelectExpr, 109) */ + (58, 203), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(SelectExpr, 109) */ + (59, 203), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(SelectExpr, 109) */ + ], + gotos: &[], + }, + // State 190 + LR1State { + actions: &[ + (5, 207), /* '\r?\n|\r' => LRAction::Reduce(SelectScopeOpt, 114) */ + (9, 158), /* '(' => LRAction::Reduce(LogicalOrExprList, 55) */ + (31, 158), /* '-' => LRAction::Reduce(LogicalOrExprList, 55) */ + (36, 158), /* 'wait' => LRAction::Reduce(LogicalOrExprList, 55) */ + (37, 158), /* 'call' => LRAction::Reduce(LogicalOrExprList, 55) */ + (38, 158), /* '&' => LRAction::Reduce(LogicalOrExprList, 55) */ + (39, 158), /* '$' => LRAction::Reduce(LogicalOrExprList, 55) */ + (41, 158), /* 'if' => LRAction::Reduce(LogicalOrExprList, 55) */ + (43, 158), /* 'select' => LRAction::Reduce(LogicalOrExprList, 55) */ + (45, 207), /* '}' => LRAction::Reduce(SelectScopeOpt, 114) */ + (47, 158), /* '~' => LRAction::Reduce(LogicalOrExprList, 55) */ + (48, 158), /* '@' => LRAction::Reduce(LogicalOrExprList, 55) */ + (49, 158), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(LogicalOrExprList, 55) */ + (50, 158), /* '[' => LRAction::Reduce(LogicalOrExprList, 55) */ + (52, 158), /* '"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (53, 158), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (54, 158), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(LogicalOrExprList, 55) */ + (55, 158), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (56, 158), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (57, 158), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (58, 158), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(LogicalOrExprList, 55) */ + (59, 158), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(LogicalOrExprList, 55) */ + ], + gotos: &[ + (35, 176), /* Expr => 176 */ + (54, 44), /* LogicalOrExpr => 44 */ + (55, 45), /* LogicalOrExprList => 45 */ + (83, 196), /* SelectScope => 196 */ + (84, 178), /* SelectScopeContent => 178 */ + (85, 179), /* SelectScopeOpt => 179 */ + (88, 46), /* SetExpr => 46 */ + ], + }, + // State 191 + LR1State { + actions: &[ + (45, 204), /* '}' => LRAction::Reduce(SelectScope, 110) */ + ], + gotos: &[], + }, + // State 192 + LR1State { + actions: &[ + (51, 92), /* ']' => LRAction::Reduce(CommaExprList, 139) */ + ], + gotos: &[], + }, + // State 193 + LR1State { + actions: &[ + (51, 93), /* ']' => LRAction::Reduce(CommaExprListOpt, 140) */ + ], + gotos: &[], + }, + // State 194 + LR1State { + actions: &[ + (9, 143), /* '(' => LRAction::Reduce(IfExprOpt, 107) */ + (10, 143), /* ')' => LRAction::Reduce(IfExprOpt, 107) */ + (12, 143), /* ',' => LRAction::Reduce(IfExprOpt, 107) */ + (17, 143), /* ';' => LRAction::Reduce(IfExprOpt, 107) */ + (20, 143), /* ':=' => LRAction::Reduce(IfExprOpt, 107) */ + (21, 143), /* '||' => LRAction::Reduce(IfExprOpt, 107) */ + (22, 143), /* '&&' => LRAction::Reduce(IfExprOpt, 107) */ + (23, 143), /* '>=' => LRAction::Reduce(IfExprOpt, 107) */ + (24, 143), /* '<=' => LRAction::Reduce(IfExprOpt, 107) */ + (25, 143), /* '>' => LRAction::Reduce(IfExprOpt, 107) */ + (26, 143), /* '<' => LRAction::Reduce(IfExprOpt, 107) */ + (27, 143), /* '!=' => LRAction::Reduce(IfExprOpt, 107) */ + (28, 143), /* '/=' => LRAction::Reduce(IfExprOpt, 107) */ + (29, 143), /* '==' => LRAction::Reduce(IfExprOpt, 107) */ + (30, 143), /* '+' => LRAction::Reduce(IfExprOpt, 107) */ + (31, 143), /* '-' => LRAction::Reduce(IfExprOpt, 107) */ + (32, 143), /* '*' => LRAction::Reduce(IfExprOpt, 107) */ + (33, 143), /* '/' => LRAction::Reduce(IfExprOpt, 107) */ + (34, 143), /* '%' => LRAction::Reduce(IfExprOpt, 107) */ + (35, 143), /* 'as' => LRAction::Reduce(IfExprOpt, 107) */ + (38, 143), /* '&' => LRAction::Reduce(IfExprOpt, 107) */ + (39, 143), /* '$' => LRAction::Reduce(IfExprOpt, 107) */ + (41, 143), /* 'if' => LRAction::Reduce(IfExprOpt, 107) */ + (43, 143), /* 'select' => LRAction::Reduce(IfExprOpt, 107) */ + (44, 143), /* '{' => LRAction::Reduce(IfExprOpt, 107) */ + (46, 143), /* '=>' => LRAction::Reduce(IfExprOpt, 107) */ + (47, 143), /* '~' => LRAction::Reduce(IfExprOpt, 107) */ + (48, 143), /* '@' => LRAction::Reduce(IfExprOpt, 107) */ + (49, 143), /* '[_a-zA-Z](\w|[\/-])*' => LRAction::Reduce(IfExprOpt, 107) */ + (50, 143), /* '[' => LRAction::Reduce(IfExprOpt, 107) */ + (51, 143), /* ']' => LRAction::Reduce(IfExprOpt, 107) */ + (52, 143), /* '"(\\.|[^"])*"' => LRAction::Reduce(IfExprOpt, 107) */ + (53, 143), /* 'b"(\\.|[^"])*"' => LRAction::Reduce(IfExprOpt, 107) */ + (54, 143), /* 'bx"[0-9a-fA-F_]*"' => LRAction::Reduce(IfExprOpt, 107) */ + (55, 143), /* '0b[01_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(IfExprOpt, 107) */ + (56, 143), /* '0o[0-7_]+([a-zA-Z](\w|[\/-])*)?' => LRAction::Reduce(IfExprOpt, 107) */ + (57, 143), /* '0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?' => LRAction::Reduce(IfExprOpt, 107) */ + (58, 143), /* '[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?' => LRAction::Reduce(IfExprOpt, 107) */ + (59, 143), /* '\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})' => LRAction::Reduce(IfExprOpt, 107) */ + ], + gotos: &[], + }, + // State 195 + LR1State { + actions: &[ + (5, 205), /* '\r?\n|\r' => LRAction::Reduce(SelectScopeContent, 115) */ + (45, 205), /* '}' => LRAction::Reduce(SelectScopeContent, 115) */ + ], + gotos: &[], + }, + // State 196 + LR1State { + actions: &[ + (45, 208), /* '}' => LRAction::Reduce(SelectScopeOpt0, 111) */ + ], + gotos: &[], + }, + ], +}; + +pub const PRODUCTIONS: &[LRProduction; 155] = &[ + // 0 - Program0: Program; + LRProduction { lhs: 71, len: 1 }, + // 1 - EndOfLine: /\r?\n|\r/; + LRProduction { lhs: 34, len: 1 }, + // 2 - Comment: Hash CommentOpt /* Option */; + LRProduction { lhs: 22, len: 2 }, + // 3 - CommentOpt: CommentContent; + LRProduction { lhs: 24, len: 1 }, + // 4 - CommentOpt: ; + LRProduction { lhs: 24, len: 0 }, + // 5 - Hash: '#'; + LRProduction { lhs: 42, len: 1 }, + // 6 - CommentContent: /[^\r\n]*/; + LRProduction { lhs: 23, len: 1 }, + // 7 - Program: Definition EndOfLine Program; + LRProduction { lhs: 70, len: 3 }, + // 8 - Program: Definition; + LRProduction { lhs: 70, len: 1 }, + // 9 - Definition: DefinitionOpt /* Option */ DefinitionOpt0 /* Option */; + LRProduction { lhs: 30, len: 2 }, + // 10 - DefinitionOpt0: Comment; + LRProduction { lhs: 32, len: 1 }, + // 11 - DefinitionOpt0: ; + LRProduction { lhs: 32, len: 0 }, + // 12 - DefinitionOpt: DefinitionOptGroup; + LRProduction { lhs: 31, len: 1 }, + // 13 - DefinitionOptGroup: FunctionDef; + LRProduction { lhs: 33, len: 1 }, + // 14 - DefinitionOptGroup: ConstantDef; + LRProduction { lhs: 33, len: 1 }, + // 15 - DefinitionOpt: ; + LRProduction { lhs: 31, len: 0 }, + // 16 - FunctionDef: 'prc' Ident '(' FunctionDefOpt /* Option */ ')' FunctionDefOpt0 /* Option */ Block; + LRProduction { lhs: 39, len: 7 }, + // 17 - FunctionDefOpt0: '->' Path; + LRProduction { lhs: 41, len: 2 }, + // 18 - FunctionDefOpt0: ; + LRProduction { lhs: 41, len: 0 }, + // 19 - FunctionDefOpt: ParameterList; + LRProduction { lhs: 40, len: 1 }, + // 20 - FunctionDefOpt: ; + LRProduction { lhs: 40, len: 0 }, + // 21 - ParameterList: Parameter ParameterListOpt /* Option */; + LRProduction { lhs: 64, len: 2 }, + // 22 - ParameterListOpt: CommaParameterList; + LRProduction { lhs: 65, len: 1 }, + // 23 - ParameterListOpt: ; + LRProduction { lhs: 65, len: 0 }, + // 24 - CommaParameterList: ',' CommaParameterListOpt /* Option */; + LRProduction { lhs: 18, len: 2 }, + // 25 - CommaParameterListOpt: ParameterList; + LRProduction { lhs: 19, len: 1 }, + // 26 - CommaParameterListOpt: ; + LRProduction { lhs: 19, len: 0 }, + // 27 - Parameter: Ident ':' Path; + LRProduction { lhs: 63, len: 3 }, + // 28 - ConstantDef: 'const' Ident ':' Path '=' Expr Semi; + LRProduction { lhs: 28, len: 7 }, + // 29 - Scope: ScopeContent ScopeOpt /* Option */; + LRProduction { lhs: 75, len: 2 }, + // 30 - ScopeOpt: EndOfLine Scope; + LRProduction { lhs: 81, len: 2 }, + // 31 - ScopeOpt: ; + LRProduction { lhs: 81, len: 0 }, + // 32 - ScopeContent: ScopeContentOpt /* Option */ ScopeContentOpt0 /* Option */ ScopeContentOpt1 /* Option */; + LRProduction { lhs: 76, len: 3 }, + // 33 - ScopeContentOpt1: Comment; + LRProduction { lhs: 80, len: 1 }, + // 34 - ScopeContentOpt1: ; + LRProduction { lhs: 80, len: 0 }, + // 35 - ScopeContentOpt0: ScopeContentKind; + LRProduction { lhs: 79, len: 1 }, + // 36 - ScopeContentOpt0: ; + LRProduction { lhs: 79, len: 0 }, + // 37 - ScopeContentOpt: Break; + LRProduction { lhs: 78, len: 1 }, + // 38 - ScopeContentOpt: ; + LRProduction { lhs: 78, len: 0 }, + // 39 - ScopeContentKind: Statement; + LRProduction { lhs: 77, len: 1 }, + // 40 - ScopeContentKind: Block; + LRProduction { lhs: 77, len: 1 }, + // 41 - Statement: StatementKind Semi; + LRProduction { lhs: 90, len: 2 }, + // 42 - Break: '.'; + LRProduction { lhs: 10, len: 1 }, + // 43 - Semi: ';'; + LRProduction { lhs: 87, len: 1 }, + // 44 - StatementKind: LetStmt; + LRProduction { lhs: 91, len: 1 }, + // 45 - StatementKind: Expr; + LRProduction { lhs: 91, len: 1 }, + // 46 - StatementKind: ReturnStmt; + LRProduction { lhs: 91, len: 1 }, + // 47 - ReturnStmt: 'return'; + LRProduction { lhs: 73, len: 1 }, + // 48 - LetStmt: 'let' Ident '=' Expr; + LRProduction { lhs: 50, len: 4 }, + // 49 - Expr: SetExpr; + LRProduction { lhs: 35, len: 1 }, + // 50 - SetExpr: LogicalOrExpr SetExprOpt /* Option */; + LRProduction { lhs: 88, len: 2 }, + // 51 - SetExprOpt: ':=' LogicalOrExpr; + LRProduction { lhs: 89, len: 2 }, + // 52 - SetExprOpt: ; + LRProduction { lhs: 89, len: 0 }, + // 53 - LogicalOrExpr: LogicalOrExprList /* Vec */ LogicalAndExpr; + LRProduction { lhs: 54, len: 2 }, + // 54 - LogicalOrExprList: LogicalOrExprList LogicalAndExpr '||'; + LRProduction { lhs: 55, len: 3 }, + // 55 - LogicalOrExprList: ; + LRProduction { lhs: 55, len: 0 }, + // 56 - LogicalAndExpr: LogicalAndExprList /* Vec */ CompareExpr; + LRProduction { lhs: 52, len: 2 }, + // 57 - LogicalAndExprList: LogicalAndExprList CompareExpr '&&'; + LRProduction { lhs: 53, len: 3 }, + // 58 - LogicalAndExprList: ; + LRProduction { lhs: 53, len: 0 }, + // 59 - CompareExpr: ArithmeticExpr CompareExprList /* Vec */; + LRProduction { lhs: 25, len: 2 }, + // 60 - CompareExprList: CompareExprList CompareOp ArithmeticExpr; + LRProduction { lhs: 26, len: 3 }, + // 61 - CompareExprList: ; + LRProduction { lhs: 26, len: 0 }, + // 62 - CompareOp: '>='; + LRProduction { lhs: 27, len: 1 }, + // 63 - CompareOp: '<='; + LRProduction { lhs: 27, len: 1 }, + // 64 - CompareOp: '>'; + LRProduction { lhs: 27, len: 1 }, + // 65 - CompareOp: '<'; + LRProduction { lhs: 27, len: 1 }, + // 66 - CompareOp: '!='; + LRProduction { lhs: 27, len: 1 }, + // 67 - CompareOp: '/='; + LRProduction { lhs: 27, len: 1 }, + // 68 - CompareOp: '=='; + LRProduction { lhs: 27, len: 1 }, + // 69 - ArithmeticExpr: ArithmeticExprList /* Vec */ FactorExpr; + LRProduction { lhs: 2, len: 2 }, + // 70 - ArithmeticExprList: ArithmeticExprList FactorExpr ArithmeticOp; + LRProduction { lhs: 3, len: 3 }, + // 71 - ArithmeticExprList: ; + LRProduction { lhs: 3, len: 0 }, + // 72 - ArithmeticOp: '+'; + LRProduction { lhs: 4, len: 1 }, + // 73 - ArithmeticOp: '-'; + LRProduction { lhs: 4, len: 1 }, + // 74 - FactorExpr: FactorExprList /* Vec */ CastExpr; + LRProduction { lhs: 36, len: 2 }, + // 75 - FactorExprList: FactorExprList CastExpr FactorOp; + LRProduction { lhs: 37, len: 3 }, + // 76 - FactorExprList: ; + LRProduction { lhs: 37, len: 0 }, + // 77 - FactorOp: '*'; + LRProduction { lhs: 38, len: 1 }, + // 78 - FactorOp: '/'; + LRProduction { lhs: 38, len: 1 }, + // 79 - FactorOp: '%'; + LRProduction { lhs: 38, len: 1 }, + // 80 - CastExpr: PrefixExpr CastExprOpt /* Option */; + LRProduction { lhs: 14, len: 2 }, + // 81 - CastExprOpt: 'as' Path; + LRProduction { lhs: 15, len: 2 }, + // 82 - CastExprOpt: ; + LRProduction { lhs: 15, len: 0 }, + // 83 - PrefixExpr: '-' ApplyExpr; + LRProduction { lhs: 68, len: 2 }, + // 84 - PrefixExpr: PrefixExprList /* Vec */ ApplyExpr; + LRProduction { lhs: 68, len: 2 }, + // 85 - PrefixExprList: PrefixExprList Qualif; + LRProduction { lhs: 69, len: 2 }, + // 86 - PrefixExprList: ; + LRProduction { lhs: 69, len: 0 }, + // 87 - PrefixExpr: 'wait' ApplyExpr; + LRProduction { lhs: 68, len: 2 }, + // 88 - PrefixExpr: 'call' ApplyExpr; + LRProduction { lhs: 68, len: 2 }, + // 89 - ApplyExpr: LowerPrefixExpr ApplyExprList /* Vec */; + LRProduction { lhs: 0, len: 2 }, + // 90 - ApplyExprList: ApplyExprList AtomicExpr; + LRProduction { lhs: 1, len: 2 }, + // 91 - ApplyExprList: ; + LRProduction { lhs: 1, len: 0 }, + // 92 - LowerPrefixExpr: LowerPrefixExprOpt /* Option */ Callable; + LRProduction { lhs: 56, len: 2 }, + // 93 - LowerPrefixExprOpt: LowerPrefixOp; + LRProduction { lhs: 57, len: 1 }, + // 94 - LowerPrefixExprOpt: ; + LRProduction { lhs: 57, len: 0 }, + // 95 - LowerPrefixOp: '&'; + LRProduction { lhs: 58, len: 1 }, + // 96 - LowerPrefixOp: '$'; + LRProduction { lhs: 58, len: 1 }, + // 97 - Callable: Path; + LRProduction { lhs: 12, len: 1 }, + // 98 - Callable: Literal CallableOpt /* Option */; + LRProduction { lhs: 12, len: 2 }, + // 99 - Callable: '(' Expr ')'; + LRProduction { lhs: 12, len: 3 }, + // 100 - Callable: IfExpr; + LRProduction { lhs: 12, len: 1 }, + // 101 - Callable: SelectExpr; + LRProduction { lhs: 12, len: 1 }, + // 102 - CallableOpt: '?' Path; + LRProduction { lhs: 13, len: 2 }, + // 103 - CallableOpt: ; + LRProduction { lhs: 13, len: 0 }, + // 104 - AtomicExpr: Qualif; + LRProduction { lhs: 7, len: 1 }, + // 105 - AtomicExpr: LowerPrefixExpr; + LRProduction { lhs: 7, len: 1 }, + // 106 - IfExpr: 'if' Expr Block IfExprOpt /* Option */; + LRProduction { lhs: 47, len: 4 }, + // 107 - IfExprOpt: 'else' Block; + LRProduction { lhs: 48, len: 2 }, + // 108 - IfExprOpt: ; + LRProduction { lhs: 48, len: 0 }, + // 109 - SelectExpr: 'select' '{' SelectScope '}'; + LRProduction { lhs: 82, len: 4 }, + // 110 - SelectScope: SelectScopeOpt /* Option */ SelectScopeOpt0 /* Option */; + LRProduction { lhs: 83, len: 2 }, + // 111 - SelectScopeOpt0: EndOfLine SelectScope; + LRProduction { lhs: 86, len: 2 }, + // 112 - SelectScopeOpt0: ; + LRProduction { lhs: 86, len: 0 }, + // 113 - SelectScopeOpt: SelectScopeContent; + LRProduction { lhs: 85, len: 1 }, + // 114 - SelectScopeOpt: ; + LRProduction { lhs: 85, len: 0 }, + // 115 - SelectScopeContent: Expr '=>' Block; + LRProduction { lhs: 84, len: 3 }, + // 116 - Qualif: Modifier; + LRProduction { lhs: 72, len: 1 }, + // 117 - Qualif: DefaultModifier; + LRProduction { lhs: 72, len: 1 }, + // 118 - DefaultModifier: '~' Path; + LRProduction { lhs: 29, len: 2 }, + // 119 - Modifier: '@' Path ModifierOpt /* Option */; + LRProduction { lhs: 59, len: 3 }, + // 120 - ModifierOpt: KindArg; + LRProduction { lhs: 60, len: 1 }, + // 121 - ModifierOpt: ; + LRProduction { lhs: 60, len: 0 }, + // 122 - KindArg: ':' Callable; + LRProduction { lhs: 49, len: 2 }, + // 123 - Path: Ident PathList /* Vec */; + LRProduction { lhs: 66, len: 2 }, + // 124 - PathList: PathList '.' Ident; + LRProduction { lhs: 67, len: 3 }, + // 125 - PathList: ; + LRProduction { lhs: 67, len: 0 }, + // 126 - Ident: /[_a-zA-Z](\w|[\/-])*/; + LRProduction { lhs: 45, len: 1 }, + // 127 - Literal: Array; + LRProduction { lhs: 51, len: 1 }, + // 128 - Literal: String; + LRProduction { lhs: 51, len: 1 }, + // 129 - Literal: ByteLiteral; + LRProduction { lhs: 51, len: 1 }, + // 130 - Literal: HexByteLiteral; + LRProduction { lhs: 51, len: 1 }, + // 131 - Literal: Numeric; + LRProduction { lhs: 51, len: 1 }, + // 132 - Literal: Rfc3339DateTime; + LRProduction { lhs: 51, len: 1 }, + // 133 - Array: '[' ArrayOpt /* Option */ ']'; + LRProduction { lhs: 5, len: 3 }, + // 134 - ArrayOpt: CommaSepElements; + LRProduction { lhs: 6, len: 1 }, + // 135 - ArrayOpt: ; + LRProduction { lhs: 6, len: 0 }, + // 136 - CommaSepElements: Expr CommaSepElementsOpt /* Option */; + LRProduction { lhs: 20, len: 2 }, + // 137 - CommaSepElementsOpt: CommaExprList; + LRProduction { lhs: 21, len: 1 }, + // 138 - CommaSepElementsOpt: ; + LRProduction { lhs: 21, len: 0 }, + // 139 - CommaExprList: ',' CommaExprListOpt /* Option */; + LRProduction { lhs: 16, len: 2 }, + // 140 - CommaExprListOpt: CommaSepElements; + LRProduction { lhs: 17, len: 1 }, + // 141 - CommaExprListOpt: ; + LRProduction { lhs: 17, len: 0 }, + // 142 - String: /"(\\.|[^"])*"/; + LRProduction { lhs: 92, len: 1 }, + // 143 - ByteLiteral: /b"(\\.|[^"])*"/; + LRProduction { lhs: 11, len: 1 }, + // 144 - HexByteLiteral: /bx"[0-9a-fA-F_]*"/; + LRProduction { lhs: 43, len: 1 }, + // 145 - Numeric: BinaryInteger; + LRProduction { lhs: 61, len: 1 }, + // 146 - Numeric: OctalInteger; + LRProduction { lhs: 61, len: 1 }, + // 147 - Numeric: HexadecimalInteger; + LRProduction { lhs: 61, len: 1 }, + // 148 - Numeric: Ieee754Float; + LRProduction { lhs: 61, len: 1 }, + // 149 - BinaryInteger: /0b[01_]+([a-zA-Z](\w|[\/-])*)?/; + LRProduction { lhs: 8, len: 1 }, + // 150 - OctalInteger: /0o[0-7_]+([a-zA-Z](\w|[\/-])*)?/; + LRProduction { lhs: 62, len: 1 }, + // 151 - HexadecimalInteger: /0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?/; + LRProduction { lhs: 44, len: 1 }, + // 152 - Ieee754Float: /[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?/; + LRProduction { lhs: 46, len: 1 }, + // 153 - Rfc3339DateTime: /\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})/; + LRProduction { lhs: 74, len: 1 }, + // 154 - Block: '{' Scope '}'; + LRProduction { lhs: 9, len: 3 }, +]; + +static SCANNERS: Lazy> = Lazy::new(|| { + vec![ + ScannerConfig::new( + "INITIAL", + Tokenizer::build(TERMINALS, SCANNER_0.0, SCANNER_0.1).unwrap(), + &[(6 /* Hash */, 1 /* Cmnt */)], + ), + ScannerConfig::new( + "Cmnt", + Tokenizer::build(TERMINALS, SCANNER_1.0, SCANNER_1.1).unwrap(), + &[(5 /* EndOfLine */, 0 /* INITIAL */)], + ), + ] +}); + +pub fn parse<'t, T>( + input: &'t str, + file_name: T, + user_actions: &mut Action<'t>, +) -> Result +where + T: AsRef, +{ + let mut lr_parser = LRParser::new(71, &PARSE_TABLE, PRODUCTIONS, TERMINAL_NAMES, NON_TERMINALS); + lr_parser.trim_parse_tree(); + + // Initialize wrapper + let mut user_actions = ActionAuto::new(user_actions); + lr_parser.parse( + TokenStream::new(input, file_name, &SCANNERS, 1).unwrap(), + &mut user_actions, + ) +} diff --git a/opslang-parser/src/version/v1/grammar.par b/opslang-parser/src/version/v1/grammar.par new file mode 100644 index 0000000..08b56a5 --- /dev/null +++ b/opslang-parser/src/version/v1/grammar.par @@ -0,0 +1,271 @@ +%start Program +%title "opslang v1 grammar" +%grammar_type 'LALR(1)' +%auto_newline_off + +%on Hash %enter Cmnt + +%scanner Cmnt { + %auto_newline_off + %auto_ws_off + %on EndOfLine %enter INITIAL +} + +%% + +EndOfLine + : /\r?\n|\r/ + ; + +Comment: Hash [ CommentContent ]; + +Hash: '#'; + +CommentContent + : /[^\r\n]*/ + ; + +// `Definition [ EndOfLine Program ]` don't work (?) +Program + : Definition EndOfLine Program + | Definition; + +Definition + : [ FunctionDef | ConstantDef ] [ Comment ] + ; + +FunctionDef + : 'prc' Ident '(' [ ParameterList ] ')' [ '->' Path ] Block + ; + +ParameterList + : Parameter [ CommaParameterList ] + ; + +CommaParameterList + : ',' [ ParameterList ] + ; + +Parameter + : Ident ':' Path + ; + +ConstantDef + : 'const' Ident ':' Path '=' Expr Semi + ; + +Scope + : ScopeContent [ EndOfLine Scope ] + ; + +ScopeContent + : [ Break ] [ ScopeContentKind ] [ Comment ] + ; + +ScopeContentKind + : Statement + | Block + ; + +Statement: StatementKind Semi; + +Break: '.'; +Semi: ';'; + +StatementKind + : LetStmt + | Expr + | ReturnStmt + ; + +ReturnStmt: 'return'; + +LetStmt + : 'let' Ident '=' Expr + ; + +// Precedence climbing method +Expr + : SetExpr + ; + +// `:=`: lower than `||` +SetExpr + : LogicalOrExpr [ ':=' LogicalOrExpr ] + ; + +// `||` : lower than `&&` +LogicalOrExpr + : { LogicalAndExpr '||' } LogicalAndExpr + ; + +// `&&` : lower then compare +LogicalAndExpr + : { CompareExpr '&&' } CompareExpr + ; + +// `>=`, `<=`, `>`, `<`, `!=` (`/=`), `==` +// : lower then arithmetic +CompareExpr + : ArithmeticExpr { CompareOp ArithmeticExpr } + ; + +CompareOp + : '>=' + | '<=' + | '>' + | '<' + | '!=' + | '/=' + | '==' + ; + +// `+`, `-` +// : lower then factor +ArithmeticExpr + : { FactorExpr ArithmeticOp } FactorExpr + ; + +ArithmeticOp + : '+' + | '-' + ; + +// `*`, `/` +// : lower then prefix +FactorExpr + : { CastExpr FactorOp } CastExpr + ; + +FactorOp + : '*' + | '/' + | '%' + ; + +// `-`: lower than application +CastExpr + : PrefixExpr [ 'as' Path ] + ; + +// `-`: lower than application +PrefixExpr + : '-' ApplyExpr + | { Qualif } ApplyExpr + | 'wait' ApplyExpr + | 'call' ApplyExpr // ad-hoc "call" + ; + +// application: lower than `&`, `$` +ApplyExpr + : LowerPrefixExpr { AtomicExpr } + ; + +// `&`, `$`: lower than grouping +LowerPrefixExpr + : [ LowerPrefixOp ] Callable + ; + +LowerPrefixOp + : '&' + | '$'; + +Callable + : Path + | Literal ['?' Path] + | '(' Expr ')' + | IfExpr + | SelectExpr + ; + +// expressions with clear space delimitation +AtomicExpr + : Qualif + | LowerPrefixExpr + ; + +IfExpr + : 'if' Expr Block [ 'else' Block ] + ; + +SelectExpr + : 'select' '{' SelectScope '}' + ; + +SelectScope + : [ SelectScopeContent ] [ EndOfLine SelectScope ] + ; + +SelectScopeContent + : Expr '=>' Block + ; + +// Qualification for function application +Qualif + : Modifier + | DefaultModifier + ; + +DefaultModifier: '~' Path; + +Modifier: '@' Path [ KindArg ]; +KindArg: ':' Callable; + +Path: Ident { '.' Ident }; + +Ident: /[_a-zA-Z](\w|[\/-])*/; + +Literal + : Array + | String + | ByteLiteral + | HexByteLiteral + | Numeric + | Rfc3339DateTime + ; + +Array + : '[' [ CommaSepElements ] ']'; + +CommaSepElements + : Expr [ CommaExprList ] + ; + +CommaExprList + : ',' [ CommaSepElements ] + ; + +// String with permissive escapes +String: /"(\\.|[^"])*"/; + +// Byte string with permissive escapes +ByteLiteral: /b"(\\.|[^"])*"/; + +// Byte string in hexadecimal with permissive digit separators +HexByteLiteral: /bx"[0-9a-fA-F_]*"/; + +Numeric + : BinaryInteger + | OctalInteger + | HexadecimalInteger + | Ieee754Float + ; + +// Binary integer with permissive digit separators +BinaryInteger: /0b[01_]+([a-zA-Z](\w|[\/-])*)?/; + +// Octal integer with permissive digit separators +OctalInteger: /0o[0-7_]+([a-zA-Z](\w|[\/-])*)?/; + +// Hexadecimal integer with permissive digit separators +HexadecimalInteger: /0x[0-9a-fA-F_]+([g-zG-Z](\w|[\/-])*)?/; + +// IEEE 754 with permissive digit separators, without leading zeros +Ieee754Float: /[-+]?(0|[1-9][0-9_]*)(\.[0-9_]+)?([eE][-+]?(0|[1-9][0-9_]*)?)?([a-df-zA-DF-Z](\w|[\/-])*)?/; + +// `chrono`-crate version of RFC 3339 +Rfc3339DateTime: /\d{4}-\d{2}-\d{2}[tT]\d{2}:\d{2}:\d{2}(.\d+)?([zZ]|[+-]\d{2}:\d{2})/; + +Block + : '{' Scope '}' + ; diff --git a/opslang-parser/src/version/v1/parse.rs b/opslang-parser/src/version/v1/parse.rs new file mode 100644 index 0000000..cb643be --- /dev/null +++ b/opslang-parser/src/version/v1/parse.rs @@ -0,0 +1,979 @@ +use super::generated::grammar_trait::{self, ActionTrait, Program}; +use opslang_ast::{ + ScopeItem, V1Token as Token, + token::{IntoPosition, IntoSpan}, + v1::{self as syn, context::Context}, +}; + +#[allow(unused_imports)] +use parol_runtime::{Result, Token}; + +/// The main action for parsing the grammar. +/// +/// This type is referenced in the `build.rs` file to generate the parser. +pub struct Action<'cx> { + cx: &'cx Context<'cx>, + parsed: Option>, +} + +impl<'cx> Action<'cx> { + pub fn new(cx: &'cx Context<'cx>) -> Self { + Self { cx, parsed: None } + } + + pub fn finish(self) -> syn::Program<'cx> { + self.parsed.expect("Action was not parsed") + } +} + +/// Linking the [`Action`] type to the [`ActionTrait`] trait. +impl<'cx> ActionTrait<'cx> for Action<'cx> { + fn program(&mut self, arg: &Program<'cx>) -> Result<()> { + let program = arg.process_token(self.cx); + self.parsed = Some(program); + Ok(()) + } +} + +/// Locally defined types, needed so that this crate is independent from `opslang-ast`. +struct Loc(T); +impl IntoSpan<'_> for Loc { + fn into_span(self) -> syn::Span { + self.0 + } +} +impl IntoPosition<'_> for Loc { + fn into_position(self) -> syn::Position { + self.0 + } +} + +/// Wraps a foreign type into a locally defined type. +trait WrapLoc { + fn wrap(&self) -> Loc; +} + +impl WrapLoc for parol_runtime::Token<'_> { + fn wrap(&self) -> Loc { + let parol_runtime::Location { start, end, .. } = self.location; + Loc(syn::Span { + start: syn::BytePos(start), + end: syn::BytePos(end), + }) + } +} + +impl WrapLoc for parol_runtime::Token<'_> { + fn wrap(&self) -> Loc { + let parol_runtime::Location { start, .. } = self.location; + Loc(syn::BytePos(start)) + } +} + +/// A trait for processing tokens in the grammar. +/// +/// This trait is used to process tokens in the grammar and convert them into +/// the appropriate types of the AST. +/// The implementations of this trait, which is the rest of this file, should be synced with the `parol` grammar file. +trait ProcessToken<'cx> { + type Output; + + /// Processes a token into an [`Output`] type. + /// + /// [`Output`]: ProcessToken::Output + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output; +} + +impl<'cx, T: ProcessToken<'cx>> ProcessToken<'cx> for Option { + type Output = Option; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + self.as_ref().map(|this| this.process_token(cx)) + } +} + +impl<'cx, T: ProcessToken<'cx>> ProcessToken<'cx> for Box { + type Output = >::Output; + #[track_caller] + #[inline(always)] + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + >::process_token(&**self, cx) + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Program<'_> { + type Output = syn::Program<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + let mut definitions = Vec::new(); + let mut program = self; + loop { + match program { + Program::DefinitionEndOfLineProgram(x) => { + definitions.push(x.definition.process_token(cx)); + program = &x.program; + } + Program::Definition(x) => { + definitions.push(x.definition.process_token(cx)); + break; + } + } + } + syn::Program { + toplevel_items: cx.alloc_toplevel_item_slice(definitions), + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Definition<'_> { + type Output = syn::ToplevelItem<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + let kind = self + .definition_opt + .as_ref() + .map(|def| match &*def.definition_opt_group { + grammar_trait::DefinitionOptGroup::FunctionDef(function_def) => { + syn::DefinitionKind::Function(function_def.function_def.process_token(cx)) + } + grammar_trait::DefinitionOptGroup::ConstantDef(constant_def) => { + syn::DefinitionKind::Constant(constant_def.constant_def.process_token(cx)) + } + }); + let comment = self + .definition_opt0 + .as_ref() + .map(|c| c.comment.process_token(cx)); + syn::ToplevelItem { kind, comment } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::FunctionDef<'_> { + type Output = syn::FunctionDef<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + let params = if let Some(param_list) = &self.function_def_opt { + let mut params = Vec::new(); + let mut current = ¶m_list.parameter_list; + loop { + params.push(current.parameter.process_token(cx)); + let Some(comma_param_list) = ¤t.parameter_list_opt else { + break; + }; + let Some(next_param_list) = &comma_param_list + .comma_parameter_list + .comma_parameter_list_opt + else { + break; + }; + current = &next_param_list.parameter_list; + } + params + } else { + vec![] + }; + + syn::FunctionDef { + prc_token: Token![prc](self.prc.wrap()), + name: self.ident.process_token(cx), + left_paren: syn::token::OpenParen(self.l_paren.wrap()), + parameters: cx.alloc_parameter_slice(params), + right_paren: syn::token::CloseParen(self.r_paren.wrap()), + return_type: syn::FnReturnTy(self.function_def_opt0.as_ref().map(|return_opt| { + ( + Token![->](return_opt.minus_g_t.wrap()), + return_opt.path.process_token(cx), + ) + })), + body: cx.alloc_block(self.block.process_token(cx)), + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Parameter<'_> { + type Output = syn::Parameter<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + syn::Parameter { + name: self.ident.process_token(cx), + colon: Token![:](self.colon.wrap()), + ty: self.path.process_token(cx), + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::ConstantDef<'_> { + type Output = syn::ConstantDef<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + syn::ConstantDef { + const_token: Token![const](self.r#const.wrap()), + name: self.ident.process_token(cx), + colon: Token![:](self.colon.wrap()), + ty: self.path.process_token(cx), + eq: Token![=](self.equ.wrap()), + value: self.expr.process_token(cx), + semi: Token![;](self.semi.semi.wrap()), + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Scope<'_> { + type Output = syn::Scope<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + let mut items = Vec::new(); + let mut scope = self; + items.push(scope.scope_content.process_token(cx)); + while let Some(content) = &scope.scope_opt { + scope = &content.scope; + items.push(scope.scope_content.process_token(cx)); + } + fn non_empty<'cx>(item: &ScopeItem<'cx>) -> bool { + match item { + ScopeItem::Row(row) => !row.is_empty(), + ScopeItem::Block(_) => true, + } + } + let begin = items.iter().position(non_empty).unwrap_or(items.len()); + let end = items + .iter() + .rposition(non_empty) + .map(|i| i + 1) + .unwrap_or(0); + let len = end.saturating_sub(begin); + syn::Scope { + items: cx.alloc_scope_item_slice(items.into_iter().skip(begin).take(len)), + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::ScopeContentOpt<'_> { + type Output = syn::token::Break<'cx>; + + fn process_token(&self, _cx: &'cx Context<'cx>) -> Self::Output { + Token![.](self.r#break.r#break.wrap()) + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::ScopeContent<'_> { + type Output = syn::ScopeItem<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + let Self { + scope_content_opt, + scope_content_opt0, + scope_content_opt1, + } = self; + let breaks = scope_content_opt.process_token(cx); + let statement = if let Some(scope_content_kind) = scope_content_opt0 { + match &*scope_content_kind.scope_content_kind { + grammar_trait::ScopeContentKind::Block(block) => { + let block = block.block.process_token(cx); + return syn::ScopeItem::Block(cx.alloc_block(block)); + } + grammar_trait::ScopeContentKind::Statement(stmt) => { + Some(stmt.statement.process_token(cx)) + } + } + } else { + None + }; + let comment = scope_content_opt1 + .as_ref() + .map(|comment| comment.comment.process_token(cx)); + syn::ScopeItem::Row(cx.alloc_row(syn::Row { + breaks, + statement, + comment, + })) + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Block<'_> { + type Output = syn::Block<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + syn::Block { + left_brace: syn::token::OpenBrace(self.l_brace.wrap()), + scope: self.scope.process_token(cx), + right_brace: syn::token::CloseBrace(self.r_brace.wrap()), + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Statement<'_> { + type Output = syn::Statement<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + let semi = Token![;](self.semi.semi.wrap()); + match &*self.statement_kind { + grammar_trait::StatementKind::LetStmt(grammar_trait::StatementKindLetStmt { + let_stmt, + }) => { + let grammar_trait::LetStmt { + r#let, + ident, + equ, + expr, + } = &**let_stmt; + syn::Statement::Let(syn::Let { + let_token: Token![let](r#let.wrap()), + variable: ident.process_token(cx), + eq: Token![=](equ.wrap()), + rhs: expr.process_token(cx), + semi, + }) + } + grammar_trait::StatementKind::Expr(statement_kind_expr) => { + syn::Statement::Expr(syn::ExprStatement { + expr: statement_kind_expr.expr.process_token(cx), + semi, + }) + } + grammar_trait::StatementKind::ReturnStmt(statement_kind_return_stmt) => { + syn::Statement::Return(syn::ReturnStmt { + return_token: Token![return]( + statement_kind_return_stmt.return_stmt.return_stmt.wrap(), + ), + semi, + }) + } + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Expr<'_> { + type Output = syn::Expr<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + if let Some(grammar_trait::SetExprOpt { + colon_equ, + logical_or_expr, + }) = &self.set_expr.set_expr_opt + { + cx.alloc_expr(syn::ExprKind::Set(syn::Set { + lhs: self.set_expr.logical_or_expr.process_token(cx), + colon_eq: Token![:=](colon_equ.wrap()), + rhs: logical_or_expr.process_token(cx), + })) + } else { + self.set_expr.logical_or_expr.process_token(cx) + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::LogicalOrExpr<'_> { + type Output = syn::Expr<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + if self.logical_or_expr_list.is_empty() { + self.logical_and_expr.process_token(cx) + } else { + self.logical_or_expr_list.iter().rfold( + self.logical_and_expr.process_token(cx), + |acc, expr| { + cx.alloc_expr(syn::ExprKind::Binary(syn::Binary { + lhs: expr.logical_and_expr.process_token(cx), + op: syn::BinOp::Or(Token![||](expr.or_or.wrap())), + rhs: acc, + })) + }, + ) + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::LogicalAndExpr<'_> { + type Output = syn::Expr<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + if self.logical_and_expr_list.is_empty() { + self.compare_expr.process_token(cx) + } else { + self.logical_and_expr_list.iter().rfold( + self.compare_expr.process_token(cx), + |acc, expr| { + cx.alloc_expr(syn::ExprKind::Binary(syn::Binary { + lhs: expr.compare_expr.process_token(cx), + op: syn::BinOp::And(Token![&&](expr.amp_amp.wrap())), + rhs: acc, + })) + }, + ) + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::CompareExpr<'_> { + type Output = syn::Expr<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + if self.compare_expr_list.is_empty() { + self.arithmetic_expr.process_token(cx) + } else { + cx.alloc_expr(syn::ExprKind::Compare(syn::Compare { + head: self.arithmetic_expr.process_token(cx), + tail_with_op: cx.alloc_compare_op_expr_tuple_slice( + self.compare_expr_list + .iter() + .map(|expr| syn::CompareOpExpr { + op: expr.compare_op.process_token(cx), + val: expr.arithmetic_expr.process_token(cx), + }), + ), + })) + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::CompareOp<'_> { + type Output = syn::CompareOp<'cx>; + + fn process_token(&self, _cx: &'cx Context<'cx>) -> Self::Output { + match self { + grammar_trait::CompareOp::GTEqu(compare_op_gtequ) => { + syn::CompareOp::GreaterEq(Token![>=](compare_op_gtequ.g_t_equ.wrap())) + } + grammar_trait::CompareOp::LTEqu(compare_op_ltequ) => { + syn::CompareOp::LessEq(Token![<=](compare_op_ltequ.l_t_equ.wrap())) + } + grammar_trait::CompareOp::GT(compare_op_gt) => { + syn::CompareOp::Greater(Token![>](compare_op_gt.g_t.wrap())) + } + grammar_trait::CompareOp::LT(compare_op_lt) => { + syn::CompareOp::Less(Token![<](compare_op_lt.l_t.wrap())) + } + grammar_trait::CompareOp::BangEqu(compare_op_bang_equ) => syn::CompareOp::NotEqual( + syn::NotEqualToken::BangEqual(Token![!=](compare_op_bang_equ.bang_equ.wrap())), + ), + grammar_trait::CompareOp::SlashEqu(compare_op_slash_equ) => syn::CompareOp::NotEqual( + syn::NotEqualToken::SlashEqual(Token![/=](compare_op_slash_equ.slash_equ.wrap())), + ), + grammar_trait::CompareOp::EquEqu(compare_op_equ_equ) => { + syn::CompareOp::Equal(Token![==](compare_op_equ_equ.equ_equ.wrap())) + } + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::ArithmeticExpr<'_> { + type Output = syn::Expr<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + if self.arithmetic_expr_list.is_empty() { + self.factor_expr.process_token(cx) + } else { + self.arithmetic_expr_list.iter().rfold( + self.factor_expr.process_token(cx), + |acc, expr| { + cx.alloc_expr(syn::ExprKind::Binary(syn::Binary { + lhs: expr.factor_expr.process_token(cx), + op: expr.arithmetic_op.process_token(cx), + rhs: acc, + })) + }, + ) + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::ArithmeticOp<'_> { + type Output = syn::BinOp<'cx, syn::DefaultTypeFamily>; + + fn process_token(&self, _cx: &'cx Context<'cx>) -> Self::Output { + match self { + grammar_trait::ArithmeticOp::Plus(token) => { + syn::BinOp::Add(Token![+](token.plus.wrap())) + } + grammar_trait::ArithmeticOp::Minus(token) => { + syn::BinOp::Sub(Token![-](token.minus.wrap())) + } + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::FactorExpr<'_> { + type Output = syn::Expr<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + if self.factor_expr_list.is_empty() { + self.cast_expr.process_token(cx) + } else { + self.factor_expr_list + .iter() + .rfold(self.cast_expr.process_token(cx), |acc, expr| { + cx.alloc_expr(syn::ExprKind::Binary(syn::Binary { + lhs: expr.cast_expr.process_token(cx), + op: expr.factor_op.process_token(cx), + rhs: acc, + })) + }) + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::FactorOp<'_> { + type Output = syn::BinOp<'cx, syn::DefaultTypeFamily>; + + fn process_token(&self, _cx: &'cx Context<'cx>) -> Self::Output { + match self { + grammar_trait::FactorOp::Star(token) => syn::BinOp::Mul(Token![*](token.star.wrap())), + grammar_trait::FactorOp::Slash(token) => syn::BinOp::Div(Token![/](token.slash.wrap())), + grammar_trait::FactorOp::Percent(token) => { + syn::BinOp::Mod(Token![%](token.percent.wrap())) + } + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::CastExpr<'_> { + type Output = syn::Expr<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + if let Some(grammar_trait::CastExprOpt { r#as, path }) = &self.cast_expr_opt { + cx.alloc_expr(syn::ExprKind::Cast(syn::Cast { + expr: self.prefix_expr.process_token(cx), + as_kw: Token![as](r#as.wrap()), + ty: path.process_token(cx), + })) + } else { + self.prefix_expr.process_token(cx) + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::PrefixExpr<'_> { + type Output = syn::Expr<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + match self { + grammar_trait::PrefixExpr::MinusApplyExpr(prefix_expr_minus_apply_expr) => cx + .alloc_expr(syn::ExprKind::Unary(syn::Unary { + op: syn::UnOp::Neg(Token![-](prefix_expr_minus_apply_expr.minus.wrap())), + expr: prefix_expr_minus_apply_expr.apply_expr.process_token(cx), + })), + grammar_trait::PrefixExpr::PrefixExprListApplyExpr( + prefix_expr_prefix_expr_list_apply_expr, + ) => { + if prefix_expr_prefix_expr_list_apply_expr + .prefix_expr_list + .is_empty() + { + prefix_expr_prefix_expr_list_apply_expr + .apply_expr + .process_token(cx) + } else { + cx.alloc_expr(syn::ExprKind::PreQualified(syn::PreQualified { + qualifs: cx.alloc_qualif_slice( + prefix_expr_prefix_expr_list_apply_expr + .prefix_expr_list + .iter() + .map(|qualif| qualif.qualif.process_token(cx)), + ), + expr: prefix_expr_prefix_expr_list_apply_expr + .apply_expr + .process_token(cx), + })) + } + } + grammar_trait::PrefixExpr::WaitApplyExpr(prefix_expr_wait_apply_expr) => { + cx.alloc_expr(syn::ExprKind::Wait(syn::Wait { + wait_kw: Token![wait](prefix_expr_wait_apply_expr.wait.wrap()), + expr: prefix_expr_wait_apply_expr.apply_expr.process_token(cx), + })) + } + grammar_trait::PrefixExpr::CallApplyExpr(prefix_expr_call_apply_expr) => { + cx.alloc_expr(syn::ExprKind::Call(syn::Call { + call_kw: Token![call](prefix_expr_call_apply_expr.call.wrap()), + expr: prefix_expr_call_apply_expr.apply_expr.process_token(cx), + })) + } + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Qualif<'_> { + type Output = syn::Qualif<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + match self { + grammar_trait::Qualif::Modifier(qualif_mod) => { + let e = &*qualif_mod.modifier; + syn::Qualif::Modifier(syn::Modifier { + at_token: Token![@](e.at.wrap()), + id: e.path.process_token(cx), + arg: e.modifier_opt.as_ref().map(|k| syn::ModifierParam { + colon_token: Token![:](k.kind_arg.colon.wrap()), + value: k.kind_arg.callable.process_token(cx), + }), + }) + } + grammar_trait::Qualif::DefaultModifier(qualif_default) => { + let t = &*qualif_default.default_modifier; + syn::Qualif::DefaultModifier(syn::DefaultModifier { + tilde_token: Token![~](t.tilde.wrap()), + value: t.path.process_token(cx), + }) + } + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::ApplyExpr<'_> { + type Output = syn::Expr<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + if self.apply_expr_list.is_empty() { + self.lower_prefix_expr.process_token(cx) + } else { + cx.alloc_expr(syn::ExprKind::Apply(syn::Apply { + function: self.lower_prefix_expr.process_token(cx), + args: cx.alloc_expr_slice( + self.apply_expr_list + .iter() + .map(|arg| arg.atomic_expr.process_token(cx)), + ), + })) + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::LowerPrefixExpr<'_> { + type Output = syn::Expr<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + if let Some(lower_prefix) = self.lower_prefix_expr_opt.as_ref() { + cx.alloc_expr(syn::ExprKind::Unary(syn::Unary { + op: match &*lower_prefix.lower_prefix_op { + grammar_trait::LowerPrefixOp::Amp(lower_prefix_op_amp) => { + syn::UnOp::IdRef(Token![&](lower_prefix_op_amp.amp.wrap())) + } + grammar_trait::LowerPrefixOp::Dollar(lower_prefix_op_dollar) => { + syn::UnOp::Deref(Token![$](lower_prefix_op_dollar.dollar.wrap())) + } + }, + expr: self.callable.process_token(cx), + })) + } else { + self.callable.process_token(cx) + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Callable<'_> { + type Output = syn::Expr<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + match self { + grammar_trait::Callable::Path(callable_path) => cx.alloc_expr(syn::ExprKind::Variable( + callable_path.path.process_token(cx), + )), + grammar_trait::Callable::LiteralCallableOpt(callable_literal) => { + let literal = callable_literal.literal.process_token(cx); + if let Some(opt) = &callable_literal.callable_opt { + syn::Expr::import( + cx, + literal, + Token![?](opt.quest.wrap()), + opt.path.process_token(cx), + ) + } else { + cx.alloc_expr(syn::ExprKind::Literal(literal)) + } + } + grammar_trait::Callable::LParenExprRParen(callable_lparen_expr_rparen) => cx + .alloc_expr(syn::ExprKind::Parened(syn::Parened { + left_paren: syn::token::OpenParen(callable_lparen_expr_rparen.l_paren.wrap()), + expr: callable_lparen_expr_rparen.expr.process_token(cx), + right_paren: syn::token::CloseParen(callable_lparen_expr_rparen.r_paren.wrap()), + })), + + grammar_trait::Callable::IfExpr(atomic_expr_if_expr) => { + let e = &atomic_expr_if_expr.if_expr; + syn::Expr::if_expr( + cx, + Token![if](e.r#if.wrap()), + e.expr.process_token(cx), + cx.alloc_block(e.block.process_token(cx)), + e.if_expr_opt.as_ref().map(|el| syn::IfElse { + else_kw: Token![else](el.r#else.wrap()), + else_clause: cx.alloc_block(el.block.process_token(cx)), + }), + ) + } + grammar_trait::Callable::SelectExpr(atomic_expr_select_expr) => { + let e = &*atomic_expr_select_expr.select_expr; + let mut items = Vec::new(); + let mut scope = &e.select_scope; + if let Some(c) = scope.select_scope_opt.as_ref() { + items.push(c.select_scope_content.process_token(cx)); + } + while let Some(content) = &scope.select_scope_opt0 { + scope = &content.select_scope; + if let Some(c) = scope.select_scope_opt.as_ref() { + items.push(c.select_scope_content.process_token(cx)); + } + } + syn::Expr::select( + cx, + Token![select](e.select.wrap()), + syn::token::OpenBrace(e.l_brace.wrap()), + cx.alloc_select_item_slice(items), + syn::token::CloseBrace(e.r_brace.wrap()), + ) + } + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::AtomicExpr<'_> { + type Output = syn::Expr<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + match self { + grammar_trait::AtomicExpr::Qualif(atomic_expr_qualif) => cx.alloc_expr( + syn::ExprKind::Qualif(atomic_expr_qualif.qualif.process_token(cx)), + ), + grammar_trait::AtomicExpr::LowerPrefixExpr(atomic_expr_import) => { + atomic_expr_import.lower_prefix_expr.process_token(cx) + } + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::SelectScopeContent<'_> { + type Output = syn::SelectItem<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + let Self { + expr, + equ_g_t, + block, + } = self; + syn::SelectItem { + expr: expr.process_token(cx), + arrow: Token![=>](equ_g_t.wrap()), + body: cx.alloc_block(block.process_token(cx)), + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Literal<'_> { + type Output = syn::Literal<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + match self { + grammar_trait::Literal::Array(literal_array) => syn::Literal::Array(syn::Array { + left_bracket: syn::token::OpenSquare(literal_array.array.l_bracket.wrap()), + exprs: { + let mut exprs = Vec::new(); + if let Some(comma_sep_elements) = &literal_array.array.array_opt { + let mut elements = &comma_sep_elements.comma_sep_elements; + loop { + exprs.push(elements.expr.process_token(cx)); + let Some(comma_expr_list) = &elements.comma_sep_elements_opt else { + break; + }; + // ignoring the comma... + let Some(comma_sep_elements) = + &comma_expr_list.comma_expr_list.comma_expr_list_opt + else { + break; + }; + elements = &comma_sep_elements.comma_sep_elements; + } + } + cx.alloc_expr_slice(exprs) + }, + right_bracket: syn::token::CloseSquare(literal_array.array.r_bracket.wrap()), + }), + grammar_trait::Literal::String(literal_string) => syn::Literal::String(syn::String { + raw: cx.alloc_str(literal_string.string.string.text().trim_matches('"')), + span: literal_string.string.string.wrap().0, + }), + grammar_trait::Literal::ByteLiteral(literal_byte_literal) => { + syn::Literal::Bytes(syn::Bytes { + raw: cx.alloc_str( + literal_byte_literal + .byte_literal + .byte_literal + .text() + .trim_start_matches('b') + .trim_matches('"'), + ), + span: literal_byte_literal.byte_literal.byte_literal.wrap().0, + }) + } + grammar_trait::Literal::HexByteLiteral(literal_hex_byte_literal) => { + syn::Literal::HexBytes(syn::HexBytes { + raw: cx.alloc_str( + literal_hex_byte_literal + .hex_byte_literal + .hex_byte_literal + .text() + .trim_start_matches("bx") + .trim_matches('"'), + ), + span: literal_hex_byte_literal + .hex_byte_literal + .hex_byte_literal + .wrap() + .0, + }) + } + grammar_trait::Literal::Numeric(literal_numeric) => { + syn::Literal::Numeric(literal_numeric.numeric.process_token(cx)) + } + grammar_trait::Literal::Rfc3339DateTime(literal_rfc3339_datetime) => { + syn::Literal::DateTime(syn::DateTime { + raw: cx.alloc_str( + literal_rfc3339_datetime + .rfc3339_date_time + .rfc3339_date_time + .text(), + ), + span: literal_rfc3339_datetime + .rfc3339_date_time + .rfc3339_date_time + .wrap() + .0, + }) + } + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Numeric<'_> { + type Output = syn::Numeric<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + fn extract_suffix<'cx, 'input>( + token: &'input Token, + predicate: impl Fn(char) -> bool, + cx: &'cx Context<'cx>, + ) -> (&'input str, Option>) { + let input = token.text(); + if let Some(split_pos) = input.find(predicate) { + let (raw, suffix_str) = input.split_at(split_pos); + ( + raw, + Some(syn::NumericSuffix(syn::Ident { + raw: cx.alloc_str(suffix_str), + span: token.wrap().0, + })), + ) + } else { + (input, None) + } + } + + let (raw, suffix, kind) = match self { + grammar_trait::Numeric::BinaryInteger(binary_integer) => { + let token = &binary_integer.binary_integer.binary_integer; + let (raw, suffix) = extract_suffix(token, |c: char| c.is_alphabetic(), cx); + ( + raw.trim_start_matches("0b"), + suffix, + syn::NumericKind::Integer(syn::IntegerPrefix::Binary), + ) + } + grammar_trait::Numeric::OctalInteger(octal_integer) => { + let token = &octal_integer.octal_integer.octal_integer; + let (raw, suffix) = extract_suffix(token, |c: char| c.is_alphabetic(), cx); + ( + raw.trim_start_matches("0o"), + suffix, + syn::NumericKind::Integer(syn::IntegerPrefix::Octal), + ) + } + grammar_trait::Numeric::HexadecimalInteger(hexadecimal_integer) => { + let token = &hexadecimal_integer.hexadecimal_integer.hexadecimal_integer; + let (raw, suffix) = extract_suffix( + token, + |c: char| c.is_alphabetic() && !c.is_ascii_hexdigit(), + cx, + ); + ( + raw.trim_start_matches("0x"), + suffix, + syn::NumericKind::Integer(syn::IntegerPrefix::Hexadecimal), + ) + } + grammar_trait::Numeric::Ieee754Float(ieee754_float) => { + let token = &ieee754_float.ieee754_float.ieee754_float; + let (raw, suffix) = extract_suffix( + token, + |c: char| c.is_alphabetic() && !matches!(c, 'e' | 'E'), + cx, + ); + ( + raw, + suffix, + if raw.contains('.') || raw.contains(['e', 'E']) { + syn::NumericKind::Float + } else { + syn::NumericKind::Integer(syn::IntegerPrefix::None) + }, + ) + } + }; + + syn::Numeric { + raw: cx.alloc_str(raw), + kind, + suffix, + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Comment<'_> { + type Output = &'cx syn::Comment<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + cx.alloc_comment(syn::Comment { + content: cx.alloc_str( + self.comment_opt + .as_ref() + .map(|c| c.comment_content.comment_content.text()) + .unwrap_or(""), + ), + span: if let Some(comment) = &self.comment_opt { + comment.comment_content.comment_content.wrap().0 + } else { + let position = syn::BytePos(self.hash.hash.location.end + 1); + syn::Span { + start: position, + end: position, + } + }, + }) + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Ident<'_> { + type Output = syn::Ident<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + let token = &self.ident; + syn::Ident { + raw: cx.alloc_str(token.text()), + span: token.wrap().0, + } + } +} + +impl<'cx> ProcessToken<'cx> for grammar_trait::Path<'_> { + type Output = syn::Path<'cx>; + + fn process_token(&self, cx: &'cx Context<'cx>) -> Self::Output { + let mut segments = Vec::with_capacity(self.path_list.len() + 1); + segments.push(self.ident.process_token(cx)); + for segment in &self.path_list { + segments.push(segment.ident.process_token(cx)); + } + syn::Path { + segments: cx.alloc_ident_slice(segments), + } + } +} diff --git a/opslang-parser/tests/test_v1.ops b/opslang-parser/tests/test_v1.ops new file mode 100644 index 0000000..6caacc1 --- /dev/null +++ b/opslang-parser/tests/test_v1.ops @@ -0,0 +1,29 @@ +#! lang=v1 + +prc main() { + let ok = "OK"; # string型 + let t = 2024-01-01T00:00:00Z; # time型 + let d = 1; # duration型 + let ti = 2000; # 数値型 + + .# breakpoint機能 + assert (2 == 2); # WINGS: check_value + assert_eq 2 2; + assert_approx_eq 1.0 1.0 0.001; # WINGS: --tolerance 0.001 + print 2; # WINGS: get + wait 5; # WINGS: wait_sec + wait (1 == 1 && 2 <= 2); # WINGS: wait_until + wait (0 == 1 || 5); # タイムアウトつき + + print &MOBC.HK; # telemetry id 参照 + print $MOBC.HK.XX.YY; + let hk = MOBC.HK; # テレメトリ集合型 + print hk.OBC.XX.YY; # テレメトリ集合型は構造体のように参照できる + + @RT MOBC.NOP; # Time Indicator をとらないコマンド + MOBC.NOP @TL:20; # ステップ単位のTime Indicatorをとるコマンド + @TL:20 MOBC.NOP; # Time Indicatorは前置が可能 + MOBC.NOP @BL:30; + MOBC.NOP @UTL:2024-01-01T00:00:00Z; # 時刻をTime Indicatorとしてとるコマンド + AOBC.NOP @TL:20 ~MOBC; # 最終的な実行コンポーネントが異なるコマンド (WINGSのMOBC_TL.AOBC_RTに相当) +} diff --git a/opslang-printer/Cargo.toml b/opslang-printer/Cargo.toml new file mode 100644 index 0000000..3762a7f --- /dev/null +++ b/opslang-printer/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "opslang-printer" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +opslang-ast.workspace = true +serde = { workspace = true, optional = true } + +[features] +serde = ["dep:serde"] + +[dev-dependencies] +opslang-parser.workspace = true diff --git a/opslang-printer/src/lib.rs b/opslang-printer/src/lib.rs new file mode 100644 index 0000000..2af4d2a --- /dev/null +++ b/opslang-printer/src/lib.rs @@ -0,0 +1,461 @@ +use std::borrow::Cow; +use std::fmt::{self, Write}; +use std::marker::PhantomData; +use std::ops::Deref; + +pub mod v1; + +/// Sealed trait for formatting strategies +mod sealed { + pub trait Sealed {} +} + +/// Trait representing different formatting strategies. +/// +/// This trait is sealed and can only be implemented by types defined in this crate. +/// Different strategies control how elements are formatted, particularly how comments +/// are positioned and aligned. +pub trait Strategy: sealed::Sealed + Default {} + +/// Naive formatting strategy that adds comments with simple spacing. +/// +/// This strategy follows a simple approach: comments are added after expressions +/// with a single space separator, without any column alignment. +#[derive(Debug, Clone, Copy, Default)] +pub struct Naive; + +impl sealed::Sealed for Naive {} +impl Strategy for Naive {} + +/// Comment-aligned formatting strategy that aligns comments in consecutive lines. +/// +/// This strategy analyzes consecutive non-empty lines and aligns their comments +/// to the same column position. The alignment position is determined by the +/// alignment configuration in PrintOptions. +#[derive(Debug, Clone, Copy, Default)] +pub struct CommentAligned; + +impl sealed::Sealed for CommentAligned {} +impl Strategy for CommentAligned {} + +/// Comment grouping strategy for alignment +#[derive(Debug, Clone, Copy, Default)] +pub enum CommentGrouping { + /// Group consecutive lines (separated by empty lines) + #[default] + Consecutive, + /// Group comments per block scope + PerBlock, +} + +/// Comment position calculation method +#[derive(Debug, Clone, Copy, Default)] +pub enum CommentPosition { + /// Align comments to the longest line in the group + #[default] + ToLongest, + /// Align comments to a fixed column position + /// If `fallback_to_longest` is true, lines longer than the fixed position + /// fall back to longest alignment within the group + ToFixed { + column: usize, + fallback_to_longest: bool, + }, + /// Align comments to multiples of the given tab size + /// If `fallback_to_longest` is true, lines that don't fit the tab boundary + /// may fall back to longest alignment within the group + ToTabMultiple { + tab_size: usize, + fallback_to_longest: bool, + }, +} + +/// Configuration for comment alignment +#[derive(Debug, Clone, Copy, Default)] +pub struct CommentAlignment { + /// Grouping strategy for comment alignment + pub grouping: CommentGrouping, + /// Position calculation method + pub position: CommentPosition, +} + +/// Style for newlines in output +#[derive(Debug, Clone, Copy)] +pub enum NewlineStyle { + /// Unix style (\n) + Unix, + /// Windows style (\r\n) + Windows, +} + +/// Basic pretty-print options without comment alignment +#[derive(Debug, Clone)] +pub struct BasePrintOptions { + /// String used for indentation (usually spaces or tabs) + pub indent_str: Cow<'static, str>, + /// Current indentation level + pub indent_level: usize, + /// Whether to reserve a space for break tokens + pub reserve_for_break: bool, + /// Maximum line width + pub max_width: usize, + /// Newline style + pub newline_style: NewlineStyle, +} + +/// Complete pretty-print options with comment alignment +#[derive(Debug, Clone, Default)] +pub struct PrintOptions { + /// Base options + pub base: BasePrintOptions, + /// Comment alignment configuration + pub comment_alignment: CommentAlignment, + _strategy: PhantomData, +} + +impl Default for BasePrintOptions { + fn default() -> Self { + Self { + indent_str: Cow::Borrowed(" "), // 4 spaces + indent_level: 0, + reserve_for_break: true, + max_width: 80, + newline_style: NewlineStyle::Unix, + } + } +} + +impl BasePrintOptions { + /// Create a new BasePrintOptions with increased indentation level + pub fn with_increased_indent(&self) -> Self { + let mut new_opts = self.clone(); + new_opts.indent_level += 1; + new_opts + } + + /// Get the current indentation string + pub fn current_indent(&self) -> String { + self.indent_str.repeat(self.indent_level) + } + + /// Get the newline character(s) + pub fn newline(&self) -> &'static str { + match self.newline_style { + NewlineStyle::Unix => "\n", + NewlineStyle::Windows => "\r\n", + } + } +} + +impl PrintOptions { + /// Create a new PrintOptions + pub fn new(base: BasePrintOptions, comment_alignment: CommentAlignment) -> Self { + Self { + base, + comment_alignment, + _strategy: PhantomData, + } + } + + /// Create a new PrintOptions with increased indentation level + pub fn with_increased_indent(&self) -> Self { + Self { + base: self.base.with_increased_indent(), + comment_alignment: self.comment_alignment, + _strategy: PhantomData, + } + } + + /// Create PrintOptions from BasePrintOptions with default comment alignment + pub fn from_base(base: BasePrintOptions) -> Self { + Self { + base, + comment_alignment: CommentAlignment::default(), + _strategy: PhantomData, + } + } + + /// Create PrintOptions from BasePrintOptions with specific comment alignment + pub fn from_base_with_alignment( + base: BasePrintOptions, + comment_alignment: CommentAlignment, + ) -> Self { + Self { + base, + comment_alignment, + _strategy: PhantomData, + } + } +} + +/// Deref implementation to allow PrintOptions to be used as BasePrintOptions +impl Deref for PrintOptions { + type Target = BasePrintOptions; + + fn deref(&self) -> &Self::Target { + &self.base + } +} + +/// Main trait for pretty-printing AST elements with different strategies +/// +/// This trait is version-agnostic and can be implemented for AST elements +/// from different versions. The strategy type parameter determines how +/// formatting is performed, particularly for comment alignment. +pub trait PrettyPrint { + /// Convert to a pretty-printed string + fn to_pretty_string(&self, options: &PrintOptions) -> String { + let mut result = String::new(); + self.pretty_print(&mut result, options).unwrap(); + result + } + + /// Write pretty-printed output to the specified writer + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result; +} + +/// Pretty-printer instance with a specific strategy +pub struct Printer { + options: PrintOptions, +} + +impl Printer { + /// Create a new printer with the specified options + pub fn new(options: PrintOptions) -> Self { + Self { options } + } + + /// Create a printer with default options + pub fn with_default_options() -> Self { + Self::new(PrintOptions::default()) + } + + /// Pretty-print the specified object to a string + pub fn print>(&self, item: &T) -> String { + item.to_pretty_string(&self.options) + } + + /// Pretty-print the specified object to the specified writer + pub fn print_to>(&self, item: &T, writer: &mut impl Write) -> fmt::Result { + item.pretty_print(writer, &self.options) + } + + /// Create a new printer with modified options + pub fn with_options(&self, options: PrintOptions) -> Self { + Self { options } + } +} + +impl Default for Printer { + fn default() -> Self { + Self::with_default_options() + } +} + +/// Zero-sized type for writing indentation +/// +/// This type provides a method to write indentation to a writer. It's designed +/// as a ZST (Zero-Sized Type) to provide a clean API for indentation operations +/// while maintaining zero runtime cost. +/// +/// # Usage +/// +/// ```rust +/// # use opslang_printer::{Indent, PrintOptions, Naive}; +/// # use std::fmt::Write; +/// # let mut output = String::new(); +/// # let options = PrintOptions::::default(); +/// Indent.write(&mut output, &options).unwrap(); +/// ``` +#[derive(Debug, Clone, Copy, Default)] +pub struct Indent; + +impl Indent { + /// Write the current indentation to the writer + pub fn write(self, writer: &mut impl Write, options: &BasePrintOptions) -> fmt::Result { + writer.write_str(&options.current_indent()) + } +} + +/// Zero-sized type for writing newlines. +/// +/// This type provides a method to write newlines to a writer according to the +/// configured newline style. It's designed as a ZST to provide a clean API +/// for newline operations while maintaining zero runtime cost. +/// +/// # Usage +/// +/// ```rust +/// # use opslang_printer::{Newline, PrintOptions, Naive}; +/// # use std::fmt::Write; +/// # let mut output = String::new(); +/// # let options = PrintOptions::::default(); +/// Newline.write(&mut output, &options).unwrap(); +/// ``` +#[derive(Debug, Clone, Copy, Default)] +pub struct Newline; + +impl Newline { + /// Write a newline to the writer + pub fn write(self, writer: &mut impl Write, options: &BasePrintOptions) -> fmt::Result { + writer.write_str(options.newline()) + } +} + +/// Zero-sized type for writing indented newlines. +/// +/// This type provides a method to write a newline followed by indentation. +/// It's designed as a ZST to provide a clean API for combined newline and +/// indentation operations while maintaining zero runtime cost. +/// +/// # Usage +/// +/// ```rust +/// # use opslang_printer::{IndentedNewline, PrintOptions, Naive}; +/// # use std::fmt::Write; +/// # let mut output = String::new(); +/// # let options = PrintOptions::::default(); +/// IndentedNewline.write(&mut output, &options).unwrap(); +/// ``` +#[derive(Debug, Clone, Copy, Default)] +pub struct IndentedNewline; + +impl IndentedNewline { + /// Write a newline followed by indentation to the writer + pub fn write(self, writer: &mut impl Write, options: &BasePrintOptions) -> fmt::Result { + Newline.write(writer, options)?; + Indent.write(writer, options) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_base_print_options_default() { + let opts = BasePrintOptions::default(); + assert_eq!(opts.indent_str, " "); + assert_eq!(opts.indent_level, 0); + assert_eq!(opts.max_width, 80); + } + + #[test] + fn test_print_options_default() { + let opts = PrintOptions::::default(); + assert_eq!(opts.base.indent_str, " "); + assert_eq!(opts.base.indent_level, 0); + assert_eq!(opts.base.max_width, 80); + assert!(matches!( + opts.comment_alignment.position, + CommentPosition::ToLongest + )); + assert!(matches!( + opts.comment_alignment.grouping, + CommentGrouping::Consecutive + )); + } + + #[test] + fn test_print_options_deref() { + let opts = PrintOptions::::default(); + // Can access BasePrintOptions fields directly through Deref + assert_eq!(opts.indent_str, " "); + assert_eq!(opts.indent_level, 0); + assert_eq!(opts.max_width, 80); + } + + #[test] + fn test_base_print_options_indent() { + let opts = BasePrintOptions::default(); + let nested = opts.with_increased_indent(); + assert_eq!(nested.indent_level, 1); + assert_eq!(nested.current_indent(), " "); + } + + #[test] + fn test_print_options_indent() { + let opts = PrintOptions::::default(); + let nested = opts.with_increased_indent(); + assert_eq!(nested.indent_level, 1); + assert_eq!(nested.current_indent(), " "); + } + + #[test] + fn test_zst_helpers() { + let opts = BasePrintOptions::default(); + let mut output = String::new(); + + Indent.write(&mut output, &opts).unwrap(); + assert_eq!(output, ""); + + Newline.write(&mut output, &opts).unwrap(); + assert_eq!(output, "\n"); + + output.clear(); + let nested_opts = opts.with_increased_indent(); + IndentedNewline.write(&mut output, &nested_opts).unwrap(); + assert_eq!(output, "\n "); + } + + #[test] + fn test_zst_helpers_with_print_options() { + let opts = PrintOptions::::default(); + let mut output = String::new(); + + // PrintOptions can be used where BasePrintOptions is expected due to Deref + Indent.write(&mut output, &opts).unwrap(); + assert_eq!(output, ""); + + Newline.write(&mut output, &opts).unwrap(); + assert_eq!(output, "\n"); + + output.clear(); + let nested_opts = opts.with_increased_indent(); + IndentedNewline.write(&mut output, &nested_opts).unwrap(); + assert_eq!(output, "\n "); + } + + #[test] + fn test_printer_creation() { + let printer: Printer = Printer::default(); + assert_eq!(printer.options.indent_level, 0); + } + + #[test] + fn test_construction_methods() { + let base = BasePrintOptions { + indent_str: Cow::Borrowed("\t"), + indent_level: 1, + reserve_for_break: true, + max_width: 120, + newline_style: NewlineStyle::Windows, + }; + + let opts_default = PrintOptions::::from_base(base.clone()); + assert_eq!(opts_default.indent_str, "\t"); + assert!(matches!( + opts_default.comment_alignment.position, + CommentPosition::ToLongest + )); + + let opts_aligned = PrintOptions::::from_base_with_alignment( + base, + CommentAlignment { + grouping: CommentGrouping::Consecutive, + position: CommentPosition::ToFixed { + column: 40, + fallback_to_longest: false, + }, + }, + ); + assert_eq!(opts_aligned.indent_str, "\t"); + assert!(matches!( + opts_aligned.comment_alignment.position, + CommentPosition::ToFixed { + column: 40, + fallback_to_longest: false + } + )); + } +} diff --git a/opslang-printer/src/v1.rs b/opslang-printer/src/v1.rs new file mode 100644 index 0000000..dbd7a1a --- /dev/null +++ b/opslang-printer/src/v1.rs @@ -0,0 +1,748 @@ +use std::fmt::{self, Write}; + +mod prec; +mod strat_helper; + +use crate::{ + CommentAligned, CommentGrouping, CommentPosition, Indent, Naive, Newline, PrettyPrint, + PrintOptions, Strategy, +}; +use opslang_ast::syntax::v1::*; +use prec::{HasPrecedence, Precedence}; + +#[derive(Debug, Clone, Copy, Default)] +pub struct Token; + +impl Token { + #[inline] + /// Write a token to the writer. + pub fn write(self, token: T, writer: &mut impl Write) -> fmt::Result { + let _ = token; + writer.write_str(T::REPR) + } +} + +/// Macro to define a trait alias for TypeFamily with specific associated types. +macro_rules! define_trait_alias { + ( + $(#[$attr:meta])* + pub trait $trait_name:ident<$lifetime:lifetime> = $base_trait:path + ) => { + pub trait $trait_name<$lifetime>: $base_trait {} + + impl<$lifetime, F: $base_trait> $trait_name<$lifetime> for F {} + }; +} + +define_trait_alias!( + /// Alias for printable family used in this module. + /// + /// Types that implement this trait looks very similar to [`DefaultTypeFamily`], but + /// accepts any `Span` and `Position` types, which allows for more flexibility in + /// printing operations. + /// + /// **IMPORTANT**: When modifying [`TypeFamily`] trait in opslang-ast, you must also + /// update this trait to include the same associated types to maintain compatibility. + /// This trait must be kept in sync with [`DefaultTypeFamily`] associated type definitions. + pub trait PrintableFamily<'cx> = TypeFamily< + 'cx, + Comment = &'cx Comment<'cx, Self>, + ToplevelItem = ToplevelItem<'cx, Self>, + Row = &'cx Row<'cx, Self>, + Statement = Statement<'cx, Self>, + Block = &'cx Block<'cx, Self>, + Scope = Scope<'cx, Self>, + ReturnStmt = ReturnStmt<'cx, Self>, + Ident = Ident<'cx, Self>, + Path = Path<'cx, Self>, + Ty = Path<'cx, Self>, + Expr = Expr<'cx, Self>, + Exprs = &'cx [Expr<'cx, Self>], + Qualif = Qualif<'cx, Self>, + PreQualified = PreQualified<'cx, Self>, + Parened = Parened<'cx, Self>, + Literal = Literal<'cx, Self>, + FilePath = Literal<'cx, Self>, + ImportedPath = Path<'cx, Self>, + Array = Array<'cx, Self>, + String = String<'cx, Self>, + Bytes = Bytes<'cx, Self>, + HexBytes = HexBytes<'cx, Self>, + DateTime = DateTime<'cx, Self>, + Numeric = Numeric<'cx, Self>, + Apply = Apply<'cx, Self>, + Unary = Unary<'cx, Self>, + Binary = Binary<'cx, Self>, + BinOp = BinOp<'cx, Self>, + Compare = Compare<'cx, Self>, + Set = Set<'cx, Self>, + Cast = Cast<'cx, Self>, + InfixImport = InfixImport<'cx, Self>, + If = If<'cx, Self>, + Call = Call<'cx, Self>, + Wait = Wait<'cx, Self>, + Select = Select<'cx, Self>, + SelectItems = &'cx [SelectItem<'cx, Self>], + FunctionDef = FunctionDef<'cx, Self>, + ConstantDef = ConstantDef<'cx, Self>, + > +); + +#[doc(hidden)] +const _: () = { + /// Assert that `opslang_ast::DefaultTypeFamily: for<'cx> PrintableFamily<'cx>`, + /// which means `opslang-printer` can print AST. + const fn check_impl PrintableFamily<'cx>>() {} + check_impl::(); +}; + +impl<'cx, F: PrintableFamily<'cx>> PrettyPrint for Program<'cx, F> { + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + for (i, definition) in self.toplevel_items.iter().enumerate() { + if i > 0 { + Newline.write(writer, options)?; + } + PrettyPrint::::pretty_print(definition, writer, options)?; + } + Ok(()) + } +} + +impl<'cx, F: PrintableFamily<'cx>> PrettyPrint for Program<'cx, F> { + fn pretty_print( + &self, + writer: &mut impl Write, + options: &PrintOptions, + ) -> fmt::Result { + for (i, definition) in self.toplevel_items.iter().enumerate() { + if i > 0 { + Newline.write(writer, options)?; + } + PrettyPrint::::pretty_print(definition, writer, options)?; + } + Ok(()) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for ToplevelItem<'cx, F> +where + Block<'cx, F>: PrettyPrint, + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + if let Some(kind) = &self.kind { + match kind { + DefinitionKind::Function(func_def) => { + PrettyPrint::::pretty_print(func_def, writer, options)?; + } + DefinitionKind::Constant(const_def) => { + PrettyPrint::::pretty_print(const_def, writer, options)?; + } + } + } + if let Some(comment) = self.comment { + PrettyPrint::::pretty_print(comment, writer, options)?; + } + Ok(()) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for FunctionDef<'cx, F> +where + Block<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + Token.write(self.prc_token, writer)?; + writer.write_str(" ")?; + PrettyPrint::::pretty_print(&self.name, writer, options)?; + Token.write(self.left_paren, writer)?; + + for (i, param) in self.parameters.iter().enumerate() { + if i > 0 { + writer.write_str(", ")?; + } + PrettyPrint::::pretty_print(param, writer, options)?; + } + + Token.write(self.right_paren, writer)?; + writer.write_str(" ")?; + PrettyPrint::::pretty_print(self.body, writer, options) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Parameter<'cx, F> { + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + PrettyPrint::::pretty_print(&self.name, writer, options)?; + Token.write(self.colon, writer)?; + writer.write_str(" ")?; + PrettyPrint::::pretty_print(&self.ty, writer, options) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for ConstantDef<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + Token.write(self.const_token, writer)?; + writer.write_str(" ")?; + PrettyPrint::::pretty_print(&self.name, writer, options)?; + Token.write(self.colon, writer)?; + writer.write_str(" ")?; + PrettyPrint::::pretty_print(&self.ty, writer, options)?; + writer.write_str(" ")?; + Token.write(self.eq, writer)?; + writer.write_str(" ")?; + PrettyPrint::::pretty_print(&self.value, writer, options) + } +} + +impl<'cx, F: PrintableFamily<'cx>> PrettyPrint for Scope<'cx, F> { + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + for item in self.items { + match item { + ScopeItem::Row(row) => PrettyPrint::::pretty_print(*row, writer, options)?, + ScopeItem::Block(block) => { + PrettyPrint::::pretty_print(*block, writer, options)? + } + }; + Newline.write(writer, options)?; + } + Ok(()) + } +} + +impl<'cx, F: PrintableFamily<'cx>> PrettyPrint for Scope<'cx, F> { + fn pretty_print( + &self, + writer: &mut impl Write, + options: &PrintOptions, + ) -> fmt::Result { + match options.comment_alignment.grouping { + CommentGrouping::Consecutive => { + strat_helper::pretty_print_consecutive(self, writer, options) + } + CommentGrouping::PerBlock => { + strat_helper::pretty_print_per_block(self, writer, options) + } + } + } +} + +// Strategy-specific implementations for Row (where comment formatting matters) + +fn indent_break<'cx, S: Strategy, F: PrintableFamily<'cx>>( + row: &Row<'cx, F>, + writer: &mut impl Write, + options: &PrintOptions, +) -> fmt::Result { + if row.breaks.is_some() { + let mut indent_str = options.current_indent(); + if let Some(c) = indent_str.pop() { + writer.write_str(&indent_str)?; + writer.write_char('.')?; + if c == '\t' { + // assuming tab size >= 2 + writer.write_char('\t')?; + } + } else { + writer.write_char('.')?; + } + } else if options.reserve_for_break && !row.is_empty() && options.current_indent().is_empty() { + writer.write_char(' ')?; + } else { + Indent.write(writer, options)?; + } + Ok(()) +} + +impl<'cx, F: PrintableFamily<'cx>> PrettyPrint for Row<'cx, F> { + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + // Handle breaks + indent_break(self, writer, options)?; + + // Handle content + if let Some(content) = &self.statement { + PrettyPrint::::pretty_print(content, writer, options)?; + } + + // Handle comment (naive approach: just add space) + if let Some(comment) = &self.comment { + if self.statement.is_some() { + writer.write_str(" ")?; + } + PrettyPrint::::pretty_print(*comment, writer, options)?; + } + + Ok(()) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Comment<'cx, F> { + fn pretty_print(&self, writer: &mut impl Write, _options: &PrintOptions) -> fmt::Result { + writer.write_str("#")?; + if !self.content.trim_end().is_empty() { + writer.write_str(self.content) + } else { + Ok(()) + } + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Block<'cx, F> +where + Scope<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + Token.write(self.left_brace, writer)?; + Newline.write(writer, options)?; + + let nested_options = options.with_increased_indent(); + PrettyPrint::::pretty_print(&self.scope, writer, &nested_options)?; + + Indent.write(writer, options)?; + Token.write(self.right_brace, writer) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Statement<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + match self { + Statement::Let(let_stmt) => PrettyPrint::::pretty_print(let_stmt, writer, options), + Statement::Expr(expr_stmt) => { + PrettyPrint::::pretty_print(expr_stmt, writer, options) + } + Statement::Return(return_stmt) => { + PrettyPrint::::pretty_print(return_stmt, writer, options) + } + } + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Let<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + writer.write_str("let ")?; + PrettyPrint::::pretty_print(&self.variable, writer, options)?; + writer.write_str(" = ")?; + PrettyPrint::::pretty_print(&self.rhs, writer, options)?; + Token.write(self.semi, writer) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for ExprStatement<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + PrettyPrint::::pretty_print(&self.expr, writer, options)?; + Token.write(self.semi, writer) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for ReturnStmt<'cx, F> { + fn pretty_print(&self, writer: &mut impl Write, _options: &PrintOptions) -> fmt::Result { + Token.write(self.return_token, writer)?; + Token.write(self.semi, writer) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Expr<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + self.0.pretty_print(writer, options) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for ExprKind<'cx, F> +where + Block<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + match self { + ExprKind::Variable(path) => PrettyPrint::::pretty_print(path, writer, options), + ExprKind::Literal(literal) => PrettyPrint::::pretty_print(literal, writer, options), + ExprKind::Parened(parened) => PrettyPrint::::pretty_print(parened, writer, options), + ExprKind::Qualif(qualif) => PrettyPrint::::pretty_print(qualif, writer, options), + ExprKind::PreQualified(pre_qual) => { + PrettyPrint::::pretty_print(pre_qual, writer, options) + } + ExprKind::Unary(unary) => PrettyPrint::::pretty_print(unary, writer, options), + ExprKind::Compare(compare) => PrettyPrint::::pretty_print(compare, writer, options), + ExprKind::Binary(binary) => PrettyPrint::::pretty_print(binary, writer, options), + ExprKind::Apply(apply) => PrettyPrint::::pretty_print(apply, writer, options), + ExprKind::Set(set) => PrettyPrint::::pretty_print(set, writer, options), + ExprKind::Cast(cast) => PrettyPrint::::pretty_print(cast, writer, options), + ExprKind::InfixImport(import) => { + PrettyPrint::::pretty_print(import, writer, options) + } + ExprKind::If(if_expr) => PrettyPrint::::pretty_print(if_expr, writer, options), + ExprKind::Call(call_expr) => PrettyPrint::::pretty_print(call_expr, writer, options), + ExprKind::Wait(wait_expr) => PrettyPrint::::pretty_print(wait_expr, writer, options), + ExprKind::Select(select_expr) => { + PrettyPrint::::pretty_print(select_expr, writer, options) + } + } + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Path<'cx, F> { + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + for (i, ident) in self.segments.iter().enumerate() { + if i > 0 { + writer.write_char('.')?; + } + PrettyPrint::::pretty_print(ident, writer, options)?; + } + Ok(()) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Ident<'cx, F> { + fn pretty_print(&self, writer: &mut impl Write, _options: &PrintOptions) -> fmt::Result { + writer.write_str(self.raw) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Literal<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + match self { + Literal::Array(array) => PrettyPrint::::pretty_print(array, writer, options), + Literal::String(string) => PrettyPrint::::pretty_print(string, writer, options), + Literal::Bytes(bytes) => PrettyPrint::::pretty_print(bytes, writer, options), + Literal::HexBytes(hex_bytes) => { + PrettyPrint::::pretty_print(hex_bytes, writer, options) + } + Literal::Numeric(numeric) => PrettyPrint::::pretty_print(numeric, writer, options), + Literal::DateTime(datetime) => { + PrettyPrint::::pretty_print(datetime, writer, options) + } + } + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Array<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + Token.write(self.left_bracket, writer)?; + for (i, expr) in self.exprs.iter().enumerate() { + if i > 0 { + writer.write_str(", ")?; + } + PrettyPrint::::pretty_print(expr, writer, options)?; + } + Token.write(self.right_bracket, writer) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for String<'cx, F> { + fn pretty_print(&self, writer: &mut impl Write, _options: &PrintOptions) -> fmt::Result { + writer.write_str("\"")?; + writer.write_str(self.raw)?; + writer.write_str("\"") + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Bytes<'cx, F> { + fn pretty_print(&self, writer: &mut impl Write, _options: &PrintOptions) -> fmt::Result { + writer.write_str("b\"")?; + writer.write_str(self.raw)?; + writer.write_str("\"") + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for HexBytes<'cx, F> { + fn pretty_print(&self, writer: &mut impl Write, _options: &PrintOptions) -> fmt::Result { + writer.write_str("bx\"")?; + writer.write_str(self.raw)?; + writer.write_str("\"") + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Numeric<'cx, F> +where + Ident<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + match self.kind { + NumericKind::Integer(IntegerPrefix::Hexadecimal) => writer.write_str("0x")?, + NumericKind::Integer(IntegerPrefix::Octal) => writer.write_str("0o")?, + NumericKind::Integer(IntegerPrefix::Binary) => writer.write_str("0b")?, + NumericKind::Integer(IntegerPrefix::None) | NumericKind::Float => (), + }; + writer.write_str(self.raw)?; + if let Some(suffix) = &self.suffix { + PrettyPrint::::pretty_print(&suffix.0, writer, options)?; + } + Ok(()) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for DateTime<'cx, F> { + fn pretty_print(&self, writer: &mut impl Write, _options: &PrintOptions) -> fmt::Result { + writer.write_str(self.raw) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Parened<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + writer.write_str("(")?; + PrettyPrint::::pretty_print(&self.expr, writer, options)?; + writer.write_str(")") + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Qualif<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, + DefaultModifier<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + match self { + Qualif::Modifier(Modifier { at_token, id, arg }) => { + Token.write(at_token, writer)?; + PrettyPrint::::pretty_print(id, writer, options)?; + if let Some(expr) = arg { + Token.write(expr.colon_token, writer)?; + Precedence::ATOMIC.write_with_parens(&expr.value, writer, options)?; + } + Ok(()) + } + Qualif::DefaultModifier(exec_comp) => { + PrettyPrint::::pretty_print(exec_comp, writer, options) + } + } + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for DefaultModifier<'cx, F> +where + Path<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + Token.write(self.tilde_token, writer)?; + PrettyPrint::::pretty_print(&self.value, writer, options) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for PreQualified<'cx, F> +where + Qualif<'cx, F>: PrettyPrint, + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + for qualif in self.qualifs { + PrettyPrint::::pretty_print(qualif, writer, options)?; + writer.write_str(" ")?; + } + PrettyPrint::::pretty_print(&self.expr, writer, options) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Unary<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + match self.op { + UnOp::Neg(t) => Token.write(t, writer)?, + UnOp::IdRef(t) => Token.write(t, writer)?, + UnOp::Deref(t) => Token.write(t, writer)?, + }; + self.op + .precedence() + .write_with_parens(self.expr.0, writer, options) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Compare<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + Precedence::COMPARE.write_with_parens(self.head.0, writer, options)?; + for CompareOpExpr { op, val: expr } in self.tail_with_op { + writer.write_str(" ")?; + match op { + CompareOp::GreaterEq(t) => Token.write(t, writer), + CompareOp::LessEq(t) => Token.write(t, writer), + CompareOp::Greater(t) => Token.write(t, writer), + CompareOp::Less(t) => Token.write(t, writer), + CompareOp::NotEqual(NotEqualToken::BangEqual(t)) => Token.write(t, writer), + CompareOp::NotEqual(NotEqualToken::SlashEqual(t)) => Token.write(t, writer), + CompareOp::Equal(t) => Token.write(t, writer), + }?; + writer.write_str(" ")?; + Precedence::COMPARE.write_with_parens(expr.0, writer, options)?; + } + Ok(()) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Binary<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + let op_prec = self.op.precedence(); + + op_prec.write_with_parens(self.lhs.0, writer, options)?; + writer.write_str(" ")?; + match self.op { + BinOp::And(_) => writer.write_str("&&")?, + BinOp::Or(_) => writer.write_str("||")?, + BinOp::Mul(_) => writer.write_str("*")?, + BinOp::Div(_) => writer.write_str("/")?, + BinOp::Mod(_) => writer.write_str("%")?, + BinOp::Add(_) => writer.write_str("+")?, + BinOp::Sub(_) => writer.write_str("-")?, + } + writer.write_str(" ")?; + op_prec.write_with_parens(self.rhs.0, writer, options) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Apply<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + // OCaml-like function application: f x y instead of f(x, y) + Precedence::APPLY.write_with_parens(self.function.0, writer, options)?; + for arg in self.args.iter() { + writer.write_str(" ")?; + Precedence::APPLY.write_with_parens(arg.0, writer, options)?; + } + Ok(()) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Set<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + Precedence::SET.write_with_parens(self.lhs.0, writer, options)?; + writer.write_str(" ")?; + Token.write(self.colon_eq, writer)?; + writer.write_str(" ")?; + Precedence::SET.write_with_parens(self.rhs.0, writer, options) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Cast<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + Precedence::CAST.write_with_parens(self.expr.0, writer, options)?; + writer.write_str(" ")?; + Token.write(self.as_kw, writer)?; + writer.write_str(" ")?; + PrettyPrint::::pretty_print(&self.ty, writer, options) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for InfixImport<'cx, F> +where + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + PrettyPrint::::pretty_print(&self.file, writer, options)?; + Token.write(self.question, writer)?; + PrettyPrint::::pretty_print(&self.path, writer, options) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for If<'cx, F> +where + Block<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + Token.write(self.if_kw, writer)?; + PrettyPrint::::pretty_print(self.cond.0, writer, options)?; + PrettyPrint::::pretty_print(self.then_clause, writer, options)?; + if let Some(if_else) = &self.else_opt { + Token.write(if_else.else_kw, writer)?; + PrettyPrint::::pretty_print(if_else.else_clause, writer, options) + } else { + Ok(()) + } + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Call<'cx, F> +where + Block<'cx, F>: PrettyPrint, + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + Token.write(self.call_kw, writer)?; + writer.write_str(" ")?; + PrettyPrint::::pretty_print(&self.expr, writer, options) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Wait<'cx, F> +where + Block<'cx, F>: PrettyPrint, + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + Token.write(self.wait_kw, writer)?; + writer.write_str(" ")?; + PrettyPrint::::pretty_print(&self.expr, writer, options) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for Select<'cx, F> +where + Block<'cx, F>: PrettyPrint, + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + Token.write(self.select_kw, writer)?; + writer.write_str(" ")?; + Token.write(self.left_brace, writer)?; + Newline.write(writer, options)?; + + let nested_options = options.with_increased_indent(); + for item in self.items { + Indent.write(writer, &nested_options)?; + PrettyPrint::::pretty_print(item, writer, &nested_options)?; + Newline.write(writer, &nested_options)?; + } + + Indent.write(writer, options)?; + Token.write(self.right_brace, writer) + } +} + +impl<'cx, S: Strategy, F: PrintableFamily<'cx>> PrettyPrint for SelectItem<'cx, F> +where + Block<'cx, F>: PrettyPrint, + ExprKind<'cx, F>: PrettyPrint, +{ + fn pretty_print(&self, writer: &mut impl Write, options: &PrintOptions) -> fmt::Result { + PrettyPrint::::pretty_print(&self.expr, writer, options)?; + writer.write_str(" ")?; + Token.write(self.arrow, writer)?; + writer.write_str(" ")?; + PrettyPrint::::pretty_print(self.body, writer, options) + } +} diff --git a/opslang-printer/src/v1/prec.rs b/opslang-printer/src/v1/prec.rs new file mode 100644 index 0000000..12fc118 --- /dev/null +++ b/opslang-printer/src/v1/prec.rs @@ -0,0 +1,101 @@ +use core::fmt; +use std::fmt::Write; + +use opslang_ast::{BinOp, ExprKind, UnOp}; + +use crate::{PrettyPrint, PrintOptions, Strategy, v1::PrintableFamily}; + +/// Operator precedence for proper parenthesization +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Precedence(u8); + +/// Constant definitions. +/// +/// Note that `pub`lished constant leaks definition of `precedence`. +impl Precedence { + pub const SET: Self = Self(0); // := + const LOGICAL_OR: Self = Self(2); // || + const LOGICAL_AND: Self = Self(3); // && + pub const COMPARE: Self = Self(4); // >=, <=, >, <, !=, /=, == + const ARITHMETIC: Self = Self(5); // +, - + const FACTOR: Self = Self(6); // *, /, % + pub const CAST: Self = Self(7); // as + const PREFIX: Self = Self(8); // unary - + pub const APPLY: Self = Self(9); // function application + const LOWER_PREFIX: Self = Self(10); // &, $ + pub const ATOMIC: Self = Self(11); // grouping, literals, etc. +} + +pub trait HasPrecedence { + fn precedence(&self) -> Precedence; +} + +impl<'cx, F: PrintableFamily<'cx>> HasPrecedence for ExprKind<'cx, F> { + /// Get the precedence of an expression kind. + fn precedence(&self) -> Precedence { + let expr = self; + match expr { + ExprKind::Set(_) => Precedence::SET, + ExprKind::Binary(binary) => binary.op.precedence(), + ExprKind::Compare(_) => Precedence::COMPARE, + ExprKind::Unary(unary) => unary.op.precedence(), + ExprKind::Cast(_) => Precedence::CAST, + ExprKind::Apply(_) => Precedence::APPLY, + ExprKind::Variable(_) + | ExprKind::Literal(_) + | ExprKind::Parened(_) + | ExprKind::Qualif(_) + | ExprKind::PreQualified(_) + | ExprKind::InfixImport(_) + | ExprKind::If(_) + | ExprKind::Call(_) + | ExprKind::Wait(_) + | ExprKind::Select(_) => Precedence::ATOMIC, + } + } +} + +impl<'cx, F: PrintableFamily<'cx>> HasPrecedence for BinOp<'cx, F> { + fn precedence(&self) -> Precedence { + match self { + BinOp::Or(_) => Precedence::LOGICAL_OR, + BinOp::And(_) => Precedence::LOGICAL_AND, + BinOp::Add(_) | BinOp::Sub(_) => Precedence::ARITHMETIC, + BinOp::Mul(_) | BinOp::Div(_) | BinOp::Mod(_) => Precedence::FACTOR, + } + } +} + +impl<'cx, F: PrintableFamily<'cx>> HasPrecedence for UnOp<'cx, F> { + fn precedence(&self) -> Precedence { + match self { + UnOp::Neg(_) => Precedence::PREFIX, + UnOp::IdRef(_) | UnOp::Deref(_) => Precedence::LOWER_PREFIX, + } + } +} + +impl Precedence { + /// Print an expression with parentheses if needed. + /// + /// This function will give parens when `self` is greater than the + /// precedence of the child expression. In other words, if the child expression is + /// the same or more prioritized than the parent, it will be printed without parens. + pub fn write_with_parens<'cx, S: Strategy, F: PrintableFamily<'cx>>( + self, + expr: &ExprKind<'cx, F>, + writer: &mut impl Write, + options: &PrintOptions, + ) -> fmt::Result + where + ExprKind<'cx, F>: PrettyPrint, + { + if expr.precedence() < self { + writer.write_str("(")?; + PrettyPrint::::pretty_print(expr, writer, options)?; + writer.write_str(")") + } else { + PrettyPrint::::pretty_print(expr, writer, options) + } + } +} diff --git a/opslang-printer/src/v1/strat_helper.rs b/opslang-printer/src/v1/strat_helper.rs new file mode 100644 index 0000000..94b3d4e --- /dev/null +++ b/opslang-printer/src/v1/strat_helper.rs @@ -0,0 +1,217 @@ +use crate::v1::indent_break; + +use super::{ + Comment, CommentAligned, CommentPosition, Newline, PrettyPrint, PrintOptions, PrintableFamily, + Row, Scope, ScopeItem, Write, fmt, +}; + +/// Implementation for consecutive grouping: group rows separated by empty lines +pub fn pretty_print_consecutive<'cx, F: PrintableFamily<'cx>>( + scope: &Scope<'cx, F>, + writer: &mut impl Write, + options: &PrintOptions, +) -> fmt::Result { + let mut current_group = Vec::new(); + let mut temp_buffer = String::new(); + + for item in scope.items { + match item { + ScopeItem::Row(row) => { + // Format the content part + let row_info = format_row_before_comment(&mut temp_buffer, row, options)?; + + // If this is an empty line (default Row), output current group + if row.is_empty() { + if !current_group.is_empty() { + write_comment_group(¤t_group, writer, options)?; + current_group.clear(); + } + // Write the empty line + Newline.write(writer, options)?; + } else { + current_group.push(row_info); + } + } + ScopeItem::Block(block) => { + // Output any pending group before the block + if !current_group.is_empty() { + write_comment_group(¤t_group, writer, options)?; + current_group.clear(); + } + // Output the block + PrettyPrint::::pretty_print(*block, writer, options)?; + } + } + } + + // Output any remaining group + if !current_group.is_empty() { + write_comment_group(¤t_group, writer, options)?; + } + + Ok(()) +} + +/// Implementation for per-block grouping: group all comments in the current block +pub fn pretty_print_per_block<'cx, F: PrintableFamily<'cx>>( + scope: &Scope<'cx, F>, + writer: &mut impl Write, + options: &PrintOptions, +) -> fmt::Result { + let mut row_infos = Vec::new(); + let mut temp_buffer = String::new(); + + // Collect all row information + for item in scope.items { + match item { + ScopeItem::Row(row) => { + // Format the content part + let row_info = format_row_before_comment(&mut temp_buffer, row, options)?; + + row_infos.push(row_info); + } + ScopeItem::Block(block) => { + // Output any pending rows before the block + if !row_infos.is_empty() { + write_comment_group(&row_infos, writer, options)?; + row_infos.clear(); + } + // Output the block (recursively handles its own alignment) + PrettyPrint::::pretty_print(*block, writer, options)?; + } + } + } + + // Output any remaining rows + if !row_infos.is_empty() { + write_comment_group(&row_infos, writer, options)?; + } + + Ok(()) +} + +/// Information about a single row for comment alignment calculation. +#[derive(Debug, Clone)] +struct RowInfo<'cx, F: PrintableFamily<'cx>> { + /// Pre-formatted content string (before comment). + content: std::string::String, + + /// Whether this row has content. + has_content: bool, + + /// Raw comment reference (None if no comment). + comment: Option<&'cx Comment<'cx, F>>, +} + +impl<'cx, F: PrintableFamily<'cx>> RowInfo<'cx, F> { + fn need_align(&self) -> bool { + if !self.has_content { + return false; + } + let Some(comment) = self.comment else { + return false; + }; + // Shebang comments (starting with '!') are not aligned + !comment.content.starts_with('!') + } +} + +/// Write a group of rows with aligned comments. +fn write_comment_group<'cx, F: PrintableFamily<'cx>>( + rows: &[RowInfo<'cx, F>], + writer: &mut impl Write, + options: &PrintOptions, +) -> fmt::Result { + if rows.is_empty() { + return Ok(()); + } + + // Find the target alignment position (excluding shebang comments) + let longest_content = rows + .iter() + .filter(|row| row.need_align()) + .map(|row| row.content.len()) + .max() + .unwrap_or(0); + + let target_position = + calculate_target_position(longest_content, options.comment_alignment.position); + + // Write each row with proper alignment + for row in rows { + writer.write_str(&row.content)?; + + if row.need_align() { + let current_len = row.content.len(); + if target_position > current_len { + let spaces_needed = target_position - current_len; + writer.write_str(&" ".repeat(spaces_needed))?; + } + } + + if let Some(comment) = row.comment { + PrettyPrint::::pretty_print(comment, writer, options)?; + } + + Newline.write(writer, options)?; + } + + Ok(()) +} + +/// Formats content part and extract information for comment alignment +fn format_row_before_comment<'cx, F: PrintableFamily<'cx>>( + temp_buffer: &mut std::string::String, + row: &Row<'cx, F>, + options: &PrintOptions, +) -> Result, fmt::Error> { + // Handle meta comment first + if row.breaks.is_none() && row.statement.is_none() && row.comment.is_some_and(|c| c.is_meta()) { + return Ok(RowInfo { + content: Default::default(), + has_content: row.statement.is_some(), + comment: row.comment, + }); + } + indent_break(row, temp_buffer, options)?; + if let Some(content) = &row.statement { + PrettyPrint::::pretty_print(content, temp_buffer, options)?; + } + + Ok(RowInfo { + content: std::mem::take(temp_buffer), + has_content: row.statement.is_some(), + comment: row.comment, + }) +} + +/// Calculate the target position based on position strategy +fn calculate_target_position(longest_content: usize, position: CommentPosition) -> usize { + if longest_content == 0 { + return 0; // No content, no alignment needed + } + match position { + CommentPosition::ToLongest => longest_content + 1, // +1 for space before comment + CommentPosition::ToFixed { + column, + fallback_to_longest, + } => { + if fallback_to_longest && longest_content >= column { + longest_content + 1 + } else { + column + } + } + CommentPosition::ToTabMultiple { + tab_size, + fallback_to_longest, + } => { + let tab_position = ((longest_content / tab_size) + 1) * tab_size; + if fallback_to_longest && longest_content >= tab_position { + longest_content + 1 + } else { + tab_position + } + } + } +} diff --git a/opslang-printer/tests/v1_integration.rs b/opslang-printer/tests/v1_integration.rs new file mode 100644 index 0000000..03860b9 --- /dev/null +++ b/opslang-printer/tests/v1_integration.rs @@ -0,0 +1,253 @@ +//! Integration tests for v1 printer functionality +//! These tests use the parser to create AST nodes and then test printer behavior + +use opslang_ast::v1::context::Context; +use opslang_parser::{ParseOps, ParserInput}; +use opslang_printer::{ + BasePrintOptions, CommentAligned, CommentAlignment, CommentGrouping, CommentPosition, Naive, + PrettyPrint, PrintOptions, +}; + +// Helper to parse a given source code string +fn parse_source<'cx>( + source: &'cx str, + context: &'cx Context<'cx>, +) -> opslang_ast::v1::Program<'cx> { + let input = ParserInput { + content: source, + file_name: "test.ops".into(), + }; + opslang_ast::v1::Program::parse(input, context).expect("Failed to parse test source") +} + +#[test] +fn test_naive_vs_comment_aligned_simple() { + let source = r#"#! lang=v1 +prc main() { + let x = value1; # comment1 + let very_long_var = value2; # comment2 +} +"#; + + let context = Context::new(); + let program = parse_source(source, &context); + + // Test with Naive strategy + let naive_options = PrintOptions::::default(); + let naive_result = program.to_pretty_string(&naive_options); + + // Test with CommentAligned strategy + let aligned_options = PrintOptions::::default(); + let aligned_result = program.to_pretty_string(&aligned_options); + + println!("Naive result:\n{naive_result}"); + println!("Aligned result:\n{aligned_result}"); + + // Both should contain the same content but with different comment alignment + assert!(naive_result.contains("let x = value1")); + assert!(aligned_result.contains("let x = value1")); + assert!(naive_result.contains("comment1")); + assert!(aligned_result.contains("comment1")); + + // The aligned version should have different spacing + assert_ne!(naive_result, aligned_result); +} + +#[test] +fn test_consecutive_vs_per_block_grouping() { + let source = r#"#! lang=v1 +prc main() { + let x = val1; # comment1 + let very_long_var = val2; # comment2 + + let y = val3; # comment3 +} +"#; + + let context = Context::new(); + let program = parse_source(source, &context); + + // Test with Consecutive grouping + let consecutive_options = PrintOptions::::from_base_with_alignment( + BasePrintOptions::default(), + CommentAlignment { + grouping: CommentGrouping::Consecutive, + position: CommentPosition::ToLongest, + }, + ); + let consecutive_result = program.to_pretty_string(&consecutive_options); + + // Test with PerBlock grouping + let per_block_options = PrintOptions::::from_base_with_alignment( + BasePrintOptions::default(), + CommentAlignment { + grouping: CommentGrouping::PerBlock, + position: CommentPosition::ToLongest, + }, + ); + let per_block_result = program.to_pretty_string(&per_block_options); + + println!("Consecutive result:\n{consecutive_result}"); + println!("Per block result:\n{per_block_result}"); + + // Both should contain the same content + assert!(consecutive_result.contains("let x = val1")); + assert!(per_block_result.contains("let x = val1")); + + // The grouping should be different + assert_ne!(consecutive_result, per_block_result); +} + +#[test] +fn test_position_strategies() { + let source = r#"#! lang=v1 +prc main() { + let x = val1; # comment1 + let very_long_variable = val2; # comment2 +} +"#; + + let context = Context::new(); + let program = parse_source(source, &context); + + // Test ToLongest + let longest_options = PrintOptions::::from_base_with_alignment( + BasePrintOptions::default(), + CommentAlignment { + grouping: CommentGrouping::Consecutive, + position: CommentPosition::ToLongest, + }, + ); + let longest_result = program.to_pretty_string(&longest_options); + + // Test ToFixed + let fixed_options = PrintOptions::::from_base_with_alignment( + BasePrintOptions::default(), + CommentAlignment { + grouping: CommentGrouping::Consecutive, + position: CommentPosition::ToFixed { + column: 30, + fallback_to_longest: false, + }, + }, + ); + let fixed_result = program.to_pretty_string(&fixed_options); + + // Test ToTabMultiple + let tab_options = PrintOptions::::from_base_with_alignment( + BasePrintOptions::default(), + CommentAlignment { + grouping: CommentGrouping::Consecutive, + position: CommentPosition::ToTabMultiple { + tab_size: 6, + fallback_to_longest: false, + }, + }, + ); + let tab_result = program.to_pretty_string(&tab_options); + + println!("ToLongest result:\n{longest_result}"); + println!("ToFixed result:\n{fixed_result}"); + println!("ToTabMultiple result:\n{tab_result}"); + + // All should contain the same content + assert!(longest_result.contains("let x = val1")); + assert!(fixed_result.contains("let x = val1")); + assert!(tab_result.contains("let x = val1")); + + // The alignment should be different + assert_ne!(longest_result, fixed_result); + assert_ne!(longest_result, tab_result); + assert_ne!(fixed_result, tab_result); +} + +#[test] +fn test_fallback_to_longest_behavior() { + let source = r#"#! lang=v1 +prc main() { + let x = val1; # comment1 + let this_is_a_very_very_long_variable_name = val2; # comment2 +} +"#; + + let context = Context::new(); + let program = parse_source(source, &context); + + // Test ToFixed with fallback disabled + let fixed_no_fallback = PrintOptions::::from_base_with_alignment( + BasePrintOptions::default(), + CommentAlignment { + grouping: CommentGrouping::Consecutive, + position: CommentPosition::ToFixed { + column: 20, + fallback_to_longest: false, + }, + }, + ); + let fixed_no_fallback_result = program.to_pretty_string(&fixed_no_fallback); + + // Test ToFixed with fallback enabled + let fixed_with_fallback = PrintOptions::::from_base_with_alignment( + BasePrintOptions::default(), + CommentAlignment { + grouping: CommentGrouping::Consecutive, + position: CommentPosition::ToFixed { + column: 20, + fallback_to_longest: true, + }, + }, + ); + let fixed_with_fallback_result = program.to_pretty_string(&fixed_with_fallback); + + println!("Fixed no fallback result:\n{fixed_no_fallback_result}"); + println!("Fixed with fallback result:\n{fixed_with_fallback_result}"); + + // Both should contain the same content + assert!(fixed_no_fallback_result.contains("let x = val1")); + assert!(fixed_with_fallback_result.contains("let x = val1")); + + // The fallback behavior should be different + assert_ne!(fixed_no_fallback_result, fixed_with_fallback_result); +} + +#[test] +fn test_empty_lines_with_consecutive_grouping() { + let source = r#"#! lang=v1 +prc main() { + let x = val1; # comment1 + let y = val2; # comment2 + + let very_long_var = val3; # comment3 + let z = val4; # comment4 +} +"#; + + let context = Context::new(); + let program = parse_source(source, &context); + + let consecutive_options = PrintOptions::::from_base_with_alignment( + BasePrintOptions::default(), + CommentAlignment { + grouping: CommentGrouping::Consecutive, + position: CommentPosition::ToLongest, + }, + ); + let result = program.to_pretty_string(&consecutive_options); + + println!("Empty lines with consecutive grouping result:\n{result}"); + + // Should contain all content + assert!(result.contains("let x = val1")); + assert!(result.contains("let y = val2")); + assert!(result.contains("let very_long_var = val3")); + assert!(result.contains("let z = val4")); + + // Should contain all comments + assert!(result.contains("comment1")); + assert!(result.contains("comment2")); + assert!(result.contains("comment3")); + assert!(result.contains("comment4")); + + // Should have empty line separating groups + assert!(result.contains("\n\n")); +} diff --git a/opslang-visitor-macro-helper/Cargo.toml b/opslang-visitor-macro-helper/Cargo.toml new file mode 100644 index 0000000..2cae74c --- /dev/null +++ b/opslang-visitor-macro-helper/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "opslang-visitor-macro-helper" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +syn.workspace = true +proc-macro2.workspace = true +quote.workspace = true +convert_case.workspace = true diff --git a/opslang-visitor-macro-helper/src/generate_visitor_impl.rs b/opslang-visitor-macro-helper/src/generate_visitor_impl.rs new file mode 100644 index 0000000..50e34e0 --- /dev/null +++ b/opslang-visitor-macro-helper/src/generate_visitor_impl.rs @@ -0,0 +1,166 @@ +use super::*; + +/// Generates visitor implementation for AST types. +pub fn generate_visitor_impl( + visitor_impl: VisitorImpl, + callsite_trait: CallsiteTraitName, + types: Vec, +) -> syn::Result { + let impl_type = &visitor_impl.impl_type; + let impl_generics = &visitor_impl.impl_generics; + let user_methods = &visitor_impl.methods; + + // Collect user-defined methods + let mut user_method_map: std::collections::HashMap = + user_methods.iter().map(|m| (m.name.clone(), m)).collect(); + + // Generate Visitor implementations for each AST type + let mut visitor_impls = Vec::new(); + let mut links_for_callsite = Vec::new(); + for visitor_type in &types { + visitor_impls.push(generate_single_visitor_impl( + visitor_type, + impl_generics, + impl_type, + &callsite_trait, + &mut user_method_map, + &mut links_for_callsite, + )?); + } + + // Check for unused user methods and report errors + if !user_method_map.is_empty() { + let mut errors: VecDeque = user_method_map + .into_iter() + .map(|(unused_name, unused_method)| { + syn::Error::new( + unused_method.name_span, + format!( + "invalid visitor method `{unused_name}`\nfound no matching type for hook" + ), + ) + }) + .collect(); + + // Combine all errors into a single error + let mut combined_error = errors.pop_front().unwrap(); + for error in errors { + combined_error.combine(error); + } + return Err(combined_error); + } + + let generics = syn::parse_quote!(<'cx>); + let combined_generics = concatenate_generics(impl_generics, &generics); + let (combined_impl_generics, _, combined_where_clause) = combined_generics.split_for_impl(); + + Ok(quote! { + #(#visitor_impls)* + + #[doc(hidden)] + const _: () = { + fn links_for_callsite #combined_impl_generics () #combined_where_clause { + #(#links_for_callsite)* + } + }; + }) +} + +/// Holds the trait paths for callsite linking. +/// +/// This information is not necessary for the visitor generation itself, +/// but is used to create references to the visitor methods to ensure +/// they are linked correctly at the callsite. +pub struct CallsiteTraitName { + visitor: Path, + visitor_mut: Option, +} + +impl CallsiteTraitName { + pub fn both(visitor: Path, visitor_mut: Path) -> Self { + Self { + visitor, + visitor_mut: Some(visitor_mut), + } + } + pub fn visitor_only(visitor: Path) -> Self { + Self { + visitor, + visitor_mut: None, + } + } +} + +/// Generate a single visitor implementation for a specific AST type. +fn generate_single_visitor_impl( + visitor_type: &VisitorType, + impl_generics: &Generics, + impl_type: &Type, + callsite_trait: &CallsiteTraitName, + user_method_map: &mut std::collections::HashMap, + links_for_callsite: &mut Vec, +) -> syn::Result { + let VisitorType { + generics, + path, + visit_method_name, + mode, + } = visitor_type; + + let trait_name = mode.trait_name(); + let method_name_str = mode.method_name(); + let method_name_ident = syn::Ident::new(method_name_str, proc_macro2::Span::call_site()); + + let visit_fn = if let Some(user_method) = user_method_map.remove(visit_method_name) { + // Found a user-defined method for this type. Use it and remove from map. + let attrs = &user_method.attrs; + let PatType { pat, ty, .. } = &user_method.param; + let block = &user_method.block; + let visit_method_name = syn::Ident::new(visit_method_name, user_method.name_span); + let callsite_trait = match mode { + VisitorMode::Visit => &callsite_trait.visitor, + VisitorMode::VisitMut => callsite_trait.visitor_mut.as_ref().ok_or_else(|| { + syn::Error::new( + user_method.name_span, + format!("no mutable visitor trait provided for method `{visit_method_name}`",), + ) + })?, + }; + links_for_callsite.push(quote! { + let _ = <#impl_type as #callsite_trait>::#visit_method_name; + }); + + // Use user-defined method with their exact parameter and type + quote! { + #(#attrs)* + fn #method_name_ident(&mut self, #pat: #ty) { + #block + } + } + } else { + match mode { + VisitorMode::Visit => quote! { + #[inline] + fn #method_name_ident(&mut self, node: &#path) { + <#path as ::opslang_visitor::TemplateVisit>::super_visit(node, self); + } + }, + VisitorMode::VisitMut => quote! { + #[inline] + fn #method_name_ident(&mut self, node: &mut #path) { + <#path as ::opslang_visitor::TemplateVisitMut>::super_visit_mut(node, self); + } + }, + } + }; + + // Concatenate generics properly + let combined_generics = concatenate_generics(impl_generics, generics); + let (combined_impl_generics, _, combined_where_clause) = combined_generics.split_for_impl(); + + Ok(quote! { + impl #combined_impl_generics #trait_name<#path> for #impl_type #combined_where_clause { + #visit_fn + } + }) +} diff --git a/opslang-visitor-macro-helper/src/lib.rs b/opslang-visitor-macro-helper/src/lib.rs new file mode 100644 index 0000000..5792077 --- /dev/null +++ b/opslang-visitor-macro-helper/src/lib.rs @@ -0,0 +1,307 @@ +use std::{borrow::Cow, collections::VecDeque}; + +use quote::quote; +use syn::{ + Attribute, Block, FnArg, Generics, ItemFn, PatType, Path, ReturnType, Token, Type, + parse::{Parse, ParseStream}, +}; + +pub mod generate_visitor_impl; +pub use generate_visitor_impl::{CallsiteTraitName, generate_visitor_impl}; +pub mod no_intermediate_helper; +pub mod shared_visitor_trait; + +/// Method kind for generating method names. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum MethodKind { + /// Generate `visit_*` method names + Visit, + /// Generate `super_*` method names (for identifier-safe names) + Super, +} + +/// Validated visitor method with checked parameter and block. +pub struct VisitorMethod { + pub attrs: Vec, + pub name: String, + pub param: PatType, + pub block: Block, + + /// For diagnostic purpose + pub name_span: proc_macro2::Span, +} + +/// Structure representing a visitor implementation block. +pub struct VisitorImpl { + pub impl_generics: Generics, + pub impl_type: Type, + pub methods: Vec, +} + +impl Parse for VisitorImpl { + fn parse(input: ParseStream) -> syn::Result { + let mut impl_generics = input.parse::()?; + + input.parse::()?; + let impl_type = input.parse::()?; + + // Parse where clause if present + if input.peek(Token![where]) { + impl_generics.where_clause = Some(input.parse()?); + } + + let content; + syn::braced!(content in input); + + let mut methods = Vec::new(); + while !content.is_empty() { + let item_fn = content.parse::()?; + let validated_method = validate_visitor_method(item_fn)?; + methods.push(validated_method); + } + + Ok(VisitorImpl { + impl_generics, + impl_type, + methods, + }) + } +} + +/// Validates a visitor method function to ensure it has the correct signature. +fn validate_visitor_method(item_fn: ItemFn) -> syn::Result { + let sig = &item_fn.sig; + + // Check for invalid modifiers + if sig.constness.is_some() { + return Err(syn::Error::new_spanned( + sig.constness, + "visitor methods cannot be const", + )); + } + if sig.asyncness.is_some() { + return Err(syn::Error::new_spanned( + sig.asyncness, + "visitor methods cannot be async", + )); + } + if sig.unsafety.is_some() { + return Err(syn::Error::new_spanned( + sig.unsafety, + "visitor methods cannot be unsafe", + )); + } + if sig.abi.is_some() { + return Err(syn::Error::new_spanned( + &sig.abi, + "visitor methods cannot have custom ABI", + )); + } + + // Check return type (should be () or omitted) + match &sig.output { + ReturnType::Default => {} + ReturnType::Type(_, ty) => { + if let Type::Tuple(tuple) = ty.as_ref() { + if !tuple.elems.is_empty() { + return Err(syn::Error::new_spanned( + ty, + "visitor methods must return () or have no return type", + )); + } + } else { + return Err(syn::Error::new_spanned( + ty, + "visitor methods must return () or have no return type", + )); + } + } + } + + // Check that signature has exactly 2 parameters: &mut self and one other parameter + if sig.inputs.len() != 2 { + return Err(syn::Error::new_spanned( + &sig.inputs, + "visitor methods must have exactly 2 parameters: &mut self and the node parameter", + )); + } + + // Check first parameter is &mut self + if let Some(FnArg::Receiver(receiver)) = sig.inputs.first() { + if receiver.reference.is_none() || receiver.mutability.is_none() { + return Err(syn::Error::new_spanned( + receiver, + "first parameter must be &mut self", + )); + } + } else { + return Err(syn::Error::new_spanned( + sig.inputs.first().unwrap(), + "first parameter must be &mut self", + )); + } + + let sig = item_fn.sig; + + // The second parameter should be a reference, we'll validate the exact type later + let arg = sig.inputs.into_iter().nth(1).unwrap(); + let param = if let FnArg::Typed(param) = arg { + // Valid - we have a typed parameter + param + } else { + return Err(syn::Error::new_spanned( + arg, + "second parameter must be a typed parameter", + )); + }; + + Ok(VisitorMethod { + attrs: item_fn.attrs, + name: sig.ident.to_string(), + name_span: sig.ident.span(), + param, + block: *item_fn.block, + }) +} + +/// Visitor mode indicating whether to generate immutable or mutable visitor implementations. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum VisitorMode { + /// Generate immutable visitor implementations (`Visitor` trait, `visit` method) + Visit, + /// Generate mutable visitor implementations (`VisitorMut` trait, `visit_mut` method) + VisitMut, +} + +impl VisitorMode { + /// Returns the trait name for this visitor mode. + pub fn trait_name(&self) -> proc_macro2::TokenStream { + use quote::quote; + match self { + VisitorMode::Visit => quote!(::opslang_visitor::Visitor), + VisitorMode::VisitMut => quote!(::opslang_visitor::VisitorMut), + } + } + + /// Returns the method name for this visitor mode. + pub fn method_name(&self) -> &'static str { + match self { + VisitorMode::Visit => "visit", + VisitorMode::VisitMut => "visit_mut", + } + } +} + +/// Type definition for visitor implementation generation. +pub struct VisitorType { + pub generics: Generics, + pub path: Path, + pub visit_method_name: String, + pub mode: VisitorMode, +} + +/// Check if generics are empty (equivalent to default) +fn is_empty_generics(generics: &Generics) -> bool { + generics.params.is_empty() && generics.where_clause.is_none() +} + +/// Concatenates two Generics, combining parameters and where clauses. +fn concatenate_generics<'a>(left: &'a Generics, right: &'a Generics) -> Cow<'a, Generics> { + if is_empty_generics(left) { + return Cow::Borrowed(right); + } else if is_empty_generics(right) { + return Cow::Borrowed(left); + } + let mut combined = left.clone(); + + // Extend parameters + combined.params.extend(right.params.iter().cloned()); + + // Ensure we have angle bracket tokens if we have parameters + if !combined.params.is_empty() && combined.lt_token.is_none() { + combined.lt_token = Some(left.lt_token.or(right.lt_token).unwrap()); + combined.gt_token = Some(left.gt_token.or(right.gt_token).unwrap()); + } + + // Combine where clauses + if let Some(type_where) = &right.where_clause { + if combined.where_clause.is_some() { + combined + .make_where_clause() + .predicates + .extend(type_where.predicates.iter().cloned()); + } else { + *combined.make_where_clause() = type_where.clone(); + } + } + + Cow::Owned(combined) +} + +#[cfg(test)] +mod tests { + use super::*; + use syn::parse_quote; + + #[test] + fn test_visitor_impl_parse() { + // Test simple case without generics + let input = parse_quote! { + for TestVisitor { + fn visit_test(&mut self, node: &TestNode) { + println!("test"); + } + } + }; + let parsed: VisitorImpl = input; + assert_eq!(parsed.methods.len(), 1); + + // Test with generics + let input2 = parse_quote! { + for T { + fn visit_generic(&mut self, item: &GenericNode) { + println!("generic"); + } + } + }; + let parsed2: VisitorImpl = input2; + assert_eq!(parsed2.methods.len(), 1); + } + + #[test] + fn test_visitor_method_validation() { + use syn::parse_quote; + + // Valid method + let valid_fn: ItemFn = parse_quote! { + fn visit_test(&mut self, node: &TestNode) { + println!("test"); + } + }; + assert!(validate_visitor_method(valid_fn).is_ok()); + + // Invalid: const method + let const_fn: ItemFn = parse_quote! { + const fn visit_test(&mut self, node: &TestNode) { + println!("test"); + } + }; + assert!(validate_visitor_method(const_fn).is_err()); + + // Invalid: async method + let async_fn: ItemFn = parse_quote! { + async fn visit_test(&mut self, node: &TestNode) { + println!("test"); + } + }; + assert!(validate_visitor_method(async_fn).is_err()); + + // Invalid: wrong number of parameters + let wrong_params: ItemFn = parse_quote! { + fn visit_test(&mut self) { + println!("test"); + } + }; + assert!(validate_visitor_method(wrong_params).is_err()); + } +} diff --git a/opslang-visitor-macro-helper/src/no_intermediate_helper.rs b/opslang-visitor-macro-helper/src/no_intermediate_helper.rs new file mode 100644 index 0000000..9b13155 --- /dev/null +++ b/opslang-visitor-macro-helper/src/no_intermediate_helper.rs @@ -0,0 +1,201 @@ +pub fn update_generics( + impl_generics: &syn::Generics, + update: impl Fn(&mut syn::Generics), +) -> syn::Generics { + let mut updated_generics = impl_generics.clone(); + update(&mut updated_generics); + + // Ensure we have angle bracket tokens if we have parameters + if updated_generics.lt_token.is_none() { + updated_generics.lt_token = Some(syn::Token![<](proc_macro2::Span::call_site())); + updated_generics.gt_token = Some(syn::Token![>](proc_macro2::Span::call_site())); + } + updated_generics +} + +/// Visitor implementation mode for generic types. +#[derive(Debug, Clone, Copy)] +pub enum VisitorMode { + /// Generate immutable visitor implementations using `[visit]` + Visit, + /// Generate mutable visitor implementations using `[visit_mut]` + VisitMut, +} + +impl VisitorMode { + /// Returns the visitor mode as a token stream for use in `impl_visitor!` macro. + fn as_tokens(&self) -> proc_macro2::TokenStream { + use quote::quote; + match self { + VisitorMode::Visit => quote!([visit]), + VisitorMode::VisitMut => quote!([visit_mut]), + } + } + + /// Returns the trait name for constraints. + fn trait_name(&self) -> proc_macro2::TokenStream { + use quote::quote; + match self { + VisitorMode::Visit => quote!(::opslang_visitor::Visitor), + VisitorMode::VisitMut => quote!(::opslang_visitor::VisitorMut), + } + } +} + +/// Generate generic visitor implementations from the given generics. +/// +/// This function creates visitor implementations for common generic types like `str`, `Option`, +/// `[T]`, `&T`, and tuple `(T1, T2)` using the provided generics as the base. +/// +/// # Arguments +/// +/// * `updated_generics`: +/// The base generics that have been updated (e.g., with additional lifetimes). +/// Must have generic angle brackets (lt_token must be Some) as verified by the assert. +/// New type parameters will be added to this base for each generated implementation. +/// * `impl_type`: +/// The visitor type being implemented (e.g., `MyVisitor<'a>`). +/// * `mode`: +/// The visitor mode (Visit or VisitMut) determining which trait implementations to generate. +/// +/// # Generated implementations +/// +/// The function generates the following visitor implementations: +/// - `str` - Uses the base generics unchanged +/// - `Option` - Adds type parameter `T` with `Self: Visitor` constraint +/// - `[T]` - Adds type parameter `T` with `Self: Visitor` constraint +/// - `&T` - Adds type parameter `T` with `T: ?Sized` and `Self: Visitor` constraints +/// - `(T1, T2)` - Adds type parameters `T1, T2` with `Self: Visitor + Visitor` constraints +/// +/// # Panics +/// +/// Panics if `updated_generics.params.is_empty()`, indicating the generics don't have parameters, +/// which disrupts `::opslang_visitor::impl_visitor!` call. +fn generate_generic_visitor_impls_internal( + updated_generics: &syn::Generics, + impl_type: &syn::Type, + mode: VisitorMode, +) -> proc_macro2::TokenStream { + use quote::quote; + + let t = impl_type; + let mode_tokens = mode.as_tokens(); + let trait_name = mode.trait_name(); + + assert!(!updated_generics.params.is_empty()); + let (impl_generics, _, where_clause) = updated_generics.split_for_impl(); + + // Base implementation for str (no additional generics) + let str_impl = quote! { + ::opslang_visitor::impl_visitor!(#impl_generics #t #mode_tokens str #where_clause); + }; + + let t_generics = update_generics(updated_generics, |g| { + // Add T to generics for Option, [T] and &T + g.params.push(syn::parse_quote!(T)); + + // Add where clause for T + g.make_where_clause() + .predicates + .push(syn::parse_quote!(Self: #trait_name)) + }); + + let (t_impl_generics, _, t_where_clause) = t_generics.split_for_impl(); + + let generic_impls = quote! { + ::opslang_visitor::impl_visitor!(#t_impl_generics #t #mode_tokens Option #t_where_clause); + ::opslang_visitor::impl_visitor!(#t_impl_generics #t #mode_tokens [T] #t_where_clause); + }; + + let ref_t_generics = match mode { + VisitorMode::Visit => { + update_generics(&t_generics, |g| { + // For &T, we need T: ?Sized to handle &str, &[U], etc. + g.make_where_clause() + .predicates + .push(syn::parse_quote!(T: ?Sized)) + }) + } + VisitorMode::VisitMut => { + update_generics(updated_generics, |g| { + // Add T to generics for &mut T + g.params.push(syn::parse_quote!(T)); + + // Add where clause for T + let trait_name = VisitorMode::Visit.trait_name(); + g.make_where_clause() + .predicates + .push(syn::parse_quote!(Self: #trait_name)); + + // For &mut T, we need T: ?Sized to handle &mut str, &mut [U], etc. + g.make_where_clause() + .predicates + .push(syn::parse_quote!(T: ?Sized)) + }) + } + }; + + let (ref_t_impl_generics, _, ref_t_where_clause) = ref_t_generics.split_for_impl(); + + let ref_impl = quote! { + ::opslang_visitor::impl_visitor!(#ref_t_impl_generics #t #mode_tokens &T #ref_t_where_clause); + }; + + let ref_mut_t_generics = update_generics(&t_generics, |g| { + // For &mut T, we need T: ?Sized to handle &mut str, &mut [U], etc. + g.make_where_clause() + .predicates + .push(syn::parse_quote!(T: ?Sized)) + }); + + let (ref_mut_t_impl_generics, _, ref_mut_t_where_clause) = ref_mut_t_generics.split_for_impl(); + + let ref_mut_impl = quote! { + ::opslang_visitor::impl_visitor!(#ref_mut_t_impl_generics #t #mode_tokens &mut T #ref_mut_t_where_clause); + }; + + // Add tuple implementations + let tuple2_generics = update_generics(updated_generics, |g| { + // For 2-tuple (T1, T2) + g.params.push(syn::parse_quote!(T1)); + g.params.push(syn::parse_quote!(T2)); + + let tuple2_where_clause = g.make_where_clause(); + tuple2_where_clause + .predicates + .push(syn::parse_quote!(Self: #trait_name)); + tuple2_where_clause + .predicates + .push(syn::parse_quote!(Self: #trait_name)); + }); + + let (tuple2_impl_generics, _, tuple2_where_clause) = tuple2_generics.split_for_impl(); + + let tuple2_impl = quote! { + ::opslang_visitor::impl_visitor!(#tuple2_impl_generics #t #mode_tokens (T1, T2) #tuple2_where_clause); + }; + + quote! { + #str_impl + #generic_impls + #ref_impl + #ref_mut_impl + #tuple2_impl + } +} + +/// Generate generic visitor implementations for immutable visiting. +pub fn generate_generic_visitor_impls( + updated_generics: &syn::Generics, + impl_type: &syn::Type, +) -> proc_macro2::TokenStream { + generate_generic_visitor_impls_internal(updated_generics, impl_type, VisitorMode::Visit) +} + +/// Generate generic visitor implementations for mutable visiting. +pub fn generate_generic_visitor_mut_impls( + updated_generics: &syn::Generics, + impl_type: &syn::Type, +) -> proc_macro2::TokenStream { + generate_generic_visitor_impls_internal(updated_generics, impl_type, VisitorMode::VisitMut) +} diff --git a/opslang-visitor-macro-helper/src/shared_visitor_trait.rs b/opslang-visitor-macro-helper/src/shared_visitor_trait.rs new file mode 100644 index 0000000..857af89 --- /dev/null +++ b/opslang-visitor-macro-helper/src/shared_visitor_trait.rs @@ -0,0 +1,212 @@ +use quote::{format_ident, quote}; +use syn::{Token, braced, token}; + +/// Trait declaration structure that can be parsed from input. +pub struct TraitDeclaration { + pub attrs: Vec, + pub vis: syn::Visibility, + pub _trait_token: Token![trait], + pub ident: syn::Ident, + pub generics: syn::Generics, + pub _brace_token: token::Brace, +} + +impl syn::parse::Parse for TraitDeclaration { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let _content; + Ok(Self { + attrs: input.call(syn::Attribute::parse_outer)?, + vis: input.parse()?, + _trait_token: input.parse()?, + ident: input.parse()?, + generics: input.parse()?, + _brace_token: braced!(_content in input), + }) + } +} + +/// Type interface for visitor trait generation. +pub trait VisitableType { + /// Generate the method name for this type based on method kind and visitor mode. + fn generate_visit_method_name( + &self, + kind: crate::MethodKind, + mode: crate::VisitorMode, + ) -> String; + + /// Generate the full type path for this type. + fn full_type_path(&self) -> proc_macro2::TokenStream; +} + +/// Generate visitor trait implementation. +pub fn declare_visitor_trait( + trait_decl: TraitDeclaration, + types: impl Iterator, + mode: crate::VisitorMode, +) -> syn::Result { + let TraitDeclaration { + attrs, + vis, + ident, + generics, + .. + } = &trait_decl; + let types: Vec<_> = types.into_iter().collect(); + + // Generate visit_* and super_* method signatures + // Expansion of `unzip` for 3-tuples is not supported in std. + let mut unzipped: (Vec<_>, Vec<_>, Vec<_>) = Default::default(); + let it = types.iter() + .map(|visitor_type| { + let visit_name = + visitor_type.generate_visit_method_name(crate::MethodKind::Visit, mode); + let super_name = + visitor_type.generate_visit_method_name(crate::MethodKind::Super, mode); + let method_ident = format_ident!("{visit_name}"); + let super_method_ident = format_ident!("{super_name}"); + let type_path = visitor_type.full_type_path(); + + let param_type = match mode { + crate::VisitorMode::Visit => quote! { &#type_path }, + crate::VisitorMode::VisitMut => quote! { &mut #type_path }, + }; + + let sig = quote! { + #[doc = "This method can be overridden by visitor implementation macros."] + fn #method_ident(&mut self, node: #param_type); + #[doc = "This method cannot be overridden."] + fn #super_method_ident(&mut self, node: #param_type); + }; + let method = match mode { + crate::VisitorMode::Visit => quote! { + fn #method_ident(&mut self, node: #param_type) { + ::opslang_visitor::Visitor::<#type_path>::visit(self, node) + } + fn #super_method_ident(&mut self, node: #param_type) { + <#type_path as ::opslang_visitor::TemplateVisit>::super_visit(node, self) + } + }, + crate::VisitorMode::VisitMut => quote! { + fn #method_ident(&mut self, node: #param_type) { + ::opslang_visitor::VisitorMut::<#type_path>::visit_mut(self, node) + } + fn #super_method_ident(&mut self, node: #param_type) { + <#type_path as ::opslang_visitor::TemplateVisitMut>::super_visit_mut(node, self) + } + }, + }; + let doc_method = match mode { + crate::VisitorMode::Visit => quote! { + fn #method_ident(&mut self, node: #param_type) { + unimplemented!() + } + fn #super_method_ident(&mut self, node: #param_type) { + unimplemented!() + } + }, + crate::VisitorMode::VisitMut => quote! { + fn #method_ident(&mut self, node: #param_type) { + unimplemented!() + } + fn #super_method_ident(&mut self, node: #param_type) { + unimplemented!() + } + }, + }; + (sig, method, doc_method) + }); + unzipped.extend(it); + let (visit_signatures, visit_methods, doc_visit_methods) = unzipped; + + // Generate trait bounds for Self: Visitor + Visitor + ... + let (visitor_bounds, node_type_bounds) = match mode { + crate::VisitorMode::Visit => { + let visitor_bounds = types.iter().map(|visitor_type| { + let type_path = visitor_type.full_type_path(); + quote! { + ::opslang_visitor::Visitor<#type_path> + } + }); + let ast_type_bounds = types.iter().map(|visitor_type| { + let type_path = visitor_type.full_type_path(); + quote! { + #type_path: ::opslang_visitor::TemplateVisit + } + }); + ( + visitor_bounds.collect::>(), + ast_type_bounds.collect::>(), + ) + } + crate::VisitorMode::VisitMut => { + let visitor_bounds = types.iter().map(|visitor_type| { + let type_path = visitor_type.full_type_path(); + quote! { + ::opslang_visitor::VisitorMut<#type_path> + } + }); + let node_type_bounds = types.iter().map(|visitor_type| { + let type_path = visitor_type.full_type_path(); + quote! { + #type_path: ::opslang_visitor::TemplateVisitMut + } + }); + ( + visitor_bounds.collect::>(), + node_type_bounds.collect::>(), + ) + } + }; + let doc_only_trait_name = match mode { + crate::VisitorMode::Visit => format_ident!("TooManyBoundsForDocumentation"), + crate::VisitorMode::VisitMut => format_ident!("TooManyBoundsForDocumentationMut"), + }; + let doc_hidden_bounds_len = visitor_bounds.len(); + let doc_crate_link = format!( + "Actual trait definition is generated by macro. This documentation and the macro are located at `{}` crate.", + env!("CARGO_CRATE_NAME") + ); + + Ok(quote! { + #(#attrs)* + #vis trait #ident #generics { + #(#visit_signatures)* + } + #[cfg(not(doc))] + impl<'cx, V> #ident #generics for V + where + V: ?Sized #(+ #visitor_bounds)*, + #(#node_type_bounds),* + { + #(#visit_methods)* + } + + // below is only for documentation purposes + + #[cfg(doc)] + #[doc(hidden)] + trait #doc_only_trait_name {} + + /// Implements the visitor trait for any type that visits all node types. + /// + /// This enables referring to the visitor methods by its name like + /// `visitor.visit_ty` instead of `use`-ing the `Visitor` trait directly, + /// which accepts all node types as parameters and may introduce bugs + /// by accident. + /// + /// In fact, `V` needs to implement `Visitor` or `VisitorMut + /// for each node type and all node types should be visitable. + /// We omit this from the documentation to reduce clutter. + #[doc = ""] + #[doc = #doc_crate_link] + #[doc = ""] + #[doc = concat!("This impl has ", #doc_hidden_bounds_len, " * 2 bounds that are hidden for documentation purposes.")] + #[cfg(doc)] + impl<'cx, V> #ident #generics for V + where + V: ?Sized + #doc_only_trait_name, + { + #(#doc_visit_methods)* + } + }) +} diff --git a/opslang-visitor/Cargo.toml b/opslang-visitor/Cargo.toml new file mode 100644 index 0000000..4b14e2a --- /dev/null +++ b/opslang-visitor/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "opslang-visitor" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +chrono.workspace = true diff --git a/opslang-visitor/macro/Cargo.toml b/opslang-visitor/macro/Cargo.toml new file mode 100644 index 0000000..4468515 --- /dev/null +++ b/opslang-visitor/macro/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "opslang-visitor-macro" +version.workspace = true +edition.workspace = true +license.workspace = true + +[lib] +proc-macro = true + +[dependencies] +syn.workspace = true +proc-macro2.workspace = true +quote.workspace = true +synstructure.workspace = true diff --git a/opslang-visitor/macro/src/derive_visit.rs b/opslang-visitor/macro/src/derive_visit.rs new file mode 100644 index 0000000..d490ceb --- /dev/null +++ b/opslang-visitor/macro/src/derive_visit.rs @@ -0,0 +1,117 @@ +pub fn derive_visit( + input: proc_macro::TokenStream, +) -> Result { + let derive_input = + syn::parse::(input).map_err(syn::Error::into_compile_error)?; + let mut s = + synstructure::Structure::try_new(&derive_input).map_err(syn::Error::into_compile_error)?; + s.bind_with(|_| synstructure::BindStyle::Move); + + let skip_all = has_skip_all_visit(&derive_input); + + let visit_body = s.each(|bi| { + if skip_all || has_skip_visit(bi.ast()) { + quote::quote! {} + } else { + quote::quote! { + ::opslang_visitor::Visitor::visit(visitor, #bi); + } + } + }); + + let visit_mut_body = s.each(|bi| { + if skip_all || has_skip_visit(bi.ast()) { + quote::quote! {} + } else { + quote::quote! { + ::opslang_visitor::VisitorMut::visit_mut(visitor, #bi); + } + } + }); + + // Collect unique types of all binding fields to generate where clauses + // Skip fields with #[skip_visit] attribute or if #[skip_all_visit] is present + let mut field_types = std::collections::HashSet::new(); + if !skip_all { + for variant in s.variants() { + for binding in variant.bindings() { + let field = binding.ast(); + if !has_skip_visit(field) { + field_types.insert(&field.ty); + } + } + } + } + + // Generate impl trait bounds for Visitor trait + let visit_bounds = field_types.iter().map(|ty| { + quote::quote! { + ::opslang_visitor::Visitor<#ty> + } + }); + + // Generate impl trait bounds for VisitorMut trait + let visit_mut_bounds = field_types.iter().map(|ty| { + quote::quote! { + ::opslang_visitor::VisitorMut<#ty> + } + }); + + // Build generics properly by adding V to the existing generics + let mut visit_generics = derive_input.generics.clone(); + visit_generics.params.push(syn::parse_quote! { V }); + + let mut visit_mut_generics = derive_input.generics.clone(); + visit_mut_generics.params.push(syn::parse_quote! { V }); + + // Add where clauses for visitor bounds + visit_generics + .make_where_clause() + .predicates + .push(syn::parse_quote! { V: #(#visit_bounds)+* }); + + visit_mut_generics + .make_where_clause() + .predicates + .push(syn::parse_quote! { V: #(#visit_mut_bounds)+* }); + + let (visit_impl_generics, _, visit_where_clause) = visit_generics.split_for_impl(); + let (visit_mut_impl_generics, _, visit_mut_where_clause) = visit_mut_generics.split_for_impl(); + + let (_, ty_generics, _) = derive_input.generics.split_for_impl(); + let name = &derive_input.ident; + + let result = quote::quote! { + impl #visit_impl_generics ::opslang_visitor::TemplateVisit for #name #ty_generics + #visit_where_clause + { + fn super_visit(&self, visitor: &mut V) { + match self { #visit_body } + } + } + + impl #visit_mut_impl_generics ::opslang_visitor::TemplateVisitMut for #name #ty_generics + #visit_mut_where_clause + { + fn super_visit_mut(&mut self, visitor: &mut V) { + match self { #visit_mut_body } + } + } + }; + + Ok(result) +} + +fn has_skip_visit(field: &syn::Field) -> bool { + field + .attrs + .iter() + .any(|attr| attr.path().is_ident("skip_visit")) +} + +fn has_skip_all_visit(derive_input: &syn::DeriveInput) -> bool { + derive_input + .attrs + .iter() + .any(|attr| attr.path().is_ident("skip_all_visit")) +} diff --git a/opslang-visitor/macro/src/lib.rs b/opslang-visitor/macro/src/lib.rs new file mode 100644 index 0000000..f8caa34 --- /dev/null +++ b/opslang-visitor/macro/src/lib.rs @@ -0,0 +1,8 @@ +mod derive_visit; + +#[proc_macro_derive(Visit, attributes(skip_visit, skip_all_visit))] +pub fn derive_visit(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + derive_visit::derive_visit(input) + .unwrap_or_else(std::convert::identity) + .into() +} diff --git a/opslang-visitor/src/impls.rs b/opslang-visitor/src/impls.rs new file mode 100644 index 0000000..a6e116d --- /dev/null +++ b/opslang-visitor/src/impls.rs @@ -0,0 +1,103 @@ +use crate::{TemplateVisit, TemplateVisitMut, Visitor, VisitorMut}; + +impl_template_visit_base_case!( + str, + std::convert::Infallible, + usize, + u8, + chrono::DateTime +); + +impl, T> TemplateVisit for Option { + fn super_visit(&self, visitor: &mut V) { + if let Some(node) = self { + visitor.visit(node); + } + } +} + +impl, T> TemplateVisitMut for Option { + fn super_visit_mut(&mut self, visitor: &mut V) { + if let Some(node) = self { + visitor.visit_mut(node); + } + } +} + +impl, T: ?Sized> TemplateVisit for &T { + fn super_visit(&self, visitor: &mut V) { + >::visit(visitor, &**self); + } +} + +/// Enables immutable visitation during mutable visitor traversal. +/// +/// This implementation is more important than it appears. When encountering an immutable reference +/// during a mutable visitor traversal, it allows the visitor to continue with immutable visitation +/// of the inner type, ensuring the visitor pattern remains consistent and type-safe. +impl, T: ?Sized> TemplateVisitMut for &T { + fn super_visit_mut(&mut self, visitor: &mut V) { + >::visit(visitor, &**self); + } +} + +/// Enables immutable visitation of mutable references. +impl, T: ?Sized> TemplateVisit for &mut T { + fn super_visit(&self, visitor: &mut V) { + >::visit(visitor, &**self); + } +} + +impl, T: ?Sized> TemplateVisitMut for &mut T { + fn super_visit_mut(&mut self, visitor: &mut V) { + >::visit_mut(visitor, &mut **self); + } +} + +impl, T> TemplateVisit for [T] { + fn super_visit(&self, visitor: &mut V) { + for node in self.iter() { + visitor.visit(node); + } + } +} + +impl, T> TemplateVisitMut for [T] { + fn super_visit_mut(&mut self, visitor: &mut V) { + for node in self.iter_mut() { + visitor.visit_mut(node); + } + } +} + +impl, T> TemplateVisit for Vec { + fn super_visit(&self, visitor: &mut V) { + for node in self { + visitor.visit(node); + } + } +} + +impl, T> TemplateVisitMut for Vec { + fn super_visit_mut(&mut self, visitor: &mut V) { + for node in self { + visitor.visit_mut(node); + } + } +} + +impl + Visitor, T1, T2> TemplateVisit for (T1, T2) { + fn super_visit(&self, visitor: &mut V) { + let (x1, x2) = self; + visitor.visit(x1); + visitor.visit(x2); + } +} + +impl + VisitorMut, T1, T2> TemplateVisitMut for (T1, T2) { + fn super_visit_mut(&mut self, visitor: &mut V) { + let (x1, x2) = self; + visitor.visit_mut(x1); + visitor.visit_mut(x2); + } +} diff --git a/opslang-visitor/src/lib.rs b/opslang-visitor/src/lib.rs new file mode 100644 index 0000000..67dc7cd --- /dev/null +++ b/opslang-visitor/src/lib.rs @@ -0,0 +1,110 @@ +#[diagnostic::on_unimplemented( + message = "add `#[derive(Visit)]` to `{Self}` or implement `TemplateVisit` manually" +)] +pub trait TemplateVisit { + #[inline] + #[allow(unused_variables)] + fn super_visit(&self, visitor: &mut V) {} +} + +#[diagnostic::on_unimplemented( + message = "add `#[derive(Visit)]` to `{Self}` or implement `TemplateVisitMut` manually" +)] +pub trait TemplateVisitMut { + #[inline] + #[allow(unused_variables)] + fn super_visit_mut(&mut self, visitor: &mut V) {} +} + +#[diagnostic::on_unimplemented( + message = "add `{T}` to visitor_type_registry.rs: node types (allow hooking) or inter types (disallow hooking)" +)] +pub trait Visitor { + fn visit(&mut self, node: &T); +} + +#[diagnostic::on_unimplemented( + message = "add `{T}` to visitor_type_registry.rs: node types (allow hooking) or inter types (disallow hooking)" +)] +pub trait VisitorMut { + fn visit_mut(&mut self, node: &mut T); +} + +/// Generates base case implementations for [`TemplateVisit`] and [`TemplateVisitMut`]. +/// +/// This macro creates empty implementations for types that serve as base cases +/// in the visitor pattern, providing default no-op behavior for both immutable +/// and mutable visiting. +/// +/// # Examples +/// +/// ```ignore +/// impl_template_visit_base_case!(str); +/// impl_template_visit_base_case!(u32, i32, f64); +/// ``` +#[macro_export] +macro_rules! impl_template_visit_base_case { + ($($t:ty),+ $(,)?) => { + $( + impl $crate::TemplateVisit for $t {} + impl $crate::TemplateVisitMut for $t {} + )+ + }; +} + +/// Generates visitor trait implementations for visitor types. +/// +/// This macro automatically implements the [`Visitor`] trait for a given visitor type and target type, +/// delegating to the target type's [`TemplateVisit`] implementation. It supports both immutable (`visit`) +/// and mutable (`visit_mut`) visitor patterns. +/// +/// # Syntax +/// +/// ```ignore +/// impl_visitor!(< generics > VisitorType [visit] TargetType where constraints); +/// impl_visitor!(< generics > VisitorType [visit_mut] TargetType where constraints); +/// ``` +/// +/// # Generated Implementation +/// +/// For the `[visit]` variant, generates: +/// ```ignore +/// impl Visitor for VisitorType where constraints { +/// fn visit(&mut self, node: &TargetType) { +/// >::super_visit(node, self); +/// } +/// } +/// ``` +/// +/// # Examples +/// +/// ```ignore +/// // Basic usage for a simple visitor type +/// impl_visitor!(<> MyVisitor [visit] AstNode); +/// +/// // With generic parameters and constraints +/// impl_visitor!( Wrapper [visit] Option where Wrapper: Visitor); +/// +/// // For reference types +/// // Tips: complex bounds such as `?Sized` is accepted by parenthesized +/// impl_visitor!( MyVisitor [visit] &T where MyVisitor: Visitor); +/// ``` +#[macro_export] +macro_rules! impl_visitor { + (< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),* > $v:ty [visit] $t:ty $(where $($tt:tt)*)?) => { + impl < $( $lt $( : $clt $(+ $dlt )* )? ),* > $crate::Visitor<$t> for $v $(where $($tt)*)? { + fn visit(&mut self, node: &$t) { + <$t as $crate::TemplateVisit>::super_visit(node, self); + } + } + }; + (< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),* > $v:ty [visit_mut] $t:ty $(where $($tt:tt)*)?) => { + impl < $( $lt $( : $clt $(+ $dlt )* )? ),* > $crate::VisitorMut<$t> for $v $(where $($tt)*)? { + fn visit_mut(&mut self, node: &mut $t) { + <$t as $crate::TemplateVisitMut>::super_visit_mut(node, self); + } + } + }; +} + +mod impls; diff --git a/structure/opslang-ast/Cargo.toml b/structure/opslang-ast/Cargo.toml new file mode 100644 index 0000000..e3b4416 --- /dev/null +++ b/structure/opslang-ast/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "opslang-ast" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "ops file language AST" + +[features] +v0 = [] +v1 = ["dep:typed-arena"] +default = ["v0", "v1"] + +[dependencies] +opslang-ast-macro.workspace = true +opslang-visitor.workspace = true +opslang-visitor-macro.workspace = true +typed-arena.workspace = true +typed-arena.optional = true + +escape8259 = "0.5.3" +chrono = "0.4.33" + +[dev-dependencies] +opslang-ast-macro.workspace = true +opslang-parser.workspace = true diff --git a/structure/opslang-ast/macro/Cargo.toml b/structure/opslang-ast/macro/Cargo.toml new file mode 100644 index 0000000..b3669ef --- /dev/null +++ b/structure/opslang-ast/macro/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "opslang-ast-macro" +version.workspace = true +edition.workspace = true +license.workspace = true + +[lib] +proc-macro = true + +[dependencies] +syn.workspace = true +proc-macro2.workspace = true +quote.workspace = true +synstructure.workspace = true +convert_case.workspace = true +opslang-type-registry.workspace = true +opslang-visitor-macro-helper.workspace = true diff --git a/structure/opslang-ast/macro/src/ast_consistency_check.rs b/structure/opslang-ast/macro/src/ast_consistency_check.rs new file mode 100644 index 0000000..356b4dc --- /dev/null +++ b/structure/opslang-ast/macro/src/ast_consistency_check.rs @@ -0,0 +1,32 @@ +use proc_macro2::TokenStream; +use quote::quote; + +/// Generates a compile-time consistency check that verifies all AST types defined in `ast_types.rs` +/// actually exist and are accessible from a v1 child module. +/// +/// This macro creates a compile-time check that ensures type consistency between the centralized +/// type registry in `ast_types.rs` and the actual type definitions in `opslang-ast/src/syntax/v1.rs`. +/// +/// The generated code uses `const _: () = { let _: T; }` pattern to verify that each type +/// can be referenced and is valid at compile time. If any type in the registry doesn't exist +/// or isn't accessible, compilation will fail with a clear error message. +/// +/// See the call site for more information. +pub fn ast_consistency_check() -> TokenStream { + let ast_types = opslang_type_registry::v1::ast::types::AstNodeTy::get_v1_ast_node_types(); + + let type_checks = ast_types.map(|ast_type| { + let type_path = ast_type.inside_of_v1_child_mod().super_path(); + quote! { + let _: #type_path; + } + }); + + quote! { + const _: () = { + fn check<'cx>() { + #(#type_checks)* + } + }; + } +} diff --git a/structure/opslang-ast/macro/src/declare_ast_visitor.rs b/structure/opslang-ast/macro/src/declare_ast_visitor.rs new file mode 100644 index 0000000..662ba9a --- /dev/null +++ b/structure/opslang-ast/macro/src/declare_ast_visitor.rs @@ -0,0 +1,14 @@ +use opslang_visitor_macro_helper::{ + VisitorMode, + shared_visitor_trait::{TraitDeclaration, declare_visitor_trait}, +}; + +use opslang_type_registry::v1::ast::types::AstNodeTy; + +/// Generates a comprehensive visitor trait for all V1 AST types. +pub fn declare_ast_visitor_trait( + trait_decl: TraitDeclaration, +) -> syn::Result { + let all_ast_types = AstNodeTy::get_v1_ast_node_types(); + declare_visitor_trait::(trait_decl, all_ast_types, VisitorMode::Visit) +} diff --git a/structure/opslang-ast/macro/src/derive_map_into_token.rs b/structure/opslang-ast/macro/src/derive_map_into_token.rs new file mode 100644 index 0000000..1ad8fe6 --- /dev/null +++ b/structure/opslang-ast/macro/src/derive_map_into_token.rs @@ -0,0 +1,191 @@ +use std::collections::HashMap; + +use proc_macro2::TokenStream; +use quote::quote; +use syn::{ + Data, DeriveInput, Fields, Ident, Token, WherePredicate, punctuated::Punctuated, + visit_mut::VisitMut, +}; + +struct TypeParamReplacer<'a> { + map: &'a HashMap, +} + +impl VisitMut for TypeParamReplacer<'_> { + fn visit_type_path_mut(&mut self, node: &mut syn::TypePath) { + // Continue visiting children first + syn::visit_mut::visit_type_path_mut(self, node); + + // Then check if this path matches our target + if let Some(first_segment) = node.path.segments.first_mut() + && let Some(target) = self.map.get(&first_segment.ident) + { + let span = first_segment.ident.span(); + first_segment.ident.clone_from(target); + first_segment.ident.set_span(span); + } + } + + fn visit_lifetime_mut(&mut self, node: &mut syn::Lifetime) { + if let Some(target) = self.map.get(&node.ident) { + let span = node.ident.span(); + node.ident.clone_from(target); + node.ident.set_span(span); + } + } +} + +pub fn derive_map_into_token(input: DeriveInput) -> syn::Result { + let name = &input.ident; + let (_impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + // Parse the enum data + // In next refactoring, it is better to use `synstructure` to handle aggregation + let data: Vec<_> = match &input.data { + Data::Struct(data) => vec![(name, &data.fields)], + Data::Enum(data) => data + .variants + .iter() + .map(|v| (&v.ident, &v.fields)) + .collect(), + _ => { + return Err(syn::Error::new_spanned( + input, + "MapIntoToken can only be derived for enums", + )); + } + }; + + // Generate match arms for each variant + let mut match_arms = Vec::new(); + + for (variant_name, fields) in &data { + match fields { + Fields::Unit => { + match_arms.push(quote! { + #name::#variant_name => #name::#variant_name, + }); + } + Fields::Unnamed(fields) => { + if fields.unnamed.len() == 1 { + match_arms.push(quote! { + #name::#variant_name(field) => #name::#variant_name(field.into_token()), + }); + } else { + return Err(syn::Error::new_spanned( + variant_name, + "MapIntoToken only supports variants with exactly one field", + )); + } + } + Fields::Named(fields) => { + let (bindings, rhs): (Punctuated<_, Token![,]>, Punctuated<_, Token![,]>) = fields + .named + .iter() + .map(|f| { + let id = f.ident.as_ref().unwrap(); + (id, quote! { #id: #id.into_token() }) + }) + .unzip(); + match_arms.push(quote! { + #name { + #bindings + } => #name { + #rhs + }, + }); + } + } + } + + // Create new generics with renamed type parameters + let mut new_generics = input.generics.clone(); + let mut param_map = std::collections::HashMap::new(); + + // Rename all parameters by appending suffixes + for param in &mut new_generics.params { + match param { + syn::GenericParam::Type(type_param) => { + let old_name = type_param.ident.clone(); + let new_name = format!("{old_name}Target"); + let new_ident = syn::Ident::new(&new_name, type_param.ident.span()); + param_map.insert(old_name, new_ident.clone()); + type_param.ident = new_ident; + } + syn::GenericParam::Lifetime(lifetime_param) => { + let old_name = lifetime_param.lifetime.ident.clone(); + let new_name = format!("{old_name}_target"); + let new_ident = syn::Ident::new(&new_name, lifetime_param.lifetime.ident.span()); + param_map.insert(old_name, new_ident.clone()); + lifetime_param.lifetime.ident = new_ident; + } + syn::GenericParam::Const(_) => {} // Don't handle const generics for now + } + } + + let mut replacer = TypeParamReplacer { map: ¶m_map }; + + // Also rename references in bounds and where clauses + replacer.visit_generics_mut(&mut new_generics); + + // Get new_ty_generics before moving new_generics + let new_generics_for_ty = new_generics.clone(); + let (_, new_ty_generics, _) = new_generics_for_ty.split_for_impl(); + + // Build where clause predicates + let mut predicates = Punctuated::::new(); + if let Some(where_clause) = where_clause { + predicates.clone_from(&where_clause.predicates); + } + + // Add constraints for each variant field that needs IntoToken + for (_, variant) in &data { + match variant { + Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { + let field_type = &fields.unnamed.first().unwrap().ty; + // Create target type by replacing type parameters with renamed ones + let mut target_type = field_type.clone(); + replacer.visit_type_mut(&mut target_type); + + predicates.push(syn::parse_quote! { + #field_type: crate::syntax::v1::token::IntoToken<#target_type> + }); + } + Fields::Named(fields) => { + for field_type in fields.named.iter().map(|f| &f.ty) { + // Create target type by replacing type parameters with renamed ones + let mut target_type = field_type.clone(); + + replacer.visit_type_mut(&mut target_type); + + predicates.push(syn::parse_quote! { + #field_type: crate::syntax::v1::token::IntoToken<#target_type> + }); + } + } + _ => unreachable!(), + } + } + + // Merge impl_generics and new_impl_generics + let mut merged_generics = input.generics.clone(); + for param in new_generics.params { + merged_generics.params.push(param); + } + let (merged_impl_generics, _, _) = merged_generics.split_for_impl(); + + let expanded = quote! { + impl #merged_impl_generics crate::syntax::v1::token::IntoToken<#name #new_ty_generics> for #name #ty_generics + where + #predicates + { + fn into_token(self) -> #name #new_ty_generics { + match self { + #(#match_arms)* + } + } + } + }; + + Ok(expanded) +} diff --git a/structure/opslang-ast/macro/src/derive_position.rs b/structure/opslang-ast/macro/src/derive_position.rs new file mode 100644 index 0000000..884bead --- /dev/null +++ b/structure/opslang-ast/macro/src/derive_position.rs @@ -0,0 +1,14 @@ +use syn::DeriveInput; + +pub fn derive_position(input: DeriveInput) -> syn::Result { + let name = input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + let position = quote::quote! { + impl #impl_generics crate::loc::Position for #name #ty_generics #where_clause { + fn position(&self) -> crate::Position { + self.position + } + } + }; + Ok(position) +} diff --git a/structure/opslang-ast/macro/src/derive_span.rs b/structure/opslang-ast/macro/src/derive_span.rs new file mode 100644 index 0000000..8f46a3f --- /dev/null +++ b/structure/opslang-ast/macro/src/derive_span.rs @@ -0,0 +1,77 @@ +use syn::{DeriveInput, Token, WherePredicate, punctuated::Punctuated, spanned::Spanned}; + +pub fn derive_span(input: DeriveInput) -> syn::Result { + let name = input.ident; + let span = quote::quote! { + impl crate::loc::Span for #name { + fn span(&self) -> crate::Span { + self.span + } + } + }; + Ok(span) +} + +pub fn derive_order_span(input: DeriveInput) -> syn::Result { + let name = input.ident.clone(); + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + let mut predicates = Punctuated::::new(); + if let Some(where_clause) = where_clause { + predicates.clone_from(&where_clause.predicates); + } + let span = input.span(); + let data = if let syn::Data::Struct(data) = input.data { + data + } else { + return Err(syn::Error::new_spanned( + input, + "OrderSpan can only be derived for structs", + )); + }; + let fields = if let syn::Fields::Named(fields) = data.fields { + fields + } else { + return Err(syn::Error::new( + span, + "OrderSpan can only be derived for structs with named fields", + )); + }; + let Some(first_field) = fields.named.first() else { + return Err(syn::Error::new_spanned( + fields, + "OrderSpan can only be derived for structs with at least one field", + )); + }; + let first_field_name = &first_field.ident.as_ref().unwrap(); + let first_field_ty = &first_field.ty; + let last_field = fields.named.last().unwrap(); + let last_field_name = &last_field.ident.as_ref().unwrap(); + let last_field_ty = &last_field.ty; + predicates.push(syn::parse_quote! { + #first_field_ty: crate::loc::Span + }); + predicates.push(syn::parse_quote! { + #last_field_ty: crate::loc::Span + }); + let span = quote::quote! { + impl #impl_generics crate::loc::Span for #name #ty_generics + where + #predicates + { + fn span_start(&self) -> crate::Position { + self.#first_field_name.span_start() + } + fn span_end(&self) -> crate::Position { + self.#last_field_name.span_end() + } + fn span(&self) -> crate::Span { + crate::Span { + start: self.span_start(), + end: self.span_end(), + } + } + } + }; + + Ok(span) +} diff --git a/structure/opslang-ast/macro/src/lib.rs b/structure/opslang-ast/macro/src/lib.rs new file mode 100644 index 0000000..f8c5415 --- /dev/null +++ b/structure/opslang-ast/macro/src/lib.rs @@ -0,0 +1,161 @@ +mod ast_consistency_check; +mod declare_ast_visitor; +mod derive_map_into_token; +mod derive_position; +mod derive_span; +mod v1_default_type_subst; +mod visitor_impl; + +#[inline] +fn wrap_proc_macro( + input: proc_macro::TokenStream, + f: impl Fn(T) -> syn::Result, +) -> proc_macro::TokenStream { + syn::parse(input) + .and_then(f) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +#[proc_macro_derive(Span)] +pub fn derive_span(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + wrap_proc_macro(input, derive_span::derive_span) +} + +#[proc_macro_derive(OrderSpan)] +pub fn derive_order_span(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + wrap_proc_macro(input, derive_span::derive_order_span) +} + +#[proc_macro_derive(Position)] +pub fn derive_position(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + wrap_proc_macro(input, derive_position::derive_position) +} + +#[proc_macro_derive(MapIntoToken)] +pub fn derive_map_into_token(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + wrap_proc_macro(input, derive_map_into_token::derive_map_into_token) +} + +#[proc_macro] +pub fn v1_default_type_subst(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + wrap_proc_macro(input, v1_default_type_subst::v1_default_type_subst) +} + +#[proc_macro] +pub fn v1_default_type_subst_internal(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + wrap_proc_macro(input, v1_default_type_subst::v1_default_type_subst_internal) +} + +/// Generates comprehensive AST visitor implementations for v1 syntax nodes. +/// +/// This procedural macro implements the visitor pattern for AST traversal by generating +/// `Visitor` trait implementations for all v1 AST node types. It enables differential +/// programming where you can provide custom implementations for specific node types while +/// automatically getting default traversal behavior for all others. +/// +/// # Implementation Details +/// +/// The macro generates `Visitor` implementations for every AST node type defined +/// in the v1 syntax. For methods you provide, it uses your custom implementation exactly. +/// For methods you don't provide, it generates default implementations that automatically +/// traverse child nodes. Additionally, your visitor type will implement the `AstVisitor` +/// trait, which provides convenient `visit_*` and `super_*` method pairs. +/// +/// # Syntax +/// +/// ```ignore (illustrative) +/// opslang_ast_macro::v1_ast_visitor_impl!(for YourVisitor { +/// fn visit_some_node(&mut self, node: &SomeNode<'cx>) { +/// // Your custom logic here +/// self.super_some_node(node); // Continue traversal +/// } +/// }); +/// ``` +/// +/// # Method Pairs +/// +/// The `AstVisitor` trait provides two methods for each AST node type: +/// - `visit_*`: Entry point for visiting a node (delegates to `Visitor::visit`) +/// - `super_*`: Default traversal behavior that visits all child nodes +/// +/// This design allows you to easily override specific node handling while preserving +/// automatic traversal of the entire AST structure. +/// +/// # Example +/// +/// ```ignore (illustrative) +/// #[derive(Default)] +/// struct CountingVisitor { +/// function_count: usize, +/// } +/// +/// opslang_ast_macro::v1_ast_visitor_impl!(for CountingVisitor { +/// fn visit_function_def(&mut self, node: &opslang_ast::v1::FunctionDef<'cx>) { +/// self.function_count += 1; +/// self.super_function_def(node); // Continue visiting child nodes +/// } +/// }); +/// ``` +#[proc_macro] +pub fn v1_ast_visitor_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + wrap_proc_macro(input, visitor_impl::visitor_impl) +} + +#[proc_macro_attribute] +pub fn v1_declare_ast_visitor_trait( + _attr: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + wrap_proc_macro(input, declare_ast_visitor::declare_ast_visitor_trait) +} + +/// Generates a compile-time consistency check for AST types registry. +/// +/// This procedural macro verifies that all AST types defined in the centralized registry +/// (`visitor_type_registry.rs`) actually exist and are accessible from the context where this macro is called. +/// The macro is designed to be called from within a v1 child module context to ensure that +/// all registered types can be referenced using `super::` paths. +/// +/// # Purpose +/// +/// The AST types registry in `visitor_type_registry.rs` maintains a list of all AST node types for use by +/// procedural macros, but this registry is independent of the actual type definitions. This +/// creates a potential inconsistency where the registry might reference types that don't exist +/// or have been renamed/moved. +/// +/// # Implementation +/// +/// The macro generates compile-time checks in the form: +/// ```ignore +/// const _: () = { +/// let _: super::Type1<'cx>; +/// let _: super::module::Type2<'cx>; +/// // ... for each registered type +/// }; +/// ``` +/// +/// If any type in the registry doesn't exist or isn't accessible with the expected path, +/// compilation will fail with a clear error message pointing to the problematic type. +/// +/// # Usage +/// +/// This macro should be called from within a child module of `opslang_ast::syntax::v1` +/// to verify type accessibility: +/// +/// ```ignore +/// // In opslang-ast/src/syntax/v1/some_child_module.rs +/// opslang_ast_macro::ast_consistency_check!(); +/// ``` +/// +/// # Guarantees +/// +/// Successful compilation of this macro ensures: +/// 1. All types in the AST registry exist +/// 2. All types are accessible from v1 child module context using `super::` paths +/// 3. All types accept the expected lifetime parameter `'cx` +/// 4. The registry is consistent with actual type definitions +#[proc_macro] +pub fn ast_consistency_check(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { + ast_consistency_check::ast_consistency_check().into() +} diff --git a/structure/opslang-ast/macro/src/v1_default_type_subst.rs b/structure/opslang-ast/macro/src/v1_default_type_subst.rs new file mode 100644 index 0000000..06d8fd3 --- /dev/null +++ b/structure/opslang-ast/macro/src/v1_default_type_subst.rs @@ -0,0 +1,160 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::{Ident, Token, Type, parse::Parse}; + +pub struct TypeSubstitution { + overrides: Vec, + #[allow(dead_code)] + has_default: bool, +} + +struct TypeOverride { + name: Ident, + ty: Type, +} + +impl Parse for TypeSubstitution { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let mut overrides = Vec::new(); + let mut has_default = false; + + while !input.is_empty() { + if input.peek(Token![..]) { + input.parse::()?; + has_default = true; + break; + } + + let name: Ident = input.parse()?; + input.parse::()?; + let ty: Type = input.parse()?; + + // Optional comma + if input.peek(Token![,]) { + input.parse::()?; + } + + overrides.push(TypeOverride { name, ty }); + } + + Ok(TypeSubstitution { + overrides, + has_default, + }) + } +} + +/// A macro to define default types in a more Rust-like syntax. +/// +/// This macro accepts type definitions like `type Span = syntax::v1::Span;` +/// and converts them to a list of (name, path) tuples using `stringify!`. +/// Uses a dummy trait to ensure proper call_site for tokens. +macro_rules! define_default_types { + ($(type $name:ident = $path:ty;)*) => {{ + { + trait __DummyTypesForCallSite { + $(type $name;)* + } + &[ + $((stringify!($name), stringify!($path)),)* + ] + } + }}; +} + +/// Default type definitions for the v1 syntax. +/// +/// This matches the structure of the original `v1_default_type_subst!` macro. +/// The order must match the order in the original macro. +const DEFAULT_TYPES: &[(&str, &str)] = define_default_types! { + type Span = syn::Span; + type Position = syn::Position; + type Comment = &'cx syn::Comment<'cx, Self>; + type ToplevelItem = syn::ToplevelItem<'cx, Self>; + type Row = &'cx syn::Row<'cx, Self>; + type Statement = syn::Statement<'cx, Self>; + type Block = &'cx syn::Block<'cx, Self>; + type Scope = syn::Scope<'cx, Self>; + type ReturnStmt = syn::ReturnStmt<'cx, Self>; + type Ident = syn::Ident<'cx, Self>; + type Path = syn::Path<'cx, Self>; + type Ty = syn::Path<'cx, Self>; + type FnReturnTy = syn::FnReturnTy<'cx, Self>; + type Expr = syn::Expr<'cx, Self>; + type Exprs = &'cx [syn::Expr<'cx, Self>]; + type Qualif = syn::Qualif<'cx, Self>; + type PreQualified = syn::PreQualified<'cx, Self>; + type Parened = syn::Parened<'cx, Self>; + type Literal = syn::Literal<'cx, Self>; + type FilePath = syn::Literal<'cx, Self>; + type ImportedPath = syn::Path<'cx, Self>; + type Array = syn::literal::Array<'cx, Self>; + type String = syn::literal::String<'cx, Self>; + type Bytes = syn::literal::Bytes<'cx, Self>; + type HexBytes = syn::literal::HexBytes<'cx, Self>; + type DateTime = syn::literal::DateTime<'cx, Self>; + type Numeric = syn::literal::Numeric<'cx, Self>; + type Apply = syn::Apply<'cx, Self>; + type Unary = syn::Unary<'cx, Self>; + type Binary = syn::Binary<'cx, Self>; + type BinOp = syn::BinOp<'cx, Self>; + type Compare = syn::Compare<'cx, Self>; + type Set = syn::Set<'cx, Self>; + type Cast = syn::Cast<'cx, Self>; + type InfixImport = syn::InfixImport<'cx, Self>; + type If = syn::If<'cx, Self>; + type Call = syn::Call<'cx, Self>; + type Wait = syn::Wait<'cx, Self>; + type Select = syn::Select<'cx, Self>; + type SelectItems = &'cx [syn::SelectItem<'cx, Self>]; + type FunctionDef = syn::FunctionDef<'cx, Self>; + type ConstantDef = syn::ConstantDef<'cx, Self>; +}; + +/// Generate type definitions for use within the opslang-ast crate itself. +pub fn v1_default_type_subst_internal(input: TypeSubstitution) -> Result { + generate_type_subst(input, "crate") +} + +/// Generate type definitions for use in external crates. +pub fn v1_default_type_subst(input: TypeSubstitution) -> Result { + generate_type_subst(input, "::opslang_ast") +} + +fn generate_type_subst( + substitution: TypeSubstitution, + crate_prefix: &str, +) -> Result { + let mut type_definitions = Vec::new(); + + for (name, default_type_path) in DEFAULT_TYPES { + let name_ident = syn::parse_str::(name)?; + + // Check if this type is overridden + if let Some(override_type) = substitution.overrides.iter().find(|o| o.name == name_ident) { + let name = &override_type.name; + let ty = &override_type.ty; + type_definitions.push(quote! { + type #name = #ty; + }); + } else { + // Replace relative paths with absolute paths + let full_type_path = + default_type_path.replace("syn::", &format!("{crate_prefix}::syntax::v1::")); + let default_type_tokens: TokenStream = + syn::parse_str(&full_type_path).map_err(|e| { + syn::Error::new_spanned( + &name_ident, + format!("Failed to parse default type `{full_type_path}`: {e}"), + ) + })?; + type_definitions.push(quote! { + type #name_ident = #default_type_tokens; + }); + } + } + + Ok(quote! { + #(#type_definitions)* + }) +} diff --git a/structure/opslang-ast/macro/src/visitor_impl.rs b/structure/opslang-ast/macro/src/visitor_impl.rs new file mode 100644 index 0000000..1450b3d --- /dev/null +++ b/structure/opslang-ast/macro/src/visitor_impl.rs @@ -0,0 +1,84 @@ +use opslang_type_registry::v1::ast::types::{AstInterTy, AstNodeTy}; +use opslang_visitor_macro_helper::{CallsiteTraitName, no_intermediate_helper}; + +/// Generates visitor implementation for AST types. +/// +/// # Design Note +/// +/// **You should rarely need to modify this function.** Most visitor changes happen in +/// [`visitor_type_registry.rs`](./visitor_type_registry.rs) by updating the type registries. This function +/// mechanically converts the registered types into visitor trait implementations. +pub fn visitor_impl( + input: opslang_visitor_macro_helper::VisitorImpl, +) -> Result { + // Get all AST types for v1 syntax + let ast_node_types = AstNodeTy::get_v1_ast_node_types(); + + // Convert AST types to VisitorType format with 'cx lifetime + // Generate both Visit and VisitMut implementations for each type + let visitor_types = ast_node_types + .map(|ast_type| { + let crate_qualified = ast_type.outside_of_ast_crate(); + let path = crate_qualified.full_crate_path(); + let visit_method_name = ast_type + .generate_visit_method_name(opslang_visitor_macro_helper::MethodKind::Visit); + + // Generate Visit version + opslang_visitor_macro_helper::VisitorType { + generics: syn::parse_quote!(<'cx>), + path, + visit_method_name, + mode: opslang_visitor_macro_helper::VisitorMode::Visit, + } + }) + .collect(); + + // Generate intermediate implementations for generic types like &[T], Option, etc. + let additional_impls = generate_intermediate_visitor_impls(&input); + + let callsite_trait = CallsiteTraitName::visitor_only(syn::parse_quote!( + ::opslang_ast::syntax::v1::visit::AstVisitor + )); + let main_expanded = + opslang_visitor_macro_helper::generate_visitor_impl(input, callsite_trait, visitor_types)?; + + Ok(quote::quote! { + #main_expanded + #additional_impls + }) +} + +/// Generate intermediate visitor implementations for generic types like `&[T]`, `Option`. +fn generate_intermediate_visitor_impls( + visitor_impl: &opslang_visitor_macro_helper::VisitorImpl, +) -> proc_macro2::TokenStream { + use quote::quote; + + let impl_type = &visitor_impl.impl_type; + let impl_generics = &visitor_impl.impl_generics; + + // Add 'cx lifetime to existing generics + let updated_generics = no_intermediate_helper::update_generics(impl_generics, |g| { + g.params.push(syn::parse_quote!('cx)); + }); + + // Generate generic implementations + let generic_impls = + no_intermediate_helper::generate_generic_visitor_impls(&updated_generics, impl_type); + + let (updated_impl_generics, _, updated_where_clause) = updated_generics.split_for_impl(); + + let specific_impls = AstInterTy::get_v1_ast_node_types().map(|ty| { + let outside = ty.outside_of_ast_crate(); + let ty = outside.full_path(); + let ty = &ty; + quote! { + ::opslang_visitor::impl_visitor!(#updated_impl_generics #impl_type [visit] #ty #updated_where_clause); + } + }); + + quote! { + #generic_impls + #(#specific_impls)* + } +} diff --git a/structure/opslang-ast/src/lib.rs b/structure/opslang-ast/src/lib.rs new file mode 100644 index 0000000..64341bd --- /dev/null +++ b/structure/opslang-ast/src/lib.rs @@ -0,0 +1,4 @@ +pub mod syntax; +pub mod version; + +pub use syntax::*; diff --git a/structure/opslang-ast/src/syntax.rs b/structure/opslang-ast/src/syntax.rs new file mode 100644 index 0000000..2c255a1 --- /dev/null +++ b/structure/opslang-ast/src/syntax.rs @@ -0,0 +1,47 @@ +//! type definition of AST. + +macro_rules! declare_versions { + () => {}; + ($([$current:vis])? $path:ident, $ty:ident; $($tt:tt)*) => { + pub mod $path; + pub struct $ty; + impl $crate::version::sealed::Sealed for $ty {} + impl $crate::version::VersionMarker for $ty { + fn version() -> &'static str { + stringify!($path) + } + } + + $( + /// Type alias for the default version of the ast. + $current type Default = $ty; + $current use $path::*; + )? + + declare_versions! { $($tt)* } + } +} + +declare_versions! { + v0, V0; + [pub] v1, V1; +} + +macro_rules! type_exists { + () => {}; + ($name:path ; $($rest:tt)*) => { + /// Assertion that the given type exists. + /// + /// This is a compile-time check that will fail if the type is not defined. + const _: () = { + let _: $name; + }; + + type_exists! { $($rest)* } + }; +} + +type_exists! { + V0; V1; + Default; +} diff --git a/opslang-ast/src/lib.rs b/structure/opslang-ast/src/syntax/v0.rs similarity index 99% rename from opslang-ast/src/lib.rs rename to structure/opslang-ast/src/syntax/v0.rs index a20b44e..df8b089 100644 --- a/opslang-ast/src/lib.rs +++ b/structure/opslang-ast/src/syntax/v0.rs @@ -1,5 +1,3 @@ -//! type definition of AST. - use chrono::{DateTime, Utc}; use std::ops::Range; diff --git a/structure/opslang-ast/src/syntax/v1.rs b/structure/opslang-ast/src/syntax/v1.rs new file mode 100644 index 0000000..2b0594b --- /dev/null +++ b/structure/opslang-ast/src/syntax/v1.rs @@ -0,0 +1,611 @@ +/*! +AST for opslang v1. + +This module defines the AST structures for opslang v1 syntax. The AST is designed to be +generic over a type family to support different contexts (parsing vs analysis). + +**IMPORTANT**: When modifying type structures in this module, update visitor type +registries to ensure proper visitor macro generation: +- `opslang-ast-macro/src/visitor_type_registry.rs` for AST visitors +- `opslang-ir-macro/src/visitor_type_registry.rs` for IR visitors + +Choose whether to make types hookable (add to node types) or not hookable (add to inter types). +*/ + +use std::fmt::Debug; + +pub use family::TypeFamily; +use opslang_ast_macro::OrderSpan; +use opslang_visitor_macro::Visit; + +pub mod ast_consistency_check; +pub mod context; +pub mod family; +pub mod loc; +pub mod token; +pub mod visit; + +pub mod constructors; +pub mod impls; + +impl Versioned for Program<'_, DefaultTypeFamily> { + type Version = V1; +} + +#[derive(Debug, PartialEq, Clone, Copy, Default, Visit)] +#[skip_all_visit] +/// Default value for each types in this crate, to allow this crate define an AST. +/// +/// This type does not take any lifetime parameters because [`TypeFamily`] trait has them. +pub struct DefaultTypeFamily; + +impl<'cx> TypeFamily<'cx> for DefaultTypeFamily { + opslang_ast_macro::v1_default_type_subst_internal! { + .. + } +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +#[skip_all_visit] +pub struct BytePos(pub u32); +pub type Position = BytePos; + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +#[skip_all_visit] +/// A location in the code. +pub struct Span { + pub start: Position, + pub end: Position, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// An overall program. A program is a sequence of function definitions and constant definitions. +pub struct Program<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub toplevel_items: &'cx [F::ToplevelItem], +} + +/// A top-level item in a program. +/// +/// This represents a single item at the top level of a program, which can be either +/// a definition (function or constant) or just a comment. Items can be empty when +/// they contain only whitespace or empty lines, which is valid in the AST representation. +#[derive(Debug, PartialEq, Visit)] +pub struct ToplevelItem<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub kind: Option>, + pub comment: Option, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A top-level definition in a program. +pub enum DefinitionKind<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + Function(F::FunctionDef), + Constant(F::ConstantDef), +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A function definition with `prc` keyword. +/// +/// # Examples +/// +/// ```ops +/// prc main() { +/// NOP; +/// } +/// prc add(x: i32, y: i32) { +/// return x + y; +/// } +/// ``` +pub struct FunctionDef<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub prc_token: token::Prc<'cx, F>, + pub name: F::Ident, + pub left_paren: token::OpenParen<'cx, F>, + pub parameters: &'cx [Parameter<'cx, F>], + pub right_paren: token::CloseParen<'cx, F>, + pub return_type: F::FnReturnTy, + pub body: F::Block, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A function parameter. +/// +/// # Examples +/// +/// ```ops +/// x: i32 +/// ``` +pub struct Parameter<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub name: F::Ident, + pub colon: token::Colon<'cx, F>, + pub ty: F::Ty, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +pub struct FnReturnTy<'cx, F: TypeFamily<'cx> = DefaultTypeFamily>( + pub Option<(token::Arrow<'cx, F>, F::Path)>, +); + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A constant definition. +/// +/// # Examples +/// +/// ```ops +/// const CONSTANT: i32 = 0; +/// ``` +pub struct ConstantDef<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub const_token: token::Const<'cx, F>, + pub name: F::Ident, + pub colon: token::Colon<'cx, F>, + pub ty: F::Path, + pub eq: token::Eq<'cx, F>, + pub value: F::Expr, + pub semi: token::Semi<'cx, F>, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// Sequence of statements. +pub struct Scope<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub items: &'cx [ScopeItem<'cx, F>], +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A scope item can be a single statement or a block of statements, or a comment. +pub enum ScopeItem<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + Row(F::Row), + Block(F::Block), +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A single row of program with optional comments and breaks. +pub struct Row<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub breaks: Option>, + pub statement: Option, + pub comment: Option, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A comment in a program. +pub struct Comment<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + #[skip_visit] + pub content: &'cx str, + pub span: F::Span, +} + +#[derive(Debug, PartialEq, Visit)] +/// A block of statements with optional comments and a default receiver component. A block can also have a delay. +/// +/// # Examples +/// +/// ```ops +/// { +/// NOP +/// NOP +/// } +/// ``` +pub struct Block<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub left_brace: token::OpenBrace<'cx, F>, + pub scope: F::Scope, + pub right_brace: token::CloseBrace<'cx, F>, +} + +#[derive(Debug, PartialEq, Visit)] +/// A statement kind. +pub enum Statement<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + Let(Let<'cx, F>), + Expr(ExprStatement<'cx, F>), + Return(F::ReturnStmt), +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A let statement. +/// +/// # Examples +/// +/// ```ops +/// let d = 1s +/// ``` +pub struct Let<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub let_token: token::Let<'cx, F>, + pub variable: F::Ident, + pub eq: token::Eq<'cx, F>, + pub rhs: F::Expr, + pub semi: token::Semi<'cx, F>, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A statement kind. +pub struct ExprStatement<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub expr: F::Expr, + pub semi: token::Semi<'cx, F>, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, opslang_ast_macro::MapIntoToken)] +/// A `return` statement. +/// +/// # Examples +/// +/// ```ops +/// return; +/// ``` +pub struct ReturnStmt<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub return_token: token::Return<'cx, F>, + pub semi: token::Semi<'cx, F>, +} + +pub type OwnedExpr<'cx, F = DefaultTypeFamily> = ExprKind<'cx, F>; + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// An expression. +pub enum ExprKind<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + Variable(F::Path), + Literal(F::Literal), + Parened(F::Parened), + Qualif(F::Qualif), + PreQualified(F::PreQualified), + Unary(F::Unary), + Compare(F::Compare), + Binary(F::Binary), + Apply(F::Apply), + Set(F::Set), + Cast(F::Cast), + InfixImport(F::InfixImport), + If(F::If), + Call(F::Call), + Wait(F::Wait), + Select(F::Select), +} + +mod sealed { + #[derive(Clone, Copy)] + pub struct Sealed; +} + +/// A newtyped [`ExprKind`]. Use this type instead of [`ExprKind`] whenever possible. +pub struct Expr<'cx, F: TypeFamily<'cx> = DefaultTypeFamily>( + pub &'cx ExprKind<'cx, F>, + sealed::Sealed, +); + +/// Unused type in Ast, but used in Ir crate. +pub struct ExprMut<'cx, F: TypeFamily<'cx>>(pub &'cx mut ExprKind<'cx, F>, sealed::Sealed); + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +pub struct Path<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub segments: &'cx [F::Ident], +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +pub struct Ident<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + #[skip_visit] + pub raw: &'cx str, + pub span: F::Span, +} + +#[derive(Debug, PartialEq, Visit)] +/// A qualification for a function application. +/// +/// The qualification system enables flexible function argument modification and assignment. +/// This system abstracts argument handling at a higher level than traditional named parameter +/// systems found in languages like OCaml. +/// +/// ## Core Concepts +/// +/// **Modifiers**: Argument specification constructs that allow functions to accept parameters of +/// specific types (numeric or DateTime). Modifiers are provided by modules and enable global +/// abstraction of same-named arguments across different functions. +/// - Syntax: `@TL:20` where `TL` is the modifier name and `:20` is the parameter +/// +/// **Default Modifiers**: Provide unnamed optional arguments that can be applied without explicit +/// parameters, offering a simplified qualification syntax. +/// - Syntax: `~MOBC` where `MOBC` is the default modifier value +/// +/// ## Key Features +/// +/// 1. **Global Argument Abstraction**: Unlike function-specific named parameters, the qualification +/// system provides module-level argument abstraction, allowing the same argument names to be +/// reused across multiple functions. +/// +/// 2. **Flexible Parameter Assignment**: The system facilitates easy argument substitution and +/// modification, making function application more intuitive. +/// +/// 3. **Module-Based Provision**: Modifiers are provided by modules, creating a systematic approach +/// to argument specification across the language ecosystem. +/// +/// ## Example Usage +/// +/// ```ops +/// AOBC.NOP @TL:20 ~MOBC +/// ``` +/// +/// In this example: +/// - `@TL:20` is a `Modifier` with parameter `20` +/// - `~MOBC` is a `DefaultModifier` +/// - Both qualify the function call `AOBC.NOP` +pub enum Qualif<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + Modifier(Modifier<'cx, F>), + DefaultModifier(DefaultModifier<'cx, F>), +} + +#[derive(Debug, PartialEq, Visit)] +/// A modifier for command argument specification. +/// +/// See [`Qualif`] for more information. +/// +/// # Examples +/// +/// - `@TL:20` in `AOBC.NOP @TL:20 ~MOBC`. +pub struct Modifier<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub at_token: token::Atmark<'cx, F>, + pub id: F::Path, + pub arg: Option>, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A parameter for a command modifier. +/// +/// See [`Qualif`] for more information. +/// +/// # Examples +/// +/// - `:20` in `@TL:20`. +pub struct ModifierParam<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub colon_token: token::Colon<'cx, F>, + pub value: F::Expr, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A default modifier for command without explicit parameters. +/// +/// See [`Qualif`] for more information. +/// +/// # Examples +/// +/// - `~MOBC` in `AOBC.NOP @TL:20 ~MOBC`. +pub struct DefaultModifier<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub tilde_token: token::Tilde<'cx, F>, + pub value: F::Path, +} + +pub use literal::*; + +use crate::{V1, version::Versioned}; + +pub mod literal { + use super::*; + + #[derive(Debug, PartialEq, Clone, Copy, Visit)] + pub enum Literal<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + Array(F::Array), + String(F::String), + Bytes(F::Bytes), + HexBytes(F::HexBytes), + Numeric(F::Numeric), + DateTime(F::DateTime), + } + + #[derive(Debug, PartialEq, Clone, Copy, Visit)] + pub struct Array<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub left_bracket: token::OpenSquare<'cx, F>, + pub exprs: F::Exprs, + pub right_bracket: token::CloseSquare<'cx, F>, + } + + #[derive(Debug, PartialEq, Clone, Copy, Visit)] + pub struct String<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + #[skip_visit] + pub raw: &'cx str, + pub span: F::Span, + } + + #[derive(Debug, PartialEq, Clone, Copy, Visit)] + pub struct Bytes<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + #[skip_visit] + pub raw: &'cx str, + pub span: F::Span, + } + + #[derive(Debug, PartialEq, Clone, Copy, Visit)] + pub struct HexBytes<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + #[skip_visit] + pub raw: &'cx str, + pub span: F::Span, + } + + #[derive(Debug, PartialEq, Clone, Copy, Visit)] + pub struct Numeric<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + #[skip_visit] + /// The raw string representation of the numeric value, without any prefix or suffix. + pub raw: &'cx str, + + pub kind: NumericKind, + pub suffix: Option>, + } + + #[derive(Debug, PartialEq, Clone, Copy, Visit)] + #[skip_all_visit] + pub enum NumericKind { + Integer(IntegerPrefix), + Float, + } + + #[derive(Debug, PartialEq, Clone, Copy, Visit)] + /// Suffix of numeral value. Allows any ident at this point. + pub struct NumericSuffix<'cx, F: TypeFamily<'cx> = DefaultTypeFamily>(pub F::Ident); + + #[derive(Debug, PartialEq, Clone, Copy)] + pub enum IntegerPrefix { + /// `0x` + Hexadecimal, + + /// `0o` + Octal, + + /// `0b` + Binary, + + None, + } + + #[derive(Debug, PartialEq, Clone, Copy, Visit)] + /// A date-time value. + pub struct DateTime<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + #[skip_visit] + pub raw: &'cx str, + pub span: F::Span, + } +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +pub struct Parened<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub left_paren: token::OpenParen<'cx, F>, + pub expr: F::Expr, + pub right_paren: token::CloseParen<'cx, F>, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +pub struct PreQualified<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub qualifs: &'cx [F::Qualif], + pub expr: F::Expr, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +pub struct Unary<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub op: UnOp<'cx, F>, + pub expr: F::Expr, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, opslang_ast_macro::MapIntoToken)] +pub enum UnOp<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + /// Negates an expression. + Neg(token::Hyphen<'cx, F>), + + /// Create a reference of an expression. + /// + /// This is a temporal solution for accepting the old `tlmid!` functionality. + IdRef(token::Ampersand<'cx, F>), + + Deref(token::Dollar<'cx, F>), +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +pub struct Compare<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub head: F::Expr, + pub tail_with_op: &'cx [CompareOpExpr<'cx, F>], +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +pub struct CompareOpExpr<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub op: CompareOp<'cx, F>, + pub val: F::Expr, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, opslang_ast_macro::MapIntoToken)] +pub enum CompareOp<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + GreaterEq(token::RightAngleEq<'cx, F>), + LessEq(token::AngleEq<'cx, F>), + Greater(token::RightAngle<'cx, F>), + Less(token::Angle<'cx, F>), + NotEqual(NotEqualToken<'cx, F>), + Equal(token::EqualEqual<'cx, F>), +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, opslang_ast_macro::MapIntoToken)] +pub enum NotEqualToken<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + /// `!=` + BangEqual(token::BangEqual<'cx, F>), + /// `/=` + SlashEqual(token::SlashEqual<'cx, F>), +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +pub struct Binary<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub lhs: F::Expr, + pub op: F::BinOp, + pub rhs: F::Expr, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, opslang_ast_macro::MapIntoToken)] +pub enum BinOp<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + /// `&&` + And(token::AndAnd<'cx, F>), + /// `||` + Or(token::OrOr<'cx, F>), + /// `*` + Mul(token::Star<'cx, F>), + /// `/` + Div(token::Slash<'cx, F>), + /// `%` + Mod(token::Percent<'cx, F>), + /// `+` + Add(token::Plus<'cx, F>), + /// `-` + Sub(token::Hyphen<'cx, F>), +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +pub struct Apply<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub function: F::Expr, + pub args: &'cx [F::Expr], +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, OrderSpan)] +pub struct Set<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub lhs: F::Expr, + pub colon_eq: token::ColonEq<'cx, F>, + pub rhs: F::Expr, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, OrderSpan)] +pub struct Cast<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub expr: F::Expr, + pub as_kw: token::As<'cx, F>, + pub ty: F::Ty, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, OrderSpan)] +pub struct InfixImport<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub file: F::FilePath, + pub question: token::Question<'cx, F>, + pub path: F::ImportedPath, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, OrderSpan)] +pub struct If<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub if_kw: token::If<'cx, F>, + pub cond: F::Expr, + pub then_clause: F::Block, + pub else_opt: Option>, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, OrderSpan)] +pub struct IfElse<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub else_kw: token::Else<'cx, F>, + pub else_clause: F::Block, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, OrderSpan)] +pub struct Call<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub call_kw: token::Call<'cx, F>, + pub expr: F::Expr, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, OrderSpan)] +pub struct Wait<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub wait_kw: token::Wait<'cx, F>, + pub expr: F::Expr, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, OrderSpan)] +pub struct Select<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub select_kw: token::Select<'cx, F>, + pub left_brace: token::OpenBrace<'cx, F>, + pub items: F::SelectItems, + pub right_brace: token::CloseBrace<'cx, F>, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit, OrderSpan)] +pub struct SelectItem<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + pub expr: F::Expr, + pub arrow: token::DoubleArrow<'cx, F>, + pub body: F::Block, +} diff --git a/structure/opslang-ast/src/syntax/v1/ast_consistency_check.rs b/structure/opslang-ast/src/syntax/v1/ast_consistency_check.rs new file mode 100644 index 0000000..5667131 --- /dev/null +++ b/structure/opslang-ast/src/syntax/v1/ast_consistency_check.rs @@ -0,0 +1,48 @@ +//! Compile-time consistency check for AST types registry. +//! +//! This module performs a compile-time verification that all AST types defined in the +//! centralized registry (`opslang_ast_macro::visitor_type_registry`) actually exist and are accessible +//! from this v1 child module context using `super::` paths. +//! +//! # Purpose +//! +//! The AST types registry in `opslang-ast-macro/src/visitor_type_registry.rs` maintains a comprehensive +//! list of all AST node types for use by procedural macros. However, this registry is +//! independent of the actual type definitions in `opslang-ast/src/syntax/v1.rs`, creating +//! a potential source of inconsistency. +//! +//! This design weakness cannot be avoided due to architectural constraints, but this +//! compile-time check helps detect inconsistencies early through compilation errors +//! and comments that guide developers when types are added, removed, or renamed. +//! +//! # Implementation +//! +//! The macro call below generates compile-time type checks in the form: +//! ```ignore +//! const _: () = { +//! let _: super::Program<'cx>; +//! let _: super::ToplevelItem<'cx>; +//! let _: super::token::Semi<'cx>; +//! // ... for each type in the registry +//! }; +//! ``` +//! +//! # Guarantees +//! +//! Successful compilation of this module ensures: +//! 1. **Type Existence**: All types in the AST registry actually exist in the codebase +//! 2. **Path Accessibility**: All types are accessible from v1 child module context using `super::` paths +//! 3. **Lifetime Compatibility**: All types accept the expected lifetime parameter `'cx` +//! 4. **Registry Consistency**: The centralized type registry matches the actual type definitions +//! +//! # Maintenance +//! +//! When adding, removing, or renaming AST types: +//! 1. Update the actual type definitions in `v1.rs` and related files +//! 2. Update the registry in `opslang-ast-macro/src/visitor_type_registry.rs` +//! 3. Ensure this compilation check continues to pass +//! +//! If this check fails, it indicates a mismatch between the registry and actual definitions +//! that must be resolved to maintain consistency across the codebase. + +opslang_ast_macro::ast_consistency_check!(); diff --git a/structure/opslang-ast/src/syntax/v1/constructors.rs b/structure/opslang-ast/src/syntax/v1/constructors.rs new file mode 100644 index 0000000..a97e63d --- /dev/null +++ b/structure/opslang-ast/src/syntax/v1/constructors.rs @@ -0,0 +1,472 @@ +use super::{ + Apply, Array, Binary, Bytes, Cast, Compare, CompareOp, CompareOpExpr, DateTime, Expr, ExprKind, + ExprMut, HexBytes, Ident, If, IfElse, InfixImport, IntegerPrefix, Literal, Numeric, + NumericKind, NumericSuffix, Parened, Path, PreQualified, Row, Select, Set, String, + ToplevelItem, TypeFamily, UnOp, Unary, Wait, context, token, +}; + +impl<'cx, F: TypeFamily<'cx>> Default for ToplevelItem<'cx, F> { + fn default() -> Self { + Self { + kind: Default::default(), + comment: Default::default(), + } + } +} + +impl<'cx, F: TypeFamily<'cx>> Default for Row<'cx, F> { + fn default() -> Self { + Self { + breaks: Default::default(), + statement: Default::default(), + comment: Default::default(), + } + } +} + +impl<'cx, F: TypeFamily<'cx>> Expr<'cx, F> { + #[inline] + pub fn from_kind(ctx: &'cx context::Context<'cx, F>, kind: ExprKind<'cx, F>) -> Self { + ctx.alloc_expr(kind) + } +} + +impl<'cx, F: TypeFamily<'cx>> ExprMut<'cx, F> { + #[inline] + pub fn from_kind(ctx: &'cx context::Context<'cx, F>, kind: ExprKind<'cx, F>) -> Self { + ctx.alloc_expr_mut(kind) + } +} + +/// dupricates impl content into two impls. +macro_rules! impl_expr_and_expr_mut { + ($($tt:tt)*) => { + impl<'cx, F: TypeFamily<'cx>> Expr<'cx, F> { + $($tt)* + } + impl<'cx, F: TypeFamily<'cx>> ExprMut<'cx, F> { + $($tt)* + } + }; +} + +impl_expr_and_expr_mut! { + #[inline] + pub fn ident(ctx: &'cx context::Context<'cx, F>, name: &str, span: F::Span) -> Self + where + F: TypeFamily<'cx, Path = Path<'cx, F>, Ident = Ident<'cx, F>>, + { + Self::variable(ctx, Path::single(ctx, name, span)) + } + + #[inline] + pub fn variable(ctx: &'cx context::Context<'cx, F>, path: F::Path) -> Self { + Self::from_kind(ctx, ExprKind::Variable(path)) + } + + #[inline] + pub fn literal(ctx: &'cx context::Context<'cx, F>, literal: F::Literal) -> Self { + Self::from_kind(ctx, ExprKind::Literal(literal)) + } + + #[inline] + pub fn parened( + ctx: &'cx context::Context<'cx, F>, + left_paren: token::OpenParen<'cx, F>, + expr: F::Expr, + right_paren: token::CloseParen<'cx, F>, + ) -> Self + where + F: TypeFamily<'cx, Parened = Parened<'cx, F>>, + { + let parened = Parened { + left_paren, + expr, + right_paren, + }; + Self::from_kind(ctx, ExprKind::Parened(parened)) + } + + #[inline] + pub fn apply(ctx: &'cx context::Context<'cx, F>, function: F::Expr, args: Vec) -> Self + where + F: TypeFamily<'cx, Apply = Apply<'cx, F>>, + { + let apply = Apply { + function, + args: ctx.alloc_expr_slice(args), + }; + Self::from_kind(ctx, ExprKind::Apply(apply)) + } + + #[inline] + pub fn binary( + ctx: &'cx context::Context<'cx, F>, + lhs: F::Expr, + op: F::BinOp, + rhs: F::Expr, + ) -> Self + where + F: TypeFamily<'cx, Binary = Binary<'cx, F>>, + { + let binary = Binary { lhs, op, rhs }; + Self::from_kind(ctx, ExprKind::Binary(binary)) + } + + #[inline] + pub fn unary(ctx: &'cx context::Context<'cx, F>, op: UnOp<'cx, F>, expr: F::Expr) -> Self + where + F: TypeFamily<'cx, Unary = Unary<'cx, F>>, + { + let unary = Unary { op, expr }; + Self::from_kind(ctx, ExprKind::Unary(unary)) + } + + #[inline] + pub fn compare( + ctx: &'cx context::Context<'cx, F>, + head: F::Expr, + tail_with_op: Vec>, + ) -> Self + where + F: TypeFamily<'cx, Compare = Compare<'cx, F>>, + { + let compare = Compare { + head, + tail_with_op: ctx.alloc_compare_op_expr_tuple_slice(tail_with_op), + }; + Self::from_kind(ctx, ExprKind::Compare(compare)) + } + + #[inline] + pub fn compare_single( + ctx: &'cx context::Context<'cx, F>, + lhs: F::Expr, + op: CompareOp<'cx, F>, + rhs: F::Expr, + ) -> Self + where + F: TypeFamily<'cx, Compare = Compare<'cx, F>>, + { + Self::compare(ctx, lhs, vec![CompareOpExpr { op, val: rhs }]) + } + + #[inline] + pub fn set( + ctx: &'cx context::Context<'cx, F>, + lhs: F::Expr, + colon_eq: token::ColonEq<'cx, F>, + rhs: F::Expr, + ) -> Self + where + F: TypeFamily<'cx, Set = Set<'cx, F>>, + { + let set = Set { lhs, colon_eq, rhs }; + Self::from_kind(ctx, ExprKind::Set(set)) + } + + #[inline] + pub fn cast( + ctx: &'cx context::Context<'cx, F>, + expr: F::Expr, + as_kw: token::As<'cx, F>, + ty: F::Ty, + ) -> Self + where + F: TypeFamily<'cx, Cast = Cast<'cx, F>>, + { + let cast = Cast { expr, as_kw, ty }; + Self::from_kind(ctx, ExprKind::Cast(cast)) + } + + #[inline] + pub fn import( + ctx: &'cx context::Context<'cx, F>, + file: F::FilePath, + question: token::Question<'cx, F>, + path: F::ImportedPath, + ) -> Self + where + F: TypeFamily<'cx, InfixImport = InfixImport<'cx, F>>, + { + let import = InfixImport { + file, + question, + path, + }; + Self::from_kind(ctx, ExprKind::InfixImport(import)) + } + + #[inline] + pub fn if_then_else( + ctx: &'cx context::Context<'cx, F>, + if_kw: token::If<'cx, F>, + cond: F::Expr, + then_clause: F::Block, + else_kw: token::Else<'cx, F>, + else_clause: F::Block, + ) -> Self + where + F: TypeFamily<'cx, If = If<'cx, F>>, + { + let if_expr = If { + if_kw, + cond, + then_clause, + else_opt: Some(IfElse { + else_kw, + else_clause, + }), + }; + Self::from_kind(ctx, ExprKind::If(if_expr)) + } + #[inline] + pub fn if_then( + ctx: &'cx context::Context<'cx, F>, + if_kw: token::If<'cx, F>, + cond: F::Expr, + then_clause: F::Block, + ) -> Self + where + F: TypeFamily<'cx, If = If<'cx, F>>, + { + let if_expr = If { + if_kw, + cond, + then_clause, + else_opt: None, + }; + Self::from_kind(ctx, ExprKind::If(if_expr)) + } + #[inline] + pub fn if_expr( + ctx: &'cx context::Context<'cx, F>, + if_kw: token::If<'cx, F>, + cond: F::Expr, + then_clause: F::Block, + else_opt: Option>, + ) -> Self + where + F: TypeFamily<'cx, If = If<'cx, F>>, + { + let if_expr = If { + if_kw, + cond, + then_clause, + else_opt, + }; + Self::from_kind(ctx, ExprKind::If(if_expr)) + } + + #[inline] + pub fn wait( + ctx: &'cx context::Context<'cx, F>, + wait_kw: token::Wait<'cx, F>, + expr: F::Expr, + ) -> Self + where + F: TypeFamily<'cx, Wait = Wait<'cx, F>>, + { + let wait = Wait { wait_kw, expr }; + Self::from_kind(ctx, ExprKind::Wait(wait)) + } + + #[inline] + pub fn select( + ctx: &'cx context::Context<'cx, F>, + select_kw: token::Select<'cx, F>, + left_brace: token::OpenBrace<'cx, F>, + items: F::SelectItems, + right_brace: token::CloseBrace<'cx, F>, + ) -> Self + where + F: TypeFamily<'cx, Select = Select<'cx, F>>, + { + let select = Select { + select_kw, + left_brace, + items, + right_brace, + }; + Self::from_kind(ctx, ExprKind::Select(select)) + } + + #[inline] + pub fn qualif(ctx: &'cx context::Context<'cx, F>, qualif: F::Qualif) -> Self { + Self::from_kind(ctx, ExprKind::Qualif(qualif)) + } + + #[inline] + pub fn pre_qualified( + ctx: &'cx context::Context<'cx, F>, + qualifs: Vec, + expr: F::Expr, + ) -> Self + where + F: TypeFamily<'cx, PreQualified = PreQualified<'cx, F>>, + { + let pre_qualified = PreQualified { + qualifs: ctx.alloc_qualif_slice(qualifs), + expr, + }; + Self::from_kind(ctx, ExprKind::PreQualified(pre_qualified)) + } +} + +impl<'cx, F: TypeFamily<'cx>> Path<'cx, F> { + pub fn new(segments: &'cx [F::Ident]) -> Self { + Path { segments } + } + + pub fn single(ctx: &'cx context::Context<'cx, F>, name: &str, span: F::Span) -> Self + where + F: TypeFamily<'cx, Ident = Ident<'cx, F>>, + { + assert!(!name.contains('.')); + let ident = Ident::new(ctx, name, span); + let segments = ctx.alloc_ident_slice(vec![ident]); + Path::new(segments) + } +} + +impl<'cx, F: TypeFamily<'cx>> Ident<'cx, F> { + pub fn new( + ctx: &'cx context::Context<'cx, impl TypeFamily<'cx>>, + name: &str, + span: F::Span, + ) -> Self { + let name_str = ctx.alloc_str(name); + Ident { + raw: name_str, + span, + } + } +} + +impl<'cx, F: TypeFamily<'cx>> Literal<'cx, F> { + pub fn string( + ctx: &'cx crate::syntax::v1::context::Context<'cx, F>, + content: &str, + span: F::Span, + ) -> Self + where + F: TypeFamily<'cx, String = String<'cx, F>>, + { + let string_str = ctx.alloc_str(content); + Literal::String(String { + raw: string_str, + span, + }) + } + + pub fn bytes( + ctx: &'cx crate::syntax::v1::context::Context<'cx, F>, + content: &str, + span: F::Span, + ) -> Self + where + F: TypeFamily<'cx, Bytes = Bytes<'cx, F>>, + { + let bytes_str = ctx.alloc_str(content); + Literal::Bytes(Bytes { + raw: bytes_str, + span, + }) + } + + pub fn hex_bytes( + ctx: &'cx crate::syntax::v1::context::Context<'cx, F>, + content: &str, + span: F::Span, + ) -> Self + where + F: TypeFamily<'cx, HexBytes = HexBytes<'cx, F>>, + { + let hex_str = ctx.alloc_str(content); + Literal::HexBytes(HexBytes { raw: hex_str, span }) + } + + pub fn numeric(numeric: F::Numeric) -> Self + where + F: TypeFamily<'cx, Numeric = Numeric<'cx>>, + { + Literal::Numeric(numeric) + } + + pub fn date_time( + ctx: &'cx crate::syntax::v1::context::Context<'cx, F>, + content: &str, + span: F::Span, + ) -> Self + where + F: TypeFamily<'cx, DateTime = DateTime<'cx, F>>, + { + let date_str = ctx.alloc_str(content); + Literal::DateTime(DateTime { + raw: date_str, + span, + }) + } + + pub fn array( + left_bracket: token::OpenSquare<'cx, F>, + exprs: F::Exprs, + right_bracket: token::CloseSquare<'cx, F>, + ) -> Self + where + F: TypeFamily<'cx, Array = Array<'cx, F>>, + { + Literal::Array(Array { + left_bracket, + exprs, + right_bracket, + }) + } +} + +impl<'cx, F: TypeFamily<'cx>> Numeric<'cx, F> { + #[inline] + pub fn integer( + ctx: &'cx crate::syntax::v1::context::Context<'cx, impl TypeFamily<'cx>>, + raw: &str, + prefix: IntegerPrefix, + suffix: Option>, + ) -> Self { + let raw_str = ctx.alloc_str(raw); + Numeric { + raw: raw_str, + kind: NumericKind::Integer(prefix), + suffix, + } + } + + #[inline] + pub fn float( + ctx: &'cx crate::syntax::v1::context::Context<'cx, F>, + raw: &str, + suffix: Option>, + ) -> Self { + let raw_str = ctx.alloc_str(raw); + Numeric { + raw: raw_str, + kind: NumericKind::Float, + suffix, + } + } + + #[inline] + pub fn suffix( + ctx: &'cx crate::syntax::v1::context::Context<'cx, F>, + name: &str, + span: F::Span, + ) -> NumericSuffix<'cx, F> + where + F: TypeFamily<'cx, Ident = Ident<'cx, F>>, + { + let name_str = ctx.alloc_str(name); + NumericSuffix(Ident { + raw: name_str, + span, + }) + } +} diff --git a/structure/opslang-ast/src/syntax/v1/context.rs b/structure/opslang-ast/src/syntax/v1/context.rs new file mode 100644 index 0000000..1a59052 --- /dev/null +++ b/structure/opslang-ast/src/syntax/v1/context.rs @@ -0,0 +1,140 @@ +use crate::SelectItem; + +use super::{ + Block, Comment, CompareOpExpr, DefaultTypeFamily, Expr, ExprKind, ExprMut, Parameter, Row, + ScopeItem, ToplevelItem, family::TypeFamily, +}; +use typed_arena::Arena; + +/// A context for constructing expressions. +/// +/// This type exists to hold the contents of reference types, which is introduced: +/// - to reduce type size and +/// - to provide uniform lifetimes for mutually recursive types. +pub struct Context<'cx, F: TypeFamily<'cx> = DefaultTypeFamily> { + str_arena: Arena, + expr_arena: Arena>, + row_arena: Arena>, + block_arena: Arena>, + comment_arena: Arena>, + + // Slice arenas for different types + toplevel_slice_arena: Arena>, + parameter_slice_arena: Arena>, + scope_item_slice_arena: Arena>, + expr_slice_arena: Arena, + ident_slice_arena: Arena, + select_item_slice_arena: Arena>, + qualif_slice_arena: Arena, + compare_op_expr_tuple_slice_arena: Arena>, +} + +impl<'cx, F: TypeFamily<'cx>> Context<'cx, F> { + pub fn alloc_str<'any>(&'cx self, string: &'any str) -> &'cx str { + if string.is_empty() { + return ""; + } + self.str_arena.alloc_str(string) + } + pub fn alloc_bytes<'any>(&'cx self, bytes: &'any [u8]) -> &'cx [u8] { + self.str_arena.alloc_extend(bytes.iter().copied()) + } + + pub fn alloc_expr(&'cx self, expr: ExprKind<'cx, F>) -> Expr<'cx, F> { + Expr(self.expr_arena.alloc(expr), super::sealed::Sealed) + } + + pub fn alloc_expr_mut(&'cx self, expr: ExprKind<'cx, F>) -> ExprMut<'cx, F> { + ExprMut(self.expr_arena.alloc(expr), super::sealed::Sealed) + } + + pub fn alloc_row(&'cx self, row: Row<'cx, F>) -> &'cx Row<'cx, F> { + self.row_arena.alloc(row) + } + + pub fn alloc_block(&'cx self, block: Block<'cx, F>) -> &'cx Block<'cx, F> { + self.block_arena.alloc(block) + } + + pub fn alloc_comment(&'cx self, comment: Comment<'cx, F>) -> &'cx Comment<'cx, F> { + self.comment_arena.alloc(comment) + } + + // Slice allocation methods + pub fn alloc_toplevel_item_slice( + &'cx self, + items: impl IntoIterator>, + ) -> &'cx [ToplevelItem<'cx, F>] { + self.toplevel_slice_arena.alloc_extend(items) + } + + pub fn alloc_parameter_slice( + &'cx self, + parameters: impl IntoIterator>, + ) -> &'cx [Parameter<'cx, F>] { + self.parameter_slice_arena.alloc_extend(parameters) + } + + pub fn alloc_scope_item_slice( + &'cx self, + items: impl IntoIterator>, + ) -> &'cx [ScopeItem<'cx, F>] { + self.scope_item_slice_arena.alloc_extend(items) + } + + pub fn alloc_expr_slice(&'cx self, exprs: impl IntoIterator) -> &'cx [F::Expr] { + self.expr_slice_arena.alloc_extend(exprs) + } + + pub fn alloc_ident_slice( + &'cx self, + idents: impl IntoIterator, + ) -> &'cx [F::Ident] { + self.ident_slice_arena.alloc_extend(idents) + } + + pub fn alloc_select_item_slice( + &'cx self, + items: impl IntoIterator>, + ) -> &'cx [SelectItem<'cx, F>] { + self.select_item_slice_arena.alloc_extend(items) + } + + pub fn alloc_qualif_slice( + &'cx self, + qualifs: impl IntoIterator, + ) -> &'cx [F::Qualif] { + self.qualif_slice_arena.alloc_extend(qualifs) + } + + pub fn alloc_compare_op_expr_tuple_slice( + &'cx self, + tuples: impl IntoIterator>, + ) -> &'cx [CompareOpExpr<'cx, F>] { + self.compare_op_expr_tuple_slice_arena.alloc_extend(tuples) + } + + pub fn new() -> Self { + Self { + str_arena: Arena::new(), + expr_arena: Arena::new(), + row_arena: Arena::new(), + block_arena: Arena::new(), + comment_arena: Arena::new(), + toplevel_slice_arena: Arena::new(), + parameter_slice_arena: Arena::new(), + scope_item_slice_arena: Arena::new(), + expr_slice_arena: Arena::new(), + ident_slice_arena: Arena::new(), + select_item_slice_arena: Arena::new(), + qualif_slice_arena: Arena::new(), + compare_op_expr_tuple_slice_arena: Arena::new(), + } + } +} + +impl<'cx, F: TypeFamily<'cx>> Default for Context<'cx, F> { + fn default() -> Self { + Self::new() + } +} diff --git a/structure/opslang-ast/src/syntax/v1/family.rs b/structure/opslang-ast/src/syntax/v1/family.rs new file mode 100644 index 0000000..a435bca --- /dev/null +++ b/structure/opslang-ast/src/syntax/v1/family.rs @@ -0,0 +1,185 @@ +use std::fmt::Debug; + +/// Shorthand for repeating trait constraints with optional documentation. +macro_rules! declare_family { + ($($(#[$attr:meta])* type $ident:ident $(: $tr:ident)?;)*) => { + $( + $(#[$attr])* + type $ident: std::fmt::Debug + PartialEq $(+ $tr)*; + )* + }; +} + +/// Type family that occurs in almost every AST types to allow global type substitution. +/// This pattern is known as "trees that grow" and allows for flexible AST transformations. +/// +/// # Design Overview +/// +/// This trait enables the same AST structure to be used with different concrete types +/// across different phases of compilation (parsing, type checking, IR generation, etc.). +/// Each phase can provide its own TypeFamily implementation with appropriate concrete types. +/// +/// This trait takes a lifetime parameter `'cx` so that all associated types can refer to it +/// uniformly, enabling arena-based memory allocation patterns. +/// +/// # Adding New Types +/// +/// When adding a new associated type to this trait, you **MUST** update all of the following: +/// +/// 1. **Core implementation in `opslang-ast`**: +/// - Add the type to this trait definition +/// - Add corresponding parameter to [`opslang_ast_macro::v1_default_type_subst!`] macro +/// - Add implementation in the macro body to map to concrete type +/// - Update any enums/structs to use `F::YourType` instead of `YourType<'cx, F>` +/// +/// 2. **Printer support in `opslang-printer`**: +/// - Add the type to `PrintableFamily` trait definition +/// - Add the type to `PrintableFamily` implementation (the impl block before the trait) +/// +/// 3. **IR support in `opslang-ir`**: +/// - Add the type to `TypeFamily` implementation (maps to IR version of the type) +/// +/// 4. **Migration support in `opslang-migration`** (if applicable): +/// - Update conversion code if the type is used in v0 to v1 migration +/// +/// # Type Categories +/// +/// The associated types are organized into logical groups: +/// - **Foundational**: `Span`, `Position` - source location information +/// - **Structural**: `Comment`, `Row`, `Block`, etc. - document structure +/// - **Names**: `Ident`, `Path` - identifier and path resolution +/// - **Expressions**: `Expr` and all expression-related types +/// - **Definitions**: Top-level constructs like function and constant definitions +/// +/// [`v1_default_type_subst!`]: opslang_ast_macro::v1_default_type_subst +pub trait TypeFamily<'cx>: Debug + PartialEq + Clone + Copy + Default + 'static { + declare_family! { + // === Foundational Types === + /// Source location span representing a range in the source code (start/end positions). + /// + /// It is useful to implement [`super::token::IntoSpan`] for conversion into this type. + type Span: Copy; + + /// Single source position (line, column) in the source code. + /// + /// It is useful to implement [`super::token::IntoPosition`] for conversion into this type. + type Position: Copy; + + // === Structural Types === + /// Comments attached to AST nodes, preserving documentation and annotations. + type Comment; + + type ToplevelItem; + + type Scope; + + /// A single row/line in the source code. + type Row; + + /// Content of a row, typically containing a statement or expression. + type Statement; + + /// Block of code containing a sequence of scope items (statements, nested blocks). + type Block; + + /// Return statement that yields a value from a function or block. + type ReturnStmt; + + // === Names and Identifiers === + /// Simple identifier used for variable names, function names, etc. + type Ident: Copy; + + /// Path to an identifier, which may include module qualification or scope resolution. + type Path: Copy; + + type Ty; + + type FnReturnTy; + + // === Expression Types === + /// Base expression type representing the main expression enum that contains all expression variants. + type Expr; + + type Exprs; + + /// Literal values including numbers, strings, arrays, and other constant data. + type Literal; + + /// String literal (AST) or resolved local module (IR) file path. + type FilePath; + + /// Imported path representing an item being imported from another local module. + type ImportedPath; + + /// Array literal containing a sequence of expressions. + type Array; + + /// String literal value. + type String; + + /// Byte sequence literal value. + type Bytes; + + /// Hexadecimal byte sequence literal value. + type HexBytes; + + /// Date-time literal value. + type DateTime; + + /// Parenthesized expressions that group sub-expressions and control precedence. + type Parened; + + /// Qualification expressions such as attributes, decorators, and metadata annotations. + type Qualif; + + /// Pre-qualified expressions that have qualifications applied before the main expression. + type PreQualified; + + /// Numeric literal values (integers, floating-point numbers). + type Numeric; + + /// Function application/call expressions that invoke functions with arguments. + type Apply; + + /// Unary operation expression. + type Unary; + + /// Binary operation expression. + type Binary; + + /// Binary operations including arithmetic (+, -, *, /, %), logical (&&, ||), etc. + type BinOp; + + /// Comparison operations including equality (==, !=) and relational (<, >, <=, >=). + type Compare; + + /// Assignment/set operations using the `:=` operator. + type Set; + + type Cast; + + /// Infix import operations that import from a file using the `file?path` syntax. + type InfixImport; + + /// Conditional expressions with if/then/else branching logic. + type If; + + /// Precedure call expression that invokes a procedure with arguments. + type Call; + + /// Async wait expression that awaits the result of an awaitable expression. + type Wait; + + /// Async select expression from multiple awaitable expressions. + type Select; + + type SelectItems; + + // === Definition Types === + /// Function definition declared with `prc` keyword, including parameters and body. + type FunctionDef; + + /// Constant definition declared with `const` keyword, binding a name to a value. + type ConstantDef; + } +} diff --git a/structure/opslang-ast/src/syntax/v1/impls.rs b/structure/opslang-ast/src/syntax/v1/impls.rs new file mode 100644 index 0000000..d9e4177 --- /dev/null +++ b/structure/opslang-ast/src/syntax/v1/impls.rs @@ -0,0 +1,138 @@ +use super::{ + Bytes, Comment, Debug, Expr, ExprKind, ExprMut, HexBytes, Ident, Path, Row, String, + ToplevelItem, TypeFamily, +}; +use std::fmt::Write; + +impl<'cx, F: TypeFamily<'cx>> ToplevelItem<'cx, F> { + pub fn is_empty(&self) -> bool { + let Self { kind, comment } = self; + kind.is_none() && comment.is_none() + } +} + +impl<'cx, F: TypeFamily<'cx>> Row<'cx, F> { + pub fn is_empty(&self) -> bool { + let Self { + breaks, + statement, + comment, + } = self; + breaks.is_none() && statement.is_none() && comment.is_none() + } +} + +impl<'cx, F: TypeFamily<'cx>> Comment<'cx, F> { + #[inline] + pub fn is_meta(&self) -> bool { + self.content.starts_with('!') + } +} + +impl<'cx, F: TypeFamily<'cx>> std::ops::Deref for Expr<'cx, F> { + type Target = &'cx ExprKind<'cx, F>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'cx, F: TypeFamily<'cx>> Debug for Expr<'cx, F> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +impl<'cx, F: TypeFamily<'cx>> PartialEq for Expr<'cx, F> { + fn eq(&self, other: &Self) -> bool { + self.0.eq(other.0) + } +} + +impl<'cx, F: TypeFamily<'cx>> Clone for Expr<'cx, F> { + fn clone(&self) -> Self { + *self + } +} + +impl<'cx, F: TypeFamily<'cx>> Copy for Expr<'cx, F> {} + +impl<'cx, F: TypeFamily<'cx>> std::ops::Deref for ExprMut<'cx, F> { + type Target = ExprKind<'cx, F>; + + fn deref(&self) -> &Self::Target { + self.0 + } +} + +impl<'cx, F: TypeFamily<'cx>> std::ops::DerefMut for ExprMut<'cx, F> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.0 + } +} + +impl<'cx, F: TypeFamily<'cx>> Debug for ExprMut<'cx, F> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +impl<'cx, F: TypeFamily<'cx>> PartialEq for ExprMut<'cx, F> { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } +} + +impl<'cx, F: TypeFamily<'cx>> Path<'cx, F> { + pub fn is_ident(&self) -> Option { + if self.segments.len() == 1 { + Some(self.segments[0]) + } else { + None + } + } +} + +impl<'cx, F: TypeFamily<'cx, Ident = Ident<'cx, F>>> std::fmt::Display for Path<'cx, F> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for (i, segment) in self.segments.iter().enumerate() { + if i > 0 { + f.write_char('.')?; + } + f.write_str(segment.raw)?; + } + Ok(()) + } +} + +impl<'cx, F: TypeFamily<'cx>> std::fmt::Display for Ident<'cx, F> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.raw) + } +} + +impl<'cx, F: TypeFamily<'cx>> String<'cx, F> { + pub fn unescape(&self) -> Result { + escape8259::unescape(self.raw) + } +} + +impl<'cx, F: TypeFamily<'cx>> Bytes<'cx, F> { + pub fn as_bytes(&self) -> &'cx [u8] { + self.raw.as_bytes() + } +} + +impl<'cx, F: TypeFamily<'cx>> HexBytes<'cx, F> { + pub fn as_bytes(&self) -> Result, char> { + self.raw + .chars() + .map(|c| match c { + c @ '0'..='9' => Ok(c as u8 - b'0'), + c @ 'a'..='f' => Ok(c as u8 - b'a' + 10), + c @ 'A'..='F' => Ok(c as u8 - b'A' + 10), + c => Err(c), + }) + .collect() + } +} diff --git a/structure/opslang-ast/src/syntax/v1/loc.rs b/structure/opslang-ast/src/syntax/v1/loc.rs new file mode 100644 index 0000000..b25b1b8 --- /dev/null +++ b/structure/opslang-ast/src/syntax/v1/loc.rs @@ -0,0 +1,73 @@ +//! Extension traits for `opslang_ast` types. + +use super::family::TypeFamily; + +pub trait Span { + fn span(&self) -> super::Span; + + fn span_start(&self) -> super::Position { + self.span().start + } + + fn span_end(&self) -> super::Position { + self.span().end + } +} + +#[diagnostic::do_not_recommend] +impl Span for super::Span { + fn span(&self) -> super::Span { + *self + } +} + +pub trait Position { + fn position(&self) -> super::Position; +} + +#[diagnostic::do_not_recommend] +impl Position for super::Position { + fn position(&self) -> super::Position { + *self + } +} + +#[diagnostic::do_not_recommend] +impl Span for T { + fn span(&self) -> super::Span { + super::Span { + start: self.position(), + end: self.position(), + } + } + + fn span_start(&self) -> super::Position { + self.position() + } + + fn span_end(&self) -> super::Position { + self.position() + } +} + +impl<'cx, F: TypeFamily<'cx, Span: Span>> Span for super::Comment<'cx, F> { + fn span(&self) -> super::Span { + self.span.span() + } +} + +impl Span for super::Ident<'_> { + fn span(&self) -> super::Span { + self.span + } +} + +impl Position for super::UnOp<'_> { + fn position(&self) -> super::Position { + match self { + super::UnOp::Neg(hyphen) => hyphen.position, + super::UnOp::IdRef(ampersand) => ampersand.position, + super::UnOp::Deref(dollar) => dollar.position, + } + } +} diff --git a/structure/opslang-ast/src/syntax/v1/token.rs b/structure/opslang-ast/src/syntax/v1/token.rs new file mode 100644 index 0000000..3a0304d --- /dev/null +++ b/structure/opslang-ast/src/syntax/v1/token.rs @@ -0,0 +1,322 @@ +//! Token and keyword definitions +//! +//! This module has three responsibilities: +//! - token definitions via `declare_token!` macro, +//! - keyword definitions via `declare_kw!` macro, +//! - public type macro `V1Token!` for converting embedded tokens to types. +use super::{Position, Span}; + +pub trait Token { + /// Source code representation of this token. + const REPR: &'static str; +} +impl Token for &T { + const REPR: &'static str = T::REPR; +} + +pub trait IntoSpan<'cx, F: super::family::TypeFamily<'cx> = super::DefaultTypeFamily> { + fn into_span(self) -> F::Span; +} + +pub trait IntoPosition<'cx, F: super::family::TypeFamily<'cx> = super::DefaultTypeFamily> { + fn into_position(self) -> F::Position; +} + +/// Re-defined version of [`Into`], which does not have `impl Into for T`. +pub trait IntoToken: Sized { + /// Token lowering. + /// + /// Performs conversion between different AST substitutions, typically from AST into IR. + fn into_token(self) -> T; +} + +/// Declares all tokens for v1 grammar. +macro_rules! declare_token { + ($(pub struct $name:ident/$lit:tt $str:literal)*) => { + $( + token_define_if_1!($name/$lit); + token_define_if_many!($name/$lit); + + impl<'cx, F: super::family::TypeFamily<'cx>> Token for $name<'cx, F> { + const REPR: &'static str = $str; + } + + derive_visit!($name); + )* + }; +} + +macro_rules! token_define_if_1 { + ($name:ident/1) => { + #[derive(Debug, PartialEq, Clone, Copy)] + pub struct $name<'cx, F: super::family::TypeFamily<'cx> = super::DefaultTypeFamily> { + pub position: F::Position, + } + + impl<'cx, F: super::family::TypeFamily<'cx>, G: super::family::TypeFamily<'cx>> + IntoToken<$name<'cx, G>> for $name<'cx, F> + where + F::Position: IntoPosition<'cx, G>, + { + fn into_token(self) -> $name<'cx, G> { + $name(self.position) + } + } + + #[doc(hidden)] + #[inline(always)] + #[allow(non_snake_case)] + pub fn $name<'cx, F: super::family::TypeFamily<'cx>>( + position: impl IntoPosition<'cx, F>, + ) -> $name<'cx, F> { + $name { + position: position.into_position(), + } + } + + impl<'cx, F: super::family::TypeFamily<'cx, Position: super::loc::Position>> + super::loc::Position for $name<'cx, F> + { + fn position(&self) -> Position { + self.position.position() + } + } + }; + ($name:ident/$lit:tt) => {}; +} + +macro_rules! token_define_if_many { + ($name:ident/1) => {}; + ($name:ident/$lit:tt) => { + #[derive(Debug, PartialEq, Clone, Copy)] + pub struct $name<'cx, F: super::family::TypeFamily<'cx> = super::DefaultTypeFamily> { + pub span: F::Span, + } + + impl<'cx, F: super::family::TypeFamily<'cx>, G: super::family::TypeFamily<'cx>> + IntoToken<$name<'cx, G>> for $name<'cx, F> + where + F::Span: IntoSpan<'cx, G>, + { + fn into_token(self) -> $name<'cx, G> { + $name(self.span) + } + } + + #[doc(hidden)] + #[inline(always)] + #[allow(non_snake_case)] + pub fn $name<'cx, F: super::family::TypeFamily<'cx>>( + span: impl IntoSpan<'cx, F>, + ) -> $name<'cx, F> { + $name { + span: span.into_span(), + } + } + impl<'cx, F: super::family::TypeFamily<'cx, Span: super::loc::Span>> super::loc::Span + for $name<'cx, F> + { + fn span(&self) -> Span { + self.span.span() + } + } + }; +} + +macro_rules! derive_visit { + ($name:ident) => { + impl<'cx, F: super::family::TypeFamily<'cx>, V: ?Sized> opslang_visitor::TemplateVisit + for $name<'cx, F> + { + } + impl<'cx, F: super::family::TypeFamily<'cx>, V: ?Sized> opslang_visitor::TemplateVisitMut + for $name<'cx, F> + { + } + }; +} + +declare_token! { + pub struct Semi/1 ";" + pub struct Break/1 "." + pub struct Atmark/1 "@" + pub struct Tilde/1 "~" + pub struct Colon/1 ":" + pub struct Eq/1 "=" + pub struct OpenBrace/1 "{" + pub struct CloseBrace/1 "}" + pub struct OpenParen/1 "(" + pub struct CloseParen/1 ")" + pub struct OpenSquare/1 "[" + pub struct CloseSquare/1 "]" + pub struct Hyphen/1 "-" + pub struct Ampersand/1 "&" + pub struct Dollar/1 "$" + pub struct Question/1 "?" + pub struct RightAngle/1 ">" + pub struct Angle/1 "<" + pub struct Star/1 "*" + pub struct Slash/1 "/" + pub struct Percent/1 "%" + pub struct Plus/1 "+" + pub struct BangEqual/2 "!=" + pub struct SlashEqual/2 "/=" + pub struct EqualEqual/2 "==" + pub struct RightAngleEq/2 ">=" + pub struct AngleEq/2 "<=" + pub struct ColonEq/2 ":=" + pub struct AndAnd/2 "&&" + pub struct OrOr/2 "||" + pub struct Arrow/2 "->" + pub struct DoubleArrow/2 "=>" +} + +/// Declare all keywords for v1 grammar. +macro_rules! declare_kw { + ($(pub struct $name:ident $str:literal)*) => { + $( + token_define_if_many!($name/2); + + impl<'cx, F: super::family::TypeFamily<'cx>> Token for $name<'cx, F> { + const REPR: &'static str = $str; + } + + derive_visit!($name); + )* + }; +} + +declare_kw! { + pub struct Return "return" + pub struct Let "let" + pub struct If "if" + pub struct As "as" + pub struct Else "else" + pub struct Call "call" + pub struct Wait "wait" + pub struct Select "select" + pub struct Prc "prc" + pub struct Const "const" +} + +#[macro_export] +/// A type-macro that expands to the name of the Rust type representation of a +/// given token. +/// +/// Usage is similar to `syn::Token!`. +macro_rules! V1Token { + // Keywords + (return) => { + $crate::syntax::v1::token::Return + }; + (let) => { + $crate::syntax::v1::token::Let + }; + (if) => { + $crate::syntax::v1::token::If + }; + (as) => { + $crate::syntax::v1::token::As + }; + (else) => { + $crate::syntax::v1::token::Else + }; + (call) => { + $crate::syntax::v1::token::Call + }; + (wait) => { + $crate::syntax::v1::token::Wait + }; + (select) => { + $crate::syntax::v1::token::Select + }; + (prc) => { + $crate::syntax::v1::token::Prc + }; + (const) => { + $crate::syntax::v1::token::Const + }; + + // Single character tokens + (;) => { + $crate::syntax::v1::token::Semi + }; + (.) => { + $crate::syntax::v1::token::Break + }; + (@) => { + $crate::syntax::v1::token::Atmark + }; + (~) => { + $crate::syntax::v1::token::Tilde + }; + (:) => { + $crate::syntax::v1::token::Colon + }; + (=) => { + $crate::syntax::v1::token::Eq + }; + // Note: {, }, (, ), [, ] cannot be defined in Rust macros due to syntax limitations + (-) => { + $crate::syntax::v1::token::Hyphen + }; + (&) => { + $crate::syntax::v1::token::Ampersand + }; + ($) => { + $crate::syntax::v1::token::Dollar + }; + (?) => { + $crate::syntax::v1::token::Question + }; + (>) => { + $crate::syntax::v1::token::RightAngle + }; + (<) => { + $crate::syntax::v1::token::Angle + }; + (*) => { + $crate::syntax::v1::token::Star + }; + (/) => { + $crate::syntax::v1::token::Slash + }; + (%) => { + $crate::syntax::v1::token::Percent + }; + (+) => { + $crate::syntax::v1::token::Plus + }; + + // Two character tokens + (!=) => { + $crate::syntax::v1::token::BangEqual + }; + (/=) => { + $crate::syntax::v1::token::SlashEqual + }; + (==) => { + $crate::syntax::v1::token::EqualEqual + }; + (>=) => { + $crate::syntax::v1::token::RightAngleEq + }; + (<=) => { + $crate::syntax::v1::token::AngleEq + }; + (:=) => { + $crate::syntax::v1::token::ColonEq + }; + (&&) => { + $crate::syntax::v1::token::AndAnd + }; + (||) => { + $crate::syntax::v1::token::OrOr + }; + (->) => { + $crate::syntax::v1::token::Arrow + }; + (=>) => { + $crate::syntax::v1::token::DoubleArrow + }; +} diff --git a/structure/opslang-ast/src/syntax/v1/visit.rs b/structure/opslang-ast/src/syntax/v1/visit.rs new file mode 100644 index 0000000..991667f --- /dev/null +++ b/structure/opslang-ast/src/syntax/v1/visit.rs @@ -0,0 +1,87 @@ +use opslang_visitor::{TemplateVisit, TemplateVisitMut, Visitor, VisitorMut}; + +/// A comprehensive visitor trait for all V1 AST types. +/// +/// This trait provides `visit_*` and `super_*` methods for every V1 AST type, +/// allowing convenient traversal of the entire AST. Although it appears as an empty +/// trait definition due to the attribute macro, it actually contains generated methods +/// for all AST node types. +/// +/// The trait includes method pairs like: +/// - `visit_program(&mut self, node: &Program<'cx>)` - visits a Program node +/// - `super_program(&mut self, node: &Program<'cx>)` - performs default traversal +/// - And similar pairs for every AST node type +/// +/// The trait is automatically implemented for any type that implements the required +/// `Visitor` traits for individual AST types. The implementation delegates to the +/// individual `Visitor` trait implementations. +/// +/// # Usage +/// +/// ```ignore +/// struct MyVisitor; +/// v1_ast_visitor_impl!(for MyVisitor { +/// fn visit_program(&mut self, node: &Program<'cx>) { +/// // Custom logic for visiting Program nodes +/// +/// // You can recover default behavior by calling "super method" of [`AstVisitor`] +/// self.super_program(node); +/// } +/// }) +/// +/// // MyVisitor automatically implements AstVisitor +/// let mut visitor = MyVisitor; +/// visitor.visit_program(&program); // Generated method available +/// ``` +/// +/// # Implementation Details +/// +/// This trait is generated by the `declare_ast_visitor_trait` attribute macro, +/// which transforms the empty trait declaration into a full visitor trait with +/// methods for all AST types and provides a blanket implementation. +#[opslang_ast_macro::v1_declare_ast_visitor_trait] +pub trait AstVisitor<'cx> {} + +/// Implement [`TemplateVisit`] for [`Expr`], ignoring sealed field. +/// +/// [`Expr`]: super::Expr +impl<'cx, F: super::TypeFamily<'cx>, V: ?Sized + Visitor<&'cx super::ExprKind<'cx, F>>> + TemplateVisit for super::Expr<'cx, F> +{ + fn super_visit(&self, visitor: &mut V) { + visitor.visit(&self.0) + } +} + +/// Implement [`TemplateVisitMut`] for [`Expr`], ignoring sealed field. +/// +/// [`Expr`]: super::Expr +impl<'cx, F: super::TypeFamily<'cx>, V: ?Sized + Visitor<&'cx super::ExprKind<'cx, F>>> + TemplateVisitMut for super::Expr<'cx, F> +{ + fn super_visit_mut(&mut self, visitor: &mut V) { + visitor.visit(&self.0) + } +} + +/// Implement [`TemplateVisit`] for [`ExprMut`], ignoring sealed field. +/// +/// [`ExprMut`]: super::ExprMut +impl<'cx, F: super::TypeFamily<'cx>, V: ?Sized + for<'a> Visitor<&'a super::ExprKind<'cx, F>>> + TemplateVisit for super::ExprMut<'cx, F> +{ + fn super_visit(&self, visitor: &mut V) { + visitor.visit(&&*self.0) + } +} + +/// Implement [`TemplateVisitMut`] for [`ExprMut`], ignoring sealed field. +/// +/// [`ExprMut`]: super::ExprMut +impl<'cx, F: super::TypeFamily<'cx>, V: ?Sized + VisitorMut<&'cx mut super::ExprKind<'cx, F>>> + TemplateVisitMut for super::ExprMut<'cx, F> +{ + fn super_visit_mut(&mut self, visitor: &mut V) { + visitor.visit_mut(&mut self.0) + } +} diff --git a/structure/opslang-ast/src/version.rs b/structure/opslang-ast/src/version.rs new file mode 100644 index 0000000..e38fd48 --- /dev/null +++ b/structure/opslang-ast/src/version.rs @@ -0,0 +1,21 @@ +pub(crate) mod sealed { + pub trait Sealed {} +} + +/// A marker trait for versioning the AST. +pub trait VersionMarker: sealed::Sealed { + /// Shows the version of the AST in lowercase. + fn version() -> &'static str; +} + +/// A trait for types that is versioned. +pub trait Versioned { + /// The version type. + type Version: VersionMarker; + + /// Returns the version of the AST in lowercase. + fn version() -> &'static str { + // Re-export the function from the sealed trait. + ::version() + } +} diff --git a/structure/opslang-ast/tests/v1_visitor_integration.rs b/structure/opslang-ast/tests/v1_visitor_integration.rs new file mode 100644 index 0000000..57286de --- /dev/null +++ b/structure/opslang-ast/tests/v1_visitor_integration.rs @@ -0,0 +1,290 @@ +//! Integration tests for v1 visitor functionality +//! These tests use the parser to create AST nodes and then test visitor behavior + +use opslang_ast::v1::context::Context; +use opslang_ast::v1::visit::AstVisitor; +use opslang_parser::{ParseOps, ParserInput}; + +// Helper to parse a given source code string +fn parse_source<'cx>( + source: &'cx str, + context: &'cx Context<'cx>, +) -> opslang_ast::v1::Program<'cx> { + let input = ParserInput { + content: source, + file_name: "test.ops".into(), + }; + opslang_ast::v1::Program::parse(input, context).expect("Failed to parse test source") +} + +#[derive(Default)] +struct CountingVisitor { + program_count: usize, + function_count: usize, + expr_count: usize, + literal_count: usize, + statement_count: usize, + let_count: usize, + return_count: usize, + ident_count: usize, + numeric_count: usize, +} + +opslang_ast_macro::v1_ast_visitor_impl!(for CountingVisitor { + fn visit_program(&mut self, node: &opslang_ast::v1::Program<'cx>) { + self.program_count += 1; + self.super_program(node); + } + + fn visit_function_def(&mut self, node: &opslang_ast::v1::FunctionDef<'cx>) { + self.function_count += 1; + self.super_function_def(node); + } + + fn visit_expr(&mut self, node: &opslang_ast::v1::Expr<'cx>) { + self.expr_count += 1; + self.super_expr(node); + } + + fn visit_literal(&mut self, node: &opslang_ast::v1::Literal<'cx>) { + self.literal_count += 1; + self.super_literal(node); + } + + fn visit_statement(&mut self, node: &opslang_ast::v1::Statement<'cx>) { + self.statement_count += 1; + self.super_statement(node); + } + + fn visit_let(&mut self, node: &opslang_ast::v1::Let<'cx>) { + self.let_count += 1; + self.super_let(node); + } + + fn visit_return_stmt(&mut self, node: &opslang_ast::v1::ReturnStmt<'cx>) { + self.return_count += 1; + self.super_return_stmt(node); + } + + fn visit_ident(&mut self, node: &opslang_ast::v1::Ident<'cx>) { + self.ident_count += 1; + self.super_ident(node); + } + + fn visit_numeric(&mut self, node: &opslang_ast::v1::Numeric<'cx>) { + self.numeric_count += 1; + self.super_numeric(node); + } +}); + +#[derive(Default)] +struct CollectingVisitor { + identifiers: Vec, + numeric_values: Vec, + string_literals: Vec, +} + +opslang_ast_macro::v1_ast_visitor_impl!(for CollectingVisitor { + fn visit_ident(&mut self, node: &opslang_ast::v1::Ident<'cx>) { + self.identifiers.push(node.raw.to_string()); + self.super_ident(node); + } + + fn visit_numeric(&mut self, node: &opslang_ast::v1::Numeric<'cx>) { + self.numeric_values.push(node.raw.to_string()); + self.super_numeric(node); + } + + fn visit_string(&mut self, node: &opslang_ast::v1::String<'cx>) { + self.string_literals.push(node.raw.to_string()); + self.super_string(node); + } +}); + +#[test] +fn test_counting_visitor_simple_program() { + let source = r#"#! lang=v1 +prc main() { + let x = 42; + return; +} +"#; + + let context = Context::new(); + let program = parse_source(source, &context); + let mut visitor = CountingVisitor::default(); + + visitor.visit_program(&program); + + assert_eq!(visitor.program_count, 1); + assert_eq!(visitor.function_count, 1); + assert_eq!(visitor.let_count, 1); + assert_eq!(visitor.return_count, 1); + assert!(visitor.expr_count > 0); // Should have at least one expression (42) + assert!(visitor.literal_count > 0); // Should have numeric literal + assert!(visitor.ident_count >= 2); // Should have 'main' and 'x' + assert_eq!(visitor.numeric_count, 1); // Should have '42' +} + +#[test] +fn test_counting_visitor_multiple_functions() { + let source = r#"#! lang=v1 +prc main() { + let x = 10; + let y = 20; + return; +} + +prc add() { + let result = 30; + return; +} +"#; + + let context = Context::new(); + let program = parse_source(source, &context); + let mut visitor = CountingVisitor::default(); + + visitor.visit_program(&program); + + assert_eq!(visitor.program_count, 1); + assert_eq!(visitor.function_count, 2); + assert_eq!(visitor.let_count, 3); + assert_eq!(visitor.return_count, 2); + assert_eq!(visitor.numeric_count, 3); // Should have '10', '20', '30' +} + +#[test] +fn test_collecting_visitor_identifiers() { + let source = r#"#! lang=v1 +prc main() { + let variable_name = 123; + let another_var = 456; + return; +} +"#; + + let context = Context::new(); + let program = parse_source(source, &context); + let mut visitor = CollectingVisitor::default(); + + visitor.visit_program(&program); + + // Should collect all identifiers + assert!(visitor.identifiers.contains(&"main".to_string())); + assert!(visitor.identifiers.contains(&"variable_name".to_string())); + assert!(visitor.identifiers.contains(&"another_var".to_string())); + + // Should collect numeric values + assert!(visitor.numeric_values.contains(&"123".to_string())); + assert!(visitor.numeric_values.contains(&"456".to_string())); +} + +#[test] +fn test_collecting_visitor_with_strings() { + let source = r#"#! lang=v1 +prc main() { + let greeting = "hello"; + let message = "world"; + let number = 42; + return; +} +"#; + + let context = Context::new(); + let program = parse_source(source, &context); + let mut visitor = CollectingVisitor::default(); + + visitor.visit_program(&program); + + // Should collect string literals + assert!(visitor.string_literals.contains(&"hello".to_string())); + assert!(visitor.string_literals.contains(&"world".to_string())); + + // Should collect identifiers + assert!(visitor.identifiers.contains(&"greeting".to_string())); + assert!(visitor.identifiers.contains(&"message".to_string())); + assert!(visitor.identifiers.contains(&"number".to_string())); + + // Should collect numeric value + assert!(visitor.numeric_values.contains(&"42".to_string())); +} + +#[test] +fn test_visitor_traversal_completeness() { + let source = r#"#! lang=v1 +prc test_function() { + let a = 1; + let b = 2; + let c = a + b; + return; +} + +const CONSTANT: i32 = 100; +"#; + + let context = Context::new(); + let program = parse_source(source, &context); + let mut visitor = CountingVisitor::default(); + + visitor.visit_program(&program); + + // Verify that the visitor traversed the entire AST + assert_eq!(visitor.program_count, 1); + assert!(visitor.function_count >= 1); // At least the function + assert!(visitor.ident_count >= 4); // Function name, variables a, b, c + assert!(visitor.expr_count >= 3); // At least a few expressions +} + +#[derive(Default)] +struct ExpressionTypeVisitor { + variable_exprs: usize, + literal_exprs: usize, + binary_exprs: usize, + parened_exprs: usize, +} + +opslang_ast_macro::v1_ast_visitor_impl!(for ExpressionTypeVisitor { + fn visit_expr(&mut self, node: &opslang_ast::v1::Expr<'cx>) { + match node.0 { + opslang_ast::v1::ExprKind::Variable(_) => { + self.variable_exprs += 1; + } + opslang_ast::v1::ExprKind::Literal(_) => { + self.literal_exprs += 1; + } + opslang_ast::v1::ExprKind::Binary(_) => { + self.binary_exprs += 1; + } + opslang_ast::v1::ExprKind::Parened(_) => { + self.parened_exprs += 1; + } + _ => {} + } + self.super_expr(node); + } +}); + +#[test] +fn test_expression_type_visitor() { + let source = r#"#! lang=v1 +prc main() { + let x = 10; + let y = x + 20; + let z = (y * 2); + return; +} +"#; + + let context = Context::new(); + let program = parse_source(source, &context); + let mut visitor = ExpressionTypeVisitor::default(); + + visitor.visit_program(&program); + + // Should find different types of expressions + assert!(visitor.literal_exprs > 0); // Numbers like 10, 20, 2 + assert!(visitor.variable_exprs > 0); // Variables like x, y + // Binary and parenthesized expressions depend on the exact parsing + // but we can at least verify the visitor ran without errors +} diff --git a/structure/opslang-ast/tests/visitor_consistency.rs b/structure/opslang-ast/tests/visitor_consistency.rs new file mode 100644 index 0000000..a2c8278 --- /dev/null +++ b/structure/opslang-ast/tests/visitor_consistency.rs @@ -0,0 +1,70 @@ +//! Visitor implementation consistency tests. +//! +//! This test file validates that the visitor implementation macros can generate +//! valid code for empty visitor definitions. This serves as a structural consistency +//! check for the AST type registry and visitor implementation logic. +//! +//! # Purpose +//! +//! Empty visitor definitions are particularly valuable for testing because they +//! exercise the complete visitor generation machinery without any custom logic: +//! +//! 1. **Type Registry Validation**: All types in `visitor_type_registry.rs` must exist and be +//! accessible for the macro to generate visitor methods. +//! +//! 2. **Method Generation Logic**: The visitor implementation macro must correctly +//! generate method signatures and default implementations for all AST types. +//! +//! 3. **Path Resolution**: All type paths used in generated code must resolve +//! correctly from the visitor implementation context. +//! +//! # Failure Scenarios +//! +//! If any test in this file fails to compile, it indicates one of these issues: +//! +//! - **Registry Inconsistency**: A type listed in `visitor_type_registry.rs` doesn't exist +//! or has been renamed/moved without updating the registry. +//! +//! - **Visitor Implementation Bug**: The `visitor_impl.rs` macro has a bug in +//! method signature generation, path construction, or code generation logic. +//! +//! - **Type Path Issues**: Generated visitor methods reference types using +//! incorrect paths that don't resolve in the current module context. +//! +//! These tests complement the compile-time consistency checks by validating +//! the end-to-end visitor generation pipeline rather than just type existence. + +/// Empty AST visitor to test basic visitor generation without custom implementations. +/// +/// This visitor defines no custom visit methods, relying entirely on the macro +/// to generate all required visitor trait implementations. Successful compilation +/// indicates that: +/// +/// 1. All AST types in the registry are accessible and properly defined +/// 2. The visitor macro can generate syntactically correct method signatures +/// 3. Default traversal implementations compile without errors +/// 4. Type paths resolve correctly in the generated code +struct EmptyAstVisitor; + +opslang_ast_macro::v1_ast_visitor_impl!(for EmptyAstVisitor { + // Intentionally empty - this tests that the macro can generate + // complete visitor implementations with no custom methods +}); + +/// Test that an empty AST visitor implements the expected traits. +/// +/// This test validates that the generated visitor properly implements +/// all necessary visitor traits, ensuring the macro generates complete +/// and correct implementations. +#[test] +fn empty_ast_visitor_trait_implementation() { + use opslang_ast::v1::visit::AstVisitor; + + let visitor = EmptyAstVisitor; + + // Test that the visitor implements AstVisitor trait + // We can't actually call visit methods without constructing AST nodes, + // but we can verify the trait is implemented + fn _assert_implements_ast_visitor<'cx, T: AstVisitor<'cx>>(_: T) {} + _assert_implements_ast_visitor(visitor); +} diff --git a/structure/opslang-ir/Cargo.toml b/structure/opslang-ir/Cargo.toml new file mode 100644 index 0000000..e026148 --- /dev/null +++ b/structure/opslang-ir/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "opslang-ir" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "ops file language IR" + +[dependencies] +opslang-ast.workspace = true +opslang-ast-macro.workspace = true +opslang-ir-macro.workspace = true +opslang-visitor.workspace = true +opslang-visitor-macro.workspace = true +opslang-ty.workspace = true +opslang-module.workspace = true +chrono.workspace = true +typed-arena.workspace = true + +[dev-dependencies] +opslang-parser.workspace = true diff --git a/structure/opslang-ir/macro/Cargo.toml b/structure/opslang-ir/macro/Cargo.toml new file mode 100644 index 0000000..f1fc43a --- /dev/null +++ b/structure/opslang-ir/macro/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "opslang-ir-macro" +version.workspace = true +edition.workspace = true +license.workspace = true + +[lib] +proc-macro = true + +[dependencies] +syn.workspace = true +proc-macro2.workspace = true +quote.workspace = true +synstructure.workspace = true +convert_case.workspace = true +opslang-visitor-macro-helper.workspace = true +opslang-type-registry.workspace = true diff --git a/structure/opslang-ir/macro/src/declare_ir_visitor_trait.rs b/structure/opslang-ir/macro/src/declare_ir_visitor_trait.rs new file mode 100644 index 0000000..0e585f8 --- /dev/null +++ b/structure/opslang-ir/macro/src/declare_ir_visitor_trait.rs @@ -0,0 +1,21 @@ +use opslang_type_registry::v1::ir::types::IrNodeTy; +use opslang_visitor_macro_helper::{ + VisitorMode, + shared_visitor_trait::{TraitDeclaration, declare_visitor_trait}, +}; + +/// Generates a comprehensive immutable visitor trait for all V1 IR types. +pub fn declare_ir_visitor_trait( + trait_decl: TraitDeclaration, +) -> syn::Result { + let all_ir_types = IrNodeTy::get_v1_ir_node_types(); + declare_visitor_trait(trait_decl, all_ir_types, VisitorMode::Visit) +} + +/// Generates a comprehensive mutable visitor trait for all V1 IR types. +pub fn declare_ir_visitor_mut_trait( + trait_decl: TraitDeclaration, +) -> syn::Result { + let all_ir_types = IrNodeTy::get_v1_ir_node_types(); + declare_visitor_trait(trait_decl, all_ir_types, VisitorMode::VisitMut) +} diff --git a/structure/opslang-ir/macro/src/ir_consistency_check.rs b/structure/opslang-ir/macro/src/ir_consistency_check.rs new file mode 100644 index 0000000..cb2abdb --- /dev/null +++ b/structure/opslang-ir/macro/src/ir_consistency_check.rs @@ -0,0 +1,33 @@ +use proc_macro2::TokenStream; +use quote::quote; + +/// Generates a compile-time consistency check that verifies all IR types defined in `visitor_type_registry.rs` +/// actually exist and are accessible from a v1 child module. +/// +/// This macro creates a compile-time check that ensures type consistency between the centralized +/// type registry in `visitor_type_registry.rs` and the actual type definitions across multiple crates +/// (opslang-ast, opslang-ir, opslang-ty). +/// +/// The generated code uses `const _: () = { let _: T; }` pattern to verify that each type +/// can be referenced and is valid at compile time. If any type in the registry doesn't exist +/// or isn't accessible, compilation will fail with a clear error message. +/// +/// See the call site for more information. +pub fn ir_consistency_check() -> TokenStream { + let ir_types = opslang_type_registry::v1::ir::types::IrNodeTy::get_v1_ir_node_types(); + + let type_checks = ir_types.map(|ir_type| { + let type_path = ir_type.inside_of_v1_child_mod().super_path(); + quote! { + let _: #type_path; + } + }); + + quote! { + const _: () = { + fn check<'cx>() { + #(#type_checks)* + } + }; + } +} diff --git a/structure/opslang-ir/macro/src/lib.rs b/structure/opslang-ir/macro/src/lib.rs new file mode 100644 index 0000000..48d530d --- /dev/null +++ b/structure/opslang-ir/macro/src/lib.rs @@ -0,0 +1,132 @@ +mod declare_ir_visitor_trait; +mod ir_consistency_check; +mod visitor_impl; + +use proc_macro::TokenStream; + +#[inline] +fn wrap_proc_macro( + input: proc_macro::TokenStream, + f: impl Fn(T) -> syn::Result, +) -> proc_macro::TokenStream { + syn::parse(input) + .and_then(f) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +#[proc_macro] +pub fn v1_ir_visitor_impl(input: TokenStream) -> TokenStream { + wrap_proc_macro(input, visitor_impl::visitor_impl) +} + +/// Generates a comprehensive IR visitor trait for all V1 IR types. +/// +/// This attribute macro creates immutable visitor traits that can traverse IR structures. +/// It provides `visit_*` and `super_*` method pairs for each IR type, where the `visit_*` +/// methods can be overridden by implementations and `super_*` methods provide default +/// traversal behavior. +/// +/// # Usage +/// +/// ```ignore +/// #[opslang_ir_macro::v1_declare_ir_visitor_trait] +/// pub trait MyIrVisitor { +/// // trait body will be automatically generated +/// } +/// ``` +/// +/// This generates methods like: +/// - `visit_program(&mut self, node: &Program<'cx>)` +/// - `super_program(&mut self, node: &Program<'cx>)` +/// - `visit_expr(&mut self, node: &Expr<'cx>)` +/// - `super_expr(&mut self, node: &Expr<'cx>)` +/// - And so on for all IR types... +#[proc_macro_attribute] +pub fn v1_declare_ir_visitor_trait(_attr: TokenStream, input: TokenStream) -> TokenStream { + wrap_proc_macro(input, declare_ir_visitor_trait::declare_ir_visitor_trait) +} + +/// Generates a comprehensive mutable IR visitor trait for all V1 IR types. +/// +/// This attribute macro creates mutable visitor traits that can traverse and modify IR structures. +/// It provides `visit_*_mut` and `super_*_mut` method pairs for each IR type, where the `visit_*_mut` +/// methods can be overridden by implementations and `super_*_mut` methods provide default +/// traversal behavior. +/// +/// # Usage +/// +/// ```ignore +/// #[opslang_ir_macro::v1_declare_ir_visitor_mut_trait] +/// pub trait MyIrVisitorMut { +/// // trait body will be automatically generated +/// } +/// ``` +/// +/// This generates methods like: +/// - `visit_program_mut(&mut self, node: &mut Program<'cx>)` +/// - `super_program_mut(&mut self, node: &mut Program<'cx>)` +/// - `visit_expr_mut(&mut self, node: &mut Expr<'cx>)` +/// - `super_expr_mut(&mut self, node: &mut Expr<'cx>)` +/// - And so on for all IR types... +#[proc_macro_attribute] +pub fn v1_declare_ir_visitor_mut_trait(_attr: TokenStream, input: TokenStream) -> TokenStream { + wrap_proc_macro( + input, + declare_ir_visitor_trait::declare_ir_visitor_mut_trait, + ) +} + +/// Generates a compile-time consistency check for IR types registry. +/// +/// This procedural macro verifies that all IR types defined in the centralized registry +/// (`visitor_type_registry.rs`) actually exist and are accessible from the context where this macro is called. +/// The macro is designed to be called from within a v1 child module context to ensure that +/// all registered types can be referenced using `super::` paths. +/// +/// # Purpose +/// +/// The IR types registry in `visitor_type_registry.rs` maintains a comprehensive list of all IR-related +/// node types from multiple crates (opslang-ast, opslang-ir, opslang-ty) for use by +/// procedural macros, but this registry is independent of the actual type definitions. This +/// creates a potential inconsistency where the registry might reference types that don't exist +/// or have been renamed/moved. +/// +/// # Implementation +/// +/// The macro generates compile-time checks in the form: +/// ```ignore +/// const _: () = { +/// fn check<'cx>() { +/// let _: super::Program<'cx, super::IrTypeFamily>; +/// let _: super::Expr<'cx>; +/// let _: super::ResolvedPath<'cx>; +/// // ... for each registered type +/// } +/// }; +/// ``` +/// +/// If any type in the registry doesn't exist or isn't accessible with the expected path, +/// compilation will fail with a clear error message pointing to the problematic type. +/// +/// # Usage +/// +/// This macro should be called from within a child module of `opslang_ir::version::v1` +/// to verify type accessibility: +/// +/// ```ignore +/// // In opslang-ir/src/version/v1/some_child_module.rs +/// opslang_ir_macro::ir_consistency_check!(); +/// ``` +/// +/// # Guarantees +/// +/// Successful compilation of this macro ensures: +/// 1. All types in the IR registry exist across referenced crates +/// 2. All types are accessible from v1 child module context using appropriate paths +/// 3. All types accept the expected lifetime and type family parameters +/// 4. The registry is consistent with actual type definitions across multiple crates +#[proc_macro] +pub fn ir_consistency_check(_input: TokenStream) -> TokenStream { + ir_consistency_check::ir_consistency_check().into() +} diff --git a/structure/opslang-ir/macro/src/visitor_impl.rs b/structure/opslang-ir/macro/src/visitor_impl.rs new file mode 100644 index 0000000..a5cddd0 --- /dev/null +++ b/structure/opslang-ir/macro/src/visitor_impl.rs @@ -0,0 +1,98 @@ +use opslang_type_registry::v1::ir::types::{IrInterTy, IrNodeTy}; +use opslang_visitor_macro_helper::{CallsiteTraitName, VisitorType, no_intermediate_helper}; + +/// Generates visitor implementation for IR types. +/// +/// # Design Note +/// +/// **You should rarely need to modify this function.** Most visitor changes happen in +/// [`visitor_type_registry.rs`](./visitor_type_registry.rs) by updating the multi-crate type registries. This function +/// mechanically converts the registered types into visitor trait implementations. +pub fn visitor_impl( + input: opslang_visitor_macro_helper::VisitorImpl, +) -> Result { + // Get all IR types for v1 syntax (includes both AST and IR specific types) + let all_ir_types = IrNodeTy::get_v1_ir_node_types(); + + // Convert IR types to VisitorType format with 'cx lifetime + // Generate both Visit and VisitMut implementations for each type + let mut visitor_types: Vec = Vec::new(); + + for ir_type in all_ir_types { + let crate_qualified = ir_type.outside_of_ir_crate(); + let path = crate_qualified.full_crate_path(); + let kind = opslang_visitor_macro_helper::MethodKind::Visit; + // Generate Visit version + let mode = opslang_visitor_macro_helper::VisitorMode::Visit; + visitor_types.push(VisitorType { + generics: syn::parse_quote!(<'cx>), + path: path.clone(), + visit_method_name: ir_type.generate_visit_method_name(kind, mode), + mode, + }); + + // Generate VisitMut version + let mode = opslang_visitor_macro_helper::VisitorMode::VisitMut; + visitor_types.push(VisitorType { + generics: syn::parse_quote!(<'cx>), + path, + visit_method_name: ir_type.generate_visit_method_name(kind, mode), + mode, + }); + } + + // Generate intermediate implementations for generic types like &[T], Option, etc. + let additional_impls = generate_intermediate_visitor_impls(&input); + + let callsite_trait = CallsiteTraitName::both( + syn::parse_quote!(::opslang_ir::version::v1::visit::IrVisitor), + syn::parse_quote!(::opslang_ir::version::v1::visit::IrMutVisitor), + ); + let main_expanded = + opslang_visitor_macro_helper::generate_visitor_impl(input, callsite_trait, visitor_types)?; + + Ok(quote::quote! { + #main_expanded + #additional_impls + }) +} + +/// Generate intermediate visitor implementations for both Visit and VisitMut modes. +fn generate_intermediate_visitor_impls( + visitor_impl: &opslang_visitor_macro_helper::VisitorImpl, +) -> proc_macro2::TokenStream { + use quote::quote; + + let impl_type = &visitor_impl.impl_type; + let impl_generics = &visitor_impl.impl_generics; + + // Add 'cx lifetime to existing generics + let updated_generics = no_intermediate_helper::update_generics(impl_generics, |g| { + g.params.push(syn::parse_quote!('cx)); + }); + + // Generate generic implementations for both Visitor and VisitorMut + let visit_generic_impls = + no_intermediate_helper::generate_generic_visitor_impls(&updated_generics, impl_type); + + let visit_mut_generic_impls = + no_intermediate_helper::generate_generic_visitor_mut_impls(&updated_generics, impl_type); + + let (updated_impl_generics, _, updated_where_clause) = updated_generics.split_for_impl(); + + let specific_impls = IrInterTy::get_v1_ir_inter_types().map(|ty| { + let outside = ty.outside_of_ir_crate(); + let ty = outside.full_path(); + let ty = &ty; + quote! { + ::opslang_visitor::impl_visitor!(#updated_impl_generics #impl_type [visit] #ty #updated_where_clause); + ::opslang_visitor::impl_visitor!(#updated_impl_generics #impl_type [visit_mut] #ty #updated_where_clause); + } + }); + + quote! { + #visit_generic_impls + #visit_mut_generic_impls + #(#specific_impls)* + } +} diff --git a/structure/opslang-ir/src/lib.rs b/structure/opslang-ir/src/lib.rs new file mode 100644 index 0000000..a6db76a --- /dev/null +++ b/structure/opslang-ir/src/lib.rs @@ -0,0 +1 @@ +pub mod version; diff --git a/structure/opslang-ir/src/version.rs b/structure/opslang-ir/src/version.rs new file mode 100644 index 0000000..9aac22e --- /dev/null +++ b/structure/opslang-ir/src/version.rs @@ -0,0 +1,27 @@ +macro_rules! declare_versions { + () => {}; + ($([$current:vis])? $path:ident, $ty:ident; $($tt:tt)*) => { + pub mod $path; + pub struct $ty; + + $( + /// Type alias for the default version of the ast. + $current type Default = $ty; + $current use $path::*; + )? + + declare_versions! { $($tt)* } + } +} + +/// Assertion that [`Default`] type alias exists at this scope. +/// +/// This is a compile-time check that will fail if [`Default`] is not defined. +#[allow(dead_code)] +const _: () = { + let _: Default; +}; + +declare_versions! { + [pub] v1, V1; +} diff --git a/structure/opslang-ir/src/version/v1.rs b/structure/opslang-ir/src/version/v1.rs new file mode 100644 index 0000000..0b4280d --- /dev/null +++ b/structure/opslang-ir/src/version/v1.rs @@ -0,0 +1,416 @@ +/*! +Intermediate Representation (IR) for opslang v1. + +The IR serves as a bridge between the Abstract Syntax Tree (AST) and the type-checked representation. +This module defines the responsibility and structure of the IR layer. + +**IMPORTANT**: When modifying type structures in this module, update the visitor type +registry in `opslang-ir-macro/src/visitor_type_registry.rs` to ensure proper visitor +macro generation. Choose whether to make types hookable (add to node types) or not +hookable (add to inter types). + +## IR Responsibilities + +The IR has several key responsibilities that distinguish it from the AST: + +1. **Type Inference Results**: The IR holds the results of type inference, including resolved + types for expressions, identifiers, and literals. This is primarily achieved through the + `v1_default_type_subst!` macro which configures `Expr` to be typed. + +2. **Name Resolution Results**: AST `Ident` types are resolved to `opslang_ty::Ident` with scope + information, and AST `Path` types are resolved to `opslang_ty::ModuleItem` references + after module resolution. + +3. **Qualification Integration**: Qualif and PreQualified expressions are integrated into Apply + expressions, and these qualification types are made infallible (using `std::convert::Infallible`) + to prevent construction in the IR, as they should be resolved into Apply operations. + +4. **Parsed Literal Values**: Literals are stored as their parsed values rather than raw strings. + While the AST uses permissive parsing to avoid early failures, the IR contains only the + meaningful parsed values since validation has already occurred. + +5. **Comment Merging**: Adjacent comments that were stored line-by-line in the AST are merged + into comment blocks in the IR. This reflects the common practice of multi-line comments + and provides a more convenient representation for downstream processing. + +The IR represents the result of type inference and name resolution, providing a more semantic +view of the program structure while maintaining references to the original AST for source +location information and tooling support. +*/ + +use chrono::Utc; +use opslang_ast::{ + token::{IntoPosition, IntoSpan}, + v1::{self as ast, TypeFamily as AstTypeFamily, token}, +}; +use opslang_module::version::v1 as module; +use opslang_ty::version::v1::{self as ty, Ident, Ty, TypingContext}; +use opslang_visitor_macro::Visit; +use std::convert::Infallible; + +pub mod context; +pub use context::Context; +pub mod ir_consistency_check; + +pub mod visit; +pub use visit::{IrMutVisitor, IrVisitor}; + +pub mod binop; +pub use binop::*; + +#[derive(Debug, PartialEq, Clone, Copy, Default, Visit)] +#[skip_all_visit] +/// IR type family that includes type information and resolved names. +pub struct IrTypeFamily; + +impl<'cx> AstTypeFamily<'cx> for IrTypeFamily { + opslang_ast_macro::v1_default_type_subst! { + Span = Option, + Position = Option, + + // Core structural types + Comment = Comment<'cx>, + ToplevelItem = Definition<'cx>, + Row = ast::Row<'cx, Self>, + Block = ast::Block<'cx, Self>, + Scope = Scope<'cx>, + SelectItems = Vec>, + + // Resolved name types + Ident = Ident<'cx>, + Path = ResolvedPath<'cx>, + Ty = Ty<'cx>, + FnReturnTy = Ty<'cx>, + + // Typed expression + Expr = Expr<'cx>, + Exprs = Vec>, + + // Infallible qualification types (resolved into Apply) + Qualif = Infallible, + PreQualified = Infallible, + + // Expression components + FilePath = module::ModulePath<'cx>, + ImportedPath = Ident<'cx>, + String = String<'cx>, + Bytes = Bytes<'cx>, + HexBytes = HexBytes<'cx>, + DateTime = DateTime<'cx>, + Numeric = Numeric<'cx>, + Apply = Apply<'cx>, + + BinOp = BinOp<'cx>, + Compare = Compare<'cx>, + + // Parentheses are removed + Parened = Infallible, + .. + } +} + +/// Re-export AST types with IrTypeFamily applied for convenience. +/// +/// Use this types instead of `ast::{type}<'cx, IrTypeFamily>` for brevity and clarity. +macro_rules! re_export { + ($(pub type $ty:ident<'cx>;)*) => { + $( + pub type $ty<'cx> = ast::$ty<'cx, IrTypeFamily>; + )* + }; +} + +pub type AstContext<'cx> = ast::context::Context<'cx, IrTypeFamily>; + +re_export! { + pub type Program<'cx>; + + pub type ToplevelItem<'cx>; + pub type DefinitionKind<'cx>; + + pub type FunctionDef<'cx>; + pub type Parameter<'cx>; + pub type ConstantDef<'cx>; + + pub type ScopeItem<'cx>; + + pub type Row<'cx>; + pub type Statement<'cx>; + pub type Block<'cx>; + pub type ReturnStmt<'cx>; + + pub type ExprKind<'cx>; + pub type ExprMut<'cx>; + pub type Qualif<'cx>; + pub type ModifierParam<'cx>; + pub type Modifier<'cx>; + pub type DefaultModifier<'cx>; + pub type Let<'cx>; + pub type ExprStatement<'cx>; + + pub type Literal<'cx>; + pub type Array<'cx>; + + pub type Unary<'cx>; + pub type Binary<'cx>; + pub type CompareOp<'cx>; + pub type CompareOpExpr<'cx>; + pub type Set<'cx>; + pub type InfixImport<'cx>; + pub type If<'cx>; + pub type Select<'cx>; + pub type SelectItem<'cx>; +} + +impl<'cx> IntoSpan<'cx, IrTypeFamily> for ast::Span { + fn into_span(self) -> >::Span { + Some(self) + } +} + +impl<'cx> IntoPosition<'cx, IrTypeFamily> for ast::Position { + fn into_position(self) -> >::Position { + Some(self) + } +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A merged comment block in the IR. +/// +/// Unlike AST comments which are stored line-by-line, IR comments represent +/// merged blocks of adjacent comments, which is more natural for multi-line +/// comment blocks in the source code. +pub struct Comment<'cx> { + #[skip_visit] + /// The combined content of all adjacent comments in the block. + pub content: &'cx str, + /// The span covering all merged comments. + pub span: ast::Span, + /// References to the original AST comments that were merged. + pub source_comments: &'cx [&'cx ast::Comment<'cx>], +} + +/// A top-level definition in the IR. +/// +/// Unlike AST ToplevelItem, IR definitions cannot be empty and must contain +/// a concrete definition kind. Comments are split into leading and trailing +/// to provide better structure for code generation and analysis. +#[derive(Debug, PartialEq, Visit)] +pub struct Definition<'cx> { + /// Comment appearing before this definition. + pub comment_before: Option>, + /// Comment appearing after this definition on the same line. + pub comment_trailing: Option>, + /// The actual definition content. + pub kind: DefinitionKind<'cx>, +} + +#[derive(Debug, PartialEq, Visit)] +/// A sequence of statements in the IR with mutable data storage. +pub struct Scope<'cx> { + /// The statements in this scope, stored as a vector for mutability. + pub items: Vec>, +} + +#[derive(Debug, Clone, Copy, Visit, PartialEq)] +/// A resolved path reference to a definition or module item. +pub struct ResolvedPath<'cx> { + /// The resolved item. + pub item: ResolvedItem<'cx>, + /// The original path that was resolved. + pub original_path: &'cx ast::Path<'cx>, +} + +#[derive(Debug, Clone, Copy, Visit, PartialEq)] +/// The resolved item - either a module item, local variable, or external reference. +pub enum ResolvedItem<'cx> { + /// Reference to a module item (types, functions, constants from modules). + ModuleItem(opslang_module::version::v1::ModuleItem<'cx>), + /// Reference to a local variable (function parameters, local bindings). + LocalVariable(opslang_ty::version::v1::Ident<'cx>), + /// Reference to an external path resolved via an external resolver. + External, + /// Temporary placeholder for unresolved external functions during type checking. + /// + /// FIXME: This should be removed once proper module system are implemented. + Main, +} + +#[derive(Debug, PartialEq, Visit)] +/// A typed expression in the IR. +/// +/// This is the core difference from AST expressions - IR expressions carry +/// type information from the type inference process. +pub struct Expr<'cx> { + /// The expression kind/content. + pub kind: ExprMut<'cx>, + /// The inferred type of this expression. + pub ty: Ty<'cx>, +} + +impl<'cx> Expr<'cx> { + pub fn new(kind: ExprMut<'cx>, ty: Ty<'cx>) -> Self { + Self { kind, ty } + } +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A parsed string literal in the IR. +pub struct String<'cx> { + #[skip_visit] + /// The parsed string value (escape sequences processed). + pub value: &'cx str, + /// Reference to the original AST string. + pub ast: &'cx ast::literal::String<'cx>, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A parsed bytes literal in the IR. +pub struct Bytes<'cx> { + #[skip_visit] + /// The parsed byte array. + pub value: &'cx [u8], + /// Reference to the original AST bytes literal. + pub ast: &'cx ast::literal::Bytes<'cx>, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A parsed hexadecimal bytes literal in the IR. +pub struct HexBytes<'cx> { + #[skip_visit] + /// The parsed byte array from hex representation. + pub value: &'cx [u8], + /// Reference to the original AST hex bytes literal. + pub ast: &'cx ast::literal::HexBytes<'cx>, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A parsed datetime literal in the IR. +pub struct DateTime<'cx> { + #[skip_visit] + /// The parsed datetime value. + pub value: chrono::DateTime, + /// Reference to the original AST datetime literal. + pub ast: &'cx ast::literal::DateTime<'cx>, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +/// A parsed numeric literal in the IR. +pub struct Numeric<'cx> { + /// The value. + pub kind: NumericKind<'cx>, + /// Reference to the original AST numeric literal. + pub ast: &'cx ast::literal::Numeric<'cx>, +} + +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +#[skip_all_visit] +/// A parsed numeric literal in the IR. +pub enum NumericKind<'cx> { + /// Signed integer with unified i64 representation. + Int(i64), + + /// Unsigned integer with unified u64 representation. + Uint(u64), + + /// Floating point with unified u64 bits representation. + Float(u64), + + Duration(chrono::Duration), + + Repr(&'cx str), +} + +#[derive(Debug, PartialEq, Visit)] +/// A function application in the IR. +/// +/// This includes qualifications that were resolved from Qualif and PreQualified +/// expressions in the AST. +pub struct Apply<'cx> { + /// The function being called. + pub function: Expr<'cx>, + /// The function arguments. + pub args: Vec>, + /// Qualifications applied to this call (resolved from AST Qualif/PreQualified). + pub qualifications: Vec>, + /// The resolved function definition. + pub resolved_function: Option>, +} + +#[derive(Debug, PartialEq, Visit)] +pub struct Compare<'cx> { + pub head: Expr<'cx>, + pub tail_with_op: Vec>, +} + +/// Obtain the representative type of this node. +pub trait Typed<'cx> { + /// The type of this node, can be optional if the node may not have a type. + type Ty; + + /// Get the type of this node. + fn ty(&self, cx: &'cx TypingContext<'cx>) -> Self::Ty; +} + +impl<'cx, F: ast::TypeFamily<'cx>> Typed<'cx> for ast::Block<'cx, F> { + type Ty = Option>; + fn ty(&self, _cx: &'cx TypingContext<'cx>) -> Self::Ty { + None + } +} + +impl<'cx, F: ast::TypeFamily<'cx>> Typed<'cx> for ast::Scope<'cx, F> { + type Ty = Option>; + fn ty(&self, _cx: &'cx TypingContext<'cx>) -> Self::Ty { + // FIXME: the last item type + None + } +} + +impl<'cx, F: ast::TypeFamily<'cx>> Typed<'cx> for ast::ScopeItem<'cx, F> { + type Ty = Option>; + fn ty(&self, _cx: &'cx TypingContext<'cx>) -> Self::Ty { + // FIXME: Block can have types + None + } +} + +impl<'cx, F: ast::TypeFamily<'cx>> Typed<'cx> for ast::Statement<'cx, F> { + type Ty = Ty<'cx>; + fn ty(&self, cx: &'cx TypingContext<'cx>) -> Self::Ty { + match self { + ast::Statement::Let(let_stmt) => let_stmt.ty(cx), + ast::Statement::Expr(expr_stmt) => expr_stmt.ty(cx), + ast::Statement::Return(_) => Ty::mk_unit(cx), + } + } +} + +impl<'cx, F: ast::TypeFamily<'cx>> Typed<'cx> for ast::Let<'cx, F> { + type Ty = Ty<'cx>; + fn ty(&self, cx: &'cx TypingContext<'cx>) -> Self::Ty { + Ty::mk_unit(cx) + } +} + +impl<'cx, F: ast::TypeFamily<'cx>> Typed<'cx> for ast::ExprStatement<'cx, F> { + type Ty = Ty<'cx>; + fn ty(&self, cx: &'cx TypingContext<'cx>) -> Self::Ty { + Ty::mk_unit(cx) + } +} + +impl<'cx> Typed<'cx> for Expr<'cx> { + type Ty = Ty<'cx>; + fn ty(&self, _cx: &'cx TypingContext<'cx>) -> Self::Ty { + self.ty + } +} + +impl<'cx> Typed<'cx> for Scope<'cx> { + type Ty = Option>; + fn ty(&self, _cx: &'cx TypingContext<'cx>) -> Self::Ty { + // FIXME: the last item type + None + } +} diff --git a/structure/opslang-ir/src/version/v1/binop.rs b/structure/opslang-ir/src/version/v1/binop.rs new file mode 100644 index 0000000..da463a7 --- /dev/null +++ b/structure/opslang-ir/src/version/v1/binop.rs @@ -0,0 +1,210 @@ +use super::*; + +/// IR-specific binary operation that replaces AST BinOp. +/// +/// Unlike AST BinOp which only has token information, IR BinOp contains +/// resolved type information for builtin operations. +/// +/// FIXME: consider adding these variants into TypeFamily directly to avoid copying +/// structure. +#[derive(Debug, PartialEq, Clone, Copy, Visit)] +#[skip_all_visit] +pub enum BinOp<'cx> { + /// Logical AND operation (unchanged from AST) + And { + span: token::AndAnd<'cx, IrTypeFamily>, + }, + /// Logical OR operation (unchanged from AST) + Or { + span: token::OrOr<'cx, IrTypeFamily>, + }, + /// Multiplication operation (unchanged from AST) + Mul { + kind: BuiltinMul, + span: token::Star<'cx, IrTypeFamily>, + }, + /// Division operation (unchanged from AST) + Div { + kind: BuiltinDiv, + span: token::Slash<'cx, IrTypeFamily>, + }, + /// Modulo operation (unchanged from AST) + Mod { + span: token::Percent<'cx, IrTypeFamily>, + }, + + /// Builtin addition with resolved types + Add { + kind: BuiltinAdd, + span: token::Plus<'cx, IrTypeFamily>, + }, + /// Builtin subtraction with resolved types + Sub { + kind: BuiltinSub, + span: token::Hyphen<'cx, IrTypeFamily>, + }, +} + +impl<'cx> BinOp<'cx> { + pub fn result_ty(&self, cx: &'cx TypingContext<'cx>) -> Ty<'cx> { + match self { + BinOp::And { .. } | BinOp::Or { .. } => Ty::mk_bool(cx), + BinOp::Mul { kind, .. } => kind.result_ty(cx), + BinOp::Div { kind, .. } => kind.result_ty(cx), + BinOp::Mod { .. } => Ty::mk_i64(cx), + BinOp::Add { kind, .. } => kind.result_ty(cx), + BinOp::Sub { kind, .. } => kind.result_ty(cx), + } + } +} + +impl<'cx> Typed<'cx> for BinOp<'cx> { + type Ty = Ty<'cx>; + + fn ty(&self, cx: &'cx TypingContext<'cx>) -> Self::Ty { + self.result_ty(cx) + } +} + +/// Represents the operand types supported by builtin add and subtract operations. +/// +/// This enum defines the valid type combinations for addition and subtraction operations, +/// including integer + integer, float + float, Duration + Duration, and datetime arithmetic. +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum BuiltinAddSubOperand { + /// Integer addition/subtraction: integer + integer + Int(MagmaTriad), + /// Unsigned integer + Unsigned integer + Uint(MagmaTriad), + /// Float addition/subtraction: float + float + /// Mixed FloatTy are permitted, output type uses larger bit width + Float(MagmaTriad), + /// Duration addition/subtraction: Duration + Duration + DurationDuration, + /// DateTime + Duration + DateTimeDuration, + /// Duration + DateTime + DurationDateTime, +} + +impl BuiltinAddSubOperand { + pub fn result_ty<'cx>(&self, cx: &'cx TypingContext<'cx>) -> Ty<'cx> { + match self { + BuiltinAddSubOperand::Int(triad) => Ty::mk_int(cx, triad.result_ty), + BuiltinAddSubOperand::Uint(triad) => Ty::mk_uint(cx, triad.result_ty), + BuiltinAddSubOperand::Float(triad) => Ty::mk_float(cx, triad.result_ty), + BuiltinAddSubOperand::DurationDuration => Ty::mk_duration(cx), + BuiltinAddSubOperand::DateTimeDuration => Ty::mk_time(cx), + BuiltinAddSubOperand::DurationDateTime => Ty::mk_time(cx), + } + } +} + +/// Builtin add operation with type information. +/// +/// This represents a resolved addition operation with specific operand types +/// determined during type checking. +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum BuiltinAdd { + /// Basic add operation with operand type information + Basic(BuiltinAddSubOperand), +} + +impl BuiltinAdd { + pub fn result_ty<'cx>(&self, cx: &'cx TypingContext<'cx>) -> Ty<'cx> { + match self { + BuiltinAdd::Basic(operand) => operand.result_ty(cx), + } + } +} + +/// Builtin subtract operation with type information. +/// +/// This represents a resolved subtraction operation with specific operand types +/// determined during type checking. +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum BuiltinSub { + /// Basic subtract operation with operand type information + Basic(BuiltinAddSubOperand), +} + +impl BuiltinSub { + pub fn result_ty<'cx>(&self, cx: &'cx TypingContext<'cx>) -> Ty<'cx> { + match self { + BuiltinSub::Basic(operand) => operand.result_ty(cx), + } + } +} + +/// Represents the operand types supported by builtin multiplication and division operations. +/// +/// This enum defines the valid type combinations for multiplication and division operations, +/// including integer * integer, float * float, and duration * integer. +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum BuiltinMulDivOperand { + /// Integer addition/subtraction: integer * integer. + Int(MagmaTriad), + /// Unsigned integer * unsigned integer. + Uint(MagmaTriad), + /// Float multiplication/division: float * float. + /// + /// Mixed FloatTy are permitted, output type uses larger bit width. + Float(MagmaTriad), + /// Duration * numeric. + DurationNumeric(ty::Numeric), +} + +impl BuiltinMulDivOperand { + pub fn result_ty<'cx>(&self, cx: &'cx TypingContext<'cx>) -> Ty<'cx> { + match self { + BuiltinMulDivOperand::Int(triad) => Ty::mk_int(cx, triad.result_ty), + BuiltinMulDivOperand::Uint(triad) => Ty::mk_uint(cx, triad.result_ty), + BuiltinMulDivOperand::Float(triad) => Ty::mk_float(cx, triad.result_ty), + BuiltinMulDivOperand::DurationNumeric(_) => Ty::mk_duration(cx), + } + } +} + +/// Builtin multiplication operation with type information. +/// +/// This represents a resolved multiplication operation with specific operand types +/// determined during type checking. +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum BuiltinMul { + /// Basic multiply operation with operand type information. + Basic(BuiltinMulDivOperand), +} + +impl BuiltinMul { + pub fn result_ty<'cx>(&self, cx: &'cx TypingContext<'cx>) -> Ty<'cx> { + match self { + BuiltinMul::Basic(operand) => operand.result_ty(cx), + } + } +} + +/// Builtin division operation with type information. +/// +/// This represents a resolved division operation with specific operand types +/// determined during type checking. +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum BuiltinDiv { + /// Basic divide operation with operand type information. + Basic(BuiltinMulDivOperand), +} + +impl BuiltinDiv { + pub fn result_ty<'cx>(&self, cx: &'cx TypingContext<'cx>) -> Ty<'cx> { + match self { + BuiltinDiv::Basic(operand) => operand.result_ty(cx), + } + } +} + +#[derive(Debug, PartialEq, Clone, Copy)] +/// Represents a triad of types for binary operations. +pub struct MagmaTriad { + pub lhs_ty: T, + pub rhs_ty: T, + pub result_ty: T, +} diff --git a/structure/opslang-ir/src/version/v1/context.rs b/structure/opslang-ir/src/version/v1/context.rs new file mode 100644 index 0000000..07a0968 --- /dev/null +++ b/structure/opslang-ir/src/version/v1/context.rs @@ -0,0 +1,179 @@ +use super::ast; +use super::{ + Apply, AstContext, Block, Bytes, Comment, DateTime, Definition, Expr, ExprKind, HexBytes, + Numeric, ResolvedPath, Row, String, +}; +use opslang_ty::version::v1::Ty; +use typed_arena::Arena; + +/// A context for constructing IR expressions with type information. +/// +/// This context wraps an AST context and adds additional allocation arenas +/// for IR-specific types that include type information and resolved names. +#[derive(Default)] +pub struct Context<'cx> { + /// Underlying AST context for basic allocations + ast_context: AstContext<'cx>, + + /// Arena for IR-specific comment blocks + comment_arena: Arena>, + + /// Arena for IR-specific string literals + string_arena: Arena>, + + /// Arena for IR-specific bytes literals + bytes_arena: Arena>, + + /// Arena for IR-specific hex bytes literals + hex_bytes_arena: Arena>, + + /// Arena for IR-specific datetime literals + datetime_arena: Arena>, + + /// Arena for IR-specific numeric literals + numeric_arena: Arena>, + + /// Arena for IR-specific apply expressions + apply_arena: Arena>, + + /// Arena for IR-specific expressions with types + expr_arena: Arena>, + + /// Arena for resolved path references + resolved_path_arena: Arena>, + + /// Arena for IR definitions + definition_arena: Arena>, + + /// Arena for AST comment references (for source_comments in IR Comment) + ast_comment_arena: Arena<&'cx ast::Comment<'cx>>, +} + +impl<'cx> std::ops::Deref for Context<'cx> { + type Target = AstContext<'cx>; + + fn deref(&self) -> &Self::Target { + &self.ast_context + } +} + +impl<'cx> Context<'cx> { + /// Creates a new IR context. + pub fn new() -> Self { + Self::default() + } + + /// Gets a reference to the underlying AST context. + /// + /// Note: the result of this method is not a pure ast context. To create an ast node + /// for example, use `ast::context::Context::new()` instead. + pub fn ast_context(&self) -> &AstContext<'cx> { + &self.ast_context + } + + /// Allocates a string in the context. + pub fn alloc_str(&'cx self, string: &str) -> &'cx str { + self.ast_context.alloc_str(string) + } + + /// Allocates bytes in the context. + pub fn alloc_bytes(&'cx self, bytes: &[u8]) -> &'cx [u8] { + self.ast_context.alloc_bytes(bytes) + } + + /// Allocates an IR comment block. + pub fn alloc_comment(&'cx self, comment: Comment<'cx>) -> &'cx Comment<'cx> { + self.comment_arena.alloc(comment) + } + + /// Allocates an IR string literal. + pub fn alloc_string(&'cx self, string: String<'cx>) -> &'cx String<'cx> { + self.string_arena.alloc(string) + } + + /// Allocates an IR bytes literal. + pub fn alloc_bytes_literal(&'cx self, bytes: Bytes<'cx>) -> &'cx Bytes<'cx> { + self.bytes_arena.alloc(bytes) + } + + /// Allocates an IR hex bytes literal. + pub fn alloc_hex_bytes(&'cx self, hex_bytes: HexBytes<'cx>) -> &'cx HexBytes<'cx> { + self.hex_bytes_arena.alloc(hex_bytes) + } + + /// Allocates an IR datetime literal. + pub fn alloc_datetime(&'cx self, datetime: DateTime<'cx>) -> &'cx DateTime<'cx> { + self.datetime_arena.alloc(datetime) + } + + /// Allocates an IR numeric literal. + pub fn alloc_numeric(&'cx self, numeric: Numeric<'cx>) -> &'cx Numeric<'cx> { + self.numeric_arena.alloc(numeric) + } + + /// Allocates an IR apply expression. + pub fn alloc_apply(&'cx self, apply: Apply<'cx>) -> &'cx Apply<'cx> { + self.apply_arena.alloc(apply) + } + + /// Allocates an IR expression with type information. + pub fn alloc_expr(&'cx self, expr: Expr<'cx>) -> &'cx Expr<'cx> { + self.expr_arena.alloc(expr) + } + + /// Allocates a resolved path reference. + pub fn alloc_resolved_path( + &'cx self, + resolved_path: ResolvedPath<'cx>, + ) -> &'cx ResolvedPath<'cx> { + self.resolved_path_arena.alloc(resolved_path) + } + + /// Allocates an IR definition in the IR context. + pub fn alloc_definition(&'cx self, definition: Definition<'cx>) -> &'cx Definition<'cx> { + self.definition_arena.alloc(definition) + } + + /// Allocates a slice of IR definitions. + pub fn alloc_definition_slice( + &'cx self, + definitions: Vec>, + ) -> &'cx [Definition<'cx>] { + self.definition_arena.alloc_extend(definitions) + } + + /// Allocates a slice of AST comment references for IR Comment source_comments. + pub fn alloc_ast_comment_slice( + &'cx self, + comments: &[&'cx ast::Comment<'cx>], + ) -> &'cx [&'cx ast::Comment<'cx>] { + self.ast_comment_arena + .alloc_extend(comments.iter().copied()) + } + + /// Allocates a row using the underlying AST context. + pub fn alloc_row(&'cx self, row: Row<'cx>) -> &'cx Row<'cx> { + self.ast_context.alloc_row(row) + } + + /// Allocates a block using the underlying AST context. + pub fn alloc_block(&'cx self, block: Block<'cx>) -> &'cx Block<'cx> { + self.ast_context.alloc_block(block) + } + + /// Creates an IR expression with type information from expression kind and type. + /// + /// This method first uses the AST context to allocate the expression kind, + /// then creates an IR expression with the provided type information. + pub fn alloc_expr_with_type( + &'cx self, + ir_expr_kind: ExprKind<'cx>, + expected_type: Ty<'cx>, + ) -> Expr<'cx> { + let expr_ref = self.ast_context.alloc_expr_mut(ir_expr_kind); + Expr { + kind: expr_ref, + ty: expected_type, + } + } +} diff --git a/structure/opslang-ir/src/version/v1/ir_consistency_check.rs b/structure/opslang-ir/src/version/v1/ir_consistency_check.rs new file mode 100644 index 0000000..c369693 --- /dev/null +++ b/structure/opslang-ir/src/version/v1/ir_consistency_check.rs @@ -0,0 +1,56 @@ +//! Compile-time consistency check for IR types registry. +//! +//! This module performs a compile-time verification that all IR types defined in the +//! centralized registry (`opslang_ir_macro::ir_types`) actually exist and are accessible +//! from this v1 child module context using appropriate paths. +//! +//! # Purpose +//! +//! The IR types registry in `opslang-ir-macro/src/visitor_type_registry.rs` maintains a comprehensive +//! list of all IR-related node types from multiple crates (opslang-ast, opslang-ir, opslang-ty) +//! for use by procedural macros. However, this registry is independent of the actual type +//! definitions across these crates, creating a potential source of inconsistency. +//! +//! This design weakness cannot be avoided due to architectural constraints, but this +//! compile-time check helps detect inconsistencies early through compilation errors +//! and comments that guide developers when types are added, removed, or renamed. +//! +//! # Implementation +//! +//! The macro call below generates compile-time type checks in the form: +//! ```ignore +//! const _: () = { +//! fn check<'cx>() { +//! let _: super::Program<'cx, super::IrTypeFamily>; +//! let _: super::Expr<'cx>; +//! let _: super::ResolvedPath<'cx>; +//! let _: ::opslang_ast::syntax::v1::Comment<'cx>; +//! let _: ::opslang_ty::version::v1::Ty<'cx>; +//! // ... for each type in the registry +//! } +//! }; +//! ``` +//! +//! # Guarantees +//! +//! Successful compilation of this module ensures: +//! 1. **Cross-crate Type Existence**: All types in the IR registry exist across referenced crates +//! 2. **Path Accessibility**: All types are accessible from v1 child module context using appropriate paths +//! 3. **Type Family Compatibility**: All types accept the expected lifetime and type family parameters +//! 4. **Registry Consistency**: The centralized type registry matches actual type definitions across multiple crates +//! +//! # Maintenance +//! +//! When adding, removing, or renaming IR-related types across any crate: +//! 1. Update the actual type definitions in the respective crates (opslang-ast, opslang-ir, opslang-ty) +//! 2. Update the registry in `opslang-ir-macro/src/visitor_type_registry.rs` +//! 3. Ensure this compilation check continues to pass +//! +//! If this check fails, it indicates a mismatch between the registry and actual definitions +//! that must be resolved to maintain consistency across the entire IR ecosystem. + +// Note: This macro call is skipped during test compilation because doctests +// change the module context, causing `super` paths in the generated code +// to fail resolution. The consistency check still runs during normal builds. +#[cfg(not(test))] +opslang_ir_macro::ir_consistency_check!(); diff --git a/structure/opslang-ir/src/version/v1/visit.rs b/structure/opslang-ir/src/version/v1/visit.rs new file mode 100644 index 0000000..08293d2 --- /dev/null +++ b/structure/opslang-ir/src/version/v1/visit.rs @@ -0,0 +1,5 @@ +#[opslang_ir_macro::v1_declare_ir_visitor_trait] +pub trait IrVisitor<'cx> {} + +#[opslang_ir_macro::v1_declare_ir_visitor_mut_trait] +pub trait IrMutVisitor<'cx> {} diff --git a/structure/opslang-ir/tests/v1_visitor_integration.rs b/structure/opslang-ir/tests/v1_visitor_integration.rs new file mode 100644 index 0000000..5d9b1c3 --- /dev/null +++ b/structure/opslang-ir/tests/v1_visitor_integration.rs @@ -0,0 +1,30 @@ +//! Integration tests for v1 IR visitor functionality +//! These tests create simple IR structures and test visitor behavior + +use opslang_ty::version::v1::{Ty, TypingContext}; + +#[derive(Default)] +struct SimpleIrVisitor { + ty_count: usize, +} + +// Start with just one visitor implementation to test the basic functionality +opslang_ir_macro::v1_ir_visitor_impl!(for SimpleIrVisitor { + fn visit_ty(&mut self, _node: &Ty<'cx>) { + self.ty_count += 1; + } +}); + +#[test] +fn test_simple_ir_visitor_ty() { + // Create a simple test to verify the basic visitor mechanism works + let visitor = SimpleIrVisitor::default(); + + // Create a typing context for testing + let _typing_context = TypingContext::new(); + + // For now, just verify the visitor struct was created successfully + assert_eq!(visitor.ty_count, 0); + + // We'll expand this once we verify the macro compilation works +} diff --git a/structure/opslang-ir/tests/visitor_consistency.rs b/structure/opslang-ir/tests/visitor_consistency.rs new file mode 100644 index 0000000..9bdfc27 --- /dev/null +++ b/structure/opslang-ir/tests/visitor_consistency.rs @@ -0,0 +1,110 @@ +//! Visitor implementation consistency tests for IR types. +//! +//! This test file validates that the IR visitor implementation macros can generate +//! valid code for empty visitor definitions. This serves as a structural consistency +//! check for the IR type registry and visitor implementation logic across multiple +//! crates (opslang-ast, opslang-ir, opslang-ty). +//! +//! # Purpose +//! +//! Empty visitor definitions are particularly valuable for testing because they +//! exercise the complete visitor generation machinery without any custom logic: +//! +//! 1. **Cross-crate Type Registry Validation**: All types in `visitor_type_registry.rs` from +//! multiple crates must exist and be accessible for the macro to generate +//! visitor methods. +//! +//! 2. **Method Generation Logic**: The visitor implementation macro must correctly +//! generate method signatures and default implementations for all IR types, +//! including proper type family substitutions. +//! +//! 3. **Path Resolution**: All type paths used in generated code must resolve +//! correctly from the visitor implementation context, including external +//! crate references. +//! +//! # Failure Scenarios +//! +//! If any test in this file fails to compile, it indicates one of these issues: +//! +//! - **Registry Inconsistency**: A type listed in `visitor_type_registry.rs` doesn't exist +//! or has been renamed/moved without updating the registry across any of the +//! referenced crates (opslang-ast, opslang-ir, opslang-ty). +//! +//! - **Visitor Implementation Bug**: The `visitor_impl.rs` macro has a bug in +//! method signature generation, path construction, or code generation logic +//! for cross-crate type references. +//! +//! - **Type Path Issues**: Generated visitor methods reference types using +//! incorrect paths that don't resolve in the current module context, especially +//! for types from external crates. +//! +//! - **Type Family Issues**: IR type family substitutions are incorrect, causing +//! type parameter mismatches in generated visitor methods. +//! +//! These tests complement the compile-time consistency checks by validating +//! the end-to-end visitor generation pipeline rather than just type existence. + +/// Empty IR visitor to test basic immutable visitor generation without custom implementations. +/// +/// This visitor defines no custom visit methods, relying entirely on the macro +/// to generate all required visitor trait implementations. Successful compilation +/// indicates that: +/// +/// 1. All IR types in the registry are accessible and properly defined across crates +/// 2. The visitor macro can generate syntactically correct method signatures +/// 3. Default traversal implementations compile without errors +/// 4. Type paths resolve correctly in the generated code for cross-crate references +/// 5. Type family substitutions work correctly for AST types used in IR context +struct EmptyIrVisitor; + +opslang_ir_macro::v1_ir_visitor_impl!(for EmptyIrVisitor { + // Intentionally empty - this tests that the macro can generate + // complete visitor implementations with no custom methods +}); + +/// Empty mutable IR visitor to test basic mutable visitor generation. +/// +/// This visitor tests the mutable visitor generation pipeline, ensuring that +/// mutable references and traversal work correctly across all IR types. +struct EmptyIrMutVisitor; + +opslang_ir_macro::v1_ir_visitor_impl!(for EmptyIrMutVisitor { + // Intentionally empty - this tests that the macro can generate + // complete mutable visitor implementations with no custom methods +}); + +/// Test that empty IR visitors implement the expected immutable visitor trait. +/// +/// This test validates that the generated visitor properly implements +/// the IrVisitor trait, ensuring the macro generates complete and correct +/// implementations for immutable traversal. +#[test] +fn empty_ir_visitor_trait_implementation() { + use opslang_ir::version::v1::visit::IrVisitor; + + let visitor = EmptyIrVisitor; + + // Test that the visitor implements IrVisitor trait + // We can't actually call visit methods without constructing IR nodes, + // but we can verify the trait is implemented + fn _assert_implements_ir_visitor<'cx, T: IrVisitor<'cx>>(_: T) {} + _assert_implements_ir_visitor(visitor); +} + +/// Test that empty IR visitors implement the expected mutable visitor trait. +/// +/// This test validates that the generated visitor properly implements +/// the IrVisitorMut trait, ensuring the macro generates complete and correct +/// implementations for mutable traversal. +#[test] +fn empty_ir_mut_visitor_trait_implementation() { + use opslang_ir::version::v1::visit::IrMutVisitor; + + let visitor = EmptyIrMutVisitor; + + // Test that the visitor implements IrMutVisitor trait + // We can't actually call visit methods without constructing IR nodes, + // but we can verify the trait is implemented + fn _assert_implements_ir_mut_visitor<'cx, T: IrMutVisitor<'cx>>(_: T) {} + _assert_implements_ir_mut_visitor(visitor); +} diff --git a/structure/type-registry/Cargo.toml b/structure/type-registry/Cargo.toml new file mode 100644 index 0000000..8462b24 --- /dev/null +++ b/structure/type-registry/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "opslang-type-registry" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +syn.workspace = true +quote.workspace = true +proc-macro2.workspace = true +convert_case.workspace = true +opslang-visitor-macro-helper.workspace = true diff --git a/structure/type-registry/src/lib.rs b/structure/type-registry/src/lib.rs new file mode 100644 index 0000000..a3a6d96 --- /dev/null +++ b/structure/type-registry/src/lib.rs @@ -0,0 +1 @@ +pub mod v1; diff --git a/structure/type-registry/src/v1.rs b/structure/type-registry/src/v1.rs new file mode 100644 index 0000000..f4ae8f2 --- /dev/null +++ b/structure/type-registry/src/v1.rs @@ -0,0 +1,2 @@ +pub mod ast; +pub mod ir; diff --git a/structure/type-registry/src/v1/ast.rs b/structure/type-registry/src/v1/ast.rs new file mode 100644 index 0000000..533dde2 --- /dev/null +++ b/structure/type-registry/src/v1/ast.rs @@ -0,0 +1,55 @@ +//! AST Visitor Type Registry - Core type registry and interfaces for visitor generation. +//! +//! # Purpose +//! +//! This module serves as the **central hub** for AST visitor type management, containing: +//! +//! 1. **Type Registry**: Complete const-defined registries of all visitable AST types +//! 2. **Core Interfaces**: Primary type descriptors used by macro generation +//! 3. **Utility Modules**: Supporting infrastructure for type management +//! +//! # Registry Constants (The Heart of the System) +//! +//! - [`visitor_type_registry::NODE_TYPES`]: Complete registry of main AST node types +//! - [`visitor_type_registry::INTER_TYPES`]: Registry of intermediate/utility types +//! +//! These const-defined registries are the **single source of truth** for visitor generation. +//! +//! # Core Type Interfaces +//! +//! - [`types::AstNodeTy`]: Individual AST type descriptor (macro generation interface) +//! - [`types::AstInterTy`]: Intermediate type descriptor +//! +//! # Design Principle & Maintenance +//! +//! **When AST structures change in `opslang-ast`, you will almost certainly need to update these registries.** +//! +//! This visitor system requires **complete type coverage**: every type appearing in AST definitions +//! must be handled by one of three mechanisms: +//! 1. **Node types** (defined in this registry) +//! 2. **Intermediate types** (defined in this registry) +//! 3. **Generic types** (handled by `opslang-visitor-macro-helper`) +//! +//! Types marked with `skip_visit` attributes are automatically excluded from visitor generation. +//! +//! This macro-driven design makes maintenance **significantly easier** than manually editing +//! visitor implementations for every structural change. +//! +//! # Consistency Verification +//! +//! **Incomplete coverage is automatically detected**: If any type is missing from these registries, +//! compilation will fail in `opslang-ast/tests/visitor_consistency.rs`, providing clear error +//! messages about which types need to be added to the registry. +//! +//! # Module Structure +//! +//! - [`types`]: Multi-crate wrapper types and path generators +//! - [`const_compatible`]: Const-time construction for complex type hierarchies + +use syn::{Ident, Path, parse_quote}; + +pub mod const_compatible; +pub mod types; +pub mod visitor_type_registry; + +mod macro_def; diff --git a/structure/type-registry/src/v1/ast/const_compatible.rs b/structure/type-registry/src/v1/ast/const_compatible.rs new file mode 100644 index 0000000..a526118 --- /dev/null +++ b/structure/type-registry/src/v1/ast/const_compatible.rs @@ -0,0 +1,58 @@ +use std::fmt::Debug; + +use proc_macro2::Span; +use syn::Ident; + +use super::types::*; + +mod sealed { + pub trait Sealed {} +} + +pub trait ExecPhase: Clone + Copy + Debug + sealed::Sealed + TypeMap {} +impl

ExecPhase for P where P: Clone + Copy + Debug + sealed::Sealed + TypeMap {} + +#[derive(Clone, Copy, Debug)] +pub struct Const; +impl sealed::Sealed for Const {} + +#[derive(Clone, Copy, Debug)] +pub struct Runtime; +impl sealed::Sealed for Runtime {} + +pub trait TypeMap { + type Mapped: Debug; +} + +impl TypeMap for Runtime { + type Mapped = T; +} + +impl TypeMap for Const { + type Mapped = &'static str; +} + +pub type Mapped =

>::Mapped; + +impl AstNodeTy { + pub(super) fn parse(&self) -> AstNodeTy { + let Self { + name, + child: module_path, + } = self; + AstNodeTy { + name: Ident::new(name, Span::call_site()), + child: module_path.map(|child| Ident::new(child, Span::call_site())), + } + } +} + +impl AstInterTy { + pub(super) fn parse(&self) -> AstInterTy { + let Self { name, has_lifetime } = self; + AstInterTy { + name: Ident::new(name, Span::call_site()), + has_lifetime: *has_lifetime, + } + } +} diff --git a/structure/type-registry/src/v1/ast/macro_def.rs b/structure/type-registry/src/v1/ast/macro_def.rs new file mode 100644 index 0000000..d201aed --- /dev/null +++ b/structure/type-registry/src/v1/ast/macro_def.rs @@ -0,0 +1,56 @@ +#[macro_export] +/// Macro for defining AST node types using Rust-like syntax. +/// +/// Supports both top-level types and module-grouped types. +macro_rules! define_v1_ast_node_types { + ( + crate ast<'cx> { + $(type $name:ident;)* + $(mod $module:ident { + $(type $mod_name:ident;)* + })* + } + ) => { + &[ + $( + AstNodeTy { + name: stringify!($name), + child: None, + }, + )* + $( + $( + AstNodeTy { + name: stringify!($mod_name), + child: Some(stringify!($module)) + }, + )* + )* + ] + }; +} + +#[macro_export] +/// Macro for defining intermediate AST types with optional lifetime parameters. +macro_rules! define_v1_ast_inter_types { + ( + crate ast { + $(type $name:ident $(<$cx:lifetime>)?;)* + } + ) => { + &[ + $({ + #[allow(unused_mut)] + let mut t = AstInterTy { + name: stringify!($name), + has_lifetime: false, + }; + $( + stringify!($cx); + t.has_lifetime = true; + )? + t + },)* + ] + }; +} diff --git a/structure/type-registry/src/v1/ast/types.rs b/structure/type-registry/src/v1/ast/types.rs new file mode 100644 index 0000000..292f901 --- /dev/null +++ b/structure/type-registry/src/v1/ast/types.rs @@ -0,0 +1,231 @@ +//! Definitions needed for `visitor_type_registry`. + +use super::*; +use const_compatible::*; + +/// Represents a generic type in the AST that can be instantiated with a lifetime. +/// +/// # Invariants +/// +/// This struct represents a generic type from the `opslang-ast` crate that can be +/// instantiated with a lifetime parameter, conventionally `'cx`. +/// +/// The primary invariants are: +/// 1. The combination of `name` and `module_path` must form a valid path to a type +/// definition within the `opslang-ast` crate (e.g., `crate::syntax::v1::Stmt`). +/// 2. The referenced type must be a generic type that accepts exactly one lifetime +/// parameter. +/// 3. The type must be instantiable when provided with the `'cx` lifetime. For instance, +/// if the type is `path::to::TypeName`, then `path::to::TypeName<'cx>` must be a +/// valid, constructible type. +/// +/// This ensures that the procedural macros using this struct can correctly generate +/// code that references these lifetime-annotated AST types. +/// +/// # Context-specific types +/// +/// Different usage contexts have different requirements for path generation. +/// Use the context-specific newtypes instead of accessing `full_path()` or `type_path()` directly: +/// - [`OutsideAstCrateTy`] for external crate references +/// - [`InsideV1ChildModTy`] for relative references within the same crate + +#[derive(Debug)] +pub struct AstNodeTy { + pub(crate) name: Mapped, + pub(crate) child: Option>, +} + +impl opslang_visitor_macro_helper::shared_visitor_trait::VisitableType for AstNodeTy { + fn generate_visit_method_name( + &self, + kind: opslang_visitor_macro_helper::MethodKind, + _mode: opslang_visitor_macro_helper::VisitorMode, + ) -> String { + self.generate_visit_method_name(kind) + } + + fn full_type_path(&self) -> proc_macro2::TokenStream { + let super_qualified = self.inside_of_v1_child_mod(); + let type_path = super_qualified.super_path(); + quote::quote! { #type_path } + } +} + +impl AstNodeTy { + /// Convert to a crate-qualified type for external references. + /// + /// This creates a type that generates paths like `::opslang_ast::syntax::v1::Type<'cx>` + /// for use in contexts where the full crate path is needed. + pub const fn outside_of_ast_crate(&self) -> OutsideAstCrateTy<'_> { + OutsideAstCrateTy { inner: self } + } + + /// Convert to a super-qualified type for relative references. + /// + /// This creates a type that generates paths like `super::Type<'cx>` or `super::module::Type<'cx>` + /// for use in trait declarations within the same crate. + pub const fn inside_of_v1_child_mod(&self) -> InsideV1ChildModTy<'_> { + InsideV1ChildModTy { inner: self } + } + + /// Returns all AST types for v1 syntax including token types. + pub fn get_v1_ast_node_types() -> impl Iterator { + visitor_type_registry::NODE_TYPES + .iter() + .map(|ty| ty.parse()) + } +} + +/// Represents an intermediate AST type that may or may not have a lifetime parameter. +/// +/// These are typically utility types like `Span`, `BytePos`, or `NumericKind` used +/// throughout the AST but not part of the main visitor pattern. +#[derive(Debug)] +pub struct AstInterTy { + pub(crate) name: Mapped, + pub(crate) has_lifetime: bool, +} + +impl AstInterTy { + /// Convert to a crate-qualified type for external references. + pub const fn outside_of_ast_crate(&self) -> OutsideAstCrateInterTy<'_> { + OutsideAstCrateInterTy { inner: self } + } + + /// Returns all intermediate AST types for v1 syntax. + pub fn get_v1_ast_node_types() -> impl Iterator { + visitor_type_registry::INTER_TYPES + .iter() + .map(|ty| ty.parse()) + } +} + +/// A newtyped wrapper for [`AstNodeTy`] that ensures crate-qualified paths. +/// +/// This type generates paths like `::opslang_ast::syntax::v1::Type<'cx>` and is intended +/// for contexts where external crate references are needed, such as in visitor implementations +/// that reference types from outside the current crate. +#[derive(Clone, Debug)] +pub struct OutsideAstCrateTy<'a> { + pub(super) inner: &'a AstNodeTy, +} + +impl OutsideAstCrateTy<'_> { + /// Generate fully qualified path with crate prefix. + /// + /// Returns a string like `::opslang_ast::syntax::v1::Type<'cx>` suitable for + /// external references to AST types. + pub fn full_crate_path(&self) -> syn::Path { + self.inner.full_path() + } +} + +/// A newtyped wrapper for [`AstNodeTy`] that ensures super-qualified paths. +/// +/// This type generates paths like `super::Type<'cx>` or `super::module::Type<'cx>` and is +/// intended for contexts where relative references within the same crate are appropriate, +/// such as in trait declarations. +#[derive(Clone, Debug)] +pub struct InsideV1ChildModTy<'a> { + pub(super) inner: &'a AstNodeTy, +} + +impl InsideV1ChildModTy<'_> { + /// Generate super-qualified token stream path. + /// + /// Returns a [`proc_macro2::TokenStream`] representing paths like `super::Type<'cx>` + /// suitable for relative references within the same crate. + pub fn super_path(&self) -> proc_macro2::TokenStream { + self.inner.relative_path() + } +} + +/// A newtyped wrapper for [`AstInterTy`] that ensures crate-qualified paths. +#[derive(Clone, Debug)] +pub struct OutsideAstCrateInterTy<'a> { + pub(super) inner: &'a AstInterTy, +} + +impl OutsideAstCrateInterTy<'_> { + /// Generate fully qualified path with crate prefix. + pub fn full_path(&self) -> Path { + self.inner.full_path() + } +} + +impl AstNodeTy { + /// Generate full path for this type with proper module qualification. + /// + /// # Private + /// + /// This method is private to prevent direct usage. Use [`AstNodeTy::outside_of_ast_crate`] + /// or [`AstNodeTy::inside_of_v1_child_mod`] to get context-appropriate types. + fn full_path(&self) -> syn::Path { + let str = match &self.child { + Some(child) => format!("::opslang_ast::syntax::v1::{child}::{}<'cx>", self.name), + None => format!("::opslang_ast::syntax::v1::{}<'cx>", self.name), + }; + syn::parse_str(&str).unwrap() + } + + /// Generate syn path for this type with proper module qualification. + /// + /// # Private + /// + /// This method is private to prevent direct usage. Use [`AstNodeTy::outside_of_ast_crate`] + /// or [`AstNodeTy::inside_of_v1_child_mod`] to get context-appropriate types. + fn relative_path(&self) -> proc_macro2::TokenStream { + use quote::quote; + let name = &self.name; + match &self.child { + Some(child) => { + quote! { super::#child::#name<'cx> } + } + None => quote! { super::#name<'cx> }, + } + } + + /// Generate appropriate method name based on the type and method kind. + /// If module_path exists, generates `{prefix}_{module}_{name}`, otherwise `{prefix}_{name}`. + pub fn generate_visit_method_name( + &self, + kind: opslang_visitor_macro_helper::MethodKind, + ) -> String { + use convert_case::{Case, Casing}; + + let snake_name = self.name.to_string().to_case(Case::Snake); + let prefix = match kind { + opslang_visitor_macro_helper::MethodKind::Visit => "visit", + opslang_visitor_macro_helper::MethodKind::Super => "super", + }; + + if let Some(module) = &self.child { + let snake_module = module.to_string(); + format!("{prefix}_{snake_module}_{snake_name}") + } else { + format!("{prefix}_{snake_name}") + } + } +} + +impl AstInterTy { + /// Generate full crate path for this intermediate type. + fn full_path(&self) -> Path { + let name = &self.name; + if self.has_lifetime { + parse_quote!(::opslang_ast::syntax::v1::#name<'cx>) + } else { + parse_quote!(::opslang_ast::syntax::v1::#name) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ident_safe() { + let _ast_node_types = AstNodeTy::get_v1_ast_node_types(); + } +} diff --git a/structure/type-registry/src/v1/ast/visitor_type_registry.rs b/structure/type-registry/src/v1/ast/visitor_type_registry.rs new file mode 100644 index 0000000..589dfa7 --- /dev/null +++ b/structure/type-registry/src/v1/ast/visitor_type_registry.rs @@ -0,0 +1,140 @@ +/// Complete registry of all AST node types for v1 syntax. +/// +/// # Maintenance Guide +/// +/// **IMPORTANT**: When you add, remove, or rename types in `opslang-ast/src/syntax/v1/`: +/// +/// 1. **Adding a type**: Add it to the appropriate section below (main types or token module) +/// 2. **Removing a type**: Remove it from this list +/// 3. **Renaming a type**: Update the name here to match +/// 4. **Moving to/from a module**: Update the module structure accordingly +/// +/// This registry drives visitor method generation - missing types won't have visitor methods, +/// and stale entries will cause compilation errors. +pub const NODE_TYPES: &[AstNodeTy] = crate::define_v1_ast_node_types! { + crate ast<'cx> { + // Main types + type Program; + type ToplevelItem; + type DefinitionKind; + type FunctionDef; + type Parameter; + type FnReturnTy; + type ConstantDef; + type Scope; + type ScopeItem; + type Row; + type Comment; + type Block; + type Statement; + type Let; + type ExprStatement; + type ReturnStmt; + type Expr; + type Path; + type Ident; + type Qualif; + type Modifier; + type ModifierParam; + type DefaultModifier; + type Parened; + type PreQualified; + type Unary; + type UnOp; + type Compare; + type CompareOp; + type CompareOpExpr; + type NotEqualToken; + type Binary; + type BinOp; + type Apply; + type Set; + type Cast; + type InfixImport; + type If; + type IfElse; + type Call; + type Wait; + type Select; + + // Literal types + type Literal; + type Array; + type String; + type Bytes; + type HexBytes; + type Numeric; + type NumericSuffix; + type DateTime; + + // Token types + mod token { + type Semi; + type Break; + type Atmark; + type Tilde; + type Colon; + type Eq; + type OpenBrace; + type CloseBrace; + type OpenParen; + type CloseParen; + type OpenSquare; + type CloseSquare; + type Hyphen; + type Ampersand; + type Dollar; + type Question; + type RightAngle; + type Angle; + type Star; + type Slash; + type Percent; + type Plus; + type BangEqual; + type SlashEqual; + type EqualEqual; + type RightAngleEq; + type AngleEq; + type ColonEq; + type AndAnd; + type OrOr; + type Arrow; + type DoubleArrow; + type Return; + type Let; + type As; + type If; + type Else; + type Call; + type Wait; + type Select; + type Prc; + type Const; + } + } +}; + +/// Registry of intermediate AST types for v1 syntax. +/// +/// # Maintenance Guide +/// +/// These are utility types like `Span`, `BytePos`, `NumericKind` that need visitor +/// implementations but are not primary AST nodes. +/// +/// **When structures change**: You will almost certainly need to update this registry. +/// **Incomplete coverage**: Will cause compilation failures in `opslang-ast/tests/visitor_consistency.rs` +pub const INTER_TYPES: &[AstInterTy] = crate::define_v1_ast_inter_types! { + crate ast { + type DefaultTypeFamily; + type Span; + type BytePos; + type NumericKind; + type ExprKind<'cx>; + type SelectItem<'cx>; + } +}; + +use super::*; +use const_compatible::*; +use types::*; diff --git a/structure/type-registry/src/v1/ir.rs b/structure/type-registry/src/v1/ir.rs new file mode 100644 index 0000000..224367d --- /dev/null +++ b/structure/type-registry/src/v1/ir.rs @@ -0,0 +1,63 @@ +//! IR Visitor Type Registry - Multi-crate type registry and interfaces for IR visitor generation. +//! +//! # Purpose +//! +//! This module serves as the **comprehensive hub** for IR visitor type management across +//! multiple crates. It handles the complex orchestration of types from: +//! +//! - **AST types** (`opslang-ast`): With type family substitution (default or IR) +//! - **IR types** (`opslang-ir`): Native IR representations +//! - **Ty types** (`opslang-ty`): Type system representations +//! +//! # Registry Constants (Multi-Crate Registry) +//! +//! - [`visitor_type_registry::NODE_TYPES`]: Complete registry spanning all three crates +//! - [`visitor_type_registry::INTER_TYPES`]: Intermediate types with wrapper and external type support +//! +//! These const-defined registries manage the **complex multi-crate type ecosystem** for IR. +//! +//! # Core Type Interfaces +//! +//! - [`types::IrNodeTy`]: Multi-crate type descriptor with type family substitution +//! - [`types::IrInterTy`]: Advanced intermediate type with wrapper support +//! - [`types::InstanceKind`]: Crate origin and type family specification +//! - [`types::TypeSubstitution`]: Type family substitution control +//! +//! # Design Principle +//! +//! **When structures change in `opslang-ast`, `opslang-ir`, or `opslang-ty`, you will almost +//! certainly need to update these registries.** +//! +//! This visitor system requires **complete type coverage** across all three crates: every type +//! appearing in IR-context definitions must be handled by one of three mechanisms: +//! 1. **Node types** (defined in this registry with proper crate mapping) +//! 2. **Intermediate types** (defined in this registry with wrapper support) +//! 3. **Generic types** (handled by `opslang-visitor-macro-helper`) +//! +//! The multi-crate nature adds complexity through type family substitutions and crate classifications, +//! but this macro-driven approach still provides **significantly easier maintenance** than manual +//! visitor implementation updates. +//! +//! # Consistency Verification +//! +//! **Incomplete coverage is automatically detected**: If any type is missing from these registries, +//! compilation will fail in `opslang-ir/tests/visitor_consistency.rs`, providing clear error +//! messages about which types need to be added to the registry. +//! +//! # Module Structure +//! +//! - [`types`]: Multi-crate wrapper types and path generators +//! - [`const_compatible`]: Const-time construction for complex type hierarchies + +use proc_macro2::Span; +use std::{borrow::Cow, fmt::Debug}; +use syn::{ + AngleBracketedGenericArguments, GenericArgument, Ident, Path, Token, parse_quote, + punctuated::Punctuated, +}; + +pub mod const_compatible; +pub mod types; +pub mod visitor_type_registry; + +mod macro_def; diff --git a/structure/type-registry/src/v1/ir/const_compatible.rs b/structure/type-registry/src/v1/ir/const_compatible.rs new file mode 100644 index 0000000..af58108 --- /dev/null +++ b/structure/type-registry/src/v1/ir/const_compatible.rs @@ -0,0 +1,103 @@ +use std::fmt::Debug; + +use super::types::*; +use super::*; + +mod sealed { + pub trait Sealed {} +} + +pub trait ExecPhase: + Clone + + Copy + + Debug + + sealed::Sealed + + TypeMap + + TypeMap + + TypeMap + + TypeMap +{ +} +impl

ExecPhase for P where + P: Clone + + Copy + + Debug + + sealed::Sealed + + TypeMap + + TypeMap + + TypeMap + + TypeMap +{ +} + +#[derive(Clone, Copy, Debug)] +pub struct Const; +impl sealed::Sealed for Const {} + +#[derive(Clone, Copy, Debug)] +pub struct Runtime; +impl sealed::Sealed for Runtime {} + +pub trait TypeMap { + type Mapped: Debug; +} + +impl TypeMap for Runtime { + type Mapped = T; +} + +impl TypeMap for Const { + type Mapped = &'static str; +} +impl TypeMap for Const { + type Mapped = &'static str; +} +impl TypeMap for Const { + type Mapped = Option; +} +impl TypeMap for Const { + type Mapped = Option; +} + +pub type Mapped =

>::Mapped; + +impl IrNodeTy { + pub(super) fn parse(&self) -> IrNodeTy { + let Self { name, child, ty } = self; + IrNodeTy { + name: Ident::new(name, Span::call_site()), + child: child.map(|child| Ident::new(child, Span::call_site())), + ty: ty.unwrap(), + } + } +} + +impl IrInterTy { + pub(super) fn parse(&self) -> IrInterTy { + match self { + IrInterTy::Instance(ir_inter_ty_instance) => { + IrInterTy::Instance(ir_inter_ty_instance.parse()) + } + IrInterTy::External(path) => IrInterTy::External(syn::parse_str(path).unwrap()), + } + } +} + +impl IrInterTyInstance { + fn parse(&self) -> IrInterTyInstance { + let Self { + name, + child, + ty, + has_lifetime, + wrapper, + } = self; + IrInterTyInstance { + name: Ident::new(name, Span::call_site()), + child: child.map(|child| Ident::new(child, Span::call_site())), + ty: ty.unwrap(), + has_lifetime: *has_lifetime, + wrapper: wrapper.map(|child| syn::parse_str(child).unwrap()), + } + } +} diff --git a/structure/type-registry/src/v1/ir/macro_def.rs b/structure/type-registry/src/v1/ir/macro_def.rs new file mode 100644 index 0000000..ba7ffb3 --- /dev/null +++ b/structure/type-registry/src/v1/ir/macro_def.rs @@ -0,0 +1,207 @@ +#[macro_export] +/// Macro for defining IR node types from multiple crates with type family support. +/// +/// Supports AST types with both default and IR type families, plus native IR and Ty types. +macro_rules! define_ir_node_types { + ( + crate ast<'cx, ir> { + $(type $ast_name:ident;)* + $(mod $ast_module:ident { + $(type $ast_mod_name:ident;)* + })* + } + crate ast<'cx, default> { + $(type $ast_default_name:ident;)* + } + crate ir<'cx> { + $(type $ir_name:ident;)* + } + crate ty<'cx> { + $(type $ty_name:ident;)* + } + crate ty { + $(type $ty_no_cx_name:ident;)* + } + crate module<'cx> { + $(type $module_name:ident;)* + } + ) => { + { + let default = IrNodeTy { + name: "!", + child: None, + ty: None, + }; + &[ + $( + IrNodeTy { + ty: Some(IrNodeTyInstance { + ty: InstanceKind::ast_ir(), + has_lifetime: true, + }), + name: stringify!($ast_name), + ..default + }, + )* + $( + $( + IrNodeTy { + ty: Some(IrNodeTyInstance { + ty: InstanceKind::ast_ir(), + has_lifetime: true, + }), + child: Some(stringify!($ast_module)), + name: stringify!($ast_mod_name), + }, + )* + )* + $( + IrNodeTy { + ty: Some(IrNodeTyInstance { + ty: InstanceKind::ast_default(), + has_lifetime: true, + }), + name: stringify!($ast_default_name), + ..default + }, + )* + $( + IrNodeTy { + ty: Some(IrNodeTyInstance { + ty: InstanceKind::ir(), + has_lifetime: true, + }), + name: stringify!($ir_name), + ..default + }, + )* + $( + IrNodeTy { + ty: Some(IrNodeTyInstance { + ty: InstanceKind::Other("opslang_ty"), + has_lifetime: true, + }), + name: stringify!($ty_name), + ..default + }, + )* + $( + IrNodeTy { + ty: Some(IrNodeTyInstance { + ty: InstanceKind::Other("opslang_ty"), + has_lifetime: false, + }), + name: stringify!($ty_no_cx_name), + ..default + }, + )* + $( + IrNodeTy { + ty: Some(IrNodeTyInstance { + ty: InstanceKind::Other("opslang_module"), + has_lifetime: true, + }), + name: stringify!($module_name), + ..default + }, + )* + ] + } + }; +} + +#[macro_export] +/// Macro for defining intermediate IR types with wrapper and external type support. +macro_rules! define_ir_inter_types { + ( + crate ast { + $(type $ast_name:ident $(<$ast_cx:lifetime, $ast_subst:ident>)? $(: $ast_wrapper:path)?;)* + } + crate ir { + $(type $ir_name:ident $(<$ir_cx:lifetime>)? $(: $ir_wrapper:path)?;)* + } + crate ty { + $(type $ty_name:ident $(<$ty_cx:lifetime>)? $(: $ty_wrapper:path)?;)* + } + crate module { + $(type $module_name:ident $(<$module_cx:lifetime>)? $(: $module_wrapper:path)?;)* + } + extern { + $(type $ext_name:path;)* + } + ) => { + { + let default = IrInterTyInstance { + name: "!", + child: None, + ty: None, + has_lifetime: false, + wrapper: None, + }; + &[ + $( + IrInterTy::Instance(IrInterTyInstance { + ty: Some(InstanceKind::Ast({ + #[allow(unused_mut, unused_assignments)] + let mut kind = TypeSubstitution::Default; + $( + kind = TypeSubstitution::$ast_subst(); + )? + kind + })), + name: stringify!($ast_name), + $( + has_lifetime: {stringify!($ast_cx); true}, + )? + $( + wrapper: Some(stringify!($ast_wrapper)), + )? + ..default + }), + )* + $( + IrInterTy::Instance(IrInterTyInstance { + ty: Some(InstanceKind::ir()), + name: stringify!($ir_name), + $( + has_lifetime: {stringify!($ir_cx); true}, + )? + $( + wrapper: Some(stringify!($ir_wrapper)), + )? + ..default + }), + )* + $( + IrInterTy::Instance(IrInterTyInstance { + ty: Some(InstanceKind::Other("opslang_ty")), + name: stringify!($ty_name), + $( + has_lifetime: {stringify!($ty_cx); true}, + )? + $( + wrapper: Some(stringify!($ty_wrapper)), + )? + ..default + }), + )* + $( + IrInterTy::Instance(IrInterTyInstance { + ty: Some(InstanceKind::Other("opslang_module")), + name: stringify!($module_name), + $( + has_lifetime: {stringify!($module_cx); true}, + )? + $( + wrapper: Some(stringify!($module_wrapper)), + )? + ..default + }), + )* + $( + IrInterTy::External(stringify!($ext_name)), + )* + ] + } + }; +} diff --git a/structure/type-registry/src/v1/ir/types.rs b/structure/type-registry/src/v1/ir/types.rs new file mode 100644 index 0000000..50d8ce2 --- /dev/null +++ b/structure/type-registry/src/v1/ir/types.rs @@ -0,0 +1,414 @@ +//! Definitions needed for `visitor_type_registry`. + +use super::*; +use const_compatible::*; + +/// Represents a type in the IR that can be instantiated with a lifetime. +/// +/// # Invariants +/// +/// This struct represents types from both `opslang-ast` and `opslang-ir` crates +/// that can be instantiated with a lifetime parameter, conventionally `'cx`. +/// +/// The primary invariants are: +/// 1. The combination of `name`, `module_path`, and `crate_name` must form a valid path +/// to a type definition (e.g., `::opslang_ast::syntax::v1::Stmt` or `::opslang_ir::version::v1::Comment`). +/// 2. The referenced type must be a generic type that accepts exactly one lifetime parameter. +/// 3. The type must be instantiable when provided with the `'cx` lifetime. +/// +/// This ensures that the procedural macros using this struct can correctly generate +/// code that references these lifetime-annotated IR types. +/// Represents an IR node type from AST, IR, or Ty crates that can be instantiated with a lifetime. +/// +/// Can represent types from `opslang-ast`, `opslang-ir`, or `opslang-ty` crates with proper +/// type family substitution and path qualification. +#[derive(Debug)] +pub struct IrNodeTy { + pub(crate) name: Mapped, + pub(crate) child: Option>, + pub(crate) ty: Mapped, +} + +impl opslang_visitor_macro_helper::shared_visitor_trait::VisitableType for IrNodeTy { + fn generate_visit_method_name( + &self, + kind: opslang_visitor_macro_helper::MethodKind, + mode: opslang_visitor_macro_helper::VisitorMode, + ) -> String { + self.generate_visit_method_name(kind, mode) + } + + fn full_type_path(&self) -> proc_macro2::TokenStream { + let type_path = self.inside_of_v1_child_mod().super_path(); + quote::quote! { #type_path } + } +} + +impl IrNodeTy { + /// Convert to a super-qualified type for relative references. + /// + /// This creates a type that generates paths like `super::Type<'cx>` or `super::module::Type<'cx>` + /// for use in contexts where relative references within the same crate are appropriate. + pub const fn inside_of_v1_child_mod(&self) -> InsideV1ChildModTy<'_> { + InsideV1ChildModTy { inner: self } + } + + /// Convert to a crate-qualified type for external references. + /// + /// This creates a type that generates paths like `::opslang_ir::version::v1::Type<'cx>` + /// for use in contexts where the full crate path is needed. + pub const fn outside_of_ir_crate(&self) -> OutsideIrCrateTy<'_> { + OutsideIrCrateTy { inner: self } + } + + /// Returns all IR node types for v1 syntax including both AST and IR specific types. + pub fn get_v1_ir_node_types() -> impl Iterator { + visitor_type_registry::NODE_TYPES + .iter() + .map(|ty| ty.parse()) + } +} + +/// Represents intermediate IR types that may be instance-based or external paths. +#[derive(Debug)] +pub enum IrInterTy { + /// IR type instance with configurable generics. + Instance(IrInterTyInstance

), + /// External type path (like std types). + External(Mapped), +} + +impl IrInterTy { + /// Convert to a crate-qualified type for external references. + pub const fn outside_of_ir_crate(&self) -> OutsideIrCrateInterTy<'_> { + OutsideIrCrateInterTy { inner: self } + } + + /// Returns all intermediate IR types for v1 syntax. + pub fn get_v1_ir_inter_types() -> impl Iterator { + visitor_type_registry::INTER_TYPES + .iter() + .map(|ty| ty.parse()) + } +} + +/// A newtyped wrapper for [`IrNodeTy`] that ensures super-qualified paths. +/// +/// This type generates paths like `super::Type<'cx>` or `super::module::Type<'cx>` and is +/// intended for contexts where relative references within the same crate are appropriate, +/// such as in trait declarations. +#[derive(Clone, Debug)] +pub struct InsideV1ChildModTy<'a> { + pub(super) inner: &'a IrNodeTy, +} + +impl InsideV1ChildModTy<'_> { + /// Generate super-qualified token stream path. + /// + /// Returns a [`proc_macro2::TokenStream`] representing paths like `super::Type<'cx>` + /// suitable for relative references within the same crate. + pub fn super_path(&self) -> Path { + self.inner.full_path(true) + } +} + +/// A newtyped wrapper for [`IrNodeTy`] that ensures crate-qualified paths. +/// +/// This type generates paths like `::opslang_ir::version::v1::Type<'cx>` and is intended +/// for contexts where external crate references are needed, such as in visitor implementations +/// that reference types from outside the current crate. +#[derive(Clone, Debug)] +pub struct OutsideIrCrateTy<'a> { + pub(super) inner: &'a IrNodeTy, +} + +impl OutsideIrCrateTy<'_> { + /// Generate fully qualified path with crate prefix. + /// + /// Returns a string like `::opslang_ir::version::v1::Type<'cx>` suitable for + /// external references to IR types. + pub fn full_crate_path(&self) -> Path { + self.inner.full_path(false) + } +} + +/// A newtyped wrapper for [`IrInterTy`] that ensures crate-qualified paths. +#[derive(Clone, Debug)] +pub struct OutsideIrCrateInterTy<'a> { + pub(super) inner: &'a IrInterTy, +} + +impl OutsideIrCrateInterTy<'_> { + /// Generate fully qualified path with crate prefix. + pub fn full_path(&self) -> Cow<'_, Path> { + self.inner.full_path() + } +} + +/// Wrapper for `InstanceKind` that provides type generation methods. +#[derive(Clone, Copy, Debug)] +pub struct IrNodeTyInstance { + pub(super) ty: InstanceKind, + pub(super) has_lifetime: bool, +} + +/// Specifies the source crate and type family for IR node types. +#[derive(Clone, Copy, Debug)] +pub enum InstanceKind { + /// AST crate types with optional type family substitution. + Ast(TypeSubstitution), + /// Native IR crate types. + Ir, + /// Other crate types (e.g., opslang-ty). + Other(&'static str), +} + +/// Controls type family substitution for AST types in IR context. +#[derive(Clone, Copy, Debug)] +pub enum TypeSubstitution { + /// Use default TypeFamily (no substitution). + Default, + /// Use IrTypeFamily for IR context. + Ir, +} + +impl std::ops::Deref for IrNodeTyInstance { + type Target = InstanceKind; + + fn deref(&self) -> &Self::Target { + &self.ty + } +} + +impl InstanceKind { + /// Return self for method chaining. + fn kind(self) -> Self { + self + } +} + +impl TypeSubstitution { + /// Generate type family argument for generic instantiation. + fn ty_arg(&self, rebase_ir_to_super: bool) -> Option { + match self { + TypeSubstitution::Default => None, + TypeSubstitution::Ir => Some(GenericArgument::Type(if rebase_ir_to_super { + parse_quote!(super::IrTypeFamily) + } else { + parse_quote!(::opslang_ir::version::v1::IrTypeFamily) + })), + } + } +} + +impl InstanceKind { + /// Generate type family argument for this instance kind. + fn ty_arg(&self, rebase_ir_to_super: bool) -> Option { + match self { + InstanceKind::Ast(type_substitution) => type_substitution.ty_arg(rebase_ir_to_super), + InstanceKind::Ir | InstanceKind::Other(_) => None, + } + } +} + +impl InstanceKind { + /// Generate base crate path for this instance kind. + fn base_path(&self, rebase_ir_to_super: bool) -> Path { + match self { + Self::Ir if rebase_ir_to_super => parse_quote!(super), + Self::Ir => parse_quote!(::opslang_ir::version::v1), + Self::Other(crate_name) => { + let crate_ident = Ident::new(crate_name, Span::call_site()); + parse_quote!(::#crate_ident::version::v1) + } + Self::Ast(_) => parse_quote!(::opslang_ast::syntax::v1), + } + } +} + +impl IrNodeTyInstance { + /// Generate complete generic arguments including lifetime and type family. + fn ty_generics(&self, rebase_ir_to_super: bool) -> AngleBracketedGenericArguments { + let mut g = AngleBracketedGenericArguments { + lt_token: Token![<](Span::call_site()), + gt_token: Token![>](Span::call_site()), + colon2_token: None, + args: Punctuated::new(), + }; + if self.has_lifetime { + g.args.push(parse_quote!('cx)); + } + if let Some(path) = self.kind().ty_arg(rebase_ir_to_super) { + g.args.push(path); + } + g + } + /// Get base crate path from the wrapped instance kind. + fn base_path(&self, rebase_ir_to_super: bool) -> Path { + self.ty.base_path(rebase_ir_to_super) + } +} + +impl IrNodeTy { + /// Generate full path for this type with proper crate and module qualification. + /// + /// When `rebase_ir_to_super` is true, IR crate types use "super" instead of absolute paths. + fn full_path(&self, rebase_ir_to_super: bool) -> Path { + let Self { name, child, ty } = self; + let ty_generics = ty.ty_generics(rebase_ir_to_super); + + let mut path = ty.base_path(rebase_ir_to_super); + if let Some(child) = child { + path.segments.push(parse_quote!(#child)); + } + path.segments.push(parse_quote!(#name #ty_generics)); + path + } +} + +impl IrNodeTy { + /// Generate appropriate visit method name based on the type, method kind, and visitor mode. + /// If module_path exists, generates `{prefix}_{module}_{name}[_mut]`, otherwise `{prefix}_{name}[_mut]`. + pub fn generate_visit_method_name( + &self, + kind: opslang_visitor_macro_helper::MethodKind, + mode: opslang_visitor_macro_helper::VisitorMode, + ) -> String { + use convert_case::{Case, Casing}; + + let mut string; + let prefix = match kind { + opslang_visitor_macro_helper::MethodKind::Visit => "visit_", + opslang_visitor_macro_helper::MethodKind::Super => "super_", + }; + string = prefix.to_string(); + + if let InstanceKind::Ast(TypeSubstitution::Default) = &*self.ty { + string.push_str("ast_"); + } + + if let Some(module) = &self.child { + string.push_str(module.to_string().as_str()); + string.push('_'); + }; + + string.push_str(&self.name.to_string().to_case(Case::Snake)); + + if let opslang_visitor_macro_helper::VisitorMode::VisitMut = mode { + string.push_str("_mut"); + } + + string + } +} + +/// Represents a configurable IR type instance with optional wrapper and generics. +#[derive(Debug)] +pub struct IrInterTyInstance { + pub(super) name: Mapped, + pub(super) child: Option>, + pub(super) ty: Mapped, + pub(super) has_lifetime: bool, + pub(super) wrapper: Option>, +} + +impl IrInterTyInstance { + /// Generate generic arguments for this type instance. + fn ty_generics(&self, rebase_ir_to_super: bool) -> Option { + let mut args = Punctuated::::new(); + + if self.has_lifetime { + args.push(parse_quote!('cx)); + } + if let Some(param) = self.ty.ty_arg(rebase_ir_to_super) { + args.push(param); + } + + if args.is_empty() { + None + } else { + Some(AngleBracketedGenericArguments { + lt_token: Token![<](Span::call_site()), + gt_token: Token![>](Span::call_site()), + colon2_token: None, + args, + }) + } + } +} + +impl IrInterTyInstance { + /// Generate complete type path including wrapper if present. + fn full_path(&self) -> Path { + let Self { + name, + child, + ty, + has_lifetime: _, + wrapper, + } = self; + let ty_generics = self.ty_generics(false); + + let mut path = ty.base_path(false); + if let Some(child) = child { + path.segments.push(parse_quote!(#child)); + } + path.segments.push(parse_quote!(#name #ty_generics)); + if let Some(wrapper) = wrapper { + path = parse_quote!(#wrapper<#path>); + } + path + } +} + +impl IrInterTy { + /// Get the full path for this intermediate type. + fn full_path(&self) -> Cow<'_, Path> { + match self { + IrInterTy::Instance(ir_inter_ty_instance) => { + Cow::Owned(ir_inter_ty_instance.full_path()) + } + IrInterTy::External(ext) => Cow::Borrowed(ext), + } + } +} + +/// Functions for macro. +impl InstanceKind { + /// Create AST instance with IR type family substitution. + pub const fn ast_ir() -> Self { + Self::Ast(TypeSubstitution::Ir) + } + /// Create AST instance with default type family. + pub const fn ast_default() -> Self { + Self::Ast(TypeSubstitution::Default) + } + /// Create IR crate instance. + pub const fn ir() -> Self { + Self::Ir + } +} + +/// Functions for macro. +impl TypeSubstitution { + /// Create default type substitution. + #[allow(dead_code)] + pub const fn default() -> Self { + Self::Default + } + /// Create IR type substitution. + pub const fn ir() -> Self { + Self::Ir + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ident_safe() { + let _ir_node_types = IrNodeTy::get_v1_ir_node_types(); + let _ir_inter_types = IrInterTy::get_v1_ir_inter_types(); + } +} diff --git a/structure/type-registry/src/v1/ir/visitor_type_registry.rs b/structure/type-registry/src/v1/ir/visitor_type_registry.rs new file mode 100644 index 0000000..e83eb1d --- /dev/null +++ b/structure/type-registry/src/v1/ir/visitor_type_registry.rs @@ -0,0 +1,211 @@ +/// Complete registry of all IR node types for v1 syntax from multiple crates. +/// +/// # Maintenance Guide +/// +/// **CRITICAL**: This registry spans THREE crates. When you modify types: +/// +/// ## AST Types (`opslang-ast`) +/// - **With IR type family**: Add to `crate ast<'cx, ir>` section +/// - **With default type family**: Add to `crate ast<'cx, default>` section +/// - Choose based on whether the type should use `IrTypeFamily` or `DefaultTypeFamily` +/// +/// ## IR Types (`opslang-ir`) +/// - Add to `crate ir<'cx>` section +/// - These are native IR representations +/// +/// ## Ty Types (`opslang-ty`) +/// - Add to `crate ty<'cx>` section +/// - These are type system representations +/// +/// **Incomplete coverage**: Will cause compilation failures in `opslang-ir/tests/visitor_consistency.rs` +pub const NODE_TYPES: &[IrNodeTy] = crate::define_ir_node_types! { + // types that are defined in ast crate, substituted with 'cx and ir type family + crate ast<'cx, ir> { + type Program; // actual type is `Program<'cx, IrTypeFamily>` + type ToplevelItem; + type DefinitionKind; + type FunctionDef; + type Parameter; + type ConstantDef; + type ScopeItem; + type Row; + type Block; + type Statement; + type Let; + type ExprStatement; + type ReturnStmt; + type Qualif; + type Modifier; + type ModifierParam; + type DefaultModifier; + type PreQualified; + type Unary; + type UnOp; + type CompareOp; + type NotEqualToken; + type Binary; + type BinOp; + type Set; + type Cast; + type InfixImport; + type If; + type IfElse; + type Call; + type Wait; + type Select; + + // Literal types + type Literal; + type Array; + + // Token types + mod token { + type Semi; // actual type is `Semi<'cx, IrTypeFamily>` + type Break; + type Atmark; + type Tilde; + type Colon; + type Eq; + type OpenBrace; + type CloseBrace; + type OpenParen; + type CloseParen; + type OpenSquare; + type CloseSquare; + type Hyphen; + type Ampersand; + type Dollar; + type Question; + type RightAngle; + type Angle; + type Star; + type Slash; + type Percent; + type Plus; + type BangEqual; + type SlashEqual; + type EqualEqual; + type RightAngleEq; + type AngleEq; + type ColonEq; + type AndAnd; + type OrOr; + type Arrow; + type DoubleArrow; + type Return; + type Let; + type As; + type If; + type Else; + type Call; + type Wait; + type Select; + type Prc; + type Const; + } + } + // types that are defined in ast crate, substituted with 'cx and default type family + crate ast<'cx, default> { + type Comment; // actual type is `Comment<'cx>` + type Path; + type NumericSuffix; + type Ident; + + type String; + type Bytes; + type HexBytes; + type DateTime; + type Numeric; + } + // types that are defined in ir crate, substituted with 'cx + crate ir<'cx> { + type Comment; // actual type is `Comment<'cx>` + type Definition; + type ResolvedPath; + type ResolvedItem; + type Expr; + type Scope; + type String; + type Bytes; + type HexBytes; + type DateTime; + type Numeric; + type Apply; + type Compare; + } + // types that are defined in ty crate, substituted with 'cx + crate ty<'cx> { + type Ty; // actual type is `Ty<'cx>` + } + // types that are defined in ty crate, without 'cx + crate ty { + type InferTy; // actual type is `InferTy`, and so on + type TyVid; + type IntVid; + type FloatVid; + } + // types that are defined in module crate, substituted with 'cx + crate module<'cx> { + type ModuleItem; // actual type is `ModuleItem<'cx>` + } +}; + +/// Registry of intermediate IR types with multi-crate and wrapper support. +/// +/// # Maintenance Guide +/// +/// **Advanced registry**: Supports wrapper types (like `Vec`) and external types. +/// +/// ## Adding Types +/// - **AST intermediate**: Add to `crate ast` with optional lifetime/substitution +/// - **IR intermediate**: Add to `crate ir` with optional lifetime +/// - **Ty intermediate**: Add to `crate ty` with optional lifetime +/// - **External types**: Add to `extern` (like `std::convert::Infallible`) +/// - **Wrapped types**: Use `: WrapperType` syntax (like `: ::std::vec::Vec`) +/// +/// **When structures change**: You will almost certainly need to update this registry. +/// **Incomplete coverage**: Will cause compilation failures in `opslang-ir/tests/visitor_consistency.rs` +pub const INTER_TYPES: &[IrInterTy] = crate::define_ir_inter_types! { + crate ast { + type DefaultTypeFamily; + type Span; + type BytePos; + type NumericKind; + type ExprKind<'cx, ir>; + type ExprMut<'cx, ir>; + type ScopeItem<'cx, ir>: ::std::vec::Vec; // actual type is Vec> + type Qualif<'cx, ir>: ::std::vec::Vec; + type SelectItem<'cx, ir>; + type SelectItem<'cx, ir>: ::std::vec::Vec; + } + crate ir { + type IrTypeFamily; + type BinOp<'cx>; + type NumericKind<'cx>; + type Expr<'cx>: ::std::vec::Vec; + type CompareOpExpr<'cx>; + type CompareOpExpr<'cx>: ::std::vec::Vec; // actual type is Vec + } + crate ty { + type Ident<'cx>; + type TyKind<'cx>; + type Procedure<'cx>; + type Identifier<'cx>; + type Ty<'cx>: ::std::vec::Vec; // actual type is Vec> + type IntTy; + type UintTy; + type FloatTy; + } + crate module { + type ModuleItemDef<'cx>; + type ModulePath<'cx>; + } + extern { + type ::std::convert::Infallible; + type ::chrono::DateTime<::chrono::Utc>; + } +}; + +use super::*; +use const_compatible::*; +use types::*; diff --git a/tools/opslang-formatter/Cargo.toml b/tools/opslang-formatter/Cargo.toml new file mode 100644 index 0000000..462f180 --- /dev/null +++ b/tools/opslang-formatter/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "opslang-formatter" +version.workspace = true +edition.workspace = true +license.workspace = true + +[[bin]] +name = "opslang-formatter" +path = "src/main.rs" + +[dependencies] +opslang-ast.workspace = true +opslang-parser.workspace = true +opslang-printer.workspace = true +clap.workspace = true +serde.workspace = true +toml.workspace = true +anyhow.workspace = true +walkdir.workspace = true diff --git a/tools/opslang-formatter/default.toml b/tools/opslang-formatter/default.toml new file mode 100644 index 0000000..eeb6936 --- /dev/null +++ b/tools/opslang-formatter/default.toml @@ -0,0 +1,11 @@ +strategy = "comment_aligned" + +# Base formatting options +indent_str = " " +indent_level = 0 +max_width = 80 +newline_style = "unix" + +# Comment alignment options +grouping = "consecutive" +position = "to_longest" diff --git a/tools/opslang-formatter/src/lib.rs b/tools/opslang-formatter/src/lib.rs new file mode 100644 index 0000000..7a94043 --- /dev/null +++ b/tools/opslang-formatter/src/lib.rs @@ -0,0 +1,248 @@ +use anyhow::{Context as AnyhowContext, Result}; +use opslang_ast::v1::context::Context; +use opslang_parser::{ParseOps, ParserInput}; +use opslang_printer::{CommentAligned, Naive, PrettyPrint, PrintOptions}; +use serde::{Deserialize, Serialize}; +use std::borrow::Cow; +use std::fs; +use std::path::Path; + +/// Runtime strategy selection for formatting +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] +#[serde(rename_all = "snake_case")] +pub enum FormatterStrategy { + Naive, + #[default] + CommentAligned, +} + +/// Configuration for the formatter +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct FormatterConfig { + pub strategy: FormatterStrategy, + #[serde(flatten)] + pub print_options: PrintOptionsConfig, +} + +/// Serializable version of print options +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PrintOptionsConfig { + /// Base options + #[serde(flatten)] + pub base: BasePrintOptionsConfig, + /// Comment alignment configuration + #[serde(flatten)] + pub comment_alignment: CommentAlignmentConfig, +} + +/// Serializable version of base print options +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BasePrintOptionsConfig { + /// String used for indentation (usually spaces or tabs) + #[serde(default = "default_indent_str")] + pub indent_str: String, + + /// Current indentation level + #[serde(default)] + pub indent_level: usize, + + /// Whether to reserve a space for break tokens + #[serde(default = "default_reserve_for_break")] + pub reserve_for_break: bool, + + /// Maximum line width + #[serde(default = "default_max_width")] + pub max_width: usize, + + /// Newline style + #[serde(default)] + pub newline_style: NewlineStyleConfig, +} + +/// Serializable version of comment alignment +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct CommentAlignmentConfig { + /// Grouping strategy for comment alignment + #[serde(default)] + pub grouping: CommentGroupingConfig, + /// Position calculation method + #[serde(default)] + pub position: CommentPositionConfig, +} + +/// Serializable version of comment grouping +#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum CommentGroupingConfig { + #[default] + Consecutive, + PerBlock, +} + +/// Serializable version of comment position +#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum CommentPositionConfig { + #[default] + ToLongest, + ToFixed { + column: usize, + fallback_to_longest: bool, + }, + ToTabMultiple { + tab_size: usize, + fallback_to_longest: bool, + }, +} + +/// Serializable version of newline style +#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum NewlineStyleConfig { + #[default] + Unix, + Windows, +} + +// Default functions for serde +fn default_indent_str() -> String { + " ".to_string() // 4 spaces +} + +fn default_reserve_for_break() -> bool { + true +} + +fn default_max_width() -> usize { + 80 +} + +impl Default for BasePrintOptionsConfig { + fn default() -> Self { + Self { + indent_str: default_indent_str(), + indent_level: 0, + reserve_for_break: default_reserve_for_break(), + max_width: default_max_width(), + newline_style: NewlineStyleConfig::default(), + } + } +} + +impl FormatterConfig { + /// Load configuration from TOML file + pub fn from_file>(path: P) -> Result { + let content = fs::read_to_string(path.as_ref()) + .with_context(|| format!("Failed to read config file: {}", path.as_ref().display()))?; + + let config: Self = + toml::from_str(&content).with_context(|| "Failed to parse TOML configuration")?; + + Ok(config) + } +} + +/// Convert config types to printer types +impl From<&FormatterConfig> for PrintOptions { + fn from(config: &FormatterConfig) -> Self { + let base = opslang_printer::BasePrintOptions { + indent_str: Cow::Owned(config.print_options.base.indent_str.clone()), + indent_level: config.print_options.base.indent_level, + reserve_for_break: config.print_options.base.reserve_for_break, + max_width: config.print_options.base.max_width, + newline_style: match config.print_options.base.newline_style { + NewlineStyleConfig::Unix => opslang_printer::NewlineStyle::Unix, + NewlineStyleConfig::Windows => opslang_printer::NewlineStyle::Windows, + }, + }; + + PrintOptions::new(base, Default::default()) + } +} + +impl From<&FormatterConfig> for PrintOptions { + fn from(config: &FormatterConfig) -> Self { + let base = opslang_printer::BasePrintOptions { + indent_str: Cow::Owned(config.print_options.base.indent_str.clone()), + indent_level: config.print_options.base.indent_level, + reserve_for_break: config.print_options.base.reserve_for_break, + max_width: config.print_options.base.max_width, + newline_style: match config.print_options.base.newline_style { + NewlineStyleConfig::Unix => opslang_printer::NewlineStyle::Unix, + NewlineStyleConfig::Windows => opslang_printer::NewlineStyle::Windows, + }, + }; + + let comment_alignment = opslang_printer::CommentAlignment { + grouping: match config.print_options.comment_alignment.grouping { + CommentGroupingConfig::Consecutive => opslang_printer::CommentGrouping::Consecutive, + CommentGroupingConfig::PerBlock => opslang_printer::CommentGrouping::PerBlock, + }, + position: match config.print_options.comment_alignment.position { + CommentPositionConfig::ToLongest => opslang_printer::CommentPosition::ToLongest, + CommentPositionConfig::ToFixed { + column, + fallback_to_longest, + } => opslang_printer::CommentPosition::ToFixed { + column, + fallback_to_longest, + }, + CommentPositionConfig::ToTabMultiple { + tab_size, + fallback_to_longest, + } => opslang_printer::CommentPosition::ToTabMultiple { + tab_size, + fallback_to_longest, + }, + }, + }; + + PrintOptions::new(base, comment_alignment) + } +} + +/// Format opslang source code according to the specified configuration +pub fn format_source(source: &str, config: &FormatterConfig) -> Result { + // Create v1 context for allocating reference types + let ctx = Context::new(); + + // Parse the source code using ParseOps + let input = ParserInput { + content: source, + file_name: "input.ops".into(), + }; + + let program = opslang_ast::v1::Program::parse(input, &ctx) + .map_err(|e| anyhow::anyhow!("Parse error: {e:?}"))?; + + // Format using the appropriate strategy + let mut output = String::new(); + + match config.strategy { + FormatterStrategy::Naive => { + let options: PrintOptions = config.into(); + PrettyPrint::::pretty_print(&program, &mut output, &options) + .with_context(|| "Failed to format with naive strategy")?; + } + FormatterStrategy::CommentAligned => { + let options: PrintOptions = config.into(); + PrettyPrint::::pretty_print(&program, &mut output, &options) + .with_context(|| "Failed to format with comment-aligned strategy")?; + } + } + + Ok(output) +} + +/// Format a file in place +pub fn format_file>(file_path: P, config: &FormatterConfig) -> Result<()> { + let source = fs::read_to_string(&file_path) + .with_context(|| format!("Failed to read file: {}", file_path.as_ref().display()))?; + + let formatted = format_source(&source, config)?; + + fs::write(&file_path, formatted) + .with_context(|| format!("Failed to write file: {}", file_path.as_ref().display()))?; + + Ok(()) +} diff --git a/tools/opslang-formatter/src/main.rs b/tools/opslang-formatter/src/main.rs new file mode 100644 index 0000000..2f9b741 --- /dev/null +++ b/tools/opslang-formatter/src/main.rs @@ -0,0 +1,126 @@ +use anyhow::{Context, Result}; +use clap::Parser; +use opslang_formatter::{FormatterConfig, format_file, format_source}; +use std::fs; +use std::io::{self, Read}; +use std::path::{Path, PathBuf}; +use walkdir::WalkDir; + +#[derive(Parser)] +#[command(name = "opslang-formatter")] +#[command(about = "Format opslang source files")] +#[command(version)] +struct Cli { + /// Configuration file path + #[arg(short, long)] + config: PathBuf, + + /// Input files to format (if none provided, reads from stdin) + #[arg(value_name = "FILE")] + files: Vec, + + /// Format files in place + #[arg(short, long)] + in_place: bool, + + /// Print formatted output to stdout instead of modifying files + #[arg(long)] + stdout: bool, + + /// Fail if input path is a directory + #[arg(long)] + fail_on_dir: bool, +} + +fn main() -> Result<()> { + let cli = Cli::parse(); + + // Load configuration + let config = FormatterConfig::from_file(&cli.config) + .with_context(|| format!("Failed to load config from {}", cli.config.display()))?; + + if cli.files.is_empty() { + // Read from stdin + let mut input = String::new(); + io::stdin() + .read_to_string(&mut input) + .context("Failed to read from stdin")?; + + let formatted = + format_source(&input, &config).context("Failed to format input from stdin")?; + + print!("{formatted}"); + } else { + // Process files + let mut all_files = Vec::new(); + + for file_path in cli.files { + if file_path.is_dir() { + if cli.fail_on_dir { + return Err(anyhow::anyhow!( + "Directory provided but --fail-on-dir specified: {}", + file_path.display() + )); + } + + // Recursively collect all files in directory + collect_files(&file_path, &mut all_files)?; + } else { + all_files.push(file_path); + } + } + + for file_path in all_files { + if cli.stdout { + // Read file and print formatted output to stdout + let source = fs::read_to_string(&file_path) + .with_context(|| format!("Failed to read file: {}", file_path.display()))?; + + let formatted = format_source(&source, &config) + .with_context(|| format!("Failed to format file: {}", file_path.display()))?; + + println!("=== {} ===", file_path.display()); + print!("{formatted}"); + } else if cli.in_place { + // Format file in place + format_file(&file_path, &config).with_context(|| { + format!("Failed to format file in place: {}", file_path.display()) + })?; + + eprintln!("Formatted: {}", file_path.display()); + } else { + // Read file and print formatted output to stdout (default behavior) + let source = fs::read_to_string(&file_path) + .with_context(|| format!("Failed to read file: {}", file_path.display()))?; + + let formatted = format_source(&source, &config) + .with_context(|| format!("Failed to format file: {}", file_path.display()))?; + + print!("{formatted}"); + } + } + } + + Ok(()) +} + +fn collect_files(dir: &PathBuf, files: &mut Vec) -> Result<()> { + for entry in WalkDir::new(dir) { + let entry = entry + .with_context(|| format!("Failed to read directory entry in: {}", dir.display()))?; + let path = entry.path(); + + if path.is_file() && is_opslang_file(path) { + files.push(path.to_path_buf()); + } + } + + Ok(()) +} + +fn is_opslang_file(path: &Path) -> bool { + path.extension() + .and_then(|ext| ext.to_str()) + .map(|ext| ext == "ops" || ext == "opslang") + .unwrap_or(false) +} diff --git a/tools/opslang-formatter/tests/debug_assert.rs b/tools/opslang-formatter/tests/debug_assert.rs new file mode 100644 index 0000000..62efa88 --- /dev/null +++ b/tools/opslang-formatter/tests/debug_assert.rs @@ -0,0 +1,124 @@ +use opslang_ast::{ + DefinitionKind, + v1::{ExprKind, Program, context::Context}, +}; +use opslang_formatter::{FormatterConfig, format_source}; +use opslang_parser::{ParseOps, ParserInput}; + +#[test] +fn debug_assert_parentheses_behavior() { + let config = FormatterConfig::default(); + + let test_cases = [ + // Case 1: Simple assert with comparison + "#! lang=v1\nprc main() { assert 2 == 2; }\n", + // Case 2: Assert with explicit parentheses + "#! lang=v1\nprc main() { assert (2 == 2); }\n", + // Case 3: Simple assert with single value + "#! lang=v1\nprc main() { assert true; }\n", + // Case 4: Assert with complex expression + "#! lang=v1\nprc main() { assert (1 + 1 == 2); }\n", + ]; + + for (i, input) in test_cases.iter().enumerate() { + println!("\n=== Test Case {} ===", i + 1); + println!("Input: {}", input.trim()); + + // Format the input + let output = format_source(input, &config).expect("Failed to format"); + println!("Output: {}", output.trim()); + + // Debug AST structure + let ctx = Context::new(); + let parser_input = ParserInput { + content: input, + file_name: "test.ops".into(), + }; + let program: Program = Program::parse(parser_input, &ctx).expect("Failed to parse"); + + if let Some(DefinitionKind::Function(f)) = &program.toplevel_items[0].kind + && let Some(first_item) = f.body.scope.items.get(1) + { + // Skip shebang + if let opslang_ast::v1::ScopeItem::Row(row) = first_item + && let Some(opslang_ast::v1::Statement::Expr(expr_stmt)) = &row.statement + { + println!("AST Type: {:?}", discriminant(&expr_stmt.expr.0)); + + match &expr_stmt.expr.0 { + ExprKind::Apply(apply) => { + println!("Apply function: {:?}", apply.function); + println!("Apply args count: {}", apply.args.len()); + if let Some(first_arg) = apply.args.first() { + println!("First arg type: {:?}", discriminant(&first_arg.0)); + match &first_arg.0 { + ExprKind::Parened(parened) => { + println!(" -> Argument is parenthesized"); + println!( + " -> Inner expr: {:?}", + discriminant(&parened.expr.0) + ); + } + ExprKind::Compare(_) => { + println!(" -> Argument is Compare (no parens)"); + } + ExprKind::Binary(_) => { + println!(" -> Argument is Binary (no parens)"); + } + _ => { + println!(" -> Argument is: {:?}", first_arg.0); + } + } + } + } + ExprKind::Compare(compare) => { + println!("Compare head: {:?}", discriminant(&compare.head.0)); + println!("Compare tail count: {}", compare.tail_with_op.len()); + } + _ => { + println!("Other expression type: {:?}", expr_stmt.expr.0); + } + } + } + } + + println!("Expected behavior:"); + if input.contains("assert (") { + println!(" -> Should preserve explicit parentheses"); + } else if input.contains("assert ") && input.contains(" == ") { + println!(" -> Should NOT add extra parentheses"); + } + } +} + +fn discriminant(val: &T) -> std::mem::Discriminant { + std::mem::discriminant(val) +} + +#[test] +fn test_specific_assert_cases() { + let config = FormatterConfig::default(); + + // Test the exact case from test_v1.ops + let input = "#! lang=v1\nprc main() {assert (2 == 2);}\n"; + let output = format_source(input, &config).expect("Failed to format"); + + println!("Input: assert (2 == 2);"); + println!("Output: {}", output.trim()); + + // This should preserve the parentheses as written + // The issue is: why does it output "assert (2 == 2);" when input has explicit parens? + // Answer: Because parser correctly sees Apply(assert, [Parened(Compare(...))]) + + // Test without explicit parentheses + let input2 = "#! lang=v1\nprc main() {assert 2 == 2;}\n"; + let output2 = format_source(input2, &config).expect("Failed to format"); + + println!("Input2: assert 2 == 2;"); + println!("Output2: {}", output2.trim()); + + // This should NOT add parentheses + // The issue is: why does it output "assert (2 == 2);" for simple comparison? + // Answer: Because parser sees Compare(Apply(assert, [2]), [(==, 2)]) + // which means (assert 2) == 2, not assert(2 == 2) +} diff --git a/tools/opslang-formatter/tests/v1.rs b/tools/opslang-formatter/tests/v1.rs new file mode 100644 index 0000000..2207054 --- /dev/null +++ b/tools/opslang-formatter/tests/v1.rs @@ -0,0 +1,72 @@ +use opslang_formatter::{FormatterConfig, format_source}; +use std::fs; + +#[test] +fn test_format_ocaml_style_application() { + let config = FormatterConfig::default(); + + let input = "#! lang=v1\nprc main() { assert 2 == 2; }\n"; + let output = format_source(input, &config).expect("Failed to format"); + + // Should use OCaml-style function application (f x y) not C-style (f(x, y)) + assert!(output.contains("assert 2 == 2;")); + assert!(!output.contains("assert(2 == 2)")); +} + +#[test] +fn test_format_preserves_basic_structure() { + let config = FormatterConfig::default(); + + let input = "#! lang=v1\nprc main() { let x = 42;\nprint x; }\n"; + let output = format_source(input, &config).expect("Failed to format"); + + // Should preserve basic statements + assert!(output.contains("let x = 42;")); + assert!(output.contains("print x;")); + assert!(!output.contains("print(x)")); +} + +#[test] +fn test_format_with_parentheses() { + let config = FormatterConfig::default(); + + let input = "#! lang=v1\nprc main() { print (1 + 2); }\n"; + let output = format_source(input, &config).expect("Failed to format"); + + // Should use OCaml-style function application + assert!(output.contains("print (")); + assert!(!output.contains("print(")); + // Note: Parser has known issue with binary operator order, + // but parentheses should be preserved + assert!(output.contains("(")); + assert!(output.contains(")")); +} + +#[test] +fn test_v1_ops_formatting() { + // Load default config + let config_path = concat!(env!("CARGO_MANIFEST_DIR"), "/default.toml"); + let config = FormatterConfig::from_file(config_path).expect("Failed to load default config"); + + // Read test_v1.ops + let input_path = concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../opslang-parser/tests/test_v1.ops" + ); + let input = fs::read_to_string(input_path).expect("Failed to read test_v1.ops"); + + // Format the input + let formatted = format_source(&input, &config).expect("Failed to format test_v1.ops"); + + // Compare + if input != formatted { + fs::write( + concat!(env!("CARGO_MANIFEST_DIR"), "/formatted_v1.ops"), + &formatted, + ) + .expect("Failed to write formatted output"); + panic!("Formatting did not preserve original structure"); + } else { + println!("Formatting preserved original structure."); + } +} diff --git a/tools/opslang-migration/Cargo.toml b/tools/opslang-migration/Cargo.toml new file mode 100644 index 0000000..dd02fbf --- /dev/null +++ b/tools/opslang-migration/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "opslang-migration" +version.workspace = true +edition.workspace = true +license.workspace = true + +[[bin]] +name = "opslang-migration" +path = "src/main.rs" + +[dependencies] +opslang-ast.workspace = true +opslang-ast-macro.workspace = true +opslang-parser.workspace = true +opslang-ty.workspace = true +opslang-ir.workspace = true +opslang-typeck.workspace = true +opslang-printer.workspace = true +parol_runtime.workspace = true +thiserror.workspace = true +clap.workspace = true +walkdir.workspace = true +chrono.workspace = true diff --git a/tools/opslang-migration/src/lib.rs b/tools/opslang-migration/src/lib.rs new file mode 100644 index 0000000..b0661ab --- /dev/null +++ b/tools/opslang-migration/src/lib.rs @@ -0,0 +1,91 @@ +/// A trait for migrating AST from one version to another. +/// +/// This trait defines the interface for converting AST nodes from version A to version B. +/// It is typically implemented on Zero-Sized Types (ZSTs) that represent the migration +/// from one specific version to the next. +/// +/// # Type Parameters +/// +/// - `A`: The source version (must implement [`VersionMarker`]) +/// - `B`: The target version (must implement [`VersionMarker`]) +/// +/// # Examples +/// +/// ```rust +/// # use opslang_migration::Migrate; +/// # use opslang_ast::{V0, V1}; +/// struct V0ToV1; +/// +/// impl Migrate for V0ToV1 { +/// type Error = String; +/// +/// fn migrate(&self, input: &str) -> Result { +/// // Parse v0, convert to v1, and print +/// todo!() +/// } +/// } +/// ``` +pub trait Migrate { + /// The error type that can be returned during migration. + type Error; + + /// Migrates the input string from version A to version B. + /// + /// This method takes a string representation of the AST in version A format, + /// parses it, converts it to version B format, and returns the string + /// representation of the converted AST. + /// + /// # Parameters + /// + /// - `input`: The source code string in version A format + /// + /// # Returns + /// + /// - `Ok(String)`: The converted code string in version B format + /// - `Err(Self::Error)`: An error if the migration fails + fn migrate(&self, input: &str) -> Result; +} + +/// Errors that can occur during migration. +#[derive(Debug, thiserror::Error)] +pub enum MigrationError { + /// The migration is not yet implemented. + #[error("Migration from {from} to {to} is not yet implemented")] + NotImplemented { + from: &'static str, + to: &'static str, + }, + + /// An error occurred during parsing. + #[error("Parse error: {0}")] + ParseError(String), + + /// An error occurred during AST conversion. + #[error("Conversion error: {0}")] + ConversionError(#[from] ConversionError), + + /// An error occurred during printing. + #[error("Print error: {0}")] + PrintError(String), +} + +/// Errors that can occur during AST conversion. +#[derive(Debug, thiserror::Error)] +pub enum ConversionError { + /// A feature in v0 is not supported in v1. + #[error("Unsupported feature: {feature}")] + UnsupportedFeature { feature: String }, + + /// A required field is missing. + #[error("Missing field: {field}")] + MissingField { field: String }, + + /// An invalid value was encountered. + #[error("Invalid value: {value}")] + InvalidValue { value: String }, +} + +// Re-export v0 to v1 migration +pub mod v0_to_v1; +use opslang_ast::version::VersionMarker; +pub use v0_to_v1::V0ToV1; diff --git a/tools/opslang-migration/src/main.rs b/tools/opslang-migration/src/main.rs new file mode 100644 index 0000000..1a554dd --- /dev/null +++ b/tools/opslang-migration/src/main.rs @@ -0,0 +1,503 @@ +use clap::Parser; +use opslang_ast::version::VersionMarker; +use opslang_migration::{Migrate, V0ToV1}; +use std::collections::HashSet; +use std::env; +use std::fs; +use std::io::{self, Read}; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; +use walkdir::WalkDir; + +#[derive(Parser)] +#[command( + name = "opslang-migration", + about = "Migrates opslang source files from v0 to v1", + version +)] +struct Cli { + /// Input file or directory paths + #[arg(help = "Input file or directory paths to process")] + inputs: Vec, + + /// Output file path (defaults to stdout when processing single file) + #[arg(short, long, value_name = "FILE")] + output: Option, + + /// Disable reading from stdin when no inputs provided + #[arg(long, help = "Disable reading from stdin")] + no_stdin: bool, + + /// Stop processing if input is a directory instead of processing recursively + #[arg(long, help = "Don't process directories recursively")] + no_recursive: bool, + + /// Stop on first error when processing multiple inputs + #[arg(long, help = "Stop on first error")] + fail_fast: bool, + + /// Ignore git working directory status check + #[arg(long, help = "Ignore git working directory dirty status")] + allow_dirty: bool, + + /// Create separate output files, keeping original files + #[arg( + long, + help = "Create separate output files with version suffix instead of modifying in-place" + )] + keep: bool, + + /// Omit metadata comments (shebang is always included) + #[arg( + long, + help = "Omit metadata comments like timestamp and command line (shebang is always included)" + )] + no_metadata: bool, +} + +#[derive(Debug)] +enum MigrationError { + IoError(std::io::Error), + GitDirty, + DirectoryInput, + MigrationFailed(String), + NoInputs, +} + +impl std::fmt::Display for MigrationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + MigrationError::IoError(e) => write!(f, "IO error: {e}"), + MigrationError::GitDirty => write!( + f, + "Git working directory is dirty. Use --allow-dirty to bypass this check." + ), + MigrationError::DirectoryInput => write!( + f, + "Input is a directory. Use --no-recursive to disable recursive processing of directories." + ), + MigrationError::MigrationFailed(msg) => write!(f, "{msg}"), + MigrationError::NoInputs => write!( + f, + "No inputs provided and stdin disabled. Provide input files or remove --no-stdin." + ), + } + } +} + +impl std::error::Error for MigrationError {} + +impl From for MigrationError { + fn from(error: std::io::Error) -> Self { + MigrationError::IoError(error) + } +} + +impl From for MigrationError { + fn from(error: walkdir::Error) -> Self { + MigrationError::IoError(error.into()) + } +} + +fn check_git_status_in_directory(dir: &Path) -> Result { + let output = Command::new("git") + .args(["status", "--porcelain"]) + .current_dir(dir) + .stdout(Stdio::piped()) + .stderr(Stdio::null()) + .output() + .map_err(|_| { + MigrationError::IoError(std::io::Error::new( + std::io::ErrorKind::NotFound, + "git command not found", + )) + })?; + + Ok(!output.stdout.is_empty()) +} + +fn validate_git_status_for_files( + files: &[PathBuf], + allow_dirty: bool, +) -> Result<(), MigrationError> { + if allow_dirty { + return Ok(()); + } + + let mut checked_dirs = HashSet::new(); + + for file_path in files { + if let Some(parent_dir) = file_path.parent() { + let canonical_dir = parent_dir.canonicalize().map_err(MigrationError::IoError)?; + + if checked_dirs.insert(canonical_dir.clone()) + && check_git_status_in_directory(&canonical_dir)? + { + return Err(MigrationError::GitDirty); + } + } + } + + Ok(()) +} + +fn is_opslang_v0_file(path: &Path) -> bool { + path.extension() + .and_then(|ext| ext.to_str()) + .map(|ext| ext == "ops" || ext == "opslang") + .unwrap_or(false) + // ad-hoc check for v0 files + && { + let path_str = path.to_string_lossy(); + !path_str.ends_with("v1.ops") && !path_str.ends_with("v1.ops") + } +} + +fn collect_input_files(inputs: &[String], recursive: bool) -> Result, MigrationError> { + let mut files = Vec::new(); + + for input in inputs { + let path = Path::new(input); + + if path.is_file() { + files.push(path.to_path_buf()); + } else if path.is_dir() { + if !recursive { + return Err(MigrationError::DirectoryInput); + } + + for entry in WalkDir::new(path) { + let entry = entry?; + let entry_path = entry.path(); + + if entry_path.is_file() && is_opslang_v0_file(entry_path) { + files.push(entry_path.to_path_buf()); + } + } + } else { + return Err(MigrationError::IoError(std::io::Error::new( + std::io::ErrorKind::NotFound, + format!("Input path not found: {input}"), + ))); + } + } + + Ok(files) +} + +fn migrate_content(content: &str) -> Result { + V0ToV1.migrate(content).map_err(|e| { + let error_msg = format_migration_error(&e.to_string()); + MigrationError::MigrationFailed(error_msg) + }) +} + +fn add_metadata_to_content(content: &str, include_comments: bool) -> String { + let metadata = generate_metadata(include_comments); + format!("{metadata}{content}") +} + +fn generate_output_filename(input_path: &Path) -> PathBuf { + let version = opslang_ast::V1::version(); + let mut file_stem = input_path + .file_stem() + .and_then(|s| s.to_str()) + .unwrap_or("output") + .to_string(); + + file_stem.push_str(&format!(".{version}")); + + if let Some(ext) = input_path.extension().and_then(|s| s.to_str()) { + file_stem.push('.'); + file_stem.push_str(ext); + } + + input_path.with_file_name(file_stem) +} + +fn generate_metadata(include_comments: bool) -> String { + let mut metadata = String::new(); + + // Shebang is always included + metadata.push_str("#! lang=v1\n"); + + if include_comments { + // Add timestamp and command line info + let now = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs(); + let datetime = chrono::DateTime::from_timestamp(now as i64, 0) + .unwrap() + .format("%Y-%m-%d %H:%M:%S UTC"); + + let args: Vec = env::args().collect(); + let command_line = args.join(" "); + + metadata.push_str(&format!("#! Migrated at {datetime} by: {command_line}\n")); + } + + metadata +} + +fn format_migration_error(error: &str) -> String { + if error.contains("Parse error:") { + // Extract the location information if available + if let Some(pos_start) = error.find("error at ") + && let Some(pos_end) = error[pos_start..].find(": ") + { + let location = &error[pos_start + 9..pos_start + pos_end]; + return format!( + "Parse error at {location}: The syntax is not valid opslang v0. Please check your syntax." + ); + } + "Parse error: The syntax is not valid opslang v0. Please check your syntax.".to_string() + } else if error.contains("Conversion error:") { + format!( + "Conversion error: {}", + error.strip_prefix("Conversion error: ").unwrap_or(error) + ) + } else if error.contains("Print error:") { + format!( + "Output generation error: {}", + error.strip_prefix("Print error: ").unwrap_or(error) + ) + } else { + error.to_string() + } +} + +fn process_single_input( + input_content: String, + output_path: Option<&str>, + include_metadata_comments: bool, + input_file_path: Option<&Path>, + allow_dirty: bool, +) -> Result<(), MigrationError> { + // Check git status for the file's directory if it's a file (not stdin) + if let Some(file_path) = input_file_path { + validate_git_status_for_files(&[file_path.to_path_buf()], allow_dirty)?; + } + let migrated_content = migrate_content(&input_content)?; + let output_content = add_metadata_to_content(&migrated_content, include_metadata_comments); + + if let Some(output_file) = output_path { + fs::write(output_file, output_content)?; + eprintln!("Migration completed successfully. Output written to: {output_file}"); + } else { + print!("{output_content}"); + } + + Ok(()) +} + +fn process_multiple_inputs( + files: Vec, + fail_fast: bool, + separate_files: bool, + include_metadata_comments: bool, + allow_dirty: bool, +) -> Result<(), MigrationError> { + // Check git status for all directories before processing + validate_git_status_for_files(&files, allow_dirty)?; + + let mut errors = Vec::new(); + + for file_path in files { + match fs::read_to_string(&file_path) { + Ok(content) => match migrate_content(&content) { + Ok(migrated_content) => { + let output_content = + add_metadata_to_content(&migrated_content, include_metadata_comments); + + let output_path = if separate_files { + generate_output_filename(&file_path) + } else { + file_path.clone() + }; + + if let Err(e) = fs::write(&output_path, output_content) { + let error_msg = format!("Failed to write {}: {}", output_path.display(), e); + if fail_fast { + return Err(MigrationError::IoError(e)); + } + errors.push(error_msg); + } else if separate_files { + eprintln!( + "Migrated: {} -> {}", + file_path.display(), + output_path.display() + ); + } else { + eprintln!("Migrated: {}", file_path.display()); + } + } + Err(e) => { + let error_msg = format!("{}: {}", file_path.display(), e); + if fail_fast { + return Err(e); + } + errors.push(error_msg); + } + }, + Err(e) => { + let error_msg = format!("Failed to read {}: {}", file_path.display(), e); + if fail_fast { + return Err(MigrationError::IoError(e)); + } + errors.push(error_msg); + } + } + } + + if !errors.is_empty() { + eprintln!("Errors encountered during migration:"); + for error in &errors { + eprintln!(" - {error}"); + } + return Err(MigrationError::MigrationFailed(format!( + "{} errors occurred", + errors.len() + ))); + } + + Ok(()) +} + +fn main() -> Result<(), Box> { + let cli = Cli::parse(); + + // Note: Git status is now checked per-directory in processing functions + + // Handle input sources + match cli.inputs.len() { + 0 => { + // No inputs provided + if cli.no_stdin { + eprintln!("Error: {}", MigrationError::NoInputs); + std::process::exit(1); + } + + // Read from stdin + let mut buffer = String::new(); + if let Err(e) = io::stdin().read_to_string(&mut buffer) { + eprintln!("Error: Failed to read from stdin: {e}"); + std::process::exit(1); + } + if let Err(e) = process_single_input( + buffer, + cli.output.as_deref(), + !cli.no_metadata, + None, + cli.allow_dirty, + ) { + eprintln!("Error: {e}"); + std::process::exit(1); + } + } + 1 => { + // Single input + let input = &cli.inputs[0]; + + if input == "-" { + // Explicit stdin + let mut buffer = String::new(); + if let Err(e) = io::stdin().read_to_string(&mut buffer) { + eprintln!("Error: Failed to read from stdin: {e}"); + std::process::exit(1); + } + if let Err(e) = process_single_input( + buffer, + cli.output.as_deref(), + !cli.no_metadata, + None, + cli.allow_dirty, + ) { + eprintln!("Error: {e}"); + std::process::exit(1); + } + } else { + let path = Path::new(input); + if path.is_file() { + // Single file + let content = match fs::read_to_string(path) { + Ok(content) => content, + Err(e) => { + eprintln!("Error: Failed to read file '{input}': {e}"); + std::process::exit(1); + } + }; + let output_path = if cli.output.is_none() { + if cli.keep { + Some(generate_output_filename(path).to_string_lossy().to_string()) + } else { + // In-place modification for single file + Some(input.to_string()) + } + } else { + cli.output.clone() + }; + + if let Err(e) = process_single_input( + content, + output_path.as_deref(), + !cli.no_metadata, + Some(path), + cli.allow_dirty, + ) { + eprintln!("Error: {e}"); + std::process::exit(1); + } + } else if path.is_dir() { + // Single directory + let files = match collect_input_files(&cli.inputs, !cli.no_recursive) { + Ok(files) => files, + Err(e) => { + eprintln!("Error: {e}"); + std::process::exit(1); + } + }; + if let Err(e) = process_multiple_inputs( + files, + cli.fail_fast, + cli.keep, + !cli.no_metadata, + cli.allow_dirty, + ) { + eprintln!("Error: {e}"); + std::process::exit(1); + } + } else { + eprintln!("Error: Input path not found: {input}"); + std::process::exit(1); + } + } + } + _ => { + // Multiple inputs + if cli.output.is_some() { + eprintln!("Warning: Output file option ignored when processing multiple inputs"); + } + + let files = match collect_input_files(&cli.inputs, !cli.no_recursive) { + Ok(files) => files, + Err(e) => { + eprintln!("Error: {e}"); + std::process::exit(1); + } + }; + if let Err(e) = process_multiple_inputs( + files, + cli.fail_fast, + cli.keep, + !cli.no_metadata, + cli.allow_dirty, + ) { + eprintln!("Error: {e}"); + std::process::exit(1); + } + } + } + + Ok(()) +} diff --git a/tools/opslang-migration/src/v0_to_v1.rs b/tools/opslang-migration/src/v0_to_v1.rs new file mode 100644 index 0000000..3e7cd19 --- /dev/null +++ b/tools/opslang-migration/src/v0_to_v1.rs @@ -0,0 +1,926 @@ +use std::collections::VecDeque; +use std::fmt::Debug; + +use opslang_ast::V1Token; +use opslang_ast::token::IntoPosition; +use opslang_ast::token::IntoSpan; +use opslang_ast::v0::BinOpKind; +use opslang_ast::v1::context::Context; +use opslang_printer::{Naive, PrettyPrint, PrintOptions}; + +// Import v0 and v1 types +use opslang_ast::v0; +use opslang_ast::v1; + +use crate::{ConversionError, Migrate, MigrationError}; + +/// A Zero-Sized Type (ZST) that implements migration from v0 to v1. +/// +/// This type represents the migration path from opslang v0 syntax to v1 syntax. +/// It can be used to convert v0 AST structures to their v1 equivalents. +/// +/// # Examples +/// +/// ```rust +/// # use opslang_migration::{Migrate, V0ToV1}; +/// # use opslang_ast::{V0, V1}; +/// let migrator = V0ToV1; +/// let v0_code = "NOP"; +/// // Migration may succeed or fail depending on implementation status +/// let result = migrator.migrate(v0_code); +/// // Just check that we get some result +/// match result { +/// Ok(output) => assert!(!output.is_empty()), +/// Err(_) => (), // Also acceptable +/// } +/// ``` +pub struct V0ToV1; + +impl Migrate for V0ToV1 { + type Error = MigrationError; + + fn migrate(&self, input: &str) -> Result { + // Create a v1 context for allocating reference types + let ctx = Context::new(); + + // Parse v0 input + let v0_statements = opslang_parser::v0::parser::parse_statements(input) + .map_err(|e| MigrationError::ParseError(e.to_string()))?; + + // Convert v0 AST to v1 AST + let v1_program = v0_statements.convert(&ctx)?; + + // Print v1 AST to string + let options = PrintOptions::::default(); + // This line can be written more simply, but keep it to assert + // the important contraction that `v1::Program` can be printed. + let output = as PrettyPrint>::to_pretty_string( + &v1_program, + &options, + ); + + { + let ast_context = Context::new(); + let _program = parse_source(&output, &ast_context).unwrap_or_else(|e| { + if let parol_runtime::ParolError::ParserError( + parol_runtime::ParserError::SyntaxErrors { entries }, + ) = &e + { + for entry in entries { + eprintln!( + "Syntax error at {}: {}\n source:\n{}", + entry.error_location, + entry.cause, + entry.input.as_ref().unwrap().input + ); + } + } else { + eprintln!("Parse error: {e}"); + } + panic!("Failed to parse migrated code: {e}") + }); + } + + Ok(output) + } +} + +/// Helper function to parse source code into AST. +fn parse_source<'cx>( + source: &'cx str, + context: &'cx Context<'cx>, +) -> Result, parol_runtime::ParolError> { + let input = opslang_parser::ParserInput { + content: source, + file_name: "after_migration.ops".into(), + } + .assume_inferred(); + use opslang_parser::ParseOps; + opslang_ast::v1::Program::parse(input, context) +} + +// Helper functions for common Apply expression patterns + +/// Creates a function application expression with a function name +fn create_apply_with_string_function<'cx>( + ctx: &'cx Context<'cx, ConvertedFamily>, + function_name: &str, + args: Vec>, +) -> v1::Expr<'cx, ConvertedFamily> { + let function_path = v1::Expr::ident(ctx, function_name, Span); + v1::Expr::apply(ctx, function_path, args) +} + +/// A trait for converting v0 AST nodes to v1 AST nodes. +/// +/// This trait is implemented for each v0 type that needs to be converted to v1. +/// The conversion uses a Context to manage lifetimes and allocate v1 reference types. +pub trait ConvertV0ToV1<'cx> { + /// The target v1 type after conversion. + type Converted; + + /// Converts the v0 type to its v1 equivalent. + /// + /// # Parameters + /// + /// - `ctx`: The context for allocating v1 reference types + /// + /// # Returns + /// + /// - `Ok(Self::Converted)`: The converted v1 type + /// - `Err(ConversionError)`: An error if the conversion fails + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result; +} + +#[derive(Debug, PartialEq, Clone, Copy, Default)] +pub struct ConvertedFamily; + +impl<'cx> v1::TypeFamily<'cx> for ConvertedFamily { + opslang_ast_macro::v1_default_type_subst! { + Span = Span, + Position = Position, + .. + } +} + +#[derive(Debug, PartialEq, Clone, Copy, Default)] +/// Dummy `Span`. +/// +/// `Span` is not available in converted v1 AST currently. Parse the converted v1 AST +/// to retrieve spans and positions. +pub struct Span; + +#[derive(Debug, PartialEq, Clone, Copy, Default)] +/// Dummy `Position`. +/// +/// `Position` is not available in converted v1 AST currently. Parse the converted v1 AST +/// to retrieve spans and positions. +pub struct Position; + +impl<'cx> IntoSpan<'cx, ConvertedFamily> for Span { + fn into_span(self) -> Self { + self + } +} + +impl<'cx> IntoPosition<'cx, ConvertedFamily> for Position { + fn into_position(self) -> Self { + self + } +} + +// Implementation of ConvertV0ToV1 for basic types + +impl<'cx> ConvertV0ToV1<'cx> for Vec { + type Converted = v1::Program<'cx, ConvertedFamily>; + + fn convert( + mut self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + let mut scope_items = Vec::new(); + + if self.last().is_some_and(|statement| { + if let v0::Statement::Single(row) = statement { + row.breaks.is_none() && row.content.is_none() && row.comment_trailing.is_none() + } else { + false + } + }) { + self.pop(); + } + + for statement in self { + match statement { + v0::Statement::Single(row) => { + let converted_row = row.convert(ctx)?; + scope_items.push(v1::ScopeItem::::Row(converted_row)); + } + v0::Statement::Block(block) => { + let converted_block = block.convert(ctx)?; + scope_items.push(v1::ScopeItem::Block(converted_block)); + } + } + } + + let scope = v1::Scope { + items: ctx.alloc_scope_item_slice(scope_items), + }; + + // Wrap the entire v0 program in a main function + let main_function = v1::FunctionDef { + prc_token: V1Token![prc](Span), + name: v1::Ident::new(ctx, "main", Span), + left_paren: v1::token::OpenParen(Position), + parameters: &[], + right_paren: v1::token::CloseParen(Position), + return_type: v1::FnReturnTy(None), + body: ctx.alloc_block(v1::Block { + left_brace: v1::token::OpenBrace(Position), + scope, + right_brace: v1::token::CloseBrace(Position), + }), + }; + + let definition = v1::ToplevelItem { + kind: Some(v1::DefinitionKind::Function(main_function)), + ..Default::default() + }; + let definitions = ctx.alloc_toplevel_item_slice(vec![definition]); + + Ok(v1::Program { + toplevel_items: definitions, + }) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::SRow { + type Converted = &'cx v1::Row<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + let converted = self.value.convert(ctx)?; + Ok(ctx.alloc_row(converted)) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::Row { + type Converted = v1::Row<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + let breaks = if self.breaks.is_some() { + Some(V1Token![.](Position)) + } else { + None + }; + + let statement = if let Some(stmt) = self.content { + Some(stmt.convert(ctx)?) + } else { + None + }; + + let comment = if let Some(v0::Comment(comment_text)) = self.comment_trailing { + let comment_str = ctx.alloc_str(&comment_text); + Some(ctx.alloc_comment(v1::Comment { + content: comment_str, + span: Span, + })) + } else { + None + }; + + Ok(v1::Row { + breaks, + statement, + comment, + }) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::SBlock { + type Converted = &'cx v1::Block<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + let block = self.value.convert(ctx)?; + Ok(ctx.alloc_block(block)) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::Block { + type Converted = v1::Block<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + let mut scope_items = Vec::new(); + + for row in self.rows { + let converted_row = row.convert(ctx)?; + scope_items.push(v1::ScopeItem::Row(converted_row)); + } + + let scope = v1::Scope { + items: ctx.alloc_scope_item_slice(scope_items), + }; + + Ok(v1::Block { + left_brace: v1::token::OpenBrace(Position), + scope, + right_brace: v1::token::CloseBrace(Position), + }) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::SingleStatement { + type Converted = v1::Statement<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + match self { + v0::SingleStatement::Let(let_stmt) => { + let converted_let = let_stmt.convert(ctx)?; + Ok(v1::Statement::Let(converted_let)) + } + v0::SingleStatement::Return => Ok(v1::Statement::Return(v1::ReturnStmt { + return_token: V1Token![return](Span), + semi: V1Token![;](Position), + })), + v0::SingleStatement::Command(cmd) => { + // Convert command to expression statement + let expr = cmd.convert(ctx)?; + Ok(v1::Statement::Expr(v1::ExprStatement { + expr, + semi: V1Token![;](Position), + })) + } + v0::SingleStatement::Print(print) => { + // Convert print to expression statement + let expr = print.convert(ctx)?; + Ok(v1::Statement::Expr(v1::ExprStatement { + expr, + semi: V1Token![;](Position), + })) + } + v0::SingleStatement::Call(call) => { + // Convert call to expression statement + let expr = call.convert(ctx)?; + Ok(v1::Statement::Expr(v1::ExprStatement { + expr, + semi: V1Token![;](Position), + })) + } + v0::SingleStatement::Wait(wait) => { + // Convert wait to expression statement + let expr = wait.convert(ctx)?; + Ok(v1::Statement::Expr(v1::ExprStatement { + expr, + semi: V1Token![;](Position), + })) + } + v0::SingleStatement::Assert(assert) => { + // Convert assert to expression statement + let expr = assert.convert(ctx)?; + Ok(v1::Statement::Expr(v1::ExprStatement { + expr, + semi: V1Token![;](Position), + })) + } + v0::SingleStatement::AssertEq(assert_eq) => { + // Convert assert_eq to expression statement + let expr = assert_eq.convert(ctx)?; + Ok(v1::Statement::Expr(v1::ExprStatement { + expr, + semi: V1Token![;](Position), + })) + } + v0::SingleStatement::Set(set) => { + // Convert set to expression statement + let expr = set.convert(ctx)?; + Ok(v1::Statement::Expr(v1::ExprStatement { + expr, + semi: V1Token![;](Position), + })) + } + } + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::Let { + type Converted = v1::Let<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + let variable = self.variable.convert(ctx)?; + let rhs = self.rhs.convert(ctx)?; + + Ok(v1::Let { + let_token: V1Token![let](Span), + variable, + eq: V1Token![=](Position), + rhs, + semi: V1Token![;](Position), + }) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::Ident { + type Converted = v1::Ident<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + Ok(v1::Ident::new(ctx, &self.raw, Span)) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::VariablePath { + type Converted = v1::Path<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + let segments: Vec> = self + .raw + .split('.') + .map(|segment| v1::Ident::new(ctx, segment, Span)) + .collect(); + + Ok(v1::Path::new(ctx.alloc_ident_slice(segments))) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::Command { + type Converted = v1::Expr<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + // Convert destination spec (part 1) + // Create command name as a string literal (variable reference) + assert!(!self.name.contains('.')); + let path_string = if let Some(receiver_component) = &self.destination.receiver_component { + if let Some(executor_component) = &self.destination.executor_component { + format!("{}.{}", executor_component.name, self.name) + } else { + format!("{}.{}", receiver_component.name, self.name) + } + } else { + self.name + }; + let segments = path_string + .split('.') + .map(|seg| v1::Ident::new(ctx, seg, Span)) + .collect::>(); + let command_path = v1::Path::new(ctx.alloc_ident_slice(segments)); + + // Create the function expression (command name as a variable) + let function_expr = v1::Expr::variable(ctx, command_path); + + // Convert arguments + let mut converted_args = Vec::new(); + for arg in self.args { + converted_args.push(arg.convert(ctx)?); + } + + // Convert destination spec (part 2) + let mut qualifs = Vec::new(); + if let Some(receiver_component) = &self.destination.receiver_component { + let segments = receiver_component + .exec_method + .split('.') + .map(|seg| v1::Ident::new(ctx, seg, Span)) + .collect::>(); + let path = v1::Path::new(ctx.alloc_ident_slice(segments)); + let kind_spec = v1::Modifier { + at_token: V1Token![@](Position), + id: path, + arg: if let Some(expr) = self.destination.time_indicator { + Some(v1::ModifierParam { + colon_token: V1Token![:](Position), + value: expr.convert(ctx)?, + }) + } else { + None + }, + }; + qualifs.push(v1::Qualif::Modifier(kind_spec)); + } else { + assert!( + self.destination.time_indicator.is_none(), + "invalid ti occurrence" + ) + } + if let Some(executor_component) = &self.destination.executor_component { + if executor_component.name.contains('.') { + unimplemented!() + } + + let receiver_component = self.destination.receiver_component.as_ref().unwrap(); + let component = v1::DefaultModifier { + tilde_token: V1Token![~](Position), + value: v1::Path::single(ctx, &receiver_component.name, Span), + }; + qualifs.push(v1::Qualif::DefaultModifier(component)); + } + + Ok(v1::Expr::pre_qualified( + ctx, + qualifs, + v1::Expr::apply(ctx, function_expr, converted_args), + )) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::Print { + type Converted = v1::Expr<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + let converted_arg = self.arg.convert(ctx)?; + Ok(create_apply_with_string_function( + ctx, + "print", + vec![converted_arg], + )) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::Expr { + type Converted = v1::Expr<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + match self { + v0::Expr::Variable(var_path) => { + let path = var_path.convert(ctx)?; + Ok(v1::Expr::variable(ctx, path)) + } + v0::Expr::Literal(literal) => literal.convert(ctx), + v0::Expr::FunCall(function, args) => { + let converted_function = function.convert(ctx)?; + let mut converted_args = Vec::new(); + for arg in args { + converted_args.push(arg.convert(ctx)?); + } + + Ok(v1::Expr::apply(ctx, converted_function, converted_args)) + } + v0::Expr::TlmRef(variable_path) => { + // TlmRef ($var) becomes unary Deref in v1 + let path = variable_path.convert(ctx)?; + Ok(v1::Expr::unary( + ctx, + v1::UnOp::Deref(V1Token![$](Position)), + v1::Expr::variable(ctx, path), + )) + } + v0::Expr::UnOp(un_op_kind, expr) => { + let converted_expr = expr.convert(ctx)?; + let op = match un_op_kind { + v0::UnOpKind::Neg => v1::UnOp::Neg(V1Token![-](Position)), + }; + + Ok(v1::Expr::unary(ctx, op, converted_expr)) + } + v0::Expr::BinOp(bin_op_kind, lhs, rhs) => { + let converted_lhs = lhs.convert(ctx)?; + let converted_rhs = rhs.convert(ctx)?; + + match bin_op_kind { + v0::BinOpKind::Compare(compare_op) => { + // Convert to Compare expression + let v1_compare_op = match compare_op { + v0::CompareBinOpKind::GreaterEq => { + v1::CompareOp::GreaterEq(V1Token![>=](Span)) + } + v0::CompareBinOpKind::LessEq => { + v1::CompareOp::LessEq(V1Token![<=](Span)) + } + v0::CompareBinOpKind::Greater => { + v1::CompareOp::Greater(V1Token![>](Position)) + } + v0::CompareBinOpKind::Less => { + v1::CompareOp::Less(V1Token![<](Position)) + } + v0::CompareBinOpKind::Equal => v1::CompareOp::Equal(V1Token![==](Span)), + v0::CompareBinOpKind::NotEqual => v1::CompareOp::NotEqual( + v1::NotEqualToken::BangEqual(V1Token![!=](Span)), + ), + }; + + Ok(v1::Expr::compare_single( + ctx, + converted_lhs, + v1_compare_op, + converted_rhs, + )) + } + _ => { + // Convert to Binary expression + let v1_bin_op = match bin_op_kind { + v0::BinOpKind::If => { + unimplemented!("please report usage of infix `if`") + } + v0::BinOpKind::And => v1::BinOp::And(V1Token![&&](Span)), + v0::BinOpKind::Or => v1::BinOp::Or(V1Token![||](Span)), + v0::BinOpKind::In => unimplemented!( + "`in` support have been removed. please report usage of infix `in`" + ), + v0::BinOpKind::Mul => v1::BinOp::Mul(V1Token![*](Position)), + v0::BinOpKind::Div => v1::BinOp::Div(V1Token![/](Position)), + v0::BinOpKind::Mod => v1::BinOp::Mod(V1Token![%](Position)), + v0::BinOpKind::Add => v1::BinOp::Add(V1Token![+](Position)), + v0::BinOpKind::Sub => v1::BinOp::Sub(V1Token![-](Position)), + v0::BinOpKind::Compare(_) => unreachable!(), // Already handled above + }; + + Ok(v1::Expr::binary( + ctx, + converted_lhs, + v1_bin_op, + converted_rhs, + )) + } + } + } + } + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::Literal { + type Converted = v1::Expr<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + Ok(v1::Expr::literal( + ctx, + match self { + v0::Literal::String(s) => { + let string_str = ctx.alloc_str(&s); + v1::literal::Literal::String(v1::literal::String { + raw: string_str, + span: Span, + }) + } + v0::Literal::Numeric(numeric, suffix) => { + let converted_numeric = (numeric, suffix).convert(ctx)?; + v1::literal::Literal::Numeric(converted_numeric) + } + v0::Literal::Array(exprs) => { + let mut converted_exprs = Vec::new(); + for expr in exprs { + converted_exprs.push(expr.convert(ctx)?); + } + v1::literal::Literal::Array(v1::literal::Array { + left_bracket: v1::token::OpenSquare(Position), + exprs: ctx.alloc_expr_slice(converted_exprs), + right_bracket: v1::token::CloseSquare(Position), + }) + } + v0::Literal::DateTime(date_time) => { + // Convert DateTime to RFC3339 string + let datetime_string = date_time.to_rfc3339(); + let datetime_str = ctx.alloc_str(&datetime_string); + + v1::literal::Literal::date_time(ctx, datetime_str, Span) + } + v0::Literal::TlmId(tlm_id) => { + // TlmId literals should be converted to unary IdRef expressions + + let path = v1::Path::new( + ctx.alloc_ident_slice( + tlm_id + .split('.') + .map(|segment| v1::Ident::new(ctx, segment, Span)), + ), + ); + return Ok(v1::Expr::unary( + ctx, + v1::UnOp::IdRef(V1Token![&](Position)), + v1::Expr::variable(ctx, path), + )); + } + v0::Literal::Bytes(bytes) => { + // Convert Vec to hex string + let hex_string = bytes.iter().map(|b| format!("{b:02x}")).collect::(); + let hex_str = ctx.alloc_str(&hex_string); + + v1::literal::Literal::hex_bytes(ctx, hex_str, Span) + } + }, + )) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for (v0::Numeric, Option) { + type Converted = v1::literal::Numeric<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + let (numeric, suffix) = self; + let suffix = suffix.map(|n| match n { + v0::NumericSuffix::Second => v1::Numeric::suffix(ctx, "s", Span), + }); + match numeric { + v0::Numeric::Integer(raw, prefix) => { + let raw_str = ctx.alloc_str(&raw); + let kind = match prefix { + v0::IntegerPrefix::Hexadecimal => { + v1::literal::NumericKind::Integer(v1::literal::IntegerPrefix::Hexadecimal) + } + v0::IntegerPrefix::Octal => { + v1::literal::NumericKind::Integer(v1::literal::IntegerPrefix::Octal) + } + v0::IntegerPrefix::Binary => { + v1::literal::NumericKind::Integer(v1::literal::IntegerPrefix::Binary) + } + v0::IntegerPrefix::Decimal => { + v1::literal::NumericKind::Integer(v1::literal::IntegerPrefix::None) + } + }; + + Ok(v1::literal::Numeric { + raw: raw_str, + kind, + suffix, + }) + } + v0::Numeric::Float(raw) => { + let raw_str = ctx.alloc_str(&raw); + Ok(v1::literal::Numeric { + raw: raw_str, + kind: v1::literal::NumericKind::Float, + suffix, + }) + } + } + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::Call { + type Converted = v1::Expr<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + // Create path argument as string literal + let path_str = ctx.alloc_str(&self.path.full_name); + let file = v1::literal::Literal::string(ctx, path_str, Span); + let path = v1::Path::single(ctx, "main", Span); + let arg = v1::Expr::import(ctx, file, V1Token![?](Position), path); + + Ok(create_apply_with_string_function(ctx, "call", vec![arg])) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::Wait { + type Converted = v1::Expr<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + if let v0::Expr::BinOp(BinOpKind::And, ..) = self.condition { + return Err(ConversionError::UnsupportedFeature { + feature: "wait with `and` condition".to_string(), + }); + } + let mut conds = vec![]; + let mut queue = VecDeque::new(); + queue.push_back(self.condition); + while let Some(cond) = queue.pop_front() { + if let v0::Expr::BinOp(BinOpKind::Or, lhs, rhs) = cond { + queue.push_back(*lhs); + queue.push_back(*rhs); + } else { + let condition_expr = cond.convert(ctx)?; + conds.push(v1::SelectItem { + expr: condition_expr, + arrow: V1Token![=>](Span), + body: ctx.alloc_block(v1::Block { + left_brace: v1::token::OpenBrace(Position), + scope: v1::Scope { items: &[] }, + right_brace: v1::token::CloseBrace(Position), + }), + }); + } + } + + if conds.len() == 1 { + // Single condition, no need for select + return Ok(v1::Expr::wait( + ctx, + V1Token![wait](Span), + conds.pop().unwrap().expr, + )); + } + + Ok(v1::Expr::select( + ctx, + V1Token![select](Span), + v1::token::OpenBrace(Position), + ctx.alloc_select_item_slice(conds), + v1::token::CloseBrace(Position), + )) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::Assert { + type Converted = v1::Expr<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + let condition_expr = self.condition.convert(ctx)?; + Ok(create_apply_with_string_function( + ctx, + "assert", + vec![condition_expr], + )) + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::AssertEq { + type Converted = v1::Expr<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + let left_expr = self.left.convert(ctx)?; + let right_expr = self.right.convert(ctx)?; + + if let Some(tolerance) = self.tolerance { + let tolerance_expr = tolerance.convert(ctx)?; + Ok(create_apply_with_string_function( + ctx, + "assert_eq_tol", + vec![tolerance_expr, left_expr, right_expr], + )) + } else { + Ok(create_apply_with_string_function( + ctx, + "assert_eq", + vec![left_expr, right_expr], + )) + } + } +} + +impl<'cx> ConvertV0ToV1<'cx> for v0::Set { + type Converted = v1::Expr<'cx, ConvertedFamily>; + + fn convert( + self, + ctx: &'cx Context<'cx, ConvertedFamily>, + ) -> Result { + Ok(v1::Expr::set( + ctx, + v1::Expr::variable(ctx, self.name.convert(ctx)?), + V1Token![:=](Span), + self.expr.convert(ctx)?, + )) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_convert_empty_statements() { + let ctx = Context::new(); + let statements: Vec = vec![]; + let result = statements.convert(&ctx); + assert!(result.is_ok()); + let program = result.unwrap(); + assert_eq!(program.toplevel_items.len(), 1); + if let Some(v1::DefinitionKind::Function(func_def)) = &program.toplevel_items[0].kind { + assert_eq!(func_def.name.raw, "main"); + assert_eq!(func_def.parameters.len(), 0); + assert_eq!(func_def.body.scope.items.len(), 0); + } else { + panic!("Expected main function definition"); + } + } + + #[test] + fn test_conversion_error_display() { + let error = ConversionError::UnsupportedFeature { + feature: "test feature".to_string(), + }; + let error_string = error.to_string(); + assert!(error_string.contains("Unsupported feature")); + assert!(error_string.contains("test feature")); + } +} diff --git a/ty/opslang-module/Cargo.toml b/ty/opslang-module/Cargo.toml new file mode 100644 index 0000000..faaae4f --- /dev/null +++ b/ty/opslang-module/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "opslang-module" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +opslang-ty.workspace = true +opslang-ast.workspace = true +opslang-visitor.workspace = true +opslang-visitor-macro.workspace = true +typed-arena.workspace = true diff --git a/ty/opslang-module/src/lib.rs b/ty/opslang-module/src/lib.rs new file mode 100644 index 0000000..a6db76a --- /dev/null +++ b/ty/opslang-module/src/lib.rs @@ -0,0 +1 @@ +pub mod version; diff --git a/ty/opslang-module/src/version.rs b/ty/opslang-module/src/version.rs new file mode 100644 index 0000000..a3a6d96 --- /dev/null +++ b/ty/opslang-module/src/version.rs @@ -0,0 +1 @@ +pub mod v1; diff --git a/ty/opslang-module/src/version/v1.rs b/ty/opslang-module/src/version/v1.rs new file mode 100644 index 0000000..71f819e --- /dev/null +++ b/ty/opslang-module/src/version/v1.rs @@ -0,0 +1,11 @@ +use opslang_visitor_macro::Visit; +use typed_arena::Arena; + +mod module; +pub use module::{AlreadyDefinedError, Module, ModuleDef, ModuleItem, ModuleItemDef, ModuleLoader}; + +pub mod context; +pub use context::ModuleContext; + +pub mod path; +pub use path::{ModulePath, ModulePathData}; diff --git a/ty/opslang-module/src/version/v1/context.rs b/ty/opslang-module/src/version/v1/context.rs new file mode 100644 index 0000000..81e44c5 --- /dev/null +++ b/ty/opslang-module/src/version/v1/context.rs @@ -0,0 +1,70 @@ +use super::*; + +/// The module context for type checking operations. +/// +/// This structure manages memory allocation for types, identifiers, and modules +/// using arenas to ensure efficient memory usage and proper lifetime management. +pub struct ModuleContext<'cx> { + /// Arena for allocating module paths. + path_arena: Arena>, + /// Arena for allocating module definitions. + module_arena: Arena>, + /// Arena for allocating module items. + module_item_arena: Arena>, +} + +impl<'cx> ModuleContext<'cx> { + /// Creates a new typing context with empty arenas. + /// + /// This initializes all the necessary memory arenas for type checking operations. + pub fn new() -> Self { + Self { + path_arena: Arena::new(), + module_arena: Arena::new(), + module_item_arena: Arena::new(), + } + } + + /// Creates a root-level module path. + pub fn alloc_root_path(&'cx self, segment: &'cx str) -> ModulePath<'cx> { + let data = ModulePathData { + segment, + parent: None, + }; + ModulePath(self.path_arena.alloc(data)) + } + + /// Creates a child module path extending a parent. + pub fn alloc_child_path( + &'cx self, + parent: ModulePath<'cx>, + segment: &'cx str, + ) -> ModulePath<'cx> { + let data = ModulePathData { + segment, + parent: Some(parent), + }; + ModulePath(self.path_arena.alloc(data)) + } + + /// Allocates a module in the module arena and returns a reference. + /// + /// This allows modules to be stored with the same lifetime as the typing context, + /// enabling safe references across the type checking process. + pub fn alloc_module(&'cx self, module: ModuleDef<'cx>) -> Module<'cx> { + Module(self.module_arena.alloc(module)) + } + + /// Allocates a module item in the module item arena and returns a reference. + /// + /// This allows module items to be stored with the same lifetime as the typing context. + pub fn alloc_module_item(&'cx self, item: ModuleItemDef<'cx>) -> ModuleItem<'cx> { + ModuleItem(self.module_item_arena.alloc(item)) + } +} + +impl<'cx> Default for ModuleContext<'cx> { + fn default() -> Self { + Self::new() + } +} diff --git a/ty/opslang-module/src/version/v1/module.rs b/ty/opslang-module/src/version/v1/module.rs new file mode 100644 index 0000000..a9ce306 --- /dev/null +++ b/ty/opslang-module/src/version/v1/module.rs @@ -0,0 +1,237 @@ +use std::collections::HashMap; + +use opslang_ty::version::v1::{Ident, PolyTy, Ty}; + +use super::*; + +/// Represents different kinds of items that can exist within a module. +/// +/// Module items define the public interface of a module, including constants, +/// type definitions, and function definitions that can be imported by other modules. +#[derive(Debug, Clone, Visit, PartialEq)] +#[skip_all_visit] +pub enum ModuleItemDef<'cx> { + /// A constant value. + Constant { + /// The identifier of this module item + id: Ident<'cx>, + /// The type associated with this module item + ty: Ty<'cx>, + }, + /// A type definition. + Type { + /// The identifier of this module item + id: Ident<'cx>, + /// The type associated with this module item + ty: Ty<'cx>, + }, + /// A procedure definition. + Prc { + /// The identifier of this module item + id: Ident<'cx>, + /// The type associated with this module item + ty: Ty<'cx>, + }, + /// A library function definition with polymorphic type. + LibraryFn { + /// The identifier of this module item + id: Ident<'cx>, + /// The polymorphic type associated with this module item + ty: PolyTy<'cx>, + }, +} + +#[derive(Debug, Clone, Copy, PartialEq, Visit)] +/// Represents a module item definition. +pub struct ModuleItem<'cx>(pub &'cx ModuleItemDef<'cx>); + +impl<'cx> std::ops::Deref for ModuleItem<'cx> { + type Target = &'cx ModuleItemDef<'cx>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Debug, Clone)] +/// Definition of a module containing named items. +pub struct ModuleDef<'cx> { + /// The name of this module. + id: Ident<'cx>, + + /// Map from item names to their definitions. + items: HashMap<&'cx str, ModuleItemDef<'cx>>, +} + +#[derive(Debug, Clone, Copy)] +/// Represents a module containing named items. +/// +/// Modules provide namespacing and organization for types, functions, and constants. +/// Each module maintains a mapping from names to their corresponding items. +pub struct Module<'cx>(pub &'cx ModuleDef<'cx>); + +impl<'cx> std::ops::Deref for Module<'cx> { + type Target = &'cx ModuleDef<'cx>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Debug)] +/// Error indicating that a module item with the same name already exists. +/// +/// FIXME: Replace with `HashMap::try_insert` once stabilized. +pub struct AlreadyDefinedError<'module, 'cx> { + pub name: &'cx str, + pub entry: std::collections::hash_map::OccupiedEntry<'module, &'cx str, ModuleItemDef<'cx>>, +} + +impl<'cx> ModuleDef<'cx> { + /// Creates a new empty module with the given name. + /// + /// The module starts with no items and can be populated using add_item. + pub fn new(id: Ident<'cx>) -> Self { + Self { + id, + items: HashMap::new(), + } + } + + /// Returns the name of this module. + /// + /// This provides read-only access to the module's name. + pub fn name(&self) -> &str { + self.id.name + } + + /// Adds an item to this module. + /// + /// The item is indexed by its name, allowing for efficient lookup. + /// If an item with the same name already exists, + fn add_item(&mut self, item: ModuleItemDef<'cx>) -> Result<(), AlreadyDefinedError<'_, 'cx>> { + let id = match &item { + ModuleItemDef::Constant { id, .. } => id, + ModuleItemDef::Type { id, .. } => id, + ModuleItemDef::Prc { id, .. } => id, + ModuleItemDef::LibraryFn { id, .. } => id, + }; + use std::collections::hash_map::Entry; + // FIXME: Replace with `HashMap::try_insert` once stabilized. + match self.items.entry(id.name) { + Entry::Occupied(occupied_entry) => Err(AlreadyDefinedError { + name: id.name, + entry: occupied_entry, + }), + Entry::Vacant(vacant_entry) => { + vacant_entry.insert(item); + Ok(()) + } + } + } + + /// Creates a new constant module item. + pub fn add_constant( + &mut self, + id: Ident<'cx>, + ty: Ty<'cx>, + ) -> Result<(), AlreadyDefinedError<'_, 'cx>> { + self.add_item(ModuleItemDef::Constant { id, ty }) + } + + /// Creates a new type module item. + pub fn add_type( + &mut self, + id: Ident<'cx>, + ty: Ty<'cx>, + ) -> Result<(), AlreadyDefinedError<'_, 'cx>> { + self.add_item(ModuleItemDef::Type { id, ty }) + } + + /// Creates a new procedure module item. + pub fn add_prc( + &mut self, + id: Ident<'cx>, + ty: Ty<'cx>, + ) -> Result<(), AlreadyDefinedError<'_, 'cx>> { + self.add_item(ModuleItemDef::Prc { id, ty }) + } + + /// Creates a new library function module item, which can be polymorphic. + pub fn add_library_function( + &mut self, + id: Ident<'cx>, + ty: PolyTy<'cx>, + ) -> Result<(), AlreadyDefinedError<'_, 'cx>> { + self.add_item(ModuleItemDef::LibraryFn { id, ty }) + } + + /// Looks up an item by name within this module. + /// + /// Returns None if no item with the given name exists in this module. + pub fn lookup_item(&self, name: opslang_ast::Path<'cx>) -> Option<&ModuleItemDef<'cx>> { + self.items.get(name.to_string().as_str()) + } + + /// Returns an iterator over all items in this module. + /// + /// This allows iteration over module contents without exposing the internal HashMap. + pub fn items(&self) -> impl Iterator> { + self.items.values() + } +} + +/// Manages loading and resolution of modules and their items. +/// +/// The module loader maintains a registry of available modules and provides +/// path resolution functionality for finding items across modules. +#[derive(Debug)] +pub struct ModuleLoader<'cx> { + /// Map from module names to their definitions + modules: HashMap<&'cx str, Module<'cx>>, +} + +impl<'cx> ModuleLoader<'cx> { + /// Creates a new empty module loader. + /// + /// The loader starts with no registered modules. + pub fn new() -> Self { + Self { + modules: HashMap::new(), + } + } + + /// Registers a module with the loader under the given name. + /// + /// This makes the module available for path resolution and import operations. + pub fn add_module(&mut self, module: Module<'cx>) { + self.modules.insert(module.id.name, module); + } + + /// Looks up a module by name. + /// + /// Returns None if no module with the given name is registered. + pub fn lookup_module(&self, name: &str) -> Option> { + self.modules.get(name).copied() + } + + /// Resolves a path to a module item. + /// + /// Currently supports only flat paths that resolve to items in the builtin module. + /// In the future, this will support hierarchical paths like "module::item". + pub fn resolve_path(&self, path: opslang_ast::Path<'cx>) -> Option> { + // Currently only supports non-hierarchical paths + // Future enhancement: support "module::item" format + if let Some(module) = self.modules.get("builtin") { + module.lookup_item(path).map(ModuleItem) + } else { + None + } + } +} + +impl<'cx> Default for ModuleLoader<'cx> { + fn default() -> Self { + Self::new() + } +} diff --git a/ty/opslang-module/src/version/v1/path.rs b/ty/opslang-module/src/version/v1/path.rs new file mode 100644 index 0000000..0eee464 --- /dev/null +++ b/ty/opslang-module/src/version/v1/path.rs @@ -0,0 +1,41 @@ +use std::ops::Deref; + +use opslang_visitor_macro::Visit; + +/// Represents a module path as a cons cell (single-linked list). +/// +/// Module paths form a chain from leaf to root, enabling efficient +/// sharing of common parent paths. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ModulePathData<'cx> { + /// The segment name at this level. + pub segment: &'cx str, + /// Reference to the parent path, or None for root-level modules. + pub parent: Option>, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Visit)] +#[skip_all_visit] +pub struct ModulePath<'cx>(pub(super) &'cx ModulePathData<'cx>); + +impl<'cx> Deref for ModulePath<'cx> { + type Target = &'cx ModulePathData<'cx>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'cx> ModulePath<'cx> { + /// Collects all components from root to leaf. + pub fn components(self) -> Vec<&'cx str> { + let mut result = Vec::new(); + let mut current = Some(self); + while let Some(path) = current { + result.push(path.segment); + current = path.parent; + } + result.reverse(); + result + } +} diff --git a/ty/opslang-ty/Cargo.toml b/ty/opslang-ty/Cargo.toml new file mode 100644 index 0000000..e30874e --- /dev/null +++ b/ty/opslang-ty/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "opslang-ty" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +opslang-ast.workspace = true +opslang-visitor.workspace = true +opslang-visitor-macro.workspace = true +typed-arena.workspace = true diff --git a/ty/opslang-ty/src/lib.rs b/ty/opslang-ty/src/lib.rs new file mode 100644 index 0000000..a6db76a --- /dev/null +++ b/ty/opslang-ty/src/lib.rs @@ -0,0 +1 @@ +pub mod version; diff --git a/ty/opslang-ty/src/version.rs b/ty/opslang-ty/src/version.rs new file mode 100644 index 0000000..9aac22e --- /dev/null +++ b/ty/opslang-ty/src/version.rs @@ -0,0 +1,27 @@ +macro_rules! declare_versions { + () => {}; + ($([$current:vis])? $path:ident, $ty:ident; $($tt:tt)*) => { + pub mod $path; + pub struct $ty; + + $( + /// Type alias for the default version of the ast. + $current type Default = $ty; + $current use $path::*; + )? + + declare_versions! { $($tt)* } + } +} + +/// Assertion that [`Default`] type alias exists at this scope. +/// +/// This is a compile-time check that will fail if [`Default`] is not defined. +#[allow(dead_code)] +const _: () = { + let _: Default; +}; + +declare_versions! { + [pub] v1, V1; +} diff --git a/ty/opslang-ty/src/version/v1.rs b/ty/opslang-ty/src/version/v1.rs new file mode 100644 index 0000000..7346dbb --- /dev/null +++ b/ty/opslang-ty/src/version/v1.rs @@ -0,0 +1,337 @@ +/*! +Type system for opslang v1. + +This module defines the type system structures including type kinds, identifiers, and +module management for the opslang v1 implementation. + +**IMPORTANT**: When modifying type structures in this module, update the visitor type +registry in `opslang-ir-macro/src/visitor_type_registry.rs` to ensure proper visitor +macro generation. Choose whether to make types hookable (add to node types) or not +hookable (add to inter types). +*/ + +use opslang_visitor_macro::Visit; +use std::fmt::Display; +use std::hash::Hash; +use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; +use typed_arena::Arena; + +use opslang_ast::syntax::v1 as ast; + +pub mod hm; +pub use hm::Substitution; + +mod infer; +pub use infer::{FloatVid, InferTy, IntVid, TyVid}; + +pub mod constructor; + +pub mod context; +pub use context::TypingContext; + +mod poly; +pub use poly::PolyTy; + +/// Represents the different kinds of types in the type system. +/// +/// This enum defines all possible type variants that can exist in the language, +/// including primitive types, compound types, and type variables for inference. +#[derive(Debug, Clone, PartialEq, Visit)] +pub enum TyKind<'cx> { + /// Signed integer types. + Int(IntTy), + + /// Unsigned integer types. + Uint(UintTy), + + /// Floating point types. + Float(FloatTy), + + /// String type for text data. + String, + + /// Byte array type for binary data. + Bytes, + + /// Boolean type for true/false values. + Bool, + + /// Duration type for time intervals. + Duration, + + /// Time type for specific points in time. + Time, + + /// Array type containing elements of a specific inner type. + Array { inner: Ty<'cx> }, + + /// Function type with argument types and return type. + Function { + arg: Vec>, + ret: Ty<'cx>, + + /// Whether this is a procedure. + is_procedure: Option>, + }, + + /// Inference variable used during type inference. + Infer(InferTy), + + /// Unit type representing no meaningful value. + Unit, + + /// External type identified by a string name. + External { path: ast::Path<'cx>, ty: Ty<'cx> }, +} + +/// A type reference that points to a type kind. +/// +/// This is a lightweight wrapper around a reference to TyKind that allows +/// for efficient sharing of type information across the type checker. +#[derive(Debug, Clone, Copy, PartialEq, Visit)] +pub struct Ty<'cx>(pub &'cx TyKind<'cx>); + +impl<'cx> Ty<'cx> { + /// Returns a reference to the underlying type kind. + /// + /// This provides access to the actual type information stored within the type reference. + pub fn kind(&self) -> &'cx TyKind<'cx> { + self.0 + } +} + +impl<'cx> std::ops::Deref for Ty<'cx> { + type Target = &'cx TyKind<'cx>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Display for Ty<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +/// Signed integer types, following Rust's naming convention. +#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Visit)] +#[skip_all_visit] +pub enum IntTy { + I8, + I16, + I32, + I64, +} + +/// Unsigned integer types, following Rust's naming convention. +#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Visit)] +#[skip_all_visit] +pub enum UintTy { + U8, + U16, + U32, + U64, +} + +/// Floating point types, following Rust's naming convention. +#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Visit)] +#[skip_all_visit] +pub enum FloatTy { + F32, + F64, +} + +#[derive(Debug, Clone, Copy, PartialEq, Visit)] +pub enum Procedure<'cx> { + SameModule { name: Ident<'cx> }, + // FIXME: Add cross-module procedures + External, +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub enum Integer { + Int(IntTy), + Uint(UintTy), +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub enum Numeric { + Int(IntTy), + Uint(UintTy), + Float(FloatTy), +} + +/// Represents an identifier with scope information. +/// +/// Identifiers are used to distinguish variables and functions across different scopes, +/// allowing proper name resolution in nested contexts. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Visit)] +#[skip_all_visit] +pub struct Identifier<'cx> { + /// The string name of the identifier + pub name: &'cx str, + /// The unique definition ID for this identifier + pub definition_id: usize, +} + +/// A reference to an identifier. +/// +/// This is a lightweight wrapper around an Identifier reference that enables +/// efficient passing and comparison of identifiers. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Visit)] +pub struct Ident<'cx>(pub &'cx Identifier<'cx>); + +impl<'cx> std::ops::Deref for Ident<'cx> { + type Target = &'cx Identifier<'cx>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'cx> TyKind<'cx> { + /// Performs the occurs check for the given type variable. + /// + /// This check prevents infinite types by ensuring a type variable doesn't + /// occur within its own definition during unification. + pub fn occurs(&self, var: TyVid) -> bool { + match self { + // Direct variable occurrence + TyKind::Infer(InferTy::TyVar(v)) => *v == var, + // IntVar and FloatVar cannot occur in general type variables + TyKind::Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) => false, + // Recursively check array element type + TyKind::Array { inner } => inner.occurs(var), + // Check all argument types and return type + TyKind::Function { + arg, + ret, + is_procedure: _, + } => arg.iter().any(|arg| arg.occurs(var)) || ret.occurs(var), + // Primitive types cannot contain variables + _ => false, + } + } + + /// Returns `true` if the ty kind is [`Bool`]. + /// + /// [`Bool`]: TyKind::Bool + #[must_use] + pub fn is_bool(&self) -> bool { + matches!(self, Self::Bool) + } + + /// Returns `true` if the ty kind is [`Duration`]. + /// + /// [`Duration`]: TyKind::Duration + #[must_use] + pub fn is_duration(&self) -> bool { + matches!(self, Self::Duration) + } + + /// Returns `true` if the ty kind is [`Time`]. + /// + /// [`Time`]: TyKind::Time + #[must_use] + pub fn is_time(&self) -> bool { + matches!(self, Self::Time) + } + + /// Returns `true` if the ty kind is [`Unit`]. + /// + /// [`Unit`]: TyKind::Unit + #[must_use] + pub fn is_unit(&self) -> bool { + matches!(self, Self::Unit) + } + + #[must_use] + pub fn as_numeric(&self) -> Option { + match self { + TyKind::Int(int_ty) => Some(Numeric::Int(*int_ty)), + TyKind::Uint(uint_ty) => Some(Numeric::Uint(*uint_ty)), + TyKind::Float(float_ty) => Some(Numeric::Float(*float_ty)), + _ => None, + } + } + + #[must_use] + pub fn is_numeric(&self) -> bool { + matches!(self, TyKind::Int(_) | TyKind::Uint(_) | TyKind::Float(_)) + } + + #[must_use] + pub fn as_integer(&self) -> Option { + match self { + TyKind::Int(int_ty) => Some(Integer::Int(*int_ty)), + TyKind::Uint(uint_ty) => Some(Integer::Uint(*uint_ty)), + _ => None, + } + } + + #[must_use] + pub fn is_integer(&self) -> bool { + matches!(self, TyKind::Int(_) | TyKind::Uint(_)) + } + + /// Returns `true` if the ty kind is [`Infer`]. + /// + /// [`Infer`]: TyKind::Infer + #[must_use] + pub fn is_infer(&self) -> bool { + matches!(self, Self::Infer(..)) + } +} + +impl Display for TyKind<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let e = match self { + TyKind::Int(int_ty) => match int_ty { + IntTy::I8 => "i8", + IntTy::I16 => "i16", + IntTy::I32 => "i32", + IntTy::I64 => "i64", + }, + TyKind::Uint(uint_ty) => match uint_ty { + UintTy::U8 => "u8", + UintTy::U16 => "u16", + UintTy::U32 => "u32", + UintTy::U64 => "u64", + }, + TyKind::Float(float_ty) => match float_ty { + FloatTy::F32 => "f32", + FloatTy::F64 => "f64", + }, + TyKind::String => "string", + TyKind::Bytes => "bytes", + TyKind::Bool => "bool", + TyKind::Duration => "duration", + TyKind::Time => "time", + TyKind::Unit => "()", + // Format array types as [element_type] + TyKind::Array { inner } => return write!(f, "[{inner}]"), + // Format function types as (arg1, arg2, ...) -> return_type + TyKind::Function { + arg, + ret, + is_procedure, + } => { + let arg_strs: Vec = arg.iter().map(|arg| arg.to_string()).collect(); + return if is_procedure.is_some() { + write!(f, "prc ({}) -> {ret}", arg_strs.join(", "),) + } else { + write!(f, "({}) -> {ret}", arg_strs.join(", "),) + }; + } + // Display inference variables with distinctive prefixes + TyKind::Infer(infer_ty) => match infer_ty { + InferTy::TyVar(var) => return write!(f, "{var}"), + InferTy::IntVar(var) => return write!(f, "{var}"), + InferTy::FloatVar(var) => return write!(f, "{var}"), + }, + TyKind::External { path, ty } => return write!(f, "(extern<`{path}`>: {ty})"), + }; + write!(f, "{e}") + } +} diff --git a/ty/opslang-ty/src/version/v1/constructor.rs b/ty/opslang-ty/src/version/v1/constructor.rs new file mode 100644 index 0000000..1aeabf3 --- /dev/null +++ b/ty/opslang-ty/src/version/v1/constructor.rs @@ -0,0 +1,134 @@ +use super::*; + +impl<'cx> Ty<'cx> { + pub fn from_kind(cx: &'cx TypingContext<'cx>, kind: TyKind<'cx>) -> Self { + cx.alloc_type(kind) + } + + pub fn mk_int(cx: &'cx TypingContext<'cx>, int_ty: IntTy) -> Self { + Self::from_kind(cx, TyKind::Int(int_ty)) + } + + pub fn mk_uint(cx: &'cx TypingContext<'cx>, uint_ty: UintTy) -> Self { + Self::from_kind(cx, TyKind::Uint(uint_ty)) + } + + pub fn mk_float(cx: &'cx TypingContext<'cx>, float_ty: FloatTy) -> Self { + Self::from_kind(cx, TyKind::Float(float_ty)) + } + + pub fn mk_i8(cx: &'cx TypingContext<'cx>) -> Self { + Self::mk_int(cx, IntTy::I8) + } + + pub fn mk_i16(cx: &'cx TypingContext<'cx>) -> Self { + Self::mk_int(cx, IntTy::I16) + } + + pub fn mk_i32(cx: &'cx TypingContext<'cx>) -> Self { + Self::mk_int(cx, IntTy::I32) + } + + pub fn mk_i64(cx: &'cx TypingContext<'cx>) -> Self { + Self::mk_int(cx, IntTy::I64) + } + + pub fn mk_u8(cx: &'cx TypingContext<'cx>) -> Self { + Self::mk_uint(cx, UintTy::U8) + } + + pub fn mk_u16(cx: &'cx TypingContext<'cx>) -> Self { + Self::mk_uint(cx, UintTy::U16) + } + + pub fn mk_u32(cx: &'cx TypingContext<'cx>) -> Self { + Self::mk_uint(cx, UintTy::U32) + } + + pub fn mk_u64(cx: &'cx TypingContext<'cx>) -> Self { + Self::mk_uint(cx, UintTy::U64) + } + + pub fn mk_f32(cx: &'cx TypingContext<'cx>) -> Self { + Self::mk_float(cx, FloatTy::F32) + } + + pub fn mk_f64(cx: &'cx TypingContext<'cx>) -> Self { + Self::mk_float(cx, FloatTy::F64) + } + + pub fn mk_string(cx: &'cx TypingContext<'cx>) -> Self { + Self::from_kind(cx, TyKind::String) + } + + pub fn mk_bytes(cx: &'cx TypingContext<'cx>) -> Self { + Self::from_kind(cx, TyKind::Bytes) + } + + pub fn mk_bool(cx: &'cx TypingContext<'cx>) -> Self { + Self::from_kind(cx, TyKind::Bool) + } + + pub fn mk_duration(cx: &'cx TypingContext<'cx>) -> Self { + Self::from_kind(cx, TyKind::Duration) + } + + pub fn mk_time(cx: &'cx TypingContext<'cx>) -> Self { + Self::from_kind(cx, TyKind::Time) + } + + pub fn mk_array(cx: &'cx TypingContext<'cx>, inner: Ty<'cx>) -> Self { + Self::from_kind(cx, TyKind::Array { inner }) + } + + pub fn mk_procedure( + cx: &'cx TypingContext<'cx>, + procedure: Option>, + arg: Vec>, + ret: Ty<'cx>, + ) -> Self { + Self::from_kind( + cx, + TyKind::Function { + arg, + ret, + is_procedure: procedure, + }, + ) + } + + pub fn mk_function(cx: &'cx TypingContext<'cx>, arg: Vec>, ret: Ty<'cx>) -> Self { + Self::from_kind( + cx, + TyKind::Function { + arg, + ret, + is_procedure: None, + }, + ) + } + + pub fn mk_variable(cx: &'cx TypingContext<'cx>, var: TyVid) -> Self { + Self::from_kind(cx, TyKind::Infer(InferTy::TyVar(var))) + } + + pub fn mk_fresh(cx: &'cx TypingContext<'cx>) -> Self { + Self::mk_variable(cx, TyVid::fresh()) + } + + pub fn mk_int_var(cx: &'cx TypingContext<'cx>, var: IntVid) -> Self { + Self::from_kind(cx, TyKind::Infer(InferTy::IntVar(var))) + } + + pub fn mk_float_var(cx: &'cx TypingContext<'cx>, var: FloatVid) -> Self { + Self::from_kind(cx, TyKind::Infer(InferTy::FloatVar(var))) + } + + pub fn mk_unit(cx: &'cx TypingContext<'cx>) -> Self { + Self::from_kind(cx, TyKind::Unit) + } + + pub fn mk_external(cx: &'cx TypingContext<'cx>, path: ast::Path<'cx>, ty: Ty<'cx>) -> Self { + Self::from_kind(cx, TyKind::External { path, ty }) + } +} diff --git a/ty/opslang-ty/src/version/v1/context.rs b/ty/opslang-ty/src/version/v1/context.rs new file mode 100644 index 0000000..99967cd --- /dev/null +++ b/ty/opslang-ty/src/version/v1/context.rs @@ -0,0 +1,72 @@ +pub use super::*; + +/// The main context for type checking operations. +/// +/// This structure manages memory allocation for types, identifiers, and modules +/// using arenas to ensure efficient memory usage and proper lifetime management. +pub struct TypingContext<'cx> { + /// Arena for allocating type kinds + type_arena: Arena>, + /// Arena for allocating identifier information + identifier_arena: Arena>, + /// Global counter for unique definition IDs + next_definition_id: AtomicUsize, +} + +impl<'cx> TypingContext<'cx> { + /// Creates a new typing context with empty arenas. + /// + /// This initializes all the necessary memory arenas for type checking operations. + pub fn new() -> Self { + Self { + type_arena: Arena::new(), + identifier_arena: Arena::new(), + next_definition_id: AtomicUsize::new(1), + } + } + + /// Allocates a type in the type arena and returns a reference. + /// + /// This ensures that types have the same lifetime as the typing context + /// and can be safely shared throughout the type checking process. + pub fn alloc_type(&'cx self, ty: TyKind<'cx>) -> Ty<'cx> { + Ty(self.type_arena.alloc(ty)) + } + + /// Allocates an identifier in the identifier arena and returns a reference. + /// + /// This provides a consistent way to manage identifier lifetimes and enables + /// efficient comparison and storage of identifiers. + pub fn alloc_ident(&'cx self, identifier: Identifier<'cx>) -> Ident<'cx> { + Ident(self.identifier_arena.alloc(identifier)) + } + + /// Allocates a toplevel identifier in the identifier arena and returns a reference. + /// + /// This provides a consistent way to manage identifier lifetimes and enables + /// efficient comparison and storage of identifiers. + pub fn alloc_toplevel_ident(&'cx self, str: &'cx str) -> Ident<'cx> { + Ident(self.identifier_arena.alloc(Identifier { + name: str, + definition_id: 0, + })) + } + + /// Allocates a new identifier with a unique definition ID. + /// + /// Each call to this method generates a globally unique identifier, + /// enabling proper shadowing where multiple variables can have the same name. + pub fn alloc_identifier(&'cx self, name: ast::Ident<'cx>) -> Ident<'cx> { + let definition_id = self.next_definition_id.fetch_add(1, Ordering::SeqCst); + Ident(self.identifier_arena.alloc(Identifier { + name: name.raw, + definition_id, + })) + } +} + +impl<'cx> Default for TypingContext<'cx> { + fn default() -> Self { + Self::new() + } +} diff --git a/ty/opslang-ty/src/version/v1/hm.rs b/ty/opslang-ty/src/version/v1/hm.rs new file mode 100644 index 0000000..70973c4 --- /dev/null +++ b/ty/opslang-ty/src/version/v1/hm.rs @@ -0,0 +1,196 @@ +use std::collections::HashMap; + +use super::{ + FloatTy, FloatVid, InferTy, IntTy, IntVid, Integer, Ty, TyKind, TyVid, TypingContext, UintTy, +}; + +/// Represents a type substitution mapping type variables to concrete types. +/// +/// Substitutions are the result of unification operations and are used to +/// replace type variables with their inferred concrete types throughout the type system. +#[derive(Debug, Clone, Default)] +pub struct Substitution<'cx> { + /// Maps type variables to their substituted types + ty_map: HashMap>, + /// Maps integer variables to their substituted types + int_map: HashMap, + /// Maps float variables to their substituted types + float_map: HashMap, +} + +impl<'cx> Substitution<'cx> { + /// Creates a new empty substitution. + /// + /// An empty substitution represents the identity mapping where no variables are substituted. + pub fn new() -> Self { + Self { + ty_map: HashMap::new(), + int_map: HashMap::new(), + float_map: HashMap::new(), + } + } + + /// Inserts a mapping from a type variable to a concrete type. + /// + /// This adds or replaces the substitution for the given type variable. + pub fn insert(&mut self, var: TyVid, ty: Ty<'cx>) { + self.ty_map.insert(var, ty); + } + + /// Inserts a mapping from an integer variable to a concrete integer type. + pub fn resolve_int_var(&mut self, var: IntVid, ty: Integer) { + self.int_map.insert(var, ty); + } + + /// Inserts a mapping from an integer variable to a concrete integer type. + pub fn resolve_int(&mut self, var: IntVid, ty: IntTy) { + self.int_map.insert(var, Integer::Int(ty)); + } + + /// Inserts a mapping from an integer variable to a concrete unsigned integer type. + pub fn resolve_uint(&mut self, var: IntVid, ty: UintTy) { + self.int_map.insert(var, Integer::Uint(ty)); + } + + /// Inserts a mapping from a float variable to a concrete float type. + pub fn resolve_float(&mut self, var: FloatVid, ty: FloatTy) { + self.float_map.insert(var, ty); + } + + /// Gets the substituted type for a given type variable. + /// + /// Returns None if no substitution exists for the variable. + pub fn get(&self, var: &TyVid) -> Option> { + self.ty_map.get(var).copied() + } + + /// Gets the substituted integer type for a given integer variable. + pub fn get_int(&self, var: &IntVid) -> Option { + self.int_map.get(var).copied() + } + + /// Gets the substituted float type for a given float variable. + pub fn get_float(&self, var: &FloatVid) -> Option { + self.float_map.get(var).copied() + } + + /// Checks if this substitution is empty (contains no mappings). + /// + /// An empty substitution is equivalent to the identity substitution. + pub fn is_empty(&self) -> bool { + self.ty_map.is_empty() && self.int_map.is_empty() && self.float_map.is_empty() + } + + /// Applies this substitution to a type, replacing type variables with their substituted types. + /// + /// This recursively walks through the type structure and applies substitutions to all + /// type variables found. The process continues until no more substitutions can be applied. + pub fn apply_substitution(&self, cx: &'cx TypingContext<'cx>, ty: &mut Ty<'cx>) { + *ty = self.apply_substitution_pure(cx, *ty); + } + + pub fn apply_substitution_pure(&self, cx: &'cx TypingContext<'cx>, ty: Ty<'cx>) -> Ty<'cx> { + match ty.kind() { + TyKind::Infer(InferTy::TyVar(var)) => { + // Recursively apply substitutions to handle chains of substitutions + if let Some(substituted) = self.ty_map.get(var) { + self.apply_substitution_pure(cx, *substituted) + } else { + ty + } + } + TyKind::Infer(InferTy::IntVar(var)) => { + if let Some(substituted_ty) = self.int_map.get(var) { + match substituted_ty { + Integer::Int(int_ty) => Ty::mk_int(cx, *int_ty), + Integer::Uint(uint_ty) => Ty::mk_uint(cx, *uint_ty), + } + } else { + ty + } + } + TyKind::Infer(InferTy::FloatVar(var)) => { + if let Some(substituted_ty) = self.float_map.get(var) { + Ty::mk_float(cx, *substituted_ty) + } else { + ty + } + } + TyKind::Array { inner } => { + let substituted_inner = self.apply_substitution_pure(cx, *inner); + // Only allocate a new type if something actually changed + if substituted_inner == *inner { + ty + } else { + cx.alloc_type(TyKind::Array { + inner: substituted_inner, + }) + } + } + TyKind::Function { + arg, + ret, + is_procedure, + } => { + let mut changed = false; + // Apply substitutions to all argument types + let substituted_args: Vec> = arg + .iter() + .map(|&arg| { + let substituted = self.apply_substitution_pure(cx, arg); + if substituted != arg { + changed = true; + } + substituted + }) + .collect(); + // Apply substitution to return type + let substituted_ret = self.apply_substitution_pure(cx, *ret); + if substituted_ret != *ret { + changed = true; + } + + // Only allocate new function type if something changed + if changed { + cx.alloc_type(TyKind::Function { + arg: substituted_args, + ret: substituted_ret, + is_procedure: *is_procedure, + }) + } else { + ty + } + } + TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::String + | TyKind::Bytes + | TyKind::Bool + | TyKind::Duration + | TyKind::Time + | TyKind::Unit + | TyKind::External { .. } => ty, + } + } + + /// Composes this substitution with another substitution. + /// + /// The composition applies the first substitution to the types in the second substitution, + /// then combines both mappings. This ensures that variable chains are properly resolved. + pub fn compose(&mut self, other: &Substitution<'cx>, cx: &'cx TypingContext<'cx>) { + if self.is_empty() { + self.clone_from(other); + return; + } + // Apply this substitution to all types in the other substitution + for (var, &ty) in &other.ty_map { + let substituted_ty = self.apply_substitution_pure(cx, ty); + self.insert(*var, substituted_ty); + } + + // Directly extend integer and float substitutions + self.int_map.extend(other.int_map.iter()); + self.float_map.extend(other.float_map.iter()); + } +} diff --git a/ty/opslang-ty/src/version/v1/infer.rs b/ty/opslang-ty/src/version/v1/infer.rs new file mode 100644 index 0000000..58ed23a --- /dev/null +++ b/ty/opslang-ty/src/version/v1/infer.rs @@ -0,0 +1,69 @@ +use super::*; + +/// Represents inference variables used during type inference. +/// +/// Different kinds of inference variables allow for more precise type inference, +/// particularly for numeric types that can have default fallbacks. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Visit)] +pub enum InferTy { + /// General type inference variable + TyVar(TyVid), + /// Integer inference variable that can fallback to default integer type + IntVar(IntVid), + /// Float inference variable that can fallback to default float type + FloatVar(FloatVid), +} + +/// Integer type variable for type inference. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Visit)] +#[skip_all_visit] +pub struct IntVid(u32); + +impl IntVid { + pub fn fresh() -> Self { + static COUNTER: AtomicU32 = AtomicU32::new(0); + Self(COUNTER.fetch_add(1, std::sync::atomic::Ordering::AcqRel)) + } +} + +impl std::fmt::Display for IntVid { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "$int{}", self.0) + } +} + +/// Float type variable for type inference. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Visit)] +#[skip_all_visit] +pub struct FloatVid(u32); + +impl FloatVid { + pub fn fresh() -> Self { + static COUNTER: AtomicU32 = AtomicU32::new(0); + Self(COUNTER.fetch_add(1, std::sync::atomic::Ordering::AcqRel)) + } +} + +impl std::fmt::Display for FloatVid { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "$float{}", self.0) + } +} + +/// General type variable for type inference. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Visit)] +#[skip_all_visit] +pub struct TyVid(u32); + +impl TyVid { + pub fn fresh() -> Self { + static COUNTER: AtomicU32 = AtomicU32::new(0); + Self(COUNTER.fetch_add(1, std::sync::atomic::Ordering::AcqRel)) + } +} + +impl std::fmt::Display for TyVid { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "$t{}", self.0) + } +} diff --git a/ty/opslang-ty/src/version/v1/poly.rs b/ty/opslang-ty/src/version/v1/poly.rs new file mode 100644 index 0000000..223c48b --- /dev/null +++ b/ty/opslang-ty/src/version/v1/poly.rs @@ -0,0 +1,46 @@ +use super::*; + +/// Represents a polymorphic type with type variables. +/// +/// A polymorphic type consists of type variables (TyVar) that can be instantiated +/// to create monomorphic types. This enables generic functions and types. +#[derive(Debug, Clone, PartialEq, Visit)] +pub struct PolyTy<'cx> { + /// The type variables bound by this polymorphic type. + pub type_vars: Vec, + /// The body type that may contain the bound type variables. + pub body: Ty<'cx>, +} + +impl<'cx> PolyTy<'cx> { + /// Creates a new polymorphic type. + pub fn new(type_vars: Vec, body: Ty<'cx>) -> Self { + Self { type_vars, body } + } + + /// Creates a monomorphic type (no type variables). + pub fn mono(body: Ty<'cx>) -> Self { + Self { + type_vars: Vec::new(), + body, + } + } + + /// Instantiates the polymorphic type with fresh type variables. + /// + /// This creates a new monomorphic type by replacing bound type variables + /// with fresh type variables for inference. + pub fn instantiate(&self, cx: &'cx TypingContext<'cx>) -> Ty<'cx> { + if self.type_vars.is_empty() { + return self.body; + } + + let mut substitution = hm::Substitution::new(); + for &var in &self.type_vars { + let fresh_var = TyVid::fresh(); + let fresh_ty = Ty::mk_variable(cx, fresh_var); + substitution.insert(var, fresh_ty); + } + substitution.apply_substitution_pure(cx, self.body) + } +} diff --git a/ty/opslang-typeck/Cargo.toml b/ty/opslang-typeck/Cargo.toml new file mode 100644 index 0000000..d9e1cd1 --- /dev/null +++ b/ty/opslang-typeck/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "opslang-typeck" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "ops file language type checker" + +[dependencies] +opslang-ty.workspace = true + +opslang-ast.workspace = true +opslang-ir.workspace = true +opslang-ir-macro.workspace = true +opslang-module.workspace = true +opslang-visitor.workspace = true +anyhow.workspace = true +chrono.workspace = true +typed-arena.workspace = true + +[dev-dependencies] +opslang-parser.workspace = true diff --git a/ty/opslang-typeck/examples/v1_typeck_directory/example_root_dir/child_dir/test3.ops b/ty/opslang-typeck/examples/v1_typeck_directory/example_root_dir/child_dir/test3.ops new file mode 100644 index 0000000..7b06e10 --- /dev/null +++ b/ty/opslang-typeck/examples/v1_typeck_directory/example_root_dir/child_dir/test3.ops @@ -0,0 +1,6 @@ +#! lang=v1 + +prc main() { + assert (1 == 1); + return; +} diff --git a/ty/opslang-typeck/examples/v1_typeck_directory/example_root_dir/test1.ops b/ty/opslang-typeck/examples/v1_typeck_directory/example_root_dir/test1.ops new file mode 100644 index 0000000..ab80dc9 --- /dev/null +++ b/ty/opslang-typeck/examples/v1_typeck_directory/example_root_dir/test1.ops @@ -0,0 +1,6 @@ +#! lang=v1 + +prc main() { + assert true; + return; +} diff --git a/ty/opslang-typeck/examples/v1_typeck_directory/example_root_dir/test2.ops b/ty/opslang-typeck/examples/v1_typeck_directory/example_root_dir/test2.ops new file mode 100644 index 0000000..c5a30a1 --- /dev/null +++ b/ty/opslang-typeck/examples/v1_typeck_directory/example_root_dir/test2.ops @@ -0,0 +1,6 @@ +#! lang=v1 + +prc main() { + print false; + return; +} diff --git a/ty/opslang-typeck/examples/v1_typeck_directory/main.rs b/ty/opslang-typeck/examples/v1_typeck_directory/main.rs new file mode 100644 index 0000000..2d8328c --- /dev/null +++ b/ty/opslang-typeck/examples/v1_typeck_directory/main.rs @@ -0,0 +1,93 @@ +//! Example: Type check all .ops files in the example directory. +//! +//! Usage: cargo run --example v1_typeck_directory + +use anyhow::Result; +use opslang_ast::syntax::v1 as ast; +use opslang_ir::version::v1 as ir; +use opslang_module::version::v1::ModuleContext; +use opslang_parser::{ParseOps, ParserInput}; +use opslang_ty::version::v1::TypingContext; +use opslang_typeck::version::v1::{ + Session, TypeChecker, context::GlobalContext, create_builtin_module, +}; +use std::fs; +use std::path::PathBuf; + +fn main() -> Result<()> { + // Use the directory where this example file is located + let example_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("examples") + .join("v1_typeck_directory") + .join("example_root_dir"); + + // Collect all .ops files recursively in the example directory + let mut ops_files = Vec::new(); + let mut dirs_to_visit = vec![example_dir.clone()]; + while let Some(dir) = dirs_to_visit.pop() { + for entry in fs::read_dir(&dir)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + dirs_to_visit.push(path); + } else if path.is_file() && path.extension().is_some_and(|ext| ext == "ops") { + ops_files.push(path); + } + } + } + + if ops_files.is_empty() { + println!("No .ops files found in {}", example_dir.display()); + return Ok(()); + } + + println!("Found {} .ops file(s)", ops_files.len()); + + // Set up contexts + let ast_cx = ast::context::Context::new(); + let ir_cx = ir::context::Context::new(); + let tcx = TypingContext::new(); + let module_cx = ModuleContext::new(); + let gcx = GlobalContext { + tcx: &tcx, + module: &module_cx, + }; + + // Parse all files and create session + let mut session = Session::new(); + for path in &ops_files { + let source = fs::read_to_string(path)?; + let input = ParserInput { + content: ast_cx.alloc_str(&source), + file_name: path.to_path_buf(), + }; + let program = ast::Program::parse(input, &ast_cx) + .map_err(|e| anyhow::anyhow!("Failed to parse '{}': {e}", path.display()))?; + + // Create module path from file name + let file_name = path.file_stem().unwrap().to_str().unwrap(); + let module_path = module_cx.alloc_root_path(ast_cx.alloc_str(file_name)); + + session.add_module(module_path, program); + println!("Parsed: {}", path.display()); + } + + // Create type checker + let mut typeck = TypeChecker::new(gcx, &ir_cx); + typeck.add_module(create_builtin_module(gcx)); + + // Type check all programs + println!("\nType checking {} module(s)...", session.iter().count()); + typeck.typeck_programs(&mut session)?; + + println!("\nType checking completed successfully!"); + println!( + "Generated {} IR program(s)", + session + .iter() + .filter(|(_, entry)| entry.ir_program.is_some()) + .count() + ); + + Ok(()) +} diff --git a/ty/opslang-typeck/src/lib.rs b/ty/opslang-typeck/src/lib.rs new file mode 100644 index 0000000..a6db76a --- /dev/null +++ b/ty/opslang-typeck/src/lib.rs @@ -0,0 +1 @@ +pub mod version; diff --git a/ty/opslang-typeck/src/version.rs b/ty/opslang-typeck/src/version.rs new file mode 100644 index 0000000..a3a6d96 --- /dev/null +++ b/ty/opslang-typeck/src/version.rs @@ -0,0 +1 @@ +pub mod v1; diff --git a/ty/opslang-typeck/src/version/v1.rs b/ty/opslang-typeck/src/version/v1.rs new file mode 100644 index 0000000..0429078 --- /dev/null +++ b/ty/opslang-typeck/src/version/v1.rs @@ -0,0 +1,299 @@ +use anyhow::anyhow; +use ast::token::IntoToken; +use chrono::Utc; +use opslang_ast::v1::{self as ast}; +use opslang_ir::version::v1::{self as ir}; +use opslang_module::version::v1 as module; + +use ir::Typed; +use opslang_module::version::v1::{ + Module, ModuleContext, ModuleDef, ModuleItem, ModuleItemDef, ModuleLoader, ModulePath, +}; +use opslang_ty::version::v1::{ + self as ty, FloatTy, Ident, IntTy, PolyTy, Procedure, Substitution, Ty, TyKind, TyVid, + TypingContext, +}; +use opslang_visitor::VisitorMut; +use std::collections::HashMap; +use std::ops::{Deref, DerefMut}; + +type Result = std::result::Result; + +mod environment; +use environment::Scope; + +mod session; +pub use session::{ModuleEntry, SecondPassSession, Session}; + +mod hm; +pub use hm::generalize_ty; + +mod lower; +mod register_signature; +mod resolve; + +mod typeck_apply; +mod typeck_binary; +mod typeck_block; +mod typeck_call; +mod typeck_constant; +mod typeck_expr; +mod typeck_function; +mod typeck_infix_import; +mod typeck_literal; +mod typeck_path; +mod typeck_statement; + +mod builtin_module; +pub use builtin_module::create_builtin_module; + +pub mod context; +use context::GlobalContext; + +/// The main type checker that performs type inference and checking. +pub struct TypeChecker<'cx> { + /// Module loader for resolving external symbols. + module_loader: ModuleLoader<'cx>, + + /// Optional external resolver for custom type resolution. + external_resolver: Option>>, + + gcx: GlobalContext<'cx>, + ir_cx: &'cx ir::Context<'cx>, +} + +impl<'cx> Deref for TypeChecker<'cx> { + type Target = GlobalContext<'cx>; + + fn deref(&self) -> &Self::Target { + &self.gcx + } +} + +impl core::fmt::Debug for TypeChecker<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + let TypeChecker { module_loader, .. } = self; + f.debug_struct("TypeChecker") + .field("module_loader", &module_loader) + .finish() + } +} + +/// Trait for resolving external types by path. +/// +/// Resolved item belongs to no module. +pub trait ExternalResolver<'cx> { + /// Resolves a path to a type, returning `None` if not found. + fn resolve(&self, path: ast::Path<'cx>, tcx: &'cx TypingContext<'cx>) -> Option>; +} + +impl<'cx> TypeChecker<'cx> { + /// Creates a new type checker with empty module loader. + /// + /// The type checker starts with no modules loaded. + pub fn new(gcx: GlobalContext<'cx>, ir_cx: &'cx ir::Context<'cx>) -> Self { + Self { + external_resolver: None, + module_loader: ModuleLoader::new(), + gcx, + ir_cx, + } + } + + /// Creates a new type checker with the given module loader. + /// + /// This allows pre-loading modules before starting type checking operations. + pub fn with_module_loader( + module_loader: ModuleLoader<'cx>, + gcx: GlobalContext<'cx>, + ir_cx: &'cx ir::Context<'cx>, + ) -> Self { + Self { + external_resolver: None, + module_loader, + gcx, + ir_cx, + } + } + + pub fn add_external_resolver( + &mut self, + resolver: impl ExternalResolver<'cx> + 'static, + ) -> &mut Self { + self.external_resolver = Some(Box::new(resolver)); + self + } + + /// Adds a module to the type checker's module loader. + /// + /// This makes the module's exported items available for type resolution. + pub fn add_module(&mut self, module: Module<'cx>) { + self.module_loader.add_module(module); + } + + /// Performs type checking on multiple modules using a session. + /// + /// This is the entry point for type checking multiple files. + /// The session should already contain all modules with their AST programs. + /// This function performs a two-pass type check: + /// 1. First pass: collect signatures from each module + /// 2. Second pass: type check each module with access to all module environments + pub fn typeck_programs<'env>(&mut self, session: &mut Session<'cx, 'env>) -> Result<()> { + // First pass: collect all signatures from all modules + let module_paths: Vec<_> = session.iter().map(|(path, _)| *path).collect(); + + for &path in &module_paths { + let entry = session.get_module(&path).unwrap(); + let mut toplevel = Scope::new(); + + for definition in entry.program.toplevel_items { + // Note: 'env does not refer to this borrowing. + self.register_signature(&mut toplevel, definition)?; + } + + session.register_environment(path, toplevel); + } + + // Second pass: type check each module + for path in &module_paths { + let entry = session.get_module(path).unwrap(); + let program = &entry.program; + + // Note: 'env DOES refer to this variable's lifetime. + let env = session.get_environment(path).unwrap(); + let ir_program = self.typeck_items_with_global_env( + SecondPassSession::new(session, *path), + env, + program, + )?; + + session.get_module_mut(path).unwrap().ir_program = Some(ir_program); + } + + Ok(()) + } + + /// Performs type checking on an AST program and converts it to IR. + /// + /// This is the main entry point for type checking and IR generation. + /// It processes all top-level definitions, performs type inference, + /// and converts the AST to a typed IR representation. + pub fn typeck_single_program( + &mut self, + program: &ast::Program<'cx>, + path: module::ModulePath<'cx>, + ) -> Result> { + let mut session = Session::new(); + + // First pass: collect all function and constant signatures + let global_env = self.collect_signatures(program)?; + session.register_environment(path, global_env); + let global_env = session.get_environment(&path).unwrap(); + + // Second pass: type check implementations and lower comments + self.typeck_items_with_global_env( + SecondPassSession::new(&session, path), + global_env, + program, + ) + } + + // Note: 'env can be any lifetime, even that of later borrowing from the *returned value*. + pub fn collect_signatures<'env>( + &mut self, + program: &ast::Program<'cx>, + ) -> Result> { + // Create global environment for top-level definitions + let mut toplevel = Scope::new(); + + for definition in program.toplevel_items { + self.register_signature(&mut toplevel, definition)?; + } + Ok(toplevel) + } + + pub fn typeck_items_with_global_env<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + global_env: &Scope<'cx, 'env>, + program: &ast::Program<'cx>, + ) -> Result> { + let mut ir_definitions = Vec::new(); + let mut pending_comments: Vec<&'cx ast::Comment<'cx>> = Vec::new(); + + for toplevel_item in program.toplevel_items { + if toplevel_item.is_empty() { + // Empty item (empty line) - discard any pending comments + pending_comments.clear(); + continue; + } + + // If this item has a definition, create an IR Definition + if let Some(kind) = &toplevel_item.kind { + let leading_comment = if pending_comments.is_empty() { + None + } else { + Some(lower::merge_comments(self.ir_cx, &pending_comments)?) + }; + + let ir_kind = match kind { + ast::DefinitionKind::Function(func_def) => { + let ir_func = self.typeck_function(session, global_env, func_def)?; + ir::DefinitionKind::Function(ir_func) + } + ast::DefinitionKind::Constant(const_def) => { + let ir_const = self.typeck_constant(session, global_env, const_def)?; + ir::DefinitionKind::Constant(ir_const) + } + }; + + let ir_definition = ir::Definition { + comment_before: leading_comment, + comment_trailing: toplevel_item + .comment + .map(|ast_comment| lower::lower_comment(self.ir_cx, ast_comment)), + kind: ir_kind, + }; + + ir_definitions.push(ir_definition); + pending_comments.clear(); + } else if let Some(comment) = &toplevel_item.comment { + // Collect comment from this item if present + pending_comments.push(comment); + } + } + + Ok(ir::Program { + toplevel_items: self.ir_cx.alloc_definition_slice(ir_definitions), + }) + } +} + +/// Result of path resolution containing both the IR representation and the original item. +#[derive(Debug, Clone, Copy)] +struct ResolvePathResult<'cx> { + /// The resolved path for IR generation + resolved_path: ir::ResolvedPath<'cx>, + /// The original module item with type information + item: ModuleItem<'cx>, +} + +#[cfg(test)] +mod tests; + +#[macro_export] +/// Shorthand to set up a type checking contexts. +/// +/// Internal use only but exposed for use in tests. +macro_rules! v1_setup_cx { + ($ast_context:ident, $ir_context:ident, $gcx:ident = { $typing_context:ident, $module_context:ident $(,)? }) => { + let $ast_context = ast::context::Context::new(); + let $ir_context = ir::context::Context::new(); + let $typing_context = TypingContext::new(); + let $module_context = ModuleContext::new(); + let $gcx = GlobalContext { + tcx: &$typing_context, + module: &$module_context, + }; + }; +} diff --git a/ty/opslang-typeck/src/version/v1/builtin_module.rs b/ty/opslang-typeck/src/version/v1/builtin_module.rs new file mode 100644 index 0000000..ff59084 --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/builtin_module.rs @@ -0,0 +1,88 @@ +use super::*; + +/// Creates the builtin module containing all primitive types. +/// +/// The builtin module provides access to fundamental types like integers, strings, +/// and other primitives that are available in all contexts without explicit imports. +pub fn create_builtin_module<'cx>(gcx: GlobalContext<'cx>) -> Module<'cx> { + let cx = gcx.tcx; + let mut builtin = ModuleDef::new(cx.alloc_toplevel_ident("builtin")); + + // Add all builtin primitive types + builtin + .add_type(cx.alloc_toplevel_ident("i8"), Ty::mk_i8(cx)) + .unwrap(); + builtin + .add_type(cx.alloc_toplevel_ident("i16"), Ty::mk_i16(cx)) + .unwrap(); + builtin + .add_type(cx.alloc_toplevel_ident("i32"), Ty::mk_i32(cx)) + .unwrap(); + builtin + .add_type(cx.alloc_toplevel_ident("i64"), Ty::mk_i64(cx)) + .unwrap(); + + builtin + .add_type(cx.alloc_toplevel_ident("u8"), Ty::mk_u8(cx)) + .unwrap(); + builtin + .add_type(cx.alloc_toplevel_ident("u16"), Ty::mk_u16(cx)) + .unwrap(); + builtin + .add_type(cx.alloc_toplevel_ident("u32"), Ty::mk_u32(cx)) + .unwrap(); + builtin + .add_type(cx.alloc_toplevel_ident("u64"), Ty::mk_u64(cx)) + .unwrap(); + + builtin + .add_type(cx.alloc_toplevel_ident("f32"), Ty::mk_f32(cx)) + .unwrap(); + builtin + .add_type(cx.alloc_toplevel_ident("f64"), Ty::mk_f64(cx)) + .unwrap(); + + builtin + .add_type(cx.alloc_toplevel_ident("string"), Ty::mk_string(cx)) + .unwrap(); + builtin + .add_type(cx.alloc_toplevel_ident("bool"), Ty::mk_bool(cx)) + .unwrap(); + builtin + .add_type(cx.alloc_toplevel_ident("duration"), Ty::mk_duration(cx)) + .unwrap(); + builtin + .add_type(cx.alloc_toplevel_ident("time"), Ty::mk_time(cx)) + .unwrap(); + + builtin + .add_library_function( + cx.alloc_toplevel_ident("assert"), + PolyTy::mono(Ty::mk_function(cx, vec![Ty::mk_bool(cx)], Ty::mk_unit(cx))), + ) + .unwrap(); + + builtin + .add_library_function(cx.alloc_toplevel_ident("assert_eq"), { + let var = Ty::mk_fresh(cx); + let body = Ty::mk_function(cx, vec![var, var], Ty::mk_unit(cx)); + generalize_ty(body) + }) + .unwrap(); + // any type can be printed, for now. + builtin + .add_library_function( + cx.alloc_toplevel_ident("print"), + generalize_ty(Ty::mk_function(cx, vec![Ty::mk_fresh(cx)], Ty::mk_unit(cx))), + ) + .unwrap(); + + builtin + .add_constant(cx.alloc_toplevel_ident("true"), Ty::mk_bool(cx)) + .unwrap(); + builtin + .add_constant(cx.alloc_toplevel_ident("false"), Ty::mk_bool(cx)) + .unwrap(); + + gcx.module.alloc_module(builtin) +} diff --git a/ty/opslang-typeck/src/version/v1/context.rs b/ty/opslang-typeck/src/version/v1/context.rs new file mode 100644 index 0000000..5eb15a9 --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/context.rs @@ -0,0 +1,16 @@ +use opslang_module::version::v1::ModuleContext; +use opslang_ty::version::v1::TypingContext; + +#[derive(Clone, Copy)] +pub struct GlobalContext<'cx> { + pub tcx: &'cx TypingContext<'cx>, + pub module: &'cx ModuleContext<'cx>, +} + +impl<'cx> std::ops::Deref for GlobalContext<'cx> { + type Target = &'cx TypingContext<'cx>; + + fn deref(&self) -> &Self::Target { + &self.tcx + } +} diff --git a/ty/opslang-typeck/src/version/v1/environment.rs b/ty/opslang-typeck/src/version/v1/environment.rs new file mode 100644 index 0000000..ab651e8 --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/environment.rs @@ -0,0 +1,81 @@ +use super::*; +use opslang_ast::syntax::v1 as ast; + +/// Represents a lexical environment for name and type bindings. +/// +/// Environments form a chain through parent references, enabling proper +/// lexical scoping where inner scopes can shadow outer scope bindings. +#[derive(Debug)] +pub struct Scope<'cx, 'scope> { + /// Maps variable names to their unique identifiers. + name_bindings: HashMap<&'cx str, TypedIdent<'cx>>, + + /// Reference to parent environment for scope chaining. + parent: Option<&'scope Self>, +} + +#[derive(Debug, Clone, Copy)] +pub struct TypedIdent<'cx> { + pub id: Ident<'cx>, + pub ty: Ty<'cx>, +} + +impl<'cx, 'scope> Scope<'cx, 'scope> { + /// Creates a new top-level environment with no parent. + /// + /// This represents the global scope. + pub fn new() -> Self { + Self { + name_bindings: HashMap::new(), + parent: None, + } + } + + /// Creates a new environment that extends a parent environment. + /// + /// The new environment can access bindings from the parent chain while allowing local shadowing. + pub fn extend_inherit(&'scope self) -> Self { + Self { + name_bindings: HashMap::new(), + parent: Some(self), + } + } + + /// Binds a name to an identifier and associates the identifier with a type. + /// + /// This is a convenience method that performs both name and type binding in one operation. + pub fn bind(&mut self, name: ast::Ident<'cx>, id: Ident<'cx>, ty: Ty<'cx>) { + self.name_bindings.insert(name.raw, TypedIdent { id, ty }); + } + + /// Looks up a name to find its associated identifier. + /// + /// Searches the current environment first, then walks up the parent chain. + /// Returns None if the name is not bound in any accessible scope. + pub fn lookup_var(&self, name: ast::Ident<'cx>) -> Option> { + self.name_bindings + .get(name.raw) + .copied() + .or_else(|| self.parent.and_then(|parent| parent.lookup_var(name))) + } +} + +impl<'cx, 'scope> Default for Scope<'cx, 'scope> { + fn default() -> Self { + Self::new() + } +} + +impl<'cx> TypeChecker<'cx> { + /// Binds a name to a new identifier with type and returns the identifier. + pub fn bind( + &mut self, + scope: &mut Scope<'cx, '_>, + name: ast::Ident<'cx>, + ty: Ty<'cx>, + ) -> Ident<'cx> { + let id = self.tcx.alloc_identifier(name); + scope.bind(name, id, ty); + id + } +} diff --git a/ty/opslang-typeck/src/version/v1/hm.rs b/ty/opslang-typeck/src/version/v1/hm.rs new file mode 100644 index 0000000..46b1716 --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/hm.rs @@ -0,0 +1,296 @@ +use anyhow::anyhow; +use opslang_ty::version::v1::{InferTy, PolyTy, Substitution, Ty, TyKind, TyVid}; +use std::collections::HashSet; + +use super::*; + +impl<'cx> super::TypeChecker<'cx> { + /// Attempts to unify two types, producing a substitution that makes them equal. + /// + /// Unification is the core algorithm for type inference, determining what type variables + /// must be bound to make two types compatible. This implements the standard unification + /// algorithm with occurs check to prevent infinite types. + pub fn unify( + &self, + subst: &mut Substitution<'cx>, + t1: Ty<'cx>, + t2: Ty<'cx>, + ) -> super::Result<()> { + match (t1.kind(), t2.kind()) { + // Inference variables + (TyKind::Infer(InferTy::TyVar(var1)), TyKind::Infer(InferTy::TyVar(var2))) + if var1 == var2 => + { + Ok(()) + } + (TyKind::Infer(InferTy::IntVar(var1)), TyKind::Infer(InferTy::IntVar(var2))) + if var1 == var2 => + { + Ok(()) + } + (TyKind::Infer(InferTy::FloatVar(var1)), TyKind::Infer(InferTy::FloatVar(var2))) + if var1 == var2 => + { + Ok(()) + } + + // General type variable unification + (TyKind::Infer(InferTy::TyVar(var)), ty) | (ty, TyKind::Infer(InferTy::TyVar(var))) => { + if ty.occurs(*var) { + Err(anyhow!("occurs check failed: {var} occurs in {ty}",)) + } else { + subst.insert(*var, Ty(ty)); + Ok(()) + } + } + + // Integer variable unification - can unify with any integer or unsigned type + (TyKind::Infer(InferTy::IntVar(var)), TyKind::Int(int_ty)) + | (TyKind::Int(int_ty), TyKind::Infer(InferTy::IntVar(var))) => { + subst.resolve_int(*var, *int_ty); + Ok(()) + } + (TyKind::Infer(InferTy::IntVar(var)), TyKind::Uint(uint_ty)) + | (TyKind::Uint(uint_ty), TyKind::Infer(InferTy::IntVar(var))) => { + subst.resolve_uint(*var, *uint_ty); + Ok(()) + } + + // Integer variable unification - can unify with any integer or unsigned type + (TyKind::Infer(InferTy::IntVar(var1)), TyKind::Infer(InferTy::IntVar(var2))) => { + let val1 = subst.get_int(var1); + let val2 = subst.get_int(var2); + match (val1, val2) { + (None, None) => { + // ok, do nothing + Ok(()) + } + (None, Some(concrete)) => { + subst.resolve_int_var(*var1, concrete); + Ok(()) + } + (Some(concrete), None) => { + subst.resolve_int_var(*var2, concrete); + Ok(()) + } + (Some(concrete1), Some(concrete2)) => { + if concrete1 != concrete2 { + Err(anyhow!("failed to unify {concrete1:?} and {concrete2:?}",)) + } else { + Ok(()) + } + } + } + } + + // Float variable unification - can unify with any float type + (TyKind::Infer(InferTy::FloatVar(var)), TyKind::Float(float_ty)) + | (TyKind::Float(float_ty), TyKind::Infer(InferTy::FloatVar(var))) => { + subst.resolve_float(*var, *float_ty); + Ok(()) + } + // Primitive types unify only with themselves + (TyKind::Int(int1), TyKind::Int(int2)) if int1 == int2 => Ok(()), + (TyKind::Uint(uint1), TyKind::Uint(uint2)) if uint1 == uint2 => Ok(()), + (TyKind::Float(float1), TyKind::Float(float2)) if float1 == float2 => Ok(()), + (TyKind::String, TyKind::String) + | (TyKind::Bool, TyKind::Bool) + | (TyKind::Duration, TyKind::Duration) + | (TyKind::Time, TyKind::Time) + | (TyKind::Unit, TyKind::Unit) => Ok(()), + // Array types unify if their element types unify + (TyKind::Array { inner: inner1 }, TyKind::Array { inner: inner2 }) => { + self.unify(subst, *inner1, *inner2) + } + // Function types unify if they have the same arity and corresponding types unify + ( + TyKind::Function { + arg: arg1, + ret: ret1, + is_procedure: prc1, + }, + TyKind::Function { + arg: arg2, + ret: ret2, + is_procedure: prc2, + }, + ) => { + if arg1.len() != arg2.len() { + return Err(anyhow!( + "function arity mismatch: {} vs {}", + arg1.len(), + arg2.len() + )); + } + if prc1.is_some() && prc2.is_some() && prc1 != prc2 { + return Err(anyhow!("procedure mismatch: {prc1:?} vs {prc2:?}")); + } + + // Unify corresponding argument types + for (arg1, arg2) in arg1.iter().zip(arg2.iter()) { + self.unify(subst, *arg1, *arg2)?; + } + + // Apply accumulated substitutions to return types before unifying + let substituted_ret1 = subst.apply_substitution_pure(self.tcx, *ret1); + let substituted_ret2 = subst.apply_substitution_pure(self.tcx, *ret2); + self.unify(subst, substituted_ret1, substituted_ret2)?; + Ok(()) + } + + // All other combinations are incompatible + + // Below we list all the possible TyKind variants to ensure exhaustiveness. + // If you add a new TyKind, you must handle it *above* and here. + (TyKind::Int(_), _) + | (TyKind::Uint(_), _) + | (TyKind::Float(_), _) + | (TyKind::String, _) + | (TyKind::Bytes, _) + | (TyKind::Bool, _) + | (TyKind::Duration, _) + | (TyKind::Time, _) + | (TyKind::Array { .. }, _) + | (TyKind::Function { .. }, _) + | (TyKind::Infer(_), _) + | (TyKind::Unit, _) + | (TyKind::External { .. }, _) => Err(anyhow!("cannot unify {t1} and {t2}",)), + } + } + + pub fn unify_pure(&self, t1: Ty<'cx>, t2: Ty<'cx>) -> super::Result> { + let mut subst = Substitution::new(); + self.unify(&mut subst, t1, t2)?; + Ok(subst) + } +} + +/// Generalizes a type by quantifying over all free type variables. +/// +/// This function collects all type variables that appear in the given type +/// and creates a polymorphic type that quantifies over them. +/// +/// FIXME: This function can be defined in opslang-ty crate, but it would require +/// big changes to macro crates. +pub fn generalize_ty<'cx>(body: Ty<'cx>) -> PolyTy<'cx> { + use opslang_visitor::Visitor; + let mut visitor = TyVarCollector::new(); + visitor.visit(&body); + PolyTy { + type_vars: visitor.type_vars, + body, + } +} + +/// A visitor that collects all type variables in a type. +struct TyVarCollector { + type_vars: Vec, + seen: HashSet, +} + +impl TyVarCollector { + fn new() -> Self { + Self { + type_vars: Vec::new(), + seen: HashSet::new(), + } + } +} + +opslang_ir_macro::v1_ir_visitor_impl!(for TyVarCollector { + fn visit_ty_vid(&mut self, var: &TyVid) { + if !self.seen.contains(var) { + self.seen.insert(*var); + self.type_vars.push(*var); + } + } +}); + +/// Mutable `Cow`, do not copy on write. +enum CowMut<'a, T> { + Borrowed(&'a mut T), + Owned(T), +} + +impl<'a, T> Deref for CowMut<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + match self { + CowMut::Borrowed(r) => r, + CowMut::Owned(v) => v, + } + } +} + +impl<'a, T> DerefMut for CowMut<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + match self { + CowMut::Borrowed(r) => r, + CowMut::Owned(v) => v, + } + } +} + +/// Visitor for applying substitutions to all types in the IR. +pub struct SubstitutionVisitor<'cx, 'a> { + ty_last_seen: Option>, + subst: CowMut<'a, Substitution<'cx>>, + tcx: &'cx TypingContext<'cx>, +} + +impl<'cx, 'a> SubstitutionVisitor<'cx, 'a> { + pub fn new(subst: Substitution<'cx>, tcx: &'cx TypingContext<'cx>) -> Self { + Self { + subst: CowMut::Owned(subst), + tcx, + ty_last_seen: None, + } + } + pub fn new_borrowed(subst: &'a mut Substitution<'cx>, tcx: &'cx TypingContext<'cx>) -> Self { + Self { + subst: CowMut::Borrowed(subst), + tcx, + ty_last_seen: None, + } + } +} + +opslang_ir_macro::v1_ir_visitor_impl!(for SubstitutionVisitor<'cx, '_> { + fn visit_expr_mut(&mut self, expr: &mut ir::Expr<'cx>) { + use ir::IrMutVisitor; + // visit ty first + self.visit_ty_mut(&mut expr.ty); + self.visit_mut(&mut expr.kind); + } + fn visit_ty_mut(&mut self, ty: &mut Ty<'cx>) { + self.subst.apply_substitution(self.tcx, ty); + let kind = ty.kind(); + match kind { + TyKind::Infer(InferTy::IntVar(int_vid)) => { + // Resolve integer type variables to i32 by default + self.subst.resolve_int(*int_vid, IntTy::I64); + } + TyKind::Infer(InferTy::FloatVar(float_vid)) => { + // Resolve float type variables to f64 by default in Rust + self.subst.resolve_float(*float_vid, FloatTy::F64); + } + _ => {} + } + self.subst.apply_substitution(self.tcx, ty); + self.ty_last_seen = Some(*ty); + } + fn visit_ty(&mut self, _ty: &Ty<'cx>) { + dbg!(_ty); + panic!("Found `Ty` immutability. this prevents type variable resolution. review changes to IR structure and eliminate possession of immutable `Ty`pes."); + } + fn visit_numeric_mut(&mut self, numeric: &mut ir::Numeric<'cx>) { + if let ir::NumericKind::Repr(unparsed) = numeric.kind { + let literal = typeck_literal::parse_literal(unparsed, self.ty_last_seen.unwrap()).unwrap(); + numeric.kind = literal; + } + } + fn visit_resolved_item_mut(&mut self, _resolved_item: &mut ir::ResolvedItem<'cx>) { + // `ResolvedItem` is immutable, not calling super + } +}); diff --git a/ty/opslang-typeck/src/version/v1/lower.rs b/ty/opslang-typeck/src/version/v1/lower.rs new file mode 100644 index 0000000..6646758 --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/lower.rs @@ -0,0 +1,62 @@ +use anyhow::anyhow; +use opslang_ast::v1::{self as ast}; +use opslang_ir::version::v1::{self as ir}; + +/// Lowers an AST comment to an IR comment, preserving source information. +pub fn lower_comment<'cx>( + ir_cx: &'cx ir::Context<'cx>, + ast_comment: &'cx ast::Comment<'cx>, +) -> ir::Comment<'cx> { + ir::Comment { + content: ast_comment.content, + span: ast_comment.span, + source_comments: ir_cx.alloc_ast_comment_slice(&[ast_comment]), + } +} + +/// Merges multiple AST comments into a single IR comment, preserving source information. +pub fn merge_comments<'cx>( + ir_cx: &'cx ir::Context<'cx>, + comments: &[&'cx ast::Comment<'cx>], +) -> super::Result> { + if comments.is_empty() { + return Err(anyhow!("Cannot merge empty comment list")); + } + + if comments.len() == 1 { + // Single comment - simple case + return Ok(ir::Comment { + content: comments[0].content, + span: comments[0].span, + source_comments: ir_cx.alloc_ast_comment_slice(comments), + }); + } + + // Multiple comments - merge content and spans + let mut merged_content = String::new(); + let start = comments[0].span.start; + let mut end = comments[0].span.end; + + for (i, comment) in comments.iter().enumerate() { + if i > 0 { + merged_content.push('\n'); + } + merged_content.push_str(comment.content); + + // Track the overall span from first to last + if i == comments.len() - 1 { + end = comment.span.end; + } + } + + let merged_span = ast::Span { start, end }; + + // Allocate the merged content in the context + let content_ref = ir_cx.alloc_str(&merged_content); + + Ok(ir::Comment { + content: content_ref, + span: merged_span, + source_comments: ir_cx.alloc_ast_comment_slice(comments), + }) +} diff --git a/ty/opslang-typeck/src/version/v1/register_signature.rs b/ty/opslang-typeck/src/version/v1/register_signature.rs new file mode 100644 index 0000000..56bfb5c --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/register_signature.rs @@ -0,0 +1,78 @@ +use super::*; + +use environment::Scope; + +impl<'cx> TypeChecker<'cx> { + pub(super) fn register_signature<'env>( + &mut self, + scope: &mut Scope<'cx, 'env>, + definition: &ast::ToplevelItem<'cx>, + ) -> Result<()> { + if let Some(kind) = &definition.kind { + match kind { + ast::DefinitionKind::Function(func_def) => { + self.register_function_signature(scope, func_def)?; + } + ast::DefinitionKind::Constant(const_def) => { + self.register_constant_signature(scope, const_def)?; + } + } + } + Ok(()) + } + + fn register_function_signature<'env>( + &mut self, + scope: &mut Scope<'cx, 'env>, + func_def: &ast::FunctionDef<'cx>, + ) -> Result<()> { + let func_name = func_def.name; + + // Check if function with same name already exists + if scope.lookup_var(func_name).is_some() { + return Err(anyhow!("function '{func_name}' is already defined")); + } + + let mut param_types = Vec::new(); + + for param in func_def.parameters { + let param_type = self.resolve_type_from_path(param.ty)?; + param_types.push(param_type); + } + + // Handle return type from function definition + let return_type = match &func_def.return_type.0 { + Some((_, return_path)) => self.resolve_type_from_path(*return_path)?, + None => Ty::mk_unit(self.tcx), + }; + + let func_identifier_id = self.tcx.alloc_identifier(func_name); + + let func_type = Ty::mk_procedure( + self.tcx, + Some(Procedure::SameModule { + name: func_identifier_id, + }), + param_types, + return_type, + ); + + scope.bind(func_name, func_identifier_id, func_type); + + Ok(()) + } + + fn register_constant_signature<'env>( + &mut self, + scope: &mut Scope<'cx, 'env>, + const_def: &ast::ConstantDef<'cx>, + ) -> Result<()> { + self.bind( + scope, + const_def.name, + self.resolve_type_from_path(const_def.ty)?, + ); + + Ok(()) + } +} diff --git a/ty/opslang-typeck/src/version/v1/resolve.rs b/ty/opslang-typeck/src/version/v1/resolve.rs new file mode 100644 index 0000000..7fae203 --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/resolve.rs @@ -0,0 +1,52 @@ +use super::*; + +impl<'cx> TypeChecker<'cx> { + pub(super) fn resolve_type_from_path(&self, path: ast::Path<'cx>) -> Result> { + match self.module_loader.resolve_path(path) { + Some(item) => match &*item { + opslang_module::version::v1::ModuleItemDef::Type { ty, .. } => Ok(*ty), + _ => Err(anyhow!("path `{path}` does not refer to a type")), + }, + None => Err(anyhow!("unknown type: {path}")), + } + } + + pub(super) fn resolve_path(&self, path: &'cx ast::Path<'cx>) -> Result> { + match self.module_loader.resolve_path(*path) { + Some(item) => { + let resolved_path = ir::ResolvedPath { + item: opslang_ir::version::ResolvedItem::ModuleItem(item), + original_path: path, + }; + Ok(ResolvePathResult { + resolved_path, + item, + }) + } + None => Err(anyhow!("cannot resolve path: {path}")), + } + } + + /// Eagerly resolves type variables in the given type using the provided substitution. + pub(super) fn eagerly_resolve( + &self, + subst: &mut Substitution<'cx>, + ty: &mut Ty<'cx>, + ) -> Result<()> { + // call `visit_ty_mut` to resolve type variables eagerly + hm::SubstitutionVisitor::new_borrowed(subst, self.tcx).visit_mut(ty); + self.require_resolved(*ty) + } + + pub(super) fn require_resolved(&self, ty: Ty<'cx>) -> Result<()> { + if ty.is_infer() { + Err(anyhow!("type `{ty}` must be resolved at this point")) + } else { + Ok(()) + } + } + + pub(super) fn try_external_resolve(&self, path: ast::Path<'cx>) -> Option> { + self.external_resolver.as_ref()?.resolve(path, self.tcx) + } +} diff --git a/ty/opslang-typeck/src/version/v1/session.rs b/ty/opslang-typeck/src/version/v1/session.rs new file mode 100644 index 0000000..18203de --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/session.rs @@ -0,0 +1,103 @@ +use super::*; + +use opslang_module::version::v1::path::ModulePath; + +/// Entry in the module tree representing a single module. +#[derive(Debug)] +pub struct ModuleEntry<'cx> { + /// The AST program for this module. + pub program: ast::Program<'cx>, + /// The IR program result (populated after type checking). + pub ir_program: Option>, +} + +/// Type checking session managing multiple modules. +/// +/// The session holds a tree of modules and accumulates type checking results. +pub struct Session<'cx, 'env> { + /// Map from module path to module entry. + modules: HashMap, ModuleEntry<'cx>>, + /// Map from module path to its environment with registered signatures. + module_toplevel: HashMap, Scope<'cx, 'env>>, +} + +impl<'cx, 'env> Session<'cx, 'env> { + /// Creates a new empty session. + pub fn new() -> Self { + Self { + modules: HashMap::new(), + module_toplevel: HashMap::new(), + } + } + + /// Adds a module to the session. + pub fn add_module(&mut self, path: ModulePath<'cx>, program: ast::Program<'cx>) { + self.modules.insert( + path, + ModuleEntry { + program, + ir_program: None, + }, + ); + } + + /// Gets a module entry by path. + pub fn get_module(&self, path: &ModulePath<'cx>) -> Option<&ModuleEntry<'cx>> { + self.modules.get(path) + } + + /// Gets a mutable module entry by path. + pub fn get_module_mut(&mut self, path: &ModulePath<'cx>) -> Option<&mut ModuleEntry<'cx>> { + self.modules.get_mut(path) + } + + /// Iterates over all module paths and entries. + pub fn iter(&self) -> impl Iterator, &ModuleEntry<'cx>)> { + self.modules.iter() + } + + /// Iterates mutably over all module paths and entries. + pub fn iter_mut(&mut self) -> impl Iterator, &mut ModuleEntry<'cx>)> { + self.modules.iter_mut() + } + + /// Gets the environment for a module. + pub fn get_environment(&self, path: &ModulePath<'cx>) -> Option<&Scope<'cx, '_>> { + self.module_toplevel.get(path) + } + + /// Gets a mutable environment for a module. + pub fn get_environment_mut(&mut self, path: &ModulePath<'cx>) -> Option<&mut Scope<'cx, 'env>> { + self.module_toplevel.get_mut(path) + } + + /// Registers an environment for a module. + pub fn register_environment(&mut self, path: ModulePath<'cx>, env: Scope<'cx, 'env>) { + self.module_toplevel.insert(path, env); + } +} + +impl<'cx, 'env> Default for Session<'cx, 'env> { + fn default() -> Self { + Self::new() + } +} + +#[derive(Clone, Copy)] +pub struct SecondPassSession<'cx, 'sess> { + /// The underlying type checking session. + sess: &'sess Session<'cx, 'sess>, + + /// The module path currently being type checked. + pub module_path: ModulePath<'cx>, +} + +impl<'cx, 'sess> SecondPassSession<'cx, 'sess> { + pub fn new(sess: &'sess Session<'cx, 'sess>, module_path: ModulePath<'cx>) -> Self { + Self { sess, module_path } + } + + pub fn get_toplevel_items_of(&self, path: &ModulePath<'cx>) -> Option<&Scope<'cx, '_>> { + self.sess.get_environment(path) + } +} diff --git a/ty/opslang-typeck/src/version/v1/tests.rs b/ty/opslang-typeck/src/version/v1/tests.rs new file mode 100644 index 0000000..d8c4d1d --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/tests.rs @@ -0,0 +1,182 @@ +use opslang_ir::version::v1::ResolvedItem; +use opslang_module::version::v1::{ModuleContext, ModuleItemDef}; +use opslang_ty::version::v1::IntTy; + +use crate::v1_setup_cx; + +use super::*; + +fn parse_ident<'cx>(cx: &'cx ast::context::Context<'cx>, str: &str) -> ast::Path<'cx> { + ast::Path::single( + cx, + str, + ast::Span { + start: ast::BytePos(0), + end: ast::BytePos(0), + }, + ) +} + +#[test] +fn test_display() { + let cx = TypingContext::new(); + + let int_type = Ty::mk_i32(&cx); + let array_type = Ty::mk_array(&cx, int_type); + + assert_eq!(int_type.to_string(), "i32"); + assert_eq!(array_type.to_string(), "[i32]"); +} + +#[test] +fn test_builtin_module() { + v1_setup_cx!(ast_cx, _ir_cx, gcx = { cx, module }); + let builtin = create_builtin_module(gcx); + + assert_eq!(builtin.name(), "builtin"); + assert!(builtin.lookup_item(parse_ident(&ast_cx, "i32")).is_some()); + assert!(builtin.lookup_item(parse_ident(&ast_cx, "f64")).is_some()); + assert!( + builtin + .lookup_item(parse_ident(&ast_cx, "unknown")) + .is_none() + ); + + if let Some(ModuleItemDef::Type { id, ty }) = builtin.lookup_item(parse_ident(&ast_cx, "i32")) { + assert_eq!(id.name, "i32"); + assert!(matches!(ty.kind(), TyKind::Int(IntTy::I32))); + } +} + +#[test] +fn test_module_loader() { + let cx = TypingContext::new(); + let ast_cx = ast::context::Context::new(); + let module = ModuleContext::new(); + let gcx = GlobalContext { + tcx: &cx, + module: &module, + }; + let builtin = create_builtin_module(gcx); + + let mut loader = ModuleLoader::new(); + loader.add_module(builtin); + + assert!(loader.lookup_module("builtin").is_some()); + assert!(loader.lookup_module("unknown").is_none()); + + assert!(loader.resolve_path(parse_ident(&ast_cx, "i32")).is_some()); + assert!( + loader + .resolve_path(parse_ident(&ast_cx, "unknown")) + .is_none() + ); +} + +#[test] +fn test_type_checker_with_modules() { + let cx = TypingContext::new(); + let ast_cx = ast::context::Context::new(); + let ir_cx = ir::Context::new(); + let module = ModuleContext::new(); + let gcx = GlobalContext { + tcx: &cx, + module: &module, + }; + let builtin = create_builtin_module(gcx); + + let mut loader = ModuleLoader::new(); + loader.add_module(builtin); + + let checker = TypeChecker::with_module_loader(loader, gcx, &ir_cx); + + let i32_type = checker + .resolve_type_from_path(parse_ident(&ast_cx, "i32")) + .unwrap(); + assert!(matches!(i32_type.kind(), TyKind::Int(IntTy::I32))); + + let unknown_result = checker.resolve_type_from_path(parse_ident(&ast_cx, "unknown")); + assert!(unknown_result.is_err()); +} + +#[test] +fn test_substitution() { + let cx = TypingContext::new(); + let var = TyVid::fresh(); + let int_type = Ty::mk_i32(&cx); + + let mut subst = Substitution::new(); + subst.insert(var, int_type); + + let var_type = Ty::mk_variable(&cx, var); + let result = subst.apply_substitution_pure(&cx, var_type); + + assert!(matches!(result.kind(), TyKind::Int(IntTy::I32))); +} + +#[test] +fn test_unify_basic() { + let cx = TypingContext::new(); + let ir_cx = ir::Context::new(); + let module = ModuleContext::new(); + let gcx = GlobalContext { + tcx: &cx, + module: &module, + }; + + let int_type1 = Ty::mk_i32(&cx); + let int_type2 = Ty::mk_i32(&cx); + let float_type = Ty::mk_f64(&cx); + + let chk = TypeChecker::new(gcx, &ir_cx); + + let result = chk.unify_pure(int_type1, int_type2); + assert!(result.is_ok()); + assert!(result.unwrap().is_empty()); + + let result = chk.unify_pure(int_type1, float_type); + assert!(result.is_err()); +} + +#[test] +fn test_variable_resolution_priority() { + let cx = TypingContext::new(); + let ir_cx = ir::Context::new(); + let module = ModuleContext::new(); + let gcx = GlobalContext { + tcx: &cx, + module: &module, + }; + + // these variables are defined here so as to live longer than the checker + let i32_ident = ast::Ident { + raw: "i32", + span: ast::Span { + start: ast::BytePos(0), + end: ast::BytePos(0), + }, + }; + let binding = [i32_ident]; + let path = ast::Path { segments: &binding }; + + let builtin = create_builtin_module(gcx); + + let mut loader = ModuleLoader::new(); + loader.add_module(builtin); + let mut checker = TypeChecker::with_module_loader(loader, gcx, &ir_cx); + + let mut env = Scope::new(); + + // define local variable `i32` with type `String` + let local_i32_type = Ty::mk_string(&cx); + checker.bind(&mut env, i32_ident, local_i32_type); + + // resolve path `i32` + let (resolved_type, _) = checker.typeck_path(&env, &path).unwrap(); + + // should resolve to local variable type `String` instead of builtin type `i32` + assert!(matches!( + resolved_type.item, + ResolvedItem::LocalVariable { .. } + )); +} diff --git a/ty/opslang-typeck/src/version/v1/typeck_apply.rs b/ty/opslang-typeck/src/version/v1/typeck_apply.rs new file mode 100644 index 0000000..67bb49d --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/typeck_apply.rs @@ -0,0 +1,107 @@ +use super::*; + +impl<'cx> TypeChecker<'cx> { + pub(super) fn typeck_apply<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + env: &Scope<'cx, 'env>, + subst: &mut Substitution<'cx>, + apply: &'cx ast::Apply<'cx>, + qualifs: &'cx [ast::Qualif<'cx>], + ) -> Result> { + let func_ir = self.typeck_expr(session, env, subst, &apply.function)?; + let mut arg_types = Vec::new(); + let mut args = Vec::new(); + let mut qualifications = Vec::new(); + + // Process qualifications first + for qualif in qualifs { + let qualif_ir = self.typeck_qualif(session, env, subst, qualif)?; + qualifications.push(qualif_ir); + } + + // Process arguments, collecting any Qualif expressions + for arg in apply.args { + if let ast::ExprKind::Qualif(qualif) = arg.0 { + // Collect Qualif as qualification + let qualif_ir = self.typeck_qualif(session, env, subst, qualif)?; + qualifications.push(qualif_ir); + } else { + // Regular argument + let arg_ir = self.typeck_expr(session, env, subst, arg)?; + arg_types.push(arg_ir.ty); + args.push(arg_ir); + } + } + + let return_type = Ty::mk_variable(self.tcx, TyVid::fresh()); + let expected_func_type = Ty::mk_function(self.tcx, arg_types, return_type); + + self.unify(subst, func_ir.ty, expected_func_type)?; + + if let TyKind::Function { + arg: _, + ret: _, + is_procedure, + } = func_ir.ty.kind() + { + if is_procedure.is_some() { + return Err(anyhow!( + "cannot apply a procedure, add `call` before the procedure name" + )); + } + } else { + unreachable!(); + } + + args.shrink_to_fit(); + qualifications.shrink_to_fit(); + + // Create IR Apply expression + let ir_apply = ir::Apply { + function: func_ir, + args, + qualifications, + resolved_function: None, // FIXME + }; + let ir_expr_kind = ir::ExprKind::Apply(ir_apply); + let ir_expr = self.ir_cx.alloc_expr_with_type(ir_expr_kind, return_type); + Ok(ir_expr) + } + + fn typeck_qualif<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + env: &Scope<'cx, 'env>, + subst: &mut Substitution<'cx>, + qualif: &'cx ast::Qualif<'cx>, + ) -> Result> { + match qualif { + ast::Qualif::Modifier(modifier) => { + let ir_path = self.resolve_path(&modifier.id)?.resolved_path; + let ir_param = if let Some(param) = &modifier.arg { + let param_ir = self.typeck_expr(session, env, subst, ¶m.value)?; + Some(ir::ModifierParam { + colon_token: param.colon_token.into_token(), + value: param_ir, + }) + } else { + None + }; + + Ok(ir::Qualif::Modifier(ir::Modifier { + at_token: modifier.at_token.into_token(), + id: ir_path, + arg: ir_param, + })) + } + ast::Qualif::DefaultModifier(default_modifier) => { + let ir_path = self.resolve_path(&default_modifier.value)?.resolved_path; + Ok(ir::Qualif::DefaultModifier(ir::DefaultModifier { + tilde_token: default_modifier.tilde_token.into_token(), + value: ir_path, + })) + } + } + } +} diff --git a/ty/opslang-typeck/src/version/v1/typeck_binary.rs b/ty/opslang-typeck/src/version/v1/typeck_binary.rs new file mode 100644 index 0000000..a07d060 --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/typeck_binary.rs @@ -0,0 +1,274 @@ +use super::*; + +impl<'cx> TypeChecker<'cx> { + /// Performs type checking on an expression and converts it to IR. + /// + /// This function infers the type of an expression and converts it to its IR representation. + /// It updates the provided substitution with any new type constraints discovered during checking. + pub(super) fn typeck_binary<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + env: &Scope<'cx, 'env>, + subst: &mut Substitution<'cx>, + expr: &'cx ast::Binary<'cx>, + ) -> Result> { + let binary = expr; + let mut lhs_ir = self.typeck_expr(session, env, subst, &binary.lhs)?; + let mut rhs_ir = self.typeck_expr(session, env, subst, &binary.rhs)?; + + match binary.op { + ast::BinOp::Add(span) => { + self.eagerly_resolve(subst, &mut lhs_ir.ty)?; + self.eagerly_resolve(subst, &mut rhs_ir.ty)?; + self.typeck_add_sub(lhs_ir, rhs_ir, |operand| ir::BinOp::Add { + kind: ir::BuiltinAdd::Basic(operand), + span: span.into_token(), + }) + } + ast::BinOp::Sub(span) => { + self.eagerly_resolve(subst, &mut lhs_ir.ty)?; + self.eagerly_resolve(subst, &mut rhs_ir.ty)?; + self.typeck_add_sub(lhs_ir, rhs_ir, |operand| ir::BinOp::Sub { + kind: ir::BuiltinSub::Basic(operand), + span: span.into_token(), + }) + } + ast::BinOp::Mul(span) => { + self.eagerly_resolve(subst, &mut lhs_ir.ty)?; + self.eagerly_resolve(subst, &mut rhs_ir.ty)?; + self.typeck_mul_div(lhs_ir, rhs_ir, |operand| ir::BinOp::Mul { + kind: ir::BuiltinMul::Basic(operand), + span: span.into_token(), + }) + } + ast::BinOp::Div(span) => { + self.eagerly_resolve(subst, &mut lhs_ir.ty)?; + self.eagerly_resolve(subst, &mut rhs_ir.ty)?; + self.typeck_mul_div(lhs_ir, rhs_ir, |operand| ir::BinOp::Div { + kind: ir::BuiltinDiv::Basic(operand), + span: span.into_token(), + }) + } + ast::BinOp::Mod(span) => { + self.unify(subst, lhs_ir.ty, rhs_ir.ty)?; + if lhs_ir.ty.is_integer() { + // Create IR binary expression + let ty = lhs_ir.ty; + let ir_expr = ir::Expr::new( + ir::ExprMut::binary( + self.ir_cx, + lhs_ir, + ir::BinOp::Mod { + span: span.into_token(), + }, + rhs_ir, + ), + ty, + ); + Ok(ir_expr) + } else { + Err(anyhow!( + "modulo operation requires integer type, got {}", + lhs_ir.ty + )) + } + } + ast::BinOp::And(span) => { + let bool_type = Ty::mk_bool(self.tcx); + self.unify(subst, lhs_ir.ty, bool_type)?; + self.unify(subst, lhs_ir.ty, bool_type)?; + + // Create IR binary expression + let ir_expr = ir::Expr::new( + ir::ExprMut::binary( + self.ir_cx, + lhs_ir, + ir::BinOp::And { + span: span.into_token(), + }, + rhs_ir, + ), + bool_type, + ); + Ok(ir_expr) + } + ast::BinOp::Or(span) => { + let bool_type = Ty::mk_bool(self.tcx); + self.unify(subst, lhs_ir.ty, bool_type)?; + self.unify(subst, lhs_ir.ty, bool_type)?; + + // Create IR binary expression + let ir_expr = ir::Expr::new( + ir::ExprMut::binary( + self.ir_cx, + lhs_ir, + ir::BinOp::Or { + span: span.into_token(), + }, + rhs_ir, + ), + bool_type, + ); + Ok(ir_expr) + } + } + } + + fn typeck_add_sub( + &mut self, + lhs_ir: ir::Expr<'cx>, + rhs_ir: ir::Expr<'cx>, + op: impl FnOnce(ir::BuiltinAddSubOperand) -> ir::BinOp<'cx>, + ) -> Result> { + match (lhs_ir.ty.kind(), rhs_ir.ty.kind()) { + (&TyKind::Int(lhs_ty), &TyKind::Int(rhs_ty)) => { + let result_ty = lhs_ty.max(rhs_ty); + let operand = ir::BuiltinAddSubOperand::Int(ir::MagmaTriad { + lhs_ty, + rhs_ty, + result_ty, + }); + let ty = Ty::mk_int(self.tcx, result_ty); + let ir_expr = ir::Expr::new( + ir::ExprMut::binary(self.ir_cx, lhs_ir, op(operand), rhs_ir), + ty, + ); + Ok(ir_expr) + } + (&TyKind::Uint(lhs_ty), &TyKind::Uint(rhs_ty)) => { + let result_ty = lhs_ty.max(rhs_ty); + let operand = ir::BuiltinAddSubOperand::Uint(ir::MagmaTriad { + lhs_ty, + rhs_ty, + result_ty, + }); + let ty = Ty::mk_uint(self.tcx, result_ty); + let ir_expr = ir::Expr::new( + ir::ExprMut::binary(self.ir_cx, lhs_ir, op(operand), rhs_ir), + ty, + ); + Ok(ir_expr) + } + (&TyKind::Float(lhs_ty), &TyKind::Float(rhs_ty)) => { + let result_ty = lhs_ty.max(rhs_ty); + let operand = ir::BuiltinAddSubOperand::Float(ir::MagmaTriad { + lhs_ty, + rhs_ty, + result_ty, + }); + let ty = Ty::mk_float(self.tcx, result_ty); + let ir_expr = ir::Expr::new( + ir::ExprMut::binary(self.ir_cx, lhs_ir, op(operand), rhs_ir), + ty, + ); + Ok(ir_expr) + } + (&TyKind::Duration, &TyKind::Duration) => { + let ty = Ty::mk_duration(self.tcx); + let operand = ir::BuiltinAddSubOperand::DurationDuration; + let ir_expr = ir::Expr::new( + ir::ExprMut::binary(self.ir_cx, lhs_ir, op(operand), rhs_ir), + ty, + ); + Ok(ir_expr) + } + (&TyKind::Time, &TyKind::Duration) => { + let ty = Ty::mk_time(self.tcx); + let operand = ir::BuiltinAddSubOperand::DateTimeDuration; + let ir_expr = ir::Expr::new( + ir::ExprMut::binary(self.ir_cx, lhs_ir, op(operand), rhs_ir), + ty, + ); + Ok(ir_expr) + } + (&TyKind::Duration, &TyKind::Time) => { + let ty = Ty::mk_time(self.tcx); + let operand = ir::BuiltinAddSubOperand::DurationDateTime; + let ir_expr = ir::Expr::new( + ir::ExprMut::binary(self.ir_cx, lhs_ir, op(operand), rhs_ir), + ty, + ); + Ok(ir_expr) + } + _ => Err(anyhow!( + "addition requires both operands to be of compatible types (int, uint, float, duration, time), got {} and {}", + lhs_ir.ty, + rhs_ir.ty + )), + } + } + + fn typeck_mul_div( + &mut self, + lhs_ir: ir::Expr<'cx>, + rhs_ir: ir::Expr<'cx>, + op: impl FnOnce(ir::BuiltinMulDivOperand) -> ir::BinOp<'cx>, + ) -> Result> { + match (lhs_ir.ty.kind(), rhs_ir.ty.kind()) { + (&TyKind::Int(lhs_ty), &TyKind::Int(rhs_ty)) => { + let result_ty = lhs_ty.max(rhs_ty); + let operand = ir::BuiltinMulDivOperand::Int(ir::MagmaTriad { + lhs_ty, + rhs_ty, + result_ty, + }); + let ty = Ty::mk_int(self.tcx, result_ty); + let ir_expr = ir::Expr::new( + ir::ExprMut::binary(self.ir_cx, lhs_ir, op(operand), rhs_ir), + ty, + ); + Ok(ir_expr) + } + (&TyKind::Uint(lhs_ty), &TyKind::Uint(rhs_ty)) => { + let result_ty = lhs_ty.max(rhs_ty); + let operand = ir::BuiltinMulDivOperand::Uint(ir::MagmaTriad { + lhs_ty, + rhs_ty, + result_ty, + }); + let ty = Ty::mk_uint(self.tcx, result_ty); + let ir_expr = ir::Expr::new( + ir::ExprMut::binary(self.ir_cx, lhs_ir, op(operand), rhs_ir), + ty, + ); + Ok(ir_expr) + } + (&TyKind::Float(lhs_ty), &TyKind::Float(rhs_ty)) => { + let result_ty = lhs_ty.max(rhs_ty); + let operand = ir::BuiltinMulDivOperand::Float(ir::MagmaTriad { + lhs_ty, + rhs_ty, + result_ty, + }); + let ty = Ty::mk_float(self.tcx, result_ty); + let ir_expr = ir::Expr::new( + ir::ExprMut::binary(self.ir_cx, lhs_ir, op(operand), rhs_ir), + ty, + ); + Ok(ir_expr) + } + (&TyKind::Duration, rhs @ TyKind::Int(_)) + | (&TyKind::Duration, rhs @ TyKind::Uint(_)) + | (&TyKind::Duration, rhs @ TyKind::Float(_)) => { + let rhs_ty = match rhs { + TyKind::Int(ty) => ty::Numeric::Int(*ty), + TyKind::Uint(ty) => ty::Numeric::Uint(*ty), + TyKind::Float(ty) => ty::Numeric::Float(*ty), + _ => unreachable!(), + }; + let operand = ir::BuiltinMulDivOperand::DurationNumeric(rhs_ty); + let ty = Ty::mk_duration(self.tcx); + let ir_expr = ir::Expr::new( + ir::ExprMut::binary(self.ir_cx, lhs_ir, op(operand), rhs_ir), + ty, + ); + Ok(ir_expr) + } + _ => Err(anyhow!( + "multiplication/division requires both operands to be of compatible types (int, uint, float, duration), got {} and {}", + lhs_ir.ty, + rhs_ir.ty + )), + } + } +} diff --git a/ty/opslang-typeck/src/version/v1/typeck_block.rs b/ty/opslang-typeck/src/version/v1/typeck_block.rs new file mode 100644 index 0000000..2d0887d --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/typeck_block.rs @@ -0,0 +1,115 @@ +use super::*; + +impl<'cx> TypeChecker<'cx> { + pub(super) fn typeck_block<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + env: &Scope<'cx, 'env>, + subst: &mut Substitution<'cx>, + block: &ast::Block<'cx>, + ) -> Result> { + let mut local_env = env.extend_inherit(); + let mut ir_items: Vec> = Vec::new(); + let mut pending_comments: Vec<&'cx ast::Comment<'cx>> = Vec::new(); + + for item in block.scope.items { + match item { + ast::ScopeItem::Row(row) => { + match self.typeck_row(session, &mut local_env, subst, row)? { + RowProcessResult::Comment(comment) => { + pending_comments.push(comment); + } + RowProcessResult::ScopeItem(scope_item) => { + // Flush any pending comments before adding the regular item + self.flush_comments_to_items(&mut pending_comments, &mut ir_items)?; + ir_items.push(scope_item); + } + } + } + ast::ScopeItem::Block(nested_block) => { + // Flush any pending comments before adding the block + self.flush_comments_to_items(&mut pending_comments, &mut ir_items)?; + let ir_block = self.typeck_block(session, &local_env, subst, nested_block)?; + ir_items.push(ir::ScopeItem::Block(ir_block)); + } + } + } + + // Flush any remaining comments at the end + self.flush_comments_to_items(&mut pending_comments, &mut ir_items)?; + + let ir_scope = ir::Scope { items: ir_items }; + + let ir_block = ir::Block { + left_brace: block.left_brace.into_token(), + scope: ir_scope, + right_brace: block.right_brace.into_token(), + }; + + Ok(ir_block) + } +} + +/// Result of [`TypeChecker::typeck_row`] - either a comment to be merged or a regular scope item +enum RowProcessResult<'cx> { + Comment(&'cx ast::Comment<'cx>), + ScopeItem(ir::ScopeItem<'cx>), +} + +impl<'cx> TypeChecker<'cx> { + fn typeck_row<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + env: &mut Scope<'cx, 'env>, + subst: &mut Substitution<'cx>, + row: &ast::Row<'cx>, + ) -> Result> { + // Check if this row is only a comment (no content, no breaks) + if row.breaks.is_none() + && row.statement.is_none() + && let Some(comment) = &row.comment + { + return Ok(RowProcessResult::Comment(comment)); + } + + // Process as a regular row + let ir_content = if let Some(content) = &row.statement { + let stmt = self.typeck_statement(session, env, subst, content)?; + Some(stmt) + } else { + None + }; + + let ir_comment = row.comment.as_ref().map(|comment| ir::Comment { + content: comment.content, + span: comment.span, + source_comments: self.ir_cx.alloc_ast_comment_slice(&[comment]), + }); + + let ir_row = ir::Row { + breaks: row.breaks.map(|b| b.into_token()), + statement: ir_content, + comment: ir_comment, + }; + + Ok(RowProcessResult::ScopeItem(ir::ScopeItem::Row(ir_row))) + } + + fn flush_comments_to_items( + &self, + comments: &mut Vec<&'cx ast::Comment<'cx>>, + ir_items: &mut Vec>, + ) -> Result<()> { + if !comments.is_empty() { + let merged_comment = lower::merge_comments(self.ir_cx, comments)?; + let comment_row = ir::Row { + breaks: None, + statement: None, + comment: Some(merged_comment), + }; + ir_items.push(ir::ScopeItem::Row(comment_row)); + comments.clear(); + } + Ok(()) + } +} diff --git a/ty/opslang-typeck/src/version/v1/typeck_call.rs b/ty/opslang-typeck/src/version/v1/typeck_call.rs new file mode 100644 index 0000000..2531d89 --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/typeck_call.rs @@ -0,0 +1,79 @@ +use super::*; + +impl<'cx> TypeChecker<'cx> { + pub(super) fn typeck_call<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + env: &Scope<'cx, 'env>, + subst: &mut Substitution<'cx>, + call: &'cx ast::Call<'cx>, + ) -> Result> { + if let ast::ExprKind::Apply(apply) = call.expr.0 { + let func_ir = self.typeck_expr(session, env, subst, &apply.function)?; + let mut arg_types = Vec::new(); + let mut args = Vec::new(); + + // Process arguments + for arg in apply.args { + let arg_ir = self.typeck_expr(session, env, subst, arg)?; + arg_types.push(arg_ir.ty); + args.push(arg_ir); + } + + let return_type = Ty::mk_variable(self.tcx, TyVid::fresh()); + let expected_func_type = Ty::mk_function(self.tcx, arg_types, return_type); + + self.unify(subst, func_ir.ty, expected_func_type)?; + + guard_calling_non_prc(&func_ir)?; + + args.shrink_to_fit(); + + // Create IR Apply expression + let ir_apply = ir::Apply { + function: func_ir, + args, + qualifications: vec![], + resolved_function: None, // FIXME + }; + let ir_expr_kind = ir::ExprKind::Apply(ir_apply); + let ir_expr = self.ir_cx.alloc_expr_with_type(ir_expr_kind, return_type); + Ok(ir_expr) + } else { + // Allow calling `() -> T` procedures + let func_ir = self.typeck_expr(session, env, subst, call.expr.0)?; + let return_type = Ty::mk_variable(self.tcx, TyVid::fresh()); + let expected_func_type = Ty::mk_function(self.tcx, vec![], return_type); + self.unify(subst, func_ir.ty, expected_func_type)?; + guard_calling_non_prc(&func_ir)?; + let ir_apply = ir::Apply { + function: func_ir, + args: vec![], + qualifications: vec![], + resolved_function: None, // FIXME + }; + let ir_expr_kind = ir::ExprKind::Apply(ir_apply); + let ir_expr = self.ir_cx.alloc_expr_with_type(ir_expr_kind, return_type); + Ok(ir_expr) + } + } +} + +/// Ensures that the function being called is a procedure. +fn guard_calling_non_prc<'cx>(func_ir: &ir::Expr<'cx>) -> Result<()> { + if let TyKind::Function { + arg: _, + ret: _, + is_procedure, + } = func_ir.ty.kind() + { + if is_procedure.is_none() { + return Err(anyhow!( + "cannot call a pure function, remove `call` before the function name" + )); + } + } else { + unreachable!(); + } + Ok(()) +} diff --git a/ty/opslang-typeck/src/version/v1/typeck_constant.rs b/ty/opslang-typeck/src/version/v1/typeck_constant.rs new file mode 100644 index 0000000..7bdf61d --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/typeck_constant.rs @@ -0,0 +1,31 @@ +use super::*; + +impl<'cx> TypeChecker<'cx> { + pub(super) fn typeck_constant<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + env: &Scope<'cx, 'env>, + const_def: &'cx ast::ConstantDef<'cx>, + ) -> Result> { + let declared_type = self.resolve_type_from_path(const_def.ty)?; + let mut subst = Substitution::new(); + let mut inferred_expr = self.typeck_expr(session, env, &mut subst, &const_def.value)?; + + self.unify(&mut subst, declared_type, inferred_expr.ty)?; + + // Apply final substitution using visitor + hm::SubstitutionVisitor::new(subst, self.tcx).visit_mut(&mut inferred_expr); + + let ir_ty = self.resolve_path(&const_def.ty)?.resolved_path; + + Ok(ir::ConstantDef { + const_token: const_def.const_token.into_token(), + name: self.tcx.alloc_identifier(const_def.name), + colon: const_def.colon.into_token(), + ty: ir_ty, + eq: const_def.eq.into_token(), + value: inferred_expr, + semi: const_def.semi.into_token(), + }) + } +} diff --git a/ty/opslang-typeck/src/version/v1/typeck_expr.rs b/ty/opslang-typeck/src/version/v1/typeck_expr.rs new file mode 100644 index 0000000..a65f1d3 --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/typeck_expr.rs @@ -0,0 +1,368 @@ +use super::*; + +impl<'cx> TypeChecker<'cx> { + /// Performs type checking on an expression and converts it to IR. + /// + /// This function infers the type of an expression and converts it to its IR representation. + /// It updates the provided substitution with any new type constraints discovered during checking. + pub(super) fn typeck_expr<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + env: &Scope<'cx, 'env>, + subst: &mut Substitution<'cx>, + mut expr: &'cx ast::ExprKind<'cx>, + ) -> Result> { + // Peel parentheses + while let ast::ExprKind::Parened(parened) = expr { + expr = &parened.expr; + } + match expr { + ast::ExprKind::Parened(_parened) => unreachable!("handled above"), + ast::ExprKind::Literal(literal) => { + let (ir_literal, ty) = self.typeck_literal(session, env, subst, literal)?; + let ir_expr = ir::Expr::new(ir::ExprMut::literal(self.ir_cx, ir_literal), ty); + Ok(ir_expr) + } + ast::ExprKind::Variable(path) => { + let (resolved_path, ty) = self.typeck_path(env, path)?; + let ir_expr = ir::Expr::new(ir::ExprMut::variable(self.ir_cx, resolved_path), ty); + Ok(ir_expr) + } + ast::ExprKind::Binary(binary) => self.typeck_binary(session, env, subst, binary), + ast::ExprKind::Unary(unary) => { + let expr_ir = self.typeck_expr(session, env, subst, &unary.expr)?; + + match unary.op { + ast::UnOp::Neg(_) => { + match expr_ir.ty.kind() { + TyKind::Int(_) | TyKind::Uint(_) | TyKind::Float(_) => { + // Ok, do nothing + } + _ => { + // resolve to default int + self.unify(subst, expr_ir.ty, Ty::mk_i32(self.tcx))? + } + } + // Create IR operand with unified type + + // Create IR unary expression + let ty = expr_ir.ty; + let ir_result = ir::Expr::new( + ir::ExprMut::unary(self.ir_cx, unary.op.into_token(), expr_ir), + ty, + ); + Ok(ir_result) + } + ast::UnOp::IdRef(_) => { + // IdRef (&expr) - obtain an identifier of an external variable as i64 + let ty = expr_ir.ty; + let ty = match ty.kind() { + TyKind::External { .. } => Ty::mk_i64(self.tcx), + _ => { + return Err(anyhow!( + "idref operator requires an external variable, got {ty}" + )); + } + }; + let ir_result = ir::Expr::new( + ir::ExprMut::unary(self.ir_cx, unary.op.into_token(), expr_ir), + ty, + ); + Ok(ir_result) + } + ast::UnOp::Deref(_) => { + // Deref ($expr) - dereferences an external variable to its underlying type + let ty = expr_ir.ty; + let ty = match ty.kind() { + TyKind::External { ty, .. } => *ty, + _ => { + return Err(anyhow!( + "deref operator requires an external variable, got {ty}" + )); + } + }; + let ir_result = ir::Expr::new( + ir::ExprMut::unary(self.ir_cx, unary.op.into_token(), expr_ir), + ty, + ); + Ok(ir_result) + } + } + } + ast::ExprKind::Cast(cast) => { + let mut expr_ir = self.typeck_expr(session, env, subst, &cast.expr)?; + self.eagerly_resolve(subst, &mut expr_ir.ty)?; + let target_ty = self.resolve_type_from_path(cast.ty)?; + + // Ensure the cast is valid (basic check) + let lhs_kind = expr_ir.ty.kind(); + let rhs_kind = target_ty.kind(); + if lhs_kind.is_bool() && rhs_kind.is_bool() + || lhs_kind.is_numeric() && rhs_kind.is_numeric() + || lhs_kind.is_integer() && rhs_kind.is_bool() + || lhs_kind.is_bool() && rhs_kind.is_integer() + { + // Ok + } else { + // For other types, ensure they are compatible numeric types + return Err(anyhow!("invalid cast from {} to {target_ty}", expr_ir.ty)); + } + + // Create IR cast expression + let ir_expr = ir::Expr::new( + ir::ExprMut::cast(self.ir_cx, expr_ir, cast.as_kw.into_token(), target_ty), + target_ty, + ); + Ok(ir_expr) + } + ast::ExprKind::Apply(apply) => self.typeck_apply(session, env, subst, apply, &[]), + ast::ExprKind::If(if_expr) => { + let cond_ir = self.typeck_expr(session, env, subst, &if_expr.cond)?; + let bool_type = Ty::mk_bool(self.tcx); + self.unify(subst, cond_ir.ty, bool_type)?; + let ir_then_block = self.typeck_block(session, env, subst, if_expr.then_clause)?; + + if let Some(else_clause) = &if_expr.else_opt { + let ir_else_block = + self.typeck_block(session, env, subst, else_clause.else_clause)?; + let unified_then = subst.apply_substitution_pure( + self.tcx, + ir_then_block.ty(self.tcx).unwrap_or(Ty::mk_unit(self.tcx)), + ); + let unified_else = subst.apply_substitution_pure( + self.tcx, + ir_else_block.ty(self.tcx).unwrap_or(Ty::mk_unit(self.tcx)), + ); + self.unify(subst, unified_then, unified_else)?; + let result_type = subst.apply_substitution_pure(self.tcx, unified_then); + + // Create IR if-else expression + let ir_expr = ir::Expr::new( + ir::ExprMut::if_then_else( + self.ir_cx, + if_expr.if_kw.into_token(), + cond_ir, + ir_then_block, + else_clause.else_kw.into_token(), + ir_else_block, + ), + result_type, + ); + Ok(ir_expr) + } else { + // no else + let unit_type = Ty::mk_unit(self.tcx); + if let Some(ty) = ir_then_block.ty(self.tcx) { + self.unify(subst, ty, unit_type)?; + } + + // Create IR if expression (without else) + let ir_expr = ir::Expr::new( + ir::ExprMut::if_then( + self.ir_cx, + if_expr.if_kw.into_token(), + cond_ir, + ir_then_block, + ), + unit_type, + ); + Ok(ir_expr) + } + } + ast::ExprKind::Wait(wait) => { + let mut expr_ir = self.typeck_expr(session, env, subst, &wait.expr)?; + self.eagerly_resolve(subst, &mut expr_ir.ty)?; + + // Check that the expression is awaitable + let ty = expr_ir.ty; + let is_awaitable = ty.is_bool() || ty.is_duration(); + if !is_awaitable { + return Err(anyhow!( + "wait expression requires awaitable type (bool or duration), got {ty}", + )); + } + + // Create IR wait expression + let ir_expr = ir::Expr::new( + ir::ExprMut::wait(self.ir_cx, wait.wait_kw.into_token(), expr_ir), + Ty::mk_unit(self.tcx), + ); + Ok(ir_expr) + } + ast::ExprKind::Select(select) => { + let ast::Select { + select_kw, + left_brace, + items, + right_brace, + } = select; + let mut ir_items = Vec::new(); + let mut result_type = None; + + for item in *items { + let mut expr_ir = self.typeck_expr(session, env, subst, &item.expr)?; + let body_ir = self.typeck_block(session, env, subst, item.body)?; + + // Check that the expression is awaitable + self.eagerly_resolve(subst, &mut expr_ir.ty)?; + let ty = expr_ir.ty; + let is_awaitable = ty.is_bool() || ty.is_duration(); + if !is_awaitable { + return Err(anyhow!( + "select expression requires awaitable type (bool or duration), got {ty}", + )); + } + + // Ensure all bodies have the same type + if let Some(existing_type) = result_type { + let body_type = body_ir.ty(self.tcx).unwrap_or(Ty::mk_unit(self.tcx)); + self.unify(subst, existing_type, body_type)?; + result_type = Some(subst.apply_substitution_pure(self.tcx, existing_type)); + } else { + result_type = Some(body_ir.ty(self.tcx).unwrap_or(Ty::mk_unit(self.tcx))); + } + + ir_items.push(ir::SelectItem { + expr: expr_ir, + arrow: item.arrow.into_token(), + body: body_ir, + }); + } + + let final_type = result_type.unwrap_or(Ty::mk_unit(self.tcx)); + + // Create IR select expression + let ir_expr = ir::Expr::new( + ir::ExprMut::select( + self.ir_cx, + select_kw.into_token(), + left_brace.into_token(), + ir_items, + right_brace.into_token(), + ), + final_type, + ); + Ok(ir_expr) + } + ast::ExprKind::Qualif(_) => { + Err(anyhow!("Qualif cannot be used as a standalone expression")) + } + ast::ExprKind::PreQualified(prequalified) => { + if let ast::ExprKind::Apply(apply) = &prequalified.expr.0 { + self.typeck_apply(session, env, subst, apply, prequalified.qualifs) + } else { + Err(anyhow!( + "PreQualified expressions can only be applied to function calls" + )) + } + } + ast::ExprKind::Compare(compare) => { + // Compare expressions have a head expression and a tail of (op, expr) pairs + let head_ir = self.typeck_expr(session, env, subst, &compare.head)?; + let mut ir_tail = Vec::new(); + + // Type check all comparison operands - they should all have the same type + let expected_type = head_ir.ty; + + for ast::CompareOpExpr { op, val: expr } in compare.tail_with_op { + let expr_ir = self.typeck_expr(session, env, subst, expr)?; + + // Unify with expected type + self.unify(subst, expected_type, expr_ir.ty)?; + + ir_tail.push(ast::CompareOpExpr { + op: op.into_token(), + val: expr_ir, + }); + } + + // Create IR Compare expression - result is always bool + let bool_type = Ty::mk_bool(self.tcx); + let ir_expr = ir::Expr::new( + ir::ExprMut::from_kind( + self.ir_cx, + ir::ExprKind::Compare(ir::Compare { + head: head_ir, + tail_with_op: ir_tail, + }), + ), + bool_type, + ); + Ok(ir_expr) + } + ast::ExprKind::Set(set) => { + // Set expressions are assignment-like operations (lhs := rhs) + let lhs_ir = self.typeck_expr(session, env, subst, &set.lhs)?; + let rhs_ir = self.typeck_expr(session, env, subst, &set.rhs)?; + + // Unify lhs and rhs types - they should be the same + self.unify(subst, lhs_ir.ty, rhs_ir.ty)?; + + // Create IR Set expression - result is unit type + let unit_type = Ty::mk_unit(self.tcx); + let ir_expr = ir::Expr::new( + ir::ExprMut::set(self.ir_cx, lhs_ir, set.colon_eq.into_token(), rhs_ir), + unit_type, + ); + Ok(ir_expr) + } + ast::ExprKind::InfixImport(infix_import) => { + self.typeck_infix_import(session, infix_import) + } + ast::ExprKind::Call(call) => self.typeck_call(session, env, subst, call), + } + } +} + +#[cfg(test)] +mod tests { + use opslang_module::version::v1::ModuleContext; + + use super::*; + + #[test] + fn test_external_resolve() { + struct Resolver; + impl<'cx> ExternalResolver<'cx> for Resolver { + // A simple resolver that maps all variable to i32 type for testing + fn resolve( + &self, + _path: ast::Path<'cx>, + cx: &'cx TypingContext<'cx>, + ) -> Option> { + Some(Ty::mk_i32(cx)) + } + } + + let tcx = TypingContext::new(); + let ast_cx = ast::context::Context::new(); + let ir_cx = ir::Context::new(); + let module = ModuleContext::new(); + let gcx = GlobalContext { + tcx: &tcx, + module: &module, + }; + let mut type_checker = TypeChecker::new(gcx, &ir_cx); + type_checker.add_external_resolver(Resolver); + let path = ast::Path::single( + &ast_cx, + "ExternalVar", + ast::Span { + start: ast::BytePos(0), + end: ast::BytePos(11), + }, + ); + let resolved_ty = type_checker.try_external_resolve(path); + assert_eq!(resolved_ty, Some(Ty::mk_i32(&tcx))); + + let expr = ast_cx.alloc_expr(ast::ExprKind::Variable(path)); + let mut subst = Substitution::new(); + let env = Scope::new(); + let session = Session::new(); + let session = SecondPassSession::new(&session, module.alloc_root_path("test")); + let ir_expr = type_checker + .typeck_expr(session, &env, &mut subst, &expr) + .unwrap(); + assert_eq!(ir_expr.ty, Ty::mk_external(&tcx, path, Ty::mk_i32(&tcx))); + } +} diff --git a/ty/opslang-typeck/src/version/v1/typeck_function.rs b/ty/opslang-typeck/src/version/v1/typeck_function.rs new file mode 100644 index 0000000..a2a330f --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/typeck_function.rs @@ -0,0 +1,61 @@ +use super::*; + +impl<'cx> TypeChecker<'cx> { + pub(super) fn typeck_function<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + global_env: &Scope<'cx, 'env>, + func_def: &'cx ast::FunctionDef<'cx>, + ) -> Result> { + let func_name = func_def.name; + + // Retrieve the already resolved function type from the environment + let environment::TypedIdent { + id: typed_func_name, + ty: func_type, + } = global_env + .lookup_var(func_name) + .ok_or_else(|| anyhow!("function '{func_name}' not found in environment"))?; + + let TyKind::Function { + arg: param_types, + ret: return_type, + is_procedure: _, + } = func_type.kind() + else { + return Err(anyhow!("expected function type for '{func_name}'")); + }; + + let mut func_env = global_env.extend_inherit(); + + // Convert parameters to IR using the already resolved types + let mut ir_parameters = Vec::new(); + for (param, param_type) in func_def.parameters.iter().zip(param_types) { + let param_id = self.bind(&mut func_env, param.name, *param_type); + + let ir_param = ir::Parameter { + name: param_id, + colon: param.colon.into_token(), + ty: self.resolve_type_from_path(param.ty)?, + }; + ir_parameters.push(ir_param); + } + + // Type check function body and collect substitutions + let mut subst = Substitution::new(); + let mut ir_body = self.typeck_block(session, &func_env, &mut subst, func_def.body)?; + + // Apply final substitution using visitor + hm::SubstitutionVisitor::new(subst, self.tcx).visit_mut(&mut ir_body); + + Ok(ir::FunctionDef { + prc_token: func_def.prc_token.into_token(), + name: typed_func_name, + left_paren: func_def.left_paren.into_token(), + parameters: self.ir_cx.alloc_parameter_slice(ir_parameters), + right_paren: func_def.right_paren.into_token(), + return_type: *return_type, + body: ir_body, + }) + } +} diff --git a/ty/opslang-typeck/src/version/v1/typeck_infix_import.rs b/ty/opslang-typeck/src/version/v1/typeck_infix_import.rs new file mode 100644 index 0000000..9862b8e --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/typeck_infix_import.rs @@ -0,0 +1,120 @@ +// FIXME: implement LSP or something to remove infix import +use super::*; + +impl<'cx> TypeChecker<'cx> { + /// Performs type checking on an expression and converts it to IR. + /// + /// This function infers the type of an expression and converts it to its IR representation. + /// It updates the provided substitution with any new type constraints discovered during checking. + pub(super) fn typeck_infix_import<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + infix_import: &'cx ast::InfixImport<'cx>, + ) -> Result> { + let ast::InfixImport { + file, + question, + path, + } = infix_import; + // InfixImport expressions are like "file ? path" operations + let file_name = if let ast::Literal::String(s) = file { + s.raw + } else { + return Err(anyhow::anyhow!( + "Infix import file must be a string literal" + )); + }; + + let parsed_segments = ParsedSegment::parse_segments(file_name) + .ok_or_else(|| anyhow::anyhow!("Invalid module path in infix import: {file_name}"))?; + + // Determine if this is an absolute or relative path + let (mut module_path, segments) = match parsed_segments.first() { + Some(ParsedSegment::Ident(root_segment)) => { + // Absolute path: starts with an identifier + let root_path = self.gcx.module.alloc_root_path(root_segment); + (root_path, &parsed_segments[1..]) + } + Some(ParsedSegment::Current | ParsedSegment::Super) | None => { + // Relative path: starts with "." or ".." + (session.module_path, &parsed_segments[..]) + } + }; + + for segment in segments { + segment + .rebase_path(&mut module_path, self.gcx.module) + .ok_or_else(|| { + anyhow::anyhow!("Invalid module path in infix import: {file_name}") + })?; + } + + let item_ident = path.is_ident().ok_or_else(|| { + anyhow::anyhow!("Currently single identifier are supported in infix import paths") + })?; + + let typed_ident = session + .get_toplevel_items_of(&module_path) + .and_then(|scope| scope.lookup_var(item_ident)) + .ok_or_else(|| { + anyhow::anyhow!("Could not find item `{item_ident}` in file \"{file_name}\"") + })?; + + // Create IR InfixImport expression + let ir_expr = ir::Expr::new( + ir::ExprMut::import( + self.ir_cx, + module_path, + question.into_token(), + typed_ident.id, + ), + typed_ident.ty, + ); + Ok(ir_expr) + } +} + +#[derive(Clone, Copy)] +enum ParsedSegment<'cx> { + Current, + Super, + Ident(&'cx str), +} + +impl<'cx> ParsedSegment<'cx> { + /// Parses a module path string into its constituent segments. + /// + /// Returns `None` if the path is invalid (contains empty segments). + /// + /// Path classification: + /// - Absolute: starts with an identifier (e.g., "foo/bar", "module") + /// - Relative: starts with "." or ".." (e.g., "./foo", "../bar") + /// - Invalid: empty segments (e.g., "foo//bar", "/foo") + fn parse_segments(path: &'cx str) -> Option> { + let mut segments = Vec::new(); + + for segment in path.split('/') { + match segment { + "" => return None, // Empty segments are not allowed + "." => segments.push(ParsedSegment::Current), + ".." => segments.push(ParsedSegment::Super), + ident => segments.push(ParsedSegment::Ident(ident.trim_end_matches(".ops"))), + } + } + + Some(segments) + } + + fn rebase_path(self, path: &mut ModulePath<'cx>, mcx: &'cx ModuleContext<'cx>) -> Option<()> { + match self { + ParsedSegment::Current => {} + ParsedSegment::Super => { + *path = path.parent?; + } + ParsedSegment::Ident(ident) => { + *path = mcx.alloc_child_path(*path, ident); + } + }; + Some(()) + } +} diff --git a/ty/opslang-typeck/src/version/v1/typeck_literal.rs b/ty/opslang-typeck/src/version/v1/typeck_literal.rs new file mode 100644 index 0000000..370e832 --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/typeck_literal.rs @@ -0,0 +1,209 @@ +use super::*; +use chrono::Duration; +use opslang_ir::version::v1::NumericKind; +use opslang_ty::version::v1::{FloatVid, IntVid}; + +impl<'cx> TypeChecker<'cx> { + pub(super) fn typeck_literal<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + scope: &Scope<'cx, 'env>, + subst: &mut Substitution<'cx>, + literal: &'cx ast::Literal<'cx>, + ) -> Result<(ir::Literal<'cx>, Ty<'cx>)> { + match literal { + ast::Literal::String(s) => { + let ir_string = ir::String { + value: self.ir_cx.alloc_str(&s.unescape()?), + ast: s, + }; + let ir_literal = ir::Literal::String(ir_string); + let string_type = Ty::mk_string(self.tcx); + Ok((ir_literal, string_type)) + } + ast::Literal::Numeric(numeric) => { + let mut kind = NumericKind::Repr(numeric.raw); + // Check if there's a suffix and resolve it + let ty = if let Some(suffix) = &numeric.suffix { + self.resolve_numeric_suffix(suffix, &mut kind, numeric.raw)? + } else { + match &numeric.kind { + ast::literal::NumericKind::Integer(_prefix) => { + Ty::mk_int_var(self.tcx, IntVid::fresh()) + } + ast::literal::NumericKind::Float => { + Ty::mk_float_var(self.tcx, FloatVid::fresh()) + } + } + }; + + let ir_numeric = ir::Numeric { kind, ast: numeric }; + let ir_literal = ir::Literal::Numeric(ir_numeric); + Ok((ir_literal, ty)) + } + ast::Literal::Array(array) => { + if array.exprs.is_empty() { + // Empty array - use a type variable for the element type + let element_type = Ty::mk_variable(self.tcx, TyVid::fresh()); + let array_type = Ty::mk_array(self.tcx, element_type); + + let ir_array = ir::Array { + left_bracket: array.left_bracket.into_token(), + exprs: Vec::new(), + right_bracket: array.right_bracket.into_token(), + }; + let ir_literal = ir::Literal::Array(ir_array); + Ok((ir_literal, array_type)) + } else { + // Non-empty array - type check all elements + let mut ir_exprs = Vec::new(); + + // Type check first element to establish the element type + let first_ir = self.typeck_expr(session, scope, subst, &array.exprs[0])?; + + let ty = first_ir.ty; + ir_exprs.push(first_ir); + let element_type = ty; + + // Type check remaining elements and unify with element type + for expr in &array.exprs[1..] { + let expr_ir = self.typeck_expr(session, scope, subst, expr)?; + + self.unify(subst, element_type, expr_ir.ty)?; + + ir_exprs.push(expr_ir); + } + + let array_type = Ty::mk_array(self.tcx, element_type); + let ir_array = ast::Literal::array( + array.left_bracket.into_token(), + ir_exprs, + array.right_bracket.into_token(), + ); + Ok((ir_array, array_type)) + } + } + ast::Literal::Bytes(bytes) => { + let byte_data = self.ir_cx.alloc_bytes(bytes.as_bytes()); + let ir_bytes = ir::Bytes { + value: byte_data, + ast: bytes, + }; + let ir_literal = ast::Literal::Bytes(ir_bytes); + let bytes_type = Ty::mk_bytes(self.tcx); + Ok((ir_literal, bytes_type)) + } + ast::Literal::HexBytes(hex_bytes) => { + let byte_data = self.ir_cx.alloc_bytes( + &hex_bytes + .as_bytes() + .map_err(|c| anyhow!("illegal hex charactor: {c}"))?, + ); + let ir_hex_bytes = ir::HexBytes { + value: byte_data, + ast: hex_bytes, + }; + let ir_literal = ast::Literal::HexBytes(ir_hex_bytes); + let hex_bytes_type = Ty::mk_bytes(self.tcx); + Ok((ir_literal, hex_bytes_type)) + } + ast::Literal::DateTime(dt) => { + // Parse the raw datetime string to chrono::DateTime + let parsed_datetime = match dt.raw.parse::>() { + Ok(datetime) => datetime, + Err(_) => { + return Err(anyhow!("failed to parse datetime literal: {}", dt.raw)); + } + }; + + let ir_datetime = ir::DateTime { + value: parsed_datetime, + ast: dt, + }; + let ir_literal = ast::Literal::DateTime(ir_datetime); + let time_type = Ty::mk_time(self.tcx); + Ok((ir_literal, time_type)) + } + } + } + + /// Resolves a numeric suffix to the corresponding type and numeric kind. + /// + /// This function takes a numeric suffix (like "i32", "u64", "f32") and returns + /// the corresponding type and numeric representation for IR generation. + fn resolve_numeric_suffix( + &mut self, + suffix: &ast::literal::NumericSuffix<'cx>, + kind: &mut NumericKind<'cx>, + repr: &'cx str, + ) -> Result> { + let suffix = suffix.0.raw; + Ok(match suffix { + "i8" => Ty::mk_i8(self.tcx), + "i16" => Ty::mk_i16(self.tcx), + "i32" => Ty::mk_i32(self.tcx), + "i64" => Ty::mk_i64(self.tcx), + + "u8" => Ty::mk_u8(self.tcx), + "u16" => Ty::mk_u16(self.tcx), + "u32" => Ty::mk_u32(self.tcx), + "u64" => Ty::mk_u64(self.tcx), + + "f32" => Ty::mk_f32(self.tcx), + "f64" => Ty::mk_f64(self.tcx), + + "f" => Ty::mk_float_var(self.tcx, FloatVid::fresh()), + + "s" => { + *kind = NumericKind::Duration(Duration::seconds(repr.parse()?)); + Ty::mk_duration(self.tcx) + } + "ms" => { + *kind = NumericKind::Duration(Duration::milliseconds(repr.parse()?)); + Ty::mk_duration(self.tcx) + } + "us" => { + *kind = NumericKind::Duration(Duration::microseconds(repr.parse()?)); + Ty::mk_duration(self.tcx) + } + "ns" => { + *kind = NumericKind::Duration(Duration::nanoseconds(repr.parse()?)); + Ty::mk_duration(self.tcx) + } + + suffix => Err(anyhow!("unknown suffix: {suffix}"))?, + }) + } +} + +pub(super) fn parse_literal<'cx>(unparsed: &'cx str, ty: Ty<'cx>) -> Result> { + use opslang_ty::version::{FloatTy, IntTy, UintTy}; + match ty.kind() { + TyKind::Int(int_ty) => { + let int = match int_ty { + IntTy::I8 => unparsed.parse::()? as i64, + IntTy::I16 => unparsed.parse::()? as i64, + IntTy::I32 => unparsed.parse::()? as i64, + IntTy::I64 => unparsed.parse::()?, + }; + Ok(ir::NumericKind::Int(int)) + } + TyKind::Uint(uint_ty) => { + let uint = match uint_ty { + UintTy::U8 => unparsed.parse::()? as u64, + UintTy::U16 => unparsed.parse::()? as u64, + UintTy::U32 => unparsed.parse::()? as u64, + UintTy::U64 => unparsed.parse::()?, + }; + Ok(ir::NumericKind::Uint(uint)) + } + TyKind::Float(float_ty) => { + let float = match float_ty { + FloatTy::F32 => unparsed.parse::()?.to_bits() as u64, + FloatTy::F64 => unparsed.parse::()?.to_bits(), + }; + Ok(ir::NumericKind::Float(float)) + } + ty => Err(anyhow!("unexpected literal type `{ty}` to be parsed",)), + } +} diff --git a/ty/opslang-typeck/src/version/v1/typeck_path.rs b/ty/opslang-typeck/src/version/v1/typeck_path.rs new file mode 100644 index 0000000..66a0edc --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/typeck_path.rs @@ -0,0 +1,54 @@ +use super::*; + +impl<'cx> TypeChecker<'cx> { + /// Type checks a path expression, resolving it to a variable or module item. + pub(super) fn typeck_path<'env>( + &mut self, + env: &Scope<'cx, 'env>, + path: &'cx ast::Path<'cx>, + ) -> Result<(ir::ResolvedPath<'cx>, Ty<'cx>)> { + // First check if this is a single identifier that can be resolved in local environment + if let Some(ident) = path.is_ident() + && let Some(environment::TypedIdent { id, ty }) = env.lookup_var(ident) + { + let resolved_path = ir::ResolvedPath { + item: ir::ResolvedItem::LocalVariable(id), + original_path: path, + }; + + return Ok((resolved_path, ty)); + } + + // Fall back to module resolution + if let Ok(ResolvePathResult { + resolved_path, + item, + }) = self.resolve_path(path) + { + match &*item { + ModuleItemDef::Constant { ty, .. } | ModuleItemDef::Prc { ty, .. } => { + return Ok((resolved_path, *ty)); + } + ModuleItemDef::LibraryFn { ty: poly_ty, .. } => { + // Instantiate polymorphic type with fresh type variables + let instantiated_ty = poly_ty.instantiate(self.tcx); + return Ok((resolved_path, instantiated_ty)); + } + _ => {} + } + } + + // Try external resolver if available + if let Some(ty) = self.try_external_resolve(*path) { + let resolved_path = ir::ResolvedPath { + item: ir::ResolvedItem::External, + original_path: path, + }; + let wrapped_ty = Ty::mk_external(self.tcx, *path, ty); + return Ok((resolved_path, wrapped_ty)); + } + + // Not found + Err(anyhow!("unbound variable: {path}")) + } +} diff --git a/ty/opslang-typeck/src/version/v1/typeck_statement.rs b/ty/opslang-typeck/src/version/v1/typeck_statement.rs new file mode 100644 index 0000000..c7be0e2 --- /dev/null +++ b/ty/opslang-typeck/src/version/v1/typeck_statement.rs @@ -0,0 +1,38 @@ +use super::*; + +impl<'cx> TypeChecker<'cx> { + pub(super) fn typeck_statement<'env>( + &mut self, + session: SecondPassSession<'cx, 'env>, + env: &mut Scope<'cx, 'env>, + subst: &mut Substitution<'cx>, + stmt: &ast::Statement<'cx>, + ) -> Result> { + match stmt { + ast::Statement::Let(let_stmt) => { + let ir_rhs = self.typeck_expr(session, env, subst, &let_stmt.rhs)?; + + // Bind the variable to the environment with the inferred type + let var_name = let_stmt.variable; + let var_identifier_id = self.bind(env, var_name, ir_rhs.ty); + + Ok(ir::Statement::Let(ir::Let { + let_token: let_stmt.let_token.into_token(), + variable: var_identifier_id, + eq: let_stmt.eq.into_token(), + rhs: ir_rhs, + semi: let_stmt.semi.into_token(), + })) + } + ast::Statement::Expr(expr_stmt) => { + let ir_expr = self.typeck_expr(session, env, subst, &expr_stmt.expr)?; + + Ok(ir::Statement::Expr(ir::ExprStatement { + expr: ir_expr, + semi: expr_stmt.semi.into_token(), + })) + } + ast::Statement::Return(ret_stmt) => Ok(ir::Statement::Return(ret_stmt.into_token())), + } + } +} diff --git a/ty/opslang-typeck/tests/parser_typeck_integration.rs b/ty/opslang-typeck/tests/parser_typeck_integration.rs new file mode 100644 index 0000000..133ad2c --- /dev/null +++ b/ty/opslang-typeck/tests/parser_typeck_integration.rs @@ -0,0 +1,444 @@ +//! Integration tests for parser and type checker +//! These tests parse source code and perform type checking end-to-end + +use std::fmt::Debug; + +use opslang_ast::syntax::v1 as ast; +use opslang_ir::version::v1 as ir; +use opslang_module::version::v1::ModuleContext; +use opslang_parser::{ParseOps, ParserInput}; +use opslang_ty::version::v1::TypingContext; +use opslang_typeck::{ + v1_setup_cx, + version::v1::{TypeChecker, context::GlobalContext, create_builtin_module}, +}; + +/// Helper function to parse source code into AST. +fn parse_source<'cx>( + source: &'cx str, + context: &'cx ast::context::Context<'cx>, +) -> Result, impl Debug> { + let input = ParserInput { + content: source, + file_name: "test.ops".into(), + }; + opslang_ast::v1::Program::parse(input, context) +} + +/// Helper function to create type checker with builtin types. +fn create_type_checker<'cx>( + gcx: GlobalContext<'cx>, + ir_cx: &'cx ir::context::Context<'cx>, +) -> TypeChecker<'cx> { + let mut checker = TypeChecker::new(gcx, ir_cx); + checker.add_module(create_builtin_module(gcx)); + checker +} + +fn parse_typeck_success(source: &'static str) { + v1_setup_cx!(ast_context, ir_context, gcx = { typing_context, module_context, }); + + let program = parse_source(source, &ast_context).expect("Failed to parse source"); + let mut checker = create_type_checker(gcx, &ir_context); + let root_path = module_context.alloc_root_path("test"); + let result = checker.typeck_single_program(&program, root_path); + + assert!(result.is_ok(), "Type checking failed: {:?}", result.err()); +} + +#[test] +fn test_simple_function_typeck() { + let source = r#"#! lang=v1 +prc main() { + let x = 42; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_function_with_parameters() { + let source = r#"#! lang=v1 +prc add(x: i32, y: i32) -> i32 { + let result = x + y; + return; +} +"#; + + v1_setup_cx!(ast_context, ir_context, gcx = { typing_context, module_context, }); + + let program = parse_source(source, &ast_context).expect("Failed to parse source"); + let mut checker = create_type_checker(gcx, &ir_context); + let root_path = module_context.alloc_root_path("test"); + let result = checker.typeck_single_program(&program, root_path); + + assert!(result.is_ok(), "Type checking failed: {:?}", result.err()); + + if let Ok(ir_program) = result { + // Verify we got some IR output + assert!(!ir_program.toplevel_items.is_empty()); + } +} + +#[test] +fn test_constant_definition() { + let source = r#"#! lang=v1 +const VALUE: i32 = 100; +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_multiple_functions() { + let source = r#"#! lang=v1 +prc main() { + let x = 10; + return; +} + +prc helper(value: i32) -> i32 { + let doubled = value + value; + return; +} +"#; + + v1_setup_cx!(ast_context, ir_context, gcx = { typing_context, module_context, }); + + let program = parse_source(source, &ast_context).expect("Failed to parse source"); + let mut checker = create_type_checker(gcx, &ir_context); + let root_path = module_context.alloc_root_path("test"); + let result = checker.typeck_single_program(&program, root_path); + + assert!(result.is_ok(), "Type checking failed: {:?}", result.err()); + + if let Ok(ir_program) = result { + assert_eq!(ir_program.toplevel_items.len(), 2); + } +} + +#[test] +fn test_builtin_types() { + let source = r#"#! lang=v1 +const INT_VAL: i32 = 42; +const FLOAT_VAL: f64 = 3.14; +const STRING_VAL: string = "hello"; +"#; + + v1_setup_cx!(ast_context, ir_context, gcx = { typing_context, module_context, }); + + let program = parse_source(source, &ast_context).expect("Failed to parse source"); + let mut checker = create_type_checker(gcx, &ir_context); + let root_path = module_context.alloc_root_path("test"); + let result = checker.typeck_single_program(&program, root_path); + + assert!(result.is_ok(), "Type checking failed: {:?}", result.err()); + + if let Ok(ir_program) = result { + assert_eq!( + ir_program.toplevel_items.len(), + 3, + "{:?}", + ir_program.toplevel_items + ); + } +} + +#[test] +fn test_array_literal() { + let source = r#"#! lang=v1 +prc main() { + let numbers = [1, 2, 3]; + let empty_array = []; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_binary_operations() { + let source = r#"#! lang=v1 +prc main() { + let x = 10; + let y = 20; + let sum = x + y; + let diff = x - y; + let product = x * y; + let quotient = x / y; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_if_expression() { + let source = r#"#! lang=v1 +prc main() { + let x = 10; + if x > 5 { + let y = 20; + }; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_unbound_variable_error() { + let source = r#"#! lang=v1 +prc main() { + let x = unknown_variable; + return; +} +"#; + + v1_setup_cx!(ast_context, ir_context, gcx = { typing_context, module_context, }); + + let program = parse_source(source, &ast_context).expect("Failed to parse source"); + let mut checker = create_type_checker(gcx, &ir_context); + let root_path = module_context.alloc_root_path("test"); + let result = checker.typeck_single_program(&program, root_path); + + // This should fail due to unbound variable + assert!( + result.is_err(), + "Expected type checking to fail but it succeeded" + ); +} + +#[test] +fn test_same_scope_shadowing_should_work() { + let source = r#"#! lang=v1 +prc main() { + let x = 42; + let x = 100; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_nested_scope_shadowing_should_work() { + let source = r#"#! lang=v1 +prc main() { + let x = 42; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_parameter_shadowing_should_work() { + let source = r#"#! lang=v1 +prc test_func(x: i32) { + let x = 100; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_multiple_functions_same_variable_names_should_work() { + let source = r#"#! lang=v1 +prc func1() { + let x = 42; + return; +} + +prc func2() { + let x = 100; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_integer_literals_with_suffixes() { + let source = r#"#! lang=v1 +prc main() { + let i8_val = 42i8; + let i16_val = 1000i16; + let i32_val = 50000i32; + let i64_val = 1234567890i64; + + let u8_val = 255u8; + let u16_val = 65535u16; + let u32_val = 4294967295u32; + let u64_val = 18446744073709551615u64; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_float_literals_with_suffixes() { + let source = r#"#! lang=v1 +prc main() { + let f32_val = 3.14f32; + let f64_val = 2.71828f64; + let float_var = 1.0f; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_duration_literals() { + let source = r#"#! lang=v1 +prc main() { + let seconds = 30s; + let milliseconds = 500ms; + let microseconds = 1000us; + let nanoseconds = 123456ns; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_numeric_literals_in_expressions() { + let source = r#"#! lang=v1 +prc main() { + let sum = 10i32 + 20i32; + let float_calc = 3.14f64 * 2.0f64; + let time_sum = 1s + 500ms; + let mixed = 42; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_numeric_literals_type_inference() { + let source = r#"#! lang=v1 +prc main() { + let inferred_int = 42; + let inferred_float = 3.14; + let explicit_int = 100i32; + let explicit_float = 2.71f64; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_as_cast() { + let source = r#"#! lang=v1 +prc main() { + let int_64 = 42; + let int_32 = int_64 as i32; + let float_64 = int_32 as f64; + let bool_val = 1 as bool; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_wait_select() { + let source = r#"#! lang=v1 +prc main() { + wait 1s; + select { + 1s => { + let x = 42; + } + 500ms => { + let y = 100; + } + }; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_assert() { + let source = r#"#! lang=v1 +prc main() { + assert true; + assert (1 + 1 == 2); + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_assert_eq() { + let source = r#"#! lang=v1 +prc main() { + assert_eq true false; + assert_eq 1 1; + assert_eq 3.14 3.14; + assert_eq "hello" "hello"; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_print() { + let source = r#"#! lang=v1 +prc main() { + print "Hello, World!"; + print 42; + print 3.14; + print true; + print 1s; + return; +} +"#; + + parse_typeck_success(source); +} + +#[test] +fn test_prc_call() { + let source = r#"#! lang=v1 +prc f() { + return; +} + +prc main() { + call f; + call "test"?main; # import itself from same file + return; +} +"#; + + parse_typeck_success(source); +}