A lot to unwrap

- Make ShaderSources return a LoadResult
- Refactor SourceFile loading to do all parsing outside the ctor
- Don't immediately swallow import errors, instead forward them
- Change Span to reference SourceLines instead of SourceFile
- Still WIP, but functional at this stage
This commit is contained in:
Jozufozu 2023-05-08 22:43:55 -07:00
parent d44c973bcc
commit 639b2185ab
21 changed files with 314 additions and 267 deletions

View file

@ -1,5 +1,7 @@
package com.jozufozu.flywheel.backend.compile; package com.jozufozu.flywheel.backend.compile;
import java.util.List;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -24,7 +26,8 @@ public class CullingCompiler extends AbstractCompiler<InstanceType<?>> {
super(sources, keys); super(sources, keys);
this.uniformComponent = uniformComponent; this.uniformComponent = uniformComponent;
pipelineCompute = sources.find(Files.INDIRECT_CULL); pipelineCompute = sources.find(Files.INDIRECT_CULL)
.unwrap();
} }
@Nullable @Nullable
@ -40,9 +43,11 @@ public class CullingCompiler extends AbstractCompiler<InstanceType<?>> {
return programLinker.link(compute); return programLinker.link(compute);
} }
private ImmutableList<SourceComponent> getComputeComponents(InstanceType<?> instanceType) { private List<SourceComponent> getComputeComponents(InstanceType<?> instanceType) {
var instanceAssembly = new IndirectComponent(sources, instanceType); var instanceAssembly = new IndirectComponent(sources, instanceType);
var instance = sources.find(instanceType.instanceShader()); ResourceLocation key = instanceType.instanceShader();
var instance = sources.find(key)
.unwrap();
return ImmutableList.of(uniformComponent, instanceAssembly, instance, pipelineCompute); return ImmutableList.of(uniformComponent, instanceAssembly, instance, pipelineCompute);
} }

View file

