clojure 代碼分析 2022年3月22日

image.png

方便學(xué)習(xí) 測(cè)試 生成 java 代碼的

args=new String[]{"feng", "one","E:\clojure\yanjiuclojure\src\boot.clj"};

關(guān)于eval 和 emit 的區(qū)別與聯(lián)系

在compiler 中 最外層有 compile 和 eval analyze
其中 compile 和 eval 都會(huì)調(diào)用 analyze . 而在 analyze 中會(huì)生成fn 的compile .
最外層的 compile 生成的是init 加載類等. 也會(huì)生成class文件. eval 不會(huì)在磁盤上落地class文件.

關(guān)鍵代碼在 FnExpr 中 .因?yàn)槊總€(gè) fn 都要編譯成一個(gè)class 才能調(diào)用. (除了special)


image.png
image.png

clojure 代碼reader 出來(lái)后 都是 symbol var list set map 等對(duì)象. 這里就是同像性的來(lái)源, 代碼是數(shù)據(jù), 符合標(biāo)準(zhǔn)的數(shù)據(jù)也能轉(zhuǎn)為代碼.

調(diào)試的時(shí)候 Compiler.java 中的 暫時(shí)去掉 有點(diǎn)礙事. (學(xué)習(xí)的時(shí)候靈活之.)

private static Var ensureMacroCheck() throws ClassNotFoundException, IOException {
    if(MACRO_CHECK == null) {
        synchronized(MACRO_CHECK_LOCK) {
            if(MACRO_CHECK == null) {
                MACRO_CHECK_LOADING = true;
                RT.load("clojure/spec/alpha");
                RT.load("clojure/core/specs/alpha");
                MACRO_CHECK = Var.find(Symbol.intern("clojure.spec.alpha", "macroexpand-check"));
                MACRO_CHECK_LOADING = false;
            }
        }
    }
    return MACRO_CHECK;
}
image.png

https://athos.hatenablog.com/entry/20110605/clojure_internal_ast

http://blog.guillermowinkler.com/blog/2014/04/13/decompiling-clojure-i/

lisp 中的 cons 是個(gè)重要概念 . 他與數(shù)組完全不同..
https://blog.csdn.net/baozi3026/article/details/7973147 說(shuō)的一般,但到門口了.
https://www.cnblogs.com/adolph-suyu/p/3639020.html 這個(gè)說(shuō)的較好

仔細(xì)看第三章cons的說(shuō)明,發(fā)現(xiàn)cons放在c語(yǔ)言里面,無(wú)非就是一個(gè)如下的結(jié)構(gòu)
typedef struct _cons cons;
struct  _cons
{
    void*     content;   //cons的內(nèi)容
    cons*     next;
}

http://yaodanzhang.com/blog/2015/03/16/three-implementations-of-cons-in-lisp/

https://stackoverflow.com/questions/12389303/clojure-cons-vs-conj-with-lazy-seq

https://gigamonkeys.com/book/they-called-it-lisp-for-a-reason-list-processing.html

因?yàn)?cons 單元格中的值可以引用任何類型的對(duì)象授嘀,所以您可以通過(guò)將 cons 單元格鏈接在一起來(lái)構(gòu)建更大的結(jié)構(gòu)滑沧。列表是通過(guò)將鏈中的 cons 單元鏈接在一起來(lái)構(gòu)建的栈妆。列表的元素保存在 cons 單元格的CARs 中翠霍,而到后續(xù) cons 單元格的鏈接保存在 CDRs 中。鏈中的最后一個(gè)單元格有一個(gè)CDRof NIL还最,正如我在第 4 章中提到的那樣魂迄,它表示空列表以及布爾值 false。

這種安排絕不是 Lisp 獨(dú)有的。它被稱為 單鏈表措近。然而溶弟,除了 Lisp 家族之外,很少有語(yǔ)言為這種不起眼的數(shù)據(jù)類型提供如此廣泛的支持瞭郑。(feng 這是env 和 樹 的核心啊!!)

