Package wycc.lang

Source Code of wycc.lang.Wyil2CBuilder$Method

// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//    * Neither the name of the <organization> nor the
//      names of its contributors may be used to endorse or promote products
//      derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL DAVID J. PEARCE BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package wycc.lang;

import java.io.*;
import java.util.*;
import java.math.BigInteger;

import wyautl_old.lang.Automaton;
import wyautl_old.lang.Automaton.State;
import wybs.lang.Build;
import wybs.lang.Builder;
import wyfs.lang.Path;
import wyil.lang.WyilFile;
import wycc.util.Logger;
import wycc.util.Pair;
import wyil.lang.Code;
import wyil.lang.Codes;
import wyil.lang.Constant.Bool;
import wyil.lang.Modifier;
import wyil.lang.Type;
import wyil.lang.Constant;
import wyil.lang.Type.Record;
import wyil.lang.Type.Strung;
import wyil.lang.WyilFile;
import wyil.lang.WyilFile.Case;
import wyil.lang.WyilFile.ConstantDeclaration;
import wyil.lang.WyilFile.FunctionOrMethodDeclaration;
import wyil.lang.WyilFile.TypeDeclaration;

public class Wyil2CBuilder implements Builder {
  // * these are configuration parameters of the translation process
  private final String defaultManglePrefix = "wycc__";
  private final String includeFile = "#include \"wycc_lib.h\"";

  // * these are parameters of the translation process from invocation

  private String name;
  private boolean debugFlag;      // generate output and code to help diagnose the compiler
  private boolean lineNumFlag;    // add line number directives in the C to map it to the Whiley source
  private boolean floatFlag;      // produce floating point code to approximate the rationals
  private boolean floatForceFlag;
  private boolean indirectForceFlag;  // force all calls to use indirect references.

  // * these are details of the c implementation
  private final int wyccTypeAny = 0;
  private final int wyccTypeNone = -1;
  private final String exit_fail = "exit(-4);";

  //* these are derived or intermediate parameters
  private Logger logger = Logger.NULL;
  private String optIncludeFile = "";
  private String manglePrefix = null;
  private int ourFOMstate;      // index of first external
  private int initor_flg = 1;

  // * these are structures for recording characteristics of the code.
  private List<String> fileBody;
  // special handling needed for both record objects and FOM objects.
  // each type of record and each FOM has an integer token assigned.
  // FOM objects can be overloaded, so the type must be known for calling.
  // However, all variant types in the standard libraries share one file per name.
  private Map<Integer, Type.Record> recdReg;
  private Map<String, Integer> recdTok;
  private Map<Integer, String> fomReg;
  private Map<String, Integer> fomTok;
  private Set<String> fomNames;
  private List<Method> mets;      // the collection of our structures for handling FOMs in this source
  private Set<String> faultCodes;
  //private String commentsFOM = "";

  public Wyil2CBuilder() {
    this.wy2cbInit();
  }

  public Wyil2CBuilder(boolean dflg) {
    this.wy2cbInit();
    this.debugFlag = dflg;
  }

  public Wyil2CBuilder(Map<String, Object> values) {
    this.wy2cbInit();
    this.debugFlag = false;
    this.lineNumFlag = true;
    for (String itm : values.keySet()) {
      if (itm.equals("debug")) {
        this.debugFlag = true;
      } else if (itm.equals("no_numbers")) {
        this.lineNumFlag = false;
      } else if (itm.equals("floats")) {
        this.floatFlag = true;
        this.floatForceFlag = true;
      } else if (itm.equals("no_floats")) {
        this.floatFlag = false;
        this.floatForceFlag = true;
      } else if (itm.equals("only_indirect_calls")) {
        this.lineNumFlag = true;
      }

    }

    return;
  }

  private void wy2cbInit(){
    // * construct all the empty data structures for recording code details during processing
    //System.err.println("Got to my init code.");
    recdReg = new HashMap<Integer, Type.Record>();
    recdTok = new HashMap<String, Integer>();
    fomReg = new HashMap<Integer, String>();
    fomTok = new HashMap<String, Integer>();
    fomNames = new HashSet<String>();

    faultCodes = new HashSet<String>();
    faultCodes.add("invoke");
    faultCodes.add("throw");

    // * initalise the invocation flags and the starting states
    this.debugFlag = true;
    this.lineNumFlag = true;
    this.floatFlag = true;    // the default setting
    this.floatForceFlag = false// no user choice made.
    this.indirectForceFlag = false// the default setting
    this.ourFOMstate = -1// the initial setting

  }

  public void setLogger(Logger logger) {
    this.logger = logger;
  }

  public Build.Project project() {
    return null; // TODO: **** this seems like a mistake in Builder ?
  }

  public Set<Path.Entry<?>> build(
      Collection<Pair<Path.Entry<?>, Path.Root>> delta)
      throws IOException {

    Runtime runtime = Runtime.getRuntime();
    long start = System.currentTimeMillis();
    long memory = runtime.freeMemory();

    // ========================================================================
    // Translate files
    // ========================================================================
    HashSet<Path.Entry<?>> generatedFiles = new HashSet<Path.Entry<?>>();

    for (Pair<Path.Entry<?>, Path.Root> p : delta) {
      // System.err.println("Processing .... ");
      Path.Entry<WyilFile> sf = (Path.Entry<WyilFile>) p.first();
      Path.Root dst = p.second();
      Path.Entry<CFile> df = dst.create(sf.id(), CFile.ContentType);
      generatedFiles.add(df);
      // build the C-File
      CFile contents = build(sf.read());
      // finally, write the file into its destination
      df.write(contents);
    }

    // ========================================================================
    // Done
    // ========================================================================

    long endTime = System.currentTimeMillis();
    logger.logTimedMessage("Wyil => C: compiled " + delta.size()
        + " file(s)", endTime - start, memory - runtime.freeMemory());

    return generatedFiles;
  }

