Skip to content

Commit e4dba4f

Browse files
committed
Fix some issues with getting and setting traits
1 parent 68d2124 commit e4dba4f

3 files changed

Lines changed: 179 additions & 46 deletions

File tree

AS3/src/com/cff/anebe/ir/ASClass.as

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@ package com.cff.anebe.ir
2727
/**
2828
* Gets a static trait present in the class
2929
* @param name Name of the trait to retrieve
30-
* @param whichIfMultiple If there are multiple traits that match this ASMultiname (such as may be the case with getters and setters), which index to get
30+
* @param favorSetter If this name refers to both a getter and a setter, true will retrieve the getter, while false will retrieve the setter. If it is neither or only one exists, has no effect.
3131
* @return The trait retrieved, or null if none were found
3232
*/
33-
public function getStaticTrait(name:ASMultiname, whichIfMultiple:uint = 0):ASTrait
33+
public function getStaticTrait(name:ASMultiname, favorSetter:Boolean = false):ASTrait
3434
{
3535
if (name == null || name.type != ASMultiname.TYPE_QNAME)
3636
{
3737
throw new ArgumentError("Trait name must be a QName");
3838
}
3939

40-
var ret:Object = context.call("GetStaticTrait", name, whichIfMultiple);
40+
var ret:Object = context.call("GetStaticTrait", name, favorSetter);
4141

4242
if (ret == null)
4343
{
@@ -53,7 +53,13 @@ package com.cff.anebe.ir
5353
}
5454

5555
/**
56-
* Sets a trait as static into the class. If it does not exist, it will be created, and if it does it will be overwritten.
56+
* Sets a trait as static into the class.
57+
* If a trait does not exist by the name of the new trait, the new trait will be added.
58+
* If a getter exists by the name of the new trait and the new trait is a setter, the new trait will be added.
59+
* If a setter exists by the name of the new trait and the new trait is a getter, the new trait will be added.
60+
* If both a getter and setter exist by the name of the new trait and the new trait is neither a getter nor setter, the new trait will replace both the getter and setter.
61+
* If a trait of the same kind already exists by the name of the new trait, the new trait will replace that trait.
62+
* If a trait exists by the name of the new trait and the kinds do not match any of the above rules, the new trait will replace the original.
5763
* @param value The trait to set or add to the class
5864
*/
5965
public function setStaticTrait(value:ASTrait):void
@@ -82,16 +88,16 @@ package com.cff.anebe.ir
8288
/**
8389
* Deletes a static trait present in the class
8490
* @param name Name of the trait to retrieve
85-
* @param whichIfMultiple If there are multiple traits that match this ASMultiname (such as may be the case with getters and setters), which index to delete
91+
* @param favorSetter If this name refers to both a getter and a setter, true will delete the getter, while false will delete the setter. If it is neither or only one exists, has no effect.
8692
*/
87-
public function deleteStaticTrait(name:ASMultiname, whichIfMultiple:uint = 0):void
93+
public function deleteStaticTrait(name:ASMultiname, favorSetter:Boolean = false):void
8894
{
8995
if (name == null || name.type != ASMultiname.TYPE_QNAME)
9096
{
9197
throw new ArgumentError("Trait name must be a QName");
9298
}
9399

94-
var ret:Object = context.call("DeleteStaticTrait", name, whichIfMultiple);
100+
var ret:Object = context.call("DeleteStaticTrait", name, favorSetter);
95101

96102
if (ret is String)
97103
{
@@ -106,17 +112,17 @@ package com.cff.anebe.ir
106112
/**
107113
* Gets an instance trait present in the class
108114
* @param name Name of the trait to retrieve
109-
* @param whichIfMultiple If there are multiple traits that match this ASMultiname (such as may be the case with getters and setters), which index to get
115+
* @param favorSetter If this name refers to both a getter and a setter, true will retrieve the getter, while false will retrieve the setter. If it is neither or only one exists, has no effect.
110116
* @return The trait retrieved, or null if none were found
111117
*/
112-
public function getInstanceTrait(name:ASMultiname, whichIfMultiple:uint = 0):ASTrait
118+
public function getInstanceTrait(name:ASMultiname, favorSetter:Boolean = false):ASTrait
113119
{
114120
if (name == null || name.type != ASMultiname.TYPE_QNAME)
115121
{
116122
throw new ArgumentError("Trait name must be a QName");
117123
}
118124

119-
var ret:Object = context.call("GetInstanceTrait", name, whichIfMultiple);
125+
var ret:Object = context.call("GetInstanceTrait", name, favorSetter);
120126

121127
if (ret == null)
122128
{
@@ -132,7 +138,13 @@ package com.cff.anebe.ir
132138
}
133139

134140
/**
135-
* Sets an instance trait into the class. If it does not exist, it will be created, and if it does it will be overwritten.
141+
* Sets an instance trait as into the class.
142+
* If a trait does not exist by the name of the new trait, the new trait will be added.
143+
* If a getter exists by the name of the new trait and the new trait is a setter, the new trait will be added.
144+
* If a setter exists by the name of the new trait and the new trait is a getter, the new trait will be added.
145+
* If both a getter and setter exist by the name of the new trait and the new trait is neither a getter nor setter, the new trait will replace both the getter and setter.
146+
* If a trait of the same kind already exists by the name of the new trait, the new trait will replace that trait.
147+
* If a trait exists by the name of the new trait and the kinds do not match any of the above rules, the new trait will replace the original.
136148
* @param value The trait to set or add to the class
137149
*/
138150
public function setInstanceTrait(value:ASTrait):void
@@ -159,18 +171,18 @@ package com.cff.anebe.ir
159171
}
160172

161173
/**
162-
* Deletes an instance trait present in the class
174+
* Deletes an instance trait present in the class.
163175
* @param name Name of the trait to retrieve
164-
* @param whichIfMultiple If there are multiple traits that match this ASMultiname (such as may be the case with getters and setters), which index to delete
176+
* @param favorSetter If this name refers to both a getter and a setter, true will delete the getter, while false will delete the setter. If it is neither or only one exists, has no effect.
165177
*/
166-
public function deleteInstanceTrait(name:ASMultiname, whichIfMultiple:uint = 0):void
178+
public function deleteInstanceTrait(name:ASMultiname, favorSetter:Boolean = false):void
167179
{
168180
if (name == null || name.type != ASMultiname.TYPE_QNAME)
169181
{
170182
throw new ArgumentError("Trait name must be a QName");
171183
}
172184

173-
var ret:Object = context.call("DeleteInstanceTrait", name, whichIfMultiple);
185+
var ret:Object = context.call("DeleteInstanceTrait", name, favorSetter);
174186

175187
if (ret is String)
176188
{

Native/BytecodeEditor/include/utils/SmallTrivialVector.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ class SmallTrivialVector<T, Size>
1616
// clang-format on
1717
{
1818
private:
19-
std::array<T, Size> data{};
20-
std::size_t populated{0};
19+
std::array<T, Size> data;
20+
std::size_t populated;
2121

2222
public:
23-
consteval SmallTrivialVector() = default;
23+
consteval SmallTrivialVector() : data(), populated(0) {}
2424

2525
consteval SmallTrivialVector(std::initializer_list<T> l) : data(), populated(0)
2626
{

Native/BytecodeEditor/source/ASClassFunctions.cpp

Lines changed: 149 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,53 @@ namespace
1717

1818
GET_CLASS();
1919

20-
ASASM::Multiname name = ConvertMultiname(argv[0]);
20+
try
21+
{
22+
ASASM::Multiname name = ConvertMultiname(argv[0]);
2123

22-
uint32_t whichIfMultiple = CHECK_OBJECT<FRE_TYPE_NUMBER, uint32_t>(argv[1]);
24+
bool favorSetter = CHECK_OBJECT<FRE_TYPE_BOOLEAN>(argv[1]);
2325

24-
uint32_t currentIfMultiple = 0;
26+
SmallTrivialVector<const ASASM::Trait*, 2> found;
2527

26-
try
27-
{
2828
for (const auto& trait : std::invoke(accessor, clazz).traits)
2929
{
3030
if (trait.name == name)
3131
{
32-
if (currentIfMultiple == whichIfMultiple)
32+
if (!found.emplace_back(&trait))
33+
{
34+
FAIL("More than two traits matched this multiname. This should never "
35+
"happen!");
36+
}
37+
}
38+
}
39+
40+
if (found.size() == 1)
41+
{
42+
return ConvertTrait(*found[0]);
43+
}
44+
else if (found.size() == 2)
45+
{
46+
if (favorSetter && found[0]->kind == TraitKind::Getter)
47+
{
48+
if (favorSetter)
49+
{
50+
return ConvertTrait(*found[1]);
51+
}
52+
else
53+
{
54+
return ConvertTrait(*found[0]);
55+
}
56+
}
57+
else
58+
{
59+
if (favorSetter)
60+
{
61+
return ConvertTrait(*found[0]);
62+
}
63+
else
3364
{
34-
return ConvertTrait(trait);
65+
return ConvertTrait(*found[1]);
3566
}
36-
currentIfMultiple++;
3767
}
3868
}
3969
}
@@ -68,21 +98,80 @@ namespace
6898
{
6999
ASASM::Trait value = ConvertTrait(argv[0]);
70100

71-
bool hasSet = false;
72-
for (size_t i = 0; i < std::invoke(accessor, clazz).traits.size(); i++)
101+
SmallTrivialVector<size_t, 2> found{};
102+
103+
auto& traits = std::invoke(accessor, clazz).traits;
104+
105+
for (size_t i = 0; i < traits.size(); i++)
73106
{
74-
auto& trait = std::invoke(accessor, clazz).traits[i];
75-
if (trait.name == value.name)
107+
if (traits[i].name == value.name)
76108
{
77-
trait = std::move(value);
78-
hasSet = true;
79-
break;
109+
if (!found.emplace_back(i))
110+
{
111+
FAIL("More than two traits matched this multiname. This should never "
112+
"happen!");
113+
}
80114
}
81115
}
82116

83-
if (!hasSet)
117+
if (found.size() > 0)
84118
{
85-
std::invoke(accessor, clazz).traits.emplace_back(std::move(ConvertTrait(argv[0])));
119+
if (found.size() == 2) // Must be both getter and setter
120+
{
121+
if (value.kind == TraitKind::Getter)
122+
{
123+
if (traits[found[0]].kind == TraitKind::Getter)
124+
{
125+
traits[found[0]] = std::move(value);
126+
}
127+
else
128+
{
129+
traits[found[1]] = std::move(value);
130+
}
131+
}
132+
else if (value.kind == TraitKind::Setter)
133+
{
134+
if (traits[found[0]].kind == TraitKind::Setter)
135+
{
136+
traits[found[0]] = std::move(value);
137+
}
138+
else
139+
{
140+
traits[found[1]] = std::move(value);
141+
}
142+
}
143+
else
144+
{
145+
traits.erase(
146+
traits.begin() +
147+
found[1]); // Erase found[1] because it's the closest to the back
148+
traits[found[0]] = std::move(value); // And replace found[0]
149+
}
150+
}
151+
else
152+
{
153+
TraitKind kind = traits[found[0]].kind;
154+
if ((kind == TraitKind::Getter || kind == TraitKind::Setter) &&
155+
(value.kind == TraitKind::Setter || value.kind == TraitKind::Getter) &&
156+
kind == value.kind)
157+
{
158+
traits[found[0]] = std::move(value);
159+
}
160+
else if ((kind == TraitKind::Getter || kind == TraitKind::Setter) &&
161+
(value.kind == TraitKind::Setter || value.kind == TraitKind::Getter) &&
162+
kind != value.kind)
163+
{
164+
traits.emplace_back(std::move(value));
165+
}
166+
else
167+
{
168+
traits[found[0]] = std::move(value);
169+
}
170+
}
171+
}
172+
else
173+
{
174+
traits.emplace_back(std::move(value));
86175
}
87176
}
88177
catch (FREObject o)
@@ -112,27 +201,59 @@ namespace
112201

113202
GET_CLASS();
114203

115-
ASASM::Multiname name = ConvertMultiname(argv[0]);
116-
117204
try
118205
{
119-
uint32_t whichIfMultiple = CHECK_OBJECT<FRE_TYPE_NUMBER, uint32_t>(argv[1]);
206+
ASASM::Multiname name = ConvertMultiname(argv[0]);
120207

121-
uint32_t currentIfMultiple = 0;
208+
bool favorSetter = CHECK_OBJECT<FRE_TYPE_BOOLEAN>(argv[1]);
122209

123-
for (size_t i = 0; i < std::invoke(accessor, clazz).traits.size(); i++)
210+
auto& traits = std::invoke(accessor, clazz).traits;
211+
212+
SmallTrivialVector<size_t, 2> found;
213+
214+
for (size_t i = 0; i < traits.size(); i++)
124215
{
125-
const auto& trait = std::invoke(accessor, clazz).traits[i];
216+
const auto& trait = traits[i];
126217
if (trait.name == name)
127218
{
128-
if (currentIfMultiple == whichIfMultiple)
219+
if (!found.emplace_back(i))
220+
{
221+
FAIL("More than two traits matched this multiname. This should never "
222+
"happen!");
223+
}
224+
}
225+
}
226+
227+
if (found.size() == 1)
228+
{
229+
traits.erase(traits.begin() + found[0]);
230+
SUCCEED_VOID();
231+
}
232+
else if (found.size() == 2)
233+
{
234+
if (traits[found[0]].kind == TraitKind::Getter)
235+
{
236+
if (favorSetter)
237+
{
238+
traits.erase(traits.begin() + found[1]);
239+
}
240+
else
241+
{
242+
traits.erase(traits.begin() + found[0]);
243+
}
244+
}
245+
else
246+
{
247+
if (favorSetter)
248+
{
249+
traits.erase(traits.begin() + found[0]);
250+
}
251+
else
129252
{
130-
std::invoke(accessor, clazz)
131-
.traits.erase(std::invoke(accessor, clazz).traits.begin() + i);
132-
SUCCEED_VOID();
253+
traits.erase(traits.begin() + found[1]);
133254
}
134-
currentIfMultiple++;
135255
}
256+
SUCCEED_VOID();
136257
}
137258

138259
FAIL("Trait not found");

0 commit comments

Comments
 (0)