From 9bb4e1b94478ac05fed4316f61967e7bd2747927 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 23 Mar 2024 08:15:48 -0400 Subject: [PATCH] Begin standard library --- dust-lang/src/abstract_tree/map_index.rs | 4 +- dust-lang/src/abstract_tree/mod.rs | 1 - dust-lang/src/built_in_functions.rs | 123 ++++++++++++ dust-lang/src/context.rs | 43 +---- dust-lang/src/lib.rs | 11 ++ dust-lang/src/value.rs | 234 +---------------------- dust-shell/src/main.rs | 6 +- std/io.ds | 9 + 8 files changed, 154 insertions(+), 277 deletions(-) create mode 100644 dust-lang/src/built_in_functions.rs create mode 100644 std/io.ds diff --git a/dust-lang/src/abstract_tree/map_index.rs b/dust-lang/src/abstract_tree/map_index.rs index 80c0845..ba31f5a 100644 --- a/dust-lang/src/abstract_tree/map_index.rs +++ b/dust-lang/src/abstract_tree/map_index.rs @@ -20,8 +20,6 @@ impl MapIndex { impl AbstractNode for MapIndex { fn expected_type(&self, context: &Context) -> Result { - let left_type = self.left.node.expected_type(context)?; - if let ( Expression::Identifier(collection_identifier), Expression::Identifier(index_identifier), @@ -72,7 +70,7 @@ impl AbstractNode for MapIndex { } Err(ValidationError::CannotIndexWith { - collection_type: left_type, + collection_type: self.left.node.expected_type(context)?, collection_position: self.left.position, index_type: self.right.node.expected_type(context)?, index_position: self.right.position, diff --git a/dust-lang/src/abstract_tree/mod.rs b/dust-lang/src/abstract_tree/mod.rs index 6c01f6e..95c62fc 100644 --- a/dust-lang/src/abstract_tree/mod.rs +++ b/dust-lang/src/abstract_tree/mod.rs @@ -84,7 +84,6 @@ impl AbstractTree { (_, _) => Ordering::Equal, }); - println!("{:?}", statements); AbstractTree(statements) } diff --git a/dust-lang/src/built_in_functions.rs b/dust-lang/src/built_in_functions.rs new file mode 100644 index 0000000..45cc136 --- /dev/null +++ b/dust-lang/src/built_in_functions.rs @@ -0,0 +1,123 @@ +use core::fmt; +use std::{ + fmt::{Display, Formatter}, + io::stdin, + thread, + time::Duration, +}; + +use rand::{thread_rng, Rng}; + +use crate::{ + abstract_tree::{Action, Type}, + context::Context, + error::{RuntimeError, ValidationError}, + value::ValueInner, + Value, +}; + +pub const BUILT_IN_FUNCTIONS: [BuiltInFunction; 5] = [ + BuiltInFunction::IntParse, + BuiltInFunction::IntRandomRange, + BuiltInFunction::ReadLine, + BuiltInFunction::WriteLine, + BuiltInFunction::Sleep, +]; + +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub enum BuiltInFunction { + IntParse, + IntRandomRange, + ReadLine, + WriteLine, + Sleep, +} + +impl BuiltInFunction { + pub fn name(&self) -> &'static str { + match self { + BuiltInFunction::IntParse => "parse", + BuiltInFunction::IntRandomRange => "random_range", + BuiltInFunction::ReadLine => "read_line", + BuiltInFunction::WriteLine => "write_line", + BuiltInFunction::Sleep => "sleep", + } + } + + pub fn as_value(self) -> Value { + Value::built_in_function(self) + } + + pub fn call(&self, arguments: Vec, context: &Context) -> Result { + match self { + BuiltInFunction::IntParse => { + let string = arguments.get(0).unwrap(); + + if let ValueInner::String(_string) = string.inner().as_ref() { + // let integer = string.parse(); + + todo!() + + // Ok(Action::Return(Value::integer(integer))) + } else { + let mut actual = Vec::with_capacity(arguments.len()); + + for value in arguments { + let r#type = value.r#type(context)?; + + actual.push(r#type); + } + + Err(RuntimeError::ValidationFailure( + ValidationError::WrongArguments { + expected: vec![Type::String], + actual, + }, + )) + } + } + BuiltInFunction::IntRandomRange => { + let range = arguments.get(0).unwrap(); + + 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.") + } + } + BuiltInFunction::ReadLine => { + let mut input = String::new(); + + stdin().read_line(&mut input)?; + + Ok(Action::Return(Value::string(input))) + } + BuiltInFunction::WriteLine => { + println!("{}", arguments[0]); + + Ok(Action::None) + } + BuiltInFunction::Sleep => { + if let ValueInner::Integer(milliseconds) = arguments[0].inner().as_ref() { + thread::sleep(Duration::from_millis(*milliseconds as u64)); + } + + Ok(Action::None) + } + } + } +} + +impl Display for BuiltInFunction { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + BuiltInFunction::IntParse => write!(f, "(input : int) : str {{ *MAGIC* }}"), + BuiltInFunction::IntRandomRange => write!(f, "(input: range) : int {{ *MAGIC* }}"), + BuiltInFunction::ReadLine => write!(f, "() : str {{ *MAGIC* }}"), + BuiltInFunction::WriteLine => write!(f, "(to_output : any) : none {{ *MAGIC* }}"), + BuiltInFunction::Sleep => write!(f, "(milliseconds : int) : none {{ *MAGIC* }}"), + } + } +} diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 1ff04e9..56b7a16 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -6,7 +6,6 @@ use std::{ use crate::{ abstract_tree::{Identifier, Type}, error::{RwLockPoisonError, ValidationError}, - value::{BUILT_IN_FUNCTIONS, BUILT_IN_MODULES}, Value, }; @@ -60,18 +59,6 @@ impl Context { if self.inner.read()?.contains_key(identifier) { Ok(true) } else { - for module in BUILT_IN_MODULES { - if identifier.as_str() == module.name() { - return Ok(true); - } - } - - for function in BUILT_IN_FUNCTIONS { - if identifier.as_str() == function.name() { - return Ok(true); - } - } - Ok(false) } } @@ -83,40 +70,16 @@ impl Context { ValueData::Value(value) => value.r#type(self)?, }; - return Ok(Some(r#type.clone())); + Ok(Some(r#type.clone())) + } else { + Ok(None) } - - for module in BUILT_IN_MODULES { - if identifier.as_str() == module.name() { - return Ok(Some(module.r#type())); - } - } - - for function in BUILT_IN_MODULES { - if identifier.as_str() == function.name() { - return Ok(Some(function.r#type())); - } - } - - Ok(None) } pub fn get_value(&self, identifier: &Identifier) -> Result, RwLockPoisonError> { if let Some(ValueData::Value(value)) = self.inner.read()?.get(identifier) { Ok(Some(value.clone())) } else { - for module in BUILT_IN_MODULES { - if identifier.as_str() == module.name() { - return Ok(Some(module.value())); - } - } - - for function in BUILT_IN_MODULES { - if identifier.as_str() == function.name() { - return Ok(Some(function.value())); - } - } - Ok(None) } } diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 01b346a..e67d8ac 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -1,10 +1,13 @@ pub mod abstract_tree; +pub mod built_in_functions; pub mod context; pub mod error; pub mod lexer; pub mod parser; pub mod value; +use abstract_tree::Identifier; +use built_in_functions::BUILT_IN_FUNCTIONS; use context::Context; use error::Error; use lexer::lex; @@ -13,8 +16,16 @@ pub use value::Value; pub fn interpret(source: &str) -> Result, Vec> { let context = Context::new(); + + for function in BUILT_IN_FUNCTIONS { + context + .set_value(Identifier::new(function.name()), function.as_value()) + .unwrap(); + } + let mut interpreter = Interpreter::new(context); + interpreter.run(include_str!("../../std/io.ds"))?; interpreter.run(source) } diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 8439af6..0d76a55 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -2,14 +2,10 @@ use std::{ cmp::Ordering, collections::BTreeMap, fmt::{self, Display, Formatter}, - io::stdin, ops::Range, - sync::{Arc, OnceLock}, - thread, - time::Duration, + sync::Arc, }; -use rand::{thread_rng, Rng}; use stanza::{ renderer::{console::Console, Renderer}, style::{HAlign, MinWidth, Styles}, @@ -18,6 +14,7 @@ use stanza::{ use crate::{ abstract_tree::{AbstractNode, Action, Block, Identifier, Type, WithPosition}, + built_in_functions::BuiltInFunction, context::Context, error::{RuntimeError, ValidationError}, }; @@ -225,7 +222,9 @@ impl ValueInner { .collect(), return_type: Box::new(parsed_function.return_type.node.clone()), }, - Function::BuiltIn(built_in_function) => built_in_function.r#type(), + Function::BuiltIn(built_in_function) => { + (*built_in_function).as_value().r#type(context)? + } }, ValueInner::Structure { name, .. } => { if let Some(r#type) = context.get_type(name)? { @@ -331,226 +330,3 @@ pub struct ParsedFunction { return_type: WithPosition, body: WithPosition, } - -static INT_PARSE: OnceLock = OnceLock::new(); -static INT_RANDOM_RANGE: OnceLock = OnceLock::new(); -static READ_LINE: OnceLock = OnceLock::new(); -static WRITE_LINE: OnceLock = OnceLock::new(); -static SLEEP: OnceLock = OnceLock::new(); - -pub const BUILT_IN_FUNCTIONS: [BuiltInFunction; 5] = [ - BuiltInFunction::IntParse, - BuiltInFunction::IntRandomRange, - BuiltInFunction::ReadLine, - BuiltInFunction::WriteLine, - BuiltInFunction::Sleep, -]; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub enum BuiltInFunction { - IntParse, - IntRandomRange, - ReadLine, - WriteLine, - Sleep, -} - -impl BuiltInFunction { - pub fn name(&self) -> &'static str { - match self { - BuiltInFunction::IntParse => "parse", - BuiltInFunction::IntRandomRange => "random_range", - BuiltInFunction::ReadLine => "read_line", - BuiltInFunction::WriteLine => "write_line", - BuiltInFunction::Sleep => "sleep", - } - } - - pub fn value(&self) -> Value { - match self { - BuiltInFunction::IntParse => { - INT_PARSE.get_or_init(|| Value::built_in_function(BuiltInFunction::IntParse)) - } - BuiltInFunction::IntRandomRange => INT_RANDOM_RANGE - .get_or_init(|| Value::built_in_function(BuiltInFunction::IntRandomRange)), - BuiltInFunction::ReadLine => { - READ_LINE.get_or_init(|| Value::built_in_function(BuiltInFunction::ReadLine)) - } - BuiltInFunction::WriteLine => { - WRITE_LINE.get_or_init(|| Value::built_in_function(BuiltInFunction::WriteLine)) - } - BuiltInFunction::Sleep => { - SLEEP.get_or_init(|| Value::built_in_function(BuiltInFunction::Sleep)) - } - } - .clone() - } - - pub fn r#type(&self) -> Type { - match self { - BuiltInFunction::IntParse => Type::Function { - parameter_types: vec![Type::String], - return_type: Box::new(Type::Integer), - }, - BuiltInFunction::IntRandomRange => Type::Function { - parameter_types: vec![Type::Range], - return_type: Box::new(Type::Integer), - }, - BuiltInFunction::ReadLine => Type::Function { - parameter_types: Vec::with_capacity(0), - return_type: Box::new(Type::String), - }, - BuiltInFunction::WriteLine => Type::Function { - parameter_types: vec![Type::Any], - return_type: Box::new(Type::None), - }, - BuiltInFunction::Sleep => Type::Function { - parameter_types: vec![Type::Integer], - return_type: Box::new(Type::None), - }, - } - } - - pub fn call(&self, arguments: Vec, context: &Context) -> Result { - match self { - BuiltInFunction::IntParse => { - let string = arguments.get(0).unwrap(); - - if let ValueInner::String(_string) = string.inner().as_ref() { - // let integer = string.parse(); - - todo!() - - // Ok(Action::Return(Value::integer(integer))) - } else { - let mut actual = Vec::with_capacity(arguments.len()); - - for value in arguments { - let r#type = value.r#type(context)?; - - actual.push(r#type); - } - - Err(RuntimeError::ValidationFailure( - ValidationError::WrongArguments { - expected: vec![Type::String], - actual, - }, - )) - } - } - BuiltInFunction::IntRandomRange => { - let range = arguments.get(0).unwrap(); - - 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.") - } - } - BuiltInFunction::ReadLine => { - let mut input = String::new(); - - stdin().read_line(&mut input)?; - - Ok(Action::Return(Value::string(input))) - } - BuiltInFunction::WriteLine => { - println!("{}", arguments[0]); - - Ok(Action::None) - } - BuiltInFunction::Sleep => { - if let ValueInner::Integer(milliseconds) = arguments[0].inner().as_ref() { - thread::sleep(Duration::from_millis(*milliseconds as u64)); - } - - Ok(Action::None) - } - } - } -} - -impl Display for BuiltInFunction { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - BuiltInFunction::IntParse => write!(f, "(input : int) : str {{ *MAGIC* }}"), - BuiltInFunction::IntRandomRange => write!(f, "(input: range) : int {{ *MAGIC* }}"), - BuiltInFunction::ReadLine => write!(f, "() : str {{ *MAGIC* }}"), - BuiltInFunction::WriteLine => write!(f, "(to_output : any) : none {{ *MAGIC* }}"), - BuiltInFunction::Sleep => write!(f, "(milliseconds : int) : none {{ *MAGIC* }}"), - } - } -} - -static INT: OnceLock = OnceLock::new(); -static IO: OnceLock = OnceLock::new(); -static THREAD: OnceLock = OnceLock::new(); - -pub const BUILT_IN_MODULES: [BuiltInModule; 3] = - [BuiltInModule::Int, BuiltInModule::Io, BuiltInModule::Thread]; - -pub enum BuiltInModule { - Int, - Io, - Thread, -} - -impl BuiltInModule { - pub fn name(&self) -> &'static str { - match self { - BuiltInModule::Int => "int", - BuiltInModule::Io => "io", - BuiltInModule::Thread => "thread", - } - } - - pub fn value(self) -> Value { - match self { - BuiltInModule::Int => { - let mut properties = BTreeMap::new(); - - properties.insert( - Identifier::new("parse"), - Value::built_in_function(BuiltInFunction::IntParse), - ); - properties.insert( - Identifier::new("random_range"), - Value::built_in_function(BuiltInFunction::IntRandomRange), - ); - - INT.get_or_init(|| Value::map(properties)).clone() - } - BuiltInModule::Io => { - let mut properties = BTreeMap::new(); - - properties.insert( - Identifier::new("read_line"), - Value::built_in_function(BuiltInFunction::ReadLine), - ); - properties.insert( - Identifier::new("write_line"), - Value::built_in_function(BuiltInFunction::WriteLine), - ); - - IO.get_or_init(|| Value::map(properties)).clone() - } - BuiltInModule::Thread => { - let mut properties = BTreeMap::new(); - - properties.insert( - Identifier::new("sleep"), - Value::built_in_function(BuiltInFunction::Sleep), - ); - - THREAD.get_or_init(|| Value::map(properties)).clone() - } - } - } - - pub fn r#type(self) -> Type { - Type::Map - } -} diff --git a/dust-shell/src/main.rs b/dust-shell/src/main.rs index 86daaed..5282191 100644 --- a/dust-shell/src/main.rs +++ b/dust-shell/src/main.rs @@ -10,7 +10,7 @@ use std::{ io::{stderr, Write}, }; -use dust_lang::{context::Context, Interpreter}; +use dust_lang::{context::Context, interpret}; /// Command-line arguments to be parsed. #[derive(Parser, Debug)] @@ -46,9 +46,7 @@ fn main() { return run_shell(context); }; - let mut interpreter = Interpreter::new(context); - - let eval_result = interpreter.run(&source); + let eval_result = interpret(&source); match eval_result { Ok(value) => { diff --git a/std/io.ds b/std/io.ds new file mode 100644 index 0000000..05827c4 --- /dev/null +++ b/std/io.ds @@ -0,0 +1,9 @@ +io = { + read_line = () : str { + read_line() + } + + write_line = (output: str) : none { + write_line(output) + } +}