[WIP] Make statement lists have a scope

Note that this doesn't actually properly execute shadowing, it simply
makes it not error. And introduces a bunch of other problems.

The reason this doesn't shadow variables is that locals are created at
parse time (hence why a scope is needed in both `Stmt.cc` and `parse.y`
for the statement lists), but locals are used at execution time
(obviously). This means that executing the local will just grab the
outer scope one every time - the inner scope one goes to die.

So the next step *could* be to move locals to getting created at
execution time, which seems like it's what should happen. But that may
be a lot of work.

Optionally, we can alse just add a scope counter and "append" that in
some way to the variable's name. That seems pretty easy.

Not that shadowing is that important to do anyway, I just wanted to try.
This commit is contained in:
Evan Typanski 2024-09-20 15:37:06 -04:00
parent b22ec06568
commit 5d6674f05f
7 changed files with 44 additions and 31 deletions

View file

@ -4321,7 +4321,7 @@ void LambdaExpr::BuildName() {
my_name = "lambda_<" + std::to_string(h[0]) + ">";
auto fullname = make_full_var_name(current_module.data(), my_name.data());
const auto& id = current_scope()->Find(fullname);
const auto& id = current_function_scope()->Find(fullname);
if ( id )
// Just try again to make a unique lambda name.

View file

@ -90,7 +90,7 @@ TraversalCode Scope::Traverse(TraversalCallback* cb) const {
}
const IDPtr& lookup_ID(const char* name, const char* curr_module, bool no_global, bool same_module_only,
bool check_export) {
bool check_export, bool same_scope_only) {
bool explicit_global = zeek::util::starts_with(name, "::");
static std::string global_prefix = util::fmt("%s::", GLOBAL_MODULE_NAME);
@ -123,6 +123,9 @@ const IDPtr& lookup_ID(const char* name, const char* curr_module, bool no_global
return id;
}
if ( same_scope_only )
break;
}
}
@ -170,20 +173,39 @@ void push_scope(IDPtr id, std::unique_ptr<std::vector<AttrPtr>> attrs) {
scopes.push_back(top_scope);
}
void pop_local_scope() {
scopes.pop_back();
top_scope = scopes.empty() ? nullptr : scopes.back();
}
ScopePtr pop_scope() {
if ( scopes.empty() )
reporter->InternalError("scope underflow");
while ( scopes.back()->GetID() == nullptr )
scopes.pop_back();
auto old_top = top_scope;
auto old_top = scopes.back();
top_scope = scopes.empty() ? nullptr : scopes.back();
scopes.pop_back();
top_scope = scopes.back();
return old_top;
}
ScopePtr current_scope() { return top_scope; }
ScopePtr current_function_scope() {
for ( auto s_i = scopes.rbegin(); s_i != scopes.rend(); ++s_i ) {
if ( (*s_i)->GetID() != nullptr ) {
return *s_i;
}
}
return top_scope;
}
ScopePtr global_scope() { return scopes.empty() ? 0 : scopes.front(); }
} // namespace zeek::detail

View file

@ -81,7 +81,7 @@ protected:
// If no_global is true, don't search in the default "global" namespace.
extern const IDPtr& lookup_ID(const char* name, const char* module, bool no_global = false,
bool same_module_only = false, bool check_export = true);
bool same_module_only = false, bool check_export = true, bool same_scope_only = false);
extern IDPtr install_ID(const char* name, const char* module_name, bool is_global, bool is_export);
@ -91,7 +91,10 @@ extern void push_existing_scope(ScopePtr scope);
// Returns the one popped off.
extern ScopePtr pop_scope();
extern void pop_local_scope();
extern ScopePtr current_scope();
extern ScopePtr current_function_scope();
extern ScopePtr global_scope();
// Current module (identified by its name).

View file

