]>
Witch of Git - ivy/blob - src/trans.rs
1 use crate::ast
::{self, Ast
};
3 collections
::{HashMap
, HashSet
},
9 #[derive(Hash, PartialEq, Eq, Clone, Copy)]
10 pub struct FnName(u32);
12 #[derive(Hash, PartialEq, Eq, Clone, Copy)]
13 pub struct SsaName(u32);
15 #[derive(Hash, PartialEq, Eq, Clone, Copy)]
23 #[derive(PartialEq, Eq, Clone)]
26 StoreGlobal(u32, SsaName
),
36 #[derive(Debug, PartialEq, Eq, Clone)]
38 pub globals
: HashSet
<u32>,
39 functions
: HashMap
<FnName
, Func
>,
45 fn fresh(&mut self) -> u32 {
52 #[derive(PartialEq, Eq, Clone)]
57 block
: HashMap
<SsaName
, Code
>,
63 fn fresh_ssa(&mut self) -> SsaName
{
64 let fresh
= SsaName(self.fresh
);
71 mapping
: HashMap
<ast
::Name
, Var
>,
75 fn resolve(&self, name
: &ast
::Name
) -> Option
<Var
> {
76 self.mapping
.get(&name
).copied().or_else(|| match name
{
77 ast
::Name
::Global(x
) => Some(Var
::Global(*x
)),
83 pub fn translate(ast
: &Ast
) -> Result
<Program
, String
> {
84 let mut prog
= Program
{
85 globals
: HashSet
::new(),
86 functions
: HashMap
::new(),
91 mapping
: HashMap
::new(),
93 let func
= make_func(0, &mut prog
, &mut env
, ast
)?
;
95 prog
.funct
ions
.insert
(func
.name
, func
);
99 fn make_func(params
: u16, prog
: &mut Program
, env
: &mut Env
, ast
: &Ast
) -> Result
<Func
, String
> {
100 let mut func
= Func
{
101 name
: FnName(prog
.fresh
()),
104 block
: HashMap
::new(),
108 func
.result
= trans_expr(prog
, env
, &mut func
, ast
)?
;
117 ) -> Result
<SsaName
, String
> {
119 Ast
::Let(binds
, body
) => {
120 for (name
, init
) in binds
{
121 let ssa
= trans_expr(prog
, env
, func
, init
)?
;
122 if let ast
::Name
::Global(g
) = name
{
123 let ssa2
= func
.fresh
_ssa
();
124 prog
.globals
.insert
(*g
);
125 func
.block
.insert
(ssa2
, Code
::StoreGlobal(*g
, ssa
));
126 func
.order
.push(ssa2
);
128 // Inserting this unconditionally means that lookups within the
129 // local function will see the SSA name, and potentially avoid
130 // having to do a lookup on a global.
131 env
.mapping
.insert
(*name
, Var
::Ssa(ssa
));
133 trans_expr(prog
, env
, func
, body
)
140 let mut new_env
= Env
{
141 mapping
: HashMap
::with_capacity(binds
.len() + upvars
.len()),
143 for (i
, &name
) in binds
.iter
().enumerate() {
144 new_env
.mapping
.insert
(name
, Var
::Param(i
as u16));
146 for (i
, &name
) in upvars
.iter
().enumerate() {
147 new_env
.mapping
.insert
(name
, Var
::Upvar(i
as u16));
149 let new_func
= make_func(binds
.len() as u16, prog
, &mut new_env
, body
)?
;
150 let ssa
= func
.fresh
_ssa
();
153 .map(|&var
| trans_expr(prog
, env
, func
, &Ast
::Var(var
)))
154 .collect
::<Result
<_
, String
>>()?
;
160 params
: binds
.len() as u16,
163 func
.order
.push(ssa
);
164 prog
.funct
ions
.insert
(new_func
.name
, new_func
);
170 .map(|term
| trans_expr(prog
, env
, func
, term
))
171 .collect
::<Result
<_
, _
>>()?
;
172 let ssa
= func
.fresh
_ssa
();
173 func
.block
.insert
(ssa
, Code
::App(terms
));
174 func
.order
.push(ssa
);
178 match env
.resolve(name
) {
179 // Forwarding SSA variables skips unnecessary loads
180 Some(Var
::Ssa(ssa
)) => Ok(ssa
),
182 if let Var
::Global(g
) = var
{
183 prog
.globals
.insert
(g
);
185 let ssa
= func
.fresh
_ssa
();
186 func
.block
.insert
(ssa
, Code
::Load(var
));
187 // Inserting the result of the lookup into the environment deduplicates loads.
188 env
.mapping
.insert
(*name
, Var
::Ssa(ssa
));
189 func
.order
.push(ssa
);
192 None
=> Err(format
!("Unable to resolve variable {:?}", name
)),
196 let ssa
= func
.fresh
_ssa
();
197 func
.block
.insert
(ssa
, Code
::Num(*n
));
198 func
.order
.push(ssa
);
204 impl fmt
::Debug
for FnName
{
205 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
206 write
!(fmt
, "@fn{}", self.0)
210 impl fmt
::Debug
for SsaName
{
211 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
212 write
!(fmt
, "%{}", self.0)
216 impl fmt
::Debug
for Var
{
217 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
219 Var
::Global(x
) => write
!(fmt
, "@{}", x
),
220 Var
::Param(x
) => write
!(fmt
, "p{}", x
),
221 Var
::Upvar(x
) => write
!(fmt
, "c{}", x
),
222 Var
::Ssa(x
) => write
!(fmt
, "{:?}", x
),
227 impl fmt
::Debug
for Code
{
228 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
230 Code
::Load(var
) => write
!(fmt
, "load {:?}", var
),
231 Code
::StoreGlobal(g
, ssa
) => write
!(fmt
, "store [{:?}] = {:?}", Var
::Global(*g
), ssa
),
237 write
!(fmt
, "lam {:?} ({}) [", name
, params
)?
;
239 write
!(fmt
, "{:?} ", up
)?
;
244 write
!(fmt
, "app (")?
;
246 write
!(fmt
, "{:?} ", arg
)?
;
250 Code
::Num(n
) => write
!(fmt
, "{}", n
),
255 impl fmt
::Debug
for Func
{
256 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
257 write
!(fmt
, "fn {:?} ({}) ", self.name
, self.params
)?
;
259 .entries(self.order
.iter
().map(|x
| (x
, &self.block
[x
])))
260 .entry(&"ret", &self.result
)