Refactor Purity enum and NativeFunction struct

Move `Purity` enum definition from `optimizer.rs` to `types.rs` and
create a `NativeFunction` struct to hold the function and its purity.
Update `Value::Function` to store `Rc<NativeFunction>` and
`Value::make_function`
helper to simplify creation.

This change allows tracking the purity of native functions, which is
useful
for optimization and static analysis.
This commit is contained in:
Michael Schimmel
2026-02-22 10:50:37 +01:00
parent b54a449369
commit a726b79d8a
9 changed files with 111 additions and 83 deletions
+1 -2
View File
@@ -1,6 +1,5 @@
use crate::ast::compiler::optimizer::Purity;
use crate::ast::environment::Environment;
use crate::ast::types::{Signature, StaticType, Value};
use crate::ast::types::{Purity, Signature, StaticType, Value};
use std::rc::Rc;
pub fn register(env: &Environment) {
+1 -2
View File
@@ -1,6 +1,5 @@
use crate::ast::compiler::optimizer::Purity;
use crate::ast::environment::Environment;
use crate::ast::types::{Signature, StaticType, Value};
use crate::ast::types::{Purity, Signature, StaticType, Value};
use chrono::{NaiveDate, NaiveDateTime};
pub fn register(env: &Environment) {
+19 -20
View File
@@ -1,5 +1,4 @@
use crate::ast::types::{StaticType, Value};
use std::rc::Rc;
use crate::ast::types::{Purity, StaticType, Value};
/// Looks up a specialized intrinsic function for the given operator and argument types.
/// Returns (Executable Value, Return Type) if a fast-path exists.
@@ -7,29 +6,29 @@ pub fn lookup(name: &str, args: &[StaticType]) -> Option<(Value, StaticType)> {
match (name, args) {
// --- Integer Arithmetic ---
("+", [StaticType::Int, StaticType::Int]) => Some((
Value::Function(Rc::new(|args| {
Value::make_function(Purity::Pure, |args| {
if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) {
Value::Int(a + b)
} else {
Value::Int(0) // Should not happen if type checker works
}
})),
}),
StaticType::Int,
)),
("-", [StaticType::Int, StaticType::Int]) => Some((
Value::Function(Rc::new(|args| {
Value::make_function(Purity::Pure, |args| {
if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) {
Value::Int(a - b)
} else {
Value::Int(0)
}
})),
}),
StaticType::Int,
)),
("-", [StaticType::Int, StaticType::Int, StaticType::Int]) => Some((
// Variadic optimization for 3 args (common in some Lisp dialects, though - usually is binary/unary)
// MyC's core.rs supports variadic subtraction.
Value::Function(Rc::new(|args| {
Value::make_function(Purity::Pure, |args| {
let a = match args[0] {
Value::Int(i) => i,
_ => 0,
@@ -43,69 +42,69 @@ pub fn lookup(name: &str, args: &[StaticType]) -> Option<(Value, StaticType)> {
_ => 0,
};
Value::Int(a - b - c)
})),
}),
StaticType::Int,
)),
("*", [StaticType::Int, StaticType::Int]) => Some((
Value::Function(Rc::new(|args| {
Value::make_function(Purity::Pure, |args| {
if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) {
Value::Int(a * b)
} else {
Value::Int(0)
}
})),
}),
StaticType::Int,
)),
// --- Integer Comparison ---
("<=", [StaticType::Int, StaticType::Int]) => Some((
Value::Function(Rc::new(|args| {
Value::make_function(Purity::Pure, |args| {
if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) {
Value::Bool(a <= b)
} else {
Value::Bool(false)
}
})),
}),
StaticType::Bool,
)),
("<", [StaticType::Int, StaticType::Int]) => Some((
Value::Function(Rc::new(|args| {
Value::make_function(Purity::Pure, |args| {
if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) {
Value::Bool(a < b)
} else {
Value::Bool(false)
}
})),
}),
StaticType::Bool,
)),
(">", [StaticType::Int, StaticType::Int]) => Some((
Value::Function(Rc::new(|args| {
Value::make_function(Purity::Pure, |args| {
if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) {
Value::Bool(a > b)
} else {
Value::Bool(false)
}
})),
}),
StaticType::Bool,
)),
(">=", [StaticType::Int, StaticType::Int]) => Some((
Value::Function(Rc::new(|args| {
Value::make_function(Purity::Pure, |args| {
if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) {
Value::Bool(a >= b)
} else {
Value::Bool(false)
}
})),
}),
StaticType::Bool,
)),
("=", [StaticType::Int, StaticType::Int]) => Some((
Value::Function(Rc::new(|args| {
Value::make_function(Purity::Pure, |args| {
if let (Value::Int(a), Value::Int(b)) = (&args[0], &args[1]) {
Value::Bool(a == b)
} else {
Value::Bool(false)
}
})),
}),
StaticType::Bool,
)),
+1 -2
View File
@@ -1,6 +1,5 @@
use crate::ast::compiler::optimizer::Purity;
use crate::ast::environment::Environment;
use crate::ast::types::{Signature, StaticType, Value};
use crate::ast::types::{Purity, Signature, StaticType, Value};
use std::f64::consts;
pub fn register(env: &Environment) {
+7 -6
View File
@@ -1,4 +1,4 @@
use crate::ast::types::{Keyword, Signature, StaticType, Value};
use crate::ast::types::{Keyword, Purity, Signature, StaticType, Value};
use std::any::TypeId;
use std::collections::HashMap;
use std::rc::Rc;
@@ -68,7 +68,7 @@ impl TypeRegistry {
}
}
};
Value::Function(Rc::new(closure))
Value::make_function(Purity::Impure, closure)
}
}
@@ -94,7 +94,8 @@ impl RecordBuilder {
F: Fn(Vec<Value>) -> Value + 'static,
{
let key = Keyword::intern(name);
self.fields.push((key, Value::Function(Rc::new(func))));
self.fields
.push((key, Value::make_function(Purity::Impure, func)));
self
}
@@ -217,7 +218,7 @@ mod tests {
let greet_fn = &r.values[idx];
if let Value::Function(f) = greet_fn {
let res = f(vec![]);
let res = (f.func)(vec![]);
if let Value::Text(s) = res {
assert_eq!(&*s, "Hello Alice");
} else {
@@ -249,7 +250,7 @@ mod tests {
});
if let Value::Function(f) = factory_val {
let instance = f(vec![Value::Text("Bob".into()), Value::Int(40)]);
let instance = (f.func)(vec![Value::Text("Bob".into()), Value::Int(40)]);
if let Value::Record(r) = instance {
let idx = r
.keys
@@ -259,7 +260,7 @@ mod tests {
let greet_fn = &r.values[idx];
if let Value::Function(gf) = greet_fn {
let res = gf(vec![]);
let res = (gf.func)(vec![]);
if let Value::Text(s) = res {
assert_eq!(&*s, "Hello Bob");
} else {