mirror of
https://github.com/bellard/quickjs.git
synced 2024-11-23 14:18:13 +08:00
JSX implementation
This commit is contained in:
parent
a60f3b0ac2
commit
43198ce9ec
4
.gitignore
vendored
4
.gitignore
vendored
@ -4,8 +4,8 @@
|
|||||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
# Premake files
|
# Premake files
|
||||||
.bin/*
|
.bin/
|
||||||
.build/*
|
.build/
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.suo
|
*.suo
|
||||||
|
15
premake5.lua
15
premake5.lua
@ -17,7 +17,11 @@ workspace "quickjs-msvc"
|
|||||||
-- Premake output folder
|
-- Premake output folder
|
||||||
location(path.join(".build", _ACTION))
|
location(path.join(".build", _ACTION))
|
||||||
|
|
||||||
defines {"JS_STRICT_NAN_BOXING"} -- this option enables x64 build
|
defines {
|
||||||
|
"JS_STRICT_NAN_BOXING", -- this option enables x64 build on Windows/MSVC
|
||||||
|
"CONFIG_BIGNUM",
|
||||||
|
"CONFIG_JSX", -- native JSX support - enables JSX literals
|
||||||
|
}
|
||||||
|
|
||||||
platforms { "x86", "x64", "arm32", "arm64" }
|
platforms { "x86", "x64", "arm32", "arm64" }
|
||||||
|
|
||||||
@ -71,6 +75,7 @@ project "quickjs"
|
|||||||
"libunicode.c",
|
"libunicode.c",
|
||||||
"quickjs.c",
|
"quickjs.c",
|
||||||
"quickjs-libc.c",
|
"quickjs-libc.c",
|
||||||
|
"libbf.c",
|
||||||
"libregexp.h",
|
"libregexp.h",
|
||||||
"libregexp-opcode.h",
|
"libregexp-opcode.h",
|
||||||
"libunicode.h",
|
"libunicode.h",
|
||||||
@ -79,7 +84,8 @@ project "quickjs"
|
|||||||
"quickjs.h",
|
"quickjs.h",
|
||||||
"quickjs-atom.h",
|
"quickjs-atom.h",
|
||||||
"quickjs-libc.h",
|
"quickjs-libc.h",
|
||||||
"quickjs-opcode.h"
|
"quickjs-opcode.h",
|
||||||
|
"quickjs-jsx.h",
|
||||||
}
|
}
|
||||||
|
|
||||||
-----------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------
|
||||||
@ -102,8 +108,11 @@ project "qjs"
|
|||||||
files {
|
files {
|
||||||
"qjs.c",
|
"qjs.c",
|
||||||
"repl.js",
|
"repl.js",
|
||||||
"repl.c"
|
"repl.c",
|
||||||
|
"qjscalc.js",
|
||||||
|
"qjscalc.c"
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Compile repl.js and save bytecode into repl.c
|
-- Compile repl.js and save bytecode into repl.c
|
||||||
prebuildcommands { "\"%{cfg.buildtarget.directory}/qjsc.exe\" -c -o \"../../repl.c\" -m \"../../repl.js\"" }
|
prebuildcommands { "\"%{cfg.buildtarget.directory}/qjsc.exe\" -c -o \"../../repl.c\" -m \"../../repl.js\"" }
|
||||||
|
prebuildcommands { "\"%{cfg.buildtarget.directory}/qjsc.exe\" -c -o \"../../qjscalc.c\" -m \"../../qjscalc.js\"" }
|
||||||
|
@ -223,6 +223,9 @@ DEF(BigDecimal, "BigDecimal")
|
|||||||
DEF(OperatorSet, "OperatorSet")
|
DEF(OperatorSet, "OperatorSet")
|
||||||
DEF(Operators, "Operators")
|
DEF(Operators, "Operators")
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_JSX
|
||||||
|
DEF(JSX, "JSX")
|
||||||
|
#endif
|
||||||
DEF(Map, "Map")
|
DEF(Map, "Map")
|
||||||
DEF(Set, "Set") /* Map + 1 */
|
DEF(Set, "Set") /* Map + 1 */
|
||||||
DEF(WeakMap, "WeakMap") /* Map + 2 */
|
DEF(WeakMap, "WeakMap") /* Map + 2 */
|
||||||
|
224
quickjs-jsx.h
Normal file
224
quickjs-jsx.h
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
|
||||||
|
/* JSX translates XML literals like this
|
||||||
|
*
|
||||||
|
* var jsx = <div foo="bar">some text</div>;
|
||||||
|
*
|
||||||
|
* into calls of "JSX driver function":
|
||||||
|
*
|
||||||
|
* __jsx__("div", {foo:"bar"}, ["some text"]);
|
||||||
|
*
|
||||||
|
* note:
|
||||||
|
* a) the call always have 3 arguments: string, object|null, array|null
|
||||||
|
* b) __jsx__ can be redefined, e.g. for https://mithril.js.org it will be just
|
||||||
|
*
|
||||||
|
* __jsx__ = m; // using mithril as JSX driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
static __exception int next_web_token(JSParseState *s) {
|
||||||
|
s->allow_web_name_token = 1;
|
||||||
|
int r = next_token(s);
|
||||||
|
s->allow_web_name_token = 0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int js_parse_jsx_expr(JSParseState *s, int level)
|
||||||
|
{
|
||||||
|
int atts_count = 0;
|
||||||
|
int kids_count = 0;
|
||||||
|
|
||||||
|
// NOTE: caller already consumed '<'
|
||||||
|
if (next_web_token(s)) goto fail;
|
||||||
|
if (s->token.val != TOK_IDENT)
|
||||||
|
return js_parse_error(s, "Expecting tag name");
|
||||||
|
|
||||||
|
//tag
|
||||||
|
JSAtom tag_atom = s->token.u.ident.atom;
|
||||||
|
JSValue tag = JS_AtomToString(s->ctx,tag_atom);
|
||||||
|
|
||||||
|
// load JSX function - driver of JSX expressions:
|
||||||
|
#if 1 // load it as a global function
|
||||||
|
emit_op(s, OP_get_var);
|
||||||
|
emit_atom(s, JS_ATOM_JSX);
|
||||||
|
#else // load it as a local/scope function - do we need that?
|
||||||
|
emit_op(s, OP_scope_get_var);
|
||||||
|
emit_atom(s, JS_ATOM_JSX);
|
||||||
|
emit_u16(s, s->cur_func->scope_level);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// #0 #1 #2
|
||||||
|
// JSX(tag, atts ,kids); where
|
||||||
|
// - atts - object {...}, can be empty
|
||||||
|
// - kids - array [...], can be empty
|
||||||
|
|
||||||
|
emit_push_const(s, tag, 0);
|
||||||
|
JS_FreeValue(s->ctx, tag);
|
||||||
|
|
||||||
|
// parse attributes
|
||||||
|
JSAtom attr_name = JS_ATOM_NULL;
|
||||||
|
JSValue attr_value = JS_UNINITIALIZED;
|
||||||
|
|
||||||
|
#if defined(CONFIG_JSX_SCITER) // HTML shortcuts used by Sciter
|
||||||
|
char class_buffer[512] = {0};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (next_web_token(s)) goto fail;
|
||||||
|
|
||||||
|
emit_op(s, OP_object);
|
||||||
|
|
||||||
|
while (s->token.val != '>') {
|
||||||
|
|
||||||
|
if (s->token.val == '/') {
|
||||||
|
next_token(s);
|
||||||
|
//json_parse_expect(s, '>');
|
||||||
|
if(s->token.val != '>')
|
||||||
|
js_parse_error(s, "expecting '>'");
|
||||||
|
goto GENERATE_KIDS;
|
||||||
|
}
|
||||||
|
#if defined(CONFIG_JSX_SCITER) // HTML shortcuts used by Sciter
|
||||||
|
if (s->token.val == '#') { // <div #some> -> <div id="some">
|
||||||
|
if (next_web_token(s)) goto fail;
|
||||||
|
if (s->token.val != TOK_IDENT) { js_parse_error(s, "expecting identifier"); goto fail; }
|
||||||
|
attr_name = JS_NewAtom(s->ctx,"id");
|
||||||
|
attr_value = JS_AtomToString(s->ctx, s->token.u.ident.atom);
|
||||||
|
goto PUSH_ATTR_VALUE;
|
||||||
|
}
|
||||||
|
if (s->token.val == '|') { // <input|text> -> <input type="text">
|
||||||
|
if (next_web_token(s)) goto fail;
|
||||||
|
if (s->token.val != TOK_IDENT) { js_parse_error(s, "expecting identifier"); goto fail; }
|
||||||
|
attr_name = JS_NewAtom(s->ctx, "type");
|
||||||
|
attr_value = JS_AtomToString(s->ctx, s->token.u.ident.atom);
|
||||||
|
goto PUSH_ATTR_VALUE;
|
||||||
|
}
|
||||||
|
if (s->token.val == '(') { // <input(foo)> -> <input name="foo">
|
||||||
|
if (next_web_token(s)) goto fail;
|
||||||
|
if (s->token.val != TOK_IDENT) { js_parse_error(s, "expecting identifier"); goto fail; }
|
||||||
|
attr_name = JS_NewAtom(s->ctx, "name");
|
||||||
|
attr_value = JS_AtomToString(s->ctx, s->token.u.ident.atom);
|
||||||
|
if (next_token(s)) goto fail;
|
||||||
|
if (s->token.val != ')') { js_parse_error(s, "expecting ')'"); goto fail; }
|
||||||
|
goto PUSH_ATTR_VALUE;
|
||||||
|
}
|
||||||
|
if (s->token.val == '.') { // <div.some> -> <div class="some">
|
||||||
|
if (next_web_token(s)) goto fail;
|
||||||
|
if (s->token.val != TOK_IDENT) { js_parse_error(s, "expecting identifier"); goto fail; }
|
||||||
|
char cls1[256];
|
||||||
|
const char *name = JS_AtomGetStr(s->ctx, cls1, countof(cls1), s->token.u.ident.atom);
|
||||||
|
if (strlen(class_buffer) + strlen(name) + 2 < countof(class_buffer)) {
|
||||||
|
if(class_buffer[0]) strcat(class_buffer, " ");
|
||||||
|
strcat(class_buffer, name);
|
||||||
|
}
|
||||||
|
next_web_token(s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (token_is_ident(s->token.val)) {
|
||||||
|
/* keywords and reserved words have a valid atom */
|
||||||
|
attr_name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
|
||||||
|
if (next_token(s))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (js_parse_expect(s, '='))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (s->token.val == TOK_STRING) {
|
||||||
|
attr_value = JS_DupValue(s->ctx,s->token.u.str.str);
|
||||||
|
PUSH_ATTR_VALUE:
|
||||||
|
if (emit_push_const(s, attr_value, 0))
|
||||||
|
goto fail;
|
||||||
|
JS_FreeValue(s->ctx, attr_value);
|
||||||
|
}
|
||||||
|
else if (s->token.val == '{')
|
||||||
|
{
|
||||||
|
if (next_token(s))
|
||||||
|
goto fail;
|
||||||
|
if (js_parse_assign_expr(s, TRUE))
|
||||||
|
goto fail;
|
||||||
|
if(s->token.val != '}')
|
||||||
|
return js_parse_error(s, "expecting '}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
set_object_name(s, attr_name);
|
||||||
|
emit_op(s, OP_define_field);
|
||||||
|
emit_atom(s, attr_name);
|
||||||
|
JS_FreeAtom(s->ctx, attr_name);
|
||||||
|
|
||||||
|
if (next_web_token(s))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_JSX_SCITER) // HTML shortcuts used by Sciter
|
||||||
|
if (class_buffer[0]) { // add remaining classes
|
||||||
|
attr_value = JS_NewString(s->ctx, class_buffer);
|
||||||
|
emit_push_const(s, JS_NewString(s->ctx, class_buffer), 0);
|
||||||
|
JS_FreeValue(s->ctx, attr_value);
|
||||||
|
attr_name = JS_NewAtom(s->ctx, "class");
|
||||||
|
set_object_name(s, attr_name);
|
||||||
|
emit_op(s, OP_define_field);
|
||||||
|
emit_atom(s, attr_name);
|
||||||
|
JS_FreeAtom(s->ctx, attr_name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// parse content of the element
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
const uint8_t *p;
|
||||||
|
p = s->last_ptr = s->buf_ptr;
|
||||||
|
s->last_line_num = s->token.line_num;
|
||||||
|
if (js_parse_string(s, '<', TRUE, p, &s->token, &p))
|
||||||
|
goto fail;
|
||||||
|
if (s->buf_ptr != p) {
|
||||||
|
s->buf_ptr = p;
|
||||||
|
if (emit_push_const(s, s->token.u.str.str, 1))
|
||||||
|
goto fail;
|
||||||
|
++kids_count;
|
||||||
|
}
|
||||||
|
next_token(s);
|
||||||
|
if (s->token.val == '<') {
|
||||||
|
if (*s->buf_ptr == '/') {
|
||||||
|
next_token(s); // skip '/'
|
||||||
|
next_web_token(s); // get tail tag name
|
||||||
|
if (token_is_ident(s->token.val)) { /* keywords and reserved words have a valid atom */
|
||||||
|
if(s->token.u.ident.atom != tag_atom)
|
||||||
|
return js_parse_error(s, "head and tail tags do not match");
|
||||||
|
next_token(s);
|
||||||
|
if (s->token.val != '>')
|
||||||
|
return js_parse_error(s, "expecting '>' in tail tag");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
js_parse_jsx_expr(s, level + 1);
|
||||||
|
++kids_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (s->token.val == '{') {
|
||||||
|
if (next_token(s))
|
||||||
|
goto fail;
|
||||||
|
if (js_parse_assign_expr(s, TRUE))
|
||||||
|
goto fail;
|
||||||
|
if(s->token.val != '}')
|
||||||
|
return js_parse_error(s, "expected '}'");
|
||||||
|
++kids_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GENERATE_KIDS:
|
||||||
|
emit_op(s, OP_array_from);
|
||||||
|
emit_u16(s, kids_count);
|
||||||
|
|
||||||
|
emit_op(s, OP_call);
|
||||||
|
emit_u16(s, 3);
|
||||||
|
|
||||||
|
if (level == 0)
|
||||||
|
next_token(s);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
JS_FreeValue(s->ctx, tag);
|
||||||
|
JS_FreeAtom(s->ctx, attr_name);
|
||||||
|
JS_FreeValue(s->ctx, attr_value);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
81
quickjs.c
81
quickjs.c
@ -2821,6 +2821,11 @@ static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
|
|||||||
return __JS_NewAtom(rt, p, atom_type);
|
return __JS_NewAtom(rt, p, atom_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSAtom JS_NewAtomLenRT(JSRuntime *rt, const char *str, int len)
|
||||||
|
{
|
||||||
|
return __JS_NewAtomInit(rt, str, len, JS_ATOM_TYPE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
|
static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
|
||||||
int atom_type)
|
int atom_type)
|
||||||
{
|
{
|
||||||
@ -2995,7 +3000,7 @@ static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
|
|||||||
#define ATOM_GET_STR_BUF_SIZE 64
|
#define ATOM_GET_STR_BUF_SIZE 64
|
||||||
|
|
||||||
/* Should only be used for debug. */
|
/* Should only be used for debug. */
|
||||||
static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
|
const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
|
||||||
JSAtom atom)
|
JSAtom atom)
|
||||||
{
|
{
|
||||||
if (__JS_AtomIsTaggedInt(atom)) {
|
if (__JS_AtomIsTaggedInt(atom)) {
|
||||||
@ -7357,7 +7362,7 @@ static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
|
void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
if (tab) {
|
if (tab) {
|
||||||
@ -9742,6 +9747,16 @@ void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSClassID JS_GetClassID(JSValueConst obj, void** ppopaque) {
|
||||||
|
JSObject *p;
|
||||||
|
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
|
||||||
|
return 0;
|
||||||
|
p = JS_VALUE_GET_OBJ(obj);
|
||||||
|
if(ppopaque)
|
||||||
|
*ppopaque = p->u.opaque;
|
||||||
|
return p->class_id;
|
||||||
|
}
|
||||||
|
|
||||||
#define HINT_STRING 0
|
#define HINT_STRING 0
|
||||||
#define HINT_NUMBER 1
|
#define HINT_NUMBER 1
|
||||||
#define HINT_NONE 2
|
#define HINT_NONE 2
|
||||||
@ -20061,6 +20076,9 @@ typedef struct JSParseState {
|
|||||||
BOOL is_module; /* parsing a module */
|
BOOL is_module; /* parsing a module */
|
||||||
BOOL allow_html_comments;
|
BOOL allow_html_comments;
|
||||||
BOOL ext_json; /* true if accepting JSON superset */
|
BOOL ext_json; /* true if accepting JSON superset */
|
||||||
|
#ifdef CONFIG_JSX;
|
||||||
|
BOOL allow_web_name_token; /* HTML and CSS tokens that accept '-' as part of the nmtoken */
|
||||||
|
#endif
|
||||||
} JSParseState;
|
} JSParseState;
|
||||||
|
|
||||||
typedef struct JSOpCode {
|
typedef struct JSOpCode {
|
||||||
@ -20306,6 +20324,13 @@ static __exception int js_parse_string(JSParseState *s, int sep,
|
|||||||
uint32_t c;
|
uint32_t c;
|
||||||
StringBuffer b_s, *b = &b_s;
|
StringBuffer b_s, *b = &b_s;
|
||||||
|
|
||||||
|
int multiline_str =
|
||||||
|
#ifdef CONFIG_JSX
|
||||||
|
sep == '`' || '<';
|
||||||
|
#else
|
||||||
|
sep == '`';
|
||||||
|
#endif
|
||||||
|
|
||||||
/* string */
|
/* string */
|
||||||
if (string_buffer_init(s->ctx, b, 32))
|
if (string_buffer_init(s->ctx, b, 32))
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -20319,7 +20344,7 @@ static __exception int js_parse_string(JSParseState *s, int sep,
|
|||||||
js_parse_error(s, "invalid character in a JSON string");
|
js_parse_error(s, "invalid character in a JSON string");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (sep == '`') {
|
if (multiline_str) {
|
||||||
if (c == '\r') {
|
if (c == '\r') {
|
||||||
if (p[1] == '\n')
|
if (p[1] == '\n')
|
||||||
p++;
|
p++;
|
||||||
@ -20330,8 +20355,16 @@ static __exception int js_parse_string(JSParseState *s, int sep,
|
|||||||
goto invalid_char;
|
goto invalid_char;
|
||||||
}
|
}
|
||||||
p++;
|
p++;
|
||||||
|
#ifdef CONFIG_JSX
|
||||||
|
if ((c == '{' || c == '<') && sep == '<') {
|
||||||
|
/* expr start */
|
||||||
|
--p;
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
if (c == sep)
|
if (c == sep)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (c == '$' && *p == '{' && sep == '`') {
|
if (c == '$' && *p == '{' && sep == '`') {
|
||||||
/* template start or middle part */
|
/* template start or middle part */
|
||||||
p++;
|
p++;
|
||||||
@ -20598,6 +20631,9 @@ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
|
|||||||
} else if (c >= 128) {
|
} else if (c >= 128) {
|
||||||
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
|
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_JSX
|
||||||
|
if (c == '-' && s->allow_web_name_token) {;} else
|
||||||
|
#endif
|
||||||
if (!lre_js_is_ident_next(c))
|
if (!lre_js_is_ident_next(c))
|
||||||
break;
|
break;
|
||||||
p = p1;
|
p = p1;
|
||||||
@ -20800,6 +20836,10 @@ static __exception int next_token(JSParseState *s)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '#':
|
case '#':
|
||||||
|
#ifdef CONFIG_JSX
|
||||||
|
if (s->allow_web_name_token) goto def_token;
|
||||||
|
#endif // CONFIG_JSX
|
||||||
|
|
||||||
/* private name */
|
/* private name */
|
||||||
{
|
{
|
||||||
const uint8_t *p1;
|
const uint8_t *p1;
|
||||||
@ -24227,6 +24267,10 @@ static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
|
|||||||
emit_label(s, label_next);
|
emit_label(s, label_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_JSX
|
||||||
|
#include "quickjs-jsx.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen)
|
static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen)
|
||||||
{
|
{
|
||||||
FuncCallType call_type;
|
FuncCallType call_type;
|
||||||
@ -24441,6 +24485,12 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#ifdef CONFIG_JSX
|
||||||
|
case '<':
|
||||||
|
if (js_parse_jsx_expr(s,0))
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case TOK_NEW:
|
case TOK_NEW:
|
||||||
if (next_token(s))
|
if (next_token(s))
|
||||||
return -1;
|
return -1;
|
||||||
@ -28027,6 +28077,9 @@ JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m->evaluated)
|
||||||
|
return m;
|
||||||
|
|
||||||
/* Evaluate the module code */
|
/* Evaluate the module code */
|
||||||
func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
|
func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
|
||||||
ret = JS_EvalFunction(ctx, func_obj);
|
ret = JS_EvalFunction(ctx, func_obj);
|
||||||
@ -28036,6 +28089,28 @@ JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSValue JS_GetModuleExportItem(JSContext *ctx, JSModuleDef *m, JSAtom atom)
|
||||||
|
{
|
||||||
|
JSValue rv = JS_UNDEFINED;
|
||||||
|
for (int n = 0; n < m->export_entries_count; ++n)
|
||||||
|
{
|
||||||
|
JSExportEntry *me = &m->export_entries[n];
|
||||||
|
if (me->local_name == atom && me->export_type == JS_EXPORT_TYPE_LOCAL /*???*/) {
|
||||||
|
rv = me->u.local.var_ref->value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JS_DupValue(ctx, rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue JS_GetModuleExportItemStr(JSContext *ctx, JSModuleDef *m, const char *name)
|
||||||
|
{
|
||||||
|
JSAtom atom = JS_NewAtom(ctx, name);
|
||||||
|
JSValue rv = JS_GetModuleExportItem(ctx, m, atom);
|
||||||
|
JS_FreeAtom(ctx, atom);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
static JSValue js_dynamic_import_job(JSContext *ctx,
|
static JSValue js_dynamic_import_job(JSContext *ctx,
|
||||||
int argc, JSValueConst *argv)
|
int argc, JSValueConst *argv)
|
||||||
{
|
{
|
||||||
|
@ -520,6 +520,8 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt);
|
|||||||
JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len);
|
JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len);
|
||||||
JSAtom JS_NewAtom(JSContext *ctx, const char *str);
|
JSAtom JS_NewAtom(JSContext *ctx, const char *str);
|
||||||
JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n);
|
JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n);
|
||||||
|
JSAtom JS_NewAtomLenRT(JSRuntime *rt, const char *str, int len);
|
||||||
|
const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size, JSAtom atom);
|
||||||
JSAtom JS_DupAtom(JSContext *ctx, JSAtom v);
|
JSAtom JS_DupAtom(JSContext *ctx, JSAtom v);
|
||||||
void JS_FreeAtom(JSContext *ctx, JSAtom v);
|
void JS_FreeAtom(JSContext *ctx, JSAtom v);
|
||||||
void JS_FreeAtomRT(JSRuntime *rt, JSAtom v);
|
void JS_FreeAtomRT(JSRuntime *rt, JSAtom v);
|
||||||
@ -535,6 +537,8 @@ typedef struct JSPropertyEnum {
|
|||||||
JSAtom atom;
|
JSAtom atom;
|
||||||
} JSPropertyEnum;
|
} JSPropertyEnum;
|
||||||
|
|
||||||
|
void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len);
|
||||||
|
|
||||||
typedef struct JSPropertyDescriptor {
|
typedef struct JSPropertyDescriptor {
|
||||||
int flags;
|
int flags;
|
||||||
JSValue value;
|
JSValue value;
|
||||||
@ -897,6 +901,7 @@ int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
|
|||||||
void JS_SetOpaque(JSValue obj, void *opaque);
|
void JS_SetOpaque(JSValue obj, void *opaque);
|
||||||
void *JS_GetOpaque(JSValueConst obj, JSClassID class_id);
|
void *JS_GetOpaque(JSValueConst obj, JSClassID class_id);
|
||||||
void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id);
|
void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id);
|
||||||
|
JSClassID JS_GetClassID(JSValueConst obj, void** ppopaque);
|
||||||
|
|
||||||
/* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
|
/* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
|
||||||
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
|
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
|
||||||
@ -999,6 +1004,9 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);
|
|||||||
JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
|
JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
|
||||||
|
JSValue JS_GetModuleExportItemStr(JSContext *ctx, JSModuleDef *m, const char *name);
|
||||||
|
JSValue JS_GetModuleExportItem(JSContext *ctx, JSModuleDef *m, JSAtom atom);
|
||||||
|
|
||||||
/* C function definition */
|
/* C function definition */
|
||||||
typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
|
typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
|
||||||
JS_CFUNC_generic,
|
JS_CFUNC_generic,
|
||||||
|
63
tests/JSX/test-jsx.js
Normal file
63
tests/JSX/test-jsx.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
|
||||||
|
|
||||||
|
// "driver" of JSX expressions
|
||||||
|
JSX = function(tag,atts,kids) {
|
||||||
|
return [tag,atts,kids]; // just produce "vnode" tuple
|
||||||
|
}
|
||||||
|
|
||||||
|
function isObject(object) {
|
||||||
|
return object != null && typeof object === 'object';
|
||||||
|
}
|
||||||
|
|
||||||
|
function deepEqual(object1, object2) {
|
||||||
|
const keys1 = Object.keys(object1);
|
||||||
|
const keys2 = Object.keys(object2);
|
||||||
|
|
||||||
|
if (keys1.length !== keys2.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key of keys1) {
|
||||||
|
const val1 = object1[key];
|
||||||
|
const val2 = object2[key];
|
||||||
|
const areObjects = isObject(val1) && isObject(val2);
|
||||||
|
if (
|
||||||
|
areObjects && !deepEqual(val1, val2) ||
|
||||||
|
!areObjects && val1 !== val2
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert(v1,v2) {
|
||||||
|
if(!deepEqual(v1,v2)) {
|
||||||
|
//console.log(JSON.stringify(v1,v2));
|
||||||
|
throw "problem in JSX construct"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var t1 = <div>test</div>;
|
||||||
|
var t1a = ["div",{},["test"]];
|
||||||
|
assert(t1,t1a);
|
||||||
|
|
||||||
|
var t2 = <h1 id="foo">test</h1>;
|
||||||
|
var t2a = ["h1",{id:"foo"},["test"]];
|
||||||
|
|
||||||
|
assert(t2,t2a);
|
||||||
|
|
||||||
|
var t3 = <div><h1/></div>;
|
||||||
|
var t3a = ["div",{},[["h1",{},[]]]];
|
||||||
|
|
||||||
|
assert(t3,t3a);
|
||||||
|
|
||||||
|
|
||||||
|
var t4 = <div id="foo" class="bar"><h1>header</h1><button>clicks</button></div>;
|
||||||
|
var t4a = ["div",{id:"foo",class:"bar"},[["h1",{},["header"]],["button",{},["clicks"]]]];
|
||||||
|
|
||||||
|
assert(t3,t3a);
|
||||||
|
|
||||||
|
console.log("JSX test passed!");
|
Loading…
Reference in New Issue
Block a user