blob: 20427860d1208f0940fcc71e1d48188594503c43 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::Rule,
failure::Fail,
pest::iterators::{Pair, Pairs},
serde_derive::Serialize,
std::fmt,
std::{
collections::{HashMap, HashSet, VecDeque},
str::FromStr,
},
};
#[derive(Debug, Fail)]
pub enum ParseError {
#[fail(display = "The primary namespace was already set")]
AlreadyPrimaryNamespace,
#[fail(display = "{} is not yet support", 0)]
NotYetSupported(String),
#[fail(display = "{:?} is not expected in this location", 0)]
UnexpectedToken(Rule),
#[fail(display = "{} was not included in the input libraries", 0)]
UnImported(String),
#[fail(display = "{:?} is an unknown type", 0)]
UnrecognizedType(String),
#[fail(display = "Failed to parse because {:?} is not an integer", 0)]
NotAnInteger(Rule),
#[fail(display = "Invalid dependencies: {}", 0)]
InvalidDeps(String),
}
#[derive(PartialEq, Eq, Serialize, Default, Debug, Hash)]
pub struct Attr {
pub key: String,
pub val: Option<String>,
}
#[derive(PartialEq, Eq, Serialize, Default, Debug, Hash)]
pub struct Attrs(pub Vec<Attr>);
pub type Ident = String;
impl Attrs {
#[allow(dead_code)]
pub fn has_attributes(&self) -> bool {
self.0.len() > 0
}
pub fn has_attribute(&self, key: &str) -> bool {
self.0.iter().any(|attr| attr.key == key)
}
pub fn get_attribute<'a>(&'a self, key: &str) -> Option<&'a String> {
if let Some(attr) = self.0.iter().find(|attr| attr.key == key) {
if let Some(ref val) = attr.val {
Some(val)
} else {
None
}
} else {
None
}
}
pub fn from_pair(pair: Pair<'_, Rule>) -> Result<Attrs, ParseError> {
let mut attrs = Attrs::default();
let mut doc_string: Option<String> = None; // String::default();
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::doc_comment => {
if doc_string.is_none() {
doc_string = Some(String::default())
}
if let Some(ref mut doc_string) = doc_string {
*doc_string += inner_pair.as_str().split_at(3).1;
}
}
Rule::attribute_list => {
let attr_string = inner_pair
.as_str()
.trim_start_matches('[')
.trim_end_matches(']');
let attr_pairs = attr_string.split(",");
for ap in attr_pairs {
if !ap.contains("=") {
attrs.0.push(Attr {
key: String::from(ap.trim()),
val: None,
});
} else {
let split: Vec<&str> = ap.split("=").collect();
attrs.0.push(Attr {
key: String::from(split[0].trim()),
val: Some(String::from(split[1])),
});
}
}
}
_ => unreachable!(),
}
}
if doc_string.is_some() {
attrs.0.push(Attr {
key: String::from("Doc"),
val: doc_string,
});
}
Ok(attrs)
}
}
#[derive(PartialEq, Eq, Clone, Serialize, Debug, Hash)]
pub enum Constant {
SizedRaw(usize),
SizedConstant(Ident),
}
impl Constant {
pub fn from_str(string: &str) -> Result<Self, ParseError> {
match usize::from_str(string) {
Ok(s) => Ok(Constant::SizedRaw(s)),
Err(_) => Ok(Constant::SizedConstant(string.to_string())),
}
}
}
#[derive(PartialEq, Eq, Clone, Serialize, Debug, Hash)]
pub enum HandleTy {
Handle,
Process,
Thread,
Vmo,
Channel,
Event,
Port,
Interrupt,
Log,
Socket,
Resource,
EventPair,
Job,
Vmar,
Fifo,
Guest,
Timer,
Bti,
Profile,
}
#[derive(PartialEq, Eq, Clone, Serialize, Debug, Hash)]
pub enum Ty {
Voidptr,
USize,
Bool,
Int8,
Int16,
Int32,
Int64,
UInt8,
UInt16,
UInt32,
UInt64,
Float32,
Float64,
Str {
size: Option<Constant>,
nullable: bool,
},
Vector {
ty: Box<Ty>,
size: Option<Constant>,
nullable: bool,
},
Array {
ty: Box<Ty>,
size: Constant,
},
Interface,
Struct,
Union,
Enum,
Handle {
ty: HandleTy,
nullable: bool,
},
Ident {
id: String,
nullable: bool,
},
}
impl fmt::Display for Ty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Ty::UInt32 => write!(f, "UInt32"),
_ => panic!("unknown type in Display conversion"),
}
}
}
impl Ty {
pub fn is_primitive(&self) -> bool {
match self {
Ty::Ident { id, .. } => {
if id == "zx.status" {
return true;
} else {
return false;
}
}
Ty::Str { .. } | Ty::Vector { .. } | Ty::Array { .. } | Ty::Handle { .. } => false,
_ => true,
}
}
pub fn is_nullable(&self) -> bool {
match self {
Ty::Str { nullable, .. } => *nullable,
Ty::Vector { nullable, .. } => *nullable,
Ty::Ident { nullable, .. } => *nullable,
Ty::Handle { nullable, .. } => *nullable,
_ => false,
}
}
pub fn from_pair(pair: &Pair<'_, Rule>) -> Result<Self, ParseError> {
let rule = pair.as_rule();
match rule {
Rule::primitive_type => match pair.as_str() {
"usize" => Ok(Ty::USize),
"bool" => Ok(Ty::Bool),
"int8" => Ok(Ty::Int8),
"int16" => Ok(Ty::Int16),
"int32" => Ok(Ty::Int32),
"int64" => Ok(Ty::Int64),
"uint8" => Ok(Ty::UInt8),
"uint16" => Ok(Ty::UInt16),
"uint32" => Ok(Ty::UInt32),
"uint64" => Ok(Ty::UInt64),
"float32" => Ok(Ty::Float32),
"float64" => Ok(Ty::Float64),
"voidptr" => Ok(Ty::Voidptr),
_e => Err(ParseError::UnrecognizedType(pair.as_str().to_string())),
},
Rule::handle_type => {
let mut ty = HandleTy::Handle;
let mut nullable = false;
for inner_pair in pair.clone().into_inner() {
match inner_pair.as_rule() {
Rule::handle_subtype => {
ty = match inner_pair.as_str() {
"process" => HandleTy::Process,
"thread" => HandleTy::Thread,
"vmo" => HandleTy::Vmo,
"channel" => HandleTy::Channel,
"event" => HandleTy::Event,
"port" => HandleTy::Port,
"interrupt" => HandleTy::Interrupt,
"log" => HandleTy::Log,
"socket" => HandleTy::Socket,
"resource" => HandleTy::Resource,
"eventpair" => HandleTy::EventPair,
"job" => HandleTy::Job,
"vmar" => HandleTy::Vmar,
"fifo" => HandleTy::Fifo,
"guest" => HandleTy::Guest,
"timer" => HandleTy::Timer,
"bti" => HandleTy::Bti,
"profile" => HandleTy::Profile,
_e => {
return Err(ParseError::UnrecognizedType(
inner_pair.as_str().to_string(),
));
}
}
}
Rule::nullable => {
nullable = true;
}
_e => {
return Err(ParseError::UnrecognizedType(
inner_pair.as_str().to_string(),
));
}
}
}
Ok(Ty::Handle { ty, nullable })
}
Rule::integer_type => match pair.as_str() {
"usize" => Ok(Ty::USize),
"int8" => Ok(Ty::Int8),
"int16" => Ok(Ty::Int16),
"int32" => Ok(Ty::Int32),
"int64" => Ok(Ty::Int64),
"uint8" => Ok(Ty::UInt8),
"uint16" => Ok(Ty::UInt16),
"uint32" => Ok(Ty::UInt32),
"uint64" => Ok(Ty::UInt64),
_e => Err(ParseError::NotAnInteger(rule)),
},
Rule::array_type => {
let vec_contents: Vec<Pair<'_, Rule>> = pair.clone().into_inner().collect();
let ty = Box::new(Ty::from_pair(&vec_contents[0])?);
let size = Constant::from_str(vec_contents[1].as_str())?;
Ok(Ty::Array { ty, size })
}
Rule::identifier_type => {
let mut iter = pair.clone().into_inner();
let id = String::from(iter.next().unwrap().as_str());
let nullable = if let Some(pair) = iter.next() {
match pair.as_rule() {
Rule::nullable => true,
e => {
return Err(ParseError::UnexpectedToken(e));
}
}
} else {
false
};
Ok(Ty::Ident { id, nullable })
}
Rule::string_type => {
let mut size = None;
let mut nullable = false;
for inner_pair in pair.clone().into_inner() {
match inner_pair.as_rule() {
Rule::constant => {
size = Some(Constant::from_str(inner_pair.as_str())?);
}
Rule::nullable => {
nullable = true;
}
e => {
return Err(ParseError::UnexpectedToken(e));
}
}
}
Ok(Ty::Str { size, nullable })
}
Rule::vector_type => {
let mut iter = pair.clone().into_inner();
let ty = Box::new(Ty::from_pair(&iter.next().unwrap())?);
let mut size = None;
let mut nullable = false;
for inner_pair in iter {
match inner_pair.as_rule() {
Rule::constant => {
size = Some(Constant::from_str(inner_pair.as_str())?);
}
Rule::nullable => {
nullable = true;
}
e => {
return Err(ParseError::UnexpectedToken(e));
}
}
}
Ok(Ty::Vector { ty, size, nullable })
}
_e => Err(ParseError::UnrecognizedType(pair.as_str().to_string())),
}
}
}
// TODO string should be an Ident type
#[derive(PartialEq, Eq, Serialize, Debug, Hash)]
pub struct StructField {
pub attributes: Attrs,
pub ty: Ty,
pub ident: String,
}
impl StructField {
pub fn from_pair(pair: Pair<'_, Rule>) -> Result<Self, ParseError> {
let mut attributes = Attrs::default();
let mut ty = None;
let mut ident = String::default();
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::attributes => {
attributes = Attrs::from_pair(inner_pair)?;
}
Rule::ident => {
ident = String::from(inner_pair.as_str());
}
_ => {
ty = Some(Ty::from_pair(&inner_pair)?);
}
}
}
// TODO use the val field in structs
Ok(StructField {
attributes: attributes,
ty: ty.unwrap(),
ident: ident,
// val: String::from(fields[2].as_str()),
})
}
}
// TODO string should be an Ident type
#[derive(PartialEq, Eq, Serialize, Debug, Hash)]
pub struct UnionField {
pub attributes: Attrs,
pub ty: Ty,
pub ident: String,
}
impl UnionField {
pub fn from_pair(pair: Pair<'_, Rule>) -> Result<Self, ParseError> {
let fields: Vec<Pair<'_, Rule>> = pair.into_inner().collect();
let ty = &fields[1];
Ok(UnionField {
attributes: Attrs::from_pair(fields[0].clone())?,
ty: Ty::from_pair(ty)?,
ident: String::from(fields[2].as_str()),
})
}
}
// TODO string should be an Ident type
#[derive(PartialEq, Eq, Serialize, Debug, Hash)]
pub struct EnumVariant {
pub attributes: Attrs,
pub name: String,
pub size: Constant,
}
impl EnumVariant {
pub fn from_pair(pair: Pair<'_, Rule>) -> Result<Self, ParseError> {
let fields: Vec<Pair<'_, Rule>> = pair.into_inner().collect();
Ok(EnumVariant {
attributes: Attrs::from_pair(fields[0].clone())?,
name: String::from(fields[1].as_str()),
size: Constant::from_str(fields[2].as_str())?,
})
}
}
#[derive(PartialEq, Eq, Serialize, Debug, Hash)]
pub struct Method {
pub attributes: Attrs,
pub name: String,
pub in_params: Vec<(String, Ty)>,
pub out_params: Vec<(String, Ty)>,
}
impl Method {
pub fn from_pair(pair: Pair<'_, Rule>) -> Result<Self, ParseError> {
let mut attributes = Attrs::default();
let mut name = String::default();
let mut in_params = Vec::new();
let mut out_params = Vec::new();
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::attributes => {
attributes = Attrs::from_pair(inner_pair)?;
}
Rule::interface_parameters => {
let mut fields: Vec<Pair<'_, Rule>> = inner_pair.into_inner().collect();
name = String::from(fields[0].as_str());
// TODO cleaner way of getting in/out params
let inner_params = fields.remove(1);
for in_pair in inner_params.into_inner() {
match in_pair.as_rule() {
Rule::parameter => {
let mut param = in_pair.into_inner();
let ty = Ty::from_pair(&param.next().unwrap())?;
let name = String::from(param.next().unwrap().as_str());
in_params.push((name, ty));
}
e => return Err(ParseError::UnexpectedToken(e)),
}
}
let inner_params = fields.remove(1);
for in_pair in inner_params.into_inner() {
match in_pair.as_rule() {
Rule::parameter => {
let mut param = in_pair.into_inner();
let ty = Ty::from_pair(&param.next().unwrap())?;
let name = String::from(param.next().unwrap().as_str());
out_params.push((name, ty));
}
e => return Err(ParseError::UnexpectedToken(e)),
}
}
}
e => return Err(ParseError::UnexpectedToken(e)),
}
}
Ok(Method {
attributes,
name,
in_params,
out_params,
})
}
}
#[derive(PartialEq, Eq, Serialize, Debug, Hash)]
pub enum Decl {
Struct {
attributes: Attrs,
name: String,
fields: Vec<StructField>,
},
Interface {
attributes: Attrs,
name: String,
methods: Vec<Method>,
},
Alias(String, String),
Constant {
attributes: Attrs,
name: String,
ty: Ty,
value: Constant,
},
Union {
attributes: Attrs,
name: String,
fields: Vec<UnionField>,
},
Enum {
attributes: Attrs,
name: String,
ty: Ty,
variants: Vec<EnumVariant>,
},
}
#[derive(PartialEq, Serialize, Debug)]
pub struct BanjoAst {
pub primary_namespace: String,
pub namespaces: HashMap<String, Vec<Decl>>,
}
impl BanjoAst {
pub fn id_to_type(&self, fq_ident: &str) -> Ty {
// check if FQ
let v: Vec<&str> = fq_ident.rsplitn(2, '.').collect();
let mut namespace = self.primary_namespace.as_str();
let mut ident = fq_ident;
if v.len() > 1 {
namespace = v[1];
ident = v[0];
}
match ident {
"usize" => return Ty::USize,
"bool" => return Ty::Bool,
"int8" => return Ty::Int8,
"int16" => return Ty::Int16,
"int32" => return Ty::Int32,
"int64" => return Ty::Int64,
"uint8" => return Ty::UInt8,
"uint16" => return Ty::UInt16,
"uint32" => return Ty::UInt32,
"uint64" => return Ty::UInt64,
"float32" => return Ty::Float32,
"float64" => return Ty::Float64,
"voidptr" => return Ty::Voidptr,
_ => {}
};
for decl in self.namespaces[namespace].iter() {
match decl {
Decl::Interface { name, .. } => {
if name == ident {
return Ty::Interface;
}
}
Decl::Struct { name, .. } => {
if name == ident {
return Ty::Struct;
}
}
Decl::Union { name, .. } => {
if name == ident {
return Ty::Union;
}
}
Decl::Enum { name, .. } => {
if name == ident {
return Ty::Enum;
}
}
Decl::Alias(to, from) => {
if to == ident {
return self.id_to_type(from);
}
}
Decl::Constant { name, ty, .. } => {
if name == ident {
return (*ty).clone();
}
}
}
}
panic!("Unidentified {}", fq_ident);
}
pub fn parse_decl(
pair: Pair<'_, Rule>, _namespaces: &HashMap<String, Vec<Decl>>,
) -> Result<Decl, ParseError> {
match pair.as_rule() {
Rule::struct_declaration => {
let mut attributes = Attrs::default();
let mut name = String::default();
let mut fields = Vec::default();
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::attributes => {
attributes = Attrs::from_pair(inner_pair)?;
}
Rule::ident => {
name = String::from(inner_pair.as_str());
}
Rule::struct_field => fields.push(StructField::from_pair(inner_pair)?),
e => return Err(ParseError::UnexpectedToken(e)),
}
}
Ok(Decl::Struct {
attributes,
name,
fields,
})
}
Rule::enum_declaration => {
let mut attributes = Attrs::default();
let mut name = String::default();
let mut variants = Vec::default();
let mut ty = Ty::UInt16;
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::attributes => {
attributes = Attrs::from_pair(inner_pair)?;
}
Rule::ident => {
name = String::from(inner_pair.as_str());
}
Rule::integer_type => {
ty = Ty::from_pair(&inner_pair)?;
}
Rule::enum_field => variants.push(EnumVariant::from_pair(inner_pair)?),
e => return Err(ParseError::UnexpectedToken(e)),
}
}
Ok(Decl::Enum {
attributes,
name,
ty,
variants,
})
}
Rule::union_declaration => {
let mut attributes = Attrs::default();
let mut name = String::default();
let mut fields = Vec::default();
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::attributes => {
attributes = Attrs::from_pair(inner_pair)?;
}
Rule::ident => {
name = String::from(inner_pair.as_str());
}
Rule::union_field => fields.push(UnionField::from_pair(inner_pair)?),
e => return Err(ParseError::UnexpectedToken(e)),
}
}
Ok(Decl::Union {
attributes,
name,
fields,
})
}
// TODO extend to be more expressive for banjo
Rule::interface_declaration => {
let mut attributes = Attrs::default();
let mut name = String::default();
let mut methods = Vec::default();
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::attributes => {
attributes = Attrs::from_pair(inner_pair)?;
}
Rule::ident => {
name = String::from(inner_pair.as_str());
}
Rule::interface_method => methods.push(Method::from_pair(inner_pair)?),
e => return Err(ParseError::UnexpectedToken(e)),
}
}
Ok(Decl::Interface {
attributes,
name,
methods,
})
}
Rule::const_declaration => {
let mut attributes = Attrs::default();
let mut name = String::default();
let mut ty = Ty::UInt32;
let mut value = Constant::SizedRaw(0);
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::attributes => {
attributes = Attrs::from_pair(inner_pair)?;
}
Rule::ident => {
name = String::from(inner_pair.as_str());
}
Rule::primitive_type => {
ty = Ty::from_pair(&inner_pair)?;
}
Rule::constant => {
value = Constant::from_str(inner_pair.clone().into_span().as_str())?;
}
e => return Err(ParseError::UnexpectedToken(e)),
}
}
Ok(Decl::Constant {
attributes,
name,
ty,
value,
})
}
e => Err(ParseError::UnexpectedToken(e)),
}
}
fn type_to_decl(&self, ty: &Ty) -> Option<&Decl> {
match ty {
Ty::Array { ref ty, .. } => self.type_to_decl(ty),
Ty::Vector { ref ty, .. } => self.type_to_decl(ty),
Ty::Ident { id, .. } => {
// check if FQ
let v: Vec<&str> = id.rsplitn(2, '.').collect();
let (namespace, ident) = if v.len() > 1 {
(v[1], v[0])
} else {
(self.primary_namespace.as_str(), id.as_str())
};
for decl in self.namespaces[namespace].iter() {
match decl {
Decl::Interface { name, .. }
| Decl::Struct { name, .. }
| Decl::Union { name, .. }
| Decl::Enum { name, .. }
| Decl::Constant { name, .. } => {
if name == ident {
return Some(decl);
}
}
Decl::Alias(to, from) => {
if to == ident {
return self.type_to_decl(&self.id_to_type(from));
}
}
}
}
None
}
_ => None,
}
}
// An edge from D1 to D2 means that a C needs to see the declaration
// of D1 before the declaration of D2. For instance, given the banjo
// struct D2 { D1 d; };
// struct D1 { int32 x; };
// D1 has an edge pointing to D2. Note that struct and union pointers,
// unlike inline structs or unions, do not have dependency edges.
fn decl_dependencies(&self, decl: &Decl) -> Result<HashSet<&Decl>, ParseError> {
let mut edges = HashSet::new();
let mut maybe_add_decl = |ty| {
if let Some(type_decl) = self.type_to_decl(ty) {
edges.insert(type_decl);
}
};
match decl {
Decl::Interface { methods, .. } => {
for method in methods {
for (_, ty) in method.in_params.iter() {
maybe_add_decl(&ty);
}
for (_, ty) in method.out_params.iter() {
maybe_add_decl(&ty);
}
}
}
Decl::Struct { fields, .. } => {
for field in fields {
maybe_add_decl(&field.ty);
}
}
Decl::Union { fields, .. } => {
for field in fields {
maybe_add_decl(&field.ty);
}
}
Decl::Alias(_to, from) => {
maybe_add_decl(&self.id_to_type(from));
}
// TODO(surajmalhtora): Implement constant.
Decl::Constant { .. } => (),
// Enum cannot have dependencies.
Decl::Enum { .. } => (),
};
Ok(edges)
}
// Validates that the declarations are cycle free.
fn validate_declaration_deps(&self) -> Result<(), ParseError> {
// The number of undelcared dependencies for each decl.
let mut degrees: HashMap<&Decl, u32> = HashMap::new();
// Records the decls that depend on each other.
let mut inverse_dependencies: HashMap<&Decl, Vec<&Decl>> = HashMap::new();
for decl in self.namespaces.iter().flat_map(|(_, decls)| decls.iter()) {
degrees.insert(&decl, 0);
}
for decl in self.namespaces.iter().flat_map(|(_, decls)| decls.iter()) {
let deps = self.decl_dependencies(&decl)?;
for dep in deps.iter().filter(|&dep| dep != &decl) {
let entry = degrees.get_mut(&decl).unwrap();
*entry += 1;
let entry = inverse_dependencies.entry(&dep).or_insert(Vec::new());
entry.push(&decl);
}
}
// Remove mutability.
let inverse_dependencies = inverse_dependencies;
// Start with all decls that have no incoming edges.
let mut decls_without_deps = degrees
.iter()
.filter(|(_, &degrees)| degrees == 0)
.map(|(&decl, _)| decl)
.collect::<VecDeque<_>>();
let mut decl_order = Vec::new();
// Pull one out of the queue.
while let Some(decl) = decls_without_deps.pop_front() {
assert_eq!(degrees.get(decl), Some(&0));
decl_order.push(decl);
// Decrement the incoming degree of all other decls it points to.
if let Some(inverse_deps) = inverse_dependencies.get(decl) {
for inverse_dep in inverse_deps {
let degree = degrees.get_mut(inverse_dep).unwrap();
assert_ne!(*degree, 0);
*degree -= 1;
if *degree == 0 {
decls_without_deps.push_back(inverse_dep);
}
}
}
}
if decl_order.len() != degrees.len() {
// We didn't visit all the edges! There was a cycle.
return Err(ParseError::InvalidDeps(String::from(
"There is a cycle in the declarations",
)));
}
Ok(())
}
pub fn parse(pair_vec: Vec<Pairs<'_, Rule>>) -> Result<Self, ParseError> {
let mut primary_namespace = None;
let mut namespaces = HashMap::default();
for pairs in pair_vec {
for pair in pairs {
let mut current_namespace = String::default();
let mut namespace = Vec::default();
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::library_header => {
for token in inner_pair.into_inner() {
if Rule::compound_ident == token.as_rule() {
current_namespace = String::from(token.as_str());
if let Some(primary_namespace) = primary_namespace {
if primary_namespace == current_namespace {
return Err(ParseError::AlreadyPrimaryNamespace);
}
}
primary_namespace = Some(String::from(token.as_str()));
}
}
}
Rule::using_decl => {
let contents: Vec<&str> = inner_pair
.clone()
.into_inner()
.map(|p| p.as_str())
.collect();
namespace.push(Decl::Alias(
contents[0].to_string(),
contents[1].to_string(),
));
}
Rule::using => {
for (cnt, pair) in inner_pair.into_inner().enumerate() {
if cnt == 0 {
if !namespaces.contains_key(pair.as_str()) {
return Err(ParseError::UnImported(format!(
"{}",
pair.as_str()
)));
}
} else {
return Err(ParseError::NotYetSupported(String::from(
"'as' in library imports",
)));
}
}
}
Rule::struct_declaration
| Rule::union_declaration
| Rule::enum_declaration
| Rule::interface_declaration
| Rule::const_declaration => {
let decl = Self::parse_decl(inner_pair, &namespaces)?;
namespace.push(decl)
}
Rule::EOI => (),
e => return Err(ParseError::UnexpectedToken(e)),
};
}
namespaces.insert(current_namespace, namespace);
}
}
let ast = BanjoAst {
primary_namespace: primary_namespace.unwrap(),
namespaces,
};
ast.validate_declaration_deps()?;
Ok(ast)
}
}