]>
Witch of Git - ivy/blob - src/ast.rs
6 sync
::atomic
::{AtomicU32
, Ordering
},
9 #[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)]
16 pub fn local(&self) -> bool
{
18 Name
::Local(_
) => true,
19 Name
::Global(_
) => false,
23 pub fn global_number(&self) -> Option
<u32> {
25 Name
::Local(_
) => None
,
26 Name
::Global(g
) => Some(*g
),
30 fn to_doc(&self) -> RcDoc
{
32 Name
::Local(n
) => RcDoc
::text(format
!("x{}", n
)),
33 Name
::Global(n
) => RcDoc
::text(format
!("g{}", n
)),
38 #[derive(PartialEq, Clone, Debug)]
40 Let(Vec
<(Name
, Ast
)>, Box
<Ast
>),
52 pub fn to_doc(&self) -> RcDoc
{
54 Ast
::Let(binds
, body
) => RcDoc
::text("let")
57 .append(RcDoc
::intersperse(
58 binds
.iter
().map(|(n
, v
)| {
60 .append(RcDoc
::space())
61 .append(RcDoc
::text("="))
62 .append(RcDoc
::line().append(v
.to_doc()).nest(2).group())
64 RcDoc
::text(";").append(RcDoc
::line()),
68 .append(RcDoc
::line())
69 .append(RcDoc
::text("in"))
70 .append(RcDoc
::line())
71 .append(body
.to_doc()),
72 Ast
::Lam
{ binds
, body
, .. } => RcDoc
::text("lam").append(
74 .append(RcDoc
::text("("))
76 RcDoc
::intersperse(binds
.iter
().map(|x
| x
.to_doc()), RcDoc
::line())
80 .append(RcDoc
::text(") =>"))
81 .append(RcDoc
::line())
82 .append(body
.to_doc())
86 Ast
::App(terms
) => RcDoc
::intersperse(
87 terms
.iter
().map(|x
| match x
{
88 Ast
::App(..) | Ast
::Lam
{ .. } => {
89 RcDoc
::text("(").append(x
.to_doc()).append(RcDoc
::text(")"))
97 Ast
::Var(name
) => name
.to_doc(),
98 Ast
::Num(n
) => RcDoc
::as_string(n
),
105 vars
: HashMap
<String
, Name
>,
106 upvars
: RefCell
<HashMap
<String
, Name
>>,
107 up
: Option
<&'e Env
<'e
>>,
111 fn new() -> Env
<'
static> {
113 fresh
: AtomicU32
::new(0),
114 vars
: HashMap
::new(),
115 upvars
: RefCell
::new(HashMap
::new()),
120 fn wrapping
<'e
, 'r
: 'e
>(env
: &'r Env
<'e
>) -> Env
<'r
> {
122 fresh
: AtomicU32
::new(env
.fresh
.load(Ordering
::Relaxed
)),
123 vars
: HashMap
::new(),
124 upvars
: RefCell
::new(HashMap
::new()),
129 fn fresh(&mut self, text
: &str) -> Name
{
130 let name
= if self.up
.is
_some
() {
131 Name
::Local(*self.fresh
.get_mut())
133 Name
::Global(*self.fresh
.get_mut())
135 self.vars
.insert
(text
.into
(), name
);
136 *self.fresh
.get_mut() += 1;
140 fn _get(&self, name
: &str) -> Option
<Name
> {
141 if let Some(&resolved
) = self.vars
.get(name
) {
142 return Some(resolved
);
144 self.up
.and_then(|up
| up
._get
(name
)).map(|resolved
| {
145 if resolved
.local() {
146 self.upvars
.borrow_mut().insert
(name
.into
(), resolved
);
152 fn lookup(&mut self, name
: &str) -> Option
<Name
> {
153 if let Some(&resolved
) = self.vars
.get(name
) {
154 return Some(resolved
);
156 self.up
.and_then(|up
| up
._get
(name
)).map(|resolved
| {
157 self.vars
.insert
(name
.into
(), resolved
);
158 if resolved
.local() {
159 self.upvars
.get_mut().insert
(name
.into
(), resolved
);
165 fn upvars(&self) -> Vec
<Name
> {
166 self.upvars
.borrow().values().map(|&x
| x
).collect()
170 impl Drop
for Env
<'_
> {
172 if let Some(up
) = &self.up
{
173 up
.fresh
.store(*self.fresh
.get_mut(), Ordering
::Relaxed
);
180 builtins
: &[impl AsRef
<str>],
182 ) -> Result
<(Ast
, HashMap
<String
, Name
>), &'
static str> {
183 let mut env
= Env
::new();
184 let mut builtin_map
= HashMap
::new();
185 for builtin
in builtins
{
186 let builtin
= builtin
.as_ref();
187 builtin_map
.insert
(builtin
.into
(), env
.fresh
(builtin
));
189 Ok((Ast
::from_sexp(&mut env
, sexp
)?
, builtin_map
))
192 fn from_sexp
<'r
, 'e
: 'r
>(env
: &'r
mut Env
<'e
>, sexp
: &Sexp
) -> Result
<Ast
, &'
static str> {
194 Sexp
::List(xs
, _
) => match xs
.first
() {
195 Some(Sexp
::Sym(s
, _
)) if s
== "let" => {
197 return Err("too many body expressions in 'let'");
199 let binds
= match xs
.get(1) {
200 Some(Sexp
::List(binds
, _
)) => binds
202 .map(|bind
| match bind
{
203 Sexp
::List(bind
, _
) => {
205 return Err("binding lists must have two elements");
207 // We do the body before the name to avoid being "letrec"
208 let body
= Ast
::from_sexp(env
, &bind
[1])?
;
209 let name
= match &bind
[0] {
210 Sexp
::Sym(name
, _
) => env
.fresh
(&name
),
212 return Err("binding lists must start with a variable")
217 _
=> Err("bindings must be lists"),
219 .collect
::<Result
<_
, _
>>()?
,
220 Some(_
) => return Err("the binding in 'let' is not a list"),
221 None
=> return Err("no binding form in 'let'"),
223 let body
= match xs
.get(2) {
224 Some(x
) => Box
::new(Ast
::from_sexp(env
, x
)?
),
225 None
=> return Err("no body expression in 'let'"),
227 Ok(Ast
::Let(binds
, body
))
229 Some(Sexp
::Sym(s
, _
)) if s
== "lam" => {
231 return Err("too many body expressions in 'lam'");
233 let mut env
= Env
::wrapping(env
);
234 let binds
= match xs
.get(1) {
235 Some(Sexp
::List(names
, _
)) => names
237 .map(|name
| match name
{
238 Sexp
::Sym(s
, _
) => Ok(env
.fresh
(&s
)),
239 _
=> Err("non-symbol in 'lam' arguments"),
241 .collect
::<Result
<_
, _
>>()?
,
242 Some(_
) => return Err("'lam' arguments weren't a list"),
243 None
=> return Err("no arguments in 'lam'"),
245 let body
= match xs
.get(2) {
246 Some(x
) => Box
::new(Ast
::from_sexp(&mut env
, x
)?
),
247 None
=> return Err("no body expression in 'lam'"),
249 let upvars
= env
.upvars
();
256 Some(_
) => Ok(Ast
::App(
258 .map(|x
| Ast
::from_sexp(env
, x
))
259 .collect
::<Result
<_
, _
>>()?
,
261 None
=> Err("expected a non-empty list for an application"),
263 Sexp
::Sym(s
, _
) if s
== "let" => Err("unexpected id 'let'"),
264 Sexp
::Sym(s
, _
) if s
== "lam" => Err("unexpected id 'lam'"),
265 Sexp
::Sym(s
, _
) => Ok(Ast
::Var(
266 env
.lookup(s
).ok_or("variable used but not defined")?
,
268 Sexp
::Int(i
, _
) => Ok(Ast
::Num(*i
)),
269 _
=> Err("unexpected s-expression type"),