466 lines
11 KiB
Java
466 lines
11 KiB
Java
// -*- java -*-
|
|
|
|
/*
|
|
* General Notes:
|
|
*
|
|
* 1) we need some sort of error reporting mechanism. Full exceptions
|
|
* would be nice, but even a MzScheme-like error primitive would be
|
|
* sufficient for now.
|
|
* 2) We desperately need some sort of polymorphism -- even Java 1.4
|
|
* style would be an improvement!
|
|
* 3) What did we decide w.r.t typing _this_ again?
|
|
*/
|
|
|
|
/*
|
|
* Assumed built-in types, operations
|
|
* OCaml-style extensional equality
|
|
* null? (or, more generally, intensional equality)
|
|
* String (changed to str)
|
|
* int
|
|
* boolean (changed to bool)
|
|
*/
|
|
|
|
/*
|
|
**********************************************************************
|
|
* Boxing: str -> String
|
|
**********************************************************************/
|
|
|
|
type String {
|
|
str val;
|
|
}
|
|
|
|
/*
|
|
**********************************************************************
|
|
* Infrastructure: sets, lists, etc.
|
|
**********************************************************************/
|
|
|
|
type StringList
|
|
{
|
|
bool contains(String s);
|
|
|
|
// Returns copy of this list with first occurrence of s removed.
|
|
// If no s, returns copy of this list.
|
|
StringList remove(String s);
|
|
|
|
// fold that produces a set.
|
|
StringSet setFold(StringSet initial, StringSetOp op);
|
|
|
|
bool hasDuplicates();
|
|
}
|
|
|
|
type StringSetOp
|
|
{
|
|
// invoke this closure.
|
|
StringSet run(StringSet accum, String s);
|
|
}
|
|
|
|
class EmptyStringList() : StringList impl StringList
|
|
{
|
|
bool contains(String s) { false; }
|
|
StringList remove(String s) { this : StringList; }
|
|
|
|
StringSet setFold(StringSet initial, StringSetOp op) { initial; }
|
|
|
|
bool hasDuplicates() { false; }
|
|
|
|
export StringList : contains, setFold, remove, hasDuplicates;
|
|
}
|
|
|
|
class ConsStringList(String init_first, StringList init_rest) : StringList impl StringList
|
|
{
|
|
String first =
|
|
if(init_first == null) {
|
|
error("ConsStringList.init_first null");
|
|
} else {
|
|
init_first;
|
|
};
|
|
StringList rest =
|
|
if init_rest == null {
|
|
error("ConsStringList.init_rest null");
|
|
} else { init_rest; };
|
|
|
|
bool contains(String s)
|
|
{
|
|
(s ==== first) || rest.contains(s);
|
|
}
|
|
|
|
StringList remove(String s)
|
|
{
|
|
if s ==== first {
|
|
rest;
|
|
} else {
|
|
new ConsStringList : StringList
|
|
(init_first = first,
|
|
init_rest = rest.remove(s));
|
|
};
|
|
}
|
|
|
|
StringSet setFold(StringSet initial, StringSetOp op)
|
|
{
|
|
rest.setFold(op.run(initial, first), op);
|
|
}
|
|
|
|
bool hasDuplicates()
|
|
{
|
|
rest.contains(first) || rest.hasDuplicates();
|
|
}
|
|
|
|
export StringList : contains, setFold, remove, hasDuplicates;
|
|
}
|
|
|
|
class UnionOp() : StringSetOp impl StringSetOp
|
|
{
|
|
StringSet run(StringSet accum, String s)
|
|
{
|
|
accum.singleUnion(s);
|
|
}
|
|
|
|
export StringSetOp : run;
|
|
}
|
|
|
|
type StringSet
|
|
{
|
|
StringSet singleUnion(String elt);
|
|
StringSet union(StringSet rhs);
|
|
StringSet subElt(String elt);
|
|
}
|
|
|
|
class StringSetCls() : StringSet impl StringSet
|
|
{
|
|
init StringList init_contents = new EmptyStringList : StringList();
|
|
// this showed up a bug in the parser where I wasn't adding
|
|
// the default expressions to things. This caused problems
|
|
// when relying on them (i.e. not giving a contents init arg).
|
|
// Fixed.
|
|
|
|
// How should this get translated? You have a default value
|
|
// for contents so it can't go into the init args in the header,
|
|
// but you want an additional check later (hasDuplicates()).
|
|
StringList contents =
|
|
if init_contents.hasDuplicates() {
|
|
error("StringList.contents must be set");
|
|
} else { init_contents; };
|
|
|
|
StringSet singleUnion(String elt)
|
|
{
|
|
if contents.contains(elt) {
|
|
this : StringSet;
|
|
} else {
|
|
new StringSetCls : StringSet
|
|
(init_contents = new ConsStringList : StringList(init_first = elt,
|
|
init_rest = contents));
|
|
};
|
|
}
|
|
|
|
StringSet union(StringSet rhs)
|
|
{
|
|
contents.setFold(rhs, new UnionOp : StringSetOp());
|
|
}
|
|
|
|
StringSet subElt(String elt)
|
|
{
|
|
new StringSetCls : StringSet(init_contents = contents.remove(elt));
|
|
}
|
|
|
|
export StringSet : singleUnion, union, subElt;
|
|
// was export StringSetCls, typechecker caught this.
|
|
}
|
|
|
|
/*
|
|
**********************************************************************
|
|
* Values
|
|
**********************************************************************/
|
|
|
|
type Value
|
|
{
|
|
Value apply(Value arg);
|
|
}
|
|
|
|
class IntValue() : Value impl Value // was class Constant, typechecker caught this
|
|
// line 359 was the use of IntValue
|
|
{
|
|
init int init_n;
|
|
|
|
Value apply(Value arg) { error("cannot apply a constant"); }
|
|
|
|
export Value : apply;
|
|
}
|
|
|
|
class Closure(String init_argName, Ast init_body, Env init_rho) : Value impl Value
|
|
{
|
|
String argName =
|
|
if init_argName == null {
|
|
error("Closure.argName null");
|
|
} else { init_argName; };
|
|
Ast body =
|
|
if init_body == null {
|
|
error("Closure.body null");
|
|
} else { init_body; };
|
|
Env rho =
|
|
if init_rho == null {
|
|
error("Closure.rho null") ;
|
|
} else { init_rho; }; // was else body, Typechecker caught this
|
|
|
|
Value apply(Value arg)
|
|
{
|
|
body.getValue(rho.extend(argName, arg));
|
|
// originally thought this was a bug in the interpreter,
|
|
// but it was a bug in the typechecker (did supertype
|
|
// checking on method arguments, not subtype checking). Fixed.
|
|
}
|
|
|
|
export Value : apply; // no export statement, typechecker caught this.
|
|
}
|
|
|
|
/*
|
|
**********************************************************************
|
|
* Types
|
|
**********************************************************************/
|
|
|
|
type Type
|
|
{
|
|
Type getRange(Type domain);
|
|
}
|
|
|
|
class IntType() : Type impl Type
|
|
{
|
|
Type getRange(Type domain) { error("IntType.getRange"); }
|
|
|
|
export Type : getRange;
|
|
}
|
|
|
|
class ArrowType(Type init_dom, Type init_rng) : Type impl Type
|
|
{
|
|
Type dom =
|
|
if init_dom == null {
|
|
error("ArrowType.dom null");
|
|
} else { init_dom; };
|
|
Type rng =
|
|
if init_rng == null {
|
|
error("ArrowType.rng null");
|
|
} else { init_rng; };
|
|
|
|
Type getRange(Type domain)
|
|
{
|
|
// extensional equality
|
|
if domain ==== dom { rng; }
|
|
else { error("arrowType.getRange: domain mismatch"); };
|
|
}
|
|
|
|
export Type : getRange;
|
|
}
|
|
|
|
/*
|
|
**********************************************************************
|
|
* Environments
|
|
**********************************************************************/
|
|
|
|
type Env
|
|
{
|
|
Env extend(String var, Any t);
|
|
Any lookup(String var);
|
|
}
|
|
|
|
class EmptyEnv() : Env impl Env
|
|
{
|
|
Env extend(String var, Any t)
|
|
{
|
|
new RibEnv : Env(init_id = var, init_bdg = t, init_rest = this : Env);
|
|
}
|
|
|
|
Any lookup(String var)
|
|
{
|
|
error("unbound id");
|
|
}
|
|
|
|
export Env : extend, lookup;
|
|
}
|
|
|
|
class RibEnv(String init_id, Any init_bdg, Env init_rest) : Env impl Env
|
|
{
|
|
|
|
String id =
|
|
if init_id == null {
|
|
error("RibEnv.id null");
|
|
} else { init_id; };
|
|
Any bdg =
|
|
if init_bdg == null {
|
|
error("RibEnv.bdg null");
|
|
} else { init_bdg; };
|
|
Env rest =
|
|
if init_rest == null {
|
|
error("RibEnv.rest null");
|
|
} else { init_rest; };
|
|
|
|
Env extend(String var, Any t)
|
|
{
|
|
new RibEnv : Env(init_id = var, init_bdg = t, init_rest = this : Env);
|
|
}
|
|
|
|
Any lookup(String var)
|
|
{
|
|
if var ==== id { bdg; }
|
|
else { rest.lookup(var); };
|
|
}
|
|
|
|
export Env : extend, lookup;
|
|
// was export TypeEnv, should be Env, typechecker caught this.
|
|
}
|
|
/*
|
|
**********************************************************************
|
|
* ASTS
|
|
**********************************************************************/
|
|
|
|
type Ast
|
|
{
|
|
StringSet vars();
|
|
StringSet freeVars();
|
|
|
|
Type getType(Env gamma);
|
|
Value getValue(Env rho);
|
|
}
|
|
|
|
class Constant() : Ast impl Ast
|
|
{
|
|
init int n;
|
|
|
|
StringSet vars()
|
|
{
|
|
new StringSetCls : StringSet();
|
|
}
|
|
|
|
StringSet fv()
|
|
{
|
|
vars();
|
|
}
|
|
|
|
Type getType(Env gamma)
|
|
{
|
|
new IntType : Type();
|
|
}
|
|
|
|
Value getValue(Env rho)
|
|
{
|
|
new IntValue : Value(init_n = n);
|
|
}
|
|
|
|
export Ast : vars, fv as freeVars, getType, getValue;
|
|
}
|
|
|
|
class Variable(String init_name) : Ast impl Ast
|
|
{
|
|
String name =
|
|
if init_name == null {
|
|
error("Variable.name null");
|
|
} else { init_name; };
|
|
|
|
StringSet vars()
|
|
{
|
|
StringSet result = new StringSetCls : StringSet();
|
|
result.singleUnion(name);
|
|
}
|
|
|
|
StringSet fv() { vars(); }
|
|
|
|
Type getType(Env gamma)
|
|
{
|
|
gamma.lookup(name) : Type;
|
|
}
|
|
|
|
Value getValue(Env rho)
|
|
{
|
|
rho.lookup(name) : Value;
|
|
}
|
|
|
|
export Ast : vars, fv as freeVars, getType, getValue;
|
|
// last part was erroneously typed "getName" instead of "getValue",
|
|
// caught by typechecker.
|
|
}
|
|
|
|
class Lambda(String init_arg, Ast init_body, Type init_argType) : Ast impl Ast
|
|
{
|
|
String argName =
|
|
if init_arg == null {
|
|
error("Lambda.argName null");
|
|
} else { init_arg; };
|
|
Ast body =
|
|
if init_body == null {
|
|
error("Lambda.body null");
|
|
} else { init_body; };
|
|
Type argType =
|
|
if init_argType == null {
|
|
error("Lambda.argType null");
|
|
} else { init_argType; };
|
|
|
|
StringSet vars()
|
|
{
|
|
body.vars();
|
|
}
|
|
|
|
StringSet freeVars()
|
|
{
|
|
body.freeVars().subElt(argName);
|
|
// was arg (init field) instead of argName (field).
|
|
// typechecker caught this.
|
|
}
|
|
|
|
Type getType(Env gamma)
|
|
{
|
|
body.getType(gamma.extend(argName, argType));
|
|
// originally thought this was a bug in the interpreter,
|
|
// but it was a bug in the typechecker (did supertype
|
|
// checking on method arguments, not subtype checking). Fixed.
|
|
}
|
|
|
|
Value getValue(Env rho)
|
|
{
|
|
return new Closure : Value(init_argName = argName, init_body = body, init_rho = rho);
|
|
}
|
|
|
|
export Ast : vars, freeVars, getType, getValue;
|
|
}
|
|
|
|
class Application(Ast init_rator, Ast init_rand) : Ast impl Ast
|
|
{
|
|
Ast rator =
|
|
if init_rator == null {
|
|
error("Application.rator null");
|
|
} else { init_rator; };
|
|
Ast rand =
|
|
if init_rand == null {
|
|
error("Application.rand null");
|
|
} else { init_rand; };
|
|
|
|
StringSet vars()
|
|
{
|
|
StringSet ratorVars = rator.vars();
|
|
ratorVars.union(rand.vars());
|
|
}
|
|
|
|
StringSet fv()
|
|
{
|
|
StringSet ratorFv = rator.freeVars();
|
|
// rator.freeVars (public name) was rator.fv (private name).
|
|
// typechecker caught this (happened below also with rand)
|
|
ratorFv.union(rand.freeVars());
|
|
}
|
|
|
|
Type getType(Env gamma)
|
|
{
|
|
Type ratorType = rator.getType(gamma);
|
|
ratorType.getRange(rand.getType(gamma));
|
|
}
|
|
|
|
Value getValue(Env rho)
|
|
{
|
|
Value ratorVal = rator.getValue(rho);
|
|
ratorVal.apply(rand.getValue(rho));
|
|
// ratorVal.apply was rator.apply, which gave method not found error
|
|
// typechecker caught this.
|
|
// also, rand.getValue was rand.value. Same error.
|
|
// typechecker caught this.
|
|
}
|
|
|
|
export Ast : vars, fv as freeVars, getType, getValue;
|
|
}
|