feat: 添加对数组和对象字面量的尾随逗号支持,更新相关测试用例
This commit is contained in:
@@ -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"))
|
||||
@@ -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")?;
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user