feat(engine): establish calcpad-engine workspace with Epic 1 modules
Cherry-picked and integrated the best code from 105 parallel epic branches into a clean workspace structure: - calcpad-engine/: Core Rust crate with lexer, parser, AST, interpreter, types, FFI (C ABI), pipeline, error handling, span tracking, eval context (from epic/1-5 base) - calcpad-engine/src/number.rs: Arbitrary precision arithmetic via dashu crate, WASM-compatible, exact decimals (from epic/1-4) - calcpad-engine/src/sheet_context.rs: SheetContext with dependency graph, dirty tracking, circular detection, cheap clone (from epic/1-8) - calcpad-wasm/: Thin WASM wrapper crate via wasm-bindgen, delegates to calcpad-engine (from epic/1-6) - Updated .gitignore for target/, node_modules/, build artifacts - Fixed run-pipeline.sh for macOS compat and CalcPad phases 79 tests passing across workspace.
This commit is contained in:
77
calcpad-engine/src/context.rs
Normal file
77
calcpad-engine/src/context.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use crate::types::CalcResult;
|
||||
use chrono::NaiveDate;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Evaluation context holding exchange rates, current date, variables, and other state
|
||||
/// needed during interpretation.
|
||||
pub struct EvalContext {
|
||||
/// Exchange rates relative to USD. Key is currency code (e.g. "EUR"),
|
||||
/// value is how many units of that currency per 1 USD.
|
||||
pub exchange_rates: HashMap<String, f64>,
|
||||
/// The current date for resolving `today`.
|
||||
pub today: NaiveDate,
|
||||
/// Named variables set via assignment expressions (e.g., `x = 5`).
|
||||
pub variables: HashMap<String, CalcResult>,
|
||||
}
|
||||
|
||||
impl EvalContext {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
exchange_rates: HashMap::new(),
|
||||
today: chrono::Local::now().date_naive(),
|
||||
variables: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a context with a fixed date (useful for testing).
|
||||
pub fn with_date(today: NaiveDate) -> Self {
|
||||
Self {
|
||||
exchange_rates: HashMap::new(),
|
||||
today,
|
||||
variables: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set exchange rate: 1 USD = `rate` units of `currency`.
|
||||
pub fn set_rate(&mut self, currency: &str, rate: f64) {
|
||||
self.exchange_rates.insert(currency.to_string(), rate);
|
||||
}
|
||||
|
||||
/// Store a variable result.
|
||||
pub fn set_variable(&mut self, name: &str, result: CalcResult) {
|
||||
self.variables.insert(name.to_string(), result);
|
||||
}
|
||||
|
||||
/// Retrieve a variable result.
|
||||
pub fn get_variable(&self, name: &str) -> Option<&CalcResult> {
|
||||
self.variables.get(name)
|
||||
}
|
||||
|
||||
/// Convert `amount` from `from_currency` to `to_currency`.
|
||||
/// Returns None if either rate is missing.
|
||||
pub fn convert_currency(
|
||||
&self,
|
||||
amount: f64,
|
||||
from_currency: &str,
|
||||
to_currency: &str,
|
||||
) -> Option<f64> {
|
||||
let from_rate = if from_currency == "USD" {
|
||||
1.0
|
||||
} else {
|
||||
*self.exchange_rates.get(from_currency)?
|
||||
};
|
||||
let to_rate = if to_currency == "USD" {
|
||||
1.0
|
||||
} else {
|
||||
*self.exchange_rates.get(to_currency)?
|
||||
};
|
||||
let usd_amount = amount / from_rate;
|
||||
Some(usd_amount * to_rate)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EvalContext {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user