feat: Implement purity inference for optimization
This commit introduces purity inference to the compiler's optimizer. This allows for more aggressive constant folding and dead code elimination by tracking which functions and global variables are free of side effects. Key changes include: - Added `global_purity` field to `Optimizer` and `Environment`. - Modified `Optimizer::is_pure` to recursively determine if an AST node represents a pure computation. - Introduced `Optimizer::try_fold_pure` to replace the old `try_fold_intrinsic`, enabling folding of pure function calls with constant arguments. - Updated `Environment::register_native` and `Environment::register_constant` to optionally record purity. - Added purity flags to several built-in functions in `core.rs` and `datetime.rs`. - A new example `optimizer_purity.myc` demonstrates the new feature.
This commit is contained in:
+18
-18
@@ -28,7 +28,7 @@ fn register_arithmetic(env: &Environment) {
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Text, StaticType::Text]), ret: StaticType::Text },
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::DateTime, StaticType::Int]), ret: StaticType::DateTime },
|
||||
]);
|
||||
env.register_native("+", add_ty, |args| {
|
||||
env.register_native("+", add_ty, true, |args| {
|
||||
if args.len() == 2 {
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a + b),
|
||||
@@ -63,7 +63,7 @@ fn register_arithmetic(env: &Environment) {
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::DateTime, StaticType::DateTime]), ret: StaticType::Int },
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::DateTime, StaticType::Int]), ret: StaticType::DateTime },
|
||||
]);
|
||||
env.register_native("-", sub_ty, |args| {
|
||||
env.register_native("-", sub_ty, true, |args| {
|
||||
if args.is_empty() { return Value::Void; }
|
||||
if args.len() == 1 {
|
||||
return match args[0] {
|
||||
@@ -101,7 +101,7 @@ fn register_arithmetic(env: &Environment) {
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]), ret: StaticType::Int },
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Float, StaticType::Float]), ret: StaticType::Float },
|
||||
]);
|
||||
env.register_native("*", mul_ty, |args| {
|
||||
env.register_native("*", mul_ty, true, |args| {
|
||||
if args.len() == 2 {
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a * b),
|
||||
@@ -125,7 +125,7 @@ fn register_arithmetic(env: &Environment) {
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]), ret: StaticType::Float },
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Float, StaticType::Float]), ret: StaticType::Float },
|
||||
]);
|
||||
env.register_native("/", div_ty, |args| {
|
||||
env.register_native("/", div_ty, true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
let a = match args[0] { Value::Int(i) => i as f64, Value::Float(f) => f, _ => return Value::Void };
|
||||
let b = match args[1] { Value::Int(i) => i as f64, Value::Float(f) => f, _ => return Value::Void };
|
||||
@@ -136,7 +136,7 @@ fn register_arithmetic(env: &Environment) {
|
||||
let int_div_ty = StaticType::Function(Box::new(
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]), ret: StaticType::Int }
|
||||
));
|
||||
env.register_native("//", int_div_ty, |args| {
|
||||
env.register_native("//", int_div_ty, true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => {
|
||||
@@ -152,7 +152,7 @@ fn register_arithmetic(env: &Environment) {
|
||||
let mod_ty = StaticType::Function(Box::new(
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]), ret: StaticType::Int }
|
||||
));
|
||||
env.register_native("%", mod_ty, |args| {
|
||||
env.register_native("%", mod_ty, true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => {
|
||||
@@ -171,7 +171,7 @@ fn register_comparison(env: &Environment) {
|
||||
]);
|
||||
|
||||
// --- Greater Than (>) ---
|
||||
env.register_native(">", cmp_ty.clone(), |args| {
|
||||
env.register_native(">", cmp_ty.clone(), true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Bool(a > b),
|
||||
@@ -184,7 +184,7 @@ fn register_comparison(env: &Environment) {
|
||||
});
|
||||
|
||||
// --- Less Than (<) ---
|
||||
env.register_native("<", cmp_ty.clone(), |args| {
|
||||
env.register_native("<", cmp_ty.clone(), true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Bool(a < b),
|
||||
@@ -197,7 +197,7 @@ fn register_comparison(env: &Environment) {
|
||||
});
|
||||
|
||||
// --- Greater Or Equal (>=) ---
|
||||
env.register_native(">=", cmp_ty.clone(), |args| {
|
||||
env.register_native(">=", cmp_ty.clone(), true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Bool(a >= b),
|
||||
@@ -210,7 +210,7 @@ fn register_comparison(env: &Environment) {
|
||||
});
|
||||
|
||||
// --- Less Or Equal (<=) ---
|
||||
env.register_native("<=", cmp_ty.clone(), |args| {
|
||||
env.register_native("<=", cmp_ty.clone(), true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Bool(a <= b),
|
||||
@@ -226,7 +226,7 @@ fn register_comparison(env: &Environment) {
|
||||
let eq_ty = StaticType::Function(Box::new(
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Any, StaticType::Any]), ret: StaticType::Bool }
|
||||
));
|
||||
env.register_native("=", eq_ty.clone(), |args| {
|
||||
env.register_native("=", eq_ty.clone(), true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
// Simple equality check.
|
||||
// Note: Floating point equality is tricky, but we follow standard behavior for now.
|
||||
@@ -245,7 +245,7 @@ fn register_comparison(env: &Environment) {
|
||||
});
|
||||
|
||||
// --- Not Equal (<>) ---
|
||||
env.register_native("<>", eq_ty, |args| {
|
||||
env.register_native("<>", eq_ty, true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Bool(a != b),
|
||||
@@ -268,7 +268,7 @@ fn register_logic(env: &Environment) {
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Bool]), ret: StaticType::Bool },
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Int]), ret: StaticType::Int },
|
||||
]);
|
||||
env.register_native("not", not_ty, |args| {
|
||||
env.register_native("not", not_ty, true, |args| {
|
||||
if args.len() != 1 { return Value::Void; }
|
||||
match &args[0] {
|
||||
Value::Bool(b) => Value::Bool(!b),
|
||||
@@ -282,7 +282,7 @@ fn register_logic(env: &Environment) {
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Bool, StaticType::Bool]), ret: StaticType::Bool },
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]), ret: StaticType::Int },
|
||||
]);
|
||||
env.register_native("and", logic_op_ty.clone(), |args| {
|
||||
env.register_native("and", logic_op_ty.clone(), true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Bool(a), Value::Bool(b)) => Value::Bool(*a && *b),
|
||||
@@ -292,7 +292,7 @@ fn register_logic(env: &Environment) {
|
||||
});
|
||||
|
||||
// --- Or (or) ---
|
||||
env.register_native("or", logic_op_ty.clone(), |args| {
|
||||
env.register_native("or", logic_op_ty.clone(), true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Bool(a), Value::Bool(b)) => Value::Bool(*a || *b),
|
||||
@@ -302,7 +302,7 @@ fn register_logic(env: &Environment) {
|
||||
});
|
||||
|
||||
// --- Xor (xor) ---
|
||||
env.register_native("xor", logic_op_ty.clone(), |args| {
|
||||
env.register_native("xor", logic_op_ty.clone(), true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Bool(a), Value::Bool(b)) => Value::Bool(*a ^ *b),
|
||||
@@ -315,7 +315,7 @@ fn register_logic(env: &Environment) {
|
||||
let shift_ty = StaticType::Function(Box::new(
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]), ret: StaticType::Int }
|
||||
));
|
||||
env.register_native("<<", shift_ty.clone(), |args| {
|
||||
env.register_native("<<", shift_ty.clone(), true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a << b),
|
||||
@@ -324,7 +324,7 @@ fn register_logic(env: &Environment) {
|
||||
});
|
||||
|
||||
// --- Shift Right (>>) ---
|
||||
env.register_native(">>", shift_ty, |args| {
|
||||
env.register_native(">>", shift_ty, true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a >> b),
|
||||
|
||||
@@ -8,7 +8,7 @@ pub fn register(env: &Environment) {
|
||||
ret: StaticType::DateTime
|
||||
}));
|
||||
|
||||
env.register_native("date", date_ty, |args| {
|
||||
env.register_native("date", date_ty, true, |args| {
|
||||
if let Value::Text(s) = &args[0] {
|
||||
// Try parse YYYY-MM-DD
|
||||
if let Ok(dt) = NaiveDate::parse_from_str(s, "%Y-%m-%d") {
|
||||
|
||||
Reference in New Issue
Block a user