Variables code completion

This commit is contained in:
Jindra Petřík
2025-06-15 18:16:06 +02:00
parent 53b8279ce5
commit aecef68d7b
14 changed files with 395 additions and 225 deletions

View File

@@ -469,8 +469,9 @@ public class ActionScript3SimpleParser implements SimpleParser {
private void function(List<SimpleParseException> errors, boolean isInterface, boolean isNative, Reference<Boolean> needsActivation, List<DottedChain> importedClasses, TypeItem thisType, List<NamespaceItem> openedNamespaces, Path functionName, boolean isMethod, List<VariableOrScope> variables, ABC abc, int functionNamePos, boolean isStatic, Reference<Path> returnTypeRef, Reference<Variable> returnSubTypeRef) throws IOException, AVM2ParseException, SimpleParseException, InterruptedException {
ParsedSymbol s;
expectedType(errors, SymbolType.PARENT_OPEN);
ParsedSymbol s = lex();
expected(errors, s, lexer.yyline(), SymbolType.PARENT_OPEN);
int scopePos = s.position;
s = lex();
List<Path> paramNames = new ArrayList<>();
List<Integer> paramPositions = new ArrayList<>();
@@ -543,21 +544,26 @@ public class ActionScript3SimpleParser implements SimpleParser {
subvariables.add(new Variable(true, paramNames.get(paramNames.size() - 1), paramPositions.get(paramNames.size() - 1), null, new Path("Array"), null));
}
Reference<Boolean> needsActivation2 = new Reference<>(false);
if (!isInterface && !isNative) {
s = lex();
expected(errors, s, lexer.yyline(), SymbolType.CURLY_OPEN);
subvariables.add(new Variable(true, new Path("arguments"), -s.position - 1, null, new Path("Array"), null));
commands(errors, thisType, needsActivation2, importedClasses, openedNamespaces, new Stack<>(), new HashMap<>(), new HashMap<>(), true, isMethod, isStatic, 0, subvariables, abc);
expectedType(errors, SymbolType.CURLY_CLOSE);
s = lex();
expected(errors, s, lexer.yyline(), SymbolType.CURLY_CLOSE);
} else {
expectedType(errors, SymbolType.SEMICOLON);
s = lex();
expected(errors, s, lexer.yyline(), SymbolType.SEMICOLON);
}
int scopeEndPos = s.position;
if (isMethod) {
MethodScope ms = new MethodScope(subvariables, isStatic);
MethodScope ms = new MethodScope(scopePos, scopeEndPos, subvariables, isStatic);
variables.add(ms);
} else {
FunctionScope fs = new FunctionScope(subvariables, isStatic);
FunctionScope fs = new FunctionScope(scopePos, scopeEndPos, subvariables, isStatic);
variables.add(fs);
}
}
@@ -861,8 +867,9 @@ public class ActionScript3SimpleParser implements SimpleParser {
if (s.type == SymbolType.ASSIGN) {
List<VariableOrScope> constVarVariables = new ArrayList<>();
expression(errors, thisType, new Reference<>(false), importedClasses, openedNamespaces, new HashMap<>(), false, false, isStatic, true, constVarVariables, false, abc);
classVariables.add(new TraitVarConstValueScope(constVarVariables, isStatic));
int scopePos = s.position;
s = lex();
classVariables.add(new TraitVarConstValueScope(scopePos, s.position, constVarVariables, isStatic));
}
if (s.type != SymbolType.SEMICOLON) {
lexer.pushback(s);
@@ -1031,6 +1038,7 @@ public class ActionScript3SimpleParser implements SimpleParser {
switch (s.type) {
case CLASS:
case INTERFACE:
int scopePos = s.position;
isEmpty = false;
List<NamespaceItem> subOpenedNamespaces = new ArrayList<>(openedNamespaces);
boolean isInterface = false;
@@ -1084,9 +1092,10 @@ public class ActionScript3SimpleParser implements SimpleParser {
classTraits(errors, !inPackage, cinitNeedsActivation, importedClasses, subOpenedNamespaces, pkgName, subNameStr, isInterface, iinitNeedsActivation, abc, classVariables);
sinitVariables.add(new ClassScope(classVariables));
s = lex();
sinitVariables.add(new ClassScope(scopePos, s.position, classVariables));
expectedType(errors, SymbolType.CURLY_CLOSE);
expected(errors, s, lexer.yyline(), SymbolType.CURLY_CLOSE);
break;
case FUNCTION:
isEmpty = false;
@@ -1557,6 +1566,7 @@ public class ActionScript3SimpleParser implements SimpleParser {
s = lex();
boolean found = false;
while (s.type == SymbolType.CATCH) {
int scopePos = s.position;
expectedType(errors, SymbolType.PARENT_OPEN);
s = lex();
if (!expected(errors, s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.THIS, SymbolType.SUPER, SymbolType.STRING_OP)) {
@@ -1571,8 +1581,10 @@ public class ActionScript3SimpleParser implements SimpleParser {
List<VariableOrScope> catchVars = new ArrayList<>();
expectedType(errors, SymbolType.CURLY_OPEN);
commands(errors, thisType, needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, isStatic, forinlevel, catchVars, abc);
expectedType(errors, SymbolType.CURLY_CLOSE);
variables.add(new CatchScope(new Variable(true, enamestr, ePos, null, catchType, null, catchSubType.getVal(), null), catchVars));
int eScopePos = s.position;
s = lex();
expected(errors, s, lexer.yyline(), SymbolType.CURLY_CLOSE);
variables.add(new CatchScope(eScopePos, s.position, new Variable(true, enamestr, ePos, null, catchType, null, catchSubType.getVal(), null), catchVars));
s = lex();
found = true;
}
@@ -2300,7 +2312,9 @@ public class ActionScript3SimpleParser implements SimpleParser {
Map<Integer, Boolean> separatorIsStatic,
Map<Path, List<String>> localTypeTraitNames,
Map<Integer, Path> definitionToType,
Map<Integer, Path> definitionToCallType
Map<Integer, Path> definitionToCallType,
Integer caretPosition,
List<String> variableSuggestions
) throws SimpleParseException, IOException, InterruptedException {
List<List<NamespaceItem>> allOpenedNamespaces = new ArrayList<>();
Reference<Boolean> sinitNeedsActivation = new Reference<>(false);
@@ -2320,7 +2334,7 @@ public class ActionScript3SimpleParser implements SimpleParser {
//Logger.getLogger(ActionScript3SimpleParser.class.getName()).log(Level.SEVERE, null, ex);
throw new SimpleParseException(str, ex.line);
}
SimpleParser.parseVariablesList(new ArrayList<>(), vars, definitionPosToReferences, referenceToDefinition, errors, true, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference, linkHandler, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic, localTypeTraitNames, definitionToType, definitionToCallType);
SimpleParser.parseVariablesList(vars, definitionPosToReferences, referenceToDefinition, errors, true, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference, linkHandler, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic, localTypeTraitNames, definitionToType, definitionToCallType, caretPosition, variableSuggestions);
}
/**

View File

@@ -164,12 +164,14 @@ public class ActionScript2SimpleParser implements SimpleParser {
}
private FunctionScope function(List<SimpleParseException> errors, boolean withBody, Path functionName, int functionNamePosition, boolean isMethod, List<VariableOrScope> variables, boolean inTellTarget, Reference<Boolean> hasEval, boolean isStatic) throws IOException, InterruptedException, SimpleParseException, ActionParseException {
ParsedSymbol s;
expectedType(errors, SymbolType.PARENT_OPEN);
ParsedSymbol s = lex();
int scopePos = s.position;
expected(errors, s, lexer.yyline(), SymbolType.PARENT_OPEN);
s = lex();
List<Path> paramNames = new ArrayList<>();
List<Integer> paramPositions = new ArrayList<>();
int scopeEndPos;
while (s.type != SymbolType.PARENT_CLOSE) {
if (s.type != SymbolType.COMMA) {
lexer.pushback(s);
@@ -191,6 +193,7 @@ public class ActionScript2SimpleParser implements SimpleParser {
}
}
}
scopeEndPos = s.position;
List<VariableOrScope> subvariables = new ArrayList<>();
Reference<Boolean> subHasEval = new Reference<>(false);
@@ -205,7 +208,9 @@ public class ActionScript2SimpleParser implements SimpleParser {
if (withBody) {
expectedType(errors, SymbolType.CURLY_OPEN);
commands(errors, true, isMethod, 0, inTellTarget, subvariables, subHasEval);
expectedType(errors, SymbolType.CURLY_CLOSE);
s = lex();
expected(errors, s, lexer.yyline(), SymbolType.CURLY_CLOSE);
scopeEndPos = s.position;
}
if (subHasEval.getVal()) {
@@ -213,9 +218,9 @@ public class ActionScript2SimpleParser implements SimpleParser {
}
if (isMethod) {
return new MethodScope(subvariables, isStatic);
return new MethodScope(scopePos, scopeEndPos, subvariables, isStatic);
}
return new FunctionScope(subvariables, isStatic);
return new FunctionScope(scopePos, scopeEndPos, subvariables, isStatic);
}
private boolean traits(List<SimpleParseException> errors, boolean isInterface, Path className, List<VariableOrScope> variables, boolean inTellTarget, Reference<Boolean> hasEval) throws IOException, InterruptedException, SimpleParseException, ActionParseException {
@@ -276,10 +281,12 @@ public class ActionScript2SimpleParser implements SimpleParser {
s = lex();
}
if (s.type == SymbolType.ASSIGN) {
int scopePos = s.position;
List<VariableOrScope> subVariables = new ArrayList<>();
expression(errors, false, false, false, true, subVariables, false, hasEval);
variables.add(new TraitVarConstValueScope(subVariables, isStatic));
s = lex();
variables.add(new TraitVarConstValueScope(scopePos, s.position, subVariables, isStatic));
}
if (s.type != SymbolType.SEMICOLON) {
lexer.pushback(s);
@@ -783,6 +790,7 @@ public class ActionScript2SimpleParser implements SimpleParser {
ret = true;
break;
case CLASS:
int scopePos = s.position;
Path className = type(errors, true, variables);
if (className != null) {
s = lex();
@@ -800,10 +808,12 @@ public class ActionScript2SimpleParser implements SimpleParser {
variables.add(new Variable(true, new Path("this"), s.position));
List<VariableOrScope> subVariables = new ArrayList<>();
traits(errors, false, className, subVariables, inTellTarget, hasEval);
ClassScope cs = new ClassScope(subVariables);
s = lex();
ClassScope cs = new ClassScope(scopePos, s.position, subVariables);
variables.add(cs);
expectedType(errors, SymbolType.CURLY_CLOSE);
expectedType(errors, s, lexer.yyline(), SymbolType.CURLY_CLOSE);
ret = true;
}
break;
@@ -993,6 +1003,7 @@ public class ActionScript2SimpleParser implements SimpleParser {
s = lex();
boolean found = false;
while (s.type == SymbolType.CATCH) {
int catchScopePos = s.position;
expectedType(errors, SymbolType.PARENT_OPEN);
ParsedSymbol si = lex();
if (expectedIdentifier(errors, si, lexer.yyline(), SymbolType.STRING)) {
@@ -1007,8 +1018,9 @@ public class ActionScript2SimpleParser implements SimpleParser {
List<VariableOrScope> subvariables = new ArrayList<>();
command(errors, inFunction, inMethod, forinlevel, inTellTarget, subvariables, hasEval);
variables.add(new CatchScope(new Variable(true, new Path((String) si.value), si.position), subvariables));
s = lex();
variables.add(new CatchScope(catchScopePos, s.position, new Variable(true, new Path((String) si.value), si.position), subvariables));
lexer.pushback(s);
}
s = lex();
found = true;
@@ -1585,7 +1597,9 @@ public class ActionScript2SimpleParser implements SimpleParser {
Map<Integer, Boolean> separatorIsStatic,
Map<Path, List<String>> localTypeTraitNames,
Map<Integer, Path> definitionToType,
Map<Integer, Path> definitionToCallType
Map<Integer, Path> definitionToCallType,
Integer caretPosition,
List<String> variableSuggestions
) throws SimpleParseException, IOException, InterruptedException {
List<VariableOrScope> vars = new ArrayList<>();
@@ -1676,7 +1690,7 @@ public class ActionScript2SimpleParser implements SimpleParser {
} catch (ActionParseException ex) {
errors.add(new SimpleParseException(ex.getMessage(), ex.line, ex.position));
}
SimpleParser.parseVariablesList(new ArrayList<>(), vars, definitionPosToReferences, referenceToDefinition, errors, false, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference, linkHandler, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic, localTypeTraitNames, definitionToType, definitionToCallType);
SimpleParser.parseVariablesList(vars, definitionPosToReferences, referenceToDefinition, errors, false, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference, linkHandler, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic, localTypeTraitNames, definitionToType, definitionToCallType, caretPosition, variableSuggestions);
}
private void versionRequired(List<SimpleParseException> errors, ParsedSymbol s, int min) throws SimpleParseException {

View File

@@ -27,11 +27,15 @@ public class CatchScope implements Scope {
private final List<VariableOrScope> privateItems;
private final List<VariableOrScope> sharedItems;
private final int position;
private final int endPosition;
public CatchScope(Variable catchVariable, List<VariableOrScope> catchBody) {
public CatchScope(int position, int endPosition, Variable catchVariable, List<VariableOrScope> catchBody) {
this.privateItems = new ArrayList<>();
this.privateItems.add(catchVariable);
this.sharedItems = catchBody;
this.position = position;
this.endPosition = endPosition;
}
@Override
@@ -44,4 +48,14 @@ public class CatchScope implements Scope {
return privateItems;
}
@Override
public int getPosition() {
return position;
}
@Override
public int getEndPosition() {
return endPosition;
}
}

View File

@@ -26,9 +26,13 @@ import java.util.List;
public class ClassScope implements Scope {
private final List<VariableOrScope> privateItems;
private final int position;
private final int endPosition;
public ClassScope(List<VariableOrScope> traits) {
public ClassScope(int position, int endPosition, List<VariableOrScope> traits) {
this.privateItems = traits;
this.position = position;
this.endPosition = endPosition;
}
@Override
@@ -40,4 +44,14 @@ public class ClassScope implements Scope {
public List<VariableOrScope> getPrivateItems() {
return privateItems;
}
@Override
public int getPosition() {
return position;
}
@Override
public int getEndPosition() {
return endPosition;
}
}

View File

@@ -27,10 +27,14 @@ public class FunctionScope implements Scope {
private final List<VariableOrScope> privateItems;
private final boolean isStatic;
private final int position;
private final int endPosition;
public FunctionScope(List<VariableOrScope> functionBody, boolean isStatic) {
public FunctionScope(int position, int endPosition, List<VariableOrScope> functionBody, boolean isStatic) {
this.privateItems = functionBody;
this.isStatic = isStatic;
this.position = position;
this.endPosition = endPosition;
}
public boolean isStatic() {
@@ -46,4 +50,15 @@ public class FunctionScope implements Scope {
public List<VariableOrScope> getPrivateItems() {
return privateItems;
}
@Override
public int getPosition() {
return position;
}
@Override
public int getEndPosition() {
return endPosition;
}
}

View File

@@ -24,8 +24,8 @@ import java.util.List;
*/
public class MethodScope extends FunctionScope {
public MethodScope(List<VariableOrScope> functionBody, boolean isStatic) {
super(functionBody, isStatic);
public MethodScope(int position, int endPosition, List<VariableOrScope> functionBody, boolean isStatic) {
super(position, endPosition, functionBody, isStatic);
}
}

View File

@@ -27,4 +27,6 @@ public interface Scope extends VariableOrScope {
public List<VariableOrScope> getSharedItems();
public List<VariableOrScope> getPrivateItems();
public int getEndPosition();
}

View File

@@ -29,6 +29,9 @@ public class Separator implements VariableOrScope {
this.position = position;
}
@Override
public int getPosition() {
return position;
}
}

View File

@@ -18,8 +18,10 @@ package com.jpexs.decompiler.flash.simpleparser;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -63,11 +65,12 @@ public interface SimpleParser {
Map<Integer, Boolean> separatorIsStatic,
Map<Path, List<String>> localTypeTraitNames,
Map<Integer, Path> definitionToType,
Map<Integer, Path> definitionToCallType
Map<Integer, Path> definitionToCallType,
Integer caretPosition,
List<String> variableSuggestions
) throws SimpleParseException, IOException, InterruptedException;
public static void parseVariablesList(
List<VariableOrScope> privateVariables,
List<VariableOrScope> sharedVariables,
Map<Integer, List<Integer>> definitionPosToReferences,
Map<Integer, Integer> referenceToDefinition,
@@ -81,9 +84,11 @@ public interface SimpleParser {
Map<Path, List<Integer>> externalTraitKeyToReference,
Map<Integer, Path> separatorPosToType,
Map<Integer, Boolean> separatorIsStatic,
Map<Path, List<String>> localTypeTraitNames,
Map<Path, List<String>> localTypeTraitNames,
Map<Integer, Path> definitionToType,
Map<Integer, Path> definitionToCallType
Map<Integer, Path> definitionToCallType,
Integer caretPosition,
List<String> variableSuggestions
) {
List<Path> externalSimpleTypes = new ArrayList<>();
Map<Path, Path> simpleExternalClassNameToFullClassName = new LinkedHashMap<>();
@@ -98,9 +103,17 @@ public interface SimpleParser {
Map<Integer, Variable> definitionToCallSubType = new LinkedHashMap<>();
Map<Path, Integer> traitFullNameToDefinition = new LinkedHashMap<>();
List<VariableOrScopeWithAccess> variables = new ArrayList<>();
for (VariableOrScope vs : sharedVariables) {
variables.add(new VariableOrScopeWithAccess(vs, true));
}
Map<Integer, Boolean> positionToStatic = new LinkedHashMap<>();
findClassTraits(privateVariables, traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType);
findClassTraits(sharedVariables, traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType);
Map<Path, Integer> parentVarFullNameToDefinitionPosition = new LinkedHashMap<>();
Map<Path, Integer> parentVarNameToDefinitionPosition = new LinkedHashMap<>();
findClassTraits(variables, traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, parentVarFullNameToDefinitionPosition, parentVarNameToDefinitionPosition);
for (Path p : traitFullNameToDefinition.keySet()) {
int definition = traitFullNameToDefinition.get(p);
@@ -116,18 +129,35 @@ public interface SimpleParser {
localTypeTraitNames.get(cls).add((isStatic ? "static::" : "") + traitName);
}
parseVariablesList(privateVariables, sharedVariables, definitionPosToReferences, referenceToDefinition, new LinkedHashMap<>(), new LinkedHashMap<>(), positionToStatic, true, errors, null, innerFunctionCanUseTraits, externalSimpleTypes, externalTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic);
parseVariablesList(variables, definitionPosToReferences, referenceToDefinition, parentVarFullNameToDefinitionPosition, parentVarNameToDefinitionPosition, positionToStatic, true, errors, null, innerFunctionCanUseTraits, externalSimpleTypes, externalTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic, caretPosition, variableSuggestions, null, null);
for (Map.Entry<Integer, Integer> entry : referenceToExternalTypeIndex.entrySet()) {
if (!externalTypeIndexToReference.containsKey(entry.getValue())) {
externalTypeIndexToReference.put(entry.getValue(), new ArrayList<>());
}
externalTypeIndexToReference.get(entry.getValue()).add(entry.getKey());
}
if (caretPosition != null && variableSuggestions.isEmpty()) {
if ((variables.isEmpty() || variables.get(variables.size() - 1).var.getPosition() <= caretPosition)) {
for (Path p : parentVarNameToDefinitionPosition.keySet()) {
if (parentVarNameToDefinitionPosition.get(p) >= 0) {
variableSuggestions.add(p.getFirst().toString());
}
}
variableSuggestions.add("--finish--");
}
}
if (!variableSuggestions.isEmpty()) {
variableSuggestions.remove(variableSuggestions.size() - 1);
}
Set<String> uniqueSuggestions = new LinkedHashSet<>(variableSuggestions);
variableSuggestions.clear();
variableSuggestions.addAll(uniqueSuggestions);
}
public static void parseVariablesList(
List<VariableOrScope> privateVariables,
List<VariableOrScope> sharedVariables,
List<VariableOrScopeWithAccess> variables,
Map<Integer, List<Integer>> definitionPosToReferences,
Map<Integer, Integer> referenceToDefinition,
Map<Path, Integer> parentVarFullNameToDefinitionPosition,
@@ -150,7 +180,11 @@ public interface SimpleParser {
Map<Integer, Path> referenceToExternalTraitKey,
Map<Path, List<Integer>> externalTraitKeyToReference,
Map<Integer, Path> separatorPosToType,
Map<Integer, Boolean> separatorIsStatic
Map<Integer, Boolean> separatorIsStatic,
Integer caretPosition,
List<String> variableSuggestions,
Integer scopeStartPos,
Integer scopeEndPos
) {
Map<Path, Integer> privateVarNameToDefinitionPosition = new LinkedHashMap<>();
privateVarNameToDefinitionPosition.putAll(parentVarNameToDefinitionPosition);
@@ -158,7 +192,30 @@ public interface SimpleParser {
Map<Path, Integer> privateVarFullNameToDefinitionPosition = new LinkedHashMap<>();
privateVarFullNameToDefinitionPosition.putAll(parentVarFullNameToDefinitionPosition);
for (VariableOrScope vt : privateVariables) {
for (int i = 0; i < variables.size(); i++) {
VariableOrScopeWithAccess vsa = variables.get(i);
VariableOrScope vt = variables.get(i).var;
VariableOrScope vt2 = i + 1 < variables.size() ? variables.get(i + 1).var : null;
if (i == 0
&& scopeStartPos != null
&& caretPosition != null
&& caretPosition >= scopeStartPos
&& vt.getPosition() > caretPosition
&& variableSuggestions.isEmpty()) {
for (Path p : parentVarNameToDefinitionPosition.keySet()) {
if (parentVarNameToDefinitionPosition.get(p) >= 0) {
variableSuggestions.add(p.getFirst().toString());
}
}
for (Path p : privateVarNameToDefinitionPosition.keySet()) {
if (privateVarNameToDefinitionPosition.get(p) >= 0) {
variableSuggestions.add(p.getFirst().toString());
}
}
variableSuggestions.add("--finish--");
}
if (vt instanceof Separator) {
Separator s = (Separator) vt;
searchTrait(s.parentName, s.position, true, separatorPosToType, separatorIsStatic, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference);
@@ -166,6 +223,11 @@ public interface SimpleParser {
if (vt instanceof Variable) {
Variable v = (Variable) vt;
if (v.definition) {
if (vsa.shared) {
parentVarFullNameToDefinitionPosition.put(v.name, v.position);
parentVarNameToDefinitionPosition.put(v.getLastName(), v.position);
}
privateVarFullNameToDefinitionPosition.put(v.name, v.position);
privateVarNameToDefinitionPosition.put(v.getLastName(), v.position);
if (!definitionPosToReferences.containsKey(v.position)) {
@@ -189,8 +251,10 @@ public interface SimpleParser {
} else {
boolean traitFound = searchTrait(v.name, v.position, false, separatorPosToType, separatorIsStatic, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference);
if (!traitFound) {
parentVarFullNameToDefinitionPosition.put(v.name, -v.position - 1);
parentVarNameToDefinitionPosition.put(v.getLastName(), -v.position - 1);
if (vsa.shared) {
parentVarFullNameToDefinitionPosition.put(v.name, -v.position - 1);
parentVarNameToDefinitionPosition.put(v.getLastName(), -v.position - 1);
}
privateVarFullNameToDefinitionPosition.put(v.name, -v.position - 1);
privateVarNameToDefinitionPosition.put(v.getLastName(), -v.position - 1);
definitionPosToReferences.put(-v.position - 1, new ArrayList<>());
@@ -200,103 +264,6 @@ public interface SimpleParser {
}
} else {
if ("this".equals(v.name.toString()) && isStatic) {
errors.add(new SimpleParseException("Cannot use this in static context", -1, v.position));
} else {
int definitionPos;
if (privateVarFullNameToDefinitionPosition.containsKey(v.name)) {
definitionPos = privateVarFullNameToDefinitionPosition.get(v.name);
} else {
definitionPos = privateVarNameToDefinitionPosition.get(v.name);
}
boolean staticDefinition = definitionPos >= 0 ? positionToStatic.get(definitionPos) : true;
if (!(!staticDefinition && isStatic)) {
definitionPosToReferences.get(definitionPos).add(v.position);
referenceToDefinition.put(v.position, definitionPos);
} else {
//errors.add(new SimpleParseException("Cannot reference instance variable from static context", -1, v.position));
}
}
}
}
}
if (vt instanceof Scope) {
Scope vs = (Scope) vt;
boolean subStatic = isStatic;
if (vs instanceof FunctionScope) {
subStatic = ((FunctionScope) vs).isStatic();
}
if (vs instanceof TraitVarConstValueScope) {
subStatic = ((TraitVarConstValueScope) vs).isStatic();
}
//if its inner function (not a method), remove all this variables
Map<Path, Integer> subPrivateVarFullNameToDefinitionPosition = privateVarFullNameToDefinitionPosition;
Map<Path, Integer> subPrivateVarNameToDefinitionPosition = privateVarNameToDefinitionPosition;
if ((vs instanceof FunctionScope) && (!(vs instanceof MethodScope))) {
subPrivateVarFullNameToDefinitionPosition = new LinkedHashMap<>(subPrivateVarFullNameToDefinitionPosition);
subPrivateVarNameToDefinitionPosition = new LinkedHashMap<>(subPrivateVarNameToDefinitionPosition);
Set<Path> keys = new HashSet<>(subPrivateVarFullNameToDefinitionPosition.keySet());
for (Path vName : keys) {
if (vName.toString().equals("this") || vName.getFirst().toString().equals("this")) {
subPrivateVarFullNameToDefinitionPosition.remove(vName);
if (vName.toString().equals("this")) {
subPrivateVarNameToDefinitionPosition.remove(new Path("this"));
}
if (!innerFunctionCanUseTraits) {
subPrivateVarNameToDefinitionPosition.remove(vName.getLast());
}
}
}
}
parseVariablesList(vs.getPrivateItems(), vs.getSharedItems(), definitionPosToReferences, referenceToDefinition, subPrivateVarFullNameToDefinitionPosition, subPrivateVarNameToDefinitionPosition, positionToStatic, subStatic, errors, vs, innerFunctionCanUseTraits, externalSimpleTypes, externalFullTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic);
}
}
for (VariableOrScope vt : sharedVariables) {
if (vt instanceof Separator) {
Separator s = (Separator) vt;
searchTrait(s.parentName, s.position, true, separatorPosToType, separatorIsStatic, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference);
}
if (vt instanceof Variable) {
Variable v = (Variable) vt;
if (v.definition) {
parentVarFullNameToDefinitionPosition.put(v.name, v.position);
parentVarNameToDefinitionPosition.put(v.getLastName(), v.position);
privateVarFullNameToDefinitionPosition.put(v.name, v.position);
privateVarNameToDefinitionPosition.put(v.getLastName(), v.position);
if (!definitionPosToReferences.containsKey(v.position)) {
definitionPosToReferences.put(v.position, new ArrayList<>());
}
positionToStatic.put(v.position, v.isStatic != null ? v.isStatic : isStatic);
if (v.type != null) {
definitionToType.put(v.position, v.type);
}
if (v.subType != null) {
definitionToSubType.put(v.position, v.subType);
}
} else {
if (!privateVarFullNameToDefinitionPosition.containsKey(v.name)
&& !privateVarNameToDefinitionPosition.containsKey(v.name)) {
if (externalFullTypes.contains(v.name)) {
referenceToExternalTypeIndex.put(v.position, externalFullTypes.indexOf(v.name));
} else if (externalSimpleTypes.contains(v.name)) {
referenceToExternalTypeIndex.put(v.position, externalSimpleTypes.indexOf(v.name));
} else {
boolean traitFound = searchTrait(v.name, v.position, false, separatorPosToType, separatorIsStatic, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference);
if (!traitFound) {
parentVarFullNameToDefinitionPosition.put(v.name, -v.position - 1);
parentVarNameToDefinitionPosition.put(v.getFirstName(), -v.position - 1);
privateVarFullNameToDefinitionPosition.put(v.name, -v.position - 1);
privateVarNameToDefinitionPosition.put(v.getFirstName(), -v.position - 1);
definitionPosToReferences.put(-v.position - 1, new ArrayList<>());
definitionPosToReferences.get(-v.position - 1).add(v.position);
referenceToDefinition.put(v.position, -v.position - 1);
}
}
} else {
if ("this".equals(v.name) && isStatic) {
errors.add(new SimpleParseException("Cannot use this in static context", -1, v.position));
} else {
@@ -317,6 +284,7 @@ public interface SimpleParser {
}
}
}
if (vt instanceof Scope) {
Scope vs = (Scope) vt;
boolean subStatic = isStatic;
@@ -347,22 +315,72 @@ public interface SimpleParser {
}
}
parseVariablesList(vs.getPrivateItems(), vs.getSharedItems(), definitionPosToReferences, referenceToDefinition, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, positionToStatic, subStatic, errors, vs, innerFunctionCanUseTraits, externalSimpleTypes, externalFullTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic);
List<VariableOrScopeWithAccess> list = new ArrayList<>();
for (VariableOrScope it : vs.getPrivateItems()) {
list.add(new VariableOrScopeWithAccess(it, false));
}
for (VariableOrScope it : vs.getSharedItems()) {
list.add(new VariableOrScopeWithAccess(it, true));
}
list.sort(new Comparator<VariableOrScopeWithAccess>() {
@Override
public int compare(VariableOrScopeWithAccess o1, VariableOrScopeWithAccess o2) {
return o1.var.getPosition() - o2.var.getPosition();
}
});
parseVariablesList(list, definitionPosToReferences, referenceToDefinition, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, positionToStatic, subStatic, errors, vs, innerFunctionCanUseTraits, externalSimpleTypes, externalFullTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic, caretPosition, variableSuggestions, vs.getPosition(), vs.getEndPosition());
}
if (vt2 != null && caretPosition != null && variableSuggestions.isEmpty()) {
if (vt.getPosition() <= caretPosition && vt2.getPosition() > caretPosition) {
if (vt instanceof Variable) {
for (Path p : parentVarNameToDefinitionPosition.keySet()) {
if (parentVarNameToDefinitionPosition.get(p) >= 0) {
variableSuggestions.add(p.getFirst().toString());
}
}
for (Path p : privateVarNameToDefinitionPosition.keySet()) {
if (privateVarNameToDefinitionPosition.get(p) >= 0) {
variableSuggestions.add(p.getFirst().toString());
}
}
variableSuggestions.add("--finish--");
}
}
}
}
if (caretPosition != null && variableSuggestions.isEmpty() && scopeEndPos != null) {
if (scopeEndPos > caretPosition) {
for (Path p : parentVarNameToDefinitionPosition.keySet()) {
if (parentVarNameToDefinitionPosition.get(p) >= 0) {
variableSuggestions.add(p.getFirst().toString());
}
}
for (Path p : privateVarNameToDefinitionPosition.keySet()) {
if (privateVarNameToDefinitionPosition.get(p) >= 0) {
variableSuggestions.add(p.getFirst().toString());
}
}
variableSuggestions.add("--finish--");
}
}
}
public static void findClassTraits(
List<VariableOrScope> variables,
List<VariableOrScopeWithAccess> variables,
Map<Path, Integer> traitFullNameToDefinition,
Map<Integer, List<Integer>> definitionPosToReferences,
Map<Integer, Boolean> positionToStatic,
Map<Integer, Path> definitionToType,
Map<Integer, Path> definitionToCallType,
Map<Integer, Variable> definitionToSubType,
Map<Integer, Variable> definitionToCallSubType
Map<Integer, Variable> definitionToCallSubType,
Map<Path, Integer> parentVarFullNameToDefinitionPosition,
Map<Path, Integer> parentVarNameToDefinitionPosition
) {
for (VariableOrScope v : variables) {
for (VariableOrScopeWithAccess vsa : variables) {
VariableOrScope v = vsa.var;
if (v instanceof Type) {
Type t = (Type) v;
if (t.definition) {
@@ -386,11 +404,20 @@ public interface SimpleParser {
definitionToCallSubType.put(ct.position, ct.callSubType);
}
traitFullNameToDefinition.put(ct.getFullIdentifier(), ((ClassTrait) v).position);
parentVarFullNameToDefinitionPosition.put(ct.name, ct.position);
parentVarNameToDefinitionPosition.put(ct.getLastName(), ct.position);
}
if (v instanceof Scope) {
Scope s = (Scope) v;
findClassTraits(s.getPrivateItems(), traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType);
findClassTraits(s.getSharedItems(), traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType);
List<VariableOrScopeWithAccess> list = new ArrayList<>();
for (VariableOrScope it : s.getPrivateItems()) {
list.add(new VariableOrScopeWithAccess(it, false));
}
for (VariableOrScope it : s.getSharedItems()) {
list.add(new VariableOrScopeWithAccess(it, true));
}
findClassTraits(list, traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, parentVarFullNameToDefinitionPosition, parentVarNameToDefinitionPosition);
}
}
}

View File

@@ -25,10 +25,15 @@ import java.util.List;
*/
public class TraitVarConstValueScope implements Scope {
private final int position;
private final int endPosition;
private List<VariableOrScope> sharedItems;
private final boolean isStatic;
public TraitVarConstValueScope(List<VariableOrScope> sharedItems, boolean isStatic) {
public TraitVarConstValueScope(int position, int endPosition, List<VariableOrScope> sharedItems, boolean isStatic) {
this.position = position;
this.endPosition = endPosition;
this.sharedItems = sharedItems;
this.isStatic = isStatic;
}
@@ -46,4 +51,16 @@ public class TraitVarConstValueScope implements Scope {
public List<VariableOrScope> getPrivateItems() {
return new ArrayList<>();
}
@Override
public int getPosition() {
return position;
}
@Override
public int getEndPosition() {
return endPosition;
}
}

View File

@@ -16,7 +16,6 @@
*/
package com.jpexs.decompiler.flash.simpleparser;
import java.util.Arrays;
import java.util.List;
/**
@@ -81,4 +80,9 @@ public class Variable implements VariableOrScope {
public boolean hasParent() {
return name.hasParent();
}
@Override
public int getPosition() {
return position;
}
}

View File

@@ -21,5 +21,5 @@ package com.jpexs.decompiler.flash.simpleparser;
* @author JPEXS
*/
public interface VariableOrScope {
public int getPosition();
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2010-2025 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.simpleparser;
/**
*
* @author JPEXS
*/
public class VariableOrScopeWithAccess {
public VariableOrScope var;
public boolean shared;
public VariableOrScopeWithAccess(VariableOrScope var, boolean shared) {
this.var = var;
this.shared = shared;
}
}