/*! Pops all the instances on the scope stack until it is empty or until it it reaches a block identifier \sa pushScopeBlock */ void QSEnv::popScopeBlock() { while (!scopeChain->isEmpty() && scopeChain->first().isValid()) popScope(); popScope(); Q_ASSERT(labels.front().isNull()); labels.pop_front(); }
llvm::Value * Generator::visit(For & node) { VarDecl initial(node.variable, nullptr, node.initial); auto counter = initial.accept(this); // create the block. auto function = builder.GetInsertBlock()->getParent(); auto block = llvm::BasicBlock::Create(*context, "forloop", function); auto after = llvm::BasicBlock::Create(*context, "forcont"); auto condition = node.condition->accept(this); // fall to the block. builder.CreateCondBr(condition, block, after); builder.SetInsertPoint(block); createScope(); node.block->accept(this); popScope(); // increment the counter. auto variable = builder.CreateLoad(counter); auto result = builder.CreateAdd(variable, node.increment->accept(this), "counter"); builder.CreateStore(result, counter); // execute again or stop. condition = node.condition->accept(this); builder.CreateCondBr(condition, block, after); // insert the after block. function->getBasicBlockList().push_back(after); builder.SetInsertPoint(after); return nullptr; }
std::unique_ptr<Update> TreeResolver::resolve(Change change) { auto& renderView = *m_document.renderView(); Element* documentElement = m_document.documentElement(); if (!documentElement) return nullptr; if (change != Force && !documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc()) return nullptr; m_update = std::make_unique<Update>(m_document); m_scopeStack.append(adoptRef(*new Scope(m_document))); m_parentStack.append(Parent(m_document, change)); // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc. renderView.setUsesFirstLineRules(renderView.usesFirstLineRules() || scope().styleResolver.usesFirstLineRules()); renderView.setUsesFirstLetterRules(renderView.usesFirstLetterRules() || scope().styleResolver.usesFirstLetterRules()); resolveComposedTree(); renderView.setUsesFirstLineRules(scope().styleResolver.usesFirstLineRules()); renderView.setUsesFirstLetterRules(scope().styleResolver.usesFirstLetterRules()); ASSERT(m_scopeStack.size() == 1); ASSERT(m_parentStack.size() == 1); m_parentStack.clear(); popScope(); if (m_update->roots().isEmpty()) return { }; return WTFMove(m_update); }
llvm::Value * Generator::visit(If & node) { auto condition = node.condition->accept(this); auto function = builder.GetInsertBlock()->getParent(); auto thenBlock = llvm::BasicBlock::Create(*context, "then", function); auto elseBlock = llvm::BasicBlock::Create(*context, "else"); auto mergeBlock = llvm::BasicBlock::Create(*context, "ifcont"); if (node.elseBlock) { builder.CreateCondBr(condition, thenBlock, elseBlock); } else { builder.CreateCondBr(condition, thenBlock, mergeBlock); } builder.SetInsertPoint(thenBlock); createScope(); node.thenBlock->accept(this); popScope(); thenBlock = builder.GetInsertBlock(); if (thenBlock->getTerminator() == nullptr) { builder.CreateBr(mergeBlock); } if (node.elseBlock) { function->getBasicBlockList().push_back(elseBlock); builder.SetInsertPoint(elseBlock); createScope(); node.elseBlock->accept(this); popScope(); builder.CreateBr(mergeBlock); } function->getBasicBlockList().push_back(mergeBlock); builder.SetInsertPoint(mergeBlock); return nullptr; }
void ScopeConsistencyChecker::checkConsistent(IHqlExpression * root, const HqlExprArray & _activeTables) { ForEachItemIn(i, _activeTables) activeTables.append(OLINK(_activeTables.item(i))); if (root->isDataset()) pushScope(); analyse(root, 0); if (root->isDataset()) popScope(); }
void Semantic::traverse(Defn * cur) { if (cur->v == Defn::STRUCT_T) { newSym(sid, Symbol(cur->id, cur)); //check struct types and names pairwise to be distinct ArgItem * ptr = cur->args; std::set<std::string> ids; while (ptr != NULL) { valSctType(ptr->arg->type); if (ids.find(ptr->arg->ID) != ids.end()) error("struct field names must be pairwise distinct"); ptr = ptr->next; } } else if (cur->v == Defn::FUNC_T) { //check ret type valRetType(cur->type); newSym(vid.back(), Symbol(cur->id, cur)); curF = cur->id; pushScope(); //check args types and names ArgItem * ptr = cur->args; std::set<std::string> ids; while (ptr != NULL) { valArgType(ptr->arg->type); newSym(vid.back(), Symbol(ptr->arg->ID, cur->type)); if (ids.find(ptr->arg->ID) != ids.end()) error("argument names must be pairwise distinct"); ptr = ptr->next; } pushScope(); traverse(cur->stmts); popScope(); popScope(); curF = ""; } else if (cur->v == Defn::TYPEDEF_T) { valArgType(cur->type); newSym(aid, Symbol(cur->id, cur)); } }
void TreeResolver::popParent() { auto& parentElement = *parent().element; parentElement.clearNeedsStyleRecalc(); parentElement.clearChildNeedsStyleRecalc(); if (parent().didPushScope) popScope(); scope().selectorFilter.popParent(); m_parentStack.removeLast(); }
llvm::Value * Generator::visit(Function & node) { std::vector<llvm::Type *> parameterTypes; for (auto i : node.parameters) { parameterTypes.push_back(i->type->getType(typeSys)); } std::string name = node.name; if (node.name == "Main") { name = "main"; } else { name = node.getVirtualName(); } auto type = llvm::FunctionType::get(node.type->getType(typeSys), parameterTypes, false); auto function = llvm::Function::Create(type, llvm::Function::ExternalLinkage, name, module.get()); lastFunction = &node; // create the block for this function. builder.SetInsertPoint(llvm::BasicBlock::Create(*context, "entry", function)); // create the scope. createScope(); int i = 0; for (auto & arg : function->args()) { auto parameter = node.parameters[i]; arg.setName("param." + parameter->name); auto value = parameter->accept(this); builder.CreateStore(&arg, value); scope().add(parameter->name, value); i++; } node.block->accept(this); if (builder.GetInsertBlock()->getTerminator() == nullptr) { builder.CreateRetVoid(); } popScope(); return function; }
BlockNode* Parser::parseBlock(bool needBraces, const bool scoped/* = true */) { if (needBraces) { ensureToken(tLBRACE); } if (scoped) { pushScope(); } BlockNode* block = new BlockNode(_currentTokenIndex, _currentScope); TokenKind sentinel = needBraces ? tRBRACE : tEOF; while (currentToken() != sentinel) { if (currentToken() == tSEMICOLON) { consumeToken(); continue; } AstNode* statement = parseStatement(); // Ignore statements that doesn't result in AST nodes, such // as variable or function declaration. if (statement != 0) { block->add(statement); } } if (scoped) { popScope(); } if (needBraces) { ensureToken(tRBRACE); } return block; }
FunctionNode* Parser::parseFunction() { uint32_t tokenIndex = _currentTokenIndex; ensureKeyword("function"); if (currentToken() != tIDENT) { error("identifier expected"); } const string& returnTypeName = currentTokenValue(); VarType returnType = nameToType(returnTypeName); if (returnType == VT_INVALID) { error("wrong return type"); } consumeToken(); if (currentToken() != tIDENT) { error("name expected"); } const string& name = currentTokenValue(); consumeToken(); Signature signature; signature.push_back(SignatureElement(returnType, "return")); ensureToken(tLPAREN); while (currentToken() != tRPAREN) { const string& parameterTypeName = currentTokenValue(); VarType parameterType = nameToType(parameterTypeName); if (parameterType == VT_INVALID) { error("wrong parameter type"); } consumeToken(); const string& parameterName = currentTokenValue(); if (currentToken() != tIDENT) { error("identifier expected"); } consumeToken(); signature.push_back(SignatureElement(parameterType, parameterName)); if (currentToken() == tCOMMA) { consumeToken(); } } ensureToken(tRPAREN); BlockNode* body = 0; pushScope(); for (uint32_t i = 1; i < signature.size(); i++) { const string& name = signature[i].second; VarType type = signature[i].first; if (!_currentScope->declareVariable(name, type)) { error("Formal \"%s\" already declared", name.c_str()); } } if ((currentToken() == tIDENT) && currentTokenValue() == "native") { consumeToken(); if (currentToken() != tSTRING) { error("Native name expected, got %s", tokenStr(currentToken())); } pushScope(); body = new BlockNode(_currentTokenIndex, _currentScope); body->add(new NativeCallNode(tokenIndex, currentTokenValue(), signature)); consumeToken(); ensureToken(tSEMICOLON); body->add(new ReturnNode(0, 0)); popScope(); } else { body = parseBlock(true, false); if (body->nodes() == 0 || !(body->nodeAt(body->nodes() - 1)->isReturnNode())) { body->add(new ReturnNode(0, defaultReturnExpr(returnType))); } } popScope(); if (_currentScope->lookupFunction(name) != 0) { error("Function %s already defined", name.c_str()); } FunctionNode* result = new FunctionNode(tokenIndex, name, signature, body); _currentScope->declareFunction(result); // We don't add function node into AST. return 0; }
static void parseValue (tokenInfo *const token) { if (token->type == TOKEN_OPEN_CURLY) { tokenInfo *name = newToken (); do { readTokenFull (token, TRUE); if (token->type == TOKEN_STRING) { jsonKind tagKind = TAG_NULL; /* default in case of invalid value */ copyToken (name, token); /* skip any possible garbage before the value */ skipToOneOf3 (token, TOKEN_CLOSE_CURLY, TOKEN_COLON, TOKEN_COMMA); if (token->type == TOKEN_COLON) { readToken (token); tagKind = tokenToKind (token->type); pushScope (token, name, tagKind); parseValue (token); popScope (token, name); } makeJsonTag (name, tagKind); } /* skip to the end of the construct */ skipToOneOf2 (token, TOKEN_CLOSE_CURLY, TOKEN_COMMA); } while (token->type != TOKEN_EOF && token->type != TOKEN_CLOSE_CURLY); if (token->type == TOKEN_CLOSE_CURLY) readToken (token); deleteToken (name); } else if (token->type == TOKEN_OPEN_SQUARE) { tokenInfo *name = newToken (); char buf[32]; unsigned int nth = 0; readToken (token); while (token->type != TOKEN_EOF && token->type != TOKEN_CLOSE_SQUARE) { jsonKind tagKind; tagKind = tokenToKind (token->type); copyToken (name, token); snprintf (buf, sizeof buf, "%u", nth++); vStringCopyS (name->string, buf); makeJsonTag (name, tagKind); pushScope (token, name, tagKind); parseValue (token); popScope (token, name); /* skip to the end of the construct */ skipToOneOf2 (token, TOKEN_CLOSE_SQUARE, TOKEN_COMMA); if (token->type != TOKEN_CLOSE_SQUARE) readToken (token); } if (token->type == TOKEN_CLOSE_SQUARE) readToken (token); deleteToken (name); } }
/** * Implement abstract operation from NativeImportBase. * @return success status of operation */ bool PythonImport::parseStmt() { const int srcLength = m_source.count(); const QString& keyword = m_source[m_srcIndex]; if (keyword == QLatin1String("class")) { const QString& name = advance(); UMLObject *ns = Import_Utils::createUMLObject(UMLObject::ot_Class, name, currentScope(), m_comment); pushScope(m_klass = static_cast<UMLClassifier*>(ns)); m_comment.clear(); if (advance() == QLatin1String("(")) { while (m_srcIndex < srcLength - 1 && advance() != QLatin1String(")")) { const QString& baseName = m_source[m_srcIndex]; Import_Utils::createGeneralization(m_klass, baseName); if (advance() != QLatin1String(",")) break; } } if (m_source[m_srcIndex] != QLatin1String("{")) { skipStmt(QLatin1String("{")); } log(QLatin1String("class ") + name); return true; } if (keyword == QLatin1String("@")) { const QString& annotation = m_source[++m_srcIndex]; uDebug() << "annotation:" << annotation; if (annotation == QLatin1String("staticmethod")) m_isStatic = true; return true; } if (keyword == QLatin1String("def")) { if (m_klass == NULL) { // skip functions outside of a class skipBody(); return true; } if (!m_klass->hasDoc() && !m_comment.isEmpty()) { m_klass->setDoc(m_comment); m_comment = QString(); } const QString& name = advance(); // operation UMLOperation *op = Import_Utils::makeOperation(m_klass, name); if (advance() != QLatin1String("(")) { uError() << "importPython def " << name << ": expecting \"(\""; skipBody(); return true; } bool firstParam = true; while (m_srcIndex < srcLength && advance() != QLatin1String(")")) { const QString& parName = m_source[m_srcIndex]; if (firstParam) { if (parName.compare(QLatin1String("self"), Qt::CaseInsensitive) != 0) { m_isStatic = true; Import_Utils::addMethodParameter(op, QLatin1String("string"), parName); } firstParam = false; } else { /*UMLAttribute *att =*/ Import_Utils::addMethodParameter(op, QLatin1String("string"), parName); } if (advance() != QLatin1String(",")) break; } Import_Utils::insertMethod(m_klass, op, Uml::Visibility::Public, QLatin1String("string"), m_isStatic, false /*isAbstract*/, false /*isFriend*/, false /*isConstructor*/, m_comment); m_isStatic = false; op->setSourceCode(skipBody()); if (!op->hasDoc() && !m_comment.isEmpty()) { op->setDoc(m_comment); m_comment = QString(); } log(QLatin1String("def ") + name); return true; } if (keyword == QLatin1String("}")) { if (scopeIndex()) { m_klass = dynamic_cast<UMLClassifier*>(popScope()); } else uError() << "parsing: too many }"; return true; } return false; // @todo parsing of attributes }
void analyzeClass(Type classType, Writer &writer){ auto eclass = classType.eclass; writer.writeEmojicodeChar(eclass->name); if(eclass->superclass){ writer.writeUInt16(eclass->superclass->index); } else { //If the eclass does not have a superclass the own index gets written writer.writeUInt16(eclass->index); } Scope objectScope(true); //Get the ID offset for this eclass by summing up all superclasses instance variable counts uint16_t offset = 0; for(Class *aClass = eclass->superclass; aClass != nullptr; aClass = aClass->superclass){ offset += aClass->instanceVariables.size(); } writer.writeUInt16(eclass->instanceVariables.size() + offset); //Number of methods inclusive superclass writer.writeUInt16(eclass->nextMethodVti); //Number of eclass methods inclusive superclass writer.writeUInt16(eclass->nextClassMethodVti); //Initializer inclusive superclass writer.writeByte(eclass->inheritsContructors ? 1 : 0); writer.writeUInt16(eclass->nextInitializerVti); writer.writeUInt16(eclass->methodList.size()); writer.writeUInt16(eclass->initializerList.size()); writer.writeUInt16(eclass->classMethodList.size()); for (auto var : eclass->instanceVariables) { CompilerVariable *cv = new CompilerVariable(var->type, offset++, 1, false); cv->variable = var; objectScope.setLocalVariable(var->name, cv); } pushScope(&objectScope); for (auto method : eclass->methodList) { StaticFunctionAnalyzer::writeAndAnalyzeProcedure(*method, writer, classType); } for (auto initializer : eclass->initializerList) { StaticFunctionAnalyzer::writeAndAnalyzeProcedure(*initializer, writer, classType, false, initializer); } popScope(); for (auto classMethod : eclass->classMethodList) { StaticFunctionAnalyzer::writeAndAnalyzeProcedure(*classMethod, writer, classType, true); } if (eclass->instanceVariables.size() > 0 && eclass->initializerList.size() == 0) { auto str = classType.toString(typeNothingness, true); compilerWarning(eclass->classBegin, "Class %s defines %d instances variables but has no initializers.", str.c_str(), eclass->instanceVariables.size()); } writer.writeUInt16(eclass->protocols().size()); if (eclass->protocols().size() > 0) { auto biggestPlaceholder = writer.writePlaceholder<uint16_t>(); auto smallestPlaceholder = writer.writePlaceholder<uint16_t>(); uint_fast16_t smallestProtocolIndex = UINT_FAST16_MAX; uint_fast16_t biggestProtocolIndex = 0; for (auto protocol : eclass->protocols()) { writer.writeUInt16(protocol->index); if (protocol->index > biggestProtocolIndex) { biggestProtocolIndex = protocol->index; } if (protocol->index < smallestProtocolIndex) { smallestProtocolIndex = protocol->index; } writer.writeUInt16(protocol->methods().size()); for (auto method : protocol->methods()) { Method *clm = eclass->getMethod(method->name); if (clm == nullptr) { auto className = classType.toString(typeNothingness, true); auto protocolName = Type(protocol, false).toString(typeNothingness, true); ecCharToCharStack(method->name, ms); compilerError(eclass->classBegin, "Class %s does not agree to protocol %s: Method %s is missing.", className.c_str(), protocolName.c_str(), ms); } writer.writeUInt16(clm->vti); clm->checkPromises(method, "protocol definition", classType); } } biggestPlaceholder.write(biggestProtocolIndex); smallestPlaceholder.write(smallestProtocolIndex); } }
/** * Implement abstract operation from NativeImportBase. * @return success status of operation */ bool PythonImport::parseStmt() { const int srcLength = m_source.count(); QString keyword = m_source[m_srcIndex]; if (keyword == QLatin1String("class")) { const QString& name = advance(); UMLObject *ns = Import_Utils::createUMLObject(UMLObject::ot_Class, name, currentScope(), m_comment); pushScope(m_klass = ns->asUMLClassifier()); m_comment.clear(); if (advance() == QLatin1String("(")) { while (m_srcIndex < srcLength - 1 && advance() != QLatin1String(")")) { const QString& baseName = m_source[m_srcIndex]; Import_Utils::createGeneralization(m_klass, baseName); if (advance() != QLatin1String(",")) break; } } if (m_source[m_srcIndex] != QLatin1String("{")) { skipStmt(QLatin1String("{")); } log(QLatin1String("class ") + name); return true; } if (keyword == QLatin1String("@")) { const QString& annotation = m_source[++m_srcIndex]; uDebug() << "annotation:" << annotation; if (annotation == QLatin1String("staticmethod")) m_isStatic = true; return true; } if (keyword == QLatin1String("def")) { if (m_klass == 0) { // skip functions outside of a class skipBody(); return true; } if (!m_klass->hasDoc() && !m_comment.isEmpty()) { m_klass->setDoc(m_comment); m_comment = QString(); } const QString& name = advance(); // operation UMLOperation *op = Import_Utils::makeOperation(m_klass, name); if (advance() != QLatin1String("(")) { uError() << "importPython def " << name << ": expecting \"(\""; skipBody(); return true; } bool firstParam = true; while (m_srcIndex < srcLength && advance() != QLatin1String(")")) { const QString& parName = m_source[m_srcIndex]; if (firstParam) { if (parName.compare(QLatin1String("self"), Qt::CaseInsensitive) != 0) { m_isStatic = true; Import_Utils::addMethodParameter(op, QLatin1String("string"), parName); } firstParam = false; } else { /*UMLAttribute *att =*/ Import_Utils::addMethodParameter(op, QLatin1String("string"), parName); } if (advance() != QLatin1String(",")) break; } Import_Utils::insertMethod(m_klass, op, Uml::Visibility::Public, QLatin1String("string"), m_isStatic, false /*isAbstract*/, false /*isFriend*/, false /*isConstructor*/, m_comment); m_isStatic = false; int srcIndex = m_srcIndex; op->setSourceCode(skipBody()); if (!op->hasDoc() && !m_comment.isEmpty()) { op->setDoc(m_comment); m_comment = QString(); } // parse instance variables from __init__ method if (name == QLatin1String("__init__")) { int indexSave = m_srcIndex; m_srcIndex = srcIndex; advance(); keyword = advance(); while (m_srcIndex < indexSave) { if (lookAhead() == QLatin1String("=")) { parseAssignmentStmt(keyword); // skip ; inserted by lexer if (lookAhead() == QLatin1String(";")) { advance(); keyword = advance(); } } else { skipStmt(QLatin1String(";")); keyword = advance(); } } m_srcIndex = indexSave; } log(QLatin1String("def ") + name); return true; } // parse class variables if (m_klass && lookAhead() == QLatin1String("=")) { bool result = parseAssignmentStmt(keyword); log(QLatin1String("class attribute ") + keyword); return result; } if (keyword == QLatin1String("}")) { if (scopeIndex()) { m_klass = popScope()->asUMLClassifier(); } else uError() << "parsing: too many }"; return true; } return false; // @todo parsing of attributes }
/** * Implement abstract operation from NativeImportBase. */ bool AdaImport::parseStmt() { const int srcLength = m_source.count(); QString keyword = m_source[m_srcIndex]; UMLDoc *umldoc = UMLApp::app()->document(); //uDebug() << '"' << keyword << '"'; if (keyword == QLatin1String("with")) { if (m_inGenericFormalPart) { // mapping of generic formal subprograms or packages is not yet implemented return false; } while (++m_srcIndex < srcLength && m_source[m_srcIndex] != QLatin1String(";")) { QStringList components = m_source[m_srcIndex].toLower().split(QLatin1Char('.')); const QString& prefix = components.first(); if (prefix == QLatin1String("system") || prefix == QLatin1String("ada") || prefix == QLatin1String("gnat") || prefix == QLatin1String("interfaces") || prefix == QLatin1String("text_io") || prefix == QLatin1String("unchecked_conversion") || prefix == QLatin1String("unchecked_deallocation")) { if (advance() != QLatin1String(",")) break; continue; } parseStems(components); if (advance() != QLatin1String(",")) break; } return true; } if (keyword == QLatin1String("generic")) { m_inGenericFormalPart = true; return true; } if (keyword == QLatin1String("package")) { const QString& name = advance(); QStringList parentPkgs = name.toLower().split(QLatin1Char('.')); parentPkgs.pop_back(); // exclude the current package parseStems(parentPkgs); UMLObject *ns = NULL; if (advance() == QLatin1String("is")) { ns = Import_Utils::createUMLObject(UMLObject::ot_Package, name, currentScope(), m_comment); if (m_source[m_srcIndex + 1] == QLatin1String("new")) { m_srcIndex++; QString pkgName = advance(); UMLObject *gp = Import_Utils::createUMLObject(UMLObject::ot_Package, pkgName, currentScope()); gp->setStereotype(QLatin1String("generic")); // Add binding from instantiator to instantiatee UMLAssociation *assoc = new UMLAssociation(Uml::AssociationType::Dependency, ns, gp); assoc->setUMLPackage(umldoc->rootFolder(Uml::ModelType::Logical)); assoc->setStereotype(QLatin1String("bind")); // Work around missing display of stereotype in AssociationWidget: assoc->setName(assoc->stereotype(true)); umldoc->addAssociation(assoc); skipStmt(); } else { pushScope(static_cast<UMLPackage*>(ns)); } } else if (m_source[m_srcIndex] == QLatin1String("renames")) { m_renaming[name] = advance(); } else { uError() << "unexpected: " << m_source[m_srcIndex]; skipStmt(QLatin1String("is")); } if (m_inGenericFormalPart) { if (ns) ns->setStereotype(QLatin1String("generic")); m_inGenericFormalPart = false; } return true; } if (m_inGenericFormalPart) return false; // skip generic formal parameter (not yet implemented) if (keyword == QLatin1String("subtype")) { QString name = advance(); advance(); // "is" QString base = expand(advance()); base.remove(QLatin1String("Standard."), Qt::CaseInsensitive); UMLObject *type = umldoc->findUMLObject(base, UMLObject::ot_UMLObject, currentScope()); if (type == NULL) { type = Import_Utils::createUMLObject(UMLObject::ot_Datatype, base, currentScope()); } UMLObject *subtype = Import_Utils::createUMLObject(type->baseType(), name, currentScope(), m_comment); UMLAssociation *assoc = new UMLAssociation(Uml::AssociationType::Dependency, subtype, type); assoc->setUMLPackage(umldoc->rootFolder(Uml::ModelType::Logical)); assoc->setStereotype(QLatin1String("subtype")); // Work around missing display of stereotype in AssociationWidget: assoc->setName(assoc->stereotype(true)); umldoc->addAssociation(assoc); skipStmt(); return true; } if (keyword == QLatin1String("type")) { QString name = advance(); QString next = advance(); if (next == QLatin1String("(")) { uDebug() << name << ": discriminant handling is not yet implemented"; // @todo Find out how to map discriminated record to UML. // For now, we just create a pro forma empty record. Import_Utils::createUMLObject(UMLObject::ot_Class, name, currentScope(), m_comment, QLatin1String("record")); skipStmt(QLatin1String("end")); if ((next = advance()) == QLatin1String("case")) m_srcIndex += 2; // skip "case" ";" skipStmt(); return true; } if (next == QLatin1String(";")) { // forward declaration Import_Utils::createUMLObject(UMLObject::ot_Class, name, currentScope(), m_comment); return true; } if (next != QLatin1String("is")) { uError() << "expecting \"is\""; return false; } next = advance(); if (next == QLatin1String("(")) { // enum type UMLObject *ns = Import_Utils::createUMLObject(UMLObject::ot_Enum, name, currentScope(), m_comment); UMLEnum *enumType = static_cast<UMLEnum*>(ns); while ((next = advance()) != QLatin1String(")")) { Import_Utils::addEnumLiteral(enumType, next, m_comment); m_comment.clear(); if (advance() != QLatin1String(",")) break; } skipStmt(); return true; } bool isTaggedType = false; if (next == QLatin1String("abstract")) { m_isAbstract = true; next = advance(); } if (next == QLatin1String("tagged")) { isTaggedType = true; next = advance(); } if (next == QLatin1String("limited") || next == QLatin1String("task") || next == QLatin1String("protected") || next == QLatin1String("synchronized")) { next = advance(); // we can't (yet?) represent that } if (next == QLatin1String("private") || next == QLatin1String("interface") || next == QLatin1String("record") || (next == QLatin1String("null") && m_source[m_srcIndex+1] == QLatin1String("record"))) { UMLObject::ObjectType t = (next == QLatin1String("interface") ? UMLObject::ot_Interface : UMLObject::ot_Class); UMLObject *ns = Import_Utils::createUMLObject(t, name, currentScope(), m_comment); if (t == UMLObject::ot_Interface) { while ((next = advance()) == QLatin1String("and")) { UMLClassifier *klass = static_cast<UMLClassifier*>(ns); QString base = expand(advance()); UMLObject *p = Import_Utils::createUMLObject(UMLObject::ot_Interface, base, currentScope()); UMLClassifier *parent = static_cast<UMLClassifier*>(p); Import_Utils::createGeneralization(klass, parent); } } else { ns->setAbstract(m_isAbstract); } m_isAbstract = false; if (isTaggedType) { if (! m_classesDefinedInThisScope.contains(ns)) m_classesDefinedInThisScope.append(ns); } else { ns->setStereotype(QLatin1String("record")); } if (next == QLatin1String("record")) m_klass = static_cast<UMLClassifier*>(ns); else skipStmt(); return true; } if (next == QLatin1String("new")) { QString base = expand(advance()); QStringList baseInterfaces; while ((next = advance()) == QLatin1String("and")) { baseInterfaces.append(expand(advance())); } const bool isExtension = (next == QLatin1String("with")); UMLObject::ObjectType t; if (isExtension || m_isAbstract) { t = UMLObject::ot_Class; } else { base.remove(QLatin1String("Standard."), Qt::CaseInsensitive); UMLObject *known = umldoc->findUMLObject(base, UMLObject::ot_UMLObject, currentScope()); t = (known ? known->baseType() : UMLObject::ot_Datatype); } UMLObject *ns = Import_Utils::createUMLObject(t, base, NULL); UMLClassifier *parent = static_cast<UMLClassifier*>(ns); ns = Import_Utils::createUMLObject(t, name, currentScope(), m_comment); if (isExtension) { next = advance(); if (next == QLatin1String("null") || next == QLatin1String("record")) { UMLClassifier *klass = static_cast<UMLClassifier*>(ns); Import_Utils::createGeneralization(klass, parent); if (next == QLatin1String("record")) { // Set the m_klass for attributes. m_klass = klass; } if (baseInterfaces.count()) { t = UMLObject::ot_Interface; QStringList::Iterator end(baseInterfaces.end()); for (QStringList::Iterator bi(baseInterfaces.begin()); bi != end; ++bi) { ns = Import_Utils::createUMLObject(t, *bi, currentScope()); parent = static_cast<UMLClassifier*>(ns); Import_Utils::createGeneralization(klass, parent); } } } } skipStmt(); return true; } // Datatypes: TO BE DONE return false; } if (keyword == QLatin1String("private")) { m_currentAccess = Uml::Visibility::Private; return true; } if (keyword == QLatin1String("end")) { if (m_klass) { if (advance() != QLatin1String("record")) { uError() << "end: expecting \"record\" at " << m_source[m_srcIndex]; } m_klass = NULL; } else if (scopeIndex()) { if (advance() != QLatin1String(";")) { QString scopeName = currentScope()->fullyQualifiedName(); if (scopeName.toLower() != m_source[m_srcIndex].toLower()) uError() << "end: expecting " << scopeName << ", found " << m_source[m_srcIndex]; } popScope(); m_currentAccess = Uml::Visibility::Public; // @todo make a stack for this } else { uError() << "importAda: too many \"end\""; } skipStmt(); return true; } // subprogram if (keyword == QLatin1String("not")) keyword = advance(); if (keyword == QLatin1String("overriding")) keyword = advance(); if (keyword == QLatin1String("function") || keyword == QLatin1String("procedure")) { const QString& name = advance(); QString returnType; if (advance() != QLatin1String("(")) { // Unlike an Ada package, a UML package does not support // subprograms. // In order to map those, we would need to create a UML // class with stereotype <<utility>> for the Ada package. uDebug() << "ignoring parameterless " << keyword << " " << name; skipStmt(); return true; } UMLClassifier *klass = NULL; UMLOperation *op = NULL; const uint MAX_PARNAMES = 16; while (m_srcIndex < srcLength && m_source[m_srcIndex] != QLatin1String(")")) { QString parName[MAX_PARNAMES]; uint parNameCount = 0; do { if (parNameCount >= MAX_PARNAMES) { uError() << "MAX_PARNAMES is exceeded at " << name; break; } parName[parNameCount++] = advance(); } while (advance() == QLatin1String(",")); if (m_source[m_srcIndex] != QLatin1String(":")) { uError() << "importAda: expecting ':'"; skipStmt(); break; } const QString &direction = advance(); QString typeName; Uml::ParameterDirection::Enum dir = Uml::ParameterDirection::In; if (direction == QLatin1String("access")) { // Oops, we have to improvise here because there // is no such thing as "access" in UML. // So we use the next best thing, "inout". // Better ideas, anyone? dir = Uml::ParameterDirection::InOut; typeName = advance(); } else if (direction == QLatin1String("in")) { if (m_source[m_srcIndex + 1] == QLatin1String("out")) { dir = Uml::ParameterDirection::InOut; m_srcIndex++; } typeName = advance(); } else if (direction == QLatin1String("out")) { dir = Uml::ParameterDirection::Out; typeName = advance(); } else { typeName = direction; // In Ada, the default direction is "in" } typeName.remove(QLatin1String("Standard."), Qt::CaseInsensitive); typeName = expand(typeName); if (op == NULL) { // In Ada, the first parameter indicates the class. UMLObject *type = Import_Utils::createUMLObject(UMLObject::ot_Class, typeName, currentScope()); UMLObject::ObjectType t = type->baseType(); if ((t != UMLObject::ot_Interface && (t != UMLObject::ot_Class || type->stereotype() == QLatin1String("record"))) || !m_classesDefinedInThisScope.contains(type)) { // Not an instance bound method - we cannot represent it. skipStmt(QLatin1String(")")); break; } klass = static_cast<UMLClassifier*>(type); op = Import_Utils::makeOperation(klass, name); // The controlling parameter is suppressed. parNameCount--; if (parNameCount) { for (uint i = 0; i < parNameCount; ++i) { parName[i] = parName[i + 1]; } } } for (uint i = 0; i < parNameCount; ++i) { UMLAttribute *att = Import_Utils::addMethodParameter(op, typeName, parName[i]); att->setParmKind(dir); } if (advance() != QLatin1String(";")) break; } if (keyword == QLatin1String("function")) { if (advance() != QLatin1String("return")) { if (klass) uError() << "importAda: expecting \"return\" at function " << name; return false; } returnType = expand(advance()); returnType.remove(QLatin1String("Standard."), Qt::CaseInsensitive); } bool isAbstract = false; if (advance() == QLatin1String("is") && advance() == QLatin1String("abstract")) isAbstract = true; if (klass != NULL && op != NULL) Import_Utils::insertMethod(klass, op, m_currentAccess, returnType, false, isAbstract, false, false, m_comment); skipStmt(); return true; } if (keyword == QLatin1String("task") || keyword == QLatin1String("protected")) { // Can task and protected objects/types be mapped to UML? QString name = advance(); if (name == QLatin1String("type")) { name = advance(); } QString next = advance(); if (next == QLatin1String("(")) { skipStmt(QLatin1String(")")); // skip discriminant next = advance(); } if (next == QLatin1String("is")) skipStmt(QLatin1String("end")); skipStmt(); return true; } if (keyword == QLatin1String("for")) { // rep spec QString typeName = advance(); QString next = advance(); if (next == QLatin1String("'")) { advance(); // skip qualifier next = advance(); } if (next == QLatin1String("use")) { if (advance() == QLatin1String("record")) skipStmt(QLatin1String("end")); } else { uError() << "importAda: expecting \"use\" at rep spec of " << typeName; } skipStmt(); return true; } // At this point we're only interested in attribute declarations. if (m_klass == NULL || keyword == QLatin1String("null")) { skipStmt(); return true; } const QString& name = keyword; if (advance() != QLatin1String(":")) { uError() << "adaImport: expecting \":\" at " << name << " " << m_source[m_srcIndex]; skipStmt(); return true; } QString nextToken = advance(); if (nextToken == QLatin1String("aliased")) nextToken = advance(); QString typeName = expand(nextToken); QString initialValue; if (advance() == QLatin1String(":=")) { initialValue = advance(); QString token; while ((token = advance()) != QLatin1String(";")) { initialValue.append(QLatin1Char(' ') + token); } } UMLObject *o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name, typeName, m_comment); if (o) { UMLAttribute *attr = static_cast<UMLAttribute*>(o); attr->setInitialValue(initialValue); } skipStmt(); return true; }
void AVisitor<Vis>::pop(){ popScope(); }
void Semantic::traverse(Stmt * cur) { if (cur->v == Stmt::LIST_T) { pushScope(); traverse(cur->list); popScope(); } else if (cur->v == Stmt::IF_T || cur->v == Stmt::WHILE_T) { if (cur->v == Stmt::WHILE_T) loops.push(cur); Type t = expType(cur->exp); traverse(cur->exp); if (t.v == Type::INT_T || t.v == Type::CHAR_T) { //warning pushScope(); traverse(cur->left); popScope(); } else if (t.v == Type::BOOL_T) { pushScope(); traverse(cur->left); popScope(); } else error("Condition must be of type bool"); if (cur->v == Stmt::WHILE_T) loops.pop(); } else if (cur->v == Stmt::FOR_T) { loops.push(cur); pushScope(); traverse(cur->left); Type t = expType(cur->exp); traverse(cur->exp); if (t.v == Type::INT_T || t.v == Type::CHAR_T) { //warning pushScope(); traverse(cur->stmt); popScope(); } else if (t.v == Type::BOOL_T) { pushScope(); traverse(cur->stmt); popScope(); } else error("Condition must be of type bool"); if (hasDecl(cur->right)) error("For loop-end statement must not include declarations"); traverse(cur->right); popScope(); loops.pop(); } else if (cur->v == Stmt::RETURN_T) { //check current function return type and compare it with this if (!sameType(expType(cur->exp), *getSym(curF).defn->type)) error("return expression type differs from function " + curF + " signature"); if (cur->exp != NULL) traverse(cur->exp); } else if (cur->v == Stmt::ASSERT_T) { //check argument type to be of bool if (!sameType(expType(cur->exp), Type(Type::BOOL_T))) error("assert expression type must be bool"); traverse(cur->exp); } else if (cur->v == Stmt::ERROR_T) { //call error function with argment string if (!sameType(expType(cur->exp), Type(Type::STRING_T))) error("error argument must be of type string"); traverse(cur->exp); } else if (cur->v == Stmt::ASSIGN_T) { //check if lhs and rhs same type, ensure rhs and lhs is not a struct Type l = lvalType(cur->lval), r = expType(cur->exp); traverse(cur->exp); if (cur->op == "=") { if (!sameType(l, r)) error("lval and expression have different types"); } else if (cur->op == ">>=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from right shift must be of type int or char"); if (!sameType(r, Type(Type::INT_T))) error("shift ammount must be of type int"); } else if (cur->op == "<<=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from left shift must be of type int or char"); if (!sameType(r, Type(Type::INT_T))) error("shift ammount must be of type int"); } else if (cur->op == "+=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from add assign must be of type int or char"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)))) error("expression from add assign must be of type int or char"); } else if (cur->op == "-=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from sub assign must be of type int or char"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)))) error("expression from sub assign must be of type int or char"); } else if (cur->op == "*=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from mul assign must be of type int or char"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)))) error("expression from mul assign must be of type int or char"); } else if (cur->op == "/=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from div assign must be of type int or char"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)))) error("expression from div assign must be of type int or char"); } else if (cur->op == "%=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from mod assign must be of type int or char"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)))) error("expression from mod assign must be of type int or char"); } else if (cur->op == "&=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)) || sameType(l, Type(Type::BOOL_T)))) error("lval from and assign must be of type int or char or bool"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)) || sameType(r, Type(Type::BOOL_T)))) error("expression from and assign must be of type int or char or bool"); } else if (cur->op == "^=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)) || sameType(l, Type(Type::BOOL_T)))) error("lval from xor assign must be of type int or char or bool"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)) || sameType(r, Type(Type::BOOL_T)))) error("expression from xor assign must be of type int or char or bool"); } else if (cur->op == "|=") { if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)) || sameType(l, Type(Type::BOOL_T)))) error("lval from or assign must be of type int or char or bool"); if (!(sameType(r, Type(Type::INT_T)) || sameType(r, Type(Type::CHAR_T)) || sameType(r, Type(Type::BOOL_T)))) error("expression from or assign must be of type int or char or bool"); } } else if (cur->v == Stmt::INC_T) { //check if lhs is int or char Type l = lvalType(cur->lval); if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from increment must be of type int or char"); } else if (cur->v == Stmt::DEC_T) { //check if lhs is int or char Type l = lvalType(cur->lval); if (!(sameType(l, Type(Type::INT_T)) || sameType(l, Type(Type::CHAR_T)))) error("lval from decrement must be of type int or char"); } else if (cur->v == Stmt::EXP_T) { traverse(cur->exp); } else if (cur->v == Stmt::DECL_T) { //declaring a variable newSym(vid.back(), Symbol(cur->arg->ID, cur->arg->type)); } else if (cur->v == Stmt::DECLI_T) { //declaring and assigning a variable newSym(vid.back(), Symbol(cur->arg->ID, cur->arg->type)); } else if (cur->v == Stmt::BREAK_T) { //check most recent loop if (loops.empty()) error("break statement does not have a loop"); } else if (cur->v == Stmt::CONT_T) { if (loops.empty()) error("continue statement does not have a loop"); } }