雖然 cons 單元格和列表通常被認(rèn)為是同義詞辜御,但這并不完全正確——正如我之前提到的,您可以使用列表列表來(lái)表示樹屈张。正如本章討論的函數(shù)允許您將由 cons 單元構(gòu)建的結(jié)構(gòu)視為列表擒权,其他函數(shù)允許您使用 cons 單元來(lái)表示樹、集合和兩種鍵/值映射阁谆。我將在下一章討論其中的一些功能碳抄。

image.png

其實(shí),Lisp中所有這些符號(hào)场绿,都是Symbol剖效。 什么變量,什么函數(shù)焰盗,都是浮云璧尸。上面的 例子中,緊接著用fboundp判斷Symbol var 的Function域是否綁定熬拒,這個(gè)時(shí)候?yàn)榧佟?然后我們定義了一個(gè)名為 var 的函數(shù)爷光,之后再判斷,則已然為真澎粟。這也是為什么蛀序, 在Lisp中某個(gè)函數(shù)可以和某個(gè)變量同名的原因所在。 從這段代碼中我們也可以看出 defvar/defun這些操作符活烙、宏所做事情的本質(zhì)哼拔。
More More More
事情就這樣結(jié)束了?Of course not瓣颅。還有很多上文提到的疑惑沒有解決倦逐。首先,Symbol是 如此復(fù)雜,那么Lisp如何決定它在不同環(huán)境下的含義呢檬姥?Symbol雖然是個(gè)對(duì)象曾我,但它并不像 C++中的對(duì)象一樣,它出現(xiàn)時(shí)并不指代自己健民!不同應(yīng)用環(huán)境下抒巢,它指代的東西也不一樣。這 些指代主要包括變量和函數(shù)秉犹,意思是說(shuō): Symbol出現(xiàn)時(shí)蛉谜,要么指的是它的Value,要么是 它的Function崇堵。 這種背地里干的事情型诚,也算是造成迷惑的一個(gè)原因。

當(dāng)一個(gè)Symbol出現(xiàn)在一個(gè)List的第一個(gè)元素時(shí)鸳劳,它被處理為函數(shù)狰贯。這么說(shuō)有點(diǎn)迷惑人,因?yàn)?它帶進(jìn)了Lisp中代碼和數(shù)據(jù)之間的模糊邊界特性赏廓。簡(jiǎn)單來(lái)說(shuō)涵紊,就是當(dāng)Symbol出現(xiàn)在一個(gè)括號(hào) 表達(dá)式(s-expression)中第一個(gè)位置時(shí),算是個(gè)函數(shù)幔摸,例如:
https://blog.csdn.net/dc_726/article/details/8774740

下面的例子說(shuō)明了Evaluator的作用:

[1]> (foo 1 2)
*** - EVAL: undefined function FOO

毫無(wú)疑問摸柄,(foo 1 2)是一個(gè)有效的S-expression,其通過(guò)Reader這關(guān)是沒有問題的既忆。但是當(dāng)Evaluator對(duì)S-expression"(foo 1 2)"進(jìn)行驗(yàn)證求值時(shí)塘幅,卻發(fā)現(xiàn)無(wú)法找到函數(shù)foo的定義,這行源碼不合法尿贫。

簡(jiǎn)單總結(jié)Reader和Evaluator的工作流程就是:"源碼文本"通過(guò)Reader轉(zhuǎn)換為有效的"S-expressions"电媳,后者則由Evaluator轉(zhuǎn)換成有效"Lisp Form"并求值得出結(jié)果。

clojure 早期實(shí)現(xiàn)是用 clisp 生成一個(gè)clojure.java 的
https://blog.csdn.net/acool555/article/details/6918248 clisp 較好的文章

https://www.bilibili.com/video/BV1XZ4y1k7T7 good

image.png

image.png

image.png

非常感謝這個(gè)作者


image.png

程序中看管理!:: 直接數(shù)字計(jì)算簡(jiǎn)單但不靈活. (初級(jí)管理) 所以需要先安置各個(gè)變量(職位,雖然難一點(diǎn),但這就是 團(tuán)伙和團(tuán)隊(duì)的本質(zhì)區(qū)別. 變量管理的細(xì) 變量不亂,就是好管理.) (二級(jí)管理)

image.png

第一次看到 自動(dòng)解析 . 對(duì)自動(dòng)化工具產(chǎn)生了一點(diǎn)好感..


image.png

函數(shù) 只是一塊block 一組代碼的抽象.

