diff --git a/dust-lang/src/abstract_tree/map_index.rs b/dust-lang/src/abstract_tree/map_index.rs index 5a08c7e..ba31f5a 100644 --- a/dust-lang/src/abstract_tree/map_index.rs +++ b/dust-lang/src/abstract_tree/map_index.rs @@ -111,8 +111,6 @@ impl AbstractNode for MapIndex { if let (ValueInner::Map(map), Expression::Identifier(identifier)) = (collection.inner().as_ref(), &self.right.node) { - println!("{map:?} {identifier}"); - let action = map .get(identifier) .map(|value| Action::Return(value.clone())) diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index 0ff4bf3..407f54c 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -1,6 +1,7 @@ use std::{cmp::Ordering, collections::BTreeMap, ops::Range}; use crate::{ + built_in_functions::BuiltInFunction, context::Context, error::{RuntimeError, ValidationError}, Value, @@ -11,6 +12,7 @@ use super::{AbstractNode, Action, Block, Expression, Identifier, Type, WithPosit #[derive(Clone, Debug, PartialEq)] pub enum ValueNode { Boolean(bool), + BuiltInFunction(BuiltInFunction), Float(f64), Integer(i64), List(Vec>), @@ -27,7 +29,7 @@ pub enum ValueNode { name: Identifier, fields: Vec<(Identifier, WithPosition)>, }, - Function { + ParsedFunction { parameters: Vec<(Identifier, WithPosition)>, return_type: WithPosition, body: WithPosition, @@ -35,7 +37,7 @@ pub enum ValueNode { } impl AbstractNode for ValueNode { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, context: &Context) -> Result { let r#type = match self { ValueNode::Boolean(_) => Type::Boolean, ValueNode::Float(_) => Type::Float, @@ -44,7 +46,7 @@ impl AbstractNode for ValueNode { let mut item_types = Vec::with_capacity(items.len()); for expression in items { - item_types.push(expression.node.expected_type(_context)?); + item_types.push(expression.node.expected_type(context)?); } Type::ListExact(item_types) @@ -52,7 +54,7 @@ impl AbstractNode for ValueNode { ValueNode::Map(_) => Type::Map, ValueNode::Range(_) => Type::Range, ValueNode::String(_) => Type::String, - ValueNode::Function { + ValueNode::ParsedFunction { parameters, return_type, .. @@ -70,7 +72,7 @@ impl AbstractNode for ValueNode { let mut types = Vec::with_capacity(expressions.len()); for (identifier, expression) in expressions { - let r#type = expression.node.expected_type(_context)?; + let r#type = expression.node.expected_type(context)?; types.push(( identifier.clone(), @@ -86,6 +88,7 @@ impl AbstractNode for ValueNode { fields: types, } } + ValueNode::BuiltInFunction(built_in_function) => built_in_function.r#type(), }; Ok(r#type) @@ -108,7 +111,7 @@ impl AbstractNode for ValueNode { } } - if let ValueNode::Function { + if let ValueNode::ParsedFunction { parameters, return_type, body, @@ -141,30 +144,22 @@ impl AbstractNode for ValueNode { fields: expressions, } = self { - let types = if let Some(r#type) = context.get_type(name)? { - if let Type::Structure { - name: _, - fields: types, - } = r#type - { - types - } else { - todo!() + if let Type::Structure { + name: _, + fields: types, + } = name.expected_type(context)? + { + for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) { + let actual_type = expression.node.expected_type(context)?; + + expected_type.node.check(&actual_type).map_err(|conflict| { + ValidationError::TypeCheck { + conflict, + actual_position: expression.position, + expected_position: expected_type.position, + } + })? } - } else { - return Err(ValidationError::TypeNotFound(name.clone())); - }; - - for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) { - let actual_type = expression.node.expected_type(context)?; - - expected_type.node.check(&actual_type).map_err(|conflict| { - ValidationError::TypeCheck { - conflict, - actual_position: expression.position, - expected_position: expected_type.position, - } - })? } } @@ -214,7 +209,7 @@ impl AbstractNode for ValueNode { } ValueNode::Range(range) => Value::range(range), ValueNode::String(string) => Value::string(string), - ValueNode::Function { + ValueNode::ParsedFunction { parameters, return_type, body, @@ -240,6 +235,9 @@ impl AbstractNode for ValueNode { Value::structure(name, fields) } + ValueNode::BuiltInFunction(built_in_function) => { + Value::built_in_function(built_in_function) + } }; Ok(Action::Return(value)) @@ -282,12 +280,12 @@ impl Ord for ValueNode { (String(left), String(right)) => left.cmp(right), (String(_), _) => Ordering::Greater, ( - Function { + ParsedFunction { parameters: left_parameters, return_type: left_return, body: left_body, }, - Function { + ParsedFunction { parameters: right_parameters, return_type: right_return, body: right_body, @@ -307,7 +305,7 @@ impl Ord for ValueNode { parameter_cmp } } - (Function { .. }, _) => Ordering::Greater, + (ParsedFunction { .. }, _) => Ordering::Greater, ( Structure { name: left_name, @@ -327,6 +325,8 @@ impl Ord for ValueNode { } } (Structure { .. }, _) => Ordering::Greater, + (BuiltInFunction(_), BuiltInFunction(_)) => todo!(), + (BuiltInFunction(_), _) => todo!(), } } } diff --git a/dust-lang/src/built_in_functions.rs b/dust-lang/src/built_in_functions.rs index 45cc136..54ce561 100644 --- a/dust-lang/src/built_in_functions.rs +++ b/dust-lang/src/built_in_functions.rs @@ -1,6 +1,5 @@ -use core::fmt; use std::{ - fmt::{Display, Formatter}, + fmt::{self, Display, Formatter}, io::stdin, thread, time::Duration, @@ -9,48 +8,46 @@ use std::{ use rand::{thread_rng, Rng}; use crate::{ - abstract_tree::{Action, Type}, + abstract_tree::{Action, Identifier, Type, WithPosition}, 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, +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct BuiltInFunction { + name: WithPosition, } 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 new(name: WithPosition) -> Self { + Self { name } + } + + pub fn name(&self) -> &Identifier { + &self.name.node } pub fn as_value(self) -> Value { Value::built_in_function(self) } + pub fn r#type(&self) -> Type { + match self.name.node.as_str() { + "WRITE_LINE" => Type::Function { + parameter_types: vec![Type::String], + return_type: Box::new(Type::None), + }, + _ => { + todo!() + } + } + } + pub fn call(&self, arguments: Vec, context: &Context) -> Result { - match self { - BuiltInFunction::IntParse => { + match self.name.node.as_str() { + "INT_PARSE" => { let string = arguments.get(0).unwrap(); if let ValueInner::String(_string) = string.inner().as_ref() { @@ -76,7 +73,7 @@ impl BuiltInFunction { )) } } - BuiltInFunction::IntRandomRange => { + "INT_RANDOM_RANGE" => { let range = arguments.get(0).unwrap(); if let ValueInner::Range(range) = range.inner().as_ref() { @@ -87,37 +84,34 @@ impl BuiltInFunction { panic!("Built-in function cannot have a non-function type.") } } - BuiltInFunction::ReadLine => { + "READ_LINE" => { let mut input = String::new(); stdin().read_line(&mut input)?; Ok(Action::Return(Value::string(input))) } - BuiltInFunction::WriteLine => { + "WRITE_LINE" => { println!("{}", arguments[0]); Ok(Action::None) } - BuiltInFunction::Sleep => { + "SLEEP" => { if let ValueInner::Integer(milliseconds) = arguments[0].inner().as_ref() { thread::sleep(Duration::from_millis(*milliseconds as u64)); } Ok(Action::None) } + _ => { + todo!() + } } } } 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* }}"), - } + write!(f, "{}", self.name.node) } } diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 24d0726..8e01586 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -5,7 +5,6 @@ use std::{ use crate::{ abstract_tree::{Identifier, Type}, - built_in_functions::BUILT_IN_FUNCTIONS, error::{RwLockPoisonError, ValidationError}, Interpreter, Value, }; @@ -14,22 +13,11 @@ static STD_CONTEXT: OnceLock = OnceLock::new(); pub fn std_context<'a>() -> &'a Context { STD_CONTEXT.get_or_init(|| { - let mut data = BTreeMap::new(); - - for function in BUILT_IN_FUNCTIONS { - data.insert( - Identifier::new(function.name()), - ValueData::Value(function.as_value()), - ); - } - - let context = Context::with_data(data); + let context = Context::new(); let mut interpreter = Interpreter::new(context.clone()); interpreter.run(include_str!("../../std/io.ds")).unwrap(); - context.remove(&Identifier::new("write_line")).unwrap(); - context }) } diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index 5a7da6c..444d38c 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -116,6 +116,7 @@ pub enum Control { Comma, DoubleColon, Colon, + Dollar, Dot, DoubleDot, Semicolon, @@ -127,6 +128,7 @@ impl Display for Control { Control::Arrow => write!(f, "->"), Control::CurlyOpen => write!(f, "{{"), Control::CurlyClose => write!(f, "}}"), + Control::Dollar => write!(f, "$"), Control::SquareOpen => write!(f, "["), Control::SquareClose => write!(f, "]"), Control::ParenOpen => write!(f, "("), @@ -252,6 +254,7 @@ pub fn lexer<'src>() -> impl Parser< just(":").to(Control::Colon), just("..").to(Control::DoubleDot), just(".").to(Control::Dot), + just("$").to(Control::Dollar), )) .map(Token::Control); diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 0f5c455..ddeb32b 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -4,6 +4,7 @@ use chumsky::{input::SpannedInput, pratt::*, prelude::*}; use crate::{ abstract_tree::*, + built_in_functions::BuiltInFunction, error::Error, lexer::{Control, Keyword, Operator, Token}, }; @@ -212,7 +213,7 @@ pub fn parser<'src>() -> impl Parser< .with_position(state.span()) }); - let function = identifier + let parsed_function = identifier .clone() .then(type_specification.clone()) .separated_by(just(Token::Control(Control::Comma))) @@ -224,7 +225,7 @@ pub fn parser<'src>() -> impl Parser< .then(type_specification.clone()) .then(block.clone()) .map_with(|((parameters, return_type), body), state| { - Expression::Value(ValueNode::Function { + Expression::Value(ValueNode::ParsedFunction { parameters, return_type, body: body.with_position(state.span()), @@ -232,8 +233,16 @@ 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 atom = choice(( - function.clone(), + built_in_function.clone(), + parsed_function.clone(), identifier_expression.clone(), basic_value.clone(), list.clone(), @@ -406,7 +415,8 @@ pub fn parser<'src>() -> impl Parser< structure_instance, range, logic_math_indexes_and_function_calls, - function, + parsed_function, + built_in_function, list, map, basic_value, @@ -522,6 +532,18 @@ mod tests { use super::*; + #[test] + fn built_in_function() { + assert_eq!( + 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)) + ) + ))) + ) + } + #[test] fn async_block() { assert_eq!( @@ -756,7 +778,7 @@ mod tests { fn function() { assert_eq!( parse(&lex("(x: int) : int { x }").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Function { + Statement::Expression(Expression::Value(ValueNode::ParsedFunction { parameters: vec![(Identifier::new("x"), Type::Integer.with_position((4, 7)))], return_type: Type::Integer.with_position((11, 14)), body: Block::new(vec![Statement::Expression(Expression::Identifier( diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 0d76a55..22bbed0 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -223,7 +223,7 @@ impl ValueInner { return_type: Box::new(parsed_function.return_type.node.clone()), }, Function::BuiltIn(built_in_function) => { - (*built_in_function).as_value().r#type(context)? + built_in_function.clone().as_value().r#type(context)? } }, ValueInner::Structure { name, .. } => { diff --git a/std/io.ds b/std/io.ds index 05827c4..5e94eac 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) } }