From 91e0fb3af724114a6934ca68d55514e096ab9337 Mon Sep 17 00:00:00 2001 From: jaywcjlove <398188662@qq.com> Date: Tue, 25 Jun 2024 19:23:58 +0800 Subject: [PATCH] doc: add hook.md --- README.md | 1 + docs/hook.md | 1025 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1026 insertions(+) create mode 100644 docs/hook.md diff --git a/README.md b/README.md index 4b58d14..3df48b5 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ Quick Reference [Flutter](./docs/flutter.md) [Golang](./docs/golang.md) [GraphQL](./docs/graphql.md) +[Hook](./docs/hook.md) [Java](./docs/java.md) [Julia](./docs/julia.md) [Kotlin](./docs/kotlin.md) diff --git a/docs/hook.md b/docs/hook.md new file mode 100644 index 0000000..3181d0a --- /dev/null +++ b/docs/hook.md @@ -0,0 +1,1025 @@ +Hook 备忘清单 +=== + +Hook 备忘单是 [Hook](https://github.com/hook-lang/hook/) 编程语言的一页参考表。 + +## 入门 + +### 介绍 + +- [GitHub](https://github.com/hook-lang/hook) +- [在线运行](https://hook-lang.github.io/hook-playground) +- [示例](https://github.com/hook-lang/hook/tree/main/examples) +- [VSCode 扩展](https://marketplace.visualstudio.com/items?itemName=fabiosvm.hook) + +### Hook 看起来是什么样的? + +```rust +fn factorial(n) { + if (n == 0) + return 1; + return n * factorial(n - 1); +} +``` + +Hook 具有类似于 `C` 的现代语法。 + +### Hello, World + +```js +println("Hello, World!"); +// Hello, World! +``` + +Hook 中的 `Hello, World!` 程序。 + +### 使用 Homebrew 安装 + +```text +brew tap hook-lang/hook +brew install hook +hook --help +``` + +解释器可以通过 [`Homebrew`](https://brew.sh) 获取。 + +### 在 Windows 上安装 + + +```bash +cd %tmp% +curl -sSLO https://raw.githubusercontent.com/hook-lang/hook/main/scripts/install.bat install +``` + +这是你在 `Windows` 上安装的方法。 + +## 类型和值 + +### 基本类型 + +| | | +| -------- | :-------- | +| `Nil` | `Bool` | +| `Number` | `String` | +| `Range` | `Array` | +| `Record` | `Closure` | + + +基本类型列表。 + +### 布尔值 + +```js +let x = true; +let y = false; +``` + +Bool 是布尔类型。所以,它可以是 `true` 或 `false` + +### 数字 + +```js +let x = 0; +let degree = 45; // 整数 +let pi = 3.14; // 浮点数 +``` + +数字可以是整数或浮点数 + +### 字符串 + +```js +let empty = ""; + +let name = "John"; + +let message = 'Hello, "John"!'; +``` + +字符串可以用单引号或双引号表示 + +### 区间 + +```js +let range = 1..5; + +println(range); +// 1..5 +``` + +区间是整数的序列 + +### 数组 + +```js +let fruits = ["apple", "banana", "cherry"]; + +println(fruits); +// ["apple", "banana", "cherry"] +``` + +数组是元素的序列 + +### 记录 + +```js +let p = { x: 5, y: 10 }; + +println(p); +// {x: 5, y: 10} +``` + +记录将字段映射到值 + +### **nil** 值 + +```swift +let x = nil; +var y; +``` + +```js +println(x); // nil +println(y); // nil +``` + +`nil` 表示没有值 + +### 假值 + +```swift +if (nil) "true" else "false"; // false +if (false) "true" else "false"; // false +if (true) "true" else "false"; // true +if (0) "true" else "false"; // true +if (1) "true" else "false"; // true +if ("") "true" else "false"; // true +if ([]) "true" else "false"; // true +if ({}) "true" else "false"; // true +``` + +只有 `nil` 和 `false` 是假值。 + +## 语法 + +### 注释 + +```js +// This is a single-line comment. + +// And this is +// a multi-line +// comment. ;) +``` + +Hook 只支持单行注释。抱歉! + +### 分号 + + + +```js +println(1) ; println(2) ; println(3) ; +println(4) ; println(5) +; println(6) ; +; // error: unexpected token `;` +``` + +需要使用分号,不允许空语句。 + +### 代码块 + +```js +{ + println("Hello"); + { + println("World"); + } +} +``` + +使用代码块定义作用域。 + +### 保留字 + +| | | | | +| ------- | :------- | :--------- | :------ | +| `as` | `break` | `continue` | `do` | +| `else` | `false` | `fn` | `for` | +| `from` | `if` | `import` | `in` | +| `inout` | `let` | `loop` | `match` | +| `nil` | `return` | `struct` | `trait` | +| `true` | `var` | `while` | | + + +有少量保留字。 + +### 标识符 + +```php +var lowercase; +var CAPS_LOCK; +var camelCase; +var PascalCase; +var snake_case; +var _123; +``` + +标识符是区分大小写的。 + +## 变量 + +### 变量 + +```js +var x; // x contains nil +x = 5; // now, x contains a number +x = "foo"; // a string + +println(x); +``` + +数值有类型,但变量没有。 + +### 不可变变量 + + +```js +let x = 5; + +x = 10; // error: cannot assign to immutable variable `x` + +let y; // error: unexpected token `;` +``` + +不可变变量在声明时必须初始化。 + +### 作用域 + + +```js +let x = 5; +{ + let y = 15; + println(x); // 10 + println(y); // 15 +} +println(x); // 5 +println(y); // error: variable `y` is used but not defined +``` + +当堆分配的变量超出作用域时,会自动释放。 + +### 遮蔽 + +```js +let x = 5; +{ + let x = 10; // shadows the outer `x` + println(x); // 10 +} +println(x); // 5 +``` + +变量可以被遮蔽。 + +## 运算符和表达式 + +### 算术运算 + +```js +println(5 + 10); // 15 +println(5 - 10); // -5 +println(5 * 10); // 50 +println(5 / 10); // 0.5 +println(5 % 10); // 5 +println(-5); // -5 +``` + +基本算术运算符。 + +### 比较运算 + +```js +println(5 == 10); // false +println(5 != 10); // true +println(5 < 10); // true +println(5 > 10); // false +println(5 <= 10); // true +println(5 >= 10); // false +``` + +比较运算符。 + +### 逻辑运算 + +```js +println(true && false); // false +println(true || false); // true +println(!true); // false +``` + +逻辑运算符。 + +### 位运算和移位 + +```js +println(5 & 10); // 0 +println(5 | 10); // 15 +println(5 ^ 10); // 15 +println(~5); // -6 +println(5 << 1); // 10 +println(5 >> 1); // 2 +``` + +位运算和移位运算符。 + +### 赋值 + +```js +var x = 5; // 5 +x += 10; // 15 +x -= 10; // 5 +x *= 10; // 50 +x /= 10; // 5 +x %= 10; // 5 +x &= 10; // 0 +x |= 10; // 10 +x ^= 5; // 15 +x <<= 5; // 480 +x >>= 5; // 15 +x++; // 16 +x--; // 15 +``` + +赋值运算符。 + +### 三元运算符 + +```js +let x = 5; +let y = if (x > 5) 10 else 20; + +println(y); +// 20 +``` + +在 Hook 中,三元运算符是 `if else`。 + +## 分支 + +### 如果 + +```js +let x = 10; + +if (x > 5) { + println("x is greater than 5"); +} +// x is greater than 5 +``` + +`if` 语句。 + +### 如果否则 + +```js +let x = 11; + +if (x == 5) { + println("x is 5"); +} else if (x == 10) { + println("x is 10"); +} else { + println("x is neither 5 nor 10"); +} +// x is neither 5 nor 10 +``` + +`if else` 语句。 + +### 匹配 + +```rust +let x = 5; + +match (x) { + 1 => println("one"); + 2 => println("two"); + 3 => println("three"); + _ => println("other"); +} +// other +``` + +`match` 语句。 + +## 循环 + +### while + +```js +var x = 0; + +while (x < 5) { + print(x); + x += 1; +} +// 01234 +``` + +`while` 循环。 + +### do while + +```js +var x = 0; + +do { + print(x); + x += 1; +} while (x < 5); +// 01234 +``` + +`do while` 循环。 + +### for + +```rust +for (var i = 0; i < 5; i++) { + print(i); +} +// 01234 +``` + +经典的 `for` 循环。 + +### 循环 + +```rust +loop { + println("Press Ctrl+C to stop"); +} +``` + +无条件的 `loop` 循环。 + +### 中断 + +```js +var i = 0; +``` + +```rust +loop { + if (i == 5) break; + + print(i); + i += 1; +} +// 01234 +``` + +使用 `break` 退出循环。 + +### 继续 + +```js +var i = 0; +``` + +```rust +loop { + i += 1; + if (i % 2 == 0) continue; + + print(i); + +if (i == 5) break; +} +// 135 +``` + +使用 `continue` 跳过循环体的剩余部分。 + +## 字符串 + +### 索引字符串 + +```js +let s = "Hello"; + +println(s[0]); // H +println(s[1]); // e +println(s[4]); // o +``` + +对字符串进行索引返回一个包含1个字符的字符串。 + +### 切片字符串 + +```js +let s = "Hello, World!"; + +println(s[0..5]); // Hello, +println(s[7..12]); // World! +``` + +通过传递一个区间来切片字符串。 + +### 连接字符串 + +```js +let greeting = "Hi" + " there!"; + +println(greeting); +// Hi there! +``` + +使用 `+` 运算符连接字符串。 + +## 数组 + +### 索引数组 + +```js +let a = [1, 2, 3]; + +println(a[0]); // 1 +println(a[1]); // 2 +println(a[2]); // 3 +``` + +对数组进行索引返回一个元素 + +### 切片数组 + +```js +let a = [1, 2, 3, 4]; + +println(a[0..2]); // [1, 2, 3] +println(a[1..3]); // [2, 3, 4] +println(a[2 .. len(a) - 1]); // [3, 4] +``` + +数组从零开始索引 + +### 附加元素 + +```js +var a = [1, 2]; + +a[] = 3; + +println(a); +// [1, 2, 3] +``` + +数组是可变的。使用 `[]` 来附加一个元素 + +### 元素赋值 + +```js +var a = [1, 2, 3]; + +a[0] = 4; + +println(a); +// [4, 2, 3] +``` + +更新数组中的元素 + +### 连接数组 + +```js +let a = [1, 2]; +let b = [3]; +let c = a + b; + +println(c); +// [1, 2, 3] +``` + +使用 `+` 运算符来连接数组 + +### 数组相减 + +```js +let a = [1, 2, 2, 3]; +let b = [2]; +let c = a - b; + +println(c); +// [1, 3] +``` + +获取两个数组之间的差异。 + +## 函数和闭包 + +### 函数声明 + +```rust +fn sum(a, b) { + return a + b; +} + +println(sum(5, 10)); +// 15 +``` + +函数是一等公民 + +### 函数调用 + +```rust +fn greet(name) { + println("Hi, " + name + "!"); +} + +greet("John", "Doe"); +// Hi, John! +``` + +参数的数量可以调整 + +### 匿名函数 + +```js +let sum = |a, b| { + return a + b; +}; + +println(sum(5, 10)); +// 15 +``` + +Hook 也支持匿名函数 + +### 闭包 + +```js +let pi = 3.14; +``` + +```rust +fn area(r) { + return pi * r * r; +} + +println(area(5)); +// 78.5 +``` + +Hook 中的闭包只捕获数值 + +### 高阶函数 + +```rust +fn apply(f, x) { + return f(x); +} + +fn double(x) { + return x * 2; +} + +println(apply(double, 5)); +// 10 +``` + +函数可以作为参数传递或返回 + +### 函数的语法糖 + +```rust +fn factorial(n) => + if (n == 0) 1 + else n * factorial(n - 1); + +println(factorial(5)); +// 120 +``` + +当函数体是单个表达式时使用 `=>` + +### 递归 + +```rust +fn fib(n) { + if (n < 2) + return n; + return fib(n - 1) + fib(n - 2); +} + +println(fib(10)); +// 55 +``` + +支持递归 + +### 内置函数 + +```js +println(type(5)); +// number +println("1" + to_string(2)); +// 12 +println(len("foo")); +// 3 +``` + +有许多内置函数 + +### 更多内置函数 + +| | | | +| ----------- | :-------- | :---------- | +| `print` | `println` | `type` | +| `is_nil` | `is_bool` | `to_number` | +| `to_string` | `hex` | `len` | +| `exit` | `assert` | `panic` | + + +参见:[内置函数](https://github.com/hook-lang/hook/blob/main/docs/built-in.md) + +## 结构体 + +### 结构体 + +```rust +struct Point { + x, y +} +``` + +```js +let p = Point { 5, 10 }; + +println(p); +// {x: 5, y: 10} +``` + +结构体是记录的原型 + +### 访问字段 + +```js +println(p.x); // 5 +println(p.y); // 10 +``` + +使用 `.` 来访问记录中的字段 + +### 字段赋值 + +```js +p.x = 10; +p.y = 20; + +println(p); +// {x: 10, y: 20} +``` + +更新记录中字段的值。 + +## 解构 + +### 解构数组 + +```js +let a = [1, 2]; +let [x, y] = a; + +println(x); // 1 +println(y); // 2 +``` + +变量被声明并赋值 + +### 解构记录 + +```js +let p = { x: 5, y: 10 }; +let { x } = p; + +println(x); +// 5 +``` + +使用 `{}` 来解构记录 + +### 占位符 + +```js +let a = [1, 2]; +let [x] = a; +let [_, y] = a; + +println(x); // 1 +println(y); // 2 +``` + +使用 `_` 跳过前导或中间元素。 + +## 模块化 + +### 导入模块 + +```js +import math; +``` + +```js +println(math.sqrt(25)); +// 5 +``` + +使用 `import` 将一个模块引入作用域。 + +### 导出符号 + +```rust +// my_module.hk +fn useful_fn() { + return "Nothing"; +} + +return { useful: useful_fn }; +``` + +返回一个包含要导出符号的记录。 + +### 导入本地模块 + +```python +import "./my_module.hk" as my; +``` + +```js +println(my.useful()); +// Nothing +``` + +指定本地模块的路径。 + +### 选择性导入 + +```js +import { pow, sqrt } from math; + +let [ b, c ] = [ 4, 3 ]; +let a = sqrt(pow(b, 2) + pow(c, 2)); + +println(a); +// 5 +``` + +使用 `{}` 导入特定的符号。 + +### 核心模块 + +| | | | | +| ---------- | :------- | :----- | :-------- | +| `math` | `os` | `io` | `numbers` | +| `strings` | `arrays` | `utf8` | `hashing` | +| `encoding` | `socket` | `json` | `lists` | + + +参见:[核心模块](https://github.com/hook-lang/hook/blob/main/docs/core-modules.md) + +### 扩展模块 + +| | | | | +| --------- | :-------- | :------ | :-------- | +| `bigint` | `crypto` | `curl` | `fastcgi` | +| `geohash` | `leveldb` | `mysql` | `redis` | +| `regex` | `sqlite` | `uuid` | `zeromq` | + + +这是扩展模块的列表。 + +### **io** 模块 + +```js +import { stderr, writeln } from io; + +writeln(stderr, "Something went wrong"); +// Something went wrong +``` + +使用 `io` 模块将内容输出到 `stderr` + +### **hashing** 模块 + +```python +import hashing as h; +``` + +```js +let d = h.sha256("Hello, world!"); + +println(hex(d)); +// 315f5bdb76d078c43b8ac0064e4a... +``` + +`hashing` 模块提供哈希函数 + +### **json** 模块 + +```js +import json; +``` + +```js +let j = '{"x": 1, "y": 2}'; +let p = json.decode(j); + +println(p.x); // 1 + +let k = json.encode(p); +println(type(k)); // string +``` + +使用 `json` 模块处理 JSON。 + +## 错误处理 + +### 错误 + + +```js +println(to_int("foo")); + +// runtime error: type error: argument #1 is not a convertible string +// at to_int() in +// at main() in example.hk:1 +``` + +Hook 使用 panic 模式进行错误处理。当出现错误时,解释器会停止运行 + +### 语法错误 + +```js +println("Hello, World!"); + +// syntax error: unexpected end of file +// at main() in example.hk:1,25 +``` + +Hook 具有严格的语法 + +### 崩溃 + +```js +panic("Something went wrong"); + +// panic: Something went wrong +// at main() in example.hk:1 +``` + +使用内置函数 `panic` 来引发错误 + +### 断言 + + +```js +assert(5 > 10, "5 is not greater than 10"); + +// assert: 5 is not greater than 10 +// at main() in example.hk:1 +``` + +使用内置函数 `assert` 来检查条件 + +### 返回错误 + + +```rust +fn divide(a, b) { + if (b == 0) + return [nil, "division by zero"]; + return a / b; +} + +if (let [ok, err] = divide(5, 0); ok) { + println(ok); +} else { + println(err); +} +// division by zero +``` + +使用一对来返回一个值和一个错误 + +### 传递错误 + +```rust +if (let [ok, err] = divide(5, 0); err) { + return [nil, err]; +} +``` + +传递错误而不处理它