Skip to content

Commit 14efc74

Browse files
authored
Merge pull request #24 from bluelhf/feature/compiler-resources
Compiler Resources
2 parents fe5ca82 + 8d424d1 commit 14efc74

20 files changed

+322
-98
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>org.byteskript</groupId>
88
<artifactId>byteskript</artifactId>
9-
<version>1.0.40</version>
9+
<version>1.0.41</version>
1010
<name>ByteSkript</name>
1111
<description>A compiled JVM implementation of the Skript language.</description>
1212

src/main/java/org/byteskript/skript/api/Library.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import mx.kenzie.autodoc.api.note.Description;
1010
import mx.kenzie.foundation.Type;
1111
import mx.kenzie.foundation.compiler.State;
12-
import mx.kenzie.foundation.language.PostCompileClass;
12+
import org.byteskript.skript.api.resource.Resource;
1313
import org.byteskript.skript.compiler.Context;
1414
import org.byteskript.skript.runtime.type.Converter;
1515
import org.byteskript.skript.runtime.type.OperatorFunction;
@@ -61,7 +61,7 @@ public interface Library {
6161
Type[] getTypes();
6262

6363
@Description("Runtime dependencies to be included in complete archive.")
64-
Collection<PostCompileClass> getRuntime();
64+
Collection<Resource> getRuntime();
6565

6666
@Description("""
6767
Generates documentation for all available syntax to be exported to a processor.

src/main/java/org/byteskript/skript/api/ModifiableLibrary.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import mx.kenzie.autodoc.api.note.Ignore;
1111
import mx.kenzie.foundation.Type;
1212
import mx.kenzie.foundation.compiler.State;
13-
import mx.kenzie.foundation.language.PostCompileClass;
13+
import org.byteskript.skript.api.resource.Resource;
1414
import org.byteskript.skript.api.syntax.EventHolder;
1515
import org.byteskript.skript.compiler.CompileState;
1616
import org.byteskript.skript.compiler.Context;
@@ -178,7 +178,7 @@ public Type[] getTypes() {
178178

179179
@Override
180180
@Ignore
181-
public Collection<PostCompileClass> getRuntime() {
181+
public Collection<Resource> getRuntime() {
182182
return Collections.emptyList();
183183
}
184184

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.byteskript.skript.api.resource;
2+
3+
import mx.kenzie.foundation.language.PostCompileClass;
4+
5+
import java.io.*;
6+
7+
/**
8+
* A resource which represents a compiled class file.
9+
* @param source The source class file.
10+
* */
11+
public record ClassResource(PostCompileClass source) implements Resource {
12+
@Override
13+
public InputStream open() {
14+
return new ByteArrayInputStream(source.code());
15+
}
16+
17+
@Override
18+
public String getEntryName() {
19+
return source.internalName() + ".class";
20+
}
21+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package org.byteskript.skript.api.resource;
2+
3+
import mx.kenzie.foundation.language.PostCompileClass;
4+
5+
import java.io.*;
6+
import java.nio.charset.Charset;
7+
import java.util.jar.JarEntry;
8+
import java.util.zip.ZipOutputStream;
9+
10+
/**
11+
* Represents a resource, such as a file, that may be copied to a ZIP archive.
12+
* */
13+
public interface Resource {
14+
/**
15+
* Opens the source of this resource for reading.
16+
* @return A new input stream from which bytes are read when the resource is being copied.
17+
* @throws IOException If an I/O error occurs when opening the stream.
18+
* */
19+
InputStream open() throws IOException;
20+
21+
/**
22+
* The name that the resource should have in the final ZIP archive.
23+
* @return A text with the name of the resource.
24+
* */
25+
String getEntryName();
26+
27+
/**
28+
* Writes a resource to a ZIP output stream, closing any entries that were previously being written.
29+
* The resource's stream is opened, read, and closed.
30+
* @param outputStream The ZIP output stream to write to
31+
* @param resource The resource to copy
32+
* @throws IOException If an I/O error occurs when opening the stream or writing to the ZIP output stream.
33+
* */
34+
static void write(final ZipOutputStream outputStream, final Resource resource) throws IOException {
35+
try (final InputStream inputStream = resource.open()) {
36+
outputStream.putNextEntry(new JarEntry(resource.getEntryName()));
37+
inputStream.transferTo(outputStream);
38+
outputStream.closeEntry();
39+
}
40+
}
41+
42+
/**
43+
* Creates a new resource containing some bytes. The resource will maintain a reference to the byte array, so
44+
* modifications to the byte array between calls to {@link Resource#write(ZipOutputStream, Resource)} will result
45+
* in different contents being written.
46+
* @param name The name that the resource should have, were it to be added to a ZIP archive
47+
* @param bytes The byte contents of the resource.
48+
* @return A resource containing the given bytes as its contents.
49+
* */
50+
static Resource ofBytes(final String name, final byte[] bytes) {
51+
return new Resource() {
52+
@Override
53+
public InputStream open() {
54+
return new ByteArrayInputStream(bytes);
55+
}
56+
57+
@Override
58+
public String getEntryName() {
59+
return name;
60+
}
61+
};
62+
}
63+
64+
/**
65+
* Creates a new resource with the given ZIP entry name, containing the given text encoded using the JVM default character set.
66+
* Equivalent to {@link Resource#ofString(String, String, Charset)} with {@link Charset#defaultCharset()}.
67+
* @param name The name that the resource should have, were it to be added to a ZIP archive
68+
* @param text The text that the resource should contain
69+
* @return The newly created resource.
70+
* */
71+
static Resource ofString(final String name, final String text) {
72+
return ofString(name, text, Charset.defaultCharset());
73+
}
74+
75+
/**
76+
* Creates a new resource containing the given text encoded using the given character set.
77+
* @param name The name that the resource should have, were it to be added to a ZIP archive
78+
* @param text The text that the resource should contain
79+
* @param charset The character set that should be used to encode the text
80+
* @return The newly created resource.
81+
* */
82+
static Resource ofString(final String name, final String text, final Charset charset) {
83+
return ofBytes(name, text.getBytes(charset));
84+
}
85+
86+
/**
87+
* Creates a new resource with the internal file name of the compiled class (<code>com/example/Main.class</code>) containing
88+
* the compiled code of the class.
89+
* @param compiledClass The compiled class to use as the source of the resource.
90+
* @return The newly created resource.
91+
* */
92+
static ClassResource ofCompiledClass(final PostCompileClass compiledClass) {
93+
return new ClassResource(compiledClass);
94+
}
95+
96+
/**
97+
* Creates a new resource that will contain the contents of the given {@link File}. The file is accessed lazily, i.e.,
98+
* if the file is deleted before the resource is written to an archive, the resource will no longer be readable. To
99+
* load a file in memory and create a resource from its bytes, use {@link Resource#ofImmediateFile}
100+
* @param name The name that the resource should have, were it to be added to a ZIP archive
101+
* @param file The file that will act as the source for the contents of the resource
102+
* @return The newly created resource.
103+
* */
104+
static Resource ofFile(final String name, final File file) {
105+
return new Resource() {
106+
@Override
107+
public InputStream open() throws IOException {
108+
return new FileInputStream(file);
109+
}
110+
111+
@Override
112+
public String getEntryName() {
113+
return name;
114+
}
115+
};
116+
}
117+
118+
/**
119+
* Immediately reads all bytes in the given input stream and creates a new resource containing the read bytes.
120+
* This stores the entire stream contents in memory, so the stream may be closed and the resource
121+
* will remain readable. Equivalent to {@link Resource#ofBytes(String, byte[])} with {@link InputStream#readAllBytes()}.
122+
* @param name The name that the resource should have, were it to be added to a ZIP archive
123+
* @param stream The stream that will be read immediately.
124+
* @return The newly created resource with the contents of the stream.
125+
* */
126+
static Resource ofImmediate(final String name, final InputStream stream) throws IOException {
127+
return Resource.ofBytes(name, stream.readAllBytes());
128+
}
129+
130+
/**
131+
* Immediately reads all bytes in the given file and creates a new resource containing the read bytes.
132+
* This stores the entire file in memory, so the file may be deleted and the resource will remain readable.
133+
* Equivalent to {@link Resource#ofImmediate(String, InputStream)} with {@link FileInputStream}.
134+
* @param name The name that the resource should have, were it to be added to a ZIP archive
135+
* @param file The file that will be read immediately.
136+
* @return The newly created resource with the contents of the file.
137+
* */
138+
static Resource ofImmediateFile(final String name, final File file) throws IOException {
139+
return Resource.ofImmediate(name, new FileInputStream(file));
140+
}
141+
}

src/main/java/org/byteskript/skript/app/ByteSkriptApp.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
package org.byteskript.skript.app;
88

9-
import mx.kenzie.foundation.language.PostCompileClass;
9+
import org.byteskript.skript.api.resource.Resource;
1010
import org.byteskript.skript.runtime.Skript;
1111
import org.byteskript.skript.runtime.internal.ExtractedSyntaxCalls;
1212

@@ -55,10 +55,8 @@ public static void main(String... args) throws Throwable {
5555
final File file = new File(name);
5656
registerLibraries(SKRIPT);
5757
try (final InputStream stream = new FileInputStream(file)) {
58-
final PostCompileClass[] classes = SKRIPT.compileComplexScript(stream, "skript." + file.getName());
59-
for (final PostCompileClass type : classes) {
60-
SKRIPT.loadScript(type);
61-
}
58+
final Resource[] classes = SKRIPT.compileComplexScript(stream, "skript." + file.getName());
59+
SKRIPT.loadScript(classes);
6260
}
6361
new SimpleThrottleController(SKRIPT).run();
6462
} else if (args[0].equalsIgnoreCase("jar")) {
@@ -79,10 +77,8 @@ public static void main(String... args) throws Throwable {
7977
final File file = new File(name);
8078
registerLibraries(SKRIPT);
8179
try (final InputStream stream = new FileInputStream(file)) {
82-
final PostCompileClass[] classes = SKRIPT.compileComplexScript(stream, "skript." + file.getName());
83-
for (final PostCompileClass type : classes) {
84-
SKRIPT.loadScript(type);
85-
}
80+
final Resource[] classes = SKRIPT.compileComplexScript(stream, "skript." + file.getName());
81+
SKRIPT.loadScript(classes);
8682
}
8783
new SimpleThrottleController(SKRIPT).run();
8884
} else if (args[0].equalsIgnoreCase("debug")) {

src/main/java/org/byteskript/skript/app/ScriptJarBuilder.java

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,13 @@
88

99
import mx.kenzie.foundation.assembler.JarBuilder;
1010
import mx.kenzie.foundation.assembler.Manifest;
11-
import mx.kenzie.foundation.language.PostCompileClass;
1211
import org.byteskript.skript.api.Library;
12+
import org.byteskript.skript.api.resource.Resource;
1313
import org.byteskript.skript.runtime.Skript;
1414

1515
import java.io.File;
16-
import java.io.FileInputStream;
1716
import java.io.IOException;
18-
import java.util.ArrayList;
19-
import java.util.List;
17+
import java.util.*;
2018

2119
import static org.byteskript.skript.runtime.internal.ConsoleColour.*;
2220

@@ -26,30 +24,29 @@ public final class ScriptJarBuilder extends SkriptApp {
2624
public static void main(String... args) throws IOException {
2725
registerLibraries(SKRIPT);
2826
final String name = args.length > 0 ? args[0] : "CompiledScripts";
29-
final PostCompileClass[] scripts = SKRIPT.compileScripts(SOURCE);
27+
final Resource[] scripts = SKRIPT.compileScripts(SOURCE);
3028
final File jar = new File(OUTPUT, name + ".jar");
3129
compileResource(jar, scripts);
3230
System.out.println(RESET + "Available scripts have been compiled to " + CYAN + CYAN_UNDERLINED + "skripts/" + jar.getName() + RESET);
3331
}
3432

35-
static void compileResource(File jar, PostCompileClass... classes) throws IOException {
33+
static void compileResource(File jar, Resource... compiledResources) throws IOException {
3634
if (!jar.exists()) jar.createNewFile();
37-
final List<File> resources = getFiles(new ArrayList<>(), RESOURCES.toPath());
38-
final List<PostCompileClass> runtime = new ArrayList<>();
35+
final List<Resource> runtime = new ArrayList<>(Arrays.asList(compiledResources));
3936
scrapeRuntimeResources(runtime);
37+
for (final File file : getFiles(new ArrayList<>(), RESOURCES.toPath())) {
38+
runtime.add(Resource.ofFile(file.getName(), file));
39+
}
4040
try (final JarBuilder builder = new JarBuilder(jar)) {
41-
builder.write(runtime.toArray(new PostCompileClass[0]));
42-
builder.write(classes);
43-
for (final File resource : resources)
44-
try (final FileInputStream stream = new FileInputStream(resource)) {
45-
builder.write(resource.getName(), stream);
46-
}
41+
for (final Resource resource : runtime) {
42+
builder.write(resource.getEntryName(), resource.open());
43+
}
4744
final String version = ScriptJarBuilder.class.getPackage().getImplementationVersion();
4845
builder.manifest(new Manifest(ScriptRunner.class.getName(), "Skript Compiler " + version, "Skript Jar Builder"));
4946
}
5047
}
5148

52-
static void scrapeRuntimeResources(final List<PostCompileClass> runtime) {
49+
static void scrapeRuntimeResources(final List<Resource> runtime) {
5350
for (final Library library : SKRIPT.getLoadedLibraries()) {
5451
runtime.addAll(library.getRuntime());
5552
}

src/main/java/org/byteskript/skript/compiler/Context.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import mx.kenzie.foundation.*;
1010
import mx.kenzie.foundation.compiler.State;
1111
import org.byteskript.skript.api.*;
12+
import org.byteskript.skript.api.resource.Resource;
1213
import org.byteskript.skript.api.syntax.Section;
1314
import org.byteskript.skript.compiler.structure.*;
1415

@@ -62,6 +63,8 @@ public void setStoredVariableName(String storedVariableName) {
6263
public abstract ClassBuilder getSuppressedBuilder(Type type);
6364

6465
public abstract ClassBuilder getSuppressedBuilder();
66+
67+
public abstract void addResource(final Resource resource);
6568

6669
public abstract MethodBuilder getMethod();
6770

src/main/java/org/byteskript/skript/compiler/DebugSkriptCompiler.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
package org.byteskript.skript.compiler;
88

99
import mx.kenzie.foundation.Type;
10-
import mx.kenzie.foundation.language.PostCompileClass;
1110
import org.byteskript.skript.api.Library;
11+
import org.byteskript.skript.api.resource.Resource;
1212

1313
import java.io.InputStream;
1414
import java.io.OutputStream;
@@ -38,15 +38,15 @@ protected void compileLine(String line, FileContext context) {
3838
}
3939

4040
@Override
41-
public PostCompileClass[] compile(InputStream stream, Type path) {
41+
public Resource[] compile(InputStream stream, Type path) {
4242
this.stream.print("\n");
4343
this.stream.print("--" + path.internalName());
4444
this.stream.print("\n\n");
4545
return super.compile(stream, path);
4646
}
4747

4848
@Override
49-
public PostCompileClass[] compile(String source, Type path) {
49+
public Resource[] compile(String source, Type path) {
5050
this.stream.print("\n");
5151
this.stream.print("--" + path.internalName());
5252
this.stream.print("\n\n");

0 commit comments

Comments
 (0)