diff --git a/src/dale/Context/Context.cpp b/src/dale/Context/Context.cpp index d87ab2b5..e8d0b813 100644 --- a/src/dale/Context/Context.cpp +++ b/src/dale/Context/Context.cpp @@ -54,42 +54,6 @@ Context::~Context() { deleteNamespaces(namespaces); } Namespace *Context::ns() { return active_ns_nodes.back()->ns; } -bool Context::popUntilNamespace(Namespace *ns) { - assert(ns && "null argument to popUntilNamespace"); - - for (;;) { - if (active_ns_nodes.size() == 0) { - fprintf(stderr, - "Internal error: no active namespaces left.\n"); - abort(); - } - if (active_ns_nodes.back()->ns == ns) { - break; - } - active_ns_nodes.pop_back(); - } - std::vector new_used_nodes; - for (;;) { - if (used_ns_nodes.size() == 0) { - fprintf(stderr, - "Internal error: no used namespaces left.\n"); - abort(); - } - if (used_ns_nodes.back()->ns == ns) { - break; - } - if (used_ns_nodes.back()->ns->name.compare(0, 4, "anon")) { - new_used_nodes.push_back(used_ns_nodes.back()); - } - used_ns_nodes.pop_back(); - } - std::reverse(new_used_nodes.begin(), new_used_nodes.end()); - std::copy(new_used_nodes.begin(), new_used_nodes.end(), - back_inserter(used_ns_nodes)); - - return true; -} - bool Context::activateNamespace(const char *name) { assert(active_ns_nodes.size() && "no active namespace nodes"); @@ -182,6 +146,26 @@ bool Context::deactivateAnonymousNamespace() { return true; } +static int function_scope_count = 0; + +int Context::activateFunctionScope() { + int new_scope = ++function_scope_count; + active_function_scopes.push_back(new_scope); + return new_scope; +} + +void Context::deactivateFunctionScope(int scope) { + assert((active_function_scopes.size() && + active_function_scopes.back() == scope) + && "unmatched function scope"); + active_function_scopes.pop_back(); +} + +int Context::getCurrentFunctionScope() { + if (!active_function_scopes.size()) return -1; + return active_function_scopes.back(); +} + NSNode *getNSNodeFromNode(std::vector *ns_parts, NSNode *current) { for (std::vector::iterator b = ns_parts->begin(), diff --git a/src/dale/Context/Context.h b/src/dale/Context/Context.h index 42a650dc..63318b0c 100644 --- a/src/dale/Context/Context.h +++ b/src/dale/Context/Context.h @@ -50,6 +50,9 @@ class Context { std::vector retrieved_var; /*! Functions that have been retrieved. */ std::vector retrieved_fn; + /*! Active function scopes. It will be an empty vector for global + * variables. */ + std::vector active_function_scopes; public: /*! The native types for the context. Used primarily for type @@ -87,12 +90,6 @@ class Context { /*! Get the currently-active namespace. */ Namespace *ns(); - /*! Pop active namespaces until the given namespace has been - * reached. Does the same thing for used namespaces, save that - * only anonymous namespaces are removed. - * @param ns The namespace that needs to be reached. - */ - bool popUntilNamespace(Namespace *ns); /*! Activate the namespace with the given name. * @param name The name of the namespace. @@ -135,6 +132,25 @@ class Context { */ bool deactivateAnonymousNamespace(); + /*! Activate a function scope. + * + * The function scopes is a set of scopes parallel to namespaces, + * and used to catch invalid variable references to a local + * variable in a different function. + * @return The new function scope. The value is guaranteed to be + * positive. + */ + int activateFunctionScope(); + /*! Deactivate the current function scope. + * @param scope The function scope to deactivate. + */ + void deactivateFunctionScope(int scope); + /*! Get the current active scope. + * @return Returns -1 if currently it's outside of any function + * scope (i.e. the function scope of global variables). + */ + int getCurrentFunctionScope(); + /*! Retrieve a namespace node by name. * @param name The name of the namespace. * @param ignore_last Whether to ignore the last segment of the diff --git a/src/dale/Form/Proc/Def/Def.cpp b/src/dale/Form/Proc/Def/Def.cpp index 784effba..6f5c5b8a 100644 --- a/src/dale/Form/Proc/Def/Def.cpp +++ b/src/dale/Form/Proc/Def/Def.cpp @@ -37,22 +37,10 @@ bool typeRequiresExplicitInit(Context *ctx, Type *type) { llvm::Constant *parseGlobalLiteral(Units *units, Type *type, Node *node) { - Context *ctx = units->top()->ctx; - - std::vector active_ns_nodes = ctx->active_ns_nodes; - std::vector used_ns_nodes = ctx->used_ns_nodes; - if (!units->prefunction_ns) { - units->prefunction_ns = ctx->active_ns_nodes.front()->ns; - } - ctx->popUntilNamespace(units->prefunction_ns); - llvm::Constant *init = NULL; int size; init = FormValueParse(units, type, node, &size); - ctx->active_ns_nodes = active_ns_nodes; - ctx->used_ns_nodes = used_ns_nodes; - return init; } diff --git a/src/dale/Form/Proc/Inst/Inst.cpp b/src/dale/Form/Proc/Inst/Inst.cpp index ded69804..8b94269f 100644 --- a/src/dale/Form/Proc/Inst/Inst.cpp +++ b/src/dale/Form/Proc/Inst/Inst.cpp @@ -31,13 +31,6 @@ bool createAnonymousFunction(Units *units, llvm::BasicBlock *block, Context *ctx = units->top()->ctx; int preindex = ctx->lv_index; - std::vector active_ns_nodes = ctx->active_ns_nodes; - std::vector used_ns_nodes = ctx->used_ns_nodes; - if (!units->prefunction_ns) { - units->prefunction_ns = ctx->active_ns_nodes.front()->ns; - } - ctx->popUntilNamespace(units->prefunction_ns); - int error_count_begin = ctx->er->getErrorTypeCount(ErrorType::Error); @@ -49,8 +42,6 @@ bool createAnonymousFunction(Units *units, llvm::BasicBlock *block, int error_count_end = ctx->er->getErrorTypeCount(ErrorType::Error); if (error_count_begin != error_count_end) { - ctx->active_ns_nodes = active_ns_nodes; - ctx->used_ns_nodes = used_ns_nodes; return false; } @@ -76,9 +67,6 @@ bool createAnonymousFunction(Units *units, llvm::BasicBlock *block, (*b)->index = 0; } - ctx->active_ns_nodes = active_ns_nodes; - ctx->used_ns_nodes = used_ns_nodes; - return true; } diff --git a/src/dale/Form/ProcBody/ProcBody.cpp b/src/dale/Form/ProcBody/ProcBody.cpp index 27d855fc..1aeca79f 100644 --- a/src/dale/Form/ProcBody/ProcBody.cpp +++ b/src/dale/Form/ProcBody/ProcBody.cpp @@ -334,6 +334,7 @@ bool FormProcBodyParse(Units *units, Node *node, Function *fn, llvm::Function *llvm_fn, int skip, bool is_anonymous, llvm::Value *return_value) { Context *ctx = units->top()->ctx; + int fnscope = ctx->activateFunctionScope(); std::vector *lst = node->list; @@ -372,6 +373,7 @@ bool FormProcBodyParse(Units *units, Node *node, Function *fn, bool res = Operation::Copy(units->top()->ctx, fn, (*b), &res_pr, &res_pr); if (!res) { + ctx->deactivateFunctionScope(fnscope); return false; } last_value = res_pr.getValue(ctx); @@ -382,6 +384,7 @@ bool FormProcBodyParse(Units *units, Node *node, Function *fn, bool res = Operation::Destruct(ctx, &res_pr, &destruct_pr); if (!res) { + ctx->deactivateFunctionScope(fnscope); return false; } next = destruct_pr.block; @@ -391,17 +394,20 @@ bool FormProcBodyParse(Units *units, Node *node, Function *fn, bool res = resolveDeferredGotos(ctx, node, fn, block); if (!res) { + ctx->deactivateFunctionScope(fnscope); return false; } res = terminateBlocks(ctx, fn, llvm_fn, last_value, last_type, last_position); if (!res) { + ctx->deactivateFunctionScope(fnscope); return false; } removePostTerminators(llvm_fn); units->top()->popGlobalBlock(); + ctx->deactivateFunctionScope(fnscope); return true; } diff --git a/src/dale/Form/Value/Value.cpp b/src/dale/Form/Value/Value.cpp index 000d26d3..a7ac8066 100644 --- a/src/dale/Form/Value/Value.cpp +++ b/src/dale/Form/Value/Value.cpp @@ -34,13 +34,6 @@ bool parseFunction(Units *units, Type *type, Node *top, Function *fn) { nodes.push_back(top); Node *copy_top = new Node(&nodes); - std::vector active_ns_nodes = ctx->active_ns_nodes; - std::vector used_ns_nodes = ctx->used_ns_nodes; - if (!units->prefunction_ns) { - units->prefunction_ns = ctx->active_ns_nodes.front()->ns; - } - ctx->popUntilNamespace(units->prefunction_ns); - units->top()->pushGlobalFunction(fn); ctx->activateAnonymousNamespace(); std::string anon_name = ctx->ns()->name; @@ -48,9 +41,6 @@ bool parseFunction(Units *units, Type *type, Node *top, Function *fn) { ctx->deactivateNamespace(anon_name.c_str()); units->top()->popGlobalFunction(); - ctx->active_ns_nodes = active_ns_nodes; - ctx->used_ns_nodes = used_ns_nodes; - int error_count_end = ctx->er->getErrorTypeCount(ErrorType::Error); if (error_count_begin != error_count_end) { llvm_fn->replaceAllUsesWith( @@ -134,12 +124,14 @@ llvm::Function *createCopyFunction(Units *units, Type *type, Node *top, llvm::Constant *FormValueParse(Units *units, Type *type, Node *top, int *size) { Context *ctx = units->top()->ctx; + int fnscope = ctx->activateFunctionScope(); /* Try to parse the value as a literal first. */ ParseResult pr; bool res = FormLiteralParse(units, type, top, &pr); if (res) { + ctx->deactivateFunctionScope(fnscope); return llvm::dyn_cast(pr.getValue(ctx)); } @@ -153,10 +145,12 @@ llvm::Constant *FormValueParse(Units *units, Type *type, Node *top, Function *fn = createFunction(units, type, top); fn->cto = true; if (!fn) { + ctx->deactivateFunctionScope(fnscope); return NULL; } res = parseFunction(units, type, top, fn); if (!res) { + ctx->deactivateFunctionScope(fnscope); return NULL; } std::string name; @@ -196,11 +190,13 @@ llvm::Constant *FormValueParse(Units *units, Type *type, Node *top, fn->llvm_function->eraseFromParent(); if (parsed) { + ctx->deactivateFunctionScope(fnscope); return parsed; } int error_count_end = ctx->er->getErrorTypeCount(ErrorType::Error); if (error_count_begin != error_count_end) { + ctx->deactivateFunctionScope(fnscope); return NULL; } @@ -208,6 +204,7 @@ llvm::Constant *FormValueParse(Units *units, Type *type, Node *top, type->toString(&type_str); Error *e = new Error(CannotParseLiteral, top, type_str.c_str()); ctx->er->addError(e); + ctx->deactivateFunctionScope(fnscope); return NULL; } } diff --git a/src/dale/Introspection/Introspection.cpp b/src/dale/Introspection/Introspection.cpp index 9aeb4d93..32814a6b 100644 --- a/src/dale/Introspection/Introspection.cpp +++ b/src/dale/Introspection/Introspection.cpp @@ -869,20 +869,10 @@ bool eval_2D_expression(MContext *mc, DNode *type_form, DNode *form, units->top()->makeTemporaryGlobalFunction(); - std::vector active_ns_nodes = ctx->active_ns_nodes; - std::vector used_ns_nodes = ctx->used_ns_nodes; - if (!units->prefunction_ns) { - units->prefunction_ns = ctx->active_ns_nodes.front()->ns; - } - ctx->popUntilNamespace(units->prefunction_ns); - llvm::Constant *init = NULL; int size; init = FormValueParse(units, type, n, &size); - ctx->active_ns_nodes = active_ns_nodes; - ctx->used_ns_nodes = used_ns_nodes; - units->top()->removeTemporaryGlobalFunction(); int error_count_end = ctx->er->getErrorTypeCount(ErrorType::Error); diff --git a/src/dale/Variable/Variable.h b/src/dale/Variable/Variable.h index ee22959b..ed07802f 100644 --- a/src/dale/Variable/Variable.h +++ b/src/dale/Variable/Variable.h @@ -42,6 +42,8 @@ class Variable { int linkage; /*! Whether the variable should be serialised. */ bool serialise; + /*! The function scope the variable is in */ + int fnscope; Variable(); /*! Construct a new variable with the given name and type.