/* RTMaude Code generator helper class.
Copyright (c) 2009 The Regents of the University of California.
All rights reserved.
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the above
copyright notice and the following two paragraphs appear in all copies
of this software.
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
PROVIDED HEREUNDER IS ON AN AS IS BASIS, AND THE UNIVERSITY OF
CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
ENHANCEMENTS, OR MODIFICATIONS.
PT_COPYRIGHT_VERSION_2
COPYRIGHTENDKEY
*/
package ptolemy.codegen.rtmaude.kernel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import ptolemy.actor.CompositeActor;
import ptolemy.codegen.kernel.CodeGeneratorHelper;
import ptolemy.codegen.kernel.CodeStream;
import ptolemy.codegen.kernel.ParseTreeCodeGenerator;
import ptolemy.codegen.rtmaude.data.expr.PropertyParameter;
import ptolemy.codegen.rtmaude.kernel.util.ListTerm;
import ptolemy.data.BooleanToken;
import ptolemy.data.IntToken;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.NamedObj;
//////////////////////////////////////////////////////////////////////////
//// RTMaudeAdaptor
/**
* Generate RTMaude code in DE domain. Every adaptor (helper) class for
* RTMaude should extend this class.
*
* @see ptolemy.codegen.kernel.CodeGeneratorHelper
* @author Kyungmin Bae
* @since Ptolemy II 7.1
* @version $Id$
* @Pt.AcceptedRating Red (kquine)
* @Pt.ProposedRating Red (kquine)
*
*/
public class RTMaudeAdaptor extends CodeGeneratorHelper {
protected String defaultTermBlock = "termBlock";
public RTMaudeAdaptor(NamedObj component) {
super(component);
_parseTreeCodeGenerator = getParseTreeCodeGenerator();
}
public List<String> getBlockCodeList(String blockName, String ... args)
throws IllegalActionException {
List<String> rl = new LinkedList();
String bcode = _generateBlockCode(blockName,args);
rl.add(bcode);
return rl;
}
/**
* @param blockName
* @param args
* @return The block code
* @throws IllegalActionException
*/
protected String _generateBlockCode(String blockName, String ... args)
throws IllegalActionException {
return super._generateBlockCode(blockName, Arrays.asList(args));
}
protected String _generateTypeConvertMethod(String ref, String castType,
String refType) throws IllegalActionException {
//FIXME: too specific.
if (refType != null && refType.equals("String"))
return "# " + ref;
if (castType != null && castType.equals("time")) {
return "toTime(" + ref + ")";
}
else
return super._generateTypeConvertMethod(ref, castType, refType);
}
public String generateFireCode() throws IllegalActionException {
String comment = _codeGenerator.comment("Fire " +
((getComponent() instanceof CompositeActor) ? "Composite Actor: " : "") +
generateName(getComponent()));
if (_codeGenerator.inline.getToken() == BooleanToken.TRUE)
return processCode(comment +
_generateFireCode() + generateTypeConvertFireCode());
else
return processCode(comment + generateTermCode());
}
public String generateFireFunctionCode() throws IllegalActionException {
return _generateBlockCode("fireFuncBlock",
CodeStream.indent(1,_generateFireCode() + generateTypeConvertFireCode())
);
}
/**
* Generate a Real-time Maude term representation of given component.
*
* @return the term representation of a component
* @throws IllegalActionException
*/
public String generateTermCode() throws IllegalActionException {
try
{
return _generateBlockCode(defaultTermBlock); // term block
}
catch (Exception e) // FIXME: temporally ignore exceptions, for avoiding bugs caused by others..
{
return null;
}
}
public Set getSharedCode() throws IllegalActionException {
// Use LinkedHashSet to give order to the shared code.
Set sharedCode = new LinkedHashSet();
semanticsIncludes = getModuleCode("semantics");
formalIncludes = getModuleCode("formal");
for (String m : semanticsIncludes)
sharedCode.add(getRTMmodule().get(m));
for (String m : formalIncludes)
sharedCode.add(getRTMmodule().get(m));
return sharedCode;
}
public List<String> getModuleCode(String header)
throws IllegalActionException {
Set<String> blocks = new HashSet(_codeStream.getAllCodeBlockNames());
LinkedList<String> modNames = new LinkedList();
if (RTMmodule == null) RTMmodule = new HashMap();
for (Class c = getComponent().getClass();
!c.getName().equals("ptolemy.kernel.util.NamedObj");
c = c.getSuperclass()) {
String blockName = header + "_" + c.getSimpleName();
if (blocks.contains(blockName)) {
String module = _generateBlockCode(blockName);
Matcher nameMat = Pattern.compile("tomod\\s+(\\S+)").matcher(module);
if (!nameMat.find())
throw new IllegalActionException("Invalid " + header + " module block: No name");
else {
String name = nameMat.group(1);
RTMmodule.put(name, module);
modNames.addFirst(name);
}
}
}
return modNames;
}
public String generateEntryCode() throws IllegalActionException {
LinkedHashSet<String> incs ;
if (_codeGenerator.inline.getToken() == BooleanToken.TRUE)
incs = new LinkedHashSet(semanticsIncludes);
else
incs = new LinkedHashSet(getBlockCodeList("funcModuleName"));
return _generateBlockCode("mainEntry",
CodeStream.indent(2,
new ListTerm<String>("ACTOR-BASE", " +" + _eol, incs).generateCode())
);
}
public String generateExitCode() throws IllegalActionException {
LinkedHashSet<String> check_inc_set = new LinkedHashSet<String>();
StringBuffer commands = new StringBuffer();
ptolemy.data.Token bound = ((RTMaudeCodeGenerator)_codeGenerator).
simulation_bound.getToken();
check_inc_set.add("INIT");
if (formalIncludes != null)
check_inc_set.addAll(formalIncludes);
else
throw new IllegalActionException("getSharedCode() has not been invoked");
if ( bound != null ) {
if (bound.toString().equals("Infinity"))
commands.append("(rew {init} .)");
else
commands.append("(trew {init} in time <= " +
IntToken.convert(bound).toString() + " .)");
}
for (PropertyParameter p : (List<PropertyParameter>)
_codeGenerator.attributeList(PropertyParameter.class)) {
commands.append("(" + p.stringValue() + " .)" + _eol);
}
return _generateBlockCode("mainExit",
CodeStream.indent(2,
new ListTerm<String>("MODELCHECK-BASE", " +" + _eol, check_inc_set).generateCode()),
commands.toString()
);
}
protected String getInfo(String name, List<String> parameters)
throws IllegalActionException {
if (name.equals("name"))
return getComponent().getName();
throw new IllegalActionException("Unknown RTMaudeObj Information");
}
protected String _replaceMacro(String macro, String parameter)
throws IllegalActionException {
if (macro.equals("info") || macro.equals("block")) {
String[] args = parameter.split("(?<!\\\\),");
for (int i = 1 ; i < args.length ; i++)
if (args[i].contains("$"))
args[i] = processCode(args[i]);
ArrayList<String> largs = new ArrayList(Arrays.asList(args));
String aName = largs.remove(0);
if (macro.equals("info"))
return getInfo(aName, largs);
else
return _generateBlockCode(aName, largs);
}
if (macro.equals("indent")) {
return CodeStream.indent(1, processCode(parameter));
}
return super._replaceMacro(macro, parameter);
}
/** Return a new parse tree code generator to use with expressions.
* @return the parse tree code generator to use with expressions.
*/
public ParseTreeCodeGenerator getParseTreeCodeGenerator() {
_parseTreeCodeGenerator = new RTMaudeParseTreeCodeGenerator(); //FIXME: _codeGenerator
return _parseTreeCodeGenerator;
}
public Map<String,String> getRTMmodule() {
return RTMmodule;
}
Map<String,String> RTMmodule;
List<String> semanticsIncludes;
List<String> formalIncludes;
}