Skip to content

Commit

Permalink
Add groovy implementation.
Browse files Browse the repository at this point in the history
I'm away from my main workstation for a week and unfortunately, I only
copied the code but not the branch with full history so this is just
the implementation. However, the history isn't all that interesting
(mostly just the steps one at a time) and I wanted to get this out
there.
  • Loading branch information
kanaka committed May 19, 2015
1 parent daf6831 commit a9cd654
Show file tree
Hide file tree
Showing 25 changed files with 1,778 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@ nim/nimcache
.m2
.ivy2
.sbt
groovy/*.class
8 changes: 5 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ PYTHON = python
# Settings
#

IMPLS = bash c clojure coffee cpp cs erlang factor forth go haskell java \
julia js lua make mal ocaml matlab miniMAL nim perl php ps \
python r racket ruby rust scala swift vb guile
IMPLS = bash c clojure coffee cpp cs erlang factor forth go groovy \
haskell java julia js lua make mal ocaml matlab miniMAL nim \
perl php ps python r racket ruby rust scala swift vb guile

step0 = step0_repl
step1 = step1_read_print
Expand Down Expand Up @@ -62,6 +62,7 @@ erlang_STEP_TO_PROG = erlang/$($(1))
factor_STEP_TO_PROG = factor/src/$($(1))/$($(1)).factor
forth_STEP_TO_PROG = forth/$($(1)).fs
go_STEP_TO_PROG = go/$($(1))
groovy_STEP_TO_PROG = groovy/$($(1)).groovy
java_STEP_TO_PROG = java/src/main/java/mal/$($(1)).java
haskell_STEP_TO_PROG = haskell/$($(1))
julia_STEP_TO_PROG = julia/$($(1)).jl
Expand Down Expand Up @@ -102,6 +103,7 @@ erlang_RUNSTEP = ../$(2) $(3)
factor_RUNSTEP = factor ../$(2) $(3)
forth_RUNSTEP = gforth ../$(2) $(3)
go_RUNSTEP = ../$(2) $(3)
groovy_RUNSTEP = groovy ../$(2) $(3)
haskell_RUNSTEP = ../$(2) $(3)
java_RUNSTEP = mvn -quiet exec:java -Dexec.mainClass="mal.$($(1))" $(if $(3), -Dexec.args="$(3)",)
julia_RUNSTEP = ../$(2) $(3)
Expand Down
33 changes: 33 additions & 0 deletions groovy/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
CLASSES = types.class reader.class printer.class env.class core.class

SOURCES_BASE = types.groovy reader.groovy printer.groovy
SOURCES_LISP = env.groovy core.groovy stepA_mal.groovy
SOURCES = $(SOURCES_BASE) $(SOURCES_LISP)

all: ${CLASSES}

types.class: types.groovy
groovyc $<

env.class: env.groovy
groovyc $<

reader.class: reader.groovy
groovyc $<

printer.class: printer.groovy
groovyc $<

core.class: core.groovy types.class reader.class printer.class
groovyc $<

clean:
rm -f *.class

.PHONY: stats tests

stats: $(SOURCES)
@wc $^
stats-lisp: $(SOURCES_LISP)
@wc $^

105 changes: 105 additions & 0 deletions groovy/core.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import types
import types.MalException
import types.MalSymbol
import reader
import printer

class core {
def static do_pr_str(args) {
return printer._pr_list(args, " ", true)
}
def static do_str(args) {
return printer._pr_list(args, "", false)
}
def static do_prn(args) {
println(printer._pr_list(args, " ", true))
}
def static do_println(args) {
println(printer._pr_list(args, " ", false))
}

def static do_concat(args) {
args.inject([], { a, b -> a + (b as List) })
}
def static do_nth(args) {
if (args[0].size() <= args[1]) {
throw new MalException("nth: index out of range")
}
args[0][args[1]]
}
def static do_apply(args) {
def start_args = args.drop(1).take(args.size()-2) as List
args[0](start_args + (args.last() as List))
}

def static do_swap_BANG(args) {
def (atm,f) = [args[0], args[1]]
atm.value = f([atm.value] + (args.drop(2) as List))
}

static ns = [
"=": { a -> a[0]==a[1]},
"throw": { a -> throw new MalException(a[0]) },

"nil?": { a -> a[0] == null },
"true?": { a -> a[0] == true },
"false?": { a -> a[0] == false },
"symbol": { a -> new MalSymbol(a[0]) },
"symbol?": { a -> a[0] instanceof MalSymbol },
"keyword": { a -> types.keyword(a[0]) },
"keyword?": { a -> types.keyword_Q(a[0]) },

"pr-str": core.&do_pr_str,
"str": core.&do_str,
"prn": core.&do_prn,
"println": core.&do_println,
"read-string": reader.&read_str,
"readline": { a -> System.console().readLine(a[0]) },
"slurp": { a -> new File(a[0]).text },

"<": { a -> a[0]<a[1]},
"<=": { a -> a[0]<=a[1]},
">": { a -> a[0]>a[1]},
">=": { a -> a[0]>=a[1]},
"+": { a -> a[0]+a[1]},
"-": { a -> a[0]-a[1]},
"*": { a -> a[0]*a[1]},
"/": { a -> a[0]/a[1]}, // /
"time-ms": { a -> System.currentTimeMillis() },

"list": { a -> a},
"list?": { a -> types.list_Q(a[0]) },
"vector": { a -> types.vector(a) },
"vector?": { a -> types.vector_Q(a[0]) },
"hash-map": { a -> types.hash_map(a) },
"map?": { a -> types.hash_map_Q(a[0]) },
"assoc": { a -> types.assoc_BANG(types.copy(a[0]), a.drop(1)) },
"dissoc": { a -> types.dissoc_BANG(types.copy(a[0]), a.drop(1)) },
"get": { a -> a[0] == null ? null : a[0][a[1]] },
"contains?": { a -> a[0].containsKey(a[1]) },
"keys": { a -> a[0].keySet() as List },
"vals": { a -> a[0].values() as List },

"sequential?": { a -> types.&sequential_Q(a[0]) },
"cons": { a -> [a[0]] + (a[1] as List) },
"concat": core.&do_concat,
"nth": core.&do_nth,
"first": { a -> a[0].size() == 0 ? null : a[0][0] },
"rest": { a -> a[0].drop(1) },
"empty?": { a -> a[0] == null || a[0].size() == 0 },
"count": { a -> a[0] == null ? 0 : a[0].size() },
"apply": core.&do_apply,
"map": { a -> a[1].collect { x -> a[0].call([x]) } },

"conj": null,

"meta": { a -> a[0].hasProperty("meta") ? a[0].getProperties().meta : null },
"with-meta": { a -> def b = types.copy(a[0]); b.getMetaClass().meta = a[1]; b },
"atom": { a -> new types.MalAtom(a[0]) },
"atom?": { a -> a[0] instanceof types.MalAtom },
"deref": { a -> a[0].value },
"reset!": { a -> a[0].value = a[1] },
"swap!": core.&do_swap_BANG
]
}

55 changes: 55 additions & 0 deletions groovy/env.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import types.MalException
import types.MalSymbol

class env {
static class Env {
def data
def outer

Env() {
outer = null
data = [:]
}
Env(Env outer_env) {
outer = outer_env
data = [:]
}
Env(Env outer_env, binds, exprs) {
outer = outer_env
data = [:]
for (int i=0; i<binds.size; i++) {
if (binds[i].value == "&") {
data[binds[i+1].value] = (exprs.size() > i) ? exprs[i..-1] : []
break
} else {
data[binds[i].value] = exprs[i]
}
}
}

def set(MalSymbol key, def val) {
data[key.value] = val
}

def find(MalSymbol key) {
if (data.containsKey(key.value)) {
this
} else if (outer != null) {
outer.find(key)
} else {
null
}
}

def get(MalSymbol key) {
def e = find(key)
if (e == null) {
throw new MalException("'${key.value}' not found")
} else {
e.data.get(key.value)
}
}
}

}

44 changes: 44 additions & 0 deletions groovy/printer.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import groovy.json.StringEscapeUtils
import types
import types.MalSymbol
import types.MalAtom


class printer {
def static _pr_list(lst, sep, Boolean print_readably) {
return lst.collect{ e -> pr_str(e, print_readably) }.join(sep)
}

def static pr_str(exp, Boolean print_readably) {
def _r = print_readably
switch (exp) {
case { types.list_Q(exp) }:
def lst = exp.collect { pr_str(it, _r) }
return "(${lst.join(" ")})"
case { types.vector_Q(exp) }:
def lst = exp.collect { pr_str(it, _r) }
return "[${lst.join(" ")}]"
case Map:
def lst = []
exp.each { k,v -> lst.add(pr_str(k,_r)); lst.add(pr_str(v,_r)) }
return "{${lst.join(" ")}}"
case String:
if (types.keyword_Q(exp)) {
return ":" + exp.drop(1)
} else if (print_readably) {
return "\"${StringEscapeUtils.escapeJava(exp)}\""
} else {
return exp
}
case null:
return 'nil'
case MalSymbol:
return exp.value
case MalAtom:
return "(atom ${exp.value})"
default:
return exp.toString()
}
}
}

Loading

0 comments on commit a9cd654

Please sign in to comment.