Skip to content

Commit

Permalink
tests for apply_explicit_annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
timbod7 committed Aug 15, 2022
1 parent 156f0c0 commit 73a45b4
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 62 deletions.
1 change: 1 addition & 0 deletions rust/compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ pub mod adlgen;
pub mod adlrt;
pub mod parser;
pub mod processing;
pub mod utils;

9 changes: 2 additions & 7 deletions rust/compiler/src/parser/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use std::fs;
use std::path::PathBuf;

use crate::utils::ast::{mk_typeexpr0, mk_scoped_name};

use super::*;
use nom::{
error::{ErrorKind, VerboseError, VerboseErrorKind},
Expand Down Expand Up @@ -360,10 +362,3 @@ fn mk_json_map(vs: Vec<(String,serde_json::Value)>) -> serde_json::Map<String, s
map
}

fn mk_scoped_name(mname: &str, name: &str) -> adlast::ScopedName {
adlast::ScopedName::new(mname.to_string(), name.to_string())
}

fn mk_typeexpr0(type_ref: adlast::ScopedName) -> adlast::TypeExpr<adlast::ScopedName> {
adlast::TypeExpr{type_ref, parameters: vec![]}
}
136 changes: 136 additions & 0 deletions rust/compiler/src/processing/annotations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
use crate::adlgen::sys::{adlast2 as adlast};
use crate::parser::{RawModule, ExplicitAnnotationRef};

type TypeExpr0 = adlast::TypeExpr<adlast::ScopedName>;
type Module0 = adlast::Module<TypeExpr0>;


/// Attach explicit annotations to the appropriate nodes in the AST. On failure, returns
/// the nodes that could not be attached.
pub fn apply_explicit_annotations(raw_module: RawModule) -> Result<Module0, Vec<UnResolvedExplicitAnnotation>> {
let (mut module0, explicit_annotations) = raw_module;
let mut unresolved = Vec::new();

for ea in explicit_annotations {
let aref = find_annotations_ref(&ea.refr, &mut module0);
match aref {
Some(aref) => { aref.0.insert(ea.scoped_name,ea.value); }
None => { unresolved.push(ea.refr); }
}
}

if unresolved.is_empty() {
Ok(module0)
} else {
Err(unresolved)
}
}

/// Find the referenced annotations hashmap
fn find_annotations_ref<'a>(ear: &ExplicitAnnotationRef, module0: &'a mut Module0) -> Option<&'a mut adlast::Annotations> {
match ear {
ExplicitAnnotationRef::Module => {
Some(&mut module0.annotations)
}
ExplicitAnnotationRef::Decl(decl_name) => {
if let Some(decl) = module0.decls.get_mut(decl_name) {
return Some(&mut decl.annotations);
}
None
}
ExplicitAnnotationRef::Field((decl_name, field_name)) => {
if let Some(decl) = module0.decls.get_mut(decl_name) {
let ofields = match &mut decl.r#type {
adlast::DeclType::Struct(s) => Some(&mut s.fields),
adlast::DeclType::Union(u) => Some(&mut u.fields),
_ => None,
};
if let Some(fields) = ofields {
let ofield = fields.iter_mut().find(|f| f.name.value == *field_name);
if let Some(field) = ofield {
return Some(&mut field.annotations);
}
}
}
None
}
}
}

type UnResolvedExplicitAnnotation = ExplicitAnnotationRef;


#[cfg(test)]
mod tests {
use nom_locate::LocatedSpan;
use crate::{parser::raw_module, utils::ast::mk_scoped_name};
use crate::adlgen::sys::{adlast2 as adlast};


#[test]
fn explicit_annotations_ok() {
let rm = raw_module(LocatedSpan::new(OK_ADL)).unwrap().1;

// We should have 3 explicit annotations to attach
assert_eq!(rm.1.len(), 3);

let m0 = super::apply_explicit_annotations(rm).unwrap();
assert_eq!(m0.annotations.0.get(&mk_scoped_name("", "A")), Some(&serde_json::Value::from(1i32)));
assert_eq!(m0.annotations.0.get(&mk_scoped_name("", "E")), Some(&serde_json::Value::from(6i32)));

let decl = m0.decls.get("Y").unwrap();
assert_eq!(decl.annotations.0.get(&mk_scoped_name("", "B")), Some(&serde_json::Value::from(2i32)));
assert_eq!(decl.annotations.0.get(&mk_scoped_name("", "F")), Some(&serde_json::Value::from(7i32)));

let field = if let adlast::DeclType::Struct(s) = &decl.r#type {
s.fields.iter().find(|f| f.name.value == "z")
} else {
None
}.unwrap();
assert_eq!(field.annotations.0.get(&mk_scoped_name("", "C")), Some(&serde_json::Value::from(3i32)));
assert_eq!(field.annotations.0.get(&mk_scoped_name("", "G")), Some(&serde_json::Value::from(8i32)));
}

