diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index c68fc3723a..14f1627d98 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -264,9 +264,9 @@ FxExpression *FxExpression::Resolve(FCompileContext &ctx) // //========================================================================== -bool FxExpression::RequestAddress() +bool FxExpression::RequestAddress(bool *writable) { - ScriptPosition.Message(MSG_ERROR, "invalid dereference\n"); + if (writable != nullptr) *writable = false; return false; } @@ -1488,6 +1488,67 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) return from; } +//========================================================================== +// +// +// +//========================================================================== + +FxSizeAlign::FxSizeAlign(FxExpression *operand, int which) + : FxExpression(operand->ScriptPosition) +{ + Operand = operand; + Which = which; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxSizeAlign::~FxSizeAlign() +{ + SAFE_DELETE(Operand); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxSizeAlign::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Operand, ctx); + + auto type = Operand->ValueType; + if (Operand->isConstant()) + { + ScriptPosition.Message(MSG_ERROR, "cannot determine %s of a constant", Which == 'a'? "alignment" : "size"); + delete this; + return NULL; + } + else if (!Operand->RequestAddress(nullptr)) + { + ScriptPosition.Message(MSG_ERROR, "Operand must be addressable to determine %s", Which == 'a' ? "alignment" : "size"); + delete this; + return NULL; + } + else + { + FxExpression *x = new FxConstant(Which == 'a' ? int(type->Align) : int(type->Size), Operand->ScriptPosition); + delete this; + return x->Resolve(ctx); + } +} + +ExpEmit FxSizeAlign::Emit(VMFunctionBuilder *build) +{ + return ExpEmit(); +} + //========================================================================== // // FxPreIncrDecr @@ -1506,10 +1567,11 @@ FxPreIncrDecr::~FxPreIncrDecr() SAFE_DELETE(Base); } -bool FxPreIncrDecr::RequestAddress() +bool FxPreIncrDecr::RequestAddress(bool *writable) { AddressRequested = true; - return AddressWritable; + if (writable != nullptr) *writable = AddressWritable; + return true; } FxExpression *FxPreIncrDecr::Resolve(FCompileContext &ctx) @@ -1531,7 +1593,7 @@ FxExpression *FxPreIncrDecr::Resolve(FCompileContext &ctx) delete this; return nullptr; } - if (!(AddressWritable = Base->RequestAddress())) + if (!Base->RequestAddress(&AddressWritable) || !AddressWritable ) { ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); delete this; @@ -1594,6 +1656,7 @@ FxExpression *FxPostIncrDecr::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); SAFE_RESOLVE(Base, ctx); + bool AddressWritable; ValueType = Base->ValueType; @@ -1609,7 +1672,7 @@ FxExpression *FxPostIncrDecr::Resolve(FCompileContext &ctx) delete this; return nullptr; } - if (!Base->RequestAddress()) + if (!Base->RequestAddress(&AddressWritable) || !AddressWritable) { ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); delete this; @@ -1667,10 +1730,11 @@ FxAssign::~FxAssign() SAFE_DELETE(Right); } -bool FxAssign::RequestAddress() +bool FxAssign::RequestAddress(bool *writable) { AddressRequested = true; - return AddressWritable; + if (writable != nullptr) *writable = AddressWritable; + return true; } FxExpression *FxAssign::Resolve(FCompileContext &ctx) @@ -1688,7 +1752,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) delete this; return nullptr; } - if (!(AddressWritable = Base->RequestAddress())) + if (!Base->RequestAddress(&AddressWritable) || !AddressWritable) { ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); delete this; @@ -3968,10 +4032,11 @@ FxClassMember::~FxClassMember() // //========================================================================== -bool FxClassMember::RequestAddress() +bool FxClassMember::RequestAddress(bool *writable) { AddressRequested = true; - return !!(~membervar->Flags & VARF_ReadOnly); + if (writable != nullptr) *writable = !(membervar->Flags & VARF_ReadOnly); + return true; } //========================================================================== @@ -4079,10 +4144,11 @@ FxArrayElement::~FxArrayElement() // //========================================================================== -bool FxArrayElement::RequestAddress() +bool FxArrayElement::RequestAddress(bool *writable) { AddressRequested = true; - return AddressWritable; + if (writable != nullptr) *writable = AddressWritable; + return true; } //========================================================================== @@ -4108,7 +4174,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) return NULL; } } - if (index->ValueType->GetRegType() != REGT_INT) + if (index->ValueType->GetRegType() != REGT_INT && index->ValueType != TypeName) { ScriptPosition.Message(MSG_ERROR, "Array index must be integer"); delete this; @@ -4141,7 +4207,12 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) delete this; return NULL; } - AddressWritable = Array->RequestAddress(); + if (!Array->RequestAddress(&AddressWritable)) + { + ScriptPosition.Message(MSG_ERROR, "Unable to dereference array."); + delete this; + return NULL; + } return this; } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 8d49361857..1a2d2045d1 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -212,7 +212,7 @@ public: virtual FxExpression *Resolve(FCompileContext &ctx); virtual bool isConstant() const; - virtual bool RequestAddress(); + virtual bool RequestAddress(bool *writable); virtual PPrototype *ReturnProto(); virtual VMFunction *GetDirectFunction(); bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); } @@ -553,6 +553,24 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxSign +// +//========================================================================== + +class FxSizeAlign : public FxExpression +{ + FxExpression *Operand; + int Which; + +public: + FxSizeAlign(FxExpression*, int which); + ~FxSizeAlign(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxPreIncrDecr @@ -570,7 +588,7 @@ public: FxPreIncrDecr(FxExpression *base, int token); ~FxPreIncrDecr(); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(); + bool RequestAddress(bool *writable); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -609,7 +627,7 @@ public: FxAssign(FxExpression *base, FxExpression *right); ~FxAssign(); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(); + bool RequestAddress(bool *writable); ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Address; @@ -932,7 +950,7 @@ public: FxClassMember(FxExpression*, PField*, const FScriptPosition&); ~FxClassMember(); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(); + bool RequestAddress(bool *writable); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -967,7 +985,7 @@ public: FxArrayElement(FxExpression*, FxExpression*); ~FxArrayElement(); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(); + bool RequestAddress(bool *writable); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 9d0ff5428d..c55d6994ae 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2405,6 +2405,46 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) } } + case AST_ExprUnary: + { + auto unary = static_cast(ast); + auto operand = ConvertNode(unary->Operand); + auto op = unary->Operation; + switch (op) + { + case PEX_PostDec: + case PEX_PostInc: + return new FxPostIncrDecr(operand, op == PEX_PostDec ? TK_Decr : TK_Incr); + + case PEX_PreDec: + case PEX_PreInc: + return new FxPreIncrDecr(operand, op == PEX_PostDec ? TK_Decr : TK_Incr); + + case PEX_Negate: + return new FxMinusSign(operand); + + case PEX_AntiNegate: + return new FxPlusSign(operand); + + case PEX_BitNot: + return new FxUnaryNotBitwise(operand); + + case PEX_BoolNot: + return new FxUnaryNotBoolean(operand); + + case PEX_SizeOf: + case PEX_AlignOf: + return new FxSizeAlign(operand, op == PEX_AlignOf ? 'a' : 's'); + + default: + assert(0 && "Unknown unary operator."); // should never happen + Error(unary, "Unknown unary operator ID #%d", op); + return new FxNop(*ast); + } + break; + } + + case AST_ExprBinary: { auto binary = static_cast(ast); @@ -2433,6 +2473,31 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) case PEX_BitXor: return new FxBinaryInt(op == PEX_LeftShift ? TK_LShift : op == PEX_RightShift ? TK_RShift : op == PEX_URightShift? TK_URShift : op == PEX_BitAnd ? '&' : op == PEX_BitOr ? '|' : '^', left, right); + case PEX_BoolOr: + case PEX_BoolAnd: + return new FxBinaryLogical(op == PEX_BoolAnd ? TK_AndAnd : TK_OrOr, left, right); + + case PEX_LT: + case PEX_LTEQ: + case PEX_GT: + case PEX_GTEQ: + return new FxCompareRel(op == PEX_LT ? '<' : op == PEX_RightShift ? '>' : op == PEX_LTEQ ? TK_Leq : TK_Geq, left, right); + + case PEX_EQEQ: + case PEX_NEQ: + return new FxCompareEq(op == PEX_NEQ ? TK_Neq : TK_Eq, left, right); + + + // todo: These do not have representations in DECORATE and no implementation exists yet. + case PEX_LTGTEQ: + case PEX_Concat: + case PEX_Is: + // more esoteric operators + case PEX_APREQ: + + // vector operations will be done later. + case PEX_CrossProduct: + case PEX_DotProduct: default: I_Error("Binary operator %d not implemented yet", op); }