]>
Witch of Git - ivy/blob - src/ast.rs
6 sync
::atomic
::{AtomicU32
, Ordering
},
9 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
16 pub fn local(&self) -> bool
{
18 Name
::Local(_
) => true,
19 Name
::Global(_
) => false,
25 fn to_doc(&self) -> RcDoc
{
27 Name
::Local(n
) => RcDoc
::text(format
!("x{}", n
)),
28 Name
::Global(n
) => RcDoc
::text(format
!("g{}", n
)),
33 #[derive(PartialEq, Clone, Debug)]
35 Let(Vec
<(Name
, Ast
)>, Box
<Ast
>),
47 pub fn to_doc(&self) -> RcDoc
{
49 Ast
::Let(binds
, body
) => RcDoc
::text("let")
52 .append(RcDoc
::intersperse(
53 binds
.iter
().map(|(n
, v
)| {
55 .append(RcDoc
::space())
56 .append(RcDoc
::text("="))
57 .append(RcDoc
::line().append(v
.to_doc()).nest(2).group())
59 RcDoc
::text(";").append(RcDoc
::line()),
63 .append(RcDoc
::line())
64 .append(RcDoc
::text("in"))
65 .append(RcDoc
::line())
66 .append(body
.to_doc()),
67 Ast
::Lam
{ binds
, body
, .. } => RcDoc
::text("lam").append(
69 .append(RcDoc
::text("("))
71 RcDoc
::intersperse(binds
.iter
().map(|x
| x
.to_doc()), RcDoc
::line())
75 .append(RcDoc
::text(") =>"))
76 .append(RcDoc
::line())
77 .append(body
.to_doc())
81 Ast
::App(terms
) => RcDoc
::intersperse(
82 terms
.iter
().map(|x
| match x
{
83 Ast
::App(..) | Ast
::Lam
{ .. } => {
84 RcDoc
::text("(").append(x
.to_doc()).append(RcDoc
::text(")"))
92 Ast
::Var(name
) => name
.to_doc(),
93 Ast
::Num(n
) => RcDoc
::as_string(n
),
100 vars
: HashMap
<String
, Name
>,
101 upvars
: RefCell
<HashMap
<String
, Name
>>,
102 up
: Option
<&'e Env
<'e
>>,
106 fn new() -> Env
<'
static> {
108 fresh
: AtomicU32
::new(0),
109 vars
: HashMap
::new(),
110 upvars
: RefCell
::new(HashMap
::new()),
115 fn wrapping
<'e
, 'r
: 'e
>(env
: &'r Env
<'e
>) -> Env
<'r
> {
117 fresh
: AtomicU32
::new(env
.fresh
.load(Ordering
::Relaxed
)),
118 vars
: HashMap
::new(),
119 upvars
: RefCell
::new(HashMap
::new()),
124 fn fresh(&mut self, text
: &str) -> Name
{
125 let name
= if self.up
.is
_some
() {
126 Name
::Local(*self.fresh
.get_mut())
128 Name
::Global(*self.fresh
.get_mut())
130 self.vars
.insert
(text
.into
(), name
);
131 *self.fresh
.get_mut() += 1;
135 fn _get(&self, name
: &str) -> Option
<Name
> {
136 if let Some(&resolved
) = self.vars
.get(name
) {
137 return Some(resolved
);
139 self.up
.and_then(|up
| up
._get
(name
)).map(|resolved
| {
140 if resolved
.local() {
141 self.upvars
.borrow_mut().insert
(name
.into
(), resolved
);
147 fn lookup(&mut self, name
: &str) -> Option
<Name
> {
148 if let Some(&resolved
) = self.vars
.get(name
) {
149 return Some(resolved
);
151 self.up
.and_then(|up
| up
._get
(name
)).map(|resolved
| {
152 self.vars
.insert
(name
.into
(), resolved
);
153 if resolved
.local() {
154 self.upvars
.get_mut().insert
(name
.into
(), resolved
);
160 fn upvars(&self) -> Vec
<Name
> {
161 self.upvars
.borrow().values().map(|&x
| x
).collect()
165 impl Drop
for Env
<'_
> {
167 if let Some(up
) = &self.up
{
168 up
.fresh
.store(*self.fresh
.get_mut(), Ordering
::Relaxed
);
175 builtins
: &[impl AsRef
<str>],
177 ) -> Result
<(Ast
, HashMap
<String
, Name
>), &'
static str> {
178 let mut env
= Env
::new();
179 let mut builtin_map
= HashMap
::new();
180 for builtin
in builtins
{
181 let builtin
= builtin
.as_ref();
182 builtin_map
.insert
(builtin
.into
(), env
.fresh
(builtin
));
184 Ok((Ast
::from_sexp(&mut env
, sexp
)?
, builtin_map
))
187 fn from_sexp
<'r
, 'e
: 'r
>(env
: &'r
mut Env
<'e
>, sexp
: &Sexp
) -> Result
<Ast
, &'
static str> {
189 Sexp
::List(xs
, _
) => match xs
.first
() {
190 Some(Sexp
::Sym(s
, _
)) if s
== "let" => {
192 return Err("too many body expressions in 'let'");
194 let binds
= match xs
.get(1) {
195 Some(Sexp
::List(binds
, _
)) => binds
197 .map(|bind
| match bind
{
198 Sexp
::List(bind
, _
) => {
200 return Err("binding lists must have two elements");
202 // We do the body before the name to avoid being "letrec"
203 let body
= Ast
::from_sexp(env
, &bind
[1])?
;
204 let name
= match &bind
[0] {
205 Sexp
::Sym(name
, _
) => env
.fresh
(&name
),
207 return Err("binding lists must start with a variable")
212 _
=> Err("bindings must be lists"),
214 .collect
::<Result
<_
, _
>>()?
,
215 Some(_
) => return Err("the binding in 'let' is not a list"),
216 None
=> return Err("no binding form in 'let'"),
218 let body
= match xs
.get(2) {
219 Some(x
) => Box
::new(Ast
::from_sexp(env
, x
)?
),
220 None
=> return Err("no body expression in 'let'"),
222 Ok(Ast
::Let(binds
, body
))
224 Some(Sexp
::Sym(s
, _
)) if s
== "lam" => {
226 return Err("too many body expressions in 'lam'");
228 let mut env
= Env
::wrapping(env
);
229 let binds
= match xs
.get(1) {
230 Some(Sexp
::List(names
, _
)) => names
232 .map(|name
| match name
{
233 Sexp
::Sym(s
, _
) => Ok(env
.fresh
(&s
)),
234 _
=> Err("non-symbol in 'lam' arguments"),
236 .collect
::<Result
<_
, _
>>()?
,
237 Some(_
) => return Err("'lam' arguments weren't a list"),
238 None
=> return Err("no arguments in 'lam'"),
240 let body
= match xs
.get(2) {
241 Some(x
) => Box
::new(Ast
::from_sexp(&mut env
, x
)?
),
242 None
=> return Err("no body expression in 'lam'"),
244 let upvars
= env
.upvars
();
251 Some(_
) => Ok(Ast
::App(
253 .map(|x
| Ast
::from_sexp(env
, x
))
254 .collect
::<Result
<_
, _
>>()?
,
256 None
=> Err("expected a non-empty list for an application"),
258 Sexp
::Sym(s
, _
) if s
== "let" => Err("unexpected id 'let'"),
259 Sexp
::Sym(s
, _
) if s
== "lam" => Err("unexpected id 'lam'"),
260 Sexp
::Sym(s
, _
) => Ok(Ast
::Var(
261 env
.lookup(s
).ok_or("variable used but not defined")?
,
263 Sexp
::Int(i
, _
) => Ok(Ast
::Num(*i
)),
264 _
=> Err("unexpected s-expression type"),