image.png

尾遞歸 優(yōu)化成迭代.

http://www.yinwang.org/blog-cn/2012/07/04/dan-friedman

印第安納大學(xué).... 好書.. . nanopass 的作者 參與者 寫的書
https://www.brinckerhoff.org/clements/2198-csc431/essentials-of-compilation.pdf

https://wphomes.soic.indiana.edu/jsiek/ 作者老師的主頁(yè).
2022年3月27日 ChezScheme 現(xiàn)在教程太少. 源碼看不懂. 暫時(shí)停止. 繼續(xù)主攻clojure

git checkout da14d89c hello main

https://blog.ndk.io/clojure-compilation.html

clojure 因?yàn)楹瘮?shù)是first class 對(duì)應(yīng)到j(luò)ava 就是一個(gè)fn 一個(gè) class
clojure 發(fā)展至今初次啟動(dòng) 會(huì)有clojure.core 自動(dòng)加載初始化.
每個(gè)lisp 都有一個(gè) runtime clisp chezscheme ..等都是c 寫的runtime 自己需要實(shí)現(xiàn)gc
clojure 用的是用java寫的runtime 實(shí)現(xiàn) Symbol Var NameSpace RT ..等幾個(gè)關(guān)鍵的就ok了. 其余的用jvm.. 怪不得這么穩(wěn)定,高可用.. 阿彌陀佛


image.png

core_init.class
const__469

        const__12 = (AFn)RT.map(new Object[]{
RT.keyword((String)null, "line"), 13, 
RT.keyword((String)null, "column"), 1, 
RT.keyword((String)null, "file"), "clojure/core.clj"});

git checkout 4ff27c7a 加入了 LispReader.java ..

lisp 的知識(shí)中 剛開始不易接觸到的是 runtime . 似乎這個(gè)大家都會(huì)了...或者覺得,實(shí)現(xiàn)的方式很多,不值得一說(shuō). 繆也. 理論 與 實(shí)現(xiàn)同樣重要. 搞懂一個(gè)runtime 很不容易,需要先要學(xué)理論,然后再精通一門語(yǔ)言,然后根據(jù)該語(yǔ)言來(lái)實(shí)現(xiàn). 一般都是c . clojure 使用的是java .
clojure 在早期 4ff27c7a 把runtime 和 Lispreader Compiler 分開存放的. 但后期放到一起了.都是runtime了. packagename 也改為了 clojure.lang . 因?yàn)閘isp 需要在運(yùn)行時(shí)動(dòng)態(tài) 編譯 lisp代碼. 所以 編譯器也是runtime的重要一環(huán).

image.png

remove 改為 without 是什么 心里?? git checkout db58898d

image.png

clojure list 本質(zhì)是cons !

git checkout 987dad56 加入了 Compiler.java 但是空的

image.png

哈哈哈.. 在 51c468f8(2006.9) 把NameSpace 改為了Module ... now (2022年3月28日) 又改回了..

git checkout bbabe65c Compiler.java 有了可以調(diào)試 學(xué)習(xí)的代碼.
此處 macroexpand 還未實(shí)現(xiàn).

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

munge 方法

static public  IPersistentMap CHAR_MAP =
        new PersistentArrayMap('-', "_HY_",
                               '.', "_DT_",
                               ':', "_CL_",
                               '+', "_PL_",
                               '>', "_GT_",
                               '<', "_LT_",
                               '=', "_EQ_",
                               '~', "_TL_",
                               '!', "_EP_",
                               '@', "_AT_",
                               '#', "_SH_",
                               '$', "_DS_",
                               '%', "_PT_",
                               '^', "_CT_",
                               '&', "_AM_",
                               '*', "_ST_",
                               '{', "_LB_",
                               '}', "_RB_",
                               '[', "_LK_",
                               ']', "_RK_",
                               '/', "_SL_",
                               '\\',"_BS_",
                               '?', "_QM_");

static String munge(String name){
    StringBuilder sb = new StringBuilder();
    for(char c : name.toCharArray())
        {
        String sub = (String) CHAR_MAP.get(c);
        if(sub != null)
            sb.append(sub);
        else
            sb.append(c);
        }
    return sb.toString();
}

    public static void main(String[] args) {
        System.out.println(munge("feng.lib #{} '[abc]"));
      //feng_DT_lib _SH__LB__RB_ '_LK_abc_RK_
    }

