Skip to content
Snippets Groups Projects
  • Sam Yates's avatar
    Add KINETIC block rewriter (issue #63) (#95) · 4e229b01
    Sam Yates authored
    Adds a new KineticRewriter visitor that transforms (after semantic analysis) a parsed KINETIC procedure into an equivalent DERIVATIVE procedure. The visitor takes a ProcedureExpression and composes the equivalent procedure, available via the as_procedure() method on the visitor object.
    
    Move common functinality for 'local' variable insertion during transformation phase to new files astmanip.?pp.
    Add Expression method for directly setting scope.
    Use scope_ptr type alias widely.
    Implement correct clone() behaviour for DerivativeExpression
    Implement KineticRewriter transforming visitor class.
    Add equivalence test for KineticRewriter: the test incorporates a simple ad-hoc algebraic expression simplifier.
    Add unit test to Parser.parse_binop to exercise bug #94
    4e229b01
functionexpander.hpp 2.70 KiB
#pragma once

#include <sstream>

#include "scope.hpp"
#include "visitor.hpp"

// storage for a list of expressions
using call_list_type = std::list<expression_ptr>;

// Make a local declaration and assignment for the given expression,
// and insert at the front and back respectively of the statement list.
// Return the new unique local identifier.
expression_ptr insert_unique_local_assignment(call_list_type& stmts, Expression* e);

// prototype for lowering function calls
call_list_type lower_function_calls(Expression* e);

///////////////////////////////////////////////////////////////////////////////
// visitor that takes function call sites and lowers them to inline assignments
//
// e.g. if called on the following statement
//
// a = 3 + foo(x, y)
//
// the calls_ member will be
//
// LOCAL ll0_
// ll0_ = foo(x,y)
//
// and the original statment is modified to be
//
// a = 3 + ll0_
//
// If the calls_ data is spliced directly before the original statement
// the function call will have been fully lowered
///////////////////////////////////////////////////////////////////////////////
class FunctionCallLowerer : public Visitor {
public:
    FunctionCallLowerer(scope_ptr s)
    :   scope_(s)
    {}

    void visit(CallExpression *e)       override;
    void visit(Expression *e)           override;
    void visit(UnaryExpression *e)      override;
    void visit(BinaryExpression *e)     override;
    void visit(NumberExpression *e)     override {};
    void visit(IdentifierExpression *e) override {};

    call_list_type& calls() {
        return calls_;
    }

    call_list_type move_calls() {
        return std::move(calls_);
    }

    ~FunctionCallLowerer() {}

private:
    template< typename F>
    void expand_call(CallExpression* func, F replacer) {
        auto id = insert_unique_local_assignment(calls_, func);
        // replace the function call in the original expression with the local
        // variable which holds the pre-computed value
        replacer(std::move(id));
    }

    call_list_type calls_;
    scope_ptr scope_;
};

///////////////////////////////////////////////////////////////////////////////
// visitor that takes function arguments that are not literals of identifiers
// and lowers them to inline assignments
//
// e.g. if called on the following statement
//
// a = foo(2+x, y)
//
// the calls_ member will be
//
// LOCAL ll0_
// ll0_ = 2+x
//
// and the original statment is modified to be
//
// a = foo(ll0_, y)
//
// If the calls_ data is spliced directly before the original statement
// the function arguments will have been fully lowered
///////////////////////////////////////////////////////////////////////////////
call_list_type lower_function_arguments(std::vector<expression_ptr>& args);