1use std::{rc::Rc};
2use fnv::{FnvBuildHasher};
3use quickscope::ScopeMap;
4use crate::{lang::{Sequence, Expression}, RantValue, Rant};
5use crate::runtime::*;
6use super::{output::OutputWriter};
7
8type CallStackVector<I> = SmallVec<[StackFrame<I>; super::CALL_STACK_INLINE_COUNT]>;
9
10pub struct CallStack<I> {
12 frames: CallStackVector<I>,
13 locals: ScopeMap<InternalString, RantVar, FnvBuildHasher>,
14}
15
16impl<I> Default for CallStack<I> {
17 #[inline]
18 fn default() -> Self {
19 Self::new()
20 }
21}
22
23impl<I> CallStack<I> {
24 #[inline]
25 pub(crate) fn new() -> Self {
26 Self {
27 frames: Default::default(),
28 locals: Default::default(),
29 }
30 }
31
32 #[inline]
34 pub fn is_empty(&self) -> bool {
35 self.frames.is_empty()
36 }
37
38 #[inline]
40 pub fn len(&self) -> usize {
41 self.frames.len()
42 }
43
44 #[inline]
46 pub fn pop_frame(&mut self) -> Option<StackFrame<I>> {
47 if let Some(frame) = self.frames.pop() {
48 if frame.has_scope {
49 self.locals.pop_layer();
50 }
51 return Some(frame)
52 }
53 None
54 }
55
56 #[inline]
58 pub fn push_frame(&mut self, frame: StackFrame<I>) {
59 if frame.has_scope {
60 self.locals.push_layer();
61 }
62 self.frames.push(frame);
63 }
64
65 #[inline]
67 pub fn top_mut(&mut self) -> Option<&mut StackFrame<I>> {
68 self.frames.last_mut()
69 }
70
71
72 #[inline]
74 pub fn parent_mut(&mut self, depth: usize) -> Option<&mut StackFrame<I>> {
75 self.frames.iter_mut().rev().nth(depth)
76 }
77
78 #[inline]
80 pub fn parent(&self, depth: usize) -> Option<&StackFrame<I>> {
81 self.frames.iter().rev().nth(depth)
82 }
83
84 #[inline]
86 pub fn top(&self) -> Option<&StackFrame<I>> {
87 self.frames.last()
88 }
89
90 pub fn gen_stack_trace(&self) -> String {
92 let mut trace = String::new();
93 let mut last_frame_info: Option<(String, usize)> = None;
94 for frame in self.frames.iter().rev() {
95 let current_frame_string = frame.to_string();
96
97 if let Some((last_frame_string, count)) = last_frame_info.take() {
98 if current_frame_string == last_frame_string {
99 last_frame_info = Some((last_frame_string, count + 1));
100 } else {
101 match count {
103 1 => trace.push_str(&format!("-> {}\n", last_frame_string)),
104 _ => trace.push_str(&format!("-> {} ({} frames)\n", last_frame_string, count)),
105 }
106 last_frame_info = Some((current_frame_string, 1));
107 }
108 } else {
109 last_frame_info = Some((current_frame_string, 1));
110 }
111 }
112
113 if let Some((last_frame_string, count)) = last_frame_info.take() {
115 match count {
116 1 => trace.push_str(&format!("-> {}", last_frame_string)),
117 _ => trace.push_str(&format!("-> {} ({} frames)", last_frame_string, count)),
118 }
119 }
120
121 trace
122 }
123
124 #[inline]
126 pub fn set_var_value(&mut self, context: &mut Rant, id: &str, access: VarAccessMode, val: RantValue) -> RuntimeResult<()> {
127 match access {
128 VarAccessMode::Local => {
129 if let Some(var) = self.locals.get_mut(id) {
130 if !var.write(val) {
131 runtime_error!(RuntimeErrorType::InvalidAccess, "cannot reassign local constant '{}'", id);
132 }
133 return Ok(())
134 }
135 },
136 VarAccessMode::Descope(n) => {
137 if let Some(var) = self.locals.get_parent_mut(id, n) {
138 if !var.write(val) {
139 runtime_error!(RuntimeErrorType::InvalidAccess, "cannot reassign local constant '{}'", id);
140 }
141 return Ok(())
142 }
143 },
144 VarAccessMode::ExplicitGlobal => {}
146 }
147
148 if context.has_global(id) {
150 if !context.set_global(id, val) {
151 runtime_error!(RuntimeErrorType::InvalidAccess, "cannot reassign global constant '{}'", id);
152 }
153 return Ok(())
154 }
155
156 runtime_error!(RuntimeErrorType::InvalidAccess, "variable '{}' not found", id);
157 }
158
159 #[inline]
161 pub fn get_var_value(&self, context: &Rant, id: &str, access: VarAccessMode, prefer_function: bool) -> RuntimeResult<RantValue> {
162
163 macro_rules! percolating_func_lookup {
164 ($value_iter:expr) => {
165 if let Some(mut vars) = $value_iter {
166 if let Some(mut var) = vars.next() {
167 if !var.value_ref().is_callable() {
169 if let Some(func_var) = vars
170 .find(|v| v.value_ref().is_callable())
171 .or_else(|| context.get_global_var(id).filter(|v| v.value_ref().is_callable()))
172 {
173 var = func_var;
174 }
175 }
176 return Ok(var.value_cloned())
177 }
178 }
179 }
180 }
181
182 match access {
183 VarAccessMode::Local => {
184 if prefer_function {
186 percolating_func_lookup!(self.locals.get_all(id));
187 } else if let Some(var) = self.locals.get(id) {
188 return Ok(var.value_cloned())
189 }
190 },
191 VarAccessMode::Descope(n) => {
192 if prefer_function {
193 percolating_func_lookup!(self.locals.get_parents(id, n));
194 } else if let Some(var) = self.locals.get_parent(id, n) {
195 return Ok(var.value_cloned())
196 }
197 },
198 VarAccessMode::ExplicitGlobal => {},
199 }
200
201 if let Some(val) = context.get_global(id) {
203 return Ok(val)
204 }
205
206 Err(RuntimeError {
207 error_type: RuntimeErrorType::InvalidAccess,
208 description: Some(format!("{} '{}' not found", if prefer_function { "function" } else { "variable" }, id)),
209 stack_trace: None,
210 })
211 }
212
213 pub fn get_var_mut<'a>(&'a mut self, context: &'a mut Rant, id: &str, access: VarAccessMode) -> RuntimeResult<&'a mut RantVar> {
215 match access {
216 VarAccessMode::Local => {
217 if let Some(var) = self.locals.get_mut(id) {
218 return Ok(var)
219 }
220 },
221 VarAccessMode::Descope(n) => {
222 if let Some(var) = self.locals.get_parent_mut(id, n) {
223 return Ok(var)
224 }
225 },
226 VarAccessMode::ExplicitGlobal => {},
227 }
228
229 if let Some(var) = context.get_global_var_mut(id) {
231 return Ok(var)
232 }
233
234 Err(RuntimeError {
235 error_type: RuntimeErrorType::InvalidAccess,
236 description: Some(format!("variable '{}' not found", id)),
237 stack_trace: None,
238 })
239 }
240
241 pub fn def_local_var(&mut self, id: &str, var: RantVar) -> RuntimeResult<()> {
247 self.locals.define(InternalString::from(id), var);
248 Ok(())
249 }
250
251 #[inline]
257 pub fn def_var_value(&mut self, context: &mut Rant, id: &str, access: VarAccessMode, val: RantValue, is_const: bool) -> RuntimeResult<()> {
258 #[cfg(feature = "cli")]
260 let access = match access {
261 VarAccessMode::Local if self.locals.depth() <= 2 => VarAccessMode::ExplicitGlobal,
262 VarAccessMode::Descope(n) if self.locals.depth() - n <= 2 => VarAccessMode::ExplicitGlobal,
263 other => other,
264 };
265
266 match access {
267 VarAccessMode::Local => {
268 if let Some(v) = self.locals.get(id) {
270 if v.is_const() && self.locals.depth_of(id) == Some(0) {
271 runtime_error!(RuntimeErrorType::InvalidAccess, "attempted to redefine local constant '{}'", id);
272 }
273 }
274
275 let variable = if is_const { RantVar::ByValConst(val) } else { RantVar::ByVal(val) };
276 self.locals.define(InternalString::from(id), variable);
277 return Ok(())
278 },
279 VarAccessMode::Descope(descope_count) => {
280 if let Some((v, vd)) = self.locals.get_parent_depth(id, descope_count) {
282 if v.is_const() && vd == descope_count {
283 runtime_error!(RuntimeErrorType::InvalidAccess, "attempted to redefine parent constant '{}'", id);
284 }
285 }
286
287 let variable = if is_const { RantVar::ByValConst(val) } else { RantVar::ByVal(val) };
288 self.locals.define_parent(InternalString::from(id), variable, descope_count);
289 return Ok(())
290 },
291 VarAccessMode::ExplicitGlobal => {}
292 }
293
294 if !(if is_const { context.set_global_const(id, val) } else { context.set_global(id, val) }) {
296 runtime_error!(RuntimeErrorType::InvalidAccess, "attempted to redefine global constant '{}'", id);
297 }
298
299 Ok(())
300 }
301
302 #[inline]
305 pub fn taste_for_first(&self, target_flavor: StackFrameFlavor) -> Option<usize> {
306 for (frame_index, frame) in self.frames.iter().rev().enumerate() {
307 if frame.flavor > target_flavor {
308 return None
309 } else if frame.flavor == target_flavor {
310 return Some(frame_index)
311 }
312 }
313 None
314 }
315
316 #[inline]
319 pub fn taste_for(&self, target_flavor: StackFrameFlavor) -> Option<usize> {
320 for (frame_index, frame) in self.frames.iter().rev().enumerate() {
321 if frame.flavor == target_flavor {
322 return Some(frame_index)
323 }
324 }
325 None
326 }
327}
328
329pub struct StackFrame<I> {
331 sequence: Option<Rc<Sequence>>,
333 has_scope: bool,
335 pc: usize,
337 output: OutputWriter,
339 intents: Vec<I>,
341 debug_cursor: (usize, usize),
343 origin: Rc<RantProgramInfo>,
345 flavor: StackFrameFlavor,
347}
348
349impl<I> StackFrame<I> {
350 #[inline]
351 pub(crate) fn new(sequence: Rc<Sequence>, prev_output: Option<&OutputWriter>) -> Self {
352 Self {
353 origin: Rc::clone(&sequence.origin),
354 sequence: Some(sequence),
355 output: OutputWriter::new(prev_output),
356 has_scope: true,
357 pc: 0,
358 intents: Default::default(),
359 debug_cursor: (0, 0),
360 flavor: Default::default(),
361 }
362 }
363
364 #[inline]
365 pub(crate) fn with_extended_config(
366 sequence: Option<Rc<Sequence>>,
367 prev_output: Option<&OutputWriter>,
368 origin: Rc<RantProgramInfo>,
369 has_scope: bool,
370 debug_pos: (usize, usize),
371 flavor: StackFrameFlavor
372 ) -> Self
373 {
374 Self {
375 origin,
376 sequence,
377 output: OutputWriter::new(prev_output),
378 has_scope,
379 pc: 0,
380 intents: Default::default(),
381 debug_cursor: debug_pos,
382 flavor,
383 }
384 }
385
386 #[inline]
387 pub(crate) fn without_scope(self) -> Self {
388 let mut frame = self;
389 frame.has_scope = false;
390 frame
391 }
392
393 #[inline]
394 pub(crate) fn has_scope(self, has_scope: bool) -> Self {
395 let mut frame = self;
396 frame.has_scope = has_scope;
397 frame
398 }
399
400 #[inline(always)]
401 pub(crate) fn with_flavor(self, flavor: StackFrameFlavor) -> Self {
402 let mut frame = self;
403 frame.flavor = flavor;
404 frame
405 }
406}
407
408impl<I> StackFrame<I> {
409 #[inline]
410 pub(crate) fn seq_next(&mut self) -> Option<Rc<Expression>> {
411 if self.is_done() {
412 return None
413 }
414
415 let next = self.sequence.as_ref().and_then(|seq| seq.get(self.pc).map(Rc::clone));
416
417 self.pc += 1;
419
420 next
421 }
422
423 #[inline(always)]
425 pub fn pc(&self) -> usize {
426 self.pc
427 }
428
429 #[inline(always)]
431 pub fn flavor(&self) -> StackFrameFlavor {
432 self.flavor
433 }
434
435 #[inline(always)]
436 pub fn output(&self) -> &OutputWriter {
437 &self.output
438 }
439
440 #[inline(always)]
441 pub fn output_mut(&mut self) -> &mut OutputWriter {
442 &mut self.output
443 }
444
445 #[inline]
446 pub fn render_and_reset_output(&mut self) -> RantValue {
447 let mut other = OutputWriter::new(Some(&self.output));
448 std::mem::swap(&mut self.output, &mut other);
449 other.render_value()
450 }
451
452 #[inline(always)]
453 pub fn origin(&self) -> &Rc<RantProgramInfo> {
454 &self.origin
455 }
456
457 #[inline(always)]
458 pub fn debug_cursor(&self) -> (usize, usize) {
459 self.debug_cursor
460 }
461
462 #[inline]
463 pub fn origin_name(&self) -> &str {
464 self.origin.path
465 .as_deref()
466 .unwrap_or_else(||
467 self.origin.name
468 .as_deref()
469 .unwrap_or(DEFAULT_PROGRAM_NAME)
470 )
471 }
472
473 #[inline(always)]
475 pub fn push_intent(&mut self, intent: I) {
476 self.intents.push(intent);
477 }
478
479 #[inline(always)]
481 pub(crate) fn pop_intent(&mut self) -> Option<I> {
482 self.intents.pop()
483 }
484
485 #[inline]
487 pub fn set_debug_info(&mut self, info: &DebugInfo) {
488 match info {
489 DebugInfo::Location { line, col } => self.debug_cursor = (*line, *col),
490 }
491 }
492}
493
494impl<I> StackFrame<I> {
495 #[inline(always)]
496 fn is_done(&self) -> bool {
497 self.sequence.is_none() || self.pc >= self.sequence.as_ref().unwrap().len()
498 }
499
500 #[inline]
502 pub fn write_frag(&mut self, frag: &str) {
503 self.output.write_frag(frag);
504 }
505
506 #[inline]
508 pub fn write_ws(&mut self, ws: &str) {
509 self.output.write_ws(ws);
510 }
511
512 #[inline]
514 pub fn write<T: IntoRant>(&mut self, val: T) {
515 self.output.write_value(val.into_rant());
516 }
517
518 #[inline]
520 pub fn into_output(self) -> RantValue {
521 self.output.render_value()
522 }
523}
524
525impl<I> Display for StackFrame<I> {
526 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
527 write!(f, "[{}:{}:{}] in {}",
528 self.origin_name(),
529 self.debug_cursor.0,
530 self.debug_cursor.1,
531 self.sequence.as_ref()
532 .and_then(|seq| seq.name().map(|name| name.as_str()))
533 .unwrap_or_else(|| self.flavor.name()),
534 )
535 }
536}
537
538#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
542pub enum StackFrameFlavor {
543 Original,
545 NativeCall,
547 BlockElement,
549 RepeaterElement,
551 FunctionBody,
553 DynamicKeyExpression,
555 ArgumentExpression,
557}
558
559impl Default for StackFrameFlavor {
560 fn default() -> Self {
561 Self::Original
562 }
563}
564
565impl StackFrameFlavor {
566 fn name(&self) -> &'static str {
567 match self {
568 Self::Original => "sequence",
569 Self::NativeCall => "native call",
570 Self::BlockElement => "block element",
571 Self::RepeaterElement => "repeater element",
572 Self::FunctionBody => "function body",
573 Self::DynamicKeyExpression => "dynamic key",
574 Self::ArgumentExpression => "argument",
575 }
576 }
577}