2019-11-27 09:18:17 -05:00
|
|
|
// Proof-of-concept TAME linker
|
|
|
|
//
|
2020-03-06 11:05:18 -05:00
|
|
|
// Copyright (C) 2014-2020 Ryan Specialty Group, LLC.
|
|
|
|
//
|
|
|
|
// This file is part of TAME.
|
2019-11-27 09:18:17 -05:00
|
|
|
//
|
|
|
|
// 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/>.
|
|
|
|
|
|
|
|
//! **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.
|
|
|
|
|
2020-04-06 22:07:39 -04:00
|
|
|
use crate::fs::{
|
|
|
|
CanonicalFile, Filesystem, VisitOnceFile, VisitOnceFilesystem,
|
|
|
|
};
|
2020-01-12 22:59:16 -05:00
|
|
|
use crate::global;
|
2020-03-07 10:49:41 -05:00
|
|
|
use crate::ir::asg::{
|
2020-04-07 10:43:54 -04:00
|
|
|
Asg, AsgError, DefaultAsg, IdentObject, IdentObjectData, Sections,
|
|
|
|
SortableAsg,
|
2020-03-07 10:49:41 -05:00
|
|
|
};
|
2020-03-11 10:23:34 -04:00
|
|
|
use crate::obj::xmle::writer::XmleWriter;
|
2020-04-06 23:28:07 -04:00
|
|
|
use crate::obj::xmlo::reader::{XmloError, XmloReader};
|
2020-04-07 10:43:54 -04:00
|
|
|
use crate::obj::xmlo::{AsgBuilder, AsgBuilderState};
|
2020-01-14 16:26:36 -05:00
|
|
|
use crate::sym::{DefaultInterner, Interner, Symbol};
|
2020-04-06 23:28:07 -04:00
|
|
|
use fxhash::{FxBuildHasher, FxHashMap};
|
2019-11-27 09:18:17 -05:00
|
|
|
use std::error::Error;
|
|
|
|
use std::fs;
|
2020-02-13 15:43:25 -05:00
|
|
|
use std::io::BufReader;
|
2020-04-06 22:07:39 -04:00
|
|
|
use std::path::PathBuf;
|
2019-11-27 09:18:17 -05:00
|
|
|
|
2020-03-16 11:49:41 -04:00
|
|
|
type LinkerAsg<'i> = DefaultAsg<'i, IdentObject<'i>, global::ProgIdentSize>;
|
2019-11-27 09:18:17 -05:00
|
|
|
|
2020-04-07 10:43:54 -04:00
|
|
|
type LinkerAsgBuilderState<'i> =
|
|
|
|
AsgBuilderState<'i, FxBuildHasher, global::ProgIdentSize>;
|
2020-03-06 12:44:22 -05:00
|
|
|
|
2020-03-04 15:31:20 -05:00
|
|
|
pub fn main(package_path: &str, output: &str) -> Result<(), Box<dyn Error>> {
|
2020-04-06 16:13:32 -04:00
|
|
|
let mut fs = VisitOnceFilesystem::new();
|
2020-01-15 10:27:35 -05:00
|
|
|
let mut fragments: FxHashMap<&str, String> = Default::default();
|
2020-01-12 22:59:16 -05:00
|
|
|
let mut depgraph = LinkerAsg::with_capacity(65536, 65536);
|
2020-01-09 10:56:24 -05:00
|
|
|
let interner = DefaultInterner::new();
|
2019-11-27 09:18:17 -05:00
|
|
|
|
2020-03-06 11:29:04 -05:00
|
|
|
let abs_path = fs::canonicalize(package_path)?;
|
2019-11-27 09:18:17 -05:00
|
|
|
|
2020-04-07 10:43:54 -04:00
|
|
|
let state = load_xmlo(
|
2019-11-27 09:18:17 -05:00
|
|
|
&abs_path.to_str().unwrap().to_string(),
|
2020-04-06 16:13:32 -04:00
|
|
|
&mut fs,
|
2019-11-27 09:18:17 -05:00
|
|
|
&mut fragments,
|
2019-12-01 01:17:37 -05:00
|
|
|
&mut depgraph,
|
2020-01-09 10:56:24 -05:00
|
|
|
&interner,
|
2020-04-07 10:43:54 -04:00
|
|
|
Default::default(),
|
|
|
|
)?;
|
|
|
|
|
|
|
|
let AsgBuilderState {
|
|
|
|
mut roots,
|
|
|
|
name,
|
|
|
|
relroot,
|
|
|
|
found: _,
|
|
|
|
} = state;
|
2019-12-01 01:17:37 -05:00
|
|
|
|
2020-01-12 22:59:16 -05:00
|
|
|
roots.extend(
|
|
|
|
vec!["___yield", "___worksheet"]
|
|
|
|
.iter()
|
|
|
|
.map(|name| interner.intern(name))
|
|
|
|
.filter_map(|sym| depgraph.lookup(sym)),
|
|
|
|
);
|
|
|
|
|
2020-03-25 10:20:25 -04:00
|
|
|
let mut sorted = match depgraph.sort(&roots) {
|
|
|
|
Ok(sections) => sections,
|
|
|
|
Err(AsgError::Cycles(cycles)) => {
|
|
|
|
let msg: Vec<String> = cycles
|
|
|
|
.into_iter()
|
|
|
|
.map(|cycle| {
|
|
|
|
let mut path: Vec<String> = cycle
|
|
|
|
.into_iter()
|
|
|
|
.map(|obj| {
|
|
|
|
format!(
|
|
|
|
"{}",
|
|
|
|
depgraph.get(obj).unwrap().name().unwrap()
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
path.reverse();
|
|
|
|
path.push(path[0].clone());
|
|
|
|
format!("cycle: {}", path.join(" -> "))
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
return Err(msg.join("\n").into());
|
|
|
|
}
|
|
|
|
Err(e) => return Err(e.into()),
|
|
|
|
};
|
2019-11-27 09:18:17 -05:00
|
|
|
|
2020-01-13 16:41:06 -05:00
|
|
|
//println!("Sorted ({}): {:?}", sorted.len(), sorted);
|
|
|
|
|
2020-01-14 16:26:36 -05:00
|
|
|
output_xmle(
|
|
|
|
&depgraph,
|
|
|
|
&interner,
|
2020-02-13 15:43:25 -05:00
|
|
|
&mut sorted,
|
2020-01-14 16:26:36 -05:00
|
|
|
name.expect("missing root package name"),
|
|
|
|
relroot.expect("missing root package relroot"),
|
2020-03-04 15:31:20 -05:00
|
|
|
output,
|
2020-01-14 16:26:36 -05:00
|
|
|
)?;
|
2019-11-27 09:18:17 -05:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-01-09 10:56:24 -05:00
|
|
|
fn load_xmlo<'a, 'i, I: Interner<'i>>(
|
2019-11-27 09:18:17 -05:00
|
|
|
path_str: &'a str,
|
2020-04-06 16:13:32 -04:00
|
|
|
fs: &mut VisitOnceFilesystem<FxBuildHasher>,
|
2020-01-15 10:27:35 -05:00
|
|
|
fragments: &mut FxHashMap<&'i str, String>,
|
2020-01-12 22:59:16 -05:00
|
|
|
depgraph: &mut LinkerAsg<'i>,
|
2020-01-09 10:56:24 -05:00
|
|
|
interner: &'i I,
|
2020-04-07 10:43:54 -04:00
|
|
|
state: LinkerAsgBuilderState<'i>,
|
|
|
|
) -> Result<LinkerAsgBuilderState<'i>, Box<dyn Error>> {
|
2020-04-06 22:38:44 -04:00
|
|
|
let cfile: CanonicalFile<BufReader<fs::File>> = match fs.open(path_str)? {
|
2020-04-06 16:13:32 -04:00
|
|
|
VisitOnceFile::FirstVisit(file) => file,
|
2020-04-07 10:43:54 -04:00
|
|
|
VisitOnceFile::Visited => return Ok(state),
|
2020-04-06 16:13:32 -04:00
|
|
|
};
|
|
|
|
|
2020-04-06 22:07:39 -04:00
|
|
|
let (path, file) = cfile.into();
|
|
|
|
|
2020-04-06 23:28:07 -04:00
|
|
|
let xmlo: XmloReader<'_, _, _> = (file, interner).into();
|
2020-01-13 15:15:38 -05:00
|
|
|
|
2020-04-07 10:43:54 -04:00
|
|
|
let mut state = xmlo.build(depgraph, state)?;
|
2020-01-12 22:59:16 -05:00
|
|
|
|
2020-04-06 22:07:39 -04:00
|
|
|
let mut dir: PathBuf = path.clone();
|
2019-11-27 09:18:17 -05:00
|
|
|
dir.pop();
|
|
|
|
|
2020-04-07 10:43:54 -04:00
|
|
|
let found = state.found.take().unwrap_or_default();
|
|
|
|
|
2019-11-27 09:18:17 -05:00
|
|
|
for relpath in found.iter() {
|
|
|
|
let mut path_buf = dir.clone();
|
|
|
|
path_buf.push(relpath);
|
|
|
|
path_buf.set_extension("xmlo");
|
|
|
|
|
2020-01-14 16:26:36 -05:00
|
|
|
// println!("Trying {:?}", path_buf);
|
2020-03-06 12:32:42 -05:00
|
|
|
let path_abs = path_buf.canonicalize()?;
|
2019-11-27 09:18:17 -05:00
|
|
|
let path = path_abs.to_str().unwrap();
|
|
|
|
|
2020-04-07 10:43:54 -04:00
|
|
|
state = load_xmlo(path, fs, fragments, depgraph, interner, state)?;
|
2019-11-27 09:18:17 -05:00
|
|
|
}
|
|
|
|
|
2020-04-07 10:43:54 -04:00
|
|
|
Ok(state)
|
2019-11-27 09:18:17 -05:00
|
|
|
}
|
|
|
|
|
2020-03-13 01:19:43 -04:00
|
|
|
fn get_ident<'a, 'i>(
|
2020-02-13 15:43:25 -05:00
|
|
|
depgraph: &'a LinkerAsg<'i>,
|
2020-03-13 01:19:43 -04:00
|
|
|
name: &'i Symbol<'i>,
|
2020-03-16 11:49:41 -04:00
|
|
|
) -> Result<&'a IdentObject<'i>, XmloError> {
|
2020-03-13 01:19:43 -04:00
|
|
|
depgraph
|
|
|
|
.lookup(name)
|
|
|
|
.and_then(|id| depgraph.get(id))
|
|
|
|
.ok_or(XmloError::MissingFragment(String::from(name as &str)))
|
2020-02-13 15:43:25 -05:00
|
|
|
}
|
|
|
|
|
2020-01-13 16:41:06 -05:00
|
|
|
fn output_xmle<'a, 'i, I: Interner<'i>>(
|
|
|
|
depgraph: &'a LinkerAsg<'i>,
|
|
|
|
interner: &'i I,
|
2020-03-16 11:49:41 -04:00
|
|
|
sorted: &mut Sections<'a, IdentObject<'i>>,
|
2020-01-14 16:26:36 -05:00
|
|
|
name: &'i Symbol<'i>,
|
|
|
|
relroot: String,
|
2020-03-04 15:31:20 -05:00
|
|
|
output: &str,
|
2020-01-13 16:41:06 -05:00
|
|
|
) -> Result<(), Box<dyn Error>> {
|
2020-02-13 15:43:25 -05:00
|
|
|
if !sorted.map.is_empty() {
|
2020-03-13 01:19:43 -04:00
|
|
|
sorted
|
|
|
|
.map
|
|
|
|
.push_head(get_ident(depgraph, interner.intern(":map:___head"))?);
|
|
|
|
sorted
|
|
|
|
.map
|
|
|
|
.push_tail(get_ident(depgraph, interner.intern(":map:___tail"))?);
|
2020-01-13 16:41:06 -05:00
|
|
|
}
|
|
|
|
|
2020-02-13 15:43:25 -05:00
|
|
|
if !sorted.retmap.is_empty() {
|
2020-03-13 01:19:43 -04:00
|
|
|
sorted.retmap.push_head(get_ident(
|
2020-02-13 15:43:25 -05:00
|
|
|
depgraph,
|
2020-03-13 01:19:43 -04:00
|
|
|
interner.intern(":retmap:___head"),
|
2020-03-07 11:18:56 -05:00
|
|
|
)?);
|
2020-03-13 01:19:43 -04:00
|
|
|
sorted.retmap.push_tail(get_ident(
|
2020-02-13 15:43:25 -05:00
|
|
|
depgraph,
|
2020-03-13 01:19:43 -04:00
|
|
|
interner.intern(":retmap:___tail"),
|
2020-03-07 11:18:56 -05:00
|
|
|
)?);
|
2020-01-13 16:41:06 -05:00
|
|
|
}
|
|
|
|
|
2020-03-04 15:31:20 -05:00
|
|
|
let file = fs::File::create(output)?;
|
|
|
|
let mut xmle_writer = XmleWriter::new(file);
|
2020-03-07 11:18:56 -05:00
|
|
|
xmle_writer.write(&sorted, name, &relroot)?;
|
2020-01-13 16:41:06 -05:00
|
|
|
|
|
|
|
Ok(())
|
2019-11-27 09:18:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2019-12-06 15:03:29 -05:00
|
|
|
mod test {
|
2019-11-27 09:18:17 -05:00
|
|
|
#[test]
|
|
|
|
fn placeholder() {}
|
|
|
|
}
|