# Deeplang
**Repository Path**: ploc-org/deeplang
## Basic Information
- **Project Name**: Deeplang
- **Description**: 面向资源受限的IoT设备的编程语言
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: develop
- **Homepage**: https://github.com/deeplang-org/deeplang
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2023-11-22
- **Last Updated**: 2024-01-16
## Categories & Tags
**Categories**: scripting-language
**Tags**: IOT, PL
## README
# Deeplang 简介
Deeplang语言是一种自制编程语言,由来自浙大、中科大、帝国理工等高校的学生共同完成。
我们致力于将Deeplang语言打造为具有鲜明内存安全特性的面向IoT场景的语言,设计过程中参考Rust的安全机制,但又根据IoT场景的特性选择了更合适的解释执行模式。Deeplang是一种静态类型、强类型语言,参考C-style设计语法,同时支持过程式、逻辑式和函数式的混合范式。
Deeplang的独特安全特性帮助其具有一定的竞争力。作者正在持续的开发和迭代中。
---
## 目录
1. [注释](#注释)
1. [程序入口](#程序入口)
1. [表达式](#表达式)
1. [控制语句](#控制语句)
1. [模式匹配](#模式匹配)
1. [函数](#函数)
1. [内建类型](#内建类型)
1. [类型定义](#类型定义)
1. [接口声明](#接口实现)
1. [接口实现](#接口实现)
1. [命名规范与作用域规则总结](#命名规范与作用域规则总结)
1. [仍在设计中的特性](#仍在设计中的特性)
## 注释
单行注释
``` dp
// code
```
多行注释
``` dp
/*
code
code
*/
```
## 程序入口
在Deeplang程序中,顶层代码没有表达式,只有各类定义。
具体来说,Deeplang有如下的顶层代码:
- 类型定义
- 接口声明
- 接口实现
- 全局变量定义
- 函数定义
整个程序的运行入口有且只有一个,就是以main作为名字的函数。
## 表达式
Deeplang和C、Java等语言一样,采用了表达式和语句二分的设计。
Deeplang中有以下几种表达式:
- 字面量,包括整数、浮点数、单个字符和字符串
- 变量名字。变量名字必须以小写字母开头。
- 一元操作符和二元操作符,如`! x`、`1 + 2`等。
- 元组,如`(1, "2", (3, 4))`
- 数组,如`[1, 1, 4, 5, 1, 4]`
- 代数数据类型(和类型),形如`<分支名字>(<值列表>)`。详见[类型定义的部分](#类型定义)。
- 创建结构体,形如是`<类型名字> { <域名字>: <值>, ... }`。
- 获取结构体中的域,如`point.x`。
- 函数调用,形如`<函数名字>(<参数列表>)`。
- 调用方法,形如`<表达式>.<方法名字>(<参数列表>)`。Deeplang中没有类系统,方法调用的解析是静态的。多态可以通过接口实现。
- 表达式层级的条件。语法待定。
- 表达式层级的模式匹配。语法待定。
## 控制语句
Deeplang中有以下的控制语句:
- 每个表达式都是控制语句。表达式的结果会被丢弃。
- 可以将多条控制语句有分号连接、用花括号括起,按顺序执行,变成一条语句。
- 声明变量`let [= ]`。其中``是一个**带类型标注的**[模式](#模式匹配),``是一个表达式。通过支持等于号左侧出现任意pattern,可以实现如`let (x, y) = some_pair`的便利解构。
- 条件语句`if (<条件>) <分支1> else <分支2>`。
- 传统for循环,如:
```
for ({let mut i: I32 = 0}; i < 10, i += 1) {
foo();
}
```
与大部分语言不同,循环初始化部分的语句必须用花括号括起。
- 基于迭代器的for循环,如:
```Deeplang
for ( : iterable) {
...
}
```
这类for循环的具体语义取决于(尚未完成的)标准库中的迭代器设计。
- while循环,形如:
```Deeplang
while (<循环继续条件,表达式>)
<循环体,必要时由花括号括起>
```
- 模式匹配语句,例如:
```Deeplang
match (optional_integer) {
Some(x) => { return x }
None => { return 0 }
}
```
- 特殊控制语句,如`return`,`break`和`continue`。
## 模式匹配
Deeplang中支持一套模式匹配系统,包括如下几种可以用于匹配的模式:
- 下划线`_`,匹配任何值。
- 变量`[mut] <变量名> [: <类型>]`,匹配任何值,并将`<变量名>`绑定到匹配到的值。新的变量默认是不可变的,除非在变量名前加上`mut`前缀。
- `as`模式,形如如` as [mut] [: <类型]`。如果匹配的值能够与``匹配,将``绑定到该值。`variable`同样可以用`mut`修饰。
- ADT模式,如`None`,`Some(x)`,`Some(Some(y))`等。
- 结构体模式,形如`<类型名字> { <结构体的域> : <匹配这个域的值的模式>, ... }`。不需要匹配所有的域,没有在模式中出现的域将被无视。
- 元组解包模式,如`(a, (b, c), d)`等。
## 函数
函数的签名形如`fun <函数名字>(<参数列表>) -> <返回值类型>`,其中参数列表用逗号隔开。目前参数类型和返回值类型都必须显式标注。一些函数定义的例子如下:
```dp
fun foo(bar: Bar) -> Foo {
...
}
```
```dp
fun multiParam(x: i32, y: i32) {
...
}
```
## 内建类型
Deeplang中有如下的内建类型:
```Deeplang
Bool
(...) // tuple type
() // empty tuple alias Unit type
I8, I16, I32, I64
U8, U16, U32, U64
F32, F64
Char // 16bit
[T; N] // T-array of length N
```
暂时还没有List的类型。
## 自定义类型
Deeplang中支持两种自定义类型:结构体和代数数据类型(ADT)。Deeplang中类型名字必须以大写字母开头。
### 结构体类型定义
```Deeplang
type <类型名字> {
<域名字> : <域类型>,
...
}
```
结构体的域的名字都必须以小写字母开头。
使用结构体定义新类型的一些例子如下:
```Deeplang
type Color {
r : U8,
g : U8,
b : U8
}
```
```Deeplang
type Point {
x : F32,
y : F32,
z : F32
}
```
此外,结构体定义还支持委托。在结构体类型的声明中,可以加入形如`as <域名字> : <委托的类型>`的声明。
例如,在声明:
```Deeplang
type S2 {
as s1 : S1
}
```
中,类型`S2`会有一个名为`s1`、类型为`S1`的域。此外,`S1`中的所有域都将被“委托”到`S2`中。也就是说,对于`S1`中的每一个域`x`,
`S2`中也会有一个对应的域`x`,且`S2.x = S2.s1.x`。
下面的例子展示了委托的使用方法:
```Deeplang
type ColoredPoint {
as position : Point,
color : Color
}
```
```Deeplang
let cp : ColoredPoint = ...;
cp.color; // of type Color
cp.position; // of type Point
cp.x // of type F32, same as cp.position.x
```
### ADT类型定义
```Deeplang
type <类型名字> [
<分支名字>[(<类型参数列表>)],
...
]
```
每个ADT必须有至少一个分支,而每个分支的参数类型列表是可选的。如果没有参数,则不写`()`。
ADT中分支的名字必须以大写字母开头。分支的类型参数列表中,可以给参数加上名字。但这些名字只有注释作用,没有实际语义。
使用ADT定义新类型的一个例子如下:
```Deeplang
type Shape [
Rectangle(width : U32, height : U32),
Circle(radius : U32),
Nothing
]
```
可以通过模式匹配来对一个ADT值的不同分支作出不同的处理。
## 接口声明
在Deeplang中,方法调用的解析是静态的,多态需要通过接口来实现的。
接口声明形如:
```Deeplang
interface <接口名字> extends <依赖的接口列表> {
fun <方法名字>(参数列表) -> <返回值类型>;
...
}
```
通过为一个类型实现该接口,可以使该类型的值支持接口中的方法的调用。在接口声明内部,可以通过`This`来指代实现该接口的类型自身。下面是一些接口声明的例子:
```Deeplang
interface Eq {
fun equals(this, other : This) : Bool;
}
```
```Deeplang
type Order [ Eq, Lt, Gt ]
interface Ordered extends Eq {
fun compare(this, other : This) : Order;
}
interface Add {
fun add(this, other : This) : This;
}
interface Mul {
fun mul(this, other : This) : This;
}
```
假设`I`是一个接口,那么`I`也可以被用作类型,此时它表示任意实现了接口`I`的类型。当需要表达“同时实现了若干个接口的类型”时,可以利用一个没有方法的空接口以及接口的依赖列表来实现,例如:
```Deeplang
// 接口Number等价与接口Ordered + Add + Mul
interface Number extends Ordered, Add, Mul {
}
```
```Deeplang
fun some_function(a : Number, b : Number) : Number {
if (equals(a, b))
return add(a, a);
else
return mul(a, a);
}
```
## 接口实现
在Deeplang中,为一个类型`T`实现接口`I`的语法如下:
```Deeplang
impl I for T {
fun <方法名字>(<参数列表>) -> <返回值类型> {
<方法的实现>
}
}
```
在方法的实现中,可以用`this`来访问方法的调用者。除了实现接口外,也可以直接为一个类型实现一些方法,语法为:
```Deeplang
impl T {
... // 同上
}
```
在这种`impl`块中实现的方法将能够被类型为`T`的值调用。下面是一个通过接口来模拟鸭子类型的例子:
```Deeplang
interface Quack {
quack() -> ();
}
```Deeplang
type Duck [ RubberDuck ]
impl Quack for Duck {
fun quack() -> () {
print("quaaaack");
}
}
type Bird [ Snidget ]
impl Quack for Bird {
fun quack() -> () {
print("bird quaaaack");
}
}
fun sound(animal: Quack) -> () {
animal.quack();
}
fun main() -> () {
let duck: Duck = Duck();
let bird: Bird = Bird();
// type checking pass
sound(duck); // quaaaak
sound(bird); // bird quaaaak
}
```
# 命名规范与作用域规则总结
以下名字必须以小写字母开头:
- 变量、函数的名字
- 结构体的域的名字
以下名字必须以大写字母开头:
- 类型、接口的名字
- 代数数据类型的分支的名字
除此之外,名字中可以包含下划线、字母和数字(首字母不能为数字)。上述“首字母”指的都是第一个非下划线的字母,也就是说不管是哪一种名字,都允许以若干个下划线开始,但只有下划线的名字是不被允许的。上述命名规范是语法的一部分,而不是一种软性的建议。违反上述命名规范的程序是语法错误的。但除了首字母外,Deeplang的使用者可以自由选择名字其他部分的命名规范,例如选择驼峰命名法或下划线命名法。
Deeplang中的各种名字处于不同的命名空间中。不同命名空间中的名字互不干涉。每种名字所处的命名空间及对应的作用域规则如下:
- 函数的名字处于独立的命名空间,且不允许重名。
- 方法名字本身没有一个全局的命名空间。因此不同的接口、不同的类型中可以声明/实现同名的方法。但是,同一个类型实现的方法不允许重名。
- 结构体的域的名字不能和该结构体实现的方法重名。但不同结构体之间可以有同名的域。
- 类型名字处于独立的命名空间,且不允许重名。
- 接口名字处于独立的命名空间,且不允许重名。
- 代数数据类型的分支名字处于独立的命名空间,且不允许重名。
变量的作用域规则比较复杂,这里用如下的例子来展示:
```
fun (x1 : A) {
// 作用域S1
let x2 : B = ...;
for ({let x3 : C = ...}; ...) {
// 作用域S2,嵌套于S1中,与S3平行
}
for ({let x4 : D = ...}; ...) {
// 作用域S3,嵌套于S1中,与S2平行
}
}
```
所有局部变量,包括函数的参数,处于同一个命名空间中。同一个局部作用域内,不允许有重名/覆盖定义。因此,上述例子中,`x1`和`x2`不能重名。但是对于嵌套的局部作用域,内层作用域可以覆盖外层作用域的名字。在上面的例子中,`x3`、`x4`都可以与`x1`或`x2`重名,并会在各自的作用域内覆盖掉`x1`/`x2`的定义。互不嵌套的作用域互不干扰。所以上述作用域`S2`、`S3`互不干涉,`x3`和`x4`可以重名。
## 仍在设计中的特性
Deeplang目前正处于活跃开发中。上述的设计和特性都尚未稳定,随时可能被更改。下面是一些仍在讨论中的特性,它们可能会在未来成为语言的一部分。
### 数组宏
Deeplang是一门面向IoT的语言,在IoT编程中一个十分重要的应用场景就是对各类二进制协议的高效解析。关于Deeplang中如何支持这一场景仍在讨论中。其中一个语言层面的方案是支持内建的数组操作宏,例如:
```dp
let arr: [i32; 100] = [];
arr@match([s] == 1, [s + 10] == 1);
```