Skip to content

Commit

Permalink
Allow if then else if... nested expressions.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ivorforce committed Apr 25, 2024
1 parent aebd1ad commit 9c898ec
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 41 deletions.
14 changes: 9 additions & 5 deletions src/monoteny_grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ Statement: Statement = {
<mutability: VariableDeclarationMutability> <identifier: Identifier> <type_declaration: ("'" <Box<Expression>>)?> <assignment: ("=" <Box<Expression>>)?> => Statement::VariableDeclaration { mutability, identifier, type_declaration, assignment },
"upd" <target: Box<Expression>> "=" <new_value: Box<Expression>> => Statement::VariableUpdate { <> },
"return" <Box<Expression>?> => Statement::Return(<>),
Box<IfThenElse> => Statement::IfThenElse(<>),
Box<Expression> => Statement::Expression(<>),
Box<Function> => Statement::FunctionDeclaration(<>),
Box<Trait> => Statement::Trait(<>),
Expand All @@ -137,13 +136,18 @@ VariableDeclarationMutability: Mutability = {
"var" => Mutability::Mutable,
}

IfThenElse: IfThenElse = {
"if" <condition: Expression> "::" <consequent: Expression> <alternative: ("else" "::" <Expression>)?> => IfThenElse { <> },
}

// =============================== Expression =====================================

Expression: Expression = {
Box<Positioned<IfThenElseTerm>> => Expression::from(vec![<>]),
ExpressionNoIfThenElse,
}

IfThenElseTerm: Term = {
"if" <condition: ExpressionNoIfThenElse> "::" <consequent: ExpressionNoIfThenElse> <alternative: ("else" "::" <Expression>)?> => Term::IfThenElse(Box::new(IfThenElse { <> })),
}

ExpressionNoIfThenElse: Expression = {
Box<Positioned<Term>>+ => Expression::from(<>),
}

Expand Down
16 changes: 8 additions & 8 deletions src/parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ pub enum Statement {
FunctionDeclaration(Box<Function>),
Trait(Box<TraitDefinition>),
Conformance(Box<TraitConformanceDeclaration>),
IfThenElse(Box<IfThenElse>),
}

#[derive(Eq, PartialEq, Clone)]
Expand Down Expand Up @@ -128,6 +127,7 @@ pub enum Term {
Array(Box<Array>),
StringLiteral(Vec<Box<Positioned<StringPart>>>),
Block(Box<Block>),
IfThenElse(Box<IfThenElse>),
}

#[derive(Eq, PartialEq, Clone)]
Expand Down Expand Up @@ -266,13 +266,6 @@ impl Display for Statement {
Statement::FunctionDeclaration(function) => write!(fmt, "{}", function),
Statement::Trait(trait_) => write!(fmt, "{}", trait_),
Statement::Conformance(conformance) => write!(fmt, "{}", conformance),
Statement::IfThenElse(if_then_else) => {
write!(fmt, "if {} :: {}", if_then_else.condition, if_then_else.consequent)?;
if let Some(alternative) = &if_then_else.alternative {
write!(fmt, "else :: {}", alternative)?;
}
Ok(())
},
}
}
}
Expand Down Expand Up @@ -308,6 +301,13 @@ impl Display for Term {
write!(fmt, "{{\n{}}}", block)
}
Term::Dot => write!(fmt, "."),
Term::IfThenElse(if_then_else) => {
write!(fmt, "if {} :: {}", if_then_else.condition, if_then_else.consequent)?;
if let Some(alternative) = &if_then_else.alternative {
write!(fmt, "else :: {}", alternative)?;
}
Ok(())
}
}
}
}
Expand Down
24 changes: 23 additions & 1 deletion src/resolver/grammar/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ use crate::resolver::scopes;
use crate::parser::ast;
use crate::program::allocation::ObjectReference;
use crate::program::expression_tree::{ExpressionID, ExpressionOperation};
use crate::program::function_object;
use crate::program::{function_object, primitives};
use crate::program::function_object::{FunctionCallExplicity, FunctionRepresentation, FunctionTargetType};
use crate::program::functions::{FunctionHead, ParameterKey};
use crate::program::types::{TypeProto, TypeUnit};
use crate::util::position::Positioned;

