1 /*
2 * Copyright (c) 2024-2026, 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 optkl.codebuilders;
26
27 import jdk.incubator.code.Op;
28 import jdk.incubator.code.dialect.core.CoreOp;
29 import jdk.incubator.code.dialect.java.JavaOp;
30 import optkl.util.Mutable;
31
32 import java.util.function.BiConsumer;
33 import java.util.function.Consumer;
34 import java.util.stream.Stream;
35
36 /**
37 * Extends the base TextBuilder to add common constructs/keywords for generating C99/Java style code.
38 *
39 * @author Gary Frost
40 */
41 public abstract class CodeBuilder<T extends CodeBuilder<T>>
42 extends TextBuilder<T> implements CodeRenderer<T> {
43
44 final public T semicolon() {
45 return symbol(";");
46 }
47
48 final public T snl() {
49 return semicolon().nl();
50 }
51
52 final public T cnl() {
53 return comma().nl();
54 }
55 final public T comma() {
56 return symbol(",");
57 }
58
59 final public T csp() {
60 return comma().sp();
61 }
62
63 final public T tilde() {
64 return symbol("~");
65 }
66
67 final public T dot() {
68 return symbol(".");
69 }
70
71 final public T leftShift() {
72 return symbol("<<");
73 }
74
75 final public T rightShift() {
76 return symbol(">>");
77 }
78
79 final public T rightShift(int v) {
80 return rightShift().intValue(v);
81 }
82
83 final public T leftShift(int v) {
84 return leftShift().intValue(v);
85 }
86
87 final public T equals() {
88 return symbol("=");
89 }
90
91 final public T assign() {
92 return sp().equals().sp();
93 }
94
95 final public T dollar() {
96 return symbol("$");
97 }
98
99 final public T plusplus() {
100 return symbol("++");
101 }
102
103 final public T plusEquals() {
104 return symbol("+=");
105 }
106
107 final public T minusminus() {
108 return symbol("--");
109 }
110
111 final public T ne() {
112 return pling().equals();
113 }
114
115 final public T lineComment(String line) {
116 return comment("//").sp().comment(line).nl();
117 }
118
119 final public T autoGenerated(){
120 return nl().lineComment("Auto generated DO NOT EDIT").nl();
121 }
122
123 @Override
124 final public T constant(String text) {
125 return emitText(text);
126 }
127
128 public final T constantHalf(Integer value) {
129 return emitText("(half)"+value);
130 }
131
132
133 final public T blockComment(String block) {
134 return comment("/*").nl().comment(block).nl().symbol("*/").nl();
135 }
136
137 final public T blockInlineComment(String block) {
138 return comment("/*").sp().comment(block).sp().comment("*/");
139 }
140
141 final public T newKeyword() {
142 return keyword("new");
143 }
144 final public T newKwSp() {
145 return newKeyword().sp();
146 }
147
148 final public T staticKeyword() {
149 return keyword("static");
150 }
151 final public T staticKwSp() {
152 return staticKeyword().sp();
153 }
154
155 final public T constexprKeyword() {
156 return keyword("constexpr");
157 }
158
159 final public T constKeyword() {
160 return keyword("const");
161 }
162
163 final public T explicitKeyword() {
164 return keyword("explicit");
165 }
166
167 final public T virtualKeyword() {
168 return keyword("virtual");
169 }
170
171 final public T ifKeyword() {
172 return keyword("if");
173 }
174
175 final public T whileKeyword() {
176 return keyword("while");
177 }
178
179
180 final public T breakKeyword() {
181 return keyword("break");
182 }
183
184 final public T gotoKeyword() {
185 return keyword("goto");
186 }
187
188 final public T continueKeyword() {
189 return keyword("continue");
190 }
191
192
193 final public T colon() {
194 return symbol(":");
195 }
196
197
198 final public T nullConst() {
199 return symbol("NULL");
200 }
201
202
203 final public T elseKeyword() {
204 return keyword("else");
205 }
206
207
208 final public T returnKeyword() {
209 return keyword("return");
210 }
211 final public T returnKwSp() {
212 return returnKeyword().sp();
213 }
214
215 final public T returnKeyword(String identifier) {
216 return returnKeyword().sp().id(identifier);
217 }
218
219 final public T switchKeyword() {
220 return keyword("switch");
221 }
222
223
224 final public T caseKeyword() {
225 return keyword("case");
226 }
227
228
229 final public T defaultKeyword() {
230 return keyword("default");
231 }
232 final public T defaultKwSp() {
233 return defaultKeyword().sp();
234 }
235
236 final public T defaultKeyword( String typeName) {
237 return defaultKeyword().sp().type(typeName);
238 }
239
240 final public T doKeyword() {
241 return keyword("do");
242 }
243
244 final public T forKeyword() {
245 return keyword("for");
246 }
247
248 final public T ampersand() {
249 return symbol("&");
250 }
251
252 final public T addressOf(String identifier) {
253 return ampersand().id(identifier);
254 }
255
256 final public T asterisk() {
257 return symbol("*");
258 }
259
260 final public T dereference(String identifier) {
261 return asterisk().id(identifier);
262 }
263
264 final public T mul() {
265 return asterisk();
266 }
267
268 final public T percent() {
269 return symbol("%");
270 }
271
272 final public T mod() {
273 return percent();
274 }
275
276 final public T slash() {
277 return symbol("/");
278 }
279
280 final public T div() {
281 return slash();
282 }
283
284 final public T plus() {
285 return symbol("+");
286 }
287
288 final public T add() {
289 return plus();
290 }
291
292 final public T minus() {
293 return symbol("-");
294 }
295
296 final public T sub() {
297 return minus();
298 }
299
300 final public T lt() {
301 return symbol("<");
302 }
303 final public T ltgt(Consumer<T> consumer) {
304 return lt().accept(consumer).gt();
305 }
306 final public T eq() {
307 return equals().equals();
308 }
309
310 final public T lte() {
311 return lt().equals();
312 }
313
314 final public T gte() {
315 return gt().equals();
316 }
317
318 final public T pling() {
319 return symbol("!");
320 }
321
322 final public T gt() {
323 return symbol(">");
324 }
325
326 final public T condAnd() {
327 return symbol("&&");
328 }
329
330 final public T condOr() {
331 return symbol("||");
332 }
333
334 final public T oparen() {
335 return symbol("(");
336 }
337
338 final public T paren(Consumer<T> consumer) {
339 return oparen().accept(consumer).cparen();
340 }
341
342 final public T ocparen() {
343 return oparen().cparen();
344 }
345
346 final public T parenWhen(boolean value, Consumer<T> consumer) {
347 if (value) {
348 oparen().accept(consumer).cparen();
349 } else {
350 accept(consumer);
351 }
352 return self();
353 }
354
355 final public T semicolonTerminated(Consumer<T> consumer) {
356 return accept(consumer).semicolon();
357 }
358
359 final public T semicolonNlTerminated(Consumer<T> consumer) {
360 return semicolonTerminated(consumer).nl();
361 }
362
363 final public T obrace() {
364 return symbol("{");
365 }
366
367 final public T indent(Consumer<T> ct) {
368 return in().accept(ct).out();
369 }
370
371 final public T nlIndentNl(Consumer<T> ct) {
372 return nl().indent(ct).nl();
373 }
374
375 final public T braceNlIndented(Consumer<T> ct) {
376 return obrace().nlIndentNl(ct).cbrace();
377 }
378
379 final public T parenNlIndented(Consumer<T> ct) {
380 return oparen().nlIndentNl(ct).cparen();
381 }
382
383 final public T brace(Consumer<T> ct) {
384 return obrace().indent(ct).cbrace();
385 }
386
387 final public T ocsbrace() {
388 return osbrace().csbrace();
389 }
390
391 final public T ocbrace() {
392 return obrace().cbrace();
393 }
394
395 final public T sbrace(Consumer<T> ct) {
396 return osbrace().accept(ct).csbrace();
397 }
398
399 final public T accept(Consumer<T> ct) {
400 ct.accept(self());
401 return self();
402 }
403
404
405 final public T ochevron() {
406 return rawochevron();
407 }
408
409 final public T rawochevron() {
410 return emitText("<");
411 }
412
413 final public T bitwiseOR() {
414 return symbol("|");
415 }
416
417 final public T cchevron() {
418 return rawcchevron();
419 }
420
421 final public T chevron(Consumer<T> ct) {
422 return rawochevron().indent(ct).rawcchevron();
423 }
424
425 final public T rawcchevron() {
426 return emitText(">");
427 }
428
429 final public T osbrace() {
430 return symbol("[");
431 }
432
433 final public T cparen() {
434 return symbol(")");
435 }
436
437 final public T cbrace() {
438 return symbol("}");
439 }
440
441
442 final public T csbrace() {
443 return symbol("]");
444 }
445
446 final public T underscore() {
447 return symbol("_");
448 }
449
450 final public T dquote() {
451 return symbol("\"");
452 }
453
454 public final T backslash() {
455 return symbol("\\");
456 }
457
458 final public T odquote() {
459 return dquote();
460 }
461
462 final public T cdquote() {
463 return dquote();
464 }
465
466 final public T squote() {
467 return symbol("'");
468 }
469
470 final public T osquote() {
471 return squote();
472 }
473
474 final public T csquote() {
475 return squote();
476 }
477
478 final public T dquote(String string) {
479 return odquote().escaped(string).cdquote();
480 }
481
482 final public T at() {
483 return symbol("@");
484 }
485
486 final public T hat() {
487 return symbol("^");
488 }
489
490 final public T squote(String txt) {
491 return osquote().escaped(txt).csquote();
492 }
493
494 final public T rarrow() {
495 return symbol("->");
496 }
497
498 final public T larrow() {
499 return symbol("<-");
500 }
501
502
503 final public T questionMark() {
504 return symbol("?");
505 }
506
507 final public T hash() {
508 return symbol("#");
509 }
510
511 final public T when(boolean c, Consumer<T> consumer) {
512 if (c) {
513 accept(consumer);
514 }
515 return self();
516 }
517
518 public final T either(boolean c, Consumer<T> lhs, Consumer<T> rhs) {
519 if (c) {
520 accept(lhs);
521 } else {
522 accept(rhs);
523 }
524 return self();
525 }
526
527 public final T dotOrArrow(boolean c) {
528 return either(c, _ -> dot(), _ -> rarrow());
529 }
530
531 public final <I> T sep(Iterable<I> iterable, Consumer<T> separator, Consumer<I> consumer) {
532 var first = Mutable.of(true);
533 iterable.forEach(t -> {
534 if (first.get()) {
535 first.set(false);
536 } else {
537 separator.accept(self());
538 }
539 consumer.accept(t);
540 });
541 return self();
542 }
543 final public <I> T joinX2(Iterable<I> iterable1, Iterable<I> iterable2, Consumer<T> separator, BiConsumer<I,I> consumer) {
544 return sep(iterable1,separator, $1 -> sep(iterable2,separator, $2 -> consumer.accept($1, $2)));
545 }
546
547 // Join is a better name lets delegate for a while then deprecate
548 // public <I> T separated(Iterable<I> iterable, Consumer<T> separator, Consumer<I> consumer) {
549 // return join(iterable,separator,consumer);
550 // }
551
552 final public <I> T commaSpaceSeparated(Iterable<I> iterable, Consumer<I> consumer) {
553 return sep(iterable, _ -> csp(), consumer);
554 }
555
556 final public T commaSpaceSeparated(Consumer<T>... consumers) {
557 for (int i = 0; i < consumers.length; i++) {
558 if (i > 0) {
559 csp();
560 }
561 consumers[i].accept(self());
562 }
563 return self();
564 }
565
566 public final <I> T spaceSeparated(Iterable<I> iterable, Consumer<I> consumer) {
567 return sep(iterable, _ -> sp(), consumer);
568 }
569
570 final public T args(Consumer<T>... consumers) {
571 return commaSpaceSeparated(consumers);
572 }
573
574 final public <I> T commaSeparated(Iterable<I> iterable, Consumer<I> consumer) {
575 return sep(iterable, _ -> comma(), consumer);
576 }
577
578 final public <I> T commaNlSeparated(Iterable<I> iterable, Consumer<I> consumer) {
579 return sep(iterable, _ -> comma().nl(), consumer);
580 }
581
582 final public <I> T barSeparated(Iterable<I> iterable, Consumer<I> consumer) {
583 return sep(iterable, _ -> bitwiseOR(), consumer);
584 }
585
586 final public <I> T semicolonNlSeparated(Iterable<I> iterable, Consumer<I> consumer) {
587 return sep(iterable, _ -> snl(), consumer);
588 }
589
590
591 final public <I> T sep(Stream<I> stream, Consumer<T> separator, Consumer<I> consumer) {
592 var first = Mutable.of(true);
593 stream.forEach(t -> {
594 if (first.get()) {
595 first.set(false);
596 } else {
597 separator.accept(self());
598 }
599 consumer.accept(t);
600 });
601 return self();
602 }
603
604 final public <I> T commaSpaceSeparated(Stream<I> stream, Consumer<I> consumer) {
605 return sep(stream, _ -> csp(), consumer);
606 }
607
608 final public <I> T nlSeparated(Stream<I> stream, Consumer<I> consumer) {
609 return sep(stream, _ -> nl(), consumer);
610 }
611
612 final public T s32Type() {
613 return type("int");
614 }
615
616 final public T s32Type(String identifier) {
617 return s32Type().sp().id(identifier);
618 }
619
620 final public T boolConst(boolean b) {
621 return constant(Boolean.toString(b));
622 }
623
624 final public T intConst(int i) {
625 return constant(Integer.toString(i));
626 }
627 final public T intConstZero() {
628 return intConst(0);
629 }
630 final public T intConstOne() {
631 return intConst(1);
632 }
633
634 final public T intConstTwo() {
635 return intConst(2);
636 }
637 final public T floatConst(float f) {
638 return constant(f+"f");
639 }
640 final public T floatConstZero() {
641 return floatConst(0f);
642 }
643
644
645
646 final public T voidType() {
647 return type("void");
648 }
649
650 final public T s08Type() {
651 return type("char");
652 }
653
654 final public T s08Type(String name) {
655 return s08Type().sp().id(name);
656 }
657
658 final public T f32Type() {
659 return type("float");
660 }
661
662 final public T f32Type(String identifier) {
663 return f32Type().sp().id(identifier);
664 }
665
666 final public T s64Type() {
667 return type("long");
668 }
669
670 final public T f64Type() {
671 return type("double");
672 }
673
674 final public T boolType() {
675 return type("char");
676 }
677
678 final public T s16Type() {
679 return type("short");
680 }
681
682 final public T s16Type(String identifier) {
683 return s16Type().sp().id(identifier);
684 }
685
686
687 @Override
688 final public T comment(String text) {
689 return emitText(text);
690 }
691
692 @Override
693 final public T id(String text) {
694 return emitText(text);
695 }
696
697
698 @Override
699 final public T reserved(String text) {
700 return emitText(text);
701 }
702
703 @Override
704 final public T label(String text) {
705 return emitText(text);
706 }
707
708 @Override
709 final public T symbol(String text) {
710 return emitText(text);
711 }
712
713 @Override
714 final public T type(String text) {
715 return emitText(text);
716 }
717
718 @Override
719 final public T keyword(String text) {
720 return emitText(text);
721 }
722
723 @Override
724 final public T literal(String text) {
725 return emitText(text);
726 }
727
728 final public T nl(int n) {
729 for (int i=0; i< n;i++){
730 nl();
731 }
732 return self();
733 }
734
735 @Override
736 final public T sp() {
737 return emitText(" ");
738 }
739
740 final public String toCamelExceptFirst(String s) {
741 String[] parts = s.split("_");
742 StringBuilder camelCaseString = new StringBuilder();
743 for (String part : parts) {
744 camelCaseString.append(camelCaseString.isEmpty()
745 ? part.toLowerCase()
746 : part.substring(0, 1).toUpperCase() + part.substring(1).toLowerCase());
747 }
748 return camelCaseString.toString();
749 }
750
751 public T using() {
752 return emitText("using");
753 }
754
755 public T namespace() {
756 return emitText("namespace");
757 }
758
759 public T builtin(String text) {
760 return emitText(text);
761 }
762
763 final public T oracleCopyright(){
764 return blockComment("""
765 * Copyright (c) 2025-2026, Oracle and/or its affiliates. All rights reserved.
766 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
767 *
768 * This code is free software; you can redistribute it and/or modify it
769 * under the terms of the GNU General Public License version 2 only, as
770 * published by the Free Software Foundation. Oracle designates this
771 * particular file as subject to the "Classpath" exception as provided
772 * by Oracle in the LICENSE file that accompanied this code.
773 *
774 * This code is distributed in the hope that it will be useful, but WITHOUT
775 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
776 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
777 * version 2 for more details (a copy is included in the LICENSE file that
778 * accompanied this code).
779 *
780 * You should have received a copy of the GNU General Public License version
781 * 2 along with this work; if not, write to the Free Software Foundation,
782 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
783 *
784 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
785 * or visit www.oracle.com if you need additional information or have any
786 * questions."""
787 );
788 }
789
790 public final T varName(String name) {
791 return id(name);
792 }
793
794 public final T varName(CoreOp.VarOp varOp) {
795 return varName(varOp.varName());
796 }
797 final public T varName(CoreOp.VarAccessOp.VarLoadOp varOp) {
798 blockInlineComment(varOp.toString());
799 return self();
800 }
801 final public T funcName(CoreOp.FuncCallOp funcCallOp){
802 return funcName(funcCallOp.funcName());
803 }
804 final public T funcName(String name){
805 return id(name);
806 }
807 final public T funcName(CoreOp.FuncOp funcOp) {
808 return funcName(funcOp.funcName());
809 }
810 final public T fieldName(JavaOp.FieldAccessOp fieldAccessOp) {
811 return id(fieldAccessOp.fieldReference().name());
812 }
813 final public T funcName(JavaOp.InvokeOp invokeOp){
814 return id(invokeOp.invokeReference().name());
815 }
816
817
818 protected final T camel(String value) {
819 return id(Character.toString(Character.toLowerCase(value.charAt(0)))).id(value.substring(1));
820 }
821
822 final public T camelJoin(String prefix, String suffix) {
823 return camel(prefix).id(Character.toString(Character.toUpperCase(suffix.charAt(0)))).id(suffix.substring(1));
824 }
825
826 public T symbol(Op op) {
827 return switch (op) {
828 case JavaOp.ModOp o -> percent();
829 case JavaOp.MulOp o -> mul();
830 case JavaOp.DivOp o -> div();
831 case JavaOp.AddOp o -> add();
832 case JavaOp.SubOp o -> sub();
833 case JavaOp.LtOp o -> lt();
834 case JavaOp.GtOp o -> gt();
835 case JavaOp.LeOp o -> lte();
836 case JavaOp.GeOp o -> gte();
837 case JavaOp.AshrOp o -> cchevron().cchevron();
838 case JavaOp.LshlOp o -> ochevron().ochevron();
839 case JavaOp.LshrOp o -> cchevron().cchevron();
840 case JavaOp.NeqOp o -> pling().equals();
841 case JavaOp.NegOp o -> minus();
842 case JavaOp.EqOp o -> equals().equals();
843 case JavaOp.NotOp o -> pling();
844 case JavaOp.AndOp o -> ampersand();
845 case JavaOp.OrOp o -> bitwiseOR();
846 case JavaOp.XorOp o -> hat();
847 case JavaOp.ConditionalAndOp o -> condAnd();
848 case JavaOp.ConditionalOrOp o -> condOr();
849 default -> throw new IllegalStateException("Unexpected value: " + op);
850 };
851 }
852 }