diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index d115cbbd80..4554a830b3 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5014,6 +5014,58 @@ ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build) return v; } +//========================================================================== +// +// FxSequence :: Resolve +// +//========================================================================== + +FxExpression *FxSequence::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + for (unsigned i = 0; i < Expressions.Size(); ++i) + { + if (NULL == (Expressions[i] = Expressions[i]->Resolve(ctx))) + { + delete this; + return nullptr; + } + } + return this; +} + +//========================================================================== +// +// FxSequence :: Emit +// +//========================================================================== + +ExpEmit FxSequence::Emit(VMFunctionBuilder *build) +{ + for (unsigned i = 0; i < Expressions.Size(); ++i) + { + ExpEmit v = Expressions[i]->Emit(build); + // Throw away any result. We don't care about it. + v.Free(build); + } + return ExpEmit(); +} + +//========================================================================== +// +// FxSequence :: GetDirectFunction +// +//========================================================================== + +VMFunction *FxSequence::GetDirectFunction() +{ + if (Expressions.Size() == 1) + { + return Expressions[0]->GetDirectFunction(); + } + return NULL; +} + //========================================================================== // // FxCompoundStatement :: Resolve @@ -5023,18 +5075,11 @@ ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build) FxExpression *FxCompoundStatement::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); + auto outer = ctx.Block; Outer = ctx.Block; ctx.Block = this; - for (unsigned i = 0; i < Expressions.Size(); ++i) - { - if (NULL == (Expressions[i] = Expressions[i]->Resolve(ctx))) - { - ctx.Block = Outer; - delete this; - return nullptr; - } - } - ctx.Block = Outer; + auto x = FxSequence::Resolve(ctx); + ctx.Block = outer; return this; } @@ -5046,33 +5091,13 @@ FxExpression *FxCompoundStatement::Resolve(FCompileContext &ctx) ExpEmit FxCompoundStatement::Emit(VMFunctionBuilder *build) { - for (unsigned i = 0; i < Expressions.Size(); ++i) - { - ExpEmit v = Expressions[i]->Emit(build); - // Throw away any result. We don't care about it. - v.Free(build); - } + auto e = FxSequence::Emit(build); // Release all local variables in this block. for (auto l : LocalVars) { l->Release(build); } - return ExpEmit(); -} - -//========================================================================== -// -// FxCompoundStatement :: GetDirectFunction -// -//========================================================================== - -VMFunction *FxCompoundStatement::GetDirectFunction() -{ - if (Expressions.Size() == 1) - { - return Expressions[0]->GetDirectFunction(); - } - return NULL; + return e; } //========================================================================== diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 75cdadf8d3..eeabf891e1 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -1087,25 +1087,41 @@ public: //========================================================================== // -// FxCompoundStatement +// FxSequence (a list of statements with no semantics attached - used to return multiple nodes as one) // //========================================================================== class FxLocalVariableDeclaration; -class FxCompoundStatement : public FxExpression +class FxSequence : public FxExpression +{ + TDeletingArray Expressions; + +public: + FxSequence(const FScriptPosition &pos) : FxExpression(pos) {} + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); + void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); } + VMFunction *GetDirectFunction(); +}; + +//========================================================================== +// +// FxCompoundStatement (like a list but implements maintenance of local variables) +// +//========================================================================== +class FxLocalVariableDeclaration; + +class FxCompoundStatement : public FxSequence { TArray LocalVars; - TDeletingArray Expressions; FxCompoundStatement *Outer = nullptr; friend class FxLocalVariableDeclaration; public: - FxCompoundStatement(const FScriptPosition &pos) : FxExpression(pos) {} + FxCompoundStatement(const FScriptPosition &pos) : FxSequence(pos) {} FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); - void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); } - VMFunction *GetDirectFunction(); FxLocalVariableDeclaration *FindLocalVariable(FName name); bool CheckLocalVariable(FName name); }; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index e641524afc..33830d1352 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2534,6 +2534,39 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) return new FxConditional(condition, left, right); } + case AST_LocalVarStmt: + { + auto loc = static_cast(ast); + auto node = loc->Vars; + FxSequence *list = new FxSequence(*ast); + do + { + // Type determination must be done for each field to properly handle array definitions. + PType *type = DetermineType(ConvertClass, node, node->Name, loc->Type, true, false); + if (type->IsKindOf(RUNTIME_CLASS(PArray))) + { + Error(loc, "Local array variables not implemented yet."); + } + else + { + FxExpression *val; + if (node->InitIsArray) + { + Error(node, "Tried to initialize %s with an array", FName(node->Name).GetChars()); + val = nullptr; + } + else + { + val = node->Init ? ConvertNode(node->Init) : nullptr; + } + list->Add(new FxLocalVariableDeclaration(type, node->Name, val, *node)); + } + + node = static_cast(node->SiblingNext); + } while (node != loc->Vars); + return list; + } + case AST_ExpressionStmt: return ConvertNode(static_cast(ast)->Expression);