当前位置:网站首页>Compiler analysis of clojure operation principle
Compiler analysis of clojure operation principle
2022-07-26 16:12:00 【Flying watermelon】
Clojure is a compiled language, yet remains completely dynamic — every feature supported by Clojure is supported at runtime. Rich Hickey https://clojure.org/
there runtime refer to JVM,JVM At first, it was for operation Java Designed for language , Now it has developed into a heavyweight platform , except Clojure outside , Many dynamic languages They also choose to be based on JVM To achieve . For a more specific description Clojure Operation principle , There will be two articles to introduce . This is the first article , The main contents involved are : Compiler workflow 、Lisp The macro mechanism of . The second part will mainly analyze Clojure Program compiled into bytecode How to ensure the characteristics of dynamic language and how to accelerate Clojure Program execution speed , This will involve JVM Class loading mechanism of 、 The reflex mechanism .
A compiled VS. interpreted
SO There is a problem Is Clojure compiled or interpreted, According to the official website quotation at the beginning of this article , explain Clojure It is a compiled language , It's like Java、Scala. however Clojure And Java What's different is ,Clojure You can compile at run time and then load , and Java Clearly distinguish between compile time and run time .
Compiler workflow
It is similar to the interpreter in interpretive language , Compiled languages pass through compilers (Compiler) To compile the source program into bytecode . Generally speaking , The compiler includes Two parts :
- front end : Lexical analysis → Syntax analysis → Semantic analysis
- Back end : analysis 、 Optimize → Target code generation
Clojure Our compiler also follows this pattern , It can be roughly divided into the following two modules :
- Read Clojure Source program → participle → structure S- expression , from LispReader.java Class implementation
- Macro extension → Semantic analysis → Generate JVM Bytecode , from Compiler.java Class implementation
The above figure shows the input and output of different stages , The specific implementation is explained one by one below .
LispReader.java
Generally speaking , Programming languages with complex syntax will separate lexical analysis and grammatical analysis into Lexer And Parser, But in Lisp In the family , The syntax of the source program is already AST 了 , So the Lexer And Parser Merge into one process Reader, Core code The implementation is as follows :
for (; ; ) {
if (pendingForms instanceof List && !((List) pendingForms).isEmpty())
return ((List) pendingForms).remove(0);
int ch = read1(r);
while (isWhitespace(ch))
ch = read1(r);
if (ch == -1) {
if (eofIsError)
throw Util.runtimeException("EOF while reading");
return eofValue;
}
if (returnOn != null && (returnOn.charValue() == ch)) {
return returnOnValue;
}
if (Character.isDigit(ch)) {
Object n = readNumber(r, (char) ch);
return n;
}
IFn macroFn = getMacro(ch);
if (macroFn != null) {
Object ret = macroFn.invoke(r, (char) ch, opts, pendingForms);
//no op macros return the reader
if (ret == r)
continue;
return ret;
}
if (ch == '+' || ch == '-') {
int ch2 = read1(r);
if (Character.isDigit(ch2)) {
unread(r, ch2);
Object n = readNumber(r, (char) ch);
return n;
}
unread(r, ch2);
}
String token = readToken(r, (char) ch);
return interpretToken(token);
}Reader The behavior of is by the built-in constructor ( There are currently figures 、 character 、Symbol These three categories ) With one called read table The extension mechanism of (getMacro) Driven ,read table Each record in it is provided with a characteristic symbol ( be called macro characters) To specific read behavior ( be called reader macros) Mapping .
And Common Lisp Different , Ordinary users cannot expand Clojure Inside read table. About extension read table The benefits of , You can refer to StackOverflow Upper What advantage does common lisp reader macros have that Clojure does not have?.Rich Hickey stay One Google Group There are explanations that are not open read table The reason of , Here is an excerpt from :
I am unconvinced that reader macros are needed in Clojure at this time. They greatly reduce the readability of code that uses them (by people who otherwise know Clojure), encourage incompatible custom mini- languages and dialects (vs namespace-partitioned macros), and complicate loading and evaluation. To the extent I’m willing to accommodate common needs different from my own (e.g. regexes), I think many things that would otherwise have forced people to reader macros may end up in Clojure, where everyone can benefit from a common approach. Clojure is arguably a very simple language, and in that simplicity lies a different kind of power. I’m going to pass on pursuing this for now,
By the end of Clojure 1.8 edition , There are nine in total macro characters:
Quote (')
Character (\)
Comment (;)
Deref (@)
Metadata (^)
Dispatch (#)
Syntax-quote (`)
Unquote (~)
Unquote-splicing ([email protected])Their specific meanings can be referred to Official documents reader#macrochars.
Compiler.java
Compiler Class mainly has three entry functions :
- compile, When calling
clojure.core/compileWhen using - load, When calling
clojure.core/require、clojure.core/useWhen using - eval, When calling
clojure.core/evalWhen using
These three entry functions will call macroexpand、analyze Method , Generate Expr object ,compile The function also calls emit Method generation bytecode.
macroexpand
Macro There is no doubt that Lisp The Dragon butcher's knife in the world , Can be in Compile time Automatic code generation :
static Object macroexpand(Object form) {
Object exf = macroexpand1(form);
if (exf != form)
return macroexpand(exf);
return form;
}macroexpand1 Function to do the main extension work , It will be called isMacro Judge the present Var Is it a macro , And this is through inspection var Is it a function , And meta information macro Is it true. Clojure Inside through defmacro Function to create a macro , It will be called var Of setMacro Function to set meta information macro by true.
analyze
interface Expr {
Object eval();
void emit(C context, ObjExpr objx, GeneratorAdapter gen);
boolean hasJavaClass();
Class getJavaClass();
}
private static Expr analyze(C context, Object form, String name)analyze Conduct major semantic analysis ,form Parameters are various data structures after macro expansion (String/ISeq/IPersistentList etc. ), The return value type is Expr, You can guess ,Expr Subclasses of are the body of the program , Follow the modular programming style , Every subclass knows how to evaluate itself (eval) Or output bytecode(emit).
emit
What needs to be clear here is ,Clojure The compiler didn't put Clojure The code changes to the corresponding Java Code , But by means of bytecode Operation Library ASM Direct generation can run in JVM Upper bytecode.
according to JVM bytecode The specification of , Every .class Files must consist of classes , and Clojure As a functional language , The body is a function , adopt namespace To encapsulate 、 Isolation function , You may take it for granted that everyone namespace Corresponding to a class ,namespace Each function in the class corresponds to the method in the class , In fact, this is not the case , according to Clojure Official documents , The correspondence is like this :
- Each file 、 function 、
gen-classWill generate a.classfile - Each file generates one
<filename>__initLoad class for gen-classGenerate classes with fixed names , Convenience and Java Interaction
Generated bytecode It will be introduced in detail in the second article in this series , Coming soon .
eval
Every Expr All subclasses of have eval Corresponding implementation of method . The following code snippet is LispExpr.eval The implementation of the , Other subclasses implement similar , I'm not going to repeat it here .
public Object eval() {
IPersistentVector ret = PersistentVector.EMPTY;
for (int i = 0; i < args.count(); i++)
// Here recursively find the value of each item in the list
ret = (IPersistentVector) ret.cons(((Expr) args.nth(i)).eval());
return ret.seq();
}summary
See before SICP After the implementation of several interpreters , But they are relatively simple , Through analysis Clojure Compiler implementation , Deepened eval-apply loop The understanding of the , Another point is to uncover the true face of macro , I always thought that macro was a magical thing , In fact, it's just Functions that run at compile time nothing more , The content of input and output is the data structure of the program , It is also inherent in the program AST.
Reference resources
边栏推荐
- PAT甲级 1045 Favorite Color Stripe
- 剑指offer专项突击版第11天
- Octree establishes map and realizes path planning and navigation
- 2021年软件测试工具趋势
- Specific practice cases of "card note taking method" in Siyuan
- Bucher gear pump qx81-400r301
- C# 给Word每一页设置不同文字水印
- 2022年最新北京建筑安全员模拟题库及答案
- 如何通过ETL调度工具 TASKCTL 使用作业插件类型调用 kettle作业?
- Parker pump pv140r1k1t1pmmc
猜你喜欢

大型仿人机器人整机构型研究与应用
![[RCTF2015]EasySQL](/img/68/328ee5cffc8b267b6b0f284eb8db2c.png)
[RCTF2015]EasySQL

Implementation of personalized healthy diet recommendation system based on SSM

综合设计一个OPPE主页--明星机型的设计

Botu PLC Sequential switch function block (SCL)

如何通过ETL调度工具 TASKCTL 使用作业插件类型调用 kettle作业?

FTP协议

Mapwithstate of spark streaming state flow

A comprehensive review of image enhancement technology in deep learning

潘多拉 IOT 开发板学习(RT-Thread)—— 实验17 ESP8266 实验(学习笔记)
随机推荐
C语言重点知识总结
Mapwithstate of spark streaming state flow
Bugku login1
First knowledge of OpenGL (4) link shader
互联网协议
13年资深开发者分享一年学习Rust经历:从必备书目到代码练习一网打尽
测试用例千万不能随便,记录由一个测试用例异常引起的思考
Vs2019debug mode too laggy can't enter the breakpoint
[ten thousand words long text] Based on LSM tree thought Net 6.0 C # realize kV database (case version)
教大模型自己跳过“无用”层,推理速度×3性能不变,谷歌MIT这个新方法火了...
C # set different text watermarks for each page of word
Paper: all models are wrong, but many are useful: all models are wrong, but many are useful: understand the importance of variables by studying a whole class of prediction models at the same time
Paper:《All Models are Wrong, but Many are Useful: 所有模型都是错误的,但许多模型都是有用的:通过同时研究一整类预测模型来了解变量的重要性》翻译与解读
JVM 的类初始化机制
PAT甲级 1045 Favorite Color Stripe
2022年全国最新消防设施操作员(高级消防设施操作员)考试试题及答案
Bugku login2
We were tossed all night by a Kong performance bug
A comprehensive review of image enhancement technology in deep learning
国元期货网上开户安全吗?开户办理流程是怎样的?