Added: AS3 ambiguous namespace detection (back again)

Fixed: #2514 AS3 direct editation - problems with namespaces
This commit is contained in:
Jindra Petřík
2026-02-28 20:57:33 +01:00
parent 92e43cb615
commit 0ccacf3865
12 changed files with 286 additions and 130 deletions

View File

@@ -225,46 +225,36 @@ public class FullMultinameAVM2Item extends AVM2Item {
} else {
localName = constants.getMultiname(multinameIndex).getNameAndCustomNamespace(localData.usedDeobfuscations, localData.abc, fullyQualifiedNames, false, true, customNsRef);
}
DottedChain customNs = customNsRef.getVal();
if (customNs != null) {
String nsname = customNs.getLast();
String identifier = IdentifiersDeobfuscation.printIdentifier(localData.abc.getSwf(), localData.usedDeobfuscations, true, nsname);
writer.hilightSpecial(identifier, HighlightSpecialType.TYPE_NAME, customNs.toRawString());
writer.appendNoHilight("::");
} else {
//FIXME!! This is slow, should be moved to indexing
if (false && parentType instanceof TypeItem) { //not ApplyTypeAVM2Item or UnboundedTypeItem
String rawName = constants.getMultiname(multinameIndex).getName(localData.usedDeobfuscations, localData.abc, localData.abc.constants, fullyQualifiedNames, true, true);
List<AbcIndexing.PropertyDef> defs = new ArrayList<>();
List<Boolean> staticRef = new ArrayList<>();
localData.abcIndex.getClassTraits(localData.usedDeobfuscations, parentType, localData.abc, null, true, true, true, true, true, defs, staticRef);
int numStaticUsed = 0;
int numInstanceUsed = 0;
for (int i = 0; i < defs.size(); i++) {
AbcIndexing.PropertyDef def = defs.get(i);
if (Objects.equals(rawName, def.getPropertyName())) {
//cannot access instance properties via static context
if (isStatic && !staticRef.get(i)) {
continue;
}
if (staticRef.get(i)) {
numStaticUsed++;
} else {
numInstanceUsed++;
}
}
}
if (numInstanceUsed > 1 || numStaticUsed > 1) {
Namespace ns = constants.getMultiname(multinameIndex).getSingleNamespace(localData.abc.constants);
if (ns != null) {
String prefix = Namespace.kindToPrefix(ns.kind);
if (prefix != null) {
writer.append(prefix).append("::");
}
Boolean isAmbiguous = null;
if (parentType instanceof TypeItem) { //not ApplyTypeAVM2Item or UnboundedTypeItem
String rawName = constants.getMultiname(multinameIndex).getName(localData.usedDeobfuscations, localData.abc, localData.abc.constants, fullyQualifiedNames, true, true);
isAmbiguous = localData.abcIndex.isPropertyAmbiguous(localData.abc, rawName, parentType, true, true);
}
/*if (customNs != null) {
isAmbiguous = true;
}*/
if (isAmbiguous == null || isAmbiguous) {
if (customNs != null) {
String nsname = customNs.getLast();
String identifier = IdentifiersDeobfuscation.printIdentifier(localData.abc.getSwf(), localData.usedDeobfuscations, true, nsname);
writer.hilightSpecial(identifier, HighlightSpecialType.TYPE_NAME, customNs.toRawString());
writer.appendNoHilight("::");
} else if (isAmbiguous != null) {
Namespace ns = constants.getMultiname(multinameIndex).getSingleNamespace(localData.abc.constants);
if (ns != null) {
String prefix = Namespace.kindToPrefix(ns.kind);
if (prefix != null) {
writer.append(prefix).append("::");
}
}
}
}
if (!isAttribute && afterDot && namespaceSuffix.isEmpty() && Configuration.as3QNameObfuscatedPropsInSquareBrackets.get()) {
if (IdentifiersDeobfuscation.isValidName(true, localName)) {

View File

@@ -18,15 +18,19 @@ package com.jpexs.decompiler.flash.abc.avm2.model;
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing;
import com.jpexs.decompiler.flash.abc.types.Multiname;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TypeItem;
import com.jpexs.decompiler.graph.model.LocalData;
import com.jpexs.helpers.Reference;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@@ -94,14 +98,28 @@ public class GetLexAVM2Item extends AVM2Item {
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) {
Reference<DottedChain> customNsRef = new Reference<>(null);
String localName = propertyName.getNameAndCustomNamespace(localData.usedDeobfuscations, localData.abc, localData.fullyQualifiedNames, false, true, customNsRef);
DottedChain customNs = customNsRef.getVal();
if (customNs != null) {
DottedChain customNs = customNsRef.getVal();
if (customNs != null) {
String nsname = customNs.getLast();
String identifier = IdentifiersDeobfuscation.printIdentifier(localData.abc.getSwf(), localData.usedDeobfuscations, true, nsname);
writer.hilightSpecial(identifier, HighlightSpecialType.TYPE_NAME, customNs.toRawString());
writer.appendNoHilight("::");
getSrcData().localName = nsname + "::" + localName;
return writer.append(localName);
Boolean ambiguous = null;
if (localData.classIndex > -1) {
DottedChain fullClassName = localData.abc.instance_info.get(localData.classIndex).getName(localData.abc.constants).getNameWithNamespace(new HashSet<>(), localData.abc, localData.abc.constants, false);
ambiguous = localData.abcIndex.isPropertyAmbiguous(localData.abc, localName, new TypeItem(fullClassName), true, true);
}
if (ambiguous == null || ambiguous == true) {
writer.hilightSpecial(identifier, HighlightSpecialType.TYPE_NAME, customNs.toRawString());
writer.appendNoHilight("::");
getSrcData().localName = nsname + "::" + localName;
return writer.append(localName);
} else {
getSrcData().localName = nsname + "::" + localName;
return writer.append(localName);
}
}

View File

@@ -767,7 +767,7 @@ public class AVM2SourceGenerator implements SourceGenerator {
List<List<NamespaceItem>> allopns = new ArrayList<>();
allopns.add(openedNamespaces);
GetterAVM2Item getter = new GetterAVM2Item(allopns, false, false, new ArrayList<>(), new NamespaceItem(pkg.isEmpty() ? baseClassName : pkg.toRawString() + ":" + baseClassName, Namespace.KIND_PROTECTED), isInterface, false, null, false, false, 0,
GetterAVM2Item getter = new GetterAVM2Item(allopns, false, false, new ArrayList<>(), new NamespaceItem(pkg.isEmpty() ? baseClassName : pkg.toRawString() + ":" + baseClassName, Namespace.KIND_PROTECTED, -1), isInterface, false, null, false, false, 0,
true, false, false, "skinParts", new ArrayList<>(), new ArrayList<>(), new ArrayList<>(),
getterBody, subvars, new TypeItem("Object"));
@@ -783,7 +783,7 @@ public class AVM2SourceGenerator implements SourceGenerator {
NewObjectAVM2Item sltVal = new NewObjectAVM2Item(null, null, pairs);
SlotAVM2Item slt = new SlotAVM2Item(
new ArrayList<>(), new NamespaceItem(pkg.isEmpty() ? baseClassName : pkg.toRawString() + ":" + baseClassName, Namespace.KIND_PRIVATE),
new ArrayList<>(), new NamespaceItem(pkg.isEmpty() ? baseClassName : pkg.toRawString() + ":" + baseClassName, Namespace.KIND_PRIVATE, -1),
null, true, "_skinParts", new TypeItem("Object"), sltVal, 0);
traitItems.add(0, slt);
@@ -1763,6 +1763,27 @@ public class AVM2SourceGenerator implements SourceGenerator {
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);
ConstAVM2Item cai = (ConstAVM2Item) item;
if (cai.ns) {
TraitSlotConst tsc = (TraitSlotConst) traits[k];
GraphTargetItem val = cai.value;
GraphTargetItem type = cai.type;
if (cai.pkg != null) {
cai.pkg.resolveCustomNs(abcIndex, importedClasses, localData.pkg, openedNamespaces, localData);
}
int namespace = cai.pkg == null ? 0 : cai.pkg.getCpoolIndex(abcIndex);
tsc.type_index = 0;
ValueKind vk = getValueKind(namespace, type, val, cai.generatedNs);
if (vk == null) {
tsc.value_index = ValueKind.CONSTANT_Undefined;
tsc.value_kind = ValueKind.CONSTANT_Undefined;
} else {
tsc.value_kind = vk.value_kind;
tsc.value_index = vk.value_index;
}
}
} else if (item instanceof SlotAVM2Item) {
traits[k].name_index = traitName(genNs(importedClasses, pkg, ((SlotAVM2Item) item).pkg, openedNamespaces, localData, ((SlotAVM2Item) item).line), ((SlotAVM2Item) item).var);
}
@@ -1960,10 +1981,7 @@ public class AVM2SourceGenerator implements SourceGenerator {
TraitSlotConst tsc = (TraitSlotConst) traits[k];
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 (!isScriptTraits && sai.isStatic() != generateStatic) {
@@ -1971,7 +1989,6 @@ public class AVM2SourceGenerator implements SourceGenerator {
}
val = sai.value;
type = sai.type;
isStatic = sai.isStatic();
if (sai.pkg != null) {
sai.pkg.resolveCustomNs(abcIndex, importedClasses, localData.pkg, openedNamespaces, localData);
}
@@ -1984,16 +2001,17 @@ public class AVM2SourceGenerator implements SourceGenerator {
if (!isScriptTraits && cai.isStatic() != generateStatic) {
continue;
}
if (cai.ns) {
continue;
}
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 = cai.ns;
isStatic = cai.isStatic();
}
tsc.type_index = isNamespace ? 0 : (type == null ? 0 : typeName(localData, type));
tsc.type_index = type == null ? 0 : typeName(localData, type);
ValueKind vk = getValueKind(namespace, type, val, generatedNs);
if (vk == null) {
@@ -2299,7 +2317,7 @@ public class AVM2SourceGenerator implements SourceGenerator {
* @throws AVM2ParseException On parse error
* @throws CompilationException On compilation error
*/
public void generateScriptInfo(List<AssignableAVM2Item> sinitVariables, boolean sinitNeedsActivation, List<DottedChain> importedClasses, List<NamespaceItem> openedNamespaces, int scriptIndex, ScriptInfo scriptInfo, List<List<NamespaceItem>> allOpenedNamespaces, SourceGeneratorLocalData localData, List<GraphTargetItem> commands, int classPos) throws AVM2ParseException, CompilationException {
public void generateScriptInfo(List<AssignableAVM2Item> sinitVariables, boolean sinitNeedsActivation, List<DottedChain> importedClasses, List<NamespaceItem> openedNamespaces, int scriptIndex, ScriptInfo scriptInfo, List<List<NamespaceItem>> allOpenedNamespaces, SourceGeneratorLocalData localData, List<GraphTargetItem> commands, int classPos, DottedChain pkg) throws AVM2ParseException, CompilationException {
List<GraphTargetItem> traitsList = new ArrayList<>();
for (GraphTargetItem it : commands) {
if ((it instanceof SlotAVM2Item)
@@ -2316,7 +2334,21 @@ public class AVM2SourceGenerator implements SourceGenerator {
localData.currentScript = scriptInfo;
localData.scriptIndex = scriptIndex;
Trait[] traitArr = generateTraitsPhase1(new ArrayList<>(), new ArrayList<>(), null, null, true, localData, traitsList, scriptInfo.traits, class_index, true);
generateTraitsPhase2(new ArrayList<>(), null/*FIXME*/, traitsList, traitArr, new ArrayList<>(), localData);
generateTraitsPhase2(new ArrayList<>(), null/*FIXME*/, traitsList, traitArr, new ArrayList<>(), localData);
localData.pkg = pkg;
for (NamespaceItem ns : openedNamespaces) {
if (!ns.isResolved()) {
if (ns.kind == NamespaceItem.KIND_NAMESPACE_CUSTOM || ns.kind == Namespace.KIND_NAMESPACE) {
continue;
}
ns.getCpoolIndex(abcIndex);
}
}
for (NamespaceItem ns : openedNamespaces) {
ns.resolveCustomNs(abcIndex, importedClasses, pkg, openedNamespaces, localData);
}
abcIndex.refreshSelected();
generateTraitsPhase3(traitsList, traitArr, localData);
abcIndex.refreshSelected();

View File

@@ -104,6 +104,44 @@ public final class AbcIndexing {
this(null, null);
}
private static class AmbiguousPropertyDef {
private final String propName;
private final GraphTargetItem parent;
public AmbiguousPropertyDef(String propName, GraphTargetItem parent) {
this.propName = propName;
this.parent = parent;
}
@Override
public int hashCode() {
int hash = 7;
hash = 79 * hash + Objects.hashCode(this.propName);
hash = 79 * hash + Objects.hashCode(this.parent);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final AmbiguousPropertyDef other = (AmbiguousPropertyDef) obj;
if (!Objects.equals(this.propName, other.propName)) {
return false;
}
return Objects.equals(this.parent, other.parent);
}
}
/**
* Property key
*/
@@ -168,12 +206,13 @@ public final class AbcIndexing {
case Namespace.KIND_PACKAGE_INTERNAL:
case Namespace.KIND_PROTECTED:
case Namespace.KIND_STATIC_PROTECTED:
case Namespace.KIND_NAMESPACE:
//this.abc = null;
//this.propNsString = abc.constants.getNamespace(propNsIndex).getRawName(abc.constants);
break;
case Namespace.KIND_NAMESPACE:
this.propNsString = abc.constants.getNamespace(propNsIndex).getRawName(abc.constants);
break;
//this.propNsString = abc.constants.getNamespace(propNsIndex).getRawName(abc.constants);
//break;
default:
this.abc = abc;
this.propNsIndex = propNsIndex;
@@ -191,7 +230,7 @@ public final class AbcIndexing {
this.parent = parent;
this.abc = null;
if (nsKind == Namespace.KIND_NAMESPACE) {
this.propNsString = propNsString;
//this.propNsString = propNsString;
}
//this.propNsKind = nsKind;
//this.propNsString = propNsString;
@@ -281,12 +320,10 @@ public final class AbcIndexing {
return;
}
int k = abc.constants.getNamespace(nsIndex).kind;
/*if (k != Namespace.KIND_PACKAGE) {
setPrivate(abc, nsIndex);
}*/
this.propNsIndex = nsIndex;
this.abc = abc;
if (k == Namespace.KIND_PRIVATE) {
this.propNsIndex = nsIndex;
this.abc = abc;
}
}
/**
@@ -556,6 +593,12 @@ public final class AbcIndexing {
private final Map<PropertyNsDef, TraitIndex> classNsProperties = new HashMap<>();
private final Map<PropertyNsDef, TraitIndex> scriptProperties = new HashMap<>();
private final Map<AmbiguousPropertyDef, List<TraitIndex>> instanceAmbiguousProperties = new HashMap<>();
private final Map<AmbiguousPropertyDef, List<TraitIndex>> classAmbiguousProperties = new HashMap<>();
private final Map<AmbiguousPropertyDef, List<TraitIndex>> scriptAmbiguousProperties = new HashMap<>();
/**
* Rebuilds package to objects name map.
@@ -921,7 +964,7 @@ public final class AbcIndexing {
if (ci != null && ci.parent != null && (prop.abc == null || prop.propNsIndex == 0)) {
AbcIndexing.ClassIndex ciParent = ci.parent;
DottedChain parentClass = ciParent.abc.instance_info.get(ciParent.index).getName(ciParent.abc.constants).getNameWithNamespace(new LinkedHashSet<>(), ciParent.abc, ciParent.abc.constants, true);
PropertyDef parentDef = new PropertyDef(prop.propName, new TypeItem(parentClass), prop.propNsString, prop.propNsKind);
PropertyDef parentDef = new PropertyDef(prop.propName, new TypeItem(parentClass), (ABC) null, 0);
TraitIndex pti = findProperty(parentDef, findStatic, findInstance, findProtected, foundStatic);
if (pti != null) {
return pti;
@@ -1059,13 +1102,36 @@ public final class AbcIndexing {
* @param mapNs Map to index
* @param scriptIndex Script index
*/
protected void indexTraits(ABC abc, int name_index, Traits ts, Map<PropertyDef, TraitIndex> map, Map<PropertyNsDef, TraitIndex> mapNs, int scriptIndex) {
protected void indexTraits(ABC abc, int name_index, Traits ts, Map<PropertyDef, TraitIndex> map, Map<PropertyNsDef, TraitIndex> mapNs, Map<AmbiguousPropertyDef, List<TraitIndex>> mapAmbiguous, int scriptIndex) {
for (Trait t : ts.traits) {
ValueKind propValue = null;
if (t instanceof TraitSlotConst) {
TraitSlotConst tsc = (TraitSlotConst) t;
propValue = new ValueKind(tsc.value_index, tsc.value_kind);
}
if (mapAmbiguous != null) {
AmbiguousPropertyDef dp = new AmbiguousPropertyDef(t.getName(abc).getName(new LinkedHashSet<>(), abc, abc.constants, new ArrayList<>() /*?*/, true, false), multinameToType(new LinkedHashSet<>(), name_index, abc, abc.constants));
TraitIndex ti = new TraitIndex(t, abc, getTraitReturnType(new LinkedHashSet<>(), abc, t), getTraitCallReturnType(new LinkedHashSet<>(), abc, t), propValue, multinameToType(new LinkedHashSet<>(), name_index, abc, abc.constants), scriptIndex);
if (!mapAmbiguous.containsKey(dp)) {
mapAmbiguous.put(dp, new ArrayList<>());
mapAmbiguous.get(dp).add(ti);
} else {
int thisNsKind = t.getName(abc).getNamespace(abc.constants).kind;
boolean onlySameNsKind = true;
for (TraitIndex ti2 : mapAmbiguous.get(dp)) {
int prevNsKind = ti2.trait.getName(ti2.abc).getNamespace(ti2.abc.constants).kind;
if (prevNsKind != thisNsKind) {
onlySameNsKind = false;
break;
}
}
if (!onlySameNsKind) {
mapAmbiguous.get(dp).add(ti);
}
}
}
if (map != null) {
PropertyDef dp = new PropertyDef(t.getName(abc).getName(new LinkedHashSet<>(), abc, abc.constants, new ArrayList<>() /*?*/, true, false), multinameToType(new LinkedHashSet<>(), name_index, abc, abc.constants), abc, abc.constants.getMultiname(t.name_index).namespace_index);
map.put(dp, new TraitIndex(t, abc, getTraitReturnType(new LinkedHashSet<>(), abc, t), getTraitCallReturnType(new LinkedHashSet<>(), abc, t), propValue, multinameToType(new LinkedHashSet<>(), name_index, abc, abc.constants), scriptIndex));
@@ -1164,7 +1230,7 @@ public final class AbcIndexing {
List<ClassIndex> addedClasses = new ArrayList<>();
for (int i = 0; i < abc.script_info.size(); i++) {
indexTraits(abc, 0, abc.script_info.get(i).traits, null, scriptProperties, i);
indexTraits(abc, 0, abc.script_info.get(i).traits, null, scriptProperties, scriptAmbiguousProperties, i);
for (int t = 0; t < abc.script_info.get(i).traits.traits.size(); t++) {
Trait tr = abc.script_info.get(i).traits.traits.get(t);
if (tr instanceof TraitClass) {
@@ -1181,8 +1247,8 @@ public final class AbcIndexing {
GraphTargetItem cname = multinameToType(new LinkedHashSet<>(), ii.name_index, abc, abc.constants);
classes.put(new ClassDef(cname, abc, classScriptIndex), cindex);
indexTraits(abc, ii.name_index, ii.instance_traits, instanceProperties, instanceNsProperties, i);
indexTraits(abc, ii.name_index, ci.static_traits, classProperties, classNsProperties, i);
indexTraits(abc, ii.name_index, ii.instance_traits, instanceProperties, instanceNsProperties, instanceAmbiguousProperties, i);
indexTraits(abc, ii.name_index, ci.static_traits, classProperties, classNsProperties, classAmbiguousProperties, i);
}
}
}
@@ -1267,4 +1333,23 @@ public final class AbcIndexing {
}
return isInstanceOf(ci.abc, ci.index, searchClassName);
}
public Boolean isPropertyAmbiguous(ABC abc, String propertyName, GraphTargetItem parent, boolean findStatic, boolean findInstance) {
AmbiguousPropertyDef key = new AmbiguousPropertyDef(propertyName, parent);
if (findStatic && classAmbiguousProperties.containsKey(key)) {
return classAmbiguousProperties.get(key).size() > 1;
}
if (findInstance && instanceAmbiguousProperties.containsKey(key)) {
return instanceAmbiguousProperties.get(key).size() > 1;
}
ClassIndex ci = findClass(parent, abc, null);
if (ci != null) {
if (ci.parent != null) {
ci = ci.parent;
DottedChain parentClassName = ci.abc.instance_info.get(ci.index).getName(ci.abc.constants).getNameWithNamespace(new HashSet<>(), ci.abc, ci.abc.constants, false);
return isPropertyAmbiguous(ci.abc, propertyName, new TypeItem(parentClassName), findStatic, findInstance);
}
}
return null;
}
}

View File

@@ -94,6 +94,7 @@ import com.jpexs.decompiler.flash.abc.types.Float4;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
import com.jpexs.decompiler.flash.action.swf4.ActionIf;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.flash.tags.Tag;
@@ -689,12 +690,12 @@ public class ActionScript3Parser {
private void classTraits(List<List<NamespaceItem>> allOpenedNamespaces, boolean outsidePackage, List<AssignableAVM2Item> cinitVariables, Reference<Boolean> cinitNeedsActivation, List<GraphTargetItem> cinit, List<DottedChain> importedClasses, List<NamespaceItem> openedNamespaces, NamespaceItem pkg, String classNameStr, boolean isInterface, List<GraphTargetItem> traits, List<AssignableAVM2Item> iinitVariables, Reference<Boolean> iinitNeedsActivation, Reference<GraphTargetItem> iinit, ABC abc) throws AVM2ParseException, IOException, CompilationException, InterruptedException {
NamespaceItem publicNs = new NamespaceItem("", Namespace.KIND_PACKAGE);
NamespaceItem privateNs = new NamespaceItem(pkg.name.toRawString().isEmpty() ? classNameStr : pkg.name.toRawString() + ":" + classNameStr, Namespace.KIND_PRIVATE);
NamespaceItem protectedNs = new NamespaceItem(pkg.name.toRawString().isEmpty() ? classNameStr : pkg.name.toRawString() + ":" + classNameStr, Namespace.KIND_PROTECTED);
NamespaceItem staticProtectedNs = new NamespaceItem(pkg.name.toRawString().isEmpty() ? classNameStr : pkg.name.toRawString() + ":" + classNameStr, Namespace.KIND_STATIC_PROTECTED);
NamespaceItem packageInternalNs = new NamespaceItem(pkg.name, Namespace.KIND_PACKAGE_INTERNAL);
NamespaceItem interfaceNs = new NamespaceItem(pkg.name.toRawString().isEmpty() ? classNameStr : pkg.name.toRawString() + ":" + classNameStr, Namespace.KIND_NAMESPACE);
NamespaceItem publicNs = new NamespaceItem("", Namespace.KIND_PACKAGE, -1);
NamespaceItem privateNs = new NamespaceItem(pkg.name.toRawString().isEmpty() ? classNameStr : pkg.name.toRawString() + ":" + classNameStr, Namespace.KIND_PRIVATE, -1);
NamespaceItem protectedNs = new NamespaceItem(pkg.name.toRawString().isEmpty() ? classNameStr : pkg.name.toRawString() + ":" + classNameStr, Namespace.KIND_PROTECTED, -1);
NamespaceItem staticProtectedNs = new NamespaceItem(pkg.name.toRawString().isEmpty() ? classNameStr : pkg.name.toRawString() + ":" + classNameStr, Namespace.KIND_STATIC_PROTECTED, -1);
NamespaceItem packageInternalNs = new NamespaceItem(pkg.name, Namespace.KIND_PACKAGE_INTERNAL, -1);
NamespaceItem interfaceNs = new NamespaceItem(pkg.name.toRawString().isEmpty() ? classNameStr : pkg.name.toRawString() + ":" + classNameStr, Namespace.KIND_NAMESPACE, -1);
openedNamespaces = new ArrayList<>(openedNamespaces);
allOpenedNamespaces.add(openedNamespaces);
@@ -820,7 +821,7 @@ public class ActionScript3Parser {
s = lex();
expected(s, lexer.yyline(), SymbolType.STRING);
preSymbols.add(s);
namespace = new NamespaceItem((String) s.value, Namespace.KIND_NAMESPACE);
namespace = new NamespaceItem((String) s.value, Namespace.KIND_NAMESPACE, lexer.yyline());
s = lex();
expected(s, lexer.yyline(), SymbolType.PARENT_CLOSE);
preSymbols.add(s);
@@ -846,7 +847,7 @@ public class ActionScript3Parser {
}
if (namespace == null && customNs != null) {
//Special: it will be resolved later:
namespace = new NamespaceItem(customNs, NamespaceItem.KIND_NAMESPACE_CUSTOM);
namespace = new NamespaceItem(customNs, NamespaceItem.KIND_NAMESPACE_CUSTOM, lexer.yyline());
}
switch (s.type) {
@@ -1045,7 +1046,8 @@ public class ActionScript3Parser {
Reference<Integer> numberPrecisionRef,
ABC abc,
Reference<Boolean> sinitNeedsActivation,
List<AssignableAVM2Item> sinitVariables
List<AssignableAVM2Item> sinitVariables,
Reference<DottedChain> pkgRef
) throws AVM2ParseException, IOException, CompilationException, InterruptedException {
Stack<Loop> sinitLoops = new Stack<>();
@@ -1067,7 +1069,8 @@ public class ActionScript3Parser {
sinitLoops,
sinitLoopLabels,
sinitRegisterVars,
sinitVariables
sinitVariables,
pkgRef
)) {
//empty
}
@@ -1088,7 +1091,8 @@ public class ActionScript3Parser {
Stack<Loop> sinitLoops,
Map<Loop, String> sinitLoopLabels,
HashMap<String, Integer> sinitRegisterVars,
List<AssignableAVM2Item> sinitVariables
List<AssignableAVM2Item> sinitVariables,
Reference<DottedChain> pkgRef
) throws AVM2ParseException, IOException, CompilationException, InterruptedException {
ParsedSymbol s;
boolean inPackage = false;
@@ -1110,20 +1114,22 @@ public class ActionScript3Parser {
s = lex();
}
expected(s, lexer.yyline(), SymbolType.CURLY_OPEN);
publicNs = new NamespaceItem(pkgName, Namespace.KIND_PACKAGE);
packageInternalNs = new NamespaceItem(pkgName, Namespace.KIND_PACKAGE_INTERNAL);
pkgRef.setVal(pkgName);
publicNs = new NamespaceItem(pkgName, Namespace.KIND_PACKAGE, -1);
packageInternalNs = new NamespaceItem(pkgName, Namespace.KIND_PACKAGE_INTERNAL, -1);
s = lex();
inPackage = true;
} else {
publicNs = null;
packageInternalNs = new NamespaceItem(scriptName + "$" + scriptIndex, Namespace.KIND_PRIVATE);
packageInternalNs = new NamespaceItem(scriptName + "$" + scriptIndex, Namespace.KIND_PRIVATE, -1);
}
lexer.pushback(s);
allOpenedNamespaces.add(openedNamespaces);
NamespaceItem emptyNs = new NamespaceItem("", Namespace.KIND_PACKAGE);
NamespaceItem emptyNs = new NamespaceItem("", Namespace.KIND_PACKAGE, -1);
openedNamespaces.add(emptyNs);
NamespaceItem as3Ns = new NamespaceItem(AS3_NAMESPACE, Namespace.KIND_NAMESPACE);
NamespaceItem as3Ns = new NamespaceItem(AS3_NAMESPACE, Namespace.KIND_NAMESPACE, -1);
as3Ns.forceResolve(abcIndex);
openedNamespaces.add(as3Ns);
@@ -1262,7 +1268,7 @@ public class ActionScript3Parser {
if (namespaces.get(i) == null || namespaces.get(i).isEmpty()) {
continue;
}
subOpenedNamespaces.add(new NamespaceItem(namespaces.get(i) + ":" + names.get(i), Namespace.KIND_STATIC_PROTECTED));
subOpenedNamespaces.add(new NamespaceItem(namespaces.get(i) + ":" + names.get(i), Namespace.KIND_STATIC_PROTECTED, -1));
}
}
@@ -1667,8 +1673,8 @@ public class ActionScript3Parser {
switch (s.type) {
case USE:
expectedType(SymbolType.NAMESPACE);
GraphTargetItem ns = type(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, variables, abc);
openedNamespaces.add(new NamespaceItem(ns.toString(), Namespace.KIND_PACKAGE /*FIXME?*/));
GraphTargetItem ns = type(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, variables, abc);
openedNamespaces.add(new NamespaceItem(ns.toString(), NamespaceItem.KIND_NAMESPACE_CUSTOM, lexer.yyline()));
break;
case WITH:
needsActivation.setVal(true);
@@ -2857,7 +2863,7 @@ public class ActionScript3Parser {
openedNamespaces.add(new NamespaceItem(fullName, Namespace.KIND_NAMESPACE));
} else */
if (isStar) {
openedNamespaces.add(new NamespaceItem(fullName, Namespace.KIND_PACKAGE));
openedNamespaces.add(new NamespaceItem(fullName, Namespace.KIND_PACKAGE, -1));
} else {
importedClasses.add(fullName);
}
@@ -2885,6 +2891,7 @@ public class ActionScript3Parser {
s = lex();
}
lexer.pushback(s);
openedNamespaces.add(new NamespaceItem(fullName, NamespaceItem.KIND_NAMESPACE_CUSTOM, lexer.yyline()));
} else {
if (!abc.hasDecimalSupport()) {
throw new AVM2ParseException("Invalid use kind", lexer.yyline());
@@ -2978,7 +2985,8 @@ public class ActionScript3Parser {
Reference<Integer> numberContextRef,
ABC abc,
Reference<Boolean> sinitNeedsActivation,
List<AssignableAVM2Item> sinitVariables
List<AssignableAVM2Item> sinitVariables,
Reference<DottedChain> pkgRef
) throws IOException, AVM2ParseException, CompilationException, InterruptedException {
//int scriptPrivateNs;
@@ -2992,7 +3000,7 @@ public class ActionScript3Parser {
Reference<Integer> numberUsageRef = new Reference<>(NumberContext.USE_NUMBER);
Reference<Integer> numberRoundingRef = new Reference<>(NumberContext.ROUND_HALF_EVEN);
Reference<Integer> numberPrecisionRef = new Reference<>(34);
scriptTraits(importedClasses, openedNamespaces, allOpenedNamespaces, scriptIndex, fileName, items, numberUsageRef, numberRoundingRef, numberPrecisionRef, abc, sinitNeedsActivation, sinitVariables);
scriptTraits(importedClasses, openedNamespaces, allOpenedNamespaces, scriptIndex, fileName, items, numberUsageRef, numberRoundingRef, numberPrecisionRef, abc, sinitNeedsActivation, sinitVariables, pkgRef);
NumberContext nc = new NumberContext(numberUsageRef.getVal(), numberPrecisionRef.getVal(), numberRoundingRef.getVal());
if (!nc.isDefault()) {
@@ -3030,11 +3038,12 @@ public class ActionScript3Parser {
Reference<Integer> numberContextRef,
ABC abc,
Reference<Boolean> sinitNeedsActivation,
List<AssignableAVM2Item> sinitVariables
List<AssignableAVM2Item> sinitVariables,
Reference<DottedChain> pkgRef
) throws AVM2ParseException, IOException, CompilationException, InterruptedException {
lexer = new ActionScriptLexer(str);
List<GraphTargetItem> ret = parseScript(importedClasses, openedNamespaces, allOpenedNamespaces, scriptIndex, fileName, numberContextRef, abc, sinitNeedsActivation, sinitVariables);
List<GraphTargetItem> ret = parseScript(importedClasses, openedNamespaces, allOpenedNamespaces, scriptIndex, fileName, numberContextRef, abc, sinitNeedsActivation, sinitVariables, pkgRef);
if (lex().type != SymbolType.EOF) {
throw new AVM2ParseException("Parsing finished before end of the file", lexer.yyline());
}
@@ -3056,7 +3065,7 @@ public class ActionScript3Parser {
* @throws AVM2ParseException On parsing error
* @throws CompilationException On compilation error
*/
public void addScriptFromTree(List<AssignableAVM2Item> sinitVariables, boolean sinitNeedsActivation, List<DottedChain> importedClasses, List<NamespaceItem> openedNamespaces, List<List<NamespaceItem>> allOpenedNamespaces, List<GraphTargetItem> items, int classPos, String documentClass, Integer numberContext) throws AVM2ParseException, CompilationException {
public void addScriptFromTree(List<AssignableAVM2Item> sinitVariables, boolean sinitNeedsActivation, List<DottedChain> importedClasses, List<NamespaceItem> openedNamespaces, List<List<NamespaceItem>> allOpenedNamespaces, List<GraphTargetItem> items, int classPos, String documentClass, Integer numberContext, DottedChain pkg) throws AVM2ParseException, CompilationException {
AVM2SourceGenerator gen = new AVM2SourceGenerator(abcIndex);
SourceGeneratorLocalData localData = new SourceGeneratorLocalData(
new HashMap<>(), 0, Boolean.FALSE, 0);
@@ -3066,7 +3075,7 @@ public class ActionScript3Parser {
int scriptIndex = abcIndex.getSelectedAbc().script_info.size();
abcIndex.getSelectedAbc().script_info.add(si);
try {
gen.generateScriptInfo(sinitVariables, sinitNeedsActivation, importedClasses, openedNamespaces, scriptIndex, si, allOpenedNamespaces, localData, items, classPos);
gen.generateScriptInfo(sinitVariables, sinitNeedsActivation, importedClasses, openedNamespaces, scriptIndex, si, allOpenedNamespaces, localData, items, classPos, pkg);
} catch (Exception ex) {
Logger.getLogger(ActionScript3Parser.class.getName()).log(Level.FINE, "Script generation exception", ex);
abcIndex.getSelectedAbc().script_info.remove(si);
@@ -3102,8 +3111,9 @@ public class ActionScript3Parser {
List<AssignableAVM2Item> sinitVariables = new ArrayList<>();
List<DottedChain> importedClasses = new ArrayList<>();
List<NamespaceItem> openedNamespaces = new ArrayList<>();
List<GraphTargetItem> traits = scriptTraitsFromString(importedClasses, openedNamespaces, allOpenedNamespaces, s, fileName, scriptIndex, numberContextRef, abc, sinitNeedsActivation, sinitVariables);
addScriptFromTree(sinitVariables, sinitNeedsActivation.getVal(), importedClasses, openedNamespaces, allOpenedNamespaces, traits, classPos, documentClass, numberContextRef.getVal());
Reference<DottedChain> pkgRef = new Reference<>(null);
List<GraphTargetItem> traits = scriptTraitsFromString(importedClasses, openedNamespaces, allOpenedNamespaces, s, fileName, scriptIndex, numberContextRef, abc, sinitNeedsActivation, sinitVariables, pkgRef);
addScriptFromTree(sinitVariables, sinitNeedsActivation.getVal(), importedClasses, openedNamespaces, allOpenedNamespaces, traits, classPos, documentClass, numberContextRef.getVal(), pkgRef.getVal());
}
/**

View File

@@ -376,15 +376,24 @@ public class ActionScript3SimpleParser implements SimpleParser {
continue;
}
} else {
if (!expected(errors, s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.NAMESPACE, SymbolType.MULTIPLY)) {
if (!expected(errors, s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.NAMESPACE, SymbolType.MULTIPLY,
SymbolType.PUBLIC, SymbolType.PROTECTED, SymbolType.PRIVATE, SymbolType.INTERNAL
)) {
lexer.pushback(s);
return new Path();
}
if (s.isType(SymbolType.PUBLIC, SymbolType.PROTECTED, SymbolType.PRIVATE, SymbolType.INTERNAL)) {
nsKeyword = s;
}
lastName = s.value.toString();
identPos = s.position;
}
s = lex();
if (s.type == SymbolType.NAMESPACESUFFIX) {
if (nsKeyword != null) {
errors.add(new SimpleParseException(nsKeyword.value + " not expected in this situation", lexer.yyline(), nsKeyword.position));
}
lastName += "#" + s.value;
s = lex();
}

View File

@@ -55,6 +55,11 @@ public class NamespaceItem {
* Namespace index
*/
private int nsIndex = -1;
/**
* Line
*/
private int line;
/**
* Force resolves namespace.
@@ -68,20 +73,24 @@ public class NamespaceItem {
* Constructor.
* @param name Name
* @param kind Kind
* @param line Line
*/
public NamespaceItem(DottedChain name, int kind) {
public NamespaceItem(DottedChain name, int kind, int line) {
this.name = name;
this.kind = kind;
this.line = line;
}
/**
* Constructor.
* @param name Name
* @param kind Kind
* @param line Line
*/
public NamespaceItem(String name, int kind) {
public NamespaceItem(String name, int kind, int line) {
this.name = DottedChain.parseWithSuffix(name);
this.kind = kind;
this.line = line;
}
/**
@@ -148,35 +157,32 @@ public class NamespaceItem {
resolved = false;
}
if (!resolved) {
DottedChain fullCustom = null;
AbcIndexing.TraitIndex ti = null;
for (DottedChain imp : importedClasses) {
if (imp.getLast().equals(custom)) {
fullCustom = imp;
ti = abcIndex.findScriptProperty(imp);
break;
}
}
if (fullCustom != null) {
/*List<ABC> aas = new ArrayList<>();
aas.add(abc);
aas.addAll(allABCs);*/
AbcIndexing.TraitIndex ti = abcIndex.findScriptProperty(fullCustom);
if (ti != null) {
if (ti.trait instanceof TraitSlotConst) {
if (((TraitSlotConst) ti.trait).isNamespace()) {
Namespace ns = ti.abc.constants.getNamespace(((TraitSlotConst) ti.trait).value_index);
nsIndex = abcIndex.getSelectedAbc().constants.getNamespaceId(ns.kind, ns.getName(ti.abc.constants), 0, true);
return;
}
if (ti == null) {
ti = abcIndex.findScriptProperty(pkg.add(custom, ""));
}
if (ti != null) {
if (ti.trait instanceof TraitSlotConst) {
if (((TraitSlotConst) ti.trait).isNamespace()) {
Namespace ns = ti.abc.constants.getNamespace(((TraitSlotConst) ti.trait).value_index);
nsIndex = abcIndex.getSelectedAbc().constants.getNamespaceId(ns.kind, ns.getName(ti.abc.constants), 0, true);
kind = ns.kind;
return;
}
}
}
throw new CompilationException("Namespace \"" + name + "\" not defined", -1);
throw new CompilationException("Namespace \"" + name + "\" not defined", line);
}
nsIndex = abcIndex.getSelectedAbc().constants.getNamespaceId(Namespace.KIND_NAMESPACE,
outAbc.getVal().constants.getNamespace(value.getVal().value_index).getName(outAbc.getVal().constants), 0, true);
Namespace ns = outAbc.getVal().constants.getNamespace(value.getVal().value_index);
nsIndex = abcIndex.getSelectedAbc().constants.getNamespaceId(ns.kind, ns.getName(outAbc.getVal().constants), 0, true);
kind = Namespace.KIND_NAMESPACE;
}
}
@@ -199,7 +205,10 @@ public class NamespaceItem {
return nsIndex;
}
if (kind == Namespace.KIND_NAMESPACE) { //must set manually
throw new CompilationException("Namespace \"" + name + "\" unresolved", -1);
throw new CompilationException("Namespace \"" + name + "\" unresolved", line);
}
if (kind == KIND_NAMESPACE_CUSTOM) { //must set manually
throw new CompilationException("Namespace \"" + name + "\" unresolved", line);
}
nsIndex = abcIndex.getSelectedAbc().constants.getNamespaceId(kind, name, 0, true);
return nsIndex;