]>
Witch of Git - ivy/blob - src/ast.rs
5 sync
::atomic
::{AtomicU32
, Ordering
},
8 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
15 pub fn local(&self) -> bool
{
17 Name
::Local(_
) => true,
18 Name
::Global(_
) => false,
23 #[derive(PartialEq, Clone, Debug)]
25 Let(Vec
<(Name
, Ast
)>, Box
<Ast
>),
38 vars
: HashMap
<String
, Name
>,
39 upvars
: RefCell
<HashMap
<String
, Name
>>,
40 up
: Option
<&'e Env
<'e
>>,
44 fn new() -> Env
<'
static> {
46 fresh
: AtomicU32
::new(0),
48 upvars
: RefCell
::new(HashMap
::new()),
53 fn wrapping
<'e
, 'r
: 'e
>(env
: &'r Env
<'e
>) -> Env
<'r
> {
55 fresh
: AtomicU32
::new(env
.fresh
.load(Ordering
::Relaxed
)),
57 upvars
: RefCell
::new(HashMap
::new()),
62 fn fresh(&mut self, text
: &str) -> Name
{
63 let name
= if self.up
.is
_some
() {
64 Name
::Local(*self.fresh
.get_mut())
66 Name
::Global(*self.fresh
.get_mut())
68 self.vars
.insert
(text
.into
(), name
);
69 *self.fresh
.get_mut() += 1;
73 fn _get(&self, name
: &str) -> Option
<Name
> {
74 if let Some(&resolved
) = self.vars
.get(name
) {
75 return Some(resolved
);
77 self.up
.and_then(|up
| up
._get
(name
)).map(|resolved
| {
79 self.upvars
.borrow_mut().insert
(name
.into
(), resolved
);
85 fn lookup(&mut self, name
: &str) -> Option
<Name
> {
86 if let Some(&resolved
) = self.vars
.get(name
) {
87 return Some(resolved
);
89 self.up
.and_then(|up
| up
._get
(name
)).map(|resolved
| {
90 self.vars
.insert
(name
.into
(), resolved
);
92 self.upvars
.get_mut().insert
(name
.into
(), resolved
);
98 fn upvars(&self) -> Vec
<Name
> {
99 self.upvars
.borrow().values().map(|&x
| x
).collect()
103 impl Drop
for Env
<'_
> {
105 if let Some(up
) = &self.up
{
106 up
.fresh
.store(*self.fresh
.get_mut(), Ordering
::Relaxed
);
112 pub fn parse(builtins
: &[impl AsRef
<str>], sexp
: &Sexp
) -> Result
<(Ast
, HashMap
<String
, Name
>), &'
static str> {
113 let mut env
= Env
::new();
114 let mut builtin_map
= HashMap
::new();
115 for builtin
in builtins
{
116 let builtin
= builtin
.as_ref();
117 builtin_map
.insert
(builtin
.into
(), env
.fresh
(builtin
));
119 Ok((Ast
::from_sexp(&mut env
, sexp
)?
, builtin_map
))
122 fn from_sexp
<'r
, 'e
: 'r
>(env
: &'r
mut Env
<'e
>, sexp
: &Sexp
) -> Result
<Ast
, &'
static str> {
124 Sexp
::List(xs
, _
) => match xs
.first
() {
125 Some(Sexp
::Sym(s
, _
)) if s
== "let" => {
127 return Err("too many body expressions in 'let'");
129 let binds
= match xs
.get(1) {
130 Some(Sexp
::List(binds
, _
)) => binds
132 .map(|bind
| match bind
{
133 Sexp
::List(bind
, _
) => {
135 return Err("binding lists must have two elements");
137 // We do the body before the name to avoid being "letrec"
138 let body
= Ast
::from_sexp(env
, &bind
[1])?
;
139 let name
= match &bind
[0] {
140 Sexp
::Sym(name
, _
) => env
.fresh
(&name
),
142 return Err("binding lists must start with a variable")
147 _
=> Err("bindings must be lists"),
149 .collect
::<Result
<_
, _
>>()?
,
150 Some(_
) => return Err("the binding in 'let' is not a list"),
151 None
=> return Err("no binding form in 'let'"),
153 let body
= match xs
.get(2) {
154 Some(x
) => Box
::new(Ast
::from_sexp(env
, x
)?
),
155 None
=> return Err("no body expression in 'let'"),
157 Ok(Ast
::Let(binds
, body
))
159 Some(Sexp
::Sym(s
, _
)) if s
== "lam" => {
161 return Err("too many body expressions in 'lam'");
163 let mut env
= Env
::wrapping(env
);
164 let binds
= match xs
.get(1) {
165 Some(Sexp
::List(names
, _
)) => names
167 .map(|name
| match name
{
168 Sexp
::Sym(s
, _
) => Ok(env
.fresh
(&s
)),
169 _
=> Err("non-symbol in 'lam' arguments"),
171 .collect
::<Result
<_
, _
>>()?
,
172 Some(_
) => return Err("'lam' arguments weren't a list"),
173 None
=> return Err("no arguments in 'lam'"),
175 let body
= match xs
.get(2) {
176 Some(x
) => Box
::new(Ast
::from_sexp(&mut env
, x
)?
),
177 None
=> return Err("no body expression in 'lam'"),
179 let upvars
= env
.upvars
();
186 Some(_
) => Ok(Ast
::App(
188 .map(|x
| Ast
::from_sexp(env
, x
))
189 .collect
::<Result
<_
, _
>>()?
,
191 None
=> Err("expected a non-empty list for an application"),
193 Sexp
::Sym(s
, _
) if s
== "let" => Err("unexpected id 'let'"),
194 Sexp
::Sym(s
, _
) if s
== "lam" => Err("unexpected id 'lam'"),
195 Sexp
::Sym(s
, _
) => Ok(Ast
::Var(
196 env
.lookup(s
).ok_or("variable used but not defined")?
,
198 Sexp
::Int(i
, _
) => Ok(Ast
::Num(*i
)),
199 _
=> Err("unexpected s-expression type"),