Clean up
This commit is contained in:
parent
2871fd125a
commit
4b460c0e68
@ -69,6 +69,24 @@ impl AbstractNode for MapIndex {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let (
|
||||||
|
Expression::Value(ValueNode::Structure { fields, .. }),
|
||||||
|
Expression::Identifier(identifier),
|
||||||
|
) = (&self.left.node, &self.right.node)
|
||||||
|
{
|
||||||
|
return if let Some(type_result) = fields.iter().find_map(|(property, expression)| {
|
||||||
|
if property == identifier {
|
||||||
|
Some(expression.node.expected_type(context))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
type_result
|
||||||
|
} else {
|
||||||
|
Ok(Type::None)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Err(ValidationError::CannotIndexWith {
|
Err(ValidationError::CannotIndexWith {
|
||||||
collection_type: self.left.node.expected_type(context)?,
|
collection_type: self.left.node.expected_type(context)?,
|
||||||
collection_position: self.left.position,
|
collection_position: self.left.position,
|
||||||
|
@ -6,7 +6,11 @@ pub mod lexer;
|
|||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
|
||||||
use std::{cell::RefCell, ops::Range, rc::Rc, vec};
|
use std::{
|
||||||
|
ops::Range,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
vec,
|
||||||
|
};
|
||||||
|
|
||||||
use abstract_tree::Type;
|
use abstract_tree::Type;
|
||||||
use ariadne::{Color, Fmt, Label, Report, ReportKind};
|
use ariadne::{Color, Fmt, Label, Report, ReportKind};
|
||||||
@ -14,42 +18,48 @@ 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;
|
||||||
|
use rayon::prelude::*;
|
||||||
pub use value::Value;
|
pub use value::Value;
|
||||||
|
|
||||||
pub fn interpret<'src>(source_id: &str, source: &str) -> Result<Option<Value>, InterpreterError> {
|
pub fn interpret<'src>(source_id: &str, source: &str) -> Result<Option<Value>, InterpreterError> {
|
||||||
let mut interpreter = Interpreter::new(Context::new());
|
let mut interpreter = Interpreter::new(Context::new());
|
||||||
|
|
||||||
interpreter.load_std()?;
|
interpreter.load_std()?;
|
||||||
interpreter.run(Rc::from(source_id), Rc::from(source))
|
interpreter.run(Arc::from(source_id), Arc::from(source))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interpret_without_std(
|
pub fn interpret_without_std(
|
||||||
source_id: &str,
|
source_id: &str,
|
||||||
source: &str,
|
source: &str,
|
||||||
) -> Result<Option<Value>, InterpreterError> {
|
) -> Result<Option<Value>, InterpreterError> {
|
||||||
let mut interpreter = Interpreter::new(Context::new());
|
let interpreter = Interpreter::new(Context::new());
|
||||||
|
|
||||||
interpreter.run(Rc::from(source_id.to_string()), Rc::from(source))
|
interpreter.run(Arc::from(source_id.to_string()), Arc::from(source))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Interpreter {
|
pub struct Interpreter {
|
||||||
context: Context,
|
context: Context,
|
||||||
sources: Rc<RefCell<Vec<(Rc<str>, Rc<str>)>>>,
|
sources: Arc<RwLock<Vec<(Arc<str>, Arc<str>)>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpreter {
|
impl Interpreter {
|
||||||
pub fn new(context: Context) -> Self {
|
pub fn new(context: Context) -> Self {
|
||||||
Interpreter {
|
Interpreter {
|
||||||
context,
|
context,
|
||||||
sources: Rc::new(RefCell::new(Vec::new())),
|
sources: Arc::new(RwLock::new(Vec::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(
|
pub fn run(
|
||||||
&mut self,
|
&self,
|
||||||
source_id: Rc<str>,
|
source_id: Arc<str>,
|
||||||
source: Rc<str>,
|
source: Arc<str>,
|
||||||
) -> Result<Option<Value>, InterpreterError> {
|
) -> Result<Option<Value>, InterpreterError> {
|
||||||
|
self.sources
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.push((source_id.clone(), source.clone()));
|
||||||
|
|
||||||
let tokens = lex(source.as_ref()).map_err(|errors| InterpreterError {
|
let tokens = lex(source.as_ref()).map_err(|errors| InterpreterError {
|
||||||
source_id: source_id.clone(),
|
source_id: source_id.clone(),
|
||||||
errors,
|
errors,
|
||||||
@ -60,50 +70,42 @@ impl Interpreter {
|
|||||||
})?;
|
})?;
|
||||||
let value_option = abstract_tree
|
let value_option = abstract_tree
|
||||||
.run(&self.context)
|
.run(&self.context)
|
||||||
.map_err(|errors| InterpreterError {
|
.map_err(|errors| InterpreterError { source_id, errors })?;
|
||||||
source_id: source_id.clone(),
|
|
||||||
errors,
|
|
||||||
})?;
|
|
||||||
|
|
||||||
self.sources.borrow_mut().push((source_id, source.into()));
|
|
||||||
|
|
||||||
Ok(value_option)
|
Ok(value_option)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_all<T: IntoIterator<Item = (Rc<str>, Rc<str>)>>(
|
pub fn load_std(&mut self) -> Result<(), InterpreterError> {
|
||||||
&mut self,
|
let std_sources = [
|
||||||
sources: T,
|
|
||||||
) -> Result<Option<Value>, InterpreterError> {
|
|
||||||
let mut previous_value_option = None;
|
|
||||||
|
|
||||||
for (source_id, source) in sources {
|
|
||||||
previous_value_option = self.run(source_id.clone(), source)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(previous_value_option)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_std(&mut self) -> Result<Option<Value>, InterpreterError> {
|
|
||||||
self.run_all([
|
|
||||||
(
|
(
|
||||||
Rc::from("std/io.ds"),
|
Arc::from("std/io.ds"),
|
||||||
Rc::from(include_str!("../../std/io.ds")),
|
Arc::from(include_str!("../../std/io.ds")),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Rc::from("std/thread.ds"),
|
Arc::from("std/thread.ds"),
|
||||||
Rc::from(include_str!("../../std/thread.ds")),
|
Arc::from(include_str!("../../std/thread.ds")),
|
||||||
),
|
),
|
||||||
])
|
];
|
||||||
|
|
||||||
|
let error = std_sources
|
||||||
|
.into_par_iter()
|
||||||
|
.find_map_any(|(source_id, source)| self.run(source_id, source).err());
|
||||||
|
|
||||||
|
if let Some(error) = error {
|
||||||
|
Err(error)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sources(&self) -> vec::IntoIter<(Rc<str>, Rc<str>)> {
|
pub fn sources(&self) -> vec::IntoIter<(Arc<str>, Arc<str>)> {
|
||||||
self.sources.borrow().clone().into_iter()
|
self.sources.read().unwrap().clone().into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct InterpreterError {
|
pub struct InterpreterError {
|
||||||
source_id: Rc<str>,
|
source_id: Arc<str>,
|
||||||
errors: Vec<Error>,
|
errors: Vec<Error>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +116,7 @@ impl InterpreterError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl InterpreterError {
|
impl InterpreterError {
|
||||||
pub fn build_reports<'a>(self) -> Vec<Report<'a, (Rc<str>, Range<usize>)>> {
|
pub fn build_reports<'a>(self) -> Vec<Report<'a, (Arc<str>, Range<usize>)>> {
|
||||||
let mut reports = Vec::new();
|
let mut reports = Vec::new();
|
||||||
|
|
||||||
for error in self.errors {
|
for error in self.errors {
|
||||||
@ -173,6 +175,17 @@ impl InterpreterError {
|
|||||||
span.into(),
|
span.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
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),
|
||||||
|
position,
|
||||||
|
),
|
||||||
Error::Runtime { error, position } => (
|
Error::Runtime { error, position } => (
|
||||||
Report::build(
|
Report::build(
|
||||||
ReportKind::Custom("Runtime Error", Color::Red),
|
ReportKind::Custom("Runtime Error", Color::Red),
|
||||||
@ -185,6 +198,9 @@ impl InterpreterError {
|
|||||||
)
|
)
|
||||||
.with_help(
|
.with_help(
|
||||||
"This is the interpreter's fault. Please submit a bug with this error message.",
|
"This is the interpreter's fault. Please submit a bug with this error message.",
|
||||||
|
)
|
||||||
|
.with_label(
|
||||||
|
Label::new((self.source_id.clone(), position.0..position.1)).with_message("Runtime error occured here.")
|
||||||
),
|
),
|
||||||
if let RuntimeError::ValidationFailure(validation_error) = error {
|
if let RuntimeError::ValidationFailure(validation_error) = error {
|
||||||
Some(validation_error)
|
Some(validation_error)
|
||||||
@ -193,17 +209,6 @@ impl InterpreterError {
|
|||||||
},
|
},
|
||||||
position,
|
position,
|
||||||
),
|
),
|
||||||
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 is not sound.")
|
|
||||||
.with_note("This error was detected by the interpreter before running the code."),
|
|
||||||
Some(error),
|
|
||||||
position,
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let type_color = Color::Green;
|
let type_color = Color::Green;
|
||||||
@ -235,14 +240,14 @@ impl InterpreterError {
|
|||||||
ValidationError::TypeCheck {
|
ValidationError::TypeCheck {
|
||||||
conflict,
|
conflict,
|
||||||
actual_position,
|
actual_position,
|
||||||
expected_position: expected_postion,
|
expected_position,
|
||||||
} => {
|
} => {
|
||||||
let TypeConflict { actual, expected } = conflict;
|
let TypeConflict { actual, expected } = conflict;
|
||||||
|
|
||||||
builder.add_labels([
|
builder.add_labels([
|
||||||
Label::new((
|
Label::new((
|
||||||
self.source_id.clone(),
|
self.source_id.clone(),
|
||||||
expected_postion.0..expected_postion.1,
|
expected_position.0..expected_position.1,
|
||||||
))
|
))
|
||||||
.with_message(format!(
|
.with_message(format!(
|
||||||
"Type {} established here.",
|
"Type {} established here.",
|
||||||
@ -308,11 +313,10 @@ impl InterpreterError {
|
|||||||
Type::String.fg(type_color)
|
Type::String.fg(type_color)
|
||||||
));
|
));
|
||||||
|
|
||||||
builder.add_labels([Label::new((
|
builder.add_label(
|
||||||
self.source_id.clone(),
|
Label::new((self.source_id.clone(), position.0..position.1))
|
||||||
position.0..position.1,
|
.with_message(format!("This has type {}.", actual.fg(type_color),)),
|
||||||
))
|
)
|
||||||
.with_message(format!("This has type {}.", actual.fg(type_color),))])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use std::{
|
|||||||
io::{self, stderr},
|
io::{self, stderr},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
process::Command,
|
process::Command,
|
||||||
rc::Rc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ariadne::sources;
|
use ariadne::sources;
|
||||||
@ -19,7 +19,7 @@ use reedline::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn run_shell(context: Context) -> Result<(), io::Error> {
|
pub fn run_shell(context: Context) -> Result<(), io::Error> {
|
||||||
let mut interpreter = Interpreter::new(context.clone());
|
let interpreter = Interpreter::new(context.clone());
|
||||||
let mut keybindings = default_emacs_keybindings();
|
let mut keybindings = default_emacs_keybindings();
|
||||||
|
|
||||||
keybindings.add_binding(
|
keybindings.add_binding(
|
||||||
@ -80,7 +80,7 @@ pub fn run_shell(context: Context) -> Result<(), io::Error> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let run_result = interpreter.run(Rc::from("input"), Rc::from(buffer.as_str()));
|
let run_result = interpreter.run(Arc::from("input"), Arc::from(buffer.as_str()));
|
||||||
|
|
||||||
match run_result {
|
match run_result {
|
||||||
Ok(Some(value)) => {
|
Ok(Some(value)) => {
|
||||||
|
@ -9,7 +9,7 @@ use colored::Colorize;
|
|||||||
use std::{
|
use std::{
|
||||||
fs::read_to_string,
|
fs::read_to_string,
|
||||||
io::{stderr, Write},
|
io::{stderr, Write},
|
||||||
rc::Rc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use dust_lang::{context::Context, Interpreter};
|
use dust_lang::{context::Context, Interpreter};
|
||||||
@ -46,12 +46,12 @@ fn main() {
|
|||||||
|
|
||||||
interpreter.load_std().unwrap();
|
interpreter.load_std().unwrap();
|
||||||
|
|
||||||
let (source_id, source) = if let Some(path) = args.path {
|
let (source_id, source): (Arc<str>, Arc<str>) = if let Some(path) = args.path {
|
||||||
let source = read_to_string(&path).unwrap();
|
let source = read_to_string(&path).unwrap();
|
||||||
|
|
||||||
(Rc::from(path), source)
|
(Arc::from(path), Arc::from(source.as_str()))
|
||||||
} else if let Some(command) = args.command {
|
} else if let Some(command) = args.command {
|
||||||
(Rc::from("input"), command)
|
(Arc::from("command"), Arc::from(command.as_str()))
|
||||||
} else {
|
} else {
|
||||||
match run_shell(context) {
|
match run_shell(context) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
@ -61,7 +61,7 @@ fn main() {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let run_result = interpreter.run(source_id, Rc::from(source));
|
let run_result = interpreter.run(source_id.clone(), source.clone());
|
||||||
|
|
||||||
match run_result {
|
match run_result {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user