Formatting
This commit is contained in:
+473
-334
@@ -1,334 +1,473 @@
|
||||
use std::rc::Rc;
|
||||
use crate::ast::types::{Value, StaticType, Signature};
|
||||
use crate::ast::environment::Environment;
|
||||
|
||||
|
||||
pub fn register(env: &Environment) {
|
||||
register_constants(env);
|
||||
register_arithmetic(env);
|
||||
register_comparison(env);
|
||||
register_logic(env);
|
||||
}
|
||||
|
||||
fn register_constants(env: &Environment) {
|
||||
// True/False are keywords or literals in parser, but could be exposed as constants too if needed.
|
||||
// In Delphi RTL: CFalse, CTrue, CNaN
|
||||
|
||||
// We register NaN as a value, not a function.
|
||||
env.register_constant("NaN", StaticType::Float, Value::Float(f64::NAN));
|
||||
env.register_constant("true", StaticType::Bool, Value::Bool(true));
|
||||
env.register_constant("false", StaticType::Bool, Value::Bool(false));
|
||||
}
|
||||
|
||||
fn register_arithmetic(env: &Environment) {
|
||||
// --- Add (+) ---
|
||||
let add_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]), ret: StaticType::Int },
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Float, StaticType::Float]), ret: StaticType::Float },
|
||||
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, true, |args| {
|
||||
if args.len() == 2 {
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a + b),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Float(a + b),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Float(*a as f64 + b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Float(a + *b as f64),
|
||||
(Value::Text(a), Value::Text(b)) => {
|
||||
let mut res = a.to_string();
|
||||
res.push_str(b);
|
||||
Value::Text(Rc::from(res))
|
||||
},
|
||||
(Value::DateTime(ts), Value::Int(ms)) => Value::DateTime(ts + ms),
|
||||
_ => Value::Void,
|
||||
}
|
||||
} else {
|
||||
// Variadic sum
|
||||
let mut acc = 0.0;
|
||||
for arg in args {
|
||||
if let Value::Int(i) = arg { acc += i as f64; }
|
||||
else if let Value::Float(f) = arg { acc += f; }
|
||||
}
|
||||
if acc.fract() == 0.0 { Value::Int(acc as i64) } else { Value::Float(acc) }
|
||||
}
|
||||
});
|
||||
|
||||
// --- Subtract (-) ---
|
||||
let sub_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]), ret: StaticType::Int },
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Float, StaticType::Float]), ret: StaticType::Float },
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Int]), ret: StaticType::Int }, // Negation
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Float]), ret: StaticType::Float },
|
||||
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, true, |args| {
|
||||
if args.is_empty() { return Value::Void; }
|
||||
if args.len() == 1 {
|
||||
return match args[0] {
|
||||
Value::Int(i) => Value::Int(-i),
|
||||
Value::Float(f) => Value::Float(-f),
|
||||
_ => Value::Void,
|
||||
};
|
||||
}
|
||||
if args.len() == 2 {
|
||||
return match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a - b),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Float(a - b),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Float(*a as f64 - b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Float(a - *b as f64),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Int(a - b),
|
||||
(Value::DateTime(a), Value::Int(b)) => Value::DateTime(a - b),
|
||||
_ => Value::Void,
|
||||
};
|
||||
}
|
||||
// Variadic sub
|
||||
let mut acc = match args[0] {
|
||||
Value::Int(i) => i as f64,
|
||||
Value::Float(f) => f,
|
||||
_ => return Value::Void,
|
||||
};
|
||||
for arg in &args[1..] {
|
||||
if let Value::Int(i) = arg { acc -= *i as f64; }
|
||||
else if let Value::Float(f) = arg { acc -= f; }
|
||||
}
|
||||
if acc.fract() == 0.0 { Value::Int(acc as i64) } else { Value::Float(acc) }
|
||||
});
|
||||
|
||||
// --- Multiply (*) ---
|
||||
let mul_ty = StaticType::FunctionOverloads(vec![
|
||||
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, true, |args| {
|
||||
if args.len() == 2 {
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a * b),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Float(a * b),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Float(*a as f64 * b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Float(a * *b as f64),
|
||||
_ => Value::Void,
|
||||
}
|
||||
} else {
|
||||
let mut acc = 1.0;
|
||||
for arg in args {
|
||||
if let Value::Int(i) = arg { acc *= i as f64; }
|
||||
else if let Value::Float(f) = arg { acc *= f; }
|
||||
}
|
||||
if acc.fract() == 0.0 { Value::Int(acc as i64) } else { Value::Float(acc) }
|
||||
}
|
||||
});
|
||||
|
||||
// --- Divide (/) ---
|
||||
let div_ty = StaticType::FunctionOverloads(vec![
|
||||
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, 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 };
|
||||
if b == 0.0 { Value::Float(f64::NAN) } else { Value::Float(a / b) }
|
||||
});
|
||||
|
||||
// --- Integer Divide (//) ---
|
||||
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, true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => {
|
||||
if *b == 0 { Value::Void } else { Value::Int(a / b) }
|
||||
},
|
||||
// Also allow float truncation? Delphi RTL says IntDivide takes DataValue and returns DataValue.
|
||||
// Usually div is for integers. Let's stick to Int.
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// --- Modulus (%) ---
|
||||
let mod_ty = StaticType::Function(Box::new(
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]), ret: StaticType::Int }
|
||||
));
|
||||
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)) => {
|
||||
if *b == 0 { Value::Void } else { Value::Int(a % b) }
|
||||
},
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn register_comparison(env: &Environment) {
|
||||
let cmp_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]), ret: StaticType::Bool },
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::Float, StaticType::Float]), ret: StaticType::Bool },
|
||||
Signature { params: StaticType::Tuple(vec![StaticType::DateTime, StaticType::DateTime]), ret: StaticType::Bool },
|
||||
]);
|
||||
|
||||
// --- Greater Than (>) ---
|
||||
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),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64) > *b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool(*a > (*b as f64)),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool(a > b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a > b),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
});
|
||||
|
||||
// --- Less Than (<) ---
|
||||
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),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64) < *b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool(*a < (*b as f64)),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool(a < b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a < b),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
});
|
||||
|
||||
// --- Greater Or Equal (>=) ---
|
||||
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),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64) >= *b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool(*a >= (*b as f64)),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool(a >= b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a >= b),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
});
|
||||
|
||||
// --- Less Or Equal (<=) ---
|
||||
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),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64) <= *b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool(*a <= (*b as f64)),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool(a <= b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a <= b),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
});
|
||||
|
||||
// --- Equal (=) ---
|
||||
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(), 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.
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Bool(a == b),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool((a - b).abs() < f64::EPSILON),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64 - b).abs() < f64::EPSILON),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool((a - *b as f64).abs() < f64::EPSILON),
|
||||
(Value::Text(a), Value::Text(b)) => Value::Bool(a == b),
|
||||
(Value::Bool(a), Value::Bool(b)) => Value::Bool(a == b),
|
||||
(Value::Keyword(a), Value::Keyword(b)) => Value::Bool(a == b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a == b),
|
||||
(Value::Void, Value::Void) => Value::Bool(true),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
});
|
||||
|
||||
// --- Not Equal (<>) ---
|
||||
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),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool((a - b).abs() >= f64::EPSILON),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64 - b).abs() >= f64::EPSILON),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool((a - *b as f64).abs() >= f64::EPSILON),
|
||||
(Value::Text(a), Value::Text(b)) => Value::Bool(a != b),
|
||||
(Value::Bool(a), Value::Bool(b)) => Value::Bool(a != b),
|
||||
(Value::Keyword(a), Value::Keyword(b)) => Value::Bool(a != b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a != b),
|
||||
(Value::Void, Value::Void) => Value::Bool(false),
|
||||
_ => Value::Bool(true),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn register_logic(env: &Environment) {
|
||||
// --- Not (not) ---
|
||||
let not_ty = StaticType::FunctionOverloads(vec![
|
||||
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, true, |args| {
|
||||
if args.len() != 1 { return Value::Void; }
|
||||
match &args[0] {
|
||||
Value::Bool(b) => Value::Bool(!b),
|
||||
Value::Int(i) => Value::Int(!i), // Bitwise NOT
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// --- And (and) ---
|
||||
let logic_op_ty = StaticType::FunctionOverloads(vec![
|
||||
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(), true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Bool(a), Value::Bool(b)) => Value::Bool(*a && *b),
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a & b),
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// --- Or (or) ---
|
||||
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),
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a | b),
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// --- Xor (xor) ---
|
||||
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),
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a ^ b),
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// --- Shift Left (<<) ---
|
||||
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(), true, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a << b),
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// --- Shift Right (>>) ---
|
||||
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),
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
}
|
||||
use crate::ast::environment::Environment;
|
||||
use crate::ast::types::{Signature, StaticType, Value};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn register(env: &Environment) {
|
||||
register_constants(env);
|
||||
register_arithmetic(env);
|
||||
register_comparison(env);
|
||||
register_logic(env);
|
||||
}
|
||||
|
||||
fn register_constants(env: &Environment) {
|
||||
// True/False are keywords or literals in parser, but could be exposed as constants too if needed.
|
||||
// In Delphi RTL: CFalse, CTrue, CNaN
|
||||
|
||||
// We register NaN as a value, not a function.
|
||||
env.register_constant("NaN", StaticType::Float, Value::Float(f64::NAN));
|
||||
env.register_constant("true", StaticType::Bool, Value::Bool(true));
|
||||
env.register_constant("false", StaticType::Bool, Value::Bool(false));
|
||||
}
|
||||
|
||||
fn register_arithmetic(env: &Environment) {
|
||||
// --- Add (+) ---
|
||||
let add_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]),
|
||||
ret: StaticType::Int,
|
||||
},
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Float, StaticType::Float]),
|
||||
ret: StaticType::Float,
|
||||
},
|
||||
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, true, |args| {
|
||||
if args.len() == 2 {
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a + b),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Float(a + b),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Float(*a as f64 + b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Float(a + *b as f64),
|
||||
(Value::Text(a), Value::Text(b)) => {
|
||||
let mut res = a.to_string();
|
||||
res.push_str(b);
|
||||
Value::Text(Rc::from(res))
|
||||
}
|
||||
(Value::DateTime(ts), Value::Int(ms)) => Value::DateTime(ts + ms),
|
||||
_ => Value::Void,
|
||||
}
|
||||
} else {
|
||||
// Variadic sum
|
||||
let mut acc = 0.0;
|
||||
for arg in args {
|
||||
if let Value::Int(i) = arg {
|
||||
acc += i as f64;
|
||||
} else if let Value::Float(f) = arg {
|
||||
acc += f;
|
||||
}
|
||||
}
|
||||
if acc.fract() == 0.0 {
|
||||
Value::Int(acc as i64)
|
||||
} else {
|
||||
Value::Float(acc)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// --- Subtract (-) ---
|
||||
let sub_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]),
|
||||
ret: StaticType::Int,
|
||||
},
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Float, StaticType::Float]),
|
||||
ret: StaticType::Float,
|
||||
},
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Int]),
|
||||
ret: StaticType::Int,
|
||||
}, // Negation
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Float]),
|
||||
ret: StaticType::Float,
|
||||
},
|
||||
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, true, |args| {
|
||||
if args.is_empty() {
|
||||
return Value::Void;
|
||||
}
|
||||
if args.len() == 1 {
|
||||
return match args[0] {
|
||||
Value::Int(i) => Value::Int(-i),
|
||||
Value::Float(f) => Value::Float(-f),
|
||||
_ => Value::Void,
|
||||
};
|
||||
}
|
||||
if args.len() == 2 {
|
||||
return match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a - b),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Float(a - b),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Float(*a as f64 - b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Float(a - *b as f64),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Int(a - b),
|
||||
(Value::DateTime(a), Value::Int(b)) => Value::DateTime(a - b),
|
||||
_ => Value::Void,
|
||||
};
|
||||
}
|
||||
// Variadic sub
|
||||
let mut acc = match args[0] {
|
||||
Value::Int(i) => i as f64,
|
||||
Value::Float(f) => f,
|
||||
_ => return Value::Void,
|
||||
};
|
||||
for arg in &args[1..] {
|
||||
if let Value::Int(i) = arg {
|
||||
acc -= *i as f64;
|
||||
} else if let Value::Float(f) = arg {
|
||||
acc -= f;
|
||||
}
|
||||
}
|
||||
if acc.fract() == 0.0 {
|
||||
Value::Int(acc as i64)
|
||||
} else {
|
||||
Value::Float(acc)
|
||||
}
|
||||
});
|
||||
|
||||
// --- Multiply (*) ---
|
||||
let mul_ty = StaticType::FunctionOverloads(vec![
|
||||
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, true, |args| {
|
||||
if args.len() == 2 {
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a * b),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Float(a * b),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Float(*a as f64 * b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Float(a * *b as f64),
|
||||
_ => Value::Void,
|
||||
}
|
||||
} else {
|
||||
let mut acc = 1.0;
|
||||
for arg in args {
|
||||
if let Value::Int(i) = arg {
|
||||
acc *= i as f64;
|
||||
} else if let Value::Float(f) = arg {
|
||||
acc *= f;
|
||||
}
|
||||
}
|
||||
if acc.fract() == 0.0 {
|
||||
Value::Int(acc as i64)
|
||||
} else {
|
||||
Value::Float(acc)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// --- Divide (/) ---
|
||||
let div_ty = StaticType::FunctionOverloads(vec![
|
||||
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, 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,
|
||||
};
|
||||
if b == 0.0 {
|
||||
Value::Float(f64::NAN)
|
||||
} else {
|
||||
Value::Float(a / b)
|
||||
}
|
||||
});
|
||||
|
||||
// --- Integer Divide (//) ---
|
||||
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, true, |args| {
|
||||
if args.len() != 2 {
|
||||
return Value::Void;
|
||||
}
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => {
|
||||
if *b == 0 {
|
||||
Value::Void
|
||||
} else {
|
||||
Value::Int(a / b)
|
||||
}
|
||||
}
|
||||
// Also allow float truncation? Delphi RTL says IntDivide takes DataValue and returns DataValue.
|
||||
// Usually div is for integers. Let's stick to Int.
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// --- Modulus (%) ---
|
||||
let mod_ty = StaticType::Function(Box::new(Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]),
|
||||
ret: StaticType::Int,
|
||||
}));
|
||||
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)) => {
|
||||
if *b == 0 {
|
||||
Value::Void
|
||||
} else {
|
||||
Value::Int(a % b)
|
||||
}
|
||||
}
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn register_comparison(env: &Environment) {
|
||||
let cmp_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Int, StaticType::Int]),
|
||||
ret: StaticType::Bool,
|
||||
},
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::Float, StaticType::Float]),
|
||||
ret: StaticType::Bool,
|
||||
},
|
||||
Signature {
|
||||
params: StaticType::Tuple(vec![StaticType::DateTime, StaticType::DateTime]),
|
||||
ret: StaticType::Bool,
|
||||
},
|
||||
]);
|
||||
|
||||
// --- Greater Than (>) ---
|
||||
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),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64) > *b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool(*a > (*b as f64)),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool(a > b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a > b),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
});
|
||||
|
||||
// --- Less Than (<) ---
|
||||
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),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64) < *b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool(*a < (*b as f64)),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool(a < b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a < b),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
});
|
||||
|
||||
// --- Greater Or Equal (>=) ---
|
||||
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),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64) >= *b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool(*a >= (*b as f64)),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool(a >= b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a >= b),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
});
|
||||
|
||||
// --- Less Or Equal (<=) ---
|
||||
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),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64) <= *b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool(*a <= (*b as f64)),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool(a <= b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a <= b),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
});
|
||||
|
||||
// --- Equal (=) ---
|
||||
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(), 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.
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Bool(a == b),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool((a - b).abs() < f64::EPSILON),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64 - b).abs() < f64::EPSILON),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool((a - *b as f64).abs() < f64::EPSILON),
|
||||
(Value::Text(a), Value::Text(b)) => Value::Bool(a == b),
|
||||
(Value::Bool(a), Value::Bool(b)) => Value::Bool(a == b),
|
||||
(Value::Keyword(a), Value::Keyword(b)) => Value::Bool(a == b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a == b),
|
||||
(Value::Void, Value::Void) => Value::Bool(true),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
});
|
||||
|
||||
// --- Not Equal (<>) ---
|
||||
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),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool((a - b).abs() >= f64::EPSILON),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64 - b).abs() >= f64::EPSILON),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool((a - *b as f64).abs() >= f64::EPSILON),
|
||||
(Value::Text(a), Value::Text(b)) => Value::Bool(a != b),
|
||||
(Value::Bool(a), Value::Bool(b)) => Value::Bool(a != b),
|
||||
(Value::Keyword(a), Value::Keyword(b)) => Value::Bool(a != b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a != b),
|
||||
(Value::Void, Value::Void) => Value::Bool(false),
|
||||
_ => Value::Bool(true),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn register_logic(env: &Environment) {
|
||||
// --- Not (not) ---
|
||||
let not_ty = StaticType::FunctionOverloads(vec![
|
||||
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, true, |args| {
|
||||
if args.len() != 1 {
|
||||
return Value::Void;
|
||||
}
|
||||
match &args[0] {
|
||||
Value::Bool(b) => Value::Bool(!b),
|
||||
Value::Int(i) => Value::Int(!i), // Bitwise NOT
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// --- And (and) ---
|
||||
let logic_op_ty = StaticType::FunctionOverloads(vec![
|
||||
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(), true, |args| {
|
||||
if args.len() != 2 {
|
||||
return Value::Void;
|
||||
}
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Bool(a), Value::Bool(b)) => Value::Bool(*a && *b),
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a & b),
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// --- Or (or) ---
|
||||
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),
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a | b),
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// --- Xor (xor) ---
|
||||
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),
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a ^ b),
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// --- Shift Left (<<) ---
|
||||
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(), true, |args| {
|
||||
if args.len() != 2 {
|
||||
return Value::Void;
|
||||
}
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a << b),
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
|
||||
// --- Shift Right (>>) ---
|
||||
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),
|
||||
_ => Value::Void,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user