1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#![recursion_limit = "128"]
#[macro_use]
extern crate binjs_io;
#[macro_use]
extern crate binjs_shared;
#[macro_use]
extern crate assert_matches;
extern crate clap;
extern crate itertools;
#[macro_use]
extern crate serde;
#[macro_use]
extern crate log;
pub mod ast;
pub mod io;
#[derive(Debug)]
pub enum EnrichError {
ScopeError(scopes::ScopeError),
}
impl From<scopes::ScopeError> for EnrichError {
fn from(err: scopes::ScopeError) -> Self {
EnrichError::ScopeError(err)
}
}
pub struct Enrich {
pub lazy_threshold: u32,
pub pure_data_threshold: Option<usize>,
}
const_with_str! {
const DEFAULT_LAZY_THRESHOLD: u32 = 0;
const DEFAULT_PURE_DATA_THRESHOLD: Option<usize> = None;
mod defaults_as_strings;
}
impl Default for Enrich {
fn default() -> Self {
Enrich {
lazy_threshold: DEFAULT_LAZY_THRESHOLD,
pure_data_threshold: DEFAULT_PURE_DATA_THRESHOLD,
}
}
}
impl Enrich {
pub fn args<'a, 'b>(&self) -> Vec<clap::Arg<'a, 'b>> {
use clap::*;
vec![
Arg::with_name("inject-lazy")
.long("inject-lazy")
.alias("lazify")
.takes_value(true)
.value_name("LEVEL")
.help("Rewrite the AST for all functions strictly below level LEVEL. Do nothing if LEVEL = 0")
.default_value(defaults_as_strings::DEFAULT_LAZY_THRESHOLD),
Arg::with_name("inject-json-specialization")
.long("inject-json-specialization")
.value_name("SIZE")
.takes_value(true)
.help("Rewrite the AST to introduce scoped dictionary changes around pure data fragments with size >= SIZE")
.default_value(defaults_as_strings::DEFAULT_PURE_DATA_THRESHOLD),
]
}
pub fn from_matches(matches: &clap::ArgMatches) -> Self {
use std::str::FromStr;
let lazy_threshold = u32::from_str(matches.value_of("inject-lazy").unwrap())
.unwrap_or_else(|e| panic!("Error parsing inject-lazy: {:?}", e));
let pure_data_threshold = match matches.value_of("inject-json-specialization").unwrap() {
"none" | "None" => None,
other => Some(
usize::from_str(other)
.unwrap_or_else(|e| panic!("Error parsing inject-lazy: {:?}", e)),
),
};
Enrich {
lazy_threshold,
pure_data_threshold,
}
}
pub fn enrich(&self, script: &mut ast::Script) -> Result<(), EnrichError> {
if self.lazy_threshold > 0 {
let mut visitor = lazy::LazifierVisitor::new(self.lazy_threshold);
visitor.annotate_script(script)?;
}
{
let mut visitor = scopes::AnnotationVisitor::new();
visitor.annotate_script(script)?;
}
if let Some(threshold) = self.pure_data_threshold {
sublanguages::InjectVisitor::rewrite_script(threshold, script)?;
}
Ok(())
}
}
pub struct Cleanup {
pub scoped_dictionaries: bool,
}
impl Default for Cleanup {
fn default() -> Self {
Cleanup {
scoped_dictionaries: false,
}
}
}
impl Cleanup {
pub fn cleanup(&self, script: &mut ast::Script) {
if self.scoped_dictionaries {
sublanguages::CleanupVisitor::rewrite_script(script);
}
}
}
mod scopes;
mod lazy;
mod sublanguages;