1
0

Begin revising built-in functions

This commit is contained in:
Jeff 2024-04-21 17:00:08 -04:00
parent fe1e27fd70
commit fb78798a1d
10 changed files with 132 additions and 198 deletions

View File

@ -0,0 +1,35 @@
use std::{
fmt::{self, Display, Formatter},
io::stdin,
thread,
time::Duration,
};
use crate::{
abstract_tree::{Action, Type},
context::Context,
error::RuntimeError,
};
use super::{AbstractNode, Expression, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum BuiltInFunctionCall {
ReadLine,
Sleep(Expression),
WriteLine(Expression),
}
impl AbstractNode for BuiltInFunctionCall {
fn expected_type(&self, context: &Context) -> Result<Type, crate::error::ValidationError> {
todo!()
}
fn validate(&self, context: &Context) -> Result<(), crate::error::ValidationError> {
todo!()
}
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
todo!()
}
}

View File

@ -5,12 +5,13 @@ use crate::{
}; };
use super::{ use super::{
AbstractNode, Action, FunctionCall, ListIndex, Logic, MapIndex, Math, SourcePosition, Type, AbstractNode, Action, BuiltInFunctionCall, FunctionCall, ListIndex, Logic, MapIndex, Math,
ValueNode, WithPosition, SourcePosition, Type, ValueNode, WithPosition,
}; };
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Expression { pub enum Expression {
BuiltInFunctionCall(WithPosition<Box<BuiltInFunctionCall>>),
FunctionCall(WithPosition<FunctionCall>), FunctionCall(WithPosition<FunctionCall>),
Identifier(WithPosition<Identifier>), Identifier(WithPosition<Identifier>),
MapIndex(WithPosition<Box<MapIndex>>), MapIndex(WithPosition<Box<MapIndex>>),
@ -30,6 +31,7 @@ impl Expression {
Expression::Logic(inner) => inner.position, Expression::Logic(inner) => inner.position,
Expression::Math(inner) => inner.position, Expression::Math(inner) => inner.position,
Expression::Value(inner) => inner.position, Expression::Value(inner) => inner.position,
Expression::BuiltInFunctionCall(inner) => inner.position,
} }
} }
} }
@ -53,6 +55,7 @@ impl AbstractNode for Expression {
Expression::Logic(logic) => logic.node.expected_type(_context), Expression::Logic(logic) => logic.node.expected_type(_context),
Expression::Math(math) => math.node.expected_type(_context), Expression::Math(math) => math.node.expected_type(_context),
Expression::Value(value_node) => value_node.node.expected_type(_context), Expression::Value(value_node) => value_node.node.expected_type(_context),
Expression::BuiltInFunctionCall(_) => todo!(),
} }
} }
@ -74,6 +77,7 @@ impl AbstractNode for Expression {
Expression::Logic(logic) => logic.node.validate(context), Expression::Logic(logic) => logic.node.validate(context),
Expression::Math(math) => math.node.validate(context), Expression::Math(math) => math.node.validate(context),
Expression::Value(value_node) => value_node.node.validate(context), Expression::Value(value_node) => value_node.node.validate(context),
Expression::BuiltInFunctionCall(_) => todo!(),
} }
} }
@ -97,6 +101,7 @@ impl AbstractNode for Expression {
Expression::Logic(logic) => logic.node.run(_context), Expression::Logic(logic) => logic.node.run(_context),
Expression::Math(math) => math.node.run(_context), Expression::Math(math) => math.node.run(_context),
Expression::Value(value_node) => value_node.node.run(_context), Expression::Value(value_node) => value_node.node.run(_context),
Expression::BuiltInFunctionCall(_) => todo!(),
} }
} }
} }

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
value::{Function, ParsedFunction, ValueInner}, value::ValueInner,
}; };
use super::{AbstractNode, Action, Expression, Type, WithPosition}; use super::{AbstractNode, Action, Expression, Type, WithPosition};
@ -133,20 +133,16 @@ impl AbstractNode for FunctionCall {
let function_context = Context::new(); let function_context = Context::new();
if let Function::Parsed(ParsedFunction { for (type_parameter, type_argument) in function
type_parameters, .. .type_parameters()
}) = function .iter()
.map(|r#type| r#type.node.clone())
.zip(self.type_arguments.into_iter().map(|r#type| r#type.node))
{ {
for (type_parameter, type_argument) in type_parameters if let Type::Argument(identifier) = type_parameter {
.iter() function_context.set_type(identifier, type_argument)?;
.map(|r#type| r#type.node.clone())
.zip(self.type_arguments.into_iter().map(|r#type| r#type.node))
{
if let Type::Argument(identifier) = type_parameter {
function_context.set_type(identifier, type_argument)?;
}
} }
}; }
function_context.inherit_data_from(&context)?; function_context.inherit_data_from(&context)?;
function.clone().call(arguments, function_context) function.clone().call(arguments, function_context)

View File

@ -1,6 +1,7 @@
pub mod assignment; pub mod assignment;
pub mod async_block; pub mod async_block;
pub mod block; pub mod block;
pub mod built_in_function_call;
pub mod expression; pub mod expression;
pub mod function_call; pub mod function_call;
pub mod if_else; pub mod if_else;
@ -23,6 +24,7 @@ pub use self::{
assignment::{Assignment, AssignmentOperator}, assignment::{Assignment, AssignmentOperator},
async_block::AsyncBlock, async_block::AsyncBlock,
block::Block, block::Block,
built_in_function_call::BuiltInFunctionCall,
expression::Expression, expression::Expression,
function_call::FunctionCall, function_call::FunctionCall,
if_else::IfElse, if_else::IfElse,

View File

@ -1,7 +1,6 @@
use std::{cmp::Ordering, collections::BTreeMap, ops::Range}; use std::{cmp::Ordering, collections::BTreeMap, ops::Range};
use crate::{ use crate::{
built_in_functions::BuiltInFunction,
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
identifier::Identifier, identifier::Identifier,
@ -13,7 +12,6 @@ use super::{AbstractNode, Action, Block, Expression, Type, WithPos, WithPosition
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum ValueNode { pub enum ValueNode {
Boolean(bool), Boolean(bool),
BuiltInFunction(BuiltInFunction),
Float(f64), Float(f64),
Integer(i64), Integer(i64),
List(Vec<Expression>), List(Vec<Expression>),
@ -88,7 +86,6 @@ impl AbstractNode for ValueNode {
fields: types, fields: types,
} }
} }
ValueNode::BuiltInFunction(built_in_function) => built_in_function.r#type(),
}; };
Ok(r#type) Ok(r#type)
@ -260,9 +257,6 @@ impl AbstractNode for ValueNode {
Value::structure(name, fields) Value::structure(name, fields)
} }
ValueNode::BuiltInFunction(built_in_function) => {
Value::built_in_function(built_in_function)
}
}; };
Ok(Action::Return(value)) Ok(Action::Return(value))
@ -358,8 +352,6 @@ impl Ord for ValueNode {
} }
} }
(Structure { .. }, _) => Ordering::Greater, (Structure { .. }, _) => Ordering::Greater,
(BuiltInFunction(_), BuiltInFunction(_)) => todo!(),
(BuiltInFunction(_), _) => todo!(),
} }
} }
} }

