Skip to content

Commit

Permalink
Fix #193 (#208)
Browse files Browse the repository at this point in the history
* Rename arg to param

* Fix #193
  • Loading branch information
marcauberer authored Oct 8, 2022
1 parent 9731222 commit b30cc33
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 117 deletions.
2 changes: 1 addition & 1 deletion media/specs/generics.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ While running the analyzer, Spice will check which concrete manifestations gener
within the code base. It will generate IR for exactly those manifestations.

### Detailed technical description
After a call to `substantiateOptionalArgs()`, the optional arguments are substantiated, but the generic types are not. When `match()` is called,
After a call to `substantiateOptionalParams()`, the optional arguments are substantiated, but the generic types are not. When `match()` is called,
it also checks if the call matches to a generic function. If yes, the generic function is duplicated in the function registry, the
duplicate gets the concrete types by the `match()` method and the new function gets returned to the caller of `match()`. At the end
of the analyzer run, all functions that are not fully substantiated (optional types as well as generic types) get removed from the
Expand Down
29 changes: 22 additions & 7 deletions media/test-project/os-test.spice
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
import "std/data/vector" as vec;
import "std/data/pair" as pair;
const int SIZE = 9;

p print(int[][] grid) {
for int i = 0; i < size; i++ {
for int j = 0; j < size; j++ {
printf("%d ", grid[i][j]);
}
printf("\n");
}
}

f<int> main() {
vec::Vector<pair::Pair<int, string>> pairVector = vec.Vector<pair::Pair<int, string>>();
pairVector.pushBack(pair.Pair<int, string>(0, "Hello"));
pairVector.pushBack(pair.Pair<int, string>(1, "World"));
int[SIZE][SIZE] grid = {
{ 3, 0, 6, 5, 0, 8, 4, 0, 0 },
{ 5, 2, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 8, 7, 0, 0, 0, 0, 3, 1 },
{ 0, 0, 3, 0, 1, 0, 0, 8, 0 },
{ 9, 0, 0, 8, 6, 3, 0, 0, 5 },
{ 0, 5, 0, 0, 9, 0, 6, 0, 0 },
{ 1, 3, 0, 0, 0, 0, 2, 5, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 7, 4 },
{ 0, 0, 5, 2, 0, 6, 3, 0, 0 }
};

pair::Pair<int, string> p1 = pairVector.get(1);
printf("Hello %s!\n", p1.getSecond());
print(grid);
}

