diff --git a/src/main/java/org/taumc/glsl/InjectorPoint.java b/src/main/java/org/taumc/glsl/InjectorPoint.java new file mode 100644 index 0000000..ac448a3 --- /dev/null +++ b/src/main/java/org/taumc/glsl/InjectorPoint.java @@ -0,0 +1,40 @@ +package org.taumc.glsl; + +import org.taumc.glsl.grammar.GLSLParser; +import org.taumc.glsl.grammar.GLSLParserBaseListener; + +import java.util.concurrent.atomic.AtomicReference; + +public class InjectorPoint extends GLSLParserBaseListener { + + private final Transformer transformer; + private final boolean function; + + public InjectorPoint(Transformer transformer, boolean function) { + this.transformer = transformer; + this.function = function; + } + + @Override + public void enterFunction_definition(GLSLParser.Function_definitionContext ctx) { + if (ctx.getParent() instanceof GLSLParser.External_declarationContext list) { + transformer.function = list; + transformer.variable = list; + } + } + + @Override + public void enterStorage_qualifier(GLSLParser.Storage_qualifierContext ctx) { + if (function) { + return; + } + var parent = ctx.getParent(); + while (!(parent instanceof GLSLParser.External_declarationContext list)) { + if (parent.getParent() == null) { + return; + } + parent = parent.getParent(); + } + transformer.variable = list; + } +} diff --git a/src/main/java/org/taumc/glsl/Main.java b/src/main/java/org/taumc/glsl/Main.java index 0f7de6c..aa8297b 100644 --- a/src/main/java/org/taumc/glsl/Main.java +++ b/src/main/java/org/taumc/glsl/Main.java @@ -30,21 +30,23 @@ public static void main(String[] args) throws Exception { parser.setBuildParseTree(true); var translationUnit = parser.translation_unit(); - Util.injectVariable(translationUnit, "in ivec2 a_LightCoord2;"); - Util.rename(translationUnit, "a_Color", "rewritten_Color"); + Transformer transformer = new Transformer(translationUnit); + + transformer.injectVariable("in ivec2 a_LightCoord2;"); + transformer.rename("a_Color", "rewritten_Color"); Set found = new HashSet<>(); - Util.renameArray(translationUnit, "test", "replaced", found); + transformer.renameArray("test", "replaced", found); //Util.removeVariable(translationUnit, "_vert_tex_diffuse_coord"); - Util.removeVariable(translationUnit, "testing"); - Util.removeConstAssignment(translationUnit); - Util.renameFunctionCall(translationUnit, "_vert_init", "newCall"); - Util.renameAndWrapShadow(translationUnit, "function", "wrapped"); - Util.prependMain(translationUnit, "injected = 5;"); - Util.replaceExpression(translationUnit, "vartest", "unint(5)"); - Util.removeUnusedFunctions(translationUnit); - Util.rewriteStructArrays(translationUnit); - Util.renameFunctionCall(translationUnit, "texture2D", "texture"); - Util.replaceExpression(translationUnit, "gl_TextureMatrix[0]", "mat4(1.0f)"); + transformer.removeVariable("testing"); + transformer.removeConstAssignment(); + transformer.renameFunctionCall("_vert_init", "newCall"); + transformer.renameAndWrapShadow("function", "wrapped"); + transformer.prependMain("injected = 5;"); + transformer.replaceExpression("vartest", "unint(5)"); + transformer.removeUnusedFunctions(); + transformer.rewriteStructArrays(); + transformer.renameFunctionCall("texture2D", "texture"); + transformer.replaceExpression("gl_TextureMatrix[0]", "mat4(1.0f)"); System.out.println(getFormattedShader(translationUnit)); diff --git a/src/main/java/org/taumc/glsl/ShaderParser.java b/src/main/java/org/taumc/glsl/ShaderParser.java new file mode 100644 index 0000000..df48cd7 --- /dev/null +++ b/src/main/java/org/taumc/glsl/ShaderParser.java @@ -0,0 +1,76 @@ +package org.taumc.glsl; + +import com.github.bsideup.jabel.Desugar; +import org.antlr.v4.runtime.BailErrorStrategy; +import org.antlr.v4.runtime.BufferedTokenStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.ConsoleErrorListener; +import org.antlr.v4.runtime.DefaultErrorStrategy; +import org.antlr.v4.runtime.Parser; +import org.antlr.v4.runtime.atn.PredictionMode; +import org.taumc.glsl.grammar.GLSLLexer; +import org.taumc.glsl.grammar.GLSLParser; +import org.taumc.glsl.grammar.GLSLPreParser; + +import java.util.function.Function; + +public class ShaderParser { + @Desugar + public record ParsedShader(GLSLPreParser.Translation_unitContext pre, GLSLParser.Translation_unitContext full) {} + + private static void configureNoError(Parser parser) { + parser.setErrorHandler(new BailErrorStrategy()); + parser.removeErrorListeners(); + parser.getInterpreter().setPredictionMode(PredictionMode.SLL); + } + + private static void configureError(Parser parser) { + parser.setErrorHandler(new DefaultErrorStrategy()); + parser.addErrorListener(ConsoleErrorListener.INSTANCE); + parser.getInterpreter().setPredictionMode(PredictionMode.LL); + } + + private static ParsedShader tryParse(GLSLLexer lexer, GLSLPreParser preParser, GLSLParser parser) { + var pre = preParser.translation_unit(); + lexer.reset(); + parser.reset(); + var full = parser.translation_unit(); + return new ParsedShader(pre, full); + } + + public static ParsedShader parseShader(String shader) { + GLSLLexer lexer = new GLSLLexer(CharStreams.fromString(shader)); + GLSLPreParser preParser = new GLSLPreParser(new BufferedTokenStream(lexer)); + GLSLParser parser = new GLSLParser(new CommonTokenStream(lexer)); + preParser.setBuildParseTree(true); + parser.setBuildParseTree(true); + configureNoError(parser); + configureNoError(preParser); + try { + return tryParse(lexer, preParser, parser); + } catch (Exception e) { + lexer.reset(); + parser.reset(); + preParser.reset(); + configureError(parser); + configureError(preParser); + return tryParse(lexer, preParser, parser); + } + } + + public static T parseSnippet(String codeSnippet, Function parseLogic) { + GLSLLexer lexer = new GLSLLexer(CharStreams.fromString(codeSnippet)); + GLSLParser parser = new GLSLParser(new CommonTokenStream(lexer)); + parser.setBuildParseTree(true); + configureNoError(parser); + try { + return parseLogic.apply(parser); + } catch (Exception e) { + lexer.reset(); + parser.reset(); + configureError(parser); + return parseLogic.apply(parser); + } + } +} diff --git a/src/main/java/org/taumc/glsl/Transformer.java b/src/main/java/org/taumc/glsl/Transformer.java index 232e3db..d958d76 100644 --- a/src/main/java/org/taumc/glsl/Transformer.java +++ b/src/main/java/org/taumc/glsl/Transformer.java @@ -1,12 +1,15 @@ package org.taumc.glsl; +import com.github.bsideup.jabel.Desugar; +import com.ibm.icu.impl.CollectionSet; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonToken; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.RuleContext; +import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.ParseTreeWalker; import org.antlr.v4.runtime.tree.TerminalNode; -import org.taumc.glsl.grammar.GLSLLexer; import org.taumc.glsl.grammar.GLSLParser; import java.util.*; @@ -19,9 +22,53 @@ public class Transformer { private final GLSLParser.Translation_unitContext root; + private final List functionDefinitions; + private final List> postfixExpressions; + private final List assignmentExpressions; + private final List variableIdentifiers; + private final List parameterDeclarations; + private final List typelessDeclarations; + private final List functionPrototypes; + private final List> binaryExpressions; + private final List storageQualifiers; + private final List structDeclarations; + private final List singleDeclarations; + private final List textures; + public GLSLParser.External_declarationContext variable = null; + public GLSLParser.External_declarationContext function = null; + + @Desugar + private record CachedTextExpression(T expr, String exprText) { + @Override + public boolean equals(Object obj) { + if(obj instanceof CachedTextExpression cachedExpr) { + return cachedExpr.expr == this.expr; + } else { + return false; + } + } + + @Override + public int hashCode() { + return System.identityHashCode(expr); + } + } public Transformer(GLSLParser.Translation_unitContext root) { this.root = root; + this.functionDefinitions = new ArrayList<>(); + this.postfixExpressions = new ArrayList<>(); + this.assignmentExpressions = new ArrayList<>(); + this.variableIdentifiers = new ArrayList<>(); + this.parameterDeclarations = new ArrayList<>(); + this.typelessDeclarations = new ArrayList<>(); + this.functionPrototypes = new ArrayList<>(); + this.binaryExpressions = new ArrayList<>(); + this.storageQualifiers = new ArrayList<>(); + this.structDeclarations = new ArrayList<>(); + this.singleDeclarations = new ArrayList<>(); + this.textures = new ArrayList<>(); + ParseTreeWalker.DEFAULT.walk(new TransformerCollector(this), root); } /** @@ -29,100 +76,285 @@ public Transformer(GLSLParser.Translation_unitContext root) { * @param code the to inject code */ public void injectVariable(String code) { - GLSLLexer lexer = new GLSLLexer(CharStreams.fromString(code)); - GLSLParser parser = new GLSLParser(new CommonTokenStream(lexer)); - var insert = parser.external_declaration(); + var insert = ShaderParser.parseSnippet(code, GLSLParser::external_declaration); + + if (variable == null) { + if (!storageQualifiers.isEmpty()) { + var parent = storageQualifiers.get(0).getParent(); + while (!(parent instanceof GLSLParser.External_declarationContext)) { + if (parent.getParent() == null) { + break; + } + parent = parent.getParent(); + } + if (parent instanceof GLSLParser.External_declarationContext list) { + variable = list; + } + } + } - AtomicReference ref = new AtomicReference<>(); - ParseTreeWalker.DEFAULT.walk(new VariableInjector(ref), root); + if (variable == null){ + if (functionDefinitions.get(0).getParent() instanceof GLSLParser.External_declarationContext list) { + variable = list; + } + } - var left = ref.get(); - if (left != null) { - var parent = left.getParent(); - int i = parent.children.indexOf(left); + if (variable != null) { + var parent = variable.getParent(); + int i = parent.children.indexOf(variable); parent.children.add(i, insert); insert.setParent(parent); + scanNode(insert); + ParseTreeWalker.DEFAULT.walk(new InjectorPoint(this, false), insert); } } public void injectFunction(String code) { - GLSLLexer lexer = new GLSLLexer(CharStreams.fromString(code)); - GLSLParser parser = new GLSLParser(new CommonTokenStream(lexer)); - var insert = parser.external_declaration(); + var insert = ShaderParser.parseSnippet(code, GLSLParser::external_declaration); - AtomicReference ref = new AtomicReference<>(); - ParseTreeWalker.DEFAULT.walk(new FunctionInjector(ref), root); + if (function == null) { + if (functionDefinitions.get(0).getParent() instanceof GLSLParser.External_declarationContext list) { + function = list; + } + } - var left = ref.get(); - if (left != null) { - var parent = left.getParent(); - int i = parent.children.indexOf(left); + if (function != null) { + var parent = function.getParent(); + int i = parent.children.indexOf(function); parent.children.add(i, insert); insert.setParent(parent); + scanNode(insert); + ParseTreeWalker.DEFAULT.walk(new InjectorPoint(this, true), insert); } } + public void injectAtEnd(String code) { + var insert = ShaderParser.parseSnippet(code, GLSLParser::external_declaration); + + root.children.add(insert); + scanNode(insert); + } + public void rename(String oldName, String newName) { rename(Collections.singletonMap(oldName, newName)); } public void rename(Map names) { - ParseTreeWalker.DEFAULT.walk(new Renamer(names), root); + List nodes = new ArrayList<>(); + nodes.addAll(typelessDeclarations.stream().map(GLSLParser.Typeless_declarationContext::IDENTIFIER).collect(Collectors.toList())); + nodes.addAll(variableIdentifiers.stream().map(GLSLParser.Variable_identifierContext::IDENTIFIER).collect(Collectors.toList())); + nodes.addAll(functionPrototypes.stream().map(GLSLParser.Function_prototypeContext::IDENTIFIER).collect(Collectors.toList())); + for (var node : nodes) { + Token token = node.getSymbol(); + if(token instanceof CommonToken cToken) { + String replacement = names.get(cToken.getText()); + if(replacement != null) { + cToken.setText(replacement); + } + } + } } public void replaceExpression(String oldCode, String newCode) { - ParseTreeWalker.DEFAULT.walk(new ReplaceExpression(oldCode, newCode), root); + var oldExpression = ShaderParser.parseSnippet(oldCode, GLSLParser::binary_expression); + String oldText = oldExpression.getText(); + var exprList = new ArrayList<>(binaryExpressions); + for (var cachedExpr : exprList) { + String ctxText = cachedExpr.exprText(); + var ctx = cachedExpr.expr(); + if (ctxText.equals(oldText)) { + replaceNode(ctx, ShaderParser.parseSnippet(newCode, GLSLParser::binary_expression)); + } else if (ctxText.startsWith(oldText)) { + if (ctx.unary_expression() != null) { + if (ctx.unary_expression().postfix_expression() != null) { + if (ctx.unary_expression().postfix_expression().postfix_expression() != null) { + var postfix = ctx.unary_expression().postfix_expression().postfix_expression(); + while (postfix.getText().startsWith(oldText) && !postfix.getText().equals(oldText)) { + if (postfix.postfix_expression() != null) { + postfix = postfix.postfix_expression(); + } else { + break; + } + } + if (postfix.getText().equals(oldText)) { + replaceNode(postfix, ShaderParser.parseSnippet(newCode, GLSLParser::unary_expression)); + } + } + } + } + } + } + } + + private void replaceNode(ParserRuleContext oldNode, ParserRuleContext newNode) { + scanNode(newNode); + newNode.parent = oldNode.getParent(); + int i = oldNode.getParent().children.indexOf(oldNode); + oldNode.getParent().children.set(i, newNode); + removeNode(oldNode); + } + + private void removeNode(ParserRuleContext node) { + ParseTreeWalker.DEFAULT.walk(new TransformerRemover(this), node); + } + + private void scanNode(ParserRuleContext node) { + ParseTreeWalker.DEFAULT.walk(new TransformerCollector(this), node); } public void prependMain(String code) { - ParseTreeWalker.DEFAULT.walk(new PrependFunction("main", code), root); + var insert = ShaderParser.parseSnippet(code, GLSLParser::statement); + for (var ctx : functionDefinitions) { + if (ctx.function_prototype().IDENTIFIER().getText().equals("main")) { + ctx.compound_statement_no_new_scope().statement_list().children.add(0, insert); + scanNode(insert); + } + } } public void removeVariable(String code) { - AtomicReference top = new AtomicReference<>(); - ParseTreeWalker.DEFAULT.walk(new RemoveVariable(code, top), root); - if (top.get() != null) { - if (top.get().getParent() instanceof GLSLParser.Init_declarator_listContext listContext) { - int i = listContext.children.indexOf(top.get()); - listContext.children.remove(i-1); - listContext.children.remove(i-1); - } else if (top.get().parent instanceof GLSLParser.Single_declarationContext singleContext) { - singleContext.getParent().getParent().getParent().getParent().children.remove(singleContext.getParent().getParent().getParent()); + ParserRuleContext typeless = null; + var typelessDeclaration = new ArrayList<>(this.typelessDeclarations); + for (var ctx : typelessDeclaration) { + if (ctx.IDENTIFIER() != null) { + Token token = ctx.IDENTIFIER().getSymbol(); + if(token instanceof CommonToken cToken) { + if(code.equals(cToken.getText())) { + if (ctx.getParent() instanceof GLSLParser.Single_declarationContext) { + if (ctx.getParent().getParent() instanceof GLSLParser.Init_declarator_listContext list) { + if (!list.typeless_declaration().isEmpty()) { + var entry = list.typeless_declaration(0); + cToken.setText(entry.getText()); + typeless = entry; + break; + } else { + typeless = ctx; + } + } + } + else if (ctx.getParent() instanceof GLSLParser.Init_declarator_listContext) { + typeless = ctx; + break; + } + } + } } } + + if (typeless == null) { + return; + } + + if (typeless.getParent() instanceof GLSLParser.Init_declarator_listContext listContext) { + int i = listContext.children.indexOf(typeless); + if (listContext.children.remove(i-1) instanceof ParserRuleContext context) { + removeNode(context); + } + if (listContext.children.remove(i-1) instanceof ParserRuleContext context) { + removeNode(context); + } + } else if (typeless.parent instanceof GLSLParser.Single_declarationContext singleContext) { + ParserRuleContext node = singleContext.getParent().getParent().getParent(); + node.getParent().children.remove(node); + removeNode(node); + } } public int findType(String code) { - AtomicInteger type = new AtomicInteger(); - FastTreeWalker.walk(new TypeFinder(code, type), root); - return type.get(); + for (var ctx : singleDeclarations) { + if (ctx.typeless_declaration() == null) { + return 0; + } + if (ctx.typeless_declaration().IDENTIFIER().getSymbol() instanceof CommonToken cToken) { + if (cToken.getText().equals(code)) { + if (ctx.fully_specified_type().type_specifier().type_specifier_nonarray().getChild(0) instanceof TerminalNode node) { + if (node.getSymbol() instanceof CommonToken t) { + return t.getType(); + } + } + } + } + if (ctx.getParent() instanceof GLSLParser.Init_declarator_listContext listContext) { + for (var entry : listContext.typeless_declaration()) { + if (entry.IDENTIFIER().getSymbol() instanceof CommonToken cToken) { + if (cToken.getText().equals(code)) { + if (ctx.fully_specified_type().type_specifier().type_specifier_nonarray().getChild(0) instanceof TerminalNode node) { + if (node.getSymbol() instanceof CommonToken t) { + return t.getType(); + } + } + } + } + } + } + } + return 0; } public void appendMain(String code) { - ParseTreeWalker.DEFAULT.walk(new AppendFunction("main", code), root); + var insert = ShaderParser.parseSnippet(code, GLSLParser::statement); + for (var ctx : functionDefinitions) { + if (ctx.function_prototype().IDENTIFIER().getText().equals("main")) { + ctx.compound_statement_no_new_scope().statement_list().children.add(insert); + scanNode(insert); + } + } } public boolean containsCall(String name) { - AtomicBoolean atomicBoolean = new AtomicBoolean(false); - FastTreeWalker.walk(new IdentifierCollector(id -> { - if(id.equals(name)) { - atomicBoolean.set(true); - return false; - } else { - return true; + for (var ctx : variableIdentifiers) { + if (ctx.IDENTIFIER().getSymbol() instanceof CommonToken cToken) { + if (cToken.getText().equals(name)) { + return true; + } } - }), root); - return atomicBoolean.get(); + } + return false; } public boolean hasVariable(String name) { - AtomicBoolean atomicBoolean = new AtomicBoolean(false); - ParseTreeWalker.DEFAULT.walk(new HasVariable(name, atomicBoolean), root); - return atomicBoolean.get(); + List nodes = new ArrayList<>(); + nodes.addAll(typelessDeclarations.stream().map(GLSLParser.Typeless_declarationContext::IDENTIFIER).collect(Collectors.toList())); + nodes.addAll(functionPrototypes.stream().map(GLSLParser.Function_prototypeContext::IDENTIFIER).collect(Collectors.toList())); + for (var node : nodes) { + Token token = node.getSymbol(); + if(token instanceof CommonToken cToken) { + if (name.equals(cToken.getText())) { + return true; + } + } + } + return false; } public void renameArray(String oldName, String newName, Set found) { - ParseTreeWalker.DEFAULT.walk(new ArrayExpressionRewriteListener(Collections.singletonMap(oldName, newName), found), root); + renameArray(Collections.singletonMap(oldName, newName), found); + } + + public void renameArray(Map replacements, Set found) { + for (var cachedExpr : postfixExpressions) { + var ctx = cachedExpr.expr(); + if (ctx.postfix_expression() == null) { + continue; + } + if (ctx.postfix_expression().primary_expression() == null) { + continue; + } + if (ctx.postfix_expression().primary_expression().variable_identifier() == null) { + continue; + } + if (ctx.postfix_expression().primary_expression().variable_identifier().IDENTIFIER().getSymbol() instanceof CommonToken cToken) { + String replacement = replacements.get(cToken.getText()); + if(replacement != null && ctx.integer_expression() != null) { + String i = ctx.integer_expression().getText(); + found.add(Integer.parseInt(i)); + cToken.setText(replacement + i); + ctx.removeLastChild(); + ctx.removeLastChild(); + ctx.removeLastChild(); + } + } + } } /** @@ -139,35 +371,55 @@ public void renameFunctionCall(String oldName, String newName) { } public void renameFunctionCall(Map names) { - ParseTreeWalker.DEFAULT.walk(new ExpressionRenamer(names), root); + List nodes = new ArrayList<>(); + nodes.addAll(functionPrototypes.stream().map(GLSLParser.Function_prototypeContext::IDENTIFIER).collect(Collectors.toList())); + nodes.addAll(variableIdentifiers.stream().map(GLSLParser.Variable_identifierContext::IDENTIFIER).collect(Collectors.toList())); + nodes.addAll(textures.stream().map(c -> { + if (c.TEXTURE2D() != null) { + return c.TEXTURE2D(); + } else { + return c.TEXTURE3D(); + } + }).collect(Collectors.toList())); + for (var node : nodes) { + Token token = node.getSymbol(); + if(token instanceof CommonToken cToken) { + String replacement = names.get(cToken.getText()); + if(replacement != null) { + cToken.setText(replacement); + } + } + } } public void renameAndWrapShadow(String oldName, String newName) { - ParseTreeWalker.DEFAULT.walk( new FunctionCallWrapper(oldName, "vec4"), root); + var postfixExpression = new ArrayList<>(postfixExpressions); + for (var cachedExpr : postfixExpression) { + String function = cachedExpr.exprText(); + if (cachedExpr.expr().function_call_parameters() != null && function.startsWith(oldName + "(")) { + function = "vec4" + "(" + function + ")"; + var def = ShaderParser.parseSnippet(function, GLSLParser::postfix_expression); + replaceNode(cachedExpr.expr(), def); + } + } renameFunctionCall(oldName, newName); } - public List collectFunctions(GLSLParser.Translation_unitContext root) { - List result = new ArrayList<>(); - ParseTreeWalker.DEFAULT.walk(new FunctionCollector(result), root); - return result; - } - public void removeFunction(String name) { - AtomicReference context = new AtomicReference<>(); - FastTreeWalker.walk(new FunctionRemover(name, context), root); - if (context.get() != null) { - context.get().getParent().children.remove(context.get()); + var functionPrototype = new ArrayList<>(functionPrototypes); + for (var ctx : functionPrototype) { + if (ctx.IDENTIFIER().getText().equals(name)) { + if (ctx.getParent().getParent() instanceof GLSLParser.External_declarationContext declarationContext) { + declarationContext.getParent().children.remove(declarationContext); + removeNode(declarationContext); + } + } } } public void removeUnusedFunctions() { - List result = collectFunctions(root); - Set usedIdentifiers = new HashSet<>(); - FastTreeWalker.walk(new IdentifierCollector(id -> { - usedIdentifiers.add(id); - return true; - }), root); + List result = functionPrototypes.stream().map(c -> c.IDENTIFIER().getText()).collect(Collectors.toList()); + List usedIdentifiers = variableIdentifiers.stream().map(c -> c.IDENTIFIER().getText()).collect(Collectors.toList()); List functionsToRemove = result.stream().filter(name -> !usedIdentifiers.contains(name) && !name.equals("main")).collect(Collectors.toList()); // TODO - remove all the functions in one walk of the tree for (String name : functionsToRemove) { @@ -177,13 +429,67 @@ public void removeUnusedFunctions() { public Map> findConstParameter() { Map> functions = new HashMap<>(); - ParseTreeWalker.DEFAULT.walk(new ConstParameterFinder(functions), root); + for (var ctx : parameterDeclarations) { + GLSLParser.Type_qualifierContext typeQualifierContext = ctx.type_qualifier(); + if (typeQualifierContext == null) { + continue; + } + GLSLParser.Single_type_qualifierContext singleTypeQualifierContext = typeQualifierContext.single_type_qualifier(0); + if (singleTypeQualifierContext == null) { + continue; + } + GLSLParser.Storage_qualifierContext storageQualifierContext = singleTypeQualifierContext.storage_qualifier(); + if (storageQualifierContext != null && storageQualifierContext.CONST() != null) { + if (ctx.getParent().getParent() instanceof GLSLParser.Function_prototypeContext proto) { + if (functions.containsKey(proto.IDENTIFIER().getText())) { + functions.get(proto.IDENTIFIER().getText()).add(ctx.parameter_declarator().IDENTIFIER().getText()); + + } else { + List params = new ArrayList<>(); + params.add(ctx.parameter_declarator().IDENTIFIER().getText()); + functions.put(proto.IDENTIFIER().getText(), params); + } + } + } + } return functions; } public void removeConstAssignment(Map> functions) { for (Map.Entry> entry : functions.entrySet()) { - ParseTreeWalker.DEFAULT.walk(new ConstAssignmentRemover(entry.getKey(), entry.getValue()), root); + for (var ctx : variableIdentifiers) { + if (entry.getValue().contains(ctx.IDENTIFIER().getText())) { + var parent = ctx.getParent(); + while (!(parent instanceof GLSLParser.Function_definitionContext definitionContext)) { + parent = parent.getParent(); + if (parent == null) { + return; + } + } + + if (definitionContext.function_prototype().IDENTIFIER().getText().equals(entry.getKey())) { + parent = ctx.getParent(); + while (!(parent instanceof GLSLParser.Single_declarationContext declarationContext)) { + parent = parent.getParent(); + if (parent == null) { + return; + } + } + + entry.getValue().add(declarationContext.typeless_declaration().IDENTIFIER().getText()); + + GLSLParser.Type_qualifierContext typeQualifierContext = declarationContext.fully_specified_type().type_qualifier(); + if (typeQualifierContext == null || typeQualifierContext.single_type_qualifier(0) == null) { + return; + } + GLSLParser.Storage_qualifierContext storageQualifierContext = typeQualifierContext.single_type_qualifier(0).storage_qualifier(); + if (storageQualifierContext != null && storageQualifierContext.CONST() != null) { + declarationContext.fully_specified_type().children.remove(typeQualifierContext); + removeNode(typeQualifierContext); + } + } + } + } } } @@ -206,25 +512,158 @@ public void makeOutDeclaration(GLSLParser.Single_declarationContext inDeclaratio } public Map findQualifiers(int type) { - Map result = new HashMap<>(); - ParseTreeWalker.DEFAULT.walk(new QualifierFinder(type, result), root); - return result; + Map nodes = new HashMap<>(); + mainLoop: + for (var ctx : storageQualifiers) { + if (ctx.children.get(0) instanceof TerminalNode node && + node.getSymbol() instanceof CommonToken token && + token.getType() == type) { + var parent = node.getParent(); + while (!(parent instanceof GLSLParser.Single_declarationContext declarationContext)) { + parent = parent.getParent(); + if (parent == null) { + continue mainLoop; + } + } + + nodes.put(declarationContext.typeless_declaration().IDENTIFIER().getText(), declarationContext); + + if (declarationContext.getParent() instanceof GLSLParser.Init_declarator_listContext listContext) { + if (listContext.typeless_declaration() != null) { + for (var entry : listContext.typeless_declaration()) { + nodes.put(entry.IDENTIFIER().getText(), declarationContext); + } + } + } + } + } + return nodes; } public boolean hasAssigment(String name) { - AtomicBoolean atomicBoolean = new AtomicBoolean(false); - ParseTreeWalker.DEFAULT.walk(new AssigmentChecker(name, atomicBoolean), root); - return atomicBoolean.get(); + for (var ctx : assignmentExpressions) { + if (ctx.unary_expression() != null && (ctx.unary_expression().getText().startsWith(name) || ctx.unary_expression().getText().startsWith(name + "."))) { + return true; + } + } + return false; } public void rewriteStructArrays() { - ParseTreeWalker.DEFAULT.walk(new StructArrayRewriter(), root); + for (var ctx : structDeclarations) { + if (ctx.type_specifier().array_specifier() != null) { + var array_specifier = ctx.type_specifier().array_specifier(); + if (array_specifier.dimension().get(0).constant_expression() != null) { + return; + } + ctx.type_specifier().children.remove(array_specifier); + for (var entry : ctx.struct_declarator_list().struct_declarator()) { + array_specifier.setParent(entry); + entry.children.add(array_specifier); + } + } + } } public List collectStorage() { - List tokens = new ArrayList<>(); - ParseTreeWalker.DEFAULT.walk(new StorageCollector(tokens), root); - return tokens; + return storageQualifiers.stream().filter(ctx -> ctx.getChild(0) instanceof TerminalNode).map(ctx -> (TerminalNode) ctx.getChild(0)).collect(Collectors.toList()); + } + + //Add + public void addFunctionDefinition(GLSLParser.Function_definitionContext ctx) { + this.functionDefinitions.add(ctx); + } + + public void addPostfix(GLSLParser.Postfix_expressionContext ctx) { + this.postfixExpressions.add(new CachedTextExpression<>(ctx, ctx.getText())); + } + + public void addAssignment(GLSLParser.Assignment_expressionContext ctx) { + this.assignmentExpressions.add(ctx); + } + + public void addVariable(GLSLParser.Variable_identifierContext ctx) { + this.variableIdentifiers.add(ctx); + } + + public void addParameter(GLSLParser.Parameter_declarationContext ctx) { + this.parameterDeclarations.add(ctx); + } + + public void addFunctionPrototype(GLSLParser.Function_prototypeContext ctx) { + this.functionPrototypes.add(ctx); + } + + public void addTypeless(GLSLParser.Typeless_declarationContext ctx) { + this.typelessDeclarations.add(ctx); + } + + public void addBinary(GLSLParser.Binary_expressionContext ctx) { + this.binaryExpressions.add(new CachedTextExpression<>(ctx, ctx.getText())); + } + + public void addStorage(GLSLParser.Storage_qualifierContext ctx) { + this.storageQualifiers.add(ctx); + } + + public void addStruct(GLSLParser.Struct_declarationContext ctx) { + this.structDeclarations.add(ctx); + } + + public void addSingle(GLSLParser.Single_declarationContext ctx) { + this.singleDeclarations.add(ctx); + } + + public void addTexture(GLSLParser.Type_specifier_nonarrayContext ctx) { + this.textures.add(ctx); + } + + //Remove + public void removeFunctionDefinition(GLSLParser.Function_definitionContext ctx) { + functionDefinitions.remove(ctx); + } + + public void removeFunctionPrototype(GLSLParser.Function_prototypeContext ctx) { + functionPrototypes.remove(ctx); + } + + public void removeParameter(GLSLParser.Parameter_declarationContext ctx) { + parameterDeclarations.remove(ctx); + } + + public void removeTypeless(GLSLParser.Typeless_declarationContext ctx) { + typelessDeclarations.remove(ctx); } + public void removeTexture(GLSLParser.Type_specifier_nonarrayContext ctx) { + textures.remove(ctx); + } + + public void removePostfix(GLSLParser.Postfix_expressionContext ctx) { + postfixExpressions.remove(new CachedTextExpression<>(ctx, null)); + } + + public void removeAssignment(GLSLParser.Assignment_expressionContext ctx) { + assignmentExpressions.remove(ctx); + } + + public void removeBinary(GLSLParser.Binary_expressionContext ctx) { + binaryExpressions.remove(new CachedTextExpression<>(ctx, null)); + } + + public void removeStorage(GLSLParser.Storage_qualifierContext ctx) { + storageQualifiers.remove(ctx); + } + + public void removeStruct(GLSLParser.Struct_declarationContext ctx) { + structDeclarations.remove(ctx); + } + + public void removeSingle(GLSLParser.Single_declarationContext ctx) { + singleDeclarations.remove(ctx); + } + + public void removeVariables(GLSLParser.Variable_identifierContext ctx) { + variableIdentifiers.remove(ctx); + } } diff --git a/src/main/java/org/taumc/glsl/TransformerCollector.java b/src/main/java/org/taumc/glsl/TransformerCollector.java new file mode 100644 index 0000000..dfa8ef3 --- /dev/null +++ b/src/main/java/org/taumc/glsl/TransformerCollector.java @@ -0,0 +1,78 @@ +package org.taumc.glsl; + +import org.taumc.glsl.grammar.GLSLParser; +import org.taumc.glsl.grammar.GLSLParserBaseListener; + +public class TransformerCollector extends GLSLParserBaseListener { + + private final Transformer transformer; + + public TransformerCollector(Transformer transformer) { + this.transformer = transformer; + } + + @Override + public void enterFunction_definition(GLSLParser.Function_definitionContext ctx) { + this.transformer.addFunctionDefinition(ctx); + } + + @Override + public void enterFunction_prototype(GLSLParser.Function_prototypeContext ctx) { + this.transformer.addFunctionPrototype(ctx); + } + + @Override + public void enterParameter_declaration(GLSLParser.Parameter_declarationContext ctx) { + this.transformer.addParameter(ctx); + } + + @Override + public void enterVariable_identifier(GLSLParser.Variable_identifierContext ctx) { + this.transformer.addVariable(ctx); + } + + @Override + public void enterTypeless_declaration(GLSLParser.Typeless_declarationContext ctx) { + this.transformer.addTypeless(ctx); + } + + @Override + public void enterType_specifier_nonarray(GLSLParser.Type_specifier_nonarrayContext ctx) { + if (ctx.TEXTURE2D() != null) { + this.transformer.addTexture(ctx); + } + if (ctx.TEXTURE3D() != null) { + this.transformer.addTexture(ctx); + } + } + + @Override + public void enterPostfix_expression(GLSLParser.Postfix_expressionContext ctx) { + this.transformer.addPostfix(ctx); + } + + @Override + public void exitAssignment_expression(GLSLParser.Assignment_expressionContext ctx) { + this.transformer.addAssignment(ctx); + } + + @Override + public void enterBinary_expression(GLSLParser.Binary_expressionContext ctx) { + this.transformer.addBinary(ctx); + } + + @Override + public void enterStorage_qualifier(GLSLParser.Storage_qualifierContext ctx) { + this.transformer.addStorage(ctx); + } + + @Override + public void enterStruct_declaration(GLSLParser.Struct_declarationContext ctx) { + this.transformer.addStruct(ctx); + } + + @Override + public void enterSingle_declaration(GLSLParser.Single_declarationContext ctx) { + this.transformer.addSingle(ctx); + } +} diff --git a/src/main/java/org/taumc/glsl/TransformerRemover.java b/src/main/java/org/taumc/glsl/TransformerRemover.java new file mode 100644 index 0000000..246f5e6 --- /dev/null +++ b/src/main/java/org/taumc/glsl/TransformerRemover.java @@ -0,0 +1,78 @@ +package org.taumc.glsl; + +import org.taumc.glsl.grammar.GLSLParser; +import org.taumc.glsl.grammar.GLSLParserBaseListener; + +public class TransformerRemover extends GLSLParserBaseListener { + + private final Transformer transformer; + + public TransformerRemover(Transformer transformer) { + this.transformer = transformer; + } + + @Override + public void enterFunction_definition(GLSLParser.Function_definitionContext ctx) { + this.transformer.removeFunctionDefinition(ctx); + } + + @Override + public void enterFunction_prototype(GLSLParser.Function_prototypeContext ctx) { + this.transformer.removeFunctionPrototype(ctx); + } + + @Override + public void enterParameter_declaration(GLSLParser.Parameter_declarationContext ctx) { + this.transformer.removeParameter(ctx); + } + + @Override + public void enterVariable_identifier(GLSLParser.Variable_identifierContext ctx) { + this.transformer.removeVariables(ctx); + } + + @Override + public void enterTypeless_declaration(GLSLParser.Typeless_declarationContext ctx) { + this.transformer.removeTypeless(ctx); + } + + @Override + public void enterType_specifier_nonarray(GLSLParser.Type_specifier_nonarrayContext ctx) { + if (ctx.TEXTURE2D() != null) { + this.transformer.removeTexture(ctx); + } + if (ctx.TEXTURE3D() != null) { + this.transformer.removeTexture(ctx); + } + } + + @Override + public void enterPostfix_expression(GLSLParser.Postfix_expressionContext ctx) { + this.transformer.removePostfix(ctx); + } + + @Override + public void exitAssignment_expression(GLSLParser.Assignment_expressionContext ctx) { + this.transformer.removeAssignment(ctx); + } + + @Override + public void enterBinary_expression(GLSLParser.Binary_expressionContext ctx) { + this.transformer.removeBinary(ctx); + } + + @Override + public void enterStorage_qualifier(GLSLParser.Storage_qualifierContext ctx) { + this.transformer.removeStorage(ctx); + } + + @Override + public void enterStruct_declaration(GLSLParser.Struct_declarationContext ctx) { + this.transformer.removeStruct(ctx); + } + + @Override + public void enterSingle_declaration(GLSLParser.Single_declarationContext ctx) { + this.transformer.removeSingle(ctx); + } +}