Remove exported everywhere.
[SquirrelJME.git] / modules / tool-classfile / src / main / java / net / multiphasicapps / classfile / FieldDescriptor.java
blob1e6d240c88850b814d25df0c392c07187ade301f
1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the GNU General Public License v3+, or later.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package net.multiphasicapps.classfile;
12 import cc.squirreljme.runtime.cldc.annotation.Exported;
13 import cc.squirreljme.runtime.cldc.debug.Debugging;
15 /**
16 * This represents the type descriptor of a field.
18 * @since 2017/06/12
20 public final class FieldDescriptor
21 implements Comparable<FieldDescriptor>, MemberDescriptor
23 /** The short type. */
24 public static final FieldDescriptor SHORT =
25 new FieldDescriptor("S");
27 /** The integer type. */
28 public static final FieldDescriptor INTEGER =
29 new FieldDescriptor("I");
31 /** String representation. */
32 protected final String string;
34 /** Is this a primitive type? */
35 protected final boolean primitive;
37 /** Array dimensions. */
38 protected final int dimensions;
40 /** The component type. */
41 protected final FieldDescriptor component;
43 /** The class this refers to. */
44 protected final ClassName classname;
46 /**
47 * Initializes the field descriptor.
49 * @param __n The field descriptor to decode.
50 * @throws InvalidClassFormatException If it is not a valid field descriptor.
51 * @throws NullPointerException On null arguments.
52 * @since 2017/06/12
54 public FieldDescriptor(String __n)
55 throws InvalidClassFormatException, NullPointerException
57 // Check
58 if (__n == null)
59 throw new NullPointerException("NARG");
61 // Set
62 this.string = __n;
64 // {@squirreljme.error JC2q The field descriptor cannot be blank. (The
65 // field descriptor)}
66 int n = __n.length();
67 if (n <= 0)
68 throw new InvalidClassFormatException(
69 String.format("JC2q %s", __n));
71 // Depends on the first character
72 char c = __n.charAt(0);
73 switch (c)
75 // Primitive
76 case 'B':
77 case 'C':
78 case 'D':
79 case 'F':
80 case 'I':
81 case 'J':
82 case 'S':
83 case 'Z':
84 this.primitive = true;
85 this.dimensions = 0;
86 this.component = null;
87 this.classname = null;
88 break;
90 // Array
91 case '[':
92 this.primitive = false;
93 this.classname = null;
95 // Count dimensions
96 int dims = 0;
97 for (int i = 0; i < n; i++)
98 if (__n.charAt(i) != '[')
99 break;
100 else
101 dims++;
102 this.dimensions = dims;
104 // Parse component
105 this.component = new FieldDescriptor(__n.substring(1));
106 break;
108 // Class
109 case 'L':
110 this.primitive = false;
111 this.dimensions = 0;
112 this.component = null;
114 // {@squirreljme.error JC2r The field descriptor for a class
115 // must end with a semicolon. (The field descriptor)}
116 if (';' != __n.charAt(n - 1))
117 throw new InvalidClassFormatException(
118 String.format("JC2r %s", __n));
120 // Decode
121 this.classname = new ClassName(__n.substring(1, n - 1));
122 break;
124 // {@squirreljme.error JC2s The field descriptor is not valid.
125 // (The field descriptor)}
126 default:
127 throw new InvalidClassFormatException(
128 String.format("JC2s %s", __n));
133 * Adds dimensions to the field descriptor.
135 * @param __d The number of dimensions to add.
136 * @return The field descriptor with added dimensions.
137 * @throws IllegalArgumentException If the dimensions are negative.
138 * @since 2018/09/15
140 public final FieldDescriptor addDimensions(int __d)
141 throws IllegalArgumentException
143 if (__d == 0)
144 return this;
146 // {@squirreljme.error JC2t Cannot add negative dimensions.}
147 if (__d < 0)
148 throw new IllegalArgumentException("JC2t");
150 // Prepend string with brackets, to declare a new array
151 StringBuilder sb = new StringBuilder();
152 for (int i = 0; i < __d; i++)
153 sb.append('[');
155 // Rebuild field
156 sb.append(this.toString());
157 return new FieldDescriptor(sb.toString());
161 * Returns the name of the used class.
163 * @return The used class or {@code null} if a class is not referred to and
164 * this is a primitive type.
165 * @since 2018/09/01
167 public final ClassName className()
169 // If this is an array then the class name will be the array descriptor
170 if (this.dimensions > 0)
171 return new ClassName(this.toString());
173 // Otherwise as normal class (or primitive representation)
174 if (this.primitive)
175 return ClassName.fromPrimitiveType(this.primitiveType());
176 return this.classname;
180 * {@inheritDoc}
181 * @since 2017/10/02
183 @Override
184 public int compareTo(FieldDescriptor __o)
186 return this.string.compareTo(__o.string);
190 * Returns the component type of the array if this is one.
192 * @return The component type or {@code null} if this is not one.
193 * @since 2018/09/27
195 public final FieldDescriptor componentType()
197 return this.component;
201 * Returns the number of dimensions in this class.
203 * @return The number of dimensions in the class.
204 * @since 2018/09/28
206 public final int dimensions()
208 return this.dimensions;
212 * {@inheritDoc}
213 * @since 2017/06/12
215 @Override
216 public boolean equals(Object __o)
218 if (this == __o)
219 return true;
221 // Check
222 if (!(__o instanceof FieldDescriptor))
223 return false;
225 return this.string.equals(((FieldDescriptor)__o).string);
229 * {@inheritDoc}
230 * @since 2017/06/12
232 @Override
233 public int hashCode()
235 return this.string.hashCode();
239 * Is this an array type?
241 * @return {@code true} if an array type.
242 * @since 2017/10/08
244 public boolean isArray()
246 return this.component != null;
250 * Is this a primitive type?
252 * @return {@code true} if this is a primitive type.
253 * @since 2017/07/28
255 public boolean isPrimitive()
257 return this.primitive;
261 * Is this an object type?
263 * @return If this is an object type.
264 * @since 2017/09/16
266 public boolean isObject()
268 return !this.isPrimitive();
272 * Returns if this is a wide field or not.
274 * @return If this is a wide field.
275 * @since 2019/02/05
277 public final boolean isWide()
279 if (this.isObject())
280 return false;
281 switch (this.primitiveType())
283 case LONG:
284 case DOUBLE:
285 return true;
287 default:
288 return false;
293 * Returns the primitive type for this field.
295 * @return The primitive type to use or {@code null} if there is none.
296 * @since 2017/10/16
298 public PrimitiveType primitiveType()
300 // Quick detect
301 if (!this.primitive)
302 return null;
304 // Depends on the string
305 switch (this.toString())
307 case "B": return PrimitiveType.BYTE;
308 case "C": return PrimitiveType.CHARACTER;
309 case "D": return PrimitiveType.DOUBLE;
310 case "F": return PrimitiveType.FLOAT;
311 case "I": return PrimitiveType.INTEGER;
312 case "J": return PrimitiveType.LONG;
313 case "S": return PrimitiveType.SHORT;
314 case "Z": return PrimitiveType.BOOLEAN;
315 default:
316 return null;
321 * Returns the simple storage type of the field.
323 * @return The simple storage type for this field.
324 * @since 2018/09/15
326 public final SimpleStorageType simpleStorageType()
328 // Objects
329 if (this.isObject())
330 return SimpleStorageType.OBJECT;
332 // Primitive types, these are promoted
333 switch (this.primitiveType())
335 case BOOLEAN:
336 case BYTE:
337 case SHORT:
338 case CHARACTER:
339 case INTEGER:
340 return SimpleStorageType.INTEGER;
342 case LONG:
343 return SimpleStorageType.LONG;
345 case FLOAT:
346 return SimpleStorageType.FLOAT;
348 case DOUBLE:
349 return SimpleStorageType.DOUBLE;
351 // Should not occur
352 default:
353 throw Debugging.oops();
358 * Returns the width of this field on the stack.
360 * @return The width of the field on the stack.
361 * @since 2019/02/05
363 public final int stackWidth()
365 return (this.isWide() ? 2 : 1);
369 * {@inheritDoc}
370 * @since 2017/06/12
372 @Override
373 public String toString()
375 return this.string;