public static JumpTarget exit_target(BasicBlock basic_block) { JumpTarget @this = new JumpTarget(); @this.basic_block = basic_block; @this.is_exit_target = true; return(@this); }
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); }
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); }
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); }
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)); } }
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); }
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); }
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); }
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(); } }
public void TeleportToJumpTarget(JumpTarget target) { transform.position = target.transform.position; transform.rotation = target.transform.rotation; _currTarget = target; }