From 57de598e4824d53a29acb69e706f559bcb3f420a Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 2 Nov 2017 15:51:13 +0200 Subject: [PATCH] Added implicit scope for if/else, while and do/while statements in ZScript Scope is added only for variable or constant definition so it will no longer leak to outer scope https://forum.zdoom.org/viewtopic.php?t=57848 --- src/scripting/zscript/zcc_compile.cpp | 49 +++++++++++++++++++++++++-- src/scripting/zscript/zcc_compile.h | 1 + 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 71f8e6d35c..5971806058 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -3495,7 +3495,9 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) case AST_IfStmt: { auto iff = static_cast(ast); - return new FxIfStatement(ConvertNode(iff->Condition), ConvertNode(iff->TruePath), ConvertNode(iff->FalsePath), *ast); + FxExpression *const truePath = ConvertImplicitScopeNode(ast, iff->TruePath); + FxExpression *const falsePath = ConvertImplicitScopeNode(ast, iff->FalsePath); + return new FxIfStatement(ConvertNode(iff->Condition), truePath, falsePath, *ast); } case AST_IterationStmt: @@ -3504,7 +3506,8 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) if (iter->CheckAt == ZCC_IterationStmt::End) { assert(iter->LoopBumper == nullptr); - return new FxDoWhileLoop(ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopStatement), *ast); + FxExpression *const loop = ConvertImplicitScopeNode(ast, iter->LoopStatement); + return new FxDoWhileLoop(ConvertNode(iter->LoopCondition), loop, *ast); } else if (iter->LoopBumper != nullptr) { @@ -3520,7 +3523,8 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) } else { - return new FxWhileLoop(ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopStatement), *ast); + FxExpression *const loop = ConvertImplicitScopeNode(ast, iter->LoopStatement); + return new FxWhileLoop(ConvertNode(iter->LoopCondition), loop, *ast); } } @@ -3584,6 +3588,45 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) return nullptr; } +//========================================================================== +// +// Wrapper around ConvertNode() that adds a scope (a compound statement) +// when needed to avoid leaking of variable or contant to an outer scope: +// +// if (true) int i; else bool b[1]; +// while (false) readonly a; +// do static const float f[] = {0}; while (false); +// +// Accessing such variables outside of their statements is now an error +// +//========================================================================== + +FxExpression *ZCCCompiler::ConvertImplicitScopeNode(ZCC_TreeNode *node, ZCC_Statement *nested) +{ + assert(nullptr != node); + + if (nullptr == nested) + { + return nullptr; + } + + FxExpression *nestedExpr = ConvertNode(nested); + assert(nullptr != nestedExpr); + + const EZCCTreeNodeType nestedType = nested->NodeType; + const bool needScope = AST_LocalVarStmt == nestedType || AST_StaticArrayStatement == nestedType; + + if (needScope) + { + FxCompoundStatement *implicitCompound = new FxCompoundStatement(*node); + implicitCompound->Add(nestedExpr); + + nestedExpr = implicitCompound; + } + + return nestedExpr; +} + FArgumentList &ZCCCompiler::ConvertNodeList(FArgumentList &args, ZCC_TreeNode *head) { diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index baa5c89f63..9a4a0af8b2 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -145,6 +145,7 @@ private: FxExpression *ConvertAST(PContainerType *cclass, ZCC_TreeNode *ast); FxExpression *ConvertNode(ZCC_TreeNode *node); + FxExpression *ConvertImplicitScopeNode(ZCC_TreeNode *node, ZCC_Statement *nested); FArgumentList &ConvertNodeList(FArgumentList &, ZCC_TreeNode *head); DObject *Outer;