From bf705069a59207ca412d5e6bddcb83731049162b Mon Sep 17 00:00:00 2001 From: 0264408 Date: Tue, 16 Jun 2026 19:40:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=AF=B9=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E5=92=8C=E5=AF=B9=E8=B1=A1=E5=AD=97=E9=9D=A2=E9=87=8F?= =?UTF-8?q?=E7=9A=84=E5=B0=BE=E9=9A=8F=E9=80=97=E5=8F=B7=E6=94=AF=E6=8C=81?= =?UTF-8?q?=EF=BC=8C=E6=9B=B4=E6=96=B0=E7=9B=B8=E5=85=B3=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/practical.ast | 182 +++++++++++++++++++++++++++++++++++++++++ src/parser/parser.rs | 8 ++ src/parser/tests.rs | 16 ++++ 3 files changed, 206 insertions(+) create mode 100644 examples/practical.ast diff --git a/examples/practical.ast b/examples/practical.ast new file mode 100644 index 0000000..4c58320 --- /dev/null +++ b/examples/practical.ast @@ -0,0 +1,182 @@ +// ============================================================================ +// 实用脚本集合:文本统计、数组工具、排序、数据转换 +// 运行: cargo run -- examples/practical.ast +// ============================================================================ + +// ============================================================================ +// 1. 文本统计工具 +// ============================================================================ +fn count_chars(s) { + return len(s) +} + +fn count_words(s) { + let count = 0 + let in_word = false + for (c in s) { + if (c == " " || c == "\n" || c == "\t") { + in_word = false + } else if (!in_word) { + count = count + 1 + in_word = true + } + } + return count +} + +fn text_stats(text) { + print("=== Text Stats ===") + print("chars:", count_chars(text)) + print("words:", count_words(text)) +} + +let sample = "hello world from Aster scripting language" +text_stats(sample) + + +// ============================================================================ +// 2. 数组工具函数 (map / filter / reduce) +// ============================================================================ + +fn map(arr, func) { + let result = [] + for (x in arr) { + push(result, func(x)) + } + return result +} + +fn filter(arr, pred) { + let result = [] + for (x in arr) { + if (pred(x)) { + push(result, x) + } + } + return result +} + +fn reduce(arr, func, init) { + let acc = init + for (x in arr) { + acc = func(acc, x) + } + return acc +} + +let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + +let doubled = map(nums, fn(x) { return x * 2 }) +print("map (*2):", doubled) + +let evens = filter(nums, fn(x) { return x % 2 == 0 }) +print("filter (even):", evens) + +let sum = reduce(nums, fn(a, b) { return a + b }, 0) +print("reduce (sum):", sum) + +// 链式: 偶数平方和 +let even_squares = map( + filter(nums, fn(x) { return x % 2 == 0 }), + fn(x) { return x * x } +) +let sum_squares = reduce(even_squares, fn(a, b) { return a + b }, 0) +print("sum of even squares:", sum_squares) + + +// ============================================================================ +// 3. 冒泡排序 +// ============================================================================ + +fn sort(arr) { + let n = len(arr) + let i = 0 + while (i < n - 1) { + let j = 0 + while (j < n - i - 1) { + if (arr[j] > arr[j + 1]) { + let tmp = arr[j] + arr[j] = arr[j + 1] + arr[j + 1] = tmp + } + j = j + 1 + } + i = i + 1 + } + return arr +} + +let unsorted = [42, 17, 8, 99, 3, 56] +print("unsorted:", unsorted) +print("sorted:", sort(unsorted)) + + +// ============================================================================ +// 4. 数据转换 (类 JSON 处理) +// ============================================================================ + +let users = [ + { name: "Alice", age: 28, active: true }, + { name: "Bob", age: 35, active: false }, + { name: "Carol", age: 22, active: true }, + { name: "Dave", age: 40, active: true }, +] + +// 找出活跃用户的名字,按年龄排序 +let active = filter(users, fn(u) { return u["active"] }) +print("active users:", len(active)) + +// 计算平均年龄 +let total_age = reduce(users, fn(acc, u) { return acc + u["age"] }, 0) +print("avg age:", total_age / len(users)) + +// 生成名字列表 +let names = map(users, fn(u) { return u["name"] }) +print("names:", names) + + +// ============================================================================ +// 5. 斐波那契 (递归 + 迭代 + 缓存对比) +// ============================================================================ + +fn fib_rec(n) { + if (n <= 1) { return n } + return fib_rec(n - 1) + fib_rec(n - 2) +} + +fn fib_iter(n) { + if (n <= 1) { return n } + let a = 0 + let b = 1 + let i = 2 + while (i <= n) { + let tmp = a + b + a = b + b = tmp + i = i + 1 + } + return b +} + +print("fib_rec(20):", fib_rec(20)) +print("fib_iter(20):", fib_iter(20)) + + +// ============================================================================ +// 6. 回文检测 +// ============================================================================ + +fn is_palindrome(s) { + let n = len(s) + let i = 0 + while (i < n / 2) { + if (s[i] != s[n - 1 - i]) { + return false + } + i = i + 1 + } + return true +} + +print("is_palindrome('radar'):", is_palindrome("radar")) +print("is_palindrome('hello'):", is_palindrome("hello")) diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 596904f..e77519d 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -567,6 +567,10 @@ impl Parser { if !self.match_kind(&[TokenKind::Comma]) { break; } + // Allow trailing comma + if self.check(&TokenKind::RightBrace) { + break; + } } } self.consume(TokenKind::RightBrace, "Expected '}' after object literal")?; @@ -581,6 +585,10 @@ impl Parser { if !self.match_kind(&[TokenKind::Comma]) { break; } + // Allow trailing comma + if self.check(&TokenKind::RightBracket) { + break; + } } } self.consume(TokenKind::RightBracket, "Expected ']' after array literal")?; diff --git a/src/parser/tests.rs b/src/parser/tests.rs index face204..69fd310 100644 --- a/src/parser/tests.rs +++ b/src/parser/tests.rs @@ -551,6 +551,22 @@ } } + #[test] + fn parse_array_trailing_comma() { + match parse_expr("[1, 2, 3,]") { + Expr::ArrayLiteral { elements } => assert_eq!(elements.len(), 3), + e => panic!("Expected ArrayLiteral, got {:?}", e), + } + } + + #[test] + fn parse_object_trailing_comma() { + match parse_expr("{a: 1, b: 2,}") { + Expr::ObjectLiteral { properties } => assert_eq!(properties.len(), 2), + e => panic!("Expected ObjectLiteral, got {:?}", e), + } + } + // ----- statements ----- #[test]