// ================================================================= // Performs semantic analysis on this node. // ================================================================= CASTNode* CSliceExpressionASTNode::Semant(CSemanter* semanter) { SEMANT_TRACE("CSliceExpressionASTNode"); // Only semant once. if (Semanted == true) { return this; } Semanted = true; // Semant expressions. LeftValue = ReplaceChild(LeftValue, LeftValue->Semant(semanter)); if (StartExpression != NULL) { StartExpression = ReplaceChild(StartExpression, StartExpression->Semant(semanter)); } if (EndExpression != NULL) { EndExpression = ReplaceChild(EndExpression, EndExpression->Semant(semanter)); } // Get expression references. CExpressionBaseASTNode* lValueBase = dynamic_cast<CExpressionBaseASTNode*>(LeftValue); CExpressionBaseASTNode* startExprBase = dynamic_cast<CExpressionBaseASTNode*>(StartExpression); CExpressionBaseASTNode* endExprBase = dynamic_cast<CExpressionBaseASTNode*>(EndExpression); // Cast index to integer. if (startExprBase != NULL) { StartExpression = ReplaceChild(startExprBase, startExprBase->CastTo(semanter, new CIntDataType(Token), Token)); } if (endExprBase != NULL) { EndExpression = ReplaceChild(endExprBase, endExprBase->CastTo (semanter, new CIntDataType(Token), Token)); } // Valid object to slice? std::vector<CDataType*> argumentTypes; argumentTypes.push_back(new CIntDataType(Token)); argumentTypes.push_back(new CIntDataType(Token)); CClassASTNode* classNode = lValueBase->ExpressionResultType->GetClass(semanter); CClassMemberASTNode* memberNode = classNode->FindClassMethod(semanter, "GetSlice", argumentTypes, true, NULL, NULL); if (memberNode == NULL) { semanter->GetContext()->FatalError("Data type does not support slicing, no GetSlice method defined.", Token); } else { ExpressionResultType = memberNode->ReturnType; } return this; }
void GpxRootElement::SetMetadata(GpxMetadataElement *metadata) { bool b_was_cloned = true; if (!metadata) RemoveMetadata(); else { if(my_metadata) my_metadata = (GpxMetadataElement *)ReplaceChild(my_metadata, *metadata); else if (first_waypoint) my_metadata = (GpxMetadataElement *)InsertBeforeChild(first_waypoint, *metadata); else if (first_route) my_metadata = (GpxMetadataElement *)InsertBeforeChild(first_route, *metadata); else if (first_track) my_metadata = (GpxMetadataElement *)InsertBeforeChild(first_track, *metadata); else if (my_extensions) my_metadata = (GpxMetadataElement *)InsertBeforeChild(my_extensions, *metadata); else { b_was_cloned = false; my_metadata = (GpxMetadataElement *)LinkEndChild(metadata); } if(b_was_cloned) { metadata->Clear(); delete metadata; } } }
// ================================================================= // Performs semantic analysis on this node. // ================================================================= CASTNode* CCommaExpressionASTNode::Semant(CSemanter* semanter) { // Only semant once. if (Semanted == true) { return this; } Semanted = true; // Semant expressions. LeftValue = ReplaceChild(LeftValue, LeftValue->Semant(semanter)); RightValue = ReplaceChild(RightValue, RightValue->Semant(semanter)); // Resulting type is always our right hand type. ExpressionResultType = dynamic_cast<CExpressionBaseASTNode*>(RightValue)->ExpressionResultType; return this; }
// ================================================================= // Performs semantic analysis on this node. // ================================================================= CASTNode* CComparisonExpressionASTNode::Semant(CSemanter* semanter) { SEMANT_TRACE("CComparisonExpressionASTNode"); // Only semant once. if (Semanted == true) { return this; } Semanted = true; // Semant expressions. LeftValue = ReplaceChild(LeftValue, LeftValue->Semant(semanter)); RightValue = ReplaceChild(RightValue, RightValue->Semant(semanter)); // Get expression references. CExpressionBaseASTNode* leftValueBase = dynamic_cast<CExpressionBaseASTNode*>(LeftValue); CExpressionBaseASTNode* rightValueBase = dynamic_cast<CExpressionBaseASTNode*>(RightValue); // Balance types. ExpressionResultType = semanter->BalanceDataTypes(leftValueBase->ExpressionResultType, rightValueBase->ExpressionResultType); // Objects only permit equality operations. if (dynamic_cast<CObjectDataType*>(ExpressionResultType) != NULL && Token.Type != TokenIdentifier::OP_EQUAL && Token.Type != TokenIdentifier::OP_NOT_EQUAL) { semanter->GetContext()->FatalError(CStringHelper::FormatString("%s operator cannot be used on objects.", Token.Literal.c_str()), Token); } // Cast to resulting expression. LeftValue = ReplaceChild(LeftValue, leftValueBase->CastTo(semanter, ExpressionResultType, Token)); RightValue = ReplaceChild(RightValue, rightValueBase->CastTo(semanter, ExpressionResultType, Token)); CompareResultType = ExpressionResultType; ExpressionResultType = new CBoolDataType(Token); return this; }
// ================================================================= // Performs semantic analysis of this node. // ================================================================= CASTNode* CCaseStatementASTNode::Semant(CSemanter* semanter) { SEMANT_TRACE("CCaseStatementASTNode"); // Only semant once. if (Semanted == true) { return this; } Semanted = true; // Find the switch statement we are part of. CASTNode* scope = this; CSwitchStatementASTNode* switchScope = NULL; while (scope != NULL && switchScope == NULL) { switchScope = dynamic_cast<CSwitchStatementASTNode*>(scope); scope = scope->Parent; } // Semant the expression. for (auto iter = Expressions.begin(); iter != Expressions.end(); iter++) { CASTNode* node = *iter; node = ReplaceChild(node, node->Semant(semanter)); node = ReplaceChild(node, dynamic_cast<CExpressionBaseASTNode*>(node)->CastTo(semanter, switchScope->ExpressionStatement->ExpressionResultType, Token)); (*iter) = node; } // Semant Body statement. if (BodyStatement != NULL) { BodyStatement = ReplaceChild(BodyStatement, BodyStatement->Semant(semanter)); } return this; }
Element *Element::ReplaceChild(Element *oldchild, Scm code) { Element *elm = GetElementFromObject(code); // if error with child, report error if (!elm) return NULL; // ensure elements are not added twice if (elm->GetParent() != NULL) { Error("element already has parent."); return NULL; } ReplaceChild(oldchild, elm); return elm; }
void GpxRootElement::SetExtensions(GpxExtensionsElement *extensions) { if (!extensions) RemoveExtensions(); else { if(!my_extensions) my_extensions = (GpxExtensionsElement *)LinkEndChild(extensions); else { my_extensions = (GpxExtensionsElement *)ReplaceChild(my_extensions, *extensions); extensions->Clear(); delete extensions; } } }
// ================================================================= // Performs semantic analysis on this node. // ================================================================= CASTNode* CThrowStatementASTNode::Semant(CSemanter* semanter) { Expression = dynamic_cast<CExpressionBaseASTNode*>(ReplaceChild(Expression, Expression->Semant(semanter))); CDataType* exception_base = FindDataType(semanter, "Exception", std::vector<CDataType*>()); if (exception_base == NULL || exception_base->GetClass(semanter) == NULL) { semanter->GetContext()->FatalError("Internal error, could not find base 'Exception' class."); } CDataType* catch_type = Expression->ExpressionResultType; if (catch_type == NULL || catch_type->GetClass(semanter)->InheritsFromClass(semanter, exception_base->GetClass(semanter)) == false) { semanter->GetContext()->FatalError("Thrown exceptions must inherit from 'Exception' class.", Token); } return this; }
void GpxTrkElement::SetProperty(const wxString &name, const wxString &value) { //FIXME: doesn't care about order so it can be absolutely wrong, have to redo this code if it has to be used by something else than the constructor //then it can be made public //FIXME: can be reused for route and track GpxSimpleElement *element = new GpxSimpleElement(name, value); TiXmlElement *curelement = FirstChildElement(); bool found = false; while(curelement) { if((const char *)curelement->Value() == (const char *)name.ToUTF8()) { ReplaceChild(curelement, *element); element->Clear(); delete element; break; } curelement = curelement->NextSiblingElement(); } if (!found) LinkEndChild(element); }
// ================================================================= // Performs semantic analysis on this node. // ================================================================= CASTNode* CMethodCallExpressionASTNode::Semant(CSemanter* semanter) { SEMANT_TRACE("CMethodCallExpressionASTNode"); // Only semant once. if (Semanted == true) { return this; } Semanted = true; // Get expression representations. CExpressionBaseASTNode* left_hand_expr = dynamic_cast<CExpressionBaseASTNode*>(LeftValue); CExpressionBaseASTNode* right_hand_expr = dynamic_cast<CExpressionBaseASTNode*>(RightValue); // Semant left hand node. LeftValue = ReplaceChild(LeftValue, LeftValue->Semant(semanter)); // Make sure we can access class. CClassASTNode* accessClass = left_hand_expr->ExpressionResultType->GetClass(semanter); if (accessClass == NULL) { semanter->GetContext()->FatalError(CStringHelper::FormatString("Invalid use of scoping operator."), Token); } // Check we can access this class from here. accessClass->CheckAccess(semanter, this); // NOTE: Do not r-value semant identifier, we want to process that ourselves. CIdentifierExpressionASTNode* identNode = dynamic_cast<CIdentifierExpressionASTNode*>(RightValue); // Semant arguments. std::vector<CDataType*> argument_types; std::string argument_types_string; for (std::vector<CASTNode*>::iterator iter = ArgumentExpressions.begin(); iter < ArgumentExpressions.end(); iter++) { CExpressionBaseASTNode* node = dynamic_cast<CExpressionBaseASTNode*>((*iter)->Semant(semanter)); argument_types.push_back(node->ExpressionResultType); if (iter != ArgumentExpressions.begin()) { argument_types_string += ", "; } argument_types_string += node->ExpressionResultType->ToString(); (*iter) = node; } // Make sure the identifier represents a valid field. CClassMemberASTNode* declaration = accessClass->FindClassMethod(semanter, identNode->Token.Literal, argument_types, false, NULL, this); if (declaration == NULL) { semanter->GetContext()->FatalError(CStringHelper::FormatString("Undefined method '%s(%s)' in class '%s'.", identNode->Token.Literal.c_str(), argument_types_string.c_str(), accessClass->ToString().c_str()), Token); } // UPDATE: Abstract method calling is fine. Remember we won't be able to instantiate classes that do not override all abstract methods. // if (declaration->IsAbstract == true) // { // semanter->GetContext()->FatalError(CStringHelper::FormatString("Cannot call method '%s(%s)' in class '%s', method is abstract.", identNode->Token.Literal.c_str(), argument_types_string.c_str(), accessClass->ToString().c_str()), Token); // } ResolvedDeclaration = declaration; // Check we can access this field from here. declaration->CheckAccess(semanter, this); // HACK: This is really hackish and needs fixing! if (dynamic_cast<CThisExpressionASTNode*>(LeftValue) != NULL && declaration->IsStatic == true) { LeftValue = ReplaceChild(LeftValue, new CClassRefExpressionASTNode(NULL, Token)); LeftValue->Token.Literal = declaration->FindClassScope(semanter)->Identifier; LeftValue->Semant(semanter); left_hand_expr = dynamic_cast<CExpressionBaseASTNode*>(LeftValue); } // Add default arguments if we do not have enough args to call. if (declaration->Arguments.size() > ArgumentExpressions.size()) { for (unsigned int i = ArgumentExpressions.size(); i < declaration->Arguments.size() ; i++) { CASTNode* expr = declaration->Arguments.at(i)->AssignmentExpression->Clone(semanter); AddChild(expr); ArgumentExpressions.push_back(expr); expr->Semant(semanter); } } // Cast all arguments to correct data types. int index = 0; for (std::vector<CASTNode*>::iterator iter = ArgumentExpressions.begin(); iter != ArgumentExpressions.end(); iter++) { CDataType* dataType = declaration->Arguments.at(index++)->Type; CExpressionBaseASTNode* subnode = dynamic_cast<CExpressionBaseASTNode*>(*iter); subnode = dynamic_cast<CExpressionBaseASTNode*>(ReplaceChild(subnode, subnode->CastTo(semanter, dataType, Token))); (*iter) = subnode; } // If we are a class reference, we can only access static fields. bool isClassReference = (dynamic_cast<CClassReferenceDataType*>(left_hand_expr->ExpressionResultType) != NULL); if (isClassReference == true) { if (declaration->IsStatic == false) { semanter->GetContext()->FatalError(CStringHelper::FormatString("Cannot access instance method '%s' through class reference '%s'.", declaration->Identifier.c_str(), accessClass->ToString().c_str()), Token); } } // If this is a constructor we are calling, make sure we are in a constructors scope, or its illegal! else { CClassMemberASTNode* methodScope = FindClassMethodScope(semanter); if (methodScope == NULL || methodScope->IsConstructor == false) { if (declaration->IsConstructor == true) { semanter->GetContext()->FatalError("Calling constructors manually is only valid inside another constructors scope.", Token); } } } // Resulting type is always our right hand type. ExpressionResultType = declaration->ReturnType; return this; }