diff --git a/cli-impl/src/main/java/org/aya/cli/library/incremental/DiskCompilerAdvisor.java b/cli-impl/src/main/java/org/aya/cli/library/incremental/DiskCompilerAdvisor.java index b9a009fcc5..366e4dd456 100644 --- a/cli-impl/src/main/java/org/aya/cli/library/incremental/DiskCompilerAdvisor.java +++ b/cli-impl/src/main/java/org/aya/cli/library/incremental/DiskCompilerAdvisor.java @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. // Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. package org.aya.cli.library.incremental; @@ -8,7 +8,6 @@ import org.aya.cli.library.source.LibrarySource; import org.aya.cli.utils.CompilerUtil; import org.aya.compiler.CompiledModule; -import org.aya.compiler.free.morphism.SourceFreeJavaBuilder; import org.aya.compiler.serializers.ModuleSerializer; import org.aya.compiler.serializers.NameSerializer; import org.aya.prelude.GeneratedVersion; @@ -129,8 +128,8 @@ public void addURL(Path url) throws MalformedURLException { @NotNull ImmutableSeq defs, @NotNull ModuleLoader recurseLoader ) throws IOException, ClassNotFoundException { - var javaCode = new ModuleSerializer(resolveInfo.shapeFactory()) - .serialize(SourceFreeJavaBuilder.create(), new ModuleSerializer.ModuleResult( + var javaCode = new ModuleSerializer(resolveInfo.shapeFactory()) + .serializeWithBestBuilder(new ModuleSerializer.ModuleResult( QPath.fileLevel(file.moduleName()), defs.filterIsInstance(TopLevelDef.class))); var libraryRoot = file.owner().outDir(); diff --git a/jit-compiler/src/main/java/module-info.java b/jit-compiler/src/main/java/module-info.java index 3a26ce8ed2..d08f772db3 100644 --- a/jit-compiler/src/main/java/module-info.java +++ b/jit-compiler/src/main/java/module-info.java @@ -8,6 +8,5 @@ exports org.aya.compiler; exports org.aya.compiler.free; exports org.aya.compiler.free.data; - exports org.aya.compiler.free.morphism; exports org.aya.compiler.serializers; } diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/ArgumentProvider.java b/jit-compiler/src/main/java/org/aya/compiler/free/ArgumentProvider.java index 1017812fce..37fd18739d 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/ArgumentProvider.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/ArgumentProvider.java @@ -5,6 +5,9 @@ import org.aya.compiler.free.data.LocalVariable; import org.jetbrains.annotations.NotNull; +/** + * The implementation should be pure (at least, same input same output, some kind of side effect is acceptable) + */ public interface ArgumentProvider { interface Lambda extends ArgumentProvider { @NotNull FreeJavaExpr capture(int nth); diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/Constants.java b/jit-compiler/src/main/java/org/aya/compiler/free/Constants.java index 4e765b1dd6..2528c921c2 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/Constants.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/Constants.java @@ -7,8 +7,8 @@ import kala.collection.immutable.ImmutableTreeSeq; import kala.collection.mutable.MutableSeq; import kala.control.Result; -import org.aya.compiler.free.data.FieldRef; import org.aya.compiler.free.data.MethodRef; +import org.aya.compiler.free.data.FieldRef; import org.aya.syntax.compile.JitClass; import org.aya.syntax.compile.JitCon; import org.aya.syntax.compile.JitData; @@ -41,7 +41,7 @@ private Constants() { } public static final @NotNull ClassDesc CD_Result = FreeUtil.fromClass(Result.class); // Term -> Term - public static final @NotNull MethodRef CLOSURE = new MethodRef.Default( + public static final @NotNull MethodRef CLOSURE = new MethodRef( FreeUtil.fromClass(UnaryOperator.class), "apply", ConstantDescs.CD_Object, ImmutableSeq.of(ConstantDescs.CD_Object), @@ -49,14 +49,14 @@ private Constants() { } ); // () -> Term - public static final @NotNull MethodRef THUNK = new MethodRef.Default( + public static final @NotNull MethodRef THUNK = new MethodRef( FreeUtil.fromClass(Supplier.class), "get", ConstantDescs.CD_Object, ImmutableSeq.empty(), true ); - public static final @NotNull MethodRef FUNCTION = new MethodRef.Default( + public static final @NotNull MethodRef FUNCTION = new MethodRef( FreeUtil.fromClass(Function.class), "apply", ConstantDescs.CD_Object, ImmutableSeq.of(ConstantDescs.CD_Object), @@ -64,7 +64,7 @@ private Constants() { } ); // ImmutableSeq from(Object[]) - public static final @NotNull MethodRef IMMSEQ = new MethodRef.Default( + public static final @NotNull MethodRef IMMSEQ = new MethodRef( CD_ImmutableSeq, "from", CD_ImmutableSeq, ImmutableSeq.of(ConstantDescs.CD_Object.arrayType()), @@ -74,7 +74,7 @@ private Constants() { } /** * @see MutableSeq#fill(int, Object) */ - public static final @NotNull MethodRef MUTSEQ = new MethodRef.Default( + public static final @NotNull MethodRef MUTSEQ = new MethodRef( CD_MutableSeq, "fill", CD_MutableSeq, ImmutableSeq.of(ConstantDescs.CD_int, ConstantDescs.CD_Object), @@ -84,7 +84,7 @@ private Constants() { } /** * @see MutableSeq#set(int, Object) */ - public static final @NotNull MethodRef MUTSEQ_SET = new MethodRef.Default( + public static final @NotNull MethodRef MUTSEQ_SET = new MethodRef( CD_MutableSeq, "set", ConstantDescs.CD_void, ImmutableSeq.of(ConstantDescs.CD_int, ConstantDescs.CD_Object), true @@ -95,7 +95,7 @@ private Constants() { } * * @see Seq#get(int) */ - public static final @NotNull MethodRef SEQ_GET = new MethodRef.Default( + public static final @NotNull MethodRef SEQ_GET = new MethodRef( CD_Seq, "get", ConstantDescs.CD_Object, ImmutableSeq.of(ConstantDescs.CD_int), true @@ -104,11 +104,11 @@ private Constants() { } /** * @see Seq#toImmutableSeq() */ - public static final @NotNull MethodRef SEQ_TOIMMSEQ = new MethodRef.Default( + public static final @NotNull MethodRef SEQ_TOIMMSEQ = new MethodRef( CD_Seq, "toImmutableSeq", CD_ImmutableSeq, ImmutableSeq.empty(), true ); - public static final @NotNull MethodRef IMMTREESEQ = new MethodRef.Default( + public static final @NotNull MethodRef IMMTREESEQ = new MethodRef( FreeUtil.fromClass(ImmutableTreeSeq.class), "from", FreeUtil.fromClass(ImmutableTreeSeq.class), @@ -116,7 +116,7 @@ private Constants() { } false ); - public static final @NotNull MethodRef BETAMAKE = new MethodRef.Default( + public static final @NotNull MethodRef BETAMAKE = new MethodRef( FreeUtil.fromClass(BetaRedex.class), "make", CD_Term, ImmutableSeq.empty(), @@ -126,14 +126,14 @@ private Constants() { } /** * @see Term#elevate(int) */ - public static final @NotNull MethodRef ELEVATE = new MethodRef.Default( + public static final @NotNull MethodRef ELEVATE = new MethodRef( CD_Term, "elevate", CD_Term, ImmutableSeq.of(ConstantDescs.CD_int), true ); /** * @see RuleReducer#make() */ - public static final @NotNull MethodRef RULEREDUCER_MAKE = new MethodRef.Default( + public static final @NotNull MethodRef RULEREDUCER_MAKE = new MethodRef( FreeUtil.fromClass(RuleReducer.class), "make", CD_Term, ImmutableSeq.empty(), @@ -143,7 +143,7 @@ private Constants() { } /** * @see Closure#mkConst(Term) */ - public static final @NotNull MethodRef CLOSURE_MKCONST = new MethodRef.Default( + public static final @NotNull MethodRef CLOSURE_MKCONST = new MethodRef( FreeUtil.fromClass(Closure.class), "mkConst", FreeUtil.fromClass(Closure.class), @@ -154,7 +154,7 @@ private Constants() { } /** * @see Panic#unreachable() */ - public static final @NotNull MethodRef PANIC = new MethodRef.Default( + public static final @NotNull MethodRef PANIC = new MethodRef( FreeUtil.fromClass(Panic.class), "unreachable", ConstantDescs.CD_Object, @@ -162,7 +162,7 @@ private Constants() { } true ); - public static final @NotNull MethodRef INT_REPR = new MethodRef.Default( + public static final @NotNull MethodRef INT_REPR = new MethodRef( FreeUtil.fromClass(IntegerTerm.class), "repr", ConstantDescs.CD_int, @@ -173,7 +173,7 @@ private Constants() { } /** * @see ConCallLike#conArgs() */ - public static final @NotNull MethodRef CONARGS = new MethodRef.Default( + public static final @NotNull MethodRef CONARGS = new MethodRef( FreeUtil.fromClass(ConCallLike.class), "conArgs", CD_ImmutableSeq, @@ -184,7 +184,7 @@ private Constants() { } /** * @see TupTerm#lhs() */ - public static final @NotNull MethodRef TUP_LHS = new MethodRef.Default( + public static final @NotNull MethodRef TUP_LHS = new MethodRef( FreeUtil.fromClass(TupTerm.class), "lhs", CD_Term, @@ -195,7 +195,7 @@ private Constants() { } /** * @see TupTerm#rhs() */ - public static final @NotNull MethodRef TUP_RHS = new MethodRef.Default( + public static final @NotNull MethodRef TUP_RHS = new MethodRef( FreeUtil.fromClass(TupTerm.class), "rhs", CD_Term, @@ -206,13 +206,13 @@ private Constants() { } /** * @see Result#ok(Object) */ - public static final @NotNull MethodRef RESULT_OK = new MethodRef.Default( + public static final @NotNull MethodRef RESULT_OK = new MethodRef( CD_Result, "ok", CD_Result, ImmutableSeq.of(ConstantDescs.CD_Object), true ); - public static final @NotNull MethodRef RESULT_ERR = new MethodRef.Default( + public static final @NotNull MethodRef RESULT_ERR = new MethodRef( CD_Result, "err", CD_Result, ImmutableSeq.of(ConstantDescs.CD_Object), true @@ -225,13 +225,13 @@ private Constants() { } ConstantDescs.CD_int, ConstantDescs.CD_boolean.arrayType(), ConstantDescs.CD_String.arrayType() ); - public static final @NotNull FieldRef JITDATA_CONS = new FieldRef.Default( + public static final @NotNull FieldRef JITDATA_CONS = new FieldRef( FreeUtil.fromClass(JitData.class), FreeUtil.fromClass(JitCon.class).arrayType(), "constructors" ); - public static final @NotNull FieldRef JITCLASS_MEMS = new FieldRef.Default( + public static final @NotNull FieldRef JITCLASS_MEMS = new FieldRef( FreeUtil.fromClass(JitClass.class), FreeUtil.fromClass(JitMember.class).arrayType(), "members" @@ -240,7 +240,7 @@ private Constants() { } /** * @see UnaryOperator#identity() */ - public static final @NotNull MethodRef CLOSURE_ID = new MethodRef.Default( + public static final @NotNull MethodRef CLOSURE_ID = new MethodRef( FreeUtil.fromClass(UnaryOperator.class), "identity", FreeUtil.fromClass(UnaryOperator.class), @@ -251,7 +251,7 @@ private Constants() { } /** * @see PatMatcher#apply(ImmutableSeq, ImmutableSeq) */ - public static final @NotNull MethodRef PATMATCHER_APPLY = new MethodRef.Default( + public static final @NotNull MethodRef PATMATCHER_APPLY = new MethodRef( FreeUtil.fromClass(PatMatcher.class), "apply", CD_Result, ImmutableSeq.of(CD_ImmutableSeq, CD_ImmutableSeq), false ); diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/FreeClassBuilder.java b/jit-compiler/src/main/java/org/aya/compiler/free/FreeClassBuilder.java index 4820ef6feb..0e9634b47f 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/FreeClassBuilder.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/FreeClassBuilder.java @@ -16,10 +16,9 @@ public interface FreeClassBuilder { static @NotNull MethodRef makeConstructorRef(@NotNull ClassDesc owner, @NotNull ImmutableSeq parameterTypes) { - return new MethodRef.Default(owner, ConstantDescs.INIT_NAME, ConstantDescs.CD_void, parameterTypes, false); + return new MethodRef(owner, ConstantDescs.INIT_NAME, ConstantDescs.CD_void, parameterTypes, false); } - void buildMetadata(@NotNull CompiledAya compiledAya); void buildNestedClass( @NotNull CompiledAya compiledAya, @NotNull String name, @@ -44,6 +43,4 @@ void buildNestedClass( @NotNull String name, @NotNull Function initializer ); - - @NotNull FreeJavaResolver resolver(); } diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/FreeCodeBuilder.java b/jit-compiler/src/main/java/org/aya/compiler/free/FreeCodeBuilder.java index e7e599df17..7de35bde0d 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/FreeCodeBuilder.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/FreeCodeBuilder.java @@ -4,7 +4,6 @@ import kala.collection.immutable.ImmutableSeq; import kala.collection.immutable.primitive.ImmutableIntSeq; -import org.aya.compiler.free.data.FieldRef; import org.aya.compiler.free.data.LocalVariable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,10 +26,6 @@ default LocalVariable makeVar(@NotNull Class type, @Nullable FreeJavaExpr ini void updateArray(@NotNull FreeJavaExpr array, int idx, @NotNull FreeJavaExpr update); - void updateField(@NotNull FieldRef field, @NotNull FreeJavaExpr update); - - void updateField(@NotNull FieldRef field, @NotNull FreeJavaExpr owner, @NotNull FreeJavaExpr update); - void ifNotTrue(@NotNull LocalVariable notTrue, @NotNull Consumer thenBlock, @Nullable Consumer elseBlock); void ifTrue(@NotNull LocalVariable theTrue, @NotNull Consumer thenBlock, @Nullable Consumer elseBlock); diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/FreeExprBuilder.java b/jit-compiler/src/main/java/org/aya/compiler/free/FreeExprBuilder.java index c51252ef2a..4b690c4bb8 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/FreeExprBuilder.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/FreeExprBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. // Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. package org.aya.compiler.free; @@ -7,6 +7,7 @@ import org.aya.compiler.free.data.LocalVariable; import org.aya.compiler.free.data.MethodRef; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.lang.constant.ClassDesc; import java.util.Arrays; @@ -16,8 +17,6 @@ * the result only depends on the {@link FreeCodeBuilder} that this builder derived from */ public interface FreeExprBuilder { - @NotNull FreeJavaResolver resolver(); - /** * A {@code new} expression on specified constructor. */ @@ -39,7 +38,9 @@ public interface FreeExprBuilder { return mkNew(conRef, args); } - @NotNull FreeJavaExpr refVar(@NotNull LocalVariable name); + default @NotNull FreeJavaExpr refVar(@NotNull LocalVariable name) { + return name.ref(); + } /** * Invoke a (non-interface) method on {@param owner}. @@ -62,6 +63,12 @@ public interface FreeExprBuilder { return refEnum(cd, name); } + /** + * Make a lambda expression + * + * @param builder the builder for building the lambda body, you should use local variable comes from this and the + * {@link ArgumentProvider.Lambda} ONLY, other variables introduced outside of the lambda is unavailable. + */ @NotNull FreeJavaExpr mkLambda( @NotNull ImmutableSeq captures, @NotNull MethodRef method, @@ -85,7 +92,7 @@ public interface FreeExprBuilder { */ @NotNull FreeJavaExpr mkArray( @NotNull ClassDesc type, int length, - @NotNull ImmutableSeq initializer + @Nullable ImmutableSeq initializer ); @NotNull FreeJavaExpr getArray(@NotNull FreeJavaExpr array, int index); diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/FreeJavaResolver.java b/jit-compiler/src/main/java/org/aya/compiler/free/FreeJavaResolver.java index fff9ed8ed3..012e2dbe0d 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/FreeJavaResolver.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/FreeJavaResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. // Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. package org.aya.compiler.free; @@ -12,28 +12,29 @@ import java.lang.constant.ConstantDescs; import java.util.Arrays; -public interface FreeJavaResolver { +public final class FreeJavaResolver { /** * Find a method with given information */ - @NotNull MethodRef resolve( + public static @NotNull MethodRef resolve( @NotNull ClassDesc owner, @NotNull String name, @NotNull ClassDesc returnType, @NotNull ImmutableSeq paramType, boolean isInterface - ); + ) { + return new MethodRef(owner, name, returnType, paramType, isInterface); + } - @NotNull FieldRef resolve( + public static @NotNull FieldRef resolve( @NotNull ClassDesc owner, @NotNull String name, @NotNull ClassDesc returnType - ); - - default @NotNull FieldRef resolve( - @NotNull Class owner, - @NotNull String name ) { + return new FieldRef(owner, returnType, name); + } + + public static @NotNull FieldRef resolve(@NotNull Class owner, @NotNull String name) { try { var field = owner.getField(name); return resolve(FreeUtil.fromClass(owner), name, FreeUtil.fromClass(field.getType())); @@ -45,7 +46,7 @@ public interface FreeJavaResolver { /** * Find the only method with given name */ - default @NotNull MethodRef resolve(@NotNull Class owner, @NotNull String name, int paramSize) { + public static @NotNull MethodRef resolve(@NotNull Class owner, @NotNull String name, int paramSize) { if (name.equals(ConstantDescs.INIT_NAME)) { throw new Panic("use ExprBuilder#newObject instead"); } diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/data/FieldRef.java b/jit-compiler/src/main/java/org/aya/compiler/free/data/FieldRef.java index 1b6bd24b8e..b30a2bafdb 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/data/FieldRef.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/data/FieldRef.java @@ -6,15 +6,9 @@ import java.lang.constant.ClassDesc; -public interface FieldRef { - record Default( - @NotNull ClassDesc owner, - @NotNull ClassDesc returnType, - @NotNull String name - ) implements FieldRef { - } - - @NotNull ClassDesc owner(); - @NotNull ClassDesc returnType(); - @NotNull String name(); +public record FieldRef( + @NotNull ClassDesc owner, + @NotNull ClassDesc returnType, + @NotNull String name +) { } diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/data/MethodRef.java b/jit-compiler/src/main/java/org/aya/compiler/free/data/MethodRef.java index f8ca330af9..ebbde792c0 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/data/MethodRef.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/data/MethodRef.java @@ -6,21 +6,16 @@ import org.jetbrains.annotations.NotNull; import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; -public interface MethodRef { - record Default( - @Override @NotNull ClassDesc owner, - @Override @NotNull String name, - @Override @NotNull ClassDesc returnType, - @Override @NotNull ImmutableSeq paramTypes, - @Override boolean isInterface - ) implements MethodRef { +public record MethodRef( + @Override @NotNull ClassDesc owner, + @Override @NotNull String name, + @Override @NotNull ClassDesc returnType, + @Override @NotNull ImmutableSeq paramTypes, + @Override boolean isInterface +) { + public boolean isConstructor() { + return name().equals(ConstantDescs.INIT_NAME); } - - @NotNull ClassDesc owner(); - @NotNull String name(); - @NotNull ClassDesc returnType(); - @NotNull ImmutableSeq paramTypes(); - - boolean isInterface(); } diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeArgumentProvider.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeArgumentProvider.java new file mode 100644 index 0000000000..952ccb8321 --- /dev/null +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeArgumentProvider.java @@ -0,0 +1,27 @@ +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. +// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. +package org.aya.compiler.free.morphism.free; + +import org.aya.compiler.free.ArgumentProvider; +import org.aya.compiler.free.FreeJavaExpr; +import org.aya.compiler.free.data.LocalVariable; +import org.jetbrains.annotations.NotNull; + +public record FreeArgumentProvider(int paramCount) implements ArgumentProvider { + @Override public @NotNull LocalVariable arg(int nth) { + assert nth < paramCount; + return new FreeVariable.Arg(nth); + } + + record Lambda(int captureCount, int paramCount) implements ArgumentProvider.Lambda { + @Override public @NotNull FreeJavaExpr capture(int nth) { + assert nth < captureCount; + return new FreeExpr.RefCapture(nth); + } + + @Override public @NotNull LocalVariable arg(int nth) { + assert nth < paramCount; + return new FreeVariable.Arg(nth); + } + } +} diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeClassBuilderImpl.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeClassBuilderImpl.java new file mode 100644 index 0000000000..399e3e387e --- /dev/null +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeClassBuilderImpl.java @@ -0,0 +1,84 @@ +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. +// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. +package org.aya.compiler.free.morphism.free; + +import kala.collection.immutable.ImmutableSeq; +import kala.collection.mutable.FreezableMutableList; +import org.aya.compiler.free.*; +import org.aya.compiler.free.data.FieldRef; +import org.aya.compiler.free.data.MethodRef; +import org.aya.syntax.compile.CompiledAya; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.constant.ClassDesc; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; + +public record FreeClassBuilderImpl( + @Nullable CompiledAya metadata, + @NotNull ClassDesc parentOrThis, + @Nullable String nested, + @NotNull Class superclass, + @NotNull FreezableMutableList members +) implements FreeClassBuilder { + public @NotNull FreeDecl.Clazz build() { + return new FreeDecl.Clazz(metadata, parentOrThis, nested, superclass, members.freeze()); + } + + public @NotNull ClassDesc className() { + return nested == null ? parentOrThis : parentOrThis.nested(nested); + } + + @Override public void buildNestedClass( + @NotNull CompiledAya compiledAya, + @NotNull String name, + @NotNull Class superclass, + @NotNull Consumer builder + ) { + var classBuilder = new FreeClassBuilderImpl(compiledAya, className(), name, superclass, FreezableMutableList.create()); + builder.accept(classBuilder); + members.append(classBuilder.build()); + } + + private void buildMethod( + @NotNull MethodRef ref, + @NotNull BiConsumer builder + ) { + var codeBuilder = new FreeCodeBuilderImpl(FreezableMutableList.create(), new VariablePool(), ref.isConstructor(), false); + builder.accept(new FreeArgumentProvider(ref.paramTypes().size()), codeBuilder); + members.append(new FreeDecl.Method(ref, codeBuilder.build())); + } + + @Override public @NotNull MethodRef buildMethod( + @NotNull ClassDesc returnType, + @NotNull String name, + @NotNull ImmutableSeq paramTypes, + @NotNull BiConsumer builder + ) { + var ref = new MethodRef(className(), name, returnType, paramTypes, false); + buildMethod(ref, builder); + return ref; + } + + @Override public @NotNull MethodRef buildConstructor( + @NotNull ImmutableSeq paramTypes, + @NotNull BiConsumer builder + ) { + var ref = FreeClassBuilder.makeConstructorRef(className(), paramTypes); + buildMethod(ref, builder); + return ref; + } + + @Override public @NotNull FieldRef buildConstantField( + @NotNull ClassDesc returnType, + @NotNull String name, + @NotNull Function initializer + ) { + var ref = new FieldRef(className(), returnType, name); + var expr = (FreeExpr) initializer.apply(FreeExprBuilderImpl.INSTANCE); + members.append(new FreeDecl.ConstantField(ref, expr)); + return ref; + } +} diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeCodeBuilderImpl.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeCodeBuilderImpl.java new file mode 100644 index 0000000000..dcc3ae8fe9 --- /dev/null +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeCodeBuilderImpl.java @@ -0,0 +1,228 @@ +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. +// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. +package org.aya.compiler.free.morphism.free; + +import kala.collection.immutable.ImmutableSeq; +import kala.collection.immutable.primitive.ImmutableIntSeq; +import kala.collection.mutable.FreezableMutableList; +import kala.value.MutableValue; +import org.aya.compiler.free.ArgumentProvider; +import org.aya.compiler.free.FreeCodeBuilder; +import org.aya.compiler.free.FreeJavaExpr; +import org.aya.compiler.free.data.FieldRef; +import org.aya.compiler.free.data.LocalVariable; +import org.aya.compiler.free.data.MethodRef; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.constant.ClassDesc; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.ObjIntConsumer; + +public record FreeCodeBuilderImpl( + @NotNull FreezableMutableList stmts, + @NotNull VariablePool pool, + boolean isConstructor, + boolean isBreakable +) implements FreeCodeBuilder { + public @NotNull ImmutableSeq subscoped(boolean isBreakable, @NotNull Consumer block) { + var inner = new FreeCodeBuilderImpl(FreezableMutableList.create(), pool, isConstructor, isBreakable); + block.accept(inner); + return inner.build(); + } + + public @NotNull ImmutableSeq build() { + return stmts.freeze(); + } + + public static @NotNull FreeExpr assertFreeExpr(@NotNull FreeJavaExpr expr) { + return (FreeExpr) expr; + } + + public static @NotNull ImmutableSeq assertFreeExpr(@NotNull ImmutableSeq exprs) { + return exprs.map(x -> (FreeExpr) x); + } + + public static @NotNull FreeVariable assertFreeVariable(@NotNull LocalVariable var) { + return (FreeVariable) var; + } + + public @NotNull FreeVariable.Local acquireVariable() { + return new FreeVariable.Local(pool.acquire()); + } + + @Override + public @NotNull FreeVariable makeVar(@NotNull ClassDesc type, @Nullable FreeJavaExpr initializer) { + var theVar = acquireVariable(); + stmts.append(new FreeStmt.DeclareVariable(type, theVar)); + if (initializer != null) updateVar(theVar, initializer); + return theVar; + } + + @Override + public void invokeSuperCon(@NotNull ImmutableSeq superConParams, @NotNull ImmutableSeq superConArgs) { + assert isConstructor; + stmts.append(new FreeStmt.Super(superConParams, assertFreeExpr(superConArgs))); + } + + @Override + public void updateVar(@NotNull LocalVariable var, @NotNull FreeJavaExpr update) { + stmts.append(new FreeStmt.SetVariable(assertFreeVariable(var), assertFreeExpr(update))); + } + + @Override + public void updateArray(@NotNull FreeJavaExpr array, int idx, @NotNull FreeJavaExpr update) { + stmts.append(new FreeStmt.SetArray(assertFreeExpr(array), idx, assertFreeExpr(update))); + } + + private void buildIf(@NotNull FreeStmt.Condition condition, @NotNull Consumer thenBlock, @Nullable Consumer elseBlock) { + var thenBlockBody = subscoped(isBreakable, thenBlock::accept); + var elseBlockBody = elseBlock == null ? null : subscoped(isBreakable, elseBlock::accept); + + stmts.append(new FreeStmt.IfThenElse(condition, thenBlockBody, elseBlockBody)); + } + + @Override + public void ifNotTrue(@NotNull LocalVariable notTrue, @NotNull Consumer thenBlock, @Nullable Consumer elseBlock) { + buildIf(new FreeStmt.Condition.IsFalse(assertFreeVariable(notTrue)), thenBlock, elseBlock); + } + + @Override + public void ifTrue(@NotNull LocalVariable theTrue, @NotNull Consumer thenBlock, @Nullable Consumer elseBlock) { + buildIf(new FreeStmt.Condition.IsTrue(assertFreeVariable(theTrue)), thenBlock, elseBlock); + } + + @Override + public void ifInstanceOf(@NotNull FreeJavaExpr lhs, @NotNull ClassDesc rhs, @NotNull BiConsumer thenBlock, @Nullable Consumer elseBlock) { + var varHolder = MutableValue.create(); + buildIf(new FreeStmt.Condition.IsInstanceOf(assertFreeExpr(lhs), rhs, varHolder), b -> { + var asTerm = ((FreeCodeBuilderImpl) b).acquireVariable(); + varHolder.set(asTerm); + thenBlock.accept(b, asTerm); + }, elseBlock); + } + + @Override + public void ifIntEqual(@NotNull FreeJavaExpr lhs, int rhs, @NotNull Consumer thenBlock, @Nullable Consumer elseBlock) { + buildIf(new FreeStmt.Condition.IsIntEqual(assertFreeExpr(lhs), rhs), thenBlock, elseBlock); + } + + @Override + public void ifRefEqual(@NotNull FreeJavaExpr lhs, @NotNull FreeJavaExpr rhs, @NotNull Consumer thenBlock, @Nullable Consumer elseBlock) { + buildIf(new FreeStmt.Condition.IsRefEqual(assertFreeExpr(lhs), assertFreeExpr(rhs)), thenBlock, elseBlock); + } + + @Override + public void ifNull(@NotNull FreeJavaExpr isNull, @NotNull Consumer thenBlock, @Nullable Consumer elseBlock) { + buildIf(new FreeStmt.Condition.IsNull(assertFreeExpr(isNull)), thenBlock, elseBlock); + } + + @Override + public void breakable(@NotNull Consumer innerBlock) { + var innerBlockBody = subscoped(true, innerBlock::accept); + stmts.append(new FreeStmt.Breakable(innerBlockBody)); + } + + @Override + public void breakOut() { + assert isBreakable; + stmts.append(FreeStmt.Break.INSTANCE); + } + + @Override + public void exec(@NotNull FreeJavaExpr expr) { + stmts.append(new FreeStmt.Exec(assertFreeExpr(expr))); + } + + @Override + public void switchCase( + @NotNull LocalVariable elim, + @NotNull ImmutableIntSeq cases, + @NotNull ObjIntConsumer branch, + @NotNull Consumer defaultCase + ) { + var branchBodies = cases.mapToObj(kase -> + subscoped(isBreakable, b -> branch.accept(b, kase))); + var defaultBody = subscoped(isBreakable, defaultCase::accept); + + stmts.append(new FreeStmt.Switch(assertFreeVariable(elim), cases, branchBodies, defaultBody)); + } + + @Override public void returnWith(@NotNull FreeJavaExpr expr) { + stmts.append(new FreeStmt.Return(assertFreeExpr(expr))); + } + + @Override + public @NotNull FreeJavaExpr mkNew(@NotNull MethodRef conRef, @NotNull ImmutableSeq args) { + return FreeExprBuilderImpl.INSTANCE.mkNew(conRef, args); + } + + @Override public @NotNull FreeJavaExpr refVar(@NotNull LocalVariable name) { + return FreeExprBuilderImpl.INSTANCE.refVar(name); + } + + @Override + public @NotNull FreeJavaExpr invoke(@NotNull MethodRef method, @NotNull FreeJavaExpr owner, @NotNull ImmutableSeq args) { + return FreeExprBuilderImpl.INSTANCE.invoke(method, owner, args); + } + + @Override + public @NotNull FreeJavaExpr invoke(@NotNull MethodRef method, @NotNull ImmutableSeq args) { + return FreeExprBuilderImpl.INSTANCE.invoke(method, args); + } + + @Override public @NotNull FreeJavaExpr refField(@NotNull FieldRef field) { + return FreeExprBuilderImpl.INSTANCE.refField(field); + } + + @Override + public @NotNull FreeJavaExpr refField(@NotNull FieldRef field, @NotNull FreeJavaExpr owner) { + return FreeExprBuilderImpl.INSTANCE.refField(field, owner); + } + + @Override + public @NotNull FreeJavaExpr refEnum(@NotNull ClassDesc enumClass, @NotNull String enumName) { + return FreeExprBuilderImpl.INSTANCE.refEnum(enumClass, enumName); + } + + @Override + public @NotNull FreeJavaExpr mkLambda(@NotNull ImmutableSeq captures, @NotNull MethodRef method, @NotNull BiConsumer builder) { + return FreeExprBuilderImpl.INSTANCE.mkLambda(captures, method, builder); + } + + @Override + public @NotNull FreeJavaExpr iconst(int i) { + return FreeExprBuilderImpl.INSTANCE.iconst(i); + } + + @Override + public @NotNull FreeJavaExpr iconst(boolean b) { + return FreeExprBuilderImpl.INSTANCE.iconst(b); + } + + @Override public @NotNull FreeJavaExpr aconst(@NotNull String value) { + return FreeExprBuilderImpl.INSTANCE.aconst(value); + } + + @Override public @NotNull FreeJavaExpr aconstNull(@NotNull ClassDesc type) { + return FreeExprBuilderImpl.INSTANCE.aconstNull(type); + } + + @Override public @NotNull FreeJavaExpr thisRef() { + return FreeExprBuilderImpl.INSTANCE.thisRef(); + } + + @Override + public @NotNull FreeJavaExpr mkArray(@NotNull ClassDesc type, int length, @Nullable ImmutableSeq initializer) { + return FreeExprBuilderImpl.INSTANCE.mkArray(type, length, initializer); + } + + @Override public @NotNull FreeJavaExpr getArray(@NotNull FreeJavaExpr array, int index) { + return FreeExprBuilderImpl.INSTANCE.getArray(array, index); + } + + @Override public @NotNull FreeJavaExpr checkcast(@NotNull FreeJavaExpr obj, @NotNull ClassDesc as) { + return FreeExprBuilderImpl.INSTANCE.checkcast(obj, as); + } +} diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeDecl.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeDecl.java new file mode 100644 index 0000000000..e095e73137 --- /dev/null +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeDecl.java @@ -0,0 +1,34 @@ +// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. +package org.aya.compiler.free.morphism.free; + +import kala.collection.immutable.ImmutableSeq; +import org.aya.compiler.free.data.FieldRef; +import org.aya.compiler.free.data.MethodRef; +import org.aya.syntax.compile.CompiledAya; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.constant.ClassDesc; + +public sealed interface FreeDecl { + record Clazz( + @Nullable CompiledAya metadata, + @NotNull ClassDesc owner, + @Nullable String nested, + @NotNull Class superclass, + @NotNull ImmutableSeq members + ) implements FreeDecl { + public @NotNull ClassDesc className() { + return nested != null ? owner.nested(nested) : owner; + } + } + + // Constructors also count as method, with method name "". + record Method( + @NotNull MethodRef signature, + @NotNull ImmutableSeq body + ) implements FreeDecl { } + + record ConstantField(@NotNull FieldRef signature, @NotNull FreeExpr init) implements FreeDecl { } +} diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeExpr.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeExpr.java new file mode 100644 index 0000000000..2f67fba4bb --- /dev/null +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeExpr.java @@ -0,0 +1,36 @@ +// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. +package org.aya.compiler.free.morphism.free; + +import kala.collection.immutable.ImmutableSeq; +import org.aya.compiler.free.FreeJavaExpr; +import org.aya.compiler.free.data.FieldRef; +import org.aya.compiler.free.data.MethodRef; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.constant.ClassDesc; + +public sealed interface FreeExpr extends FreeJavaExpr { + record New(@NotNull MethodRef conRef, @NotNull ImmutableSeq args) implements FreeExpr { } + record RefVariable(@NotNull FreeVariable var) implements FreeExpr { } + record RefCapture(int capture) implements FreeExpr { } + record Invoke(@NotNull MethodRef methodRef, @Nullable FreeExpr owner, + @NotNull ImmutableSeq args) implements FreeExpr { } + record RefField(@NotNull FieldRef fieldRef, @Nullable FreeExpr owner) implements FreeExpr { } + record RefEnum(@NotNull ClassDesc enumClass, @NotNull String enumName) implements FreeExpr { } + record Lambda(@NotNull ImmutableSeq captures, @NotNull MethodRef method, + @NotNull ImmutableSeq body) implements FreeExpr { } + + sealed interface Const extends FreeExpr { } + record Iconst(int value) implements Const { } + record Bconst(boolean value) implements Const { } + record Sconst(@NotNull String value) implements Const { } + record Null(@NotNull ClassDesc type) implements Const { } + enum This implements FreeExpr { INSTANCE } + + record Array(@NotNull ClassDesc type, int length, + @Nullable ImmutableSeq initializer) implements FreeExpr { } + record GetArray(@NotNull FreeExpr array, int index) implements FreeExpr { } + record CheckCast(@NotNull FreeExpr obj, @NotNull ClassDesc as) implements FreeExpr { } +} diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeExprBuilderImpl.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeExprBuilderImpl.java new file mode 100644 index 0000000000..6a7595448f --- /dev/null +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeExprBuilderImpl.java @@ -0,0 +1,92 @@ +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. +// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. +package org.aya.compiler.free.morphism.free; + +import kala.collection.immutable.ImmutableSeq; +import kala.collection.mutable.FreezableMutableList; +import org.aya.compiler.free.ArgumentProvider; +import org.aya.compiler.free.FreeCodeBuilder; +import org.aya.compiler.free.FreeExprBuilder; +import org.aya.compiler.free.FreeJavaExpr; +import org.aya.compiler.free.data.FieldRef; +import org.aya.compiler.free.data.MethodRef; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.constant.ClassDesc; +import java.util.function.BiConsumer; + +import static org.aya.compiler.free.morphism.free.FreeCodeBuilderImpl.assertFreeExpr; + +public final class FreeExprBuilderImpl implements FreeExprBuilder { + public static final @NotNull FreeExprBuilderImpl INSTANCE = new FreeExprBuilderImpl(); + + private FreeExprBuilderImpl() { } + + @Override + public @NotNull FreeJavaExpr mkNew(@NotNull MethodRef conRef, @NotNull ImmutableSeq args) { + return new FreeExpr.New(conRef, assertFreeExpr(args)); + } + + @Override + public @NotNull FreeJavaExpr invoke(@NotNull MethodRef method, @NotNull FreeJavaExpr owner, @NotNull ImmutableSeq args) { + return new FreeExpr.Invoke(method, assertFreeExpr(owner), assertFreeExpr(args)); + } + + @Override + public @NotNull FreeJavaExpr invoke(@NotNull MethodRef method, @NotNull ImmutableSeq args) { + return new FreeExpr.Invoke(method, null, assertFreeExpr(args)); + } + + @Override + public @NotNull FreeJavaExpr refField(@NotNull FieldRef field) { + return new FreeExpr.RefField(field, null); + } + + @Override + public @NotNull FreeJavaExpr refField(@NotNull FieldRef field, @NotNull FreeJavaExpr owner) { + return new FreeExpr.RefField(field, assertFreeExpr(owner)); + } + + @Override + public @NotNull FreeJavaExpr refEnum(@NotNull ClassDesc enumClass, @NotNull String enumName) { + return new FreeExpr.RefEnum(enumClass, enumName); + } + + @Override + public @NotNull FreeJavaExpr mkLambda( + @NotNull ImmutableSeq captures, + @NotNull MethodRef method, + @NotNull BiConsumer builder + ) { + var capturec = captures.size(); + var argc = method.paramTypes().size(); + // [0..captures.size()]th parameters are captures + // [captures.size()..]th parameters are lambda arguments + var lambdaBodyBuilder = new FreeCodeBuilderImpl(FreezableMutableList.create(), new VariablePool(), false, false); + builder.accept(new FreeArgumentProvider.Lambda(capturec, argc), lambdaBodyBuilder); + var lambdaBody = lambdaBodyBuilder.build(); + + return new FreeExpr.Lambda(assertFreeExpr(captures), method, lambdaBody); + } + @Override public @NotNull FreeJavaExpr iconst(int i) { return new FreeExpr.Iconst(i); } + @Override public @NotNull FreeJavaExpr iconst(boolean b) { return new FreeExpr.Bconst(b); } + @Override public @NotNull FreeJavaExpr aconst(@NotNull String value) { return new FreeExpr.Sconst(value); } + @Override public @NotNull FreeJavaExpr aconstNull(@NotNull ClassDesc type) { return new FreeExpr.Null(type); } + @Override public @NotNull FreeJavaExpr thisRef() { + return FreeExpr.This.INSTANCE; + } + + @Override + public @NotNull FreeJavaExpr mkArray(@NotNull ClassDesc type, int length, @Nullable ImmutableSeq initializer) { + return new FreeExpr.Array(type, length, initializer == null ? null : assertFreeExpr(initializer)); + } + + @Override public @NotNull FreeJavaExpr getArray(@NotNull FreeJavaExpr array, int index) { + return new FreeExpr.GetArray(assertFreeExpr(array), index); + } + + @Override public @NotNull FreeJavaExpr checkcast(@NotNull FreeJavaExpr obj, @NotNull ClassDesc as) { + return new FreeExpr.CheckCast(assertFreeExpr(obj), as); + } +} diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeJavaBuilderImpl.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeJavaBuilderImpl.java new file mode 100644 index 0000000000..b57d886eef --- /dev/null +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeJavaBuilderImpl.java @@ -0,0 +1,27 @@ +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. +// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. +package org.aya.compiler.free.morphism.free; + +import kala.collection.mutable.FreezableMutableList; +import org.aya.compiler.free.FreeClassBuilder; +import org.aya.compiler.free.FreeJavaBuilder; +import org.aya.syntax.compile.CompiledAya; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.constant.ClassDesc; +import java.util.function.Consumer; + +public enum FreeJavaBuilderImpl implements FreeJavaBuilder { + INSTANCE; + + @Override public @NotNull FreeDecl.Clazz buildClass( + @Nullable CompiledAya compiledAya, + @NotNull ClassDesc className, + @NotNull Class superclass, + @NotNull Consumer builder) { + var classBuilder = new FreeClassBuilderImpl(compiledAya, className, null, superclass, FreezableMutableList.create()); + builder.accept(classBuilder); + return classBuilder.build(); + } +} diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeRunner.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeRunner.java new file mode 100644 index 0000000000..f2fd29988a --- /dev/null +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeRunner.java @@ -0,0 +1,204 @@ +// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. +package org.aya.compiler.free.morphism.free; + +import kala.collection.immutable.ImmutableSeq; +import kala.collection.mutable.MutableMap; +import org.aya.compiler.free.*; +import org.aya.compiler.free.data.LocalVariable; +import org.aya.util.error.Panic; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; + +import java.util.Objects; +import java.util.function.Consumer; + +public final class FreeRunner { + private final @NotNull FreeJavaBuilder runner; + + // TODO: trying to use MutableArray, our VariablePool has a good property + private @UnknownNullability MutableMap binding; + + public FreeRunner(@NotNull FreeJavaBuilder runner) { + this.runner = runner; + this.binding = null; + } + + public Carrier runFree(@NotNull FreeDecl.Clazz free) { + return runner.buildClass(free.metadata(), free.owner(), free.superclass(), + cb -> runFree(cb, free.members())); + } + + private void runFree(@NotNull FreeClassBuilder builder, @NotNull ImmutableSeq frees) { + frees.forEach(it -> runFree(builder, it)); + } + + private void runFree(@NotNull FreeClassBuilder builder, @NotNull FreeDecl free) { + try (var _ = new SubscopeHandle(MutableMap.create())) { + switch (free) { + case FreeDecl.Clazz(var metadata, _, var nested, var superclass, var members) -> { + assert metadata != null && nested != null; + builder.buildNestedClass(metadata, nested, superclass, cb -> runFree(cb, members)); + } + case FreeDecl.ConstantField constantField -> + builder.buildConstantField(constantField.signature().returnType(), constantField.signature().name(), + eb -> runFree(null, eb, constantField.init())); + case FreeDecl.Method(var sig, var body) -> { + if (sig.isConstructor()) { + builder.buildConstructor(sig.paramTypes(), + (ap, cb) -> runFree(ap, cb, body)); + } else { + builder.buildMethod(sig.returnType(), sig.name(), sig.paramTypes(), + (ap, cb) -> runFree(ap, cb, body)); + } + } + } + } + } + + private @NotNull ImmutableSeq runFree(@Nullable ArgumentProvider ap, @NotNull FreeExprBuilder builder, @NotNull ImmutableSeq exprs) { + return exprs.map(it -> runFree(ap, builder, it)); + } + + private LocalVariable runFree(@Nullable ArgumentProvider ap, @NotNull FreeVariable var) { + return switch (var) { + case FreeVariable.Local local -> getVar(local.index()); + case FreeVariable.Arg arg -> { + if (ap == null) yield Panic.unreachable(); + yield ap.arg(arg.nth()); + } + }; + } + + private FreeJavaExpr runFree(@Nullable ArgumentProvider ap, @NotNull FreeExprBuilder builder, @NotNull FreeExpr expr) { + return switch (expr) { + case FreeExpr.RefVariable(var theVar) -> builder.refVar(runFree(ap, theVar)); + case FreeExpr.Array(var type, var length, var initializer) -> + builder.mkArray(type, length, initializer == null ? null : runFree(ap, builder, initializer)); + case FreeExpr.CheckCast(var obj, var as) -> builder.checkcast(runFree(ap, builder, obj), as); + case FreeExpr.Iconst(var i) -> builder.iconst(i); + case FreeExpr.Bconst(var b) -> builder.iconst(b); + case FreeExpr.Sconst(var s) -> builder.aconst(s); + case FreeExpr.Null(var ty) -> builder.aconstNull(ty); + case FreeExpr.GetArray(var arr, var idx) -> builder.getArray(runFree(ap, builder, arr), idx); + case FreeExpr.Invoke(var ref, var owner, var args) -> { + var argsExpr = runFree(ap, builder, args); + yield owner == null + ? builder.invoke(ref, argsExpr) + : builder.invoke(ref, runFree(ap, builder, owner), argsExpr); + } + case FreeExpr.Lambda(var lamCaptures, var methodRef, var body) -> { + var captureExprs = runFree(ap, builder, lamCaptures); + + // run captures outside of subscope! + // brand new scope! the lambda body lives in a difference place to the current scope + try (var _ = new SubscopeHandle(MutableMap.create())) { + yield builder.mkLambda(captureExprs, methodRef, (lap, cb) -> + runFree(lap, cb, body)); + } + } + case FreeExpr.New(var ref, var args) -> builder.mkNew(ref, runFree(ap, builder, args)); + case FreeExpr.RefEnum(var enumClass, var enumName) -> builder.refEnum(enumClass, enumName); + case FreeExpr.RefField(var fieldRef, var owner) -> owner != null + ? builder.refField(fieldRef, runFree(ap, builder, owner)) + : builder.refField(fieldRef); + case FreeExpr.This _ -> builder.thisRef(); + case FreeExpr.RefCapture(var idx) -> { + if (!(ap instanceof ArgumentProvider.Lambda lap)) { + yield Panic.unreachable(); + } + + yield lap.capture(idx); + } + }; + } + + private void runFree(@NotNull ArgumentProvider ap, @NotNull FreeCodeBuilder builder, @NotNull ImmutableSeq free) { + free.forEach(it -> runFree(ap, builder, it)); + } + + private void runFree(@NotNull ArgumentProvider ap, @NotNull FreeCodeBuilder builder, @NotNull FreeStmt free) { + switch (free) { + case FreeStmt.Break _ -> builder.breakOut(); + case FreeStmt.Breakable(var inner) -> builder.breakable(cb -> runFree(ap, cb, inner)); + case FreeStmt.DeclareVariable mkVar -> bindVar(mkVar.theVar().index(), builder.makeVar(mkVar.type(), null)); + case FreeStmt.Exec exec -> builder.exec(runFree(ap, builder, exec.expr())); + case FreeStmt.IfThenElse(var cond, var thenBody, var elseBody) -> { + Consumer thenBlock = cb -> { + try (var _ = subscoped()) { + runFree(ap, cb, thenBody); + } + }; + Consumer elseBlock = elseBody != null + ? cb -> { + try (var _ = subscoped()) { + runFree(ap, cb, elseBody); + } + } : null; + + switch (cond) { + case FreeStmt.Condition.IsFalse(var isFalse) -> builder.ifNotTrue(runFree(ap, isFalse), thenBlock, elseBlock); + case FreeStmt.Condition.IsTrue(var isTrue) -> builder.ifTrue(runFree(ap, isTrue), thenBlock, elseBlock); + case FreeStmt.Condition.IsInstanceOf(var lhs, var rhs, var as) -> { + var asTerm = as.get(); + assert asTerm != null; + builder.ifInstanceOf(runFree(ap, builder, lhs), rhs, (cb, var) -> { + try (var _ = subscoped()) { + bindVar(asTerm.index(), var); + runFree(ap, cb, thenBody); // prevent unnecessary subscoping + } + }, elseBlock); + } + case FreeStmt.Condition.IsIntEqual(var lhs, var rhs) -> + builder.ifIntEqual(runFree(ap, builder, lhs), rhs, thenBlock, elseBlock); + case FreeStmt.Condition.IsNull(var ref) -> builder.ifNull(runFree(ap, builder, ref), thenBlock, elseBlock); + case FreeStmt.Condition.IsRefEqual(var lhs, var rhs) -> + builder.ifRefEqual(runFree(ap, builder, lhs), runFree(ap, builder, rhs), thenBlock, elseBlock); + } + } + case FreeStmt.Return(var expr) -> builder.returnWith(runFree(ap, builder, expr)); + case FreeStmt.SetArray(var arr, var idx, var update) -> + builder.updateArray(runFree(ap, builder, arr), idx, runFree(ap, builder, update)); + case FreeStmt.SetVariable(var var, var update) -> + builder.updateVar(runFree(ap, var), runFree(ap, builder, update)); + case FreeStmt.Super(var params, var args) -> builder.invokeSuperCon(params, runFree(ap, builder, args)); + case FreeStmt.Switch(var elim, var cases, var branches, var defaultCase) -> + builder.switchCase(runFree(ap, elim), cases, (cb, kase) -> { + // slow impl, i am lazy + int idx = cases.indexOf(kase); + assert idx != -1; + var branch = branches.get(idx); + runFree(ap, cb, branch); + }, cb -> runFree(ap, cb, defaultCase)); + } + } + + private @NotNull LocalVariable getVar(int index) { + return Objects.requireNonNull(binding.getOrNull(index), "No substitution for local variable: " + index); + } + + private void bindVar(int index, @NotNull LocalVariable userVar) { + var exists = binding.put(index, userVar); + if (exists.isNotEmpty()) Panic.unreachable(); + } + + private class SubscopeHandle implements AutoCloseable { + private final @UnknownNullability MutableMap oldBinding = binding; + + public SubscopeHandle( + @NotNull MutableMap newScope + ) { + binding = newScope; + } + + @Override + public void close() { + binding = oldBinding; + } + } + + private @NotNull SubscopeHandle subscoped() { + return new SubscopeHandle(MutableMap.from(binding)); + } +} diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeStmt.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeStmt.java new file mode 100644 index 0000000000..e38283af91 --- /dev/null +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeStmt.java @@ -0,0 +1,42 @@ +// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. +package org.aya.compiler.free.morphism.free; + +import kala.collection.immutable.ImmutableSeq; +import kala.collection.immutable.primitive.ImmutableIntSeq; +import kala.value.MutableValue; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.constant.ClassDesc; + +public sealed interface FreeStmt { + record DeclareVariable(@NotNull ClassDesc type, @NotNull FreeVariable.Local theVar) implements FreeStmt { } + record Super(@NotNull ImmutableSeq superConParams, + @NotNull ImmutableSeq superConArgs) implements FreeStmt { } + record SetVariable(@NotNull FreeVariable var, @NotNull FreeExpr update) implements FreeStmt { } + record SetArray(@NotNull FreeExpr array, int index, @NotNull FreeExpr update) implements FreeStmt { } + + sealed interface Condition { + record IsFalse(@NotNull FreeVariable var) implements Condition { } + record IsTrue(@NotNull FreeVariable var) implements Condition { } + record IsInstanceOf(@NotNull FreeExpr lhs, @NotNull ClassDesc rhs, + @NotNull MutableValue asTerm) implements Condition { } + record IsIntEqual(@NotNull FreeExpr lhs, int rhs) implements Condition { } + record IsRefEqual(@NotNull FreeExpr lhs, @NotNull FreeExpr rhs) implements Condition { } + record IsNull(@NotNull FreeExpr ref) implements Condition { } + } + + record IfThenElse(@NotNull Condition cond, @NotNull ImmutableSeq thenBlock, + @Nullable ImmutableSeq elseBlock) implements FreeStmt { } + + record Breakable(@NotNull ImmutableSeq block) implements FreeStmt { } + enum Break implements FreeStmt { INSTANCE } + + record Exec(@NotNull FreeExpr expr) implements FreeStmt { } + record Switch(@NotNull FreeVariable elim, @NotNull ImmutableIntSeq cases, + @NotNull ImmutableSeq> branch, + @NotNull ImmutableSeq defaultCase) implements FreeStmt { } + + record Return(@NotNull FreeExpr expr) implements FreeStmt { } +} diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeVariable.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeVariable.java new file mode 100644 index 0000000000..d3486b759c --- /dev/null +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/FreeVariable.java @@ -0,0 +1,23 @@ +// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. +package org.aya.compiler.free.morphism.free; + +import org.aya.compiler.free.FreeJavaExpr; +import org.aya.compiler.free.data.LocalVariable; +import org.jetbrains.annotations.NotNull; + +public sealed interface FreeVariable extends LocalVariable { + record Local(int index) implements FreeVariable { + @Override + public @NotNull FreeJavaExpr ref() { + return new FreeExpr.RefVariable(this); + } + } + + record Arg(int nth) implements FreeVariable { + @Override + public @NotNull FreeJavaExpr ref() { + return new FreeExpr.RefVariable(this); + } + } +} diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/VariablePool.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/VariablePool.java new file mode 100644 index 0000000000..61b526bb99 --- /dev/null +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/free/VariablePool.java @@ -0,0 +1,29 @@ +// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. +package org.aya.compiler.free.morphism.free; + +import org.jetbrains.annotations.NotNull; + +/** + * A variable name counter. + * Note that we do not reserve place for arguments even though they are local variables in Java, + * because we need to keep the invocation of {@link org.aya.compiler.free.ArgumentProvider}, see {@link FreeVariable.Arg} + */ +public class VariablePool { + private int nextAvailable = 0; + + public VariablePool() { + } + + private VariablePool(int nextAvailable) { + this.nextAvailable = nextAvailable; + } + + public int acquire() { + return nextAvailable++; + } + + public @NotNull VariablePool copy() { + return new VariablePool(nextAvailable); + } +} diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceArgumentProvider.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceArgumentProvider.java similarity index 95% rename from jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceArgumentProvider.java rename to jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceArgumentProvider.java index d56fb4edf1..f121c5cafe 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceArgumentProvider.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceArgumentProvider.java @@ -1,6 +1,6 @@ // Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. // Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. -package org.aya.compiler.free.morphism; +package org.aya.compiler.free.morphism.source; import kala.collection.immutable.ImmutableSeq; import org.aya.compiler.free.ArgumentProvider; diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceClassBuilder.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceClassBuilder.java similarity index 79% rename from jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceClassBuilder.java rename to jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceClassBuilder.java index 3cf68f4eec..4e92d21d8f 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceClassBuilder.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceClassBuilder.java @@ -1,12 +1,12 @@ // Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. // Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. -package org.aya.compiler.free.morphism; +package org.aya.compiler.free.morphism.source; import kala.collection.immutable.ImmutableSeq; import org.aya.compiler.SourceBuilder; import org.aya.compiler.free.*; -import org.aya.compiler.free.data.FieldRef; import org.aya.compiler.free.data.MethodRef; +import org.aya.compiler.free.data.FieldRef; import org.aya.compiler.serializers.ExprializeUtil; import org.aya.syntax.compile.CompiledAya; import org.aya.syntax.core.repr.CodeShape; @@ -17,21 +17,19 @@ import java.util.function.Consumer; import java.util.function.Function; -import static org.aya.compiler.free.morphism.SourceFreeJavaBuilder.toClassName; -import static org.aya.compiler.free.morphism.SourceFreeJavaBuilder.toClassRef; +import static org.aya.compiler.free.morphism.source.SourceFreeJavaBuilder.toClassName; +import static org.aya.compiler.free.morphism.source.SourceFreeJavaBuilder.toClassRef; public record SourceClassBuilder( @NotNull SourceFreeJavaBuilder parent, @NotNull ClassDesc owner, @NotNull SourceBuilder sourceBuilder -) implements FreeClassBuilder, FreeJavaResolver { - @Override public @NotNull FreeJavaResolver resolver() { return this; } - +) implements FreeClassBuilder { private void buildMetadataRecord(@NotNull String name, @NotNull String value, boolean isFirst) { var prepend = isFirst ? "" : ", "; sourceBuilder.appendLine(prepend + name + " = " + value); } - @Override public void buildMetadata(@NotNull CompiledAya compiledAya) { + public void buildMetadata(@NotNull CompiledAya compiledAya) { sourceBuilder.appendLine("@" + toClassRef(FreeUtil.fromClass(CompiledAya.class)) + "("); sourceBuilder.runInside(() -> { buildMetadataRecord("module", SourceCodeBuilder.mkHalfArray( @@ -84,7 +82,7 @@ private void buildMethod( @NotNull BiConsumer builder ) { buildMethod(toClassRef(returnType), name, paramTypes, builder); - return new MethodRef.Default(this.owner, name, returnType, paramTypes, false); + return new MethodRef(this.owner, name, returnType, paramTypes, false); } @Override public @NotNull MethodRef buildConstructor( @@ -111,22 +109,7 @@ private void buildMethod( codeBuilder.appendExpr(initValue); sourceBuilder.append(";"); sourceBuilder.appendLine(); - - return new FieldRef.Default(this.owner, returnType, name); - } - - @Override public @NotNull MethodRef resolve( - @NotNull ClassDesc owner, - @NotNull String name, - @NotNull ClassDesc returnType, - @NotNull ImmutableSeq paramType, - boolean isInterface - ) { - return new MethodRef.Default(owner, name, returnType, paramType, isInterface); - } - @Override public @NotNull FieldRef - resolve(@NotNull ClassDesc owner, @NotNull String name, @NotNull ClassDesc returnType) { - return new FieldRef.Default(owner, returnType, name); + return new FieldRef(this.owner, returnType, name); } } diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceCodeBuilder.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceCodeBuilder.java similarity index 92% rename from jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceCodeBuilder.java rename to jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceCodeBuilder.java index 4d2df6822c..60e8d0b22c 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceCodeBuilder.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceCodeBuilder.java @@ -1,11 +1,14 @@ -// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. // Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. -package org.aya.compiler.free.morphism; +package org.aya.compiler.free.morphism.source; import kala.collection.immutable.ImmutableSeq; import kala.collection.immutable.primitive.ImmutableIntSeq; import org.aya.compiler.SourceBuilder; -import org.aya.compiler.free.*; +import org.aya.compiler.free.ArgumentProvider; +import org.aya.compiler.free.FreeCodeBuilder; +import org.aya.compiler.free.FreeJavaExpr; +import org.aya.compiler.free.FreeUtil; import org.aya.compiler.free.data.FieldRef; import org.aya.compiler.free.data.LocalVariable; import org.aya.compiler.free.data.MethodRef; @@ -19,7 +22,7 @@ import java.util.function.Consumer; import java.util.function.ObjIntConsumer; -import static org.aya.compiler.free.morphism.SourceFreeJavaBuilder.toClassRef; +import static org.aya.compiler.free.morphism.source.SourceFreeJavaBuilder.toClassRef; public record SourceCodeBuilder( @NotNull SourceClassBuilder parent, @@ -40,8 +43,6 @@ public void appendExpr(@NotNull FreeJavaExpr expr) { return ((SourceFreeJavaExpr.BlackBox) expr).expr(); } - @Override public @NotNull FreeJavaResolver resolver() { return parent; } - @Override public void invokeSuperCon(@NotNull ImmutableSeq superConParams, @NotNull ImmutableSeq superConArgs) { sourceBuilder.append("super("); @@ -92,20 +93,6 @@ private void buildUpdate(@NotNull String lhs, @NotNull FreeJavaExpr rhs) { sourceBuilder.appendLine(); } - @Override public void updateField(@NotNull FieldRef field, @NotNull FreeJavaExpr update) { - var fieldRef = toClassRef(field.owner()) + "." + field.name(); - buildUpdate(fieldRef, update); - } - - @Override - public void updateField(@NotNull FieldRef field, @NotNull FreeJavaExpr owner, @NotNull FreeJavaExpr update) { - appendExpr(owner); - sourceBuilder.append("." + field.name() + " = "); - appendExpr(update); - sourceBuilder.append(";"); - sourceBuilder.appendLine(); - } - private void buildIf( @NotNull Runnable condition, @NotNull Consumer thenBlock, @@ -250,10 +237,6 @@ private void buildIf( return mkNew(FreeUtil.fromClass(className), args); } - @Override public @NotNull FreeJavaExpr refVar(@NotNull LocalVariable name) { - return name.ref(); - } - @Override public @NotNull SourceFreeJavaExpr.Cont invoke(@NotNull MethodRef method, @NotNull FreeJavaExpr owner, @NotNull ImmutableSeq args) { return () -> { diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceFreeJavaBuilder.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceFreeJavaBuilder.java similarity index 98% rename from jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceFreeJavaBuilder.java rename to jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceFreeJavaBuilder.java index 0ac14d5dc4..954f3167bf 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceFreeJavaBuilder.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceFreeJavaBuilder.java @@ -1,6 +1,6 @@ // Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. // Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. -package org.aya.compiler.free.morphism; +package org.aya.compiler.free.morphism.source; import kala.collection.Seq; import org.aya.compiler.SourceBuilder; diff --git a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceFreeJavaExpr.java b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceFreeJavaExpr.java similarity index 93% rename from jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceFreeJavaExpr.java rename to jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceFreeJavaExpr.java index 7b89418b42..088d85869d 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/free/morphism/SourceFreeJavaExpr.java +++ b/jit-compiler/src/main/java/org/aya/compiler/free/morphism/source/SourceFreeJavaExpr.java @@ -1,6 +1,6 @@ // Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. // Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. -package org.aya.compiler.free.morphism; +package org.aya.compiler.free.morphism.source; import org.aya.compiler.free.FreeJavaExpr; import org.aya.compiler.free.data.LocalVariable; diff --git a/jit-compiler/src/main/java/org/aya/compiler/serializers/AbstractExprializer.java b/jit-compiler/src/main/java/org/aya/compiler/serializers/AbstractExprializer.java index 1242431a82..058a77cc05 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/serializers/AbstractExprializer.java +++ b/jit-compiler/src/main/java/org/aya/compiler/serializers/AbstractExprializer.java @@ -3,10 +3,7 @@ package org.aya.compiler.serializers; import kala.collection.immutable.ImmutableSeq; -import org.aya.compiler.free.Constants; -import org.aya.compiler.free.FreeExprBuilder; -import org.aya.compiler.free.FreeJavaExpr; -import org.aya.compiler.free.FreeUtil; +import org.aya.compiler.free.*; import org.aya.compiler.free.data.MethodRef; import org.aya.syntax.core.def.AnyDef; import org.aya.syntax.core.def.TyckDef; @@ -64,7 +61,7 @@ public abstract class AbstractExprializer { } public static @NotNull FreeJavaExpr getInstance(@NotNull FreeExprBuilder builder, @NotNull ClassDesc desc) { - return builder.refField(builder.resolver().resolve(desc, AyaSerializer.STATIC_FIELD_INSTANCE, desc)); + return builder.refField(FreeJavaResolver.resolve(desc, AyaSerializer.STATIC_FIELD_INSTANCE, desc)); } public static @NotNull FreeJavaExpr getInstance(@NotNull FreeExprBuilder builder, @NotNull AnyDef def) { @@ -72,14 +69,14 @@ public abstract class AbstractExprializer { } public static @NotNull FreeJavaExpr getRef(@NotNull FreeExprBuilder builder, @NotNull CallKind callType, @NotNull FreeJavaExpr call) { - return builder.invoke(builder.resolver().resolve( + return builder.invoke(FreeJavaResolver.resolve( callType.callType, AyaSerializer.FIELD_INSTANCE, callType.refType, ImmutableSeq.empty(), true ), call, ImmutableSeq.empty()); } public final @NotNull FreeJavaExpr getCallInstance(@NotNull CallKind callType, @NotNull AnyDef def) { - return builder.refField(builder.resolver().resolve( + return builder.refField(FreeJavaResolver.resolve( NameSerializer.getClassDesc(def), AyaSerializer.FIELD_EMPTYCALL, callType.callType) diff --git a/jit-compiler/src/main/java/org/aya/compiler/serializers/FnSerializer.java b/jit-compiler/src/main/java/org/aya/compiler/serializers/FnSerializer.java index 694988d72d..2d6aed76b4 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/serializers/FnSerializer.java +++ b/jit-compiler/src/main/java/org/aya/compiler/serializers/FnSerializer.java @@ -8,8 +8,8 @@ import org.aya.compiler.free.FreeClassBuilder; import org.aya.compiler.free.FreeCodeBuilder; import org.aya.compiler.free.FreeJavaExpr; -import org.aya.compiler.free.data.LocalVariable; import org.aya.compiler.free.data.MethodRef; +import org.aya.compiler.free.data.LocalVariable; import org.aya.generic.Modifier; import org.aya.primitive.ShapeFactory; import org.aya.syntax.compile.JitFn; @@ -33,7 +33,7 @@ public FnSerializer(@NotNull ShapeFactory shapeFactory, ModuleSerializer.@NotNul } public static @NotNull MethodRef resolveInvoke(@NotNull ClassDesc owner, int argc) { - return new MethodRef.Default( + return new MethodRef( owner, "invoke", Constants.CD_Term, ImmutableSeq.of(Constants.CD_Thunk) .appendedAll(ImmutableSeq.fill(argc, Constants.CD_Term)), false ); diff --git a/jit-compiler/src/main/java/org/aya/compiler/serializers/MatchySerializer.java b/jit-compiler/src/main/java/org/aya/compiler/serializers/MatchySerializer.java index 574eb6951a..5ae6460404 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/serializers/MatchySerializer.java +++ b/jit-compiler/src/main/java/org/aya/compiler/serializers/MatchySerializer.java @@ -7,12 +7,11 @@ import org.aya.compiler.free.Constants; import org.aya.compiler.free.FreeClassBuilder; import org.aya.compiler.free.FreeCodeBuilder; -import org.aya.compiler.free.data.LocalVariable; import org.aya.compiler.free.data.MethodRef; +import org.aya.compiler.free.data.LocalVariable; import org.aya.syntax.compile.CompiledAya; import org.aya.syntax.compile.JitMatchy; import org.aya.syntax.core.def.Matchy; -import org.aya.syntax.core.def.MatchyLike; import org.aya.syntax.core.repr.CodeShape; import org.aya.syntax.core.term.Term; import org.aya.syntax.core.term.call.MatchCall; @@ -42,7 +41,7 @@ public MatchySerializer(ModuleSerializer.@NotNull MatchyRecorder recorder) { } public static @NotNull MethodRef resolveInvoke(@NotNull ClassDesc owner, int capturec, int argc) { - return new MethodRef.Default( + return new MethodRef( owner, "invoke", Constants.CD_Term, ImmutableSeq.fill(capturec + argc, Constants.CD_Term), false diff --git a/jit-compiler/src/main/java/org/aya/compiler/serializers/ModuleSerializer.java b/jit-compiler/src/main/java/org/aya/compiler/serializers/ModuleSerializer.java index d1096270e5..1ff00b378f 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/serializers/ModuleSerializer.java +++ b/jit-compiler/src/main/java/org/aya/compiler/serializers/ModuleSerializer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. // Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. package org.aya.compiler.serializers; @@ -6,6 +6,9 @@ import kala.collection.mutable.MutableList; import org.aya.compiler.free.FreeClassBuilder; import org.aya.compiler.free.FreeJavaBuilder; +import org.aya.compiler.free.morphism.free.FreeJavaBuilderImpl; +import org.aya.compiler.free.morphism.free.FreeRunner; +import org.aya.compiler.free.morphism.source.SourceFreeJavaBuilder; import org.aya.compiler.serializers.MatchySerializer.MatchyData; import org.aya.primitive.ShapeFactory; import org.aya.syntax.compile.JitUnit; @@ -13,6 +16,7 @@ import org.aya.syntax.core.repr.CodeShape; import org.aya.syntax.ref.QPath; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; import java.lang.constant.ClassDesc; @@ -21,7 +25,7 @@ /** * Serializing a module, note that it may not a file module, so we need not to make importing. */ -public final class ModuleSerializer { +public final class ModuleSerializer { /** Input to the module serializer. */ public record ModuleResult( @NotNull QPath name, @@ -74,7 +78,13 @@ private void doSerialize(@NotNull FreeClassBuilder builder, @NotNull TyckDef uni } } - public Carrier serialize(@NotNull FreeJavaBuilder builder, ModuleResult unit) { + public String serializeWithBestBuilder(ModuleResult unit) { + var freeJava = serialize(FreeJavaBuilderImpl.INSTANCE, unit); + return new FreeRunner<>(SourceFreeJavaBuilder.create()).runFree(freeJava); + } + + @VisibleForTesting + public Carrier serialize(@NotNull FreeJavaBuilder builder, ModuleResult unit) { var desc = ClassDesc.of(getReference(unit.name, null, NameSerializer.NameType.ClassName)); var metadata = new ClassTargetSerializer.CompiledAyaImpl(unit.name, "", -1, -1, new CodeShape.GlobalId[0]); diff --git a/jit-compiler/src/main/java/org/aya/compiler/serializers/PatternSerializer.java b/jit-compiler/src/main/java/org/aya/compiler/serializers/PatternSerializer.java index d09e483dc0..e84b12b215 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/serializers/PatternSerializer.java +++ b/jit-compiler/src/main/java/org/aya/compiler/serializers/PatternSerializer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. // Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. package org.aya.compiler.serializers; @@ -96,7 +96,6 @@ private void doSerialize( onMatchSucc.accept(builder); } - // TODO: match IntegerTerm / ListTerm first case Pat.Con con -> builder.ifInstanceOf(term, FreeUtil.fromClass(ConCallLike.class), (builder1, conTerm) -> builder1.ifRefEqual( AbstractExprializer.getRef(builder1, CallKind.Con, conTerm.ref()), diff --git a/jit-compiler/src/main/java/org/aya/compiler/serializers/TermExprializer.java b/jit-compiler/src/main/java/org/aya/compiler/serializers/TermExprializer.java index b1f3fb5071..f71b6f6b0b 100644 --- a/jit-compiler/src/main/java/org/aya/compiler/serializers/TermExprializer.java +++ b/jit-compiler/src/main/java/org/aya/compiler/serializers/TermExprializer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. // Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. package org.aya.compiler.serializers; @@ -6,10 +6,8 @@ import kala.collection.mutable.MutableLinkedHashMap; import kala.tuple.Tuple; import kala.tuple.Tuple2; -import org.aya.compiler.free.ArgumentProvider; -import org.aya.compiler.free.Constants; -import org.aya.compiler.free.FreeExprBuilder; -import org.aya.compiler.free.FreeJavaExpr; +import org.aya.compiler.free.*; +import org.aya.compiler.free.data.FieldRef; import org.aya.compiler.free.data.MethodRef; import org.aya.compiler.serializers.ModuleSerializer.MatchyRecorder; import org.aya.generic.stmt.Shaped; @@ -28,22 +26,19 @@ import java.lang.constant.ClassDesc; import java.util.function.BiFunction; -import java.util.function.Function; import java.util.function.Supplier; /** * Build the "constructor form" of {@link Term}, but in Java. */ public final class TermExprializer extends AbstractExprializer { - /** - * Terms that should be instantiated - */ + public static final @NotNull FieldRef TYPE0_FIELD = FreeJavaResolver.resolve(SortTerm.class, "Type0"); + public static final @NotNull FieldRef ISET_FIELD = FreeJavaResolver.resolve(SortTerm.class, "ISet"); + /// Terms that should be instantiated private final @NotNull ImmutableSeq instantiates; private final @NotNull MutableLinkedHashMap binds; - /** - * Whether allow LocalTerm, false in default (in order to report unexpected LocalTerm) - */ + /// Whether allow {@link LocalTerm}, false in default (in order to report unexpected LocalTerm) private final boolean allowLocalTerm; private final @NotNull MatchyRecorder recorder; @@ -191,11 +186,8 @@ case FnCall(var ref, var ulift, var args) -> buildFnInvoke( )); yield builder.invoke(Constants.RULEREDUCER_MAKE, onStuck, ImmutableSeq.empty()); } - // TODO: make the resolving const - case SortTerm sort when sort.equals(SortTerm.Type0) -> - builder.refField(builder.resolver().resolve(SortTerm.class, "Type0")); - case SortTerm sort when sort.equals(SortTerm.ISet) -> - builder.refField(builder.resolver().resolve(SortTerm.class, "ISet")); + case SortTerm sort when sort.equals(SortTerm.Type0) -> builder.refField(TYPE0_FIELD); + case SortTerm sort when sort.equals(SortTerm.ISet) -> builder.refField(ISET_FIELD); case SortTerm(var kind, var ulift) -> builder.mkNew(SortTerm.class, ImmutableSeq.of(builder.refEnum(kind), builder.iconst(ulift))); case DepTypeTerm(var kind, var param, var body) -> builder.mkNew(DepTypeTerm.class, ImmutableSeq.of( @@ -274,11 +266,6 @@ yield buildMatchyInvoke(NameSerializer.getClassDesc(ref), }); } - // TODO: unify with makeClosure - private @NotNull FreeJavaExpr makeThunk(@NotNull Function cont) { - return makeLambda(Constants.THUNK, (_, te) -> cont.apply(te)); - } - private @NotNull FreeJavaExpr makeClosure(@NotNull BiFunction cont) { return makeLambda(Constants.CLOSURE, (ap, te) -> cont.apply(te, ap.arg(0).ref())); } diff --git a/jit-compiler/src/test/java/CompileTest.java b/jit-compiler/src/test/java/CompileTest.java index f73eef4ba7..44eaceb566 100644 --- a/jit-compiler/src/test/java/CompileTest.java +++ b/jit-compiler/src/test/java/CompileTest.java @@ -2,9 +2,9 @@ // Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. import kala.collection.immutable.ImmutableSeq; -import org.aya.compiler.free.morphism.SourceClassBuilder; -import org.aya.compiler.free.morphism.SourceCodeBuilder; -import org.aya.compiler.free.morphism.SourceFreeJavaBuilder; +import org.aya.compiler.free.morphism.source.SourceClassBuilder; +import org.aya.compiler.free.morphism.source.SourceCodeBuilder; +import org.aya.compiler.free.morphism.source.SourceFreeJavaBuilder; import org.aya.compiler.serializers.ModuleSerializer; import org.aya.compiler.serializers.TermExprializer; import org.aya.prettier.AyaPrettierOptions; @@ -103,7 +103,7 @@ public record TyckResult(@NotNull ImmutableSeq defs, @NotNull ResolveIn public static final ThrowingReporter REPORTER = new ThrowingReporter(AyaPrettierOptions.pretty()); public static @NotNull String serializeFrom(@NotNull TyckResult result) { - return new ModuleSerializer(result.info.shapeFactory()) + return new ModuleSerializer(result.info.shapeFactory()) .serialize(SourceFreeJavaBuilder.create(), new ModuleSerializer.ModuleResult( DumbModuleLoader.DUMB_MODULE_NAME, result.defs.filterIsInstance(TopLevelDef.class))); } diff --git a/jit-compiler/src/test/java/CompileTester.java b/jit-compiler/src/test/java/CompileTester.java index 92676b4888..4b28e32a9b 100644 --- a/jit-compiler/src/test/java/CompileTester.java +++ b/jit-compiler/src/test/java/CompileTester.java @@ -19,14 +19,15 @@ import java.util.List; public class CompileTester { + public static Path GEN_DIR = Paths.get("build/tmp/testGenerated"); + private final Path baka; public final ClassLoader cl; public CompileTester(@NotNull String code) throws IOException { - var root = Paths.get("build/tmp/testGenerated"); - var genDir = root.resolve(AyaSerializer.PACKAGE_BASE); + var genDir = GEN_DIR.resolve(AyaSerializer.PACKAGE_BASE); FileUtil.writeString(baka = genDir.resolve("_baka.java"), code); - cl = new URLClassLoader(new URL[]{root.toUri().toURL()}); + cl = new URLClassLoader(new URL[]{GEN_DIR.toUri().toURL()}); } public void compile() { diff --git a/jit-compiler/src/test/java/FreeTest.java b/jit-compiler/src/test/java/FreeTest.java new file mode 100644 index 0000000000..dc95e9d5b9 --- /dev/null +++ b/jit-compiler/src/test/java/FreeTest.java @@ -0,0 +1,42 @@ +// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang. +// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file. + +import org.aya.compiler.free.morphism.free.FreeJavaBuilderImpl; +import org.aya.compiler.free.morphism.free.FreeRunner; +import org.aya.compiler.free.morphism.source.SourceFreeJavaBuilder; +import org.aya.compiler.serializers.ModuleSerializer; +import org.aya.resolve.module.DumbModuleLoader; +import org.aya.syntax.core.def.TopLevelDef; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Files; + +public class FreeTest { + public static ModuleSerializer serializer = null; + public static ModuleSerializer.ModuleResult moduleResult = null; + + @BeforeAll + public static void init() { + var result = CompileTest.tyck(""" + open inductive Nat | zero | suc Nat + def plus Nat Nat : Nat + | 0, b => b + | suc a, b => suc (plus a b) + """); + + serializer = new ModuleSerializer(result.info().shapeFactory()); + moduleResult = new ModuleSerializer.ModuleResult( + DumbModuleLoader.DUMB_MODULE_NAME, result.defs().filterIsInstance(TopLevelDef.class) + ); + } + + @Test public void free2source() throws IOException { + var free = serializer.serialize(FreeJavaBuilderImpl.INSTANCE, moduleResult); + var result = new FreeRunner<>(SourceFreeJavaBuilder.create()) + .runFree(free); + + Files.writeString(CompileTester.GEN_DIR.resolve("freeJavaBaka.java"), result); + } +}