mirror of
https://gitee.com/zlgopen/awtk.git
synced 2024-11-30 02:58:26 +08:00
fscript support define function
This commit is contained in:
parent
7991663340
commit
b0384390f3
@ -1,5 +1,7 @@
|
||||
# 最新动态
|
||||
|
||||
2021/08/26
|
||||
* fscript 支持函数定义。
|
||||
2021/08/25
|
||||
* 修改OpenGL的lcd旋转被裁剪的问题(感谢智明提供补丁)
|
||||
* 修复linux-fb的lcd旋转异常的问题(感谢智明提供补丁)
|
||||
|
@ -1279,7 +1279,55 @@ fscript_register_func("foo", func_foo);
|
||||
|
||||
```
|
||||
|
||||
#### 5.1 定义私有函数
|
||||
#### 5.4 定义脚本函数
|
||||
|
||||
* 函数定义
|
||||
|
||||
```
|
||||
function foo1(v1, v2) {
|
||||
return v1 + v2;
|
||||
}
|
||||
assert(foo1(100, 200) == 300)
|
||||
```
|
||||
|
||||
* 使用var定义局部变量。
|
||||
|
||||
```
|
||||
function foo2(v1, v2) {
|
||||
var v3 = v1 + v2;
|
||||
return v3
|
||||
}
|
||||
assert(foo2(100, 200) == 300)
|
||||
|
||||
function foo3(v1, v2) {
|
||||
var v3 = v1 + v2;
|
||||
if(v3 < 100) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
assert(foo3(10, 20))
|
||||
assert(!foo3(100, 200))
|
||||
```
|
||||
|
||||
> 函数内的临时变量,无论在哪里定义,一旦定义,在该函数内都可以使用。
|
||||
|
||||
```
|
||||
function foo4 (v1, v2) {
|
||||
var v3 = v1 + v2;
|
||||
if(v3 < 100) {
|
||||
var name = "awtk";
|
||||
} else {
|
||||
var name = "react-awtk";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
assert(foo4(10, 20) == 'awtk')
|
||||
assert(foo4(100, 200) == 'react-awtk')
|
||||
```
|
||||
|
||||
### 6. 性能测量与优化
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* File: fscript.c
|
||||
* Author: AWTK Develop Team
|
||||
* Brief: a simple functional script language
|
||||
* Brief: a simple script language
|
||||
*
|
||||
* Copyright (c) 2020 - 2021 Guangzhou ZHIYUAN Electronics Co.,Ltd.
|
||||
*
|
||||
@ -18,10 +18,12 @@
|
||||
#ifndef AWTK_LITE
|
||||
#include "tkc/mem.h"
|
||||
#include "tkc/utils.h"
|
||||
#include "tkc/darray.h"
|
||||
#include "tkc/fscript.h"
|
||||
#include "tkc/object_default.h"
|
||||
|
||||
struct _fscript_func_call_t {
|
||||
void* ctx;
|
||||
fscript_func_t func;
|
||||
fscript_args_t args;
|
||||
fscript_func_call_t* next;
|
||||
@ -32,11 +34,29 @@ struct _fscript_func_call_t {
|
||||
#define VALUE_TYPE_JSCRIPT_ID 128
|
||||
#define VALUE_TYPE_JSCRIPT_FUNC VALUE_TYPE_JSCRIPT_ID + 1
|
||||
|
||||
static ret_t func_if(fscript_t* fscript, fscript_args_t* args, value_t* result);
|
||||
static ret_t func_while(fscript_t* fscript, fscript_args_t* args, value_t* result);
|
||||
static ret_t func_function_def(fscript_t* fscript, fscript_args_t* args, value_t* result) {
|
||||
return RET_OK;
|
||||
}
|
||||
static ret_t func_if(fscript_t* fscript, fscript_args_t* args, value_t* result) {
|
||||
return RET_OK;
|
||||
}
|
||||
static ret_t func_while(fscript_t* fscript, fscript_args_t* args, value_t* result) {
|
||||
return RET_OK;
|
||||
}
|
||||
static ret_t func_noop(fscript_t* fscript, fscript_args_t* args, value_t* result) {
|
||||
return RET_OK;
|
||||
}
|
||||
static ret_t func_return(fscript_t* fscript, fscript_args_t* args, value_t* result) {
|
||||
if (args->size > 0) {
|
||||
value_deep_copy(result, args->args);
|
||||
}
|
||||
fscript->returned = TRUE;
|
||||
return RET_OK;
|
||||
}
|
||||
static ret_t func_set(fscript_t* fscript, fscript_args_t* args, value_t* result);
|
||||
static ret_t func_unset(fscript_t* fscript, fscript_args_t* args, value_t* result);
|
||||
static ret_t fscript_exec_func(fscript_t* fscript, fscript_func_call_t* iter, value_t* result);
|
||||
static ret_t func_set_local(fscript_t* fscript, fscript_args_t* args, value_t* result);
|
||||
|
||||
ret_t fscript_set_error(fscript_t* fscript, ret_t code, const char* func, const char* message) {
|
||||
fscript->error_code = code;
|
||||
@ -57,7 +77,6 @@ static value_t* value_set_func(value_t* v, fscript_func_call_t* func) {
|
||||
|
||||
static fscript_func_call_t* value_func(const value_t* v) {
|
||||
return_value_if_fail(v->type == VALUE_TYPE_JSCRIPT_FUNC, NULL);
|
||||
|
||||
return (fscript_func_call_t*)(v->value.ptr);
|
||||
}
|
||||
|
||||
@ -132,9 +151,38 @@ static ret_t fscript_func_call_destroy(fscript_func_call_t* call) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
typedef struct _fscript_function_def_t {
|
||||
darray_t params;
|
||||
fscript_func_call_t* body;
|
||||
} fscript_function_def_t;
|
||||
|
||||
static fscript_function_def_t* fscript_function_def_create(fscript_func_call_t* body) {
|
||||
fscript_function_def_t* func = TKMEM_ZALLOC(fscript_function_def_t);
|
||||
return_value_if_fail(func != NULL, NULL);
|
||||
func->body = body;
|
||||
darray_init(&(func->params), 3, default_destroy, NULL);
|
||||
return func;
|
||||
}
|
||||
|
||||
static ret_t fscript_function_def_destroy(fscript_function_def_t* func) {
|
||||
return_value_if_fail(func != NULL, RET_BAD_PARAMS);
|
||||
darray_deinit(&(func->params));
|
||||
fscript_func_call_destroy(func->body);
|
||||
memset(func, 0x00, sizeof(fscript_function_def_t));
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static ret_t fscript_function_def_add_param(fscript_function_def_t* func, const char* name) {
|
||||
return_value_if_fail(func != NULL, RET_BAD_PARAMS);
|
||||
return darray_push(&(func->params), tk_strdup(name));
|
||||
}
|
||||
|
||||
typedef enum _token_type_t {
|
||||
TOKEN_ID = 1,
|
||||
TOKEN_VAR,
|
||||
TOKEN_FUNC,
|
||||
TOKEN_RETURN,
|
||||
TOKEN_FUNC_DEF,
|
||||
TOKEN_STR,
|
||||
TOKEN_NUMBER,
|
||||
TOKEN_LPAREN,
|
||||
@ -166,6 +214,7 @@ typedef struct _fscript_parser_t {
|
||||
str_t temp;
|
||||
uint16_t row;
|
||||
uint16_t col;
|
||||
object_t* funcs_def;
|
||||
fscript_func_call_t* first;
|
||||
fscript_parser_error_t* error;
|
||||
} fscript_parser_t;
|
||||
@ -206,6 +255,12 @@ static ret_t fscript_get_var(fscript_t* fscript, const char* name, value_t* valu
|
||||
name += 1;
|
||||
}
|
||||
|
||||
if (fscript->locals != NULL) {
|
||||
if (object_get_prop(fscript->locals, name, value) == RET_OK) {
|
||||
return RET_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_fast_var(name)) {
|
||||
value_t* var = fscript_get_fast_var(fscript, name);
|
||||
if (name[1] == '.') {
|
||||
@ -241,7 +296,12 @@ static ret_t fscript_set_var(fscript_t* fscript, const char* name, const value_t
|
||||
ret = value_deep_copy(var, value);
|
||||
}
|
||||
} else {
|
||||
ret = object_set_prop(fscript->obj, name, value);
|
||||
value_t v;
|
||||
if (fscript->locals != NULL && object_get_prop(fscript->locals, name, &v) == RET_OK) {
|
||||
ret = object_set_prop(fscript->locals, name, value);
|
||||
} else {
|
||||
ret = object_set_prop(fscript->obj, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -256,7 +316,8 @@ static ret_t fscript_eval_arg(fscript_t* fscript, fscript_func_call_t* iter, uin
|
||||
value_set_str(d, NULL);
|
||||
if (s->type == VALUE_TYPE_JSCRIPT_ID) {
|
||||
s->type = VALUE_TYPE_STRING;
|
||||
if ((iter->func == func_set || iter->func == func_unset) && i == 0) {
|
||||
if ((iter->func == func_set_local || iter->func == func_set || iter->func == func_unset) &&
|
||||
i == 0) {
|
||||
value_copy(d, s); /*func_set accept id/str as first param*/
|
||||
} else {
|
||||
const char* name = value_str(s);
|
||||
@ -345,6 +406,8 @@ static ret_t fscript_exec_core_func(fscript_t* fscript, fscript_func_call_t* ite
|
||||
return fscript_exec_if(fscript, iter, result);
|
||||
} else if (iter->func == func_while) {
|
||||
return fscript_exec_while(fscript, iter, result);
|
||||
} else if (iter->func == func_function_def) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
return RET_NOT_FOUND;
|
||||
@ -363,13 +426,14 @@ static ret_t fscript_exec_ext_func(fscript_t* fscript, fscript_func_call_t* iter
|
||||
for (i = 0; i < iter->args.size; i++) {
|
||||
ret = fscript_eval_arg(fscript, iter, i, args.args + i);
|
||||
if (fscript->breaked || fscript->continued || fscript->returned) {
|
||||
value_set_int(result, 0);
|
||||
value_deep_copy(result, args.args + i);
|
||||
func_args_deinit(&args);
|
||||
return RET_OK;
|
||||
}
|
||||
}
|
||||
|
||||
value_set_int(result, 0);
|
||||
fscript->curr = iter;
|
||||
ret = iter->func(fscript, &args, result);
|
||||
func_args_deinit(&args);
|
||||
|
||||
@ -406,11 +470,23 @@ ret_t fscript_exec(fscript_t* fscript, value_t* result) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static ret_t on_free_func_def(void* ctx, const void* data) {
|
||||
named_value_t* iter = (named_value_t*)(data);
|
||||
fscript_function_def_destroy(value_pointer(&(iter->value)));
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
ret_t fscript_destroy(fscript_t* fscript) {
|
||||
uint32_t i = 0;
|
||||
return_value_if_fail(fscript != NULL, RET_FAIL);
|
||||
|
||||
str_reset(&(fscript->str));
|
||||
OBJECT_UNREF(fscript->locals);
|
||||
if (fscript->funcs_def != NULL) {
|
||||
object_foreach_prop(fscript->funcs_def, on_free_func_def, NULL);
|
||||
}
|
||||
OBJECT_UNREF(fscript->funcs_def);
|
||||
TKMEM_FREE(fscript->error_message);
|
||||
fscript_func_call_destroy(fscript->first);
|
||||
for (i = 0; i < ARRAY_SIZE(fscript->fast_vars); i++) {
|
||||
@ -486,7 +562,7 @@ static ret_t fscript_parser_set_error(fscript_parser_t* parser, const char* str)
|
||||
log_warn("token: \"%s\"\n", parser->token.token);
|
||||
log_warn("at line(%u) col (%u): %s\n", parser->row, parser->col, str);
|
||||
|
||||
return RET_OK;
|
||||
return RET_FAIL;
|
||||
}
|
||||
|
||||
static ret_t fscript_parser_skip_seperators(fscript_parser_t* parser) {
|
||||
@ -609,8 +685,8 @@ static ret_t fscript_parser_parse_id_or_number(fscript_parser_t* parser, token_t
|
||||
|
||||
do {
|
||||
c = fscript_parser_get_char(parser);
|
||||
if (tk_isxdigit(c) || tk_isdigit(c) || tk_isalpha(c) || c == '.' || c == '_' || c == '[' || c == ']' ||
|
||||
c == '#') {
|
||||
if (tk_isxdigit(c) || tk_isdigit(c) || tk_isalpha(c) || c == '.' || c == '_' || c == '[' ||
|
||||
c == ']' || c == '#') {
|
||||
str_append_char(str, c);
|
||||
} else {
|
||||
break;
|
||||
@ -628,6 +704,16 @@ static ret_t fscript_parser_parse_id_or_number(fscript_parser_t* parser, token_t
|
||||
fscript_parser_unget_char(parser, c);
|
||||
}
|
||||
|
||||
if (t->type == TOKEN_ID) {
|
||||
if (tk_str_eq(t->token, "function")) {
|
||||
t->type = TOKEN_FUNC_DEF;
|
||||
} else if (tk_str_eq(t->token, "var")) {
|
||||
t->type = TOKEN_VAR;
|
||||
} else if (tk_str_eq(t->token, "return")) {
|
||||
t->type = TOKEN_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
@ -780,8 +866,7 @@ static ret_t fscript_parser_expect_token(fscript_parser_t* parser, token_type_t
|
||||
const char* msg) {
|
||||
token_t* t = fscript_parser_get_token(parser);
|
||||
if (t == NULL || t->type != type) {
|
||||
fscript_parser_set_error(parser, msg);
|
||||
return RET_FAIL;
|
||||
return fscript_parser_set_error(parser, msg);
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
@ -930,8 +1015,7 @@ static ret_t fexpr_parse_function(fscript_parser_t* parser, value_t* result) {
|
||||
do {
|
||||
t = fscript_parser_get_token(parser);
|
||||
if (t == NULL) {
|
||||
fscript_parser_set_error(parser, "expect \")\"");
|
||||
return RET_FAIL;
|
||||
return fscript_parser_set_error(parser, "expect \")\"");
|
||||
}
|
||||
|
||||
if (t->type == TOKEN_RPAREN) {
|
||||
@ -945,8 +1029,7 @@ static ret_t fexpr_parse_function(fscript_parser_t* parser, value_t* result) {
|
||||
t = fscript_parser_get_token(parser);
|
||||
|
||||
if (t == NULL) {
|
||||
fscript_parser_set_error(parser, "expect \")\"");
|
||||
return RET_FAIL;
|
||||
return fscript_parser_set_error(parser, "expect \")\"");
|
||||
} else if (t->type == TOKEN_RPAREN) {
|
||||
break;
|
||||
}
|
||||
@ -978,6 +1061,21 @@ static ret_t fexpr_parse_term(fscript_parser_t* parser, value_t* result) {
|
||||
} else if (t->type == TOKEN_FUNC) {
|
||||
fscript_parser_unget_token(parser);
|
||||
ret = fexpr_parse_function(parser, result);
|
||||
} else if (t->type == TOKEN_RETURN) {
|
||||
fscript_func_call_t* acall = fscript_func_call_create(parser, "return", 6);
|
||||
return_value_if_fail(acall != NULL, RET_OOM);
|
||||
value_set_func(result, acall);
|
||||
t = fscript_parser_get_token(parser);
|
||||
if (t != NULL && t->type != TOKEN_SEMICOLON && t->type != TOKEN_RBRACKET) {
|
||||
value_t v;
|
||||
value_set_int(&v, 0);
|
||||
fscript_parser_unget_token(parser);
|
||||
if (fexpr_parse(parser, &v) == RET_OK) {
|
||||
func_args_push(&(acall->args), &v);
|
||||
}
|
||||
} else {
|
||||
fscript_parser_unget_token(parser);
|
||||
}
|
||||
} else if (t->type == TOKEN_LPAREN) {
|
||||
ret = fexpr_parse(parser, result);
|
||||
return_value_if_fail(ret == RET_OK, ret);
|
||||
@ -1005,8 +1103,7 @@ static ret_t fexpr_parse_unary(fscript_parser_t* parser, value_t* result) {
|
||||
bool_t valid = FALSE;
|
||||
for (i = 0; i < t->size; i++) {
|
||||
if (t->token[i] != c) {
|
||||
fscript_parser_set_error(parser, "unexpected token");
|
||||
return RET_FAIL;
|
||||
return fscript_parser_set_error(parser, "unexpected token");
|
||||
} else {
|
||||
valid = !valid;
|
||||
}
|
||||
@ -1195,15 +1292,23 @@ static ret_t fexpr_parse_question(fscript_parser_t* parser, value_t* result) {
|
||||
static ret_t fexpr_parse(fscript_parser_t* parser, value_t* result) {
|
||||
value_t v;
|
||||
token_t* t = NULL;
|
||||
bool_t is_local = FALSE;
|
||||
fscript_args_t* args = NULL;
|
||||
fscript_func_call_t* acall = NULL;
|
||||
|
||||
value_set_int(result, 0);
|
||||
|
||||
t = fscript_parser_get_token_ex(parser, TRUE);
|
||||
if (t != NULL && t->type == TOKEN_VAR) {
|
||||
is_local = TRUE;
|
||||
} else {
|
||||
fscript_parser_unget_token(parser);
|
||||
}
|
||||
return_value_if_fail(fexpr_parse_question(parser, result) == RET_OK, RET_FAIL);
|
||||
|
||||
t = fscript_parser_get_token_ex(parser, TRUE);
|
||||
if (t != NULL && tk_str_eq(t->token, "=")) {
|
||||
acall = fscript_func_call_create(parser, t->token, t->size);
|
||||
const char* name = is_local ? "set_local" : "=";
|
||||
acall = fscript_func_call_create(parser, name, strlen(name));
|
||||
return_value_if_fail(acall != NULL, RET_OOM);
|
||||
args = &(acall->args);
|
||||
func_args_push(args, result);
|
||||
@ -1223,14 +1328,90 @@ fscript_t* fscript_create_impl(fscript_parser_t* parser) {
|
||||
fscript->str = parser->temp;
|
||||
fscript->obj = parser->obj;
|
||||
fscript->first = parser->first;
|
||||
fscript->funcs_def = parser->funcs_def;
|
||||
|
||||
parser->obj = NULL;
|
||||
parser->first = NULL;
|
||||
parser->temp.str = NULL;
|
||||
parser->funcs_def = NULL;
|
||||
|
||||
return fscript;
|
||||
}
|
||||
|
||||
static ret_t func_function(fscript_t* fscript, fscript_args_t* args, value_t* result) {
|
||||
ret_t ret = RET_OK;
|
||||
object_t* saved_locals = fscript->locals;
|
||||
fscript_function_def_t* func_def = (fscript_function_def_t*)(fscript->curr->ctx);
|
||||
fscript_func_call_t* func = func_def->body;
|
||||
|
||||
func->func = func_noop;
|
||||
fscript->locals = NULL;
|
||||
if (func_def->params.size > 0 && args->size > 0) {
|
||||
uint32_t i = 0;
|
||||
uint32_t n = tk_min(func_def->params.size, args->size);
|
||||
fscript->locals = object_default_create();
|
||||
for (i = 0; i < n; i++) {
|
||||
const value_t* value = args->args + i;
|
||||
const char* name = (const char*)(func_def->params.elms[i]);
|
||||
object_set_prop(fscript->locals, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
ret = fscript_exec_func(fscript, func, result);
|
||||
|
||||
OBJECT_UNREF(fscript->locals);
|
||||
fscript->locals = saved_locals;
|
||||
fscript->returned = FALSE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ret_t fscript_parse_function_def(fscript_parser_t* parser, fscript_func_call_t* acall) {
|
||||
char func_name[TK_NAME_LEN + 1];
|
||||
fscript_function_def_t* func_def = NULL;
|
||||
fscript_func_call_t* statements = NULL;
|
||||
token_t* t = fscript_parser_get_token(parser);
|
||||
|
||||
if (t->type != TOKEN_FUNC) {
|
||||
return fscript_parser_set_error(parser, "expect function name\n");
|
||||
}
|
||||
tk_strncpy(func_name, t->token, TK_NAME_LEN);
|
||||
fscript_parser_expect_token(parser, TOKEN_LPAREN, "expect \"(\"");
|
||||
if (parser->funcs_def == NULL) {
|
||||
parser->funcs_def = object_default_create();
|
||||
}
|
||||
if (object_get_prop_pointer(parser->funcs_def, func_name) != NULL) {
|
||||
return fscript_parser_set_error(parser, "duplicate function\n");
|
||||
}
|
||||
statements = fscript_func_call_create(parser, "func", 4);
|
||||
return_value_if_fail(statements != NULL, RET_OOM);
|
||||
|
||||
func_def = fscript_function_def_create(statements);
|
||||
return_value_if_fail(func_def != NULL, RET_OOM);
|
||||
object_set_prop_pointer(parser->funcs_def, func_name, func_def);
|
||||
|
||||
while (TRUE) {
|
||||
t = fscript_parser_get_token(parser);
|
||||
if (t == NULL || t->type == TOKEN_EOF || t->type == TOKEN_RPAREN) {
|
||||
fscript_parser_unget_token(parser);
|
||||
break;
|
||||
}
|
||||
if (t->type == TOKEN_ID) {
|
||||
fscript_function_def_add_param(func_def, t->token);
|
||||
} else if (t->type == TOKEN_COMMA) {
|
||||
} else {
|
||||
fscript_parser_unget_token(parser);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fscript_parser_expect_token(parser, TOKEN_RPAREN, "expect \")\"");
|
||||
fscript_parser_expect_token(parser, TOKEN_LBRACKET, "expect \"{\"");
|
||||
fscript_parse_statements(parser, statements);
|
||||
fscript_parser_expect_token(parser, TOKEN_RBRACKET, "expect \"}\"");
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static ret_t fscript_parse_statements(fscript_parser_t* parser, fscript_func_call_t* acall) {
|
||||
value_t v;
|
||||
ret_t ret = RET_OK;
|
||||
@ -1251,14 +1432,13 @@ static ret_t fscript_parse_statements(fscript_parser_t* parser, fscript_func_cal
|
||||
}
|
||||
|
||||
if (t->type == TOKEN_FUNC || t->type == TOKEN_ID || t->type == TOKEN_NUMBER ||
|
||||
t->type == TOKEN_STR) {
|
||||
t->type == TOKEN_STR || t->type == TOKEN_VAR || t->type == TOKEN_RETURN) {
|
||||
fscript_parser_unget_token(parser);
|
||||
} else if (t->type == TOKEN_RBRACKET) {
|
||||
} else if (t->type == TOKEN_RBRACKET || t->type == TOKEN_FUNC_DEF) {
|
||||
fscript_parser_unget_token(parser);
|
||||
break;
|
||||
} else if (t->type != TOKEN_COMMA && t->type != TOKEN_SEMICOLON) {
|
||||
fscript_parser_set_error(parser, "unexpected token\n");
|
||||
break;
|
||||
return fscript_parser_set_error(parser, "unexpected token\n");
|
||||
}
|
||||
} else {
|
||||
if (v.type == VALUE_TYPE_JSCRIPT_FUNC) {
|
||||
@ -1274,6 +1454,23 @@ static ret_t fscript_parse_statements(fscript_parser_t* parser, fscript_func_cal
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static ret_t fscript_parse_all(fscript_parser_t* parser, fscript_func_call_t* acall) {
|
||||
ret_t ret = RET_OK;
|
||||
while (ret == RET_OK) {
|
||||
token_t* t = fscript_parser_get_token(parser);
|
||||
if (t && t->type == TOKEN_FUNC_DEF) {
|
||||
ret = fscript_parse_function_def(parser, acall);
|
||||
} else if (t == NULL || t->type == TOKEN_EOF) {
|
||||
break;
|
||||
} else {
|
||||
fscript_parser_unget_token(parser);
|
||||
ret = fscript_parse_statements(parser, acall);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
fscript_parser_error_t* fscript_parser_error_init(fscript_parser_error_t* error) {
|
||||
return_value_if_fail(error != NULL, NULL);
|
||||
memset(error, 0x00, sizeof(fscript_parser_error_t));
|
||||
@ -1313,7 +1510,7 @@ fscript_t* fscript_create(object_t* obj, const char* expr) {
|
||||
fscript_parser_error_init(&error);
|
||||
fscript_parser_init(&parser, obj, expr, &error);
|
||||
parser.first = fscript_func_call_create(&parser, "expr", 4);
|
||||
ret = fscript_parse_statements(&parser, parser.first);
|
||||
ret = fscript_parse_all(&parser, parser.first);
|
||||
if (ret == RET_OK) {
|
||||
fscript = fscript_create_impl(&parser);
|
||||
fscript_parser_deinit(&parser);
|
||||
@ -1532,11 +1729,16 @@ static ret_t func_join(fscript_t* fscript, fscript_args_t* args, value_t* result
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static ret_t func_if(fscript_t* fscript, fscript_args_t* args, value_t* result) {
|
||||
return RET_OK;
|
||||
}
|
||||
static ret_t func_set_local(fscript_t* fscript, fscript_args_t* args, value_t* result) {
|
||||
const char* name = NULL;
|
||||
FSCRIPT_FUNC_CHECK(args->size == 2, RET_BAD_PARAMS);
|
||||
name = value_str(args->args);
|
||||
FSCRIPT_FUNC_CHECK(name != NULL, RET_BAD_PARAMS);
|
||||
if (fscript->locals == NULL) {
|
||||
fscript->locals = object_default_create();
|
||||
}
|
||||
value_set_bool(result, object_set_prop(fscript->locals, name, args->args + 1) == RET_OK);
|
||||
|
||||
static ret_t func_while(fscript_t* fscript, fscript_args_t* args, value_t* result) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
@ -1950,10 +2152,6 @@ static ret_t func_exec(fscript_t* fscript, fscript_args_t* args, value_t* result
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static ret_t func_noop(fscript_t* fscript, fscript_args_t* args, value_t* result) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static ret_t func_unset(fscript_t* fscript, fscript_args_t* args, value_t* result) {
|
||||
value_t* var = NULL;
|
||||
const char* name = NULL;
|
||||
@ -1965,7 +2163,12 @@ static ret_t func_unset(fscript_t* fscript, fscript_args_t* args, value_t* resul
|
||||
if (var != NULL) {
|
||||
value_reset(var);
|
||||
} else {
|
||||
object_remove_prop(fscript->obj, name);
|
||||
value_t v;
|
||||
if (fscript->locals != NULL && object_get_prop(fscript->locals, name, &v) == RET_OK) {
|
||||
object_remove_prop(fscript->locals, name);
|
||||
} else {
|
||||
object_remove_prop(fscript->obj, name);
|
||||
}
|
||||
}
|
||||
value_set_bool(result, TRUE);
|
||||
|
||||
@ -1979,10 +2182,13 @@ typedef struct _func_entry_t {
|
||||
} func_entry_t;
|
||||
|
||||
static const func_entry_t s_builtin_funcs[] = {
|
||||
{"func", func_function_def, 4},
|
||||
{"return", func_return, 1},
|
||||
{"print", func_print, 4},
|
||||
{"expr", func_expr, 4},
|
||||
{"=", func_set, 2},
|
||||
{"set", func_set, 2},
|
||||
{"set_local", func_set_local, 2},
|
||||
{"max", func_max, 2},
|
||||
{"min", func_min, 2},
|
||||
{"==", func_eq, 2},
|
||||
@ -2089,6 +2295,14 @@ static fscript_func_call_t* fscript_func_call_create(fscript_parser_t* parser, c
|
||||
func = (fscript_func_t)object_get_prop_pointer(parser->obj, full_func_name);
|
||||
}
|
||||
|
||||
if (func == NULL) {
|
||||
value_t v;
|
||||
if (object_get_prop(parser->funcs_def, func_name, &v) == RET_OK) {
|
||||
func = func_function;
|
||||
call->ctx = value_pointer(&v);
|
||||
}
|
||||
}
|
||||
|
||||
if (func == NULL) {
|
||||
func = func_noop;
|
||||
log_warn("not found %s\n", func_name);
|
||||
|
@ -146,6 +146,11 @@ typedef struct _fscript_t {
|
||||
bool_t continued;
|
||||
bool_t returned;
|
||||
uint8_t while_count;
|
||||
|
||||
/*函数局部变量和参数*/
|
||||
object_t* locals;
|
||||
/*脚本定义的函数*/
|
||||
object_t* funcs_def;
|
||||
} fscript_t;
|
||||
|
||||
typedef ret_t (*fscript_func_t)(fscript_t* fscript, fscript_args_t* args, value_t* v);
|
||||
|
@ -21,12 +21,16 @@ static ret_t run_fscript(const char* code, uint32_t times) {
|
||||
uint64_t start = time_now_us();
|
||||
object_t* obj = object_default_create();
|
||||
tk_mem_dump();
|
||||
log_debug("======================\n");
|
||||
if (times > 1) {
|
||||
/*stress test*/
|
||||
uint32_t i = 0;
|
||||
fscript_t* fscript = fscript_create(obj, code);
|
||||
for (i = 0; i < times; i++) {
|
||||
log_debug("%u times....\n", i);
|
||||
tk_mem_dump();
|
||||
fscript_exec(fscript, &v);
|
||||
tk_mem_dump();
|
||||
value_reset(&v);
|
||||
}
|
||||
fscript_destroy(fscript);
|
||||
|
34
tests/fscripts/demo_function1.fs
Normal file
34
tests/fscripts/demo_function1.fs
Normal file
@ -0,0 +1,34 @@
|
||||
function add(v1, v2, v3){
|
||||
return (v1+v2+v3);
|
||||
}
|
||||
assert(add(100, 200, 300) == 600)
|
||||
|
||||
function f(n) {
|
||||
if(n == 0) {
|
||||
return (0);
|
||||
} else if(n == 1) {
|
||||
return (1);
|
||||
} else {
|
||||
return (f(n-1) + f(n-2));
|
||||
}
|
||||
}
|
||||
|
||||
assert(f(0) == 0);
|
||||
assert(f(1) == 1);
|
||||
assert(f(2) == 1);
|
||||
assert(f(3) == 2);
|
||||
assert(f(4) == 3);
|
||||
assert(f(5) == 5);
|
||||
assert(f(6) == 8);
|
||||
assert(f(7) == 13);
|
||||
assert(f(8) == 21);
|
||||
|
||||
var cc = 100;
|
||||
function bar(aa, bb) {
|
||||
var cc = aa + bb;
|
||||
return (cc)
|
||||
}
|
||||
assert(bar(100, 200) == 300);
|
||||
assert(cc == 100);
|
||||
|
||||
|
30
tests/fscripts/demo_function2.fs
Normal file
30
tests/fscripts/demo_function2.fs
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
function f1() {
|
||||
var a = 10;
|
||||
var b = 20;
|
||||
var c = a + b;
|
||||
return c;
|
||||
}
|
||||
|
||||
assert(f1() == 30);
|
||||
|
||||
function f2() {
|
||||
var a = 10;
|
||||
var b = 20;
|
||||
return a + b;
|
||||
}
|
||||
assert(f2() == 30);
|
||||
|
||||
function f3() {
|
||||
var a = 10;
|
||||
var b = 20;
|
||||
return (a + b);
|
||||
}
|
||||
assert(f3() == 30);
|
||||
|
||||
function f4() {
|
||||
var a = 10;
|
||||
var b = 20;
|
||||
return 30
|
||||
}
|
||||
assert(f4() == 30);
|
13
tests/fscripts/demo_function3.fs
Normal file
13
tests/fscripts/demo_function3.fs
Normal file
@ -0,0 +1,13 @@
|
||||
function foo4 (v1, v2) {
|
||||
var v3 = v1 + v2;
|
||||
if(v3 < 100) {
|
||||
var name = "awtk";
|
||||
} else {
|
||||
var name = "react-awtk";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
assert(foo4(10, 20) == 'awtk')
|
||||
assert(foo4(100, 200) == 'react-awtk')
|
14
tests/fscripts/demo_local.fs
Normal file
14
tests/fscripts/demo_local.fs
Normal file
@ -0,0 +1,14 @@
|
||||
name = 'tom'
|
||||
assert(name == 'tom')
|
||||
|
||||
var name='jim'
|
||||
assert(name == 'jim')
|
||||
|
||||
unset(name);
|
||||
assert(name == 'tom')
|
||||
|
||||
if(name == 'tom') {
|
||||
var age = 100;
|
||||
}
|
||||
assert(age == 100)
|
||||
|
Loading…
Reference in New Issue
Block a user