git checkout 3302b103 出現(xiàn)main 測(cè)試方法.
測(cè)試該方法 準(zhǔn)備個(gè)測(cè)試文件

(def a 3)
(fn (x) (do x 2))
public static void main(String[] args) throws Exception {
    args=new String[]{"pfeng","one", "E:\\clojure\\yanjiuclojure\\src\\lisp\\test.lisp"};
 args = new String[]{"pfeng", "one", "E:\\clojure\\yanjiuclojure\\src\\one.clj"};
輸出 

/* Generated by Clojure */

package pfeng;
public class one{
static Var clj_HY_user_CL_a;
static public class FN__2 extends AFn{
public Object invoke(Object x) throws Exception{
x;
return %S;
}
}
public void load() throws Exception{
clj_HY_user_CL_a = Module.intern("clj-user","a");
clj_HY_user_CL_a.bind(%S);
(new FN__2());
}
}
這里的%s 是bug 

2022年3月28日 現(xiàn)在看 Compiler 理解非常困難. 什么東西,什么時(shí)候從lisp的 fn do ..if 轉(zhuǎn)為 java xx格式. 需要耐心攻關(guān)..

(def a 3)
(def one (fn (x) (if (a x 2) 3 4)))

生成如下 ,此時(shí)的 [Compiler.java] http://www.reibang.com/p/255b6190541c

/* Generated by Clojure */

package pfeng;

import clojure.lang.*;

public class one {
    static Var clj_DSH_user_CLN_a;
    static Var clj_DSH_user_CLN_one;

    static public class FN__one__2 extends AFn {
        public Object invoke(Object x) throws Exception {
            if (((IFn) clj_DSH_user_CLN_a.getValue()).invoke(x, 2) != null) {
                return 3;
            } else {
                return 4;
            }
        }
    }

    public void load() throws Exception {
        clj_DSH_user_CLN_a = Module.intern("clj-user", "a");
        clj_DSH_user_CLN_one = Module.intern("clj-user", "one");
        clj_DSH_user_CLN_a.bind(3);
        clj_DSH_user_CLN_one.bind((new FN__one__2()));
    }
}

git checkout 3ed36822 rich hickey 老師 體驗(yàn)了一把 antlr . 哈哈哈哈..
rh 難得一見的注釋.. declared exceptions are an incredibly bad idea !!!


image.png

Lisper read 出來(lái)的都是clojure runtime 內(nèi)置的數(shù)據(jù). 所謂同像性在這里明確體現(xiàn)了.
(hao [ 3 2] (23 33)) (Symbol PersistentVector IteratorSeq .. good.

92075ac2 got rid of ANTLR reader (擺脫了 antlr :)

c894ed9b 出現(xiàn) eval 方法了... 在新的類 BytecodeCompiler.java

手動(dòng)編譯成字節(jié)碼的 只有 fn 對(duì)應(yīng)一個(gè)class 里面的所有都是 Object Var AFn RT Arrays Symbol PersistentVector PersistentList ILookupThunk LockingTransaction ....等被從lisp 代碼中轉(zhuǎn)換過(guò)來(lái)的 調(diào)用invoke getRawRoot......阿彌陀佛

例如 core$sort.class

package clojure;

import clojure.core.meta__5483;
import clojure.core.seq__5467;
import clojure.core.to_array;
import clojure.core.with_meta__5485;
import clojure.lang.AFunction;
import clojure.lang.PersistentList;
import clojure.lang.RT;
import clojure.lang.Var;
import java.util.Arrays;
import java.util.Comparator;

public final class core$sort extends AFunction {
    public static final Var const__1 = (Var)RT.var("clojure.core", "compare");

    public core$sort() {
    }

    public static Object invokeStatic(Object comp, Object coll) {
        Object var10000 = seq__5467.invokeStatic(coll);
        if (var10000 != null) {
            if (var10000 != Boolean.FALSE) {
                Object a = to_array.invokeStatic(coll);
                Object[] var3 = (Object[])a;
                Object var10001 = comp;
                comp = null;
                Arrays.sort(var3, (Comparator)var10001);
                var10000 = a;
                a = null;
                var10000 = seq__5467.invokeStatic(var10000);
                var10001 = coll;
                coll = null;
                var10000 = with_meta__5485.invokeStatic(var10000, meta__5483.invokeStatic(var10001));
                return var10000;
            }
        }

        var10000 = PersistentList.EMPTY;
        return var10000;
    }

    public Object invoke(Object var1, Object var2) {
        Object var10000 = var1;
        var1 = null;
        Object var10001 = var2;
        var2 = null;
        return invokeStatic(var10000, var10001);
    }

    public static Object invokeStatic(Object coll) {
        Object var10000 = const__1.getRawRoot();
        Object var10001 = coll;
        coll = null;
        return invokeStatic(var10000, var10001);
    }

    public Object invoke(Object var1) {
        Object var10000 = var1;
        var1 = null;
        return invokeStatic(var10000);
    }
}

8a36fd5f renamed DynamicVar -> Var

clojure list form 中包含的 數(shù)據(jù)結(jié)構(gòu)


image.png

The first Clojure compiler was a Common Lisp program that generated Java and C# code. Java and C# are extremely similar and their intersection determined the first cut of what Clojure expected, but did not necessarily require, of a host.
(是 clisp )
The compiler was moved to Java and eventually
(prior to release) generated bytecode directly. Only interop on the JVM is discussed below.

I was happy to find that Java’s collection class library authors a) used interfaces, and b) declared all of the mutating methods of the collection interfaces optional.
(keai )

