improve fscript docs and testcase

This commit is contained in:
lixianjing 2021-01-02 12:36:30 +08:00
parent 151d1b8c15
commit ddfbed2fc7
6 changed files with 215 additions and 116 deletions

View File

@ -6,9 +6,9 @@ fscript 是一个极简的脚本引擎,借鉴了函数语言中一些思路,
* 特色:
* 小内存。最低开销小于 400 字节。
* 小巧。核心代码 1000 行,扩展函数 700 行。
* 小巧。核心代码 1000 行,扩展函数 800 行。
* 灵活。支持多条语句、函数嵌套调用和变量定义。
* 简单。只有函数调用和表达式,熟悉任何一种编程语言的人5分钟内即可学会。
* 简单。熟悉任何一种编程语言的人5 分钟内即可学会。
* 强大。超过 60 个内置函数,支持条件语句和循环语句,支持复杂的表达式,支持用 C 语言扩展函数。
> 如果不需要数学函数,可以定义 AWTK_LITE 宏。
@ -29,12 +29,22 @@ fscript 是一个极简的脚本引擎,借鉴了函数语言中一些思路,
print("hello fscript")
```
在 PC 上测试运行:
* 在 PC 上测试运行:
如:
```
./bin/runFScript 'print("hello fscript")'
```
* 在 PC 上测试运行指定文件:
> 第一个命令行参数以 @ 开头表示它是一个脚本文件,读取其内容执行。
如:
```
./bin/runFScript @tests/testdata/demo_while1.fs
```
## 3. 语法
### 数据类型
@ -58,10 +68,60 @@ print("hello", 123)
### 定义变量
* 通过 set 函数设置
如:
```
set(a, 123)
```
* 通过=赋值
如:
```
a = 123
b = "abc"
c = true
```
#### 变量名命名规则:
* 以字母开头,后面可用数字、英文下划线和英文点。
如:
```
age=123
name="fscript"
file_name="test.txt"
```
* 英文点"."可以用来访问对象的成员,如果对应的对象不存在则当作普通变量。
如:
```
msg.payload = "hello"
```
>在这里,如果对象 msg 存在msg.payload 为 msg 对象的 payload 成员,否则 msg.payload 则是一个普通变量。
* a、b、c 和 d 为快速访问变量,具有更快的访问速度,建议在循环中优先使用。
如:
```
a=0
b=0
while(a < 100) {
a=a+1
b=b+a
print(a, b)
}
```
### 获取变量
```
@ -70,47 +130,102 @@ a
> 获取变量时,如果变量不存在,自动当成字符串处理。不希望当成字符串,可以加上$前缀。
如:
```
./bin/runFScript 'print($abc)'
get var abc failed
(null)
result:true
cost: 112 us
```
```
./bin/runFScript 'print(abc)'
get var abc failed
abc
result:true
cost: 112 us
```
### 函数嵌套调用
```
print(join(",", 1, 2, 3))
print(join(",", +(1, 2), -(5, 2), *(2, 3), /(9, 3)))
print(join(",",1,2,3,4), join(";",5,6,7,8))
```
### 条件执行
* 语句方式
```
if(false, print("a"), print("b"))
a=random(1, 100)
b=random(1, 100)
print("a is ", a);
print("b is ", b);
if(a < b) {
print(a, "<", b)
} else {
print(a, ">=", b)
}
```
> 代码块需要用 {} 扩起来else 语句可以省略。
* 函数方式
```
if(true, print("a"), print("b"))
```
### 循环执行
* 语句方式
```
set(a, 0)
while(a < 10, print(a), set(a, a+1))
a=0
b=0
while(a < 100) {
a=a+1
b=b+a
print(a, b)
}
```
> 代码块需要用 {} 扩起来
* 函数方式
```
a=0
while(a < 10, print(a), a=a+1)
```
### 表达式
为了确保优先级正确,尽量用括号明确优先级。
#### 支持的操作符
* 四则运算:+ - * / %
* 逻辑运算: || && !
* 逻辑运算|| && !
* 位运算:| & ~
* 比较运算:< <= > >= ==
* 条件运算: (p) ? a : b
* 条件运算(p) ? a : b
> 对于加法运算(+),参数中有字符串时,进行字符串连接。
> 对于加法运算 (+),参数中有字符串时,进行字符串连接。
#### 示例
```
set(a, 10);
set(b, 20);
a = 10
b = 20
```
```
@ -131,7 +246,6 @@ a<=b
a>b
a>=b
(1+2)*(2+3)
(1+2)*(2+3)
sin(a) + sin(b)
a<b ? print(a) : print(b)
set(a, a+1)
@ -185,88 +299,6 @@ print(a+b)
print(join(",", a, b))
```
#### noop
> 空函数。什么也不做,主要给 if 函数用。
----------------------------
##### 原型
```
noop()
```
#### seq
> 把组合多条语句组合成一条语句。方便在if语句中执行多条语句。
----------------------------
##### 原型
```
seq(s1, s2, s3, ...)
```
示例
```js
if(
msg.topic == "eof",
seq(
print(msg.topic),
set(aborted, true),
#("文件读取完毕,关闭定时器"),
set(flow.timer.enable, false)
),
seq(
print(str(msg.payload, true)),
set(msg.payload, toupper(str(msg.payload, true)))
)
)
```
#### if
> 条件执行。如果第一个参数为 true执行第二个参数否则执行第三个参数。
----------------------------
##### 原型
```
if(p, s1, s2)
```
#### 示例
```
set(a, 1)
if(<(a, 0), print(" a < 0"), print("a >= 0"))
```
#### while
> 循环执行。如果第一个参数为 true循环执行后面参数的各个语句直到第一个参数返回 false 为止。
----------------------------
##### 原型
```
while(p, s1, ...)
```
#### 示例
```
set(a, 0)
while(a < 10, print(a), set(a, a+1))
```
```
set(a, 0)
set(b, 0)
while(a < 10, print(a, ",", b), set(b, b+a), set(a, a+1))
```
#### set
> 设置变量的值。
@ -474,7 +506,7 @@ float("123")
str(var [,force_pointer_as_str])
```
> force\_pointer\_as\_str 如果输入参数是POINTER类型是否将强制转换成字符串。
> force\_pointer\_as\_str 如果输入参数是 POINTER 类型,是否将强制转换成字符串。
#### 示例

View File

@ -1,3 +1,4 @@
#include "tkc/fs.h"
#include "tkc/mem.h"
#include "tkc/utils.h"
#include "tkc/platform.h"
@ -5,24 +6,15 @@
#include "tkc/fscript.h"
#include "tkc/object_default.h"
int main(int argc, char* argv[]) {
platform_prepare();
tk_mem_dump();
if (argc < 2) {
printf("Usage: %s script\n", argv[0]);
return 0;
} else {
static ret_t run_fscript(const char* code, uint32_t times) {
value_t v;
char buff[64];
uint64_t start = time_now_us();
const char* code = argv[1];
object_t* obj = object_default_create();
tk_mem_dump();
if (argc == 3) {
if (times > 1) {
/*stress test*/
uint32_t i = 0;
uint32_t times = tk_atoi(argv[2]);
fscript_t* fscript = fscript_create(obj, code);
for (i = 0; i < times; i++) {
fscript_exec(fscript, &v);
@ -36,6 +28,35 @@ int main(int argc, char* argv[]) {
}
OBJECT_UNREF(obj);
log_debug("cost: %d us\n", (int)(time_now_us() - start));
return RET_OK;
}
static ret_t run_fscript_file(const char* filename, uint32_t times) {
uint32_t size = 0;
char* code = (char*)file_read(filename, &size);
return_value_if_fail(code != NULL, RET_BAD_PARAMS);
run_fscript(code, times);
TKMEM_FREE(code);
return RET_OK;
}
int main(int argc, char* argv[]) {
platform_prepare();
tk_mem_dump();
if (argc < 2) {
printf("Usage: %s script\n", argv[0]);
return 0;
} else {
const char* code = argv[1];
uint32_t times = argc > 2 ? tk_atoi(argv[2]) : 1;
if (*code == '@') {
run_fscript_file(code + 1, times);
} else {
run_fscript(code, times);
}
}
tk_mem_dump();

24
tests/testdata/demo_expr.fs vendored Normal file
View File

@ -0,0 +1,24 @@
a = 10
b = 20
print(a<b)
print(1+2)
print(1-2)
print(1*2)
print(1/2)
print(3%2)
print(a||b)
print(a&&b)
print(a|b)
print(a&b)
print(!a)
print(~a)
print(a<b)
print(a<=b)
print(a>b)
print(a>=b)
print((1+2)*(2+3))
print(sin(a) + sin(b))
print(set(a, a+1))
print(set(a, a+b))
print("abc" + "123")

11
tests/testdata/demo_if1.fs vendored Normal file
View File

@ -0,0 +1,11 @@
a=random(1, 100)
b=random(1, 100)
print("a is ", a);
print("b is ", b);
if(a < b) {
print(a, "<", b)
} else {
print(a, ">=", b)
}

8
tests/testdata/demo_while1.fs vendored Normal file
View File

@ -0,0 +1,8 @@
a=0
b=0
while(a < 100) {
a=a+1
b=b+a
print(a, b)
}

3
tests/testdata/demo_while2.fs vendored Normal file
View File

@ -0,0 +1,3 @@
a=0
while(a < 10, print(a), a=a+1)