/*
Protocol Definition Language
Copyright (C) 2003-2006 Marcus Andersson
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package net.sf.nmedit.jpdl2.utils;
import java.util.Iterator;
import net.sf.nmedit.jpdl2.dom.PDLBlock;
import net.sf.nmedit.jpdl2.dom.PDLCaseStatement;
import net.sf.nmedit.jpdl2.dom.PDLChoice;
import net.sf.nmedit.jpdl2.dom.PDLConditional;
import net.sf.nmedit.jpdl2.dom.PDLConstant;
import net.sf.nmedit.jpdl2.dom.PDLDocument;
import net.sf.nmedit.jpdl2.dom.PDLInstruction;
import net.sf.nmedit.jpdl2.dom.PDLItem;
import net.sf.nmedit.jpdl2.dom.PDLItemType;
import net.sf.nmedit.jpdl2.dom.PDLMultiplicity;
import net.sf.nmedit.jpdl2.dom.PDLOptional;
import net.sf.nmedit.jpdl2.dom.PDLPacketDecl;
import net.sf.nmedit.jpdl2.dom.PDLPacketRef;
import net.sf.nmedit.jpdl2.dom.PDLSwitchStatement;
import net.sf.nmedit.jpdl2.dom.PDLVariable;
/**
* TODO
*/
public class PDLWriter
{
private int indentIncrement = 4;
private String newline = "\r\n";
private StringBuilder s;
private String headerComment = "# generated by "+getClass().getName();
private boolean printHeaderComment = true;
public void setHeaderCommentEnabled(boolean enable)
{
this.printHeaderComment = enable;
}
public static String toString(PDLDocument doc)
{
StringBuilder s = new StringBuilder();
PDLWriter w = new PDLWriter(s);
w.append(doc);
return s.toString();
}
public PDLWriter(StringBuilder s)
{
this.s = s;
}
public void append(PDLDocument doc)
{
if (headerComment != null && printHeaderComment)
{
s.append(headerComment);
s.append(newline);
}
for (PDLPacketDecl packetdecl: doc)
{
append(packetdecl);
s.append(newline);
}
}
public void append(PDLOptional optional)
{
s.append('?');
appendBlock(optional, 0);
}
public void append(PDLMultiplicity multiplicity)
{
if (multiplicity.getConstant()>=0)
{
s.append(Integer.valueOf(multiplicity.getConstant()));
s.append('*');
}
else if (multiplicity.getVariable() != null)
{
s.append(multiplicity.getVariable());
s.append('*');
}
}
public void append(PDLConstant constant)
{
if (constant.getMultiplicity() != null)
append(constant.getMultiplicity());
s.append(Integer.valueOf(constant.getValue()));
s.append(':');
s.append(Integer.valueOf(constant.getSize()));
}
public void append(PDLVariable variable)
{
if (variable.getType() == PDLItemType.AnonymousVariable)
s.append("%");
if (variable.getMultiplicity() != null)
append(variable.getMultiplicity());
s.append(variable.getName());
s.append(':');
s.append(Integer.valueOf(variable.getSize()));
if (variable.getFunction() != null)
{
s.append('=');
s.append(variable.getFunction());
}
}
public void append(PDLPacketRef packetReference)
{
if (packetReference.getType() == PDLItemType.PacketRefList)
append(packetReference.getMultiplicity());
s.append(packetReference.getPacketName());
s.append('$');
if (packetReference.getType() == PDLItemType.InlinePacketRef)
s.append('$');
else
s.append(packetReference.getBinding());
}
public void append(PDLConditional conditionalBlock)
{
append(conditionalBlock, 0);
}
public void append(PDLConditional conditionalBlock, int indent)
{
s.append(conditionalBlock.getCondition());
s.append(' ');
appendBlock(conditionalBlock, indent+indentIncrement);
}
private void appendBlock(PDLBlock block, int indent)
{
if (block.getItemCount() == 1)
{
append(block.getItem(0));
s.append(newline);
}
else if (block.getItemCount() > 1)
{
if (!(block instanceof PDLPacketDecl))
s.append("{");
s.append(newline);
for (int i=0;i<block.getItemCount();i++)
{
s.append(' ');
append(' ', (i+1)%6==0 ? indent : 0);
PDLItem item = block.getItem(i);
append(item, indent);
}
s.append(newline);
if (!(block instanceof PDLPacketDecl))
s.append('}');
s.append(newline);
}
}
public void append(PDLItem item)
{
append(item, 0);
}
public void append(PDLItem item, int indent)
{
switch (item.getType())
{
case Conditional:
append(item.asConditional(), indent+indentIncrement);
break;
case Constant:
append(item.asConstant());
break;
case InlinePacketRef:
case PacketRef:
case PacketRefList:
append(item.asPacketRef());
break;
case Variable:
case VariableList:
case ImplicitVariable:
case AnonymousVariable:
append(item.asVariable());
break;
case Optional:
append(item.asOptional());
break;
case Choice:
append(item.asChoice());
break;
case SwitchStatement:
append(item.asSwitchStatement());
break;
case Fail:
s.append("fail()");
break;
case Block:
append(item.asBlock());
break;
case Label:
s.append("@"+item.asInstruction().getString());
break;
case MessageId:
s.append("messageId(\""+item.asInstruction().getString()+"\") ");
break;
case StringDef:
{
PDLInstruction ins = item.asInstruction();
s.append(ins.getString()+":=\""+ins.getString2()+"\"");
break;
}
default:
throw new InternalError("unsupported type: "+item.getType());
}
}
private void append(PDLBlock block)
{
if (block.getItemCount()==1)
{
append(block.getItem(0));
return;
}
s.append('{');
for (PDLItem item: block)
{
append(item);
s.append(' ');
}
s.append('}');
}
private void append(PDLSwitchStatement sw)
{
s.append("switch ("+sw.getFunction()+")\n{\n");
for (PDLCaseStatement cs: sw)
{
if (cs.isDefaultCase())
s.append("default:");
else
s.append("case "+cs.getValue()+":");
append(cs.getBlock());
}
s.append("}\n");
}
private void append(PDLChoice m)
{
s.append('(');
Iterator<PDLBlock> b = m.iterator();
if (b.hasNext())
{
append(b.next());
while (b.hasNext())
{
s.append('|');
append(b.next());
}
}
s.append(')');
}
public void append(PDLPacketDecl pdecl)
{
s.append(pdecl.getName());
if (pdecl.getPadding()>1)
{
s.append('%');
s.append(Integer.valueOf(pdecl.getPadding()));
}
s.append(" := \r\n");
appendBlock(pdecl, 0);
s.append("\r\n");
append(' ', indentIncrement);
s.append(";\r\n");
}
private void append(char c, int count)
{
while (count>0)
{
s.append(c);
count--;
}
}
}