use std::ops::Deref;
use crate::syntax::{cst::kind::TreeKind, lexer::token::{Kw, NumLit, Sym, TokenKind}};
use super::{
parser::{CloseHandle, OpenHandle, Parser},
token::{Tt, TtSet},
};
type P<'a, 'b> = &'a mut Parser<'b>;
const PACKAGE_RECOVERY: TtSet = TtSet::new();
pub fn package(p: P) {
let h = p.open();
if p.at(Kw::Package) {
let h = p.open();
p.expect(Kw::Package);
p.expect(Tt::Ident);
p.expect(Sym::Semi);
p.close(h, TreeKind::StartClause);
}
body(p, Kw::Endpackage, &PACKAGE_RECOVERY);
if p.at(Kw::Endpackage) {
p.advance();
end_clause(p);
}
if !p.at(Tt::Eof) {
p.error("Trailing elements after 'endpacakge'");
}
p.close(h, TreeKind::Package);
}
fn end_clause(p: P) {
if p.at(Sym::Colon) {
let h = p.open();
p.advance();
p.expect(Tt::Ident);
p.close(h, TreeKind::EndClause);
}
}
#[rustfmt::skip]
const BODY_RECOVERY: TtSet = TtSet::new().kws(&[
Kw::Endaction, Kw::Endactionvalue, Kw::Endmethod, Kw::Endpar, Kw::Endrule, Kw::Endrules,
Kw::Endseq, Kw::End, Kw::Endcase, Kw::Endfunction, Kw::Endmodule, Kw::Endpackage,
Kw::Endinstance, Kw::Endinterface, Kw::Endtypeclass,
]);
fn body(p: P, endsep: impl Into<Tt>, recovery: &TtSet) {
body_impl(p, endsep, recovery, false, false);
}
fn body_with_subifs(p: P, endsep: impl Into<Tt>, recovery: &TtSet) {
body_impl(p, endsep, recovery, true, false);
}
fn body_with_bvi(p: P, endsep: impl Into<Tt>, recovery: &TtSet) {
body_impl(p, endsep, recovery, false, true);
}
fn body_impl(p: P, endsep: impl Into<Tt>, recovery: &TtSet, has_subifs: bool, bvi: bool) {
let endsep = endsep.into();
let h = p.open();
let first = if bvi { &STMT_BVI_FIRST } else { &STMT_FIRST };
while !p.eof_or(endsep) {
if p.at_set(first) {
stmt_impl(p, has_subifs, bvi);
} else if p.at_set(recovery) {
break;
} else {
p.advance_error("Expected statement");
}
}
p.close(h, TreeKind::Body);
}
#[rustfmt::skip]
const STMT_FIRST: TtSet = TtSet::new()
.inherit(EXPR_OR_TY_START)
.inherit(EXPR_FIRST)
.inherit(TYPE_EXPR_FIRST)
.kws(&[
Kw::Module, Kw::Return, Kw::Function, Kw::Rule, Kw::Method, Kw::If, Kw::Abortif, Kw::Case,
Kw::Repeat, Kw::While, Kw::For, Kw::Break, Kw::Continue, Kw::Goto, Kw::Typedef, Kw::Import,
Kw::Export, Kw::Interface, Kw::Typeclass, Kw::Instance, Kw::Action, Kw::Actionvalue,
Kw::Begin, Kw::Seq, Kw::Par, Kw::Let, Kw::Match,
]);
const STMT_BVI_FIRST: TtSet = TtSet::new()
.inherit(STMT_FIRST)
.kws(&[Kw::Inout, Kw::Parameter, Kw::Method, Kw::Interface])
.tys(&[Tt::Ident]);
const STMT_RECOVERY: TtSet = BODY_RECOVERY.inherit(STMT_FIRST);
fn stmt(p: P) {
stmt_impl(p, false, false);
}
fn stmt_impl(p: P, has_subifs: bool, bvi: bool) {
let h = p.open();
while p.at(Sym::LparenStar) {
attribute_list(p);
}
match p.peek() {
Tt::Ident if bvi && p.at_id("default_clock") => bvi_stub(p),
Tt::Ident if bvi && p.at_id("default_reset") => bvi_stub(p),
Tt::Ident if bvi && p.at_id("no_reset") => bvi_stub(p),
Tt::Ident if bvi && p.at_id("input_clock") => bvi_stub(p),
Tt::Ident if bvi && p.at_id("input_reset") => bvi_stub(p),
Tt::Kw(Kw::Inout) if bvi => bvi_stub(p),
Tt::Ident if bvi && p.at_id("ancestor") => bvi_stub(p),
Tt::Ident if bvi && p.at_id("same_family") => bvi_stub(p),
Tt::Kw(Kw::Parameter) if bvi => bvi_stub(p),
Tt::Ident if bvi && p.at_id("port") => bvi_stub(p),
Tt::Ident if bvi && p.at_id("schedule") => bvi_stub(p),
Tt::Ident if bvi && p.at_id("path") => bvi_stub(p),
Tt::Ident if bvi && p.at_id("unsync") => bvi_stub(p),
Tt::Kw(Kw::Method) if bvi => bvi_stub(p),
Tt::Ident if bvi && p.at_id("output_clock") => bvi_stub(p),
Tt::Ident if bvi && p.at_id("output_reset") => bvi_stub(p),
Tt::Ident if bvi && p.at_id("ifc_inout") => bvi_stub(p),
Tt::Kw(Kw::Interface) if bvi => bvi_interface(p),
Tt::Kw(Kw::Module) => stmt_at_module(p),
Tt::Kw(Kw::Return) => stmt_return(p),
Tt::Kw(Kw::Function) => stmt_function(p),
Tt::Kw(Kw::Rule) => stmt_rule(p),
Tt::Kw(Kw::Method) => stmt_method(p),
Tt::Kw(Kw::If) => stmt_if_else(p),
Tt::Kw(Kw::Abortif) => stmt_abortif(p),
Tt::Kw(Kw::Case) => stmt_case(p),
Tt::Kw(Kw::Repeat) => stmt_repeat(p),
Tt::Kw(Kw::While) => stmt_while(p),
Tt::Kw(Kw::For) => stmt_for(p),
Tt::Kw(Kw::Break) => stmt_break(p),
Tt::Kw(Kw::Continue) => stmt_continue(p),
Tt::Kw(Kw::Goto) => stmt_goto(p),
Tt::Kw(Kw::Typedef) => stmt_typedef(p),
Tt::Kw(Kw::Import) => stmt_import(p),
Tt::Kw(Kw::Export) => stmt_export(p),
Tt::Kw(Kw::Interface) if !has_subifs => stmt_interface(p),
Tt::Kw(Kw::Interface) if has_subifs => stmt_subinterface(p),
Tt::Kw(Kw::Typeclass) => stmt_typeclass(p),
Tt::Kw(Kw::Instance) => stmt_instance(p),
Tt::Kw(Kw::Action) => {
inline_block(
p,
TreeKind::StmtAction,
Kw::Action,
Kw::Endaction,
&STMT_RECOVERY,
);
}
Tt::Kw(Kw::Actionvalue) => {
#[rustfmt::skip]
inline_block(p, TreeKind::StmtActionvalue,
Kw::Actionvalue, Kw::Endactionvalue, &STMT_RECOVERY);
}
Tt::Kw(Kw::Begin) => {
inline_block(p, TreeKind::StmtBlock, Kw::Begin, Kw::End, &STMT_RECOVERY);
}
Tt::Kw(Kw::Seq) => {
inline_block(p, TreeKind::StmtSeq, Kw::Seq, Kw::Endseq, &STMT_RECOVERY);
}
Tt::Kw(Kw::Par) => {
inline_block(p, TreeKind::StmtPar, Kw::Par, Kw::Endpar, &STMT_RECOVERY);
}
ty if EXPR_OR_BIND_START.contains(ty) => stmt_expr_or_bind(p),
_ => {
p.advance_error("Expected statement");
}
}
p.close(h, TreeKind::Stmt);
}
fn bvi_stub(p: P) {
let h = p.open();
while !p.eof_or(Sym::Semi) {
p.advance();
}
p.expect(Sym::Semi);
p.close(h, TreeKind::BviStub);
}
const BVI_INTERFACE_RECOVERY: TtSet = STMT_RECOVERY;
fn bvi_interface(p: P) {
let h = p.open();
p.expect(Kw::Interface);
qual_id(p);
p.expect(Tt::Ident);
p.expect(Sym::Semi);
body_with_bvi(p, Kw::Endinterface, &BVI_INTERFACE_RECOVERY);
p.expect(Kw::Endinterface);
end_clause(p);
p.close(h, TreeKind::BviInterface);
}
const STMT_FOR_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_for(p: P) {
let h = p.open();
p.expect(Kw::For);
p.expect(Sym::Lparen);
let init = p.open();
bind_list(p);
p.close(init, TreeKind::ForInit);
p.expect(Sym::Semi);
expr(p);
p.expect(Sym::Semi);
bind_list(p);
p.expect(Sym::Rparen);
stmt(p);
p.close(h, TreeKind::StmtFor);
}
const BIND_LIST_RECOVERY: TtSet = STMT_FOR_RECOVERY.syms(&[Sym::Semi, Sym::Rparen]);
fn bind_list(p: P) {
let h = p.open();
while !p.eof() && !p.at(Sym::Semi) && !p.at(Sym::Rparen) {
if p.at_set(&EXPR_OR_BIND_START) {
expr_or_bind(p, false);
} else if p.at_set(&BIND_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected variable declaration or assignment");
}
}
p.close(h, TreeKind::BindList);
}
const STMT_INSTANCE_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_instance(p: P) {
let h = p.open();
p.expect(Kw::Instance);
type_expr(p);
if p.at(Kw::Provisos) {
proviso_list(p);
}
p.expect(Sym::Semi);
instance_body(p);
p.expect(Kw::Endinstance);
end_clause(p);
p.close(h, TreeKind::StmtInstance);
}
const INSTANCE_BODY_RECOVERY: TtSet = STMT_INSTANCE_RECOVERY.kws(&[Kw::Endinstance]);
const INSTANCE_ITEM_RECOVERY: TtSet = INSTANCE_BODY_RECOVERY
.tys(&[Tt::Ident])
.kws(&[Kw::Function, Kw::Module]);
fn instance_body(p: P) {
let h = p.open();
while !p.eof_or(Kw::Endinstance) {
if p.at(Kw::Function) {
instance_function(p);
} else if p.at(Kw::Module) {
instance_module(p);
} else if p.at(Tt::Ident) {
instance_var(p);
} else if p.at_set(&INSTANCE_BODY_RECOVERY) {
break;
} else {
p.advance_error("Expected instance item");
}
}
p.close(h, TreeKind::InstanceBody);
}
fn instance_var(p: P) {
let h = p.open();
p.expect(Tt::Ident);
p.expect(Sym::Eq);
expr(p);
p.expect(Sym::Semi);
p.close(h, TreeKind::InstanceVar);
}
fn instance_module(p: P) {
let h = p.open();
p.expect(Kw::Module);
if p.eat(Sym::Lbracket) {
type_expr(p);
p.expect(Sym::Rbracket);
}
p.expect(Tt::Ident);
if p.at(Sym::Hash) {
module_param_list(p);
}
if p.at(Sym::Lparen) {
module_port_list(p)
}
if p.at(Kw::Provisos) {
proviso_list(p);
}
p.expect(Sym::Semi);
body_with_subifs(p, Kw::Endmodule, &INSTANCE_ITEM_RECOVERY);
p.expect(Kw::Endmodule);
end_clause(p);
p.close(h, TreeKind::InstanceModule);
}
fn instance_function(p: P) {
let h = p.open();
p.expect(Kw::Function);
typed_fun_name(p);
if p.at(Sym::Lparen) {
function_param_list(p);
}
if p.eat(Sym::Eq) {
expr(p);
p.expect(Sym::Semi);
} else {
p.expect(Sym::Semi);
body(p, Kw::Endfunction, &INSTANCE_ITEM_RECOVERY);
p.expect(Kw::Endfunction);
end_clause(p);
}
p.close(h, TreeKind::InstanceFunction);
}
const STMT_TYPECLASS_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_typeclass(p: P) {
let h = p.open();
p.expect(Kw::Typeclass);
p.expect(Tt::Ident);
if p.at(Sym::Hash) {
typedef_param_list(p);
}
if p.at(Kw::Provisos) {
proviso_list(p);
}
if p.at_id("dependencies") {
dependency_list(p);
}
p.expect(Sym::Semi);
typeclass_body(p);
p.expect(Kw::Endtypeclass);
end_clause(p);
p.close(h, TreeKind::StmtTypeclass);
}
const TYPECLASS_BODY_RECOVERY: TtSet = STMT_TYPECLASS_RECOVERY.kws(&[Kw::Endtypeclass]);
const TYPECLASS_ITEM_RECOVERY: TtSet = TYPECLASS_BODY_RECOVERY
.inherit(TYPE_EXPR_FIRST)
.kws(&[Kw::Function, Kw::Module]);
fn typeclass_body(p: P) {
let h = p.open();
while !p.eof_or(Kw::Endtypeclass) {
if p.at(Kw::Function) {
typeclass_function(p);
} else if p.at(Kw::Module) {
typeclass_module(p);
} else if p.at_set(&TYPE_EXPR_FIRST) {
typeclass_var(p);
} else if p.at_set(&TYPECLASS_BODY_RECOVERY) {
break;
} else {
p.advance_error("Expected typeclass item");
}
}
p.close(h, TreeKind::TypeclassBody);
}
fn typeclass_var(p: P) {
let h = p.open();
type_expr(p);
p.expect(Tt::Ident);
if p.eat(Sym::Eq) {
expr(p);
}
p.expect(Sym::Semi);
p.close(h, TreeKind::TypeclassVar);
}
fn typeclass_module(p: P) {
let h = p.open();
p.expect(Kw::Module);
if p.eat(Sym::Lbracket) {
type_expr(p);
p.expect(Sym::Rbracket);
}
p.expect(Tt::Ident);
if p.at(Sym::Hash) {
module_param_list(p);
}
if p.at(Sym::Lparen) {
module_port_list(p)
}
if p.at(Kw::Provisos) {
proviso_list(p);
}
p.expect(Sym::Semi);
match p.peek() {
Tt::Kw(Kw::Function) | Tt::Kw(Kw::Module) | Tt::Kw(Kw::Endtypeclass) => (),
_ => {
body_with_subifs(p, Kw::Endmodule, &TYPECLASS_ITEM_RECOVERY);
p.expect(Kw::Endmodule);
end_clause(p);
}
}
p.close(h, TreeKind::TypeclassModule);
}
fn typeclass_function(p: P) {
let h = p.open();
p.expect(Kw::Function);
type_expr(p);
p.expect(Tt::Ident);
if p.at(Sym::Lparen) {
function_param_list(p);
}
if p.eat(Sym::Eq) {
expr(p);
p.expect(Sym::Semi);
} else {
p.expect(Sym::Semi);
match p.peek() {
Tt::Kw(Kw::Function) | Tt::Kw(Kw::Module) | Tt::Kw(Kw::Endtypeclass) => (),
_ => {
body(p, Kw::Endfunction, &TYPECLASS_ITEM_RECOVERY);
p.expect(Kw::Endfunction);
end_clause(p);
}
}
}
p.close(h, TreeKind::TypeclassFunction);
}
const DEPENDENCY_LIST_RECOVERY: TtSet = STMT_TYPECLASS_RECOVERY.syms(&[Sym::Semi]);
fn dependency_list(p: P) {
let h = p.open();
if p.at_id("dependencies") {
soft_kw(p);
} else {
p.error("Expected keyword 'dependencies'");
}
p.expect(Sym::Lparen);
while !p.eof_or(Sym::Rparen) {
if p.at_set(&DEPENDENCY_FIRST) {
dependency(p);
if !p.at(Sym::Rparen) {
p.expect(Sym::Comma);
}
} else if p.at_set(&DEPENDENCY_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected dependency");
}
}
p.expect(Sym::Rparen);
p.close(h, TreeKind::DependencyList);
}
const DEPENDENCY_FIRST: TtSet = TtSet::new()
.inherit(TYPE_EXPR_FIRST)
.tys(&[Tt::Sym(Sym::Lparen)]);
const DEPENDENCY_RECOVERY: TtSet = STMT_TYPECLASS_RECOVERY
.inherit(DEPENDENCY_FIRST)
.syms(&[Sym::Rparen]);
fn dependency(p: P) {
let h = p.open();
if p.at(Sym::Lparen) {
dependency_type_list(p);
} else {
type_expr(p);
}
if p.at_id("determines") {
soft_kw(p);
} else {
p.error("Expected keyword 'determines'");
}
if p.at(Sym::Lparen) {
dependency_type_list(p);
} else {
type_expr(p);
}
p.close(h, TreeKind::Dependency);
}
const DEPENDENCY_TYPE_LIST_RECOVERY: TtSet = DEPENDENCY_RECOVERY;
fn dependency_type_list(p: P) {
let h = p.open();
p.expect(Sym::Lparen);
while !p.eof_or(Sym::Rparen) {
if p.at_set(&TYPE_EXPR_FIRST) {
type_expr(p);
if !p.at(Sym::Rparen) {
p.expect(Sym::Comma);
}
} else if p.at_set(&DEPENDENCY_TYPE_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected type name");
}
}
p.expect(Sym::Rparen);
p.close(h, TreeKind::DependencyTypeList);
}
const STMT_TYPEDEF_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_typedef(p: P) {
let h = p.open();
p.expect(Kw::Typedef);
match p.peek() {
Tt::Kw(Kw::Enum) => typedef_enum(p),
Tt::Kw(Kw::Struct) => typedef_struct(p),
Tt::Kw(Kw::Union) => typedef_union(p),
_ => typedef_alias(p),
}
p.close(h, TreeKind::StmtTypedef);
}
const TYPEDEF_UNION_RECOVERY: TtSet = STMT_TYPEDEF_RECOVERY
.inherit(TYPE_EXPR_FIRST)
.kws(&[Kw::Struct, Kw::Union, Kw::Void])
.syms(&[Sym::Rbrace]);
fn typedef_union(p: P) {
let h = p.open();
p.expect(Kw::Union);
p.expect(Kw::Tagged);
if p.at(Sym::Lbrace) {
typedef_field_list(p);
} else {
p.error("Expected union variants");
}
p.expect(Tt::Ident);
if p.at(Sym::Hash) {
typedef_param_list(p);
}
if p.at(Kw::Deriving) {
derives(p);
}
p.expect(Sym::Semi);
p.close(h, TreeKind::TypedefUnion);
}
const TYPEDEF_STRUCT_RECOVERY: TtSet = STMT_TYPEDEF_RECOVERY
.inherit(TYPE_EXPR_FIRST)
.kws(&[Kw::Struct, Kw::Union, Kw::Void])
.syms(&[Sym::Rbrace]);
fn typedef_struct(p: P) {
let h = p.open();
p.expect(Kw::Struct);
if p.at(Sym::Lbrace) {
typedef_field_list(p);
} else {
p.error("Expected struct fields");
}
p.expect(Tt::Ident);
if p.at(Sym::Hash) {
typedef_param_list(p);
}
if p.at(Kw::Deriving) {
derives(p);
}
p.expect(Sym::Semi);
p.close(h, TreeKind::TypedefStruct);
}
const TYPEDEF_ENUM_RECOVERY: TtSet = STMT_TYPEDEF_RECOVERY;
fn typedef_enum(p: P) {
let h = p.open();
p.expect(Kw::Enum);
if p.at(Sym::Lbrace) {
enum_variant_list(p);
} else {
p.error("Expected enum variants");
}
p.expect(Tt::Ident);
if p.at(Kw::Deriving) {
derives(p);
}
p.expect(Sym::Semi);
p.close(h, TreeKind::TypedefEnum);
}
const TYPEDEF_ALIAS_RECOVERY: TtSet = STMT_TYPEDEF_RECOVERY;
fn typedef_alias(p: P) {
let h = p.open();
type_expr(p);
p.expect(Tt::Ident);
if p.at(Sym::Hash) {
typedef_param_list(p);
}
p.expect(Sym::Semi);
p.close(h, TreeKind::TypedefAlias);
}
const TYPEDEF_FIELD_LIST_RECOVERY: TtSet = STMT_TYPEDEF_RECOVERY.tys(&[Tt::Ident]);
fn typedef_field_list(p: P) {
let h = p.open();
p.expect(Sym::Lbrace);
while !p.eof_or(Sym::Rbrace) {
if p.at(Kw::Struct) {
typedef_struct(p);
} else if p.at(Kw::Union) {
typedef_union(p);
} else if p.at(Kw::Void) {
typedef_void_field(p);
} else if p.at_set(&TYPE_EXPR_FIRST) {
typedef_field(p);
} else if p.at_set(&TYPEDEF_FIELD_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected union variant");
}
}
p.expect(Sym::Rbrace);
p.close(h, TreeKind::TypedefFieldList);
}
fn typedef_void_field(p: P) {
let h = p.open();
p.expect(Kw::Void);
p.expect(Tt::Ident);
p.expect(Sym::Semi);
p.close(h, TreeKind::StructField);
}
const TYPEDEF_FIELD_RECOVERY: TtSet = ENUM_VARIANT_LIST_RECOVERY.syms(&[Sym::Rbrace]);
fn typedef_field(p: P) {
let h = p.open();
type_expr(p);
p.expect(Tt::Ident);
p.expect(Sym::Semi);
p.close(h, TreeKind::StructField);
}
const ENUM_VARIANT_LIST_RECOVERY: TtSet = TYPEDEF_ENUM_RECOVERY.tys(&[Tt::Ident]);
fn enum_variant_list(p: P) {
let h = p.open();
p.expect(Sym::Lbrace);
while !p.eof_or(Sym::Rbrace) {
if p.at(Tt::Ident) {
enum_variant(p);
if !p.at(Sym::Rbrace) {
p.expect(Sym::Comma);
}
} else if p.at_set(&ENUM_VARIANT_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected enum variant");
}
}
p.expect(Sym::Rbrace);
p.close(h, TreeKind::EnumVariantList);
}
fn enum_variant(p: P) {
let h = p.open();
p.expect(Tt::Ident);
if p.at(Sym::Lbracket) {
subscript(p);
}
if p.eat(Sym::Eq) {
expr(p);
}
p.close(h, TreeKind::EnumVariant);
}
const DERIVES_RECOVERY: TtSet = TYPEDEF_UNION_RECOVERY
.inherit(TYPEDEF_STRUCT_RECOVERY)
.inherit(TYPEDEF_ENUM_RECOVERY)
.syms(&[Sym::Semi]);
fn derives(p: P) {
let h = p.open();
p.expect(Kw::Deriving);
p.expect(Sym::Lparen);
while !p.eof_or(Sym::Rparen) {
if p.at(Tt::Ident) {
qual_id(p);
if !p.at(Sym::Rparen) {
p.expect(Sym::Comma);
}
} else if p.at_set(&DERIVES_RECOVERY) {
break;
} else {
p.advance_error("Expected typeclass name");
}
}
p.expect(Sym::Rparen);
p.close(h, TreeKind::Derives);
}
const STMT_INTERFACE_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_interface(p: P) {
let h = p.open();
p.expect(Kw::Interface);
p.expect(Tt::Ident);
if p.at(Sym::Hash) {
typedef_param_list(p);
}
p.expect(Sym::Semi);
interface_body(p);
p.expect(Kw::Endinterface);
end_clause(p);
p.close(h, TreeKind::StmtInterface);
}
const INTERFACE_BODY_RECOVERY: TtSet = STMT_INTERFACE_RECOVERY.kws(&[Kw::Endinterface]);
fn interface_body(p: P) {
let h = p.open();
while !p.eof_or(Kw::Endinterface) {
if p.at_set(&INTERFACE_ITEM_FIRST) {
interface_item(p);
} else if p.at_set(&INTERFACE_BODY_RECOVERY) {
break;
} else {
p.advance_error("Expected interface item");
}
}
p.close(h, TreeKind::InterfaceBody);
}
const INTERFACE_ITEM_FIRST: TtSet = TtSet::new()
.syms(&[Sym::LparenStar])
.kws(&[Kw::Method, Kw::Interface]);
const INTERFACE_ITEM_RECOVERY: TtSet = INTERFACE_BODY_RECOVERY;
fn interface_item(p: P) {
let h = p.open();
while p.at(Sym::LparenStar) {
attribute_list(p);
}
match p.peek() {
Tt::Kw(Kw::Method) => interface_item_method(p),
Tt::Kw(Kw::Interface) => interface_item_subinterface(p),
_ => p.error("Expected interface item"),
}
p.close(h, TreeKind::InterfaceItem);
}
fn interface_item_method(p: P) {
let h = p.open();
p.expect(Kw::Method);
type_expr(p);
p.expect(Tt::Ident);
if p.at(Sym::Lparen) {
function_param_list(p);
}
if p.at(Kw::Provisos) {
proviso_list(p);
}
p.expect(Sym::Semi);
p.close(h, TreeKind::InterfaceItemMethod);
}
fn interface_item_subinterface(p: P) {
let h = p.open();
p.expect(Kw::Interface);
type_expr(p);
p.expect(Tt::Ident);
p.expect(Sym::Semi);
p.close(h, TreeKind::InterfaceItemSubinterface);
}
const TYPEDEF_PARAM_LIST_RECOVERY: TtSet = TtSet::new()
.inherit(STMT_TYPECLASS_RECOVERY)
.inherit(TYPEDEF_UNION_RECOVERY)
.inherit(TYPEDEF_STRUCT_RECOVERY)
.inherit(TYPEDEF_ALIAS_RECOVERY)
.inherit(STMT_INTERFACE_RECOVERY)
.kws(&[Kw::Provisos, Kw::Deriving])
.syms(&[Sym::Semi]);
fn typedef_param_list(p: P) {
let h = p.open();
p.expect(Sym::Hash);
p.expect(Sym::Lparen);
while !p.eof_or(Sym::Rparen) {
if p.at_set(&TYPEDEF_PARAM_FIRST) {
typedef_param(p);
if !p.at(Sym::Rparen) {
p.expect(Sym::Comma);
}
} else if p.at_set(&TYPEDEF_PARAM_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected type parameter");
}
}
p.expect(Sym::Rparen);
p.close(h, TreeKind::TypedefParamList);
}
const TYPEDEF_PARAM_FIRST: TtSet =
TtSet::new()
.tys(&[Tt::Ident])
.kws(&[Kw::Parameter, Kw::String, Kw::Type]);
fn typedef_param(p: P) {
let h = p.open();
p.eat(Kw::Parameter);
match p.peek_kind() {
Some(TokenKind::Ident(str)) if str == "numeric" => soft_kw(p),
Some(TokenKind::Kw(Kw::String)) => p.advance(),
_ => (),
}
p.expect(Kw::Type);
p.expect(Tt::Ident);
p.close(h, TreeKind::TypedefParam);
}
const STMT_SUBINTERFACE_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_subinterface(p: P) {
let h = p.open();
p.expect(Kw::Interface);
qual_id(p);
if p.at(Tt::Ident) {
qual_id(p);
}
if p.eat(Sym::Eq) {
expr(p);
p.expect(Sym::Semi);
} else {
p.expect(Sym::Semi);
body_with_subifs(p, Kw::Endinterface, &STMT_SUBINTERFACE_RECOVERY);
p.expect(Kw::Endinterface);
end_clause(p);
}
p.close(h, TreeKind::StmtSubinterface);
}
const DECL_MATCH_RECOVERY: TtSet = EXPR_OR_BIND_RECOVERY;
fn decl_match(p: P) -> CloseHandle {
let h = p.open();
p.expect(Kw::Match);
pattern(p);
if !p.eat(Sym::Eq) && !p.eat(Sym::LtMinus) {
p.error("Expected assignment operator");
}
expr(p);
p.close(h, TreeKind::BindMatch)
}
fn stmt_goto(p: P) {
let h = p.open();
p.expect(Kw::Goto);
p.expect(Tt::Ident);
p.expect(Sym::Semi);
p.close(h, TreeKind::StmtGoto);
}
fn stmt_continue(p: P) {
let h = p.open();
p.expect(Kw::Continue);
p.expect(Sym::Semi);
p.close(h, TreeKind::StmtContinue);
}
fn stmt_break(p: P) {
let h = p.open();
p.expect(Kw::Break);
p.expect(Sym::Semi);
p.close(h, TreeKind::StmtBreak);
}
fn stmt_while(p: P) {
let h = p.open();
p.expect(Kw::While);
p.expect(Sym::Lparen);
expr(p);
p.expect(Sym::Rparen);
stmt(p);
p.close(h, TreeKind::StmtWhile);
}
fn stmt_repeat(p: P) {
let h = p.open();
p.expect(Kw::Repeat);
p.expect(Sym::Lparen);
expr(p);
p.expect(Sym::Rparen);
stmt(p);
p.close(h, TreeKind::StmtRepeat);
}
fn stmt_case(p: P) {
let h = p.open();
case(p);
p.close(h, TreeKind::StmtCase);
}
fn stmt_abortif(p: P) {
let h = p.open();
p.expect(Kw::Abortif);
p.expect(Sym::Lparen);
expr(p);
p.expect(Sym::Rparen);
stmt(p);
if p.eat(Kw::With) {
stmt(p);
}
p.close(h, TreeKind::StmtAbortif);
}
fn stmt_if_else(p: P) {
let h = p.open();
p.expect(Kw::If);
p.expect(Sym::Lparen);
expr(p);
p.expect(Sym::Rparen);
stmt(p);
if p.eat(Kw::Else) {
stmt(p);
}
p.close(h, TreeKind::StmtIfElse);
}
const STMT_METHOD_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_method(p: P) {
let h = p.open();
p.expect(Kw::Method);
typed_fun_name(p);
if p.at(Sym::Lparen) {
function_param_list(p);
}
if p.at(Kw::Provisos) {
proviso_list(p);
}
if p.eat(Kw::If) {
expr(p);
}
if p.eat(Sym::Eq) {
expr(p);
p.expect(Sym::Semi);
} else {
p.expect(Sym::Semi);
body(p, Kw::Endmethod, &STMT_METHOD_RECOVERY);
p.expect(Kw::Endmethod);
end_clause(p);
}
p.close(h, TreeKind::StmtMethod);
}
const TYPED_FUN_NAME_RECOVERY: TtSet = TtSet::new()
.inherit(INSTANCE_ITEM_RECOVERY)
.inherit(STMT_RECOVERY)
.syms(&[Sym::Lparen, Sym::Eq, Sym::Semi])
.kws(&[Kw::Provisos, Kw::If]);
fn typed_fun_name(p: P) {
let h: OpenHandle = p.open();
if p.at(Tt::Ident) {
match p.nth(1) {
Tt::Sym(Sym::Hash) | Tt::Sym(Sym::Lbracket) | Tt::Ident | Tt::Sym(Sym::ColonColon) => {
type_expr(p);
while p.eat(Sym::Lbracket) {
p.expect(Sym::Rbracket);
}
}
_ => (),
}
p.expect(Tt::Ident);
} else {
type_expr(p);
while p.eat(Sym::Lbracket) {
p.expect(Sym::Rbracket);
}
p.expect(Tt::Ident);
}
p.close(h, TreeKind::TypedFunName);
}
const STMT_RULE_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_rule(p: P) {
let h = p.open();
p.expect(Kw::Rule);
p.expect(Tt::Ident);
if p.eat(Kw::If) || p.at_set(&EXPR_FIRST) {
expr(p);
}
p.expect(Sym::Semi);
body(p, Kw::Endrule, &STMT_RULE_RECOVERY);
p.expect(Kw::Endrule);
end_clause(p);
p.close(h, TreeKind::StmtRule);
}
const STMT_FUNCTION_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_function(p: P) {
let h = p.open();
p.expect(Kw::Function);
typed_fun_name(p);
if p.at(Sym::Lparen) {
function_param_list(p);
}
if p.at(Kw::Provisos) {
proviso_list(p);
}
if p.eat(Sym::Eq) {
expr(p);
p.expect(Sym::Semi);
} else {
p.expect(Sym::Semi);
body(p, Kw::Endfunction, &STMT_FUNCTION_RECOVERY);
p.expect(Kw::Endfunction);
end_clause(p);
}
p.close(h, TreeKind::StmtFunction);
}
fn stmt_return(p: P) {
let h = p.open();
p.expect(Kw::Return);
if !p.at(Sym::Semi) {
expr(p);
}
p.expect(Sym::Semi);
p.close(h, TreeKind::StmtReturn);
}
const STMT_EXPR_OR_BIND_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_expr_or_bind(p: P) {
let h = p.open();
expr_or_bind(p, true);
p.expect(Sym::Semi);
p.close(h, TreeKind::StmtExprOrBind);
}
fn stmt_with_type(p: P, ty: CloseHandle) -> CloseHandle {
let inner = decl_with_type(p, ty, true);
let h = p.open_before(inner);
p.expect(Sym::Semi);
p.close(h, TreeKind::StmtExprOrBind)
}
const EXPR_OR_BIND_START: TtSet = TtSet::new()
.inherit(EXPR_OR_TY_START)
.inherit(EXPR_FIRST)
.inherit(TYPE_EXPR_FIRST)
.kws(&[Kw::Let, Kw::Match]);
const EXPR_OR_BIND_RECOVERY: TtSet = TtSet::new()
.inherit(BIND_LIST_RECOVERY)
.inherit(STMT_EXPR_OR_BIND_RECOVERY)
.syms(&[Sym::Semi]);
fn expr_or_bind(p: P, multiple_inits: bool) -> CloseHandle {
match p.peek() {
Tt::Kw(Kw::Let) => decl_let(p, multiple_inits),
Tt::Kw(Kw::Match) => decl_match(p),
ty if EXPR_OR_TY_START.contains(ty) => match expr_or_ty(p, true) {
ExprOrTy::Expr(expr) => bind_with_expr(p, expr),
ExprOrTy::Ty(ty) => decl_with_type(p, ty, multiple_inits),
},
ty if EXPR_FIRST.contains(ty) => {
let expr = expr(p);
bind_with_expr(p, expr)
}
ty if TYPE_EXPR_FIRST.contains(ty) => {
let ty = type_expr(p);
decl_with_type(p, ty, multiple_inits)
}
_ => p.error_empty("Expected variable declaration or assignment"),
}
}
fn decl_let(p: P, multiple_inits: bool) -> CloseHandle {
let h = p.open();
p.expect(Kw::Let);
var_init_list_or_inst(p, multiple_inits);
p.close(h, TreeKind::BindDecl)
}
const DECL_WITH_TYPE_RECOVERY: TtSet = EXPR_OR_BIND_RECOVERY;
fn decl_with_type(p: P, ty: CloseHandle, multiple_inits: bool) -> CloseHandle {
let h: OpenHandle = p.open_before(ty);
var_init_list_or_inst(p, multiple_inits);
p.close(h, TreeKind::BindDecl)
}
const VAR_INIT_LIST_RECOVERY: TtSet = DECL_WITH_TYPE_RECOVERY;
fn var_init_list_or_inst(p: P, multiple_inits: bool) {
let h: OpenHandle = p.open();
if p.at(Tt::Ident) && p.nth_is(1, Sym::Lparen) {
p.advance_error("Long-form module instantiation currently not supported in blues-lsp");
} else {
var_init(p);
}
if multiple_inits && p.eat(Sym::Comma) {
while !p.eof_or(Sym::Semi) {
if p.at_set(&VAR_INIT_FIRST) {
var_init(p);
if !p.at(Sym::Semi) {
p.expect(Sym::Comma);
}
} else if p.at_set(&VAR_INIT_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected variable name");
}
}
}
p.close(h, TreeKind::VarInitList);
}
const VAR_INIT_FIRST: TtSet = TtSet::new().tys(&[Tt::Ident]).syms(&[Sym::Lbrace]);
fn var_init(p: P) {
let h = p.open();
match p.peek() {
Tt::Ident => {
p.advance();
}
Tt::Sym(Sym::Lbrace) => {
decl_pattern_list(p);
}
_ => {
p.error("Expected variable name");
}
}
while p.at(Sym::Lbracket) {
array_dim(p);
}
if p.eat(Sym::Eq) || p.eat(Sym::LtMinus) || p.eat(Sym::LtEq) {
expr(p);
}
p.close(h, TreeKind::VarInit);
}
fn array_dim(p: P) {
let h = p.open();
p.expect(Sym::Lbracket);
expr(p);
p.expect(Sym::Rbracket);
p.close(h, TreeKind::ArrayDim);
}
fn bind_with_expr(p: P, h: CloseHandle) -> CloseHandle {
match p.peek() {
Tt::Sym(Sym::Eq) | Tt::Sym(Sym::LtMinus) | Tt::Sym(Sym::LtEq) => {
let h = p.open_before(h);
p.advance();
expr(p);
p.close(h, TreeKind::BindAssign)
}
_ => h, }
}
const DECL_PATTERN_LIST_RECOVERY: TtSet =
VAR_INIT_FIRST.syms(&[Sym::Lbracket, Sym::Eq, Sym::LtMinus, Sym::LtEq]);
fn decl_pattern_list(p: P) {
let h = p.open();
p.expect(Sym::Lbrace);
while !p.eof_or(Sym::Rbrace) {
if p.at_set(&DECL_PATTERN_START) {
decl_pattern(p);
if !p.at(Sym::Rbrace) {
p.expect(Sym::Comma);
}
} else if p.at_set(&DECL_PATTERN_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected bind pattern");
}
}
p.expect(Sym::Rbrace);
p.close(h, TreeKind::DeclPatternList);
}
const DECL_PATTERN_START: TtSet = TtSet::new().tys(&[Tt::Ident]).syms(&[Sym::DotStar]);
fn decl_pattern(p: P) {
let h = p.open();
match p.peek() {
Tt::Ident => {
p.advance();
}
Tt::Sym(Sym::DotStar) => p.advance(),
_ => {
p.error("Expected bind pattern");
p.close(h, TreeKind::Error);
return;
}
}
p.close(h, TreeKind::DeclPattern);
}
const ATTRIBUTE_LIST_RECOVERY: TtSet = TtSet::new()
.inherit(STMT_FIRST)
.inherit(STMT_RECOVERY)
.inherit(INTERFACE_ITEM_FIRST)
.inherit(INTERFACE_ITEM_RECOVERY)
.inherit(MODULE_PARAM_FIRST)
.inherit(MODULE_PARAM_RECOVERY)
.inherit(MODULE_PORT_FIRST)
.inherit(MODULE_PORT_RECOVERY)
.inherit(FUNCTION_PARAM_FIRST)
.inherit(FUNCTION_PARAM_RECOVERY)
.inherit(EXPR_PREFIXED_RECOVERY)
.inherit(EXPR_PREFIXED_FIRST);
fn attribute_list(p: P) {
let h = p.open();
p.assert(Sym::LparenStar);
while !p.eof_or(Sym::StarRparen) {
if p.at_set(&ATTRIBUTE_FIRST) {
attribute(p);
if !p.at(Sym::StarRparen) {
p.expect(Sym::Comma);
}
} else if p.at_set(&ATTRIBUTE_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected attribute");
}
}
p.expect(Sym::StarRparen);
p.close(h, TreeKind::AttributeList);
}
const ATTRIBUTE_FIRST: TtSet =
TtSet::new()
.tys(&[Tt::Ident])
.kws(&[Kw::ClockedBy, Kw::ResetBy, Kw::Parameter]);
const ATTRIBUTE_RECOVERY: TtSet = ATTRIBUTE_LIST_RECOVERY.syms(&[Sym::StarRparen]);
fn attribute(p: P) {
let h = p.open();
attribute_name(p);
if p.eat(Sym::Eq) {
attribute_value(p);
}
p.close(h, TreeKind::Attribute);
}
fn attribute_name(p: P) {
let h = p.open();
match p.peek() {
Tt::Ident | Tt::Kw(Kw::ClockedBy) | Tt::Kw(Kw::ResetBy) | Tt::Kw(Kw::Parameter) => {
p.advance();
}
_ => p.error("Missing attribute name"),
}
p.close(h, TreeKind::AttributeName);
}
const ATTRIBUTE_VALUE_FIRST: TtSet = TtSet::new()
.tys(&[Tt::Num(NumLit::Int), Tt::Str])
.syms(&[Sym::Lbrace]);
const ATTRIBUTE_VALUE_RECOVERY: TtSet = ATTRIBUTE_RECOVERY.syms(&[Sym::Rbrace]);
fn attribute_value(p: P) {
let h = p.open();
match p.peek() {
Tt::Num(NumLit::Int) | Tt::Str => p.advance(),
Tt::Sym(Sym::Lbrace) => {
attribute_value_list(p);
}
_ => p.error("Expected attribute value"),
}
p.close(h, TreeKind::AttributeValue);
}
const ATTRIBUTE_VALUE_LIST_RECOVERY: TtSet = ATTRIBUTE_VALUE_RECOVERY;
fn attribute_value_list(p: P) {
let h = p.open();
p.expect(Sym::Lbrace);
while !p.eof_or(Sym::Rbrace) {
if p.at_set(&ATTRIBUTE_VALUE_FIRST) {
attribute_value(p);
if !p.at(Sym::Rbrace) {
p.expect(Sym::Comma);
}
} else if p.at_set(&ATTRIBUTE_VALUE_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected attribute value");
}
}
p.expect(Sym::Rbrace);
p.close(h, TreeKind::AttributeValueList);
}
const STMT_IMPORT_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_import(p: P) {
let h = p.open();
p.expect(Kw::Import);
if let Some(TokenKind::Str(str)) = p.peek_kind() {
match str.deref() {
"BVI" => {
p.advance();
if p.eat(Sym::Lbracket) {
type_expr(p);
p.expect(Sym::Rbracket);
}
if p.eat(Tt::Ident) {
p.expect(Sym::Eq);
}
p.expect(Kw::Module);
p.expect(Tt::Ident);
if p.at(Sym::Hash) {
module_param_list(p);
}
if p.at(Sym::Lparen) {
module_port_list(p)
}
if p.at(Kw::Provisos) {
proviso_list(p);
}
p.expect(Sym::Semi);
body_with_bvi(p, Kw::Endmodule, &STMT_IMPORT_RECOVERY);
p.expect(Kw::Endmodule);
end_clause(p);
p.close(h, TreeKind::StmtBvi);
return;
}
"BDPI" => {
p.advance();
if p.eat(Tt::Ident) {
p.expect(Sym::Eq);
}
function_proto(p);
if p.at(Kw::Provisos) {
proviso_list(p);
}
p.expect(Sym::Semi);
p.close(h, TreeKind::StmtBdpi);
return;
}
_ => p.advance_error("Invalid import type"),
};
};
while !p.eof_or(Sym::Semi) {
if p.at(Tt::Ident) {
import_item(p);
if !p.at(Sym::Semi) {
p.expect(Sym::Comma);
}
} else if p.at_set(&STMT_IMPORT_RECOVERY) {
break;
} else {
p.advance_error("Expected import item");
}
}
p.expect(Sym::Semi);
p.close(h, TreeKind::StmtImport);
}
fn import_item(p: P) {
let h = p.open();
p.expect(Tt::Ident);
p.expect(Sym::ColonColon);
p.expect(Sym::Star);
p.close(h, TreeKind::ImportItem);
}
const STMT_EXPORT_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_export(p: P) {
let h = p.open();
p.expect(Kw::Export);
while !p.eof_or(Sym::Semi) {
if p.at(Tt::Ident) {
export_item(p);
if !p.at(Sym::Semi) {
p.expect(Sym::Comma);
}
} else if p.at_set(&STMT_EXPORT_RECOVERY) {
break;
} else {
p.advance_error("Expected export item");
}
}
p.expect(Sym::Semi);
p.close(h, TreeKind::StmtExport);
}
fn export_item(p: P) {
let h = p.open();
p.expect(Tt::Ident);
if p.eat(Sym::ColonColon) {
p.expect(Sym::Star);
} else if p.eat(Sym::Lparen) {
p.expect(Sym::DotDot);
p.expect(Sym::Rparen);
}
p.close(h, TreeKind::ExportItem);
}
const STMT_MODULE_RECOVERY: TtSet = STMT_RECOVERY;
fn stmt_at_module(p: P) {
let h = p.open();
p.expect(Kw::Module);
let has_mod_ty = p.eat(Sym::Lbracket);
if has_mod_ty {
type_expr(p);
p.expect(Sym::Rbracket);
}
if !has_mod_ty && p.at(Sym::Hash) {
let ty = p.close(h, TreeKind::TypeModule);
let ty = type_with(p, ty);
if p.at(Sym::Semi) {
let expr = expr_module_with(p, ty);
bind_with_expr(p, expr);
} else {
stmt_with_type(p, ty);
}
return;
}
p.expect(Tt::Ident);
if p.at(Sym::Hash) {
module_param_list(p);
}
if p.at(Sym::Lparen) {
module_port_list(p)
}
if p.at(Kw::Provisos) {
proviso_list(p);
}
p.expect(Sym::Semi);
body_with_subifs(p, Kw::Endmodule, &STMT_RECOVERY);
p.expect(Kw::Endmodule);
end_clause(p);
p.close(h, TreeKind::StmtModule);
}
const MODULE_PARAM_LIST_RECOVERY: TtSet = TtSet::new()
.inherit(INSTANCE_ITEM_RECOVERY)
.inherit(TYPECLASS_ITEM_RECOVERY)
.inherit(STMT_IMPORT_RECOVERY)
.inherit(STMT_MODULE_RECOVERY)
.syms(&[Sym::Lparen, Sym::Semi])
.kws(&[Kw::Provisos]);
fn module_param_list(p: P) {
let h = p.open();
p.expect(Sym::Hash);
p.expect(Sym::Lparen);
while !p.eof_or(Sym::Rparen) {
if p.at_set(&MODULE_PARAM_FIRST) {
module_param(p);
if !p.at(Sym::Rparen) {
p.expect(Sym::Comma);
}
} else if p.at_set(&MODULE_PARAM_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected type parameter");
}
}
p.expect(Sym::Rparen);
p.close(h, TreeKind::ModuleParamList);
}
const MODULE_PARAM_FIRST: TtSet = TtSet::new()
.inherit(TYPED_NAME_FIRST)
.syms(&[Sym::LparenStar])
.kws(&[Kw::Parameter]);
const MODULE_PARAM_RECOVERY: TtSet = MODULE_PARAM_LIST_RECOVERY.syms(&[Sym::Rparen]);
fn module_param(p: P) {
let h = p.open();
while p.at(Sym::LparenStar) {
attribute_list(p);
}
p.eat(Kw::Parameter);
typed_name(p);
p.close(h, TreeKind::ModuleParam);
}
const MODULE_PORT_LIST_RECOVERY: TtSet = TtSet::new()
.inherit(INSTANCE_ITEM_RECOVERY)
.inherit(TYPECLASS_ITEM_RECOVERY)
.inherit(STMT_IMPORT_RECOVERY)
.inherit(STMT_MODULE_RECOVERY)
.syms(&[Sym::Semi])
.kws(&[Kw::Provisos]);
fn module_port_list(p: P) {
let h = p.open();
p.expect(Sym::Lparen);
while !p.eof_or(Sym::Rparen) {
if p.at_set(&MODULE_PORT_FIRST) {
module_port(p);
if !p.at(Sym::Rparen) {
p.expect(Sym::Comma);
}
} else if p.at_set(&MODULE_PORT_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected port parameter");
}
}
p.expect(Sym::Rparen);
p.close(h, TreeKind::ModulePortList);
}
const MODULE_PORT_FIRST: TtSet = TtSet::new()
.inherit(TYPE_EXPR_FIRST)
.syms(&[Sym::LparenStar]);
const MODULE_PORT_RECOVERY: TtSet = MODULE_PORT_LIST_RECOVERY.syms(&[Sym::Rparen]);
fn module_port(p: P) {
let h = p.open();
while p.at(Sym::LparenStar) {
attribute_list(p);
}
module_port_param(p);
p.close(h, TreeKind::ModulePort);
}
fn module_port_param(p: P) {
let h = p.open();
type_expr(p);
p.eat(Tt::Ident);
while p.eat(Sym::Lbracket) {
p.expect(Sym::Rbracket);
}
p.close(h, TreeKind::ModulePortParam);
}
const PROVISO_LIST_RECOVERY: TtSet = TtSet::new()
.inherit(STMT_INSTANCE_RECOVERY)
.inherit(INSTANCE_ITEM_RECOVERY)
.inherit(STMT_TYPECLASS_RECOVERY)
.inherit(TYPECLASS_ITEM_RECOVERY)
.inherit(INTERFACE_ITEM_RECOVERY)
.inherit(STMT_METHOD_RECOVERY)
.inherit(STMT_FUNCTION_RECOVERY)
.inherit(STMT_IMPORT_RECOVERY)
.inherit(STMT_MODULE_RECOVERY)
.syms(&[Sym::Semi, Sym::Eq])
.kws(&[Kw::If]);
fn proviso_list(p: P) {
let h = p.open();
p.expect(Kw::Provisos);
p.expect(Sym::Lparen);
while !p.eof_or(Sym::Rparen) {
if p.at_set(&TYPE_EXPR_FIRST) {
type_expr(p);
if !p.at(Sym::Rparen) {
p.expect(Sym::Comma);
}
} else if p.at_set(&PROVISO_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected proviso");
}
}
p.expect(Sym::Rparen);
p.close(h, TreeKind::ProvisoList);
}
const TYPE_EXPR_FIRST: TtSet = TtSet::new()
.tys(&[Tt::Ident, Tt::Str, Tt::Num(NumLit::Int)])
.kws(&[
Kw::Bit,
Kw::Int,
Kw::Real,
Kw::Void,
Kw::ActionType,
Kw::ActionValueType,
Kw::Function,
Kw::Module,
])
.syms(&[Sym::Lparen]);
#[rustfmt::skip]
const TYPE_EXPR_RECOVERY: TtSet = TtSet::new()
.inherit(STMT_RECOVERY)
.inherit(EXPR_ATOM_RECOVERY)
.inherit(DEPENDENCY_RECOVERY)
.inherit(DEPENDENCY_TYPE_LIST_RECOVERY)
.inherit(TYPEDEF_FIELD_RECOVERY)
.inherit(INTERFACE_ITEM_RECOVERY)
.inherit(TYPED_FUN_NAME_RECOVERY)
.inherit(EXPR_OR_BIND_RECOVERY)
.inherit(VAR_INIT_FIRST)
.inherit(MODULE_PORT_RECOVERY)
.inherit(PROVISO_LIST_RECOVERY)
.inherit(FUNCTION_PROTO_RECOVERY)
.inherit(TYPED_NAME_RECOVERY)
.tys(&[Tt::Ident])
.kws(&[Kw::Provisos])
.syms(&[
Sym::Semi, Sym::Lbracket, Sym::Rbracket, Sym::Rparen,
]);
fn type_expr(p: P) -> CloseHandle {
let h = type_atom(p);
type_with(p, h)
}
fn type_with(p: P, atom: CloseHandle) -> CloseHandle {
let mut h = atom;
while p.at(Sym::Hash) {
h = type_app(p, h);
}
h
}
fn type_atom(p: P) -> CloseHandle {
match p.peek() {
Tt::Kw(Kw::Bit) => type_bit(p),
Tt::Kw(Kw::Int) => type_int(p),
Tt::Kw(Kw::Real) => type_real(p),
Tt::Kw(Kw::Void) => type_void(p),
Tt::Kw(Kw::ActionType) => type_action(p),
Tt::Kw(Kw::ActionValueType) => type_actionvalue(p),
Tt::Kw(Kw::Function) => type_function(p),
Tt::Kw(Kw::Module) => type_module(p),
Tt::Num(NumLit::Int) | Tt::Str => type_literal(p),
Tt::Ident => type_at_ident(p),
Tt::Sym(Sym::Lparen) => type_in_parens(p),
_ => p.error_empty("Expected type"),
}
}
fn type_in_parens(p: P) -> CloseHandle {
let h = p.open();
p.expect(Sym::Lparen);
type_expr(p);
p.expect(Sym::Rparen);
p.close(h, TreeKind::TypeInParens)
}
fn type_bit(p: P) -> CloseHandle {
let h = p.open();
p.expect(Kw::Bit);
p.expect(Sym::Lbracket);
p.expect(Tt::Num(NumLit::Int));
p.expect(Sym::Colon);
p.expect(Tt::Num(NumLit::Int));
p.expect(Sym::Rbracket);
p.close(h, TreeKind::TypeBit)
}
fn type_int(p: P) -> CloseHandle {
let h = p.open();
p.expect(Kw::Int);
p.close(h, TreeKind::TypeInt)
}
fn type_real(p: P) -> CloseHandle {
let h = p.open();
p.expect(Kw::Real);
p.close(h, TreeKind::TypeReal)
}
fn type_void(p: P) -> CloseHandle {
let h = p.open();
p.expect(Kw::Void);
p.close(h, TreeKind::TypeVoid)
}
fn type_action(p: P) -> CloseHandle {
let h = p.open();
p.expect(Kw::ActionType);
p.close(h, TreeKind::TypeAction)
}
fn type_actionvalue(p: P) -> CloseHandle {
let h = p.open();
p.expect(Kw::ActionValueType);
p.close(h, TreeKind::TypeActionvalue)
}
fn type_function(p: P) -> CloseHandle {
let h = p.open();
function_proto(p);
p.close(h, TreeKind::TypeFunction)
}
fn type_module(p: P) -> CloseHandle {
let h = p.open();
p.expect(Kw::Module);
p.close(h, TreeKind::TypeModule)
}
fn type_literal(p: P) -> CloseHandle {
let h = p.open();
p.advance();
p.close(h, TreeKind::TypeLiteral)
}
fn type_at_ident(p: P) -> CloseHandle {
let h = p.open();
match p.peek_kind() {
Some(TokenKind::Ident(id)) if id.starts_with(char::is_lowercase) => {
p.expect(Tt::Ident);
p.close(h, TreeKind::TypeVar)
}
_ => {
qual_id(p);
p.close(h, TreeKind::TypeCons)
}
}
}
fn qual_id(p: P) -> CloseHandle {
let mut h = p.open();
p.expect(Tt::Ident);
if p.eat(Sym::ColonColon) {
let c = p.close(h, TreeKind::PkgId);
h = p.open_before(c);
p.expect(Tt::Ident);
}
p.close(h, TreeKind::QualId)
}
const TYPE_APP_RECOVERY: TtSet = TYPE_EXPR_RECOVERY;
fn type_app(p: P, h: CloseHandle) -> CloseHandle {
let h = p.open_before(h);
type_arg_list(p);
p.close(h, TreeKind::TypeApp)
}
const TYPE_ARG_LIST_RECOVERY: TtSet = TYPE_APP_RECOVERY;
fn type_arg_list(p: P) {
let h = p.open();
p.expect(Sym::Hash);
p.expect(Sym::Lparen);
while !p.eof_or(Sym::Rparen) {
if p.at_set(&TYPE_EXPR_FIRST) {
type_expr(p);
if !p.at(Sym::Rparen) {
p.expect(Sym::Comma);
}
} else if p.at_set(&TYPE_ARG_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected type argument");
}
}
p.expect(Sym::Rparen);
p.close(h, TreeKind::TypeArgList);
}
const FUNCTION_PROTO_RECOVERY: TtSet = TtSet::new()
.inherit(STMT_RECOVERY)
.kws(&[Kw::Provisos])
.syms(&[Sym::Semi]);
fn function_proto(p: P) {
let h = p.open();
p.expect(Kw::Function);
type_expr(p);
p.expect(Tt::Ident);
if p.at(Sym::Lparen) {
function_param_list(p);
}
p.close(h, TreeKind::FunctionProto);
}
const FUNCTION_PARAM_LIST_RECOVERY: TtSet = TtSet::new()
.inherit(INSTANCE_ITEM_RECOVERY)
.inherit(TYPECLASS_ITEM_RECOVERY)
.inherit(INTERFACE_ITEM_RECOVERY)
.inherit(STMT_RECOVERY)
.inherit(FUNCTION_PROTO_RECOVERY)
.kws(&[Kw::Provisos, Kw::If])
.syms(&[Sym::Eq, Sym::Semi]);
fn function_param_list(p: P) {
let h = p.open();
p.expect(Sym::Lparen);
while !p.eof_or(Sym::Rparen) {
if p.at_set(&FUNCTION_PARAM_FIRST) {
function_param(p);
if !p.at(Sym::Rparen) {
p.expect(Sym::Comma);
}
} else if p.at_set(&FUNCTION_PARAM_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected function parameter");
}
}
p.expect(Sym::Rparen);
p.close(h, TreeKind::FunctionParamList);
}
const FUNCTION_PARAM_FIRST: TtSet = TtSet::new()
.inherit(TYPED_NAME_FIRST)
.syms(&[Sym::LparenStar]);
const FUNCTION_PARAM_RECOVERY: TtSet = FUNCTION_PARAM_LIST_RECOVERY.syms(&[Sym::Rparen]);
fn function_param(p: P) {
let h = p.open();
while p.at(Sym::LparenStar) {
attribute_list(p);
}
typed_name(p);
p.close(h, TreeKind::FunctionParam);
}
const TYPED_NAME_FIRST: TtSet = TtSet::new().inherit(TYPE_EXPR_FIRST).kws(&[Kw::Function]);
const TYPED_NAME_RECOVERY: TtSet = TtSet::new()
.inherit(MODULE_PARAM_RECOVERY)
.inherit(FUNCTION_PARAM_RECOVERY);
fn typed_name(p: P) {
let h = p.open();
if p.at(Kw::Function) {
function_proto(p);
} else {
if p.at(Tt::Ident) {
match p.nth(1) {
Tt::Sym(Sym::Hash) | Tt::Ident | Tt::Sym(Sym::ColonColon) => {
type_expr(p);
}
_ => (),
}
p.expect(Tt::Ident);
} else {
type_expr(p);
p.expect(Tt::Ident);
}
while p.eat(Sym::Lbracket) {
p.expect(Sym::Rbracket);
}
}
p.close(h, TreeKind::TypedName);
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
enum Prec {
StarStar, Mul, Add, Shift, Cmp, Eq, BitAnd, BitXor, BitOr, And, Or,
Matches, CondChain,
Ternary,
Top,
}
#[rustfmt::skip]
const BINARY_OPS: TtSet = TtSet::new()
.syms(&[
Sym::StarStar, Sym::Star, Sym::Slash, Sym::Percent, Sym::Plus, Sym::Minus, Sym::LtLt,
Sym::GtGt, Sym::Lt, Sym::LtEq, Sym::Gt, Sym::GtEq, Sym::EqEq, Sym::BangEq, Sym::Et,
Sym::Caret, Sym::CaretTilde, Sym::TildeCaret, Sym::Pipe, Sym::EtEt, Sym::PipePipe,
Sym::EtEtEt, Sym::Question,
])
.kws(&[Kw::Matches]);
impl Prec {
pub fn of(ty: Tt) -> Self {
use Sym::*;
match ty {
Tt::Sym(sym) => match sym {
StarStar => Prec::StarStar,
Star | Slash | Percent => Prec::Mul,
Plus | Minus => Prec::Add,
LtLt | GtGt => Prec::Shift,
Lt | LtEq | Gt | GtEq => Prec::Cmp,
EqEq | BangEq => Prec::Eq,
Et => Prec::BitAnd,
Caret | CaretTilde | TildeCaret => Prec::BitXor,
Pipe => Prec::BitOr,
EtEt => Prec::And,
PipePipe => Prec::Or,
EtEtEt => Prec::CondChain,
Question => Prec::Ternary,
_ => Prec::Top,
},
Tt::Kw(Kw::Matches) => Prec::Matches,
_ => Prec::Top,
}
}
}
const EXPR_FIRST: TtSet = TtSet::new().inherit(EXPR_PREFIXED_FIRST);
#[rustfmt::skip]
const EXPR_RECOVERY: TtSet = STMT_RECOVERY.tys(&[Tt::Ident]).syms(&[
Sym::Semi, Sym::Rparen, Sym::Rbracket, Sym::Rbrace, Sym::Eq,
Sym::LtMinus, Sym::LtEq, Sym::Colon
]);
fn expr(p: P) -> CloseHandle {
expr_impl(p, Prec::Top)
}
fn expr_impl(p: P, prec: Prec) -> CloseHandle {
let expr = expr_prefixed(p);
let expr = expr_postfix(p, expr);
expr_pratt(p, expr, prec)
}
fn expr_pratt(p: P, mut lhs: CloseHandle, lhs_prec: Prec) -> CloseHandle {
loop {
let rhs_prec = Prec::of(p.peek());
if rhs_prec < lhs_prec {
lhs = expr_infix(p, lhs, rhs_prec);
} else {
break;
}
}
lhs
}
const INFIX_OPS: TtSet = BINARY_OPS.kws(&[Kw::Matches]).syms(&[Sym::Question]);
fn expr_infix(p: P, lhs: CloseHandle, prec: Prec) -> CloseHandle {
match p.peek() {
Tt::Kw(Kw::Matches) => expr_matches(p, lhs),
Tt::Sym(Sym::Question) => expr_ternary(p, lhs),
_ => expr_binary(p, lhs, prec),
}
}
const EXPR_MATCHES_RECOVERY: TtSet = EXPR_RECOVERY;
fn expr_matches(p: P, lhs: CloseHandle) -> CloseHandle {
let h = p.open_before(lhs);
p.expect(Kw::Matches);
pattern(p);
p.close(h, TreeKind::ExprMatches)
}
fn expr_ternary(p: P, lhs: CloseHandle) -> CloseHandle {
let h = p.open_before(lhs);
p.expect(Sym::Question);
expr(p);
p.expect(Sym::Colon);
expr(p);
p.close(h, TreeKind::ExprTernary)
}
fn expr_binary(p: P, lhs: CloseHandle, prec: Prec) -> CloseHandle {
let h = p.open_before(lhs);
p.advance();
expr_impl(p, prec);
p.close(h, TreeKind::ExprBinary)
}
#[rustfmt::skip]
const EXPR_PREFIXED_FIRST: TtSet = TtSet::new().inherit(EXPR_ATOM_FIRST).syms(&[
Sym::LparenStar, Sym::Plus, Sym::Minus, Sym::Bang, Sym::Tilde, Sym::Et, Sym::Pipe,
Sym::Caret, Sym::TildeEt, Sym::TildePipe, Sym::TildeCaret, Sym::CaretTilde,
]);
const EXPR_PREFIXED_RECOVERY: TtSet = EXPR_RECOVERY.inherit(POSTFIX_OPS).inherit(INFIX_OPS);
fn expr_prefixed(p: P) -> CloseHandle {
use Sym::*;
if let Tt::Sym(sym) = p.peek() {
match sym {
LparenStar => {
let h = p.open();
while p.at(Sym::LparenStar) {
attribute_list(p);
}
expr_prefixed(p);
return p.close(h, TreeKind::ExprAttributes);
}
#[rustfmt::skip]
Plus | Minus | Bang | Tilde | Et |
Pipe | Caret | TildeEt | TildePipe |
TildeCaret | CaretTilde => {
let h = p.open();
p.advance();
expr_prefixed(p);
return p.close(h, TreeKind::ExprPrefixOp);
}
_ => (),
}
}
expr_atom(p)
}
#[rustfmt::skip]
const EXPR_ATOM_FIRST: TtSet = TtSet::new()
.inherit(EXPR_OR_TY_START)
.tys(&[
Tt::Num(NumLit::Int), Tt::Num(NumLit::Mixed), Tt::Num(NumLit::Real),
Tt::Num(NumLit::Repeated), Tt::SysIdent,
])
.kws(&[
Kw::Action, Kw::Actionvalue, Kw::Rules, Kw::Begin, Kw::Seq, Kw::Par, Kw::Interface,
Kw::Case, Kw::Valueof, Kw::ValueOf, Kw::Stringof, Kw::StringOf, Kw::Tagged,
])
.syms(&[Sym::Lbrace, Sym::Lparen, Sym::Question]);
const EXPR_ATOM_RECOVERY: TtSet = EXPR_PREFIXED_RECOVERY;
fn expr_atom(p: P) -> CloseHandle {
match p.peek() {
ty if EXPR_OR_TY_START.contains(ty) => match expr_atom_or_ty(p, false) {
ExprOrTy::Expr(expr) => expr,
ExprOrTy::Ty(ty) => expr_with_type(p, ty),
},
Tt::Num(_) => expr_lit(p),
#[rustfmt::skip]
Tt::Kw(Kw::Action) => inline_block(
p,
TreeKind::ExprAction,
Kw::Action,
Kw::Endaction,
&EXPR_ATOM_RECOVERY
),
#[rustfmt::skip]
Tt::Kw(Kw::Actionvalue) => inline_block(
p,
TreeKind::ExprActionvalue,
Kw::Actionvalue,
Kw::Endactionvalue,
&EXPR_ATOM_RECOVERY
),
#[rustfmt::skip]
Tt::Kw(Kw::Rules) => inline_block(
p,
TreeKind::ExprRules,
Kw::Rules,
Kw::Endrules,
&EXPR_ATOM_RECOVERY
),
#[rustfmt::skip]
Tt::Kw(Kw::Begin) => inline_block(
p,
TreeKind::ExprBlock,
Kw::Begin,
Kw::End,
&EXPR_ATOM_RECOVERY
),
#[rustfmt::skip]
Tt::Kw(Kw::Seq) => inline_block(
p,
TreeKind::ExprSeq,
Kw::Seq,
Kw::Endseq,
&EXPR_ATOM_RECOVERY
),
#[rustfmt::skip]
Tt::Kw(Kw::Par) => inline_block(
p,
TreeKind::ExprPar,
Kw::Par,
Kw::Endpar,
&EXPR_ATOM_RECOVERY
),
Tt::Kw(Kw::Interface) => expr_interface(p),
Tt::Kw(Kw::Case) => expr_case(p),
Tt::Sym(Sym::Lbrace) => expr_bit_concat(p),
Tt::SysIdent => expr_systask(p),
Tt::Kw(Kw::Valueof) | Tt::Kw(Kw::ValueOf) => expr_valueof(p),
Tt::Kw(Kw::Stringof) | Tt::Kw(Kw::StringOf) => expr_stringof(p),
Tt::Sym(Sym::Lparen) => expr_in_parens(p),
Tt::Sym(Sym::Question) => expr_dont_care(p),
Tt::Kw(Kw::Tagged) => expr_tagged(p),
_ => p.error_empty("Expected expression"),
}
}
fn expr_in_parens(p: P) -> CloseHandle {
let h = p.open();
p.expect(Sym::Lparen);
expr(p);
p.expect(Sym::Rparen);
p.close(h, TreeKind::ExprInParens)
}
fn expr_lit(p: P) -> CloseHandle {
let h = p.open();
p.advance();
p.close(h, TreeKind::ExprLit)
}
fn inline_block(p: P, outer: TreeKind, start_kw: Kw, end_kw: Kw, recovery: &TtSet) -> CloseHandle {
let h = p.open();
p.expect(start_kw);
end_clause(p);
body(p, end_kw, recovery);
p.expect(end_kw);
end_clause(p);
p.close(h, outer)
}
const EXPR_INTERFACE_RECOVERY: TtSet = EXPR_ATOM_RECOVERY;
fn expr_interface(p: P) -> CloseHandle {
let h = p.open();
p.expect(Kw::Interface);
type_expr(p);
p.eat(Sym::Semi);
body_with_subifs(p, Kw::Endinterface, &EXPR_INTERFACE_RECOVERY);
p.expect(Kw::Endinterface);
end_clause(p);
p.close(h, TreeKind::ExprInterface)
}
fn expr_case(p: P) -> CloseHandle {
let h = p.open();
case(p);
p.close(h, TreeKind::ExprCase)
}
const EXPR_BIT_CONCAT_RECOVERY: TtSet = EXPR_ATOM_RECOVERY;
fn expr_bit_concat(p: P) -> CloseHandle {
let h = p.open();
p.expect(Sym::Lbrace);
while !p.eof_or(Sym::Rbrace) {
if p.at_set(&EXPR_FIRST) {
expr(p);
if !p.at(Sym::Rbrace) {
p.expect(Sym::Comma);
}
} else if p.at_set(&EXPR_BIT_CONCAT_RECOVERY) {
break;
} else {
p.advance_error("Expected expression");
}
}
p.expect(Sym::Rbrace);
p.close(h, TreeKind::ExprBitConcat)
}
fn expr_systask(p: P) -> CloseHandle {
let h = p.open();
p.expect(Tt::SysIdent);
p.close(h, TreeKind::ExprSystask)
}
fn expr_valueof(p: P) -> CloseHandle {
let h = p.open();
p.advance();
p.expect(Sym::Lparen);
type_expr(p);
p.expect(Sym::Rparen);
p.close(h, TreeKind::ExprValueof)
}
fn expr_stringof(p: P) -> CloseHandle {
let h = p.open();
p.advance();
p.expect(Sym::Lparen);
type_expr(p);
p.expect(Sym::Rparen);
p.close(h, TreeKind::ExprStringof)
}
fn expr_dont_care(p: P) -> CloseHandle {
let h = p.open();
p.expect(Sym::Question);
p.close(h, TreeKind::ExprDontCare)
}
fn expr_tagged(p: P) -> CloseHandle {
let h = p.open();
p.expect(Kw::Tagged);
qual_id(p);
if p.at(Sym::Lbrace) {
init_list(p);
} else if p.at_set(&EXPR_ATOM_FIRST) {
expr_atom(p);
}
p.close(h, TreeKind::ExprTagged)
}
const POSTFIX_OPS: TtSet = TtSet::new().syms(&[Sym::Dot, Sym::Lparen, Sym::Lbracket]);
const EXPR_POSTFIX_RECOVERY: TtSet = EXPR_RECOVERY.inherit(INFIX_OPS);
fn expr_postfix(p: P, inner: CloseHandle) -> CloseHandle {
let mut h = inner;
loop {
h = match p.peek() {
Tt::Sym(Sym::Dot) => expr_field(p, h),
Tt::Sym(Sym::Lparen) => expr_call(p, h),
Tt::Sym(Sym::Lbracket) => expr_subscript(p, h),
_ => break,
}
}
h
}
fn expr_field(p: P, inner: CloseHandle) -> CloseHandle {
let h = p.open_before(inner);
p.expect(Sym::Dot);
qual_id(p);
p.close(h, TreeKind::ExprField)
}
const EXPR_CALL_RECOVERY: TtSet = EXPR_POSTFIX_RECOVERY;
fn expr_call(p: P, inner: CloseHandle) -> CloseHandle {
let h = p.open_before(inner);
p.expect(Sym::Lparen);
while !p.eof_or(Sym::Rparen) {
if p.at_set(&FUNCTION_ARG_FIRST) {
function_arg(p);
if !p.at(Sym::Rparen) {
p.expect(Sym::Comma);
}
} else if p.at_set(&EXPR_CALL_RECOVERY) {
break;
} else {
p.advance_error("Expected argument");
}
}
p.expect(Sym::Rparen);
p.close(h, TreeKind::ExprCall)
}
const FUNCTION_ARG_FIRST: TtSet =
TtSet::new()
.inherit(EXPR_FIRST)
.kws(&[Kw::ClockedBy, Kw::ResetBy, Kw::PoweredBy]);
fn function_arg(p: P) {
let h = p.open();
match p.peek() {
Tt::Kw(Kw::ClockedBy) | Tt::Kw(Kw::ResetBy) | Tt::Kw(Kw::PoweredBy) => p.advance(),
_ => (),
}
expr(p);
p.close(h, TreeKind::FunctionArg);
}
fn expr_subscript(p: P, inner: CloseHandle) -> CloseHandle {
let h = p.open_before(inner);
subscript(p);
p.close(h, TreeKind::ExprSubscript)
}
fn subscript(p: P) {
let h = p.open();
p.expect(Sym::Lbracket);
expr(p);
if p.eat(Sym::Colon) {
expr(p);
}
p.expect(Sym::Rbracket);
p.close(h, TreeKind::Subscript);
}
fn expr_struct_init(p: P, id: CloseHandle) -> CloseHandle {
let h = p.open_before(id);
init_list(p);
p.close(h, TreeKind::ExprStructInit)
}
const INIT_LIST_RECOVERY: TtSet = EXPR_ATOM_RECOVERY;
fn init_list(p: P) {
let h = p.open();
p.expect(Sym::Lbrace);
while !p.eof_or(Sym::Rbrace) {
if p.at_set(&FIELD_INIT_OR_EXPR_FIRST) {
field_init_or_expr(p);
if !p.at(Sym::Rbrace) {
p.expect(Sym::Comma);
}
} else if p.at_set(&INIT_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected struct field");
}
}
p.expect(Sym::Rbrace);
p.close(h, TreeKind::InitList);
}
const FIELD_INIT_OR_EXPR_FIRST: TtSet = TtSet::new().inherit(EXPR_FIRST).tys(&[Tt::Ident]);
fn field_init_or_expr(p: P) {
if p.at(Tt::Ident) {
let id = qual_id(p);
if p.at(Sym::Colon) {
let h = p.open_before(id);
p.advance();
expr(p);
p.close(h, TreeKind::FieldInit);
} else {
let expr = expr_atom_with_id(p, id);
expr_from_atom(p, expr);
}
} else {
expr(p);
}
}
const CASE_RECOVERY: TtSet = TtSet::new()
.inherit(STMT_RECOVERY)
.inherit(EXPR_ATOM_RECOVERY)
.syms(&[Sym::Semi]);
fn case(p: P) {
let h = p.open();
p.expect(Kw::Case);
expr_impl(p, Prec::Matches);
if p.eat(Kw::Matches) {
case_match_list(p);
} else {
case_if_list(p);
}
p.expect(Kw::Endcase);
p.close(h, TreeKind::Case);
}
const CASE_MATCH_LIST_RECOVERY: TtSet = CASE_RECOVERY.kws(&[Kw::Endcase]);
fn case_match_list(p: P) {
let h = p.open();
while !p.eof_or(Kw::Endcase) {
if p.at(Kw::Default) {
case_default(p);
} else if p.at_set(&CASE_MATCH_START) {
case_match(p);
} else if p.at_set(&CASE_MATCH_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected match case arm");
}
}
p.close(h, TreeKind::CaseMatchList);
}
const CASE_MATCH_START: TtSet = TtSet::new().inherit(PATTERN_FIRST);
const CASE_MATCH_RECOVERY: TtSet = CASE_MATCH_LIST_RECOVERY;
fn case_match(p: P) {
let h = p.open();
case_match_cond(p);
p.expect(Sym::Colon);
stmt(p);
p.close(h, TreeKind::CaseMatch);
}
const CASE_MATCH_COND_RECOVERY: TtSet = CASE_MATCH_RECOVERY.syms(&[Sym::Colon]);
fn case_match_cond(p: P) {
let h = p.open();
pattern(p);
while p.eat(Sym::EtEtEt) {
expr_impl(p, Prec::CondChain);
}
p.close(h, TreeKind::CaseMatchCond);
}
const CASE_IF_LIST_START: TtSet = CASE_RECOVERY.kws(&[Kw::Endcase]);
fn case_if_list(p: P) {
let h = p.open();
while !p.eof_or(Kw::Endcase) {
if p.at(Kw::Default) {
case_default(p);
} else if p.at_set(&CASE_IF_START) {
case_if(p);
} else if p.at_set(&CASE_IF_LIST_START) {
break;
} else {
p.advance_error("Expected conditional case arm");
}
}
p.close(h, TreeKind::CaseIfList);
}
const CASE_IF_START: TtSet = TtSet::new().inherit(EXPR_FIRST);
fn case_if(p: P) {
let h = p.open();
case_if_cond_list(p);
p.expect(Sym::Colon);
stmt(p);
p.close(h, TreeKind::CaseIf);
}
fn case_if_cond_list(p: P) {
let h: OpenHandle = p.open();
expr(p);
while p.eat(Sym::Comma) {
expr(p);
}
p.close(h, TreeKind::CaseIfCondList);
}
fn case_default(p: P) {
let h = p.open();
p.expect(Kw::Default);
p.eat(Sym::Colon);
stmt(p);
p.close(h, TreeKind::CaseDefault);
}
const EXPR_OR_TY_START: TtSet = TtSet::new()
.tys(&[Tt::Num(NumLit::Int), Tt::Str, Tt::Ident])
.kws(&[Kw::Module])
.syms(&[Sym::Lparen]);
enum ExprOrTy {
Expr(CloseHandle),
Ty(CloseHandle),
}
fn expr_or_ty(p: P, in_stmt: bool) -> ExprOrTy {
match expr_atom_or_ty(p, in_stmt) {
ExprOrTy::Expr(expr) => {
ExprOrTy::Expr(expr_from_atom(p, expr))
}
ty => ty,
}
}
fn expr_from_atom(p: P, inner: CloseHandle) -> CloseHandle {
let expr = expr_postfix(p, inner);
expr_pratt(p, expr, Prec::Top)
}
fn expr_atom_or_ty(p: P, in_stmt: bool) -> ExprOrTy {
match p.peek() {
Tt::Num(NumLit::Int) | Tt::Str => expr_or_ty_at_lit(p, in_stmt),
Tt::Kw(Kw::Module) => expr_or_ty_at_module(p),
Tt::Ident => expr_or_ty_at_ident(p, in_stmt),
Tt::Sym(Sym::Lparen) => expr_or_ty_at_lparen(p, in_stmt),
_ => unreachable!(),
}
}
fn expr_or_ty_at_ident(p: P, in_stmt: bool) -> ExprOrTy {
let after_id = {
let mut ofs = 0;
if p.nth_is(ofs, Tt::Ident) {
ofs += 1;
}
if p.nth_is(ofs, Sym::ColonColon) {
ofs += 1;
if p.nth_is(ofs, Tt::Ident) {
ofs += 1;
}
}
p.nth(ofs)
};
if after_id == Sym::Hash.into() {
let ty = type_expr(p);
return ExprOrTy::Ty(ty);
}
if in_stmt && VAR_INIT_FIRST.contains(after_id) {
let ty = type_expr(p);
return ExprOrTy::Ty(ty);
}
if after_id == Sym::Tick.into() || after_id == Sym::Lbrace.into() {
let ty = type_expr(p);
let expr = expr_with_type(p, ty);
return ExprOrTy::Expr(expr);
}
let id = qual_id(p);
let expr = expr_atom_with_id(p, id);
ExprOrTy::Expr(expr)
}
fn expr_or_ty_at_lit(p: P, in_stmt: bool) -> ExprOrTy {
let h = p.open();
p.advance();
if p.at(Sym::Hash) {
let ty = p.close(h, TreeKind::TypeLiteral);
return ExprOrTy::Ty(ty);
}
if in_stmt && p.at_set(&VAR_INIT_FIRST) {
let ty = p.close(h, TreeKind::TypeLiteral);
return ExprOrTy::Ty(ty);
}
if p.at(Sym::Tick) || p.at(Sym::Lbrace) {
let ty = p.close(h, TreeKind::TypeLiteral);
let expr = expr_with_type(p, ty);
return ExprOrTy::Expr(expr);
}
let expr = p.close(h, TreeKind::ExprLit);
ExprOrTy::Expr(expr)
}
fn expr_or_ty_at_module(p: P) -> ExprOrTy {
let ty = type_expr(p);
if p.at(Sym::Semi) {
let expr = expr_module_with(p, ty);
ExprOrTy::Expr(expr)
} else {
ExprOrTy::Ty(ty)
}
}
fn expr_or_ty_at_lparen(p: P, in_stmt: bool) -> ExprOrTy {
assert!(p.at(Sym::Lparen));
let mut depth = 1;
let mut ofs = 1;
let tok_after = loop {
match p.nth_raw(ofs) {
Some(tok) if depth == 0 => break tok,
None if depth == 0 => (),
Some(Tt::Eof) => break Tt::Eof,
Some(Tt::Sym(Sym::Lparen)) => depth += 1,
Some(Tt::Sym(Sym::Rparen)) => depth -= 1,
_ => (),
}
ofs += 1;
};
if tok_after == Tt::Sym(Sym::Hash) {
let ty = type_in_parens(p);
return ExprOrTy::Ty(ty);
}
if in_stmt && p.at_set(&VAR_INIT_FIRST) {
let ty = type_in_parens(p);
return ExprOrTy::Ty(ty);
}
if p.at(Sym::Tick) || p.at(Sym::Lbrace) {
let ty = type_in_parens(p);
let expr = expr_with_type(p, ty);
return ExprOrTy::Expr(expr);
}
let expr = expr_in_parens(p);
ExprOrTy::Expr(expr)
}
fn expr_atom_with_id(p: P, id: CloseHandle) -> CloseHandle {
p.wrap(id, TreeKind::ExprVar)
}
fn expr_with_type(p: P, ty: CloseHandle) -> CloseHandle {
if p.at(Sym::Tick) {
let h = p.open_before(ty);
p.expect(Sym::Tick);
expr(p);
p.close(h, TreeKind::ExprCast)
} else if p.at(Sym::Lbrace) {
expr_struct_init(p, ty)
} else {
p.error_empty("Expected cast or struct init expression following type")
}
}
fn expr_module_with(p: P, ty: CloseHandle) -> CloseHandle {
let h = p.open_before(ty);
p.expect(Sym::Semi);
body_with_subifs(p, Kw::Endmodule, &EXPR_ATOM_RECOVERY);
p.expect(Kw::Endmodule);
p.close(h, TreeKind::ExprModule)
}
const PATTERN_FIRST: TtSet = TtSet::new()
.tys(&[
Tt::Num(NumLit::Int),
Tt::Num(NumLit::Mixed),
Tt::Num(NumLit::Real),
Tt::Num(NumLit::Repeated),
Tt::Str,
Tt::Ident,
])
.kws(&[Kw::Tagged])
.syms(&[Sym::Dot, Sym::DotStar, Sym::Lbrace, Sym::Lparen]);
const PATTERN_RECOVERY: TtSet = TtSet::new()
.inherit(DECL_MATCH_RECOVERY)
.inherit(EXPR_MATCHES_RECOVERY)
.inherit(CASE_MATCH_COND_RECOVERY)
.syms(&[Sym::Eq, Sym::LtMinus, Sym::EtEtEt, Sym::Rparen, Sym::Rbrace]);
fn pattern(p: P) {
match p.peek() {
Tt::Sym(Sym::Dot) => pattern_bind(p),
Tt::Sym(Sym::DotStar) => pattern_wildcard(p),
Tt::Num(_) | Tt::Str => pattern_literal(p),
Tt::Kw(Kw::Tagged) => pattern_tagged(p),
Tt::Sym(Sym::Lbrace) => pattern_list(p),
Tt::Ident => pattern_struct_or_enum(p),
Tt::Sym(Sym::Lparen) => pattern_in_parens(p),
_ => p.error("Expected pattern"),
}
}
fn pattern_bind(p: P) {
let h = p.open();
p.expect(Sym::Dot);
p.expect(Tt::Ident);
p.close(h, TreeKind::PatternBind);
}
fn pattern_wildcard(p: P) {
let h = p.open();
p.expect(Sym::DotStar);
p.close(h, TreeKind::PatternWildcard);
}
fn pattern_literal(p: P) {
let h = p.open();
p.advance();
p.close(h, TreeKind::PatternLiteral);
}
fn pattern_tagged(p: P) {
let h = p.open();
p.expect(Kw::Tagged);
qual_id(p);
if p.at_set(&PATTERN_FIRST) {
pattern(p);
}
p.close(h, TreeKind::PatternTagged);
}
fn pattern_in_parens(p: P) {
let h = p.open();
p.expect(Sym::Lparen);
pattern(p);
p.expect(Sym::Rparen);
p.close(h, TreeKind::PatternInParens);
}
fn pattern_struct_or_enum(p: P) {
let h = p.open();
qual_id(p);
if p.at(Sym::Lbrace) {
pattern_list(p);
p.close(h, TreeKind::PatternStruct);
} else {
p.close(h, TreeKind::PatternEnum);
}
}
const PATTERN_LIST_RECOVERY: TtSet = PATTERN_RECOVERY;
fn pattern_list(p: P) {
let h = p.open();
p.expect(Sym::Lbrace);
while !p.eof_or(Sym::Rbrace) {
if p.at(Tt::Ident) {
pattern_or_field(p);
if !p.at(Sym::Rbrace) {
p.expect(Sym::Comma);
}
} else if p.at_set(&PATTERN_FIRST) {
pattern(p);
if !p.at(Sym::Rbrace) {
p.expect(Sym::Comma);
}
} else if p.at_set(&PATTERN_LIST_RECOVERY) {
break;
} else {
p.advance_error("Expected pattern");
}
}
p.expect(Sym::Rbrace);
p.close(h, TreeKind::PatternList);
}
fn pattern_or_field(p: P) {
let h = p.open();
let mut can_label = if let Some(TokenKind::Ident(id)) = p.peek_kind() {
id.starts_with(char::is_lowercase)
} else {
false
};
p.expect(Tt::Ident);
if p.eat(Sym::ColonColon) {
p.expect(Tt::Ident);
can_label = false;
}
let id = p.close(h, TreeKind::QualId);
if p.at(Sym::Colon) {
pattern_field_with(p, id);
} else if p.at(Sym::Lbrace) {
pattern_struct_with(p, id);
} else if can_label {
pattern_field_with(p, id);
} else {
p.wrap(id, TreeKind::PatternEnum);
}
}
fn pattern_struct_with(p: P, id: CloseHandle) {
let h = p.open_before(id);
pattern_list(p);
p.close(h, TreeKind::PatternStruct);
}
fn pattern_field_with(p: P, id: CloseHandle) {
let h = p.open_before(id);
if p.eat(Sym::Colon) {
pattern(p);
}
p.close(h, TreeKind::PatternField);
}
fn soft_kw(p: P) {
let h = p.open();
p.expect(Tt::Ident);
p.close(h, TreeKind::SoftKw);
}