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>> {
|
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;
|
let mut previous_value = None;
|
||||||
|
|
||||||
for statement in valid_statements {
|
for statement in valid_statements {
|
||||||
@ -124,7 +124,7 @@ impl AbstractTree {
|
|||||||
Ok(previous_value)
|
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 errors = Vec::new();
|
||||||
let mut valid_statements = Vec::new();
|
let mut valid_statements = Vec::new();
|
||||||
|
|
||||||
@ -152,6 +152,8 @@ impl AbstractTree {
|
|||||||
} else {
|
} else {
|
||||||
valid_statements.push(statement)
|
valid_statements.push(statement)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,12 +12,13 @@ use std::{
|
|||||||
vec,
|
vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
use abstract_tree::Type;
|
use abstract_tree::{AbstractTree, Type};
|
||||||
use ariadne::{Color, Fmt, Label, Report, ReportKind};
|
use ariadne::{Color, Fmt, Label, Report, ReportKind};
|
||||||
|
use chumsky::prelude::*;
|
||||||
use context::Context;
|
use context::Context;
|
||||||
use error::{Error, RuntimeError, TypeConflict, ValidationError};
|
use error::{Error, RuntimeError, TypeConflict, ValidationError};
|
||||||
use lexer::lex;
|
use lexer::lex;
|
||||||
use parser::parse;
|
use parser::{parse, parser};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
pub use value::Value;
|
pub use value::Value;
|
||||||
|
|
||||||
@ -76,7 +77,7 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_std(&mut self) -> Result<(), InterpreterError> {
|
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("std/io.ds"),
|
||||||
Arc::from(include_str!("../../std/io.ds")),
|
Arc::from(include_str!("../../std/io.ds")),
|
||||||
@ -89,7 +90,54 @@ impl Interpreter {
|
|||||||
|
|
||||||
let error = std_sources
|
let error = std_sources
|
||||||
.into_par_iter()
|
.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 {
|
if let Some(error) = error {
|
||||||
Err(error)
|
Err(error)
|
||||||
|
@ -13,7 +13,7 @@ pub type ParserInput<'src> =
|
|||||||
SpannedInput<Token<'src>, SimpleSpan, &'src [(Token<'src>, SimpleSpan)]>;
|
SpannedInput<Token<'src>, SimpleSpan, &'src [(Token<'src>, SimpleSpan)]>;
|
||||||
|
|
||||||
pub fn parse<'src>(tokens: &'src [(Token<'src>, SimpleSpan)]) -> Result<AbstractTree, Vec<Error>> {
|
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()))
|
.parse(tokens.spanned((tokens.len()..tokens.len()).into()))
|
||||||
.into_result()
|
.into_result()
|
||||||
.map_err(|errors| {
|
.map_err(|errors| {
|
||||||
@ -27,6 +27,7 @@ pub fn parse<'src>(tokens: &'src [(Token<'src>, SimpleSpan)]) -> Result<Abstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn parser<'src>(
|
pub fn parser<'src>(
|
||||||
|
allow_built_ins: bool,
|
||||||
) -> impl Parser<'src, ParserInput<'src>, Vec<Statement>, extra::Err<Rich<'src, Token<'src>, SimpleSpan>>>
|
) -> impl Parser<'src, ParserInput<'src>, Vec<Statement>, extra::Err<Rich<'src, Token<'src>, SimpleSpan>>>
|
||||||
{
|
{
|
||||||
let identifiers: RefCell<HashMap<&str, Identifier>> = RefCell::new(HashMap::new());
|
let identifiers: RefCell<HashMap<&str, Identifier>> = RefCell::new(HashMap::new());
|
||||||
@ -154,6 +155,7 @@ pub fn parser<'src>(
|
|||||||
});
|
});
|
||||||
|
|
||||||
let statement = recursive(|statement| {
|
let statement = recursive(|statement| {
|
||||||
|
let allow_built_ins = allow_built_ins.clone();
|
||||||
let block = statement
|
let block = statement
|
||||||
.clone()
|
.clone()
|
||||||
.repeated()
|
.repeated()
|
||||||
@ -165,6 +167,7 @@ pub fn parser<'src>(
|
|||||||
.map_with(|statements, state| Block::new(statements).with_position(state.span()));
|
.map_with(|statements, state| Block::new(statements).with_position(state.span()));
|
||||||
|
|
||||||
let expression = recursive(|expression| {
|
let expression = recursive(|expression| {
|
||||||
|
let allow_built_ins = allow_built_ins.clone();
|
||||||
let identifier_expression = identifier.clone().map_with(|identifier, state| {
|
let identifier_expression = identifier.clone().map_with(|identifier, state| {
|
||||||
Expression::Identifier(identifier.with_position(state.span()))
|
Expression::Identifier(identifier.with_position(state.span()))
|
||||||
});
|
});
|
||||||
@ -269,10 +272,17 @@ pub fn parser<'src>(
|
|||||||
.map(|expression| BuiltInFunctionCall::WriteLine(expression)),
|
.map(|expression| BuiltInFunctionCall::WriteLine(expression)),
|
||||||
))
|
))
|
||||||
.then_ignore(just(Token::Control(Control::ParenClose)))
|
.then_ignore(just(Token::Control(Control::ParenClose)))
|
||||||
.map_with(|built_in_function_call, state| {
|
.try_map_with(move |built_in_function_call, state| {
|
||||||
Expression::BuiltInFunctionCall(
|
if allow_built_ins {
|
||||||
Box::new(built_in_function_call).with_position(state.span()),
|
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
|
let structure_field = identifier
|
||||||
@ -602,15 +612,39 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn built_in_function() {
|
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!(
|
assert_eq!(
|
||||||
parse(&lex("READ_LINE()").unwrap()).unwrap()[0],
|
statements[0],
|
||||||
Statement::Expression(Expression::BuiltInFunctionCall(
|
Statement::Expression(Expression::BuiltInFunctionCall(
|
||||||
Box::new(BuiltInFunctionCall::ReadLine).with_position((0, 11))
|
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!(
|
assert_eq!(
|
||||||
parse(&lex("WRITE_LINE('hiya')").unwrap()).unwrap()[0],
|
statements[0],
|
||||||
Statement::Expression(Expression::BuiltInFunctionCall(
|
Statement::Expression(Expression::BuiltInFunctionCall(
|
||||||
Box::new(BuiltInFunctionCall::WriteLine(Expression::Value(
|
Box::new(BuiltInFunctionCall::WriteLine(Expression::Value(
|
||||||
ValueNode::String("hiya".to_string()).with_position((11, 17))
|
ValueNode::String("hiya".to_string()).with_position((11, 17))
|
||||||
|
Loading…
Reference in New Issue
Block a user