版本: 0.2.0
更新日期: 2026-02-01
Chen Lang 是一个简洁、动态类型的编程语言,具有以下特点:
- 🎯 简洁语法 - 易于学习和使用
- 🔄 动态类型 - 灵活的类型系统
- 📦 对象系统 - 基于原型的对象模型
- ⚡ 高精度数值 - 使用 Decimal 类型避免浮点误差
- 🛡️ 异常处理 - 完整的 try-catch-finally 机制
- 🚀 快速执行 - 基于字节码的虚拟机
# 运行demo文件
cargo run --bin chen_lang -- run demo_codes/fibonacci.ch
# 从标准输入运行程序
echo 'let io = import("stdlib/io"); io.println("Hello from stdin")' | cargo run --bin chen_lang -- run -
# 直接运行代码
echo 'let x = 5; let y = 3; print(x + y)' | cargo run --bin chen_lang -- run -# 这是单行注释
# 多行注释需要每行都用 # 开头
# 第二行注释
# 第三行注释Chen Lang 使用换行符作为语句分隔符:
let x = 10
let y = 20
let z = x + y使用花括号 {} 定义代码块:
if x > 0 {
println("Positive")
}
for i < 10 {
println(i)
i = i + 1
}Chen Lang 支持以下数据类型:
let age = 25
let negative = -100
let zero = 0使用高精度 Decimal 类型,避免浮点误差:
let price = 19.99
let pi = 3.14159
let result = 0.1 + 0.2 # 结果是精确的 0.3使用双引号或单引号:
let name = "Chen Lang"
let message = 'Hello, World!'
# 字符串拼接
let greeting = "Hello, " + namelet is_valid = true
let is_empty = falselet empty = null使用 ${} 创建对象:
let person = ${
name: "Alice",
age: 30,
city: "Beijing"
}使用 [] 创建数组:
let numbers = [1, 2, 3, 4, 5]
let mixed = [1, "two", true, null]函数是一等公民:
let add = def(a, b) {
a + b
}使用 let 关键字声明变量:
let x = 10
let name = "Chen"
let is_valid = truelet x = 10
x = 20 # 重新赋值Chen Lang 使用词法作用域:
let global_var = "global"
def my_function() {
let local_var = "local"
# println 需要导入,这里假设已导入
# println(global_var) # 可以访问全局变量
# println(local_var) # 可以访问局部变量
}
# println(local_var) # 错误!无法访问局部变量let x = 10
if true {
let y = 20
println(x) # 10
println(y) # 20
}
# println(y) # 错误!y 在块外不可见let a = 10
let b = 3
let sum = a + b # 13
let diff = a - b # 7
let product = a * b # 30
let quotient = a / b # 3.333...
let remainder = a % b # 1let x = 10
let y = 20
x == y # false (等于)
x != y # true (不等于)
x < y # true (小于)
x <= y # true (小于等于)
x > y # false (大于)
x >= y # false (大于等于)let a = true
let b = false
a && b # false (逻辑与)
a || b # true (逻辑或)
!a # false (逻辑非)let first = "Hello"
let second = "World"
let result = first + " " + second # "Hello World"从高到低:
!(逻辑非),-(负号)*,/,%+,-<,<=,>,>===,!=&&||
let score = 85
if score >= 90 {
println("A")
} else if score >= 80 {
println("B")
} else {
println("C")
}If 可以作为表达式使用:
let status = if age >= 18 { "adult" } else { "minor" }Chen Lang 的 for 循环非常灵活, 支持条件循环、无限循环以及集合迭代。
let i = 0
for i < 10 {
println(i)
i = i + 1
}for {
if some_condition() {
break
}
}可以使用 for...in 语法遍历数组、对象、字符串以及协程。它会自动调用集合的
:iter() 方法。
# 遍历数组值
let arr = ["A", "B", "C"]
for x in arr {
println(x)
}
# 遍历对象值
let obj = ${ a: 1, b: 2 }
for v in obj {
println(v)
}
# 遍历字符串字符
for char in "Hello" {
println(char)
}如果需要同时获取索引/键和值,可以使用 :entries() 方法。它会返回一个包含 key
和 value 属性的对象。
for e in arr:entries() {
println("Index: " + e.key + ", Value: " + e.value)
}
for e in obj:entries() {
println("Key: " + e.key + ", Value: " + e.value)
}let i = 0
for i < 10 {
if i == 5 {
break # 退出循环
}
if i % 2 == 0 {
i = i + 1
continue # 跳过本次迭代
}
println(i)
i = i + 1
}def greet(name) {
println("Hello, " + name + "!")
}
greet("Alice") # 输出: Hello, Alice!def add(a, b) {
return a + b
}
let result = add(10, 20) # 30函数的最后一个表达式会自动返回:
def multiply(a, b) {
a * b # 隐式返回
}
let result = multiply(5, 6) # 30let square = def(x) {
x * x
}
println(square(5)) # 25def fibonacci(n) {
if n <= 1 {
return n
}
return fibonacci(n - 1) + fibonacci(n - 2)
}
println(fibonacci(10)) # 55def outer() {
def inner() {
println("Inner function")
}
inner()
}
outer() # 输出: Inner functiondef apply(func, value) {
func(value)
}
def double(x) {
x * 2
}
let result = apply(double, 10) # 20let person = ${
name: "Alice",
age: 30,
city: "Beijing"
}println(person.name) # "Alice"
println(person.age) # 30person.age = 31
person.email = "alice@example.com" # 添加新属性调用对象方法时,如果方法需要访问对象本身(即 self),请使用冒号 :
语法。冒号语法会自动将调用者作为第一个参数传递给方法。如果使用点号 .
调用,对象不会作为参数传递。
let calculator = ${
value: 0,
add: def(self, n) {
self.value = self.value + n
},
get: def(self) {
self.value
}
}
# 使用冒号调用(自动传递 self)
calculator:add(10)
calculator:add(5)
println(calculator:get()) # 15元表用于实现高级特性,如运算符重载和方法查找:
# 定义 Point 原型
let Point = ${
__index: ${
to_string: def(self) {
"Point(" + self.x + ", " + self.y + ")"
}
},
__add: def(a, b) {
new_Point(a.x + b.x, a.y + b.y)
}
}
# 构造函数
def new_Point(x, y) {
let instance = ${ x: x, y: y }
set_meta(instance, Point)
return instance
}
# 使用
let p1 = new_Point(10, 20)
let p2 = new_Point(5, 10)
let p3 = p1 + p2 # 使用重载的 + 运算符
println(p3:to_string()) # "Point(15, 30)"支持的元方法:
__add- 加法 (+)__sub- 减法 (-)__mul- 乘法 (*)__index- 属性查找拦截。当访问不存在的属性时触发。它可以是一个对象(在该对象中继续查找),也可以是一个函数def(obj, key),用于动态返回默认值。__newindex- 属性赋值拦截。当给不存在的属性赋值时触发。它必须是一个函数def(obj, key, value),用于动态拦截和处理赋值行为。
let io = import("stdlib/io")
let proto = ${
# 当查找不存在的属性时触发
__index: def(obj, key) {
return "fallback_" + key
},
# 当给不存在的属性赋值时触发
__newindex: def(obj, key, value) {
io.println("拦截到赋值: " + key + " = " + value)
# 注意: 如果这里直接给 obj[key] 赋值会触发死循环
}
}
let person = ${ name: "Alice" }
set_meta(person, proto)
# 触发 __index
println(person.age) # 输出: fallback_age
# 触发 __newindex
person.city = "Beijing" # 输出: 拦截到赋值: city = Beijinglet numbers = [1, 2, 3, 4, 5]
let mixed = [1, "two", true, null]
let empty = []let first = numbers[0] # 1
let second = numbers[1] # 2numbers[0] = 10
numbers[5] = 6 # 添加新元素let arr = [1, 2, 3]
# 获取长度
let length = arr:len() # 3
# 添加元素
arr:push(4) # 返回新长度 4, arr 变为 [1, 2, 3, 4]
# 弹出元素
let last = arr:pop() # 返回 4, arr 变为 [1, 2, 3]
# 获取类型
println(arr.__type) # "Array"let arr = [10, 20, 30]
let i = 0
for i < arr:len() {
println(arr[i])
i = i + 1
}try {
throw "Something went wrong!"
} catch error {
println("Caught error: " + error)
}try {
throw "Error"
} catch error {
println("Error: " + error)
} finally {
println("Cleanup") # 总是执行
}try {
throw "Error"
} catch {
println("An error occurred")
}def divide(a, b) {
if b == 0 {
throw "Division by zero"
}
a / b
}
try {
let result = divide(10, 0)
} catch error {
println("Error: " + error)
}try {
try {
throw "Inner error"
} catch e {
println("Inner catch: " + e)
throw "Outer error"
}
} catch e {
println("Outer catch: " + e)
}Chen Lang 采用显式导入机制。除了极少数核心功能(如 null,
coroutine)外,大部分标准库功能(即所谓的“标准库”)都需要通过 import
语句显式引入。
let <变量名> = import("<模块路径>")示例:
let JSON = import("stdlib/json")
let io = import("stdlib/io")- 按需引入: 减少全局命名空间污染,提高加载性能。
- 显式依赖: 从代码中可以清晰看到使用了哪些外部模块。
| 模块路径 | 返回对象包含的成员 | 说明 |
|---|---|---|
stdlib/io |
print, println, readline |
标准输入输出 |
stdlib/json |
stringify, parse |
JSON 序列化与解析 |
stdlib/date |
new, now, parse |
日期时间处理 |
stdlib/fs |
read_to_string, write_file 等 |
文件系统操作 |
stdlib/http |
get, post 等 |
HTTP 客户端 |
stdlib/process |
exit, args, env 等 |
进程与环境信息 |
你可以创建自己的 .ch
文件并导入它们。被导入的文件会作为独立的模块执行,最后一行表达式的值将作为模块的返回值。
例如,创建 math_utils.ch:
# math_utils.ch
${
add: def(a, b) { a + b },
sub: def(a, b) { a - b }
}在主程序中导入:
let math_utils = import("math_utils.ch")
let result = math_utils.add(10, 20)
let io = import("stdlib/io")
io.println(result) # 30注意:导入路径是相对于当前执行目录或绝对路径。模块会被缓存,重复导入不会重新执行。
let io = import("stdlib/io")
let JSON = import("stdlib/json")
let score = 85
let level = if score >= 90 { "A" } else if score >= 60 { "P" } else { "F" }
let result = ${
score: score,
level: level
}
# 必须导入 stdlib/io 才能使用 println
io.println("Final Result: " + JSON.stringify(result))# 打印(不换行)
print("Hello")
print(" World") # 输出: Hello World
# 打印(换行)
println("Hello")
println("World")
# 输出:
# Hello
# World# 创建当前时间
let now = Date:new()
# 获取类型
println(now.__type) # "Date"
# 格式化日期
let formatted = now:format('%Y-%m-%d %H:%M:%S')
println(formatted) # 例如: 2025-12-10 22:40:00
# 常用格式符号:
# %Y - 年份 (2025)
# %m - 月份 (01-12)
# %d - 日期 (01-31)
# %H - 小时 (00-23)
# %M - 分钟 (00-59)
# %S - 秒 (00-59)# 序列化为 JSON
let data = ${
name: "Alice",
age: 30,
hobbies: ["reading", "coding"]
}
let json_str = JSON.stringify(data)
io.println(json_str)
# 输出: {"name":"Alice","age":30,"hobbies":["reading","coding"]}
# 解析 JSON
let parsed = JSON.parse(json_str)
println(parsed.name) # "Alice"let text = "Hello, World!"
# 获取长度
let length = text:len() # 13
# 转大写
let upper = text:upper() # "HELLO, WORLD!"
# 转小写
let lower = text:lower() # "hello, world!"
# 去除空白
let trimmed = " hello ":trim() # "hello"
# 获取类型
println(text.__type) # "String"let obj = ${
name: "Alice",
age: 30,
city: "Beijing"
}
# 获取所有键
let keys = obj:keys() # ["name", "age", "city"]
# 获取迭代器 (仅返回值)
let it = obj:iter()
# 获取键值对迭代器
let entries = obj:entries()
# 返回的对象结构为: ${ key: "name", value: "Alice" }# 设置元表
set_meta(object, metatable)
# 获取元表
let mt = get_meta(object)def fibonacci(n) {
if n <= 1 {
return n
}
fibonacci(n - 1) + fibonacci(n - 2)
}
let i = 0
for i < 10 {
println("fib(" + i + ") = " + fibonacci(i))
i = i + 1
}let i = 1
for i <= 9 {
let j = 1
for j <= i {
print(j + " × " + i + " = " + (i * j) + " ")
j = j + 1
}
println("")
i = i + 1
}let calculator = ${
value: 0,
add: def(self, n) {
self.value = self.value + n
self
},
subtract: def(self, n) {
self.value = self.value - n
self
},
multiply: def(self, n) {
self.value = self.value * n
self
},
divide: def(self, n) {
if n == 0 {
throw "Division by zero"
}
self.value = self.value / n
self
},
result: def(self) {
self.value
}
}
try {
let result = calculator.add(10).multiply(5).subtract(20).result()
println("Result: " + result) # 30
} catch error {
println("Error: " + error)
}# Point 原型
let Point = ${
__index: ${
to_string: def(self) {
"Point(" + self.x + ", " + self.y + ")"
},
move_by: def(self, dx, dy) {
self.x = self.x + dx
self.y = self.y + dy
}
},
__add: def(a, b) {
new_Point(a.x + b.x, a.y + b.y)
},
__sub: def(a, b) {
new_Point(a.x - b.x, a.y - b.y)
}
}
def new_Point(x, y) {
let instance = ${ x: x, y: y }
set_meta(instance, Point)
return instance
}
# 使用
let p1 = new_Point(10, 20)
let p2 = new_Point(5, 10)
println(p1.to_string()) # "Point(10, 20)"
println(p2.to_string()) # "Point(5, 10)"
let p3 = p1 + p2
println(p3.to_string()) # "Point(15, 30)"
p1.move_by(5, -10)
println(p1.to_string()) # "Point(15, 10)"def safe_divide(a, b) {
try {
if b == 0 {
throw "Division by zero"
}
return a / b
} catch error {
println("Error: " + error)
return null
}
}
println(safe_divide(10, 2)) # 5
println(safe_divide(10, 0)) # Error: Division by zero, 然后输出 null# 变量和函数使用 snake_case
let user_name = "Alice"
def calculate_total() { }
# 构造函数推荐使用驼峰或 new_ 前缀
def new_Point(x, y) { }
def NewPoint(x, y) { }
# 常量使用大写
let MAX_SIZE = 100# 将相关功能组织在一起
let MathUtils = ${
PI: 3.14159,
square: def(x) { x * x },
cube: def(x) { x * x * x }
}# 对可能失败的操作使用 try-catch
try {
risky_operation()
} catch error {
println("Error: " + error)
}try {
# 执行操作
process_data()
} catch error {
println("Error: " + error)
} finally {
# 总是清理资源
println("Cleanup done")
}A: Chen Lang 是动态类型语言,变量的类型在运行时确定。
A: Chen Lang 使用 Decimal 类型存储浮点数,避免了常见的浮点精度问题。例如
0.1 + 0.2 的结果是精确的 0.3。
A: Chen Lang 使用基于原型的对象系统,通过元表的 __index 实现类似继承的功能。
A: 使用 println() 输出调试信息,查看错误消息中的行号定位问题。
A: 推荐使用 for...in 语法直接遍历:
let arr = [1, 2, 3]
for x in arr {
println(x)
}如果需要索引,请使用 :entries():
for e in arr:entries() {
println(e.key + ": " + e.value)
}传统的索引遍历依然有效:
let i = 0
for i < arr:len() {
println(arr[i])
i = i + 1
}| 关键字 | 说明 |
|---|---|
let |
变量声明 |
def |
函数定义 |
if |
条件语句 |
else |
否则分支 |
for |
循环 |
return |
返回值 |
break |
退出循环 |
continue |
继续下一次迭代 |
try |
异常处理 |
catch |
捕获异常 |
finally |
最终执行 |
throw |
抛出异常 |
true |
布尔真值 |
false |
布尔假值 |
null |
空值 |
| 函数 | 说明 |
|---|---|
print(...) |
打印(不换行) |
println(...) |
打印(换行) |
set_meta(obj, meta) |
设置对象的元表 |
get_meta(obj) |
获取对象的元表 |
| 对象 | 说明 |
|---|---|
Date |
日期时间对象,使用 Date.new() 创建 |
JSON |
JSON 序列化,提供 stringify() 和 parse() 方法 |
| 方法 | 说明 |
|---|---|
arr:len() |
返回数组长度 |
arr:push(value) |
添加元素到末尾, 返回新长度 |
arr:pop() |
移除并返回最后一个元素 |
arr:iter() |
返回一个仅产生值的迭代器 (用于 for-in) |
arr:entries() |
返回一个产生 {key, value} 对象的迭代器 |
| 方法 | 说明 |
|---|---|
str:len() |
返回字符串长度 |
str:upper() |
转换为大写 |
str:lower() |
转换为小写 |
str:trim() |
去除首尾空白 |
str:iter() |
返回一个产生每个字符的迭代器 (用于 for-in) |
| 方法 | 说明 |
|---|---|
obj:keys() |
返回对象所有键名组成的数组 |
obj:iter() |
返回一个仅产生值的迭代器 (用于 for-in) |
obj:entries() |
返回一个产生 {key, value} 对象的迭代器 |
协程是 Chen Lang 处理异步和迭代的核心。
| 方法 | 说明 |
|---|---|
co:resume() |
恢复运行协程 |
co:status() |
返回协程状态 ("suspended", "running", "dead") |
co:iter() |
返回协程自身, 以便直接在 for-in 中使用 |
以下功能目前尚未支持:
- ❌ 闭包 - 内部函数无法捕获外部作用域的变量
祝你学习愉快! 🎉
如有问题,请参考示例代码或查看项目文档。