Vars. Clojure also has a global variable system: vars. These references are interned in names?paces and are the storage locations to which free symbolic references in code are resolved and
bound. Vars are created and interned via def and its various flavors. Vars can be dynamically
rebound on an opt-in basis. The primary purpose of the var system is for references to functions,
and their variable nature is what supports dynamic development.

feng !(編譯: first 你必須要弄清楚 源語(yǔ)言 和 目標(biāo)語(yǔ)言,弄清楚每個(gè)源expr(element atom ) 將會(huì)變成目標(biāo)語(yǔ)言的確定格式.)
作者: dmitrySoshnikov dmitrySoshnikov.com (niu ren)
https://www.bilibili.com/video/BV1XZ4y1k7T7 good 課程,該老師還有后續(xù)的 vm 課程.
深入 JavaScript 運(yùn)行時(shí)細(xì)節(jié)和有關(guān)原型的種種真相推薦 http://dmitrysoshnikov.com/ 的 ECMA-262-3 in detail庆亡,這是我讀過(guò)的最透徹的關(guān)于 JavaScript 運(yùn)行機(jī)制和 object 繼承機(jī)制的解釋匾乓。
鏈接:https://juejin.cn/post/6844903477609660424

Building a Virtual Machine for Programming Language
Essential of low-level interpretation

image.png

https://www.udemy.com/course/virtual-machine/
good

image.png

https://juejin.cn/post/6844903477609660424

#### [Building a Virtual Machine for Programming Language](http://dmitrysoshnikov.com/courses/virtual-machine/)

Lecture 1: VM pipeline ??
Lecture 2: Stack vs. Register VM
Lecture 3: Logger implementation
Lecture 4: Basic numbers: introduction to Stack
Lecture 5: Math binary operation
Lecture 6: Strings: introduction to Heap and objects
Lecture 7: Syntax | Parser implementation
Lecture 8: Compiler | Bytecode
Lecture 9: Complex expressions
Lecture 10: Boolean | Comparison
Lecture 11: Control flow: Branch instruction
Lecture 12: Disassembler
Lecture 13: Global object | Variables
Lecture 14: Blocks and Local variables
Lecture 15: While loops
Lecture 16: Native functions | Function calls
Lecture 17: User-defined functions
Lecture 18: Call stack | Function calls
Lecture 19: Lambda functions
Lecture 20: Bytecode optimizations
Lecture 21: Closures | Scope analysis
Lecture 22: Closures | Compilation
Lecture 23: Closures | Runtime
Lecture 24: Garbage collection
Lecture 25: Mark-Sweep GC
Lecture 26: OOP | Classes
Lecture 27: OOP | Instances
Lecture 28: Super classes | Inheritance
Lecture 29: Final VM executable
Building a Parser from scratch

