LispPrimitive.java :  » Scripting » Jatha » org » jatha » compile » Java Open Source

Java Open Source » Scripting » Jatha 
Jatha » org » jatha » compile » LispPrimitive.java
/*
 * Jatha - a Common LISP-compatible LISP library in Java.
 * Copyright (C) 1997-2005 Micheal Scott Hewett
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 * For further information, please contact Micheal Hewett at
 *   hewett@cs.stanford.edu
 *
 */

package org.jatha.compile;

import java.io.*;

import org.jatha.Jatha;
import org.jatha.dynatype.*;
import org.jatha.machine.*;


// @date    Fri Jan 31 17:31:40 1997
/**
 * The LispPrimitive class makes the
 * transition from LISP code to Java code.  There
 * is a LispPrimitive for each builtin LISP function.
 *
 *  1) Create the new LISP primitive as an instance of
 *     this class.  It must have several methods as
 *     described below.
 *  2) Register the new primitive with the compiler.
 *
 * Each primitive must implement one method:
 *
 *   public void Execute(SECDMachine machine)
 *
 * @see org.jatha.compile.LispCompiler
 * @author  Micheal S. Hewett    hewett@cs.stanford.edu
 */
public abstract class LispPrimitive extends StandardLispValue
{
  // Fields
  protected long minNumberOfArgs;
  protected long maxNumberOfArgs;

  /**
   * Set inlineP to true if the function effectively evaluates itself
   * simply by compiling its argument list.  This is true for
   * functions like LIST, LIST*, and QUOTE.  This inhibits putting
   * the function call on the stack, thus saving a millisecond of time.
   *
   * @see org.jatha.compile.LispPrimitive
   */
  public boolean inlineP = false;


  /**
   * the <tt>functionName</tt> is part of the string that
   * gets printed when the instruction appears in a printed list.
   */
  protected String    functionName;
  protected LispValue functionNameSymbol;


  /**
   * The output of this function is printed when the
   * instruction needs to be printed.
   */
  public String toString()
  {
    return "#<function " + functionName + " " + parameterCountString() + ">";
  }

  public boolean basic_functionp()
  {
    return true;
  }


/* ------------------  PRINT FUNCTION   ------------------------------ */

  /**
   * printCode prints a list of compiled code in a nice manner.
   * Calls the 'grindef' function on each primitive.
   * Grindef is an historical LISP function not found in Common LISP.
   *
   * Example:
   * <pre>
   *   printCode(compiled-function, 2);
   * </pre>
   * @see LispPrimitive
   * @param code the code to be printed, with indent 2.
   */
  public void printCode(LispValue code)
  {
    printCode(code, 2);
  }

  public void printCode(LispValue code, int indentAmount)
  {
    while (code != f_lisp.NIL)
    {
      code = ((LispPrimitive)(code.second())).grindef(code, indentAmount);
    }
  }


  public LispValue grindef(LispValue code, int indentAmount)
  {
    indent(indentAmount);
    System.out.print(functionName);
    f_lisp.NEWLINE.internal_princ(System.out);

    return code.cdr();
  }


  public void indent(int amount)
  {
    for (int i=0; i<amount; ++i)
      f_lisp.SPACE.internal_princ(System.out);
  }


/* ------------------ CONSTRUCTORS    ------------------------------ */

  /**
   * The constructor for the LispPrimitive class.
   * @see org.jatha.compile.LispCompiler
   * @param fnName The LISP function name being implemented.
   * @param minArgs      The minimum number of Arguments to this function.
   * @param maxArgs      The maximum number of Arguments to this function.
   */
  public LispPrimitive(Jatha lisp, String fnName, long minArgs, long maxArgs)
  {
    super(lisp);
    minNumberOfArgs     = minArgs;
    maxNumberOfArgs     = maxArgs;
    functionName        = fnName;
    functionNameSymbol  = new StandardLispSymbol(f_lisp, fnName);
  }

  public LispPrimitive(Jatha lisp, String fnName, long minArgs)
  {
    super(lisp);
    minNumberOfArgs     = minArgs;
    maxNumberOfArgs     = minArgs;  // default value
    functionName        = fnName;
    functionNameSymbol  = new StandardLispSymbol(f_lisp, fnName);
  }

  public LispPrimitive(Jatha lisp, String fnName) // Abstract machine ops have no args
  {
    super(lisp);
    minNumberOfArgs     = 0;         // default value
    maxNumberOfArgs     = 0;         // default value
    functionName        = fnName;
    functionNameSymbol  = new StandardLispSymbol(f_lisp, fnName);
  }

  public String    LispFunctionNameString() { return functionName; }
  public LispValue LispFunctionNameSymbol() { return functionNameSymbol; }

  public void internal_princ(PrintStream os) { os.print(toString()); }
  public void internal_prin1(PrintStream os) { os.print(toString()); }
  public void internal_print(PrintStream os) { os.print(toString()); }

