/// This file contains the grammar for Java 8.
///
/// The grammar is still highly incomplete! At every production/non-terminal
/// is a TODO-comment if it's not completed yet. However, these features won't
/// be "implemented" yet (read: we ignore them for now). Not implementing those
/// features doesn't count as "not completed":
///
/// - Annotations
/// - Generics
///
use ast;
use ast::ItemExt;
use lex::{self, Token, Keyword};
use base::code::{BytePos, Span};
use base::diag::Report;
use lalrpop_util::ParseError;
use std::iter;
use super::{
check_allowed_modifier,
get_abstract,
get_default,
get_final,
get_native,
get_static,
get_strictfp,
get_synchronized,
get_visibility,
unwrap_keyword,
};
grammar(errors: &mut Vec<Report>)["LALR"];
extern {
type Location = BytePos;
type Error = Report;
enum Token {
// Variants of the Java-*Token*
Word => Token::Ident(<String>),
Literal => Token::Literal(<lex::Lit>),
// Keywords
"abstract" => Token::KeyW(Keyword::Abstract),
"assert" => Token::KeyW(Keyword::Assert),
"boolean" => Token::KeyW(Keyword::Boolean),
"break" => Token::KeyW(Keyword::Break),
"byte" => Token::KeyW(Keyword::Byte),
"case" => Token::KeyW(Keyword::Case),
"catch" => Token::KeyW(Keyword::Catch),
"char" => Token::KeyW(Keyword::Char),
"class" => Token::KeyW(Keyword::Class),
"const" => Token::KeyW(Keyword::Const),
"continue" => Token::KeyW(Keyword::Continue),
"default" => Token::KeyW(Keyword::Default),
"do" => Token::KeyW(Keyword::Do),
"double" => Token::KeyW(Keyword::Double),
"else" => Token::KeyW(Keyword::Else),
"enum" => Token::KeyW(Keyword::Enum),
"extends" => Token::KeyW(Keyword::Extends),
"final" => Token::KeyW(Keyword::Final),
"finally" => Token::KeyW(Keyword::Finally),
"float" => Token::KeyW(Keyword::Float),
"for" => Token::KeyW(Keyword::For),
"if" => Token::KeyW(Keyword::If),
"goto" => Token::KeyW(Keyword::Goto),
"implements" => Token::KeyW(Keyword::Implements),
"import" => Token::KeyW(Keyword::Import),
"instanceof" => Token::KeyW(Keyword::Instanceof),
"int" => Token::KeyW(Keyword::Int),
"interface" => Token::KeyW(Keyword::Interface),
"long" => Token::KeyW(Keyword::Long),
"native" => Token::KeyW(Keyword::Native),
"new" => Token::KeyW(Keyword::New),
"package" => Token::KeyW(Keyword::Package),
"private" => Token::KeyW(Keyword::Private),
"protected" => Token::KeyW(Keyword::Protected),
"public" => Token::KeyW(Keyword::Public),
"return" => Token::KeyW(Keyword::Return),
"short" => Token::KeyW(Keyword::Short),
"static" => Token::KeyW(Keyword::Static),
"strictfp" => Token::KeyW(Keyword::Strictfp),
"super" => Token::KeyW(Keyword::Super),
"switch" => Token::KeyW(Keyword::Switch),
"synchronized" => Token::KeyW(Keyword::Synchronized),
"this" => Token::KeyW(Keyword::This),
"throw" => Token::KeyW(Keyword::Throw),
"throws" => Token::KeyW(Keyword::Throws),
"transient" => Token::KeyW(Keyword::Transient),
"try" => Token::KeyW(Keyword::Try),
"void" => Token::KeyW(Keyword::Void),
"volatile" => Token::KeyW(Keyword::Volatile),
"while" => Token::KeyW(Keyword::While),
// Variants of Java-*Seperator*
// ( ) { } [ ] ; , . ... @ ::
"(" => Token::ParenOp,
")" => Token::ParenCl,
"{" => Token::BraceOp,
"}" => Token::BraceCl,
"[" => Token::BracketOp,
"]" => Token::BracketCl,
";" => Token::Semi,
"," => Token::Comma,
"." => Token::Dot,
"..." => Token::DotDotDot,
"@" => Token::At,
"::" => Token::ColonSep,
// Variants of Java-*Operator*
"=" => Token::Eq,
">" => Token::Gt,
"<" => Token::Lt,
"!" => Token::Bang,
"~" => Token::Tilde,
"?" => Token::Question,
":" => Token::Colon,
"->" => Token::Arrow,
"==" => Token::EqEq,
">=" => Token::Ge,
"<=" => Token::Le,
"!=" => Token::Ne,
"&&" => Token::AndAnd,
"||" => Token::OrOr,
"++" => Token::PlusPlus,
"--" => Token::MinusMinus,
"+" => Token::Plus,
"-" => Token::Minus,
"*" => Token::Star,
"/" => Token::Slash,
"&" => Token::And,
"|" => Token::Or,
"^" => Token::Caret,
"%" => Token::Percent,
"<<" => Token::Shl,
">>" => Token::Shr,
">>>" => Token::ShrUn,
"+=" => Token::PlusEq,
"-=" => Token::MinusEq,
"*=" => Token::StarEq,
"/=" => Token::SlashEq,
"&=" => Token::AndEq,
"|=" => Token::OrEq,
"^=" => Token::CaretEq,
"%=" => Token::PercentEq,
"<<=" => Token::ShlEq,
">>=" => Token::ShrEq,
">>>=" => Token::ShrUnEq,
}
}
// ===========================================================================
// Definition of helper productions and macros
// ===========================================================================
#[inline]
Comma<T>: Vec<T> = {
<head: T> <tail: ("," <T>)*> => {
let mut v = vec![head];
v.extend_from_slice(&tail);
v
}
};
#[inline]
Spanned<T>: ast::Spanned<T> = {
<l:@L> <t:T> <r:@R> => ast::Spanned { inner: t, span: Span::new(l, r) },
};
#[inline]
BinOp<L, O, R>: ast::ExprType = {
<lhs: Spanned<L>> <op: O> <rhs: Spanned<R>> => {
ast::ExprType::BinOp {
// this macro is only used in the parser and we assume that the
// parser only specifies correct tokens (unwrap ok)
op: ast::BinOpType::from_token(&op).unwrap(),
lhs: lhs.into(),
rhs: rhs.into(),
}
},
};
BinOpLeftAssoc<O, N>: ast::ExprType = {
N,
BinOp<BinOpLeftAssoc<O, N>, O, N>,
};
ExprTypeAsStatement<E>: ast::Statement = {
Spanned<E> => {
ast::Statement {
span: <>.span,
label: None,
stmt: ast::StatementType::Expr(ast::Expr {
span: <>.span,
expr: <>.inner,
})
}
},
};
// ===========================================================================
// Helper grammar definitions that are used in several sections
// ===========================================================================
// Type modifier is a merge of "InterfaceModifier" and "ClassModifier"
ModifierImpl = {
"public",
"protected",
"private",
"abstract",
"static",
"final",
"synchronized",
"native",
"strictfp",
};
#[inline]
Modifier: Keyword = {
ModifierImpl => unwrap_keyword(&<>),
};
#[inline]
Ident: ast::Ident = {
<w: Spanned<Word>> => ast::Ident {
name: w.inner,
span: w.span,
}
};
#[inline]
Path: ast::Path = {
<head: Ident> <tail: ("." <Ident>)*> => {
let mut v = vec![head];
v.extend_from_slice(&tail);
ast::Path {
segments: v,
}
}
};
// ----------------------------------------------------------------------------
// ~~~ Section 4 [ANNO, -] ~~~
// 4.2 ANNO
PrimitiveType = UnannPrimitiveType;
// 4.2
NumericType: ast::Type = {
Spanned<IntegralType> => ast::Type::without_dims(
ast::Path::single(<>.map(|t| unwrap_keyword(&t)).into())
),
Spanned<FloatingPointType> => ast::Type::without_dims(
ast::Path::single(<>.map(|t| unwrap_keyword(&t)).into())
),
};
// 4.2
#[inline]
IntegralType = {
"byte",
"short",
"int",
"long",
"char",
};
// 4.2
#[inline]
FloatingPointType = {
"float",
"double",
};
// 4.3 ANNO
#[inline]
DimsOpt: ast::Dims = {
Dims? => <>.unwrap_or(0),
};
Dims: ast::Dims = {
<dims: Spanned<("[" "]")+>> =>? {
if dims.inner.len() > ast::Dims::max_value() as usize {
Err(ParseError::User {
error: Report::simple_error(
format!(
"too many dimensions! Do you really need a {} \
dimensional array?",
dims.inner.len(),
),
dims.span,
)
})
} else {
Ok(dims.inner.len() as ast::Dims)
}
} ,
};
// 4.3 ANNO
ReferenceType = UnannReferenceType;
#[inline]
InterfaceType = ClassType;
#[inline]
ClassType = UnannClassType;
ArrayType = UnannArrayType;
// ArrayType: ast::Type = {
// <ty: PrimitiveType> <dims: Dims> => {
// ast::Type {
// name: ty.name,
// dims: dims,
// }
// },
// };
// ===========================================================================
// Grammar definitions in a top-down fashion/depth first search order
// ===========================================================================
// ~~~ Section 7 ~~~
// 7.3 (goal symbol)
pub CompilationUnit: ast::CompilationUnit = {
<package: PackageDecl?>
<imports: ImportDecl*>
<types: TypeDecl*>
=>
{
ast::CompilationUnit {
package: package,
imports: imports,
types: types.into_iter().filter_map(|t| t).collect()
}
}
};
// 7.4
PackageDecl = { "package" <Path> ";" };
// 7.5
ImportDecl: ast::Import = {
"import" <Path> ";" => ast::Import::SingleType(<>),
"import" <Path> "." "*" ";" => ast::Import::TypeOnDemand(<>),
"import" "static" <Path> ";" => ast::Import::SingleStatic(<>),
"import" "static" <Path> "." "*" ";" => ast::Import::StaticOnDemand(<>),
};
// 7.6
TypeDecl: Option<ast::TypeDef> = {
<ClassDecl> => Some(<>),
<InterfaceDecl> => Some(<>),
";" => None
};
// ---------------------------------------------------------------------------
// ~~~ TODO: Section 9 ~~~
// 9.1
InterfaceDecl: ast::TypeDef = {
<NormalInterfaceDecl> => ast::TypeDef::NormalInterface(<>),
// TODO: AnnotationTypeDeclaration
};
// 9.1 GENE
NormalInterfaceDecl: ast::Interface = {
<mods: Spanned<Modifier>*>
"interface" <name: Ident>
// GENE: type parameters
<extends: ("extends" <Comma<InterfaceType>>)?>
<body: InterfaceBody> =>
{
check_mods!(errors, "interface", mods,
[Public, Private, Protected, Abstract, Static, Strictfp]
);
// check if unnecessary `abstract` keyword was specified
if let Some(span) = get_abstract(&mods) {
errors.push(Report::simple_warning(
"interfaces are abstract by default. The `abstract` \
modifier is obsolete -- better remove it.",
span
));
}
// check body
let mut types = Vec::new();
let mut constants = Vec::new();
let mut methods = Vec::new();
for item in body.into_iter().flat_map(|v| v) {
match item {
ast::TypeItem::Type(t) => {
// there are special rules for inner types
// TODO: spans are confusing right now (from type name)
// TODO: fix these stupid spans! For real now.
match t.vis() {
ast::Visibility::Private | ast::Visibility::Protected => {
errors.push(Report::simple_error(
"a member type of an interface is always \
public. You must not use `private` or \
`protected` modifiers.",
t.ident().map(|i| i.span).unwrap_or(Span::dummy())
));
},
ast::Visibility::Public => {
errors.push(Report::simple_warning(
"a member type of an interface is implicitly \
public. You don't need to explicitly mark \
it public.",
t.ident().map(|i| i.span).unwrap_or(Span::dummy())
));
}
_ => {},
}
// TODO: set visibility to public
types.push(t);
},
ast::TypeItem::Constant(c) => {
constants.push(c);
},
ast::TypeItem::Method(m) => {
methods.push(m);
},
}
}
ast::Interface {
name: name,
vis: get_visibility(&mods, errors).unwrap_or(ast::Visibility::Package),
static_: get_static(&mods).is_some(),
strictfp: get_strictfp(&mods).is_some(),
extends: extends.unwrap_or_default(),
types: types,
constants: constants,
methods: methods,
}
}
};
// 9.1.4
InterfaceBody = "{" <InterfaceMemberDecl*> "}";
// 9.1.4 TODO
InterfaceMemberDecl: Vec<ast::TypeItem> = {
ConstantDecl => {
<>.into_iter().map(|f| ast::TypeItem::Constant(f)).collect()
},
InterfaceMethodDecl => vec![ast::TypeItem::Method(<>)],
InterfaceDecl => vec![ast::TypeItem::Type(<>)],
ClassDecl => vec![ast::TypeItem::Type(<>)],
};
// 9.3
ConstantDecl: Vec<ast::Field> = {
<mods: Spanned<Modifier>*>
<ty: UnannType>
<var_decls: VariableDeclaratorList> ";" => {
check_mods!(errors, "constant", mods, [Public, Static, Final]);
var_decls.into_iter().map(|ast::VariableDeclarator { name, dims, init }| {
let mut ty = ty.clone();
ty.dims += dims;
ast::Field {
vis: ast::Visibility::Public,
static_: true,
final_: true,
ty: ty.clone(),
name: name,
// init: init, TODO
}
}).collect()
}
};
// 9.4 TODO
InterfaceMethodDecl: ast::Method = {
<mods: Spanned<Modifier>*> <header: MethodHeader> <body: MethodBody> => {
check_mods!(errors, "interface-method", mods,
[Public, Abstract, Default, Static, Strictfp]
);
let (ret_ty, name, params, throws) = header;
let is_static = get_static(&mods);
let is_default = get_default(&mods);
let is_abstract = get_abstract(&mods);
// TODO: Check if more than one of static/default/abstract is set [E]
// TODO: Check if abstract is combined with strictfp [E]
// TODO: Add "public" useless modifier warning
// TODO: Add "abstract" useless modifier warning
ast::Method {
vis: ast::Visibility::Public,
name: name,
ret_ty: ret_ty,
static_: is_static.is_some(),
final_: false,
strictfp: get_strictfp(&mods).is_some(),
abstract_: is_abstract.is_some(),
native: false,
synchronized: false,
default: is_default.is_some(),
params: params,
throws: throws,
block: body,
}
}
};
// ---------------------------------------------------------------------------
// 8.1 TODO
ClassDecl: ast::TypeDef = {
<NormalClassDecl> => ast::TypeDef::NormalClass(<>),
// EnumDecl,
};
// 8.1 TODO GENE
#[inline]
NormalClassDecl: ast::Class = {
<modifier: Spanned<Modifier>*>
"class" <class_name: Ident>
<body: ClassBody> =>
{
// TODO: check modifier
ast::Class {
name: class_name,
vis: ast::Visibility::Public,
members: body,
}
}
};
// 8.1.6
ClassBody: Vec<ast::ClassMember> = {
"{" <ClassBodyDecl*> "}" => {
<>.into_iter().flat_map(|v| v.into_iter()).collect()
}
};
// 8.1.6 TODO
ClassBodyDecl = {
ClassMemberDecl,
// InstanceInitializer
// StaticInitializer
// ConstructorDeclaration
};
// 8.1.6 TODO
ClassMemberDecl: Vec<ast::ClassMember> = {
FieldDecl => {
<>.into_iter().map(|f| ast::ClassMember::Field(f)).collect()
},
MethodDecl => {
vec![ast::ClassMember::Method(<>)]
},
// ClassDecl,
// InterfaceDecl,
};
// 8.3 TODO
FieldDecl: Vec<ast::Field> = {
<mods: Spanned<Modifier>*>
<ty: UnannType> <decls: VariableDeclaratorList> ";" =>
{
// TODO: modifier checks
// check_mods!(errors, "class-field", mods, [
// Public, Protected, Private, Abstract, Static, Final,
// Synchronized, Native, Strictfp
// ]
// );
decls.into_iter().map(|ast::VariableDeclarator { name, dims, init }| {
let mut ty = ty.clone();
ty.dims += dims;
ast::Field {
vis: ast::Visibility::Package,
static_: false,
final_: false,
ty: ty,
name: name,
}
}).collect()
}
};
// 8.3
// #[inline]
UnannType: ast::Type = {
UnannPrimitiveType,
UnannReferenceType,
};
// 8.3 ANNO GENE
#[inline]
UnannPrimitiveType: ast::Type = {
NumericType,
Spanned<"boolean"> => ast::Type::without_dims(
ast::Path::single(<>.map(|t| unwrap_keyword(&t)).into())
),
};
// #[inline] UnannReferenceType = { UnannClassType, UnannArrayType };
UnannReferenceType = { UnannClassType, UnannArrayType };
// UnannInterfaceType = UnannClassType;
#[inline] UnannClassType: ast::Type = Path => ast::Type::without_dims(<>);
UnannArrayType: ast::Type = {
<ty: UnannPrimitiveType> <dims: Dims> => {
ast::Type {
name: ty.name,
dims: dims,
}
},
<ty: UnannClassType> <dims: Dims> => {
ast::Type {
name: ty.name,
dims: dims,
}
},
};
// 8.3
VariableDeclaratorList = Comma<VariableDeclarator>;
// 8.3
VariableDeclarator: ast::VariableDeclarator = {
<id: VariableDeclaratorId> <init: ("=" <VariableInitializer>)?> => {
ast::VariableDeclarator {
name: id.0,
dims: id.1,
init: init,
}
}
};
// 8.3
VariableDeclaratorId = {
<Ident> <DimsOpt>
};
// 8.3 TODO
VariableInitializer: ast::Expr = {
Expression,
Spanned<ArrayInitializer> => <>.into(),
};
// 8.4 ANNO
MethodDecl: ast::Method = {
<mods: Spanned<Modifier>*> <header: MethodHeader> <body: Spanned<MethodBody>> => {
check_mods!(errors, "class-method", mods,
[Public, Protected, Private, Abstract, Static, Final, Synchronized, Native, Strictfp]
);
let (ret_ty, name, params, throws) = header;
let is_static = get_static(&mods);
let is_final = get_final(&mods);
let is_abstract = get_abstract(&mods);
let is_native = get_native(&mods);
let is_strictfp = get_strictfp(&mods);
let is_syncronized = get_synchronized(&mods);
let vis = get_visibility(&mods, errors);
// E: abstract + method body
if let (Some(abstract_span), true) = (is_abstract, body.inner.is_some()) {
errors.push(Report::simple_error(
"an abstract method must not provide a method body",
body.span,
).with_span_note(
"method was declared `abstract` here",
abstract_span,
));
}
// E: native + method body
if let (Some(native_span), true) = (is_native, body.inner.is_some()) {
errors.push(Report::simple_error(
"a native method must not provide a method body",
body.span,
).with_span_note(
"method was declared `native` here",
native_span,
));
}
// E: `abstract` paired with one of [private, static, final, native,
// strictfp, synchronized]
if is_abstract.is_some() {
check_mods!(errors, "abstract class-method", mods,
[Public, Protected, Abstract]
);
}
// E: `native` cannot be paired with `strictfp`
if let (Some(native_span), Some(strictfp_span)) = (is_native, is_strictfp) {
errors.push(Report::simple_error(
"the `strictfp` modifier cannot be paired with `native`",
strictfp_span,
).with_span_note(
"method was declared `native` here",
native_span,
));
}
ast::Method {
vis: vis.unwrap_or(ast::Visibility::Package),
name: name,
ret_ty: ret_ty,
static_: is_static.is_some(),
final_: is_final.is_some(),
strictfp: is_strictfp.is_some(),
abstract_: is_abstract.is_some(),
native: is_native.is_some(),
synchronized: is_syncronized.is_some(),
default: false,
params: params,
throws: throws,
block: body.inner,
}
}
};
// 8.4 GENE ANNO
MethodHeader: (ast::Type, ast::Ident, Vec<ast::FormalParameter>, Vec<ast::Type>) = {
<ret: Result> <decl: MethodDeclarator> <throws: Throws?> => {
let mut ret_ty = ret;
ret_ty.dims += decl.2;
(ret_ty, decl.0, decl.1.unwrap_or_default(), throws.unwrap_or_default())
}
};
// 8.4 TODO
MethodDeclarator = {
<Ident> "(" <FormalParameterList?> ")" <DimsOpt>
};
// 8.4.1 TODO
FormalParameterList = {
Comma<FormalParameter>,
// TODO: LastParameter (...)
// TODO: ReceiverParameter
};
// 8.4.1 ANNO
FormalParameter: ast::FormalParameter = {
<final_: "final"?> <ty: UnannType> <id: VariableDeclaratorId> => {
let mut ty = ty;
ty.dims += id.1;
ast::FormalParameter {
ty: ty,
name: id.0,
final_: final_.is_some(),
}
}
};
// 8.4.5 TODO
#[inline]
Result = {
UnannType,
Spanned<"void"> => ast::Type::without_dims(
ast::Path::single(<>.map(|t| unwrap_keyword(&t)).into())
),
};
// 8.4.6 GENE
Throws = "throws" <Comma<ExceptionType>>;
ExceptionType = ClassType;
// 8.4.7 TODO
MethodBody: Option<ast::Block> = {
";" => None,
Block => Some(<>),
};
// ----------------------------------------------------------------------------
// ~~~ Section 14 [TODO] ~~~
// 14.2 TODO
Block: ast::Block = {
"{" <BlockStatement*> "}" => {
ast::Block {
stmts: <>
}
}
};
// 14.2 TODO
BlockStatement: ast::BlockStatement = {
LocalVariableDeclStatement,
// ClassDecl,
Statement => ast::BlockStatement::Statement(<>),
};
// 14.4 ANNO
LocalVariableDeclStatement = <LocalVariableDecl> ";";
LocalVariableDecl: ast::BlockStatement = {
<final_: "final"?> <ty: UnannType> <decls: VariableDeclaratorList> => {
ast::BlockStatement::LocalVariableDecl {
final_: final_.is_some(),
ty: ty,
vars: decls,
}
}
};
// 14.5
Statement = {
StatementWithoutTrailingSubstatement,
LabeledStatement,
Spanned<IfThenStatement> => ast::Statement {
label: None,
stmt: <>.inner,
span: <>.span,
},
Spanned<IfThenElseStatement> => ast::Statement {
label: None,
stmt: <>.inner,
span: <>.span,
},
Spanned<WhileStatement> => ast::Statement {
label: None,
stmt: <>.inner,
span: <>.span,
},
Spanned<ForStatement> => ast::Statement {
label: None,
stmt: <>.inner,
span: <>.span,
},
};
StatementNoShortIf = {
StatementWithoutTrailingSubstatement,
LabeledStatementNoShortIf,
Spanned<IfThenElseStatementNoShortIf> => ast::Statement {
label: None,
stmt: <>.inner,
span: <>.span,
},
Spanned<WhileStatementNoShortIf> => ast::Statement {
label: None,
stmt: <>.inner,
span: <>.span,
},
Spanned<ForStatementNoShortIf> => ast::Statement {
label: None,
stmt: <>.inner,
span: <>.span,
},
};
// TODO
StatementWithoutTrailingSubstatement: ast::Statement = {
Spanned<Block> => {
ast::Statement {
label: None,
stmt: ast::StatementType::Block(<>.inner),
span: <>.span,
}
},
EmptyStatement,
ExpressionStatement,
// AssertStatement,
Spanned<SwitchStatement> => {
ast::Statement {
label: None,
stmt: <>.inner,
span: <>. span,
}
},
<l: @L> "do" <body: Statement> "while" "(" <cond: Expression> ")" ";" <r: @R> => {
ast::Statement {
label: None,
stmt: ast::StatementType::DoWhile{
cond: cond,
body: Box::new(body),
},
span: Span::new(l, r),
}
},
<l: @L> "break" <label: Ident?> ";" <r: @R> => {
ast::Statement {
label: None,
stmt: ast::StatementType::Break(label),
span: Span::new(l, r),
}
},
<l: @L> "continue" <label: Ident?> ";" <r: @R> => {
ast::Statement {
label: None,
stmt: ast::StatementType::Continue(label),
span: Span::new(l, r),
}
},
<l: @L> "return" <expr: Expression?> ";" <r: @R> => {
ast::Statement {
label: None,
stmt: ast::StatementType::Return(expr),
span: Span::new(l, r),
}
},
// ReturnStatement,
// SynchronizedStatement,
<l: @L> "throw" <expr: Expression> ";" <r: @R> => {
ast::Statement {
label: None,
stmt: ast::StatementType::Throw(expr),
span: Span::new(l, r),
}
},
// TryStatement,
};
// 14.6
EmptyStatement: ast::Statement = {
Spanned<";"> => {
ast::Statement {
label: None,
stmt: ast::StatementType::Empty,
span: <>.span,
}
}
};
// 14.7
LabeledStatement: ast::Statement = {
<label: Ident> ":" <stmt: Statement> => {
let mut stmt = stmt;
stmt.label = Some(label);
stmt
}
};
LabeledStatementNoShortIf: ast::Statement = {
<label: Ident> ":" <stmt: StatementNoShortIf> => {
let mut stmt = stmt;
stmt.label = Some(label);
stmt
}
};
// 14.8
#[inline]
ExpressionStatement = <StatementExpression> ";";
StatementExpression: ast::Statement = {
Spanned<Assignment> => {
ast::Statement {
span: <>.span,
label: None,
stmt: ast::StatementType::Expr(<>.into()),
}
},
ExprTypeAsStatement<PreIncrementExpression>,
ExprTypeAsStatement<PreDecrementExpression>,
ExprTypeAsStatement<PostIncrementExpression>,
ExprTypeAsStatement<PostDecrementExpression>,
// ExprTypeAsStatement<MethodInvocation>,
Spanned<MethodInvocation> => {
ast::Statement {
span: <>.span,
label: None,
stmt: ast::StatementType::Expr(ast::Expr {
span: <>.span,
expr: ast::ExprType::MethodInvocation {
name: <>.inner.0,
args: <>.inner.1,
}
})
}
},
// ClassInstanceCreationExpression
};
// 14.9
IfThenStatement: ast::StatementType = {
"if" "(" <cond: Expression> ")" <then: Statement> => {
ast::StatementType::IfThenElse {
cond: cond,
then_branch: Box::new(then),
else_branch: None,
}
},
};
IfThenElseStatement: ast::StatementType = {
"if" "(" <cond: Expression> ")"
<then: StatementNoShortIf>
"else" <else_branch: Statement> =>
{
ast::StatementType::IfThenElse {
cond: cond,
then_branch: Box::new(then),
else_branch: Some(Box::new(else_branch)),
}
}
};
IfThenElseStatementNoShortIf: ast::StatementType = {
"if" "(" <cond: Expression> ")"
<then: StatementNoShortIf>
"else" <else_branch: StatementNoShortIf> =>
{
ast::StatementType::IfThenElse {
cond: cond,
then_branch: Box::new(then),
else_branch: Some(Box::new(else_branch)),
}
}
};
// 14.11
SwitchStatement: ast::StatementType = {
"switch" "(" <val: Expression> ")"
"{" <arms: SwitchArm*> <empty_arms: SwitchLabel*> "}" =>
{
ast::StatementType::Switch {
val: val,
arms: arms,
empty_arms: empty_arms,
}
}
};
SwitchArm: ast::SwitchArm = <labels: SwitchLabel*> <block: BlockStatement> => {
ast::SwitchArm {
labels: labels,
block: block,
}
};
SwitchLabel: ast::SwitchLabel = {
"default" ":" => ast::SwitchLabel::Default,
// "case" <Ident> ":" => ast::SwitchLabel::Name(<>),
"case" <Expression> ":" => ast::SwitchLabel::Expr(<>),
};
// 14.12
WhileStatement: ast::StatementType = {
"while" "(" <cond: Expression> ")" <body: Statement> => {
ast::StatementType::While {
cond: cond,
body: Box::new(body),
}
}
};
WhileStatementNoShortIf: ast::StatementType = {
"while" "(" <cond: Expression> ")" <body: StatementNoShortIf> => {
ast::StatementType::While {
cond: cond,
body: Box::new(body),
}
}
};
// 14.14 TODO
ForStatement = {
BasicForStatement,
// EnhancedForStatement,
};
ForStatementNoShortIf = {
BasicForStatementNoShortIf,
// EnhancedForStatement,
};
// 14.14.1
BasicForStatement: ast::StatementType = {
"for" "(" <init: ForInit> ";"
<cond: Expression?> ";"
<update: ForUpdate?> ")"
<body: Statement> =>
{
ast::StatementType::For {
init: init,
cond: cond,
update: update.unwrap_or_default(),
body: Box::new(body),
}
}
};
BasicForStatementNoShortIf: ast::StatementType = {
"for" "(" <init: ForInit> ";"
<cond: Expression?> ";"
<update: ForUpdate?> ")"
<body: StatementNoShortIf> =>
{
ast::StatementType::For {
init: init,
cond: cond,
update: update.unwrap_or_default(),
body: Box::new(body),
}
}
};
ForInit: ast::ForInit = {
StatementExpressionList? => ast::ForInit::Stmts(<>.unwrap_or_default()),
LocalVariableDecl => ast::ForInit::VarDecl(Box::new(<>)),
};
ForUpdate = StatementExpressionList;
StatementExpressionList = Comma<StatementExpression>;
// 15.2
Expression: ast::Expr = {
Spanned<AssignmentExpression> => <>.into(),
};
// 15.8 TODO
Primary = {
PrimaryNoNewArray,
ArrayCreationExpression,
};
PrimaryNoNewArray: ast::ExprType = {
Literal => ast::ExprType::Literal(<>),
ClassLiteral => ast::ExprType::ClassLiteral(<>),
"this" => ast::ExprType::This,
// TypeName . this
"(" <Expression> ")" => <>.expr,
ClassInstanceCreationExpression,
FieldAccess,
ArrayAccess,
MethodInvocation => ast::ExprType::MethodInvocation {
name: <>.0,
args: <>.1,
},
// MethodReference,
// Spanned<Assignment> =>? {
// let rep = Report::simple_error(
// format!(),
// dims.span,
// );
// Err(ParseError::User {
// error:
// })
// }
};
// 15.8.2
ClassLiteral: ast::Type = {
<name: TypeName> <dims: DimsOpt> "." "class" => {
ast::Type { name: name, dims: dims }
},
<name: NumericType> <dims: DimsOpt> "." "class" => {
ast::Type {
name: name.name,
dims: dims,
}
},
<name: Spanned<"boolean">> <dims: DimsOpt> "." "class" => {
ast::Type {
name: ast::Path::single(name.map(|t| unwrap_keyword(&t)).into()),
dims: dims,
}
},
<Spanned<"void">> "." "class" => ast::Type::without_dims(
ast::Path::single(<>.map(|t| unwrap_keyword(&t)).into())
),
};
// 15.9 GENE ANNO TODO
ClassInstanceCreationExpression = {
UnqualifiedClassInstanceCreationExpression,
};
UnqualifiedClassInstanceCreationExpression: ast::ExprType = {
"new" <name: ClassOrInterfaceTypeToInstantiate>
"(" <args: ArgumentList?> ")"
<body: ClassBody?> =>
{
ast::ExprType::InstanceCreation {
name: name,
args: args.unwrap_or_default(),
body: body,
}
}
};
ClassOrInterfaceTypeToInstantiate = {
Path,
};
// 15.10.1 TODO ANNO
ArrayCreationExpression: ast::ExprType = {
"new" <ty: ArrayCreationType> <expr_dims: DimExpr+> <empty_dims: DimsOpt> => {
ast::ExprType::ArrayCreation {
ty: ty,
expr_dims: expr_dims,
empty_dims: empty_dims,
init: None,
}
},
"new" <ty: ArrayCreationType> <dims: Dims> <init: Spanned<ArrayInitializer>> => {
ast::ExprType::ArrayCreation {
ty: ty,
expr_dims: Vec::new(),
empty_dims: dims,
init: Some(init.into()),
}
},
};
ArrayCreationType = { PrimitiveType, ClassType };
DimExpr = "[" <Expression> "]";
// 15.10.3
ArrayAccess: ast::ExprType = {
<lhs: Spanned<ExpressionName>> "[" <idx: Expression> "]" => {
ast::ExprType::ArrayAccess {
obj: Box::new(lhs.into()),
idx: Box::new(idx),
}
},
<lhs: Spanned<PrimaryNoNewArray>> "[" <idx: Expression> "]" => {
ast::ExprType::ArrayAccess {
obj: Box::new(lhs.into()),
idx: Box::new(idx),
}
},
};
// 15.11
FieldAccess: ast::ExprType = FieldAccessImpl => {
ast::ExprType::FieldAccess {
root: <>.0,
path: <>.1,
}
};
FieldAccessImpl: (Option<Box<ast::Expr>>, ast::Path) = {
<r: Spanned<Primary>> "." <p: Ident> => {
(Some(Box::new(r.into())), ast::Path::single(p))
},
<h: Spanned<"super">> "." <t: Ident> => {
(None, ast::Ident { name: "super".into(), span: h.span } + t)
},
<p: TypeName> "." <sup: Spanned<"super">> "." <last: Ident> => {
(None, p + ast::Ident { name: "super".into(), span: sup.span } + last)
},
};
// 15.12 TODO GENE
#[inline]
MethodInvocation: (ast::MethodInvocationType, Vec<ast::Expr>) = {
<name: MethodName> "(" <args: ArgumentList?> ")" => {(
ast::MethodInvocationType::SimpleName(name),
args.unwrap_or_default(),
)},
<p: TypeName> "." <name: Ident> "(" <args: ArgumentList?> ")" => {(
ast::MethodInvocationType::SimplePath(p + name),
args.unwrap_or_default(),
)},
<p: Spanned<Primary>> "." <name: Ident> "(" <args: ArgumentList?> ")" => {(
ast::MethodInvocationType::Expr(p.into(), name),
args.unwrap_or_default(),
)},
};
ArgumentList = Comma<Expression>;
// 15.14
PostfixExpression = {
Primary,
ExpressionName,
PostIncrementExpression,
PostDecrementExpression,
};
// 15.14.2
PostIncrementExpression: ast::ExprType = <Spanned<PostfixExpression>> "++" => {
ast::ExprType::UnaryOp {
op: ast::UnaryOpType::PostIncr,
expr: <>.into(),
}
};
// 15.14.3
PostDecrementExpression: ast::ExprType = <Spanned<PostfixExpression>> "--" => {
ast::ExprType::UnaryOp {
op: ast::UnaryOpType::PostDecr,
expr: <>.into(),
}
};
// 15.15 TODO
UnaryExpression: ast::ExprType = {
PreIncrementExpression,
PreDecrementExpression,
"+" <Spanned<UnaryExpression>> => ast::ExprType::UnaryOp {
op: ast::UnaryOpType::Plus,
expr: <>.into(),
},
"-" <Spanned<UnaryExpression>> => ast::ExprType::UnaryOp {
op: ast::UnaryOpType::Neg,
expr: <>.into(),
},
UnaryExpressionNotPlusMinus,
};
PreIncrementExpression: ast::ExprType = "++" <Spanned<UnaryExpression>> => {
ast::ExprType::UnaryOp {
op: ast::UnaryOpType::PreIncr,
expr: <>.into(),
}
};
PreDecrementExpression: ast::ExprType = "--" <Spanned<UnaryExpression>> => {
ast::ExprType::UnaryOp {
op: ast::UnaryOpType::PreDecr,
expr: <>.into(),
}
};
UnaryExpressionNotPlusMinus: ast::ExprType = {
PostfixExpression,
"~" <Spanned<UnaryExpression>> => ast::ExprType::UnaryOp {
op: ast::UnaryOpType::BitwiseNot,
expr: <>.into(),
},
"!" <Spanned<UnaryExpression>> => ast::ExprType::UnaryOp {
op: ast::UnaryOpType::Not,
expr: <>.into(),
},
CastExpression,
};
// 15.16 GENE LAMBDA
CastExpression: ast::ExprType = {
"(" <ty: PrimitiveType> ")" <expr: Spanned<UnaryExpression>> => {
ast::ExprType::Cast {
ty: ty,
expr: expr.into(),
}
},
// "(" <ty: ReferenceType> ")" <expr: Spanned<UnaryExpressionNotPlusMinus>> => {
// ast::ExprType::Cast {
// ty: ty,
// expr: expr.into(),
// }
// },
};
// 15.17
MultiplicativeExpression = {
UnaryExpression,
BinOp<MultiplicativeExpression, "*", UnaryExpression>,
BinOp<MultiplicativeExpression, "/", UnaryExpression>,
BinOp<MultiplicativeExpression, "%", UnaryExpression>,
};
// 15.18
AdditiveExpression = {
MultiplicativeExpression,
BinOp<AdditiveExpression, "+", MultiplicativeExpression>,
BinOp<AdditiveExpression, "-", MultiplicativeExpression>,
};
// 15.19
ShiftExpression = {
AdditiveExpression,
BinOp<ShiftExpression, "<<", AdditiveExpression>,
BinOp<ShiftExpression, ">>", AdditiveExpression>,
BinOp<ShiftExpression, ">>>", AdditiveExpression>,
};
// 15.20 TODO
RelationalExpression = {
ShiftExpression,
BinOp<RelationalExpression, "<", ShiftExpression>,
BinOp<RelationalExpression, ">", ShiftExpression>,
BinOp<RelationalExpression, "<=", ShiftExpression>,
BinOp<RelationalExpression, ">=", ShiftExpression>,
// BinOp<RelationalExpression, "instanceof", ReferenceType>,
};
// 15.21
EqualityExpression = {
RelationalExpression,
BinOp<EqualityExpression, "==", RelationalExpression>,
BinOp<EqualityExpression, "!=", RelationalExpression>,
};
// 15.22
AndExpression = BinOpLeftAssoc<"&", EqualityExpression>;
ExclusiveOrExpression = BinOpLeftAssoc<"^", AndExpression>;
InclusiveOrExpression = BinOpLeftAssoc<"|", ExclusiveOrExpression>;
// 15.23
ConditionalAndExpression = BinOpLeftAssoc<"&&", InclusiveOrExpression>;
// 15.24
ConditionalOrExpression = BinOpLeftAssoc<"||", ConditionalAndExpression>;
// 15.25 TODO
ConditionalExpression: ast::ExprType = {
ConditionalOrExpression,
<cond: Spanned<ConditionalOrExpression>> "?"
<if_branch: Expression> ":"
<else_branch: Spanned<ConditionalExpression>> =>
{
ast::ExprType::Conditional {
cond: cond.into(),
if_branch: if_branch.into(),
else_branch: else_branch.into(),
}
},
// ConditionalOrExpression "?" Expression ":" LambdaExpression,
};
// 15.26 TODO
AssignmentExpression = {
ConditionalExpression,
Assignment,
};
Assignment: ast::ExprType = {
<lhs: Spanned<LeftHandSide>> <op: AssignmentOperator> <rhs: Expression> => {
ast::ExprType::BinOp {
// we know that we only allow assignment operators
op: ast::BinOpType::from_token(&op).unwrap(),
lhs: lhs.into(),
rhs: rhs.into(),
}
}
};
LeftHandSide = {
ExpressionName,
ArrayAccess,
FieldAccess,
};
AssignmentOperator = {
"=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", "|="
};
// 10.6
ArrayInitializer: ast::ExprType = {
"{" <VariableInitializerList?> ","? "}" => {
ast::ExprType::ArrayInit{ items: <>.unwrap_or_default() }
},
};
#[inline]
VariableInitializerList = Comma<VariableInitializer>;
// 6.5
#[inline]
TypeName = Path;
#[inline]
ExpressionName: ast::ExprType = {
Path => ast::ExprType::Name(<>),
};
MethodName = Ident;