1
2 package org.galagosearch.tupleflow.typebuilder;
3
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import org.antlr.stringtemplate.CommonGroupLoader;
9 import org.antlr.stringtemplate.StringTemplate;
10 import org.antlr.stringtemplate.StringTemplateGroup;
11 import org.antlr.stringtemplate.language.AngleBracketTemplateLexer;
12 import org.galagosearch.tupleflow.typebuilder.FieldSpecification.DataType;
13
14 /***
15 *
16 * @author trevor
17 */
18 public class TemplateTypeBuilder {
19 StringTemplateGroup template;
20 String typeName;
21 String typePackage;
22 ArrayList<Field> typeFields;
23 ArrayList<OrderSpec> typeOrders;
24
25 /***
26 * For an array master, returns
27 * an array containing the last master.length-index elements.
28 */
29 public static String[] subarray(String[] master, int index) {
30 if (master.length <= index) {
31 return new String[0];
32 } else {
33 String[] sub = new String[master.length - index];
34 System.arraycopy(master, index, sub, 0, sub.length);
35 return sub;
36 }
37 }
38
39 /***
40 * Returns a string containing all the elements of args, space delimited.
41 */
42 public static String join(String[] args, String delimiter) {
43 String output = "";
44 StringBuilder builder = new StringBuilder();
45
46 for (String arg : args) {
47 if (builder.length() > 0) {
48 builder.append(delimiter);
49 }
50 builder.append(arg);
51 }
52
53 return builder.toString();
54 }
55
56 public static String join(String[] args) {
57 return join(args, " ");
58 }
59
60 public static String caps(String input) {
61 if (input.length() == 0) {
62 return input;
63 }
64 char first = Character.toUpperCase(input.charAt(0));
65 return "" + first + input.substring(1);
66 }
67
68 public static String plural(String input) {
69 return input + "s";
70 }
71
72 public static class Field {
73 public Field(DataType type, String name) {
74 this.dataType = type;
75 this.type = type.getType();
76 this.name = name;
77 this.capsName = caps(name);
78 this.pluralName = plural(name);
79
80 this.inputType = caps(type.getInternalType());
81 this.baseType = type.getBaseType();
82 this.classTypeName = type.getClassName();
83 this.isArray = dataType.isArray();
84 }
85 public DataType dataType;
86 public String type;
87 public String name;
88 public String baseType;
89 public boolean isInteger;
90 public boolean isString;
91 public boolean isArray;
92 public String classTypeName;
93 public String capsName;
94 public String inputType;
95 public String pluralName;
96 }
97
98 public static class OrderedField extends Field {
99 public OrderedField(Field field, boolean ascending, boolean delta, boolean runLengthEncoded) {
100 this(field.dataType, field.name, ascending, delta, runLengthEncoded);
101 }
102
103 public OrderedField(DataType type, String name, boolean ascending, boolean delta, boolean runLengthEncoded) {
104 super(type, name);
105 this.ascending = ascending;
106 this.direction = ascending ? "+" : "-";
107 this.directionName = ascending ? "Ascending" : "Descending";
108 this.runLengthEncoded = runLengthEncoded;
109 this.delta = delta;
110 }
111 public boolean ascending;
112 public String direction;
113 public String directionName;
114 public boolean delta;
115 public boolean runLengthEncoded;
116 public ArrayList<OrderedField> remaining = new ArrayList();
117 }
118
119 public static class OrderSpec {
120 public OrderSpec(OrderSpecification spec, ArrayList<Field> allFields) {
121 this.allFields = allFields;
122
123 HashMap<String, Field> fieldMap = new HashMap();
124 HashSet<String> orderedNames = new HashSet();
125
126 for (Field f : allFields) {
127 fieldMap.put(f.name, f);
128 }
129
130 ArrayList<OrderedFieldSpecification> inputFields = spec.getOrderedFields();
131
132 for (int i = 0; i < inputFields.size(); i++) {
133 Field field = fieldMap.get(inputFields.get(i).getName());
134 boolean isLastField = ((inputFields.size() - i) == 1);
135
136 boolean useDelta = false;
137 boolean useRLE = !useDelta;
138 boolean isAscending = (inputFields.get(i).getDirection() == Direction.ASCENDING);
139 String fieldName = inputFields.get(i).getName();
140
141 if (fieldMap.get(fieldName) == null) {
142 throw new RuntimeException("'" + fieldName + "' is specified in an order statement, " +
143 "but it isn't a type field name.");
144 }
145
146 OrderedField ordered = new OrderedField(fieldMap.get(fieldName),
147 isAscending, useDelta, useRLE);
148 orderedFields.add(ordered);
149 orderedNames.add(fieldName);
150 }
151
152 for (int i = 0; i < inputFields.size(); i++) {
153 orderedFields.get(i).remaining.addAll(
154 orderedFields.subList(i + 1, orderedFields.size()));
155 }
156
157 backwardOrderedFields.addAll(orderedFields);
158 Collections.reverse(backwardOrderedFields);
159
160 for (int i = 0; i < orderedFields.size(); i++) {
161 if (orderedFields.get(i).runLengthEncoded) {
162 rleFields.add(orderedFields.get(i));
163 }
164 if (orderedFields.get(i).delta) {
165 deltaFields.add(orderedFields.get(i));
166 }
167 }
168
169 for (int i = 0; i < orderedFields.size(); i++) {
170 OrderedField current = orderedFields.get(i);
171 OrderedField next = ((i + 1) < orderedFields.size()) ? orderedFields.get(i + 1) : null;
172 OrderedField previous = (i != 0) ? orderedFields.get(i - 1) : null;
173
174 fieldPairs.add(new FieldPair(current, next, previous));
175 }
176
177 for (int i = 0; i < allFields.size(); i++) {
178 if (orderedNames.contains(allFields.get(i).name)) {
179 continue;
180 }
181 unorderedFields.add(allFields.get(i));
182 }
183 }
184
185 public String getClassName() {
186 StringBuilder builder = new StringBuilder();
187
188 if (orderedFields.size() > 0) {
189 for (OrderedField orderedField : orderedFields) {
190 if (!orderedField.ascending) {
191 builder.append("Desc");
192 }
193 builder.append(caps(orderedField.name));
194 }
195
196 builder.append("Order");
197 } else {
198 builder.append("Unordered");
199 }
200
201 return builder.toString();
202 }
203
204 public static class FieldPair {
205 public FieldPair(OrderedField c, OrderedField n, OrderedField p) {
206 current = c;
207 next = n;
208 previous = p;
209 }
210 public OrderedField current;
211 public OrderedField next;
212 public OrderedField previous;
213 }
214 public ArrayList<OrderedField> orderedFields = new ArrayList();
215 public ArrayList<OrderedField> backwardOrderedFields = new ArrayList();
216 public ArrayList<FieldPair> fieldPairs = new ArrayList();
217 public ArrayList<OrderedField> rleFields = new ArrayList();
218 public ArrayList<Field> unorderedFields = new ArrayList();
219 public ArrayList<OrderedField> deltaFields = new ArrayList();
220 public ArrayList<Field> allFields;
221 }
222
223 /***
224 * Returns the text of a Type<T> object for the T class.
225 */
226 @Override
227 public String toString() {
228 StringTemplate t = template.getInstanceOf("type");
229 HashMap<String, Object> map = new HashMap<String, Object>();
230 map.put("typeName", this.typeName);
231 map.put("package", this.typePackage);
232 map.put("orders", this.typeOrders);
233 map.put("fields", this.typeFields);
234
235 boolean containsArray = false;
236 for (Field f : typeFields) {
237 containsArray = containsArray || f.isArray;
238 }
239 map.put("containsArray", containsArray);
240 t.setAttributes(map);
241 return t.toString();
242 }
243
244 public TemplateTypeBuilder(TypeSpecification spec) {
245 CommonGroupLoader loader = new CommonGroupLoader("org/galagosearch/tupleflow/templates", null);
246 StringTemplateGroup.registerGroupLoader(loader);
247 StringTemplateGroup.registerDefaultLexer(AngleBracketTemplateLexer.class);
248 this.template = StringTemplateGroup.loadGroup("GalagoType");
249
250 this.typeName = spec.getTypeName();
251 this.typePackage = spec.getPackageName();
252 this.typeFields = new ArrayList<Field>();
253 this.typeOrders = new ArrayList<OrderSpec>();
254
255 for (FieldSpecification fieldSpec : spec.getFields()) {
256 Field field = new Field(fieldSpec.getType(), fieldSpec.getName());
257 typeFields.add(field);
258 }
259
260 for (OrderSpecification orderSpec : spec.getOrders()) {
261 OrderSpec order = new OrderSpec(orderSpec, typeFields);
262 typeOrders.add(order);
263 }
264 }
265
266 public static void main(String[] args) throws java.lang.Exception {
267 for (String fileName : args) {
268 TypeSpecification spec = ParserDriver.getTypeSpecification(fileName);
269 TemplateTypeBuilder builder = new TemplateTypeBuilder(spec);
270
271 java.io.FileWriter writer = new java.io.FileWriter(spec.getTypeName() + ".java");
272 String comment = "// This file was automatically generated with the command: \n" +
273 "// java org.galagosearch.tupleflow.typebuilder.TemplateTypeBuilder ...\n";
274
275 writer.write(comment);
276 writer.write(builder.toString());
277 writer.close();
278 }
279 }
280 }