]>
Witch of Git - ivy/blob - src/trans.rs
1 use crate::ast
::{self, Ast
};
3 collections
::{HashMap
, HashSet
},
7 #[derive(Hash, PartialEq, Eq, Clone, Copy)]
8 pub struct FnName(u32);
10 #[derive(Hash, PartialEq, Eq, Clone, Copy)]
11 pub struct SsaName(u32);
13 #[derive(Hash, PartialEq, Eq, Clone, Copy)]
21 #[derive(PartialEq, Eq, Clone)]
24 StoreGlobal(u32, SsaName
),
34 #[derive(Debug, PartialEq, Eq, Clone)]
36 globals
: HashSet
<u32>,
37 functions
: HashMap
<FnName
, Func
>,
43 fn fresh(&mut self) -> u32 {
50 #[derive(PartialEq, Eq, Clone)]
55 block
: HashMap
<SsaName
, Code
>,
61 fn fresh_ssa(&mut self) -> SsaName
{
62 let fresh
= SsaName(self.fresh
);
69 mapping
: HashMap
<ast
::Name
, Var
>,
73 fn resolve(&self, name
: &ast
::Name
) -> Option
<Var
> {
74 self.mapping
.get(&name
).copied().or_else(|| match name
{
75 ast
::Name
::Global(x
) => Some(Var
::Global(*x
)),
81 pub fn translate(ast
: &Ast
) -> Result
<Program
, String
> {
82 let mut prog
= Program
{
83 globals
: HashSet
::new(),
84 functions
: HashMap
::new(),
89 mapping
: HashMap
::new(),
91 let func
= make_func(0, &mut prog
, &mut env
, ast
)?
;
93 prog
.funct
ions
.insert
(func
.name
, func
);
97 fn make_func(params
: u16, prog
: &mut Program
, env
: &mut Env
, ast
: &Ast
) -> Result
<Func
, String
> {
99 name
: FnName(prog
.fresh
()),
102 block
: HashMap
::new(),
106 func
.result
= trans_expr(prog
, env
, &mut func
, ast
)?
;
115 ) -> Result
<SsaName
, String
> {
117 Ast
::Let(binds
, body
) => {
118 for (name
, init
) in binds
{
119 let ssa
= trans_expr(prog
, env
, func
, init
)?
;
120 if let ast
::Name
::Global(g
) = name
{
121 let ssa2
= func
.fresh
_ssa
();
122 prog
.globals
.insert
(*g
);
123 func
.block
.insert
(ssa2
, Code
::StoreGlobal(*g
, ssa
));
124 func
.order
.push(ssa2
);
126 // Inserting this unconditionally means that lookups within the
127 // local function will see the SSA name, and potentially avoid
128 // having to do a lookup on a global.
129 env
.mapping
.insert
(*name
, Var
::Ssa(ssa
));
131 trans_expr(prog
, env
, func
, body
)
138 let mut new_env
= Env
{
139 mapping
: HashMap
::with_capacity(binds
.len() + upvars
.len()),
141 for (i
, &name
) in binds
.iter
().enumerate() {
142 new_env
.mapping
.insert
(name
, Var
::Param(i
as u16));
144 for (i
, &name
) in upvars
.iter
().enumerate() {
145 new_env
.mapping
.insert
(name
, Var
::Upvar(i
as u16));
147 let new_func
= make_func(binds
.len() as u16, prog
, &mut new_env
, body
)?
;
148 let ssa
= func
.fresh
_ssa
();
152 let ssa
= func
.fresh
_ssa
();
153 let load
= Code
::Load(
155 .ok_or_else(|| format
!("Unable to resolve variable {:?}", var
))?
,
157 func
.block
.insert
(ssa
, load
);
158 func
.order
.push(ssa
);
161 .collect
::<Result
<_
, String
>>()?
;
167 params
: binds
.len() as u16,
170 func
.order
.push(ssa
);
171 prog
.funct
ions
.insert
(new_func
.name
, new_func
);
177 .map(|term
| trans_expr(prog
, env
, func
, term
))
178 .collect
::<Result
<_
, _
>>()?
;
179 let ssa
= func
.fresh
_ssa
();
180 func
.block
.insert
(ssa
, Code
::App(terms
));
181 func
.order
.push(ssa
);
185 match env
.resolve(name
) {
186 // Forwarding SSA variables skips unnecessary loads
187 Some(Var
::Ssa(ssa
)) => Ok(ssa
),
189 let ssa
= func
.fresh
_ssa
();
190 func
.block
.insert
(ssa
, Code
::Load(var
));
191 // Inserting the result of the lookup into the environment deduplicates loads.
192 env
.mapping
.insert
(*name
, Var
::Ssa(ssa
));
193 func
.order
.push(ssa
);
196 None
=> Err(format
!("Unable to resolve variable {:?}", name
)),
200 let ssa
= func
.fresh
_ssa
();
201 func
.block
.insert
(ssa
, Code
::Num(*n
));
202 func
.order
.push(ssa
);
208 impl fmt
::Debug
for FnName
{
209 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
210 write
!(fmt
, "@fn{}", self.0)
214 impl fmt
::Debug
for SsaName
{
215 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
216 write
!(fmt
, "%{}", self.0)
220 impl fmt
::Debug
for Var
{
221 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
223 Var
::Global(x
) => write
!(fmt
, "@{}", x
),
224 Var
::Param(x
) => write
!(fmt
, "p{}", x
),
225 Var
::Upvar(x
) => write
!(fmt
, "c{}", x
),
226 Var
::Ssa(x
) => write
!(fmt
, "{:?}", x
),
231 impl fmt
::Debug
for Code
{
232 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
234 Code
::Load(var
) => write
!(fmt
, "load {:?}", var
),
235 Code
::StoreGlobal(g
, ssa
) => write
!(fmt
, "store [{:?}] = {:?}", Var
::Global(*g
), ssa
),
241 write
!(fmt
, "lam {:?} ({}) [", name
, params
)?
;
243 write
!(fmt
, "{:?} ", up
)?
;
248 write
!(fmt
, "app (")?
;
250 write
!(fmt
, "{:?} ", arg
)?
;
254 Code
::Num(n
) => write
!(fmt
, "{}", n
),
259 impl fmt
::Debug
for Func
{
260 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
261 write
!(fmt
, "fn {:?} ({}) ", self.name
, self.params
)?
;
263 .entries(self.order
.iter
().map(|x
| (x
, &self.block
[x
])))
264 .entry(&"ret", &self.result
)