View Javadoc
1   package net.sourceforge.jenesis4java.impl;
2   
3   /*
4    * #%L
5    * Jenesis 4 Java Code Generator
6    * %%
7    * Copyright (C) 2000 - 2015 jenesis4java
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * #L%
23   */
24  
25  /**
26   * Copyright (C) 2008, 2010 Richard van Nieuwenhoven - ritchie [at] gmx [dot] at
27   * Copyright (C) 2000, 2001 Paul Cody Johnston - pcj@inxar.org <br>
28   * This file is part of Jenesis4java. Jenesis4java is free software: you can
29   * redistribute it and/or modify it under the terms of the GNU Lesser General
30   * Public License as published by the Free Software Foundation, either version 3
31   * of the License, or (at your option) any later version.<br>
32   * Jenesis4java is distributed in the hope that it will be useful, but WITHOUT
33   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
34   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
35   * details.<br>
36   * You should have received a copy of the GNU Lesser General Public License
37   * along with Jenesis4java. If not, see <http://www.gnu.org/licenses/>.
38   */
39  
40  import net.sourceforge.jenesis4java.*;
41  import net.sourceforge.jenesis4java.impl.util.VisitorUtils;
42  
43  import java.util.*;
44  
45  import static java.lang.String.format;
46  
47  /**
48   * Standard {@code Literal} implementations.
49   */
50  public abstract class MLiteral extends MVM.MCodeable implements Literal {
51  
52      /**
53       * BOOLEAN LITERAL
54       */
55      static class MBooleanLiteral extends MLiteral implements BooleanLiteral {
56  
57          MBooleanLiteral(MVM vm, boolean val) {
58              super(vm, vm.BOOLEAN, val, val ? "true" : "false");
59          }
60  
61          @Override
62          public boolean toBoolean() {
63              return (Boolean) val;
64          }
65      }
66  
67      /**
68       * BYTE LITERAL
69       */
70      static class MByteLiteral extends MLiteral implements ByteLiteral {
71  
72          MByteLiteral(MVM vm, byte val) {
73              super(vm, vm.BYTE, val, "(byte) " + val);
74          }
75  
76          @Override
77          public byte toByte() {
78              return (Byte) val;
79          }
80      }
81  
82      /**
83       * CHAR LITERAL
84       */
85      static class MCharLiteral extends MLiteral implements CharLiteral {
86  
87          /**
88           * Control characters that are not actually printable characters and
89           * therefor need to be escaped with UTF-8 syntax.
90           */
91          private static final Set<Character> CONTROL_CODES;
92  
93          /**
94           * Characters, for which Java provides a special encoding.
95           */
96          private static final Map<Character, String> SPECIAL_ENCODINGS;
97  
98          MCharLiteral(MVM vm, char val) {
99              super(vm, vm.CHAR, val, escapedValue(val));
100         }
101 
102         private static String escapedValue(char val) {
103             StringBuilder b = new StringBuilder();
104             b.append("'");
105             escape(val, b, false);
106             b.append("'");
107             return b.toString();
108         }
109 
110         static {
111             CONTROL_CODES = new HashSet<>();
112             CONTROL_CODES.addAll(Arrays.asList( //
113                     '\u0001', '\u0002', '\u0003', '\u0004', '\u0005', '\u0006', //
114                     '\u0007', '\u000B', '\u000E', '\u000F', '\u0010', '\u0011', //
115                     '\u0012', '\u0013', '\u0014', '\u0015', '\u0016', '\u0017', //
116                     '\u0018', '\u0019', '\u001A', '\u001B', '\u001C', '\u001D', //
117                     '\u001E', '\u001F'));
118 
119             SPECIAL_ENCODINGS = new HashMap<>();
120             SPECIAL_ENCODINGS.put('\0', "\\0");
121             SPECIAL_ENCODINGS.put('\b', "\\b");
122             SPECIAL_ENCODINGS.put('\t', "\\t");
123             SPECIAL_ENCODINGS.put('\n', "\\n");
124             SPECIAL_ENCODINGS.put('\f', "\\f");
125             SPECIAL_ENCODINGS.put('\r', "\\r");
126             SPECIAL_ENCODINGS.put('\\', "\\\\");
127         }
128 
129         static void escape(char c, StringBuilder b, boolean escapeForString) {
130             // Check if the char is in the ACSII range.
131 
132             if (c == '"' && escapeForString //
133                     || c == '\'' && !escapeForString) {
134                 b.append("\\");
135                 b.append(c);
136 
137             } else if (CONTROL_CODES.contains(c)) {
138                 String charString = Integer.toHexString(c);
139                 b.append("\\u");
140                 b.append("0000".substring(charString.length()));
141                 b.append(charString);
142 
143             } else if (SPECIAL_ENCODINGS.containsKey(c)) {
144                 b.append(SPECIAL_ENCODINGS.get(c));
145 
146             } else {
147                 b.append(c);
148             }
149         }
150 
151         @Override
152         public char toChar() {
153             return (Character) val;
154         }
155     }
156 
157     /**
158      * CLASS LITERAL
159      */
160     static class MClassLiteral extends MLiteral implements ClassLiteral {
161 
162         MClassLiteral(MVM vm, ClassType val) {
163             super(vm, val, val, val.toString() + ".class");
164         }
165 
166     }
167 
168     /**
169      * DOUBLE LITERAL
170      */
171     static class MDoubleLiteral extends MLiteral implements DoubleLiteral {
172 
173         MDoubleLiteral(MVM vm, double val) {
174             super(vm, vm.DOUBLE, val, Double.toString(val) + "D");
175         }
176 
177         @Override
178         public double toDouble() {
179             return (Double) val;
180         }
181     }
182 
183     /**
184      * FALSE LITERAL
185      */
186     static class MFalse extends MBooleanLiteral implements False {
187 
188         MFalse(MVM vm) {
189             super(vm, false);
190         }
191     }
192 
193     /**
194      * FLOAT LITERAL
195      */
196     static class MFloatLiteral extends MLiteral implements FloatLiteral {
197 
198         MFloatLiteral(MVM vm, float val) {
199             super(vm, vm.FLOAT, val, Float.toString(val) + "F");
200         }
201 
202         @Override
203         public float toFloat() {
204             return (Float) val;
205         }
206     }
207 
208     /**
209      * INT LITERAL
210      */
211     static class MIntLiteral extends MLiteral implements IntLiteral {
212 
213         MIntLiteral(MVM vm, int val) {
214             super(vm, vm.INT, val, Integer.toString(val));
215         }
216 
217         @Override
218         public int toInt() {
219             return (Integer) val;
220         }
221     }
222 
223     /**
224      * LONG LITERAL
225      */
226     static class MLongLiteral extends MLiteral implements LongLiteral {
227 
228         MLongLiteral(MVM vm, long val) {
229             super(vm, vm.LONG, val, Long.toString(val) + 'L');
230         }
231 
232         @Override
233         public long toLong() {
234             return (Long) val;
235         }
236     }
237 
238     /**
239      * NULL LITERAL
240      */
241     static class MNull extends MLiteral implements Null {
242 
243         MNull(MVM vm) {
244             super(vm, vm.NULL, null, "null");
245         }
246     }
247 
248     /**
249      * OCTAL LITERAL
250      */
251     static class MOctalLiteral extends MCharLiteral implements OctalLiteral {
252 
253         MOctalLiteral(MVM vm, char val) {
254             super(vm, val);
255             label = "'\\" + Integer.toOctalString(val) + "'";
256         }
257     }
258 
259     /**
260      * SCIENTIFIC LITERAL
261      */
262     static class MScientificLiteral extends MLiteral implements ScientificLiteral {
263 
264         final int precision;
265 
266         final int scale;
267 
268         final int exponent;
269 
270         MScientificLiteral(MVM vm, int precision, int scale, int exponent) {
271             super(vm, vm.DOUBLE, null, format("%d.%de%d", precision, scale, exponent));
272             this.precision = precision;
273             this.scale = scale;
274             this.exponent = exponent;
275         }
276 
277         @Override
278         public int getExponent() {
279             return exponent;
280         }
281 
282         @Override
283         public int getPrecision() {
284             return precision;
285         }
286 
287         @Override
288         public int getScale() {
289             return scale;
290         }
291     }
292 
293     /**
294      * SHORT LITERAL
295      */
296     static class MShortLiteral extends MLiteral implements ShortLiteral {
297 
298         MShortLiteral(MVM vm, short val) {
299             super(vm, vm.SHORT, val, "(short) " + val);
300         }
301 
302         @Override
303         public short toShort() {
304             return (short) val;
305         }
306     }
307 
308     /**
309      * STRING LITERAL
310      */
311     static class MStringLiteral extends MLiteral implements StringLiteral {
312 
313         MStringLiteral(MVM vm, String val) {
314             super(vm, vm.STRING, val, escapeValue(val));
315         }
316 
317         private static void escape(String s, StringBuilder b) {
318             // Cache the length of the String to escape.
319             int len = s.length();
320             // Iterate over the length of the string.
321             for (int i = 0; i < len; i++) {
322                 MCharLiteral.escape(s.charAt(i), b, true);
323             }
324         }
325 
326         private static String escapeValue(String val) {
327             StringBuilder b = new StringBuilder();
328             b.append("\"");
329             escape(val, b);
330             b.append("\"");
331             return b.toString();
332         }
333     }
334 
335     /**
336      * TRUE LITERAL
337      */
338     static class MTrue extends MBooleanLiteral implements True {
339 
340         MTrue(MVM vm) {
341             super(vm, true);
342         }
343     }
344 
345     /**
346      * UNICODE LITERAL
347      */
348     static class MUnicodeLiteral extends MCharLiteral implements UnicodeLiteral {
349 
350         MUnicodeLiteral(MVM vm, char val) {
351             super(vm, val);
352             label = "'\\u" + Integer.toHexString(val) + "'";
353         }
354     }
355 
356     private Comment comment;
357 
358     private Type type;
359 
360     final Object val;
361 
362     String label;
363 
364     MLiteral(MVM vm, Type type, Object val, String label) {
365         super(vm);
366         this.type = type;
367         this.val = val;
368         this.label = label;
369     }
370 
371     @Override
372     public Comment getComment() {
373         return comment;
374     }
375 
376     public MLiteral setComment(Comment comment) {
377         this.comment = comment;
378         return this;
379     }
380 
381     @Override
382     public Type getType() {
383         return type;
384     }
385 
386     @Override
387     public CodeWriter toCode(CodeWriter out) {
388         out.queue(comment);
389         out.write(label);
390         return out;
391     }
392 
393     @Override
394     public Object toObject() {
395         return val;
396     }
397 
398     @Override
399     public void visit(ReplacingVisitor visitor) {
400         super.visit(visitor);
401         type = VisitorUtils.visit(type, this, visitor);
402         comment = VisitorUtils.visit(comment, this, visitor);
403     }
404 }