From efb7009cfbfbb9b07dbcd058e24e76445d54326a Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Tue, 22 Jul 2014 20:49:51 +0400 Subject: [PATCH] Generate bytecode while parsing --- src/libcoreint/opcode-structures.h | 188 +- src/libcoreint/opcodes.c | 70 +- src/libcoreint/opcodes.h | 42 +- src/libjsparser/allocator.h | 53 - src/libjsparser/bytecode-generator.c | 418 ---- src/libjsparser/bytecode-generator.h | 25 - src/libjsparser/lexer.c | 154 +- src/libjsparser/lexer.h | 216 +- src/libjsparser/parser.c | 2331 +++++++++++++--------- src/libjsparser/parser.h | 421 +--- src/libruntime/jerry-exit.c | 4 +- src/libruntime/pretty-printer.c | 1081 ---------- src/libruntime/pretty-printer.h | 28 - src/libruntime/serializer.h | 2 + src/libruntime/target/linux/serializer.c | 26 +- src/main.c | 104 +- 16 files changed, 1882 insertions(+), 3281 deletions(-) delete mode 100644 src/libjsparser/allocator.h delete mode 100644 src/libjsparser/bytecode-generator.c delete mode 100644 src/libjsparser/bytecode-generator.h delete mode 100644 src/libruntime/pretty-printer.c delete mode 100644 src/libruntime/pretty-printer.h diff --git a/src/libcoreint/opcode-structures.h b/src/libcoreint/opcode-structures.h index 07415491c..c3782bf77 100644 --- a/src/libcoreint/opcode-structures.h +++ b/src/libcoreint/opcode-structures.h @@ -166,6 +166,11 @@ OP_CODE_DECL (b_xor, T_IDX_IDX_IDX, var_left, var_right) +/** dst = ~ R */ +OP_CODE_DECL (b_not, T_IDX_IDX, + dst, + var_right) + // Binary logical operators. // Operands are booleans. // Return boolean. @@ -182,6 +187,11 @@ OP_CODE_DECL (logical_or, T_IDX_IDX_IDX, var_left, var_right) +/** dst = ! R */ +OP_CODE_DECL (logical_not, T_IDX_IDX, + dst, + var_right) + // Equality operations. /** dst = L == R. */ @@ -234,6 +244,18 @@ OP_CODE_DECL (greater_or_equal_than, T_IDX_IDX_IDX, var_left, var_right) +/** dst = L instanceof R. */ +OP_CODE_DECL (instanceof, T_IDX_IDX_IDX, + dst, + var_left, + var_right) + +/** dst = L in R. */ +OP_CODE_DECL (in, T_IDX_IDX_IDX, + dst, + var_left, + var_right) + // Assignment operators. // Assign value to LEFT operand based on value of RIGHT operand. @@ -244,22 +266,43 @@ OP_CODE_DECL (assignment, T_IDX_IDX, // Functions calls, declarations and argument handling -/** name(arg1); */ -OP_CODE_DECL (call_1, T_IDX_IDX, +/** a = name(); */ +OP_CODE_DECL (call_0, T_IDX_IDX, + lhs, + name_lit_idx) + +/** a = name(arg1); */ +OP_CODE_DECL (call_1, T_IDX_IDX_IDX, + lhs, name_lit_idx, arg1_lit_idx) -/** name(arg1, arg2); */ -OP_CODE_DECL (call_2, T_IDX_IDX_IDX, - name_lit_idx, - arg1_lit_idx, - arg2_lit_idx) - -/** name(arg1, arg2, ... */ +/** a = name(arg1, ... */ OP_CODE_DECL (call_n, T_IDX_IDX_IDX, + lhs, name_lit_idx, - arg1_lit_idx, - arg2_lit_idx) + arg1_lit_idx) + +/** a = new name(); */ +OP_CODE_DECL (construct_0, T_IDX_IDX, + lhs, + name_lit_idx) + +/** a = new name(arg1); */ +OP_CODE_DECL (construct_1, T_IDX_IDX_IDX, + lhs, + name_lit_idx, + arg1_lit_idx) + +/** a = new name(arg1, ... */ +OP_CODE_DECL (construct_n, T_IDX_IDX_IDX, + lhs, + name_lit_idx, + arg1_lit_idx) + +/** name(); */ +OP_CODE_DECL (func_decl_0, T_IDX, + name_lit_idx) /** name(arg1); */ OP_CODE_DECL (func_decl_1, T_IDX_IDX, @@ -278,19 +321,27 @@ OP_CODE_DECL (func_decl_n, T_IDX_IDX_IDX, arg1_lit_idx, arg2_lit_idx) -/** ..., arg1, ... */ -OP_CODE_DECL (varg_1, T_IDX, +/** a = name(); */ +OP_CODE_DECL (func_expr_0, T_IDX_IDX, + lhs, + name_lit_idx) + +/** a = name(arg1); */ +OP_CODE_DECL (func_expr_1, T_IDX_IDX_IDX, + lhs, + name_lit_idx, + arg1_lit_idx) + +/** a = name(arg1, ... */ +OP_CODE_DECL (func_expr_n, T_IDX_IDX_IDX, + lhs, + name_lit_idx, arg1_lit_idx) /** ..., arg1); */ OP_CODE_DECL (varg_1_end, T_IDX, arg1_lit_idx) -/** ..., arg1, arg2, ... */ -OP_CODE_DECL (varg_2, T_IDX_IDX, - arg1_lit_idx, - arg2_lit_idx) - /** ..., arg1, arg2); */ OP_CODE_DECL (varg_2_end, T_IDX_IDX, arg1_lit_idx, @@ -356,26 +407,91 @@ OP_CODE_DECL (loop_postcond, T_IDX_IDX, condition, body_root) -///** for vars...in iter, state, ctl */ -//OP_CODE_DECL (loop_init, T_IDX_IDX_IDX, -// start_idx, stop_idx, step_idx) -///** loop (condition) */ -//OP_CODE_DECL (loop_cond_pre_begin, T_IDX_IDX, -// condition, body_root) -///** i++;*/ -//OP_CODE_DECL (loop_cond_pre_end, T_IDX, -// iterator, body_root) +/** a = [] */ +OP_CODE_DECL (array_0, T_IDX, + lhs) -// Property accessors (array, objects, strings) -/** Array ops for ILMIR*/ -//OP_CODE_DECL (array_copy, T_IDX_IDX, /** L = R */ -// var_left, var_right) -//OP_CODE_DECL (array_set, T_IDX_IDX_IDX, /** array[index] = src */ -// dst, var_left, var_right) -//OP_CODE_DECL (array_get, T_IDX_IDX_IDX, /** dst = array[index] */ -// dst, array, index) +/** a = [b] */ +OP_CODE_DECL (array_1, T_IDX_IDX, + lhs, + elem1) -//// TODO +/** a = [b, c] */ +OP_CODE_DECL (array_2, T_IDX_IDX_IDX, + lhs, + elem1, + elem2) + +/** a = [b, c ... */ +OP_CODE_DECL (array_n, T_IDX_IDX_IDX, + lhs, + elem1, + elem2) + +/** a = b : c */ +OP_CODE_DECL (prop, T_IDX_IDX_IDX, + lhs, + name, + value) + +/** a = b.c OR a = b[c] */ +OP_CODE_DECL (prop_access, T_IDX_IDX_IDX, + lhs, + obj, + prop) + +/** a = get prop () */ +OP_CODE_DECL (prop_get_decl, T_IDX_IDX, + lhs, + prop) + +/** a = set prop (arg) */ +OP_CODE_DECL (prop_set_decl, T_IDX_IDX_IDX, + lhs, + prop, + arg) + +/** a = { } */ +OP_CODE_DECL (obj_0, T_IDX, + lhs) + +/** a = { b } */ +OP_CODE_DECL (obj_1, T_IDX_IDX, + lhs, + arg1) + +/** a = { b, c } */ +OP_CODE_DECL (obj_2, T_IDX_IDX_IDX, + lhs, + arg1, + arg2) + +/** a = { b, c ... */ +OP_CODE_DECL (obj_n, T_IDX_IDX_IDX, + lhs, + arg1, + arg2) + +/** a = this */ +OP_CODE_DECL (this, T_IDX, + lhs) + +/** a = delete b */ +OP_CODE_DECL (delete, T_IDX_IDX, + lhs, + obj) + +/** a = delete b */ +OP_CODE_DECL (typeof, T_IDX_IDX, + lhs, + obj) + +/** with (b) { */ +OP_CODE_DECL (with, T_IDX, + expr) + +/** } */ +OP_CODE_DECL_VOID (end_with) // Variable declaration OP_CODE_DECL (decl_var, T_IDX, diff --git a/src/libcoreint/opcodes.c b/src/libcoreint/opcodes.c index abb07cef1..5d13c8b44 100644 --- a/src/libcoreint/opcodes.c +++ b/src/libcoreint/opcodes.c @@ -22,19 +22,42 @@ void opfunc_loop_init_num (OPCODE opdata __unused, struct __int_data *int_data _ void opfunc_loop_precond_begin_num (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_loop_precond_end_num (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_loop_postcond (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } -void opfunc_call_2 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_call_0 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_call_n (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_construct_0 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_construct_1 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_construct_n (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_func_decl_0 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_func_decl_1 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_func_decl_2 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_func_decl_n (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } -void opfunc_varg_1 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_func_expr_0 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_func_expr_1 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_func_expr_n (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_varg_1_end (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } -void opfunc_varg_2 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_varg_2_end (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_varg_3 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_varg_3_end (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_retval (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_ret (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_array_0 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_array_1 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_array_2 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_array_n (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_obj_0 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_obj_1 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_obj_2 (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_obj_n (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_prop (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_prop_access (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_prop_get_decl (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_prop_set_decl (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_this (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_delete (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_typeof (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_with (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_end_with (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_decl_var (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_nop (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_equal_value (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_not_equal_value (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } @@ -44,6 +67,8 @@ void opfunc_less_than (OPCODE opdata __unused, struct __int_data *int_data __unu void opfunc_greater_than (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_less_or_equal_than (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_greater_or_equal_than (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_instanceof (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_in (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_assignment(OPCODE opdata __unused, @@ -54,9 +79,11 @@ opfunc_assignment(OPCODE opdata __unused, void opfunc_logical_and (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_logical_or (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_logical_not (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_b_and (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_b_or (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_b_xor (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } +void opfunc_b_not (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_b_shift_left (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_b_shift_right (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } void opfunc_b_shift_uright (OPCODE opdata __unused, struct __int_data *int_data __unused) { JERRY_UNREACHABLE (); } @@ -124,8 +151,10 @@ GETOP_IMPL_3 (b_shift_uright, dst, var_left, var_right) GETOP_IMPL_3 (b_and, dst, var_left, var_right) GETOP_IMPL_3 (b_or, dst, var_left, var_right) GETOP_IMPL_3 (b_xor, dst, var_left, var_right) +GETOP_IMPL_2 (b_not, dst, var_right) GETOP_IMPL_3 (logical_and, dst, var_left, var_right) GETOP_IMPL_3 (logical_or, dst, var_left, var_right) +GETOP_IMPL_2 (logical_not, dst, var_right) GETOP_IMPL_3 (equal_value, dst, var_left, var_right) GETOP_IMPL_3 (not_equal_value, dst, var_left, var_right) GETOP_IMPL_3 (equal_value_type, dst, var_left, var_right) @@ -134,16 +163,23 @@ GETOP_IMPL_3 (less_than, dst, var_left, var_right) GETOP_IMPL_3 (greater_than, dst, var_left, var_right) GETOP_IMPL_3 (less_or_equal_than, dst, var_left, var_right) GETOP_IMPL_3 (greater_or_equal_than, dst, var_left, var_right) +GETOP_IMPL_3 (instanceof, dst, var_left, var_right) +GETOP_IMPL_3 (in, dst, var_left, var_right) GETOP_IMPL_2 (assignment, value_left, value_right) -GETOP_IMPL_2 (call_1, name_lit_idx, arg1_lit_idx) -GETOP_IMPL_3 (call_2, name_lit_idx, arg1_lit_idx, arg2_lit_idx) -GETOP_IMPL_3 (call_n, name_lit_idx, arg1_lit_idx, arg2_lit_idx) +GETOP_IMPL_2 (call_0, lhs, name_lit_idx) +GETOP_IMPL_3 (call_1, lhs, name_lit_idx, arg1_lit_idx) +GETOP_IMPL_3 (call_n, lhs, name_lit_idx, arg1_lit_idx) +GETOP_IMPL_2 (construct_0, lhs, name_lit_idx) +GETOP_IMPL_3 (construct_1, lhs, name_lit_idx, arg1_lit_idx) +GETOP_IMPL_3 (construct_n, lhs, name_lit_idx, arg1_lit_idx) +GETOP_IMPL_1 (func_decl_0, name_lit_idx) GETOP_IMPL_2 (func_decl_1, name_lit_idx, arg1_lit_idx) GETOP_IMPL_3 (func_decl_2, name_lit_idx, arg1_lit_idx, arg2_lit_idx) GETOP_IMPL_3 (func_decl_n, name_lit_idx, arg1_lit_idx, arg2_lit_idx) -GETOP_IMPL_1 (varg_1, arg1_lit_idx) +GETOP_IMPL_2 (func_expr_0, lhs, name_lit_idx) +GETOP_IMPL_3 (func_expr_1, lhs, name_lit_idx, arg1_lit_idx) +GETOP_IMPL_3 (func_expr_n, lhs, name_lit_idx, arg1_lit_idx) GETOP_IMPL_1 (varg_1_end, arg1_lit_idx) -GETOP_IMPL_2 (varg_2, arg1_lit_idx, arg2_lit_idx) GETOP_IMPL_2 (varg_2_end, arg1_lit_idx, arg2_lit_idx) GETOP_IMPL_3 (varg_3, arg1_lit_idx, arg2_lit_idx, arg3_lit_idx) GETOP_IMPL_3 (varg_3_end, arg1_lit_idx, arg2_lit_idx, arg3_lit_idx) @@ -155,4 +191,22 @@ GETOP_IMPL_3 (loop_init_num, start, stop, step) GETOP_IMPL_2 (loop_precond_begin_num, condition, after_loop_op) GETOP_IMPL_3 (loop_precond_end_num, iterator, step, precond_begin) GETOP_IMPL_2 (loop_postcond, condition, body_root) +GETOP_IMPL_1 (array_0, lhs) +GETOP_IMPL_2 (array_1, lhs, elem1) +GETOP_IMPL_3 (array_2, lhs, elem1, elem2) +GETOP_IMPL_3 (array_n, lhs, elem1, elem2) +GETOP_IMPL_3 (prop, lhs, name, value) +GETOP_IMPL_3 (prop_access, lhs, obj, prop) +GETOP_IMPL_2 (prop_get_decl, lhs, prop) +GETOP_IMPL_3 (prop_set_decl, lhs, prop, arg) +GETOP_IMPL_1 (obj_0, lhs) +GETOP_IMPL_2 (obj_1, lhs, arg1) +GETOP_IMPL_3 (obj_2, lhs, arg1, arg2) +GETOP_IMPL_3 (obj_n, lhs, arg1, arg2) +GETOP_IMPL_1 (this, lhs) +GETOP_IMPL_2 (delete, lhs, obj) +GETOP_IMPL_2 (typeof, lhs, obj) +GETOP_IMPL_1 (with, expr) +GETOP_IMPL_0 (end_with) +GETOP_IMPL_1 (decl_var, variable) diff --git a/src/libcoreint/opcodes.h b/src/libcoreint/opcodes.h index 9cd396428..a9e24c2ef 100644 --- a/src/libcoreint/opcodes.h +++ b/src/libcoreint/opcodes.h @@ -42,21 +42,46 @@ typedef void (*opfunc)(OPCODE, struct __int_data *); op(loop_postcond) #define OP_CALLS_AND_ARGS(op) \ + op(call_0) \ op(call_1) \ - op(call_2) \ op(call_n) \ + op(construct_0) \ + op(construct_1) \ + op(construct_n) \ + op(func_decl_0) \ op(func_decl_1) \ op(func_decl_2) \ op(func_decl_n) \ - op(varg_1) \ + op(func_expr_0) \ + op(func_expr_1) \ + op(func_expr_n) \ op(varg_1_end) \ - op(varg_2) \ op(varg_2_end) \ op(varg_3) \ op(varg_3_end) \ op(retval) \ op(ret) +#define OP_INITS(op) \ + op(array_0) \ + op(array_1) \ + op(array_2) \ + op(array_n) \ + op(prop) \ + op(prop_access) \ + op(prop_get_decl) \ + op(prop_set_decl) \ + op(obj_0) \ + op(obj_1) \ + op(obj_2) \ + op(obj_n) \ + op(this) \ + op(delete) \ + op(typeof) \ + op(with) \ + op(end_with) \ + op(decl_var) + #define OP_ASSIGNMENTS(op) \ op(assignment) @@ -68,11 +93,13 @@ typedef void (*opfunc)(OPCODE, struct __int_data *); #define OP_B_BITWISE(op) \ op(b_and) \ op(b_or) \ - op(b_xor) + op(b_xor) \ + op(b_not) #define OP_B_LOGICAL(op) \ op(logical_and) \ - op(logical_or) + op(logical_or) \ + op(logical_not) #define OP_EQUALITY(op) \ op(equal_value) \ @@ -84,7 +111,9 @@ typedef void (*opfunc)(OPCODE, struct __int_data *); op(less_than) \ op(greater_than) \ op(less_or_equal_than) \ - op(greater_or_equal_than) + op(greater_or_equal_than) \ + op(instanceof) \ + op(in) #define OP_ARITHMETIC(op) \ op(addition) \ @@ -106,6 +135,7 @@ typedef void (*opfunc)(OPCODE, struct __int_data *); #define OP_LIST(op) \ OP_LOOPS(op) \ OP_CALLS_AND_ARGS(op) \ + OP_INITS(op) \ OP_ASSIGNMENTS(op) \ OP_B_LOGICAL(op) \ OP_B_BITWISE(op) \ diff --git a/src/libjsparser/allocator.h b/src/libjsparser/allocator.h deleted file mode 100644 index b8bdac751..000000000 --- a/src/libjsparser/allocator.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright 2014 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* This allocator only allocates a memmory and doesn't free it. - Use it only in dedicated parser, otherwise use jerry fixed pool allocator. */ -#ifndef ALLOCATOR_H -#define ALLOCATOR_H - -#include "../globals.h" - -#define ALLOCATION_BUFFER_SIZE 4096 - -char allocation_buffer[ALLOCATION_BUFFER_SIZE]; -char *free_memory; - -static void * -geppetto_allocate_memory (size_t size) -{ - void *res; - if (!free_memory) - free_memory = allocation_buffer; - - res = free_memory; - free_memory += size; - JERRY_ASSERT (free_memory - allocation_buffer < ALLOCATION_BUFFER_SIZE); - return res; -} - -static inline void * -malloc (size_t size) -{ - return geppetto_allocate_memory (size); -} - -static inline void -free (void *mem __unused) -{ - JERRY_UNREACHABLE (); -} - -#endif // ALLOCATOR_H diff --git a/src/libjsparser/bytecode-generator.c b/src/libjsparser/bytecode-generator.c deleted file mode 100644 index 08127037b..000000000 --- a/src/libjsparser/bytecode-generator.c +++ /dev/null @@ -1,418 +0,0 @@ -/* Copyright 2014 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "bytecode-generator.h" -#include "globals.h" -#include "libcoreint/opcodes.h" -#include "libruntime/serializer.h" -#include "libruntime/jerry-libc.h" - -static uint8_t opcode_index; - -#define MAX_STACK_SIZE 10 - -static uint8_t opcode_stack[10]; -static uint8_t stack_head; - -static void -push_opcode (uint8_t opcode) -{ - JERRY_ASSERT (stack_head < MAX_STACK_SIZE); - opcode_stack[stack_head++] = opcode; -} - -static uint8_t -pop_opcode (void) -{ - return opcode_stack[--stack_head]; -} - -void -generator_init (void) -{ - opcode_index = 0; - stack_head = 0; -} - -void -generator_dump_strings (const char **strings, uint8_t num) -{ - uint8_t len = num, i; - - for (i = 0; i < num; i++) - { - serializer_dump_data (&len, 1); - len = (uint8_t) (len + __strlen (strings[i])); - } - - for (i = 0; i < num; i++) - serializer_dump_data (strings[i], __strlen (strings[i]) + 1); -} - -static bool -is_expression (statement stmt) -{ - switch (stmt.type) - { - case STMT_IF: - case STMT_ELSE_IF: - case STMT_END_DO_WHILE: - case STMT_WHILE: - case STMT_RETURN: - case STMT_WITH: - case STMT_SWITCH: - case STMT_CASE: - case STMT_THROW: - case STMT_EXPRESSION: - return true; - - default: - return false; - } -} - -static bool -is_assignment (statement stmt) -{ - JERRY_ASSERT (is_expression (stmt)); - return stmt.data.expr.oper != AO_NONE; -} - -static expression_type -get_expression_type (statement stmt) -{ - JERRY_ASSERT (is_expression (stmt)); - return stmt.data.expr.type; -} - -static bool -expression_has_operands (statement stmt) -{ - switch (get_expression_type (stmt)) - { - case ET_OBJECT: - case ET_FUNCTION: - case ET_ARRAY: - case ET_SUBEXPRESSION: - case ET_NONE: - return false; - - default: - return true; - } -} - -static operand -first_operand (statement stmt) -{ - JERRY_ASSERT (expression_has_operands (stmt)); - return stmt.data.expr.data.ops.op1; -} - -static literal -first_operand_as_literal (statement stmt) -{ - operand oper = first_operand (stmt); - - JERRY_ASSERT (oper.is_literal); - - return oper.data.lit; -} - -static uint8_t -first_operand_id (statement stmt) -{ - JERRY_ASSERT (expression_has_operands (stmt)); - if (first_operand (stmt).is_literal) - JERRY_UNIMPLEMENTED (); - return first_operand (stmt).data.name; -} - -static operand -second_operand (statement stmt) -{ - JERRY_ASSERT (expression_has_operands (stmt)); - return stmt.data.expr.data.ops.op2; -} - -static uint8_t -second_operand_id (statement stmt) -{ - JERRY_ASSERT (expression_has_operands (stmt)); - if (second_operand (stmt).is_literal) - JERRY_UNIMPLEMENTED (); - return second_operand (stmt).data.name; -} - -static uint8_t -lhs (statement stmt) -{ - JERRY_ASSERT (is_assignment (stmt)); - - return stmt.data.expr.var; -} - -static void -dump_opcode (OPCODE *opcode) -{ - serializer_dump_data (opcode, sizeof (OPCODE)); - opcode_index++; -} - -static assignment_operator -get_assignment_operator (statement stmt) -{ - JERRY_ASSERT (is_assignment (stmt)); - - return stmt.data.expr.oper; -} - -static OPCODE -generate_triple_address (OPCODE (*getop)(T_IDX, T_IDX, T_IDX), statement stmt) -{ - return (*getop) (lhs (stmt), first_operand_id (stmt), second_operand_id (stmt)); -} - -void -generator_dump_statement (statement stmt) -{ - OPCODE opcode = getop_nop (); - JERRY_STATIC_ASSERT (sizeof (OPCODE) <= sizeof (uint32_t)); - - switch (stmt.type) - { - case STMT_EMPTY: - break; - - case STMT_WHILE: - if (!is_assignment (stmt)) - { - literal lit; - - switch (get_expression_type (stmt)) - { - case ET_LITERAL: - lit = first_operand_as_literal (stmt); - if (lit.type == LIT_BOOL && lit.data.is_true) - { - opcode = getop_loop_inf ((uint8_t) (opcode_index + 1)); - push_opcode ((uint8_t) (opcode_index + 1)); - dump_opcode (&opcode); - return; - } - else - JERRY_UNIMPLEMENTED (); - break; - - default: - JERRY_UNIMPLEMENTED (); - } - } - else - JERRY_UNIMPLEMENTED (); - break; - - case STMT_EXPRESSION: - if (is_assignment (stmt)) - { - switch (get_expression_type (stmt)) - { - case ET_NONE: - JERRY_UNREACHABLE (); - break; - - case ET_LOGICAL_OR: - opcode = generate_triple_address (getop_logical_or, stmt); - dump_opcode (&opcode); - break; - - case ET_LOGICAL_AND: - opcode = generate_triple_address (getop_logical_and, stmt); - dump_opcode (&opcode); - break; - - case ET_BITWISE_OR: - opcode = generate_triple_address (getop_b_or, stmt); - dump_opcode (&opcode); - break; - - case ET_BITWISE_XOR: - opcode = generate_triple_address (getop_b_xor, stmt); - dump_opcode (&opcode); - break; - - case ET_BITWISE_AND: - opcode = generate_triple_address (getop_b_and, stmt); - dump_opcode (&opcode); - break; - - case ET_DOUBLE_EQ: - opcode = generate_triple_address (getop_equal_value, stmt); - dump_opcode (&opcode); - break; - - case ET_NOT_EQ: - opcode = generate_triple_address (getop_not_equal_value, stmt); - dump_opcode (&opcode); - break; - - case ET_TRIPLE_EQ: - opcode = generate_triple_address (getop_equal_value_type, stmt); - dump_opcode (&opcode); - break; - - case ET_NOT_DOUBLE_EQ: - opcode = generate_triple_address (getop_not_equal_value_type, stmt); - dump_opcode (&opcode); - break; - - case ET_LESS: - opcode = generate_triple_address (getop_less_than, stmt); - dump_opcode (&opcode); - break; - - case ET_GREATER: - opcode = generate_triple_address (getop_greater_than, stmt); - dump_opcode (&opcode); - break; - - case ET_LESS_EQ: - opcode = generate_triple_address (getop_less_or_equal_than, stmt); - dump_opcode (&opcode); - break; - - case ET_GREATER_EQ: - opcode = generate_triple_address (getop_greater_or_equal_than, stmt); - dump_opcode (&opcode); - break; - - case ET_INSTANCEOF: - case ET_IN: - JERRY_UNIMPLEMENTED (); - break; - - case ET_LSHIFT: - opcode = generate_triple_address (getop_b_shift_left, stmt); - dump_opcode (&opcode); - break; - - case ET_RSHIFT: - opcode = generate_triple_address (getop_b_shift_right, stmt); - dump_opcode (&opcode); - break; - - case ET_RSHIFT_EX: - opcode = generate_triple_address (getop_b_shift_uright, stmt); - dump_opcode (&opcode); - break; - - case ET_PLUS: - opcode = generate_triple_address (getop_addition, stmt); - dump_opcode (&opcode); - break; - - case ET_MINUS: - opcode = generate_triple_address (getop_substraction, stmt); - dump_opcode (&opcode); - break; - - case ET_MULT: - opcode = generate_triple_address (getop_multiplication, stmt); - dump_opcode (&opcode); - break; - - case ET_DIV: - opcode = generate_triple_address (getop_division, stmt); - dump_opcode (&opcode); - break; - - case ET_MOD: - opcode = generate_triple_address (getop_remainder, stmt); - dump_opcode (&opcode); - break; - - case ET_UNARY_DELETE: - case ET_UNARY_VOID: - case ET_UNARY_TYPEOF: - JERRY_UNIMPLEMENTED (); - break; - - case ET_UNARY_INCREMENT: - // opcode = getop_addition (first_operand_id (stmt), first_operand_id (stmt), INTEGER_ONE); - case ET_UNARY_DECREMENT: - case ET_UNARY_PLUS: - case ET_UNARY_MINUS: - case ET_UNARY_COMPL: - case ET_UNARY_NOT: - case ET_POSTFIX_INCREMENT: - case ET_POSTFIX_DECREMENT: - case ET_CALL: - case ET_NEW: - case ET_INDEX: - case ET_PROP_REF: - case ET_OBJECT: - case ET_FUNCTION: - case ET_ARRAY: - case ET_SUBEXPRESSION: - JERRY_UNIMPLEMENTED (); - break; - - case ET_LITERAL: - case ET_IDENTIFIER: - switch (get_assignment_operator (stmt)) - { - case AO_NONE: - JERRY_UNREACHABLE (); - break; - - case AO_EQ: - opcode = getop_assignment (lhs (stmt), first_operand_id (stmt)); - dump_opcode (&opcode); - return; - - default: - JERRY_UNIMPLEMENTED (); - } - JERRY_UNREACHABLE (); - - default: - JERRY_UNREACHABLE (); - } - - if (get_assignment_operator (stmt) != AO_EQ) - JERRY_UNIMPLEMENTED (); - - } - else - { - call_expression expr = stmt.data.expr.data.call_expr; - JERRY_ASSERT (!is_operand_list_empty (expr.args)); - if (!is_operand_empty (expr.args.ops[1])) - JERRY_UNREACHABLE (); - if (expr.args.ops[0].is_literal) - JERRY_UNREACHABLE (); - opcode = getop_call_1 (expr.name, expr.args.ops[0].data.name); - } - break; - - case STMT_END_WHILE: - opcode = getop_jmp (pop_opcode ()); - break; - - default: - __printf (" generator_dump_statement: %d ", stmt.type); - JERRY_UNREACHABLE (); - } -} \ No newline at end of file diff --git a/src/libjsparser/bytecode-generator.h b/src/libjsparser/bytecode-generator.h deleted file mode 100644 index 4634decc2..000000000 --- a/src/libjsparser/bytecode-generator.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright 2014 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef BYTECODE_GENERATOR_H -#define BYTECODE_GENERATOR_H - -#include "parser.h" - -void generator_init (void); -void generator_dump_strings (const char **, uint8_t); -void generator_dump_statement (statement); - -#endif // BYTECODE_GENERATOR_H \ No newline at end of file diff --git a/src/libjsparser/lexer.c b/src/libjsparser/lexer.c index df053daaf..9d06ab772 100644 --- a/src/libjsparser/lexer.c +++ b/src/libjsparser/lexer.c @@ -13,14 +13,14 @@ * limitations under the License. */ -#include "allocator.h" +#include "mem-allocator.h" #include "globals.h" #include "jerry-libc.h" #include "lexer.h" #include "parser.h" static token saved_token; -static token empty_token = { .type = TOK_EMPTY, .data.none = NULL }; +static token empty_token = { .type = TOK_EMPTY, .data.uid = 0 }; typedef struct { @@ -45,7 +45,7 @@ static string_and_token keyword_tokens[] = { .str = "enum", .tok = { .type = TOK_KEYWORD, .data.kw = KW_RESERVED } }, { .str = "export", .tok = { .type = TOK_KEYWORD, .data.kw = KW_RESERVED } }, { .str = "extends", .tok = { .type = TOK_KEYWORD, .data.kw = KW_RESERVED } }, - { .str = "false", .tok = { .type = TOK_BOOL, .data.is_true = false } }, + { .str = "false", .tok = { .type = TOK_BOOL, .data.uid = false } }, { .str = "finally", .tok = { .type = TOK_KEYWORD, .data.kw = KW_FINALLY } }, { .str = "for", .tok = { .type = TOK_KEYWORD, .data.kw = KW_FOR } }, { .str = "function", .tok = { .type = TOK_KEYWORD, .data.kw = KW_FUNCTION } }, @@ -57,7 +57,7 @@ static string_and_token keyword_tokens[] = { .str = "implements", .tok = { .type = TOK_KEYWORD, .data.kw = KW_RESERVED } }, { .str = "let", .tok = { .type = TOK_KEYWORD, .data.kw = KW_RESERVED } }, { .str = "new", .tok = { .type = TOK_KEYWORD, .data.kw = KW_NEW } }, - { .str = "null", .tok = { .type = TOK_NULL, .data.none = NULL } }, + { .str = "null", .tok = { .type = TOK_NULL, .data.uid = 0 } }, { .str = "package", .tok = { .type = TOK_KEYWORD, .data.kw = KW_RESERVED } }, { .str = "private", .tok = { .type = TOK_KEYWORD, .data.kw = KW_RESERVED } }, { .str = "protected", .tok = { .type = TOK_KEYWORD, .data.kw = KW_RESERVED } }, @@ -68,7 +68,7 @@ static string_and_token keyword_tokens[] = { .str = "switch", .tok = { .type = TOK_KEYWORD, .data.kw = KW_SWITCH } }, { .str = "this", .tok = { .type = TOK_KEYWORD, .data.kw = KW_THIS } }, { .str = "throw", .tok = { .type = TOK_KEYWORD, .data.kw = KW_THROW } }, - { .str = "true", .tok = { .type = TOK_BOOL, .data.is_true = true } }, + { .str = "true", .tok = { .type = TOK_BOOL, .data.uid = true } }, { .str = "try", .tok = { .type = TOK_KEYWORD, .data.kw = KW_TRY } }, { .str = "typeof", .tok = { .type = TOK_KEYWORD, .data.kw = KW_TYPEOF } }, { .str = "var", .tok = { .type = TOK_KEYWORD, .data.kw = KW_VAR } }, @@ -78,10 +78,25 @@ static string_and_token keyword_tokens[] = { .str = "yield", .tok = { .type = TOK_KEYWORD, .data.kw = KW_RESERVED } } }; +typedef struct +{ + int num; + token tok; +} +num_and_token; + #define MAX_NAMES 100 +#define MAX_NUMS 25 static string_and_token seen_names[MAX_NAMES]; -static uint8_t seen_names_num; +static uint8_t seen_names_count = 0; + +static num_and_token seen_nums[MAX_NAMES] = +{ + [0] = { .num = 0, .tok = { .type = TOK_INT, .data.uid = 0 } }, + [1] = { .num = 1, .tok = { .type = TOK_INT, .data.uid = 1 } } +}; +static uint8_t seen_nums_count = 2; static bool is_empty (token tok) @@ -114,7 +129,7 @@ get_char (size_t i) if (buffer == NULL) { - buffer = (char *) malloc (BUFFER_SIZE); + buffer = (char *) mem_HeapAllocBlock (BUFFER_SIZE, MEM_HEAP_ALLOC_SHORT_TERM); error = __fread (buffer, 1, BUFFER_SIZE, file); if (error == 0) return '\0'; @@ -184,7 +199,7 @@ decode_keyword (void) for (i = 0; i < size; i++) { - if (!__strncmp (keyword_tokens[i].str, token_start, __strlen (keyword_tokens[i].str))) + if (!__strncmp (keyword_tokens[i].str, token_start, (size_t) (buffer - token_start))) return keyword_tokens[i].tok; } @@ -196,9 +211,9 @@ convert_seen_name_to_token (void) { size_t i; - for (i = 0; i < seen_names_num; i++) + for (i = 0; i < seen_names_count; i++) { - if (!__strncmp (seen_names[i].str, token_start, __strlen (seen_names[i].str))) + if (!__strncmp (seen_names[i].str, token_start, (size_t) (buffer - token_start))) return seen_names[i].tok; } @@ -206,12 +221,33 @@ convert_seen_name_to_token (void) } static void -add_to_seen_tokens (string_and_token snt) +add_name_to_seen_tokens (string_and_token snt) { - JERRY_ASSERT (seen_names_num < MAX_NAMES); + JERRY_ASSERT (seen_names_count < MAX_NAMES); - snt.tok.data.name = (string_id) seen_names_num; - seen_names[seen_names_num++] = snt; + seen_names[seen_names_count++] = snt; +} + +static token +convert_seen_num_to_token (int num) +{ + size_t i; + + for (i = 0; i < seen_nums_count; i++) + { + if (seen_nums[i].num == num) + return seen_nums[i].tok; + } + + return empty_token; +} + +static void +add_num_to_seen_tokens (num_and_token nat) +{ + JERRY_ASSERT (seen_nums_count < MAX_NUMS); + + seen_nums[seen_nums_count++] = nat; } uint8_t @@ -219,20 +255,32 @@ lexer_get_strings (const char **strings) { int i; - for (i = 0; i < seen_names_num; i++) - strings[i] = seen_names[i].str; + if (strings) + for (i = 0; i < seen_names_count; i++) + strings[i] = seen_names[i].str; - return seen_names_num; + return seen_names_count; } const char * -lexer_get_string_by_id (string_id id) +lexer_get_string_by_id (uint8_t id) { - JERRY_ASSERT (id < seen_names_num); + JERRY_ASSERT (id < seen_names_count); return seen_names[id].str; } +uint8_t +lexer_get_nums (int *nums) +{ + int i; + + for (i = 0; i < seen_nums_count; i++) + nums[i] = seen_nums[i].num; + + return seen_nums_count; +} + static void new_token (void) { @@ -254,7 +302,7 @@ current_token (void) JERRY_ASSERT (token_start); JERRY_ASSERT (token_start <= buffer); size_t length = (size_t) (buffer - token_start); - char *res = (char *) malloc (length + 1); + char *res = (char *) mem_HeapAllocBlock (length + 1, MEM_HEAP_ALLOC_SHORT_TERM); __strncpy (res, token_start, length); res[length] = '\0'; token_start = NULL; @@ -265,7 +313,7 @@ current_token (void) do \ { \ buffer += NUM; \ - return (token) { .type = TOK, .data.none = NULL }; \ + return (token) { .type = TOK, .data.uid = 0 }; \ } \ while (0) @@ -338,9 +386,9 @@ parse_name (void) } string = current_token (); - known_token = (token) { .type = TOK_NAME, .data.name = seen_names_num }; + known_token = (token) { .type = TOK_NAME, .data.uid = seen_names_count }; - add_to_seen_tokens ((string_and_token) { .str = string, .tok = known_token }); + add_name_to_seen_tokens ((string_and_token) { .str = string, .tok = known_token }); return known_token; } @@ -387,6 +435,7 @@ parse_number (void) bool is_exp = false; size_t tok_length = 0, i; int res = 0; + token known_token; JERRY_ASSERT (__isdigit (c) || c == '.'); @@ -423,7 +472,14 @@ parse_number (void) res = (res << 4) + hex_to_int (token_start[i]); token_start = NULL; - return (token) { .type = TOK_INT, .data.num = res }; + + known_token = convert_seen_num_to_token (res); + if (!is_empty (known_token)) + return known_token; + + known_token = (token) { .type = TOK_INT, .data.uid = seen_nums_count }; + add_num_to_seen_tokens ((num_and_token) { .num = res, .tok = known_token }); + return known_token; } JERRY_ASSERT (!is_hex && !is_exp); @@ -475,7 +531,8 @@ parse_number (void) { float res = __strtof (token_start, NULL); token_start = NULL; - return (token) { .type = TOK_FLOAT, .data.fp_num = res }; + JERRY_UNIMPLEMENTED_REF_UNUSED_VARS (res); + return empty_token; } tok_length = (size_t) (buffer - token_start);; @@ -484,7 +541,13 @@ parse_number (void) token_start = NULL; - return (token) { .type = TOK_INT, .data.num = res }; + known_token = convert_seen_num_to_token (res); + if (!is_empty (known_token)) + return known_token; + + known_token = (token) { .type = TOK_INT, .data.uid = seen_nums_count }; + add_num_to_seen_tokens ((num_and_token) { .num = res, .tok = known_token }); + return known_token; } static char @@ -513,7 +576,7 @@ parse_string (void) char *tok = NULL; char *index = NULL; const char *i; - size_t length; + size_t length, num; token res = empty_token; JERRY_ASSERT (c == '\'' || c == '"'); @@ -553,7 +616,7 @@ parse_string (void) } length = (size_t) (buffer - token_start); - tok = (char *) malloc (length); + tok = (char *) mem_HeapAllocBlock (length, MEM_HEAP_ALLOC_SHORT_TERM); index = tok; for (i = token_start; i < buffer; i++) @@ -581,9 +644,18 @@ parse_string (void) // Eat up '"' consume_char (); - res = (token) { .type = TOK_STRING, .data.str = seen_names_num }; + for (num = 0; num < seen_names_count; num++) + { + if (!__strncmp (seen_names[num].str, tok, __strlen (tok))) + { + mem_HeapFreeBlock ((uint8_t*) tok); + return seen_names[num].tok; + } + } - add_to_seen_tokens ((string_and_token) { .str = tok, .tok = res }); + res = (token) { .type = TOK_STRING, .data.uid = seen_names_count }; + + add_name_to_seen_tokens ((string_and_token) { .str = tok, .tok = res }); return res; } @@ -593,7 +665,7 @@ grobble_whitespaces (void) { char c = LA (0); - while ((__isspace (c) && c != '\n') || c == '\0') + while ((__isspace (c) && c != '\n')) { consume_char (); c = LA (0); @@ -685,11 +757,11 @@ lexer_next_token (void) if (c == '\n') { consume_char (); - return (token) { .type = TOK_NEWLINE, .data.none = NULL }; + return (token) { .type = TOK_NEWLINE, .data.uid = 0 }; } if (c == '\0') - return (token) { .type = TOK_EOF, .data.none = NULL };; + return (token) { .type = TOK_EOF, .data.uid = 0 };; if (c == '\'' || c == '"') return parse_string (); @@ -708,7 +780,7 @@ lexer_next_token (void) if (c == '/' && LA (1) == '*') { if (replace_comment_by_newline ()) - return (token) { .type = TOK_NEWLINE, .data.none = NULL }; + return (token) { .type = TOK_NEWLINE, .data.uid = 0 }; else return #ifdef __HOST @@ -803,11 +875,11 @@ lexer_next_token (void) token tok = lexer_next_token_private (); if (tok.type == TOK_NEWLINE) return tok; - // if (tok.type == TOK_CLOSE_BRACE) + if (tok.type == TOK_CLOSE_PAREN) { // if (i == 300) - __fprintf (lexer_debug_log, "lexer_next_token(%d): type=0x%x, data=%p\n", i, tok.type, tok.data.none); - i++; + __fprintf (lexer_debug_log, "lexer_next_token(%d): type=%d, data=%d\n", i, tok.type, tok.data.uid); + i++; } return tok; } @@ -816,10 +888,10 @@ lexer_next_token (void) void lexer_save_token (token tok) { - #ifdef __HOST - // if (tok.type == TOK_CLOSE_BRACE) - __fprintf (lexer_debug_log, "lexer_save_token(%d): type=0x%x, data=%p\n", i, tok.type, tok.data.none); - #endif +#ifdef __HOST + if (tok.type == TOK_CLOSE_PAREN) + __fprintf (lexer_debug_log, "lexer_save_token(%d): type=%d, data=%d\n", i, tok.type, tok.data.uid); +#endif saved_token = tok; } diff --git a/src/libjsparser/lexer.h b/src/libjsparser/lexer.h index 9203d3ab5..8868c2a4a 100644 --- a/src/libjsparser/lexer.h +++ b/src/libjsparser/lexer.h @@ -18,121 +18,120 @@ #include "globals.h" -typedef uint8_t string_id; /* Keywords. */ -typedef enum -{ - /* Not a keyword. */ - KW_NONE = 0, - /* Future reserved keyword. */ - KW_RESERVED, +typedef uint8_t keyword; - KW_BREAK, - KW_CASE, - KW_CATCH, - KW_CONTINUE, - KW_DEBUGGER, - KW_DEFAULT, - KW_DELETE, +/* Not a keyword. */ +#define KW_NONE 0 +/* Future reserved keyword. */ +#define KW_RESERVED 1 +#define KW_BREAK 2 +#define KW_CASE 3 +#define KW_CATCH 4 - KW_DO, - KW_ELSE, - KW_FINALLY, - KW_FOR, - KW_FUNCTION, - KW_IF, - KW_IN, +#define KW_CONTINUE 5 +#define KW_DEBUGGER 6 +#define KW_DEFAULT 7 +#define KW_DELETE 8 +#define KW_DO 9 - KW_INSTANCEOF, - KW_NEW, - KW_RETURN, - KW_SWITCH, - KW_THIS, - KW_THROW, - KW_TRY, +#define KW_ELSE 10 +#define KW_FINALLY 11 +#define KW_FOR 12 +#define KW_FUNCTION 13 +#define KW_IF 14 + +#define KW_IN 15 +#define KW_INSTANCEOF 16 +#define KW_NEW 17 +#define KW_RETURN 18 +#define KW_SWITCH 19 + +#define KW_THIS 20 +#define KW_THROW 21 +#define KW_TRY 22 +#define KW_TYPEOF 23 +#define KW_VAR 24 + +#define KW_VOID 25 +#define KW_WHILE 26 +#define KW_WITH 27 - KW_TYPEOF, - KW_VAR, - KW_VOID, - KW_WHILE, - KW_WITH -} -keyword; /* Type of tokens. */ -typedef enum -{ - TOK_EOF = 0x0, // End of file - TOK_NAME = 0x1, // Identifier - TOK_KEYWORD = 0x2, // Keyword - TOK_INT = 0x3, - TOK_FLOAT = 0x4, - TOK_NULL = 0x5, - TOK_BOOL = 0x6, - TOK_NEWLINE = 0x7, - TOK_STRING = 0x8, +typedef uint8_t token_type; - /* Punctuators. */ - TOK_OPEN_BRACE = 0x9, // { - TOK_CLOSE_BRACE = 0xa, // } - TOK_OPEN_PAREN = 0xb, // ( - TOK_CLOSE_PAREN = 0xc, // ) - TOK_OPEN_SQUARE, // [ - TOK_CLOSE_SQUARE, // [ +#define TOK_EOF 0 // End of file +#define TOK_NAME 1 // Identifier +#define TOK_KEYWORD 2 // Keyword +#define TOK_INT 3 +#define TOK_FLOAT 4 - TOK_DOT, // . - TOK_SEMICOLON, // ; - TOK_COMMA, // , - TOK_LESS, // < - TOK_GREATER, // > - TOK_LESS_EQ, // <= +#define TOK_NULL 5 +#define TOK_BOOL 6 +#define TOK_NEWLINE 7 +#define TOK_STRING 8 +#define TOK_OPEN_BRACE 9 // { - TOK_GREATER_EQ, // <= - TOK_DOUBLE_EQ, // == - TOK_NOT_EQ, // != - TOK_TRIPLE_EQ, // === - TOK_NOT_DOUBLE_EQ, // !== +#define TOK_CLOSE_BRACE 10 // } +#define TOK_OPEN_PAREN 11 // ( +#define TOK_CLOSE_PAREN 12 // ) +#define TOK_OPEN_SQUARE 13 // [ +#define TOK_CLOSE_SQUARE 14 // [ - TOK_PLUS, // + - TOK_MINUS, // - - TOK_MULT, // * - TOK_MOD, // % - TOK_DOUBLE_PLUS, // ++ - TOK_DOUBLE_MINUS, // -- +#define TOK_DOT 15 // . +#define TOK_SEMICOLON 16 // ; +#define TOK_COMMA 17 // , +#define TOK_LESS 18 // < +#define TOK_GREATER 19 // > - TOK_LSHIFT, // << - TOK_RSHIFT, // >> - TOK_RSHIFT_EX, // >>> - TOK_AND, // & - TOK_OR, // | - TOK_XOR, // ^ +#define TOK_LESS_EQ 20 // <= +#define TOK_GREATER_EQ 21 // <= +#define TOK_DOUBLE_EQ 22 // == +#define TOK_NOT_EQ 23 // != +#define TOK_TRIPLE_EQ 24 // === - TOK_NOT, // ! - TOK_COMPL, // ~ - TOK_DOUBLE_AND, // && - TOK_DOUBLE_OR, // || - TOK_QUERY, // ? - TOK_COLON, // : +#define TOK_NOT_DOUBLE_EQ 25 // !== +#define TOK_PLUS 26 // + +#define TOK_MINUS 27 // - +#define TOK_MULT 28 // * +#define TOK_MOD 29 // % - TOK_EQ, // = - TOK_PLUS_EQ, // += - TOK_MINUS_EQ, // -= - TOK_MULT_EQ, // *= - TOK_MOD_EQ, // %= - TOK_LSHIFT_EQ, // <<= +#define TOK_DOUBLE_PLUS 30 // ++ +#define TOK_DOUBLE_MINUS 31 // -- +#define TOK_LSHIFT 32 // << +#define TOK_RSHIFT 33 // >> +#define TOK_RSHIFT_EX 34 // >>> - TOK_RSHIFT_EQ, // >>= - TOK_RSHIFT_EX_EQ, // >>>= - TOK_AND_EQ, // &= - TOK_OR_EQ, // |= - TOK_XOR_EQ, // ^= +#define TOK_AND 35 // & +#define TOK_OR 36 // | +#define TOK_XOR 37 // ^ +#define TOK_NOT 38 // ! +#define TOK_COMPL 39 // ~ + +#define TOK_DOUBLE_AND 40 // && +#define TOK_DOUBLE_OR 41 // || +#define TOK_QUERY 42 // ? +#define TOK_COLON 43 // : +#define TOK_EQ 44 // = + +#define TOK_PLUS_EQ 45 // += +#define TOK_MINUS_EQ 46 // -= +#define TOK_MULT_EQ 47 // *= +#define TOK_MOD_EQ 48 // %= +#define TOK_LSHIFT_EQ 49 // <<= + +#define TOK_RSHIFT_EQ 50 // >>= +#define TOK_RSHIFT_EX_EQ 51 // >>>= +#define TOK_AND_EQ 52 // &= +#define TOK_OR_EQ 53 // |= +#define TOK_XOR_EQ 54 // ^= + +#define TOK_DIV 55 // / +#define TOK_DIV_EQ 56 // /= +#define TOK_EMPTY 57 - TOK_DIV, // / - TOK_DIV_EQ, // /= - TOK_EMPTY -} -token_type; /* Represents the contents of a token. */ typedef struct @@ -140,17 +139,12 @@ typedef struct token_type type; union - { - void *none; - keyword kw; - string_id name; - bool is_true; - int num; - float fp_num; - string_id str; - } + { + keyword kw; + uint8_t uid; + } data; -} +} __packed token; #ifdef __HOST @@ -160,11 +154,9 @@ void lexer_set_source (const char *); #endif token lexer_next_token (void); void lexer_save_token (token); - void lexer_dump_buffer_state (void); - uint8_t lexer_get_strings (const char **); - -const char *lexer_get_string_by_id (string_id id); +const char *lexer_get_string_by_id (uint8_t); +uint8_t lexer_get_nums (int *); #endif diff --git a/src/libjsparser/parser.c b/src/libjsparser/parser.c index 8c0644d57..3a7f7565d 100644 --- a/src/libjsparser/parser.c +++ b/src/libjsparser/parser.c @@ -16,142 +16,37 @@ #include "jerry-libc.h" #include "lexer.h" #include "parser.h" +#include "opcodes.h" +#include "serializer.h" -bool -is_formal_parameter_list_empty (formal_parameter_list list) -{ - return list.names[0] == null_string; -} - -bool -is_operand_empty (operand op) -{ - return op.is_literal == false && op.data.none == NULL; -} - -bool -is_operand_list_empty (operand_list list) -{ - return is_operand_empty (list.ops[0]); -} - -bool -is_property_empty (property prop) -{ - return is_operand_empty (prop.name) && is_operand_empty (prop.value); -} - -bool -is_property_list_empty (property_list list) -{ - return is_property_empty (list.props[0]); -} - -bool -is_expression_empty (assignment_expression expr) -{ - return expr.oper == AO_NONE && expr.type == ET_NONE && expr.data.none == NULL; -} - -bool -is_variable_declaration_empty (variable_declaration var_decl) -{ - return var_decl.name == null_string && is_expression_empty (var_decl.assign_expr); -} - -bool -is_statement_null (statement stmt) -{ - return stmt.type == STMT_NULL && stmt.data.none == NULL; -} +#define MAX_OPCODES 10 static token tok; +static OPCODE opcode, opcodes_buffer[10]; +static uint8_t current_opcode_in_buffer = 0; +static uint8_t opcode_counter = 0; #ifdef __HOST FILE *debug_file; #endif -static expression parse_expression (void); -static assignment_expression parse_assigment_expression (void); +static T_IDX parse_expression (void); +static void parse_statement (void); +static T_IDX parse_assignment_expression (void); +static void parse_source_element_list (void); -typedef enum +static T_IDX temp_name, min_temp_name; + +static T_IDX +next_temp_name (void) { - SCOPE_GLOBAL = 0, - SCOPE_IF = 1u << 0, - SCOPE_BLOCK = 1u << 1, - SCOPE_DO = 1u << 2, - SCOPE_WHILE = 1u << 3, - SCOPE_FOR = 1u << 4, - SCOPE_LOOP = SCOPE_WHILE | SCOPE_FOR | SCOPE_DO, - SCOPE_WITH = 1u << 5, - SCOPE_SWITCH = 1u << 6, - SCOPE_CASE = 1u << 7, - SCOPE_ELSE = 1u << 8, - SCOPE_TRY = 1u << 9, - SCOPE_CATCH = 1u << 10, - SCOPE_FINALLY = 1u << 11, - SCOPE_FUNCTION = 1u << 12, - SCOPE_SUBEXPRESSION = 1u << 13 -} -scope_type; - -typedef struct scope -{ - scope_type type; - bool was_stmt; -} -scope; - -#define MAX_SCOPES 10 - -static scope current_scopes[MAX_SCOPES]; - -static unsigned int scope_index; - -static void -scope_must_be (unsigned int scopes) -{ - size_t i; - - for (i = 0; i < scope_index; i++) - { - if (scopes & current_scopes[i].type) - return; - } - parser_fatal (ERR_PARSER); + return temp_name++; } static void -current_scope_must_be (unsigned int scopes) +reset_temp_name (void) { - if (scopes & current_scopes[scope_index - 1].type) - return; - parser_fatal (ERR_PARSER); -} - -static inline void -current_scope_must_be_global (void) -{ - if (scope_index != 1) - parser_fatal (ERR_PARSER); -} - -static void -push_scope (int type) -{ -#ifdef __HOST - __fprintf (debug_file, "push_scope: 0x%x\n", type); -#endif - current_scopes[scope_index++] = (scope) { .type = type, .was_stmt = false }; -} - -static void -pop_scope (void) -{ -#ifdef __HOST - __fprintf (debug_file, "pop_scope: 0x%x\n", current_scopes[scope_index - 1].type); -#endif - scope_index--; + temp_name = min_temp_name; } static void @@ -221,6 +116,7 @@ token_after_newlines_must_be_keyword (keyword kw) parser_fatal (ERR_PARSER); } +#if 0 static void insert_semicolon (void) { @@ -228,238 +124,51 @@ insert_semicolon (void) if (tok.type != TOK_NEWLINE && tok.type != TOK_SEMICOLON) parser_fatal (ERR_PARSER); } +#endif -/* formal_parameter_list - : LT!* Identifier (LT!* ',' LT!* Identifier)* - ; */ -static formal_parameter_list -parse_formal_parameter_list (void) +#define NEXT(ID, TYPE) \ + do { skip_newlines (); ID = parse_##TYPE (); } while (0) + +#define DUMP_VOID_OPCODE(GETOP) \ + do { opcode=getop_##GETOP (); serializer_dump_data (&opcode, sizeof (OPCODE)); opcode_counter++; } while (0) + +#define DUMP_OPCODE(GETOP, ...) \ + do { opcode=getop_##GETOP (__VA_ARGS__); serializer_dump_data (&opcode, sizeof (OPCODE)); opcode_counter++; } while (0) + +#define REWRITE_OPCODE(OC, GETOP, ...) \ + do { opcode=getop_##GETOP (__VA_ARGS__); serializer_rewrite_data ((int8_t) (OC - opcode_counter), &opcode, sizeof (OPCODE)); } while (0) + +static T_IDX +integer_zero (void) { - int i; - formal_parameter_list res; - - current_token_must_be (TOK_NAME); - - for (i = 0; i < MAX_PARAMS; i++) - { - res.names[i] = tok.data.name; - - skip_newlines (); - if (tok.type != TOK_COMMA) - { - lexer_save_token (tok); - - if (i != MAX_PARAMS - 1) - res.names[i + 1] = null_string; - break; - } - } - return res; + T_IDX lhs = next_temp_name (); + DUMP_OPCODE (assignment, lhs, 0); + return lhs; } -/* function_declaration - : 'function' LT!* Identifier LT!* - '(' formal_parameter_list? LT!* ')' LT!* function_body - ; - - function_body - : '{' LT!* sourceElements LT!* '}' */ -static function_declaration -parse_function_declaration (void) +static T_IDX +integer_one (void) { - function_declaration res; - - assert_keyword (KW_FUNCTION); - - token_after_newlines_must_be (TOK_NAME); - res.name = tok.data.name; - - token_after_newlines_must_be (TOK_OPEN_PAREN); - - skip_newlines (); - if (tok.type != TOK_CLOSE_PAREN) - { - res.params = parse_formal_parameter_list (); - next_token_must_be (TOK_CLOSE_PAREN); - } - else - res.params = empty_formal_parameter_list; - - return res; + T_IDX lhs = next_temp_name (); + DUMP_OPCODE (assignment, lhs, 1); + return lhs; } -/* function_expression - : 'function' LT!* Identifier? LT!* '(' formal_parameter_list? LT!* ')' LT!* function_body - ; */ -static function_expression -parse_function_expression (void) +static void +save_opcode (void) { - function_expression res; + JERRY_ASSERT (current_opcode_in_buffer < MAX_OPCODES); - assert_keyword (KW_FUNCTION); - - skip_newlines (); - if (tok.type == TOK_NAME) - { - res.name = tok.data.name; - skip_newlines (); - } - else - res.name = null_string; - - current_token_must_be (TOK_OPEN_PAREN); - - skip_newlines (); - if (tok.type != TOK_CLOSE_PAREN) - { - res.params = parse_formal_parameter_list (); - next_token_must_be (TOK_CLOSE_PAREN); - } - else - res.params = empty_formal_parameter_list; - - push_scope (SCOPE_FUNCTION); - - return res; + opcodes_buffer[current_opcode_in_buffer++] = opcode; } -static literal -parse_literal (void) +static void +dump_saved_opcodes (void) { - literal res; - - switch (tok.type) - { - case TOK_NULL: - res.type = LIT_NULL; - res.data.none = NULL; - return res; - - case TOK_BOOL: - res.type = LIT_BOOL; - res.data.is_true = tok.data.is_true; - return res; - - case TOK_INT: - res.type = LIT_INT; - res.data.num = tok.data.num; - return res; - - case TOK_STRING: - res.type = LIT_STR; - res.data.str = tok.data.str; - return res; - - default: - JERRY_UNREACHABLE (); - } -} - -static operand -parse_operand (void) -{ - operand res; - - switch (tok.type) - { - case TOK_NULL: - case TOK_BOOL: - case TOK_INT: - case TOK_STRING: - res.is_literal = true; - res.data.lit = parse_literal (); - return res; - - case TOK_NAME: - res.is_literal = false; - res.data.name = tok.data.name; - return res; - - default: - return empty_operand; - } -} - -/* arguments - : operand LT!* ( ',' LT!* operand * LT!* )* - ;*/ -static argument_list -parse_argument_list (void) -{ - argument_list res; - int i; - - for (i = 0; i < MAX_PARAMS; i++) - { - res.ops[i] = parse_operand (); - - skip_newlines (); - if (tok.type != TOK_COMMA) - { - lexer_save_token (tok); - - if (i != MAX_PARAMS - 1) - res.ops[i + 1] = empty_operand; - break; - } - - skip_newlines (); - } - return res; -} - -/* call_expression - : identifier LT!* '(' LT!* arguments * LT!* ')' LT!* - ;*/ -static call_expression -parse_call_expression (void) -{ - call_expression res; - - current_token_must_be (TOK_NAME); - res.name = tok.data.name; - - token_after_newlines_must_be (TOK_OPEN_PAREN); - - skip_newlines (); - if (tok.type != TOK_CLOSE_PAREN) - { - res.args = parse_argument_list (); - next_token_must_be (TOK_CLOSE_PAREN); - } - else - res.args = empty_operand_list; - - skip_newlines (); - if (tok.type == TOK_OPEN_PAREN || tok.type == TOK_OPEN_SQUARE - || tok.type == TOK_DOT) - JERRY_UNREACHABLE (); - else - lexer_save_token (tok); - - return res; -} - -/* array_literal - : [ arguments ] - ; */ -static array_literal -parse_array_literal (void) -{ - array_literal res; - - current_token_must_be (TOK_OPEN_SQUARE); - - skip_newlines (); - if (tok.type != TOK_CLOSE_SQUARE) - { - res = parse_argument_list (); - next_token_must_be (TOK_CLOSE_SQUARE); - } - else - res = empty_operand_list; - - return res; + uint8_t i; + for (i = 0; i < current_opcode_in_buffer; i++) + serializer_dump_data (&opcodes_buffer[i], sizeof (OPCODE)); + current_opcode_in_buffer = 0; } /* property_name @@ -467,447 +176,1143 @@ parse_array_literal (void) | StringLiteral | NumericLiteral ; */ -static inline property_name +static T_IDX parse_property_name (void) -{ +{ switch (tok.type) { case TOK_NAME: case TOK_STRING: case TOK_INT: - return parse_operand (); - + return tok.data.uid; + default: JERRY_UNREACHABLE (); } } /* property_name_and_value - : property_name LT!* ':' LT!* operand + : property_name LT!* ':' LT!* assignment_expression ; */ -static property -parse_property (void) +static T_IDX +parse_property_name_and_value (void) { - property res; + T_IDX lhs, name, value; - res.name = parse_property_name (); + lhs = next_temp_name (); + name = parse_property_name (); token_after_newlines_must_be (TOK_COLON); + NEXT (value, assignment_expression); - skip_newlines (); - res.value = parse_operand (); + DUMP_OPCODE (prop, lhs, name, value); - return res; + return lhs; } -/* object_literal - : LT!* property (LT!* ',' LT!* property)* LT!* +/* property_assignment + : property_name_and_value + | get LT!* property_name LT!* '(' LT!* ')' LT!* '{' LT!* function_body LT!* '}' + | set LT!* property_name LT!* '(' identifier ')' LT!* '{' LT!* function_body LT!* '}' ; */ -static object_literal -parse_object_literal (void) +static T_IDX +parse_property_assignment (void) { - object_literal res; - int i; - - for (i = 0; i < MAX_PROPERTIES; i++) - { - res.props[i] = parse_property (); - - skip_newlines (); - if (tok.type != TOK_COMMA) - { - lexer_save_token (tok); - - if (i != MAX_PROPERTIES - 1) - res.props[i + 1] = empty_property; - break; - } - } - - return res; -} - -static void -parse_unary_expression (assignment_expression *res, expression_type type) -{ - res->type = type; - token_after_newlines_must_be (TOK_NAME); - res->data.ops.op1 = parse_operand (); - res->data.ops.op2 = empty_operand; -} - -static assignment_expression -parse_assigment_expression (void) -{ - assignment_expression res; - - if (tok.type != TOK_NAME) - { - res.oper = AO_NONE; - goto parse_operands; - } + T_IDX lhs, name, arg; current_token_must_be (TOK_NAME); - token saved_token = tok; + lhs = next_temp_name (); - skip_newlines (); - if (tok.type == TOK_OPEN_PAREN) + if (!__strcmp ("get", lexer_get_string_by_id (tok.data.uid))) { - lexer_save_token (tok); - tok = saved_token; - return (assignment_expression) - { - .oper = AO_NONE, - .type = ET_CALL, - .var = null_string, - .data.call_expr = parse_call_expression () - }; + NEXT (name, property_name); + + token_after_newlines_must_be (TOK_OPEN_PAREN); + token_after_newlines_must_be (TOK_CLOSE_PAREN); + token_after_newlines_must_be (TOK_OPEN_BRACE); + + DUMP_OPCODE (prop_get_decl, lhs, name); + + skip_newlines (); + parse_source_element_list (); + + token_after_newlines_must_be (TOK_CLOSE_BRACE); + DUMP_VOID_OPCODE (ret); + + return lhs; } + else if (!__strcmp ("set", lexer_get_string_by_id (tok.data.uid))) + { + NEXT (name, property_name); - res.var = saved_token.data.name; + token_after_newlines_must_be (TOK_OPEN_PAREN); + token_after_newlines_must_be (TOK_NAME); + arg = tok.data.uid; + token_after_newlines_must_be (TOK_CLOSE_PAREN); + token_after_newlines_must_be (TOK_OPEN_BRACE); - // Assume that this is assignment - skip_newlines (); - switch (tok.type) - { - case TOK_EQ: - res.oper = AO_EQ; - break; - case TOK_MULT_EQ: - res.oper = AO_MULT_EQ; - break; - case TOK_DIV_EQ: - res.oper = AO_DIV_EQ; - break; - case TOK_MOD_EQ: - res.oper = AO_MOD_EQ; - break; - case TOK_PLUS_EQ: - res.oper = AO_PLUS_EQ; - break; - case TOK_MINUS_EQ: - res.oper = AO_MINUS_EQ; - break; - case TOK_LSHIFT_EQ: - res.oper = AO_LSHIFT_EQ; - break; - case TOK_RSHIFT_EQ: - res.oper = AO_RSHIFT_EQ; - break; - case TOK_RSHIFT_EX_EQ: - res.oper = AO_RSHIFT_EX_EQ; - break; - case TOK_AND_EQ: - res.oper = AO_AND_EQ; - break; - case TOK_XOR_EQ: - res.oper = AO_XOR_EQ; - break; - case TOK_OR_EQ: - res.oper = AO_OR_EQ; - break; + DUMP_OPCODE (prop_set_decl, lhs, name, arg); - default: - res.oper = AO_NONE; - res.data.ops.op1 = (operand) { .is_literal = false, .data.name = res.var }; - res.var = null_string; - goto parse_operator; - } + skip_newlines (); + parse_source_element_list (); - skip_newlines (); + token_after_newlines_must_be (TOK_CLOSE_BRACE); + DUMP_VOID_OPCODE (ret); -parse_operands: - saved_token = tok; - switch (tok.type) + return lhs; + } + else + return parse_property_name_and_value (); +} + +static void +dump_varg_3 (T_IDX current_param, T_IDX params[3]) +{ + if (current_param == 3) + { + DUMP_OPCODE (varg_3, params[0], params[1], params[2]); + current_param = 0; + } +} + +static void +dump_varg_end (T_IDX current_param, T_IDX params[3]) +{ + switch (current_param) { - case TOK_NAME: - case TOK_STRING: - case TOK_INT: - case TOK_NULL: - case TOK_BOOL: - res.data.ops.op1 = parse_operand (); + case 0: + DUMP_OPCODE (varg_1_end, params[0]); + break; + + case 1: + DUMP_OPCODE (varg_2_end, params[0], params[1]); + break; + + case 2: + DUMP_OPCODE (varg_3_end, params[0], params[1], params[2]); break; - case TOK_OPEN_PAREN: - res.type = ET_SUBEXPRESSION; - res.data.none = NULL; - return res; + default: + JERRY_UNREACHABLE (); + } +} - case TOK_OPEN_BRACE: - res.type = ET_OBJECT; - res.data.obj_lit = parse_object_literal (); - next_token_must_be (TOK_CLOSE_BRACE); - return res; +typedef enum +{ + AL_FUNC_DECL, + AL_FUNC_EXPR, + AL_ARRAY_LIT, + AL_OBJECT_LIT, + AL_CONSTRUCT_EXPR, + AL_CALL_EXPR +} +argument_list_type; - case TOK_OPEN_SQUARE: - res.type = ET_ARRAY; - res.data.arr_lit = parse_array_literal (); - next_token_must_be (TOK_CLOSE_SQUARE); - return res; +/** Parse list of identifiers, assigment expressions or properties, splitted by comma. + For each ALT dumps appropriate bytecode. Uses OBJ during dump if neccesary. + Returns temp var if expression has lhs, or 0 otherwise. */ +static T_IDX +parse_argument_list (argument_list_type alt, T_IDX obj) +{ + token_type open_tt, close_tt; + T_IDX first_opcode_args_count, + lhs = 0, + args[3+1/* +1 for stack protector */], + current_arg = 0; + bool is_first_opcode = true; - case TOK_DOUBLE_PLUS: - parse_unary_expression (&res, ET_UNARY_INCREMENT); - return res; + switch (alt) + { + case AL_FUNC_DECL: + open_tt = TOK_OPEN_PAREN; // Openning token + close_tt = TOK_CLOSE_PAREN; // Ending token + first_opcode_args_count = 2; // Maximum number of arguments in first opcode + break; - case TOK_DOUBLE_MINUS: - parse_unary_expression (&res, ET_UNARY_DECREMENT); - return res; + case AL_FUNC_EXPR: + case AL_CONSTRUCT_EXPR: + case AL_CALL_EXPR: + open_tt = TOK_OPEN_PAREN; + close_tt = TOK_CLOSE_PAREN; + first_opcode_args_count = 1; + lhs = next_temp_name (); + break; - case TOK_PLUS: - parse_unary_expression (&res, ET_UNARY_PLUS); - return res; + case AL_ARRAY_LIT: + open_tt = TOK_OPEN_SQUARE; + close_tt = TOK_CLOSE_SQUARE; + first_opcode_args_count = 2; + lhs = next_temp_name (); + break; - case TOK_MINUS: - parse_unary_expression (&res, ET_UNARY_MINUS); - return res; - - case TOK_COMPL: - parse_unary_expression (&res, ET_UNARY_COMPL); - return res; - - case TOK_NOT: - parse_unary_expression (&res, ET_UNARY_NOT); - return res; - - case TOK_KEYWORD: - switch (tok.data.kw) - { - case KW_DELETE: - parse_unary_expression (&res, ET_UNARY_DELETE); - return res; - case KW_VOID: - parse_unary_expression (&res, ET_UNARY_VOID); - return res; - case KW_TYPEOF: - parse_unary_expression (&res, ET_UNARY_TYPEOF); - return res; - - case KW_FUNCTION: - res.type = ET_FUNCTION; - res.data.func_expr = parse_function_expression (); - return res; - - case KW_NEW: - parse_unary_expression (&res, ET_NEW); - return res; - - default: - JERRY_UNREACHABLE (); - } + case AL_OBJECT_LIT: + open_tt = TOK_OPEN_BRACE; + close_tt = TOK_CLOSE_BRACE; + first_opcode_args_count = 2; + lhs = next_temp_name (); + break; default: JERRY_UNREACHABLE (); } -parse_operator: + current_token_must_be (open_tt); + skip_newlines (); - switch (tok.type) - { - case TOK_DOUBLE_OR: - res.type = ET_LOGICAL_OR; - break; - case TOK_DOUBLE_AND: - res.type = ET_LOGICAL_AND; - break; - case TOK_OR: - res.type = ET_BITWISE_OR; - break; - case TOK_XOR: - res.type = ET_BITWISE_XOR; - break; - case TOK_AND: - res.type = ET_BITWISE_AND; - break; - case TOK_DOUBLE_EQ: - res.type = ET_DOUBLE_EQ; - break; - case TOK_NOT_EQ: - res.type = ET_NOT_EQ; - break; - case TOK_TRIPLE_EQ: - res.type = ET_TRIPLE_EQ; - break; - case TOK_NOT_DOUBLE_EQ: - res.type = ET_NOT_DOUBLE_EQ; - break; - case TOK_LESS: - res.type = ET_LESS; - break; - case TOK_GREATER: - res.type = ET_GREATER; - break; - case TOK_LESS_EQ: - res.type = ET_LESS_EQ; - break; - case TOK_GREATER_EQ: - res.type = ET_GREATER_EQ; - break; - case TOK_LSHIFT: - res.type = ET_LSHIFT; - break; - case TOK_RSHIFT: - res.type = ET_RSHIFT; - break; - case TOK_RSHIFT_EX: - res.type = ET_RSHIFT_EX; - break; - case TOK_PLUS: - res.type = ET_PLUS; - break; - case TOK_MINUS: - res.type = ET_MINUS; - break; - case TOK_MULT: - res.type = ET_MULT; - break; - case TOK_DIV: - res.type = ET_DIV; - break; - case TOK_MOD: - res.type = ET_MOD; - break; + if (tok.type != close_tt) + { + while (true) + { + if (is_first_opcode) + { + if (current_arg == first_opcode_args_count) + { + switch (alt) + { + case AL_FUNC_DECL: + DUMP_OPCODE (func_decl_n, obj, args[0], args[1]); + break; - case TOK_DOUBLE_PLUS: - res.type = ET_POSTFIX_INCREMENT; - res.data.ops.op2 = empty_operand; - return res; + case AL_FUNC_EXPR: + DUMP_OPCODE (func_expr_n, lhs, obj, args[0]); + break; - case TOK_DOUBLE_MINUS: - res.type = ET_POSTFIX_DECREMENT; - res.data.ops.op2 = empty_operand; - return res; + case AL_ARRAY_LIT: + DUMP_OPCODE (array_n, lhs, args[0], args[1]); + break; - case TOK_OPEN_PAREN: - res.type = ET_CALL; - lexer_save_token (tok); - tok = saved_token; - res.data.call_expr = parse_call_expression (); - return res; + case AL_OBJECT_LIT: + DUMP_OPCODE (obj_n, lhs, args[0], args[1]); + break; - case TOK_DOT: - res.type = ET_PROP_REF; - skip_newlines (); - res.data.ops.op2 = parse_operand (); - JERRY_ASSERT (!res.data.ops.op2.is_literal); - return res; + case AL_CONSTRUCT_EXPR: + DUMP_OPCODE (construct_n, lhs, obj, args[0]); + break; - case TOK_OPEN_SQUARE: - res.type = ET_INDEX; - skip_newlines (); - res.data.ops.op2 = parse_operand (); - token_after_newlines_must_be (TOK_CLOSE_SQUARE); - return res; + case AL_CALL_EXPR: + DUMP_OPCODE (call_n, lhs, obj, args[0]); + break; + + default: + JERRY_UNREACHABLE (); + } + current_arg = 0; + is_first_opcode = false; + } + } + else + dump_varg_3 (current_arg, args); - case TOK_KEYWORD: - switch (tok.data.kw) + switch (alt) + { + case AL_FUNC_DECL: + current_token_must_be (TOK_NAME); + args[current_arg] = tok.data.uid; + break; + + case AL_FUNC_EXPR: + case AL_ARRAY_LIT: + case AL_CONSTRUCT_EXPR: + case AL_CALL_EXPR: + args[current_arg] = parse_assignment_expression (); + break; + + case AL_OBJECT_LIT: + args[current_arg] = parse_property_assignment (); + break; + + default: + JERRY_UNREACHABLE (); + } + + skip_newlines (); + if (tok.type != TOK_COMMA) + { + current_token_must_be (close_tt); + break; + } + + skip_newlines (); + current_arg++; + } + + if (is_first_opcode) + { + if (current_arg == 0) + { + switch (alt) + { + case AL_FUNC_DECL: + DUMP_OPCODE (func_decl_1, obj, args[0]); + break; + + case AL_FUNC_EXPR: + DUMP_OPCODE (func_expr_1, lhs, obj, args[0]); + break; + + case AL_ARRAY_LIT: + DUMP_OPCODE (array_1, lhs, args[0]); + break; + + case AL_OBJECT_LIT: + DUMP_OPCODE (obj_1, lhs, args[0]); + break; + + case AL_CONSTRUCT_EXPR: + DUMP_OPCODE (construct_1, lhs, obj, args[0]); + break; + + case AL_CALL_EXPR: + DUMP_OPCODE (call_1, lhs, obj, args[0]); + break; + + default: + JERRY_UNREACHABLE (); + } + } + else if (current_arg == 1) + { + switch (alt) + { + case AL_FUNC_DECL: + DUMP_OPCODE (func_decl_2, obj, args[0], args[1]); + break; + + case AL_ARRAY_LIT: + DUMP_OPCODE (array_2, lhs, args[0], args[1]); + break; + + case AL_OBJECT_LIT: + DUMP_OPCODE (obj_2, lhs, args[0], args[1]); + break; + + default: + JERRY_UNREACHABLE (); + } + } + else + JERRY_UNREACHABLE (); + } + else + dump_varg_end (current_arg, args); + } + else + { + switch (alt) { - case KW_INSTANCEOF: - res.type = ET_INSTANCEOF; + case AL_FUNC_DECL: + DUMP_OPCODE (func_decl_0, obj); break; - case KW_IN: - res.type = ET_IN; + + case AL_FUNC_EXPR: + DUMP_OPCODE (func_expr_0, lhs, obj); + break; + + case AL_ARRAY_LIT: + DUMP_OPCODE (array_0, lhs); + break; + + case AL_OBJECT_LIT: + DUMP_OPCODE (obj_0, lhs); + break; + + case AL_CONSTRUCT_EXPR: + DUMP_OPCODE (construct_0, lhs, obj); + break; + + case AL_CALL_EXPR: + DUMP_OPCODE (call_0, lhs, obj); break; default: JERRY_UNREACHABLE (); } - break; + } - default: - lexer_save_token (tok); - res.oper = AO_NONE; - if (res.data.ops.op1.is_literal) - res.type = ET_LITERAL; - else - res.type = ET_IDENTIFIER; - res.data.ops.op2 = empty_operand; - return res; - } + return lhs; +} + +/* function_declaration + : 'function' LT!* Identifier LT!* + '(' (LT!* Identifier (LT!* ',' LT!* Identifier)* ) ? LT!* ')' LT!* function_body + ; + + function_body + : '{' LT!* sourceElements LT!* '}' */ +static void +parse_function_declaration (void) +{ + T_IDX name; + + assert_keyword (KW_FUNCTION); + + token_after_newlines_must_be (TOK_NAME); + + name = tok.data.uid; skip_newlines (); - res.data.ops.op2 = parse_operand (); - return res; + parse_argument_list (AL_FUNC_DECL, name); + + token_after_newlines_must_be (TOK_OPEN_BRACE); + + skip_newlines (); + parse_source_element_list (); + + next_token_must_be (TOK_CLOSE_BRACE); + + DUMP_VOID_OPCODE (ret); +} + +/* function_expression + : 'function' LT!* Identifier? LT!* '(' formal_parameter_list? LT!* ')' LT!* function_body + ; */ +static T_IDX +parse_function_expression (void) +{ + T_IDX name, lhs; + + assert_keyword (KW_FUNCTION); + + skip_newlines (); + if (tok.type == TOK_NAME) + name = tok.data.uid; + else + { + lexer_save_token (tok); + name = next_temp_name (); + } + + skip_newlines (); + lhs = parse_argument_list (AL_FUNC_EXPR, name); + + token_after_newlines_must_be (TOK_OPEN_BRACE); + + skip_newlines (); + parse_source_element_list (); + + token_after_newlines_must_be (TOK_CLOSE_BRACE); + + DUMP_VOID_OPCODE (ret); + + return lhs; +} + +/* array_literal + : '[' LT!* assignment_expression? (LT!* ',' (LT!* assignment_expression)?)* LT!* ']' LT!* + ; */ +static T_IDX +parse_array_literal (void) +{ + return parse_argument_list (AL_ARRAY_LIT, 0); +} + +/* object_literal + : '{' LT!* property_assignment (LT!* ',' LT!* property_assignment)* LT!* '}' + ; */ +static T_IDX +parse_object_literal (void) +{ + return parse_argument_list (AL_OBJECT_LIT, 0); +} + +static T_IDX +parse_literal (void) +{ + switch (tok.type) + { + case TOK_NULL: + case TOK_BOOL: + case TOK_INT: + case TOK_STRING: + return tok.data.uid; + + default: + JERRY_UNREACHABLE (); + } +} + +/* primary_expression + : 'this' + | Identifier + | literal + | '[' LT!* array_literal LT!* ']' + | '{' LT!* object_literal LT!* '}' + | '(' LT!* expression LT!* ')' + ; */ +static T_IDX +parse_primary_expression (void) +{ + T_IDX lhs; + + if (is_keyword (KW_THIS)) + { + lhs = next_temp_name (); + DUMP_OPCODE (this, lhs); + return lhs; + } + else if (tok.type == TOK_NAME) + return tok.data.uid; + else if (tok.type == TOK_NULL || tok.type == TOK_BOOL + || tok.type == TOK_INT || tok.type == TOK_STRING) + return parse_literal (); + else if (tok.type == TOK_OPEN_SQUARE) + return parse_array_literal (); + else if (tok.type == TOK_OPEN_BRACE) + return parse_object_literal (); + else if (tok.type == TOK_OPEN_PAREN) + { + skip_newlines (); + if (tok.type != TOK_CLOSE_PAREN) + { + lhs = parse_expression (); + token_after_newlines_must_be (TOK_CLOSE_PAREN); + return lhs; + } + } + JERRY_UNREACHABLE (); +} + +/* member_expression + : (primary_expression | function_expression | 'new' LT!* member_expression (LT!* '(' LT!* arguments? LT!* ')') + (LT!* member_expression_suffix)* + ; + + arguments + : assignment_expression (LT!* ',' LT!* assignment_expression)*)? + ; + + member_expression_suffix + : index_suffix + | property_reference_suffix + ; + + index_suffix + : '[' LT!* expression LT!* ']' + ; + + property_reference_suffix + : '.' LT!* Identifier + ; */ +static T_IDX +parse_member_expression (void) +{ + T_IDX lhs, obj, prop; + if (is_keyword (KW_FUNCTION)) + obj = parse_function_expression (); + else if (is_keyword (KW_NEW)) + { + T_IDX member; + + NEXT (member, member_expression); + + obj = parse_argument_list (AL_CONSTRUCT_EXPR, member); + } + else + obj = parse_primary_expression (); + + skip_newlines (); + while (tok.type == TOK_OPEN_SQUARE || tok.type == TOK_DOT) + { + lhs = next_temp_name (); + + if (tok.type == TOK_OPEN_SQUARE) + { + NEXT (prop, expression); + next_token_must_be (TOK_CLOSE_SQUARE); + } + else if (tok.type == TOK_DOT) + { + skip_newlines (); + if (tok.type != TOK_NAME) + parser_fatal (ERR_PARSER); + prop = tok.data.uid; + } + else + JERRY_UNREACHABLE (); + + DUMP_OPCODE (prop_access, lhs, obj, prop); + obj = lhs; + skip_newlines (); + } + + lexer_save_token (tok); + + return obj; +} + +/* call_expression + : member_expression LT!* arguments (LT!* call_expression_suffix)* + ; + + call_expression_suffix + : arguments + | index_suffix + | property_reference_suffix + ; + + arguments + : '(' LT!* assignment_expression LT!* ( ',' LT!* assignment_expression * LT!* )* ')' + ; */ +static T_IDX +parse_call_expression (void) +{ + T_IDX lhs, obj, prop; + + obj = parse_member_expression (); + + skip_newlines (); + if (tok.type != TOK_OPEN_PAREN) + { + lexer_save_token (tok); + return obj; + } + + lhs = parse_argument_list (AL_CALL_EXPR, obj); + obj = lhs; + + skip_newlines (); + if (tok.type == TOK_OPEN_PAREN || tok.type == TOK_OPEN_SQUARE + || tok.type == TOK_DOT) + { + while (tok.type == TOK_OPEN_PAREN || tok.type == TOK_OPEN_SQUARE + || tok.type == TOK_DOT) + { + switch (tok.type) + { + case TOK_OPEN_PAREN: + lhs = parse_argument_list (AL_CALL_EXPR, obj); + break; + + case TOK_OPEN_SQUARE: + NEXT (prop, expression); + next_token_must_be (TOK_CLOSE_SQUARE); + + DUMP_OPCODE (prop_access, lhs, obj, prop); + obj = lhs; + skip_newlines (); + break; + + case TOK_DOT: + token_after_newlines_must_be (TOK_NAME); + prop = tok.data.uid; + + DUMP_OPCODE (prop_access, lhs, obj, prop); + obj = lhs; + skip_newlines (); + break; + + default: + JERRY_UNREACHABLE (); + } + } + } + else + lexer_save_token (tok); + + return obj; +} + +/* left_hand_side_expression + : call_expression + | new_expression + ; */ +static T_IDX +parse_left_hand_side_expression (void) +{ + return parse_call_expression (); +} + +/* postfix_expression + : left_hand_side_expression ('++' | '--')? + ; */ +static T_IDX +parse_postfix_expression (void) +{ + T_IDX expr = parse_left_hand_side_expression (); + + tok = lexer_next_token (); + if (tok.type == TOK_DOUBLE_PLUS) + { + opcode = getop_addition (expr, expr, integer_one ()); + save_opcode (); + } + else if (tok.type == TOK_DOUBLE_MINUS) + { + opcode = getop_substraction (expr, expr, integer_one ()); + save_opcode (); + } + else + lexer_save_token (tok); + + return expr; +} + +/* unary_expression + : postfix_expression + | ('delete' | 'void' | 'typeof' | '++' | '--' | '+' | '-' | '~' | '!') unary_expression + ; */ +static T_IDX +parse_unary_expression (void) +{ + T_IDX expr, lhs; + + switch (tok.type) + { + case TOK_DOUBLE_PLUS: + NEXT (expr, unary_expression); + DUMP_OPCODE (addition, expr, expr, integer_one ()); + return expr; + + case TOK_DOUBLE_MINUS: + NEXT (expr, unary_expression); + DUMP_OPCODE (substraction, expr, expr, integer_one ()); + return expr; + + case TOK_PLUS: + lhs = next_temp_name (); + NEXT (expr, unary_expression); + DUMP_OPCODE (addition, lhs, integer_zero (), expr); + return lhs; + + case TOK_MINUS: + lhs = next_temp_name (); + NEXT (expr, unary_expression); + DUMP_OPCODE (substraction, lhs, integer_zero (), expr); + return lhs; + + case TOK_COMPL: + lhs = next_temp_name (); + NEXT (expr, unary_expression); + DUMP_OPCODE (b_not, lhs, expr); + return lhs; + + case TOK_NOT: + lhs = next_temp_name (); + NEXT (expr, unary_expression); + DUMP_OPCODE (logical_not, lhs, expr); + return lhs; + + case TOK_KEYWORD: + if (is_keyword (KW_DELETE)) + { + lhs = next_temp_name (); + NEXT (expr, unary_expression); + DUMP_OPCODE (delete, lhs, expr); + return lhs; + } + if (is_keyword (KW_VOID)) + JERRY_UNIMPLEMENTED (); + if (is_keyword (KW_TYPEOF)) + { + lhs = next_temp_name (); + NEXT (expr, unary_expression); + DUMP_OPCODE (typeof, lhs, expr); + return lhs; + } + /* FALLTHRU. */ + + default: + return parse_postfix_expression (); + } +} + +#define DUMP_OF(GETOP, EXPR) \ + lhs = next_temp_name (); \ + NEXT (expr2, EXPR);\ + DUMP_OPCODE (GETOP, lhs, expr1, expr2); \ + expr1 = lhs; \ + break; + +/* multiplicative_expression + : unary_expression (LT!* ('*' | '/' | '%') LT!* unary_expression)* + ; */ +static T_IDX +parse_multiplicative_expression (void) +{ + T_IDX lhs, expr1, expr2; + + expr1 = parse_unary_expression (); + + skip_newlines (); + while (true) + { + switch (tok.type) + { + case TOK_MULT: DUMP_OF (multiplication, unary_expression) + case TOK_DIV: DUMP_OF (division, unary_expression) + case TOK_MOD: DUMP_OF (remainder, unary_expression) + + default: + lexer_save_token (tok); + return expr1; + } + + skip_newlines (); + } +} + +/* additive_expression + : multiplicative_expression (LT!* ('+' | '-') LT!* multiplicative_expression)* + ; */ +static T_IDX +parse_additive_expression (void) +{ + T_IDX lhs, expr1, expr2; + + expr1 = parse_multiplicative_expression (); + + skip_newlines (); + while (true) + { + switch (tok.type) + { + case TOK_PLUS: DUMP_OF (addition, multiplicative_expression); + case TOK_MINUS: DUMP_OF (substraction, multiplicative_expression); + + default: + lexer_save_token (tok); + return expr1; + } + + skip_newlines (); + } +} + +/* shift_expression + : additive_expression (LT!* ('<<' | '>>' | '>>>') LT!* additive_expression)* + ; */ +static T_IDX +parse_shift_expression (void) +{ + T_IDX lhs, expr1, expr2; + + expr1 = parse_additive_expression (); + + skip_newlines (); + while (true) + { + switch (tok.type) + { + case TOK_LSHIFT: DUMP_OF (b_shift_left, additive_expression) + case TOK_RSHIFT: DUMP_OF (b_shift_right, additive_expression) + case TOK_RSHIFT_EX: DUMP_OF (b_shift_uright, additive_expression) + + default: + lexer_save_token (tok); + return expr1; + } + + skip_newlines (); + } +} + +/* relational_expression + : shift_expression (LT!* ('<' | '>' | '<=' | '>=' | 'instanceof' | 'in') LT!* shift_expression)* + ; */ +static T_IDX +parse_relational_expression (void) +{ + T_IDX lhs, expr1, expr2; + + expr1 = parse_shift_expression (); + + skip_newlines (); + while (true) + { + switch (tok.type) + { + case TOK_LESS: DUMP_OF (less_than, shift_expression) + case TOK_GREATER: DUMP_OF (greater_than, shift_expression) + case TOK_LESS_EQ: DUMP_OF (less_or_equal_than, shift_expression) + case TOK_GREATER_EQ: DUMP_OF (greater_or_equal_than, shift_expression) + case TOK_KEYWORD: + if (is_keyword (KW_INSTANCEOF)) + { + DUMP_OF (instanceof, shift_expression) + } + else if (is_keyword (KW_IN)) + { + DUMP_OF (in, shift_expression) + } + // FALLTHRU + + default: + lexer_save_token (tok); + return expr1; + } + + skip_newlines (); + } +} + +/* equality_expression + : relational_expression (LT!* ('==' | '!=' | '===' | '!==') LT!* relational_expression)* + ; */ +static T_IDX +parse_equality_expression (void) +{ + T_IDX lhs, expr1, expr2; + + expr1 = parse_relational_expression (); + + skip_newlines (); + while (true) + { + switch (tok.type) + { + case TOK_DOUBLE_EQ: DUMP_OF (equal_value, relational_expression) + case TOK_NOT_EQ: DUMP_OF (not_equal_value, relational_expression) + case TOK_TRIPLE_EQ: DUMP_OF (equal_value_type, relational_expression) + case TOK_NOT_DOUBLE_EQ: DUMP_OF (not_equal_value_type, relational_expression) + + default: + lexer_save_token (tok); + return expr1; + } + + skip_newlines (); + } +} + +#define PARSE_OF(FUNC, EXPR, TOK_TYPE, GETOP) \ +static T_IDX parse_##FUNC (void) { \ + T_IDX lhs, expr1, expr2; \ + expr1 = parse_##EXPR (); \ + skip_newlines (); \ + while (true) \ + { \ + switch (tok.type) \ + { \ + case TOK_##TOK_TYPE: DUMP_OF (GETOP, EXPR) \ + default: lexer_save_token (tok); return expr1; \ + } \ + skip_newlines (); \ + } \ +} + +/* bitwise_and_expression + : equality_expression (LT!* '&' LT!* equality_expression)* + ; */ +PARSE_OF (bitwise_and_expression, equality_expression, AND, b_and) + +/* bitwise_xor_expression + : bitwise_and_expression (LT!* '^' LT!* bitwise_and_expression)* + ; */ +PARSE_OF (bitwise_xor_expression, bitwise_and_expression, XOR, b_xor) + +/* bitwise_or_expression + : bitwise_xor_expression (LT!* '|' LT!* bitwise_xor_expression)* + ; */ +PARSE_OF (bitwise_or_expression, bitwise_xor_expression, OR, b_or) + +/* logical_and_expression + : bitwise_or_expression (LT!* '&&' LT!* bitwise_or_expression)* + ; */ +PARSE_OF (logical_and_expression, bitwise_or_expression, DOUBLE_AND, logical_and) + +/* logical_or_expression + : logical_and_expression (LT!* '||' LT!* logical_and_expression)* + ; */ +PARSE_OF (logical_or_expression, logical_and_expression, DOUBLE_OR, logical_or) + +/* conditional_expression + : logical_or_expression (LT!* '?' LT!* assignment_expression LT!* ':' LT!* assignment_expression)? + ; */ +static T_IDX +parse_conditional_expression (bool *was_conditional) +{ + T_IDX expr = parse_logical_or_expression (); + + skip_newlines (); + if (tok.type == TOK_QUERY) + { + T_IDX lhs, jmp_oc, res = next_temp_name (); + + DUMP_OPCODE (is_true_jmp, expr, (uint8_t) (opcode_counter + 2)); + jmp_oc = opcode_counter; + DUMP_OPCODE (jmp_down, 1); + + NEXT (lhs, assignment_expression); + DUMP_OPCODE (assignment, res, lhs); + token_after_newlines_must_be (TOK_COLON); + + REWRITE_OPCODE (jmp_oc, jmp_down, (uint8_t) (opcode_counter - jmp_oc)); + jmp_oc = opcode_counter; + DUMP_OPCODE (jmp_down, 1); + + NEXT (lhs, assignment_expression); + DUMP_OPCODE (assignment, res, lhs); + REWRITE_OPCODE (jmp_oc, jmp_down, (uint8_t) (opcode_counter - jmp_oc)); + + *was_conditional = true; + return res; + } + else + { + lexer_save_token (tok); + return expr; + } +} + +/* assignment_expression + : conditional_expression + | left_hand_side_expression LT!* assignment_operator LT!* assignment_expression + ; */ +static T_IDX +parse_assignment_expression (void) +{ + T_IDX lhs, rhs; + bool was_conditional = false; + + reset_temp_name (); + + lhs = parse_conditional_expression (&was_conditional); + if (was_conditional) + { + dump_saved_opcodes (); + return lhs; + } + + skip_newlines (); + switch (tok.type) + { + case TOK_EQ: + NEXT (rhs, assignment_expression); + DUMP_OPCODE (assignment, lhs, rhs); + break; + + case TOK_MULT_EQ: + NEXT (rhs, assignment_expression); + DUMP_OPCODE (multiplication, lhs, lhs, rhs); + break; + + case TOK_DIV_EQ: + NEXT (rhs, assignment_expression); + DUMP_OPCODE (division, lhs, lhs, rhs); + break; + + case TOK_MOD_EQ: + NEXT (rhs, assignment_expression); + DUMP_OPCODE (remainder, lhs, lhs, rhs); + break; + + case TOK_PLUS_EQ: + NEXT (rhs, assignment_expression); + DUMP_OPCODE (addition, lhs, lhs, rhs); + break; + + case TOK_MINUS_EQ: + NEXT (rhs, assignment_expression); + DUMP_OPCODE (substraction, lhs, lhs, rhs); + break; + + case TOK_LSHIFT_EQ: + NEXT (rhs, assignment_expression); + DUMP_OPCODE (b_shift_left, lhs, lhs, rhs); + break; + + case TOK_RSHIFT_EQ: + NEXT (rhs, assignment_expression); + DUMP_OPCODE (b_shift_right, lhs, lhs, rhs); + break; + + case TOK_RSHIFT_EX_EQ: + NEXT (rhs, assignment_expression); + DUMP_OPCODE (b_shift_uright, lhs, lhs, rhs); + break; + + case TOK_AND_EQ: + NEXT (rhs, assignment_expression); + DUMP_OPCODE (b_and, lhs, lhs, rhs); + break; + + case TOK_XOR_EQ: + NEXT (rhs, assignment_expression); + DUMP_OPCODE (b_xor, lhs, lhs, rhs); + break; + + case TOK_OR_EQ: + NEXT (rhs, assignment_expression); + DUMP_OPCODE (b_or, lhs, lhs, rhs); + break; + + default: + lexer_save_token (tok); + } + + dump_saved_opcodes (); + return lhs; } /* expression : assignment_expression (LT!* ',' LT!* assignment_expression)* ; */ -static expression +static T_IDX parse_expression (void) { - expression res; - int i; + T_IDX expr = parse_assignment_expression (); - for (i = 0; i < MAX_EXPRS; i++) + while (true) { - res.exprs[i] = parse_assigment_expression (); skip_newlines (); - if (tok.type != TOK_COMMA) + if (tok.type == TOK_COMMA) + NEXT (expr, assignment_expression); + else { lexer_save_token (tok); - if (i != MAX_EXPRS - 1) - res.exprs[i + 1] = empty_expression; - break; + return expr; } } - - return res; } -/* variable_declaration(_no_in) - : Identifier LT!* initialiser(_no_in)? +/* variable_declaration + : Identifier LT!* initialiser? ; - initialiser(_no_in) + initialiser : '=' LT!* assignment_expression ; */ -static variable_declaration +static void parse_variable_declaration (void) { - variable_declaration res; + T_IDX name, expr; current_token_must_be (TOK_NAME); - res.name = tok.data.name; + name = tok.data.uid; + DUMP_OPCODE (decl_var, name); skip_newlines (); if (tok.type == TOK_EQ) { - skip_newlines (); - res.assign_expr = parse_assigment_expression (); + NEXT (expr, assignment_expression); + DUMP_OPCODE (assignment, name, expr); } else - { - lexer_save_token (tok); - res.assign_expr = empty_expression; - } - - return res; + lexer_save_token (tok); } -/* variable_declaration_list(_no_in) - : variable_declaration(_no_in) - (LT!* ',' LT!* variable_declaration(_no_in))* +/* variable_declaration_list + : variable_declaration + (LT!* ',' LT!* variable_declaration)* ; */ -static variable_declaration_list -parse_variable_declaration_list (void) +static void +parse_variable_declaration_list (bool *several_decls) { - variable_declaration_list res; - int i; - - for (i = 0; i < MAX_DECLS; i++) + while (true) { - res.decls[i] = parse_variable_declaration (); + parse_variable_declaration (); + skip_newlines (); if (tok.type != TOK_COMMA) { lexer_save_token (tok); - if (i != MAX_DECLS - 1) - res.decls[i + 1] = empty_variable_declaration; - break; + return; } - } - return res; + skip_newlines (); + if (several_decls) + *several_decls = true; + } } /* for_statement @@ -916,8 +1321,8 @@ parse_variable_declaration_list (void) ; for_statement_initialiser_part - : expression_no_in - | 'var' LT!* variable_declaration_list_no_in + : expression + | 'var' LT!* variable_declaration_list ; for_in_statement @@ -927,17 +1332,13 @@ parse_variable_declaration_list (void) for_in_statement_initialiser_part : left_hand_side_expression - | 'var' LT!* variable_declaration_no_in + | 'var' LT!* variable_declaration ;*/ -static for_or_for_in_statement +static void parse_for_or_for_in_statement (void) { - for_or_for_in_statement res; - variable_declaration_list list; - expression expr; - expr.exprs[0] = empty_expression; - list.decls[0] = empty_variable_declaration; + T_IDX stop, cond_oc, body_oc, step_oc, end_oc; assert_keyword (KW_FOR); token_after_newlines_must_be (TOK_OPEN_PAREN); @@ -949,9 +1350,10 @@ parse_for_or_for_in_statement (void) contains 'var'. Check it first. */ if (is_keyword (KW_VAR)) { + bool several_decls = false; skip_newlines (); - list = parse_variable_declaration_list (); - if (!is_variable_declaration_empty (list.decls[1])) + parse_variable_declaration_list (&several_decls); + if (several_decls) { token_after_newlines_must_be (TOK_SEMICOLON); goto plain_for; @@ -967,10 +1369,9 @@ parse_for_or_for_in_statement (void) parser_fatal (ERR_PARSER); } } - JERRY_ASSERT (is_variable_declaration_empty(list.decls[0])); /* expression contains left_hand_side_expression. */ - expr = parse_expression (); + parse_expression (); skip_newlines (); if (tok.type == TOK_SEMICOLON) @@ -983,69 +1384,216 @@ parse_for_or_for_in_statement (void) JERRY_UNREACHABLE (); plain_for: - res.is_for_in = false; - if (!is_variable_declaration_empty(list.decls[0])) - { - JERRY_ASSERT (is_expression_empty(expr.exprs[0])); - res.data.for_stmt.init.is_decl = true; - res.data.for_stmt.init.data.decl_list = list; - } - if (!is_expression_empty(expr.exprs[0])) - { - JERRY_ASSERT (is_variable_declaration_empty(list.decls[0])); - res.data.for_stmt.init.is_decl = false; - res.data.for_stmt.init.data.expr = expr; - } + /* Represent loop like + for (i = 0; i < 10; i++) { + body; + } + + as + + 11 i = #0; + cond_oc: + 12 tmp1 = #10; + 13 tmp2 = i < tmp1; + end_oc: + 14 is_false_jmp tmp2, 8 // end of loop + body_oc: + 15 jmp_down 5 // body + step_oc: + 16 tmp3 = #1; + 17 tmp4 = i + 1; + 18 i = tmp4; + 19 jmp_up 7; // cond_oc + + 20 body + + 21 jmp_up 5; // step_oc; + 22 ... + */ + cond_oc = opcode_counter; skip_newlines (); - if (tok.type == TOK_SEMICOLON) - res.data.for_stmt.limit = empty_expression; - else + if (tok.type != TOK_SEMICOLON) { - res.data.for_stmt.limit = parse_assigment_expression (); + stop = parse_assignment_expression (); next_token_must_be (TOK_SEMICOLON); } - - skip_newlines (); - if (tok.type == TOK_CLOSE_PAREN) - res.data.for_stmt.incr = empty_expression; else + stop = integer_one (); + + end_oc = opcode_counter; + DUMP_OPCODE (is_false_jmp, stop, 1); + + body_oc = opcode_counter; + DUMP_OPCODE (jmp_down, 1); + + step_oc = opcode_counter; + skip_newlines (); + if (tok.type != TOK_CLOSE_PAREN) { - res.data.for_stmt.incr = parse_assigment_expression (); + parse_assignment_expression (); next_token_must_be (TOK_CLOSE_PAREN); } - return res; + DUMP_OPCODE (jmp_up, (uint8_t) (opcode_counter - cond_oc)); + REWRITE_OPCODE (body_oc, jmp_down, (uint8_t) (opcode_counter - body_oc)); + + token_after_newlines_must_be (TOK_OPEN_BRACE); + skip_newlines (); + parse_source_element_list (); + next_token_must_be (TOK_CLOSE_BRACE); + + DUMP_OPCODE (jmp_up, (uint8_t) (opcode_counter - step_oc)); + REWRITE_OPCODE (end_oc, is_false_jmp, stop, opcode_counter); + return; for_in: - res.is_for_in = true; - if (!is_variable_declaration_empty(list.decls[0])) - { - JERRY_ASSERT (is_expression_empty (expr.exprs[0])); - JERRY_ASSERT (is_variable_declaration_empty (list.decls[1])); - res.data.for_in_stmt.init.is_decl = true; - res.data.for_in_stmt.init.data.decl = list.decls[0]; - } - if (!is_expression_empty(expr.exprs[0])) - { - JERRY_ASSERT (is_expression_empty(expr.exprs[0])); - res.data.for_in_stmt.init.is_decl = false; - res.data.for_in_stmt.init.data.left_hand_expr = expr.exprs[0]; - } + JERRY_UNIMPLEMENTED (); - skip_newlines (); - res.data.for_in_stmt.list_expr = parse_expression (); - token_after_newlines_must_be (TOK_CLOSE_PAREN); - - return res; } -static void -parse_expression_inside_parens (statement *res) +static T_IDX +parse_expression_inside_parens (void) { + T_IDX expr; token_after_newlines_must_be (TOK_OPEN_PAREN); - skip_newlines (); - res->data.expr = parse_assigment_expression (); + NEXT (expr, expression); token_after_newlines_must_be (TOK_CLOSE_PAREN); + return expr; +} + +/* statement_list + : statement (LT!* statement)* + ; */ +static void +parse_statement_list (void) +{ + while (true) + { + parse_statement (); + + tok = lexer_next_token (); + if (tok.type != TOK_NEWLINE && tok.type != TOK_SEMICOLON) + { + lexer_save_token (tok); + return; + } + + skip_newlines (); + } +} + +/* if_statement + : 'if' LT!* '(' LT!* expression LT!* ')' LT!* statement (LT!* 'else' LT!* statement)? + ; */ +static void +parse_if_statement (void) +{ + T_IDX cond, cond_oc; + assert_keyword (KW_IF); + + cond = parse_expression_inside_parens (); + cond_oc = opcode_counter; + DUMP_OPCODE (is_false_jmp, cond, 1); + + skip_newlines (); + parse_statement (); + + REWRITE_OPCODE (cond_oc, is_false_jmp, cond, opcode_counter); + + skip_newlines (); + if (is_keyword (KW_ELSE)) + { + skip_newlines (); + parse_statement (); + } + else + lexer_save_token (tok); +} + +/* do_while_statement + : 'do' LT!* statement LT!* 'while' LT!* '(' expression ')' (LT | ';')! + ; */ +static void +parse_do_while_statement (void) +{ + T_IDX cond, loop_oc; + + assert_keyword (KW_DO); + + loop_oc = opcode_counter; + + skip_newlines (); + parse_statement (); + + token_after_newlines_must_be_keyword (KW_WHILE); + cond = parse_expression_inside_parens (); + DUMP_OPCODE (is_true_jmp, cond, loop_oc); +} + +/* while_statement + : 'while' LT!* '(' LT!* expression LT!* ')' LT!* statement + ; */ +static void +parse_while_statement (void) +{ + T_IDX cond, cond_oc, jmp_oc; + + assert_keyword (KW_WHILE); + + cond_oc = opcode_counter; + cond = parse_expression_inside_parens (); + jmp_oc = opcode_counter; + DUMP_OPCODE (is_false_jmp, cond, 1); + + skip_newlines (); + parse_statement (); + + DUMP_OPCODE (jmp_up, (uint8_t) (opcode_counter - cond_oc)); + REWRITE_OPCODE (jmp_oc, is_false_jmp, cond, opcode_counter); +} + +/* with_statement + : 'with' LT!* '(' LT!* expression LT!* ')' LT!* statement + ; */ +static void +parse_with_statement (void) +{ + T_IDX expr; + assert_keyword (KW_WITH); + expr = parse_expression_inside_parens (); + + DUMP_OPCODE (with, expr); + + skip_newlines (); + parse_statement (); + + DUMP_VOID_OPCODE (end_with); +} + +/* switch_statement + : 'switch' LT!* '(' LT!* expression LT!* ')' LT!* '{' LT!* case_block LT!* '}' + ; */ +static void +parse_switch_statement (void) +{ + JERRY_UNIMPLEMENTED (); +} + +/* try_statement + : 'try' LT!* '{' LT!* statement_list LT!* '}' LT!* (finally_clause | catch_clause (LT!* finally_clause)?) + ; + + catch_clause + : 'catch' LT!* '(' LT!* Identifier LT!* ')' LT!* '{' LT!* statement_list LT!* '}' + ; + + finally_clause + : 'finally' LT!* '{' LT!* statement_list LT!* '}' + ;*/ +static void +parse_try_statement (void) +{ + JERRY_UNIMPLEMENTED (); } /* statement @@ -1111,261 +1659,91 @@ parse_expression_inside_parens (statement *res) try_statement : 'try' LT!* '{' LT!* statement_list LT!* '}' LT!* (finally_clause | catch_clause (LT!* finally_clause)?) ;*/ -statement -parser_parse_statement (void) +static void +parse_statement (void) { - statement res; - res.data.none = NULL; - - JERRY_ASSERT (scope_index); - - skip_newlines (); - - if (current_scopes[scope_index - 1].was_stmt - && (current_scopes[scope_index - 1].type - & (SCOPE_IF | SCOPE_WITH | SCOPE_SWITCH | SCOPE_ELSE | SCOPE_CATCH - | SCOPE_FUNCTION | SCOPE_WHILE | SCOPE_FOR))) - { - uint32_t type = current_scopes[scope_index - 1].type; - pop_scope (); - - lexer_save_token (tok); - - if (type & SCOPE_IF && !is_keyword (KW_ELSE)) - return (statement) { .type = STMT_END_IF, .data.none = NULL }; - if (type & SCOPE_WITH) - return (statement) { .type = STMT_END_WITH, .data.none = NULL }; - if (type & SCOPE_SWITCH) - return (statement) { .type = STMT_END_SWITCH, .data.none = NULL }; - if (type & SCOPE_ELSE) - return (statement) { .type = STMT_END_IF, .data.none = NULL }; - if (type & SCOPE_CATCH && !is_keyword (KW_FINALLY)) - return (statement) { .type = STMT_END_CATCH, .data.none = NULL }; - if (type & SCOPE_CATCH) - return (statement) { .type = STMT_END_FINALLY, .data.none = NULL }; - if (type & SCOPE_FUNCTION) - return (statement) { .type = STMT_END_FUNCTION, .data.none = NULL }; - if (type & SCOPE_WHILE) - return (statement) { .type = STMT_END_WHILE, .data.none = NULL }; - if (type & SCOPE_FOR) - return (statement) { .type = STMT_END_FOR_OR_FOR_IN, .data.none = NULL }; - - } - - if (is_keyword (KW_FINALLY)) - { - res.type = STMT_FINALLY; - current_scope_must_be (SCOPE_TRY | SCOPE_CATCH); - pop_scope (); - push_scope (SCOPE_FINALLY); - return res; - } - - current_scopes[scope_index - 1].was_stmt = true; - - if (tok.type == TOK_EOF) - { - current_scope_must_be_global (); - res.type = STMT_EOF; - return res; - } - - if (current_scopes[scope_index - 1].type == SCOPE_SUBEXPRESSION) - { - if (tok.type == TOK_CLOSE_PAREN) - { - res.type = STMT_END_SUBEXPRESSION; - pop_scope (); - return res; - } - res.type = STMT_EXPRESSION; - res.data.expr = parse_assigment_expression (); - return res; - } + if (tok.type == TOK_CLOSE_BRACE) + return; if (tok.type == TOK_OPEN_BRACE) { - push_scope (SCOPE_BLOCK); - return parser_parse_statement (); - } - if (tok.type == TOK_CLOSE_BRACE) - { - current_scope_must_be (SCOPE_BLOCK); - pop_scope (); - current_scopes[scope_index - 1].was_stmt = true; - return parser_parse_statement (); - } - if (is_keyword (KW_ELSE)) - { - current_scope_must_be (SCOPE_IF); skip_newlines (); - if (is_keyword (KW_IF)) + if (tok.type != TOK_CLOSE_BRACE) { - res.type = STMT_ELSE_IF; - parse_expression_inside_parens (&res); - return res; + parse_statement_list (); + next_token_must_be (TOK_CLOSE_BRACE); } - else - { - lexer_save_token (tok); - res.type = STMT_ELSE; - pop_scope (); - push_scope (SCOPE_ELSE); - return res; - } - } - if (is_keyword (KW_WHILE)) - { - res.type = STMT_WHILE; - parse_expression_inside_parens (&res); - if (current_scopes[scope_index - 1].type == SCOPE_DO) - { - insert_semicolon (); - pop_scope (); - res.type = STMT_END_DO_WHILE; - } - else - push_scope (SCOPE_WHILE); - return res; - } - if (is_keyword (KW_CATCH)) - { - res.type = STMT_CATCH; - current_scope_must_be (SCOPE_TRY); - parse_expression_inside_parens (&res); - pop_scope (); - push_scope (SCOPE_CATCH); - return res; - } - if (is_keyword (KW_FUNCTION)) - { - res.type = STMT_FUNCTION; - res.data.fun_decl = parse_function_declaration (); - push_scope (SCOPE_FUNCTION); - return res; + return; } if (is_keyword (KW_VAR)) { - res.type = STMT_VARIABLE; - skip_newlines (); - res.data.var_stmt = parse_variable_declaration_list (); - return res; + parse_variable_declaration_list (NULL); + return; } if (tok.type == TOK_SEMICOLON) { - res.type = STMT_EMPTY; - return res; + skip_newlines (); + return; } if (is_keyword (KW_IF)) { - res.type = STMT_IF; - parse_expression_inside_parens (&res); - push_scope (SCOPE_IF); - return res; + parse_if_statement (); + return; } if (is_keyword (KW_DO)) { - res.type = STMT_DO_WHILE; - push_scope (SCOPE_DO); - return res; + parse_do_while_statement (); + return; + } + if (is_keyword (KW_WHILE)) + { + parse_while_statement (); + return; } if (is_keyword (KW_FOR)) { - res.type = STMT_FOR_OR_FOR_IN; - res.data.for_stmt = parse_for_or_for_in_statement (); - push_scope (SCOPE_FOR); - return res; + parse_for_or_for_in_statement (); + return; } if (is_keyword (KW_CONTINUE)) { - scope_must_be (SCOPE_LOOP); - res.type = STMT_CONTINUE; - tok = lexer_next_token (); - if (tok.type == TOK_NAME) - res.data.name = tok.data.name; - else - lexer_save_token (tok); - insert_semicolon (); - return res; + JERRY_UNIMPLEMENTED (); } if (is_keyword (KW_BREAK)) { - scope_must_be (SCOPE_LOOP | SCOPE_CASE); - res.type = STMT_BREAK; - tok = lexer_next_token (); - if (tok.type == TOK_NAME) - { - if (current_scopes[scope_index - 1].type == SCOPE_CASE) - parser_fatal (ERR_PARSER); - res.data.name = tok.data.name; - } - else - lexer_save_token (tok); - insert_semicolon (); - return res; + JERRY_UNIMPLEMENTED (); } if (is_keyword (KW_RETURN)) { - scope_must_be (SCOPE_FUNCTION); - res.type = STMT_RETURN; + T_IDX expr; tok = lexer_next_token (); - if (tok.type != TOK_SEMICOLON && tok.type != TOK_NEWLINE) + if (tok.type != TOK_SEMICOLON) { - unsigned int current_scope_index = scope_index; - res.data.expr = parse_assigment_expression (); - if (current_scope_index == scope_index) - insert_semicolon (); + expr = parse_expression (); + DUMP_OPCODE (retval, expr); } - // Eat TOK_SEMICOLON - return res; + else + DUMP_VOID_OPCODE (ret); + return; } if (is_keyword (KW_WITH)) { - res.type = STMT_WITH; - parse_expression_inside_parens (&res); - push_scope (SCOPE_WITH); - return res; + parse_with_statement (); + return; } if (is_keyword (KW_SWITCH)) { - res.type = STMT_SWITCH; - parse_expression_inside_parens (&res); - push_scope (SCOPE_SWITCH); - return res; + parse_switch_statement (); + return; } if (is_keyword (KW_THROW)) { - res.type = STMT_THROW; - tok = lexer_next_token (); - res.data.expr = parse_assigment_expression (); - insert_semicolon (); - return res; + JERRY_UNIMPLEMENTED (); } if (is_keyword (KW_TRY)) { - res.type = STMT_TRY; - push_scope (SCOPE_TRY); - return res; - } - if (is_keyword (KW_CASE)) - { - if (current_scopes[scope_index - 1].type == SCOPE_CASE) - pop_scope (); - current_scope_must_be (SCOPE_SWITCH); - skip_newlines (); - res.data.expr = parse_assigment_expression (); - token_after_newlines_must_be (TOK_SEMICOLON); - push_scope (SCOPE_CASE); - return res; - } - if (is_keyword (KW_DEFAULT)) - { - if (current_scopes[scope_index - 1].type == SCOPE_CASE) - pop_scope (); - current_scope_must_be (SCOPE_SWITCH); - token_after_newlines_must_be (TOK_SEMICOLON); - push_scope (SCOPE_CASE); - return res; + parse_try_statement (); + return; } if (tok.type == TOK_NAME) { @@ -1373,39 +1751,64 @@ parser_parse_statement (void) skip_newlines (); if (tok.type == TOK_COLON) { - res.type = STMT_LABELLED; - res.data.name = saved.data.name; - return res; + // STMT_LABELLED; + JERRY_UNIMPLEMENTED (); } else { lexer_save_token (tok); tok = saved; - assignment_expression expr = parse_assigment_expression (); - res.type = STMT_EXPRESSION; - res.data.expr = expr; - return res; + parse_expression (); + return; } } - - assignment_expression expr = parse_assigment_expression (); - if (!is_expression_empty (expr)) - { - res.type = STMT_EXPRESSION; - res.data.expr = expr; - return res; - } else { - lexer_save_token (tok); - return null_statement; + parse_expression (); + return; } } +/* source_element + : function_declaration + | statement + ; */ +static void +parse_source_element (void) +{ + if (is_keyword (KW_FUNCTION)) + parse_function_declaration (); + else + parse_statement (); +} + +/* source_element_list + : source_element (LT!* source_element)* + ; */ +static void +parse_source_element_list (void) +{ + while (tok.type != TOK_EOF && tok.type != TOK_CLOSE_BRACE) + parse_source_element (); +} + +/* program + : LT!* source_element_list LT!* EOF! + ; */ +void +parser_parse_program (void) +{ + skip_newlines (); + parse_source_element_list (); + + skip_newlines (); + JERRY_ASSERT (tok.type == TOK_EOF); +} + void parser_init (void) { - scope_index = 1; + temp_name = min_temp_name = lexer_get_strings (NULL); #ifdef __HOST debug_file = __fopen ("parser.log", "w"); #endif diff --git a/src/libjsparser/parser.h b/src/libjsparser/parser.h index 43fec8c96..e89097349 100644 --- a/src/libjsparser/parser.h +++ b/src/libjsparser/parser.h @@ -18,427 +18,8 @@ #include "globals.h" -#define null_string 255 -#define MAX_PARAMS 5 -#define MAX_EXPRS 2 -#define MAX_PROPERTIES 5 -#define MAX_DECLS 5 -#define MAX_SUFFIXES 2 - -/** Represents list of parameters. */ -typedef struct formal_parameter_list -{ - /** Identifiers of a parameter. Next after last parameter is NULL. */ - uint8_t names[MAX_PARAMS]; -} -formal_parameter_list; - -static const formal_parameter_list -empty_formal_parameter_list = -{ - .names = { [0] = null_string } -}; - -bool is_formal_parameter_list_empty (formal_parameter_list); - -/** @function_declaration represents both declaration and expression of a function. - After this parser must return a block of statements. */ -typedef struct -{ - /** Identifier: name of a function. Can be NULL for anonimous functions. */ - uint8_t name; - /** List of parameter of a function. Can be NULL. */ - formal_parameter_list params; -} -function_declaration; - -typedef function_declaration function_expression; - -/** Types of literals: null, bool, decimal and string. - Decimal type is represented by LIT_INT and supports only double-word sized integers. */ -typedef enum -{ - LIT_NULL, - LIT_BOOL, - LIT_INT, - LIT_STR -} -literal_type; - -/** Represents different literals, contains a data of them. */ -typedef struct -{ - /** Type of a literal. */ - literal_type type; - - /** Value of a literal. */ - union - { - /** Used by null literal, always NULL. */ - void *none; - /** String literal value. */ - uint8_t str; - /** Number value. */ - int num; - /** Boolean value. */ - bool is_true; - } - data; -} -literal; - -typedef struct -{ - bool is_literal; - - union - { - void *none; - literal lit; - uint8_t name; - } - data; -} -operand; - -typedef operand property_name; - -static const operand -empty_operand = -{ - .is_literal = false, - .data.none = NULL -}; - -bool is_operand_empty (operand); - -typedef struct -{ - operand op1, op2; -} -operand_pair; - -typedef struct -{ - operand ops[MAX_PARAMS]; -} -operand_list; - -static const operand_list -empty_operand_list = -{ - .ops = { [0] = { .is_literal = false, .data.none = NULL } } -}; - -bool is_operand_list_empty (operand_list); - -typedef operand_list array_literal; -typedef operand_list argument_list; - -typedef struct -{ - uint8_t name; - argument_list args; -} -call_expression; - -/** Represents a single property. */ -typedef struct -{ - /** Name of property. */ - property_name name; - /** Value of property. */ - operand value; -} -property; - -static const property empty_property = -{ - .name = { .is_literal = false, .data.none = NULL }, - .value = { .is_literal = false, .data.none = NULL } -}; - -bool is_property_empty (property); - -/** List of properties. Represents ObjectLiteral. */ -typedef struct -{ - /** Properties. */ - property props[MAX_PROPERTIES]; -} -property_list; - -static const property_list -empty_property_list = -{ - .props = - { [0] = - { .name = - { .is_literal = false, .data.none = NULL }, - .value = - { .is_literal = false, .data.none = NULL }}} -}; - -bool is_property_list_empty (property_list); - -typedef property_list object_literal; - -typedef enum -{ - AO_NONE, - AO_EQ, - AO_MULT_EQ, - AO_DIV_EQ, - AO_MOD_EQ, - AO_PLUS_EQ, - AO_MINUS_EQ, - AO_LSHIFT_EQ, - AO_RSHIFT_EQ, - AO_RSHIFT_EX_EQ, - AO_AND_EQ, - AO_XOR_EQ, - AO_OR_EQ -} -assignment_operator; - -typedef enum -{ - ET_NONE, - ET_LOGICAL_OR, - ET_LOGICAL_AND, - ET_BITWISE_OR, - ET_BITWISE_XOR, - ET_BITWISE_AND, - ET_DOUBLE_EQ, - ET_NOT_EQ, - ET_TRIPLE_EQ, - ET_NOT_DOUBLE_EQ, - ET_LESS, - ET_GREATER, - ET_LESS_EQ, - ET_GREATER_EQ, - ET_INSTANCEOF, - ET_IN, - ET_LSHIFT, - ET_RSHIFT, - ET_RSHIFT_EX, - ET_PLUS, - ET_MINUS, - ET_MULT, - ET_DIV, - ET_MOD, - ET_UNARY_DELETE, - ET_UNARY_VOID, - ET_UNARY_TYPEOF, - ET_UNARY_INCREMENT, - ET_UNARY_DECREMENT, - ET_UNARY_PLUS, - ET_UNARY_MINUS, - ET_UNARY_COMPL, - ET_UNARY_NOT, - ET_POSTFIX_INCREMENT, - ET_POSTFIX_DECREMENT, - ET_CALL, - ET_NEW, - ET_INDEX, - ET_PROP_REF, - ET_OBJECT, - ET_FUNCTION, - ET_ARRAY, - ET_SUBEXPRESSION, - ET_LITERAL, - ET_IDENTIFIER -} -expression_type; - -typedef struct -{ - assignment_operator oper; - expression_type type; - - /** NUllable. */ - uint8_t var; - - union - { - void *none; - operand_pair ops; - call_expression call_expr; - array_literal arr_lit; - object_literal obj_lit; - function_expression func_expr; - } - data; -} -assignment_expression; - -static const assignment_expression -empty_expression = -{ - .oper = AO_NONE, - .type = ET_NONE, - .data.none = NULL -}; - -bool is_expression_empty (assignment_expression); - -/** Represents expression, array literal and list of argument. */ -typedef struct -{ - /** Single assignment expression. Cannot be NULL for expression and list of arguments. - But can be NULL for array literal. */ - assignment_expression exprs[MAX_EXPRS]; -} -expression_list; - -typedef expression_list expression; - -/* Statements. */ - -typedef struct -{ - uint8_t name; - assignment_expression assign_expr; -} -variable_declaration; - -static const variable_declaration -empty_variable_declaration = -{ - .name = null_string, - .assign_expr = { .oper = AO_NONE, .type = ET_NONE, .data.none = NULL } -}; - -bool is_variable_declaration_empty (variable_declaration); - -typedef struct -{ - variable_declaration decls[MAX_DECLS]; -} -variable_declaration_list; - -typedef struct -{ - bool is_decl; - - union - { - expression expr; - variable_declaration_list decl_list; - } - data; -} -for_statement_initialiser_part; - -typedef struct -{ - for_statement_initialiser_part init; - assignment_expression limit, incr; -} -for_statement; - -typedef struct -{ - bool is_decl; - - union - { - assignment_expression left_hand_expr; - variable_declaration decl; - } - data; -} -for_in_statement_initializer_part; - -typedef struct -{ - for_in_statement_initializer_part init; - expression list_expr; -} -for_in_statement; - -typedef struct -{ - bool is_for_in; - - union - { - for_statement for_stmt; - for_in_statement for_in_stmt; - } - data; -} -for_or_for_in_statement; - -typedef enum -{ - STMT_NULL, - STMT_VARIABLE, - STMT_EMPTY, - STMT_IF, - STMT_ELSE, - STMT_ELSE_IF, - STMT_END_IF, - STMT_DO_WHILE, - STMT_END_DO_WHILE, - STMT_WHILE, - - STMT_END_WHILE, - STMT_FOR_OR_FOR_IN, - STMT_END_FOR_OR_FOR_IN, - STMT_CONTINUE, - STMT_BREAK, - STMT_RETURN, - STMT_WITH, - STMT_END_WITH, - STMT_LABELLED, - STMT_SWITCH, - - STMT_END_SWITCH, - STMT_CASE, - STMT_THROW, - STMT_TRY, - STMT_CATCH, - STMT_END_CATCH, - STMT_FINALLY, - STMT_END_FINALLY, - STMT_EXPRESSION, - STMT_END_SUBEXPRESSION, - - STMT_FUNCTION, - STMT_END_FUNCTION, - STMT_EOF -} -statement_type; - -typedef struct statement -{ - statement_type type; - - union - { - void *none; - variable_declaration_list var_stmt; - assignment_expression expr; - for_or_for_in_statement for_stmt; - uint8_t name; - function_declaration fun_decl; - } - data; -} -statement; - -static const statement -null_statement = -{ - .type = STMT_NULL, - .data.none = NULL -}; - -bool is_statement_null (statement); - void parser_init (void); -statement parser_parse_statement (void); +void parser_parse_program (void); void parser_fatal (jerry_Status_t code); diff --git a/src/libruntime/jerry-exit.c b/src/libruntime/jerry-exit.c index 2fc97fc28..277f0b2b9 100644 --- a/src/libruntime/jerry-exit.c +++ b/src/libruntime/jerry-exit.c @@ -69,9 +69,9 @@ jerry_Exit( jerry_Status_t code) /**< status code */ case ERR_GENERAL: __printf("ERR_GENERAL\n"); break; + default: + __printf( "Return code is zero"); } - - jerry_AssertFail( "Return code is zero", __FILE__, __LINE__); } #endif /* !JERRY_NDEBUG */ diff --git a/src/libruntime/pretty-printer.c b/src/libruntime/pretty-printer.c deleted file mode 100644 index e242dbb7d..000000000 --- a/src/libruntime/pretty-printer.c +++ /dev/null @@ -1,1081 +0,0 @@ -/* Copyright 2014 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "jerry-libc.h" -#include "pretty-printer.h" - -static int intendation; - -#define MAX_NAMES 100 - -void -pp_reset (void) -{ - intendation = 0; -} - -void -pp_token (token tok) -{ - switch (tok.type) - { - case TOK_NAME: - __printf ("IDENTIFIER (%s)\n", tok.data.name); - break; - - case TOK_STRING: - __printf ("STRING (n%d)\n", tok.data.str); - break; - - case TOK_KEYWORD: - pp_keyword (tok.data.kw); - break; - - case TOK_INT: - __printf ("INTEGER (%d)\n", tok.data.num); - break; - - case TOK_FLOAT: - FIXME(int -> float); - __printf ("FLOAT (%d)\n", (int)tok.data.fp_num); - break; - - case TOK_NULL: - __printf ("NULL (null)\n"); - break; - - case TOK_BOOL: - if (tok.data.is_true) - __printf ("BOOL (true)\n"); - else - __printf ("BOOL (false)\n"); - break; - - - case TOK_OPEN_BRACE: - __printf ("PUNC ({)\n"); - break; - - case TOK_CLOSE_BRACE: - __printf ("PUNC (})\n"); - break; - - case TOK_OPEN_PAREN: - __printf ("PUNC (()\n"); - break; - - case TOK_CLOSE_PAREN: - __printf ("PUNC ())\n"); - break; - - case TOK_OPEN_SQUARE: - __printf ("PUNC ([)\n"); - break; - - case TOK_CLOSE_SQUARE: - __printf ("PUNC (])\n"); - break; - - - case TOK_DOT: - __printf ("PUNC (.)\n"); - break; - - case TOK_SEMICOLON: - __printf ("PUNC (;)\n"); - break; - - case TOK_COMMA: - __printf ("PUNC (,)\n"); - break; - - case TOK_LESS: - __printf ("PUNC (<)\n"); - break; - - case TOK_GREATER: - __printf ("PUNC (>)\n"); - break; - - case TOK_LESS_EQ: - __printf ("PUNC (<=)\n"); - break; - - - case TOK_GREATER_EQ: - __printf ("PUNC (>=)\n"); - break; - - case TOK_DOUBLE_EQ: - __printf ("PUNC (==)\n"); - break; - - case TOK_NOT_EQ: - __printf ("PUNC (!=)\n"); - break; - - case TOK_TRIPLE_EQ: - __printf ("PUNC (===)\n"); - break; - - case TOK_NOT_DOUBLE_EQ: - __printf ("PUNC (!==)\n"); - break; - - - case TOK_PLUS: - __printf ("PUNC (+)\n"); - break; - - case TOK_MINUS: - __printf ("PUNC (-)\n"); - break; - - case TOK_MULT: - __printf ("PUNC (*)\n"); - break; - - case TOK_MOD: - __printf ("PUNC (%%)\n"); - break; - - case TOK_DOUBLE_PLUS: - __printf ("PUNC (++)\n"); - break; - - case TOK_DOUBLE_MINUS: - __printf ("PUNC (--)\n"); - break; - - - case TOK_LSHIFT: - __printf ("PUNC (<<)\n"); - break; - - case TOK_RSHIFT: - __printf ("PUNC (>>)\n"); - break; - - case TOK_RSHIFT_EX: - __printf ("PUNC (>>>)\n"); - break; - - case TOK_AND: - __printf ("PUNC (&)\n"); - break; - - case TOK_OR: - __printf ("PUNC (|)\n"); - break; - - case TOK_XOR: - __printf ("PUNC (^)\n"); - break; - - - case TOK_NOT: - __printf ("PUNC (!)\n"); - break; - - case TOK_COMPL: - __printf ("PUNC (~)\n"); - break; - - case TOK_DOUBLE_AND: - __printf ("PUNC (&&)\n"); - break; - - case TOK_DOUBLE_OR: - __printf ("PUNC (||)\n"); - break; - - case TOK_QUERY: - __printf ("PUNC (?)\n"); - break; - - case TOK_COLON: - __printf ("PUNC (:)\n"); - break; - - - case TOK_EQ: - __printf ("PUNC (=)\n"); - break; - - case TOK_PLUS_EQ: - __printf ("PUNC (+=)\n"); - break; - - case TOK_MINUS_EQ: - __printf ("PUNC (-=)\n"); - break; - - case TOK_MULT_EQ: - __printf ("PUNC (*=)\n"); - break; - - case TOK_MOD_EQ: - __printf ("PUNC (%%=)\n"); - break; - - case TOK_LSHIFT_EQ: - __printf ("PUNC (<<=)\n"); - break; - - - case TOK_RSHIFT_EQ: - __printf ("PUNC (>>=)\n"); - break; - - case TOK_RSHIFT_EX_EQ: - __printf ("PUNC (>>>=)\n"); - break; - - case TOK_AND_EQ: - __printf ("PUNC (&=)\n"); - break; - - case TOK_OR_EQ: - __printf ("PUNC (|=)\n"); - break; - - case TOK_XOR_EQ: - __printf ("PUNC (^=)\n"); - break; - - - case TOK_DIV: - __printf ("PUNC (/)\n"); - break; - - case TOK_DIV_EQ: - __printf ("PUNC (/=)\n"); - break; - - case TOK_NEWLINE: - __printf ("NEWLINE\n"); - break; - - default: - JERRY_UNREACHABLE (); - - } -} - -void -pp_keyword (keyword kw) -{ - switch (kw) - { - case KW_NONE: - JERRY_UNREACHABLE (); - break; - - case KW_RESERVED: - __printf ("KEYWORD RESERVED\n"); - break; - - - case KW_BREAK: - __printf ("KEYWORD (break)\n"); - break; - - case KW_CASE: - __printf ("KEYWORD (case)\n"); - break; - - case KW_CATCH: - __printf ("KEYWORD (catch)\n"); - break; - - case KW_CONTINUE: - __printf ("KEYWORD (continue)\n"); - break; - - case KW_DEBUGGER: - __printf ("KEYWORD (debugger)\n"); - break; - - case KW_DEFAULT: - __printf ("KEYWORD (default)\n"); - break; - - case KW_DELETE: - __printf ("KEYWORD (delete)\n"); - break; - - - case KW_DO: - __printf ("KEYWORD (do)\n"); - break; - - case KW_ELSE: - __printf ("KEYWORD (else)\n"); - break; - - case KW_FINALLY: - __printf ("KEYWORD (finally)\n"); - break; - - case KW_FOR: - __printf ("KEYWORD (for)\n"); - break; - - case KW_FUNCTION: - __printf ("KEYWORD (function)\n"); - break; - - case KW_IF: - __printf ("KEYWORD (if)\n"); - break; - - case KW_IN: - __printf ("KEYWORD (in)\n"); - break; - - - case KW_INSTANCEOF: - __printf ("KEYWORD (instanceof)\n"); - break; - - case KW_NEW: - __printf ("KEYWORD (new)\n"); - break; - - case KW_RETURN: - __printf ("KEYWORD (return)\n"); - break; - - case KW_SWITCH: - __printf ("KEYWORD (switch)\n"); - break; - - case KW_THIS: - __printf ("KEYWORD (this)\n"); - break; - - case KW_THROW: - __printf ("KEYWORD (throw)\n"); - break; - - case KW_TRY: - __printf ("KEYWORD (try)\n"); - break; - - - case KW_TYPEOF: - __printf ("KEYWORD (typeof)\n"); - break; - - case KW_VAR: - __printf ("KEYWORD (var)\n"); - break; - - case KW_VOID: - __printf ("KEYWORD (void)\n"); - break; - - case KW_WHILE: - __printf ("KEYWORD (while)\n"); - break; - - case KW_WITH: - __printf ("KEYWORD (with)\n"); - break; - - default: - JERRY_UNREACHABLE (); - - } -} - -static void -intend (void) -{ - for (int i = 0; i < intendation; i++) - __putchar (' '); -} - -static void -pp_formal_parameter_list (formal_parameter_list param_list) -{ - int i; - - for (i = 0; i < MAX_PARAMS; i++) - { - if (param_list.names[i] == null_string) - break; - if (i != 0) - __printf (", "); - __printf ("%s", lexer_get_string_by_id (param_list.names[i])); - } -} - -static void -pp_function_declaration (function_declaration func_decl) -{ - __printf ("function "); - if (func_decl.name) - __printf ("%s ", lexer_get_string_by_id (func_decl.name)); - __putchar ('('); - pp_formal_parameter_list (func_decl.params); - __printf (") "); -} - -static void -pp_literal (literal lit) -{ - switch (lit.type) - { - case LIT_NULL: - __printf ("null"); - break; - - case LIT_BOOL: - __printf ("%s", lit.data.is_true ? "true" : "false"); - break; - - case LIT_INT: - __printf ("%d", lit.data.num); - break; - - case LIT_STR: - __printf ("\"%s\"", lit.data.str); - break; - - default: - JERRY_UNREACHABLE (); - } -} - -static void -pp_operand (operand op) -{ - JERRY_ASSERT (!is_operand_empty (op)); - if (op.is_literal) - pp_literal (op.data.lit); - else - __printf ("%s", lexer_get_string_by_id (op.data.name)); -} - -static void -pp_operand_list (operand_list list) -{ - int i; - - for (i = 0; i < MAX_PARAMS; i++) - { - if (is_operand_empty (list.ops[i])) - break; - if (i != 0) - __printf (", "); - pp_operand (list.ops[i]); - } -} - -static void -pp_property (property prop) -{ - JERRY_ASSERT (!is_property_empty (prop)); - pp_operand (prop.name); - __printf (" : "); - pp_operand (prop.value); -} - -static void -pp_property_list (property_list prop_list) -{ - int i; - - for (i = 0; i < MAX_PROPERTIES; i++) - { - if (is_property_empty (prop_list.props[i])) - break; - if (i != 0) - __printf (", "); - pp_property (prop_list.props[i]); - } -} - -static void -pp_call_expression (call_expression expr) -{ - JERRY_ASSERT (expr.name < MAX_NAMES); - __printf ("%s (", lexer_get_string_by_id (expr.name)); - pp_operand_list (expr.args); - __printf (")\n"); -} - -static void -dump_two_operands (operand_pair pair, const char *operation) -{ - pp_operand (pair.op1); - __printf ("%s", operation); - pp_operand (pair.op2); - __putchar ('\n'); -} - -static void -dump_unary (operand op, const char *operation) -{ - __printf ("%s", operation); - pp_operand (op); - __putchar ('\n'); -} - -static void -dump_postfix (operand op, const char *operation) -{ - pp_operand (op); - __printf ("%s\n", operation); -} - -static void -pp_assignment_expression (assignment_expression expr) -{ - if (expr.oper != AO_NONE && expr.var) - __printf ("%s", expr.var); - - switch (expr.oper) - { - case AO_NONE: - break; - - case AO_EQ: - __printf (" = "); - break; - - case AO_MULT_EQ: - __printf (" *= "); - break; - - case AO_DIV_EQ: - __printf (" ?= "); - break; - - case AO_MOD_EQ: - __printf (" %%= "); - break; - - case AO_PLUS_EQ: - __printf (" += "); - break; - - case AO_MINUS_EQ: - __printf (" -= "); - break; - - case AO_LSHIFT_EQ: - __printf (" <<= "); - break; - - case AO_RSHIFT_EQ: - __printf (" >>= "); - break; - - case AO_RSHIFT_EX_EQ: - __printf (" >>>= "); - break; - - case AO_AND_EQ: - __printf (" &= "); - break; - - case AO_XOR_EQ: - __printf (" ^= "); - break; - - case AO_OR_EQ: - __printf (" |= "); - break; - - default: - JERRY_UNREACHABLE (); - } - - switch (expr.type) - { - case ET_NONE: - pp_operand (expr.data.ops.op1); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - return; - - case ET_LOGICAL_OR: - dump_two_operands (expr.data.ops, " || "); - return; - - case ET_LOGICAL_AND: - dump_two_operands (expr.data.ops, " && "); - return; - - case ET_BITWISE_OR: - dump_two_operands (expr.data.ops, " | "); - return; - - case ET_BITWISE_XOR: - dump_two_operands (expr.data.ops, " ^ "); - return; - - case ET_BITWISE_AND: - dump_two_operands (expr.data.ops, " & "); - return; - - case ET_DOUBLE_EQ: - dump_two_operands (expr.data.ops, " == "); - return; - - case ET_NOT_EQ: - dump_two_operands (expr.data.ops, " != "); - return; - - case ET_TRIPLE_EQ: - dump_two_operands (expr.data.ops, " === "); - return; - - case ET_NOT_DOUBLE_EQ: - dump_two_operands (expr.data.ops, " !== "); - return; - - case ET_LESS: - dump_two_operands (expr.data.ops, " < "); - return; - - case ET_GREATER: - dump_two_operands (expr.data.ops, " > "); - return; - - case ET_LESS_EQ: - dump_two_operands (expr.data.ops, " <= "); - return; - - case ET_GREATER_EQ: - dump_two_operands (expr.data.ops, " <= "); - return; - - case ET_INSTANCEOF: - dump_two_operands (expr.data.ops, " instanceof "); - return; - - case ET_IN: - dump_two_operands (expr.data.ops, " in "); - return; - - case ET_LSHIFT: - dump_two_operands (expr.data.ops, " << "); - return; - - case ET_RSHIFT: - dump_two_operands (expr.data.ops, " >> "); - return; - - case ET_RSHIFT_EX: - dump_two_operands (expr.data.ops, " >>> "); - return; - - case ET_PLUS: - dump_two_operands (expr.data.ops, " + "); - return; - - case ET_MINUS: - dump_two_operands (expr.data.ops, " - "); - return; - - case ET_MULT: - dump_two_operands (expr.data.ops, " * "); - return; - - case ET_DIV: - dump_two_operands (expr.data.ops, " / "); - return; - - case ET_MOD: - dump_two_operands (expr.data.ops, " %% "); - return; - - case ET_UNARY_DELETE: - dump_unary (expr.data.ops.op1, "delete "); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - return; - - case ET_UNARY_VOID: - dump_unary (expr.data.ops.op1, "void "); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - return; - - case ET_UNARY_TYPEOF: - dump_unary (expr.data.ops.op1, "typeof "); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - return; - - case ET_UNARY_INCREMENT: - dump_unary (expr.data.ops.op1, "++"); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - return; - - case ET_UNARY_DECREMENT: - dump_unary (expr.data.ops.op1, "--"); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - return; - - case ET_UNARY_PLUS: - dump_unary (expr.data.ops.op1, "+"); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - return; - - case ET_UNARY_MINUS: - dump_unary (expr.data.ops.op1, "-"); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - return; - - case ET_UNARY_COMPL: - dump_unary (expr.data.ops.op1, "~"); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - return; - - case ET_UNARY_NOT: - dump_unary (expr.data.ops.op1, "!"); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - return; - - case ET_POSTFIX_INCREMENT: - dump_postfix (expr.data.ops.op1, "++"); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - return; - - case ET_POSTFIX_DECREMENT: - dump_postfix (expr.data.ops.op1, "--"); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - return; - - case ET_CALL: - pp_call_expression (expr.data.call_expr); - return; - - case ET_NEW: - __printf ("new "); - pp_operand (expr.data.ops.op1); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - __putchar ('\n'); - return; - - case ET_INDEX: - pp_operand (expr.data.ops.op1); - __putchar ('.'); - pp_operand (expr.data.ops.op2); - __putchar ('\n'); - return; - - case ET_PROP_REF: - pp_operand (expr.data.ops.op1); - __putchar ('['); - pp_operand (expr.data.ops.op2); - __printf ("]\n"); - return; - - case ET_OBJECT: - __putchar ('{'); - pp_property_list (expr.data.obj_lit); - __printf ("}\n"); - return; - - case ET_FUNCTION: - pp_function_declaration (expr.data.func_expr); - return; - - case ET_ARRAY: - __putchar ('['); - pp_operand_list (expr.data.arr_lit); - __printf ("]\n"); - return; - - case ET_SUBEXPRESSION: - __putchar ('('); - return; - - case ET_LITERAL: - case ET_IDENTIFIER: - pp_operand (expr.data.ops.op1); - JERRY_ASSERT (is_operand_empty (expr.data.ops.op2)); - __putchar ('\n'); - return; - - default: - JERRY_UNREACHABLE (); - } -} - -static void -pp_expression (expression_list expr_list) -{ - int i; - - for (i = 0; i < MAX_EXPRS; i++) - { - if (is_expression_empty (expr_list.exprs[i])) - break; - if (i != 0) - __printf (", "); - pp_assignment_expression (expr_list.exprs[i]); - } -} - -static void -pp_variable_declaration (variable_declaration var_decl) -{ - __printf ("%s", lexer_get_string_by_id (var_decl.name)); - if (!is_expression_empty (var_decl.assign_expr)) - { - __printf (" = "); - pp_assignment_expression (var_decl.assign_expr); - } -} - -static void -pp_variable_declaration_list (variable_declaration_list decl_list) -{ - int i; - - __printf ("var "); - - for (i = 0; i < MAX_DECLS; i++) - { - if (is_variable_declaration_empty (decl_list.decls[i])) - break; - if (i != 0) - __printf (", "); - pp_variable_declaration (decl_list.decls[i]); - } -} - -static void -pp_for_in_statement_initializer_part (for_in_statement_initializer_part init) -{ - if (init.is_decl) - { - __printf ("var "); - pp_variable_declaration (init.data.decl); - } - else if (!is_expression_empty (init.data.left_hand_expr)) - pp_assignment_expression (init.data.left_hand_expr); -} - -static void -pp_for_in_statement (for_in_statement for_in_stmt) -{ - __printf ("for ("); - pp_for_in_statement_initializer_part (for_in_stmt.init); - __printf (" in "); - pp_expression (for_in_stmt.list_expr); - __printf (") "); -} - -static void -pp_for_statement_initialiser_part (for_statement_initialiser_part init) -{ - if (init.is_decl) - pp_variable_declaration_list (init.data.decl_list); - else - pp_expression (init.data.expr); -} - -static void -pp_for_statement (for_statement for_stmt) -{ - __printf ("for ("); - pp_for_statement_initialiser_part (for_stmt.init); - __printf ("; "); - if (is_expression_empty (for_stmt.limit)) - pp_assignment_expression (for_stmt.limit); - __printf ("; "); - if (is_expression_empty (for_stmt.incr)) - pp_assignment_expression (for_stmt.incr); - __printf (") "); -} - -static void -pp_for_or_for_in_statement (for_or_for_in_statement for_or_for_in_stmt) -{ - if (for_or_for_in_stmt.is_for_in) - pp_for_in_statement (for_or_for_in_stmt.data.for_in_stmt); - else - pp_for_statement (for_or_for_in_stmt.data.for_stmt); -} - -void -pp_statement (statement stmt) -{ - switch (stmt.type) - { - case STMT_EMPTY: - break; - - case STMT_VARIABLE: - intend (); - pp_variable_declaration_list (stmt.data.var_stmt); - break; - - case STMT_IF: - intend (); - __printf ("if ("); - pp_assignment_expression (stmt.data.expr); - __printf (") {\n"); - intendation += 2; - break; - - case STMT_ELSE: - intendation -= 2; - intend (); - __printf ("} else {\n"); - intendation += 2; - break; - - case STMT_ELSE_IF: - intendation -= 2; - intend (); - __printf ("} else if("); - pp_assignment_expression (stmt.data.expr); - __printf (") {\n"); - intendation += 2; - break; - - case STMT_END_IF: - case STMT_END_WHILE: - case STMT_END_WITH: - case STMT_END_SWITCH: - case STMT_END_CATCH: - case STMT_END_FINALLY: - case STMT_END_FUNCTION: - intendation -= 2; - intend (); - __printf ("}\n"); - break; - - case STMT_DO_WHILE: - intend (); - __printf ("do {"); - intendation += 2; - break; - - case STMT_END_DO_WHILE: - intendation -= 2; - intend (); - __printf ("} while ("); - pp_assignment_expression (stmt.data.expr); - __printf (");\n"); - - case STMT_WHILE: - intend (); - __printf ("while ("); - pp_assignment_expression (stmt.data.expr); - __printf (") {\n"); - intendation += 2; - break; - - case STMT_FOR_OR_FOR_IN: - intend (); - pp_for_or_for_in_statement (stmt.data.for_stmt); - intendation += 2; - break; - - case STMT_CONTINUE: - intend (); - __printf ("continue\n"); - break; - - case STMT_BREAK: - intend (); - __printf ("break\n"); - break; - - case STMT_RETURN: - intend (); - __printf ("return "); - pp_assignment_expression (stmt.data.expr); - break; - - case STMT_WITH: - intend (); - __printf ("with ("); - pp_assignment_expression (stmt.data.expr); - __printf (") "); - intendation += 2; - break; - - case STMT_LABELLED: - intend (); - __printf ("%s:\n", stmt.data.name); - break; - - case STMT_SWITCH: - intend (); - __printf ("switch ("); - pp_assignment_expression (stmt.data.expr); - __printf (") "); - intendation += 2; - break; - - case STMT_CASE: - intend (); - __printf ("case "); - pp_assignment_expression (stmt.data.expr); - __printf (":\n"); - break; - - case STMT_THROW: - intend (); - __printf ("throw "); - pp_assignment_expression (stmt.data.expr); - __printf (";\n"); - break; - - case STMT_TRY: - intend (); - __printf ("try "); - break; - - case STMT_CATCH: - intend (); - __printf ("catch ("); - pp_assignment_expression (stmt.data.expr); - __printf (") "); - intendation += 2; - break; - - case STMT_FINALLY: - intend (); - __printf ("finally "); - intendation += 2; - break; - - case STMT_EXPRESSION: - intend (); - pp_assignment_expression (stmt.data.expr); - break; - - case STMT_END_SUBEXPRESSION: - __putchar (')'); - break; - - case STMT_FUNCTION: - intend (); - pp_function_declaration (stmt.data.fun_decl); - __printf ("{\n"); - intendation += 2; - break; - - default: - JERRY_UNREACHABLE (); - } -} diff --git a/src/libruntime/pretty-printer.h b/src/libruntime/pretty-printer.h deleted file mode 100644 index 22e9fb49f..000000000 --- a/src/libruntime/pretty-printer.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright 2014 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef PRETTY_PRINTER_H -#define PRETTY_PRINTER_H - -#include "lexer.h" -#include "parser.h" - -void pp_reset (void); -void pp_finish (void); -void pp_token (token); -void pp_keyword (keyword); -void pp_statement (statement); - -#endif \ No newline at end of file diff --git a/src/libruntime/serializer.h b/src/libruntime/serializer.h index acb4d0f34..5a5314b06 100644 --- a/src/libruntime/serializer.h +++ b/src/libruntime/serializer.h @@ -22,4 +22,6 @@ void serializer_init (void); void serializer_dump_data (const void *, size_t); +void serializer_rewrite_data (const int8_t, const void *, size_t); + #endif // SERIALIZER_H \ No newline at end of file diff --git a/src/libruntime/target/linux/serializer.c b/src/libruntime/target/linux/serializer.c index f8a32ddcf..5c176f169 100644 --- a/src/libruntime/target/linux/serializer.c +++ b/src/libruntime/target/linux/serializer.c @@ -15,17 +15,39 @@ #include "serializer.h" #include "jerry-libc.h" +#include "opcodes.h" + +FILE *dump; + +#define OPCODE_STR(op) \ + #op, + +static char* massive[] = { + OP_LIST (OPCODE_STR) + "" +}; void serializer_init (void) { } +static int opcode_counter = 0; + void serializer_dump_data (const void *data, size_t size) { size_t i; - for (i = 0; i < size; i++) - __putchar (((char *) data)[i]); + __printf ("%03d: %20s ", opcode_counter++, massive[(int)((char*)data)[0]]); + for (i = 1; i < size; i++) + __printf ("%4d ", ((char*)data)[i]); + + __printf ("\n"); +} + +void +serializer_rewrite_data (const int8_t offset __unused, const void *data __unused, size_t size __unused) +{ + TODO (implement); } \ No newline at end of file diff --git a/src/main.c b/src/main.c index 1d26ccb48..1b4603f6e 100644 --- a/src/main.c +++ b/src/main.c @@ -35,8 +35,6 @@ #include "jerry-libc.h" #include "lexer.h" #include "parser.h" -#include "pretty-printer.h" -#include "bytecode-generator.h" #define DUMP_TOKENS (1u << 0) #define DUMP_AST (1u << 1) @@ -99,27 +97,9 @@ fake_exit (void) #endif } -static inline void -check_for_several_dumps (uint8_t dump) -{ - bool was_bit = 0; - for (; dump; dump >>= 1) - { - if (dump & 1u) - { - if (was_bit) - jerry_Exit (ERR_SEVERAL_FILES); - else - was_bit = true; - } - } -} - int main (int argc, char **argv) { - statement st; - uint8_t dump = 0; #ifdef __HOST const char *file_name = NULL; FILE *file = NULL; @@ -127,27 +107,15 @@ main (int argc, char **argv) mem_Init (); - if (argc > 0) - for (int i = 1; i < argc; i++) - { - if (!__strcmp ("-t", argv[i])) - dump |= DUMP_TOKENS; - else if (!__strcmp ("-a", argv[i])) - dump |= DUMP_AST; - else if (!__strcmp ("-b", argv[i])) - dump |= DUMP_BYTECODE; #ifdef __HOST - else if (file_name == NULL) - file_name = argv[i]; -#endif + if (argc > 0) + { + if (file_name == NULL) + file_name = argv[1]; else jerry_Exit (ERR_SEVERAL_FILES); } - - check_for_several_dumps (dump); - - if (!dump) - dump |= DUMP_BYTECODE; +#endif #ifdef __HOST if (file_name == NULL) @@ -165,60 +133,26 @@ main (int argc, char **argv) lexer_set_source (generated_source); #endif - if (dump & DUMP_AST) - { - parser_init (); - st = parser_parse_statement (); - JERRY_ASSERT (!is_statement_null (st)); - while (st.type != STMT_EOF) - { - pp_statement (st); - st = parser_parse_statement (); - JERRY_ASSERT (!is_statement_null (st)); - } - } + // const char *strings[MAX_STRINGS]; + // uint8_t strings_num; + // First run parser to fill list of strings + token tok = lexer_next_token (); + while (tok.type != TOK_EOF) + tok = lexer_next_token (); - if (dump & DUMP_TOKENS) - { - token tok = lexer_next_token (); - while (tok.type != TOK_EOF) - { - pp_token (tok); - tok = lexer_next_token (); - } - } + // strings_num = lexer_get_strings (strings); - if (dump & DUMP_BYTECODE) - { - const char *strings[MAX_STRINGS]; - uint8_t strings_num; - // First run parser to fill list of strings - token tok = lexer_next_token (); - while (tok.type != TOK_EOF) - tok = lexer_next_token (); - - strings_num = lexer_get_strings (strings); - - // Reset lexer + // Reset lexer #ifdef __HOST - __rewind (file); - lexer_set_file (file); + __rewind (file); + lexer_set_file (file); #else - lexer_set_source (generated_source); + lexer_set_source (generated_source); #endif - parser_init (); - generator_init (); - generator_dump_strings (strings, strings_num); - st = parser_parse_statement (); - JERRY_ASSERT (!is_statement_null (st)); - while (st.type != STMT_EOF) - { - generator_dump_statement (st); - st = parser_parse_statement (); - JERRY_ASSERT (!is_statement_null (st)); - } - } + parser_init (); + TODO (serializer_dump_data (strings strings_num)); + parser_parse_program (); //gen_bytecode (generated_source); //gen_bytecode ();