diff --git a/src/ast.rs b/src/ast.rs index 52c493a..4ebfbba 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -126,6 +126,14 @@ pub enum Expr { }, #[serde(rename = "expr_neg")] Negate { expr: Box }, + #[serde(rename = "expr_import")] + Import(ExprStr), +} +#[derive(Debug, PartialEq, Eq, Clone, Deserialize)] +#[serde(rename = "expr_str")] +pub struct ExprStr { + #[serde(deserialize_with = "deserialize_string_content_opt")] + pub content: Rc, } fn deserialize_string_content_opt<'de, D: serde::Deserializer<'de>>( diff --git a/src/evaluator.rs b/src/evaluator.rs index 2eb5bd3..4d8fb8e 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -1,4 +1,5 @@ use crate::ast::ArrayItem; +use crate::ast::ExprStr; use crate::ast::Ident; use crate::ast::ObjItem; use crate::ast::TopTerm; @@ -22,7 +23,6 @@ use crate::Program; use crate::Value; use gc::Gc; -use std::borrow::Borrow; use std::collections::HashMap; use std::path::PathBuf; @@ -384,6 +384,10 @@ impl RuntimeContext { let index = self.eval_expr(index, local_env, current_module)?; self.get_index(&value, &index) } + Expr::Import(ExprStr { content }) => { + let module = self.load_module(&ModulePath::new((**content).to_owned()))?; + Ok(module.pub_object().clone()) + } } } diff --git a/src/lib.rs b/src/lib.rs index 32e4d96..3ee8e94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,9 +61,10 @@ mod test { use crate::module::{ModulePath, NullModuleLoader}; use crate::value::ObjectKey; - use self::module::FsModuleLoader; + use self::module::{FsModuleLoader, Module}; use super::*; + use gc::Gc; use pretty_assertions::assert_eq; #[ctor::ctor] @@ -99,6 +100,14 @@ mod test { }; } + fn new_rt() -> (RuntimeContext, Gc) { + let mut ctx = RuntimeContext::with_paths(vec!["lib"]); + let module = ctx + .new_module(crate::module::ModulePath::new("__test__")) + .unwrap(); + (ctx, module) + } + #[test] fn int_lit() { assert_eval_ok!("1", 1); @@ -403,4 +412,20 @@ mod test { ); assert_eq!(m.pub_object(), &Value::from(object_value! {a: 1})); } + + #[test] + fn import() { + let (mut rt, m) = new_rt(); + + rt.eval_program_in_module( + &parse_program(r#"let prelude = import "std/prelude";"#).unwrap(), + &m, + ) + .unwrap(); + assert_eq!( + rt.eval_expr_in_module(&parse_expr("prelude.true").unwrap(), &m) + .unwrap(), + Value::bool(true) + ); + } } diff --git a/src/value.rs b/src/value.rs index f3d1564..4b78d3e 100644 --- a/src/value.rs +++ b/src/value.rs @@ -195,10 +195,7 @@ impl TryFrom<&Value> for String { fn try_from(value: &Value) -> Result { match value { - Value::Atom(a) => match a { - AtomValue::Str(s) => Ok((**s).clone()), - _ => Err(EvalError::type_error("String", value.clone())), - }, + Value::Atom(AtomValue::Str(s)) => Ok((**s).clone()), _ => Err(EvalError::type_error("String", value.clone())), } } diff --git a/tree-sitter-borlang/rules.js b/tree-sitter-borlang/rules.js index e27dfd9..2b8caec 100644 --- a/tree-sitter-borlang/rules.js +++ b/tree-sitter-borlang/rules.js @@ -42,6 +42,7 @@ const common_rules = { $.expr_prop, $.expr_prop_opt, $.expr_index, + $.expr_import, ), expr_int: _ => /[0-9]+/, expr_str: $ => seq( @@ -163,6 +164,10 @@ const common_rules = { field('index', $._expr), ']', )), + expr_import: $ => seq( + 'import', + $.expr_str + ), ident: _ => /[A-Za-z_][a-z0-9_]*/, op_plus: _ => '+', op_minus: _ => '-',