Changeset - ce6477db7861
[Not reviewed]
0 2 0
MH - 3 years ago 2022-02-04 18:11:51
contact@maxhenger.nl
WIP: More AST rewriting
2 files changed with 182 insertions and 6 deletions:
0 comments (0 inline, 0 general)
src/protocol/input_source.rs
Show inline comments
 
@@ -21,7 +21,8 @@ pub struct InputSpan {
 
}
 

	
 
impl InputSpan {
 
    // This will only be used for builtin functions
 
    // This must only be used if you're sure that the span will not be involved
 
    // in creating an error message.
 
    #[inline]
 
    pub fn new() -> InputSpan {
 
        InputSpan{ begin: InputPosition{ line: 0, offset: 0 }, end: InputPosition{ line: 0, offset: 0 }}
src/protocol/parser/pass_rewriting.rs
Show inline comments
 
// TODO: File contains a lot of manual AST element construction. Wherein we have
 
//  (for the first time in this compiler) a lot of fields that have no real
 
//  meaning (e.g. the InputSpan of a AST-transformation). What are we going to
 
//  do with this to make the code and datastructures more easily grokable?
 
//  We could do an intermediate AST structure. But considering how close this
 
//  phase of compilation is to bytecode generation, that might be a lot of busy-
 
//  work with few results. Alternatively we may put the AST elements inside
 
//  a special substructure. We could also force ourselves (and put the
 
//  appropriate comments in the code) to not use certain fields anymore after
 
//  a particular stage of compilation.
 

	
 
use crate::collections::*;
 
use crate::protocol::*;
 

	
 
@@ -112,11 +123,19 @@ impl Visitor for PassRewriting {
 
        for port_var_idx in 0..call_id_section.len() {
 
            let call_id = call_id_section[port_var_idx];
 
            let expr_id = expr_id_section[port_var_idx];
 
            let (replacement_variable_id, variable_stmt_id) = self.modify_call_and_create_replacement_variable(ctx, call_id, expr_id);
 
            transformed_stmts.push(variable_stmt_id);
 
            let (replacement_variable_id, variable_stmt_id) = self.modify_get_call_insert_variable(ctx, call_id, expr_id);
 
            transformed_stmts.push(variable_stmt_id.upcast().upcast());
 
            locals.push(replacement_variable_id);
 
        }
 

	
 
        // Our transformed statements now contain all of the temporary port
 
        // calculations. We'll now insert the appropriate runtime calls to
 
        // notify the runtime that we're going to wait on these ports.
 
        let (_, select_start_stmt_id) = self.create_runtime_select_start_call_statement(ctx, total_num_cases, total_num_ports);
 
        transformed_stmts.push(select_start_stmt_id.upcast());
 

	
 
        // TODO: Call the runtime function for eeach of the substituted port variables to register all ports for the select statement
 

	
 
        call_id_section.forget();
 
        expr_id_section.forget();
 

	
 
@@ -139,7 +158,7 @@ impl Visitor for PassRewriting {
 
}
 

	
 
impl PassRewriting {
 
    fn modify_call_and_create_replacement_variable(&self, ctx: &mut Ctx, call_expr_id: CallExpressionId, port_expr_id: ExpressionId) -> (VariableId, MemoryStatementId) {
 
    fn modify_get_call_insert_variable(&self, ctx: &mut Ctx, call_expr_id: CallExpressionId, port_expr_id: ExpressionId) -> (VariableId, MemoryStatementId) {
 
        // Retrieve original expression which we're going to transplant into
 
        // its own variable
 
        let port_expr = &ctx.heap[port_expr_id];
 
@@ -175,8 +194,8 @@ impl PassRewriting {
 
                full_span: port_expr_span
 
            },
 
            identifier: Identifier::new_empty(port_expr_span),
 
            relative_pos_in_block: 0,
 
            unique_id_in_scope: 0,
 
            relative_pos_in_block: -1,
 
            unique_id_in_scope: -1,
 
        });
 
        let variable_decl_stmt = ctx.heap.alloc_memory_statement(|this| MemoryStatement{
 
            this,
 
@@ -209,9 +228,165 @@ impl PassRewriting {
 
            unique_id_in_definition: port_expr_unique_id,
 
        });
 
        let call_expr = &mut ctx.heap[call_expr_id];
 
        debug_assert_eq!(call_expr.method, Method::Get);
 
        debug_assert!(call_expr.arguments.len() == 1 && call_expr.arguments[0] == port_expr_id);
 
        call_expr.arguments[0] = call_arg_expr_id.upcast();
 

	
 
        return (variable_id, variable_decl_stmt);
 
    }
 

	
 
    fn create_runtime_call_statement(&self, ctx: &mut Ctx, method: Method, arguments: Vec<ExpressionId>) -> (CallExpressionId, ExpressionStatementId) {
 
        let call_expr_id = ctx.heap.alloc_call_expression(|this| CallExpression{
 
            this,
 
            func_span: InputSpan::new(),
 
            full_span: InputSpan::new(),
 
            parser_type: ParserType{
 
                elements: Vec::new(),
 
                full_span: InputSpan::new(),
 
            },
 
            method,
 
            arguments,
 
            definition: DefinitionId::new_invalid(),
 
            parent: ExpressionParent::None,
 
            unique_id_in_definition: -1,
 
        });
 
        let call_stmt_id = ctx.heap.alloc_expression_statement(|this| ExpressionStatement{
 
            this,
 
            span: InputSpan::new(),
 
            expression: call_expr_id.upcast(),
 
            next: StatementId::new_invalid(),
 
        });
 

	
 
        let call_expr = &mut ctx.heap[call_expr_id];
 
        call_expr.parent = ExpressionParent::ExpressionStmt(call_stmt_id);
 

	
 
        return (call_expr_id, call_stmt_id);
 
    }
 

	
 
    fn create_runtime_select_start_call_statement(&self, ctx: &mut Ctx, num_cases: usize, num_ports_total: usize) -> (CallExpressionId, ExpressionStatementId) {
 
        let num_cases_expr_id = self.create_literal_integer(ctx, num_cases as u64);
 
        let num_ports_expr_id = self.create_literal_integer(ctx, num_ports_total as u64);
 
        let arguments = vec![
 
            num_cases_expr_id.upcast(),
 
            num_ports_expr_id.upcast()
 
        ];
 

	
 
        let (call_expr_id, call_stmt_id) = self.create_runtime_call_statement(ctx, Method::SelectStart, arguments);
 

	
 
        let num_cases_expr = &mut ctx.heap[num_cases_expr_id];
 
        num_cases_expr.parent = ExpressionParent::Expression(call_expr_id.upcast(), 0);
 
        let num_ports_expr = &mut ctx.heap[num_ports_expr_id];
 
        num_ports_expr.parent = ExpressionParent::Expression(num_ports_expr_id.upcast(), 1);
 

	
 
        return (call_expr_id, call_stmt_id);
 
    }
 

	
 
    fn create_runtime_select_register_port_call_statement(&self, ctx: &mut Ctx, case_index: usize, port_index: usize, original_port_expr_id: ExpressionId, port_variable_id: VariableId) -> (CallExpressionId, ExpressionStatementId) {
 
        let original_port_expr = &ctx.heap[original_port_expr_id];
 
        let original_port_span = original_port_expr.full_span();
 
        let original_port_unique_id = original_port_expr.get_unique_id_in_definition();
 

	
 
        let case_index_expr_id = self.create_literal_integer(ctx, case_index as u64);
 
        let port_index_expr_id = self.create_literal_integer(ctx, port_index as u64);
 
        let port_var_expr_id = self.create_variable_expr(ctx, port_variable_id);
 

	
 
        let arguments = vec![
 
            case_index_expr_id.upcast(),
 
            port_index_expr_id.upcast(),
 
            port_var_expr_id.upcast()
 
        ];
 

	
 
        let (call_expr_id, call_stmt_id) = self.create_runtime_call_statement(ctx, Method::SelectRegisterCasePort, arguments);
 

	
 
        let case_index_expr = &mut ctx.heap[case_index_expr_id];
 
        case_index_expr.parent = ExpressionParent::Expression(call_expr_id.upcast(), 0);
 
        let port_index_expr = &mut ctx.heap[port_index_expr_id];
 
        port_index_expr.parent = ExpressionParent::Expression(call_expr_id.upcast(), 1);
 
        let port_var_expr = &mut ctx.heap[port_var_expr_id];
 
        port_var_expr.parent = ExpressionParent::Expression(call_expr_id.upcast(), 2);
 

	
 
        return (call_expr_id, call_stmt_id);
 
    }
 

	
 
    fn create_runtime_select_wait_variable_and_statement(&self, ctx: &mut Ctx) -> (VariableId, MemoryStatementId) {
 
        let variable_id = ctx.heap.alloc_variable(|this| Variable{
 
            this,
 
            kind: VariableKind::Local,
 
            parser_type: ParserType{
 
                elements: Vec::new(),
 
                full_span: InputSpan::new(),
 
            },
 
            identifier: Identifier::new_empty(InputSpan::new()),
 
            relative_pos_in_block: -1,
 
            unique_id_in_scope: -1
 
        });
 
        let variable_expr_id = self.create_variable_expr(ctx, variable_id);
 
        let runtime_call_expr_id = ctx.heap.alloc_call_expression(|this| CallExpression{
 
            this,
 
            func_span: InputSpan::new(),
 
            full_span: InputSpan::new(),
 
            parser_type: ParserType{
 
                elements: Vec::new(),
 
                full_span: InputSpan::new(),
 
            },
 
            method: Method::SelectWait,
 
            arguments: Vec::new(),
 
            definition: DefinitionId::new_invalid(),
 
            parent: ExpressionParent::None,
 
            unique_id_in_definition: -1
 
        });
 
        let initial_expr_id = ctx.heap.alloc_assignment_expression(|this| AssignmentExpression{
 
            this,
 
            operator_span: InputSpan::new(),
 
            full_span: InputSpan::new(),
 
            left: variable_expr_id.upcast(),
 
            operation: AssignmentOperator::Set,
 
            right: runtime_call_expr_id.upcast(),
 
            parent: ExpressionParent::None,
 
            unique_id_in_definition: -1
 
        });
 

	
 
        let variable_statement_id = ctx.heap.alloc_memory_statement(|this| MemoryStatement{
 
            this,
 
            span: InputSpan::new(),
 
            variable: variable_id,
 
            initial_expr: initial_expr_id,
 
            next: StatementId::new_invalid()
 
        });
 

	
 
        let variable_expr = &mut ctx.heap[variable_expr_id];
 
        variable_expr.parent = ExpressionParent::Expression(initial_expr_id.upcast(), 0);
 
        let runtime_call_expr = &mut ctx.heap[runtime_call_expr_id];
 
        runtime_call_expr.parent = ExpressionParent::Expression(initial_expr_id.upcast(), 1);
 
        let initial_expr = &mut ctx.heap[initial_expr_id];
 
        initial_expr.parent = ExpressionParent::Memory(variable_statement_id);
 

	
 
        return (variable_id, variable_statement_id);
 
    }
 

	
 
    /// Creates an integer literal. The caller still needs to set its expression
 
    /// parent afterwards.
 
    fn create_literal_integer(&self, ctx: &mut Ctx, value: u64) -> LiteralExpressionId {
 
        return ctx.heap.alloc_literal_expression(|this| LiteralExpression{
 
            this,
 
            span: InputSpan::new(),
 
            value: Literal::Integer(LiteralInteger{
 
                unsigned_value: value,
 
                negated: false,
 
            }),
 
            parent: ExpressionParent::None,
 
            unique_id_in_definition: -1
 
        });
 
    }
 

	
 
    fn create_variable_expr(&self, ctx: &mut Ctx, variable_id: VariableId) -> VariableExpressionId {
 
        return ctx.heap.alloc_variable_expression(|this| VariableExpression{
 
            this,
 
            identifier: Identifier::new_empty(InputSpan::new()),
 
            declaration: Some(variable_id),
 
            used_as_binding_target: false,
 
            parent: ExpressionParent::None,
 
            unique_id_in_definition: -1
 
        })
 
    }
 
}
 
\ No newline at end of file
0 comments (0 inline, 0 general)