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