]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/parser/repository/DataValueRepository.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / parser / repository / DataValueRepository.java
1 /*******************************************************************************\r
2  *  Copyright (c) 2010 Association for Decentralized Information Management in\r
3  *  Industry THTH ry.\r
4  *  All rights reserved. This program and the accompanying materials\r
5  *  are made available under the terms of the Eclipse Public License v1.0\r
6  *  which accompanies this distribution, and is available at\r
7  *  http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  *  Contributors:\r
10  *      VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.databoard.parser.repository;\r
13 \r
14 import java.io.IOException;\r
15 import java.io.StringReader;\r
16 import java.util.Collection;\r
17 import java.util.HashMap;\r
18 import java.util.IdentityHashMap;\r
19 import java.util.Map;\r
20 import java.util.Map.Entry;\r
21 import java.util.Set;\r
22 \r
23 import org.simantics.databoard.Bindings;\r
24 import org.simantics.databoard.Datatypes;\r
25 import org.simantics.databoard.binding.ArrayBinding;\r
26 import org.simantics.databoard.binding.Binding;\r
27 import org.simantics.databoard.binding.BooleanBinding;\r
28 import org.simantics.databoard.binding.ByteBinding;\r
29 import org.simantics.databoard.binding.DoubleBinding;\r
30 import org.simantics.databoard.binding.FloatBinding;\r
31 import org.simantics.databoard.binding.IntegerBinding;\r
32 import org.simantics.databoard.binding.LongBinding;\r
33 import org.simantics.databoard.binding.MapBinding;\r
34 import org.simantics.databoard.binding.OptionalBinding;\r
35 import org.simantics.databoard.binding.RecordBinding;\r
36 import org.simantics.databoard.binding.StringBinding;\r
37 import org.simantics.databoard.binding.UnionBinding;\r
38 import org.simantics.databoard.binding.VariantBinding;\r
39 import org.simantics.databoard.binding.error.BindingConstructionException;\r
40 import org.simantics.databoard.binding.error.BindingException;\r
41 import org.simantics.databoard.binding.error.RuntimeBindingException;\r
42 import org.simantics.databoard.binding.factory.BindingScheme;\r
43 import org.simantics.databoard.binding.mutable.MutableVariant;\r
44 import org.simantics.databoard.file.RuntimeIOException;\r
45 import org.simantics.databoard.parser.DataParser;\r
46 import org.simantics.databoard.parser.DataValuePrinter;\r
47 import org.simantics.databoard.parser.ParseException;\r
48 import org.simantics.databoard.parser.PrintFormat;\r
49 import org.simantics.databoard.parser.TokenMgrError;\r
50 import org.simantics.databoard.parser.ast.value.AstArray;\r
51 import org.simantics.databoard.parser.ast.value.AstBoolean;\r
52 import org.simantics.databoard.parser.ast.value.AstComponentAssignment;\r
53 import org.simantics.databoard.parser.ast.value.AstFloat;\r
54 import org.simantics.databoard.parser.ast.value.AstInteger;\r
55 import org.simantics.databoard.parser.ast.value.AstMap;\r
56 import org.simantics.databoard.parser.ast.value.AstMapAssignment;\r
57 import org.simantics.databoard.parser.ast.value.AstNull;\r
58 import org.simantics.databoard.parser.ast.value.AstRecord;\r
59 import org.simantics.databoard.parser.ast.value.AstReference;\r
60 import org.simantics.databoard.parser.ast.value.AstString;\r
61 import org.simantics.databoard.parser.ast.value.AstTaggedValue;\r
62 import org.simantics.databoard.parser.ast.value.AstTuple;\r
63 import org.simantics.databoard.parser.ast.value.AstValue;\r
64 import org.simantics.databoard.parser.ast.value.AstValueDefinition;\r
65 import org.simantics.databoard.parser.ast.value.AstVariant;\r
66 import org.simantics.databoard.parser.ast.value.visitor.AstValueVisitor;\r
67 import org.simantics.databoard.parser.unparsing.DataTypePrinter;\r
68 import org.simantics.databoard.type.Component;\r
69 import org.simantics.databoard.type.Datatype;\r
70 import org.simantics.databoard.type.MapType;\r
71 import org.simantics.databoard.type.RecordType;\r
72 import org.simantics.databoard.type.UnionType;\r
73 \r
74 /**\r
75  * Data value repository is a collection of name data values.\r
76  * Each value is associated with type. \r
77  * \r
78  * <p>\r
79  * It can also translate data lines and value texts to objects and \r
80  * print values as \r
81  * \r
82  * \r
83  * \r
84  * @author Hannu Niemist&ouml;\r
85  */\r
86 public class DataValueRepository {\r
87         \r
88         // Type respository to convert \r
89         DataTypeRepository typeRepository = Datatypes.datatypeRepository;\r
90         \r
91         // Scheme to convert values \r
92         BindingScheme bindingScheme = Bindings.mutableBindingFactory;\r
93         \r
94         /** Stored values */\r
95         Map<String, MutableVariant> values = new HashMap<String, MutableVariant>();\r
96         Map<Object, String> nameMap = new IdentityHashMap<Object, String>();\r
97         \r
98         public MutableVariant get(String name) {\r
99                 return values.get(name);\r
100         }\r
101         \r
102         public String getName(Object value) {\r
103                 return nameMap.get(value);\r
104         }\r
105 \r
106         public void put(String name, Binding binding, Object value) {\r
107                 put(name, new MutableVariant(binding, value));\r
108         }\r
109         \r
110         public void put(String name, MutableVariant value) {\r
111                 values.put(name, value);\r
112                 nameMap.put(value.getValue(), name);\r
113         }\r
114         \r
115         public MutableVariant remove(String name) {\r
116                 MutableVariant value = values.remove(name);\r
117                 if (value==null) return null;\r
118                 nameMap.remove(value.getValue());\r
119                 return value;\r
120         }\r
121         \r
122         public void clear() {\r
123                 values.clear();\r
124                 nameMap.clear();\r
125         }\r
126         \r
127         /**\r
128          * Get a view of the value names in this repository\r
129          * \r
130          * @return names\r
131          */\r
132         public Set<String> getValueNames() {\r
133                 return values.keySet();\r
134         }\r
135         \r
136         /**\r
137          * Translates a data value from an abstract syntax tree to an object by the binding.\r
138          * \r
139          * @param value\r
140          * @param binding\r
141          * @return value\r
142          * @throws DataTypeSyntaxError\r
143          */\r
144         public Object translate(AstValue value, Binding binding) throws DataTypeSyntaxError {           \r
145                 try {\r
146                         if(value instanceof AstReference) {\r
147                                 String name = ((AstReference)value).name;\r
148                                 MutableVariant v = get(name);\r
149                                 if(v == null) {\r
150                                         if(binding instanceof UnionBinding) {\r
151                                                 UnionBinding b = (UnionBinding)binding;\r
152                                                 UnionType type = b.type();\r
153                                                 Integer index = type.getComponentIndex(name);\r
154                                                 if(index != null)\r
155                                                         try {\r
156                                                                 return b.create(index, \r
157                                                                                 b.getComponentBinding(index).createDefault());\r
158                                                         } catch(BindingException e) {\r
159                                                                 throw new DataTypeSyntaxError(e);\r
160                                                         }\r
161                                         }\r
162                                         throw new DataTypeSyntaxError("Undefined reference to " + name + ".");\r
163                                 }\r
164                                 return Bindings.adaptUnchecked(v.getValue(), v.getBinding(), binding);\r
165                         }\r
166                         return binding.accept(new ValueTranslator(value));\r
167                 } catch(ValueTranslationRuntimeException e) {\r
168                         throw new DataTypeSyntaxError(e);\r
169                 }\r
170         }\r
171         \r
172         /**\r
173          * Translates a data value from a string to an object by the binding.\r
174          * @param value\r
175          * @param binding\r
176          * @return value\r
177          * @throws DataTypeSyntaxError\r
178          */\r
179         public Object translate(String value, Binding binding) throws DataTypeSyntaxError {\r
180                 try {\r
181                         return translate(new DataParser(new StringReader(value)).value(), binding);\r
182                 } catch (TokenMgrError e) {\r
183                         throw new DataTypeSyntaxError(e);\r
184                 } catch (ParseException e) {\r
185                         throw new DataTypeSyntaxError(e);\r
186                 }\r
187         }\r
188         \r
189         /**\r
190          * Adds a value definition to the repository\r
191          * @param def\r
192          * @throws DataTypeSyntaxError\r
193          */\r
194         public void addValueDefinition(AstValueDefinition def) throws DataTypeSyntaxError {\r
195                 Datatype type = typeRepository.translate(def.type);\r
196                 Binding binding = Bindings.getMutableBinding(type);\r
197                 MutableVariant variant = new MutableVariant(binding, translate(def.value, binding));\r
198                 values.put(def.name, variant);\r
199                 nameMap.put(variant.getValue(), def.name);\r
200         }\r
201         \r
202         /**\r
203          * Adds a value definition to the repository\r
204          * @param def\r
205          * @return name\r
206          * @throws DataTypeSyntaxError\r
207          */\r
208         public String addValueDefinition(String def) throws DataTypeSyntaxError {\r
209                 try {\r
210                         StringReader reader = new StringReader(def);\r
211                         DataParser parser = new DataParser( reader );\r
212                         AstValueDefinition valueAstDef = parser.valueDefinition(); \r
213                         addValueDefinition( valueAstDef );\r
214                         return valueAstDef.name;\r
215                 } catch (TokenMgrError e) {\r
216                         throw new DataTypeSyntaxError(e);\r
217                 } catch (ParseException e) {\r
218                         throw new DataTypeSyntaxError(e);\r
219                 }\r
220         }\r
221         \r
222         /**\r
223          * Adds multiple value definitions to the repository\r
224          * \r
225          * @param defs\r
226          * @throws DataTypeSyntaxError\r
227          */\r
228         public void addValueDefinitions(Collection<AstValueDefinition> defs) throws DataTypeSyntaxError {\r
229                 // TODO recursive definitions\r
230                 for(AstValueDefinition def : defs)\r
231                         addValueDefinition(def);\r
232         }\r
233         \r
234         /**\r
235          * Adds multiple value definitions to the repository\r
236          * @param def\r
237          * @throws DataTypeSyntaxError\r
238          */\r
239         public void addValueDefinitions(String def) throws DataTypeSyntaxError {\r
240                 try {\r
241                         addValueDefinitions(new DataParser(new StringReader(def)).valueDefinitions());\r
242                 } catch (TokenMgrError e) {\r
243                         throw new DataTypeSyntaxError(e);\r
244                 } catch (ParseException e) {\r
245                         throw new DataTypeSyntaxError(e);\r
246                 }\r
247         }\r
248         \r
249         public DataTypeRepository getTypeRepository() {\r
250                 return typeRepository;\r
251         }\r
252 \r
253         public void setTypeRepository(DataTypeRepository typeRepository) {\r
254                 this.typeRepository = typeRepository;\r
255         }\r
256 \r
257         public BindingScheme getBindingScheme() {\r
258                 return bindingScheme;\r
259         }\r
260 \r
261         public void setBindingScheme(BindingScheme bindingScheme) {\r
262                 this.bindingScheme = bindingScheme;\r
263         }\r
264 \r
265         /**\r
266          * Print the content part of a data value. This excludes the name and type of the value.\r
267          * \r
268          * @param valueName\r
269          * @return value or <code>null</code> if value doesn't exist\r
270          * @throws BindingException \r
271          * @throws IOException \r
272          */\r
273         public String printValue(String valueName) throws IOException, BindingException {\r
274                 MutableVariant value = get(valueName);\r
275                 if (value==null) return null;\r
276                 StringBuilder sb = new StringBuilder();\r
277                 DataValuePrinter vp = new DataValuePrinter(sb, this);\r
278                 vp.print(value);\r
279                 return sb.toString();\r
280         }\r
281         \r
282         /**\r
283          * Print the whole value repository\r
284          * \r
285          * @param sb\r
286          * @throws IOException\r
287          * @throws BindingException\r
288          */\r
289         public void print(StringBuilder sb)\r
290         throws IOException, BindingException\r
291         {\r
292                 DataValuePrinter vp = new DataValuePrinter(sb, this);\r
293                 vp.setFormat( PrintFormat.SINGLE_LINE );\r
294                 DataTypePrinter tp = new DataTypePrinter( sb );\r
295                 tp.setLinefeed( false );\r
296                         \r
297                 for (Entry<String, MutableVariant> e : values.entrySet()) {\r
298                         String name = e.getKey();\r
299                         MutableVariant value = e.getValue();\r
300                         Datatype type = value.type();\r
301                         sb.append( name+" : " );\r
302                         tp.print(type);\r
303                         sb.append( " = " );\r
304                         vp.print(value);                        \r
305                         sb.append("\n");\r
306                 }\r
307         }       \r
308 \r
309         /**\r
310          * Print the whole data value repository as a single multiline string\r
311          * \r
312          * @throws RuntimeBindingException\r
313          * @throws {@link RuntimeIOException}\r
314          */\r
315         @Override\r
316         public String toString() {\r
317                 try {\r
318                         StringBuilder sb = new StringBuilder();\r
319                         print(sb);\r
320                         return sb.toString();\r
321                 } catch (BindingException e) {\r
322                         throw new RuntimeBindingException(e);\r
323                 } catch (IOException e) {\r
324                         throw new RuntimeIOException(e);\r
325                 }\r
326         }\r
327         \r
328         /**\r
329          * Gives a data type to a value heuristically.\r
330          */\r
331         public Datatype guessDataType(AstValue value) throws DataTypeSyntaxError {\r
332                 return value.accept(guessDataType);\r
333         }\r
334         \r
335         /**\r
336          * Gives a data type to a value heuristically.\r
337          */\r
338         public Datatype guessDataType(String value) throws DataTypeSyntaxError {\r
339                 try {\r
340                         return guessDataType(new DataParser(new StringReader(value)).value());\r
341                 } catch (TokenMgrError e) {\r
342                         throw new DataTypeSyntaxError(e);\r
343                 } catch (ParseException e) {\r
344                         throw new DataTypeSyntaxError(e);\r
345                 }\r
346         }\r
347 \r
348         class ValueTranslator implements Binding.Visitor<Object> {\r
349 \r
350                 AstValue value;\r
351                 \r
352                 public ValueTranslator(AstValue value) {\r
353                         this.value = value;\r
354                 }\r
355                 \r
356                 private ValueTranslationRuntimeException typeError(Binding expectedType, AstValue actualValue) {\r
357                         throw new ValueTranslationRuntimeException("Expected " + expectedType.type().toSingleLineString() + \r
358                                         " but got " + actualValue.getClass().getSimpleName() + ".");\r
359                 }\r
360 \r
361                 @Override\r
362                 public Object visit(ArrayBinding b) {\r
363                         if(value instanceof AstArray) {\r
364                                 AstArray array = (AstArray)value;\r
365                                 Object[] components = new Object[array.elements.size()];\r
366                                 Binding componentBinding = b.getComponentBinding();\r
367                                 int i=0;\r
368                                 for(AstValue component : array.elements) {\r
369                                         value = component;\r
370                                         components[i++] = componentBinding.accept(this);\r
371                                 }\r
372                                 return b.createUnchecked(components);\r
373                         }\r
374                         throw typeError(b, value);\r
375                 }\r
376 \r
377                 @Override\r
378                 public Object visit(BooleanBinding b) {\r
379                         if(value instanceof AstBoolean) {                               \r
380                                 return b.createUnchecked(((AstBoolean)value).value);\r
381                         }\r
382                         throw typeError(b, value);\r
383                 }\r
384 \r
385                 @Override\r
386                 public Object visit(DoubleBinding b) {\r
387                         if(value instanceof AstFloat) {                         \r
388                                 return b.createUnchecked(((AstFloat)value).value);\r
389                         }\r
390                         if(value instanceof AstInteger) {                               \r
391                                 return b.createUnchecked(((AstInteger)value).value);\r
392                         }\r
393                         throw typeError(b, value);\r
394                 }\r
395 \r
396                 @Override\r
397                 public Object visit(FloatBinding b) {\r
398                         if(value instanceof AstFloat) {                         \r
399                                 return b.createUnchecked(((AstFloat)value).value);\r
400                         }\r
401                         if(value instanceof AstInteger) {                               \r
402                                 return b.createUnchecked(((AstInteger)value).value);\r
403                         }\r
404                         throw typeError(b, value);\r
405                 }\r
406 \r
407                 @Override\r
408                 public Object visit(IntegerBinding b) {\r
409                         if(value instanceof AstInteger) {                               \r
410                                 return b.createUnchecked(((AstInteger)value).value);\r
411                         }\r
412                         throw typeError(b, value);\r
413                 }\r
414 \r
415                 @Override\r
416                 public Object visit(ByteBinding b) {\r
417                         if(value instanceof AstInteger) {                               \r
418                                 return b.createUnchecked(((AstInteger)value).value);\r
419                         }\r
420                         throw typeError(b, value);\r
421                 }\r
422 \r
423                 @Override\r
424                 public Object visit(LongBinding b) {\r
425                         if(value instanceof AstInteger) {                               \r
426                                 return b.createUnchecked(((AstInteger)value).value);\r
427                         }\r
428                         throw typeError(b, value);\r
429                 }\r
430 \r
431                 @Override\r
432                 public Object visit(OptionalBinding b) {\r
433                         if(value == AstNull.NULL)\r
434                                 return b.createNoValueUnchecked();\r
435                         else\r
436                                 return b.createValueUnchecked(b.getComponentBinding().accept(this));                            \r
437                 }\r
438 \r
439                 @Override\r
440                 public Object visit(RecordBinding b) {\r
441                         if(value instanceof AstRecord) {\r
442                                 AstRecord record = (AstRecord)value;\r
443                                 Object[] components = new Object[b.getComponentCount()];\r
444                                 boolean[] assigned = new boolean[b.getComponentCount()];\r
445                                 for(AstComponentAssignment assignment : record.components) {\r
446                                         value = assignment.value;\r
447                                         Integer index = b.type().getComponentIndex(assignment.component);\r
448                                         if(index == null)\r
449                                                 throw new ValueTranslationRuntimeException("Invalid record component " + assignment.component + ".");\r
450                                         components[index] = b.getComponentBinding(index).accept(this);\r
451                                         assigned[index] = true;\r
452                                 }\r
453                                 for(int i=0;i<assigned.length;++i)\r
454                                         if(!assigned[i]) {\r
455                                                 Binding binding = b.getComponentBinding(i);\r
456                                                 if(binding instanceof OptionalBinding)\r
457                                                         components[i] = ((OptionalBinding)binding).createNoValueUnchecked();\r
458                                                 else\r
459                                                         throw new ValueTranslationRuntimeException("Non-optional field " + \r
460                                                                         b.type().getComponent(i).name + " is not defined.");\r
461                                         }\r
462                                 return b.createUnchecked(components);                           \r
463                         }\r
464                         if(value instanceof AstTuple) {\r
465                                 AstTuple tuple = (AstTuple)value;\r
466                                 Object[] components = new Object[b.getComponentCount()];\r
467                                 int i=0;\r
468                                 for(AstValue element : tuple.elements) {\r
469                                         value = element;\r
470                                         components[i] = b.getComponentBinding(i).accept(this);\r
471                                         ++i;\r
472                                 }\r
473                                 return b.createUnchecked(components);\r
474                         }\r
475                         throw typeError(b, value);\r
476                 }\r
477 \r
478                 @Override\r
479                 public Object visit(StringBinding b) {\r
480                         if(value instanceof AstString) {                                \r
481                                 return b.createUnchecked(((AstString)value).value);\r
482                         }\r
483                         throw typeError(b, value);\r
484                 }\r
485 \r
486                 @Override\r
487                 public Object visit(UnionBinding b) {\r
488                         if(value instanceof AstTaggedValue) {\r
489                                 AstTaggedValue taggedValue = (AstTaggedValue)value;\r
490                                 Integer tagIndex = b.type().getComponentIndex(taggedValue.tag);\r
491                                 if(tagIndex == null)\r
492                                         throw new ValueTranslationRuntimeException("Invalid union tag " + taggedValue.tag + ".");\r
493                                 value = taggedValue.value;\r
494                                 return b.createUnchecked(tagIndex, b.getComponentBinding(tagIndex).accept(this));\r
495                         }\r
496                         else if(value instanceof AstReference) {\r
497                             AstReference ref = (AstReference)value;\r
498                             Integer tagIndex = b.type().getComponentIndex(ref.name);\r
499                             if(tagIndex == null)\r
500                     throw new ValueTranslationRuntimeException("Invalid union tag " + ref.name + ".");\r
501                             try {\r
502                                 return b.createUnchecked(tagIndex, b.getComponentBinding(tagIndex).createDefault());\r
503                             } catch(BindingException e) {                               \r
504                             }\r
505                         }\r
506                         throw typeError(b, value);\r
507                 }\r
508 \r
509                 @Override\r
510                 public Object visit(VariantBinding b) {\r
511                         try {\r
512                                 if(value instanceof AstVariant) {\r
513                                         AstVariant variant = (AstVariant)value;\r
514                                         Datatype dataType = typeRepository.translate(variant.type);\r
515                                         Binding binding = bindingScheme.getBinding(dataType);\r
516                                         value = variant.value;\r
517                                         return b.createUnchecked(binding, binding.accept(this));\r
518                                 }\r
519                                 else {\r
520                                         Datatype dataType = guessDataType(value);\r
521                                         Binding binding = bindingScheme.getBinding(dataType);\r
522                                         return b.createUnchecked(binding, binding.accept(this));\r
523                                 }\r
524                         } catch(DataTypeSyntaxError e) {\r
525                                 throw new ValueTranslationRuntimeException(e);\r
526                         } catch (BindingConstructionException e) {\r
527                                 throw new ValueTranslationRuntimeException(e);\r
528                         }\r
529                 }\r
530 \r
531                 @Override\r
532                 public Object visit(MapBinding b) {\r
533                         if(value instanceof AstMap) {\r
534                                 AstMap map = (AstMap)value;\r
535                                 Object[] keys = new Object[map.components.size()];\r
536                                 Object[] values = new Object[map.components.size()];\r
537                                 Binding keyBinding = b.getKeyBinding();\r
538                                 Binding valueBinding = b.getValueBinding();\r
539                                 int i = 0;\r
540                                 for(AstMapAssignment assignment : map.components) {\r
541                                         value = assignment.key;\r
542                                         keys[i] = keyBinding.accept(this);                                      \r
543                                         value = assignment.value;\r
544                                         values[i] = valueBinding.accept(this);                                  \r
545                                         ++i;\r
546                                 }\r
547                                 return b.createUnchecked(keys, values);                         \r
548                         }\r
549                         throw typeError(b, value);\r
550                 }\r
551                 \r
552         }\r
553         \r
554         AstValueVisitor<Datatype> guessDataType = new AstValueVisitor<Datatype>() {\r
555 \r
556                 @Override\r
557                 public Datatype visit(AstArray astArray) {\r
558                         if(astArray.elements.isEmpty())\r
559                                 throw new ValueTranslationRuntimeException("Cannot guess the data type of empty array.");\r
560                         return astArray.elements.get(0).accept(this);\r
561                 }\r
562 \r
563                 @Override\r
564                 public Datatype visit(AstBoolean astBoolean) {\r
565                         return Datatypes.BOOLEAN;\r
566                 }\r
567 \r
568                 @Override\r
569                 public Datatype visit(AstFloat astFloat) {\r
570                         return Datatypes.DOUBLE;\r
571                 }\r
572 \r
573                 @Override\r
574                 public Datatype visit(AstInteger astInteger) {\r
575                         return Datatypes.INTEGER;\r
576                 }\r
577 \r
578                 @Override\r
579                 public Datatype visit(AstMap astMap) {\r
580                         if(astMap.components.isEmpty())\r
581                                 throw new ValueTranslationRuntimeException("Cannot guess the data type of empty map.");\r
582                         AstMapAssignment assignment = astMap.components.get(0);\r
583                         return new MapType(assignment.key.accept(this), assignment.value.accept(this));\r
584                 }\r
585 \r
586                 @Override\r
587                 public Datatype visit(AstNull astNull) {\r
588                         throw new ValueTranslationRuntimeException("Cannot guess the data type");\r
589                 }\r
590 \r
591                 @Override\r
592                 public Datatype visit(AstRecord astRecord) {\r
593                         Component[] components = new Component[astRecord.components.size()];\r
594                         int i = 0;\r
595                         for(AstComponentAssignment assignment : astRecord.components) {\r
596                                 components[i++] = new Component(\r
597                                                 assignment.component,\r
598                                                 assignment.value.accept(this)\r
599                                                 );\r
600                         }\r
601                         return new RecordType(false, components);\r
602                 }\r
603 \r
604                 @Override\r
605                 public Datatype visit(AstReference astReference) {\r
606                         MutableVariant v = get(astReference.name);\r
607                         if(v == null)\r
608                                 throw new ValueTranslationRuntimeException("Undefined reference to " + astReference.name + ".");\r
609                         return v.type();\r
610                 }\r
611 \r
612                 @Override\r
613                 public Datatype visit(AstString astString) {\r
614                         return Datatypes.STRING;\r
615                 }\r
616 \r
617                 @Override\r
618                 public Datatype visit(AstTaggedValue astTaggedValue) {\r
619                         // Guessed datatype would be a union with just one component. Not very useful.\r
620                         throw new ValueTranslationRuntimeException("Cannot guess the data type of tagged value");\r
621                 }\r
622 \r
623                 @Override\r
624                 public Datatype visit(AstTuple astTuple) {\r
625                         Component[] components = new Component[astTuple.elements.size()];\r
626                         int i = 0;\r
627                         for(AstValue value : astTuple.elements) {\r
628                                 components[i] = new Component(\r
629                                                 Integer.toString(i),\r
630                                                 value.accept(this)\r
631                                                 );\r
632                                 ++i;\r
633                         }\r
634                         return new RecordType(false, components);\r
635                 }\r
636 \r
637                 @Override\r
638                 public Datatype visit(AstVariant astVariant) {\r
639                         return Datatypes.VARIANT;\r
640                 }\r
641         };\r
642         \r
643         \r
644 }\r