Fixed: Script/Class initializers order of assignment

Changed: Compound script has slot/const traits inside main script initializer
This commit is contained in:
Jindra Petřík
2024-08-17 01:59:54 +02:00
parent 54faceb9a8
commit 4e528c181c
50 changed files with 1521 additions and 465 deletions

View File

@@ -35,6 +35,7 @@ import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.abc.types.traits.TraitClass;
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings;
@@ -258,7 +259,7 @@ public class ScriptPack extends AS3ClassTreeItem {
int sinit_index = abc.script_info.get(scriptIndex).init_index;
int sinit_bodyIndex = abc.findBodyIndex(sinit_index);
if (sinit_bodyIndex != -1) {
if (sinit_bodyIndex != -1 && (isSimple || traitIndices.isEmpty())) {
//initialize all classes traits
/*for (Trait t : traits) {
if (t instanceof TraitClass) {
@@ -306,42 +307,28 @@ public class ScriptPack extends AS3ClassTreeItem {
if (!isSimple && traitIndices.isEmpty()) {
for (Trait t : abc.script_info.get(scriptIndex).traits.traits) {
if (t instanceof TraitSlotConst) {
continue;
}
String fullName = t.getName(abc).getNameWithNamespace(abc.constants, false).toPrintableString(true);
writer.appendNoHilight("include \"" + fullName.replace(".", "/") + ".as\";").newLine();
}
writer.newLine();
}
if (bodyIndex != -1 && (isSimple || traitIndices.isEmpty())) {
//Note: There must be trait/method highlight even if the initializer is empty to TraitList in GUI to work correctly
writer.startTrait(GraphTextWriter.TRAIT_SCRIPT_INITIALIZER);
writer.startMethod(script_init, null);
if (exportMode != ScriptExportMode.AS_METHOD_STUBS) {
if (!scriptInitializerIsEmpty) {
writer.startBlock();
List<MethodBody> callStack = new ArrayList<>();
callStack.add(abc.bodies.get(bodyIndex));
abc.bodies.get(bodyIndex).toString(callStack, abcIndex, path + "/.scriptinitializer", exportMode, abc, null, writer, new ArrayList<>(), new HashSet<>());
writer.endBlock();
} else {
writer.append("");
}
}
writer.endMethod();
writer.endTrait();
if (!scriptInitializerIsEmpty) {
writer.newLine();
first = false;
}
}
}
for (int t : traitIndices) {
Trait trait = traits.get(t);
if ((trait instanceof TraitSlotConst) && convertData.assignedValues.containsKey((TraitSlotConst) trait)) {
continue;
}
if (!first) {
writer.newLine();
}
Trait trait = traits.get(t);
//if (!(trait instanceof TraitClass)) {
writer.startTrait(t);
//}
@@ -357,6 +344,29 @@ public class ScriptPack extends AS3ClassTreeItem {
}
first = false;
}
if (bodyIndex != -1 && (isSimple || traitIndices.isEmpty())) {
//Note: There must be trait/method highlight even if the initializer is empty to TraitList in GUI to work correctly
writer.startTrait(GraphTextWriter.TRAIT_SCRIPT_INITIALIZER);
writer.startMethod(script_init, null);
if (exportMode != ScriptExportMode.AS_METHOD_STUBS) {
if (!scriptInitializerIsEmpty) {
//writer.startBlock();
List<MethodBody> callStack = new ArrayList<>();
callStack.add(abc.bodies.get(bodyIndex));
abc.bodies.get(bodyIndex).toString(callStack, abcIndex, path + "/.scriptinitializer", exportMode, abc, null, writer, new ArrayList<>(), new HashSet<>());
//writer.endBlock();
} else {
writer.append("");
}
}
writer.endMethod();
writer.endTrait();
if (!scriptInitializerIsEmpty) {
writer.newLine();
first = false;
}
}
}
/**

View File

@@ -261,12 +261,15 @@ import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NewActivationAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NewFunctionAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.PackageAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.ReturnValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.ReturnVoidAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.SetPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.SetSlotAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.SetTypeAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.StoreNewActivationAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.TraitSlotConstAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.DeclarationAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForEachInAVM2Item;
@@ -278,6 +281,7 @@ import com.jpexs.decompiler.flash.abc.types.ConvertData;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
import com.jpexs.decompiler.flash.abc.types.Multiname;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
@@ -296,6 +300,7 @@ import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.GraphTargetVisitorInterface;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.decompiler.graph.SecondPassException;
import com.jpexs.decompiler.graph.SimpleValue;
@@ -312,8 +317,10 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
@@ -1905,6 +1912,34 @@ public class AVM2Code implements Cloneable {
}
}
}
if (ins.definition instanceof KillIns) {
int killedReg = ins.operands[0];
if (output.size() >= 2 && !stack.isEmpty()) {
if ((stack.peek() instanceof LocalRegAVM2Item) && (((LocalRegAVM2Item) stack.peek()).regIndex == killedReg)) {
if (output.get(output.size() - 1) instanceof SetPropertyAVM2Item) {
SetPropertyAVM2Item setProp = (SetPropertyAVM2Item) output.get(output.size() - 1);
if ((output.get(output.size() - 2) instanceof SetLocalAVM2Item) && (((SetLocalAVM2Item) output.get(output.size() - 2)).regIndex == killedReg)) {
SetLocalAVM2Item setLoc = (SetLocalAVM2Item) output.get(output.size() - 2);
AVM2Instruction insAfter = ip + 1 < code.size() ? code.get(ip + 1) : null;
if (insAfter != null && (insAfter.definition instanceof PopIns)) {
if (setProp.value instanceof LocalRegAVM2Item) {
LocalRegAVM2Item locReg = (LocalRegAVM2Item) setProp.value;
if (locReg.regIndex == killedReg) {
setProp.value = setLoc.value;
output.remove(output.size() - 2);
stack.pop();
ip += 2;
continue;
}
}
}
}
}
}
}
}
/*
if (ins.definition instanceof DupIns) {
int nextPos;
@@ -2480,6 +2515,10 @@ public class AVM2Code implements Cloneable {
}
}*/
}
private static interface BlockVisitor {
public void visitBlock(List<GraphTargetItem> items);
}
/**
* Converts code to source - list of GraphTargetItems.
@@ -2541,10 +2580,10 @@ public class AVM2Code implements Cloneable {
NewFunctionAVM2Item f = (NewFunctionAVM2Item) value;
f.functionName = tsc.getName(abc).getName(abc.constants, fullyQualifiedNames, true, true);
}
AssignedValue av = new AssignedValue(value, initializerType, methodIndex);
AssignedValue av = new AssignedValue(ti, value, initializerType, methodIndex);
convertData.assignedValues.put(tsc, av);
list.remove(i);
i--;
//list.remove(i);
//i--;
continue loopi;
}
}
@@ -2609,10 +2648,10 @@ public class AVM2Code implements Cloneable {
NewFunctionAVM2Item f = (NewFunctionAVM2Item) value;
f.functionName = tsc.getName(abc).getName(abc.constants, fullyQualifiedNames, true, true);
}
AssignedValue av = new AssignedValue(value, initializerType, methodIndex);
AssignedValue av = new AssignedValue(ti, value, initializerType, methodIndex);
convertData.assignedValues.put(tsc, av);
list.remove(i);
i--;
//list.remove(i);
//i--;
continue loopi;
}
}
@@ -2626,7 +2665,153 @@ public class AVM2Code implements Cloneable {
}
}
}
int lastPos = list.size() - 1;
if (lastPos < 0) {
lastPos = 0;
}
if ((list.size() > lastPos) && (list.get(lastPos) instanceof ScriptEndItem)) {
lastPos--;
}
if (lastPos < 0) {
lastPos = 0;
}
if ((list.size() > lastPos) && (list.get(lastPos) instanceof ReturnVoidAVM2Item)) {
list.remove(lastPos);
}
if (initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) {
if ((list.size() > lastPos) && (list.get(lastPos) instanceof ReturnValueAVM2Item)) {
ReturnValueAVM2Item rv = (ReturnValueAVM2Item) list.get(lastPos);
if (rv.value instanceof LocalRegAVM2Item) {
list.remove(lastPos);
} else {
list.set(lastPos, rv.value);
}
}
}
if (initializerType == GraphTextWriter.TRAIT_CLASS_INITIALIZER || initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) {
Map<GraphTargetItem, AssignedValue> commandToAssigned = new IdentityHashMap<>();
Map<GraphTargetItem, TraitSlotConst> commandToTrait = new IdentityHashMap<>();
for (TraitSlotConst tsc : convertData.assignedValues.keySet()) {
AssignedValue asv = convertData.assignedValues.get(tsc);
commandToAssigned.put(asv.command, asv);
commandToTrait.put(asv.command, tsc);
}
for (int i = 0; i < list.size(); i++) {
GraphTargetItem ti = list.get(i);
if (commandToAssigned.containsKey(ti)) {
AssignedValue asv = commandToAssigned.get(ti);
TraitSlotConst tsc = commandToTrait.get(ti);
TraitSlotConstAVM2Item item = new TraitSlotConstAVM2Item(
ti.getSrc(),
ti.getLineStartItem(),
tsc,
asv.value,
isStatic,
scriptIndex,
classIndex,
initializerType,
methodIndex,
initTraits.traits.indexOf(tsc)
);
list.set(i, item);
}
}
if (initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) {
//Eliminate all setlocals, can sometimes happen
BlockVisitor bv = new BlockVisitor() {
@Override
public void visitBlock(List<GraphTargetItem> items) {
for (int i = 0; i < items.size(); i++) {
GraphTargetItem item = items.get(i);
if (item instanceof SetLocalAVM2Item) {
items.set(i, item.value);
}
if (item instanceof Block) {
Block b = (Block) item;
for (List<GraphTargetItem> list : b.getSubs()) {
visitBlock(list);
}
}
}
}
};
bv.visitBlock(list);
PackageAVM2Item currentPkg = null;
for (int i = 0; i < list.size(); i++) {
GraphTargetItem ti = list.get(i);
if (ti instanceof TraitSlotConstAVM2Item) {
TraitSlotConstAVM2Item tsci = (TraitSlotConstAVM2Item) ti;
Namespace ns = tsci.getTrait().getName(abc).getNamespace(abc.constants);
if (ns.kind == Namespace.KIND_PACKAGE || ns.kind == Namespace.KIND_PACKAGE_INTERNAL) {
String newPkgName = ns.getName(abc.constants).toRawString();
if (currentPkg == null) {
currentPkg = new PackageAVM2Item(new ArrayList<>(), newPkgName);
currentPkg.addItem(tsci);
list.set(i, currentPkg);
} else if (currentPkg.getPackageName().equals(newPkgName)){
currentPkg.addItem(tsci);
list.remove(i);
i--;
} else {
currentPkg = new PackageAVM2Item(new ArrayList<>(), newPkgName);
currentPkg.addItem(tsci);
list.set(i, currentPkg);
}
}
} else if (currentPkg != null) {
final String currentPkgName = currentPkg.getPackageName();
Reference<Boolean> insidePackage = new Reference<>(true);
//Check whether the command references internal traits of other package
ti.visitRecursively(new AbstractGraphTargetVisitor() {
@Override
public void visit(GraphTargetItem item) {
if (item instanceof GetSlotAVM2Item) {
GetSlotAVM2Item gs = (GetSlotAVM2Item) item;
if ((gs.slotObject instanceof GlobalAVM2Item) && (initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER)) {
for (Trait t : initTraits.traits) {
if (t instanceof TraitSlotConst) {
TraitSlotConst tsc = (TraitSlotConst) t;
if (tsc.slot_id == gs.slotIndex) {
int nsKind = tsc.getName(abc).getNamespace(abc.constants).kind;
if (
(
nsKind == Namespace.KIND_PACKAGE_INTERNAL
&& !currentPkgName.equals(tsc.getName(abc).getNamespace(abc.constants).getRawName(abc.constants))
)
|| (nsKind == Namespace.KIND_PRIVATE)
) {
insidePackage.setVal(false);
}
}
}
}
}
}
}
});
if (insidePackage.getVal()) {
currentPkg.addItem(ti);
list.remove(i);
i--;
} else {
currentPkg = null;
}
}
}
}
List<GraphTargetItem> newList = new ArrayList<>();
for (GraphTargetItem ti : list) {
if (!(ti instanceof ReturnVoidAVM2Item)) {
@@ -2678,21 +2863,7 @@ public class AVM2Code implements Cloneable {
for (int ir = 0; ir < r; ir++) {
paramNamesList.add(AVM2Item.localRegName(localRegNames, ir));
}
injectDeclarations(0, paramNamesList, list, 1, d, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), abc, body);
int lastPos = list.size() - 1;
if (lastPos < 0) {
lastPos = 0;
}
if ((list.size() > lastPos) && (list.get(lastPos) instanceof ScriptEndItem)) {
lastPos--;
}
if (lastPos < 0) {
lastPos = 0;
}
if ((list.size() > lastPos) && (list.get(lastPos) instanceof ReturnVoidAVM2Item)) {
list.remove(lastPos);
}
injectDeclarations(0, paramNamesList, list, 1, d, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), abc, body);
return list;
}

View File

@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.abc.avm2;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.model.LocalData;
@@ -83,7 +84,7 @@ public class CodeStats {
if (stats.stackpos > ms) {
ms = stats.stackpos;
}
writer.appendNoHilight(i + ":" + stats.stackpos + (deltastack >= 0 ? "+" + deltastack : deltastack) + "," + stats.scopepos + " " + stats.ins.toString(writer, LocalData.create(new ArrayList<>(), null, abc, null, fullyQualifiedNames, new HashSet<>()))).newLine();
writer.appendNoHilight(i + ":" + stats.stackpos + (deltastack >= 0 ? "+" + deltastack : deltastack) + "," + stats.scopepos + " " + stats.ins.toString(writer, LocalData.create(new ArrayList<>(), null, abc, null, fullyQualifiedNames, new HashSet<>(), ScriptExportMode.AS))).newLine();
i++;
}
return writer;

View File

@@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
import com.jpexs.decompiler.flash.abc.avm2.model.UnparsedAVM2Item;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
@@ -48,7 +49,7 @@ public class NewClassIns extends InstructionDefinition {
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) throws InterruptedException {
int clsIndex = ins.operands[0];
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false);
stack.pop().toString(writer, LocalData.create(localData.callStack /*??*/, localData.abcIndex, localData.abc, localData.localRegNames, localData.fullyQualifiedNames, new HashSet<>()));
stack.pop().toString(writer, LocalData.create(localData.callStack /*??*/, localData.abcIndex, localData.abc, localData.localRegNames, localData.fullyQualifiedNames, new HashSet<>(), ScriptExportMode.AS));
writer.finishHilights();
String baseType = writer.toString();
ABC abc = localData.abc;

