LeekScript Next

LeekScript Next

> LeekScript

简介

LeekScript NextLeekScript 语言的未来版本,它基于一个使用 LLVM 的全新编译器,速度更快。这个版本目前暂停开发,以便集中精力为当前的 LeekScript(第 2 版、第 3 版等)添加新功能。

项目的 Git 仓库:https://github.com/leek-wars/leekscript-v2 论坛主题:https://leekwars.com/forum/category-6/topic-7833

这是一份基于 LSv1 教程的草稿,欢迎参与完善!

这里有一份 pastebin,按模块列出了全部函数。

字面量

字面量就是直接写在代码里的值。LeekScript 允许直接写出以下类型的值:

容器可以存放任何类型的字面量(包括其他容器)。提醒一下:

表达式

一个表达式由字面量以及运算符或函数的调用组成。它最简单的形式就是一个字面量:0。另一种更常见的形式是数学运算符与数字的组合:-1、1 + 1、0 * 3 等等。而最高级的形式会用到函数调用:max(1, 2)、rand() 等等。

在 LeekScript 中,可以连续求值多个表达式,既可以忽略它们的结果,也可以把结果保存到变量里。

1 + 1 2 * 2 Number.cos(π * 2)

上面这段代码的求值结果是 1。

变量

变量把一个名字和一个值关联起来。它可以存放任何对象:既可以赋给它一个字面量,也可以赋给它一个表达式的结果。

let me = Fight.getEntity() var y = 1 + 1 const RAD = 180.0 / π global DEBUG = false

在这四种声明中,有两种允许修改所声明的变量,另外两种可以在代码的任何地方访问。建议按以下优先顺序使用它们:

const 和 global 这两个关键字目前还没有在语言中实现。你可以用 let 和 var 得到同样的效果:把所有函数都用匿名语法来声明,从而利用变量的作用域规则。

更多细节请看变量页面。虽然它目前是为旧版 LeekScript 写的,但运作方式是一样的,新关键字只是带来了上面提到的那些新功能。为 LS 2 准备的草稿见变量 V2

控制结构

我们已经看到,可以连续求值多个表达式,从而写出稍微复杂一点的程序。你新建文件时得到的那个基础 AI 就是这么做的。不过,这远远算不上最有用的写法,所以我们还有一些工具,可以改变表达式的求值顺序。

分支

我们可以根据某个表达式的结果,选择求值这一部分表达式而不是另一部分,比如先看看当前装备的是哪把武器,再决定换上另一把武器,或者避免重复装备同一把武器。

IF

用 if 控制结构就能做到。if 需要一个求值结果为布尔值的表达式、一组在结果为真时求值的表达式,以及一组在结果为假时求值的表达式。第二组表达式可以省略。

if me.getWeapon() == null me.setWeapon(Weapon.PISTOL)

if weapon != Weapon.PISTOL { me.setWeapon(Weapon.PISTOL) weapon = Weapon.PISTOL } else { me.say("我准备好决斗了。") }

if !me.setWeapon(Weapon.PISTOL) then me.say("我的手枪去哪儿了?") end

let fruit = if me.getWeapon() == Weapon.AXE then "apple" else "banana" end

关于 if 的更多信息,可以去看为当前版本 LeekScript 写的页面,那里讲的内容在 LeekScript 2 中同样适用(除了 == 和 === 之间的区别):条件

MATCH

用 match 控制结构也能做到同样的事,甚至能做得更多。这一次可以对任意表达式求值,然后给出一组结果以及各自要求值的表达式。这样就能轻松重现 if 的行为,有些语言甚至把它当作一种语法糖,直接用 match 来替换。

关于分支的更多信息,可以查看“分支”页面。

函数

函数是一段代码,它把一些参数与一个表达式或一串指令关联起来。 它最简单的形式是匿名函数。这样一来,一个不修改自身参数的函数可以写成下面几种形式:

x -> x (x) -> x x -> { x } (x) => { x } function(x) { x }

对于箭头函数,括号是可选的;如果函数体只有一个表达式/指令,花括号也可以省略。 默认会返回最后一个表达式的结果。也可以使用 return 关键字。

我们还可以给函数命名:要么把它赋给一个变量,要么使用专门的语法:

let id = x -> x function id(x) { x }

这样就能在表达式里更方便地复用它们:max(id(1), 0)。

循环

用叫做循环的控制结构,可以重复执行一串指令。

WHILE

最简单的循环形式,就是只要块头部的条件成立,就一直重复执行它的代码块:

这种循环的语法是:while condition { instructions }(while 条件 { 指令 })。如果代码块里只有一条指令,可以省略花括号,不过并不推荐这么做。

FOR

这种循环稍微复杂一些,它由一个初始化、一个条件和一个步进组成:

这种循环的语法是:for initialisation; condition; pas { instructions }(for 初始化; 条件; 步进 { 指令 })。花括号的注意事项同上。头部的这几个部分也可以全部或部分省略,因此 for ; condition ; { instructions } 等价于 while。不过,如果一个 while 循环能完成完全一样的工作,就不要用 for 循环。

FOREACH

这种循环可以遍历数据结构中的元素,比如数组、映射、匿名对象等等……

这种循环的语法是:for elem in struct { instructions }(for 元素 in 结构 { 指令 })。struct 当然不一定要像上面的例子那样直接写在指令里。elem 是一个模式,取决于数据结构本身以及你想使用的内容。对于映射,可以使用与 LS 1 的关联数组类似的语法(for k : v in map),但更常用的语法是:for k, v in map。当然也可以省略键,只遍历元素:for v in map。这些说明适用于所有可迭代的结构。[待确认]

BREAK
CONTINUE
数组推导式

数据结构