From f9611182f3f4a94f8feae961f7d653d022f1817d Mon Sep 17 00:00:00 2001
From: Neotamandua <107320179+Neotamandua@users.noreply.github.com>
Date: Sun, 9 Aug 2026 21:09:56 +0200
Subject: [PATCH] Make crate dependency-free
- Update README
---
Cargo.lock | 58 ----------------
Cargo.toml | 3 -
README.md | 32 ++++++---
src/error.rs | 187 +++++++++++++++++++++++++++++----------------------
4 files changed, 129 insertions(+), 151 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 26e6472..07fcab0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5,61 +5,3 @@ version = 4
[[package]]
name = "Sub-OCaml"
version = "0.1.0"
-dependencies = [
- "thiserror",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.91"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "thiserror"
-version = "2.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "2.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
diff --git a/Cargo.toml b/Cargo.toml
index aa98a2c..da9bd5c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,6 +4,3 @@ version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-thiserror = "2.0"
diff --git a/README.md b/README.md
index b4a239d..ad860c9 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,32 @@
+
+
# Sub-OCaml
-[](https://www.rust-lang.org/)
-[](https://github.com/Neotamandua/Sub-OCaml/blob/master/LICENSE)
-
-
> Interpreter for a subset of the OCaml language. \
> This project did not intend to use idiomatic rust code. I mainly explored the syntactical possibilites of matches, recursion etc. for rust.
+
+
+
+
+
+
+
+
+
+
+
+
+
## Usage
+
You can use the [REPL](https://github.com/Neotamandua/Sub-OCaml-REPL/) to directly execute code and try it out
-### Dependencies:
+### Dependencies
-```toml
-[dependencies]
-thiserror = "2.0"
-```
+This project has no external dependencies.
-### Features:
+### Features
| Features | Status |
| -------- | --------------- |
@@ -27,7 +36,8 @@ thiserror = "2.0"
| Evaluator | ✅ |
-### Examples:
+### Examples
+
**1**
```ocaml
let x = 5 in x
diff --git a/src/error.rs b/src/error.rs
index 778aed7..4cfc9cd 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -2,94 +2,123 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-use thiserror::Error;
+use std::{error, fmt};
// std result alias
pub type Result = std::result::Result;
-#[derive(Debug, Error)]
-pub enum Error {
- #[error("{0}")]
- LexerError(#[from] LexerError),
- #[error("{0}")]
- ParserError(#[from] ParserError),
- #[error("{0}")]
- TypeCheckError(#[from] TypeCheckError),
- #[error("{0}")]
- EvaluatorError(#[from] EvaluatorError),
- #[error("{0}")]
- UtilsError(#[from] UtilsError),
-}
+macro_rules! error_enums {
+ ($($name:ident { $($variant:ident $(($field:ident: $ty:ty))? => $message:literal),* $(,)? })*) => {
+ #[derive(Debug)]
+ pub enum Error { $($name($name)),* }
-#[derive(Debug, Error)]
-pub enum LexerError {
- #[error(
- "Lexer Error: '<' is forbidden in Identifiers, Keywords and Variables (Syntax Error). \n
- Additional information: No LT (<=) supported yet"
- )]
- ForbiddenCharLEQ,
- #[error("Lexer Error: no valid Character found")]
- ForbiddenChar,
- #[error("Lexer Error: Comment started but does not end")]
- CommentError,
- #[error("Lexer Error: Identifiers are not allowed to start with a number")]
- IdentifierError,
- #[error("Lexer Error: unexpected EOF")]
- EOFError,
- #[error("Lexer Error (take_while): No Matches for Identifier")]
- NoMatches,
-}
+ impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self { $(Self::$name(error) => fmt::Display::fmt(error, f)),* }
+ }
+ }
-#[derive(Debug, Error)]
-pub enum ParserError {
- #[error("Parser Error: Type Error")]
- TypeError,
- #[error("Parser Error: pexp parse error \n {0}")]
- PexpError(String),
- #[error("Verify failed: No token")]
- NoToken,
- #[error("Verify failed: wrong token")]
- WrongToken,
-}
+ impl error::Error for Error {
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match self { $(Self::$name(error) => Some(error)),* }
+ }
+ }
+
+ $(
+ impl From<$name> for Error {
+ fn from(error: $name) -> Self { Self::$name(error) }
+ }
-#[derive(Debug, Error)]
-pub enum TypeCheckError {
- #[error("Typecheck Error: operator application failed because of ill-typed arguments")]
- ArgumentError,
- #[error("Typecheck Error: function application failed because of wrong argument type")]
- WrongArgument,
- #[error(
- "Typecheck Error: function application failed because function was expected but none given"
- )]
- MissingFunction,
- #[error("Typecheck Error: variable {0} is unbound")]
- UnboundVariable(String),
- #[error("Typecheck Error: types for branch cases (if-case, else-case) are not equal")]
- UnequalIfTypes,
- #[error("Typecheck Error: bool expected for if but got {0}")]
- WrongIfType(String),
- #[error("Typecheck Error: fun has missing type")]
- MissingFunctionType,
- #[error("Typecheck Error: missing types for let rec")]
- MissingType,
- #[error("Typecheck Error: declared type of let rec not matched")]
- NoTypeMatch,
+ #[derive(Debug)]
+ pub enum $name { $($variant $(($ty))?),* }
+
+ impl fmt::Display for $name {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ $(Self::$variant $(($field))? => write!(f, $message $(, $field)?)),*
+ }
+ }
+ }
+
+ impl error::Error for $name {}
+ )*
+ };
}
-#[derive(Debug, Error)]
-pub enum EvaluatorError {
- #[error("Evaluate Error: operator application failed because of ill-typed arguments")]
- ArgumentError,
- #[error(
- "Evaluate Error: function application failed because function was expected but none given"
- )]
- MissingFunction,
- #[error("Evaluate Error: bool expected for if but got {0}")]
- WrongIfType(String),
+error_enums! {
+ LexerError {
+ ForbiddenCharLEQ => "Lexer Error: '<' is forbidden in Identifiers, Keywords and Variables (Syntax Error). \n \n Additional information: No LT (<=) supported yet",
+ ForbiddenChar => "Lexer Error: no valid Character found",
+ CommentError => "Lexer Error: Comment started but does not end",
+ IdentifierError => "Lexer Error: Identifiers are not allowed to start with a number",
+ EOFError => "Lexer Error: unexpected EOF",
+ NoMatches => "Lexer Error (take_while): No Matches for Identifier",
+ }
+ ParserError {
+ TypeError => "Parser Error: Type Error",
+ PexpError(context: String) => "Parser Error: pexp parse error \n {}",
+ NoToken => "Verify failed: No token",
+ WrongToken => "Verify failed: wrong token",
+ }
+ TypeCheckError {
+ ArgumentError => "Typecheck Error: operator application failed because of ill-typed arguments",
+ WrongArgument => "Typecheck Error: function application failed because of wrong argument type",
+ MissingFunction => "Typecheck Error: function application failed because function was expected but none given",
+ UnboundVariable(variable: String) => "Typecheck Error: variable {} is unbound",
+ UnequalIfTypes => "Typecheck Error: types for branch cases (if-case, else-case) are not equal",
+ WrongIfType(ty: String) => "Typecheck Error: bool expected for if but got {}",
+ MissingFunctionType => "Typecheck Error: fun has missing type",
+ MissingType => "Typecheck Error: missing types for let rec",
+ NoTypeMatch => "Typecheck Error: declared type of let rec not matched",
+ }
+ EvaluatorError {
+ ArgumentError => "Evaluate Error: operator application failed because of ill-typed arguments",
+ MissingFunction => "Evaluate Error: function application failed because function was expected but none given",
+ WrongIfType(ty: String) => "Evaluate Error: bool expected for if but got {}",
+ }
+ UtilsError {
+ OutOfBounds => "EOF, out of bounds",
+ }
}
-#[derive(Debug, Error)]
-pub enum UtilsError {
- #[error("EOF, out of bounds")]
- OutOfBounds,
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::error::Error as _;
+
+ #[test]
+ fn displays_errors() {
+ assert_eq!(
+ LexerError::ForbiddenCharLEQ.to_string(),
+ "Lexer Error: '<' is forbidden in Identifiers, Keywords and Variables (Syntax Error). \n \n Additional information: No LT (<=) supported yet"
+ );
+ assert_eq!(
+ LexerError::ForbiddenChar.to_string(),
+ "Lexer Error: no valid Character found"
+ );
+ assert_eq!(
+ ParserError::PexpError("context".into()).to_string(),
+ "Parser Error: pexp parse error \n context"
+ );
+ assert_eq!(
+ TypeCheckError::UnboundVariable("x".into()).to_string(),
+ "Typecheck Error: variable x is unbound"
+ );
+ assert_eq!(
+ EvaluatorError::WrongIfType("int".into()).to_string(),
+ "Evaluate Error: bool expected for if but got int"
+ );
+ assert_eq!(UtilsError::OutOfBounds.to_string(), "EOF, out of bounds");
+ }
+
+ #[test]
+ fn wraps_error_sources() {
+ let error: Error = ParserError::WrongToken.into();
+ assert_eq!(error.to_string(), "Verify failed: wrong token");
+ assert_eq!(
+ error.source().unwrap().to_string(),
+ "Verify failed: wrong token"
+ );
+ assert!(error.source().unwrap().source().is_none());
+ }
}