/******************************************************************************* * 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.unparsing; import gnu.trove.set.hash.THashSet; import java.util.ArrayList; import java.util.List; import org.simantics.databoard.parser.ast.type.AstArrayType; import org.simantics.databoard.parser.ast.type.AstComponent; import org.simantics.databoard.parser.ast.type.AstRecordType; import org.simantics.databoard.parser.ast.type.AstTupleType; import org.simantics.databoard.parser.ast.type.AstType; import org.simantics.databoard.parser.ast.type.AstTypeDefinition; import org.simantics.databoard.parser.ast.type.AstTypeReference; import org.simantics.databoard.parser.ast.type.AstUnionType; import org.simantics.databoard.parser.repository.DataTypeRepository; import org.simantics.databoard.type.ArrayType; import org.simantics.databoard.type.BooleanType; import org.simantics.databoard.type.ByteType; import org.simantics.databoard.type.Component; import org.simantics.databoard.type.Datatype; import org.simantics.databoard.type.Datatype.Visitor; import org.simantics.databoard.type.DoubleType; import org.simantics.databoard.type.FloatType; import org.simantics.databoard.type.IntegerType; import org.simantics.databoard.type.LongType; import org.simantics.databoard.type.MapType; import org.simantics.databoard.type.NumberType; import org.simantics.databoard.type.OptionalType; import org.simantics.databoard.type.RecordType; import org.simantics.databoard.type.StringType; import org.simantics.databoard.type.UnionType; import org.simantics.databoard.type.VariantType; /** * Converts data type to abstract syntax tree. * * @author Hannu Niemistö */ public class DataTypeToAst implements Visitor { List typeDefinitions = new ArrayList(); DataTypeRepository repo = new DataTypeRepository(); THashSet underConstruction = new THashSet(); int id = 0; public DataTypeToAst(DataTypeRepository repo) { this.repo = repo; } private String freshTypeName() { return "Temp" + (++id); } public AstType addDefinition(String name, Datatype type) { repo.add(name, type); AstType ast = type.accept(this); typeDefinitions.add(new AstTypeDefinition(name, type.accept(this))); return ast; } public AstType visit(Datatype type) { if(repo.contains(type)) return new AstTypeReference(repo.get(type)); if(underConstruction.contains(type)) { String name = repo.get(type); if (name==null) { name = freshTypeName(); repo.add(name, type); } underConstruction.remove(type); return new AstTypeReference(name); } else { underConstruction.add(type); AstType ast = type.accept(this); if(!underConstruction.remove(type)) { String name = repo.get(type); typeDefinitions.add(new AstTypeDefinition(name, ast)); return new AstTypeReference(name); } else return ast; } } @Override public AstType visit(ArrayType b) { return new AstArrayType(visit(b.componentType), b.getLength()==null ? null : b.getLength().getLower().smallestIncludedInteger(), b.getLength()==null ? null : b.getLength().getUpper().greatestIncludedInteger()); } @Override public AstType visit(BooleanType b) { return new AstTypeReference("Boolean"); } @Override public AstType visit(DoubleType b) { AstTypeReference ref = new AstTypeReference("Double"); // XXX if( b.metadata.containsKey( NumberType.KEY_RANGE ) ) ref.addAttribute("range", b.metadata.get( NumberType.KEY_RANGE ) ); if( b.metadata.containsKey( NumberType.KEY_UNIT ) ) ref.addAttribute("unit", b.metadata.get( NumberType.KEY_UNIT )); return ref; } @Override public AstType visit(FloatType b) { AstTypeReference ref = new AstTypeReference("Float"); // XXX if( b.metadata.containsKey( NumberType.KEY_RANGE ) ) ref.addAttribute("range", b.metadata.get( NumberType.KEY_RANGE ) ); if( b.metadata.containsKey( NumberType.KEY_UNIT ) ) ref.addAttribute("unit", b.metadata.get( NumberType.KEY_UNIT )); return ref; } @Override public AstType visit(IntegerType b) { AstTypeReference ref = new AstTypeReference("Integer"); // XXX if( b.metadata.containsKey( NumberType.KEY_RANGE ) ) ref.addAttribute("range", b.metadata.get( NumberType.KEY_RANGE ) ); if( b.metadata.containsKey( NumberType.KEY_UNIT ) ) ref.addAttribute("unit", b.metadata.get( NumberType.KEY_UNIT )); return ref; } @Override public AstType visit(ByteType b) { return new AstTypeReference("Byte"); } @Override public AstType visit(LongType b) { AstTypeReference ref = new AstTypeReference("Long"); // XXX if( b.metadata.containsKey( NumberType.KEY_RANGE ) ) ref.addAttribute("range", b.metadata.get( NumberType.KEY_RANGE ) ); if( b.metadata.containsKey( NumberType.KEY_UNIT ) ) ref.addAttribute("unit", b.metadata.get( NumberType.KEY_UNIT )); return ref; } @Override public AstType visit(OptionalType b) { return new AstTypeReference("Optional", visit(b.getComponentType())); } @Override public AstType visit(RecordType b) { if(b.isTupleType()) { AstTupleType tuple = new AstTupleType(new ArrayList(b.getComponentCount())); for(Component component : b.getComponents()) tuple.addComponent(visit(component.type)); return tuple; } else { AstRecordType record = new AstRecordType(b.isReferable(), new ArrayList(b.getComponentCount())); for(Component component : b.getComponents()) record.addComponent(component.name, visit(component.type)); return record; } } @Override public AstType visit(StringType b) { AstTypeReference ref = new AstTypeReference("String"); // XXX if( b.metadata.containsKey( StringType.KEY_MIMETYPE ) ) ref.addAttribute("mimeType", b.metadata.get( StringType.KEY_MIMETYPE )); if( b.metadata.containsKey( StringType.KEY_LENGTH ) ) ref.addAttribute("length", b.metadata.get( StringType.KEY_LENGTH )); if( b.metadata.containsKey( StringType.KEY_PATTERN )) ref.addAttribute("pattern", b.metadata.get( StringType.KEY_PATTERN )); return ref; } @Override public AstType visit(UnionType b) { AstUnionType union = new AstUnionType(new ArrayList(b.components.length)); for(Component component : b.components) union.addComponent(component.name, visit(component.type)); return union; } @Override public AstType visit(VariantType b) { AstTypeReference ref = new AstTypeReference("Variant"); return ref; } public List getTypeDefinitions() { return typeDefinitions; } @Override public AstType visit(MapType b) { AstTypeReference ref = new AstTypeReference("Map", visit(b.keyType), visit(b.valueType)); return ref; } }