Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,28 @@ No changelog available.
1. IR target.
1. Runtime flags.
### Fixed
1. Full issue coverage now.
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.

## v9 -- Semantic-driven disambiguation
### Added
1. Functions.
1. Ambiguity resolution for function calls and implicit multiplication based on context.
### Changed
1. Definitions now are done with `:=` instead of `==` and `=` always produces equations.
### Removed
1. Old declaration constructs.
1. Locking mechanics.
### Fixed
1. CLI behaviour under stress.
Comment on lines +210 to +234
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix markdown formatting: missing blank lines around headings and missing trailing newline.

Come on, the rest of the changelog is formatted properly — don't drop the ball on the new sections. Static analysis flagged numerous MD022 violations (headings need blank lines above and below) and a missing trailing newline (MD047).

📝 Proposed formatting fix
 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.
+
 ## v9 -- Semantic-driven disambiguation
+
 ### Added
 1. Functions.
 1. Ambiguity resolution for function calls and implicit multiplication based on context.
+
 ### Changed
 1. Definitions now are done with `:=` instead of `==` and `=` always produces equations.
+
 ### Removed
 1. Old declaration constructs.
 1. Locking mechanics.
+
 ### Fixed
 1. CLI behaviour under stress.
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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.
## v9 -- Semantic-driven disambiguation
### Added
1. Functions.
1. Ambiguity resolution for function calls and implicit multiplication based on context.
### Changed
1. Definitions now are done with `:=` instead of `==` and `=` always produces equations.
### Removed
1. Old declaration constructs.
1. Locking mechanics.
### Fixed
1. CLI behaviour under stress.
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.
## v9 -- Semantic-driven disambiguation
### Added
1. Functions.
1. Ambiguity resolution for function calls and implicit multiplication based on context.
### Changed
1. Definitions now are done with `:=` instead of `==` and `=` always produces equations.
### Removed
1. Old declaration constructs.
1. Locking mechanics.
### Fixed
1. CLI behaviour under stress.
🧰 Tools
🪛 LanguageTool

[style] ~234-~234: ‘under stress’ might be wordy. Consider a shorter alternative.
Context: ...g mechanics. ### Fixed 1. CLI behaviour under stress.

(EN_WORDINESS_PREMIUM_UNDER_STRESS)

🪛 markdownlint-cli2 (0.21.0)

[warning] 212-212: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 213-213: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


[warning] 213-213: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 216-216: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


[warning] 216-216: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 219-219: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


[warning] 219-219: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 221-221: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


[warning] 221-221: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 224-224: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 225-225: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


[warning] 225-225: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 228-228: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


[warning] 228-228: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 230-230: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


[warning] 230-230: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 233-233: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above

(MD022, blanks-around-headings)


[warning] 233-233: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 234-234: Files should end with a single newline character

