2024-02-25 18:49:26 +00:00
|
|
|
pub mod abstract_tree;
|
|
|
|
pub mod context;
|
|
|
|
pub mod error;
|
2024-03-25 04:16:55 +00:00
|
|
|
pub mod identifier;
|
2024-02-25 18:49:26 +00:00
|
|
|
pub mod lexer;
|
|
|
|
pub mod parser;
|
2024-02-26 21:27:01 +00:00
|
|
|
pub mod value;
|
2024-02-23 12:40:01 +00:00
|
|
|
|
2024-03-24 21:34:36 +00:00
|
|
|
use std::{
|
|
|
|
ops::Range,
|
|
|
|
sync::{Arc, RwLock},
|
|
|
|
vec,
|
|
|
|
};
|
2024-03-24 13:10:49 +00:00
|
|
|
|
2024-04-22 01:33:21 +00:00
|
|
|
use abstract_tree::{AbstractTree, Type};
|
2024-03-24 13:10:49 +00:00
|
|
|
use ariadne::{Color, Fmt, Label, Report, ReportKind};
|
2024-05-18 20:21:46 +00:00
|
|
|
use chumsky::prelude::*;
|
2024-03-24 00:36:23 +00:00
|
|
|
use context::Context;
|
2024-03-24 13:10:49 +00:00
|
|
|
use error::{Error, RuntimeError, TypeConflict, ValidationError};
|
2024-03-06 20:36:58 +00:00
|
|
|
use lexer::lex;
|
2024-04-22 01:33:21 +00:00
|
|
|
use parser::{parse, parser};
|
2024-03-24 21:34:36 +00:00
|
|
|
use rayon::prelude::*;
|
2024-02-26 21:27:01 +00:00
|
|
|
pub use value::Value;
|
2024-02-25 08:12:09 +00:00
|
|
|
|
2024-03-24 19:35:19 +00:00
|
|
|
pub fn interpret<'src>(source_id: &str, source: &str) -> Result<Option<Value>, InterpreterError> {
|
2024-05-21 20:29:54 +00:00
|
|
|
let mut interpreter = Interpreter::new(Context::new(None));
|
2024-03-23 12:15:48 +00:00
|
|
|
|
2024-03-24 19:47:23 +00:00
|
|
|
interpreter.load_std()?;
|
2024-03-24 21:34:36 +00:00
|
|
|
interpreter.run(Arc::from(source_id), Arc::from(source))
|
2024-03-24 13:10:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn interpret_without_std(
|
2024-03-24 19:35:19 +00:00
|
|
|
source_id: &str,
|
2024-03-24 13:10:49 +00:00
|
|
|
source: &str,
|
|
|
|
) -> Result<Option<Value>, InterpreterError> {
|
2024-05-21 20:29:54 +00:00
|
|
|
let mut interpreter = Interpreter::new(Context::new(None));
|
2024-03-24 13:10:49 +00:00
|
|
|
|
2024-03-24 21:34:36 +00:00
|
|
|
interpreter.run(Arc::from(source_id.to_string()), Arc::from(source))
|
2024-03-24 19:35:19 +00:00
|
|
|
}
|
|
|
|
|
2024-05-21 20:29:54 +00:00
|
|
|
pub struct Interpreter<'a> {
|
|
|
|
context: Context<'a>,
|
2024-03-24 21:34:36 +00:00
|
|
|
sources: Arc<RwLock<Vec<(Arc<str>, Arc<str>)>>>,
|
2024-03-24 19:35:19 +00:00
|
|
|
}
|
|
|
|
|
2024-05-21 20:29:54 +00:00
|
|
|
impl<'a> Interpreter<'a> {
|
|
|
|
pub fn new(context: Context<'a>) -> Self {
|
2024-03-24 19:35:19 +00:00
|
|
|
Interpreter {
|
|
|
|
context,
|
2024-03-24 21:34:36 +00:00
|
|
|
sources: Arc::new(RwLock::new(Vec::new())),
|
2024-03-24 19:35:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn run(
|
2024-04-22 05:51:34 +00:00
|
|
|
&mut self,
|
2024-03-24 21:34:36 +00:00
|
|
|
source_id: Arc<str>,
|
|
|
|
source: Arc<str>,
|
2024-03-24 19:35:19 +00:00
|
|
|
) -> Result<Option<Value>, InterpreterError> {
|
2024-03-24 21:34:36 +00:00
|
|
|
self.sources
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.push((source_id.clone(), source.clone()));
|
|
|
|
|
2024-03-24 19:35:19 +00:00
|
|
|
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
|
2024-04-22 05:51:34 +00:00
|
|
|
.run(&mut self.context, true)
|
2024-03-24 21:34:36 +00:00
|
|
|
.map_err(|errors| InterpreterError { source_id, errors })?;
|
2024-03-24 19:35:19 +00:00
|
|
|
|
|
|
|
Ok(value_option)
|
|
|
|
}
|
|
|
|
|
2024-03-24 21:34:36 +00:00
|
|
|
pub fn load_std(&mut self) -> Result<(), InterpreterError> {
|
2024-04-22 01:33:21 +00:00
|
|
|
let std_sources: [(Arc<str>, Arc<str>); 2] = [
|
2024-03-24 19:35:19 +00:00
|
|
|
(
|
2024-03-24 21:34:36 +00:00
|
|
|
Arc::from("std/io.ds"),
|
|
|
|
Arc::from(include_str!("../../std/io.ds")),
|
2024-03-24 19:35:19 +00:00
|
|
|
),
|
|
|
|
(
|
2024-03-24 21:34:36 +00:00
|
|
|
Arc::from("std/thread.ds"),
|
|
|
|
Arc::from(include_str!("../../std/thread.ds")),
|
2024-03-24 19:35:19 +00:00
|
|
|
),
|
2024-03-24 21:34:36 +00:00
|
|
|
];
|
|
|
|
|
2024-04-27 07:40:05 +00:00
|
|
|
log::info!("Start loading standard library...");
|
|
|
|
|
2024-03-24 21:34:36 +00:00
|
|
|
let error = std_sources
|
|
|
|
.into_par_iter()
|
2024-04-22 01:33:21 +00:00
|
|
|
.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(),
|
2024-05-18 18:27:42 +00:00
|
|
|
errors: errors.into_iter().map(Error::from).collect(),
|
2024-04-22 01:33:21 +00:00
|
|
|
});
|
|
|
|
let abstract_tree = match parse_result {
|
|
|
|
Ok(statements) => AbstractTree::new(statements),
|
|
|
|
Err(error) => return Some(error),
|
|
|
|
};
|
|
|
|
|
|
|
|
abstract_tree
|
2024-04-22 05:51:34 +00:00
|
|
|
.run(&mut self.context.clone(), false)
|
2024-04-22 01:33:21 +00:00
|
|
|
.map_err(|errors| InterpreterError { source_id, errors })
|
|
|
|
.err()
|
|
|
|
});
|
2024-03-24 21:34:36 +00:00
|
|
|
|
2024-04-27 07:40:05 +00:00
|
|
|
log::info!("Finish loading standard library.");
|
|
|
|
|
2024-03-24 21:34:36 +00:00
|
|
|
if let Some(error) = error {
|
|
|
|
Err(error)
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
2024-03-24 19:35:19 +00:00
|
|
|
}
|
|
|
|
|
2024-03-24 21:34:36 +00:00
|
|
|
pub fn sources(&self) -> vec::IntoIter<(Arc<str>, Arc<str>)> {
|
|
|
|
self.sources.read().unwrap().clone().into_iter()
|
2024-03-24 19:35:19 +00:00
|
|
|
}
|
2024-03-24 13:10:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub struct InterpreterError {
|
2024-03-24 21:34:36 +00:00
|
|
|
source_id: Arc<str>,
|
2024-03-24 13:10:49 +00:00
|
|
|
errors: Vec<Error>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InterpreterError {
|
|
|
|
pub fn errors(&self) -> &Vec<Error> {
|
|
|
|
&self.errors
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InterpreterError {
|
2024-03-24 21:34:36 +00:00
|
|
|
pub fn build_reports<'a>(self) -> Vec<Report<'a, (Arc<str>, Range<usize>)>> {
|
2024-03-24 13:10:49 +00:00
|
|
|
let mut reports = Vec::new();
|
|
|
|
|
|
|
|
for error in self.errors {
|
2024-03-25 04:16:55 +00:00
|
|
|
let (mut builder, validation_error) = match error {
|
2024-03-24 13:10:49 +00:00
|
|
|
Error::Lex {
|
|
|
|
expected,
|
|
|
|
span,
|
|
|
|
reason,
|
|
|
|
} => {
|
|
|
|
let description = if expected.is_empty() {
|
|
|
|
"Invalid character.".to_string()
|
|
|
|
} else {
|
|
|
|
format!("Expected {expected}.")
|
|
|
|
};
|
|
|
|
|
|
|
|
(
|
|
|
|
Report::build(
|
|
|
|
ReportKind::Custom("Lexing Error", Color::Yellow),
|
|
|
|
self.source_id.clone(),
|
|
|
|
span.1,
|
|
|
|
)
|
|
|
|
.with_message(description)
|
|
|
|
.with_label(
|
|
|
|
Label::new((self.source_id.clone(), span.0..span.1))
|
|
|
|
.with_message(reason)
|
|
|
|
.with_color(Color::Red),
|
|
|
|
),
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
Error::Parse {
|
|
|
|
expected,
|
|
|
|
span,
|
2024-05-18 18:27:42 +00:00
|
|
|
found,
|
2024-03-24 13:10:49 +00:00
|
|
|
} => {
|
|
|
|
let description = if expected.is_empty() {
|
|
|
|
"Invalid token.".to_string()
|
|
|
|
} else {
|
|
|
|
format!("Expected {expected}.")
|
|
|
|
};
|
|
|
|
|
2024-05-18 18:27:42 +00:00
|
|
|
let label_message = format!(
|
|
|
|
"{} is not valid in this position.",
|
|
|
|
found.unwrap_or_else(|| String::with_capacity(0))
|
|
|
|
);
|
|
|
|
|
2024-03-24 13:10:49 +00:00
|
|
|
(
|
|
|
|
Report::build(
|
|
|
|
ReportKind::Custom("Parsing Error", Color::Yellow),
|
|
|
|
self.source_id.clone(),
|
|
|
|
span.1,
|
|
|
|
)
|
|
|
|
.with_message(description)
|
|
|
|
.with_label(
|
|
|
|
Label::new((self.source_id.clone(), span.0..span.1))
|
2024-05-18 18:27:42 +00:00
|
|
|
.with_message(label_message)
|
2024-03-24 13:10:49 +00:00
|
|
|
.with_color(Color::Red),
|
|
|
|
),
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
}
|
2024-03-24 21:34:36 +00:00
|
|
|
Error::Validation { error, position } => (
|
|
|
|
Report::build(
|
|
|
|
ReportKind::Custom("Validation Error", Color::Magenta),
|
|
|
|
self.source_id.clone(),
|
|
|
|
position.1,
|
|
|
|
)
|
|
|
|
.with_message("The syntax is valid but this code would cause an error.")
|
|
|
|
.with_note("This error was detected by the interpreter before running the code."),
|
|
|
|
Some(error),
|
|
|
|
),
|
2024-03-24 13:10:49 +00:00
|
|
|
Error::Runtime { error, position } => (
|
|
|
|
Report::build(
|
|
|
|
ReportKind::Custom("Runtime Error", Color::Red),
|
|
|
|
self.source_id.clone(),
|
|
|
|
position.1,
|
|
|
|
)
|
|
|
|
.with_message("An error occured that forced the program to exit.")
|
|
|
|
.with_note(
|
|
|
|
"There may be unexpected side-effects because the program could not finish.",
|
|
|
|
)
|
|
|
|
.with_help(
|
|
|
|
"This is the interpreter's fault. Please submit a bug with this error message.",
|
2024-03-24 21:34:36 +00:00
|
|
|
)
|
|
|
|
.with_label(
|
|
|
|
Label::new((self.source_id.clone(), position.0..position.1)).with_message("Runtime error occured here.")
|
2024-03-24 13:10:49 +00:00
|
|
|
),
|
|
|
|
if let RuntimeError::ValidationFailure(validation_error) = error {
|
|
|
|
Some(validation_error)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
|
|
|
),
|
|
|
|
};
|
|
|
|
|
|
|
|
let type_color = Color::Green;
|
|
|
|
let identifier_color = Color::Blue;
|
|
|
|
|
|
|
|
if let Some(validation_error) = validation_error {
|
|
|
|
match validation_error {
|
|
|
|
ValidationError::ExpectedBoolean { actual, position } => {
|
|
|
|
builder.add_label(
|
|
|
|
Label::new((self.source_id.clone(), position.0..position.1))
|
|
|
|
.with_message(format!(
|
|
|
|
"Expected {} but got {}.",
|
|
|
|
"boolean".fg(type_color),
|
|
|
|
actual.fg(type_color)
|
|
|
|
)),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
ValidationError::ExpectedIntegerOrFloat(position) => {
|
|
|
|
builder.add_label(
|
|
|
|
Label::new((self.source_id.clone(), position.0..position.1))
|
|
|
|
.with_message(format!(
|
|
|
|
"Expected {} or {}.",
|
|
|
|
"integer".fg(type_color),
|
|
|
|
"float".fg(type_color)
|
|
|
|
)),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
ValidationError::RwLockPoison(_) => todo!(),
|
|
|
|
ValidationError::TypeCheck {
|
|
|
|
conflict,
|
|
|
|
actual_position,
|
2024-03-24 21:34:36 +00:00
|
|
|
expected_position,
|
2024-03-24 13:10:49 +00:00
|
|
|
} => {
|
|
|
|
let TypeConflict { actual, expected } = conflict;
|
|
|
|
|
|
|
|
builder.add_labels([
|
|
|
|
Label::new((
|
|
|
|
self.source_id.clone(),
|
2024-03-24 21:34:36 +00:00
|
|
|
expected_position.0..expected_position.1,
|
2024-03-24 13:10:49 +00:00
|
|
|
))
|
|
|
|
.with_message(format!(
|
|
|
|
"Type {} established here.",
|
|
|
|
expected.fg(type_color)
|
|
|
|
)),
|
|
|
|
Label::new((
|
|
|
|
self.source_id.clone(),
|
|
|
|
actual_position.0..actual_position.1,
|
|
|
|
))
|
|
|
|
.with_message(format!("Got type {} here.", actual.fg(type_color))),
|
|
|
|
]);
|
|
|
|
}
|
2024-03-25 04:16:55 +00:00
|
|
|
ValidationError::VariableNotFound {
|
|
|
|
identifier,
|
|
|
|
position,
|
|
|
|
} => builder.add_label(
|
|
|
|
Label::new((self.source_id.clone(), position.0..position.1)).with_message(
|
|
|
|
format!(
|
2024-03-24 13:10:49 +00:00
|
|
|
"Variable {} does not exist in this context.",
|
|
|
|
identifier.fg(identifier_color)
|
2024-03-25 04:16:55 +00:00
|
|
|
),
|
|
|
|
),
|
2024-03-24 13:10:49 +00:00
|
|
|
),
|
|
|
|
ValidationError::CannotIndex { r#type, position } => builder.add_label(
|
|
|
|
Label::new((self.source_id.clone(), position.0..position.1)).with_message(
|
|
|
|
format!("Cannot index into a {}.", r#type.fg(type_color)),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
ValidationError::CannotIndexWith {
|
|
|
|
collection_type,
|
|
|
|
collection_position,
|
|
|
|
index_type,
|
|
|
|
index_position,
|
|
|
|
} => {
|
|
|
|
builder = builder.with_message(format!(
|
|
|
|
"Cannot index into {} with {}.",
|
|
|
|
collection_type.clone().fg(type_color),
|
|
|
|
index_type.clone().fg(type_color)
|
|
|
|
));
|
|
|
|
|
|
|
|
builder.add_labels([
|
|
|
|
Label::new((
|
|
|
|
self.source_id.clone(),
|
|
|
|
collection_position.0..collection_position.1,
|
|
|
|
))
|
|
|
|
.with_message(format!(
|
|
|
|
"This has type {}.",
|
|
|
|
collection_type.fg(type_color),
|
|
|
|
)),
|
|
|
|
Label::new((
|
|
|
|
self.source_id.clone(),
|
|
|
|
index_position.0..index_position.1,
|
|
|
|
))
|
|
|
|
.with_message(format!("This has type {}.", index_type.fg(type_color),)),
|
|
|
|
])
|
|
|
|
}
|
|
|
|
ValidationError::InterpreterExpectedReturn(_) => todo!(),
|
|
|
|
ValidationError::ExpectedFunction { .. } => todo!(),
|
|
|
|
ValidationError::ExpectedValue(_) => todo!(),
|
|
|
|
ValidationError::PropertyNotFound { .. } => todo!(),
|
|
|
|
ValidationError::WrongArguments { .. } => todo!(),
|
|
|
|
ValidationError::ExpectedIntegerFloatOrString { actual, position } => {
|
|
|
|
builder = builder.with_message(format!(
|
|
|
|
"Expected an {}, {} or {}.",
|
|
|
|
Type::Integer.fg(type_color),
|
|
|
|
Type::Float.fg(type_color),
|
|
|
|
Type::String.fg(type_color)
|
|
|
|
));
|
|
|
|
|
2024-03-24 21:34:36 +00:00
|
|
|
builder.add_label(
|
|
|
|
Label::new((self.source_id.clone(), position.0..position.1))
|
|
|
|
.with_message(format!("This has type {}.", actual.fg(type_color),)),
|
|
|
|
)
|
2024-03-24 13:10:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let report = builder.finish();
|
|
|
|
|
|
|
|
reports.push(report);
|
|
|
|
}
|
|
|
|
|
|
|
|
reports
|
|
|
|
}
|
2024-03-06 23:15:25 +00:00
|
|
|
}
|