void jsil_typecheckt::typecheck_expr_index(exprt &expr) { if(expr.operands().size()!=2) { err_location(expr); error() << "operator `" << expr.id() << "' expects two operands" << eom; throw 0; } make_type_compatible(expr.op0(), jsil_object_type(), true); make_type_compatible(expr.op1(), string_typet(), true); // special case for function identifiers if (expr.op1().id()=="fid" || expr.op1().id()=="constructid") expr.type()=code_typet(); else expr.type()=jsil_value_type(); }
void cpp_typecheckt::static_initialization() { code_blockt block_sini; // Static Initialization Block code_blockt block_dini; // Dynamic Initialization Block disable_access_control = true; // first do zero initialization context.foreach_operand([this, &block_sini](const symbolt &s) { if(!s.static_lifetime || s.mode != current_mode) return; // it has a non-code initializer already? if(s.value.is_not_nil() && s.value.id() != "code") return; // it's a declaration only if(s.is_extern) return; if(!s.lvalue) return; zero_initializer( cpp_symbol_expr(s), s.type, s.location, block_sini.operands()); }); while(!dinis.empty()) { symbolt &symbol = *context.find_symbol(dinis.front()); dinis.pop_front(); if(symbol.is_extern) continue; if(symbol.mode != current_mode) continue; assert(symbol.static_lifetime); assert(!symbol.is_type); assert(symbol.type.id() != "code"); exprt symexpr = cpp_symbol_expr(symbol); if(symbol.value.is_not_nil()) { if(!cpp_is_pod(symbol.type)) { block_dini.move_to_operands(symbol.value); } else { exprt symbexpr("symbol", symbol.type); symbexpr.identifier(symbol.name); codet code; code.set_statement("assign"); code.copy_to_operands(symbexpr, symbol.value); code.location() = symbol.location; if(symbol.value.id() == "constant") block_sini.move_to_operands(code); else block_dini.move_to_operands(code); } // Make it nil because we do not want // global_init to try to initialize the // object symbol.value.make_nil(); } else { exprt::operandst ops; codet call = cpp_constructor(locationt(), symexpr, ops); if(call.is_not_nil()) block_dini.move_to_operands(call); } } block_sini.move_to_operands(block_dini); // Create the initialization procedure symbolt init_symbol; init_symbol.name = "#ini#" + id2string(module); init_symbol.base_name = "#ini#" + id2string(module); init_symbol.value.swap(block_sini); init_symbol.mode = current_mode; init_symbol.module = module; init_symbol.type = code_typet(); init_symbol.type.add("return_type") = typet("empty"); init_symbol.type.set("initialization", true); init_symbol.is_type = false; init_symbol.is_macro = false; context.move(init_symbol); disable_access_control = false; }
void jsil_typecheckt::typecheck_function_call( code_function_callt &call) { if(call.operands().size()!=3) throw "function call expected to have three operands"; exprt &lhs=call.lhs(); typecheck_expr(lhs); exprt &f=call.function(); typecheck_expr(f); for(auto &arg : call.arguments()) typecheck_expr(arg); // Look for a function declaration symbol in the symbol table if(f.id()==ID_symbol) { const irep_idt &id=to_symbol_expr(f).get_identifier(); if(symbol_table.has_symbol(id)) { symbolt &s=symbol_table.lookup(id); if(s.type.id()==ID_code) { code_typet &codet=to_code_type(s.type); for(std::size_t i=0; i<codet.parameters().size(); i++) { if(i>=call.arguments().size()) break; const typet ¶m_type=codet.parameters()[i].type(); if(!param_type.id().empty() && param_type.is_not_nil()) { // check argument's type if parameter's type is given make_type_compatible(call.arguments()[i], param_type, true); } } // if there are too few arguments, add undefined if(codet.parameters().size()>call.arguments().size()) { for(std::size_t i=call.arguments().size(); i<codet.parameters().size(); ++i) call.arguments().push_back( exprt("undefined", jsil_undefined_type())); } // if there are too many arguments, remove while(codet.parameters().size()<call.arguments().size()) call.arguments().pop_back(); // check return type if exists if(!codet.return_type().id().empty() && codet.return_type().is_not_nil()) make_type_compatible(lhs, codet.return_type(), true); else make_type_compatible(lhs, jsil_any_type(), true); } else { // TODO: a symbol can be a variable evaluating to a string // which corresponds to a function identifier make_type_compatible(lhs, jsil_any_type(), true); } } else { // Should be function, declaration not found yet symbolt new_symbol; new_symbol.name=id; new_symbol.type=code_typet(); new_symbol.mode="jsil"; new_symbol.is_type=false; new_symbol.value=exprt("no-body-just-yet"); make_type_compatible(lhs, jsil_any_type(), true); if(symbol_table.add(new_symbol)) throw "failed to add expression symbol to symbol table"; } } else { // TODO: this might be a string literal // which corresponds to a function identifier make_type_compatible(lhs, jsil_any_type(), true); } }
void c_typecheck_baset::typecheck_code(codet &code) { if(code.id()!=ID_code) { err_location(code); error() << "expected code, got " << code.pretty() << eom; throw 0; } code.type()=code_typet(); const irep_idt &statement=code.get_statement(); if(statement==ID_expression) typecheck_expression(code); else if(statement==ID_label) typecheck_label(to_code_label(code)); else if(statement==ID_switch_case) typecheck_switch_case(to_code_switch_case(code)); else if(statement==ID_gcc_switch_case_range) typecheck_gcc_switch_case_range(code); else if(statement==ID_block) typecheck_block(code); else if(statement==ID_decl_block) { } else if(statement==ID_ifthenelse) typecheck_ifthenelse(to_code_ifthenelse(code)); else if(statement==ID_while) typecheck_while(to_code_while(code)); else if(statement==ID_dowhile) typecheck_dowhile(to_code_dowhile(code)); else if(statement==ID_for) typecheck_for(code); else if(statement==ID_switch) typecheck_switch(to_code_switch(code)); else if(statement==ID_break) typecheck_break(code); else if(statement==ID_goto) typecheck_goto(to_code_goto(code)); else if(statement==ID_gcc_computed_goto) typecheck_gcc_computed_goto(code); else if(statement==ID_continue) typecheck_continue(code); else if(statement==ID_return) typecheck_return(code); else if(statement==ID_decl) typecheck_decl(code); else if(statement==ID_assign) typecheck_assign(code); else if(statement==ID_skip) { } else if(statement==ID_asm) typecheck_asm(code); else if(statement==ID_start_thread) typecheck_start_thread(code); else if(statement==ID_gcc_local_label) typecheck_gcc_local_label(code); else if(statement==ID_msc_try_finally) { assert(code.operands().size()==2); typecheck_code(to_code(code.op0())); typecheck_code(to_code(code.op1())); } else if(statement==ID_msc_try_except) { assert(code.operands().size()==3); typecheck_code(to_code(code.op0())); typecheck_expr(code.op1()); typecheck_code(to_code(code.op2())); } else if(statement==ID_msc_leave) { // fine as is, but should check that we // are in a 'try' block } else if(statement==ID_static_assert) { assert(code.operands().size()==2); typecheck_expr(code.op0()); typecheck_expr(code.op1()); } else if(statement==ID_CPROVER_try_catch || statement==ID_CPROVER_try_finally) { assert(code.operands().size()==2); typecheck_code(to_code(code.op0())); typecheck_code(to_code(code.op1())); } else if(statement==ID_CPROVER_throw) { assert(code.operands().empty()); } else if(statement==ID_assume || statement==ID_assert) { // These are not generated by the C/C++ parsers, // but we allow them for the benefit of other users // of the typechecker. assert(code.operands().size()==1); typecheck_expr(code.op0()); } else { err_location(code); error() << "unexpected statement: " << statement << eom; throw 0; } }