Closed armoha closed 1 month ago
Great ideas! I think allowing assignment to ExprProxy wrapping variable (hereafter typed variable) is acceptable. Though I believe we must carefully design the epScript grammar so that unwanted/unexpected behaviors don't come up - for example, constants should be kept as constants, and make a new typed variable grammar; allow the variable to change only when there is an explicit assignment to the typed variable.
Typed variable feature was introduced in https://github.com/armoha/euddraft/issues/138 and we need to finish which operations are allowed or forbidden on them.
ExprProxy
ExprProxy
is a base class for proxy classes, which are able to wrap both constants and variables.Reference types
EUDArray
,EUDVArray
,EUDStruct
,EUDStructArray
CUnit
,CSprite
Those classes wrap address of object. Addition does not make sense between them. Subtracting two memory addresses results in the distance between the addresses (the output should be integer type).
Mutability
Mutating them would mean redirecting the reference, or becoming null reference. Since there're two major representations of addresses in EUD, ptr and epd, assignment without providing both representations of address will cost non-trivial runtime conversion between ptr and epd. For
CUnit
andCSprite
, which uses epd as representative value (subject of proxy class), ptr is rarely needed so ptr calculation is cached from epd.EUDArray
should have used epd as subject, but it wraps ptr and it will be major breaking change to wrap epd instead of ptr.EUDVArray
is an array ofEUDVariable
(a trigger with 0 condition and 1SetDeaths
action) with some fixed fields. It stores element at value field ofSetDeaths
action and executes its triggers to take out its elements. It requires ptr of trigger to execute trigger (read value), and requires epd of trigger to modify trigger (write value).It requires low-level knowledge to correctly and efficiently modify those classes (e.g. in
EUDLoopUnit2
function, ptr is incremented by 336 and epd is incremented by 84 at the continue point of the loop, which is related to the size of CUnit struct). The current behavior ofExprProxy
on assignment operations can be quite confusing and suboptimal so I'm willing to fix on next version:<<
as assignment operator and avoid using=
,ExprProxy(constant) << new_value
will calculate bitwise left shift between subject of proxy class and new_value (The subject of ExprProxy will left unchanged after assignment). Python does not support operator overloading on built-in types.__lshift__
as assignment,ExprProxy(variable) << new_value
will copy new_value to the subject variable.ExprProxy
does not implement any in-place operations,+=
,-=
,*=
,/=
etc. will result in performing original binary operations (+
,-
,*
,/
etc.) and rebinding name to the result, losing its type. Only binding(name) rebinds and originalExprProxy
is left unchanged (which is actually defined behavior of Python; i.e. string and tuple are immutable and do not implement__iadd__
and yet you can writestring += "text"
, andid(x)
will be changed after+=
of immutable types. See Python reference forobject.__iadd__
and https://docs.python.org/3/faq/programming.html#faq-augmented-assignment-tuple-error).Value types
TrgUnit
,Weapon
,UnitOrder
,Flingy
,Sprite
,Image
,TrgPlayer
,Upgrade
,Tech
LocalLocale
eudplib.scdata.offsetmap.
EnumMember
Those classes wrap ranged integers. Arithmetic on them does not guarantee valid value of original type.
Mutability
(TBD)
Others
DBString
,TrgString
,Db
, ...DBString
andDb
are similar, they are reference types.DBString
is subclass ofExprProxy
and it always put\0
null terminator at the end (hence named-String
).Db
isEUDObject
and it will put null terminator ifstr
is provided to its constructor, and it won't put null terminators forbytes
.TrgString
itself is map string id, which is the input of string triggers (DisplayText, PlayWAV etc.).GetMapStringAddr
function will convert string id to its starting address (it is constant function if string id is constant).Backward compatiblity on mutability of
ExprProxy
+=
,-=
,*=
,/=
are in some sense already broken in losing its type after operation. We don't need to worry about backward compatibility here.Assignment on typed variable (
ExprProxy
wrapping variable) can be a problem:Should we support assignment on reference types? Should we allow assigning 0, -1, or any integer to reference types?
// write logic on local unit selection const unitType = unit.unitType; // this is valid code switch (unitType, 0xFF) { case $U("Terran SCV"), $U("Zerg Drone"), $U("Protoss Probe"): printAll("You're clicking on workers!"); break; default: printAll("You're clicking {:s} (UnitID={})", GetTBLAddr(1+unitType), unitType); }
return ptr, unit; }
cc @Dr-zzt