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

Chapter 4: Exercise 4.2 #914

Open
EmilyOng opened this issue Aug 27, 2023 · 0 comments
Open

Chapter 4: Exercise 4.2 #914

EmilyOng opened this issue Aug 27, 2023 · 0 comments

Comments

@EmilyOng
Copy link

EmilyOng commented Aug 27, 2023

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

  • Literals
  • Names
  • Applications
  • Conditionals
  • Lambdas
  • Sequences
  • Blocks
  • Returns
  • Assignments
  • Declarations
  • Functions
  • Operators

Notes:

  • Always surround the strings that result from unparsing operator combinations with parentheses to enforce respect for operator precedence
Code
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:

// Functions, returns, operators, conditionals, applications
display(unparse(parse("function factorial(n) { return n === 0 ? 1 : n * factorial(n - 1);}")));
// Lambdas, declarations, operators, conditionals, applications
display(unparse(parse("const factorial = n => n === 0 ? 1 : n * factorial(n - 1);")));
// Declarations, operators, applications, sequences
display(unparse(parse("const size = 2; let five_times = 5 * size; !true; 4 + p(5);")));
// Conditionals, applications
display(unparse(parse("if (is_even(n)) { display(\"even!\"); } else { display(\"odd!\"); } ")));
// Functions, conditionals, returns, operators, applications (this is the example for normal-order evaluation)
display(unparse(parse("function p() { return p(); } function f(x, y) { return x === 0 ? x : y; } f(0, p());")));

Result:

"function factorial(n) {\nreturn (n) === (0) ? 1 : (n) * (factorial((n) - (1)))\n}"
"const factorial = (n) => return (n) === (0) ? 1 : (n) * (factorial((n) - (1)))"
"const size = 2;\nlet five_times = (5) * (size);\n!(true);\n(4) + (p(5))"
"if (is_even(n)) {\ndisplay(even!)\n} else {\ndisplay(odd!)\n}"
"function p() {\nreturn p()\n};\nfunction f(x , y) {\nreturn (x) === (0) ? x : y\n};\nf(0 , p())"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant