added: parameter access validation
This commit is contained in:
parent
372c14c575
commit
88e1f061d8
|
@ -387,6 +387,49 @@ BackendError impl_variable_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *sc
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
BackendError impl_parameter_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
|
||||
LLVMBuilderRef builder, Parameter *parameter,
|
||||
LLVMBool reference,
|
||||
LLVMValueRef *llvm_result) {
|
||||
|
||||
LLVMValueRef llvm_variable = NULL;
|
||||
if (g_hash_table_contains(scope->func_scope->params, parameter->name)) {
|
||||
llvm_variable = g_hash_table_lookup(scope->func_scope->params, parameter->name);
|
||||
}
|
||||
|
||||
Type* type;
|
||||
|
||||
ParameterDeclaration decl;
|
||||
|
||||
if (parameter->kind == ParameterDeclarationKind) {
|
||||
decl = parameter->impl.definiton.declaration;
|
||||
} else {
|
||||
decl = parameter->impl.declaration;
|
||||
}
|
||||
type = decl.type;
|
||||
|
||||
if (llvm_variable == NULL) {
|
||||
return new_backend_impl_error(Implementation, NULL, "Variable not found");
|
||||
}
|
||||
|
||||
if (decl.qualifier == In) {
|
||||
*llvm_result = llvm_variable;
|
||||
} else {
|
||||
// no referencing, load value
|
||||
LLVMTypeRef llvm_type;
|
||||
|
||||
get_type_impl(unit, scope->func_scope->global_scope, type, &llvm_type);
|
||||
|
||||
if (LLVMGetTypeKind(LLVMTypeOf(llvm_variable)) == LLVMPointerTypeKind) {
|
||||
*llvm_result = LLVMBuildLoad2(builder, llvm_type, llvm_variable, "");
|
||||
} else {
|
||||
*llvm_result = llvm_variable;
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
BackendError impl_address_of(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
|
||||
LLVMBuilderRef builder, AddressOf* addressOf,
|
||||
LLVMValueRef *llvm_result) {
|
||||
|
@ -405,7 +448,12 @@ BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
|
|||
LLVMValueRef *llvm_result) {
|
||||
BackendError err;
|
||||
|
||||
LLVMValueRef llvm_pointer = get_variable(scope, dereference->variable->impl.variable->name);
|
||||
LLVMValueRef llvm_pointer = NULL;
|
||||
err = impl_expr(unit, scope, builder, dereference->variable, TRUE, &llvm_pointer);
|
||||
if (err.kind != Success) {
|
||||
return err;
|
||||
}
|
||||
|
||||
LLVMTypeRef llvm_deref_type = NULL;
|
||||
err = get_type_impl(unit, scope->func_scope->global_scope, dereference->variable->result->impl.reference, &llvm_deref_type);
|
||||
if (err.kind != Success) {
|
||||
|
@ -454,6 +502,11 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
|
|||
reference,
|
||||
llvm_result);
|
||||
break;
|
||||
case ExpressionKindParameter:
|
||||
err = impl_parameter_load(unit, scope, builder, expr->impl.parameter,
|
||||
reference,
|
||||
llvm_result);
|
||||
break;
|
||||
case ExpressionKindAddressOf:
|
||||
err = impl_address_of(unit, scope, builder, &expr->impl.addressOf,
|
||||
llvm_result);
|
||||
|
|
|
@ -26,7 +26,7 @@ void delete_local_scope(LLVMLocalScope* scope) {
|
|||
free(scope);
|
||||
}
|
||||
|
||||
static LLVMValueRef get_parameter(const LLVMFuncScope* scope,
|
||||
LLVMValueRef get_parameter(const LLVMFuncScope* scope,
|
||||
const char* name) {
|
||||
if (g_hash_table_contains(scope->params, name)) {
|
||||
return g_hash_table_lookup(scope->params, name);
|
||||
|
@ -44,11 +44,6 @@ LLVMValueRef get_variable(const LLVMLocalScope* scope, const char* name) {
|
|||
return get_variable(scope->parent_scope, name);
|
||||
}
|
||||
|
||||
LLVMValueRef param = get_parameter(scope->func_scope, name);
|
||||
if (param != NULL) {
|
||||
return param;
|
||||
}
|
||||
|
||||
LLVMValueRef global_var = get_global_variable(scope->func_scope->global_scope, (char*) name);
|
||||
return global_var;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ void delete_local_scope(LLVMLocalScope*);
|
|||
|
||||
LLVMValueRef get_variable(const LLVMLocalScope* scope, const char* name);
|
||||
|
||||
LLVMValueRef get_parameter(const LLVMFuncScope* scope, const char* name);
|
||||
|
||||
LLVMBool is_parameter(const LLVMLocalScope* scope, const char* name);
|
||||
|
||||
BackendError impl_function_types(LLVMBackendCompileUnit* unit,
|
||||
|
|
|
@ -27,6 +27,10 @@ BackendError impl_storage_expr(
|
|||
*storage_target =
|
||||
get_variable(scope, expr->impl.variable->name);
|
||||
break;
|
||||
case StorageExprKindParameter:
|
||||
*storage_target =
|
||||
get_parameter(scope->func_scope, expr->impl.parameter->name);
|
||||
break;
|
||||
case StorageExprKindDereference:
|
||||
|
||||
LLVMValueRef index = NULL;
|
||||
|
|
119
src/set/set.c
119
src/set/set.c
|
@ -541,6 +541,18 @@ char* type_to_string(Type* type) {
|
|||
return string;
|
||||
}
|
||||
|
||||
int getParameter(const char *name, Parameter **parameter) {
|
||||
// loop through all variable scope and find a variable
|
||||
if (functionParameter != NULL) {
|
||||
if (g_hash_table_contains(functionParameter, name)) {
|
||||
*parameter = g_hash_table_lookup(functionParameter, name);
|
||||
return SEMANTIC_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
||||
int getVariableFromScope(const char *name, Variable **variable) {
|
||||
assert(name != NULL);
|
||||
assert(variable != NULL);
|
||||
|
@ -548,13 +560,6 @@ int getVariableFromScope(const char *name, Variable **variable) {
|
|||
DEBUG("getting var from scope");
|
||||
int found = 0;
|
||||
|
||||
// loop through all variable scope and find a variable
|
||||
if (functionParameter != NULL) {
|
||||
if (g_hash_table_contains(functionParameter, name)) {
|
||||
*variable = g_hash_table_lookup(functionParameter, name);
|
||||
found += 1;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < Scope->len; i++) {
|
||||
|
||||
GHashTable *variable_table = g_array_index(Scope, GHashTable*, i);
|
||||
|
@ -1435,6 +1440,14 @@ int createAddressOf(Expression *ParentExpression, AST_NODE_PTR currentNode) {
|
|||
return SEMANTIC_OK;
|
||||
}
|
||||
|
||||
IO_Qualifier getParameterQualifier(Parameter* parameter) {
|
||||
if (parameter->kind == ParameterDeclarationKind) {
|
||||
return parameter->impl.declaration.qualifier;
|
||||
} else {
|
||||
return parameter->impl.definiton.declaration.qualifier;
|
||||
}
|
||||
}
|
||||
|
||||
Expression *createExpression(AST_NODE_PTR currentNode) {
|
||||
DEBUG("create Expression");
|
||||
Expression *expression = mem_alloc(MemoryNamespaceSet, sizeof(Expression));
|
||||
|
@ -1455,23 +1468,32 @@ Expression *createExpression(AST_NODE_PTR currentNode) {
|
|||
case AST_Ident:
|
||||
DEBUG("find var");
|
||||
expression->kind = ExpressionKindVariable;
|
||||
int status = getVariableFromScope(currentNode->value, &(expression->impl.variable));
|
||||
int status = getVariableFromScope(currentNode->value, &expression->impl.variable);
|
||||
if (status == SEMANTIC_ERROR) {
|
||||
expression->kind = ExpressionKindParameter;
|
||||
status = getParameter(currentNode->value, &expression->impl.parameter);
|
||||
if (status == SEMANTIC_ERROR) {
|
||||
DEBUG("Identifier is not in current scope");
|
||||
print_diagnostic(¤tNode->location, Error, "Variable not found");
|
||||
print_diagnostic(¤tNode->location, Error, "Unknown identifier: `%s`", currentNode->value);
|
||||
return NULL;
|
||||
}
|
||||
switch (expression->impl.variable->kind) {
|
||||
case VariableKindDeclaration:
|
||||
|
||||
if (getParameterQualifier(expression->impl.parameter) == Out) {
|
||||
print_diagnostic(¤tNode->location, Error, "Parameter is write-only: `%s`", currentNode->value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (expression->impl.parameter->kind == VariableKindDeclaration) {
|
||||
expression->result = expression->impl.parameter->impl.declaration.type;
|
||||
} else {
|
||||
expression->result = expression->impl.parameter->impl.definiton.declaration.type;
|
||||
}
|
||||
} else {
|
||||
if (expression->impl.variable->kind == VariableKindDeclaration) {
|
||||
expression->result = expression->impl.variable->impl.declaration.type;
|
||||
DEBUG("%d", expression->impl.variable->impl.declaration.type->kind);
|
||||
break;
|
||||
case VariableKindDefinition:
|
||||
} else {
|
||||
expression->result = expression->impl.variable->impl.definiton.declaration.type;
|
||||
break;
|
||||
default:
|
||||
PANIC("current Variable should not be an BoxMember");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AST_Add:
|
||||
|
@ -1611,15 +1633,33 @@ Type* getVariableType(Variable* variable) {
|
|||
}
|
||||
}
|
||||
|
||||
Type* getParameterType(Parameter* parameter) {
|
||||
if (parameter->kind == ParameterDeclarationKind) {
|
||||
return parameter->impl.declaration.type;
|
||||
} else {
|
||||
return parameter->impl.definiton.declaration.type;
|
||||
}
|
||||
}
|
||||
|
||||
int createStorageExpr(StorageExpr* expr, AST_NODE_PTR node) {
|
||||
switch (node->kind) {
|
||||
case AST_Ident:
|
||||
expr->kind = StorageExprKindVariable;
|
||||
int status = getVariableFromScope(node->value, &expr->impl.variable);
|
||||
if (status == SEMANTIC_ERROR) {
|
||||
|
||||
expr->kind = StorageExprKindParameter;
|
||||
status = getParameter(node->value, &expr->impl.parameter);
|
||||
if (status == SEMANTIC_ERROR) {
|
||||
print_diagnostic(&node->location, Error, "Unknown token: `%s`", node->value);
|
||||
return SEMANTIC_ERROR;
|
||||
} else {
|
||||
expr->target_type = getParameterType(expr->impl.parameter);
|
||||
}
|
||||
|
||||
} else {
|
||||
expr->target_type = getVariableType(expr->impl.variable);
|
||||
}
|
||||
break;
|
||||
case AST_Dereference:
|
||||
expr->kind = StorageExprKindDereference;
|
||||
|
@ -1656,11 +1696,19 @@ int createAssign(Statement *ParentStatement, AST_NODE_PTR currentNode) {
|
|||
assign.nodePtr = currentNode;
|
||||
assign.destination = mem_alloc(MemoryNamespaceSet, sizeof(StorageExpr));
|
||||
|
||||
int status = createStorageExpr(assign.destination, AST_get_node(currentNode, 0));
|
||||
AST_NODE_PTR strg_expr = AST_get_node(currentNode, 0);
|
||||
int status = createStorageExpr(assign.destination, strg_expr);
|
||||
if (status == SEMANTIC_ERROR) {
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
||||
if (strg_expr->kind == StorageExprKindParameter) {
|
||||
if (getParameterQualifier(assign.destination->impl.parameter) == In) {
|
||||
print_diagnostic(¤tNode->location, Error, "Parameter is read-only: `%s`", assign.destination->impl.parameter->name);
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
assign.value = createExpression(AST_get_node(currentNode, 1));
|
||||
if (assign.value == NULL) {
|
||||
return SEMANTIC_ERROR;
|
||||
|
@ -1682,7 +1730,8 @@ int fillBlock(Block *block, AST_NODE_PTR currentNode) {
|
|||
g_array_append_val(Scope, lowerScope);
|
||||
|
||||
for (size_t i = 0; i < currentNode->children->len; i++) {
|
||||
int signal = createStatement(block, AST_get_node(currentNode, i));
|
||||
AST_NODE_PTR stmt_node = AST_get_node(currentNode, i);
|
||||
int signal = createStatement(block, stmt_node);
|
||||
if (signal) {
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
@ -2003,30 +2052,20 @@ int createParam(GArray *Paramlist, AST_NODE_PTR currentNode) {
|
|||
if (set_get_type_impl(AST_get_node(paramdecl, 0), &(decl.type))) {
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
Parameter param;
|
||||
param.nodePtr = currentNode;
|
||||
param.kind = ParameterDeclarationKind;
|
||||
param.impl.declaration = decl;
|
||||
param.name = AST_get_node(paramdecl, 1)->value;
|
||||
Parameter* param = mem_alloc(MemoryNamespaceSet, sizeof(Parameter));
|
||||
param->nodePtr = currentNode;
|
||||
param->kind = ParameterDeclarationKind;
|
||||
param->impl.declaration = decl;
|
||||
param->name = AST_get_node(paramdecl, 1)->value;
|
||||
|
||||
DEBUG("param name: %s", param.name);
|
||||
g_array_append_val(Paramlist, param);
|
||||
DEBUG("param name: %s", param->name);
|
||||
g_array_append_val(Paramlist, *param);
|
||||
|
||||
DEBUG("create var for param");
|
||||
|
||||
Variable *paramvar = mem_alloc(MemoryNamespaceSet, sizeof(Variable));
|
||||
paramvar->kind = VariableKindDeclaration;
|
||||
paramvar->name = param.name;
|
||||
paramvar->nodePtr = currentNode;
|
||||
paramvar->impl.declaration.nodePtr = currentNode;
|
||||
paramvar->impl.declaration.qualifier = Local;
|
||||
paramvar->impl.declaration.type = param.impl.declaration.type;
|
||||
|
||||
if (g_hash_table_contains(functionParameter, param.name)) {
|
||||
print_diagnostic(¶m.nodePtr->location, Error, "Names of function parameters must be unique: %s", param.name);
|
||||
if (g_hash_table_contains(functionParameter, param->name)) {
|
||||
print_diagnostic(¶m->nodePtr->location, Error, "Names of function parameters must be unique: %s", param->name);
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
g_hash_table_insert(functionParameter, (gpointer) param.name, paramvar);
|
||||
g_hash_table_insert(functionParameter, (gpointer) param->name, param);
|
||||
|
||||
DEBUG("created param successfully");
|
||||
return SEMANTIC_OK;
|
||||
|
|
|
@ -432,6 +432,7 @@ typedef enum ExpressionKind_t {
|
|||
ExpressionKindTransmute,
|
||||
ExpressionKindConstant,
|
||||
ExpressionKindVariable,
|
||||
ExpressionKindParameter,
|
||||
ExpressionKindDereference,
|
||||
ExpressionKindAddressOf,
|
||||
} ExpressionKind;
|
||||
|
@ -446,6 +447,7 @@ typedef struct Expression_t {
|
|||
Transmute transmute;
|
||||
TypeValue constant;
|
||||
Variable* variable;
|
||||
Parameter* parameter;
|
||||
Dereference dereference;
|
||||
AddressOf addressOf;
|
||||
} impl;
|
||||
|
@ -526,6 +528,7 @@ typedef struct Branch_t {
|
|||
|
||||
typedef enum StorageExprKind_t {
|
||||
StorageExprKindVariable,
|
||||
StorageExprKindParameter,
|
||||
StorageExprKindBoxAccess,
|
||||
StorageExprKindDereference,
|
||||
} StorageExprKind;
|
||||
|
@ -535,6 +538,7 @@ typedef struct StorageExpr_t {
|
|||
Type* target_type;
|
||||
union StorageExprImpl {
|
||||
Variable* variable;
|
||||
Parameter* parameter;
|
||||
BoxAccess boxAccess;
|
||||
StorageDereference dereference;
|
||||
} impl;
|
||||
|
|
Loading…
Reference in New Issue