View File

@ -1,88 +0,0 @@
use std::{
fmt::{self, Display, Formatter},
io::stdin,
thread,
time::Duration,
};
use crate::{
abstract_tree::{Action, Type, WithPos},
context::Context,
error::RuntimeError,
value::ValueInner,
Value,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum BuiltInFunction {
ReadLine,
Sleep,
WriteLine,
}
impl BuiltInFunction {
pub fn name(&self) -> &'static str {
match self {
BuiltInFunction::ReadLine => "__READ_LINE__",
BuiltInFunction::Sleep => "__SLEEP__",
BuiltInFunction::WriteLine => "__WRITE_LINE__",
}
}
pub fn as_value(self) -> Value {
Value::built_in_function(self)
}
pub fn r#type(&self) -> Type {
match self {
BuiltInFunction::WriteLine => Type::Function {
parameter_types: vec![Type::String.with_position((0, 0))],
return_type: Box::new(Type::None.with_position((0, 0))),
},
_ => {
todo!()
}
}
}
pub fn call(&self, arguments: Vec<Value>, _context: &Context) -> Result<Action, RuntimeError> {
match self {
// "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());
// 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::Sleep => {
if let ValueInner::Integer(milliseconds) = arguments[0].inner().as_ref() {
thread::sleep(Duration::from_millis(*milliseconds as u64));
}
Ok(Action::None)
}
BuiltInFunction::WriteLine => {
println!("{}", arguments[0]);
Ok(Action::None)
}
}
}
}
impl Display for BuiltInFunction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}

