方便学习 测试 生成 java 代码的
args=new String[]{"feng", "one","E:\clojure\yanjiuclojure\src\boot.clj"};
关于eval 和 emit 的区别与联系
在compiler 中 最外层有 compile 和 eval analyze
其中 compile 和 eval 都会调用 analyze . 而在 analyze 中会生成fn 的compile .
最外层的 compile 生成的是init 加载类等. 也会生成class文件. eval 不会在磁盘上落地class文件.
关键代码在 FnExpr 中 .因为每个 fn 都要编译成一个class 才能调用. (除了special)
clojure 代码reader 出来后 都是 symbol var list set map 等对象. 这里就是同像性的来源, 代码是数据, 符合标准的数据也能转为代码.
调试的时候 Compiler.java 中的 暂时去掉 有点碍事. (学习的时候灵活之.)
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;
}
https://athos.hatenablog.com/entry/20110605/clojure_internal_ast
http://blog.guillermowinkler.com/blog/2014/04/13/decompiling-clojure-i/
lisp 中的 cons 是个重要概念 . 他与数组完全不同..
https://blog.csdn.net/baozi3026/article/details/7973147 说的一般,但到门口了.
https://www.cnblogs.com/adolph-suyu/p/3639020.html 这个说的较好
仔细看第三章cons的说明,发现cons放在c语言里面,无非就是一个如下的结构
typedef struct _cons cons;
struct _cons
{
void* content; //cons的内容
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 单元格链接在一起来构建更大的结构。列表是通过将链中的 cons 单元链接在一起来构建的。列表的元素保存在 cons 单元格的CARs 中,而到后续 cons 单元格的链接保存在 CDRs 中。链中的最后一个单元格有一个CDRof NIL,正如我在第 4 章中提到的那样,它表示空列表以及布尔值 false。
这种安排绝不是 Lisp 独有的。它被称为 单链表。然而,除了 Lisp 家族之外,很少有语言为这种不起眼的数据类型提供如此广泛的支持。(feng 这是env 和 树 的核心啊!!)
虽然 cons 单元格和列表通常被认为是同义词,但这并不完全正确——正如我之前提到的,您可以使用列表列表来表示树。正如本章讨论的函数允许您将由 cons 单元构建的结构视为列表,其他函数允许您使用 cons 单元来表示树、集合和两种键/值映射。我将在下一章讨论其中的一些功能。
其实,Lisp中所有这些符号,都是Symbol。 什么变量,什么函数,都是浮云。上面的 例子中,紧接着用fboundp判断Symbol var 的Function域是否绑定,这个时候为假。 然后我们定义了一个名为 var 的函数,之后再判断,则已然为真。这也是为什么, 在Lisp中某个函数可以和某个变量同名的原因所在。 从这段代码中我们也可以看出 defvar/defun这些操作符、宏所做事情的本质。
More More More
事情就这样结束了?Of course not。还有很多上文提到的疑惑没有解决。首先,Symbol是 如此复杂,那么Lisp如何决定它在不同环境下的含义呢?Symbol虽然是个对象,但它并不像 C++中的对象一样,它出现时并不指代自己!不同应用环境下,它指代的东西也不一样。这 些指代主要包括变量和函数,意思是说: Symbol出现时,要么指的是它的Value,要么是 它的Function。 这种背地里干的事情,也算是造成迷惑的一个原因。
当一个Symbol出现在一个List的第一个元素时,它被处理为函数。这么说有点迷惑人,因为 它带进了Lisp中代码和数据之间的模糊边界特性。简单来说,就是当Symbol出现在一个括号 表达式(s-expression)中第一个位置时,算是个函数,例如:
https://blog.csdn.net/dc_726/article/details/8774740
下面的例子说明了Evaluator的作用:
[1]> (foo 1 2)
*** - EVAL: undefined function FOO
毫无疑问,(foo 1 2)是一个有效的S-expression,其通过Reader这关是没有问题的。但是当Evaluator对S-expression"(foo 1 2)"进行验证求值时,却发现无法找到函数foo的定义,这行源码不合法。
简单总结Reader和Evaluator的工作流程就是:"源码文本"通过Reader转换为有效的"S-expressions",后者则由Evaluator转换成有效"Lisp Form"并求值得出结果。
clojure 早期实现是用 clisp 生成一个clojure.java 的
https://blog.csdn.net/acool555/article/details/6918248 clisp 较好的文章
https://www.bilibili.com/video/BV1XZ4y1k7T7 good
非常感谢这个作者
程序中看管理!:: 直接数字计算简单但不灵活. (初级管理) 所以需要先安置各个变量(职位,虽然难一点,但这就是 团伙和团队的本质区别. 变量管理的细 变量不乱,就是好管理.) (二级管理)
第一次看到 自动解析 . 对自动化工具产生了一点好感..
函数 只是一块block 一组代码的抽象.
尾递归 优化成迭代.
http://www.yinwang.org/blog-cn/2012/07/04/dan-friedman
印第安纳大学.... 好书.. . nanopass 的作者 参与者 写的书
https://www.brinckerhoff.org/clements/2198-csc431/essentials-of-compilation.pdf
https://wphomes.soic.indiana.edu/jsiek/ 作者老师的主页.
2022年3月27日 ChezScheme 现在教程太少. 源码看不懂. 暂时停止. 继续主攻clojure
git checkout da14d89c hello main
https://blog.ndk.io/clojure-compilation.html
clojure 因为函数是first class 对应到java 就是一个fn 一个 class
clojure 发展至今初次启动 会有clojure.core 自动加载初始化.
每个lisp 都有一个 runtime clisp chezscheme ..等都是c 写的runtime 自己需要实现gc
clojure 用的是用java写的runtime 实现 Symbol Var NameSpace RT ..等几个关键的就ok了. 其余的用jvm.. 怪不得这么稳定,高可用.. 阿弥陀佛
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 . 似乎这个大家都会了...或者觉得,实现的方式很多,不值得一说. 缪也. 理论 与 实现同样重要. 搞懂一个runtime 很不容易,需要先要学理论,然后再精通一门语言,然后根据该语言来实现. 一般都是c . clojure 使用的是java .
clojure 在早期 4ff27c7a 把runtime 和 Lispreader Compiler 分开存放的. 但后期放到一起了.都是runtime了. packagename 也改为了 clojure.lang . 因为lisp 需要在运行时动态 编译 lisp代码. 所以 编译器也是runtime的重要一环.
remove 改为 without 是什么 心里?? git checkout db58898d
clojure list 本质是cons !
git checkout 987dad56 加入了 Compiler.java 但是空的
哈哈哈.. 在 51c468f8(2006.9) 把NameSpace 改为了Module ... now (2022年3月28日) 又改回了..
git checkout bbabe65c Compiler.java 有了可以调试 学习的代码.
此处 macroexpand 还未实现.
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 出现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日 现在看 Compiler 理解非常困难. 什么东西,什么时候从lisp的 fn do ..if 转为 java xx格式. 需要耐心攻关..
(def a 3)
(def one (fn (x) (if (a x 2) 3 4)))
生成如下 ,此时的 [Compiler.java] https://www.jianshu.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 老师 体验了一把 antlr . 哈哈哈哈..
rh 难得一见的注释.. declared exceptions are an incredibly bad idea !!!
Lisper read 出来的都是clojure runtime 内置的数据. 所谓同像性在这里明确体现了.
(hao [ 3 2] (23 33)) (Symbol PersistentVector IteratorSeq .. good.
92075ac2 got rid of ANTLR reader (摆脱了 antlr :)
c894ed9b 出现 eval 方法了... 在新的类 BytecodeCompiler.java
手动编译成字节码的 只有 fn 对应一个class 里面的所有都是 Object Var AFn RT Arrays Symbol PersistentVector PersistentList ILookupThunk LockingTransaction ....等被从lisp 代码中转换过来的 调用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 中包含的 数据结构
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 课程,该老师还有后续的 vm 课程.
深入 JavaScript 运行时细节和有关原型的种种真相推荐 http://dmitrysoshnikov.com/ 的 ECMA-262-3 in detail,这是我读过的最透彻的关于 JavaScript 运行机制和 object 继承机制的解释。
链接:https://juejin.cn/post/6844903477609660424
Building a Virtual Machine for Programming Language
Essential of low-level interpretation
https://www.udemy.com/course/virtual-machine/
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 可变参数 不定长参数 a(int ...a ) 是个语法糖, java 会把 a 弄成 int[] a
Methods which uses variable arguments (varargs, arguments with three dots) are known as variadic functions.
注意:
FnExpr 对应的是Class
FnMethod 对应的是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; // 可变参数, 不定长参数.
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 虚拟机执行栈细节. 例如 返回结果 一直在栈顶. 参数都是通过栈来传送的.
Compiler.java 中的 enclosingMethod closes 是在
getEnclosingClass 是类中的 封闭类.
C:\Program Files\Java\jdk1.8.0_101\src.zip!\java\lang\Class.java
一、getEnclosingXX
/**
* getEnclosingClass:该类是在那个类中定义的, 比如直接定义的内部类或匿名内部类
* getEnclosingConstructor:该类是在哪个构造函数中定义的,比如构造方法中定义的匿名内部类
* getEnclosingMethod:该类是在哪个方法中定义的,比如方法中定义的匿名内部类
* getDeclaredClasses : 该类包含的内部类
*
* @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());
}
https://www.jianshu.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
A Symbol is a canonicalized string.(符号是标准化的字符串。) (from: hotspot symbol.hpp)
https://blog.csdn.net/u013928208/article/details/106758062 jvm 启动分析
而OpenJ9其自身是基于IBM开源的OMR项目所构建,OMR项目由一个高度集成的开放源码C和c++组件,可用于构建大量的语言,运行时支持许多不同的硬件和操作系统平台。这些组件包括但不限于:内存管理,线程处理,平台端口(抽象)库,诊断支持,监控支持,垃圾收集和本地实时编译。OMR的意图在于让实现语言的人能够重用IBM在Java运行时方面所投入的数百开发人年所取得的成果,能够受益的包含已有的语言如Ruby、Python、Javascript等等,它还能加快新语言的创建过程。
作者:崩天的勾玉
链接:https://www.zhihu.com/question/65452135/answer/2280521447
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
https://www.infoq.cn/article/PQi0LYV7HhmsgHkPzkJI 目前一切语言底层的运行时
都是c写的. 因为操作系统是c写的..
2022年4月8日 4b899d76 加入了 boot.clj 参数 用了 [ ] 中括号
d43857f2 删除了 OldCompiler
https://asm.ow2.io/developer-guide.html asm 最好的教程.
从 Lisp read 到 form 后 (共有 15种 form) Compiler parse 成 Expr (共有58种 Expr)
;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中叫关键字..)
ImportExpr ; ns 中 :import 调用的是 clojure.core/import
AssignableExpr ;接口
MaybePrimitiveExpr ;接口 用于原生优化.
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 ; 元数据 .
IfExpr
EmptyExpr
ListExpr ;一个没用的. seq 已经可以了.
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日 现在到了 inline 。。。 注意! 专业级代码,,每一个细节都是坎。。!
(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)))
2022年4月13日23点06分 。。。 终于追到了 xxx.xxx. last dot 转为了 (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 {
//这里就已经要报错了。
Class c = Compiler.HostExpr.maybeClass(RT.second(form), false);
if (c == null) { //这里似乎没有必要了。
throw new IllegalArgumentException("Unable to resolve classname: " + RT.second(form));
}