http://dmitrysoshnikov.com/compilers/writing-a-memory-allocator/
https://justinmeiners.github.io/lc3-vm/

java Variadic 可變參數(shù) 不定長(zhǎng)參數(shù) a(int ...a ) 是個(gè)語(yǔ)法糖, java 會(huì)把 a 弄成 int[] a
Methods which uses variable arguments (varargs, arguments with three dots) are known as variadic functions.
注意:
FnExpr 對(duì)應(yīng)的是Class
FnMethod 對(duì)應(yīng)的是class 中的具體 invoke 方法
(來(lái)源: https://github.com/clojure/tools.emitter.jvm.git )

(defmethod -emit :fn
  [{:keys [form internal-name variadic?] :as ast}
   frame]
  (let [class-name (str (namespace-munge *ns*)
                        "$"
                        (munge internal-name))
        super (if variadic? :clojure.lang.RestFn :clojure.lang.AFunction)
        ast (assoc ast
              :class-name class-name
              :super super)]
    (emit-class ast frame)))
static class FnMethod{
    //when closures are defined inside other closures,
    //the closed over locals need to be propagated to the enclosing fn
    final FnMethod parent;
    //localbinding->localbinding
    IPersistentMap locals = null;
    //localbinding->localbinding
    PersistentVector reqParms = PersistentVector.EMPTY;
    LocalBinding restParm = null;   // 可變參數(shù), 不定長(zhǎng)參數(shù). 
    Expr body = null;
    FnExpr fn;

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

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

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.getstatic
這里加點(diǎn) jvm 虛擬機(jī)執(zhí)行棧細(xì)節(jié). 例如 返回結(jié)果 一直在棧頂. 參數(shù)都是通過(guò)棧來(lái)傳送的.

image.png

Compiler.java 中的 enclosingMethod closes 是在
getEnclosingClass 是類中的 封閉類.
C:\Program Files\Java\jdk1.8.0_101\src.zip!\java\lang\Class.java

一、getEnclosingXX

/**
     * getEnclosingClass:該類是在那個(gè)類中定義的又谋, 比如直接定義的內(nèi)部類或匿名內(nèi)部類
     * getEnclosingConstructor:該類是在哪個(gè)構(gòu)造函數(shù)中定義的拼缝,比如構(gòu)造方法中定義的匿名內(nèi)部類
     * getEnclosingMethod:該類是在哪個(gè)方法中定義的,比如方法中定義的匿名內(nèi)部類
     * getDeclaredClasses :  該類包含的內(nèi)部類
     *
     * @param cls
     */
    private static void getEnclosing(Class cls) {
        Class enclosingClass = cls.getEnclosingClass();
        Constructor enclosingConstructor = cls.getEnclosingConstructor();
        Method enclosingMethod = cls.getEnclosingMethod();
        System.out.println("enclosingClass=" + enclosingClass);
        System.out.println("enclosingConstructor=" + enclosingConstructor);
        System.out.println("enclosingMethod=" + enclosingMethod);
        for (Class c: Outer1.class.getDeclaredClasses()){
            System.out.println("decar:" + c.getName());
        }
        System.out.println("decar:" + cls.getDeclaredMethods());

    }

http://www.reibang.com/p/107c05b29290
// There are five kinds of classes (or interfaces):
// a) Top level classes
// b) Nested classes (static member classes)
// c) Inner classes (non-static member classes)
// d) Local classes (named classes declared within a method)
// e) Anonymous classes

image.png

A Symbol is a canonicalized string.(符號(hào)是標(biāo)準(zhǔn)化的字符串彰亥。) (from: hotspot symbol.hpp)


image.png

https://blog.csdn.net/u013928208/article/details/106758062 jvm 啟動(dòng)分析

image.png

而OpenJ9其自身是基于IBM開源的OMR項(xiàng)目所構(gòu)建咧七,OMR項(xiàng)目由一個(gè)高度集成的開放源碼C和c++組件,可用于構(gòu)建大量的語(yǔ)言,運(yùn)行時(shí)支持許多不同的硬件和操作系統(tǒng)平臺(tái)任斋。這些組件包括但不限于:內(nèi)存管理继阻,線程處理,平臺(tái)端口(抽象)庫(kù),診斷支持瘟檩,監(jiān)控支持抹缕,垃圾收集和本地實(shí)時(shí)編譯。OMR的意圖在于讓實(shí)現(xiàn)語(yǔ)言的人能夠重用IBM在Java運(yùn)行時(shí)方面所投入的數(shù)百開發(fā)人年所取得的成果墨辛,能夠受益的包含已有的語(yǔ)言如Ruby卓研、Python、Javascript等等睹簇,它還能加快新語(yǔ)言的創(chuàng)建過(guò)程奏赘。

作者:崩天的勾玉
鏈接:https://www.zhihu.com/question/65452135/answer/2280521447
來(lái)源:知乎
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)太惠,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處磨淌。

https://www.infoq.cn/article/PQi0LYV7HhmsgHkPzkJI 目前一切語(yǔ)言底層的運(yùn)行時(shí)
都是c寫的. 因?yàn)椴僮飨到y(tǒng)是c寫的..

