Open EmilyOng opened 1 year ago
There were various issues with this solution, involving the placement of semicolons. Here is an improved version: https://share.sourceacademy.org/6yoyp The major remaining problem: expression statements that are applications do not end with a semicolon. To fix this, one would need to carefully distinguish between statements and expressions. So I'll mark this as "work-in-progress", hoping that someone finds the time for this.
Also: indentation would be nice!
Here is my suggestion for Exercise 4.2: https://share.sourceacademy.org/c53du
Specifications on syntax predicates and selectors are taken from: https://sourceacademy.org/sicpjs/4.1.2
Supports
Notes:
Code
```javascript function is_tagged_list(component, the_tag) { return is_pair(component) && head(component) === the_tag; } // Literals function is_literal(component) { return is_tagged_list(component, "literal"); } function literal_value(component) { return head(tail(component)); } function construct_literal(component) { const literal = literal_value(component); return is_string(literal) ? literal : stringify(literal); } // Names function is_name(component) { return is_tagged_list(component, "name"); } function symbol_of_name(component) { return head(tail(component)); } // Applications function is_application(component) { return is_tagged_list(component, "application"); } function function_expression(component) { return head(tail(component)); } function arg_expressions(component) { return head(tail(tail(component))); } function construct_function_application(component, unparse) { // Constructs fun-expr(arg-expr_1, ..., arg-expr_n) return unparse(function_expression(component)) + bracketize(join(map(unparse, arg_expressions(component)), " , ")); } // Conditionals function is_conditional_expression(component) { return is_tagged_list(component, "conditional_expression"); } function is_conditional_statement(component) { return is_tagged_list(component, "conditional_statement"); } function conditional_predicate(component) { return head(tail(component)); } function conditional_consequent(component) { return head(tail(tail(component))); } function conditional_alternative(component) { return head(tail(tail(tail(component)))); } function construct_conditional_expression(component, unparse) { return unparse(conditional_predicate(component)) + " ? " + unparse(conditional_consequent(component)) + " : " + unparse(conditional_alternative(component)); } function construct_conditional_statement(component, unparse) { return "if " + bracketize(unparse(conditional_predicate(component))) + " {\n" + unparse(conditional_consequent(component)) + "\n} " + "else {\n" + unparse(conditional_alternative(component)) + "\n}"; } // Lambdas function is_lambda_expression(component) { return is_tagged_list(component, "lambda_expression"); } function lambda_parameter_symbols(component) { return head(tail(component)); } function lambda_body(component) { return head(tail(tail(component))); } function construct_lambda_expression(component, unparse) { const names = map(unparse, lambda_parameter_symbols(component)); const block = unparse(lambda_body(component)); return bracketize(join(names, " , ")) + " => " + block; } // Sequences function is_sequence(component) { return is_tagged_list(component, "sequence"); } function sequence_statements(component) { return head(tail(component)); } function construct_sequence(component, unparse) { return join(map(unparse, sequence_statements(component)), ";\n"); } // Blocks function is_block(component) { return is_tagged_list(component, "block"); } function block_body(component) { return head(tail(component)); } function construct_block(component, unparse) { return "{\n" + unparse(block_body(component)) + "\n}"; } // Returns function is_return_statement(component) { return is_tagged_list(component, "return_statement"); } function return_expression(component) { return head(tail(component)); } function construct_return_statement(component, unparse) { return "return " + unparse(return_expression(component)); } // Assignments function is_assignment(component) { return is_tagged_list(component, "assignment"); } function assignment_symbol(component) { return head(tail(component)); } function assignment_value_expression(component) { return head(tail(tail(component))); } function construct_assignment(component, unparse) { return unparse(assignment_symbol(component)) + " = " + unparse(assignment_value_expression(component)); } // Declarations function is_constant_declaratino(component) { return is_tagged_list(component, "constant_declaration"); } function is_variable_declaration(component) { return is_tagged_list(component, "variable_declaration"); } function declaration_symbol(component) { return head(tail(component)); } function declaration_value_expression(component) { return head(tail(tail(component))); } function construct_constant_declaration(component, unparse) { return "const " + unparse(declaration_symbol(component)) + " = " + unparse(declaration_value_expression(component)); } function construct_variable_declaration(component, unparse) { return "let " + unparse(declaration_symbol(component)) + " = " + unparse(declaration_value_expression(component)); } // Functions function is_function_declaration(component) { return is_tagged_list(component, "function_declaration"); } function function_declaration_name(component) { return head(tail(component)); } function function_declaration_parameters(component) { return head(tail(tail(component))); } function function_declaration_body(component) { return head(tail(tail(tail(component)))); } function construct_function_declaration(component, unparse) { return "function " + unparse(function_declaration_name(component)) + bracketize(join(map(unparse, function_declaration_parameters(component)), " , ")) + " {\n" + unparse(function_declaration_body(component)) + "\n}"; } // Operators function is_unary_operator_combination(component) { return is_tagged_list(component, "unary_operator_combination"); } function is_binary_operator_combination(component) { return is_tagged_list(component, "binary_operator_combination"); } function operator_symbol(component) { return head(tail(component)); } function first_operand(component) { return head(tail(tail(component))); } function second_operand(component) { return head(tail(tail(tail(component)))); } function construct_unary_operator_combination(component, unparse) { // Always use parantheses to enforce respect for operator precedence return operator_symbol(component) + bracketize(unparse(first_operand(component))); } function construct_binary_operator_combination(component, unparse) { // Always use parantheses to enforce respect for operator precedence return bracketize(unparse(first_operand(component))) + " " + operator_symbol(component) + " " + bracketize(unparse(second_operand(component))); } // Helpers function join(sequence, delimitter) { return is_null(sequence) ? "" : is_null(tail(sequence)) ? head(sequence) : head(sequence) + delimitter + join(tail(sequence), delimitter); } function bracketize(unparsed) { return "(" + unparsed + ")"; } function unparse(component) { return is_literal(component) ? construct_literal(component) : is_name(component) ? symbol_of_name(component) : is_application(component) ? construct_function_application(component, unparse) : is_conditional_expression(component) ? construct_conditional_expression(component, unparse) : is_conditional_statement(component) ? construct_conditional_statement(component, unparse) : is_lambda_expression(component) ? construct_lambda_expression(component, unparse) : is_sequence(component) ? construct_sequence(component, unparse) : is_block(component) ? construct_block(component, unparse) : is_return_statement(component) ? construct_return_statement(component, unparse) : is_assignment(component) ? construct_assignment(component, unparse) : is_constant_declaratino(component) ? construct_constant_declaration(component, unparse) : is_variable_declaration(component) ? construct_variable_declaration(component, unparse) : is_function_declaration(component) ? construct_function_declaration(component, unparse) : is_unary_operator_combination(component) ? construct_unary_operator_combination(component, unparse) : is_binary_operator_combination(component) ? construct_binary_operator_combination(component, unparse) : error(component, "unknown syntax -- unparse"); } ```Some sample cases:
Result: