├── example ├── scripts │ ├── hello.pd │ └── fib.pd ├── sal.h ├── example.h ├── Makefile ├── foreign.c ├── native.c ├── compile.c ├── sal.c ├── interpreter.c ├── dump.c └── interactive.c ├── doc ├── develGuide.md ├── userGuide.md └── syntax.txt ├── .gitignore ├── cunit ├── Makefile ├── CUnit_Intl.h ├── CUnit_Basic.h ├── CUnit_Mem.h ├── CUnit_Util.h ├── CUnit_Error.c └── CUnit_Error.h ├── test ├── test.h ├── test_util.h ├── test_hello.c ├── test_lang_symtbl.c ├── test_util.c ├── test.c ├── test_lang_image.c ├── test_lang_async.c ├── test_lang_val.c ├── test_lang_lex.c └── test_lang_type_buffer.c ├── lang ├── type_number.h ├── type_boolean.h ├── gc.h ├── type_boolean.c ├── type_number.c ├── ast.c ├── Makefile ├── err.h ├── scope.h ├── type_function.c ├── heap.c ├── interp.h ├── heap.h ├── type_array.h ├── type_string.h ├── compile.h ├── type_function.h ├── types.h ├── types.c ├── type_buffer.h ├── type_object.h ├── parse.h ├── def.h ├── lex.h ├── bcode.h ├── ast.h ├── executable.h ├── type_string.c ├── type_buffer.c ├── env.h ├── gc.c └── bcode.c ├── make ├── lang.mk ├── test.mk ├── example.mk └── Makefile.pub ├── include └── panda.h ├── Makefile └── README.md /example/scripts/hello.pd: -------------------------------------------------------------------------------- 1 | print("hello world"); 2 | -------------------------------------------------------------------------------- /doc/develGuide.md: -------------------------------------------------------------------------------- 1 | = 扩展panda 2 | 3 | = 将panda嵌入自己的应用程序 4 | 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | 4 | *.[oad] 5 | *.so 6 | *.swp 7 | 8 | build/ 9 | -------------------------------------------------------------------------------- /doc/userGuide.md: -------------------------------------------------------------------------------- 1 | = 基本数据类型 2 | 3 | = 表达式运算 4 | 5 | = 函数 6 | 7 | = 数组 8 | 9 | = 对象 10 | 11 | = Buffer对象 12 | 13 | = 闭包 14 | 15 | = 模块 16 | 17 | = 参考 18 | 19 | == 原生函数 20 | 21 | == 原生模块 22 | -------------------------------------------------------------------------------- /cunit/Makefile: -------------------------------------------------------------------------------- 1 | lib_NAMES = cunit 2 | 3 | cunit_SRCS = CUnit_Basic.c \ 4 | CUnit_Error.c \ 5 | CUnit_Mem.c \ 6 | CUnit_TestDB.c \ 7 | CUnit_TestRun.c \ 8 | CUnit_Util.c 9 | 10 | cunit_CPPFLAGS = 11 | cunit_CFLAGS = 12 | cunit_LDFLAGS = 13 | 14 | -------------------------------------------------------------------------------- /example/scripts/fib.pd: -------------------------------------------------------------------------------- 1 | 2 | def f(x) { 3 | var a = 1; 4 | var b = 1; 5 | var c; 6 | 7 | while(b < x) { 8 | c = b; 9 | b = a + b; 10 | a = c; 11 | } 12 | 13 | return b; 14 | } 15 | 16 | 17 | var a = f(1024); 18 | 19 | if (a == 1597) { 20 | print("test 1: ok"); 21 | } else { 22 | print("test 1: fail"); 23 | } 24 | -------------------------------------------------------------------------------- /test/test.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __TEST_INC__ 21 | #define __TEST_INC__ 22 | 23 | 24 | #endif /* __TEST_INC__ */ 25 | 26 | -------------------------------------------------------------------------------- /lang/type_number.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #ifndef __LANG_NUMBER_INC__ 22 | #define __LANG_NUMBER_INC__ 23 | 24 | #include "def.h" 25 | 26 | #include "val.h" 27 | #include "env.h" 28 | 29 | extern const val_metadata_t metadata_num; 30 | 31 | #endif /* __LANG_NUMBER_INC__ */ 32 | 33 | -------------------------------------------------------------------------------- /lang/type_boolean.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __LANG_TYPE_BOOLEAN_INC__ 21 | #define __LANG_TYPE_BOOLEAN_INC__ 22 | 23 | #include "def.h" 24 | 25 | #include "val.h" 26 | #include "env.h" 27 | 28 | extern const val_metadata_t metadata_boolean; 29 | 30 | #endif /* __LANG_TYPE_BOOLEAN_INC__ */ 31 | -------------------------------------------------------------------------------- /lang/gc.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __LANG_GC_INC__ 21 | #define __LANG_GC_INC__ 22 | 23 | #include "scope.h" 24 | 25 | void gc_scan(void *env); 26 | 27 | void gc_types_copy(void *env, int n, val_t *p); 28 | scope_t *gc_scope_copy(void *env, scope_t *scope); 29 | 30 | #endif /* __LANG_GC_INC__ */ 31 | 32 | -------------------------------------------------------------------------------- /test/test_util.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __TEST_UTIL_INC__ 21 | #define __TEST_UTIL_INC__ 22 | 23 | #include "lang/ast.h" 24 | 25 | void test_clr_line(void); 26 | void test_set_line(const char *line); 27 | int test_get_line(void *buf, int size); 28 | 29 | char * expr_stringify_after_older(expr_t *e, int size, char *buf); 30 | 31 | #endif /* __TEST_UTIL_INC__ */ 32 | 33 | -------------------------------------------------------------------------------- /lang/type_boolean.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include "type_boolean.h" 21 | 22 | static int boolean_is_true(val_t *self) 23 | { 24 | return val_2_intptr(self); 25 | } 26 | 27 | const val_metadata_t metadata_boolean = { 28 | .name = "boolean", 29 | 30 | .is_true = boolean_is_true, 31 | .is_equal = val_op_false, 32 | 33 | .value_of = val_as_integer, 34 | }; 35 | 36 | 37 | -------------------------------------------------------------------------------- /example/sal.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #ifndef __SAL_INC__ 22 | #define __SAL_INC__ 23 | 24 | #include "config.h" 25 | 26 | int output(const char *s); 27 | 28 | void *file_load(const char *name, int *size); 29 | int file_release(void *map, int sz); 30 | int file_store(const char *name, void *data, int len); 31 | int file_base_name(const char *name, void *buf, int sz); 32 | 33 | #endif /* __SAL_INC__ */ 34 | 35 | -------------------------------------------------------------------------------- /lang/type_number.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include "val.h" 21 | #include "type_string.h" 22 | #include "type_number.h" 23 | 24 | static int number_is_true(val_t *self) { 25 | return val_2_double(self) != 0; 26 | } 27 | 28 | const val_metadata_t metadata_num = { 29 | .name = "number", 30 | 31 | .is_true = number_is_true, 32 | .is_equal = val_op_false, 33 | 34 | .value_of = val_as_number, 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /lang/ast.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include "ast.h" 21 | 22 | void ast_traveral_expr(expr_t *e, void (*cb)(void *, expr_t *), void *ud) 23 | { 24 | if (e) { 25 | if (e->type > EXPR_STRING) { 26 | ast_traveral_expr(e->body.child.lft, cb, ud); 27 | } 28 | 29 | if (e->type > EXPR_DICT) { 30 | ast_traveral_expr(e->body.child.rht, cb, ud); 31 | } 32 | 33 | cb(ud, e); 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /lang/Makefile: -------------------------------------------------------------------------------- 1 | ## GPLv2 License 2 | ## 3 | ## Copyright (C) 2016-2018 Lixing Ding 4 | ## 5 | ## This program is free software; you can redistribute it and/or 6 | ## modify it under the terms of the GNU General Public License 7 | ## as published by the Free Software Foundation; either version 2 8 | ## of the License, or (at your option) any later version. 9 | ## 10 | ## This program is distributed in the hope that it will be useful, 11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ## GNU General Public License for more details. 14 | ## 15 | ## You should have received a copy of the GNU General Public License 16 | ## along with this program; if not, write to the Free Software 17 | ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | 19 | lib_NAMES = lang 20 | 21 | lang_SRCS = heap.c \ 22 | ast.c \ 23 | env.c\ 24 | gc.c \ 25 | lex.c \ 26 | val.c \ 27 | parse.c \ 28 | bcode.c \ 29 | compile.c\ 30 | executable.c \ 31 | interp.c \ 32 | types.c \ 33 | type_number.c \ 34 | type_boolean.c \ 35 | type_function.c \ 36 | type_array.c \ 37 | type_string.c \ 38 | type_buffer.c \ 39 | type_object.c \ 40 | 41 | lang_CPPFLAGS = -I.. -Wall -Werror 42 | lang_CFLAGS = -g 43 | lang_LDFLAGS = 44 | -------------------------------------------------------------------------------- /example/example.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #ifndef __EXAMPLE_INC__ 22 | #define __EXAMPLE_INC__ 23 | 24 | #include "lang/bcode.h" 25 | #include "lang/interp.h" 26 | #include "lang/compile.h" 27 | #include "lang/err.h" 28 | 29 | int output(const char *s); 30 | 31 | void *file_load(const char *name, int *size); 32 | int file_release(void *map, int sz); 33 | int file_store(const char *name, void *data, int len); 34 | int file_base_name(const char *name, void *buf, int sz); 35 | 36 | int native_init(env_t *env); 37 | 38 | #endif /* __EXAMPLE_INC__ */ 39 | 40 | -------------------------------------------------------------------------------- /make/lang.mk: -------------------------------------------------------------------------------- 1 | ## GPLv2 License 2 | ## 3 | ## Copyright (C) 2016-2018 Lixing Ding 4 | ## 5 | ## This program is free software; you can redistribute it and/or 6 | ## modify it under the terms of the GNU General Public License 7 | ## as published by the Free Software Foundation; either version 2 8 | ## of the License, or (at your option) any later version. 9 | ## 10 | ## This program is distributed in the hope that it will be useful, 11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ## GNU General Public License for more details. 14 | ## 15 | ## You should have received a copy of the GNU General Public License 16 | ## along with this program; if not, write to the Free Software 17 | ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | 19 | lib_NAMES = lang 20 | 21 | lang_SRCS = heap.c \ 22 | ast.c \ 23 | env.c\ 24 | gc.c \ 25 | lex.c \ 26 | val.c \ 27 | parse.c \ 28 | bcode.c \ 29 | compile.c\ 30 | executable.c \ 31 | interp.c \ 32 | types.c \ 33 | type_number.c \ 34 | type_boolean.c \ 35 | type_function.c \ 36 | type_array.c \ 37 | type_string.c \ 38 | type_buffer.c \ 39 | type_object.c \ 40 | 41 | lang_CPPFLAGS = -I.. -Wall -Wundef 42 | lang_CFLAGS = -g -Werror 43 | lang_LDFLAGS = 44 | 45 | VPATH = ${BASE}/lang 46 | 47 | include ${BASE}/make/Makefile.pub 48 | 49 | -------------------------------------------------------------------------------- /test/test_hello.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include 21 | #include 22 | 23 | #include "cunit/CUnit.h" 24 | #include "cunit/CUnit_Basic.h" 25 | 26 | 27 | static int test_setup() 28 | { 29 | return 0; 30 | } 31 | 32 | static int test_clean() 33 | { 34 | return 0; 35 | } 36 | 37 | static void test_hello(void) 38 | { 39 | CU_ASSERT(1); 40 | } 41 | 42 | CU_pSuite test_hello_entry() 43 | { 44 | CU_pSuite suite = CU_add_suite("hello", test_setup, test_clean); 45 | 46 | if (suite) { 47 | CU_add_test(suite, "hello", test_hello); 48 | } 49 | 50 | return suite; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /test/test_lang_symtbl.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include 21 | #include 22 | 23 | #include "cunit/CUnit.h" 24 | #include "cunit/CUnit_Basic.h" 25 | 26 | static int test_setup() 27 | { 28 | return 0; 29 | } 30 | 31 | static int test_clean() 32 | { 33 | return 0; 34 | } 35 | 36 | static void test_symtbl_common(void) 37 | { 38 | } 39 | 40 | CU_pSuite test_lang_symtbl_entry() 41 | { 42 | CU_pSuite suite = CU_add_suite("lang symtbl", test_setup, test_clean); 43 | 44 | if (suite) { 45 | CU_add_test(suite, "symtbl common", test_symtbl_common); 46 | } 47 | 48 | return suite; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /include/panda.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __PANDA_INC__ 21 | #define __PANDA_INC__ 22 | 23 | #include "../lang/def.h" 24 | #include "../lang/err.h" 25 | #include "../lang/val.h" 26 | #include "../lang/env.h" 27 | #include "../lang/types.h" 28 | #include "../lang/compile.h" 29 | #include "../lang/interp.h" 30 | #include "../lang/executable.h" 31 | #include "../lang/type_boolean.h" 32 | #include "../lang/type_number.h" 33 | #include "../lang/type_string.h" 34 | #include "../lang/type_array.h" 35 | #include "../lang/type_object.h" 36 | #include "../lang/type_buffer.h" 37 | #include "../lang/type_function.h" 38 | 39 | #endif /* __PANDA_INC__ */ 40 | 41 | -------------------------------------------------------------------------------- /lang/err.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __LANG_ERR_INC__ 21 | #define __LANG_ERR_INC__ 22 | 23 | #define ERR_InvalidToken 1 24 | #define ERR_InvalidSyntax 2 25 | #define ERR_InvalidLeftValue 3 26 | #define ERR_InvalidSementic 4 27 | 28 | #define ERR_NotEnoughMemory 5 29 | #define ERR_NotImplemented 6 30 | #define ERR_StackOverflow 7 31 | #define ERR_ResourceOutLimit 8 32 | 33 | #define ERR_InvalidByteCode 9 34 | #define ERR_InvalidInput 10 35 | #define ERR_InvalidCallor 11 36 | #define ERR_NotDefinedId 12 37 | 38 | #define ERR_SysError 255 39 | 40 | #endif /* __LANG_ERR_INC__ */ 41 | 42 | -------------------------------------------------------------------------------- /lang/scope.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __LANG_SCOPE_INC__ 21 | #define __LANG_SCOPE_INC__ 22 | 23 | #define MAGIC_SCOPE (MAGIC_BASE + 1) 24 | 25 | #define SCOPE_FL_HEAP (1) // variable space alloced in heap 26 | 27 | typedef struct scope_t { 28 | uint8_t magic; 29 | uint8_t age; 30 | uint8_t num; // all variables number 31 | uint8_t nao; // nonamed arguments offset 32 | val_t *var_buf; 33 | struct scope_t *super; 34 | } scope_t; 35 | 36 | static inline int scope_mem_space(scope_t *scope) { 37 | return SIZE_ALIGN(sizeof(scope_t)) + SIZE_ALIGN(sizeof(val_t) * scope->num); 38 | } 39 | 40 | #endif /* __LANG_SCOPE_INC__ */ 41 | 42 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | ## GPLv2 License 2 | ## 3 | ## Copyright (C) 2016-2018 Lixing Ding 4 | ## 5 | ## This program is free software; you can redistribute it and/or 6 | ## modify it under the terms of the GNU General Public License 7 | ## as published by the Free Software Foundation; either version 2 8 | ## of the License, or (at your option) any later version. 9 | ## 10 | ## This program is distributed in the hope that it will be useful, 11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ## GNU General Public License for more details. 14 | ## 15 | ## You should have received a copy of the GNU General Public License 16 | ## along with this program; if not, write to the Free Software 17 | ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | 19 | lib_NAMES = example 20 | bin_NAMES = compile dump repl panda 21 | 22 | example_SRCS = sal.c native.c 23 | example_CPPFLAGS = -I.. -Wall -Werror 24 | example_CFLAGS = -g 25 | 26 | compile_SRCS = compile.c 27 | compile_CPPFLAGS = -I.. 28 | compile_CFLAGS = -g 29 | compile_LDFLAGS = -L. -L../lang -lexample -llang 30 | 31 | dump_SRCS = dump.c 32 | dump_CPPFLAGS = -I.. 33 | dump_CFLAGS = -g 34 | dump_LDFLAGS = -L. -L../lang -lexample -llang 35 | 36 | repl_SRCS = interactive.c 37 | repl_CPPFLAGS = -I.. 38 | repl_CFLAGS = -g 39 | repl_LDFLAGS = -L. -L../lang -lexample -llang -lreadline 40 | 41 | panda_SRCS = interpreter.c 42 | panda_CPPFLAGS = -I.. 43 | panda_CFLAGS = -g 44 | panda_LDFLAGS = -L. -L../lang -lexample -llang 45 | 46 | -------------------------------------------------------------------------------- /make/test.mk: -------------------------------------------------------------------------------- 1 | ## GPLv2 License 2 | ## 3 | ## Copyright (C) 2016-2018 Lixing Ding 4 | ## 5 | ## This program is free software; you can redistribute it and/or 6 | ## modify it under the terms of the GNU General Public License 7 | ## as published by the Free Software Foundation; either version 2 8 | ## of the License, or (at your option) any later version. 9 | ## 10 | ## This program is distributed in the hope that it will be useful, 11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ## GNU General Public License for more details. 14 | ## 15 | ## You should have received a copy of the GNU General Public License 16 | ## along with this program; if not, write to the Free Software 17 | ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | 19 | lib_NAMES = cunit 20 | bin_NAMES = test 21 | 22 | cunit_SRCS = CUnit_Basic.c \ 23 | CUnit_Error.c \ 24 | CUnit_Mem.c \ 25 | CUnit_TestDB.c \ 26 | CUnit_TestRun.c \ 27 | CUnit_Util.c 28 | cunit_CPPFLAGS = 29 | cunit_CFLAGS = 30 | cunit_LDFLAGS = 31 | 32 | test_SRCS = test.c \ 33 | test_util.c \ 34 | test_hello.c \ 35 | test_lang_lex.c \ 36 | test_lang_val.c \ 37 | test_lang_parse.c \ 38 | test_lang_symtbl.c \ 39 | test_lang_exec.c \ 40 | test_lang_image.c \ 41 | test_lang_async.c \ 42 | test_lang_foreign.c 43 | 44 | test_CPPFLAGS = -I${BASE} 45 | test_CFLAGS = 46 | test_LDFLAGS = -L${BASE}/build/lang -L. -llang -lcunit 47 | 48 | VPATH = ${BASE}/cunit:${BASE}/test 49 | 50 | include ${BASE}/make/Makefile.pub 51 | 52 | -------------------------------------------------------------------------------- /lang/type_function.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include "type_function.h" 21 | 22 | intptr_t function_create(env_t *env, uint8_t *entry) 23 | { 24 | function_t *fn = (function_t *) env_heap_alloc(env, sizeof(function_t)); 25 | 26 | if (fn) { 27 | fn->magic = MAGIC_FUNCTION; 28 | fn->age = 0; 29 | fn->entry = entry; 30 | fn->super = env->scope; 31 | } 32 | return (intptr_t) fn; 33 | } 34 | 35 | int function_destroy(intptr_t fn) 36 | { 37 | (void) fn; 38 | return 0; 39 | } 40 | 41 | const val_metadata_t metadata_function = { 42 | .is_true = val_as_true, 43 | .is_equal = val_op_false, 44 | 45 | .value_of = val_as_nan, 46 | }; 47 | 48 | const val_metadata_t metadata_function_native = { 49 | .name = "function", 50 | 51 | .is_true = val_as_true, 52 | .is_equal = val_op_false, 53 | 54 | .value_of = val_as_nan, 55 | }; 56 | 57 | -------------------------------------------------------------------------------- /make/example.mk: -------------------------------------------------------------------------------- 1 | ## GPLv2 License 2 | ## 3 | ## Copyright (C) 2016-2018 Lixing Ding 4 | ## 5 | ## This program is free software; you can redistribute it and/or 6 | ## modify it under the terms of the GNU General Public License 7 | ## as published by the Free Software Foundation; either version 2 8 | ## of the License, or (at your option) any later version. 9 | ## 10 | ## This program is distributed in the hope that it will be useful, 11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ## GNU General Public License for more details. 14 | ## 15 | ## You should have received a copy of the GNU General Public License 16 | ## along with this program; if not, write to the Free Software 17 | ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | 19 | lib_NAMES = example 20 | bin_NAMES = compile dump repl panda 21 | 22 | example_SRCS = sal.c native.c foreign.c 23 | example_CPPFLAGS = -I${BASE} -Wall -Werror 24 | example_CFLAGS = -g 25 | 26 | compile_SRCS = compile.c 27 | compile_CPPFLAGS = -I${BASE} 28 | compile_CFLAGS = -g 29 | compile_LDFLAGS = -L. -L${BASE}/build/lang -lexample -llang 30 | 31 | dump_SRCS = dump.c 32 | dump_CPPFLAGS = -I${BASE} 33 | dump_CFLAGS = -g 34 | dump_LDFLAGS = -L. -L${BASE}/build/lang -lexample -llang 35 | 36 | repl_SRCS = interactive.c 37 | repl_CPPFLAGS = -I${BASE} 38 | repl_CFLAGS = -g 39 | repl_LDFLAGS = -L. -L${BASE}/build/lang -lexample -llang -lreadline 40 | 41 | panda_SRCS = interpreter.c 42 | panda_CPPFLAGS = -I${BASE} 43 | panda_CFLAGS = -g 44 | panda_LDFLAGS = -L. -L${BASE}/build/lang -lexample -llang 45 | 46 | VPATH = ${BASE}/example 47 | 48 | include ${BASE}/make/Makefile.pub 49 | -------------------------------------------------------------------------------- /lang/heap.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #include "heap.h" 22 | 23 | void heap_init(heap_t *heap, void *base, int size) 24 | { 25 | if (heap && base && size) { 26 | heap->size = size; 27 | heap->free = 0; 28 | heap->base = base; 29 | //memset(base, 0, size); 30 | } 31 | } 32 | 33 | void heap_clean(heap_t *heap) 34 | { 35 | if (heap) { 36 | heap->free = 0; 37 | memset(heap->base, 0, heap->size); 38 | } 39 | } 40 | 41 | void *heap_alloc(heap_t *heap, int size) { 42 | if (heap) { 43 | int free; 44 | 45 | size = SIZE_ALIGN(size); 46 | free = heap->free + size; 47 | //printf("Alloc %d, size: %u, free: %u\n", size, heap->size, heap->free); 48 | if (free <= heap->size) { 49 | void *p = heap->base + heap->free; 50 | heap->free = free; 51 | return p; 52 | } 53 | } 54 | return NULL; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ## GPLv2 License 2 | ## 3 | ## Copyright (C) 2016-2018 Lixing Ding 4 | ## 5 | ## This program is free software; you can redistribute it and/or 6 | ## modify it under the terms of the GNU General Public License 7 | ## as published by the Free Software Foundation; either version 2 8 | ## of the License, or (at your option) any later version. 9 | ## 10 | ## This program is distributed in the hope that it will be useful, 11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ## GNU General Public License for more details. 14 | ## 15 | ## You should have received a copy of the GNU General Public License 16 | ## along with this program; if not, write to the Free Software 17 | ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | 19 | export BASE = ${PWD} 20 | export PREFIX 21 | 22 | MAKE_DIR = ${BASE}/make 23 | 24 | LANG_BUILD_DIR = ${BASE}/build/lang 25 | TEST_BUILD_DIR = ${BASE}/build/test 26 | EXAMPLE_BUILD_DIR = ${BASE}/build/example 27 | 28 | 29 | .PHONY: all test cunit lang example build pre_lang pre_test pre_example 30 | 31 | all: lang 32 | 33 | pre_lang: 34 | @mkdir -p ${LANG_BUILD_DIR} 35 | 36 | pre_test: 37 | @mkdir -p ${TEST_BUILD_DIR} 38 | 39 | pre_example: 40 | @mkdir -p ${EXAMPLE_BUILD_DIR} 41 | 42 | lang: pre_lang 43 | @printf "[Build] lang\n" 44 | @${MAKE} -C ${LANG_BUILD_DIR} -f ${MAKE_DIR}/lang.mk 45 | 46 | test: lang pre_test 47 | @printf "[Build] test\n" 48 | @${RM} ${TEST_BUILD_DIR}/test 49 | @${MAKE} -C ${TEST_BUILD_DIR} -f ${MAKE_DIR}/test.mk 50 | @${TEST_BUILD_DIR}/test 51 | 52 | example: lang pre_example 53 | @printf "[Build] example\n" 54 | @${MAKE} -C ${EXAMPLE_BUILD_DIR} -f ${MAKE_DIR}/example.mk 55 | 56 | clean: 57 | @${RM} -rf build 58 | 59 | -------------------------------------------------------------------------------- /lang/interp.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __LANG_INTERP_INC__ 21 | #define __LANG_INTERP_INC__ 22 | 23 | #include "def.h" 24 | 25 | #include "val.h" 26 | #include "env.h" 27 | #include "executable.h" 28 | 29 | int interp_env_init_interactive(env_t *env, void *mem_ptr, int mem_size, void *heap_ptr, int heap_size, val_t *stack_ptr, int stack_size); 30 | int interp_env_init_interpreter(env_t *env, void *mem_ptr, int mem_size, void *heap_ptr, int heap_size, val_t *stack_ptr, int stack_size); 31 | int interp_env_init_image(env_t *env, void *mem_ptr, int mem_size, void *heap_ptr, int heap_size, val_t *stack_ptr, int stack_size, image_info_t *image); 32 | 33 | int interp_execute_interactive(env_t *env, const char *input, char *(*input_more)(void), val_t **v); 34 | int interp_execute_string(env_t *env, const char *input, val_t **result); 35 | int interp_execute_image(env_t *env, val_t **result); 36 | 37 | val_t interp_execute_call(env_t *env, int ac); 38 | 39 | 40 | int interp_execute_stmts(env_t *env, const char *input, val_t **v); 41 | 42 | #endif /* __LANG_INTERP_INC__ */ 43 | 44 | -------------------------------------------------------------------------------- /lang/heap.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | 22 | #ifndef __LANG_HEAP_INC__ 23 | #define __LANG_HEAP_INC__ 24 | 25 | #include "def.h" 26 | 27 | typedef struct heap_t { 28 | int size; 29 | int free; 30 | void *base; 31 | } heap_t; 32 | 33 | void heap_init(heap_t *heap, void *base, int size); 34 | void heap_clean(heap_t *heap); 35 | 36 | void *heap_alloc(heap_t *heap, int size); 37 | 38 | static inline 39 | int heap_is_owned(heap_t *heap, void *p) { 40 | int dis = p - heap->base; 41 | return dis >= 0 && dis < heap->size; 42 | } 43 | 44 | static inline 45 | void heap_reset(heap_t *heap) { 46 | heap->free = 0; 47 | } 48 | 49 | static inline 50 | void heap_copy(heap_t *dst, heap_t *src) { 51 | dst->base = src->base; 52 | dst->size = src->size; 53 | dst->free = src->free; 54 | } 55 | 56 | static inline 57 | int heap_free_size(heap_t *heap) { 58 | return heap->size - heap->free; 59 | } 60 | 61 | static inline 62 | void *heap_free_addr(heap_t *heap) { 63 | return heap->base + heap->free; 64 | } 65 | 66 | 67 | #endif /* __LANG_HEAP_INC__ */ 68 | 69 | -------------------------------------------------------------------------------- /test/test_util.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include 21 | #include 22 | 23 | #include "test_util.h" 24 | 25 | static const char *lines[256]; 26 | static int max = 0; 27 | static int cur = 0; 28 | static int start = 0; 29 | 30 | void test_clr_line(void) 31 | { 32 | max = 0; 33 | cur = 0; 34 | start = 0; 35 | } 36 | 37 | void test_set_line(const char *line) 38 | { 39 | if (max < 256) { 40 | lines[max++] = line; 41 | } 42 | } 43 | 44 | int test_get_line(void *buf, int size) 45 | { 46 | const char *line_cur = lines[cur]; 47 | int end, lft; 48 | 49 | if (cur >= max) { 50 | return 0; 51 | } 52 | 53 | end = strlen(line_cur); 54 | lft = end - start; 55 | if (lft > size) { 56 | memcpy(buf, line_cur + start, size); 57 | start += size; 58 | return size; 59 | } else { 60 | memcpy(buf, line_cur + start, lft); 61 | start = 0; 62 | cur++; 63 | 64 | return lft; 65 | } 66 | } 67 | 68 | struct sbuf_t { 69 | int pos, end; 70 | char *buf; 71 | }; 72 | 73 | -------------------------------------------------------------------------------- /test/test.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include "cunit/CUnit.h" 21 | #include "cunit/CUnit_Basic.h" 22 | 23 | CU_pSuite test_hello_entry(); 24 | 25 | CU_pSuite test_lang_lex_entry(); 26 | CU_pSuite test_lang_val_entry(); 27 | CU_pSuite test_lang_parse_entry(); 28 | CU_pSuite test_lang_symtbl_entry(); 29 | CU_pSuite test_lang_interp_entry(); 30 | CU_pSuite test_lang_image_entry(); 31 | CU_pSuite test_lang_async_entry(); 32 | 33 | CU_pSuite test_lang_type_foreign(); 34 | 35 | int main(int argc, const char *argv[]) 36 | { 37 | if (CUE_SUCCESS != CU_initialize_registry()) { 38 | return CU_get_error(); 39 | } 40 | 41 | // Set test suite here: 42 | test_hello_entry(); 43 | test_lang_lex_entry(); 44 | test_lang_val_entry(); 45 | test_lang_parse_entry(); 46 | test_lang_symtbl_entry(); 47 | test_lang_interp_entry(); 48 | test_lang_image_entry(); 49 | test_lang_async_entry(); 50 | 51 | test_lang_type_foreign(); 52 | 53 | CU_basic_set_mode(CU_BRM_VERBOSE); 54 | CU_basic_run_tests(); 55 | CU_cleanup_registry(); 56 | 57 | return CU_get_error(); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /cunit/CUnit_Intl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CUnit - A Unit testing framework library for C. 3 | * Copyright (C) 2006 Jerry St.Clair 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | */ 19 | 20 | /* 21 | * Internationalization support 22 | * 23 | * 05-May-2006 Initial implementation. (JDS) 24 | */ 25 | 26 | /** @file 27 | * Internal CUnit header supporting internationalization of 28 | * CUnit framework & interfaces. 29 | */ 30 | /** @addtogroup Framework 31 | * @{ 32 | */ 33 | 34 | #ifndef CUNIT_CUNIT_INTL_H_SEEN 35 | #define CUNIT_CUNIT_INTL_H_SEEN 36 | 37 | /* activate these when source preparation is complete 38 | #include 39 | #ifndef _ 40 | # define _(String) gettext (String) 41 | #endif 42 | #ifndef gettext_noop 43 | # define gettext_noop(String) String 44 | #endif 45 | #ifndef N_ 46 | # define N_(String) gettext_noop (String) 47 | #endif 48 | */ 49 | 50 | /* deactivate these when source preparation is complete */ 51 | #undef _ 52 | #define _(String) (String) 53 | #undef N_ 54 | #define N_(String) String 55 | #undef textdomain 56 | #define textdomain(Domain) 57 | #undef bindtextdomain 58 | #define bindtextdomain(Package, Directory) 59 | 60 | #endif /* CUNIT_CUNIT_INTL_H_SEEN */ 61 | 62 | /** @} */ 63 | -------------------------------------------------------------------------------- /lang/type_array.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #ifndef __LANG_ARRAY_INC__ 22 | #define __LANG_ARRAY_INC__ 23 | 24 | #include "def.h" 25 | #include "val.h" 26 | #include "env.h" 27 | 28 | #define MAGIC_ARRAY (MAGIC_BASE + 11) 29 | 30 | typedef struct array_t { 31 | uint8_t magic; 32 | uint8_t age; 33 | uint16_t elem_size; 34 | uint16_t elem_bgn; 35 | uint16_t elem_end; 36 | val_t *elems; 37 | } array_t; 38 | 39 | static inline array_t *array_entry(val_t *v) { 40 | return val_is_array(v) ? (array_t *)val_2_intptr(v) : NULL; 41 | } 42 | 43 | static inline int array_mem_space(array_t *a) { 44 | return SIZE_ALIGN(sizeof(array_t) + sizeof(val_t) * a->elem_size); 45 | } 46 | 47 | static inline val_t *array_values(array_t *a) { 48 | return a->elems + a->elem_bgn; 49 | } 50 | 51 | static inline int array_length(array_t *a) { 52 | return a->elem_end - a->elem_bgn; 53 | } 54 | 55 | static inline val_t *array_get(array_t *a, int i) 56 | { 57 | return (a->elem_bgn + i < a->elem_end) ? (a->elems + i) : NULL; 58 | } 59 | 60 | array_t *array_alloc_u8(env_t *env, int len, uint8_t *data); 61 | 62 | array_t *_array_create(env_t *env, int len); 63 | val_t *array_elem(array_t *a, int i); 64 | 65 | extern const val_metadata_t metadata_array; 66 | void array_proto_init(env_t *env); 67 | intptr_t array_create(env_t *env, int ac, val_t *av); 68 | 69 | #endif /* __LANG_ARRAY_INC__ */ 70 | 71 | -------------------------------------------------------------------------------- /example/foreign.c: -------------------------------------------------------------------------------- 1 | #include "example.h" 2 | 3 | val_t foreign_set(void *env, val_t *self, val_t *val) 4 | { 5 | (void) env; 6 | (void) self; 7 | 8 | return *val; 9 | } 10 | 11 | void foreign_keep(intptr_t entry) 12 | { 13 | (void) entry; 14 | } 15 | 16 | int foreign_is_true(val_t *self) 17 | { 18 | (void) self; 19 | return 0; 20 | } 21 | 22 | int foreign_is_equal(val_t *self, val_t *other) 23 | { 24 | (void) self; 25 | (void) other; 26 | return 0; 27 | } 28 | 29 | double foreign_value_of(val_t *self) 30 | { 31 | (void) self; 32 | return 0; 33 | } 34 | 35 | val_t foreign_get_prop(void *env, val_t *self, const char *key) 36 | { 37 | (void) env; 38 | (void) self; 39 | (void) key; 40 | return VAL_UNDEFINED; 41 | } 42 | 43 | val_t foreign_get_elem(void *env, val_t *self, int id) 44 | { 45 | (void) env; 46 | (void) self; 47 | (void) id; 48 | return VAL_UNDEFINED; 49 | } 50 | 51 | void foreign_set_prop(void *env, val_t *self, const char *key, val_t *data) 52 | { 53 | (void) env; 54 | (void) self; 55 | (void) key; 56 | (void) data; 57 | } 58 | 59 | void foreign_set_elem(void *env, val_t *self, int id, val_t *data) 60 | { 61 | (void) env; 62 | (void) self; 63 | (void) id; 64 | (void) data; 65 | } 66 | 67 | void foreign_opx_prop(void *env, val_t *self, const char *key, val_t *res, val_opx_t op) 68 | { 69 | (void) env; 70 | (void) self; 71 | (void) key; 72 | (void) res; 73 | (void) op; 74 | } 75 | 76 | void foreign_opx_elem(void *env, val_t *self, int id, val_t *res, val_opx_t op) 77 | { 78 | (void) env; 79 | (void) self; 80 | (void) id; 81 | (void) res; 82 | (void) op; 83 | } 84 | 85 | void foreign_opxx_prop(void *env, val_t *self, const char *key, val_t *data, val_t *res, val_opxx_t op) 86 | { 87 | (void) env; 88 | (void) self; 89 | (void) key; 90 | (void) data; 91 | (void) res; 92 | (void) op; 93 | } 94 | 95 | void foreign_opxx_elem(void *env, val_t *self, int id, val_t *data, val_t *res, val_opxx_t op) 96 | { 97 | (void) env; 98 | (void) self; 99 | (void) id; 100 | (void) data; 101 | (void) res; 102 | (void) op; 103 | } 104 | 105 | -------------------------------------------------------------------------------- /example/native.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #include "example.h" 22 | 23 | static void print_value(val_t *v) 24 | { 25 | if (val_is_number(v)) { 26 | char buf[32]; 27 | if (*v & 0xffff) { 28 | snprintf(buf, 32, "%f", val_2_double(v)); 29 | } else { 30 | snprintf(buf, 32, "%d", (int)val_2_double(v)); 31 | } 32 | output(buf); 33 | } else 34 | if (val_is_boolean(v)) { 35 | output(val_2_intptr(v) ? "true" : "false"); 36 | } else 37 | if (val_is_string(v)) { 38 | output("\""); 39 | output(val_2_cstring(v)); 40 | output("\""); 41 | } else 42 | if (val_is_undefined(v)) { 43 | output("undefined"); 44 | } else 45 | if (val_is_nan(v)) { 46 | output("NaN"); 47 | } else 48 | if (val_is_function(v)) { 49 | char buf[32]; 50 | snprintf(buf, 32, "function:%ld", val_2_intptr(v)); 51 | output(buf); 52 | } else { 53 | output("object"); 54 | } 55 | } 56 | 57 | static val_t print(env_t *env, int ac, val_t *av) 58 | { 59 | int i; 60 | 61 | for (i = 0; i < ac; i++) { 62 | if (i > 0) { 63 | output(" "); 64 | } 65 | print_value(av+i); 66 | } 67 | output("\n"); 68 | 69 | return val_mk_undefined(); 70 | } 71 | 72 | static native_t native_entry[] = { 73 | {"print", print} 74 | }; 75 | 76 | int native_init(env_t *env) 77 | { 78 | return env_native_set(env, native_entry, 1); 79 | } 80 | 81 | -------------------------------------------------------------------------------- /lang/type_string.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __LANG_STRING_INC__ 21 | #define __LANG_STRING_INC__ 22 | 23 | #include "def.h" 24 | 25 | #include "val.h" 26 | #include "env.h" 27 | 28 | 29 | #define MAGIC_STRING (MAGIC_BASE + 3) 30 | 31 | typedef struct string_t { 32 | uint8_t magic; 33 | uint8_t age; 34 | 35 | uint16_t size; 36 | char str[0]; 37 | } string_t; 38 | 39 | static inline int string_mem_space(intptr_t p) { 40 | string_t *s = (string_t *) p; 41 | 42 | return SIZE_ALIGN(sizeof(string_t) + s->size); 43 | } 44 | 45 | static inline intptr_t string_mem_ptr(intptr_t s) { 46 | return s + sizeof(string_t); 47 | } 48 | 49 | static inline int string_len(val_t *v) { 50 | if (val_is_inline_string(v)) { 51 | return 1; 52 | } else 53 | if (val_is_foreign_string(v)) { 54 | return strlen((void*)val_2_intptr(v)); 55 | } else 56 | if (val_is_heap_string(v)) { 57 | string_t *s = (string_t *) val_2_intptr(v); 58 | return strlen(s->str); 59 | } else { 60 | return -1; 61 | } 62 | } 63 | 64 | val_t string_create_heap_val(env_t *env, const char *data); 65 | 66 | int string_compare(val_t *a, val_t *b); 67 | 68 | void string_add(env_t *env, val_t *a, val_t *b, val_t *res); 69 | void string_at(env_t *env, val_t *a, val_t *b, val_t *res); 70 | void string_elem_get(val_t *self, int i, val_t *elem); 71 | 72 | void string_proto_init(env_t *env); 73 | extern const val_metadata_t metadata_str_inline; 74 | extern const val_metadata_t metadata_str_heap; 75 | extern const val_metadata_t metadata_str_foreign; 76 | 77 | #endif /* __LANG_STRING_INC__ */ 78 | 79 | -------------------------------------------------------------------------------- /test/test_lang_image.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include 21 | #include 22 | 23 | #include "cunit/CUnit.h" 24 | #include "cunit/CUnit_Basic.h" 25 | 26 | #include "lang/compile.h" 27 | #include "lang/interp.h" 28 | 29 | #define CPL_BUF_SIZE 10240 30 | #define IMG_BUF_SIZE 10240 31 | #define RUN_BUF_SIZE 20480 32 | //#define RUN_BUF_SIZE 10480 33 | 34 | uint8_t cpl_buf[CPL_BUF_SIZE]; 35 | uint8_t img_buf[IMG_BUF_SIZE]; 36 | uint8_t run_buf[RUN_BUF_SIZE]; 37 | 38 | static int test_setup() 39 | { 40 | return 0; 41 | } 42 | 43 | static int test_clean() 44 | { 45 | return 0; 46 | } 47 | 48 | static void test_image_simple(void) 49 | { 50 | int img_sz; 51 | env_t env; 52 | val_t *res; 53 | image_info_t image; 54 | const char *input = " \ 55 | var a = 0, b = 1; \ 56 | def fn() return a + b; \ 57 | fn() == 1; \ 58 | "; 59 | 60 | CU_ASSERT_FATAL(0 == compile_env_init(&env, cpl_buf, CPL_BUF_SIZE)); 61 | CU_ASSERT_FATAL(0 < (img_sz = compile_exe(&env, input, img_buf, IMG_BUF_SIZE))); 62 | CU_ASSERT_FATAL(0 == image_load(&image, img_buf, img_sz)); 63 | CU_ASSERT_FATAL(0 == interp_env_init_image(&env, run_buf, RUN_BUF_SIZE, 64 | NULL, 8192, NULL, 1024, &image)); 65 | 66 | CU_ASSERT_FATAL(0 <= interp_execute_image(&env, &res));// && val_is_number(res) && 1 == val_2_double(res)); 67 | } 68 | 69 | CU_pSuite test_lang_image_entry() 70 | { 71 | CU_pSuite suite = CU_add_suite("lang image", test_setup, test_clean); 72 | 73 | if (suite) { 74 | CU_add_test(suite, "image simple", test_image_simple); 75 | } 76 | 77 | return suite; 78 | } 79 | 80 | -------------------------------------------------------------------------------- /lang/compile.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #ifndef __LANG_COMPILE_INC__ 22 | #define __LANG_COMPILE_INC__ 23 | 24 | #include "def.h" 25 | 26 | #include "ast.h" 27 | #include "env.h" 28 | #include "interp.h" 29 | 30 | typedef struct compile_func_t { 31 | int16_t owner; 32 | uint16_t stack_space; 33 | uint16_t stack_high; 34 | 35 | uint8_t closure; 36 | uint8_t var_max; 37 | uint8_t var_num; 38 | uint8_t arg_num; 39 | 40 | uint16_t code_max; 41 | uint16_t code_num; 42 | uint8_t *code_buf; 43 | intptr_t *var_map; 44 | } compile_func_t; 45 | 46 | typedef struct compile_t { 47 | int error; // 48 | 49 | int16_t bgn_pos; // for loop continue 50 | int16_t skip_pos; // for loop break 51 | 52 | uint16_t func_size; 53 | uint16_t func_num; 54 | uint16_t func_cur; 55 | uint16_t func_offset; 56 | 57 | env_t *env; 58 | heap_t heap; 59 | 60 | compile_func_t *func_buf; 61 | } compile_t; 62 | 63 | int compile_init(compile_t *cpl, env_t *env, void *heap_ptr, int heap_size); 64 | int compile_deinit(compile_t *cpl); 65 | 66 | /* 67 | int compile_arg_add(compile_t *cpl, intptr_t sym_id); 68 | int compile_var_add(compile_t *cpl, intptr_t sym_id); 69 | int compile_var_get(compile_t *cpl, intptr_t sym_id); 70 | */ 71 | 72 | int compile_stmt(compile_t *cpl, stmt_t *stmt); 73 | int compile_one_stmt(compile_t *cpl, stmt_t *stmt); 74 | int compile_multi_stmt(compile_t *cpl, stmt_t *stmt); 75 | 76 | int compile_update(compile_t *cpl); 77 | 78 | int compile_env_init(env_t *env, void *mem_ptr, int mem_size); 79 | int compile_exe(env_t *env, const char *input, void *mem_ptr, int mem_size); 80 | 81 | 82 | #endif /* __LANG_COMPILE_INC__ */ 83 | -------------------------------------------------------------------------------- /lang/type_function.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #ifndef __LANG_FUNCTION_INC__ 22 | #define __LANG_FUNCTION_INC__ 23 | 24 | #include "def.h" 25 | 26 | #include "val.h" 27 | #include "env.h" 28 | #include "interp.h" 29 | 30 | #define MAGIC_FUNCTION (MAGIC_BASE + 5) 31 | 32 | typedef struct function_t { 33 | uint8_t magic; 34 | uint8_t age; 35 | uint8_t reserved[2]; 36 | uint8_t *entry; 37 | scope_t *super; 38 | } function_t; 39 | 40 | typedef val_t (*function_native_t) (env_t *env, int ac, val_t *av); 41 | 42 | intptr_t function_create(env_t *env, uint8_t *code); 43 | int function_destroy(intptr_t func); 44 | 45 | static inline 46 | int function_mem_space(function_t *f) { 47 | (void) f; 48 | return SIZE_ALIGN(sizeof(function_t)); 49 | } 50 | 51 | static inline 52 | uint8_t function_varc(function_t *fn) { 53 | return executable_func_get_var_cnt(fn->entry); 54 | } 55 | 56 | static inline 57 | uint8_t function_size(function_t *fn) { 58 | return executable_func_get_code_size(fn->entry); 59 | } 60 | 61 | static inline 62 | uint8_t function_argc(function_t *fn) { 63 | return executable_func_get_arg_cnt(fn->entry); 64 | } 65 | 66 | static inline 67 | uint16_t function_stack_high(function_t *fn) { 68 | return executable_func_get_stack_high(fn->entry); 69 | } 70 | 71 | static inline 72 | int function_is_closure(function_t *fn) { 73 | return executable_func_is_closure(fn->entry); 74 | } 75 | 76 | static inline 77 | uint8_t *function_code(function_t *fn) { 78 | return fn->entry + FUNC_HEAD_SIZE; 79 | } 80 | 81 | //extern const val_metadata_t metadata_boolean; 82 | 83 | extern const val_metadata_t metadata_function; 84 | extern const val_metadata_t metadata_function_native; 85 | 86 | #endif /* __LANG_FUNCTION_INC__ */ 87 | 88 | -------------------------------------------------------------------------------- /lang/types.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __LANG_TYPES_INC__ 21 | #define __LANG_TYPES_INC__ 22 | 23 | #include "def.h" 24 | #include "val.h" 25 | 26 | extern const val_metadata_t metadata_undefined; 27 | extern const val_metadata_t metadata_nan; 28 | extern const val_metadata_t metadata_date; 29 | extern const val_metadata_t metadata_array_buffer; 30 | extern const val_metadata_t metadata_data_view; 31 | extern const val_metadata_t metadata_object_foreign; 32 | extern const val_metadata_t metadata_none; 33 | 34 | int foreign_is_true(val_t *self) __attribute__ ((weak)); 35 | int foreign_is_equal(val_t *self, val_t *other) __attribute__ ((weak)); 36 | double foreign_value_of(val_t *self) __attribute__ ((weak)); 37 | 38 | val_t foreign_get_prop(void *env, val_t *self, const char *key) __attribute__ ((weak)); 39 | val_t foreign_get_elem(void *env, val_t *self, int id) __attribute__ ((weak)); 40 | 41 | void foreign_set_prop(void *env, val_t *self, const char *key, val_t *data) __attribute__ ((weak)); 42 | void foreign_set_elem(void *env, val_t *self, int id, val_t *data) __attribute__ ((weak)); 43 | 44 | void foreign_opx_prop(void *env, val_t *self, const char *key, val_t *res, val_opx_t op) __attribute__ ((weak)); 45 | void foreign_opx_elem(void *env, val_t *self, int id, val_t *res, val_opx_t op) __attribute__ ((weak)); 46 | 47 | void foreign_opxx_prop(void *env, val_t *self, const char *key, val_t *data, val_t *res, val_opxx_t op) __attribute__ ((weak)); 48 | void foreign_opxx_elem(void *env, val_t *self, int id, val_t *data, val_t *res, val_opxx_t op) __attribute__ ((weak)); 49 | 50 | val_t foreign_set(void *env, val_t *self, val_t *value) __attribute__ ((weak)); 51 | void foreign_keep(intptr_t entry) __attribute__ ((weak)); 52 | 53 | #endif /* __LANG_TYPES_INC__ */ 54 | 55 | -------------------------------------------------------------------------------- /make/Makefile.pub: -------------------------------------------------------------------------------- 1 | ## GPLv2 License 2 | ## 3 | ## Copyright (C) 2016-2018 Lixing Ding 4 | ## 5 | ## This program is free software; you can redistribute it and/or 6 | ## modify it under the terms of the GNU General Public License 7 | ## as published by the Free Software Foundation; either version 2 8 | ## of the License, or (at your option) any later version. 9 | ## 10 | ## This program is distributed in the hope that it will be useful, 11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ## GNU General Public License for more details. 14 | ## 15 | ## You should have received a copy of the GNU General Public License 16 | ## along with this program; if not, write to the Free Software 17 | ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | 19 | AS := ${PREFIX}as 20 | CC := ${PREFIX}gcc 21 | LD := ${PREFIX}gcc 22 | AR := ${PREFIX}ar 23 | RM := rm -rf 24 | MAKE := make 25 | 26 | # Marco build_obj_rule 27 | # param ${1}: source file 28 | # param ${2}: program or library name 29 | define build_obj_rule 30 | ${1:%.c=%.o}: ${1} 31 | @printf "[CC]\t$$@\n" 32 | @${CC} ${TGT_CPPFLAGS} ${${2}_CPPFLAGS} ${TGT_CFLAGS} ${${2}_CFLAGS} -MD -c $$< -o $$@ 33 | endef 34 | 35 | # Marco build_prog_rule 36 | # param ${1}: program name 37 | define build_prog_rule 38 | ${1}_OBJS = ${${1}_SRCS:%.c=%.o} 39 | ${1}_DEPS = ${${1}_SRCS:%.c=%.d} 40 | ${1}: $${${1}_OBJS} 41 | @printf "[LD]\t$$@\n" 42 | @${LD} -o $$@ $${${1}_OBJS} ${TGT_LDFLAGS} $${${1}_LDFLAGS} 43 | 44 | ${1}.clean: 45 | @${RM} $${${1}_OBJS} 46 | @${RM} $${${1}_DEPS} 47 | @${RM} ${1} 48 | 49 | $(foreach src,${${1}_SRCS},$(eval $(call build_obj_rule,${src},${1}))) 50 | -include $${${1}_DEPS} 51 | endef 52 | 53 | # Marco build_lib_rule 54 | # param ${1}: library name 55 | define build_lib_rule 56 | ${1}_OBJS = ${${1}_SRCS:%.c=%.o} 57 | ${1}_DEPS = ${${1}_SRCS:%.c=%.d} 58 | ${1}: lib${1}.a 59 | 60 | lib${1}.a: $${${1}_OBJS} 61 | @printf "[AR]\t$$@\n" 62 | @${AR} rcs lib${1}.a $${${1}_OBJS} 63 | 64 | ${1}.clean: 65 | @${RM} $${${1}_OBJS} 66 | @${RM} $${${1}_DEPS} 67 | @${RM} lib${1}.a 68 | 69 | $(foreach src,${${1}_SRCS},$(eval $(call build_obj_rule,${src},${1}))) 70 | -include $${${1}_DEPS} 71 | endef 72 | 73 | $(info ${lib_NAMES} ${PWD}) 74 | all: lib bin 75 | 76 | lib: ${lib_NAMES} 77 | 78 | bin: ${bin_NAMES} 79 | 80 | clean: ${bin_NAMES:%=%.clean} ${lib_NAMES:%=%.clean} 81 | 82 | $(foreach lib,${lib_NAMES},$(eval $(call build_lib_rule,${lib}))) 83 | 84 | $(foreach bin,${bin_NAMES},$(eval $(call build_prog_rule,${bin}))) 85 | 86 | .PHONY: clean bin lib all 87 | 88 | -------------------------------------------------------------------------------- /lang/types.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include "types.h" 21 | 22 | const val_metadata_t metadata_undefined = { 23 | .name = "undefined", 24 | 25 | .is_true = val_as_false, 26 | .is_equal = val_op_false, 27 | 28 | .value_of = val_as_nan, 29 | }; 30 | 31 | const val_metadata_t metadata_nan = { 32 | .name = "number", 33 | 34 | .is_true = val_as_false, 35 | .is_equal = val_op_false, 36 | 37 | .value_of = val_as_nan, 38 | }; 39 | 40 | const val_metadata_t metadata_date = { 41 | .name = "object", 42 | 43 | .is_true = val_as_true, 44 | .is_equal = val_op_false, 45 | 46 | .value_of = val_as_integer, 47 | }; 48 | 49 | const val_metadata_t metadata_array_buffer = { 50 | .name = "object", 51 | 52 | .is_true = val_as_false, 53 | .is_equal = val_op_false, 54 | 55 | .value_of = val_as_zero, 56 | }; 57 | 58 | const val_metadata_t metadata_data_view = { 59 | .name = "object", 60 | 61 | .is_true = val_as_false, 62 | .is_equal = val_op_false, 63 | 64 | .value_of = val_as_zero, 65 | }; 66 | 67 | const val_metadata_t metadata_object_foreign = { 68 | .name = "object", 69 | 70 | .is_true = foreign_is_true, 71 | .is_equal = foreign_is_equal, 72 | 73 | .value_of = foreign_value_of, 74 | 75 | .get_prop = foreign_get_prop, 76 | .get_elem = foreign_get_elem, 77 | 78 | .set_prop = foreign_set_prop, 79 | .set_elem = foreign_set_elem, 80 | 81 | .opx_prop = foreign_opx_prop, 82 | .opx_elem = foreign_opx_elem, 83 | 84 | .opxx_prop = foreign_opxx_prop, 85 | .opxx_elem = foreign_opxx_elem, 86 | }; 87 | 88 | const val_metadata_t metadata_none = { 89 | .name = "object", 90 | 91 | .is_true = val_as_false, 92 | .is_equal = val_op_false, 93 | 94 | .value_of = val_as_zero, 95 | }; 96 | 97 | -------------------------------------------------------------------------------- /lang/type_buffer.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __LANG_TYPE_BUFFER_INC__ 21 | #define __LANG_TYPE_BUFFER_INC__ 22 | 23 | /* 24 | #include "def.h" 25 | 26 | #include "val.h" 27 | #include "env.h" 28 | 29 | #define MAGIC_BUFFER (MAGIC_BASE + 13) 30 | typedef struct type_buffer_t { 31 | uint8_t magic; 32 | uint8_t age; 33 | uint16_t len; 34 | uint8_t buf[0]; 35 | } type_buffer_t; 36 | 37 | static inline 38 | int buffer_mem_space(type_buffer_t *buf) { 39 | return SIZE_ALIGN(sizeof(type_buffer_t) + buf->len); 40 | } 41 | 42 | type_buffer_t *buffer_create(env_t *env, int size); 43 | type_buffer_t *buffer_slice(env_t *env, type_buffer_t *b, int start, int size); 44 | int buffer_read_int(type_buffer_t *b, int off, int size, int be, int *v); 45 | int buffer_write_int(type_buffer_t *b, int off, int size, int be, int num); 46 | 47 | static inline 48 | int _buffer_size(type_buffer_t *b) {return b->len;} 49 | static inline 50 | void *_buffer_addr(type_buffer_t *b) {return b->buf;} 51 | 52 | val_t buffer_native_create(env_t *env, int ac, val_t *av); 53 | val_t buffer_native_write_int(env_t *env, int ac, val_t *av); 54 | val_t buffer_native_write_uint(env_t *env, int ac, val_t *av); 55 | val_t buffer_native_read_int(env_t *env, int ac, val_t *av); 56 | val_t buffer_native_read_uint(env_t *env, int ac, val_t *av); 57 | val_t buffer_native_slice(env_t *env, int ac, val_t *av); 58 | val_t buffer_native_to_string(env_t *env, int ac, val_t *av); 59 | 60 | void buffer_elem_get(val_t *self, int index, val_t *elem); 61 | 62 | static inline 63 | void *_val_buffer_addr(val_t *v) { 64 | return _buffer_addr((type_buffer_t *) val_2_intptr(v)); 65 | } 66 | 67 | static inline 68 | int _val_buffer_size(val_t *v) { 69 | return _buffer_size((type_buffer_t *) val_2_intptr(v)); 70 | } 71 | */ 72 | 73 | #endif /* __LANG_TYPE_BUFFER_INC__ */ 74 | 75 | -------------------------------------------------------------------------------- /lang/type_object.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #ifndef __LANG_OBJECT_INC__ 22 | #define __LANG_OBJECT_INC__ 23 | 24 | #include "def.h" 25 | 26 | #include "val.h" 27 | #include "env.h" 28 | #include "err.h" 29 | 30 | #define MAGIC_OBJECT (MAGIC_BASE + 7) 31 | #define MAGIC_OBJECT_STATIC (MAGIC_BASE + 9) 32 | 33 | typedef struct object_t { 34 | uint8_t magic; 35 | uint8_t age; 36 | uint8_t reserved[2]; 37 | 38 | uint16_t prop_size; 39 | uint16_t prop_num; 40 | struct object_t *proto; 41 | intptr_t *keys; 42 | val_t *vals; 43 | } object_t; 44 | 45 | typedef struct object_prop_t { 46 | intptr_t symbal; 47 | val_t (*getter) (env_t *env, void *entry); 48 | void (*setter) (env_t *env, void *entry, val_t *data); 49 | } object_prop_t; 50 | 51 | typedef struct object_iter_t { 52 | object_t *obj; 53 | int cur; 54 | } object_iter_t; 55 | 56 | //int objects_env_init(env_t *env); 57 | 58 | intptr_t object_create(env_t *env, int n, val_t *av); 59 | 60 | static inline int object_length(object_t *obj) 61 | { 62 | return obj->prop_num; 63 | } 64 | 65 | static inline int object_mem_space(object_t *o) { 66 | return SIZE_ALIGN(sizeof(object_t) + (sizeof(intptr_t) + sizeof(val_t)) * o->prop_size); 67 | }; 68 | 69 | static inline void _object_iter_init(object_iter_t *it, object_t *obj) { 70 | it->obj = obj; 71 | it->cur = 0; 72 | }; 73 | 74 | static inline int object_iter_init(object_iter_t *it, val_t *obj) 75 | { 76 | if (val_is_object(obj)) { 77 | _object_iter_init(it, (object_t *)val_2_intptr(obj)); 78 | return 0; 79 | } 80 | return -1; 81 | } 82 | 83 | int object_iter_next(object_iter_t *it, const char **k, val_t **v); 84 | 85 | void object_proto_init(env_t *env); 86 | extern const val_metadata_t metadata_object; 87 | 88 | #endif /* __LANG_OBJECT_INC__ */ 89 | 90 | -------------------------------------------------------------------------------- /example/compile.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include "example.h" 21 | 22 | #define MEM_SIZE 10240 23 | static char *MEM_PTR[MEM_SIZE]; 24 | 25 | static int set_output_name(const char *input, void *buf, int sz) 26 | { 27 | int pos = file_base_name(input, buf, sz - 5); 28 | 29 | if (pos < 1) { 30 | return -1; 31 | } 32 | 33 | memcpy(buf + pos, ".pdc", 5); 34 | 35 | return 0; 36 | } 37 | 38 | #define OUTPUT_NAME_MAX (128) 39 | 40 | static int compile(const char *input, void *mem_ptr, int mem_size) 41 | { 42 | char *output = (char *) mem_ptr; 43 | void *cpl_mem, *exe_mem; 44 | env_t env; 45 | int cpl_mem_sz, exe_mem_sz, input_sz; 46 | int exe_sz; 47 | 48 | exe_mem_sz = (mem_size / 3) & (~0xf); 49 | cpl_mem_sz = mem_size - OUTPUT_NAME_MAX - exe_mem_sz; 50 | 51 | exe_mem = mem_ptr + OUTPUT_NAME_MAX; 52 | cpl_mem = mem_ptr + OUTPUT_NAME_MAX + exe_mem_sz; 53 | 54 | if (0 != set_output_name(input, output, OUTPUT_NAME_MAX)) { 55 | return -1; 56 | } 57 | 58 | if (0 != compile_env_init(&env, cpl_mem, cpl_mem_sz)) { 59 | return -1; 60 | } 61 | 62 | native_init(&env); 63 | 64 | input = file_load(input, &input_sz); 65 | if (!input) { 66 | return -1; 67 | } 68 | 69 | exe_sz = compile_exe(&env, input, exe_mem, exe_mem_sz); 70 | file_release((void *)input, input_sz); 71 | 72 | if (exe_sz <= 0) { 73 | return -1; 74 | } else { 75 | return file_store(output, exe_mem, exe_sz); 76 | } 77 | } 78 | 79 | int main(int ac, char **av) 80 | { 81 | int error; 82 | 83 | if (ac == 1) { 84 | printf("Usage: %s \n", av[0]); 85 | return 0; 86 | } 87 | 88 | if (0 > (error = compile(av[1], MEM_PTR, MEM_SIZE))) { 89 | printf("compile: %s fail:%d\n", av[1], error); 90 | } 91 | 92 | return error ? 1 : 0; 93 | } 94 | 95 | -------------------------------------------------------------------------------- /doc/syntax.txt: -------------------------------------------------------------------------------- 1 | # miniJS syntax 2 | 3 | # expression syntax 4 | factor ::= id | number | string | 'true' | 'false' | 'und' | enclosure | funcdef 5 | enclosure ::= parenth_form | array_form | dict_form 6 | parenth_form :: '(' expr ')' 7 | array_form ::= '[' [ expr ] ']' 8 | dict_form ::= '{' [ kv_list ] '}' 9 | kv_list ::= kv ( ',' kv )* 10 | kv ::= (id | string) ':' expr 11 | funcdef ::= 'def' [ id ] '(' [ vardef_list ] ')' ('{' stmt* '}' | stmt) 12 | vardef_list ::= vardef [ ',' vardef ]* 13 | vardef ::= id [ '=' expr ] 14 | 15 | primary ::= factor | prop_form | elem_form | call_form 16 | prop_form ::= primary | prop_form '.' id 17 | elem_form ::= primary | elem_form '[' expr ']' 18 | call_form ::= callor | call_form '(' comma ')' 19 | callor :: id | prop_form | elem_form 20 | 21 | selfop :: pre_selfop | aft_selfop 22 | pre_selfop :: ('++' | '--') primary 23 | aft_selfop :: primary ('++' | '--') 24 | 25 | # unary ::= primary | ( '-' |'~' ) unary | 'new' funcall 26 | unary ::= selfop | ( '-' | '~' | '!') unary 27 | 28 | m_expr ::= u_expr | m_expr '*' u_expr | m_expr '/' u_expr | m_expr '%' u_expr 29 | a_expr ::= m_expr | a_expr '+' m_expr | a_expr '-' m_expr 30 | shift_expr ::= a_expr | shift_expr ( '>>' | '<<' ) a_expr 31 | 32 | # and_expr ::= shift_expr | and_expr '&' shift_expr 33 | # xor_expr ::= and_expr | xor_expr '^' and_expr 34 | # or_expr ::= xor_expr | or_expr '|' xor_expr 35 | aand_expr ::= shift_expr | aand_expr ( '&' | '^' | '|' ) shift_expr 36 | 37 | test ::= aand_expr ( '>' | '<' | '>=' | '<=' | '==' | '!=' | 'in' ) aand_expr 38 | 39 | # not_test ::= comparison [ '!' not_test ] 40 | and_test ::= test [ '&&' and_test ] # right with 41 | or_test ::= test [ '||' or_test ] # right with 42 | 43 | ternary ::= or_test [ '?' pair ] 44 | pair ::= ternary ':' ternary 45 | 46 | assign ::= ternary [ '=' assign] # right with 47 | 48 | comma ::= assign [ ',' comma ] # right with 49 | 50 | [first] 51 | expr ::= comma 52 | 53 | # statement syntax 54 | statement :: simp_stmt | comp_stmt 55 | simp_stmt :: expr_stmt | del_stmt | var_stmt | ret_stmt | break_stmt | continue_stmt | pass_stmt 56 | comp_stmt :: if_stmt | while_stmt | for_stmt 57 | 58 | pass_stmt :: ';' | # empty statement 59 | expr_stmt :: expr [ ';' ] 60 | del_stmt :: 'del' expr [ ';' ] 61 | var_stmt :: 'var' vardef_list [ ';' ] 62 | ret_stmt :: 'return' [ expr ] [ ';' ] 63 | break_stmt :: 'break' [ ';' ] 64 | continue_stmt :: 'continue' [ ';' ] 65 | 66 | if_stmt :: 'if' '(' expr ')' block 67 | [ 'else' block ] 68 | block: statement | '{' stmt_list '}' 69 | 70 | while_stmt :: 'while' '(' expr ')' block 71 | 72 | # First 73 | stmt_list :: statement* 74 | 75 | -------------------------------------------------------------------------------- /example/sal.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | int output(const char *s) 30 | { 31 | return printf("%s", s); 32 | } 33 | 34 | void *file_load(const char *name, int *size) 35 | { 36 | 37 | char *addr; 38 | int fd; 39 | struct stat sb; 40 | size_t length; 41 | 42 | fd = open(name, O_RDONLY); 43 | if (fd < 0) { 44 | return NULL; 45 | } 46 | 47 | if (fstat(fd, &sb) == -1) { 48 | close(fd); 49 | return NULL; 50 | } 51 | length = sb.st_size + 1; 52 | 53 | addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0); 54 | *size = length; 55 | 56 | return addr; 57 | } 58 | 59 | int file_release(void *addr, int size) 60 | { 61 | return munmap(addr, size); 62 | } 63 | 64 | int file_store(const char *name, void *buf, int sz) 65 | { 66 | int fd = open(name, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU); 67 | int off, n; 68 | 69 | if (fd < 0) { 70 | return -1; 71 | } 72 | 73 | off = 0; 74 | while(off < sz) { 75 | n = write(fd, buf + off, sz - off); 76 | if (n < 0) { 77 | unlink(name); 78 | close(fd); 79 | return -1; 80 | } 81 | off += n; 82 | } 83 | 84 | close(fd); 85 | return 0; 86 | } 87 | 88 | int file_base_name(const char *name, void *buf, int sz) 89 | { 90 | const char *base = rindex(name, '/'); 91 | const char *suffix = rindex(name, '.'); 92 | int len; 93 | 94 | base = base ? base : name; 95 | if (!suffix || suffix < base) { 96 | len = strlen(base); 97 | } else { 98 | len = suffix - base; 99 | } 100 | 101 | if (len < sz) { 102 | ((char *)buf)[len] = 0; 103 | memcpy(buf, base, len); 104 | return len; 105 | } 106 | 107 | return -1; 108 | } 109 | 110 | -------------------------------------------------------------------------------- /lang/parse.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #ifndef __LANG_PARSE_INC__ 22 | #define __LANG_PARSE_INC__ 23 | 24 | #include "def.h" 25 | 26 | #include "lex.h" 27 | #include "ast.h" 28 | #include "heap.h" 29 | 30 | enum { 31 | PARSE_EOF = 0, 32 | PARSE_FAIL, 33 | PARSE_SIMPLE, 34 | PARSE_COMPOSE, 35 | PARSE_ENTER_BLOCK, 36 | PARSE_LEAVE_BLOCK 37 | }; 38 | 39 | struct parser_t; 40 | typedef struct parse_event_t { 41 | int type; 42 | int line, col; 43 | struct parser_t *psr; 44 | } parse_event_t; 45 | 46 | typedef struct parser_t { 47 | int error; 48 | lexer_t lex; 49 | heap_t heap; 50 | void (*usr_cb) (void *, parse_event_t *); 51 | void *usr_data; 52 | } parser_t; 53 | 54 | typedef void (*parse_callback_t)(void *u, parse_event_t *e); 55 | 56 | static inline int parse_init(parser_t *psr, const char *input, char *(*more)(void), void *mem, int size) { 57 | if (psr && input && mem) { 58 | psr->error = 0; 59 | lex_init(&psr->lex, input, more); 60 | heap_init(&psr->heap, mem, size); 61 | psr->usr_cb = NULL; 62 | psr->usr_data = NULL; 63 | return 0; 64 | } else { 65 | return -1; 66 | } 67 | } 68 | 69 | static inline void parse_set_cb(parser_t *psr, parse_callback_t cb, void *data) { 70 | if (psr) { 71 | psr->usr_cb = cb; 72 | psr->usr_data = data; 73 | } 74 | } 75 | 76 | static inline void parse_disable_more(parser_t *psr) { 77 | psr->lex.line_more = NULL; 78 | } 79 | 80 | expr_t *parse_expr(parser_t *psr); 81 | stmt_t *parse_stmt(parser_t *psr); 82 | stmt_t *parse_stmt_multi(parser_t *psr); 83 | 84 | static inline int parse_position(parser_t *psr, int *line, int *col) { 85 | return lex_position(&psr->lex, line, col); 86 | } 87 | static inline int parse_token(parser_t *psr, token_t *token) { 88 | return lex_token(&psr->lex, token); 89 | } 90 | static inline int parse_match(parser_t *psr, int tok) { 91 | // printf("match: %d(%c)\n", tok, tok); 92 | return lex_match(&psr->lex, tok); 93 | } 94 | 95 | #endif /* __LANG_PARSE_INC__ */ 96 | 97 | -------------------------------------------------------------------------------- /lang/def.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __LANG_DEF__ 21 | #define __LANG_DEF__ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #ifndef NULL 36 | # define NULL ((void *)0) 37 | #endif 38 | 39 | #define LE 1 40 | #define BE 2 41 | 42 | #define ADDRSIZE_32 1 43 | #define ADDRSIZE_64 2 44 | 45 | #define SYS_BYTE_ORDER (BYTE_ORDER == LITTLE_ENDIAN ? LE : BE) 46 | #define SYS_ADDR_SIZE ADDRSIZE_64 47 | 48 | #define ADDR_ALIGN_4(a) ((void *)((((intptr_t)(a)) + 3) & ~0x03L)) 49 | #define ADDR_ALIGN_8(a) ((void *)((((intptr_t)(a)) + 7) & ~0x07L)) 50 | #define ADDR_ALIGN_16(a) ((void *)((((intptr_t)(a)) + 15) & ~0x0FL)) 51 | #define ADDR_ALIGN_32(a) ((void *)((((intptr_t)(a)) + 31) & ~0x1FL)) 52 | 53 | #define SIZE_ALIGN_4(x) (((x) + 3) & ~0x03) 54 | #define SIZE_ALIGN_8(x) (((x) + 7) & ~0x07) 55 | #define SIZE_ALIGN_16(x) (((x) + 15) & ~0x0F) 56 | #define SIZE_ALIGN_32(x) (((x) + 31) & ~0x1F) 57 | #define SIZE_ALIGN_64(x) (((x) + 63) & ~0x3F) 58 | #define SIZE_ALIGN_64(x) (((x) + 63) & ~0x3F) 59 | 60 | #define SIZE_ALIGN SIZE_ALIGN_8 61 | #define ADDR_ALING ADDR_ALIGN_8 62 | 63 | typedef uint64_t val_t; 64 | 65 | // lang profile 66 | #define MAGIC_BASE (0xE0) 67 | #define TOKEN_MAX_SIZE (128) 68 | 69 | # define INTERACTIVE_VAR_MAX (32) 70 | 71 | # define DEF_PROP_SIZE (4) 72 | # define DEF_ELEM_SIZE (8) 73 | # define DEF_FUNC_SIZE (4) 74 | # define DEF_VMAP_SIZE (4) 75 | # define DEF_FUNC_CODE_SIZE (32) 76 | 77 | # define LIMIT_VMAP_SIZE (32) // max variable number in function 78 | # define LIMIT_FUNC_SIZE (32767) // max function number in module 79 | # define LIMIT_FUNC_CODE_SIZE (32767) // max code of each function 80 | 81 | # define DEF_STRING_SIZE (8) 82 | 83 | // lang compile resource default and limit 84 | 85 | #endif /* __LANG_DEF__ */ 86 | 87 | -------------------------------------------------------------------------------- /lang/lex.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __LANG_LEX_INC__ 21 | #define __LANG_LEX_INC__ 22 | 23 | #include "def.h" 24 | 25 | #include "heap.h" 26 | 27 | enum LEX_TOKEN_TYPE{ 28 | TOK_EOF = 0, 29 | TOK_ID = 256, 30 | TOK_NUM, 31 | TOK_STR, 32 | 33 | TOK_EQ, // == 34 | TOK_NE, // != 35 | TOK_GE, // >= 36 | TOK_LE, // <= 37 | 38 | TOK_INC, // ++ 39 | TOK_DEC, // -- 40 | 41 | TOK_ADDASSIGN, // += 42 | TOK_SUBASSIGN, // -= 43 | TOK_MULASSIGN, // *= 44 | TOK_DIVASSIGN, // /= 45 | TOK_MODASSIGN, // %= 46 | TOK_ANDASSIGN, // &= 47 | TOK_ORASSIGN, // |= 48 | TOK_XORASSIGN, // ^= 49 | TOK_NOTASSIGN, // ~= 50 | TOK_LSHIFTASSIGN, // <<= 51 | TOK_RSHIFTASSIGN, // >>= 52 | 53 | TOK_LSHIFT, // << 54 | TOK_RSHIFT, // >> 55 | 56 | TOK_LOGICAND, // && 57 | TOK_LOGICOR, // || 58 | 59 | /* Key words */ 60 | TOK_UND, 61 | TOK_NAN, 62 | TOK_NULL, 63 | TOK_TRUE, 64 | TOK_FALSE, 65 | 66 | TOK_IN, 67 | TOK_IF, 68 | TOK_VAR, 69 | TOK_DEF, 70 | TOK_RET, 71 | TOK_TRY, 72 | TOK_ELSE, 73 | TOK_ELIF, 74 | TOK_WHILE, 75 | TOK_BREAK, 76 | TOK_CATCH, 77 | TOK_THROW, 78 | TOK_CONTINUE 79 | }; 80 | 81 | typedef struct lexer_t { 82 | int curr_ch; 83 | int next_ch; 84 | int curr_tok; 85 | int line, col; 86 | int line_end, line_pos; 87 | 88 | int token_buf_size; 89 | int line_buf_size; 90 | int token_len; 91 | 92 | heap_t heap; 93 | char *line_buf; 94 | char *(*line_more)(void); 95 | char token_buf[TOKEN_MAX_SIZE]; 96 | } lexer_t; 97 | 98 | typedef struct token_t { 99 | int type; 100 | int line, col; 101 | int value; // value or length of id | string 102 | char *text; 103 | } token_t; 104 | 105 | int lex_init(lexer_t *lex, const char *input, char *(*more)(void)); 106 | int lex_deinit(lexer_t *lex); 107 | 108 | int lex_token(lexer_t *lex, token_t *tok); 109 | int lex_match(lexer_t *lex, int tok); 110 | int lex_position(lexer_t *lex, int *line, int *col); 111 | 112 | #endif /* __LANG_LEX_INC__ */ 113 | 114 | -------------------------------------------------------------------------------- /lang/bcode.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #ifndef __LANG_BCODE_INC__ 22 | #define __LANG_BCODE_INC__ 23 | 24 | #include "def.h" 25 | 26 | typedef enum bcode_t { 27 | BC_STOP = 0, 28 | BC_PASS = 1, 29 | 30 | BC_RET, 31 | BC_RET0, 32 | 33 | BC_JMP, 34 | BC_SJMP, 35 | 36 | BC_JMP_T, 37 | BC_SJMP_T, 38 | BC_JMP_F, 39 | BC_SJMP_F, 40 | 41 | BC_POP_JMP_T, 42 | BC_POP_SJMP_T, 43 | BC_POP_JMP_F, 44 | BC_POP_SJMP_F, 45 | BC_POP, 46 | 47 | BC_PUSH_UND, 48 | BC_PUSH_NAN, 49 | BC_PUSH_ZERO, 50 | BC_PUSH_TRUE, 51 | BC_PUSH_FALSE, 52 | BC_PUSH_NUM, 53 | BC_PUSH_STR, 54 | BC_PUSH_VAR, 55 | BC_PUSH_REF, 56 | BC_PUSH_SCRIPT, 57 | BC_PUSH_NATIVE, 58 | 59 | BC_NEG, 60 | BC_NOT, 61 | BC_LOGIC_NOT, 62 | 63 | BC_MUL, 64 | BC_DIV, 65 | BC_MOD, 66 | BC_ADD, 67 | BC_SUB, 68 | BC_LSHIFT, 69 | BC_RSHIFT, 70 | BC_AAND, 71 | BC_AOR, 72 | BC_AXOR, 73 | 74 | BC_TEQ, 75 | BC_TNE, 76 | BC_TGT, 77 | BC_TGE, 78 | BC_TLT, 79 | BC_TLE, 80 | BC_TIN, 81 | 82 | BC_PROP, 83 | BC_PROP_METH, 84 | 85 | BC_ELEM, 86 | BC_ELEM_METH, 87 | 88 | BC_INC, 89 | BC_INCP, 90 | BC_DEC, 91 | BC_DECP, 92 | 93 | BC_ASSIGN, 94 | BC_ADD_ASSIGN, 95 | BC_SUB_ASSIGN, 96 | BC_MUL_ASSIGN, 97 | BC_DIV_ASSIGN, 98 | BC_MOD_ASSIGN, 99 | BC_AND_ASSIGN, 100 | BC_OR_ASSIGN, 101 | BC_XOR_ASSIGN, 102 | BC_NOT_ASSIGN, 103 | BC_LSHIFT_ASSIGN, 104 | BC_RSHIFT_ASSIGN, 105 | 106 | BC_PROP_INC, 107 | BC_PROP_INCP, 108 | BC_PROP_DEC, 109 | BC_PROP_DECP, 110 | 111 | BC_PROP_ASSIGN, 112 | BC_PROP_ADD_ASSIGN, 113 | BC_PROP_SUB_ASSIGN, 114 | BC_PROP_MUL_ASSIGN, 115 | BC_PROP_DIV_ASSIGN, 116 | BC_PROP_MOD_ASSIGN, 117 | BC_PROP_AND_ASSIGN, 118 | BC_PROP_OR_ASSIGN, 119 | BC_PROP_XOR_ASSIGN, 120 | BC_PROP_NOT_ASSIGN, 121 | BC_PROP_LSHIFT_ASSIGN, 122 | BC_PROP_RSHIFT_ASSIGN, 123 | 124 | BC_ELEM_INC, 125 | BC_ELEM_INCP, 126 | BC_ELEM_DEC, 127 | BC_ELEM_DECP, 128 | 129 | BC_ELEM_ASSIGN, 130 | BC_ELEM_ADD_ASSIGN, 131 | BC_ELEM_SUB_ASSIGN, 132 | BC_ELEM_MUL_ASSIGN, 133 | BC_ELEM_DIV_ASSIGN, 134 | BC_ELEM_MOD_ASSIGN, 135 | BC_ELEM_AND_ASSIGN, 136 | BC_ELEM_OR_ASSIGN, 137 | BC_ELEM_XOR_ASSIGN, 138 | BC_ELEM_NOT_ASSIGN, 139 | BC_ELEM_LSHIFT_ASSIGN, 140 | BC_ELEM_RSHIFT_ASSIGN, 141 | 142 | BC_FUNC_CALL, 143 | 144 | BC_ARRAY, 145 | BC_DICT, 146 | 147 | } bcode_t; 148 | 149 | int bcode_parse(const uint8_t *code, int *offset, const char **name, int *param1, int *param2); 150 | 151 | #endif /* __LANG_BCODE_INC__ */ 152 | 153 | -------------------------------------------------------------------------------- /example/interpreter.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include "example.h" 21 | 22 | #define HEAP_SIZE (1024 * 400) 23 | #define STACK_SIZE (1024) 24 | #define EXE_MEM_SPACE (1024 * 100) 25 | #define SYM_MEM_SPACE (1024 * 4) 26 | #define MEM_SIZE (STACK_SIZE * sizeof(val_t) + HEAP_SIZE + EXE_MEM_SPACE + SYM_MEM_SPACE) 27 | 28 | static uint8_t memory[MEM_SIZE]; 29 | 30 | static int panda_binary(const char *input, void *mem_ptr, int mem_size, int heap_size, int stack_size) 31 | { 32 | env_t env; 33 | val_t *res; 34 | int err, size; 35 | uint8_t *binary; 36 | image_info_t ef; 37 | 38 | binary = file_load(input, &size); 39 | if (!binary) { 40 | return -1; 41 | } 42 | 43 | if (0 != image_load(&ef, binary, size)) { 44 | file_release((void *)input, size); 45 | return -1; 46 | } 47 | 48 | if (0 != interp_env_init_image (&env, mem_ptr, mem_size, NULL, heap_size, NULL, stack_size, &ef)) { 49 | file_release((void *)input, size); 50 | return -1; 51 | } 52 | native_init(&env); 53 | 54 | err = interp_execute_image(&env, &res); 55 | if (err < 0) { 56 | printf("error: %d\n", err); 57 | } 58 | 59 | file_release((void *)input, size); 60 | 61 | return err; 62 | } 63 | 64 | static int panda_string(const char *input, void *mem_ptr, int mem_size, int heap_size, int stack_size) 65 | { 66 | env_t env; 67 | val_t *res; 68 | int err, size; 69 | 70 | input = file_load(input, &size); 71 | if (!input) { 72 | return -1; 73 | } 74 | 75 | if(0 != interp_env_init_interpreter(&env, mem_ptr, mem_size, NULL, heap_size, NULL, stack_size)) { 76 | file_release((void *)input, size); 77 | return -1; 78 | } 79 | native_init(&env); 80 | 81 | err = interp_execute_string(&env, input, &res); 82 | if (err < 0) { 83 | printf("error: %d\n", err); 84 | } 85 | 86 | file_release((void *)input, size); 87 | 88 | return err; 89 | } 90 | 91 | static inline int interpreter(const char *input, int ac, char **av) { 92 | char *suffix; 93 | 94 | suffix = rindex(input, '.'); 95 | if (suffix && !strcmp(suffix, ".pdc")) { 96 | return panda_binary(input, memory, MEM_SIZE, HEAP_SIZE, STACK_SIZE); 97 | } else { 98 | return panda_string(input, memory, MEM_SIZE, HEAP_SIZE, STACK_SIZE); 99 | } 100 | } 101 | 102 | int main(int ac, char **av) 103 | { 104 | char *input; 105 | int error; 106 | 107 | if (ac == 1) { 108 | printf("Usage: %s \n", av[0]); 109 | return 0; 110 | } 111 | input = av[1]; 112 | 113 | error = interpreter(input, ac - 1, av + 1); 114 | if (error < 0) { 115 | printf("execute %s fail:%d\n", input, error); 116 | } 117 | 118 | return error ? 1 : 0; 119 | } 120 | 121 | -------------------------------------------------------------------------------- /test/test_lang_async.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include 21 | #include 22 | 23 | #include "cunit/CUnit.h" 24 | #include "cunit/CUnit_Basic.h" 25 | 26 | #include "lang/type_function.h" 27 | #include "lang/interp.h" 28 | 29 | 30 | #define STACK_SIZE 128 31 | #define HEAP_SIZE 4096 32 | 33 | #define EXE_MEM_SPACE 4096 34 | #define SYM_MEM_SPACE 1024 35 | #define ENV_BUF_SIZE (sizeof(val_t) * STACK_SIZE + HEAP_SIZE + EXE_MEM_SPACE + SYM_MEM_SPACE) 36 | 37 | uint8_t env_buf[ENV_BUF_SIZE]; 38 | 39 | static int test_setup() 40 | { 41 | return 0; 42 | } 43 | 44 | static int test_clean() 45 | { 46 | return 0; 47 | } 48 | 49 | static val_t ref[4]; 50 | static int gc_count = 0; 51 | static void gc_callback() 52 | { 53 | gc_count++; 54 | } 55 | 56 | static val_t test_async_register(env_t *env, int ac, val_t *av) 57 | { 58 | int i; 59 | 60 | (void) env; 61 | (void) ac; 62 | (void) av; 63 | 64 | if (ac > 0) { 65 | for (i = 0; i < 4; i++) { 66 | if (val_is_undefined(ref + i)) { 67 | ref[i] = *av; 68 | return val_mk_number(i); 69 | } 70 | } 71 | } 72 | 73 | return val_mk_undefined(); 74 | } 75 | 76 | static val_t test_async_call(env_t *env, val_t *fn) 77 | { 78 | if (val_is_native(fn)) { 79 | function_native_t native = (function_native_t) val_2_intptr(fn); 80 | return native(env, 0, NULL); 81 | } else { 82 | env_push_call_function(env, fn); 83 | return interp_execute_call(env, 0); 84 | } 85 | } 86 | 87 | static void test_async_common(void) 88 | { 89 | env_t env; 90 | val_t *res; 91 | native_t native_entry[] = { 92 | {"register", test_async_register} 93 | }; 94 | int i; 95 | 96 | for (i = 0; i < 4; i++) { 97 | val_set_undefined(ref + i); 98 | } 99 | 100 | CU_ASSERT_FATAL(0 == interp_env_init_interactive(&env, env_buf, ENV_BUF_SIZE, NULL, HEAP_SIZE, NULL, STACK_SIZE)); 101 | CU_ASSERT(0 == env_native_set(&env, native_entry, 1)); 102 | CU_ASSERT(0 == env_reference_set(&env, ref, 4)); 103 | CU_ASSERT(0 == env_callback_set(&env, gc_callback)); 104 | 105 | CU_ASSERT(0 < interp_execute_string(&env, "register", &res) && val_is_function(res)); 106 | CU_ASSERT(0 < interp_execute_string(&env, "var n = 0, a = [], o = {}, s;", &res)); 107 | CU_ASSERT(0 < interp_execute_string(&env, "def fn() {n += 1}", &res) && val_is_function(res)); 108 | CU_ASSERT(0 < interp_execute_string(&env, "register(fn)", &res) && val_is_number(res) && 0 == val_2_double(res)); 109 | 110 | for (i = 0; i < 4; i++) { 111 | val_t *fn = ref + i; 112 | if (val_is_function(fn)) { 113 | test_async_call(&env, fn); 114 | val_set_undefined(fn); 115 | } 116 | } 117 | CU_ASSERT(0 < interp_execute_string(&env, "n == 1", &res) && val_is_true(res)); 118 | 119 | env_deinit(&env); 120 | } 121 | 122 | CU_pSuite test_lang_async_entry() 123 | { 124 | CU_pSuite suite = CU_add_suite("lang async execute", test_setup, test_clean); 125 | 126 | if (suite) { 127 | CU_add_test(suite, "async common", test_async_common); 128 | } 129 | 130 | return suite; 131 | } 132 | 133 | -------------------------------------------------------------------------------- /example/dump.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #include "example.h" 22 | 23 | static int dump_image(const char *file) 24 | { 25 | int err, size; 26 | image_info_t image; 27 | uint8_t *binary; 28 | 29 | binary = file_load(file, &size); 30 | if (!binary) { 31 | printf("file load fail: %s\n", file); 32 | return -1; 33 | } 34 | 35 | if (0 == (err = image_load(&image, binary, size))) { 36 | int i; 37 | double *numbers = image_number_entry(&image); 38 | 39 | printf("================ executable image file ==================\n"); 40 | printf("+ Version : %d\n", 0); 41 | printf("+ AddrSize : %d\n", image.addr_size == ADDRSIZE_32 ? 32 : 64); 42 | printf("+ ByteOrder: %s\n", image.byte_order == LE ? "LittleEndian" : "BigEndian"); 43 | printf("+ Number count: %d\n", image.num_cnt); 44 | printf("+ String count: %d\n", image.str_cnt); 45 | printf("+ Function count: %d\n", image.fn_cnt); 46 | printf("-------------------- static numbers ---------------------\n"); 47 | for (i = 0; i < image.num_cnt; i++) { 48 | printf("N[%d] %f\n", i, numbers[i]); 49 | } 50 | printf("-------------------- static strings ---------------------\n"); 51 | for (i = 0; i < image.str_cnt; i++) { 52 | printf("S[%d] %s\n", i, image_get_string(&image, i)); 53 | } 54 | printf("----------------------- functions -----------------------\n"); 55 | for (i = 0; i < image.fn_cnt; i++) { 56 | const uint8_t *entry = image_get_function(&image, i); 57 | const uint8_t *code = executable_func_get_code(entry); 58 | uint32_t size = executable_func_get_code_size(entry); 59 | int off = 0; 60 | 61 | printf("\n* Function[%d] %c\n", i, executable_func_is_closure(entry) ? '*' : ' '); 62 | printf("* variables: %u, arguments: %u, stack_need: %u, code_size: %u\n", 63 | executable_func_get_var_cnt(entry), executable_func_get_arg_cnt(entry), 64 | executable_func_get_stack_high(entry), size); 65 | while (off < size) { 66 | const char *name; 67 | int p1, p2, pos = off; 68 | int n = bcode_parse(code, &off, &name, &p1, &p2); 69 | if (n == 2) { 70 | printf("[%4d] %s %d %d\n", pos, name, p1, p2); 71 | } else if (n == 1) { 72 | printf("[%4d] %s %d\n", pos, name, p1); 73 | } else { 74 | printf("[%4d] %s\n", pos, name); 75 | } 76 | } 77 | } 78 | printf("========================= end ===========================\n"); 79 | } else { 80 | printf("Invalid image file: %s\n", file); 81 | } 82 | 83 | file_release((void *)binary, size); 84 | 85 | return err; 86 | } 87 | 88 | int main(int ac, char **av) 89 | { 90 | int error; 91 | 92 | if (ac == 1) { 93 | printf("Usage: %s \n", av[0]); 94 | return 0; 95 | } 96 | 97 | error = dump_image(av[1]); 98 | if (error < 0) { 99 | printf("dump: %s fail:%d\n", av[1], error); 100 | } 101 | 102 | return error ? 1 : 0; 103 | } 104 | 105 | -------------------------------------------------------------------------------- /lang/ast.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #ifndef __LANG_AST_INC__ 21 | #define __LANG_AST_INC__ 22 | 23 | #include "def.h" 24 | 25 | #include "lex.h" 26 | 27 | enum EXPR_TYPE { 28 | // factor expression 29 | EXPR_ID = 1, 30 | EXPR_NUM, 31 | EXPR_NAN, 32 | EXPR_UND, 33 | EXPR_NULL, 34 | EXPR_TRUE, 35 | EXPR_FALSE, 36 | EXPR_FUNCPROC, 37 | EXPR_STRING, 38 | 39 | // unary expression 40 | EXPR_NEG, 41 | EXPR_NOT, 42 | EXPR_LOGIC_NOT, 43 | 44 | EXPR_INC, 45 | EXPR_INC_PRE, 46 | EXPR_DEC, 47 | EXPR_DEC_PRE, 48 | 49 | EXPR_ARRAY, 50 | EXPR_DICT, 51 | 52 | // binary expression 53 | EXPR_MUL, 54 | EXPR_DIV, 55 | EXPR_MOD, 56 | EXPR_ADD, 57 | EXPR_SUB, 58 | 59 | EXPR_LSHIFT, 60 | EXPR_RSHIFT, 61 | 62 | EXPR_AND, 63 | EXPR_OR, 64 | EXPR_XOR, 65 | 66 | EXPR_TNE, 67 | EXPR_TEQ, 68 | EXPR_TGT, 69 | EXPR_TGE, 70 | EXPR_TLT, 71 | EXPR_TLE, 72 | EXPR_TIN, 73 | 74 | EXPR_LOGIC_AND, 75 | EXPR_LOGIC_OR, 76 | 77 | EXPR_ASSIGN, 78 | EXPR_ADD_ASSIGN, 79 | EXPR_SUB_ASSIGN, 80 | EXPR_MUL_ASSIGN, 81 | EXPR_DIV_ASSIGN, 82 | EXPR_MOD_ASSIGN, 83 | EXPR_AND_ASSIGN, 84 | EXPR_OR_ASSIGN, 85 | EXPR_XOR_ASSIGN, 86 | EXPR_NOT_ASSIGN, 87 | EXPR_LSHIFT_ASSIGN, 88 | EXPR_RSHIFT_ASSIGN, 89 | 90 | EXPR_COMMA, 91 | 92 | EXPR_PROP, 93 | EXPR_ELEM, 94 | EXPR_CALL, 95 | 96 | EXPR_TERNARY, 97 | 98 | // form 99 | EXPR_FUNCDEF, 100 | EXPR_FUNCHEAD, 101 | EXPR_PAIR, 102 | 103 | EXPR_DUMMY 104 | }; 105 | 106 | enum STMT_TYPE { 107 | STMT_EXPR, 108 | STMT_IF, 109 | STMT_VAR, 110 | STMT_RET, 111 | STMT_WHILE, 112 | STMT_BREAK, 113 | STMT_CONTINUE, 114 | STMT_THROW, 115 | STMT_TRY, 116 | STMT_PASS, 117 | }; 118 | 119 | struct expr_t; 120 | typedef struct stmt_t { 121 | int type; 122 | 123 | struct expr_t *expr; 124 | struct stmt_t *block; 125 | struct stmt_t *other; 126 | 127 | struct stmt_t *next; 128 | } stmt_t; 129 | 130 | typedef struct expr_t { 131 | int type; 132 | int line, col; 133 | union { 134 | union { 135 | char *str; 136 | double num; 137 | stmt_t *proc; 138 | } data; 139 | struct { 140 | struct expr_t *lft; 141 | struct expr_t *rht; 142 | } child; 143 | } body; 144 | } expr_t; 145 | 146 | 147 | static inline const char * ast_expr_text(expr_t *e) { 148 | return e->body.data.str; 149 | } 150 | 151 | static inline double ast_expr_num(expr_t *e) { 152 | return e->body.data.num; 153 | } 154 | 155 | static inline stmt_t * ast_expr_stmt(expr_t *e) { 156 | return e->body.data.proc; 157 | } 158 | 159 | static inline int ast_expr_type(expr_t *e) { 160 | return e->type; 161 | } 162 | 163 | static inline expr_t *ast_expr_lft(expr_t *e) { 164 | return e->body.child.lft; 165 | } 166 | 167 | static inline expr_t *ast_expr_rht(expr_t *e) { 168 | return e->body.child.rht; 169 | } 170 | 171 | static inline void ast_expr_set_lft(expr_t *e, expr_t *lft) { 172 | e->body.child.lft = lft; 173 | } 174 | 175 | static inline void ast_expr_set_rht(expr_t *e, expr_t *rht) { 176 | e->body.child.rht = rht; 177 | } 178 | 179 | void ast_traveral_expr(expr_t *e, void (*cb)(void *, expr_t *), void *ud); 180 | 181 | #endif /* __LANG_AST_INC__ */ 182 | 183 | -------------------------------------------------------------------------------- /cunit/CUnit_Basic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CUnit - A Unit testing framework library for C. 3 | * Copyright (C) 2004-2006 Jerry St.Clair 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | */ 19 | 20 | /* 21 | * Interface for simple test runner. 22 | * 23 | * 11-Aug-2004 Initial implementation of basic test runner interface. (JDS) 24 | */ 25 | 26 | /** @file 27 | * Basic interface with output to stdout. 28 | */ 29 | /** @addtogroup Basic 30 | * @{ 31 | */ 32 | 33 | #ifndef CUNIT_BASIC_H_SEEN 34 | #define CUNIT_BASIC_H_SEEN 35 | 36 | #include "CUnit.h" 37 | #include "CUnit_TestDB.h" 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | /** Run modes for the basic interface. */ 44 | typedef enum { 45 | CU_BRM_NORMAL = 0, /**< Normal mode - failures and run summary are printed [default]. */ 46 | CU_BRM_SILENT, /**< Silent mode - no output is printed except framework error messages. */ 47 | CU_BRM_VERBOSE /**< Verbose mode - maximum output of run details. */ 48 | } CU_BasicRunMode; 49 | 50 | CU_EXPORT CU_ErrorCode CU_basic_run_tests(void); 51 | /**< 52 | * Runs all registered CUnit tests using the basic interface. 53 | * The default CU_BasicRunMode is used unless it has been 54 | * previously changed using CU_basic_set_mode(). The CUnit test 55 | * registry must have been initialized before calling this function. 56 | * 57 | * @return A CU_ErrorCode indicating the framework error condition, including 58 | * CUE_NOREGISTRY - Registry has not been initialized. 59 | */ 60 | 61 | CU_EXPORT CU_ErrorCode CU_basic_run_suite(CU_pSuite pSuite); 62 | /**< 63 | * Runs all tests for a specific suite in the basic interface. 64 | * If pSuite is NULL, the function returns without taking any 65 | * action. The default CU_BasicRunMode is used unless it has 66 | * been changed using CU_basic_set_mode(). 67 | * 68 | * @param pSuite The CU_Suite to run. 69 | * @return A CU_ErrorCode indicating the framework error condition, including 70 | * CUE_NOSUITE - pSuite was NULL. 71 | */ 72 | 73 | CU_EXPORT CU_ErrorCode CU_basic_run_test(CU_pSuite pSuite, CU_pTest pTest); 74 | /**< 75 | * Runs a single test in a specific suite in the basic interface. 76 | * If pSuite or pTest is NULL, the function returns without 77 | * taking any action. The default CU_BasicRunMode is used unless 78 | * it has been changed using CU_basic_set_mode. 79 | * 80 | * @param pSuite The CU_Suite holding the CU_Test to run. 81 | * @param pTest The CU_Test to run. 82 | * @return A CU_ErrorCode indicating the framework error condition, including 83 | * CUE_NOSUITE - pSuite was NULL. 84 | * CUE_NOTEST - pTest was NULL. 85 | */ 86 | 87 | CU_EXPORT void CU_basic_set_mode(CU_BasicRunMode mode); 88 | /**< Sets the run mode for the basic interface. 89 | * @param mode The new CU_BasicRunMode for subsequent test 90 | * runs using the basic interface. 91 | */ 92 | 93 | CU_EXPORT CU_BasicRunMode CU_basic_get_mode(void); 94 | /**< Retrieves the current run mode for the basic interface. 95 | * @return The current CU_BasicRunMode setting for test 96 | * runs using the basic interface. 97 | */ 98 | 99 | CU_EXPORT void CU_basic_show_failures(CU_pFailureRecord pFailure); 100 | /**< 101 | * Prints a summary of run failures to stdout. 102 | * This is provided for user convenience upon request, and does 103 | * not take into account the current run mode. The failures are 104 | * printed to stdout independent of the most recent run mode. 105 | * 106 | * @param pFailure List of CU_pFailureRecord's to output. 107 | */ 108 | 109 | #ifdef __cplusplus 110 | } 111 | #endif 112 | #endif /* CUNIT_BASIC_H_SEEN */ 113 | /** @} */ 114 | -------------------------------------------------------------------------------- /cunit/CUnit_Mem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CUnit - A Unit testing framework library for C. 3 | * Copyright (C) 2001 Anil Kumar 4 | * Copyright (C) 2004-2006 Anil Kumar, Jerry St.Clair 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | /* 22 | * Contains Memory Related Defines to use internal routines to detect Memory Leak 23 | * in Debug Versions 24 | * 25 | * 18/Jun/2002 Memory Debug Functions. (AK) 26 | * 27 | * 17-Jul-2004 New interface for global function names. (JDS) 28 | * 29 | * 05-Sep-2004 Added internal test interface. (JDS) 30 | */ 31 | 32 | /** @file 33 | * Memory management functions (user interface). 34 | * Two versions of memory allocation/deallocation are available. 35 | * If compiled with MEMTRACE defined, CUnit keeps track of all 36 | * system allocations & deallocations. The memory record can 37 | * then be reported using CU_CREATE_MEMORY_REPORT. Otherwise, 38 | * standard system memory allocation is used without tracing. 39 | */ 40 | /** @addtogroup Framework 41 | * @{ 42 | */ 43 | 44 | #ifndef CUNIT_MYMEM_H_SEEN 45 | #define CUNIT_MYMEM_H_SEEN 46 | 47 | #ifdef __cplusplus 48 | extern "C" { 49 | #endif 50 | 51 | #ifdef MEMTRACE 52 | void* CU_calloc(size_t nmemb, size_t size, unsigned int uiLine, const char* szFileName); 53 | void* CU_malloc(size_t size, unsigned int uiLine, const char* szFileName); 54 | void CU_free(void *ptr, unsigned int uiLine, const char* szFileName); 55 | void* CU_realloc(void *ptr, size_t size, unsigned int uiLine, const char* szFileName); 56 | CU_EXPORT void CU_dump_memory_usage(const char*); 57 | 58 | /** c-allocate with memory tracking. */ 59 | #define CU_CALLOC(x, y) CU_calloc((x), (y), __LINE__, __FILE__) 60 | /** m-allocate with memory tracking. */ 61 | #define CU_MALLOC(x) CU_malloc((x), __LINE__, __FILE__) 62 | /** Free with memory tracking. */ 63 | #define CU_FREE(x) CU_free((x), __LINE__, __FILE__) 64 | /** Reallocate with memory tracking. */ 65 | #define CU_REALLOC(x, y) CU_realloc((x), (y), __LINE__, __FILE__) 66 | /** Generate report on tracked memory. */ 67 | #define CU_CREATE_MEMORY_REPORT(x) CU_dump_memory_usage((x)) 68 | /** Generate report on tracked memory (old macro). */ 69 | #define CU_DUMP_MEMORY_USAGE(x) CU_dump_memory_usage((x)) 70 | #else /* MEMTRACE */ 71 | /** Standard calloc() if MEMTRACE not defined. */ 72 | #define CU_CALLOC(x, y) calloc((x), (y)) 73 | /** Standard malloc() if MEMTRACE not defined. */ 74 | #define CU_MALLOC(x) malloc((x)) 75 | /** Standard free() if MEMTRACE not defined. */ 76 | #define CU_FREE(x) free((x)) 77 | /** Standard realloc() if MEMTRACE not defined. */ 78 | #define CU_REALLOC(x, y) realloc((x), (y)) 79 | /** No-op if MEMTRACE not defined. */ 80 | #define CU_CREATE_MEMORY_REPORT(x) 81 | /** No-op if MEMTRACE not defined. */ 82 | #define CU_DUMP_MEMORY_USAGE(x) 83 | #endif /* MEMTRACE */ 84 | 85 | #ifdef CUNIT_BUILD_TESTS 86 | /** Disable memory allocation for testing purposes. */ 87 | void test_cunit_deactivate_malloc(void); 88 | /** Enable memory allocation for testing purposes. */ 89 | void test_cunit_activate_malloc(void); 90 | /** Retrieve number of memory events for a given pointer */ 91 | unsigned int test_cunit_get_n_memevents(void* pLocation); 92 | /** Retrieve number of allocations for a given pointer */ 93 | unsigned int test_cunit_get_n_allocations(void* pLocation); 94 | /** Retrieve number of deallocations for a given pointer */ 95 | unsigned int test_cunit_get_n_deallocations(void* pLocation); 96 | 97 | void test_cunit_MyMem(void); 98 | #endif /* CUNIT_BUILD_TESTS */ 99 | 100 | #ifdef __cplusplus 101 | } 102 | #endif 103 | #endif /* CUNIT_MYMEM_H_SEEN */ 104 | /** @} */ 105 | -------------------------------------------------------------------------------- /lang/executable.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | 22 | #ifndef __LANG_EXECUTABLE_INC__ 23 | #define __LANG_EXECUTABLE_INC__ 24 | 25 | #include "def.h" 26 | #include "val.h" 27 | 28 | #define FUNC_HEAD_SIZE 8 29 | 30 | #define EXEC_FL_BE 1 31 | #define EXEC_FL_64 2 32 | 33 | typedef struct executable_t { 34 | uint16_t string_max; 35 | uint16_t string_num; 36 | 37 | uint16_t number_max; 38 | uint16_t number_num; 39 | 40 | uint16_t func_max; 41 | uint16_t func_num; 42 | 43 | double *number_map; 44 | intptr_t *string_map; 45 | uint8_t **func_map; 46 | 47 | uint32_t main_code_end; 48 | uint32_t func_code_end; 49 | 50 | uint8_t *code; 51 | } executable_t; 52 | 53 | typedef struct image_info_t { 54 | int8_t error; 55 | uint8_t addr_size; 56 | uint8_t byte_order; 57 | uint8_t version; 58 | 59 | uint32_t size; 60 | uint32_t end; 61 | 62 | uint32_t num_cnt, num_ent; 63 | uint32_t str_cnt, str_ent; 64 | uint32_t fn_cnt, fn_ent; 65 | 66 | uint8_t *base; 67 | } image_info_t; 68 | 69 | 70 | int executable_init(executable_t *exe, void *memory, int size, 71 | int number_max, int string_max, int func_max, int code_max); 72 | 73 | static inline 74 | void executable_main_clr(executable_t *exe) 75 | { 76 | exe->main_code_end = 0; 77 | } 78 | 79 | int executable_func_set_head(void *buf, uint8_t vc, uint8_t ac, uint32_t code_size, uint16_t stack_size, int closure); 80 | int executable_func_get_head(void *buf, uint8_t *vc, uint8_t *ac, uint32_t *code_size, uint16_t *stack_size, int *closure); 81 | int executable_main_add(executable_t *exe, void *code, uint16_t size, uint8_t vc, uint8_t ac, uint16_t stack_size, int closure); 82 | int executable_func_add(executable_t *exe, void *code, uint16_t size, uint8_t vc, uint8_t ac, uint16_t stack_size, int closure); 83 | 84 | static inline 85 | uint8_t executable_func_get_var_cnt(const uint8_t *entry) { 86 | return entry[0]; 87 | } 88 | 89 | static inline 90 | uint8_t executable_func_get_arg_cnt(const uint8_t *entry) { 91 | return entry[1]; 92 | } 93 | 94 | static inline 95 | uint16_t executable_func_get_stack_high(const uint8_t *entry) { 96 | return (entry[2] * 0x100 + entry[3]) & 0x7FFF; 97 | } 98 | 99 | static inline 100 | uint32_t executable_func_get_code_size(const uint8_t *entry) { 101 | return (entry[4] * 0x1000000 + entry[5] * 0x10000 + entry[6] * 0x100 + entry[7]); 102 | } 103 | 104 | static inline 105 | const uint8_t *executable_func_get_code(const uint8_t *entry) { 106 | return entry + FUNC_HEAD_SIZE; 107 | } 108 | 109 | static inline 110 | int executable_func_is_closure(const uint8_t *entry) { 111 | return (entry[2] & 0x80) == 0x80; 112 | } 113 | 114 | int executable_number_find_add(executable_t *exe, double n); 115 | int executable_string_find_add(executable_t *exe, intptr_t s); 116 | 117 | int image_init(image_info_t *img, void *mem_ptr, int mem_size, int byte_order, int nc, int sc, int fc); 118 | int image_load(image_info_t *img, uint8_t *input, int size); 119 | int image_fill_data(image_info_t *img, unsigned int nc, double *nv, unsigned int sc, intptr_t *sv); 120 | int image_fill_code(image_info_t *img, unsigned int entry, uint8_t vc, uint8_t ac, uint16_t stack_need, int closure, uint8_t *code, unsigned int size); 121 | double *image_number_entry(image_info_t *img); 122 | double image_get_number(image_info_t *img, int index); 123 | const char *image_get_string(image_info_t *img, int index); 124 | const uint8_t *image_get_function(image_info_t *img, int index); 125 | 126 | static inline int image_size(image_info_t *img) { 127 | return img->end; 128 | } 129 | 130 | #endif /* __LANG_EXECUTABLE_INC__ */ 131 | 132 | -------------------------------------------------------------------------------- /test/test_lang_val.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include 21 | #include 22 | 23 | #include "cunit/CUnit.h" 24 | #include "cunit/CUnit_Basic.h" 25 | 26 | #include "lang/val.h" 27 | 28 | static int test_setup() 29 | { 30 | return 0; 31 | } 32 | 33 | static int test_clean() 34 | { 35 | return 0; 36 | } 37 | 38 | static void test_val_make(void) 39 | { 40 | val_t v; 41 | 42 | v = val_mk_undefined(); 43 | CU_ASSERT(!val_is_number(&v)); 44 | CU_ASSERT(!val_is_boolean(&v)); 45 | CU_ASSERT(val_is_undefined(&v)); 46 | CU_ASSERT(!val_is_function(&v)); 47 | CU_ASSERT(!val_is_string(&v)); 48 | CU_ASSERT(!val_is_array(&v)); 49 | CU_ASSERT(!val_is_object(&v)); 50 | CU_ASSERT(!val_is_nan(&v)); 51 | CU_ASSERT(!val_is_true(&v)); 52 | 53 | v = val_mk_nan(); 54 | CU_ASSERT(!val_is_number(&v)); 55 | CU_ASSERT(!val_is_boolean(&v)); 56 | CU_ASSERT(!val_is_undefined(&v)); 57 | CU_ASSERT(!val_is_function(&v)); 58 | CU_ASSERT(!val_is_string(&v)); 59 | CU_ASSERT(!val_is_array(&v)); 60 | CU_ASSERT(!val_is_object(&v)); 61 | CU_ASSERT(val_is_nan(&v)); 62 | CU_ASSERT(!val_is_true(&v)); 63 | 64 | v = val_mk_boolean(1); 65 | CU_ASSERT(!val_is_number(&v)); 66 | CU_ASSERT(!val_is_nan(&v)); 67 | CU_ASSERT(val_is_boolean(&v)); 68 | CU_ASSERT(!val_is_undefined(&v)); 69 | CU_ASSERT(!val_is_function(&v)); 70 | CU_ASSERT(!val_is_string(&v)); 71 | CU_ASSERT(!val_is_array(&v)); 72 | CU_ASSERT(!val_is_object(&v)); 73 | CU_ASSERT(val_is_true(&v)); 74 | 75 | v = val_mk_boolean(0); 76 | CU_ASSERT(!val_is_true(&v)); 77 | 78 | v = val_mk_number(1.1); 79 | CU_ASSERT(val_is_number(&v)); 80 | CU_ASSERT(!val_is_boolean(&v)); 81 | CU_ASSERT(!val_is_undefined(&v)); 82 | CU_ASSERT(!val_is_function(&v)); 83 | CU_ASSERT(!val_is_string(&v)); 84 | CU_ASSERT(!val_is_array(&v)); 85 | CU_ASSERT(!val_is_object(&v)); 86 | CU_ASSERT(!val_is_nan(&v)); 87 | CU_ASSERT(1 == val_2_integer(&v)); 88 | CU_ASSERT(1.1 == val_2_double(&v)); 89 | CU_ASSERT(val_is_true(&v)); 90 | v = val_mk_number(0.0); 91 | CU_ASSERT(!val_is_true(&v)); 92 | v = val_mk_number(-0.0); 93 | CU_ASSERT(!val_is_true(&v)); 94 | v = val_mk_number(0.0000000001); 95 | CU_ASSERT(val_is_true(&v)); 96 | 97 | v = val_mk_script(1); 98 | CU_ASSERT(val_is_script(&v)); 99 | CU_ASSERT(!val_is_native(&v)); 100 | CU_ASSERT(val_is_function(&v)); 101 | v = val_mk_native(1); 102 | CU_ASSERT(val_is_native(&v)); 103 | CU_ASSERT(!val_is_script(&v)); 104 | CU_ASSERT(val_is_function(&v)); 105 | 106 | v = val_mk_foreign_string(1); 107 | CU_ASSERT(val_is_string(&v)); 108 | CU_ASSERT(val_is_foreign_string(&v)); 109 | CU_ASSERT(!val_is_heap_string(&v)); 110 | CU_ASSERT(!val_is_inline_string(&v)); 111 | 112 | v = val_mk_heap_string(1); 113 | CU_ASSERT(val_is_string(&v)); 114 | CU_ASSERT(!val_is_foreign_string(&v)); 115 | CU_ASSERT(val_is_heap_string(&v)); 116 | CU_ASSERT(!val_is_inline_string(&v)); 117 | } 118 | 119 | static void test_val_set(void) 120 | { 121 | val_t v; 122 | 123 | val_set_number(&v, 1.1); 124 | CU_ASSERT(v == val_mk_number(1.1)); 125 | 126 | val_set_undefined(&v); 127 | CU_ASSERT(v == val_mk_undefined()); 128 | 129 | val_set_nan(&v); 130 | CU_ASSERT(v == val_mk_nan()); 131 | 132 | val_set_boolean(&v, 1); 133 | CU_ASSERT(v == val_mk_boolean(1)); 134 | } 135 | 136 | CU_pSuite test_lang_val_entry() 137 | { 138 | CU_pSuite suite = CU_add_suite("lang value", test_setup, test_clean); 139 | 140 | if (suite) { 141 | CU_add_test(suite, "value make", test_val_make); 142 | CU_add_test(suite, "value set", test_val_set); 143 | } 144 | 145 | return suite; 146 | } 147 | 148 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # panda简介 2 | 3 | panda是脚本语言解释器,它基于javascript,但裁剪了部分语法特性; 4 | 5 | panda是轻量级语言,它被设计用来作为嵌入式硬件的解释器; 6 | 7 | panda很容易学习。 8 | 9 | ## 动手操作 10 | 11 | 首先,需要一个解释器来执行你编写的脚本,目前有几种方式: 12 | 13 | 1. 在Mac或Pc机上运行panda的交互解释器(源代码编译生成) 14 | 2. 通过Mac或Pc连接到安装了cupkee OS的硬件板(这种方式下,你将能够直接操作硬件,更多内容请参考cupkee相关资料) 15 | 16 | 解释器在显示出一个漂亮(丑陋)的logo后,开始等待用户输入。 17 | 你可以键入panda/javascript语句,解释器将进行语法解析、编译为字节码、解释执行,最后将执行结果通过终端返回。 18 | 19 | 如果你使用panda交互解释器,看到的输出大概就是下面的样子 20 | 21 | ``` 22 | $ panda/repl 23 | > 24 | ``` 25 | 26 | ## 编译panda解释器 27 | 28 | ### 获取源代码 29 | ``` 30 | cd your_workspace_path 31 | git clone https://github.com/cupkee/panda.git 32 | ``` 33 | 34 | ### 编译 35 | 36 | 在编译panda之前,你需要安装gcc编译器以及libreadline库 37 | 38 | 编译步骤: 39 | 40 | 1. 通过终端,进入panda源代码目录 41 | 2. 执行命令 make example 42 | 3. 正常情况下,在panda源代码目录中会出现一个build子目录,这里存放所有编译好的可执行文件 43 | 4. .../panda/build/example/repl 就是我们需要的交互解释器 44 | 45 | ## 把panda用到你自己的项目中 46 | 47 | 正向你所看到的,之前用到的交互解释器只是一个例子程序。 48 | 49 | 你完全可以将panda用到自己的项目中,作为配置解释器、命令行或其它。 50 | 51 | ## bug反馈 52 | 我非常需要实际使用中发现bug的反馈,以便不断对程序进行完善。 53 | 54 | 欢迎你通过以下两种方式提交bug: 55 | 56 | 1. 在github上提交issue(推荐) 57 | 2. 发EMail到bug-report@cupkee.cn 58 | 59 | ## 使用简介 60 | 61 | panda一个裁剪板的javascript解释器,基础语法与javascript相同,非常易于学习掌握 62 | 63 | ### 支持的数据类型 64 | 65 | * undefined类型 66 | * NaN类型 67 | * 布尔类型 68 | * 数值类型 69 | * 字符串类型 70 | * 数组类型 71 | * 对象类型 72 | 73 | ### 基本语句 74 | 75 | #### var语句 - 定义变量 76 | 77 | 1. 定义变量a, b, c 78 | 79 | ``` 80 | var a, b, c 81 | ``` 82 | 83 | 2. 定义变量并赋值 84 | 85 | ``` 86 | var a = 0, b, c = 'hello' 87 | ``` 88 | 89 | #### 表达式语句 90 | 91 | 1. panda解释器在计算表达式时与标准javascript区别 92 | 93 | 不同类型的值进行运算时,不会进行类型转换,直接返回NaN(非数字) 94 | 95 | 2. 运算符 96 | 97 | * ++ -- () [] . 98 | * (单目) - ~ ! 99 | * * / % 100 | * + - 101 | * & | ^ 102 | * << >> 103 | * < > >= <= 104 | * == != 105 | * && || 106 | * = += -= * = /= %= &= |= ^= <<= >>= 107 | * ? : 108 | * , 109 | 110 | 3. 基本表达式举例 111 | 112 | ``` 113 | > 1 + 1 114 | 2 115 | > (10 + 5) * 3 / 5 116 | 9 117 | > 1, 2, 3, 5 + 6 118 | 11 119 | > 1 > 2 120 | false 121 | > 'hello' + 'world' 122 | "helloworld" 123 | > 'a1' < 'b2' 124 | true 125 | > 'hello' + 1 126 | NaN 127 | > 1 * 'hello' 128 | NaN 129 | ... 130 | ``` 131 | 132 | #### if语句 133 | if语句是根据条件选择不同分支处理的语句 134 | 135 | ``` 136 | if (true) { 137 | // always execute 138 | } else { 139 | // never execute 140 | } 141 | 142 | if (a > 100) { 143 | ... 144 | } 145 | ``` 146 | 147 | #### while语句 148 | while语句是进行循环处理的语句 149 | 150 | ``` 151 | while(a++ < 100) { 152 | ... 153 | } 154 | ``` 155 | 156 | #### break语句 157 | break用于跳出循环 158 | 159 | #### continue语句 160 | continue用于跳转到循环条件判断 161 | 162 | #### return语句 163 | return 用于从函数跳出,并可指定返回值 164 | 165 | ### 函数 166 | 167 | 在panda中扩展了javascript定义函数的语法 168 | 169 | #### 定义函数 170 | 171 | 1. 标准的定义方法 172 | 173 | ``` 174 | function fn() { 175 | // statements ... 176 | } 177 | 178 | // 匿名函数 179 | var fn = function () { 180 | // statements ... 181 | } 182 | ``` 183 | 184 | 2. panda扩展语法 185 | 186 | 在panda中提供了def关键字,作为function的别名 187 | 188 | ``` 189 | def fn() { 190 | // statements ... 191 | } 192 | 193 | // 匿名函数 194 | var fn = def () { 195 | } 196 | ``` 197 | 198 | 在panda中定义单语句函数时,可以不带"{}" 199 | 200 | ``` 201 | def fn() return 0; 202 | var fn = def() return 1; 203 | ``` 204 | 205 | #### 调用函数 206 | 207 | panda支持javascript程序中常用的即时调用 208 | 209 | ``` 210 | (def(x, y) { 211 | ... 212 | return x + y; 213 | })(100, 50); // return 150 214 | ``` 215 | 216 | #### 关于new关键字 217 | 218 | 在panda中不支持new的相关语义,但保留new关键字(不要把"new"作为变量或函数名)。 219 | 220 | #### 闭包 221 | 222 | panda支持闭包 223 | 224 | ``` 225 | var fn = (def(n) { 226 | var c = n; 227 | return def() return c++; 228 | })(100); 229 | 230 | fn() // 100 231 | fn() // 101 232 | ``` 233 | 234 | ### 复合数据类型 235 | 236 | * panda中的数组和对象与javascript非常相似,但目前只提供了有限的方法。(一个好消息是:panda是开源代码,你可以随意添加需要的方法) 237 | 238 | * Buffer对象来源于nodejs, panda同样也没有实现完整操作接口 239 | 240 | * Date对象目前没有实现, 但已经在计划之中 241 | 242 | * panda对复合类型的支持还在持续完善中, 参考test和example中的代码了解更多(不用担心,代码非常容易理解) 243 | 244 | 以下是一些使用复合对象的例子 245 | 246 | ``` 247 | /* array example */ 248 | var a = []; // 定义空数组,赋值到变量a 249 | 250 | a.push(1); 251 | a.push('hello'); 252 | a.length(); // 2 253 | a[0] // 1 254 | a[1] // 'hello' 255 | a[2] // undefined 256 | a.shift() // 1 257 | a.length() // 1 258 | a.pop() // 'hello' 259 | a.length() // 0 260 | a[0] // undefined 261 | a.unshift('hi'); 262 | a.push('panda'); 263 | a.length() // 2 264 | a[0] // 'hi' 265 | a[1] // 'panda' 266 | 267 | a.foreach(def(value, index) { 268 | ... 269 | }); 270 | 271 | /* object example */ 272 | var o = {}; // 定义空对象,赋值到变量o 273 | 274 | o.length(); // 0 275 | o.a // undefined 276 | o.a = 1; // 1 277 | o.a // 1 278 | o['a'] // 1 279 | o['a'] = 'hello // 'hello 280 | o['a'] // 'hello 281 | o.length(); // 1 282 | o.foreach(def(key, value) { 283 | ... 284 | }); 285 | 286 | ``` 287 | 288 | ### 定义原生函数 289 | 290 | 请参考test和example中的代码,非常简单。 291 | 292 | 293 | ## 总结和提示 294 | 295 | panda目前已经具备了解释器库的基本特性,而且很容易使用,可以用在很多项目中实现很有意思的功能 296 | 297 | 但以下几点需要注意: 298 | 299 | 1. panda还不完善,接口没有达到稳定状态,后续还将保持更新 300 | 301 | 2. panda首先被设计用在资源有限的嵌入式处理器,最小4k内存就可以工作,但对于大内存条件没有经过良好测试 302 | 303 | 3. panda内建了内存管理和垃圾收集机制,但当前的gc算法对大内存环境没有进行优化,随着内存使用量的增大gc占用的时间会有较大增长 304 | 305 | 4. panda不依赖任何操作系统层的支持, 整合到应用中非常简单,但操作系统提供的高级特性(如:多线程/任务,事件处理)需要集成开发人员处理 306 | 307 | 5. panda被cupkee(一个开源智能硬件操作系统)用来作为解释器,它的特性和开发进度是被cupkee驱动的 308 | 309 | ## 帮助panda成长 310 | 311 | 1. 使用并反馈bug或特性需求 312 | 313 | 2. 为panda提交代码 314 | 315 | 3. 其它你觉得有帮助的任何事 316 | 317 | 318 | -------------------------------------------------------------------------------- /cunit/CUnit_Util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CUnit - A Unit testing framework library for C. 3 | * Copyright (C) 2001 Anil Kumar 4 | * Copyright (C) 2004-2006 Anil Kumar, Jerry St.Clair 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | /* 22 | * Contains Type Definitions for some generic functions used across 23 | * CUnit project files. 24 | * 25 | * 13/Oct/2001 Moved some of the generic functions declarations from 26 | * other files to this one so as to use the functions 27 | * consitently. This file is not included in the distribution 28 | * headers because it is used internally by CUnit. (AK) 29 | * 30 | * 20-Jul-2004 New interface, support for deprecated version 1 names. (JDS) 31 | * 32 | * 5-Sep-2004 Added internal test interface. (JDS) 33 | * 34 | * 17-Apr-2006 Added CU_translated_strlen() and CU_number_width(). 35 | * Removed CUNIT_MAX_STRING_LENGTH - dangerous since not enforced. 36 | * Fixed off-by-1 error in CU_translate_special_characters(), 37 | * modifying implementation & results in some cases. User can 38 | * now tell if conversion failed. (JDS) 39 | */ 40 | 41 | /** @file 42 | * Utility functions (user interface). 43 | */ 44 | /** @addtogroup Framework 45 | * @{ 46 | */ 47 | 48 | #ifndef CUNIT_UTIL_H_SEEN 49 | #define CUNIT_UTIL_H_SEEN 50 | 51 | #include "CUnit.h" 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | #define CUNIT_MAX_ENTITY_LEN 5 58 | /**< Maximum number of characters in a translated xml entity. */ 59 | 60 | CU_EXPORT size_t CU_translate_special_characters(const char *szSrc, char *szDest, size_t maxlen); 61 | /**< 62 | * Converts special characters in szSrc to xml entity codes and stores 63 | * result in szDest. Currently conversion of '&', '<', and '>' is supported. 64 | * Note that conversion to entities increases the length of the converted 65 | * string. The greatest conversion size increase would be a string 66 | * consisting entirely of entity characters of converted length 67 | * CUNIT_MAX_ENTITY_LEN. Neither szSrc nor szDest may be NULL 68 | * (checked by assertion).

