clojure git checkout bb50ab52

/**
 *   Copyright (c) Rich Hickey. All rights reserved.
 *   The use and distribution terms for this software are covered by the
 *   Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
 *   which can be found in the file CPL.TXT at the root of this distribution.
 *   By using this software in any fashion, you are agreeing to be bound by
 *   the terms of this license.
 *   You must not remove this notice, or any other, from this software.
 **/

/* rich Sep 3, 2006 */

package clojure.lang;

import java.io.StringWriter;
import java.io.InputStreamReader;
import java.io.FileInputStream;

public class Compiler{
///*
static Symbol DEF = Symbol.intern("def");
static Symbol FN = Symbol.intern("fn");
static Symbol DO = Symbol.intern("do");
static Symbol IF = Symbol.intern("if");
static Symbol OR = Symbol.intern("or");
static Symbol AND = Symbol.intern("and");
static Symbol LET = Symbol.intern("let");
static Symbol LET_STAR_ = Symbol.intern("let*");
static Symbol LETFN = Symbol.intern("letfn");
static Symbol NOT = Symbol.intern("not");
static Symbol NULL_QM_ = Symbol.intern("null?");

static Symbol IMPORT = Symbol.intern("import");
static Symbol USE = Symbol.intern("use");
static Symbol _AMP_KEY = Symbol.intern("&key");
static Symbol _AMP_REST = Symbol.intern("&rest");

static public Var _CRT_OUT = RT.OUT;
static public Var _CRT_MODULE = RT._CT_MODULE;

static NilExpr NIL_EXPR = new NilExpr();

//short-name-string->full-name-string
static public Var IMPORTS = Module.intern("clojure", "^compiler-imports");
//keyword->keywordexpr
static public Var KEYWORDS = Module.intern("clojure", "^compiler-keywords");
//var->var
static public Var VARS = Module.intern("clojure", "^compiler-vars");
//symbol->localbinding
static public Var LOCAL_ENV = Module.intern("clojure", "^compiler-local-env");
//FnFrame
static public Var METHOD = Module.intern("clojure", "^compiler-method");
//module->module
static public Var USES = Module.intern("clojure", "^compiler-uses");
//ISeq FnExprs
static public Var FNS = Module.intern("clojure", "^compiler-fns");

static public  IPersistentMap CHAR_MAP =
        new PersistentArrayMap('-', "_DSH_",
                               '.', "_DOT_",
                               ':', "_CLN_",
                               '+', "_PLS_",
                               '>', "_GT_",
                               '<', "_LT_",
                               '=', "_EQ_",
                               '~', "_TLD_",
                               '!', "_EXC_",
                               '@', "_AT_",
                               '#', "_SHP_",
                               '$', "_DS_",
                               '%', "_PCT_",
                               '^', "_CRT_",
                               '&', "_AMP_",
                               '*', "_STAR_",
                               '{', "_LBC_",
                               '}', "_RBC_",
                               '[', "_LBK_",
                               ']', "_RBK_",
                               '/', "_FSL_",
                               '\\',"_BSL_",
                               '?', "_QM_");

private static final int MAX_POSITIONAL_ARITY = 20;


static String compile(String ns, String className, LineNumberingPushbackReader... files) throws Exception {
    StringWriter w = new StringWriter();
    try
        {
        _CRT_OUT.pushThreadBinding(w);
        KEYWORDS.pushThreadBinding(null);
        VARS.pushThreadBinding(null);
        METHOD.pushThreadBinding(null);
        LOCAL_ENV.pushThreadBinding(null);
        FNS.pushThreadBinding(new PersistentArrayList(4));

        format("/* Generated by Clojure */~%~%");
        format("package ~A;~%", ns);
        format("import clojure.lang.*;~%~%");
        format("public class ~A{~%", className);

        PersistentArrayList forms = new PersistentArrayList(20);
        for(LineNumberingPushbackReader reader : files)
            {
            try
                {
                IMPORTS.pushThreadBinding(null);
                USES.pushThreadBinding(null);

                Object eof = new Object();
                Object form = null;

                while((form = LispReader.read(reader,false,eof,false)) != eof)
                    {
                    form = macroexpand(form);
                        System.out.println("此时的form:  " + RT.first(form) +":" + RT.second(form));
                    if(!(form instanceof ISeq)) throw new Exception("No atoms allowed at top level");
                    Object op = RT.first(form);
                    //enact import and use at compile-time
                    if(op == IMPORT)
                        {
                        //todo implement import
                        }
                    else if(op == USE)
                        {
                        //todo implement use
                        }
                    else
                        forms = forms.cons(analyze(C.STATEMENT, form));
                    }
                }
            finally
                {
                IMPORTS.popThreadBinding();
                USES.popThreadBinding();
                }
            }
        //declare static members for keywords, vars
        for(ISeq keys = RT.seq(KEYWORDS.getValue());keys != null;keys = keys.rest())
            {
            KeywordExpr k = (KeywordExpr) ((IMapEntry) keys.first()).val();
            format("static Keyword ~A;~%", k.emitExpressionString());
            }
        for(ISeq vars = RT.seq(VARS.getValue());vars != null;vars = vars.rest())
            {
            Var v = (Var) ((IMapEntry) vars.first()).val();
            format("static Var ~A;~%", munge(v.toString()));
            }

        //todo declare static members for syms, quoted aggregates

        //emit nested static class/method declarations for nested fns
        PersistentArrayList fns = (PersistentArrayList)FNS.getValue();
        for(int f =0;f expr
    if(bindings == null && form.count() < 4)
        return analyze(context, macroexpand(RT.third(form)));
    ISeq body = RT.rest(RT.rest(form));

    if(context == C.EXPRESSION)
        {
        //(let (a b) c) -> ((fn (a) c) b)
        PersistentArrayList parms = new PersistentArrayList(4);
        PersistentArrayList args = new PersistentArrayList(4);
        for (ISeq bs = bindings; bs != null; bs = RT.rest(RT.rest(bs)))
            {
            parms = parms.cons(RT.first(bs));
            args = args.cons(RT.second(bs));
            }
        return analyze(context, RT.cons(RT.listStar(FN, RT.seq(parms), body),RT.seq(args)));
        }

    PersistentArrayList bindingInits = new PersistentArrayList(4);
    //analyze inits before adding bindings to env
    for (ISeq bs = bindings; bs != null; bs = RT.rest(RT.rest(bs)))
        {
        LocalBinding lb = new LocalBinding(baseSymbol((Symbol) RT.first(bs)));
        lb.typeHint = typeHint((Symbol) RT.first(bs));
        bindingInits = bindingInits.cons(new BindingInit(lb, analyze(C.EXPRESSION, RT.second(bs))));
        }
     try
        {
        LOCAL_ENV.pushThreadBinding(LOCAL_ENV.getValue());
        for(int i=0;i expr
    if(bindings == null && form.count() < 4)
        return analyze(context, macroexpand(RT.third(form)));
    ISeq body = RT.rest(RT.rest(form));

    if(context == C.EXPRESSION)
        return analyze(context, RT.list(RT.list(FN, null, form)));

    try
       {
       LOCAL_ENV.pushThreadBinding(LOCAL_ENV.getValue());
       PersistentArrayList bindingInits = new PersistentArrayList(4);
       for (ISeq bs = bindings; bs != null; bs = RT.rest(RT.rest(bs)))
           {
           LocalBinding lb = new LocalBinding(baseSymbol((Symbol) RT.first(bs)));
           lb.typeHint = typeHint((Symbol) RT.first(bs));
           BindingInit bi = new BindingInit(lb, analyze(C.EXPRESSION, RT.second(bs)));
           bindingInits = bindingInits.cons(bi);
          if(bi.init instanceof FnExpr)
            {
            bi.binding.letfn = (FnExpr) bi.init;
            ((FnExpr) bi.init).binding = bi.binding;
            }
           //sequential enhancement of env
           registerLocal(lb);
           }

       return new LetExpr(bindingInits, analyzeBody(context, body));
       }
    finally
        {
        LOCAL_ENV.popThreadBinding();
        }

}

static class LetExpr extends AnExpr{
    PersistentArrayList bindingInits;
    Expr body;

    public LetExpr(PersistentArrayList bindingInits, Expr body) {
        this.bindingInits = bindingInits;
        this.body = body;
    }

    public void emitStatement() throws Exception {
        emitBindings();
        body.emitStatement();
    }

    private void emitBindings() throws Exception {
        for(int i=0;iitself
    IPersistentMap closes = null;

    String getName(){
        if(name == null)
            {
            if(binding != null)
                name = "FN__" + munge(binding.sym.name) + "__" + RT.nextID();
            else
                name = "FN__" + RT.nextID();
            }
        return name;
    }

    public void emitExpression() throws Exception{
        format("(new ~A(", getName());
        for(ISeq s = RT.seq(closes);s!=null;s=s.rest())
            {
            LocalBinding b = (LocalBinding) ((IMapEntry) s.first()).key();
            format("~A", b.getName());
            if (s.rest() != null)
                format(",");
            }
        format("))");
    }

    public void emitDeclaration() throws Exception {
        PersistentArrayList closesDecls = null;
        if(closes != null)
            {
            closesDecls = new PersistentArrayList(closes.count() * 2);
            for (ISeq s = RT.seq(closes); s != null; s = s.rest())
                {
                LocalBinding b = (LocalBinding) ((IMapEntry) s.first()).key();
                if(!b.bindsToStaticFn())
                    {
                    closesDecls = closesDecls.cons(b.typeDeclaration());
                    closesDecls = closesDecls.cons(b.getName());
                    }
                }
            }
        if(!willBeStaticMethod())
            {
            //emit class declaration
            format("static public class ~A extends ~A{~%",
                   getName(),
                   variadicMethod != null ? "clojure.lang.RestFn" : "AFn");

            if(closes != null)
                {
                //emit members and ctor if closure
                format("~{~A ~A;~%~}", closesDecls);
                format("public ~A (~{~A ~A~^, ~}){~%", getName(), closesDecls);
                if(variadicMethod != null) //must call base ctor
                    format("super(~A);~%", variadicMethod.reqParms.count());
                for (ISeq s = RT.seq(closes); s != null; s = s.rest())
                    {
                    LocalBinding b = (LocalBinding) ((IMapEntry) s.first()).key();
                    if(!b.bindsToStaticFn())
                        {
                        format("this.~A = ~A;~%", b.getName(), b.getName());
                        if (s.rest() != null)
                            format(",");
                        }
                    }
                format("}~%");
                }
            else if(variadicMethod != null) //must create ctor in order to call base ctor
                {
                format("public ~A (){~%", getName());
                format("super(~A);~%", variadicMethod.reqParms.count());
                format("}~%");
                }

            }
        else
            {
            format("static public Object ~A(~{~A ~A~^, ~}",
                   getName(),
                   closesDecls);
            }

        for(ISeq methods = RT.seq(this.methods);methods != null;methods = methods.rest())
            {
            //this will run once if static method
            FnMethod m = (FnMethod) methods.first();
            if(!willBeStaticMethod())
                 format("public Object ~A(", m.isVariadic()?"doInvoke":"invoke");
            for(ISeq reqs = RT.seq(m.reqParms);reqs != null;reqs = reqs.rest())
                {
                LocalBindingExpr be = (LocalBindingExpr) reqs.first();
                format("Object ~A", be.b.getName());
                if(be.b.needsBox())
                    format("__arg");
                if(reqs.rest() != null)
                    format(",");
                }
            if(m.isVariadic())
                {
                if(m.reqParms.count() > 0)
                    format(",");
                format("ISeq ");
                if(m.restParm != null)
                    {
                    format("~A", m.restParm.b.getName());
                    if(m.restParm.b.needsBox())
                        format("__arg");
                    }
                else
                    format("__keys");
                }
            format(") throws Exception{~%");

            //emit declarations for any boxed args
            for(ISeq reqs = RT.seq(m.reqParms);reqs != null;reqs = reqs.rest())
                {
                LocalBindingExpr be = (LocalBindingExpr) reqs.first();
                if(be.b.needsBox())
                    be.b.emitDeclaration(be.b.getName() + "__arg");
                }
            //emit declaration for any boxed rest arg
            if(m.restParm != null && m.restParm.b.needsBox())
                m.restParm.b.emitDeclaration(m.restParm.b.getName() + "__arg");
            //keys are locals, plucked out of rest arg
            if(m.keyParms != null)
                {
                format("ISeq __valseq = null;~%");
                for (ISeq keys = RT.seq(m.keyParms); keys != null; keys = keys.rest())
                    {
                    KeyParam key = (KeyParam) keys.first();
                    KeywordExpr kw = registerKeyword((Keyword) Symbol.intern(":" + key.bindingExpression.b.sym.name));
                    format("__valseq = RT.findKey(~A,__keys);~%", kw.emitExpressionString());
                    key.bindingExpression.b.emitDeclaration(
                            (String) RT.format(null, "(__valseq!=null)?clojure.lang.RT.first(__valseq):~A"
                                    , key.init.emitExpressionString()));
                    }
                }

            //local variables
            for (ISeq locals = RT.seq(m.locals); locals != null; locals = locals.rest())
                {
                LocalBinding b = (LocalBinding) ((IMapEntry) locals.first()).key();
                if(!b.isParam && !b.bindsToStaticFn())
                    b.emitDeclaration("null");
                }

            m.body.emitReturn();
            //end of function
            format("}~%");
            }

        //end of class
        if(!willBeStaticMethod())
            format("}~%");
    }

    boolean willBeStaticMethod() {
        return variadicMethod == null
               && methods.count() == 1
               &&
               (
                       isCalledDirectly
                       ||
                       (binding != null && !binding.isAssigned && !binding.valueTaken)
               );
    }
}

static class FnMethod {
    FnMethod parent = null;
    //localbinding->localbinding
    IPersistentMap locals = null;
    //localbinding->localbinding
    PersistentArrayList reqParms = new PersistentArrayList(4);
    PersistentArrayList keyParms = null;
    LocalBindingExpr restParm = null;
    Expr body = null;
    FnExpr fn;

    public FnMethod(FnExpr fn,FnMethod parent) {
        this.parent = parent;
        this.fn = fn;
    }

    boolean isVariadic(){
        return keyParms != null || restParm != null;
    }
}

enum PSTATE{REQ,REST,KEY,DONE}

private static FnMethod analyzeMethod(FnExpr fn,ISeq form) throws Exception {
    //((args) body)
    ISeq parms = (ISeq) RT.first(form);
    ISeq body = RT.rest(form);
    try
        {
        FnMethod method = new FnMethod(fn,(FnMethod) METHOD.getValue());
        METHOD.pushThreadBinding(method);
        LOCAL_ENV.pushThreadBinding(LOCAL_ENV.getValue());
        PSTATE state = PSTATE.REQ;
        for (ISeq ps = parms; ps != null; ps = ps.rest())
            {
            Object p = ps.first();
            if (p == _AMP_REST)
                {
                if (state == PSTATE.REQ)
                    state = PSTATE.REST;
                else
                    throw new Exception("Invalid parameter list");
                }
            else if (p == _AMP_KEY)
                {
                if (state == PSTATE.REQ)
                    {
                    state = PSTATE.KEY;
                    method.keyParms = new PersistentArrayList(4);
                    }
                else
                    throw new Exception("Invalid parameter list");
                }
            else
                {
                switch (state)
                    {
                    case REQ:
                        method.reqParms = method.reqParms.cons(createParamBinding((Symbol) p));
                        break;
                    case REST:
                        method.restParm = createParamBinding((Symbol) p);
                        state = PSTATE.DONE;
                        break;
                    case KEY:
                        if(p instanceof ISeq)
                            method.keyParms = method.keyParms.cons(
                                        new KeyParam(createParamBinding((Symbol) RT.first(p)),
                                                     analyze(C.EXPRESSION, RT.second(p))));
                        else
                            method.keyParms = method.keyParms.cons(
                                        new KeyParam(createParamBinding((Symbol) p)));

                        break;
                    default:
                        throw new Exception("Unexpected parameter");
                    }
                }
            }
        if(method.reqParms.count() > MAX_POSITIONAL_ARITY)
            throw new Exception("Sorry, can't specify more than " + MAX_POSITIONAL_ARITY + " params");
        method.body = analyze(C.RETURN, RT.cons(DO, body));
        return method;
        }
    finally{
        METHOD.popThreadBinding();
        LOCAL_ENV.popThreadBinding();
    }
}



static LocalBindingExpr createParamBinding(Symbol p) {
    Symbol basep = baseSymbol(p);
    LocalBinding b = new LocalBinding(basep);
    b.isParam = true;
    String typeHint = typeHint(p);
    b.typeHint = typeHint;
    registerLocal(b);
    return new LocalBindingExpr(b, typeHint);
}

private static Expr analyzeDef(C context, ISeq form) throws Exception {
    //(def x) or (def x initexpr)
    if(form.count() > 3)
        throw new Exception("Too many arguments to def");
    Symbol sym = (Symbol) RT.second(form);
    Module module = (Module) _CRT_MODULE.getValue();
    Var var = module.intern(baseSymbol(sym));
    registerVar(var);
    VarExpr ve = new VarExpr(var, typeHint(sym));
    Expr init = analyze(C.EXPRESSION, macroexpand(RT.third(form)));
    if(init instanceof FnExpr)
        ((FnExpr)init).name = "FN__" + munge(var.name.toString()) + "__" + RT.nextID();

    return new DefExpr(ve, init);
}

static Symbol baseSymbol(Symbol sym) {
    String base = baseName(sym);

    if(base == sym.name) //no typeHint
        return sym;

    return Symbol.intern(base);
}

static String baseName(Symbol sym){
    int slash = sym.name.indexOf('/');
    if(slash > 0)
       return sym.name.substring(0, slash);
    return sym.name;
}

static String typeHint(Symbol sym){
    int slash = sym.name.indexOf('/');
    if(slash > 0)
       return sym.name.substring(slash + 1);
    return null;
}

private static Expr analyzeSymbol(Symbol sym) throws Exception {
    if(sym instanceof Keyword)
        return registerKeyword((Keyword)sym);
    else if(sym instanceof HostSymbol)
        return new HostExpr((HostSymbol)sym);
    else
        {
        String typeHint = typeHint(sym);
        sym = baseSymbol(sym);
        LocalBinding b = referenceLocal(sym);
        if(b != null)
            return new LocalBindingExpr(b, typeHint);
        Var v = lookupVar(sym);
        if(v != null)
            return new VarExpr(v, typeHint);
        throw new Exception("Unable to resolve symbol: " + sym.name + " in this context");
        }
}

static Var lookupVar(Symbol sym){
    Module module = (Module) _CRT_MODULE.getValue();
    Var v = module.find(sym);
    if(v != null)
        return v;
    for(ISeq seq = RT.seq(USES.getValue());seq != null;seq = RT.rest(seq))
        {
        module = (Module) ((IMapEntry)RT.first(seq)).key();
        v = module.find(sym);
        if(v != null && !v.hidden)
            return v;
        }
    return null;
}

static Object macroexpand(Object x){
    return x; //placeholder
}

private static KeywordExpr registerKeyword(Keyword keyword) {
    IPersistentMap keywordsMap = (IPersistentMap) KEYWORDS.getValue();
    KeywordExpr ke = (KeywordExpr) RT.get(keyword,keywordsMap);
    if(ke == null)
        KEYWORDS.setValue(RT.assoc(keyword, ke = new KeywordExpr(keyword),keywordsMap));
    return ke;
}

private static void registerVar(Var var) {
    IPersistentMap varsMap = (IPersistentMap) VARS.getValue();
    if(RT.get(var,varsMap) == null)
        VARS.setValue(RT.assoc(var, var, varsMap));
}

private static void registerFn(FnExpr fn) {
    FNS.setValue(RT.cons(fn, (IPersistentCollection) FNS.getValue()));
}

static void closeOver(LocalBinding b,FnMethod method){
    if(b != null && method != null && RT.get(b,method.locals) == null)
        {
        b.isClosed = true;
        method.fn.closes = (IPersistentMap)RT.assoc(b, b, method.fn.closes);
        closeOver(b,method.parent);
        }
}

static LocalBinding referenceLocal(Symbol sym) {
    LocalBinding b = (LocalBinding) RT.get(sym, LOCAL_ENV.getValue());
    if(b != null)
        {
        b.valueTaken = true;
        closeOver(b,(FnMethod) METHOD.getValue());
        }
    return b;
}

private static void registerLocal(LocalBinding b) {
    IPersistentMap localsMap = (IPersistentMap) LOCAL_ENV.getValue();
    LOCAL_ENV.setValue(RT.assoc(b.sym, b, localsMap));
    FnMethod method = (FnMethod) METHOD.getValue();
    method.locals = (IPersistentMap) RT.assoc(b, b, method.locals);
}
/*
(defun reference-var (sym)
  (let ((b (first (member sym *var-env* :key (lambda (b)
                                               (@ :symbol b))))))
    (labels
        ((check-closed (b frame)
           (when (and b frame
                      (not (member b (@ :local-bindings frame)))) ;closed over
             (setf (@ :closed? b) t)
             (pushnew b (@ :closes frame))
             (check-closed b (@ :parent frame)))))
      (check-closed b *frame*))
    b))
    */

static String resolveHostClassname(String classname) throws Exception {
    if(classname.indexOf('.') != -1)    //presume fully qualified if contains .
        return classname;
    IPersistentMap importMap = (IPersistentMap) IMPORTS.getValue();
    String fullyQualifiedName = (String) RT.get(classname,importMap);
    if(fullyQualifiedName == null)
        throw new Exception("Can't resolve type name: " + classname);
    return fullyQualifiedName;
}



static class KeyParam{
    public KeyParam(LocalBindingExpr b, Expr init) {
        this.bindingExpression = b;
        this.init = init;
        kw = registerKeyword((Keyword) Symbol.intern(":" + bindingExpression.b.sym.name));
    }

    public KeyParam(LocalBindingExpr b) {
        this(b,NIL_EXPR);
    }

    LocalBindingExpr bindingExpression;
    Expr init;
    KeywordExpr kw;
}


static class NilExpr extends AnExpr{
    public void emitExpression() throws Exception{
        format("null");
    }
}

static class LiteralExpr extends AnExpr{
    final Object val;

    public LiteralExpr(Object val){
        this.val = val;
    }

    public void emitExpression() throws Exception{
        format("~S",val);
    }
}

static class NotExpr extends AnExpr{
    final Expr expr;

    public NotExpr(Expr expr){
        this.expr = expr;
    }

    public void emitStatement() throws Exception {
        //just execute expr for side effects - no negation
        expr.emitStatement();
    }

    public void emitExpression() throws Exception {
        format("((");
        expr.emitExpression();
        format("==null)?RT.T:null)");
    }

}

static class CharExpr extends AnExpr{
    final Character val;

    public CharExpr(Character val){
        this.val = val;
    }

    public void emitExpression() throws Exception{
        format("'~A'",val);
    }
}


static class HostExpr extends AnExpr{
    final HostSymbol sym;

    public HostExpr(HostSymbol sym){
        this.sym = sym;
    }

    public void emitExpression() throws Exception{
        if(sym instanceof ClassSymbol)
            format("~A.class", resolveHostClassname(((ClassSymbol) sym).className));
    }
}
/*
static class SymExpr extends AnExpr{
    Symbol sym;
    String typeHint;

    public SymExpr(Symbol sym, String typeHint){
        this.sym = sym;
        this.typeHint = typeHint;
    }

    public void emitExpression() throws Exception{
        format("~A", munge(sym.name));
    }
}
*/
static class KeywordExpr extends AnExpr{
    final Symbol sym;

    public KeywordExpr(Symbol sym){
        this.sym = sym;
    }

    public void emitExpression() throws Exception {
        format("~A", munge(sym.name));
    }
}

static class LocalBinding{
    final Symbol sym;
    boolean isClosed = false;
    boolean isParam = false;
    final int id = RT.nextID();
    String typeHint;
    public boolean valueTaken = false;
    boolean isAssigned = false;
    FnExpr letfn = null;


    public LocalBinding(Symbol sym) {
        this.sym = sym;
    }

    public String getName(){
        return munge(sym.name) + (isParam?"":("__" + id));
    }

    boolean needsBox(){
        return (isClosed && isAssigned)
                ||
                letfn != null && isClosed && valueTaken;
    }

    boolean bindsToStaticFn() {
        return letfn != null && letfn.willBeStaticMethod();
    }

    String typeDeclaration(){
        if(needsBox())
            return "clojure.lang.Box";
        return "Object";
    }

    String getExpr(){
        if(needsBox())
            return getName() + ".val";
        return getName();
    }

    void emitDeclaration(String init) throws Exception {
        format("~A ~A = ", typeDeclaration(), getName());
        if(needsBox())
            format("new clojure.lang.Box(~A);~%", init);
        else
            format("~A;~%", init);
    }
}

static class LocalBindingExpr extends AnExpr{
    final LocalBinding b;
    final String typeHint;

    public LocalBindingExpr(LocalBinding b, String typeHint){
        this.b = b;
        this.typeHint = typeHint;
    }

    public void emitExpression() throws Exception{
        format("~A", b.getExpr());
    }
}

static class VarExpr extends AnExpr{
    final Var var;
    final String typeHint;

    public VarExpr(Var var, String typeHint){
        this.var = var;
        this.typeHint = typeHint;
    }

    public String getName() {
        return munge(var.toString());
    }

    public void emitExpression() throws Exception{
        format("~A.getValue()", getName());
    }
}

static class DefExpr extends AnExpr{
    final VarExpr var;
    final Expr init;

    public DefExpr(VarExpr var, Expr init){
        this.var = var;
        this.init = init;
    }

    public void emitExpression() throws Exception{
        format("~A.bind(~A)", var.getName(),init.emitExpressionString());
    }
}

public static void main(String[] args) throws Exception {
    args=new String[]{"pfeng","one", "E:\\clojure\\yanjiuclojure\\src\\lisp\\test.lisp"};
    String pkg = args[0];
    String classname = args[1];
    LineNumberingPushbackReader[] rs = new LineNumberingPushbackReader[args.length - 2];
    String ret;
    try
        {
        for(int i=0;i

你可能感兴趣的:(clojure git checkout bb50ab52)