/******************************************************************************* * Copyright (c) CWI 2009 * 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: * Jurgen Vinju (jurgenv@cwi.nl) - initial API and implementation *******************************************************************************/ package org.rascalmpl.value.io; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.rascalmpl.value.IBool; import org.rascalmpl.value.IConstructor; import org.rascalmpl.value.IDateTime; import org.rascalmpl.value.IExternalValue; import org.rascalmpl.value.IInteger; import org.rascalmpl.value.IList; import org.rascalmpl.value.IMap; import org.rascalmpl.value.INode; import org.rascalmpl.value.IRational; import org.rascalmpl.value.IReal; import org.rascalmpl.value.ISet; import org.rascalmpl.value.ISourceLocation; import org.rascalmpl.value.IString; import org.rascalmpl.value.ITuple; import org.rascalmpl.value.IValue; import org.rascalmpl.value.type.TypeStore; import org.rascalmpl.value.visitors.IValueVisitor; /** * This class implements the ATerm readable syntax for {@link IValue}'s. * See also {@link ATermReader} */ public class ATermWriter implements IValueTextWriter { public void write(IValue value, java.io.Writer stream) throws IOException { value.accept(new Writer(stream)); } public void write(IValue value, java.io.Writer stream, TypeStore typeStore) throws IOException { write(value, stream); } private static class Writer implements IValueVisitor<IValue, IOException> { private java.io.Writer stream; public Writer(java.io.Writer stream) { this.stream = stream; } private void append(String string) throws IOException { stream.write(string); } private void append(char c) throws IOException { stream.write(c); } public IValue visitBoolean(IBool boolValue) throws IOException { append(boolValue.getStringRepresentation()); return boolValue; } public IValue visitConstructor(IConstructor o) throws IOException { return visitNode(o); } public IValue visitReal(IReal o) throws IOException { append(o.getStringRepresentation()); return o; } public IValue visitInteger(IInteger o) throws IOException { append(o.getStringRepresentation()); return o; } // TODO: There probably isn't a good ATerm repr of rationals, // what should we do here? public IValue visitRational(IRational o) throws IOException { append("rat"); append('('); append(o.numerator().getStringRepresentation()); append(','); append(o.denominator().getStringRepresentation()); append(')'); return o; } public IValue visitList(IList o) throws IOException { append('['); Iterator<IValue> listIterator = o.iterator(); if(listIterator.hasNext()){ append(listIterator.next().toString()); while(listIterator.hasNext()){ append(','); listIterator.next().accept(this); } } append(']'); return o; } public IValue visitMap(IMap o) throws IOException { append('['); Iterator<IValue> mapIterator = o.iterator(); if(mapIterator.hasNext()){ append('('); IValue key = mapIterator.next(); key.accept(this); append(','); o.get(key).accept(this); append(')'); while(mapIterator.hasNext()){ append(','); append('('); key = mapIterator.next(); append(','); o.get(key).accept(this); append(')'); } } append(']'); return o; } public IValue visitNode(INode o) throws IOException { String name = o.getName(); append(name); append('('); Iterator<IValue> it = o.iterator(); while (it.hasNext()) { it.next().accept(this); if (it.hasNext()) { append(','); } } append(')'); if (o.asAnnotatable().hasAnnotations()) { append("{["); int i = 0; Map<String, IValue> annotations = o.asAnnotatable().getAnnotations(); for (Entry<String, IValue> entry : annotations.entrySet()) { append("[" + entry.getKey() + ","); entry.getValue().accept(this); append("]"); if (++i < annotations.size()) { append(","); } } append("]}"); } return o; } public IValue visitRelation(ISet o) throws IOException { return visitSet(o); } public IValue visitSet(ISet o) throws IOException { append('['); Iterator<IValue> setIterator = o.iterator(); if(setIterator.hasNext()){ setIterator.next().accept(this); while(setIterator.hasNext()){ append(","); setIterator.next().accept(this); } } append(']'); return o; } public IValue visitSourceLocation(ISourceLocation o) throws IOException { append("loc("); append('\"'); append(o.getURI().toString()); append('\"'); append("," + o.getOffset()); append("," + o.getLength()); append("," + o.getBeginLine()); append("," + o.getBeginColumn()); append("," + o.getEndLine()); append("," + o.getEndColumn()); append(')'); return o; } public IValue visitString(IString o) throws IOException { // TODO optimize this implementation and finish all escapes append('\"'); append(o.getValue().replaceAll("\"", "\\\"").replaceAll("\n","\\\\n")); append('\"'); return o; } public IValue visitTuple(ITuple o) throws IOException { append('('); Iterator<IValue> it = o.iterator(); if (it.hasNext()) { it.next().accept(this); } while (it.hasNext()) { append(','); it.next().accept(this); } append(')'); return o; } public IValue visitExternal(IExternalValue externalValue) { // ignore external values return externalValue; } public IValue visitDateTime(IDateTime o) throws IOException { append("$"); if (o.isDate()) { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); append(df.format(new Date(o.getInstant()))); } else if (o.isTime()) { SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSSZZZ"); append("T"); append(df.format(new Date(o.getInstant()))); } else { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZ"); append(df.format(new Date(o.getInstant()))); } return o; } public IValue visitListRelation(IList o) throws IOException { visitList(o); return o; } } }