orelang を Java で実装してみた

http://qiita.com/shuetsu@github/items/ac21e597265d6bb906dc

わりとよくある JSON ベースの lisp っぽいインタープリタの実装ですが、コードを見ていてもよくわからなかったので自分で実装しなおしてみました。

package com.example;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

import com.fasterxml.jackson.databind.ObjectMapper;

public class OreLang {
    HashMap<String, Object> vars = new HashMap<>();

    private Object eval(Object o) {
        if (o instanceof List) {
            System.out.println("Running: " + o);
            Object result = doRun((List<?>) o);
            System.out.println("Result: " + o + " : " + result + " : " + vars);
            return result;
        } else {
            return o;
        }
    }

    private Object doRun(List<?> list) {
        String op = (String) list.get(0);
        List<?> args = list.subList(1, list.size());
        switch (op) {
            case "set":
                vars.put((String) args.get(0), eval(args.get(1)));
                return null;
            case "get":
                return vars.get(args.get(0));
            case "+":
                return (Integer) eval(args.get(0)) + (Integer) eval(args.get(1));
            case "=":
                return eval(args.get(0)) == eval(args.get(1));
            case "until":
                while (!(Boolean) eval(args.get(0))) {
                    eval(args.get(1));
                }
                return null;
            case "step":
                List<Object> collect = args.stream()
                                           .map(this::eval)
                                           .collect(Collectors.toList());
                return collect.get(collect.size() - 1);
        }
        throw new RuntimeException("Unknown operation: " + op);
    }

    public static void main(String[] args) throws IOException {
        String source = "[\"step\",\n"
                        + "  [\"set\", \"i\", 10],\n"
                        + "  [\"set\", \"sum\", 0],\n"
                        + "  [\"until\", [\"=\", [\"get\", \"i\"], 0], [\n"
                        + "    \"step\",\n"
                        + "    [\"set\", \"sum\", [\"+\", [\"get\", \"sum\"], [\"get\", \"i\"]]],\n"
                        + "    [\"set\", \"i\", [\"+\", [\"get\", \"i\"], -1]]\n"
                        + "  ]],\n"
                        + "  [\"get\", \"sum\"]\n"
                        + "]\n";
        ObjectMapper objectMapper = new ObjectMapper();
        Object script = objectMapper.readValue(source, Object.class);
        Object result = new OreLang().eval(script);
        System.out.println("RESULT: " + result);
    }
}