diff --git a/CHANGELOG.md b/CHANGELOG.md index b33b98733..dca34f37b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added +- AS3.1 null-conditional operator `?.` (air - swf version 50) +- AS3.1 nullish coalescing operator `??` (air - swf version 50) + ### Fixed - [#2366] Running simple editor on background slowing down other views diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index 3b2670050..761c9748b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -3229,9 +3229,6 @@ public class AVM2Graph extends Graph { return ternar; } - if (true) { //FIXME, WIP - implement compiler part - return ternar; - } if (ternar.expression instanceof EqAVM2Item) { EqAVM2Item eq = (EqAVM2Item) ternar.expression; if (eq.rightSide instanceof NullAVM2Item) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NullCoalesceAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NullCoalesceAVM2Item.java index 7cc1d2d7c..24671c4ce 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NullCoalesceAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NullCoalesceAVM2Item.java @@ -16,8 +16,12 @@ */ package com.jpexs.decompiler.flash.abc.avm2.model; +import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.AVM2SourceGenerator; +import com.jpexs.decompiler.graph.CompilationException; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.SourceGenerator; import com.jpexs.decompiler.graph.model.BinaryOpItem; import java.util.ArrayList; import java.util.List; @@ -32,6 +36,12 @@ public class NullCoalesceAVM2Item extends BinaryOpItem { super(instruction, lineStartItem, PRECEDENCE_NULLCOALESCE, leftSide, rightSide, "??", null, null); } + @Override + public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + AVM2SourceGenerator a2generator = (AVM2SourceGenerator) generator; + return a2generator.generate(localData, this); + } + @Override public GraphTargetItem returnType() { return leftSide.returnType(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java index 95b39ac4f..0f7a8a483 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java @@ -43,6 +43,7 @@ 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.NullCoalesceAVM2Item; 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; @@ -2671,12 +2672,33 @@ public class AVM2SourceGenerator implements SourceGenerator { ret.addAll(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(xmlListReg))); return ret; } - + @Override public List generate(SourceGeneratorLocalData localData, IfItem item) throws CompilationException { return generateIf(localData, item.expression, item.onTrue, item.onFalse, false); } + public List generate(SourceGeneratorLocalData localData, NullCoalesceAVM2Item item) throws CompilationException { + List ret = new ArrayList<>(); + ret.addAll(GraphTargetItem.toSourceMerge(localData, this, item.leftSide)); + ret.add(ins(AVM2Instructions.PushNull)); + AVM2Instruction ifEq = ins(AVM2Instructions.IfEq, 0); + ret.add(ifEq); + + List onNotNull = GraphTargetItem.toSourceMerge(localData, this, item.leftSide); + AVM2Instruction jump = ins(AVM2Instructions.Jump, 0); + onNotNull.add(jump); + ifEq.operands[0] = insToBytes(toInsList(onNotNull)).length; + + List onNull = GraphTargetItem.toSourceMerge(localData, this, item.rightSide); + jump.operands[0] = insToBytes(toInsList(onNull)).length; + + ret.addAll(onNotNull); + ret.addAll(onNull); + + return ret; + } + @Override public List generate(SourceGeneratorLocalData localData, TernarOpItem item) throws CompilationException { List onTrue = new ArrayList<>(); @@ -2989,7 +3011,7 @@ public class AVM2SourceGenerator implements SourceGenerator { ret.add(ins(AVM2Instructions.NewObject, 0)); ret.add(ins(AVM2Instructions.PushWith)); scope = localData.scopeStack.size(); - localData.scopeStack.add(new PropertyAVM2Item(null, false, item.functionName, "" /*??*/, abcIndex, new ArrayList<>(), localData.callStack)); + localData.scopeStack.add(new PropertyAVM2Item(null, false, item.functionName, "" /*??*/, abcIndex, new ArrayList<>(), localData.callStack, false)); } AVM2ConstantPool constants = abcIndex.getSelectedAbc().constants; ret.add(ins(AVM2Instructions.NewFunction, method(null, false, constants.getStringId(item.functionName, true), true, false, false, localData.callStack, localData.pkg, item.needsActivation, item.subvariables, 0 /*Set later*/, item.hasRest, item.line, localData.currentClassBaseName, null, false, localData, item.paramTypes, item.paramNames, item.paramValues, item.body, item.retType))); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java index 5219d038c..d6e0841fe 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java @@ -45,6 +45,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.NewArrayAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.NewObjectAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.NextNameAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.NullCoalesceAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.PostDecrementAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.PostIncrementAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.RegExpAvm2Item; @@ -196,10 +197,11 @@ public class ActionScript3Parser { } ParsedSymbol s = lex(); GraphTargetItem ret = newcmds; - while (s.isType(SymbolType.DOT, SymbolType.PARENT_OPEN, SymbolType.BRACKET_OPEN, SymbolType.TYPENAME, SymbolType.FILTER, SymbolType.DESCENDANTS)) { + while (s.isType(SymbolType.DOT, SymbolType.NULL_DOT, SymbolType.PARENT_OPEN, SymbolType.BRACKET_OPEN, SymbolType.TYPENAME, SymbolType.FILTER, SymbolType.DESCENDANTS)) { switch (s.type) { case BRACKET_OPEN: case DOT: + case NULL_DOT: case TYPENAME: lexer.pushback(s); ret = member(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, ret, registerVars, inFunction, inMethod, variables, abc); @@ -282,10 +284,14 @@ public class ActionScript3Parser { } GraphTargetItem ret = obj; ParsedSymbol s = lex(); - while (s.isType(SymbolType.DOT, SymbolType.BRACKET_OPEN, SymbolType.TYPENAME)) { + while (s.isType(SymbolType.DOT, SymbolType.NULL_DOT, SymbolType.BRACKET_OPEN, SymbolType.TYPENAME)) { ParsedSymbol s2 = lex(); boolean attr = false; - if (s.type == SymbolType.DOT) { + boolean nullDot = false; + if (s.type == SymbolType.NULL_DOT) { + nullDot = true; + lexer.pushback(s2); + } else if (s.type == SymbolType.DOT) { if (s2.type == SymbolType.ATTRIBUTE) { attr = true; } else { @@ -335,7 +341,7 @@ public class ActionScript3Parser { if (ns != null) { ret = new NamespacedAVM2Item(ns, propName, propItem, ret, attr, openedNamespaces, null); } else { - ret = new PropertyAVM2Item(ret, attr, propName, nsSuffix, abcIndex, openedNamespaces, new ArrayList<>()); + ret = new PropertyAVM2Item(ret, attr, propName, nsSuffix, abcIndex, openedNamespaces, new ArrayList<>(), nullDot); } s = lex(); } @@ -2285,6 +2291,9 @@ public class ActionScript3Parser { GraphTargetItem istype = rhs; lhs = new IsTypeAVM2Item(null, null, lhs, istype); break; + case NULL_COALESCE: + lhs = new NullCoalesceAVM2Item(null, null, lhs, rhs); + break; case ASSIGN: case ASSIGN_BITAND: case ASSIGN_BITOR: diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/CallAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/CallAVM2Item.java index 2ce71091c..8cc36cda8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/CallAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/CallAVM2Item.java @@ -138,7 +138,7 @@ public class CallAVM2Item extends AVM2Item { nobj.setRegNumber(0); obj = nobj; }*/ - PropertyAVM2Item p = new PropertyAVM2Item(obj, n.isAttribute(), n.getVariableName(), n.getNamespaceSuffix(), g.abcIndex, n.openedNamespaces, new ArrayList<>()); + PropertyAVM2Item p = new PropertyAVM2Item(obj, n.isAttribute(), n.getVariableName(), n.getNamespaceSuffix(), g.abcIndex, n.openedNamespaces, new ArrayList<>(), false); p.setAssignedValue(n.getAssignedValue()); callable = p; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NamespaceItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NamespaceItem.java index da9436bf3..6360bde76 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NamespaceItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NamespaceItem.java @@ -136,7 +136,7 @@ public class NamespaceItem { } if (kind == KIND_NAMESPACE_CUSTOM) { String custom = name.toRawString(); - PropertyAVM2Item prop = new PropertyAVM2Item(null, false, custom, "", abcIndex, openedNamespaces, new ArrayList<>()); + PropertyAVM2Item prop = new PropertyAVM2Item(null, false, custom, "", abcIndex, openedNamespaces, new ArrayList<>(), false); Reference value = new Reference<>(null); Reference outAbc = new Reference<>(null); Reference isType = new Reference<>(false); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java index 2119e9655..27adfaa47 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java @@ -16,6 +16,7 @@ */ 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.AVM2ConstantPool; @@ -41,6 +42,8 @@ import com.jpexs.decompiler.graph.SourceGenerator; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.decompiler.graph.model.LocalData; import com.jpexs.helpers.Reference; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -95,10 +98,11 @@ public class PropertyAVM2Item extends AssignableAVM2Item { * Scope stack */ public List scopeStack = new ArrayList<>(); + private final boolean nullish; @Override public AssignableAVM2Item copy() { - PropertyAVM2Item p = new PropertyAVM2Item(object, attribute, propertyName, namespaceSuffix, abcIndex, openedNamespaces, callStack); + PropertyAVM2Item p = new PropertyAVM2Item(object, attribute, propertyName, namespaceSuffix, abcIndex, openedNamespaces, callStack, nullish); return p; } @@ -112,8 +116,9 @@ public class PropertyAVM2Item extends AssignableAVM2Item { * @param abcIndex ABC indexing * @param openedNamespaces Opened namespaces * @param callStack Call stack + * @param nullish Nullish */ - public PropertyAVM2Item(GraphTargetItem object, boolean attribute, String propertyName, String namespaceSuffix, AbcIndexing abcIndex, List openedNamespaces, List callStack) { + public PropertyAVM2Item(GraphTargetItem object, boolean attribute, String propertyName, String namespaceSuffix, AbcIndexing abcIndex, List openedNamespaces, List callStack, boolean nullish) { this.attribute = attribute; this.propertyName = propertyName; this.namespaceSuffix = namespaceSuffix; @@ -121,6 +126,7 @@ public class PropertyAVM2Item extends AssignableAVM2Item { this.abcIndex = abcIndex; this.openedNamespaces = openedNamespaces; this.callStack = callStack; + this.nullish = nullish; } @Override @@ -468,6 +474,8 @@ public class PropertyAVM2Item extends AssignableAVM2Item { */ public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator, boolean needsReturn) throws CompilationException { + + AVM2SourceGenerator a2Generator = (AVM2SourceGenerator) generator; Reference objType = new Reference<>(null); Reference propType = new Reference<>(null); Reference propIndex = new Reference<>(0); @@ -507,14 +515,46 @@ public class PropertyAVM2Item extends AssignableAVM2Item { needsReturn ? null : ins(AVM2Instructions.Pop) ); } - return toSourceMerge(localData, generator, + + List onFalse = toSourceMerge(localData, generator, isSuper ? ins(AVM2Instructions.FindPropertyStrict, propertyId) : obj, ins(isSuper ? AVM2Instructions.GetSuper : AVM2Instructions.GetProperty, propertyId), needsReturn ? null : ins(AVM2Instructions.Pop) ); + + if (!nullish) { + return onFalse; + } + + + AVM2Instruction ifFalse = ins(AVM2Instructions.IfFalse, 0); + List result = toSourceMerge(localData, generator, obj, + ins(AVM2Instructions.PushNull), + ins(AVM2Instructions.Equals), + ifFalse + ); + + List onTrue = new ArrayList<>(); + onTrue.add(ins(AVM2Instructions.PushNull)); + AVM2Instruction jump = ins(AVM2Instructions.Jump, 0); + onTrue.add(jump); + ifFalse.operands[0] = getBytesLen(onTrue); + jump.operands[0] = getBytesLen(onFalse); + result.addAll(onTrue); + result.addAll(onFalse); + return result; } } + private int getBytesLen(List code) { + int len = 0; + for (GraphSourceItem instruction : code) { + AVM2Instruction ins = (AVM2Instruction) instruction; + len += ins.getBytes().length; + } + return len; + } + @Override public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { return toSource(localData, generator, true); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/UnresolvedAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/UnresolvedAVM2Item.java index 50692ffe4..56d1c2114 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/UnresolvedAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/UnresolvedAVM2Item.java @@ -418,7 +418,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { ret.setRegNumber(n.getRegNumber()); resolved = ret; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>()); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -445,7 +445,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { GraphTargetItem ret = new NameAVM2Item(t, line, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), null, false, openedNamespaces, abcIndex, false); resolved = ret; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>()); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -458,7 +458,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { boolean isProperty = false; if (localData != null) { //resolve can be called without localData - PropertyAVM2Item resolvedx = new PropertyAVM2Item(null, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), abc, openedNamespaces, callStack); + PropertyAVM2Item resolvedx = new PropertyAVM2Item(null, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), abc, openedNamespaces, callStack, false); ((PropertyAVM2Item) resolvedx).scopeStack = scopeStack; ((PropertyAVM2Item) resolvedx).setAssignedValue(assignedValue); Reference objectType = new Reference<>(null); @@ -488,7 +488,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { if (ci != null) { resolved = ti; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>()); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -515,7 +515,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { } resolved = ti; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>()); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -533,7 +533,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { TypeItem ret = new TypeItem(imp); resolved = ret; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>()); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -566,7 +566,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { TypeItem ret = new TypeItem(fname); resolved = ret; for (int j = i + 1; j < name.size(); j++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(j), name.get(j), name.getNamespaceSuffix(j), abc, openedNamespaces, new ArrayList<>()); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(j), name.get(j), name.getNamespaceSuffix(j), abc, openedNamespaces, new ArrayList<>(), false); if (j == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -595,7 +595,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { TypeItem ret = ti; resolved = ret; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>()); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -632,7 +632,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { NameAVM2Item ret = new NameAVM2Item(ntype, line, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), null, false, openedNamespaces, abcIndex, false); resolved = ret; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>()); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -655,7 +655,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { resolved = null; GraphTargetItem ret = null; for (int i = 0; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, callStack); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, callStack, false); if (ret == null) { ((PropertyAVM2Item) resolved).scopeStack = scopeStack; ret = resolved; diff --git a/libsrc/ffdec_lib/testdata/as3_harman/bin/harman.swf b/libsrc/ffdec_lib/testdata/as3_harman/bin/harman.swf index a88da8fee..a4abffb67 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_harman/bin/harman.swf and b/libsrc/ffdec_lib/testdata/as3_harman/bin/harman.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_harman/bin/harman_encrypted.swf b/libsrc/ffdec_lib/testdata/as3_harman/bin/harman_encrypted.swf index 82f5b563b..25abb41a6 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_harman/bin/harman_encrypted.swf and b/libsrc/ffdec_lib/testdata/as3_harman/bin/harman_encrypted.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_harman/src/Operators.as b/libsrc/ffdec_lib/testdata/as3_harman/src/Operators.as index 57330f7e4..793eec568 100644 --- a/libsrc/ffdec_lib/testdata/as3_harman/src/Operators.as +++ b/libsrc/ffdec_lib/testdata/as3_harman/src/Operators.as @@ -4,17 +4,29 @@ package { private var a:Object = {x:1, y:2}; private var b:String = null; + private var c:String = null; public function testNullMember() : void { var result:*; result = a?.z; + + result = f()?.z; + } public function testNullCoalesce() :void { var result:String; - result = b ?? "empty"; + result = b ?? "empty"; + } + + public function f():Object { + return {z:5}; + } + + public function verbatimString(): void { + var s:String = @"ab\ncd"; } } }