1use crate::arena::Arena;
79use crate::gc::{Gc, GcContext, GcTrace, GcView};
80use crate::interner::{InternedStr, StrInterner};
81use crate::lexer::Lexer;
82use crate::parser::Parser;
83use crate::span::{SourceId, SpanContextId, SpanId, SpanManager};
84use crate::{FHashMap, ast};
85
86mod analyze;
87mod data;
88mod error;
89mod eval;
90mod ir;
91mod stdlib;
92
93use data::{
94 ArrayData, BuiltInFunc, FuncData, FuncKind, FuncParams, ObjectData, ObjectLayer,
95 SimpleObjectBuilder, ThunkData, ThunkEnv, ThunkEnvData, ThunkState, ValueData,
96};
97pub use error::{AnalyzeError, EvalError, EvalErrorKind, EvalErrorValueType, LoadError};
98
99#[derive(Clone, Debug)]
104pub struct ImportError;
105
106#[derive(Clone, Debug)]
110pub struct NativeError;
111
112pub trait Callbacks<'p> {
117 fn import(
119 &mut self,
120 program: &mut Program<'p>,
121 from: SpanId,
122 path: &str,
123 ) -> Result<Thunk<'p>, ImportError>;
124
125 fn import_str(
127 &mut self,
128 program: &mut Program<'p>,
129 from: SpanId,
130 path: &str,
131 ) -> Result<String, ImportError>;
132
133 fn import_bin(
135 &mut self,
136 program: &mut Program<'p>,
137 from: SpanId,
138 path: &str,
139 ) -> Result<Vec<u8>, ImportError>;
140
141 fn trace(&mut self, program: &mut Program<'p>, message: &str, stack: &[EvalStackTraceItem]);
143
144 fn native_call(
149 &mut self,
150 program: &mut Program<'p>,
151 name: InternedStr<'p>,
152 args: &[Value<'p>],
153 ) -> Result<Value<'p>, NativeError>;
154}
155
156#[derive(Clone, Debug, PartialEq, Eq)]
157pub enum EvalStackTraceItem {
158 Expr {
159 span: SpanId,
160 },
161 Call {
162 span: Option<SpanId>,
163 name: Option<String>,
164 },
165 Variable {
166 span: SpanId,
167 name: String,
168 },
169 ArrayItem {
170 span: Option<SpanId>,
171 index: usize,
172 },
173 ObjectField {
174 span: Option<SpanId>,
175 name: String,
176 },
177 CompareArrayItem {
178 index: usize,
179 },
180 CompareObjectField {
181 name: String,
182 },
183 ManifestArrayItem {
184 index: usize,
185 },
186 ManifestObjectField {
187 name: String,
188 },
189 Import {
190 span: SpanId,
191 },
192}
193
194pub struct Program<'p> {
198 arena: &'p Arena,
199 str_interner: StrInterner<'p>,
200 span_mgr: SpanManager,
201 gc_ctx: GcContext<'p>,
202 objs_after_last_gc: usize,
203 max_stack: usize,
204 exprs: Exprs<'p>,
205 stdlib_src_id: SourceId,
206 stdlib_data: &'static [u8],
207 stdlib_base_obj: Option<GcView<ObjectData<'p>>>,
208 stdlib_extra: FHashMap<InternedStr<'p>, GcView<ThunkData<'p>>>,
209 empty_array: GcView<ArrayData<'p>>,
210 identity_func: GcView<FuncData<'p>>,
211 ext_vars: FHashMap<InternedStr<'p>, GcView<ThunkData<'p>>>,
212 native_funcs: FHashMap<InternedStr<'p>, GcView<FuncData<'p>>>,
213}
214
215struct Exprs<'p> {
216 null: &'p ir::Expr<'p>,
217 false_: &'p ir::Expr<'p>,
218 true_: &'p ir::Expr<'p>,
219 self_obj: &'p ir::Expr<'p>,
220 top_obj: &'p ir::Expr<'p>,
221}
222
223impl<'p> Program<'p> {
224 pub fn new(arena: &'p Arena) -> Self {
226 let str_interner = StrInterner::new();
227 let gc_ctx = GcContext::new();
228 let exprs = Exprs {
229 null: arena.alloc(ir::Expr::Null),
230 false_: arena.alloc(ir::Expr::Bool(false)),
231 true_: arena.alloc(ir::Expr::Bool(true)),
232 self_obj: arena.alloc(ir::Expr::SelfObj),
233 top_obj: arena.alloc(ir::Expr::TopObj),
234 };
235
236 let stdlib_data = stdlib::STDLIB_DATA;
237 let mut span_mgr = SpanManager::new();
238 let (stdlib_span_ctx, stdlib_src_id) = span_mgr.insert_source_context(stdlib_data.len());
239
240 let stdlib_extra = Self::build_stdlib_extra(arena, &str_interner, &gc_ctx, &exprs);
241
242 let empty_array: GcView<ArrayData<'p>> = gc_ctx.alloc_view(Box::new([]));
243 let identity_func = gc_ctx.alloc_view(FuncData::new_identity_func(
244 Some(str_interner.intern(arena, "id")),
245 arena.alloc([(str_interner.intern(arena, "x"), None)]),
246 ));
247
248 let mut this = Self {
249 arena,
250 str_interner,
251 span_mgr,
252 gc_ctx,
253 objs_after_last_gc: 0,
254 max_stack: 500,
255 exprs,
256 stdlib_src_id,
257 stdlib_data,
258 stdlib_base_obj: None,
259 stdlib_extra,
260 empty_array,
261 identity_func,
262 ext_vars: FHashMap::default(),
263 native_funcs: FHashMap::default(),
264 };
265 this.load_stdlib(stdlib_span_ctx);
266 this
267 }
268
269 #[inline]
270 pub fn str_interner(&self) -> &StrInterner<'p> {
271 &self.str_interner
272 }
273
274 #[inline]
275 pub fn intern_str(&self, s: &str) -> InternedStr<'p> {
276 self.str_interner.intern(self.arena, s)
277 }
278
279 #[inline]
280 pub fn span_manager(&self) -> &SpanManager {
281 &self.span_mgr
282 }
283
284 #[inline]
285 pub fn span_manager_mut(&mut self) -> &mut SpanManager {
286 &mut self.span_mgr
287 }
288
289 pub fn gc(&mut self) {
291 self.gc_ctx.gc();
292 self.objs_after_last_gc = self.gc_ctx.num_objects();
293 }
294
295 pub fn maybe_gc(&mut self) {
297 let num_objects = self.gc_ctx.num_objects();
298 if num_objects > 1000 && (num_objects / 2) > self.objs_after_last_gc {
299 self.gc();
300 }
301 }
302
303 pub fn set_max_stack(&mut self, max_stack: usize) {
307 self.max_stack = max_stack;
308 }
309
310 pub fn get_stdlib_source(&self) -> (SourceId, &[u8]) {
313 (self.stdlib_src_id, self.stdlib_data)
314 }
315
316 pub fn add_ext_var(&mut self, name: InternedStr<'p>, thunk: &Thunk<'p>) {
321 match self.ext_vars.entry(name) {
322 std::collections::hash_map::Entry::Occupied(entry) => {
323 panic!("external variable {:?} already set", entry.key());
324 }
325 std::collections::hash_map::Entry::Vacant(entry) => {
326 entry.insert(thunk.data.clone());
327 }
328 }
329 }
330
331 pub fn register_native_func(&mut self, name: InternedStr<'p>, params: &[InternedStr<'p>]) {
344 match self.native_funcs.entry(name) {
345 std::collections::hash_map::Entry::Occupied(entry) => {
346 panic!("native function {:?} already registered", entry.key());
347 }
348 std::collections::hash_map::Entry::Vacant(entry) => {
349 let params_order: Vec<_> = params.iter().map(|&name| (name, None)).collect();
350 entry.insert(self.gc_ctx.alloc_view(FuncData::new(
351 self.arena.alloc_slice(¶ms_order),
352 FuncKind::Native { name },
353 )));
354 }
355 }
356 }
357
358 #[must_use]
359 #[inline]
360 fn gc_alloc<T: GcTrace + 'p>(&self, data: T) -> Gc<T> {
361 self.gc_ctx.alloc(data)
362 }
363
364 #[must_use]
365 #[inline]
366 fn gc_alloc_view<T: GcTrace + 'p>(&self, data: T) -> GcView<T> {
367 self.gc_ctx.alloc_view(data)
368 }
369
370 fn insert_thunk_with_value(&mut self, value: ValueData<'p>) -> GcView<ThunkData<'p>> {
371 self.gc_alloc_view(ThunkData::new_done(value))
372 }
373
374 pub fn value_to_thunk(&mut self, value: &Value<'p>) -> Thunk<'p> {
376 Thunk::new(self.insert_thunk_with_value(value.inner.clone()))
377 }
378
379 pub fn make_array(&mut self, items: &[Value<'p>]) -> Value<'p> {
381 let array = self.make_value_array(items.iter().map(|item| item.inner.clone()));
382 Value::from_value(ValueData::Array(array))
383 }
384
385 pub fn make_object(&mut self, obj_fields: &[(InternedStr<'p>, Value<'p>)]) -> Value<'p> {
387 let mut obj_builder = SimpleObjectBuilder::new();
388 for (name, value) in obj_fields.iter() {
389 obj_builder.insert_field(
390 *name,
391 ast::Visibility::Default,
392 self.gc_alloc(ThunkData::new_done(value.inner.clone())),
393 );
394 }
395
396 let obj = self.gc_alloc(obj_builder.build());
397 Value::from_value(ValueData::Object(obj))
398 }
399
400 pub fn load_source(
405 &mut self,
406 span_ctx: SpanContextId,
407 input: &[u8],
408 with_stdlib: bool,
409 this_file: &str,
410 ) -> Result<Thunk<'p>, LoadError> {
411 let ast_arena = Arena::new();
412 let lexer = Lexer::new(
413 self.arena,
414 &ast_arena,
415 &self.str_interner,
416 &mut self.span_mgr,
417 span_ctx,
418 input,
419 );
420 let tokens = lexer.lex_to_eof(false)?;
421
422 let parser = Parser::new(
423 self.arena,
424 &ast_arena,
425 &self.str_interner,
426 &mut self.span_mgr,
427 tokens,
428 );
429 let root_expr = parser.parse_root_expr()?;
430
431 let env = if with_stdlib {
432 let stdlib_obj = self.make_custom_stdlib(this_file);
433 let stdlib_thunk =
434 self.gc_alloc_view(ThunkData::new_done(ValueData::Object(stdlib_obj)));
435
436 let mut env = FHashMap::default();
437 env.insert(self.intern_str("std"), Thunk::new(stdlib_thunk));
438
439 Some(env)
440 } else {
441 None
442 };
443 let thunk = self.analyze(&root_expr, env)?;
444 Ok(thunk)
445 }
446
447 fn analyze(
448 &mut self,
449 ast: &ast::Expr<'p, '_>,
450 env: Option<FHashMap<InternedStr<'p>, Thunk<'p>>>,
451 ) -> Result<Thunk<'p>, AnalyzeError> {
452 let analyze_env = env
453 .as_ref()
454 .map(|env| env.keys().cloned().collect())
455 .unwrap_or_default();
456 let ir_expr = analyze::Analyzer::new(self).analyze(ast, analyze_env)?;
457
458 let mut thunk_env_data = ThunkEnvData::new(None);
459 if let Some(env) = env {
460 for (name, value) in env.iter() {
461 thunk_env_data.set_var(*name, Gc::from(&value.data));
462 }
463 }
464 let thunk_env = self.gc_alloc(ThunkEnv::from(thunk_env_data));
465
466 let thunk = self.gc_alloc_view(ThunkData::new_pending_expr(ir_expr, thunk_env));
467
468 Ok(Thunk::new(thunk))
469 }
470
471 pub fn eval_value(
473 &mut self,
474 thunk: &Thunk<'p>,
475 callbacks: &mut dyn Callbacks<'p>,
476 ) -> Result<Value<'p>, EvalError> {
477 let output = eval::Evaluator::eval(
478 self,
479 Some(callbacks),
480 eval::EvalInput::Value(thunk.data.clone()),
481 )
482 .map_err(|e| *e)?;
483 let eval::EvalOutput::Value(value) = output else {
484 unreachable!();
485 };
486 Ok(Value::from_value(value))
487 }
488
489 fn eval_value_internal(&mut self, thunk: &Thunk<'p>) -> Result<ValueData<'p>, EvalError> {
490 let output = eval::Evaluator::eval(self, None, eval::EvalInput::Value(thunk.data.clone()))
491 .map_err(|e| *e)?;
492 let eval::EvalOutput::Value(value) = output else {
493 unreachable!();
494 };
495 Ok(value)
496 }
497
498 pub fn eval_call(
500 &mut self,
501 func: &Thunk<'p>,
502 pos_args: &[Thunk<'p>],
503 named_args: &[(InternedStr<'p>, Thunk<'p>)],
504 callbacks: &mut dyn Callbacks<'p>,
505 ) -> Result<Value<'p>, EvalError> {
506 let output = eval::Evaluator::eval(
507 self,
508 Some(callbacks),
509 eval::EvalInput::Call(
510 func.data.clone(),
511 eval::TopLevelArgs {
512 positional: pos_args.iter().map(|thunk| thunk.data.clone()).collect(),
513 named: named_args
514 .iter()
515 .map(|(name, thunk)| (*name, thunk.data.clone()))
516 .collect(),
517 },
518 ),
519 )
520 .map_err(|e| *e)?;
521 let eval::EvalOutput::Value(value) = output else {
522 unreachable!();
523 };
524 Ok(Value::from_value(value))
525 }
526
527 pub fn manifest_json(
529 &mut self,
530 value: &Value<'p>,
531 multiline: bool,
532 ) -> Result<String, EvalError> {
533 let thunk = self.insert_thunk_with_value(value.inner.clone());
534 let output =
535 eval::Evaluator::eval(self, None, eval::EvalInput::ManifestJson(thunk, multiline))
536 .map_err(|e| *e)?;
537 let eval::EvalOutput::String(s) = output else {
538 unreachable!();
539 };
540 Ok(s)
541 }
542}
543
544#[derive(Clone)]
550pub struct Thunk<'p> {
551 data: GcView<ThunkData<'p>>,
552}
553
554impl<'p> Thunk<'p> {
555 #[inline]
556 fn new(data: GcView<ThunkData<'p>>) -> Self {
557 Self { data }
558 }
559}
560
561#[derive(Clone)]
567pub struct Value<'p> {
568 inner: ValueData<'p>,
569}
570
571impl<'p> Value<'p> {
572 #[inline]
573 fn from_value(inner: ValueData<'p>) -> Self {
574 Self { inner }
575 }
576
577 #[inline]
578 fn from_thunk(thunk: &ThunkData<'p>) -> Self {
579 Self {
580 inner: match *thunk.state() {
581 ThunkState::Done(ref value) => value.clone(),
582 _ => panic!("thunk not evaluated"),
583 },
584 }
585 }
586
587 #[inline]
592 pub fn null() -> Self {
593 Self::from_value(ValueData::Null)
594 }
595
596 #[inline]
601 pub fn bool(value: bool) -> Self {
602 Self::from_value(ValueData::Bool(value))
603 }
604
605 #[inline]
610 pub fn number(value: f64) -> Self {
611 Self::from_value(ValueData::Number(value))
612 }
613
614 #[inline]
619 pub fn string(s: &str) -> Self {
620 Self::from_value(ValueData::String(s.into()))
621 }
622
623 #[must_use]
624 pub fn kind(&self) -> ValueKind<'p> {
625 match self.inner {
626 ValueData::Null => ValueKind::Null,
627 ValueData::Bool(value) => ValueKind::Bool(value),
628 ValueData::Number(value) => ValueKind::Number(value),
629 ValueData::String(ref s) => ValueKind::String((**s).into()),
630 ValueData::Array(ref array) => ValueKind::Array(Self::extract_array(&array.view())),
631 ValueData::Object(ref object) => {
632 ValueKind::Object(Self::extract_object(&object.view()))
633 }
634 ValueData::Function(_) => ValueKind::Function,
635 }
636 }
637
638 #[must_use]
639 #[inline]
640 pub fn is_null(&self) -> bool {
641 matches!(self.inner, ValueData::Null)
642 }
643
644 #[must_use]
645 #[inline]
646 pub fn is_bool(&self) -> bool {
647 matches!(self.inner, ValueData::Bool(_))
648 }
649
650 #[must_use]
651 #[inline]
652 pub fn as_bool(&self) -> Option<bool> {
653 if let ValueData::Bool(value) = self.inner {
654 Some(value)
655 } else {
656 None
657 }
658 }
659
660 #[must_use]
661 #[inline]
662 pub fn is_number(&self) -> bool {
663 matches!(self.inner, ValueData::Number(_))
664 }
665
666 #[must_use]
667 #[inline]
668 pub fn as_number(&self) -> Option<f64> {
669 if let ValueData::Number(value) = self.inner {
670 Some(value)
671 } else {
672 None
673 }
674 }
675
676 #[must_use]
677 #[inline]
678 pub fn is_string(&self) -> bool {
679 matches!(self.inner, ValueData::String(_))
680 }
681
682 #[must_use]
683 #[inline]
684 pub fn to_string(&self) -> Option<String> {
685 if let ValueData::String(ref s) = self.inner {
686 Some((**s).into())
687 } else {
688 None
689 }
690 }
691
692 #[must_use]
693 #[inline]
694 pub fn is_array(&self) -> bool {
695 matches!(self.inner, ValueData::Array(_))
696 }
697
698 #[must_use]
699 pub fn to_array(&self) -> Option<Vec<Self>> {
700 if let ValueData::Array(ref array) = self.inner {
701 Some(Self::extract_array(&array.view()))
702 } else {
703 None
704 }
705 }
706
707 #[must_use]
708 #[inline]
709 pub fn is_object(&self) -> bool {
710 matches!(self.inner, ValueData::Object(_))
711 }
712
713 #[must_use]
714 pub fn to_object(&self) -> Option<Vec<(InternedStr<'p>, Self)>> {
715 if let ValueData::Object(ref object) = self.inner {
716 Some(Self::extract_object(&object.view()))
717 } else {
718 None
719 }
720 }
721
722 #[must_use]
723 #[inline]
724 pub fn is_function(&self) -> bool {
725 matches!(self.inner, ValueData::Function(_))
726 }
727
728 fn extract_array(array: &ArrayData<'p>) -> Vec<Self> {
729 array
730 .iter()
731 .map(|item| Self::from_thunk(&item.view()))
732 .collect()
733 }
734
735 fn extract_object(object: &ObjectData<'p>) -> Vec<(InternedStr<'p>, Self)> {
736 let mut fields = Vec::new();
737 for &(name, visibility) in object.get_fields_order().iter() {
738 if visibility != ast::Visibility::Hidden {
739 let (_, field) = object.find_field(0, name).unwrap();
740 let thunk = field.thunk.get().unwrap().clone();
741 fields.push((name, Self::from_thunk(&thunk.view())));
742 }
743 }
744 fields
745 }
746}
747
748#[derive(Clone)]
749pub enum ValueKind<'p> {
750 Null,
751 Bool(bool),
752 Number(f64),
753 String(String),
754 Array(Vec<Value<'p>>),
755 Object(Vec<(InternedStr<'p>, Value<'p>)>),
756 Function,
757}