1 Star 0 Fork 0

PLOC / Deeplang

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT
Deeplang: a new programming language for IoT

Deeplang 简介

Deeplang语言是一种自制编程语言,由来自浙大、中科大、帝国理工等高校的学生共同完成。

我们致力于将Deeplang语言打造为具有鲜明内存安全特性的面向IoT场景的语言,设计过程中参考Rust的安全机制,但又根据IoT场景的特性选择了更合适的解释执行模式。Deeplang是一种静态类型、强类型语言,参考C-style设计语法,同时支持过程式、逻辑式和函数式的混合范式。

Deeplang的独特安全特性帮助其具有一定的竞争力。作者正在持续的开发和迭代中。


目录

  1. 注释
  2. 程序入口
  3. 表达式
  4. 控制语句
  5. 模式匹配
  6. 函数
  7. 内建类型
  8. 类型定义
  9. 接口声明
  10. 接口实现
  11. 命名规范与作用域规则总结
  12. 仍在设计中的特性

注释

单行注释

// code

多行注释

/*
code
code
*/

程序入口

在Deeplang程序中,顶层代码没有表达式,只有各类定义。 具体来说,Deeplang有如下的顶层代码:

  • 类型定义
  • 接口声明
  • 接口实现
  • 全局变量定义
  • 函数定义

整个程序的运行入口有且只有一个,就是以main作为名字的函数。

表达式

Deeplang和C、Java等语言一样,采用了表达式和语句二分的设计。

Deeplang中有以下几种表达式:

  • 字面量,包括整数、浮点数、单个字符和字符串
  • 变量名字。变量名字必须以小写字母开头。
  • 一元操作符和二元操作符,如! x1 + 2等。
  • 元组,如(1, "2", (3, 4))
  • 数组,如[1, 1, 4, 5, 1, 4]
  • 代数数据类型(和类型),形如<分支名字>(<值列表>)。详见类型定义的部分
  • 创建结构体,形如是<类型名字> { <域名字>: <值>, ... }
  • 获取结构体中的域,如point.x
  • 函数调用,形如<函数名字>(<参数列表>)
  • 调用方法,形如<表达式>.<方法名字>(<参数列表>)。Deeplang中没有类系统,方法调用的解析是静态的。多态可以通过接口实现。
  • 表达式层级的条件。语法待定。
  • 表达式层级的模式匹配。语法待定。

控制语句

Deeplang中有以下的控制语句:

  • 每个表达式都是控制语句。表达式的结果会被丢弃。

  • 可以将多条控制语句有分号连接、用花括号括起,按顺序执行,变成一条语句。

  • 声明变量let <pattern> [= <rhs>]。其中<pattern>是一个带类型标注的模式<rhs>是一个表达式。通过支持等于号左侧出现任意pattern,可以实现如let (x, y) = some_pair的便利解构。

  • 条件语句if (<条件>) <分支1> else <分支2>

  • 传统for循环,如:

        for ({let mut i: I32 = 0}; i < 10, i += 1) {
            foo();
        }

    与大部分语言不同,循环初始化部分的语句必须用花括号括起。

  • 基于迭代器的for循环,如:

            for (<pattern> : iterable) {
                ...
            }

    这类for循环的具体语义取决于(尚未完成的)标准库中的迭代器设计。

  • while循环,形如:

            while (<循环继续条件,表达式>)
              <循环体,必要时由花括号括起>
  • 模式匹配语句,例如:

          match (optional_integer) {
              Some(x) => { return x }
              None    => { return 0 }
          }
  • 特殊控制语句,如returnbreakcontinue

模式匹配

Deeplang中支持一套模式匹配系统,包括如下几种可以用于匹配的模式:

  • 下划线_,匹配任何值。
  • 变量[mut] <变量名> [: <类型>],匹配任何值,并将<变量名>绑定到匹配到的值。新的变量默认是不可变的,除非在变量名前加上mut前缀。
  • as模式,形如如<pattern> as [mut] <variable> [: <类型]。如果匹配的值能够与<pattern>匹配,将<variable>绑定到该值。variable同样可以用mut修饰。
  • ADT模式,如NoneSome(x)Some(Some(y))等。
  • 结构体模式,形如<类型名字> { <结构体的域> : <匹配这个域的值的模式>, ... }。不需要匹配所有的域,没有在模式中出现的域将被无视。
  • 元组解包模式,如(a, (b, c), d)等。

函数

函数的签名形如fun <函数名字>(<参数列表>) -> <返回值类型>,其中参数列表用逗号隔开。目前参数类型和返回值类型都必须显式标注。一些函数定义的例子如下:

