From 966983920eee3996486bcd58ca8fc2a9904912eb Mon Sep 17 00:00:00 2001 From: Jeff Date: Sun, 24 Mar 2024 15:35:19 -0400 Subject: [PATCH] Toy with chumsky and ariadne --- dust-lang/src/abstract_tree/function_call.rs | 12 ++ dust-lang/src/abstract_tree/type.rs | 2 +- dust-lang/src/abstract_tree/value_node.rs | 4 + dust-lang/src/built_in_functions.rs | 8 +- dust-lang/src/lexer.rs | 31 +---- dust-lang/src/lib.rs | 127 +++++++++++-------- dust-lang/src/parser.rs | 12 +- dust-lang/tests/expressions.rs | 19 +-- dust-lang/tests/functions.rs | 23 ++-- dust-lang/tests/statements.rs | 15 +-- dust-lang/tests/structs.rs | 15 +-- dust-lang/tests/values.rs | 71 ++++------- dust-lang/tests/variables.rs | 13 +- dust-shell/src/cli.rs | 6 +- dust-shell/src/main.rs | 24 ++-- 15 files changed, 181 insertions(+), 201 deletions(-) diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs index 9dd3f60..dacf206 100644 --- a/dust-lang/src/abstract_tree/function_call.rs +++ b/dust-lang/src/abstract_tree/function_call.rs @@ -66,6 +66,18 @@ impl AbstractNode for FunctionCall { })?; } + for (type_parameter, expression) in parameter_types.iter().zip(self.arguments.iter()) { + let actual = expression.node.expected_type(context)?; + + type_parameter.node.check(&actual).map_err(|conflict| { + ValidationError::TypeCheck { + conflict, + actual_position: expression.position, + expected_position: type_parameter.position, + } + })?; + } + Ok(()) } else { Err(ValidationError::ExpectedFunction { diff --git a/dust-lang/src/abstract_tree/type.rs b/dust-lang/src/abstract_tree/type.rs index 22f2b02..3cd04ff 100644 --- a/dust-lang/src/abstract_tree/type.rs +++ b/dust-lang/src/abstract_tree/type.rs @@ -180,7 +180,7 @@ impl Display for Type { write!(f, ") : {}", return_type.node) } Type::Structure { name, .. } => write!(f, "{name}"), - Type::Argument(_) => todo!(), + Type::Argument(identifier) => write!(f, "{identifier}"), } } } diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index 985b1fb..bd7e6fd 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -115,6 +115,8 @@ impl AbstractNode for ValueNode { })?; } } + + return Ok(()); } if let ValueNode::ParsedFunction { @@ -150,6 +152,8 @@ impl AbstractNode for ValueNode { actual_position: body.position, expected_position: return_type.position, })?; + + return Ok(()); } if let ValueNode::Structure { diff --git a/dust-lang/src/built_in_functions.rs b/dust-lang/src/built_in_functions.rs index e7455cc..307d56c 100644 --- a/dust-lang/src/built_in_functions.rs +++ b/dust-lang/src/built_in_functions.rs @@ -13,7 +13,7 @@ use crate::{ Value, }; -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum BuiltInFunction { ReadLine, Sleep, @@ -23,9 +23,9 @@ pub enum BuiltInFunction { impl BuiltInFunction { pub fn name(&self) -> &'static str { match self { - BuiltInFunction::ReadLine => todo!(), - BuiltInFunction::Sleep => todo!(), - BuiltInFunction::WriteLine => todo!(), + BuiltInFunction::ReadLine => "__READ_LINE__", + BuiltInFunction::Sleep => "__SLEEP__", + BuiltInFunction::WriteLine => "__WRITE_LINE__", } } diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index 9cd1581..6f19cac 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -5,12 +5,12 @@ use std::{ use chumsky::prelude::*; -use crate::error::Error; +use crate::{built_in_functions::BuiltInFunction, error::Error}; #[derive(Copy, Clone, Debug, PartialEq)] pub enum Token<'src> { Boolean(bool), - BuiltInIdentifier(BuiltInIdentifier), + BuiltInFunction(BuiltInFunction), Integer(i64), Float(f64), String(&'src str), @@ -24,7 +24,7 @@ impl<'src> Display for Token<'src> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Token::Boolean(boolean) => write!(f, "{boolean}"), - Token::BuiltInIdentifier(built_in_identifier) => write!(f, "{built_in_identifier}"), + Token::BuiltInFunction(built_in_identifier) => write!(f, "{built_in_identifier}"), Token::Integer(integer) => write!(f, "{integer}"), Token::Float(float) => write!(f, "{float}"), Token::String(string) => write!(f, "{string}"), @@ -36,23 +36,6 @@ impl<'src> Display for Token<'src> { } } -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum BuiltInIdentifier { - ReadLine, - Sleep, - WriteLine, -} - -impl Display for BuiltInIdentifier { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - BuiltInIdentifier::ReadLine => write!(f, "__READ_LINE__"), - BuiltInIdentifier::Sleep => write!(f, "__SLEEP__"), - BuiltInIdentifier::WriteLine => write!(f, "__WRITE_LINE__"), - } - } -} - #[derive(Copy, Clone, Debug, PartialEq)] pub enum Keyword { Any, @@ -315,11 +298,11 @@ pub fn lexer<'src>() -> impl Parser< .map(Token::Keyword); let built_in_identifier = choice(( - just("__READ_LINE__").to(BuiltInIdentifier::ReadLine), - just("__SLEEP__").to(BuiltInIdentifier::Sleep), - just("__WRITE_LINE__").to(BuiltInIdentifier::WriteLine), + just(BuiltInFunction::ReadLine.name()).to(BuiltInFunction::ReadLine), + just(BuiltInFunction::Sleep.name()).to(BuiltInFunction::Sleep), + just(BuiltInFunction::WriteLine.name()).to(BuiltInFunction::WriteLine), )) - .map(Token::BuiltInIdentifier); + .map(Token::BuiltInFunction); choice(( boolean, diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 55fe397..f9cc274 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -6,7 +6,7 @@ pub mod lexer; pub mod parser; pub mod value; -use std::{ops::Range, rc::Rc}; +use std::{cell::RefCell, ops::Range, rc::Rc, vec}; use abstract_tree::Type; use ariadne::{Color, Fmt, Label, Report, ReportKind}; @@ -16,20 +16,88 @@ use lexer::lex; use parser::parse; pub use value::Value; -pub fn interpret(source_id: Rc, source: &str) -> Result, InterpreterError> { +pub fn interpret<'src>(source_id: &str, source: &str) -> Result, InterpreterError> { let mut interpreter = Interpreter::new(Context::new()); - interpreter.load_std()?; - interpreter.run(source_id, source) + interpreter.run(Rc::new(source_id.to_string()), Rc::from(source)) } pub fn interpret_without_std( - source_id: Rc, + source_id: &str, source: &str, ) -> Result, InterpreterError> { let mut interpreter = Interpreter::new(Context::new()); - interpreter.run(source_id, source) + interpreter.run(Rc::new(source_id.to_string()), Rc::from(source)) +} + +pub struct Interpreter { + context: Context, + sources: Rc, Rc)>>>, +} + +impl Interpreter { + pub fn new(context: Context) -> Self { + Interpreter { + context, + sources: Rc::new(RefCell::new(Vec::new())), + } + } + + pub fn run( + &mut self, + source_id: Rc, + source: Rc, + ) -> Result, InterpreterError> { + let tokens = lex(source.as_ref()).map_err(|errors| InterpreterError { + source_id: source_id.clone(), + errors, + })?; + let abstract_tree = parse(&tokens).map_err(|errors| InterpreterError { + source_id: source_id.clone(), + errors, + })?; + let value_option = abstract_tree + .run(&self.context) + .map_err(|errors| InterpreterError { + source_id: source_id.clone(), + errors, + })?; + + self.sources.borrow_mut().push((source_id, source.into())); + + Ok(value_option) + } + + pub fn run_all, Rc)>>( + &mut self, + sources: T, + ) -> Result, InterpreterError> { + let mut previous_value_option = None; + + for (source_id, source) in sources { + previous_value_option = self.run(source_id.clone(), source)?; + } + + Ok(previous_value_option) + } + + pub fn load_std(&mut self) -> Result, InterpreterError> { + self.run_all([ + ( + Rc::new("std/io.ds".to_string()), + Rc::from(include_str!("../../std/io.ds")), + ), + ( + Rc::new("std/thread.ds".to_string()), + Rc::from(include_str!("../../std/thread.ds")), + ), + ]) + } + + pub fn sources(&self) -> vec::IntoIter<(Rc, Rc)> { + self.sources.borrow().clone().into_iter() + } } #[derive(Debug, PartialEq)] @@ -45,7 +113,7 @@ impl InterpreterError { } impl InterpreterError { - pub fn build_reports<'id>(self) -> Vec, Range)>> { + pub fn build_reports<'a>(self) -> Vec, Range)>> { let mut reports = Vec::new(); for error in self.errors { @@ -170,8 +238,6 @@ impl InterpreterError { } => { let TypeConflict { actual, expected } = conflict; - builder = builder.with_message("A type conflict was found."); - builder.add_labels([ Label::new(( self.source_id.clone(), @@ -257,46 +323,3 @@ impl InterpreterError { reports } } - -pub struct Interpreter { - context: Context, -} - -impl Interpreter { - pub fn new(context: Context) -> Self { - Interpreter { context } - } - - pub fn run( - &mut self, - source_id: Rc, - source: &str, - ) -> Result, InterpreterError> { - let tokens = lex(source).map_err(|errors| InterpreterError { - source_id: source_id.clone(), - errors, - })?; - let abstract_tree = parse(&tokens).map_err(|errors| InterpreterError { - source_id: source_id.clone(), - errors, - })?; - let value_option = abstract_tree - .run(&self.context) - .map_err(|errors| InterpreterError { source_id, errors })?; - - Ok(value_option) - } - - pub fn load_std(&mut self) -> Result<(), InterpreterError> { - self.run( - Rc::new("std/io.ds".to_string()), - include_str!("../../std/io.ds"), - )?; - self.run( - Rc::new("std/io.ds".to_string()), - include_str!("../../std/thread.ds"), - )?; - - Ok(()) - } -} diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 635c814..230e8fb 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -4,9 +4,8 @@ use chumsky::{input::SpannedInput, pratt::*, prelude::*}; use crate::{ abstract_tree::*, - built_in_functions::BuiltInFunction, error::Error, - lexer::{BuiltInIdentifier, Control, Keyword, Operator, Token}, + lexer::{Control, Keyword, Operator, Token}, }; pub type ParserInput<'src> = @@ -256,11 +255,8 @@ pub fn parser<'src>() -> impl Parser< let built_in_function = { select! { - Token::BuiltInIdentifier(built_in_identifier) => { - match built_in_identifier {BuiltInIdentifier::ReadLine=>BuiltInFunction::ReadLine,BuiltInIdentifier::WriteLine=>BuiltInFunction::WriteLine, - BuiltInIdentifier::Sleep => BuiltInFunction::Sleep, } - } - } + Token::BuiltInFunction(built_in_function) => built_in_function, + } } .map_with(|built_in_function, state| { Expression::Value(ValueNode::BuiltInFunction(built_in_function)) @@ -582,7 +578,7 @@ pub fn parser<'src>() -> impl Parser< #[cfg(test)] mod tests { - use crate::lexer::lex; + use crate::{built_in_functions::BuiltInFunction, lexer::lex}; use super::*; diff --git a/dust-lang/tests/expressions.rs b/dust-lang/tests/expressions.rs index ff27ac8..90b26c7 100644 --- a/dust-lang/tests/expressions.rs +++ b/dust-lang/tests/expressions.rs @@ -1,27 +1,22 @@ -use std::rc::Rc; - use dust_lang::*; #[test] fn logic() { assert_eq!( - interpret(Rc::new("test".to_string()), "1 == 1").unwrap(), + interpret("test", "1 == 1").unwrap(), Some(Value::boolean(true)) ); assert_eq!( - interpret(Rc::new("test".to_string()), "('42' == '42') && (42 != 0)").unwrap(), + interpret("test", "('42' == '42') && (42 != 0)").unwrap(), Some(Value::boolean(true)) ); } #[test] fn math() { + assert_eq!(interpret("test", "1 + 1").unwrap(), Some(Value::integer(2))); assert_eq!( - interpret(Rc::new("test".to_string()), "1 + 1").unwrap(), - Some(Value::integer(2)) - ); - assert_eq!( - interpret(Rc::new("test".to_string()), "2 * (21 + 19 + 1 * 2) / 2").unwrap(), + interpret("test", "2 * (21 + 19 + 1 * 2) / 2").unwrap(), Some(Value::integer(42)) ); } @@ -29,7 +24,7 @@ fn math() { #[test] fn list_index() { assert_eq!( - interpret(Rc::new("test".to_string()), "foo = [1, 2, 3]; foo[2]").unwrap(), + interpret("test", "foo = [1, 2, 3]; foo[2]").unwrap(), Some(Value::integer(3)) ); } @@ -37,11 +32,11 @@ fn list_index() { #[test] fn map_index() { assert_eq!( - interpret(Rc::new("test".to_string()), "{ x = 3 }.x").unwrap(), + interpret("test", "{ x = 3 }.x").unwrap(), Some(Value::integer(3)) ); assert_eq!( - interpret(Rc::new("test".to_string()), "foo = { x = 3 }; foo.x").unwrap(), + interpret("test", "foo = { x = 3 }; foo.x").unwrap(), Some(Value::integer(3)) ); } diff --git a/dust-lang/tests/functions.rs b/dust-lang/tests/functions.rs index b66a481..4e6699b 100644 --- a/dust-lang/tests/functions.rs +++ b/dust-lang/tests/functions.rs @@ -1,16 +1,16 @@ -use std::rc::Rc; - use dust_lang::{ abstract_tree::Identifier, error::{Error, ValidationError}, *, }; +use dust_lang::interpret; + #[test] fn function_call() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " foobar = (message : str) str { message } foobar('Hiya') @@ -24,7 +24,7 @@ fn function_call() { fn call_empty_function() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " foobar = (message : str) none {} foobar('Hiya') @@ -38,7 +38,7 @@ fn call_empty_function() { fn callback() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " foobar = (cb: fn() -> str) str { cb() @@ -52,17 +52,14 @@ fn callback() { #[test] fn built_in_function_call() { - assert_eq!( - interpret(Rc::new("test".to_string()), "io.write_line('Hiya')"), - Ok(None) - ); + assert_eq!(interpret("test", "io.write_line('Hiya')"), Ok(None)); } #[test] fn function_context_does_not_capture_values() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " x = 1 @@ -79,7 +76,7 @@ fn function_context_does_not_capture_values() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " x = 1 foo = (x: int) int { x } @@ -94,7 +91,7 @@ fn function_context_does_not_capture_values() { fn function_context_captures_functions() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " bar = () int { 2 } foo = () int { bar() } @@ -109,7 +106,7 @@ fn function_context_captures_functions() { fn recursion() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " fib = (i: int) int { if i <= 1 { diff --git a/dust-lang/tests/statements.rs b/dust-lang/tests/statements.rs index 5b8e898..d9b30c0 100644 --- a/dust-lang/tests/statements.rs +++ b/dust-lang/tests/statements.rs @@ -1,12 +1,10 @@ -use std::rc::Rc; - use dust_lang::*; #[test] fn async_block() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " x = 41 async { @@ -24,7 +22,7 @@ fn async_block() { fn loops_and_breaks() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " i = 0 loop { @@ -41,7 +39,7 @@ fn loops_and_breaks() { ); assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " foobar = { while true { @@ -60,7 +58,7 @@ fn loops_and_breaks() { #[test] fn r#if() { assert_eq!( - interpret(Rc::new("test".to_string()), "if true { 'foobar' }"), + interpret("test", "if true { 'foobar' }"), Ok(Some(Value::string("foobar".to_string()))) ) } @@ -68,10 +66,7 @@ fn r#if() { #[test] fn if_else() { assert_eq!( - interpret( - Rc::new("test".to_string()), - "if false { 'foo' } else { 'bar' }" - ), + interpret("test", "if false { 'foo' } else { 'bar' }"), Ok(Some(Value::string("bar".to_string()))) ) } diff --git a/dust-lang/tests/structs.rs b/dust-lang/tests/structs.rs index ba2f348..4a76720 100644 --- a/dust-lang/tests/structs.rs +++ b/dust-lang/tests/structs.rs @@ -1,15 +1,14 @@ -use std::rc::Rc; - use dust_lang::{ abstract_tree::{Identifier, Type}, error::{Error, TypeConflict, ValidationError}, - *, + interpret, Value, }; + #[test] fn simple_structure() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " struct Foo { bar : int, @@ -36,7 +35,7 @@ fn simple_structure() { fn field_type_error() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " struct Foo { bar : int, @@ -67,7 +66,7 @@ fn field_type_error() { fn nested_structure() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " struct Bar { baz : int @@ -100,7 +99,7 @@ fn nested_structure() { fn undefined_struct() { assert_eq!( interpret( - Rc::new("test".to_string()), + "test", " Foo { bar = 42 @@ -110,7 +109,7 @@ fn undefined_struct() { .unwrap_err() .errors(), &vec![Error::Validation { - error: error::ValidationError::VariableNotFound(Identifier::new("Foo")), + error: ValidationError::VariableNotFound(Identifier::new("Foo")), position: (17, 69).into() }] ) diff --git a/dust-lang/tests/values.rs b/dust-lang/tests/values.rs index a13302f..237696c 100644 --- a/dust-lang/tests/values.rs +++ b/dust-lang/tests/values.rs @@ -1,4 +1,4 @@ -use std::{collections::BTreeMap, rc::Rc}; +use std::collections::BTreeMap; use dust_lang::{ abstract_tree::{Identifier, Type, WithPos}, @@ -8,37 +8,25 @@ use dust_lang::{ #[test] fn none() { - assert_eq!(interpret(Rc::new("test".to_string()), "x = 9"), Ok(None)); - assert_eq!( - interpret(Rc::new("test".to_string()), "x = 1 + 1"), - Ok(None) - ); + assert_eq!(interpret("test", "x = 9"), Ok(None)); + assert_eq!(interpret("test", "x = 1 + 1"), Ok(None)); } #[test] fn integer() { - assert_eq!( - interpret(Rc::new("test".to_string()), "1"), - Ok(Some(Value::integer(1))) - ); - assert_eq!( - interpret(Rc::new("test".to_string()), "123"), - Ok(Some(Value::integer(123))) - ); - assert_eq!( - interpret(Rc::new("test".to_string()), "-666"), - Ok(Some(Value::integer(-666))) - ); + assert_eq!(interpret("test", "1"), Ok(Some(Value::integer(1)))); + assert_eq!(interpret("test", "123"), Ok(Some(Value::integer(123)))); + assert_eq!(interpret("test", "-666"), Ok(Some(Value::integer(-666)))); } #[test] fn integer_saturation() { assert_eq!( - interpret(Rc::new("test".to_string()), "9223372036854775807 + 1"), + interpret("test", "9223372036854775807 + 1"), Ok(Some(Value::integer(i64::MAX))) ); assert_eq!( - interpret(Rc::new("test".to_string()), "-9223372036854775808 - 1"), + interpret("test", "-9223372036854775808 - 1"), Ok(Some(Value::integer(i64::MIN))) ); } @@ -46,11 +34,11 @@ fn integer_saturation() { #[test] fn float() { assert_eq!( - interpret(Rc::new("test".to_string()), "1.7976931348623157e308"), + interpret("test", "1.7976931348623157e308"), Ok(Some(Value::float(f64::MAX))) ); assert_eq!( - interpret(Rc::new("test".to_string()), "-1.7976931348623157e308"), + interpret("test", "-1.7976931348623157e308"), Ok(Some(Value::float(f64::MIN))) ); } @@ -58,11 +46,11 @@ fn float() { #[test] fn float_saturation() { assert_eq!( - interpret(Rc::new("test".to_string()), "1.7976931348623157e308 + 1"), + interpret("test", "1.7976931348623157e308 + 1"), Ok(Some(Value::float(f64::MAX))) ); assert_eq!( - interpret(Rc::new("test".to_string()), "-1.7976931348623157e308 - 1"), + interpret("test", "-1.7976931348623157e308 - 1"), Ok(Some(Value::float(f64::MIN))) ); } @@ -70,27 +58,27 @@ fn float_saturation() { #[test] fn string() { assert_eq!( - interpret(Rc::new("test".to_string()), "\"one\""), + interpret("test", "\"one\""), Ok(Some(Value::string("one".to_string()))) ); assert_eq!( - interpret(Rc::new("test".to_string()), "'one'"), + interpret("test", "'one'"), Ok(Some(Value::string("one".to_string()))) ); assert_eq!( - interpret(Rc::new("test".to_string()), "`one`"), + interpret("test", "`one`"), Ok(Some(Value::string("one".to_string()))) ); assert_eq!( - interpret(Rc::new("test".to_string()), "`'one'`"), + interpret("test", "`'one'`"), Ok(Some(Value::string("'one'".to_string()))) ); assert_eq!( - interpret(Rc::new("test".to_string()), "'`one`'"), + interpret("test", "'`one`'"), Ok(Some(Value::string("`one`".to_string()))) ); assert_eq!( - interpret(Rc::new("test".to_string()), "\"'one'\""), + interpret("test", "\"'one'\""), Ok(Some(Value::string("'one'".to_string()))) ); } @@ -98,7 +86,7 @@ fn string() { #[test] fn list() { assert_eq!( - interpret(Rc::new("test".to_string()), "[1, 2, 'foobar']"), + interpret("test", "[1, 2, 'foobar']"), Ok(Some(Value::list(vec![ Value::integer(1).with_position((1, 2)), Value::integer(2).with_position((4, 5)), @@ -109,10 +97,7 @@ fn list() { #[test] fn empty_list() { - assert_eq!( - interpret(Rc::new("test".to_string()), "[]"), - Ok(Some(Value::list(Vec::new()))) - ); + assert_eq!(interpret("test", "[]"), Ok(Some(Value::list(Vec::new())))); } #[test] @@ -123,7 +108,7 @@ fn map() { map.insert(Identifier::new("foo"), Value::string("bar".to_string())); assert_eq!( - interpret(Rc::new("test".to_string()), "{ x = 1, foo = 'bar' }"), + interpret("test", "{ x = 1, foo = 'bar' }"), Ok(Some(Value::map(map))) ); } @@ -131,7 +116,7 @@ fn map() { #[test] fn empty_map() { assert_eq!( - interpret(Rc::new("test".to_string()), "{}"), + interpret("test", "{}"), Ok(Some(Value::map(BTreeMap::new()))) ); } @@ -144,10 +129,7 @@ fn map_types() { map.insert(Identifier::new("foo"), Value::string("bar".to_string())); assert_eq!( - interpret( - Rc::new("test".to_string()), - "{ x : int = 1, foo : str = 'bar' }" - ), + interpret("test", "{ x : int = 1, foo : str = 'bar' }"), Ok(Some(Value::map(map))) ); } @@ -155,7 +137,7 @@ fn map_types() { #[test] fn map_type_errors() { assert_eq!( - interpret(Rc::new("test".to_string()), "{ foo : bool = 'bar' }") + interpret("test", "{ foo : bool = 'bar' }") .unwrap_err() .errors(), &vec![Error::Validation { @@ -174,8 +156,5 @@ fn map_type_errors() { #[test] fn range() { - assert_eq!( - interpret(Rc::new("test".to_string()), "0..100"), - Ok(Some(Value::range(0..100))) - ); + assert_eq!(interpret("test", "0..100"), Ok(Some(Value::range(0..100)))); } diff --git a/dust-lang/tests/variables.rs b/dust-lang/tests/variables.rs index 46def12..3a54e54 100644 --- a/dust-lang/tests/variables.rs +++ b/dust-lang/tests/variables.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - use dust_lang::{ abstract_tree::{Block, Expression, Identifier, Statement, Type, WithPos}, error::{Error, TypeConflict, ValidationError}, @@ -9,7 +7,7 @@ use dust_lang::{ #[test] fn set_and_get_variable() { assert_eq!( - interpret(Rc::new("test".to_string()), "foobar = true; foobar"), + interpret("test", "foobar = true; foobar"), Ok(Some(Value::boolean(true))) ); } @@ -17,7 +15,7 @@ fn set_and_get_variable() { #[test] fn set_variable_with_type() { assert_eq!( - interpret(Rc::new("test".to_string()), "foobar: bool = true; foobar"), + interpret("test", "foobar: bool = true; foobar"), Ok(Some(Value::boolean(true))) ); } @@ -25,7 +23,7 @@ fn set_variable_with_type() { #[test] fn set_variable_with_type_error() { assert_eq!( - interpret(Rc::new("test".to_string()), "foobar: str = true") + interpret("test", "foobar: str = true") .unwrap_err() .errors(), &vec![Error::Validation { @@ -45,10 +43,7 @@ fn set_variable_with_type_error() { #[test] fn function_variable() { assert_eq!( - interpret( - Rc::new("test".to_string()), - "foobar = (x: int) int { x }; foobar" - ), + interpret("test", "foobar = (x: int) int { x }; foobar"), Ok(Some(Value::function( Vec::with_capacity(0), vec![(Identifier::new("x"), Type::Integer.with_position((13, 16)))], diff --git a/dust-shell/src/cli.rs b/dust-shell/src/cli.rs index d1569e0..48a1c52 100644 --- a/dust-shell/src/cli.rs +++ b/dust-shell/src/cli.rs @@ -80,7 +80,8 @@ pub fn run_shell(context: Context) -> Result<(), io::Error> { continue; } - let run_result = interpreter.run(Rc::new("input".to_string()), &buffer); + let run_result = + interpreter.run(Rc::new("input".to_string()), Rc::from(buffer.as_str())); match run_result { Ok(Some(value)) => { @@ -88,12 +89,11 @@ pub fn run_shell(context: Context) -> Result<(), io::Error> { } Ok(None) => {} Err(error) => { - let source_id = Rc::new("input".to_string()); let reports = error.build_reports(); for report in reports { report - .write_for_stdout(sources([(source_id.clone(), &buffer)]), stderr()) + .write_for_stdout(sources(interpreter.sources()), stderr()) .unwrap(); } } diff --git a/dust-shell/src/main.rs b/dust-shell/src/main.rs index 241e3d1..cb07177 100644 --- a/dust-shell/src/main.rs +++ b/dust-shell/src/main.rs @@ -12,7 +12,7 @@ use std::{ rc::Rc, }; -use dust_lang::{context::Context, interpret, interpret_without_std}; +use dust_lang::{context::Context, Interpreter}; /// Command-line arguments to be parsed. #[derive(Parser, Debug)] @@ -42,10 +42,16 @@ fn main() { let args = Args::parse(); let context = Context::new(); - let (source, source_id) = if let Some(path) = args.path { - (read_to_string(&path).unwrap(), Rc::new(path)) + let mut interpreter = Interpreter::new(context.clone()); + + interpreter.load_std().unwrap(); + + let (source_id, source) = if let Some(path) = args.path { + let source = read_to_string(&path).unwrap(); + + (Rc::new(path.to_string()), source) } else if let Some(command) = args.command { - (command, Rc::new("input".to_string())) + (Rc::new("input".to_string()), command) } else { match run_shell(context) { Ok(_) => {} @@ -55,13 +61,9 @@ fn main() { return; }; - let eval_result = if args.no_std { - interpret_without_std(source_id.clone(), &source) - } else { - interpret(source_id.clone(), &source) - }; + let run_result = interpreter.run(source_id, Rc::from(source)); - match eval_result { + match run_result { Ok(value) => { if let Some(value) = value { println!("{value}") @@ -70,7 +72,7 @@ fn main() { Err(error) => { for report in error.build_reports() { report - .write_for_stdout(sources([(source_id.clone(), source.as_str())]), stderr()) + .write_for_stdout(sources(interpreter.sources()), stderr()) .unwrap(); } }