From 004b7be27a3351aeacf2f7133c5134d546bf8d35 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 23 Mar 2024 11:24:25 -0400 Subject: [PATCH] Implement better standard library interface --- dust-lang/src/built_in_functions.rs | 60 +++++++++++----------- dust-lang/src/context.rs | 16 +++--- dust-lang/src/error.rs | 2 - dust-lang/src/lexer.rs | 80 +++++++++++++++++++++-------- dust-lang/src/lib.rs | 2 +- dust-lang/src/parser.rs | 28 ++++++---- dust-lang/src/value.rs | 2 +- dust-lang/tests/structs.rs | 3 +- std/io.ds | 4 +- 9 files changed, 116 insertions(+), 81 deletions(-) diff --git a/dust-lang/src/built_in_functions.rs b/dust-lang/src/built_in_functions.rs index 54ce561..05ea6a0 100644 --- a/dust-lang/src/built_in_functions.rs +++ b/dust-lang/src/built_in_functions.rs @@ -16,17 +16,17 @@ use crate::{ }; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub struct BuiltInFunction { - name: WithPosition, +pub enum BuiltInFunction { + ReadLine, + WriteLine, } impl BuiltInFunction { - pub fn new(name: WithPosition) -> Self { - Self { name } - } - - pub fn name(&self) -> &Identifier { - &self.name.node + pub fn name(&self) -> &'static str { + match self { + BuiltInFunction::ReadLine => todo!(), + BuiltInFunction::WriteLine => todo!(), + } } pub fn as_value(self) -> Value { @@ -34,8 +34,8 @@ impl BuiltInFunction { } pub fn r#type(&self) -> Type { - match self.name.node.as_str() { - "WRITE_LINE" => Type::Function { + match self { + BuiltInFunction::WriteLine => Type::Function { parameter_types: vec![Type::String], return_type: Box::new(Type::None), }, @@ -46,8 +46,8 @@ impl BuiltInFunction { } pub fn call(&self, arguments: Vec, context: &Context) -> Result { - match self.name.node.as_str() { - "INT_PARSE" => { + match self { + BuiltInFunction::ReadLine => { let string = arguments.get(0).unwrap(); if let ValueInner::String(_string) = string.inner().as_ref() { @@ -73,36 +73,36 @@ impl BuiltInFunction { )) } } - "INT_RANDOM_RANGE" => { - let range = arguments.get(0).unwrap(); + // "INT_RANDOM_RANGE" => { + // let range = arguments.get(0).unwrap(); - if let ValueInner::Range(range) = range.inner().as_ref() { - let random = thread_rng().gen_range(range.clone()); + // if let ValueInner::Range(range) = range.inner().as_ref() { + // let random = thread_rng().gen_range(range.clone()); - Ok(Action::Return(Value::integer(random))) - } else { - panic!("Built-in function cannot have a non-function type.") - } - } - "READ_LINE" => { + // Ok(Action::Return(Value::integer(random))) + // } else { + // panic!("Built-in function cannot have a non-function type.") + // } + // } + BuiltInFunction::ReadLine => { let mut input = String::new(); stdin().read_line(&mut input)?; Ok(Action::Return(Value::string(input))) } - "WRITE_LINE" => { + BuiltInFunction::WriteLine => { println!("{}", arguments[0]); Ok(Action::None) } - "SLEEP" => { - if let ValueInner::Integer(milliseconds) = arguments[0].inner().as_ref() { - thread::sleep(Duration::from_millis(*milliseconds as u64)); - } + // "SLEEP" => { + // if let ValueInner::Integer(milliseconds) = arguments[0].inner().as_ref() { + // thread::sleep(Duration::from_millis(*milliseconds as u64)); + // } - Ok(Action::None) - } + // Ok(Action::None) + // } _ => { todo!() } @@ -112,6 +112,6 @@ impl BuiltInFunction { impl Display for BuiltInFunction { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}", self.name.node) + write!(f, "{}", self.name()) } } diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 8e01586..c23c984 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -1,6 +1,6 @@ use std::{ collections::BTreeMap, - sync::{Arc, OnceLock, RwLock, RwLockReadGuard}, + sync::{Arc, RwLock, RwLockReadGuard}, }; use crate::{ @@ -9,17 +9,13 @@ use crate::{ Interpreter, Value, }; -static STD_CONTEXT: OnceLock = OnceLock::new(); +pub fn std_context() -> Context { + let context = Context::new(); + let mut interpreter = Interpreter::new(context.clone()); -pub fn std_context<'a>() -> &'a Context { - STD_CONTEXT.get_or_init(|| { - let context = Context::new(); - let mut interpreter = Interpreter::new(context.clone()); + interpreter.run(include_str!("../../std/io.ds")).unwrap(); - interpreter.run(include_str!("../../std/io.ds")).unwrap(); - - context - }) + context } #[derive(Clone, Debug)] diff --git a/dust-lang/src/error.rs b/dust-lang/src/error.rs index 99f3c4f..bc73360 100644 --- a/dust-lang/src/error.rs +++ b/dust-lang/src/error.rs @@ -200,7 +200,6 @@ impl Error { ValidationError::ExpectedValue(_) => todo!(), ValidationError::PropertyNotFound { .. } => todo!(), ValidationError::WrongArguments { .. } => todo!(), - ValidationError::TypeNotFound(_) => todo!(), } } @@ -317,7 +316,6 @@ pub enum ValidationError { actual: Vec, }, VariableNotFound(Identifier), - TypeNotFound(Identifier), PropertyNotFound { identifier: Identifier, position: SourcePosition, diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index 444d38c..dcc13db 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -1,4 +1,7 @@ -use std::fmt::{self, Display, Formatter}; +use std::{ + f64::{INFINITY, NAN, NEG_INFINITY}, + fmt::{self, Display, Formatter}, +}; use chumsky::prelude::*; @@ -7,6 +10,7 @@ use crate::error::Error; #[derive(Copy, Clone, Debug, PartialEq)] pub enum Token<'src> { Boolean(bool), + BuiltInIdentifier(BuiltInIdentifier), Integer(i64), Float(f64), String(&'src str), @@ -16,6 +20,37 @@ pub enum Token<'src> { Keyword(Keyword), } +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::Integer(integer) => write!(f, "{integer}"), + Token::Float(float) => write!(f, "{float}"), + Token::String(string) => write!(f, "{string}"), + Token::Identifier(string) => write!(f, "{string}"), + Token::Operator(operator) => write!(f, "{operator}"), + Token::Control(control) => write!(f, "{control}"), + Token::Keyword(keyword) => write!(f, "{keyword}"), + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum BuiltInIdentifier { + ReadLine, + WriteLine, +} + +impl Display for BuiltInIdentifier { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + BuiltInIdentifier::ReadLine => write!(f, "__READ_LINE__"), + BuiltInIdentifier::WriteLine => write!(f, "__WRITE_LINE__"), + } + } +} + #[derive(Copy, Clone, Debug, PartialEq)] pub enum Keyword { Any, @@ -143,21 +178,6 @@ impl Display for Control { } } -impl<'src> Display for Token<'src> { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Token::Boolean(boolean) => write!(f, "{boolean}"), - Token::Integer(integer) => write!(f, "{integer}"), - Token::Float(float) => write!(f, "{float}"), - Token::String(string) => write!(f, "{string}"), - Token::Identifier(string) => write!(f, "{string}"), - Token::Operator(operator) => write!(f, "{operator}"), - Token::Control(control) => write!(f, "{control}"), - Token::Keyword(keyword) => write!(f, "{keyword}"), - } - } -} - pub fn lex<'src>(source: &'src str) -> Result, SimpleSpan)>, Vec> { lexer() .parse(source) @@ -184,17 +204,19 @@ pub fn lexer<'src>() -> impl Parser< .to_slice() .map(|text: &str| Token::Float(text.parse().unwrap())); - let float_other = choice((just("Infinity"), just("-Infinity"), just("NaN"))) - .map(|text| Token::Float(text.parse().unwrap())); - - let float = choice((float_numeric, float_other)); + let float = choice(( + float_numeric, + just("Infinity").to(Token::Float(INFINITY)), + just("-Infinity").to(Token::Float(NEG_INFINITY)), + just("NaN").to(Token::Float(NAN)), + )); let integer = just('-') .or_not() .then(text::int(10)) .to_slice() .map(|text: &str| { - let integer = text.parse::().unwrap(); + let integer = text.parse().unwrap(); Token::Integer(integer) }); @@ -278,8 +300,22 @@ pub fn lexer<'src>() -> impl Parser< )) .map(Token::Keyword); + let built_in_identifier = choice(( + just("__READ_LINE__").to(BuiltInIdentifier::ReadLine), + just("__WRITE_LINE__").to(BuiltInIdentifier::WriteLine), + )) + .map(Token::BuiltInIdentifier); + choice(( - boolean, float, integer, string, keyword, identifier, control, operator, + boolean, + float, + integer, + string, + keyword, + identifier, + control, + operator, + built_in_identifier, )) .map_with(|token, state| (token, state.span())) .padded() diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 5e4f197..ba5151e 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -13,7 +13,7 @@ use parser::parse; pub use value::Value; pub fn interpret(source: &str) -> Result, Vec> { - let mut interpreter = Interpreter::new(std_context().clone()); + let mut interpreter = Interpreter::new(std_context()); interpreter.run(source) } diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index ddeb32b..81c3f59 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -6,7 +6,7 @@ use crate::{ abstract_tree::*, built_in_functions::BuiltInFunction, error::Error, - lexer::{Control, Keyword, Operator, Token}, + lexer::{BuiltInIdentifier, Control, Keyword, Operator, Token}, }; pub type ParserInput<'src> = @@ -233,12 +233,20 @@ pub fn parser<'src>() -> impl Parser< .with_position(state.span()) }); - let built_in_function = just(Token::Control(Control::Dollar)) - .ignore_then(positioned_identifier.clone()) - .map_with(|identifier, state| { - Expression::Value(ValueNode::BuiltInFunction(BuiltInFunction::new(identifier))) - .with_position(state.span()) - }); + let built_in_function = { + select! { + Token::BuiltInIdentifier(built_in_identifier) => { + match built_in_identifier { + BuiltInIdentifier::ReadLine => BuiltInFunction::ReadLine, + BuiltInIdentifier::WriteLine => BuiltInFunction::WriteLine, + } + } + } + } + .map_with(|built_in_function, state| { + Expression::Value(ValueNode::BuiltInFunction(built_in_function)) + .with_position(state.span()) + }); let atom = choice(( built_in_function.clone(), @@ -535,11 +543,9 @@ mod tests { #[test] fn built_in_function() { assert_eq!( - parse(&lex("$READ_LINE").unwrap()).unwrap()[0].node, + parse(&lex("__READ_LINE__").unwrap()).unwrap()[0].node, Statement::Expression(Expression::Value(ValueNode::BuiltInFunction( - BuiltInFunction::new( - Identifier::new("READ_LINE".to_string()).with_position((1, 10)) - ) + BuiltInFunction::ReadLine ))) ) } diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 22bbed0..1c3bd54 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -230,7 +230,7 @@ impl ValueInner { if let Some(r#type) = context.get_type(name)? { r#type } else { - return Err(ValidationError::TypeNotFound(name.clone())); + return Err(ValidationError::VariableNotFound(name.clone())); } } }; diff --git a/dust-lang/tests/structs.rs b/dust-lang/tests/structs.rs index 11ca475..49b0cec 100644 --- a/dust-lang/tests/structs.rs +++ b/dust-lang/tests/structs.rs @@ -3,7 +3,6 @@ use dust_lang::{ error::{Error, TypeConflict, ValidationError}, *, }; - #[test] fn simple_structure() { assert_eq!( @@ -101,7 +100,7 @@ fn undefined_struct() { " ), Err(vec![Error::Validation { - error: error::ValidationError::TypeNotFound(Identifier::new("Foo")), + error: error::ValidationError::VariableNotFound(Identifier::new("Foo")), position: (17, 69).into() }]) ) diff --git a/std/io.ds b/std/io.ds index 5e94eac..74983fb 100644 --- a/std/io.ds +++ b/std/io.ds @@ -1,9 +1,9 @@ io = { read_line = () : str { - $READ_LINE() + __READ_LINE__() } write_line = (output: str) : none { - $WRITE_LINE(output) + __WRITE_LINE__(output) } }