-
-
Save kravchik/2962011 to your computer and use it in GitHub Desktop.
package simple; | |
import par.ParParser; | |
import java.util.List; | |
import java.util.Map; | |
import static yk.Util.copy; | |
import static yk.Util.list; | |
import static yk.Util.map; | |
import static par.ParParser.Symbol; | |
/** | |
* Kravchik Yuri | |
* Date: 19.06.2012 | |
* Time: 11:32 PM | |
*/ | |
public class Executor { | |
private Map initialContext = map(); | |
private final Symbol inline = s("inline"); | |
private final List<Thr> threads = list(); | |
private void l(String name) { | |
initialContext.put(s(name), new Lambda(null, null)); | |
} | |
private static Symbol s(String s) { return new Symbol(s.intern()); } | |
public void run(Object program) {//program is data - lists, symbols, Floats, Integers and Strings | |
l("add-float"); | |
l("sub-float"); | |
l("mul-float"); | |
l("def"); | |
l("break"); | |
l("fn"); | |
l("quote"); | |
l("do"); | |
l("spawn"); | |
l("macro"); | |
l("by-index"); | |
initialContext.put(s("main"), new Lambda(program, initialContext)); | |
threads.add(new Thr(0, initialContext, list(new ParParser.Symbol("main")))); | |
//run while there is threads | |
while(!threads.isEmpty()) { | |
try { | |
Thr thr = threads.remove(0); | |
System.out.println("process end with " + exec(thr.context, thr.call)); | |
} catch (Break ignore) {} | |
} | |
} | |
public Object exec(Map map, List list, int index) { | |
while(true) {//inline with X, if result is (inline X) | |
Object result = exec(map, list.get(index)); | |
if (result instanceof List && ((List)result).get(0).equals(inline)) list.set(index, ((List)result).get(1)); | |
else return result; | |
} | |
} | |
public Object exec(Map map, Object o) { | |
if (o instanceof List) { | |
Object result = execCall(map, (List) o); | |
if (result instanceof List && ((List)result).get(0) instanceof Lambda) { | |
Lambda l = (Lambda) ((List) result).get(0); | |
return exec(l.context, l.body); | |
} | |
return result; | |
} | |
if (o instanceof Symbol) return map.get(o); | |
return o; | |
} | |
public Object tail(Map map, Lambda lambda) { | |
return list(new Lambda(lambda.body, map)); | |
} | |
public Object execCall(Map map, List list) { | |
Lambda toCall; | |
Object firstItem = exec(map, list, 0); | |
if (!(firstItem instanceof Lambda)) throw new Error(firstItem + " is not lambda"); | |
toCall = (Lambda) firstItem; | |
if (toCall == map.get(s("fn"))) return new Lambda(list.get(1), map);//TODO refactor with macros | |
if (toCall == map.get(s("macro"))) return new Lambda(list.get(1), map, true); | |
if (toCall == map.get(s("quote"))) return execQuote(map, list.get(1)); | |
if (toCall == map.get(s("def"))) { | |
Object val = exec(map, list, 2); | |
map.put(list.get(1), val); | |
return val; | |
} | |
if (toCall == map.get(s("while"))) { | |
Object result = null; | |
while(true) { | |
Object condition = exec(map, list, 1); | |
if (condition.equals(Boolean.FALSE)) break; | |
result = exec(map, list, 2); | |
} | |
return result; | |
} | |
if (toCall == map.get(s("if"))) return !exec(map, list, 1).equals(Boolean.FALSE) ? exec(map, list, 2) : list.size() > 3 ? exec(map, list, 3) : null; | |
List resolved; | |
if (toCall.isMacro) resolved = list.subList(1, list.size()); | |
else { | |
resolved = list(); | |
for (int i = 1; i < list.size(); i++) resolved.add(exec(map, list, i)); | |
} | |
if (toCall == map.get(s("do"))) return resolved.get(resolved.size() - 1);//todo implement by macros? | |
if (toCall == map.get(s("break"))) throw new Break(); | |
if (toCall == map.get(s("add-float"))) return (Float)resolved.get(0) + (Float)resolved.get(1); | |
if (toCall == map.get(s("sub-float"))) return (Float)resolved.get(0) - (Float)resolved.get(1); | |
if (toCall == map.get(s("mul-float"))) return (Float)resolved.get(0) * (Float)resolved.get(1); | |
if (toCall == map.get(s("by-index"))) return ((List)resolved.get(1)).get((Integer) resolved.get(0)); | |
if (toCall == map.get(s("list"))) return resolved; | |
if (toCall == map.get(s("spawn"))) { | |
threads.add(new Thr((Integer) resolved.get(0), copy(map, s("args"), resolved), (List) resolved.get(1))); | |
return null; | |
} | |
return tail(copy(toCall.context, s("args"), resolved), toCall); | |
} | |
public Object execQuote(Map map, Object o) { | |
if (o instanceof List) { | |
if (((ParParser.Symbol)((List)o).get(0)).name.equals("unquote")) { | |
return exec(map, ((List) o).get(1)); | |
} else { | |
List result = list(); | |
for (Object l : (List)o) result.add(execQuote(map, l)); | |
return result; | |
} | |
} | |
return o; | |
} | |
} |
package simple; | |
import par.ParParser; | |
import java.util.List; | |
import java.util.Map; | |
/** | |
* Kravchik Yuri | |
* Date: 20.06.2012 | |
* Time: 12:46 AM | |
*/ | |
public class Lambda { | |
public boolean isMacro; | |
public Map context; | |
public Object body; | |
public Lambda(Object body, Map context) { | |
this.body = body; | |
this.context = context; | |
} | |
public Lambda(Object body, Map context, boolean isMacro) { | |
this.body = body; | |
this.context = context; | |
this.isMacro = isMacro; | |
} | |
} |
Lambdas and threading is already here.
There is not shown ParParser - javacc generated parser for lisp-like syntax.
Templates, work with data structures are not implemented yet.
valid program:
(do
(def foo (fn (x) (mul-float x 2)))
(spawn 1 (quote (foo 3)))
(def x 5)
(spawn 1 (quote (foo 4)))
(add-float x 5)
(spawn 1 (quote (foo (unquote (add-float 10 x))))))
Added macros support.
Args is transferred as array only, but one can create macros of function with normally named args. And more - var args, map-like args also easily constructed with macros.
It seems like I have added not usual macros support but kind of "run-time macros". It is interesting where this could lead. "Handmade hot spot" or something. Some data-driven run-time program modifications...
Added automatic tail recursion, 'while' and 'if'. Executor is growing up. It's a bad sign :)
ParParser is javacc generated parser for lisp-like syntax.