You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
754 lines
14 KiB
754 lines
14 KiB
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
%{
|
|
open JSourceAST
|
|
|
|
let location_of_pos pos =
|
|
let line = pos.Lexing.pos_lnum in
|
|
let col = pos.Lexing.pos_cnum - pos.Lexing.pos_bol in
|
|
{ line; col }
|
|
|
|
%}
|
|
|
|
%token PACKAGE
|
|
%token IMPORT
|
|
%token CLASS
|
|
%token INTERFACE
|
|
%token IMPLEMENTS
|
|
%token EXTENDS
|
|
%token ENUM
|
|
%token NEW
|
|
%token INSTANCEOF
|
|
%token VOID
|
|
%token THROWS
|
|
%token VAR
|
|
%token ASSERT
|
|
%token DO
|
|
%token WHILE
|
|
%token IF
|
|
%token ELSE
|
|
%token TRY
|
|
%token CATCH
|
|
%token FINALLY
|
|
%token FOR
|
|
%token BREAK
|
|
%token CONTINUE
|
|
%token RETURN
|
|
%token THROW
|
|
%token SYNCHRONIZED
|
|
%token YIELD
|
|
%token THIS
|
|
%token NULL
|
|
%token TRUE
|
|
%token FALSE
|
|
|
|
|
|
//non Java terminals
|
|
%token PRIMTYPE
|
|
|
|
%token LBRACKET
|
|
%token RBRACKET
|
|
%token LSBRACKET
|
|
%token RSBRACKET
|
|
%token LPAREN
|
|
%token RPAREN
|
|
%token LANGLE
|
|
%token RANGLE
|
|
|
|
%token EQ
|
|
%token ASSIGNOP
|
|
%token SEMICOLON
|
|
%token COLON
|
|
%token COMMA
|
|
%token DOT
|
|
%token QMARK
|
|
%token BANG
|
|
%token TILDE
|
|
%token PIPE
|
|
|
|
%token INCR_DECR
|
|
%token THREEDOTS
|
|
|
|
%token EOF
|
|
|
|
%token <string> IDENT
|
|
%token <string> INTEGER
|
|
%token <string> FLOATINGPOINT
|
|
%token <string> STRING
|
|
%token <string> CHAR
|
|
|
|
%token BINOP
|
|
|
|
%left BINOP LANGLE RANGLE
|
|
%nonassoc INSTANCEOF
|
|
|
|
%start <JSourceAST.file_content> main
|
|
|
|
%%
|
|
|
|
main:
|
|
| package_declaration? import_declaration* app_list(type_declaration) EOF
|
|
{ { package = $1; classes = $3 } }
|
|
|
|
import_declaration:
|
|
| IMPORT import_name SEMICOLON
|
|
{}
|
|
|
|
import_name:
|
|
| IDENT import_name_end
|
|
{}
|
|
import_name_end:
|
|
|
|
|
| DOT BINOP
|
|
| DOT IDENT import_name_end
|
|
{}
|
|
|
|
package_declaration:
|
|
| PACKAGE unann_class_or_interface_type SEMICOLON
|
|
{ $2 }
|
|
|
|
type_declaration:
|
|
| class_declaration
|
|
| interface_declaration
|
|
{ [$1] }
|
|
| SEMICOLON
|
|
{ [] }
|
|
|
|
class_declaration:
|
|
| normal_class_declaration
|
|
| enum_declaration
|
|
{ $1 }
|
|
|
|
normal_class_declaration:
|
|
| CLASS id=identifier superclass? superinterfaces? inner=class_body
|
|
{ {
|
|
location = location_of_pos $startpos(id);
|
|
kind = Class id;
|
|
inner_elements = inner;
|
|
}
|
|
}
|
|
|
|
enum_declaration:
|
|
| ENUM id=identifier superinterfaces? inner=enum_body
|
|
{ {
|
|
location = location_of_pos $startpos(id);
|
|
kind = Enum id;
|
|
inner_elements = inner;
|
|
}
|
|
}
|
|
|
|
superclass:
|
|
| EXTENDS class_type
|
|
{}
|
|
|
|
superinterfaces:
|
|
| IMPLEMENTS separated_nonempty_list(COMMA, class_type)
|
|
{}
|
|
|
|
enum_body:
|
|
| LBRACKET enum_constant_list RBRACKET // TODO add optional comma
|
|
{ [] }
|
|
| LBRACKET enum_constant_list inner=enum_body_declarations RBRACKET
|
|
{ inner }
|
|
|
|
enum_constant_list:
|
|
| separated_nonempty_list(COMMA, enum_constant)
|
|
{}
|
|
|
|
enum_constant:
|
|
| identifier class_body?
|
|
| identifier LPAREN argument_list? RPAREN class_body?
|
|
{}
|
|
|
|
enum_body_declarations:
|
|
| SEMICOLON app_list(class_body_declaration)
|
|
{ $2 }
|
|
|
|
class_body:
|
|
| LBRACKET app_list(class_body_declaration) RBRACKET
|
|
{ $2 }
|
|
|
|
class_body_declaration:
|
|
| class_member_declaration
|
|
{ $1 }
|
|
| constructor_declaration
|
|
{ $1 }
|
|
|
|
constructor_declaration:
|
|
| constructor_declarator throws? inner=constructor_body
|
|
{ inner }
|
|
|
|
constructor_declarator:
|
|
| identifier LPAREN formal_parameter_list RPAREN // TODO add receive_parameter
|
|
{}
|
|
|
|
constructor_body:
|
|
| LBRACKET inner=loption(block_statements) RBRACKET
|
|
{ inner }
|
|
|
|
argument_list:
|
|
| app_separated_non_empty_list(COMMA, expression)
|
|
{ $1 }
|
|
|
|
class_member_declaration:
|
|
| class_declaration
|
|
| interface_declaration
|
|
{ [$1] }
|
|
| field_declaration
|
|
| method_declaration
|
|
{ $1 }
|
|
| SEMICOLON
|
|
{ [] }
|
|
|
|
method_declaration:
|
|
| method_header method_body
|
|
{ $2 }
|
|
|
|
interface_declaration:
|
|
| normal_interface_declaration
|
|
{ $1 }
|
|
|
|
normal_interface_declaration:
|
|
| INTERFACE id=identifier inner=interface_body
|
|
{ {
|
|
location = location_of_pos $startpos(id);
|
|
kind = Interface id;
|
|
inner_elements = inner;
|
|
}
|
|
}
|
|
|
|
interface_body:
|
|
| LBRACKET app_list(interface_member_declaration) RBRACKET
|
|
{ $2 }
|
|
|
|
interface_member_declaration:
|
|
| constant_declaration
|
|
| interface_method_declaration
|
|
{ [] }
|
|
| class_declaration
|
|
| interface_declaration
|
|
{ [$1] }
|
|
|
|
interface_method_declaration:
|
|
| method_header method_body
|
|
{}
|
|
|
|
method_header:
|
|
| result method_declarator throws?
|
|
{}
|
|
|
|
%inline
|
|
result:
|
|
| unann_type
|
|
| VOID
|
|
{}
|
|
|
|
method_declarator:
|
|
| identifier LPAREN formal_parameter_list RPAREN dims? //TODO add receiver_parameter
|
|
{}
|
|
|
|
formal_parameter_list:
|
|
| separated_list(COMMA, formal_parameter)
|
|
{}
|
|
|
|
formal_parameter:
|
|
| unann_type variable_declarator_id
|
|
| variable_arity_parameter
|
|
{}
|
|
|
|
variable_arity_parameter:
|
|
| unann_type THREEDOTS identifier
|
|
{}
|
|
|
|
method_body:
|
|
| block
|
|
{ $1 }
|
|
| SEMICOLON
|
|
{ [] }
|
|
|
|
block:
|
|
| LBRACKET loption(block_statements) RBRACKET
|
|
{ $2 }
|
|
|
|
block_statements:
|
|
| app_non_empty_list(block_statement)
|
|
{ $1 }
|
|
|
|
block_statement:
|
|
| class_declaration
|
|
{ [$1] }
|
|
| local_variable_declaration_statement
|
|
| statement
|
|
{ $1 }
|
|
|
|
local_variable_declaration_statement:
|
|
| local_variable_declaration SEMICOLON
|
|
{ $1 }
|
|
|
|
local_variable_declaration:
|
|
| local_variable_type variable_declarator_list
|
|
{ $2 }
|
|
|
|
local_variable_type:
|
|
| unann_type
|
|
| VAR
|
|
{}
|
|
|
|
statement:
|
|
| statement_without_trailing_substatement
|
|
// TODO: add labeled_statement
|
|
| if_then_statement
|
|
| if_then_else_statement
|
|
| while_statement
|
|
| for_statement
|
|
{ $1 }
|
|
|
|
for_statement:
|
|
| basic_for_statement
|
|
| enhanced_for_statement
|
|
{ $1 }
|
|
|
|
for_statement_no_short_if:
|
|
| basic_for_statement_no_short_if
|
|
| enhanced_for_statement_no_short_if
|
|
{ $1 }
|
|
|
|
basic_for_statement:
|
|
| FOR LPAREN loption(for_init) SEMICOLON loption(expression) SEMICOLON loption(for_update) RPAREN statement
|
|
{ $3 @ $5 @ $7 @ $9 }
|
|
|
|
enhanced_for_statement:
|
|
| FOR LPAREN local_variable_type variable_declarator_id COLON expression RPAREN statement
|
|
{ $6 @ $8 }
|
|
|
|
enhanced_for_statement_no_short_if:
|
|
| FOR LPAREN local_variable_type variable_declarator_id COLON expression RPAREN statement_no_short_if
|
|
{ $6 @ $8 }
|
|
|
|
basic_for_statement_no_short_if:
|
|
| FOR LPAREN loption(for_init) SEMICOLON loption(expression) SEMICOLON loption(for_update) RPAREN statement_no_short_if
|
|
{ $3 @ $5 @ $7 @ $9 }
|
|
|
|
for_init:
|
|
| statement_expression_list
|
|
| local_variable_declaration
|
|
{ $1 }
|
|
|
|
for_update:
|
|
| statement_expression_list
|
|
{ $1 }
|
|
|
|
statement_expression_list:
|
|
| app_separated_non_empty_list(COMMA, statement_expression)
|
|
{ $1 }
|
|
|
|
if_then_statement:
|
|
| IF LPAREN expression RPAREN statement
|
|
{ $3 @ $5 }
|
|
|
|
if_then_else_statement:
|
|
| IF LPAREN expression RPAREN statement_no_short_if ELSE statement
|
|
{ $3 @ $5 @ $7 }
|
|
|
|
if_then_else_statement_no_short_if:
|
|
| IF LPAREN expression RPAREN statement_no_short_if ELSE statement_no_short_if
|
|
{ $3 @ $5 @ $7 }
|
|
|
|
statement_no_short_if:
|
|
| statement_without_trailing_substatement
|
|
| if_then_else_statement_no_short_if
|
|
| while_statement_no_short_if
|
|
| for_statement_no_short_if
|
|
{ $1 }
|
|
|
|
while_statement:
|
|
| WHILE LPAREN expression RPAREN statement
|
|
{ $3 @ $5 }
|
|
|
|
while_statement_no_short_if:
|
|
| WHILE LPAREN expression RPAREN statement_no_short_if
|
|
{ $3 @ $5 }
|
|
|
|
statement_without_trailing_substatement:
|
|
| block
|
|
| empty_statement
|
|
| expression_statement
|
|
| assert_statement
|
|
| do_statement
|
|
| break_statement
|
|
| continue_statement
|
|
| return_statement
|
|
| synchronized_statement
|
|
| throw_statement
|
|
| try_statement
|
|
| yield_statement
|
|
{ $1 }
|
|
|
|
empty_statement:
|
|
| SEMICOLON
|
|
{ [] }
|
|
|
|
expression_statement:
|
|
| statement_expression SEMICOLON
|
|
{ $1 }
|
|
|
|
statement_expression:
|
|
| INCR_DECR unary_expression
|
|
{ $2 }
|
|
| assignment
|
|
| postfix_expression INCR_DECR
|
|
| method_invocation
|
|
| class_instance_creation_expression
|
|
{ $1 }
|
|
|
|
assert_statement:
|
|
| ASSERT expression SEMICOLON
|
|
{ $2 }
|
|
| ASSERT expression COLON expression SEMICOLON
|
|
{ $2 @ $4 }
|
|
|
|
do_statement:
|
|
| DO statement WHILE LPAREN expression RPAREN SEMICOLON
|
|
{ $2 @ $5 }
|
|
|
|
break_statement:
|
|
| BREAK identifier? SEMICOLON
|
|
{ [] }
|
|
|
|
continue_statement:
|
|
| CONTINUE identifier? SEMICOLON
|
|
{ [] }
|
|
|
|
return_statement:
|
|
| RETURN loption(expression) SEMICOLON
|
|
{ $2 }
|
|
|
|
synchronized_statement:
|
|
| SYNCHRONIZED LPAREN expression RPAREN block
|
|
{ $3 }
|
|
|
|
try_statement:
|
|
| TRY block catches
|
|
{ $2 @ $3 }
|
|
| TRY block loption(catches) finally
|
|
{ $2 @ $3 @ $4 }
|
|
|
|
catches:
|
|
| app_non_empty_list(catch_clause)
|
|
{ $1 }
|
|
|
|
catch_clause:
|
|
| CATCH LPAREN catch_formal_parameter RPAREN block
|
|
{ $5 }
|
|
|
|
catch_formal_parameter:
|
|
| catch_type variable_declarator_id
|
|
{}
|
|
|
|
catch_type:
|
|
| separated_nonempty_list(PIPE,unann_class_or_interface_type)
|
|
{}
|
|
|
|
finally:
|
|
| FINALLY block
|
|
{ $2 }
|
|
|
|
yield_statement:
|
|
| YIELD expression SEMICOLON
|
|
{ $2 }
|
|
|
|
throw_statement:
|
|
| THROW expression SEMICOLON
|
|
{ $2 }
|
|
|
|
throws:
|
|
| THROWS exception_type_list
|
|
{ $2 }
|
|
|
|
exception_type_list:
|
|
| separated_nonempty_list(COMMA, exception_type)
|
|
{ [] }
|
|
|
|
exception_type:
|
|
| unann_class_or_interface_type // WE DROP ANNOTS
|
|
{ [] }
|
|
|
|
constant_declaration:
|
|
| unann_type variable_declarator_list SEMICOLON
|
|
{ $2 }
|
|
|
|
field_declaration:
|
|
| unann_type variable_declarator_list SEMICOLON
|
|
{ $2 }
|
|
|
|
variable_declarator_list:
|
|
| app_separated_non_empty_list(COMMA,variable_declarator)
|
|
{ $1 }
|
|
|
|
variable_declarator:
|
|
| variable_declarator_id
|
|
{ [] }
|
|
| variable_declarator_id EQ variable_initializer
|
|
{ $3 }
|
|
|
|
variable_declarator_id:
|
|
| identifier dims?
|
|
{}
|
|
|
|
variable_initializer:
|
|
| expression
|
|
| array_initializer
|
|
{ $1 }
|
|
|
|
array_initializer:
|
|
| LBRACKET RBRACKET
|
|
| LBRACKET COMMA RBRACKET
|
|
{ [] }
|
|
| LBRACKET variable_initializer array_initializer_end
|
|
{ $2 @ $3 }
|
|
|
|
array_initializer_end:
|
|
| RBRACKET
|
|
| COMMA RBRACKET
|
|
{ [] }
|
|
| COMMA variable_initializer array_initializer_end
|
|
{ $2 @ $3 }
|
|
|
|
unann_type:
|
|
| PRIMTYPE
|
|
| unann_reference_type
|
|
{}
|
|
|
|
unann_reference_type:
|
|
| unann_class_or_interface_type
|
|
| unann_array_type
|
|
{}
|
|
|
|
dotted_name:
|
|
| identifier
|
|
{ $1 }
|
|
| identifier DOT dotted_name
|
|
{ $1 ^ "." ^ $3 }
|
|
// | package_opt? separated_nonempty_list(DOT, IDENT)
|
|
// don't know how to write Java programs like that
|
|
|
|
%inline
|
|
unann_class_or_interface_type:
|
|
| dotted_name { $1 }
|
|
%inline
|
|
class_type:
|
|
| dotted_name { $1 }
|
|
%inline
|
|
class_or_interface_type_to_instantiate:
|
|
| dotted_name { $1 }
|
|
%inline
|
|
expression_name:
|
|
| dotted_name { $1 }
|
|
|
|
unann_array_type:
|
|
| PRIMTYPE dims
|
|
| unann_class_or_interface_type dims
|
|
{}
|
|
|
|
%inline dim:
|
|
| LSBRACKET RSBRACKET
|
|
{}
|
|
dims:
|
|
| dim+
|
|
{}
|
|
|
|
expression:
|
|
| assignment_expression
|
|
{ $1 }
|
|
|
|
assignment_expression:
|
|
| conditional_expression
|
|
| assignment
|
|
{ $1 }
|
|
|
|
assignment:
|
|
| left_hand_side assignment_operator expression
|
|
{ $1 @ $3 }
|
|
|
|
assignment_operator:
|
|
| EQ
|
|
| ASSIGNOP
|
|
{}
|
|
|
|
left_hand_side:
|
|
| expression_name
|
|
{ [] }
|
|
| field_access
|
|
| array_access
|
|
{ $1 }
|
|
|
|
field_access:
|
|
| primary DOT identifier
|
|
{ $1 }
|
|
|
|
array_access:
|
|
| expression_name LSBRACKET expression RSBRACKET
|
|
{ $3 }
|
|
| primary_no_new_array LSBRACKET expression RSBRACKET
|
|
{ $1 @ $3 }
|
|
|
|
primary:
|
|
| primary_no_new_array
|
|
| array_creation_expression
|
|
{ $1 }
|
|
|
|
array_creation_expression:
|
|
| NEW PRIMTYPE dim_exprs
|
|
| NEW class_type dim_exprs
|
|
{ $3 }
|
|
| NEW PRIMTYPE dims array_initializer
|
|
| NEW class_type dims array_initializer
|
|
{ $4 }
|
|
|
|
dim_exprs:
|
|
| app_non_empty_list(dim_expr)
|
|
{ $1 }
|
|
|
|
dim_expr:
|
|
| LSBRACKET expression RSBRACKET
|
|
{ $2 }
|
|
|
|
primary_no_new_array:
|
|
| LPAREN expression RPAREN
|
|
{ $2 }
|
|
| literal
|
|
| class_literal
|
|
| THIS
|
|
{ [] }
|
|
| class_instance_creation_expression
|
|
| field_access
|
|
| array_access
|
|
| method_invocation
|
|
{ $1 }
|
|
|
|
method_invocation:
|
|
| expression_name LPAREN loption(argument_list) RPAREN
|
|
{ $3 }
|
|
| primary DOT identifier LPAREN loption(argument_list) RPAREN
|
|
{ $1 @ $5 }
|
|
|
|
literal:
|
|
| INTEGER
|
|
| FLOATINGPOINT
|
|
| boolean
|
|
| CHAR
|
|
| STRING
|
|
| NULL
|
|
{}
|
|
|
|
boolean:
|
|
| TRUE
|
|
| FALSE
|
|
{}
|
|
|
|
class_literal:
|
|
| type_name DOT CLASS
|
|
{}
|
|
|
|
%inline
|
|
identifier:
|
|
| id=IDENT { id }
|
|
|
|
%inline
|
|
type_name:
|
|
| IDENT
|
|
{}
|
|
|
|
class_instance_creation_expression:
|
|
| unqualified_class_instance_creation_expression
|
|
{ $1 }
|
|
| identifier DOT unqualified_class_instance_creation_expression
|
|
{ $3 }
|
|
| primary DOT unqualified_class_instance_creation_expression
|
|
{ $1 @ $3 }
|
|
|
|
%inline
|
|
unqualified_class_instance_creation_expression:
|
|
| NEW class_or_interface_type_to_instantiate LPAREN loption(argument_list) RPAREN
|
|
{ $4 }
|
|
| NEW class_or_interface_type_to_instantiate LPAREN args=loption(argument_list) RPAREN inner=class_body
|
|
{ args @
|
|
[{
|
|
location = location_of_pos $startpos(inner);
|
|
kind = AnonymousClass;
|
|
inner_elements = inner;
|
|
}]
|
|
}
|
|
|
|
conditional_expression:
|
|
| conditional_or_expression
|
|
{ $1 }
|
|
| conditional_or_expression QMARK expression COLON conditional_expression
|
|
{ $1 @ $3 @ $5 }
|
|
|
|
// we simpify official spec and merge many rules here
|
|
conditional_or_expression:
|
|
| conditional_or_expression binop conditional_or_expression
|
|
{ $1 @ $3 }
|
|
| conditional_or_expression INSTANCEOF unann_reference_type // WE DROP ANNOTS
|
|
| unary_expression
|
|
{ $1 }
|
|
|
|
%inline
|
|
binop:
|
|
| BINOP | RANGLE | LANGLE
|
|
{}
|
|
|
|
unary_expression:
|
|
| INCR_DECR unary_expression
|
|
| BINOP unary_expression
|
|
{ $2 }
|
|
| unary_expression_not_plus_minus
|
|
{ $1 }
|
|
|
|
|
|
unary_expression_not_plus_minus:
|
|
| postfix_expression
|
|
| cast_expression
|
|
{ $1 }
|
|
| BANG unary_expression
|
|
| TILDE unary_expression
|
|
{ $2 }
|
|
|
|
%inline
|
|
cast_expression:
|
|
| LPAREN PRIMTYPE RPAREN unary_expression
|
|
{ $4 }
|
|
|
|
postfix_expression:
|
|
| primary
|
|
{ $1 }
|
|
| expression_name
|
|
{ [] }
|
|
| postfix_expression INCR_DECR
|
|
{ $1 }
|
|
|
|
//speciazed version of Menhir macros using concatenation
|
|
app_list(X):
|
|
{ [] }
|
|
| x = X; xs = app_list(X)
|
|
{ x@xs }
|
|
|
|
app_non_empty_list(X):
|
|
| x = X; xs = app_list(X)
|
|
{ x@xs }
|
|
|
|
app_separated_list(SEP,X):
|
|
xs = loption(app_separated_non_empty_list(SEP,X))
|
|
{ xs }
|
|
|
|
app_separated_non_empty_list(SEP,X):
|
|
x = X
|
|
{ x }
|
|
| x = X; SEP; xs = app_separated_non_empty_list(SEP,X)
|
|
{ x@xs }
|