Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions compiler-lib/src/do_compile/nodes/for_statement.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
use aria_parser::ast::{
AssignStatement, BreakStatement, CodeBlock, DeclarationId, ElsePiece, Expression, Identifier,
IfCondPiece, IfPiece, IfStatement, ParenExpression, PostfixExpression, PostfixRvalue, Primary,
Statement, UnaryOperation, ValDeclStatement, WhileStatement,
IfCondExpr, IfCondPiece, IfPiece, IfStatement, ParenExpression, PostfixExpression,
PostfixRvalue, Primary, Statement, UnaryOperation, ValDeclStatement, WhileStatement,
};

use crate::do_compile::{CompilationResult, CompileNode, CompileParams};
Expand Down Expand Up @@ -115,7 +115,7 @@ impl<'a> CompileNode<'a> for aria_parser::ast::ForStatement {
// if !__for__any_hit { <do the else block if any> }
let if_not_any_hit = IfCondPiece {
loc: self.loc.clone(),
expression: Box::new(check_any_hit_expr),
expression: IfCondExpr::Expression(check_any_hit_expr),
then: CodeBlock {
loc: self.loc.clone(),
entries: if let Some(els) = &self.els {
Expand Down Expand Up @@ -183,7 +183,7 @@ impl<'a> CompileNode<'a> for aria_parser::ast::ForStatement {
iff: IfPiece {
content: IfCondPiece {
loc: self.loc.clone(),
expression: Box::new(check_done_expr),
expression: IfCondExpr::Expression(check_done_expr),
then: if_done_blk,
},
},
Expand Down
9 changes: 9 additions & 0 deletions compiler-lib/src/do_compile/nodes/if_cond_case.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
use crate::do_compile::{CompilationResult, CompileNode, CompileParams};

impl<'a> CompileNode<'a> for aria_parser::ast::IfCondCase {
fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult {
self.target.do_compile(params)?;
self.pattern.do_compile(params)
}
}
11 changes: 11 additions & 0 deletions compiler-lib/src/do_compile/nodes/if_cond_expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: Apache-2.0
use crate::do_compile::{CompilationResult, CompileNode, CompileParams};

impl<'a> CompileNode<'a> for aria_parser::ast::IfCondExpr {
fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult {
match self {
aria_parser::ast::IfCondExpr::IfCondCase(p) => p.do_compile(params),
aria_parser::ast::IfCondExpr::Expression(e) => e.do_compile(params),
}
}
}
16 changes: 10 additions & 6 deletions compiler-lib/src/do_compile/nodes/match_pattern_enum_case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,22 @@ use crate::{
func_builder::BasicBlockOpcode,
};

// in theory you may use __match_control_expr, which is defined by the match statement
// but if you do, this breaks if case matches, so prefer to dup/pop as necessary instead
impl<'a> CompileNode<'a> for aria_parser::ast::MatchPatternEnumCase {
fn do_compile(&self, params: &'a mut CompileParams) -> CompilationResult {
let case_name_idx = self.insert_const_or_fail(
params,
ConstantValue::String(self.case.value.clone()),
&self.loc,
)?;
let has_decl = self.payload.is_some();
if has_decl {
params
.writer
.get_current_block()
.write_opcode_and_source_info(BasicBlockOpcode::Dup, self.loc.clone());
}
params
.writer
.get_current_block()
Expand Down Expand Up @@ -48,6 +57,7 @@ impl<'a> CompileNode<'a> for aria_parser::ast::MatchPatternEnumCase {
params
.writer
.get_current_block()
.write_opcode_and_source_info(BasicBlockOpcode::Pop, self.loc.clone())
.write_opcode_and_source_info(BasicBlockOpcode::PushFalse, self.loc.clone());
params
.writer
Expand All @@ -57,12 +67,6 @@ impl<'a> CompileNode<'a> for aria_parser::ast::MatchPatternEnumCase {
self.loc.clone(),
);
params.writer.set_current_block(if_true);
params.scope.emit_read(
"__match_control_expr",
&mut params.module.constants,
params.writer.get_current_block(),
p.loc.clone(),
)?;
params
.writer
.get_current_block()
Expand Down
2 changes: 2 additions & 0 deletions compiler-lib/src/do_compile/nodes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ mod function_body;
mod function_decl;
mod guard_block;
mod identifier;
mod if_cond_case;
mod if_cond_expr;
mod if_statement;
mod import_from_statement;
mod import_statement;
Expand Down
18 changes: 18 additions & 0 deletions docs/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,24 @@ func main() {
}
```

For simple pattern matches, i.e. one enum, and matching to a case, with our without payload extraction, `if case` is also available:

```
func main() {
val may = Maybe::Some(3);

if case Some(value) = may {
println(value); # prints 3
} elsif case None = may {
println("None"); # does not print anything
} else {
println("not a Maybe"); # does not print anything
}
}
```

If the right-hand side of `if case` is not an enum, a runtime error occurs.

## ⁉️ Maybe and Result

`Maybe` is an enum that represents a potentially missing value. It is defined as
Expand Down
11 changes: 4 additions & 7 deletions lib/aria/core/maybe.aria
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ flag: no_std;

extension Maybe {
func prettyprint() {
match this {
case None => {
return "None";
},
case Some(value) => {
return "Some({0})".format(value);
}
if case Some(value) = this {
return "Some({0})".format(value);
} else {
return "None";
}
}
}
7 changes: 4 additions & 3 deletions lib/aria/core/result.aria
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ func err(e) { return Result::Err(e); }

extension Result {
type func new_with_maybe(m: Maybe) {
match m {
case Some(v) => { return ok(v); }
case None => { return err(Unit.new()); }
if case Some(v) = m {
return ok(v);
} else {
return err(Unit.new());
}
}

Expand Down
4 changes: 2 additions & 2 deletions lib/aria/network/retry.aria
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ func retry(f, check, attempts_count = 3, delay_ms = 500) {
}
}

if last_exception.is_Some() {
return RetryResult::Exception(last_exception.unwrap_Some());
if case Some(le) = last_exception {
return RetryResult::Exception(le);
} else {
return RetryResult::Fail(last_result);
}
Expand Down
25 changes: 24 additions & 1 deletion parser-lib/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -807,10 +807,33 @@ pub struct WriteOpEqStatement {
pub val: Expression,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IfCondCase {
pub loc: SourcePointer,
pub pattern: MatchPatternEnumCase,
pub target: Expression,
}

#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IfCondExpr {
IfCondCase(IfCondCase),
Expression(Expression),
}

impl IfCondExpr {
pub fn loc(&self) -> &SourcePointer {
match self {
Self::IfCondCase(c) => &c.loc,
Self::Expression(e) => e.loc(),
}
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IfCondPiece {
pub loc: SourcePointer,
pub expression: Box<Expression>,
pub expression: IfCondExpr,
pub then: CodeBlock,
}

Expand Down
21 changes: 21 additions & 0 deletions parser-lib/src/ast/nodes/if_cond_case.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: Apache-2.0
use crate::{
ast::{
IfCondCase,
derive::Derive,
prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator},
},
gen_from_components,
};

use crate::ast::{Expression, MatchPatternEnumCase};

impl Derive for IfCondCase {
gen_from_components!(if_cond_case; pattern: MatchPatternEnumCase, target: Expression);
}

impl PrettyPrintable for IfCondCase {
fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator {
buffer << &self.pattern << " = " << &self.target
}
}
24 changes: 24 additions & 0 deletions parser-lib/src/ast/nodes/if_cond_expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: Apache-2.0
use crate::{
ast::{
IfCondExpr,
derive::Derive,
prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator},
},
gen_from_options,
};

use crate::ast::{Expression, IfCondCase};

impl Derive for IfCondExpr {
gen_from_options!(if_cond; (if_cond_case, IfCondCase), (expression, Expression));
}

impl PrettyPrintable for IfCondExpr {
fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator {
match self {
Self::IfCondCase(c) => c.prettyprint(buffer),
Self::Expression(e) => e.prettyprint(buffer),
}
}
}
6 changes: 3 additions & 3 deletions parser-lib/src/ast/nodes/if_cond_piece.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::{
ast::{
CodeBlock, Expression, IfCondPiece, SourceBuffer,
CodeBlock, IfCondExpr, IfCondPiece, SourceBuffer,
derive::Derive,
prettyprint::{PrettyPrintable, printout_accumulator::PrintoutAccumulator},
},
Expand All @@ -15,11 +15,11 @@ impl Derive for IfCondPiece {
let mut inner = p.into_inner();
let expr = inner.next().expect("need expression");
let body = inner.next().expect("need body");
let expression = Expression::from_parse_tree(expr, source);
let expression = IfCondExpr::from_parse_tree(expr, source);
let then = CodeBlock::from_parse_tree(body, source);
Self {
loc: source.pointer(loc),
expression: Box::new(expression),
expression,
then,
}
}
Expand Down
2 changes: 1 addition & 1 deletion parser-lib/src/ast/nodes/match_pattern_enum_case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl Derive for MatchPatternEnumCase {

impl PrettyPrintable for MatchPatternEnumCase {
fn prettyprint(&self, buffer: PrintoutAccumulator) -> PrintoutAccumulator {
let buffer = buffer << " case " << &self.case;
let buffer = buffer << "case " << &self.case;
if let Some(p) = &self.payload {
buffer << "(" << p << ")"
} else {
Expand Down
2 changes: 2 additions & 0 deletions parser-lib/src/ast/nodes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ mod function_decl;
mod guard_block;
mod identifier;
mod identifier_list;
mod if_cond_case;
mod if_cond_expr;
mod if_cond_piece;
mod if_piece;
mod if_statement;
Expand Down
4 changes: 3 additions & 1 deletion parser-lib/src/grammar/grammar.pest
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ val_write_stmt = { postfix_lv ~ "=" ~ expression ~ ";" }
add_op_eq = @{ "+=" | "-=" | "*=" | "/=" | "%=" }
val_add_eq_write = { postfix_lv ~ add_op_eq ~ expression ~ ";" }

if_cond_piece = { expression ~ code_block }
if_cond_case = { match_pattern_enum_case ~ "=" ~ expression }
if_cond = { if_cond_case | expression }
if_cond_piece = { if_cond ~ code_block }
if_piece = { "if" ~ if_cond_piece }
elsif_piece = { "elsif" ~ if_cond_piece }
else_piece = { "else" ~ code_block }
Expand Down
16 changes: 16 additions & 0 deletions tests/if_case_elsif.aria
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# SPDX-License-Identifier: Apache-2.0
func get_payload_value(p) {
if case Some(n) = p {
return n;
} elsif case None = p {
return -1;
} else {
return 0;
}
}

func main() {
assert get_payload_value(Maybe::Some(5)) == 5;
assert get_payload_value(Maybe::None) == -1;
assert get_payload_value(Result::Err("not a Maybe")) == 0;
}
13 changes: 13 additions & 0 deletions tests/if_case_empty.aria
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# SPDX-License-Identifier: Apache-2.0
func main() {
val x = Maybe::None;
val hit = false;

if case None = x {
hit = true;
} else {
assert false;
}

assert hit;
}
14 changes: 14 additions & 0 deletions tests/if_case_some.aria
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# SPDX-License-Identifier: Apache-2.0
func main() {
val x = Maybe::Some(3);
val hit = false;

if case Some(v) = x {
assert v == 3;
hit = true;
} else {
assert false;
}

assert hit;
}