Jer lang grammar design
最近准备实现一个基于JVM的新语言"Jer",一开始想先实现一个Hello world,然后逐步再朝上面添加新的功能;后来觉得还是需要先把这个语言的语法层面大致设计好再动手才行。本身是出于好玩的一个目的,但是也的确希望这个语言有一些特点,而不是单纯换一个语法而已。在这个期间思考了很多,但一直没有想到自己满意的方法,姑且先按照现在的想法设计一版出来吧。
设计目标
我对这个语言有这些期望:
- 基于JVM平台,即最终通过代码编译生成class字节码
- 跟Java能够兼容(可以互相调用)
- 尽量简单,应该基本的数据类型、流程控制等,支持OO,但对于一些高级特性例如泛型、lambda等就不考虑了
- 依然是强类型的语言
hello world
类似Java这样一个java文件只能对应一个类也许不是也个好的办法,jer源文件中可以申明任意数量的类。对于一个hello world来说,(大概)应该长这样子:
// 导入其他类或者其中的静态方法
use jer/lang/System
// 没有定义在类中的方法对应到java中的静态方法
main(args: [String) = {
msg: String = "hello world!"
println(msg)
}
其中,不需要使用分号作为行的分隔符,直接换行就行了。一个Jer源文件即对应到一个Java的类,类的名称即是文件名。
Jer 语法
compilationUint
: importedType* declaration* EOF
;
declaration
: constantDeclaration
| methodDeclaration
| abstractDeclaration
| typeDeclaration
;
每一个文件中,可以包含任意:
- 导入申明
- 常量变量申明
- 方法申明(即为静态函数)
- type或者类的申明
导入申明
通过导入申明来引入其他包或者文件中定义的类。
importedType
: USE fullPath
;
fullPath
: (IDENTIFIER '/')* TYPE_NAME
;
use java/lang/String
use java/util/DateTime
这里需要考虑一个场景就是,如果是其他Jer文件中定义了常量或者静态方法,在其他文件中如何使用?
// com/riguz/jer/Util.jer
sum(a: Integer, b: Integer) -> Integer = {
// ...
}
// com/riguz/jer/Foo.jer
use com/riguz/jer/Util
main(args: [String) = {
sum(1, 20)
}
常量定义
常量定义跟普通的局部变量唯一的区别就是多了一个const的关键字。具体的语法在后面介绍。
constantDeclaration
: CONST variableDeclaration
;
方法
methodDeclaration
: methodSignature methodImplementation?
;
methodSignature
: IDENTIFIER '(' formalParameters? ')' functionReturnType?
;
formalParameters
: formalParameter (',' formalParameter)*
;
functionReturnType
: TO type
;
methodImplementation
: '=' block
;
formalParameter
: IDENTIFIER ':' type
;
方法分为两种,一种是有返回值的方法,另一种是没有返回值的方法(void),在定义的时候稍微有些区别:
// 没有返回值的方法依靠方法的副作用
main(args: [String) = {
msg: String = "hello world!"
println(msg)
}
// 返回值通过箭头表示
sum(a: Integer, b: Integer) -> Integer = {
return a + b
}
抽象类和自定义类型
abstractDeclaration
: ABSTRACT TYPE_NAME '{' propertyDeclaration* methodSignature*'}'
;
typeDeclaration
: TYPE TYPE_NAME typeAbstractions? '{' propertyDeclaration* constructorDeclaration* methodDeclaration*'}'
;
typeAbstractions
: IS TYPE_NAME (',' TYPE_NAME)*
;
propertyDeclaration
: IDENTIFIER ':' type
;
constructorDeclaration
: '(' constructorFormalArguments? ')' methodImplementation
;
constructorFormalArguments
: constructorFormalArgument (',' constructorFormalArgument)*
;
constructorFormalArgument
: IDENTIFIER (':' TYPE_NAME)?
;
数据类型
type
: TYPE_NAME
| arrayType
;
arrayType
: '[' type
;
基本数据类型
数据类型与Java基本一致,对应到JVM的各个数据类型:
- Bool : JVM boolean
- Byte : JVM byte
- Short: JVM short
- Integer: JVM int
- Long: JVM long
- Float: JVM float
- Double: JVM double
- Char: JVM char
- String: java/lang/String
取消java中的primitive 类型,即所有一切都是引用类型。
数组类型
数组类型用`[<Type>`表示,例如`[Integer`即表示一个整数数组。
表达式
expression
: primary
| expression bop='.'
( methodCall
| IDENTIFIER
)
| methodCall
| objectCreation
;
primary
: '(' expression ')'
| literal
| IDENTIFIER
;
literal
: DECIMAL_LITERAL
| FLOAT_LITERAL
| CHAR_LITERAL
| STRING_LITERAL
| BOOL_LITERAL
| NULL_LITERAL
;
methodCall
: instance=IDENTIFIER? '('methodName=IDENTIFIER methodArguments? ')'
;
methodArguments
: expression (',' expression)*
;
objectCreation
: NEW '(' methodArguments? ')'
;
statement
block
: '{' statement* '}'
;
statement
: variableDeclaration
| embeddedStatement
;
embeddedStatement
: block
| assignment
| expressionStatement
| selectionStatement
| loopStatement
| returnStatement
;
assignment
: IDENTIFIER '=' expression
;
selectionStatement
: IF '(' expression ')' statement (ELSE statement)?
;
loopStatement
: WHILE '(' expression ')' statement
;
returnStatement
: RETURN expression
;
expressionStatement
: methodCall
;
variableDeclaration
: IDENTIFIER ':' type ('=' variableInitializer)?
;
variableInitializer
: arrayInitializer
| expression
;
arrayInitializer
: '{' variableInitializer (',' variableInitializer)* '}'
代码示例
use java/lang/String
use java/util/DateTime
const pi: Float = 3.1415926f
const msg: String = "hello world"
const kb: Integer = 1024
const success: Boolean = true
const id: Long = 12345678
main(args: [String) = {
(println "Hello world")
}
circleArea(radius: Float) -> Float = {
return pi(multiply 2, radius)
}
abstract Movable {
x: Integer
y: Integer
move(x1: Integer, y1: Integer)
}
abstract Animal {
name: String
sayHelloTo(person: Person)
address() -> String
}
type Dog is Animal, Movable {
(name) = {
x = 0
y = 0
}
sayHelloTo(person: Person) = {
(println "Hello")
}
}