[DEV-7084] TAMER: AsgBuilder extracted from POC

This extracts the changes nearly verbatim before doing refactoring so that
it's easier to observe what changes have been made.
master
Mike Gerwitz 2020-04-06 23:28:07 -04:00
parent 7ed0691c45
commit 3f46917da9
3 changed files with 199 additions and 105 deletions

View File

@ -25,14 +25,14 @@ use crate::fs::{
};
use crate::global;
use crate::ir::asg::{
Asg, AsgError, DefaultAsg, IdentKind, IdentObject, IdentObjectData,
ObjectRef, Sections, SortableAsg, Source,
Asg, AsgError, DefaultAsg, IdentObject, IdentObjectData, ObjectRef,
Sections, SortableAsg,
};
use crate::obj::xmle::writer::XmleWriter;
use crate::obj::xmlo::reader::{XmloError, XmloEvent, XmloReader};
use crate::obj::xmlo::reader::{XmloError, XmloReader};
use crate::obj::xmlo::{AsgBuilder, AsgBuilderResult};
use crate::sym::{DefaultInterner, Interner, Symbol};
use fxhash::{FxBuildHasher, FxHashMap, FxHashSet};
use std::convert::TryInto;
use fxhash::{FxBuildHasher, FxHashMap};
use std::error::Error;
use std::fs;
use std::io::BufReader;
@ -131,8 +131,6 @@ fn load_xmlo<'a, 'i, I: Interner<'i>>(
) -> LoadResult<'i> {
let first = fs.visit_len() == 0;
let mut found: FxHashSet<&str> = Default::default();
let cfile: CanonicalFile<BufReader<fs::File>> = match fs.open(path_str)? {
VisitOnceFile::FirstVisit(file) => file,
VisitOnceFile::Visited => return Ok(None),
@ -140,106 +138,16 @@ fn load_xmlo<'a, 'i, I: Interner<'i>>(
let (path, file) = cfile.into();
let mut xmlo: XmloReader<'_, _, _> = (file, interner).into();
let mut elig = None;
let xmlo: XmloReader<'_, _, _> = (file, interner).into();
let mut name: Option<&'i Symbol<'i>> = None;
let mut relroot: Option<String> = None;
let AsgBuilderResult::<'i, FxBuildHasher, _> {
found,
roots: mut pkgroots,
name,
relroot,
} = xmlo.build(depgraph, first)?;
loop {
match xmlo.read_event() {
Ok(XmloEvent::Package(attrs)) => {
if first {
name = attrs.name;
relroot = attrs.relroot;
}
elig = attrs.elig;
}
Ok(XmloEvent::SymDeps(sym, deps)) => {
// TODO: API needs to expose whether a symbol is already
// known so that we can warn on them
// Maps should not pull in symbols since we may end up
// mapping to params that are never actually used
if !sym.starts_with(":map:") {
for dep_sym in deps {
depgraph.add_dep_lookup(sym, dep_sym);
}
}
}
Ok(XmloEvent::SymDecl(sym, attrs)) => {
if let Some(sym_src) = attrs.src {
found.insert(sym_src);
} else {
let owned = attrs.src.is_none();
let extern_ = attrs.extern_;
let kind = (&attrs).try_into().map_err(|err| {
format!("sym `{}` attrs error: {}", sym, err)
});
let mut src: Source = attrs.into();
// Existing convention is to omit @src of local package
// (in this case, the program being linked)
if first {
src.pkg_name = None;
}
match kind {
Ok(kindval) => {
// TODO: inefficient
let link_root = owned
&& (kindval == IdentKind::Meta
|| kindval == IdentKind::Map
|| kindval == IdentKind::RetMap);
if extern_ {
depgraph.declare_extern(sym, kindval, src)?;
} else {
let node =
depgraph.declare(sym, kindval, src)?;
if link_root {
roots.push(node);
}
}
}
Err(e) => return Err(e.into()),
};
}
}
Ok(XmloEvent::Fragment(sym, text)) => {
match depgraph.lookup(sym) {
Some(frag) => match depgraph.set_fragment(frag, text) {
Ok(_) => (),
Err(e) => return Err(e.into()),
},
None => {
return Err(XmloError::MissingFragment(String::from(
"missing fragment",
))
.into());
}
};
}
// We don't need to read any further than the end of the
// header (symtable, sym-deps, fragments)
Ok(XmloEvent::Eoh) => break,
Err(e) => return Err(e.into()),
}
}
if let Some(elig_sym) = elig {
roots.push(depgraph.lookup(elig_sym).expect(
"internal error: package elig references nonexistant symbol",
));
}
roots.append(&mut pkgroots);
let mut dir: PathBuf = path.clone();
dir.pop();

