Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@ryansg.com>2020-01-13 16:41:06 -0500
committerMike Gerwitz <mike.gerwitz@ryansg.com>2020-02-26 10:49:00 -0500
commit6939753ca04416082720a0e773a3491686f25a4d (patch)
treefc60e5152b74274b814b57156417b8b7a2cda338 /tamer/src/ld/poc.rs
parent85a4934db55b8f3f4b8f0f82a75d31c967963a96 (diff)
downloadtame-6939753ca04416082720a0e773a3491686f25a4d.tar.gz
tame-6939753ca04416082720a0e773a3491686f25a4d.tar.bz2
tame-6939753ca04416082720a0e773a3491686f25a4d.zip
TAMER: POC: Output xmle
This is a working proof-of-concept that will be finalized in future commits.
Diffstat (limited to 'tamer/src/ld/poc.rs')
-rw-r--r--tamer/src/ld/poc.rs312
1 files changed, 297 insertions, 15 deletions
diff --git a/tamer/src/ld/poc.rs b/tamer/src/ld/poc.rs
index d11d863..59928f3 100644
--- a/tamer/src/ld/poc.rs
+++ b/tamer/src/ld/poc.rs
@@ -24,11 +24,13 @@ use crate::ir::asg::{Asg, DefaultAsg, Object, ObjectRef};
use crate::obj::xmlo::reader::{XmloError, XmloEvent, XmloReader};
use crate::sym::{DefaultInterner, Interner};
use petgraph::visit::DfsPostOrder;
+use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
+use quick_xml::Writer;
use std::collections::{HashMap, HashSet};
use std::convert::TryInto;
use std::error::Error;
use std::fs;
-use std::io::BufReader;
+use std::io::{BufReader, Write};
type LinkerAsg<'i> = DefaultAsg<'i, global::ProgIdentSize>;
type LinkerObjectRef = ObjectRef<global::ProgIdentSize>;
@@ -73,7 +75,9 @@ pub fn main() -> Result<(), Box<dyn Error>> {
let sorted = sort_deps(&depgraph, &roots);
- println!("Sorted ({}): {:?}", sorted.len(), sorted);
+ //println!("Sorted ({}): {:?}", sorted.len(), sorted);
+
+ output_xmle(&depgraph, &interner, sorted)?;
Ok(())
}
@@ -118,13 +122,18 @@ fn load_xmlo<'a, 'i, I: Interner<'i>>(
.lookup(sym)
.expect(&format!("missing sym for deps: `{}`", sym));
- for dep_sym in deps {
- let dep_node = depgraph.lookup(dep_sym).expect(&format!(
- "missing dep sym for deps: `{}` -> `{}`",
- sym, dep_sym
- ));
-
- depgraph.add_dep(sym_node, dep_node);
+ // 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 {
+ let dep_node =
+ depgraph.lookup(dep_sym).expect(&format!(
+ "missing dep sym for deps: `{}` -> `{}`",
+ sym, dep_sym
+ ));
+
+ depgraph.add_dep(sym_node, dep_node);
+ }
}
}
@@ -147,8 +156,8 @@ fn load_xmlo<'a, 'i, I: Interner<'i>>(
// TODO: inefficient
let link_root = owned
&& (kindval == IdentKind::Meta
- || sym.starts_with(":map:")
- || sym.starts_with(":retmap:"));
+ || kindval == IdentKind::Map
+ || kindval == IdentKind::RetMap);
let node = depgraph.declare(sym, kindval, src)?;
@@ -211,18 +220,35 @@ fn load_xmlo<'a, 'i, I: Interner<'i>>(
Ok(())
}
+type ObjectVec<'a, 'i> = Vec<&'a Object<'i>>;
+
+// Note that the classifier has nothing in it anymore; it's only there for
+// API compability, so we don't include it here.
+#[derive(Default)]
+struct SortedDeps<'a, 'i> {
+ map: ObjectVec<'a, 'i>,
+ retmap: ObjectVec<'a, 'i>,
+ meta: ObjectVec<'a, 'i>,
+ worksheet: ObjectVec<'a, 'i>,
+ params: ObjectVec<'a, 'i>,
+ types: ObjectVec<'a, 'i>,
+ funcs: ObjectVec<'a, 'i>,
+ rater: ObjectVec<'a, 'i>,
+}
+
fn sort_deps<'a, 'i>(
depgraph: &'a LinkerAsg<'i>,
roots: &Vec<LinkerObjectRef>,
-) -> Vec<&'a Object<'i>> {
+) -> SortedDeps<'a, 'i> {
// @type=meta, @preproc:elig-class-yields
// @type={ret}map{,:head,:tail}
+ let mut deps: SortedDeps = Default::default();
+
// This is technically a topological sort, but functions have
// cycles. Once we have more symbol metadata, we can filter them out
// and actually invoke toposort.
let mut dfs = DfsPostOrder::empty(&depgraph);
- let mut sorted = Vec::new();
//println!("discovered roots: {:?}", roots);
@@ -233,10 +259,266 @@ fn sort_deps<'a, 'i>(
// TODO: can we encapsulate NodeIndex?
while let Some(index) = dfs.next(&depgraph) {
- sorted.push(depgraph.get(index).unwrap());
+ let ident = depgraph.get(index).unwrap();
+
+ match ident {
+ Object::Ident(_, kind, _)
+ | Object::IdentFragment(_, kind, _, _) => match kind {
+ IdentKind::Meta => deps.meta.push(ident),
+ IdentKind::Worksheet => deps.worksheet.push(ident),
+ IdentKind::Param(_, _) => deps.params.push(ident),
+ IdentKind::Type(_) => deps.types.push(ident),
+ IdentKind::Func(_, _) => deps.funcs.push(ident),
+ IdentKind::MapHead | IdentKind::Map | IdentKind::MapTail => {
+ deps.map.push(ident)
+ }
+ IdentKind::RetMapHead
+ | IdentKind::RetMap
+ | IdentKind::RetMapTail => deps.retmap.push(ident),
+ _ => deps.rater.push(ident),
+ },
+ _ => panic!("unexpected node: {:?}", ident),
+ }
+ }
+
+ deps
+}
+
+fn output_xmle<'a, 'i, I: Interner<'i>>(
+ depgraph: &'a LinkerAsg<'i>,
+ interner: &'i I,
+ sorted: SortedDeps<'a, 'i>,
+) -> Result<(), Box<dyn Error>> {
+ use std::io::Cursor;
+
+ let mut writer =
+ Writer::new_with_indent(Cursor::new(Vec::new()), ' ' as u8, 2);
+
+ let root =
+ BytesStart::owned_name(b"package".to_vec()).with_attributes(vec![
+ ("xmlns", "http://www.lovullo.com/rater"),
+ ("xmlns:preproc", "http://www.lovullo.com/rater/preproc"),
+ ("xmlns:l", "http://www.lovullo.com/rater/linker"),
+ ("title", "Title TODO"), // TODO
+ ("program", "true"),
+ ("name", "name/todo"), // TODO
+ ]);
+
+ writer.write_event(Event::Start(root))?;
+
+ // All of the other namespaces output in the existing xmle files are
+ // unneeded.
+ writer.write_event(Event::Start(BytesStart::borrowed_name(b"l:dep")))?;
+
+ let all = sorted
+ .meta
+ .iter()
+ .chain(sorted.map.iter())
+ .chain(sorted.retmap.iter())
+ .chain(sorted.worksheet.iter())
+ .chain(sorted.params.iter())
+ .chain(sorted.types.iter())
+ .chain(sorted.funcs.iter())
+ .chain(sorted.rater.iter());
+
+ for ident in all {
+ // TODO: we're doing this in two places!
+ match ident {
+ Object::Ident(sym, kind, src)
+ | Object::IdentFragment(sym, kind, src, _) => {
+ let name: &str = sym;
+
+ // this'll be formalized more sanely
+ let mut attrs = match kind {
+ IdentKind::Cgen(dim) => {
+ vec![("type", "cgen"), ("dim", dim.as_ref())]
+ }
+ IdentKind::Class(dim) => {
+ vec![("type", "class"), ("dim", dim.as_ref())]
+ }
+ IdentKind::Const(dim, dtype) => vec![
+ ("type", "const"),
+ ("dim", dim.as_ref()),
+ ("dtype", dtype.as_ref()),
+ ],
+ IdentKind::Func(dim, dtype) => vec![
+ ("type", "func"),
+ ("dim", dim.as_ref()),
+ ("dtype", dtype.as_ref()),
+ ],
+ IdentKind::Gen(dim, dtype) => vec![
+ ("type", "gen"),
+ ("dim", dim.as_ref()),
+ ("dtype", dtype.as_ref()),
+ ],
+ IdentKind::Lparam(dim, dtype) => vec![
+ ("type", "lparam"),
+ ("dim", dim.as_ref()),
+ ("dtype", dtype.as_ref()),
+ ],
+ IdentKind::Param(dim, dtype) => vec![
+ ("type", "param"),
+ ("dim", dim.as_ref()),
+ ("dtype", dtype.as_ref()),
+ ],
+ IdentKind::Rate(dtype) => {
+ vec![("type", "rate"), ("dtype", dtype.as_ref())]
+ }
+ IdentKind::Tpl => vec![("type", "tpl")],
+ IdentKind::Type(dtype) => {
+ vec![("type", "type"), ("dtype", dtype.as_ref())]
+ }
+ IdentKind::MapHead => vec![("type", "map:head")],
+ IdentKind::Map => vec![("type", "map")],
+ IdentKind::MapTail => vec![("type", "map:tail")],
+ IdentKind::RetMapHead => vec![("type", "retmap:head")],
+ IdentKind::RetMap => vec![("type", "retmap")],
+ IdentKind::RetMapTail => vec![("type", "retmap:tail")],
+ IdentKind::Meta => vec![("type", "meta")],
+ IdentKind::Worksheet => vec![("type", "worksheet")],
+ };
+
+ attrs.push(("name", name));
+
+ if src.generated {
+ attrs.push(("preproc:generated", "true"));
+ }
+
+ if let Some(parent) = src.parent {
+ attrs.push(("parent", parent));
+ }
+ if let Some(yields) = src.yields {
+ attrs.push(("yields", yields));
+ }
+ if let Some(desc) = &src.desc {
+ attrs.push(("desc", &desc));
+ }
+
+ let sym = BytesStart::owned_name(b"preproc:sym".to_vec())
+ .with_attributes(attrs);
+
+ writer.write_event(Event::Empty(sym))?;
+ }
+ _ => unreachable!("filtered out during sorting"),
+ }
}
- sorted
+ writer.write_event(Event::End(BytesEnd::borrowed(b"l:dep")))?;
+
+ // This was not in the original linker, but we need to be able to convey
+ // this information for `standalones` (which has received some logic
+ // from the old linker for the time being).
+ writer
+ .write_event(Event::Start(BytesStart::borrowed_name(b"l:map-from")))?;
+
+ let mut map_froms = HashSet::<&str>::new();
+
+ for map_ident in &sorted.map {
+ match map_ident {
+ Object::Ident(_, _, src) | Object::IdentFragment(_, _, src, _) => {
+ if let Some(froms) = &src.from {
+ for from in froms {
+ map_froms.insert(from);
+ }
+ }
+ }
+
+ _ => unreachable!("filtered out during sorting"),
+ }
+ }
+
+ for from in map_froms {
+ let name: &str = from;
+
+ writer.write_event(Event::Empty(
+ BytesStart::borrowed_name(b"l:from")
+ .with_attributes(vec![("name", name)]),
+ ))?;
+ }
+
+ writer.write_event(Event::End(BytesEnd::borrowed(b"l:map-from")))?;
+ writer
+ .write_event(Event::Start(BytesStart::borrowed_name(b"l:map-exec")))?;
+
+ if sorted.map.len() > 0 {
+ write_fragments(
+ &mut writer,
+ &vec![depgraph
+ .get(depgraph.lookup(interner.intern(":map:___head")).unwrap())
+ .unwrap()],
+ )?;
+ write_fragments(&mut writer, &sorted.map)?;
+ write_fragments(
+ &mut writer,
+ &vec![depgraph
+ .get(depgraph.lookup(interner.intern(":map:___tail")).unwrap())
+ .unwrap()],
+ )?;
+ }
+
+ writer.write_event(Event::End(BytesEnd::borrowed(b"l:map-exec")))?;
+ writer.write_event(Event::Start(BytesStart::borrowed_name(
+ b"l:retmap-exec",
+ )))?;
+
+ if sorted.retmap.len() > 0 {
+ write_fragments(
+ &mut writer,
+ &vec![depgraph
+ .get(
+ depgraph
+ .lookup(interner.intern(":retmap:___head"))
+ .unwrap(),
+ )
+ .unwrap()],
+ )?;
+ write_fragments(&mut writer, &sorted.retmap)?;
+ write_fragments(
+ &mut writer,
+ &vec![depgraph
+ .get(
+ depgraph
+ .lookup(interner.intern(":retmap:___tail"))
+ .unwrap(),
+ )
+ .unwrap()],
+ )?;
+ }
+
+ writer.write_event(Event::End(BytesEnd::borrowed(b"l:retmap-exec")))?;
+ writer.write_event(Event::Start(BytesStart::borrowed_name(b"l:exec")))?;
+
+ write_fragments(&mut writer, &sorted.meta)?;
+ write_fragments(&mut writer, &sorted.worksheet)?;
+ write_fragments(&mut writer, &sorted.params)?;
+ write_fragments(&mut writer, &sorted.types)?;
+ write_fragments(&mut writer, &sorted.funcs)?;
+ write_fragments(&mut writer, &sorted.rater)?;
+
+ writer.write_event(Event::End(BytesEnd::borrowed(b"l:exec")))?;
+ writer.write_event(Event::End(BytesEnd::borrowed(b"package")))?;
+
+ print!("{}", String::from_utf8(writer.into_inner().into_inner())?);
+
+ Ok(())
+}
+
+fn write_fragments<W: Write>(
+ writer: &mut Writer<W>,
+ idents: &ObjectVec,
+) -> Result<(), Box<dyn Error>> {
+ for ident in idents {
+ match ident {
+ Object::IdentFragment(_, _, _, frag) => {
+ writer.write_event(Event::Text(BytesText::from_plain_str(
+ frag,
+ )))?;
+ }
+ _ => (),
+ }
+ }
+
+ Ok(())
}
#[cfg(test)]