Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'tamer/src/ld/poc.rs')
-rw-r--r--tamer/src/ld/poc.rs201
1 files changed, 41 insertions, 160 deletions
diff --git a/tamer/src/ld/poc.rs b/tamer/src/ld/poc.rs
index c75aacb..11f2f23 100644
--- a/tamer/src/ld/poc.rs
+++ b/tamer/src/ld/poc.rs
@@ -20,54 +20,47 @@
//! **This is a poorly-written proof of concept; do not use!** It has been
//! banished to its own file to try to make that more clear.
+use crate::fs::{
+ Filesystem, FsCanonicalizer, PathFile, VisitOnceFile, VisitOnceFilesystem,
+};
use crate::global;
use crate::ir::asg::{
- Asg, AsgError, DefaultAsg, IdentKind, IdentObject, IdentObjectData,
- ObjectRef, Sections, SortableAsg, Source,
+ Asg, AsgError, DefaultAsg, IdentObject, IdentObjectData, Sections,
+ SortableAsg,
};
use crate::obj::xmle::writer::XmleWriter;
-use crate::obj::xmlo::reader::{XmloError, XmloEvent, XmloReader};
+use crate::obj::xmlo::{AsgBuilder, AsgBuilderState, XmloReader};
use crate::sym::{DefaultInterner, Interner, Symbol};
-use fxhash::{FxHashMap, FxHashSet};
-use std::convert::TryInto;
+use fxhash::FxBuildHasher;
use std::error::Error;
use std::fs;
use std::io::BufReader;
+use std::path::{Path, PathBuf};
type LinkerAsg<'i> = DefaultAsg<'i, IdentObject<'i>, global::ProgIdentSize>;
-type LinkerObjectRef = ObjectRef<global::ProgIdentSize>;
-type LoadResult<'i> =
- Result<Option<(Option<&'i Symbol<'i>>, Option<String>)>, Box<dyn Error>>;
+type LinkerAsgBuilderState<'i> =
+ AsgBuilderState<'i, FxBuildHasher, global::ProgIdentSize>;
pub fn main(package_path: &str, output: &str) -> Result<(), Box<dyn Error>> {
- let mut pkgs_seen: FxHashSet<String> = Default::default();
- let mut fragments: FxHashMap<&str, String> = Default::default();
+ let mut fs = VisitOnceFilesystem::new();
let mut depgraph = LinkerAsg::with_capacity(65536, 65536);
- let mut roots = Vec::new();
let interner = DefaultInterner::new();
- let abs_path = fs::canonicalize(package_path)?;
-
- let (name, relroot) = load_xmlo(
- &abs_path.to_str().unwrap().to_string(),
- &mut pkgs_seen,
- &mut fragments,
+ let state = load_xmlo(
+ package_path,
+ &mut fs,
&mut depgraph,
&interner,
- &mut roots,
- )?
- .expect("missing root package information");
+ AsgBuilderState::new(),
+ )?;
- // println!(
- // "Graph {:?}",
- // depgraph
- // .graph
- // .raw_nodes()
- // .iter()
- // .map(|node| &node.weight)
- // .collect::<Vec<_>>()
- // );
+ let AsgBuilderState {
+ mut roots,
+ name,
+ relroot,
+ found: _,
+ } = state;
roots.extend(
vec!["___yield", "___worksheet"]
@@ -117,160 +110,48 @@ pub fn main(package_path: &str, output: &str) -> Result<(), Box<dyn Error>> {
Ok(())
}
-fn load_xmlo<'a, 'i, I: Interner<'i>>(
- path_str: &'a str,
- pkgs_seen: &mut FxHashSet<String>,
- fragments: &mut FxHashMap<&'i str, String>,
+fn load_xmlo<'a, 'i, I: Interner<'i>, P: AsRef<Path>>(
+ path_str: P,
+ fs: &mut VisitOnceFilesystem<FsCanonicalizer, FxBuildHasher>,
depgraph: &mut LinkerAsg<'i>,
interner: &'i I,
- roots: &mut Vec<LinkerObjectRef>,
-) -> LoadResult<'i> {
- let path = fs::canonicalize(path_str)?;
- let path_str = path.to_str().unwrap();
-
- let first = pkgs_seen.len() == 0;
-
- if !pkgs_seen.insert(path_str.to_string()) {
- return Ok(None);
- }
-
- //println!("processing {}", path_str);
-
- let mut found: FxHashSet<&str> = Default::default();
-
- let file = fs::File::open(&path)?;
- let reader = BufReader::new(file);
- let mut xmlo = XmloReader::new(reader, interner);
- let mut elig = None;
-
- let mut name: Option<&'i Symbol<'i>> = None;
- let mut relroot: Option<String> = None;
-
- 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());
- }
- };
- }
+ state: LinkerAsgBuilderState<'i>,
+) -> Result<LinkerAsgBuilderState<'i>, Box<dyn Error>> {
+ let cfile: PathFile<BufReader<fs::File>> = match fs.open(path_str)? {
+ VisitOnceFile::FirstVisit(file) => file,
+ VisitOnceFile::Visited => return Ok(state),
+ };
- // We don't need to read any further than the end of the
- // header (symtable, sym-deps, fragments)
- Ok(XmloEvent::Eoh) => break,
+ let (path, file) = cfile.into();
- Err(e) => return Err(e.into()),
- }
- }
+ let xmlo: XmloReader<'_, _, _> = (file, interner).into();
- if let Some(elig_sym) = elig {
- roots.push(depgraph.lookup(elig_sym).expect(
- "internal error: package elig references nonexistant symbol",
- ));
- }
+ let mut state = depgraph.import_xmlo(xmlo, state)?;
- let mut dir = path.clone();
+ let mut dir: PathBuf = path.clone();
dir.pop();
+ let found = state.found.take().unwrap_or_default();
+
for relpath in found.iter() {
let mut path_buf = dir.clone();
path_buf.push(relpath);
path_buf.set_extension("xmlo");
- // println!("Trying {:?}", path_buf);
- let path_abs = path_buf.canonicalize()?;
- let path = path_abs.to_str().unwrap();
-
- load_xmlo(path, pkgs_seen, fragments, depgraph, interner, roots)?;
+ state = load_xmlo(path_buf, fs, depgraph, interner, state)?;
}
- if first {
- Ok(Some((name, relroot)))
- } else {
- Ok(None)
- }
+ Ok(state)
}
fn get_ident<'a, 'i>(
depgraph: &'a LinkerAsg<'i>,
name: &'i Symbol<'i>,
-) -> Result<&'a IdentObject<'i>, XmloError> {
+) -> Result<&'a IdentObject<'i>, String> {
depgraph
.lookup(name)
.and_then(|id| depgraph.get(id))
- .ok_or(XmloError::MissingFragment(String::from(name as &str)))
+ .ok_or(format!("missing identifier: {}", name))
}
fn output_xmle<'a, 'i, I: Interner<'i>>(