X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=bundles%2Forg.simantics.databoard%2Fsrc%2Forg%2Fsimantics%2Fdataboard%2Fparser%2Frepository%2FDataValueRepository.java;h=9912e9ac6529fb5f8eb33913420f2a27207d4262;hb=refs%2Fchanges%2F38%2F238%2F2;hp=0bba95ada2cfde5f657933b07d6e6532fbb9c9cf;hpb=24e2b34260f219f0d1644ca7a138894980e25b14;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/parser/repository/DataValueRepository.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/parser/repository/DataValueRepository.java index 0bba95ada..9912e9ac6 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/parser/repository/DataValueRepository.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/parser/repository/DataValueRepository.java @@ -1,644 +1,644 @@ -/******************************************************************************* - * Copyright (c) 2010 Association for Decentralized Information Management in - * Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.databoard.parser.repository; - -import java.io.IOException; -import java.io.StringReader; -import java.util.Collection; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.simantics.databoard.Bindings; -import org.simantics.databoard.Datatypes; -import org.simantics.databoard.binding.ArrayBinding; -import org.simantics.databoard.binding.Binding; -import org.simantics.databoard.binding.BooleanBinding; -import org.simantics.databoard.binding.ByteBinding; -import org.simantics.databoard.binding.DoubleBinding; -import org.simantics.databoard.binding.FloatBinding; -import org.simantics.databoard.binding.IntegerBinding; -import org.simantics.databoard.binding.LongBinding; -import org.simantics.databoard.binding.MapBinding; -import org.simantics.databoard.binding.OptionalBinding; -import org.simantics.databoard.binding.RecordBinding; -import org.simantics.databoard.binding.StringBinding; -import org.simantics.databoard.binding.UnionBinding; -import org.simantics.databoard.binding.VariantBinding; -import org.simantics.databoard.binding.error.BindingConstructionException; -import org.simantics.databoard.binding.error.BindingException; -import org.simantics.databoard.binding.error.RuntimeBindingException; -import org.simantics.databoard.binding.factory.BindingScheme; -import org.simantics.databoard.binding.mutable.MutableVariant; -import org.simantics.databoard.file.RuntimeIOException; -import org.simantics.databoard.parser.DataParser; -import org.simantics.databoard.parser.DataValuePrinter; -import org.simantics.databoard.parser.ParseException; -import org.simantics.databoard.parser.PrintFormat; -import org.simantics.databoard.parser.TokenMgrError; -import org.simantics.databoard.parser.ast.value.AstArray; -import org.simantics.databoard.parser.ast.value.AstBoolean; -import org.simantics.databoard.parser.ast.value.AstComponentAssignment; -import org.simantics.databoard.parser.ast.value.AstFloat; -import org.simantics.databoard.parser.ast.value.AstInteger; -import org.simantics.databoard.parser.ast.value.AstMap; -import org.simantics.databoard.parser.ast.value.AstMapAssignment; -import org.simantics.databoard.parser.ast.value.AstNull; -import org.simantics.databoard.parser.ast.value.AstRecord; -import org.simantics.databoard.parser.ast.value.AstReference; -import org.simantics.databoard.parser.ast.value.AstString; -import org.simantics.databoard.parser.ast.value.AstTaggedValue; -import org.simantics.databoard.parser.ast.value.AstTuple; -import org.simantics.databoard.parser.ast.value.AstValue; -import org.simantics.databoard.parser.ast.value.AstValueDefinition; -import org.simantics.databoard.parser.ast.value.AstVariant; -import org.simantics.databoard.parser.ast.value.visitor.AstValueVisitor; -import org.simantics.databoard.parser.unparsing.DataTypePrinter; -import org.simantics.databoard.type.Component; -import org.simantics.databoard.type.Datatype; -import org.simantics.databoard.type.MapType; -import org.simantics.databoard.type.RecordType; -import org.simantics.databoard.type.UnionType; - -/** - * Data value repository is a collection of name data values. - * Each value is associated with type. - * - *

- * It can also translate data lines and value texts to objects and - * print values as - * - * - * - * @author Hannu Niemistö - */ -public class DataValueRepository { - - // Type respository to convert - DataTypeRepository typeRepository = Datatypes.datatypeRepository; - - // Scheme to convert values - BindingScheme bindingScheme = Bindings.mutableBindingFactory; - - /** Stored values */ - Map values = new HashMap(); - Map nameMap = new IdentityHashMap(); - - public MutableVariant get(String name) { - return values.get(name); - } - - public String getName(Object value) { - return nameMap.get(value); - } - - public void put(String name, Binding binding, Object value) { - put(name, new MutableVariant(binding, value)); - } - - public void put(String name, MutableVariant value) { - values.put(name, value); - nameMap.put(value.getValue(), name); - } - - public MutableVariant remove(String name) { - MutableVariant value = values.remove(name); - if (value==null) return null; - nameMap.remove(value.getValue()); - return value; - } - - public void clear() { - values.clear(); - nameMap.clear(); - } - - /** - * Get a view of the value names in this repository - * - * @return names - */ - public Set getValueNames() { - return values.keySet(); - } - - /** - * Translates a data value from an abstract syntax tree to an object by the binding. - * - * @param value - * @param binding - * @return value - * @throws DataTypeSyntaxError - */ - public Object translate(AstValue value, Binding binding) throws DataTypeSyntaxError { - try { - if(value instanceof AstReference) { - String name = ((AstReference)value).name; - MutableVariant v = get(name); - if(v == null) { - if(binding instanceof UnionBinding) { - UnionBinding b = (UnionBinding)binding; - UnionType type = b.type(); - Integer index = type.getComponentIndex(name); - if(index != null) - try { - return b.create(index, - b.getComponentBinding(index).createDefault()); - } catch(BindingException e) { - throw new DataTypeSyntaxError(e); - } - } - throw new DataTypeSyntaxError("Undefined reference to " + name + "."); - } - return Bindings.adaptUnchecked(v.getValue(), v.getBinding(), binding); - } - return binding.accept(new ValueTranslator(value)); - } catch(ValueTranslationRuntimeException e) { - throw new DataTypeSyntaxError(e); - } - } - - /** - * Translates a data value from a string to an object by the binding. - * @param value - * @param binding - * @return value - * @throws DataTypeSyntaxError - */ - public Object translate(String value, Binding binding) throws DataTypeSyntaxError { - try { - return translate(new DataParser(new StringReader(value)).value(), binding); - } catch (TokenMgrError e) { - throw new DataTypeSyntaxError(e); - } catch (ParseException e) { - throw new DataTypeSyntaxError(e); - } - } - - /** - * Adds a value definition to the repository - * @param def - * @throws DataTypeSyntaxError - */ - public void addValueDefinition(AstValueDefinition def) throws DataTypeSyntaxError { - Datatype type = typeRepository.translate(def.type); - Binding binding = Bindings.getMutableBinding(type); - MutableVariant variant = new MutableVariant(binding, translate(def.value, binding)); - values.put(def.name, variant); - nameMap.put(variant.getValue(), def.name); - } - - /** - * Adds a value definition to the repository - * @param def - * @return name - * @throws DataTypeSyntaxError - */ - public String addValueDefinition(String def) throws DataTypeSyntaxError { - try { - StringReader reader = new StringReader(def); - DataParser parser = new DataParser( reader ); - AstValueDefinition valueAstDef = parser.valueDefinition(); - addValueDefinition( valueAstDef ); - return valueAstDef.name; - } catch (TokenMgrError e) { - throw new DataTypeSyntaxError(e); - } catch (ParseException e) { - throw new DataTypeSyntaxError(e); - } - } - - /** - * Adds multiple value definitions to the repository - * - * @param defs - * @throws DataTypeSyntaxError - */ - public void addValueDefinitions(Collection defs) throws DataTypeSyntaxError { - // TODO recursive definitions - for(AstValueDefinition def : defs) - addValueDefinition(def); - } - - /** - * Adds multiple value definitions to the repository - * @param def - * @throws DataTypeSyntaxError - */ - public void addValueDefinitions(String def) throws DataTypeSyntaxError { - try { - addValueDefinitions(new DataParser(new StringReader(def)).valueDefinitions()); - } catch (TokenMgrError e) { - throw new DataTypeSyntaxError(e); - } catch (ParseException e) { - throw new DataTypeSyntaxError(e); - } - } - - public DataTypeRepository getTypeRepository() { - return typeRepository; - } - - public void setTypeRepository(DataTypeRepository typeRepository) { - this.typeRepository = typeRepository; - } - - public BindingScheme getBindingScheme() { - return bindingScheme; - } - - public void setBindingScheme(BindingScheme bindingScheme) { - this.bindingScheme = bindingScheme; - } - - /** - * Print the content part of a data value. This excludes the name and type of the value. - * - * @param valueName - * @return value or null if value doesn't exist - * @throws BindingException - * @throws IOException - */ - public String printValue(String valueName) throws IOException, BindingException { - MutableVariant value = get(valueName); - if (value==null) return null; - StringBuilder sb = new StringBuilder(); - DataValuePrinter vp = new DataValuePrinter(sb, this); - vp.print(value); - return sb.toString(); - } - - /** - * Print the whole value repository - * - * @param sb - * @throws IOException - * @throws BindingException - */ - public void print(StringBuilder sb) - throws IOException, BindingException - { - DataValuePrinter vp = new DataValuePrinter(sb, this); - vp.setFormat( PrintFormat.SINGLE_LINE ); - DataTypePrinter tp = new DataTypePrinter( sb ); - tp.setLinefeed( false ); - - for (Entry e : values.entrySet()) { - String name = e.getKey(); - MutableVariant value = e.getValue(); - Datatype type = value.type(); - sb.append( name+" : " ); - tp.print(type); - sb.append( " = " ); - vp.print(value); - sb.append("\n"); - } - } - - /** - * Print the whole data value repository as a single multiline string - * - * @throws RuntimeBindingException - * @throws {@link RuntimeIOException} - */ - @Override - public String toString() { - try { - StringBuilder sb = new StringBuilder(); - print(sb); - return sb.toString(); - } catch (BindingException e) { - throw new RuntimeBindingException(e); - } catch (IOException e) { - throw new RuntimeIOException(e); - } - } - - /** - * Gives a data type to a value heuristically. - */ - public Datatype guessDataType(AstValue value) throws DataTypeSyntaxError { - return value.accept(guessDataType); - } - - /** - * Gives a data type to a value heuristically. - */ - public Datatype guessDataType(String value) throws DataTypeSyntaxError { - try { - return guessDataType(new DataParser(new StringReader(value)).value()); - } catch (TokenMgrError e) { - throw new DataTypeSyntaxError(e); - } catch (ParseException e) { - throw new DataTypeSyntaxError(e); - } - } - - class ValueTranslator implements Binding.Visitor { - - AstValue value; - - public ValueTranslator(AstValue value) { - this.value = value; - } - - private ValueTranslationRuntimeException typeError(Binding expectedType, AstValue actualValue) { - throw new ValueTranslationRuntimeException("Expected " + expectedType.type().toSingleLineString() + - " but got " + actualValue.getClass().getSimpleName() + "."); - } - - @Override - public Object visit(ArrayBinding b) { - if(value instanceof AstArray) { - AstArray array = (AstArray)value; - Object[] components = new Object[array.elements.size()]; - Binding componentBinding = b.getComponentBinding(); - int i=0; - for(AstValue component : array.elements) { - value = component; - components[i++] = componentBinding.accept(this); - } - return b.createUnchecked(components); - } - throw typeError(b, value); - } - - @Override - public Object visit(BooleanBinding b) { - if(value instanceof AstBoolean) { - return b.createUnchecked(((AstBoolean)value).value); - } - throw typeError(b, value); - } - - @Override - public Object visit(DoubleBinding b) { - if(value instanceof AstFloat) { - return b.createUnchecked(((AstFloat)value).value); - } - if(value instanceof AstInteger) { - return b.createUnchecked(((AstInteger)value).value); - } - throw typeError(b, value); - } - - @Override - public Object visit(FloatBinding b) { - if(value instanceof AstFloat) { - return b.createUnchecked(((AstFloat)value).value); - } - if(value instanceof AstInteger) { - return b.createUnchecked(((AstInteger)value).value); - } - throw typeError(b, value); - } - - @Override - public Object visit(IntegerBinding b) { - if(value instanceof AstInteger) { - return b.createUnchecked(((AstInteger)value).value); - } - throw typeError(b, value); - } - - @Override - public Object visit(ByteBinding b) { - if(value instanceof AstInteger) { - return b.createUnchecked(((AstInteger)value).value); - } - throw typeError(b, value); - } - - @Override - public Object visit(LongBinding b) { - if(value instanceof AstInteger) { - return b.createUnchecked(((AstInteger)value).value); - } - throw typeError(b, value); - } - - @Override - public Object visit(OptionalBinding b) { - if(value == AstNull.NULL) - return b.createNoValueUnchecked(); - else - return b.createValueUnchecked(b.getComponentBinding().accept(this)); - } - - @Override - public Object visit(RecordBinding b) { - if(value instanceof AstRecord) { - AstRecord record = (AstRecord)value; - Object[] components = new Object[b.getComponentCount()]; - boolean[] assigned = new boolean[b.getComponentCount()]; - for(AstComponentAssignment assignment : record.components) { - value = assignment.value; - Integer index = b.type().getComponentIndex(assignment.component); - if(index == null) - throw new ValueTranslationRuntimeException("Invalid record component " + assignment.component + "."); - components[index] = b.getComponentBinding(index).accept(this); - assigned[index] = true; - } - for(int i=0;i guessDataType = new AstValueVisitor() { - - @Override - public Datatype visit(AstArray astArray) { - if(astArray.elements.isEmpty()) - throw new ValueTranslationRuntimeException("Cannot guess the data type of empty array."); - return astArray.elements.get(0).accept(this); - } - - @Override - public Datatype visit(AstBoolean astBoolean) { - return Datatypes.BOOLEAN; - } - - @Override - public Datatype visit(AstFloat astFloat) { - return Datatypes.DOUBLE; - } - - @Override - public Datatype visit(AstInteger astInteger) { - return Datatypes.INTEGER; - } - - @Override - public Datatype visit(AstMap astMap) { - if(astMap.components.isEmpty()) - throw new ValueTranslationRuntimeException("Cannot guess the data type of empty map."); - AstMapAssignment assignment = astMap.components.get(0); - return new MapType(assignment.key.accept(this), assignment.value.accept(this)); - } - - @Override - public Datatype visit(AstNull astNull) { - throw new ValueTranslationRuntimeException("Cannot guess the data type"); - } - - @Override - public Datatype visit(AstRecord astRecord) { - Component[] components = new Component[astRecord.components.size()]; - int i = 0; - for(AstComponentAssignment assignment : astRecord.components) { - components[i++] = new Component( - assignment.component, - assignment.value.accept(this) - ); - } - return new RecordType(false, components); - } - - @Override - public Datatype visit(AstReference astReference) { - MutableVariant v = get(astReference.name); - if(v == null) - throw new ValueTranslationRuntimeException("Undefined reference to " + astReference.name + "."); - return v.type(); - } - - @Override - public Datatype visit(AstString astString) { - return Datatypes.STRING; - } - - @Override - public Datatype visit(AstTaggedValue astTaggedValue) { - // Guessed datatype would be a union with just one component. Not very useful. - throw new ValueTranslationRuntimeException("Cannot guess the data type of tagged value"); - } - - @Override - public Datatype visit(AstTuple astTuple) { - Component[] components = new Component[astTuple.elements.size()]; - int i = 0; - for(AstValue value : astTuple.elements) { - components[i] = new Component( - Integer.toString(i), - value.accept(this) - ); - ++i; - } - return new RecordType(false, components); - } - - @Override - public Datatype visit(AstVariant astVariant) { - return Datatypes.VARIANT; - } - }; - - -} +/******************************************************************************* + * Copyright (c) 2010 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.databoard.parser.repository; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Collection; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.simantics.databoard.Bindings; +import org.simantics.databoard.Datatypes; +import org.simantics.databoard.binding.ArrayBinding; +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.binding.BooleanBinding; +import org.simantics.databoard.binding.ByteBinding; +import org.simantics.databoard.binding.DoubleBinding; +import org.simantics.databoard.binding.FloatBinding; +import org.simantics.databoard.binding.IntegerBinding; +import org.simantics.databoard.binding.LongBinding; +import org.simantics.databoard.binding.MapBinding; +import org.simantics.databoard.binding.OptionalBinding; +import org.simantics.databoard.binding.RecordBinding; +import org.simantics.databoard.binding.StringBinding; +import org.simantics.databoard.binding.UnionBinding; +import org.simantics.databoard.binding.VariantBinding; +import org.simantics.databoard.binding.error.BindingConstructionException; +import org.simantics.databoard.binding.error.BindingException; +import org.simantics.databoard.binding.error.RuntimeBindingException; +import org.simantics.databoard.binding.factory.BindingScheme; +import org.simantics.databoard.binding.mutable.MutableVariant; +import org.simantics.databoard.file.RuntimeIOException; +import org.simantics.databoard.parser.DataParser; +import org.simantics.databoard.parser.DataValuePrinter; +import org.simantics.databoard.parser.ParseException; +import org.simantics.databoard.parser.PrintFormat; +import org.simantics.databoard.parser.TokenMgrError; +import org.simantics.databoard.parser.ast.value.AstArray; +import org.simantics.databoard.parser.ast.value.AstBoolean; +import org.simantics.databoard.parser.ast.value.AstComponentAssignment; +import org.simantics.databoard.parser.ast.value.AstFloat; +import org.simantics.databoard.parser.ast.value.AstInteger; +import org.simantics.databoard.parser.ast.value.AstMap; +import org.simantics.databoard.parser.ast.value.AstMapAssignment; +import org.simantics.databoard.parser.ast.value.AstNull; +import org.simantics.databoard.parser.ast.value.AstRecord; +import org.simantics.databoard.parser.ast.value.AstReference; +import org.simantics.databoard.parser.ast.value.AstString; +import org.simantics.databoard.parser.ast.value.AstTaggedValue; +import org.simantics.databoard.parser.ast.value.AstTuple; +import org.simantics.databoard.parser.ast.value.AstValue; +import org.simantics.databoard.parser.ast.value.AstValueDefinition; +import org.simantics.databoard.parser.ast.value.AstVariant; +import org.simantics.databoard.parser.ast.value.visitor.AstValueVisitor; +import org.simantics.databoard.parser.unparsing.DataTypePrinter; +import org.simantics.databoard.type.Component; +import org.simantics.databoard.type.Datatype; +import org.simantics.databoard.type.MapType; +import org.simantics.databoard.type.RecordType; +import org.simantics.databoard.type.UnionType; + +/** + * Data value repository is a collection of name data values. + * Each value is associated with type. + * + *

+ * It can also translate data lines and value texts to objects and + * print values as + * + * + * + * @author Hannu Niemistö + */ +public class DataValueRepository { + + // Type respository to convert + DataTypeRepository typeRepository = Datatypes.datatypeRepository; + + // Scheme to convert values + BindingScheme bindingScheme = Bindings.mutableBindingFactory; + + /** Stored values */ + Map values = new HashMap(); + Map nameMap = new IdentityHashMap(); + + public MutableVariant get(String name) { + return values.get(name); + } + + public String getName(Object value) { + return nameMap.get(value); + } + + public void put(String name, Binding binding, Object value) { + put(name, new MutableVariant(binding, value)); + } + + public void put(String name, MutableVariant value) { + values.put(name, value); + nameMap.put(value.getValue(), name); + } + + public MutableVariant remove(String name) { + MutableVariant value = values.remove(name); + if (value==null) return null; + nameMap.remove(value.getValue()); + return value; + } + + public void clear() { + values.clear(); + nameMap.clear(); + } + + /** + * Get a view of the value names in this repository + * + * @return names + */ + public Set getValueNames() { + return values.keySet(); + } + + /** + * Translates a data value from an abstract syntax tree to an object by the binding. + * + * @param value + * @param binding + * @return value + * @throws DataTypeSyntaxError + */ + public Object translate(AstValue value, Binding binding) throws DataTypeSyntaxError { + try { + if(value instanceof AstReference) { + String name = ((AstReference)value).name; + MutableVariant v = get(name); + if(v == null) { + if(binding instanceof UnionBinding) { + UnionBinding b = (UnionBinding)binding; + UnionType type = b.type(); + Integer index = type.getComponentIndex(name); + if(index != null) + try { + return b.create(index, + b.getComponentBinding(index).createDefault()); + } catch(BindingException e) { + throw new DataTypeSyntaxError(e); + } + } + throw new DataTypeSyntaxError("Undefined reference to " + name + "."); + } + return Bindings.adaptUnchecked(v.getValue(), v.getBinding(), binding); + } + return binding.accept(new ValueTranslator(value)); + } catch(ValueTranslationRuntimeException e) { + throw new DataTypeSyntaxError(e); + } + } + + /** + * Translates a data value from a string to an object by the binding. + * @param value + * @param binding + * @return value + * @throws DataTypeSyntaxError + */ + public Object translate(String value, Binding binding) throws DataTypeSyntaxError { + try { + return translate(new DataParser(new StringReader(value)).value(), binding); + } catch (TokenMgrError e) { + throw new DataTypeSyntaxError(e); + } catch (ParseException e) { + throw new DataTypeSyntaxError(e); + } + } + + /** + * Adds a value definition to the repository + * @param def + * @throws DataTypeSyntaxError + */ + public void addValueDefinition(AstValueDefinition def) throws DataTypeSyntaxError { + Datatype type = typeRepository.translate(def.type); + Binding binding = Bindings.getMutableBinding(type); + MutableVariant variant = new MutableVariant(binding, translate(def.value, binding)); + values.put(def.name, variant); + nameMap.put(variant.getValue(), def.name); + } + + /** + * Adds a value definition to the repository + * @param def + * @return name + * @throws DataTypeSyntaxError + */ + public String addValueDefinition(String def) throws DataTypeSyntaxError { + try { + StringReader reader = new StringReader(def); + DataParser parser = new DataParser( reader ); + AstValueDefinition valueAstDef = parser.valueDefinition(); + addValueDefinition( valueAstDef ); + return valueAstDef.name; + } catch (TokenMgrError e) { + throw new DataTypeSyntaxError(e); + } catch (ParseException e) { + throw new DataTypeSyntaxError(e); + } + } + + /** + * Adds multiple value definitions to the repository + * + * @param defs + * @throws DataTypeSyntaxError + */ + public void addValueDefinitions(Collection defs) throws DataTypeSyntaxError { + // TODO recursive definitions + for(AstValueDefinition def : defs) + addValueDefinition(def); + } + + /** + * Adds multiple value definitions to the repository + * @param def + * @throws DataTypeSyntaxError + */ + public void addValueDefinitions(String def) throws DataTypeSyntaxError { + try { + addValueDefinitions(new DataParser(new StringReader(def)).valueDefinitions()); + } catch (TokenMgrError e) { + throw new DataTypeSyntaxError(e); + } catch (ParseException e) { + throw new DataTypeSyntaxError(e); + } + } + + public DataTypeRepository getTypeRepository() { + return typeRepository; + } + + public void setTypeRepository(DataTypeRepository typeRepository) { + this.typeRepository = typeRepository; + } + + public BindingScheme getBindingScheme() { + return bindingScheme; + } + + public void setBindingScheme(BindingScheme bindingScheme) { + this.bindingScheme = bindingScheme; + } + + /** + * Print the content part of a data value. This excludes the name and type of the value. + * + * @param valueName + * @return value or null if value doesn't exist + * @throws BindingException + * @throws IOException + */ + public String printValue(String valueName) throws IOException, BindingException { + MutableVariant value = get(valueName); + if (value==null) return null; + StringBuilder sb = new StringBuilder(); + DataValuePrinter vp = new DataValuePrinter(sb, this); + vp.print(value); + return sb.toString(); + } + + /** + * Print the whole value repository + * + * @param sb + * @throws IOException + * @throws BindingException + */ + public void print(StringBuilder sb) + throws IOException, BindingException + { + DataValuePrinter vp = new DataValuePrinter(sb, this); + vp.setFormat( PrintFormat.SINGLE_LINE ); + DataTypePrinter tp = new DataTypePrinter( sb ); + tp.setLinefeed( false ); + + for (Entry e : values.entrySet()) { + String name = e.getKey(); + MutableVariant value = e.getValue(); + Datatype type = value.type(); + sb.append( name+" : " ); + tp.print(type); + sb.append( " = " ); + vp.print(value); + sb.append("\n"); + } + } + + /** + * Print the whole data value repository as a single multiline string + * + * @throws RuntimeBindingException + * @throws {@link RuntimeIOException} + */ + @Override + public String toString() { + try { + StringBuilder sb = new StringBuilder(); + print(sb); + return sb.toString(); + } catch (BindingException e) { + throw new RuntimeBindingException(e); + } catch (IOException e) { + throw new RuntimeIOException(e); + } + } + + /** + * Gives a data type to a value heuristically. + */ + public Datatype guessDataType(AstValue value) throws DataTypeSyntaxError { + return value.accept(guessDataType); + } + + /** + * Gives a data type to a value heuristically. + */ + public Datatype guessDataType(String value) throws DataTypeSyntaxError { + try { + return guessDataType(new DataParser(new StringReader(value)).value()); + } catch (TokenMgrError e) { + throw new DataTypeSyntaxError(e); + } catch (ParseException e) { + throw new DataTypeSyntaxError(e); + } + } + + class ValueTranslator implements Binding.Visitor { + + AstValue value; + + public ValueTranslator(AstValue value) { + this.value = value; + } + + private ValueTranslationRuntimeException typeError(Binding expectedType, AstValue actualValue) { + throw new ValueTranslationRuntimeException("Expected " + expectedType.type().toSingleLineString() + + " but got " + actualValue.getClass().getSimpleName() + "."); + } + + @Override + public Object visit(ArrayBinding b) { + if(value instanceof AstArray) { + AstArray array = (AstArray)value; + Object[] components = new Object[array.elements.size()]; + Binding componentBinding = b.getComponentBinding(); + int i=0; + for(AstValue component : array.elements) { + value = component; + components[i++] = componentBinding.accept(this); + } + return b.createUnchecked(components); + } + throw typeError(b, value); + } + + @Override + public Object visit(BooleanBinding b) { + if(value instanceof AstBoolean) { + return b.createUnchecked(((AstBoolean)value).value); + } + throw typeError(b, value); + } + + @Override + public Object visit(DoubleBinding b) { + if(value instanceof AstFloat) { + return b.createUnchecked(((AstFloat)value).value); + } + if(value instanceof AstInteger) { + return b.createUnchecked(((AstInteger)value).value); + } + throw typeError(b, value); + } + + @Override + public Object visit(FloatBinding b) { + if(value instanceof AstFloat) { + return b.createUnchecked(((AstFloat)value).value); + } + if(value instanceof AstInteger) { + return b.createUnchecked(((AstInteger)value).value); + } + throw typeError(b, value); + } + + @Override + public Object visit(IntegerBinding b) { + if(value instanceof AstInteger) { + return b.createUnchecked(((AstInteger)value).value); + } + throw typeError(b, value); + } + + @Override + public Object visit(ByteBinding b) { + if(value instanceof AstInteger) { + return b.createUnchecked(((AstInteger)value).value); + } + throw typeError(b, value); + } + + @Override + public Object visit(LongBinding b) { + if(value instanceof AstInteger) { + return b.createUnchecked(((AstInteger)value).value); + } + throw typeError(b, value); + } + + @Override + public Object visit(OptionalBinding b) { + if(value == AstNull.NULL) + return b.createNoValueUnchecked(); + else + return b.createValueUnchecked(b.getComponentBinding().accept(this)); + } + + @Override + public Object visit(RecordBinding b) { + if(value instanceof AstRecord) { + AstRecord record = (AstRecord)value; + Object[] components = new Object[b.getComponentCount()]; + boolean[] assigned = new boolean[b.getComponentCount()]; + for(AstComponentAssignment assignment : record.components) { + value = assignment.value; + Integer index = b.type().getComponentIndex(assignment.component); + if(index == null) + throw new ValueTranslationRuntimeException("Invalid record component " + assignment.component + "."); + components[index] = b.getComponentBinding(index).accept(this); + assigned[index] = true; + } + for(int i=0;i guessDataType = new AstValueVisitor() { + + @Override + public Datatype visit(AstArray astArray) { + if(astArray.elements.isEmpty()) + throw new ValueTranslationRuntimeException("Cannot guess the data type of empty array."); + return astArray.elements.get(0).accept(this); + } + + @Override + public Datatype visit(AstBoolean astBoolean) { + return Datatypes.BOOLEAN; + } + + @Override + public Datatype visit(AstFloat astFloat) { + return Datatypes.DOUBLE; + } + + @Override + public Datatype visit(AstInteger astInteger) { + return Datatypes.INTEGER; + } + + @Override + public Datatype visit(AstMap astMap) { + if(astMap.components.isEmpty()) + throw new ValueTranslationRuntimeException("Cannot guess the data type of empty map."); + AstMapAssignment assignment = astMap.components.get(0); + return new MapType(assignment.key.accept(this), assignment.value.accept(this)); + } + + @Override + public Datatype visit(AstNull astNull) { + throw new ValueTranslationRuntimeException("Cannot guess the data type"); + } + + @Override + public Datatype visit(AstRecord astRecord) { + Component[] components = new Component[astRecord.components.size()]; + int i = 0; + for(AstComponentAssignment assignment : astRecord.components) { + components[i++] = new Component( + assignment.component, + assignment.value.accept(this) + ); + } + return new RecordType(false, components); + } + + @Override + public Datatype visit(AstReference astReference) { + MutableVariant v = get(astReference.name); + if(v == null) + throw new ValueTranslationRuntimeException("Undefined reference to " + astReference.name + "."); + return v.type(); + } + + @Override + public Datatype visit(AstString astString) { + return Datatypes.STRING; + } + + @Override + public Datatype visit(AstTaggedValue astTaggedValue) { + // Guessed datatype would be a union with just one component. Not very useful. + throw new ValueTranslationRuntimeException("Cannot guess the data type of tagged value"); + } + + @Override + public Datatype visit(AstTuple astTuple) { + Component[] components = new Component[astTuple.elements.size()]; + int i = 0; + for(AstValue value : astTuple.elements) { + components[i] = new Component( + Integer.toString(i), + value.accept(this) + ); + ++i; + } + return new RecordType(false, components); + } + + @Override + public Datatype visit(AstVariant astVariant) { + return Datatypes.VARIANT; + } + }; + + +}