Begin implementing functions
This commit is contained in:
parent
b7288ceed8
commit
56fbbdee0b
@ -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!()
|
||||||
}
|
}
|
||||||
|
@ -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))),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
@ -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()),
|
||||||
|
@ -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)?;
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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, _)
|
||||||
|
@ -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),
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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())))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
56
src/value.rs
56
src/value.rs
@ -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,
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user