Alle TPHS einer Methode und pairs (TPH < SuperTPH) werden gesammelt,
gemeinsamme TPHs werden bestimmt, die Klassenkopf als Type-Variables definiert werden sollen. Erzeugung von Signature angepasst.
This commit is contained in:
parent
66078360da
commit
ff2bca5ce5
@ -17,6 +17,7 @@ import de.dhbwstuttgart.bytecode.descriptor.DescriptorToString;
|
||||
import de.dhbwstuttgart.bytecode.descriptor.TypeToDescriptor;
|
||||
import de.dhbwstuttgart.bytecode.signature.Signature;
|
||||
import de.dhbwstuttgart.bytecode.signature.TypeToString;
|
||||
import de.dhbwstuttgart.bytecode.utilities.MethodAndTPH;
|
||||
import de.dhbwstuttgart.bytecode.utilities.NormalConstructor;
|
||||
import de.dhbwstuttgart.bytecode.utilities.NormalMethod;
|
||||
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
|
||||
@ -28,6 +29,7 @@ import de.dhbwstuttgart.syntaxtree.type.RefType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.syntaxtree.type.SuperWildcardType;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
import de.dhbwstuttgart.typeinference.result.GenericInsertPair;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultPair;
|
||||
import de.dhbwstuttgart.typeinference.result.ResultSet;
|
||||
|
||||
@ -50,6 +52,9 @@ public class BytecodeGen implements ASTVisitor {
|
||||
// stores generics and their bounds of method
|
||||
HashMap<String, String> genericsAndBoundsMethod = new HashMap<>();
|
||||
|
||||
private final ArrayList<GenericInsertPair> commonPairs = new ArrayList<>();
|
||||
private ArrayList<MethodAndTPH> ListOfMethodsAndTph = new ArrayList<>();
|
||||
|
||||
HashMap<String,RefTypeOrTPHOrWildcardOrGeneric> methodParamsAndTypes = new HashMap<>();
|
||||
byte[] bytecode;
|
||||
HashMap<String,byte[]> classFiles;
|
||||
@ -90,6 +95,7 @@ public class BytecodeGen implements ASTVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(ClassOrInterface classOrInterface) {
|
||||
|
||||
className = classOrInterface.getClassName().toString();
|
||||
|
||||
cw.visitSource(className +".jav", null);
|
||||
@ -97,27 +103,41 @@ public class BytecodeGen implements ASTVisitor {
|
||||
isInterface = (classOrInterface.getModifiers()&512)==512;
|
||||
|
||||
int acc = isInterface?classOrInterface.getModifiers()+Opcodes.ACC_ABSTRACT:classOrInterface.getModifiers()+Opcodes.ACC_SUPER;
|
||||
String sig = null;
|
||||
/* if class has generics then creates signature
|
||||
* Signature looks like:
|
||||
* <E:Ljava/...>Superclass
|
||||
*/
|
||||
if(classOrInterface.getGenerics().iterator().hasNext()) {
|
||||
Signature signature = new Signature(classOrInterface, genericsAndBounds);
|
||||
sig = signature.toString();
|
||||
}
|
||||
// needs implemented Interfaces?
|
||||
cw.visit(Opcodes.V1_8, acc, classOrInterface.getClassName().toString()
|
||||
, sig, classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()), null);
|
||||
|
||||
for(Field f : classOrInterface.getFieldDecl()) {
|
||||
f.accept(this);
|
||||
}
|
||||
|
||||
// resultSet = listOfResultSets.get(0);
|
||||
boolean isConsWithNoParamsVisited = false;
|
||||
boolean isVisited = false;
|
||||
for(ResultSet rs : listOfResultSets) {
|
||||
resultSet = rs;
|
||||
|
||||
// Nur einmal ausführen!!
|
||||
if(!isVisited) {
|
||||
TPHExtractor tphExtractor = new TPHExtractor();
|
||||
classOrInterface.accept(tphExtractor);
|
||||
|
||||
getCommonTPHS(tphExtractor);
|
||||
ListOfMethodsAndTph = tphExtractor.ListOfMethodsAndTph;
|
||||
String sig = null;
|
||||
/* if class has generics then creates signature
|
||||
* Signature looks like:
|
||||
* <E:Ljava/...>Superclass
|
||||
*/
|
||||
if(classOrInterface.getGenerics().iterator().hasNext() || !commonPairs.isEmpty()) {
|
||||
Signature signature = new Signature(classOrInterface, genericsAndBounds,commonPairs);
|
||||
sig = signature.toString();
|
||||
System.out.println("Signature: => " + sig);
|
||||
}
|
||||
|
||||
cw.visit(Opcodes.V1_8, acc, classOrInterface.getClassName().toString()
|
||||
, sig, classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()), null);
|
||||
|
||||
isVisited = true;
|
||||
}
|
||||
|
||||
for(Field f : classOrInterface.getFieldDecl()) {
|
||||
f.accept(this);
|
||||
}
|
||||
|
||||
for(Constructor c : classOrInterface.getConstructors()) {
|
||||
if(!isConsWithNoParamsVisited)
|
||||
c.accept(this);
|
||||
@ -133,6 +153,36 @@ public class BytecodeGen implements ASTVisitor {
|
||||
|
||||
}
|
||||
|
||||
private void getCommonTPHS(TPHExtractor tphExtractor) {
|
||||
// Gemeinsame TPHs
|
||||
ArrayList<TypePlaceholder> cTPHs = new ArrayList<>();
|
||||
// Alle TPHs der Felder speichern
|
||||
for(TypePlaceholder tph : tphExtractor.allTPHS.keySet()) {
|
||||
if(!tphExtractor.allTPHS.get(tph))
|
||||
cTPHs.add(tph);
|
||||
}
|
||||
|
||||
ArrayList<MethodAndTPH> tphsMethod = tphExtractor.ListOfMethodsAndTph;
|
||||
// Für jede Methode speichere die gemeinsame TPHs:
|
||||
// -> Für jedes Pair prüfe ob, auf der rechten Seite ein TPH steht, der
|
||||
// in der Liste der TPHs der Methode enthalten ist.
|
||||
// Wenn ja -> gemeinsamer TPH
|
||||
for(MethodAndTPH m:tphsMethod){
|
||||
for(GenericInsertPair p : m.getPairs()){
|
||||
if(!m.getTphs().contains(p.TA2))
|
||||
cTPHs.add(p.TA2);
|
||||
}
|
||||
}
|
||||
|
||||
for(TypePlaceholder tph : cTPHs) {
|
||||
for(GenericInsertPair p : tphExtractor.allPairs) {
|
||||
if(p.contains(tph))
|
||||
commonPairs.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Constructor field) {
|
||||
field.getParameterList().accept(this);
|
||||
@ -186,11 +236,6 @@ public class BytecodeGen implements ASTVisitor {
|
||||
System.out.println("Method: "+method.name +" , paramsType: "+methParamTypes);
|
||||
String methDesc = null;
|
||||
|
||||
TPHEx tphEx = new TPHEx();
|
||||
method.accept(tphEx);
|
||||
System.out.println("TPHs: \n");
|
||||
tphEx.allTPHS.forEach(e->System.out.println(e.getName()));
|
||||
|
||||
// Method getModifiers() ?
|
||||
int acc = isInterface?Opcodes.ACC_ABSTRACT:method.modifier;
|
||||
System.out.println(acc);
|
||||
@ -220,11 +265,18 @@ public class BytecodeGen implements ASTVisitor {
|
||||
/* if method has generics or return type is TPH, create signature */
|
||||
// zwite operand muss weggelassen werden
|
||||
if(hasGen||method.getReturnType().acceptTV(new TypeToString()).equals("TPH")) {
|
||||
// resultset hier zum testen
|
||||
Signature signature = new Signature(method, genericsAndBoundsMethod, methodParamsAndTypes,resultSet, tphEx.allTPHS);
|
||||
ArrayList<GenericInsertPair> pairs = new ArrayList<>();
|
||||
for(MethodAndTPH m : ListOfMethodsAndTph) {
|
||||
if(m.getName().equals(method.name)) {
|
||||
pairs = m.getPairs();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Signature signature = new Signature(method, genericsAndBoundsMethod, genericsAndBounds,methodParamsAndTypes,resultSet, pairs);
|
||||
sig = signature.toString();
|
||||
}
|
||||
System.out.println(sig);
|
||||
System.out.println(method.getName()+" ==> "+sig);
|
||||
NormalMethod meth = new NormalMethod(method,genericsAndBounds,genericsAndBoundsMethod,hasGen);
|
||||
methDesc = meth.accept(new DescriptorToString(resultSet));
|
||||
|
||||
@ -481,12 +533,47 @@ public class BytecodeGen implements ASTVisitor {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private class TPHEx extends AbstractASTWalker{
|
||||
// Liste enthält alle tph der Klasse
|
||||
ArrayList<TypePlaceholder> allTPHS = new ArrayList<>();
|
||||
private class TPHExtractor extends AbstractASTWalker{
|
||||
// Alle TPHs der Felder werden iKopf der Klasse definiert
|
||||
// alle TPHs der Klasse: (TPH, is in Method?)
|
||||
final HashMap<TypePlaceholder,Boolean> allTPHS = new HashMap<>();
|
||||
MethodAndTPH methodAndTph;
|
||||
Boolean inMethod = false;
|
||||
final ArrayList<MethodAndTPH> ListOfMethodsAndTph = new ArrayList<>();
|
||||
final ArrayList<GenericInsertPair> allPairs = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void visit(TypePlaceholder tph) {
|
||||
allTPHS.add(tph);
|
||||
if(resultSet.resolveType(tph).resolvedType instanceof TypePlaceholder) {
|
||||
TypePlaceholder resolvedTPH = (TypePlaceholder) resultSet.resolveType(tph).resolvedType;
|
||||
if(inMethod)
|
||||
methodAndTph.getTphs().add(resolvedTPH);
|
||||
|
||||
allTPHS.put(resolvedTPH,inMethod);
|
||||
resultSet.resolveType(tph).additionalGenerics.forEach(ag ->{
|
||||
if(ag.contains(resolvedTPH)&&ag.TA1.equals(resolvedTPH)&&!contains(allPairs,ag)) {
|
||||
if(inMethod)
|
||||
methodAndTph.getPairs().add(ag);
|
||||
allPairs.add(ag);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
private boolean contains(ArrayList<GenericInsertPair> pairs, GenericInsertPair genPair) {
|
||||
for(int i=0; i<pairs.size();++i) {
|
||||
GenericInsertPair p = pairs.get(i);
|
||||
if(p.TA1.equals(genPair.TA1) && p.TA2.equals(genPair.TA2))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public void visit(Method method) {
|
||||
inMethod = true;
|
||||
methodAndTph = new MethodAndTPH(method.name);
|
||||
super.visit(method);
|
||||
inMethod = false;
|
||||
ListOfMethodsAndTph.add(methodAndTph);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,11 +30,13 @@ public class Signature {
|
||||
private Method method;
|
||||
private HashMap<String,RefTypeOrTPHOrWildcardOrGeneric> methodParamsAndTypes;
|
||||
private ResultSet resultSet;
|
||||
ArrayList<TypePlaceholder> allTPHS;
|
||||
private ArrayList<GenericInsertPair> commonPairs;
|
||||
private ArrayList<GenericInsertPair> methodPairs;
|
||||
|
||||
public Signature(ClassOrInterface classOrInterface, HashMap<String, String> genericsAndBounds) {
|
||||
public Signature(ClassOrInterface classOrInterface, HashMap<String, String> genericsAndBounds,ArrayList<GenericInsertPair> commonPairs) {
|
||||
this.classOrInterface = classOrInterface;
|
||||
this.genericsAndBounds = genericsAndBounds;
|
||||
this.commonPairs = commonPairs;
|
||||
sw = new SignatureWriter();
|
||||
createSignatureForClassOrInterface();
|
||||
}
|
||||
@ -47,13 +49,14 @@ public class Signature {
|
||||
createSignatureForConsOrMethod(this.constructor,true);
|
||||
}
|
||||
|
||||
public Signature(Method method, HashMap<String, String> genericsAndBoundsMethod,
|
||||
HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> methodParamsAndTypes, ResultSet resultSet, ArrayList<TypePlaceholder> allTPHS) {
|
||||
public Signature(Method method, HashMap<String, String> genericsAndBoundsMethod,HashMap<String, String> genericsAndBounds,
|
||||
HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> methodParamsAndTypes, ResultSet resultSet, ArrayList<GenericInsertPair> methodPairs) {
|
||||
this.method = method;
|
||||
this.genericsAndBoundsMethod = genericsAndBoundsMethod;
|
||||
this.genericsAndBounds = genericsAndBounds;
|
||||
this.methodParamsAndTypes = methodParamsAndTypes;
|
||||
this.resultSet = resultSet;
|
||||
this.allTPHS = allTPHS;
|
||||
this.methodPairs = methodPairs;
|
||||
sw = new SignatureWriter();
|
||||
createSignatureForConsOrMethod(this.method,false);
|
||||
}
|
||||
@ -98,75 +101,66 @@ public class Signature {
|
||||
GenericTypeVar g = itr.next();
|
||||
getBoundsOfTypeVar(g,genericsAndBoundsMethod);
|
||||
}
|
||||
// Wenn die RückgabeType eine TPH ist, wird als generic behandelt
|
||||
// z.B: Type = TPH K => wird eine Formal Type Parameter K$ erzeugt und Bound = Object
|
||||
String ret = resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToSignature());
|
||||
if(ret.substring(0,4).equals("TPH ")) {
|
||||
/* (1) Wenn TPH X -> TPH Y, dann ersetze TPH X in allTPHs durch TPH Y,
|
||||
* da X = Y (in RES) ist */
|
||||
if(method.getReturnType() instanceof TypePlaceholder) {
|
||||
TypePlaceholder retTPH = (TypePlaceholder) method.getReturnType();
|
||||
TypePlaceholder resolvedTPH = (TypePlaceholder) resultSet.resolveType(method.getReturnType()).resolvedType;
|
||||
|
||||
allTPHS.remove(retTPH);
|
||||
allTPHS.add(resolvedTPH);
|
||||
}
|
||||
String g = ret.substring(4)+"$";
|
||||
sw.visitFormalTypeParameter(g);
|
||||
sw.visitClassBound().visitClassType(Type.getInternalName(Object.class));
|
||||
genericsAndBoundsMethod.put(g, Type.getInternalName(Object.class));
|
||||
sw.visitClassBound().visitEnd();
|
||||
}
|
||||
|
||||
for(String paramName : methodParamsAndTypes.keySet()) {
|
||||
RefTypeOrTPHOrWildcardOrGeneric t = methodParamsAndTypes.get(paramName);
|
||||
String pT = t.acceptTV(new TypeToSignature());
|
||||
// S.o
|
||||
if(pT.substring(0,4).equals("TPH ") && !genericsAndBoundsMethod.containsKey(pT)) {
|
||||
String gP = pT.substring(4)+"$";
|
||||
sw.visitFormalTypeParameter(gP);
|
||||
|
||||
String resolvedT = resultSet.resolveType(t).resolvedType.acceptTV(new TypeToSignature());
|
||||
String bound;
|
||||
if(resolvedT.subSequence(0, 4).equals("TPH ")) {
|
||||
/* TODO: Prüfe, ob man hier auch (1) braucht*/
|
||||
|
||||
int s = resultSet.resolveType(t).additionalGenerics.size();
|
||||
System.out.println(gP+"AdditionalG: "+s);
|
||||
resultSet.resolveType(t).additionalGenerics.forEach(a->System.out.println(a.TA2.getName()));
|
||||
Iterator<GenericInsertPair> itr2 = resultSet.resolveType(t).additionalGenerics.iterator();
|
||||
//TypePlaceholder temp = null;
|
||||
bound = Type.getInternalName(Object.class);
|
||||
while(itr2.hasNext()) {
|
||||
TypePlaceholder tph = itr2.next().TA2;
|
||||
String tphName = tph.getName()+"$";
|
||||
if(allTPHS.contains(tph) && !tphName.equals(gP)) {
|
||||
bound = tphName;
|
||||
break;
|
||||
if(!methodPairs.isEmpty()) {
|
||||
// Wenn die RückgabeType eine TPH ist, wird als generic behandelt
|
||||
// z.B: Type = TPH K => wird eine Formal Type Parameter K$ erzeugt und Bound = Object
|
||||
String ret = resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToSignature());
|
||||
if(ret.substring(0,4).equals("TPH ")) {
|
||||
String g = ret.substring(4)+"$";
|
||||
if(genericsAndBounds.containsKey(g)) {
|
||||
genericsAndBoundsMethod.put(g, genericsAndBounds.get(g));
|
||||
}else {
|
||||
sw.visitFormalTypeParameter(g);
|
||||
sw.visitClassBound().visitClassType(Type.getInternalName(Object.class));
|
||||
genericsAndBoundsMethod.put(g, Type.getInternalName(Object.class));
|
||||
sw.visitClassBound().visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
// Parameters
|
||||
for(String paramName : methodParamsAndTypes.keySet()) {
|
||||
RefTypeOrTPHOrWildcardOrGeneric t = methodParamsAndTypes.get(paramName);
|
||||
String pT = t.acceptTV(new TypeToSignature());
|
||||
// S.o
|
||||
if(pT.substring(0,4).equals("TPH ")) {
|
||||
String gP = pT.substring(4)+"$";
|
||||
if(!genericsAndBounds.containsKey(gP) && !genericsAndBoundsMethod.containsKey(gP)) {
|
||||
sw.visitFormalTypeParameter(gP);
|
||||
String bound = Type.getInternalName(Object.class);
|
||||
boolean isTypeVar = false;
|
||||
for(GenericInsertPair pair : methodPairs) {
|
||||
if(pT.substring(4).equals(pair.TA1.getName())) {
|
||||
bound = pair.TA2.getName()+"$";
|
||||
isTypeVar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(isTypeVar) {
|
||||
sw.visitClassBound().visitTypeVariable(bound);
|
||||
}else {
|
||||
sw.visitClassBound().visitClassType(bound);
|
||||
sw.visitClassBound().visitEnd();
|
||||
}
|
||||
|
||||
genericsAndBoundsMethod.put(gP, bound);
|
||||
}
|
||||
}
|
||||
sw.visitClassBound().visitTypeVariable(bound);
|
||||
} else {
|
||||
bound = Type.getInternalName(Object.class);
|
||||
sw.visitClassBound().visitClassType(bound);
|
||||
}
|
||||
genericsAndBoundsMethod.put(gP, bound);
|
||||
// sw.visitClassBound().visitEnd();
|
||||
}
|
||||
|
||||
// methodPairs.forEach(p->{
|
||||
// String name = p.TA2.getName() + "$";
|
||||
// if(!genericsAndBoundsMethod.containsKey(name)) {
|
||||
// sw.visitFormalTypeParameter(name);
|
||||
// String bound = Type.getInternalName(Object.class);
|
||||
// sw.visitClassBound().visitClassType(bound);
|
||||
// sw.visitClassBound().visitEnd();
|
||||
// genericsAndBoundsMethod.put(name, bound);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
allTPHS.forEach(tph -> {
|
||||
String tp = tph.getName()+"$";
|
||||
if(!genericsAndBoundsMethod.containsKey(tp)) {
|
||||
sw.visitFormalTypeParameter(tp);
|
||||
String bound = Type.getInternalName(Object.class);
|
||||
sw.visitClassBound().visitClassType(bound);
|
||||
sw.visitClassBound().visitEnd();
|
||||
genericsAndBoundsMethod.put(tp, bound);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// visit each method-parameter to create the signature
|
||||
for(String paramName : methodParamsAndTypes.keySet()) {
|
||||
RefTypeOrTPHOrWildcardOrGeneric t = methodParamsAndTypes.get(paramName);
|
||||
@ -236,7 +230,34 @@ public class Signature {
|
||||
GenericTypeVar g = itr.next();
|
||||
getBoundsOfTypeVar(g,genericsAndBounds);
|
||||
}
|
||||
|
||||
if(!commonPairs.isEmpty()) {
|
||||
ArrayList<TypePlaceholder> types = new ArrayList<>();
|
||||
ArrayList<TypePlaceholder> superTypes = new ArrayList<>();
|
||||
|
||||
for(GenericInsertPair p : commonPairs) {
|
||||
types.add(p.TA1);
|
||||
superTypes.add(p.TA2);
|
||||
}
|
||||
|
||||
for(GenericInsertPair p : commonPairs) {
|
||||
String t = p.TA1.getName()+"$";
|
||||
String bound = p.TA2.getName()+"$";
|
||||
sw.visitFormalTypeParameter(t);
|
||||
sw.visitClassBound().visitTypeVariable(bound);
|
||||
genericsAndBounds.put(t, bound);
|
||||
}
|
||||
|
||||
for(GenericInsertPair p : commonPairs) {
|
||||
if(!types.contains(p.TA2)) {
|
||||
String t = p.TA2.getName()+"$";
|
||||
String bound = Type.getInternalName(Object.class);
|
||||
sw.visitFormalTypeParameter(t);
|
||||
sw.visitClassBound().visitClassType(bound);
|
||||
genericsAndBounds.put(t, bound);
|
||||
sw.visitClassBound().visitEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
sw.visitSuperclass().visitClassType(classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()));;
|
||||
sw.visitEnd();
|
||||
}
|
||||
|
29
src/de/dhbwstuttgart/bytecode/utilities/MethodAndTPH.java
Normal file
29
src/de/dhbwstuttgart/bytecode/utilities/MethodAndTPH.java
Normal file
@ -0,0 +1,29 @@
|
||||
package de.dhbwstuttgart.bytecode.utilities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
import de.dhbwstuttgart.typeinference.result.GenericInsertPair;
|
||||
|
||||
public class MethodAndTPH {
|
||||
|
||||
private String name;
|
||||
private final ArrayList<TypePlaceholder> tphs = new ArrayList<>();
|
||||
private final ArrayList<GenericInsertPair> pairs = new ArrayList<>();
|
||||
|
||||
public MethodAndTPH(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public ArrayList<TypePlaceholder> getTphs() {
|
||||
return tphs;
|
||||
}
|
||||
|
||||
public ArrayList<GenericInsertPair> getPairs(){
|
||||
return pairs;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
import java.lang.Integer;
|
||||
import java.lang.Boolean;
|
||||
|
||||
public class IfTest{
|
||||
Integer m1(Boolean b) {
|
||||
Integer i;
|
||||
|
10
test/bytecode/javFiles/Tph2.jav
Normal file
10
test/bytecode/javFiles/Tph2.jav
Normal file
@ -0,0 +1,10 @@
|
||||
public class Tph2 {
|
||||
m(a,b){
|
||||
var c = m2(a,b);
|
||||
return a;
|
||||
}
|
||||
|
||||
m2(a,b){
|
||||
return b;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user