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::{
AbstractNode, Action, FunctionCall, ListIndex, Logic, MapIndex, Math, SourcePosition, Type,
ValueNode, WithPosition,
AbstractNode, Action, BuiltInFunctionCall, FunctionCall, ListIndex, Logic, MapIndex, Math,
SourcePosition, Type, ValueNode, WithPosition,
};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Expression {
BuiltInFunctionCall(WithPosition<Box<BuiltInFunctionCall>>),
FunctionCall(WithPosition<FunctionCall>),
Identifier(WithPosition<Identifier>),
MapIndex(WithPosition<Box<MapIndex>>),
@ -30,6 +31,7 @@ impl Expression {
Expression::Logic(inner) => inner.position,
Expression::Math(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::Math(math) => math.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::Math(math) => math.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::Math(math) => math.node.run(_context),
Expression::Value(value_node) => value_node.node.run(_context),
Expression::BuiltInFunctionCall(_) => todo!(),
}
}
}

View File

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

View File

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

View File

@ -1,7 +1,6 @@
use std::{cmp::Ordering, collections::BTreeMap, ops::Range};
use crate::{
built_in_functions::BuiltInFunction,
context::Context,
error::{RuntimeError, ValidationError},
identifier::Identifier,
@ -13,7 +12,6 @@ use super::{AbstractNode, Action, Block, Expression, Type, WithPos, WithPosition
#[derive(Clone, Debug, PartialEq)]
pub enum ValueNode {
Boolean(bool),
BuiltInFunction(BuiltInFunction),
Float(f64),
Integer(i64),
List(Vec<Expression>),
@ -88,7 +86,6 @@ impl AbstractNode for ValueNode {
fields: types,
}
}
ValueNode::BuiltInFunction(built_in_function) => built_in_function.r#type(),
};
Ok(r#type)
@ -260,9 +257,6 @@ impl AbstractNode for ValueNode {
Value::structure(name, fields)
}
ValueNode::BuiltInFunction(built_in_function) => {
Value::built_in_function(built_in_function)
}
};
Ok(Action::Return(value))
@ -358,8 +352,6 @@ impl Ord for ValueNode {
}
}
(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 crate::{built_in_functions::BuiltInFunction, error::Error};
use crate::error::Error;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Token<'src> {
Boolean(bool),
BuiltInFunction(BuiltInFunction),
Integer(i64),
Float(f64),
String(&'src str),
@ -24,7 +23,6 @@ impl<'src> Display for Token<'src> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Token::Boolean(boolean) => write!(f, "{boolean}"),
Token::BuiltInFunction(built_in_function) => write!(f, "{built_in_function}"),
Token::Integer(integer) => write!(f, "{integer}"),
Token::Float(float) => write!(f, "{float}"),
Token::String(string) => write!(f, "{string}"),
@ -51,11 +49,14 @@ pub enum Keyword {
Map,
None,
Range,
ReadLine,
Sleep,
Struct,
Str,
Type,
Loop,
While,
WriteLine,
}
impl Display for Keyword {
@ -79,6 +80,9 @@ impl Display for Keyword {
Keyword::Loop => write!(f, "loop"),
Keyword::While => write!(f, "while"),
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,
SkinnyArrow,
FatArrow,
DoubleUnderscore,
}
impl Display for Control {
@ -167,6 +172,7 @@ impl Display for Control {
Control::DoubleDot => write!(f, ".."),
Control::SkinnyArrow => 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::Dot),
just("$").to(Control::Dollar),
just("__").to(Control::DoubleUnderscore),
))
.map(Token::Control);
@ -294,26 +301,14 @@ pub fn lexer<'src>() -> impl Parser<
just("type").to(Keyword::Type),
just("loop").to(Keyword::Loop),
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);
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((
boolean,
float,
integer,
string,
keyword,
identifier,
control,
operator,
built_in_function,
boolean, float, integer, string, keyword, identifier, control, operator,
))
.map_with(|token, state| (token, state.span()))
.padded()

View File

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

View File

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

View File

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