/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: LibData.java
* Written by Jonathan Gainsley, Sun Microsystems.
*
* Copyright (c) 2009 Sun Microsystems and Static Free Software
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.simulation.sctiming;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.io.PrintStream;
import java.io.FileOutputStream;
/**
* LibertyObjects.java
* Jonathan Gainsley
* 24 Oct 2006
*
* Objects to store parsed data from LibertyParser
*/
public class LibData
{
public Group library;
private static final int MAX_LINE_LENGTH = 80; // when writing to disk
/**
* Create a new LibData object to hold Liberty format data.
*/
public LibData() {}
/**
* Write the data stored in this object to a Liberty format file.
* @param filename the file to write to
*/
public void write(String filename) {
try {
write(new PrintStream(new FileOutputStream(filename)));
} catch (java.io.FileNotFoundException e) {
System.out.println("LibData: Error writing to file "+filename+": "+e.getMessage());
}
}
/**
* Write the data stored in this object to a Liberty format file.
* @param out the output stream to write to
*/
public void write(PrintStream out) {
if (library == null) {
System.out.println("LibData: No Data to write");
return;
}
library.write(out, 0);
}
/**
* Get the library from the liberty file read.
* Note that there is only one library per file.
* @return the library data
*/
public Group getLibrary() {
return library;
}
/**
* Set the library for the liberty file.
* Note that there is only one library per file.
*/
public void setLibrary(Group group) {
this.library = group;
}
// ---------------------------------------------------------
// Liberty Object Definitions
// ---------------------------------------------------------
/**
* Head object
*/
public static class Head {
public String name;
int lineno;
String filename;
List<Value> valuesList;
public Head(String name, List attrList) {
this.name = name;
valuesList = new ArrayList<Value>();
for (Object obj : attrList) {
if (obj instanceof Value)
valuesList.add((Value)obj);
}
}
public List<Value> getValues() { return valuesList; }
}
/**
* Group object
*/
public static class Group {
private String type;
private List<String> names;
private Group owner;
Map<String,Attribute> attrList;
Map<String,Define> defineList;
List<Group> groupList; // multiple groups of the same type and no name may exist
public Group(String type, String name, Group owner) {
this.type = type;
this.names = new ArrayList<String>();
if (name != null)
this.names.add(name);
this.owner = owner;
this.attrList = new LinkedHashMap<String,Attribute>();
this.defineList = new LinkedHashMap<String,Define>();
this.groupList = new ArrayList<Group>();
if (owner != null)
owner.putGroup(this);
}
public Group(Head h, Group owner) {
this.type = h.name;
this.names = new ArrayList<String>();
this.owner = owner;
this.attrList = new LinkedHashMap<String,Attribute>();
this.defineList = new LinkedHashMap<String,Define>();
this.groupList = new ArrayList<Group>();
for (Value a : h.getValues()) {
names.add(a.value.toString());
}
if (owner != null)
owner.putGroup(this);
}
public String getType() { return type; }
public String getName() { if (names.size() > 0) return names.get(0); return null; }
public List<String> getNames() { return names; }
public Group getOwner() { return owner; }
public String getHName() {
String parentName = owner == null ? "" : owner.getHName()+".";
String thisname = type + (names.size() == 0 ? "" : "-"+names.get(0));
return parentName + thisname;
}
public void putAttribute(Attribute a) {
if (attrList.containsKey(a.name)) {
System.out.println("Duplicate Attribute name "+a.name+" in group "+getHName());
}
attrList.put(a.name, a);
}
public void putGroup(Group g) {
groupList.add(g);
}
public void putDefine(Define d) {
if (defineList.containsKey(d.name)) {
System.out.println("Duplicate Define name "+d.name+" in group "+getHName());
}
defineList.put(d.name, d);
}
public Attribute getAttribute(String name) {
return attrList.get(name);
}
public void putAttribute(String name, double value) {
Value val = new Value(ValueType.DOUBLE, new Double(value));
putAttribute(new Attribute(name, val));
}
public void putAttribute(String name, String value) {
Value val = new Value(ValueType.STRING, value);
putAttribute(new Attribute(name, val));
}
public void putAttribute(String name, int value) {
Value val = new Value(ValueType.INT, new Integer(value));
putAttribute(new Attribute(name, val));
}
public void putAttribute(String name, List<String> values) {
List<Value> vals = new ArrayList<Value>();
for (String s : values) vals.add(new Value(ValueType.STRING, s));
Head h = new Head(name, vals);
putAttribute(new Attribute(name, h));
}
public void putAttributeComplex(String name, String value) {
List<String> vals = new ArrayList<String>();
vals.add(value);
putAttribute(name, vals);
}
/**
* Get all groups in this group
* @return all groups in this group
*/
public List<Group> getGroups() {
return groupList;
}
/**
* Get the group of the given type and name,
* in this group. Name can be null.
* More than one group may exist; all matching
* the criteria are returned.
* @param type the group type: type(name) {}
* @param name the group name
* @return any group in this group matching the criteria
*/
public List<Group> getGroups(String type, String name) {
List<Group> groups = new ArrayList<Group>();
if (type == null) return groups;
for (Group g : groupList) {
if (!type.equals(g.type)) continue;
if (name == null && g.names.size() == 0) {
groups.add(g); continue;
}
if (name != null && g.names.contains(name)) {
groups.add(g);
}
}
return groups;
}
public Define getDefine(String name) {
return defineList.get(name);
}
public void removeGroup(Group group) {
for (Group g : groupList) {
if (g == group) {
groupList.remove(g);
return;
}
}
}
private void write(PrintStream out, int tabs) {
prtabs(out, tabs);
out.print(type+" (");
for (Iterator<String> it = names.iterator(); it.hasNext(); ) {
out.print(it.next());
if (it.hasNext()) out.print(", ");
}
out.println(") {");
tabs++;
for (Attribute attr : attrList.values()) {
attr.write(out, tabs);
}
for (Define define : defineList.values()) {
define.write(out, tabs);
}
for (Group group : groupList) {
group.write(out, tabs);
}
tabs--;
prtabs(out, tabs);
out.println("}");
}
}
/**
* Attribute Types
*/
public enum AttrType { SIMPLE, COMPLEX }
/**
* Attribute object
*/
public static class Attribute {
AttrType type;
String name;
List<Value> values;
public Attribute(String name, Value value) {
this.name = name;
this.type = AttrType.SIMPLE;
this.values = new ArrayList<Value>();
values.add(value);
}
public Attribute(String name, Head complexAttributeValues) {
this.name = name;
this.type = AttrType.COMPLEX;
this.values = complexAttributeValues.getValues();
}
public AttrType getType() { return type; }
public String getName() { return name; }
public List<Value> getValues() { return values; }
/** Get the integer value. Returns null if not an integer */
public Integer getInt() {
if (values.size() == 0) return null;
return values.get(0).getInt();
}
/** Get the double value. Returns null if not a double */
public Double getDouble() {
if (values.size() == 0) return null;
return values.get(0).getDouble();
}
/** Get the String value. Returns null if not a String */
public String getString() {
if (values.size() == 0) return null;
return values.get(0).getString();
}
/** Get the Boolean value. Returns null if not a Boolean */
public Boolean getBoolean() {
if (values.size() == 0) return null;
return values.get(0).getBoolean();
}
private void write(PrintStream out, int tabs) {
prtabs(out, tabs);
out.print(name);
int i = tabs*2 + name.length();
switch(type) {
case SIMPLE: out.print(" : "); i+=3; break;
case COMPLEX: out.print(" ("); i+=2; break;
}
int start = i;
for (Iterator<Value> it = values.iterator(); it.hasNext(); ) {
Value v = it.next();
String s = v.getValueAsString();
if ((i+s.length()) > MAX_LINE_LENGTH) {
out.println(" \\");
i=start;
prtabs(out, start/2);
}
out.print(s);
i += s.length();
if (it.hasNext()) { out.print(", "); i+=2; }
}
if (type == AttrType.COMPLEX) out.print(")");
out.println(" ;");
}
}
/**
* Value types
*/
public enum ValueType { STRING, DOUBLE, BOOLEAN, INT, EXPR, UNDEFINED }
/**
* Value objects
*/
public static class Value {
ValueType type;
Object value;
public Value(ValueType type, Object value) {
this.type = type;
this.value = value;
if (value instanceof String) {
String s = (String)value;
if (s.startsWith("\"") && s.endsWith("\"")) {
s = s.substring(1, s.length()-1); // strip quotes
this.value = s;
}
}
}
public ValueType getType() { return type; }
public Object getValue() { return value; }
public static ValueType getType(String s) {
if (s == null) return ValueType.UNDEFINED;
try {
return ValueType.valueOf(s.trim().toUpperCase());
} catch (IllegalArgumentException e) {
return ValueType.UNDEFINED;
}
}
/** Get the integer value. Returns null if not an integer */
public Integer getInt() {
if (value == null || type != ValueType.DOUBLE) return null;
return new Integer(((Double)value).intValue());
}
/** Get the double value. Returns null if not a double */
public Double getDouble() {
if (value == null || type != ValueType.DOUBLE) return null;
return (Double)value;
}
/** Get the String value. Returns null if not a String */
public String getString() {
if (value == null || type != ValueType.STRING) return null;
return (String)value;
}
/** Get the Boolean value. Returns null if not a Boolean */
public Boolean getBoolean() {
if (value == null || type != ValueType.BOOLEAN) return null;
return (Boolean)value;
}
private String getValueAsString() {
String s = value.toString().trim();
if (s.indexOf(' ') != -1 || s.indexOf('/') != -1 || s.indexOf('\\') != -1) {
if (!s.startsWith("\"") && !s.endsWith("\""))
return "\""+s+"\"";
}
return s;
}
}
/**
* Definition objects
*/
public static class Define {
String name;
String groupType;
ValueType valueType;
String comment;
Group owner;
Define(String name, Group owner, ValueType valueType) {
this.name = name;
this.owner = owner;
this.valueType = valueType;
if (owner != null)
owner.putDefine(this);
}
private void write(PrintStream out, int tabs) {
}
}
/**
* Error types
*/
public enum Error {
NO_ERROR,
INTERNAL_SYSTEM_ERROR,
INVALID_VALUE,
INVALID_NAME,
INVALID_OBJECTTYPE,
INVALID_ATTRTYPE,
UNUSABLE_OID,
OBJECT_ALREADY_EXISTS,
OBJECT_NOT_FOUND,
SYNTAX_ERROR,
TRACE_FILES_CANNOT_BE_OPENED,
PIINIT_NOT_CALLED,
SEMANTIC_ERROR,
REFERENCE_ERROR,
MAX_ERROR
}
/**
* Get error string for the given type
* @param error
* @return the error string
*/
public static String getMessage(Error error) {
switch(error) {
case NO_ERROR: return "";
case INTERNAL_SYSTEM_ERROR: return "Internal System Error";
case INVALID_VALUE: return "Invalid Value";
case INVALID_NAME: return "Invalid Name";
case INVALID_OBJECTTYPE: return "Invalid Object Type";
case INVALID_ATTRTYPE: return "Invalid Attribute Type";
case UNUSABLE_OID: return "Unusable Object Identifier?";
case OBJECT_ALREADY_EXISTS: return "Object Already Exists";
case OBJECT_NOT_FOUND: return "Object Not Found";
case SYNTAX_ERROR: return "Syntax Error";
case TRACE_FILES_CANNOT_BE_OPENED: return "Trace Files Cannot be Opened";
case PIINIT_NOT_CALLED: return "PI init() not called";
case SEMANTIC_ERROR: return "Semantic Error";
case REFERENCE_ERROR: return "Reference Error";
case MAX_ERROR: return "Maximum Error";
}
return "Unknown Error Number: "+error;
}
private static void prtabs(PrintStream out, int tabs) {
for (int i=0; i<tabs; i++) out.print(" ");
}
}