2022年4月8日 4b899d76 加入了 boot.clj 參數(shù) 用了 [ ] 中括號(hào)


image.png

d43857f2 刪除了 OldCompiler

https://asm.ow2.io/developer-guide.html asm 最好的教程.

從 Lisp read 到 form 后 (共有 15種 form) Compiler parse 成 Expr (共有58種 Expr)


image.png
;Expr expr = analyze(C.EVAL, form);
(let [
      expr (Compiler/analyze Compiler$C/EVAL '(+ 3 2))  ;Compiler$StaticMethodExpr
      expr (Compiler/analyze Compiler$C/EVAL (read-string "(+ 3 2)"))  ;Compiler$StaticMethodExpr
      expr (Compiler/analyze Compiler$C/EVAL (read-string "+"))  ;Compiler$VarExpr
      expr (Compiler/analyze Compiler$C/EVAL (read-string "(new Compiler)"))  ;Compiler$NewExpr
      expr (Compiler/analyze Compiler$C/EVAL (read-string "(Compiler.)"))  ;Compiler$NewExpr  ;最后一個(gè)點(diǎn)是 new 的語(yǔ)法糖
      ;expr (Compiler/analyze Compiler$C/EVAL (read-string "3"))  ;Compiler$NumberExpr
      ;expr (Compiler/analyze Compiler$C/EVAL (read-string "prn"))  ;Compiler$VarExpr
      ;expr (Compiler/analyze Compiler$C/EVAL (read-string "(map prn [3 2 'a])")) ;Compiler$InvokeExpr
      ]
 ;(prn (.get (.var expr)))
 (prn (.c expr))
 (w/prewalk (fn [x] (prn x (type x)) x) expr)
 )



;=> "classes"  必須要在當(dāng)前目錄新建 class 文件夾
*compile-path*
(compile (symbol "cfenxi.testclass"))
;(compile (symbol "clojure.java.io"))
C
Recur

Expr

LiteralExpr  ;字面量
NumberExpr
ConstantExpr
NilExpr
BooleanExpr
StringExpr
KeywordExpr

UntypedExpr     ;非類型的.
MonitorEnterExpr
MonitorExitExpr
ThrowExpr

DefExpr
AssignExpr   ;(set! target val) set! 開頭
VarExpr       ;似乎是Class 中的filed..
TheVarExpr    ;(var map)  var 和 do fn* ...都是special form 特殊形式. (c中叫關(guān)鍵字..)
ImportExpr    ; ns 中 :import 調(diào)用的是 clojure.core/import

AssignableExpr  ;接口
MaybePrimitiveExpr ;接口 用于原生優(yōu)化.




HostExpr      ;與java交互的expr  (. x methodname-sym args+)
FieldExpr     ; 一個(gè)abstract 空類.
InstanceFieldExpr
StaticFieldExpr   
MethodExpr
InstanceMethodExpr

; 這里高度注意. 因?yàn)閕nline 所以+是Compiler$StaticMethodExpr
(. Math pow 2 4) ; -> 16.0
(Math/pow 2 4)  這個(gè)是上面的語(yǔ)法糖.

StaticMethodExpr  (defn + [x y] (. clojure.lang.Numbers (add x y)))   


