dust/dust-lang/src/lib.rs

496 lines
19 KiB
Rust
Raw Normal View History

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-06-19 16:03:25 +00:00
use ariadne::{Color, Config, Fmt, Label, Report, ReportKind};
2024-06-22 15:44:09 +00:00
use chumsky::prelude::*;
2024-03-24 00:36:23 +00:00
use context::Context;
2024-06-18 23:42:04 +00:00
use error::{DustError, RuntimeError, TypeConflict, ValidationError};
2024-06-04 18:47:15 +00:00
use lexer::{lex, Token};
2024-06-22 15:44:09 +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-06-22 15:44:09 +00:00
pub fn interpret(source_id: &str, source: &str) -> Result<Option<Value>, InterpreterError> {
2024-06-22 11:46:10 +00:00
let 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-06-22 11:46:10 +00:00
let interpreter = Interpreter::new(Context::new(None));
2024-03-24 13:10:49 +00:00
2024-06-22 15:44:09 +00:00
interpreter.run(Arc::from(source_id), Arc::from(source))
2024-03-24 19:35:19 +00:00
}
2024-06-22 10:36:59 +00:00
pub struct Interpreter {
context: Context,
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-06-22 10:36:59 +00:00
impl Interpreter {
pub fn new(context: Context) -> 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
}
}
2024-06-22 11:46:10 +00:00
pub fn lex<'src>(
&self,
2024-06-04 18:47:15 +00:00
source_id: Arc<str>,
2024-06-22 11:46:10 +00:00
source: &'src str,
) -> Result<Vec<Token<'src>>, InterpreterError> {
2024-06-04 18:47:15 +00:00
let mut sources = self.sources.write().unwrap();
sources.clear();
sources.push((source_id.clone(), Arc::from(source)));
lex(source.as_ref())
.map(|tokens| tokens.into_iter().map(|(token, _)| token).collect())
.map_err(|errors| InterpreterError { source_id, errors })
}
2024-06-22 11:46:10 +00:00
pub fn parse<'src>(
&self,
2024-06-04 18:47:15 +00:00
source_id: Arc<str>,
2024-06-22 11:46:10 +00:00
source: &'src str,
2024-06-04 18:47:15 +00:00
) -> Result<AbstractTree, InterpreterError> {
let mut sources = self.sources.write().unwrap();
sources.clear();
sources.push((source_id.clone(), Arc::from(source)));
parse(&lex(source).map_err(|errors| InterpreterError {
source_id: source_id.clone(),
errors,
})?)
.map_err(|errors| InterpreterError { source_id, errors })
}
2024-03-24 19:35:19 +00:00
pub fn run(
2024-06-22 11:46:10 +00:00
&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-06-04 18:47:15 +00:00
let mut sources = self.sources.write().unwrap();
sources.clear();
sources.push((source_id.clone(), source.clone()));
2024-03-24 21:34:36 +00:00
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-06-22 11:46:10 +00:00
.run(&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-06-22 11:46:10 +00:00
pub fn load_std(&self) -> Result<(), InterpreterError> {
let std_core_source: (Arc<str>, Arc<str>) = {
2024-06-04 18:47:15 +00:00
(
Arc::from("std/core.ds"),
Arc::from(include_str!("../../std/core.ds")),
2024-06-22 11:46:10 +00:00
)
};
let std_sources: [(Arc<str>, Arc<str>); 4] = [
2024-05-25 15:48:43 +00:00
(
Arc::from("std/fs.ds"),
Arc::from(include_str!("../../std/fs.ds")),
),
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-06-05 16:10:57 +00:00
(
Arc::from("std/json.ds"),
Arc::from(include_str!("../../std/json.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-06-22 11:46:10 +00:00
// Always load the core library first because other parts of the standard library may depend
// on it.
2024-06-22 15:44:09 +00:00
self.run_with_builtins(std_core_source.0, std_core_source.1)?;
2024-06-22 11:46:10 +00:00
let error = if cfg!(test) {
// In debug mode, load the standard library sequentially to get consistent errors.
std_sources
.into_iter()
2024-06-22 15:44:09 +00:00
.find_map(|(source_id, source)| self.run_with_builtins(source_id, source).err())
2024-06-22 11:46:10 +00:00
} else {
// In release mode, load the standard library asynchronously.
std_sources
.into_par_iter()
2024-06-22 15:44:09 +00:00
.find_map_any(|(source_id, source)| self.run_with_builtins(source_id, source).err())
2024-06-22 11:46:10 +00:00
};
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-06-22 15:44:09 +00:00
fn run_with_builtins(
&self,
source_id: Arc<str>,
source: Arc<str>,
) -> Result<Option<Value>, InterpreterError> {
let mut sources = self.sources.write().unwrap();
sources.clear();
sources.push((source_id.clone(), source.clone()));
let tokens = lex(source.as_ref()).map_err(|errors| InterpreterError {
source_id: source_id.clone(),
errors,
})?;
let abstract_tree = 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| DustError::from(error))
.collect(),
})?;
let value_option = abstract_tree
.run(&self.context, true)
.map_err(|errors| InterpreterError { source_id, errors })?;
Ok(value_option)
}
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-06-18 23:42:04 +00:00
errors: Vec<DustError>,
2024-03-24 13:10:49 +00:00
}
impl InterpreterError {
2024-06-18 23:42:04 +00:00
pub fn errors(&self) -> &Vec<DustError> {
2024-03-24 13:10:49 +00:00
&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-06-18 23:42:04 +00:00
let token_color = Color::Yellow;
let type_color = Color::Green;
let identifier_color = Color::Blue;
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 {
DustError::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,
2024-03-24 13:10:49 +00:00
)
}
DustError::Parse {
expected,
span,
found,
} => {
let description = if expected.is_empty() {
"Invalid token.".to_string()
} else {
format!("Expected {expected}.")
};
let found = found
.unwrap_or_else(|| "End of input".to_string())
.fg(token_color);
(
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))
.with_message(format!("{found} is not valid in this position."))
.with_color(Color::Red),
),
None,
)
}
DustError::Validation { error, position } => (
2024-03-24 13:10:49 +00:00
Report::build(
ReportKind::Custom("Validation Error", Color::Magenta),
2024-03-24 13:10:49 +00:00
self.source_id.clone(),
position.1,
2024-03-24 13:10:49 +00:00
)
.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.",
2024-03-24 13:10:49 +00:00
),
Some(error),
2024-03-24 13:10:49 +00:00
),
DustError::Runtime { error, position } => {
2024-06-19 08:56:56 +00:00
let note = match &error {
RuntimeError::Io(io_error) => &io_error.to_string(),
RuntimeError::RwLockPoison(_) => todo!(),
2024-06-19 08:56:56 +00:00
RuntimeError::ValidationFailure(_) => {
"This is the interpreter's fault. Please submit a bug with this error message."
}
RuntimeError::SerdeJson(serde_json_error) => &serde_json_error.to_string(),
};
(
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_help(
2024-06-19 08:56:56 +00:00
"There may be unexpected side-effects because the program could not finish.",
)
2024-06-19 08:56:56 +00:00
.with_note(note)
.with_label(
2024-06-19 08:56:56 +00:00
Label::new((self.source_id.clone(), position.0..position.1)).with_message("Error occured here.")
),
if let RuntimeError::ValidationFailure(validation_error) = error {
Some(validation_error)
} else {
None
},
)
}
};
2024-03-24 13:10:49 +00:00
if let Some(validation_error) = validation_error {
match validation_error {
ValidationError::CannotAssignToNone(postion) => {
builder.add_label(
Label::new((self.source_id.clone(), postion.0..postion.1))
.with_message(format!(
"This statement does not yield a value, you cannot assign a variable to it."
)),
);
}
2024-03-24 13:10:49 +00:00
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::FullTypeNotKnown {
identifier,
position,
} => builder.add_label(
Label::new((self.source_id.clone(), position.0..position.1)).with_message(
format!(
"The full type for {} must be known.",
identifier.fg(identifier_color)
),
),
),
2024-03-24 13:10:49 +00:00
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;
2024-06-17 14:10:06 +00:00
if let Some(position) = expected_position {
builder.add_label(
Label::new((self.source_id.clone(), position.0..position.1))
.with_message(format!(
"Type {} established here.",
expected.fg(type_color)
)),
)
}
builder.add_label(
2024-03-24 13:10:49 +00:00
Label::new((
self.source_id.clone(),
actual_position.0..actual_position.1,
))
.with_message(format!("Got type {} here.", actual.fg(type_color))),
2024-06-17 14:10:06 +00:00
);
2024-03-24 13:10:49 +00:00
}
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),)),
])
}
2024-06-22 03:37:25 +00:00
ValidationError::ExpectedExpression(_) => todo!(),
2024-03-24 13:10:49 +00:00
ValidationError::ExpectedFunction { .. } => todo!(),
ValidationError::ExpectedValue(_) => todo!(),
ValidationError::PropertyNotFound { .. } => todo!(),
ValidationError::WrongArguments { .. } => todo!(),
2024-06-17 14:10:06 +00:00
ValidationError::WrongTypeArgumentCount { .. } => todo!(),
2024-03-24 13:10:49 +00:00
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
}
2024-06-16 07:12:04 +00:00
ValidationError::ExpectedString { .. } => todo!(),
ValidationError::EnumDefinitionNotFound {
identifier,
position,
} => {
let message = format!(
"The enum {} does not exist in this context.",
identifier.fg(identifier_color),
);
if let Some(position) = position {
builder.add_label(
Label::new((self.source_id.clone(), position.0..position.1))
.with_message(message),
)
} else {
builder = builder.with_message(message);
}
}
ValidationError::EnumVariantNotFound { .. } => todo!(),
2024-03-24 13:10:49 +00:00
}
}
2024-06-19 14:48:22 +00:00
2024-06-19 16:03:25 +00:00
builder = builder.with_config(Config::default().with_multiline_arrows(false));
2024-03-24 13:10:49 +00:00
let report = builder.finish();
reports.push(report);
}
reports
}
2024-03-06 23:15:25 +00:00
}
2024-05-25 15:48:43 +00:00
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn load_standard_library() {
Interpreter::new(Context::new(None)).load_std().unwrap();
}
}