mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-06 04:16:36 +01:00
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:
parent
d44c973bcc
commit
639b2185ab
21 changed files with 314 additions and 267 deletions
|
@ -1,5 +1,7 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
@ -24,7 +26,8 @@ public class CullingCompiler extends AbstractCompiler<InstanceType<?>> {
|
|||
super(sources, keys);
|
||||
|
||||
this.uniformComponent = uniformComponent;
|
||||
pipelineCompute = sources.find(Files.INDIRECT_CULL);
|
||||
pipelineCompute = sources.find(Files.INDIRECT_CULL)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -40,9 +43,11 @@ public class CullingCompiler extends AbstractCompiler<InstanceType<?>> {
|
|||
return programLinker.link(compute);
|
||||
}
|
||||
|
||||
private ImmutableList<SourceComponent> getComputeComponents(InstanceType<?> instanceType) {
|
||||
private List<SourceComponent> getComputeComponents(InstanceType<?> 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);
|
||||
}
|
||||
|
|
|
@ -5,9 +5,13 @@ import com.jozufozu.flywheel.Flywheel;
|
|||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.uniform.ShaderUniforms;
|
||||
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.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.material.MaterialIndices;
|
||||
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
|
||||
|
@ -25,8 +29,30 @@ public class FlwPrograms {
|
|||
.toList())
|
||||
.build(sources);
|
||||
|
||||
InstancingPrograms.reload(sources, pipelineKeys, uniformComponent);
|
||||
IndirectPrograms.reload(sources, pipelineKeys, uniformComponent);
|
||||
var vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
|
||||
.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() {
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.google.common.collect.ImmutableList;
|
|||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
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.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
|
@ -22,12 +23,12 @@ public class IndirectPrograms {
|
|||
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) {
|
||||
instance.delete();
|
||||
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 pipelineResult = pipelineCompiler.compileAndReportErrors();
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.google.common.collect.ImmutableList;
|
|||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
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.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
|
@ -20,12 +21,12 @@ public class InstancingPrograms {
|
|||
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) {
|
||||
instance.delete();
|
||||
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();
|
||||
|
||||
if (result != null) {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
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.UniformComponent;
|
||||
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.SourceComponent;
|
||||
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> {
|
||||
private final Pipeline pipeline;
|
||||
|
@ -23,34 +21,17 @@ public class PipelineCompiler extends AbstractCompiler<PipelineProgramKey> {
|
|||
private final SourceFile pipelineFragment;
|
||||
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);
|
||||
this.pipeline = pipeline;
|
||||
this.vertexMaterialComponent = vertexMaterialComponent;
|
||||
this.fragmentMaterialComponent = fragmentMaterialComponent;
|
||||
this.uniformComponent = uniformComponent;
|
||||
|
||||
vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
|
||||
.materialSources(MaterialIndices.getAllVertexShaders())
|
||||
.adapt(FnSignature.ofVoid("flw_materialVertex"))
|
||||
.switchOn(GlslExpr.variable("_flw_materialVertexID"))
|
||||
.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());
|
||||
pipelineFragment = this.sources.find(pipeline.fragmentShader())
|
||||
.unwrap();
|
||||
pipelineVertex = this.sources.find(pipeline.vertexShader())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -71,23 +52,27 @@ public class PipelineCompiler extends AbstractCompiler<PipelineProgramKey> {
|
|||
return glProgram;
|
||||
}
|
||||
|
||||
private ImmutableList<SourceComponent> getVertexComponents(PipelineProgramKey key) {
|
||||
private List<SourceComponent> getVertexComponents(PipelineProgramKey key) {
|
||||
var instanceAssembly = pipeline.assembler()
|
||||
.assemble(new Pipeline.InstanceAssemblerContext(sources, key.vertexType(), key.instanceType()));
|
||||
|
||||
var layout = sources.find(key.vertexType()
|
||||
.layoutShader());
|
||||
.layoutShader())
|
||||
.unwrap();
|
||||
var instance = sources.find(key.instanceType()
|
||||
.instanceShader());
|
||||
.instanceShader())
|
||||
.unwrap();
|
||||
var context = sources.find(key.contextShader()
|
||||
.vertexShader());
|
||||
.vertexShader())
|
||||
.unwrap();
|
||||
|
||||
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()
|
||||
.fragmentShader());
|
||||
.fragmentShader())
|
||||
.unwrap();
|
||||
return ImmutableList.of(uniformComponent, fragmentMaterialComponent, context, pipelineFragment);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,66 +1,55 @@
|
|||
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
|
||||
public class SourceChecks {
|
||||
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> MATERIAL_VERTEX = checkFunctionArity("flw_materialVertex", 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_FRAGMENT = checkFunctionArity("flw_contextFragment", 0).andThen(checkFunctionArity("flw_initFragment", 0));
|
||||
public static final BiConsumer<ErrorReporter, SourceFile> PIPELINE = checkFunctionArity("main", 0);
|
||||
|
||||
public static BiConsumer<ErrorReporter, SourceFile> checkFunctionArity(String name, int arity) {
|
||||
return (errorReporter, file) -> checkFunctionArity(errorReporter, file, name, arity);
|
||||
}
|
||||
|
||||
public static BiConsumer<ErrorReporter, SourceFile> checkFunctionParameterTypeExists(String name, int arity, int param) {
|
||||
return (errorReporter, file) -> {
|
||||
var func = checkFunctionArity(errorReporter, file, name, arity);
|
||||
|
||||
if (func == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var maybeStruct = func.getParameterType(param)
|
||||
.findStruct();
|
||||
|
||||
if (maybeStruct.isEmpty()) {
|
||||
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.
|
||||
*/
|
||||
@Nullable
|
||||
private static ShaderFunction checkFunctionArity(ErrorReporter errorReporter, SourceFile file, String name, int arity) {
|
||||
Optional<ShaderFunction> maybeFunc = file.findFunction(name);
|
||||
|
||||
if (maybeFunc.isEmpty()) {
|
||||
errorReporter.generateMissingFunction(file, name, "\"" + name + "\" function not defined");
|
||||
return null;
|
||||
}
|
||||
|
||||
ShaderFunction func = maybeFunc.get();
|
||||
ImmutableList<ShaderVariable> params = func.getParameters();
|
||||
if (params.size() != arity) {
|
||||
errorReporter.generateFunctionArgumentCountError(name, arity, func.getArgs());
|
||||
return null;
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
// 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> MATERIAL_VERTEX = checkFunctionArity("flw_materialVertex", 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_FRAGMENT = checkFunctionArity("flw_contextFragment", 0).andThen(checkFunctionArity("flw_initFragment", 0));
|
||||
// public static final BiConsumer<ErrorReporter, SourceFile> PIPELINE = checkFunctionArity("main", 0);
|
||||
//
|
||||
// public static BiConsumer<ErrorReporter, SourceFile> checkFunctionArity(String name, int arity) {
|
||||
// return (errorReporter, file) -> checkFunctionArity(errorReporter, file, name, arity);
|
||||
// }
|
||||
//
|
||||
// public static BiConsumer<ErrorReporter, SourceFile> checkFunctionParameterTypeExists(String name, int arity, int param) {
|
||||
// return (errorReporter, file) -> {
|
||||
// var func = checkFunctionArity(errorReporter, file, name, arity);
|
||||
//
|
||||
// if (func == null) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// var maybeStruct = func.getParameterType(param)
|
||||
// .findStruct();
|
||||
//
|
||||
// if (maybeStruct.isEmpty()) {
|
||||
// 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.
|
||||
// */
|
||||
// @Nullable
|
||||
// private static ShaderFunction checkFunctionArity(ErrorReporter errorReporter, SourceFile file, String name, int arity) {
|
||||
// Optional<ShaderFunction> maybeFunc = file.findFunction(name);
|
||||
//
|
||||
// if (maybeFunc.isEmpty()) {
|
||||
// errorReporter.generateMissingFunction(file, name, "\"" + name + "\" function not defined");
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// ShaderFunction func = maybeFunc.get();
|
||||
// ImmutableList<ShaderVariable> params = func.getParameters();
|
||||
// if (params.size() != arity) {
|
||||
// errorReporter.generateFunctionArgumentCountError(name, arity, func.getArgs());
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// return func;
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -35,7 +35,8 @@ public class IndirectComponent implements SourceComponent {
|
|||
|
||||
public IndirectComponent(ShaderSources sources, InstanceType<?> instanceType) {
|
||||
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
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.google.common.collect.ImmutableList;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
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.GlslBlock;
|
||||
import com.jozufozu.flywheel.glsl.generate.GlslBuilder;
|
||||
|
@ -145,7 +146,8 @@ public class MaterialAdapterComponent implements SourceComponent {
|
|||
|
||||
int index = 0;
|
||||
for (var rl : materialSources) {
|
||||
var sourceFile = sources.find(rl);
|
||||
SourceFile sourceFile = sources.find(rl)
|
||||
.unwrap();
|
||||
final int finalIndex = index;
|
||||
var adapterMap = createAdapterMap(adaptedFunctions, fnName -> "_" + fnName + "_" + finalIndex);
|
||||
transformed.add(new StringSubstitutionSourceComponent(sourceFile, adapterMap));
|
||||
|
|
|
@ -67,7 +67,8 @@ public class UniformComponent implements SourceComponent {
|
|||
var out = ImmutableList.<SourceFile>builder();
|
||||
|
||||
for (var fileResolution : uniformShaders) {
|
||||
out.add(sources.find(fileResolution));
|
||||
out.add(sources.find(fileResolution)
|
||||
.unwrap());
|
||||
}
|
||||
|
||||
return new UniformComponent(name, out.build());
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.util.stream.Stream;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
import com.jozufozu.flywheel.glsl.SourceLines;
|
||||
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.StringUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
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 final List<SourceFile> files;
|
||||
private final SourceLines generatedSource;
|
||||
|
@ -25,7 +29,7 @@ public class FailedCompilation {
|
|||
public FailedCompilation(String shaderName, List<SourceFile> files, String generatedSource, String errorLog) {
|
||||
this.shaderName = shaderName;
|
||||
this.files = files;
|
||||
this.generatedSource = new SourceLines(generatedSource);
|
||||
this.generatedSource = new SourceLines(GENERATED_SOURCE_NAME, generatedSource);
|
||||
this.errorLog = errorLog;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.compile.core;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
@ -10,7 +11,6 @@ import java.util.function.Consumer;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.gl.shader.GlShader;
|
||||
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.glsl.GLSLVersion;
|
||||
|
@ -29,7 +29,7 @@ public class ShaderCompiler {
|
|||
}
|
||||
|
||||
@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 cached = shaderCache.get(key);
|
||||
if (cached != null) {
|
||||
|
@ -51,7 +51,7 @@ public class ShaderCompiler {
|
|||
}
|
||||
|
||||
@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_conservative_depth");
|
||||
|
||||
|
@ -60,14 +60,14 @@ public class ShaderCompiler {
|
|||
return ctx.compile();
|
||||
}
|
||||
|
||||
private static void expand(ImmutableList<SourceComponent> rootSources, Consumer<SourceComponent> out) {
|
||||
var included = new LinkedHashSet<SourceComponent>(); // use hash set to deduplicate. linked to preserve order
|
||||
for (var component : rootSources) {
|
||||
recursiveDepthFirstInclude(included, component);
|
||||
included.add(component);
|
||||
}
|
||||
included.forEach(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
|
||||
for (var component : rootSources) {
|
||||
recursiveDepthFirstInclude(included, component);
|
||||
included.add(component);
|
||||
}
|
||||
included.forEach(out);
|
||||
}
|
||||
|
||||
private static void recursiveDepthFirstInclude(Set<SourceComponent> included, SourceComponent component) {
|
||||
for (var include : component.included()) {
|
||||
|
@ -76,7 +76,6 @@ public class ShaderCompiler {
|
|||
included.addAll(component.included());
|
||||
}
|
||||
|
||||
private record ShaderKey(GLSLVersion glslVersion, ShaderType shaderType,
|
||||
ImmutableList<SourceComponent> sourceComponents) {
|
||||
private record ShaderKey(GLSLVersion glslVersion, ShaderType shaderType, List<SourceComponent> sourceComponents) {
|
||||
}
|
||||
}
|
||||
|
|
39
src/main/java/com/jozufozu/flywheel/glsl/LoadResult.java
Normal file
39
src/main/java/com/jozufozu/flywheel/glsl/LoadResult.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ public class ShaderSources {
|
|||
|
||||
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.
|
||||
|
@ -35,7 +35,7 @@ public class ShaderSources {
|
|||
}
|
||||
|
||||
@Nonnull
|
||||
public SourceFile find(ResourceLocation location) {
|
||||
public LoadResult find(ResourceLocation location) {
|
||||
pushFindStack(location);
|
||||
// Can't use computeIfAbsent because mutual recursion causes ConcurrentModificationExceptions
|
||||
var out = cache.get(location);
|
||||
|
@ -48,15 +48,15 @@ public class ShaderSources {
|
|||
}
|
||||
|
||||
@Nonnull
|
||||
private SourceFile load(ResourceLocation loc) {
|
||||
private LoadResult load(ResourceLocation loc) {
|
||||
try {
|
||||
var resource = manager.getResource(ResourceUtil.prefixed(SHADER_DIR, loc));
|
||||
|
||||
var sourceString = StringUtil.readToString(resource.getInputStream());
|
||||
|
||||
return new SourceFile(this, loc, sourceString);
|
||||
} catch (IOException ioException) {
|
||||
throw new ShaderLoadingException("Could not load shader " + loc, ioException);
|
||||
return SourceFile.parse(this, loc, sourceString);
|
||||
} catch (IOException e) {
|
||||
return new LoadResult.IOError(loc, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
package com.jozufozu.flywheel.glsl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.glsl.parse.Import;
|
||||
|
@ -29,8 +34,6 @@ import net.minecraft.resources.ResourceLocation;
|
|||
public class SourceFile implements SourceComponent {
|
||||
public final ResourceLocation name;
|
||||
|
||||
public final ShaderSources parent;
|
||||
|
||||
public final SourceLines source;
|
||||
|
||||
/**
|
||||
|
@ -51,30 +54,51 @@ public class SourceFile implements SourceComponent {
|
|||
|
||||
public final List<SourceFile> included;
|
||||
|
||||
public SourceFile(ShaderSources sourceFinder, ResourceLocation name, String source) {
|
||||
this.parent = sourceFinder;
|
||||
public final String finalSource;
|
||||
|
||||
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.source = source;
|
||||
this.functions = functions;
|
||||
this.structs = structs;
|
||||
this.imports = imports;
|
||||
this.fields = fields;
|
||||
this.included = included;
|
||||
this.finalSource = finalSource;
|
||||
}
|
||||
|
||||
this.source = new SourceLines(source);
|
||||
public static LoadResult parse(ShaderSources sourceFinder, ResourceLocation name, String stringSource) {
|
||||
var source = new SourceLines(name, stringSource);
|
||||
|
||||
this.imports = parseImports(source);
|
||||
this.functions = parseFunctions(source);
|
||||
this.structs = parseStructs(source);
|
||||
this.fields = parseFields(source);
|
||||
var imports = parseImports(source);
|
||||
|
||||
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();
|
||||
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
|
||||
|
@ -84,7 +108,26 @@ public class SourceFile implements SourceComponent {
|
|||
|
||||
@Override
|
||||
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
|
||||
|
@ -96,7 +139,7 @@ public class SourceFile implements SourceComponent {
|
|||
int begin = source.lineStartIndex(lineNo);
|
||||
int end = begin + source.lineString(lineNo)
|
||||
.length();
|
||||
return new StringSpan(this, source.getCharPos(begin), source.getCharPos(end));
|
||||
return new StringSpan(source, begin, end);
|
||||
}
|
||||
|
||||
public Span getLineSpanNoWhitespace(int line) {
|
||||
|
@ -108,7 +151,7 @@ public class SourceFile implements SourceComponent {
|
|||
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();
|
||||
}
|
||||
|
||||
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
|
||||
public String toString() {
|
||||
return name.toString();
|
||||
|
@ -199,19 +216,18 @@ public class SourceFile implements SourceComponent {
|
|||
return System.identityHashCode(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scan the source for {@code #use "..."} directives.
|
||||
* 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);
|
||||
|
||||
var imports = ImmutableList.<Import>builder();
|
||||
|
||||
while (uses.find()) {
|
||||
Span use = Span.fromMatcher(this, uses);
|
||||
Span file = Span.fromMatcher(this, uses, 1);
|
||||
Span use = Span.fromMatcher(source, uses);
|
||||
Span file = Span.fromMatcher(source, uses, 1);
|
||||
|
||||
imports.add(new Import(use, file));
|
||||
}
|
||||
|
@ -219,19 +235,18 @@ public class SourceFile implements SourceComponent {
|
|||
return imports.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
Map<String, ShaderFunction> functions = new HashMap<>();
|
||||
|
||||
while (matcher.find()) {
|
||||
Span type = Span.fromMatcher(this, matcher, 1);
|
||||
Span name = Span.fromMatcher(this, matcher, 2);
|
||||
Span args = Span.fromMatcher(this, matcher, 3);
|
||||
Span type = Span.fromMatcher(source, matcher, 1);
|
||||
Span name = Span.fromMatcher(source, matcher, 2);
|
||||
Span args = Span.fromMatcher(source, matcher, 3);
|
||||
|
||||
int blockStart = matcher.end();
|
||||
int blockEnd = findEndOfBlock(source, blockStart);
|
||||
|
@ -239,11 +254,11 @@ public class SourceFile implements SourceComponent {
|
|||
Span self;
|
||||
Span body;
|
||||
if (blockEnd > blockStart) {
|
||||
self = new StringSpan(this, matcher.start(), blockEnd + 1);
|
||||
body = new StringSpan(this, blockStart, blockEnd);
|
||||
self = new StringSpan(source, matcher.start(), blockEnd + 1);
|
||||
body = new StringSpan(source, blockStart, blockEnd);
|
||||
} else {
|
||||
self = new ErrorSpan(this, matcher.start(), matcher.end());
|
||||
body = new ErrorSpan(this, blockStart);
|
||||
self = new ErrorSpan(source, matcher.start(), matcher.end());
|
||||
body = new ErrorSpan(source, blockStart);
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
private ImmutableMap<String, ShaderStruct> parseStructs(String source) {
|
||||
private static ImmutableMap<String, ShaderStruct> parseStructs(SourceLines source) {
|
||||
Matcher matcher = ShaderStruct.PATTERN.matcher(source);
|
||||
|
||||
ImmutableMap.Builder<String, ShaderStruct> structs = ImmutableMap.builder();
|
||||
while (matcher.find()) {
|
||||
Span self = Span.fromMatcher(this, matcher);
|
||||
Span name = Span.fromMatcher(this, matcher, 1);
|
||||
Span body = Span.fromMatcher(this, matcher, 2);
|
||||
Span variableName = Span.fromMatcher(this, matcher, 3);
|
||||
Span self = Span.fromMatcher(source, matcher);
|
||||
Span name = Span.fromMatcher(source, matcher, 1);
|
||||
Span body = Span.fromMatcher(source, matcher, 2);
|
||||
Span variableName = Span.fromMatcher(source, matcher, 3);
|
||||
|
||||
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.
|
||||
*/
|
||||
private ImmutableMap<String, ShaderField> parseFields(String source) {
|
||||
private static ImmutableMap<String, ShaderField> parseFields(SourceLines source) {
|
||||
Matcher matcher = ShaderField.PATTERN.matcher(source);
|
||||
|
||||
ImmutableMap.Builder<String, ShaderField> fields = ImmutableMap.builder();
|
||||
while (matcher.find()) {
|
||||
Span self = Span.fromMatcher(this, matcher);
|
||||
Span location = Span.fromMatcher(this, matcher, 1);
|
||||
Span decoration = Span.fromMatcher(this, matcher, 2);
|
||||
Span type = Span.fromMatcher(this, matcher, 3);
|
||||
Span name = Span.fromMatcher(this, matcher, 4);
|
||||
Span self = Span.fromMatcher(source, matcher);
|
||||
Span location = Span.fromMatcher(source, matcher, 1);
|
||||
Span decoration = Span.fromMatcher(source, matcher, 2);
|
||||
Span type = Span.fromMatcher(source, matcher, 3);
|
||||
Span name = Span.fromMatcher(source, matcher, 4);
|
||||
|
||||
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.
|
||||
*/
|
||||
private static int findEndOfBlock(String source, int start) {
|
||||
private static int findEndOfBlock(CharSequence source, int start) {
|
||||
int blockDepth = 0;
|
||||
for (int i = start + 1; i < source.length(); i++) {
|
||||
char ch = source.charAt(i);
|
||||
|
||||
if (ch == '{') blockDepth++;
|
||||
else if (ch == '}') blockDepth--;
|
||||
if (ch == '{') {
|
||||
blockDepth++;
|
||||
} else if (ch == '}') {
|
||||
blockDepth--;
|
||||
}
|
||||
|
||||
if (blockDepth < 0) {
|
||||
return i;
|
||||
|
|
|
@ -11,11 +11,13 @@ import com.jozufozu.flywheel.glsl.span.CharPos;
|
|||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import it.unimi.dsi.fastutil.ints.IntLists;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class SourceLines implements CharSequence {
|
||||
|
||||
private static final Pattern newLine = Pattern.compile("(\\r\\n|\\r|\\n)");
|
||||
|
||||
public final ResourceLocation name;
|
||||
/**
|
||||
* 0-indexed line to char pos mapping.
|
||||
*/
|
||||
|
@ -27,7 +29,8 @@ public class SourceLines implements CharSequence {
|
|||
private final ImmutableList<String> lines;
|
||||
public final String raw;
|
||||
|
||||
public SourceLines(String raw) {
|
||||
public SourceLines(ResourceLocation name, String raw) {
|
||||
this.name = name;
|
||||
this.raw = raw;
|
||||
this.lineStarts = createLineLookup(raw);
|
||||
this.lines = getLines(raw, lineStarts);
|
||||
|
|
|
@ -59,6 +59,10 @@ public class ErrorBuilder {
|
|||
return pointAtFile(file.name.toString());
|
||||
}
|
||||
|
||||
public ErrorBuilder pointAtFile(SourceLines source) {
|
||||
return pointAtFile(source.name.toString());
|
||||
}
|
||||
|
||||
public ErrorBuilder pointAtFile(String file) {
|
||||
lines.add(new FileLine(file));
|
||||
return this;
|
||||
|
@ -69,13 +73,13 @@ public class ErrorBuilder {
|
|||
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);
|
||||
|
||||
return this.pointAtFile(sourceFile)
|
||||
return this.pointAtFile(source)
|
||||
.pointAt(span, 0);
|
||||
}
|
||||
|
||||
|
@ -85,12 +89,12 @@ public class ErrorBuilder {
|
|||
|
||||
public ErrorBuilder pointAt(Span span, int ctxLines) {
|
||||
if (span.lines() == 1) {
|
||||
SourceLines lines = span.getSourceFile().source;
|
||||
SourceLines lines = span.source();
|
||||
|
||||
int spanLine = span.firstLine();
|
||||
int firstCol = span.getStart()
|
||||
int firstCol = span.start()
|
||||
.col();
|
||||
int lastCol = span.getEnd()
|
||||
int lastCol = span.end()
|
||||
.col();
|
||||
|
||||
pointAtLine(lines, spanLine, ctxLines, firstCol, lastCol);
|
||||
|
|
|
@ -62,7 +62,7 @@ public class ErrorReporter {
|
|||
}
|
||||
|
||||
public ErrorBuilder generateSpanError(Span span, String message) {
|
||||
SourceFile file = span.getSourceFile();
|
||||
var file = span.source();
|
||||
|
||||
return error(message).pointAtFile(file)
|
||||
.pointAt(span, 2);
|
||||
|
|
|
@ -4,16 +4,6 @@ import java.util.regex.Pattern;
|
|||
|
||||
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 final Span self;
|
||||
public final Span file;
|
||||
|
||||
public Import(Span self, Span file) {
|
||||
this.self = self;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
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.
|
||||
*/
|
||||
public class ErrorSpan extends Span {
|
||||
public ErrorSpan(SourceFile in, int loc) {
|
||||
public ErrorSpan(SourceLines in, int 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);
|
||||
}
|
||||
|
||||
public ErrorSpan(SourceFile in, CharPos start, CharPos end) {
|
||||
public ErrorSpan(SourceLines in, CharPos start, CharPos end) {
|
||||
super(in, start, end);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
package com.jozufozu.flywheel.glsl.span;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
import com.jozufozu.flywheel.glsl.parse.ShaderFunction;
|
||||
import com.jozufozu.flywheel.glsl.parse.ShaderStruct;
|
||||
import com.jozufozu.flywheel.glsl.SourceLines;
|
||||
|
||||
/**
|
||||
* A segment of code in a {@link SourceFile}.
|
||||
|
@ -17,16 +15,15 @@ import com.jozufozu.flywheel.glsl.parse.ShaderStruct;
|
|||
* </p>
|
||||
*/
|
||||
public abstract class Span implements CharSequence, Comparable<Span> {
|
||||
|
||||
protected final SourceFile in;
|
||||
protected final SourceLines in;
|
||||
protected final CharPos start;
|
||||
protected final CharPos end;
|
||||
|
||||
public Span(SourceFile in, int start, int end) {
|
||||
this(in, in.source.getCharPos(start), in.source.getCharPos(end));
|
||||
public Span(SourceLines in, int start, int 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.start = start;
|
||||
this.end = end;
|
||||
|
@ -35,29 +32,29 @@ public abstract class Span implements CharSequence, Comparable<Span> {
|
|||
/**
|
||||
* @return The file that contains this code segment.
|
||||
*/
|
||||
public SourceFile getSourceFile() {
|
||||
public SourceLines source() {
|
||||
return in;
|
||||
}
|
||||
|
||||
public CharPos getStart() {
|
||||
public CharPos start() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public CharPos getEnd() {
|
||||
public CharPos end() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the string index at the (inclusive) beginning of this code segment.
|
||||
*/
|
||||
public int getStartPos() {
|
||||
public int startIndex() {
|
||||
return start.pos();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the string index at the (exclusive) end of this code segment.
|
||||
*/
|
||||
public int getEndPos() {
|
||||
public int endIndex() {
|
||||
return end.pos();
|
||||
}
|
||||
|
||||
|
@ -93,12 +90,12 @@ public abstract class Span implements CharSequence, Comparable<Span> {
|
|||
|
||||
@Override
|
||||
public int length() {
|
||||
return getEndPos() - getStartPos();
|
||||
return endIndex() - startIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return in.source.charAt(start.pos() + index);
|
||||
return in.charAt(start.pos() + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,7 +108,7 @@ public abstract class Span implements CharSequence, Comparable<Span> {
|
|||
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));
|
||||
}
|
||||
|
||||
|
@ -119,7 +116,7 @@ public abstract class Span implements CharSequence, Comparable<Span> {
|
|||
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());
|
||||
}
|
||||
|
||||
|
@ -127,22 +124,8 @@ public abstract class Span implements CharSequence, Comparable<Span> {
|
|||
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
|
||||
public int compareTo(@NotNull Span o) {
|
||||
return Integer.compareUnsigned(getStartPos(), o.getStartPos());
|
||||
return Integer.compareUnsigned(startIndex(), o.startIndex());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
package com.jozufozu.flywheel.glsl.span;
|
||||
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
import com.jozufozu.flywheel.glsl.SourceLines;
|
||||
|
||||
public class StringSpan extends Span {
|
||||
|
||||
public StringSpan(SourceFile in, int start, int end) {
|
||||
super(in, start, end);
|
||||
}
|
||||
|
||||
public StringSpan(SourceFile in, CharPos start, CharPos end) {
|
||||
public StringSpan(SourceLines in, int start, int end) {
|
||||
super(in, start, end);
|
||||
}
|
||||
|
||||
|
@ -19,7 +15,7 @@ public class StringSpan extends Span {
|
|||
|
||||
@Override
|
||||
public String get() {
|
||||
return in.source.raw.substring(start.pos(), end.pos());
|
||||
return in.raw.substring(start.pos(), end.pos());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue