1
0

Begin implementing functions

This commit is contained in:
Jeff 2024-03-08 16:14:47 -05:00
parent b7288ceed8
commit 56fbbdee0b
12 changed files with 212 additions and 105 deletions

View File

@ -6,11 +6,11 @@ use crate::{
use super::{AbstractTree, Action, Identifier, Statement, Type}; use super::{AbstractTree, Action, Identifier, Statement, Type};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Assignment<'src> { pub struct Assignment {
identifier: Identifier, identifier: Identifier,
r#type: Option<Type>, r#type: Option<Type>,
operator: AssignmentOperator, operator: AssignmentOperator,
statement: Box<Statement<'src>>, statement: Box<Statement>,
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
@ -20,12 +20,12 @@ pub enum AssignmentOperator {
SubAssign, SubAssign,
} }
impl<'src> Assignment<'src> { impl Assignment {
pub fn new( pub fn new(
identifier: Identifier, identifier: Identifier,
r#type: Option<Type>, r#type: Option<Type>,
operator: AssignmentOperator, operator: AssignmentOperator,
statement: Statement<'src>, statement: Statement,
) -> Self { ) -> Self {
Self { Self {
identifier, identifier,
@ -36,7 +36,7 @@ impl<'src> Assignment<'src> {
} }
} }
impl<'src> AbstractTree for Assignment<'src> { impl AbstractTree for Assignment {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
todo!() todo!()
} }

View File

@ -7,17 +7,17 @@ use crate::{
use super::{AbstractTree, Action, Statement, Type}; use super::{AbstractTree, Action, Statement, Type};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Block<'src> { pub struct Block {
statements: Vec<Statement<'src>>, statements: Vec<Statement>,
} }
impl<'src> Block<'src> { impl Block {
pub fn new(statements: Vec<Statement<'src>>) -> Self { pub fn new(statements: Vec<Statement>) -> Self {
Self { statements } Self { statements }
} }
} }
impl<'src> AbstractTree for Block<'src> { impl AbstractTree for Block {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
let final_statement = self.statements.last().unwrap(); let final_statement = self.statements.last().unwrap();
@ -70,7 +70,7 @@ mod tests {
#[test] #[test]
fn expected_type_returns_type_of_final_statement() { fn expected_type_returns_type_of_final_statement() {
let block = Block::new(vec![ let block = Block::new(vec![
Statement::Expression(Expression::Value(ValueNode::String("42"))), Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))),
Statement::Expression(Expression::Value(ValueNode::Integer(42))), Statement::Expression(Expression::Value(ValueNode::Integer(42))),
]); ]);

View File

@ -6,15 +6,15 @@ use crate::{
use super::{AbstractTree, Action, Identifier, Index, Logic, Math, Type, ValueNode}; use super::{AbstractTree, Action, Identifier, Index, Logic, Math, Type, ValueNode};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Expression<'src> { pub enum Expression {
Identifier(Identifier), Identifier(Identifier),
Index(Box<Index<'src>>), Index(Box<Index>),
Logic(Box<Logic<'src>>), Logic(Box<Logic>),
Math(Box<Math<'src>>), Math(Box<Math>),
Value(ValueNode<'src>), Value(ValueNode),
} }
impl<'src> AbstractTree for Expression<'src> { impl AbstractTree for Expression {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
match self { match self {
Expression::Identifier(identifier) => identifier.expected_type(_context), Expression::Identifier(identifier) => identifier.expected_type(_context),

View File

@ -6,17 +6,17 @@ use crate::{
use super::{AbstractTree, Action, Expression, Statement, Type}; use super::{AbstractTree, Action, Expression, Statement, Type};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct IfElse<'src> { pub struct IfElse {
if_expression: Expression<'src>, if_expression: Expression,
if_statement: Box<Statement<'src>>, if_statement: Box<Statement>,
else_statement: Option<Box<Statement<'src>>>, else_statement: Option<Box<Statement>>,
} }
impl<'src> IfElse<'src> { impl IfElse {
pub fn new( pub fn new(
if_expression: Expression<'src>, if_expression: Expression,
if_statement: Statement<'src>, if_statement: Statement,
else_statement: Option<Statement<'src>>, else_statement: Option<Statement>,
) -> Self { ) -> Self {
Self { Self {
if_expression, if_expression,
@ -26,7 +26,7 @@ impl<'src> IfElse<'src> {
} }
} }
impl<'src> AbstractTree for IfElse<'src> { impl AbstractTree for IfElse {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
Ok(Type::None) Ok(Type::None)
} }
@ -71,7 +71,7 @@ mod tests {
assert_eq!( assert_eq!(
IfElse::new( IfElse::new(
Expression::Value(ValueNode::Boolean(true)), Expression::Value(ValueNode::Boolean(true)),
Statement::Expression(Expression::Value(ValueNode::String("foo"))), Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))),
None None
) )
.run(&Context::new()), .run(&Context::new()),
@ -84,9 +84,9 @@ mod tests {
assert_eq!( assert_eq!(
IfElse::new( IfElse::new(
Expression::Value(ValueNode::Boolean(false)), Expression::Value(ValueNode::Boolean(false)),
Statement::Expression(Expression::Value(ValueNode::String("foo"))), Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))),
Some(Statement::Expression(Expression::Value(ValueNode::String( Some(Statement::Expression(Expression::Value(ValueNode::String(
"bar" "bar".to_string()
)))) ))))
) )
.run(&Context::new()), .run(&Context::new()),

View File

@ -7,18 +7,18 @@ use crate::{
use super::{AbstractTree, Action, Expression, Type, ValueNode}; use super::{AbstractTree, Action, Expression, Type, ValueNode};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Index<'src> { pub struct Index {
left: Expression<'src>, left: Expression,
right: Expression<'src>, right: Expression,
} }
impl<'src> Index<'src> { impl Index {
pub fn new(left: Expression<'src>, right: Expression<'src>) -> Self { pub fn new(left: Expression, right: Expression) -> Self {
Self { left, right } Self { left, right }
} }
} }
impl<'src> AbstractTree for Index<'src> { impl AbstractTree for Index {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
let left_type = self.left.expected_type(_context)?; let left_type = self.left.expected_type(_context)?;

View File

@ -7,19 +7,19 @@ use crate::{
use super::{AbstractTree, Action, Expression, Type}; use super::{AbstractTree, Action, Expression, Type};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Logic<'src> { pub enum Logic {
Equal(Expression<'src>, Expression<'src>), Equal(Expression, Expression),
NotEqual(Expression<'src>, Expression<'src>), NotEqual(Expression, Expression),
Greater(Expression<'src>, Expression<'src>), Greater(Expression, Expression),
Less(Expression<'src>, Expression<'src>), Less(Expression, Expression),
GreaterOrEqual(Expression<'src>, Expression<'src>), GreaterOrEqual(Expression, Expression),
LessOrEqual(Expression<'src>, Expression<'src>), LessOrEqual(Expression, Expression),
And(Expression<'src>, Expression<'src>), And(Expression, Expression),
Or(Expression<'src>, Expression<'src>), Or(Expression, Expression),
Not(Expression<'src>), Not(Expression),
} }
impl<'src> AbstractTree for Logic<'src> { impl AbstractTree for Logic {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
Ok(Type::Boolean) Ok(Type::Boolean)
} }

View File

@ -6,17 +6,17 @@ use crate::{
use super::{AbstractTree, Action, Statement, Type}; use super::{AbstractTree, Action, Statement, Type};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Loop<'src> { pub struct Loop {
statements: Vec<Statement<'src>>, statements: Vec<Statement>,
} }
impl<'src> Loop<'src> { impl Loop {
pub fn new(statements: Vec<Statement<'src>>) -> Self { pub fn new(statements: Vec<Statement>) -> Self {
Self { statements } Self { statements }
} }
} }
impl<'src> AbstractTree for Loop<'src> { impl AbstractTree for Loop {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
Ok(Type::None) Ok(Type::None)
} }

View File

@ -8,15 +8,15 @@ use crate::{
use super::{AbstractTree, Action, Expression, Type}; use super::{AbstractTree, Action, Expression, Type};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Math<'src> { pub enum Math {
Add(Expression<'src>, Expression<'src>), Add(Expression, Expression),
Subtract(Expression<'src>, Expression<'src>), Subtract(Expression, Expression),
Multiply(Expression<'src>, Expression<'src>), Multiply(Expression, Expression),
Divide(Expression<'src>, Expression<'src>), Divide(Expression, Expression),
Modulo(Expression<'src>, Expression<'src>), Modulo(Expression, Expression),
} }
impl<'src> AbstractTree for Math<'src> { impl AbstractTree for Math {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
match self { match self {
Math::Add(left, _) Math::Add(left, _)

View File

@ -6,16 +6,16 @@ use crate::{
use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type}; use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Statement<'src> { pub enum Statement {
Assignment(Assignment<'src>), Assignment(Assignment),
Block(Block<'src>), Block(Block),
Break(Expression<'src>), Break(Expression),
Expression(Expression<'src>), Expression(Expression),
IfElse(IfElse<'src>), IfElse(IfElse),
Loop(Loop<'src>), Loop(Loop),
} }
impl<'src> AbstractTree for Statement<'src> { impl AbstractTree for Statement {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
match self { match self {
Statement::Assignment(assignment) => assignment.expected_type(_context), Statement::Assignment(assignment) => assignment.expected_type(_context),

View File

@ -6,21 +6,26 @@ use crate::{
Value, Value,
}; };
use super::{AbstractTree, Action, Expression, Identifier, Type}; use super::{AbstractTree, Action, Expression, Identifier, Statement, Type};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum ValueNode<'src> { pub enum ValueNode {
Boolean(bool), Boolean(bool),
Float(f64), Float(f64),
Integer(i64), Integer(i64),
List(Vec<Expression<'src>>), List(Vec<Expression>),
Map(Vec<(Identifier, Option<Type>, Expression<'src>)>), Map(Vec<(Identifier, Option<Type>, Expression)>),
Range(Range<i64>), Range(Range<i64>),
String(&'src str), String(String),
Enum(Identifier, Identifier), Enum(Identifier, Identifier),
Function {
parameters: Vec<(Identifier, Type)>,
return_type: Type,
body: Box<Statement>,
},
} }
impl<'src> AbstractTree for ValueNode<'src> { impl AbstractTree for ValueNode {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
let r#type = match self { let r#type = match self {
ValueNode::Boolean(_) => Type::Boolean, ValueNode::Boolean(_) => Type::Boolean,
@ -39,6 +44,7 @@ impl<'src> AbstractTree for ValueNode<'src> {
ValueNode::Range(_) => Type::Range, ValueNode::Range(_) => Type::Range,
ValueNode::String(_) => Type::String, ValueNode::String(_) => Type::String,
ValueNode::Enum(name, _) => Type::Custom(name.clone()), ValueNode::Enum(name, _) => Type::Custom(name.clone()),
ValueNode::Function { .. } => todo!(),
}; };
Ok(r#type) Ok(r#type)
@ -84,21 +90,26 @@ impl<'src> AbstractTree for ValueNode<'src> {
Value::r#enum(name, variant) Value::r#enum(name, variant)
} }
} }
ValueNode::Function {
parameters,
return_type,
body,
} => Value::function(parameters, return_type, *body),
}; };
Ok(Action::Return(value)) Ok(Action::Return(value))
} }
} }
impl<'src> Eq for ValueNode<'src> {} impl Eq for ValueNode {}
impl<'src> PartialOrd for ValueNode<'src> { impl PartialOrd for ValueNode {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
} }
impl<'src> Ord for ValueNode<'src> { impl Ord for ValueNode {
fn cmp(&self, other: &Self) -> Ordering { fn cmp(&self, other: &Self) -> Ordering {
use ValueNode::*; use ValueNode::*;
@ -135,6 +146,33 @@ impl<'src> Ord for ValueNode<'src> {
} }
} }
(Enum(_, _), _) => Ordering::Greater, (Enum(_, _), _) => Ordering::Greater,
(
Function {
parameters: left_parameters,
return_type: left_return,
body: left_body,
},
Function {
parameters: right_parameters,
return_type: right_return,
body: right_body,
},
) => {
let parameter_cmp = left_parameters.cmp(right_parameters);
if parameter_cmp.is_eq() {
let return_cmp = left_return.cmp(right_return);
if return_cmp.is_eq() {
left_body.cmp(right_body)
} else {
return_cmp
}
} else {
parameter_cmp
}
}
(Function { .. }, _) => Ordering::Greater,
} }
} }
} }

View File

@ -12,7 +12,7 @@ pub type DustParser<'src> = Boxed<
'src, 'src,
'src, 'src,
ParserInput<'src>, ParserInput<'src>,
Vec<(Statement<'src>, SimpleSpan)>, Vec<(Statement, SimpleSpan)>,
extra::Err<Rich<'src, Token<'src>, SimpleSpan>>, extra::Err<Rich<'src, Token<'src>, SimpleSpan>>,
>; >;
@ -21,7 +21,7 @@ pub type ParserInput<'src> =
pub fn parse<'src>( pub fn parse<'src>(
tokens: &'src [(Token<'src>, SimpleSpan)], tokens: &'src [(Token<'src>, SimpleSpan)],
) -> Result<Vec<(Statement<'src>, SimpleSpan)>, Vec<Error>> { ) -> Result<Vec<(Statement, SimpleSpan)>, Vec<Error>> {
parser() parser()
.parse(tokens.spanned((tokens.len()..tokens.len()).into())) .parse(tokens.spanned((tokens.len()..tokens.len()).into()))
.into_result() .into_result()
@ -85,7 +85,7 @@ pub fn parser<'src>() -> DustParser<'src> {
Token::Boolean(boolean) => ValueNode::Boolean(boolean), Token::Boolean(boolean) => ValueNode::Boolean(boolean),
Token::Integer(integer) => ValueNode::Integer(integer), Token::Integer(integer) => ValueNode::Integer(integer),
Token::Float(float) => ValueNode::Float(float), Token::Float(float) => ValueNode::Float(float),
Token::String(string) => ValueNode::String(string), Token::String(string) => ValueNode::String(string.to_string()),
} }
.map(|value| Expression::Value(value)) .map(|value| Expression::Value(value))
.boxed(); .boxed();
@ -221,6 +221,7 @@ pub fn parser<'src>() -> DustParser<'src> {
.map(|expression| Statement::Break(expression)); .map(|expression| Statement::Break(expression));
let assignment = identifier let assignment = identifier
.clone()
.then(type_specification.clone().or_not()) .then(type_specification.clone().or_not())
.then(choice(( .then(choice((
just(Token::Operator(Operator::Assign)).to(AssignmentOperator::Assign), just(Token::Operator(Operator::Assign)).to(AssignmentOperator::Assign),
@ -269,6 +270,25 @@ pub fn parser<'src>() -> DustParser<'src> {
}) })
.boxed(); .boxed();
let function = identifier
.clone()
.then(type_specification.clone())
.separated_by(just(Token::Control(Control::Comma)))
.collect::<Vec<(Identifier, Type)>>()
.delimited_by(
just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)),
)
.then(type_specification)
.then(statement.clone())
.map(|((parameters, return_type), body)| {
Statement::Expression(Expression::Value(ValueNode::Function {
parameters,
return_type,
body: Box::new(body),
}))
});
choice(( choice((
assignment, assignment,
expression_statement, expression_statement,
@ -276,6 +296,7 @@ pub fn parser<'src>() -> DustParser<'src> {
block, block,
r#loop, r#loop,
if_else, if_else,
function,
)) ))
.then_ignore(just(Token::Control(Control::Semicolon)).or_not()) .then_ignore(just(Token::Control(Control::Semicolon)).or_not())
}); });
@ -293,13 +314,27 @@ mod tests {
use super::*; use super::*;
#[test]
fn function() {
assert_eq!(
parse(&lex("(x: int): int x ").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::Function {
parameters: vec![(Identifier::new("x"), Type::Integer)],
return_type: Type::Integer,
body: Box::new(Statement::Expression(Expression::Identifier(
Identifier::new("x")
)))
}))
)
}
#[test] #[test]
fn r#if() { fn r#if() {
assert_eq!( assert_eq!(
parse(&lex("if true 'foo'").unwrap()).unwrap()[0].0, parse(&lex("if true 'foo'").unwrap()).unwrap()[0].0,
Statement::IfElse(IfElse::new( Statement::IfElse(IfElse::new(
Expression::Value(ValueNode::Boolean(true)), Expression::Value(ValueNode::Boolean(true)),
Statement::Expression(Expression::Value(ValueNode::String("foo"))), Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))),
None None
)) ))
) )
@ -311,9 +346,9 @@ mod tests {
parse(&lex("if true 'foo' else 'bar'").unwrap()).unwrap()[0].0, parse(&lex("if true 'foo' else 'bar'").unwrap()).unwrap()[0].0,
Statement::IfElse(IfElse::new( Statement::IfElse(IfElse::new(
Expression::Value(ValueNode::Boolean(true)), Expression::Value(ValueNode::Boolean(true)),
Statement::Expression(Expression::Value(ValueNode::String("foo"))), Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))),
Some(Statement::Expression(Expression::Value(ValueNode::String( Some(Statement::Expression(Expression::Value(ValueNode::String(
"bar" "bar".to_string()
)))) ))))
)) ))
) )
@ -326,7 +361,7 @@ mod tests {
Statement::Expression(Expression::Value(ValueNode::Map(vec![( Statement::Expression(Expression::Value(ValueNode::Map(vec![(
Identifier::new("foo"), Identifier::new("foo"),
None, None,
Expression::Value(ValueNode::String("bar")) Expression::Value(ValueNode::String("bar".to_string()))
)]))) )])))
); );
assert_eq!( assert_eq!(
@ -521,7 +556,7 @@ mod tests {
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::List(vec![ Statement::Expression(Expression::Value(ValueNode::List(vec![
Expression::Value(ValueNode::Integer(42)), Expression::Value(ValueNode::Integer(42)),
Expression::Value(ValueNode::String("foo")) Expression::Value(ValueNode::String("foo".to_string()))
]))) ])))
)), )),
); );
@ -596,8 +631,8 @@ mod tests {
parse(&lex("[42, 'foo', 'bar', [1, 2, 3,]]").unwrap()).unwrap()[0].0, parse(&lex("[42, 'foo', 'bar', [1, 2, 3,]]").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::List(vec![ Statement::Expression(Expression::Value(ValueNode::List(vec![
Expression::Value(ValueNode::Integer(42)), Expression::Value(ValueNode::Integer(42)),
Expression::Value(ValueNode::String("foo")), Expression::Value(ValueNode::String("foo".to_string())),
Expression::Value(ValueNode::String("bar")), Expression::Value(ValueNode::String("bar".to_string())),
Expression::Value(ValueNode::List(vec![ Expression::Value(ValueNode::List(vec![
Expression::Value(ValueNode::Integer(1)), Expression::Value(ValueNode::Integer(1)),
Expression::Value(ValueNode::Integer(2)), Expression::Value(ValueNode::Integer(2)),
@ -751,15 +786,15 @@ mod tests {
fn double_quoted_string() { fn double_quoted_string() {
assert_eq!( assert_eq!(
parse(&lex("\"\"").unwrap()).unwrap()[0].0, parse(&lex("\"\"").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::String(""))) Statement::Expression(Expression::Value(ValueNode::String("".to_string())))
); );
assert_eq!( assert_eq!(
parse(&lex("\"42\"").unwrap()).unwrap()[0].0, parse(&lex("\"42\"").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::String("42"))) Statement::Expression(Expression::Value(ValueNode::String("42".to_string())))
); );
assert_eq!( assert_eq!(
parse(&lex("\"foobar\"").unwrap()).unwrap()[0].0, parse(&lex("\"foobar\"").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::String("foobar"))) Statement::Expression(Expression::Value(ValueNode::String("foobar".to_string())))
); );
} }
@ -767,15 +802,15 @@ mod tests {
fn single_quoted_string() { fn single_quoted_string() {
assert_eq!( assert_eq!(
parse(&lex("''").unwrap()).unwrap()[0].0, parse(&lex("''").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::String(""))) Statement::Expression(Expression::Value(ValueNode::String("".to_string())))
); );
assert_eq!( assert_eq!(
parse(&lex("'42'").unwrap()).unwrap()[0].0, parse(&lex("'42'").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::String("42"))) Statement::Expression(Expression::Value(ValueNode::String("42".to_string())))
); );
assert_eq!( assert_eq!(
parse(&lex("'foobar'").unwrap()).unwrap()[0].0, parse(&lex("'foobar'").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::String("foobar"))) Statement::Expression(Expression::Value(ValueNode::String("foobar".to_string())))
); );
} }
@ -783,15 +818,15 @@ mod tests {
fn grave_quoted_string() { fn grave_quoted_string() {
assert_eq!( assert_eq!(
parse(&lex("``").unwrap()).unwrap()[0].0, parse(&lex("``").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::String(""))) Statement::Expression(Expression::Value(ValueNode::String("".to_string())))
); );
assert_eq!( assert_eq!(
parse(&lex("`42`").unwrap()).unwrap()[0].0, parse(&lex("`42`").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::String("42"))) Statement::Expression(Expression::Value(ValueNode::String("42".to_string())))
); );
assert_eq!( assert_eq!(
parse(&lex("`foobar`").unwrap()).unwrap()[0].0, parse(&lex("`foobar`").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Value(ValueNode::String("foobar"))) Statement::Expression(Expression::Value(ValueNode::String("foobar".to_string())))
); );
} }
} }

View File

@ -13,7 +13,7 @@ use stanza::{
}; };
use crate::{ use crate::{
abstract_tree::{Identifier, Type}, abstract_tree::{Identifier, Statement, Type},
error::ValidationError, error::ValidationError,
}; };
@ -72,6 +72,18 @@ impl Value {
Value(Arc::new(ValueInner::Enum(name, variant))) Value(Arc::new(ValueInner::Enum(name, variant)))
} }
pub fn function(
parameters: Vec<(Identifier, Type)>,
return_type: Type,
body: Statement,
) -> Self {
Value(Arc::new(ValueInner::Function(Function {
parameters,
return_type,
body,
})))
}
pub fn r#type(&self) -> Type { pub fn r#type(&self) -> Type {
match self.0.as_ref() { match self.0.as_ref() {
ValueInner::Boolean(_) => Type::Boolean, ValueInner::Boolean(_) => Type::Boolean,
@ -90,6 +102,7 @@ impl Value {
ValueInner::Range(_) => Type::Range, ValueInner::Range(_) => Type::Range,
ValueInner::String(_) => Type::String, ValueInner::String(_) => Type::String,
ValueInner::Enum(name, _) => Type::Custom(name.clone()), ValueInner::Enum(name, _) => Type::Custom(name.clone()),
ValueInner::Function(_) => todo!(),
} }
} }
@ -152,17 +165,15 @@ impl Value {
impl Display for Value { impl Display for Value {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use ValueInner::*;
fn create_table() -> Table { fn create_table() -> Table {
Table::with_styles(Styles::default().with(HAlign::Centred).with(MinWidth(3))) Table::with_styles(Styles::default().with(HAlign::Centred).with(MinWidth(3)))
} }
match self.inner().as_ref() { match self.inner().as_ref() {
Boolean(boolean) => write!(f, "{boolean}"), ValueInner::Boolean(boolean) => write!(f, "{boolean}"),
Float(float) => write!(f, "{float}"), ValueInner::Float(float) => write!(f, "{float}"),
Integer(integer) => write!(f, "{integer}"), ValueInner::Integer(integer) => write!(f, "{integer}"),
List(list) => { ValueInner::List(list) => {
let mut table = create_table(); let mut table = create_table();
for value in list { for value in list {
@ -171,7 +182,7 @@ impl Display for Value {
write!(f, "{}", Console::default().render(&table)) write!(f, "{}", Console::default().render(&table))
} }
Map(map) => { ValueInner::Map(map) => {
let mut table = create_table(); let mut table = create_table();
for (identifier, value) in map { for (identifier, value) in map {
@ -180,10 +191,23 @@ impl Display for Value {
write!(f, "{}", Console::default().render(&table)) write!(f, "{}", Console::default().render(&table))
} }
Range(_) => todo!(), ValueInner::Range(_) => todo!(),
String(string) => write!(f, "{string}"), ValueInner::String(string) => write!(f, "{string}"),
Enum(_, _) => todo!(), ValueInner::Enum(_, _) => todo!(),
ValueInner::Function(Function {
parameters,
return_type,
body,
}) => {
write!(f, "(")?;
for (identifier, r#type) in parameters {
write!(f, "{identifier}: {}", r#type)?;
}
write!(f, "): {return_type} {body:?}")
}
} }
} }
} }
@ -206,6 +230,7 @@ impl Ord for Value {
pub enum ValueInner { pub enum ValueInner {
Boolean(bool), Boolean(bool),
Float(f64), Float(f64),
Function(Function),
Integer(i64), Integer(i64),
List(Vec<Value>), List(Vec<Value>),
Map(BTreeMap<Identifier, Value>), Map(BTreeMap<Identifier, Value>),
@ -259,6 +284,15 @@ impl Ord for ValueInner {
} }
} }
(Enum(..), _) => Ordering::Greater, (Enum(..), _) => Ordering::Greater,
(Function(left), Function(right)) => left.cmp(right),
(Function(_), _) => Ordering::Greater,
} }
} }
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Function {
parameters: Vec<(Identifier, Type)>,
return_type: Type,
body: Statement,
}