View File

@@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.abc.avm2.model;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphSourceItem;
@@ -150,13 +151,13 @@ public class FullMultinameAVM2Item extends AVM2Item {
public boolean isTopLevel(String tname, ABC abc, HashMap<Integer, String> localRegNames, List<DottedChain> fullyQualifiedNames, Set<Integer> seenMethods) throws InterruptedException {
String cname;
if (name != null) {
cname = name.toString(LocalData.create(new ArrayList<>(), null, abc, localRegNames, fullyQualifiedNames, seenMethods));
cname = name.toString(LocalData.create(new ArrayList<>(), null, abc, localRegNames, fullyQualifiedNames, seenMethods, ScriptExportMode.AS));
} else {
cname = (abc.constants.getMultiname(multinameIndex).getName(abc.constants, fullyQualifiedNames, true, true));
}
String cns = "";
if (namespace != null) {
cns = namespace.toString(LocalData.create(new ArrayList<>(), null, abc, localRegNames, fullyQualifiedNames, seenMethods));
cns = namespace.toString(LocalData.create(new ArrayList<>(), null, abc, localRegNames, fullyQualifiedNames, seenMethods, ScriptExportMode.AS));
} else {
Namespace ns = abc.constants.getMultiname(multinameIndex).getNamespace(abc.constants);
if ((ns != null) && (ns.name_index != 0)) {

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2010-2024 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.model;
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.Graph;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.GraphTargetVisitorInterface;
import com.jpexs.decompiler.graph.model.LocalData;
import java.util.List;
/**
*
* @author JPEXS
*/
public class PackageAVM2Item extends AVM2Item {
private final List<GraphTargetItem> items;
private final String packageName;
public PackageAVM2Item(List<GraphTargetItem> items, String packageName) {
super(null, null, PRECEDENCE_PRIMARY);
this.items = items;
this.packageName = packageName;
}
public String getPackageName() {
return packageName;
}
public void addItem(GraphTargetItem item) {
items.add(item);
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
writer.appendNoHilight("package");
if (!packageName.isEmpty()) {
writer.appendNoHilight(" " + DottedChain.parseWithSuffix(packageName).toPrintableString(true));
}
writer.startBlock();
Graph.graphToString(items, writer, localData);
writer.endBlock();
writer.newLine();
return writer;
}
@Override
public boolean hasReturnValue() {
return false;
}
@Override
public GraphTargetItem returnType() {
return null;
}
@Override
public boolean needsSemicolon() {
return false;
}
@Override
public void visit(GraphTargetVisitorInterface visitor) {
visitor.visitAll(items);
}
@Override
public void visitNoBlock(GraphTargetVisitorInterface visitor) {
}
}

View File

@@ -0,0 +1,146 @@
/*
* Copyright (C) 2010-2024 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.model;
import com.jpexs.decompiler.flash.abc.types.AssignedValue;
import com.jpexs.decompiler.flash.abc.types.ConvertData;
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
import com.jpexs.decompiler.flash.abc.types.traits.TraitType;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.model.LocalData;
/**
*
* @author JPEXS
*/
public class TraitSlotConstAVM2Item extends AVM2Item {
private final TraitSlotConst trait;
private final GraphTargetItem assignedValue;
private final boolean isStatic;
private final int scriptIndex;
private final int classIndex;
private final int initializer;
private final int methodIndex;
private final int traitIndex;
/**
*
* @param instruction
* @param lineStartIns
* @param trait
* @param isStatic
* @param assignedValue
* @param classIndex
* @param scriptIndex
* @param initializer
* @param methodIndex
* @param traitIndex
*/
public TraitSlotConstAVM2Item(
GraphSourceItem instruction,
GraphSourceItem lineStartIns,
TraitSlotConst trait,
GraphTargetItem assignedValue,
boolean isStatic,
int scriptIndex,
int classIndex,
int initializer,
int methodIndex,
int traitIndex
) {
super(instruction, lineStartIns, PRECEDENCE_PRIMARY);
this.trait = trait;
this.assignedValue = assignedValue;
this.isStatic = isStatic;
this.scriptIndex = scriptIndex;
this.classIndex = classIndex;
this.initializer = initializer;
this.methodIndex = methodIndex;
this.traitIndex = traitIndex;
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
writer.endMethod();
writer.endTrait();
int h = traitIndex;
if (initializer != GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) {
h = localData.abc.getGlobalTraitId(TraitType.METHOD , isStatic, classIndex, traitIndex);
}
writer.startTrait(h);
ConvertData cd = new ConvertData();
cd.assignedValues.put(trait, new AssignedValue(null, assignedValue, initializer, methodIndex));
boolean insideInterface = classIndex > -1 ? localData.abc.instance_info.get(classIndex).isInterface() : false;
trait.toString(
localData.abcIndex,
null,
cd,
"trait " + trait.getName(localData.abc),
localData.abc,
isStatic,
localData.exportMode,
scriptIndex,
classIndex,
writer,
localData.fullyQualifiedNames,
false,
insideInterface
);
writer.endTrait();
writer.startTrait(initializer);
writer.startMethod(methodIndex, null);
return writer;
}
@Override
public boolean hasReturnValue() {
return false;
}
@Override
public GraphTargetItem returnType() {
return null;
}
@Override
public boolean needsSemicolon() {
return false;
}
@Override
public boolean hasSingleNewLineAround() {
return true;
}
@Override
public boolean handlesNewLine() {
return true;
}
public TraitSlotConst getTrait() {
return trait;
}
}

View File

@@ -620,12 +620,25 @@ public class AVM2SourceGenerator implements SourceGenerator {
* @param iinit Instance initializer
* @param iinitVariables Instance initializer variables
* @param iinitNeedsActivation Instance initializer needs activation
* @param traitItems Trait items
* @param commands Trait items
* @param class_index Class index
* @throws AVM2ParseException On parse error
* @throws CompilationException On compilation error
*/
public void generateClass(List<DottedChain> importedClasses, List<AssignableAVM2Item> cinitVariables, boolean cinitNeedsActivation, List<GraphTargetItem> cinit, List<NamespaceItem> openedNamespaces, int namespace, int initScope, DottedChain pkg, ClassInfo classInfo, InstanceInfo instanceInfo, SourceGeneratorLocalData localData, boolean isInterface, String baseClassName, String superName, GraphTargetItem extendsVal, List<GraphTargetItem> implementsStr, GraphTargetItem iinit, List<AssignableAVM2Item> iinitVariables, boolean iinitNeedsActivation, List<GraphTargetItem> traitItems, Reference<Integer> class_index) throws AVM2ParseException, CompilationException {
public void generateClass(List<DottedChain> importedClasses, List<AssignableAVM2Item> cinitVariables, boolean cinitNeedsActivation, List<GraphTargetItem> cinit, List<NamespaceItem> openedNamespaces, int namespace, int initScope, DottedChain pkg, ClassInfo classInfo, InstanceInfo instanceInfo, SourceGeneratorLocalData localData, boolean isInterface, String baseClassName, String superName, GraphTargetItem extendsVal, List<GraphTargetItem> implementsStr, GraphTargetItem iinit, List<AssignableAVM2Item> iinitVariables, boolean iinitNeedsActivation, List<GraphTargetItem> commands, Reference<Integer> class_index) throws AVM2ParseException, CompilationException {
List<GraphTargetItem> traitItems = new ArrayList<>();
for (GraphTargetItem it : commands) {
if ((it instanceof SlotAVM2Item)
|| (it instanceof ConstAVM2Item)
|| (it instanceof ClassAVM2Item)
|| (it instanceof InterfaceAVM2Item)
|| (it instanceof MethodAVM2Item)
|| (it instanceof GetterAVM2Item)
|| (it instanceof SetterAVM2Item)
) {
traitItems.add(it);
}
}
localData.currentClassBaseName = baseClassName;
localData.pkg = pkg;
localData.privateNs = abcIndex.getSelectedAbc().constants.getNamespaceId(Namespace.KIND_PRIVATE, pkg.toRawString().isEmpty() ? baseClassName : pkg.toRawString() + ":" + baseClassName, 0, true);
@@ -634,7 +647,8 @@ public class AVM2SourceGenerator implements SourceGenerator {
extendsVal = new TypeItem(DottedChain.OBJECT);
}
ParsedSymbol s = null;
if (Configuration.handleSkinPartsAutomatically.get()) {
Map<String, Boolean> skinParts = new HashMap<>();
@@ -772,9 +786,29 @@ public class AVM2SourceGenerator implements SourceGenerator {
int cinit_index = method(true, str(""), false, false, false, new ArrayList<>(), pkg, cinitNeedsActivation, cinitVariables, initScope + (implementsStr.isEmpty() ? 0 : 1), false, 0, isInterface ? null : baseClassName, superName, false, localData, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), cinit, TypeItem.UNBOUNDED);
MethodBody cinitBody = abcIndex.getSelectedAbc().findBody(cinit_index);
List<AVM2Instruction> sinitcode = new ArrayList<>();
for (int i = 0; i < cinitVariables.size(); i++) {
AssignableAVM2Item an = cinitVariables.get(i);
if (an instanceof UnresolvedAVM2Item) {
UnresolvedAVM2Item n = (UnresolvedAVM2Item) an;
if (n.resolved == null) {
String fullClass = localData.getFullClass();
List<MethodBody> callStack = new ArrayList<>();
callStack.add(cinitBody);
GraphTargetItem res = n.resolve(localData, fullClass, new TypeItem(fullClass), new ArrayList<>(), new ArrayList<>(), abcIndex, callStack, cinitVariables);
if (res instanceof AssignableAVM2Item) {
cinitVariables.set(i, (AssignableAVM2Item) res);
} else {
cinitVariables.remove(i);
i--;
}
}
}
}
List<AVM2Instruction> cinitcode = new ArrayList<>();
List<AVM2Instruction> initcode = new ArrayList<>();
for (GraphTargetItem ti : traitItems) {
for (GraphTargetItem ti : commands) {
if ((ti instanceof SlotAVM2Item) || (ti instanceof ConstAVM2Item)) {
GraphTargetItem val = null;
boolean isStatic = false;
@@ -798,10 +832,10 @@ public class AVM2SourceGenerator implements SourceGenerator {
}
}
if (isStatic && val != null) {
sinitcode.add(ins(AVM2Instructions.FindProperty, traitName(ns, tname)));
cinitcode.add(ins(AVM2Instructions.FindProperty, traitName(ns, tname)));
localData.isStatic = true;
sinitcode.addAll(toInsList(val.toSource(localData, this)));
sinitcode.add(ins(isConst ? AVM2Instructions.InitProperty : AVM2Instructions.SetProperty, traitName(ns, tname)));
cinitcode.addAll(toInsList(val.toSource(localData, this)));
cinitcode.add(ins(isConst ? AVM2Instructions.InitProperty : AVM2Instructions.SetProperty, traitName(ns, tname)));
}
if (!isStatic && val != null) {
//do not init basic values, that can be stored in trait
@@ -812,15 +846,23 @@ public class AVM2SourceGenerator implements SourceGenerator {
initcode.add(ins(isConst ? AVM2Instructions.InitProperty : AVM2Instructions.SetProperty, traitName(ns, tname)));
}
}
} else if (ti instanceof MethodAVM2Item) {
//ignore
} else {
localData.isStatic = true;
List<GraphSourceItem> srcs = ti.toSourceIgnoreReturnValue(localData, this);
for (GraphSourceItem src : srcs) {
cinitcode.add((AVM2Instruction)src);
}
}
}
MethodBody initBody = null;
if (!isInterface) {
initBody = abcIndex.getSelectedAbc().findBody(init);
initBody.insertAll(iinit == null ? 0 : 2, initcode); //after getlocal0,pushscope
initBody.getCode().code.addAll(iinit == null ? 0 : 2, initcode); //after getlocal0,pushscope
if (cinitBody.getCode().code.get(cinitBody.getCode().code.size() - 1).definition instanceof ReturnVoidIns) {
cinitBody.insertAll(2, sinitcode); //after getlocal0,pushscope
cinitBody.getCode().code.addAll(2, cinitcode); //after getlocal0,pushscope
}
}
cinitBody.markOffsets();
@@ -1305,7 +1347,7 @@ public class AVM2SourceGenerator implements SourceGenerator {
continue;
}
NameAVM2Item d = new NameAVM2Item(n.type, n.line, n.isAttribute(), n.getVariableName(), n.getNamespaceSuffix(), null /*NameAVM2Item.getDefaultValue("" + n.type)*/, true, n.openedNamespaces, abcIndex);
NameAVM2Item d = new NameAVM2Item(n.type, n.line, n.isAttribute(), n.getVariableName(), n.getNamespaceSuffix(), null /*NameAVM2Item.getDefaultValue("" + n.type)*/, true, n.openedNamespaces, abcIndex, n.isConst());
//no index
if (needsActivation) {
if (d.getSlotNumber() <= 0) {
@@ -1367,9 +1409,9 @@ public class AVM2SourceGenerator implements SourceGenerator {
mbody.traits.traits.add(tsc);
}
for (int i = 1; i < paramRegCount; i++) {
NameAVM2Item param = new NameAVM2Item(registerTypes.get(i), 0, false, registerNames.get(i), "", null, false, new ArrayList<>(), abcIndex);
NameAVM2Item param = new NameAVM2Item(registerTypes.get(i), 0, false, registerNames.get(i), "", null, false, new ArrayList<>(), abcIndex, false);
param.setRegNumber(i);
NameAVM2Item d = new NameAVM2Item(registerTypes.get(i), 0, false, registerNames.get(i), "", param, true, new ArrayList<>(), abcIndex);
NameAVM2Item d = new NameAVM2Item(registerTypes.get(i), 0, false, registerNames.get(i), "", param, true, new ArrayList<>(), abcIndex, false);
d.setSlotScope(slotScope);
d.setSlotNumber(slotNames.indexOf(registerNames.get(i)));
declarations.add(d);
@@ -2099,6 +2141,10 @@ public class AVM2SourceGenerator implements SourceGenerator {
/**
* Generates script info.
* @param sinitVariables Script initializer variables
* @param sinitNeedsActivation Script initializer needs activation
* @param importedClasses Imported classes
* @param openedNamespaces Opened namespaces
* @param scriptIndex Script index
* @param scriptInfo Script info
* @param allOpenedNamespaces All opened namespaces
@@ -2108,14 +2154,27 @@ public class AVM2SourceGenerator implements SourceGenerator {
* @throws AVM2ParseException On parse error
* @throws CompilationException On compilation error
*/
public void generateScriptInfo(int scriptIndex, ScriptInfo scriptInfo, List<List<NamespaceItem>> allOpenedNamespaces, SourceGeneratorLocalData localData, List<GraphTargetItem> commands, int classPos) throws AVM2ParseException, CompilationException {
public void generateScriptInfo(List<AssignableAVM2Item> sinitVariables, boolean sinitNeedsActivation, List<DottedChain> importedClasses, List<NamespaceItem> openedNamespaces, int scriptIndex, ScriptInfo scriptInfo, List<List<NamespaceItem>> allOpenedNamespaces, SourceGeneratorLocalData localData, List<GraphTargetItem> commands, int classPos) throws AVM2ParseException, CompilationException {
List<GraphTargetItem> traitsList = new ArrayList<>();
for (GraphTargetItem it : commands) {
if ((it instanceof SlotAVM2Item)
|| (it instanceof ConstAVM2Item)
|| (it instanceof ClassAVM2Item)
|| (it instanceof InterfaceAVM2Item)
|| (it instanceof MethodAVM2Item)
|| (it instanceof GetterAVM2Item)
|| (it instanceof SetterAVM2Item)
) {
traitsList.add(it);
}
}
Reference<Integer> class_index = new Reference<>(classPos);
localData.currentScript = scriptInfo;
localData.scriptIndex = scriptIndex;
Trait[] traitArr = generateTraitsPhase1(new ArrayList<>(), new ArrayList<>(), null, null, true, localData, commands, scriptInfo.traits, class_index, true);
generateTraitsPhase2(new ArrayList<>(), null/*FIXME*/, commands, traitArr, new ArrayList<>(), localData);
Trait[] traitArr = generateTraitsPhase1(new ArrayList<>(), new ArrayList<>(), null, null, true, localData, traitsList, scriptInfo.traits, class_index, true);
generateTraitsPhase2(new ArrayList<>(), null/*FIXME*/, traitsList, traitArr, new ArrayList<>(), localData);
abcIndex.refreshSelected();
generateTraitsPhase3(commands, traitArr, localData);
generateTraitsPhase3(traitsList, traitArr, localData);
abcIndex.refreshSelected();
ABC abc = abcIndex.getSelectedAbc();
@@ -2194,9 +2253,67 @@ public class AVM2SourceGenerator implements SourceGenerator {
abc.addMethodBody(mb);
scriptInfo.init_index = mb.method_info;
localData.pkg = DottedChain.EMPTY;
generateTraitsPhase4(new ArrayList<>(), new ArrayList<>(), 1/*??*/, false, null, null, true, localData, commands, scriptInfo.traits, traitArr, initScopes, class_index, true);
localData.registerVars.put("this", 0);
generateTraitsPhase4(new ArrayList<>(), new ArrayList<>(), 1/*??*/, false, null, null, true, localData, traitsList, scriptInfo.traits, traitArr, initScopes, class_index, true);
int maxSlotId = 0;
List<AVM2Instruction> sinitcode = new ArrayList<>();
for (int i = 0; i < sinitVariables.size(); i++) {
AssignableAVM2Item an = sinitVariables.get(i);
if (an instanceof UnresolvedAVM2Item) {
UnresolvedAVM2Item n = (UnresolvedAVM2Item) an;
if (n.resolved == null) {
String fullClass = localData.getFullClass();
List<MethodBody> callStack = new ArrayList<>();
callStack.add(mb);
GraphTargetItem res = n.resolve(localData, fullClass, new TypeItem(fullClass), new ArrayList<>(), new ArrayList<>(), abcIndex, callStack, sinitVariables);
if (res instanceof AssignableAVM2Item) {
sinitVariables.set(i, (AssignableAVM2Item) res);
} else {
sinitVariables.remove(i);
i--;
}
}
}
}
for (GraphTargetItem ti : commands) {
if ((ti instanceof SlotAVM2Item) || (ti instanceof ConstAVM2Item)) {
GraphTargetItem val = null;
int ns = -1;
String tname = null;
boolean isConst = false;
NamespaceItem pkg = null;
if (ti instanceof SlotAVM2Item) {
val = ((SlotAVM2Item) ti).value;
pkg = ((SlotAVM2Item) ti).pkg;
ns = genNs(importedClasses, pkg.name, ((SlotAVM2Item) ti).pkg, openedNamespaces, localData, ((SlotAVM2Item) ti).line);
tname = ((SlotAVM2Item) ti).var;
}
if (ti instanceof ConstAVM2Item) {
val = ((ConstAVM2Item) ti).value;
pkg = ((ConstAVM2Item) ti).pkg;
ns = genNs(importedClasses, pkg.name, ((ConstAVM2Item) ti).pkg, openedNamespaces, localData, ((ConstAVM2Item) ti).line);
tname = ((ConstAVM2Item) ti).var;
isConst = true;
if (((ConstAVM2Item) ti).type.toString().equals("Namespace")) {
continue;
}
}
if (val != null) {
sinitcode.add(ins(AVM2Instructions.FindProperty, traitName(ns, tname)));
localData.isStatic = true;
sinitcode.addAll(toInsList(val.toSource(localData, this)));
sinitcode.add(ins(isConst ? AVM2Instructions.InitProperty : AVM2Instructions.SetProperty, traitName(ns, tname)));
}
} else {
List<GraphSourceItem> srcs = ti.toSourceIgnoreReturnValue(localData, this);
for (GraphSourceItem src : srcs) {
sinitcode.add((AVM2Instruction)src);
}
}
}
mbCode.addAll(sinitcode);
/*int maxSlotId = 0;
for (int k = 0; k < scriptInfo.traits.traits.size(); k++) {
if (scriptInfo.traits.traits.get(k) instanceof TraitSlotConst) {
TraitSlotConst ti = (TraitSlotConst) scriptInfo.traits.traits.get(k);
@@ -2225,9 +2342,10 @@ public class AVM2SourceGenerator implements SourceGenerator {
mbCode.add(ins(AVM2Instructions.InitProperty, nts.name_index));
}
}
}
}*/
mbCode.add(ins(AVM2Instructions.ReturnVoid));
mb.markOffsets();
mb.autoFillStats(abc, 1, false);
}

View File

@@ -561,14 +561,14 @@ public class ActionScript3Parser {
}
List<GraphTargetItem> body = null;
List<AssignableAVM2Item> subvariables = new ArrayList<>();
subvariables.add(new NameAVM2Item(thisType, lexer.yyline(), false, "this", "", null, true, openedNamespaces, abcIndex));
subvariables.add(new NameAVM2Item(thisType, lexer.yyline(), false, "this", "", null, true, openedNamespaces, abcIndex, false));
for (int i = 0; i < paramNames.size() - (hasRest ? 1 : 0); i++) {
subvariables.add(new NameAVM2Item(paramTypes.get(i), lexer.yyline(), false, paramNames.get(i), "", null, true, openedNamespaces, abcIndex));
subvariables.add(new NameAVM2Item(paramTypes.get(i), lexer.yyline(), false, paramNames.get(i), "", null, true, openedNamespaces, abcIndex, false));
}
if (hasRest) {
subvariables.add(new NameAVM2Item(TypeItem.UNBOUNDED, lexer.yyline(), false, paramNames.get(paramNames.size() - 1), "", null, true, openedNamespaces, abcIndex));
subvariables.add(new NameAVM2Item(TypeItem.UNBOUNDED, lexer.yyline(), false, paramNames.get(paramNames.size() - 1), "", null, true, openedNamespaces, abcIndex, false));
}
subvariables.add(new NameAVM2Item(thisType, lexer.yyline(), false, "arguments", "", null, true, openedNamespaces, abcIndex));
subvariables.add(new NameAVM2Item(thisType, lexer.yyline(), false, "arguments", "", null, true, openedNamespaces, abcIndex, false));
int parCnt = subvariables.size();
Reference<Boolean> needsActivation2 = new Reference<>(false);
if (!isInterface && !isNative) {
@@ -650,6 +650,10 @@ public class ActionScript3Parser {
openedNamespaces.add(privateNs);
openedNamespaces.add(protectedNs);
openedNamespaces.add(staticProtectedNs);
Stack<Loop> cinitLoops = new Stack<>();
Map<Loop, String> cinitLoopLabels = new HashMap<>();
HashMap<String, Integer> cinitRegisterVars = new HashMap<>();
looptraits:
while (true) {
@@ -667,14 +671,14 @@ public class ActionScript3Parser {
NamespaceItem namespace = null;
ParsedSymbol s = lex();
//static class initializer
if (s.type == SymbolType.CURLY_OPEN) {
/*if (s.type == SymbolType.CURLY_OPEN) {
cinit.addAll(commands(allOpenedNamespaces, thisType, pkg, cinitNeedsActivation, importedClasses, openedNamespaces, new Stack<>(), new HashMap<>(), new HashMap<>(), true, false, 0, cinitVariables, abc));
expectedType(SymbolType.CURLY_CLOSE);
} else {
lexer.pushback(s);
}
}*/
List<Map.Entry<String, Map<String, String>>> metadata = parseMetadata();
s = lex();
//s = lex();
while (s.isType(SymbolType.NATIVE, SymbolType.STATIC, SymbolType.PUBLIC, SymbolType.PRIVATE, SymbolType.PROTECTED, SymbolType.OVERRIDE, SymbolType.FINAL, SymbolType.DYNAMIC, SymbolGroup.IDENTIFIER, SymbolType.INTERNAL, SymbolType.PREPROCESSOR)) {
if (s.type == SymbolType.FINAL) {
@@ -939,23 +943,77 @@ public class ActionScript3Parser {
break;
default:
lexer.pushback(s);
break looptraits;
GraphTargetItem cmd = command(allOpenedNamespaces, null, publicNs, cinitNeedsActivation, importedClasses, openedNamespaces, cinitLoops, cinitLoopLabels, cinitRegisterVars, true, false, 0, false, cinitVariables, abc);
if (cmd != null) {
traits.add(cmd);
} else {
break looptraits;
}
}
}
}
private void scriptTraits(List<List<NamespaceItem>> allOpenedNamespaces, int scriptIndex, String scriptName, List<GraphTargetItem> traits, Reference<Integer> numberUsageRef, Reference<Integer> numberRoundingRef, Reference<Integer> numberPrecisionRef, ABC abc) throws AVM2ParseException, IOException, CompilationException, InterruptedException {
private void scriptTraits(
List<DottedChain> importedClasses,
List<NamespaceItem> openedNamespaces,
List<List<NamespaceItem>> allOpenedNamespaces,
int scriptIndex,
String scriptName,
List<GraphTargetItem> traits,
Reference<Integer> numberUsageRef,
Reference<Integer> numberRoundingRef,
Reference<Integer> numberPrecisionRef,
ABC abc,
Reference<Boolean> sinitNeedsActivation,
List<AssignableAVM2Item> sinitVariables
) throws AVM2ParseException, IOException, CompilationException, InterruptedException {
while (scriptTraitsBlock(allOpenedNamespaces, scriptIndex, scriptName, traits, numberUsageRef, numberRoundingRef, numberPrecisionRef, abc)) {
Stack<Loop> sinitLoops = new Stack<>();
Map<Loop, String> sinitLoopLabels = new HashMap<>();
HashMap<String, Integer> sinitRegisterVars = new HashMap<>();
while (scriptTraitsBlock(
importedClasses,
openedNamespaces,
allOpenedNamespaces,
scriptIndex,
scriptName,
traits,
numberUsageRef,
numberRoundingRef,
numberPrecisionRef,
abc,
sinitNeedsActivation,
sinitLoops,
sinitLoopLabels,
sinitRegisterVars,
sinitVariables
)) {
//empty
}
}
private boolean scriptTraitsBlock(List<List<NamespaceItem>> allOpenedNamespaces, int scriptIndex, String scriptName, List<GraphTargetItem> traits, Reference<Integer> numberUsageRef, Reference<Integer> numberRoundingRef, Reference<Integer> numberPrecisionRef, ABC abc) throws AVM2ParseException, IOException, CompilationException, InterruptedException {
private boolean scriptTraitsBlock(
List<DottedChain> importedClasses,
List<NamespaceItem> openedNamespaces,
List<List<NamespaceItem>> allOpenedNamespaces,
int scriptIndex,
String scriptName,
List<GraphTargetItem> traits,
Reference<Integer> numberUsageRef,
Reference<Integer> numberRoundingRef,
Reference<Integer> numberPrecisionRef,
ABC abc,
Reference<Boolean> sinitNeedsActivation,
Stack<Loop> sinitLoops,
Map<Loop, String> sinitLoopLabels,
HashMap<String, Integer> sinitRegisterVars,
List<AssignableAVM2Item> sinitVariables
) throws AVM2ParseException, IOException, CompilationException, InterruptedException {
ParsedSymbol s;
boolean inPackage = false;
s = lex();
List<AssignableAVM2Item> sinitVariables = new ArrayList<>();
NamespaceItem publicNs;
NamespaceItem packageInternalNs;
DottedChain pkgName = DottedChain.TOPLEVEL;
@@ -983,7 +1041,6 @@ public class ActionScript3Parser {
}
lexer.pushback(s);
List<NamespaceItem> openedNamespaces = new ArrayList<>();
allOpenedNamespaces.add(openedNamespaces);
NamespaceItem emptyNs = new NamespaceItem("", Namespace.KIND_PACKAGE);
openedNamespaces.add(emptyNs);
@@ -1000,7 +1057,7 @@ public class ActionScript3Parser {
}
}
List<DottedChain> importedClasses = parseImportsUsages(openedNamespaces, numberUsageRef, numberPrecisionRef, numberRoundingRef, abc);
parseImportsUsages(importedClasses, openedNamespaces, numberUsageRef, numberPrecisionRef, numberRoundingRef, abc);
boolean isEmpty = true;
@@ -1206,7 +1263,13 @@ public class ActionScript3Parser {
traits.add(new ConstAVM2Item(metadata, ns, null, true, nname, new TypeItem(DottedChain.NAMESPACE), new StringAVM2Item(null, null, nval), lexer.yyline(), generatedNs));
break;
default:
lexer.pushback(s);
lexer.pushback(s);
parseImportsUsages(importedClasses, openedNamespaces, numberUsageRef, numberPrecisionRef, numberRoundingRef, abc);
GraphTargetItem cmd = command(allOpenedNamespaces, null, publicNs, sinitNeedsActivation, importedClasses, openedNamespaces, sinitLoops, sinitLoopLabels, sinitRegisterVars, true, false, 0, false, sinitVariables, abc);
if (cmd != null) {
traits.add(cmd);
isEmpty = false;
}
break looptrait;
}
@@ -1532,6 +1595,8 @@ public class ActionScript3Parser {
ret = (function(allOpenedNamespaces, new ArrayList<>(), pkg, false, false, needsActivation, importedClasses, thisType, openedNamespaces, s.value.toString(), false, variables, abc));
break;
case VAR:
case CONST:
boolean isConst = s.type == SymbolType.CONST;
s = lex();
expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER);
String varIdentifier = s.value.toString();
@@ -1546,10 +1611,10 @@ public class ActionScript3Parser {
if (s.type == SymbolType.ASSIGN) {
GraphTargetItem varval = (expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false, abc));
ret = new NameAVM2Item(type, lexer.yyline(), false, varIdentifier, "", varval, true, openedNamespaces, abcIndex);
ret = new NameAVM2Item(type, lexer.yyline(), false, varIdentifier, "", varval, true, openedNamespaces, abcIndex, isConst);
variables.add((NameAVM2Item) ret);
} else {
ret = new NameAVM2Item(type, lexer.yyline(), false, varIdentifier, "", null, true, openedNamespaces, abcIndex);
ret = new NameAVM2Item(type, lexer.yyline(), false, varIdentifier, "", null, true, openedNamespaces, abcIndex, isConst);
variables.add((NameAVM2Item) ret);
lexer.pushback(s);
}
@@ -1817,7 +1882,7 @@ public class ActionScript3Parser {
String enamestr = s.value.toString();
expectedType(SymbolType.COLON);
GraphTargetItem etype = type(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, variables, abc);
NameAVM2Item e = new NameAVM2Item(etype, lexer.yyline(), false, enamestr, "", new ExceptionAVM2Item(null)/*?*/, true/*?*/, openedNamespaces, abcIndex);
NameAVM2Item e = new NameAVM2Item(etype, lexer.yyline(), false, enamestr, "", new ExceptionAVM2Item(null)/*?*/, true/*?*/, openedNamespaces, abcIndex, false);
//variables.add(e);
catchExceptions.add(e);
e.setSlotNumber(1);
@@ -2607,10 +2672,9 @@ public class ActionScript3Parser {
private List<String> constantPool;
private List<DottedChain> parseImportsUsages(List<NamespaceItem> openedNamespaces, Reference<Integer> numberUsageRef, Reference<Integer> numberPrecisionRef, Reference<Integer> numberRoundingRef, ABC abc) throws IOException, AVM2ParseException, InterruptedException {
private void parseImportsUsages(List<DottedChain> importedClasses, List<NamespaceItem> openedNamespaces, Reference<Integer> numberUsageRef, Reference<Integer> numberPrecisionRef, Reference<Integer> numberRoundingRef, ABC abc) throws IOException, AVM2ParseException, InterruptedException {
ParsedSymbol s;
List<DottedChain> importedClasses = new ArrayList<>();
ParsedSymbol s;
s = lex();
while (s.isType(SymbolType.IMPORT, SymbolType.USE)) {
@@ -2747,10 +2811,19 @@ public class ActionScript3Parser {
s = lex();
}
lexer.pushback(s);
return importedClasses;
}
private List<GraphTargetItem> parseScript(List<List<NamespaceItem>> allOpenedNamespaces, int scriptIndex, String fileName, Reference<Integer> numberContextRef, ABC abc) throws IOException, AVM2ParseException, CompilationException, InterruptedException {
private List<GraphTargetItem> parseScript(
List<DottedChain> importedClasses,
List<NamespaceItem> openedNamespaces,
List<List<NamespaceItem>> allOpenedNamespaces,
int scriptIndex,
String fileName,
Reference<Integer> numberContextRef,
ABC abc,
Reference<Boolean> sinitNeedsActivation,
List<AssignableAVM2Item> sinitVariables
) throws IOException, AVM2ParseException, CompilationException, InterruptedException {
//int scriptPrivateNs;
if (fileName.contains("/")) {
@@ -2763,7 +2836,7 @@ public class ActionScript3Parser {
Reference<Integer> numberUsageRef = new Reference<>(NumberContext.USE_NUMBER);
Reference<Integer> numberRoundingRef = new Reference<>(NumberContext.ROUND_HALF_EVEN);
Reference<Integer> numberPrecisionRef = new Reference<>(34);
scriptTraits(allOpenedNamespaces, scriptIndex, fileName, items, numberUsageRef, numberRoundingRef, numberPrecisionRef, abc);
scriptTraits(importedClasses, openedNamespaces, allOpenedNamespaces, scriptIndex, fileName, items, numberUsageRef, numberRoundingRef, numberPrecisionRef, abc, sinitNeedsActivation, sinitVariables);
NumberContext nc = new NumberContext(numberUsageRef.getVal(), numberPrecisionRef.getVal(), numberRoundingRef.getVal());
if (!nc.isDefault()) {
@@ -2774,22 +2847,37 @@ public class ActionScript3Parser {
/**
* Converts string to script traits.
* @param importedClasses Imported classes
* @param openedNamespaces Opened namespaces
* @param allOpenedNamespaces All opened namespaces
* @param str String to parse
* @param fileName File name
* @param scriptIndex Script index
* @param numberContextRef Number context reference
* @param abc ABC
* @param sinitNeedsActivation Script initializer needs activation
* @param sinitVariables Script initializer variables
* @return List of script traits
* @throws AVM2ParseException On parsing error
* @throws IOException On I/O error
* @throws CompilationException On compilation error
* @throws InterruptedException On interrupt
*/
public List<GraphTargetItem> scriptTraitsFromString(List<List<NamespaceItem>> allOpenedNamespaces, String str, String fileName, int scriptIndex, Reference<Integer> numberContextRef, ABC abc) throws AVM2ParseException, IOException, CompilationException, InterruptedException {
public List<GraphTargetItem> scriptTraitsFromString(
List<DottedChain> importedClasses,
List<NamespaceItem> openedNamespaces,
List<List<NamespaceItem>> allOpenedNamespaces,
String str,
String fileName,
int scriptIndex,
Reference<Integer> numberContextRef,
ABC abc,
Reference<Boolean> sinitNeedsActivation,
List<AssignableAVM2Item> sinitVariables
) throws AVM2ParseException, IOException, CompilationException, InterruptedException {
lexer = new ActionScriptLexer(str);
List<GraphTargetItem> ret = parseScript(allOpenedNamespaces, scriptIndex, fileName, numberContextRef, abc);
List<GraphTargetItem> ret = parseScript(importedClasses, openedNamespaces, allOpenedNamespaces, scriptIndex, fileName, numberContextRef, abc, sinitNeedsActivation, sinitVariables);
if (lexer.lex().type != SymbolType.EOF) {
throw new AVM2ParseException("Parsing finisned before end of the file", lexer.yyline());
}
@@ -2798,14 +2886,19 @@ public class ActionScript3Parser {
/**
* Adds script from tree.
* @param sinitVariables Script initializer variables
* @param sinitNeedsActivation Script initializer needs activation
* @param importedClasses Imported classes
* @param openedNamespaces Opened namespaces
* @param allOpenedNamespaces All opened namespaces
* @param items Items
* @param classPos Class position
* @param documentClass Document class
* @param numberContext Number context
* @throws AVM2ParseException On parsing error
* @throws CompilationException On compilation error
*/
public void addScriptFromTree(List<List<NamespaceItem>> allOpenedNamespaces, List<GraphTargetItem> items, int classPos, String documentClass, Integer numberContext) throws AVM2ParseException, CompilationException {
public void addScriptFromTree(List<AssignableAVM2Item> sinitVariables, boolean sinitNeedsActivation, List<DottedChain> importedClasses, List<NamespaceItem> openedNamespaces, List<List<NamespaceItem>> allOpenedNamespaces, List<GraphTargetItem> items, int classPos, String documentClass, Integer numberContext) throws AVM2ParseException, CompilationException {
AVM2SourceGenerator gen = new AVM2SourceGenerator(abcIndex);
SourceGeneratorLocalData localData = new SourceGeneratorLocalData(
new HashMap<>(), 0, Boolean.FALSE, 0);
@@ -2815,8 +2908,9 @@ public class ActionScript3Parser {
int scriptIndex = abcIndex.getSelectedAbc().script_info.size();
abcIndex.getSelectedAbc().script_info.add(si);
try {
gen.generateScriptInfo(scriptIndex, si, allOpenedNamespaces, localData, items, classPos);
gen.generateScriptInfo(sinitVariables, sinitNeedsActivation, importedClasses, openedNamespaces, scriptIndex, si, allOpenedNamespaces, localData, items, classPos);
} catch (Exception ex) {
ex.printStackTrace(); // FIXME
abcIndex.getSelectedAbc().script_info.remove(si);
throw ex;
}
@@ -2840,8 +2934,12 @@ public class ActionScript3Parser {
public void addScript(String s, String fileName, int classPos, int scriptIndex, String documentClass, ABC abc) throws AVM2ParseException, IOException, CompilationException, InterruptedException {
List<List<NamespaceItem>> allOpenedNamespaces = new ArrayList<>();
Reference<Integer> numberContextRef = new Reference<>(null);
List<GraphTargetItem> traits = scriptTraitsFromString(allOpenedNamespaces, s, fileName, scriptIndex, numberContextRef, abc);
addScriptFromTree(allOpenedNamespaces, traits, classPos, documentClass, numberContextRef.getVal());
Reference<Boolean> sinitNeedsActivation = new Reference<>(false);
List<AssignableAVM2Item> sinitVariables = new ArrayList<>();
List<DottedChain> importedClasses = new ArrayList<>();
List<NamespaceItem> openedNamespaces = new ArrayList<>();
List<GraphTargetItem> traits = scriptTraitsFromString(importedClasses, openedNamespaces, allOpenedNamespaces, s, fileName, scriptIndex, numberContextRef, abc, sinitNeedsActivation, sinitVariables);
addScriptFromTree(sinitVariables, sinitNeedsActivation.getVal(), importedClasses, openedNamespaces, allOpenedNamespaces, traits, classPos, documentClass, numberContextRef.getVal());
}
/**

View File

@@ -93,16 +93,26 @@ public class NameAVM2Item extends AssignableAVM2Item {
private AbcIndexing abcIndex;
private String namespaceSuffix;
private final boolean isConst;
@Override
public AssignableAVM2Item copy() {
NameAVM2Item c = new NameAVM2Item(type, line, attribute, variableName, namespaceSuffix, assignedValue, definition, openedNamespaces, abcIndex);
NameAVM2Item c = new NameAVM2Item(type, line, attribute, variableName, namespaceSuffix, assignedValue, definition, openedNamespaces, abcIndex, isConst);
c.setNs(ns);
c.regNumber = regNumber;
c.unresolved = unresolved;
c.nsKind = nsKind;
return c;
}
/**
* Checks whether this name is const.
* @return Whether this name is const
*/
public boolean isConst() {
return isConst;
}
/**
* Is attribute.
@@ -235,8 +245,9 @@ public class NameAVM2Item extends AssignableAVM2Item {
* @param definition Is definition
* @param openedNamespaces Opened namespaces
* @param abcIndex ABC index
* @param isConst Is const
*/
public NameAVM2Item(GraphTargetItem type, int line, boolean attribute, String variableName, String namespaceSuffix, GraphTargetItem storeValue, boolean definition, List<NamespaceItem> openedNamespaces, AbcIndexing abcIndex) {
public NameAVM2Item(GraphTargetItem type, int line, boolean attribute, String variableName, String namespaceSuffix, GraphTargetItem storeValue, boolean definition, List<NamespaceItem> openedNamespaces, AbcIndexing abcIndex, boolean isConst) {
super(storeValue);
this.attribute = attribute;
this.variableName = variableName;
@@ -247,6 +258,7 @@ public class NameAVM2Item extends AssignableAVM2Item {
this.type = type;
this.openedNamespaces = openedNamespaces;
this.abcIndex = abcIndex;
this.isConst = isConst;
}
/**

View File

@@ -411,7 +411,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
if (a instanceof NameAVM2Item) {
NameAVM2Item n = (NameAVM2Item) a;
if (n.isDefinition() && name.get(0).equals(n.getVariableName())) {
NameAVM2Item ret = new NameAVM2Item(n.type, n.line, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), null, false, openedNamespaces, abcIndex);
NameAVM2Item ret = new NameAVM2Item(n.type, n.line, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), null, false, openedNamespaces, abcIndex, n.isConst());
ret.setSlotScope(n.getSlotScope());
ret.setSlotNumber(n.getSlotNumber());
ret.setRegNumber(n.getRegNumber());
@@ -441,7 +441,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
t = paramTypes.get(ind);
} //else rest parameter
GraphTargetItem ret = new NameAVM2Item(t, line, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), null, false, openedNamespaces, abcIndex);
GraphTargetItem ret = new NameAVM2Item(t, line, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), null, false, openedNamespaces, abcIndex, false);
resolved = ret;
for (int i = 1; i < name.size(); i++) {
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>());
@@ -627,7 +627,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
}
}
NameAVM2Item ret = new NameAVM2Item(ntype, line, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), null, false, openedNamespaces, abcIndex);
NameAVM2Item ret = new NameAVM2Item(ntype, line, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), null, false, openedNamespaces, abcIndex, false);
resolved = ret;
for (int i = 1; i < name.size(); i++) {
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>());

View File

@@ -25,6 +25,11 @@ import com.jpexs.decompiler.graph.GraphTargetItem;
*/
public class AssignedValue {
/**
* Command
*/
public GraphTargetItem command;
/**
* Value
*/
@@ -43,11 +48,13 @@ public class AssignedValue {
/**
* Constructs a new assigned value.
*
* @param command Command
* @param value Value
* @param initializer Initializer type
* @param method Method index
*/
public AssignedValue(GraphTargetItem value, int initializer, int method) {
public AssignedValue(GraphTargetItem command, GraphTargetItem value, int initializer, int method) {
this.command = command;
this.value = value;
this.initializer = initializer;
this.method = method;

View File

@@ -474,7 +474,7 @@ public final class MethodBody implements Cloneable {
convertedItems1 = converted.getCode().toGraphTargetItems(callStack, abcIndex, convertData.thisHasDefaultToPrimitive, convertData, path, methodIndex, isStatic, scriptIndex, classIndex, abc, converted, localRegNames, scopeStack, initializerType, fullyQualifiedNames, initTraits, 0, new HashMap<>()); //converted.getCode().visitCode(converted)
}
try (Statistics s = new Statistics("Graph.graphToString")) {
Graph.graphToString(convertedItems1, writer, LocalData.create(callStack, abcIndex, abc, localRegNames, fullyQualifiedNames, seenMethods));
Graph.graphToString(convertedItems1, writer, LocalData.create(callStack, abcIndex, abc, localRegNames, fullyQualifiedNames, seenMethods, exportMode));
}
convertedItems = convertedItems1;
}
@@ -565,7 +565,7 @@ public final class MethodBody implements Cloneable {
fullyQualifiedNames2.remove(tname);
}
Graph.graphToString(convertedItems, writer, LocalData.create(callStack, abcIndex, abc, localRegNames, fullyQualifiedNames2, seenMethods));
Graph.graphToString(convertedItems, writer, LocalData.create(callStack, abcIndex, abc, localRegNames, fullyQualifiedNames2, seenMethods, exportMode));
//writer.endMethod();
} else if (convertException instanceof TimeoutException) {
// exception was logged in convert method

View File

@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ClassPath;
import com.jpexs.decompiler.flash.abc.ScriptPack;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.graph.DottedChain;
@@ -171,6 +172,9 @@ public class ScriptInfo {
for (int j = 0; j < traits.traits.size(); j++) {
Trait t = traits.traits.get(j);
if (!isSimple && (t instanceof TraitSlotConst)) {
continue;
}
Multiname name = t.getName(abc);
int nskind = name.getSimpleNamespaceKind(abc.constants);
if ((nskind == Namespace.KIND_PACKAGE_INTERNAL)

View File

@@ -644,13 +644,16 @@ public abstract class Trait implements Cloneable, Serializable {
}
}
}
String nsPrefix = Namespace.getPrefix(nskind);
if (nsPrefix != null && !nsPrefix.isEmpty()) {
writer.appendNoHilight(nsPrefix).appendNoHilight(" ");
if (!(classIndex == -1 && nskind == Namespace.KIND_PACKAGE_INTERNAL)) {
String nsPrefix = Namespace.getPrefix(nskind);
if (nsPrefix != null && !nsPrefix.isEmpty()) {
writer.appendNoHilight(nsPrefix).appendNoHilight(" ");
}
}
}
}
if (isStatic) {
if (isStatic && classIndex > -1) {
if ((this instanceof TraitSlotConst) && ((TraitSlotConst) this).isNamespace()) {
//static is automatic
} else {

View File

@@ -234,7 +234,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
String instanceInfoName = instanceInfoMultiname.getName(abc.constants, fullyQualifiedNames, false, true);
getMetaData(parent, convertData, abc, writer);
getMetaData(this, convertData, abc, writer);
boolean allowEmbed = true;
@@ -284,11 +284,11 @@ public class TraitClass extends Trait implements TraitWithSlot {
writer.startMethod(classInfo.cinit_index, "cinit");
if (exportMode != ScriptExportMode.AS_METHOD_STUBS) {
if (!classInitializerIsEmpty) {
writer.startBlock();
//writer.startBlock();
List<MethodBody> callStack = new ArrayList<>();
callStack.add(abc.bodies.get(bodyIndex));
abc.bodies.get(bodyIndex).toString(callStack, abcIndex, path + "/" + instanceInfoName + ".staticinitializer", exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>());
writer.endBlock();
//writer.endBlock();
} else {
//Note: There must be trait/method highlight even if the initializer is empty to TraitList in GUI to work correctly
//TODO: handle this better in GUI(?)
@@ -297,9 +297,9 @@ public class TraitClass extends Trait implements TraitWithSlot {
}
writer.endMethod();
writer.endTrait();
if (!classInitializerIsEmpty) {
/*if (!classInitializerIsEmpty) {
writer.newLine();
}
}*/
} else {
//"/*classInitializer*/";
}

View File

@@ -162,7 +162,7 @@ public class TraitFunction extends Trait implements TraitWithSlot {
@Override
public GraphTextWriter toString(AbcIndexing abcIndex, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel, boolean insideInterface) throws InterruptedException {
writeImports(abcIndex, scriptIndex, classIndex, false, abc, writer, getPackage(abc), fullyQualifiedNames);
getMetaData(parent, convertData, abc, writer);
getMetaData(this, convertData, abc, writer);
writer.startMethod(method_info, getName(abc).getName(abc.constants, new ArrayList<>(), true, false));
toStringHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel, insideInterface);

View File

@@ -240,7 +240,7 @@ public class TraitMethodGetterSetter extends Trait {
if (classIndex < 0) {
writeImports(abcIndex, scriptIndex, classIndex, isStatic, abc, writer, getPackage(abc), fullyQualifiedNames);
}
getMetaData(parent, convertData, abc, writer);
getMetaData(this, convertData, abc, writer);
writer.startMethod(method_info, getName(abc).getName(abc.constants, new ArrayList<>(), true, false));
path = path + "." + getName(abc).getName(abc.constants, fullyQualifiedNames, false, true);
toStringHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel, insideInterface);

View File

@@ -166,14 +166,13 @@ public class TraitSlotConst extends Trait implements TraitWithSlot {
*
* @param abcIndex ABC indexing
* @param exportMode Export mode
* @param parent Parent
* @param convertData Convert data
* @param writer Writer
* @param abc ABC
* @param fullyQualifiedNames Fully qualified names
* @throws InterruptedException On interrupt
*/
public void getValueStr(AbcIndexing abcIndex, ScriptExportMode exportMode, Trait parent, ConvertData convertData, GraphTextWriter writer, ABC abc, List<DottedChain> fullyQualifiedNames) throws InterruptedException {
public void getValueStr(AbcIndexing abcIndex, ScriptExportMode exportMode, ConvertData convertData, GraphTextWriter writer, ABC abc, List<DottedChain> fullyQualifiedNames) throws InterruptedException {
if (convertData.assignedValues.containsKey(this)) {
AssignedValue assignment = convertData.assignedValues.get(this);
@@ -189,7 +188,7 @@ public class TraitSlotConst extends Trait implements TraitWithSlot {
if (exportMode != ScriptExportMode.AS_METHOD_STUBS) {
List<MethodBody> callStack = new ArrayList<>();
callStack.add(abc.bodies.get(abc.findBodyIndex(assignment.method)));
assignment.value.toString(writer, LocalData.create(callStack, abcIndex, abc, new HashMap<>(), fullyQualifiedNames, new HashSet<>()));
assignment.value.toString(writer, LocalData.create(callStack, abcIndex, abc, new HashMap<>(), fullyQualifiedNames, new HashSet<>(), exportMode));
}
writer.endMethod();
writer.endTrait();
@@ -252,7 +251,7 @@ public class TraitSlotConst extends Trait implements TraitWithSlot {
*/
@Override
public GraphTextWriter toString(AbcIndexing abcIndex, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel, boolean insideInterface) throws InterruptedException {
getMetaData(parent, convertData, abc, writer);
getMetaData(this, convertData, abc, writer);
Multiname n = getName(abc);
boolean showModifier = true;
if ((classIndex == -1) && (n != null)) {
@@ -272,13 +271,13 @@ public class TraitSlotConst extends Trait implements TraitWithSlot {
List<MethodBody> callStack = new ArrayList<>();
AssignedValue assignment = convertData.assignedValues.get(this);
callStack.add(abc.bodies.get(abc.findBodyIndex(assignment.method)));
return val.toString(writer, LocalData.create(callStack, abcIndex, abc, new HashMap<>(), fullyQualifiedNames, new HashSet<>()));
return val.toString(writer, LocalData.create(callStack, abcIndex, abc, new HashMap<>(), fullyQualifiedNames, new HashSet<>(), exportMode));
}
}
getNameStr(writer, abc, fullyQualifiedNames);
if (hasValueStr(abc, convertData)) {
writer.appendNoHilight(" = ");
getValueStr(abcIndex, exportMode, parent, convertData, writer, abc, fullyQualifiedNames);
getValueStr(abcIndex, exportMode, convertData, writer, abc, fullyQualifiedNames);
}
return writer.appendNoHilight(";").newLine();
}
@@ -305,7 +304,7 @@ public class TraitSlotConst extends Trait implements TraitWithSlot {
public void convert(AbcIndexing abcIndex, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel, ScopeStack scopeStack) throws InterruptedException {
getNameStr(writer, abc, fullyQualifiedNames);
if (hasValueStr(abc, convertData)) {
getValueStr(abcIndex, exportMode, parent, convertData, writer, abc, fullyQualifiedNames);
getValueStr(abcIndex, exportMode, convertData, writer, abc, fullyQualifiedNames);
}
}

View File

@@ -316,7 +316,7 @@ public class Traits implements Cloneable, Serializable {
*/
public GraphTextWriter toString(AbcIndexing abcIndex, Class[] traitTypes, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, boolean makePackages, int scriptIndex, int classIndex, GraphTextWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel, List<String> ignoredTraitNames, boolean insideInterface) throws InterruptedException {
List<Trait> ordered = new ArrayList<>(traits);
/*List<Trait> ordered = new ArrayList<>(traits);
loopi:
for (int i = 0; i < ordered.size(); i++) {
for (int j = i + 1; j < ordered.size(); j++) {
@@ -356,7 +356,9 @@ public class Traits implements Cloneable, Serializable {
}
}
}
*/
List<Trait> ordered = traits;
for (Trait trait : ordered) {
int t = traits.indexOf(trait);
if (traitTypes != null) {
@@ -377,8 +379,13 @@ public class Traits implements Cloneable, Serializable {
if (ignoredTraitNames.contains(trait.getName(abc).getName(abc.constants, new ArrayList<>(), false, false))) {
continue;
}
writer.newLine();
int h = abc.getGlobalTraitId(TraitType.METHOD /*non-initializer*/, isStatic, classIndex, t);
if ((trait instanceof TraitSlotConst) && convertData.assignedValues.containsKey((TraitSlotConst) trait)) {
continue;
}
writer.newLine();
int h = abc.getGlobalTraitId(TraitType.METHOD , isStatic, classIndex, t);
writer.startTrait(h);
if (makePackages) {
trait.toStringPackaged(abcIndex, parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel, insideInterface);

View File

@@ -3872,12 +3872,21 @@ public class Graph {
* @throws InterruptedException On interrupt
*/
public static GraphTextWriter graphToString(List<GraphTargetItem> tree, GraphTextWriter writer, LocalData localData) throws InterruptedException {
boolean lastNewLine = false;
for (GraphTargetItem ti : tree) {
if (!ti.isEmpty()) {
ti.toStringSemicoloned(writer, localData);
if (ti.hasSingleNewLineAround() && !lastNewLine) {
writer.newLine();
}
ti.toStringSemicoloned(writer, localData);
if (!ti.handlesNewLine()) {
writer.newLine();
}
lastNewLine = false;
if (ti.hasSingleNewLineAround()) {
writer.newLine();
lastNewLine = true;
}
}
}
return writer;

View File

@@ -767,6 +767,14 @@ public abstract class GraphTargetItem implements Serializable, Cloneable {
public boolean handlesNewLine() {
return false;
}
/**
* Checks whether this item needs single newline before and after.
* @return True if needs
*/
public boolean hasSingleNewLineAround() {
return false;
}
/**
* Converts this to string with new line.

View File

@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.action.model.ConstantPool;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.graph.DottedChain;
import java.util.HashMap;
import java.util.HashSet;
@@ -78,6 +79,11 @@ public class LocalData {
* ABC
*/
public ABC abc;
/**
* Script export mode
*/
public ScriptExportMode exportMode;
/**
* Creates a new local data
@@ -99,9 +105,10 @@ public class LocalData {
* @param localRegNames Local register names
* @param fullyQualifiedNames Fully qualified names
* @param seenMethods Seen methods
* @param exportMode
* @return Local data
*/
public static LocalData create(List<MethodBody> callStack, AbcIndexing abcIndex, ABC abc, HashMap<Integer, String> localRegNames, List<DottedChain> fullyQualifiedNames, Set<Integer> seenMethods) {
public static LocalData create(List<MethodBody> callStack, AbcIndexing abcIndex, ABC abc, HashMap<Integer, String> localRegNames, List<DottedChain> fullyQualifiedNames, Set<Integer> seenMethods, ScriptExportMode exportMode) {
LocalData localData = new LocalData();
localData.abc = abc;
localData.constantsAvm2 = abc.constants;
@@ -110,6 +117,7 @@ public class LocalData {
localData.seenMethods = seenMethods;
localData.abcIndex = abcIndex;
localData.callStack = callStack;
localData.exportMode = exportMode;
return localData;
}
}