Continue revising built-in functions
This commit is contained in:
parent
4726288b9a
commit
3d64883e2a
@ -99,7 +99,7 @@ impl AbstractTree {
|
||||
}
|
||||
|
||||
pub fn run(self, context: &Context) -> Result<Option<Value>, Vec<Error>> {
|
||||
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<Statement>, Vec<Error>> {
|
||||
fn validate(self, context: &Context) -> Result<Vec<Statement>, Vec<Error>> {
|
||||
let mut errors = Vec::new();
|
||||
let mut valid_statements = Vec::new();
|
||||
|
||||
@ -152,6 +152,8 @@ impl AbstractTree {
|
||||
} else {
|
||||
valid_statements.push(statement)
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<str>, Arc<str>); 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)
|
||||
|
@ -13,7 +13,7 @@ pub type ParserInput<'src> =
|
||||
SpannedInput<Token<'src>, SimpleSpan, &'src [(Token<'src>, SimpleSpan)]>;
|
||||
|
||||
pub fn parse<'src>(tokens: &'src [(Token<'src>, SimpleSpan)]) -> Result<AbstractTree, Vec<Error>> {
|
||||
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<Abstract
|
||||
}
|
||||
|
||||
pub fn parser<'src>(
|
||||
allow_built_ins: bool,
|
||||
) -> impl Parser<'src, ParserInput<'src>, Vec<Statement>, extra::Err<Rich<'src, Token<'src>, SimpleSpan>>>
|
||||
{
|
||||
let identifiers: RefCell<HashMap<&str, Identifier>> = 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(
|
||||
.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::<Vec<Error>>()
|
||||
})
|
||||
.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::<Vec<Error>>()
|
||||
})
|
||||
.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))
|
||||
|
Loading…
Reference in New Issue
Block a user