revo, the programming language
revo, the programming language
revo, the programming language docs | github revo is a dynamic language made for the joy of programming, a 1mb toolkit with a ton of focus on ergonomics. revo 编程语言文档 | GitHub revo 是一门为编程乐趣而生的动态语言,它是一个专注于人体工程学(易用性)、体积仅 1MB 的工具包。
Pipes (管道)
Clean data flow without nesting; things flow from top to bottom. 清晰的数据流,无需嵌套;数据从上到下流动。
"hello!!"
|> string.upper
|> string.sub(0, 4)
|> fn(s) s + ", world!"
|> inspect
# or with placeholders
"hello!!"
|> _:upper() # obj:method() == obj.method(obj)
|> _:sub(0, 4)
|> do # you can even put any expression here
# even do-end blocks
_ + ", world!"
end
|> print
Errors-as-values (错误即值)
Nil and booleans are replaced by atoms. You can’t use a value without handling an error. All crashes are explicit (WIP), aided massively by pattern matching, ?, orelse, and :unwrap().
Nil 和布尔值被原子(atoms)取代。如果不处理错误,你就无法使用该值。所有的崩溃都是显式的(开发中),并得到了模式匹配、?、orelse 和 :unwrap() 的极大辅助。
# f might be (:ok, "file-contents") or (:err, :IoError)
const f = fs.open({path = "./readme.md"})
# `?` unwraps :ok and panics on :err at top-level
const f2 = fs.open({path = "./readme.md"})?
# crashes if :err
const f = fs.open({path = "./readme.md"}):unwrap()
Everything is an expression (一切皆表达式)
No statements, everything (really) always returns a value… but the code still looks procedural. 没有语句,一切(真的)总是返回一个值……但代码看起来仍然是过程式的。
let x = 10 # this line evaluates to 10
let label = if x > 0 "positive" else "zero"
let a = let b = 5 # this whole line evaluates to 5
fn is_true() 5 + 5 == 10
# both x and is_true are the same function
const x = fn is_true() do # do-end is one too
# return and break are special
return 5 + 5 == 10
end
Comp (编译时执行)
Execute any (really) expression at compile time. Any script can be compiled into bytecode and get any value baked in. 在编译时执行任何(真的)表达式。任何脚本都可以编译成字节码,并将任何值预先植入。
# asks for a line of input at build-time
# then keeps the result at run-time
const x = comp read()
const long = do
let t = 0
for x in 0..100 t += x
t # similar to rust's {}, revo do-end blocks return the last value
end
Procedural Macros (过程宏)
Along with an AST-substituting macro system, this lets you just get an iterator over the raw AST tokens, run any code to transform them, then return back a table of the new AST. 除了 AST 替换宏系统外,这还允许你获取原始 AST 标记的迭代器,运行任何代码来转换它们,然后返回一个新的 AST 表。
# > num, num, num -> Sigma^4_n=1(a * b + c)
proc cmul!(iter) do
let a = 10 + (iter:next_of(:number))
let b = iter:next_of(:number)
let c = iter:next_of(:number)
let acc = 0
for i in 1..5 do acc += a * b + c end
{(:number, acc)}
end
Pattern Matching (模式匹配)
Destructure and branch in place. You will be using atoms and tuples; they are beautiful solutions to their problems. 原地解构和分支。你将使用原子和元组;它们是解决各自问题的优雅方案。
const response = match "hello!"
| "hello!" => "hi!"
| x when (x:len() > 10) => ""
| x when string?(x) => x + " to you too!"
| _ => ":("
Fibers (纤程)
I made all your blocking code become non-blocking by just adding a spawn before it.
我通过在阻塞代码前添加 spawn,使你所有的阻塞代码都变成了非阻塞代码。
fn serve(peer, message) do peer:send(message)? end
while :true do
# accept the next connection; if none is ready, this fiber parks
let conn = server:accept()?
# the only thing you have to do to make it async is to add `spawn` here!
spawn serve(conn, port - 1)
end
Tables (表)
Represent everything: used for module exports, arrays, and maps. 代表一切:用于模块导出、数组和映射。
let t = {1, 2, 3, key = "value"}
let rec = {name = "revo", version = 1}
rec.name
t[0]
Convenient Typing (便捷的类型系统)
The type system is optional, but very well-integrated. Untyped code works just fine, but typed code is faster and gets optimized better (and ensures code correctness at compile-time!). 类型系统是可选的,但集成得非常好。无类型代码运行良好,但有类型代码运行更快且优化更好(并确保编译时的代码正确性!)。
type Result = (:ok, any) | (:err, atom)
struct User {
name: string = "me",
age: int = 21,
fn get_age(self) -> Result (:ok, self.age),
}
# type is inferred
let user = User{}
print(user:get_age())