View File

@ -5,12 +5,11 @@ use std::{
use chumsky::prelude::*; use chumsky::prelude::*;
use crate::{built_in_functions::BuiltInFunction, error::Error}; use crate::error::Error;
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
pub enum Token<'src> { pub enum Token<'src> {
Boolean(bool), Boolean(bool),
BuiltInFunction(BuiltInFunction),
Integer(i64), Integer(i64),
Float(f64), Float(f64),
String(&'src str), String(&'src str),
@ -24,7 +23,6 @@ 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::BuiltInFunction(built_in_function) => write!(f, "{built_in_function}"),
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}"),
@ -51,11 +49,14 @@ pub enum Keyword {
Map, Map,
None, None,
Range, Range,
ReadLine,
Sleep,
Struct, Struct,
Str, Str,
Type, Type,
Loop, Loop,
While, While,
WriteLine,
} }
impl Display for Keyword { impl Display for Keyword {
@ -79,6 +80,9 @@ impl Display for Keyword {
Keyword::Loop => write!(f, "loop"), Keyword::Loop => write!(f, "loop"),
Keyword::While => write!(f, "while"), Keyword::While => write!(f, "while"),
Keyword::Type => write!(f, "type"), Keyword::Type => write!(f, "type"),
Keyword::ReadLine => write!(f, "READ_LINE"),
Keyword::Sleep => write!(f, "SLEEP"),
Keyword::WriteLine => write!(f, "WRITE_LINE"),
} }
} }
} }
@ -146,6 +150,7 @@ pub enum Control {
Semicolon, Semicolon,
SkinnyArrow, SkinnyArrow,
FatArrow, FatArrow,
DoubleUnderscore,
} }
impl Display for Control { impl Display for Control {
@ -167,6 +172,7 @@ impl Display for Control {
Control::DoubleDot => write!(f, ".."), Control::DoubleDot => write!(f, ".."),
Control::SkinnyArrow => write!(f, "->"), Control::SkinnyArrow => write!(f, "->"),
Control::FatArrow => write!(f, "=>"), Control::FatArrow => write!(f, "=>"),
Control::DoubleUnderscore => write!(f, "__"),
} }
} }
} }
@ -272,6 +278,7 @@ pub fn lexer<'src>() -> impl Parser<
just("..").to(Control::DoubleDot), just("..").to(Control::DoubleDot),
just(".").to(Control::Dot), just(".").to(Control::Dot),
just("$").to(Control::Dollar), just("$").to(Control::Dollar),
just("__").to(Control::DoubleUnderscore),
)) ))
.map(Token::Control); .map(Token::Control);
@ -294,26 +301,14 @@ pub fn lexer<'src>() -> impl Parser<
just("type").to(Keyword::Type), just("type").to(Keyword::Type),
just("loop").to(Keyword::Loop), just("loop").to(Keyword::Loop),
just("while").to(Keyword::While), just("while").to(Keyword::While),
just("READ_LINE").to(Keyword::ReadLine),
just("SLEEP").to(Keyword::Sleep),
just("WRITE_LINE").to(Keyword::WriteLine),
)) ))
.map(Token::Keyword); .map(Token::Keyword);
let built_in_function = choice((
just(BuiltInFunction::ReadLine.name()).to(BuiltInFunction::ReadLine),
just(BuiltInFunction::Sleep.name()).to(BuiltInFunction::Sleep),
just(BuiltInFunction::WriteLine.name()).to(BuiltInFunction::WriteLine),
))
.map(Token::BuiltInFunction);
choice(( choice((
boolean, boolean, float, integer, string, keyword, identifier, control, operator,
float,
integer,
string,
keyword,
identifier,
control,
operator,
built_in_function,
)) ))
.map_with(|token, state| (token, state.span())) .map_with(|token, state| (token, state.span()))
.padded() .padded()

View File

@ -1,5 +1,4 @@
pub mod abstract_tree; pub mod abstract_tree;
pub mod built_in_functions;
pub mod context; pub mod context;
pub mod error; pub mod error;
pub mod identifier; pub mod identifier;