/*import "std/net/http" as http;
Expand Down
68 changes: 36 additions & 32 deletions src/analyzer/AnalyzerVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,25 +155,25 @@ std::any AnalyzerVisitor::visitFctDef(FctDefNode *node) {
}
}

// Visit arguments in new scope
std::vector<std::string> argNames;
ArgList argTypes;
// Visit parameters in new scope
std::vector<std::string> paramNames;
ParamList paramTypes;
if (node->hasParams) {
auto namedArgList = any_cast<NamedParamList>(visit(node->paramLst()));
for (const auto &namedArg : namedArgList) {
std::string argName = std::get<0>(namedArg);
SymbolType argType = std::get<1>(namedArg);
bool argOptional = std::get<2>(namedArg);
auto namedParamList = any_cast<NamedParamList>(visit(node->paramLst()));
for (const auto &namedParam : namedParamList) {
const std::string paramName = std::get<0>(namedParam);
const SymbolType paramType = std::get<1>(namedParam);
bool isOptional = std::get<2>(namedParam);

// Check if the type is present in the template for generic types
if (argType.is(TY_GENERIC)) {
if (std::none_of(templateTypes.begin(), templateTypes.end(), [&](const GenericType &t) { return t == argType; }))
if (paramType.is(TY_GENERIC)) {
if (std::none_of(templateTypes.begin(), templateTypes.end(), [&](const GenericType &t) { return t == paramType; }))
throw SemanticError(node->paramLst()->codeLoc, GENERIC_TYPE_NOT_IN_TEMPLATE,
"Generic arg type not included in function template");
}

argNames.push_back(argName);
argTypes.push_back({argType, argOptional});
paramNames.push_back(paramName);
paramTypes.push_back({paramType, isOptional});
}
}

Expand Down Expand Up @@ -211,11 +211,11 @@ std::any AnalyzerVisitor::visitFctDef(FctDefNode *node) {
}

// Insert function into the symbol table
Function spiceFunc(node->functionName, fctSymbolSpecifiers, thisType, returnType, argTypes, templateTypes, node);
Function spiceFunc(node->functionName, fctSymbolSpecifiers, thisType, returnType, paramTypes, templateTypes, node);
currentScope->insertFunction(spiceFunc);

// Rename / duplicate the original child block to reflect the substantiated versions of the function
std::vector<Function> substantiatedFunctions = spiceFunc.substantiateOptionalArgs();
std::vector<Function> substantiatedFunctions = spiceFunc.substantiateOptionalParams();
currentScope->renameChildBlock(node->getScopeId(), substantiatedFunctions.front().getSignature());
for (int i = 1; i < substantiatedFunctions.size(); i++)
currentScope->copyChildBlock(substantiatedFunctions.front().getSignature(), substantiatedFunctions[i].getSignature());
Expand Down Expand Up @@ -280,7 +280,7 @@ std::any AnalyzerVisitor::visitFctDef(FctDefNode *node) {
}

// Morph the generic types to the replacements
std::vector<SymbolType> newArgTypes = spiceFunc.getArgTypes();
std::vector<SymbolType> newArgTypes = spiceFunc.getParamTypes();
for (int i = 0; i < newArgTypes.size(); i++) {
SymbolTableEntry *argEntry = currentScope->lookup(args[i].first);
argEntry->updateType(newArgTypes[i], true);
Expand Down Expand Up @@ -362,25 +362,25 @@ std::any AnalyzerVisitor::visitProcDef(ProcDefNode *node) {
if (node->hasParams && node->procedureName == "dtor")
throw SemanticError(node->codeLoc, DTOR_WITH_PARAMS, "It is not allowed to specify parameters for destructors");

// Visit arguments in new scope
std::vector<std::string> argNames;
ArgList argTypes;
// Visit parameters in new scope
std::vector<std::string> paramNames;
ParamList paramTypes;
if (node->hasParams) {
auto namedArgList = any_cast<NamedParamList>(visit(node->paramLst()));
for (const auto &namedArg : namedArgList) {
std::string argName = std::get<0>(namedArg);
SymbolType argType = std::get<1>(namedArg);
bool argOptional = std::get<2>(namedArg);
auto namedParamList = any_cast<NamedParamList>(visit(node->paramLst()));
for (const auto &namedParam : namedParamList) {
const std::string paramName = std::get<0>(namedParam);
const SymbolType paramType = std::get<1>(namedParam);
bool isOptional = std::get<2>(namedParam);

// Check if the type is present in the template for generic types
if (argType.is(TY_GENERIC)) {
if (std::none_of(templateTypes.begin(), templateTypes.end(), [&](const GenericType &t) { return t == argType; }))
if (paramType.is(TY_GENERIC)) {
if (std::none_of(templateTypes.begin(), templateTypes.end(), [&](const GenericType &t) { return t == paramType; }))
throw SemanticError(node->paramLst()->codeLoc, GENERIC_TYPE_NOT_IN_TEMPLATE,
"Generic arg type not included in procedure template");
}

argNames.push_back(argName);
argTypes.push_back({argType, argOptional});
paramNames.push_back(paramName);
paramTypes.push_back({paramType, isOptional});
}
}

Expand Down Expand Up @@ -409,11 +409,11 @@ std::any AnalyzerVisitor::visitProcDef(ProcDefNode *node) {
}

// Insert function into the symbol table
Function spiceProc(node->procedureName, procSymbolSpecifiers, thisType, SymbolType(TY_DYN), argTypes, templateTypes, node);
Function spiceProc(node->procedureName, procSymbolSpecifiers, thisType, SymbolType(TY_DYN), paramTypes, templateTypes, node);
currentScope->insertFunction(spiceProc);

// Rename / duplicate the original child block to reflect the substantiated versions of the function
std::vector<Function> substantiatedProcedures = spiceProc.substantiateOptionalArgs();
std::vector<Function> substantiatedProcedures = spiceProc.substantiateOptionalParams();
currentScope->renameChildBlock(node->getScopeId(), substantiatedProcedures.front().getSignature());
for (int i = 1; i < substantiatedProcedures.size(); i++)
currentScope->copyChildBlock(substantiatedProcedures.front().getSignature(), substantiatedProcedures[i].getSignature());
Expand Down Expand Up @@ -468,7 +468,7 @@ std::any AnalyzerVisitor::visitProcDef(ProcDefNode *node) {
}

// Morph the generic types to the replacements
std::vector<SymbolType> newArgTypes = spiceProc.getArgTypes();
std::vector<SymbolType> newArgTypes = spiceProc.getParamTypes();
for (int i = 0; i < newArgTypes.size(); i++) {
SymbolTableEntry *argEntry = currentScope->lookup(params[i].first);
argEntry->updateType(newArgTypes[i], true);
Expand Down Expand Up @@ -758,7 +758,7 @@ std::any AnalyzerVisitor::visitExtDecl(ExtDeclNode *node) {
if (runNumber > 1)
return nullptr;

ArgList argTypes;
ParamList argTypes;
if (node->hasArgs) {
// Check if an argument is dyn
for (const auto &arg : node->argTypeLst()->dataTypes()) {
Expand Down Expand Up @@ -1976,7 +1976,7 @@ std::any AnalyzerVisitor::visitFunctionCall(FunctionCallNode *node) {
// Build dummy function to get a better error message
SymbolSpecifiers specifiers = SymbolSpecifiers(SymbolType(TY_FUNCTION));

ArgList errArgTypes;
ParamList errArgTypes;
for (const auto &argType : argTypes)
errArgTypes.emplace_back(argType, false);

Expand Down Expand Up @@ -2180,6 +2180,10 @@ std::any AnalyzerVisitor::visitDataType(DataTypeNode *node) {
if (typeModifier.hardcodedSize <= 1)
throw SemanticError(node->codeLoc, ARRAY_SIZE_INVALID, "The size of an array must be > 1 and explicitly stated");
} else {
// Do not allow dynamic sized types in parameter lists
if (node->isParamType())
throw SemanticError(node->codeLoc, ARRAY_SIZE_INVALID, "Types in parameter lists may not be dynamically sized");

auto sizeType = any_cast<SymbolType>(visit(arraySizeExpr[assignExprCounter++]));
if (!sizeType.isOneOf({TY_INT, TY_LONG, TY_SHORT}))
throw SemanticError(node->codeLoc, ARRAY_SIZE_INVALID, "The array size must be of type int, long or short");
Expand Down
9 changes: 9 additions & 0 deletions src/ast/AstNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,9 @@ class DeclStmtNode : public AstNode {
[[nodiscard]] DataTypeNode *dataType() const { return getChild<DataTypeNode>(); }
[[nodiscard]] AssignExprNode *assignExpr() const { return getChild<AssignExprNode>(); }

// Util methods
[[nodiscard]] bool isParam() const { return dynamic_cast<ParamLstNode *>(parent); }

// Public members
std::string varName;
bool hasAssignment = false;
Expand Down Expand Up @@ -1237,6 +1240,12 @@ class DataTypeNode : public AstNode {
[[nodiscard]] BaseDataTypeNode *baseDataType() const { return getChild<BaseDataTypeNode>(); }
[[nodiscard]] std::vector<AssignExprNode *> arraySizeExpr() const { return getChildren<AssignExprNode>(); }

// Util methods
[[nodiscard]] bool isParamType() const {
auto declStmt = dynamic_cast<DeclStmtNode *>(parent);
return declStmt && declStmt->isParam();
}

// Public members
std::queue<TypeModifier> tmQueue;
};
Expand Down
12 changes: 6 additions & 6 deletions src/generator/GeneratorVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ std::any GeneratorVisitor::visitFctDef(FctDefNode *node) {
// Arguments
unsigned int currentArgIndex = 0;
if (node->hasParams) {
std::vector<SymbolType> argSymbolTypes = spiceFunc.getArgTypes();
std::vector<SymbolType> argSymbolTypes = spiceFunc.getParamTypes();
for (; currentArgIndex < argSymbolTypes.size(); currentArgIndex++) {
currentVarName = node->paramLst()->params()[currentArgIndex]->varName;
argNames.push_back(currentVarName);
Expand Down Expand Up @@ -558,7 +558,7 @@ std::any GeneratorVisitor::visitProcDef(ProcDefNode *node) {
// Arguments
unsigned int currentArgIndex = 0;
if (node->paramLst()) {
std::vector<SymbolType> argSymbolTypes = spiceProc.getArgTypes();
std::vector<SymbolType> argSymbolTypes = spiceProc.getParamTypes();
for (; currentArgIndex < argSymbolTypes.size(); currentArgIndex++) {
currentVarName = node->paramLst()->params()[currentArgIndex]->varName;
argNames.push_back(currentVarName);
Expand Down Expand Up @@ -820,7 +820,7 @@ std::any GeneratorVisitor::visitExtDecl(ExtDeclNode *node) {
argTypes.push_back(argType);
}
}
std::vector<SymbolType> argSymbolTypes = spiceFunc.getArgTypes();
std::vector<SymbolType> argSymbolTypes = spiceFunc.getParamTypes();
symbolTypes.insert(std::end(symbolTypes), std::begin(argSymbolTypes), std::end(argSymbolTypes));

// Declare function
Expand Down Expand Up @@ -2641,7 +2641,7 @@ std::any GeneratorVisitor::visitFunctionCall(FunctionCallNode *node) {

if (!functionFound) { // Not found => Declare function, which will be linked in
SymbolType returnSymbolType = spiceFunc->getReturnType();
std::vector<SymbolType> argSymbolTypes = spiceFunc->getArgTypes();
std::vector<SymbolType> argSymbolTypes = spiceFunc->getParamTypes();

llvm::Type *returnType =
returnSymbolType.is(TY_DYN) ? llvm::Type::getVoidTy(*context) : returnSymbolType.toLLVMType(*context, accessScope);
Expand Down Expand Up @@ -2671,7 +2671,7 @@ std::any GeneratorVisitor::visitFunctionCall(FunctionCallNode *node) {
if (node->argLst()) {
for (const auto &arg : node->argLst()->args()) {
// Get expected arg type
SymbolType expectedArgSymbolType = spiceFunc->getArgTypes()[isMethod ? argIndex - 1 : argIndex];
SymbolType expectedArgSymbolType = spiceFunc->getParamTypes()[isMethod ? argIndex - 1 : argIndex];
llvm::Type *expectedArgType = fctType->getParamType(argIndex);
// Get the actual arg value
SymbolType actualArgSymbolType = arg->getEvaluatedSymbolType();
Expand Down Expand Up @@ -3299,7 +3299,7 @@ void GeneratorVisitor::generateFunctionDebugInfo(llvm::Function *llvmFunction, c
// Create function type
std::vector<llvm::Metadata *> argTypes;
argTypes.push_back(getDITypeForSymbolType(spiceFunc->getReturnType())); // Add result type
for (const auto &argType : spiceFunc->getArgTypes()) // Add arg types
for (const auto &argType : spiceFunc->getParamTypes()) // Add arg types
argTypes.push_back(getDITypeForSymbolType(argType));
llvm::DISubroutineType *functionTy = diBuilder->createSubroutineType(diBuilder->getOrCreateTypeArray(argTypes));

Expand Down
Loading

0 comments on commit b30cc33

Please sign in to comment.