[DEV-7085] Move sections to IR module

We need to use `Sections` in both the writer and the ASG so it needs to
be in a place that makes sense.
master
Joseph Frazer 2020-03-11 10:23:34 -04:00 committed by Mike Gerwitz
parent 5f3ccc6894
commit 59a0c382af
6 changed files with 287 additions and 265 deletions

View File

@ -185,10 +185,12 @@ mod base;
mod graph;
mod ident;
mod object;
mod section;
pub use graph::{Asg, AsgError, AsgResult, ObjectRef};
pub use ident::{Dim, IdentKind};
pub use object::{FragmentText, Object, Source};
pub use section::{Section, SectionIterator, Sections};
/// Default concrete ASG implementation.
pub type DefaultAsg<'i, Ix> = base::BaseAsg<'i, Ix>;

View File

@ -0,0 +1,274 @@
// Section/Sections IR representation
//
// Copyright (C) 2014-2020 Ryan Specialty Group, LLC.
//
// This file is part of TAME.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use crate::ir::asg::Object;
type ObjectRef<'a, 'i> = &'a Object<'i>;
pub type ObjectVec<'a, 'i> = Vec<ObjectRef<'a, 'i>>;
/// A Section that needs to be written to the buffer
///
/// Most sections will only need a `body`, but some innlude `head` and `tail`
/// information. Rather than dealing with those differently, each `Section`
/// will have a `head` and `tail` that are empty by default.
#[derive(Clone, Default)]
pub struct Section<'a, 'i> {
head: ObjectVec<'a, 'i>,
body: ObjectVec<'a, 'i>,
tail: ObjectVec<'a, 'i>,
}
impl<'a, 'i> Section<'a, 'i> {
/// Constructor for Sections
///
/// ```
/// use tamer::ir::asg::Section;
///
/// let section = Section::new();
/// ```
pub fn new() -> Self {
Self {
head: Vec::new(),
body: Vec::new(),
tail: Vec::new(),
}
}
/// The length of the `Section`
pub fn len(&self) -> usize {
self.head.len() + self.body.len() + self.tail.len()
}
/// Check if the `Section` is empty
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Push an `Object` into a `Section`'s head
pub fn push_head(&mut self, obj: ObjectRef<'a, 'i>) {
self.head.push(&obj)
}
/// Push an `Object` into a `Section`'s body
pub fn push_body(&mut self, obj: ObjectRef<'a, 'i>) {
self.body.push(&obj)
}
/// Push an `Object` into a `Section`'s tail
pub fn push_tail(&mut self, obj: ObjectRef<'a, 'i>) {
self.tail.push(&obj)
}
/// Merge the parts of a `Section` into one [`SectionIterator`]
///
/// The `Section` internals need to be iterated as a group so we needed to
/// create a custom iterator, [`SectionIterator`] to do this for us. This
/// method allows us to access the iterator.
///
/// ```
/// use tamer::ir::asg::{Object, Section};
///
/// let mut section = Section::new();
/// let obj = Object::Empty;
/// let expect = vec![&obj, &obj, &obj];
///
/// section.push_head(&obj);
/// section.push_body(&obj);
/// section.push_tail(&obj);
/// let section_iter = section.iter();
///
/// for object in section_iter {
/// assert_eq!(&obj, object);
/// }
/// ```
pub fn iter(&self) -> SectionIterator {
SectionIterator {
inner: Box::new(
self.head
.iter()
.chain(self.body.iter())
.chain(self.tail.iter())
.copied(),
),
}
}
}
/// Wrapper for an Iterator
///
/// This allows us to iterate over all parts of a [`Section`].
pub struct SectionIterator<'a, 'i> {
inner: Box<dyn Iterator<Item = &'a Object<'i>> + 'a>,
}
impl<'a, 'i> Iterator for SectionIterator<'a, 'i> {
type Item = &'a Object<'i>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
/// Sections that need to be written to a buffer
///
/// All the properties are public [`Section`] objects and will be accessed
/// directly by the the objects interacting with them.
#[derive(Default)]
pub struct Sections<'a, 'i> {
pub map: Section<'a, 'i>,
pub retmap: Section<'a, 'i>,
pub meta: Section<'a, 'i>,
pub worksheet: Section<'a, 'i>,
pub params: Section<'a, 'i>,
pub types: Section<'a, 'i>,
pub funcs: Section<'a, 'i>,
pub rater: Section<'a, 'i>,
}
impl<'a, 'i> Sections<'a, 'i> {
/// Constructor for Sections
///
/// ```
/// use tamer::ir::asg::Sections;
///
/// let sections = Sections::new();
/// ```
pub fn new() -> Self {
Self {
map: Section::new(),
retmap: Section::new(),
meta: Section::new(),
worksheet: Section::new(),
params: Section::new(),
types: Section::new(),
funcs: Section::new(),
rater: Section::new(),
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn section_empty() {
let section = Section::new();
assert!(section.head.is_empty());
assert!(section.body.is_empty());
assert!(section.tail.is_empty());
}
#[test]
fn section_head() {
let mut section = Section::new();
let obj = Object::Empty;
assert!(section.head.is_empty());
section.push_head(&obj);
assert_eq!(Some(&&obj), section.head.get(0));
}
#[test]
fn section_body() {
let mut section = Section::new();
let obj = Object::Empty;
assert!(section.body.is_empty());
section.push_body(&obj);
let body = section.body;
assert_eq!(Some(&&obj), body.get(0));
}
#[test]
fn section_tail() {
let mut section = Section::new();
let obj = Object::Empty;
assert!(section.tail.is_empty());
section.push_tail(&obj);
assert_eq!(Some(&&obj), section.tail.get(0));
}
#[test]
fn section_len() {
let mut section = Section::new();
let obj = Object::Empty;
assert_eq!(0, section.len());
section.push_head(&obj);
assert_eq!(1, section.len());
section.push_body(&obj);
assert_eq!(2, section.len());
section.push_tail(&obj);
assert_eq!(3, section.len());
}
#[test]
fn section_is_empty_head() {
let mut section = Section::new();
let obj = Object::Empty;
assert!(section.is_empty());
section.push_head(&obj);
assert!(!section.is_empty());
}
#[test]
fn section_is_empty_body() {
let mut section = Section::new();
let obj = Object::Empty;
assert!(section.is_empty());
section.push_body(&obj);
assert!(!section.is_empty());
}
#[test]
fn section_is_empty_tail() {
let mut section = Section::new();
let obj = Object::Empty;
assert!(section.is_empty());
section.push_tail(&obj);
assert!(!section.is_empty());
}
#[test]
fn section_iterator() {
let mut section = Section::new();
let obj = Object::Empty;
let expect = vec![&obj, &obj, &obj];
section.push_head(&obj);
section.push_body(&obj);
section.push_tail(&obj);
let collection: Vec<_> = section.iter().collect();
assert_eq!(expect, collection);
}
}

View File

@ -22,9 +22,9 @@
use crate::global;
use crate::ir::asg::{
Asg, AsgError, DefaultAsg, IdentKind, Object, ObjectRef, Source,
Asg, AsgError, DefaultAsg, IdentKind, Object, ObjectRef, Sections, Source,
};
use crate::obj::xmle::writer::{Sections, XmleWriter};
use crate::obj::xmle::writer::XmleWriter;
use crate::obj::xmlo::reader::{XmloError, XmloEvent, XmloReader};
use crate::sym::{DefaultInterner, Interner, Symbol};
use fxhash::{FxHashMap, FxHashSet};

View File

@ -28,7 +28,8 @@
//! The example below is incomplete, but shows the general usage.
//!
//! ```
//! use tamer::obj::xmle::writer::{Sections, XmleWriter};
//! use tamer::obj::xmle::writer::XmleWriter;
//! use tamer::ir::asg::Sections;
//! use tamer::sym::{DefaultInterner, Interner, Symbol};
//! use std::io::Cursor;
//!
@ -44,6 +45,6 @@
mod writer;
mod xmle;
pub use writer::{Result, Section, Sections, Writer, WriterError};
pub use writer::{Result, Writer, WriterError};
pub use xmle::XmleWriter;

View File

@ -17,16 +17,14 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use crate::ir::asg::Object;
use crate::ir::asg::Sections;
use crate::sym::Symbol;
use quick_xml::Error as XmlError;
use std::io::{Error as IoError, Write};
use std::result;
use std::str::Utf8Error;
type ObjectRef<'a, 'i> = &'a Object<'i>;
pub type Result<T = ()> = result::Result<T, WriterError>;
pub type ObjectVec<'a, 'i> = Vec<ObjectRef<'a, 'i>>;
/// A wrapper around a `Write` object
///
@ -42,148 +40,6 @@ pub trait Writer<W: Write> {
Self: Sized;
}
/// A Section that needs to be written to the buffer
///
/// Most sections will only need a `body`, but some innlude `head` and `tail`
/// information. Rather than dealing with those differently, each `Section`
/// will have a `head` and `tail` that are empty by default.
#[derive(Clone, Default)]
pub struct Section<'a, 'i> {
head: ObjectVec<'a, 'i>,
body: ObjectVec<'a, 'i>,
tail: ObjectVec<'a, 'i>,
}
impl<'a, 'i> Section<'a, 'i> {
/// Constructor for Sections
///
/// ```
/// use tamer::obj::xmle::writer::Section;
///
/// let section = Section::new();
/// ```
pub fn new() -> Self {
Self {
head: Vec::new(),
body: Vec::new(),
tail: Vec::new(),
}
}
/// The length of the `Section`
pub fn len(&self) -> usize {
self.head.len() + self.body.len() + self.tail.len()
}
/// Check if the `Section` is empty
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Push an `Object` into a `Section`'s head
pub fn push_head(&mut self, obj: ObjectRef<'a, 'i>) {
self.head.push(&obj)
}
/// Push an `Object` into a `Section`'s body
pub fn push_body(&mut self, obj: ObjectRef<'a, 'i>) {
self.body.push(&obj)
}
/// Push an `Object` into a `Section`'s tail
pub fn push_tail(&mut self, obj: ObjectRef<'a, 'i>) {
self.tail.push(&obj)
}
/// Merge the parts of a `Section` into one [`SectionIterator`]
///
/// The `Section` internals need to be iterated as a group so we needed to
/// create a custom iterator, [`SectionIterator`] to do this for us. This
/// method allows us to access the iterator.
///
/// ```
/// use tamer::obj::xmle::writer::Section;
/// use tamer::ir::asg::Object;
///
/// let mut section = Section::new();
/// let obj = Object::Empty;
/// let expect = vec![&obj, &obj, &obj];
///
/// section.push_head(&obj);
/// section.push_body(&obj);
/// section.push_tail(&obj);
/// let section_iter = section.iter();
///
/// for object in section_iter {
/// assert_eq!(&obj, object);
/// }
/// ```
pub fn iter(&self) -> SectionIterator {
SectionIterator {
inner: Box::new(
self.head
.iter()
.chain(self.body.iter())
.chain(self.tail.iter())
.copied(),
),
}
}
}
/// Wrapper for an Iterator
///
/// This allows us to iterate over all parts of a [`Section`].
pub struct SectionIterator<'a, 'i> {
inner: Box<dyn Iterator<Item = &'a Object<'i>> + 'a>,
}
impl<'a, 'i> Iterator for SectionIterator<'a, 'i> {
type Item = &'a Object<'i>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
/// Sections that need to be written to a buffer
///
/// All the properties are public [`Section`] objects and will be accessed
/// directly by the [`Writer`].
#[derive(Default)]
pub struct Sections<'a, 'i> {
pub map: Section<'a, 'i>,
pub retmap: Section<'a, 'i>,
pub meta: Section<'a, 'i>,
pub worksheet: Section<'a, 'i>,
pub params: Section<'a, 'i>,
pub types: Section<'a, 'i>,
pub funcs: Section<'a, 'i>,
pub rater: Section<'a, 'i>,
}
impl<'a, 'i> Sections<'a, 'i> {
/// Constructor for Sections
///
/// ```
/// use tamer::obj::xmle::writer::Sections;
///
/// let sections = Sections::new();
/// ```
pub fn new() -> Self {
Self {
map: Section::new(),
retmap: Section::new(),
meta: Section::new(),
worksheet: Section::new(),
params: Section::new(),
types: Section::new(),
funcs: Section::new(),
rater: Section::new(),
}
}
}
/// Error implementations for the writer
#[derive(Debug)]
pub enum WriterError {
@ -233,113 +89,3 @@ impl From<XmlError> for WriterError {
WriterError::XmlError(err)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn section_empty() {
let section = Section::new();
assert!(section.head.is_empty());
assert!(section.body.is_empty());
assert!(section.tail.is_empty());
}
#[test]
fn section_head() {
let mut section = Section::new();
let obj = Object::Empty;
assert!(section.head.is_empty());
section.push_head(&obj);
assert_eq!(Some(&&obj), section.head.get(0));
}
#[test]
fn section_body() {
let mut section = Section::new();
let obj = Object::Empty;
assert!(section.body.is_empty());
section.push_body(&obj);
let body = section.body;
assert_eq!(Some(&&obj), body.get(0));
}
#[test]
fn section_tail() {
let mut section = Section::new();
let obj = Object::Empty;
assert!(section.tail.is_empty());
section.push_tail(&obj);
assert_eq!(Some(&&obj), section.tail.get(0));
}
#[test]
fn section_len() {
let mut section = Section::new();
let obj = Object::Empty;
assert_eq!(0, section.len());
section.push_head(&obj);
assert_eq!(1, section.len());
section.push_body(&obj);
assert_eq!(2, section.len());
section.push_tail(&obj);
assert_eq!(3, section.len());
}
#[test]
fn section_is_empty_head() {
let mut section = Section::new();
let obj = Object::Empty;
assert!(section.is_empty());
section.push_head(&obj);
assert!(!section.is_empty());
}
#[test]
fn section_is_empty_body() {
let mut section = Section::new();
let obj = Object::Empty;
assert!(section.is_empty());
section.push_body(&obj);
assert!(!section.is_empty());
}
#[test]
fn section_is_empty_tail() {
let mut section = Section::new();
let obj = Object::Empty;
assert!(section.is_empty());
section.push_tail(&obj);
assert!(!section.is_empty());
}
#[test]
fn section_iterator() {
let mut section = Section::new();
let obj = Object::Empty;
let expect = vec![&obj, &obj, &obj];
section.push_head(&obj);
section.push_body(&obj);
section.push_tail(&obj);
let collection: Vec<_> = section.iter().collect();
assert_eq!(expect, collection);
}
}

View File

@ -17,8 +17,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use super::writer::{Result, SectionIterator, Sections, WriterError};
use crate::ir::asg::{IdentKind, Object};
use super::writer::{Result, WriterError};
use crate::ir::asg::{IdentKind, Object, SectionIterator, Sections};
use crate::sym::Symbol;
use fxhash::FxHashSet;
#[cfg(test)]
@ -69,7 +69,8 @@ impl<W: Write> XmleWriter<W> {
///
/// ```
/// use std::io::Cursor;
/// use tamer::obj::xmle::writer::{Sections, XmleWriter};
/// use tamer::obj::xmle::writer::XmleWriter;
/// use tamer::ir::asg::Sections;
/// use tamer::sym::{Symbol, SymbolIndex};
/// use tamer::sym::{DefaultInterner, Interner};
///
@ -410,10 +411,8 @@ mod mock {
#[cfg(test)]
mod test {
use super::*;
use crate::ir::asg::Dim;
use crate::ir::asg::Source;
use crate::ir::asg::{Dim, Section, Source};
use crate::ir::legacyir::SymAttrs;
use crate::obj::xmle::writer::Section;
use crate::sym::{Symbol, SymbolIndex};
use std::str;