Commit 2e19d712 authored by Jeff Smits's avatar Jeff Smits

Commit with too many things:

Changed aterm version to one that doesn't have the two parsing bugs.
Added more primitives. Fixed bugs in StackTracer and added it into the
interpreter so it actually traces. Handling annotated strategy
definitions is a stupid way. Dropping external strategy definitions.
Fixed bug in term matching.
parent 5f49b0a2
......@@ -2,7 +2,7 @@
name = "strs"
version = "0.1.0"
dependencies = [
"aterm 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"aterm 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
"phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -27,7 +27,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "aterm"
version = "0.11.0"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -289,7 +289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum aterm 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4be6658304081c33ce6f15bfb1a6c1cf0589ab87bc95624a9f5ad5a2bda618c6"
"checksum aterm 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f35a669ac49bd2e25d3739dfaf917c74341c3d24ceb6c8e0541c3babf3d74f82"
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
"checksum clap 2.23.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f57e9b63057a545ad2ecd773ea61e49422ed1b1d63d74d5da5ecaee55b3396cd"
......
......@@ -13,7 +13,7 @@ version = "0.1.0"
phf_codegen = "0.7.21"
[dependencies]
aterm = "0.11.0"
aterm = "0.12.0"
phf = "0.7.21"
rand = "0.3.15"
ref_eq = "1.0.0"
......
......@@ -7,6 +7,7 @@ use std::cell::RefCell;
use primitives::{Primitives, eval_prim_ref};
use primitives::ssl::SslState;
// TODO: do AOS to SOA transform for scopes, (to the level of individual variables? Maybe ).
/// This context is internally mutable in RefCell fields. This is just for convenience as we don't
/// want to pass around the mutable fields separately. But the internal mutability is not a hidden
/// thing without effect, so the name of the context includes `Mut`.
......@@ -81,13 +82,16 @@ impl<'a> MutContext<'a> {
}
}
Err(Error::UndefinedVariable(_)) => {
let latest_scope = self.scopes.borrow().len() - 1;
if let Some(_) = self.scopes.borrow_mut()[latest_scope]
if let Some(Some(t)) = self.scopes
.borrow_mut()
.last_mut()
.expect("Variable scope was unexpectedly empty")
.term
.insert(term_name.to_owned(), Some(current.clone())) {
unreachable!(format!("No scope had {}, but we just \
replaced something when we added it?!",
term_name))
unreachable!(format!("No scope had {}, but we just replaced {} when \
we added it?!",
term_name,
t))
} else {
Ok(())
}
......@@ -100,29 +104,30 @@ impl<'a> MutContext<'a> {
#[derive(Debug, Default, Clone)]
pub struct StackTracer {
stack: Vec<String>,
failure_depth: usize,
current_depth: usize,
}
impl StackTracer {
pub fn push(&mut self, str: String) {
self.stack.truncate(self.current_depth);
self.stack.push(str);
self.failure_depth = self.stack.len() - 1;
self.current_depth += 1;
}
pub fn pop_on_failure(&mut self) -> Option<String> {
self.stack.pop()
pub fn pop_on_failure(&mut self) {
self.current_depth -= 1;
}
pub fn pop_on_success(&mut self) -> Option<String> {
self.failure_depth = self.stack.len() - 2;
self.stack.pop()
pub fn pop_on_success(&mut self) {
let _ = self.stack.pop();
self.current_depth = self.stack.len();
}
}
impl fmt::Display for StackTracer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (n, name) in self.stack.iter().enumerate() {
if n == self.failure_depth {
if n == self.current_depth {
writeln!(f, "{} <==", name)?;
} else {
writeln!(f, "{}", name)?;
......
......@@ -452,6 +452,18 @@ impl<'a, A> TryFrom<&'a A> for StrategyDef
}
}
impl From<StrategyDef> for Def {
fn from(sdef: StrategyDef) -> Def {
use self::StrategyDef as I;
use self::Def as O;
match sdef {
I::SDefT(name, sargs, targs, body) => O::SDefT(name, sargs, targs, body),
I::ExtSDefInl(name, sargs, targs, body) => O::ExtSDefInl(name, sargs, targs, body),
I::ExtSDef(name, sargs, targs) => O::ExtSDef(name, sargs, targs),
}
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum Anno {
Extend,
......
......@@ -72,7 +72,11 @@ pub fn interpret<'a>(factory: &'a ATermFactory,
let context = MutContext::new(factory, libs, libraries.prims);
context.scopes.borrow_mut().push(preprocess(program)?);
let main = context.get_strategy(strategy)?;
main.eval(&context, Vec::new(), Vec::new(), input)
let result = main.eval(&context, Vec::new(), Vec::new(), input);
if result.is_err() {
println!("Debug. Stacktrace: \n{}", *context.stack_tracer.borrow())
}
result
}
pub trait Eval<'a> {
......@@ -102,7 +106,13 @@ impl<'a> Eval<'a> for preprocess::Strategy {
result
}
CallT(ref name, ref sargs, ref targs) => {
let sdeft = context.get_strategy(name)?;
context.stack_tracer.borrow_mut().push(name.clone());
let sdeft = context
.get_strategy(name)
.map_err(|e| {
context.stack_tracer.borrow_mut().pop_on_failure();
e
})?;
let sargs = sargs
.into_iter()
.cloned()
......@@ -111,8 +121,18 @@ impl<'a> Eval<'a> for preprocess::Strategy {
let targs = targs
.into_iter()
.map(|build_term| eval_build(context, build_term))
.collect::<Result<_>>()?;
sdeft.eval(context, sargs, targs, current)
.collect::<Result<_>>()
.map_err(|e| {
context.stack_tracer.borrow_mut().pop_on_failure();
e
})?;
let result = sdeft.eval(context, sargs, targs, current);
if result.is_ok() {
context.stack_tracer.borrow_mut().pop_on_success();
} else {
context.stack_tracer.borrow_mut().pop_on_failure();
}
result
}
CallDynamic(ref term, ref sargs, ref targs) => unimplemented!(),
Fail => Err(Error::StrategyFailed),
......@@ -140,6 +160,7 @@ impl<'a> Eval<'a> for preprocess::Strategy {
}
}
PrimT(ref name, ref sargs, ref targs) => {
context.stack_tracer.borrow_mut().push(name.clone());
let sargs = sargs
.into_iter()
.cloned()
......@@ -148,8 +169,18 @@ impl<'a> Eval<'a> for preprocess::Strategy {
let targs = targs
.into_iter()
.map(|build_term| eval_build(context, build_term))
.collect::<Result<_>>()?;
context.call_primitive(name, sargs, targs, current)
.collect::<Result<_>>()
.map_err(|e| {
context.stack_tracer.borrow_mut().pop_on_failure();
e
})?;
let result = context.call_primitive(name, sargs, targs, current);
if result.is_ok() {
context.stack_tracer.borrow_mut().pop_on_success();
} else {
context.stack_tracer.borrow_mut().pop_on_failure();
}
result
}
Some(ref strat) => eval_some(strat, context, current),
One(ref strat) => eval_one(strat, context, current),
......@@ -307,9 +338,9 @@ fn eval_build_with_annos<'a, I>(context: &MutContext<'a>,
}
Ok(cons)
}
// NOTE: `str '!((1{2}){3})'` gives `1{2}`, so the innermost `annos` list in a build is
// used!
Anno(ref term, ref annos) => {
// NOTE: `str '!((1{2}){3})'` gives `1{2}`, so the innermost annos list in a build is
// used!
let annos = &(**annos).clone().into();
let term = &(**term).clone();
if let Some(annos) = eval_build_list(context, annos)? {
......
......@@ -46,10 +46,9 @@ struct Opt {
`strategoxt-path` and go one directory up from the output. If that doesn't work, \
well.. I guess we'll just take the current directory. ")]
str_path: Option<String>,
#[structopt(short = "l", long = "libs", help = "Library files (CTree). Use the old \
libstratego-* names to load those libraries \
from --strpath along with the necessary \
primitives")]
#[structopt(short = "l", long = "libs",
help = "Library files (CTree). Use the old libstratego-* names to load those libraries \
from --strpath along with the necessary primitives")]
libraries: Vec<String>,
#[structopt(short = "p", long = "prims",
help = "Primitives to be loaded (usually done implicitly with standard \
......@@ -122,9 +121,11 @@ fn find_str_path(str_path: Option<String>) -> PathBuf {
str_path
.or_else(||
env::var_os("STRDIR").map(|s|
s.into_string().expect("STRDIR found in environment, but was not valid unicode. \
Bailing out. ")))
env::var_os("STRDIR")
.map(|s|
s.into_string().expect("STRDIR found in environment, but was not valid \
unicode. Bailing out. ")))
.and_then(|s| if s.is_empty() { None } else { Some(s) })
.or_else(||
Command::new("strategoxt-path")
.output()
......
......@@ -6,6 +6,13 @@ use interpreter::Eval;
use context::{MutContext, Scope};
use aterm::BrokenF32;
macro_rules! eprintln {
($($tt:tt)*) => {{
use std::io::{Write, stderr};
writeln!(&mut stderr(), $($tt)*).unwrap();
}}
}
pub fn preprocess(program: ctree::Module) -> Result<Scope<ATermRef>> {
let decls = match program {
ctree::Module::Module(_, decls) => decls,
......@@ -18,6 +25,8 @@ pub fn preprocess(program: ctree::Module) -> Result<Scope<ATermRef>> {
_ => Vec::new().into_iter(),
})
.map(TryInto::try_into)
// TODO: find nicer way to filter out external strategy definitions
.filter(Result::is_ok)
.collect::<Result<Vec<SDefT>>>()?;
Ok(Scope::from_sdefts(defs))
}
......@@ -90,12 +99,13 @@ impl TryFrom<ctree::Def> for SDefT {
}
})
}
ctree::Def::ExtSDef(_, _, _) => Err(Error::CTreeParse("Unknown behaviour: ExtSDef")),
ctree::Def::ExtSDefInl(_, _, _, _) => {
Err(Error::CTreeParse("Unknown behaviour: \
ExtSDefInl"))
ctree::Def::ExtSDef(name, sargs, targs) => Err(Error::CTreeParse("Unknown behaviour: ExtSDef")),
ctree::Def::ExtSDefInl(_, _, _, _) => Err(Error::CTreeParse("Unknown behaviour: ExtSDefInl")),
ctree::Def::AnnoDef(_, sdeft) => {
eprintln!("WARNING: ignoring annotations on strategy definitions");
// TODO: support single annotations like in java-backend/trans/s2j.str
Self::try_from(sdeft.into())
}
ctree::Def::AnnoDef(_, _) => Err(Error::CTreeParse("Unknown behaviour: AnnoDef")),
}
}
}
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment