TEST(TestEnumeration, CaseAccess_SwitchCase) { SEMANTIC_ANALYZE(L"enum CompassPoint { \n" L"case North\n" L"case South\n" L"case East\n" L"case West\n" L"}\n" L"var directionToHead : CompassPoint = .North;\n" L"directionToHead = .North\n" L"switch directionToHead {\n" L"case .North:\n" L" break\n" L"case .South:\n" L" break\n" L"case .East:\n" L" break\n" L"case .West:\n" L" break\n" L"}"); dumpCompilerResults(compilerResults); ASSERT_EQ(0, compilerResults.numResults()); SymbolPtr directionToHead; TypePtr CompassPoint; ASSERT_NOT_NULL(directionToHead = scope->lookup(L"directionToHead")); ASSERT_NOT_NULL(CompassPoint = dynamic_pointer_cast<Type>(scope->lookup(L"CompassPoint"))); ASSERT_EQ(CompassPoint, directionToHead->getType()); }
// Would be nice to make this a virtual member function, but it's // awkward with the recursion for list printing. std::ostream& print(std::ostream& os, const ElemPtr& e, bool first=true) { SymbolPtr sym = to_symbol(e); NumberPtr num = to_number(e); if (sym) { os << sym->value(); } else if (num) { os << num->value(); } else { PairPtr p = to_cons(e); if (p) { if (first) os << "("; if (is_nil(p)) os << ")"; else { if (!(to_symbol(p->car()))) os << "("; print(os, p->car(), false); if (!(is_nil(to_cons(p->cdr())))) os << " "; print(os, p->cdr(), false); } } } return os; }
VarType CodeBlock::make_cast(SymbolPtr p, VarType v1, VarType v2) { if (v1 != v2) { if (v1 == INTEGER && v2 == FLOATING) { // cast back to integer write_raw("CASTSI"); return INTEGER; } else if (v1 == FLOATING && v2 == INTEGER) { // cast back to floating write_raw("CASTSF"); return FLOATING; } else if ((v1 == STRING && v2 != STRING) || (v1 != STRING && v2 == STRING) || (v1 == VOID || v2 == VOID)) { if ((v1 == STRING_LITERAL && v2 == STRING) || (v1 == STRING && v2 == STRING_LITERAL)) { return STRING; } // need to catch boolean casting issues here... this->valid = false; report_error_lc("Semantic Error", "Unable to cast " + var_type_to_string(v1) + " to " + var_type_to_string(v2), p->get_row(), p->get_col()); return VOID; } else if ((v1 == BOOLEAN && v2 != BOOLEAN) || (v1 != BOOLEAN && v2 == BOOLEAN)) { return v2; } else { // fine return v2; } } else { return v2; } return VOID; }
void FunctionAnalyzer::visitProtocol(const ProtocolDefPtr& node) { SymbolScope* scope = symbolRegistry->getCurrentScope(); SymbolPtr sym = scope->getForwardDeclaration(node->getIdentifier()->getName()); assert(sym && sym->getKind() == SymbolKindType); TypePtr type = static_pointer_cast<Type>(sym); ScopeGuard guard(symbolRegistry, type->getScope()); SCOPED_SET(ctx->currentType, type); semanticAnalyzer->visitImplementation(node, this, true); }
TEST(TestFunctionOverloads, testFunc) { SEMANTIC_ANALYZE(L"func test() -> String {}\n" L"let a = test()"); dumpCompilerResults(compilerResults); SymbolPtr a; ASSERT_NOT_NULL(a = scope->lookup(L"a")); TypePtr type = a->getType(); ASSERT_NOT_NULL(type); TypePtr t_String = symbolRegistry.lookupType(L"String"); ASSERT_TRUE(type == t_String); }
TEST(TestEnumeration, ImplicitRawRepresentable) { SEMANTIC_ANALYZE(L"enum Planet: Int {\n" L" case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune\n" L"}\n" L"let earthsOrder = Planet.Earth.rawValue"); dumpCompilerResults(compilerResults); ASSERT_EQ(0, compilerResults.numResults()); SymbolPtr earthsOrder; ASSERT_NOT_NULL(earthsOrder = scope->lookup(L"earthsOrder")); ASSERT_EQ(symbolRegistry.getGlobalScope()->Int(), earthsOrder->getType()); }
void DeclarationAnalyzer::verifyProtocolConform(const TypePtr& type, const TypePtr& protocol) { for(auto entry : protocol->getDeclaredMembers()) { SymbolPtr requirement = entry.second; if(FunctionOverloadedSymbolPtr funcs = std::dynamic_pointer_cast<FunctionOverloadedSymbol>(requirement)) { //verify function for(auto func : *funcs) { verifyProtocolFunction(type, protocol, func); } } else if(FunctionSymbolPtr func = std::dynamic_pointer_cast<FunctionSymbol>(requirement)) { //verify function verifyProtocolFunction(type, protocol, func); } /* else if(requirement == Type::getPlaceHolder()) { //verify inner type SymbolPtr sym = type->getAssociatedType(entry.first); if(!(std::dynamic_pointer_cast<Type>(sym))) { //Type %0 does not conform to protocol %1, unimplemented type %2 error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNIMPLEMENTED_TYPE_3, type->getName(), protocol->getName(), entry.first); } }*/ else if(TypePtr t = std::dynamic_pointer_cast<Type>(requirement)) { //type can be ignored } else if(dynamic_pointer_cast<ComputedPropertySymbol>(requirement) || dynamic_pointer_cast<SymbolPlaceHolder>(requirement)) { //verify computed properties SymbolPtr sym = type->getMember(entry.first); //ComputedPropertySymbolPtr sp = std::dynamic_pointer_cast<ComputedPropertySymbol>(sym); if(!sym) { error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNIMPLEMENTED_PROPERTY_3, type->getName(), protocol->getName(), entry.first); } bool expectedSetter = requirement->hasFlags(SymbolFlagWritable); bool actualSetter = sym->hasFlags(SymbolFlagWritable); if(expectedSetter && !actualSetter) { error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNWRITABLE_PROPERTY_3, type->getName(), protocol->getName(), entry.first); } } } }
TEST(TestFunctionOverloads, CallVariable) { SEMANTIC_ANALYZE(L"var a = {(a : Int) -> Bool in return true}\n" L"var b = a(3)"); dumpCompilerResults(compilerResults); ASSERT_EQ(0, compilerResults.numResults()); SymbolPtr b; ASSERT_NOT_NULL(b = scope->lookup(L"b")); TypePtr type = b->getType(); ASSERT_NOT_NULL(type); TypePtr t_Bool = symbolRegistry.lookupType(L"Bool"); ASSERT_TRUE(type == t_Bool); }
TEST(TestFunctionOverloads, testClosureLiteral) { SEMANTIC_ANALYZE(L"let a = {(c : Int, b : Int)->Int in return c + b}(1, 2)"); dumpCompilerResults(compilerResults); ASSERT_EQ(0, compilerResults.numResults()); SymbolPtr a; ASSERT_NOT_NULL(a = scope->lookup(L"a")); TypePtr type = a->getType(); ASSERT_NOT_NULL(type); TypePtr t_Int = symbolRegistry.lookupType(L"Int"); ASSERT_TRUE(type == t_Int); }
bool CodeBlock::is_operand(SymbolPtr character) { if (character->get_symbol_type() == SYM_CONSTANT) { VarType op = static_pointer_cast<SymConstant>(character)->get_constant_type(); if (!OPERATOR(op)() && op != LPAREN && op != RPAREN) { return true; } else { return false; } } else if (character->get_symbol_type() == SYM_DATA) { return true; } else { return false; } }
bool CodeBlock::is_operator(SymbolPtr character) { if (character->get_symbol_type() == SYM_CONSTANT) { VarType op = static_pointer_cast<SymConstant>(character)->get_constant_type(); if (OPERATOR(op)()) { return true; } } return false; }
TEST(TestEnumeration, CaseAccess) { SEMANTIC_ANALYZE(L"enum CompassPoint { \n" L"case North\n" L"case South\n" L"case East\n" L"case West\n" L"}\n" L"var a = CompassPoint.East;"); dumpCompilerResults(compilerResults); ASSERT_EQ(0, compilerResults.numResults()); SymbolPtr a; TypePtr CompassPoint; ASSERT_NOT_NULL(a = scope->lookup(L"a")); ASSERT_NOT_NULL(CompassPoint = dynamic_pointer_cast<Type>(scope->lookup(L"CompassPoint"))); ASSERT_EQ(CompassPoint, a->getType()); }
void SemanticAnalyzer::visitValueBinding(const ValueBindingPtr& node) { PatternPtr name = node->getName(); //tuple was already exploded in declaration analyzer if(name->getNodeType() == NodeType::Tuple) { validateTupleTypeDeclaration(node); } if (name->getNodeType() != NodeType::Identifier) return; if(node->getOwner()->isReadOnly() && !node->getInitializer() && ctx->currentType == nullptr) { error(node, Errors::E_LET_REQUIRES_INITIALIZER); return; } //handle type inference for temporary variable if(node->isTemporary() && node->getInitializer()) { //temporary variable always has an initializer TypePtr initializerType; TypePtr declaredType = node->getType(); SCOPED_SET(ctx->contextualType, declaredType); node->getInitializer()->accept(this); initializerType = node->getInitializer()->getType(); assert(initializerType != nullptr); if(declaredType) { //it has both type definition and initializer, then we need to check if the initializer expression matches the type annotation if(!initializerType->canAssignTo(declaredType)) { error(node, Errors::E_CANNOT_CONVERT_EXPRESSION_TYPE_2, initializerType->toString(), declaredType->toString()); return; } } else { node->setType(initializerType); } } //add implicitly constructor for Optional IdentifierPtr id = static_pointer_cast<Identifier>(node->getName()); SymbolScope* currentScope = symbolRegistry->getCurrentScope(); TypePtr declaredType = node->getType() ? node->getType() : lookupType(node->getDeclaredType()); SCOPED_SET(ctx->contextualType, declaredType); if(!declaredType && !node->getInitializer()) { error(node, Errors::E_TYPE_ANNOTATION_MISSING_IN_PATTERN); return; } SymbolPtr sym = currentScope->lookup(id->getIdentifier()); assert(sym != nullptr); SymbolPlaceHolderPtr placeholder = std::dynamic_pointer_cast<SymbolPlaceHolder>(sym); assert(placeholder != nullptr); if(declaredType) { placeholder->setType(declaredType); } ExpressionPtr initializer = node->getInitializer(); if(initializer) { placeholder->setFlags(SymbolFlagInitializing, true); ExpressionPtr initializer = transformExpression(declaredType, node->getInitializer()); node->setInitializer(initializer); TypePtr actualType = initializer->getType(); assert(actualType != nullptr); if(declaredType) { if(!Type::equals(actualType, declaredType) && !canConvertTo(initializer, declaredType)) { error(initializer, Errors::E_CANNOT_CONVERT_EXPRESSION_TYPE_2, actualType->toString(), declaredType->toString()); return; } } if(!declaredType) placeholder->setType(actualType); } assert(placeholder->getType() != nullptr); placeholder->setFlags(SymbolFlagInitializing, false); //optional type always considered initialized, compiler will make it has a default value nil TypePtr symbolType = sym->getType(); GlobalScope* global = symbolRegistry->getGlobalScope(); if(initializer || global->isOptional(symbolType) || global->isImplicitlyUnwrappedOptional(symbolType)) markInitialized(placeholder); if (initializer) placeholder->setFlags(SymbolFlagHasInitializer, true); if(node->isTemporary()) { placeholder->setFlags(SymbolFlagTemporary, true); markInitialized(placeholder); } if(!node->isTemporary()) { //check access control level DeclarationType decl = ctx->currentType ? DeclarationTypeProperty : DeclarationTypeVariable; declarationAnalyzer->verifyAccessLevel(node->getOwner(), placeholder->getType(), decl, ComponentTypeType); } if(ctx->currentType && ctx->currentType->getCategory() == Type::Protocol) { error(node, Errors::E_PROTOCOL_VAR_MUST_BE_COMPUTED_PROPERTY_1); } }
/// Called after code is generated, this function loops over all the ops /// and figures out the lifetimes of all variables, based on whether the /// args in each op are read or written. void OSLCompilerImpl::track_variable_lifetimes (const OpcodeVec &code, const SymbolPtrVec &opargs, const SymbolPtrVec &allsyms) { // Clear the lifetimes for all symbols BOOST_FOREACH (Symbol *s, allsyms) s->clear_rw (); static ustring op_for("for"); static ustring op_while("while"); static ustring op_dowhile("dowhile"); // For each op, mark its arguments as being used at that op int opnum = 0; BOOST_FOREACH (const Opcode &op, code) { // Some work to do for each argument to the op... for (int a = 0; a < op.nargs(); ++a) { SymbolPtr s = opargs[op.firstarg()+a]; ASSERT (s->dealias() == s); // s = s->dealias(); // Make sure it's de-aliased // Mark that it's read and/or written for this op s->mark_rw (opnum, op.argread(a), op.argwrite(a)); } // If this is a loop op, we need to mark its control variable // (the only arg) as used for the duration of the loop! if (op.opname() == op_for || op.opname() == op_while || op.opname() == op_dowhile) { ASSERT (op.nargs() == 1); // loops should have just one arg SymbolPtr s = opargs[op.firstarg()]; s->mark_rw (opnum+1, true, true); s->mark_rw (op.farthest_jump()-1, true, true); } ++opnum; } // Special case: temporaries referenced both inside AND outside a // loop need their lifetimes extended to cover the entire loop so // they aren't accidentally coalesced incorrectly. The specific // danger is for a function that contains a loop, and the function // is passed an argument that is a temporary calculation. opnum = 0; BOOST_FOREACH (const Opcode &op, code) { if (op.opname() == op_for || op.opname() == op_while || op.opname() == op_dowhile) { int loopend = op.farthest_jump() - 1; BOOST_FOREACH (Symbol *s, allsyms) { if (s->symtype() == SymTypeTemp && ((s->firstuse() < opnum && s->lastuse() >= opnum) || (s->firstuse() < loopend && s->lastuse() >= loopend))) { s->mark_rw (opnum, true, true); s->mark_rw (loopend, true, true); } } } ++opnum; }
/** * @Inherit */ inline virtual void draw(SimViewer::SimViewer& viewer, const Vector2D& posRoot, scalar angleRoot, const Vector2D& posLeaf, scalar angleLeaf, scalar value) { // Joint::draw(viewer, posRoot, angleRoot, // posLeaf, angleLeaf, value); Vector2D pos_j = posRoot + Vector2D::rotate( Joint::getPosRoot(), angleRoot); viewer.drawJoint(pos_j.x(), pos_j.y(), (Joint::getAngleRoot()+angleRoot)*180.0/M_PI, (value)*180.0/M_PI); Vector2D pos = posLeaf + Vector2D::rotate( Joint::getPosLeaf(), angleLeaf); viewer.drawSegmentByEnd(posRoot.x(),posRoot.y(), pos_j.x(),pos_j.y() ,0.05,sf::Color(0,200,0,100)); // viewer.drawJoint(pos.x(), pos.y(), // (Joint::getAngleRoot()+angleRoot)*180.0/M_PI, // (value)*180.0/M_PI); double ori=(Joint::getAngleLeaf()+angleLeaf); Vector2D rot; //Draw the cam Vector2D pos_r=pos; Vector2D pos_l=pos; double x=0.0; double y=0.0; Leph::Symbolic::Bounder bounder; SymbolPtr xs = Symbol::create("x"); for(int i=0;i<100;i++) { x+=.3/100.0; xs->reset(); bounder.setValue(xs,x); // y=F(x); y=_F(xs)->evaluate(bounder); rot=Vector2D::rotate(Vector2D(x,y),ori+M_PI); viewer.drawSegmentByEnd(pos_r.x(),pos_r.y(), pos.x()+rot.x(),pos.y()+rot.y() ,0.01,sf::Color(200,200,200,100)); pos_r=Vector2D(pos.x()+rot.x(), pos.y()+rot.y()); xs->reset(); bounder.setValue(xs,-x); y=_F(xs)->evaluate(bounder); // y=F(-x); rot=Vector2D::rotate(Vector2D(-x,y),ori+M_PI); viewer.drawSegmentByEnd(pos_l.x(),pos_l.y(), pos.x()+rot.x(),pos.y()+rot.y() ,0.01,sf::Color(200,200,200,100)); pos_l=Vector2D(pos.x()+rot.x(), pos.y()+rot.y()); } viewer.drawSegment(pos.x(),pos.y(),_sH*2.0,(Joint::getAngleLeaf()+angleLeaf-M_PI/2.0)*180.0/M_PI,0.05,sf::Color(255,255,255,100)); viewer.drawSegment(pos_j.x(),pos_j.y(),_sH,((Joint::getAngleRoot()+angleRoot)+M_PI/2.0-_sphi)*180.0/M_PI,0.01,sf::Color(255,0,255,100)); viewer.drawCircle(pos_j.x()+_sH*cos((Joint::getAngleRoot()+angleRoot)+M_PI/2.0-_sphi),pos_j.y()+_sH*sin((Joint::getAngleRoot()+angleRoot)+M_PI/2.0-_sphi),0.03,sf::Color(255,0,255,100)); viewer.drawCircle(pos.x(),pos.y(),0.03,sf::Color(255,255,255,255)); //Draw spring Vector2D pos1 = posRoot + Vector2D::rotate( Joint::getPosRoot(), angleRoot); Vector2D pos2 = posLeaf + Vector2D::rotate( Joint::getPosLeaf(), angleLeaf); double zval=Vector2D::dist(pos1,pos2); scalar tmp=zval/10.0; scalar sig=1.0; Vector2D tmppos=pos1; scalar angle=atan2(pos2.y()-pos1.y(),pos2.x()-pos1.x()); Vector2D tmpnew=tmppos+Vector2D::rotate(Vector2D(0.1*sig,tmp), angle+M_PI/2.0+M_PI); viewer.drawSegmentByEnd(tmppos.x(),tmppos.y(), tmpnew.x(),tmpnew.y(),0.01,sf::Color(200,200,200,100)); tmppos=tmpnew; sig*=-1.0; tmp=zval/5.0; for(int i=1;i<5;i++) { tmpnew=tmppos+Vector2D::rotate(Vector2D(0.2*sig,tmp), angle+M_PI/2.0+M_PI); viewer.drawSegmentByEnd(tmppos.x(),tmppos.y(), tmpnew.x(),tmpnew.y(),0.01,sf::Color(200,200,200,100)); tmppos=tmpnew; sig*=-1.0; } tmp=zval/10.0; tmpnew=tmppos+Vector2D::rotate(Vector2D(0.1*sig,tmp), angle+M_PI/2.0+M_PI); viewer.drawSegmentByEnd(tmppos.x(),tmppos.y(), tmpnew.x(),tmpnew.y(),0.01,sf::Color(200,200,200,100)); }
/// Called after code is generated, this function loops over all the ops /// and figures out the lifetimes of all variables, based on whether the /// args in each op are read or written. void OSLCompilerImpl::track_variable_lifetimes (const OpcodeVec &code, const SymbolPtrVec &opargs, const SymbolPtrVec &allsyms) { // Clear the lifetimes for all symbols BOOST_FOREACH (Symbol *s, allsyms) s->clear_rw (); static ustring op_for("for"); static ustring op_while("while"); static ustring op_dowhile("dowhile"); // For each op, mark its arguments as being used at that op int opnum = 0; BOOST_FOREACH (const Opcode &op, code) { // Some work to do for each argument to the op... for (int a = 0; a < op.nargs(); ++a) { SymbolPtr s = opargs[op.firstarg()+a]; ASSERT (s->dealias() == s); // s = s->dealias(); // Make sure it's de-aliased // Mark that it's read and/or written for this op s->mark_rw (opnum, op.argread(a), op.argwrite(a)); } // If this is a loop op, we need to mark its control variable // (the only arg) as used for the duration of the loop! if (op.opname() == op_for || op.opname() == op_while || op.opname() == op_dowhile) { ASSERT (op.nargs() == 1); // loops should have just one arg SymbolPtr s = opargs[op.firstarg()]; s->mark_rw (opnum+1, true, true); s->mark_rw (op.farthest_jump()-1, true, true); } ++opnum; } // Special cases: handle variables whose lifetimes cross the boundaries // of a loop. opnum = 0; BOOST_FOREACH (const Opcode &op, code) { if (op.opname() == op_for || op.opname() == op_while || op.opname() == op_dowhile) { int loopcond = op.jump (0); // after initialization, before test int loopend = op.farthest_jump() - 1; BOOST_FOREACH (Symbol *s, allsyms) { // Temporaries referenced both inside AND outside a loop // need their lifetimes extended to cover the entire // loop so they aren't coalesced incorrectly. The // specific danger is for a function that contains a // loop, and the function is passed an argument that is // a temporary calculation. if (s->symtype() == SymTypeTemp && ((s->firstuse() < loopcond && s->lastuse() >= loopcond) || (s->firstuse() < loopend && s->lastuse() >= loopend))) { s->mark_rw (opnum, true, true); s->mark_rw (loopend, true, true); } // Locals that are written within the loop should have // their usage conservatively expanded to the whole // loop. This is not a worry for temps, because they // CAN'T be read in the next iteration unless they were // set before the loop, handled above. Ideally, we // could be less conservative if we knew that the // variable in question was declared/scoped internal to // the loop, in which case it can't carry values to the // next iteration (FIXME). if (s->symtype() == SymTypeLocal && s->firstuse() < loopend && s->lastwrite() >= loopcond) { bool read = (s->lastread() >= loopcond); s->mark_rw (opnum, read, true); s->mark_rw (loopend, read, true); } } } ++opnum; }
/** * @Inherit */ inline virtual void draw(SimViewer::SimViewer& viewer, const Vector2D& posRoot, scalar angleRoot, const Vector2D& posLeaf, scalar angleLeaf, scalar value) { Joint::draw(viewer, posRoot, angleRoot, posLeaf, angleLeaf, value); // Vector2D pos = posRoot + Vector2D::rotate( // Joint::getPosRoot(), angleRoot); Vector2D pos = posLeaf + Vector2D::rotate( Joint::getPosLeaf(), angleLeaf); viewer.drawJoint(pos.x(), pos.y(), (Joint::getAngleRoot()+angleRoot)*180.0/M_PI, (value)*180.0/M_PI); pos = posRoot + Vector2D::rotate( Joint::getPosRoot(), angleRoot); double ori=(Joint::getAngleRoot()+angleRoot); Vector2D rot; //Draw the cam Vector2D pos_r=pos; Vector2D pos_l=pos; double x=0.0; double y=0.0; Leph::Symbolic::Bounder bounder; SymbolPtr xs = Symbol::create("x"); for(int i=0;i<100;i++) { x+=.3/100.0; xs->reset(); bounder.setValue(xs,x); // y=F(x); y=_F(xs)->evaluate(bounder); // std::cout<<"x: "<<x<<" "<<xs->evaluate(bounder)<<" y: "<<y<<std::endl; rot=Vector2D::rotate(Vector2D(x,y),ori); viewer.drawSegmentByEnd(pos_r.x(),pos_r.y(), pos.x()+rot.x(),pos.y()+rot.y() ,0.01,sf::Color(200,200,200,100)); pos_r=Vector2D(pos.x()+rot.x(), pos.y()+rot.y()); xs->reset(); bounder.setValue(xs,-x); y=_F(xs)->evaluate(bounder); // y=F(-x); rot=Vector2D::rotate(Vector2D(-x,y),ori); viewer.drawSegmentByEnd(pos_l.x(),pos_l.y(), pos.x()+rot.x(),pos.y()+rot.y() ,0.01,sf::Color(200,200,200,100)); pos_l=Vector2D(pos.x()+rot.x(), pos.y()+rot.y()); } viewer.drawSegment(pos.x(),pos.y(),_sH*2.0,((Joint::getAngleRoot()+angleRoot)+M_PI/2.0)*180.0/M_PI,0.05,sf::Color(255,255,255,100)); //Draw the lever viewer.drawSegment(posLeaf.x(),posLeaf.y(),_sH,(angleLeaf-M_PI/2.0)*180.0/M_PI,0.01,sf::Color(255,0,255,100)); viewer.drawCircle(posLeaf.x()+_sH*cos(angleLeaf-M_PI/2.0),posLeaf.y()+_sH*sin(angleLeaf-M_PI/2.0),0.03,sf::Color(255,0,255,100)); viewer.drawCircle(pos.x(),pos.y(),0.03,sf::Color(255,255,255,255)); }
bool DeclarationAnalyzer::verifyProtocolConform(const TypePtr& type, const TypePtr& protocol, bool supressError) { for(auto entry : protocol->getDeclaredMembers()) { SymbolPtr requirement = entry.second; if(FunctionOverloadedSymbolPtr funcs = std::dynamic_pointer_cast<FunctionOverloadedSymbol>(requirement)) { //verify function for(auto func : *funcs) { bool success = verifyProtocolFunction(type, protocol, func, supressError); if(!success) return false; } } else if(FunctionSymbolPtr func = std::dynamic_pointer_cast<FunctionSymbol>(requirement)) { //verify function bool success = verifyProtocolFunction(type, protocol, func, supressError); if(!success) return false; } /* else if(requirement == Type::getPlaceHolder()) { //verify inner type SymbolPtr sym = type->getAssociatedType(entry.first); if(!(std::dynamic_pointer_cast<Type>(sym))) { //Type %0 does not conform to protocol %1, unimplemented type %2 error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNIMPLEMENTED_TYPE_3, type->getName(), protocol->getName(), entry.first); } }*/ else if(TypePtr t = std::dynamic_pointer_cast<Type>(requirement)) { //if type doesn't declare a type alias but the protocol has defined it with a full definition, then we will implicitly declare it wstring name = t->getName(); TypePtr originalType = t->resolveAlias(); if(type->getAssociatedType(name) == nullptr && originalType != nullptr && originalType->getCategory() != Type::Alias) { TypeBuilderPtr builder = static_pointer_cast<TypeBuilder>(type); builder->addMember(name, originalType); } //typealias checking is moved to second stage, when all other members verified continue; } else if(dynamic_pointer_cast<ComputedPropertySymbol>(requirement) || dynamic_pointer_cast<SymbolPlaceHolder>(requirement)) { //verify computed properties SymbolPtr sym = type->getMember(entry.first); //ComputedPropertySymbolPtr sp = std::dynamic_pointer_cast<ComputedPropertySymbol>(sym); if(!sym || !checkTypeConform(type, requirement->getType(), sym->getType())) { if(!supressError) { error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNIMPLEMENTED_PROPERTY_3, type->getName(), protocol->getName(), entry.first); } return false; } bool expectedSetter = requirement->hasFlags(SymbolFlagWritable); bool actualSetter = sym->hasFlags(SymbolFlagWritable); if(expectedSetter && !actualSetter) { if(!supressError) { error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNWRITABLE_PROPERTY_3, type->getName(), protocol->getName(), entry.first); } return false; } } } //check again for associated types for(auto entry : protocol->getAssociatedTypes()) { if(entry.second->resolveAlias() != nullptr) continue; TypePtr t = type->getAssociatedType(entry.first); if(t == nullptr) { //undefined type alias if(!supressError) { error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_2_, type->getName(), protocol->getName()); } return false; } } return true; }
SymbolPtr CodeBlock::translate(TokenPtr token) { if (token->get_token() == MP_ID) { string search_lexeme = token->get_lexeme(); unsigned int search_level = this->get_nesting_level(); SymbolListPtr filtered_data = this->get_analyzer()->get_symtable()->data_in_scope_at(search_lexeme, search_level); if (this->check_filter_size(filtered_data)) { SymbolPtr found = *filtered_data->begin(); found->set_col(token->get_column()); found->set_row(token->get_line()); return found; } else { SymbolListPtr global_data = this->get_analyzer()->get_symtable()->data_in_scope_at(search_lexeme, 0); if (this->check_filter_size(global_data)) { SymbolPtr found = *global_data->begin(); found->set_col(token->get_column()); found->set_row(token->get_line()); return found; } else { if (global_data == nullptr) { report_error_lc("Semantic Error", "ID '" + search_lexeme + "' not found", token->get_line(), token->get_column()); } else { report_error("Semantic Error", "ID '" + search_lexeme + "' redefined as..."); for (auto it = global_data->begin(); it != global_data->end(); it++) { SymDataPtr dptr = static_pointer_cast<SymData>(*it); report_error_lc("Definition @", (*it)->get_symbol_name() + " as " + var_type_to_string(dptr->get_var_type()), (*it)->get_row(), (*it)->get_col()); } } this->valid = false; return nullptr; } } } else if (token->get_token() == MP_INT_LITERAL) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), INTEGER_LITERAL)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_STRING_LITERAL) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), STRING_LITERAL)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_FLOAT_LITERAL) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), FLOATING_LITERAL)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_TRUE) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), BOOLEAN_LITERAL_T)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_FALSE) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), BOOLEAN_LITERAL_F)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_LEFT_PAREN) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), LPAREN)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_RIGHT_PAREN) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), RPAREN)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_PLUS) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), ADD)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_MINUS) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), SUB)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_MULT) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), MUL)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_DIV) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), DIV)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_DIV_KW) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), DIV)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_MOD_KW) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), MOD)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_AND) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), AND)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_OR) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), OR)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_NOT) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), NOT)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_LESSTHAN) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), ILT)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_EQUALS) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), IEQ)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_LESSTHAN_EQUALTO) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), ILE)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_GREATERTHAN) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), IGT)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_GREATERTHAN_EQUALTO) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), IGE)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else if (token->get_token() == MP_NOT_EQUAL) { SymbolPtr s = SymbolPtr(new SymConstant(token->get_lexeme(), INE)); s->set_row(token->get_line()); s->set_col(token->get_column()); return s; } else { return nullptr; } }
/// Called after code is generated, this function loops over all the ops /// and figures out the lifetimes of all variables, based on whether the /// args in each op are read or written. void OSLCompilerImpl::track_variable_lifetimes (const OpcodeVec &code, const SymbolPtrVec &opargs, const SymbolPtrVec &allsyms, std::vector<int> *bblockids) { // Clear the lifetimes for all symbols BOOST_FOREACH (Symbol *s, allsyms) s->clear_rw (); // Keep track of the nested loops we're inside. We track them by pairs // of begin/end instruction numbers for that loop body, including // conditional evaluation (skip the initialization). Note that the end // is inclusive. We use this vector of ranges as a stack. typedef std::pair<int,int> intpair; std::vector<intpair> loop_bounds; // For each op, mark its arguments as being used at that op int opnum = 0; BOOST_FOREACH (const Opcode &op, code) { if (op.opname() == op_for || op.opname() == op_while || op.opname() == op_dowhile) { // If this is a loop op, we need to mark its control variable // (the only arg) as used for the duration of the loop! ASSERT (op.nargs() == 1); // loops should have just one arg SymbolPtr s = opargs[op.firstarg()]; int loopcond = op.jump (0); // after initialization, before test int loopend = op.farthest_jump() - 1; // inclusive end s->mark_rw (opnum+1, true, true); s->mark_rw (loopend, true, true); // Also push the loop bounds for this loop loop_bounds.push_back (std::make_pair(loopcond, loopend)); } // Some work to do for each argument to the op... for (int a = 0; a < op.nargs(); ++a) { SymbolPtr s = opargs[op.firstarg()+a]; ASSERT (s->dealias() == s); // Make sure it's de-aliased // Mark that it's read and/or written for this op bool readhere = op.argread(a); bool writtenhere = op.argwrite(a); s->mark_rw (opnum, readhere, writtenhere); // Adjust lifetimes of symbols whose values need to be preserved // between loop iterations. BOOST_FOREACH (intpair oprange, loop_bounds) { int loopcond = oprange.first; int loopend = oprange.second; DASSERT (s->firstuse() <= loopend); // Special case: a temp or local, even if written inside a // loop, if it's entire lifetime is within one basic block // and it's strictly written before being read, then its // lifetime is truly local and doesn't need to be expanded // for the duration of the loop. if (bblockids && (s->symtype()==SymTypeLocal || s->symtype()==SymTypeTemp) && (*bblockids)[s->firstuse()] == (*bblockids)[s->lastuse()] && s->lastwrite() < s->firstread()) { continue; } // Syms written before or inside the loop, and referenced // inside or after the loop, need to preserve their value // for the duration of the loop. We know it's referenced // inside the loop because we're here examining it! if (s->firstwrite() <= loopend) { s->mark_rw (loopcond, readhere, writtenhere); s->mark_rw (loopend, readhere, writtenhere); } } } ++opnum; // Advance to the next op index // Pop any loop bounds for loops we've just exited while (!loop_bounds.empty() && loop_bounds.back().second < opnum) loop_bounds.pop_back (); }