diff --git a/Cargo.lock b/Cargo.lock index 154414a5..e5cafc1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,6 +168,7 @@ version = "0.0.0" dependencies = [ "criterion", "ndc_lib", + "ndc_stdlib", "rand", "rand_chacha", ] @@ -1250,6 +1251,7 @@ dependencies = [ "ndc_lexer", "ndc_lib", "ndc_lsp", + "ndc_stdlib", "owo-colors", "rustyline", "strsim", @@ -1275,22 +1277,13 @@ dependencies = [ "anyhow", "derive_builder", "derive_more", - "factorial", "itertools 0.14.0", - "md5", "ndc_lexer", - "ndc_macros", "ndc_parser", "num", - "once_cell", "ordered-float", - "rand", - "regex", "ryu", "self_cell", - "serde_json", - "sha1", - "tap", "thiserror", ] @@ -1301,6 +1294,7 @@ dependencies = [ "ndc_lexer", "ndc_lib", "ndc_parser", + "ndc_stdlib", "tokio", "tower-lsp", ] @@ -1326,6 +1320,25 @@ dependencies = [ "thiserror", ] +[[package]] +name = "ndc_stdlib" +version = "0.2.1" +dependencies = [ + "anyhow", + "factorial", + "itertools 0.14.0", + "md5", + "ndc_lib", + "ndc_macros", + "num", + "once_cell", + "rand", + "regex", + "serde_json", + "sha1", + "tap", +] + [[package]] name = "nibble_vec" version = "0.1.0" @@ -2051,6 +2064,7 @@ name = "tests" version = "0.2.1" dependencies = [ "ndc_lib", + "ndc_stdlib", "owo-colors", ] diff --git a/Cargo.toml b/Cargo.toml index 3d9b5934..22e7b22a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "3" -members = ["ndc_macros", "ndc_bin", "ndc_lib", "ndc_lsp", "ndc_lexer", "ndc_parser", "benches", "tests"] +members = ["ndc_macros", "ndc_bin", "ndc_lib", "ndc_lsp", "ndc_lexer", "ndc_parser", "ndc_stdlib", "benches", "tests"] [workspace.package] edition = "2024" @@ -22,6 +22,7 @@ ndc_lib = { path = "ndc_lib" } ndc_parser = { path = "ndc_parser" } ndc_lsp = { path = "ndc_lsp" } ndc_macros = { path = "ndc_macros" } +ndc_stdlib = { path = "ndc_stdlib" } num = "0.4.3" once_cell = "1.21.3" ordered-float = "5.1.0" diff --git a/benches/Cargo.toml b/benches/Cargo.toml index 14ca4abb..4c7ecc06 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -5,6 +5,7 @@ license.workspace = true [dependencies] ndc_lib.workspace = true +ndc_stdlib.workspace = true rand.workspace = true criterion.workspace = true rand_chacha.workspace = true diff --git a/benches/src/benchmark.rs b/benches/src/benchmark.rs index 5f81f20a..fba47fa5 100644 --- a/benches/src/benchmark.rs +++ b/benches/src/benchmark.rs @@ -1,5 +1,7 @@ use criterion::{Criterion, criterion_group, criterion_main}; -use ndc_lib::interpreter::{Interpreter, InterpreterError}; +use ndc_lib::interpreter::Interpreter; +use ndc_lib::interpreter::InterpreterError; +use ndc_stdlib::WithStdlib; use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; use std::fs; @@ -8,7 +10,7 @@ use std::time::Duration; fn run_string(input: &str) -> Result { let buf: Vec = vec![]; - let mut interpreter = Interpreter::new(buf); + let mut interpreter = Interpreter::new(buf).with_stdlib(); interpreter.run_str(std::hint::black_box(input)) } diff --git a/ndc_bin/Cargo.toml b/ndc_bin/Cargo.toml index d9649483..bdacdfcc 100644 --- a/ndc_bin/Cargo.toml +++ b/ndc_bin/Cargo.toml @@ -16,6 +16,7 @@ strsim.workspace = true miette = { version = "7.6.0", features = ["fancy"] } ndc_lexer.workspace = true ndc_lib.workspace = true +ndc_stdlib.workspace = true ndc_lsp.workspace = true owo-colors.workspace = true rustyline.workspace = true diff --git a/ndc_bin/src/docs.rs b/ndc_bin/src/docs.rs index 9b9ba97d..3cad915e 100644 --- a/ndc_bin/src/docs.rs +++ b/ndc_bin/src/docs.rs @@ -1,5 +1,6 @@ use ndc_lib::interpreter::Interpreter; use ndc_lib::interpreter::function::{Parameter, TypeSignature}; +use ndc_stdlib::WithStdlib; use std::cmp::Ordering; use std::fmt::Write; use strsim::normalized_damerau_levenshtein; @@ -13,7 +14,9 @@ fn string_match(needle: &str, haystack: &str) -> bool { } pub fn docs(query: Option<&str>) -> anyhow::Result<()> { - let interpreter = Interpreter::new(Vec::new()); // Discard the output + let interpreter = Interpreter::new(Vec::new()) // Discard the output + .with_stdlib(); + let functions = interpreter.environment().borrow().get_all_functions(); let matched_functions = functions diff --git a/ndc_bin/src/main.rs b/ndc_bin/src/main.rs index d77ac8cf..05a97d3c 100644 --- a/ndc_bin/src/main.rs +++ b/ndc_bin/src/main.rs @@ -6,6 +6,7 @@ use clap::{Parser, Subcommand}; use highlighter::{AndycppHighlighter, AndycppHighlighterState}; use miette::{NamedSource, highlighters::HighlighterState}; use ndc_lib::interpreter::{Interpreter, InterpreterError}; +use ndc_stdlib::WithStdlib; use std::path::PathBuf; use std::process; use std::{fs, io::Write}; @@ -118,7 +119,7 @@ fn main() -> anyhow::Result<()> { let string = fs::read_to_string(path)?; let stdout = std::io::stdout(); - let mut interpreter = Interpreter::new(stdout); + let mut interpreter = Interpreter::new(stdout).with_stdlib(); match into_miette_result(interpreter.run_str(&string)) { // we can just ignore successful runs because we have print statements Ok(_final_value) => {} diff --git a/ndc_bin/src/repl.rs b/ndc_bin/src/repl.rs index 96791985..ec71d900 100644 --- a/ndc_bin/src/repl.rs +++ b/ndc_bin/src/repl.rs @@ -2,6 +2,7 @@ use itertools::Itertools; use miette::highlighters::HighlighterState; use ndc_lib::interpreter::Interpreter; +use ndc_stdlib::WithStdlib; use rustyline::Helper; use rustyline::config::Configurer; use rustyline::error::ReadlineError; @@ -36,7 +37,7 @@ pub fn run() -> anyhow::Result<()> { rl.set_helper(Some(h)); let stdout = std::io::stdout(); - let mut interpreter = Interpreter::new(stdout); + let mut interpreter = Interpreter::new(stdout).with_stdlib(); loop { match rl.readline("λ ") { Ok(line) => { diff --git a/ndc_lib/Cargo.toml b/ndc_lib/Cargo.toml index 9fbe449b..8f82daf7 100644 --- a/ndc_lib/Cargo.toml +++ b/ndc_lib/Cargo.toml @@ -9,27 +9,15 @@ ahash = { workspace = true, optional = true } anyhow.workspace = true derive_more.workspace = true derive_builder.workspace = true -factorial.workspace = true itertools.workspace = true ndc_lexer.workspace = true -ndc_macros.workspace = true ndc_parser.workspace = true num.workspace = true -once_cell.workspace = true ordered-float.workspace = true -rand.workspace = true -regex.workspace = true ryu.workspace = true self_cell.workspace = true -serde_json.workspace = true -tap.workspace = true thiserror.workspace = true -# Crypto -md5 = { version = "0.8.0", optional = true } -sha1 = { version = "0.10.6", optional = true } - [features] -default = ["ahash", "crypto"] +default = ["ahash"] ahash = ["dep:ahash"] -crypto = ["dep:md5", "dep:sha1"] diff --git a/ndc_lib/src/interpreter/environment.rs b/ndc_lib/src/interpreter/environment.rs index fe2cf08a..c14a57ac 100644 --- a/ndc_lib/src/interpreter/environment.rs +++ b/ndc_lib/src/interpreter/environment.rs @@ -1,7 +1,7 @@ use crate::interpreter::function::{Function, StaticType}; -use ndc_parser::ResolvedVar; use crate::interpreter::value::Value; +use ndc_parser::ResolvedVar; use std::cell::RefCell; use std::fmt; use std::fmt::Formatter; @@ -50,21 +50,17 @@ impl Environment { } #[must_use] - pub fn new_with_stdlib(writer: Box) -> Self { + pub fn new(writer: Box) -> Self { let root = RootEnvironment { output: writer, global_functions: Default::default(), }; - let mut env = Self { + Self { root: Rc::new(RefCell::new(root)), parent: None, values: Default::default(), - }; - - crate::stdlib::register(&mut env); - - env + } } pub fn get_global_identifiers(&self) -> Vec<(String, StaticType)> { @@ -181,7 +177,7 @@ impl Environment { impl Default for Environment { fn default() -> Self { - Self::new_with_stdlib(Box::new(stdout())) + Self::new(Box::new(stdout())) } } diff --git a/ndc_lib/src/interpreter/evaluate/index.rs b/ndc_lib/src/interpreter/evaluate/index.rs index 23acdc42..cb31813d 100644 --- a/ndc_lib/src/interpreter/evaluate/index.rs +++ b/ndc_lib/src/interpreter/evaluate/index.rs @@ -9,14 +9,12 @@ //! | Backward index | -10 | -9 | -8 | -7 | -6 | -5 | -4 | -3 | -2 | -1 | //! +----------------+-----+----+----+----+----+----+----+----+----+----+ -use ndc_parser::{Expression, ExpressionLocation}; use super::{EvaluationError, EvaluationResult, IntoEvaluationResult, evaluate_expression}; use crate::interpreter::environment::Environment; -use crate::{ - interpreter::{function::FunctionCarrier, sequence::Sequence, value::Value}, -}; +use crate::interpreter::{function::FunctionCarrier, sequence::Sequence, value::Value}; use itertools::Itertools; use ndc_lexer::Span; +use ndc_parser::{Expression, ExpressionLocation}; use std::cell::RefCell; use std::cmp::min; use std::ops::IndexMut; @@ -300,7 +298,11 @@ pub fn set_at_index( Offset::Range(from_usize, to_usize) => { let tail = list.drain(from_usize..).collect::>(); - list.extend(rhs.try_into_vec().expect("this must succeed, but not sure why").into_iter()); + list.extend( + rhs.try_into_vec() + .expect("this must succeed, but not sure why") + .into_iter(), + ); list.extend_from_slice(&tail[(to_usize - from_usize)..]); } diff --git a/ndc_lib/src/interpreter/evaluate/mod.rs b/ndc_lib/src/interpreter/evaluate/mod.rs index 7fdc973b..9a41c094 100644 --- a/ndc_lib/src/interpreter/evaluate/mod.rs +++ b/ndc_lib/src/interpreter/evaluate/mod.rs @@ -1,6 +1,3 @@ -use ndc_parser::{ - Binding, Expression, ExpressionLocation, ForBody, ForIteration, LogicalOperator, Lvalue, -}; use crate::hash_map::HashMap; use crate::interpreter::environment::Environment; use crate::interpreter::function::{Function, FunctionBody, FunctionCarrier, StaticType}; @@ -12,6 +9,9 @@ use crate::interpreter::value::Value; use index::{Offset, evaluate_as_index, get_at_index, set_at_index}; use itertools::Itertools; use ndc_lexer::Span; +use ndc_parser::{ + Binding, Expression, ExpressionLocation, ForBody, ForIteration, LogicalOperator, Lvalue, +}; use std::cell::RefCell; use std::fmt; use std::rc::Rc; diff --git a/ndc_lib/src/interpreter/function.rs b/ndc_lib/src/interpreter/function.rs index 47aea37e..a8e93a1a 100644 --- a/ndc_lib/src/interpreter/function.rs +++ b/ndc_lib/src/interpreter/function.rs @@ -1,4 +1,3 @@ -use ndc_parser::{ExpressionLocation, ResolvedVar}; use crate::hash_map::{DefaultHasher, HashMap}; use crate::interpreter::environment::Environment; use crate::interpreter::evaluate::{ @@ -9,6 +8,7 @@ use crate::interpreter::sequence::Sequence; use crate::interpreter::value::Value; use derive_builder::Builder; use ndc_lexer::Span; +use ndc_parser::{ExpressionLocation, ResolvedVar}; pub use ndc_parser::{Parameter, StaticType, TypeSignature}; use std::cell::{BorrowError, BorrowMutError, RefCell}; use std::fmt; diff --git a/ndc_lib/src/interpreter/mod.rs b/ndc_lib/src/interpreter/mod.rs index cd479a26..61ab1875 100644 --- a/ndc_lib/src/interpreter/mod.rs +++ b/ndc_lib/src/interpreter/mod.rs @@ -1,17 +1,17 @@ use std::cell::RefCell; use std::rc::Rc; -use ndc_parser::ExpressionLocation; use crate::interpreter::environment::{Environment, InterpreterOutput}; use crate::interpreter::evaluate::{EvaluationError, evaluate_expression}; use crate::interpreter::function::FunctionCarrier; use crate::interpreter::semantic::analyser::{Analyser, ScopeTree}; use crate::interpreter::value::Value; use ndc_lexer::{Lexer, TokenLocation}; +use ndc_parser::ExpressionLocation; pub mod environment; pub mod evaluate; pub mod function; -pub(crate) mod heap; +pub mod heap; pub mod int; pub mod iterator; pub mod num; @@ -30,15 +30,24 @@ impl Interpreter { where T: InterpreterOutput + 'static, { - let environment = Environment::new_with_stdlib(Box::new(dest)); - let global_identifiers = environment.get_global_identifiers(); + Self::from_env(Environment::new(Box::new(dest))) + } + #[must_use] + pub fn from_env(environment: Environment) -> Self { + let global_identifiers = environment.get_global_identifiers(); Self { environment: Rc::new(RefCell::new(environment)), analyser: Analyser::from_scope_tree(ScopeTree::from_global_scope(global_identifiers)), } } + pub fn configure(&mut self, f: F) { + f(&mut self.environment.borrow_mut()); + let global_identifiers = self.environment.borrow().get_global_identifiers(); + self.analyser = Analyser::from_scope_tree(ScopeTree::from_global_scope(global_identifiers)); + } + #[must_use] pub fn environment(self) -> Rc> { self.environment diff --git a/ndc_lib/src/interpreter/num.rs b/ndc_lib/src/interpreter/num.rs index ee211a4d..75cae747 100644 --- a/ndc_lib/src/interpreter/num.rs +++ b/ndc_lib/src/interpreter/num.rs @@ -4,11 +4,11 @@ use std::hash::{Hash, Hasher}; use std::num::TryFromIntError; use std::ops::{Add, Div, Mul, Neg, Not, Rem, Sub}; -use ndc_parser::BinaryOperator; use crate::interpreter::evaluate::EvaluationError; use crate::interpreter::function::StaticType; use crate::interpreter::int::Int; use ndc_lexer::Span; +use ndc_parser::BinaryOperator; use num::bigint::TryFromBigIntError; use num::complex::{Complex64, ComplexFloat}; use num::{BigInt, BigRational, Complex, FromPrimitive, Signed, ToPrimitive, Zero}; diff --git a/ndc_lib/src/interpreter/semantic/analyser.rs b/ndc_lib/src/interpreter/semantic/analyser.rs index 68704aa4..8d78ead7 100644 --- a/ndc_lib/src/interpreter/semantic/analyser.rs +++ b/ndc_lib/src/interpreter/semantic/analyser.rs @@ -1,9 +1,9 @@ -use ndc_parser::{ - Binding, Expression, ExpressionLocation, ForBody, ForIteration, Lvalue, ResolvedVar, -}; use crate::interpreter::function::StaticType; use itertools::Itertools; use ndc_lexer::Span; +use ndc_parser::{ + Binding, Expression, ExpressionLocation, ForBody, ForIteration, Lvalue, ResolvedVar, +}; use std::fmt::{Debug, Formatter}; pub struct Analyser { @@ -347,7 +347,13 @@ impl Analyser { self.scope_tree.new_scope(); // TODO: when we give type parameters to all instances of sequence we can correctly infer StaticType::Any in this position - self.resolve_lvalue_declarative(l_value, sequence_type.sequence_element_type().unwrap_or(StaticType::Any), span)?; + self.resolve_lvalue_declarative( + l_value, + sequence_type + .sequence_element_type() + .unwrap_or(StaticType::Any), + span, + )?; do_destroy = true; // TODO: why is this correct } ForIteration::Guard(expr) => { diff --git a/ndc_lib/src/interpreter/value.rs b/ndc_lib/src/interpreter/value.rs index 27bc7df1..451b50de 100644 --- a/ndc_lib/src/interpreter/value.rs +++ b/ndc_lib/src/interpreter/value.rs @@ -29,18 +29,18 @@ pub enum Value { } impl Value { - pub(crate) fn function(function: Function) -> Self { + pub fn function(function: Function) -> Self { Self::Function(Rc::new(function)) } - pub(crate) fn string>(string: S) -> Self { + pub fn string>(string: S) -> Self { Self::Sequence(Sequence::String(Rc::new(RefCell::new(string.into())))) } - pub(crate) fn list>>(data: V) -> Self { + pub fn list>>(data: V) -> Self { Self::Sequence(Sequence::List(Rc::new(RefCell::new(data.into())))) } - pub(crate) fn collect_list(i: I) -> Self + pub fn collect_list(i: I) -> Self where I: Iterator, V: Into, @@ -48,23 +48,23 @@ impl Value { Self::list(i.map(Into::into).collect::>()) } - pub(crate) fn tuple>>(data: V) -> Self { + pub fn tuple>>(data: V) -> Self { Self::Sequence(Sequence::Tuple(Rc::new(data.into()))) } - pub(crate) fn unit() -> Self { + pub fn unit() -> Self { Self::Sequence(Sequence::Tuple(Rc::new(vec![]))) } - pub(crate) fn none() -> Self { + pub fn none() -> Self { Self::Option(None) } - pub(crate) fn some(value: Self) -> Self { + pub fn some(value: Self) -> Self { Self::Option(Some(Box::new(value))) } - pub(crate) fn number>(source: T) -> Self { + pub fn number>(source: T) -> Self { Self::Number(source.into()) } @@ -93,7 +93,7 @@ impl Value { } Self::Sequence(Sequence::String(string)) => match Rc::try_unwrap(string) { // This implementation is peak retard, we don't want collect_vec here - // ^-- WTF: is this comment, we collect_vec here anyways? + // ^-- WTF: is this comment, we collect_vec here anyway? Ok(string) => Some(string.into_inner().chars().map(Self::from).collect_vec()), Err(string) => Some(string.borrow().chars().map(Self::from).collect_vec()), }, diff --git a/ndc_lib/src/lib.rs b/ndc_lib/src/lib.rs index 389b0757..f4ea1ad3 100644 --- a/ndc_lib/src/lib.rs +++ b/ndc_lib/src/lib.rs @@ -1,4 +1,3 @@ -mod compare; -mod hash_map; +pub mod compare; +pub mod hash_map; pub mod interpreter; -pub mod stdlib; diff --git a/ndc_lib/src/stdlib/serde.rs b/ndc_lib/src/stdlib/serde.rs deleted file mode 100644 index 1e318f36..00000000 --- a/ndc_lib/src/stdlib/serde.rs +++ /dev/null @@ -1,142 +0,0 @@ -use ndc_macros::export_module; -use std::rc::Rc; -use std::{cell::RefCell, str::FromStr}; - -use crate::hash_map::HashMap; -use crate::interpreter::sequence::Sequence; -use crate::interpreter::value::Value; -use anyhow::Context; -use num::BigInt; -use num::ToPrimitive; -use serde_json::{Map, Number, Value as JsonValue, json}; - -impl TryFrom for JsonValue { - type Error = anyhow::Error; - - fn try_from(value: Value) -> Result { - match value { - Value::Option(Some(value)) => Self::try_from(*value), - Value::Option(None) => Ok(Self::Null), - Value::Number(number) => match number { - crate::interpreter::num::Number::Int(int) => match int { - crate::interpreter::int::Int::Int64(i) => Ok(json!(i)), - // Ehrmm.. - crate::interpreter::int::Int::BigInt(big_int) => { - Number::from_str(&big_int.to_string()) - .map(JsonValue::Number) - .context("Cannot convert bigint to string") - } - }, - crate::interpreter::num::Number::Float(f) => Ok(json!(f)), - crate::interpreter::num::Number::Rational(ratio) => Ok(json!(ratio.to_f64())), - crate::interpreter::num::Number::Complex(complex) => { - Ok(json!(format!("{complex}"))) - } - }, - Value::Bool(b) => Ok(json!(b)), - Value::Sequence(s) => match s { - Sequence::String(s) => Ok(json!(&*s.borrow())), - Sequence::List(values) => Ok(Self::Array( - values - .borrow() - .iter() - .map(|v| v.clone().try_into()) - .collect::, _>>()?, - )), - Sequence::Tuple(values) => match values.len() { - 0 => Ok(Self::Null), - _ => Ok(Self::Array( - values - .iter() - .map(|v| v.clone().try_into()) - .collect::, _>>()?, - )), - }, - Sequence::Map(values, _) => Ok(Self::Object( - values - .borrow() - .iter() - .map(|(key, value)| { - Self::try_from(value.clone()).map(|value| (key.to_string(), value)) - }) - .collect::, _>>()?, - )), - Sequence::Iterator(i) => { - let mut i = i.borrow_mut(); - let mut out = Vec::new(); - for value in i.by_ref() { - out.push(Self::try_from(value)?); - } - Ok(Self::Array(out)) - } - Sequence::MaxHeap(h) => Ok(Self::Array( - h.borrow() - .iter() - .map(|h| Self::try_from(h.0.clone())) - .collect::, _>>()?, - )), - Sequence::MinHeap(h) => Ok(Self::Array( - h.borrow() - .iter() - .map(|h| Self::try_from(h.0.0.clone())) - .collect::, _>>()?, - )), - Sequence::Deque(d) => Ok(Self::Array( - d.borrow() - .iter() - .map(|v| Self::try_from(v.clone())) - .collect::, _>>()?, - )), - }, - Value::Function(_) => Err(anyhow::anyhow!("Unable to serialize function")), - } - } -} - -impl TryFrom for Value { - type Error = anyhow::Error; - - fn try_from(value: JsonValue) -> Result { - Ok(match value { - JsonValue::Null => Self::unit(), - JsonValue::Bool(b) => Self::Bool(b), - JsonValue::Number(n) => n.as_str().parse::().map(Self::from).or_else(|_| { - n.as_f64() - .map(Self::from) - .context("Cannot parse number as int or float") - })?, - JsonValue::String(s) => Self::string(s), - JsonValue::Array(a) => Self::list( - a.into_iter() - .map(TryInto::try_into) - .collect::, _>>()?, - ), - JsonValue::Object(o) => Self::Sequence(Sequence::Map( - Rc::new(RefCell::new( - o.into_iter() - .map(|(key, value)| { - value.try_into().map(|value| (Self::string(key), value)) - }) - .collect::, _>>()?, - )), - None, - )), - }) - } -} - -#[export_module] -mod inner { - use crate::interpreter::value::Value; - - /// Converts a JSON string to a value - pub fn json_decode(input: &str) -> anyhow::Result { - serde_json::from_str::(input)?.try_into() - } - - /// Converts the input value to JSON - pub fn json_encode(input: Value) -> anyhow::Result { - let v: JsonValue = input.try_into()?; - Ok(v.to_string()) - } -} diff --git a/ndc_lsp/Cargo.toml b/ndc_lsp/Cargo.toml index 1399d3c1..f8d20249 100644 --- a/ndc_lsp/Cargo.toml +++ b/ndc_lsp/Cargo.toml @@ -8,5 +8,6 @@ version.workspace = true tokio = { version = "1.49.0", features = ["full"] } ndc_lexer.workspace = true ndc_lib.workspace = true +ndc_stdlib.workspace = true tower-lsp.workspace = true ndc_parser.workspace = true diff --git a/ndc_lsp/src/backend.rs b/ndc_lsp/src/backend.rs index 075023c4..af6ff24e 100644 --- a/ndc_lsp/src/backend.rs +++ b/ndc_lsp/src/backend.rs @@ -1,8 +1,9 @@ use std::collections::HashMap; use ndc_lexer::{Lexer, Span, TokenLocation}; -use ndc_parser::{Expression, ExpressionLocation, ForBody, ForIteration, Lvalue}; use ndc_lib::interpreter::Interpreter; +use ndc_parser::{Expression, ExpressionLocation, ForBody, ForIteration, Lvalue}; +use ndc_stdlib::WithStdlib; use tokio::sync::Mutex; use tower_lsp::jsonrpc::Result as JsonRPCResult; use tower_lsp::lsp_types::{ @@ -80,7 +81,7 @@ impl Backend { // The interpreter uses Rc internally (non-Send), so it must be fully dropped // before the next await point. let hints = { - let mut interpreter = Interpreter::new(Vec::new()); + let mut interpreter = Interpreter::new(Vec::new()).with_stdlib(); match interpreter.analyse_str(text) { Ok(expressions) => { let mut hints = Vec::new(); @@ -151,7 +152,7 @@ impl LanguageServer for Backend { &self, _params: CompletionParams, ) -> Result, tower_lsp::jsonrpc::Error> { - let interpreter = Interpreter::new(Vec::new()); + let interpreter = Interpreter::new(Vec::new()).with_stdlib(); let env = interpreter.environment(); let functions = env.borrow().get_all_functions(); diff --git a/ndc_macros/src/convert.rs b/ndc_macros/src/convert.rs index db1d9202..e280e83d 100644 --- a/ndc_macros/src/convert.rs +++ b/ndc_macros/src/convert.rs @@ -28,7 +28,7 @@ impl TypeConverter for MutRefString { } fn static_type(&self) -> TokenStream { - quote! { crate::interpreter::function::StaticType::String } + quote! { ndc_lib::interpreter::function::StaticType::String } } fn convert( @@ -42,7 +42,7 @@ impl TypeConverter for MutRefString { param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::String(#temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::String(#temp_var)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::String but wasn't"); }; let #argument_var_name = &mut *#temp_var.try_borrow_mut()?; @@ -73,7 +73,7 @@ impl TypeConverter for InternalMap { param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::Map(#temp_var, _)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::Map(#temp_var, _)) = #argument_var_name else { panic!("Value #position needed to be Sequence::Map but wasn't"); }; @@ -89,7 +89,7 @@ impl TypeConverter for InternalString { } fn static_type(&self) -> TokenStream { - quote! { crate::interpreter::function::StaticType::String } + quote! { ndc_lib::interpreter::function::StaticType::String } } fn convert( @@ -103,7 +103,7 @@ impl TypeConverter for InternalString { param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::String(#temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::String(#temp_var)) = #argument_var_name else { panic!("Value #position needed to be Sequence::List but wasn't"); }; @@ -122,8 +122,8 @@ impl TypeConverter for InternalList { fn static_type(&self) -> TokenStream { // TODO: just hardcoding Any here is lazy quote! { - crate::interpreter::function::StaticType::List(Box::new( - crate::interpreter::function::StaticType::Any + ndc_lib::interpreter::function::StaticType::List(Box::new( + ndc_lib::interpreter::function::StaticType::Any )) } } @@ -139,7 +139,7 @@ impl TypeConverter for InternalList { param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::List(#temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::List(#temp_var)) = #argument_var_name else { panic!("Value #position needed to be Sequence::List but wasn't"); }; @@ -164,11 +164,11 @@ impl TypeConverter for InternalList { // argument_var_name: syn::Ident, // ) -> Vec { // vec![Argument { -// param_type: quote! { crate::interpreter::function::StaticType::Tuple }, +// param_type: quote! { ndc_lib::interpreter::function::StaticType::Tuple }, // param_name: quote! { #original_name }, // argument: quote! { #argument_var_name }, // initialize_code: quote! { -// let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::Tuple(#temp_var)) = #argument_var_name else { +// let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::Tuple(#temp_var)) = #argument_var_name else { // panic!("Value #position needed to be Sequence::Tuple but wasn't"); // }; // diff --git a/ndc_macros/src/function.rs b/ndc_macros/src/function.rs index 6a3da976..32ee9327 100644 --- a/ndc_macros/src/function.rs +++ b/ndc_macros/src/function.rs @@ -122,7 +122,7 @@ fn map_return_type(output: &syn::ReturnType) -> TokenStream { match output { syn::ReturnType::Default => { // in case return type is not specified (for closures rust defaults to type inference which doesn't help us here) - quote! { crate::interpreter::function::StaticType::Tuple(vec![]) } + quote! { ndc_lib::interpreter::function::StaticType::Tuple(vec![]) } } syn::ReturnType::Type(_, ty) => map_type(ty), } @@ -135,13 +135,13 @@ fn map_type(ty: &syn::Type) -> TokenStream { syn::Type::Tuple(t) => { let inner = t.elems.iter().map(map_type); quote::quote! { - crate::interpreter::function::StaticType::Tuple(vec![ + ndc_lib::interpreter::function::StaticType::Tuple(vec![ #(#inner),* ]) } } syn::Type::Infer(_) => { - quote::quote! { crate::interpreter::function::StaticType::Any } + quote::quote! { ndc_lib::interpreter::function::StaticType::Any } } _ => { panic!("unmapped type: {ty:?}"); @@ -155,29 +155,29 @@ fn map_type_path(p: &syn::TypePath) -> TokenStream { match segment.ident.to_string().as_str() { "i32" | "i64" | "isize" | "u32" | "u64" | "usize" | "BigInt" => { - quote::quote! { crate::interpreter::function::StaticType::Int } + quote::quote! { ndc_lib::interpreter::function::StaticType::Int } } "f32" | "f64" => { - quote::quote! { crate::interpreter::function::StaticType::Float } + quote::quote! { ndc_lib::interpreter::function::StaticType::Float } } "bool" => { - quote::quote! { crate::interpreter::function::StaticType::Bool } + quote::quote! { ndc_lib::interpreter::function::StaticType::Bool } } "String" | "str" => { - quote::quote! { crate::interpreter::function::StaticType::String } + quote::quote! { ndc_lib::interpreter::function::StaticType::String } } "Vec" | "List" => match &segment.arguments { syn::PathArguments::AngleBracketed(args) => { let inner = args.args.first().expect("Vec<> requires inner type"); if let syn::GenericArgument::Type(inner_ty) = inner { let mapped = map_type(inner_ty); - quote::quote! { crate::interpreter::function::StaticType::List(Box::new(#mapped)) } + quote::quote! { ndc_lib::interpreter::function::StaticType::List(Box::new(#mapped)) } } else { panic!("Vec inner not a type"); } } _ => { - quote::quote! { crate::interpreter::function::StaticType::List(Box::new(crate::interpreter::function::StaticType::Any)) } + quote::quote! { ndc_lib::interpreter::function::StaticType::List(Box::new(ndc_lib::interpreter::function::StaticType::Any)) } } }, "VecDeque" | "Deque" => match &segment.arguments { @@ -185,14 +185,14 @@ fn map_type_path(p: &syn::TypePath) -> TokenStream { let inner = args.args.first().expect("VecDeque<> requires inner type"); if let syn::GenericArgument::Type(inner_ty) = inner { let mapped = map_type(inner_ty); - quote::quote! { crate::interpreter::function::StaticType::Deque(Box::new(#mapped)) } + quote::quote! { ndc_lib::interpreter::function::StaticType::Deque(Box::new(#mapped)) } } else { panic!("VecDeque inner not a type"); } } _ => quote::quote! { - crate::interpreter::function::StaticType::Deque(Box::new( - crate::interpreter::function::StaticType::Any + ndc_lib::interpreter::function::StaticType::Deque(Box::new( + ndc_lib::interpreter::function::StaticType::Any )) }, }, @@ -215,7 +215,7 @@ fn map_type_path(p: &syn::TypePath) -> TokenStream { }; let key_mapped = map_type(key_ty); let val_mapped = map_type(val_ty); - quote::quote! { crate::interpreter::function::StaticType::Map { key: Box::new(#key_mapped), value: Box::new(#val_mapped) } } + quote::quote! { ndc_lib::interpreter::function::StaticType::Map { key: Box::new(#key_mapped), value: Box::new(#val_mapped) } } } _ => temp_create_map_any(), }, @@ -224,14 +224,14 @@ fn map_type_path(p: &syn::TypePath) -> TokenStream { let inner = args.args.first().expect("MinHeap requires inner"); if let syn::GenericArgument::Type(inner_ty) = inner { let mapped = map_type(inner_ty); - quote::quote! { crate::interpreter::function::StaticType::MinHeap(Box::new(#mapped)) } + quote::quote! { ndc_lib::interpreter::function::StaticType::MinHeap(Box::new(#mapped)) } } else { panic!("MinHeap inner invalid"); } } _ => quote::quote! { - crate::interpreter::function::StaticType::MinHeap(Box::new( - crate::interpreter::function::StaticType::Any + ndc_lib::interpreter::function::StaticType::MinHeap(Box::new( + ndc_lib::interpreter::function::StaticType::Any )) }, }, @@ -240,7 +240,7 @@ fn map_type_path(p: &syn::TypePath) -> TokenStream { let inner = args.args.first().expect("MaxHeap requires inner"); if let syn::GenericArgument::Type(inner_ty) = inner { let mapped = map_type(inner_ty); - quote::quote! { crate::interpreter::function::StaticType::MaxHeap(Box::new(#mapped)) } + quote::quote! { ndc_lib::interpreter::function::StaticType::MaxHeap(Box::new(#mapped)) } } else { panic!("MaxHeap inner invalid"); } @@ -252,13 +252,13 @@ fn map_type_path(p: &syn::TypePath) -> TokenStream { let inner = args.args.first().expect("Iterator requires inner"); if let syn::GenericArgument::Type(inner_ty) = inner { let mapped = map_type(inner_ty); - quote::quote! { crate::interpreter::function::StaticType::Iterator(Box::new(#mapped)) } + quote::quote! { ndc_lib::interpreter::function::StaticType::Iterator(Box::new(#mapped)) } } else { panic!("Iterator inner invalid"); } } _ => { - quote::quote! { crate::interpreter::function::StaticType::Iterator(Box::new(crate::interpreter::function::StaticType::Any)) } + quote::quote! { ndc_lib::interpreter::function::StaticType::Iterator(Box::new(ndc_lib::interpreter::function::StaticType::Any)) } } }, "Option" => match &segment.arguments { @@ -266,7 +266,7 @@ fn map_type_path(p: &syn::TypePath) -> TokenStream { let inner = args.args.first().expect("Option requires inner type"); if let syn::GenericArgument::Type(inner_ty) = inner { let mapped = map_type(inner_ty); - quote::quote! { crate::interpreter::function::StaticType::Option(Box::new(#mapped)) } + quote::quote! { ndc_lib::interpreter::function::StaticType::Option(Box::new(#mapped)) } } else { panic!("Option inner invalid"); } @@ -283,9 +283,9 @@ fn map_type_path(p: &syn::TypePath) -> TokenStream { } _ => panic!("Result without angle bracketed args"), }, - "Number" => quote::quote! { crate::interpreter::function::StaticType::Number }, + "Number" => quote::quote! { ndc_lib::interpreter::function::StaticType::Number }, "Value" | "EvaluationResult" => { - quote::quote! { crate::interpreter::function::StaticType::Any } + quote::quote! { ndc_lib::interpreter::function::StaticType::Any } } unmatched => panic!("Cannot map type string '{unmatched}' to StaticType"), } @@ -334,7 +334,7 @@ fn wrap_single( let return_expr = match function.sig.output { syn::ReturnType::Default => quote! { - return Ok(crate::interpreter::value::Value::unit()); + return Ok(ndc_lib::interpreter::value::Value::unit()); }, syn::ReturnType::Type(_, typ) => match &*typ { // If the function returns a result we unpack it using the question mark operator @@ -342,11 +342,11 @@ fn wrap_single( return result; }, ty @ syn::Type::Path(_) if path_ends_with(ty, "Result") => quote! { - let value = result.map_err(|err| crate::interpreter::function::FunctionCarrier::IntoEvaluationError(Box::new(err)))?; - return Ok(crate::interpreter::value::Value::from(value)); + let value = result.map_err(|err| ndc_lib::interpreter::function::FunctionCarrier::IntoEvaluationError(Box::new(err)))?; + return Ok(ndc_lib::interpreter::value::Value::from(value)); }, _ => quote! { - let result = crate::interpreter::value::Value::from(result); + let result = ndc_lib::interpreter::value::Value::from(result); return Ok(result); }, }, @@ -364,9 +364,9 @@ fn wrap_single( // } let function_declaration = quote! { pub fn #identifier ( - values: &mut [crate::interpreter::value::Value], - environment: &std::rc::Rc> - ) -> crate::interpreter::evaluate::EvaluationResult { + values: &mut [ndc_lib::interpreter::value::Value], + environment: &std::rc::Rc> + ) -> ndc_lib::interpreter::evaluate::EvaluationResult { // Define the inner function that has the rust type signature #[inline] #inner @@ -384,11 +384,11 @@ fn wrap_single( }; let function_registration = quote! { - let func = crate::interpreter::function::FunctionBuilder::default() - .body(crate::interpreter::function::FunctionBody::GenericFunction { + let func = ndc_lib::interpreter::function::FunctionBuilder::default() + .body(ndc_lib::interpreter::function::FunctionBody::GenericFunction { function: #identifier, - type_signature: crate::interpreter::function::TypeSignature::Exact(vec![ - #( crate::interpreter::function::Parameter::new(#param_names, #param_types,) ),* + type_signature: ndc_lib::interpreter::function::TypeSignature::Exact(vec![ + #( ndc_lib::interpreter::function::Parameter::new(#param_names, #param_types,) ),* ]), return_type: #return_type, }) @@ -409,10 +409,10 @@ fn wrap_single( fn into_param_type(ty: &syn::Type) -> TokenStream { match ty { ty if path_ends_with(ty, "Vec") => { - quote! { crate::interpreter::function::StaticType::List(Box::new(crate::interpreter::function::StaticType::Any)) } + quote! { ndc_lib::interpreter::function::StaticType::List(Box::new(ndc_lib::interpreter::function::StaticType::Any)) } } ty if path_ends_with(ty, "VecDeque") => { - quote! { crate::interpreter::function::StaticType::Deque(Box::new(crate::interpreter::function::StaticType::Any)) } + quote! { ndc_lib::interpreter::function::StaticType::Deque(Box::new(ndc_lib::interpreter::function::StaticType::Any)) } } ty if path_ends_with(ty, "DefaultMap") || path_ends_with(ty, "DefaultMapMut") @@ -421,42 +421,48 @@ fn into_param_type(ty: &syn::Type) -> TokenStream { temp_create_map_any() } ty if path_ends_with(ty, "MinHeap") => { - quote! { crate::interpreter::function::StaticType::MinHeap(Box::new(crate::interpreter::function::StaticType::Any)) } + quote! { ndc_lib::interpreter::function::StaticType::MinHeap(Box::new(ndc_lib::interpreter::function::StaticType::Any)) } } ty if path_ends_with(ty, "MaxHeap") => { - quote! { crate::interpreter::function::StaticType::MaxHeap(Box::new(crate::interpreter::function::StaticType::Any)) } + quote! { ndc_lib::interpreter::function::StaticType::MaxHeap(Box::new(ndc_lib::interpreter::function::StaticType::Any)) } } ty if path_ends_with(ty, "ListRepr") => { - quote! { crate::interpreter::function::StaticType::List(Box::new(crate::interpreter::function::StaticType::Any)) } + quote! { ndc_lib::interpreter::function::StaticType::List(Box::new(ndc_lib::interpreter::function::StaticType::Any)) } } ty if path_ends_with(ty, "MapRepr") => temp_create_map_any(), syn::Type::Reference(syn::TypeReference { elem, .. }) => into_param_type(elem), syn::Type::Path(syn::TypePath { path, .. }) => match path { - _ if path.is_ident("i64") => quote! { crate::interpreter::function::StaticType::Int }, - _ if path.is_ident("usize") => quote! { crate::interpreter::function::StaticType::Int }, - _ if path.is_ident("f64") => quote! { crate::interpreter::function::StaticType::Float }, - _ if path.is_ident("bool") => quote! { crate::interpreter::function::StaticType::Bool }, + _ if path.is_ident("i64") => quote! { ndc_lib::interpreter::function::StaticType::Int }, + _ if path.is_ident("usize") => { + quote! { ndc_lib::interpreter::function::StaticType::Int } + } + _ if path.is_ident("f64") => { + quote! { ndc_lib::interpreter::function::StaticType::Float } + } + _ if path.is_ident("bool") => { + quote! { ndc_lib::interpreter::function::StaticType::Bool } + } _ if path.is_ident("Value") => { - quote! { crate::interpreter::function::StaticType::Any } + quote! { ndc_lib::interpreter::function::StaticType::Any } } _ if path.is_ident("Number") => { - quote! { crate::interpreter::function::StaticType::Number } + quote! { ndc_lib::interpreter::function::StaticType::Number } } _ if path.is_ident("Sequence") => { - quote! { crate::interpreter::function::StaticType::Sequence(Box::new(crate::interpreter::function::StaticType::Any)) } + quote! { ndc_lib::interpreter::function::StaticType::Sequence(Box::new(ndc_lib::interpreter::function::StaticType::Any)) } } _ if path.is_ident("Callable") => { quote! { - crate::interpreter::function::StaticType::Function { + ndc_lib::interpreter::function::StaticType::Function { parameters: None, - return_type: Box::new(crate::interpreter::function::StaticType::Any) + return_type: Box::new(ndc_lib::interpreter::function::StaticType::Any) } } } _ => panic!("Don't know how to convert Path into StaticType\n\n{path:?}"), }, syn::Type::ImplTrait(_) => { - quote! { crate::interpreter::function::StaticType::Iterator(Box::new(crate::interpreter::function::StaticType::Any)) } + quote! { ndc_lib::interpreter::function::StaticType::Iterator(Box::new(ndc_lib::interpreter::function::StaticType::Any)) } } x => panic!("Don't know how to convert {x:?} into StaticType"), } @@ -488,15 +494,15 @@ fn create_temp_variable( return vec![Argument { param_type: quote! { // TODO: how are we going to figure out the exact type of function here - crate::interpreter::function::StaticType::Function { + ndc_lib::interpreter::function::StaticType::Function { parameters: None, - return_type: Box::new(crate::interpreter::function::StaticType::Any) + return_type: Box::new(ndc_lib::interpreter::function::StaticType::Any) } }, param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Function(#temp_var) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Function(#temp_var) = #argument_var_name else { panic!("Value #position needed to be a Sequence::Map but wasn't"); }; let #argument_var_name = &Callable { @@ -515,7 +521,7 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::Map(#rc_temp_var, _default)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::Map(#rc_temp_var, _default)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::Map but wasn't"); }; let #argument_var_name = &*#rc_temp_var.borrow(); @@ -531,7 +537,7 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::Map(#rc_temp_var, _default)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::Map(#rc_temp_var, _default)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::Map but wasn't"); }; let #argument_var_name = &mut *#rc_temp_var.try_borrow_mut()?; @@ -547,7 +553,7 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::Map(#rc_temp_var, default)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::Map(#rc_temp_var, default)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::Map but wasn't"); }; let #argument_var_name = (&*#rc_temp_var.borrow(), default.to_owned()); @@ -563,7 +569,7 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::Map(#rc_temp_var, default)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::Map(#rc_temp_var, default)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::Map but wasn't"); }; let #argument_var_name = (&mut *#rc_temp_var.try_borrow_mut()?, default.to_owned()); @@ -576,11 +582,11 @@ fn create_temp_variable( let rc_temp_var = syn::Ident::new(&format!("temp_{argument_var_name}"), identifier.span()); return vec![Argument { - param_type: quote! { crate::interpreter::function::StaticType::List(Box::new(crate::interpreter::function::StaticType::Any)) }, + param_type: quote! { ndc_lib::interpreter::function::StaticType::List(Box::new(ndc_lib::interpreter::function::StaticType::Any)) }, param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::List(#rc_temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::List(#rc_temp_var)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::List but wasn't"); }; let #argument_var_name = &mut *#rc_temp_var.try_borrow_mut()?; @@ -596,7 +602,7 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::Deque(#rc_temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::Deque(#rc_temp_var)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::List but wasn't"); }; let #argument_var_name = &mut *#rc_temp_var.try_borrow_mut()?; @@ -612,7 +618,7 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::Deque(#rc_temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::Deque(#rc_temp_var)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::List but wasn't"); }; let #argument_var_name = &*#rc_temp_var.try_borrow()?; @@ -628,7 +634,7 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::MaxHeap(#rc_temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::MaxHeap(#rc_temp_var)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::MaxHeap but wasn't"); }; let #argument_var_name = &mut *#rc_temp_var.try_borrow_mut()?; @@ -644,7 +650,7 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::MaxHeap(#rc_temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::MaxHeap(#rc_temp_var)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::MaxHeap but wasn't"); }; let #argument_var_name = &*#rc_temp_var.try_borrow()?; @@ -660,7 +666,7 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::MinHeap(#rc_temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::MinHeap(#rc_temp_var)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::MinHeap but wasn't"); }; let #argument_var_name = &mut *#rc_temp_var.try_borrow_mut()?; @@ -676,7 +682,7 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::MinHeap(#rc_temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::MinHeap(#rc_temp_var)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::MinHeap but wasn't"); }; let #argument_var_name = &*#rc_temp_var.try_borrow()?; @@ -688,11 +694,11 @@ fn create_temp_variable( let rc_temp_var = syn::Ident::new(&format!("temp_{argument_var_name}"), identifier.span()); return vec![Argument { - param_type: quote! { crate::interpreter::function::StaticType::String }, + param_type: quote! { ndc_lib::interpreter::function::StaticType::String }, param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::String(#rc_temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::String(#rc_temp_var)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::String but wasn't"); }; let #rc_temp_var = #rc_temp_var.borrow(); @@ -704,19 +710,19 @@ fn create_temp_variable( else if is_ref_of_bigint(ty) { let big_int = syn::Ident::new(&format!("temp_{argument_var_name}"), identifier.span()); return vec![Argument { - param_type: quote! { crate::interpreter::function::StaticType::Int }, + param_type: quote! { ndc_lib::interpreter::function::StaticType::Int }, param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let #big_int = if let crate::interpreter::value::Value::Number(crate::interpreter::num::Number::Int(crate::interpreter::int::Int::Int64(smol))) = #argument_var_name { + let #big_int = if let ndc_lib::interpreter::value::Value::Number(ndc_lib::interpreter::num::Number::Int(ndc_lib::interpreter::int::Int::Int64(smol))) = #argument_var_name { Some(num::BigInt::from(*smol)) } else { None }; let #argument_var_name = match #argument_var_name { - crate::interpreter::value::Value::Number(crate::interpreter::num::Number::Int(crate::interpreter::int::Int::BigInt(big))) => big, - crate::interpreter::value::Value::Number(crate::interpreter::num::Number::Int(crate::interpreter::int::Int::Int64(smoll))) => #big_int.as_ref().unwrap(), + ndc_lib::interpreter::value::Value::Number(ndc_lib::interpreter::num::Number::Int(ndc_lib::interpreter::int::Int::BigInt(big))) => big, + ndc_lib::interpreter::value::Value::Number(ndc_lib::interpreter::num::Number::Int(ndc_lib::interpreter::int::Int::Int64(smoll))) => #big_int.as_ref().unwrap(), _ => panic!("Value #position need to be an Int but wasn't"), } }, @@ -725,7 +731,7 @@ fn create_temp_variable( // If we need an owned Value else if path_ends_with(ty, "Value") && !is_ref(ty) { return vec![Argument { - param_type: quote! { crate::interpreter::function::StaticType::Any }, + param_type: quote! { ndc_lib::interpreter::function::StaticType::Any }, param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { @@ -738,11 +744,11 @@ fn create_temp_variable( let rc_temp_var = syn::Ident::new(&format!("temp_{argument_var_name}"), identifier.span()); return vec![Argument { - param_type: quote! { crate::interpreter::function::StaticType::List(Box::new(crate::interpreter::function::StaticType::Any)) }, + param_type: quote! { ndc_lib::interpreter::function::StaticType::List(Box::new(ndc_lib::interpreter::function::StaticType::Any)) }, param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::List(#rc_temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::List(#rc_temp_var)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::List but wasn't"); }; let #argument_var_name = &mut *#rc_temp_var.borrow_mut(); @@ -755,22 +761,22 @@ fn create_temp_variable( syn::Ident::new(&format!("temp_{argument_var_name}"), identifier.span()); return vec![ Argument { - param_type: quote! { crate::interpreter::function::StaticType::List(Box::new(crate::interpreter::function::StaticType::Any)) }, + param_type: quote! { ndc_lib::interpreter::function::StaticType::List(Box::new(ndc_lib::interpreter::function::StaticType::Any)) }, param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::List(#rc_temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::List(#rc_temp_var)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::List but wasn't"); }; let #argument_var_name = &*#rc_temp_var.borrow(); }, }, // Argument { - // param_type: quote! { crate::interpreter::function::StaticType::Tuple }, + // param_type: quote! { ndc_lib::interpreter::function::StaticType::Tuple }, // param_name: quote! { #original_name }, // argument: quote! { #argument_var_name }, // initialize_code: quote! { - // let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::Tuple(#rc_temp_var)) = #argument_var_name else { + // let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::Tuple(#rc_temp_var)) = #argument_var_name else { // panic!("Value #position needed to be a Sequence::List but wasn't"); // }; // let #argument_var_name = &#rc_temp_var; @@ -781,11 +787,11 @@ fn create_temp_variable( // The pattern is &BigRational else if path_ends_with(ty, "BigRational") && is_ref(ty) { return vec![Argument { - param_type: quote! { crate::interpreter::function::StaticType::Rational }, + param_type: quote! { ndc_lib::interpreter::function::StaticType::Rational }, param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Number(crate::interpreter::num::Number::Rational(#argument_var_name)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Number(ndc_lib::interpreter::num::Number::Rational(#argument_var_name)) = #argument_var_name else { panic!("Value #position needs to be Rational but wasn't"); }; @@ -796,11 +802,11 @@ fn create_temp_variable( // The pattern is BigRational else if path_ends_with(ty, "BigRational") && !is_ref(ty) { return vec![Argument { - param_type: quote! { crate::interpreter::function::StaticType::Rational }, + param_type: quote! { ndc_lib::interpreter::function::StaticType::Rational }, param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Number(crate::interpreter::num::Number::Rational(#argument_var_name)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Number(ndc_lib::interpreter::num::Number::Rational(#argument_var_name)) = #argument_var_name else { panic!("VValue #position needs to be Rational but wasn't"); }; @@ -811,11 +817,11 @@ fn create_temp_variable( // The pattern is Complex64 else if path_ends_with(ty, "Complex64") && !is_ref(ty) { return vec![Argument { - param_type: quote! { crate::interpreter::function::StaticType::Complex }, + param_type: quote! { ndc_lib::interpreter::function::StaticType::Complex }, param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Number(crate::interpreter::num::Number::Complex(#argument_var_name)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Number(ndc_lib::interpreter::num::Number::Complex(#argument_var_name)) = #argument_var_name else { panic!("Value #position needs to be Complex64 but wasn't"); }; @@ -830,7 +836,7 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let #argument_var_name = #path :: try_from(#argument_var_name).map_err(|err| crate::interpreter::function::FunctionCallError::ConvertToNativeTypeError(format!("{err}")))? + let #argument_var_name = #path :: try_from(#argument_var_name).map_err(|err| ndc_lib::interpreter::function::FunctionCallError::ConvertToNativeTypeError(format!("{err}")))? }, }]; } @@ -841,7 +847,7 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let #argument_var_name = <#type_ref as TryFrom<&mut crate::interpreter::value::Value>> :: try_from(#argument_var_name).map_err(|err| crate::interpreter::function::FunctionCallError::ConvertToNativeTypeError(format!("{err}")))? + let #argument_var_name = <#type_ref as TryFrom<&mut ndc_lib::interpreter::value::Value>> :: try_from(#argument_var_name).map_err(|err| ndc_lib::interpreter::function::FunctionCallError::ConvertToNativeTypeError(format!("{err}")))? }, }]; } @@ -856,11 +862,11 @@ fn create_temp_variable( param_name: quote! { #original_name }, argument: quote! { #argument_var_name }, initialize_code: quote! { - let crate::interpreter::value::Value::Sequence(crate::interpreter::sequence::Sequence::Iterator(#rc_temp_var)) = #argument_var_name else { + let ndc_lib::interpreter::value::Value::Sequence(ndc_lib::interpreter::sequence::Sequence::Iterator(#rc_temp_var)) = #argument_var_name else { panic!("Value #position needed to be a Sequence::Iterator but wasn't"); }; - let #argument_var_name = crate::interpreter::iterator::RcIter::new(Rc::clone(#rc_temp_var)); + let #argument_var_name = ndc_lib::interpreter::iterator::RcIter::new(Rc::clone(#rc_temp_var)); }, }]; } else { @@ -874,9 +880,9 @@ fn create_temp_variable( // TODO: just adding Any as type here is lazy AF but CBA fixing generics pub fn temp_create_map_any() -> TokenStream { quote! { - crate::interpreter::function::StaticType::Map { - key: Box::new(crate::interpreter::function::StaticType::Any), - value: Box::new(crate::interpreter::function::StaticType::Any) + ndc_lib::interpreter::function::StaticType::Map { + key: Box::new(ndc_lib::interpreter::function::StaticType::Any), + value: Box::new(ndc_lib::interpreter::function::StaticType::Any) } } } diff --git a/ndc_macros/src/lib.rs b/ndc_macros/src/lib.rs index b1b8e5c0..1a9b4ccf 100644 --- a/ndc_macros/src/lib.rs +++ b/ndc_macros/src/lib.rs @@ -43,7 +43,7 @@ pub fn export_module(_attr: TokenStream, item: TokenStream) -> TokenStream { } let register_function = quote! { - pub fn register(env: &mut crate::interpreter::environment::Environment) { + pub fn register(env: &mut ndc_lib::interpreter::environment::Environment) { #(#registrations)* } }; diff --git a/ndc_stdlib/Cargo.toml b/ndc_stdlib/Cargo.toml new file mode 100644 index 00000000..8da35e51 --- /dev/null +++ b/ndc_stdlib/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "ndc_stdlib" +edition.workspace = true +version.workspace = true + +[dependencies] +anyhow.workspace = true +factorial.workspace = true +itertools.workspace = true +ndc_lib = { workspace = true } +ndc_macros.workspace = true +num.workspace = true +once_cell.workspace = true +rand.workspace = true +regex.workspace = true +serde_json = { workspace = true } +tap.workspace = true + +# Crypto +md5 = { version = "0.8.0", optional = true } +sha1 = { version = "0.10.6", optional = true } + +[features] +default = ["ahash", "crypto"] +ahash = ["ndc_lib/ahash"] +crypto = ["dep:md5", "dep:sha1"] diff --git a/ndc_lib/src/stdlib/aoc.rs b/ndc_stdlib/src/aoc.rs similarity index 80% rename from ndc_lib/src/stdlib/aoc.rs rename to ndc_stdlib/src/aoc.rs index 2d0430ad..d04a179b 100644 --- a/ndc_lib/src/stdlib/aoc.rs +++ b/ndc_stdlib/src/aoc.rs @@ -4,10 +4,10 @@ mod inner { use std::cell::RefCell; use std::rc::Rc; - use crate::hash_map::HashMap; - use crate::interpreter::iterator::mut_seq_to_iterator; - use crate::interpreter::sequence::Sequence; - use crate::interpreter::value::Value; + use ndc_lib::hash_map::HashMap; + use ndc_lib::interpreter::iterator::mut_seq_to_iterator; + use ndc_lib::interpreter::sequence::Sequence; + use ndc_lib::interpreter::value::Value; /// Counts the occurrences of each item in a sequence and returns a map with the frequencies. #[function(return_type = HashMap<_, _>)] diff --git a/ndc_lib/src/stdlib/cmp.rs b/ndc_stdlib/src/cmp.rs similarity index 96% rename from ndc_lib/src/stdlib/cmp.rs rename to ndc_stdlib/src/cmp.rs index 47feef7b..a9a160f9 100644 --- a/ndc_lib/src/stdlib/cmp.rs +++ b/ndc_stdlib/src/cmp.rs @@ -2,8 +2,8 @@ mod inner { use anyhow::anyhow; - use crate::compare::FallibleOrd; - use crate::interpreter::value::Value; + use ndc_lib::compare::FallibleOrd; + use ndc_lib::interpreter::value::Value; use std::cmp::Ordering; /// Produces an error if the argument is not true. diff --git a/ndc_lib/src/stdlib/crypto.rs b/ndc_stdlib/src/crypto.rs similarity index 100% rename from ndc_lib/src/stdlib/crypto.rs rename to ndc_stdlib/src/crypto.rs diff --git a/ndc_lib/src/stdlib/deque.rs b/ndc_stdlib/src/deque.rs similarity index 97% rename from ndc_lib/src/stdlib/deque.rs rename to ndc_stdlib/src/deque.rs index 02afff20..23e52af5 100644 --- a/ndc_lib/src/stdlib/deque.rs +++ b/ndc_stdlib/src/deque.rs @@ -2,8 +2,8 @@ use ndc_macros::export_module; #[export_module] mod inner { - use crate::interpreter::sequence::Sequence; - use crate::interpreter::value::Value; + use ndc_lib::interpreter::sequence::Sequence; + use ndc_lib::interpreter::value::Value; use std::cell::RefCell; use std::collections::VecDeque; use std::rc::Rc; diff --git a/ndc_lib/src/stdlib/file.rs b/ndc_stdlib/src/file.rs similarity index 96% rename from ndc_lib/src/stdlib/file.rs rename to ndc_stdlib/src/file.rs index 277b4bd7..0388ebbc 100644 --- a/ndc_lib/src/stdlib/file.rs +++ b/ndc_stdlib/src/file.rs @@ -1,8 +1,8 @@ -use crate::interpreter::environment::Environment; -use crate::interpreter::function::{ +use ndc_lib::interpreter::environment::Environment; +use ndc_lib::interpreter::function::{ FunctionBody, FunctionBuilder, FunctionCarrier, StaticType, TypeSignature, }; -use crate::interpreter::value::Value; +use ndc_lib::interpreter::value::Value; use ndc_macros::export_module; use std::fs::read_to_string; diff --git a/ndc_lib/src/stdlib/hash_map.rs b/ndc_stdlib/src/hash_map.rs similarity index 97% rename from ndc_lib/src/stdlib/hash_map.rs rename to ndc_stdlib/src/hash_map.rs index 4d448ad0..890fcae1 100644 --- a/ndc_lib/src/stdlib/hash_map.rs +++ b/ndc_stdlib/src/hash_map.rs @@ -1,8 +1,8 @@ -use crate::hash_map; -use crate::hash_map::HashMap; -use crate::hash_map::HashMapExt; -use crate::interpreter::sequence::{DefaultMap, MapRepr, Sequence}; -use crate::interpreter::value::Value; +use ndc_lib::hash_map; +use ndc_lib::hash_map::HashMap; +use ndc_lib::hash_map::HashMapExt; +use ndc_lib::interpreter::sequence::{DefaultMap, MapRepr, Sequence}; +use ndc_lib::interpreter::value::Value; use std::cell::RefCell; use std::rc::Rc; diff --git a/ndc_lib/src/stdlib/heap.rs b/ndc_stdlib/src/heap.rs similarity index 90% rename from ndc_lib/src/stdlib/heap.rs rename to ndc_stdlib/src/heap.rs index 9c6a2d5e..5c9385e9 100644 --- a/ndc_lib/src/stdlib/heap.rs +++ b/ndc_stdlib/src/heap.rs @@ -2,9 +2,9 @@ use ndc_macros::export_module; #[export_module] mod inner { - use crate::interpreter::heap::{MaxHeap, MinHeap}; - use crate::interpreter::sequence::Sequence; - use crate::interpreter::value::Value; + use ndc_lib::interpreter::heap::{MaxHeap, MinHeap}; + use ndc_lib::interpreter::sequence::Sequence; + use ndc_lib::interpreter::value::Value; use std::cell::RefCell; use std::rc::Rc; diff --git a/ndc_lib/src/stdlib/mod.rs b/ndc_stdlib/src/lib.rs similarity index 74% rename from ndc_lib/src/stdlib/mod.rs rename to ndc_stdlib/src/lib.rs index 2c82bb1c..41270177 100644 --- a/ndc_lib/src/stdlib/mod.rs +++ b/ndc_stdlib/src/lib.rs @@ -1,4 +1,5 @@ -use crate::interpreter::environment::Environment; +use ndc_lib::interpreter::Interpreter; +use ndc_lib::interpreter::environment::Environment; pub mod aoc; pub mod cmp; @@ -39,3 +40,14 @@ pub fn register(env: &mut Environment) { string::register(env); value::register(env); } + +pub trait WithStdlib: Sized { + fn with_stdlib(self) -> Self; +} + +impl WithStdlib for Interpreter { + fn with_stdlib(mut self) -> Self { + self.configure(register); + self + } +} diff --git a/ndc_lib/src/stdlib/list.rs b/ndc_stdlib/src/list.rs similarity index 97% rename from ndc_lib/src/stdlib/list.rs rename to ndc_stdlib/src/list.rs index 66fc5b74..f5d25483 100644 --- a/ndc_lib/src/stdlib/list.rs +++ b/ndc_stdlib/src/list.rs @@ -1,9 +1,9 @@ #[ndc_macros::export_module] mod inner { - use crate::interpreter::iterator::mut_seq_to_iterator; - use crate::interpreter::sequence::{ListRepr, Sequence}; - use crate::interpreter::value::Value; use itertools::Itertools; + use ndc_lib::interpreter::iterator::mut_seq_to_iterator; + use ndc_lib::interpreter::sequence::{ListRepr, Sequence}; + use ndc_lib::interpreter::value::Value; use std::rc::Rc; use anyhow::anyhow; diff --git a/ndc_lib/src/stdlib/math.rs b/ndc_stdlib/src/math.rs similarity index 97% rename from ndc_lib/src/stdlib/math.rs rename to ndc_stdlib/src/math.rs index 40f028cf..211fb1d1 100644 --- a/ndc_lib/src/stdlib/math.rs +++ b/ndc_stdlib/src/math.rs @@ -1,8 +1,8 @@ -use crate::interpreter::environment::Environment; -use crate::interpreter::num::{BinaryOperatorError, Number}; -use crate::interpreter::sequence::Sequence; -use crate::interpreter::value::Value; use factorial::Factorial; +use ndc_lib::interpreter::environment::Environment; +use ndc_lib::interpreter::num::{BinaryOperatorError, Number}; +use ndc_lib::interpreter::sequence::Sequence; +use ndc_lib::interpreter::value::Value; use ndc_macros::export_module; use num::ToPrimitive; use std::ops::{Add, Mul}; @@ -52,9 +52,9 @@ mod inner { use std::ops::Sub; use super::FallibleSum; - use crate::interpreter::int::Int; - use crate::interpreter::num::Number; use anyhow::Context; + use ndc_lib::interpreter::int::Int; + use ndc_lib::interpreter::num::Number; use num::{BigInt, BigRational, BigUint, Integer, complex::Complex64}; /// Returns the sign of a number. @@ -209,11 +209,11 @@ mod inner { pub mod f64 { use super::{Environment, Number, ToPrimitive, f64}; - use crate::interpreter::function::{ + use ndc_lib::interpreter::function::{ FunctionBody, FunctionBuilder, FunctionCarrier, Parameter, StaticType, TypeSignature, }; - use crate::interpreter::num::BinaryOperatorError; - use crate::interpreter::value::Value; + use ndc_lib::interpreter::num::BinaryOperatorError; + use ndc_lib::interpreter::value::Value; use std::cmp::Ordering; use std::ops::Not; @@ -475,7 +475,7 @@ pub mod f64 { ($method:ident,$docs:literal) => { let function = FunctionBuilder::default() .body( - $crate::interpreter::function::FunctionBody::NumericUnaryOp { + ndc_lib::interpreter::function::FunctionBody::NumericUnaryOp { body: |num: Number| match num { Number::Int(i) => Number::Float(f64::from(i).$method()), Number::Float(f) => Number::Float(f.$method()), diff --git a/ndc_lib/src/stdlib/rand.rs b/ndc_stdlib/src/rand.rs similarity index 92% rename from ndc_lib/src/stdlib/rand.rs rename to ndc_stdlib/src/rand.rs index 6f5fa2ea..66bb1ffd 100644 --- a/ndc_lib/src/stdlib/rand.rs +++ b/ndc_stdlib/src/rand.rs @@ -19,11 +19,11 @@ pub fn random_n( #[export_module] mod inner { - use crate::interpreter::iterator::mut_seq_to_iterator; - use crate::interpreter::num::Number; - use crate::interpreter::sequence::Sequence; - use crate::interpreter::value::Value; use itertools::Itertools; + use ndc_lib::interpreter::iterator::mut_seq_to_iterator; + use ndc_lib::interpreter::num::Number; + use ndc_lib::interpreter::sequence::Sequence; + use ndc_lib::interpreter::value::Value; /// Randomly shuffles the elements of the list in place. pub fn shuffle(list: &mut [Value]) { diff --git a/ndc_lib/src/stdlib/regex.rs b/ndc_stdlib/src/regex.rs similarity index 98% rename from ndc_lib/src/stdlib/regex.rs rename to ndc_stdlib/src/regex.rs index 5ea2aeee..7a4362a7 100644 --- a/ndc_lib/src/stdlib/regex.rs +++ b/ndc_stdlib/src/regex.rs @@ -1,4 +1,4 @@ -use crate::interpreter::value::Value; +use ndc_lib::interpreter::value::Value; use once_cell::sync::Lazy; use regex::Regex; diff --git a/ndc_lib/src/stdlib/sequence.rs b/ndc_stdlib/src/sequence.rs similarity index 98% rename from ndc_lib/src/stdlib/sequence.rs rename to ndc_stdlib/src/sequence.rs index d56fdd72..64d3f26e 100644 --- a/ndc_lib/src/stdlib/sequence.rs +++ b/ndc_stdlib/src/sequence.rs @@ -1,13 +1,13 @@ #![allow(clippy::ptr_arg)] -use crate::interpreter::iterator::{MutableValueIntoIterator, mut_seq_to_iterator}; -use crate::interpreter::sequence::Sequence; -use crate::{ +use anyhow::anyhow; +use itertools::Itertools; +use ndc_lib::interpreter::iterator::{MutableValueIntoIterator, mut_seq_to_iterator}; +use ndc_lib::interpreter::sequence::Sequence; +use ndc_lib::{ compare::FallibleOrd, interpreter::{evaluate::EvaluationResult, function::Callable, value::Value}, }; -use anyhow::anyhow; -use itertools::Itertools; use ndc_macros::export_module; use std::cmp::Ordering; use std::rc::Rc; @@ -79,8 +79,8 @@ fn try_sort_by( #[export_module] mod inner { - use crate::interpreter::iterator::{Repeat, ValueIterator}; - use crate::interpreter::{function::FunctionCarrier, iterator::mut_value_to_iterator}; + use ndc_lib::interpreter::iterator::{Repeat, ValueIterator}; + use ndc_lib::interpreter::{function::FunctionCarrier, iterator::mut_value_to_iterator}; use std::cell::RefCell; #[function(name = "in")] @@ -832,8 +832,8 @@ pub mod extra { use anyhow::anyhow; use itertools::izip; - use crate::interpreter::function::{FunctionBuilder, StaticType}; - use crate::interpreter::{ + use ndc_lib::interpreter::function::{FunctionBuilder, StaticType}; + use ndc_lib::interpreter::{ environment::Environment, function::FunctionBody, iterator::mut_value_to_iterator, value::Value, }; @@ -844,7 +844,7 @@ pub mod extra { .name("zip".to_string()) .documentation("Combines multiple sequences (or iterables) into a single sequence of tuples, where the ith tuple contains the ith element from each input sequence.\n\nIf the input sequences are of different lengths, the resulting sequence is truncated to the length of the shortest input.".to_string()) .body(FunctionBody::generic( - crate::interpreter::function::TypeSignature::Variadic, + ndc_lib::interpreter::function::TypeSignature::Variadic, StaticType::List(Box::new(StaticType::Tuple(vec![StaticType::Any, StaticType::Any]))), |args, _env| match args { [_] => { diff --git a/ndc_stdlib/src/serde.rs b/ndc_stdlib/src/serde.rs new file mode 100644 index 00000000..01939ee6 --- /dev/null +++ b/ndc_stdlib/src/serde.rs @@ -0,0 +1,132 @@ +use ndc_macros::export_module; +use std::rc::Rc; +use std::{cell::RefCell, str::FromStr}; + +use anyhow::Context; +use ndc_lib::hash_map::HashMap; +use ndc_lib::interpreter::sequence::Sequence; +use ndc_lib::interpreter::value::Value; +use num::BigInt; +use num::ToPrimitive; +use serde_json::{Map, Number, Value as JsonValue, json}; + +fn value_to_json(value: Value) -> Result { + match value { + Value::Option(Some(value)) => value_to_json(*value), + Value::Option(None) => Ok(JsonValue::Null), + Value::Number(number) => match number { + ndc_lib::interpreter::num::Number::Int(int) => match int { + ndc_lib::interpreter::int::Int::Int64(i) => Ok(json!(i)), + ndc_lib::interpreter::int::Int::BigInt(big_int) => { + Number::from_str(&big_int.to_string()) + .map(JsonValue::Number) + .context("Cannot convert bigint to string") + } + }, + ndc_lib::interpreter::num::Number::Float(f) => Ok(json!(f)), + ndc_lib::interpreter::num::Number::Rational(ratio) => Ok(json!(ratio.to_f64())), + ndc_lib::interpreter::num::Number::Complex(complex) => Ok(json!(format!("{complex}"))), + }, + Value::Bool(b) => Ok(json!(b)), + Value::Sequence(s) => match s { + Sequence::String(s) => Ok(json!(&*s.borrow())), + Sequence::List(values) => Ok(JsonValue::Array( + values + .borrow() + .iter() + .map(|v| value_to_json(v.clone())) + .collect::, _>>()?, + )), + Sequence::Tuple(values) => match values.len() { + 0 => Ok(JsonValue::Null), + _ => Ok(JsonValue::Array( + values + .iter() + .map(|v| value_to_json(v.clone())) + .collect::, _>>()?, + )), + }, + Sequence::Map(values, _) => Ok(JsonValue::Object( + values + .borrow() + .iter() + .map(|(key, value)| { + value_to_json(value.clone()).map(|value| (key.to_string(), value)) + }) + .collect::, _>>()?, + )), + Sequence::Iterator(i) => { + let mut i = i.borrow_mut(); + let mut out = Vec::new(); + for value in i.by_ref() { + out.push(value_to_json(value)?); + } + Ok(JsonValue::Array(out)) + } + Sequence::MaxHeap(h) => Ok(JsonValue::Array( + h.borrow() + .iter() + .map(|h| value_to_json(h.0.clone())) + .collect::, _>>()?, + )), + Sequence::MinHeap(h) => Ok(JsonValue::Array( + h.borrow() + .iter() + .map(|h| value_to_json(h.0.0.clone())) + .collect::, _>>()?, + )), + Sequence::Deque(d) => Ok(JsonValue::Array( + d.borrow() + .iter() + .map(|v| value_to_json(v.clone())) + .collect::, _>>()?, + )), + }, + Value::Function(_) => Err(anyhow::anyhow!("Unable to serialize function")), + } +} + +fn json_to_value(value: JsonValue) -> Result { + Ok(match value { + JsonValue::Null => Value::unit(), + JsonValue::Bool(b) => Value::Bool(b), + JsonValue::Number(n) => n.as_str().parse::().map(Value::from).or_else(|_| { + n.as_f64() + .map(Value::from) + .context("Cannot parse number as int or float") + })?, + JsonValue::String(s) => Value::string(s), + JsonValue::Array(a) => Value::list( + a.into_iter() + .map(json_to_value) + .collect::, _>>()?, + ), + JsonValue::Object(o) => Value::Sequence(Sequence::Map( + Rc::new(RefCell::new( + o.into_iter() + .map(|(key, value)| { + json_to_value(value).map(|value| (Value::string(key), value)) + }) + .collect::, _>>()?, + )), + None, + )), + }) +} + +#[export_module] +mod inner { + use ndc_lib::interpreter::value::Value; + + /// Converts a JSON string to a value + pub fn json_decode(input: &str) -> anyhow::Result { + let json: JsonValue = serde_json::from_str(input)?; + json_to_value(json) + } + + /// Converts the input value to JSON + pub fn json_encode(input: Value) -> anyhow::Result { + let v = value_to_json(input)?; + Ok(v.to_string()) + } +} diff --git a/ndc_lib/src/stdlib/string.rs b/ndc_stdlib/src/string.rs similarity index 98% rename from ndc_lib/src/stdlib/string.rs rename to ndc_stdlib/src/string.rs index 9c3b4d3f..0819e0b9 100644 --- a/ndc_lib/src/stdlib/string.rs +++ b/ndc_stdlib/src/string.rs @@ -1,8 +1,8 @@ use ndc_macros::export_module; -use crate::interpreter::iterator::mut_seq_to_iterator; -use crate::interpreter::sequence::{Sequence, StringRepr}; -use crate::interpreter::value::Value; +use ndc_lib::interpreter::iterator::mut_seq_to_iterator; +use ndc_lib::interpreter::sequence::{Sequence, StringRepr}; +use ndc_lib::interpreter::value::Value; use std::rc::Rc; use anyhow::{Context, anyhow}; diff --git a/ndc_lib/src/stdlib/value.rs b/ndc_stdlib/src/value.rs similarity index 96% rename from ndc_lib/src/stdlib/value.rs rename to ndc_stdlib/src/value.rs index b8f8c80a..eebca82e 100644 --- a/ndc_lib/src/stdlib/value.rs +++ b/ndc_stdlib/src/value.rs @@ -3,10 +3,10 @@ use std::fmt::Write; #[export_module] mod inner { - use crate::interpreter::function::Callable; - use crate::interpreter::heap::{MaxHeap, MinHeap}; - use crate::interpreter::sequence::Sequence; - use crate::interpreter::value::Value; + use ndc_lib::interpreter::function::Callable; + use ndc_lib::interpreter::heap::{MaxHeap, MinHeap}; + use ndc_lib::interpreter::sequence::Sequence; + use ndc_lib::interpreter::value::Value; use std::cell::RefCell; use std::rc::Rc; diff --git a/tests/Cargo.toml b/tests/Cargo.toml index b030f322..5228def1 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -5,6 +5,7 @@ version.workspace = true [dev-dependencies] ndc_lib.workspace = true +ndc_stdlib.workspace = true owo-colors.workspace = true [[test]] diff --git a/tests/src/programs.rs b/tests/src/programs.rs index 648a44a3..87d2d539 100644 --- a/tests/src/programs.rs +++ b/tests/src/programs.rs @@ -1,4 +1,5 @@ use ndc_lib::interpreter::Interpreter; +use ndc_stdlib::WithStdlib; use owo_colors::OwoColorize; use std::fs; use std::path::PathBuf; @@ -23,7 +24,7 @@ fn run_ndc_test(path: PathBuf) -> Result<(), std::io::Error> { print!("Running {path:?}..."); - let mut interpreter = Interpreter::new(Vec::new()); + let mut interpreter = Interpreter::new(Vec::new()).with_stdlib(); let interpreter_result = interpreter.run_str(&contents); let program_had_error = interpreter_result.is_err();