Browse Source

More work on functions, only commited to merge Stans latest changes

kindlich 6 years ago
parent
commit
89c4221b53
No known key found for this signature in database

+ 4
- 1
CodeFormatter/src/main/java/org/openzen/zenscript/formatter/ExpressionFormatter.java View File

76
 import org.openzen.zenscript.codemodel.expression.TryRethrowAsResultExpression;
76
 import org.openzen.zenscript.codemodel.expression.TryRethrowAsResultExpression;
77
 import org.openzen.zenscript.codemodel.expression.VariantValueExpression;
77
 import org.openzen.zenscript.codemodel.expression.VariantValueExpression;
78
 import org.openzen.zenscript.codemodel.expression.WrapOptionalExpression;
78
 import org.openzen.zenscript.codemodel.expression.WrapOptionalExpression;
79
+import org.openzen.zenscript.formattershared.FormattableOperator;
79
 
80
 
80
 /**
81
 /**
81
  *
82
  *
428
 
429
 
429
 	@Override
430
 	@Override
430
 	public ExpressionString visitFunction(FunctionExpression expression) {
431
 	public ExpressionString visitFunction(FunctionExpression expression) {
431
-		throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
432
+		//FIXME
433
+		return new ExpressionString("asdfghj", ZenScriptOperator.PRIMARY);
434
+		//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
432
 	}
435
 	}
433
 
436
 
434
 	@Override
437
 	@Override

+ 2
- 1
CodeModel/src/main/java/org/openzen/zenscript/codemodel/member/ref/FunctionalMemberRef.java View File

79
 	}
79
 	}
80
 	
80
 	
81
 	public String getMethodName() {
81
 	public String getMethodName() {
82
-		return ((MethodMember) target).name;
82
+		//FIXME
83
+		return (target).name;
83
 	}
84
 	}
84
 	
85
 	
85
 	public Expression call(CodePosition position, Expression target, FunctionHeader instancedHeader, CallArguments arguments, TypeScope scope) {
86
 	public Expression call(CodePosition position, Expression target, FunctionHeader instancedHeader, CallArguments arguments, TypeScope scope) {

+ 5
- 5
JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/implementations/IntRange.java View File

1
 package org.openzen.zenscript.implementations;
1
 package org.openzen.zenscript.implementations;
2
 
2
 
3
 public class IntRange {
3
 public class IntRange {
4
-    public final int min;
5
-    public final int max;
4
+    public final int from;
5
+    public final int to;
6
 
6
 
7
 
7
 
8
-    public IntRange(int min, int max) {
9
-        this.min = min;
10
-        this.max = max;
8
+    public IntRange(int from, int to) {
9
+        this.from = from;
10
+        this.to = to;
11
     }
11
     }
12
 }
12
 }

+ 1
- 1
JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/JavaModule.java View File

43
 		}
43
 		}
44
 	}
44
 	}
45
 	
45
 	
46
-	private class ScriptClassLoader extends ClassLoader {
46
+	public class ScriptClassLoader extends ClassLoader {
47
 		private final Map<String, Class> customClasses = new HashMap<>();
47
 		private final Map<String, Class> customClasses = new HashMap<>();
48
 
48
 
49
 		@Override
49
 		@Override

+ 53
- 2
JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/CompilerUtils.java View File

1
 package org.openzen.zenscript.javabytecode.compiler;
1
 package org.openzen.zenscript.javabytecode.compiler;
2
 
2
 
3
+import org.objectweb.asm.ClassWriter;
3
 import org.objectweb.asm.Opcodes;
4
 import org.objectweb.asm.Opcodes;
4
 import org.objectweb.asm.Type;
5
 import org.objectweb.asm.Type;
5
 import org.openzen.zencode.shared.CodePosition;
6
 import org.openzen.zencode.shared.CodePosition;
18
 import org.openzen.zenscript.codemodel.member.IDefinitionMember;
19
 import org.openzen.zenscript.codemodel.member.IDefinitionMember;
19
 import org.openzen.zenscript.codemodel.type.BasicTypeID;
20
 import org.openzen.zenscript.codemodel.type.BasicTypeID;
20
 import org.openzen.zenscript.codemodel.type.ITypeID;
21
 import org.openzen.zenscript.codemodel.type.ITypeID;
22
+import org.openzen.zenscript.javabytecode.JavaModule;
21
 import org.openzen.zenscript.javabytecode.JavaParameterInfo;
23
 import org.openzen.zenscript.javabytecode.JavaParameterInfo;
22
 
24
 
25
+import java.io.FileNotFoundException;
26
+import java.io.FileOutputStream;
27
+import java.io.IOException;
28
+import java.util.HashMap;
29
+import java.util.Map;
30
+
23
 public class CompilerUtils {
31
 public class CompilerUtils {
24
     public static String calcDesc(FunctionHeader header, boolean isEnum) {
32
     public static String calcDesc(FunctionHeader header, boolean isEnum) {
25
         StringBuilder descBuilder = new StringBuilder("(");
33
         StringBuilder descBuilder = new StringBuilder("(");
26
         if (isEnum)
34
         if (isEnum)
27
             descBuilder.append("Ljava/lang/String;I");
35
             descBuilder.append("Ljava/lang/String;I");
28
         for (FunctionParameter parameter : header.parameters) {
36
         for (FunctionParameter parameter : header.parameters) {
29
-            descBuilder.append(Type.getDescriptor(parameter.type.accept(JavaTypeClassVisitor.INSTANCE)));
37
+            //descBuilder.append(Type.getDescriptor(parameter.type.accept(JavaTypeClassVisitor.INSTANCE)));
38
+            descBuilder.append(parameter.type.accept(JavaTypeVisitor.INSTANCE).getDescriptor());
30
         }
39
         }
31
         descBuilder.append(")");
40
         descBuilder.append(")");
32
-        descBuilder.append(Type.getDescriptor(header.returnType.accept(JavaTypeClassVisitor.INSTANCE)));
41
+        descBuilder.append(header.returnType.accept(JavaTypeVisitor.INSTANCE).getDescriptor());
33
         return descBuilder.toString();
42
         return descBuilder.toString();
34
     }
43
     }
35
 
44
 
121
         }
130
         }
122
     }
131
     }
123
 
132
 
133
+    private static final Map<String, String> lambdas = new HashMap<>();
134
+    private static int lambdaCounter = 0;
135
+    private static int lambdaICounter = 0;
136
+    public static String getLambdaInterface(final FunctionHeader header) {
137
+        StringBuilder builder = new StringBuilder("(");
138
+        for (FunctionParameter parameter : header.parameters) {
139
+            builder.append(parameter.type.accept(JavaTypeVisitor.INSTANCE).getDescriptor());
140
+        }
141
+
142
+        //final String identifier = header.toString();
143
+        final String identifier = builder.append(")").append(header.returnType.accept(JavaTypeVisitor.INSTANCE).getDescriptor()).toString();
144
+        if(!lambdas.containsKey(identifier)) {
145
+            final String name = "lambdaInterface" + ++lambdaICounter;
146
+            lambdas.put(identifier, name);
147
+            createLambdaInterface(header, name);
148
+        }
149
+        return lambdas.get(identifier);
150
+    }
151
+
152
+    private static void createLambdaInterface(FunctionHeader header, String name) {
153
+        ClassWriter ifaceWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
154
+        ifaceWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT, name, null, "java/lang/Object", null);
155
+
156
+        ifaceWriter.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT, "accept", calcDesc(header, false), calcSign(header, false), null).visitEnd();
157
+
158
+        ifaceWriter.visitEnd();
159
+
160
+        JavaModule.classes.putIfAbsent(name, ifaceWriter.toByteArray());
161
+
162
+        try (FileOutputStream out = new FileOutputStream(name + ".class")){
163
+            out.write(ifaceWriter.toByteArray());
164
+        } catch (IOException e) {
165
+            e.printStackTrace();
166
+        }
167
+    }
168
+
169
+
170
+    public static String getLambdaCounter() {
171
+        return "lambda" + ++lambdaCounter;
172
+    }
173
+
174
+
124
 
175
 
125
     public static int getKeyForSwitch(SwitchValue expression) {
176
     public static int getKeyForSwitch(SwitchValue expression) {
126
 		return expression.accept(new SwitchKeyVisitor());
177
 		return expression.accept(new SwitchKeyVisitor());

+ 1
- 2
JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaCapturedExpressionVisitor.java View File

22
 
22
 
23
     @Override
23
     @Override
24
     public Void visitCapturedLocal(CapturedLocalVariableExpression expression) {
24
     public Void visitCapturedLocal(CapturedLocalVariableExpression expression) {
25
-        new GetLocalVariableExpression(expression.position, expression.variable)
25
+        return new GetLocalVariableExpression(expression.position, expression.variable)
26
                 .accept(expressionVisitor);
26
                 .accept(expressionVisitor);
27
-        return null;
28
     }
27
     }
29
 
28
 
30
     @Override
29
     @Override

+ 140
- 79
JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaExpressionVisitor.java View File

1
 package org.openzen.zenscript.javabytecode.compiler;
1
 package org.openzen.zenscript.javabytecode.compiler;
2
 
2
 
3
+import org.objectweb.asm.ClassWriter;
3
 import org.objectweb.asm.Label;
4
 import org.objectweb.asm.Label;
4
 import org.objectweb.asm.Opcodes;
5
 import org.objectweb.asm.Opcodes;
5
 import org.objectweb.asm.Type;
6
 import org.objectweb.asm.Type;
7
+import org.openzen.zencode.shared.CompileException;
8
+import org.openzen.zencode.shared.CompileExceptionCode;
6
 import org.openzen.zenscript.codemodel.CompareType;
9
 import org.openzen.zenscript.codemodel.CompareType;
10
+import org.openzen.zenscript.codemodel.FunctionHeader;
11
+import org.openzen.zenscript.codemodel.FunctionParameter;
7
 import org.openzen.zenscript.codemodel.expression.*;
12
 import org.openzen.zenscript.codemodel.expression.*;
8
 import org.openzen.zenscript.codemodel.member.ref.ConstMemberRef;
13
 import org.openzen.zenscript.codemodel.member.ref.ConstMemberRef;
9
 import org.openzen.zenscript.codemodel.member.ref.DefinitionMemberRef;
14
 import org.openzen.zenscript.codemodel.member.ref.DefinitionMemberRef;
14
 import org.openzen.zenscript.implementations.IntRange;
19
 import org.openzen.zenscript.implementations.IntRange;
15
 import org.openzen.zenscript.javabytecode.*;
20
 import org.openzen.zenscript.javabytecode.*;
16
 
21
 
22
+import java.io.FileOutputStream;
23
+import java.io.IOException;
17
 import java.util.*;
24
 import java.util.*;
18
-import java.util.Map;
19
-import org.objectweb.asm.Opcodes;
20
-import org.openzen.zencode.shared.CompileException;
21
-import org.openzen.zencode.shared.CompileExceptionCode;
22
-import org.openzen.zenscript.codemodel.member.ref.ConstMemberRef;
23
-import org.openzen.zenscript.codemodel.member.ref.DefinitionMemberRef;
24
-import org.openzen.zenscript.codemodel.member.ref.FieldMemberRef;
25
-import org.openzen.zenscript.codemodel.type.ArrayTypeID;
26
-import org.openzen.zenscript.codemodel.type.AssocTypeID;
27
-import org.openzen.zenscript.codemodel.type.BasicTypeID;
28
-import org.openzen.zenscript.codemodel.type.member.BuiltinID;
29
 
25
 
30
 public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
26
 public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
31
 	private static final int PUBLIC = Opcodes.ACC_PUBLIC;
27
 	private static final int PUBLIC = Opcodes.ACC_PUBLIC;
32
 	private static final int STATIC = Opcodes.ACC_STATIC;
28
 	private static final int STATIC = Opcodes.ACC_STATIC;
33
 	private static final int PUBLIC_STATIC = PUBLIC | STATIC;
29
 	private static final int PUBLIC_STATIC = PUBLIC | STATIC;
34
-	
30
+
35
 	private static final JavaClassInfo BOOLEAN = JavaClassInfo.get(Boolean.class);
31
 	private static final JavaClassInfo BOOLEAN = JavaClassInfo.get(Boolean.class);
36
 	private static final JavaMethodInfo BOOLEAN_PARSE = new JavaMethodInfo(BOOLEAN, "parseBoolean", "(Ljava/lang/String;)Z", PUBLIC_STATIC);
32
 	private static final JavaMethodInfo BOOLEAN_PARSE = new JavaMethodInfo(BOOLEAN, "parseBoolean", "(Ljava/lang/String;)Z", PUBLIC_STATIC);
37
 	private static final JavaMethodInfo BOOLEAN_TO_STRING = new JavaMethodInfo(BOOLEAN, "toString", "(Z)Ljava/lang/String;", PUBLIC_STATIC);
33
 	private static final JavaMethodInfo BOOLEAN_TO_STRING = new JavaMethodInfo(BOOLEAN, "toString", "(Z)Ljava/lang/String;", PUBLIC_STATIC);
291
 		} else {
287
 		} else {
292
 			if (!checkAndExecuteMethodInfo(expression.operator))
288
 			if (!checkAndExecuteMethodInfo(expression.operator))
293
 				throw new IllegalStateException("Call target has no method info!");
289
 				throw new IllegalStateException("Call target has no method info!");
294
-			
290
+
295
 			expression.left.accept(this);
291
 			expression.left.accept(this);
296
 			expression.right.accept(this);
292
 			expression.right.accept(this);
297
 			compareGeneric(expression.comparison);
293
 			compareGeneric(expression.comparison);
299
 
295
 
300
         return null;
296
         return null;
301
     }
297
     }
302
-	
298
+
303
 	private void compareInt(CompareType comparator) {
299
 	private void compareInt(CompareType comparator) {
304
 		Label exit = new Label();
300
 		Label exit = new Label();
305
 		Label isTrue = new Label();
301
 		Label isTrue = new Label();
318
 		javaWriter.iConst1();
314
 		javaWriter.iConst1();
319
 		javaWriter.label(exit);
315
 		javaWriter.label(exit);
320
 	}
316
 	}
321
-	
317
+
322
 	private void compareGeneric(CompareType comparator) {
318
 	private void compareGeneric(CompareType comparator) {
323
 		Label exit = new Label();
319
 		Label exit = new Label();
324
 		Label isTrue = new Label();
320
 		Label isTrue = new Label();
349
 
345
 
350
 			if (!checkAndExecuteMethodInfo(expression.member))
346
 			if (!checkAndExecuteMethodInfo(expression.member))
351
 	            throw new IllegalStateException("Call target has no method info!");
347
 	            throw new IllegalStateException("Call target has no method info!");
352
-			
348
+
353
 			return null;
349
 			return null;
354
 		}
350
 		}
355
-		
351
+
356
 		switch (builtin) {
352
 		switch (builtin) {
357
 			case STRING_RANGEGET:
353
 			case STRING_RANGEGET:
358
 			case ARRAY_INDEXGETRANGE:
354
 			case ARRAY_INDEXGETRANGE:
363
 					argument.accept(this);
359
 					argument.accept(this);
364
 				}
360
 				}
365
 		}
361
 		}
366
-		
362
+
367
 		switch (builtin) {
363
 		switch (builtin) {
368
 			case BOOL_NOT:
364
 			case BOOL_NOT:
369
 				javaWriter.iConst1();
365
 				javaWriter.iConst1();
658
 			case ASSOC_INDEXGET:
654
 			case ASSOC_INDEXGET:
659
 			case ASSOC_GETORDEFAULT: {
655
 			case ASSOC_GETORDEFAULT: {
660
 				javaWriter.invokeVirtual(MAP_GET);
656
 				javaWriter.invokeVirtual(MAP_GET);
661
-				
657
+
662
 				AssocTypeID type = (AssocTypeID) expression.target.type;
658
 				AssocTypeID type = (AssocTypeID) expression.target.type;
663
 				Type cls = type.valueType.accept(JavaTypeVisitor.INSTANCE);
659
 				Type cls = type.valueType.accept(JavaTypeVisitor.INSTANCE);
664
 				javaWriter.checkCast(cls.getInternalName());
660
 				javaWriter.checkCast(cls.getInternalName());
727
 			}
723
 			}
728
 			case ARRAY_INDEXGETRANGE: {
724
 			case ARRAY_INDEXGETRANGE: {
729
 				ArrayTypeID type = (ArrayTypeID) expression.target.type;
725
 				ArrayTypeID type = (ArrayTypeID) expression.target.type;
730
-				
726
+
731
 				expression.target.accept(this);
727
 				expression.target.accept(this);
732
 				Expression argument = expression.arguments.arguments[0];
728
 				Expression argument = expression.arguments.arguments[0];
733
 				if (argument instanceof RangeExpression) {
729
 				if (argument instanceof RangeExpression) {
743
 					javaWriter.loadInt(tmp);
739
 					javaWriter.loadInt(tmp);
744
 					javaWriter.getField("zsynthetic/IntRange", "to", "I");
740
 					javaWriter.getField("zsynthetic/IntRange", "to", "I");
745
 				}
741
 				}
746
-				
742
+
747
 				if (type.elementType instanceof BasicTypeID) {
743
 				if (type.elementType instanceof BasicTypeID) {
748
 					switch ((BasicTypeID) type.elementType) {
744
 					switch ((BasicTypeID) type.elementType) {
749
 						case BOOL:
745
 						case BOOL:
836
 				} else {
832
 				} else {
837
 					javaWriter.invokeStatic(ARRAYS_EQUALS_OBJECTS);
833
 					javaWriter.invokeStatic(ARRAYS_EQUALS_OBJECTS);
838
 				}
834
 				}
839
-				
835
+
840
 				if (builtin == BuiltinID.ARRAY_NOTEQUALS) {
836
 				if (builtin == BuiltinID.ARRAY_NOTEQUALS) {
841
 					javaWriter.iConst1();
837
 					javaWriter.iConst1();
842
 					javaWriter.iXor();
838
 					javaWriter.iXor();
844
 				break;
840
 				break;
845
 			}
841
 			}
846
 			case FUNCTION_CALL:
842
 			case FUNCTION_CALL:
847
-				throw new UnsupportedOperationException("Not yet supported!");
843
+				//expression.target.accept(this);
844
+				//for (Expression argument : expression.arguments.arguments) {
845
+				//	argument.accept(this);
846
+				//}
847
+				javaWriter.invokeInterface(new JavaMethodInfo(new JavaClassInfo(expression.target.type.accept(JavaTypeVisitor.INSTANCE).getInternalName()), "accept", CompilerUtils.calcSign(expression.instancedHeader, false), Opcodes.ACC_PUBLIC));
848
+				break;
849
+				//throw new UnsupportedOperationException("Not yet supported!");
848
 			case AUTOOP_NOTEQUALS:
850
 			case AUTOOP_NOTEQUALS:
849
 				throw new UnsupportedOperationException("Not yet supported!");
851
 				throw new UnsupportedOperationException("Not yet supported!");
850
 			default:
852
 			default:
854
         return null;
856
         return null;
855
     }
857
     }
856
 
858
 
857
-    @Override
859
+	@Override
858
     public Void visitCallStatic(CallStaticExpression expression) {
860
     public Void visitCallStatic(CallStaticExpression expression) {
859
 		for (Expression argument : expression.arguments.arguments)
861
 		for (Expression argument : expression.arguments.arguments)
860
 			argument.accept(this);
862
 			argument.accept(this);
861
-		
863
+
862
 		BuiltinID builtin = expression.member.getBuiltin();
864
 		BuiltinID builtin = expression.member.getBuiltin();
863
 		if (builtin == null) {
865
 		if (builtin == null) {
864
 			if (!checkAndExecuteMethodInfo(expression.member))
866
 			if (!checkAndExecuteMethodInfo(expression.member))
865
 	            throw new IllegalStateException("Call target has no method info!");
867
 	            throw new IllegalStateException("Call target has no method info!");
866
-			
868
+
867
 			return null;
869
 			return null;
868
 		}
870
 		}
869
-		
871
+
870
 		switch (builtin) {
872
 		switch (builtin) {
871
 			case BOOL_PARSE:
873
 			case BOOL_PARSE:
872
 				javaWriter.invokeStatic(BOOLEAN_PARSE);
874
 				javaWriter.invokeStatic(BOOLEAN_PARSE);
965
     @Override
967
     @Override
966
     public Void visitCast(CastExpression expression) {
968
     public Void visitCast(CastExpression expression) {
967
         expression.target.accept(this);
969
         expression.target.accept(this);
968
-		
970
+
969
 		BuiltinID builtin = expression.member.member.builtin;
971
 		BuiltinID builtin = expression.member.member.builtin;
970
 		if (builtin == null) {
972
 		if (builtin == null) {
971
 			if (!checkAndExecuteByteCodeImplementation(expression.member) && !checkAndExecuteMethodInfo(expression.member))
973
 			if (!checkAndExecuteByteCodeImplementation(expression.member) && !checkAndExecuteMethodInfo(expression.member))
972
 				throw new IllegalStateException("Call target has no method info!");
974
 				throw new IllegalStateException("Call target has no method info!");
973
-			
975
+
974
 			return null;
976
 			return null;
975
 		}
977
 		}
976
-		
978
+
977
 		switch (builtin) {
979
 		switch (builtin) {
978
 			case BOOL_TO_STRING:
980
 			case BOOL_TO_STRING:
979
 				javaWriter.invokeStatic(BOOLEAN_TO_STRING);
981
 				javaWriter.invokeStatic(BOOLEAN_TO_STRING);
1300
 			default:
1302
 			default:
1301
 				throw new UnsupportedOperationException("Unknown builtin cast: " + builtin);
1303
 				throw new UnsupportedOperationException("Unknown builtin cast: " + builtin);
1302
 		}
1304
 		}
1303
-		
1305
+
1304
 		return null;
1306
 		return null;
1305
     }
1307
     }
1306
 
1308
 
1346
         javaWriter.label(end);
1348
         javaWriter.label(end);
1347
         return null;
1349
         return null;
1348
     }
1350
     }
1349
-	
1351
+
1350
 	@Override
1352
 	@Override
1351
 	public Void visitConst(ConstExpression expression) {
1353
 	public Void visitConst(ConstExpression expression) {
1352
 		BuiltinID builtin = expression.constant.member.builtin;
1354
 		BuiltinID builtin = expression.constant.member.builtin;
1353
 		if (builtin == null) {
1355
 		if (builtin == null) {
1354
 			if (!checkAndGetFieldInfo(expression.constant, true))
1356
 			if (!checkAndGetFieldInfo(expression.constant, true))
1355
 	            throw new IllegalStateException("Call target has no field info!");
1357
 	            throw new IllegalStateException("Call target has no field info!");
1356
-			
1358
+
1357
 			return null;
1359
 			return null;
1358
 		}
1360
 		}
1359
-		
1361
+
1360
 		switch (builtin) {
1362
 		switch (builtin) {
1361
 			case BYTE_GET_MIN_VALUE:
1363
 			case BYTE_GET_MIN_VALUE:
1362
 				javaWriter.iConst0();
1364
 				javaWriter.iConst0();
1433
 			default:
1435
 			default:
1434
 				throw new UnsupportedOperationException("Unknown builtin: " + builtin);
1436
 				throw new UnsupportedOperationException("Unknown builtin: " + builtin);
1435
 		}
1437
 		}
1436
-		
1438
+
1437
 		return null;
1439
 		return null;
1438
 	}
1440
 	}
1439
 
1441
 
1557
 
1559
 
1558
     @Override
1560
     @Override
1559
     public Void visitFunction(FunctionExpression expression) {
1561
     public Void visitFunction(FunctionExpression expression) {
1562
+		CompilerUtils.tagMethodParameters(expression.header, false);
1563
+
1560
         if (expression.header.parameters.length == 0 && expression.body instanceof ReturnStatement && expression.body.hasTag(MatchExpression.class) && expression.closure.captures.isEmpty()) {
1564
         if (expression.header.parameters.length == 0 && expression.body instanceof ReturnStatement && expression.body.hasTag(MatchExpression.class) && expression.closure.captures.isEmpty()) {
1561
             ((ReturnStatement) expression.body).value.accept(this);
1565
             ((ReturnStatement) expression.body).value.accept(this);
1562
             return null;
1566
             return null;
1563
         }
1567
         }
1564
-        final String signature = calcFunctionSignature(expression.closure, expression.header.returnType);
1565
-        final String name = "lambda" + expression.hashCode();
1568
+        final String signature = CompilerUtils.calcSign(expression.header, false);
1569
+        //final String name = CompilerUtils.getLambdaInterface(expression.header);
1570
+		final String name = CompilerUtils.getLambdaCounter();
1566
 
1571
 
1567
-        final JavaMethodInfo methodInfo = new JavaMethodInfo(javaWriter.method.javaClass, name, signature, Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE);
1568
-        JavaWriter functionWriter = new JavaWriter(javaWriter.clazzVisitor, methodInfo, null, signature, null);
1572
+        final JavaMethodInfo methodInfo = new JavaMethodInfo(javaWriter.method.javaClass, "accept", signature, Opcodes.ACC_PUBLIC);
1573
+		final ClassWriter lambdaCW = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
1574
+		lambdaCW.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name, null, "java/lang/Object", new String[]{CompilerUtils.getLambdaInterface(expression.header)});
1575
+		final JavaWriter functionWriter = new JavaWriter(lambdaCW, methodInfo, null, signature, null, "java/lang/Override");
1576
+
1577
+
1578
+
1579
+		javaWriter.newObject(name);
1580
+		javaWriter.dup();
1581
+
1582
+		final String constructorDesc = calcFunctionSignature(expression.closure);
1583
+
1584
+
1585
+		final JavaWriter constructorWriter = new JavaWriter(lambdaCW, new JavaMethodInfo(javaWriter.method.javaClass, "<init>", constructorDesc, Opcodes.ACC_PUBLIC), null, null, null);
1586
+		constructorWriter.start();
1587
+		constructorWriter.loadObject(0);
1588
+		constructorWriter.dup();
1589
+		constructorWriter.invokeSpecial(Object.class, "<init>", "()V");
1590
+
1591
+		int i = 0;
1592
+		for (CapturedExpression capture : expression.closure.captures) {
1593
+			constructorWriter.dup();
1594
+			final Type type = capture.type.accept(JavaTypeVisitor.INSTANCE);
1595
+			lambdaCW.visitField(Opcodes.ACC_FINAL | Opcodes.ACC_PRIVATE, "captured" + ++i, type.getDescriptor(), null, null).visitEnd();
1596
+
1597
+			capture.accept(this);
1598
+
1599
+			constructorWriter.load(type, i);
1600
+			constructorWriter.putField(name, "captured" + i, type.getDescriptor());
1601
+		}
1602
+
1603
+		constructorWriter.pop();
1604
+
1605
+		javaWriter.invokeSpecial(name, "<init>", constructorDesc);
1606
+
1607
+		constructorWriter.ret();
1608
+		constructorWriter.end();
1569
 
1609
 
1570
-        for (CapturedExpression capture : expression.closure.captures) {
1571
-            capture.accept(new JavaCapturedExpressionVisitor(this));
1572
-        }
1573
 
1610
 
1574
-        javaWriter.invokeStatic(methodInfo);
1575
 
1611
 
1576
         functionWriter.start();
1612
         functionWriter.start();
1577
-        expression.body.accept(new JavaStatementVisitor(new JavaExpressionVisitor(functionWriter) {
1578
-            @Override
1579
-            public Void visitGetLocalVariable(GetLocalVariableExpression varExpression) {
1580
-                final int position = calculateMemberPosition(varExpression, expression);
1581
-                if (position < 0)
1582
-                    throw new CompileException(varExpression.position, CompileExceptionCode.INTERNAL_ERROR, "Captured Statement error");
1583
-                functionWriter.load(varExpression.variable.type.accept(JavaTypeVisitor.INSTANCE), position);
1584
-                return null;
1585
-            }
1586
-        }));
1613
+
1614
+
1615
+		final JavaStatementVisitor CSV = new JavaStatementVisitor(new JavaExpressionVisitor(functionWriter) {
1616
+			//@Override
1617
+			public Void visitGetLocalVariable(GetLocalVariableExpression varExpression) {
1618
+				final int position = calculateMemberPosition(varExpression, expression) ;
1619
+				if (position < 0)
1620
+					throw new CompileException(varExpression.position, CompileExceptionCode.INTERNAL_ERROR, "Captured Statement error");
1621
+				functionWriter.loadObject(0);
1622
+				functionWriter.getField(name, "captured" + position, varExpression.variable.type.accept(JavaTypeVisitor.INSTANCE).getDescriptor());
1623
+				return null;
1624
+			}
1625
+		});
1626
+
1627
+
1628
+		expression.body.accept(CSV);
1587
 
1629
 
1588
 
1630
 
1589
         functionWriter.ret();
1631
         functionWriter.ret();
1590
-        functionWriter.end();
1591
 
1632
 
1592
-        return null;
1633
+
1634
+
1635
+		functionWriter.end();
1636
+        lambdaCW.visitEnd();
1637
+
1638
+        JavaModule.classes.putIfAbsent(name, lambdaCW.toByteArray());
1639
+
1640
+        try (FileOutputStream out = new FileOutputStream(name + ".class")){
1641
+        	out.write(lambdaCW.toByteArray());
1642
+		} catch (IOException e) {
1643
+			e.printStackTrace();
1644
+		}
1645
+
1646
+		return null;
1593
     }
1647
     }
1594
 
1648
 
1595
     //TODO replace with visitor?
1649
     //TODO replace with visitor?
1596
     private static int calculateMemberPosition(GetLocalVariableExpression localVariableExpression, FunctionExpression expression) {
1650
     private static int calculateMemberPosition(GetLocalVariableExpression localVariableExpression, FunctionExpression expression) {
1597
-        int h = expression.header.parameters.length;
1651
+        int h = 1;//expression.header.parameters.length;
1598
         for (CapturedExpression capture : expression.closure.captures) {
1652
         for (CapturedExpression capture : expression.closure.captures) {
1599
             if (capture instanceof CapturedLocalVariableExpression && ((CapturedLocalVariableExpression) capture).variable == localVariableExpression.variable)
1653
             if (capture instanceof CapturedLocalVariableExpression && ((CapturedLocalVariableExpression) capture).variable == localVariableExpression.variable)
1600
                 return h;
1654
                 return h;
1605
         return -1;
1659
         return -1;
1606
     }
1660
     }
1607
 
1661
 
1608
-    private String calcFunctionSignature(LambdaClosure closure, ITypeID type) {
1609
-        StringJoiner joiner = new StringJoiner("", "(", ")");
1662
+    private String calcFunctionSignature(LambdaClosure closure) {
1663
+        StringJoiner joiner = new StringJoiner("", "(", ")V");
1610
 
1664
 
1611
         for (CapturedExpression capture : closure.captures) {
1665
         for (CapturedExpression capture : closure.captures) {
1612
             String descriptor = capture.type.accept(JavaTypeVisitor.INSTANCE).getDescriptor();
1666
             String descriptor = capture.type.accept(JavaTypeVisitor.INSTANCE).getDescriptor();
1613
             joiner.add(descriptor);
1667
             joiner.add(descriptor);
1614
         }
1668
         }
1615
-        return joiner.toString() + type.accept(JavaTypeVisitor.INSTANCE).getDescriptor();
1669
+        return joiner.toString();
1616
     }
1670
     }
1617
 
1671
 
1618
     @Override
1672
     @Override
1626
     @Override
1680
     @Override
1627
     public Void visitGetFunctionParameter(GetFunctionParameterExpression expression) {
1681
     public Void visitGetFunctionParameter(GetFunctionParameterExpression expression) {
1628
         JavaParameterInfo parameter = expression.parameter.getTag(JavaParameterInfo.class);
1682
         JavaParameterInfo parameter = expression.parameter.getTag(JavaParameterInfo.class);
1629
-        javaWriter.load(Type.getType(expression.parameter.type.accept(JavaTypeClassVisitor.INSTANCE)), parameter.index);
1683
+
1684
+        if(parameter == null) {
1685
+			System.err.println("NULL PARAMETER!!!");
1686
+			//FIXME
1687
+			parameter = new JavaParameterInfo(1, Type.INT_TYPE);
1688
+		}
1689
+
1690
+        javaWriter.load(expression.parameter.type.accept(JavaTypeVisitor.INSTANCE), parameter.index);
1630
         return null;
1691
         return null;
1631
     }
1692
     }
1632
 
1693
 
1650
     @Override
1711
     @Override
1651
     public Void visitGetter(GetterExpression expression) {
1712
     public Void visitGetter(GetterExpression expression) {
1652
 		expression.target.accept(this);
1713
 		expression.target.accept(this);
1653
-		
1714
+
1654
 		BuiltinID builtin = expression.getter.member.builtin;
1715
 		BuiltinID builtin = expression.getter.member.builtin;
1655
 		if (builtin == null) {
1716
 		if (builtin == null) {
1656
 			if (!checkAndExecuteMethodInfo(expression.getter))
1717
 			if (!checkAndExecuteMethodInfo(expression.getter))
1657
 	            throw new IllegalStateException("Call target has no method info!");
1718
 	            throw new IllegalStateException("Call target has no method info!");
1658
-			
1719
+
1659
 			return null;
1720
 			return null;
1660
 		}
1721
 		}
1661
-		
1722
+
1662
 		switch (builtin) {
1723
 		switch (builtin) {
1663
 			case INT_HIGHEST_ONE_BIT:
1724
 			case INT_HIGHEST_ONE_BIT:
1664
 			case UINT_HIGHEST_ONE_BIT:
1725
 			case UINT_HIGHEST_ONE_BIT:
1729
 				AssocTypeID type = (AssocTypeID) expression.target.type;
1790
 				AssocTypeID type = (AssocTypeID) expression.target.type;
1730
 				ArrayTypeID result = new ArrayTypeID(type.keyType, 1);
1791
 				ArrayTypeID result = new ArrayTypeID(type.keyType, 1);
1731
 				Type resultType = result.accept(JavaTypeVisitor.INSTANCE);
1792
 				Type resultType = result.accept(JavaTypeVisitor.INSTANCE);
1732
-				
1793
+
1733
 				javaWriter.invokeVirtual(MAP_KEYS);
1794
 				javaWriter.invokeVirtual(MAP_KEYS);
1734
 				javaWriter.dup();
1795
 				javaWriter.dup();
1735
 				javaWriter.invokeVirtual(COLLECTION_SIZE);
1796
 				javaWriter.invokeVirtual(COLLECTION_SIZE);
1742
 				AssocTypeID type = (AssocTypeID) expression.target.type;
1803
 				AssocTypeID type = (AssocTypeID) expression.target.type;
1743
 				ArrayTypeID result = new ArrayTypeID(type.valueType, 1);
1804
 				ArrayTypeID result = new ArrayTypeID(type.valueType, 1);
1744
 				Type resultType = result.accept(JavaTypeVisitor.INSTANCE);
1805
 				Type resultType = result.accept(JavaTypeVisitor.INSTANCE);
1745
-				
1806
+
1746
 				javaWriter.invokeVirtual(MAP_VALUES);
1807
 				javaWriter.invokeVirtual(MAP_VALUES);
1747
 				javaWriter.dup();
1808
 				javaWriter.dup();
1748
 				javaWriter.invokeVirtual(COLLECTION_SIZE);
1809
 				javaWriter.invokeVirtual(COLLECTION_SIZE);
1809
 			case ARRAY_ISEMPTY:
1870
 			case ARRAY_ISEMPTY:
1810
 				Label isTrue = new Label();
1871
 				Label isTrue = new Label();
1811
 				Label exit = new Label();
1872
 				Label exit = new Label();
1812
-				
1873
+
1813
 				javaWriter.arrayLength();
1874
 				javaWriter.arrayLength();
1814
 				javaWriter.ifEQ(isTrue);
1875
 				javaWriter.ifEQ(isTrue);
1815
 				javaWriter.iConst0();
1876
 				javaWriter.iConst0();
1994
 
2055
 
1995
         return null;
2056
         return null;
1996
     }
2057
     }
1997
-	
2058
+
1998
 	@Override
2059
 	@Override
1999
 	public Void visitPanic(PanicExpression expression) {
2060
 	public Void visitPanic(PanicExpression expression) {
2000
 		// TODO: compile to: throw new AssertionError(expression.value)
2061
 		// TODO: compile to: throw new AssertionError(expression.value)
2001
 		throw new UnsupportedOperationException("Not yet supported");
2062
 		throw new UnsupportedOperationException("Not yet supported");
2002
 	}
2063
 	}
2003
-	
2064
+
2004
 	@Override
2065
 	@Override
2005
 	public Void visitPostCall(PostCallExpression expression) {
2066
 	public Void visitPostCall(PostCallExpression expression) {
2006
 		expression.target.accept(this);
2067
 		expression.target.accept(this);
2027
         return null;
2088
         return null;
2028
     }
2089
     }
2029
 
2090
 
2030
-	
2091
+
2031
 	@Override
2092
 	@Override
2032
 	public Void visitSameObject(SameObjectExpression expression) {
2093
 	public Void visitSameObject(SameObjectExpression expression) {
2033
 		expression.left.accept(this);
2094
 		expression.left.accept(this);
2034
 		expression.right.accept(this);
2095
 		expression.right.accept(this);
2035
-		
2096
+
2036
 		Label end = new Label();
2097
 		Label end = new Label();
2037
 		Label equal = new Label();
2098
 		Label equal = new Label();
2038
-		
2099
+
2039
 		if (expression.inverted)
2100
 		if (expression.inverted)
2040
 			javaWriter.ifACmpNe(equal);
2101
 			javaWriter.ifACmpNe(equal);
2041
 		else
2102
 		else
2042
 			javaWriter.ifACmpEq(equal);
2103
 			javaWriter.ifACmpEq(equal);
2043
-		
2104
+
2044
 		javaWriter.iConst0();
2105
 		javaWriter.iConst0();
2045
 		javaWriter.goTo(end);
2106
 		javaWriter.goTo(end);
2046
 		javaWriter.label(equal);
2107
 		javaWriter.label(equal);
2083
     public Void visitSetStaticField(SetStaticFieldExpression expression) {
2144
     public Void visitSetStaticField(SetStaticFieldExpression expression) {
2084
         if (expression.field.isFinal())
2145
         if (expression.field.isFinal())
2085
             throw new CompileException(expression.position, CompileExceptionCode.CANNOT_SET_FINAL_VARIABLE, "Cannot set a final field!");
2146
             throw new CompileException(expression.position, CompileExceptionCode.CANNOT_SET_FINAL_VARIABLE, "Cannot set a final field!");
2086
-		
2147
+
2087
         expression.value.accept(this);
2148
         expression.value.accept(this);
2088
         if (!checkAndPutFieldInfo(expression.field, true))
2149
         if (!checkAndPutFieldInfo(expression.field, true))
2089
             throw new IllegalStateException("Missing field info on a field member!");
2150
             throw new IllegalStateException("Missing field info on a field member!");
2101
 		if (builtin == null) {
2162
 		if (builtin == null) {
2102
 			if (!checkAndExecuteMethodInfo(expression.getter))
2163
 			if (!checkAndExecuteMethodInfo(expression.getter))
2103
 	            throw new IllegalStateException("Call target has no method info!");
2164
 	            throw new IllegalStateException("Call target has no method info!");
2104
-			
2165
+
2105
 			return null;
2166
 			return null;
2106
 		}
2167
 		}
2107
-		
2168
+
2108
 		switch (builtin) {
2169
 		switch (builtin) {
2109
 			case BYTE_GET_MIN_VALUE:
2170
 			case BYTE_GET_MIN_VALUE:
2110
 				javaWriter.iConst0();
2171
 				javaWriter.iConst0();
2181
 			default:
2242
 			default:
2182
 				throw new UnsupportedOperationException("Unknown builtin: " + builtin);
2243
 				throw new UnsupportedOperationException("Unknown builtin: " + builtin);
2183
 		}
2244
 		}
2184
-		
2245
+
2185
 		throw new UnsupportedOperationException("Unknown builtin: " + builtin);
2246
 		throw new UnsupportedOperationException("Unknown builtin: " + builtin);
2186
     }
2247
     }
2187
 
2248
 
2256
         JavaMethodInfo methodInfo = member.getTag(JavaMethodInfo.class);
2317
         JavaMethodInfo methodInfo = member.getTag(JavaMethodInfo.class);
2257
         if (methodInfo == null)
2318
         if (methodInfo == null)
2258
             return false;
2319
             return false;
2259
-		
2320
+
2260
         if (methodInfo.isStatic()) {
2321
         if (methodInfo.isStatic()) {
2261
             getJavaWriter().invokeStatic(methodInfo);
2322
             getJavaWriter().invokeStatic(methodInfo);
2262
         } else {
2323
         } else {
2284
         JavaFieldInfo fieldInfo = field.getTag(JavaFieldInfo.class);
2345
         JavaFieldInfo fieldInfo = field.getTag(JavaFieldInfo.class);
2285
         if (fieldInfo == null)
2346
         if (fieldInfo == null)
2286
             return false;
2347
             return false;
2287
-		
2348
+
2288
         getJavaWriter().getStaticField(fieldInfo);
2349
         getJavaWriter().getStaticField(fieldInfo);
2289
         return true;
2350
         return true;
2290
     }
2351
     }
2293
         JavaFieldInfo fieldInfo = field.getTag(JavaFieldInfo.class);
2354
         JavaFieldInfo fieldInfo = field.getTag(JavaFieldInfo.class);
2294
         if (fieldInfo == null)
2355
         if (fieldInfo == null)
2295
             return false;
2356
             return false;
2296
-		
2357
+
2297
         //TODO Remove isStatic
2358
         //TODO Remove isStatic
2298
         if (field.isStatic() || isStatic) {
2359
         if (field.isStatic() || isStatic) {
2299
             getJavaWriter().getStaticField(fieldInfo);
2360
             getJavaWriter().getStaticField(fieldInfo);

+ 2
- 2
JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaForeachVisitor.java View File

27
     @Override
27
     @Override
28
     public Void visitIntRange() {
28
     public Void visitIntRange() {
29
         javaWriter.dup();
29
         javaWriter.dup();
30
-        javaWriter.getField("org/openzen/zenscript/implementations/IntRange", "max", "I");
30
+        javaWriter.getField("org/openzen/zenscript/implementations/IntRange", "to", "I");
31
         javaWriter.swap();
31
         javaWriter.swap();
32
-        javaWriter.getField("org/openzen/zenscript/implementations/IntRange", "min", "I");
32
+        javaWriter.getField("org/openzen/zenscript/implementations/IntRange", "from", "I");
33
 
33
 
34
         final int z = variables[0].getTag(JavaLocalVariableInfo.class).local;
34
         final int z = variables[0].getTag(JavaLocalVariableInfo.class).local;
35
         javaWriter.storeInt(z);
35
         javaWriter.storeInt(z);

+ 6
- 3
JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaStatementVisitor.java View File

271
 
271
 
272
     @Override
272
     @Override
273
     public Boolean visitVar(VarStatement statement) {
273
     public Boolean visitVar(VarStatement statement) {
274
-        Type type = statement.type.accept(JavaTypeVisitor.INSTANCE);
275
-        int local = javaWriter.local(type);
274
+
276
         if (statement.initializer != null) {
275
         if (statement.initializer != null) {
277
             statement.initializer.accept(expressionVisitor);
276
             statement.initializer.accept(expressionVisitor);
278
-            javaWriter.store(type, local);
279
         }
277
         }
278
+
279
+        Type type = statement.type.accept(JavaTypeVisitor.INSTANCE);
280
+        int local = javaWriter.local(type);
281
+        if(statement.initializer != null)
282
+            javaWriter.store(type, local);
280
         final Label variableStart = new Label();
283
         final Label variableStart = new Label();
281
         javaWriter.label(variableStart);
284
         javaWriter.label(variableStart);
282
         final JavaLocalVariableInfo info = new JavaLocalVariableInfo(type, local, variableStart, statement.name);
285
         final JavaLocalVariableInfo info = new JavaLocalVariableInfo(type, local, variableStart, statement.name);

+ 7
- 1
JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaTypeClassVisitor.java View File

1
 package org.openzen.zenscript.javabytecode.compiler;
1
 package org.openzen.zenscript.javabytecode.compiler;
2
 
2
 
3
 import org.openzen.zenscript.codemodel.type.*;
3
 import org.openzen.zenscript.codemodel.type.*;
4
+import org.openzen.zenscript.javabytecode.JavaModule;
4
 
5
 
5
 import java.lang.reflect.Array;
6
 import java.lang.reflect.Array;
6
 import java.util.Iterator;
7
 import java.util.Iterator;
63
 
64
 
64
     @Override
65
     @Override
65
     public Class visitFunction(FunctionTypeID function) {
66
     public Class visitFunction(FunctionTypeID function) {
66
-        return null;
67
+        try {
68
+            return new JavaModule().new ScriptClassLoader().loadClass(CompilerUtils.getLambdaInterface(function.header));
69
+        } catch (ClassNotFoundException e) {
70
+            return null;
71
+        }
72
+        //return function.header.returnType.accept(this);
67
     }
73
     }
68
 
74
 
69
     @Override
75
     @Override

+ 2
- 1
JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaTypeVisitor.java View File

28
 
28
 
29
     @Override
29
     @Override
30
     public Type visitFunction(FunctionTypeID function) {
30
     public Type visitFunction(FunctionTypeID function) {
31
-        return Type.getType(function.accept(JavaTypeClassVisitor.INSTANCE));
31
+        Class clazz = function.accept(JavaTypeClassVisitor.INSTANCE);
32
+        return clazz != null ? Type.getType(clazz) : Type.getType("L" + CompilerUtils.getLambdaInterface(function.header) + ";");
32
     }
33
     }
33
 
34
 
34
     @Override
35
     @Override

+ 2
- 0
JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaDefinitionVisitor.java View File

3
 import org.objectweb.asm.ClassWriter;
3
 import org.objectweb.asm.ClassWriter;
4
 import org.objectweb.asm.Opcodes;
4
 import org.objectweb.asm.Opcodes;
5
 import org.objectweb.asm.Type;
5
 import org.objectweb.asm.Type;
6
+import org.openzen.zenscript.codemodel.FunctionParameter;
6
 import org.openzen.zenscript.codemodel.definition.*;
7
 import org.openzen.zenscript.codemodel.definition.*;
7
 import org.openzen.zenscript.codemodel.member.IDefinitionMember;
8
 import org.openzen.zenscript.codemodel.member.IDefinitionMember;
8
 import org.openzen.zenscript.codemodel.type.BasicTypeID;
9
 import org.openzen.zenscript.codemodel.type.BasicTypeID;
10
 import org.openzen.zenscript.javabytecode.JavaClassInfo;
11
 import org.openzen.zenscript.javabytecode.JavaClassInfo;
11
 import org.openzen.zenscript.javabytecode.JavaMethodInfo;
12
 import org.openzen.zenscript.javabytecode.JavaMethodInfo;
12
 import org.openzen.zenscript.javabytecode.JavaModule;
13
 import org.openzen.zenscript.javabytecode.JavaModule;
14
+import org.openzen.zenscript.javabytecode.JavaParameterInfo;
13
 import org.openzen.zenscript.javabytecode.compiler.*;
15
 import org.openzen.zenscript.javabytecode.compiler.*;
14
 
16
 
15
 
17
 

+ 1
- 1
Shared/src/main/java/zsynthetic/ArrayHelpers.java View File

3
 public class ArrayHelpers {
3
 public class ArrayHelpers {
4
     public static <T> boolean contains(T[] haystack, T needle) {
4
     public static <T> boolean contains(T[] haystack, T needle) {
5
         for (int i = 0; i < haystack.length; i++)
5
         for (int i = 0; i < haystack.length; i++)
6
-            if (haystack[i].equals(needle))
6
+            if (java.util.Objects.equals(haystack[i], needle))
7
                 return true;
7
                 return true;
8
         return false;
8
         return false;
9
     }
9
     }

Loading…
Cancel
Save