From f2b1892362ebb94803ae3f9b0a4357f150b89245 Mon Sep 17 00:00:00 2001 From: Jordan Mackie Date: Mon, 9 May 2022 18:25:44 +0100 Subject: [PATCH 1/3] Add some more rewrite rules --- .../javascript-project/dist/A_Test.js | 2 +- .../javascript/effect_expressions.ditto | 11 ++ .../javascript/effect_expressions.js | 38 +++- .../javascript/match_expressions.ditto | 15 ++ .../javascript/match_expressions.js | 36 ++++ crates/ditto-codegen-js/src/convert.rs | 47 ++++- .../ditto-codegen-js/src/optimize/rewrites.rs | 171 +++++++++++++++++- 7 files changed, 307 insertions(+), 13 deletions(-) diff --git a/crates/ditto-cli/fixtures/javascript-project/dist/A_Test.js b/crates/ditto-cli/fixtures/javascript-project/dist/A_Test.js index 422356ba3..9b700a497 100644 --- a/crates/ditto-cli/fixtures/javascript-project/dist/A_Test.js +++ b/crates/ditto-cli/fixtures/javascript-project/dist/A_Test.js @@ -1,2 +1,2 @@ -function test_it_works(){return;} +function test_it_works(){return undefined;} export {test_it_works}; diff --git a/crates/ditto-codegen-js/golden-tests/javascript/effect_expressions.ditto b/crates/ditto-codegen-js/golden-tests/javascript/effect_expressions.ditto index 30dfb225a..cba111030 100644 --- a/crates/ditto-codegen-js/golden-tests/javascript/effect_expressions.ditto +++ b/crates/ditto-codegen-js/golden-tests/javascript/effect_expressions.ditto @@ -15,6 +15,17 @@ effect_map = (effect_a: Effect(a), fn: (a) -> b): Effect(b) -> do { return fn(a) }; +type Result(a, e) = Ok(a) | Err(e); + +always = (_a, b) -> b; + +get_names_from_result = (res) -> do { + get_name; + match res with + | Ok(a) -> always(a, get_names) + | Err(e) -> always(e, get_names) +}; + main : Effect(Unit) = do { effect_map(get_name, (name) -> unit) }; diff --git a/crates/ditto-codegen-js/golden-tests/javascript/effect_expressions.js b/crates/ditto-codegen-js/golden-tests/javascript/effect_expressions.js index b3f293bd8..f48f3a02a 100644 --- a/crates/ditto-codegen-js/golden-tests/javascript/effect_expressions.js +++ b/crates/ditto-codegen-js/golden-tests/javascript/effect_expressions.js @@ -1,3 +1,12 @@ +function Err($0) { + return ["Err", $0]; +} +function Ok($0) { + return ["Ok", $0]; +} +function always(_a, b) { + return b; +} function effect_map(effect_a, fn) { return () => { const a = effect_a(); @@ -15,4 +24,31 @@ function get_names() { const another_name = get_name(); return [name, another_name]; } -export { effect_map, get_name, get_names, main }; +function get_names_from_result(res) { + return () => { + get_name(); + return (() => { + if (res[0] === "Ok") { + const a = res[1]; + return always(a, get_names); + } + if (res[0] === "Err") { + const e = res[1]; + return always(e, get_names); + } + return () => { + throw new Error("Pattern match error"); + }; + })()(); + }; +} +export { + Err, + Ok, + always, + effect_map, + get_name, + get_names, + get_names_from_result, + main, +}; diff --git a/crates/ditto-codegen-js/golden-tests/javascript/match_expressions.ditto b/crates/ditto-codegen-js/golden-tests/javascript/match_expressions.ditto index 51ae39ad8..b9f89e772 100644 --- a/crates/ditto-codegen-js/golden-tests/javascript/match_expressions.ditto +++ b/crates/ditto-codegen-js/golden-tests/javascript/match_expressions.ditto @@ -23,3 +23,18 @@ is_just = (maybe): Bool -> match maybe with | Just(_) -> true | Nothing -> false; + +function_arms = (maybe: Maybe(Int)) -> + match maybe with + | Just(a) -> (b, c) -> [a, b, c] + | Nothing -> (b, c) -> [1, b, c]; + +very_function_arms = (maybe: Maybe(Int)) -> + match maybe with + | Just(a) -> (b) -> (c) -> (d) -> [a, b, c] + | Nothing -> (b) -> (c) -> (d) -> [1, b, c]; + +effect_arms = (maybe) -> + match maybe with + | Just(a) -> do { return a } + | Nothing -> do { return 5 }; diff --git a/crates/ditto-codegen-js/golden-tests/javascript/match_expressions.js b/crates/ditto-codegen-js/golden-tests/javascript/match_expressions.js index e34129a18..ebadd6531 100644 --- a/crates/ditto-codegen-js/golden-tests/javascript/match_expressions.js +++ b/crates/ditto-codegen-js/golden-tests/javascript/match_expressions.js @@ -5,6 +5,39 @@ function ManyFields($0, $1, $2, $3) { return ["ManyFields", $0, $1, $2, $3]; } const Nothing = ["Nothing"]; +function effect_arms(maybe) { + if (maybe[0] === "Just") { + const a = maybe[1]; + return () => a; + } + return maybe[0] === "Nothing" + ? () => 5 + : () => { + throw new Error("Pattern match error"); + }; +} +function very_function_arms(maybe) { + if (maybe[0] === "Just") { + const a = maybe[1]; + return b => c => d => [a, b, c]; + } + return maybe[0] === "Nothing" + ? b => c => d => [1, b, c] + : _0 => _0 => _0 => { + throw new Error("Pattern match error"); + }; +} +function function_arms(maybe) { + if (maybe[0] === "Just") { + const a = maybe[1]; + return (b, c) => [a, b, c]; + } + return maybe[0] === "Nothing" + ? (b, c) => [1, b, c] + : (_0, _1) => { + throw new Error("Pattern match error"); + }; +} function is_just(maybe) { if (maybe[0] === "Just") { return true; @@ -44,8 +77,11 @@ export { Just, ManyFields, Nothing, + effect_arms, + function_arms, is_just, many_fields_to_array, mk_five, + very_function_arms, with_default, }; diff --git a/crates/ditto-codegen-js/src/convert.rs b/crates/ditto-codegen-js/src/convert.rs index 7e7f92995..4a6287139 100644 --- a/crates/ditto-codegen-js/src/convert.rs +++ b/crates/ditto-codegen-js/src/convert.rs @@ -351,15 +351,13 @@ pub(crate) fn convert_expression( ditto_ast::Expression::Unit { .. } => Expression::Undefined, // REVIEW could use `null` or `null` here? ditto_ast::Expression::Match { span: _, + match_type, box expression, arms, .. } => { let expression = convert_expression(imported_module_idents, expression); - let err = iife!(Block::Throw(String::from( - // TODO: mention the file location here? - "Pattern match error", - ))); + let err = mk_pattern_match_err(match_type); // Reverse the arm order ahead of folding so the generated code // kinda resembles the ditto source @@ -408,6 +406,47 @@ pub(crate) fn convert_expression( } } +fn mk_pattern_match_err(match_type: ditto_ast::Type) -> Expression { + match mk_err(&match_type) { + ArrowFunctionBody::Expression(expr) => { + return expr; + } + ArrowFunctionBody::Block(block) => { + return iife!(block); + } + } + + fn mk_err(match_type: &ditto_ast::Type) -> ArrowFunctionBody { + use ditto_ast::{PrimType, Type}; + match match_type { + Type::Function { + parameters, + box return_type, + } => ArrowFunctionBody::Expression(Expression::ArrowFunction { + parameters: parameters + .iter() + .enumerate() + .map(|(i, _)| Ident(format!("_{}", i))) + .collect(), + body: Box::new(mk_err(return_type)), + }), + Type::Call { + function: box Type::PrimConstructor(PrimType::Effect), + arguments, + } => ArrowFunctionBody::Expression(Expression::ArrowFunction { + parameters: vec![], + body: Box::new(mk_err(arguments.split_first().0)), + }), + _ => { + ArrowFunctionBody::Block(Block::Throw(String::from( + // TODO: mention the file location here? + "Pattern match error", + ))) + } + } + } +} + fn convert_effect( imported_module_idents: &mut ImportedModuleIdents, effect: ditto_ast::Effect, diff --git a/crates/ditto-codegen-js/src/optimize/rewrites.rs b/crates/ditto-codegen-js/src/optimize/rewrites.rs index e1aa56b31..a6a70e9db 100644 --- a/crates/ditto-codegen-js/src/optimize/rewrites.rs +++ b/crates/ditto-codegen-js/src/optimize/rewrites.rs @@ -5,17 +5,21 @@ use egg::{ENodeOrVar, Var}; pub type Rewrite = egg::Rewrite; -pub fn rewrites() -> [Rewrite; 9] { +pub fn rewrites() -> [Rewrite; 13] { [ rewrite_ternary_with_static_true_condition(), rewrite_ternary_with_static_false_condition(), rewrite_redundant_ternary(), rewrite_arrow_expr_iife_to_arrow_block(), - rewrite_tenaray_with_iife_true_clause_to_block(), - rewrite_tenaray_with_iife_false_clause_to_block(), + rewrite_ternary_with_iife_true_clause_to_block(), + rewrite_ternary_with_iife_false_clause_to_block(), rewrite_inline_returned_iife_block(), rewrite_redundant_return_undefined(), rewrite_inline_immediate_identity_call(), + rewrite_ternary_call0(), // TODO: introduce `CallParams` variant and handle n-ary ternary calls + rewrite_redundant_arrow0_block(), + rewrite_redundant_arrow_block(), + rewrite_redundant_iife(), ] } @@ -144,7 +148,7 @@ fn rewrite_arrow_expr_iife_to_arrow_block() -> Rewrite { // condition ? (() => { block })() : 5 // 👉 (() => { if (condition) { block } return 5 })() // -fn rewrite_tenaray_with_iife_true_clause_to_block() -> Rewrite { +fn rewrite_ternary_with_iife_true_clause_to_block() -> Rewrite { let condition_var = Var::from_str("?condition").unwrap(); let block_var = Var::from_str("?block").unwrap(); let false_clause_var = Var::from_str("?false_clause").unwrap(); @@ -181,7 +185,7 @@ fn rewrite_tenaray_with_iife_true_clause_to_block() -> Rewrite { })); Rewrite::new( - egg::Symbol::from("tenaray_with_iife_true_clause_to_block"), + egg::Symbol::from("ternary_with_iife_true_clause_to_block"), egg::Pattern::new(searcher), egg::Pattern::new(applier), ) @@ -193,7 +197,7 @@ fn rewrite_tenaray_with_iife_true_clause_to_block() -> Rewrite { // condition ? 5 : (() => { block })() // 👉 (() => { if (condition) { return 5 } block })() // -fn rewrite_tenaray_with_iife_false_clause_to_block() -> Rewrite { +fn rewrite_ternary_with_iife_false_clause_to_block() -> Rewrite { let condition_var = Var::from_str("?condition").unwrap(); let block_var = Var::from_str("?block").unwrap(); let true_clause_var = Var::from_str("?true_clause").unwrap(); @@ -231,7 +235,7 @@ fn rewrite_tenaray_with_iife_false_clause_to_block() -> Rewrite { })); Rewrite::new( - egg::Symbol::from("tenaray_with_iife_false_clause_to_block"), + egg::Symbol::from("ternary_with_iife_false_clause_to_block"), egg::Pattern::new(searcher), egg::Pattern::new(applier), ) @@ -295,6 +299,7 @@ fn rewrite_redundant_return_undefined() -> Rewrite { // fn rewrite_inline_immediate_identity_call() -> Rewrite { let expr_var = Var::from_str("?var").unwrap(); + let mut searcher = egg::RecExpr::default(); let identity_id = searcher.add(ENodeOrVar::ENode(Expression::ArrowFunctionIdentity(Ident( // NOTE: this identifier is ignored during Expression matching so can be anything @@ -316,6 +321,143 @@ fn rewrite_inline_immediate_identity_call() -> Rewrite { .unwrap() } +// Prefer calling the arms of a tenary rather than the whole thing wrapped in parens. +// +// (cond ? f : g)() +// 👉 cond ? f() : g() +// +fn rewrite_ternary_call0() -> Rewrite { + let condition_var = Var::from_str("?cond").unwrap(); + let true_clause_var = Var::from_str("?true_clause").unwrap(); + let false_clause_var = Var::from_str("?false_clause").unwrap(); + + let mut searcher = egg::RecExpr::default(); + + let condition_id = searcher.add(ENodeOrVar::Var(condition_var)); + let true_clause_id = searcher.add(ENodeOrVar::Var(true_clause_var)); + let false_clause_id = searcher.add(ENodeOrVar::Var(false_clause_var)); + let ternary_id = searcher.add(ENodeOrVar::ENode(Expression::Conditional { + children: [condition_id, true_clause_id, false_clause_id], + })); + searcher.add(ENodeOrVar::ENode(Expression::Call { + children: vec![ternary_id], + })); + + let mut applier = egg::RecExpr::default(); + let condition_id = applier.add(searcher[condition_id].clone()); + let true_clause_id = applier.add(searcher[true_clause_id].clone()); + let true_clause_id = applier.add(ENodeOrVar::ENode(Expression::Call { + children: vec![true_clause_id], + })); + let false_clause_id = applier.add(searcher[false_clause_id].clone()); + let false_clause_id = applier.add(ENodeOrVar::ENode(Expression::Call { + children: vec![false_clause_id], + })); + applier.add(ENodeOrVar::ENode(Expression::Conditional { + children: [condition_id, true_clause_id, false_clause_id], + })); + + Rewrite::new( + egg::Symbol::from("ternary_call0"), + egg::Pattern::new(searcher), + egg::Pattern::new(applier), + ) + .unwrap() +} + +// Rewrite a redundant (nullary) arrow block body. +// +// () => { return x } +// 👉 () => x +// +fn rewrite_redundant_arrow0_block() -> Rewrite { + let expr_var = Var::from_str("?expr").unwrap(); + + let mut searcher = egg::RecExpr::default(); + let expr_id = searcher.add(ENodeOrVar::Var(expr_var)); + let return_id = searcher.add(ENodeOrVar::ENode(Expression::BlockReturn { + children: [expr_id], + })); + searcher.add(ENodeOrVar::ENode(Expression::ArrowFunctionBlock0 { + children: [return_id], + })); + + let mut applier = egg::RecExpr::default(); + let expr_id = applier.add(searcher[expr_id].clone()); + applier.add(ENodeOrVar::ENode(Expression::ArrowFunctionExpr0 { + children: [expr_id], + })); + + Rewrite::new( + egg::Symbol::from("redundant_arrow0_block"), + egg::Pattern::new(searcher), + egg::Pattern::new(applier), + ) + .unwrap() +} + +// Rewrite a redundant arrow block body. +// +// (...args) => { return x } +// 👉 (...args) => x +// +fn rewrite_redundant_arrow_block() -> Rewrite { + let expr_var = Var::from_str("?expr").unwrap(); + let params_var = Var::from_str("?params").unwrap(); + + let mut searcher = egg::RecExpr::default(); + let params_id = searcher.add(ENodeOrVar::Var(params_var)); + let expr_id = searcher.add(ENodeOrVar::Var(expr_var)); + let return_id = searcher.add(ENodeOrVar::ENode(Expression::BlockReturn { + children: [expr_id], + })); + searcher.add(ENodeOrVar::ENode(Expression::ArrowFunctionBlock { + children: [params_id, return_id], + })); + + let mut applier = egg::RecExpr::default(); + let params_id = applier.add(searcher[params_id].clone()); + let expr_id = applier.add(searcher[expr_id].clone()); + applier.add(ENodeOrVar::ENode(Expression::ArrowFunctionExpr { + children: [params_id, expr_id], + })); + + Rewrite::new( + egg::Symbol::from("redundant_arrow_block"), + egg::Pattern::new(searcher), + egg::Pattern::new(applier), + ) + .unwrap() +} + +// Rewrite a redundant IIFE +// +// (() => x)() +// 👉 x +// +fn rewrite_redundant_iife() -> Rewrite { + let expr_var = Var::from_str("?expr").unwrap(); + + let mut searcher = egg::RecExpr::default(); + let expr_id = searcher.add(ENodeOrVar::Var(expr_var)); + let arrow_id = searcher.add(ENodeOrVar::ENode(Expression::ArrowFunctionExpr0 { + children: [expr_id], + })); + searcher.add(ENodeOrVar::ENode(Expression::Call { + children: vec![arrow_id], + })); + + let mut applier = egg::RecExpr::default(); + applier.add(searcher[expr_id].clone()); + + Rewrite::new( + egg::Symbol::from("redundant_iife"), + egg::Pattern::new(searcher), + egg::Pattern::new(applier), + ) + .unwrap() +} + #[cfg(test)] mod tests { use crate::optimize::test_macros::assert_optimized; @@ -328,6 +470,10 @@ mod tests { assert_optimized!("[if true then 1 else 2, if false then 3 else 2]", "[1,2]"); assert_optimized!("if true then true else false", "true"); assert_optimized!("(x: Bool) -> if x then true else false", "(x) => x"); + assert_optimized!( + "(cond, fn) -> (if cond then fn else fn)()", + "(cond,fn) => cond?fn():fn()" + ); } #[test] @@ -342,11 +488,22 @@ mod tests { ); } + #[test] + fn it_rewrites_effects() { + assert_optimized!("do { return unit }", "() => undefined"); + assert_optimized!("do { return 5 }", "() => 5"); + } + #[test] fn it_removes_redundant_return_unit() { assert_optimized!("(x) -> do { return unit }", "(x) => () => {return;}"); } + #[test] + fn it_removes_redundant_iifes() { + assert_optimized!("(() -> 5)()", "5"); + } + #[test] fn it_inlines_identity_calls() { assert_optimized!("((x) -> x)(5)", "5"); From 2f7fbc43bb87faacfbe2ad4e05bf629f91b7a568 Mon Sep 17 00:00:00 2001 From: Jordan Mackie Date: Tue, 10 May 2022 09:15:37 +0100 Subject: [PATCH 2/3] Yeah nah don't do that --- .../javascript/effect_expressions.js | 28 ++++++----- .../javascript/match_expressions.js | 17 +++---- crates/ditto-codegen-js/src/convert.rs | 47 ++---------------- .../ditto-codegen-js/src/optimize/rewrites.rs | 49 +------------------ 4 files changed, 29 insertions(+), 112 deletions(-) diff --git a/crates/ditto-codegen-js/golden-tests/javascript/effect_expressions.js b/crates/ditto-codegen-js/golden-tests/javascript/effect_expressions.js index f48f3a02a..867686d80 100644 --- a/crates/ditto-codegen-js/golden-tests/javascript/effect_expressions.js +++ b/crates/ditto-codegen-js/golden-tests/javascript/effect_expressions.js @@ -27,19 +27,21 @@ function get_names() { function get_names_from_result(res) { return () => { get_name(); - return (() => { - if (res[0] === "Ok") { - const a = res[1]; - return always(a, get_names); - } - if (res[0] === "Err") { - const e = res[1]; - return always(e, get_names); - } - return () => { - throw new Error("Pattern match error"); - }; - })()(); + return ( + res[0] === "Ok" + ? (() => { + const a = res[1]; + return always(a, get_names); + })() + : res[0] === "Err" + ? (() => { + const e = res[1]; + return always(e, get_names); + })() + : (() => { + throw new Error("Pattern match error"); + })() + )(); }; } export { diff --git a/crates/ditto-codegen-js/golden-tests/javascript/match_expressions.js b/crates/ditto-codegen-js/golden-tests/javascript/match_expressions.js index ebadd6531..a75144d9e 100644 --- a/crates/ditto-codegen-js/golden-tests/javascript/match_expressions.js +++ b/crates/ditto-codegen-js/golden-tests/javascript/match_expressions.js @@ -10,11 +10,10 @@ function effect_arms(maybe) { const a = maybe[1]; return () => a; } - return maybe[0] === "Nothing" - ? () => 5 - : () => { - throw new Error("Pattern match error"); - }; + if (maybe[0] === "Nothing") { + return () => 5; + } + throw new Error("Pattern match error"); } function very_function_arms(maybe) { if (maybe[0] === "Just") { @@ -23,9 +22,9 @@ function very_function_arms(maybe) { } return maybe[0] === "Nothing" ? b => c => d => [1, b, c] - : _0 => _0 => _0 => { + : (() => { throw new Error("Pattern match error"); - }; + })(); } function function_arms(maybe) { if (maybe[0] === "Just") { @@ -34,9 +33,9 @@ function function_arms(maybe) { } return maybe[0] === "Nothing" ? (b, c) => [1, b, c] - : (_0, _1) => { + : (() => { throw new Error("Pattern match error"); - }; + })(); } function is_just(maybe) { if (maybe[0] === "Just") { diff --git a/crates/ditto-codegen-js/src/convert.rs b/crates/ditto-codegen-js/src/convert.rs index 4a6287139..7e7f92995 100644 --- a/crates/ditto-codegen-js/src/convert.rs +++ b/crates/ditto-codegen-js/src/convert.rs @@ -351,13 +351,15 @@ pub(crate) fn convert_expression( ditto_ast::Expression::Unit { .. } => Expression::Undefined, // REVIEW could use `null` or `null` here? ditto_ast::Expression::Match { span: _, - match_type, box expression, arms, .. } => { let expression = convert_expression(imported_module_idents, expression); - let err = mk_pattern_match_err(match_type); + let err = iife!(Block::Throw(String::from( + // TODO: mention the file location here? + "Pattern match error", + ))); // Reverse the arm order ahead of folding so the generated code // kinda resembles the ditto source @@ -406,47 +408,6 @@ pub(crate) fn convert_expression( } } -fn mk_pattern_match_err(match_type: ditto_ast::Type) -> Expression { - match mk_err(&match_type) { - ArrowFunctionBody::Expression(expr) => { - return expr; - } - ArrowFunctionBody::Block(block) => { - return iife!(block); - } - } - - fn mk_err(match_type: &ditto_ast::Type) -> ArrowFunctionBody { - use ditto_ast::{PrimType, Type}; - match match_type { - Type::Function { - parameters, - box return_type, - } => ArrowFunctionBody::Expression(Expression::ArrowFunction { - parameters: parameters - .iter() - .enumerate() - .map(|(i, _)| Ident(format!("_{}", i))) - .collect(), - body: Box::new(mk_err(return_type)), - }), - Type::Call { - function: box Type::PrimConstructor(PrimType::Effect), - arguments, - } => ArrowFunctionBody::Expression(Expression::ArrowFunction { - parameters: vec![], - body: Box::new(mk_err(arguments.split_first().0)), - }), - _ => { - ArrowFunctionBody::Block(Block::Throw(String::from( - // TODO: mention the file location here? - "Pattern match error", - ))) - } - } - } -} - fn convert_effect( imported_module_idents: &mut ImportedModuleIdents, effect: ditto_ast::Effect, diff --git a/crates/ditto-codegen-js/src/optimize/rewrites.rs b/crates/ditto-codegen-js/src/optimize/rewrites.rs index a6a70e9db..1649c9b63 100644 --- a/crates/ditto-codegen-js/src/optimize/rewrites.rs +++ b/crates/ditto-codegen-js/src/optimize/rewrites.rs @@ -5,7 +5,7 @@ use egg::{ENodeOrVar, Var}; pub type Rewrite = egg::Rewrite; -pub fn rewrites() -> [Rewrite; 13] { +pub fn rewrites() -> [Rewrite; 12] { [ rewrite_ternary_with_static_true_condition(), rewrite_ternary_with_static_false_condition(), @@ -16,7 +16,6 @@ pub fn rewrites() -> [Rewrite; 13] { rewrite_inline_returned_iife_block(), rewrite_redundant_return_undefined(), rewrite_inline_immediate_identity_call(), - rewrite_ternary_call0(), // TODO: introduce `CallParams` variant and handle n-ary ternary calls rewrite_redundant_arrow0_block(), rewrite_redundant_arrow_block(), rewrite_redundant_iife(), @@ -321,50 +320,6 @@ fn rewrite_inline_immediate_identity_call() -> Rewrite { .unwrap() } -// Prefer calling the arms of a tenary rather than the whole thing wrapped in parens. -// -// (cond ? f : g)() -// 👉 cond ? f() : g() -// -fn rewrite_ternary_call0() -> Rewrite { - let condition_var = Var::from_str("?cond").unwrap(); - let true_clause_var = Var::from_str("?true_clause").unwrap(); - let false_clause_var = Var::from_str("?false_clause").unwrap(); - - let mut searcher = egg::RecExpr::default(); - - let condition_id = searcher.add(ENodeOrVar::Var(condition_var)); - let true_clause_id = searcher.add(ENodeOrVar::Var(true_clause_var)); - let false_clause_id = searcher.add(ENodeOrVar::Var(false_clause_var)); - let ternary_id = searcher.add(ENodeOrVar::ENode(Expression::Conditional { - children: [condition_id, true_clause_id, false_clause_id], - })); - searcher.add(ENodeOrVar::ENode(Expression::Call { - children: vec![ternary_id], - })); - - let mut applier = egg::RecExpr::default(); - let condition_id = applier.add(searcher[condition_id].clone()); - let true_clause_id = applier.add(searcher[true_clause_id].clone()); - let true_clause_id = applier.add(ENodeOrVar::ENode(Expression::Call { - children: vec![true_clause_id], - })); - let false_clause_id = applier.add(searcher[false_clause_id].clone()); - let false_clause_id = applier.add(ENodeOrVar::ENode(Expression::Call { - children: vec![false_clause_id], - })); - applier.add(ENodeOrVar::ENode(Expression::Conditional { - children: [condition_id, true_clause_id, false_clause_id], - })); - - Rewrite::new( - egg::Symbol::from("ternary_call0"), - egg::Pattern::new(searcher), - egg::Pattern::new(applier), - ) - .unwrap() -} - // Rewrite a redundant (nullary) arrow block body. // // () => { return x } @@ -472,7 +427,7 @@ mod tests { assert_optimized!("(x: Bool) -> if x then true else false", "(x) => x"); assert_optimized!( "(cond, fn) -> (if cond then fn else fn)()", - "(cond,fn) => cond?fn():fn()" + "(cond,fn) => (cond?fn:fn)()" ); } From ef49282e8406797f670a794f39ae6d9f1c75ceae Mon Sep 17 00:00:00 2001 From: Jordan Mackie Date: Tue, 10 May 2022 09:48:36 +0100 Subject: [PATCH 3/3] Fix regression --- crates/ditto-cli/fixtures/javascript-project/dist/A_Test.js | 2 +- .../golden-tests/javascript/basic_expressions.js | 2 +- crates/ditto-codegen-js/src/convert.rs | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/ditto-cli/fixtures/javascript-project/dist/A_Test.js b/crates/ditto-cli/fixtures/javascript-project/dist/A_Test.js index 9b700a497..422356ba3 100644 --- a/crates/ditto-cli/fixtures/javascript-project/dist/A_Test.js +++ b/crates/ditto-cli/fixtures/javascript-project/dist/A_Test.js @@ -1,2 +1,2 @@ -function test_it_works(){return undefined;} +function test_it_works(){return;} export {test_it_works}; diff --git a/crates/ditto-codegen-js/golden-tests/javascript/basic_expressions.js b/crates/ditto-codegen-js/golden-tests/javascript/basic_expressions.js index adb77184c..427a4104c 100644 --- a/crates/ditto-codegen-js/golden-tests/javascript/basic_expressions.js +++ b/crates/ditto-codegen-js/golden-tests/javascript/basic_expressions.js @@ -1,5 +1,5 @@ function denied(a) { - return undefined; + return; } function select(c, x, y) { return c ? x : y; diff --git a/crates/ditto-codegen-js/src/convert.rs b/crates/ditto-codegen-js/src/convert.rs index 7e7f92995..e690e4fb6 100644 --- a/crates/ditto-codegen-js/src/convert.rs +++ b/crates/ditto-codegen-js/src/convert.rs @@ -135,6 +135,10 @@ fn expression_to_module_statement(ident: Ident, expression: Expression) -> Modul ident, parameters, body: match body { + ArrowFunctionBody::Expression(Expression::Undefined) => { + // don't undo the rewrite rule + Block::Return(None) + } ArrowFunctionBody::Expression(expression) => Block::Return(Some(expression)), ArrowFunctionBody::Block(block) => block, },