TypeSpec ASTternary_expression::typecheck (TypeSpec expected) { // FIXME - closures TypeSpec c = typecheck_list (cond(), TypeDesc::TypeInt); TypeSpec t = typecheck_list (trueexpr(), expected); TypeSpec f = typecheck_list (falseexpr(), expected); if (c.is_closure()) error ("Cannot use a closure as a condition"); if (c.is_structure()) error ("Cannot use a struct as a condition"); if (c.is_array()) error ("Cannot use an array as a condition"); // No arrays if (t.is_array() || t.is_array()) { error ("Not allowed: '%s ? %s : %s'", type_c_str(c), type_c_str(t), type_c_str(f)); return TypeSpec (); } // The true and false clauses need to be equivalent types, or one // needs to be assignable to the other (so one can be upcast). if (assignable (t, f) || assignable (f, t)) m_typespec = higherprecision (t.simpletype(), f.simpletype()); else error ("Not allowed: '%s ? %s : %s'", type_c_str(c), type_c_str(t), type_c_str(f)); return m_typespec; }
int asgn_op ( ) { descriptor *src; descriptor *dest; int status; src = pop ( ); dest = top ( ); src = deref (src); if (!assignable (dest)) { TypeError ("cannot assign to", NULL, dest, NULL, F_False); RecycleData (src); return 1; } dest = deref (dest); src = CollapseMatrix (src); status = AssignData (dest, &src); RecycleData (src); D_Temp (dest) = F_False; return status; }
void ASTvariable_declaration::typecheck_initlist (ref init, TypeSpec type, const char *name) { // Loop over a list of initializers (it's just 1 if not an array)... for (int i = 0; init; init = init->next(), ++i) { // Check for too many initializers for an array if (type.is_array() && i > type.arraylength()) { error ("Too many initializers for a '%s'", type_c_str(type)); break; } // Special case: ok to assign a literal 0 to a closure to // initialize it. if (type.is_closure() && ! init->typespec().is_closure() && init->typespec().is_int_or_float() && init->nodetype() == literal_node && ((ASTliteral *)init.get())->floatval() == 0.0f) { continue; // it's ok } if (! type.is_array() && i > 0) error ("Can't assign array initializers to non-array %s %s", type_c_str(type), name); if (! assignable(type.elementtype(), init->typespec())) error ("Can't assign '%s' to %s %s", type_c_str(init->typespec()), type_c_str(type), name); } }
unsigned int RFSMasmt::isAssignable() { unsigned int lt = m_lValue->getType(); unsigned int rt = m_rValue->getType(); return assignable(lt,rt); }
bool ASTNode::check_arglist (const char *funcname, ASTNode::ref arg, const char *formals, bool coerce) { // std::cerr << "ca " << funcname << " formals='" << formals << "\n"; for ( ; arg; arg = arg->next()) { if (! *formals) // More formal args, but no more actual args return false; if (*formals == '*') // Will match anything left return true; if (*formals == '.') { // Special case for token/value pairs // FIXME -- require that the tokens be string literals if (arg->typespec().is_string() && arg->next() != NULL) { arg = arg->next(); continue; } return false; } if (*formals == '?') { if (formals[1] == '[' && formals[2] == ']') { // Any array formals += 3; if (arg->typespec().is_array()) continue; // match else return false; // wanted an array, didn't get one } if (arg->typespec().is_array()) return false; // wanted any scalar, got an array formals += 1; continue; // match anything } TypeSpec argtype = arg->typespec(); int advance; TypeSpec formaltype = m_compiler->type_from_code (formals, &advance); formals += advance; // std::cerr << "\targ is " << argtype.string() // << ", formal is " << formaltype.string() << "\n"; if (argtype == formaltype) continue; // ok, move on to next arg if (coerce && assignable (formaltype, argtype)) continue; // Allow a fixed-length array match to a formal array with // unspecified length, if the element types are the same. if (formaltype.arraylength() < 0 && argtype.arraylength() && formaltype.elementtype() == argtype.elementtype()) continue; // anything that gets this far we don't consider a match return false; } if (*formals && *formals != '*' && *formals != '.') return false; // Non-*, non-... formals expected, no more actuals return true; // Is this safe? }
void SemanticsVisitor::visit(AssigningNode& assign) { LHSSemanticsVisitor lhsVisitor(¤tSymbolTable(), errorLog()); assign.getTargetName()->accept(lhsVisitor); assign.getValueExpr()->accept(*this); if ( assignable( assign.getTargetName()->getType(), assign.getValueExpr()->getType() ) ) { assign.setType( assign.getTargetName()->getType() ); } else { errorLog() << "Right hand side expression not assignable to left hand side name at " << &assign << "\n"; assign.setType(0); // NOTICE by design, null attribute and error type is 0. } }
TypeSpec ASTvariable_declaration::typecheck_struct_initializers (ref init) { ASSERT (m_typespec.is_structure()); if (! init->next() && init->typespec() == m_typespec) { // Special case: just one initializer, it's a whole struct of // the right type. return m_typespec; } // General case -- per-field initializers const StructSpec *structspec (m_typespec.structspec()); int numfields = (int)structspec->numfields(); for (int i = 0; init; init = init->next(), ++i) { if (i >= numfields) { error ("Too many initializers for '%s %s'", type_c_str(m_typespec), m_name.c_str()); break; } const StructSpec::FieldSpec &field (structspec->field(i)); if (init->nodetype() == compound_initializer_node) { // Initializer is itself a compound, it ought to be initializing // a field that is an array. if (field.type.is_array ()) { ustring fieldname = ustring::format ("%s.%s", m_sym->name().c_str(), field.name.c_str()); typecheck_initlist (((ASTcompound_initializer *)init.get())->initlist(), field.type, fieldname.c_str()); } else { error ("Can't use '{...}' for a struct field that is not an array"); } continue; } // Ok to assign a literal 0 to a closure to initialize it. if (field.type.is_closure() && ! init->typespec().is_closure() && (init->typespec().is_float() || init->typespec().is_int()) && init->nodetype() == literal_node && ((ASTliteral *)init.get())->floatval() == 0.0f) { continue; // it's ok } // Normal initializer, normal field. if (! assignable(field.type, init->typespec())) error ("Can't assign '%s' to '%s %s.%s'", type_c_str(init->typespec()), type_c_str(field.type), m_name.c_str(), field.name.c_str()); } return m_typespec; }
TypeSpec ASTtypecast_expression::typecheck (TypeSpec expected) { // FIXME - closures typecheck_children (m_typespec); TypeSpec t = expr()->typespec(); if (! assignable (m_typespec, t) && ! (m_typespec.is_int() && t.is_float()) && // (int)float is ok ! (m_typespec.is_triple() && t.is_triple())) error ("Cannot cast '%s' to '%s'", type_c_str(t), type_c_str(m_typespec)); return m_typespec; }
TypeSpec ASTassign_expression::typecheck (TypeSpec expected) { TypeSpec vt = var()->typecheck (); TypeSpec et = expr()->typecheck (vt); if (! var()->is_lvalue()) { error ("Can't assign via %s to something that isn't an lvalue", opname()); return TypeSpec(); } ASSERT (m_op == Assign); // all else handled by binary_op // We don't currently support assignment of whole arrays if (vt.is_array() || et.is_array()) { error ("Can't assign entire arrays"); return TypeSpec(); } // Special case: ok to assign a literal 0 to a closure to // initialize it. if (vt.is_closure() && ! et.is_closure() && (et.is_float() || et.is_int()) && expr()->nodetype() == literal_node && ((ASTliteral *)&(*expr()))->floatval() == 0.0f) { return TypeSpec(); // it's ok } // If either argument is a structure, they better both be the same // exact kind of structure. if (vt.is_structure() || et.is_structure()) { int vts = vt.structure(), ets = et.structure(); if (vts == ets) return m_typespec = vt; // Otherwise, a structure mismatch error ("Cannot assign '%s' to '%s'", type_c_str(et), type_c_str(vt)); return TypeSpec(); } // Expression must be of a type assignable to the lvalue if (! assignable (vt, et)) { error ("Cannot assign '%s' to '%s'", type_c_str(et), type_c_str(vt)); // FIXME - can we print the variable in question? return TypeSpec(); } return m_typespec = vt; }
void SemanticsVisitor::visit(ReturningNode& rn) { if (rn.getReturnVal() != 0) { // NOTICE use errorType rn.getReturnVal()->accept(*this); // the same as visitChildren if (getCurrentFunction() == 0) errorLog() << "Return statement can only appear in a function.\n"; else { if(!assignable(getCurrentFunction()->getReturnType()->getType(), rn.getReturnVal()->getType())) { errorLog() << "Illigal return type.\n"; } } } else if (getCurrentFunction() != 0 && !dynamic_cast<VoidTypeDescriptor*>(getCurrentFunction()->getReturnType()->getType()) // return type =/= void ) { errorLog() << "A value must be returned.\n"; } }
expected<strong_actor_ptr> actor_system::dyn_spawn_impl(const std::string& name, message& args, execution_unit* ctx, bool check_interface, optional<const mpi&> expected_ifs) { CAF_LOG_TRACE(CAF_ARG(name) << CAF_ARG(args) << CAF_ARG(check_interface) << CAF_ARG(expected_ifs)); if (name.empty()) return sec::invalid_argument; auto& fs = cfg_.actor_factories; auto i = fs.find(name); if (i == fs.end()) return sec::unknown_type; actor_config cfg{ctx ? ctx : &dummy_execution_unit_}; auto res = i->second(cfg, args); if (!res.first) return sec::cannot_spawn_actor_from_arguments; if (check_interface && !assignable(res.second, *expected_ifs)) return sec::unexpected_actor_messaging_interface; return std::move(res.first); }
TypeSpec ASTreturn_statement::typecheck (TypeSpec expected) { FunctionSymbol *myfunc = oslcompiler->current_function (); if (myfunc) { // If it's a user function (as opposed to a main shader body)... if (expr()) { // If we are returning a value, it must be assignable to the // kind of type the function actually returns. This check // will also catch returning a value from a void function. TypeSpec et = expr()->typecheck (myfunc->typespec()); if (! assignable (myfunc->typespec(), et)) { error ("Cannot return a '%s' from '%s %s()'", type_c_str(et), type_c_str(myfunc->typespec()), myfunc->name().c_str()); } } else { // If we are not returning a value, it must be a void function. if (! myfunc->typespec().is_void ()) error ("You must return a '%s' from function '%s'", type_c_str(myfunc->typespec()), myfunc->name().c_str()); } // If the function has other statements AFTER 'return', or if // the return statement is in a conditional, we'll need to // handle it specially when generating code. myfunc->complex_return (this->nextptr() != NULL || myfunc->nesting_level() > 0); } else { // We're not part of any user function, so this 'return' must // be from the main shader body. That's fine (it's equivalent // to calling exit()), but it can't return a value. if (expr()) error ("Cannot return a value from a shader body"); } return TypeSpec(); // TODO: what should be returned here? }
bool SemanticsVisitor::bindable(TypeDescriptor *dest, TypeDescriptor *src) { return assignable(dest, src); // TODO check array type }
int gen_op ( ) { Matrix a; Matrix b; void *ptr; descriptor *d; descriptor *v; descriptor *var; descriptor *index; descriptor *vector; descriptor temp; double value; Address increment; Array arr; int fail; unsigned offset; unsigned i; unsigned c; unsigned r; index = ntop (0); vector = ntop (1); var = ntop (2); offset = fetch (pc ++).ival; if (D_Type (index) == T_Double) { if (!assignable (var)) { TypeError ("cannot assign to", NULL, var, NULL, F_False); return 1; } d = &temp; D_Type (d) = T_Null; D_Temp (d) = F_False; D_Trapped (d) = F_False; D_Pointer (d) = NULL; v = CoerceData (vector, T_Double); AssignData (d, &v); RecycleData (v); D_Temp (d) = F_False; d_printf ("d = %s %p\n", D_TypeName (d), D_Pointer (d)); switch (D_Type (d)) { case T_Double: case T_Matrix: case T_Array: case T_Null: break; default: TypeError ("cannot index", NULL, d, NULL, F_False); return 1; } *vector = *d; D_Type (index) = T_Row; D_Row (index) = 0; } d_printf ("vector = %s %p\n", D_TypeName (vector), D_Pointer (vector)); var = deref (var); fail = F_False; switch (D_Type (vector)) { case T_Double: if (D_Row (index) ++ == 0) AssignData (var, &vector); else fail = F_True; break; case T_Matrix: a = D_Matrix (vector); d = &temp; D_Temp (d) = F_False; D_Trapped (d) = F_False; if (Mrows (a) == 1) { if (++ D_Row (index) <= Mcols (a)) { D_Type (d) = T_Double; D_Double (d) = &value; value = mdata (a, 1, D_Row (index)); AssignData (var, &d); } else fail = F_True; } else if (Mcols (a) == 1) { if (++ D_Row (index) <= Mrows (a)) { D_Type (d) = T_Double; D_Double (d) = &value; value = mdata (a, D_Row (index), 1); AssignData (var, &d); } else fail = F_True; } else { if (++ D_Row (index) <= Mcols (a)) { d_printf ("indexing matrix\n"); r = Mrows (a); c = D_Row (index); FreeData (var); CreateData (var, NULL, NULL, T_Matrix, r, 1); D_Temp (var) = F_False; b = D_Matrix (var); for (i = 1; i <= r; i ++) sdata (b, i, 1) = mdata (a, i, c); } else fail = F_True; } break; case T_Array: arr = D_Array (vector); d = &temp; if (++ D_Row (index) <= arr -> length) { increment = D_Row (index) * arr -> elt_size; ptr = (void *) ((char *) arr -> ptr + increment); D_Type (d) = arr -> type; D_Temp (d) = F_False; D_Trapped (d) = F_False; D_Pointer (d) = ptr; AssignData (var, &d); } else fail = F_True; break; case T_Null: fail = F_True; break; } /* After assignment the variable is certainly not temporary. Its trapped status remains as before: if it was trapped then AssignData() called the trap handler which didn't change the status. If it wasn't then AssignData() left the status alone. */ D_Temp (var) = F_False; if (fail == F_True) { pop ( ); FreeData (pop ( )); /* free the privately owned vector */ pop ( ); d = push ( ); D_Type (d) = T_Null; D_Temp (d) = F_False; D_Trapped (d) = F_False; D_Pointer (d) = NULL; pc += offset; d_printf ("failing\n"); } return 0; }
bool assignable(const std::set<std::string>& xs) const { return assignable(xs, message_types<T>()); }