2020-03-11 18:27:43 +00:00
/*
* Copyright ( c ) 2020 , Stephan Unverwerth < s . unverwerth @ gmx . de >
2020-04-23 14:43:10 +00:00
* Copyright ( c ) 2020 , Linus Groh < mail @ linusgroh . de >
2020-03-11 18:27:43 +00:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "Parser.h"
2020-03-12 22:02:41 +00:00
# include <AK/HashMap.h>
2020-04-13 14:42:54 +00:00
# include <AK/ScopeGuard.h>
2020-03-11 18:27:43 +00:00
# include <AK/StdLibExtras.h>
# include <stdio.h>
namespace JS {
2020-03-12 22:02:41 +00:00
2020-04-13 14:42:54 +00:00
class ScopePusher {
public :
enum Type {
Var = 1 ,
Let = 2 ,
} ;
ScopePusher ( Parser & parser , unsigned mask )
: m_parser ( parser )
, m_mask ( mask )
{
if ( m_mask & Var )
m_parser . m_parser_state . m_var_scopes . append ( NonnullRefPtrVector < VariableDeclaration > ( ) ) ;
if ( m_mask & Let )
m_parser . m_parser_state . m_let_scopes . append ( NonnullRefPtrVector < VariableDeclaration > ( ) ) ;
}
~ ScopePusher ( )
{
if ( m_mask & Var )
m_parser . m_parser_state . m_var_scopes . take_last ( ) ;
if ( m_mask & Let )
m_parser . m_parser_state . m_let_scopes . take_last ( ) ;
}
Parser & m_parser ;
unsigned m_mask { 0 } ;
} ;
2020-03-12 22:02:41 +00:00
static HashMap < TokenType , int > g_operator_precedence ;
2020-03-30 13:24:43 +00:00
Parser : : ParserState : : ParserState ( Lexer lexer )
2020-03-11 18:27:43 +00:00
: m_lexer ( move ( lexer ) )
, m_current_token ( m_lexer . next ( ) )
2020-03-30 13:24:43 +00:00
{
}
Parser : : Parser ( Lexer lexer )
: m_parser_state ( move ( lexer ) )
2020-03-11 18:27:43 +00:00
{
2020-03-12 22:02:41 +00:00
if ( g_operator_precedence . is_empty ( ) ) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
g_operator_precedence . set ( TokenType : : Period , 20 ) ;
g_operator_precedence . set ( TokenType : : BracketOpen , 20 ) ;
g_operator_precedence . set ( TokenType : : ParenOpen , 20 ) ;
g_operator_precedence . set ( TokenType : : QuestionMarkPeriod , 20 ) ;
g_operator_precedence . set ( TokenType : : New , 19 ) ;
g_operator_precedence . set ( TokenType : : PlusPlus , 18 ) ;
g_operator_precedence . set ( TokenType : : MinusMinus , 18 ) ;
g_operator_precedence . set ( TokenType : : ExclamationMark , 17 ) ;
g_operator_precedence . set ( TokenType : : Tilde , 17 ) ;
g_operator_precedence . set ( TokenType : : Typeof , 17 ) ;
g_operator_precedence . set ( TokenType : : Void , 17 ) ;
g_operator_precedence . set ( TokenType : : Delete , 17 ) ;
g_operator_precedence . set ( TokenType : : Await , 17 ) ;
g_operator_precedence . set ( TokenType : : DoubleAsterisk , 16 ) ;
g_operator_precedence . set ( TokenType : : Asterisk , 15 ) ;
g_operator_precedence . set ( TokenType : : Slash , 15 ) ;
g_operator_precedence . set ( TokenType : : Percent , 15 ) ;
g_operator_precedence . set ( TokenType : : Plus , 14 ) ;
g_operator_precedence . set ( TokenType : : Minus , 14 ) ;
g_operator_precedence . set ( TokenType : : ShiftLeft , 13 ) ;
g_operator_precedence . set ( TokenType : : ShiftRight , 13 ) ;
g_operator_precedence . set ( TokenType : : UnsignedShiftRight , 13 ) ;
g_operator_precedence . set ( TokenType : : LessThan , 12 ) ;
g_operator_precedence . set ( TokenType : : LessThanEquals , 12 ) ;
g_operator_precedence . set ( TokenType : : GreaterThan , 12 ) ;
g_operator_precedence . set ( TokenType : : GreaterThanEquals , 12 ) ;
g_operator_precedence . set ( TokenType : : In , 12 ) ;
g_operator_precedence . set ( TokenType : : Instanceof , 12 ) ;
g_operator_precedence . set ( TokenType : : EqualsEquals , 11 ) ;
g_operator_precedence . set ( TokenType : : ExclamationMarkEquals , 11 ) ;
g_operator_precedence . set ( TokenType : : EqualsEqualsEquals , 11 ) ;
g_operator_precedence . set ( TokenType : : ExclamationMarkEqualsEquals , 11 ) ;
g_operator_precedence . set ( TokenType : : Ampersand , 10 ) ;
g_operator_precedence . set ( TokenType : : Caret , 9 ) ;
g_operator_precedence . set ( TokenType : : Pipe , 8 ) ;
g_operator_precedence . set ( TokenType : : DoubleQuestionMark , 7 ) ;
g_operator_precedence . set ( TokenType : : DoubleAmpersand , 6 ) ;
g_operator_precedence . set ( TokenType : : DoublePipe , 5 ) ;
g_operator_precedence . set ( TokenType : : QuestionMark , 4 ) ;
g_operator_precedence . set ( TokenType : : Equals , 3 ) ;
g_operator_precedence . set ( TokenType : : PlusEquals , 3 ) ;
g_operator_precedence . set ( TokenType : : MinusEquals , 3 ) ;
g_operator_precedence . set ( TokenType : : AsteriskAsteriskEquals , 3 ) ;
g_operator_precedence . set ( TokenType : : AsteriskEquals , 3 ) ;
g_operator_precedence . set ( TokenType : : SlashEquals , 3 ) ;
g_operator_precedence . set ( TokenType : : PercentEquals , 3 ) ;
g_operator_precedence . set ( TokenType : : ShiftLeftEquals , 3 ) ;
g_operator_precedence . set ( TokenType : : ShiftRightEquals , 3 ) ;
g_operator_precedence . set ( TokenType : : UnsignedShiftRightEquals , 3 ) ;
g_operator_precedence . set ( TokenType : : PipeEquals , 3 ) ;
g_operator_precedence . set ( TokenType : : Yield , 2 ) ;
g_operator_precedence . set ( TokenType : : Comma , 1 ) ;
}
}
int Parser : : operator_precedence ( TokenType type ) const
{
auto it = g_operator_precedence . find ( type ) ;
if ( it = = g_operator_precedence . end ( ) ) {
2020-04-17 13:05:58 +00:00
fprintf ( stderr , " Internal Error: No precedence for operator %s \n " , Token : : name ( type ) ) ;
2020-03-12 22:02:41 +00:00
ASSERT_NOT_REACHED ( ) ;
return - 1 ;
}
return it - > value ;
}
Associativity Parser : : operator_associativity ( TokenType type ) const
{
switch ( type ) {
case TokenType : : Period :
case TokenType : : BracketOpen :
case TokenType : : ParenOpen :
case TokenType : : QuestionMarkPeriod :
case TokenType : : Asterisk :
case TokenType : : Slash :
case TokenType : : Percent :
case TokenType : : Plus :
case TokenType : : Minus :
case TokenType : : ShiftLeft :
case TokenType : : ShiftRight :
case TokenType : : UnsignedShiftRight :
case TokenType : : LessThan :
case TokenType : : LessThanEquals :
case TokenType : : GreaterThan :
case TokenType : : GreaterThanEquals :
case TokenType : : In :
case TokenType : : Instanceof :
case TokenType : : EqualsEquals :
case TokenType : : ExclamationMarkEquals :
case TokenType : : EqualsEqualsEquals :
case TokenType : : ExclamationMarkEqualsEquals :
2020-03-28 10:48:52 +00:00
case TokenType : : Typeof :
2020-04-15 16:55:03 +00:00
case TokenType : : Void :
2020-03-12 22:02:41 +00:00
case TokenType : : Ampersand :
case TokenType : : Caret :
case TokenType : : Pipe :
case TokenType : : DoubleQuestionMark :
case TokenType : : DoubleAmpersand :
case TokenType : : DoublePipe :
case TokenType : : Comma :
return Associativity : : Left ;
default :
return Associativity : : Right ;
}
2020-03-11 18:27:43 +00:00
}
2020-03-18 10:23:53 +00:00
NonnullRefPtr < Program > Parser : : parse_program ( )
2020-03-11 18:27:43 +00:00
{
2020-04-13 14:42:54 +00:00
ScopePusher scope ( * this , ScopePusher : : Var | ScopePusher : : Let ) ;
2020-03-18 10:23:53 +00:00
auto program = adopt ( * new Program ) ;
2020-03-11 18:27:43 +00:00
while ( ! done ( ) ) {
if ( match ( TokenType : : Semicolon ) ) {
consume ( ) ;
} else if ( match_statement ( ) ) {
program - > append ( parse_statement ( ) ) ;
} else {
expected ( " statement " ) ;
consume ( ) ;
}
}
2020-04-13 14:42:54 +00:00
ASSERT ( m_parser_state . m_var_scopes . size ( ) = = 1 ) ;
program - > add_variables ( m_parser_state . m_var_scopes . last ( ) ) ;
program - > add_variables ( m_parser_state . m_let_scopes . last ( ) ) ;
2020-03-11 18:27:43 +00:00
return program ;
}
2020-03-18 10:23:53 +00:00
NonnullRefPtr < Statement > Parser : : parse_statement ( )
2020-03-11 18:27:43 +00:00
{
2020-03-23 18:08:32 +00:00
auto statement = [ this ] ( ) - > NonnullRefPtr < Statement > {
2020-03-30 13:24:43 +00:00
switch ( m_parser_state . m_current_token . type ( ) ) {
2020-03-11 18:27:43 +00:00
case TokenType : : Function :
2020-03-19 10:52:56 +00:00
return parse_function_node < FunctionDeclaration > ( ) ;
2020-03-11 18:27:43 +00:00
case TokenType : : CurlyOpen :
return parse_block_statement ( ) ;
case TokenType : : Return :
return parse_return_statement ( ) ;
case TokenType : : Var :
2020-03-12 11:16:48 +00:00
case TokenType : : Let :
2020-03-12 12:24:34 +00:00
case TokenType : : Const :
2020-03-11 18:27:43 +00:00
return parse_variable_declaration ( ) ;
2020-03-12 12:12:12 +00:00
case TokenType : : For :
return parse_for_statement ( ) ;
2020-03-21 17:40:17 +00:00
case TokenType : : If :
return parse_if_statement ( ) ;
2020-03-24 21:03:50 +00:00
case TokenType : : Throw :
return parse_throw_statement ( ) ;
2020-03-24 13:03:55 +00:00
case TokenType : : Try :
return parse_try_statement ( ) ;
2020-03-29 11:09:54 +00:00
case TokenType : : Break :
return parse_break_statement ( ) ;
2020-04-04 22:22:42 +00:00
case TokenType : : Continue :
return parse_continue_statement ( ) ;
2020-03-29 11:09:54 +00:00
case TokenType : : Switch :
return parse_switch_statement ( ) ;
2020-04-04 19:29:23 +00:00
case TokenType : : Do :
return parse_do_while_statement ( ) ;
2020-04-21 18:27:57 +00:00
case TokenType : : While :
return parse_while_statement ( ) ;
2020-03-11 18:27:43 +00:00
default :
2020-04-17 13:05:58 +00:00
if ( match_expression ( ) ) {
auto expr = parse_expression ( 0 ) ;
consume_or_insert_semicolon ( ) ;
return create_ast_node < ExpressionStatement > ( move ( expr ) ) ;
}
2020-03-30 13:24:43 +00:00
m_parser_state . m_has_errors = true ;
2020-03-11 18:27:43 +00:00
expected ( " statement (missing switch case) " ) ;
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < ErrorStatement > ( ) ;
2020-03-23 18:08:32 +00:00
} } ( ) ;
2020-04-17 13:05:58 +00:00
2020-03-23 18:08:32 +00:00
return statement ;
2020-03-11 18:27:43 +00:00
}
2020-03-30 13:26:09 +00:00
RefPtr < FunctionExpression > Parser : : try_parse_arrow_function_expression ( bool expect_parens )
{
save_state ( ) ;
2020-04-13 14:42:54 +00:00
m_parser_state . m_var_scopes . append ( NonnullRefPtrVector < VariableDeclaration > ( ) ) ;
ArmedScopeGuard state_rollback_guard = [ & ] {
m_parser_state . m_var_scopes . take_last ( ) ;
load_state ( ) ;
} ;
2020-03-30 13:26:09 +00:00
Vector < FlyString > parameters ;
bool parse_failed = false ;
while ( true ) {
if ( match ( TokenType : : Comma ) ) {
consume ( TokenType : : Comma ) ;
} else if ( match ( TokenType : : Identifier ) ) {
auto token = consume ( TokenType : : Identifier ) ;
parameters . append ( token . value ( ) ) ;
} else if ( match ( TokenType : : ParenClose ) ) {
if ( expect_parens ) {
consume ( TokenType : : ParenClose ) ;
if ( match ( TokenType : : Arrow ) ) {
consume ( TokenType : : Arrow ) ;
} else {
parse_failed = true ;
}
break ;
}
parse_failed = true ;
break ;
} else if ( match ( TokenType : : Arrow ) ) {
if ( ! expect_parens ) {
consume ( TokenType : : Arrow ) ;
break ;
}
parse_failed = true ;
break ;
} else {
parse_failed = true ;
break ;
}
}
2020-04-13 14:42:54 +00:00
if ( parse_failed )
2020-03-30 13:26:09 +00:00
return nullptr ;
auto function_body_result = [ this ] ( ) - > RefPtr < BlockStatement > {
if ( match ( TokenType : : CurlyOpen ) ) {
// Parse a function body with statements
return parse_block_statement ( ) ;
}
if ( match_expression ( ) ) {
// Parse a function body which returns a single expression
// FIXME: We synthesize a block with a return statement
// for arrow function bodies which are a single expression.
// Esprima generates a single "ArrowFunctionExpression"
// with a "body" property.
auto return_expression = parse_expression ( 0 ) ;
auto return_block = create_ast_node < BlockStatement > ( ) ;
return_block - > append < ReturnStatement > ( move ( return_expression ) ) ;
return return_block ;
}
// Invalid arrow function body
return nullptr ;
} ( ) ;
if ( ! function_body_result . is_null ( ) ) {
2020-04-13 14:42:54 +00:00
state_rollback_guard . disarm ( ) ;
2020-03-30 13:26:09 +00:00
auto body = function_body_result . release_nonnull ( ) ;
2020-04-13 14:42:54 +00:00
return create_ast_node < FunctionExpression > ( " " , move ( body ) , move ( parameters ) , m_parser_state . m_var_scopes . take_last ( ) ) ;
2020-03-30 13:26:09 +00:00
}
return nullptr ;
}
2020-03-18 10:23:53 +00:00
NonnullRefPtr < Expression > Parser : : parse_primary_expression ( )
2020-03-11 18:27:43 +00:00
{
2020-03-25 08:51:54 +00:00
if ( match_unary_prefixed_expression ( ) )
return parse_unary_prefixed_expression ( ) ;
2020-03-30 13:24:43 +00:00
switch ( m_parser_state . m_current_token . type ( ) ) {
2020-03-11 18:27:43 +00:00
case TokenType : : ParenOpen : {
consume ( TokenType : : ParenOpen ) ;
2020-03-30 13:26:09 +00:00
if ( match ( TokenType : : ParenClose ) | | match ( TokenType : : Identifier ) ) {
auto arrow_function_result = try_parse_arrow_function_expression ( true ) ;
if ( ! arrow_function_result . is_null ( ) ) {
return arrow_function_result . release_nonnull ( ) ;
}
}
2020-03-12 22:02:41 +00:00
auto expression = parse_expression ( 0 ) ;
2020-03-11 18:27:43 +00:00
consume ( TokenType : : ParenClose ) ;
return expression ;
}
2020-04-12 22:42:14 +00:00
case TokenType : : This :
consume ( ) ;
return create_ast_node < ThisExpression > ( ) ;
2020-03-30 13:26:09 +00:00
case TokenType : : Identifier : {
auto arrow_function_result = try_parse_arrow_function_expression ( false ) ;
if ( ! arrow_function_result . is_null ( ) ) {
return arrow_function_result . release_nonnull ( ) ;
}
2020-03-18 10:23:53 +00:00
return create_ast_node < Identifier > ( consume ( ) . value ( ) ) ;
2020-03-30 13:26:09 +00:00
}
2020-03-11 18:27:43 +00:00
case TokenType : : NumericLiteral :
2020-03-18 10:23:53 +00:00
return create_ast_node < NumericLiteral > ( consume ( ) . double_value ( ) ) ;
2020-03-11 18:27:43 +00:00
case TokenType : : BoolLiteral :
2020-03-18 10:23:53 +00:00
return create_ast_node < BooleanLiteral > ( consume ( ) . bool_value ( ) ) ;
2020-03-12 12:05:06 +00:00
case TokenType : : StringLiteral :
2020-03-18 10:23:53 +00:00
return create_ast_node < StringLiteral > ( consume ( ) . string_value ( ) ) ;
2020-03-15 21:32:34 +00:00
case TokenType : : NullLiteral :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < NullLiteral > ( ) ;
2020-03-11 18:27:43 +00:00
case TokenType : : CurlyOpen :
return parse_object_expression ( ) ;
2020-03-19 10:52:56 +00:00
case TokenType : : Function :
return parse_function_node < FunctionExpression > ( ) ;
2020-03-20 19:29:57 +00:00
case TokenType : : BracketOpen :
return parse_array_expression ( ) ;
2020-03-28 15:33:52 +00:00
case TokenType : : New :
return parse_new_expression ( ) ;
2020-03-11 18:27:43 +00:00
default :
2020-03-30 13:24:43 +00:00
m_parser_state . m_has_errors = true ;
2020-03-11 18:27:43 +00:00
expected ( " primary expression (missing switch case) " ) ;
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < ErrorExpression > ( ) ;
2020-03-11 18:27:43 +00:00
}
}
2020-03-18 10:23:53 +00:00
NonnullRefPtr < Expression > Parser : : parse_unary_prefixed_expression ( )
2020-03-14 18:45:51 +00:00
{
2020-03-30 13:24:43 +00:00
auto precedence = operator_precedence ( m_parser_state . m_current_token . type ( ) ) ;
auto associativity = operator_associativity ( m_parser_state . m_current_token . type ( ) ) ;
switch ( m_parser_state . m_current_token . type ( ) ) {
2020-03-14 18:45:51 +00:00
case TokenType : : PlusPlus :
consume ( ) ;
2020-03-28 10:48:52 +00:00
return create_ast_node < UpdateExpression > ( UpdateOp : : Increment , parse_expression ( precedence , associativity ) , true ) ;
2020-03-14 18:45:51 +00:00
case TokenType : : MinusMinus :
consume ( ) ;
2020-03-28 10:48:52 +00:00
return create_ast_node < UpdateExpression > ( UpdateOp : : Decrement , parse_expression ( precedence , associativity ) , true ) ;
2020-03-14 18:45:51 +00:00
case TokenType : : ExclamationMark :
consume ( ) ;
2020-03-28 10:48:52 +00:00
return create_ast_node < UnaryExpression > ( UnaryOp : : Not , parse_expression ( precedence , associativity ) ) ;
2020-03-14 18:45:51 +00:00
case TokenType : : Tilde :
consume ( ) ;
2020-03-28 10:48:52 +00:00
return create_ast_node < UnaryExpression > ( UnaryOp : : BitwiseNot , parse_expression ( precedence , associativity ) ) ;
2020-04-02 16:58:39 +00:00
case TokenType : : Plus :
consume ( ) ;
return create_ast_node < UnaryExpression > ( UnaryOp : : Plus , parse_expression ( precedence , associativity ) ) ;
case TokenType : : Minus :
consume ( ) ;
return create_ast_node < UnaryExpression > ( UnaryOp : : Minus , parse_expression ( precedence , associativity ) ) ;
2020-03-17 19:33:32 +00:00
case TokenType : : Typeof :
consume ( ) ;
2020-03-28 10:48:52 +00:00
return create_ast_node < UnaryExpression > ( UnaryOp : : Typeof , parse_expression ( precedence , associativity ) ) ;
2020-04-15 16:55:03 +00:00
case TokenType : : Void :
consume ( ) ;
return create_ast_node < UnaryExpression > ( UnaryOp : : Void , parse_expression ( precedence , associativity ) ) ;
2020-03-14 18:45:51 +00:00
default :
2020-03-30 13:24:43 +00:00
m_parser_state . m_has_errors = true ;
2020-03-14 18:45:51 +00:00
expected ( " primary expression (missing switch case) " ) ;
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < ErrorExpression > ( ) ;
2020-03-14 18:45:51 +00:00
}
}
2020-03-18 10:23:53 +00:00
NonnullRefPtr < ObjectExpression > Parser : : parse_object_expression ( )
2020-03-11 18:27:43 +00:00
{
2020-04-23 18:37:53 +00:00
NonnullRefPtrVector < ObjectProperty > properties ;
2020-03-11 18:27:43 +00:00
consume ( TokenType : : CurlyOpen ) ;
2020-03-21 00:29:00 +00:00
2020-04-07 17:29:37 +00:00
while ( ! done ( ) & & ! match ( TokenType : : CurlyClose ) ) {
2020-04-23 18:37:53 +00:00
RefPtr < Expression > property_key ;
RefPtr < Expression > property_value ;
2020-04-23 18:17:39 +00:00
auto need_colon = true ;
2020-04-18 18:31:27 +00:00
if ( match_identifier_name ( ) ) {
2020-04-23 18:37:53 +00:00
auto identifier = consume ( ) . value ( ) ;
property_key = create_ast_node < StringLiteral > ( identifier ) ;
property_value = create_ast_node < Identifier > ( identifier ) ;
2020-04-23 18:17:39 +00:00
need_colon = false ;
2020-04-06 20:17:05 +00:00
} else if ( match ( TokenType : : StringLiteral ) ) {
2020-04-23 18:37:53 +00:00
property_key = create_ast_node < StringLiteral > ( consume ( TokenType : : StringLiteral ) . string_value ( ) ) ;
2020-04-06 20:17:05 +00:00
} else if ( match ( TokenType : : NumericLiteral ) ) {
2020-04-23 18:37:53 +00:00
property_key = create_ast_node < StringLiteral > ( consume ( TokenType : : NumericLiteral ) . value ( ) ) ;
} else if ( match ( TokenType : : BracketOpen ) ) {
consume ( TokenType : : BracketOpen ) ;
property_key = parse_expression ( 0 ) ;
consume ( TokenType : : BracketClose ) ;
2020-04-06 20:17:05 +00:00
} else {
m_parser_state . m_has_errors = true ;
auto & current_token = m_parser_state . m_current_token ;
2020-04-17 13:05:58 +00:00
fprintf ( stderr , " Syntax Error: Unexpected token %s as member in object initialization. Expected a numeric literal, string literal or identifier (line: %zu, column: %zu)) \n " ,
2020-04-12 22:42:14 +00:00
current_token . name ( ) ,
current_token . line_number ( ) ,
current_token . line_column ( ) ) ;
2020-04-06 20:17:05 +00:00
consume ( ) ;
continue ;
}
2020-04-23 18:17:39 +00:00
if ( need_colon | | match ( TokenType : : Colon ) ) {
2020-03-21 00:29:00 +00:00
consume ( TokenType : : Colon ) ;
2020-04-23 18:37:53 +00:00
property_value = parse_expression ( 0 ) ;
2020-03-21 00:29:00 +00:00
}
2020-04-23 18:37:53 +00:00
auto property = create_ast_node < ObjectProperty > ( * property_key , * property_value ) ;
properties . append ( property ) ;
2020-03-21 00:29:00 +00:00
if ( ! match ( TokenType : : Comma ) )
break ;
consume ( TokenType : : Comma ) ;
}
2020-03-11 18:27:43 +00:00
consume ( TokenType : : CurlyClose ) ;
2020-03-21 00:29:00 +00:00
return create_ast_node < ObjectExpression > ( properties ) ;
2020-03-11 18:27:43 +00:00
}
2020-03-20 19:29:57 +00:00
NonnullRefPtr < ArrayExpression > Parser : : parse_array_expression ( )
{
consume ( TokenType : : BracketOpen ) ;
2020-04-15 19:09:06 +00:00
Vector < RefPtr < Expression > > elements ;
while ( match_expression ( ) | | match ( TokenType : : Comma ) ) {
RefPtr < Expression > expression ;
if ( match_expression ( ) )
expression = parse_expression ( 0 ) ;
elements . append ( expression ) ;
2020-03-20 19:29:57 +00:00
if ( ! match ( TokenType : : Comma ) )
break ;
consume ( TokenType : : Comma ) ;
}
consume ( TokenType : : BracketClose ) ;
return create_ast_node < ArrayExpression > ( move ( elements ) ) ;
}
2020-03-18 10:23:53 +00:00
NonnullRefPtr < Expression > Parser : : parse_expression ( int min_precedence , Associativity associativity )
2020-03-11 18:27:43 +00:00
{
auto expression = parse_primary_expression ( ) ;
while ( match_secondary_expression ( ) ) {
2020-03-30 13:24:43 +00:00
int new_precedence = operator_precedence ( m_parser_state . m_current_token . type ( ) ) ;
2020-03-12 22:02:41 +00:00
if ( new_precedence < min_precedence )
break ;
if ( new_precedence = = min_precedence & & associativity = = Associativity : : Left )
break ;
2020-03-30 13:24:43 +00:00
Associativity new_associativity = operator_associativity ( m_parser_state . m_current_token . type ( ) ) ;
2020-03-12 22:02:41 +00:00
expression = parse_secondary_expression ( move ( expression ) , new_precedence , new_associativity ) ;
2020-03-11 18:27:43 +00:00
}
return expression ;
}
2020-03-18 10:23:53 +00:00
NonnullRefPtr < Expression > Parser : : parse_secondary_expression ( NonnullRefPtr < Expression > lhs , int min_precedence , Associativity associativity )
2020-03-11 18:27:43 +00:00
{
2020-03-30 13:24:43 +00:00
switch ( m_parser_state . m_current_token . type ( ) ) {
2020-03-11 18:27:43 +00:00
case TokenType : : Plus :
consume ( ) ;
2020-04-05 11:56:53 +00:00
return create_ast_node < BinaryExpression > ( BinaryOp : : Addition , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:09:15 +00:00
case TokenType : : PlusEquals :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < AssignmentExpression > ( AssignmentOp : : AdditionAssignment , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-11 18:27:43 +00:00
case TokenType : : Minus :
consume ( ) ;
2020-04-05 11:56:53 +00:00
return create_ast_node < BinaryExpression > ( BinaryOp : : Subtraction , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:09:15 +00:00
case TokenType : : MinusEquals :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < AssignmentExpression > ( AssignmentOp : : SubtractionAssignment , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:04:52 +00:00
case TokenType : : Asterisk :
consume ( ) ;
2020-04-05 11:56:53 +00:00
return create_ast_node < BinaryExpression > ( BinaryOp : : Multiplication , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:09:15 +00:00
case TokenType : : AsteriskEquals :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < AssignmentExpression > ( AssignmentOp : : MultiplicationAssignment , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:04:52 +00:00
case TokenType : : Slash :
consume ( ) ;
2020-04-05 11:56:53 +00:00
return create_ast_node < BinaryExpression > ( BinaryOp : : Division , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:09:15 +00:00
case TokenType : : SlashEquals :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < AssignmentExpression > ( AssignmentOp : : DivisionAssignment , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-04-04 19:17:34 +00:00
case TokenType : : Percent :
consume ( ) ;
return create_ast_node < BinaryExpression > ( BinaryOp : : Modulo , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-04-12 22:42:14 +00:00
case TokenType : : DoubleAsterisk :
2020-04-05 12:40:00 +00:00
consume ( ) ;
return create_ast_node < BinaryExpression > ( BinaryOp : : Exponentiation , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:10:27 +00:00
case TokenType : : GreaterThan :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < BinaryExpression > ( BinaryOp : : GreaterThan , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:07:08 +00:00
case TokenType : : GreaterThanEquals :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < BinaryExpression > ( BinaryOp : : GreaterThanEquals , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:10:27 +00:00
case TokenType : : LessThan :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < BinaryExpression > ( BinaryOp : : LessThan , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:07:08 +00:00
case TokenType : : LessThanEquals :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < BinaryExpression > ( BinaryOp : : LessThanEquals , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:11:33 +00:00
case TokenType : : EqualsEqualsEquals :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < BinaryExpression > ( BinaryOp : : TypedEquals , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:11:33 +00:00
case TokenType : : ExclamationMarkEqualsEquals :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < BinaryExpression > ( BinaryOp : : TypedInequals , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-15 22:23:38 +00:00
case TokenType : : EqualsEquals :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < BinaryExpression > ( BinaryOp : : AbstractEquals , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-15 22:23:38 +00:00
case TokenType : : ExclamationMarkEquals :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < BinaryExpression > ( BinaryOp : : AbstractInequals , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-04-23 15:06:01 +00:00
case TokenType : : In :
consume ( ) ;
return create_ast_node < BinaryExpression > ( BinaryOp : : In , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-28 15:56:54 +00:00
case TokenType : : Instanceof :
consume ( ) ;
return create_ast_node < BinaryExpression > ( BinaryOp : : InstanceOf , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-04-03 12:02:31 +00:00
case TokenType : : Ampersand :
consume ( ) ;
return create_ast_node < BinaryExpression > ( BinaryOp : : BitwiseAnd , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
case TokenType : : Pipe :
consume ( ) ;
return create_ast_node < BinaryExpression > ( BinaryOp : : BitwiseOr , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
case TokenType : : Caret :
consume ( ) ;
return create_ast_node < BinaryExpression > ( BinaryOp : : BitwiseXor , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-04-23 12:36:14 +00:00
case TokenType : : ShiftLeft :
consume ( ) ;
return create_ast_node < BinaryExpression > ( BinaryOp : : LeftShift , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
case TokenType : : ShiftLeftEquals :
consume ( ) ;
return create_ast_node < AssignmentExpression > ( AssignmentOp : : LeftShiftAssignment , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-04-23 12:45:19 +00:00
case TokenType : : ShiftRight :
consume ( ) ;
return create_ast_node < BinaryExpression > ( BinaryOp : : RightShift , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
case TokenType : : ShiftRightEquals :
consume ( ) ;
return create_ast_node < AssignmentExpression > ( AssignmentOp : : RightShiftAssignment , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-04-23 14:43:10 +00:00
case TokenType : : UnsignedShiftRight :
consume ( ) ;
return create_ast_node < BinaryExpression > ( BinaryOp : : UnsignedRightShift , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
case TokenType : : UnsignedShiftRightEquals :
consume ( ) ;
return create_ast_node < AssignmentExpression > ( AssignmentOp : : UnsignedRightShiftAssignment , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-11 18:27:43 +00:00
case TokenType : : ParenOpen :
return parse_call_expression ( move ( lhs ) ) ;
case TokenType : : Equals :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < AssignmentExpression > ( AssignmentOp : : Assignment , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-12 12:05:57 +00:00
case TokenType : : Period :
consume ( ) ;
2020-04-18 18:31:27 +00:00
if ( ! match_identifier_name ( ) )
expected ( " IdentifierName " ) ;
return create_ast_node < MemberExpression > ( move ( lhs ) , create_ast_node < Identifier > ( consume ( ) . value ( ) ) ) ;
2020-03-20 19:51:03 +00:00
case TokenType : : BracketOpen : {
consume ( TokenType : : BracketOpen ) ;
2020-03-23 18:08:32 +00:00
auto expression = create_ast_node < MemberExpression > ( move ( lhs ) , parse_expression ( 0 ) , true ) ;
2020-03-20 19:51:03 +00:00
consume ( TokenType : : BracketClose ) ;
return expression ;
}
2020-03-12 11:45:45 +00:00
case TokenType : : PlusPlus :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < UpdateExpression > ( UpdateOp : : Increment , move ( lhs ) ) ;
2020-03-12 11:45:45 +00:00
case TokenType : : MinusMinus :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < UpdateExpression > ( UpdateOp : : Decrement , move ( lhs ) ) ;
2020-03-15 21:35:22 +00:00
case TokenType : : DoubleAmpersand :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < LogicalExpression > ( LogicalOp : : And , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-03-15 21:35:22 +00:00
case TokenType : : DoublePipe :
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < LogicalExpression > ( LogicalOp : : Or , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-04-17 23:49:11 +00:00
case TokenType : : DoubleQuestionMark :
consume ( ) ;
return create_ast_node < LogicalExpression > ( LogicalOp : : NullishCoalescing , move ( lhs ) , parse_expression ( min_precedence , associativity ) ) ;
2020-04-03 10:14:28 +00:00
case TokenType : : QuestionMark :
return parse_conditional_expression ( move ( lhs ) ) ;
2020-03-11 18:27:43 +00:00
default :
2020-03-30 13:24:43 +00:00
m_parser_state . m_has_errors = true ;
2020-03-11 18:27:43 +00:00
expected ( " secondary expression (missing switch case) " ) ;
consume ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < ErrorExpression > ( ) ;
2020-03-11 18:27:43 +00:00
}
}
2020-03-18 10:23:53 +00:00
NonnullRefPtr < CallExpression > Parser : : parse_call_expression ( NonnullRefPtr < Expression > lhs )
2020-03-11 18:27:43 +00:00
{
consume ( TokenType : : ParenOpen ) ;
2020-03-12 18:35:23 +00:00
2020-03-18 10:23:53 +00:00
NonnullRefPtrVector < Expression > arguments ;
2020-03-12 18:35:23 +00:00
2020-03-12 19:03:12 +00:00
while ( match_expression ( ) ) {
2020-03-12 22:02:41 +00:00
arguments . append ( parse_expression ( 0 ) ) ;
2020-03-12 19:03:12 +00:00
if ( ! match ( TokenType : : Comma ) )
break ;
consume ( ) ;
2020-03-12 18:35:23 +00:00
}
2020-03-11 18:27:43 +00:00
consume ( TokenType : : ParenClose ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < CallExpression > ( move ( lhs ) , move ( arguments ) ) ;
2020-03-11 18:27:43 +00:00
}
2020-03-28 15:33:52 +00:00
NonnullRefPtr < NewExpression > Parser : : parse_new_expression ( )
{
consume ( TokenType : : New ) ;
// FIXME: Support full expressions as the callee as well.
auto callee = create_ast_node < Identifier > ( consume ( TokenType : : Identifier ) . value ( ) ) ;
NonnullRefPtrVector < Expression > arguments ;
if ( match ( TokenType : : ParenOpen ) ) {
consume ( TokenType : : ParenOpen ) ;
while ( match_expression ( ) ) {
arguments . append ( parse_expression ( 0 ) ) ;
if ( ! match ( TokenType : : Comma ) )
break ;
consume ( ) ;
}
consume ( TokenType : : ParenClose ) ;
}
return create_ast_node < NewExpression > ( move ( callee ) , move ( arguments ) ) ;
}
2020-03-18 10:23:53 +00:00
NonnullRefPtr < ReturnStatement > Parser : : parse_return_statement ( )
2020-03-11 18:27:43 +00:00
{
consume ( TokenType : : Return ) ;
2020-04-17 13:05:58 +00:00
// Automatic semicolon insertion: terminate statement when return is followed by newline
if ( m_parser_state . m_current_token . trivia ( ) . contains ( ' \n ' ) )
return create_ast_node < ReturnStatement > ( nullptr ) ;
2020-03-11 18:27:43 +00:00
if ( match_expression ( ) ) {
2020-04-18 12:00:43 +00:00
auto expression = parse_expression ( 0 ) ;
consume_or_insert_semicolon ( ) ;
return create_ast_node < ReturnStatement > ( move ( expression ) ) ;
2020-03-11 18:27:43 +00:00
}
2020-04-18 12:00:43 +00:00
2020-04-17 13:05:58 +00:00
consume_or_insert_semicolon ( ) ;
2020-03-18 10:23:53 +00:00
return create_ast_node < ReturnStatement > ( nullptr ) ;
2020-03-11 18:27:43 +00:00
}
2020-03-18 10:23:53 +00:00
NonnullRefPtr < BlockStatement > Parser : : parse_block_statement ( )
2020-03-11 18:27:43 +00:00
{
2020-04-13 14:42:54 +00:00
ScopePusher scope ( * this , ScopePusher : : Let ) ;
2020-03-18 10:23:53 +00:00
auto block = create_ast_node < BlockStatement > ( ) ;
2020-03-11 18:27:43 +00:00
consume ( TokenType : : CurlyOpen ) ;
while ( ! done ( ) & & ! match ( TokenType : : CurlyClose ) ) {
if ( match ( TokenType : : Semicolon ) ) {
consume ( ) ;
} else if ( match_statement ( ) ) {
block - > append ( parse_statement ( ) ) ;
} else {
expected ( " statement " ) ;
consume ( ) ;
}
}
consume ( TokenType : : CurlyClose ) ;
2020-04-13 14:42:54 +00:00
block - > add_variables ( m_parser_state . m_let_scopes . last ( ) ) ;
2020-03-11 18:27:43 +00:00
return block ;
}
2020-03-19 10:52:56 +00:00
template < typename FunctionNodeType >
NonnullRefPtr < FunctionNodeType > Parser : : parse_function_node ( )
2020-03-11 18:27:43 +00:00
{
2020-04-13 14:42:54 +00:00
ScopePusher scope ( * this , ScopePusher : : Var ) ;
2020-03-11 18:27:43 +00:00
consume ( TokenType : : Function ) ;
2020-03-19 10:52:56 +00:00
String name ;
if ( FunctionNodeType : : must_have_name ( ) ) {
name = consume ( TokenType : : Identifier ) . value ( ) ;
} else {
if ( match ( TokenType : : Identifier ) )
name = consume ( TokenType : : Identifier ) . value ( ) ;
}
2020-03-11 18:27:43 +00:00
consume ( TokenType : : ParenOpen ) ;
2020-03-22 10:07:55 +00:00
Vector < FlyString > parameters ;
2020-03-11 18:27:43 +00:00
while ( match ( TokenType : : Identifier ) ) {
2020-03-13 13:40:24 +00:00
auto parameter = consume ( TokenType : : Identifier ) . value ( ) ;
parameters . append ( parameter ) ;
2020-03-11 18:27:43 +00:00
if ( match ( TokenType : : ParenClose ) ) {
break ;
}
consume ( TokenType : : Comma ) ;
}
consume ( TokenType : : ParenClose ) ;
auto body = parse_block_statement ( ) ;
2020-04-13 14:42:54 +00:00
body - > add_variables ( m_parser_state . m_var_scopes . last ( ) ) ;
return create_ast_node < FunctionNodeType > ( name , move ( body ) , move ( parameters ) , NonnullRefPtrVector < VariableDeclaration > ( ) ) ;
2020-03-11 18:27:43 +00:00
}
2020-03-18 10:23:53 +00:00
NonnullRefPtr < VariableDeclaration > Parser : : parse_variable_declaration ( )
2020-03-11 18:27:43 +00:00
{
2020-04-08 09:59:18 +00:00
DeclarationKind declaration_kind ;
2020-03-12 11:16:48 +00:00
2020-03-30 13:24:43 +00:00
switch ( m_parser_state . m_current_token . type ( ) ) {
2020-03-12 11:16:48 +00:00
case TokenType : : Var :
2020-04-08 09:59:18 +00:00
declaration_kind = DeclarationKind : : Var ;
2020-03-12 11:16:48 +00:00
consume ( TokenType : : Var ) ;
break ;
case TokenType : : Let :
2020-04-08 09:59:18 +00:00
declaration_kind = DeclarationKind : : Let ;
2020-03-12 11:16:48 +00:00
consume ( TokenType : : Let ) ;
break ;
2020-03-12 12:24:34 +00:00
case TokenType : : Const :
2020-04-08 09:59:18 +00:00
declaration_kind = DeclarationKind : : Const ;
2020-03-12 12:24:34 +00:00
consume ( TokenType : : Const ) ;
break ;
2020-03-12 11:16:48 +00:00
default :
ASSERT_NOT_REACHED ( ) ;
}
2020-04-04 19:46:25 +00:00
NonnullRefPtrVector < VariableDeclarator > declarations ;
for ( ; ; ) {
auto id = consume ( TokenType : : Identifier ) . value ( ) ;
RefPtr < Expression > init ;
if ( match ( TokenType : : Equals ) ) {
consume ( ) ;
init = parse_expression ( 0 ) ;
}
declarations . append ( create_ast_node < VariableDeclarator > ( create_ast_node < Identifier > ( move ( id ) ) , move ( init ) ) ) ;
if ( match ( TokenType : : Comma ) ) {
consume ( ) ;
continue ;
}
break ;
2020-03-11 18:27:43 +00:00
}
2020-04-17 13:05:58 +00:00
consume_or_insert_semicolon ( ) ;
2020-04-13 14:42:54 +00:00
auto declaration = create_ast_node < VariableDeclaration > ( declaration_kind , move ( declarations ) ) ;
if ( declaration - > declaration_kind ( ) = = DeclarationKind : : Var )
m_parser_state . m_var_scopes . last ( ) . append ( declaration ) ;
else
m_parser_state . m_let_scopes . last ( ) . append ( declaration ) ;
return declaration ;
2020-03-11 18:27:43 +00:00
}
2020-03-24 21:03:50 +00:00
NonnullRefPtr < ThrowStatement > Parser : : parse_throw_statement ( )
{
consume ( TokenType : : Throw ) ;
2020-04-17 13:05:58 +00:00
// Automatic semicolon insertion: terminate statement when throw is followed by newline
if ( m_parser_state . m_current_token . trivia ( ) . contains ( ' \n ' ) ) {
m_parser_state . m_has_errors = true ;
fprintf ( stderr , " Syntax Error: no line break is allowed between 'throw' and its expression \n " ) ;
return create_ast_node < ThrowStatement > ( create_ast_node < ErrorExpression > ( ) ) ;
}
auto expression = parse_expression ( 0 ) ;
consume_or_insert_semicolon ( ) ;
return create_ast_node < ThrowStatement > ( move ( expression ) ) ;
2020-03-24 21:03:50 +00:00
}
2020-03-29 11:09:54 +00:00
NonnullRefPtr < BreakStatement > Parser : : parse_break_statement ( )
{
consume ( TokenType : : Break ) ;
2020-04-17 13:05:58 +00:00
consume_or_insert_semicolon ( ) ;
// FIXME: Handle labels. When fixing this, take care to correctly implement semicolon insertion
2020-03-29 11:09:54 +00:00
return create_ast_node < BreakStatement > ( ) ;
}
2020-04-04 22:22:42 +00:00
NonnullRefPtr < ContinueStatement > Parser : : parse_continue_statement ( )
{
consume ( TokenType : : Continue ) ;
2020-04-17 13:05:58 +00:00
consume_or_insert_semicolon ( ) ;
// FIXME: Handle labels. When fixing this, take care to correctly implement semicolon insertion
2020-04-04 22:22:42 +00:00
return create_ast_node < ContinueStatement > ( ) ;
}
2020-04-03 10:14:28 +00:00
NonnullRefPtr < ConditionalExpression > Parser : : parse_conditional_expression ( NonnullRefPtr < Expression > test )
{
consume ( TokenType : : QuestionMark ) ;
auto consequent = parse_expression ( 0 ) ;
consume ( TokenType : : Colon ) ;
auto alternate = parse_expression ( 0 ) ;
return create_ast_node < ConditionalExpression > ( move ( test ) , move ( consequent ) , move ( alternate ) ) ;
}
2020-03-24 13:03:55 +00:00
NonnullRefPtr < TryStatement > Parser : : parse_try_statement ( )
{
consume ( TokenType : : Try ) ;
auto block = parse_block_statement ( ) ;
RefPtr < CatchClause > handler ;
if ( match ( TokenType : : Catch ) )
handler = parse_catch_clause ( ) ;
RefPtr < BlockStatement > finalizer ;
if ( match ( TokenType : : Finally ) ) {
consume ( ) ;
finalizer = parse_block_statement ( ) ;
}
return create_ast_node < TryStatement > ( move ( block ) , move ( handler ) , move ( finalizer ) ) ;
}
2020-04-04 19:29:23 +00:00
NonnullRefPtr < DoWhileStatement > Parser : : parse_do_while_statement ( )
{
consume ( TokenType : : Do ) ;
2020-04-05 14:57:01 +00:00
2020-04-04 19:29:23 +00:00
auto body = parse_statement ( ) ;
2020-04-05 14:57:01 +00:00
2020-04-04 19:29:23 +00:00
consume ( TokenType : : While ) ;
2020-04-05 14:57:01 +00:00
consume ( TokenType : : ParenOpen ) ;
2020-04-04 19:29:23 +00:00
auto test = parse_expression ( 0 ) ;
2020-04-05 14:57:01 +00:00
consume ( TokenType : : ParenClose ) ;
2020-04-17 13:05:58 +00:00
consume_or_insert_semicolon ( ) ;
2020-04-05 14:57:01 +00:00
2020-04-04 19:29:23 +00:00
return create_ast_node < DoWhileStatement > ( move ( test ) , move ( body ) ) ;
}
2020-04-21 18:27:57 +00:00
NonnullRefPtr < WhileStatement > Parser : : parse_while_statement ( )
{
consume ( TokenType : : While ) ;
consume ( TokenType : : ParenOpen ) ;
auto test = parse_expression ( 0 ) ;
consume ( TokenType : : ParenClose ) ;
auto body = parse_statement ( ) ;
return create_ast_node < WhileStatement > ( move ( test ) , move ( body ) ) ;
}
2020-03-29 11:09:54 +00:00
NonnullRefPtr < SwitchStatement > Parser : : parse_switch_statement ( )
{
consume ( TokenType : : Switch ) ;
consume ( TokenType : : ParenOpen ) ;
auto determinant = parse_expression ( 0 ) ;
consume ( TokenType : : ParenClose ) ;
consume ( TokenType : : CurlyOpen ) ;
NonnullRefPtrVector < SwitchCase > cases ;
while ( match ( TokenType : : Case ) | | match ( TokenType : : Default ) )
cases . append ( parse_switch_case ( ) ) ;
consume ( TokenType : : CurlyClose ) ;
return create_ast_node < SwitchStatement > ( move ( determinant ) , move ( cases ) ) ;
}
NonnullRefPtr < SwitchCase > Parser : : parse_switch_case ( )
{
RefPtr < Expression > test ;
if ( consume ( ) . type ( ) = = TokenType : : Case ) {
test = parse_expression ( 0 ) ;
}
consume ( TokenType : : Colon ) ;
NonnullRefPtrVector < Statement > consequent ;
while ( match_statement ( ) )
consequent . append ( parse_statement ( ) ) ;
return create_ast_node < SwitchCase > ( move ( test ) , move ( consequent ) ) ;
}
2020-03-24 13:03:55 +00:00
NonnullRefPtr < CatchClause > Parser : : parse_catch_clause ( )
{
consume ( TokenType : : Catch ) ;
String parameter ;
if ( match ( TokenType : : ParenOpen ) ) {
consume ( ) ;
parameter = consume ( TokenType : : Identifier ) . value ( ) ;
consume ( TokenType : : ParenClose ) ;
}
auto body = parse_block_statement ( ) ;
return create_ast_node < CatchClause > ( parameter , move ( body ) ) ;
}
2020-03-21 17:40:17 +00:00
NonnullRefPtr < IfStatement > Parser : : parse_if_statement ( )
{
consume ( TokenType : : If ) ;
consume ( TokenType : : ParenOpen ) ;
auto predicate = parse_expression ( 0 ) ;
consume ( TokenType : : ParenClose ) ;
2020-03-23 15:46:41 +00:00
auto consequent = parse_statement ( ) ;
RefPtr < Statement > alternate ;
if ( match ( TokenType : : Else ) ) {
consume ( TokenType : : Else ) ;
alternate = parse_statement ( ) ;
}
return create_ast_node < IfStatement > ( move ( predicate ) , move ( consequent ) , move ( alternate ) ) ;
2020-03-21 17:40:17 +00:00
}
2020-03-18 10:23:53 +00:00
NonnullRefPtr < ForStatement > Parser : : parse_for_statement ( )
2020-03-12 12:12:12 +00:00
{
consume ( TokenType : : For ) ;
consume ( TokenType : : ParenOpen ) ;
2020-04-17 13:05:58 +00:00
bool first_semicolon_consumed = false ;
2020-03-23 18:08:32 +00:00
RefPtr < ASTNode > init ;
2020-03-30 13:24:43 +00:00
switch ( m_parser_state . m_current_token . type ( ) ) {
2020-03-12 12:12:12 +00:00
case TokenType : : Semicolon :
break ;
default :
2020-04-17 13:05:58 +00:00
if ( match_expression ( ) ) {
2020-03-23 18:08:32 +00:00
init = parse_expression ( 0 ) ;
2020-04-17 13:05:58 +00:00
} else if ( match_variable_declaration ( ) ) {
2020-03-23 18:08:32 +00:00
init = parse_variable_declaration ( ) ;
2020-04-17 13:05:58 +00:00
first_semicolon_consumed = true ;
} else {
2020-03-23 18:08:32 +00:00
ASSERT_NOT_REACHED ( ) ;
2020-04-17 13:05:58 +00:00
}
2020-03-12 12:12:12 +00:00
break ;
}
2020-04-17 13:05:58 +00:00
if ( ! first_semicolon_consumed )
consume ( TokenType : : Semicolon ) ;
2020-03-12 12:12:12 +00:00
2020-03-18 10:23:53 +00:00
RefPtr < Expression > test ;
2020-03-30 13:24:43 +00:00
switch ( m_parser_state . m_current_token . type ( ) ) {
2020-03-12 12:12:12 +00:00
case TokenType : : Semicolon :
break ;
default :
2020-03-12 22:02:41 +00:00
test = parse_expression ( 0 ) ;
2020-03-12 12:12:12 +00:00
break ;
}
consume ( TokenType : : Semicolon ) ;
2020-03-18 10:23:53 +00:00
RefPtr < Expression > update ;
2020-03-30 13:24:43 +00:00
switch ( m_parser_state . m_current_token . type ( ) ) {
2020-03-25 15:14:18 +00:00
case TokenType : : ParenClose :
2020-03-12 12:12:12 +00:00
break ;
default :
2020-03-12 22:02:41 +00:00
update = parse_expression ( 0 ) ;
2020-03-12 12:12:12 +00:00
break ;
}
consume ( TokenType : : ParenClose ) ;
2020-04-04 19:09:06 +00:00
auto body = parse_statement ( ) ;
2020-03-12 12:12:12 +00:00
2020-03-18 10:23:53 +00:00
return create_ast_node < ForStatement > ( move ( init ) , move ( test ) , move ( update ) , move ( body ) ) ;
2020-03-12 12:12:12 +00:00
}
2020-03-11 18:27:43 +00:00
bool Parser : : match ( TokenType type ) const
{
2020-03-30 13:24:43 +00:00
return m_parser_state . m_current_token . type ( ) = = type ;
2020-03-11 18:27:43 +00:00
}
2020-03-23 18:08:32 +00:00
bool Parser : : match_variable_declaration ( ) const
{
2020-03-30 13:24:43 +00:00
switch ( m_parser_state . m_current_token . type ( ) ) {
2020-03-23 18:08:32 +00:00
case TokenType : : Var :
case TokenType : : Let :
case TokenType : : Const :
return true ;
default :
return false ;
}
}
2020-03-11 18:27:43 +00:00
bool Parser : : match_expression ( ) const
{
2020-03-30 13:24:43 +00:00
auto type = m_parser_state . m_current_token . type ( ) ;
2020-03-11 18:27:43 +00:00
return type = = TokenType : : BoolLiteral
| | type = = TokenType : : NumericLiteral
| | type = = TokenType : : StringLiteral
2020-04-23 23:20:02 +00:00
| | type = = TokenType : : TemplateLiteral
2020-03-11 18:27:43 +00:00
| | type = = TokenType : : NullLiteral
| | type = = TokenType : : Identifier
| | type = = TokenType : : New
| | type = = TokenType : : CurlyOpen
| | type = = TokenType : : BracketOpen
2020-03-14 18:45:51 +00:00
| | type = = TokenType : : ParenOpen
2020-03-19 10:52:56 +00:00
| | type = = TokenType : : Function
2020-04-12 22:42:14 +00:00
| | type = = TokenType : : This
2020-03-14 18:45:51 +00:00
| | match_unary_prefixed_expression ( ) ;
}
bool Parser : : match_unary_prefixed_expression ( ) const
{
2020-03-30 13:24:43 +00:00
auto type = m_parser_state . m_current_token . type ( ) ;
2020-03-14 18:45:51 +00:00
return type = = TokenType : : PlusPlus
| | type = = TokenType : : MinusMinus
| | type = = TokenType : : ExclamationMark
2020-03-17 19:33:32 +00:00
| | type = = TokenType : : Tilde
2020-04-02 16:58:39 +00:00
| | type = = TokenType : : Plus
| | type = = TokenType : : Minus
2020-04-15 16:55:03 +00:00
| | type = = TokenType : : Typeof
| | type = = TokenType : : Void ;
2020-03-11 18:27:43 +00:00
}
bool Parser : : match_secondary_expression ( ) const
{
2020-03-30 13:24:43 +00:00
auto type = m_parser_state . m_current_token . type ( ) ;
2020-03-11 18:27:43 +00:00
return type = = TokenType : : Plus
2020-03-12 12:09:15 +00:00
| | type = = TokenType : : PlusEquals
2020-03-11 18:27:43 +00:00
| | type = = TokenType : : Minus
2020-03-12 12:09:15 +00:00
| | type = = TokenType : : MinusEquals
2020-03-11 18:27:43 +00:00
| | type = = TokenType : : Asterisk
2020-03-12 12:09:15 +00:00
| | type = = TokenType : : AsteriskEquals
2020-03-11 18:27:43 +00:00
| | type = = TokenType : : Slash
2020-03-12 12:09:15 +00:00
| | type = = TokenType : : SlashEquals
2020-04-04 19:17:34 +00:00
| | type = = TokenType : : Percent
2020-04-05 12:40:00 +00:00
| | type = = TokenType : : DoubleAsterisk
2020-03-11 18:27:43 +00:00
| | type = = TokenType : : Equals
2020-03-12 12:11:33 +00:00
| | type = = TokenType : : EqualsEqualsEquals
| | type = = TokenType : : ExclamationMarkEqualsEquals
2020-03-15 22:23:38 +00:00
| | type = = TokenType : : EqualsEquals
| | type = = TokenType : : ExclamationMarkEquals
2020-03-12 12:10:27 +00:00
| | type = = TokenType : : GreaterThan
2020-03-12 12:07:08 +00:00
| | type = = TokenType : : GreaterThanEquals
2020-03-12 12:10:27 +00:00
| | type = = TokenType : : LessThan
2020-03-12 12:07:08 +00:00
| | type = = TokenType : : LessThanEquals
2020-03-12 12:05:57 +00:00
| | type = = TokenType : : ParenOpen
2020-03-12 11:45:45 +00:00
| | type = = TokenType : : Period
2020-03-20 19:51:03 +00:00
| | type = = TokenType : : BracketOpen
2020-03-12 11:45:45 +00:00
| | type = = TokenType : : PlusPlus
2020-03-28 15:56:54 +00:00
| | type = = TokenType : : MinusMinus
2020-04-23 15:06:01 +00:00
| | type = = TokenType : : In
2020-04-03 10:14:28 +00:00
| | type = = TokenType : : Instanceof
2020-04-03 12:02:31 +00:00
| | type = = TokenType : : QuestionMark
| | type = = TokenType : : Ampersand
| | type = = TokenType : : Pipe
2020-04-03 13:33:28 +00:00
| | type = = TokenType : : Caret
2020-04-23 12:36:14 +00:00
| | type = = TokenType : : ShiftLeft
| | type = = TokenType : : ShiftLeftEquals
2020-04-23 12:45:19 +00:00
| | type = = TokenType : : ShiftRight
| | type = = TokenType : : ShiftRightEquals
2020-04-23 14:43:10 +00:00
| | type = = TokenType : : UnsignedShiftRight
| | type = = TokenType : : UnsignedShiftRightEquals
2020-04-03 13:33:28 +00:00
| | type = = TokenType : : DoubleAmpersand
2020-04-17 23:49:11 +00:00
| | type = = TokenType : : DoublePipe
| | type = = TokenType : : DoubleQuestionMark ;
2020-03-11 18:27:43 +00:00
}
bool Parser : : match_statement ( ) const
{
2020-03-30 13:24:43 +00:00
auto type = m_parser_state . m_current_token . type ( ) ;
2020-03-11 18:27:43 +00:00
return match_expression ( )
| | type = = TokenType : : Function
| | type = = TokenType : : Return
| | type = = TokenType : : Let
| | type = = TokenType : : Class
| | type = = TokenType : : Delete
| | type = = TokenType : : Do
| | type = = TokenType : : If
2020-03-24 21:03:50 +00:00
| | type = = TokenType : : Throw
2020-03-11 18:27:43 +00:00
| | type = = TokenType : : Try
| | type = = TokenType : : While
2020-03-12 12:12:12 +00:00
| | type = = TokenType : : For
2020-03-11 18:27:43 +00:00
| | type = = TokenType : : Const
| | type = = TokenType : : CurlyOpen
2020-03-29 11:09:54 +00:00
| | type = = TokenType : : Switch
| | type = = TokenType : : Break
2020-04-04 22:22:42 +00:00
| | type = = TokenType : : Continue
2020-03-11 18:27:43 +00:00
| | type = = TokenType : : Var ;
}
2020-04-18 18:31:27 +00:00
bool Parser : : match_identifier_name ( ) const
{
return m_parser_state . m_current_token . is_identifier_name ( ) ;
}
2020-03-11 18:27:43 +00:00
bool Parser : : done ( ) const
{
return match ( TokenType : : Eof ) ;
}
Token Parser : : consume ( )
{
2020-03-30 13:24:43 +00:00
auto old_token = m_parser_state . m_current_token ;
m_parser_state . m_current_token = m_parser_state . m_lexer . next ( ) ;
2020-03-12 22:02:41 +00:00
return old_token ;
2020-03-11 18:27:43 +00:00
}
2020-04-17 13:05:58 +00:00
void Parser : : consume_or_insert_semicolon ( )
2020-03-11 18:27:43 +00:00
{
2020-04-17 13:05:58 +00:00
// Semicolon was found and will be consumed
if ( match ( TokenType : : Semicolon ) ) {
consume ( ) ;
return ;
}
// Insert semicolon if...
// ...token is preceeded by one or more newlines
if ( m_parser_state . m_current_token . trivia ( ) . contains ( ' \n ' ) )
return ;
2020-04-17 13:27:51 +00:00
// ...token is a closing curly brace
if ( match ( TokenType : : CurlyClose ) )
2020-04-17 13:05:58 +00:00
return ;
// ...token is eof
if ( match ( TokenType : : Eof ) )
return ;
// No rule for semicolon insertion applies -> syntax error
expected ( " Semicolon " ) ;
}
Token Parser : : consume ( TokenType expected_type )
{
if ( m_parser_state . m_current_token . type ( ) ! = expected_type ) {
expected ( Token : : name ( expected_type ) ) ;
2020-03-11 18:27:43 +00:00
}
return consume ( ) ;
}
void Parser : : expected ( const char * what )
{
2020-03-30 13:24:43 +00:00
m_parser_state . m_has_errors = true ;
2020-04-05 09:34:03 +00:00
auto & current_token = m_parser_state . m_current_token ;
2020-04-17 13:05:58 +00:00
fprintf ( stderr , " Syntax Error: Unexpected token %s. Expected %s (line: %zu, column: %zu) \n " ,
2020-04-12 22:42:14 +00:00
current_token . name ( ) ,
what ,
current_token . line_number ( ) ,
current_token . line_column ( ) ) ;
2020-03-11 18:27:43 +00:00
}
2020-03-30 13:24:43 +00:00
void Parser : : save_state ( )
{
m_saved_state = m_parser_state ;
}
void Parser : : load_state ( )
{
ASSERT ( m_saved_state . has_value ( ) ) ;
m_parser_state = m_saved_state . value ( ) ;
m_saved_state . clear ( ) ;
}
2020-03-11 18:27:43 +00:00
}