 |
Subscribe to this site |
|
LispBuilder
ArrayList.metaClass.asType = { Class c->
if (c == LispList) {
if (delegate.size() == 0) {
return null
}
return new Cons(delegate.first(), delegate.tail() as LispList)
}
else if (c == Cons) {
return new Cons(delegate[0], delegate[1])
}
}
String.metaClass.getIsSymbol = { false } /* set closure through metaclass for class */
String.metaClass.eval = { env ->
if (delegate.isSymbol) { /* the String is lisp symbol */
if (env.containsKey(delegate)) {
return env[delegate]
}
throw new Exception("Symbol not found: "+delegate)
}
return delegate
}
Object.metaClass.eval = { env ->
delegate
}
class LispList {
}
class Cons extends LispList {
private carPart
def getCar() {
if (carPart instanceof Closure) {
carPart = carPart.call()
}
carPart
}
void replaceCar_(a) {
carPart = a
}
private cdrPart
def getCdr() {
if (cdrPart instanceof Closure) {
cdrPart = cdrPart.call()
}
cdrPart
}
void replaceCdr_(a) {
cdrPart = a
}
Cons(a, b) {
carPart = a;
cdrPart = b;
}
def getAt(n) {
assert n >= 0
n==0 ? car : cdr[n-1]
}
String toStringHelper(HashSet hashSet) {
if (hashSet.contains(this)) {
return "..."
}
hashSet.add(this)
def result = new StringBuilder("(")
def list
for (list=this; list instanceof LispList; list=list.cdr) {
def elem = list.car
if (elem == null) {
result.append("<nil>")
}
else if (elem instanceof Cons) {
result.append(elem.toStringHelper(hashSet)+(list.cdr == null?"":" "))
}
else {
result.append(elem.toString()+(list.cdr == null?"":" "))
}
}
if (list != null) {
result.append(". " + list.toString());
}
result.append(")");
}
String toString() {
def set = new HashSet()
return toStringHelper(set)
}
int size() {
if (this.cdr == null) {
1
}
else {
1 + this.cdr.size()
}
}
LispList plus(LispList a) {
if (this.size() == 0) { /* this condition is impossible in this List implementation */
a
}
else if(this.size() == 1) {
[car, a] as Cons
}
else {
[car, cdr+a] as Cons
}
}
LispList append_(a) { /* destructive append */
if (this.size() == 0) { /* this condition is impossible in this List implementation */
a
}
else if(this.size() == 1) {
replaceCdr_(new Cons(a, null))
}
else {
cdr.append_(a)
}
}
boolean equals(LispList a) {
if (this.car != a.car) {
return false
}
if (this.cdr == null && a.cdr != null) {
return false
}
if (this.cdr != null && a.cdr == null) {
return false
}
if (this.cdr == null && a.cdr == null) {
return true
}
return this.cdr == a.cdr
}
Iterator iterator() {
return new LispListIterator(this)
}
def applyLambda(lambda, args, env) {
def pseudoArgList = lambda.cdr.car
def body = lambda.cdr.cdr.car
if (args == null && pseudoArgList != null
|| args != null && pseudoArgList == null
|| args.size() != pseudoArgList.size()) {
throw new Error("Arguments number mismatch: required '$pseudoArgList' but value is '$args'")
}
def localEnv = new Env(env)
pseudoArgList.eachWithIndex { it, idx ->
localEnv[it] = args[idx]
}
body.eval(localEnv)
}
def apply(func, args, env) {
if (func instanceof String && !env.containsKey(func)) {
throw new Error("Undefined function: "+func)
}
def entry = func.eval(env)
if (entry instanceof Closure) {
/* the function is Groovy closure */
if (entry.maximumNumberOfParameters != 3) {
/* evaluate arguments and call the Groovy closure(SUBR) */
args = args*.eval(env) as LispList
return entry.call(args, env)
}
else {
/* 3 argument closure means special form,
so call without argument evaluation(FSUBR) */
return entry.call(args, env, "no_automatic_eval_arg")
}
}
else if (entry instanceof Cons) {
/* the function is list (lambda function). (EXPR) */
if (entry.car == "lambda" && entry.car.isSymbol == true) {
args = args*.eval(env) as LispList
return applyLambda(entry, args, env)
}
}
return entry
}
def eval(env = new Env()) {
def func = car
def args = cdr
def result = apply(func, args, env)
result
}
}
class LispListIterator implements Iterator {
LispList cursor
LispListIterator(LispList list) {
cursor = list
}
boolean hasNext() {
cursor != null
}
Object next() {
def result = cursor.car
cursor = cursor.cdr
return result
}
void remove() {
throw new UnsupportedOperationException("remove not supported");
}
}
class Env {
Map localEnv = [:]
def parentEnv
Env(env = null) {
if (env == null) {
parentEnv = [:]
Functions.registerFunctions(parentEnv)
}
else {
this.parentEnv = env
}
}
def getProperty(String key) {
if (localEnv.containsKey(key)) {
return localEnv[key]
}
if (parentEnv != null) {
return parentEnv[key]
}
null
}
void setProperty(String key, value) {
localEnv[key] = value
}
def containsKey(key) {
if (localEnv.containsKey(key)) {
return true
}
if (parentEnv.containsKey(key)) {
return true
}
return false
}
String toString() {
"local:" + localEnv.toString() + "parent:" + parentEnv.toString()
}
def eval(Closure c) {
def bx = new LispBuilder()
return bx.build(c).eval(this)
}
}
class Functions {
private static registerClosureFunctions(map) {
map.with {
eq = { args, env ->
assert args.size() == 2
if (args[0] == null && args[1] == null) {
return true
}
if ((args[0] == null && args[1] != null)
||(args[0] != null && args[1] == null)
) {
return false
}
if (args[0].class != args[1].class) {
return false
}
if (args[0] instanceof Number
|| args[0] instanceof String) {
return args[0] == args[1]
}
args[0].is(args[1])
}
IF = { args, env, no_automatic_eval_arg ->
assert args.size() in 2..3
def cond = args[0].eval(env)
def thenPart = args[1]
if (cond) {
return thenPart.eval(env)
}
else if (args.size() == 3) {
def elsePart = args[2]
return elsePart.eval(env)
}
return false
}
quote = { args, env, no_automatic_eval_arg ->
assert args.size() == 1
return args[0]
}
TRUE = true
FALSE = false
nil = null
car = { args, env ->
assert args.size() == 1
args[0].car }
cdr = { args, env ->
assert args.size() == 1
args[0].cdr }
cons = { args, env ->
assert args.size() == 2
new Cons(args[0], args[1]) }
setq = { args, env, no_automatic_eval_arg ->
assert args.size() == 2
env[args[0]] = args[1].eval(env)
}
and = { args, env ->
def result = true
args.each {
result = result && it
}
result
}
or = { args, env ->
def result = false
args.each {
result = result || it
}
result
}
progn = {args, env, no_automatic_eval_arg ->
def last
args.each {
last = it.eval(env)
}
last
}
equal = { args, env ->
assert args.size() == 2
args[0] == args[1]
}
lt = { args, env ->
assert args.size() == 2
args[0] < args[1]
}
le = { args, env ->
lt.call(args, env) || equal.call(args, env)
}
gt = { args, env ->
!le.call(args, env)
}
ge = { args, env ->
!lt.call(args, env)
}
add = { args, env ->
assert args.size() >= 2
def result = 0
args.each {
result += it.eval(env)
}
result
}
sub = { args, env ->
assert args.size() >= 2
def result = args[0]
args.cdr.each {
result -= it.eval(env)
}
result
}
mul = { args, env ->
assert args.size() >= 2
def result = args[0]
args.cdr.each {
result *= it.eval(env)
}
result
}
div = { args, env ->
assert args.size() >= 2
def result = args[0]
args.cdr.each {
result /= it.eval(env)
}
result
}
defun = {args, env, no_automatic_eval_arg ->
assert args.size() == 3
def sym_lambda = LispBuilder.makeSymbol("lambda");
def sym_quote = LispBuilder.makeSymbol("quote");
def new_args = [args[0],
[sym_quote,
[ sym_lambda, args[1], args[2] ] as LispList
] as LispList
] as LispList
setq.call(new_args, env, "no_automatic_eval_arg")
}
// invoke Java(groovy) level method
call = {args, env ->
assert args.size() >= 2
def new_args = []
for (int i=2; i<args.size(); i++) {
new_args += args[i]
}
args[0].invokeMethod(args[1], new_args.size()==0 ? null : new_args)
}
print = {args, env ->
args.each {
print it
}
}
println = {args, env ->
print.call(args, env)
println ""
}
}
}
private static registerLambdaFunctions(map) {
def bx = new LispBuilder()
map.with {
not = bx.build{lambda
${x}
${IF; x; FALSE; TRUE}
}
neq = bx.build{lambda
${x; y}
${not; ${eq; x; y}}
}
nullp = bx.build {lambda
${x}
${eq; nil; x}
}
append = bx.build {lambda
${a; b}
${IF;
${nullp; a}
b;
${cons; ${car; a}; ${append; ${cdr; a}; b}}}
}
reverse = bx.build {lambda
${x}
${IF
${nullp; x}
x
${append
${reverse
${cdr; x}}
${cons; ${car; x}; nil}}}
}
}
}
static registerFunctions(map) {
registerClosureFunctions(map)
registerLambdaFunctions(map)
}
}
class LispBuilder {
private LispList readBuffer
def readStart() {
readBuffer = null
}
def readResult() {
readBuffer
}
def build(Closure c) {
readStart()
c.delegate = this
c.resolveStrategy = Closure.DELEGATE_FIRST;
// c.resolveStrategy = Closure.DELEGATE_ONLY;
c.call()
return readResult()
}
def invokeMethod(String m, args) {
try {
if (m != '$') {
getProperty(m)
}
def elem = args[0]
if (elem instanceof Closure) {
LispBuilder reader = new LispBuilder()
elem = reader.build(elem)
}
if (elem != null) {
if (readBuffer == null) {
readBuffer = [elem] as LispList
}
else {
readBuffer.append_(elem)
}
}
}
catch (Exception e) {
e.printStackTrace()
}
}
static makeSymbol(s) {
def result = new String(s) /* new String instance is reqired (countermasure of 'interned' equality check) */
result.metaClass.getIsSymbol = { true } /* set closure through metaclass for instance */
result
}
def getProperty(String p) {
try {
def value = p
if (p.startsWith('$')) {
value = Integer.parseInt(p.substring(1,p.size()))
}
else {
value = makeSymbol(value)
}
if (readBuffer == null) {
readBuffer = [value] as LispList
}
else {
readBuffer.append_(value)
}
}
catch (Exception e) {
e.printStackTrace()
}
}
}
println([1,2,3] as LispList)
println([1,2] as Cons)
def bx = new LispBuilder()
// Fibonacci number by recursive call
println bx.build{progn
${defun; fib; ${n}
${IF; ${or; ${equal; n; $1}; ${equal; n; $2}}
$1
${add; ${fib; ${add; n; $(-1)}}
${fib; ${add; n; $(-2)}}}}}
${fib; $10}
}.eval()
// Square Root calcuration by newton method
def env = new Env()
env.eval{defun; abs; ${x}
${IF; ${lt; x; $0}; ${mul; x; $(-1)}; x}}
env.eval{defun; average; ${x; y}
${div; ${add; x; y}; $2}}
env.eval{progn
${defun; improve; ${y; x}
${average; y; ${div; x; y}}}
${defun; good_enoughp; ${y; x}
${le; ${abs; ${sub; ${mul; y; y}; x}}; $(0.000001)}}
${defun; sqrt_iter; ${y; x}
${IF; ${good_enoughp; y; x}
y
${sqrt_iter; ${improve; y; x}
x}}}
${defun; sqrt; ${x}
${sqrt_iter; $(1.0); x}}}
println env.eval{sqrt; $(3.0)}