fun foo(bar: Bar) -> Foo {
   ...
}
fun multiParam(x: i32, y: i32) {
    ...
}

内建类型

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中类型名字必须以大写字母开头。

结构体类型定义

type <类型名字> {
    <域名字> : <域类型>,
    ...
}

结构体的域的名字都必须以小写字母开头。

使用结构体定义新类型的一些例子如下:

type Color {
    r : U8,
    g : U8,
    b : U8
}
type Point {
    x : F32,
    y : F32,
    z : F32
}

此外,结构体定义还支持委托。在结构体类型的声明中,可以加入形如as <域名字> : <委托的类型>的声明。

例如,在声明:

type S2 {
    as s1 : S1
}

中,类型S2会有一个名为s1、类型为S1的域。此外,S1中的所有域都将被“委托”到S2中。也就是说,对于S1中的每一个域xS2中也会有一个对应的域x,且S2.x = S2.s1.x

下面的例子展示了委托的使用方法:

type ColoredPoint {
    as position : Point,
    color : Color
}
let cp : ColoredPoint = ...;
cp.color;     // of type Color
cp.position;  // of type Point
cp.x          // of type F32, same as cp.position.x

ADT类型定义

type <类型名字> [
    <分支名字>[(<类型参数列表>)],
    ...
]

每个ADT必须有至少一个分支,而每个分支的参数类型列表是可选的。如果没有参数,则不写()

ADT中分支的名字必须以大写字母开头。分支的类型参数列表中,可以给参数加上名字。但这些名字只有注释作用,没有实际语义。

使用ADT定义新类型的一个例子如下:

type Shape [
    Rectangle(width : U32, height : U32),
    Circle(radius : U32),
    Nothing
]

可以通过模式匹配来对一个ADT值的不同分支作出不同的处理。

接口声明

在Deeplang中,方法调用的解析是静态的,多态需要通过接口来实现的。

接口声明形如:

interface <接口名字> extends <依赖的接口列表> {
    fun <方法名字>(参数列表) -> <返回值类型>;
    ...
}

通过为一个类型实现该接口,可以使该类型的值支持接口中的方法的调用。在接口声明内部,可以通过This来指代实现该接口的类型自身。下面是一些接口声明的例子:

interface Eq {
    fun equals(this, other : This) : Bool;
}
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的类型。当需要表达“同时实现了若干个接口的类型”时,可以利用一个没有方法的空接口以及接口的依赖列表来实现,例如:

// 接口Number等价与接口Ordered + Add + Mul
interface Number extends Ordered, Add, Mul {
}
fun some_function(a : Number, b : Number) : Number {
    if (equals(a, b))
        return add(a, a);
    else
        return mul(a, a);
}

接口实现

在Deeplang中,为一个类型T实现接口I的语法如下:

impl I for T {
    fun <方法名字>(<参数列表>) -> <返回值类型> {
        <方法的实现>
    }
}

在方法的实现中,可以用this来访问方法的调用者。除了实现接口外,也可以直接为一个类型实现一些方法,语法为:

impl T {
    ... // 同上
}

在这种impl块中实现的方法将能够被类型为T的值调用。下面是一个通过接口来模拟鸭子类型的例子:

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平行
    }
}

所有局部变量,包括函数的参数,处于同一个命名空间中。同一个局部作用域内,不允许有重名/覆盖定义。因此,上述例子中,x1x2不能重名。但是对于嵌套的局部作用域,内层作用域可以覆盖外层作用域的名字。在上面的例子中,x3x4都可以与x1x2重名,并会在各自的作用域内覆盖掉x1/x2的定义。互不嵌套的作用域互不干扰。所以上述作用域S2S3互不干涉,x3x4可以重名。

仍在设计中的特性

Deeplang目前正处于活跃开发中。上述的设计和特性都尚未稳定,随时可能被更改。下面是一些仍在讨论中的特性,它们可能会在未来成为语言的一部分。

数组宏

Deeplang是一门面向IoT的语言,在IoT编程中一个十分重要的应用场景就是对各类二进制协议的高效解析。关于Deeplang中如何支持这一场景仍在讨论中。其中一个语言层面的方案是支持内建的数组操作宏,例如:

let arr: [i32; 100] = [];
arr@match([s] == 1, [s + 10] == 1);
MIT License Copyright (c) 2023 杨海龙 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

面向资源受限的IoT设备的编程语言 展开 收起
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/ploc-org/deeplang.git
git@gitee.com:ploc-org/deeplang.git
ploc-org
deeplang
Deeplang
develop

搜索帮助