|
| 1 | +/**************************************************************************** |
| 2 | +** |
| 3 | +** Copyright (C) 2020 @scriptiot |
| 4 | +** |
| 5 | +** EVM是一款通用化设计的虚拟机引擎,拥有语法解析前端接口、编译器、虚拟机和虚拟机扩展接口框架。 |
| 6 | +** 支持js、python、qml、lua等多种脚本语言,纯C开发,零依赖,内置REPL,支持主流 ROM > 40KB, RAM > 2KB的MCU; |
| 7 | +** 自带垃圾回收(GC)先进的内存管理,采用最复杂的压缩算法,无内存碎片(大部分解释器都存在内存碎片) |
| 8 | +** Version : 1.0 |
| 9 | +** Email : scriptiot@aliyun.com |
| 10 | +** Website : https://github.com/scriptiot/evm |
| 11 | +** https://gitee.com/scriptiot/evm |
| 12 | +** Licence: Apache-2.0 |
| 13 | +****************************************************************************/ |
| 14 | + |
| 15 | +#include "ecma.h" |
| 16 | + |
| 17 | +uint16_t ecma_hash_constructor; |
| 18 | +uint16_t ecma_hash_prototype; |
| 19 | +uint16_t ecma_hash_call; |
| 20 | +uint16_t ecma_hash___proto__; |
| 21 | +uint16_t ecma_hash_hasOwnProperty; |
| 22 | +uint16_t ecma_hash_isPrototypeOf; |
| 23 | +uint16_t ecma_hash_toString; |
| 24 | +uint16_t ecma_hash_valueOf; |
| 25 | + |
| 26 | +uint16_t ecma_hash_length; |
| 27 | +uint16_t ecma_hash_push; |
| 28 | +uint16_t ecma_hash_pop; |
| 29 | +uint16_t ecma_hash_concat; |
| 30 | +uint16_t ecma_hash_fill; |
| 31 | +uint16_t ecma_hash_indexOf; |
| 32 | +uint16_t ecma_hash_shift; |
| 33 | +uint16_t ecma_hash_slice; |
| 34 | +uint16_t ecma_hash_copyWithin; |
| 35 | +uint16_t ecma_hash_unshift; |
| 36 | +uint16_t ecma_hash_filter; |
| 37 | +uint16_t ecma_hash_map; |
| 38 | +uint16_t ecma_hash_find; |
| 39 | +uint16_t ecma_hash_join; |
| 40 | + |
| 41 | +#ifdef CONFIG_EVM_ECMA_OBJECT |
| 42 | +extern evm_val_t * ecma_object_init(evm_t * e); |
| 43 | +extern void ecma_object_attrs_apply(evm_t * e, evm_val_t * o, evm_val_t * prototype); |
| 44 | +#endif |
| 45 | +#ifdef CONFIG_EVM_ECMA_ARRAY |
| 46 | +extern evm_val_t * ecma_array_init(evm_t * e); |
| 47 | +#endif |
| 48 | +#ifdef CONFIG_EVM_ECMA_NUMBER |
| 49 | +extern evm_val_t * ecma_number_init(evm_t * e); |
| 50 | +#endif |
| 51 | +#ifdef CONFIG_EVM_ECMA_MATH |
| 52 | +extern evm_val_t * ecma_math_init(evm_t * e); |
| 53 | +#endif |
| 54 | +#ifdef CONFIG_EVM_ECMA_STRING |
| 55 | +extern evm_val_t * ecma_string_init(evm_t * e); |
| 56 | +#endif |
| 57 | +#ifdef CONFIG_EVM_ECMA_REGEXP |
| 58 | +extern evm_val_t * ecma_regex_init(evm_t * e); |
| 59 | +#endif |
| 60 | + |
| 61 | +evm_val_t * ecma_object_prototype; |
| 62 | +evm_val_t * ecma_function_prototype; |
| 63 | + |
| 64 | +static evm_val_t ecma_typeof(evm_t * e, evm_val_t * p, int argc, evm_val_t * v){ |
| 65 | + EVM_UNUSED(e);EVM_UNUSED(p); |
| 66 | + if( argc > 0){ |
| 67 | + switch (evm_type(v)) { |
| 68 | + case TYPE_BOOLEAN: return evm_mk_foreign_string((intptr_t)"boolean"); |
| 69 | + case TYPE_NUMBER: return evm_mk_foreign_string((intptr_t)"number"); |
| 70 | + case TYPE_HEAP_STRING: |
| 71 | + case TYPE_FOREIGN_STRING: return evm_mk_foreign_string((intptr_t)"string"); |
| 72 | + case TYPE_FUNCTION: return evm_mk_foreign_string((intptr_t)"function"); |
| 73 | + case TYPE_UNDEFINED: return evm_mk_foreign_string((intptr_t)"undefined"); |
| 74 | + default: |
| 75 | + return evm_mk_foreign_string((intptr_t)"object"); |
| 76 | + } |
| 77 | + } |
| 78 | + return EVM_VAL_UNDEFINED; |
| 79 | +} |
| 80 | + |
| 81 | +static evm_val_t ecma_new(evm_t * e, evm_val_t * p, int argc, evm_val_t * v){ |
| 82 | + EVM_UNUSED(e);EVM_UNUSED(p); |
| 83 | + if(argc > 0){ |
| 84 | + switch (evm_type(v)) { |
| 85 | + case TYPE_FUNCTION:{ |
| 86 | + evm_val_t * fn = v; |
| 87 | + if( evm_script_get_native(v) != NULL){ |
| 88 | + evm_native_fn fn = evm_script_get_native(v); |
| 89 | + return fn(e, v, argc - 1, v + 1); |
| 90 | + } else { |
| 91 | + evm_val_t * o = evm_object_create(e, GC_DICT, 0, 0); |
| 92 | + #ifdef CONFIG_EVM_ECMA_OBJECT |
| 93 | + evm_val_t * prototype = evm_attr_get_by_key(e, fn, ecma_hash_prototype); |
| 94 | + ecma_object_attrs_apply(e, o, prototype); |
| 95 | + evm_attr_set_key_value(e, o, 1, ecma_hash_constructor, *fn); |
| 96 | + #endif |
| 97 | + evm_run_callback(e, fn, o, v + 1, argc - 1); |
| 98 | + return *o; |
| 99 | + } |
| 100 | + }break; |
| 101 | + case TYPE_CLASS:{ |
| 102 | + evm_val_t * o = evm_object_create_by_class(e, GC_DICT, v); |
| 103 | + if( evm_class_get_native(v) != NULL){ |
| 104 | + evm_native_fn fn = evm_class_get_native(v); |
| 105 | + fn(e, o, argc - 1, v + 1); |
| 106 | + } else { |
| 107 | + evm_run_callback(e, v, o, v + 1, argc - 1); |
| 108 | + } |
| 109 | + return *o; |
| 110 | + }break; |
| 111 | + default: |
| 112 | + break; |
| 113 | + } |
| 114 | + } |
| 115 | + return EVM_VAL_UNDEFINED; |
| 116 | +} |
| 117 | + |
| 118 | +static evm_val_t ecma_function_call(evm_t * e, evm_val_t * p, int argc, evm_val_t * v){ |
| 119 | + if( argc >= 1 && p && evm_is_script(p) && evm_is_object(v) ){ |
| 120 | + evm_val_t ret_val = evm_run_callback(e, p, v, v + 1, argc - 1); |
| 121 | + return ret_val; |
| 122 | + } |
| 123 | + return EVM_VAL_UNDEFINED; |
| 124 | +} |
| 125 | + |
| 126 | +static evm_val_t * ecma_prototype_create(evm_t *e ){ |
| 127 | + evm_val_t * o = evm_object_create(e, GC_DICT, 0, 1); |
| 128 | + evm_attr_set_key_value(e, o, 0, ecma_hash_constructor, evm_mk_native( (intptr_t)ecma_new )); |
| 129 | + return o; |
| 130 | +} |
| 131 | + |
| 132 | +static evm_val_t ecma_set_prototype(evm_t * e, evm_val_t * p, int argc, evm_val_t * v){ |
| 133 | + EVM_UNUSED(p); |
| 134 | + if( argc > 0 ){ |
| 135 | + switch (evm_type(v)) { |
| 136 | + case TYPE_FUNCTION: |
| 137 | + if( evm_attr_create(e, v, 4) == ec_ok ){ |
| 138 | + evm_attr_set_key_value(e, v, 0, ecma_hash_constructor, *v); |
| 139 | + evm_attr_set_key_value(e, v, 1, ecma_hash_prototype, * ecma_prototype_create(e)); |
| 140 | + evm_attr_set_key_value(e, v, 2, ecma_hash_call, evm_mk_native((intptr_t)ecma_function_call)); |
| 141 | + evm_attr_set_key_value(e, v, 3, ecma_hash___proto__, *ecma_object_prototype); |
| 142 | + } |
| 143 | + evm_set_parent(v, ecma_object_prototype); |
| 144 | + break; |
| 145 | + case TYPE_OBJECT: |
| 146 | + #ifdef CONFIG_EVM_ECMA_OBJECT |
| 147 | + ecma_object_attrs_apply(e, v, ecma_object_prototype); |
| 148 | + #endif |
| 149 | + evm_set_parent(v, ecma_object_prototype); |
| 150 | + break; |
| 151 | + default: |
| 152 | + break; |
| 153 | + } |
| 154 | + } |
| 155 | + return EVM_VAL_UNDEFINED; |
| 156 | +} |
| 157 | + |
| 158 | +static evm_val_t ecma_isNaN(evm_t * e, evm_val_t * p, int argc, evm_val_t * v){ |
| 159 | + EVM_UNUSED(e);EVM_UNUSED(p); |
| 160 | + if( argc == 0 ) return EVM_VAL_TRUE; |
| 161 | + if( argc > 0 ) if( evm_is_nan(v) ) return EVM_VAL_TRUE; |
| 162 | + return EVM_VAL_FALSE; |
| 163 | +} |
| 164 | + |
| 165 | +int ecma_module(evm_t * e){ |
| 166 | + ecma_hash_constructor = evm_str_insert(e, "constructor", 1); |
| 167 | + ecma_hash_prototype = evm_str_insert(e, "prototype", 1); |
| 168 | + ecma_hash_call = evm_str_insert(e, "call", 1); |
| 169 | + ecma_hash___proto__ = evm_str_insert(e, "__proto__", 1); |
| 170 | + ecma_hash_hasOwnProperty = evm_str_insert(e, "hasOwnProperty", 1); |
| 171 | + ecma_hash_isPrototypeOf = evm_str_insert(e, "isPrototypeOf", 1); |
| 172 | + ecma_hash_toString = evm_str_insert(e, "toString", 1); |
| 173 | + ecma_hash_valueOf = evm_str_insert(e, "valueOf", 1); |
| 174 | + ecma_hash_length = evm_str_insert(e, "length", 1); |
| 175 | + ecma_hash_push = evm_str_insert(e, "push", 1); |
| 176 | + ecma_hash_pop = evm_str_insert(e, "pop", 1); |
| 177 | + ecma_hash_concat = evm_str_insert(e, "concat", 1); |
| 178 | + ecma_hash_fill = evm_str_insert(e, "fill", 1); |
| 179 | + ecma_hash_indexOf = evm_str_insert(e, "indexOf", 1); |
| 180 | + ecma_hash_shift = evm_str_insert(e, "shift", 1); |
| 181 | + ecma_hash_slice = evm_str_insert(e, "slice", 1); |
| 182 | + ecma_hash_copyWithin = evm_str_insert(e, "copyWithin", 1); |
| 183 | + ecma_hash_unshift = evm_str_insert(e, "unshift", 1); |
| 184 | + ecma_hash_filter = evm_str_insert(e, "filter", 1); |
| 185 | + ecma_hash_map = evm_str_insert(e, "map", 1); |
| 186 | + ecma_hash_find = evm_str_insert(e, "find", 1); |
| 187 | + ecma_hash_join = evm_str_insert(e, "join", 1); |
| 188 | + |
| 189 | + ecma_function_prototype = evm_object_create(e, GC_DICT, 0, 0); |
| 190 | + ecma_object_prototype = evm_object_create(e, GC_DICT, 0, 0); |
| 191 | + |
| 192 | +#ifdef CONFIG_EVM_ECMA_OBJECT |
| 193 | + ecma_Object = ecma_object_init(e); |
| 194 | + ecma_object_attrs_apply(e, ecma_object_prototype, ecma_function_prototype); |
| 195 | +#endif |
| 196 | +#ifdef CONFIG_EVM_ECMA_ARRAY |
| 197 | + ecma_Array = ecma_array_init(e); |
| 198 | +#endif |
| 199 | +#ifdef CONFIG_EVM_ECMA_NUMBER |
| 200 | + ecma_Number = ecma_number_init(e); |
| 201 | +#endif |
| 202 | +#ifdef CONFIG_EVM_ECMA_MATH |
| 203 | + ecma_Math = ecma_math_init(e); |
| 204 | +#endif |
| 205 | +#ifdef CONFIG_EVM_ECMA_STRING |
| 206 | + ecma_String = ecma_string_init(e); |
| 207 | +#endif |
| 208 | +#ifdef CONFIG_EVM_ECMA_REGEXP |
| 209 | + ecma_RegExp = ecma_regex_init(e); |
| 210 | +#endif |
| 211 | + evm_builtin_t natives[] = { |
| 212 | + {".set_prototype", evm_mk_native( (intptr_t)ecma_set_prototype )}, |
| 213 | + {".new", evm_mk_native( (intptr_t)ecma_new )}, |
| 214 | + {"isNaN", evm_mk_native( (intptr_t)ecma_isNaN )}, |
| 215 | + {"typeof", evm_mk_native( (intptr_t)ecma_typeof )}, |
| 216 | + #ifdef CONFIG_EVM_ECMA_REGEXP |
| 217 | + {"RegExp", *ecma_RegExp}, |
| 218 | + #endif |
| 219 | + #ifdef CONFIG_EVM_ECMA_MATH |
| 220 | + {"Math", *ecma_Math}, |
| 221 | + #endif |
| 222 | + #ifdef CONFIG_EVM_ECMA_OBJECT |
| 223 | + {"Object", *ecma_Object}, |
| 224 | + #endif |
| 225 | + #ifdef CONFIG_EVM_ECMA_ARRAY |
| 226 | + {"Array", *ecma_Array}, |
| 227 | + #endif |
| 228 | + #ifdef CONFIG_EVM_ECMA_NUMBER |
| 229 | + {"Number", *ecma_number_init(e)}, |
| 230 | + #endif |
| 231 | + #ifdef CONFIG_EVM_ECMA_STRING |
| 232 | + {"String", *ecma_string_init(e)}, |
| 233 | + #endif |
| 234 | + {NULL, EVM_VAL_UNDEFINED} |
| 235 | + }; |
| 236 | + return evm_native_add(e, natives); |
| 237 | +} |
0 commit comments