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 }