/*
* Copyright (C) 2010-2016 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.parser.script;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructSuperIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns;
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.ApplyTypeAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.BooleanAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FloatValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.GetDescendantsAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NameValuePair;
import com.jpexs.decompiler.flash.abc.avm2.model.NanAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NewObjectAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
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.StringAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.ThrowAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.WithAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.WithObjectAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForEachInAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForInAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.TryAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.operations.IfCondition;
import com.jpexs.decompiler.flash.abc.avm2.parser.AVM2ParseException;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing.ClassIndex;
import com.jpexs.decompiler.flash.abc.types.ABCException;
import com.jpexs.decompiler.flash.abc.types.ClassInfo;
import com.jpexs.decompiler.flash.abc.types.ConvertData;
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
import com.jpexs.decompiler.flash.abc.types.MetadataInfo;
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.ScriptInfo;
import com.jpexs.decompiler.flash.abc.types.ValueKind;
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.TraitFunction;
import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.NulWriter;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.Loop;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.decompiler.graph.SourceGenerator;
import com.jpexs.decompiler.graph.TypeItem;
import com.jpexs.decompiler.graph.model.AndItem;
import com.jpexs.decompiler.graph.model.BreakItem;
import com.jpexs.decompiler.graph.model.CommaExpressionItem;
import com.jpexs.decompiler.graph.model.ContinueItem;
import com.jpexs.decompiler.graph.model.DefaultItem;
import com.jpexs.decompiler.graph.model.DoWhileItem;
import com.jpexs.decompiler.graph.model.DuplicateItem;
import com.jpexs.decompiler.graph.model.FalseItem;
import com.jpexs.decompiler.graph.model.ForItem;
import com.jpexs.decompiler.graph.model.IfItem;
import com.jpexs.decompiler.graph.model.LocalData;
import com.jpexs.decompiler.graph.model.NotItem;
import com.jpexs.decompiler.graph.model.OrItem;
import com.jpexs.decompiler.graph.model.PopItem;
import com.jpexs.decompiler.graph.model.PushItem;
import com.jpexs.decompiler.graph.model.SwitchItem;
import com.jpexs.decompiler.graph.model.TernarOpItem;
import com.jpexs.decompiler.graph.model.TrueItem;
import com.jpexs.decompiler.graph.model.UnboundedTypeItem;
import com.jpexs.decompiler.graph.model.WhileItem;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
* @author JPEXS
*/
public class AVM2SourceGenerator implements SourceGenerator {
public final AbcIndexing abcIndex;
public static final int MARK_E_START = 0;
public static final int MARK_E_END = 1;
public static final int MARK_E_TARGET = 2;
public static final int MARK_E_FINALLYPART = 3;
private AVM2Instruction ins(int instructionCode, int... operands) {
return new AVM2Instruction(0, instructionCode, operands);
}
private AVM2Instruction ins(InstructionDefinition def, int... operands) {
return new AVM2Instruction(0, def, operands);
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, FalseItem item) throws CompilationException {
return GraphTargetItem.toSourceMerge(localData, this, ins(AVM2Instructions.PushFalse));
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, TrueItem item) throws CompilationException {
return GraphTargetItem.toSourceMerge(localData, this, ins(AVM2Instructions.PushTrue));
}
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, GetDescendantsAVM2Item item) throws CompilationException {
AVM2ConstantPool constants = abcIndex.getSelectedAbc().constants;
int[] nssa = new int[item.openedNamespaces.size()];
for (int i = 0; i < item.openedNamespaces.size(); i++) {
nssa[i] = item.openedNamespaces.get(i).getCpoolIndex(abcIndex);
}
int nsset = constants.getNamespaceSetId(nssa, true);
return GraphTargetItem.toSourceMerge(localData, this,
item.object,
ins(AVM2Instructions.GetDescendants, constants.getMultinameId(Multiname.createMultiname(false, constants.getStringId(item.nameStr, true), nsset), true))
);
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, AndItem item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
ret.addAll(generateToActionList(localData, item.leftSide));
ret.add(ins(AVM2Instructions.Dup));
if (!("" + item.leftSide.returnType()).equals("Boolean")) {
ret.add(ins(AVM2Instructions.ConvertB));
}
List<AVM2Instruction> andExpr = generateToActionList(localData, item.rightSide);
andExpr.add(0, ins(AVM2Instructions.Pop));
int andExprLen = insToBytes(andExpr).length;
ret.add(ins(AVM2Instructions.IfFalse, andExprLen));
ret.addAll(andExpr);
return ret;
}
private byte[] insToBytes(List<AVM2Instruction> code) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (AVM2Instruction instruction : code) {
baos.write(instruction.getBytes());
}
return baos.toByteArray();
} catch (IOException ex) {
Logger.getLogger(AVM2SourceGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
return SWFInputStream.BYTE_ARRAY_EMPTY;
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, OrItem item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
ret.addAll(generateToActionList(localData, item.leftSide));
ret.add(ins(AVM2Instructions.Dup));
if (!("" + item.leftSide.returnType()).equals("Boolean")) {
ret.add(ins(AVM2Instructions.ConvertB));
}
List<AVM2Instruction> orExpr = generateToActionList(localData, item.rightSide);
orExpr.add(0, ins(AVM2Instructions.Pop));
int orExprLen = insToBytes(orExpr).length;
ret.add(ins(AVM2Instructions.IfTrue, orExprLen));
ret.addAll(orExpr);
return ret;
}
public ArrayList<AVM2Instruction> toInsList(List<GraphSourceItem> items) {
ArrayList<AVM2Instruction> ret = new ArrayList<>();
for (GraphSourceItem s : items) {
if (s instanceof AVM2Instruction) {
ret.add((AVM2Instruction) s);
}
}
return ret;
}
private List<AVM2Instruction> nonempty(List<AVM2Instruction> list) {
if (list == null) {
return new ArrayList<>();
}
return list;
}
private List<GraphSourceItem> condition(SourceGeneratorLocalData localData, GraphTargetItem t, int offset) throws CompilationException {
if (t instanceof IfCondition) {
IfCondition ic = (IfCondition) t;
return GraphTargetItem.toSourceMerge(localData, this, ic.getLeftSide(), ic.getRightSide(), ins(ic.getIfDefinition(), offset));
}
return GraphTargetItem.toSourceMerge(localData, this, t, ins(AVM2Instructions.IfTrue, offset));
}
private List<GraphSourceItem> notCondition(SourceGeneratorLocalData localData, GraphTargetItem t, int offset) throws CompilationException {
if (t instanceof IfCondition) {
IfCondition ic = (IfCondition) t;
return GraphTargetItem.toSourceMerge(localData, this, ic.getLeftSide(), ic.getRightSide(), ins(ic.getIfNotDefinition(), offset));
}
return GraphTargetItem.toSourceMerge(localData, this, t, ins(AVM2Instructions.IfFalse, offset));
}
private List<GraphSourceItem> generateIf(SourceGeneratorLocalData localData, GraphTargetItem expression, List<GraphTargetItem> onTrueCmds, List<GraphTargetItem> onFalseCmds, boolean ternar) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
//ret.addAll(notCondition(localData, expression));
List<AVM2Instruction> onTrue;
List<AVM2Instruction> onFalse = null;
if (ternar) {
onTrue = toInsList(onTrueCmds.get(0).toSource(localData, this));
} else {
onTrue = generateToInsList(localData, onTrueCmds);
}
if (onFalseCmds != null && !onFalseCmds.isEmpty()) {
if (ternar) {
onFalse = toInsList(onFalseCmds.get(0).toSource(localData, this));
} else {
onFalse = generateToInsList(localData, onFalseCmds);
}
}
AVM2Instruction ajmp = null;
if (onFalse != null) {
if (!((!nonempty(onTrue).isEmpty())
&& ((onTrue.get(onTrue.size() - 1).definition instanceof ContinueJumpIns)
|| ((onTrue.get(onTrue.size() - 1).definition instanceof BreakJumpIns))))) {
ajmp = ins(AVM2Instructions.Jump, 0);
onTrue.add(ajmp);
}
}
byte[] onTrueBytes = insToBytes(onTrue);
int onTrueLen = onTrueBytes.length;
ret.addAll(notCondition(localData, expression, onTrueLen));
ret.addAll(onTrue);
if (onFalse != null) {
byte[] onFalseBytes = insToBytes(onFalse);
int onFalseLen = onFalseBytes.length;
if (ajmp != null) {
ajmp.operands[0] = onFalseLen;
}
ret.addAll(onFalse);
}
return ret;
}
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, XMLFilterAVM2Item item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
final Reference<Integer> counterReg = new Reference<>(0);
final Reference<Integer> collectionReg = new Reference<>(0);
final Reference<Integer> xmlListReg = new Reference<>(0);
List<GraphSourceItem> xmlListSetTemp = AssignableAVM2Item.setTemp(localData, this, xmlListReg);
AVM2ConstantPool constants = abcIndex.getSelectedAbc().constants;
ret.addAll(GraphTargetItem.toSourceMerge(localData, this,
ins(AVM2Instructions.PushByte, 0),
AssignableAVM2Item.setTemp(localData, this, counterReg),
item.object,
ins(AVM2Instructions.CheckFilter),
NameAVM2Item.generateCoerce(localData, this, TypeItem.UNBOUNDED),
AssignableAVM2Item.setTemp(localData, this, collectionReg),
ins(AVM2Instructions.GetLex, constants.getMultinameId(Multiname.createQName(false, constants.getStringId("XMLList", true), constants.getNamespaceId(Namespace.KIND_PACKAGE, "", 0, true)), true)),
ins(AVM2Instructions.PushString, constants.getStringId("", true)),
ins(AVM2Instructions.Construct, 1),
xmlListSetTemp
));
final Reference<Integer> tempVal1 = new Reference<>(0);
final Reference<Integer> tempVal2 = new Reference<>(0);
List<AVM2Instruction> forBody = toInsList(GraphTargetItem.toSourceMerge(localData, this,
ins(AVM2Instructions.Label),
AssignableAVM2Item.getTemp(localData, this, collectionReg),
AssignableAVM2Item.getTemp(localData, this, counterReg),
ins(AVM2Instructions.NextValue),
AssignableAVM2Item.dupSetTemp(localData, this, tempVal1),
AssignableAVM2Item.dupSetTemp(localData, this, tempVal2),
ins(AVM2Instructions.PushWith)
));
localData.scopeStack.add(new LocalRegAVM2Item(null, null, tempVal2.getVal(), null));
forBody.addAll(toInsList(item.value.toSource(localData, this)));
List<AVM2Instruction> trueBody = new ArrayList<>();
trueBody.addAll(toInsList(AssignableAVM2Item.getTemp(localData, this, xmlListReg)));
trueBody.addAll(toInsList(AssignableAVM2Item.getTemp(localData, this, counterReg)));
trueBody.addAll(toInsList(AssignableAVM2Item.getTemp(localData, this, tempVal1)));
trueBody.add(ins(AVM2Instructions.SetProperty, constants.getMultinameId(Multiname.createMultinameL(false, NamespaceItem.getCpoolSetIndex(abcIndex, item.openedNamespaces)), true)));
forBody.add(ins(AVM2Instructions.IfFalse, insToBytes(trueBody).length));
forBody.addAll(trueBody);
forBody.add(ins(AVM2Instructions.PopScope));
localData.scopeStack.remove(localData.scopeStack.size() - 1);
forBody.addAll(toInsList(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(tempVal2, tempVal1))));
int forBodyLen = insToBytes(forBody).length;
AVM2Instruction forwardJump = ins(AVM2Instructions.Jump, forBodyLen);
ret.add(forwardJump);
List<AVM2Instruction> expr = new ArrayList<>();
expr.add(ins(AVM2Instructions.HasNext2, collectionReg.getVal(), counterReg.getVal()));
AVM2Instruction backIf = ins(AVM2Instructions.IfTrue, 0);
expr.add(backIf);
int exprLen = insToBytes(expr).length;
backIf.operands[0] = -(exprLen + forBodyLen);
ret.addAll(forBody);
ret.addAll(expr);
ret.addAll(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(collectionReg, counterReg)));
ret.addAll(AssignableAVM2Item.getTemp(localData, this, xmlListReg));
ret.addAll(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(xmlListReg)));
return ret;
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, IfItem item) throws CompilationException {
return generateIf(localData, item.expression, item.onTrue, item.onFalse, false);
}
private void fixSwitch(List<AVM2Instruction> code, int breakOffset, long loopId) {
fixLoop(code, breakOffset, Integer.MAX_VALUE, loopId);
}
private void fixLoop(List<AVM2Instruction> code, int breakOffset, int continueOffset, long loopId) {
int pos = 0;
for (int a = 0; a < code.size(); a++) {
AVM2Instruction ins = code.get(a);
pos += ins.getBytesLength();
if (ins.definition instanceof JumpIns) {
if (ins.definition instanceof ContinueJumpIns) {
if (continueOffset != Integer.MAX_VALUE) {
ins.operands[0] = (-pos + continueOffset);
ins.definition = AVM2Code.instructionSet[AVM2Instructions.Jump];
}
}
if (ins.definition instanceof BreakJumpIns) {
ins.operands[0] = (-pos + breakOffset);
ins.definition = AVM2Code.instructionSet[AVM2Instructions.Jump];
}
}
}
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, TernarOpItem item) throws CompilationException {
List<GraphTargetItem> onTrue = new ArrayList<>();
onTrue.add(item.onTrue);
List<GraphTargetItem> onFalse = new ArrayList<>();
onFalse.add(item.onFalse);
return generateIf(localData, item.expression, onTrue, onFalse, true);
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, WhileItem item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
List<AVM2Instruction> whileExpr = new ArrayList<>();
List<GraphTargetItem> ex = new ArrayList<>(item.expression);
GraphTargetItem lastItem = null;
if (!ex.isEmpty()) {
lastItem = ex.remove(ex.size() - 1);
while (lastItem instanceof CommaExpressionItem) {
CommaExpressionItem cei = (CommaExpressionItem) lastItem;
ex.addAll(cei.commands);
lastItem = ex.remove(ex.size() - 1);
}
whileExpr.addAll(generateToInsList(localData, ex));
}
List<AVM2Instruction> whileBody = generateToInsList(localData, item.commands);
AVM2Instruction forwardJump = ins(AVM2Instructions.Jump, 0);
ret.add(forwardJump);
whileBody.add(0, ins(AVM2Instructions.Label));
ret.addAll(whileBody);
int whileBodyLen = insToBytes(whileBody).length;
forwardJump.operands[0] = whileBodyLen;
whileExpr.addAll(toInsList(condition(localData, lastItem, 0)));
int whileExprLen = insToBytes(whileExpr).length;
whileExpr.get(whileExpr.size() - 1).operands[0] = -(whileExprLen + whileBodyLen); //Assuming last is if instruction
ret.addAll(whileExpr);
fixLoop(whileBody, whileBodyLen + whileExprLen, whileBodyLen, item.loop.id);
return ret;
}
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, ForEachInAVM2Item item) throws CompilationException {
return generateForIn(localData, item.loop, item.expression.collection, (AssignableAVM2Item) item.expression.object, item.commands, true);
}
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, ForInAVM2Item item) throws CompilationException {
return generateForIn(localData, item.loop, item.expression.collection, (AssignableAVM2Item) item.expression.object, item.commands, false);
}
public List<GraphSourceItem> generateForIn(SourceGeneratorLocalData localData, Loop loop, GraphTargetItem collection, AssignableAVM2Item assignable, List<GraphTargetItem> commands, final boolean each) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
final Reference<Integer> counterReg = new Reference<>(0);
final Reference<Integer> collectionReg = new Reference<>(0);
if (assignable instanceof UnresolvedAVM2Item) {
assignable = (AssignableAVM2Item) ((UnresolvedAVM2Item) assignable).resolved;
}
ret.addAll(GraphTargetItem.toSourceMerge(localData, this,
ins(AVM2Instructions.PushByte, 0),
AssignableAVM2Item.setTemp(localData, this, counterReg),
collection,
NameAVM2Item.generateCoerce(localData, this, TypeItem.UNBOUNDED),
AssignableAVM2Item.setTemp(localData, this, collectionReg)
));
GraphTargetItem assigned = new GraphTargetItem() {
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
return null;
}
@Override
public boolean hasReturnValue() {
return true;
}
@Override
public GraphTargetItem returnType() {
return TypeItem.UNBOUNDED;
}
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
return toSourceMerge(localData, generator,
AssignableAVM2Item.getTemp(localData, generator, collectionReg),
AssignableAVM2Item.getTemp(localData, generator, counterReg),
ins(each ? AVM2Instructions.NextValue : AVM2Instructions.NextName)
);
}
};
assignable.setAssignedValue(assigned);
List<AVM2Instruction> forBody = toInsList(GraphTargetItem.toSourceMerge(localData, this,
ins(AVM2Instructions.Label),
assignable.toSourceIgnoreReturnValue(localData, this)
));
forBody.addAll(generateToInsList(localData, commands));
int forBodyLen = insToBytes(forBody).length;
AVM2Instruction forwardJump = ins(AVM2Instructions.Jump, forBodyLen);
ret.add(forwardJump);
List<AVM2Instruction> expr = new ArrayList<>();
expr.add(ins(AVM2Instructions.HasNext2, collectionReg.getVal(), counterReg.getVal()));
AVM2Instruction backIf = ins(AVM2Instructions.IfTrue, 0);
expr.add(backIf);
int exprLen = insToBytes(expr).length;
backIf.operands[0] = -(exprLen + forBodyLen);
fixLoop(forBody, forBodyLen + exprLen, forBodyLen, loop.id);
ret.addAll(forBody);
ret.addAll(expr);
ret.addAll(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(collectionReg, counterReg)));
return ret;
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, DoWhileItem item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
List<AVM2Instruction> whileExpr = new ArrayList<>();
List<GraphTargetItem> ex = new ArrayList<>(item.expression);
GraphTargetItem lastItem = null;
if (!ex.isEmpty()) {
lastItem = ex.remove(ex.size() - 1);
while (lastItem instanceof CommaExpressionItem) {
CommaExpressionItem cei = (CommaExpressionItem) lastItem;
ex.addAll(cei.commands);
lastItem = ex.remove(ex.size() - 1);
}
whileExpr.addAll(generateToInsList(localData, ex));
}
List<AVM2Instruction> dowhileBody = generateToInsList(localData, item.commands);
List<AVM2Instruction> labelBody = new ArrayList<>();
labelBody.add(ins(AVM2Instructions.Label));
int labelBodyLen = insToBytes(labelBody).length;
AVM2Instruction forwardJump = ins(AVM2Instructions.Jump, labelBodyLen);
ret.add(forwardJump);
ret.addAll(labelBody);
ret.addAll(dowhileBody);
int dowhileBodyLen = insToBytes(dowhileBody).length;
whileExpr.addAll(toInsList(condition(localData, lastItem, 0)));
int dowhileExprLen = insToBytes(whileExpr).length;
whileExpr.get(whileExpr.size() - 1).operands[0] = -(dowhileExprLen + dowhileBodyLen + labelBodyLen); //Assuming last is if instruction
ret.addAll(whileExpr);
fixLoop(dowhileBody, dowhileBodyLen + dowhileExprLen, dowhileBodyLen, item.loop.id);
return ret;
}
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, WithAVM2Item item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
ret.addAll(item.scope.toSource(localData, this));
Reference<Integer> tempReg = new Reference<>(0);
ret.addAll(AssignableAVM2Item.dupSetTemp(localData, this, tempReg));
localData.scopeStack.add(new WithObjectAVM2Item(null, null, new LocalRegAVM2Item(null, null, tempReg.getVal(), null)));
ret.add(ins(AVM2Instructions.PushWith));
ret.addAll(generate(localData, item.items));
ret.add(ins(AVM2Instructions.PopScope));
ret.addAll(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(tempReg)));
localData.scopeStack.remove(localData.scopeStack.size() - 1);
return ret;
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, ForItem item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
List<AVM2Instruction> forExpr = new ArrayList<>();
List<GraphTargetItem> ex = new ArrayList<>();
if (item.expression != null) {
ex.add(item.expression);
} else {
ex.add(new BooleanAVM2Item(null, null, true));
}
GraphTargetItem lastItem = null;
if (!ex.isEmpty()) {
lastItem = ex.remove(ex.size() - 1);
while (lastItem instanceof CommaExpressionItem) {
CommaExpressionItem cei = (CommaExpressionItem) lastItem;
ex.addAll(cei.commands);
lastItem = ex.remove(ex.size() - 1);
}
forExpr.addAll(generateToInsList(localData, ex));
}
List<AVM2Instruction> forBody = generateToInsList(localData, item.commands);
List<AVM2Instruction> forFinalCommands = generateToInsList(localData, item.finalCommands);
ret.addAll(generateToInsList(localData, item.firstCommands));
AVM2Instruction forwardJump = ins(AVM2Instructions.Jump, 0);
ret.add(forwardJump);
forBody.add(0, ins(AVM2Instructions.Label));
ret.addAll(forBody);
ret.addAll(forFinalCommands);
int forBodyLen = insToBytes(forBody).length;
int forFinalCLen = insToBytes(forFinalCommands).length;
forwardJump.operands[0] = forBodyLen + forFinalCLen;
forExpr.addAll(toInsList(condition(localData, lastItem, 0)));
int forExprLen = insToBytes(forExpr).length;
forExpr.get(forExpr.size() - 1).operands[0] = -(forExprLen + forBodyLen + forFinalCLen); //Assuming last is if instruction
ret.addAll(forExpr);
fixLoop(forBody, forBodyLen + forFinalCLen + forExprLen, forBodyLen, item.loop.id);
return ret;
}
private long uniqLast = 0;
public String uniqId() {
uniqLast++;
return "" + uniqLast;
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, SwitchItem item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
Reference<Integer> switchedReg = new Reference<>(0);
AVM2Instruction forwardJump = ins(AVM2Instructions.Jump, 0);
ret.add(forwardJump);
int defIndex = -1;
for (int i = item.caseValues.size() - 1; i >= 0; i--) {
if (item.caseValues.get(i) instanceof DefaultItem) {
defIndex = i;
break;
}
}
List<AVM2Instruction> cases = new ArrayList<>();
cases.addAll(toInsList(new IntegerValueAVM2Item(null, null, (long) defIndex).toSource(localData, this)));
int cLen = insToBytes(cases).length;
List<AVM2Instruction> caseLast = new ArrayList<>();
caseLast.add(0, ins(AVM2Instructions.Jump, cLen));
caseLast.addAll(0, toInsList(new IntegerValueAVM2Item(null, null, (long) defIndex).toSource(localData, this)));
int cLastLen = insToBytes(caseLast).length;
caseLast.add(0, ins(AVM2Instructions.Jump, cLastLen));
cases.addAll(0, caseLast);
List<AVM2Instruction> preCases = new ArrayList<>();
preCases.addAll(toInsList(item.switchedObject.toSource(localData, this)));
preCases.addAll(toInsList(AssignableAVM2Item.setTemp(localData, this, switchedReg)));
for (int i = item.caseValues.size() - 1; i >= 0; i--) {
if (item.caseValues.get(i) instanceof DefaultItem) {
continue;
}
List<AVM2Instruction> sub = new ArrayList<>();
sub.addAll(toInsList(new IntegerValueAVM2Item(null, null, (long) i).toSource(localData, this)));
sub.add(ins(AVM2Instructions.Jump, insToBytes(cases).length));
int subLen = insToBytes(sub).length;
cases.addAll(0, sub);
cases.add(0, ins(AVM2Instructions.IfStrictNe, subLen));
cases.addAll(0, toInsList(AssignableAVM2Item.getTemp(localData, this, switchedReg)));
cases.addAll(0, toInsList(item.caseValues.get(i).toSource(localData, this)));
}
cases.addAll(0, preCases);
AVM2Instruction lookupOp = new AVM2Instruction(0, AVM2Instructions.LookupSwitch, new int[item.caseValues.size() + 1 + 1]);
cases.addAll(toInsList(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(switchedReg))));
List<AVM2Instruction> bodies = new ArrayList<>();
List<Integer> bodiesOffsets = new ArrayList<>();
int defOffset;
int casesLen = insToBytes(cases).length;
bodies.add(0, ins(AVM2Instructions.Label));
bodies.add(ins(new BreakJumpIns(item.loop.id), 0)); //There could be two breaks when default clause ends with break, but official compiler does this too, so who cares...
defOffset = -(insToBytes(bodies).length + casesLen);
for (int i = item.caseCommands.size() - 1; i >= 0; i--) {
bodies.addAll(0, generateToInsList(localData, item.caseCommands.get(i)));
bodies.add(0, ins(AVM2Instructions.Label));
bodiesOffsets.add(0, -(insToBytes(bodies).length + casesLen));
}
lookupOp.operands[0] = defOffset;
lookupOp.operands[1] = item.valuesMapping.size();
for (int i = 0; i < item.valuesMapping.size(); i++) {
lookupOp.operands[2 + i] = bodiesOffsets.get(item.valuesMapping.get(i));
}
forwardJump.operands[0] = insToBytes(bodies).length;
ret.addAll(bodies);
ret.addAll(cases);
ret.add(lookupOp);
fixSwitch(toInsList(ret), insToBytes(toInsList(ret)).length, uniqLast);
return ret;
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, NotItem item) throws CompilationException {
/*if (item.getOriginal() instanceof Inverted) {
GraphTargetItem norig = ((Inverted) item).invert();
return norig.toSource(localData, this);
}*/
List<GraphSourceItem> ret = new ArrayList<>();
ret.addAll(item.getOriginal().toSource(localData, this));
ret.add(ins(AVM2Instructions.Not));
return ret;
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, DuplicateItem item) {
List<GraphSourceItem> ret = new ArrayList<>();
ret.add(ins(AVM2Instructions.Dup));
return ret;
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, BreakItem item) {
List<GraphSourceItem> ret = new ArrayList<>();
AVM2Instruction abreak = ins(new BreakJumpIns(item.loopId), 0);
ret.add(abreak);
return ret;
}
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, FunctionAVM2Item item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
int scope = 0;
if (!item.functionName.isEmpty()) {
ret.add(ins(AVM2Instructions.NewObject, 0));
ret.add(ins(AVM2Instructions.PushWith));
scope = localData.scopeStack.size();
localData.scopeStack.add(new PropertyAVM2Item(null, item.functionName, abcIndex, new ArrayList<>(), localData.callStack));
}
AVM2ConstantPool constants = abcIndex.getSelectedAbc().constants;
ret.add(ins(AVM2Instructions.NewFunction, method(false, constants.getStringId(item.functionName, true), true, false, localData.callStack, localData.pkg, item.needsActivation, item.subvariables, 0 /*Set later*/, item.hasRest, item.line, localData.currentClass, null, false, localData, item.paramTypes, item.paramNames, item.paramValues, item.body, item.retType)));
if (!item.functionName.isEmpty()) {
ret.add(ins(AVM2Instructions.Dup));
ret.add(ins(AVM2Instructions.GetScopeObject, scope));
ret.add(ins(AVM2Instructions.Swap));
ret.add(ins(AVM2Instructions.SetProperty, constants.getMultinameId(Multiname.createQName(false, constants.getStringId(item.functionName, true), constants.getNamespaceId(Namespace.KIND_PACKAGE, localData.pkg, 0, true)), true)));
ret.add(ins(AVM2Instructions.PopScope));
localData.scopeStack.remove(localData.scopeStack.size() - 1);
}
return ret;
}
private static int currentFinId = 1;
private static int finId() {
return currentFinId++;
}
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, TryAVM2Item item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
boolean newFinallyReg = false;
List<ABCException> newex = new ArrayList<>();
int aloneFinallyEx = -1;
int finallyEx = -1;
for (NameAVM2Item e : item.catchExceptions2) {
ABCException aex = new ABCException();
aex.name_index = abcIndex.getSelectedAbc().constants.getMultinameId(Multiname.createQName(false, abcIndex.getSelectedAbc().constants.getStringId(e.getVariableName(), true), abcIndex.getSelectedAbc().constants.getNamespaceId(Namespace.KIND_PACKAGE, "", 0, true)), true);
aex.type_index = typeName(localData, e.type);
newex.add(aex);
}
int finId = 0;
if (item.finallyCommands != null) {
if (item.catchExceptions2.isEmpty()) {
ABCException aex = new ABCException();
aex.name_index = 0;
aex.type_index = 0;
newex.add(aex);
aloneFinallyEx = newex.size() - 1;
}
ABCException aex = new ABCException();
aex.name_index = 0;
aex.type_index = 0;
newex.add(aex);
finallyEx = newex.size() - 1;
if (localData.finallyRegister == -1) {
localData.finallyRegister = getFreeRegister(localData);
killRegister(localData, localData.finallyRegister); //reuse for catches
newFinallyReg = true;
}
finId = finId();
}
if (finallyEx > -1) {
localData.finallyCatches.add(finId);
}
List<AVM2Instruction> tryCmds = generateToInsList(localData, item.tryCommands);
//int i = firstId + item.catchCommands.size() - 1;
List<AVM2Instruction> catches = new ArrayList<>();
Reference<Integer> tempReg = new Reference<>(0);
List<Integer> currentExceptionIds = new ArrayList<>();
List<List<AVM2Instruction>> catchCmds = new ArrayList<>();
for (int c = 0; c < item.catchCommands.size(); c++) {
int i = localData.exceptions.size();
localData.exceptions.add(newex.get(c));
currentExceptionIds.add(i);
//Reference<Integer> tempReg=new Reference<>(0);
List<AVM2Instruction> catchCmd = new ArrayList<>();
catchCmd.add(ins(AVM2Instructions.NewCatch, i));
catchCmd.addAll(toInsList(AssignableAVM2Item.dupSetTemp(localData, this, tempReg)));
catchCmd.add(ins(AVM2Instructions.Dup));
catchCmd.add(ins(AVM2Instructions.PushScope));
catchCmd.add(ins(AVM2Instructions.Swap));
catchCmd.add(ins(AVM2Instructions.SetSlot, 1));
for (AssignableAVM2Item a : item.catchVariables.get(c)) {
GraphTargetItem r = a;
if (r instanceof UnresolvedAVM2Item) {
r = ((UnresolvedAVM2Item) r).resolvedRoot;
}
if (r instanceof NameAVM2Item) {
NameAVM2Item n = (NameAVM2Item) r;
if (item.catchExceptions2.get(c).getVariableName().equals(n.getVariableName())) {
n.setSlotScope(localData.scopeStack.size());
}
}
}
localData.scopeStack.add(new LocalRegAVM2Item(null, null, tempReg.getVal(), null));
catchCmd.addAll(generateToInsList(localData, item.catchCommands.get(c)));
localData.scopeStack.remove(localData.scopeStack.size() - 1);
catchCmd.add(ins(AVM2Instructions.PopScope));
catchCmd.addAll(toInsList(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(tempReg))));
catchCmds.add(catchCmd);
}
for (int c = item.catchCommands.size() - 1; c >= 0; c--) {
List<AVM2Instruction> preCatches = new ArrayList<>();
/*preCatches.add(ins(AVM2Instructions.GetLocal0));
preCatches.add(ins(AVM2Instructions.PushScope));
preCatches.add(AssignableAVM2Item.generateGetLoc(localData.activationReg));
preCatches.add(ins(AVM2Instructions.PushScope));*/
for (GraphTargetItem s : localData.scopeStack) {
preCatches.addAll(toInsList(s.toSource(localData, this)));
if (s instanceof WithObjectAVM2Item) {
preCatches.add(ins(AVM2Instructions.PushWith));
} else {
preCatches.add(ins(AVM2Instructions.PushScope));
}
}
//catchCmds.add(catchCmd);
preCatches.addAll(catchCmds.get(c));
catches.addAll(0, preCatches);
catches.add(0, new ExceptionMarkAVM2Instruction(currentExceptionIds.get(c), MARK_E_TARGET));
catches.add(0, ins(AVM2Instructions.Jump, insToBytes(catches).length));
}
if (aloneFinallyEx > -1) {
localData.exceptions.add(newex.get(aloneFinallyEx));
aloneFinallyEx = localData.exceptions.size() - 1;
}
if (finallyEx > -1) {
localData.exceptions.add(newex.get(finallyEx));
finallyEx = localData.exceptions.size() - 1;
}
for (int i : currentExceptionIds) {
ret.add(new ExceptionMarkAVM2Instruction(i, MARK_E_START));
}
if (aloneFinallyEx > -1) {
ret.add(new ExceptionMarkAVM2Instruction(aloneFinallyEx, MARK_E_START));
}
if (finallyEx > -1) {
ret.add(new ExceptionMarkAVM2Instruction(finallyEx, MARK_E_START));
}
ret.addAll(tryCmds);
for (int i : currentExceptionIds) {
ret.add(new ExceptionMarkAVM2Instruction(i, MARK_E_END));
}
if (aloneFinallyEx > -1) {
ret.add(new ExceptionMarkAVM2Instruction(aloneFinallyEx, MARK_E_END));
}
if (aloneFinallyEx > -1) {
List<AVM2Instruction> preCatches = new ArrayList<>();
for (GraphTargetItem s : localData.scopeStack) {
preCatches.addAll(toInsList(s.toSource(localData, this)));
if (s instanceof WithObjectAVM2Item) {
preCatches.add(ins(AVM2Instructions.PushWith));
} else {
preCatches.add(ins(AVM2Instructions.PushScope));
}
}
preCatches.add(ins(AVM2Instructions.NewCatch, aloneFinallyEx));
preCatches.addAll(toInsList(AssignableAVM2Item.dupSetTemp(localData, this, tempReg)));
preCatches.add(ins(AVM2Instructions.PushScope));
preCatches.add(ins(AVM2Instructions.Throw));
preCatches.add(ins(AVM2Instructions.PopScope));
preCatches.addAll(toInsList(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(tempReg))));
catches.add(ins(AVM2Instructions.Jump, insToBytes(preCatches).length));
catches.add(new ExceptionMarkAVM2Instruction(aloneFinallyEx, MARK_E_TARGET));
catches.addAll(preCatches);
}
AVM2Instruction finSwitch = null;
AVM2Instruction pushDefIns = ins(AVM2Instructions.PushByte, 0);
int defPos = 0;
if (finallyEx > -1) {
List<AVM2Instruction> preCatches = new ArrayList<>();
preCatches.add(0, new ExceptionMarkAVM2Instruction(finallyEx, MARK_E_TARGET));
for (GraphTargetItem s : localData.scopeStack) {
preCatches.addAll(toInsList(s.toSource(localData, this)));
if (s instanceof WithObjectAVM2Item) {
preCatches.add(ins(AVM2Instructions.PushWith));
} else {
preCatches.add(ins(AVM2Instructions.PushScope));
}
}
preCatches.add(ins(AVM2Instructions.NewCatch, finallyEx));
preCatches.addAll(toInsList(AssignableAVM2Item.dupSetTemp(localData, this, tempReg)));
preCatches.add(ins(AVM2Instructions.PushScope));
preCatches.add(ins(AVM2Instructions.PopScope));
Reference<Integer> tempReg2 = new Reference<>(0);
preCatches.add(ins(AVM2Instructions.Kill, tempReg.getVal()));
preCatches.add(ins(AVM2Instructions.CoerceA));
preCatches.addAll(toInsList(AssignableAVM2Item.setTemp(localData, this, tempReg2)));
preCatches.add(pushDefIns);
List<AVM2Instruction> finallySwitchCmds = new ArrayList<>();
finSwitch = new AVM2Instruction(0, AVM2Instructions.LookupSwitch, new int[1 + 1 + 1]);
finSwitch.operands[0] = finSwitch.getBytesLength();
finSwitch.operands[1] = 0; //switch cnt
List<AVM2Instruction> preFinallySwitch = new ArrayList<>();
preFinallySwitch.add(ins(AVM2Instructions.Label));
preFinallySwitch.add(ins(AVM2Instructions.Pop));
int preFinallySwitchLen = insToBytes(preFinallySwitch).length;
finallySwitchCmds.add(ins(AVM2Instructions.Label));
finallySwitchCmds.addAll(toInsList(AssignableAVM2Item.getTemp(localData, this, tempReg2)));
finallySwitchCmds.add(ins(AVM2Instructions.Kill, tempReg2.getVal()));
finallySwitchCmds.add(ins(AVM2Instructions.Throw));
finallySwitchCmds.add(ins(AVM2Instructions.PushByte, 255));
finallySwitchCmds.add(ins(AVM2Instructions.PopScope));
finallySwitchCmds.add(ins(AVM2Instructions.Kill, tempReg.getVal()));
int finSwitchLen = insToBytes(finallySwitchCmds).length;
preCatches.add(ins(AVM2Instructions.Jump, preFinallySwitchLen + finSwitchLen));
AVM2Instruction fjump = ins(AVM2Instructions.Jump, 0);
fjump.operands[0] = insToBytes(preCatches).length + preFinallySwitchLen + finSwitchLen;
preCatches.add(0, fjump);
preCatches.add(0, new ExceptionMarkAVM2Instruction(finallyEx, MARK_E_END));
preCatches.add(0, ins(AVM2Instructions.PushByte, 255));
finallySwitchCmds.add(new ExceptionMarkAVM2Instruction(finallyEx, MARK_E_FINALLYPART));
int oldReg = localData.finallyRegister;
localData.finallyRegister = getFreeRegister(localData);
Integer cnt = localData.finallyCounter.get(finId);
if (cnt == null) {
cnt = -1;
}
defPos = cnt;
cnt++; //Skip default clause (throw)
localData.finallyCounter.put(finId, cnt);
finallySwitchCmds.addAll(generateToInsList(localData, item.finallyCommands));
killRegister(localData, localData.finallyRegister);
localData.finallyRegister = oldReg;
finSwitchLen = insToBytes(finallySwitchCmds).length;
finSwitch.operands[2] = -finSwitchLen;
preCatches.addAll(preFinallySwitch);
preCatches.addAll(finallySwitchCmds);
preCatches.add(finSwitch);
catches.addAll(preCatches);
AssignableAVM2Item.killTemp(localData, this, Arrays.asList(tempReg, tempReg2));
}
ret.addAll(catches);
//localData.exceptions.addAll(newex);
if (finallyEx > -1) {
localData.finallyCatches.remove(localData.finallyCatches.size() - 1);
}
if (newFinallyReg) {
localData.finallyRegister = -1;
killRegister(localData, localData.finallyRegister);
}
int pos = 0;
int finallyPos = 0;
int switchPos = 0;
for (int s = 0; s < ret.size(); s++) {
GraphSourceItem src = ret.get(s);
if (src == finSwitch) {
switchPos = pos;
}
if (src instanceof AVM2Instruction) {
AVM2Instruction ins = (AVM2Instruction) src;
if (ins instanceof ExceptionMarkAVM2Instruction) {
ExceptionMarkAVM2Instruction em = (ExceptionMarkAVM2Instruction) ins;
if (em.exceptionId == finallyEx && em.markType == MARK_E_FINALLYPART) {
finallyPos = pos;
ret.remove(s);
s--;
continue;
}
}
pos += ins.getBytesLength();
}
}
if (finSwitch != null) {
pos = 0;
int defLoc = finSwitch.operands[2];
List<Integer> switchLoc = new ArrayList<>();
boolean wasDef = false;
for (int s = 0; s < ret.size(); s++) {
GraphSourceItem src = ret.get(s);
if (src instanceof AVM2Instruction) {
AVM2Instruction ins = (AVM2Instruction) src;
if (ins.definition instanceof FinallyJumpIns) {
FinallyJumpIns fji = (FinallyJumpIns) ins.definition;
if (fji.getClauseId() == finId) {
List<AVM2Instruction> bet = new ArrayList<>();
bet.add(ins(AVM2Instructions.Label));
bet.add(ins(AVM2Instructions.Pop));
int betLen = insToBytes(bet).length;
if (wasDef) {
ins.operands[0] = 0;
} else {
ins.operands[0] = finallyPos - (pos + ins.getBytesLength());
}
ins.definition = AVM2Code.instructionSet[AVM2Instructions.Jump];
switchLoc.add(pos + ins.getBytesLength() + betLen - switchPos);
}
}
pos += ins.getBytesLength();
}
if (defPos == switchLoc.size() - 1) {
switchLoc.add(defLoc);
wasDef = true;
}
}
finSwitch.operands = new int[1 + 1 + switchLoc.size()];
pushDefIns.operands[0] = defPos + 1;
int afterLoc = finSwitch.getBytesLength();
finSwitch.operands[0] = afterLoc;
finSwitch.operands[1] = switchLoc.size() - 1;
for (int j = 0; j < switchLoc.size(); j++) {
finSwitch.operands[2 + j] = switchLoc.get(j);
}
}
return ret;
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, ContinueItem item) {
List<GraphSourceItem> ret = new ArrayList<>();
AVM2Instruction acontinue = ins(new ContinueJumpIns(item.loopId), 0);
ret.add(acontinue);
return ret;
}
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, ReturnValueAVM2Item item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
ret.addAll(item.value.toSource(localData, this));
if (!localData.finallyCatches.isEmpty()) {
ret.add(ins(AVM2Instructions.CoerceA));
ret.add(AssignableAVM2Item.generateSetLoc(localData.finallyRegister));
for (int i = localData.finallyCatches.size() - 1; i >= 0; i--) {
if (i < localData.finallyCatches.size() - 1) {
ret.add(ins(AVM2Instructions.Label));
}
int clauseId = localData.finallyCatches.get(i);
Integer cnt = localData.finallyCounter.get(clauseId);
if (cnt == null) {
cnt = -1;
}
cnt++;
localData.finallyCounter.put(clauseId, cnt);
ret.addAll(new IntegerValueAVM2Item(null, null, (long) cnt).toSource(localData, this));
ret.add(ins(new FinallyJumpIns(clauseId), 0));
ret.add(ins(AVM2Instructions.Label));
ret.add(ins(AVM2Instructions.Pop));
}
ret.add(ins(AVM2Instructions.Label));
ret.add(AssignableAVM2Item.generateGetLoc(localData.finallyRegister));
ret.add(ins(AVM2Instructions.Kill, localData.finallyRegister));
}
ret.add(ins(AVM2Instructions.ReturnValue));
return ret;
}
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, ReturnVoidAVM2Item item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
if (!localData.finallyCatches.isEmpty()) {
for (int i = 0; i < localData.finallyCatches.size(); i++) {
if (i > 0) {
ret.add(ins(AVM2Instructions.Label));
}
int clauseId = localData.finallyCatches.get(i);
Integer cnt = localData.finallyCounter.get(clauseId);
if (cnt == null) {
cnt = -1;
}
cnt++;
localData.finallyCounter.put(clauseId, cnt);
ret.addAll(new IntegerValueAVM2Item(null, null, (long) cnt).toSource(localData, this));
ret.add(ins(new FinallyJumpIns(clauseId), 0));
ret.add(ins(AVM2Instructions.Label));
ret.add(ins(AVM2Instructions.Pop));
}
ret.add(ins(AVM2Instructions.Label));
}
ret.add(ins(AVM2Instructions.ReturnVoid));
return ret;
}
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, ThrowAVM2Item item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
ret.addAll(item.value.toSource(localData, this));
ret.add(ins(AVM2Instructions.Throw));
return ret;
}
private List<AVM2Instruction> generateToInsList(SourceGeneratorLocalData localData, List<GraphTargetItem> commands) throws CompilationException {
return toInsList(generate(localData, commands));
}
private List<AVM2Instruction> generateToActionList(SourceGeneratorLocalData localData, GraphTargetItem command) throws CompilationException {
return toInsList(command.toSource(localData, this));
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, List<GraphTargetItem> commands) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
for (GraphTargetItem item : commands) {
ret.addAll(item.toSourceIgnoreReturnValue(localData, this));
}
return ret;
}
public HashMap<String, Integer> getRegisterVars(SourceGeneratorLocalData localData) {
return localData.registerVars;
}
public void setRegisterVars(SourceGeneratorLocalData localData, HashMap<String, Integer> value) {
localData.registerVars = value;
}
public void setInFunction(SourceGeneratorLocalData localData, int value) {
localData.inFunction = value;
}
public int isInFunction(SourceGeneratorLocalData localData) {
return localData.inFunction;
}
public boolean isInMethod(SourceGeneratorLocalData localData) {
return localData.inMethod;
}
public void setInMethod(SourceGeneratorLocalData localData, boolean value) {
localData.inMethod = value;
}
public int getForInLevel(SourceGeneratorLocalData localData) {
return localData.forInLevel;
}
public void setForInLevel(SourceGeneratorLocalData localData, int value) {
localData.forInLevel = value;
}
public int getTempRegister(SourceGeneratorLocalData localData) {
HashMap<String, Integer> registerVars = getRegisterVars(localData);
int tmpReg = 0;
for (int i = 0; i < 256; i++) {
if (!registerVars.containsValue(i)) {
tmpReg = i;
break;
}
}
return tmpReg;
}
public AVM2SourceGenerator(AbcIndexing abc) {
this.abcIndex = abc;
}
/*public ABC getABC() {
return abc;
}*/
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 name, String superName, GraphTargetItem extendsVal, List<GraphTargetItem> implementsStr, GraphTargetItem iinit, List<AssignableAVM2Item> iinitVariables, boolean iinitNeedsActivation, List<GraphTargetItem> traitItems, Reference<Integer> class_index) throws AVM2ParseException, CompilationException {
localData.currentClass = name;
localData.pkg = pkg;
localData.privateNs = abcIndex.getSelectedAbc().constants.getNamespaceId(Namespace.KIND_PRIVATE, pkg.toRawString() + ":" + name, 0, true);
localData.protectedNs = abcIndex.getSelectedAbc().constants.getNamespaceId(Namespace.KIND_PROTECTED, pkg.toRawString() + ":" + name, 0, true);
if (extendsVal == null && !isInterface) {
extendsVal = new TypeItem(DottedChain.OBJECT);
}
ParsedSymbol s = null;
if (Configuration.handleSkinPartsAutomatically.get()) {
Map<String, Boolean> skinParts = new HashMap<>();
for (GraphTargetItem t : traitItems) {
String tname = null;
List<Map.Entry<String, Map<String, String>>> tmetadata = null;
if (t instanceof MethodAVM2Item) {
tname = ((MethodAVM2Item) t).functionName;
tmetadata = ((MethodAVM2Item) t).metadata;
} else if (t instanceof SlotAVM2Item) {
tname = ((SlotAVM2Item) t).var;
tmetadata = ((SlotAVM2Item) t).metadata;
} else if (t instanceof ConstAVM2Item) {
tname = ((ConstAVM2Item) t).var;
tmetadata = ((ConstAVM2Item) t).metadata;
}
if (tname != null && tmetadata != null) {
for (Map.Entry<String, Map<String, String>> en : tmetadata) {
if ("SkinPart".equals(en.getKey())) {
boolean req = false;
if (en.getValue().containsKey("required")) {
if ("true".equals(en.getValue().get("required"))) {
req = true;
}
}
skinParts.put(tname, req);
}
}
}
}
if (!skinParts.isEmpty()) {
//Merge parts from _skinParts attribute of parent class
GraphTargetItem parent = extendsVal;
if (parent instanceof UnresolvedAVM2Item) {
parent = ((UnresolvedAVM2Item) parent).resolved;
}
if (parent instanceof TypeItem) {
ClassIndex ci = abcIndex.findClass(parent);
if (ci != null) {
int mi = ci.abc.class_info.get(ci.index).cinit_index;
MethodBody pcinit = ci.abc.findBody(mi);
ConvertData d = new ConvertData();
List<Traits> initt = new ArrayList<>();
initt.add(ci.abc.class_info.get(ci.index).static_traits);
try {
pcinit.convert(d, "-", ScriptExportMode.AS, true, mi, -1, ci.index, ci.abc, null, new ScopeStack(), GraphTextWriter.TRAIT_CLASS_INITIALIZER, new NulWriter(), new ArrayList<>(), initt, false);
//FIXME! Add skinparts from _skinParts attribute of parent class!!!
} catch (InterruptedException ex) {
Logger.getLogger(AVM2SourceGenerator.class.getName()).log(Level.SEVERE, "Getting parent skinparts interrupted", ex);
}
for (Trait t : ci.abc.class_info.get(ci.index).static_traits.traits) {
if (t instanceof TraitSlotConst) {
TraitSlotConst tsc = (TraitSlotConst) t;
if (tsc.kindType == Trait.TRAIT_SLOT) {
if ("_skinParts".equals(tsc.getName(ci.abc).getName(ci.abc.constants, new ArrayList<>(), true, true))) {
if (d.assignedValues.containsKey(tsc)) {
if (d.assignedValues.get(tsc).value instanceof NewObjectAVM2Item) {
NewObjectAVM2Item no = (NewObjectAVM2Item) d.assignedValues.get(tsc).value;
for (NameValuePair nvp : no.pairs) {
skinParts.put(EcmaScript.toString(nvp.name.getResult()), EcmaScript.toBoolean(nvp.value.getResult()));
}
}
}
}
}
}
}
}
}
/*
Add
override protected function get skinParts() : Object
{
return _skinParts;
}
*/
List<GraphTargetItem> getterBody = new ArrayList<>();
UnresolvedAVM2Item sp = new UnresolvedAVM2Item(new ArrayList<>(), importedClasses, false, TypeItem.UNBOUNDED, 0, new DottedChain(new String[]{"_skinParts"}, ""),
null, openedNamespaces);
getterBody.add(new ReturnValueAVM2Item(null, null, sp));
List<AssignableAVM2Item> subvars = new ArrayList<>();
subvars.add(sp);
List<List<NamespaceItem>> allopns = new ArrayList<>();
allopns.add(openedNamespaces);
GetterAVM2Item getter = new GetterAVM2Item(allopns, false, false, new ArrayList<>(), new NamespaceItem(pkg.toRawString() + ":" + name, Namespace.KIND_PROTECTED), isInterface, null, false, false, 0,
true, false, false, "skinParts", new ArrayList<>(), new ArrayList<>(), new ArrayList<>(),
getterBody, subvars, new TypeItem("Object"));
/*
Add
private static var _skinParts = {attr1:false, attr2:true};
*/
List<NameValuePair> pairs = new ArrayList<>();
for (String tname : skinParts.keySet()) {
pairs.add(new NameValuePair(new StringAVM2Item(null, null, tname), skinParts.get(tname) ? new TrueItem(null, null) : new FalseItem(null, null)));
}
NewObjectAVM2Item sltVal = new NewObjectAVM2Item(null, null, pairs);
SlotAVM2Item slt = new SlotAVM2Item(
new ArrayList<>(), new NamespaceItem(pkg.toRawString() + ":" + name, Namespace.KIND_PRIVATE),
null, true, "_skinParts", new TypeItem("Object"), sltVal, 0);
traitItems.add(0, slt);
traitItems.add(getter);
}
}
Trait[] it = generateTraitsPhase1(importedClasses, openedNamespaces, name, superName, false, localData, traitItems, instanceInfo.instance_traits, class_index);
Trait[] st = generateTraitsPhase1(importedClasses, openedNamespaces, name, superName, true, localData, traitItems, classInfo.static_traits, class_index);
generateTraitsPhase2(importedClasses, pkg, traitItems, it, openedNamespaces, localData);
generateTraitsPhase2(importedClasses, pkg, traitItems, st, openedNamespaces, localData);
abcIndex.refreshSelected();
generateTraitsPhase3(importedClasses, initScope, isInterface, name, superName, false, localData, traitItems, instanceInfo.instance_traits, it, new HashMap<>(), class_index);
generateTraitsPhase3(importedClasses, initScope, isInterface, name, superName, true, localData, traitItems, classInfo.static_traits, st, new HashMap<>(), class_index);
int init;
if (iinit == null || isInterface) {
instanceInfo.iinit_index = init = method(false, 0, false, isInterface, new ArrayList<>(), pkg, false, new ArrayList<>(), initScope + 1, false, 0, isInterface ? null : name, extendsVal != null ? extendsVal.toString() : null, true, localData, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), TypeItem.UNBOUNDED/*?? FIXME*/);
} else {
MethodAVM2Item m = (MethodAVM2Item) iinit;
instanceInfo.iinit_index = init = method(false, str(pkg.toRawString() + ":" + name + "/" + name), false, false, new ArrayList<>(), pkg, m.needsActivation, m.subvariables, initScope + 1, m.hasRest, m.line, name, extendsVal != null ? extendsVal.toString() : null, true, localData, m.paramTypes, m.paramNames, m.paramValues, m.body, TypeItem.UNBOUNDED/*?? FIXME*/);
}
//Class initializer
int cinit_index = method(true, str(""), false, false, new ArrayList<>(), pkg, cinitNeedsActivation, cinitVariables, initScope + (implementsStr.isEmpty() ? 0 : 1), false, 0, isInterface ? null : name, superName, false, localData, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), cinit, TypeItem.UNBOUNDED);
MethodBody cinitBody = abcIndex.getSelectedAbc().findBody(cinit_index);
List<AVM2Instruction> sinitcode = new ArrayList<>();
List<AVM2Instruction> initcode = new ArrayList<>();
for (GraphTargetItem ti : traitItems) {
if ((ti instanceof SlotAVM2Item) || (ti instanceof ConstAVM2Item)) {
GraphTargetItem val = null;
boolean isStatic = false;
int ns = -1;
String tname = null;
boolean isConst = false;
if (ti instanceof SlotAVM2Item) {
val = ((SlotAVM2Item) ti).value;
isStatic = ((SlotAVM2Item) ti).isStatic();
ns = genNs(importedClasses, pkg, ((SlotAVM2Item) ti).pkg, openedNamespaces, localData, ((SlotAVM2Item) ti).line);
tname = ((SlotAVM2Item) ti).var;
}
if (ti instanceof ConstAVM2Item) {
val = ((ConstAVM2Item) ti).value;
isStatic = ((ConstAVM2Item) ti).isStatic();
ns = genNs(importedClasses, pkg, ((ConstAVM2Item) ti).pkg, openedNamespaces, localData, ((ConstAVM2Item) ti).line);
tname = ((ConstAVM2Item) ti).var;
isConst = true;
}
if (isStatic && 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)));
}
if (!isStatic && val != null) {
//do not init basic values, that can be stored in trait
if (!(val instanceof IntegerValueAVM2Item) && !(val instanceof StringAVM2Item) && !(val instanceof BooleanAVM2Item) && !(val instanceof NullAVM2Item) && !(val instanceof UndefinedAVM2Item)) {
initcode.add(ins(AVM2Instructions.GetLocal0));
localData.isStatic = false;
initcode.addAll(toInsList(val.toSource(localData, this)));
initcode.add(ins(isConst ? AVM2Instructions.InitProperty : AVM2Instructions.SetProperty, traitName(ns, tname)));
}
}
}
}
MethodBody initBody = null;
if (!isInterface) {
initBody = abcIndex.getSelectedAbc().findBody(init);
initBody.insertAll(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.markOffsets();
cinitBody.autoFillStats(abcIndex.getSelectedAbc(), initScope + (implementsStr.isEmpty() ? 0 : 1), true);
classInfo.cinit_index = cinit_index;
if (initBody != null) {
initBody.autoFillStats(abcIndex.getSelectedAbc(), initScope + 1, true);
}
instanceInfo.interfaces = new int[implementsStr.size()];
for (int i = 0; i < implementsStr.size(); i++) {
instanceInfo.interfaces[i] = superIntName(localData, implementsStr.get(i));
}
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, CommaExpressionItem item) throws CompilationException {
if (item.commands.isEmpty()) {
return new ArrayList<>();
}
//We need to handle commands and last expression separately, otherwise last expression result will be popped
List<GraphTargetItem> cmds = new ArrayList<>(item.commands);
GraphTargetItem lastExpr = cmds.remove(cmds.size() - 1);
List<GraphSourceItem> ret = new ArrayList<>();
ret.addAll(generate(localData, cmds));
ret.addAll(lastExpr.toSource(localData, this));
return ret;
}
public int generateClass(int namespace, ClassInfo ci, InstanceInfo ii, int initScope, DottedChain pkg, SourceGeneratorLocalData localData, AVM2Item cls, Reference<Integer> class_index) throws AVM2ParseException, CompilationException {
/*ClassInfo ci = new ClassInfo();
InstanceInfo ii = new InstanceInfo();
abc.class_info.add(ci);
abc.instance_info.add(ii);
*/
if (cls instanceof ClassAVM2Item) {
ClassAVM2Item cai = (ClassAVM2Item) cls;
//TODO: iinit variables, iinit activation
generateClass(cai.importedClasses, cai.cinitVariables, cai.cinitActivation, cai.staticInit,
cai.openedNamespaces,
namespace,
initScope, pkg, ci, ii,
localData, false,
cai.className, cai.extendsOp == null ? "Object" : cai.extendsOp.toString(),
cai.extendsOp, cai.implementsOp, cai.iinit,
cai.iinitVariables, cai.iinitActivation, cai.traits, class_index
);
if (!cai.isDynamic) {
ii.flags |= InstanceInfo.CLASS_SEALED;
}
if (cai.isFinal) {
ii.flags |= InstanceInfo.CLASS_FINAL;
}
ii.flags |= InstanceInfo.CLASS_PROTECTEDNS;
ii.protectedNS = abcIndex.getSelectedAbc().constants.getNamespaceId(Namespace.KIND_PROTECTED, pkg.toRawString() + ":" + cai.className, 0, true);
}
if (cls instanceof InterfaceAVM2Item) {
InterfaceAVM2Item iai = (InterfaceAVM2Item) cls;
ii.flags |= InstanceInfo.CLASS_INTERFACE;
ii.flags |= InstanceInfo.CLASS_SEALED;
generateClass(iai.importedClasses, new ArrayList<>(), false, new ArrayList<>(),
iai.openedNamespaces, namespace, initScope, pkg, ci, ii, localData, true, iai.name, null, null, iai.superInterfaces, null, null, false, iai.methods,
class_index
);
}
return abcIndex.getSelectedAbc().instance_info.size() - 1;
}
public int traitName(int namespace, String var) {
return abcIndex.getSelectedAbc().constants.getMultinameId(Multiname.createQName(false, str(var), namespace), true);
}
public int typeName(SourceGeneratorLocalData localData, GraphTargetItem type) throws CompilationException {
if (type instanceof UnboundedTypeItem) {
return 0;
}
if (("" + type).equals("*")) {
return 0;
}
return resolveType(localData, type, abcIndex);
/*
TypeItem nameItem = (TypeItem) type;
name = nameItem.fullTypeName;
if (name.contains(".")) {
pkg = name.substring(0, name.lastIndexOf('.'));
name = name.substring(name.lastIndexOf('.') + 1);
}
if (!nameItem.subtypes.isEmpty()) { //It's vector => TypeName
List<Integer> params = new ArrayList<>();
for (GraphTargetItem p : nameItem.subtypes) {
params.add(typeName(localData, p));//abc.getLastAbc().constants.getMultinameId(new Multiname(Multiname.QNAME, str(p), namespace(Namespace.KIND_PACKAGE, ppkg), 0, 0, new ArrayList<Integer>()), true));
}
int qname = abc.getLastAbc().constants.getMultinameId(new Multiname(Multiname.QNAME, str(name), namespace(Namespace.KIND_PACKAGE, pkg), 0, 0, new ArrayList<Integer>()), true);
return abc.getLastAbc().constants.getMultinameId(new Multiname(Multiname.TYPENAME, 0, 0, 0, qname, params), true);
} else {
return abc.getLastAbc().constants.getMultinameId(new Multiname(Multiname.QNAME, str(name), namespace(Namespace.KIND_PACKAGE, pkg), 0, 0, new ArrayList<Integer>()), true);
}*/
}
public int ident(GraphTargetItem name) {
if (name instanceof NameAVM2Item) {
return str(((NameAVM2Item) name).getVariableName());
}
throw new RuntimeException("no ident"); //FIXME
}
public int namespace(int nsKind, String name) {
return abcIndex.getSelectedAbc().constants.getNamespaceId(nsKind, str(name), 0, true);
}
public int str(String name) {
return abcIndex.getSelectedAbc().constants.getStringId(name, true);
}
public int propertyName(GraphTargetItem name) {
if (name instanceof NameAVM2Item) {
NameAVM2Item va = (NameAVM2Item) name;
return abcIndex.getSelectedAbc().constants.getMultinameId(Multiname.createQName(false, str(va.getVariableName()), namespace(Namespace.KIND_PACKAGE, "")), true);
}
throw new RuntimeException("no prop"); //FIXME
}
public int getFreeRegister(SourceGeneratorLocalData localData) {
for (int i = 0;; i++) {
if (!localData.registerVars.containsValue(i)) {
localData.registerVars.put("__TEMP__" + i, i);
return i;
}
}
}
public boolean killRegister(SourceGeneratorLocalData localData, int i) {
String key = null;
for (String k : localData.registerVars.keySet()) {
if (localData.registerVars.get(k) == i) {
key = k;
break;
}
}
if (key != null) {
localData.registerVars.remove(key);
return true;
}
return false;
}
public int method(boolean isStatic, int name_index, boolean subMethod, boolean isInterface, List<MethodBody> callStack, DottedChain pkg, boolean needsActivation, List<AssignableAVM2Item> subvariables, int initScope, boolean hasRest, int line, String className, String superType, boolean constructor, SourceGeneratorLocalData localData, List<GraphTargetItem> paramTypes, List<String> paramNames, List<GraphTargetItem> paramValues, List<GraphTargetItem> body, GraphTargetItem retType) throws CompilationException {
//Reference<Boolean> hasArgs = new Reference<>(Boolean.FALSE);
//calcRegisters(localData,needsActivation,paramNames,subvariables,body, hasArgs);
SourceGeneratorLocalData newlocalData = new SourceGeneratorLocalData(new HashMap<>(), 1, true, 0);
newlocalData.currentClass = className;
newlocalData.pkg = localData.pkg;
newlocalData.callStack.addAll(localData.callStack);
newlocalData.traitUsages = localData.traitUsages;
newlocalData.currentScript = localData.currentScript;
newlocalData.documentClass = localData.documentClass;
newlocalData.privateNs = localData.privateNs;
newlocalData.protectedNs = localData.protectedNs;
newlocalData.isStatic = isStatic;
newlocalData.subMethod = subMethod;
localData = newlocalData;
localData.activationReg = 0;
for (int i = 0; i < subvariables.size(); i++) {
AssignableAVM2Item an = subvariables.get(i);
if (an instanceof UnresolvedAVM2Item) {
UnresolvedAVM2Item n = (UnresolvedAVM2Item) an;
if (n.resolved == null) {
String fullClass = localData.getFullClass();
GraphTargetItem res = n.resolve(new TypeItem(fullClass), paramTypes, paramNames, abcIndex, callStack, subvariables);
if (res instanceof AssignableAVM2Item) {
subvariables.set(i, (AssignableAVM2Item) res);
} else {
subvariables.remove(i);
i--;
}
}
}
}
for (int t = 0; t < paramTypes.size(); t++) {
GraphTargetItem an = paramTypes.get(t);
if (an instanceof UnresolvedAVM2Item) {
UnresolvedAVM2Item n = (UnresolvedAVM2Item) an;
if (n.resolved == null) {
String fullClass = localData.getFullClass();
GraphTargetItem res = n.resolve(new TypeItem(fullClass), paramTypes, paramNames, abcIndex, callStack, subvariables);
paramTypes.set(t, res);
}
}
}
boolean hasArguments = false;
List<String> slotNames = new ArrayList<>();
List<String> slotTypes = new ArrayList<>();
slotNames.add("--first");
slotTypes.add("-");
int paramLine = 0; //?
List<String> registerNames = new ArrayList<>();
List<Integer> registerLines = new ArrayList<>();
List<String> registerTypes = new ArrayList<>();
if (className != null) {
String fullClassName = pkg.addWithSuffix(className).toRawString();
registerTypes.add(fullClassName);
localData.scopeStack.add(new LocalRegAVM2Item(null, null, registerNames.size(), null));
registerNames.add("this");
registerLines.add(0); //?
} else {
registerTypes.add("global");
registerNames.add("this");
registerLines.add(0); //?
}
for (GraphTargetItem t : paramTypes) {
registerTypes.add(t.toString());
slotTypes.add(t.toString());
}
for (int i = 0; i < paramNames.size(); i++) {
registerLines.add(paramLine);
}
registerNames.addAll(paramNames);
slotNames.addAll(paramNames);
/*for (GraphTargetItem p : paramTypes) {
slotTypes.add("" + p);
}*/
if (hasRest) {
registerTypes.add("Array");
slotTypes.add("Array");
}
localData.registerVars.clear();
for (AssignableAVM2Item an : subvariables) {
if (an instanceof NameAVM2Item) {
NameAVM2Item n = (NameAVM2Item) an;
if (n.getVariableName().equals("arguments") & !n.isDefinition()) {
registerNames.add("arguments");
registerTypes.add("Object");
registerLines.add(0); //?
hasArguments = true;
break;
}
}
}
int paramRegCount = registerNames.size();
if (needsActivation) {
registerNames.add("+$activation");
registerLines.add(0); //?
localData.activationReg = registerNames.size() - 1;
registerTypes.add("Object");
localData.scopeStack.add(new LocalRegAVM2Item(null, null, localData.activationReg, null));
}
String mask = Configuration.registerNameFormat.get();
String maskRegexp = mask.replace("%d", "([0-9]+)");
Pattern pat = Pattern.compile(maskRegexp);
final String UNUSED = "~~unused";
//Two rounds
for (int round = 1; round <= 2; round++) {
for (AssignableAVM2Item an : subvariables) {
if (an instanceof NameAVM2Item) {
NameAVM2Item n = (NameAVM2Item) an;
if (n.isDefinition() && !registerNames.contains(n.getVariableName())) {
if (!needsActivation || (n.getSlotScope() <= 0)) {
String varName = n.getVariableName();
Matcher m = pat.matcher(varName);
//In first round, make all register that match standard loc_xx register
if ((round == 1) && (m.matches())) {
String regIndexStr = m.group(1);
int regIndex = Integer.parseInt(regIndexStr);
while (registerNames.size() <= regIndex) {
registerNames.add(UNUSED);
registerTypes.add("*");
registerLines.add(paramLine);
}
registerNames.set(regIndex, varName);
registerTypes.set(regIndex, varName);
registerLines.set(regIndex, n.line);
slotNames.add(varName);
slotTypes.add(n.type.toString());
} //in second round the rest
else if (round == 2 && !m.matches()) {
//search for some unused indices first:
int newRegIndex = -1;
for (int j = 0; j < registerNames.size(); j++) {
if (UNUSED.equals(registerNames.get(j))) {
newRegIndex = j;
break;
}
}
if (newRegIndex == -1) {
newRegIndex = registerNames.size();
registerNames.add(UNUSED);
registerTypes.add("*");
registerLines.add(paramLine);
}
registerNames.set(newRegIndex, n.getVariableName());
registerTypes.set(newRegIndex, n.type.toString());
registerLines.set(newRegIndex, n.line);
slotNames.add(n.getVariableName());
slotTypes.add(n.type.toString());
}
}
}
}
}
}
for (int j = 0; j < registerNames.size(); j++) {
if (UNUSED.equals(registerNames.get(j))) {
String standardName = String.format(mask, j);
registerNames.set(j, standardName);
slotNames.set(j, standardName);
}
}
int slotScope = subMethod ? 0 : 1;
for (AssignableAVM2Item an : subvariables) {
if (an instanceof NameAVM2Item) {
NameAVM2Item n = (NameAVM2Item) an;
String variableName = n.getVariableName();
if (variableName != null) {
boolean isThisOrSuper = variableName.equals("this") || variableName.equals("super");
if (!isThisOrSuper && needsActivation) {
if (n.getSlotNumber() <= 0) {
n.setSlotNumber(slotNames.indexOf(variableName));
n.setSlotScope(slotScope);
}
} else if (isThisOrSuper) {
n.setRegNumber(0);
} else {
n.setRegNumber(registerNames.indexOf(variableName));
}
}
}
}
for (int i = 0; i < registerNames.size(); i++) {
if (needsActivation && i > localData.activationReg) {
break;
}
localData.registerVars.put(registerNames.get(i), i);
}
List<NameAVM2Item> declarations = new ArrayList<>();
loopn:
for (AssignableAVM2Item an : subvariables) {
if (an instanceof NameAVM2Item) {
NameAVM2Item n = (NameAVM2Item) an;
if (needsActivation) {
if (n.getSlotScope() != slotScope) {
continue;
} else if (n.getSlotNumber() < paramRegCount) {
continue;
}
}
for (NameAVM2Item d : declarations) {
if (n.getVariableName() != null && n.getVariableName().equals(d.getVariableName())) {
continue loopn;
}
}
for (GraphTargetItem it : body) { //search first level of commands
if (it instanceof NameAVM2Item) {
NameAVM2Item n2 = (NameAVM2Item) it;
if (n2.isDefinition() && n2.getAssignedValue() != null && n2.getVariableName().equals(n.getVariableName())) {
continue loopn;
}
if (!n2.isDefinition() && n2.getVariableName() != null && n2.getVariableName().equals(n.getVariableName())) { //used earlier than defined
break;
}
}
}
if (n.unresolved) {
continue;
}
if (n.redirect != null) {
continue;
}
if (n.getNs() != null) {
continue;
}
String variableName = n.getVariableName();
if ("this".equals(variableName) || "super".equals(variableName) || paramNames.contains(variableName) || "arguments".equals(variableName)) {
continue;
}
NameAVM2Item d = new NameAVM2Item(n.type, n.line, n.getVariableName(), NameAVM2Item.getDefaultValue("" + n.type), true, n.openedNamespaces);
//no index
if (needsActivation) {
if (d.getSlotNumber() <= 0) {
d.setSlotNumber(n.getSlotNumber());
d.setSlotScope(n.getSlotScope());
}
} else {
d.setRegNumber(n.getRegNumber());
}
declarations.add(d);
}
}
int[] param_types = new int[paramTypes.size()];
ValueKind[] optional = new ValueKind[paramValues.size()];
//int[] param_names = new int[paramNames.size()];
for (int i = 0; i < paramTypes.size(); i++) {
param_types[i] = typeName(localData, paramTypes.get(i));
//param_names[i] = str(paramNames.get(i));
}
for (int i = 0; i < paramValues.size(); i++) {
optional[i] = getValueKind(Namespace.KIND_NAMESPACE/*FIXME*/, paramTypes.get(paramTypes.size() - paramValues.size() + i), paramValues.get(i));
if (optional[i] == null) {
throw new CompilationException("Default value must be compiletime constant", line);
}
}
MethodInfo mi = new MethodInfo(param_types, constructor ? 0 : typeName(localData, retType), name_index, 0, optional, new int[0]/*no param_names*/);
if (hasArguments) {
mi.setFlagNeed_Arguments();
}
//No param names like in official
/*
if (!paramNames.isEmpty()) {
mi.setFlagHas_paramnames();
}*/
if (!paramValues.isEmpty()) {
mi.setFlagHas_optional();
}
if (hasRest) {
mi.setFlagNeed_rest();
}
int mindex;
if (!isInterface) {
MethodBody mbody = new MethodBody(abcIndex.getSelectedAbc(), new Traits(), new byte[0], new ABCException[0]);
if (needsActivation) {
int slotId = 1;
for (int i = 1; i < slotNames.size(); i++) {
TraitSlotConst tsc = new TraitSlotConst();
tsc.slot_id = slotId++;
tsc.name_index = abcIndex.getSelectedAbc().constants.getMultinameId(Multiname.createQName(false, abcIndex.getSelectedAbc().constants.getStringId(slotNames.get(i), true), abcIndex.getSelectedAbc().constants.getNamespaceId(Namespace.KIND_PACKAGE_INTERNAL, pkg, 0, true)), true);
tsc.type_index = typeName(localData, new TypeItem(slotTypes.get(i)));
mbody.traits.traits.add(tsc);
}
for (int i = 1; i < paramRegCount; i++) {
NameAVM2Item param = new NameAVM2Item(new TypeItem(registerTypes.get(i)), 0, registerNames.get(i), null, false, new ArrayList<>());
param.setRegNumber(i);
NameAVM2Item d = new NameAVM2Item(new TypeItem(registerTypes.get(i)), 0, registerNames.get(i), param, true, new ArrayList<>());
d.setSlotScope(slotScope);
d.setSlotNumber(slotNames.indexOf(registerNames.get(i)));
declarations.add(d);
}
}
if (body != null) {
body.addAll(0, declarations);
}
localData.exceptions = new ArrayList<>();
localData.callStack.add(mbody);
List<GraphSourceItem> src = body == null ? new ArrayList<>() : generate(localData, body);
mbody.method_info = abcIndex.getSelectedAbc().addMethodInfo(mi);
ArrayList<AVM2Instruction> mbodyCode = toInsList(src);
mbody.setCode(new AVM2Code(mbodyCode));
if (needsActivation) {
if (localData.traitUsages.containsKey(mbody)) {
List<Integer> usages = localData.traitUsages.get(mbody);
for (int i = 0; i < mbody.traits.traits.size(); i++) {
if (usages.contains(i)) {
TraitSlotConst tsc = (TraitSlotConst) mbody.traits.traits.get(i);
GraphTargetItem type = TypeItem.UNBOUNDED;
if (tsc.type_index > 0) {
type = new TypeItem(abcIndex.getSelectedAbc().constants.getMultiname(tsc.type_index).getNameWithNamespace(abcIndex.getSelectedAbc().constants, true));
}
NameAVM2Item d = new NameAVM2Item(type, 0, tsc.getName(abcIndex.getSelectedAbc()).getName(abcIndex.getSelectedAbc().constants, null, true, true), NameAVM2Item.getDefaultValue("" + type), true, new ArrayList<>());
d.setSlotNumber(tsc.slot_id);
d.setSlotScope(slotScope);
mbodyCode.addAll(0, toInsList(d.toSourceIgnoreReturnValue(localData, this)));
}
}
}
List<AVM2Instruction> acts = new ArrayList<>();
acts.add(ins(AVM2Instructions.NewActivation));
acts.add(ins(AVM2Instructions.Dup));
acts.add(AssignableAVM2Item.generateSetLoc(localData.activationReg));
acts.add(ins(AVM2Instructions.PushScope));
mbodyCode.addAll(0, acts);
}
if (constructor) {
/* List<ABC> abcs = new ArrayList<>();
abcs.add(abc);
abcs.addAll(allABCs);
*/
int parentConstMinAC = 0;
AbcIndexing.ClassIndex ci = abcIndex.findClass(new TypeItem(superType));
if (ci != null) {
MethodInfo pmi = ci.abc.method_info.get(ci.abc.instance_info.get(ci.index).iinit_index);
parentConstMinAC = pmi.param_types.length;
if (pmi.flagHas_optional()) {
parentConstMinAC -= pmi.optional.length;
}
}
int ac = -1;
for (AVM2Instruction ins : mbodyCode) {
if (ins.definition instanceof ConstructSuperIns) {
ac = ins.operands[0];
if (parentConstMinAC > ac) {
throw new CompilationException("Parent constructor call requires different number of arguments", line);
}
}
}
if (ac == -1) {
if (parentConstMinAC == 0) {
mbodyCode.add(0, new AVM2Instruction(0, AVM2Instructions.GetLocal0, null));
mbodyCode.add(1, new AVM2Instruction(0, AVM2Instructions.ConstructSuper, new int[]{0}));
} else {
throw new CompilationException("Parent constructor must be called", line);
}
}
}
for (int i = 1; i < registerNames.size(); i++) {
mbodyCode.add(i - 1, ins(AVM2Instructions.Debug, 1, str(registerNames.get(i)), i - 1, (int) registerLines.get(i)));
}
if (!subMethod) {
mbodyCode.add(0, new AVM2Instruction(0, AVM2Instructions.GetLocal0, null));
mbodyCode.add(1, new AVM2Instruction(0, AVM2Instructions.PushScope, null));
}
boolean addRet = false;
if (!mbodyCode.isEmpty()) {
InstructionDefinition lastDef = mbodyCode.get(mbodyCode.size() - 1).definition;
if (!((lastDef instanceof ReturnVoidIns) || (lastDef instanceof ReturnValueIns))) {
addRet = true;
}
} else {
addRet = true;
}
if (addRet) {
if (retType.toString().equals("*") || retType.toString().equals("void") || constructor) {
mbodyCode.add(new AVM2Instruction(0, AVM2Instructions.ReturnVoid, null));
} else {
mbodyCode.add(new AVM2Instruction(0, AVM2Instructions.PushUndefined, null));
mbodyCode.add(new AVM2Instruction(0, AVM2Instructions.ReturnValue, null));
}
}
mbody.exceptions = localData.exceptions.toArray(new ABCException[localData.exceptions.size()]);
int offset = 0;
for (int i = 0; i < mbodyCode.size(); i++) {
AVM2Instruction ins = mbodyCode.get(i);
if (ins instanceof ExceptionMarkAVM2Instruction) {
ExceptionMarkAVM2Instruction m = (ExceptionMarkAVM2Instruction) ins;
switch (m.markType) {
case MARK_E_START:
mbody.exceptions[m.exceptionId].start = offset;
break;
case MARK_E_END:
mbody.exceptions[m.exceptionId].end = offset;
break;
case MARK_E_TARGET:
mbody.exceptions[m.exceptionId].target = offset;
break;
}
mbodyCode.remove(i);
i--;
continue;
}
offset += ins.getBytesLength();
}
mbody.markOffsets();
mbody.autoFillStats(abcIndex.getSelectedAbc(), initScope, className != null);
abcIndex.getSelectedAbc().addMethodBody(mbody);
mindex = mbody.method_info;
} else {
mindex = abcIndex.getSelectedAbc().addMethodInfo(mi);
}
return mindex;
}
public ValueKind getValueKind(int ns, GraphTargetItem type, GraphTargetItem val) {
if (val instanceof BooleanAVM2Item) {
BooleanAVM2Item bi = (BooleanAVM2Item) val;
if (bi.value) {
return new ValueKind(0, ValueKind.CONSTANT_True);
} else {
return new ValueKind(0, ValueKind.CONSTANT_False);
}
}
boolean isNs = false;
if (type instanceof NameAVM2Item) {
if (((NameAVM2Item) type).getVariableName().equals("namespace")) {
isNs = true;
}
}
if ((type instanceof TypeItem) && (((TypeItem) type).fullTypeName.equals(DottedChain.NAMESPACE))) {
isNs = true;
}
if (val instanceof StringAVM2Item) {
StringAVM2Item sval = (StringAVM2Item) val;
if (isNs) {
return new ValueKind(namespace(Namespace.KIND_NAMESPACE, sval.getValue()), ValueKind.CONSTANT_Namespace);
} else {
return new ValueKind(str(sval.getValue()), ValueKind.CONSTANT_Utf8);
}
}
if (val instanceof IntegerValueAVM2Item) {
return new ValueKind(abcIndex.getSelectedAbc().constants.getIntId(((IntegerValueAVM2Item) val).value, true), ValueKind.CONSTANT_Int);
}
if (val instanceof FloatValueAVM2Item) {
return new ValueKind(abcIndex.getSelectedAbc().constants.getDoubleId(((FloatValueAVM2Item) val).value, true), ValueKind.CONSTANT_Double);
}
if (val instanceof NanAVM2Item) {
return new ValueKind(abcIndex.getSelectedAbc().constants.getDoubleId(Double.NaN, true), ValueKind.CONSTANT_Double);
}
if (val instanceof NullAVM2Item) {
return new ValueKind(0, ValueKind.CONSTANT_Null);
}
if (val instanceof UndefinedAVM2Item) {
return new ValueKind(0, ValueKind.CONSTANT_Undefined);
}
return null;
}
private int genNs(List<DottedChain> importedClasses, DottedChain pkg, NamespaceItem ns, List<NamespaceItem> openedNamespaces, SourceGeneratorLocalData localData, int line) throws CompilationException {
ns.resolveCustomNs(abcIndex, importedClasses, pkg, openedNamespaces, localData);
return ns.getCpoolIndex(abcIndex);
}
public void generateTraitsPhase2(List<DottedChain> importedClasses, DottedChain pkg, List<GraphTargetItem> items, Trait[] traits, List<NamespaceItem> openedNamespaces, SourceGeneratorLocalData localData) throws CompilationException {
for (int k = 0; k < items.size(); k++) {
GraphTargetItem item = items.get(k);
if (traits[k] == null) {
} else if (item instanceof InterfaceAVM2Item) {
traits[k].name_index = traitName(((InterfaceAVM2Item) item).pkg == null ? 0 : ((InterfaceAVM2Item) item).pkg.getCpoolIndex(abcIndex), ((InterfaceAVM2Item) item).name);
} else if (item instanceof ClassAVM2Item) {
traits[k].name_index = traitName(((ClassAVM2Item) item).pkg == null ? 0 : ((ClassAVM2Item) item).pkg.getCpoolIndex(abcIndex), ((ClassAVM2Item) item).className);
} else if ((item instanceof MethodAVM2Item) || (item instanceof GetterAVM2Item) || (item instanceof SetterAVM2Item)) {
traits[k].name_index = traitName(genNs(importedClasses, pkg, ((MethodAVM2Item) item).pkg, openedNamespaces, localData, ((MethodAVM2Item) item).line), ((MethodAVM2Item) item).functionName);
} else if (item instanceof FunctionAVM2Item) {
traits[k].name_index = traitName(((FunctionAVM2Item) item).pkg == null ? 0 : ((FunctionAVM2Item) item).pkg.getCpoolIndex(abcIndex), ((FunctionAVM2Item) item).functionName);
} else if (item instanceof ConstAVM2Item) {
traits[k].name_index = traitName(genNs(importedClasses, pkg, ((ConstAVM2Item) item).pkg, openedNamespaces, localData, ((ConstAVM2Item) item).line), ((ConstAVM2Item) item).var);
} else if (item instanceof SlotAVM2Item) {
traits[k].name_index = traitName(genNs(importedClasses, pkg, ((SlotAVM2Item) item).pkg, openedNamespaces, localData, ((SlotAVM2Item) item).line), ((SlotAVM2Item) item).var);
}
}
for (int k = 0; k < items.size(); k++) {
GraphTargetItem item = items.get(k);
if (traits[k] == null) {
continue;
}
if (item instanceof ClassAVM2Item) {
InstanceInfo instanceInfo = abcIndex.getSelectedAbc().instance_info.get(((TraitClass) traits[k]).class_info);
instanceInfo.name_index = abcIndex.getSelectedAbc().constants.getMultinameId(
Multiname.createQName(
false,
abcIndex.getSelectedAbc().constants.getStringId(((ClassAVM2Item) item).className, true),
((ClassAVM2Item) item).pkg.getCpoolIndex(abcIndex)), true);
if (((ClassAVM2Item) item).extendsOp != null) {
instanceInfo.super_index = typeName(localData, ((ClassAVM2Item) item).extendsOp);
} else {
instanceInfo.super_index = abcIndex.getSelectedAbc().constants.getMultinameId(Multiname.createQName(false, str("Object"), namespace(Namespace.KIND_PACKAGE, "")), true);
}
instanceInfo.interfaces = new int[((ClassAVM2Item) item).implementsOp.size()];
for (int i = 0; i < ((ClassAVM2Item) item).implementsOp.size(); i++) {
instanceInfo.interfaces[i] = superIntName(localData, ((ClassAVM2Item) item).implementsOp.get(i));
}
}
if (item instanceof InterfaceAVM2Item) {
ABC abc = abcIndex.getSelectedAbc();
AVM2ConstantPool constants = abc.constants;
InstanceInfo instanceInfo = abc.instance_info.get(((TraitClass) traits[k]).class_info);
instanceInfo.name_index = constants.getMultinameId(Multiname.createQName(false, constants.getStringId(((InterfaceAVM2Item) item).name, true),
((InterfaceAVM2Item) item).pkg.getCpoolIndex(abcIndex)), true);
instanceInfo.interfaces = new int[((InterfaceAVM2Item) item).superInterfaces.size()];
for (int i = 0; i < ((InterfaceAVM2Item) item).superInterfaces.size(); i++) {
GraphTargetItem un = ((InterfaceAVM2Item) item).superInterfaces.get(i);
instanceInfo.interfaces[i] = superIntName(localData, un);
}
}
}
}
public int superIntName(SourceGeneratorLocalData localData, GraphTargetItem un) throws CompilationException {
if (un instanceof UnresolvedAVM2Item) {
((UnresolvedAVM2Item) un).resolve(null, new ArrayList<>(), new ArrayList<>(), abcIndex, new ArrayList<>(), new ArrayList<>());
un = ((UnresolvedAVM2Item) un).resolved;
}
if (!(un instanceof TypeItem)) { //not applyType
throw new CompilationException("Invalid type", 0);
}
TypeItem sup = (TypeItem) un;
int propId = resolveType(localData, sup, abcIndex);
int[] nss = new int[]{abcIndex.getSelectedAbc().constants.getMultiname(propId).namespace_index};
return abcIndex.getSelectedAbc().constants.getMultinameId(Multiname.createMultiname(false, abcIndex.getSelectedAbc().constants.getMultiname(propId).name_index, abcIndex.getSelectedAbc().constants.getNamespaceSetId(nss, true)), true);
}
public int[] generateMetadata(List<Map.Entry<String, Map<String, String>>> metadata) {
int[] ret = new int[metadata.size()];
for (int i = 0; i < metadata.size(); i++) {
Map.Entry<String, Map<String, String>> en = metadata.get(i);
int[] keys = new int[en.getValue().size()];
int[] values = new int[en.getValue().size()];
int j = 0;
for (String key : en.getValue().keySet()) {
keys[j] = abcIndex.getSelectedAbc().constants.getStringId(key, true);
values[j] = abcIndex.getSelectedAbc().constants.getStringId(en.getValue().get(key), true);
j++;
}
MetadataInfo mi = new MetadataInfo(abcIndex.getSelectedAbc().constants.getStringId(en.getKey(), true), keys, values);
ret[i] = abcIndex.getSelectedAbc().metadata_info.size();
abcIndex.getSelectedAbc().metadata_info.add(mi);
}
return ret;
}
public void generateTraitsPhase3(List<DottedChain> importedClasses, int methodInitScope, boolean isInterface, String className, String superName, boolean generateStatic, SourceGeneratorLocalData localData, List<GraphTargetItem> items, Traits ts, Trait[] traits, Map<Trait, Integer> initScopes, Reference<Integer> class_index) throws AVM2ParseException, CompilationException {
//Note: Names must be generated first before accesed in inner subs
for (int k = 0; k < items.size(); k++) {
GraphTargetItem item = items.get(k);
if (traits[k] == null) {
continue;
}
if (item instanceof InterfaceAVM2Item) {
generateClass(((InterfaceAVM2Item) item).pkg.getCpoolIndex(abcIndex), abcIndex.getSelectedAbc().class_info.get(((TraitClass) traits[k]).class_info), abcIndex.getSelectedAbc().instance_info.get(((TraitClass) traits[k]).class_info), initScopes.get(traits[k]), ((InterfaceAVM2Item) item).pkg.name, localData, (InterfaceAVM2Item) item, class_index);
}
if (item instanceof ClassAVM2Item) {
generateClass(((ClassAVM2Item) item).pkg.getCpoolIndex(abcIndex), abcIndex.getSelectedAbc().class_info.get(((TraitClass) traits[k]).class_info), abcIndex.getSelectedAbc().instance_info.get(((TraitClass) traits[k]).class_info), initScopes.get(traits[k]), ((ClassAVM2Item) item).pkg.name, localData, (ClassAVM2Item) item, class_index);
}
if ((item instanceof MethodAVM2Item) || (item instanceof GetterAVM2Item) || (item instanceof SetterAVM2Item)) {
MethodAVM2Item mai = (MethodAVM2Item) item;
if (mai.isStatic() != generateStatic) {
continue;
}
for (List<NamespaceItem> ln : mai.allOpenedNamespaces) {
for (NamespaceItem n : ln) {
n.resolveCustomNs(abcIndex, importedClasses, localData.pkg, ln, localData);
}
}
String suffix = null;
if (item instanceof GetterAVM2Item) {
suffix = "get";
}
if (item instanceof SetterAVM2Item) {
suffix = "set";
}
((TraitMethodGetterSetter) traits[k]).method_info = method(mai.isStatic(), methodName(mai.outsidePackage, localData.pkg, mai.functionName, mai.pkg, className, mai.customNamespace, suffix), false, isInterface, new ArrayList<>(), localData.pkg, mai.needsActivation, mai.subvariables, methodInitScope + (mai.isStatic() ? 0 : 1), mai.hasRest, mai.line, className, superName, false, localData, mai.paramTypes, mai.paramNames, mai.paramValues, mai.body, mai.retType);
} else if (item instanceof FunctionAVM2Item) {
FunctionAVM2Item fai = (FunctionAVM2Item) item;
((TraitFunction) traits[k]).method_info = method(false, methodName(false/*?*/, localData.pkg, fai.functionName, fai.pkg, null, null, ""), false, isInterface, new ArrayList<>(), localData.pkg, fai.needsActivation, fai.subvariables, methodInitScope, fai.hasRest, fai.line, className, superName, false, localData, fai.paramTypes, fai.paramNames, fai.paramValues, fai.body, fai.retType);
}
}
}
private int methodName(boolean outsidePkg, DottedChain pkg, String methodName, NamespaceItem ns, String className, String customNs, String typeSuffix) {
StringBuilder sb = new StringBuilder();
/*if (ns != null) {
sb.append(ns.name.toRawString());
}*/
if (className != null) {
if (pkg != null && !pkg.isEmpty() && !pkg.isTopLevel()) {
sb.append(pkg.toRawString());
sb.append(":");
}
sb.append(className);
}
if (customNs != null) {
sb.append(customNs);
} else if (ns != null) {
switch (ns.kind) {
case Namespace.KIND_PACKAGE_INTERNAL:
sb.append(pkg == null ? "" /*?*/ : pkg.toRawString());
break;
case Namespace.KIND_PRIVATE:
if (!outsidePkg) {
sb.append("/private");
}
break;
case Namespace.KIND_PROTECTED:
case Namespace.KIND_STATIC_PROTECTED:
sb.append("/protected");
break;
}
}
sb.append(":");
sb.append(methodName);
if (typeSuffix != null && !typeSuffix.isEmpty()) {
sb.append("/");
sb.append(typeSuffix);
}
return abcIndex.getSelectedAbc().constants.getStringId(sb.toString(), true);
}
public Trait[] generateTraitsPhase1(List<DottedChain> importedClasses, List<NamespaceItem> openedNamespaces, String className, String superName, boolean generateStatic, SourceGeneratorLocalData localData, List<GraphTargetItem> items, Traits ts, Reference<Integer> classIndex) throws AVM2ParseException, CompilationException {
Trait[] traits = new Trait[items.size()];
int slot_id = 1;
int disp_id = 3; //1 and 2 are for constructor
for (int k = 0; k < items.size(); k++) {
GraphTargetItem item = items.get(k);
if (item instanceof InterfaceAVM2Item) {
TraitClass tc = new TraitClass();
ClassInfo ci = new ClassInfo();
InstanceInfo ii = new InstanceInfo();
/*abc.class_info.add(ci);
abc.instance_info.add(ii);*/
tc.class_info = classIndex.getVal();
abcIndex.getSelectedAbc().addClass(ci, ii, classIndex.getVal());
classIndex.setVal(classIndex.getVal() + 1);
ii.flags |= InstanceInfo.CLASS_INTERFACE;
//ii.name_index = traitName(((InterfaceAVM2Item) item).namespace, ((InterfaceAVM2Item) item).name);
//tc.class_info = abc.instance_info.size() - 1;
tc.kindType = Trait.TRAIT_CLASS;
//tc.name_index = traitName(((InterfaceAVM2Item) item).namespace, ((InterfaceAVM2Item) item).name);
tc.slot_id = 0; //?
ts.traits.add(tc);
traits[k] = tc;
traits[k].metadata = generateMetadata(((InterfaceAVM2Item) item).metadata);
if (traits[k].metadata.length > 0) {
traits[k].kindFlags |= Trait.ATTR_Metadata;
}
}
if (item instanceof ClassAVM2Item) {
TraitClass tc = new TraitClass();
ClassInfo ci = new ClassInfo();
InstanceInfo ii = new InstanceInfo();
//ii.name_index = traitName(((ClassAVM2Item) item).namespace, ((ClassAVM2Item) item).className);
/*abc.class_info.add(ci);
abc.instance_info.add(instanceInfo);*/
tc.class_info = classIndex.getVal();
abcIndex.getSelectedAbc().addClass(ci, ii, classIndex.getVal());
classIndex.setVal(classIndex.getVal() + 1);
tc.kindType = Trait.TRAIT_CLASS;
// tc.name_index = traitName(((ClassAVM2Item) item).namespace, ((ClassAVM2Item) item).className);
tc.slot_id = slot_id++;
ts.traits.add(tc);
traits[k] = tc;
traits[k].metadata = generateMetadata(((ClassAVM2Item) item).metadata);
if (traits[k].metadata.length > 0) {
traits[k].kindFlags |= Trait.ATTR_Metadata;
}
}
if ((item instanceof SlotAVM2Item) || (item instanceof ConstAVM2Item)) {
TraitSlotConst tsc = new TraitSlotConst();
tsc.kindType = (item instanceof SlotAVM2Item) ? Trait.TRAIT_SLOT : Trait.TRAIT_CONST;
String var = null;
GraphTargetItem val = null;
GraphTargetItem type = null;
boolean isNamespace = false;
int namespace = 0;
boolean isStatic = false;
int[] metadata = new int[0];
if (item instanceof SlotAVM2Item) {
SlotAVM2Item sai = (SlotAVM2Item) item;
if (sai.isStatic() != generateStatic) {
continue;
}
var = sai.var;
val = sai.value;
type = sai.type;
isStatic = sai.isStatic();
if (sai.pkg != null) {
sai.pkg.resolveCustomNs(abcIndex, importedClasses, localData.pkg, openedNamespaces, localData);
}
namespace = sai.pkg == null ? 0 : sai.pkg.getCpoolIndex(abcIndex);
metadata = generateMetadata(((SlotAVM2Item) item).metadata);
}
if (item instanceof ConstAVM2Item) {
ConstAVM2Item cai = (ConstAVM2Item) item;
if (cai.isStatic() != generateStatic) {
continue;
}
var = cai.var;
val = cai.value;
type = cai.type;
if (cai.pkg != null) {
cai.pkg.resolveCustomNs(abcIndex, importedClasses, localData.pkg, openedNamespaces, localData);
}
namespace = cai.pkg == null ? 0 : cai.pkg.getCpoolIndex(abcIndex);
isNamespace = type.toString().equals("Namespace");
isStatic = cai.isStatic();
metadata = generateMetadata(((ConstAVM2Item) item).metadata);
}
if (isNamespace) {
tsc.name_index = traitName(namespace, var);
}
tsc.type_index = isNamespace ? 0 : (type == null ? 0 : typeName(localData, type));
ValueKind vk = getValueKind(namespace, type, val);
if (vk == null) {
tsc.value_kind = ValueKind.CONSTANT_Undefined;
} else {
tsc.value_kind = vk.value_kind;
tsc.value_index = vk.value_index;
}
tsc.slot_id = isStatic ? slot_id++ : 0;
ts.traits.add(tsc);
traits[k] = tsc;
traits[k].metadata = metadata;
if (traits[k].metadata.length > 0) {
traits[k].kindFlags |= Trait.ATTR_Metadata;
}
}
if ((item instanceof MethodAVM2Item) || (item instanceof GetterAVM2Item) || (item instanceof SetterAVM2Item)) {
MethodAVM2Item mai = (MethodAVM2Item) item;
if (mai.isStatic() != generateStatic) {
continue;
}
TraitMethodGetterSetter tmgs = new TraitMethodGetterSetter();
tmgs.kindType = (item instanceof GetterAVM2Item) ? Trait.TRAIT_GETTER : ((item instanceof SetterAVM2Item) ? Trait.TRAIT_SETTER : Trait.TRAIT_METHOD);
tmgs.disp_id = mai.isStatic() ? disp_id++ : 0; //For a reason, there is disp_id only for static methods (or not?)
if (mai.isFinal() || (className != null && mai.isStatic())) {
tmgs.kindFlags |= Trait.ATTR_Final;
}
if (mai.isOverride()) {
tmgs.kindFlags |= Trait.ATTR_Override;
}
ts.traits.add(tmgs);
traits[k] = tmgs;
traits[k].metadata = generateMetadata(((MethodAVM2Item) item).metadata);
if (traits[k].metadata.length > 0) {
traits[k].kindFlags |= Trait.ATTR_Metadata;
}
}
/*else if (item instanceof FunctionAVM2Item) {
TraitFunction tf = new TraitFunction();
tf.slot_id = slot_id++;
tf.kindType = Trait.TRAIT_FUNCTION;
//tf.name_index = traitName(((FunctionAVM2Item) item).namespace, ((FunctionAVM2Item) item).functionName);
ts.traits.add(tf);
traits[k] = tf;
traits[k].metadata = generateMetadata(((FunctionAVM2Item) item).metadata);
}*/
}
return traits;
}
public ScriptInfo generateScriptInfo(List<List<NamespaceItem>> allOpenedNamespaces, SourceGeneratorLocalData localData, List<GraphTargetItem> commands, int classPos) throws AVM2ParseException, CompilationException {
Reference<Integer> class_index = new Reference<>(classPos);
ScriptInfo si = new ScriptInfo();
localData.currentScript = si;
Trait[] traitArr = generateTraitsPhase1(new ArrayList<>(), new ArrayList<>(), null, null, true, localData, commands, si.traits, class_index);
generateTraitsPhase2(new ArrayList<>(), null/*FIXME*/, commands, traitArr, new ArrayList<>(), localData);
abcIndex.refreshSelected();
ABC abc = abcIndex.getSelectedAbc();
AVM2ConstantPool constants = abc.constants;
MethodInfo mi = new MethodInfo(new int[0], 0, constants.getStringId("", true), 0, new ValueKind[0], new int[0]);
MethodBody mb = new MethodBody(abc, new Traits(), new byte[0], new ABCException[0]);
mb.method_info = abc.addMethodInfo(mi);
mb.setCode(new AVM2Code());
List<AVM2Instruction> mbCode = mb.getCode().code;
mbCode.add(ins(AVM2Instructions.GetLocal0));
mbCode.add(ins(AVM2Instructions.PushScope));
int traitScope = 2;
Map<Trait, Integer> initScopes = new HashMap<>();
for (Trait t : si.traits.traits) {
if (t instanceof TraitClass) {
TraitClass tc = (TraitClass) t;
List<Integer> parents = new ArrayList<>();
if (localData.documentClass) {
mbCode.add(ins(AVM2Instructions.GetScopeObject, 0));
traitScope++;
} else {
int[] nsset = new int[]{constants.getMultiname(tc.name_index).namespace_index};
mbCode.add(ins(AVM2Instructions.FindPropertyStrict, constants.getMultinameId(Multiname.createMultiname(false, constants.getMultiname(tc.name_index).name_index, constants.getNamespaceSetId(nsset, true)), true)));
}
if (abc.instance_info.get(tc.class_info).isInterface()) {
mbCode.add(ins(AVM2Instructions.PushNull));
} else {
AbcIndexing.ClassIndex ci = abcIndex.findClass(AbcIndexing.multinameToType(abc.instance_info.get(tc.class_info).name_index, constants));
while (ci != null && ci.parent != null) {
ci = ci.parent;
Multiname origM = ci.abc.constants.getMultiname(ci.abc.instance_info.get(ci.index).name_index);
Namespace origNs = ci.abc.constants.getNamespace(origM.namespace_index);
if (origM.kind == Multiname.QNAME || origM.kind == Multiname.QNAMEA) {
parents.add(constants.getMultinameId(
Multiname.createQName(origM.kind == Multiname.QNAMEA,
constants.getStringId(ci.abc.constants.getString(origM.name_index), true),
constants.getNamespaceId(origNs.kind,
ci.abc.constants.getString(origNs.name_index), 0, true)), true));
}
}
//add all parent objects to scopestack
for (int i = parents.size() - 1; i >= 0; i--) {
mbCode.add(ins(AVM2Instructions.GetLex, parents.get(i)));
mbCode.add(ins(AVM2Instructions.PushScope));
traitScope++;
}
//direct parent class to new_class instruction
if (!parents.isEmpty()) { //NON EXISTING PARENT CLASS - TODO: handle as error!
mbCode.add(ins(AVM2Instructions.GetLex, parents.get(0)));
}
}
mbCode.add(ins(AVM2Instructions.NewClass, tc.class_info));
for (int i = 0; i < parents.size(); i++) {
mbCode.add(ins(AVM2Instructions.PopScope));
}
mbCode.add(ins(AVM2Instructions.InitProperty, tc.name_index));
initScopes.put(t, traitScope);
traitScope = 1;
}
}
abc.addMethodBody(mb);
si.init_index = mb.method_info;
localData.pkg = DottedChain.EMPTY;
generateTraitsPhase3(new ArrayList<>(), 1/*??*/, false, null, null, true, localData, commands, si.traits, traitArr, initScopes, class_index);
int maxSlotId = 0;
for (int k = 0; k < si.traits.traits.size(); k++) {
if (si.traits.traits.get(k) instanceof TraitSlotConst) {
TraitSlotConst ti = (TraitSlotConst) si.traits.traits.get(k);
if (ti.slot_id > maxSlotId) {
maxSlotId = ti.slot_id;
}
}
}
for (int k = 0; k < si.traits.traits.size(); k++) {
if ((si.traits.traits.get(k) instanceof TraitMethodGetterSetter) && (commands.get(k) instanceof MethodAVM2Item)) {
MethodAVM2Item mai = (MethodAVM2Item) commands.get(k);
if (mai.outsidePackage) {
TraitMethodGetterSetter tmgs = (TraitMethodGetterSetter) si.traits.traits.get(k);
TraitSlotConst nts = new TraitSlotConst();
nts.name_index = si.traits.traits.get(k).name_index;
nts.metadata = si.traits.traits.get(k).metadata;
nts.slot_id = maxSlotId + 1;
maxSlotId++;
nts.type_index = abcIndex.getSelectedAbc().constants.getQnameId("Function", Namespace.KIND_PACKAGE, "", true);
nts.value_index = 0;
nts.value_kind = 0;
int methodinfo = tmgs.method_info;
si.traits.traits.set(k, nts);
mbCode.add(ins(AVM2Instructions.NewFunction, methodinfo));
mbCode.add(ins(AVM2Instructions.InitProperty, nts.name_index));
}
}
}
mbCode.add(ins(AVM2Instructions.ReturnVoid));
mb.autoFillStats(abc, 1, false);
return si;
}
public static void parentNamesAddNames(AbcIndexing abc, int name_index, List<Integer> indices, List<String> names, List<String> namespaces) {
List<Integer> cindices = new ArrayList<>();
List<ABC> outABCs = new ArrayList<>();
parentNames(abc, name_index, cindices, names, namespaces, outABCs);
for (int i = 0; i < cindices.size(); i++) {
ABC a = outABCs.get(i);
int m = cindices.get(i);
if (a == abc.getSelectedAbc()) {
indices.add(m);
continue;
}
Multiname superName = a.constants.getMultiname(m);
indices.add(
abc.getSelectedAbc().constants.getMultinameId(
Multiname.createQName(false,
abc.getSelectedAbc().constants.getStringId(superName.getName(a.constants, null, true, true /*FIXME!!! ???*/), true),
abc.getSelectedAbc().constants.getNamespaceId(superName.getNamespace(a.constants).kind, superName.getNamespace(a.constants).getName(a.constants), 0, true)), true)
);
}
}
public static GraphTargetItem getTraitReturnType(AbcIndexing abc, Trait t) {
if (t instanceof TraitSlotConst) {
TraitSlotConst tsc = (TraitSlotConst) t;
if (tsc.type_index == 0) {
return TypeItem.UNBOUNDED;
}
return PropertyAVM2Item.multinameToType(tsc.type_index, abc.getSelectedAbc().constants);
}
if (t instanceof TraitMethodGetterSetter) {
TraitMethodGetterSetter tmgs = (TraitMethodGetterSetter) t;
if (tmgs.kindType == Trait.TRAIT_GETTER) {
return PropertyAVM2Item.multinameToType(abc.getSelectedAbc().method_info.get(tmgs.method_info).ret_type, abc.getSelectedAbc().constants);
}
if (tmgs.kindType == Trait.TRAIT_SETTER) {
if (abc.getSelectedAbc().method_info.get(tmgs.method_info).param_types.length > 0) {
return PropertyAVM2Item.multinameToType(abc.getSelectedAbc().method_info.get(tmgs.method_info).param_types[0], abc.getSelectedAbc().constants);
} else {
return TypeItem.UNBOUNDED;
}
}
}
if (t instanceof TraitFunction) {
return new TypeItem(DottedChain.FUNCTION);
}
return TypeItem.UNBOUNDED;
}
public static boolean searchPrototypeChain(List<Integer> otherNs, int privateNs, int protectedNs, boolean instanceOnly, AbcIndexing abc, DottedChain pkg, String obj, String propertyName, Reference<String> outName, Reference<DottedChain> outNs, Reference<DottedChain> outPropNs, Reference<Integer> outPropNsKind, Reference<Integer> outPropNsIndex, Reference<GraphTargetItem> outPropType, Reference<ValueKind> outPropValue, Reference<ABC> outPropValueAbc) {
for (int ns : otherNs) {
if (searchPrototypeChain(ns, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc)) {
return true;
}
}
if (searchPrototypeChain(privateNs, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc)) {
return true;
}
if (searchPrototypeChain(protectedNs, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc)) {
return true;
}
return searchPrototypeChain(0, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc);
}
private static boolean searchPrototypeChain(int selectedNs, boolean instanceOnly, AbcIndexing abc, DottedChain pkg, String obj, String propertyName, Reference<String> outName, Reference<DottedChain> outNs, Reference<DottedChain> outPropNs, Reference<Integer> outPropNsKind, Reference<Integer> outPropNsIndex, Reference<GraphTargetItem> outPropType, Reference<ValueKind> outPropValue, Reference<ABC> outPropValueAbc) {
AbcIndexing.TraitIndex sp = abc.findScriptProperty(pkg.addWithSuffix(propertyName));
if (sp == null) {
sp = abc.findProperty(new AbcIndexing.PropertyDef(propertyName, new TypeItem(pkg.addWithSuffix(obj)), abc.getSelectedAbc(), selectedNs), !instanceOnly, true);
}
if (sp != null) {
if (sp.objType instanceof TypeItem) {
outName.setVal(((TypeItem) sp.objType).fullTypeName.getLast());
outNs.setVal(((TypeItem) sp.objType).fullTypeName.getWithoutLast());
} else {
//FIXME? Vector?
}
outPropNs.setVal(sp.trait.getName(sp.abc).getNamespace(sp.abc.constants).getName(sp.abc.constants));
outPropNsKind.setVal(sp.trait.getName(sp.abc).getNamespace(sp.abc.constants).kind);
int nsi = sp.trait.getName(sp.abc).namespace_index;
outPropNsIndex.setVal(sp.abc == abc.getSelectedAbc() ? sp.abc.constants.getNamespaceSubIndex(nsi) : 0);
outPropType.setVal(sp.returnType);
outPropValue.setVal(sp.value);
outPropValueAbc.setVal(sp.abc);
return true;
}
return false;
}
public static void parentNames(AbcIndexing abc, int name_index, List<Integer> indices, List<String> names, List<String> namespaces, List<ABC> outABCs) {
AbcIndexing.ClassIndex ci = abc.findClass(new TypeItem(abc.getSelectedAbc().constants.getMultiname(name_index).getNameWithNamespace(abc.getSelectedAbc().constants, true /*FIXME!!*/)));
while (ci != null) {
int ni = ci.abc.instance_info.get(ci.index).name_index;
indices.add(ni);
outABCs.add(ci.abc);
names.add(ci.abc.constants.getMultiname(ni).getName(ci.abc.constants, null, true, true/*FIXME!!*/));
namespaces.add(ci.abc.constants.getMultiname(ni).getNamespace(ci.abc.constants).getName(ci.abc.constants).toRawString());
ci = ci.parent;
}
}
/* public void calcRegisters(Reference<Integer> activationReg, SourceGeneratorLocalData localData, boolean needsActivation, List<String> funParamNames,List<NameAVM2Item> funSubVariables,List<GraphTargetItem> funBody, Reference<Boolean> hasArguments) throws ParseException {
}*/
/*public int resolveType(String objType) {
if (objType.equals("*")) {
return 0;
}
List<ABC> abcs = new ArrayList<>();
abcs.add(abc);
abcs.addAll(allABCs);
for (ABC a : abcs) {
int ci = a.findClassByName(objType);
if (ci != -1) {
Multiname tname = a.instance_info.get(ci).getName(a.constants);
return abc.getLastAbc().constants.getMultinameId(new Multiname(tname.kind,
abc.getLastAbc().constants.getStringId(tname.getName(a.constants, new ArrayList<>()), true),
abc.getLastAbc().constants.getNamespaceId(new Namespace(tname.getNamespace(a.constants).kind, abc.getLastAbc().constants.getStringId(tname.getNamespace(a.constants).getName(a.constants), true)), 0, true), 0, 0, new ArrayList<Integer>()), true);
}
}
return 0;
}*/
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, TypeItem item) throws CompilationException {
String currentFullClassName = localData.getFullClass();
if (localData.documentClass && item.toString().equals(currentFullClassName)) {
int slotId = 0;
int c = abcIndex.getSelectedAbc().findClassByName(currentFullClassName);
for (Trait t : localData.currentScript.traits.traits) {
if (t instanceof TraitClass) {
TraitClass tc = (TraitClass) t;
if (tc.class_info == c) {
slotId = tc.slot_id;
break;
}
}
}
return GraphTargetItem.toSourceMerge(localData, this, ins(AVM2Instructions.GetGlobalScope), ins(AVM2Instructions.GetSlot, slotId));
} else {
return GraphTargetItem.toSourceMerge(localData, this, ins(AVM2Instructions.GetLex, resolveType(localData, item, abcIndex)));
}
}
public static int resolveType(SourceGeneratorLocalData localData, GraphTargetItem item, AbcIndexing abcIndex) throws CompilationException {
int name_index = 0;
GraphTargetItem typeItem = null;
if (item instanceof UnresolvedAVM2Item) {
String fullClass = localData.getFullClass();
item = ((UnresolvedAVM2Item) item).resolve(new TypeItem(fullClass), new ArrayList<>(), new ArrayList<>(), abcIndex, new ArrayList<>(), new ArrayList<>());
}
if (item instanceof TypeItem) {
typeItem = item;
} else if (item instanceof ApplyTypeAVM2Item) {
typeItem = ((ApplyTypeAVM2Item) item).object;
} else {
throw new CompilationException("Invalid type:" + item + " (" + item.getClass().getName() + ")", 0/*??*/);
}
if (typeItem instanceof UnresolvedAVM2Item) {
String fullClass = localData.getFullClass();
typeItem = ((UnresolvedAVM2Item) typeItem).resolve(new TypeItem(fullClass), new ArrayList<>(), new ArrayList<>(), abcIndex, new ArrayList<>(), new ArrayList<>());
}
if (!(typeItem instanceof TypeItem)) {
throw new CompilationException("Invalid type", 0/*??*/);
}
TypeItem type = (TypeItem) typeItem;
DottedChain dname = type.fullTypeName;
DottedChain pkg = dname.getWithoutLast();
String name = dname.getLast();
/*for (InstanceInfo ii : abc.getSelectedAbc().instance_info) {
Multiname mname = abc.getSelectedAbc().constants.constant_multiname.get(ii.name_index);
if (mname != null && name.equals(mname.getName(abc.getSelectedAbc().constants, null, true))) {
Namespace ns = mname.getNamespace(abc.getSelectedAbc().constants);
if (ns != null && ns.hasName(pkg, abc.getSelectedAbc().constants)) {
name_index = ii.name_index;
break;
}
}
}*/
ABC abc = abcIndex.getSelectedAbc();
AVM2ConstantPool constants = abc.constants;
AbcIndexing.ClassIndex ci = abcIndex.findClass(new TypeItem(dname));
if (ci != null) {
Multiname m = ci.abc.instance_info.get(ci.index).getName(ci.abc.constants);
if (m != null) {
Namespace ns = ci.abc.instance_info.get(ci.index).getName(ci.abc.constants).getNamespace(ci.abc.constants);
String n = m.getName(ci.abc.constants, new ArrayList<>(), true, true /*FIXME!!*/);
String nsn = ns == null ? null : ns.getName(ci.abc.constants).toRawString();
name_index = constants.getQnameId(
n,
ns == null ? Namespace.KIND_PACKAGE : ns.kind,
nsn, true);
}
}
for (int i = 1; i < constants.getMultinameCount(); i++) {
Multiname mname = constants.getMultiname(i);
if (mname != null && name.equals(mname.getName(constants, null, true, true /*FIXME!!*/))) {
if (mname.getNamespace(constants) != null && pkg.equals(mname.getNamespace(constants).getName(constants))) {
name_index = i;
break;
}
}
}
if (name_index == 0) {
if (pkg.isEmpty() && localData.currentScript != null /*FIXME!*/) {
for (Trait t : localData.currentScript.traits.traits) {
if (t.getName(abc).getName(constants, null, true, true /*FIXME!!*/).equals(name)) {
name_index = t.name_index;
break;
}
}
}
if (name_index == 0) {
name_index = constants.getMultinameId(Multiname.createQName(false, constants.getStringId(name, true), constants.getNamespaceId(Namespace.KIND_PACKAGE, pkg, 0, true)), true);
}
}
if (item instanceof ApplyTypeAVM2Item) {
ApplyTypeAVM2Item atype = (ApplyTypeAVM2Item) item;
int[] params = new int[atype.params.size()];
int i = 0;
for (GraphTargetItem s : atype.params) {
params[i++] = (s instanceof NullAVM2Item) ? 0 : resolveType(localData, s, abcIndex);
}
return constants.getMultinameId(Multiname.createTypeName(name_index, params), true);
}
return name_index;
}
@Override
public List<GraphSourceItem> generateDiscardValue(SourceGeneratorLocalData localData, GraphTargetItem item) throws CompilationException {
List<GraphSourceItem> ret = item.toSource(localData, this);
ret.add(ins(AVM2Instructions.Pop));
return ret;
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, PushItem item) throws CompilationException {
return item.value.toSource(localData, this);
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, PopItem item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
return ret;
}
}