View File

@ -0,0 +1,183 @@
// Read from xmlo and immediately lower to ASG IR
//
// 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 super::reader::{XmloError, XmloEvent, XmloReader};
use crate::ir::asg::{Asg, IdentKind, IdentObjectState, ObjectRef, Source};
use crate::sym::{Interner, Symbol};
use petgraph::graph::IndexType;
use std::convert::TryInto;
use std::error::Error;
use std::hash::BuildHasher;
use std::collections::HashSet;
use std::io::BufRead;
// TODO error type
pub type Result<'i, S, Ix> =
std::result::Result<AsgBuilderResult<'i, S, Ix>, Box<dyn Error>>;
pub struct AsgBuilderResult<'i, S, Ix>
where
S: BuildHasher + Default,
Ix: IndexType,
{
pub roots: Vec<ObjectRef<Ix>>,
pub found: HashSet<&'i str, S>,
pub name: Option<&'i Symbol<'i>>,
pub relroot: Option<String>,
}
pub trait AsgBuilder<'i, O, S, Ix>
where
O: IdentObjectState<'i, O>,
S: BuildHasher + Default,
Ix: IndexType,
{
fn build<G: Asg<'i, O, Ix>>(
self,
graph: &mut G,
first: bool,
) -> Result<'i, S, Ix>;
}
impl<'i, B, I, O, S, Ix> AsgBuilder<'i, O, S, Ix> for XmloReader<'i, B, I>
where
B: BufRead,
I: Interner<'i>,
O: IdentObjectState<'i, O>,
S: BuildHasher + Default,
Ix: IndexType,
{
// TOOD: remove first
fn build<G: Asg<'i, O, Ix>>(
mut self,
graph: &mut G,
first: bool,
) -> Result<'i, S, Ix> {
// TODO
let mut found: HashSet<&'i str, S> = Default::default();
let mut roots = Vec::new();
let mut elig = None;
let mut name: Option<&'i Symbol<'i>> = None;
let mut relroot: Option<String> = None;
loop {
match self.read_event() {
Ok(XmloEvent::Package(attrs)) => {
if first {
name = attrs.name;
relroot = attrs.relroot;
}
elig = attrs.elig;
}
Ok(XmloEvent::SymDeps(sym, deps)) => {
// TODO: API needs to expose whether a symbol is already
// known so that we can warn on them
// Maps should not pull in symbols since we may end up
// mapping to params that are never actually used
if !sym.starts_with(":map:") {
for dep_sym in deps {
graph.add_dep_lookup(sym, dep_sym);
}
}
}
Ok(XmloEvent::SymDecl(sym, attrs)) => {
if let Some(sym_src) = attrs.src {
found.insert(sym_src);
} else {
let owned = attrs.src.is_none();
let extern_ = attrs.extern_;
let kind = (&attrs).try_into().map_err(|err| {
format!("sym `{}` attrs error: {}", sym, err)
});
let mut src: Source = attrs.into();
// Existing convention is to omit @src of local package
// (in this case, the program being linked)
if first {
src.pkg_name = None;
}
match kind {
Ok(kindval) => {
// TODO: inefficient
let link_root = owned
&& (kindval == IdentKind::Meta
|| kindval == IdentKind::Map
|| kindval == IdentKind::RetMap);
if extern_ {
graph.declare_extern(sym, kindval, src)?;
} else {
let node =
graph.declare(sym, kindval, src)?;
if link_root {
roots.push(node);
}
}
}
Err(e) => return Err(e.into()),
};
}
}
Ok(XmloEvent::Fragment(sym, text)) => {
match graph.lookup(sym) {
Some(frag) => match graph.set_fragment(frag, text) {
Ok(_) => (),
Err(e) => return Err(e.into()),
},
None => {
return Err(XmloError::MissingFragment(
String::from("missing fragment"),
)
.into());
}
};
}
// We don't need to read any further than the end of the
// header (symtable, sym-deps, fragments)
Ok(XmloEvent::Eoh) => break,
Err(e) => return Err(e.into()),
}
}
if let Some(elig_sym) = elig {
roots.push(graph.lookup(elig_sym).expect(
"internal error: package elig references nonexistant symbol",
));
}
Ok(AsgBuilderResult {
roots,
found,
name,
relroot,
})
}
}

View File

@ -75,3 +75,6 @@
//! ```
pub mod reader;
mod asg_builder;
pub use asg_builder::{AsgBuilder, AsgBuilderResult};