Toy with chumsky and ariadne

This commit is contained in:
Jeff 2024-03-24 15:35:19 -04:00
parent 6b0bb0016f
commit 966983920e
15 changed files with 181 additions and 201 deletions

View File

@ -66,6 +66,18 @@ impl AbstractNode for FunctionCall {
})?;
}
for (type_parameter, expression) in parameter_types.iter().zip(self.arguments.iter()) {
let actual = expression.node.expected_type(context)?;
type_parameter.node.check(&actual).map_err(|conflict| {
ValidationError::TypeCheck {
conflict,
actual_position: expression.position,
expected_position: type_parameter.position,
}
})?;
}
Ok(())
} else {
Err(ValidationError::ExpectedFunction {

View File

@ -180,7 +180,7 @@ impl Display for Type {
write!(f, ") : {}", return_type.node)
}
Type::Structure { name, .. } => write!(f, "{name}"),
Type::Argument(_) => todo!(),
Type::Argument(identifier) => write!(f, "{identifier}"),
}
}
}

View File

@ -115,6 +115,8 @@ impl AbstractNode for ValueNode {
})?;
}
}
return Ok(());
}
if let ValueNode::ParsedFunction {
@ -150,6 +152,8 @@ impl AbstractNode for ValueNode {
actual_position: body.position,
expected_position: return_type.position,
})?;
return Ok(());
}
if let ValueNode::Structure {

View File

@ -13,7 +13,7 @@ use crate::{
Value,
};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum BuiltInFunction {
ReadLine,
Sleep,
@ -23,9 +23,9 @@ pub enum BuiltInFunction {
impl BuiltInFunction {
pub fn name(&self) -> &'static str {
match self {
BuiltInFunction::ReadLine => todo!(),
BuiltInFunction::Sleep => todo!(),
BuiltInFunction::WriteLine => todo!(),
BuiltInFunction::ReadLine => "__READ_LINE__",
BuiltInFunction::Sleep => "__SLEEP__",
BuiltInFunction::WriteLine => "__WRITE_LINE__",
}
}

View File

@ -5,12 +5,12 @@ use std::{
use chumsky::prelude::*;
use crate::error::Error;
use crate::{built_in_functions::BuiltInFunction, error::Error};
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Token<'src> {
Boolean(bool),
BuiltInIdentifier(BuiltInIdentifier),
BuiltInFunction(BuiltInFunction),
Integer(i64),
Float(f64),
String(&'src str),
@ -24,7 +24,7 @@ impl<'src> Display for Token<'src> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Token::Boolean(boolean) => write!(f, "{boolean}"),
Token::BuiltInIdentifier(built_in_identifier) => write!(f, "{built_in_identifier}"),
Token::BuiltInFunction(built_in_identifier) => write!(f, "{built_in_identifier}"),
Token::Integer(integer) => write!(f, "{integer}"),
Token::Float(float) => write!(f, "{float}"),
Token::String(string) => write!(f, "{string}"),
@ -36,23 +36,6 @@ impl<'src> Display for Token<'src> {
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BuiltInIdentifier {
ReadLine,
Sleep,
WriteLine,
}
impl Display for BuiltInIdentifier {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
BuiltInIdentifier::ReadLine => write!(f, "__READ_LINE__"),
BuiltInIdentifier::Sleep => write!(f, "__SLEEP__"),
BuiltInIdentifier::WriteLine => write!(f, "__WRITE_LINE__"),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Keyword {
Any,
@ -315,11 +298,11 @@ pub fn lexer<'src>() -> impl Parser<
.map(Token::Keyword);
let built_in_identifier = choice((
just("__READ_LINE__").to(BuiltInIdentifier::ReadLine),
just("__SLEEP__").to(BuiltInIdentifier::Sleep),
just("__WRITE_LINE__").to(BuiltInIdentifier::WriteLine),
just(BuiltInFunction::ReadLine.name()).to(BuiltInFunction::ReadLine),
just(BuiltInFunction::Sleep.name()).to(BuiltInFunction::Sleep),
just(BuiltInFunction::WriteLine.name()).to(BuiltInFunction::WriteLine),
))
.map(Token::BuiltInIdentifier);
.map(Token::BuiltInFunction);
choice((
boolean,

View File

@ -6,7 +6,7 @@ pub mod lexer;
pub mod parser;
pub mod value;
use std::{ops::Range, rc::Rc};
use std::{cell::RefCell, ops::Range, rc::Rc, vec};
use abstract_tree::Type;
use ariadne::{Color, Fmt, Label, Report, ReportKind};
@ -16,20 +16,88 @@ use lexer::lex;
use parser::parse;
pub use value::Value;
pub fn interpret(source_id: Rc<String>, 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());
interpreter.load_std()?;
interpreter.run(source_id, source)
interpreter.run(Rc::new(source_id.to_string()), Rc::from(source))
}
pub fn interpret_without_std(
source_id: Rc<String>,
source_id: &str,
source: &str,
) -> Result<Option<Value>, InterpreterError> {
let mut interpreter = Interpreter::new(Context::new());
interpreter.run(source_id, source)
interpreter.run(Rc::new(source_id.to_string()), Rc::from(source))
}
pub struct Interpreter {
context: Context,
sources: Rc<RefCell<Vec<(Rc<String>, Rc<str>)>>>,
}
impl Interpreter {
pub fn new(context: Context) -> Self {
Interpreter {
context,
sources: Rc::new(RefCell::new(Vec::new())),
}
}
pub fn run(
&mut self,
source_id: Rc<String>,
source: Rc<str>,
) -> Result<Option<Value>, InterpreterError> {
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
.run(&self.context)
.map_err(|errors| InterpreterError {
source_id: source_id.clone(),
errors,
})?;
self.sources.borrow_mut().push((source_id, source.into()));
Ok(value_option)
}
pub fn run_all<T: IntoIterator<Item = (Rc<String>, Rc<str>)>>(
&mut self,
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::new("std/io.ds".to_string()),
Rc::from(include_str!("../../std/io.ds")),
),
(
Rc::new("std/thread.ds".to_string()),
Rc::from(include_str!("../../std/thread.ds")),
),
])
}
pub fn sources(&self) -> vec::IntoIter<(Rc<String>, Rc<str>)> {
self.sources.borrow().clone().into_iter()
}
}
#[derive(Debug, PartialEq)]
@ -45,7 +113,7 @@ impl InterpreterError {
}
impl InterpreterError {
pub fn build_reports<'id>(self) -> Vec<Report<'id, (Rc<String>, Range<usize>)>> {
pub fn build_reports<'a>(self) -> Vec<Report<'a, (Rc<String>, Range<usize>)>> {
let mut reports = Vec::new();
for error in self.errors {
@ -170,8 +238,6 @@ impl InterpreterError {
} => {
let TypeConflict { actual, expected } = conflict;
builder = builder.with_message("A type conflict was found.");
builder.add_labels([
Label::new((
self.source_id.clone(),
@ -257,46 +323,3 @@ impl InterpreterError {
reports
}
}
pub struct Interpreter {
context: Context,
}
impl Interpreter {
pub fn new(context: Context) -> Self {
Interpreter { context }
}
pub fn run(
&mut self,
source_id: Rc<String>,
source: &str,
) -> Result<Option<Value>, InterpreterError> {
let tokens = lex(source).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
.run(&self.context)
.map_err(|errors| InterpreterError { source_id, errors })?;
Ok(value_option)
}
pub fn load_std(&mut self) -> Result<(), InterpreterError> {
self.run(
Rc::new("std/io.ds".to_string()),
include_str!("../../std/io.ds"),
)?;
self.run(
Rc::new("std/io.ds".to_string()),
include_str!("../../std/thread.ds"),
)?;
Ok(())
}
}

View File

@ -4,9 +4,8 @@ use chumsky::{input::SpannedInput, pratt::*, prelude::*};
use crate::{
abstract_tree::*,
built_in_functions::BuiltInFunction,
error::Error,
lexer::{BuiltInIdentifier, Control, Keyword, Operator, Token},
lexer::{Control, Keyword, Operator, Token},
};
pub type ParserInput<'src> =
@ -256,11 +255,8 @@ pub fn parser<'src>() -> impl Parser<
let built_in_function = {
select! {
Token::BuiltInIdentifier(built_in_identifier) => {
match built_in_identifier {BuiltInIdentifier::ReadLine=>BuiltInFunction::ReadLine,BuiltInIdentifier::WriteLine=>BuiltInFunction::WriteLine,
BuiltInIdentifier::Sleep => BuiltInFunction::Sleep, }
}
}
Token::BuiltInFunction(built_in_function) => built_in_function,
}
}
.map_with(|built_in_function, state| {
Expression::Value(ValueNode::BuiltInFunction(built_in_function))
@ -582,7 +578,7 @@ pub fn parser<'src>() -> impl Parser<
#[cfg(test)]
mod tests {
use crate::lexer::lex;
use crate::{built_in_functions::BuiltInFunction, lexer::lex};
use super::*;

View File

@ -1,27 +1,22 @@
use std::rc::Rc;
use dust_lang::*;
#[test]
fn logic() {
assert_eq!(
interpret(Rc::new("test".to_string()), "1 == 1").unwrap(),
interpret("test", "1 == 1").unwrap(),
Some(Value::boolean(true))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "('42' == '42') && (42 != 0)").unwrap(),
interpret("test", "('42' == '42') && (42 != 0)").unwrap(),
Some(Value::boolean(true))
);
}
#[test]
fn math() {
assert_eq!(interpret("test", "1 + 1").unwrap(), Some(Value::integer(2)));
assert_eq!(
interpret(Rc::new("test".to_string()), "1 + 1").unwrap(),
Some(Value::integer(2))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "2 * (21 + 19 + 1 * 2) / 2").unwrap(),
interpret("test", "2 * (21 + 19 + 1 * 2) / 2").unwrap(),
Some(Value::integer(42))
);
}
@ -29,7 +24,7 @@ fn math() {
#[test]
fn list_index() {
assert_eq!(
interpret(Rc::new("test".to_string()), "foo = [1, 2, 3]; foo[2]").unwrap(),
interpret("test", "foo = [1, 2, 3]; foo[2]").unwrap(),
Some(Value::integer(3))
);
}
@ -37,11 +32,11 @@ fn list_index() {
#[test]
fn map_index() {
assert_eq!(
interpret(Rc::new("test".to_string()), "{ x = 3 }.x").unwrap(),
interpret("test", "{ x = 3 }.x").unwrap(),
Some(Value::integer(3))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "foo = { x = 3 }; foo.x").unwrap(),
interpret("test", "foo = { x = 3 }; foo.x").unwrap(),
Some(Value::integer(3))
);
}

View File

@ -1,16 +1,16 @@
use std::rc::Rc;
use dust_lang::{
abstract_tree::Identifier,
error::{Error, ValidationError},
*,
};
use dust_lang::interpret;
#[test]
fn function_call() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
foobar = (message : str) str { message }
foobar('Hiya')
@ -24,7 +24,7 @@ fn function_call() {
fn call_empty_function() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
foobar = (message : str) none {}
foobar('Hiya')
@ -38,7 +38,7 @@ fn call_empty_function() {
fn callback() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
foobar = (cb: fn() -> str) str {
cb()
@ -52,17 +52,14 @@ fn callback() {
#[test]
fn built_in_function_call() {
assert_eq!(
interpret(Rc::new("test".to_string()), "io.write_line('Hiya')"),
Ok(None)
);
assert_eq!(interpret("test", "io.write_line('Hiya')"), Ok(None));
}
#[test]
fn function_context_does_not_capture_values() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
x = 1
@ -79,7 +76,7 @@ fn function_context_does_not_capture_values() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
x = 1
foo = (x: int) int { x }
@ -94,7 +91,7 @@ fn function_context_does_not_capture_values() {
fn function_context_captures_functions() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
bar = () int { 2 }
foo = () int { bar() }
@ -109,7 +106,7 @@ fn function_context_captures_functions() {
fn recursion() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
fib = (i: int) int {
if i <= 1 {

View File

@ -1,12 +1,10 @@
use std::rc::Rc;
use dust_lang::*;
#[test]
fn async_block() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
x = 41
async {
@ -24,7 +22,7 @@ fn async_block() {
fn loops_and_breaks() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
i = 0
loop {
@ -41,7 +39,7 @@ fn loops_and_breaks() {
);
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
foobar = {
while true {
@ -60,7 +58,7 @@ fn loops_and_breaks() {
#[test]
fn r#if() {
assert_eq!(
interpret(Rc::new("test".to_string()), "if true { 'foobar' }"),
interpret("test", "if true { 'foobar' }"),
Ok(Some(Value::string("foobar".to_string())))
)
}
@ -68,10 +66,7 @@ fn r#if() {
#[test]
fn if_else() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"if false { 'foo' } else { 'bar' }"
),
interpret("test", "if false { 'foo' } else { 'bar' }"),
Ok(Some(Value::string("bar".to_string())))
)
}

View File

@ -1,15 +1,14 @@
use std::rc::Rc;
use dust_lang::{
abstract_tree::{Identifier, Type},
error::{Error, TypeConflict, ValidationError},
*,
interpret, Value,
};
#[test]
fn simple_structure() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
struct Foo {
bar : int,
@ -36,7 +35,7 @@ fn simple_structure() {
fn field_type_error() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
struct Foo {
bar : int,
@ -67,7 +66,7 @@ fn field_type_error() {
fn nested_structure() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
struct Bar {
baz : int
@ -100,7 +99,7 @@ fn nested_structure() {
fn undefined_struct() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"test",
"
Foo {
bar = 42
@ -110,7 +109,7 @@ fn undefined_struct() {
.unwrap_err()
.errors(),
&vec![Error::Validation {
error: error::ValidationError::VariableNotFound(Identifier::new("Foo")),
error: ValidationError::VariableNotFound(Identifier::new("Foo")),
position: (17, 69).into()
}]
)

View File

@ -1,4 +1,4 @@
use std::{collections::BTreeMap, rc::Rc};
use std::collections::BTreeMap;
use dust_lang::{
abstract_tree::{Identifier, Type, WithPos},
@ -8,37 +8,25 @@ use dust_lang::{
#[test]
fn none() {
assert_eq!(interpret(Rc::new("test".to_string()), "x = 9"), Ok(None));
assert_eq!(
interpret(Rc::new("test".to_string()), "x = 1 + 1"),
Ok(None)
);
assert_eq!(interpret("test", "x = 9"), Ok(None));
assert_eq!(interpret("test", "x = 1 + 1"), Ok(None));
}
#[test]
fn integer() {
assert_eq!(
interpret(Rc::new("test".to_string()), "1"),
Ok(Some(Value::integer(1)))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "123"),
Ok(Some(Value::integer(123)))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "-666"),
Ok(Some(Value::integer(-666)))
);
assert_eq!(interpret("test", "1"), Ok(Some(Value::integer(1))));
assert_eq!(interpret("test", "123"), Ok(Some(Value::integer(123))));
assert_eq!(interpret("test", "-666"), Ok(Some(Value::integer(-666))));
}
#[test]
fn integer_saturation() {
assert_eq!(
interpret(Rc::new("test".to_string()), "9223372036854775807 + 1"),
interpret("test", "9223372036854775807 + 1"),
Ok(Some(Value::integer(i64::MAX)))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "-9223372036854775808 - 1"),
interpret("test", "-9223372036854775808 - 1"),
Ok(Some(Value::integer(i64::MIN)))
);
}
@ -46,11 +34,11 @@ fn integer_saturation() {
#[test]
fn float() {
assert_eq!(
interpret(Rc::new("test".to_string()), "1.7976931348623157e308"),
interpret("test", "1.7976931348623157e308"),
Ok(Some(Value::float(f64::MAX)))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "-1.7976931348623157e308"),
interpret("test", "-1.7976931348623157e308"),
Ok(Some(Value::float(f64::MIN)))
);
}
@ -58,11 +46,11 @@ fn float() {
#[test]
fn float_saturation() {
assert_eq!(
interpret(Rc::new("test".to_string()), "1.7976931348623157e308 + 1"),
interpret("test", "1.7976931348623157e308 + 1"),
Ok(Some(Value::float(f64::MAX)))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "-1.7976931348623157e308 - 1"),
interpret("test", "-1.7976931348623157e308 - 1"),
Ok(Some(Value::float(f64::MIN)))
);
}
@ -70,27 +58,27 @@ fn float_saturation() {
#[test]
fn string() {
assert_eq!(
interpret(Rc::new("test".to_string()), "\"one\""),
interpret("test", "\"one\""),
Ok(Some(Value::string("one".to_string())))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "'one'"),
interpret("test", "'one'"),
Ok(Some(Value::string("one".to_string())))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "`one`"),
interpret("test", "`one`"),
Ok(Some(Value::string("one".to_string())))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "`'one'`"),
interpret("test", "`'one'`"),
Ok(Some(Value::string("'one'".to_string())))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "'`one`'"),
interpret("test", "'`one`'"),
Ok(Some(Value::string("`one`".to_string())))
);
assert_eq!(
interpret(Rc::new("test".to_string()), "\"'one'\""),
interpret("test", "\"'one'\""),
Ok(Some(Value::string("'one'".to_string())))
);
}
@ -98,7 +86,7 @@ fn string() {
#[test]
fn list() {
assert_eq!(
interpret(Rc::new("test".to_string()), "[1, 2, 'foobar']"),
interpret("test", "[1, 2, 'foobar']"),
Ok(Some(Value::list(vec![
Value::integer(1).with_position((1, 2)),
Value::integer(2).with_position((4, 5)),
@ -109,10 +97,7 @@ fn list() {
#[test]
fn empty_list() {
assert_eq!(
interpret(Rc::new("test".to_string()), "[]"),
Ok(Some(Value::list(Vec::new())))
);
assert_eq!(interpret("test", "[]"), Ok(Some(Value::list(Vec::new()))));
}
#[test]
@ -123,7 +108,7 @@ fn map() {
map.insert(Identifier::new("foo"), Value::string("bar".to_string()));
assert_eq!(
interpret(Rc::new("test".to_string()), "{ x = 1, foo = 'bar' }"),
interpret("test", "{ x = 1, foo = 'bar' }"),
Ok(Some(Value::map(map)))
);
}
@ -131,7 +116,7 @@ fn map() {
#[test]
fn empty_map() {
assert_eq!(
interpret(Rc::new("test".to_string()), "{}"),
interpret("test", "{}"),
Ok(Some(Value::map(BTreeMap::new())))
);
}
@ -144,10 +129,7 @@ fn map_types() {
map.insert(Identifier::new("foo"), Value::string("bar".to_string()));
assert_eq!(
interpret(
Rc::new("test".to_string()),
"{ x : int = 1, foo : str = 'bar' }"
),
interpret("test", "{ x : int = 1, foo : str = 'bar' }"),
Ok(Some(Value::map(map)))
);
}
@ -155,7 +137,7 @@ fn map_types() {
#[test]
fn map_type_errors() {
assert_eq!(
interpret(Rc::new("test".to_string()), "{ foo : bool = 'bar' }")
interpret("test", "{ foo : bool = 'bar' }")
.unwrap_err()
.errors(),
&vec![Error::Validation {
@ -174,8 +156,5 @@ fn map_type_errors() {
#[test]
fn range() {
assert_eq!(
interpret(Rc::new("test".to_string()), "0..100"),
Ok(Some(Value::range(0..100)))
);
assert_eq!(interpret("test", "0..100"), Ok(Some(Value::range(0..100))));
}

View File

@ -1,5 +1,3 @@
use std::rc::Rc;
use dust_lang::{
abstract_tree::{Block, Expression, Identifier, Statement, Type, WithPos},
error::{Error, TypeConflict, ValidationError},
@ -9,7 +7,7 @@ use dust_lang::{
#[test]
fn set_and_get_variable() {
assert_eq!(
interpret(Rc::new("test".to_string()), "foobar = true; foobar"),
interpret("test", "foobar = true; foobar"),
Ok(Some(Value::boolean(true)))
);
}
@ -17,7 +15,7 @@ fn set_and_get_variable() {
#[test]
fn set_variable_with_type() {
assert_eq!(
interpret(Rc::new("test".to_string()), "foobar: bool = true; foobar"),
interpret("test", "foobar: bool = true; foobar"),
Ok(Some(Value::boolean(true)))
);
}
@ -25,7 +23,7 @@ fn set_variable_with_type() {
#[test]
fn set_variable_with_type_error() {
assert_eq!(
interpret(Rc::new("test".to_string()), "foobar: str = true")
interpret("test", "foobar: str = true")
.unwrap_err()
.errors(),
&vec![Error::Validation {
@ -45,10 +43,7 @@ fn set_variable_with_type_error() {
#[test]
fn function_variable() {
assert_eq!(
interpret(
Rc::new("test".to_string()),
"foobar = (x: int) int { x }; foobar"
),
interpret("test", "foobar = (x: int) int { x }; foobar"),
Ok(Some(Value::function(
Vec::with_capacity(0),
vec![(Identifier::new("x"), Type::Integer.with_position((13, 16)))],

View File

@ -80,7 +80,8 @@ pub fn run_shell(context: Context) -> Result<(), io::Error> {
continue;
}
let run_result = interpreter.run(Rc::new("input".to_string()), &buffer);
let run_result =
interpreter.run(Rc::new("input".to_string()), Rc::from(buffer.as_str()));
match run_result {
Ok(Some(value)) => {
@ -88,12 +89,11 @@ pub fn run_shell(context: Context) -> Result<(), io::Error> {
}
Ok(None) => {}
Err(error) => {
let source_id = Rc::new("input".to_string());
let reports = error.build_reports();
for report in reports {
report
.write_for_stdout(sources([(source_id.clone(), &buffer)]), stderr())
.write_for_stdout(sources(interpreter.sources()), stderr())
.unwrap();
}
}

View File

@ -12,7 +12,7 @@ use std::{
rc::Rc,
};
use dust_lang::{context::Context, interpret, interpret_without_std};
use dust_lang::{context::Context, Interpreter};
/// Command-line arguments to be parsed.
#[derive(Parser, Debug)]
@ -42,10 +42,16 @@ fn main() {
let args = Args::parse();
let context = Context::new();
let (source, source_id) = if let Some(path) = args.path {
(read_to_string(&path).unwrap(), Rc::new(path))
let mut interpreter = Interpreter::new(context.clone());
interpreter.load_std().unwrap();
let (source_id, source) = if let Some(path) = args.path {
let source = read_to_string(&path).unwrap();
(Rc::new(path.to_string()), source)
} else if let Some(command) = args.command {
(command, Rc::new("input".to_string()))
(Rc::new("input".to_string()), command)
} else {
match run_shell(context) {
Ok(_) => {}
@ -55,13 +61,9 @@ fn main() {
return;
};
let eval_result = if args.no_std {
interpret_without_std(source_id.clone(), &source)
} else {
interpret(source_id.clone(), &source)
};
let run_result = interpreter.run(source_id, Rc::from(source));
match eval_result {
match run_result {
Ok(value) => {
if let Some(value) = value {
println!("{value}")
@ -70,7 +72,7 @@ fn main() {
Err(error) => {
for report in error.build_reports() {
report
.write_for_stdout(sources([(source_id.clone(), source.as_str())]), stderr())
.write_for_stdout(sources(interpreter.sources()), stderr())
.unwrap();
}
}