-
-
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.