moonscratch 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-DQk6qfdC.mjs +18 -0
- package/dist/index.d.mts +1173 -0
- package/dist/index.mjs +27135 -0
- package/package.json +6 -1
- package/.agents/skills/moonbit-agent-guide/LICENSE +0 -202
- package/.agents/skills/moonbit-agent-guide/SKILL.mbt.md +0 -1126
- package/.agents/skills/moonbit-agent-guide/SKILL.md +0 -1126
- package/.agents/skills/moonbit-agent-guide/ide.md +0 -116
- package/.agents/skills/moonbit-agent-guide/references/advanced-moonbit-build.md +0 -106
- package/.agents/skills/moonbit-agent-guide/references/moonbit-language-fundamentals.mbt.md +0 -422
- package/.agents/skills/moonbit-agent-guide/references/moonbit-language-fundamentals.md +0 -422
- package/.agents/skills/moonbit-practice/SKILL.md +0 -258
- package/.agents/skills/moonbit-practice/assets/ci.yaml +0 -25
- package/.agents/skills/moonbit-practice/reference/agents.md +0 -1469
- package/.agents/skills/moonbit-practice/reference/configuration.md +0 -228
- package/.agents/skills/moonbit-practice/reference/ffi.md +0 -229
- package/.agents/skills/moonbit-practice/reference/ide.md +0 -189
- package/.agents/skills/moonbit-practice/reference/performance.md +0 -217
- package/.agents/skills/moonbit-practice/reference/refactor.md +0 -154
- package/.agents/skills/moonbit-practice/reference/stdlib.md +0 -351
- package/.agents/skills/moonbit-practice/reference/testing.md +0 -228
- package/.agents/skills/moonbit-refactoring/LICENSE +0 -21
- package/.agents/skills/moonbit-refactoring/SKILL.md +0 -323
- package/.githooks/README.md +0 -23
- package/.githooks/pre-commit +0 -3
- package/.github/workflows/copilot-setup-steps.yml +0 -40
- package/AGENTS.md +0 -91
- package/PLAN.md +0 -64
- package/TODO.md +0 -120
- package/benchmarks/calc.bench.ts +0 -144
- package/benchmarks/draw.bench.ts +0 -215
- package/benchmarks/load.bench.ts +0 -28
- package/benchmarks/render.bench.ts +0 -53
- package/benchmarks/run.bench.ts +0 -8
- package/benchmarks/types.d.ts +0 -15
- package/docs/scratch-vm-specs/eventloop.md +0 -103
- package/docs/scratch-vm-specs/moonscratch-time-separation.md +0 -50
- package/index.html +0 -91
- package/js/AGENTS.md +0 -5
- package/js/a.ts +0 -52
- package/js/assets/AGENTS.md +0 -5
- package/js/assets/base64.test.ts +0 -14
- package/js/assets/base64.ts +0 -21
- package/js/assets/build-asset.test.ts +0 -26
- package/js/assets/build-asset.ts +0 -28
- package/js/assets/create.test.ts +0 -142
- package/js/assets/create.ts +0 -122
- package/js/assets/index.test.ts +0 -15
- package/js/assets/index.ts +0 -2
- package/js/assets/types.ts +0 -26
- package/js/assets/validation.test.ts +0 -34
- package/js/assets/validation.ts +0 -25
- package/js/assets.test.ts +0 -14
- package/js/assets.ts +0 -1
- package/js/index.test.ts +0 -26
- package/js/index.ts +0 -3
- package/js/render/index.test.ts +0 -65
- package/js/render/index.ts +0 -13
- package/js/render/sharp.ts +0 -87
- package/js/render/svg.ts +0 -68
- package/js/render/types.ts +0 -35
- package/js/render/utils.ts +0 -108
- package/js/render/webgl.ts +0 -274
- package/js/sharp-optional.d.ts +0 -16
- package/js/test/helpers.ts +0 -116
- package/js/test/hikkaku-sample.test.ts +0 -37
- package/js/test/rubik-components.input-motion.test.ts +0 -60
- package/js/test/rubik-components.lists.test.ts +0 -49
- package/js/test/rubik-components.operators.test.ts +0 -104
- package/js/test/rubik-components.pen.test.ts +0 -112
- package/js/test/rubik-components.procedures-loops.test.ts +0 -72
- package/js/test/rubik-components.variables-branches.test.ts +0 -57
- package/js/test/rubik-components.visibility-entry.test.ts +0 -31
- package/js/test/test-projects.ts +0 -598
- package/js/test/variable.ts +0 -200
- package/js/test/warp.test.ts +0 -59
- package/js/vm/AGENTS.md +0 -6
- package/js/vm/README.md +0 -183
- package/js/vm/bindings.test.ts +0 -13
- package/js/vm/bindings.ts +0 -5
- package/js/vm/compare-operators.test.ts +0 -145
- package/js/vm/constants.test.ts +0 -11
- package/js/vm/constants.ts +0 -4
- package/js/vm/effect-guards.test.ts +0 -68
- package/js/vm/effect-guards.ts +0 -44
- package/js/vm/factory.test.ts +0 -486
- package/js/vm/factory.ts +0 -615
- package/js/vm/headless-vm.test.ts +0 -131
- package/js/vm/headless-vm.ts +0 -342
- package/js/vm/index.test.ts +0 -28
- package/js/vm/index.ts +0 -5
- package/js/vm/internal-types.ts +0 -32
- package/js/vm/json.test.ts +0 -40
- package/js/vm/json.ts +0 -273
- package/js/vm/normalize.test.ts +0 -48
- package/js/vm/normalize.ts +0 -65
- package/js/vm/options.test.ts +0 -30
- package/js/vm/options.ts +0 -55
- package/js/vm/pen-transparency.test.ts +0 -115
- package/js/vm/program-wasm.ts +0 -322
- package/js/vm/scheduler-render.test.ts +0 -401
- package/js/vm/scratch-assets.test.ts +0 -136
- package/js/vm/scratch-assets.ts +0 -202
- package/js/vm/types.ts +0 -358
- package/js/vm/value-guards.test.ts +0 -25
- package/js/vm/value-guards.ts +0 -18
- package/moon.mod.json +0 -10
- package/scripts/preinstall.ts +0 -4
- package/src/AGENTS.md +0 -6
- package/src/api.mbt +0 -161
- package/src/api_aot_commands.mbt +0 -184
- package/src/api_effects_json.mbt +0 -72
- package/src/api_options.mbt +0 -60
- package/src/api_program_wasm.mbt +0 -1647
- package/src/api_program_wat.mbt +0 -2206
- package/src/api_snapshot_json.mbt +0 -44
- package/src/cmd/AGENTS.md +0 -5
- package/src/cmd/main/AGENTS.md +0 -5
- package/src/cmd/main/main.mbt +0 -29
- package/src/cmd/main/moon.pkg +0 -7
- package/src/cmd/main/pkg.generated.mbti +0 -13
- package/src/json_helpers.mbt +0 -176
- package/src/moon.pkg +0 -65
- package/src/moonscratch.mbt +0 -3
- package/src/moonscratch_wbtest.mbt +0 -40
- package/src/parser_sb3.mbt +0 -890
- package/src/pkg.generated.mbti +0 -479
- package/src/runtime_eval.mbt +0 -2844
- package/src/runtime_exec.mbt +0 -3850
- package/src/runtime_render.mbt +0 -2550
- package/src/runtime_state.mbt +0 -870
- package/src/test/AGENTS.md +0 -3
- package/src/test/projects/AGENTS.md +0 -6
- package/src/test/projects/moon.pkg +0 -4
- package/src/test/projects/moonscratch_compat_test.mbt +0 -642
- package/src/test/projects/moonscratch_core_test.mbt +0 -1332
- package/src/test/projects/moonscratch_runtime_test.mbt +0 -1087
- package/src/test/projects/pkg.generated.mbti +0 -13
- package/src/test/projects/test_support.mbt +0 -35
- package/src/types_effects.mbt +0 -20
- package/src/types_error.mbt +0 -4
- package/src/types_options.mbt +0 -31
- package/src/types_runtime_structs.mbt +0 -254
- package/src/types_vm.mbt +0 -109
- package/tsconfig.json +0 -29
- package/viewer/index.ts +0 -399
- package/viewer/vite.d.ts +0 -1
- package/viewer/worker.ts +0 -161
- package/vite.config.ts +0 -61
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
# MoonBit Language Fundamentals
|
|
2
|
-
|
|
3
|
-
## Quick reference:
|
|
4
|
-
|
|
5
|
-
```mbt check
|
|
6
|
-
///|
|
|
7
|
-
/// comments doc string
|
|
8
|
-
pub fn sum(x : Int, y : Int) -> Int {
|
|
9
|
-
x + y
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
///|
|
|
13
|
-
struct Rect {
|
|
14
|
-
width : Int
|
|
15
|
-
height : Int
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
///|
|
|
19
|
-
fn Rect::area(self : Rect) -> Int {
|
|
20
|
-
self.width * self.height
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
///|
|
|
24
|
-
pub impl Show for Rect with output(_self, logger) {
|
|
25
|
-
logger.write_string("Rect")
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
///|
|
|
29
|
-
enum MyOption {
|
|
30
|
-
MyNone
|
|
31
|
-
MySome(Int)
|
|
32
|
-
} derive(Show, ToJson, Eq, Compare)
|
|
33
|
-
|
|
34
|
-
///|
|
|
35
|
-
/// match + loops are expressions
|
|
36
|
-
test "everything is expression in MoonBit" {
|
|
37
|
-
// tuple
|
|
38
|
-
let (n, opt) = (1, MySome(2))
|
|
39
|
-
// if expressions return values
|
|
40
|
-
let msg : String = if n > 0 { "pos" } else { "non-pos" }
|
|
41
|
-
let res = match opt {
|
|
42
|
-
MySome(x) => {
|
|
43
|
-
inspect(x, content="2")
|
|
44
|
-
1
|
|
45
|
-
}
|
|
46
|
-
MyNone => 0
|
|
47
|
-
}
|
|
48
|
-
let status : Result[Int, String] = Ok(10)
|
|
49
|
-
// match expressions return values
|
|
50
|
-
let description = match status {
|
|
51
|
-
Ok(value) => "Success: \{value}"
|
|
52
|
-
Err(error) => "Error: \{error}"
|
|
53
|
-
}
|
|
54
|
-
let array = [1, 2, 3, 4, 5]
|
|
55
|
-
let mut i = 0 // mutable bindings (local only, globals are immutable)
|
|
56
|
-
let target = 3
|
|
57
|
-
// loops return values with 'break'
|
|
58
|
-
let found : Int? = while i < array.length() {
|
|
59
|
-
if array[i] == target {
|
|
60
|
-
break Some(i) // Exit with value
|
|
61
|
-
}
|
|
62
|
-
i = i + 1
|
|
63
|
-
} else { // Value when loop completes normally
|
|
64
|
-
None
|
|
65
|
-
}
|
|
66
|
-
assert_eq(found, Some(2)) // Found at index 2
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
///|
|
|
70
|
-
/// global bindings
|
|
71
|
-
pub let my_name : String = "MoonBit"
|
|
72
|
-
|
|
73
|
-
///|
|
|
74
|
-
pub const PI : Double = 3.14159 // constants use UPPER_SNAKE or PascalCase
|
|
75
|
-
|
|
76
|
-
///|
|
|
77
|
-
pub fn maximum(xs : Array[Int]) -> Int raise {
|
|
78
|
-
// Toplevel functions are *mutually recursive* by default
|
|
79
|
-
// `raise` annotation means the function would raise any Error
|
|
80
|
-
// Only add `raise XXError` when you do need track the specific error type
|
|
81
|
-
match xs {
|
|
82
|
-
[] => fail("Empty array") // fail() is built-in for generic errors
|
|
83
|
-
[x] => x
|
|
84
|
-
// pattern match over array, the `.. rest` is a rest pattern
|
|
85
|
-
// it is of type `ArrayView[Int]` which is a slice
|
|
86
|
-
[x, .. rest] => {
|
|
87
|
-
let mut max_val = x // `mut` only allowed in local bindings
|
|
88
|
-
for y in rest {
|
|
89
|
-
if y > max_val {
|
|
90
|
-
max_val = y
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
max_val // return can be omitted if the last expression is the return value
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
///|
|
|
99
|
-
/// pub(all) means it can be both read and created outside the package
|
|
100
|
-
pub(all) struct Point {
|
|
101
|
-
x : Int
|
|
102
|
-
mut y : Int
|
|
103
|
-
} derive(Show, ToJson)
|
|
104
|
-
|
|
105
|
-
///|
|
|
106
|
-
pub enum MyResult[T, E] {
|
|
107
|
-
MyOk(T) // semicolon `;` is optional when we have a newline
|
|
108
|
-
MyErr(E) // Enum variants must start uppercase
|
|
109
|
-
} derive(Show, Eq, ToJson)
|
|
110
|
-
// pub means it can only be pattern matched outside the package
|
|
111
|
-
// but it can not be created outside the package, use `pub(all)` otherwise
|
|
112
|
-
|
|
113
|
-
///|
|
|
114
|
-
/// pub (open) means the trait can be implemented for outside packages
|
|
115
|
-
pub(open) trait Comparable {
|
|
116
|
-
compare(Self, Self) -> Int // `Self` refers to the implementing type
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
///|
|
|
120
|
-
test "inspect test" {
|
|
121
|
-
let result = sum(1, 2)
|
|
122
|
-
inspect(result, content="3")
|
|
123
|
-
// The `content` can be auto-corrected by running `moon test --update`
|
|
124
|
-
let point = Point::{ x: 10, y: 20 }
|
|
125
|
-
// For complex structures, use @json.inspect for better readability:
|
|
126
|
-
@json.inspect(point, content={ "x": 10, "y": 20 })
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Complex Types
|
|
131
|
-
|
|
132
|
-
```mbt check
|
|
133
|
-
///|
|
|
134
|
-
pub type UserId = Int // Int is aliased to UserId - like symlink
|
|
135
|
-
|
|
136
|
-
///|
|
|
137
|
-
/// Tuple-struct for callback
|
|
138
|
-
pub struct Handler((String) -> Unit) // A newtype wrapper
|
|
139
|
-
|
|
140
|
-
///|
|
|
141
|
-
/// Tuple-struct syntax for single-field newtypes
|
|
142
|
-
struct Meters(Int) // Tuple-struct syntax
|
|
143
|
-
|
|
144
|
-
///|
|
|
145
|
-
let distance : Meters = Meters(100)
|
|
146
|
-
|
|
147
|
-
///|
|
|
148
|
-
let raw : Int = distance.0 // Access first field with .0
|
|
149
|
-
|
|
150
|
-
///|
|
|
151
|
-
struct Addr {
|
|
152
|
-
host : String
|
|
153
|
-
port : Int
|
|
154
|
-
} derive(Show, Eq, ToJson, FromJson)
|
|
155
|
-
|
|
156
|
-
///|
|
|
157
|
-
/// Structural types with literal syntax
|
|
158
|
-
let config : Addr = Addr::{
|
|
159
|
-
// `Type::` can be omitted since the type is already known
|
|
160
|
-
host: "localhost",
|
|
161
|
-
port: 8080,
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
## Common Derivable Traits
|
|
168
|
-
|
|
169
|
-
Most types can automatically derive standard traits using the `derive(...)` syntax:
|
|
170
|
-
|
|
171
|
-
- **`Show`** - Enables `to_string()` and string interpolation with `\{value}`
|
|
172
|
-
- **`Eq`** - Enables `==` and `!=` equality operators
|
|
173
|
-
- **`Compare`** - Enables `<`, `>`, `<=`, `>=` comparison operators
|
|
174
|
-
- **`ToJson`** - Enables `@json.inspect()` for readable test output
|
|
175
|
-
- **`Hash`** - Enables use as Map keys
|
|
176
|
-
|
|
177
|
-
```mbt check
|
|
178
|
-
///|
|
|
179
|
-
struct Coordinate {
|
|
180
|
-
x : Int
|
|
181
|
-
y : Int
|
|
182
|
-
} derive(Show, Eq, ToJson)
|
|
183
|
-
|
|
184
|
-
///|
|
|
185
|
-
enum Status {
|
|
186
|
-
Active
|
|
187
|
-
Inactive
|
|
188
|
-
} derive(Show, Eq, Compare)
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
**Best practice**: Always derive `Show` and `Eq` for data types. Add `ToJson` if you plan to test them with `@json.inspect()`.
|
|
192
|
-
|
|
193
|
-
## Reference Semantics by Default
|
|
194
|
-
|
|
195
|
-
MoonBit passes most types by reference semantically (the optimizer may copy
|
|
196
|
-
immutables):
|
|
197
|
-
|
|
198
|
-
```mbt check
|
|
199
|
-
///|
|
|
200
|
-
/// Structs with 'mut' fields are always passed by reference
|
|
201
|
-
struct Counter {
|
|
202
|
-
mut value : Int
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
///|
|
|
206
|
-
fn increment(c : Counter) -> Unit {
|
|
207
|
-
c.value += 1 // Modifies the original
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
///|
|
|
211
|
-
/// Arrays and Maps are mutable references
|
|
212
|
-
fn modify_array(arr : Array[Int]) -> Unit {
|
|
213
|
-
arr[0] = 999 // Modifies original array
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
///|
|
|
217
|
-
test "reference semantics" {
|
|
218
|
-
let counter : Ref[Int] = Ref::{ val: 0 }
|
|
219
|
-
counter.val += 1
|
|
220
|
-
assert_true(counter.val is 1)
|
|
221
|
-
let arr : Array[Int] = [1, 2, 3] // unlike Rust, no `mut` keyword needed
|
|
222
|
-
modify_array(arr)
|
|
223
|
-
assert_true(arr[0] is 999)
|
|
224
|
-
let mut x = 3 // `mut` neeed for re-assignment to the bindings
|
|
225
|
-
x += 2
|
|
226
|
-
assert_true(x is 5)
|
|
227
|
-
}
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
## Pattern Matching
|
|
231
|
-
|
|
232
|
-
```mbt check
|
|
233
|
-
///|
|
|
234
|
-
#warnings("-unused_value")
|
|
235
|
-
test "pattern match over Array, struct and StringView" {
|
|
236
|
-
let arr : Array[Int] = [10, 20, 25, 30]
|
|
237
|
-
match arr {
|
|
238
|
-
[] => ... // empty array
|
|
239
|
-
[single] => ... // single element
|
|
240
|
-
[first, .. middle, rest] => {
|
|
241
|
-
let _ : ArrayView[Int] = middle // middle is ArrayView[Int]
|
|
242
|
-
assert_true(first is 10 && middle is [20, 25] && rest is 30)
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
fn process_point(point : Point) -> Unit {
|
|
246
|
-
match point {
|
|
247
|
-
{ x: 0, y: 0 } => ...
|
|
248
|
-
{ x, y } if x == y => ...
|
|
249
|
-
{ x, .. } if x < 0 => ...
|
|
250
|
-
...
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
/// StringView pattern matching for parsing
|
|
254
|
-
fn is_palindrome(s : StringView) -> Bool {
|
|
255
|
-
loop s {
|
|
256
|
-
[] | [_] => true
|
|
257
|
-
[a, .. rest, b] if a == b => continue rest
|
|
258
|
-
// a is of type Char, rest is of type StringView
|
|
259
|
-
_ => false
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
## Functional `loop` control flow
|
|
268
|
-
|
|
269
|
-
The `loop` construct is unique to MoonBit:
|
|
270
|
-
|
|
271
|
-
```mbt check
|
|
272
|
-
///|
|
|
273
|
-
/// Functional loop with pattern matching on loop variables
|
|
274
|
-
/// @list.List is from the standard library
|
|
275
|
-
fn sum_list(list : @list.List[Int]) -> Int {
|
|
276
|
-
loop (list, 0) {
|
|
277
|
-
(Empty, acc) => acc // Base case returns accumulator
|
|
278
|
-
(More(x, tail=rest), acc) => continue (rest, x + acc) // Recurse with new values
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
///|
|
|
283
|
-
/// Multiple loop variables with complex control flow
|
|
284
|
-
fn find_pair(arr : Array[Int], target : Int) -> (Int, Int)? {
|
|
285
|
-
loop (0, arr.length() - 1) {
|
|
286
|
-
(i, j) if i >= j => None
|
|
287
|
-
(i, j) => {
|
|
288
|
-
let sum = arr[i] + arr[j]
|
|
289
|
-
if sum == target {
|
|
290
|
-
Some((i, j)) // Found pair
|
|
291
|
-
} else if sum < target {
|
|
292
|
-
continue (i + 1, j) // Move left pointer
|
|
293
|
-
} else {
|
|
294
|
-
continue (i, j - 1) // Move right pointer
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
**Note**: You must provide a payload to `loop`. If you want an infinite loop, use `while true { ... }` instead. The syntax `loop { ... }` without arguments is invalid.
|
|
302
|
-
|
|
303
|
-
## Methods and Traits
|
|
304
|
-
|
|
305
|
-
Methods use `Type::method_name` syntax, traits require explicit implementation:
|
|
306
|
-
|
|
307
|
-
```mbt check
|
|
308
|
-
///|
|
|
309
|
-
struct Rectangle {
|
|
310
|
-
width : Double
|
|
311
|
-
height : Double
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
///|
|
|
315
|
-
// Methods are prefixed with Type::
|
|
316
|
-
fn Rectangle::area(self : Rectangle) -> Double {
|
|
317
|
-
self.width * self.height
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
///|
|
|
321
|
-
/// Static methods don't need self
|
|
322
|
-
fn Rectangle::new(w : Double, h : Double) -> Rectangle {
|
|
323
|
-
{ width: w, height: h }
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
///|
|
|
327
|
-
/// Show trait now uses output(self, logger) for custom formatting
|
|
328
|
-
/// to_string() is automatically derived from this
|
|
329
|
-
pub impl Show for Rectangle with output(self, logger) {
|
|
330
|
-
logger.write_string("Rectangle(\{self.width}x\{self.height})")
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
///|
|
|
334
|
-
/// Traits can have non-object-safe methods
|
|
335
|
-
trait Named {
|
|
336
|
-
name() -> String // No 'self' parameter - not object-safe
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
///|
|
|
340
|
-
/// Trait bounds in generics
|
|
341
|
-
fn[T : Show + Named] describe(value : T) -> String {
|
|
342
|
-
"\{T::name()}: \{value.to_string()}"
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
///|
|
|
346
|
-
/// Trait implementation
|
|
347
|
-
impl Hash for Rectangle with hash_combine(self, hasher) {
|
|
348
|
-
hasher..combine(self.width)..combine(self.height)
|
|
349
|
-
}
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
## Operator Overloading
|
|
353
|
-
|
|
354
|
-
MoonBit supports operator overloading through traits:
|
|
355
|
-
|
|
356
|
-
```mbt check
|
|
357
|
-
///|
|
|
358
|
-
struct Vector(Int, Int)
|
|
359
|
-
|
|
360
|
-
///|
|
|
361
|
-
/// Implement arithmetic operators
|
|
362
|
-
pub impl Add for Vector with add(self, other) {
|
|
363
|
-
Vector(self.0 + other.0, self.1 + other.1)
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
///|
|
|
367
|
-
struct Person {
|
|
368
|
-
age : Int
|
|
369
|
-
} derive(Eq)
|
|
370
|
-
|
|
371
|
-
///|
|
|
372
|
-
/// Comparison operators
|
|
373
|
-
pub impl Compare for Person with compare(self, other) {
|
|
374
|
-
self.age.compare(other.age)
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
///|
|
|
378
|
-
test "overloading" {
|
|
379
|
-
let v1 : Vector = Vector(1, 2)
|
|
380
|
-
let v2 : Vector = Vector(3, 4)
|
|
381
|
-
let _v3 : Vector = v1 + v2
|
|
382
|
-
|
|
383
|
-
}
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
## Access Control Modifiers
|
|
387
|
-
|
|
388
|
-
MoonBit has fine-grained visibility control:
|
|
389
|
-
|
|
390
|
-
```mbt check
|
|
391
|
-
///|
|
|
392
|
-
/// `fn` defaults to Private - only visible in current package
|
|
393
|
-
fn internal_helper() -> Unit {
|
|
394
|
-
...
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
///|
|
|
398
|
-
pub fn get_value() -> Int {
|
|
399
|
-
...
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
///|
|
|
403
|
-
// Struct (default) - type visible, implementation hidden
|
|
404
|
-
struct DataStructure {}
|
|
405
|
-
|
|
406
|
-
///|
|
|
407
|
-
/// `pub struct` defaults to readonly - can read, pattern match, but not create
|
|
408
|
-
pub struct Config {}
|
|
409
|
-
|
|
410
|
-
///|
|
|
411
|
-
/// Public all - full access
|
|
412
|
-
pub(all) struct Config2 {}
|
|
413
|
-
|
|
414
|
-
///|
|
|
415
|
-
/// Abstract trait (default) - cannot be implemented by
|
|
416
|
-
/// types outside this package
|
|
417
|
-
pub trait MyTrait {}
|
|
418
|
-
|
|
419
|
-
///|
|
|
420
|
-
/// Open for extension
|
|
421
|
-
pub(open) trait Extendable {}
|
|
422
|
-
```
|
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: moonbit-practice
|
|
3
|
-
description: MoonBit code generation best practices. Use when writing MoonBit code to avoid common AI mistakes with syntax, tests, and benchmarks.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# MoonBit Practice Guide
|
|
7
|
-
|
|
8
|
-
Best practices for AI when generating MoonBit code.
|
|
9
|
-
If you don't understand something here, use `moonbit-docs` skill to search the official documentation.
|
|
10
|
-
|
|
11
|
-
## Guidelines
|
|
12
|
-
|
|
13
|
-
### Code Navigation: Prefer moon ide over Read/Grep
|
|
14
|
-
|
|
15
|
-
In MoonBit projects, **prefer `moon ide` commands over Read tool or grep**.
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
# ❌ Avoid: Reading files directly
|
|
19
|
-
Read src/parser.mbt
|
|
20
|
-
|
|
21
|
-
# ✅ Recommended: Find definitions from symbols
|
|
22
|
-
moon ide peek-def Parser::parse
|
|
23
|
-
moon ide goto-definition -tags 'pub fn' -query 'parse'
|
|
24
|
-
|
|
25
|
-
# ❌ Avoid: Searching with grep
|
|
26
|
-
grep -r "fn parse" .
|
|
27
|
-
|
|
28
|
-
# ✅ Recommended: Semantic search
|
|
29
|
-
moon ide find-references parse
|
|
30
|
-
moon ide outline src/parser.mbt
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
**Why:**
|
|
34
|
-
|
|
35
|
-
- `moon ide` provides semantic search (distinguishes definitions from call sites)
|
|
36
|
-
- grep picks up comments and strings
|
|
37
|
-
- `moon doc` quickly reveals APIs
|
|
38
|
-
|
|
39
|
-
### Other Rules
|
|
40
|
-
|
|
41
|
-
- Use `moon doc '<Type>'` to explore APIs before implementing
|
|
42
|
-
- Check reference/configuration.md before editing moon.pkg.json / moon.mod.json
|
|
43
|
-
- Check reference/agents.md when updating CLAUDE.md
|
|
44
|
-
|
|
45
|
-
## Common Pitfalls
|
|
46
|
-
|
|
47
|
-
- **Don't use uppercase for variables/functions** - compilation error
|
|
48
|
-
- **`mut` is only for reassignment, not field mutation** - Array push doesn't need it
|
|
49
|
-
- **`return` is unnecessary** - last expression is the return value
|
|
50
|
-
- **Methods require `Type::` prefix**
|
|
51
|
-
- **`++` `--` not supported** - use `i = i + 1` or `i += 1`
|
|
52
|
-
- **No `try` needed for error propagation** - automatic (unlike Swift)
|
|
53
|
-
- **No `await` keyword** - just declare with `async fn`
|
|
54
|
-
- **Prefer range for over C-style** - `for i in 0..<n {...}`
|
|
55
|
-
- **Legacy syntax**: `function_name!(...)` and `function_name(...)?` are deprecated
|
|
56
|
-
|
|
57
|
-
## Common Syntax Mistakes by AI
|
|
58
|
-
|
|
59
|
-
### Type Parameter Position
|
|
60
|
-
|
|
61
|
-
```moonbit
|
|
62
|
-
///| NG: fn identity[T] is old syntax
|
|
63
|
-
fn identity[T](val: T) -> T { val }
|
|
64
|
-
|
|
65
|
-
///| OK: Type parameter comes right after fn
|
|
66
|
-
fn[T] identity(val: T) -> T { val }
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### raise Syntax
|
|
70
|
-
|
|
71
|
-
```moonbit
|
|
72
|
-
///|
|
|
73
|
-
/// NG: -> T!Error was removed
|
|
74
|
-
fn parse(s: String) -> Int!Error { ... }
|
|
75
|
-
|
|
76
|
-
///|
|
|
77
|
-
/// OK: Use raise keyword
|
|
78
|
-
fn parse(s: String) -> Int raise Error { ... }
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
`Int raise` is shorthand for `Int raise Error`.
|
|
82
|
-
async fn implicitly raises by default; use `noraise` to enforce no errors.
|
|
83
|
-
|
|
84
|
-
### Macro Calls
|
|
85
|
-
|
|
86
|
-
```moonbit
|
|
87
|
-
///|
|
|
88
|
-
/// NG: ! suffix was removed
|
|
89
|
-
assert_true!(true)
|
|
90
|
-
|
|
91
|
-
///|
|
|
92
|
-
/// OK
|
|
93
|
-
assert_true(true)
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### Multi-line Text
|
|
97
|
-
|
|
98
|
-
```moonbit
|
|
99
|
-
let text =
|
|
100
|
-
#|line 1
|
|
101
|
-
#|line 2
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
### Comments and Block Separators
|
|
105
|
-
|
|
106
|
-
`///|` is a block separator. `///` comments attach to the following `///|` block.
|
|
107
|
-
|
|
108
|
-
```moonbit
|
|
109
|
-
///|
|
|
110
|
-
/// This function is foo
|
|
111
|
-
fn foo() -> Unit { ... }
|
|
112
|
-
|
|
113
|
-
///|
|
|
114
|
-
/// This function is bar
|
|
115
|
-
fn bar() -> Unit { ... }
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Avoid consecutive `///|` at the file beginning as they create separate blocks.
|
|
119
|
-
|
|
120
|
-
## Snapshot Tests
|
|
121
|
-
|
|
122
|
-
`moon test -u` auto-updates `content=""` in `inspect(val)`.
|
|
123
|
-
|
|
124
|
-
```moonbit
|
|
125
|
-
test "snapshot" {
|
|
126
|
-
inspect([1, 2, 3], content="") // auto-filled by moon test -u
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
After running:
|
|
131
|
-
|
|
132
|
-
```moonbit
|
|
133
|
-
test "snapshot" {
|
|
134
|
-
inspect([1, 2, 3], content="[1, 2, 3]")
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## Doc Tests
|
|
139
|
-
|
|
140
|
-
Available in `.mbt.md` files or `///|` inline comments.
|
|
141
|
-
|
|
142
|
-
| Code Block | Behavior |
|
|
143
|
-
| ---------------- | --------------------------- |
|
|
144
|
-
| ` ```mbt check ` | Checked by LSP |
|
|
145
|
-
| ` ```mbt test ` | Executed as `test {...}` |
|
|
146
|
-
| ` ```moonbit ` | Display only (not executed) |
|
|
147
|
-
|
|
148
|
-
Example (inline comment):
|
|
149
|
-
|
|
150
|
-
````moonbit
|
|
151
|
-
|
|
152
|
-
///|
|
|
153
|
-
/// Increment an integer by 1
|
|
154
|
-
/// ```mbt test
|
|
155
|
-
/// inspect(incr(41), content="42")
|
|
156
|
-
/// ```
|
|
157
|
-
pub fn incr(x : Int) -> Int {
|
|
158
|
-
x + 1
|
|
159
|
-
}
|
|
160
|
-
````
|
|
161
|
-
|
|
162
|
-
## Pre-release Checklist
|
|
163
|
-
|
|
164
|
-
Run before releasing:
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
moon fmt # Format code
|
|
168
|
-
moon info # Generate type definition files
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
`pkg.generated.mbti` is auto-generated by `moon info`. Don't edit it directly.
|
|
172
|
-
|
|
173
|
-
## Exploring Built-in Type Methods
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
moon doc StringView # StringView methods
|
|
177
|
-
moon doc Array # Array methods
|
|
178
|
-
moon doc Map # Map methods
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
## Quick Reference
|
|
182
|
-
|
|
183
|
-
| Topic | Command | Details |
|
|
184
|
-
| ---------------- | --------------------------- | ---------------------------------------------------------- |
|
|
185
|
-
| Test | `moon test` | https://docs.moonbitlang.com/en/stable/language/tests |
|
|
186
|
-
| Update snapshots | `moon test -u` | Same as above |
|
|
187
|
-
| Filtered test | `moon test --filter 'glob'` | Run specific tests |
|
|
188
|
-
| Benchmark | `moon bench` | https://docs.moonbitlang.com/en/stable/language/benchmarks |
|
|
189
|
-
| Doc Test | `moon check` / `moon test` | https://docs.moonbitlang.com/en/stable/language/docs |
|
|
190
|
-
| Format | `moon fmt` | - |
|
|
191
|
-
| Generate types | `moon info` | - |
|
|
192
|
-
| Doc reference | `moon doc <Type>` | - |
|
|
193
|
-
|
|
194
|
-
## moon ide Tools
|
|
195
|
-
|
|
196
|
-
More accurate than grep for code navigation. See `reference/ide.md` for details.
|
|
197
|
-
|
|
198
|
-
```bash
|
|
199
|
-
# Show symbol definition
|
|
200
|
-
moon ide peek-def Parser::read_u32_leb128
|
|
201
|
-
|
|
202
|
-
# Package outline
|
|
203
|
-
moon ide outline .
|
|
204
|
-
|
|
205
|
-
# Find references
|
|
206
|
-
moon ide find-references TranslationUnit
|
|
207
|
-
|
|
208
|
-
# Jump to type definition (with location)
|
|
209
|
-
moon ide peek-def Parser -loc src/parse.mbt:46:4
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
## Functional for loop
|
|
213
|
-
|
|
214
|
-
Prefer functional for loops whenever possible. More readable and easier to reason about.
|
|
215
|
-
|
|
216
|
-
```moonbit
|
|
217
|
-
// Functional for loop with state
|
|
218
|
-
for i = 0, sum = 0; i <= 10; {
|
|
219
|
-
continue i + 1, sum + i // Update state
|
|
220
|
-
} else {
|
|
221
|
-
sum // Value at loop exit
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Range for (recommended)
|
|
225
|
-
for i in 0..<n { ... }
|
|
226
|
-
for i, v in array { ... } // index and value
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
## Error Handling
|
|
230
|
-
|
|
231
|
-
MoonBit uses checked errors. See `reference/ffi.md` for details.
|
|
232
|
-
|
|
233
|
-
```moonbit
|
|
234
|
-
///| Declare error type
|
|
235
|
-
suberror ParseError {
|
|
236
|
-
InvalidEof
|
|
237
|
-
InvalidChar(Char)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
///| Declare with raise, auto-propagates
|
|
241
|
-
fn parse(s: String) -> Int raise ParseError {
|
|
242
|
-
if s.is_empty() { raise ParseError::InvalidEof }
|
|
243
|
-
...
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
///| Convert to Result
|
|
247
|
-
let result : Result[Int, ParseError] = try? parse(s)
|
|
248
|
-
|
|
249
|
-
///| Handle with try-catch
|
|
250
|
-
parse(s) catch {
|
|
251
|
-
ParseError::InvalidEof => -1
|
|
252
|
-
_ => 0
|
|
253
|
-
}
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
## Assets
|
|
257
|
-
|
|
258
|
-
assets/ci.yaml is a GitHub Actions workflow for CI
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Github Actions CI Example
|
|
2
|
-
name: CI
|
|
3
|
-
|
|
4
|
-
on:
|
|
5
|
-
push:
|
|
6
|
-
branches:
|
|
7
|
-
- main
|
|
8
|
-
pull_request:
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
test:
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
steps:
|
|
14
|
-
- name: Checkout
|
|
15
|
-
uses: actions/checkout@v4
|
|
16
|
-
- name: Install MoonBit CLI
|
|
17
|
-
run: |
|
|
18
|
-
curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash
|
|
19
|
-
echo "$HOME/.moon/bin" >> "$GITHUB_PATH"
|
|
20
|
-
- name: Moon update
|
|
21
|
-
run: moon update
|
|
22
|
-
- name: Moon check
|
|
23
|
-
run: moon check --deny-warn
|
|
24
|
-
- name: Moon test
|
|
25
|
-
run: moon test
|