1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package shade.parsers;
 26 
 27 import optkl.textmodel.TextModel;
 28 import optkl.textmodel.terminal.ANSI;
 29 import optkl.textmodel.tokens.AbstractParentToken;
 30 import optkl.textmodel.tokens.Char;
 31 import optkl.textmodel.tokens.Close;
 32 import optkl.textmodel.tokens.Comment;
 33 import optkl.textmodel.tokens.FloatConst;
 34 import optkl.textmodel.tokens.IntConst;
 35 import optkl.textmodel.tokens.LeafReplacementToken;
 36 import optkl.textmodel.tokens.Open;
 37 import optkl.textmodel.tokens.Parent;
 38 import optkl.textmodel.tokens.Parenthesis;
 39 import optkl.textmodel.tokens.Seq;
 40 import optkl.textmodel.tokens.Token;
 41 import optkl.textmodel.tokens.Ws;
 42 import optkl.util.Regex;
 43 import shade.shaders.WavesShader;
 44 
 45 import java.util.List;
 46 
 47 import static optkl.textmodel.terminal.ANSI.BLACK;
 48 import static optkl.textmodel.terminal.ANSI.BLUE;
 49 import static optkl.textmodel.terminal.ANSI.CYAN;
 50 import static optkl.textmodel.terminal.ANSI.GREEN;
 51 import static optkl.textmodel.terminal.ANSI.PURPLE;
 52 import static optkl.textmodel.terminal.ANSI.RED;
 53 import static optkl.textmodel.terminal.ANSI.WHITE;
 54 import static optkl.textmodel.terminal.ANSI.YELLOW;
 55 
 56 public class ShaderModel extends TextModel {
 57     public static class Type extends LeafReplacementToken {
 58         public static final Regex regex = Regex.of("void|int|float|vec[234]|ivec[234]|mat[234]|imat[234]");
 59 
 60         public Type(Token t) {
 61             super(t);
 62         }
 63     }
 64 
 65     public static class Identifier extends LeafReplacementToken {
 66         public static final Regex regex = Regex.of("[a-zA-Z][a-zA-Z_0-9]*");
 67 
 68         public Identifier(Token t) {
 69             super(t);
 70         }
 71     }
 72 
 73     public static class ReservedWord extends LeafReplacementToken {
 74         public static final Regex regex = Regex.of("in|out|if|while|case|switch|break|for|new|return");
 75 
 76         public ReservedWord(Token t) {
 77             super(t);
 78         }
 79     }
 80 
 81     public static class Uniform extends LeafReplacementToken {
 82         public static final Regex regex = Regex.of("iMouse|iResolution|iTime|fragColor|fragCoord");
 83 
 84         public Uniform(Token t) {
 85             super(t);
 86         }
 87     }
 88 
 89     public static class MathFunc extends LeafReplacementToken {
 90         public static final Regex regex = Regex.of("cross|mul|add|div|sub|cos|sin|tan|atan|exp|abs|dot|sqrt|pow|clamp|min|max|mix|normalize|reflect|normal");
 91 
 92         public MathFunc(Token t) {
 93             super(t);
 94         }
 95     }
 96 
 97     public static class ArithmeticOperator extends LeafReplacementToken {
 98         public static final Regex regex = Regex.of("[+-/\\*]");
 99 
100         public ArithmeticOperator(Token t) {
101             super(t);
102         }
103     }
104 
105     public static class HashDefine extends LeafReplacementToken {
106         public HashDefine(Token hash, Token define) {
107             super(hash, define);
108         }
109     }
110 
111     public static class Declaration extends AbstractParentToken {
112         static TknPredicate3<Token> predicate = (l, ws, r) -> l instanceof Type && ws instanceof Ws && r instanceof Identifier;
113         Type type;
114         Identifier identifier;
115 
116         public Declaration(Token t, Token ws, Token i) {
117             super(List.of(t, ws, i));
118             this.type = (Type) t;
119             this.identifier = (Identifier) i;
120         }
121 
122         @Override
123         public String toString() {
124             return (type.pos() + ":" + type.asString() + " " + identifier.asString());
125         }
126     }
127 
128     public static class MethodDeclaration extends AbstractParentToken {
129         static TknPredicate2<Token> predicate = (l, r) -> l instanceof Declaration && r instanceof Parenthesis;
130         Type type;
131         Identifier identifier;
132         Parenthesis parenthesis;
133 
134         public MethodDeclaration(Token declaration, Token parenthesis) {
135             super(List.of(declaration, parenthesis));
136             this.type = ((Declaration) declaration).type;
137             this.identifier = ((Declaration) declaration).identifier;
138             this.parenthesis = (Parenthesis) parenthesis;
139         }
140 
141         @Override
142         public String toString() {
143             return (type.pos() + ":" + type.asString() + " " + identifier.asString() + " (...)");
144         }
145     }
146 
147 
148     // Example usage
149     public static void main(String[] args) {
150         ShaderModel shaderModel = new ShaderModel();
151         shaderModel.parse(WavesShader.glslSource);
152         shaderModel.replace((lhs, rhs) -> Char.isA(lhs, $ -> $.is("#")) && Seq.isA(rhs, $ -> $.is("define")), HashDefine::new);
153 
154         shaderModel.replace(t -> Seq.isA(t, $ -> $.matches(FloatConst.regex)), FloatConst::new);  // "[0-9][0-9]*" ->FloatConst
155         shaderModel.replace(t -> Seq.isA(t, $ -> $.matches(IntConst.regex)), IntConst::new); // "[0-9][0-9]*" ->IntConst
156         shaderModel.replace(t -> Seq.isA(t, $ -> $.matches(Type.regex)), Type::new);
157         shaderModel.replace(t -> Seq.isA(t, $ -> $.matches(ReservedWord.regex)), ReservedWord::new);
158         shaderModel.replace(t -> Seq.isA(t, $ -> $.matches(Uniform.regex)), Uniform::new);
159         shaderModel.replace(t -> Seq.isA(t, $ -> $.matches(MathFunc.regex)), MathFunc::new);
160         shaderModel.replace(t -> Char.isA(t, $ -> $.matches(ArithmeticOperator.regex)), ArithmeticOperator::new);
161         shaderModel.replace(t -> Seq.isA(t, $ -> $.matches(Identifier.regex)), Identifier::new);
162 
163         shaderModel.replace((t, w, i) -> Declaration.predicate.test(t, w, i), Declaration::new);
164         shaderModel.replace((d, p) -> MethodDeclaration.predicate.test(d, p), MethodDeclaration::new);
165 
166         //  List<MethodDeclaration> declarations = new ArrayList<>();
167         // shaderModel.find(c->c instanceof MethodDeclaration, (c)->{
168         //   declarations.add((MethodDeclaration) c);
169         //});
170         //  declarations.forEach(System.out::println);
171 
172         var c = ANSI.of(System.out);
173         shaderModel.visitPostOrder(token -> {
174                     if (token instanceof Parent) {
175                         switch (token) {
176                             case MethodDeclaration _ -> c.apply("/* DECL */");
177                             default -> {
178                             }
179                         }
180                     } else {
181                         switch (token) {
182 
183                             case FloatConst _, IntConst _, Uniform _, ReservedWord _, HashDefine _ -> c.fg(PURPLE, token);
184                             case Comment _ -> c.fg(GREEN, _ -> c.bg(BLACK, token));
185                             case MathFunc _ -> c.fg(CYAN, token);
186                             case Open _, Close _ -> c.fg(BLUE, token);
187                             case Type _ -> c.fg(BLUE, token);
188                             case ArithmeticOperator _ -> c.fg(RED, token);
189                             case Identifier _ -> c.fg(YELLOW, token);
190                             default -> c.fg(WHITE, token);
191                         }
192                     }
193                 }
194         );
195     }
196 }
197 
198