Skip to content

语法规范

本节定义 AutoLang 的词法和语法。

词法

AutoLang 的词法与 C++ 基本相同。词法定义了 AutoLang 源代码如何转为一系列 token。

输入格式

由一系列 UTF-8 代码单元组成的输入保证支持。

若输入以 UTF-8 编码,则应为一个结构良好的 UTF-8 码单元序列。若第一个翻译字符是 U+FEFF,则如同它不存在。输入序列中的每对 U+000DU+000A,以及每个没有后续 U+000AU+000D,都如同一个 U+000D

shebang

输入的第一行若以 #! 开头,则该行被视为 shebang 处理。对后续解析来说,shebang 如同不存在。

空白符

空白符是非空字符串,它里面只包含具有 Pattern_White_Space 属性的 Unicode 字符。即:

  • U+0009 (水平制表符, '\t')
  • U+000A (换行符, '\n')
  • U+000B (垂直制表符)
  • U+000C (分页符)
  • U+000D (回车符, '\r')
  • U+0020 (空格符, ' ')
  • U+0085 (下一行标记符)
  • U+200E (从左到右标记符)
  • U+200F (从右到标左记符)
  • U+2028 (行分隔符)
  • U+2029 (段分隔符)

在 AutoLang 中,空白符仅用于构成 token 或分割 token,没有没有语法或语义意义。若将不构成 token 的连续空白符序列换成另一个合法的空白符序列,则程序如同不变。

注释

从不在字符串字面量中的 // 开始(包含)到该行的行末或源码序列末的源码序列被视为注释。

AutoLang 不支持块注释,这主要是由于:

  1. 块注释与行注释、字符串字面量等交织时,行为较为复杂,且没有完美方案
  2. 实际考察后发现块注释极少被使用,编辑器们也主要提供行注释快捷键

标识符

ebnf
identifier = (start | `_`) { continue }

其中 startcontinue 分别对应拥有对应 Unicode XID 属性的字符。

源代码中的标识符将经过 NFC 正规化。

字面量

字面量是一个由单一 token(而不是由一连串 tokens)组成的表达式,它立即、直接表示它所代表的值,而不是通过名称或其他一些求值/计算规则来引用它。字面量是常量表达式的一种形式,所以它(主要)用在编译时求值。

字符与字节相关字面量

字符字面量由一对单引号 ' 定界。它内部包含 1 个非 '\、回车、换行、制表符的字符或转义序列。

字节字面量类似于字符字面量,但在首个 ' 前需要一个 b 前缀,且内容不允许非 ASCII 字符。

字符串字面量从 " 开始,在另一个 " 或行末(不包含换行符)结束。若字符串字面量在行末结束,则它被标记为一个多行字符串。例如:

autolang
x :=
  "114514
  "1919810
  "end";

"114514"1919810 被标记为多行字符串。

原始字符串字面量从 '' 开始,到行末或文件末处结束。原始字符串不允许转义,且会被视为多行字符串。

数字字面量

整数字面量分为十进制、二进制、八进制、十六进制、任意进制。

十进制整数允许十进制数位。二进制、八进制、十六进制整数分别以 0b0o0x 开头,任意进制整数以一个 0r 后接一个 36 进制数位开头,后接对应进制(如 0rC 对应 12 进制)的数位。在任意两个数位和进制标记之后,允许插入一个 ' 作为分隔符,如 114'514,但不允许连用两个分隔符。

浮点数字面量有待讨论。

Bool 字面量

truefalseBool 字面量。

标签

标签是一个单引号 ' 后紧接一个标识符。

标点符号与运算符

  • .
  • :
  • =
  • ,
  • ;
  • <
  • >
  • +
  • -
  • *
  • /
  • %
  • !
  • &
  • |
  • ^
  • ~
  • $
  • #
  • ?
  • \
  • @
  • ->
  • ..
  • .|
  • ++
  • --
  • +=
  • -=
  • *=
  • /=
  • %=
  • ~=
  • ==
  • !=
  • >=
  • <=
  • <<
  • >>
  • &&
  • ||
  • ...
  • <<=
  • >>=

token 树

token 树是一颗对应于 token 序列的平衡括号对树,反之,一个 token 序列对应一片 token 树森林。

ebnf
token-tree =
  | token
  | delimited-token-tree
delimited-token-tree =
  | `(` { token-tree } `)`
  | `[` { token-tree } `]`
  | `{` { token-tree } `}`

语法

AutoLang 语法主要受 Rust、Cpp2、TypeScript 影响。

程序结构

ebnf
file = [shebang] module-inner

属性

ebnf
inner-attr = `#` `[` attr `]` `;`
outer-attr = `#` `[` attr `]`
attr = path [ attr-arg ]
attr-arg =
  | `=` expr
  | delimited-token-tree

ebnf
item = { outer-attr } [ visibility ] (
    | binding-item
    | function-item
    | type-item
    | impl-item
    | block-item
    | using-item
    | module-item
  ) `;`

block-item = `{` module-inner `}`

绑定

ebnf
binding-item = binding
binding = pattern `:` [ type ] [ `=` expr ]

类型

ebnf
type-item = name `:` type-kind `=` type
type-kind = `type` | `nominal`

