Example #1
0
            public static JumpTarget exit_target(BasicBlock basic_block)
            {
                JumpTarget @this = new JumpTarget();

                @this.basic_block    = basic_block;
                @this.is_exit_target = true;
                return(@this);
            }
Example #2
0
            public static JumpTarget finally_clause(BasicBlock basic_block, BasicBlock last_block)
            {
                JumpTarget @this = new JumpTarget();

                @this.basic_block       = basic_block;
                @this.last_block        = last_block;
                @this.is_finally_clause = true;
                return(@this);
            }
Example #3
0
            public static JumpTarget error_target(BasicBlock basic_block, CatchClause catch_clause, ErrorDomain error_domain, ErrorCode error_code, Class error_class)
            {
                JumpTarget @this = new JumpTarget();

                @this.basic_block     = basic_block;
                @this.catch_clause    = catch_clause;
                @this.error_domain    = error_domain;
                @this.error_code      = error_code;
                @this.error_class     = error_class;
                @this.is_error_target = true;
                return(@this);
            }
Example #4
0
        void visit_subroutine(Subroutine m)
        {
            if (m.body == null)
            {
                return;
            }

            m.entry_block  = BasicBlock.entry();
            m.return_block = new BasicBlock();
            m.exit_block   = BasicBlock.exit();

            m.return_block.connect(m.exit_block);

            if (m is Method)
            {
                // ensure out parameters are defined at end of method
                foreach (var param in ((Method)m).get_parameters())
                {
                    if (param.direction == ParameterDirection.OUT)
                    {
                        var param_ma = MemberAccess.simple(param.name, param.source_reference);
                        param_ma.symbol_reference = param;
                        m.return_block.add_node(param_ma);
                    }
                }
            }

            current_block = new BasicBlock();
            m.entry_block.connect(current_block);
            current_block.add_node(m);

            jump_stack.Add(JumpTarget.return_target(m.return_block));
            jump_stack.Add(JumpTarget.exit_target(m.exit_block));

            m.accept_children(this);

            jump_stack.RemoveAt(jump_stack.Count - 1);

            if (current_block != null)
            {
                // end of method body reachable

                if (m.has_result)
                {
                    Report.error(m.source_reference, "missing return statement at end of subroutine body");
                    m.error = true;
                }

                current_block.connect(m.return_block);
            }

            analyze_body(m.entry_block);
        }
Example #5
0
            public static JumpTarget any_target(BasicBlock basic_block)
            {
                JumpTarget @this = new JumpTarget();

                @this.basic_block        = basic_block;
                @this.is_break_target    = true;
                @this.is_continue_target = true;
                @this.is_return_target   = true;
                @this.is_exit_target     = true;
                @this.is_error_target    = true;
                return(@this);
            }
        public static string GetAssemblySymbol(this JumpTarget jumpTarget)
        {
            switch (jumpTarget)
            {
            case LabelTarget target:
                return($"{target.Label}");

            case SourceTarget target:
                return($"{target.Target.GetAssemblySymbol()}");

            default:
                throw new ArgumentOutOfRangeException(nameof(jumpTarget));
            }
        }
Example #7
0
        public override void visit_loop(Loop stmt)
        {
            if (unreachable(stmt))
            {
                return;
            }

            var loop_block = new BasicBlock();

            jump_stack.Add(JumpTarget.continue_target(loop_block));
            var after_loop_block = new BasicBlock();

            jump_stack.Add(JumpTarget.break_target(after_loop_block));

            // loop block
            var last_block = current_block;

            last_block.connect(loop_block);
            current_block = loop_block;

            stmt.body.accept(this);
            // end of loop block reachable?
            if (current_block != null)
            {
                current_block.connect(loop_block);
            }

            // after loop
            // reachable?
            if (after_loop_block.get_predecessors().Count == 0)
            {
                // after loop block not reachable
                mark_unreachable();
            }
            else
            {
                // after loop block reachable
                current_block = after_loop_block;
            }

            jump_stack.RemoveAt(jump_stack.Count - 1);
            jump_stack.RemoveAt(jump_stack.Count - 1);
        }
Example #8
0
        public override void visit_foreach_statement(ForeachStatement stmt)
        {
            if (unreachable(stmt))
            {
                return;
            }

            // collection
            current_block.add_node(stmt.collection);
            handle_errors(stmt.collection);

            var loop_block = new BasicBlock();

            jump_stack.Add(JumpTarget.continue_target(loop_block));
            var after_loop_block = new BasicBlock();

            jump_stack.Add(JumpTarget.break_target(after_loop_block));

            // loop block
            var last_block = current_block;

            last_block.connect(loop_block);
            current_block = loop_block;
            current_block.add_node(stmt);
            stmt.body.accept(this);
            if (current_block != null)
            {
                current_block.connect(loop_block);
            }

            // after loop
            last_block.connect(after_loop_block);
            if (current_block != null)
            {
                current_block.connect(after_loop_block);
            }
            current_block = after_loop_block;

            jump_stack.RemoveAt(jump_stack.Count - 1);
            jump_stack.RemoveAt(jump_stack.Count - 1);
        }