@ -5,9 +5,13 @@ import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.uniform.ShaderUniforms; import com.jozufozu.flywheel.api.uniform.ShaderUniforms;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
import com.jozufozu.flywheel.backend.compile.component.UniformComponent; import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.glsl.ShaderSources; import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.generate.FnSignature;
import com.jozufozu.flywheel.glsl.generate.GlslExpr;
import com.jozufozu.flywheel.lib.context.Contexts; import com.jozufozu.flywheel.lib.context.Contexts;
import com.jozufozu.flywheel.lib.material.MaterialIndices;
import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceManager;
@ -25,8 +29,30 @@ public class FlwPrograms {
.toList()) .toList())
.build(sources); .build(sources);
InstancingPrograms.reload(sources, pipelineKeys, uniformComponent); var vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
IndirectPrograms.reload(sources, pipelineKeys, uniformComponent); .materialSources(MaterialIndices.getAllVertexShaders())
.adapt(FnSignature.ofVoid("flw_materialVertex"))
.switchOn(GlslExpr.variable("_flw_materialVertexID"))
.build(sources);
var fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter"))
.materialSources(MaterialIndices.getAllFragmentShaders())
.adapt(FnSignature.ofVoid("flw_materialFragment"))
.adapt(FnSignature.create()
.returnType("bool")
.name("flw_discardPredicate")
.arg("vec4", "color")
.build(), GlslExpr.literal(false))
.adapt(FnSignature.create()
.returnType("vec4")
.name("flw_fogFilter")
.arg("vec4", "color")
.build(), GlslExpr.variable("color"))
.switchOn(GlslExpr.variable("_flw_materialFragmentID"))
.build(sources);
InstancingPrograms.reload(sources, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
IndirectPrograms.reload(sources, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
} }
private static ImmutableList<PipelineProgramKey> createPipelineKeys() { private static ImmutableList<PipelineProgramKey> createPipelineKeys() {

View file

@ -8,6 +8,7 @@ import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.context.Context;
import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
import com.jozufozu.flywheel.backend.compile.component.UniformComponent; import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.gl.shader.GlProgram; import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.glsl.ShaderSources; import com.jozufozu.flywheel.glsl.ShaderSources;
@ -22,12 +23,12 @@ public class IndirectPrograms {
this.culling = culling; this.culling = culling;
} }
public static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent) { public static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
if (instance != null) { if (instance != null) {
instance.delete(); instance.delete();
instance = null; instance = null;
} }
var pipelineCompiler = new PipelineCompiler(sources, pipelineKeys, Pipelines.INDIRECT, uniformComponent); var pipelineCompiler = new PipelineCompiler(sources, pipelineKeys, Pipelines.INDIRECT, vertexMaterialComponent, fragmentMaterialComponent, uniformComponent);
var cullingCompiler = new CullingCompiler(sources, createCullingKeys(), uniformComponent); var cullingCompiler = new CullingCompiler(sources, createCullingKeys(), uniformComponent);
var pipelineResult = pipelineCompiler.compileAndReportErrors(); var pipelineResult = pipelineCompiler.compileAndReportErrors();

View file

@ -8,6 +8,7 @@ import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.context.Context;
import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
import com.jozufozu.flywheel.backend.compile.component.UniformComponent; import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.gl.shader.GlProgram; import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.glsl.ShaderSources; import com.jozufozu.flywheel.glsl.ShaderSources;
@ -20,12 +21,12 @@ public class InstancingPrograms {
this.pipeline = pipeline; this.pipeline = pipeline;
} }
public static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent) { public static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
if (instance != null) { if (instance != null) {
instance.delete(); instance.delete();
instance = null; instance = null;
} }
var instancingCompiler = new PipelineCompiler(sources, pipelineKeys, Pipelines.INSTANCED_ARRAYS, uniformComponent); var instancingCompiler = new PipelineCompiler(sources, pipelineKeys, Pipelines.INSTANCED_ARRAYS, vertexMaterialComponent, fragmentMaterialComponent, uniformComponent);
var result = instancingCompiler.compileAndReportErrors(); var result = instancingCompiler.compileAndReportErrors();
if (result != null) { if (result != null) {

View file

@ -1,9 +1,10 @@
package com.jozufozu.flywheel.backend.compile; package com.jozufozu.flywheel.backend.compile;
import java.util.List;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent; import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
import com.jozufozu.flywheel.backend.compile.component.UniformComponent; import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.gl.shader.GlProgram; import com.jozufozu.flywheel.gl.shader.GlProgram;
@ -11,9 +12,6 @@ import com.jozufozu.flywheel.gl.shader.ShaderType;
import com.jozufozu.flywheel.glsl.ShaderSources; import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.SourceComponent;
import com.jozufozu.flywheel.glsl.SourceFile; import com.jozufozu.flywheel.glsl.SourceFile;
import com.jozufozu.flywheel.glsl.generate.FnSignature;
import com.jozufozu.flywheel.glsl.generate.GlslExpr;
import com.jozufozu.flywheel.lib.material.MaterialIndices;
public class PipelineCompiler extends AbstractCompiler<PipelineProgramKey> { public class PipelineCompiler extends AbstractCompiler<PipelineProgramKey> {
private final Pipeline pipeline; private final Pipeline pipeline;
@ -23,34 +21,17 @@ public class PipelineCompiler extends AbstractCompiler<PipelineProgramKey> {
private final SourceFile pipelineFragment; private final SourceFile pipelineFragment;
private final SourceFile pipelineVertex; private final SourceFile pipelineVertex;
public PipelineCompiler(ShaderSources sources, ImmutableList<PipelineProgramKey> keys, Pipeline pipeline, UniformComponent uniformComponent) { public PipelineCompiler(ShaderSources sources, ImmutableList<PipelineProgramKey> keys, Pipeline pipeline, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent, UniformComponent uniformComponent) {
super(sources, keys); super(sources, keys);
this.pipeline = pipeline; this.pipeline = pipeline;
this.vertexMaterialComponent = vertexMaterialComponent;
this.fragmentMaterialComponent = fragmentMaterialComponent;
this.uniformComponent = uniformComponent; this.uniformComponent = uniformComponent;
vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter")) pipelineFragment = this.sources.find(pipeline.fragmentShader())
.materialSources(MaterialIndices.getAllVertexShaders()) .unwrap();
.adapt(FnSignature.ofVoid("flw_materialVertex")) pipelineVertex = this.sources.find(pipeline.vertexShader())
.switchOn(GlslExpr.variable("_flw_materialVertexID")) .unwrap();
.build(sources);
fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter"))
.materialSources(MaterialIndices.getAllFragmentShaders())
.adapt(FnSignature.ofVoid("flw_materialFragment"))
.adapt(FnSignature.create()
.returnType("bool")
.name("flw_discardPredicate")
.arg("vec4", "color")
.build(), GlslExpr.literal(false))
.adapt(FnSignature.create()
.returnType("vec4")
.name("flw_fogFilter")
.arg("vec4", "color")
.build(), GlslExpr.variable("color"))
.switchOn(GlslExpr.variable("_flw_materialFragmentID"))
.build(sources);
pipelineFragment = sources.find(pipeline.fragmentShader());
pipelineVertex = sources.find(pipeline.vertexShader());
} }
@Nullable @Nullable
@ -71,23 +52,27 @@ public class PipelineCompiler extends AbstractCompiler<PipelineProgramKey> {
return glProgram; return glProgram;
} }
private ImmutableList<SourceComponent> getVertexComponents(PipelineProgramKey key) { private List<SourceComponent> getVertexComponents(PipelineProgramKey key) {
var instanceAssembly = pipeline.assembler() var instanceAssembly = pipeline.assembler()
.assemble(new Pipeline.InstanceAssemblerContext(sources, key.vertexType(), key.instanceType())); .assemble(new Pipeline.InstanceAssemblerContext(sources, key.vertexType(), key.instanceType()));
var layout = sources.find(key.vertexType() var layout = sources.find(key.vertexType()
.layoutShader()); .layoutShader())
.unwrap();
var instance = sources.find(key.instanceType() var instance = sources.find(key.instanceType()
.instanceShader()); .instanceShader())
.unwrap();
var context = sources.find(key.contextShader() var context = sources.find(key.contextShader()
.vertexShader()); .vertexShader())
.unwrap();
return ImmutableList.of(uniformComponent, vertexMaterialComponent, instanceAssembly, layout, instance, context, pipelineVertex); return ImmutableList.of(uniformComponent, vertexMaterialComponent, instanceAssembly, layout, instance, context, pipelineVertex);
} }
private ImmutableList<SourceComponent> getFragmentComponents(PipelineProgramKey key) { private List<SourceComponent> getFragmentComponents(PipelineProgramKey key) {
var context = sources.find(key.contextShader() var context = sources.find(key.contextShader()
.fragmentShader()); .fragmentShader())
.unwrap();
return ImmutableList.of(uniformComponent, fragmentMaterialComponent, context, pipelineFragment); return ImmutableList.of(uniformComponent, fragmentMaterialComponent, context, pipelineFragment);
} }
} }

View file

@ -1,66 +1,55 @@
package com.jozufozu.flywheel.backend.compile; package com.jozufozu.flywheel.backend.compile;
import java.util.Optional;
import java.util.function.BiConsumer;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.glsl.SourceFile;
import com.jozufozu.flywheel.glsl.error.ErrorReporter;
import com.jozufozu.flywheel.glsl.parse.ShaderFunction;
import com.jozufozu.flywheel.glsl.parse.ShaderVariable;
// TODO: recycle to be invoked by the shader compiler // TODO: recycle to be invoked by the shader compiler
public class SourceChecks { public class SourceChecks {
public static final BiConsumer<ErrorReporter, SourceFile> LAYOUT_VERTEX = checkFunctionArity("flw_layoutVertex", 0); // public static final BiConsumer<ErrorReporter, SourceFile> LAYOUT_VERTEX = checkFunctionArity("flw_layoutVertex", 0);
public static final BiConsumer<ErrorReporter, SourceFile> INSTANCE_VERTEX = checkFunctionParameterTypeExists("flw_instanceVertex", 1, 0); // public static final BiConsumer<ErrorReporter, SourceFile> INSTANCE_VERTEX = checkFunctionParameterTypeExists("flw_instanceVertex", 1, 0);
public static final BiConsumer<ErrorReporter, SourceFile> MATERIAL_VERTEX = checkFunctionArity("flw_materialVertex", 0); // public static final BiConsumer<ErrorReporter, SourceFile> MATERIAL_VERTEX = checkFunctionArity("flw_materialVertex", 0);
public static final BiConsumer<ErrorReporter, SourceFile> MATERIAL_FRAGMENT = checkFunctionArity("flw_materialFragment", 0); // public static final BiConsumer<ErrorReporter, SourceFile> MATERIAL_FRAGMENT = checkFunctionArity("flw_materialFragment", 0);
public static final BiConsumer<ErrorReporter, SourceFile> CONTEXT_VERTEX = checkFunctionArity("flw_contextVertex", 0); // public static final BiConsumer<ErrorReporter, SourceFile> CONTEXT_VERTEX = checkFunctionArity("flw_contextVertex", 0);
public static final BiConsumer<ErrorReporter, SourceFile> CONTEXT_FRAGMENT = checkFunctionArity("flw_contextFragment", 0).andThen(checkFunctionArity("flw_initFragment", 0)); // public static final BiConsumer<ErrorReporter, SourceFile> CONTEXT_FRAGMENT = checkFunctionArity("flw_contextFragment", 0).andThen(checkFunctionArity("flw_initFragment", 0));
public static final BiConsumer<ErrorReporter, SourceFile> PIPELINE = checkFunctionArity("main", 0); // public static final BiConsumer<ErrorReporter, SourceFile> PIPELINE = checkFunctionArity("main", 0);
//
public static BiConsumer<ErrorReporter, SourceFile> checkFunctionArity(String name, int arity) { // public static BiConsumer<ErrorReporter, SourceFile> checkFunctionArity(String name, int arity) {
return (errorReporter, file) -> checkFunctionArity(errorReporter, file, name, arity); // return (errorReporter, file) -> checkFunctionArity(errorReporter, file, name, arity);
} // }
//
public static BiConsumer<ErrorReporter, SourceFile> checkFunctionParameterTypeExists(String name, int arity, int param) { // public static BiConsumer<ErrorReporter, SourceFile> checkFunctionParameterTypeExists(String name, int arity, int param) {
return (errorReporter, file) -> { // return (errorReporter, file) -> {
var func = checkFunctionArity(errorReporter, file, name, arity); // var func = checkFunctionArity(errorReporter, file, name, arity);
//
if (func == null) { // if (func == null) {
return; // return;
} // }
//
var maybeStruct = func.getParameterType(param) // var maybeStruct = func.getParameterType(param)
.findStruct(); // .findStruct();
//
if (maybeStruct.isEmpty()) { // if (maybeStruct.isEmpty()) {
errorReporter.generateMissingStruct(file, func.getParameterType(param), "struct not defined"); // errorReporter.generateMissingStruct(file, func.getParameterType(param), "struct not defined");
} // }
}; // };
} // }
//
/** // /**
* @return {@code null} if the function doesn't exist, or if the function has the wrong arity. // * @return {@code null} if the function doesn't exist, or if the function has the wrong arity.
*/ // */
@Nullable // @Nullable
private static ShaderFunction checkFunctionArity(ErrorReporter errorReporter, SourceFile file, String name, int arity) { // private static ShaderFunction checkFunctionArity(ErrorReporter errorReporter, SourceFile file, String name, int arity) {
Optional<ShaderFunction> maybeFunc = file.findFunction(name); // Optional<ShaderFunction> maybeFunc = file.findFunction(name);
//
if (maybeFunc.isEmpty()) { // if (maybeFunc.isEmpty()) {
errorReporter.generateMissingFunction(file, name, "\"" + name + "\" function not defined"); // errorReporter.generateMissingFunction(file, name, "\"" + name + "\" function not defined");
return null; // return null;
} // }
//
ShaderFunction func = maybeFunc.get(); // ShaderFunction func = maybeFunc.get();
ImmutableList<ShaderVariable> params = func.getParameters(); // ImmutableList<ShaderVariable> params = func.getParameters();
if (params.size() != arity) { // if (params.size() != arity) {
errorReporter.generateFunctionArgumentCountError(name, arity, func.getArgs()); // errorReporter.generateFunctionArgumentCountError(name, arity, func.getArgs());
return null; // return null;
} // }
//
return func; // return func;
} // }
} }

View file

@ -35,7 +35,8 @@ public class IndirectComponent implements SourceComponent {
public IndirectComponent(ShaderSources sources, InstanceType<?> instanceType) { public IndirectComponent(ShaderSources sources, InstanceType<?> instanceType) {
this.layoutItems = instanceType.getLayout().layoutItems; this.layoutItems = instanceType.getLayout().layoutItems;
included = ImmutableList.of(sources.find(Pipelines.Files.UTIL_TYPES)); included = ImmutableList.of(sources.find(Pipelines.Files.UTIL_TYPES)
.unwrap());
} }
@Override @Override

View file

@ -13,6 +13,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.jozufozu.flywheel.glsl.ShaderSources; import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.SourceComponent;
import com.jozufozu.flywheel.glsl.SourceFile;
import com.jozufozu.flywheel.glsl.generate.FnSignature; import com.jozufozu.flywheel.glsl.generate.FnSignature;
import com.jozufozu.flywheel.glsl.generate.GlslBlock; import com.jozufozu.flywheel.glsl.generate.GlslBlock;
import com.jozufozu.flywheel.glsl.generate.GlslBuilder; import com.jozufozu.flywheel.glsl.generate.GlslBuilder;
@ -145,7 +146,8 @@ public class MaterialAdapterComponent implements SourceComponent {
int index = 0; int index = 0;
for (var rl : materialSources) { for (var rl : materialSources) {
var sourceFile = sources.find(rl); SourceFile sourceFile = sources.find(rl)
.unwrap();
final int finalIndex = index; final int finalIndex = index;
var adapterMap = createAdapterMap(adaptedFunctions, fnName -> "_" + fnName + "_" + finalIndex); var adapterMap = createAdapterMap(adaptedFunctions, fnName -> "_" + fnName + "_" + finalIndex);
transformed.add(new StringSubstitutionSourceComponent(sourceFile, adapterMap)); transformed.add(new StringSubstitutionSourceComponent(sourceFile, adapterMap));

View file

@ -67,7 +67,8 @@ public class UniformComponent implements SourceComponent {
var out = ImmutableList.<SourceFile>builder(); var out = ImmutableList.<SourceFile>builder();
for (var fileResolution : uniformShaders) { for (var fileResolution : uniformShaders) {
out.add(sources.find(fileResolution)); out.add(sources.find(fileResolution)
.unwrap());
} }
return new UniformComponent(name, out.build()); return new UniformComponent(name, out.build());

View file

@ -8,6 +8,7 @@ import java.util.stream.Stream;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.glsl.SourceFile; import com.jozufozu.flywheel.glsl.SourceFile;
import com.jozufozu.flywheel.glsl.SourceLines; import com.jozufozu.flywheel.glsl.SourceLines;
import com.jozufozu.flywheel.glsl.error.ErrorBuilder; import com.jozufozu.flywheel.glsl.error.ErrorBuilder;
@ -15,7 +16,10 @@ import com.jozufozu.flywheel.glsl.span.Span;
import com.jozufozu.flywheel.util.ConsoleColors; import com.jozufozu.flywheel.util.ConsoleColors;
import com.jozufozu.flywheel.util.StringUtil; import com.jozufozu.flywheel.util.StringUtil;
import net.minecraft.resources.ResourceLocation;
public class FailedCompilation { public class FailedCompilation {
public static final ResourceLocation GENERATED_SOURCE_NAME = Flywheel.rl("generated_source");
private static final Pattern ERROR_LINE = Pattern.compile("(\\d+)\\((\\d+)\\) : (.*)"); private static final Pattern ERROR_LINE = Pattern.compile("(\\d+)\\((\\d+)\\) : (.*)");
private final List<SourceFile> files; private final List<SourceFile> files;
private final SourceLines generatedSource; private final SourceLines generatedSource;
@ -25,7 +29,7 @@ public class FailedCompilation {
public FailedCompilation(String shaderName, List<SourceFile> files, String generatedSource, String errorLog) { public FailedCompilation(String shaderName, List<SourceFile> files, String generatedSource, String errorLog) {
this.shaderName = shaderName; this.shaderName = shaderName;
this.files = files; this.files = files;
this.generatedSource = new SourceLines(generatedSource); this.generatedSource = new SourceLines(GENERATED_SOURCE_NAME, generatedSource);
this.errorLog = errorLog; this.errorLog = errorLog;
} }

View file

@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.compile.core;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@ -10,7 +11,6 @@ import java.util.function.Consumer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.gl.shader.GlShader; import com.jozufozu.flywheel.gl.shader.GlShader;
import com.jozufozu.flywheel.gl.shader.ShaderType; import com.jozufozu.flywheel.gl.shader.ShaderType;
import com.jozufozu.flywheel.glsl.GLSLVersion; import com.jozufozu.flywheel.glsl.GLSLVersion;
@ -29,7 +29,7 @@ public class ShaderCompiler {
} }
@Nullable @Nullable
public GlShader compile(GLSLVersion glslVersion, ShaderType shaderType, ImmutableList<SourceComponent> sourceComponents) { public GlShader compile(GLSLVersion glslVersion, ShaderType shaderType, List<SourceComponent> sourceComponents) {
var key = new ShaderKey(glslVersion, shaderType, sourceComponents); var key = new ShaderKey(glslVersion, shaderType, sourceComponents);
var cached = shaderCache.get(key); var cached = shaderCache.get(key);
if (cached != null) { if (cached != null) {
@ -51,7 +51,7 @@ public class ShaderCompiler {
} }
@NotNull @NotNull
private ShaderResult compileUncached(Compilation ctx, ImmutableList<SourceComponent> sourceComponents) { private ShaderResult compileUncached(Compilation ctx, List<SourceComponent> sourceComponents) {
ctx.enableExtension("GL_ARB_explicit_attrib_location"); ctx.enableExtension("GL_ARB_explicit_attrib_location");
ctx.enableExtension("GL_ARB_conservative_depth"); ctx.enableExtension("GL_ARB_conservative_depth");
@ -60,7 +60,7 @@ public class ShaderCompiler {
return ctx.compile(); return ctx.compile();
} }
private static void expand(ImmutableList<SourceComponent> rootSources, Consumer<SourceComponent> out) { private static void expand(List<SourceComponent> rootSources, Consumer<SourceComponent> out) {
var included = new LinkedHashSet<SourceComponent>(); // use hash set to deduplicate. linked to preserve order var included = new LinkedHashSet<SourceComponent>(); // use hash set to deduplicate. linked to preserve order
for (var component : rootSources) { for (var component : rootSources) {
recursiveDepthFirstInclude(included, component); recursiveDepthFirstInclude(included, component);
@ -76,7 +76,6 @@ public class ShaderCompiler {
included.addAll(component.included()); included.addAll(component.included());
} }
private record ShaderKey(GLSLVersion glslVersion, ShaderType shaderType, private record ShaderKey(GLSLVersion glslVersion, ShaderType shaderType, List<SourceComponent> sourceComponents) {
ImmutableList<SourceComponent> sourceComponents) {
} }
} }

View file

@ -0,0 +1,39 @@
package com.jozufozu.flywheel.glsl;
import java.io.IOException;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import net.minecraft.resources.ResourceLocation;
public sealed interface LoadResult {
static LoadResult success(SourceFile sourceFile) {
return new Success(sourceFile);
}
@Nullable SourceFile unwrap();
record Success(SourceFile source) implements LoadResult {
@Override
@NotNull
public SourceFile unwrap() {
return source;
}
}
record IOError(ResourceLocation location, IOException exception) implements LoadResult {
@Override
public SourceFile unwrap() {
return null;
}
}
record IncludeError(ResourceLocation location, List<LoadResult> innerFailures) implements LoadResult {
@Override
public SourceFile unwrap() {
return null;
}
}
}

View file

@ -23,7 +23,7 @@ public class ShaderSources {
private final ResourceManager manager; private final ResourceManager manager;
private final Map<ResourceLocation, SourceFile> cache = new HashMap<>(); private final Map<ResourceLocation, LoadResult> cache = new HashMap<>();
/** /**
* Tracks where we are in the mutual recursion to detect circular imports. * Tracks where we are in the mutual recursion to detect circular imports.
@ -35,7 +35,7 @@ public class ShaderSources {
} }
@Nonnull @Nonnull
public SourceFile find(ResourceLocation location) { public LoadResult find(ResourceLocation location) {
pushFindStack(location); pushFindStack(location);
// Can't use computeIfAbsent because mutual recursion causes ConcurrentModificationExceptions // Can't use computeIfAbsent because mutual recursion causes ConcurrentModificationExceptions
var out = cache.get(location); var out = cache.get(location);
@ -48,15 +48,15 @@ public class ShaderSources {
} }
@Nonnull @Nonnull
private SourceFile load(ResourceLocation loc) { private LoadResult load(ResourceLocation loc) {
try { try {
var resource = manager.getResource(ResourceUtil.prefixed(SHADER_DIR, loc)); var resource = manager.getResource(ResourceUtil.prefixed(SHADER_DIR, loc));
var sourceString = StringUtil.readToString(resource.getInputStream()); var sourceString = StringUtil.readToString(resource.getInputStream());
return new SourceFile(this, loc, sourceString); return SourceFile.parse(this, loc, sourceString);
} catch (IOException ioException) { } catch (IOException e) {
throw new ShaderLoadingException("Could not load shader " + loc, ioException); return new LoadResult.IOError(loc, e);
} }
} }

View file

@ -1,12 +1,17 @@
package com.jozufozu.flywheel.glsl; package com.jozufozu.flywheel.glsl;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import org.jetbrains.annotations.NotNull;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.jozufozu.flywheel.glsl.parse.Import; import com.jozufozu.flywheel.glsl.parse.Import;
@ -29,8 +34,6 @@ import net.minecraft.resources.ResourceLocation;
public class SourceFile implements SourceComponent { public class SourceFile implements SourceComponent {
public final ResourceLocation name; public final ResourceLocation name;
public final ShaderSources parent;
public final SourceLines source; public final SourceLines source;
/** /**
@ -51,30 +54,51 @@ public class SourceFile implements SourceComponent {
public final List<SourceFile> included; public final List<SourceFile> included;
public SourceFile(ShaderSources sourceFinder, ResourceLocation name, String source) { public final String finalSource;
this.parent = sourceFinder;
private SourceFile(ResourceLocation name, SourceLines source, ImmutableMap<String, ShaderFunction> functions, ImmutableMap<String, ShaderStruct> structs, ImmutableList<Import> imports, ImmutableMap<String, ShaderField> fields, List<SourceFile> included, String finalSource) {
this.name = name; this.name = name;
this.source = source;
this.source = new SourceLines(source); this.functions = functions;
this.structs = structs;
this.imports = parseImports(source); this.imports = imports;
this.functions = parseFunctions(source); this.fields = fields;
this.structs = parseStructs(source); this.included = included;
this.fields = parseFields(source); this.finalSource = finalSource;
this.included = imports.stream()
.map(i -> i.file)
.map(Span::toString)
.distinct()
.<SourceFile>mapMulti((file, sink) -> {
try {
var loc = new ResourceLocation(file);
var sourceFile = sourceFinder.find(loc);
sink.accept(sourceFile);
} catch (Exception ignored) {
} }
})
.toList(); public static LoadResult parse(ShaderSources sourceFinder, ResourceLocation name, String stringSource) {
var source = new SourceLines(name, stringSource);
var imports = parseImports(source);
List<SourceFile> included = new ArrayList<>();
List<LoadResult> failures = new ArrayList<>();
Set<String> seen = new HashSet<>();
for (Import i : imports) {
var fileSpan = i.file();
String string = fileSpan.toString();
if (!seen.add(string)) {
continue;
}
var result = sourceFinder.find(new ResourceLocation(string));
if (result instanceof LoadResult.Success s) {
included.add(s.unwrap());
} else {
failures.add(result);
}
}
if (!failures.isEmpty()) {
return new LoadResult.IncludeError(name, failures);
}
var functions = parseFunctions(source);
var structs = parseStructs(source);
var fields = parseFields(source);
var finalSource = generateFinalSource(imports, source);
return LoadResult.success(new SourceFile(name, source, functions, structs, imports, fields, included, finalSource));
} }
@Override @Override
@ -84,7 +108,26 @@ public class SourceFile implements SourceComponent {
@Override @Override
public String source() { public String source() {
return this.genFinalSource(); return finalSource;
}
@NotNull
private static String generateFinalSource(ImmutableList<Import> imports, SourceLines source) {
var out = new StringBuilder();
int lastEnd = 0;
for (var include : imports) {
var loc = include.self();
out.append(source, lastEnd, loc.startIndex());
lastEnd = loc.endIndex();
}
out.append(source, lastEnd, source.length());
return out.toString();
} }
@Override @Override
@ -96,7 +139,7 @@ public class SourceFile implements SourceComponent {
int begin = source.lineStartIndex(lineNo); int begin = source.lineStartIndex(lineNo);
int end = begin + source.lineString(lineNo) int end = begin + source.lineString(lineNo)
.length(); .length();
return new StringSpan(this, source.getCharPos(begin), source.getCharPos(end)); return new StringSpan(source, begin, end);
} }
public Span getLineSpanNoWhitespace(int line) { public Span getLineSpanNoWhitespace(int line) {
@ -108,7 +151,7 @@ public class SourceFile implements SourceComponent {
begin++; begin++;
} }
return new StringSpan(this, source.getCharPos(begin), source.getCharPos(end)); return new StringSpan(source, begin, end);
} }
/** /**
@ -157,32 +200,6 @@ public class SourceFile implements SourceComponent {
return Optional.empty(); return Optional.empty();
} }
public CharSequence importStatement() {
return "#use " + '"' + name + '"';
}
public String printSource() {
return "Source for shader '" + name + "':\n" + source.printLinesWithNumbers();
}
private String genFinalSource() {
StringBuilder out = new StringBuilder();
int lastEnd = 0;
for (var include : imports) {
var loc = include.self;
out.append(this.source, lastEnd, loc.getStartPos());
lastEnd = loc.getEndPos();
}
out.append(this.source, lastEnd, this.source.length());
return out.toString();
}
@Override @Override
public String toString() { public String toString() {
return name.toString(); return name.toString();
@ -199,19 +216,18 @@ public class SourceFile implements SourceComponent {
return System.identityHashCode(this); return System.identityHashCode(this);
} }
/** /**
* Scan the source for {@code #use "..."} directives. * Scan the source for {@code #use "..."} directives.
* Records the contents of the directive into an {@link Import} object, and marks the directive for elision. * Records the contents of the directive into an {@link Import} object, and marks the directive for elision.
*/ */
private ImmutableList<Import> parseImports(String source) { private static ImmutableList<Import> parseImports(SourceLines source) {
Matcher uses = Import.PATTERN.matcher(source); Matcher uses = Import.PATTERN.matcher(source);
var imports = ImmutableList.<Import>builder(); var imports = ImmutableList.<Import>builder();
while (uses.find()) { while (uses.find()) {
Span use = Span.fromMatcher(this, uses); Span use = Span.fromMatcher(source, uses);
Span file = Span.fromMatcher(this, uses, 1); Span file = Span.fromMatcher(source, uses, 1);
imports.add(new Import(use, file)); imports.add(new Import(use, file));
} }
@ -219,19 +235,18 @@ public class SourceFile implements SourceComponent {
return imports.build(); return imports.build();
} }
/** /**
* Scan the source for function definitions and "parse" them into objects that contain properties of the function. * Scan the source for function definitions and "parse" them into objects that contain properties of the function.
*/ */
private ImmutableMap<String, ShaderFunction> parseFunctions(String source) { private static ImmutableMap<String, ShaderFunction> parseFunctions(SourceLines source) {
Matcher matcher = ShaderFunction.PATTERN.matcher(source); Matcher matcher = ShaderFunction.PATTERN.matcher(source);
Map<String, ShaderFunction> functions = new HashMap<>(); Map<String, ShaderFunction> functions = new HashMap<>();
while (matcher.find()) { while (matcher.find()) {
Span type = Span.fromMatcher(this, matcher, 1); Span type = Span.fromMatcher(source, matcher, 1);
Span name = Span.fromMatcher(this, matcher, 2); Span name = Span.fromMatcher(source, matcher, 2);
Span args = Span.fromMatcher(this, matcher, 3); Span args = Span.fromMatcher(source, matcher, 3);
int blockStart = matcher.end(); int blockStart = matcher.end();
int blockEnd = findEndOfBlock(source, blockStart); int blockEnd = findEndOfBlock(source, blockStart);
@ -239,11 +254,11 @@ public class SourceFile implements SourceComponent {
Span self; Span self;
Span body; Span body;
if (blockEnd > blockStart) { if (blockEnd > blockStart) {
self = new StringSpan(this, matcher.start(), blockEnd + 1); self = new StringSpan(source, matcher.start(), blockEnd + 1);
body = new StringSpan(this, blockStart, blockEnd); body = new StringSpan(source, blockStart, blockEnd);
} else { } else {
self = new ErrorSpan(this, matcher.start(), matcher.end()); self = new ErrorSpan(source, matcher.start(), matcher.end());
body = new ErrorSpan(this, blockStart); body = new ErrorSpan(source, blockStart);
} }
ShaderFunction function = new ShaderFunction(self, type, name, args, body); ShaderFunction function = new ShaderFunction(self, type, name, args, body);
@ -257,15 +272,15 @@ public class SourceFile implements SourceComponent {
/** /**
* Scan the source for function definitions and "parse" them into objects that contain properties of the function. * Scan the source for function definitions and "parse" them into objects that contain properties of the function.
*/ */
private ImmutableMap<String, ShaderStruct> parseStructs(String source) { private static ImmutableMap<String, ShaderStruct> parseStructs(SourceLines source) {
Matcher matcher = ShaderStruct.PATTERN.matcher(source); Matcher matcher = ShaderStruct.PATTERN.matcher(source);
ImmutableMap.Builder<String, ShaderStruct> structs = ImmutableMap.builder(); ImmutableMap.Builder<String, ShaderStruct> structs = ImmutableMap.builder();
while (matcher.find()) { while (matcher.find()) {
Span self = Span.fromMatcher(this, matcher); Span self = Span.fromMatcher(source, matcher);
Span name = Span.fromMatcher(this, matcher, 1); Span name = Span.fromMatcher(source, matcher, 1);
Span body = Span.fromMatcher(this, matcher, 2); Span body = Span.fromMatcher(source, matcher, 2);
Span variableName = Span.fromMatcher(this, matcher, 3); Span variableName = Span.fromMatcher(source, matcher, 3);
ShaderStruct shaderStruct = new ShaderStruct(self, name, body, variableName); ShaderStruct shaderStruct = new ShaderStruct(self, name, body, variableName);
@ -278,16 +293,16 @@ public class SourceFile implements SourceComponent {
/** /**
* Scan the source for function definitions and "parse" them into objects that contain properties of the function. * Scan the source for function definitions and "parse" them into objects that contain properties of the function.
*/ */
private ImmutableMap<String, ShaderField> parseFields(String source) { private static ImmutableMap<String, ShaderField> parseFields(SourceLines source) {
Matcher matcher = ShaderField.PATTERN.matcher(source); Matcher matcher = ShaderField.PATTERN.matcher(source);
ImmutableMap.Builder<String, ShaderField> fields = ImmutableMap.builder(); ImmutableMap.Builder<String, ShaderField> fields = ImmutableMap.builder();
while (matcher.find()) { while (matcher.find()) {
Span self = Span.fromMatcher(this, matcher); Span self = Span.fromMatcher(source, matcher);
Span location = Span.fromMatcher(this, matcher, 1); Span location = Span.fromMatcher(source, matcher, 1);
Span decoration = Span.fromMatcher(this, matcher, 2); Span decoration = Span.fromMatcher(source, matcher, 2);
Span type = Span.fromMatcher(this, matcher, 3); Span type = Span.fromMatcher(source, matcher, 3);
Span name = Span.fromMatcher(this, matcher, 4); Span name = Span.fromMatcher(source, matcher, 4);
fields.put(location.get(), new ShaderField(self, location, decoration, type, name)); fields.put(location.get(), new ShaderField(self, location, decoration, type, name));
} }
@ -298,13 +313,16 @@ public class SourceFile implements SourceComponent {
/** /**
* Given the position of an opening brace, scans through the source for a paired closing brace. * Given the position of an opening brace, scans through the source for a paired closing brace.
*/ */
private static int findEndOfBlock(String source, int start) { private static int findEndOfBlock(CharSequence source, int start) {
int blockDepth = 0; int blockDepth = 0;
for (int i = start + 1; i < source.length(); i++) { for (int i = start + 1; i < source.length(); i++) {
char ch = source.charAt(i); char ch = source.charAt(i);
if (ch == '{') blockDepth++; if (ch == '{') {
else if (ch == '}') blockDepth--; blockDepth++;
} else if (ch == '}') {
blockDepth--;
}
if (blockDepth < 0) { if (blockDepth < 0) {
return i; return i;

View file

@ -11,11 +11,13 @@ import com.jozufozu.flywheel.glsl.span.CharPos;
import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntLists; import it.unimi.dsi.fastutil.ints.IntLists;
import net.minecraft.resources.ResourceLocation;
public class SourceLines implements CharSequence { public class SourceLines implements CharSequence {
private static final Pattern newLine = Pattern.compile("(\\r\\n|\\r|\\n)"); private static final Pattern newLine = Pattern.compile("(\\r\\n|\\r|\\n)");
public final ResourceLocation name;
/** /**
* 0-indexed line to char pos mapping. * 0-indexed line to char pos mapping.
*/ */
@ -27,7 +29,8 @@ public class SourceLines implements CharSequence {
private final ImmutableList<String> lines; private final ImmutableList<String> lines;
public final String raw; public final String raw;
public SourceLines(String raw) { public SourceLines(ResourceLocation name, String raw) {
this.name = name;
this.raw = raw; this.raw = raw;
this.lineStarts = createLineLookup(raw); this.lineStarts = createLineLookup(raw);
this.lines = getLines(raw, lineStarts); this.lines = getLines(raw, lineStarts);

View file

@ -59,6 +59,10 @@ public class ErrorBuilder {
return pointAtFile(file.name.toString()); return pointAtFile(file.name.toString());
} }
public ErrorBuilder pointAtFile(SourceLines source) {
return pointAtFile(source.name.toString());
}
public ErrorBuilder pointAtFile(String file) { public ErrorBuilder pointAtFile(String file) {
lines.add(new FileLine(file)); lines.add(new FileLine(file));
return this; return this;
@ -69,13 +73,13 @@ public class ErrorBuilder {
return this; return this;
} }
SourceFile sourceFile = span.getSourceFile(); var source = span.source();
String builder = "add " + sourceFile.importStatement() + ' ' + msg + "\n defined here:"; String builder = "add " + "#use " + '"' + source.name + '"' + ' ' + msg + "\n defined here:";
header(ErrorLevel.HINT, builder); header(ErrorLevel.HINT, builder);
return this.pointAtFile(sourceFile) return this.pointAtFile(source)
.pointAt(span, 0); .pointAt(span, 0);
} }
@ -85,12 +89,12 @@ public class ErrorBuilder {
public ErrorBuilder pointAt(Span span, int ctxLines) { public ErrorBuilder pointAt(Span span, int ctxLines) {
if (span.lines() == 1) { if (span.lines() == 1) {
SourceLines lines = span.getSourceFile().source; SourceLines lines = span.source();
int spanLine = span.firstLine(); int spanLine = span.firstLine();
int firstCol = span.getStart() int firstCol = span.start()
.col(); .col();
int lastCol = span.getEnd() int lastCol = span.end()
.col(); .col();
pointAtLine(lines, spanLine, ctxLines, firstCol, lastCol); pointAtLine(lines, spanLine, ctxLines, firstCol, lastCol);

View file

@ -62,7 +62,7 @@ public class ErrorReporter {
} }
public ErrorBuilder generateSpanError(Span span, String message) { public ErrorBuilder generateSpanError(Span span, String message) {
SourceFile file = span.getSourceFile(); var file = span.source();
return error(message).pointAtFile(file) return error(message).pointAtFile(file)
.pointAt(span, 2); .pointAt(span, 2);

View file

@ -4,16 +4,6 @@ import java.util.regex.Pattern;
import com.jozufozu.flywheel.glsl.span.Span; import com.jozufozu.flywheel.glsl.span.Span;
public class Import { public record Import(Span self, Span file) {
public static final Pattern PATTERN = Pattern.compile("^\\s*#\\s*use\\s+\"(.*)\"", Pattern.MULTILINE); public static final Pattern PATTERN = Pattern.compile("^\\s*#\\s*use\\s+\"(.*)\"", Pattern.MULTILINE);
public final Span self;
public final Span file;
public Import(Span self, Span file) {
this.self = self;
this.file = file;
}
} }

View file

@ -1,20 +1,20 @@
package com.jozufozu.flywheel.glsl.span; package com.jozufozu.flywheel.glsl.span;
import com.jozufozu.flywheel.glsl.SourceFile; import com.jozufozu.flywheel.glsl.SourceLines;
/** /**
* Represents a (syntactically) malformed segment of code. * Represents a (syntactically) malformed segment of code.
*/ */
public class ErrorSpan extends Span { public class ErrorSpan extends Span {
public ErrorSpan(SourceFile in, int loc) { public ErrorSpan(SourceLines in, int loc) {
super(in, loc, loc); super(in, loc, loc);
} }
public ErrorSpan(SourceFile in, int start, int end) { public ErrorSpan(SourceLines in, int start, int end) {
super(in, start, end); super(in, start, end);
} }
public ErrorSpan(SourceFile in, CharPos start, CharPos end) { public ErrorSpan(SourceLines in, CharPos start, CharPos end) {
super(in, start, end); super(in, start, end);
} }

View file

@ -1,13 +1,11 @@
package com.jozufozu.flywheel.glsl.span; package com.jozufozu.flywheel.glsl.span;
import java.util.Optional;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.jozufozu.flywheel.glsl.SourceFile; import com.jozufozu.flywheel.glsl.SourceFile;
import com.jozufozu.flywheel.glsl.parse.ShaderFunction; import com.jozufozu.flywheel.glsl.SourceLines;
import com.jozufozu.flywheel.glsl.parse.ShaderStruct;
/** /**
* A segment of code in a {@link SourceFile}. * A segment of code in a {@link SourceFile}.
@ -17,16 +15,15 @@ import com.jozufozu.flywheel.glsl.parse.ShaderStruct;
* </p> * </p>
*/ */
public abstract class Span implements CharSequence, Comparable<Span> { public abstract class Span implements CharSequence, Comparable<Span> {
protected final SourceLines in;
protected final SourceFile in;
protected final CharPos start; protected final CharPos start;
protected final CharPos end; protected final CharPos end;
public Span(SourceFile in, int start, int end) { public Span(SourceLines in, int start, int end) {
this(in, in.source.getCharPos(start), in.source.getCharPos(end)); this(in, in.getCharPos(start), in.getCharPos(end));
} }
public Span(SourceFile in, CharPos start, CharPos end) { public Span(SourceLines in, CharPos start, CharPos end) {
this.in = in; this.in = in;
this.start = start; this.start = start;
this.end = end; this.end = end;
@ -35,29 +32,29 @@ public abstract class Span implements CharSequence, Comparable<Span> {
/** /**
* @return The file that contains this code segment. * @return The file that contains this code segment.
*/ */
public SourceFile getSourceFile() { public SourceLines source() {
return in; return in;
} }
public CharPos getStart() { public CharPos start() {
return start; return start;
} }
public CharPos getEnd() { public CharPos end() {
return end; return end;
} }
/** /**
* @return the string index at the (inclusive) beginning of this code segment. * @return the string index at the (inclusive) beginning of this code segment.
*/ */
public int getStartPos() { public int startIndex() {
return start.pos(); return start.pos();
} }
/** /**
* @return the string index at the (exclusive) end of this code segment. * @return the string index at the (exclusive) end of this code segment.
*/ */
public int getEndPos() { public int endIndex() {
return end.pos(); return end.pos();
} }
@ -93,12 +90,12 @@ public abstract class Span implements CharSequence, Comparable<Span> {
@Override @Override
public int length() { public int length() {
return getEndPos() - getStartPos(); return endIndex() - startIndex();
} }
@Override @Override
public char charAt(int index) { public char charAt(int index) {
return in.source.charAt(start.pos() + index); return in.charAt(start.pos() + index);
} }
@Override @Override
@ -111,7 +108,7 @@ public abstract class Span implements CharSequence, Comparable<Span> {
return get(); return get();
} }
public static Span fromMatcher(SourceFile src, Matcher m, int group) { public static Span fromMatcher(SourceLines src, Matcher m, int group) {
return new StringSpan(src, m.start(group), m.end(group)); return new StringSpan(src, m.start(group), m.end(group));
} }
@ -119,7 +116,7 @@ public abstract class Span implements CharSequence, Comparable<Span> {
return superSpan.subSpan(m.start(group), m.end(group)); return superSpan.subSpan(m.start(group), m.end(group));
} }
public static Span fromMatcher(SourceFile src, Matcher m) { public static Span fromMatcher(SourceLines src, Matcher m) {
return new StringSpan(src, m.start(), m.end()); return new StringSpan(src, m.start(), m.end());
} }
@ -127,22 +124,8 @@ public abstract class Span implements CharSequence, Comparable<Span> {
return superSpan.subSpan(m.start(), m.end()); return superSpan.subSpan(m.start(), m.end());
} }
public Optional<ShaderStruct> findStruct() {
if (isErr()) {
return Optional.empty();
}
return in.findStructByName(this.toString());
}
public Optional<ShaderFunction> findFunction() {
if (isErr()) {
return Optional.empty();
}
return in.findFunction(this.toString());
}
@Override @Override
public int compareTo(@NotNull Span o) { public int compareTo(@NotNull Span o) {
return Integer.compareUnsigned(getStartPos(), o.getStartPos()); return Integer.compareUnsigned(startIndex(), o.startIndex());
} }
} }

View file

@ -1,14 +1,10 @@
package com.jozufozu.flywheel.glsl.span; package com.jozufozu.flywheel.glsl.span;
import com.jozufozu.flywheel.glsl.SourceFile; import com.jozufozu.flywheel.glsl.SourceLines;
public class StringSpan extends Span { public class StringSpan extends Span {
public StringSpan(SourceFile in, int start, int end) { public StringSpan(SourceLines in, int start, int end) {
super(in, start, end);
}
public StringSpan(SourceFile in, CharPos start, CharPos end) {
super(in, start, end); super(in, start, end);
} }
@ -19,7 +15,7 @@ public class StringSpan extends Span {
@Override @Override
public String get() { public String get() {
return in.source.raw.substring(start.pos(), end.pos()); return in.raw.substring(start.pos(), end.pos());
} }
@Override @Override