5个版本
0.1.4 | 2023年12月18日 |
---|---|
0.1.3 | 2023年12月18日 |
0.1.2 | 2023年12月18日 |
0.1.1 | 2023年12月17日 |
0.1.0 | 2023年12月17日 |
#133 in 编程语言
每月21次下载
290KB
7K SLoC
nope脚本
nope是一种脚本编程语言,针对小型和有趣的程序进行了优化
nope是
- 有趣的
- 基于表达式的
- 垃圾回收
- 命令式,带有一些函数式元素
- 专注于解决实际问题
- 将数据与逻辑分离
- 可以原生表示JSON和XML
- 单个二进制文件
- 用Rust构建
- 将包含一个完整的stdlib
- 将具有事件循环并发模型
运行和安装
安装rust / cargo然后
cargo install nope-lang
您可以使用以下命令启动交互式repl
nope
或运行脚本
nope myscript.nope
如果您使用vim,可以使用以下命令安装语法支持
nope --install-vim-plugin
路线图
该项目目前处于一个非常非常早期的阶段
- 评估表达式
- 全局、局部变量和作用域
- 常量与运算符
- 数学stdlib
- 循环
- 函数
- 字典和数组
- 垃圾回收
- 错误,try catch
- 字符串stdlib
- 解析和序列化
- utils stdlib
- 资源类型
- os stdlib
- 单元测试
- v1.0
- 异步
- 异步stdlib
- v2.0
- 网络服务器
- v3.0
- 模块与包
- v4.0
- 性能
类型
以下表格应该能给您一个基本类型和允许的数据模型的概念。请注意,目前尚未实现数组和对象。
[
null: null,
void: [void _ ()]
bool: [true false]
num: [0 1 99 3.14 -1_000_000 0xdead 0b10101 NaN Inf PI]
string: ['foo' "bar" ~hello]
arrays: [1 2 true null []]
dicts: {key:32 val:99}
mixed: ['foo' key:'value']
]
nope中的所有数据都是上述类型和结构的组合。
注意,数字是64位浮点数,字符串是Unicode。
代码结构
让我们看看基本的nope程序。
let x = d6() + d6()
var winning = false
if x >= 10 (
set winning = true
print 'haha, yes! :)'
) else (
print 'oh no :('
)
在第一行,我们定义了一个名为x
的变量,其初始值由一个调用两个函数'd6'并添加结果的运算符定义。变量'x'在当前作用域中的后续表达式中可用。由于它是用let
定义的,因此不能用set
来更改它。
在第二行中,我们声明了另一个变量,但这次它可以被修改。
我们接下来评估一个经典的if-else条件语句。请注意,与其他语言不同,代码块不是由花括号{
/}
定义的,而是由括号(
/)
定义的。原因是nope是一种基于表达式的语言,因此每个nope构造都是一个产生值的表达式。
以下示例将这些原则付诸实践。
let res = if flip_coin(), "heads" else "tails"
if
返回一个值,该值将取决于flip_coin()
的结果,可能是字符串“heads”或“tails”。
您可以用括号包围表达式,也可以用括号包围多个表达式。在后一种情况下,所有表达式都将按顺序评估,但只有最后一个表达式会产生值。
这就是我们使用set winning = true
表达式来改变变量winning
,并打印消息的原因。
请注意,print表达式print "hey"
省略了其参数周围的括号。这并不是print函数的特殊情况。在nope中,所有函数参数的括号和逗号都是可选的。
let clamped_0_100 = max 0 min value 100
这也适用于没有参数的函数。
let score = d6 + d6 + d6
请注意,函数应用具有最高的优先级,因此print 1 + 1
打印的是1
,因为加法是在之后执行的。这并不总是您想要的。一种方法是用括号print(1 + 1)
,注意函数名和第一个括号之间的空格是有意义的。没有空格时,期望有完整的参数列表,而有空格时,只是单个参数的括号;max(1,2)
/ max (1) (2)
另一种方法是使用左箭头<-
运算符。此运算符简单地评估右侧的完整表达式。因此,您可以像这样打印print <- 1 + 1
。
按照惯例,nope中的所有函数都将它们操作的数据作为最后一个参数。
let txt = read_text 'file.txt'
let txt2 = upper txt
write_txt 'file2.txt' txt2
借助左箭头<-
运算符,您可以编写以下代码:
write_txt 'file2.txt' <- upper <- read_text 'file.txt'
右箭头->
运算符(尚未实现)执行相同的操作,但方向相反。
read_text 'file.txt' -> upper -> write_txt 'file2.txt'
运算符
相等==
,!=
检查操作数是否为同一类型,如果是这样,则比较它们的值或引用
比较 <
、>
、<=
、>=
首先将数字转换为它们的数值等价物(字符串和数组为NaN),然后进行比较
运算符 +-=
和 !+-=
比较数字的相等性,精度达到 EPSILON
算术运算符 +
、-
、*
、/
、%
、**
,
通常的数学运算。操作数转换为它们的数值等价物(字符串为NaN)
字符串的加法 +
将执行字符串连接,并将另一个操作数转换为字符串
整数 & 位运算
所有以 ~
开头的算术运算符首先将操作数转换为 int32,然后执行整数运算。
例如 10 ~/ 4
是 2
位运算符 ~!
、~|
、~&
、~^
、~<<
、~>>
、~>>>
将操作数转换为 int32,然后执行位运算
布尔值 !
、||
、&&
操作数的布尔等价值是
false
如果是null
、void
或0
true
否则
运算符
!
取消布尔等价值的符号&&
如果第一个操作数为假,则返回第一个操作数,否则返回第二个||
如果第一个操作数为真,则返回第一个操作数,否则返回第二个
默认 ??
如果第一个操作数是 null
或 void
,则返回第二个操作数,否则返回第一个
重复 *:
重复运算符将计算并求和第二个操作数 N 次,其中 N 是第一个操作数。
例如,这将掷骰子 3 次
print(3 *: d6)
请注意,首先将第一个操作数转换为数字。如果数字为零或负数,则返回 void
。
循环
不支持两种循环机制,loop
无限重复后面的表达式,和 while
,它评估一个条件,只要条件保持为真,就重复下一个表达式。
var i = 0, while i < 10 (
set i = print i + 1
)
continue
将直接跳转到下一次迭代,而 break
将停止迭代
var i = 0, loop (
if i < 10 (
set i = i + 1
continue
)
break
)
循环也是表达式,并返回它们的表达式的最后一个值。 break
返回空值,break_as
将中断并返回下一个表达式
var i = 0, let res = loop (
if i < 10 (
set i = i + 1
) else (
break_as 'done!'
)
)
打印到终端
print
和 echo
是类似的功能,它们接受一个参数,将值打印到终端,并返回它。区别在于 print
打印原始字符串转换后的值,而 echo
打印值的彩色内部表示。
在交互式解释器中,每次提交执行后都会回显。
请注意,由于 print
和 echo
都返回它们的参数,因此可以在表达式中使用它们来显示临时值。
var i = 0, while i < 10 (
set x = print x + 1
)
类型检查与转换
以下函数将转换为其类型: to_num
、to_bool
、to_str
以下函数测试类型: is_void
、is_null
、is_bool
、is_num
、is_int
、is_nan
、is_odd
、is_even
、is_str
算术函数和常量
Nope 支持以下算术函数
floor
、ceil
、abs
、acos
、acosh
、sin
、sinh
、asin
、asinh
、cos
、cosh
、tan
、tanh
、atan
、atanh
、inv
log2
、log10
、ln
、ln1p
、exp
、expm1
、sqrt
、cbrt
、round
、fround
、trunc
、sign
、max
、min
、pow
、atan2
以下算术常量
NaN
、Inf
、PI
、E
、SQRT_2
、SQRT_2PI
、LN_2
、LN_10
、LOG2_10
、LOG2_E
、LOG10_2
、LOG10_E
、PHI
、TAU
、EPISLON
、MAX|MIN_INT
MAX|MIN_F64
、MAX|MIN_I32|16|8
、MAX_U32|16|8
字符串
len
返回字符串的长度(扫描整个字符串)upper
和lower
用于转换字符串的大小写trim
移除字符串开头和结尾的空白字符char_at(idx, text)
获取字符串中指定索引的字符substr(from_idx, to_idx, text)
,根据字符索引返回子字符串。其中to_idx
不包含在内。负索引从字符串末尾开始。replace(from, to, text)
将text
中的from
替换为to
find(substr, str)
,返回substr
在str
中的位置或-1
contains(substr, str)
如果substr
是str
的子字符串,则返回true
bitstr
将数字转换为它的位表示形式的字符串
随机性
Nope 支持以下随机数生成器函数
random
,flip_coin
,rand100
,d4
,d6
,d8
,d10
,d12
,d20
,d100
如果您想返回三次骰子投掷的总和,最好使用重复操作符 3*:d6
单位
Nope 允许您使用单位后缀注释数字字面量。
let distance = cos 45deg * (10Km + 3miles + 5yd + 3in + 5cm)
单位将数字转换为它们的国际单位制等效值。例如,所有距离都转换为米。
运行时不会保留数字的单位信息。单位不过是方便的语法技巧。
以下单位受到支持
pi
,tau
,phi
,GT
,MT
,kT
,T
,kg
,g
,mg
,ug
,ng
,Ti
,Gi
,Mi
,ki
,d
,h
,min
,s
,ms
,us
,ns
,moon
,deg
,rad
,in
,km
,m
,dm
,cm
,mm
,um
,nm
,lb
,oz
,mile
,miles
,ft
,yd
,F
,C
,K
,m3
,l
,dm3
,dl
,cl
,ml
,cm3
,barrel
,cuft
,ft3
,gal
,pint
,cuin
,in3
,cuyd
,yd3
,m2
,dm2
,cm2
,mm2
,a
,ha
,km2
,mile2
,yd2
,sqyd
,ft2
,sqft
,in2
,sqin
,belgium
,footballfield
,TiB
,TB
,GiB
,GB
,MiB
,MB
,KiB
,KB
,million
,billion
,trillion
,quadrillon
,milli
,thousandth
,micro
,nano
,pico
,
也可以使用from_unit
和to_unit
函数在运行时将一个单位转换为另一个单位。
let area_sqin = to_unit 'sqin' <- from_unit 'ha' <- 50
依赖项
~6-17MB
~182K SLoC