@ -1355,9 +1355,9 @@ TraversalCode FallthroughStmt::Traverse(TraversalCallback* cb) const {
}
ReturnStmt::ReturnStmt(ExprPtr arg_e) : ExprStmt(STMT_RETURN, std::move(arg_e)) {
auto s = current_scope();
auto s = current_function_scope();
if ( ! s || ! s->GetID() ) {
if ( ! s ) {
Error("return statement outside of function/event");
return;
}
@ -1419,6 +1419,7 @@ void ReturnStmt::StmtDescribe(ODesc* d) const {
StmtList::StmtList() : Stmt(STMT_LIST) {}
ValPtr StmtList::Exec(Frame* f, StmtFlowType& flow) {
push_scope(nullptr, nullptr);
RegisterAccess();
flow = FLOW_NEXT;
@ -1439,6 +1440,7 @@ ValPtr StmtList::Exec(Frame* f, StmtFlowType& flow) {
return result;
}
pop_local_scope();
return nullptr;
}
@ -1729,7 +1731,7 @@ WhenInfo::WhenInfo(ExprPtr arg_cond, FuncType::CaptureList* arg_cl, bool arg_is_
lambda_ft->SetCaptures(*cl);
auto id = current_scope()->GenerateTemporary("when-internal");
auto id = current_function_scope()->GenerateTemporary("when-internal");
id->SetType(lambda_ft);
push_scope(std::move(id), nullptr);
@ -1848,7 +1850,7 @@ void WhenInfo::Build(StmtPtr ws) {
auto shebang = make_intrusive<StmtList>(do_test, do_bodies, dummy_return);
auto ingredients = std::make_shared<FunctionIngredients>(current_scope(), shebang, current_module);
auto ingredients = std::make_shared<FunctionIngredients>(current_function_scope(), shebang, current_module);
auto outer_ids = gather_outer_ids(pop_scope(), ingredients->Body());
lambda = make_intrusive<LambdaExpr>(std::move(ingredients), std::move(outer_ids), "", ws);

View file

@ -644,8 +644,8 @@ void begin_func(IDPtr id, const char* module_name, FunctionFlavor flavor, bool i
if ( ! check_params(i, prototype, args, canon_args, module_name) )
break;
if ( Attr* depr_attr = find_attr(current_scope()->Attrs().get(), ATTR_DEPRECATED) )
current_scope()->GetID()->MakeDeprecated(depr_attr->GetExpr());
if ( Attr* depr_attr = find_attr(current_function_scope()->Attrs().get(), ATTR_DEPRECATED) )
current_function_scope()->GetID()->MakeDeprecated(depr_attr->GetExpr());
// Reset the AST node statistics to track afresh for this function.
Stmt::ResetNumStmts();

View file

@ -154,9 +154,6 @@ bool defining_global_ID = false;
std::vector<int> saved_in_init;
static int expr_list_has_opt_comma = 0;
std::vector<std::set<const ID*>> locals_at_this_scope;
static std::unordered_set<const ID*> out_of_scope_locals;
static Location func_hdr_location;
static int func_hdr_cond_epoch = 0;
EnumType* cur_enum_type = nullptr;
@ -772,8 +769,6 @@ expr:
| TOK_WHEN_LOCAL local_id '=' rhs
{
set_location(@2, @4);
if ( ! locals_at_this_scope.empty() )
locals_at_this_scope.back().insert($2);
$$ = add_and_assign_local({AdoptRef{}, $2}, {AdoptRef{}, $4},
val_mgr->True()).release();
}
@ -1012,9 +1007,6 @@ expr:
}
else
{
if ( out_of_scope_locals.count(id.get()) > 0 )
id->Error("use of out-of-scope local; move declaration to outer scope");
$$ = new NameExpr(std::move(id));
}
}
@ -1545,9 +1537,6 @@ func_body:
{
saved_in_init.push_back(in_init);
in_init = 0;
locals_at_this_scope.clear();
out_of_scope_locals.clear();
}
stmt_list
@ -1832,19 +1821,18 @@ attr:
stmt:
'{'
{
push_scope(nullptr, nullptr);
std::set<const ID*> id_set;
locals_at_this_scope.emplace_back(id_set);
}
opt_no_test_block stmt_list '}'
{
auto& scope_locals = locals_at_this_scope.back();
out_of_scope_locals.insert(scope_locals.begin(), scope_locals.end());
locals_at_this_scope.pop_back();
set_location(@1, @5);
$$ = $4;
if ( $3 )
script_coverage_mgr.DecIgnoreDepth();
pop_local_scope();
}
| TOK_ASSERT expr opt_assert_msg ';'
@ -1949,8 +1937,6 @@ stmt:
| TOK_LOCAL local_id opt_type init_class opt_init opt_attr ';' opt_no_test
{
set_location(@1, @7);
if ( ! locals_at_this_scope.empty() )
locals_at_this_scope.back().insert($2);
$$ = build_local($2, $3, $4, $5, $6, VAR_REGULAR, ! $8).release();
}
@ -2174,7 +2160,7 @@ local_id:
TOK_ID
{
set_location(@1);
auto id = lookup_ID($1, current_module.c_str());
auto id = lookup_ID($1, current_module.c_str(), false, false, true, true);
$$ = id.release();
if ( $$ )

View file

@ -406,7 +406,7 @@ static void terminate_zeek() {
#endif
// free the global scope
pop_scope();
pop_local_scope();
reporter = nullptr;
}