From 4b17cb1779edbdee909dbfd17e70f62326b62b95 Mon Sep 17 00:00:00 2001 From: alejandro-vaz Date: Sun, 15 Feb 2026 15:55:53 +0100 Subject: [PATCH 1/2] going to implement better resolution --- .gitignore | 4 ++-- file.msm | 9 ++------- main.rs | 9 ++++++--- syntax/level1.rs | 20 ++++++++++++++++++-- syntax/start.rs | 7 ++++++- tokenizer/tokenizer.rs | 2 +- 6 files changed, 35 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index b2f3fdf..b9cd7fa 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,5 @@ #> IGNORE -> SYMLINK mathsys -#> IGNORE -> TEST FILE -file.msm \ No newline at end of file +#> IGNORE -> TEST FILES +*.msm \ No newline at end of file diff --git a/file.msm b/file.msm index 336a159..cfec054 100644 --- a/file.msm +++ b/file.msm @@ -1,7 +1,2 @@ -x = 2 + 3*7/4 - -e == lim n->inf of (1 + 1/n)^n^ - -pi = 3.14159 - -L = |alpha - 4| +use "mynext.msm" +x = 2 diff --git a/main.rs b/main.rs index a2e61a6..1818444 100644 --- a/main.rs +++ b/main.rs @@ -100,7 +100,8 @@ pub fn check(transformers: &mut Transformers) -> Result<(), Issue> { let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; let pool = transformers.parser.run(&tokens, &transformers.settings); - let start = transformers.solver.run(&pool)?; + let mut start = transformers.solver.run(&pool)?; + start.modules(&mut transformers.tokenizer, &mut transformers.parser, &mut transformers.solver, &transformers.settings)?; return Ok(()); } @@ -109,7 +110,8 @@ pub fn ast(transformers: &mut Transformers) -> Result { let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; let pool = transformers.parser.run(&tokens, &transformers.settings); - let start = transformers.solver.run(&pool)?; + let mut start = transformers.solver.run(&pool)?; + start.modules(&mut transformers.tokenizer, &mut transformers.parser, &mut transformers.solver, &transformers.settings)?; return Ok(start); } @@ -118,7 +120,8 @@ pub fn latex(transformers: &mut Transformers) -> Result { let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; let pool = transformers.parser.run(&tokens, &transformers.settings); - let start = transformers.solver.run(&pool)?; + let mut start = transformers.solver.run(&pool)?; + start.modules(&mut transformers.tokenizer, &mut transformers.parser, &mut transformers.solver, &transformers.settings)?; return Ok(start.latex()); } diff --git a/syntax/level1.rs b/syntax/level1.rs index 56637db..f8aea52 100644 --- a/syntax/level1.rs +++ b/syntax/level1.rs @@ -13,8 +13,14 @@ use super::{ level2::Level2, level5::{Variable, Level5}, super::{ + issues::Issue, + Settings, + tokenizer::tokenizer::Tokenizer, + parser::parser::Parser, + solver::solver::Solver, backends::traits::{Backends, Spawn}, - solver::nonterminal::{NonTerminal, Item} + solver::nonterminal::{NonTerminal, Item}, + entry::File } }; @@ -118,7 +124,17 @@ pub struct Use { } } impl Spawn for Use {fn summon(items: Vec) -> NonTerminal { return NonTerminal::Level1(Level1::Use(Self { - module: if let Item::Token(token) = items.into_iter().next().unwrap() {token.value.to_string()} else {panic!()}, + module: if let Item::Token(token) = items.into_iter().next().unwrap() {token.value.trim_matches('\"').to_string()} else {panic!()}, start: None })); +}} impl Use {pub fn load(&mut self, tokenizer: &mut Tokenizer, parser: &mut Parser, solver: &mut Solver, settings: &Settings) -> Result<(), Issue> { + let Ok(content) = File { + name: self.module.clone().into() + }.read() else {return Ok(())}; + let tokens = tokenizer.run(&content, settings)?; + let pool = parser.run(&tokens, settings); + let mut start = solver.run(&pool)?; + start.modules(tokenizer, parser, solver, settings)?; + self.start = Some(start); + return Ok(()); }} \ No newline at end of file diff --git a/syntax/start.rs b/syntax/start.rs index 7be0d06..6e8bd5b 100644 --- a/syntax/start.rs +++ b/syntax/start.rs @@ -6,6 +6,11 @@ use super::{ level1::Level1, super::{ + issues::Issue, + tokenizer::tokenizer::Tokenizer, + parser::parser::Parser, + Settings, + solver::solver::Solver, backends::traits::{Spawn, Backends}, solver::nonterminal::{Item, NonTerminal} } @@ -31,4 +36,4 @@ pub struct Start { } } impl Spawn for Start {fn summon(items: Vec) -> NonTerminal {return NonTerminal::Start(Self { stream: items.into_iter().map(|element| if let Item::NonTerminal(NonTerminal::Level1(level1)) = element {level1} else {panic!("{element:?}")}).collect() -})}} \ No newline at end of file +})}} impl Start {pub fn modules(&mut self, tokenizer: &mut Tokenizer, parser: &mut Parser, solver: &mut Solver, settings: &Settings) -> Result<(), Issue> {return Ok(for statement in &mut self.stream {if let Level1::Use(element) = statement {element.load(tokenizer, parser, solver, settings)?}})}} \ No newline at end of file diff --git a/tokenizer/tokenizer.rs b/tokenizer/tokenizer.rs index 9b0ecaf..164ac95 100644 --- a/tokenizer/tokenizer.rs +++ b/tokenizer/tokenizer.rs @@ -106,7 +106,7 @@ pub static ORDER: LazyLock> = LazyLock:: (Kind::EXIT, (Regex::new(r#"^\]"#).unwrap(), Responsibility::Structural)), (Kind::SPACES, (Regex::new("^ +").unwrap(), Responsibility::Structural)), (Kind::NEWLINES, (Regex::new(r#"^\n+"#).unwrap(), Responsibility::Structural)), - (Kind::MODULE, (Regex::new(r#"^"[a-z]+""#).unwrap(), Responsibility::Total)), + (Kind::MODULE, (Regex::new(r#"^"[a-z]+\.msm""#).unwrap(), Responsibility::Total)), (Kind::COMMENT, (Regex::new(r"^\#[^\n]*").unwrap(), Responsibility::Null)), (Kind::ENDOFFILE, (Regex::new("^$").unwrap(), Responsibility::Structural)) ].into_iter().collect()}); From e1569dd4c050653e413e64d399989845db870f35 Mon Sep 17 00:00:00 2001 From: alejandro-vaz Date: Sun, 15 Feb 2026 19:16:27 +0100 Subject: [PATCH 2/2] update finished --- .github/CHANGELOG.md | 14 ++- Cargo.lock | 2 +- Cargo.toml | 7 +- file.msm | 152 +++++++++++++++++++++++++++++- lib.rs | 206 +++++++++++++++++++++++++++++++++++++++++ main.rs | 209 +++--------------------------------------- solver/nonterminal.rs | 4 - solver/solver.rs | 95 ++++++++++--------- syntax/level1.rs | 18 ++-- syntax/level2.rs | 2 +- syntax/level3.rs | 4 +- syntax/level4.rs | 14 +-- syntax/level5.rs | 12 +-- syntax/start.rs | 2 +- 14 files changed, 469 insertions(+), 272 deletions(-) create mode 100644 lib.rs diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 7c49201..9453d77 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -207,4 +207,16 @@ No changelog available. 1. IR target. 1. Runtime flags. ### Fixed -1. Full issue coverage now. \ No newline at end of file +1. Full issue coverage now. + +## v8 -- Semantic solver +### Added +1. Local module importing from filesystem. +1. Added `README.md` in `Cargo.toml`. +### Changed +1. Contextual semantic solver replaced old heuristic solver. +1. Improved filetree and directories. +### Removed +1. Old numerical solver. +### Fixed +1. Imported modules now must have `.msm` file extension. \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index cb6b8de..934ab1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,7 +99,7 @@ checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "mathsys" -version = "7.0.0" +version = "8.0.0" dependencies = [ "ahash", "colored", diff --git a/Cargo.toml b/Cargo.toml index 9838954..83cb499 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "mathsys" -version = "7.0.0" +version = "8.0.0" edition = "2024" authors = ["Alejandro Vaz "] description = "The Natural Language of Math." license = "MIT" repository = "https://github.com/alejandro-vaz/mathsys" +readme = ".github/README.md" + +[lib] +name = "mathsys" +path = "lib.rs" [[bin]] name = "mathsys" diff --git a/file.msm b/file.msm index cfec054..1e1e707 100644 --- a/file.msm +++ b/file.msm @@ -1,2 +1,150 @@ -use "mynext.msm" -x = 2 +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ +e = lim n-> inf of (1 + 1/n)^n^ \ No newline at end of file diff --git a/lib.rs b/lib.rs new file mode 100644 index 0000000..7b71508 --- /dev/null +++ b/lib.rs @@ -0,0 +1,206 @@ +//^ +//^ HEAD +//^ + +//> HEAD -> FLAGS +#![allow(unused_variables)] +#![allow(nonstandard_style)] +#![feature(try_trait_v2)] +#![feature(default_field_values)] +#![feature(if_let_guard)] + +//> HEAD -> MODULES +pub mod prelude; +pub mod issues; +pub mod entry; +pub mod tokenizer { + pub mod tokenizer; +} +pub mod parser { + pub mod grammar; + pub mod parser; +} +pub mod solver { + pub mod nonterminal; + pub mod solver; +} +pub mod syntax { + pub mod level1; + pub mod level2; + pub mod level3; + pub mod level4; + pub mod level5; + pub mod start; +} +pub mod backends { + pub mod latex; + pub mod traits; +} + +//> HEAD -> PRELUDE +use self::prelude::{ + Time +}; + +//> HEAD -> LOCAL +use self::{ + syntax::start::Start, + tokenizer::tokenizer::{ShallowToken, Tokenizer}, + parser::parser::Parser, + solver::solver::Solver, + backends::traits::Backends, + issues::Issue, + entry::{Argument, File, Flag, Target} +}; + +//> HEAD -> VERSION +pub static VERSION: usize = 8; + + +//^ +//^ PIPELINE +//^ + +//> PIPELINE -> TRANSFORMERS +pub struct Transformers { + tokenizer: Tokenizer, + parser: Parser, + solver: Solver, + pub settings: Settings, + pub time: Time +} impl Transformers {pub fn new(arguments: &[Argument]) -> Result {return Ok(Transformers { + tokenizer: Tokenizer::new(), + parser: Parser::new(), + solver: Solver::new(), + settings: Settings::set(arguments)?, + time: Time::now() +})}} + +//> PIPELINE -> HELP +pub fn help(transformers: &mut Transformers) -> Result<(), Issue> {return Err(Issue::GetHelp)} + +//> PIPELINE -> VERSION +pub fn version(transformers: &mut Transformers) -> Result {return Ok(VERSION)} + +//> PIPELINE -> TOKENS +pub fn tokens(transformers: &mut Transformers) -> Result, Issue> { + let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; + let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; + return Ok(tokens.into_iter().map(|token| token.fixate()).collect()); +} + +//> PIPELINE -> LENGTH +pub fn length(transformers: &mut Transformers) -> Result { + let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; + let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; + return Ok(tokens.len()); +} + +//> PIPELINE -> CHECK +pub fn check(transformers: &mut Transformers) -> Result<(), Issue> { + let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; + let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; + let pool = transformers.parser.run(&tokens, &transformers.settings); + let mut start = transformers.solver.run(&pool)?; + start.modules(&mut transformers.tokenizer, &mut transformers.parser, &mut transformers.solver, &transformers.settings)?; + return Ok(()); +} + +//> PIPELINE -> AST +pub fn ast(transformers: &mut Transformers) -> Result { + let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; + let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; + let pool = transformers.parser.run(&tokens, &transformers.settings); + let mut start = transformers.solver.run(&pool)?; + start.modules(&mut transformers.tokenizer, &mut transformers.parser, &mut transformers.solver, &transformers.settings)?; + return Ok(start); +} + +//> PIPELINE -> LATEX +pub fn latex(transformers: &mut Transformers) -> Result { + let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; + let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; + let pool = transformers.parser.run(&tokens, &transformers.settings); + let mut start = transformers.solver.run(&pool)?; + start.modules(&mut transformers.tokenizer, &mut transformers.parser, &mut transformers.solver, &transformers.settings)?; + return Ok(start.latex()); +} + + +//^ +//^ TARGETS +//^ + +//> TARGETS -> NOISE +pub enum Noise { + Debug, + Verbose, + Normal, + Quiet, + Zero +} impl Noise { + pub fn change(&mut self, shift: bool) -> () {*self = match self { + Noise::Debug => if shift {Noise::Debug} else {Noise::Verbose}, + Noise::Normal => if shift {Noise::Verbose} else {Noise::Quiet}, + Noise::Quiet => if shift {Noise::Normal} else {Noise::Zero}, + Noise::Verbose => if shift {Noise::Debug} else {Noise::Normal}, + Noise::Zero => if shift {Noise::Quiet} else {Noise::Zero} + }} + pub fn verbose(&self) -> bool {match self { + Noise::Debug | Noise::Verbose => true, + other => false + }} + pub fn quiet(&self) -> bool {match self { + Noise::Quiet | Noise::Zero => true, + other => false + }} + pub fn debug(&self) -> bool {if let Noise::Debug = self {true} else {false}} + pub fn zero(&self) -> bool {if let Noise::Zero = self {true} else {false}} +} + +//> TARGETS -> SETTINGS +pub struct Settings { + file: Option = None, + pub target: Option = None, + pub noise: Noise = Noise::Normal +} impl Settings { + pub fn set(arguments: &[Argument]) -> Result { + let mut settings = Settings {..}; + for argument in arguments {settings.apply(argument)?} + return Ok(settings); + } + pub fn apply(&mut self, argument: &Argument) -> Result<(), Issue> {return Ok(match argument { + Argument::Alias(alias) => for (index, letter) in alias.letters.iter().enumerate() {if let Some((character, aliasing)) = FLAGLIASES.iter().find_map(|(key, second, third)| if key == letter {Some((key, second))} else {None}) { + self.apply(&Argument::Flag(Flag {value: aliasing.to_string()}))?; + } else {return Err(Issue::UnknownAliasCharacter { + alias: alias.clone(), + at: index + })}} + Argument::File(file) => if self.file.is_none() {self.file = Some(file.clone())}, + Argument::Flag(flag) => match &flag.value.to_lowercase() as &str { + name if name == FLAGLIASES[0].1 => return Err(Issue::GetHelp), + name if name == FLAGLIASES[1].1 => self.noise.change(false), + name if name == FLAGLIASES[2].1 => self.noise.change(true), + other => return Err(Issue::UnknownFlag(flag.clone())) + }, + Argument::Target(target) => if self.target.is_none() {self.target = Some(target.clone())} + })} +} + +//> TARGETS -> LIST +pub static TARGETS: [(&'static str, &'static str); 7] = [ + ("help", "show this informative menu"), + ("version", "check current Mathsys version"), + ("tokens", "tokenize the input file"), + ("length", "show length of token stream"), + ("check", "validate the semantics"), + ("ast", "build the abstract syntax tree"), + ("latex", "show the latex program equivalency") +]; + +//> TARGETS -> FLAGS AND ALIASES +pub static FLAGLIASES: [(char, &'static str, &'static str); 3] = [ + ('h', "help", "show help menu"), + ('q', "quiet", "silence the output"), + ('v', "verbose", "increase program verbosity") +]; \ No newline at end of file diff --git a/main.rs b/main.rs index 1818444..2519b9c 100644 --- a/main.rs +++ b/main.rs @@ -5,187 +5,24 @@ //> HEAD -> FLAGS #![allow(unused_variables)] #![allow(nonstandard_style)] -#![feature(try_trait_v2)] -#![feature(default_field_values)] - -//> HEAD -> MODULES -mod prelude; -mod issues; -mod entry; -mod tokenizer { - pub mod tokenizer; -} -mod parser { - pub mod grammar; - pub mod parser; -} -mod solver { - pub mod nonterminal; - pub mod solver; -} -mod syntax { - pub mod level1; - pub mod level2; - pub mod level3; - pub mod level4; - pub mod level5; - pub mod start; -} -mod backends { - pub mod latex; - pub mod traits; -} - -//> HEAD -> PRELUDE -use crate::prelude::{ - ARCH, OS, Time, rustcv, getArguments -}; //> HEAD -> LOCAL -use self::{ - syntax::start::Start, - tokenizer::tokenizer::{ShallowToken, Tokenizer, MAXLEN}, - parser::parser::Parser, - solver::solver::Solver, - backends::traits::Backends, +use mathsys::{ + TARGETS, + help, + version, + Transformers, + prelude::{ARCH, OS, rustcv, getArguments}, + tokenizer::tokenizer::MAXLEN, issues::Issue, - entry::{Argument, File, Flag, Target, Alias} + entry::{Argument, File, Flag, Target, Alias}, + tokens, + length, + check, + ast, + latex }; -//> HEAD -> VERSION -pub static VERSION: usize = 7; - - -//^ -//^ PIPELINE -//^ - -//> PIPELINE -> TRANSFORMERS -pub struct Transformers { - tokenizer: Tokenizer, - parser: Parser, - solver: Solver, - settings: Settings, - time: Time -} impl Transformers {pub fn new(arguments: &[Argument]) -> Result {return Ok(Transformers { - tokenizer: Tokenizer::new(), - parser: Parser::new(), - solver: Solver::new(), - settings: Settings::set(arguments)?, - time: Time::now() -})}} - -//> PIPELINE -> HELP -pub fn help(transformers: &mut Transformers) -> Result<(), Issue> {return Err(Issue::GetHelp)} - -//> PIPELINE -> VERSION -pub fn version(transformers: &mut Transformers) -> Result {return Ok(VERSION)} - -//> PIPELINE -> TOKENS -pub fn tokens(transformers: &mut Transformers) -> Result, Issue> { - let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; - let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; - return Ok(tokens.into_iter().map(|token| token.fixate()).collect()); -} - -//> PIPELINE -> LENGTH -pub fn length(transformers: &mut Transformers) -> Result { - let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; - let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; - return Ok(tokens.len()); -} - -//> PIPELINE -> CHECK -pub fn check(transformers: &mut Transformers) -> Result<(), Issue> { - let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; - let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; - let pool = transformers.parser.run(&tokens, &transformers.settings); - let mut start = transformers.solver.run(&pool)?; - start.modules(&mut transformers.tokenizer, &mut transformers.parser, &mut transformers.solver, &transformers.settings)?; - return Ok(()); -} - -//> PIPELINE -> AST -pub fn ast(transformers: &mut Transformers) -> Result { - let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; - let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; - let pool = transformers.parser.run(&tokens, &transformers.settings); - let mut start = transformers.solver.run(&pool)?; - start.modules(&mut transformers.tokenizer, &mut transformers.parser, &mut transformers.solver, &transformers.settings)?; - return Ok(start); -} - -//> PIPELINE -> LATEX -pub fn latex(transformers: &mut Transformers) -> Result { - let content = transformers.settings.file.as_ref().ok_or(Issue::MissingFile)?.read()?; - let tokens = transformers.tokenizer.run(&content, &transformers.settings)?; - let pool = transformers.parser.run(&tokens, &transformers.settings); - let mut start = transformers.solver.run(&pool)?; - start.modules(&mut transformers.tokenizer, &mut transformers.parser, &mut transformers.solver, &transformers.settings)?; - return Ok(start.latex()); -} - - -//^ -//^ TARGETS -//^ - -//> TARGETS -> NOISE -enum Noise { - Debug, - Verbose, - Normal, - Quiet, - Zero -} impl Noise { - fn change(&mut self, shift: bool) -> () {*self = match self { - Noise::Debug => if shift {Noise::Debug} else {Noise::Verbose}, - Noise::Normal => if shift {Noise::Verbose} else {Noise::Quiet}, - Noise::Quiet => if shift {Noise::Normal} else {Noise::Zero}, - Noise::Verbose => if shift {Noise::Debug} else {Noise::Normal}, - Noise::Zero => if shift {Noise::Quiet} else {Noise::Zero} - }} - fn verbose(&self) -> bool {match self { - Noise::Debug | Noise::Verbose => true, - other => false - }} - fn quiet(&self) -> bool {match self { - Noise::Quiet | Noise::Zero => true, - other => false - }} - fn debug(&self) -> bool {if let Noise::Debug = self {true} else {false}} - fn zero(&self) -> bool {if let Noise::Zero = self {true} else {false}} -} - -//> TARGETS -> SETTINGS -pub struct Settings { - file: Option = None, - target: Option = None, - noise: Noise = Noise::Normal -} impl Settings { - pub fn set(arguments: &[Argument]) -> Result { - let mut settings = Settings {..}; - for argument in arguments {settings.apply(argument)?} - return Ok(settings); - } - pub fn apply(&mut self, argument: &Argument) -> Result<(), Issue> {return Ok(match argument { - Argument::Alias(alias) => for (index, letter) in alias.letters.iter().enumerate() {if let Some((character, aliasing)) = FLAGLIASES.iter().find_map(|(key, second, third)| if key == letter {Some((key, second))} else {None}) { - self.apply(&Argument::Flag(Flag {value: aliasing.to_string()}))?; - } else {return Err(Issue::UnknownAliasCharacter { - alias: alias.clone(), - at: index - })}} - Argument::File(file) => if self.file.is_none() {self.file = Some(file.clone())}, - Argument::Flag(flag) => match &flag.value.to_lowercase() as &str { - name if name == FLAGLIASES[0].1 => return Err(Issue::GetHelp), - name if name == FLAGLIASES[1].1 => self.noise.change(false), - name if name == FLAGLIASES[2].1 => self.noise.change(true), - other => return Err(Issue::UnknownFlag(flag.clone())) - }, - Argument::Target(target) => if self.target.is_none() {self.target = Some(target.clone())} - })} -} - //> TARGETS -> WRAPPER pub fn main() -> Result<(), Issue> { let mut transformers = Transformers::new(&getArguments().skip(1).map(|argument| match &argument { @@ -214,22 +51,4 @@ pub fn main() -> Result<(), Issue> { }; if transformers.settings.noise.verbose() {println!("Execution time: {:?}", transformers.time.elapsed())} return Ok(()); -} - -//> TARGETS -> LIST -pub static TARGETS: [(&'static str, &'static str); 7] = [ - ("help", "show this informative menu"), - ("version", "check current Mathsys version"), - ("tokens", "tokenize the input file"), - ("length", "show length of token stream"), - ("check", "validate the semantics"), - ("ast", "build the abstract syntax tree"), - ("latex", "show the latex program equivalency") -]; - -//> TARGETS -> FLAGS AND ALIASES -pub static FLAGLIASES: [(char, &'static str, &'static str); 3] = [ - ('h', "help", "show help menu"), - ('q', "quiet", "silence the output"), - ('v', "verbose", "increase program verbosity") -]; \ No newline at end of file +} \ No newline at end of file diff --git a/solver/nonterminal.rs b/solver/nonterminal.rs index 7f2de36..a919de7 100644 --- a/solver/nonterminal.rs +++ b/solver/nonterminal.rs @@ -84,10 +84,6 @@ pub enum Object { Object::Undefined => Undefined::summon(items), Object::Rational => Rational::summon(items) }} - pub fn score(&self) -> usize {return match self { - Object::Declaration => 1, - other => 0 - }} } diff --git a/solver/solver.rs b/solver/solver.rs index 0814159..44762ec 100644 --- a/solver/solver.rs +++ b/solver/solver.rs @@ -14,7 +14,10 @@ use super::{ issues::Issue, tokenizer::tokenizer::{ORDER, Responsibility}, parser::parser::{Backpointer, MINPOINTERS, Part}, - syntax::start::Start + syntax::{ + start::Start, + level1::Level1 + } } }; @@ -24,51 +27,59 @@ use super::{ //^ //> SOLVER -> STRUCT -pub struct Solver {} impl Solver { - pub fn new() -> Self {return Solver {}} - pub fn run<'resolving>(&self, pool: &FastMap, FastSet; MINPOINTERS]>>>) -> Result { - let mut memory = FastMap::new(); - let Partition::NonTerminal(NonTerminal::Start(start)) = self.best(pool, pool.iter().map(|item| item.0).find(|backpointer| if let Part::NonTerminal(Object::Start) = backpointer.symbol {true} else {false}).ok_or(Issue::SyntaxError)?, &mut memory).1.ok_or(Issue::SyntaxError)? else {return Err(Issue::SyntaxError)}; +pub struct Solver { + opposite: bool = false +} impl Solver { + pub fn new() -> Self {return Solver {..}} + pub fn run<'resolving>(&mut self, pool: &FastMap, FastSet; MINPOINTERS]>>>) -> Result { + let Partition::NonTerminal(NonTerminal::Start(start)) = self.select(pool, pool.iter().map(|item| item.0).find(|backpointer| if let Part::NonTerminal(Object::Start) = backpointer.symbol {true} else {false}).ok_or(Issue::SyntaxError)?) else {return Err(Issue::SyntaxError)}; return Ok(start); } - fn best<'resolving, 'active>(&self, pool: &'active FastMap, FastSet; MINPOINTERS]>>>, node: &'active Backpointer<'resolving>, memory: &mut FastMap, (usize, Option>)>) -> (usize, Option>) { - if let Some(result) = memory.get(node) {return result.clone()}; - if let Part::Token(token) = node.symbol.clone() { - let result = (0, Some(Partition::Token(token))); - memory.insert(node.clone(), result.clone()); - return result; - }; - let mut bcore = 0; - let mut btree = None; - if let Some(derivations) = pool.get(node) { - for derivation in derivations { - let mut score = match node.symbol.clone() { - Part::NonTerminal(object) => object.score(), - Part::Internal(code) => 0, - other => unreachable!() - }; - let mut children = Vec::new(); - for child in derivation { - let (ccore, ctree) = self.best(pool, child, memory); - score += ccore; - if let Some(tree) = ctree {match tree { - Partition::Internal(items) => children.extend(items), - Partition::NonTerminal(item) => children.push(Item::NonTerminal(item)), - Partition::Token(token) => if let Responsibility::Total = ORDER.get(&token.kind).unwrap().1 {children.push(Item::Token(token))}, - }}; - } - if score > bcore || btree.is_none() { - bcore = score; - btree = Some(match node.symbol.clone() { - Part::NonTerminal(object) => Partition::NonTerminal(object.summon(children)), - Part::Internal(code) => Partition::Internal(children), - other => unreachable!() - }); + fn select<'resolving, 'active>(&mut self, pool: &'active FastMap, FastSet; MINPOINTERS]>>>, node: &'active Backpointer<'resolving>) -> Partition<'resolving> { + return if let Part::Token(token) = &node.symbol {Partition::Token(token.clone())} else { + let mut candidates = pool.get(node).unwrap().clone().into_iter().collect::; MINPOINTERS]>>>(); + let mut index = 0; + while candidates.len() > 1 { + candidates.retain(|derivation| derivation.get(index).is_some()); + if candidates.len() <= 1 {break}; + let mut symbols = Vec::new() as Vec<&Backpointer>; + for derivation in &candidates { + let pointer = &derivation[index]; + if !symbols.iter().any(|thing| *thing == pointer) {symbols.push(pointer)} } + let built = symbols.into_iter().map(|symbol| (symbol, self.select(pool, symbol))).collect::)>>(); + let mut winner = &built[0]; + for contender in built.iter().skip(1) { + let Partition::NonTerminal(first) = &winner.1 else {continue}; + let Partition::NonTerminal(second) = &contender.1 else {continue}; + if self.resolve(first, second) {winner = contender} + }; + let end = winner.0.clone(); + candidates.retain(|derivation| derivation[index] == end); + index += 1; + } + let derivation = candidates.pop().unwrap(); + let mut children = Vec::new(); + for item in derivation {match self.select(pool, &item) { + Partition::Internal(items) => children.extend(items), + Partition::NonTerminal(item) => children.push(Item::NonTerminal(item)), + Partition::Token(token) if let Responsibility::Total = ORDER.get(&token.kind).unwrap().1 => children.push(Item::Token(token)), + other => continue + }} + match &node.symbol { + Part::NonTerminal(object) => Partition::NonTerminal(object.summon(children)), + Part::Internal(code) => Partition::Internal(children), + other => unreachable!() } }; - let result = (bcore, btree); - memory.insert(node.clone(), result.clone()); - return result; } + fn resolve(&mut self, first: &NonTerminal, second: &NonTerminal) -> bool {return match (first, second) { + (NonTerminal::Level1(Level1::Declaration(declaration)), NonTerminal::Level1(Level1::Equation(equation))) => false, + other => if self.opposite {panic!("{first:?} && {second:?}")} else { + self.opposite = true; + let result = !self.resolve(second, first); + self.opposite = false; + return result; + } + }} } \ No newline at end of file diff --git a/syntax/level1.rs b/syntax/level1.rs index f8aea52..42fd496 100644 --- a/syntax/level1.rs +++ b/syntax/level1.rs @@ -43,8 +43,8 @@ pub enum Level1 { //> 1ºLEVEL -> DECLARATION #[derive(Debug, Clone)] pub struct Declaration { - variable: Variable, - value: Level2 + pub variable: Variable, + pub value: Level2 } impl Backends for Declaration { fn latex(&self) -> String {return format!("{}={}", self.variable.latex(), self.value.latex())} } impl Spawn for Declaration {fn summon(items: Vec) -> NonTerminal { @@ -64,8 +64,8 @@ pub struct Declaration { //> 1ºLEVEL -> DEFINITION #[derive(Debug, Clone)] pub struct Definition { - variable: Variable, - value: Level2 + pub variable: Variable, + pub value: Level2 } impl Backends for Definition { fn latex(&self) -> String {return format!(r"{}\equiv {}", self.variable.latex(), self.value.latex())} } impl Spawn for Definition {fn summon(items: Vec) -> NonTerminal { @@ -85,7 +85,7 @@ pub struct Definition { //> 1ºLEVEL -> NODE #[derive(Debug, Clone)] pub struct Node { - value: Level2 + pub value: Level2 } impl Backends for Node { fn latex(&self) -> String {return self.value.latex()} } impl Spawn for Node {fn summon(items: Vec) -> NonTerminal { @@ -97,8 +97,8 @@ pub struct Node { //> 1ºLEVEL -> EQUATION #[derive(Debug, Clone)] pub struct Equation { - left: Level2, - right: Level2 + pub left: Level2, + pub right: Level2 } impl Backends for Equation { fn latex(&self) -> String {return format!("{}={}", self.left.latex(), self.right.latex())} } impl Spawn for Equation {fn summon(items: Vec) -> NonTerminal { @@ -112,8 +112,8 @@ pub struct Equation { //> 1ºLEVEL -> USE #[derive(Debug, Clone)] pub struct Use { - module: String, - start: Option + pub module: String, + pub start: Option } impl Backends for Use { fn latex(&self) -> String { let (start, end) = match &self.start { diff --git a/syntax/level2.rs b/syntax/level2.rs index b45dcb7..afe5ff8 100644 --- a/syntax/level2.rs +++ b/syntax/level2.rs @@ -31,7 +31,7 @@ pub enum Level2 { //> 2ºLEVEL -> EXPRESSION #[derive(Debug, Clone)] pub struct Expression { - terms: Vec<(Vec, Level3)> + pub terms: Vec<(Vec, Level3)> } impl Backends for Expression { fn latex(&self) -> String {return self.terms.iter().map(|term| term.0.iter().map(|each| if *each {'+'} else {'-'}).collect::() + &term.1.latex()).collect::()} } impl Spawn for Expression {fn summon(items: Vec) -> NonTerminal { diff --git a/syntax/level3.rs b/syntax/level3.rs index 252cb1a..c306106 100644 --- a/syntax/level3.rs +++ b/syntax/level3.rs @@ -31,8 +31,8 @@ pub enum Level3 { //> 3ºLEVEL -> TERM #[derive(Debug, Clone)] pub struct Term { - numerator: Vec, - denominator: Vec + pub numerator: Vec, + pub denominator: Vec } impl Backends for Term { fn latex(&self) -> String { let numerator = self.numerator.iter().map(|factor| factor.latex()).collect::>().join(r"\cdot "); diff --git a/syntax/level4.rs b/syntax/level4.rs index 8468b77..7d69d50 100644 --- a/syntax/level4.rs +++ b/syntax/level4.rs @@ -33,8 +33,8 @@ pub enum Level4 { //> 4ºLEVEL -> FACTOR #[derive(Debug, Clone)] pub struct Factor { - value: Level5, - exponent: Option + pub value: Level5, + pub exponent: Option } impl Backends for Factor { fn latex(&self) -> String { let exponent = if let Some(level2) = &self.exponent {&format!("^{{{}}}", level2.latex())} else {""}; @@ -51,11 +51,11 @@ pub struct Factor { //> 4ºLEVEL -> LIMIT #[derive(Debug, Clone)] pub struct Limit { - variable: Variable, - approach: Level2, - direction: Option, - nest: Nest, - exponent: Option + pub variable: Variable, + pub approach: Level2, + pub direction: Option, + pub nest: Nest, + pub exponent: Option } impl Backends for Limit { fn latex(&self) -> String { let direction = if let Some(value) = self.direction {if value {"+"} else {"-"}} else {""}; diff --git a/syntax/level5.rs b/syntax/level5.rs index ac2d0e1..7e48e18 100644 --- a/syntax/level5.rs +++ b/syntax/level5.rs @@ -47,7 +47,7 @@ pub struct Infinite {} impl Backends for Infinite { //> 5ºLEVEL -> VARIABLE #[derive(Debug, Clone)] pub struct Variable { - name: String + pub name: String } impl Backends for Variable { fn latex(&self) -> String {return augmentVariables(&self.name)} } impl Spawn for Variable {fn summon(items: Vec) -> NonTerminal { @@ -59,7 +59,7 @@ pub struct Variable { //> 5ºLEVEL -> NEST #[derive(Debug, Clone)] pub struct Nest { - value: Option + pub value: Option } impl Backends for Nest { fn latex(&self) -> String { let inside = if let Some(level2) = &self.value {&level2.latex()} else {""}; @@ -74,7 +74,7 @@ pub struct Nest { //> 5ºLEVEL -> TENSOR #[derive(Debug, Clone)] pub struct Tensor { - values: Vec + pub values: Vec } impl Backends for Tensor { fn latex(&self) -> String { let inside = if self.values.len() == 0 {r"\; "} else {&self.values.iter().map(|value| value.latex()).collect::>().join(r"\\ ")}; @@ -89,7 +89,7 @@ pub struct Tensor { //> 5ºLEVEL -> WHOLE #[derive(Debug, Clone)] pub struct Whole { - number: String + pub number: String } impl Backends for Whole { fn latex(&self) -> String {return self.number.clone()} } impl Spawn for Whole {fn summon(items: Vec) -> NonTerminal { @@ -101,7 +101,7 @@ pub struct Whole { //> 5ºLEVEL -> ABSOLUTE #[derive(Debug, Clone)] pub struct Absolute { - value: Level2 + pub value: Level2 } impl Backends for Absolute { fn latex(&self) -> String {return format!(r"\left| {}\right| ", self.value.latex())} } impl Spawn for Absolute {fn summon(items: Vec) -> NonTerminal { @@ -119,7 +119,7 @@ pub struct Undefined {} impl Backends for Undefined { //> 5ºLEVEL -> RATIONAL #[derive(Debug, Clone)] pub struct Rational { - number: String + pub number: String } impl Backends for Rational { fn latex(&self) -> String {return self.number.clone()} } impl Spawn for Rational {fn summon(items: Vec) -> NonTerminal { diff --git a/syntax/start.rs b/syntax/start.rs index 6e8bd5b..61699d2 100644 --- a/syntax/start.rs +++ b/syntax/start.rs @@ -24,7 +24,7 @@ use super::{ //> START -> CLASS #[derive(Debug, Clone)] pub struct Start { - stream: Vec + pub stream: Vec } impl Backends for Start { fn latex(&self) -> String { let (start, end) = match self.stream.len() {