Skip to content

Commit

Permalink
syntax: don't treat as and from as reserved keywords
Browse files Browse the repository at this point in the history
ECMAScript allows using `as` and `from` as identifiers so follow suit
and don't treat them specially while parsing. Extend the compiler logic
instead to check for TK_LABEL tokens with the expected value to properly
parse import and export statements.

Signed-off-by: Jo-Philipp Wich <[email protected]>
  • Loading branch information
jow- committed Nov 6, 2023
1 parent cfb24ea commit 1468cc4
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 14 deletions.
57 changes: 47 additions & 10 deletions compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,40 @@ uc_compiler_parse_match(uc_compiler_t *compiler, uc_tokentype_t type)
return true;
}

static bool
uc_compiler_keyword_check(uc_compiler_t *compiler, const char *keyword)
{
size_t keywordlen = strlen(keyword);

return (compiler->parser->curr.type == TK_LABEL &&
ucv_string_length(compiler->parser->curr.uv) == keywordlen &&
strcmp(ucv_string_get(compiler->parser->curr.uv), keyword) == 0);
}

static bool
uc_compiler_keyword_match(uc_compiler_t *compiler, const char *keyword)
{
if (!uc_compiler_keyword_check(compiler, keyword))
return false;

uc_compiler_parse_advance(compiler);

return true;
}

static void
uc_compiler_keyword_consume(uc_compiler_t *compiler, const char *keyword)
{
if (uc_compiler_keyword_check(compiler, keyword)) {
uc_compiler_parse_advance(compiler);

return;
}

uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
"Unexpected token\nExpecting '%s'", keyword);
}

static void
uc_compiler_parse_synchronize(uc_compiler_t *compiler)
{
Expand Down Expand Up @@ -3130,7 +3164,7 @@ uc_compiler_compile_exportlist(uc_compiler_t *compiler)
ucv_string_get(label));
}

if (uc_compiler_parse_match(compiler, TK_AS)) {
if (uc_compiler_keyword_match(compiler, "as")) {
if (uc_compiler_parse_match(compiler, TK_LABEL) || uc_compiler_parse_match(compiler, TK_STRING)) {
name = ucv_get(compiler->parser->prev.uv);
}
Expand Down Expand Up @@ -3553,23 +3587,23 @@ uc_compiler_compile_importlist(uc_compiler_t *compiler, uc_value_t *namelist)
label = NULL;

if (uc_compiler_parse_match(compiler, TK_DEFAULT)) {
uc_compiler_parse_consume(compiler, TK_AS);
uc_compiler_keyword_consume(compiler, "as");
uc_compiler_parse_consume(compiler, TK_LABEL);

label = ucv_get(compiler->parser->prev.uv);
}
else if (uc_compiler_parse_match(compiler, TK_STRING)) {
name = ucv_get(compiler->parser->prev.uv);

uc_compiler_parse_consume(compiler, TK_AS);
uc_compiler_keyword_consume(compiler, "as");
uc_compiler_parse_consume(compiler, TK_LABEL);

label = ucv_get(compiler->parser->prev.uv);
}
else if (uc_compiler_parse_match(compiler, TK_LABEL)) {
name = ucv_get(compiler->parser->prev.uv);

if (uc_compiler_parse_match(compiler, TK_AS)) {
if (uc_compiler_keyword_match(compiler, "as")) {
uc_compiler_parse_consume(compiler, TK_LABEL);

label = ucv_get(compiler->parser->prev.uv);
Expand All @@ -3588,9 +3622,12 @@ uc_compiler_compile_importlist(uc_compiler_t *compiler, uc_value_t *namelist)
ucv_put(label);

if (uc_compiler_parse_match(compiler, TK_RBRACE))
break;
return;
}
while (uc_compiler_parse_match(compiler, TK_COMMA));

uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
"Unexpected token\nExpecting 'as', ',' or '}'");
}

static void
Expand All @@ -3610,19 +3647,19 @@ uc_compiler_compile_import(uc_compiler_t *compiler)
/* import { ... } from */
if (uc_compiler_parse_match(compiler, TK_LBRACE)) {
uc_compiler_compile_importlist(compiler, namelist);
uc_compiler_parse_consume(compiler, TK_FROM);
uc_compiler_keyword_consume(compiler, "from");
}

/* import * as name from */
else if (uc_compiler_parse_match(compiler, TK_MUL)) {
uc_compiler_parse_consume(compiler, TK_AS);
uc_compiler_keyword_consume(compiler, "as");
uc_compiler_parse_consume(compiler, TK_LABEL);

uc_compiler_declare_local(compiler, compiler->parser->prev.uv, true);
uc_compiler_initialize_local(compiler);
ucv_array_push(namelist, ucv_boolean_new(true));

uc_compiler_parse_consume(compiler, TK_FROM);
uc_compiler_keyword_consume(compiler, "from");
}

/* import defaultExport [, ... ] from */
Expand All @@ -3639,7 +3676,7 @@ uc_compiler_compile_import(uc_compiler_t *compiler)

/* import defaultExport, * as name from */
else if (uc_compiler_parse_match(compiler, TK_MUL)) {
uc_compiler_parse_consume(compiler, TK_AS);
uc_compiler_keyword_consume(compiler, "as");
uc_compiler_parse_consume(compiler, TK_LABEL);

uc_compiler_declare_local(compiler, compiler->parser->prev.uv, true);
Expand All @@ -3654,7 +3691,7 @@ uc_compiler_compile_import(uc_compiler_t *compiler)
}
}

uc_compiler_parse_consume(compiler, TK_FROM);
uc_compiler_keyword_consume(compiler, "from");
}

uc_compiler_parse_consume(compiler, TK_STRING);
Expand Down
2 changes: 0 additions & 2 deletions include/ucode/lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,6 @@ typedef enum {
TK_TEMPLATE,
TK_IMPORT,
TK_EXPORT,
TK_FROM,
TK_AS,

TK_EOF,
TK_ERROR
Expand Down
2 changes: 0 additions & 2 deletions lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,11 @@ static const struct keyword reserved_words[] = {
{ TK_THIS, "this", 4 },
{ TK_NULL, "null", 4 },
{ TK_CASE, "case", 4 },
{ TK_FROM, "from", 4 },
{ TK_TRY, "try", 3 },
{ TK_FOR, "for", 3 },
{ TK_LOCAL, "let", 3 },
{ TK_IF, "if", 2 },
{ TK_IN, "in", 2 },
{ TK_AS, "as", 2 },
};


Expand Down
44 changes: 44 additions & 0 deletions tests/custom/99_bugs/44_compiler_as_from_identifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
Ensure that `as` and `from` are valid identifiers while their special
meaning in import statements is retained.

-- Testcase --
import { foo as bar } from 'mod';
import * as mod from 'mod';

function fn(as, from) {
return as + from;
}

as = 1;
from = true;

printf("%.J\n", [
bar,
mod,
fn(1, 2),
as,
from
]);
-- End --

-- File mod.uc --
export let foo = false;
export default 'test';
-- End --

-- Args --
-R -L files/
-- End --

-- Expect stdout --
[
false,
{
"foo": false,
"default": "test"
},
3,
1,
true
]
-- End --

0 comments on commit 1468cc4

Please sign in to comment.