| /* | |
| Copyright 2019 Alain Dargelas | |
| Licensed under the Apache License, Version 2.0 (the "License"); | |
| you may not use this file except in compliance with the License. | |
| You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| /* | |
| * File: TestbenchElaboration.cpp | |
| * Author: alain | |
| * | |
| * Created on February 6, 2019, 9:01 PM | |
| */ | |
| #include <queue> | |
| #include "../SourceCompile/VObjectTypes.h" | |
| #include "../Design/VObject.h" | |
| #include "../Library/Library.h" | |
| #include "../Design/FileContent.h" | |
| #include "../SourceCompile/SymbolTable.h" | |
| #include "../ErrorReporting/Error.h" | |
| #include "../ErrorReporting/Location.h" | |
| #include "../ErrorReporting/Error.h" | |
| #include "../ErrorReporting/ErrorDefinition.h" | |
| #include "../ErrorReporting/ErrorContainer.h" | |
| #include "../SourceCompile/CompilationUnit.h" | |
| #include "../SourceCompile/PreprocessFile.h" | |
| #include "../SourceCompile/CompileSourceFile.h" | |
| #include "../SourceCompile/ParseFile.h" | |
| #include "../SourceCompile/Compiler.h" | |
| #include "CompileDesign.h" | |
| #include "../Testbench/Property.h" | |
| #include "../Design/Function.h" | |
| #include "../Testbench/ClassDefinition.h" | |
| #include "TestbenchElaboration.h" | |
| using namespace SURELOG; | |
| TestbenchElaboration::~TestbenchElaboration() {} | |
| bool TestbenchElaboration::bindTypedefs_() { | |
| Compiler* compiler = m_compileDesign->getCompiler(); | |
| ErrorContainer* errors = compiler->getErrorContainer(); | |
| SymbolTable* symbols = compiler->getSymbolTable(); | |
| Design* design = compiler->getDesign(); | |
| std::vector<std::pair<TypeDef*, DesignComponent*>> defs; | |
| for (auto file : design->getAllFileContents()) { | |
| FileContent* fC = file.second; | |
| for (auto typed : fC->getTypeDefMap()) { | |
| TypeDef* typd = typed.second; | |
| defs.push_back(std::make_pair(typd, fC)); | |
| } | |
| } | |
| for (auto package : design->getPackageDefinitions()) { | |
| Package* pack = package.second; | |
| for (auto typed : pack->getTypeDefMap()) { | |
| TypeDef* typd = typed.second; | |
| defs.push_back(std::make_pair(typd, pack)); | |
| } | |
| } | |
| for (auto program_def : design->getProgramDefinitions()) { | |
| Program* program = program_def.second; | |
| for (auto typed : program->getTypeDefMap()) { | |
| TypeDef* typd = typed.second; | |
| defs.push_back(std::make_pair(typd, program)); | |
| } | |
| } | |
| for (auto class_def : design->getClassDefinitions()) { | |
| ClassDefinition* classp = class_def.second; | |
| for (auto typed : classp->getTypeDefMap()) { | |
| TypeDef* typd = typed.second; | |
| defs.push_back(std::make_pair(typd, classp)); | |
| } | |
| } | |
| for (auto def : defs) { | |
| TypeDef* typd = def.first; | |
| DesignComponent* comp = def.second; | |
| if (typd->getDefinition() == NULL) { | |
| DataType* def = | |
| bindTypeDef_(typd, comp, ErrorDefinition::NO_ERROR_MESSAGE); | |
| if (def && (typd != def)) { | |
| typd->setDefinition(def); | |
| } else { | |
| FileContent* fC = typd->getFileContent(); | |
| NodeId id = typd->getNodeId(); | |
| std::string fileName = fC->getFileName(id); | |
| unsigned int line = fC->Line(id); | |
| std::string definition_string; | |
| NodeId defNode = typd->getDefinitionNode(); | |
| VObjectType defType = fC->Type(defNode); | |
| if (defType == VObjectType::slStringConst) { | |
| definition_string = fC->SymName(defNode); | |
| } | |
| Location loc1(symbols->registerSymbol(fileName), line, 0, | |
| symbols->registerSymbol(definition_string)); | |
| Error err1(ErrorDefinition::COMP_UNDEFINED_TYPE, loc1); | |
| errors->addError(err1); | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| bool checkValidFunction(DataType* dtype, std::string function, Statement* stmt, | |
| Design* design, std::string& datatypeName) { | |
| bool validFunction = true; | |
| VObjectType type = dtype->getType(); | |
| DataType* def = dtype->getDefinition(); | |
| if (type == VObjectType::slClass_declaration) { | |
| ClassDefinition* the_class = dynamic_cast<ClassDefinition*>(dtype); | |
| if (the_class) { | |
| Function* func = the_class->getFunction(function); | |
| if (func) | |
| stmt->setFunction(func); | |
| else | |
| validFunction = false; | |
| } else { | |
| the_class = dynamic_cast<ClassDefinition*>(def); | |
| if (the_class) { | |
| Function* func = the_class->getFunction(function); | |
| if (func) | |
| stmt->setFunction(func); | |
| else | |
| validFunction = false; | |
| } | |
| } | |
| } else if (dtype->isString_type(type)) { | |
| ClassDefinition* array = design->getClassDefinition("builtin::string"); | |
| Function* func = array->getFunction(function); | |
| if (func) | |
| stmt->setFunction(func); | |
| else { | |
| datatypeName = "string"; | |
| validFunction = false; | |
| } | |
| } else | |
| validFunction = false; | |
| return validFunction; | |
| } | |
| bool checkValidBuiltinClass_(std::string classname, std::string function, | |
| Statement* stmt, Design* design, | |
| std::string& datatypeName) { | |
| bool validFunction = true; | |
| ClassDefinition* array = design->getClassDefinition("builtin::" + classname); | |
| Function* func = array->getFunction(function); | |
| if (func) | |
| stmt->setFunction(func); | |
| else { | |
| datatypeName = classname; | |
| validFunction = false; | |
| } | |
| return validFunction; | |
| } | |
| void computeVarChain(FileContent* fC, NodeId nodeId, | |
| std::vector<std::string>& var_chain) { | |
| while (nodeId) { | |
| VObjectType type = fC->Type(nodeId); | |
| switch (type) { | |
| case VObjectType::slStringConst: { | |
| var_chain.push_back(fC->SymName(nodeId)); | |
| break; | |
| } | |
| case VObjectType::slImplicit_class_handle: { | |
| NodeId child = fC->Child(nodeId); | |
| VObjectType childType = fC->Type(child); | |
| if (childType == VObjectType::slThis_keyword) | |
| var_chain.push_back("this"); | |
| else if (childType == VObjectType::slSuper_keyword) | |
| var_chain.push_back("super"); | |
| else | |
| var_chain.push_back("UNKNOWN_TYPE"); | |
| break; | |
| } | |
| default: | |
| var_chain.push_back("UNKNOWN_NAME"); | |
| break; | |
| } | |
| nodeId = fC->Sibling(nodeId); | |
| } | |
| } | |
| bool TestbenchElaboration::bindClasses_() { | |
| checkForMultipleDefinition_(); | |
| bindBaseClasses_(); | |
| bindDataTypes_(); | |
| bindFunctions_(); | |
| bindTasks_(); | |
| return true; | |
| } | |
| bool TestbenchElaboration::checkForMultipleDefinition_() { | |
| Compiler* compiler = m_compileDesign->getCompiler(); | |
| ErrorContainer* errors = compiler->getErrorContainer(); | |
| SymbolTable* symbols = compiler->getSymbolTable(); | |
| Design* design = compiler->getDesign(); | |
| ClassNameClassDefinitionMultiMap classes = design->getClassDefinitions(); | |
| // Check for multiple definition | |
| std::string prevClassName = ""; | |
| ClassDefinition* prevClassDefinition = NULL; | |
| for (ClassNameClassDefinitionMultiMap::iterator itr = classes.begin(); | |
| itr != classes.end(); itr++) { | |
| std::string className = (*itr).first; | |
| ClassDefinition* classDefinition = (*itr).second; | |
| bool done = false; | |
| if (className == prevClassName) { | |
| FileContent* fC1 = classDefinition->getFileContents()[0]; | |
| NodeId nodeId1 = classDefinition->getNodeIds()[0]; | |
| std::string fileName1 = fC1->getFileName(nodeId1); | |
| unsigned int line1 = fC1->Line(nodeId1); | |
| Location loc1(symbols->registerSymbol(fileName1), line1, 0, | |
| symbols->registerSymbol(className)); | |
| std::vector<Location> locations; | |
| while (1) { | |
| FileContent* fC2 = prevClassDefinition->getFileContents()[0]; | |
| NodeId nodeId2 = prevClassDefinition->getNodeIds()[0]; | |
| std::string fileName2 = fC2->getFileName(nodeId2); | |
| unsigned int line2 = fC2->Line(nodeId2); | |
| Location loc2(symbols->registerSymbol(fileName2), line2, 0, | |
| symbols->registerSymbol(className)); | |
| if ((fileName1 != fileName2) || (line1 != line2)) { | |
| std::string diff; | |
| if (fC1->diffTree(diff, nodeId1, fC2, nodeId2)) { | |
| locations.push_back(loc2); | |
| } | |
| } | |
| itr++; | |
| if (itr == classes.end()) { | |
| done = true; | |
| break; | |
| } else { | |
| std::string nextClassName = (*itr).first; | |
| ClassDefinition* nextClassDefinition = (*itr).second; | |
| prevClassName = nextClassName; | |
| prevClassDefinition = nextClassDefinition; | |
| if (prevClassName != className) { | |
| className = prevClassName; | |
| classDefinition = prevClassDefinition; | |
| break; | |
| } | |
| } | |
| } | |
| if (locations.size()) { | |
| Error err1(ErrorDefinition::COMP_MULTIPLY_DEFINED_CLASS, loc1, | |
| &locations); | |
| errors->addError(err1); | |
| } | |
| } | |
| prevClassName = className; | |
| prevClassDefinition = classDefinition; | |
| if (done) break; | |
| } | |
| return true; | |
| } | |
| bool TestbenchElaboration::bindBaseClasses_() { | |
| Compiler* compiler = m_compileDesign->getCompiler(); | |
| Design* design = compiler->getDesign(); | |
| ClassNameClassDefinitionMultiMap classes = design->getClassDefinitions(); | |
| // Bind base classes | |
| for (ClassNameClassDefinitionMultiMap::iterator itr = classes.begin(); | |
| itr != classes.end(); itr++) { | |
| std::string className = (*itr).first; | |
| ClassDefinition* classDefinition = (*itr).second; | |
| for (auto& class_def : classDefinition->getBaseClassMap()) { | |
| DataType* the_def = | |
| bindDataType_(class_def.first, class_def.second->getFileContent(), | |
| class_def.second->getNodeId(), classDefinition, | |
| ErrorDefinition::COMP_UNDEFINED_BASE_CLASS); | |
| class_def.second = dynamic_cast<ClassDefinition*>(the_def); | |
| if (class_def.second) { | |
| // Super | |
| DataType* thisdt = new DataType( | |
| class_def.second->getFileContent(), class_def.second->getNodeId(), | |
| class_def.second->getName(), VObjectType::slClass_declaration); | |
| thisdt->setDefinition(class_def.second); | |
| Property* prop = new Property(thisdt, classDefinition->getFileContent(), | |
| classDefinition->getNodeId(), 0, "super", | |
| false, false, false, false, false); | |
| classDefinition->insertProperty(prop); | |
| } else { | |
| class_def.second = dynamic_cast<Parameter*>(the_def); | |
| if (class_def.second) { | |
| // Super | |
| DataType* thisdt = new DataType( | |
| class_def.second->getFileContent(), class_def.second->getNodeId(), | |
| class_def.second->getName(), VObjectType::slClass_declaration); | |
| thisdt->setDefinition(class_def.second); | |
| Property* prop = | |
| new Property(thisdt, classDefinition->getFileContent(), | |
| classDefinition->getNodeId(), 0, "super", false, | |
| false, false, false, false); | |
| classDefinition->insertProperty(prop); | |
| } | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| bool TestbenchElaboration::bindDataTypes_() { | |
| Compiler* compiler = m_compileDesign->getCompiler(); | |
| Design* design = compiler->getDesign(); | |
| ClassNameClassDefinitionMultiMap classes = design->getClassDefinitions(); | |
| // Bind data types | |
| for (ClassNameClassDefinitionMultiMap::iterator itr = classes.begin(); | |
| itr != classes.end(); itr++) { | |
| std::string className = (*itr).first; | |
| ClassDefinition* classDefinition = (*itr).second; | |
| for (auto& datatype : classDefinition->getUsedDataTypeMap()) { | |
| std::string dataTypeName = datatype.first; | |
| DataType* dtype = datatype.second; | |
| if (dtype->getDefinition()) continue; | |
| VObjectType type = dtype->getType(); | |
| if (type == VObjectType::slStringConst || | |
| type == VObjectType::slNull_rule || | |
| type == VObjectType::slClass_scope) { | |
| DataType* the_def = bindDataType_(dataTypeName, dtype->getFileContent(), | |
| dtype->getNodeId(), classDefinition, | |
| ErrorDefinition::COMP_UNDEFINED_TYPE); | |
| if (the_def != dtype) dtype->setDefinition(the_def); | |
| } | |
| } | |
| for (auto& func : classDefinition->getFunctionMap()) { | |
| for (auto& datatype : func.second->getUsedDataTypeMap()) { | |
| std::string dataTypeName = datatype.first; | |
| DataType* dtype = datatype.second; | |
| if (dtype->getDefinition()) continue; | |
| VObjectType type = dtype->getType(); | |
| if (type == VObjectType::slStringConst || | |
| type == VObjectType::slNull_rule || | |
| type == VObjectType::slClass_scope) { | |
| DataType* the_def = bindDataType_( | |
| dataTypeName, dtype->getFileContent(), dtype->getNodeId(), | |
| classDefinition, ErrorDefinition::COMP_UNDEFINED_TYPE); | |
| if (the_def != dtype) dtype->setDefinition(the_def); | |
| } | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| bool TestbenchElaboration::bindFunctions_() { | |
| bindFunctionReturnTypesAndParamaters_(); | |
| bindFunctionBodies_(); | |
| return true; | |
| } | |
| bool TestbenchElaboration::bindFunctionReturnTypesAndParamaters_() { | |
| Compiler* compiler = m_compileDesign->getCompiler(); | |
| ErrorContainer* errors = compiler->getErrorContainer(); | |
| SymbolTable* symbols = compiler->getSymbolTable(); | |
| Design* design = compiler->getDesign(); | |
| ClassNameClassDefinitionMultiMap classes = design->getClassDefinitions(); | |
| // Bind Function return values, parameters and body | |
| for (ClassNameClassDefinitionMultiMap::iterator itr = classes.begin(); | |
| itr != classes.end(); itr++) { | |
| std::string className = (*itr).first; | |
| ClassDefinition* classDefinition = (*itr).second; | |
| for (auto& func : classDefinition->getFunctionMap()) { | |
| DataType* dtype = func.second->getReturnType(); | |
| std::string dataTypeName = dtype->getName(); | |
| if (dtype->getDefinition()) continue; | |
| if (dtype->getFileContent() == NULL) continue; | |
| if (dtype->getType() == VObjectType::slStringConst) { | |
| DataType* the_def = bindDataType_( | |
| dataTypeName, dtype->getFileContent(), func.second->getNodeId(), | |
| classDefinition, ErrorDefinition::COMP_UNDEFINED_TYPE); | |
| if (the_def != dtype) dtype->setDefinition(the_def); | |
| } | |
| for (auto& param : func.second->getParams()) { | |
| DataType* dtype = param->getDataType(); | |
| std::string dataTypeName = dtype->getName(); | |
| if (dtype->getDefinition()) continue; | |
| if (dtype->getFileContent() == NULL) continue; | |
| if (dtype->getType() == VObjectType::slStringConst) { | |
| DataType* the_def = bindDataType_( | |
| dataTypeName, dtype->getFileContent(), param->getNodeId(), | |
| classDefinition, ErrorDefinition::COMP_UNDEFINED_TYPE); | |
| if (the_def != dtype) dtype->setDefinition(the_def); | |
| if (the_def && the_def->isParameter()) continue; | |
| Value* value = param->getDefault(); | |
| if (value) { | |
| if (!dtype->isCompatible(value)) { | |
| std::string name = param->getName(); | |
| std::string typeName = dtype->getName(); | |
| NodeId p = param->getNodeId(); | |
| FileContent* fC = dtype->getFileContent(); | |
| std::string fileName = fC->getFileName(p); | |
| unsigned int line = fC->Line(p); | |
| Location loc1( | |
| symbols->registerSymbol(fileName), line, 0, | |
| symbols->registerSymbol(name + " of type " + typeName)); | |
| std::string exp; | |
| if (value->getType() == Value::String) | |
| exp = value->getValueS(); | |
| else if (value->getType() == Value::Double) | |
| exp = std::to_string(value->getValueD(0)); | |
| else | |
| exp = std::to_string(value->getValueL(0)); | |
| Location loc2(0, 0, 0, symbols->registerSymbol(exp)); | |
| Error err1(ErrorDefinition::COMP_INCOMPATIBLE_TYPES, loc1, loc2); | |
| errors->addError(err1); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| bool TestbenchElaboration::bindSubRoutineCall_(ClassDefinition* classDefinition, | |
| Statement* stmt, Design* design, | |
| SymbolTable* symbols, | |
| ErrorContainer* errors) { | |
| std::string datatypeName; | |
| SubRoutineCallStmt* st = dynamic_cast<SubRoutineCallStmt*>(stmt); | |
| std::vector<std::string> var_chain = st->getVarChainNames(); | |
| std::string function = st->getFunc(); | |
| bool validFunction = true; | |
| DataType* dtype = NULL; | |
| Variable* the_obj = NULL; | |
| if (st->isStatic()) | |
| the_obj = locateStaticVariable_( | |
| var_chain, st->getFileContent(), st->getNodeId(), stmt->getScope(), | |
| classDefinition, ErrorDefinition::ELAB_UNDEF_VARIABLE); | |
| else | |
| the_obj = locateVariable_(var_chain, st->getFileContent(), st->getNodeId(), | |
| stmt->getScope(), classDefinition, | |
| ErrorDefinition::ELAB_UNDEF_VARIABLE); | |
| if (the_obj) { | |
| dtype = the_obj->getDataType(); | |
| if (dtype == NULL) return true; | |
| VObjectType type = dtype->getType(); | |
| DataType* def = dtype->getDefinition(); | |
| if (type == VObjectType::slClass_declaration) { | |
| validFunction = | |
| checkValidFunction(dtype, function, stmt, design, datatypeName); | |
| } else if (dtype->isNumber(type) || dtype->isInteger_type(type) || | |
| dtype->isNon_integer_type(type) || dtype->isString_type(type)) { | |
| if (def) { | |
| type = def->getType(); | |
| dtype = def; | |
| } | |
| NodeId range = the_obj->getRange(); | |
| if (range) { | |
| VObjectType rangeType = the_obj->getFileContent()->Type(range); | |
| if (rangeType == VObjectType::slUnsized_dimension) { | |
| // Vector | |
| validFunction = checkValidBuiltinClass_("array", function, stmt, | |
| design, datatypeName); | |
| } else if (rangeType == VObjectType::slVariable_dimension) { | |
| FileContent* sfC = the_obj->getFileContent(); | |
| NodeId subRange = sfC->Child(range); | |
| VObjectType the_type = sfC->Type(subRange); | |
| if (the_type == VObjectType::slQueue_dimension) { | |
| // Queue | |
| // foreach (darray[id]) darray[id].func() | |
| NodeId tmp = stmt->getNodeId(); | |
| tmp = sfC->Child(tmp); | |
| tmp = sfC->Sibling(tmp); | |
| VObjectType t = sfC->Type(tmp); | |
| if ((t == VObjectType::slConstant_bit_select) && sfC->Child(tmp)) { | |
| // there is an actual array index | |
| if (type == VObjectType::slClass_declaration) { | |
| validFunction = checkValidFunction(dtype, function, stmt, | |
| design, datatypeName); | |
| } | |
| } else { | |
| validFunction = checkValidBuiltinClass_("queue", function, stmt, | |
| design, datatypeName); | |
| } | |
| } else if (the_type == VObjectType::slUnpacked_dimension) { | |
| // foreach (darray[id]) darray[id].func() | |
| NodeId subroutine_call = stmt->getNodeId(); | |
| NodeId var_id = sfC->Child(subroutine_call); | |
| NodeId constant_bit_select = sfC->Sibling(var_id); | |
| VObjectType t = sfC->Type(constant_bit_select); | |
| NodeId select_id = sfC->Child(constant_bit_select); | |
| if ((t == VObjectType::slConstant_bit_select) && select_id) { | |
| validFunction = checkValidFunction(dtype, function, stmt, design, | |
| datatypeName); | |
| } else { | |
| validFunction = checkValidBuiltinClass_("queue", function, stmt, | |
| design, datatypeName); | |
| } | |
| } | |
| } | |
| } else { | |
| validFunction = | |
| checkValidFunction(dtype, function, stmt, design, datatypeName); | |
| } | |
| } | |
| } | |
| if (var_chain.size() == 0) { | |
| if (st->isSystemCall()) { | |
| validFunction = checkValidBuiltinClass_("system", function, stmt, design, | |
| datatypeName); | |
| if (!validFunction) { | |
| FileContent* fC = st->getFileContent(); | |
| NodeId p = st->getNodeId(); | |
| std::string fileName = fC->getFileName(p); | |
| unsigned int line = fC->Line(p); | |
| Location loc1(symbols->registerSymbol(fileName), line, 0, | |
| symbols->registerSymbol(function)); | |
| Error err1(ErrorDefinition::COMP_UNDEFINED_SYSTEM_FUNCTION, loc1); | |
| errors->addError(err1); | |
| return true; | |
| } | |
| } else { | |
| Function* func = classDefinition->getFunction(function); | |
| if (func) | |
| stmt->setFunction(func); | |
| else { | |
| validFunction = false; | |
| dtype = classDefinition; | |
| } | |
| } | |
| } | |
| if (validFunction == false) { | |
| if (dtype->isParameter()) { | |
| return true; | |
| } | |
| std::string name; | |
| for (auto v : var_chain) name += v + "."; | |
| if (name.size()) name = name.substr(0, name.size() - 1); | |
| while (dtype && dtype->getDefinition()) { | |
| dtype = dtype->getDefinition(); | |
| } | |
| if (name == "") { | |
| name = "this"; | |
| } | |
| std::string typeName = dtype->getName(); | |
| if (datatypeName != "") typeName = datatypeName; | |
| NodeId p = st->getNodeId(); | |
| FileContent* fC = st->getFileContent(); | |
| std::string fileName = fC->getFileName(p); | |
| unsigned int line = fC->Line(p); | |
| Location loc1( | |
| symbols->registerSymbol(fileName), line, 0, | |
| symbols->registerSymbol("\"" + name + "\"" + " of type " + typeName)); | |
| FileContent* fC2 = dtype->getFileContent(); | |
| std::string fileName2 = fC2->getFileName(dtype->getNodeId()); | |
| unsigned int line2 = fC2->Line(dtype->getNodeId()); | |
| Location loc2(symbols->registerSymbol(fileName2), line2, 0, | |
| symbols->registerSymbol(function)); | |
| Error err1(ErrorDefinition::COMP_NO_METHOD_FOR_TYPE, loc1, loc2); | |
| errors->addError(err1); | |
| } | |
| return true; | |
| } | |
| bool TestbenchElaboration::bindForLoop_(ClassDefinition* classDefinition, | |
| Statement* stmt, ForLoopStmt* st) { | |
| FileContent* sfC = st->getFileContent(); | |
| NodeId fid = st->getNodeId(); | |
| VObjectType itr_type = st->getIteratorType(); | |
| DataType* itrDataType = new DataType(sfC, fid, "integer", itr_type); | |
| for (auto itrId : st->getIteratorIds()) { | |
| Variable* var = new Variable(itrDataType, sfC, itrId.first, 0, | |
| sfC->SymName(itrId.first)); | |
| st->getParentScope()->addVariable(var); | |
| } | |
| return true; | |
| } | |
| bool TestbenchElaboration::bindForeachLoop_(ClassDefinition* classDefinition, | |
| Statement* stmt, | |
| ForeachLoopStmt* st) { | |
| NodeId arrayId = st->getArrayId(); | |
| FileContent* sfC = st->getFileContent(); | |
| std::vector<std::string> var_chain; | |
| computeVarChain(sfC, arrayId, var_chain); | |
| Variable* arrayVar = | |
| locateVariable_(var_chain, sfC, arrayId, stmt->getScope(), | |
| classDefinition, ErrorDefinition::ELAB_UNDEF_VARIABLE); | |
| if (arrayVar) { | |
| NodeId range = arrayVar->getRange(); | |
| NodeId rangeTypeId = range; | |
| DataType* itrDataType = NULL; | |
| while (range) { | |
| rangeTypeId = range; | |
| range = sfC->Child(rangeTypeId); | |
| } | |
| VObjectType rangeType = sfC->Type(rangeTypeId); | |
| if (rangeType == VObjectType::slStringConst) { | |
| std::string dataTypeName = sfC->SymName(rangeTypeId); | |
| itrDataType = | |
| bindDataType_(dataTypeName, sfC, rangeTypeId, classDefinition, | |
| ErrorDefinition::COMP_UNDEFINED_TYPE); | |
| } else if (rangeType == VObjectType::slAssociative_dimension || | |
| rangeType == VObjectType::slQueue_dimension) { | |
| // Integer Type | |
| itrDataType = new DataType(sfC, arrayId, "integer", | |
| VObjectType::slIntegerAtomType_Int); | |
| } | |
| for (auto itrId : st->getIteratorIds()) { | |
| Variable* var = | |
| new Variable(itrDataType, sfC, itrId, 0, sfC->SymName(itrId)); | |
| st->getParentScope()->addVariable(var); | |
| } | |
| } | |
| return true; | |
| } | |
| bool TestbenchElaboration::bindFunctionBodies_() { | |
| Compiler* compiler = m_compileDesign->getCompiler(); | |
| ErrorContainer* errors = compiler->getErrorContainer(); | |
| SymbolTable* symbols = compiler->getSymbolTable(); | |
| Design* design = compiler->getDesign(); | |
| ClassNameClassDefinitionMultiMap classes = design->getClassDefinitions(); | |
| // Bind Function return values, parameters and body | |
| for (ClassNameClassDefinitionMultiMap::iterator itr = classes.begin(); | |
| itr != classes.end(); itr++) { | |
| std::string className = (*itr).first; | |
| ClassDefinition* classDefinition = (*itr).second; | |
| for (auto& func : classDefinition->getFunctionMap()) { | |
| // Skip binding of parameterized classes | |
| if (!classDefinition->hasCompleteBaseSpecification()) continue; | |
| std::queue<Statement*> stmts; | |
| for (Statement* stmt : func.second->getStmts()) stmts.push(stmt); | |
| while (stmts.size()) { | |
| Statement* stmt = stmts.front(); | |
| stmts.pop(); | |
| for (Statement* stmt1 : stmt->getStatements()) stmts.push(stmt1); | |
| VObjectType stmt_type = stmt->getType(); | |
| switch (stmt_type) { | |
| case VObjectType::slPs_or_hierarchical_array_identifier: { | |
| // Foreach loop | |
| ForeachLoopStmt* st = dynamic_cast<ForeachLoopStmt*>(stmt); | |
| if (st) { | |
| bindForeachLoop_(classDefinition, stmt, st); | |
| } | |
| break; | |
| } | |
| case VObjectType::slFor_initialization: { | |
| // For loop | |
| ForLoopStmt* st = dynamic_cast<ForLoopStmt*>(stmt); | |
| if (st) { | |
| bindForLoop_(classDefinition, stmt, st); | |
| } | |
| break; | |
| } | |
| case VObjectType::slSubroutine_call_statement: | |
| bindSubRoutineCall_(classDefinition, stmt, design, symbols, errors); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| bool TestbenchElaboration::bindTasks_() { | |
| Compiler* compiler = m_compileDesign->getCompiler(); | |
| // ErrorContainer* errors = compiler->getErrorContainer (); | |
| // SymbolTable* symbols = compiler->getSymbolTable (); | |
| Design* design = compiler->getDesign(); | |
| ClassNameClassDefinitionMultiMap classes = design->getClassDefinitions(); | |
| // Bind Tasks parameters and body | |
| for (ClassNameClassDefinitionMultiMap::iterator itr = classes.begin(); | |
| itr != classes.end(); itr++) { | |
| std::string className = (*itr).first; | |
| ClassDefinition* classDefinition = (*itr).second; | |
| // Bind Tasks parameters | |
| for (auto& func : classDefinition->getTaskMap()) { | |
| for (auto param : func.second->getParams()) { | |
| DataType* dtype = param->getDataType(); | |
| std::string dataTypeName = dtype->getName(); | |
| if (dtype->getDefinition()) continue; | |
| if (dtype->getFileContent() == NULL) continue; | |
| if (dtype->getType() == VObjectType::slStringConst) { | |
| DataType* the_def = bindDataType_( | |
| dataTypeName, dtype->getFileContent(), param->getNodeId(), | |
| classDefinition, ErrorDefinition::COMP_UNDEFINED_TYPE); | |
| if (the_def != dtype) dtype->setDefinition(the_def); | |
| } | |
| } | |
| } | |
| } | |
| return true; | |
| } |