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(()) Ok(())
} else { } else {
Err(ValidationError::ExpectedFunction { Err(ValidationError::ExpectedFunction {

View File

@ -180,7 +180,7 @@ impl Display for Type {
write!(f, ") : {}", return_type.node) write!(f, ") : {}", return_type.node)
} }
Type::Structure { name, .. } => write!(f, "{name}"), 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 { if let ValueNode::ParsedFunction {
@ -150,6 +152,8 @@ impl AbstractNode for ValueNode {
actual_position: body.position, actual_position: body.position,
expected_position: return_type.position, expected_position: return_type.position,
})?; })?;
return Ok(());
} }
if let ValueNode::Structure { if let ValueNode::Structure {

View File

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

View File

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

View File

@ -6,7 +6,7 @@ pub mod lexer;
pub mod parser; pub mod parser;
pub mod value; pub mod value;
use std::{ops::Range, rc::Rc}; use std::{cell::RefCell, ops::Range, rc::Rc, vec};
use abstract_tree::Type; use abstract_tree::Type;
use ariadne::{Color, Fmt, Label, Report, ReportKind}; use ariadne::{Color, Fmt, Label, Report, ReportKind};
@ -16,20 +16,88 @@ use lexer::lex;
use parser::parse; use parser::parse;
pub use value::Value; 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()); let mut interpreter = Interpreter::new(Context::new());
interpreter.load_std()?; interpreter.run(Rc::new(source_id.to_string()), Rc::from(source))
interpreter.run(source_id, source)
} }
pub fn interpret_without_std( pub fn interpret_without_std(
source_id: Rc<String>, source_id: &str,
source: &str, source: &str,
) -> Result<Option<Value>, InterpreterError> { ) -> Result<Option<Value>, InterpreterError> {
let mut interpreter = Interpreter::new(Context::new()); 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)] #[derive(Debug, PartialEq)]
@ -45,7 +113,7 @@ impl InterpreterError {
} }
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(); let mut reports = Vec::new();
for error in self.errors { for error in self.errors {
@ -170,8 +238,6 @@ impl InterpreterError {
} => { } => {
let TypeConflict { actual, expected } = conflict; let TypeConflict { actual, expected } = conflict;
builder = builder.with_message("A type conflict was found.");
builder.add_labels([ builder.add_labels([
Label::new(( Label::new((
self.source_id.clone(), self.source_id.clone(),
@ -257,46 +323,3 @@ impl InterpreterError {
reports 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::{ use crate::{
abstract_tree::*, abstract_tree::*,
built_in_functions::BuiltInFunction,
error::Error, error::Error,
lexer::{BuiltInIdentifier, Control, Keyword, Operator, Token}, lexer::{Control, Keyword, Operator, Token},
}; };
pub type ParserInput<'src> = pub type ParserInput<'src> =
@ -256,11 +255,8 @@ pub fn parser<'src>() -> impl Parser<
let built_in_function = { let built_in_function = {
select! { select! {
Token::BuiltInIdentifier(built_in_identifier) => { Token::BuiltInFunction(built_in_function) => built_in_function,
match built_in_identifier {BuiltInIdentifier::ReadLine=>BuiltInFunction::ReadLine,BuiltInIdentifier::WriteLine=>BuiltInFunction::WriteLine, }
BuiltInIdentifier::Sleep => BuiltInFunction::Sleep, }
}
}
} }
.map_with(|built_in_function, state| { .map_with(|built_in_function, state| {
Expression::Value(ValueNode::BuiltInFunction(built_in_function)) Expression::Value(ValueNode::BuiltInFunction(built_in_function))
@ -582,7 +578,7 @@ pub fn parser<'src>() -> impl Parser<
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::lexer::lex; use crate::{built_in_functions::BuiltInFunction, lexer::lex};
use super::*; use super::*;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,3 @@
use std::rc::Rc;
use dust_lang::{ use dust_lang::{
abstract_tree::{Block, Expression, Identifier, Statement, Type, WithPos}, abstract_tree::{Block, Expression, Identifier, Statement, Type, WithPos},
error::{Error, TypeConflict, ValidationError}, error::{Error, TypeConflict, ValidationError},
@ -9,7 +7,7 @@ use dust_lang::{
#[test] #[test]
fn set_and_get_variable() { fn set_and_get_variable() {
assert_eq!( assert_eq!(
interpret(Rc::new("test".to_string()), "foobar = true; foobar"), interpret("test", "foobar = true; foobar"),
Ok(Some(Value::boolean(true))) Ok(Some(Value::boolean(true)))
); );
} }
@ -17,7 +15,7 @@ fn set_and_get_variable() {
#[test] #[test]
fn set_variable_with_type() { fn set_variable_with_type() {
assert_eq!( assert_eq!(
interpret(Rc::new("test".to_string()), "foobar: bool = true; foobar"), interpret("test", "foobar: bool = true; foobar"),
Ok(Some(Value::boolean(true))) Ok(Some(Value::boolean(true)))
); );
} }
@ -25,7 +23,7 @@ fn set_variable_with_type() {
#[test] #[test]
fn set_variable_with_type_error() { fn set_variable_with_type_error() {
assert_eq!( assert_eq!(
interpret(Rc::new("test".to_string()), "foobar: str = true") interpret("test", "foobar: str = true")
.unwrap_err() .unwrap_err()
.errors(), .errors(),
&vec![Error::Validation { &vec![Error::Validation {
@ -45,10 +43,7 @@ fn set_variable_with_type_error() {
#[test] #[test]
fn function_variable() { fn function_variable() {
assert_eq!( assert_eq!(
interpret( interpret("test", "foobar = (x: int) int { x }; foobar"),
Rc::new("test".to_string()),
"foobar = (x: int) int { x }; foobar"
),
Ok(Some(Value::function( Ok(Some(Value::function(
Vec::with_capacity(0), Vec::with_capacity(0),
vec![(Identifier::new("x"), Type::Integer.with_position((13, 16)))], 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; 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 { match run_result {
Ok(Some(value)) => { Ok(Some(value)) => {
@ -88,12 +89,11 @@ pub fn run_shell(context: Context) -> Result<(), io::Error> {
} }
Ok(None) => {} Ok(None) => {}
Err(error) => { Err(error) => {
let source_id = Rc::new("input".to_string());
let reports = error.build_reports(); let reports = error.build_reports();
for report in reports { for report in reports {
report report
.write_for_stdout(sources([(source_id.clone(), &buffer)]), stderr()) .write_for_stdout(sources(interpreter.sources()), stderr())
.unwrap(); .unwrap();
} }
} }

View File

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