diff --git a/dust-lang/src/abstract_tree/mod.rs b/dust-lang/src/abstract_tree/mod.rs index 9579325..288ab87 100644 --- a/dust-lang/src/abstract_tree/mod.rs +++ b/dust-lang/src/abstract_tree/mod.rs @@ -99,7 +99,7 @@ impl AbstractTree { } pub fn run(self, context: &Context) -> Result, Vec> { - let valid_statements = self.run_type_definitions(context)?; + let valid_statements = self.validate(context)?; let mut previous_value = None; for statement in valid_statements { @@ -124,7 +124,7 @@ impl AbstractTree { Ok(previous_value) } - fn run_type_definitions(self, context: &Context) -> Result, Vec> { + fn validate(self, context: &Context) -> Result, Vec> { let mut errors = Vec::new(); let mut valid_statements = Vec::new(); @@ -152,6 +152,8 @@ impl AbstractTree { } else { valid_statements.push(statement) } + } else { + continue; } } diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index da7e841..c6d10f3 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -12,12 +12,13 @@ use std::{ vec, }; -use abstract_tree::Type; +use abstract_tree::{AbstractTree, Type}; use ariadne::{Color, Fmt, Label, Report, ReportKind}; +use chumsky::prelude::*; use context::Context; use error::{Error, RuntimeError, TypeConflict, ValidationError}; use lexer::lex; -use parser::parse; +use parser::{parse, parser}; use rayon::prelude::*; pub use value::Value; @@ -76,7 +77,7 @@ impl Interpreter { } pub fn load_std(&mut self) -> Result<(), InterpreterError> { - let std_sources = [ + let std_sources: [(Arc, Arc); 2] = [ ( Arc::from("std/io.ds"), Arc::from(include_str!("../../std/io.ds")), @@ -89,7 +90,54 @@ impl Interpreter { let error = std_sources .into_par_iter() - .find_map_any(|(source_id, source)| self.run(source_id, source).err()); + .find_map_any(|(source_id, source)| { + self.sources + .write() + .unwrap() + .push((source_id.clone(), source.clone())); + + let lex_result = lex(source.as_ref()).map_err(|errors| InterpreterError { + source_id: source_id.clone(), + errors, + }); + let tokens = match lex_result { + Ok(tokens) => tokens, + Err(error) => return Some(error), + }; + + let parse_result = parser(true) + .parse(tokens.spanned((tokens.len()..tokens.len()).into())) + .into_result() + .map_err(|errors| InterpreterError { + source_id: source_id.clone(), + errors: errors + .into_iter() + .map(|error| { + let expected = error + .expected() + .into_iter() + .map(|pattern| pattern.to_string()) + .collect(); + let span = error.span(); + + Error::Parse { + expected, + span: (span.start(), span.end()), + reason: error.reason().to_string(), + } + }) + .collect(), + }); + let abstract_tree = match parse_result { + Ok(statements) => AbstractTree::new(statements), + Err(error) => return Some(error), + }; + + abstract_tree + .run(&self.context) + .map_err(|errors| InterpreterError { source_id, errors }) + .err() + }); if let Some(error) = error { Err(error) diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index fd34e67..fbfbbaf 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -13,7 +13,7 @@ pub type ParserInput<'src> = SpannedInput, SimpleSpan, &'src [(Token<'src>, SimpleSpan)]>; pub fn parse<'src>(tokens: &'src [(Token<'src>, SimpleSpan)]) -> Result> { - let statements = parser() + let statements = parser(false) .parse(tokens.spanned((tokens.len()..tokens.len()).into())) .into_result() .map_err(|errors| { @@ -27,6 +27,7 @@ pub fn parse<'src>(tokens: &'src [(Token<'src>, SimpleSpan)]) -> Result( + allow_built_ins: bool, ) -> impl Parser<'src, ParserInput<'src>, Vec, extra::Err, SimpleSpan>>> { let identifiers: RefCell> = RefCell::new(HashMap::new()); @@ -154,6 +155,7 @@ pub fn parser<'src>( }); let statement = recursive(|statement| { + let allow_built_ins = allow_built_ins.clone(); let block = statement .clone() .repeated() @@ -165,6 +167,7 @@ pub fn parser<'src>( .map_with(|statements, state| Block::new(statements).with_position(state.span())); let expression = recursive(|expression| { + let allow_built_ins = allow_built_ins.clone(); let identifier_expression = identifier.clone().map_with(|identifier, state| { Expression::Identifier(identifier.with_position(state.span())) }); @@ -269,10 +272,17 @@ pub fn parser<'src>( .map(|expression| BuiltInFunctionCall::WriteLine(expression)), )) .then_ignore(just(Token::Control(Control::ParenClose))) - .map_with(|built_in_function_call, state| { - Expression::BuiltInFunctionCall( - Box::new(built_in_function_call).with_position(state.span()), - ) + .try_map_with(move |built_in_function_call, state| { + if allow_built_ins { + Ok(Expression::BuiltInFunctionCall( + Box::new(built_in_function_call).with_position(state.span()), + )) + } else { + Err(Rich::custom( + state.span(), + "Built-in function calls can only be used by the standard library.", + )) + } }); let structure_field = identifier @@ -602,15 +612,39 @@ mod tests { #[test] fn built_in_function() { + let tokens = lex("READ_LINE()").unwrap(); + let statements = parser(true) + .parse(tokens.spanned((tokens.len()..tokens.len()).into())) + .into_result() + .map_err(|errors| { + errors + .into_iter() + .map(|error| Error::from(error)) + .collect::>() + }) + .unwrap(); + assert_eq!( - parse(&lex("READ_LINE()").unwrap()).unwrap()[0], + statements[0], Statement::Expression(Expression::BuiltInFunctionCall( Box::new(BuiltInFunctionCall::ReadLine).with_position((0, 11)) )) ); + let tokens = lex("WRITE_LINE('hiya')").unwrap(); + let statements = parser(true) + .parse(tokens.spanned((tokens.len()..tokens.len()).into())) + .into_result() + .map_err(|errors| { + errors + .into_iter() + .map(|error| Error::from(error)) + .collect::>() + }) + .unwrap(); + assert_eq!( - parse(&lex("WRITE_LINE('hiya')").unwrap()).unwrap()[0], + statements[0], Statement::Expression(Expression::BuiltInFunctionCall( Box::new(BuiltInFunctionCall::WriteLine(Expression::Value( ValueNode::String("hiya".to_string()).with_position((11, 17))