Actually just three programming languages in a trenchcoat
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Redo `with` syntax.

Similar to redoing `match`, the `when` cases of a `with` expression
are now within braces, and the `else` clause is optional and cannot
have a binding.

+218 -248
-4
TODO.md
··· 10 10 * Something wrong with `or` patterns when running JIT 11 11 * Allow `with {}` (with a block) 12 12 * Make blocks and expressions more interchangeable 13 - * Rethink syntax of cases (`with`) 14 - * Add braces like most languages use 15 - * `else yield` is default fallback for `when` 16 - * Remove binding from `else _ then {}` case, as it will be optional and could just be a regular last case 17 13 * Do a proper standard library design, maybe include a prelude 18 14 * Type-agnostic global functions (similar to core, but safe) 19 15 * Consistent interfaces to individual core standard modules
+2 -1
samples/first_class_resume.tri
··· 4 4 func doubleInto x into = into (2 * x) 5 5 6 6 proc main!() { 7 - exit with divBy 8 0 7 + exit with divBy 8 0 { 8 8 when 'INF cancel doubleInto 2 (resume) 9 9 else yield 10 + } 10 11 }
+6 -3
samples/handler.tri
··· 3 3 func divBy x y = x / y 4 4 5 5 proc main!() { 6 - let x = with divBy 3 0 6 + let x = with divBy 3 0 { 7 7 when 'NAN cancel 0 8 8 when 'INF resume 1 9 9 else yield 10 + } 10 11 11 - let y = with divBy 4 "y" 12 + let y = with divBy 4 "y" { 12 13 when 'NAN cancel 9 13 14 when 'INF resume 2 14 15 else yield 16 + } 15 17 16 - let z = with divBy 4 2 18 + let z = with divBy 4 2 { 17 19 when 'NAN cancel 9 18 20 when 'INF resume 4 19 21 else yield 22 + } 20 23 21 24 exit x + y + z 22 25 }
+8 -19
spec/src/syntax-and-semantics/effects/index.tex
··· 28 28 \bnfor 29 29 } \\ 30 30 \bnfmore{ 31 - \bnfts{\kw{else}} 32 - \bnfsp 33 - \bnfpn{Binding} 34 - \bnfsp 35 - \bnfpn{Handler} 31 + \bnfpn{EffectHandler} 36 32 \bnfor 37 - } \\ 38 - \bnfmore{ 39 33 \bnfts{\kw{else}} 40 34 \bnfsp 41 - \bnfpn{Expression} 35 + \bnfpn{Handler} 42 36 } \\ 43 37 \bnfprod{EffectHandler}{ 44 38 \bnfts{\kw{when}} ··· 70 64 \bnfmore{ 71 65 \bnfts{\kw{then}} 72 66 \bnfsp 73 - \bnfpn{Expression} 74 - \bnfor 75 67 \bnfpn{Block} 76 68 \bnfor 77 - } \\ 78 - \bnfmore{ 79 69 \bnfts{\kw{yield}} 80 70 \bnfsp 81 71 \bnfpn{Expression} ··· 85 75 \end{bnf*} 86 76 87 77 Effect handlers are defined with \kw{when} and are either written in functional 88 - or imperative style. At the end of a chain of handlers, the \kw{else} clause is 89 - included to describe what to do in the case of no handler matching; the default 90 - choice should be \kw{else yield}, but in some situations there may be reason to 91 - do otherwise. 78 + or imperative style. At the end of a chain of handlers, an \kw{else} clause may be 79 + included to describe what to do in the case of no handler matching; if omitted, 80 + the default is as if it were written \kw{else yield}. 92 81 93 82 Handlers install a contextual handler around a piece of code. When an effect is 94 83 yielded, the ``nearest'' handler with a matching pattern and guard will be used ··· 102 91 to a handler in the parent scope (a re-yielded effect never gets handled by another 103 92 handler on the same chain). 104 93 105 - A \kw{cancel} handler will not respond to the yielder, instead completing the entire expression 106 - or statement on which the handler was attached, as if the \kw{with} keyword evaluated 107 - to the value that \kw{cancel} was supplied. 94 + A \kw{cancel} handler will not respond to the yielder, instead completing the entire 95 + expression or statement on which the handler was attached, as if the \kw{with} keyword 96 + evaluated to the value that \kw{cancel} was supplied. 108 97 109 98 A \kw{resume} handler will respond with the evaluation of the expression following 110 99 the keyword. The \kw{yield} that performed the effect will evaluate to that value.
+5 -1
spec/src/syntax-and-semantics/poetry/handled.tex
··· 9 9 \bnfsp 10 10 \bnfpn{Expression} 11 11 \bnfsp 12 + \bnfts{\{} 13 + \bnfsp 12 14 \bnfpn{EffectHandlers} 15 + \bnfsp 16 + \bnfts{\}} 13 17 } 14 18 \end{bnf*} 15 19 ··· 19 23 \begin{prooftree} 20 24 \AxiomC{$\Gamma\vdash E : \tau$} 21 25 \LeftLabel{With} 22 - \UnaryInfC{$\Gamma\vdash \kw{when}\ E : \tau$} 26 + \UnaryInfC{$\Gamma\vdash \kw{with}\ E : \tau$} 23 27 \end{prooftree}
+2 -1
testsuite/captured-resume/main.tri
··· 8 8 9 9 proc main!() { 10 10 let mut res = unit 11 - with yielding!() 11 + with yielding!() { 12 12 when 'capture then{ 13 13 res = (resume) 14 14 cancel unit 15 15 } 16 16 when 'get_value resume 5 17 17 else yield 18 + } 18 19 19 20 assert res 5 == 10 20 21 assert res 20 == 25
+3 -2
testsuite/captured-return-shedding/main.tri
··· 2 2 3 3 proc inner!() { 4 4 let ret = (return) 5 - with ret 3 5 + with ret 3 { 6 6 when 'eff then { 7 7 println!("hello") 8 8 cancel false 9 9 } 10 10 else yield 11 + } 11 12 } 12 13 13 14 proc outer!() { ··· 16 17 } 17 18 18 19 proc main!() { 19 - assert with outer!() when 'eff cancel true else cancel false 20 + assert with outer!() { when 'eff cancel true else cancel false } 20 21 }
+2 -2
testsuite/effects-break-after-resume/main.tri
··· 10 10 proc main!() { 11 11 let mut x = 0 12 12 while x < 5 { 13 - with thing!(x) 13 + with thing!(x) { 14 14 when 'a(a) if a > 2 then { break unit } 15 15 when 'a(a) then { 16 16 let 'b(b) = resume a 17 17 debug::dbg!('handler(b)) 18 18 cancel unit 19 19 } 20 - else yield 20 + } 21 21 x += 1 22 22 } 23 23 assert x == 3
+2 -1
testsuite/effects-cancel-mid-resume/main.tri
··· 7 7 } 8 8 9 9 proc main!() { 10 - let x = with inner!() 10 + let x = with inner!() { 11 11 when 'in then { 12 12 if resume 'a 13 13 then cancel 1 ··· 15 15 } 16 16 when 'out cancel false 17 17 else yield 18 + } 18 19 assert "final result should be 2 but it was ${x}" as x == 2 19 20 }
+1 -1
testsuite/effects-handle-and-end/main.tri
··· 3 3 } 4 4 5 5 proc main!() { 6 - with body!() when 'eff then {} else yield 6 + with body!() { when 'eff then {} } 7 7 }
+2 -1
testsuite/effects-just-cancel/main.tri
··· 3 3 } 4 4 5 5 proc main!() { 6 - let x = with inner!() 6 + let x = with inner!() { 7 7 when 'eff cancel 2 8 8 else yield 9 + } 9 10 assert x == 2 10 11 }
+2 -1
testsuite/effects-just-resume/main.tri
··· 3 3 } 4 4 5 5 proc main!() { 6 - with inner!() 6 + with inner!() { 7 7 when 'eff resume 1 8 8 else yield 9 + } 9 10 assert "Unreachable" as false 10 11 }
+3 -2
testsuite/effects-nested-cancel/main.tri
··· 6 6 } 7 7 8 8 proc do_things!() { 9 - with do_inner!() else yield 9 + with do_inner!() { else yield } 10 10 assert "don't go here" as false 11 11 return false 12 12 } 13 13 14 14 proc main!() { 15 - assert 'hello == with do_things!() 15 + assert 'hello == with do_things!() { 16 16 when 'get_hello cancel 'hello 17 17 else yield 18 + } 18 19 println!("Made it to end") 19 20 }
+6 -4
testsuite/effects-nested/main.tri
··· 12 12 13 13 proc do_things!() { 14 14 return d!(8, 15 - with d!(6, do_inner!()) 16 - else eff then { 15 + with d!(6, do_inner!()) { 16 + when eff then { 17 17 cancel d!(7, 18 18 resume d!(4, 19 19 yield d!(2, eff) 20 20 ) 21 21 ) 22 22 } 23 + } 23 24 ) 24 25 } 25 26 26 27 proc main!() { 27 - assert d!(11, with d!(9, do_things!()) 28 + assert d!(11, with d!(9, do_things!()) { 28 29 when 'get_hello cancel d!(10, resume d!(3, 'hello)) 29 - else yield) 30 + else yield 31 + }) 30 32 dbg!("Made it to end") 31 33 }
+1 -1
testsuite/effects-none-yielded/main.tri
··· 3 3 } 4 4 5 5 proc main!() { 6 - let y = with body!() else yield 6 + let y = with body!() { else yield } 7 7 assert y == 5 8 8 }
+2 -2
testsuite/effects-resume-multiple/main.tri
··· 6 6 } 7 7 8 8 proc main!() { 9 - let result = with inner!() 9 + let result = with inner!() { 10 10 when a:b then { 11 11 let first = resume a 12 12 let second = resume b 13 13 cancel first:second 14 14 } 15 - else yield 15 + } 16 16 assert "result is ${result}" as result == 1:2 17 17 }
+2 -1
testsuite/effects-skip-handler/main.tri
··· 4 4 } 5 5 6 6 proc outer!() { 7 - return with inner!() 7 + return with inner!() { 8 8 when 'done then { return 3 } 9 9 else yield 10 + } 10 11 } 11 12 12 13 proc main!() {
+2 -1
testsuite/effects-through-more-returns/main.tri
··· 11 11 } 12 12 13 13 proc main!() { 14 - let x = with process!() 14 + let x = with process!() { 15 15 when 'both then { 16 16 let a = resume true 17 17 let b = resume false 18 18 cancel a:b 19 19 } 20 20 else yield 21 + } 21 22 assert x == (('a:'c):('a:'d)):(('b:'c):('b:'d)) 22 23 }
+2 -1
testsuite/effects-through-return/main.tri
··· 10 10 } 11 11 12 12 proc main!() { 13 - let result = with inner!() 13 + let result = with inner!() { 14 14 when a:b then { 15 15 let first = resume a 16 16 let second = resume b 17 17 cancel first:second 18 18 } 19 19 else yield 20 + } 20 21 assert "result is ${result}" as result == 1:2 21 22 }
+1 -1
testsuite/effects-yield-fallback/main.tri
··· 3 3 } 4 4 5 5 proc main!() { 6 - with body!() else yield 6 + with body!() { else yield } 7 7 exit 1 8 8 }
+2 -2
testsuite/effects-yield-in-loop/main.tri
··· 12 12 13 13 proc main!() { 14 14 let mut x = 0 15 - let result = with the_loop!() 15 + let result = with the_loop!() { 16 16 when 'a(a) then { 17 17 let 'b(b) = resume 'b(a) 18 18 debug::dbg!('handler(b)) 19 19 cancel 'b(b + 1) 20 20 } 21 - else yield 21 + } 22 22 assert result == 'b(3) 23 23 }
+2 -2
testsuite/effects-yield-into-call/main.tri
··· 5 5 } 6 6 7 7 proc main!() { 8 - with inner!() 8 + with inner!() { 9 9 when 'a then { 10 10 resume 1 11 11 become 2 12 12 } 13 - else yield 13 + } 14 14 }
+3 -2
testsuite/effects-yield-nested/main.tri
··· 6 6 } 7 7 8 8 proc do_things!() { 9 - return with do_inner!() else yield 9 + return with do_inner!() { else yield } 10 10 } 11 11 12 12 proc main!() { 13 - assert with do_things!() 13 + assert with do_things!() { 14 14 when 'get_hello resume 'hello 15 15 else yield 16 + } 16 17 println!("Made it to end") 17 18 }
+4 -4
testsuite/koka-example/main.tri
··· 5 5 } 6 6 7 7 proc choice!(action) { 8 - return with [action!()] 8 + return with [action!()] { 9 9 when 'choice then { 10 10 cancel [..resume false, ..resume true] 11 11 } 12 - else yield 12 + } 13 13 } 14 14 15 15 proc surprising!() { ··· 21 21 22 22 proc pstate!(init, action) { 23 23 let mut state = init 24 - let result = with action!() 24 + let result = with action!() { 25 25 when 'get resume state 26 26 when 'set(val) then { 27 27 state = val 28 28 become unit 29 29 } 30 - else yield 30 + } 31 31 return result:state 32 32 } 33 33
+3 -3
testsuite/member-access/main.tri
··· 1 1 proc main!() { 2 2 assert [1, 2, 3].2 == 3 3 3 assert [1, 2, 3].0 == 1 4 - assert with [1, 2, 3].4 when 'mia cancel true else cancel false 4 + assert with [1, 2, 3].4 { when 'mia cancel true else cancel false } 5 5 6 6 assert "hello".4 == 'o' 7 - assert with "hello".5 when 'mia cancel true else cancel false 7 + assert with "hello".5 { when 'mia cancel true else cancel false } 8 8 9 9 assert {|'a' => 0, 'b' => 1, 'c' => 2|}.'a' == 0 10 10 assert {|0 => 'a', 1 => 'b', 2 => 'c'|}.0 == 'a' 11 - assert with {|0 => 'a', 1 => 'b', 2 => 'c'|}.3 when 'mia cancel true else cancel false 11 + assert with {|0 => 'a', 1 => 'b', 2 => 'c'|}.3 { when 'mia cancel true else cancel false } 12 12 }
+3 -2
testsuite/non-captured-return-shedding/main.tri
··· 1 1 import "trilogy:io" use println 2 2 3 3 proc inner!() { 4 - with return 3 4 + with return 3 { 5 5 when 'eff then { 6 6 println!("hello") 7 7 cancel false 8 8 } 9 9 else yield 10 + } 10 11 } 11 12 12 13 proc outer!() { ··· 15 16 } 16 17 17 18 proc main!() { 18 - assert with outer!() when 'eff cancel true else cancel false 19 + assert with outer!() { when 'eff cancel true else cancel false } 19 20 }
+2 -1
testsuite/recursion-depth-yields/main.tri
··· 3 3 proc recursive!(i) { 4 4 if i % 100_000 == 0 { dbg!(i) } 5 5 if i == 1_000_000 { return unit } 6 - with yield 'recurse 6 + with yield 'recurse { 7 7 when 'recurse resume recursive!(i + 1) 8 8 else yield 9 + } 9 10 } 10 11 11 12 proc main!() {
+2 -2
testsuite/unison-example/main.tri
··· 9 9 10 10 proc in_memory_with_map!(action) { 11 11 let mut map = {||} 12 - let result = with action!() 12 + let result = with action!() { 13 13 when 'get(k) resume match map { 14 14 case {| ^k => v, .._ |} then 'some(v) 15 15 else 'none ··· 18 18 map.k = v 19 19 become unit 20 20 } 21 - else yield 21 + } 22 22 return result:map 23 23 } 24 24
+1 -6
trilogy-ir/src/ir/handler.rs
··· 74 74 converter.scope.set_allow_resume_cancel(false); 75 75 let else_span = handler.else_token().span; 76 76 let effect = Identifier::temporary(converter, else_span); 77 - let pattern = handler 78 - .identifier 79 - .map(|id| Expression::reference(id.span(), Identifier::declare(converter, id))) 80 - .unwrap_or_else(|| Expression::wildcard(else_span)); 81 - let pattern = Expression::reference(else_span, effect.clone()) 82 - .and(else_span.union(pattern.span), pattern); 77 + let pattern = Expression::reference(else_span, effect.clone()); 83 78 let guard = Expression::boolean(else_span, true); 84 79 converter.scope.set_allow_resume_cancel(true); 85 80 let body = Self::convert_strategy(converter, handler.strategy, effect);
+8 -4
trilogy-llvm/src/expression/mod.rs
··· 338 338 self.begin_next_function(next_case_function); 339 339 } 340 340 341 - // A handler is always complete by the syntax requiring an `else` case at the end, so the last 342 - // branch is never reachable. 343 - let unreachable = self.builder.build_unreachable().unwrap(); 344 - self.end_continuation_point_as_clean(unreachable); 341 + self.push_handler_scope(resume); 342 + let effect = self.use_temporary_clone(effect).unwrap(); 343 + let returned = self.call_yield(effect, ""); 344 + let resumed = self.call_resume(returned, ""); 345 + let cancel = self.allocate_value(""); 346 + self.trilogy_value_clone_into(cancel, self.get_cancel()); 347 + self.call_known_continuation(cancel, resumed); 348 + self.pop_handler_scope(); 345 349 } 346 350 347 351 fn compile_assertion(&self, assertion: &ir::Assert, name: &str) -> Option<PointerValue<'ctx>> {
+6 -20
trilogy-parser/src/syntax/else_handler.rs
··· 1 - use super::{Identifier, *}; 1 + use super::*; 2 2 use crate::{Parser, Spanned}; 3 3 use source_span::Span; 4 - use trilogy_scanner::{ 5 - Token, 6 - TokenType::{self, *}, 7 - }; 4 + use trilogy_scanner::{Token, TokenType}; 8 5 9 6 /// A fallback `else` handler for a handled `when` statement or expression. 10 7 #[derive(Clone, Debug, PrettyPrintSExpr)] 11 8 pub struct ElseHandler { 12 9 pub r#else: Token, 13 - pub identifier: Option<Identifier>, 14 10 pub strategy: HandlerStrategy, 15 11 span: Span, 16 12 } 17 13 18 14 impl ElseHandler { 19 15 pub(crate) fn parse(parser: &mut Parser) -> SyntaxResult<Self> { 20 - let r#else = parser.expect(KwElse).unwrap(); 21 - 22 - let identifier = if parser.check(TokenType::Identifier).is_ok() { 23 - Some(Identifier::parse(parser).unwrap()) 24 - } else { 25 - None 26 - }; 27 - 16 + let r#else = parser.expect(TokenType::KwElse).unwrap(); 28 17 let strategy = HandlerStrategy::parse(parser)?; 29 18 30 19 Ok(Self { 31 20 span: r#else.span.union(strategy.span()), 32 21 r#else, 33 - identifier, 34 22 strategy, 35 23 }) 36 24 } ··· 50 38 mod test { 51 39 use super::*; 52 40 53 - test_parse!(elsehandler_yield: "else yield" => ElseHandler::parse => "(ElseHandler _ () _)"); 54 - test_parse!(elsehandler_resume_without_id: "else resume 3" => ElseHandler::parse => "(ElseHandler _ () _)"); 55 - test_parse!(elsehandler_resume_with_id: "else x resume x" => ElseHandler::parse => "(ElseHandler _ (Identifier) _)"); 56 - test_parse!(elsehandler_cancel_without_id: "else cancel 3" => ElseHandler::parse => "(ElseHandler _ () _)"); 57 - test_parse!(elsehandler_cancel_with_id: "else x cancel x" => ElseHandler::parse => "(ElseHandler _ (Identifier) _)"); 41 + test_parse!(elsehandler_yield: "else yield" => ElseHandler::parse => "(ElseHandler _ _)"); 42 + test_parse!(elsehandler_resume: "else resume 3" => ElseHandler::parse => "(ElseHandler _ _)"); 43 + test_parse!(elsehandler_cancel: "else cancel 3" => ElseHandler::parse => "(ElseHandler _ _)"); 58 44 }
+33 -18
trilogy-parser/src/syntax/handled_expression.rs
··· 7 7 pub struct HandledExpression { 8 8 pub with: Token, 9 9 pub expression: Expression, 10 + pub obrace: Token, 10 11 pub handlers: Vec<Handler>, 12 + pub cbrace: Token, 11 13 span: Span, 12 14 } 13 15 ··· 25 27 26 28 let expression = Expression::parse(parser)?; 27 29 30 + let obrace = parser 31 + .expect(OBrace) 32 + .map_err(|token| parser.expected(token, "expected { to begin `with` handlers"))?; 33 + 28 34 let mut handlers = vec![]; 29 - loop { 35 + let cbrace = loop { 36 + if let Ok(cbrace) = parser.expect(CBrace) { 37 + break cbrace; 38 + } 30 39 if let Err(token) = parser.check([KwWhen, KwElse]) { 31 40 let error = SyntaxError::new( 32 41 token.span, 33 - "expected `when`, or `else` to with an effect handler", 42 + "expected `when`, or `else` to start an effect handler", 34 43 ); 35 44 parser.error(error.clone()); 36 45 return Err(error); ··· 39 48 let end = matches!(handler, Handler::Else(..)); 40 49 handlers.push(handler); 41 50 if end { 42 - return Ok(Self { 43 - span: with.span.union(handlers.last().unwrap().span()), 44 - with, 45 - expression, 46 - handlers, 47 - }); 51 + break parser.expect(CBrace).map_err(|token| { 52 + parser.expected(token, "expected } to end `with` handlers") 53 + })?; 48 54 } 49 - } 55 + }; 56 + Ok(Self { 57 + span: with.span.union(handlers.last().unwrap().span()), 58 + with, 59 + expression, 60 + obrace, 61 + handlers, 62 + cbrace, 63 + }) 50 64 } 51 65 } 52 66 ··· 54 68 mod test { 55 69 use super::*; 56 70 57 - test_parse!(handled_expr_else_yield: "with 3 else yield" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::Else _)])"); 58 - test_parse!(handled_expr_else_resume: "with 3 else resume 3" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::Else _)])"); 59 - test_parse!(handled_expr_else_cancel: "with 3 else cancel 3" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::Else _)])"); 60 - test_parse!(handled_expr_yield: "with 3 when 'x yield else yield" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::When _) (Handler::Else _)])"); 61 - test_parse_error!(handled_expr_resume_block: "with 3 when 'x resume {} else yield" => HandledExpression::parse); 62 - test_parse_error!(handled_expr_cancel_block: "with 3 when 'x cancel {} else yield" => HandledExpression::parse); 63 - test_parse!(handled_expr_resume_expr: "with 3 when 'x resume 3 else yield" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::When _) (Handler::Else _)])"); 64 - test_parse!(handled_expr_cancel_expr: "with 3 when 'x cancel 3 else yield" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::When _) (Handler::Else _)])"); 65 - test_parse!(handled_expr_multiple_yield: "with 3 when 'x yield when 'y yield else yield" => HandledExpression::parse => "(HandledExpression _ _ [(Handler::When _) (Handler::When _) (Handler::Else _)])"); 71 + test_parse!(handled_expr_else_yield: "with 3 { else yield }" => HandledExpression::parse => "(HandledExpression _ _ _ [(Handler::Else _)] _)"); 72 + test_parse!(handled_expr_else_resume: "with 3 { else resume 3 }" => HandledExpression::parse => "(HandledExpression _ _ _ [(Handler::Else _)] _)"); 73 + test_parse!(handled_expr_else_cancel: "with 3 { else cancel 3 }" => HandledExpression::parse => "(HandledExpression _ _ _ [(Handler::Else _)] _)"); 74 + test_parse!(handled_expr_yield: "with 3 { when 'x yield else yield }" => HandledExpression::parse => "(HandledExpression _ _ _ [(Handler::When _) (Handler::Else _)] _)"); 75 + test_parse_error!(handled_expr_resume_block: "with 3 { when 'x resume {} else yield }" => HandledExpression::parse); 76 + test_parse_error!(handled_expr_cancel_block: "with 3 { when 'x cancel {} else yield }" => HandledExpression::parse); 77 + test_parse!(handled_expr_resume_expr: "with 3 { when 'x resume 3 else yield }" => HandledExpression::parse => "(HandledExpression _ _ _ [(Handler::When _) (Handler::Else _)] _)"); 78 + test_parse!(handled_expr_cancel_expr: "with 3 { when 'x cancel 3 else yield }" => HandledExpression::parse => "(HandledExpression _ _ _ [(Handler::When _) (Handler::Else _)] _)"); 79 + test_parse!(handled_expr_multiple_yield: "with 3 { when 'x yield when 'y yield else yield }" => HandledExpression::parse => "(HandledExpression _ _ _ [(Handler::When _) (Handler::When _) (Handler::Else _)] _)"); 66 80 test_parse_error!(handled_expr_block: "with {} else yield" => HandledExpression::parse); 81 + test_parse!(handled_expr_no_else: "with 3 { when 'x yield }" => HandledExpression::parse => "(HandledExpression _ _ _ [(Handler::When _)] _)"); 67 82 }
+1 -1
trilogy-parser/src/syntax/handler.rs
··· 23 23 use super::*; 24 24 25 25 test_parse!(handler_when: "when 'NAN resume 5" => Handler::parse => "(Handler::When (WhenHandler _ _ _ _))"); 26 - test_parse!(handler_else: "else n resume 5" => Handler::parse => "(Handler::Else (ElseHandler _ _ _))"); 26 + test_parse!(handler_else: "else resume 5" => Handler::parse => "(Handler::Else (ElseHandler _ _))"); 27 27 }
+16 -42
trilogy/src/stdlib/array.tri
··· 112 112 113 113 test "array reduce" { 114 114 assert reduce (+) [1, 2, 3, 4] == 10 115 - assert with (reduce (+) []; false) 116 - when 'mia cancel true 117 - else yield 115 + assert with (reduce (+) []; false) { when 'mia cancel true } 118 116 assert reduce (:) [1, 2, 3] == (1:2):3 119 117 } 120 118 ··· 123 121 124 122 test "array rreduce" { 125 123 assert rreduce (+) [1, 2, 3, 4] == 10 126 - assert with (rreduce (+) []; false) 127 - when 'mia cancel true 128 - else yield 124 + assert with (rreduce (+) []; false) { when 'mia cancel true } 129 125 assert rreduce (:) [1, 2, 3] == (3:2):1 130 126 } 131 127 ··· 172 168 173 169 test "array first" { 174 170 assert first [1, 2, 3] == 1 175 - assert with (first []; false) 176 - when 'mia cancel true 177 - else yield 171 + assert with (first []; false) { when 'mia cancel true } 178 172 } 179 173 180 174 func last [] = yield 'mia ··· 182 176 183 177 test "array last" { 184 178 assert last [1, 2, 3] == 3 185 - assert with (last []; false) 186 - when 'mia cancel true 187 - else yield 179 + assert with (last []; false) { when 'mia cancel true } 188 180 } 189 181 190 182 func tail [] = yield 'mia ··· 192 184 193 185 test "array tail" { 194 186 assert tail [1, 2, 3] == [2, 3] 195 - assert with (tail []; false) 196 - when 'mia cancel true 197 - else yield 187 + assert with (tail []; false) { when 'mia cancel true } 198 188 } 199 189 200 190 func head [] = yield 'mia ··· 202 192 203 193 test "array head" { 204 194 assert head [1, 2, 3] == [1, 2] 205 - assert with (head []; false) 206 - when 'mia cancel true 207 - else yield 195 + assert with (head []; false) { when 'mia cancel true } 208 196 } 209 197 210 198 func slice i fin (arr and typeof 'array) = core::slice i fin arr ··· 214 202 assert slice 1 2 [1, 2, 3] == [2] 215 203 assert slice 1 1 [1, 2, 3] == [] 216 204 assert slice 1 3 [1, 2, 3] == [2, 3] 217 - assert with (slice (-1) 2 [1, 2, 3]; false) 218 - when 'arg cancel true 219 - else yield 220 - assert with (slice 2 1 [1, 2, 3]; false) 221 - when 'arg cancel true 222 - else yield 223 - assert with (slice 0 5 [1, 2, 3]; false) 224 - when 'mia cancel true 225 - else yield 226 - assert with (slice 5 5 [1, 2, 3]; false) 227 - when 'mia cancel true 228 - else yield 205 + assert with (slice (-1) 2 [1, 2, 3]; false) { when 'arg cancel true } 206 + assert with (slice 2 1 [1, 2, 3]; false) { when 'arg cancel true } 207 + assert with (slice 0 5 [1, 2, 3]; false) { when 'mia cancel true } 208 + assert with (slice 5 5 [1, 2, 3]; false) { when 'mia cancel true } 229 209 } 230 210 231 211 func take n (arr and typeof 'array) = ··· 239 219 assert take 2 [1, 2, 3] == [1, 2] 240 220 assert take 3 [1, 2, 3] == [1, 2, 3] 241 221 assert take 12 [1, 2, 3] == [1, 2, 3] 242 - assert with (take (-1) [1, 2, 3]; false) 243 - when 'arg cancel true 244 - else yield 222 + assert with (take (-1) [1, 2, 3]; false) { when 'arg cancel true } 245 223 } 246 224 247 225 func skip n (arr and typeof 'array) = ··· 255 233 assert skip 2 [1, 2, 3] == [3] 256 234 assert skip 3 [1, 2, 3] == [] 257 235 assert skip 12 [1, 2, 3] == [] 258 - assert with (skip (-1) [1, 2, 3]; false) 259 - when 'arg cancel true 260 - else yield 236 + assert with (skip (-1) [1, 2, 3]; false) { when 'arg cancel true } 261 237 } 262 238 263 239 func drop n (arr and typeof 'array) = ··· 271 247 assert drop 2 [1, 2, 3] == [1] 272 248 assert drop 3 [1, 2, 3] == [] 273 249 assert drop 12 [1, 2, 3] == [] 274 - assert with (drop (-1) [1, 2, 3]; false) 275 - when 'arg cancel true 276 - else yield 250 + assert with (drop (-1) [1, 2, 3]; false) { when 'arg cancel true } 277 251 } 278 252 279 253 func collect iterator = 280 254 let arr = [], 281 - with (iterator!(); arr) 255 + with (iterator!(); arr) { 282 256 when 'next(val) then { 283 257 push!(arr, val) 284 258 become unit 285 259 } 286 - else yield 260 + } 287 261 288 262 test "array collect" { 289 263 let iterator = do() { ··· 302 276 assert chunks 3 [1, 2, 3, 4, 5, 6, 7, 8, 9] == [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 303 277 assert chunks 3 [1, 2, 3, 4, 5, 6, 7] == [[1, 2, 3], [4, 5, 6], [7]] 304 278 assert chunks 1 [1, 2, 3] == [[1], [2], [3]] 305 - with chunks 0 when 'arg cancel unit else yield 279 + with chunks 0 { when 'arg cancel unit } 306 280 } 307 281 308 282 func merge _ a [] = a
+3 -2
trilogy/src/stdlib/core.tri
··· 405 405 406 406 for test_name:test_procedure in tests { 407 407 c::print!("test ${test_name} ... ") 408 - with test_procedure!() 408 + with test_procedure!() { 409 409 when 'assertion_failed(msg) then { 410 410 c::print!(red "assertion failed") 411 411 c::print!(": ${msg}\n") 412 412 failures += 1 413 413 continue unit 414 414 } 415 - else eff then { 415 + when eff then { 416 416 c::print!(red "failure") 417 417 c::print!(": unhandled effect yielded from test: ${eff}\n") 418 418 failures += 1 419 419 continue unit 420 420 } 421 + } 421 422 c::print!(green "ok") 422 423 c::print!("\n") 423 424 successes += 1
+2 -2
trilogy/src/stdlib/grid.tri
··· 83 83 } 84 84 85 85 proc shortest_path_length!(grid, from, to) { 86 - return with algorithm::shortest_path_length!(from, to) 86 + return with algorithm::shortest_path_length!(from, to) { 87 87 when 'neighbours(from_pos) resume 88 88 adjacent from_pos 89 89 |> it::from 90 90 |> it::filter (fn p. contains_key p grid) 91 91 |> it::map (fn p. p:grid.p) 92 92 |> array::collect 93 - else yield 93 + } 94 94 }
+2 -2
trilogy/src/stdlib/heap.tri
··· 52 52 53 53 func collect iterator = 54 54 let heap = [], 55 - with (iterator!(); heap) 55 + with (iterator!(); heap) { 56 56 when 'next(val) then { 57 57 push!(heap, val) 58 58 become unit 59 59 } 60 - else yield 60 + } 61 61 } 62 62 63 63 test "heap push" {
+2 -2
trilogy/src/stdlib/io.tri
··· 42 42 export readlines 43 43 proc readlines!() { 44 44 while true { 45 - let line = with readline!() 45 + let line = with readline!() { 46 46 when 'eof cancel break unit 47 - else yield 47 + } 48 48 yield 'next(line) 49 49 } 50 50 }
+40 -38
trilogy/src/stdlib/iterator.tri
··· 31 31 } 32 32 33 33 test "iterator of" { 34 - assert 3 == with run <| of 3 when 'next(val) cancel val else yield 35 - assert unit == with run <| of 3 when 'next(3) resume 1 else yield 34 + assert 3 == with run <| of 3 { when 'next(val) cancel val } 35 + assert unit == with run <| of 3 { when 'next(3) resume 1 } 36 36 assert collect <| of 3 == [3] 37 37 } 38 38 ··· 48 48 49 49 func take n it = do() { 50 50 let mut i = 0 51 - with it!() 51 + with it!() { 52 52 when 'next(val) if i < n then { 53 53 i += 1 54 54 become yield 'next(val) 55 55 } 56 56 when 'next(_) cancel unit 57 - else yield 57 + } 58 58 } 59 59 60 60 test "iterator take" { ··· 69 69 func chunks 0 _ = yield 'arg 70 70 func chunks n it = do() { 71 71 let mut chunk = [] 72 - with it!() 72 + with it!() { 73 73 when 'next(item) then { 74 74 chunk = [..chunk, item] 75 75 if array::length chunk == n { ··· 78 78 } 79 79 become unit 80 80 } 81 - else yield 81 + } 82 82 if chunk != [] { yield 'next(chunk) } 83 83 } 84 84 ··· 86 86 assert collect <| chunks 3 <| range 1 9 == [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 87 87 assert collect <| chunks 3 <| range 1 7 == [[1, 2, 3], [4, 5, 6], [7]] 88 88 assert collect <| chunks 1 <| range 1 3 == [[1], [2], [3]] 89 - with chunks 0 when 'arg cancel unit else yield 89 + with chunks 0 { when 'arg cancel unit } 90 90 } 91 91 92 92 func range_step _ _ 0 = yield 'arg ··· 142 142 } 143 143 144 144 func filter predicate it = do() { 145 - with it!() 145 + with it!() { 146 146 when 'next(val) if predicate val resume yield 'next(val) 147 147 when 'next(_) resume unit 148 - else yield 148 + } 149 149 } 150 150 151 151 test "iterator filter" { ··· 153 153 } 154 154 155 155 func map f it = do() { 156 - with it!() 156 + with it!() { 157 157 when 'next(val) resume yield 'next(f val) 158 - else yield 158 + } 159 159 } 160 160 161 161 test "iterator map" { ··· 163 163 } 164 164 165 165 func flat_map f it = do() { 166 - with it!() 166 + with it!() { 167 167 when 'next(val) then { 168 168 let inner = f val 169 169 inner!() 170 170 become unit 171 171 } 172 - else yield 172 + } 173 173 } 174 174 175 175 test "iterator flat_map" { ··· 178 178 179 179 func scan f a it = do() { 180 180 let mut state = a 181 - with it!() 181 + with it!() { 182 182 when 'next(val) then { 183 183 state = f state val 184 184 become yield 'next(state) 185 185 } 186 - else yield 186 + } 187 187 } 188 188 189 189 test "iterator scan" { ··· 192 192 193 193 func fold f a it = 194 194 let mut state = a, 195 - with it!(); state 195 + with it!(); state { 196 196 when 'next(val) then { 197 197 state = f state val 198 198 become unit 199 199 } 200 - else yield 200 + } 201 201 202 202 test "iterator fold" { 203 203 assert fold (:) 0 <| range 1 5 == ((((0:1):2):3):4):5 ··· 206 206 func reduce f it = 207 207 let mut state = 'none, 208 208 with 209 - it!(); 210 - match state { 211 - case 'some(v) then v 212 - else yield 'mia 213 - } 209 + it!(); 210 + match state { 211 + case 'some(v) then v 212 + else yield 'mia 213 + } 214 + { 214 215 when 'next(val) then { 215 216 state = match state { 216 217 case 'some(prev) then 'some(f prev val) ··· 218 219 } 219 220 become unit 220 221 } 221 - else yield 222 + } 222 223 223 224 test "iterator reduce" { 224 225 assert reduce (:) <| range 1 5 == (((1:2):3):4):5 225 - assert with reduce (:) <| rangex 0 0 when 'mia cancel true else cancel false 226 + assert with reduce (:) <| rangex 0 0 { when 'mia cancel true else cancel false } 226 227 } 227 228 228 229 func sum it = fold (+) 0 it ··· 238 239 } 239 240 240 241 func any predicate it = 241 - with it!(); false 242 + with it!(); false { 242 243 when 'next(val) then { 243 244 if predicate val { 244 245 return true 245 246 } 246 247 become unit 247 248 } 248 - else yield 249 + } 249 250 250 251 test "iterator any" { 251 252 assert any ((==) 2) <| range 1 3 ··· 254 255 } 255 256 256 257 func all predicate it = 257 - with it!(); true 258 + with it!(); true { 258 259 when 'next(val) then { 259 260 if !(predicate val) { 260 261 return false 261 262 } 262 263 become unit 263 264 } 264 - else yield 265 + } 265 266 266 267 test "iterator all" { 267 268 assert !(all (fn x. x < 2) <| range 1 3) ··· 271 272 272 273 func enumerate it = do() { 273 274 let mut i = 0 274 - with it!() 275 + with it!() { 275 276 when 'next(v) then { 276 277 let j = i 277 278 i += 1 278 279 become yield 'next(j:v) 279 280 } 280 - else yield 281 + } 281 282 } 282 283 283 284 test "iterator enumerate" { ··· 285 286 } 286 287 287 288 func find p it = 288 - with it!(); yield 'mia 289 + with it!(); yield 'mia { 289 290 when 'next(v) then { 290 291 if p v { 291 292 return v 292 293 } 293 294 become unit 294 295 } 295 - else yield 296 + } 296 297 297 298 test "iterator find" { 298 299 assert find ((==) 4) <| range 3 5 == 4 299 - assert with find ((==) 4) <| range 1 3 when 'mia cancel true else cancel false 300 + assert with find ((==) 4) <| range 1 3 { when 'mia cancel true else cancel false } 300 301 } 301 302 302 303 func choose 0 _ = do() yield 'next([]) ··· 311 312 assert collect <| choose 0 [1, 2, 3] == [[]] 312 313 } 313 314 314 - func for_each f it = with it!(); unit 315 - when 'next(v) then { 316 - f v 317 - become unit 315 + func for_each f it = 316 + with it!(); unit { 317 + when 'next(v) then { 318 + f v 319 + become unit 320 + } 318 321 } 319 - else yield 320 322 321 323 test "iterator for_each" { 322 324 let arr = []
+16 -16
trilogy/src/stdlib/parsec.tri
··· 25 25 func run_parser parser input = 26 26 let len = core::length input, 27 27 let mut pos = 0, 28 - let result = with parser!() 28 + let result = with parser!() { 29 29 when 'eof if pos == len resume true 30 30 when 'eof resume false 31 31 when 'pos resume pos ··· 39 39 pos += 1 40 40 become unit 41 41 } 42 - else yield, 42 + }, 43 43 result : core::slice pos len input 44 44 45 45 ## Parses the parser as a single atomic unit, without consuming any of the input on failure. 46 46 func atomic parser = do() { 47 47 let pos = yield 'pos 48 - return with apply parser 48 + return with apply parser { 49 49 when 'reject(_) and rej then { 50 50 yield 'reset(pos) 51 51 yield rej 52 52 } 53 - else yield 53 + } 54 54 } 55 55 56 56 ## Transform the output value of a parser without parsing any more input. ··· 70 70 ## Attempt a parser, returning 'some(result) if it succeeds. If it fails, 71 71 ## returns 'none without consuming any input. 72 72 func option parser = do() 73 - with 'some(apply <| atomic parser) 73 + with 'some(apply <| atomic parser) { 74 74 when 'reject(_) cancel 'none 75 - else yield 75 + } 76 76 77 77 ## Attempt each of the list of parsers. Returns the value of the first 78 78 ## parser that succeeds. 79 79 func choice [] = do() yield 'reject("choice had no options") 80 80 func choice [parser, ..rest] = do () { 81 - return with apply <| atomic parser 82 - when 'reject(err) cancel with apply <| choice rest 81 + return with apply <| atomic parser { 82 + when 'reject(err) cancel with apply <| choice rest { 83 83 when 'reject("choice had no options") then { 84 84 yield 'reject(err) 85 85 end ··· 88 88 yield 'reject("${err}, or ${errs}") 89 89 end 90 90 } 91 - else yield 92 - else yield 91 + } 92 + } 93 93 } 94 94 95 95 ## Applies the parser as many times as possible, returning an array of 96 96 ## the parsed results. 97 97 func many parser = do() { 98 - let result = with apply <| atomic parser 98 + let result = with apply <| atomic parser { 99 99 when 'reject(_) then { return [] } 100 - else yield 100 + } 101 101 return [result, ..apply <| many parser] 102 102 } 103 103 ··· 248 248 249 249 test "parsec digit" { 250 250 assert parse digit "123" == '1' 251 - assert with parse digit "A"; false when 'reject(_) cancel true else cancel false 251 + assert with parse digit "A"; false { when 'reject(_) cancel true else cancel false } 252 252 } 253 253 254 254 ## A parser for any base-16 digit. ··· 259 259 test "parsec hex_digit" { 260 260 assert parse hex_digit "123" == '1' 261 261 assert parse hex_digit "abc" == 'a' 262 - assert with parse hex_digit "Z"; false when 'reject(_) cancel true else cancel false 262 + assert with parse hex_digit "Z"; false { when 'reject(_) cancel true else cancel false } 263 263 } 264 264 265 265 ## Parses a base-10 integer from a string, returning the value as a number. A leading `-` sign ··· 300 300 301 301 test "parsec letter" { 302 302 assert parse letter "a" == 'a' 303 - assert with parse letter "1"; false when 'reject(_) cancel true else cancel false 303 + assert with parse letter "1"; false { when 'reject(_) cancel true else cancel false } 304 304 } 305 305 306 306 ## A parser for any ASCII whitespace. ··· 310 310 311 311 test "parsec whitespace" { 312 312 assert parse whitespace " " == ' ' 313 - assert with parse whitespace "1"; false when 'reject(_) cancel true else cancel false 313 + assert with parse whitespace "1"; false { when 'reject(_) cancel true else cancel false } 314 314 } 315 315 316 316 ## A parser for any word (a sequence of word characters `[A-Za-z0-9_]`).
+2 -2
trilogy/src/stdlib/record.tri
··· 29 29 30 30 func collect iterator = 31 31 let record = {||}, 32 - with (iterator!(); record) 32 + with (iterator!(); record) { 33 33 when 'next(key:val) then { 34 34 record.key = val 35 35 become unit 36 36 } 37 - else yield 37 + } 38 38 39 39 test "record collect" { 40 40 let iterator = do() {
+2 -2
trilogy/src/stdlib/set.tri
··· 51 51 52 52 func collect iterator = 53 53 let set = [||], 54 - with (iterator!(); set) 54 + with (iterator!(); set) { 55 55 when 'next(val) then { 56 56 push!(set, val) 57 57 become unit 58 58 } 59 - else yield 59 + } 60 60 61 61 test "set collect" { 62 62 let iterator = do() {
+9 -23
trilogy/src/stdlib/string.tri
··· 43 43 assert slice 1 2 "123" == "2" 44 44 assert slice 1 1 "123" == "" 45 45 assert slice 1 3 "123" == "23" 46 - assert with (slice (-1) 2 "123"; false) 47 - when 'arg cancel true 48 - else yield 49 - assert with (slice 2 1 "123"; false) 50 - when 'arg cancel true 51 - else yield 52 - assert with (slice 0 5 "123"; false) 53 - when 'mia cancel true 54 - else yield 55 - assert with (slice 5 5 "123"; false) 56 - when 'mia cancel true 57 - else yield 46 + assert with (slice (-1) 2 "123"; false) { when 'arg cancel true } 47 + assert with (slice 2 1 "123"; false) { when 'arg cancel true } 48 + assert with (slice 0 5 "123"; false) { when 'mia cancel true } 49 + assert with (slice 5 5 "123"; false) { when 'mia cancel true } 58 50 } 59 51 60 52 func take n (str and typeof 'string) = ··· 68 60 assert take 2 "123" == "12" 69 61 assert take 3 "123" == "123" 70 62 assert take 12 "123" == "123" 71 - assert with (take (-1) "123"; false) 72 - when 'arg cancel true 73 - else yield 63 + assert with (take (-1) "123"; false) { when 'arg cancel true } 74 64 } 75 65 76 66 func skip n (str and typeof 'string) = ··· 84 74 assert skip 2 "123" == "3" 85 75 assert skip 3 "123" == "" 86 76 assert skip 12 "123" == "" 87 - assert with (skip (-1) "123"; false) 88 - when 'arg cancel true 89 - else yield 77 + assert with (skip (-1) "123"; false) { when 'arg cancel true } 90 78 } 91 79 92 80 func drop n (str and typeof 'string) = ··· 100 88 assert drop 2 "123" == "1" 101 89 assert drop 3 "123" == "" 102 90 assert drop 12 "123" == "" 103 - assert with (drop (-1) "123"; false) 104 - when 'arg cancel true 105 - else yield 91 + assert with (drop (-1) "123"; false) { when 'arg cancel true } 106 92 } 107 93 108 94 func starts_with prefix string = take (length prefix) string == prefix ··· 208 194 209 195 func collect iterator = 210 196 let mut str = "", 211 - with (iterator!(); str) 197 + with (iterator!(); str) { 212 198 when 'next(val) then { 213 199 str <>= core::to_string val 214 200 become unit 215 201 } 216 - else yield 202 + } 217 203 218 204 test "string collect" { 219 205 let string_iter = do() {