Summary: The current source parser is based on ocamllex only. In order to track field declaration locations, we propose a new parser using ocamllex/menhir. This is a more ambitious project that closely follows the official Java syntax. Reviewed By: jvillard Differential Revision: D24858280 fbshipit-source-id: 22d6766e5master
parent
02625ac1ce
commit
2f09b39f56
@ -0,0 +1,43 @@
|
|||||||
|
(*
|
||||||
|
* 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! IStd
|
||||||
|
|
||||||
|
type location = {line: int; col: int}
|
||||||
|
|
||||||
|
type class_kind = Class of string | Interface of string | AnonymousClass | Enum of string
|
||||||
|
|
||||||
|
type class_or_interface =
|
||||||
|
{location: location; kind: class_kind; inner_elements: class_or_interface list}
|
||||||
|
|
||||||
|
type file_content = {package: string option; classes: class_or_interface list}
|
||||||
|
|
||||||
|
type context = {prefix: string; mutable counter: int}
|
||||||
|
|
||||||
|
let name_of_kind context = function
|
||||||
|
| Class id | Interface id | Enum id ->
|
||||||
|
id
|
||||||
|
| AnonymousClass ->
|
||||||
|
context.counter <- context.counter + 1 ;
|
||||||
|
string_of_int context.counter
|
||||||
|
|
||||||
|
|
||||||
|
let rec iter ~action_on_class_location context {location; kind; inner_elements} =
|
||||||
|
let previous_prefix = context.prefix in
|
||||||
|
let name = name_of_kind context kind in
|
||||||
|
let context = {prefix= Printf.sprintf "%s%s$" context.prefix name; counter= 0} in
|
||||||
|
let classname = previous_prefix ^ name in
|
||||||
|
let col = location.col in
|
||||||
|
let line = location.line in
|
||||||
|
let _ = action_on_class_location ~classname ~col ~line in
|
||||||
|
List.iter inner_elements ~f:(iter ~action_on_class_location context)
|
||||||
|
|
||||||
|
|
||||||
|
let iter_on_declarations ~action_on_class_location {package; classes} =
|
||||||
|
let prefix = Option.fold ~init:"" ~f:(fun _ s -> s ^ ".") package in
|
||||||
|
let context = {prefix; counter= 0} in
|
||||||
|
List.iter classes ~f:(iter ~action_on_class_location context)
|
@ -0,0 +1,20 @@
|
|||||||
|
(*
|
||||||
|
* 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! IStd
|
||||||
|
|
||||||
|
type location = {line: int; col: int}
|
||||||
|
|
||||||
|
type class_kind = Class of string | Interface of string | AnonymousClass | Enum of string
|
||||||
|
|
||||||
|
type class_or_interface =
|
||||||
|
{location: location; kind: class_kind; inner_elements: class_or_interface list}
|
||||||
|
|
||||||
|
type file_content = {package: string option; classes: class_or_interface list}
|
||||||
|
|
||||||
|
val iter_on_declarations :
|
||||||
|
action_on_class_location:(classname:string -> col:int -> line:int -> unit) -> file_content -> unit
|
@ -0,0 +1,244 @@
|
|||||||
|
(*
|
||||||
|
* 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.
|
||||||
|
*)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
(** classic Ocamllex function to update current lexbuf line at each end of
|
||||||
|
line *)
|
||||||
|
let incr_linenum lexbuf =
|
||||||
|
let pos = lexbuf.Lexing.lex_curr_p in
|
||||||
|
lexbuf.Lexing.lex_curr_p <- { pos with
|
||||||
|
Lexing.pos_lnum = pos.Lexing.pos_lnum + 1;
|
||||||
|
Lexing.pos_bol = pos.Lexing.pos_cnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
open JSourceParser
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
let whitespace = [' ' '\t']
|
||||||
|
let eol = whitespace*("\r")?"\n" (* end of line *)
|
||||||
|
let eol_comment = "//" [^'\n']*
|
||||||
|
let id = ['a'-'z' 'A'-'Z' '_' '$'] ['a'-'z' 'A'-'Z' '0'-'9' '_' '$']*
|
||||||
|
let char = "'\\''" | "'\"'" | "'" [ ^'\'' ]+ "'"
|
||||||
|
let modifier = "public"|"protected"|"private"|"abstract"|"static"|
|
||||||
|
"final"|"strictfp"|"transient"|"volatile"
|
||||||
|
let numeric_type = "byte"|"short"|"int"|"long"|"char"|"float"|"double"
|
||||||
|
let primitive_type = "boolean"|numeric_type
|
||||||
|
let assignment_operator = "*="|"/="|"%="|"+="|"-="|"<<="|">>="|">>>="|"&="|"^="|"|="
|
||||||
|
let binop = "||"|"&&"|"&"|"^"|"=="|"!="|"<="|">="|"<<"|">>"|">>>"|"+"|"-"|"*"|"/"|"%"
|
||||||
|
|
||||||
|
let binary_numeral_prefix = "0" ("b"|"B")
|
||||||
|
let hex_numeral_prefix = "0" ("x"|"X")
|
||||||
|
let numeral_prefix = ['0'-'9'] | binary_numeral_prefix | hex_numeral_prefix
|
||||||
|
let numeral_digit = ['0'-'9' 'a'-'f' 'A'-'F' '_']
|
||||||
|
let integer_literal = numeral_prefix numeral_digit* ['l' 'L']?
|
||||||
|
let hexadecimal_floating_point_literal = hex_numeral_prefix (numeral_digit | ".")+ ("p"|"P")
|
||||||
|
let decimal_floating_point_literal = hex_numeral_prefix (numeral_digit | ".")+ ("p"|"P")
|
||||||
|
let digits = ['0'-'9']+
|
||||||
|
let float_type_suffix = ['f' 'F' 'd' 'D']
|
||||||
|
let exponent_part = ['e' 'E'] ['-' '+']? digits
|
||||||
|
let floating_point_literal =
|
||||||
|
(digits "." digits? exponent_part? float_type_suffix?)
|
||||||
|
| ("." digits exponent_part? float_type_suffix?)
|
||||||
|
| (digits exponent_part float_type_suffix?)
|
||||||
|
| (digits exponent_part? float_type_suffix)
|
||||||
|
|
||||||
|
|
||||||
|
(* We follow an abstraction of the official grammar described here:
|
||||||
|
https://docs.oracle.com/javase/specs/jls/se14/html/jls-19.html *)
|
||||||
|
rule class_scan = parse
|
||||||
|
| whitespace+
|
||||||
|
{ class_scan lexbuf }
|
||||||
|
| eol_comment
|
||||||
|
{ class_scan lexbuf }
|
||||||
|
| "/*"
|
||||||
|
{ skip_comments (class_scan) lexbuf }
|
||||||
|
| eol
|
||||||
|
{ incr_linenum lexbuf;
|
||||||
|
class_scan lexbuf }
|
||||||
|
| "package"
|
||||||
|
{ PACKAGE }
|
||||||
|
| "import"
|
||||||
|
{ IMPORT }
|
||||||
|
| "class"
|
||||||
|
{ CLASS }
|
||||||
|
| "instanceof"
|
||||||
|
{ INSTANCEOF }
|
||||||
|
| "interface"
|
||||||
|
{ INTERFACE }
|
||||||
|
| "void"
|
||||||
|
{ VOID }
|
||||||
|
| "throws"
|
||||||
|
{ THROWS }
|
||||||
|
| "enum"
|
||||||
|
{ ENUM }
|
||||||
|
| modifier
|
||||||
|
{ class_scan lexbuf }
|
||||||
|
| primitive_type
|
||||||
|
{ PRIMTYPE }
|
||||||
|
| "<"
|
||||||
|
{ LANGLE }
|
||||||
|
| ">"
|
||||||
|
{ RANGLE }
|
||||||
|
| "new"
|
||||||
|
{ NEW }
|
||||||
|
| "var"
|
||||||
|
{ VAR }
|
||||||
|
| "extends"
|
||||||
|
{ EXTENDS }
|
||||||
|
| "super"
|
||||||
|
{ SUPER }
|
||||||
|
| "implements"
|
||||||
|
{ IMPLEMENTS }
|
||||||
|
| "assert"
|
||||||
|
{ ASSERT }
|
||||||
|
| "do"
|
||||||
|
{ DO }
|
||||||
|
| "while"
|
||||||
|
{ WHILE }
|
||||||
|
| "if"
|
||||||
|
{ IF }
|
||||||
|
| "else"
|
||||||
|
{ ELSE }
|
||||||
|
| "try"
|
||||||
|
{ TRY }
|
||||||
|
| "catch"
|
||||||
|
{ CATCH }
|
||||||
|
| "finally"
|
||||||
|
{ FINALLY }
|
||||||
|
| "for"
|
||||||
|
{ FOR }
|
||||||
|
| "break"
|
||||||
|
{ BREAK }
|
||||||
|
| "continue"
|
||||||
|
{ CONTINUE }
|
||||||
|
| "return"
|
||||||
|
{ RETURN }
|
||||||
|
| "throw"
|
||||||
|
{ THROW }
|
||||||
|
| "synchronized"
|
||||||
|
{ SYNCHRONIZED }
|
||||||
|
| "yield"
|
||||||
|
{ YIELD }
|
||||||
|
| "null"
|
||||||
|
{ NULL }
|
||||||
|
| "true"
|
||||||
|
{ TRUE }
|
||||||
|
| "false"
|
||||||
|
{ FALSE }
|
||||||
|
|
||||||
|
| (floating_point_literal as f)
|
||||||
|
{ FLOATINGPOINT f }
|
||||||
|
| (integer_literal as i)
|
||||||
|
{ INTEGER i }
|
||||||
|
|
||||||
|
|
||||||
|
| (id as name)
|
||||||
|
{ IDENT name }
|
||||||
|
|
||||||
|
| "\"" ([^ '\"']* as s) "\""
|
||||||
|
{ STRING s }
|
||||||
|
| (char as s)
|
||||||
|
{ CHAR s }
|
||||||
|
| ";"
|
||||||
|
{ SEMICOLON }
|
||||||
|
| ":"
|
||||||
|
{ COLON }
|
||||||
|
| "."
|
||||||
|
{ DOT }
|
||||||
|
| "{"
|
||||||
|
{ LBRACKET }
|
||||||
|
| "}"
|
||||||
|
{ RBRACKET }
|
||||||
|
| "["
|
||||||
|
{ LSBRACKET }
|
||||||
|
| "]"
|
||||||
|
{ RSBRACKET }
|
||||||
|
| "("
|
||||||
|
{ LPAREN }
|
||||||
|
| ")"
|
||||||
|
{ RPAREN }
|
||||||
|
| ","
|
||||||
|
{ COMMA }
|
||||||
|
| "?"
|
||||||
|
{ QMARK }
|
||||||
|
| ("++"|"--")
|
||||||
|
{ INCR_DECR }
|
||||||
|
| "|"
|
||||||
|
{ PIPE }
|
||||||
|
| "="
|
||||||
|
{ EQ }
|
||||||
|
| "!"
|
||||||
|
{ BANG }
|
||||||
|
| "~"
|
||||||
|
{ TILDE }
|
||||||
|
| "..."
|
||||||
|
{ THREEDOTS }
|
||||||
|
| assignment_operator
|
||||||
|
{ ASSIGNOP}
|
||||||
|
| binop
|
||||||
|
{ BINOP }
|
||||||
|
|
||||||
|
| "@" whitespace* id ("." id)* "("
|
||||||
|
{ skip_well_parenthesized_parentheses 1
|
||||||
|
(class_scan) lexbuf }
|
||||||
|
| "@" whitespace* id ("." id)*
|
||||||
|
{ class_scan lexbuf }
|
||||||
|
|
||||||
|
| _
|
||||||
|
{ class_scan lexbuf }
|
||||||
|
| eof
|
||||||
|
{ EOF }
|
||||||
|
|
||||||
|
(* we skip type annotation arguments (...) because they may contain brackets *)
|
||||||
|
and skip_well_parenthesized_parentheses width action = parse
|
||||||
|
| eol
|
||||||
|
{ incr_linenum lexbuf;
|
||||||
|
skip_well_parenthesized_parentheses width action lexbuf }
|
||||||
|
| "("
|
||||||
|
{ skip_well_parenthesized_parentheses (width+1) action lexbuf }
|
||||||
|
| ")"
|
||||||
|
{ if width<=1 then action lexbuf
|
||||||
|
else skip_well_parenthesized_parentheses (width-1) action lexbuf }
|
||||||
|
| eol_comment
|
||||||
|
{ skip_well_parenthesized_parentheses width action lexbuf }
|
||||||
|
| "/*"
|
||||||
|
{ skip_comments
|
||||||
|
(skip_well_parenthesized_parentheses width action) lexbuf }
|
||||||
|
| "\""
|
||||||
|
{ skip_string (skip_well_parenthesized_parentheses width action) lexbuf }
|
||||||
|
| char
|
||||||
|
{ skip_well_parenthesized_parentheses width action lexbuf }
|
||||||
|
| _
|
||||||
|
{ skip_well_parenthesized_parentheses width action lexbuf }
|
||||||
|
|
||||||
|
and skip_comments action = parse
|
||||||
|
| "*/"
|
||||||
|
{ action lexbuf }
|
||||||
|
| eol
|
||||||
|
{ incr_linenum lexbuf;
|
||||||
|
skip_comments action lexbuf }
|
||||||
|
| _
|
||||||
|
{ skip_comments action lexbuf }
|
||||||
|
|
||||||
|
and skip_string action = parse
|
||||||
|
| "\\\\"
|
||||||
|
{ skip_string action lexbuf }
|
||||||
|
| "\\\""
|
||||||
|
{ skip_string action lexbuf }
|
||||||
|
| "\""
|
||||||
|
{ action lexbuf }
|
||||||
|
| _
|
||||||
|
{ skip_string action lexbuf }
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
(*
|
||||||
|
* Copyright (c) 2009-2013, Monoidics ltd.
|
||||||
|
* 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! IStd
|
||||||
|
open Javalib_pack
|
||||||
|
|
||||||
|
let collect_class_location (program : JProgramDesc.t) (file : SourceFile.t) =
|
||||||
|
let path = SourceFile.to_abs_path file in
|
||||||
|
if String.is_suffix path ~suffix:".java" then (
|
||||||
|
let cin = In_channel.create path in
|
||||||
|
let filebuf = Lexing.from_channel cin in
|
||||||
|
let action_on_class_location ~classname ~col ~line =
|
||||||
|
let loc : Location.t = {line; col; file} in
|
||||||
|
let cn : JBasics.class_name = JBasics.make_cn classname in
|
||||||
|
Logging.debug Capture Verbose "set_java_location %s with location %a@." (JBasics.cn_name cn)
|
||||||
|
Location.pp_file_pos loc ;
|
||||||
|
JProgramDesc.set_java_location program cn loc
|
||||||
|
in
|
||||||
|
( try
|
||||||
|
let cl = JSourceParser.main JSourceLexer.class_scan filebuf in
|
||||||
|
JSourceAST.iter_on_declarations ~action_on_class_location cl
|
||||||
|
with
|
||||||
|
| Failure s ->
|
||||||
|
Logging.debug Capture Verbose "Error parsing source file %s\n%s"
|
||||||
|
(SourceFile.to_abs_path file) s
|
||||||
|
| JSourceParser.Error ->
|
||||||
|
Logging.debug Capture Verbose "JSourceParser error on file %s\n"
|
||||||
|
(SourceFile.to_abs_path file) ) ;
|
||||||
|
In_channel.close cin )
|
||||||
|
|
||||||
|
|
||||||
|
let debug_on_file path =
|
||||||
|
if String.is_suffix path ~suffix:".java" then (
|
||||||
|
let cin = In_channel.create path in
|
||||||
|
let filebuf = Lexing.from_channel cin in
|
||||||
|
let action_on_class_location ~classname ~col ~line =
|
||||||
|
Printf.printf "class %s at line %d, column %d\n" classname line col
|
||||||
|
in
|
||||||
|
( try
|
||||||
|
let cl = JSourceParser.main JSourceLexer.class_scan filebuf in
|
||||||
|
JSourceAST.iter_on_declarations ~action_on_class_location cl
|
||||||
|
with JSourceParser.Error ->
|
||||||
|
let pos = filebuf.Lexing.lex_curr_p in
|
||||||
|
let buf_length = Lexing.lexeme_end filebuf - Lexing.lexeme_start filebuf in
|
||||||
|
let line = pos.Lexing.pos_lnum in
|
||||||
|
let col = pos.Lexing.pos_cnum - pos.Lexing.pos_bol - buf_length in
|
||||||
|
Printf.eprintf "Java source syntax error at line %d, column %d.\n%!" line col ) ;
|
||||||
|
In_channel.close cin )
|
@ -0,0 +1,13 @@
|
|||||||
|
(*
|
||||||
|
* Copyright (c) 2009-2013, Monoidics ltd.
|
||||||
|
* 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! IStd
|
||||||
|
|
||||||
|
val collect_class_location : JProgramDesc.t -> SourceFile.t -> unit
|
||||||
|
|
||||||
|
val debug_on_file : string -> unit
|
@ -0,0 +1,773 @@
|
|||||||
|
/*
|
||||||
|
* 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 SUPER
|
||||||
|
%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
|
||||||
|
{}
|
||||||
|
|
||||||
|
type_arguments:
|
||||||
|
| LANGLE type_argument_list RANGLE
|
||||||
|
{}
|
||||||
|
|
||||||
|
type_argument_list:
|
||||||
|
| separated_nonempty_list(COMMA, type_argument)
|
||||||
|
{}
|
||||||
|
|
||||||
|
type_argument:
|
||||||
|
| unann_reference_type // If we decide to parse annotations, it will
|
||||||
|
// require change here
|
||||||
|
| QMARK wildcard_bounds?
|
||||||
|
{}
|
||||||
|
|
||||||
|
wildcard_bounds:
|
||||||
|
| EXTENDS unann_reference_type
|
||||||
|
| SUPER unann_reference_type
|
||||||
|
{}
|
||||||
|
|
||||||
|
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 }
|
Loading…
Reference in new issue