]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.databoard/src/org/simantics/databoard/parser/repository/DataTypeRepository.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / parser / repository / DataTypeRepository.java
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/parser/repository/DataTypeRepository.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/parser/repository/DataTypeRepository.java
new file mode 100644 (file)
index 0000000..e9d3f81
--- /dev/null
@@ -0,0 +1,505 @@
+/*******************************************************************************\r
+ *  Copyright (c) 2010 Association for Decentralized Information Management in\r
+ *  Industry THTH ry.\r
+ *  All rights reserved. This program and the accompanying materials\r
+ *  are made available under the terms of the Eclipse Public License v1.0\r
+ *  which accompanies this distribution, and is available at\r
+ *  http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ *  Contributors:\r
+ *      VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.parser.repository;
+
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.StringReader;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
+import java.util.Set;\r
+import java.util.TreeMap;\r
+\r
+import org.simantics.databoard.Datatypes;\r
+import org.simantics.databoard.parser.DataParser;\r
+import org.simantics.databoard.parser.ParseException;\r
+import org.simantics.databoard.parser.ast.type.AstArrayType;\r
+import org.simantics.databoard.parser.ast.type.AstAttribute;\r
+import org.simantics.databoard.parser.ast.type.AstComponent;\r
+import org.simantics.databoard.parser.ast.type.AstRecordType;\r
+import org.simantics.databoard.parser.ast.type.AstTupleType;\r
+import org.simantics.databoard.parser.ast.type.AstType;\r
+import org.simantics.databoard.parser.ast.type.AstTypeDefinition;\r
+import org.simantics.databoard.parser.ast.type.AstTypeReference;\r
+import org.simantics.databoard.parser.ast.type.AstUnionType;\r
+import org.simantics.databoard.parser.unparsing.DataTypePrinter;\r
+import org.simantics.databoard.type.ArrayType;\r
+import org.simantics.databoard.type.Component;\r
+import org.simantics.databoard.type.DataTypeDefinition;\r
+import org.simantics.databoard.type.Datatype;\r
+import org.simantics.databoard.type.DoubleType;\r
+import org.simantics.databoard.type.FloatType;\r
+import org.simantics.databoard.type.IntegerType;\r
+import org.simantics.databoard.type.LongType;\r
+import org.simantics.databoard.type.MapType;\r
+import org.simantics.databoard.type.OptionalType;\r
+import org.simantics.databoard.type.RecordType;\r
+import org.simantics.databoard.type.StringType;\r
+import org.simantics.databoard.type.UnionType;\r
+import org.simantics.databoard.util.Limit;\r
+import org.simantics.databoard.util.Range;\r
+
+/**
+ * Type repository maintains a mapping from strings to
+ * data types. It can also convert abstract syntax trees
+ * to data types.
+ * 
+ * @author Hannu Niemistö
+ */
+public class DataTypeRepository {
+
+       Map<String, Datatype> dataTypes =  new TreeMap<String, Datatype>();
+       Map<String, Datatype> dataTypesConstruction =  new HashMap<String, Datatype>();
+       Map<String, AstType> untranslatedTypes = new TreeMap<String, AstType>();
+       Map<Datatype, String> typeNames = new HashMap<Datatype, String>();
+       
+       /**
+        * Adds a type to the repository.
+        * 
+        * @param name Name of the type
+        * @param type Type to be added
+        */
+       public void add(String name, Datatype type) {\r
+               //System.out.println("add(" + name + ", " + type.toSingleLineString() + ")");
+               //Datatype oldType = dataTypes.get(name);
+               //String oldName = typeNames.get(type);
+               /*if (oldType!=null && !oldType.equals(type)) throw new RuntimeException("name = "+type+" is already mapped in the repository to "+oldType);
+               if (oldName!=null && !oldName.equals(name)) throw new RuntimeException("name = "+type+" is already mapped in the repository to "+oldName);
+               */dataTypes.put(name, type);
+               typeNames.put(type, name);
+       }
+       
+       void addTemp(String name, Datatype type) {
+               Datatype oldType = dataTypesConstruction.get(name);
+               if (oldType!=null && oldType!=type) throw new RuntimeException("name = "+type+" is already mapped in the repository to "+oldType);
+               dataTypesConstruction.put(name, type);
+       }       
+       
+       void finishType(String name) {
+               Datatype type = dataTypesConstruction.remove(name);
+               if (type==null) throw new RuntimeException("X");
+               dataTypes.put(name, type);
+               typeNames.put(type, name);
+       }
+
+       
+       /**
+        * Gets a data type in the repository.
+        * 
+        * @param name
+        * @return the data type
+        */
+       public Datatype get(String name) {
+               Datatype res1 = dataTypesConstruction.get(name);
+               if (res1!=null) return res1;
+               Datatype res2 = dataTypes.get(name); 
+               return res2;
+       }
+       
+       public String get(Datatype type) {
+               return typeNames.get(type);
+       }
+       
+       public boolean contains(String name) {
+               return dataTypes.containsKey(name);
+       }
+       
+       public boolean contains(Datatype type) {
+               return typeNames.containsKey(type);
+       }
+       
+       
+       /** 
+        * @return a view of all data types defined in this repository.
+        */
+       public Set<String> getTypeNames() {
+               return dataTypes.keySet();
+       }
+       
+       /**
+        * Add a type definitions to the repository.
+        * 
+        * @param defs type definitions
+        */
+       public void addDefinitions(DataTypeDefinition...defs) {
+               for (DataTypeDefinition def : defs) {
+                       add(def.getName(), def.getDataType());
+               }
+       }
+
+       /**
+        * Add a type definition to the repository.
+        * 
+        * @param def type definition
+        */
+       public void addDefinition(DataTypeDefinition def) {
+               add(def.getName(), def.getDataType());
+       }
+       
+       
+       /**
+        * Adds a type to the repository.
+        * 
+        * @param name Name of the type
+        * @param ast Abstract syntax tree of the type to be added
+        * @return Translated data type
+        * @throws DataTypeSyntaxError 
+        */
+       public Datatype add(String name, AstType ast) throws DataTypeSyntaxError {
+               if (name!=null) {
+                       Datatype t = get(name);
+                       if (t!=null) return t;
+               }
+               
+               if(ast instanceof AstTypeReference) {
+                       AstTypeReference named = (AstTypeReference)ast;
+                       Datatype type = null;
+                       if (dataTypesConstruction.containsKey(named.name))
+                               return dataTypesConstruction.get(named.name);
+                       if (dataTypes.containsKey(named.name))
+                               return dataTypes.get(named.name);
+                       
+                       if(untranslatedTypes.containsKey(named.name))
+                               type = add(named.name, untranslatedTypes.remove(named.name)); //?
+                       else 
+                               type = translateBuiltin(named);
+                       if(name != null)
+                               add(name, type);
+                       return type;
+               }
+               else if(ast instanceof AstArrayType) {
+                       ArrayType type = new ArrayType();
+                       if(name != null) addTemp(name, type);
+                       translate((AstArrayType)ast, type);
+                       if(name != null) finishType(name);
+                       return type;
+               } 
+               else if(ast instanceof AstRecordType) {
+                       RecordType type = new RecordType();
+                       if(name != null) addTemp(name, type);
+                       translate((AstRecordType)ast, type);
+                       if(name != null) finishType(name);                      
+                       return type;
+               } 
+               else if(ast instanceof AstTupleType) {
+                       RecordType type = new RecordType();
+                       if(name != null) addTemp(name, type);
+                       translate((AstTupleType)ast, type);
+                       if(name != null) finishType(name);                      
+                       return type;
+               }
+               else if(ast instanceof AstUnionType) {
+                       UnionType type = new UnionType();
+                       if(name != null) addTemp(name, type);
+                       translate((AstUnionType)ast, type);
+                       if(name != null) finishType(name);                      
+                       return type;
+               }
+               else
+                       throw new AssertionError("Not all syntax tree nodes covered");
+       }
+       
+       private Datatype translateBuiltin(AstTypeReference named) 
+                       throws DataTypeSyntaxError {
+               try {
+                       if(named.name.equals("Boolean")) {
+                               if(!named.parameters.isEmpty())
+                                       throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
+                               if(!named.attributes.isEmpty())
+                                       throw new DataTypeSyntaxError(named.name + " does not have attributes.");
+                               return Datatypes.BOOLEAN;
+                       }
+                       else if(named.name.equals("Byte")) {
+                               if(!named.parameters.isEmpty())
+                                       throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
+                               if(!named.attributes.isEmpty())
+                                       throw new DataTypeSyntaxError(named.name + " does not have attributes.");
+                               return Datatypes.BYTE;
+                       }
+                       else if(named.name.equals("Integer")) {
+                               if(!named.parameters.isEmpty())
+                                       throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
+                               if(named.attributes.isEmpty())
+                                       return Datatypes.INTEGER;
+                               else {
+                                       IntegerType type = new IntegerType();
+                                       for(AstAttribute attribute : named.attributes) {
+                                               String key = attribute.key;
+                                               if(key.equals("range"))
+                                                       type.setRange( attribute.value );
+                                               else if(key.equals("unit"))
+                                                       type.setUnit( attribute.value );
+                                               else
+                                                       throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
+                                       }
+                                       return type;
+                               }
+                       }
+                       else if(named.name.equals("Long")) {
+                               if(!named.parameters.isEmpty())
+                                       throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
+                               if(named.attributes.isEmpty())
+                                       return Datatypes.LONG;
+                               else {
+                                       LongType type = new LongType();
+                                       for(AstAttribute attribute : named.attributes) {
+                                               String key = attribute.key;
+                                               if(key.equals("range"))
+                                                       type.setRange( attribute.value );
+                                               else if(key.equals("unit"))
+                                                       type.setUnit( attribute.value );
+                                               else
+                                                       throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
+                                       }
+                                       return type;
+                               }
+                       }
+                       else if(named.name.equals("Float")) {
+                               if(!named.parameters.isEmpty())
+                                       throw new DataTypeSyntaxError(named.name + " does not take type parameters.");                  
+                               if(named.attributes.isEmpty())
+                                       return Datatypes.FLOAT;
+                               else {
+                                       FloatType type = new FloatType();
+                                       for(AstAttribute attribute : named.attributes) {
+                                               String key = attribute.key;
+                                               if(key.equals("range"))
+                                                       type.setRange( attribute.value );
+                                               else if(key.equals("unit"))
+                                                       type.setUnit( attribute.value );
+                                               else
+                                                       throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
+                                       }
+                                       return type;
+                               }
+                       }
+                       else if(named.name.equals("Double")) {
+                               if(!named.parameters.isEmpty())
+                                       throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
+                               if(named.attributes.isEmpty())
+                                       return Datatypes.DOUBLE;
+                               else {
+                                       DoubleType type = new DoubleType();
+                                       for(AstAttribute attribute : named.attributes) {
+                                               String key = attribute.key;
+                                               if(key.equals("range"))
+                                                       type.setRange( attribute.value );                                       
+                                               else if(key.equals("unit"))
+                                                       type.setUnit( attribute.value );
+                                               else
+                                                       throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
+                                       }
+                                       return type;
+                               }
+                       }
+                       else if(named.name.equals("String")) {
+                               if(!named.parameters.isEmpty())
+                                       throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
+                               if(named.attributes.isEmpty())
+                                       return Datatypes.STRING;
+                               else {
+                                       StringType type = new StringType();
+                                       for(AstAttribute attribute : named.attributes) {
+                                               String key = attribute.key;
+                                               if(key.equals("mimeType"))
+                                                       type.setMimeType( attribute.value );
+                                               else if(key.equals("pattern")) 
+                                                       type.setPattern( attribute.value );
+                                               else if(key.equals("length"))
+                                                       type.setLength( attribute.value );                                      
+                                               else
+                                                       throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
+                                       }
+                                       return type;
+                               }
+                       }
+                       else if(named.name.equals("Optional")) {
+                               if(named.parameters.size() != 1)
+                                       throw new DataTypeSyntaxError(
+                                                       "Optional takes one type parameter not " + named.parameters.size() + ".");
+                               if(!named.attributes.isEmpty())
+                                       throw new DataTypeSyntaxError(named.name + " does not have attributes.");
+                               OptionalType type = new OptionalType();
+                               type.componentType = translate(named.parameters.get(0));
+                               return type;
+                       }
+                       else if(named.name.equals("Variant")) {
+                               if(!named.parameters.isEmpty())
+                                       throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
+                               return Datatypes.VARIANT;
+                       }
+                       else if(named.name.equals("Map")) {
+                               if(named.parameters.size() != 2)
+                                       throw new DataTypeSyntaxError(
+                                                       "Map takes two type parameters not " + named.parameters.size() + ".");
+                               return new MapType(
+                                               translate(named.parameters.get(0)), 
+                                               translate(named.parameters.get(1))
+                                       );
+                       }
+                       else
+                               throw new DataTypeSyntaxError("Undefined type " + named.name);
+               } 
+               catch(IllegalArgumentException e) {
+                       throw new DataTypeSyntaxError(e);
+               }
+       }
+
+       private void translate(AstArrayType ast, ArrayType type) throws DataTypeSyntaxError {
+               type.componentType = translate(ast.componentType);
+               if(ast.minLength == null) {
+                       if(ast.maxLength == null) {
+                               type.setLength( (String) null );
+                       } else {
+                               type.setLength( new Range(
+                                               Limit.nolimit(),
+                                               Limit.inclusive(ast.maxLength)
+                                               ));
+                       }
+               } else {
+                       if(ast.maxLength == null) {
+                               type.setLength( new Range(
+                                               Limit.inclusive(ast.minLength),
+                                               Limit.nolimit()
+                                               ));
+                       } else {
+                               type.setLength( new Range(
+                                               Limit.inclusive(ast.minLength),
+                                               Limit.inclusive(ast.maxLength)
+                                               ));
+                       }
+               }
+       }
+       
+       private void translate(AstRecordType ast, RecordType type) throws DataTypeSyntaxError {
+               Component[] components = new Component[ast.components.size()];
+               for(int i=0;i<ast.components.size();++i) {
+                       AstComponent astComponent = ast.components.get(i);
+                       components[i] = new Component(
+                                       astComponent.name,
+                                       translate(astComponent.type)
+                                       );                      
+               } \r
+               type.setReferable( ast.referable );
+               type.setComponents( components );
+       }
+       
+       private void translate(AstTupleType ast, RecordType type) throws DataTypeSyntaxError {
+               Component[] components = new Component[ast.components.size()];
+               components = new Component[ast.components.size()];
+               for(int i=0;i<ast.components.size();++i) {
+                       components[i] = new Component(
+                                       Integer.toString(i),
+                                       translate(ast.components.get(i))
+                                       );
+               }
+               type.setComponents( components );
+       }
+       
+       private void translate(AstUnionType ast, UnionType type) throws DataTypeSyntaxError {
+               type.components = new Component[ast.components.size()];
+               for(int i=0;i<ast.components.size();++i) {
+                       AstComponent astComponent = ast.components.get(i);
+                       type.components[i] = new Component(
+                                       astComponent.name,
+                                       add(astComponent.name, astComponent.type) //translate(astComponent.type)
+                                       );
+               } 
+       }
+       
+       /**
+        * Adds all type definitions to the repository.
+        * @param definitions Abstract syntax trees of the definitions
+        * @throws DataTypeSyntaxError 
+        */
+       public void add(List<AstTypeDefinition> definitions) throws DataTypeSyntaxError {
+               for(AstTypeDefinition def : definitions)
+                       untranslatedTypes.put(def.name, def.type);
+               for(AstTypeDefinition def : definitions)
+                       if(untranslatedTypes.containsKey(def.name))
+                               add(def.name, untranslatedTypes.remove(def.name));
+       }
+       
+       /**
+        * Parses and adds type definitions to the repository.
+        * 
+        * @param definitions Definitions in textual format.
+        */
+       public void addDefinitions(String definitions) throws DataTypeSyntaxError {
+               try {
+                       List<AstTypeDefinition> typeDefinitions = 
+                               new DataParser(new StringReader(definitions)).typeDefinitions();
+                       add(typeDefinitions);
+               } catch (ParseException e) {
+                       throw new DataTypeSyntaxError(e);
+               }
+       }
+       
+       public void addDefinitions(InputStream definitions) throws IOException, DataTypeSyntaxError {
+               try {
+                       List<AstTypeDefinition> typeDefinitions = 
+                               new DataParser(definitions).typeDefinitions();
+                       add(typeDefinitions);
+               } catch (ParseException e) {
+                       throw new DataTypeSyntaxError(e);
+               }
+       }
+       
+       /**
+        * Translates an unnamed data type.
+        * @param ast Abstract syntax tree of the type to be translated
+        * @return Translated data type
+        * @throws DataTypeSyntaxError 
+        */
+       public Datatype translate(AstType ast) throws DataTypeSyntaxError {
+               return add(null, ast);
+       }
+       
+       /**
+        * Parses an unnamed data type.
+        * 
+        * @param typeString The textual representation of the type to be translated
+        * @return Translated data type
+        * @throws DataTypeSyntaxError 
+        */
+       public Datatype translate(String typeString) throws DataTypeSyntaxError {
+               try {
+                       AstType type =
+                               new DataParser(new StringReader(typeString)).type();
+                       return add(null, type);
+               } catch (ParseException e) {
+                       throw new DataTypeSyntaxError(e);
+               }
+       }
+       
+       @Override
+       public String toString() {
+               StringBuilder sb = new StringBuilder();
+               DataTypePrinter printer = new DataTypePrinter( sb );
+               printer.setLinefeed( true );
+               
+               for (Entry<String, Datatype> e : dataTypes.entrySet()) {
+                       String name = e.getKey();
+                       Datatype type = e.getValue();                   
+                       sb.append("type ");
+                       sb.append( name );
+                       sb.append(" = ");
+                       printer.print( type );
+                       sb.append("\n");
+               }
+               
+               return sb.toString();
+       }
+       
+}