type =
  | type-infer
  | type-path
  | type-fn-ptr
  | type-ref
  | type-ptr
  | type-tuple-or-paren
  | type-array-or-slice
  | type-struct

type-infer = `_`

type-path = path

type-fn-ptr = type-tuple-or-paren [ `mut` ] -> type

type-ref = `&` [ `mut` ] type

type-ptr = `*` [ `mut` ] type

type-tuple-or-paren = `(` tuple-field-list `)`
tuple-field-list = { tuple-field `,` } [ tuple-field ]
tuple-field = { outer-attr } [ visibility ] type

type-array-or-slice = `[` type [ `;` expr ] `]`

type-struct = `{` struct-field-list `}`
struct-field-list = { struct-field `,` } [ struct-field ]
struct-field = { outer-attr } [ visibility ] field-name `:` type

impl-item = name `:` `impl` type `=` `{` { associated-item } `}`
associated-item = { outer-attr } [ visibility ] (
    | function-item
    | type-item
  ) `;`

函数

ebnf
function-item = name `:` `fn` [ parameters ] [ `mut` ] [ `->` type ] [ `=` expr ]
parameters = `(` { parameter `,` } [parameter] `)`
parameter = name [ `:` type ]

语句

ebnf
stmt =
  | item
  | { outer-attr } expr `;`
  | expr assignment-operator expr `;`

assignment-operator =
  | `=`
  | `+=`
  | `-=`
  | `*=`
  | `/=`
  | `%=`
  | `<<=`
  | `>>=`

模式

ebnf
pattern =
  | `_`
  | [ `mut` ] name

表达式

ebnf
expr = { outer-attr } (
    | atom-expr
    | basic-expr
    | chain-expr
  )

atom-expr =
  | `_`
  | tuple-or-paren-expr
  | `[` { expr `,` } [ expr ] `]`
  | `[` expr `;` expr `]`
  | `{` { field-value `,` } [ field-value ] `}`
  | [ label `:` ] block
  | literal
  | path
  | case-expr
  | `if` expr block [ else-clause ]
  | [ label `:` ] while-expr [ else-clause ]
  | [ label `:` ] for-expr [ else-clause ]
  | [ label `:` ] iterate-expr

tuple-or-paren-expr = `(` { expr `,` } [ expr ] `)`

field-value =
  | field-name `:` expr
  | name

block = `{` { inner-attr } { stmt } [ expr ] `}`

case-expr = `case` `{` { case-arm `,` } [ case-arm ] `}`
case-arm = expr `=` expr

while-expr = `while` expr block
for-expr = `for` pattern `in` expr block
iterate-expr = `iterate` pattern `=` expr block

else-clause = `else` block

basic-expr =
  | expr `~` expr
  | expr `~=` expr
  | expr `!=` expr
  | expr `<<` expr
  | expr `>>` expr
  | expr `+` expr
  | expr `-` expr
  | expr `*` expr
  | expr `/` expr
  | expr `%` expr
  | `-` expr
  | `!` expr
  | `*` expr
  | `&` [ `mut` ] expr
  | expr `++`
  | expr `--`
  | expr `as` type
  | expr tuple-or-paren-expr
  | expr `[` expr `]`
  | `return` expr
  | `break` [ label ] expr
  | `cont` [ label ] expr
  | `fn` [ parameters ] [ `->` type ] `=` expr
  | expr `.` name
  | expr `.` path tuple-or-paren-expr

chain-expr =
  | expr less expr { less expr }
  | expr greater expr { greater expr }
  | expr `||` expr { `||` expr }
  | expr `&&` expr { `&&` expr }
less =
  | `<`
  | `<=`
  | `==`
greater =
  | `>`
  | `>=`
  | `==`

literal =
  | integer-literal
  | char-literal
  | byte-literal
  | string-literal
  | bool-literal

给定表达式 x(x) 是括号表达式;(x,) 是单元素元组;{ x } 是块;{ x, } 是简写单字段结构体。

不支持 else if 是刻意的,case 表达式将作为其(尤其是连续的 else if)替代。

cont 仅在 iterate 循环体中可以携带值,若走到循环体结尾,则自动退出循环并返得到值。

各个绑定力有待补充。

ebnf
string-literal = atom-string { atom-string }
atom-string =
  | common-string-literal
  | multiline-string-literal
  | raw-string-literal

string-literal 由一个或多个连续的 atom-string 组成。其中连续的两条 multiline-string-literal 中间还会插入额外的 \n

名字

ebnf
ident = `_` | name

field-name = name | integer-literal

path = [ `::` ] local-path
local-path = { path-segment } name
path-segment = name `::`

ident 是词法中的 identifier,而 name 则是其去掉 _

ebnf
module-item = name `:` `mod` `=` `{` module-inner `}`
module-inner = { inner-attr } { item }

using-item = `using` using-tree
using-tree = [ `::` ] local-using-tree
local-using-tree =
  | `_`
  | local-path [ `as` ident ]
  | local-path `::` `{` { local-using-tree `,` } [ local-using-tree ] `}`

可见性:

ebnf
visibility =
  | `pub`
  | `pro`
  | `pri`