2.3. 语句
Daslang 程序是一个简单的语句序列:
stats ::= stat [';'|'\n'] stats
Daslang 中的语句与 C 系列语言(C/C++、Java、C# 等)中的语句相当:有赋值、函数调用、程序流控制结构等。 还有一些自定义语句,如 blocks、structs 和 initializers(本文档稍后将详细介绍)。 语句可以用换行符分隔,或者 ‘;’。
2.3.1. 可见性块
visibility_block ::= '{' (stat)* '}'
由大括号 ({ }) 分隔的语句序列称为 visibility_block。
2.3.2. 控制流语句
Daslang 实现最常见的控制流语句: if, while, for
2.3.2.1. true 和 false
Daslang 具有强布尔类型 (bool)。只有具有布尔类型的表达式才能成为控制语句中条件的一部分。
2.3.2.2. if/elif/else 语句
stat ::= 'if' ( exp ) visibility_block (['elif' ( exp ) visibility_block])* ['else' visibility_block]
根据表达式的结果有条件地执行语句:
if ( a > b ) {
a = b
} elif ( a < b ) {
b = a
} else {
print("equal")
}
一行 if 语句:
if ( a > b ) a = b // 这是一个单行表示法
a = b if ( a < b ) // 这是一个后缀表示法
2.3.2.3. while 语句
stat ::= 'while' ( exp ) stat
在条件为 true 时执行语句:
while ( true ) {
if ( a<0 ) {
break
}
}
2.3.3. 基于范围的循环
2.3.3.1. for
stat ::= 'for' ( iterator 'in' [rangeexp] ) visibility_block
按顺序为 expression 中的每个元素/迭代器执行一个循环体语句:
for ( i in range(0, 10) ) {
print("{i}") // 将打印 0 到 9 之间的数字
}
// 或
let arr: array<int>
resize(arr, 4)
for ( i in arr ) {
print("{i}") // 将从第一个元素到最后一个元素打印数组的内容
}
// 或
var a: array<int>
var b: int[10]
resize(a, 4)
for ( l, r in a, b ) {
print("{l}=={r}") // 将打印数组的内容和数组 B 的前 4 个元素
}
// 或
var tab: table<string; int>
for ( k, v in keys(tab), values(tab) ) {
print("{k}:{v}") // 将打印表格的内容,格式为 key:value
}
可迭代类型是通过迭代器实现的 (参阅 Iterators).
2.3.4. break
stat ::= 'break'
break 语句终止循环的执行 (for
或 while
).
2.3.5. continue
stat ::= 'continue'
continue 运算符跳转到循环的下一个迭代,跳过其余语句的执行。
2.3.6. return
stat ::= return [exp]
stat ::= return <- exp
return 语句终止当前函数、块或 lambda 的执行,并可选择返回表达式的结果。如果省略表达式,则函数将不返回任何内容,并且假定返回类型为 void。 从同一函数返回不匹配的类型是一个错误(即,所有返回都应返回相同类型的值)。 如果函数的返回类型是显式的,则返回表达式应返回相同的类型。
例:
def foo(a: bool) {
if ( a ) {
return 1
} else {
return 0.f // 错误, 不同的返回类型
}
}
def bar(a: bool): int {
if ( a ) {
return 1
} else {
return 0.f // 错误, 不匹配的返回类型
}
}
def foobar(a) {
return a // return type 将与 argument type 相同
}
在生成器块中,return 必须始终返回布尔表达式,其中 false 表示生成结束。
‘return <- exp’ 语法用于 move-on-return:
def make_array {
var a: array<int>
a.resize(10) // 填充一些东西
return <- a // return 将返回
}
let a <- make_array() //创建填充make_array的数组
2.3.7. yield
Yield 的作用类似于生成器的 ``return``(参阅 Generators).
它类似于 return 语法,但只能在 generator
块中使用。
Yield 必须始终生成与生成器的值匹配的值:
var gen <- generator<int>() <| $ {
yield 0 // int 0
yield 1 // int 1
return false
}
2.3.8. Finally 语句
stat ::= finally visibility-block
Finally 声明一个区块,该区块将对任何区块(包括控制语句)执行一次。
finally 块不能包含 break
, continue
, 或 return
语句。
它旨在确保在 “all are done ” 之后执行。请考虑以下:
def test(a: array<int>; b: int) {
for ( x in a ) {
if ( x == b ) {
return 10
}
}
return -1
} finally {
print("print anyway")
}
def test(a: array<int>; b: int) {
for ( x in a ) {
if ( x == b ) {
print("we found {x}")
break
}
} finally {
print("we print this anyway")
}
}
最后,可用于资源取消分配。
可以使用 defer
宏将代码添加到块的 finally 语句中:
require daslib/defer
def foo {
print("a\n")
} finally {
print("b\n")
}
def bar {
defer() {
print("b\n")
}
print("a\n")
}
在上面的例子中,函数 foo
和 bar
在语义上是相同的。
多个 defer
语句以相反的顺序出现。
defer_delete
宏为其参数添加 delete 语句,并且不需要块。
2.3.9. 局部变量声明
initz ::= id [:type] [= exp]
initz ::= id [:type] [<- exp]
initz ::= id [:type] [:= exp]
scope ::= `inscope`
ro_stat ::= 'let' [scope] initz
rw_stat ::= 'var' [scope] initz
可以在函数中的任何位置声明局部变量。它们存在于其声明和声明它们的可见性块的末尾之间。
let
声明只读变量,而 var
声明可变 (读写) 变量。
复制 =
、移动 ->
或克隆 :=
语义指示如何初始化变量。
如果指定了 inscope
, 则 delete id
语句被添加到块的 finally 部分,其中声明了变量。
它不能直接出现在 loop 块中,因为 loop 的 finally 部分只执行一次。
2.3.10. 函数声明
stat ::= 'def' id ['(' args ')'] [':' type ] visibility_block
arg_decl = [var] id (',' id)* [':' type]
args ::= (arg_decl)*
声明一个新函数。例子:
def hello {
print("hello")
}
def hello(): bool {
print("hello")
return false
}
def printVar(i: int) {
print("{i}")
}
def printVarRef(i: int&) {
print("{i}")
}
def setVar(var i: int&) {
i = i + 2
}
2.3.11. try/recover
stat ::= 'try' stat 'recover' visibility-block
try 语句包含一个代码块,其中可能发生 panic 情况,例如致命运行时错误或 panic 函数。try-recover 子句提供 panic 处理代码。
重要的是要理解 try/recover 不是正确的错误处理代码,也绝对不是实现 control-flow 的方法。 与 Go 语言非常相似,这实际上是一个无效的情况,通常不应该在生产环境中发生。 潜在异常的示例包括取消引用 null 指针、索引到越界数组等。
2.3.12. panic
stat ::= 'panic' '(' [string-exp] ')'
调用 panic
会导致运行时异常,并在日志中提供 string-exp。
2.3.13. 全局变量
stat ::= 'let|var' { shared } {private} '\n' id '=' expression
stat ::= 'let|var' { shared } {private} '\n' id '<-' expression
stat ::= 'let|var' { shared } {private} '\n' id ':=' expression
声明一个常量全局变量。 此变量在脚本初始化期间初始化一次(或每次手动调用脚本 init 时初始化)。
shared
表示该常量将初始化一次,并且其内存在 Daslang 上下文的多个实例之间共享。
private
表示该变量在其模块之外不可见。
2.3.14. enum
enumerations ::= ( 'id' ) '\n'
stat ::= 'enum' id { enumerations }
声明一个枚举 (参阅 Constants & Enumerations).
2.3.15. 表达式语句
stat ::= exp
在 Daslang 中,每个表达式也都允许是一个语句。 如果是这样,则表达式的结果将被丢弃。