diff --git a/Cargo.lock b/Cargo.lock
index 42119e4..a21e498 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -112,7 +112,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "fplc"
-version = "0.9.512"
+version = "0.9.513"
dependencies = [
"chrono",
"chrono-tz",
diff --git a/Cargo.toml b/Cargo.toml
index 92a92cf..7ce2266 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,7 @@
[package]
name = "fplc"
-version = "0.9.512"
+version = "0.9.513"
edition = "2021"
description = "A pseudolang interpreter written in Rust"
repository = "https://github.com/PseudoLang-Software-Foundation/Pseudolang"
diff --git a/installer/pseudolang.nsi b/installer/pseudolang.nsi
index 89d4e01..8799935 100644
--- a/installer/pseudolang.nsi
+++ b/installer/pseudolang.nsi
@@ -4,7 +4,7 @@
!define MUI_ICON "Pseudolang-Logo.ico"
-Name "PseudoLang Installer v0.9.512"
+Name "PseudoLang Installer v0.9.513"
InstallDir "$PROGRAMFILES\PseudoLang\"
OutFile "../release/installer/pseudolang-setup-x64.exe"
BrandingText "(c) 2024 PseudoLang Software Foundation"
@@ -33,7 +33,7 @@ Section ""
WriteRegStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" "$INSTDIR;$R0"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pseudolang" "DisplayName" "Pseudolang"
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pseudolang" "DisplayVersion" "0.9.512"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pseudolang" "DisplayVersion" "0.9.513"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pseudolang" "Publisher" "Pseudolang Software Foundation"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pseudolang" "DisplayIcon" "$INSTDIR\Pseudolang-Logo.ico"
diff --git a/readme.md b/readme.md
index e906aa0..44c4858 100644
--- a/readme.md
+++ b/readme.md
@@ -9,7 +9,7 @@
@@ -60,7 +60,6 @@ The file `src/tests/mod.rs` also contains various unit tests (examples of code)
Functionality
- [ ] Dictionaries
-- [ ] Evaluation
- [ ] Better error handling (line, column)
- [ ] Networking
- [ ] File IO
diff --git a/src/interpreter.rs b/src/interpreter.rs
index bfc1fac..d9f49ad 100644
--- a/src/interpreter.rs
+++ b/src/interpreter.rs
@@ -1339,6 +1339,19 @@ fn evaluate_node(
}
}
}
+ AstNode::Eval(expr) => {
+ let expr_val = evaluate_node(expr, Rc::clone(&env), debug)?;
+ if let Value::String(s) = expr_val {
+ let mut lexer = crate::lexer::Lexer::new(&s);
+ let tokens = lexer.tokenize();
+ let mut parser = crate::parser::Parser::new(tokens);
+ let ast = parser.parse_expression(debug)?;
+
+ evaluate_node(&ast, Rc::clone(&env), debug)
+ } else {
+ Err("EVAL requires a string argument".to_string())
+ }
+ }
_ => Err(format!("Unimplemented node type: {:?}", node)),
}
}
diff --git a/src/lexer.rs b/src/lexer.rs
index ffabf1a..4587498 100644
--- a/src/lexer.rs
+++ b/src/lexer.rs
@@ -86,6 +86,7 @@ pub enum Token {
Null,
NaN,
+ Eval,
}
pub struct Lexer<'a> {
@@ -432,6 +433,7 @@ impl<'a> Lexer<'a> {
"SORT" => Some(Token::Sort),
"TRY" => Some(Token::Try),
"CATCH" => Some(Token::Catch),
+ "EVAL" => Some(Token::Eval),
_ => Some(Token::Identifier(identifier)),
}
}
diff --git a/src/parser.rs b/src/parser.rs
index f65ede6..3e9e4e6 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -60,6 +60,7 @@ pub enum AstNode {
error_var: Option,
catch_block: Box,
},
+ Eval(Box),
}
#[derive(Debug, Clone)]
@@ -393,7 +394,7 @@ impl Parser {
}
}
- fn parse_expression(&mut self, debug: bool) -> Result {
+ pub fn parse_expression(&mut self, debug: bool) -> Result {
if self.match_token(&Token::Sort) {
if !self.match_token(&Token::OpenParen) {
return Err("Expected '(' after SORT".to_string());
@@ -684,6 +685,17 @@ impl Parser {
}
Ok(AstNode::Input(prompt))
}
+ Some(Token::Eval) => {
+ self.advance();
+ if !self.match_token(&Token::OpenParen) {
+ return Err("Expected '(' after EVAL".to_string());
+ }
+ let expr = self.parse_expression(debug)?;
+ if !self.match_token(&Token::CloseParen) {
+ return Err("Expected ')' after EVAL expression".to_string());
+ }
+ Ok(AstNode::Eval(Box::new(expr)))
+ }
_ => match self.advance() {
Some(Token::Integer(n)) => Ok(AstNode::Integer(n)),
Some(Token::Float(f)) => Ok(AstNode::Float(f)),
diff --git a/src/tests/mod.rs b/src/tests/mod.rs
index 069f750..08a1b80 100644
--- a/src/tests/mod.rs
+++ b/src/tests/mod.rs
@@ -2436,4 +2436,47 @@ DISPLAY(arr)"#,
"NAN",
);
}
+
+ #[test]
+ fn test_eval() {
+ assert_output(r#"DISPLAY(EVAL("1 + 2"))"#, "3");
+ assert_output(r#"DISPLAY(EVAL("2 * (3 + 4)"))"#, "14");
+ assert_output(r#"DISPLAY(EVAL("10 / 2"))"#, "5");
+ assert_output(r#"DISPLAY(EVAL("7 MOD 3"))"#, "1");
+
+ assert_output(
+ r#"
+ x <- 5
+ DISPLAY(EVAL("x * 2"))
+ DISPLAY(EVAL("x * (x + 1)"))
+ "#,
+ "10\n30",
+ );
+
+ assert_output(
+ r#"
+ nums <- [1, 3, 5]
+ DISPLAY(EVAL("nums[1] + nums[2]"))
+ "#,
+ "4",
+ );
+
+ assert_output(
+ r#"
+ x <- 10
+ y <- 20
+ DISPLAY(EVAL("x < y"))
+ DISPLAY(EVAL("x = 10"))
+ DISPLAY(EVAL("(x > 5) AND (y < 30)"))
+ "#,
+ "true\ntrue\ntrue",
+ );
+
+ assert_output(r#"DISPLAY(EVAL("1.5 + 2.3"))"#, "3.8");
+ assert_output(r#"DISPLAY(EVAL("3.0 * (4.5 - 2.5)"))"#, "6");
+
+ assert!(run_test(r#"DISPLAY(EVAL("1 + "))"#).is_err());
+ assert!(run_test(r#"DISPLAY(EVAL("1 / 0"))"#).is_err());
+ assert!(run_test(r#"DISPLAY(EVAL("invalid"))"#).is_err());
+ }
}
diff --git a/wapm.toml b/wapm.toml
index d0d788f..a58acd1 100644
--- a/wapm.toml
+++ b/wapm.toml
@@ -1,7 +1,7 @@
[package]
name = "pseudolang/fplc"
-version = "0.9.512"
+version = "0.9.513"
description = "A pseudolang interpreter written in Rust"
license = "MIT"
readme = "readme.md"