语法规范
本节定义 AutoLang 的词法和语法。
词法
AutoLang 的词法与 C++ 基本相同。词法定义了 AutoLang 源代码如何转为一系列 token。
输入格式
由一系列 UTF-8 代码单元组成的输入保证支持。
若输入以 UTF-8 编码,则应为一个结构良好的 UTF-8 码单元序列。若第一个翻译字符是 U+FEFF,则如同它不存在。输入序列中的每对 U+000D 和 U+000A,以及每个没有后续 U+000A 的 U+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 不支持块注释,这主要是由于:
- 块注释与行注释、字符串字面量等交织时,行为较为复杂,且没有完美方案
- 实际考察后发现块注释极少被使用,编辑器们也主要提供行注释快捷键
标识符
identifier = (start | `_`) { continue }其中 start 和 continue 分别对应拥有对应 Unicode XID 属性的字符。
源代码中的标识符将经过 NFC 正规化。
字面量
字面量是一个由单一 token(而不是由一连串 tokens)组成的表达式,它立即、直接表示它所代表的值,而不是通过名称或其他一些求值/计算规则来引用它。字面量是常量表达式的一种形式,所以它(主要)用在编译时求值。
字符与字节相关字面量
字符字面量由一对单引号 ' 定界。它内部包含 1 个非 '、\、回车、换行、制表符的字符或转义序列。
字节字面量类似于字符字面量,但在首个 ' 前需要一个 b 前缀,且内容不允许非 ASCII 字符。
字符串字面量从 " 开始,在另一个 " 或行末(不包含换行符)结束。若字符串字面量在行末结束,则它被标记为一个多行字符串。例如:
x :=
"114514
"1919810
"end";则 "114514 和 "1919810 被标记为多行字符串。
原始字符串字面量从 '' 开始,到行末或文件末处结束。原始字符串不允许转义,且会被视为多行字符串。
数字字面量
整数字面量分为十进制、二进制、八进制、十六进制、任意进制。
十进制整数允许十进制数位。二进制、八进制、十六进制整数分别以 0b、0o、0x 开头,任意进制整数以一个 0r 后接一个 36 进制数位开头,后接对应进制(如 0rC 对应 12 进制)的数位。在任意两个数位和进制标记之后,允许插入一个 ' 作为分隔符,如 114'514,但不允许连用两个分隔符。
浮点数字面量有待讨论。
Bool 字面量
true 和 false 是 Bool 字面量。
标签
标签是一个单引号 ' 后紧接一个标识符。
标点符号与运算符
.:=,;<>+-*/%!&|^~$#?\@->...|++--+=-=*=/=%=~===!=>=<=<<>>&&||...<<=>>=
token 树
token 树是一颗对应于 token 序列的平衡括号对树,反之,一个 token 序列对应一片 token 树森林。
token-tree =
| token
| delimited-token-tree
delimited-token-tree =
| `(` { token-tree } `)`
| `[` { token-tree } `]`
| `{` { token-tree } `}`语法
AutoLang 语法主要受 Rust、Cpp2、TypeScript 影响。
程序结构
file = [shebang] module-inner属性
inner-attr = `#` `[` attr `]` `;`
outer-attr = `#` `[` attr `]`
attr = path [ attr-arg ]
attr-arg =
| `=` expr
| delimited-token-tree项
item = { outer-attr } [ visibility ] (
| binding-item
| function-item
| type-item
| impl-item
| block-item
| using-item
| module-item
) `;`
block-item = `{` module-inner `}`绑定
binding-item = binding
binding = pattern `:` [ type ] [ `=` expr ]类型
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
) `;`函数
function-item = name `:` `fn` [ parameters ] [ `mut` ] [ `->` type ] [ `=` expr ]
parameters = `(` { parameter `,` } [parameter] `)`
parameter = name [ `:` type ]语句
stmt =
| item
| { outer-attr } expr `;`
| expr assignment-operator expr `;`
assignment-operator =
| `=`
| `+=`
| `-=`
| `*=`
| `/=`
| `%=`
| `<<=`
| `>>=`模式
pattern =
| `_`
| [ `mut` ] name表达式
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 循环体中可以携带值,若走到循环体结尾,则自动退出循环并返得到值。
各个绑定力有待补充。
string-literal = atom-string { atom-string }
atom-string =
| common-string-literal
| multiline-string-literal
| raw-string-literalstring-literal 由一个或多个连续的 atom-string 组成。其中连续的两条 multiline-string-literal 中间还会插入额外的 \n。
名字
ident = `_` | name
field-name = name | integer-literal
path = [ `::` ] local-path
local-path = { path-segment } name
path-segment = name `::`ident 是词法中的 identifier,而 name 则是其去掉 _。
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 ] `}`可见性:
visibility =
| `pub`
| `pro`
| `pri`