Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some more JavaScript rewrite rules ⚡ #52

Merged
merged 3 commits into from
May 10, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
function test_it_works(){return;}
function test_it_works(){return undefined;}
export {test_it_works};
Original file line number Diff line number Diff line change
Expand Up @@ -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)
};
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -15,4 +24,33 @@ 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 (
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 {
Err,
Ok,
always,
effect_map,
get_name,
get_names,
get_names_from_result,
main,
};
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,38 @@ 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;
}
if (maybe[0] === "Nothing") {
return () => 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]
: (() => {
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]
: (() => {
throw new Error("Pattern match error");
})();
}
function is_just(maybe) {
if (maybe[0] === "Just") {
return true;
Expand Down Expand Up @@ -44,8 +76,11 @@ export {
Just,
ManyFields,
Nothing,
effect_arms,
function_arms,
is_just,
many_fields_to_array,
mk_five,
very_function_arms,
with_default,
};
126 changes: 119 additions & 7 deletions crates/ditto-codegen-js/src/optimize/rewrites.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@ use egg::{ENodeOrVar, Var};

pub type Rewrite = egg::Rewrite<Expression, ()>;

pub fn rewrites() -> [Rewrite; 9] {
pub fn rewrites() -> [Rewrite; 12] {
[
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(),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo 🤦

rewrite_inline_returned_iife_block(),
rewrite_redundant_return_undefined(),
rewrite_inline_immediate_identity_call(),
rewrite_redundant_arrow0_block(),
rewrite_redundant_arrow_block(),
rewrite_redundant_iife(),
]
}

Expand Down Expand Up @@ -144,7 +147,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();
Expand Down Expand Up @@ -181,7 +184,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),
)
Expand All @@ -193,7 +196,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();
Expand Down Expand Up @@ -231,7 +234,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),
)
Expand Down Expand Up @@ -295,6 +298,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
Expand All @@ -316,6 +320,99 @@ fn rewrite_inline_immediate_identity_call() -> Rewrite {
.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;
Expand All @@ -328,6 +425,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]
Expand All @@ -342,11 +443,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");
Expand Down