clojure 代碼分析 2022年3月22日

image.png

方便學(xué)習(xí) 測試 生成 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 都會調(diào)用 analyze . 而在 analyze 中會生成fn 的compile .
最外層的 compile 生成的是init 加載類等. 也會生成class文件. eval 不會在磁盤上落地class文件.

關(guān)鍵代碼在 FnExpr 中 .因為每個 fn 都要編譯成一個class 才能調(diào)用. (除了special)


image.png
image.png

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

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

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 是個重要概念 . 他與數(shù)組完全不同..
https://blog.csdn.net/baozi3026/article/details/7973147 說的一般,但到門口了.
https://www.cnblogs.com/adolph-suyu/p/3639020.html 這個說的較好

仔細看第三章cons的說明,發(fā)現(xiàn)cons放在c語言里面,無非就是一個如下的結(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

因為 cons 單元格中的值可以引用任何類型的對象,所以您可以通過將 cons 單元格鏈接在一起來構(gòu)建更大的結(jié)構(gòu)。列表是通過將鏈中的 cons 單元鏈接在一起來構(gòu)建的。列表的元素保存在 cons 單元格的CARs 中,而到后續(xù) cons 單元格的鏈接保存在 CDRs 中。鏈中的最后一個單元格有一個CDRof NIL,正如我在第 4 章中提到的那樣,它表示空列表以及布爾值 false。

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

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

image.png

其實,Lisp中所有這些符號,都是Symbol。 什么變量,什么函數(shù),都是浮云。上面的 例子中,緊接著用fboundp判斷Symbol var 的Function域是否綁定,這個時候為假。 然后我們定義了一個名為 var 的函數(shù),之后再判斷,則已然為真。這也是為什么, 在Lisp中某個函數(shù)可以和某個變量同名的原因所在。 從這段代碼中我們也可以看出 defvar/defun這些操作符、宏所做事情的本質(zhì)。
More More More
事情就這樣結(jié)束了?Of course not。還有很多上文提到的疑惑沒有解決。首先,Symbol是 如此復(fù)雜,那么Lisp如何決定它在不同環(huán)境下的含義呢?Symbol雖然是個對象,但它并不像 C++中的對象一樣,它出現(xiàn)時并不指代自己!不同應(yīng)用環(huán)境下,它指代的東西也不一樣。這 些指代主要包括變量和函數(shù),意思是說: Symbol出現(xiàn)時,要么指的是它的Value,要么是 它的Function。 這種背地里干的事情,也算是造成迷惑的一個原因。

當一個Symbol出現(xiàn)在一個List的第一個元素時,它被處理為函數(shù)。這么說有點迷惑人,因為 它帶進了Lisp中代碼和數(shù)據(jù)之間的模糊邊界特性。簡單來說,就是當Symbol出現(xiàn)在一個括號 表達式(s-expression)中第一個位置時,算是個函數(shù),例如:
https://blog.csdn.net/dc_726/article/details/8774740

下面的例子說明了Evaluator的作用:

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

毫無疑問,(foo 1 2)是一個有效的S-expression,其通過Reader這關(guān)是沒有問題的。但是當Evaluator對S-expression"(foo 1 2)"進行驗證求值時,卻發(fā)現(xiàn)無法找到函數(shù)foo的定義,這行源碼不合法。

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

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

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

image.png

image.png

image.png

非常感謝這個作者


image.png

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

image.png

第一次看到 自動解析 . 對自動化工具產(chǎ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/ 作者老師的主頁.
2022年3月27日 ChezScheme 現(xiàn)在教程太少. 源碼看不懂. 暫時停止. 繼續(xù)主攻clojure

git checkout da14d89c hello main

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

clojure 因為函數(shù)是first class 對應(yīng)到j(luò)ava 就是一個fn 一個 class
clojure 發(fā)展至今初次啟動 會有clojure.core 自動加載初始化.
每個lisp 都有一個 runtime clisp chezscheme ..等都是c 寫的runtime 自己需要實現(xiàn)gc
clojure 用的是用java寫的runtime 實現(xiàn) Symbol Var NameSpace RT ..等幾個關(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 的知識中 剛開始不易接觸到的是 runtime . 似乎這個大家都會了...或者覺得,實現(xiàn)的方式很多,不值得一說. 繆也. 理論 與 實現(xiàn)同樣重要. 搞懂一個runtime 很不容易,需要先要學(xué)理論,然后再精通一門語言,然后根據(jù)該語言來實現(xiàn). 一般都是c . clojure 使用的是java .
clojure 在早期 4ff27c7a 把runtime 和 Lispreader Compiler 分開存放的. 但后期放到一起了.都是runtime了. packagename 也改為了 clojure.lang . 因為lisp 需要在運行時動態(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 還未實現(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 測試方法.
測試該方法 準備個測試文件

(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 理解非常困難. 什么東西,什么時候從lisp的 fn do ..if 轉(zhuǎn)為 java xx格式. 需要耐心攻關(guān)..

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

生成如下 ,此時的 [Compiler.java] http://www.itdecent.cn/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 老師 體驗了一把 antlr . 哈哈哈哈..
rh 難得一見的注釋.. declared exceptions are an incredibly bad idea !!!


image.png

Lisper read 出來的都是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

手動編譯成字節(jié)碼的 只有 fn 對應(yīng)一個class 里面的所有都是 Object Var AFn RT Arrays Symbol PersistentVector PersistentList ILookupThunk LockingTransaction ....等被從lisp 代碼中轉(zhuǎn)換過來的 調(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 你必須要弄清楚 源語言 和 目標語言,弄清楚每個源expr(element atom ) 將會變成目標語言的確定格式.)
作者: dmitrySoshnikov dmitrySoshnikov.com (niu ren)
https://www.bilibili.com/video/BV1XZ4y1k7T7 good 課程,該老師還有后續(xù)的 vm 課程.
深入 JavaScript 運行時細節(jié)和有關(guān)原型的種種真相推薦 http://dmitrysoshnikov.com/ 的 ECMA-262-3 in detail,這是我讀過的最透徹的關(guān)于 JavaScript 運行機制和 object 繼承機制的解釋。
鏈接: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ù) 不定長參數(shù) a(int ...a ) 是個語法糖, java 會把 a 弄成 int[] a
Methods which uses variable arguments (varargs, arguments with three dots) are known as variadic functions.
注意:
FnExpr 對應(yīng)的是Class
FnMethod 對應(yīng)的是class 中的具體 invoke 方法
(來源: 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ù), 不定長參數(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
這里加點 jvm 虛擬機執(zhí)行棧細節(jié). 例如 返回結(jié)果 一直在棧頂. 參數(shù)都是通過棧來傳送的.

image.png

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

一、getEnclosingXX

/**
     * getEnclosingClass:該類是在那個類中定義的, 比如直接定義的內(nèi)部類或匿名內(nèi)部類
     * getEnclosingConstructor:該類是在哪個構(gòu)造函數(shù)中定義的,比如構(gòu)造方法中定義的匿名內(nèi)部類
     * getEnclosingMethod:該類是在哪個方法中定義的,比如方法中定義的匿名內(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.itdecent.cn/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.(符號是標準化的字符串。) (from: hotspot symbol.hpp)


image.png

https://blog.csdn.net/u013928208/article/details/106758062 jvm 啟動分析

image.png

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

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

https://www.infoq.cn/article/PQi0LYV7HhmsgHkPzkJI 目前一切語言底層的運行時
都是c寫的. 因為操作系統(tǒng)是c寫的..

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


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  ;最后一個點是 new 的語法糖
      ;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"  必須要在當前目錄新建 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     ; 一個abstract 空類.
InstanceFieldExpr
StaticFieldExpr   
MethodExpr
InstanceMethodExpr

; 這里高度注意. 因為inline 所以+是Compiler$StaticMethodExpr
(. Math pow 2 4) ; -> 16.0
(Math/pow 2 4)  這個是上面的語法糖.

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


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


TryExpr

NewExpr   ;(new xxx) 語法糖(xxx.)
MetaExpr  ; 元數(shù)據(jù) .
IfExpr
EmptyExpr
ListExpr  ;一個沒用的. 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è)級代碼,,每一個細節(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點06分 。。。 終于追到了 xxx.xxx. last dot 轉(zhuǎn)為了 (new xxx.xxx) 然后接著才會
進入 anylzeSymbol 中查找不到該類 后就會報錯。 不是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)要報錯了。
                    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)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容