1mod num;
2mod signature;
3
4pub use num::Num;
5pub use signature::{BuiltinSignature, Param, ParamType};
6
7use pine_core::{Color, DefaultPineOutput, PineOutput, MAX_LOOKBACK};
8
9use pine_ast::{Argument, BinOp, Expr, Literal, MethodParam, Program, Stmt, TypeField, UnOp};
10use std::cell::RefCell;
11use std::collections::HashMap;
12use std::rc::Rc;
13use thiserror::Error;
14
15pub use pine_core::LibraryLoader;
16
17fn push_history<O: PineOutput>(
23 history: &mut HashMap<String, Vec<Value<O>>>,
24 name: &str,
25 value: Value<O>,
26) {
27 let entries = history.entry(name.to_string()).or_default();
28 entries.push(value);
29 if entries.len() > MAX_LOOKBACK {
30 entries.drain(..entries.len() - MAX_LOOKBACK);
31 }
32}
33
34fn numeric_op<O: PineOutput>(
38 left: &Value<O>,
39 right: &Value<O>,
40 op: impl Fn(Num, Num) -> Option<Num>,
41) -> Result<Value<O>, RuntimeError> {
42 left.to_number()?;
44 right.to_number()?;
45
46 match (left.as_num(), right.as_num()) {
47 (Some(a), Some(b)) => Ok(op(a, b).map_or(Value::Na, Value::from)),
48 _ => Ok(Value::Na),
49 }
50}
51
52#[derive(Error, Debug)]
53pub enum RuntimeError {
54 #[error("Variable '{0}' not found")]
55 UndefinedVariable(String),
56
57 #[error("Type error: {0}")]
58 TypeError(String),
59
60 #[error("Division by zero")]
61 DivisionByZero,
62
63 #[error("Index out of bounds: {0}")]
64 IndexOutOfBounds(usize),
65
66 #[error("Cannot iterate: from={0}, to={1}")]
67 InvalidForLoop(f64, f64),
68
69 #[error("Break statement outside of loop")]
70 BreakOutsideLoop,
71
72 #[error("Continue statement outside of loop")]
73 ContinueOutsideLoop,
74
75 #[error("Library error: {0}")]
76 LibraryError(String),
77
78 #[error("Cannot reassign const variable '{0}'")]
79 ConstReassignment(String),
80
81 #[error("{0}")]
82 UserError(String),
83}
84
85#[derive(Debug, Clone, PartialEq)]
87enum LoopControl {
88 None,
89 Break,
90 Continue,
91}
92
93#[derive(Clone)]
95struct Variable<O: PineOutput = DefaultPineOutput> {
96 value: Value<O>,
97 is_const: bool,
98 is_var_persistent: bool,
100}
101
102#[derive(Clone, Debug)]
104pub struct Series<O: PineOutput = DefaultPineOutput> {
105 pub id: String,
106 pub current: Box<Value<O>>,
107 pub history: Option<Rc<RefCell<Vec<Value<O>>>>>,
108}
109
110pub type ObjectValueFn<O> = Rc<dyn Fn(&mut Interpreter<O>) -> Result<Value<O>, RuntimeError>>;
115
116pub type PerBarAdvance<O> = Rc<dyn Fn(&mut Interpreter<O>)>;
117
118pub type MapEntries<O> = Rc<RefCell<Vec<(Value<O>, Value<O>)>>>;
120
121#[derive(Clone)]
123pub enum Value<O: PineOutput> {
124 Int(i64),
125 Number(f64),
126 String(String),
127 Bool(bool),
128 Na, Array(Rc<RefCell<Vec<Value<O>>>>), Series(Series<O>), Object {
132 type_name: String, fields: Rc<RefCell<HashMap<String, Value<O>>>>, call: Option<Builtin<O>>,
135 value: Option<ObjectValueFn<O>>,
136 },
137 Function {
138 params: Vec<pine_ast::FunctionParam>,
139 body: Vec<Stmt>,
140 },
141 BuiltinFunction(Builtin<O>), Expr(Rc<Expr>),
145 Type {
146 name: String,
147 fields: Vec<TypeField>,
148 }, Enum {
150 enum_name: String, field_name: String, title: String, }, Color(Color), Matrix {
156 element_type: String, data: Rc<RefCell<Vec<Vec<Value<O>>>>>, },
159 Map {
160 key_type: String,
161 value_type: String,
162 data: MapEntries<O>,
163 },
164}
165
166impl<O: PineOutput> From<Num> for Value<O> {
167 fn from(n: Num) -> Self {
169 match n {
170 Num::Int(n) => Value::Int(n),
171 Num::Float(n) => Value::Number(n),
172 }
173 }
174}
175
176impl<O: PineOutput> Value<O> {
177 pub fn new_color(r: u8, g: u8, b: u8, t: u8) -> Value<O> {
178 Value::Color(Color::new(r, g, b, t))
179 }
180}
181
182impl<O: PineOutput> std::fmt::Debug for Value<O> {
184 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
185 match self {
186 Value::Int(n) => write!(f, "Int({:?})", n),
187 Value::Number(n) => write!(f, "Number({:?})", n),
188 Value::String(s) => write!(f, "String({:?})", s),
189 Value::Bool(b) => write!(f, "Bool({:?})", b),
190 Value::Na => write!(f, "Na"),
191 Value::Array(a) => write!(f, "Array({:?})", a),
192 Value::Series(s) => write!(f, "Series({:?})", s),
193 Value::Object {
194 type_name, fields, ..
195 } => write!(f, "Object({}:{:?})", type_name, fields),
196 Value::Function { params, .. } => write!(f, "Function({} params)", params.len()),
197 Value::BuiltinFunction(_) => write!(f, "BuiltinFunction"),
198 Value::Expr(_) => write!(f, "Expr"),
199 Value::Type { name, .. } => write!(f, "Type({})", name),
200 Value::Enum {
201 enum_name,
202 field_name,
203 ..
204 } => write!(f, "Enum({}::{})", enum_name, field_name),
205 Value::Color(color) => write!(
206 f,
207 "Color(rgba({}, {}, {}, {}))",
208 color.r, color.g, color.b, color.t
209 ),
210 Value::Matrix { element_type, data } => {
211 write!(f, "Matrix<{}>({:?})", element_type, data)
212 }
213 Value::Map {
214 key_type,
215 value_type,
216 data,
217 } => {
218 write!(f, "Map<{}, {}>({:?})", key_type, value_type, data)
219 }
220 }
221 }
222}
223
224impl<O: PineOutput> PartialEq for Value<O> {
225 fn eq(&self, other: &Self) -> bool {
226 match (self, other) {
227 (Value::Int(a), Value::Int(b)) => a == b,
228 (Value::Int(a), Value::Number(b)) | (Value::Number(b), Value::Int(a)) => {
230 (*a as f64 - b).abs() < f64::EPSILON
231 }
232 (Value::Number(a), Value::Number(b)) => (a - b).abs() < f64::EPSILON,
233 (Value::String(a), Value::String(b)) => a == b,
234 (Value::Bool(a), Value::Bool(b)) => a == b,
235 (Value::Na, Value::Na) => true,
236 (Value::Array(a), Value::Array(b)) => Rc::ptr_eq(a, b),
238 (Value::Series(a), Value::Series(b)) => a.id == b.id && *a.current == *b.current,
240 (Value::Object { fields: a, .. }, Value::Object { fields: b, .. }) => Rc::ptr_eq(a, b),
241 (Value::Function { .. }, Value::Function { .. }) => false,
243 (Value::BuiltinFunction(_), Value::BuiltinFunction(_)) => false,
244 (Value::Type { name: a, .. }, Value::Type { name: b, .. }) => a == b,
246 (
248 Value::Enum {
249 enum_name: a_enum,
250 field_name: a_field,
251 ..
252 },
253 Value::Enum {
254 enum_name: b_enum,
255 field_name: b_field,
256 ..
257 },
258 ) => a_enum == b_enum && a_field == b_field,
259 (Value::Color(c1), Value::Color(c2)) => c1 == c2,
261 (Value::Matrix { data: a, .. }, Value::Matrix { data: b, .. }) => Rc::ptr_eq(a, b),
263 (Value::Map { data: a, .. }, Value::Map { data: b, .. }) => Rc::ptr_eq(a, b),
265 _ => false,
266 }
267 }
268}
269
270#[derive(Debug, Clone)]
272pub enum EvaluatedArg<O: PineOutput = DefaultPineOutput> {
273 Positional(Value<O>),
274 Named { name: String, value: Value<O> },
275}
276
277#[derive(Debug, Clone)]
279pub struct FunctionCallArgs<O: PineOutput = DefaultPineOutput> {
280 pub type_args: Vec<String>,
281 pub args: Vec<EvaluatedArg<O>>,
282 pub call_id: u32,
283}
284
285impl<O: PineOutput> FunctionCallArgs<O> {
286 pub fn new(type_args: Vec<String>, args: Vec<EvaluatedArg<O>>) -> Self {
287 Self {
288 type_args,
289 args,
290 call_id: 0,
291 }
292 }
293
294 pub fn without_types(args: Vec<EvaluatedArg<O>>) -> Self {
295 Self {
296 type_args: vec![],
297 args,
298 call_id: 0,
299 }
300 }
301
302 pub fn with_call_id(mut self, call_id: u32) -> Self {
303 self.call_id = call_id;
304 self
305 }
306}
307
308pub type BuiltinFn<O> =
310 Rc<dyn Fn(&mut Interpreter<O>, FunctionCallArgs<O>) -> Result<Value<O>, RuntimeError>>;
311
312#[derive(Clone)]
316pub struct Builtin<O: PineOutput> {
317 pub call: BuiltinFn<O>,
318 pub signature: &'static BuiltinSignature,
321}
322
323impl<O: PineOutput> Builtin<O> {
324 pub fn untyped(call: BuiltinFn<O>) -> Self {
327 Self {
328 call,
329 signature: BuiltinSignature::empty(),
330 }
331 }
332}
333
334impl<O: PineOutput> Value<O> {
335 pub fn as_number(&self) -> Result<f64, RuntimeError> {
338 self.to_number().map(|opt| opt.unwrap_or(f64::NAN))
339 }
340
341 pub fn as_bool(&self) -> Result<bool, RuntimeError> {
344 Ok(self.to_bool()?.unwrap_or(false))
345 }
346
347 pub fn as_num(&self) -> Option<Num> {
351 match self {
352 Value::Int(n) => Some(Num::Int(*n)),
353 Value::Number(n) => Some(Num::Float(*n)),
354 Value::Bool(b) => Some(Num::Int(if *b { 1 } else { 0 })),
355 Value::Series(series) => series.current.as_num(),
356 _ => None,
357 }
358 }
359
360 fn as_int(&self) -> Option<i64> {
362 match self.as_num() {
363 Some(Num::Int(n)) => Some(n),
364 _ => None,
365 }
366 }
367
368 pub fn to_number(&self) -> Result<Option<f64>, RuntimeError> {
371 match self {
372 Value::Int(n) => Ok(Some(*n as f64)),
373 Value::Number(n) => Ok(Some(*n)),
374 Value::Bool(b) => Ok(Some(if *b { 1.0 } else { 0.0 })),
375 Value::Series(series) => series.current.to_number(),
376 Value::Na => Ok(None),
377 _ => Err(RuntimeError::TypeError(format!(
378 "Expected number, got {:?}",
379 self
380 ))),
381 }
382 }
383
384 pub fn to_bool(&self) -> Result<Option<bool>, RuntimeError> {
386 match self {
387 Value::Bool(b) => Ok(Some(*b)),
388 Value::Int(n) => Ok(Some(*n != 0)),
389 Value::Number(n) => Ok(Some(*n != 0.0 && !n.is_nan())),
391 Value::Na => Ok(None),
392 _ => Err(RuntimeError::TypeError(format!(
393 "Expected bool, got {:?}",
394 self
395 ))),
396 }
397 }
398
399 pub fn truthy_for_condition(&self) -> Result<bool, RuntimeError> {
402 Ok(self.to_bool()?.unwrap_or(false))
403 }
404
405 pub fn as_string(&self) -> Result<String, RuntimeError> {
406 match self {
407 Value::String(s) => Ok(s.clone()),
408 Value::Int(n) => Ok(n.to_string()),
409 Value::Number(n) => Ok(n.to_string()),
410 Value::Bool(b) => Ok(b.to_string()),
411 Value::Na => Ok("na".to_string()),
412 _ => Err(RuntimeError::TypeError(format!(
413 "Cannot convert {:?} to string",
414 self
415 ))),
416 }
417 }
418
419 pub fn as_array(&self) -> Result<&Rc<RefCell<Vec<Value<O>>>>, RuntimeError> {
420 match self {
421 Value::Array(arr) => Ok(arr),
422 _ => Err(RuntimeError::TypeError(format!(
423 "Expected array, got {:?}",
424 self
425 ))),
426 }
427 }
428
429 pub fn as_color(&self) -> Result<Color, RuntimeError> {
430 match self {
431 Value::Color(color) => Ok(color.clone()),
432 _ => Err(RuntimeError::TypeError(format!(
433 "Expected color, got {:?}",
434 self
435 ))),
436 }
437 }
438}
439
440#[derive(Clone)]
442struct MethodDef {
443 type_name: String, params: Vec<pine_ast::MethodParam>,
445 body: Vec<Stmt>,
446}
447
448struct SeriesSite<O: PineOutput> {
452 history: Vec<Value<O>>,
454 current: Option<Value<O>>,
456 bar: u64,
458}
459
460impl<O: PineOutput> SeriesSite<O> {
461 fn new() -> Self {
462 Self {
463 history: Vec::new(),
464 current: None,
465 bar: 0,
466 }
467 }
468}
469
470pub struct Interpreter<O: PineOutput> {
472 variables: HashMap<String, Variable<O>>,
474 user_types: HashMap<String, Value<O>>,
478 methods: HashMap<String, Vec<MethodDef>>,
480 pub library_loader: Option<Box<dyn LibraryLoader>>,
482 exports: HashMap<String, Value<O>>,
484 pub output: O,
486 pub user_series_history: HashMap<String, Vec<Value<O>>>,
490 expr_history: HashMap<u32, SeriesSite<O>>,
494 function_local_state: HashMap<u32, HashMap<String, Variable<O>>>,
501 var_decls_initialized: HashMap<(u32, String), u64>,
512 current_call_id: u32,
515 bar_seq: u64,
518 pub broker: Option<Box<dyn pine_broker::Broker>>,
521 pub broker_factory: Option<Box<dyn pine_broker::BrokerFactory>>,
523 pub request_provider: Option<Rc<dyn pine_core::DataProvider>>,
525 pub chart_period: Option<i64>,
526 pub current_time: Option<i64>,
529 pub per_bar_advances: Vec<PerBarAdvance<O>>,
530 pub inputs: HashMap<String, pine_core::InputValue>,
532}
533
534fn collect_assigned_names(body: &[Stmt], out: &mut std::collections::HashSet<String>) {
539 for s in body {
540 match s {
541 Stmt::VarDecl { name, .. } => {
542 out.insert(name.clone());
543 }
544 Stmt::Assignment {
545 target: Expr::Variable { name: n, .. },
546 ..
547 } => {
548 out.insert(n.clone());
549 }
550 Stmt::TupleAssignment { names, .. } => {
551 for n in names {
552 out.insert(n.clone());
553 }
554 }
555 Stmt::If {
556 then_branch,
557 else_if_branches,
558 else_branch,
559 ..
560 } => {
561 collect_assigned_names(then_branch, out);
562 for (_, b) in else_if_branches {
563 collect_assigned_names(b, out);
564 }
565 if let Some(b) = else_branch {
566 collect_assigned_names(b, out);
567 }
568 }
569 Stmt::For { var_name, body, .. } => {
570 out.insert(var_name.clone());
571 collect_assigned_names(body, out);
572 }
573 Stmt::While { body, .. } | Stmt::ForIn { body, .. } => {
574 collect_assigned_names(body, out)
575 }
576 _ => {}
577 }
578 }
579}
580
581fn builtin_namespace<O: PineOutput>(value: &Value<O>) -> Option<&'static str> {
584 match value {
585 Value::Array(_) => Some("array"),
586 Value::Matrix { .. } => Some("matrix"),
587 Value::Map { .. } => Some("map"),
588 _ => None,
589 }
590}
591
592fn is_na_operand<O: PineOutput>(v: &Value<O>) -> bool {
596 matches!(v, Value::Na) || matches!(v, Value::Number(n) if n.is_nan())
597}
598
599impl<O: PineOutput> Interpreter<O> {
600 pub fn new() -> Self {
601 Self {
602 variables: HashMap::new(),
603 user_types: HashMap::new(),
604 methods: HashMap::new(),
605 library_loader: None,
606 exports: HashMap::new(),
607 output: O::default(),
608 user_series_history: HashMap::new(),
609 expr_history: HashMap::new(),
610 function_local_state: HashMap::new(),
611 var_decls_initialized: HashMap::new(),
612 current_call_id: 0,
613 bar_seq: 0,
614 broker: None,
615 broker_factory: Some(Box::new(pine_broker::DefaultBrokerFactory)),
616 request_provider: None,
617 chart_period: None,
618 current_time: None,
619 per_bar_advances: Vec::new(),
620 inputs: HashMap::new(),
621 }
622 }
623
624 pub fn input(&self, title: &str) -> Option<&pine_core::InputValue> {
627 if title.is_empty() {
628 None
629 } else {
630 self.inputs.get(title)
631 }
632 }
633
634 pub fn bar_seq(&self) -> u64 {
637 self.bar_seq
638 }
639
640 pub fn set_library_loader(&mut self, library_loader: Box<dyn LibraryLoader>) {
642 self.library_loader = Some(library_loader);
643 }
644
645 pub fn snapshot(&self) -> HashMap<String, Value<O>> {
649 self.variables
650 .iter()
651 .map(|(name, var)| (name.clone(), var.value.clone()))
652 .collect()
653 }
654
655 pub fn exports(&self) -> &HashMap<String, Value<O>> {
657 &self.exports
658 }
659
660 pub fn execute(&mut self, program: &Program) -> Result<O, RuntimeError> {
662 self.output.clear();
664 self.bar_seq += 1;
666
667 for advance in self.per_bar_advances.clone() {
668 advance(self);
669 }
670
671 for stmt in &program.statements {
672 self.execute_stmt(stmt)?;
673 }
674
675 Ok(self.output.clone())
677 }
678
679 pub fn get_variable(&self, name: &str) -> Option<&Value<O>> {
681 self.variables.get(name).map(|var| &var.value)
682 }
683
684 pub fn is_user_type(&self, name: &str) -> bool {
686 self.user_types.contains_key(name)
687 }
688
689 fn namespace_member(&self, namespace: &str, member: &str) -> Option<Value<O>> {
691 match self.variables.get(namespace).map(|var| &var.value) {
692 Some(Value::Object { fields, .. }) => fields.borrow().get(member).cloned(),
693 _ => None,
694 }
695 }
696
697 pub fn set_variable(&mut self, name: &str, value: Value<O>) {
699 self.variables.insert(
700 name.to_string(),
701 Variable {
702 value,
703 is_const: false,
704 is_var_persistent: false,
705 },
706 );
707 }
708
709 pub fn advance_series(&mut self, name: &str, value: Value<O>) {
716 if let Some(existing) = self.variables.get(name) {
717 let previous = match &existing.value {
720 Value::Series(series) => (*series.current).clone(),
721 other => other.clone(),
722 };
723 push_history(&mut self.user_series_history, name, previous);
724 }
725 self.set_variable(name, value);
726 }
727
728 pub fn set_object_field(&mut self, object: &str, field: &str, value: Value<O>) {
732 if let Some(Variable {
733 value: Value::Object { fields, .. },
734 ..
735 }) = self.variables.get(object)
736 {
737 fields.borrow_mut().insert(field.to_string(), value);
738 }
739 }
740
741 pub fn set_const_variable(&mut self, name: &str, value: Value<O>) {
743 self.variables.insert(
744 name.to_string(),
745 Variable {
746 value,
747 is_const: true,
748 is_var_persistent: false,
749 },
750 );
751 }
752
753 pub fn set_const_variables(&mut self, variables: HashMap<String, Value<O>>) {
756 for (name, value) in variables {
757 self.set_const_variable(&name, value);
758 }
759 }
760
761 fn evaluate_arguments(
765 &mut self,
766 args: &[Argument],
767 signature: Option<&BuiltinSignature>,
768 ) -> Result<Vec<EvaluatedArg<O>>, RuntimeError> {
769 let mut evaluated_args = Vec::new();
770 let mut seen_named = false;
771 let mut positional_index = 0;
772
773 for arg in args {
774 match arg {
775 Argument::Positional(expr) => {
776 if seen_named {
777 return Err(RuntimeError::TypeError(
778 "Positional arguments cannot follow named arguments".to_string(),
779 ));
780 }
781 let lazy = signature.is_some_and(|s| s.positional_is_lazy(positional_index));
782 let value = self.eval_or_capture(expr, lazy)?;
783 evaluated_args.push(EvaluatedArg::Positional(value));
784 positional_index += 1;
785 }
786 Argument::Named { name, value: expr } => {
787 seen_named = true;
788 let lazy = signature.is_some_and(|s| s.named_is_lazy(name));
789 let value = self.eval_or_capture(expr, lazy)?;
790 evaluated_args.push(EvaluatedArg::Named {
791 name: name.clone(),
792 value,
793 });
794 }
795 }
796 }
797
798 Ok(evaluated_args)
799 }
800
801 fn eval_or_capture(&mut self, expr: &Expr, lazy: bool) -> Result<Value<O>, RuntimeError> {
804 if lazy {
805 Ok(Value::Expr(Rc::new(expr.clone())))
806 } else {
807 self.eval_expr(expr)
808 }
809 }
810
811 fn execute_stmt(&mut self, stmt: &Stmt) -> Result<Option<Value<O>>, RuntimeError> {
812 match stmt {
813 Stmt::VarDecl {
814 name,
815 type_qualifier,
816 type_annotation: _,
817 initializer,
818 var_kind,
821 ..
822 } => {
823 let is_var_persistent = var_kind.is_persistent();
824 if is_var_persistent {
831 let init_key = (self.current_call_id, name.clone());
832 if self.var_decls_initialized.contains_key(&init_key) {
833 return Ok(None);
834 }
835 self.var_decls_initialized.insert(init_key, self.bar_seq);
836 }
837 if !is_var_persistent {
841 if let Some(existing) = self.variables.get(name) {
842 push_history(&mut self.user_series_history, name, existing.value.clone());
843 }
844 }
845 let value = if let Some(init_expr) = initializer {
846 self.eval_expr(init_expr)?
847 } else {
848 Value::Na
849 };
850 let is_const = matches!(type_qualifier, Some(pine_ast::TypeQualifier::Const));
851 self.variables.insert(
852 name.clone(),
853 Variable {
854 value,
855 is_const,
856 is_var_persistent,
857 },
858 );
859 Ok(None)
860 }
861
862 Stmt::Assignment { target, value } => {
863 if let Expr::Variable { name, .. } = target {
872 if let Some(var) = self.variables.get(name) {
873 let born_this_bar = self
874 .var_decls_initialized
875 .get(&(self.current_call_id, name.clone()))
876 == Some(&self.bar_seq);
877 if var.is_var_persistent && !born_this_bar {
878 push_history(&mut self.user_series_history, name, var.value.clone());
879 }
880 }
881 }
882
883 let val = self.eval_expr(value)?;
884 match target {
885 Expr::Variable { name, .. } => {
886 let (is_const, is_var_persistent) =
888 if let Some(var) = self.variables.get(name) {
889 if var.is_const {
890 return Err(RuntimeError::ConstReassignment(name.clone()));
891 }
892 if !var.is_var_persistent {
893 push_history(
895 &mut self.user_series_history,
896 name,
897 var.value.clone(),
898 );
899 }
900 (false, var.is_var_persistent)
902 } else {
903 (false, false)
904 };
905
906 self.variables.insert(
907 name.clone(),
908 Variable {
909 value: val,
910 is_const,
911 is_var_persistent,
912 },
913 );
914 Ok(None)
915 }
916 Expr::MemberAccess { object, member, .. } => {
917 if let Expr::Variable { name: var_name, .. } = object.as_ref() {
919 if let Some(var) = self.variables.get(var_name) {
920 if var.is_const {
921 return Err(RuntimeError::ConstReassignment(format!(
922 "{}.{}",
923 var_name, member
924 )));
925 }
926 }
927 }
928
929 let obj_value = self.eval_expr(object)?;
931
932 if let Value::Object { fields, .. } = obj_value {
933 let mut obj = fields.borrow_mut();
934 obj.insert(member.clone(), val);
935 Ok(None)
936 } else {
937 Err(RuntimeError::TypeError(
938 "Cannot assign to member of non-object value".to_string(),
939 ))
940 }
941 }
942 _ => Err(RuntimeError::TypeError(
943 "Invalid assignment target".to_string(),
944 )),
945 }
946 }
947
948 Stmt::TupleAssignment { names, value, .. } => {
949 let val = self.eval_expr(value)?;
950 if let Value::Array(arr_ref) = val {
951 let arr = arr_ref.borrow();
952 for (i, name) in names.iter().enumerate() {
953 if let Some(var) = self.variables.get(name) {
955 push_history(&mut self.user_series_history, name, var.value.clone());
956 }
957 let element_val = arr.get(i).cloned().unwrap_or(Value::Na);
958 self.variables.insert(
959 name.clone(),
960 Variable {
961 value: element_val,
962 is_const: false,
963 is_var_persistent: false,
964 },
965 );
966 }
967 Ok(None)
968 } else {
969 Err(RuntimeError::TypeError(
970 "Expected array for tuple destructuring".to_string(),
971 ))
972 }
973 }
974
975 Stmt::Expression(expr) => {
976 self.eval_expr(expr)?;
977 Ok(None)
978 }
979
980 Stmt::If {
981 condition,
982 then_branch,
983 else_if_branches,
984 else_branch,
985 } => {
986 let cond_value = self.eval_expr(condition)?;
987 if cond_value.truthy_for_condition()? {
988 for stmt in then_branch {
989 self.execute_stmt(stmt)?;
990 }
991 } else {
992 let mut executed = false;
994 for (else_if_cond, else_if_body) in else_if_branches {
995 let else_if_value = self.eval_expr(else_if_cond)?;
996 if else_if_value.truthy_for_condition()? {
997 for stmt in else_if_body {
998 self.execute_stmt(stmt)?;
999 }
1000 executed = true;
1001 break;
1002 }
1003 }
1004
1005 if !executed {
1007 if let Some(else_stmts) = else_branch {
1008 for stmt in else_stmts {
1009 self.execute_stmt(stmt)?;
1010 }
1011 }
1012 }
1013 }
1014 Ok(None)
1015 }
1016
1017 Stmt::For {
1018 var_name,
1019 from,
1020 to,
1021 step,
1022 body,
1023 ..
1024 } => {
1025 let from_val = self.eval_expr(from)?.as_number()?;
1026 let to_val = self.eval_expr(to)?.as_number()?;
1027
1028 let step_val = match step {
1031 Some(expr) => self.eval_expr(expr)?.as_number()?.abs(),
1032 None => 1.0,
1033 };
1034 if step_val == 0.0 {
1035 return Err(RuntimeError::InvalidForLoop(from_val, to_val));
1036 }
1037 let down = from_val > to_val;
1038
1039 let mut i = from_val as i64;
1040 let end = to_val as i64;
1041 let step = step_val as i64;
1042
1043 while if down { i >= end } else { i <= end } {
1044 self.variables.insert(
1045 var_name.clone(),
1046 Variable {
1047 value: Value::Int(i),
1048 is_const: false,
1049 is_var_persistent: false,
1050 },
1051 );
1052
1053 let control = self.execute_loop_body(body)?;
1054 if control == LoopControl::Break {
1055 break;
1056 }
1057
1058 if down {
1059 i -= step;
1060 } else {
1061 i += step;
1062 }
1063 }
1064
1065 Ok(None)
1066 }
1067
1068 Stmt::ForIn {
1069 index_var,
1070 item_var,
1071 collection,
1072 body,
1073 ..
1074 } => {
1075 let collection_value = self.eval_expr(collection)?;
1076 let arr = collection_value.as_array()?;
1077 let arr_borrowed = arr.borrow();
1078
1079 for (index, item) in arr_borrowed.iter().enumerate() {
1080 if let Some(idx_var) = index_var {
1082 self.variables.insert(
1083 idx_var.clone(),
1084 Variable {
1085 value: Value::Int(index as i64),
1086 is_const: false,
1087 is_var_persistent: false,
1088 },
1089 );
1090 }
1091
1092 self.variables.insert(
1094 item_var.clone(),
1095 Variable {
1096 value: item.clone(),
1097 is_const: false,
1098 is_var_persistent: false,
1099 },
1100 );
1101
1102 let control = self.execute_loop_body(body)?;
1103 if control == LoopControl::Break {
1104 break;
1105 }
1106 }
1107
1108 Ok(None)
1109 }
1110
1111 Stmt::While { condition, body } => {
1112 loop {
1113 let cond_value = self.eval_expr(condition)?;
1114 if !cond_value.truthy_for_condition()? {
1115 break;
1116 }
1117
1118 let control = self.execute_loop_body(body)?;
1119 if control == LoopControl::Break {
1120 break;
1121 }
1122 }
1123 Ok(None)
1124 }
1125
1126 Stmt::Break { .. } => Err(RuntimeError::BreakOutsideLoop),
1127 Stmt::Continue { .. } => Err(RuntimeError::ContinueOutsideLoop),
1128
1129 Stmt::TypeDecl {
1130 name,
1131 fields,
1132 export,
1133 ..
1134 } => {
1135 let type_value = Value::Type {
1137 name: name.clone(),
1138 fields: fields.clone(),
1139 };
1140 self.user_types.insert(name.clone(), type_value.clone());
1141 self.variables.insert(
1142 name.clone(),
1143 Variable {
1144 value: type_value.clone(),
1145 is_const: false,
1146 is_var_persistent: false,
1147 },
1148 );
1149
1150 if *export {
1152 self.exports.insert(name.clone(), type_value);
1153 }
1154 Ok(None)
1155 }
1156
1157 Stmt::EnumDecl {
1158 name,
1159 fields,
1160 export,
1161 ..
1162 } => {
1163 let mut enum_fields = HashMap::new();
1165
1166 for field in fields {
1167 let title = field.title.clone().unwrap_or_else(|| field.name.clone());
1168 let enum_value = Value::Enum {
1169 enum_name: name.clone(),
1170 field_name: field.name.clone(),
1171 title,
1172 };
1173 enum_fields.insert(field.name.clone(), enum_value);
1174 }
1175
1176 let enum_object = Value::Object {
1177 type_name: name.clone(),
1178 fields: Rc::new(RefCell::new(enum_fields)),
1179 call: None,
1180 value: None,
1181 };
1182 self.variables.insert(
1183 name.clone(),
1184 Variable {
1185 value: enum_object.clone(),
1186 is_const: false,
1187 is_var_persistent: false,
1188 },
1189 );
1190
1191 if *export {
1193 self.exports.insert(name.clone(), enum_object);
1194 }
1195 Ok(None)
1196 }
1197
1198 Stmt::Export { item } => {
1199 match item {
1201 pine_ast::ExportItem::Type(type_name) => {
1202 if let Some(var) = self.variables.get(type_name) {
1204 self.exports.insert(type_name.clone(), var.value.clone());
1205 }
1206 }
1207 pine_ast::ExportItem::Function(func_name) => {
1208 if let Some(var) = self.variables.get(func_name) {
1210 self.exports.insert(func_name.clone(), var.value.clone());
1211 }
1212 }
1213 }
1214 Ok(None)
1215 }
1216
1217 Stmt::Import { path, alias, .. } => {
1218 let source = match &self.library_loader {
1219 Some(loader) => loader.load_library(path),
1220 None => {
1221 return Err(RuntimeError::LibraryError(
1222 "Cannot import library: no library loader configured".to_string(),
1223 ))
1224 }
1225 }
1226 .map_err(|e| {
1227 RuntimeError::LibraryError(format!("Failed to load library '{}': {}", path, e))
1228 })?;
1229
1230 let library_program = pine_parser::Parser::parse_source(&source).map_err(|e| {
1231 RuntimeError::LibraryError(format!("Failed to parse library '{}': {}", path, e))
1232 })?;
1233
1234 let mut library_interp = Interpreter::new();
1237 for (name, value) in self.snapshot() {
1238 library_interp.set_variable(&name, value);
1239 }
1240 library_interp.execute(&library_program)?;
1241 let library_exports = library_interp.exports();
1242
1243 for (method_name, method_defs) in &library_interp.methods {
1244 for method_def in method_defs {
1245 self.methods
1246 .entry(method_name.clone())
1247 .or_default()
1248 .push(method_def.clone());
1249 }
1250 }
1251
1252 let namespace: Value<O> = Value::Object {
1253 type_name: alias.clone(),
1254 fields: Rc::new(RefCell::new(library_exports.clone())),
1255 call: None,
1256 value: None,
1257 };
1258 self.variables.insert(
1259 alias.clone(),
1260 Variable {
1261 value: namespace,
1262 is_const: false,
1263 is_var_persistent: false,
1264 },
1265 );
1266 Ok(None)
1267 }
1268
1269 Stmt::MethodDecl {
1270 name,
1271 params,
1272 body,
1273 export,
1274 ..
1275 } => {
1276 let type_name = if let Some(first_param) = params.first() {
1278 first_param.type_annotation.clone().ok_or_else(|| {
1279 RuntimeError::TypeError(
1280 "Method's first parameter must have a type annotation".to_string(),
1281 )
1282 })?
1283 } else {
1284 return Err(RuntimeError::TypeError(
1285 "Method must have at least one parameter (this)".to_string(),
1286 ));
1287 };
1288
1289 let method_def = MethodDef {
1291 type_name,
1292 params: params.clone(),
1293 body: body.clone(),
1294 };
1295
1296 self.methods
1297 .entry(name.clone())
1298 .or_default()
1299 .push(method_def);
1300
1301 if *export {
1305 }
1307
1308 Ok(None)
1309 }
1310
1311 Stmt::FunctionDecl {
1312 name,
1313 params,
1314 body,
1315 export,
1316 ..
1317 } => {
1318 let func_value = Value::Function {
1320 params: params.clone(),
1321 body: body.clone(),
1322 };
1323 self.variables.insert(
1324 name.clone(),
1325 Variable {
1326 value: func_value.clone(),
1327 is_const: false,
1328 is_var_persistent: false,
1329 },
1330 );
1331
1332 if *export {
1334 self.exports.insert(name.clone(), func_value);
1335 }
1336
1337 Ok(None)
1338 }
1339 }
1340 }
1341
1342 fn execute_loop_body(&mut self, body: &[Stmt]) -> Result<LoopControl, RuntimeError> {
1344 for stmt in body {
1345 match stmt {
1346 Stmt::Break { .. } => return Ok(LoopControl::Break),
1347 Stmt::Continue { .. } => return Ok(LoopControl::Continue),
1348 Stmt::If {
1349 condition,
1350 then_branch,
1351 else_if_branches,
1352 else_branch,
1353 } => {
1354 let cond_value = self.eval_expr(condition)?;
1355 let branch = if cond_value.truthy_for_condition()? {
1356 then_branch
1357 } else {
1358 let mut matched_branch = None;
1360 for (else_if_cond, else_if_body) in else_if_branches {
1361 let else_if_value = self.eval_expr(else_if_cond)?;
1362 if else_if_value.truthy_for_condition()? {
1363 matched_branch = Some(else_if_body);
1364 break;
1365 }
1366 }
1367
1368 if let Some(branch) = matched_branch {
1369 branch
1370 } else if let Some(else_stmts) = else_branch {
1371 else_stmts
1372 } else {
1373 continue;
1374 }
1375 };
1376
1377 let control = self.execute_loop_body(branch)?;
1378 if control != LoopControl::None {
1379 return Ok(control);
1380 }
1381 }
1382 Stmt::For { .. } | Stmt::ForIn { .. } | Stmt::While { .. } => {
1383 self.execute_stmt(stmt)?;
1385 }
1386 _ => {
1387 self.execute_stmt(stmt)?;
1388 }
1389 }
1390 }
1391 Ok(LoopControl::None)
1392 }
1393
1394 fn eval_expr(&mut self, expr: &Expr) -> Result<Value<O>, RuntimeError> {
1397 let value = self.eval_expr_raw(expr)?;
1398 if let Value::Object {
1399 value: Some(compute),
1400 ..
1401 } = &value
1402 {
1403 let compute = compute.clone();
1404 return compute(self);
1405 }
1406 Ok(value)
1407 }
1408
1409 fn eval_expr_raw(&mut self, expr: &Expr) -> Result<Value<O>, RuntimeError> {
1410 match expr {
1411 Expr::Literal(lit) => Ok(self.eval_literal(lit)),
1412
1413 Expr::Variable { name, .. } => self
1414 .variables
1415 .get(name)
1416 .map(|var| var.value.clone())
1417 .ok_or_else(|| RuntimeError::UndefinedVariable(name.clone())),
1418
1419 Expr::Binary {
1420 left, op, right, ..
1421 } => {
1422 let left_val = self.eval_expr(left)?;
1423 if matches!(op, BinOp::And | BinOp::Or) {
1430 match (op, left_val.to_bool()?) {
1431 (BinOp::And, Some(false)) => return Ok(Value::Bool(false)),
1432 (BinOp::Or, Some(true)) => return Ok(Value::Bool(true)),
1433 _ => {}
1434 }
1435 }
1436 let right_val = self.eval_expr(right)?;
1437 self.eval_binary_op(&left_val, op, &right_val)
1438 }
1439
1440 Expr::Unary { op, expr } => {
1441 let val = self.eval_expr(expr)?;
1442 self.eval_unary_op(op, &val)
1443 }
1444
1445 Expr::Ternary {
1446 condition,
1447 then_expr,
1448 else_expr,
1449 } => {
1450 let cond_val = self.eval_expr(condition)?;
1451 if cond_val.truthy_for_condition()? {
1452 self.eval_expr(then_expr)
1453 } else {
1454 self.eval_expr(else_expr)
1455 }
1456 }
1457
1458 Expr::IfExpr {
1459 condition,
1460 then_expr,
1461 else_if_branches,
1462 else_expr,
1463 } => {
1464 let cond_val = self.eval_expr(condition)?;
1465 if cond_val.truthy_for_condition()? {
1466 self.eval_expr(then_expr)
1467 } else {
1468 for (else_if_cond, else_if_expr) in else_if_branches {
1470 let else_if_val = self.eval_expr(else_if_cond)?;
1471 if else_if_val.truthy_for_condition()? {
1472 return self.eval_expr(else_if_expr);
1473 }
1474 }
1475 if let Some(expr) = else_expr {
1477 self.eval_expr(expr)
1478 } else {
1479 Ok(Value::Na)
1480 }
1481 }
1482 }
1483
1484 Expr::Array(elements) => {
1485 let values: Result<Vec<_>, _> =
1486 elements.iter().map(|e| self.eval_expr(e)).collect();
1487 Ok(Value::Array(Rc::new(RefCell::new(values?))))
1488 }
1489
1490 Expr::Index { expr, index, id } => {
1491 let index_val = self.eval_expr(index)?.as_number()? as usize;
1492
1493 if index_val > 0 {
1499 if let Expr::Variable { name: var_name, .. } = expr.as_ref() {
1500 if let Some(h) = self.user_series_history.get(var_name) {
1501 return Ok(if h.len() >= index_val {
1502 h[h.len() - index_val].clone()
1503 } else {
1504 Value::Na
1505 });
1506 }
1507 if let Some(var) = self.variables.get(var_name) {
1510 if !matches!(var.value, Value::Series(_) | Value::Array(_)) {
1511 return Ok(Value::Na);
1512 }
1513 }
1514 }
1515 }
1516
1517 let val = self.eval_expr(expr)?;
1518
1519 if let Value::Series(series) = &val {
1523 if let Some(history) = &series.history {
1524 if index_val == 0 {
1525 return Ok((*series.current).clone());
1526 }
1527 let h = history.borrow();
1528 return Ok(if h.len() >= index_val {
1529 h[h.len() - index_val].clone()
1530 } else {
1531 Value::Na
1532 });
1533 }
1534 }
1535
1536 if let Value::Array(arr_ref) = &val {
1538 let arr = arr_ref.borrow();
1539 return arr
1540 .get(index_val)
1541 .cloned()
1542 .ok_or(RuntimeError::IndexOutOfBounds(index_val));
1543 }
1544
1545 let current = match val {
1550 Value::Series(series) => (*series.current).clone(),
1551 other => other,
1552 };
1553 if index_val == 0 {
1554 return Ok(current);
1555 }
1556 let seq = self.bar_seq;
1557 let site = self.expr_history.entry(*id).or_insert_with(SeriesSite::new);
1558 if site.bar != seq {
1559 if let Some(previous) = site.current.take() {
1563 site.history.push(previous);
1564 if site.history.len() > MAX_LOOKBACK {
1565 let drop = site.history.len() - MAX_LOOKBACK;
1566 site.history.drain(..drop);
1567 }
1568 }
1569 site.bar = seq;
1570 }
1571 site.current = Some(current);
1572 Ok(if site.history.len() >= index_val {
1573 site.history[site.history.len() - index_val].clone()
1574 } else {
1575 Value::Na
1576 })
1577 }
1578
1579 Expr::Switch { value, cases } => {
1580 let switch_val = self.eval_expr(value)?;
1581
1582 for (pattern, result) in cases {
1583 let pattern_val = self.eval_expr(pattern)?;
1585
1586 if pattern_val == Value::Bool(true)
1588 && matches!(pattern, Expr::Literal(Literal::Bool(true)))
1589 {
1590 return self.eval_expr(result);
1591 }
1592
1593 if self.values_equal(&switch_val, &pattern_val)? {
1595 return self.eval_expr(result);
1596 }
1597 }
1598
1599 Ok(Value::Na)
1601 }
1602
1603 Expr::Call {
1604 callee,
1605 type_args,
1606 args,
1607 id,
1608 ..
1609 } => {
1610 if let Expr::MemberAccess { object, member, .. } = callee.as_ref() {
1612 if let Some(method_defs) = self.methods.get(member).cloned() {
1614 let obj_value = self.eval_expr_raw(object)?;
1616
1617 let obj_type = self.get_object_type_name(&obj_value)?;
1619
1620 if let Some(method_def) =
1621 method_defs.iter().find(|m| m.type_name == obj_type)
1622 {
1623 let mut evaluated_args: Vec<EvaluatedArg<O>> =
1625 vec![EvaluatedArg::Positional(obj_value)];
1626 evaluated_args.extend(self.evaluate_arguments(args, None)?);
1627
1628 return self.call_method(
1632 &method_def.params,
1633 &method_def.body,
1634 evaluated_args,
1635 *id,
1636 );
1637 }
1638 }
1639 }
1640
1641 if let Expr::MemberAccess { object, member, .. } = callee.as_ref() {
1646 if !matches!(object.as_ref(), Expr::Call { .. }) {
1647 let receiver = self.eval_expr_raw(object)?;
1648 if let Some(namespace) = builtin_namespace(&receiver) {
1649 if let Some(Value::BuiltinFunction(builtin_fn)) =
1650 self.namespace_member(namespace, member)
1651 {
1652 let mut evaluated_args = vec![EvaluatedArg::Positional(receiver)];
1653 evaluated_args.extend(self.evaluate_arguments(args, None)?);
1654 let call_args =
1655 FunctionCallArgs::new(type_args.clone(), evaluated_args)
1656 .with_call_id(*id);
1657 return (builtin_fn.call)(self, call_args);
1658 }
1659 }
1660 }
1661 }
1662
1663 let callee_value = self.eval_expr_raw(callee)?;
1667 let signature = match &callee_value {
1668 Value::BuiltinFunction(builtin) => Some(builtin.signature),
1669 _ => None,
1670 };
1671 let evaluated_args = self.evaluate_arguments(args, signature)?;
1672
1673 match callee_value {
1675 Value::Function { params, body } => {
1676 self.call_user_function(¶ms, &body, args, evaluated_args, *id)
1679 }
1680 Value::BuiltinFunction(builtin_fn) => {
1681 let call_args = FunctionCallArgs::new(type_args.clone(), evaluated_args)
1684 .with_call_id(*id);
1685 (builtin_fn.call)(self, call_args)
1686 }
1687 Value::Object {
1690 call: Some(builtin),
1691 ..
1692 } => {
1693 let call_args = FunctionCallArgs::new(type_args.clone(), evaluated_args)
1694 .with_call_id(*id);
1695 (builtin.call)(self, call_args)
1696 }
1697 Value::Na => {
1699 let is_na = matches!(
1700 evaluated_args.first(),
1701 Some(EvaluatedArg::Positional(Value::Na)) | None
1702 );
1703 Ok(Value::Bool(is_na))
1704 }
1705 _ => Err(RuntimeError::TypeError(
1706 "Attempted to call a non-function value".to_string(),
1707 )),
1708 }
1709 }
1710
1711 Expr::MemberAccess { object, member, .. } => {
1712 let obj_value = match object.as_ref() {
1715 Expr::Variable { name, .. }
1716 if (member == "new" || member == "copy")
1717 && self.user_types.contains_key(name) =>
1718 {
1719 self.user_types[name].clone()
1720 }
1721 _ => self.eval_expr_raw(object)?,
1722 };
1723 match obj_value {
1724 Value::Object { fields, .. } => {
1725 let obj = fields.borrow();
1726 obj.get(member).cloned().ok_or_else(|| {
1727 RuntimeError::TypeError(format!("Object has no member '{}'", member))
1728 })
1729 }
1730 Value::Type { name, fields } => {
1731 if member == "new" {
1733 Ok(Value::BuiltinFunction(Builtin::untyped(
1735 Self::create_constructor(name, fields),
1736 )))
1737 } else if member == "copy" {
1738 Ok(Value::BuiltinFunction(Builtin::untyped(
1740 Self::create_copy_function(),
1741 )))
1742 } else {
1743 Err(RuntimeError::TypeError(format!(
1744 "Type '{}' has no member '{}' (only 'new' and 'copy' are supported)",
1745 name, member
1746 )))
1747 }
1748 }
1749 _ => Err(RuntimeError::TypeError(format!(
1750 "Cannot access member '{}' on non-object value",
1751 member
1752 ))),
1753 }
1754 }
1755
1756 Expr::Function { params, body } => {
1757 Ok(Value::Function {
1759 params: params.clone(),
1760 body: body.clone(),
1761 })
1762 }
1763 }
1764 }
1765
1766 fn eval_literal(&self, lit: &Literal) -> Value<O> {
1767 match lit {
1768 Literal::Int(n) => Value::Int(*n),
1769 Literal::Number(n) => Value::Number(*n),
1770 Literal::String(s) => Value::String(s.clone()),
1771 Literal::Bool(b) => Value::Bool(*b),
1772 Literal::Na => Value::Na,
1773 Literal::HexColor(hex) => Value::String(hex.clone()),
1774 }
1775 }
1776
1777 fn eval_binary_op(
1778 &self,
1779 left: &Value<O>,
1780 op: &BinOp,
1781 right: &Value<O>,
1782 ) -> Result<Value<O>, RuntimeError> {
1783 match op {
1784 BinOp::Add => {
1785 if matches!(left, Value::String(_)) || matches!(right, Value::String(_)) {
1787 Ok(Value::String(format!(
1788 "{}{}",
1789 left.as_string()?,
1790 right.as_string()?
1791 )))
1792 } else {
1793 numeric_op(left, right, |a, b| Some(a + b))
1794 }
1795 }
1796
1797 BinOp::Sub => numeric_op(left, right, |a, b| Some(a - b)),
1798
1799 BinOp::Mul => numeric_op(left, right, |a, b| Some(a * b)),
1800
1801 BinOp::Div => numeric_op(left, right, Num::checked_div),
1804
1805 BinOp::Mod => numeric_op(left, right, Num::checked_rem),
1806
1807 BinOp::Eq => {
1815 if is_na_operand(left) || is_na_operand(right) {
1816 return Ok(Value::Na);
1817 }
1818 Ok(Value::Bool(self.values_equal(left, right)?))
1819 }
1820
1821 BinOp::NotEq => {
1822 if is_na_operand(left) || is_na_operand(right) {
1823 return Ok(Value::Na);
1824 }
1825 Ok(Value::Bool(!self.values_equal(left, right)?))
1826 }
1827
1828 BinOp::Less => {
1834 if is_na_operand(left) || is_na_operand(right) {
1835 return Ok(Value::Na);
1836 }
1837 match (left.to_number()?, right.to_number()?) {
1838 (Some(l), Some(r)) => Ok(Value::Bool(l < r)),
1839 _ => Ok(Value::Na),
1840 }
1841 }
1842
1843 BinOp::Greater => {
1844 if is_na_operand(left) || is_na_operand(right) {
1845 return Ok(Value::Na);
1846 }
1847 match (left.to_number()?, right.to_number()?) {
1848 (Some(l), Some(r)) => Ok(Value::Bool(l > r)),
1849 _ => Ok(Value::Na),
1850 }
1851 }
1852
1853 BinOp::LessEq => {
1854 if is_na_operand(left) || is_na_operand(right) {
1855 return Ok(Value::Na);
1856 }
1857 match (left.to_number()?, right.to_number()?) {
1858 (Some(l), Some(r)) => Ok(Value::Bool(l <= r)),
1859 _ => Ok(Value::Na),
1860 }
1861 }
1862
1863 BinOp::GreaterEq => {
1864 if is_na_operand(left) || is_na_operand(right) {
1865 return Ok(Value::Na);
1866 }
1867 match (left.to_number()?, right.to_number()?) {
1868 (Some(l), Some(r)) => Ok(Value::Bool(l >= r)),
1869 _ => Ok(Value::Na),
1870 }
1871 }
1872
1873 BinOp::And => match (left.to_bool()?, right.to_bool()?) {
1875 (Some(false), _) | (_, Some(false)) => Ok(Value::Bool(false)),
1876 (Some(true), Some(true)) => Ok(Value::Bool(true)),
1877 _ => Ok(Value::Na),
1878 },
1879
1880 BinOp::Or => match (left.to_bool()?, right.to_bool()?) {
1882 (Some(true), _) | (_, Some(true)) => Ok(Value::Bool(true)),
1883 (Some(false), Some(false)) => Ok(Value::Bool(false)),
1884 _ => Ok(Value::Na),
1885 },
1886 }
1887 }
1888
1889 fn eval_unary_op(&self, op: &UnOp, val: &Value<O>) -> Result<Value<O>, RuntimeError> {
1890 match op {
1891 UnOp::Neg => match val.as_int() {
1893 Some(n) => Ok(Value::Int(-n)),
1894 None => match val.to_number()? {
1895 Some(n) => Ok(Value::Number(-n)),
1896 None => Ok(Value::Na),
1897 },
1898 },
1899 UnOp::Not => match val.to_bool()? {
1900 Some(b) => Ok(Value::Bool(!b)),
1901 None => Ok(Value::Na),
1902 },
1903 }
1904 }
1905
1906 fn values_equal(&self, left: &Value<O>, right: &Value<O>) -> Result<bool, RuntimeError> {
1907 match (left, right) {
1908 (Value::Int(l), Value::Int(r)) => Ok(l == r),
1909 (Value::Int(l), Value::Number(r)) | (Value::Number(r), Value::Int(l)) => {
1911 Ok((*l as f64 - r).abs() < f64::EPSILON)
1912 }
1913 (Value::Number(l), Value::Number(r)) => Ok((l - r).abs() < f64::EPSILON),
1914 (Value::String(l), Value::String(r)) => Ok(l == r),
1915 (Value::Bool(l), Value::Bool(r)) => Ok(l == r),
1916 (Value::Na, Value::Na) => Ok(true),
1917 (
1918 Value::Enum {
1919 enum_name: a_enum,
1920 field_name: a_field,
1921 ..
1922 },
1923 Value::Enum {
1924 enum_name: b_enum,
1925 field_name: b_field,
1926 ..
1927 },
1928 ) => Ok(a_enum == b_enum && a_field == b_field),
1929 _ => Ok(false),
1930 }
1931 }
1932
1933 fn is_const_expr(&self, expr: &Expr) -> bool {
1935 match expr {
1936 Expr::Literal(_) => true,
1938 Expr::Variable { name, .. } => self
1940 .variables
1941 .get(name)
1942 .map(|var| var.is_const)
1943 .unwrap_or(false),
1944 Expr::MemberAccess { object, .. } => self.is_const_expr(object),
1946 _ => false,
1948 }
1949 }
1950
1951 fn call_user_function(
1952 &mut self,
1953 params: &[pine_ast::FunctionParam],
1954 body: &[Stmt],
1955 arg_exprs: &[Argument],
1956 args: Vec<EvaluatedArg<O>>,
1957 call_id: u32,
1958 ) -> Result<Value<O>, RuntimeError> {
1959 let mut positional_values = Vec::new();
1961 let mut positional_exprs = Vec::new();
1962
1963 for (i, arg) in args.iter().enumerate() {
1964 match arg {
1965 EvaluatedArg::Positional(value) => {
1966 positional_values.push(value.clone());
1967 if let Some(Argument::Positional(expr)) = arg_exprs.get(i) {
1968 positional_exprs.push(expr);
1969 }
1970 }
1971 EvaluatedArg::Named { .. } => {
1972 return Err(RuntimeError::TypeError(
1973 "User-defined functions do not support named arguments yet".to_string(),
1974 ))
1975 }
1976 }
1977 }
1978
1979 if positional_values.len() != params.len() {
1981 return Err(RuntimeError::TypeError(format!(
1982 "Expected {} arguments, got {}",
1983 params.len(),
1984 positional_values.len()
1985 )));
1986 }
1987
1988 for (i, param) in params.iter().enumerate() {
1990 if matches!(param.type_qualifier, Some(pine_ast::TypeQualifier::Const)) {
1991 if let Some(arg_expr) = positional_exprs.get(i) {
1992 if !self.is_const_expr(arg_expr) {
1993 return Err(RuntimeError::TypeError(format!(
1994 "Parameter '{}' requires a const argument, but received a non-const value",
1995 param.name
1996 )));
1997 }
1998 }
1999 }
2000 }
2001
2002 let param_bindings: Vec<(String, Variable<O>)> = params
2005 .iter()
2006 .zip(positional_values)
2007 .map(|(param, value)| {
2008 let is_const = matches!(param.type_qualifier, Some(pine_ast::TypeQualifier::Const));
2009 (
2010 param.name.clone(),
2011 Variable {
2012 value,
2013 is_const,
2014 is_var_persistent: false,
2015 },
2016 )
2017 })
2018 .collect();
2019
2020 self.run_call_site_body(call_id, param_bindings, body)
2021 }
2022
2023 fn run_call_site_body(
2031 &mut self,
2032 call_id: u32,
2033 param_bindings: Vec<(String, Variable<O>)>,
2034 body: &[Stmt],
2035 ) -> Result<Value<O>, RuntimeError> {
2036 let param_names: std::collections::HashSet<String> =
2037 param_bindings.iter().map(|(n, _)| n.clone()).collect();
2038
2039 let saved_vars = self.variables.clone();
2041
2042 if call_id != 0 {
2046 if let Some(local_state) = self.function_local_state.get(&call_id) {
2047 for (var_name, var) in local_state {
2048 if !param_names.contains(var_name) {
2049 self.variables.insert(var_name.clone(), var.clone());
2050 }
2051 }
2052 }
2053 }
2054
2055 for (name, var) in param_bindings {
2057 self.variables.insert(name, var);
2058 }
2059
2060 let prev_call_id = self.current_call_id;
2065 self.current_call_id = call_id;
2066 let mut result: Value<O> = Value::Na;
2067 for stmt in body {
2068 if let Some(return_value) = self.execute_stmt(stmt)? {
2069 result = return_value;
2070 } else if let Stmt::Expression(expr) = stmt {
2071 result = self.eval_expr(expr)?;
2073 }
2074 }
2075 self.current_call_id = prev_call_id;
2076
2077 let call_vars = std::mem::replace(&mut self.variables, saved_vars);
2081 if call_id != 0 {
2082 let mut assigned: std::collections::HashSet<String> = std::collections::HashSet::new();
2089 collect_assigned_names(body, &mut assigned);
2090 let local_state: HashMap<String, Variable<O>> = call_vars
2091 .into_iter()
2092 .filter(|(k, _)| !param_names.contains(k) && assigned.contains(k))
2093 .collect();
2094 self.function_local_state.insert(call_id, local_state);
2095 }
2096
2097 Ok(result)
2098 }
2099
2100 fn get_object_type_name(&self, value: &Value<O>) -> Result<String, RuntimeError> {
2102 match value {
2103 Value::Object { type_name, .. } => Ok(type_name.clone()),
2104 _ => Err(RuntimeError::TypeError(
2105 "Cannot determine type of non-object value".to_string(),
2106 )),
2107 }
2108 }
2109
2110 fn call_method(
2112 &mut self,
2113 params: &[MethodParam],
2114 body: &[Stmt],
2115 args: Vec<EvaluatedArg<O>>,
2116 call_id: u32,
2117 ) -> Result<Value<O>, RuntimeError> {
2118 let mut positional_idx = 0;
2122 let mut param_bindings: Vec<(String, Variable<O>)> = Vec::with_capacity(params.len());
2123
2124 for param in params {
2125 let param_value = if positional_idx < args.len() {
2126 match &args[positional_idx] {
2127 EvaluatedArg::Positional(value) => {
2128 positional_idx += 1;
2129 value.clone()
2130 }
2131 EvaluatedArg::Named { name, value } => {
2132 if name == ¶m.name {
2133 positional_idx += 1;
2134 value.clone()
2135 } else if let Some(default_expr) = ¶m.default_value {
2136 self.eval_expr(default_expr)?
2137 } else {
2138 Value::Na
2139 }
2140 }
2141 }
2142 } else if let Some(default_expr) = ¶m.default_value {
2143 self.eval_expr(default_expr)?
2144 } else {
2145 Value::Na
2146 };
2147
2148 param_bindings.push((
2149 param.name.clone(),
2150 Variable {
2151 value: param_value,
2152 is_const: false,
2153 is_var_persistent: false,
2154 },
2155 ));
2156 }
2157
2158 self.run_call_site_body(call_id, param_bindings, body)
2159 }
2160
2161 fn create_constructor(type_name: String, fields: Vec<TypeField>) -> BuiltinFn<O> {
2163 Rc::new(
2164 move |interp: &mut Interpreter<O>, call_args: FunctionCallArgs<O>| {
2165 let mut instance_fields = HashMap::new();
2166
2167 let mut positional_idx = 0;
2169
2170 for arg in &call_args.args {
2171 match arg {
2172 EvaluatedArg::Positional(value) => {
2173 if positional_idx < fields.len() {
2175 let field = &fields[positional_idx];
2176 instance_fields.insert(field.name.clone(), value.clone());
2177 positional_idx += 1;
2178 } else {
2179 return Err(RuntimeError::TypeError(format!(
2180 "Too many arguments for type '{}' (expected {} fields)",
2181 type_name,
2182 fields.len()
2183 )));
2184 }
2185 }
2186 EvaluatedArg::Named { name, value } => {
2187 if let Some(field) = fields.iter().find(|f| f.name == *name) {
2189 instance_fields.insert(field.name.clone(), value.clone());
2190 } else {
2191 return Err(RuntimeError::TypeError(format!(
2192 "Type '{}' has no field '{}'",
2193 type_name, name
2194 )));
2195 }
2196 }
2197 }
2198 }
2199
2200 for field in &fields {
2202 if !instance_fields.contains_key(&field.name) {
2203 if let Some(default_expr) = &field.default_value {
2204 let default_val = interp.eval_expr(default_expr)?;
2205 instance_fields.insert(field.name.clone(), default_val);
2206 } else {
2207 instance_fields.insert(field.name.clone(), Value::Na);
2209 }
2210 }
2211 }
2212
2213 Ok(Value::Object {
2214 type_name: type_name.clone(),
2215 fields: Rc::new(RefCell::new(instance_fields)),
2216 call: None,
2217 value: None,
2218 })
2219 },
2220 )
2221 }
2222
2223 fn create_copy_function() -> BuiltinFn<O> {
2225 Rc::new(
2226 |_interp: &mut Interpreter<O>, call_args: FunctionCallArgs<O>| {
2227 if call_args.args.len() != 1 {
2229 return Err(RuntimeError::TypeError(
2230 "copy() expects exactly one argument".to_string(),
2231 ));
2232 }
2233
2234 match &call_args.args[0] {
2235 EvaluatedArg::Positional(value) => {
2236 if let Value::Object {
2237 type_name,
2238 fields,
2239 call,
2240 value: value_fn,
2241 } = value
2242 {
2243 let obj = fields.borrow();
2245 let copied_fields = obj.clone();
2246 Ok(Value::Object {
2247 type_name: type_name.clone(),
2248 fields: Rc::new(RefCell::new(copied_fields)),
2249 call: call.clone(),
2250 value: value_fn.clone(),
2251 })
2252 } else {
2253 Err(RuntimeError::TypeError(
2254 "copy() expects an object argument".to_string(),
2255 ))
2256 }
2257 }
2258 EvaluatedArg::Named { .. } => Err(RuntimeError::TypeError(
2259 "copy() does not accept named arguments".to_string(),
2260 )),
2261 }
2262 },
2263 )
2264 }
2265}
2266
2267impl<O: PineOutput> Default for Interpreter<O> {
2268 fn default() -> Self {
2269 Self::new()
2270 }
2271}