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 26 package jdk.incubator.code.tools.renderer; 27 28 import jdk.incubator.code.Block; 29 import jdk.incubator.code.Body; 30 import jdk.incubator.code.op.CoreOp; 31 import jdk.incubator.code.Op; 32 import jdk.incubator.code.Value; 33 34 import java.io.*; 35 import jdk.incubator.code.op.ExternalizableOp; 36 import jdk.incubator.code.type.JavaType; 37 import java.nio.charset.StandardCharsets; 38 39 /** 40 * Created by gfrost 41 */ 42 public final class SRRenderer extends CommonRenderer<SRRenderer> { 43 44 static class AttributeMapper { 45 static String toString(Object value) { 46 if (value instanceof Integer i && i >= 0) { 47 return Integer.toString(i); 48 } else if (value == null) { 49 return "null"; 50 } else { 51 return "\"" + quote(value.toString()) + "\""; 52 } 53 } 54 } 55 56 // Copied from com.sun.tools.javac.util.Convert 57 static String quote(String s) { 58 StringBuilder buf = new StringBuilder(); 59 for (int i = 0; i < s.length(); i++) { 60 buf.append(quote(s.charAt(i))); 61 } 62 return buf.toString(); 63 } 64 65 /** 66 * Escapes a character if it has an escape sequence or is 67 * non-printable ASCII. Leaves non-ASCII characters alone. 68 */ 69 static String quote(char ch) { 70 switch (ch) { 71 case '\b': return "\\b"; 72 case '\f': return "\\f"; 73 case '\n': return "\\n"; 74 case '\r': return "\\r"; 75 case '\t': return "\\t"; 76 case '\'': return "\\'"; 77 case '\"': return "\\\""; 78 case '\\': return "\\\\"; 79 default: 80 return (isPrintableAscii(ch)) 81 ? String.valueOf(ch) 82 : String.format("\\u%04x", (int) ch); 83 } 84 } 85 86 /** 87 * Is a character printable ASCII? 88 */ 89 static boolean isPrintableAscii(char ch) { 90 return ch >= ' ' && ch <= '~'; 91 } 92 93 SRRenderer() { 94 super(); 95 } 96 97 SRRenderer caretLabelTarget(String name) { 98 return caret().labelTarget(name).self(); 99 } 100 101 SRRenderer atIdentifier(String name) { 102 return at().identifier(name).self(); 103 } 104 105 SRRenderer percentLiteral(String name) { 106 return percent().literal(name).self(); 107 } 108 109 SRRenderer spaceColonSpace() { 110 return space().colon().space(); 111 } 112 113 SRRenderer spaceEqualSpace() { 114 return space().equal().space(); 115 } 116 117 public void write(Op op) { 118 GlobalValueBlockNaming gn = new GlobalValueBlockNaming(); 119 write(gn, op); 120 nl(); 121 } 122 123 public void write(GlobalValueBlockNaming gn, Block.Reference successor) { 124 caretLabelTarget(gn.getBlockName(successor.targetBlock())); 125 if (!successor.arguments().isEmpty()) { 126 oparen().commaSeparatedList(); 127 for (var a : successor.arguments()) { 128 commaSeparator(); 129 percentLiteral(gn.getValueName(a)); 130 } 131 cparen(); 132 } 133 134 } 135 136 public void write(GlobalValueBlockNaming gn, Op op) { 137 keyword(op.opName()); 138 if (!op.operands().isEmpty()) { 139 space().spaceSeparatedList(); 140 for (var v : op.operands()) { 141 spaceSeparator(); 142 percentLiteral(gn.getValueName(v)); 143 } 144 } 145 if (!op.successors().isEmpty()) { 146 space().spaceSeparatedList(); 147 for (Block.Reference sb : op.successors()) { 148 spaceSeparator(); 149 write(gn, sb); 150 } 151 } 152 153 if (op instanceof ExternalizableOp exop) { 154 if (!exop.attributes().isEmpty()) { 155 space().spaceSeparatedList(); 156 for (var e : exop.attributes().entrySet()) { 157 spaceSeparator(); 158 String name = e.getKey(); 159 if (!name.isEmpty()) { 160 atIdentifier(name).equal().identifier(AttributeMapper.toString(e.getValue())); 161 } else { 162 atIdentifier(AttributeMapper.toString(e.getValue())); 163 } 164 } 165 } 166 } 167 168 if (!op.bodies().isEmpty()) { 169 int nBodies = op.bodies().size(); 170 if (nBodies == 1) { 171 space(); 172 } else { 173 nl().in().in(); 174 } 175 // @@@ separated list state does not nest as state.first gets overwritten 176 boolean first = true; 177 for (Body body : op.bodies()) { 178 if (!first) { 179 nl(); 180 } 181 write(gn, body); 182 first = false; 183 } 184 if (nBodies > 1) { 185 out().out(); 186 } 187 } 188 189 semicolon(); 190 } 191 192 public void write(GlobalValueBlockNaming gn, Block block, boolean isEntryBlock) { 193 if (!isEntryBlock) { 194 caretLabelTarget(gn.getBlockName(block)); 195 if (!block.parameters().isEmpty()) { 196 oparen().commaSpaceSeparatedList(); 197 for (var v : block.parameters()) { 198 commaSpaceSeparator(); 199 writeValueDecl(gn, v); 200 } 201 cparen(); 202 } 203 colon().nl(); 204 } 205 in(); 206 for (Op op : block.ops()) { 207 Op.Result or = op.result(); 208 if (!or.type().equals(JavaType.VOID)) { 209 writeValueDecl(gn, or); 210 spaceEqualSpace(); 211 } 212 write(gn, op); 213 nl(); 214 } 215 out(); 216 } 217 218 public void write(GlobalValueBlockNaming gn, Body body) { 219 Block eb = body.entryBlock(); 220 oparen().commaSpaceSeparatedList(); 221 for (var v : eb.parameters()) { 222 commaSpaceSeparator(); 223 writeValueDecl(gn, v); 224 } 225 cparen().type(body.bodyType().returnType().toString()).space().rarrow().space().obrace().nl(); 226 in(); 227 boolean isEntryBlock = true; 228 for (Block b : body.blocks()) { 229 if (!isEntryBlock) { 230 nl(); 231 } 232 write(gn, b, isEntryBlock); 233 isEntryBlock = false; 234 } 235 out(); 236 cbrace(); 237 } 238 239 public void writeValueDecl(GlobalValueBlockNaming gn, Value v) { 240 percentLiteral(gn.getValueName(v)).spaceColonSpace().type(v.type().toString()); 241 } 242 243 // @@@ Not used 244 public void write(GlobalValueBlockNaming gn, CoreOp.FuncOp fRep) { 245 this.append(fRep.opName());// w.write(name); 246 if (!fRep.operands().isEmpty()) { 247 space().spaceSeparatedList(); 248 for (var v : fRep.operands()) { 249 spaceSeparator(); 250 percentLiteral(gn.getValueName(v)); 251 } 252 } 253 if (!fRep.successors().isEmpty()) { 254 space().spaceSeparatedList(); 255 for (Block.Reference sb : fRep.successors()) { 256 spaceSeparator(); 257 write(gn, sb); 258 } 259 } 260 if (!fRep.attributes().isEmpty()) { 261 space(); 262 for (var e : fRep.attributes().entrySet()) { 263 String name = e.getKey(); 264 String value = AttributeMapper.toString(e.getValue()); 265 op("@"); 266 if (name.isEmpty()) { 267 literal(value); 268 } else { 269 identifier(name).equal().literal(value); 270 } 271 } 272 } 273 if (!fRep.bodies().isEmpty()) { 274 space().newlineSeparatedList(); 275 for (Body body : fRep.bodies()) { 276 newlineSeparator(); 277 write(gn, body); 278 } 279 } 280 281 } 282 283 public static void write(Writer writer, Op op) { 284 new SRRenderer().writer(writer).write(op); 285 } 286 287 public static void write(OutputStream out, Op op) { 288 write(new OutputStreamWriter(out, StandardCharsets.UTF_8), op); 289 } 290 291 public static String stringify(Op op) { 292 StringWriter sw = new StringWriter(); 293 write(sw, op); 294 return sw.toString(); 295 } 296 297 public static String colorize(TextRenderer.TokenColorMap tokenColorMap, Op op) { 298 StringWriter sw = new StringWriter(); 299 new SRRenderer().writer(sw).colorize(tokenColorMap).write(op); 300 return sw.toString(); 301 } 302 303 public static String colorize(Op op) { 304 return colorize(new TextRenderer.TokenColorMap(), op); 305 } 306 }