UnresolvedVarExpr   ;幫助類. 無(wú)法解析的 沒有綁定的Symbol


TryExpr

NewExpr   ;(new xxx) 語(yǔ)法糖(xxx.)
MetaExpr  ; 元數(shù)據(jù) .
IfExpr
EmptyExpr
ListExpr  ;一個(gè)沒用的. seq 已經(jīng)可以了.
MapExpr
SetExpr
VectorExpr
KeywordInvokeExpr
InstanceOfExpr
StaticInvokeExpr
InvokeExpr

FnExpr   ; 最核心的 Expr .

ObjExpr
PATHTYPE
PathNode
PSTATE
FnMethod
ObjMethod
LocalBinding
LocalBindingExpr
BodyExpr
BindingInit
LetFnExpr
LetExpr
RecurExpr
CompilerException
NewInstanceExpr
NewInstanceMethod
MethodParamExpr
CaseExpr

https://www.braveclojure.com/read-and-eval/ good book

2022年4月12日 現(xiàn)在到了 inline 。垛叨。。 注意柜某! 專業(yè)級(jí)代碼嗽元,,每一個(gè)細(xì)節(jié)都是坎喂击。剂癌。!

(defn +
  "Returns the sum of nums. (+) returns 0. Does not auto-promote
  longs, will throw on overflow. See also: +'"
  {:inline (nary-inline 'add 'unchecked_add)
   :inline-arities >1?
   :added "1.2"}
  ([] 0)
  ([x] (cast Number x))
  ([x y] (. clojure.lang.Numbers (add x y)))
  ([x y & more]
     (reduce1 + (+ x y) more)))
image.png
image.png

2022年4月13日23點(diǎn)06分 翰绊。佩谷。。 終于追到了 xxx.xxx. last dot 轉(zhuǎn)為了 (new xxx.xxx) 然后接著才會(huì)
進(jìn)入 anylzeSymbol 中查找不到該類 后就會(huì)報(bào)錯(cuò)监嗜。 不是unresloved symbol 是 classnotfind exception谐檀。

static class Parser implements Compiler.IParser {
            Parser() {
            }

            public Compiler.Expr parse(Compiler.C context, Object frm) {
                int line = Compiler.lineDeref();
                int column = Compiler.columnDeref();
                ISeq form = (ISeq)frm;
                if (form.count() < 2) {
                    throw Util.runtimeException("wrong number of arguments, expecting: (new Classname args...)");
                } else {
                      //這里就已經(jīng)要報(bào)錯(cuò)了。
                    Class c = Compiler.HostExpr.maybeClass(RT.second(form), false);
  if (c == null) { //這里似乎沒有必要了裁奇。
                        throw new IllegalArgumentException("Unable to resolve classname: " + RT.second(form));
                    } 
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末桐猬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刽肠,更是在濱河造成了極大的恐慌溃肪,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件音五,死亡現(xiàn)場(chǎng)離奇詭異惫撰,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)躺涝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門厨钻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事莉撇√囱担” “怎么了获询?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我亩进,道長(zhǎng),這世上最難降的妖魔是什么愿卒? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任灵莲,我火速辦了婚禮,結(jié)果婚禮上辜荠,老公的妹妹穿的比我還像新娘汽抚。我一直安慰自己,他們只是感情好伯病,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布造烁。 她就那樣靜靜地躺著,像睡著了一般午笛。 火紅的嫁衣襯著肌膚如雪惭蟋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天药磺,我揣著相機(jī)與錄音告组,去河邊找鬼。 笑死癌佩,一個(gè)胖子當(dāng)著我的面吹牛木缝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播围辙,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼我碟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了姚建?” 一聲冷哼從身側(cè)響起怎囚,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎桥胞,沒想到半個(gè)月后恳守,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贩虾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年催烘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缎罢。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伊群,死狀恐怖考杉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情舰始,我是刑警寧澤崇棠,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站丸卷,受9級(jí)特大地震影響枕稀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谜嫉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一萎坷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沐兰,春花似錦哆档、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至比原,卻和暖如春插佛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背春寿。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工朗涩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留忽孽,地道東北人绑改。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像兄一,于是被迫代替她去往敵國(guó)和親厘线。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容