scm.Procedure Maven / Gradle / Ivy
package scm;
// This is the (usual) compound procedure
// object
/**
* This is a container class that is overidden
* by primitives. It can be generated through
* @see jas.Lambda procedures.
*/
class Procedure implements Obj
{
Cell body; // the seq of expressions constituting
// the body of the procedure
Cell formals; // the arglist expected by the procedure
Env procenv; // env in which the proc was created
Env extendargs(Cell args, Env f)
throws Exception
{
Cell params = null;
Cell tail = null;
while (args != null)
{
Obj now = args.car;
if (now != null)
{ now = now.eval(f); } // eval args in context of old expression
if (tail != null)
{
tail.cdr = new Cell(now, null);
tail = tail.cdr;
}
else
{
params = new Cell(now, params);
tail = params;
}
args = args.cdr;
}
// make new frame, with appropriate
// bindings. The enclosing frame
// is the env in which the procedure
// was created.
return (procenv.extendenv(formals, params));
}
Obj apply(Cell args, Env f)
throws Exception
{
Env newEnv = extendargs(args, f);
Cell expr = body;
Obj ret = null;
// eval body with new bindings
while (expr != null)
{
ret = expr.car;
if (ret != null)
{ ret = ret.eval(newEnv); }
expr = expr.cdr;
}
return (ret);
}
public Obj eval(Env e)
{ throw new SchemeError("Cant eval procedures directly"); }
public String toString()
{
return (" " + body);
}
}
// do a few primitives here
/**
* Add two integers
* (+ int1 int2)
*/
class Plus extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Obj l1 = args.car.eval(f);
Obj l2 = args.cdr.car.eval(f);
return (new Selfrep(((Selfrep)l1).num + ((Selfrep)l2).num));
}
public String toString()
{
return ("<#plus#>");
}
}
/**
* Subtract integers
* (- int1 int2)
*/
class Minus extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Obj l1 = args.car.eval(f);
Obj l2 = args.cdr.car.eval(f);
return (new Selfrep(((Selfrep)l1).num - ((Selfrep)l2).num));
}
public String toString()
{
return ("<#minus#>");
}
}
/**
* Multiply integers
* (* int1 int2)
*/
class Mult extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Obj l1 = args.car.eval(f);
Obj l2 = args.cdr.car.eval(f);
return (new Selfrep(((Selfrep)l1).num * ((Selfrep)l2).num));
}
public String toString()
{
return ("<#mult#>");
}
}
/**
* divide integers
* (/ int1 int2)
*/
class Div extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Obj l1 = args.car.eval(f);
Obj l2 = args.cdr.car.eval(f);
return (new Selfrep(((Selfrep)l1).num / ((Selfrep)l2).num));
}
public String toString()
{
return ("<#div#>");
}
}
/**
* Bitwise or of integers
* (| int1 int2)
*/
class Or extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Obj l1 = args.car.eval(f);
Obj l2 = args.cdr.car.eval(f);
return (new Selfrep
((int)(Math.round(((Selfrep)l1).num)) |
(int)(Math.round(((Selfrep)l2).num))));
}
public String toString()
{
return ("<#or#>");
}
}
/**
* Yup. just as it says.
* (car (quote (a b)))
* => a
*
*/
class Car extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Cell tmp = (Cell) args.car.eval(f);
return (tmp.car);
}
public String toString()
{ return ("<#car#>"); }
}
/**
* More lispisms.
* (cdr (quote (a b)))
* => (b)
*
*/
class Cdr extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Cell tmp = (Cell) args.car.eval(f);
return (tmp.cdr);
}
public String toString()
{ return ("<#cdr#>"); }
}
/**
* Generate new list
* (cons (quote a) (quote (b c))) => (a b c)
*/
class Cons extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Obj ncar = args.car.eval(f);
Obj ncdr = args.cdr.car.eval(f);
return (new Cell(ncar, (Cell) ncdr));
}
public String toString()
{ return ("<#cons#>"); }
}
/**
* Prevent from evaluation.
* (quote a) => a
*/
class Quote extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
if (args == null)
{ throw new SchemeError("null args to Quote"); }
return args.car;
}
public String toString()
{ return ("<#Quote#>"); }
}
/**
* bind a value to a symbol.
*
* (define some-new-symbol "some thing") => "some thing"
* some-new-symbol => "some thing"
*/
class Define extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Symbol v; // (symbol value)
if (args == null)
{ throw new SchemeError("null args to define"); }
if (args.car instanceof Symbol)
{ v = (Symbol) args.car; }
else
{ throw new SchemeError("bad argtype to define" + args.car); }
if (v == null)
{ throw new SchemeError("null symbol value"); }
Cell val = args.cdr;
if (val == null)
{ throw new SchemeError("not enough args to define"); }
Obj ret = val.car;
if (ret != null)
{ ret = ret.eval(f); }
f.definevar(v, ret);
return ret;
}
public String toString()
{ return ("<#define#>"); }
}
/**
* reset a value to a symbol.
*
* (set! some-old-symbol "xyz")
*/
class Setvar extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Symbol v; // (symbol value)
if (args == null)
{ throw new SchemeError("null args to define"); }
if (args.car instanceof Symbol)
{ v = (Symbol) args.car; }
else
{ throw new SchemeError("bad argtype to set!" + args.car); }
if (v == null)
{ throw new SchemeError("null symbol value"); }
Cell val = args.cdr;
if (val == null)
{ throw new SchemeError("not enough args to set!"); }
Obj ret = val.car;
if (ret != null)
{ ret = ret.eval(f); }
f.setvar(v, ret);
return ret;
}
public String toString()
{ return ("<#set!#>"); }
}
/**
* (cond (condition body) (condition body)...)
*/
class Cond extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Cell t = args;
while (t != null)
{
// examine condition part
if (t.car == null)
{ throw new SchemeError("null clause for cond"); }
Obj clause = t.car;
if (!(clause instanceof Cell))
{ throw new SchemeError("need a condition body for cond clause"); }
Obj result = (((Cell)clause).car);
if (result != null) { result = result.eval(f); }
if (result == null)
{ t = t.cdr; continue; }
// Got a non nill, so do body and
// return.
Obj body = (((Cell)clause).cdr).car;
return (body.eval(f));
}
return null;
}
public String toString()
{ return ("<#cond#>"); }
}
/**
* (num? thing)
*/
class NumP extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
if (args == null) return null;
Obj target = args.car;
if (target != null) target = target.eval(f);
if (target == null) return null;
if ((target instanceof Selfrep) &&
(((Selfrep)target).val == null))
return target;
return null;
}
public String toString()
{ return ("<#num?#>"); }
}
/**
* <
*/
class LessP extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
if (args == null)
{ throw new SchemeError("< expects a pair of arguments"); }
Obj target1 = args.car;
if (target1 != null) target1 = target1.eval(f);
args = args.cdr;
Obj target2 = args.car;
if (target2 != null) target2 = target2.eval(f);
if ((target1 == null) ||
(target2 == null))
{ throw new SchemeError("< expects a pair of arguments"); }
if (!(target1 instanceof Selfrep) ||
!(target2 instanceof Selfrep))
{ throw new SchemeError("< expects a pair of numbers as args"); }
if ((((Selfrep)target1).num) < (((Selfrep)target2).num))
{ return target1; }
return null;
}
public String toString()
{ return ("<#<#>"); }
}
/**
* >
*/
class MoreP extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
if (args == null)
{ throw new SchemeError("> expects a pair of arguments"); }
Obj target1 = args.car;
if (target1 != null) target1 = target1.eval(f);
args = args.cdr;
Obj target2 = args.car;
if (target2 != null) target2 = target2.eval(f);
if ((target1 == null) ||
(target2 == null))
{ throw new SchemeError("> expects a pair of arguments"); }
if (!(target1 instanceof Selfrep) ||
!(target2 instanceof Selfrep))
{ throw new SchemeError("> expects a pair of numbers as args"); }
if ((((Selfrep)target1).num) > (((Selfrep)target2).num))
{ return target1; }
return null;
}
public String toString()
{ return ("<#>#>"); }
}
/**
* (eq? obj1 obj2)
*/
class EqP extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
if (args == null) return null;
Obj target1 = args.car;
if (target1 != null) target1 = target1.eval(f);
args = args.cdr;
Obj target2 = args.car;
if (target2 != null) target2 = target2.eval(f);
if ((target1 == null) &&
(target2 == null)) return (new Selfrep(1));
if ((target1 == null) ||
(target2 == null))
{ return null; }
if (target1 == target2)
{
return (target1);
}
if ((target1 instanceof Selfrep) &&
(target2 instanceof Selfrep))
{
if ((((Selfrep)target1).val) == null)
{
if ((((Selfrep)target1).num) == (((Selfrep)target2).num))
{ return new Selfrep(1); }
}
else
{
if ((((Selfrep)target1).val).equals((((Selfrep)target2).val)))
{ return new Selfrep(1); }
}
}
return null;
}
public String toString()
{ return ("<#eq?#>"); }
}
/**
* (string? thing)
*/
class StringP extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
if (args == null) return null;
Obj target = args.car;
if (target != null) target = target.eval(f);
if (target == null) return null;
if ((target instanceof Selfrep) &&
(((Selfrep)target).val != null))
return target;
return null;
}
public String toString()
{ return ("<#string?#>"); }
}
/**
* (progn body1 body2 ...)
*/
class Progn extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Cell t = args;
Obj result = null;
while (t != null)
{
if (t.car == null)
{
result = null;
}
else
{
result = t.car.eval(f);
}
t = t.cdr;
}
return result;
}
public String toString()
{ return ("<#progn#>"); }
}
/**
* (mapcar function (args1 args2 ...))
*/
class Mapcar extends Procedure implements Obj
{
Obj apply(Cell args, Env f)
throws Exception
{
Obj ftmp = args.car;
if (ftmp != null) ftmp = ftmp.eval(f);
if (ftmp == null)
{ throw new SchemeError("null function for mapcar"); }
if (!(ftmp instanceof Procedure))
{ throw new SchemeError("expected a procedure for mapcar"); }
Procedure fn = (Procedure) ftmp;
Cell t = (Cell)((args.cdr.car).eval(f));
Cell res = null;
Cell tail = null;
while (t != null)
{
if (tail == null)
{
res =
new Cell
(fn.apply
(new Cell((t.car), null), f),
null);
tail = res;
}
else
{
tail.cdr =
new Cell
(fn.apply
(new Cell((t.car), null), f),
null);
}
t = t.cdr;
}
return res;
}
}