69 | * 70 | * maxlen gives the maximum number of characters in the translated string. 71 | * If szDest does not have enough room to hold the converted string, the 72 | * return value will be zero and szDest will contain an empty string. 73 | * If this occurs, the remaining characters in szDest may be overwritten 74 | * in an unspecified manner. It is the caller's responsibility to make 75 | * sure there is sufficient room in szDest to hold the converted string. 76 | * CU_translated_strlen() may be used to calculate the length of buffer 77 | * required (remember to add 1 for the terminating \0). 78 | * 79 | * @param szSrc Source string to convert (non-NULL). 80 | * @param szDest Location to hold the converted string (non-NULL). 81 | * @param maxlen Maximum number of characters szDest can hold. 82 | * @return The number of special characters converted (always 0 if 83 | * szDest did not have enough room to hold converted string). 84 | */ 85 | 86 | CU_EXPORT size_t CU_translated_strlen(const char *szSrc); 87 | /**< 88 | * Calculates the length of a translated string. 89 | * This function calculates the buffer length required to hold a string 90 | * after processing with CU_translate_special_characters(). The returned 91 | * length does not include space for the terminating '\0' character. 92 | * szSrc may not be NULL (checked by assertion). 93 | * 94 | * @param szSrc Source string to analyze (non-NULL). 95 | * @return The number of characters szSrc will expand to when converted. 96 | */ 97 | 98 | CU_EXPORT int CU_compare_strings(const char *szSrc, const char *szDest); 99 | /**< 100 | * Case-insensitive string comparison. Neither string pointer 101 | * can be NULL (checked by assertion). 102 | * 103 | * @param szSrc 1st string to compare (non-NULL). 104 | * @param szDest 2nd string to compare (non-NULL). 105 | * @return 0 if the strings are equal, non-zero otherwise. 106 | */ 107 | 108 | CU_EXPORT void CU_trim_left(char *szString); 109 | /**< 110 | * Trims leading whitespace from the specified string. 111 | * @param szString The string to trim. 112 | */ 113 | 114 | CU_EXPORT void CU_trim_right(char *szString); 115 | /**< 116 | * Trims trailing whitespace from the specified string. 117 | * @param szString The string to trim. 118 | */ 119 | 120 | CU_EXPORT void CU_trim(char *szString); 121 | /**< 122 | * Trims leading and trailing whitespace from the specified string. 123 | * @param szString The string to trim. 124 | */ 125 | 126 | CU_EXPORT size_t CU_number_width(int number); 127 | /**< 128 | * Calulates the number of places required to display 129 | * number in decimal. 130 | */ 131 | 132 | #ifdef CUNIT_BUILD_TESTS 133 | void test_cunit_Util(void); 134 | #endif 135 | 136 | #ifdef __cplusplus 137 | } 138 | #endif 139 | 140 | #ifdef USE_DEPRECATED_CUNIT_NAMES 141 | #define CUNIT_MAX_STRING_LENGTH 1024 142 | /**< Maximum string length. */ 143 | #define translate_special_characters(src, dest, len) CU_translate_special_characters(src, dest, len) 144 | /**< Deprecated (version 1). @deprecated Use CU_translate_special_characters(). */ 145 | #define compare_strings(src, dest) CU_compare_strings(src, dest) 146 | /**< Deprecated (version 1). @deprecated Use CU_compare_strings(). */ 147 | 148 | #define trim_left(str) CU_trim_left(str) 149 | /**< Deprecated (version 1). @deprecated Use CU_trim_left(). */ 150 | #define trim_right(str) CU_trim_right(str) 151 | /**< Deprecated (version 1). @deprecated Use CU_trim_right(). */ 152 | #define trim(str) CU_trim(str) 153 | /**< Deprecated (version 1). @deprecated Use CU_trim(). */ 154 | 155 | #endif /* USE_DEPRECATED_CUNIT_NAMES */ 156 | 157 | #endif /* CUNIT_UTIL_H_SEEN */ 158 | /** @} */ 159 | -------------------------------------------------------------------------------- /example/interactive.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include 21 | #include 22 | 23 | #include "example.h" 24 | 25 | #define HEAP_SIZE (1024 * 400) 26 | #define STACK_SIZE (1024) 27 | #define EXE_MEM_SPACE (1024 * 100) 28 | #define SYM_MEM_SPACE (1024 * 4) 29 | #define MEM_SIZE (STACK_SIZE * sizeof(val_t) + HEAP_SIZE + EXE_MEM_SPACE + SYM_MEM_SPACE) 30 | #define INPUT_MAX (1024) 31 | 32 | #define MODE_LINE 0 33 | #define MODE_MULTI 1 34 | 35 | static uint8_t memory[MEM_SIZE]; 36 | static int input_cacahed = 0; 37 | static int input_mode = MODE_LINE; 38 | static char input_buf[INPUT_MAX]; 39 | static int done = 0; 40 | 41 | static const char *logo = "\ 42 | ___ _ \n\ 43 | | _ \\ __ _ _ _ __| | __ _ \n\ 44 | | _// _` || ' \\ / _` |/ _` |\n\ 45 | |_| \\__,_||_||_|\\__,_|\\__,_|\n\ 46 | www.cupkee.cn\n"; 47 | 48 | static void input_read(char *buf, int max) 49 | { 50 | char *input; 51 | 52 | if (input_mode == MODE_MULTI) { 53 | input = readline(". "); 54 | } else { 55 | input = readline("> "); 56 | } 57 | 58 | if (!input) { 59 | done = 1; 60 | return; 61 | } 62 | 63 | if (strlen(input)) { 64 | strncpy(buf, input, max); 65 | add_history(input); 66 | } else { 67 | buf[0] = 0; 68 | } 69 | 70 | free(input); 71 | } 72 | 73 | static char *input_more(void) 74 | { 75 | input_mode = MODE_MULTI; 76 | return NULL; 77 | } 78 | 79 | static void print_error(int error) 80 | { 81 | switch (error) { 82 | case ERR_NotEnoughMemory: output("Error: Not enought memory\n"); break; 83 | case ERR_NotImplemented: output("Error: Not implemented\n"); break; 84 | case ERR_StackOverflow: output("Error: Stack overflow\n"); break; 85 | case ERR_ResourceOutLimit: output("Error: Resource out of limited\n"); break; 86 | 87 | case ERR_InvalidToken: output("Error: Invalid Token\n"); break; 88 | case ERR_InvalidSyntax: output("Error: Invalid syntax\n"); break; 89 | case ERR_InvalidLeftValue: output("Error: Invalid left value\n"); break; 90 | case ERR_InvalidSementic: output("Error: Invalid Sementic\n"); break; 91 | 92 | case ERR_InvalidByteCode: output("Error: Invalid Byte code\n"); break; 93 | case ERR_InvalidInput: output("Error: Invalid input\n"); break; 94 | case ERR_InvalidCallor: output("Error: Invalid callor\n"); break; 95 | case ERR_NotDefinedId: output("Error: Not defined id\n"); break; 96 | 97 | case ERR_SysError: output("Error: System error\n"); break; 98 | 99 | default: output("Error: unknown error\n"); 100 | } 101 | } 102 | 103 | static void print_value(val_t *v) 104 | { 105 | if (!v) { 106 | return; 107 | } 108 | 109 | if (val_is_number(v)) { 110 | char buf[32]; 111 | if (*v & 0xffff) { 112 | snprintf(buf, 32, "%f\n", val_2_double(v)); 113 | } else { 114 | snprintf(buf, 32, "%d\n", (int)val_2_double(v)); 115 | } 116 | output(buf); 117 | } else 118 | if (val_is_boolean(v)) { 119 | output(val_2_intptr(v) ? "true\n" : "false\n"); 120 | } else 121 | if (val_is_string(v)) { 122 | output("\""); 123 | output(val_2_cstring(v)); 124 | output("\"\n"); 125 | } else 126 | if (val_is_undefined(v)) { 127 | output("undefined\n"); 128 | } else 129 | if (val_is_nan(v)) { 130 | output("NaN\n"); 131 | } else 132 | if (val_is_function(v)) { 133 | output("function\n"); 134 | } else { 135 | output("object\n"); 136 | } 137 | } 138 | 139 | static env_t env; 140 | 141 | static void line_proc(void) 142 | { 143 | int err; 144 | val_t *res; 145 | 146 | input_read(input_buf, INPUT_MAX); 147 | 148 | if (done) { 149 | return; 150 | } 151 | 152 | err = interp_execute_interactive(&env, input_buf, input_more, &res); 153 | if (err < 0) { 154 | if (input_mode == MODE_LINE) { 155 | print_error(-err); 156 | } else { 157 | input_cacahed = strlen(input_buf); 158 | } 159 | env_set_error(&env, 0); 160 | } else { 161 | input_mode = MODE_LINE; 162 | if (err > 0) { 163 | print_value(res); 164 | } 165 | } 166 | } 167 | 168 | static void mult_proc(void) 169 | { 170 | int err, len; 171 | val_t *res; 172 | 173 | input_read(input_buf + input_cacahed, INPUT_MAX - input_cacahed); 174 | if (done) { 175 | return; 176 | } 177 | 178 | len = strlen(input_buf + input_cacahed); 179 | if (len > 0) { 180 | input_cacahed += len; 181 | return; 182 | } 183 | 184 | err = interp_execute_string(&env, input_buf, &res); 185 | if (err < 0) { 186 | print_error(-err); 187 | env_set_error(&env, 0); 188 | } else 189 | if (err > 0) { 190 | print_value(res); 191 | } 192 | input_mode = MODE_LINE; 193 | } 194 | 195 | static int interactive(void *mem_ptr, int mem_size, int heap_size, int stack_size) 196 | { 197 | if(0 != interp_env_init_interactive(&env, mem_ptr, mem_size, NULL, heap_size, NULL, stack_size)) { 198 | output("env_init fail\n"); 199 | return -1; 200 | } 201 | 202 | native_init(&env); 203 | 204 | printf(logo, 0, 1, 0); 205 | 206 | while (!done) { 207 | if (input_mode == MODE_MULTI) { 208 | mult_proc(); 209 | } else { 210 | line_proc(); 211 | } 212 | } 213 | 214 | return 0; 215 | } 216 | 217 | int main(int ac, char **av) 218 | { 219 | return interactive(memory, MEM_SIZE, HEAP_SIZE, STACK_SIZE); 220 | } 221 | 222 | -------------------------------------------------------------------------------- /lang/type_string.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include "err.h" 21 | #include "type_object.h" 22 | #include "type_string.h" 23 | 24 | static inline string_t *string_alloc(env_t *env, int size) 25 | { 26 | string_t *s = env_heap_alloc(env, SIZE_ALIGN(sizeof(string_t) + size)); 27 | 28 | if (s) { 29 | s->magic = MAGIC_STRING; 30 | s->age = 0; 31 | s->size = size; 32 | } 33 | return s; 34 | } 35 | 36 | val_t string_create_heap_val(env_t *env, const char *data) 37 | { 38 | string_t *s; 39 | int size = strlen(data); 40 | 41 | size += 1; 42 | s = string_alloc(env, size); 43 | if (s) { 44 | memcpy(s->str, data, size); 45 | return val_mk_heap_string((intptr_t)s); 46 | } 47 | return VAL_UNDEFINED; 48 | } 49 | 50 | /* 51 | void string_add(env_t *env, val_t *a, val_t *b, val_t *res) 52 | { 53 | if (!val_is_string(b)) { 54 | val_set_nan(res); 55 | return; 56 | } 57 | 58 | int size1 = string_len(a); 59 | int size2 = string_len(b); 60 | int len = size1 + size2; 61 | string_t *s = string_alloc(env, len + 1); 62 | 63 | if (s) { 64 | // Todo: length overflow should be check! or variable length field. 65 | memcpy(s->str + 0, val_2_cstring(a), size1); 66 | memcpy(s->str + size1, val_2_cstring(b), size2 + 1); 67 | val_set_heap_string(res, (intptr_t) s); 68 | } else { 69 | env_set_error(env, ERR_NotEnoughMemory); 70 | val_set_undefined(res); 71 | } 72 | } 73 | 74 | void string_elem_get(val_t *self, int i, val_t *elem) 75 | { 76 | const char *s = val_2_cstring(self); 77 | int len = string_len(self); 78 | 79 | if (i >= 0 && i < len) { 80 | val_set_inner_string(elem, s[i]); 81 | } else { 82 | val_set_undefined(elem); 83 | } 84 | } 85 | */ 86 | 87 | static val_t native_index_of(env_t *env, int ac, val_t *av) 88 | { 89 | const char *s, *f; 90 | 91 | if (ac < 2 || NULL == (s = val_2_cstring(av))) { 92 | env_set_error(env, ERR_InvalidInput); 93 | return val_mk_undefined(); 94 | } else 95 | if (NULL == (f = val_2_cstring(av+1))) { 96 | return val_mk_number(-1); 97 | } else { 98 | char *pos = strstr(s, f); 99 | if (pos) { 100 | return val_mk_number(pos - s); 101 | } else { 102 | return val_mk_number(-1); 103 | } 104 | } 105 | } 106 | 107 | static val_t get_length(env_t *env, void *s) 108 | { 109 | (void) env; 110 | return val_mk_number(strlen(s)); 111 | } 112 | 113 | static val_t get_index_of(env_t *env, void *s) 114 | { 115 | (void) env; 116 | (void) s; 117 | return val_mk_native((intptr_t) native_index_of); 118 | } 119 | 120 | static object_prop_t proto[] = { 121 | {(intptr_t)"length", get_length, NULL}, 122 | {(intptr_t)"indexOf", get_index_of, NULL}, 123 | }; 124 | 125 | static int string_inline_is_true(val_t *self) { 126 | return ((const char *)self)[4]; 127 | } 128 | 129 | static int string_inline_compare(val_t *self, val_t *to) { 130 | const char *a = ((const char *)self) + 4; 131 | const char *b = val_2_cstring(to); 132 | 133 | return b ? !strcmp(a, b) : 0; 134 | } 135 | 136 | static int string_heap_is_true(val_t *self) { 137 | return ((const char *) val_2_intptr(self))[4]; 138 | } 139 | 140 | static int string_heap_compare(val_t *self, val_t *to) { 141 | const char *a = (const char *) (val_2_intptr(self) + 4); 142 | const char *b = val_2_cstring(to); 143 | 144 | return b ? !strcmp(a, b) : 0; 145 | } 146 | 147 | static int string_foreign_is_true(val_t *self) { 148 | return ((const char *) val_2_intptr(self))[0]; 149 | } 150 | 151 | static int string_foreign_compare(val_t *self, val_t *to) { 152 | const char *a = (const char *) val_2_intptr(self); 153 | const char *b = val_2_cstring(to); 154 | 155 | return b ? !strcmp(a, b) : 0; 156 | } 157 | 158 | static double value_of_string(val_t *self) 159 | { 160 | const char *s = val_2_cstring(self); 161 | 162 | return *s ? const_nan.d : 0; 163 | } 164 | 165 | static int string_concat(void *hnd, val_t *a, val_t *b, val_t *res) 166 | { 167 | env_t *env = hnd; 168 | 169 | if (!val_is_string(b)) { 170 | val_set_nan(res); 171 | return 0; 172 | } else { 173 | int size1 = string_len(a); 174 | int size2 = string_len(b); 175 | int len = size1 + size2; 176 | string_t *s = string_alloc(env, len + 1); 177 | 178 | if (s) { 179 | // Todo: length overflow should be check! or variable length field. 180 | memcpy(s->str + 0, val_2_cstring(a), size1); 181 | memcpy(s->str + size1, val_2_cstring(b), size2 + 1); 182 | val_set_heap_string(res, (intptr_t) s); 183 | return 0; 184 | } else { 185 | env_set_error(env, ERR_NotEnoughMemory); 186 | val_set_undefined(res); 187 | return -ERR_NotEnoughMemory; 188 | } 189 | } 190 | } 191 | 192 | static val_t string_get_prop(void *env, val_t *self, const char *name) 193 | { 194 | const char *s = val_2_cstring(self); 195 | intptr_t symbal = (intptr_t)name; 196 | 197 | if (s) { 198 | unsigned i; 199 | 200 | for (i = 0; i < sizeof(proto) / sizeof(object_prop_t); i++) { 201 | if (proto[i].symbal == symbal) { 202 | return proto[i].getter(env, (void *)s); 203 | } 204 | } 205 | } 206 | 207 | return VAL_UNDEFINED; 208 | } 209 | 210 | static val_t string_get_elem(void *env, val_t *self, int id) 211 | { 212 | const char *s = val_2_cstring(self); 213 | int len = string_len(self); 214 | 215 | (void) env; 216 | if (id >= 0 && id < len) { 217 | return val_mk_inner_string(s[id]); 218 | } else { 219 | return VAL_UNDEFINED; 220 | } 221 | } 222 | 223 | const val_metadata_t metadata_str_inline = { 224 | .name = "string", 225 | .is_true = string_inline_is_true, 226 | .is_equal = string_inline_compare, 227 | 228 | .value_of = value_of_string, 229 | .get_prop = string_get_prop, 230 | .get_elem = string_get_elem, 231 | 232 | .concat = string_concat, 233 | }; 234 | 235 | const val_metadata_t metadata_str_heap = { 236 | .name = "string", 237 | .is_true = string_heap_is_true, 238 | .is_equal = string_heap_compare, 239 | 240 | .value_of = value_of_string, 241 | .get_prop = string_get_prop, 242 | .get_elem = string_get_elem, 243 | 244 | .concat = string_concat, 245 | }; 246 | 247 | const val_metadata_t metadata_str_foreign = { 248 | .name = "string", 249 | .is_true = string_foreign_is_true, 250 | .is_equal = string_foreign_compare, 251 | 252 | .value_of = value_of_string, 253 | .get_prop = string_get_prop, 254 | .get_elem = string_get_elem, 255 | 256 | .concat = string_concat, 257 | }; 258 | 259 | void string_proto_init(env_t *env) 260 | { 261 | unsigned i; 262 | for (i = 0; i < sizeof(proto) / sizeof(object_prop_t); i++) { 263 | env_symbal_add_static(env, (const char *)proto[i].symbal); 264 | } 265 | } 266 | 267 | -------------------------------------------------------------------------------- /test/test_lang_lex.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #include 22 | #include 23 | 24 | #include "cunit/CUnit.h" 25 | #include "cunit/CUnit_Basic.h" 26 | 27 | #include "test_util.h" 28 | #include "lang/lex.h" 29 | 30 | static int test_setup() 31 | { 32 | return 0; 33 | } 34 | 35 | static int test_clean() 36 | { 37 | return 0; 38 | } 39 | 40 | static void test_common(void) 41 | { 42 | lexer_t lex; 43 | token_t tok; 44 | char *input = "\ 45 | \t \r \n\ 46 | # comments 1\r\n\ 47 | +-*/%\n\ 48 | // comments 2\r\n\ 49 | += -= *= /= %= &= |= ^= ~= >>= <<= >> << && ||\n\ 50 | ' bbbb\" ' \" abcd' &$|!\" \n\ 51 | 12345 09876\n\ 52 | /* comments 3\r\n comments 3 continue*/\ 53 | abc a12 _11 a_b _a_ $1 $_a \n\ 54 | undefined null NaN true false var def return while break continue in if elif else try catch throw\n"; 55 | 56 | CU_ASSERT(0 == lex_init(&lex, input, NULL)); 57 | 58 | CU_ASSERT(lex_match(&lex, '+')); 59 | CU_ASSERT(lex_match(&lex, '-')); 60 | CU_ASSERT(lex_match(&lex, '*')); 61 | CU_ASSERT(lex_match(&lex, '/')); 62 | CU_ASSERT(lex_match(&lex, '%')); 63 | 64 | CU_ASSERT(lex_match(&lex, TOK_ADDASSIGN)); 65 | CU_ASSERT(lex_match(&lex, TOK_SUBASSIGN)); 66 | CU_ASSERT(lex_match(&lex, TOK_MULASSIGN)); 67 | CU_ASSERT(lex_match(&lex, TOK_DIVASSIGN)); 68 | CU_ASSERT(lex_match(&lex, TOK_MODASSIGN)); 69 | CU_ASSERT(lex_match(&lex, TOK_ANDASSIGN)); 70 | CU_ASSERT(lex_match(&lex, TOK_ORASSIGN)); 71 | CU_ASSERT(lex_match(&lex, TOK_XORASSIGN)); 72 | CU_ASSERT(lex_match(&lex, TOK_NOTASSIGN)); 73 | CU_ASSERT(lex_match(&lex, TOK_RSHIFTASSIGN)); 74 | CU_ASSERT(lex_match(&lex, TOK_LSHIFTASSIGN)); 75 | CU_ASSERT(lex_match(&lex, TOK_RSHIFT)); 76 | CU_ASSERT(lex_match(&lex, TOK_LSHIFT)); 77 | CU_ASSERT(lex_match(&lex, TOK_LOGICAND)); 78 | CU_ASSERT(lex_match(&lex, TOK_LOGICOR)); 79 | 80 | CU_ASSERT(TOK_STR == lex_token(&lex, &tok) && 0 == strcmp(tok.text, " bbbb\" ")); 81 | CU_ASSERT(lex_match(&lex, TOK_STR)); 82 | CU_ASSERT(TOK_STR == lex_token(&lex, &tok) && 0 == strcmp(tok.text, " abcd' &$|!")); 83 | CU_ASSERT(lex_match(&lex, TOK_STR)); 84 | 85 | CU_ASSERT(TOK_NUM == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "12345")); 86 | CU_ASSERT(lex_match(&lex, TOK_NUM)); 87 | CU_ASSERT(TOK_NUM == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "09876")); 88 | CU_ASSERT(lex_match(&lex, TOK_NUM)); 89 | 90 | CU_ASSERT(TOK_ID == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "abc")); 91 | CU_ASSERT(lex_match(&lex, TOK_ID)); 92 | CU_ASSERT(TOK_ID == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "a12")); 93 | CU_ASSERT(lex_match(&lex, TOK_ID)); 94 | CU_ASSERT(TOK_ID == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "_11")); 95 | CU_ASSERT(lex_match(&lex, TOK_ID)); 96 | CU_ASSERT(TOK_ID == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "a_b")); 97 | CU_ASSERT(lex_match(&lex, TOK_ID)); 98 | CU_ASSERT(TOK_ID == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "_a_")); 99 | CU_ASSERT(lex_match(&lex, TOK_ID)); 100 | CU_ASSERT(TOK_ID == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "$1")); 101 | CU_ASSERT(lex_match(&lex, TOK_ID)); 102 | CU_ASSERT(TOK_ID == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "$_a")); 103 | CU_ASSERT(lex_match(&lex, TOK_ID)); 104 | 105 | CU_ASSERT(lex_match(&lex, TOK_UND)); 106 | CU_ASSERT(lex_match(&lex, TOK_NULL)); 107 | CU_ASSERT(lex_match(&lex, TOK_NAN)); 108 | CU_ASSERT(lex_match(&lex, TOK_TRUE)); 109 | CU_ASSERT(lex_match(&lex, TOK_FALSE)); 110 | CU_ASSERT(lex_match(&lex, TOK_VAR)); 111 | CU_ASSERT(lex_match(&lex, TOK_DEF)); 112 | CU_ASSERT(lex_match(&lex, TOK_RET)); 113 | CU_ASSERT(lex_match(&lex, TOK_WHILE)); 114 | CU_ASSERT(lex_match(&lex, TOK_BREAK)); 115 | CU_ASSERT(lex_match(&lex, TOK_CONTINUE)); 116 | CU_ASSERT(lex_match(&lex, TOK_IN)); 117 | CU_ASSERT(lex_match(&lex, TOK_IF)); 118 | CU_ASSERT(lex_match(&lex, TOK_ELIF)); 119 | CU_ASSERT(lex_match(&lex, TOK_ELSE)); 120 | CU_ASSERT(lex_match(&lex, TOK_TRY)); 121 | CU_ASSERT(lex_match(&lex, TOK_CATCH)); 122 | CU_ASSERT(lex_match(&lex, TOK_THROW)); 123 | 124 | CU_ASSERT(0 == lex_deinit(&lex)); 125 | } 126 | 127 | static void test_mch_tok(void) 128 | { 129 | lexer_t lex; 130 | 131 | CU_ASSERT(0 == lex_init(&lex, "++ -- << >> += -= *= /= %= &= |= ^= != == && ||", NULL)); 132 | 133 | CU_ASSERT(lex_match(&lex, TOK_INC)); 134 | CU_ASSERT(lex_match(&lex, TOK_DEC)); 135 | CU_ASSERT(lex_match(&lex, TOK_LSHIFT)); 136 | CU_ASSERT(lex_match(&lex, TOK_RSHIFT)); 137 | CU_ASSERT(lex_match(&lex, TOK_ADDASSIGN)); 138 | CU_ASSERT(lex_match(&lex, TOK_SUBASSIGN)); 139 | CU_ASSERT(lex_match(&lex, TOK_MULASSIGN)); 140 | CU_ASSERT(lex_match(&lex, TOK_DIVASSIGN)); 141 | CU_ASSERT(lex_match(&lex, TOK_MODASSIGN)); 142 | CU_ASSERT(lex_match(&lex, TOK_ANDASSIGN)); 143 | CU_ASSERT(lex_match(&lex, TOK_ORASSIGN)); 144 | CU_ASSERT(lex_match(&lex, TOK_XORASSIGN)); 145 | CU_ASSERT(lex_match(&lex, TOK_NE)); 146 | CU_ASSERT(lex_match(&lex, TOK_EQ)); 147 | CU_ASSERT(lex_match(&lex, TOK_LOGICAND)); 148 | CU_ASSERT(lex_match(&lex, TOK_LOGICOR)); 149 | } 150 | 151 | static void test_floating_number(void) 152 | { 153 | lexer_t lex; 154 | token_t tok; 155 | 156 | CU_ASSERT(0 == lex_init(&lex, "1.5 1e-3 123E+12 0.1e2", NULL)); 157 | CU_ASSERT(TOK_NUM == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "1.5")); 158 | CU_ASSERT(lex_match(&lex, TOK_NUM)); 159 | 160 | CU_ASSERT(TOK_NUM == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "1E-3")); 161 | CU_ASSERT(lex_match(&lex, TOK_NUM)); 162 | 163 | CU_ASSERT(TOK_NUM == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "123E12")); 164 | CU_ASSERT(lex_match(&lex, TOK_NUM)); 165 | 166 | CU_ASSERT(TOK_NUM == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "0.1E2")); 167 | CU_ASSERT(lex_match(&lex, TOK_NUM)); 168 | } 169 | 170 | static void test_hex_number(void) 171 | { 172 | lexer_t lex; 173 | token_t tok; 174 | 175 | CU_ASSERT(0 == lex_init(&lex, "0x10 0xFF 0Xff 0X01", NULL)); 176 | CU_ASSERT(TOK_NUM == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "0x10")); 177 | CU_ASSERT(lex_match(&lex, TOK_NUM)); 178 | 179 | CU_ASSERT(TOK_NUM == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "0xFF")); 180 | CU_ASSERT(lex_match(&lex, TOK_NUM)); 181 | 182 | CU_ASSERT(TOK_NUM == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "0xff")); 183 | CU_ASSERT(lex_match(&lex, TOK_NUM)); 184 | 185 | CU_ASSERT(TOK_NUM == lex_token(&lex, &tok) && 0 == strcmp(tok.text, "0x01")); 186 | CU_ASSERT(lex_match(&lex, TOK_NUM)); 187 | } 188 | 189 | CU_pSuite test_lang_lex_entry() 190 | { 191 | CU_pSuite suite = CU_add_suite("lang lex", test_setup, test_clean); 192 | 193 | if (suite) { 194 | CU_add_test(suite, "common", test_common); 195 | CU_add_test(suite, "multiCh token", test_mch_tok); 196 | CU_add_test(suite, "floating number", test_floating_number); 197 | CU_add_test(suite, "hex number", test_floating_number); 198 | } 199 | 200 | return suite; 201 | } 202 | 203 | -------------------------------------------------------------------------------- /lang/type_buffer.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | /* 21 | #include "err.h" 22 | #include "type_string.h" 23 | #include "type_buffer.h" 24 | 25 | static inline type_buffer_t *buffer_alloc(env_t *env, int size) 26 | { 27 | type_buffer_t *b = env_heap_alloc(env, SIZE_ALIGN(sizeof(type_buffer_t) + size)); 28 | 29 | if (b) { 30 | b->magic = MAGIC_BUFFER; 31 | b->age = 0; 32 | b->len = size; 33 | } 34 | return b; 35 | } 36 | 37 | type_buffer_t *buffer_create(env_t *env, int size) 38 | { 39 | return buffer_alloc(env, size); 40 | } 41 | 42 | type_buffer_t *buffer_slice(env_t *env, type_buffer_t *b, int start, int size) 43 | { 44 | type_buffer_t *slice; 45 | 46 | if (start < 0) { 47 | start = 0; 48 | } 49 | 50 | if (start + size > b->len) { 51 | size = b->len - start; 52 | if (size < 0) { 53 | size = 0; 54 | } 55 | } 56 | 57 | slice = buffer_alloc(env, size); 58 | if (slice) { 59 | memcpy(slice->buf, b->buf + start, size); 60 | } else { 61 | env_set_error(env, ERR_NotEnoughMemory); 62 | } 63 | return slice; 64 | } 65 | 66 | int buffer_read_int(type_buffer_t *b, int off, int size, int be, int *v) 67 | { 68 | if (off >= 0 && size > 0 && off + size <= b->len) { 69 | int num = 0, i; 70 | int8_t s; 71 | 72 | if (be) { 73 | s = b->buf[off]; 74 | num = s; 75 | for (i = 1; i < size; i++) { 76 | num <<= 8; 77 | num |= b->buf[off + i]; 78 | } 79 | } else { 80 | s = b->buf[off + size - 1]; 81 | num = s; 82 | for (i = size - 2; i > -1; i--) { 83 | num <<= 8; 84 | num |= b->buf[off + i]; 85 | } 86 | } 87 | *v = num; 88 | return off + size; 89 | } else { 90 | return 0; 91 | } 92 | } 93 | 94 | int buffer_write_int(type_buffer_t *b, int off, int size, int be, int num) 95 | { 96 | if (off >= 0 && size > 0 && off + size <= b->len) { 97 | int i; 98 | 99 | if (be) { 100 | b->buf[off + size - 1] = num; 101 | for (i = size - 2; i > -1; i--) { 102 | num >>= 8; 103 | b->buf[off + i] = num; 104 | } 105 | } else { 106 | b->buf[off] = num; 107 | for (i = 1; i < size; i++) { 108 | num >>= 8; 109 | b->buf[off + i] = num; 110 | } 111 | } 112 | 113 | return off + size; 114 | } else { 115 | return 0; 116 | } 117 | } 118 | 119 | val_t buffer_native_create(env_t *env, int ac, val_t *av) 120 | { 121 | int size = 8; // define a default size 122 | void *data = NULL; 123 | type_buffer_t *buf; 124 | 125 | if (ac > 0) { 126 | if (val_is_number(av)) { 127 | size = val_2_integer(av); 128 | } else { 129 | data = (void *)val_2_cstring(av); 130 | if (data) { 131 | size = strlen(data); 132 | } 133 | } 134 | } 135 | 136 | buf = buffer_alloc(env, size); 137 | if (buf) { 138 | if (data) { 139 | memcpy(buf->buf, data, size); 140 | } 141 | return val_mk_buffer(buf); 142 | } else { 143 | env_set_error(env, ERR_NotEnoughMemory); 144 | return VAL_UNDEFINED; 145 | } 146 | } 147 | 148 | static void param_parse(int ac, val_t *av, int *off, int *size, int *be) 149 | { 150 | *off = 0; 151 | *size = 1; 152 | *be = 0; 153 | 154 | if (ac > 0 && val_is_number(av)) { 155 | *off = val_2_integer(av); 156 | if (ac > 1 && val_is_number(av + 1)) { 157 | *size = val_2_integer(av + 1); 158 | if (*size > 1 && ac > 2 && val_is_true(av + 2)) { 159 | *be = 1; 160 | } 161 | } 162 | } 163 | } 164 | 165 | val_t buffer_native_read_int(env_t *env, int ac, val_t *av) 166 | { 167 | type_buffer_t *buf = NULL; 168 | int off = 0, size = 1, be = 0, num; 169 | 170 | (void) env; 171 | 172 | if (ac < 1 || !val_is_buffer(av)) { 173 | return VAL_UNDEFINED; 174 | } 175 | buf = (type_buffer_t *) val_2_intptr(av); 176 | 177 | param_parse(ac - 1, av + 1, &off, &size, &be); 178 | if (!buffer_read_int(buf, off, size, be, &num)) { 179 | return VAL_UNDEFINED; 180 | } else { 181 | return val_mk_number(num); 182 | } 183 | } 184 | 185 | val_t buffer_native_write_int(env_t *env, int ac, val_t *av) 186 | { 187 | type_buffer_t *buf = NULL; 188 | int off = 0, size = 1, be = 0, num; 189 | 190 | (void) env; 191 | 192 | if (ac < 2 || !val_is_buffer(av) || !val_is_number(av + 1)) { 193 | return val_mk_number(0); 194 | } 195 | 196 | buf = (type_buffer_t *) val_2_intptr(av); 197 | num = val_2_integer(av + 1); 198 | 199 | param_parse(ac - 2, av + 2, &off, &size, &be); 200 | if ((off = buffer_write_int(buf, off, size, be, num)) > 0) { 201 | return val_mk_number(off); 202 | } else { 203 | return val_mk_number(0); 204 | } 205 | } 206 | 207 | val_t buffer_native_to_string(env_t *env, int ac, val_t *av) 208 | { 209 | type_buffer_t *buf; 210 | uint8_t *ptr; 211 | void *str; 212 | val_t s; 213 | int len; 214 | 215 | if (ac < 1 || !val_is_buffer(av)) { 216 | env_set_error(env, ERR_InvalidInput); 217 | return VAL_UNDEFINED; 218 | } 219 | 220 | buf = (type_buffer_t *)val_2_intptr(av); 221 | for (len = 0; len < buf->len; len++) { 222 | uint8_t ch = buf->buf[len]; 223 | if (ch < ' ' || ch >= 127) { 224 | break; 225 | } 226 | } 227 | 228 | s = string_create_heap_val(env, len); 229 | str = (void *)val_2_cstring(&s); 230 | if (str && len) { 231 | // defence GC 232 | buf = (type_buffer_t *)val_2_intptr(av); 233 | ptr = buf->buf; 234 | 235 | memcpy(str, ptr, len); 236 | } 237 | 238 | return s; 239 | } 240 | 241 | val_t buffer_native_slice(env_t *env, int ac, val_t *av) 242 | { 243 | type_buffer_t *buf, *slice; 244 | int start = 0, end = -1; 245 | 246 | if (ac < 1 || !val_is_buffer(av)) { 247 | env_set_error(env, ERR_InvalidInput); 248 | return VAL_UNDEFINED; 249 | } 250 | 251 | buf = (type_buffer_t *)val_2_intptr(av); 252 | if (ac > 1 && val_is_number(av + 1)) { 253 | start = val_2_integer(av + 1); 254 | if (ac > 2 && val_is_number(av + 2)) { 255 | end = val_2_integer(av + 2); 256 | } 257 | } 258 | 259 | if (end < 0) { 260 | end = buf->len; 261 | } 262 | 263 | if (start > end) { 264 | end = start; 265 | } 266 | 267 | slice = buffer_slice(env, buf, start, end - start); 268 | if (slice) { 269 | return val_mk_buffer(slice); 270 | } else { 271 | return VAL_UNDEFINED; 272 | } 273 | } 274 | 275 | void buffer_elem_get(val_t *self, int index, val_t *elem) 276 | { 277 | type_buffer_t *buf; 278 | 279 | buf = (type_buffer_t *)val_2_intptr(self); 280 | if (index >= 0 && index < buf->len) { 281 | val_set_number(elem, buf->buf[index]); 282 | } else { 283 | val_set_undefined(elem); 284 | } 285 | } 286 | 287 | */ 288 | -------------------------------------------------------------------------------- /lang/env.h: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | 21 | #ifndef __LANG_ENV_INC__ 22 | #define __LANG_ENV_INC__ 23 | 24 | #include "def.h" 25 | 26 | #include "val.h" 27 | #include "err.h" 28 | #include "heap.h" 29 | #include "executable.h" 30 | #include "scope.h" 31 | 32 | #define PANDA_EVENT_GC_START 1 33 | #define PANDA_EVENT_GC_END 2 34 | 35 | struct native_t; 36 | 37 | typedef struct env_t { 38 | int16_t error; 39 | int16_t main_var_num; 40 | 41 | int fp; 42 | int ss; 43 | int sp; 44 | val_t *sb; 45 | 46 | scope_t *scope; // Root scope 47 | 48 | heap_t *heap; // inused heap ptr: top or bot 49 | heap_t heap_top; 50 | heap_t heap_bot; 51 | 52 | uint16_t ref_num; // External reference number 53 | uint16_t native_num; // Native function number 54 | 55 | uint16_t symbal_tbl_size; // Symbal hash table size 56 | uint16_t symbal_tbl_hold; // Symbal saved counter 57 | uint16_t symbal_buf_end; // Symbal buffer size 58 | uint16_t symbal_buf_used; // Symbal buffer used 59 | 60 | intptr_t *symbal_tbl; 61 | char *symbal_buf; 62 | val_t *ref_ent; // External reference entry 63 | const struct native_t *native_ent; // Native function entry 64 | 65 | intptr_t *main_var_map; 66 | 67 | void (*callback)(struct env_t *, int); 68 | 69 | executable_t exe; 70 | } env_t; 71 | 72 | typedef struct native_t { 73 | const char *name; 74 | val_t (*fn)(env_t *, int ac, val_t *av); 75 | } native_t; 76 | 77 | 78 | int env_exe_memery_distribute(int mem_size, int *num_max, int *str_max, int *fn_max, int *code_max); 79 | int env_init(env_t *env, void * mem_ptr, int mem_size, 80 | void *heap_ptr, int heap_size, val_t *stack_ptr, int stack_size, 81 | int number_max, int string_max, int func_max, int code_max, 82 | int interactive); 83 | 84 | int env_deinit(env_t *env); 85 | int env_reference_set(env_t *env, val_t *ent, int num); 86 | int env_callback_set(env_t *env, void (*cb)(env_t *, int)); 87 | int env_native_set(env_t *env, const native_t *ent, int num); 88 | 89 | void env_heap_gc(env_t *env, int level); 90 | 91 | scope_t *env_scope_create(env_t *env, scope_t *super, uint8_t *entry, int ac, val_t *av); 92 | int env_scope_get(env_t *env, int id, val_t **v); 93 | int env_scope_set(env_t *env, int id, val_t *v); 94 | 95 | static inline void *env_heap_alloc(env_t *env, int size) { 96 | void *ptr = heap_alloc(env->heap, size); 97 | 98 | if (!ptr) { 99 | env_heap_gc(env, size); 100 | return heap_alloc(env->heap, size); 101 | } 102 | 103 | return ptr; 104 | } 105 | 106 | intptr_t env_symbal_insert(env_t *env, const char *symbal, int alloc); 107 | intptr_t env_symbal_get(env_t *env, const char *name); 108 | static inline 109 | intptr_t env_symbal_add(env_t *env, const char *name) { 110 | return env_symbal_insert(env, name, 1); 111 | } 112 | static inline 113 | intptr_t env_symbal_add_static(env_t *env, const char *name) { 114 | return env_symbal_insert(env, name, 0); 115 | } 116 | void env_symbal_foreach(env_t *env, int (*cb)(const char *, void *), void *param); 117 | 118 | int env_string_find_add(env_t *env, intptr_t s); 119 | int env_number_find_add(env_t *env, double); 120 | 121 | int env_native_find(env_t *env, intptr_t sym_id); 122 | 123 | const uint8_t *env_frame_setup(env_t *env, const uint8_t *pc, val_t *fv, int ac, val_t *av); 124 | const uint8_t *env_func_entry_setup(env_t *env, uint8_t *entry, int ac, val_t *av); 125 | void env_frame_restore(env_t *env, const uint8_t **pc, scope_t **scope); 126 | void env_native_call(env_t *env, val_t *fv, int ac, val_t *av); 127 | 128 | const uint8_t *env_main_entry_setup(env_t *env, int ac, val_t *av); 129 | const uint8_t *env_entry_setup(env_t *env, uint8_t *entry, int ac, val_t *av); 130 | 131 | static inline 132 | void env_set_error(env_t *env, int error) { 133 | if (env) env->error = error; 134 | } 135 | 136 | static inline val_t *env_stack_peek(env_t *env) { 137 | return env->sb + env->sp; 138 | } 139 | 140 | static inline val_t *env_stack_pop(env_t *env) { 141 | return env->sb + env->sp++; 142 | } 143 | 144 | static inline val_t *env_stack_push(env_t *env) { 145 | return env->sb + (--env->sp); 146 | } 147 | 148 | static inline val_t *env_stack_release(env_t *env, int n) { 149 | env->sp += n; 150 | return env->sb + env->sp; 151 | } 152 | 153 | static inline void env_push_call_argument(env_t *env, val_t *v) { 154 | *env_stack_push(env) = *v; 155 | } 156 | 157 | static inline void env_push_call_function(env_t *env, val_t *v) { 158 | *env_stack_push(env) = *v; 159 | } 160 | 161 | static inline val_t *env_get_var(env_t *env, uint8_t id, uint8_t generation) { 162 | scope_t *scope = env->scope; 163 | 164 | while(scope && generation--) { 165 | scope = scope->super; 166 | } 167 | 168 | if (scope && id < scope->num) { 169 | return scope->var_buf + id; 170 | } else { 171 | return NULL; 172 | } 173 | } 174 | 175 | static inline void env_push_var(env_t *env, uint8_t id, uint8_t generation) { 176 | val_t *v = env_get_var(env, id, generation); 177 | 178 | if (v) { 179 | *(env_stack_push(env)) = *v; 180 | } else { 181 | env->error = ERR_SysError; 182 | } 183 | } 184 | 185 | static inline void env_push_ref(env_t *env, uint8_t id, uint8_t generation) { 186 | val_set_reference(env_stack_push(env), id, generation); 187 | } 188 | 189 | static inline void env_push_undefined(env_t *env) { 190 | val_set_undefined(env_stack_push(env)); 191 | } 192 | 193 | static inline void env_push_nan(env_t *env) { 194 | val_set_nan(env_stack_push(env)); 195 | } 196 | 197 | static inline void env_push_zero(env_t *env) { 198 | val_set_number(env_stack_push(env), 0); 199 | } 200 | 201 | static inline void env_push_number(env_t *env, int id) { 202 | if (env->exe.number_num > id) { 203 | val_set_number(env_stack_push(env), env->exe.number_map[id]); 204 | } else { 205 | env_set_error(env, ERR_SysError); 206 | } 207 | } 208 | 209 | static inline void env_push_string(env_t *env, int id) { 210 | if (env->exe.string_num > id) { 211 | val_set_foreign_string(env_stack_push(env), env->exe.string_map[id]); 212 | } else { 213 | env_set_error(env, ERR_SysError); 214 | } 215 | } 216 | 217 | static inline void env_push_boolean(env_t *env, int b) { 218 | val_set_boolean(env_stack_push(env), b); 219 | } 220 | 221 | static inline void env_push_script(env_t *env, intptr_t p) { 222 | val_set_script(env_stack_push(env), p); 223 | } 224 | 225 | static inline void env_push_native(env_t *env, int id) { 226 | if (env->native_num > id) { 227 | val_set_native(env_stack_push(env), (intptr_t)(env->native_ent[id].fn)); 228 | } else { 229 | env_set_error(env, ERR_SysError); 230 | } 231 | } 232 | 233 | static inline 234 | heap_t *env_heap_get_free(env_t *env) { 235 | return env->heap == &env->heap_top ? &env->heap_bot : &env->heap_top; 236 | } 237 | 238 | static inline 239 | int env_is_heap_memory(env_t *env, void *p) { 240 | return heap_is_owned(env->heap, p); 241 | } 242 | 243 | static inline 244 | uint8_t *env_get_main_entry(env_t *env) { 245 | return env->exe.func_map[0]; 246 | } 247 | 248 | static inline 249 | int env_is_interactive(env_t *env) { 250 | return env->main_var_map != NULL; 251 | } 252 | 253 | #endif /* __LANG_ENV_INC__ */ 254 | 255 | -------------------------------------------------------------------------------- /cunit/CUnit_Error.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CUnit - A Unit testing framework library for C. 3 | * Copyright (C) 2001 Anil Kumar 4 | * Copyright (C) 2004-2006 Anil Kumar, Jerry St.Clair 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | /* 22 | * Error handling code used by CUnit 23 | * 24 | * 16-Jul-2004 Created access functions for error code, error action 25 | * functions, messages for new error codes. (JDS) 26 | * 27 | * 02-May-2006 Added internationalization hooks. (JDS) 28 | */ 29 | 30 | /** @file 31 | * Error handling functions (implementation). 32 | */ 33 | /** @addtogroup Framework 34 | @{ 35 | */ 36 | 37 | #include 38 | #include 39 | 40 | #include "CUnit_Intl.h" 41 | #include "CUnit_Error.h" 42 | 43 | /*================================================================= 44 | * Global/Static Definitions 45 | *=================================================================*/ 46 | /** Local variable holding the current error code. */ 47 | static CU_ErrorCode g_error_number = CUE_SUCCESS; 48 | /** Local variable holding the current error action code. */ 49 | static CU_ErrorAction g_error_action = CUEA_IGNORE; 50 | 51 | /*================================================================= 52 | * Private function forward declarations 53 | *=================================================================*/ 54 | static const char* get_error_desc(CU_ErrorCode error); 55 | 56 | #ifdef CUNIT_DO_NOT_DEFINE_UNLESS_BUILDING_TESTS 57 | void test_exit(int status); 58 | #endif 59 | 60 | /*================================================================= 61 | * Public API functions 62 | *=================================================================*/ 63 | void CU_set_error(CU_ErrorCode error) 64 | { 65 | if ((error != CUE_SUCCESS) && (g_error_action == CUEA_ABORT)) { 66 | #ifndef CUNIT_DO_NOT_DEFINE_UNLESS_BUILDING_TESTS 67 | fprintf(stderr, _("\nAborting due to error #%d: %s\n"), 68 | (int)error, 69 | get_error_desc(error)); 70 | exit((int)error); 71 | #else 72 | test_exit(error); 73 | #endif 74 | } 75 | 76 | g_error_number = error; 77 | } 78 | 79 | /*------------------------------------------------------------------------*/ 80 | CU_ErrorCode CU_get_error(void) 81 | { 82 | return g_error_number; 83 | } 84 | 85 | /*------------------------------------------------------------------------*/ 86 | const char* CU_get_error_msg(void) 87 | { 88 | return get_error_desc(g_error_number); 89 | } 90 | 91 | /*------------------------------------------------------------------------*/ 92 | void CU_set_error_action(CU_ErrorAction action) 93 | { 94 | g_error_action = action; 95 | } 96 | 97 | /*------------------------------------------------------------------------*/ 98 | CU_ErrorAction CU_get_error_action(void) 99 | { 100 | return g_error_action; 101 | } 102 | 103 | /*================================================================= 104 | * Private static function definitions 105 | *=================================================================*/ 106 | /** Internal function to look up the error message for a specified 107 | * error code. An empty string is returned if iError is not a member 108 | * of CU_ErrorCode. If you add an error code to enum CU_ErrorCode, 109 | * be sure to add a corresponding error message here. 110 | * 111 | * @param iError CU_ErrorCode to look up. 112 | * @return Pointer to a string containing the error message. 113 | * @see CU_get_error_msg() 114 | */ 115 | static const char* get_error_desc(CU_ErrorCode iError) 116 | { 117 | int iMaxIndex; 118 | 119 | static const char* ErrorDescription[] = { 120 | N_("No Error."), /* CUE_SUCCESS - 0 */ 121 | N_("Memory allocation failed."), /* CUE_NOMEMORY - 1 */ 122 | "", 123 | "", 124 | "", 125 | "", 126 | "", 127 | "", 128 | "", 129 | "", 130 | N_("Test registry does not exist."), /* CUE_NOREGISTRY - 10 */ 131 | N_("Registry already exists."), /* CUE_REGISTRY_EXISTS - 11 */ 132 | "", 133 | "", 134 | "", 135 | "", 136 | "", 137 | "", 138 | "", 139 | "", 140 | N_("NULL suite not allowed."), /* CUE_NOSUITE - 20 */ 141 | N_("Suite name cannot be NULL."), /* CUE_NO_SUITENAME - 21 */ 142 | N_("Suite initialization function failed."), /* CUE_SINIT_FAILED - 22 */ 143 | N_("Suite cleanup function failed."), /* CUE_SCLEAN_FAILED - 23 */ 144 | N_("Suite having name already registered."), /* CUE_DUP_SUITE - 24 */ 145 | N_("Requested suite is not active."), /* CUE_SUITE_INACTIVE - 25 */ 146 | "", 147 | "", 148 | "", 149 | "", 150 | N_("NULL test or test function not allowed."),/* CUE_NOTEST - 30 */ 151 | N_("Test name cannot be NULL."), /* CUE_NO_TESTNAME - 31 */ 152 | N_("Test having this name already in suite."),/* CUE_DUP_TEST - 32 */ 153 | N_("Test not registered in specified suite."),/* CUE_TEST_NOT_IN_SUITE - 33 */ 154 | N_("Requested test is not active"), /* CUE_TEST_INACTIVE - 34 */ 155 | "", 156 | "", 157 | "", 158 | "", 159 | "", 160 | N_("Error opening file."), /* CUE_FOPEN_FAILED - 40 */ 161 | N_("Error closing file."), /* CUE_FCLOSE_FAILED - 41 */ 162 | N_("Bad file name."), /* CUE_BAD_FILENAME - 42 */ 163 | N_("Error during write to file."), /* CUE_WRITE_ERROR - 43 */ 164 | N_("Undefined Error") 165 | }; 166 | 167 | iMaxIndex = (int)(sizeof(ErrorDescription)/sizeof(char *) - 1); 168 | if ((int)iError < 0) { 169 | return _(ErrorDescription[0]); 170 | } 171 | else if ((int)iError > iMaxIndex) { 172 | return _(ErrorDescription[iMaxIndex]); 173 | } 174 | else { 175 | return _(ErrorDescription[(int)iError]); 176 | } 177 | } 178 | 179 | /** @} */ 180 | 181 | #ifdef CUNIT_BUILD_TESTS 182 | #include "test_cunit.h" 183 | 184 | void test_cunit_CUError(void) 185 | { 186 | CU_ErrorCode old_err = CU_get_error(); 187 | CU_ErrorAction old_action = CU_get_error_action(); 188 | 189 | test_cunit_start_tests("CUError.c"); 190 | 191 | /* CU_set_error() & CU_get_error() */ 192 | CU_set_error(CUE_NOMEMORY); 193 | TEST(CU_get_error() != CUE_SUCCESS); 194 | TEST(CU_get_error() == CUE_NOMEMORY); 195 | 196 | CU_set_error(CUE_NOREGISTRY); 197 | TEST(CU_get_error() != CUE_SUCCESS); 198 | TEST(CU_get_error() == CUE_NOREGISTRY); 199 | 200 | /* CU_get_error_msg() */ 201 | CU_set_error(CUE_SUCCESS); 202 | TEST(!strcmp(CU_get_error_msg(), get_error_desc(CUE_SUCCESS))); 203 | 204 | CU_set_error(CUE_NOTEST); 205 | TEST(!strcmp(CU_get_error_msg(), get_error_desc(CUE_NOTEST))); 206 | 207 | CU_set_error(CUE_NOMEMORY); 208 | TEST(!strcmp(CU_get_error_msg(), get_error_desc(CUE_NOMEMORY))); 209 | TEST(strcmp(CU_get_error_msg(), get_error_desc(CUE_SCLEAN_FAILED))); 210 | 211 | TEST(!strcmp(get_error_desc(100), "Undefined Error")); 212 | 213 | /* CU_set_error_action() & CU_get_error_action() */ 214 | CU_set_error_action(CUEA_FAIL); 215 | TEST(CU_get_error_action() != CUEA_IGNORE); 216 | TEST(CU_get_error_action() == CUEA_FAIL); 217 | TEST(CU_get_error_action() != CUEA_ABORT); 218 | 219 | CU_set_error_action(CUEA_ABORT); 220 | TEST(CU_get_error_action() != CUEA_IGNORE); 221 | TEST(CU_get_error_action() != CUEA_FAIL); 222 | TEST(CU_get_error_action() == CUEA_ABORT); 223 | 224 | /* reset values */ 225 | CU_set_error(old_err); 226 | CU_set_error_action(old_action); 227 | 228 | test_cunit_end_tests(); 229 | } 230 | 231 | #endif /* CUNIT_BUILD_TESTS */ 232 | -------------------------------------------------------------------------------- /cunit/CUnit_Error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CUnit - A Unit testing framework library for C. 3 | * Copyright (C) 2001 Anil Kumar 4 | * Copyright (C) 2004-2006 Anil Kumar, Jerry St.Clair 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | /* 22 | * Contains CUnit error codes which can be used externally. 23 | * 24 | * Aug 2001 Initial implementation. (AK) 25 | * 26 | * 02/Oct/2001 Added proper Eror Codes. (AK) 27 | * 28 | * 13-Oct-2001 Added Error Codes for Duplicate TestGroup and Test. (AK) 29 | * 30 | * 03-Aug-2004 Converted error code macros to an enum, doxygen comments, moved 31 | * error handing code here, changed file name from Errno.h, added 32 | * error codes for file open errors, added error action selection. (JDS) 33 | * 34 | * 05-Sep-2004 Added internal test interface. (JDS) 35 | */ 36 | 37 | /** @file 38 | * Error handling functions (user interface). 39 | * CUnit uses a simple (and conventional) error handling strategy. 40 | * Functions that can generate errors set (and usually return) an 41 | * error code to indicate the run status. The error code can be 42 | * inspected using the CU_get_error() function. A descriptive 43 | * error message can be retrieved using CU_get_error_msg(). 44 | */ 45 | /** @addtogroup Framework 46 | * @{ 47 | */ 48 | 49 | #ifndef CUNIT_CUERROR_H_SEEN 50 | #define CUNIT_CUERROR_H_SEEN 51 | 52 | #include 53 | 54 | /*------------------------------------------------------------------------*/ 55 | /** CUnit error codes. 56 | * If codes are added or removed, be sure to make a change to the 57 | * error messages in CUError.c/get_error_desc(). 58 | * @see CU_set_error() 59 | * @see CU_get_error() 60 | * @see CU_get_error_msg() 61 | */ 62 | typedef enum { 63 | /* basic errors */ 64 | CUE_SUCCESS = 0, /**< No error condition. */ 65 | CUE_NOMEMORY = 1, /**< Memory allocation failed. */ 66 | 67 | /* Test Registry Level Errors */ 68 | CUE_NOREGISTRY = 10, /**< Test registry not initialized. */ 69 | CUE_REGISTRY_EXISTS = 11, /**< Attempt to CU_set_registry() without CU_cleanup_registry(). */ 70 | 71 | /* Test Suite Level Errors */ 72 | CUE_NOSUITE = 20, /**< A required CU_pSuite pointer was NULL. */ 73 | CUE_NO_SUITENAME = 21, /**< Required CU_Suite name not provided. */ 74 | CUE_SINIT_FAILED = 22, /**< Suite initialization failed. */ 75 | CUE_SCLEAN_FAILED = 23, /**< Suite cleanup failed. */ 76 | CUE_DUP_SUITE = 24, /**< Duplicate suite name not allowed. */ 77 | CUE_SUITE_INACTIVE = 25, /**< Test run initiated for an inactive suite. */ 78 | 79 | /* Test Case Level Errors */ 80 | CUE_NOTEST = 30, /**< A required CU_pTest or CU_TestFunc pointer was NULL. */ 81 | CUE_NO_TESTNAME = 31, /**< Required CU_Test name not provided. */ 82 | CUE_DUP_TEST = 32, /**< Duplicate test case name not allowed. */ 83 | CUE_TEST_NOT_IN_SUITE = 33, /**< Test not registered in specified suite. */ 84 | CUE_TEST_INACTIVE = 34, /**< Test run initiated for an inactive test. */ 85 | 86 | /* File handling errors */ 87 | CUE_FOPEN_FAILED = 40, /**< An error occurred opening a file. */ 88 | CUE_FCLOSE_FAILED = 41, /**< An error occurred closing a file. */ 89 | CUE_BAD_FILENAME = 42, /**< A bad filename was requested (NULL, empty, nonexistent, etc.). */ 90 | CUE_WRITE_ERROR = 43 /**< An error occurred during a write to a file. */ 91 | } CU_ErrorCode; 92 | 93 | /*------------------------------------------------------------------------*/ 94 | /** CUnit error action codes. 95 | * These are used to set the action desired when an error 96 | * condition is detected in the CUnit framework. 97 | * @see CU_set_error_action() 98 | * @see CU_get_error_action() 99 | */ 100 | typedef enum CU_ErrorAction { 101 | CUEA_IGNORE, /**< Runs should be continued when an error condition occurs (if possible). */ 102 | CUEA_FAIL, /**< Runs should be stopped when an error condition occurs. */ 103 | CUEA_ABORT /**< The application should exit() when an error conditions occurs. */ 104 | } CU_ErrorAction; 105 | 106 | /* Error handling & reporting functions. */ 107 | 108 | #include "CUnit.h" 109 | 110 | #ifdef __cplusplus 111 | extern "C" { 112 | #endif 113 | 114 | CU_EXPORT CU_ErrorCode CU_get_error(void); 115 | /**< 116 | * Retrieves the current CUnit framework error code. 117 | * CUnit implementation functions set the error code to indicate the 118 | * status of the most recent operation. In general, the CUnit functions 119 | * will clear the code to CUE_SUCCESS, then reset it to a specific error 120 | * code if an exception condition is encountered. Some functions 121 | * return the code, others leave it to the user to inspect if desired. 122 | * 123 | * @return The current error condition code. 124 | * @see CU_get_error_msg() 125 | * @see CU_ErrorCode 126 | */ 127 | 128 | CU_EXPORT const char* CU_get_error_msg(void); 129 | /**< 130 | * Retrieves a message corresponding to the current framework error code. 131 | * CUnit implementation functions set the error code to indicate the 132 | * of the most recent operation. In general, the CUnit functions will 133 | * clear the code to CUE_SUCCESS, then reset it to a specific error 134 | * code if an exception condition is encountered. This function allows 135 | * the user to retrieve a descriptive error message corresponding to the 136 | * error code set by the last operation. 137 | * 138 | * @return A message corresponding to the current error condition. 139 | * @see CU_get_error() 140 | * @see CU_ErrorCode 141 | */ 142 | 143 | CU_EXPORT void CU_set_error_action(CU_ErrorAction action); 144 | /**< 145 | * Sets the action to take when a framework error condition occurs. 146 | * This function should be used to specify the action to take 147 | * when an error condition is encountered. The default action is 148 | * CUEA_IGNORE, which results in errors being ignored and test runs 149 | * being continued (if possible). A value of CUEA_FAIL causes test 150 | * runs to stop as soon as an error condition occurs, while 151 | * CU_ABORT causes the application to exit on any error. 152 | * 153 | * @param action CU_ErrorAction indicating the new error action. 154 | * @see CU_get_error_action() 155 | * @see CU_set_error() 156 | * @see CU_ErrorAction 157 | */ 158 | 159 | CU_EXPORT CU_ErrorAction CU_get_error_action(void); 160 | /**< 161 | * Retrieves the current framework error action code. 162 | * 163 | * @return The current error action code. 164 | * @see CU_set_error_action() 165 | * @see CU_set_error() 166 | * @see CU_ErrorAction 167 | */ 168 | 169 | #ifdef CUNIT_BUILD_TESTS 170 | void test_cunit_CUError(void); 171 | #endif 172 | 173 | /* Internal function - users should not generally call this function */ 174 | CU_EXPORT void CU_set_error(CU_ErrorCode error); 175 | /**< 176 | * Sets the CUnit framework error code. 177 | * This function is used internally by CUnit implementation functions 178 | * when an error condition occurs within the framework. It should 179 | * not generally be called by user code. NOTE that if the current 180 | * error action is CUEA_ABORT, then calling this function will 181 | * result in exit() being called for the current application. 182 | * 183 | * @param error CU_ErrorCode indicating the current error condition. 184 | * @see CU_get_error() 185 | * @see CU_get_error_msg() 186 | * @see CU_ErrorCode 187 | */ 188 | 189 | #ifdef __cplusplus 190 | } 191 | #endif 192 | 193 | #ifdef USE_DEPRECATED_CUNIT_NAMES 194 | /** Deprecated (version 1). @deprecated Use CU_get_error_msg(). */ 195 | #define get_error() CU_get_error_msg() 196 | #endif /* USE_DEPRECATED_CUNIT_NAMES */ 197 | 198 | #endif /* CUNIT_CUERROR_H_SEEN */ 199 | /** @} */ 200 | -------------------------------------------------------------------------------- /lang/gc.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include "val.h" 21 | #include "heap.h" 22 | #include "gc.h" 23 | #include "scope.h" 24 | #include "env.h" 25 | #include "types.h" 26 | #include "type_string.h" 27 | #include "type_function.h" 28 | #include "type_array.h" 29 | #include "type_object.h" 30 | #include "type_buffer.h" 31 | 32 | #define MAGIC_BYTE(x) (*((uint8_t *)(x))) 33 | #define ADDR_VALUE(x) (*((void **)(x))) 34 | 35 | static inline scope_t *scope_gc_dup(void *env, scope_t *scope) { 36 | scope_t *dup; 37 | val_t *buf = NULL; 38 | 39 | dup = env_heap_alloc(env, scope_mem_space(scope)); 40 | buf = (val_t *)(dup + 1); 41 | 42 | //printf("%s: free %d\n", __func__, heap->free); 43 | memcpy(dup, scope, sizeof(scope_t)); 44 | memcpy(buf, scope->var_buf, sizeof(val_t) * scope->num); 45 | dup->var_buf = buf; 46 | 47 | return dup; 48 | } 49 | 50 | static inline void scope_gc_scan(void *env, scope_t *scope) { 51 | scope->super = gc_scope_copy(env, scope->super); 52 | gc_types_copy(env, scope->num, scope->var_buf); 53 | } 54 | 55 | static inline object_t *object_gc_dup(void *env, object_t *obj) 56 | { 57 | object_t *dup; 58 | intptr_t *keys; 59 | val_t *vals; 60 | 61 | //dup = heap_alloc(heap, sizeof(scope_t) + sizeof(val_t) * scope->num); 62 | dup = env_heap_alloc(env, object_mem_space(obj)); 63 | keys = (intptr_t *) (dup + 1); 64 | vals = (val_t *)(keys + obj->prop_size); 65 | 66 | //printf("%s: free %d\n", __func__, heap->free); 67 | memcpy(dup, obj, sizeof(object_t)); 68 | memcpy(keys, obj->keys, sizeof(intptr_t) * obj->prop_num); 69 | memcpy(vals, obj->vals, sizeof(val_t) * obj->prop_num); 70 | dup->keys = keys; 71 | dup->vals = vals; 72 | 73 | return dup; 74 | } 75 | 76 | static inline void object_gc_scan(void *env, object_t *obj) 77 | { 78 | gc_types_copy(env, obj->prop_num, obj->vals); 79 | } 80 | 81 | static inline array_t *array_gc_dup(void *env, array_t *a) 82 | { 83 | array_t *dup; 84 | val_t *vals; 85 | 86 | dup = env_heap_alloc(env, array_mem_space(a)); 87 | vals = (val_t *)(dup + 1); 88 | 89 | //printf("%s: free %d\n", __func__, heap->free); 90 | memcpy(dup, a, sizeof(array_t)); 91 | memcpy(vals, array_values(a), sizeof(val_t) * array_length(a)); 92 | dup->elems = vals; 93 | 94 | return dup; 95 | } 96 | 97 | static inline void array_gc_scan(void *env, array_t *a) 98 | { 99 | gc_types_copy(env, array_length(a), array_values(a)); 100 | } 101 | 102 | static inline intptr_t string_gc_dup(void *env, intptr_t str) 103 | { 104 | int size = string_mem_space(str); 105 | void *dup = env_heap_alloc(env, size); 106 | 107 | //printf("%s: free %d, %d, %s\n", __func__, heap->free, size, (char *)(str + 3)); 108 | //printf("[str size: %d, '%s']", size, (char *)str + 3); 109 | memcpy(dup, (void*)str, size); 110 | //printf("[dup size: %d, '%s']", string_mem_space((intptr_t)dup), dup + 3); 111 | 112 | return (intptr_t) dup; 113 | } 114 | 115 | static inline function_t *function_gc_dup(void *env, function_t *func) 116 | { 117 | function_t *dup = env_heap_alloc(env, function_mem_space(func)); 118 | 119 | //printf("%s: free %d\n", __func__, heap->free); 120 | memcpy(dup, (void*)func, sizeof(function_t)); 121 | 122 | return dup; 123 | } 124 | 125 | static inline void function_gc_scan(void *env, function_t *func) 126 | { 127 | func->super = gc_scope_copy(env, func->super); 128 | } 129 | 130 | static inline object_t *gc_object_copy(void *env, object_t *obj) 131 | { 132 | object_t *dup; 133 | 134 | if (!obj || env_is_heap_memory(env, obj)) { 135 | return obj; 136 | } 137 | 138 | if (MAGIC_BYTE(obj) != MAGIC_OBJECT) { 139 | return ADDR_VALUE(obj); 140 | } 141 | dup = object_gc_dup(env, obj); 142 | ADDR_VALUE(obj) = dup; 143 | 144 | return dup; 145 | } 146 | 147 | static inline array_t *gc_array_copy(void *env, array_t *a) 148 | { 149 | array_t *dup; 150 | 151 | if (!a || env_is_heap_memory(env, a)) { 152 | return a; 153 | } 154 | 155 | if (MAGIC_BYTE(a) != MAGIC_ARRAY) { 156 | return ADDR_VALUE(a); 157 | } 158 | dup = array_gc_dup(env, a); 159 | ADDR_VALUE(a) = dup; 160 | 161 | return dup; 162 | } 163 | 164 | static inline intptr_t gc_string_copy(void *env, intptr_t str) 165 | { 166 | if (!str || env_is_heap_memory(env, (void*)str)) { 167 | return (intptr_t) str; 168 | } 169 | 170 | if (MAGIC_BYTE(str) != MAGIC_STRING) { 171 | return (intptr_t) ADDR_VALUE(str); 172 | } else { 173 | intptr_t dup = string_gc_dup(env, str); 174 | ADDR_VALUE(str) = (void *)dup; 175 | 176 | return dup; 177 | } 178 | } 179 | 180 | static inline function_t *gc_function_copy(void *env, function_t *func) 181 | { 182 | if (!func || env_is_heap_memory(env, func)) { 183 | return func; 184 | } 185 | 186 | if (MAGIC_BYTE(func) != MAGIC_FUNCTION) { 187 | return ADDR_VALUE(func); 188 | } else { 189 | function_t *dup = function_gc_dup(env, func); 190 | ADDR_VALUE(func) = dup; 191 | return dup; 192 | } 193 | } 194 | 195 | scope_t *gc_scope_copy(void *env, scope_t *scope) 196 | { 197 | scope_t *dup; 198 | 199 | if (!scope || env_is_heap_memory(env, scope)) { 200 | return scope; 201 | } 202 | 203 | if (MAGIC_BYTE(scope) != MAGIC_SCOPE) { 204 | return ADDR_VALUE(scope); 205 | } 206 | 207 | dup = scope_gc_dup(env, scope); 208 | ADDR_VALUE(scope) = dup; 209 | 210 | return dup; 211 | } 212 | 213 | void gc_types_copy(void *env, int n, val_t *p) 214 | { 215 | int i = 0; 216 | 217 | while (i < n) { 218 | val_t *v = p + i; 219 | 220 | 221 | if (val_is_heap_string(v)) { 222 | val_set_heap_string(v, gc_string_copy(env, val_2_intptr(v))); 223 | } else 224 | if (val_is_script(v)) { 225 | val_set_script(v, (intptr_t)gc_function_copy(env, (void *)val_2_intptr(v))); 226 | } else 227 | if (val_is_object(v)) { 228 | val_set_object(v, (intptr_t)gc_object_copy(env, (object_t *)val_2_intptr(v))); 229 | } else 230 | if (val_is_array(v)) { 231 | val_set_array(v, (intptr_t)gc_array_copy(env, (array_t *)val_2_intptr(v))); 232 | } else 233 | if (val_is_foreign(v)) { 234 | foreign_keep(val_2_intptr(v)); 235 | } 236 | i++; 237 | } 238 | } 239 | 240 | void gc_scan(void *env) 241 | { 242 | heap_t *heap = ((env_t *)env)->heap; 243 | uint8_t *base = heap->base; 244 | int scan = 0; 245 | 246 | while(scan < heap->free) { 247 | uint8_t magic = base[scan]; 248 | 249 | switch(magic) { 250 | case MAGIC_STRING: 251 | scan += string_mem_space((intptr_t)(base + scan)); 252 | break; 253 | case MAGIC_FUNCTION: { 254 | function_t *func = (function_t *)(base + scan); 255 | scan += function_mem_space(func); 256 | 257 | function_gc_scan(env, func); 258 | 259 | break; 260 | } 261 | case MAGIC_SCOPE: { 262 | scope_t *scope = (scope_t *) (base + scan); 263 | scan += scope_mem_space(scope); 264 | 265 | scope_gc_scan(env, scope); 266 | 267 | break; 268 | } 269 | case MAGIC_OBJECT: { 270 | object_t *obj = (object_t *) (base + scan); 271 | scan += object_mem_space(obj); 272 | 273 | object_gc_scan(env, obj); 274 | 275 | break; 276 | } 277 | case MAGIC_ARRAY: { 278 | array_t *array= (array_t*) (base + scan); 279 | scan += array_mem_space(array); 280 | 281 | array_gc_scan(env, array); 282 | 283 | break; 284 | } 285 | default: break; 286 | } 287 | } 288 | } 289 | 290 | -------------------------------------------------------------------------------- /test/test_lang_type_buffer.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include 21 | #include 22 | 23 | #include "cunit/CUnit.h" 24 | #include "cunit/CUnit_Basic.h" 25 | 26 | #include "lang/interp.h" 27 | #include "lang/type_buffer.h" 28 | 29 | #define STACK_SIZE 128 30 | #define HEAP_SIZE 4096 31 | 32 | #define EXE_MEM_SPACE 4096 33 | #define SYM_MEM_SPACE 1024 34 | #define MEMORY_SIZE (sizeof(val_t) * STACK_SIZE + HEAP_SIZE + EXE_MEM_SPACE + SYM_MEM_SPACE) 35 | 36 | uint8_t memory[MEMORY_SIZE]; 37 | 38 | static int test_setup() 39 | { 40 | return 0; 41 | } 42 | 43 | static int test_clean() 44 | { 45 | return 0; 46 | } 47 | 48 | static void test_create(void) 49 | { 50 | env_t env; 51 | val_t *res; 52 | native_t native_entry[] = { 53 | {"Buffer", buffer_native_create}, 54 | }; 55 | 56 | CU_ASSERT_FATAL(0 == interp_env_init_interactive(&env, memory, MEMORY_SIZE, NULL, HEAP_SIZE, NULL, STACK_SIZE)); 57 | CU_ASSERT(0 == env_native_set(&env, native_entry, 1)); 58 | 59 | CU_ASSERT(0 < interp_execute_string(&env, "var a, b;", &res)); 60 | 61 | CU_ASSERT(0 < interp_execute_string(&env, "a = Buffer(10);", &res) && val_is_buffer(res)); 62 | CU_ASSERT(0 < interp_execute_string(&env, "a.length() == 10;", &res) && val_is_true(res)); 63 | 64 | CU_ASSERT(0 < interp_execute_string(&env, "b = Buffer('hello');", &res) && val_is_buffer(res)); 65 | CU_ASSERT(0 < interp_execute_string(&env, "b.length() == 5", &res) && val_is_true(res)); 66 | 67 | 68 | CU_ASSERT(0 < interp_execute_string(&env, "b[0] == 104", &res) && val_is_true(res)); 69 | CU_ASSERT(0 < interp_execute_string(&env, "b[1] == 101", &res) && val_is_true(res)); 70 | CU_ASSERT(0 < interp_execute_string(&env, "b[2] == 108", &res) && val_is_true(res)); 71 | CU_ASSERT(0 < interp_execute_string(&env, "b[3] == 108", &res) && val_is_true(res)); 72 | CU_ASSERT(0 < interp_execute_string(&env, "b[4] == 111", &res) && val_is_true(res)); 73 | CU_ASSERT(0 < interp_execute_string(&env, "b[5]", &res) && val_is_undefined(res)); 74 | } 75 | 76 | static void test_write(void) 77 | { 78 | env_t env; 79 | val_t *res; 80 | native_t native_entry[] = { 81 | {"Buffer", buffer_native_create}, 82 | }; 83 | 84 | CU_ASSERT_FATAL(0 == interp_env_init_interactive(&env, memory, MEMORY_SIZE, NULL, HEAP_SIZE, NULL, STACK_SIZE)); 85 | CU_ASSERT(0 == env_native_set(&env, native_entry, 1)); 86 | 87 | CU_ASSERT(0 < interp_execute_string(&env, "var b;", &res)); 88 | 89 | CU_ASSERT(0 < interp_execute_string(&env, "b = Buffer(10);", &res) && val_is_buffer(res)); 90 | CU_ASSERT(0 < interp_execute_string(&env, "b.length() == 10;", &res) && val_is_true(res)); 91 | 92 | CU_ASSERT(0 < interp_execute_string(&env, "b.writeInt(-1) == 1;", &res) && val_is_true(res)); 93 | CU_ASSERT(0 < interp_execute_string(&env, "b.writeInt(-1, 2) == 3;", &res) && val_is_true(res)); 94 | 95 | CU_ASSERT(0 < interp_execute_string(&env, "b.writeInt(-1, 0, 2) == 2;", &res) && val_is_true(res)); 96 | CU_ASSERT(0 < interp_execute_string(&env, "b.writeInt(-1, 0, 4) == 4;", &res) && val_is_true(res)); 97 | 98 | CU_ASSERT(0 < interp_execute_string(&env, "b.writeInt(-1, 6, 4) == 10;", &res) && val_is_true(res)); 99 | } 100 | 101 | static void test_read(void) 102 | { 103 | env_t env; 104 | val_t *res; 105 | native_t native_entry[] = { 106 | {"Buffer", buffer_native_create}, 107 | }; 108 | 109 | CU_ASSERT_FATAL(0 == interp_env_init_interactive(&env, memory, MEMORY_SIZE, NULL, HEAP_SIZE, NULL, STACK_SIZE)); 110 | CU_ASSERT(0 == env_native_set(&env, native_entry, 1)); 111 | 112 | CU_ASSERT(0 < interp_execute_string(&env, "var a, b;", &res)); 113 | 114 | CU_ASSERT(0 < interp_execute_string(&env, "a = Buffer(10);", &res) && val_is_buffer(res)); 115 | CU_ASSERT(0 < interp_execute_string(&env, "a.length() == 10;", &res) && val_is_true(res)); 116 | 117 | CU_ASSERT(0 < interp_execute_string(&env, "b = Buffer('hello');", &res) && val_is_buffer(res)); 118 | CU_ASSERT(0 < interp_execute_string(&env, "b.length() == 5", &res) && val_is_true(res)); 119 | 120 | CU_ASSERT(0 < interp_execute_string(&env, "b.readInt(0) == 104", &res) && val_is_true(res)); 121 | CU_ASSERT(0 < interp_execute_string(&env, "b.readInt(0, 2) == 25960", &res) && val_is_true(res)); // Little Endian 122 | CU_ASSERT(0 < interp_execute_string(&env, "b.readInt(0, 2, 0) == 25960", &res) && val_is_true(res)); // Little Endian 123 | CU_ASSERT(0 < interp_execute_string(&env, "b.readInt(0, 2, 1) == 26725", &res) && val_is_true(res)); // Big Endian 124 | CU_ASSERT(0 < interp_execute_string(&env, "b.readInt(0, 4) == 1819043176", &res) && val_is_true(res)); // Big Endian 125 | CU_ASSERT(0 < interp_execute_string(&env, "b.readInt(0, 4, 0) == 1819043176", &res) && val_is_true(res)); // Big Endian 126 | CU_ASSERT(0 < interp_execute_string(&env, "b.readInt(0, 4, 1) == 1751477356", &res) && val_is_true(res)); // Little Endian 127 | 128 | CU_ASSERT(0 < interp_execute_string(&env, "a.writeInt(-1) == 1;", &res) && val_is_true(res)); 129 | CU_ASSERT(0 < interp_execute_string(&env, "a.writeInt(-2, 1) == 2;", &res) && val_is_true(res)); 130 | CU_ASSERT(0 < interp_execute_string(&env, "a.readInt() == -1", &res) && val_is_true(res)); // Little Endian 131 | CU_ASSERT(0 < interp_execute_string(&env, "a.readInt(0, 1) == -1", &res) && val_is_true(res)); // Little Endian 132 | CU_ASSERT(0 < interp_execute_string(&env, "a.readInt(1, 1) == -2", &res) && val_is_true(res)); // Little Endian 133 | 134 | CU_ASSERT(0 < interp_execute_string(&env, "a.writeInt(-3, 2, 2) == 4;", &res) && val_is_true(res)); 135 | CU_ASSERT(0 < interp_execute_string(&env, "a.readInt(2, 2) == -3", &res) && val_is_true(res)); // Little Endian 136 | CU_ASSERT(0 < interp_execute_string(&env, "a.writeInt(-4, 4, 4) == 8;", &res) && val_is_true(res)); 137 | CU_ASSERT(0 < interp_execute_string(&env, "a.readInt(4, 4) == -4", &res) && val_is_true(res)); // Little Endian 138 | 139 | CU_ASSERT(0 < interp_execute_string(&env, "a.writeInt(-3, 2, 2, 1) == 4;", &res) && val_is_true(res)); 140 | CU_ASSERT(0 < interp_execute_string(&env, "a.readInt(2, 2) != -3", &res) && val_is_true(res)); // Little Endian 141 | CU_ASSERT(0 < interp_execute_string(&env, "a.readInt(2, 2, 1) == -3", &res) && val_is_true(res)); // Little Endian 142 | 143 | CU_ASSERT(0 < interp_execute_string(&env, "a.writeInt(-4, 4, 4, 1) == 8;", &res) && val_is_true(res)); 144 | CU_ASSERT(0 < interp_execute_string(&env, "a.readInt(4, 4) != -4", &res) && val_is_true(res)); // Little Endian 145 | CU_ASSERT(0 < interp_execute_string(&env, "a.readInt(4, 4, 1) == -4", &res) && val_is_true(res)); // Little Endian 146 | } 147 | 148 | static void test_slice(void) 149 | { 150 | env_t env; 151 | val_t *res; 152 | native_t native_entry[] = { 153 | {"Buffer", buffer_native_create}, 154 | }; 155 | 156 | CU_ASSERT_FATAL(0 == interp_env_init_interactive(&env, memory, MEMORY_SIZE, NULL, HEAP_SIZE, NULL, STACK_SIZE)); 157 | CU_ASSERT(0 == env_native_set(&env, native_entry, 1)); 158 | 159 | CU_ASSERT(0 < interp_execute_string(&env, "var b, d;", &res)); 160 | 161 | CU_ASSERT(0 < interp_execute_string(&env, "b = Buffer('hello');", &res) && val_is_buffer(res)); 162 | CU_ASSERT(0 < interp_execute_string(&env, "b.length() == 5", &res) && val_is_true(res)); 163 | 164 | CU_ASSERT(0 < interp_execute_string(&env, "d = b.slice(1)", &res) && val_is_buffer(res)); 165 | CU_ASSERT(0 < interp_execute_string(&env, "d.length() == 4", &res) && val_is_true(res)); 166 | 167 | CU_ASSERT(0 < interp_execute_string(&env, "d = b.slice(1, 3)", &res) && val_is_buffer(res)); 168 | CU_ASSERT(0 < interp_execute_string(&env, "d.length() == 2", &res) && val_is_true(res)); 169 | } 170 | 171 | CU_pSuite test_lang_type_buffer(void) 172 | { 173 | CU_pSuite suite = CU_add_suite("TYPE: Buffer", test_setup, test_clean); 174 | 175 | if (suite) { 176 | CU_add_test(suite, "create", test_create); 177 | CU_add_test(suite, "write", test_write); 178 | CU_add_test(suite, "read", test_read); 179 | CU_add_test(suite, "slice", test_slice); 180 | } 181 | return suite; 182 | } 183 | 184 | -------------------------------------------------------------------------------- /lang/bcode.c: -------------------------------------------------------------------------------- 1 | /* GPLv2 License 2 | * 3 | * Copyright (C) 2016-2018 Lixing Ding 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | **/ 19 | 20 | #include "bcode.h" 21 | 22 | int bcode_parse(const uint8_t *code, int *offset, const char **name, int *param1, int *param2) 23 | { 24 | int shift, index; 25 | 26 | if (!name || !param1 || !param2) { 27 | return -1; 28 | } 29 | 30 | shift = offset ? *offset : 0; 31 | switch(code[shift++]) { 32 | case BC_STOP: *name = "STOP"; if(offset) *offset = shift; return 0; 33 | case BC_PASS: *name = "PASS"; if(offset) *offset = shift; return 0; 34 | 35 | /* Return instruction */ 36 | case BC_RET0: *name = "RET0"; if(offset) *offset = shift; return 0; 37 | case BC_RET: *name = "RET"; if(offset) *offset = shift; return 0; 38 | 39 | /* Jump instruction */ 40 | case BC_SJMP: *param1 = (int8_t) (code[shift++]); 41 | *name = "SJMP"; if(offset) *offset = shift; return 1; 42 | 43 | case BC_JMP: index = (int8_t) (code[shift++]); 44 | *param1 = (index << 8) | (code[shift++]); 45 | *name = "JMP"; if(offset) *offset = shift; return 1; 46 | 47 | case BC_SJMP_T: *param1 = (int8_t) (code[shift++]); 48 | *name = "SJMP_T"; if(offset) *offset = shift; return 1; 49 | 50 | case BC_SJMP_F: *param1 = (int8_t) (code[shift++]); 51 | *name = "SJMP_F"; if(offset) *offset = shift; return 1; 52 | 53 | case BC_JMP_T: index = (int8_t) (code[shift++]); 54 | *param1 = (index << 8) | (code[shift++]); 55 | *name = "JMP_T"; if(offset) *offset = shift; return 1; 56 | 57 | case BC_JMP_F: index = (int8_t) (code[shift++]); 58 | *param1 = (index << 8) | (code[shift++]); 59 | *name = "JMP_F"; if(offset) *offset = shift; return 1; 60 | 61 | case BC_POP_SJMP_T: *param1 = (int8_t) (code[shift++]); 62 | *name = "POP_SJMP_T"; if(offset) *offset = shift; return 1; 63 | 64 | case BC_POP_SJMP_F: *param1 = (int8_t) (code[shift++]); 65 | *name = "POP_SJMP_F"; if(offset) *offset = shift; return 1; 66 | 67 | case BC_POP_JMP_T: index = (int8_t) (code[shift++]); 68 | *param1 = (index << 8) | (code[shift++]); 69 | *name = "POP_JMP_T"; if(offset) *offset = shift; return 1; 70 | 71 | case BC_POP_JMP_F: index = (int8_t) (code[shift++]); 72 | *param1 = (index << 8) | (code[shift++]); 73 | *name = "POP_JMP_F"; if(offset) *offset = shift; return 1; 74 | 75 | case BC_PUSH_UND: *name = "PUSH_UND"; if(offset) *offset = shift; return 0; 76 | case BC_PUSH_NAN: *name = "PUSH_NAN"; if(offset) *offset = shift; return 0; 77 | case BC_PUSH_TRUE: *name = "PUSH_TRUE"; if(offset) *offset = shift; return 0; 78 | case BC_PUSH_FALSE: *name = "PUSH_FALSE"; if(offset) *offset = shift; return 0; 79 | case BC_PUSH_ZERO: *name = "PUSH_ZERO"; if(offset) *offset = shift; return 0; 80 | 81 | case BC_PUSH_NUM: index = (code[shift++]); 82 | *param1 = (index << 8) | (code[shift++]); 83 | *name = "PUSH_NUM"; if(offset) *offset = shift; return 1; 84 | 85 | case BC_PUSH_STR: index = (code[shift++]); 86 | *param1 = (index << 8) | (code[shift++]); 87 | *name = "PUSH_STR"; if(offset) *offset = shift; return 1; 88 | 89 | case BC_PUSH_VAR: *param1 = (code[shift++]); 90 | *param2 = (code[shift++]); 91 | *name = "PUSH_VAR"; if(offset) *offset = shift; return 2; 92 | 93 | case BC_PUSH_REF:*param1 = (code[shift++]); 94 | *param2 = (code[shift++]); 95 | *name = "PUSH_REF"; if(offset) *offset = shift; return 2; 96 | 97 | case BC_PUSH_SCRIPT:index = (code[shift++]); 98 | *param1 = (index << 8) | (code[shift++]); 99 | *name = "PUSH_SCRIPT"; if(offset) *offset = shift; return 1; 100 | 101 | case BC_PUSH_NATIVE:index = (code[shift++]); 102 | *param1 = (index << 8) | (code[shift++]); 103 | *name = "PUSH_NATIVE"; if(offset) *offset = shift; return 1; 104 | 105 | case BC_POP: *name = "POP"; if(offset) *offset = shift; return 0; 106 | 107 | case BC_NEG: *name = "NEG"; if(offset) *offset = shift; return 0; 108 | case BC_NOT: *name = "NOT"; if(offset) *offset = shift; return 0; 109 | case BC_LOGIC_NOT: *name = "LOGIC_NOT"; if(offset) *offset = shift; return 0; 110 | 111 | case BC_INC: *name = "INC"; if(offset) *offset = shift; return 0; 112 | case BC_INCP: *name = "INCP"; if(offset) *offset = shift; return 0; 113 | case BC_DEC: *name = "DEC"; if(offset) *offset = shift; return 0; 114 | case BC_DECP: *name = "DECP"; if(offset) *offset = shift; return 0; 115 | 116 | case BC_MUL: *name = "MUL"; if(offset) *offset = shift; return 0; 117 | case BC_DIV: *name = "DIV"; if(offset) *offset = shift; return 0; 118 | case BC_MOD: *name = "MOD"; if(offset) *offset = shift; return 0; 119 | case BC_ADD: *name = "ADD"; if(offset) *offset = shift; return 0; 120 | case BC_SUB: *name = "SUB"; if(offset) *offset = shift; return 0; 121 | 122 | case BC_AAND: *name = "LOGIC_AND"; if(offset) *offset = shift; return 0; 123 | case BC_AOR: *name = "LOGIC_OR"; if(offset) *offset = shift; return 0; 124 | case BC_AXOR: *name = "LOGIC_XOR"; if(offset) *offset = shift; return 0; 125 | 126 | case BC_LSHIFT: *name = "LSHIFT"; if(offset) *offset = shift; return 0; 127 | case BC_RSHIFT: *name = "RSHIFT"; if(offset) *offset = shift; return 0; 128 | 129 | case BC_TEQ: *name = "TEQ"; if(offset) *offset = shift; return 0; 130 | case BC_TNE: *name = "TNE"; if(offset) *offset = shift; return 0; 131 | case BC_TGT: *name = "TGT"; if(offset) *offset = shift; return 0; 132 | case BC_TGE: *name = "TGE"; if(offset) *offset = shift; return 0; 133 | case BC_TLT: *name = "TLT"; if(offset) *offset = shift; return 0; 134 | case BC_TLE: *name = "TLE"; if(offset) *offset = shift; return 0; 135 | 136 | case BC_TIN: *name = "TIN"; if(offset) *offset = shift; return 0; 137 | 138 | case BC_FUNC_CALL: *param1 = code[shift++]; 139 | *name = "CALL"; if(offset) *offset = shift; return 1; 140 | 141 | case BC_ARRAY: index = (code[shift++]); 142 | *param1 = (index << 8) | (code[shift++]); 143 | *name = "ARRAY"; if(offset) *offset = shift; return 1; 144 | 145 | case BC_DICT: index = (code[shift++]); 146 | *param1 = (index << 8) | (code[shift++]); 147 | *name = "DICT"; if(offset) *offset = shift; return 1; 148 | 149 | case BC_PROP: *name = "PROP"; if(offset) *offset = shift; return 0; 150 | case BC_PROP_METH: *name = "PROP_METH"; if(offset) *offset = shift; return 0; 151 | 152 | case BC_ELEM: *name = "ELEM"; if(offset) *offset = shift; return 0; 153 | case BC_ELEM_METH: *name = "ELEM_METH"; if(offset) *offset = shift; return 0; 154 | 155 | case BC_ASSIGN: *name = "ASSIGN"; if(offset) *offset = shift; return 0; 156 | case BC_ADD_ASSIGN: *name = "ADD_ASSIGN"; if(offset) *offset = shift; return 0; 157 | case BC_SUB_ASSIGN: *name = "SUB_ASSIGN"; if(offset) *offset = shift; return 0; 158 | case BC_MUL_ASSIGN: *name = "MUL_ASSIGN"; if(offset) *offset = shift; return 0; 159 | case BC_DIV_ASSIGN: *name = "DIV_ASSIGN"; if(offset) *offset = shift; return 0; 160 | case BC_MOD_ASSIGN: *name = "MOD_ASSIGN"; if(offset) *offset = shift; return 0; 161 | case BC_AND_ASSIGN: *name = "AND_ASSIGN"; if(offset) *offset = shift; return 0; 162 | case BC_OR_ASSIGN: *name = "OR_ASSIGN"; if(offset) *offset = shift; return 0; 163 | case BC_XOR_ASSIGN: *name = "XOR_ASSIGN"; if(offset) *offset = shift; return 0; 164 | case BC_LSHIFT_ASSIGN: *name = "LS_ASSIGN"; if(offset) *offset = shift; return 0; 165 | case BC_RSHIFT_ASSIGN: *name = "RS_ASSIGN"; if(offset) *offset = shift; return 0; 166 | 167 | case BC_PROP_ASSIGN: *name = "PROP_ASSIGN"; if(offset) *offset = shift; return 0; 168 | case BC_PROP_ADD_ASSIGN: *name = "PROP_ADD_ASSIGN"; if(offset) *offset = shift; return 0; 169 | case BC_PROP_SUB_ASSIGN: *name = "PROP_SUB_ASSIGN"; if(offset) *offset = shift; return 0; 170 | case BC_PROP_MUL_ASSIGN: *name = "PROP_MUL_ASSIGN"; if(offset) *offset = shift; return 0; 171 | case BC_PROP_DIV_ASSIGN: *name = "PROP_DIV_ASSIGN"; if(offset) *offset = shift; return 0; 172 | case BC_PROP_MOD_ASSIGN: *name = "PROP_MOD_ASSIGN"; if(offset) *offset = shift; return 0; 173 | case BC_PROP_AND_ASSIGN: *name = "PROP_AND_ASSIGN"; if(offset) *offset = shift; return 0; 174 | case BC_PROP_OR_ASSIGN: *name = "PROP_OR_ASSIGN"; if(offset) *offset = shift; return 0; 175 | case BC_PROP_XOR_ASSIGN: *name = "PROP_XOR_ASSIGN"; if(offset) *offset = shift; return 0; 176 | case BC_PROP_LSHIFT_ASSIGN: *name = "PROP_LS_ASSIGN"; if(offset) *offset = shift; return 0; 177 | case BC_PROP_RSHIFT_ASSIGN: *name = "PROP_RS_ASSIGN"; if(offset) *offset = shift; return 0; 178 | 179 | case BC_ELEM_ASSIGN:*name = "ELEM_ASSING"; if(offset) *offset = shift; return 0; 180 | case BC_ELEM_ADD_ASSIGN: *name = "ELEM_ADD_ASSIGN"; if(offset) *offset = shift; return 0; 181 | case BC_ELEM_SUB_ASSIGN: *name = "ELEM_SUB_ASSIGN"; if(offset) *offset = shift; return 0; 182 | case BC_ELEM_MUL_ASSIGN: *name = "ELEM_MUL_ASSIGN"; if(offset) *offset = shift; return 0; 183 | case BC_ELEM_DIV_ASSIGN: *name = "ELEM_DIV_ASSIGN"; if(offset) *offset = shift; return 0; 184 | case BC_ELEM_MOD_ASSIGN: *name = "ELEM_MOD_ASSIGN"; if(offset) *offset = shift; return 0; 185 | case BC_ELEM_AND_ASSIGN: *name = "ELEM_AND_ASSIGN"; if(offset) *offset = shift; return 0; 186 | case BC_ELEM_OR_ASSIGN: *name = "ELEM_OR_ASSIGN"; if(offset) *offset = shift; return 0; 187 | case BC_ELEM_XOR_ASSIGN: *name = "ELEM_XOR_ASSIGN"; if(offset) *offset = shift; return 0; 188 | case BC_ELEM_LSHIFT_ASSIGN: *name = "ELEM_LS_ASSIGN"; if(offset) *offset = shift; return 0; 189 | case BC_ELEM_RSHIFT_ASSIGN: *name = "ELEM_RS_ASSIGN"; if(offset) *offset = shift; return 0; 190 | 191 | default: *name = "UNKNOWN"; if(offset) *offset = shift; return 0; 192 | } 193 | } 194 | 195 | --------------------------------------------------------------------------------