  /**
   * This method returns <code>true</code> if
   * the list of arguments satisfies the length restrictions
   * posed by the function, and <code>false</code> otherwise.
   * @see LispPrimitive
   * @param numberOfArguments  usually the result of args.length()
   * @return boolean
   */
  boolean validArgumentLength(LispValue numberOfArguments)
  {
    long numArgs = ((LispInteger)numberOfArguments).getLongValue();

    return ((minNumberOfArgs <= numArgs)
      && (numArgs <= maxNumberOfArgs));
  }


  /**
   * This method returns <code>true</code> if
   * the list of arguments satisfies the length and format restrictions
   * posed by the function, and <code>false</code> otherwise.
   * It calls <code>validArgumentLength</code>, so the programmer
   * doesn't need to call it.
   * <p>
   * This method is called by the compiler.
   *
   * @see LispPrimitive
   * @see LispCompiler
   * @param args the list of arguments.
   * @return boolean
   */
  public boolean validArgumentList(LispValue args)
  {
    // ?? Need to check keywords, etc. here.
    return (validArgumentLength(args.length()));
  }

  /**
   * This method returns a Java string denoting the length of
   * the expected argument list in some readable form.
   * <p>
   * This method is called by the compiler when an argument count
   * exception is generated.
   *
   * @see LispPrimitive
   * @see LispCompiler
   * @return a Java string denoting the length of the expected argument list.
   */
  public String parameterCountString()
  {
    String result = Long.toString(minNumberOfArgs);

    if (maxNumberOfArgs == Long.MAX_VALUE)
      result += "...";
    else if (maxNumberOfArgs != minNumberOfArgs)
      result += " " + maxNumberOfArgs;

    return result;
  }


  /**
   * Execute performs the operation using the abstract machine
   * registers.  Arguments are found on the S register stack,
   * in reverse order.  UNLIMITED argument lists are collected
   * into a list which is the top element on the stack.
   *
   * The implementation should pop an appropriate number of arguments
   * from the stack, perform a computation, then push a result
   * back on the S stack.  The instruction should then be popped from
   * the C (code) register.  A LispValueFactory objects is available
   * in the static variable <code>LispValueFactory</code>.
   *
   * Example implementations:
   * <pre>
   *   <code>FIRST</code>
   *   class FirstPrimitive extends LispPrimitive
   *   {
   *     public First()
   *     {
   *       super("FIRST", 1);   // 1 argument
   *     }
   *
   *     public void Execute(SECDMachine machine)
   *     {
   *       LispValue arg = machine.S.pop();
   *
   *       machine.S.push(my_first(arg));
   *       machine.C.pop();
   *     }
   *   }
   * </pre>
   *
   * A multi-argument function must pop the arguments in reverse order.
   * <pre>
   *     public void Execute(SECDMachine machine)
   *     {
   *       LispValue arg2 = machine.S.pop();
   *       LispValue arg1 = machine.S.pop();
   *
   *       machine.S.push(my_new_function(arg1, arg2));
   *       machine.C.pop();
   *     }
   *   }
   * </pre>
   *
   * To register the new primitive, call:
   * <pre>
   *    Jatha.COMPILER.Register(new FirstPrimitive());
   * </pre>
   * @see org.jatha.compile.LispCompiler
   * @param machine   The abstract machine instance.
   */
  public abstract void Execute(SECDMachine machine)
    throws CompilerException;


   // Called only on Builtin Functions
   LispValue BuiltinFunctionCode(LispValue fn)
   {
     return ((LispFunction)fn).getCode().second();
   }


  /**
   * The CompileArgs method turns the arguments of the function call
   * into SECD abstract machine code.  Most functions won't need to
   * override the default code generation, but ones that do funny
   * things with argument lists will need to.
   *
   * @see LispCompiler
   * @param compiler
   * @param args
   * @param valueList
   * @param code
   * @return LispValue The code generated and cons'ed onto the front of the incoming code.
   */
  public LispValue CompileArgs(LispCompiler compiler, SECDMachine machine, LispValue args,
             LispValue valueList, LispValue code)
    throws CompilerException
  {
    return  compiler.compileArgsLeftToRight(args, valueList, code);
  }

  // Todo: PROGN compiles right-to-left, but executes left-to-right, thus recursive calls are not correctly compiled
  

  public LispValue CompileArgs(LispCompiler compiler, SECDMachine machine, LispValue function,
             LispValue args, LispValue valueList, LispValue code)
    throws CompilerException
  {
    if (this.inlineP)
      return  CompileArgs(compiler, machine, args, valueList, code);
    else
    {
      if (! (function instanceof LispFunction))
        function = function.symbol_function();

      LispValue fncode = ((LispFunction)function).getCode().second();

      return  CompileArgs(compiler, machine, args, valueList, f_lisp.makeCons(fncode, code));
    }
  }


}


java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.