View File

@ -255,16 +255,22 @@ pub fn parser<'src>(
}, },
); );
let built_in_function = { let built_in_function_call = just(Token::Control(Control::DoubleUnderscore))
select! { .ignore_then(choice((
Token::BuiltInFunction(built_in_function) => built_in_function, just(Token::Keyword(Keyword::ReadLine)).to(BuiltInFunctionCall::ReadLine),
} just(Token::Keyword(Keyword::Sleep))
} .ignore_then(expression.clone())
.map_with(|built_in_function, state| { .map(|expression| BuiltInFunctionCall::Sleep(expression)),
Expression::Value( just(Token::Keyword(Keyword::WriteLine))
ValueNode::BuiltInFunction(built_in_function).with_position(state.span()), .ignore_then(expression.clone())
) .map(|expression| BuiltInFunctionCall::WriteLine(expression)),
}); )))
.then_ignore(just(Token::Control(Control::DoubleUnderscore)))
.map_with(|built_in_function_call, state| {
Expression::BuiltInFunctionCall(
Box::new(built_in_function_call).with_position(state.span()),
)
});
let structure_field = identifier let structure_field = identifier
.clone() .clone()
@ -307,7 +313,6 @@ pub fn parser<'src>(
range.clone(), range.clone(),
structure_instance.clone(), structure_instance.clone(),
parsed_function.clone(), parsed_function.clone(),
built_in_function.clone(),
list.clone(), list.clone(),
map.clone(), map.clone(),
basic_value.clone(), basic_value.clone(),
@ -475,11 +480,11 @@ pub fn parser<'src>(
)); ));
choice(( choice((
built_in_function_call,
logic_math_indexes_and_function_calls, logic_math_indexes_and_function_calls,
range, range,
structure_instance, structure_instance,
parsed_function, parsed_function,
built_in_function,
list, list,
map, map,
basic_value, basic_value,
@ -588,7 +593,7 @@ pub fn parser<'src>(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{built_in_functions::BuiltInFunction, lexer::lex}; use crate::lexer::lex;
use super::*; use super::*;
@ -596,10 +601,20 @@ mod tests {
fn built_in_function() { fn built_in_function() {
assert_eq!( assert_eq!(
parse(&lex("__READ_LINE__").unwrap()).unwrap()[0], parse(&lex("__READ_LINE__").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value( Statement::Expression(Expression::BuiltInFunctionCall(
ValueNode::BuiltInFunction(BuiltInFunction::ReadLine).with_position((0, 13)) Box::new(BuiltInFunctionCall::ReadLine).with_position((0, 13))
)) ))
) );
assert_eq!(
parse(&lex("__WRITE_LINE 'hiya'__").unwrap()).unwrap()[0],
Statement::Expression(Expression::BuiltInFunctionCall(
Box::new(BuiltInFunctionCall::WriteLine(Expression::Value(
ValueNode::String("hiya".to_string()).with_position((13, 19))
)))
.with_position((0, 21))
))
);
} }
#[test] #[test]

View File

@ -14,7 +14,6 @@ use stanza::{
use crate::{ use crate::{
abstract_tree::{AbstractNode, Action, Block, Type, WithPos, WithPosition}, abstract_tree::{AbstractNode, Action, Block, Type, WithPos, WithPosition},
built_in_functions::BuiltInFunction,
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
identifier::Identifier, identifier::Identifier,
@ -62,24 +61,18 @@ impl Value {
return_type: WithPosition<Type>, return_type: WithPosition<Type>,
body: WithPosition<Block>, body: WithPosition<Block>,
) -> Self { ) -> Self {
Value(Arc::new(ValueInner::Function(Function::Parsed( Value(Arc::new(ValueInner::Function(Function {
ParsedFunction { type_parameters: type_arguments,
type_parameters: type_arguments, parameters,
parameters, return_type,
return_type, body,
body, })))
},
))))
} }
pub fn structure(name: WithPosition<Identifier>, fields: Vec<(Identifier, Value)>) -> Self { pub fn structure(name: WithPosition<Identifier>, fields: Vec<(Identifier, Value)>) -> Self {
Value(Arc::new(ValueInner::Structure { name, fields })) Value(Arc::new(ValueInner::Structure { name, fields }))
} }
pub fn built_in_function(function: BuiltInFunction) -> Self {
Value(Arc::new(ValueInner::Function(Function::BuiltIn(function))))
}
pub fn r#type(&self, context: &Context) -> Result<Type, ValidationError> { pub fn r#type(&self, context: &Context) -> Result<Type, ValidationError> {
self.0.r#type(context) self.0.r#type(context)
} }
@ -139,12 +132,12 @@ impl Display for Value {
} }
ValueInner::Range(_) => todo!(), ValueInner::Range(_) => todo!(),
ValueInner::String(string) => write!(f, "{string}"), ValueInner::String(string) => write!(f, "{string}"),
ValueInner::Function(Function::Parsed(ParsedFunction { ValueInner::Function(Function {
type_parameters: type_arguments, type_parameters: type_arguments,
parameters, parameters,
return_type, return_type,
body, body,
})) => { }) => {
if !type_arguments.is_empty() { if !type_arguments.is_empty() {
write!(f, "(")?; write!(f, "(")?;
@ -167,8 +160,8 @@ impl Display for Value {
write!(f, "): {} {:?}", return_type.node, body.node) write!(f, "): {} {:?}", return_type.node, body.node)
} }
ValueInner::Function(Function::BuiltIn(built_in_function)) => { ValueInner::Function(function) => {
write!(f, "{built_in_function}") write!(f, "{function}")
} }
ValueInner::Structure { name, fields } => { ValueInner::Structure { name, fields } => {
let mut table = create_table(); let mut table = create_table();
@ -231,18 +224,13 @@ impl ValueInner {
ValueInner::Map(_) => Type::Map, ValueInner::Map(_) => Type::Map,
ValueInner::Range(_) => Type::Range, ValueInner::Range(_) => Type::Range,
ValueInner::String(_) => Type::String, ValueInner::String(_) => Type::String,
ValueInner::Function(function) => match function { ValueInner::Function(function) => Type::Function {
Function::Parsed(parsed_function) => Type::Function { parameter_types: function
parameter_types: parsed_function .parameters
.parameters .iter()
.iter() .map(|(_, r#type)| r#type.clone())
.map(|(_, r#type)| r#type.clone()) .collect(),
.collect(), return_type: Box::new(function.return_type.clone()),
return_type: Box::new(parsed_function.return_type.clone()),
},
Function::BuiltIn(built_in_function) => {
built_in_function.clone().as_value().r#type(context)?
}
}, },
ValueInner::Structure { name, .. } => { ValueInner::Structure { name, .. } => {
if let Some(r#type) = context.get_type(&name.node)? { if let Some(r#type) = context.get_type(&name.node)? {
@ -321,34 +309,29 @@ impl Ord for ValueInner {
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Function { pub struct Function {
Parsed(ParsedFunction), type_parameters: Vec<WithPosition<Type>>,
BuiltIn(BuiltInFunction), parameters: Vec<(Identifier, WithPosition<Type>)>,
return_type: WithPosition<Type>,
body: WithPosition<Block>,
} }
impl Function { impl Function {
pub fn type_parameters(&self) -> &Vec<WithPosition<Type>> {
&self.type_parameters
}
pub fn call(self, arguments: Vec<Value>, context: Context) -> Result<Action, RuntimeError> { pub fn call(self, arguments: Vec<Value>, context: Context) -> Result<Action, RuntimeError> {
let action = match self { for ((identifier, _), value) in self.parameters.into_iter().zip(arguments.into_iter()) {
Function::Parsed(ParsedFunction { context.set_value(identifier.clone(), value)?;
parameters, body, .. }
}) => {
for ((identifier, _), value) in parameters.into_iter().zip(arguments.into_iter()) {
context.set_value(identifier.clone(), value)?;
}
body.node.run(&context)? self.body.node.run(&context)
}
Function::BuiltIn(built_in_function) => built_in_function.call(arguments, &context)?,
};
Ok(action)
} }
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] impl Display for Function {
pub struct ParsedFunction { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
pub type_parameters: Vec<WithPosition<Type>>, todo!()
pub parameters: Vec<(Identifier, WithPosition<Type>)>, }
pub return_type: WithPosition<Type>,
pub body: WithPosition<Block>,
} }