From f19d136e86cc40790172b08f2a93bf4c73a6f029 Mon Sep 17 00:00:00 2001 From: RomaRomama Date: Fri, 24 Apr 2020 14:37:56 +0800 Subject: [PATCH 1/6] Added Partial Evaluator src and various tests --- ...urce-4-partial-evaluator.arithmetictest.js | 12 + .../source-4-partial-evaluator.bindtest.js | 13 + ...rce-4-partial-evaluator.conditionaltest.js | 24 + .../source-4-partial-evaluator.mixtest.js | 22 + .../source-4-partial-evaluator.js | 913 ++++++++++++++++++ 5 files changed, 984 insertions(+) create mode 100644 src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js create mode 100644 src/partial-evaluators/_tests_/source-4-partial-evaluator.bindtest.js create mode 100644 src/partial-evaluators/_tests_/source-4-partial-evaluator.conditionaltest.js create mode 100644 src/partial-evaluators/_tests_/source-4-partial-evaluator.mixtest.js create mode 100644 src/partial-evaluators/source-4-partial-evaluator.js diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js b/src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js new file mode 100644 index 0000000..1253485 --- /dev/null +++ b/src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js @@ -0,0 +1,12 @@ +let to_partialize = partial_evaluation(parse("\ +function test(x, y, z, w) { \ + return (3 + x) * (y + w) - 2 * w * x - x * y;\ +}\ +"), list(), list()); + +let partialized = partial_evaluation(parse("\ +function test(x, y, z, w) { \ + return 3 * y + 3 * w - x * w;\ +}"), list(), list()); + +equal(exa1, exa2); \ No newline at end of file diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.bindtest.js b/src/partial-evaluators/_tests_/source-4-partial-evaluator.bindtest.js new file mode 100644 index 0000000..cd8d3f7 --- /dev/null +++ b/src/partial-evaluators/_tests_/source-4-partial-evaluator.bindtest.js @@ -0,0 +1,13 @@ +let to_partialize = partial_evaluation(parse("\ +function test(x, y, z, w) { \ + return a; \ +} \ +"), list("a"), list(1)); + +let partialized = partial_evaluation(parse("\ +function test(x, y, z, w) { \ +return 1;\ +}"), list(), list()); + +equal(to_partialize, partialized); +\\true \ No newline at end of file diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.conditionaltest.js b/src/partial-evaluators/_tests_/source-4-partial-evaluator.conditionaltest.js new file mode 100644 index 0000000..047b375 --- /dev/null +++ b/src/partial-evaluators/_tests_/source-4-partial-evaluator.conditionaltest.js @@ -0,0 +1,24 @@ +let to_partialize = partial_evaluation(parse("\ +function test(x, y, z, w) { \ + let t = x; \ + if (a + 1 === t) { \ + return 2 * (2 * t + y) + 2 * a; \ + } else { \ + return 3 * (t + 2 * y) + a; \ + } \ +}\ +"), list("a"), list(3)); + + +let partialized = partial_evaluation(parse("\ +function test(x, y, z, w) { \ + let t = x; \ + if (4 === t) { \ + return 4 * t + 2 * y + 6; \ + } else { \ + return 3 * t + 6 * y + 3; \ + } \ +}\ +"), list(), list()); + +equal(to_partialize, partialized); \ No newline at end of file diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.mixtest.js b/src/partial-evaluators/_tests_/source-4-partial-evaluator.mixtest.js new file mode 100644 index 0000000..2ee121a --- /dev/null +++ b/src/partial-evaluators/_tests_/source-4-partial-evaluator.mixtest.js @@ -0,0 +1,22 @@ +let to_partialize = partial_evaluation(parse("\ +function test(x, y, z, w) { \ + if (((x * (1 / 4) === x - (3 / 4) * x) ? y : x) <= y) {\ + if (x * 2 < x + x) {\ + return false;\ + } else {\ + return (x / a) / (1 / ((3 + b * ((w - w / 2 === w / 2) ? 2 * x - x : y) - ((true) ? 2 : 1) === x * b + 1) ? a : 3));\ + }\ + } else {\ + return (2 * x / 5) - (x / 5);\ + }\ +}\ +"), list("a"), list(5)); + + +let partialized = partial_evaluation(parse("\ +function test(x, y, z, w) { \ + return x;\ +}\ +"), list(), list()); + +equal(to_partialize, partialized); \ No newline at end of file diff --git a/src/partial-evaluators/source-4-partial-evaluator.js b/src/partial-evaluators/source-4-partial-evaluator.js new file mode 100644 index 0000000..e65ca4b --- /dev/null +++ b/src/partial-evaluators/source-4-partial-evaluator.js @@ -0,0 +1,913 @@ +//Given a program, list of global variables, and list of global values +//Note: variables and values are corresponding respect to its order +function partial_evaluation(f, names, values) { + let name = list_ref(function_name(f), 1); + let binded_f = bind(f, names, values); + + let final_simplified_conditionals = null; + while (!equal(final_simplified_conditionals, binded_f)) { + final_simplified_conditionals = binded_f; + + binded_f = repeatedDFSapplication(binded_f, function_parameters(binded_f)); + binded_f = merge_simplified_conditionals(binded_f); + } + + let pretty_printed = pretty_print(final_simplified_conditionals); + display(pretty_printed); + + return final_simplified_conditionals; +} + +//prints all simplified math expressions in the function +function pretty_print(f) { + if (!is_list(f)) { + return f; + } else { + if (is_math_application(f) || is_number(f) || is_variable(f)) { + let pretty_printed_expression = pretty_print_application(f)+";"; + //display("-----simplified expression-----"); + //display(pretty_printed_expression); + //display("-------------------------------"); + return pretty_printed_expression; + } else { + return build_list(length(f), i => pretty_print(list_ref(f, i))); + } + } +} + +function pretty_print_application(f) { + let operation = application_operation(f); + let parameter1 = application_parameter1(f); + let parameter2 = application_parameter2(f); + if (operation === "+") { + return "(" + pretty_print_application(parameter1) + + " + " + pretty_print_application(parameter2) + ")"; + } else if (operation === "-") { + return "(" + pretty_print_application(parameter1) + + " - " + pretty_print_application(parameter2) + ")"; + } else if (operation === "*") { + return "(" + pretty_print_application(parameter1) + + " * " + pretty_print_application(parameter2) + ")"; + } else if (operation === "/") { + return "(" + pretty_print_application(parameter1) + + " / " + pretty_print_application(parameter2) + ")"; + } else if (is_variable(f)) { + return list_ref(f, 1); + } else { + return stringify(f); + } +} + +function is_tagged_list(stmt, the_tag) { + return is_pair(stmt) && head(stmt) === the_tag; +} + +function is_constant_declaration(f) { + return is_tagged_list(f, "constant_declaration"); +} + +function is_function_definition(f) { + return is_tagged_list(f, "function_definition"); +} + +function is_sequence(f) { + return is_tagged_list(f, "sequence"); +} + +function is_return_statement(f) { + return is_tagged_list(f, "return_statement"); +} + +function is_math_application(f) { + if (!is_tagged_list(f, "application")) { + return false; + } else { + let op = list_ref(list_ref(f, 1), 1); + return op === "+" || op === "-" || op === "*" || op === "/"; + } +} + +function is_variable(f) { + return is_tagged_list(f, "name") + && list_ref(f, 1) !== "===" + && list_ref(f, 1) !== "!==" + && list_ref(f, 1) !== ">" + && list_ref(f, 1) !== "<" + && list_ref(f, 1) !== ">=" + && list_ref(f, 1) !== "<="; +} + +//Verify if a statement is a conditional statement +function is_conditional_statement(f) { + return is_tagged_list(f, "conditional_statement"); +} + +//Verify if a statement is a conditional expression +function is_conditional_expression(f) { + return is_tagged_list(f, "conditional_expression"); +} + +//Verify if a condition is evaluable +function is_trivial_condition(f) { + if (is_tagged_list(f, "application")) { + let operation = list_ref(list_ref(f, 1), 1); + let parameters = list_ref(f, 2); + let lhs = list_ref(parameters, 0); + let rhs = list_ref(parameters, 1); + return (operation === "===" + || operation === "!==" + || operation === ">" + || operation === "<" + || operation === ">=" + || operation === "<=") + && is_number(lhs) + && is_number(rhs); + } else { + if (is_boolean(f)) { + return true; + } else { + return false; + } + } +} + +//Evaluate the boolean value of an evaluable condition +function evaluate_trivial_condition(f) { + if (is_tagged_list(f, "application")) { + let operation = list_ref(list_ref(f, 1), 1); + let parameters = list_ref(f, 2); + let lhs = list_ref(parameters, 0); + let rhs = list_ref(parameters, 1); + if (operation === "===") { + return lhs === rhs; + } else if (operation === "!==") { + return lhs !== rhs; + } else if (operation === ">") { + return lhs > rhs; + } else if (operation === "<") { + return lhs < rhs; + } else if (operation === ">=") { + return lhs >= rhs; + } else if (operation === "<=") { + return lhs <= rhs; + } else { + return false; + } + } else { + if (is_boolean(f)) { + return f; + } else{ + return false; + } + } +} + +//Evaluate the boolean value of a variable condition if possible +function evaluate_true_variable_equation(f) { + if (is_tagged_list(f, "application")) { + let operation = list_ref(list_ref(f, 1), 1); + let parameters = list_ref(f, 2); + let lhs = list_ref(parameters, 0); + let rhs = list_ref(parameters, 1); + if (operation === "===" + || operation === "<=" + || operation === ">=") { + return equal(lhs, rhs) || lhs === rhs; + } + else { + return false; + } + } else { + return false; + } +} + +//Evaluate the boolean value of a variable condition if possible +function evaluate_false_variable_equation(f) { + if (is_tagged_list(f, "application")) { + let operation = list_ref(list_ref(f, 1), 1); + let parameters = list_ref(f, 2); + let lhs = list_ref(parameters, 0); + let rhs = list_ref(parameters, 1); + if (operation === "!==" + || operation === "<" + || operation === ">") { + return equal(lhs, rhs) || lhs === rhs; + } + else { + return false; + } + } else { + return false; + } +} + +function var_name(v) { + if (!is_variable(v)) { + return undefined; + } else {} + + return list_ref(v, 1); +} + +//The name of function +function function_name(f) { + if (!is_constant_declaration(f)) { + return undefined; + } else {} + + return list_ref(f, 1); +} + +//The function definition of the function +function function_definition(f) { + if (!is_constant_declaration(f)) { + return undefined; + } else {} + + return list_ref(f, 2); +} + +//The parameter pair of a math application +function function_parameters(f) { + if (!is_function_definition(f)){ + if(!is_constant_declaration(f) + || !is_function_definition(list_ref(f, 2))){ + return undefined; + } else {} + f = list_ref(f, 2); + } else {} + + return list_ref(f, 1); +} + +//The return block of a function +function function_return(f) { + if (!is_function_definition(f)){ + if(!is_constant_declaration(f) + || !is_function_definition(list_ref(f, 2))){ + return undefined; + } else {} + f = list_ref(f, 2); + } else {} + + f = list_ref(f, 2); + + return f; +} + +//The operator of a math application +function application_operation(f){ + if (!is_math_application(f)){ + return undefined; + } else {} + + return list_ref(list_ref(f, 1), 1); +} + +//The first paramter of a math application +function application_parameter1(f){ + if (!is_math_application(f)){ + return undefined; + } else {} + + let parameters = list_ref(f, 2); + return list_ref(parameters, 0); +} + +//The second paramter of a math application +function application_parameter2(f){ + if (!is_math_application(f)){ + return undefined; + } else {} + + let parameters = list_ref(f, 2); + return list_ref(parameters, 1); +} + +//The condition of a conditional +function condition(f) { + if (!is_conditional_statement(f) + && !is_conditional_expression(f)) { + return undefined; + } else { + return list_ref(f, 1); + } +} + +//The true branch of a conditional +function true_branch(f) { + if (!is_conditional_statement(f) + && !is_conditional_expression(f)) { + return undefined; + } else { + return list_ref(f, 2); + } +} + +//The false branch of a conditional +function false_branch(f) { + if (!is_conditional_statement(f) + && !is_conditional_expression(f)) { + return undefined; + } else { + return list_ref(f, 3); + } +} + +//Substitute all variables given the global values +function bind(sequence, names, values) { + function helper(m) { + if (is_variable(m)) { + if (!is_null(member(var_name(m), names))) { + let sublist = member(var_name(m), names); + let value = list_ref(values, + length(values) - length(sublist)); + return value; + } else { + return m; + } + } else { + if (is_list(m)) { + return bind(m, names, values); + } else { + return m; + } + } + } + + return map(helper, sequence); +} + +//Omit the other branch if the condition is evaluable, +//leave it if not +function branching(conditional, bool) { + let true_b = true_branch(conditional); + let false_b = false_branch(conditional); + if (bool) { + if (is_conditional_statement(conditional)) { + if (is_sequence(list_ref(true_b, 1))) { + return list_ref(list_ref(true_b, 1), 1); + } else { + return list(list_ref(true_b, 1)); + } + } + else { + if (is_conditional_expression(conditional)) { + return list(true_b); + } else {} + } + } else { + if (is_conditional_statement(conditional)) { + if (is_sequence(list_ref(false_b, 1))) { + return list_ref(list_ref(false_b, 1), 1); + } else { + return list(list_ref(false_b, 1)); + } + } + else { + if (is_conditional_expression(conditional)) { + return list(false_b); + } else {} + } + } +} + +//Removes all trivial conditionals after arithmetic simplification +function merge_simplified_conditionals(f) { + if (is_null(f)) { + return f; + } else { + if (is_list(head(f))) { + if ((is_conditional_statement(head(f)) + || is_conditional_expression(head(f))) + && is_trivial_condition(condition(head(f)))) { + return append(merge_simplified_conditionals(branching(head(f), + evaluate_trivial_condition(condition(head(f))))), + merge_simplified_conditionals(tail(f))); + } else { + return append(list(merge_simplified_conditionals(head(f))), + merge_simplified_conditionals(tail(f))); + } + } else { + return append(list(head(f)), + merge_simplified_conditionals(tail(f))); + } + } +} + +//doing DFS multiple times on the function to find to simplify math expressions +function repeatedDFSapplication(return_sequence, parameter_order) { + let PE = DFSapplication(return_sequence, parameter_order); + let i = 0; + const limit = 20; //additional precaution against too many loops + while (!equal(PE, return_sequence) && i < limit){ + return_sequence = PE; + PE = DFSapplication(PE, parameter_order); + i = i + 1; + } + return PE; +} + +//simplifies math applications and leaves everything else alone +function DFSapplication(f, parameter_order) { + if (!is_list(f)) { + return f; + } else { + if (is_math_application(f)) { + return simplifyFoundApplication(f, parameter_order); + } else if (evaluate_true_variable_equation(f)) { + return true; + } else if (evaluate_false_variable_equation(f)) { + return false; + } else { + return build_list(length(f), i => DFSapplication(list_ref(f, i), parameter_order)); + } + } +} + +//does a single operation to standardise and simplify a math application +//and recursivisely searches for more math applications +function simplifyFoundApplication(f, parameter_order) { + let operation = application_operation(f); + let parameter1 = application_parameter1(f); + let parameter2 = application_parameter2(f); + + if (operation === "+") { //X + Y + if (parameter1 === 0) { + return parameter2; + } else if (parameter2 === 0) { + return parameter1; + } else if (is_number(parameter1) && is_number(parameter2)) { + return parameter1 + parameter2; + } else if (!is_number(parameter1) && is_number(parameter2) + || is_variable(parameter2) && is_math_application(parameter1)) { + return form_application("+", + parameter2, + DFSapplication(parameter1, parameter_order)); + } else if ((!is_number(parameter1) && is_number(application_parameter1(parameter2)) + || is_variable(application_parameter1(parameter2)) && is_math_application(parameter1)) + && application_operation(parameter2) === "+") { + let subaddition = form_application("+", + parameter1, application_parameter2(parameter2)); + + return form_application("+", + DFSapplication(application_parameter1(parameter2), parameter_order), + DFSapplication(subaddition, parameter_order)); + } else if (is_list(parameter1) && is_list(parameter1) && (length(parameter1) < length(parameter1) + || clear_constant_and_check_is_before_addition(parameter2, parameter1, parameter_order))) { + return form_application("+", + DFSapplication(parameter2, parameter_order), + DFSapplication(parameter1, parameter_order)); + } else if (is_number(parameter1) && is_number(application_parameter1(parameter2)) + && application_operation(parameter2) === "+") { + return form_application("+", + parameter1 + application_parameter1(parameter2), + DFSapplication(application_parameter2(parameter2), parameter_order)); + } else if (application_operation(parameter1) === "+") { + let subaddition = form_application("+", + application_parameter2(parameter1), parameter2); + + let mainaddition = form_application("+", + DFSapplication(application_parameter1(parameter1), parameter_order), DFSapplication(subaddition, parameter_order)); + + return mainaddition; + } else if ((is_number(application_parameter1(parameter2)) || application_operation(application_parameter1(parameter2)) === "/") + && application_operation(parameter2) === "+") { + let subaddition = form_application("+", + application_parameter2(parameter2), parameter1); + + let mainaddition = form_application("+", + application_parameter1(parameter2), DFSapplication(subaddition, parameter_order)); + + return mainaddition; + } else if (application_operation(parameter2) === "+") { + parameter1 = DFSapplication(parameter1, parameter_order); + let newpara2para1 = DFSapplication(application_parameter1(parameter2), parameter_order); + let numerator_p1 = 1; + let numerator_p2 = 1; + let denominator_p1 = 1; + let denominator_p2 = 1; + let p1 = parameter1; + let p2 = newpara2para1; + while (application_operation(p1) === "*" + && is_number(application_parameter1(p1))) { + numerator_p1 = numerator_p1 * application_parameter1(p1); + p1 = application_parameter2(p1); + } + while (application_operation(p1) === "*" + && application_operation(application_parameter1(p1)) === "/" + && is_number(application_parameter2(application_parameter1(p1)))) { + denominator_p1 = denominator_p1 * application_parameter2(application_parameter1(p1)); + p1 = application_parameter2(p1); + } + while (application_operation(p1) === "*" + && application_operation(application_parameter1(p1)) === "/" + && application_operation(application_parameter2(application_parameter1(p1))) === "*" + && is_number(application_parameter1(application_parameter2(application_parameter1(p1))))) { + denominator_p1 = denominator_p1 * application_parameter1(application_parameter2(application_parameter1(p1))); + let denominator_extract = form_application("/", 1, application_parameter2(application_parameter2(application_parameter1(p1)))); + p1 = form_application("*", denominator_extract, application_parameter2(p1)); + } + while (application_operation(p2) === "*" + && is_number(application_parameter1(p2))) { + numerator_p2 = numerator_p2 * application_parameter1(p2); + p2 = application_parameter2(p2); + } + while (application_operation(p2) === "*" + && application_operation(application_parameter1(p2)) === "/" + && is_number(application_parameter2(application_parameter1(p2)))) { + denominator_p2 = denominator_p2 * application_parameter2(application_parameter1(p2)); + p2 = application_parameter2(p2); + } + while (application_operation(p2) === "*" + && application_operation(application_parameter1(p2)) === "/" + && application_operation(application_parameter2(application_parameter1(p2))) === "*" + && is_number(application_parameter1(application_parameter2(application_parameter1(p2))))) { + denominator_p2 = denominator_p2 * application_parameter1(application_parameter2(application_parameter1(p2))); + let denominator_extract = form_application("/", 1, application_parameter2(application_parameter2(application_parameter1(p2)))); + p2 = form_application("*", denominator_extract, application_parameter2(p2)); + } + + if (equal(p1, p2)) { + numerator_p1 = numerator_p1 * denominator_p2 + numerator_p2 * denominator_p1; + denominator_p1 = denominator_p1 * denominator_p2; + if(numerator_p1 === denominator_p1){ + numerator_p1 = 1; + denominator_p1 = 1; + } else {} + let reciprocal = form_application("/", 1, denominator_p1); + + let submultiply1 = form_application("*", reciprocal, p1); + let submultiply2 = form_application("*", numerator_p1, submultiply1); + let addition = form_application("+", submultiply2, DFSapplication(application_parameter2(parameter2), parameter_order)); + + return DFSapplication(addition, parameter_order); + } else if (is_list(p1) && is_list(p2) && (length(p2) < length(p1) || is_before_addition(p2, p1, parameter_order))) { + let subaddition = form_application("+", + parameter1, application_parameter2(parameter2)); + + return form_application("+", + DFSapplication(newpara2para1, parameter_order), + DFSapplication(subaddition, parameter_order)); + } else {} + + let subaddition = DFSapplication(form_application("+", + newpara2para1, + application_parameter2(parameter2)), parameter_order); + + return form_application("+", parameter1, subaddition); + } else { + //merge terms if their variables are the same + parameter1 = DFSapplication(parameter1, parameter_order); + parameter2 = DFSapplication(parameter2, parameter_order); + let numerator_p1 = 1; + let numerator_p2 = 1; + let denominator_p1 = 1; + let denominator_p2 = 1; + let p1 = parameter1; + let p2 = parameter2; + while (application_operation(p1) === "*" + && is_number(application_parameter1(p1))) { + numerator_p1 = numerator_p1 * application_parameter1(p1); + p1 = application_parameter2(p1); + } + while (application_operation(p1) === "*" + && application_operation(application_parameter1(p1)) === "/" + && is_number(application_parameter2(application_parameter1(p1)))) { + denominator_p1 = denominator_p1 * application_parameter2(application_parameter1(p1)); + p1 = application_parameter2(p1); + } + while (application_operation(p1) === "*" + && application_operation(application_parameter1(p1)) === "/" + && application_operation(application_parameter2(application_parameter1(p1))) === "*" + && is_number(application_parameter1(application_parameter2(application_parameter1(p1))))) { + denominator_p1 = denominator_p1 * application_parameter1(application_parameter2(application_parameter1(p1))); + let denominator_extract = form_application("/", 1, application_parameter2(application_parameter2(application_parameter1(p1)))); + p1 = form_application("*", denominator_extract, application_parameter2(p1)); + } + while (application_operation(p2) === "*" + && is_number(application_parameter1(p2))) { + numerator_p2 = numerator_p2 * application_parameter1(p2); + p2 = application_parameter2(p2); + } + while (application_operation(p2) === "*" + && application_operation(application_parameter1(p2)) === "/" + && is_number(application_parameter2(application_parameter1(p2)))) { + denominator_p2 = denominator_p2 * application_parameter2(application_parameter1(p2)); + p2 = application_parameter2(p2); + } + while (application_operation(p2) === "*" + && application_operation(application_parameter1(p2)) === "/" + && application_operation(application_parameter2(application_parameter1(p2))) === "*" + && is_number(application_parameter1(application_parameter2(application_parameter1(p2))))) { + denominator_p2 = denominator_p2 * application_parameter1(application_parameter2(application_parameter1(p2))); + let denominator_extract = form_application("/", 1, application_parameter2(application_parameter2(application_parameter1(p2)))); + p2 = form_application("*", denominator_extract, application_parameter2(p2)); + } + + if (equal(p1, p2)) { + numerator_p1 = numerator_p1 * denominator_p2 + numerator_p2 * denominator_p1; + denominator_p1 = denominator_p1 * denominator_p2; + if(numerator_p1 === denominator_p1){ + numerator_p1 = 1; + denominator_p1 = 1; + } else {} + let reciprocal = form_application("/", 1, denominator_p1); + + let submultiply = form_application("*", reciprocal, p1); + + let mainmultiply = DFSapplication(form_application("*", numerator_p1, submultiply), parameter_order); + + return mainmultiply; + } else if(is_list(p1) && is_list(p2) && (length(p2) < length(p1) || is_before_addition(p2, p1, parameter_order))){ + let temp = parameter1; + parameter1 = parameter2; + parameter2 = temp; + } else {} + + return form_application("+", parameter1, parameter2); + } + } else if (operation === "-") { //X - Y = X + (-1 * Y) + let negatedparameter2 = form_application("*", -1, parameter2); + + let sum = form_application("+", + DFSapplication(parameter1, parameter_order), DFSapplication(negatedparameter2, parameter_order)); + + return sum; + } else if (operation === "*") { //X * (Y + Z) = X * Y + X * Z + if (application_operation(parameter2) === "+") { + let distributed1 = form_application("*", + parameter1, application_parameter1(parameter2)); + + let distributed2 = form_application("*", + parameter1, application_parameter2(parameter2)); + + let distributedSum = form_application("+", + DFSapplication(distributed1, parameter_order), DFSapplication(distributed2, parameter_order)); + + return distributedSum; + } else if (application_operation(parameter1) === "+") { + let distributed1 = form_application("*", + parameter2, application_parameter1(parameter1)); + + let distributed2 = form_application("*", + parameter2, application_parameter2(parameter1)); + + let distributedSum = form_application("+", + DFSapplication(distributed1, parameter_order), DFSapplication(distributed2, parameter_order)); + + return distributedSum; + } else if (parameter1 === 1) { + return parameter2; + } else if (parameter1 === 0 || parameter2 === 0) { + return 0; + } else if (is_number(parameter1) && is_number(parameter2)) { + return parameter1 * parameter2; + } else if ((application_operation(parameter2)) === "/" + && application_parameter1(parameter2) === 1 && equal(parameter1, application_parameter2(parameter2))) { + return 1; + } else if (application_operation(parameter2) === "*" && application_operation(application_parameter1(parameter2)) === "/" + && application_parameter1(application_parameter1(parameter2)) === 1 + && equal(parameter1, application_parameter2(application_parameter1(parameter2)))) { + return form_application("*", + 1, DFSapplication(application_parameter2(parameter2), parameter_order)); + } else if (is_number(parameter1) && is_number(application_parameter1(parameter2)) && application_operation(parameter2) === "*") { + return form_application("*", + parameter1 * application_parameter1(parameter2), + DFSapplication(application_parameter2(parameter2), parameter_order)); + } else if (is_math_application(parameter1) && application_operation(parameter1) !== "/" && !is_math_application(parameter2) + || (!is_math_application(parameter1) && !is_math_application(parameter2) + && is_before_multiply(parameter2, parameter1, parameter_order)) + //|| application_operation(parameter1) === "/" && application_operation(parameter2) !== "/" + || application_operation(parameter2) === "/" && application_operation(parameter1) !== "/" + ) { + return form_application("*", + DFSapplication(parameter2, parameter_order), DFSapplication(parameter1, parameter_order)); + } else if (application_operation(parameter1) === "*") { + let submultiply = form_application("*", + application_parameter2(parameter1), parameter2); + + let mainmultiply = form_application("*", + DFSapplication(application_parameter1(parameter1), parameter_order), DFSapplication(submultiply, parameter_order)); + + return mainmultiply; + } else if (is_number(application_parameter1(parameter2)) + && application_operation(parameter2) === "*" + || application_operation(application_parameter1(parameter2)) === "/" + && application_operation(parameter2) === "*" && is_variable(parameter1) + ) { + let submultiply = form_application("*", + application_parameter2(parameter2), parameter1); + + let mainmultiply = form_application("*", + application_parameter1(parameter2), DFSapplication(submultiply, parameter_order)); + + return mainmultiply; + } else if (!is_number(application_parameter1(parameter2)) && !is_number(parameter1) + && application_operation(parameter2) === "*" && is_before_multiply(application_parameter1(parameter2), parameter1, parameter_order) + ) { + let submultiply = form_application("*", + application_parameter2(parameter2), parameter1); + + let mainmultiply = form_application("*", + application_parameter1(parameter2), DFSapplication(submultiply, parameter_order)); + + return mainmultiply; + } else if (application_operation(parameter1) === "/" && application_operation(parameter2) === "/" + ) { + let submultiply1 = form_application("*", + application_parameter1(parameter1), application_parameter1(parameter2)); + + let submultiply2 = form_application("*", + application_parameter2(parameter1), application_parameter2(parameter2)); + + let mainmultiply = form_application("/", + DFSapplication(submultiply1, parameter_order), DFSapplication(submultiply2, parameter_order)); + + return mainmultiply; + } else if (application_operation(parameter1) === "/" && application_operation(application_parameter1(parameter2)) === "/" + && application_operation(parameter2) === "*" + ) { + let submultiply1 = form_application("*", + application_parameter1(parameter1), application_parameter1(application_parameter1(parameter2))); + + let submultiply2 = form_application("*", + application_parameter2(parameter1), application_parameter2(application_parameter1(parameter2))); + + let mainmultiply = form_application("/", + DFSapplication(submultiply1, parameter_order), DFSapplication(submultiply2, parameter_order)); + + return form_application("*", + DFSapplication(mainmultiply, parameter_order), DFSapplication(application_parameter2(parameter2), parameter_order)); + } else { + return form_application("*", + DFSapplication(parameter1, parameter_order), DFSapplication(parameter2, parameter_order)); + } + } else if (operation === "/") { + if (parameter2 === 1) { + //this has 1 as denominator + return parameter1; + } else if (equal(parameter1, parameter2)) { + return 1; + } else if (parameter1 === 1 && application_operation(parameter2) !== "/") { + let extracted_denominator_denominator = 1; + if (application_operation(parameter2) === "*") { + let checkparameter2 = application_parameter1(parameter2); + if (application_operation(checkparameter2) === "/" + && application_parameter1(checkparameter2) === 1) { + extracted_denominator_denominator = application_parameter2(checkparameter2); + parameter2 = application_parameter2(parameter2); + } else if (is_number(checkparameter2) && application_operation(application_parameter2(parameter2)) === "*") { + let checkparameter2 = application_parameter1(application_parameter2(parameter2)); + if(application_operation(checkparameter2) === "/" + && application_parameter1(checkparameter2) === 1){ + extracted_denominator_denominator = application_parameter2(checkparameter2); + parameter2 = form_application("*", application_parameter1(parameter2), application_parameter2(application_parameter2(parameter2))); + display(parameter2); + } else {} + } else {} + } else {} + + //this has 1 as numerator && the denominator has no denominator + return form_application("/", + extracted_denominator_denominator, DFSapplication(parameter2, parameter_order)); + } else { + let reciprocal_numerator = 1; + let reciprocal_denominator = parameter2; + + if (application_operation(parameter2) === "/") { + reciprocal_numerator = application_parameter2(parameter2); + reciprocal_denominator = application_parameter1(parameter2); + } else {} + + let reciprocal = form_application("/", reciprocal_numerator, reciprocal_denominator); + + let productWithReciprocal = form_application("*", + DFSapplication(reciprocal, parameter_order), DFSapplication(parameter1, parameter_order)); + + return productWithReciprocal; + } + } else { + return f; + } +} + +//for + operations, clear the constants and return whether to swap the parameters to sort it by variable terms +function clear_constant_and_check_is_before_addition(p1, p2, parameter_order) { + let numerator_p1 = 1; + let numerator_p2 = 1; + let denominator_p1 = 1; + let denominator_p2 = 1; + while (application_operation(p1) === "*" + && is_number(application_parameter1(p1))) { + numerator_p1 = numerator_p1 * application_parameter1(p1); + p1 = application_parameter2(p1); + } + while (application_operation(p1) === "*" + && application_operation(application_parameter1(p1)) === "/" + && is_number(application_parameter2(application_parameter1(p1)))) { + denominator_p1 = denominator_p1 * application_parameter2(application_parameter1(p1)); + p1 = application_parameter2(p1); + } + while (application_operation(p1) === "*" + && application_operation(application_parameter1(p1)) === "/" + && application_operation(application_parameter2(application_parameter1(p1))) === "*" + && is_number(application_parameter1(application_parameter2(application_parameter1(p1))))) { + denominator_p1 = denominator_p1 * application_parameter1(application_parameter2(application_parameter1(p1))); + let denominator_extract = form_application("/", 1, application_parameter2(application_parameter2(application_parameter1(p1)))); + p1 = form_application("*", denominator_extract, application_parameter2(p1)); + } + while (application_operation(p2) === "*" + && is_number(application_parameter1(p2))) { + numerator_p2 = numerator_p2 * application_parameter1(p2); + p2 = application_parameter2(p2); + } + while (application_operation(p2) === "*" + && application_operation(application_parameter1(p2)) === "/" + && is_number(application_parameter2(application_parameter1(p2)))) { + denominator_p2 = denominator_p2 * application_parameter2(application_parameter1(p2)); + p2 = application_parameter2(p2); + } + while (application_operation(p2) === "*" + && application_operation(application_parameter1(p2)) === "/" + && application_operation(application_parameter2(application_parameter1(p2))) === "*" + && is_number(application_parameter1(application_parameter2(application_parameter1(p2))))) { + denominator_p2 = denominator_p2 * application_parameter1(application_parameter2(application_parameter1(p2))); + let denominator_extract = form_application("/", 1, application_parameter2(application_parameter2(application_parameter1(p2)))); + p2 = form_application("*", denominator_extract, application_parameter2(p2)); + } + return is_before_addition(p1, p2, parameter_order); +} + +//for + operations, return whether to swap the parameters to sort it by variable terms +function is_before_addition(p1, p2, parameter_order) { + if (application_operation(p1) === "*" && application_operation(p2) === "*") { + let p1head = application_parameter1(p1); + let p2head = application_parameter1(p2); + if (is_variable(p1head) && is_variable(p2head) && !equal(p1head, p2head)) { + return is_before_multiply(p1head, p2head, parameter_order); + } else { + return is_before_addition(application_parameter2(p1), application_parameter2(p2), parameter_order); + } + } else if (is_variable(p1) && is_variable(p2)) { + return is_before_multiply(p1, p2, parameter_order); + } else { + return false; + } +} + +//for * opeartion, return whether to swap ther variable order to sort it by parameter order +function is_before_multiply(p1, p2, parameter_order) { + let result = false; + if (application_operation(p2) === "/") { + result = false; + } else if (is_number(p1) && !is_number(p2)) { + result = true; + } else if (!is_number(p1) && is_number(p2)) { + result = false; + } else if (parameter_order === null) { + result = false; + } else if (equal(list_ref(parameter_order, 0), p2)) { + result = false; + } else if (equal(list_ref(parameter_order, 0), p1)) { + result = true; + } else { + result = is_before_multiply(p1, p2, tail(parameter_order)); + } + return result; +} + +//creates a math application +function form_application(operation, parameter1, parameter2){ + let app = + [ + "application", + [ + ["name", [operation, null]], + [ + [ + parameter1, + [ + parameter2, + null + ] + ], + null + ] + ] + ]; + return app; +} + +//creates a function +function form_function(function_name, parameter_order, simplified_return_sequence){ + let func = + [ "constant_declaration", + [ ["name", [function_name, null]], + [ [ "function_definition", + [ parameter_order, + [simplified_return_sequence, null] ] ], + null ] ] ]; + return func; +} \ No newline at end of file From 1d1a596c2b92b95e2a933ba64d322aaf3516df21 Mon Sep 17 00:00:00 2001 From: RomaRomama Date: Fri, 24 Apr 2020 14:46:33 +0800 Subject: [PATCH 2/6] Added end of file lines --- .../_tests_/source-4-partial-evaluator.arithmetictest.js | 4 +++- .../_tests_/source-4-partial-evaluator.bindtest.js | 3 ++- .../_tests_/source-4-partial-evaluator.conditionaltest.js | 4 +++- .../_tests_/source-4-partial-evaluator.mixtest.js | 4 +++- src/partial-evaluators/source-4-partial-evaluator.js | 3 ++- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js b/src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js index 1253485..bec6713 100644 --- a/src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js +++ b/src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js @@ -9,4 +9,6 @@ function test(x, y, z, w) { \ return 3 * y + 3 * w - x * w;\ }"), list(), list()); -equal(exa1, exa2); \ No newline at end of file +equal(exa1, exa2); +\\true + diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.bindtest.js b/src/partial-evaluators/_tests_/source-4-partial-evaluator.bindtest.js index cd8d3f7..a21dbe2 100644 --- a/src/partial-evaluators/_tests_/source-4-partial-evaluator.bindtest.js +++ b/src/partial-evaluators/_tests_/source-4-partial-evaluator.bindtest.js @@ -10,4 +10,5 @@ return 1;\ }"), list(), list()); equal(to_partialize, partialized); -\\true \ No newline at end of file +\\true + diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.conditionaltest.js b/src/partial-evaluators/_tests_/source-4-partial-evaluator.conditionaltest.js index 047b375..e18c849 100644 --- a/src/partial-evaluators/_tests_/source-4-partial-evaluator.conditionaltest.js +++ b/src/partial-evaluators/_tests_/source-4-partial-evaluator.conditionaltest.js @@ -21,4 +21,6 @@ function test(x, y, z, w) { \ }\ "), list(), list()); -equal(to_partialize, partialized); \ No newline at end of file +equal(to_partialize, partialized); +\\true + diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.mixtest.js b/src/partial-evaluators/_tests_/source-4-partial-evaluator.mixtest.js index 2ee121a..2d7f3c2 100644 --- a/src/partial-evaluators/_tests_/source-4-partial-evaluator.mixtest.js +++ b/src/partial-evaluators/_tests_/source-4-partial-evaluator.mixtest.js @@ -19,4 +19,6 @@ function test(x, y, z, w) { \ }\ "), list(), list()); -equal(to_partialize, partialized); \ No newline at end of file +equal(to_partialize, partialized); +\\true + diff --git a/src/partial-evaluators/source-4-partial-evaluator.js b/src/partial-evaluators/source-4-partial-evaluator.js index e65ca4b..292adad 100644 --- a/src/partial-evaluators/source-4-partial-evaluator.js +++ b/src/partial-evaluators/source-4-partial-evaluator.js @@ -910,4 +910,5 @@ function form_function(function_name, parameter_order, simplified_return_sequenc [simplified_return_sequence, null] ] ], null ] ] ]; return func; -} \ No newline at end of file +} + From 3cbffb695dd3aefd8bd511797f3ba1e7184f54eb Mon Sep 17 00:00:00 2001 From: Chong Hong Yun Date: Fri, 24 Apr 2020 17:41:03 +0800 Subject: [PATCH 3/6] Fixed typos and labels --- src/partial-evaluators/source-4-partial-evaluator.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/partial-evaluators/source-4-partial-evaluator.js b/src/partial-evaluators/source-4-partial-evaluator.js index 292adad..db421b5 100644 --- a/src/partial-evaluators/source-4-partial-evaluator.js +++ b/src/partial-evaluators/source-4-partial-evaluator.js @@ -4,18 +4,18 @@ function partial_evaluation(f, names, values) { let name = list_ref(function_name(f), 1); let binded_f = bind(f, names, values); - let final_simplified_conditionals = null; - while (!equal(final_simplified_conditionals, binded_f)) { - final_simplified_conditionals = binded_f; + let final_simplified = null; + while (!equal(final_simplified, binded_f)) { + final_simplified = binded_f; binded_f = repeatedDFSapplication(binded_f, function_parameters(binded_f)); binded_f = merge_simplified_conditionals(binded_f); } - let pretty_printed = pretty_print(final_simplified_conditionals); + let pretty_printed = pretty_print(final_simplified); display(pretty_printed); - return final_simplified_conditionals; + return final_simplified; } //prints all simplified math expressions in the function @@ -857,7 +857,7 @@ function is_before_addition(p1, p2, parameter_order) { } } -//for * opeartion, return whether to swap ther variable order to sort it by parameter order +//for * operation, return whether to swap ther variable order to sort it by parameter order function is_before_multiply(p1, p2, parameter_order) { let result = false; if (application_operation(p2) === "/") { From 49adab19317198721289008e8f2f01fc318ff09a Mon Sep 17 00:00:00 2001 From: Chong Hong Yun Date: Sat, 25 Apr 2020 18:30:41 +0800 Subject: [PATCH 4/6] fixed labelling --- .../_tests_/source-4-partial-evaluator.arithmetictest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js b/src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js index bec6713..20b753e 100644 --- a/src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js +++ b/src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js @@ -9,6 +9,6 @@ function test(x, y, z, w) { \ return 3 * y + 3 * w - x * w;\ }"), list(), list()); -equal(exa1, exa2); +equal(to_partialize, partialized); \\true From 3c4a8791c5f7c8cec2d970615ec64abb40641ec1 Mon Sep 17 00:00:00 2001 From: RomaRomama Date: Tue, 28 Apr 2020 13:32:38 +0800 Subject: [PATCH 5/6] Add opening comments --- .../source-4-partial-evaluator.js | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/partial-evaluators/source-4-partial-evaluator.js b/src/partial-evaluators/source-4-partial-evaluator.js index db421b5..5173192 100644 --- a/src/partial-evaluators/source-4-partial-evaluator.js +++ b/src/partial-evaluators/source-4-partial-evaluator.js @@ -1,3 +1,40 @@ +/* +A partial evaluator for language with booleans, conditionals, +sequences, functions, constants, variables and blocks + +This is a partial evaluator for a language that lets you declare +functions, variables and constants, apply functions, and +carry out simple arithmetic calculations, boolean operations. + +The covered sublanguage of Source ยง4 is: +program ::= stmt +stmt ::= const name = expression ; + | let name = expression ; + | function name ( params ) block + | stmt stmt + | return expression ; + | name = expr ; + | block +block ::= { stmt } +params ::=  | name ( , name )... +expr ::= number + | true | false + | null + | string + | name + | expr binop expr + | unop expr + | expr ( exprs ) + | ( params ) => expr + | ( params ) => block + | expr ? expr : expr + | ( expression ) +binop ::= + | - | * | / | % | === | !== + | > | < | >= | <= +unop ::= ! | - +exprs ::=  | expression ( , expression )... +*/ + //Given a program, list of global variables, and list of global values //Note: variables and values are corresponding respect to its order function partial_evaluation(f, names, values) { From d4afd55f40537a4587372bea4baa5c41f23c7b89 Mon Sep 17 00:00:00 2001 From: RomaRomama Date: Tue, 28 Apr 2020 17:01:07 +0800 Subject: [PATCH 6/6] Rename files --- ...ial-evaluator.arithmetictest.js => source-4.arithmetictest.js} | 0 ...ource-4-partial-evaluator.bindtest.js => source-4.bindtest.js} | 0 ...l-evaluator.conditionaltest.js => source-4.conditionaltest.js} | 0 ...{source-4-partial-evaluator.mixtest.js => source-4.mixtest.js} | 0 .../{source-4-partial-evaluator.js => source-4.js} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/partial-evaluators/_tests_/{source-4-partial-evaluator.arithmetictest.js => source-4.arithmetictest.js} (100%) rename src/partial-evaluators/_tests_/{source-4-partial-evaluator.bindtest.js => source-4.bindtest.js} (100%) rename src/partial-evaluators/_tests_/{source-4-partial-evaluator.conditionaltest.js => source-4.conditionaltest.js} (100%) rename src/partial-evaluators/_tests_/{source-4-partial-evaluator.mixtest.js => source-4.mixtest.js} (100%) rename src/partial-evaluators/{source-4-partial-evaluator.js => source-4.js} (100%) diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js b/src/partial-evaluators/_tests_/source-4.arithmetictest.js similarity index 100% rename from src/partial-evaluators/_tests_/source-4-partial-evaluator.arithmetictest.js rename to src/partial-evaluators/_tests_/source-4.arithmetictest.js diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.bindtest.js b/src/partial-evaluators/_tests_/source-4.bindtest.js similarity index 100% rename from src/partial-evaluators/_tests_/source-4-partial-evaluator.bindtest.js rename to src/partial-evaluators/_tests_/source-4.bindtest.js diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.conditionaltest.js b/src/partial-evaluators/_tests_/source-4.conditionaltest.js similarity index 100% rename from src/partial-evaluators/_tests_/source-4-partial-evaluator.conditionaltest.js rename to src/partial-evaluators/_tests_/source-4.conditionaltest.js diff --git a/src/partial-evaluators/_tests_/source-4-partial-evaluator.mixtest.js b/src/partial-evaluators/_tests_/source-4.mixtest.js similarity index 100% rename from src/partial-evaluators/_tests_/source-4-partial-evaluator.mixtest.js rename to src/partial-evaluators/_tests_/source-4.mixtest.js diff --git a/src/partial-evaluators/source-4-partial-evaluator.js b/src/partial-evaluators/source-4.js similarity index 100% rename from src/partial-evaluators/source-4-partial-evaluator.js rename to src/partial-evaluators/source-4.js