From 59ab8b7ccdc86291d4ec17963798f533667c1d7b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 16 Oct 2016 10:59:12 +0200 Subject: [PATCH] - implemented array-style syntax for Random calls. - implemented handling of the basic math operators so that heretic/beast.txt can be processed. This is working, aside from still needing the type casts to properly transform the strings to class pointers. --- src/scripting/codegeneration/codegen.cpp | 10 +-- .../codegeneration/functioncalls.cpp | 8 -- src/scripting/zscript/zcc_compile.cpp | 81 ++++++++++++++++--- 3 files changed, 73 insertions(+), 26 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 7eaecb82d..91153f3ac 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -3796,15 +3796,15 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) if (CheckArgSize(MethodName, ArgList, 1, -1, ScriptPosition)) { func = new FxRandomPick(RNG, *ArgList, MethodName == NAME_FRandomPick, ScriptPosition, ctx.FromDecorate); - for (auto &i : *ArgList) i = nullptr; // Ownership of items is transferred to FxMinMax but not ownership of the array itself, so Clear cannot be called here. + for (auto &i : *ArgList) i = nullptr; } break; case NAME_Random2: - if (CheckArgSize(NAME_Random2, ArgList, 1, 1, ScriptPosition)) + if (CheckArgSize(NAME_Random2, ArgList, 0, 1, ScriptPosition)) { - func = new FxRandom2(RNG, (*ArgList)[0], ScriptPosition, ctx.FromDecorate); - (*ArgList)[0] = nullptr; + func = new FxRandom2(RNG, ArgList->Size() == 0? nullptr : (*ArgList)[0], ScriptPosition, ctx.FromDecorate); + if (ArgList->Size() > 0) (*ArgList)[0] = nullptr; } break; @@ -3813,7 +3813,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) if (CheckArgSize(MethodName, ArgList, 2, -1, ScriptPosition)) { func = new FxMinMax(*ArgList, MethodName, ScriptPosition); - for (auto &i : *ArgList) i = nullptr; // Ownership of items is transferred to FxMinMax but not ownership of the array itself, so Clear cannot be called here. + for (auto &i : *ArgList) i = nullptr; } break; diff --git a/src/scripting/codegeneration/functioncalls.cpp b/src/scripting/codegeneration/functioncalls.cpp index 1c8dfb3f5..ca2b437e7 100644 --- a/src/scripting/codegeneration/functioncalls.cpp +++ b/src/scripting/codegeneration/functioncalls.cpp @@ -48,10 +48,6 @@ FxExpression *ConvertFunctionCall(ZCC_Expression *function, FArgumentList *args, PClass *cls, FScriptPosition &sc) { - // function names can either be - // - plain identifiers - // - class members - // - array syntax for random() calls. switch(function->NodeType) { @@ -63,10 +59,6 @@ FxExpression *ConvertFunctionCall(ZCC_Expression *function, FArgumentList *args, case AST_ExprBinary: // Array access syntax is wrapped into a ZCC_ExprBinary object. - if (fcall->Function->Operation == PEX_ArrayAccess) - { - return ConvertArrayFunctionCall(fcall); - } break; default: diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index e184ccaa1..b2f22555f 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2300,10 +2300,40 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) case AST_ExprFuncCall: { auto fcall = static_cast(ast); - assert(fcall->Function->NodeType == AST_ExprID); // of course this cannot remain. Right now nothing more complex can come along but later this will have to be decomposed into 'self' and the actual function name. - auto fname = static_cast(fcall->Function)->Identifier; - return new FxFunctionCall(fname, NAME_None, ConvertNodeList(fcall->Parameters), *ast); - //return ConvertFunctionCall(fcall->Function, ConvertNodeList(fcall->Parameters), ConvertClass, *ast); + + // function names can either be + // - plain identifiers + // - class members + // - array syntax for random() calls. + // Everything else coming here is a syntax error. + switch (fcall->Function->NodeType) + { + case AST_ExprID: + // The function name is a simple identifier. + return new FxFunctionCall(static_cast(fcall->Function)->Identifier, NAME_None, ConvertNodeList(fcall->Parameters), *ast); + + case AST_ExprMemberAccess: + // calling a class member through its pointer + // todo. + break; + + case AST_ExprBinary: + // Array syntax for randoms. They are internally stored as ExprBinary with both an identifier on the left and right side. + if (fcall->Function->Operation == PEX_ArrayAccess) + { + auto binary = static_cast(fcall->Function); + if (binary->Left->NodeType == AST_ExprID && binary->Right->NodeType == AST_ExprID) + { + return new FxFunctionCall(static_cast(binary->Left)->Identifier, static_cast(binary->Right)->Identifier, ConvertNodeList(fcall->Parameters), *ast); + } + } + // fall through if this isn't an array access node. + + default: + Error(fcall, "Invalid function identifier"); + return new FxNop(*ast); // return something so that the compiler can continue. + } + break; } case AST_FuncParm: @@ -2346,22 +2376,47 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) } } - default: - // only for development. I_Error is more convenient here than a normal error. - I_Error("ConvertNode encountered unsupported node of type %d", ast->NodeType); - return nullptr; + case AST_ExprBinary: + { + auto binary = static_cast(ast); + auto left = ConvertNode(binary->Left); + auto right = ConvertNode(binary->Right); + auto op = binary->Operation; + switch (op) + { + case PEX_Add: + case PEX_Sub: + return new FxAddSub(op == PEX_Add ? '+' : '-', left, right); + + case PEX_Mul: + case PEX_Div: + case PEX_Mod: + return new FxMulDiv(op == PEX_Mul ? '*' : op == PEX_Div ? '/' : '%', left, right); + + default: + I_Error("Binary operator %d not implemented yet", op); + } + break; } + } + + // only for development. I_Error is more convenient here than a normal error. + I_Error("ConvertNode encountered unsupported node of type %d", ast->NodeType); + return nullptr; } FArgumentList *ZCCCompiler::ConvertNodeList(ZCC_TreeNode *head) { FArgumentList *list = new FArgumentList; - auto node = head; - do + if (head != nullptr) { - list->Push(ConvertNode(node)); - node = node->SiblingNext; - } while (node != head); + auto node = head; + do + { + list->Push(ConvertNode(node)); + node = node->SiblingNext; + } while (node != head); + } return list; } \ No newline at end of file