pub fn resolve_expression_to_tokens(resolver: &mut ImperativeResolver, syntax: &[Box<Positioned<ast::Term>>], scope: &scopes::Scope) -> RResult<Vec<Positioned<Token>>> {
Expand Down Expand Up @@ -246,6 +247,27 @@ pub fn resolve_expression_to_tokens(resolver: &mut ImperativeResolver, syntax: &
Token::Value(resolver.resolve_block(statements, &scope)?)
))
}
ast::Term::IfThenElse(if_then_else) => {
let condition: ExpressionID = resolver.resolve_expression(&if_then_else.condition, &scope)?;
resolver.types.bind(condition, &TypeProto::unit(TypeUnit::Struct(Rc::clone(&resolver.runtime.primitives.as_ref().unwrap()[&primitives::Type::Bool]))))?;
let consequent: ExpressionID = resolver.resolve_expression(&if_then_else.consequent, &scope)?;

let mut arguments = vec![condition, consequent];

if let Some(alternative) = &if_then_else.alternative {
let alternative: ExpressionID = resolver.resolve_expression(alternative, &scope)?;
resolver.types.bind(alternative, &TypeProto::unit(TypeUnit::Generic(consequent)))?;
arguments.push(alternative);
}

let expression_id = resolver.register_new_expression(arguments);
resolver.expression_tree.values.insert(expression_id, ExpressionOperation::IfThenElse);
resolver.types.bind(expression_id, &TypeProto::unit(TypeUnit::Generic(consequent)))?;

tokens.push(ast_token.with_value(
Token::Value(expression_id)
))
}
}
}

Expand Down
20 changes: 0 additions & 20 deletions src/resolver/imperative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,26 +282,6 @@ impl <'a> ImperativeResolver<'a> {

self.resolve_expression(&expression, &scope)?
}
ast::Statement::IfThenElse(if_then_else) => {
pstatement.no_decorations()?;

let condition: ExpressionID = self.resolve_expression(&if_then_else.condition, &scope)?;
self.types.bind(condition, &TypeProto::unit(TypeUnit::Struct(Rc::clone(&self.runtime.primitives.as_ref().unwrap()[&primitives::Type::Bool]))))?;
let consequent: ExpressionID = self.resolve_expression(&if_then_else.consequent, &scope)?;

let mut arguments = vec![condition, consequent];

if let Some(alternative) = &if_then_else.alternative {
let alternative: ExpressionID = self.resolve_expression(alternative, &scope)?;
self.types.bind(alternative, &TypeProto::unit(TypeUnit::Generic(consequent)))?;
arguments.push(alternative);
}

let expression_id = self.register_new_expression(arguments);
self.expression_tree.values.insert(expression_id, ExpressionOperation::IfThenElse);
self.types.bind(expression_id, &TypeProto::unit(TypeUnit::Generic(consequent)))?;
expression_id
}
statement => {
return Err(RuntimeError::new(format!("Statement {} is not supported in an imperative context.", statement)))
}
Expand Down
24 changes: 18 additions & 6 deletions src/transpiler/python/imperative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,25 @@ fn transpile_block(implementation: &FunctionImplementation, context: &FunctionCo
}
}
ExpressionOperation::IfThenElse => {
let children = &implementation.expression_tree.children[&statement];
// TODO Handle inner if-then-elses as elif instead of inner else: if:
let condition = transpile_expression(children[0], context);
let consequent = transpile_as_block(implementation, context, &children[1], false);
let alternative = children.get(2).map(|a| transpile_as_block(implementation, context, a, false));
// Build up elifs from nested if else { if } expressions
let mut current_if = Some((
&implementation.expression_tree.values[statement],
statement
));
let mut if_thens = vec![];

Box::new(ast::Statement::IfThenElse(vec![(condition, consequent)], alternative))
while let Some((ExpressionOperation::IfThenElse, expression)) = current_if {
let children = &implementation.expression_tree.children[expression];
let condition = transpile_expression(children[0], context);
let consequent = transpile_as_block(implementation, context, &children[1], false);

if_thens.push((condition, consequent));
current_if = children.get(2).map(|a| (&implementation.expression_tree.values[a], a));
};

let alternative = current_if.map(|(_, a)| transpile_as_block(implementation, context, a, false));

Box::new(ast::Statement::IfThenElse(if_thens, alternative))
}
_ => Box::new(ast::Statement::Expression(transpile_expression(*statement, context))),
});
Expand Down
2 changes: 1 addition & 1 deletion test-code/control_flow/if_then_else.monoteny
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
def main! :: {
if true :: _write_line("true")
-- else :: if false :: _write_line("false")
else :: if false :: _write_line("false")
else :: _write_line("maybe");
};

Expand Down

0 comments on commit 9c898ec

Please sign in to comment.