  // combine the name and type of a FOM and return a token (index in structures) for the pair.
  public int lookupNumFOMname(String nam, Type typ) {
    int ans;
    String dtyp;
    String key;
    Integer tok;

    // **** need to fill in the invocation register
    dtyp = writeDenseType(typ);
    //commentsFOM += "// FOM query for " + nam + "  '" + dtyp + "'\n";

    key = nam + " " + dtyp;
    if (fomTok.containsKey(key)){
      tok = fomTok.get(key);
      ans = tok;
    } else {
      ans = fomTok.size();
      tok = ans;
      fomTok.put(key, tok);
      fomReg.put(tok, key);
      fomNames.add(nam);
    }
    bodyAddLineNL"// FOM query #" + ans  );
    return ans;
  }

  //mnam = lookupFOMname(nam, cnt, cod.type);
  public String lookupFOMname(String nam, Type typ) {
    int alt;

    alt = lookupNumFOMname(nam, typ);
    bodyAddLineNL"// FOM query #" + alt  );
    if (ourFOMstate < 0) {
      return getManglePrefix() + nam + "__" + alt;
    } else if (alt < ourFOMstate) {
      return getManglePrefix() + nam + "__" + alt;
    } else {
      return getManglePrefix() + nam;
    }
  }

  public void bodyAddLine(String lin){

    this.fileBody.add(lin);
    return;
  }

  public void bodyAddLineNL(String lin){

    this.fileBody.add(lin + "\n");
    return;
  }

  public void bodyAddBlock(List<String> lins){

    this.fileBody.addAll(lins);
    return;
  }

  public String bodyRender(){
    String ans = "";

    for (String itm : this.fileBody) {
      ans += itm;
    }
    return ans;
  }

  public void setManglePrefix(String str) {
    this.manglePrefix = str;
  }

  public String getManglePrefix() {
    if (this.manglePrefix == null) {
      this.manglePrefix = this.defaultManglePrefix;
    }
    return this.manglePrefix;
  }

  /*
   * convert contents of a wyil file to contents of a C file
   */
  protected CFile build(WyilFile module) {
    int cnt;

    this.fileBody = new ArrayList<String>();
    this.mets = new ArrayList<Method>();
    //System.err.println("Got to my code.");
    this.name = module.id().toString();
    this.writePreamble(module);

    //System.err.println("milestone 1.");
    Collection<TypeDeclaration> typCol = module.types();
    Collection<ConstantDeclaration> conCol = module.constants();
    Collection<FunctionOrMethodDeclaration> modCol = module.functionOrMethods();

    // * at this point we are thru with the aggregate module; now to process separate collections
    if (this.debugFlag) {
      bodyAddLineNL"// WYIL module count of types: " + typCol.size()  );
      bodyAddLineNL"// WYIL module count of constants: " + conCol.size()  );
      bodyAddLineNL"// WYIL module count of methods: " + modCol.size()  );

    }

    cnt = 0;
    for (TypeDeclaration td : typCol) {
      cnt += 1;
      this.writeTypeComments(td, cnt);
      this.writeTypeCode(td, cnt);

    }

    cnt = 0;
    for (ConstantDeclaration cd : conCol) {
      cnt += 1;
      this.writeConstant(cd, cnt);
    }

    cnt = 0;
    for (FunctionOrMethodDeclaration md : modCol) {
      cnt += 1;
      Method met = new Method(md, cnt);
      met.writeComments();
      mets.add(met);
    }

    // * done processing module and its component collections ; now to spit out C code
    // * completion of preamble is function/method prototypes
    bodyAddLine(this.optIncludeFile);
    bodyAddLineNL""  );
    for (Method met : mets) {
      met.writeProto();
    }
    bodyAddLineNL""  );
    bodyAddLineNL"// ==========================================="  )// mark end of preamble
    ourFOMstate = fomTok.size();
    for (Method met : mets) {
      met.write();
    }
    //bodyAddLineNL(  "//"  );
    bodyAddLineNL"// ==========================================="  )// mark start of postamble

    this.writePostamble();
    //System.err.println("Got to end of my code.");
    return new CFile(this.bodyRender());
  }

  // * write generic preamble
  private void writePreamble(WyilFile module) {

    if (this.lineNumFlag) {
      bodyAddLineNL"#line 0 \"" + module.id() + ".whiley\""  );
    }
    bodyAddLineNL"// WYIL Module: " + name  );
    bodyAddLineNL"// WYIL Filename: " + module.filename()  );
    bodyAddLineNLthis.includeFile  );
    bodyAddLineNL"static wycc_obj *record_reg[];"  );
    bodyAddLineNL"static wycc_obj *fom_handle_reg[];"  );
    return;
  }

  private void writePostamble() {

    if (this.initor_flg == 0) {
      return;
    }
    bodyAddLineNL("");

    this.writeTypeRegistry();
    this.writeFOMRegistry();

    bodyAddLineNL(    ""                          );
    bodyAddLineNL(    "static void __initor_b() {"            );
    bodyAddLineNL(     "  if (wycc_debug_flag != 0)"            );
    bodyAddLineNL(     "    wyil_debug_str(\"registering for " + this.name + "\\n\");"  );
    this.writeTypeRegistryFill();
    this.writeFOMRegistryFill();

    bodyAddLineNL(     "  return;"                );
    bodyAddLineNL(     "}"                      );

    bodyAddLineNL(    ""                          );
    bodyAddLineNL(    "static void __initor_d() {"              );
    bodyAddLineNL(    "  if (wycc_debug_flag != 0)"            );
    bodyAddLineNL(    "    wyil_debug_str(\"consulting for " + this.name + "\\n\");"  );

    this.writeFOMRegistryQuery();

    bodyAddLineNL(    "  return;"                    );
    bodyAddLineNL(    "}"                          );


    bodyAddLineNL(    ""                          );
    bodyAddLineNL(    "static wycc_initor __initor_c;"          );
    bodyAddLineNL(     "__attribute__ ((constructor)) static void __initor_a() {"    );
    bodyAddLineNL(     "  __initor_c.nxt = wycc_init_chain;"        );
    bodyAddLineNL(    "  __initor_c.functionr = __initor_b;"        );
    bodyAddLineNL(     "  __initor_c.functionq = __initor_d;"        );
    bodyAddLineNL(    "  wycc_init_chain = &__initor_c;"          );
    bodyAddLineNL(     "  return;"                    );
    bodyAddLineNL(     "}"                          );

    this.writeFOMLinkTrigger();
    return;
  }

  // * generate triggers to link in needed library routines ; most will be impedance matched at runtime
  private void writeFOMLinkTrigger() {
    Set<String> nams = new HashSet<String>();
    String tmp;

    bodyAddLineNL"// FOM Link Trigger references go here."  );
    bodyAddLineNL"static void* wyccTriggers[] = {"  );
    for (String nam : fomNames){
      nams.add(nam);
    }
    for (Method met : mets) {
      if (! met.isNative) {
        tmp = met.name;
        if (nams.contains(tmp))
          nams.remove(tmp);
      }
    }
    tmp = "";
    for (String nam : nams){
      //bodyAddLineNL(  "// " + nam  );
      if (tmp != "") {
        bodyAddLineNLtmp + ","  );
      }
      tmp ="  (void *) " + getManglePrefix() + nam;
    }
    bodyAddLineNLtmp  );
    bodyAddLineNL"};"  );

  }

  // * given a record type return a token (index) to refer to that type later.
  public int registerRecordType(Type.Record typ){
    int ans;
    String key;
    Integer tok;

    key = "" + typ;
    if (recdTok.containsKey(key)){
      ans = recdTok.get(key);
      return ans;
    }

    ans = recdTok.size();
    tok = ans;
    recdTok.put(key, tok);
    recdReg.put(tok, typ);
    return ans;
  }

  private void writeTypeRegistry() {

    int cnt = recdTok.size();
    bodyAddLineNL"// type registry array goes here (size " + cnt + ")"  );
    bodyAddLineNL"static wycc_obj *record_reg[" + cnt + "];"  );
  }

  private void writeFOMRegistry() {

    int cnt = fomTok.size();
    bodyAddLineNL"// FOM handle registry array goes here (size " + cnt + ")"  );
    bodyAddLineNL"static wycc_obj *fom_handle_reg[" + cnt + "];"  );
  }

  private void writeTypeRegistryFill() {
    String dtyp;

    Type.Record typ;
    int cnt = recdTok.size();
    int idx;

    bodyAddLineNL("// filling in type registry array goes here " + cnt  );
    bodyAddLineNL("  wycc_obj * rcd_rcd;"  );
    idx = 0;
    for (Integer tok:recdReg.keySet()) {
      typ = recdReg.get(tok);
      dtyp = writeDenseType(typ);
      bodyAddLineNL("  record_reg[" + idx + "] = wycc_record_type(\"" + dtyp + "\");"  );
      idx+= 1;
    }
  }

  private void writeFOMRegistryFill() {
    String tmp;

    bodyAddLineNL("// Here goes code to fill the FOM registry");
    // need a loop over the known FOM.

    for (Method met : mets) {
      tmp = "  wycc_register_routine(\"" + met.name ;
      tmp += "\", \"" + met.denseType;
      tmp += "\", " + met.altName + ");";
      bodyAddLineNLtmp  );
    }
  }

  private void writeFOMRegistryQuery() {
    String key;
    int idx;
    String nam;
    String dty;
    int cnt = 0;

    //System.err.println("milestone 99a");
    bodyAddLineNL("// Here goes code to query the FOM registry");
    //bodyAddLine(commentsFOM);
    for (Integer tok:fomReg.keySet()) {
      key = fomReg.get(tok);
      idx = key.indexOf(' ');
      nam = key.substring(0,idx);
      dty = key.substring(idx+1);
      bodyAddLineNL("  fom_handle_reg[" + cnt + "] = wycc_fom_handle(\"" + nam + "\", \"" + dty + "\");"  );
      cnt += 1;
    }

  }

  public void writeTypeComments(TypeDeclaration typDe, int idx) {
    String lin;
    String ans = "";

    Code.Block strain = typDe.invariant();
    List<Modifier> mods = typDe.modifiers();
    Type typ = typDe.type();
    List<Attribute> atts = typDe.attributes();

    lin = "#" + idx;
    lin += "(" + atts.size() + ":" + mods.size() + ")";
    lin += " is named " + typDe.name();
    ans += "// WYIL type declaration " + lin + "\n";
    if (typDe.hasModifier(wyil.lang.Modifier.PROTECTED)) {
      ans += "//                 is Protected\n";
    }
    if (typDe.hasModifier(wyil.lang.Modifier.PUBLIC)) {
      ans += "//                 is Public\n";
    }
    if (strain != null) {
      ans += "//                 with constraints\n";
    }
    if (typ != null) {
      ans += "//                 with a type\n";
    }
    if (this.debugFlag) {
      bodyAddLine(ans);
    }
    return;
  }

  // process the file wide Type declaration
  public void writeTypeCode(TypeDeclaration typDe, int idx) {
    return;
  }

  // process the file wide Constant declaration in pass 1 comments
  public void writeConstant(ConstantDeclaration conDe, int idx) {
    String tmp;

    if (this.debugFlag) {
      tmp = "// **** Need help with constant declaration #" + idx;
      bodyAddLineNL(tmp);
    }

    tmp = "// **** Need help with constant declaaration #" + idx;
    bodyAddLineNL(tmp);
    if (conDe.hasModifier(wyil.lang.Modifier.PROTECTED)) {
      tmp = "//                 is Protected";
      bodyAddLineNL(tmp);
    }
    if (conDe.hasModifier(wyil.lang.Modifier.PUBLIC)) {
      tmp = "//                 is Public";
      bodyAddLineNL(tmp);
    }
    tmp = "//                 has name '" + conDe.name() + "'";
    bodyAddLineNL(tmp);
    return;
  }

  // * a class to hold every detail we need about FOMs (Function Or Method)
  public class Method {
    private FunctionOrMethodDeclaration declaration;
    private int index;
    //private String body;
    private List<String> body;
    private String comments;
    // private String delt; // the deconstructors
    private Map<Integer, String> declsT;
    private Map<Integer, String> declsI;
    private Set<Integer> declsU;
    private List<List<String>> bStack;      // a stack of stacks of lines (a context body)
    private List<String> nStack;    // a stack of names for end-of-s
    private List<String> tStack;    // a try stack (names of end labels)
    private List<Integer> tvStack;    // a try stack (register number for the exception object)
    private List<ArrayList<Pair<Type, String>>> tcStack;

    private String indent;
    private String sourceTag;
    private String error;
    private boolean isNative;
    private boolean isPrivate;
    private boolean isExport;
    private boolean isProtected;
    private boolean isPublic;
    private boolean returnSeen;
    private List<Modifier> mods;
    private List<Case> cas;
    private List<Attribute> atts;
    private ArrayList<Type> params;
    private String proto = null;

    public String name;
    public String altName;
    public Type retType;
    public int argc;
    public String argt;
    public String denseType;
    public int indexFOM;

    public Method(FunctionOrMethodDeclaration metDe, int idx) {
      String lin;
      int cnt;
      declaration = metDe;
      index = idx;
      name = metDe.name();
      indent = "  ";
      declsT = new HashMap<Integer, String>();
      declsI = new HashMap<Integer, String>();
      declsU = new HashSet();
      this.body = new ArrayList<String>();
      this.bStack = new ArrayList<List<String>>();
      this.nStack = new ArrayList<String>();
      this.tcStack = new ArrayList<ArrayList<Pair<Type, String>>>  ();
      this.tvStack = new ArrayList<Integer>  ();

      Type.FunctionOrMethod rtnTyp;

      error = "";
      isNative = false;
      isPrivate = false;
      isExport = false;
      isProtected = false;
      isPublic = false;
      returnSeen = false;
      mods = declaration.modifiers();
      cas = declaration.cases();
      atts = declaration.attributes();
      rtnTyp = declaration.type();
      denseType = writeDenseType(rtnTyp);
      indexFOM = lookupNumFOMname(name, rtnTyp);
      altName = getManglePrefix() + name + "__" + indexFOM;
      comments = "";

      lin = "#" + index + " (";
      lin += atts.size();
      lin += ":";
      lin += mods.size();
      lin += ":";
      lin += cas.size();
      lin += ") is named " + name;
      comments += "// WYIL method declaration " + lin + "\n";
      comments += "//               with type = '"+ rtnTyp +"'\n";

      typeParse(rtnTyp);
      if (declaration.isMethod()) {
        comments += "//   is method.\n";
      }
      if (declaration.isFunction()) {
        comments += "//   is function.\n";
      }
      cnt = 0;
      for (Modifier mo : mods) {
        cnt += 1;
        this.checkModifier(mo, cnt);
      }
      cnt = 0;
      for (Case ci : cas) {
        cnt += 1;
        this.checkCase(ci, cnt);
      }
    }

    private void mbodyAddLine(String lin){
      this.body.add(lin);
      return;
    }

    private void mbodyAddLineNL(String lin){
      this.body.add(lin + "\n");
      return;
    }

    private void mbodyAddLineTINL(String lin){
      this.body.addindent + lin + this.sourceTag + "\n"  );
      return;
    }

    private void mbodyAddLineINL(String lin){
      this.body.addindent + lin + "\n"  );
      return;
    }

    private void mbodyAddBlock(List<String> lins){
      this.body.addAll(lins);
      return;
    }

    //  save a context for nested code
    private void mbodyPush(String nam) {
      this.bStack.add(this.body);
      this.body = new ArrayList<String>();
      this.nStack.add(nam);
    }

    // collapse the current context into the next save down.
    private boolean mbodyPop(String nam) {
      int idx = this.bStack.size();
      String tgt;
      List<String> blk;

      if (idx != this.nStack.size()){
        this.error += "name stack out-of-sync with block stack\n";
      }
      idx -= 1;
      if (idx < 0) {
        //System.err.println("ERROR: popping beyond the push.");
        return false;
      }
      tgt = this.nStack.remove(idx);

      if (tgt.equals(nam)){

      } else {
        this.nStack.add(tgt);
        this.comments += "// target name stack mismatch: " + tgt + "!=" + nam +"\n";
        return false;
      }
      blk = this.bStack.remove(idx);
      for (String itm:this.body){
        if (itm.startsWith("#")) {
          blk.add(itm);
        } else {
          blk.add(indent + itm);
        }
      }
      this.body = blk;
      return true;
    }

    private boolean endsWithLabel(){
      int idx;
      String tmp;
      boolean ans;

      idx = this.body.size();
      while (true) {
        idx -= 1;
        if (idx < 0) {
          return false;
        }
        tmp = this.body.get(idx);
        if (! tmp.startsWith("#")) {
          break;
        }
      }
      ans = tmp.endsWith(":\n");
      return ans;
    }

    //
    public void writeComments() {

      if (debugFlag) {
        bodyAddLine(comments);
      }
      return;
    }

    public void typeParse(Type.FunctionOrMethod typ) {
      String ans = "";
      String argl = "";
      String sep = "";

      params = typ.params();
      this.argc = params.size();
      retType = typ.ret();
      ans += "//              return type = '" + retType+ "'\n";
      ans += "//              using '" + this.argc + " parameters\n";
      this.comments += ans;
      for (Type tp : params){
        argl += sep + tp;
        sep = "^";
      }
      this.argt = argl;
      return;
    }

    private void makeProto() {
      String ans = "static ";
      String sep = "";
      String argl = "";
      int cnt;

      if (proto != null) {
        return;
      }
      // **** need to consider other possible types
      if (retType instanceof Type.Void) {
        ans += "void ";
      } else  {
        ans += "wycc_obj* ";
      }
      cnt = 0;
      for (Type tp : params){
        argl += sep + "wycc_obj* X" + cnt ;
        cnt += 1;
        sep = ", ";
      }

      ans += altName + "(" + argl + ")";
      proto = ans;
      return;
    }

    public void writeProto() {
      if (isNative) {
        return;
      }
      makeProto();
      bodyAddLineNLproto + ";"  );
      return;
    }

    //
    public void write() {
      int cnt;

      cnt = 0;
      for (Case ci : cas) {
        cnt += 1;
        this.writeCase(ci, cnt);
      }
      if (error != "") {
        bodyAddLineNL"ERROR in " + name + ": "  );
        bodyAddLineerror  );
        return;
      }
      if (isNative) {
        return;
      }
      makeProto();
      bodyAddLineNLproto + " {"  );
      writeDecls();
      bodyAddBlock(body);
      bodyAddLineNL"}"  );

      return;
    }

    private void writeDecls() {
      String ans;
      Integer k;
      String typ;
      String nam = "";
      Integer skip;
      int cnt;

      skip = params.size();
      for (Map.Entry<Integer, String> e : declsT.entrySet()) {
        k = e.getKey();
        typ = e.getValue();
        if (k < 0) {
          nam = " XN" + (-k);
        } else if (k < skip) {
          continue;
        } else {
          nam = " X" + k;
        }
        ans = indent + typ + nam + " = (" + typ + ")0;";
        bodyAddLineNL(ans);
      }
      //ans = indent + "wycc_obj* Xc = (wycc_obj*)0;";
      //bodyAddLineNL(ans);
      //ans = indent + "wycc_obj* Xb = (wycc_obj*)0;";
      //bodyAddLineNL(ans);
      //ans = indent + "wycc_obj* Xa = (wycc_obj*)0;";
      //bodyAddLineNL(ans);
      //ans = indent + "wycc_obj** Xi = (wycc_obj**)0;";
      //bodyAddLineNL(ans);

      bodyAddLineNLindent + "wycc_obj* Xc = (wycc_obj*)0;"  );;
      bodyAddLineNLindent + "wycc_obj* Xb = (wycc_obj*)0;"  );
      bodyAddLineNLindent + "wycc_obj* Xa = (wycc_obj*)0;"  );
      bodyAddLineNLindent + "wycc_obj** Xi = (wycc_obj**)0;"  );
      cnt = 0;
      //for (Type tp : params){
      while (cnt < skip) {
        bodyAddLineNLindent + "WY_OBJ_BUMP(X" + cnt + ");"  );
        cnt += 1;
      }

      return;
    }

    private void addDecl(int target, String typ) {
      Integer tgt = target;
      String tst1 = declsT.get(tgt);
      if (tst1 == null) {
        declsT.put(tgt, typ);
      } else if (tst1.equals(typ)){

      } else {
        this.error += "multiple type declarations for X" + target + "\n";

      }
    }

    // examine routine modifier, set bool variables, inject comment
    public void checkModifier(Modifier mod, int idx) {
      String tag = "Unknown";

      if (mod instanceof Modifier.Export) {
        tag = "Export";
        this.isExport = true;
      } else if (mod instanceof Modifier.Native) {
        tag = "Native";
        this.isNative = true;
      } else if (mod instanceof Modifier.Private) {
        tag = "Private";
        this.isPrivate = true;
      } else if (mod instanceof Modifier.Protected) {
        tag = "Protected";
        this.isProtected = true;
      } else if (mod instanceof Modifier.Public) {
        tag = "Public";
        this.isPublic = true;
      }
      this.comments += "// modifier #" + idx + " is " + tag + "\n";
      return;
    }

    // initial examination of properties of routines
    // currently only effect is comment injection
    public void checkCase(Case casIn, int idx) {
      String ans = "";
      int cnt = -1;
      List<Attribute> attCol = casIn.attributes();
      //Block bod = casIn.body();
      List<Code.Block> prec = casIn.precondition();
      List<Code.Block> posc = casIn.postcondition();

      if (attCol == null) {
        ans += "//           " + " no attributes\n";
      } else {
        cnt = attCol.size();
        ans += "//           " + " with " + cnt + " attributes\n";
      }
      if (prec.isEmpty()) {
        ans += "//           " + " no precondition\n";
      } else {
        cnt = prec.size();
        ans += "//           " + " precondition of size " + cnt + "\n";
      }
      if (posc.isEmpty()) {
        ans += "//           " + " no postcondition\n";
      } else {
        cnt = posc.size();
        ans += "//           " + " postcondition of size " + cnt + "\n";
      }
      this.comments += ans;
      return;
    }

    // write case delegates to write Body
    public void writeCase(Case casIn, int idx) {
      Code.Block bod = casIn.body();
      this.writeBody(bod, idx);
      return;
    }

    // generate C code for the wyil sequence, each wyil byte goes to writeBlockEntry
    public void writeBody(Code.Block bodIn, int idx) {
      int cnt = -1;

      if (bodIn == null) {
        bodyAddLineNL"// block #" + idx + " is null"  );
        return;
      }
      cnt = bodIn.size();
      bodyAddLineNL"// block #" + idx + " is of seizes " + cnt  );

      cnt = 0;
      for (Code.Block.Entry be : bodIn) {
        this.writeBlockEntry(be, cnt);
        cnt += 1;
      }
      return;
    }

    // produce comments and optionally C directives to note the source line numbers
    public String writeSourceLineID(Code.Block.Entry blkIn){
      String ans = "";
      int cnt;
      int idx;

      List<Attribute> attCol = blkIn.attributes();
      if (attCol == null) {
        return "//           " + " no attributes\n";
      }
      cnt = attCol.size();
      if (cnt < 1) {
        return "//           " + "  0 attributes\n";
      }
      if (cnt != 1) {
        ans += "//           " + " with " + cnt + " attributes\n";
      }
      idx = 0;
      while (idx < cnt) {
        Attribute att = attCol.get(idx);
        if (att instanceof Attribute.Source) {
          Attribute.Source attis = (Attribute.Source) att;
          if (lineNumFlag) {
            this.mbodyAddLineNL"#line " + attis.line  );
          }
        } else {
          ans += "//           " + " [0] is " + att+ "\n";
        }
        idx++;
      }
      return ans;
    }

    //
    // convert a block entry code into some lines of C code to put in the
    // file
    // leading comments get passed to bodyAddLine() and the code to this.mbodyAddLine().
    // **** changes needed
    // * tracking variables declared
    // ! code for variable destruction
    // * even a subclass for routines
    //
    public void writeBlockEntry(Code.Block.Entry blkIn, int idx) {
      String tmp;
      int targ;
      //String lin;
      String tag = "\t/* entry# " + idx + "*/";

      this.sourceTag = tag;
      bodyAddLineNL"// block.entry #" + idx  );
      Code cod = blkIn.code;
      tmp = this.writeSourceLineID(blkIn);
      bodyAddLine(tmp);

      String temp = cod.toString();
      bodyAddLineNL"//             Looks like " + safeString2(temp)  );

      String[] frags = temp.split(" ", 4);
      String opc = frags[0];
      if (cod instanceof Codes.Const) {
        this.writeCodeConstant(cod);
      } else if (cod instanceof Codes.Debug) {
        Codes.Debug codd = (Codes.Debug) cod;
        targ = codd.operand;
        //lin = "  wyil_debug_obj(X" + targ + ");" + tag;
        //this.mbodyAddLineNL(  lin  );
        this.mbodyAddLineTINL"wyil_debug_obj(X" + targ + ");"  );
      } else if (cod instanceof Codes.Return) {
        this.writeCodeReturn(cod);
      } else if (cod instanceof Codes.StringOperator) {
        this.writeCodeBinStringOp(cod);

      } else if (cod instanceof Codes.Assign) {
        this.writeCodeAssign(cod);
      } else if (cod instanceof Codes.Invoke) {
        this.writeCodeInvoke(cod);
      } else if (cod instanceof Codes.BinaryOperator) {
        this.writeCodeBinArithOp(cod);
      } else if (cod instanceof Codes.NewList) {
        this.writeCodeNewList(cod);
      } else if (cod instanceof Codes.NewSet) {
        this.writeCodeNewSet(cod);
      } else if (cod instanceof Codes.NewMap) {
        this.writeCodeNewMap(cod);
      } else if (cod instanceof Codes.LengthOf) {
        this.writeCodeLengthOf(cod);
      } else if (cod instanceof Codes.IndexOf) {
        this.writeCodeIndexOf(cod);
      } else if (cod instanceof Codes.LoopEnd) {
        this.writeCodeLoopEnd(cod);
      } else if (cod instanceof Codes.TryEnd) {
        this.writeCodeTryEnd(cod);
      } else if (cod instanceof Codes.Label) {
        this.writeCodeLabel(cod);

      } else if (cod instanceof Codes.FieldLoad) {
        this.writeCodeFieldLoad(cod);

      } else if (cod instanceof Codes.NewRecord) {
        this.writeCodeNewRecord(cod);
      } else if (cod instanceof Codes.If) {
        this.writeCodeIf(cod);

      } else if (cod instanceof Codes.ListOperator) {
        this.writeCodeBinListOp(cod);
      } else if (cod instanceof Codes.SetOperator) {
        this.writeCodeBinSetOp(cod);
      } else if (cod instanceof Codes.Void) {
        this.writeCodeVoid(cod);
      } else if (cod instanceof Codes.Update) {
        this.writeCodeUpdate(cod);
      } else if (cod instanceof Codes.UnaryOperator) {
        this.writeCodeUnArithOp(cod);
      } else if (cod instanceof Codes.TupleLoad) {
        this.writeCodeTupleLoad(cod);
      } else if (cod instanceof Codes.TryCatch) {
        this.writeCodeTryCatch(cod);
      } else if (cod instanceof Codes.Throw) {
        this.writeCodeThrow(cod);
      } else if (cod instanceof Codes.Switch) {
        this.writeCodeSwitch(cod);
      } else if (cod instanceof Codes.ForAll) {
        this.writeCodeForAll(cod);
      } else if (cod instanceof Codes.IfIs) {
        this.writeCodeIfIs(cod);
      } else if (cod instanceof Codes.Loop) {
        this.writeCodeLoop(cod);
      } else if (cod instanceof Codes.NewTuple) {
        this.writeCodeNewTuple(cod);

      } else if (cod instanceof Codes.Goto) {
        this.writeCodeGoto(cod);

      } else if (cod instanceof Codes.Convert) {
        this.writeCodeConvert(cod);

      } else if (cod instanceof Codes.SubList) {
        this.writeCodeSubList(cod);
      } else if (cod instanceof Codes.SubString) {
        this.writeCodeSubString(cod);

      } else if (cod instanceof Codes.NewObject) {
        this.writeCodeNewObject(cod);
      } else if (cod instanceof Codes.Dereference) {
        this.writeCodeDereference(cod);
      } else if (cod instanceof Codes.Invert) {
        this.writeCodeInvert(cod);
      } else if (cod instanceof Codes.IndirectInvoke) {
        this.writeCodeIndirectInvoke(cod);
      } else if (cod instanceof Codes.Lambda) {
        this.writeCodeLambda(cod);

      } else if (cod instanceof Codes.Void) {
        this.writeCodeVoid(cod);
      } else {
        bodyAddLineNL"// HELP! needed for opcode '" + opc + "'"  );
      }
      if (faultCodes.contains(opc)) {
        writeCatchCheck();
      }
      return;
    }

    public void writeCodeVoid(Code codIn){

      bodyAddLineNL"// HELP! needed for Void"  );
      Codes.Void cod = (Codes.Void) codIn;
      return;
    }

    public void writeCodeLambda(Code codIn){
      int targ;
      int cnt;
      int foo;
      int tok;
      Type typ;
      String nam;
      String lin;
      String dtyp;
      String sig = "++";    // ***** must change this

      bodyAddLineNL"// HELP! needed for Lambda"  );
      Codes.Lambda cod = (Codes.Lambda) codIn;
      targ = cod.target();
      nam = cod.name.name();
      typ = cod.type();
      bodyAddLineNL"//    name is '" + nam + "'"  );
      bodyAddLineNL"//    operands are:"  );
      cnt = cod.operands().length;
      writeClearTarget(targ);
      this.addDecl(targ, "wycc_obj*");
      this.mbodyAddLineTINL"Xc = wycc_list_new(" + cnt + ");"  );
      cnt = 0;
      foo = -1;
      for (int itm : cod.operands()) {
        cnt+=1;
        bodyAddLineNL"//    #" + cnt + " : " + itm  );
        if (itm < 0) {
          this.mbodyAddLineTINL"wycc_list_add(Xc, 0);"  );
        } else {
          this.mbodyAddLineTINL"wycc_list_add(Xc, X" + itm + ");"  );
        }
        if (itm == targ) {
          foo = targ;
        }
      }
      //Constant.Lambda fom = (Constant.Lambda) val;
      //bodyAddLineNL(  "// HELP! needed in lambda for FOM name: '" + fom.name.name() + "'"  );
      bodyAddLineNL"// HELP! needed in lambda for FOM name: '" + nam + "'"  );
      dtyp = writeDenseType(typ);
      bodyAddLineNL"// HELP! needed in const for FOM dtyp: '" + dtyp + "'"  );
      //tok = lookupNumFOMname(fom.name.name(), typ);
      tok = lookupNumFOMname(nam, typ);
      lin = " = wycc_lambda_new(fom_handle_reg[" + tok + "], Xc);"  ;
      writeTargetSwap(lin, targ, foo);

      return;
    }

    public void writeCodeIndirectInvoke(Code codIn){
      String tmp;
      int cnt;
      int targ;
      int opr;
      String var;

      Codes.IndirectInvoke cod = (Codes.IndirectInvoke) codIn;
      targ = cod.target();
      cnt = cod.operands().length - 1;
      opr = cod.operands()[0];

      var = "Xc";
      this.mbodyAddLineTINLvar + " = wycc_list_new(" + cnt + ");"  );
      cnt = -1;
      for (int i=1;i<cod.operands().length;++i) {
        int itm = cod.operands()[i];
        this.mbodyAddLineTINL"wycc_list_add(" + var + ", X" + itm + ");"  );
        if (itm == targ) {
          cnt = targ;
        }
      }
      if (cnt == -1) {
        if (targ == opr) {
          cnt = opr;
        }
      }
      tmp = " = wycc_indirect_invoke(X" +opr + ", " + var + ");";
      writeTargetSwap(tmp, targ, cnt);

      return;
    }

    public void writeCodeInvoke(Code codIn){
      int targ;
      String sep, mnam;
      String lin = "";
      int foo;

      Codes.Invoke cod = (Codes.Invoke) codIn;
      targ = cod.target();
      NameID nid = cod.name;
      //Path.ID pat = nid.module();
      String nam = nid.name();
      mnam = lookupFOMname(nam, cod.type());
      lin += mnam + "(";

      foo = -1;
      sep = "";
      for (int itm : cod.operands()) {
        lin += sep + "X" + itm;
        sep = ", ";
        if (itm == targ) {
          foo = targ;
        }
      }
      lin += ");";
      if (targ < 0) {
        this.mbodyAddLineTINLlin  );
        return;
      }
      lin = " = " + lin;
      writeTargetSwap(lin, targ, foo);

      return;
    }

    public void writeCatchCheck(){

      if (1 > this.tcStack.size()) {
        mbodyAddLineINL"if (wycc_exception_check()) goto return0;"  );
      } else {
        mbodyAddLineINL"if (wycc_exception_check()) break;"  );
      }
      return;
    }

    public void writeCodeTryEnd(Code codIn){
      String nam;
      Type typ;
      String dtyp;
      Integer reg;
      int opr;
      ArrayList<Pair<Type, String>> dsp;
      int idx = this.tcStack.size()-1;

      //bodyAddLineNL(  "// HELP! needed for TryEnd"  );
      Codes.TryEnd cod = (Codes.TryEnd) codIn;
      nam = cod.label;
      if (this.mbodyPop("")) {
        if (this.endsWithLabel()) {
          this.mbodyAddLineINLindent + ";"  );
        }
        this.mbodyAddLineINL"} while (0);"  );
        dsp = this.tcStack.remove(idx);
        reg = this.tvStack.remove(idx);
        opr = reg;

        for (Pair<Type, String> pitm: dsp) {
          typ = pitm.first();
          dtyp = writeDenseType(typ);
          this.mbodyAddLineINLindent + "if (wycc_exception_try(\"" + dtyp + "\")){"  );
          writeClearTarget(opr);
          this.mbodyAddLineINLindent + "X" + opr +" = wycc_exception_get();"  );
          this.mbodyAddLineINLindent + "wycc_exception_clear();"  );
          this.mbodyAddLineINLindent + "goto " + pitm.second() + ";"    );
          this.mbodyAddLineINL"};"    );
        }
        this.mbodyAddLineINL"goto return0;"  );
      }
      this.mbodyAddLineNLnam + ":"    );
      return;
    }

    public void writeCodeTryCatch(Code codIn){
      int lhs;
      Integer reg;

      //bodyAddLineNL(  "// HELP! needed for TryCatch"  );
      Codes.TryCatch cod = (Codes.TryCatch) codIn;
      lhs = cod.operand;
      ArrayList<Pair<Type, String>> foo = cod.catches;

      tcStack.add(foo);
      this.addDecl(lhs, "wycc_obj*");

      reg = lhs;
      tvStack.add(reg);
      this.mbodyAddLineINL"wyil_catch(\"" + this.name + "\");"   );
      this.mbodyAddLineINL"do {"  );
      this.mbodyPush("");
      return;
    }

    public void writeCodeThrow(Code codIn){
      int lhs;

      bodyAddLineNL"// HELP! needed for Throw"    );
      Codes.Throw cod = (Codes.Throw) codIn;
      lhs = cod.operand;
      this.mbodyAddLineTINL"wyil_throw(X" + lhs + ");"  );
      return;
    }

    public void writeCodeDereference(Code codIn){
      String tmp;
      int targ, lhs;

      bodyAddLineNL"// HELP needed for Dereference"    );
      Codes.Dereference cod = (Codes.Dereference) codIn;
      targ = cod.target();
      lhs = cod.operand(0);

      tmp = " = wyil_dereference(X" + lhs  + ");";
      writeTargetSwap(tmp, targ, lhs);

      return;
    }

    public void writeCodeNewObject(Code codIn){
      String tmp;
      int targ, lhs;

      //bodyAddLineNL(  "// HELP needed for NewObject"  );
      Codes.NewObject cod = (Codes.NewObject) codIn;
      targ = cod.target();
      lhs = cod.operand(0);

      tmp = " = wycc_box_ref(X" + lhs  + ");";
      writeTargetSwap(tmp, targ, lhs);
      return;
    }

    public void writeCodeSubString(Code codIn){
      int targ;
      String lin;
      int src, lo, hi;
      int cnt;

      //bodyAddLineNL(  "// HELP needed for SubString"  );
      Codes.SubString cod = (Codes.SubString) codIn;
      targ = cod.target();
      cnt = cod.operands().length;
      if (cnt != 3) {
        error += "ERROR SubString bad arg count " + cnt + "\n";
        return;
      }
      src = cod.operands()[0];
      lo = cod.operands()[1];
      hi = cod.operands()[2];
      writeClearTarget(targ);
      this.addDecl(targ, "wycc_obj*");
      lin = "X" + targ + " = wyil_substring(X" + src + ", X" + lo + ", X" + hi + ");";
      this.mbodyAddLineTINLlin  );

      return;
    }

    public void writeCodeNewTuple(Code codIn){
      int targ;
      int cnt;
      int idx;

      //bodyAddLineNL(  "// HELP needed for NewTuple"  );
      Codes.NewTuple cod = (Codes.NewTuple) codIn;
      targ = cod.target();
      cnt = cod.operands().length;

      writeClearTarget(targ);
      this.addDecl(targ, "wycc_obj*");
      this.mbodyAddLineTINL"X" + targ + " = wycc_tuple_new(" + cnt + ");"  );
      idx = 0;
      for (int itm : cod.operands()) {
        //lin = "wycc_update_list(X" + targ + ", X" + itm + ", " + idx+ ");" + tag;
        //this.mbodyAddLineINL(  lin  );
        this.mbodyAddLineTINL"wycc_update_list(X" + targ + ", X" + itm + ", " + idx+ ");"  );
        idx += 1;
      }
      return;
    }

    public void writeCodeTupleLoad(Code codIn){
      int targ, rhs, idx;

      //bodyAddLineNL(  "// HELP needed for TupleLoad"  );
      Codes.TupleLoad cod = (Codes.TupleLoad) codIn;
      targ = cod.target();
      rhs = cod.operand(0);
      idx = cod.index;

      writeClearTarget(targ);
      this.addDecl(targ, "wycc_obj*");
      this.mbodyAddLineTINL"X" + targ + " = wycc_list_get(X" + rhs + ", " + idx + ");"  );

      return;
    }

    public void writeCodeInvert(Code codIn){
      String tmp;
      int targ, rhs;

      //bodyAddLineNL(  "// HELP! needed for Invert"  );
      Codes.Invert cod = (Codes.Invert) codIn;
      targ = cod.target();
      rhs = cod.operand(0);

      tmp = " = wyil_invert(X" + rhs + ");";
      writeTargetSwap(tmp, targ, rhs);

      return;
    }

    public void writeCodeGoto(Code codIn){
      String target;

      //bodyAddLineNL(  "// HELP needed for Goto"  );
      Codes.Goto cod = (Codes.Goto) codIn;
      target = cod.target;
      bodyAddLineNL"//             going to " + target  );
      this.mbodyAddLineINL"goto " + target + ";"  );

      return;
    }

    public void writeCodeLoopEnd(Code codIn){
      String nam;

      //bodyAddLineNL(  "// HELP needed for LoopEnd"  );
      Codes.LoopEnd cod = (Codes.LoopEnd) codIn;
      nam = cod.label;
      bodyAddLineNL"//             called " + nam  );
      if (this.mbodyPop(nam)) {
        if (this.endsWithLabel()) {
          this.mbodyAddLineINLindent + ";"  );
        }
        this.mbodyAddLineINL"};"  );
      }
      this.mbodyAddLineNLnam + ":"  );
      return;
    }

    public void writeCodeLabel(Code codIn){
      String nam;

      //bodyAddLineNL(  "// HELP needed for Label"  );
      Codes.Label cod = (Codes.Label) codIn;
      nam = cod.label;
      bodyAddLineNL"//             called " + nam  );
      this.mbodyAddLineNLnam + ":"  );
      return;
    }

    public void writeCodeIf(Code codIn){
      int lhs, rhs;
      String cmp;
      String target;

      //bodyAddLineNL(  "// HELP needed for If"  );
      Codes.If cod = (Codes.If) codIn;
      lhs = cod.leftOperand;
      rhs = cod.rightOperand;
      Codes.Comparator opr = cod.op;
      target = cod.target;
      cmp = mapComparator(opr, false);
      if (cmp == null) {
        error += "Assert operation un-defined\n";
        bodyAddLineNL"// HELP needed for binListOp '" + opr + "'"  );
        return;
      }
      bodyAddLineNL"//             comparing X" + lhs + " " + opr + " X" + rhs  );
      bodyAddLineNL"//             going to " + target  );

      this.mbodyAddLineINL"if (wycc_compare(X" + lhs + ", X" + rhs + ", " + cmp + ")){"  );
      this.mbodyAddLineINLindent + "goto " + target + ";"  );
      this.mbodyAddLineINL"};"  );
      return;
    }

    public void writeCodeIfIs(Code codIn){
      int lhs;
      Type rhs;
      String target;
      String dtyp;

      //bodyAddLineNL(  "// HELP needed for IfIs"  );
      Codes.IfIs cod = (Codes.IfIs) codIn;
      lhs = cod.operand;
      rhs = cod.rightOperand;
      target = cod.target;

      dtyp = writeDenseType(rhs);
      bodyAddLineNL"//             checking if X" + lhs + " is of type " + rhs  );
      bodyAddLineNL"//      or " + dtyp   );
      bodyAddLineNL"//             going to " + target  );

      this.mbodyAddLineINL"if (wycc_type_check(X" + lhs + ", \"" + dtyp + "\")){"  );
      this.mbodyAddLineINLindent + "goto " + target + ";"  );
      this.mbodyAddLineINL"};"  );
      return;
    }

    public void writeCodeLoop(Code codIn){
      String target;

      //bodyAddLineNL(  "// HELP needed for Loop"  );
      Codes.Loop cod = (Codes.Loop) codIn;
      target = cod.target;
      bodyAddLineNL"//             going to " + target  );

      this.mbodyAddLineINL"while (1) {"  );
      this.mbodyPush(target);
      return;
    }

    public void writeCodeNewRecord(Code codIn){
      String tmp;
      int targ;
      int cnt;
      int idx;
      int tok;
      String lin;
      Type.Record typ;

      //bodyAddLineNL(  "// HELP needed for NewRecord"  );
      Codes.NewRecord cod = (Codes.NewRecord) codIn;
      cnt = cod.operands().length;
      targ = cod.target();
      typ = (Type.Record) cod.type();
      tok = registerRecordType(typ);

      bodyAddLineNL"//             tok " + tok + " with " + cnt + " fields:"  );

      tmp = writeCommentRecord(typ);
      bodyAddLine(tmp);
      idx = 0;
      for (int itm : cod.operands()) {
        idx += 1;
        bodyAddLineNL"//             operand " + idx + " is " + itm  );

      }

      writeClearTarget(targ);
      this.addDecl(targ, "wycc_obj*");
      this.mbodyAddLineTINL"X" + targ + " = wycc_record_new(record_reg[" + tok + "]);"  );
      idx = 0;
      for (int itm : cod.operands()) {
        this.mbodyAddLineTINL"wycc_record_fill(X" + targ + ", " + idx + ", X" + itm + ");"  );
        idx += 1;
      }
      return;
    }

    private String writeCommentRecord(Type.Record typ){
      String ans = "";
      int idx;
      idx = 0;

      for (String ke:getFieldNames(typ)){
        idx += 1;
        ans += "//             #" + idx + ":" + ke + " " + typ.field(ke)+ "\n";
      }
      return ans;
    }

    public void writeCodeFieldLoad(Code codIn){
      String tmp;
      String fnam;
      int cnt;
      int targ, rhs;
      Type.Record typ;

      //bodyAddLineNL(  "// HELP needed for FieldLoad"  );
      Codes.FieldLoad cod = (Codes.FieldLoad) codIn;
      targ = cod.target();
      fnam = cod.field;
      rhs = cod.operand(0);
      bodyAddLineNL"//             wanting field '" + fnam + "' out of:"  );

      if (cod.type() instanceof Type.Record) {
        typ = (Type.Record) cod.type();
        tmp = writeCommentRecord(typ);
        bodyAddLine(tmp);
        cnt = getFieldNames(typ).indexOf(fnam);
        tmp = " = wycc_record_get_dr(X" + rhs + ", " + cnt + ");";

      } else {
        tmp = " = wycc_record_get_nam(X" + rhs + ", \"" + fnam + "\");";
      }
      writeTargetSwap(tmp, targ, rhs);

      return;
    }

    public void writeCodeForAll(Code codIn){
      //String tmp;
      int opIdx;
      int opBlk;
      String target;

      //bodyAddLineNL(  "// HELP needed for ForAll"  );
      Codes.ForAll cod = (Codes.ForAll) codIn;
      opIdx = cod.indexOperand;
      opBlk = cod.sourceOperand;
      target = cod.target;
      bodyAddLineNL"//                 stepping over X" + opBlk + " with X" + opIdx  );
      bodyAddLineNL"//                 reaching" + target  );
      writeClearTarget(opIdx);
      this.addDecl(opIdx, "wycc_obj*");
      writeClearTarget(-opIdx);
      this.addDecl(-opIdx, "wycc_obj*");

      this.mbodyAddLineINL"XN" + opIdx + " = wycc_iter_new(X" + opBlk + ");"  );
      this.mbodyAddLineINL"while (X" + opIdx + " = wycc_iter_next(XN" + opIdx + ")) {"  );
      this.mbodyPush(target);

      return;
    }

    public void writeCodeSwitch(Code codIn){
      String tmp;
      ArrayList<Pair<Constant, String>> branches;
      String target;
      int opr;
      int cnt;
      int idx;
      String alt;
      Constant con;
      String nam;

      //bodyAddLineNL(  "// HELP needed for Switch"  );
      Codes.Switch cod = (Codes.Switch) codIn;
      branches = cod.branches;
      target = cod.defaultTarget;
      opr = cod.operand;

      cnt = branches.size();
      bodyAddLineNL"//             checking X" + opr + " with " + cnt + " choices:"  );
      idx = 0;
      nam = "XN" + opr;
      this.addDecl(-opr, "wycc_obj*");
      for (Pair<Constant, String> pick:branches) {
        alt = pick.second();
        con = pick.first();
        bodyAddLineNL"//             #" + idx + " -> " + con + ":" + alt  );
        idx += 1;

        tmp = this.writeMyConstant(con, nam, 0);
        if (tmp == null){
          continue;
        }
        this.mbodyAddLine(tmp);
        this.mbodyAddLineINL"if (wycc_compare(X" + opr + ", XN" + opr + ", Wyil_Relation_Eq)){"  );
        this.mbodyAddLineINLindent + "goto " + alt + ";"  );
        this.mbodyAddLineINL"};"  );
      }
      this.mbodyAddLineINL"goto " + target + ";"  );
      return;
    }

    public void writeCodeUnArithOp(Code codIn){
      String tmp;
      int targ, rhs;
      String rtn, lin;

      //bodyAddLine(  "// HELP needed for UnArithOp"  );
      Codes.UnaryOperator cod = (Codes.UnaryOperator) codIn;
      Codes.UnaryOperatorKind opr = cod.kind;
      targ = cod.target();
      rhs = cod.operand(0);

      if (opr == Codes.UnaryOperatorKind.NEG) {
        rtn = "wyil_negate";
      } else if (opr == Codes.UnaryOperatorKind.NUMERATOR){
        if (floatFlag) {
          bodyAddLineNL"// HELP! needed for unArithOp '" + opr + "'"  );
          return;
        }
        rtn = "wyil_numer";
      } else if (opr == Codes.UnaryOperatorKind.DENOMINATOR){
        if (floatFlag) {
          bodyAddLineNL"// HELP! needed for unArithOp '" + opr + "'"  );
          return;
        }
        rtn = "wyil_denom";
      } else {
        bodyAddLineNL"// HELP! needed for unArithOp '" + opr + "'"  );
        return;
      }
      tmp = " = " + rtn + "(X" + rhs + ");";
      writeTargetSwap(tmp, targ, rhs);

      return;
    }

    public void writeCodeUpdate(Code codIn){
      String tmp;
      int targ, rhs, ofs;
      int cnt;
      Type typ;
      String lin;
      String backFix;
      ArrayList<String> flds;
      Codes.LVal lv;
      int idx;
      int iidx, fidx;
      String tnam1, tnam2;
      String tag = this.sourceTag;

      //
      // There is a small bit of magic here, accomplished with a group of 3 temporary variables
      // Start by realising that the composite structure must be mutable at least from the top
      // on down to the point of change.
      // The 3 variables (in the C code) are Xa, Xb, and Xc
      // Xc becomes that variable by which we reference the composite
      // Xb is the starting value for the next layer down in the composite
      // Xa gets the value of the unshared (mutable) form of Xb
      // Here backFix gets the C code to update the (soon to be) previous level
      //
      // a Reference is not only mutable, but is expected to track the mutations (COWs)
      // to which it referes.
      //
      bodyAddLineNL"// HELP needed for Update"  );
      Codes.Update cod = (Codes.Update) codIn;
      targ = cod.target();
      flds = cod.fields;
      idx = cod.level();

      tmp = "//             target is " + targ + " and depth is " + idx;
      bodyAddLineNL(tmp);
      tmp = "//             field count is " + flds.size();
      bodyAddLineNL(tmp);
      cnt = 0;
      ofs = -1;
      for (int itm : cod.operands()) {
        cnt += 1;
        tmp = "//             operand " + cnt + " is " + itm;
        bodyAddLineNL(tmp);
        ofs = itm;
      }
      rhs = cod.result();
      tmp = "//             rhs is " + rhs;
      bodyAddLineNL(tmp);
      typ = cod.type();
      tmp = "//             type is " + typ;
      bodyAddLineNL(tmp);

      this.addDecl(targ, "wycc_obj*");
      tnam1 = "X" + targ;
      Iterator<Codes.LVal> foo = cod.iterator();

      iidx = 0;
      fidx = 0;
      backFix = tnam1 + " = Xa;";
      this.mbodyAddLineTINL"Xb = " + tnam1 + ";"  );
      this.mbodyAddLineTINL"Xi = &(" + tnam1 + ");"  );

      while (idx > 0) {
        lv = foo.next();
        if (lv instanceof Codes.ReferenceLVal) {
          lin = "Xc = Xb;";
          tmp = indent + lin + tag;
          tmp += " /* a */ ";
          this.mbodyAddLineNL(tmp);

        } else {
          lin = "Xa = wycc_cow_obj(Xb);";
          tmp = indent + lin + tag;
          tmp += " /* b */ ";
          this.mbodyAddLineNL(tmp);
          lin = "if (Xb != Xa) {";

          this.mbodyAddLineINLlin  );
          this.mbodyAddLineINLindent + backFix  );
          this.mbodyAddLineINL"};"  );
          this.mbodyAddLineTINL"Xc = Xa;"  );
        }

        if (lv instanceof Codes.ListLVal) {
          ofs = cod.operands()[iidx];
          iidx += 1;
          if (idx > 1) {
            lin = "Xb = wyil_index_of(Xc, X" + ofs + ");" + tag;
            backFix = "Xb = wyil_update_list(Xc, X" + ofs + ", Xa);" + tag;
          } else {
            lin =  "Xb = wyil_update_list(Xc, X" + ofs + ", X" + rhs + ");";
          }
          tmp = indent + lin + tag;
          tmp += " /* c */ ";
          this.mbodyAddLineNL(tmp);

        } else if (lv instanceof Codes.StringLVal) {
          ofs = cod.operands()[iidx];
          iidx += 1;
          if (idx > 1) {
            error += "ERROR cannot do updates below a string\n";
            return;
          } else {
            lin = "Xb = wyil_update_string(Xc, X" + ofs + ", X" + rhs + ");";
          }
          tmp = indent + lin + tag;
          tmp += " /* d */ ";
          this.mbodyAddLineNL(tmp);

        } else if (lv instanceof Codes.ReferenceLVal) {
          if (idx > 1) {
            lin = "Xb = wyil_dereference(Xc);" + tag;
            //backFix = "Xb = wycc_box_ref(Xa);" + tag;
            //backFix = "/* ugly no-op */;" + tag;
            //backFix = "if (Xi) { *Xi = wycc_box_ref(Xa); Xi = (wycc_obj**)0;};" + tag;
            backFix = "wycc_update_ref(Xc, Xa);";
          } else {
            //lin = tnam1 + " = wyil_update_string(" + tnam1 + ", X" + ofs + ", X" + rhs + ");";
            //lin = "Xb = wyil_update_string(Xc, X" + ofs + ", X" + rhs + ");";
            error += "ERROR cannot do updates at a reference\n";
            return;
          }
          tmp = indent + lin + tag;
          tmp += " /* e */ ";
          this.mbodyAddLineNL(tmp);

        } else if (lv instanceof Codes.MapLVal) {
          ofs = cod.operands()[iidx];
          iidx += 1;
          if (idx > 1) {
            lin = "Xb = wyil_index_of(Xc, X" + ofs + ");" + tag;
            backFix = "wycc_map_add(Xc, X" + ofs + ", Xa);" + tag;
          } else {
            lin = "wycc_map_add(Xc, X" + ofs + ", X" + rhs + ");";
          }
          tmp = indent + lin + tag;
          tmp += " /* f */ ";
          this.mbodyAddLineNL(tmp);

        } else if(lv instanceof Codes.RecordLVal) {
          Codes.RecordLVal l = (Codes.RecordLVal) lv;
          Type.EffectiveRecord tipe = l.rawType();
          tnam2 = flds.get(fidx);
          if (tipe instanceof Type.Record) {
            ofs = getFieldNames((Record) tipe).indexOf(tnam2);
            if (idx > 1) {
              lin = "Xb = wycc_record_get_dr(Xc, " + ofs + ");" + tag;
              backFix = "wycc_record_fill(Xc, " + ofs + ", Xa);" + tag;
            } else {
              lin = "wycc_record_fill(Xc, " + ofs + ", X" + rhs + ");";
            }
            tmp = indent + lin + tag;
            tmp += " /* g */ ";
            this.mbodyAddLineNL(tmp);
          } else {
            if (idx > 1) {
              lin = "Xb = wycc_record_get_nam(Xc, \"" + tnam2 + "\");" + tag;
              backFix = "wycc_record_put_nam(Xc, \"" + tnam2 + "\", Xa);" + tag;
            } else {
              lin = "wycc_record_put_nam(Xc, \"" + tnam2 + "\", X" + rhs + ");";
            }
            tmp = indent + lin + tag;
            tmp += " /* h */ ";
            this.mbodyAddLineNL(tmp);
          }
          fidx += 1;
        } else {
          error += "ERROR cannot yet do updates for type " + lv + "\n";
          return;
        }
        idx -= 1;
      }
      return;
    }

    public void writeCodeSubList(Code codIn){
      String tmp;
      int targ, src, lhs, rhs, cnt;

      //bodyAddLineNL(  "// HELP needed for SubList"  );
      Codes.SubList cod = (Codes.SubList) codIn;
      targ = cod.target();
      cnt = cod.operands().length;
      if (cnt != 3) {
        error += "SubList operand count is "+ cnt + "\n";
        bodyAddLineNL"// HELP needed for  SubList"  );
        return;

      };
      src = cod.operands()[0];
      lhs = cod.operands()[1];
      rhs = cod.operands()[2];
      cnt = -1;
      for (int itm : cod.operands()) {
        if (itm == targ) {
          cnt = targ;
        }
      }
      tmp = " = "+ "wyil_list_sub(X" + src + ", X" + lhs + ", X" + rhs + ");";
      writeTargetSwap(tmp, targ, cnt);
      return;
    }

    public void writeCodeBinSetOp(Code codIn){
      String tmp;
      int targ, lhs, rhs, swp;
      String rtn, lin;

      //bodyAddLineNL(  "// HELP needed for BinSetOp"  );
      Codes.SetOperator cod = (Codes.SetOperator) codIn;
      Codes.SetOperatorKind opr = cod.kind;
      targ = cod.target();
      lhs = cod.operand(0);
      rhs = cod.operand(1);

      if (opr == Codes.SetOperatorKind.DIFFERENCE) {
        rtn = "wyil_set_diff";
      } else if (opr == Codes.SetOperatorKind.INTERSECTION){
        rtn = "wyil_set_insect";
      } else if (opr == Codes.SetOperatorKind.LEFT_DIFFERENCE){
        rtn = "wyil_set_diff_odd";
      } else if (opr == Codes.SetOperatorKind.LEFT_INTERSECTION){
        rtn = "wyil_set_insect_odd";
      } else if (opr == Codes.SetOperatorKind.LEFT_UNION){
        rtn = "wyil_set_union_odd";
      } else if (opr == Codes.SetOperatorKind.RIGHT_INTERSECTION){
        rtn = "wyil_set_insect_odd";
        swp = lhs;
        lhs = rhs;
        rhs = swp;
      } else if (opr == Codes.SetOperatorKind.RIGHT_UNION){
        rtn = "wyil_set_union_odd";
        swp = lhs;
        lhs = rhs;
        rhs = swp;
      } else if (opr == Codes.SetOperatorKind.UNION){
        rtn = "wyil_set_union";
      } else {
        error += "BinSetOp un-defined\n";
        bodyAddLineNL"// HELP! needed for binSetOp '" + opr + "'"  );
        return;
      }
      tmp = " = "+ rtn + "(X" + lhs + ", X" + rhs + ");";
      writeTargetSwap(tmp, targ, lhs);

      return;
    }

    public void writeCodeBinListOp(Code codIn){
      int targ, lhs, rhs;
      String rtn;

      //bodyAddLineNL(  "// HELP needed for BinListOp"  );
      Codes.ListOperator cod = (Codes.ListOperator) codIn;
      Codes.ListOperatorKind opr = cod.kind;
      targ = cod.target();
      writeClearTarget(targ);
      this.addDecl(targ, "wycc_obj*");
      lhs = cod.operand(0);
      rhs = cod.operand(1);
      if (opr == Codes.ListOperatorKind.APPEND) {
        rtn = "wyil_list_comb";
      } else if (opr == Codes.ListOperatorKind.LEFT_APPEND){
        rtn = "wyil_list_comb";
        error += "BinListOp ill-defined\n";
      } else if (opr == Codes.ListOperatorKind.RIGHT_APPEND){
        rtn = "wyil_list_comb";
        error += "BinListOp ill-defined\n";
      } else {
        error += "BinListOp un-defined\n";
        bodyAddLineNL"// HELP! needed for binListOp '" + opr  );
        return;
      }
      this.mbodyAddLineTINL"X" + targ + " = " + rtn + "(X" + lhs + ", X" + rhs + ");"  );
      return;
    }

    //
    // do a lookup given a key (in a map) or an int (in a list)
    public void writeCodeIndexOf(Code codIn){
      int targ, lhs, rhs;

      Codes.IndexOf cod = (Codes.IndexOf) codIn;
      targ = cod.target();
      lhs = cod.operand(0);
      rhs = cod.operand(1);

      writeClearTarget(targ);
      this.addDecl(targ, "wycc_obj*");
      this.mbodyAddLineTINL"X" + targ + " = wyil_index_of(X" + lhs + ", X" + rhs + ");"  );
      return;
    }

    public void writeCodeLengthOf(Code codIn){
      int targ, rhs;
      String lin;

      Codes.LengthOf cod = (Codes.LengthOf) codIn;
      targ = cod.target();
      rhs = cod.operand(0);

      lin = " = wyil_length_of(X" + rhs + ");";
      writeTargetSwap(lin, targ, rhs);

      return;
    }

    // given an assignment (sans target), a target register, a source register, and a tag
    // handle declaring the target register, and producing the completed assignment
    // where an intermediate register has to be used if the target is the same as the source.
    private void writeTargetSwap(String lin, int targ, int opr){
      String t2;
      //String tag = this.sourceTag;

      this.addDecl(targ, "wycc_obj*");
      if (targ == opr) {
        if (targ != 0) {
          this.addDecl(-targ, "wycc_obj*");
          t2 = "XN" + targ;
        } else {
          t2 = "Xc";
        }
        this.mbodyAddLineTINLt2 + lin  );
        writeClearTarget(targ);
        this.addDecl(targ, "wycc_obj*");
        this.mbodyAddLineTINL"X" + targ + " = " + t2 + ";"  );
      } else {
        writeClearTarget(targ);
        this.mbodyAddLineTINL"X" + targ + lin  );
      }
      return;
    }

    public void writeCodeReturn(Code codIn){
      String lin;
      Integer k;
      String nam = "";
      Integer skip;
      int tgt;

      Codes.Return cod = (Codes.Return) codIn;

      if (returnSeen) {
        // seems like nothing else is needed here
      } else {
        this.mbodyAddLineNL("return0:");
      }
      returnSeen = true;
      if (retType instanceof Type.Void) {
        lin = "return;";
        tgt = 0;
      } else  {
        tgt = cod.operand;
        lin = "return X" + tgt + ";";
      }
      skip = params.size();
      for (Map.Entry<Integer, String> e : declsT.entrySet()) {
        k = e.getKey();
        if (k < skip) {
          continue;
        } if (tgt == k) {
          continue;
        } else {
          nam = " X" + k;
        }
        this.mbodyAddLineINLnam + " = wycc_deref_box(" + nam + ", 1);"  );
      }

      // **** may need to consider other return types
      this.mbodyAddLineTINLlin  );
      return;
    }

    public void writeCodeNewMap(Code codIn){
      int targ;
      String lin;
      boolean flg;

      //bodyAddLine(  "// HELP needed for NewMap"  );
      Codes.NewMap cod = (Codes.NewMap) codIn;
      targ = cod.target();
      writeClearTarget(targ);
      this.addDecl(targ, "wycc_obj*");
      this.mbodyAddLineTINL"X" + targ + " = wycc_map_new(" + wyccTypeNone + ");"  );
      flg = false;
      lin = "";
      for (int itm : cod.operands()) {
        if (flg) {
          lin += ", X" + itm + ");";
          this.mbodyAddLineTINLlin  );
          flg = false;
          lin = "";
        } else {
          lin = "wycc_map_add(X" + targ + ", X" + itm;
          flg = true;
        }
      }
      if (flg){
        error += "ERROR: odd count of arguments for initalizing a map\n";
      }
      return;
    }

    public void writeCodeNewSet(Code codIn){
      int targ;

      //bodyAddLineNL(  "// HELP needed for NewSet"  );
      Codes.NewSet cod = (Codes.NewSet) codIn;
      targ = cod.target();

      writeClearTarget(targ);
      this.addDecl(targ, "wycc_obj*");
      this.mbodyAddLineTINL"X" + targ + " = wycc_set_new(" + wyccTypeNone + ");"  );
      for (int itm : cod.operands()) {
        this.mbodyAddLineTINL"wycc_set_add(X" + targ + ", X" + itm + ");"  );
      }
      return;
    }

    public void writeCodeNewList(Code codIn){
      int cnt;
      int targ;

      //bodyAddLineNL(  "// HELP needed for NewList"  );
      Codes.NewList cod = (Codes.NewList) codIn;
      targ = cod.target();
      cnt = cod.operands().length;
      writeClearTarget(targ);
      this.addDecl(targ, "wycc_obj*");
      this.mbodyAddLineTINL"X" + targ + " = wycc_list_new(" + cnt + ");"  );
      for (int itm : cod.operands()) {
        this.mbodyAddLineTINL"wycc_list_add(X" + targ + ", X" + itm + ");"  );
      }

      return;
    }

    public void writeCodeBinStringOp(Code codIn){
      String rtn;
      int targ, lhs, rhs;

      Codes.StringOperator cods = (Codes.StringOperator) codIn;
      //Codes.BinStringKind opr = cods.kind;

      rtn = "wyil_strappend";
      targ = cods.target();
      lhs = cods.operand(0);
      rhs = cods.operand(1);
      writeClearTarget(targ);
      this.mbodyAddLineTINL"X" + targ + " = " + rtn + "(X" + lhs + ", X" + rhs + ");"  );
      this.addDecl(targ, "wycc_obj*");

      return;
    }

    public void writeCodeAssign(Code codIn){
      int targ, rhs;

      Codes.Assign cod = (Codes.Assign) codIn;
      targ = cod.target();
      rhs = cod.operand(0);
      if (targ == rhs) {
        bodyAddLineNL"//            Safely ignoring assign operation"  );
        return;
      }
      writeClearTarget(targ);
      // **** should check that types match
      this.addDecl(targ, "wycc_obj*");
      this.mbodyAddLineTINL"X" + targ + " = X" + rhs + ";"  );
      this.mbodyAddLineTINL"WY_OBJ_BUMP(X" + rhs + ");"  );
      return;
    }

    public void writeCodeConvert(Code codIn){
      String tmp;
      String dtyp;
      int tgt, opr;
      Type ntyp, otyp;

      Codes.Convert cod = (Codes.Convert) codIn;
      tgt = cod.target();
      opr = cod.operand(0);
      ntyp = cod.result;
      otyp = cod.type();
      if (ntyp instanceof Type.Any) {
        bodyAddLineNL"//            Safely ignoring convert operation to Any"  );
        return;
      }

      bodyAddLineNL"//**          change X" + opr + " from " + otyp + " to " + ntyp  );
      dtyp = writeDenseType(ntyp);
      bodyAddLineNL"//**          convert_parse " + dtyp  );
      tmp = "";
      if (ntyp instanceof Type.Union) {
        if (((Type.Union) ntyp).bounds().contains(otyp)) {
          bodyAddLineNL"//            Safely ignoring convert operation to supertype"  );
          return;
        }
      }
      if (otyp instanceof Type.Leaf) {
        tmp += "was " + otyp + " ";
      }
      if (ntyp instanceof Type.Leaf) {
        tmp += "will be " + ntyp + " ";
      }
      if (tmp != "") {
        bodyAddLineNL"//--          " + tmp + " a leaf type"  );
      }
      this.addDecl(tgt, "wycc_obj*");
      this.mbodyAddLineINL(   "Xa = wyil_convert(X" + opr + ", \"" + dtyp + "\");"    );
      writeClearTarget(tgt);
      this.mbodyAddLineINL"X" + tgt + " = Xa;"    );
      return;
    }

    public void writeCodeBinArithOp(Code codIn){
      int targ, lhs, rhs;
      String rtn;

      Codes.BinaryOperator cod = (Codes.BinaryOperator) codIn;
      Codes.BinaryOperatorKind opr = cod.kind;
      targ = cod.target();
      writeClearTarget(targ);
      this.addDecl(targ, "wycc_obj*");
      lhs = cod.operand(0);
      rhs = cod.operand(1);

      if (opr == Codes.BinaryOperatorKind.ADD) {
        rtn = "wyil_add";
      } else if (opr == Codes.BinaryOperatorKind.SUB){
        rtn = "wyil_sub";
      } else if (opr == Codes.BinaryOperatorKind.MUL){
        rtn = "wyil_mul";
      } else if (opr == Codes.BinaryOperatorKind.DIV){
        rtn = "wyil_div";
      } else if (opr == Codes.BinaryOperatorKind.REM){
        rtn = "wyil_mod";
      } else if (opr == Codes.BinaryOperatorKind.BITWISEAND){
        rtn = "wyil_bit_and";
      } else if (opr == Codes.BinaryOperatorKind.BITWISEOR){
        rtn = "wyil_bit_ior";
      } else if (opr == Codes.BinaryOperatorKind.BITWISEXOR){
        rtn = "wyil_bit_xor";
      } else if (opr == Codes.BinaryOperatorKind.LEFTSHIFT){
        rtn = "wyil_shift_up";
      } else if (opr == Codes.BinaryOperatorKind.RIGHTSHIFT){
        rtn = "wyil_shift_down";
      } else if (opr == Codes.BinaryOperatorKind.RANGE){
        rtn = "wyil_range";
      } else {
        bodyAddLineNL"// HELP! needed for binArithOp '" + opr + "'"  );
        return;
      }
      this.mbodyAddLineTINL"X" + targ + " = " + rtn + "(X" + lhs + ", X" + rhs + ");"  );
      return;
    }

    public void writeCodeConstant(Code codIn){
      String tmp;
      int targ;
      Constant val;
      String nam;

      Codes.Const cod = (Codes.Const) codIn;
      targ = cod.target();
      val = cod.constant;
      bodyAddLineNL"//             target " + targ  );
      nam = "X" + targ;

      tmp = this.writeMyConstant(val, nam, 0);
      if (tmp == null) {
        return;
      }
      this.addDecl(targ, "wycc_obj*");
      writeClearTarget(targ);
      this.mbodyAddLine(tmp);
      return;
    }

    private String writeMyConstant(Constant val, String nam, int deep){
      return writeMyConstant(val, nam, this.sourceTag, deep);
    }

    private String writeMyConstant(Constant val, String nam, String tag, int deep){
      //final Integer intMax = (Integer) 2147483647;
      final BigInteger bigIntMax = new BigInteger("2147483647");
      final Constant.Integer wyIntMax = Constant.V_INTEGER(bigIntMax);
      String ans = "";
      String tmp;
      Type typ;
      String rval;
      String assn = null;
      int alt;
      int cnt;
      int tok;
      int idx;
      String anam, bnam;
      String dtyp;

      if ((deep % 2) == 1) {
        anam = "Xb";
        bnam = "Xa";
      } else {
        anam = "Xa";
        bnam = "Xb";
      }
      typ = val.type();
      rval = val.toString();
      if (typ instanceof Type.Strung) {
        assn = "wycc_box_cstr(\"" + safeString1(rval) + "\")";
        Constant.Strung sq = (Constant.Strung) val;

        tmp = sq.value;
        idx =  tmp.indexOf('\n');
        bodyAddLineNL"//    Constant.Strung index is " + idx    );
      } else if (typ instanceof Type.Int) {
        //if (rval.length() > 9) {
        if (val.compareTo(wyIntMax) >= 0) {
          assn = "wycc_box_wint(\"" + rval + "\")";
        } else {
          assn = "wycc_box_int(" + rval + ")";
        }
      } else if (typ instanceof Type.Bool) {
        if (rval.equals("true")) {
          rval = "1";
        } else {
          rval = "0";
        }
        assn = "wycc_box_bool(" + rval + ")";
      } else if (typ instanceof Type.Char) {
        assn = "wycc_box_char(" + rval + ")";
      } else if (typ instanceof Type.Byte) {
        alt = intFromByte(rval);
        assn = "wycc_box_byte(" + alt + ")";
      } else if (typ instanceof Type.Set) {
        assn = "wycc_set_new(-1)";
        Constant.Set cs = (Constant.Set) val;
        cnt = cs.values.size();
        bodyAddLineNL"//             with " + cnt + " initialisers"  );
        tmp = indent + nam + " = " + assn + ";" + tag + "\n";
        ans += tmp;
        tmp = indent + "{\n";
        ans += tmp;
        tmp = indent + indent + "wycc_obj *" + anam + " = (wycc_obj*)0;\n";
        ans += tmp;
        for (Constant itm:cs.values) {
          tmp = writeMyConstant(itm, anam, "", deep+1);
          ans += indent + tmp;
          tmp = indent + indent + "wycc_set_add(" + nam + ", " + anam + ");\n";
          ans += tmp;
          tmp = indent + indent + "wycc_deref_box(" + anam + ", 0);\n";
          ans += tmp;
        }
        tmp = indent + "}\n";
        ans += tmp;
        return ans;
      } else if (typ instanceof Type.Map) {
        // **** does this need to handle initial values, as set does
        bodyAddLineNL"// HELP! needed in const for value type '" + typ + "'"  );
        assn = "wycc_map_new(-1)";
        Constant.Map cm = (Constant.Map)val;
      } else if (typ instanceof Type.Record) {
        Constant.Record cr = (Constant.Record) val;
        cnt = cr.values.size();
        tmp = "//             with " + cnt + " initialisers";
        bodyAddLineNL(tmp);
        tok = registerRecordType((Record) typ);
        assn = "wycc_record_new(record_reg[" + tok + "])";
        tmp = indent + nam + " = " + assn + ";" + tag + "\n";
        ans += tmp;
        tmp = indent + "{\n";
        ans += tmp;
        tmp = indent + indent + "wycc_obj *" + anam + " = (wycc_obj*)0;\n";
        ans += tmp;
        idx = 0;
        for (String ke:getFieldNames((Record) typ)){
          tmp = writeMyConstant(cr.values.get(ke), anam, "", deep+1);
          ans += indent + tmp;
          tmp = indent + indent + "wycc_record_fill(" + nam + ", " + idx +", " + anam + ");\n";
          ans += tmp;
          tmp = indent + indent + "wycc_deref_box(" + anam + ", 0);\n";
          ans += tmp;
          idx += 1;
        }
        tmp = indent + "}\n";
        ans += tmp;
        return ans;
      } else if (typ instanceof Type.List) {
        Constant.List cl = (Constant.List) val;
        cnt = cl.values.size();
        tmp = "//             with " + cnt + " initialisers";
        bodyAddLineNL(tmp);
        assn = "wycc_list_new(" + cnt + ")";
        tmp = indent + nam + " = " + assn + ";" + tag + "\n";
        ans += tmp;
        tmp = indent + "{\n";
        ans += tmp;
        tmp = indent + indent + "wycc_obj *" + anam + " = (wycc_obj*)0;\n";
        ans += tmp;
        for (Constant itm:cl.values) {
          tmp = writeMyConstant(itm, anam, "", deep+1);
          ans += indent + tmp;
          tmp = indent + indent + "wycc_list_add(" + nam + ", " + anam + ");\n";
          ans += tmp;
          tmp = indent + indent + "wycc_deref_box(" + anam + ", 0);\n";
          ans += tmp;
        }
        tmp = indent + "}\n";
        ans += tmp;
        return ans;
      } else if (typ instanceof Type.Tuple) {
        Constant.Tuple ct = (Constant.Tuple) val;
        cnt = ct.values.size();
        tmp = "//             with " + cnt + " initialisers";
        bodyAddLineNL(tmp);
        assn = "wycc_tuple_new(" + cnt + ")";
        tmp = indent + nam + " = " + assn + ";" + tag + "\n";
        ans += tmp;
        tmp = indent + "{\n";
        ans += tmp;
        tmp = indent + indent + "wycc_obj *" + anam + " = (wycc_obj*)0;\n";
        ans += tmp;
        idx = 0;
        for (Constant itm:ct.values) {
          tmp = writeMyConstant(itm, anam, "", deep+1);
          ans += indent + tmp;
          tmp = indent + indent + "wycc_update_list(" + nam + ", " + anam + "," + idx + ");\n";
          ans += tmp;
          tmp = indent + indent + "wycc_deref_box(Xc, 0);\n";
          ans += tmp;
          idx += 1;
        }
        tmp = indent + "}\n";
        ans += tmp;
        return ans;

      } else if (typ instanceof Type.Null) {
        assn = "wycc_box_null()";
      } else if (typ instanceof Type.Real) {
        if (floatFlag) {
          assn = "wycc_box_float((long double)" + rval + ")";
        } else {
          assn = "wycc_box_ratio(\"" + rval + "\")";
        }
      } else if (typ instanceof Type.FunctionOrMethod) {
        Constant.Lambda fom = (Constant.Lambda) val;
        bodyAddLineNL"// HELP! needed in const for FOM name: '" + fom.name.name() + "'"  );
        dtyp = writeDenseType(typ);
        bodyAddLineNL"// HELP! needed in const for FOM dtyp: '" + dtyp + "'"  );
        tok = lookupNumFOMname(fom.name.name(), typ);
        assn = "fom_handle_reg[" + tok + "]";
      } else {
        bodyAddLineNL"// HELP! needed in const for value type '" + typ + "'"  );
        return null;
      }
      //this.addDecl(targ, "wycc_obj*");
      //writeClearTarget(targ);
      // assn += "(" + rval + ")";
      // this.addDecl(targ, "wycc_obj*");
      //if (assn != null) {
        tmp = indent + nam + " = " + assn + ";" + tag + "\n";
        //this.mbodyAddLine(tmp);
      //} else {
        //tmp = "";
      //}
      return tmp;
    }

    private int intFromByte(String txt){
      int ans = 0;
      int idx = 0;
      char chr;

      while (idx<8){
        chr = txt.charAt(idx);
        if (chr == 'b') {
          return ans;
        }
        ans *= 2;
        if (chr == '1') {
          ans += 1;
        }

        idx += 1;
      }
      return ans;
    }

    // A register is about to be clobbered; dereference any object.
    // negative register numbers are our own constructs, very local, not ref counted.
    public void writeClearTarget(int target){
      String nam = "";
      Integer tgt = target;


      if (declsU.contains(tgt)) {
        if (target < 0) {
          //nam = "XN" + (-target);
        } else {
          nam = "X" + target;
          this.mbodyAddLineTINLnam + " = wycc_deref_box(" + nam + ", 0);"  );
        }
      }
      declsU.add(tgt);
      return;
    }


    // convert a wyil comparator code to a wycc constant
    private String mapComparator(Codes.Comparator opr, boolean flg) {

      if (opr == Codes.Comparator.IN) {
        return "Wyil_Relation_Mo";
      } else if (opr == Codes.Comparator.EQ){
        return "Wyil_Relation_Eq";
      } else if (opr == Codes.Comparator.GT){
        return "Wyil_Relation_Gt";
      } else if (opr == Codes.Comparator.GTEQ){
        return "Wyil_Relation_Ge";
      } else if (opr == Codes.Comparator.LT){
        return "Wyil_Relation_Lt";
      } else if (opr == Codes.Comparator.LTEQ){
        return "Wyil_Relation_Le";
      } else if (opr == Codes.Comparator.NEQ){
        return "Wyil_Relation_Ne";
      }
      if (flg) {
        return null;
      }
      if (opr == Codes.Comparator.SUBSET){
        return "Wyil_Relation_Ss";
      } else if (opr == Codes.Comparator.SUBSETEQ){
        return "Wyil_Relation_Se";

      }
      return null;
    }
  }

  private String writeDenseType(Type ntyp) {

    if (ntyp instanceof Type.Void) {
      return "v";
    }
    if (ntyp instanceof Type.Compound) {
      Type.Compound compound = (Type.Compound) ntyp;
      Automaton automaton = compound.automaton;

      return writeTypeCompound(automaton);
    }
    if (ntyp instanceof Type.Nominal) {
      return "N";              // **** need to fix; had nid
    }
    if (ntyp instanceof Type.Strung) {
      return "s";
    }
    if (ntyp instanceof Type.Real) {
      return "r";
    }
    if (ntyp instanceof Type.Int) {
      return "i";
    }
    if (ntyp instanceof Type.Byte) {
      return "d";
    }
    if (ntyp instanceof Type.Char) {
      return "c";
    }
    if (ntyp instanceof Type.Bool) {
      return "b";
    }
    if (ntyp instanceof Type.Meta) {
      return "m";
    }
    if (ntyp instanceof Type.Void) {
      return "v";
    }
    if (ntyp instanceof Type.Any) {
      return "a";
    }
    if (ntyp instanceof Type.Null) {
      return "n";
    }

    return "&";
  }
  private String writeTypeCompound(Automaton automaton) {

    BitSet headers = new BitSet(automaton.size());
    BitSet visited = new BitSet(automaton.size());
    BitSet onStack = new BitSet(automaton.size());
    findHeaders(0, visited, onStack, headers, automaton);
    visited.clear();
    String[] titles = new String[automaton.size()];
    int count = 0;
    for (int i = 0; i != automaton.size(); ++i) {
      if (headers.get(i)) {
        titles[i] = headerTitle(count++);
      }
    }
    return writeTypeCompound(0, visited, titles, automaton);
  }

  private void findHeaders(int index, BitSet visited,
        BitSet onStack, BitSet headers, Automaton automaton) {
    if(visited.get(index)) {
        // node already visited
      if(onStack.get(index)) {
        headers.set(index);
      }
      return;
    }
    onStack.set(index);
    visited.set(index);
    State state = automaton.states[index];
    for(int child : state.children) {
      findHeaders(child,visited,onStack,headers,automaton);
    }
    onStack.set(index,false);
  }
  private char[] headers = { 'X','Y','Z','U','V','W','L','M','N','O','P','Q','R','S','T'};
  private String headerTitle(int count) {
    String r = Character.toString(headers[count%headers.length]);
    int n = count / headers.length;
    if(n > 0) {
      return r + n;
    } else {
      return r;
    }
  }

  private String writeTypeCompound(int index, BitSet visited,
      String[] headers, Automaton automaton) {
    String sep = "";
    String middle;

    if (visited.get(index)) {
      // node already visited
      return headers[index];
    } else if(headers[index] != null) {
      visited.set(index);
    }
    String header = headers[index];
    State state = automaton.states[index];

    switch (state.kind) {
    case Type.K_VOID:
      return "v";
    case Type.K_ANY:
      return "a";
    case Type.K_NULL:
      return "n";
    case Type.K_BOOL:
      return "b";
    case Type.K_BYTE:
      return "d";
    case Type.K_CHAR:
      return "c";
    case Type.K_INT:
      return "i";
    case Type.K_RATIONAL:
      return "r";
    case Type.K_STRING:
      return "s";
    case Type.K_NOMINAL:
      System.err.println("milestone 5.3.C1+");
      return "[$]";
    };
    int[] children = state.children;

    switch (state.kind) {
    case Type.K_SET: {
      middle = "[*";
      boolean nonEmpty = (Boolean) state.data;
      if (nonEmpty) {
        middle +=  "+";
      }
      // *** need to check that there is exactly 1 child
      break;
    }
    case Type.K_LIST: {
      middle = "[#";
      boolean nonEmpty = (Boolean) state.data;
      if (nonEmpty) {
        middle +=  "+";
      }
      // *** need to check that there is exactly 1 child
      break;
    }
    case Type.K_REFERENCE:
      middle = "[.";
      // *** need to check that there is exactly 1 child
      break;
    case Type.K_NEGATION: {
      middle = "[!";
      // *** need to check that there is exactly 1 child
      break;
    }
    case Type.K_MAP: {
      // binary node
      middle = "[@";
      // *** need to check that there are exactly 2 children
      break;
    }
    case Type.K_UNION: {
      middle = "[|";
      break;
    }
    case Type.K_TUPLE: {
      middle = "[=";
      break;
    }
    case Type.K_RECORD: {
      // labeled nary node
      Record.State rs = (Record.State) state.data;
      if (rs.isOpen) {
        middle = "[%";
      }else {
        middle = "[{";
      }
      //middle = "[{";
      middle += writeTypeFieldNames(rs);
      middle +=  "}";
      break;
    }
    case Type.K_METHOD: {
      middle = "[:";
      break;
    }
    case Type.K_FUNCTION: {
      middle = "[^";
      break;
    }
    default:
      throw new IllegalArgumentException("Invalid type encountered (kind: " + state.kind +")");
    }
    sep = "";
    for (int i = 0; i != children.length; ++i) {
      middle+= sep;
      middle += writeTypeCompound(children[i], visited, headers, automaton);
      sep = ",";
    }

    middle +=  "]";
    // Finally, check whether this is a header node, or not. If it is a
    // header then we need to insert the recursive type.

    if(header != null) {
      // The following case is interesting. Basically, we'll never revisit
      // a header. Therefore, if we have multiple edges landing on a
      // header we must update the header string to represent the full
      // type reachable from the header.
      //String r = header + "<" + middle + ">";
      String r = "[<" + header + "}" + middle + "]";
      //headers[index] = r;
      return r;
    }
    return middle;

  }

  private String writeTypeFieldNames(wyil.lang.Type.Record.State fields) {
    String ans= "";
    String sep = "";

    for (int i = 0; i != fields.size(); ++i) {
      ans += sep;
      ans += fields.get(i);
      sep = ",";
    }
    return ans;
  }

  public ArrayList<String> getFieldNames(Type.Record record) {
      ArrayList<String> fields = new ArrayList<String>(record.keys());
      Collections.sort(fields);
      return fields;
  }

  public String safeString2(String was){
    return safeString(was, 0, was.length(), false);
  }

  public String safeString1(String was){
    return safeString(was, 1, was.length()-1, true);
  }

  public String safeString(String was){
    return safeString(was, 0, was.length(), true);
  }
  public String safeString(String was, int lo, int hi, boolean flg){
    String ans = "";
    int at = lo;
    char ch;

    while (at < hi) {
      ch = was.charAt(at);
      if (ch == '\\') {
        ans += "\\\\";
      } else if (ch == '\n') {
        ans += "\\n";
      } else if ((ch == '"') && flg) {
        ans += "\\\"";
      } else {
        ans += ch;
      }
      at++;
    }

    return ans;
  }

}
TOP

Related Classes of wycc.lang.Wyil2CBuilder$Method

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.