/* * Copyright (c) 1999-2003, Gene Cooperman; Rights to copy and distribute * for non-commercial purposes only are freely granted, but only as * long as this copyright statement remains. No warranty is implied. */ import java.util.HashMap; // singleton class class ObArray extends HashMap { private static final ObArray INSTANCE = new ObArray(); static ObArray getInstance() { return INSTANCE; } private ObArray() { super(); }; Symbol add(Object x) { if (x instanceof Symbol) { Symbol symbol = (Symbol)x; super.put(symbol.name, symbol); return symbol; } else throw new SchemeError("Can't add non-symbol to ObArray"); } Symbol get(String str) { return (Symbol)super.get(str); } Symbol getOrAdd(String str) { Symbol tmp = (Symbol)super.get(str); if (tmp == null) return add(new Symbol(str)); else return tmp; } boolean contains(String str) { return this.containsKey(str); } } // In Java, an interface forces its methods to be public, even // though we'd prefer package-private. // We want `interface SchemeList' and SchemeObject to have common // supertype. Otherwise, SchemeNil can be either, and Java // complains about ambiguous method calls for Cons constructor, etc. // --- Yuck! interface SchemeObject { // So any Scheme Interface is SchemeObject public SchemeObject eval() ; public SchemeObject evala( SchemeObject arg ) ; public String toString(); // override these if a SchemeList public SchemeObject car(); public SchemeObject cdr(); public int length(); public SchemeObject nth( int pos ); public SchemeObject setNth( int pos, SchemeObject value ); public SchemeObject setCar( SchemeObject obj ); public SchemeObject setCdr( SchemeObject obj ); } abstract class AbstractSchemeObject implements SchemeObject { abstract public SchemeObject eval() ; public SchemeObject evala(SchemeObject arg) { throw new SchemeWrongNumberOfArgs(); }; public abstract String toString(); // override these if a SchemeList public SchemeObject car() { throw new SchemeArgumentNotList("car", this); } public SchemeObject cdr() { throw new SchemeArgumentNotList("cdr", this); } public int length() { throw new SchemeArgumentNotList("length", this); } public SchemeObject nth( int pos ) { throw new SchemeArgumentNotList("list-ref", this); } public SchemeObject setNth( int pos, SchemeObject value ) { throw new SchemeArgumentNotList("setNth", this); } public SchemeObject setCar( SchemeObject obj ) { throw new SchemeArgumentNotList("setCar", this); } public SchemeObject setCdr( SchemeObject obj ) { throw new SchemeArgumentNotList("setCdr", this); } } class Fixnum extends AbstractSchemeObject { final int value; Fixnum(int x) { this.value = x; } Fixnum(Integer x) { this.value = x.intValue(); } public SchemeObject eval() { return this; } final public String toString() { return Integer.toString(this.value); }; } class Symbol extends AbstractSchemeObject { protected String name; // delay initialization of name, since it's final protected SchemeObject value = null; static final SchemeNil schemeNil = SchemeNil.getInstance(); static final Symbol schemeTrue = new Symbol("#t", null); static final Symbol schemeFalse = new Symbol("#f", null); static { SchemeInterpreter.obArray.add( Symbol.schemeTrue ); Symbol.schemeTrue.setValue( Symbol.schemeTrue ); SchemeInterpreter.obArray.add( Symbol.schemeFalse ); Symbol.schemeFalse.setValue( Symbol.schemeFalse ); } // Note that 'new Symbol' is called by ObArray.getOrAdd(String) Symbol(String name) { this.name = name; } Symbol(String name, SchemeObject value) { this.name = name; this.value = value; } Symbol(SchemeFunction fnc) { this( fnc.toString(), fnc ); } public SchemeObject eval() { if ( this.value == null ) throw new SchemeUnboundVariable( this ); return this.value; } SchemeObject getValue() { return this.value; } SchemeObject setValue(SchemeObject value) {this.value = value; return value;} final public String toString() { return name; }; } class LambdaSymbol extends AbstractSchemeObject{ protected String name = "LambdaSymbol"; protected int numArgs = -1; protected SchemeObject arg = null; protected SchemeObject value = null; LambdaSymbol(String name) { this.name = name; } LambdaSymbol(SchemeObject arg, SchemeObject value) { if (arg == Symbol.schemeNil) numArgs = 0; else this.numArgs = arg.length(); this.arg = arg; this.value = value; } LambdaSymbol(String name, SchemeObject arg, SchemeObject value) { this.name = name; this.arg = arg; this.value = value; } LambdaSymbol (SchemeFunction fnc) { this( fnc.toString()); } public SchemeObject eval() { SchemeObject returnval = null; int i = 0; while(i < value.length()) { returnval = value.nth(i).eval(); i++; } return returnval; } public SchemeObject evala(SchemeObject args) { int i = 0, i2 = 0; while(i < arg.length()) { arg.setNth(i, args.nth(i).eval()); i++; } return value.car().eval(); } SchemeObject getValue() { return this.value; } SchemeObject getArg() { return this.arg; } SchemeObject setValue(SchemeObject value) { this.value = value; return value; } SchemeObject setArg(SchemeObject arg) { this.arg = arg; return arg; } final public String toString() { return name; }; } /** * Used as type; Cons and SchemeNil are subtypes of SchemeList. */ interface SchemeList extends SchemeObject { } // singleton class class SchemeNil extends Symbol implements SchemeList { SchemeNil(String name, SchemeObject value) { super(name, value); this.value = this; } static final SchemeNil INSTANCE = new SchemeNil( "()", null ); static final SchemeNil getInstance() { return SchemeNil.INSTANCE; } } class Cons extends AbstractSchemeObject implements SchemeList { SchemeObject car = null; SchemeObject cdr = null; Cons( SchemeObject car, SchemeObject cdr ) { this.car = car; this.cdr = cdr; } public SchemeObject car() { return this.car; } public SchemeObject cdr() { return this.cdr; } public int length() { if ( this.cdr == Symbol.schemeNil ) return 1; else return 1 + this.cdr.length(); } public SchemeObject nth( int pos ) { if ( pos < 0 ) throw new SchemeError("list-ref called with negative integer"); if ( pos == 0 ) return this.car(); else return this.cdr().nth( pos - 1 ); } public SchemeObject setNth( int pos, SchemeObject value ) { if ( pos < 0 ) throw new SchemeError("list-set! called with negative integer"); if ( pos == 0 ) return this.setCar( value ); else if ( this.cdr() instanceof SchemeList ) return ((SchemeList)this.cdr()).setNth( pos - 1, value ); else throw new SchemeArgumentNotList("list-set!", this); } public SchemeObject eval() { SchemeObject fncPos = this.car; SchemeObject fncArg = this.cdr; SchemeObject tmp = fncPos.eval(); if ( ! (tmp instanceof SchemeFunction || tmp instanceof LambdaSymbol) ) throw new SchemeError("Function position of " + this + " not a function."); else if (tmp instanceof LambdaSymbol){ return tmp.evala(fncArg); } else{ SchemeFunction fnc = (SchemeFunction)tmp; SchemeList args = (SchemeList)this.cdr(); return fnc.callFunction( args ); } } public SchemeObject setCar( SchemeObject obj ) { this.car = obj; return obj; } public SchemeObject setCdr( SchemeObject obj ) { this.cdr = obj; return obj; } final public String toString() { StringBuffer str = new StringBuffer("("); Cons expr = this; while ( expr.cdr instanceof Cons ) { str.append( expr.car.toString() ); str.append( " " ); expr = (Cons)expr.cdr; } str.append( expr.car.toString() ); if ( expr.cdr != Symbol.schemeNil ) { str.append( " . " ); str.append( expr.toString() ); } str.append(")"); return str.toString(); } } class SchemeUnboundVariable extends SchemeError { SchemeUnboundVariable() { super(); } SchemeUnboundVariable( Symbol symb ) { super( symb.toString() ); } SchemeUnboundVariable( LambdaSymbol symb ) { super( symb.toString() ); } } class SchemeArgumentNotList extends SchemeError { SchemeArgumentNotList() { super(); } SchemeArgumentNotList( String fnc, SchemeObject arg ) { super( fnc + ": " + arg.toString() ); } }