Example #9
0
        public override void visit_switch_statement(SwitchStatement stmt)
        {
            if (unreachable(stmt))
            {
                return;
            }

            var after_switch_block = new BasicBlock();

            jump_stack.Add(JumpTarget.break_target(after_switch_block));

            // condition
            current_block.add_node(stmt.expression);
            var condition_block = current_block;

            handle_errors(stmt.expression);

            bool has_default_label = false;

            foreach (SwitchSection section in stmt.get_sections())
            {
                current_block = new BasicBlock();
                condition_block.connect(current_block);
                foreach (Statement section_stmt in section.get_statements())
                {
                    section_stmt.node.accept(this);
                }

                if (section.has_default_label())
                {
                    has_default_label = true;
                }

                if (current_block != null)
                {
                    // end of switch section reachable
                    // we don't allow fall-through

                    Report.error(section.source_reference, "missing break statement at end of switch section");
                    section.error = true;

                    current_block.connect(after_switch_block);
                }
            }

            if (!has_default_label)
            {
                condition_block.connect(after_switch_block);
            }

            // after switch
            // reachable?
            if (after_switch_block.get_predecessors().Count > 0)
            {
                current_block = after_switch_block;
            }
            else
            {
                mark_unreachable();
            }

            jump_stack.RemoveAt(jump_stack.Count - 1);
        }
Example #10
0
        public override void visit_try_statement(TryStatement stmt)
        {
            if (unreachable(stmt))
            {
                return;
            }

            var before_try_block = current_block;
            var after_try_block  = new BasicBlock();

            BasicBlock finally_block = null;

            if (stmt.finally_body != null)
            {
                finally_block = new BasicBlock();
                current_block = finally_block;

                // trap all forbidden jumps
                var invalid_block = new BasicBlock();
                jump_stack.Add(JumpTarget.any_target(invalid_block));

                stmt.finally_body.accept(this);

                if (invalid_block.get_predecessors().Count > 0)
                {
                    // don't allow finally blocks with e.g. return statements
                    Report.error(stmt.source_reference, "jump out of finally block not permitted");
                    stmt.error = true;
                    return;
                }
                jump_stack.RemoveAt(jump_stack.Count - 1);

                jump_stack.Add(JumpTarget.finally_clause(finally_block, current_block));
            }

            int finally_jump_stack_size = jump_stack.Count;

            var catch_clauses = stmt.get_catch_clauses();

            for (int i = catch_clauses.Count - 1; i >= 0; i--)
            {
                var catch_clause = catch_clauses[i];
                if (catch_clause.error_type != null)
                {
                    var error_type = (ErrorType)catch_clause.error_type;
                    jump_stack.Add(JumpTarget.error_target(new BasicBlock(), catch_clause, catch_clause.error_type.data_type as ErrorDomain, error_type.error_code, null));
                }
                else
                {
                    jump_stack.Add(JumpTarget.error_target(new BasicBlock(), catch_clause, null, null, null));
                }
            }

            current_block = before_try_block;

            stmt.body.accept(this);

            if (current_block != null)
            {
                if (finally_block != null)
                {
                    current_block.connect(finally_block);
                    current_block = finally_block;
                }
                current_block.connect(after_try_block);
            }

            // remove catch clauses from jump stack
            List <JumpTarget> catch_stack = new List <JumpTarget>();

            for (int i = jump_stack.Count - 1; i >= finally_jump_stack_size; i--)
            {
                var jump_target = jump_stack[i];
                jump_stack.RemoveAt(i);
                catch_stack.Add(jump_target);
            }

            foreach (JumpTarget jump_target in catch_stack)
            {
                foreach (JumpTarget prev_target in catch_stack)
                {
                    if (prev_target == jump_target)
                    {
                        break;
                    }

                    if (prev_target.error_domain == jump_target.error_domain &&
                        prev_target.error_code == jump_target.error_code)
                    {
                        Report.error(stmt.source_reference, "double catch clause of same error detected");
                        stmt.error = true;
                        return;
                    }
                }

                if (jump_target.basic_block.get_predecessors().Count == 0)
                {
                    // unreachable
                    Report.warning(jump_target.catch_clause.source_reference, "unreachable catch clause detected");
                }
                else
                {
                    current_block = jump_target.basic_block;
                    current_block.add_node(jump_target.catch_clause);
                    jump_target.catch_clause.body.accept(this);
                    if (current_block != null)
                    {
                        if (finally_block != null)
                        {
                            current_block.connect(finally_block);
                            current_block = finally_block;
                        }
                        current_block.connect(after_try_block);
                    }
                }
            }

            if (finally_block != null)
            {
                jump_stack.RemoveAt(jump_stack.Count - 1);
            }

            // after try statement
            // reachable?
            if (after_try_block.get_predecessors().Count > 0)
            {
                current_block = after_try_block;
            }
            else
            {
                stmt.after_try_block_reachable = false;
                mark_unreachable();
            }
        }
Example #11
0
 public void TeleportToJumpTarget(JumpTarget target)
 {
     transform.position = target.transform.position;
     transform.rotation = target.transform.rotation;
     _currTarget        = target;
 }