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