(MD047, single-trailing-newline)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/CHANGELOG.md around lines 210 - 234, Add blank lines above and below
each markdown heading in the new sections (e.g., "## v8 -- Semantic solver",
"### Added", "### Changed", "### Removed", "### Fixed", and the "## v9 --
Semantic-driven disambiguation" block and its subheadings) so they conform to
MD022, and ensure the file ends with a single trailing newline to satisfy MD047;
update the section blocks and list spacing accordingly while preserving existing
text content and numbering.

2 changes: 1 addition & 1 deletion .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Mathsys can be tried out at the [online playground](https://abscissa.eu/playgrou

### Local installation

Install the latest version via `pip`:
Install the latest version via `cargo`:

```sh
cargo install mathsys
Expand Down
6 changes: 2 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@

#> IGNORE -> FOLDER INFO
**/.DS_Store
.DS_Store
Comment on lines 9 to +10
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Redundant .DS_Store entry.

Line 9 (**/.DS_Store) already covers the root directory. The explicit .DS_Store on line 10 is unnecessary.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.gitignore around lines 9 - 10, Remove the redundant `.DS_Store` pattern
from the .gitignore: keep the recursive glob pattern `**/.DS_Store` and delete
the explicit `.DS_Store` line so the single entry covers both root and nested
`.DS_Store` files.


#> IGNORE -> SYMLINK
mathsys

#> IGNORE -> TEST FILE
file.msm
mathsys
14 changes: 11 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,19 @@
"backgroundColor": "transparent",
"bold": false,
"italic": true
}
},
{
"tag": "!",
"color": "#00FF00",
"strikethrough": false,
"underline": false,
"backgroundColor": "#FF00FF",
"bold": true,
"italic": false
},
Comment on lines +40 to +48
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

That color combo is going to melt someone's retinas, bud.

#00FF00 (pure neon green) on #FF00FF (pure magenta) is about as subtle as a foghorn. It technically works, but it's going to be visually aggressive for anything longer than a glance. Consider toning down either the foreground or background — e.g., a softer green like #39FF14 on a dark/transparent background, or keeping the magenta background but using a dark foreground for contrast.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.vscode/settings.json around lines 40 - 48, The current color pair uses
color "#00FF00" and backgroundColor "#FF00FF" which is visually harsh; update
the object with a less aggressive combination by either changing "color" to a
softer green like "#39FF14" or switching "color" to a dark foreground such as
"#1A1A1A" while keeping "backgroundColor" as the magenta, or alternatively tone
down "backgroundColor" to a darker/translucent magenta; modify the keys "color"
and/or "backgroundColor" in the object where "tag": "!" is defined to implement
one of these options.

],
"rust-analyzer.inlayHints.genericParameterHints.const.enable": false,
"rust-analyzer.inlayHints.parameterHints.enable": false,
"rust-analyzer.inlayHints.typeHints.enable": false,
"rust-analyzer.inlayHints.renderColons": false,
"python.analysis.ignore": [".venv/**"]
"rust-analyzer.inlayHints.renderColons": false
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Heads up — dropping python.analysis.ignore for .venv/** will hurt you.

The AI summary notes that "python.analysis.ignore": [".venv/**"] was removed. Without it, Pylance now crawls your entire virtual environment on every analysis pass. You'll get a flood of false-positive errors and warnings from third-party package internals polluting the Problems panel. Put it back.

🛠️ Restore the ignore setting
     "python.analysis.diagnosticMode": "workspace",
+    "python.analysis.ignore": [".venv/**"],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.vscode/settings.json at line 53, The removal of the
"python.analysis.ignore" setting causes Pylance to analyze the entire .venv and
produce noise; restore the JSON entry "python.analysis.ignore": [".venv/**"] in
the .vscode/settings.json so the analyzer ignores the virtual environment
directory (ensure the key name is exact and the pattern ".venv/**" is present
under the root settings object).

}
9 changes: 8 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
[package]
name = "mathsys"
version = "7.0.0"
version = "9.0.0"
edition = "2024"
authors = ["Alejandro Vaz <alejandro.vaz.myt@gmail.com>"]
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"
Expand All @@ -25,5 +30,6 @@ indexmap = "2.13.0"
ahash = "0.8.12"
smallvec = "1.15.1"
rustc_version_runtime = "0.3.0"
strum = "0.27.2"
strum_macros = "0.27.2"
enum_dispatch = "0.3.13"
5 changes: 4 additions & 1 deletion backends/latex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

//> HEAD -> PRELUDE
use crate::prelude::{
LazyLock, Regex, Map, Captures
LazyLock,
Regex,
Map,
Captures
};


Expand Down
74 changes: 74 additions & 0 deletions backends/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//^
//^ HEAD
//^

//> HEAD -> MODULES
pub(super) mod latex;

//> HEAD -> PRELUDE
use crate::prelude::{
dispatch
};

//> HEAD -> LOCAL
use self::super::{
solver::{
nonterminal::{
Item,
NonTerminal
},
context::Context
},
syntax::{
Start,
level1::{
Definition,
Function,
Level1,
Node,
Equation,
Use
},
level2::{
Level2,
Expression
},
level3::{
Level3,
Term
},
level4::{
Limit,
Level4,
Factor
},
level5::{
Absolute,
Level5,
Infinite,
Variable,
Nest,
Tensor,
Whole,
Undefined,
Rational,
Call
}
}
};
Comment on lines +14 to +58
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

fd -t f "mod.rs" backends/ --exec wc -l {} \;

Repository: alejandro-vaz/mathsys

Length of output: 83


🏁 Script executed:

cat -n backends/mod.rs

Repository: alejandro-vaz/mathsys

Length of output: 1779


🏁 Script executed:

# Check if syntax types are used in the backends module
rg "Start|Definition|Function|Level1|Node|Equation|Use|Level2|Expression|Level3|Term|Level4|Limit|Factor|Level5|Absolute|Infinite|Variable|Nest|Tensor|Whole|Undefined|Rational|Call" backends/ -t rust --no-filename -n

Repository: alejandro-vaz/mathsys

Length of output: 962


🏁 Script executed:

# Check what's in the latex module
cat -n backends/latex.rs | head -100

Repository: alejandro-vaz/mathsys

Length of output: 3158


Remove unused syntax imports from backends/mod.rs.

Your imports of Start, Definition, Function, Level1, Node, Equation, Use, Level2, Expression, Level3, Term, Level4, Limit, Factor, Level5, Absolute, Infinite, Variable, Nest, Tensor, Whole, Undefined, Rational, and Call aren't used anywhere in this file. Not in the trait definitions, not in the latex module—nowhere. Even the #[dispatch] macro doesn't pull these in. Clean it up and keep only what you actually use: Item, NonTerminal, and Context.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backends/mod.rs` around lines 14 - 58, Remove the unused syntax imports from
the large use block and keep only the actual symbols in use: Item, NonTerminal
and Context; specifically, update the use self::super::{ solver::{
nonterminal::{ Item, NonTerminal }, context::Context } } import pattern and
delete all the unused syntax imports (Start, Definition, Function, Level1, Node,
Equation, Use, Level2, Expression, Level3, Term, Level4, Limit, Factor, Level5,
Absolute, Infinite, Variable, Nest, Tensor, Whole, Undefined, Rational, Call) so
the module only imports Item, NonTerminal and Context.



//^
//^ TRAITS
//^

//> TRAITS -> SPAWN
pub(super) trait Spawn: Backends {
fn spawn(items: Vec<Item>, context: Option<&mut Context>) -> NonTerminal;
}
Comment on lines +66 to +68
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Spawn: Backends supertrait couples construction to rendering.

Every type that can be spawned must also implement Backends (i.e., latex()). This is fine today with a single backend, but if you ever want to construct syntax nodes without rendering (e.g., analysis passes, optimization), this coupling will get in your way. Consider whether the supertrait bound is intentional or if Spawn should be independent.

Not blocking — just making sure you've thought about it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backends/mod.rs` around lines 66 - 68, The Spawn trait currently requires
Backends via "trait Spawn: Backends", coupling construction to rendering; remove
the supertrait so Spawn is independent (change to "pub(super) trait Spawn { ...
}") and move any Backends requirement to impl sites or the spawn method
signature as needed (e.g., impl<T: Backends> Spawn for T or add a where Self:
Backends on specific impls) so types can be constructed without forcing a global
Backends bound; update all impl blocks and callers of Spawn::spawn (and any uses
of latex()) to include Backends bounds only where rendering is actually
required.


//> BACKENDS -> TRAIT
#[dispatch]
pub(super) trait Backends {
fn latex(&self) -> String;
}
36 changes: 0 additions & 36 deletions backends/traits.rs

This file was deleted.

53 changes: 36 additions & 17 deletions entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

//> HEAD -> PRELUDE
use crate::prelude::{
FilePath, readFile, writeFile
FilePath,
readFile,
writeFile,
EnumString,
AsRefStr
};

//> HEAD -> LOCAL
Expand All @@ -29,32 +33,47 @@ pub enum Argument {
//^

//> INPUT -> FILE
#[derive(Clone, Debug)]
pub struct File {
pub name: FilePath
} impl File {
pub fn read(&self) -> Result<String, Issue> {readFile(&self.name).ok().ok_or_else(|| Issue::FileNotFound(self.name.to_str().unwrap().to_string()))}
pub async fn write(&self, extension: &str, content: String) -> () {
let mut path = self.name.clone();
#[derive(Clone)]
pub struct File (pub FilePath); impl File {
pub fn read(&self) -> Result<String, Issue> {readFile(&self.0).ok().ok_or_else(|| Issue::FileNotFound(self.0.to_str().unwrap().to_string()))}
pub fn write(&self, extension: &str, content: String) -> () {
let mut path = self.0.clone();
path.set_extension(extension);
writeFile(path, content).unwrap();
}
}
Comment on lines +36 to 44
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Tuple struct conversion is fine, but File::read hides the actual I/O error.

readFile(&self.0).ok() silently discards the io::Error. When a file exists but can't be read (permissions, encoding, etc.), the user gets a generic "File not found" message, which is misleading. Consider preserving or logging the underlying error.

Also, self.0.to_str().unwrap() on line 38 will panic on non-UTF-8 paths. Unlikely on most systems, but something to be aware of.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@entry.rs` around lines 36 - 44, The File::read implementation swallows the
underlying I/O error and uses to_str().unwrap(), causing misleading "File not
found" errors and potential panics; update File::read (and the Issue variant
usage) to capture the Result from readFile(&self.0) and map Err to an Issue that
preserves the original io::Error (or its display) instead of calling .ok(), and
replace self.0.to_str().unwrap() with a non-panicking conversion such as
self.0.to_string_lossy() when constructing Issue::FileNotFound so path and
actual error details are included in the returned Result; locate the logic in
File::read, the call to readFile, and the creation of Issue::FileNotFound to
make this change.


//> INPUT -> FLAG
#[derive(Clone, Debug)]
pub struct Flag {
pub value: String
#[derive(EnumString, Clone, Copy, AsRefStr)]
#[strum(serialize_all = "lowercase")]
pub enum Flag {
Quiet,
Verbose
}

//> INPUT -> ALIAS
#[derive(Clone, Debug)]
pub struct Alias {
pub letters: Vec<char>
}
pub struct Alias(pub Vec<char>); impl Alias {pub fn expand(self) -> Result<Vec<Flag>, Issue> {
let mut converted = Vec::new();
for letter in &self.0 {converted.push(match letter {
'q' => Flag::Quiet,
'v' => Flag::Verbose,
other => return Err(Issue::UnknownAliasCharacter {
alias: self,
at: converted.len()
})
})}
return Ok(converted);
}}
Comment on lines 55 to +67
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Alias char-to-flag mapping duplicates knowledge from FLAGLIASES in issues.rs.

Right now you have 'q' => Flag::Quiet and 'v' => Flag::Verbose hardcoded here, and separately in issues.rs lines 148–151 you have ('q', Flag::Quiet, ...) and ('v', Flag::Verbose, ...). If you ever add a flag, you'll need to update both. That's a maintenance trap.

Consider driving the expansion from a single source of truth — either FLAGLIASES or a shared const — so adding a flag means touching one place only.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@entry.rs` around lines 55 - 67, The Alias::expand implementation duplicates
the q/v mapping; instead drive expansion from the single source FLAGLIASES (or a
shared public const) so mappings live in one place: remove the hardcoded match
in Alias::expand and lookup each char against FLAGLIASES (or call a new public
helper in issues.rs that maps a char -> Option<Flag>), push the resulting Flag
into converted or return Issue::UnknownAliasCharacter (preserving alias and at)
when no mapping exists; reference Alias::expand, FLAGLIASES, and
Issue::UnknownAliasCharacter to locate the code to change.


//> INPUT -> TARGET
#[derive(Clone, Debug)]
pub struct Target {
pub name: String
#[derive(EnumString, Clone, AsRefStr, Copy)]
#[strum(serialize_all = "lowercase")]
pub enum Target {
Help,
Version,
Tokens,
Check,
Ast,
Latex
}
7 changes: 0 additions & 7 deletions file.msm

This file was deleted.

Loading