const OK_ADL: &str = "
@A 1
module X {
@B 2
struct Y {
@C 3
Word64 z;
};
annotation E 6;
annotation Y F 7;
annotation Y::z G 8;
}
";

#[test]
fn explicit_annotations_bad() {
let rm = raw_module(LocatedSpan::new(BAD_ADL)).unwrap().1;

// We should have 3 explicit annotations to attach
assert_eq!(rm.1.len(), 3);

let err = super::apply_explicit_annotations(rm).unwrap_err();

// All of which should have failed
assert_eq!(err.len(), 3);
}

const BAD_ADL: &str = "
module X {
struct Y {
Word64 z;
};
annotation A F 7;
annotation A::z G 8;
annotation Y::q G 9;
}
";


}
58 changes: 3 additions & 55 deletions rust/compiler/src/processing/mod.rs
Original file line number Diff line number Diff line change
@@ -1,64 +1,12 @@
use crate::adlgen::sys::{adlast2 as adlast};
use crate::parser::{RawModule, ExplicitAnnotationRef};

type TypeExpr0 = adlast::TypeExpr<adlast::ScopedName>;
pub type Module0 = adlast::Module<TypeExpr0>;

pub mod annotations;

pub trait AdlLoader {
/// Find and load the specified ADL module
fn load(module_name: adlast::ModuleName) -> Result<Option<RawModule>, anyhow::Error>;
}

/// Attach explicit annotations to the appropriate nodes in the AST. On failure, returns
/// the nodes that could not be attached.
pub fn apply_explicit_annotations(raw_module: RawModule) -> Result<Module0, Vec<UnResolvedExplicitAnnotation>> {
let (mut module0, explicit_annotations) = raw_module;
let mut unresolved = Vec::new();

for ea in explicit_annotations {
let aref = find_annotations_ref(&ea.refr, &mut module0);
match aref {
Some(aref) => { aref.0.insert(ea.scoped_name,ea.value); }
None => { unresolved.push(ea.refr); }
}
}

if unresolved.is_empty() {
Ok(module0)
} else {
Err(unresolved)
}
}

/// Find the referenced annotations hashmap
fn find_annotations_ref<'a>(ear: &ExplicitAnnotationRef, module0: &'a mut Module0) -> Option<&'a mut adlast::Annotations> {
match ear {
ExplicitAnnotationRef::Module => {
Some(&mut module0.annotations)
}
ExplicitAnnotationRef::Decl(decl_name) => {
if let Some(decl) = module0.decls.get_mut(decl_name) {
return Some(&mut decl.annotations);
}
None
}
ExplicitAnnotationRef::Field((decl_name, field_name)) => {
if let Some(decl) = module0.decls.get_mut(decl_name) {
let ofields = match &mut decl.r#type {
adlast::DeclType::Struct(s) => Some(&mut s.fields),
adlast::DeclType::Union(u) => Some(&mut u.fields),
_ => None,
};
if let Some(fields) = ofields {
let ofield = fields.iter_mut().find(|f| f.name.value == *field_name);
if let Some(field) = ofield {
return Some(&mut field.annotations);
}
}
}
None
}
}
fn load(module_name: adlast::ModuleName) -> Result<Module0, anyhow::Error>;
}

type UnResolvedExplicitAnnotation = ExplicitAnnotationRef;
10 changes: 10 additions & 0 deletions rust/compiler/src/utils/ast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

use crate::adlgen::sys::{adlast2 as adlast};

pub fn mk_scoped_name(mname: &str, name: &str) -> adlast::ScopedName {
adlast::ScopedName::new(mname.to_string(), name.to_string())
}

pub fn mk_typeexpr0(type_ref: adlast::ScopedName) -> adlast::TypeExpr<adlast::ScopedName> {
adlast::TypeExpr{type_ref, parameters: vec![]}
}
1 change: 1 addition & 0 deletions rust/compiler/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod ast;

0 comments on commit 73a45b4

Please sign in to comment.