use crate::compiler::sexpr::{FromSExpr, ParseError, SExpr, ToSExpr, expect_n};
use super::{
Branch, Expr, ExternalItem, Item, ItemId, ItemSupply, Kind, Module, NativeItem, Row, Symbol,
TypApp, Type, TypeVar, Var, VarId,
};
use crate::external_type::FunctionType;
use std::collections::{BTreeMap, HashMap};
impl ToSExpr<()> for ItemId {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("itm_id".into()),
SExpr::Atom(self.0.to_string()),
])
}
}
impl ToSExpr<()> for VarId {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("var_id".into()),
SExpr::Atom(self.0.to_string()),
])
}
}
impl ToSExpr<()> for TypeVar {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("typ_id".into()),
SExpr::Atom(self.0.to_string()),
])
}
}
impl ToSExpr<()> for Kind {
fn to_sexpr(&self, _config: &()) -> SExpr {
match self {
Kind::Type => SExpr::List(vec![SExpr::Atom("type".into())]),
Kind::Row => SExpr::List(vec![SExpr::Atom("row".into())]),
}
}
}
impl ToSExpr<()> for Symbol {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("symbol".into()),
SExpr::Atom(self.module.clone()),
SExpr::Atom(self.field.clone()),
])
}
}
impl ToSExpr<()> for Var {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("var".into()),
self.id.to_sexpr(&()),
self.typ.to_sexpr(&()),
])
}
}
impl ToSExpr<()> for Row {
fn to_sexpr(&self, _config: &()) -> SExpr {
match self {
Row::Open(tv) => SExpr::List(vec![SExpr::Atom("open".into()), tv.to_sexpr(&())]),
Row::Closed(fields) => {
let mut elements = vec![SExpr::Atom("closed".into())];
for (name, typ) in fields {
elements.push(SExpr::Atom(name.clone()));
elements.push(typ.to_sexpr(&()));
}
SExpr::List(elements)
}
}
}
}
impl ToSExpr<()> for Type {
fn to_sexpr(&self, _config: &()) -> SExpr {
match self {
Type::Unit => SExpr::List(vec![SExpr::Atom("unit".into())]),
Type::Int => SExpr::List(vec![SExpr::Atom("int".into())]),
Type::Float => SExpr::List(vec![SExpr::Atom("float".into())]),
Type::String => SExpr::List(vec![SExpr::Atom("string".into())]),
Type::DataFrame => SExpr::List(vec![SExpr::Atom("dataframe".into())]),
Type::Var(tv) => tv.to_sexpr(&()),
Type::Abs(param, ret) => SExpr::List(vec![
SExpr::Atom("fn".into()),
param.to_sexpr(&()),
ret.to_sexpr(&()),
]),
Type::TypAbs(kind, body) => SExpr::List(vec![
SExpr::Atom("typ_abs".into()),
kind.to_sexpr(&()),
body.to_sexpr(&()),
]),
Type::Prod(row) => SExpr::List(vec![SExpr::Atom("prd".into()), row.to_sexpr(&())]),
Type::Sum(row) => SExpr::List(vec![SExpr::Atom("sum".into()), row.to_sexpr(&())]),
}
}
}
impl ToSExpr<()> for TypApp {
fn to_sexpr(&self, _config: &()) -> SExpr {
match self {
TypApp::Ty(ty) => SExpr::List(vec![SExpr::Atom("ty".into()), ty.to_sexpr(&())]),
TypApp::Row(row) => SExpr::List(vec![SExpr::Atom("row".into()), row.to_sexpr(&())]),
}
}
}
impl ToSExpr<()> for Expr {
fn to_sexpr(&self, _config: &()) -> SExpr {
match self {
Expr::Unit => SExpr::List(vec![SExpr::Atom("unit".into())]),
Expr::Integer(n) => {
SExpr::List(vec![SExpr::Atom("i".into()), SExpr::Atom(n.to_string())])
}
Expr::Float(n) => {
let s = if n.round() == *n {
format!("{}.0", n)
} else {
n.to_string()
};
SExpr::List(vec![SExpr::Atom("f".into()), SExpr::Atom(s)])
}
Expr::String(s) => SExpr::List(vec![SExpr::Atom("s".into()), SExpr::Atom(s.clone())]),
Expr::Variable(v) => v.to_sexpr(&()),
Expr::Abstraction(param, body) => SExpr::List(vec![
SExpr::Atom("abs".into()),
param.to_sexpr(&()),
body.to_sexpr(&()),
]),
Expr::Application(_fn_expr, _arg) => {
fn collect_args<'a>(expr: &'a Expr, args: &mut Vec<&'a Expr>) -> &'a Expr {
if let Expr::Application(abstraction, parameter) = expr {
args.push(parameter);
collect_args(abstraction, args)
} else {
expr
}
}
let mut args = Vec::new();
let function = collect_args(self, &mut args);
let mut elements = vec![SExpr::Atom("app".into()), function.to_sexpr(&())];
for arg in args {
elements.push(arg.to_sexpr(&()));
}
SExpr::List(elements)
}
Expr::TypAbs(kind, body) => SExpr::List(vec![
SExpr::Atom("typ_abs".into()),
kind.to_sexpr(&()),
body.to_sexpr(&()),
]),
Expr::TypApp(fn_expr, ty_app) => SExpr::List(vec![
SExpr::Atom("ty_app".into()),
fn_expr.to_sexpr(&()),
ty_app.to_sexpr(&()),
]),
Expr::Local(var, init, body) => SExpr::List(vec![
SExpr::Atom("let".into()),
var.to_sexpr(&()),
init.to_sexpr(&()),
body.to_sexpr(&()),
]),
Expr::Tuple(fields) => {
let mut elements = vec![SExpr::Atom("tuple".into())];
for (name, expr) in fields {
elements.push(SExpr::Atom(name.clone()));
elements.push(expr.to_sexpr(&()));
}
SExpr::List(elements)
}
Expr::Field(expr, index) => SExpr::List(vec![
SExpr::Atom("field".into()),
expr.to_sexpr(&()),
SExpr::Atom(index.to_string()),
]),
Expr::Tag(ty, index, body) => SExpr::List(vec![
SExpr::Atom("tag".into()),
ty.to_sexpr(&()),
SExpr::Atom(index.to_string()),
body.to_sexpr(&()),
]),
Expr::Item(ty, id, symbol) => SExpr::List(vec![
SExpr::Atom("item".into()),
id.to_sexpr(&()),
symbol.to_sexpr(&()),
ty.to_sexpr(&()),
]),
Expr::Case(typ, scrutinee, branches) => {
let mut elements = vec![
SExpr::Atom("case".into()),
typ.to_sexpr(&()),
scrutinee.to_sexpr(&()),
];
for branch in branches {
elements.push(SExpr::List(vec![
branch.param.to_sexpr(&()),
branch.body.to_sexpr(&()),
]));
}
SExpr::List(elements)
}
}
}
}
impl ToSExpr<()> for NativeItem {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("pub".into()),
self.symbol.to_sexpr(&()),
self.expr.to_sexpr(&()),
self.typ.to_sexpr(&()),
])
}
}
impl ToSExpr<()> for ExternalItem {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("pub".into()),
SExpr::Atom("ext".into()),
self.symbol.to_sexpr(&()),
self.external_type.to_sexpr(&()),
])
}
}
impl ToSExpr<()> for Item {
fn to_sexpr(&self, _config: &()) -> SExpr {
match self {
Item::Native(item) => item.to_sexpr(&()),
Item::External(item) => item.to_sexpr(&()),
}
}
}
impl ToSExpr<()> for Branch {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("branch".into()),
self.param.to_sexpr(&()),
self.body.to_sexpr(&()),
])
}
}
impl FromSExpr<()> for Branch {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let [param, body] = expect_n("branch", s.args())?;
Ok(Branch {
param: Var::from_sexp(param, _ctx)?,
body: Expr::from_sexp(body, _ctx)?,
})
}
}
impl ToSExpr<()> for Module {
fn to_sexpr(&self, _config: &()) -> SExpr {
let mut elements = vec![SExpr::Atom("mod".into())];
for item in self.items.values() {
elements.push(item.to_sexpr(&()));
}
SExpr::List(elements)
}
}
impl FromSExpr<()> for ItemId {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let args: &[SExpr; 1] = expect_n("itm_id", s.args())?;
let n = match &args[0] {
SExpr::Atom(s) => s.parse::<u32>().map_err(|_| ParseError::ParseValue {
type_name: "u32",
reason: s.clone(),
})?,
_ => {
return Err(ParseError::ExpectedTag {
expected: "itm_id value",
found: args[0].tag().map(|s| s.to_string()),
});
}
};
Ok(ItemId(n))
}
}
impl FromSExpr<()> for VarId {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let args: &[SExpr; 1] = expect_n("var_id", s.args())?;
let n = match &args[0] {
SExpr::Atom(s) => s.parse::<u32>().map_err(|_| ParseError::ParseValue {
type_name: "u32",
reason: s.clone(),
})?,
_ => {
return Err(ParseError::ExpectedTag {
expected: "var_id value",
found: args[0].tag().map(|s| s.to_string()),
});
}
};
Ok(VarId(n))
}
}
impl FromSExpr<()> for TypeVar {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let args: &[SExpr; 1] = expect_n("typ_id", s.args())?;
let n = match &args[0] {
SExpr::Atom(s) => s.parse::<usize>().map_err(|_| ParseError::ParseValue {
type_name: "usize",
reason: s.clone(),
})?,
_ => {
return Err(ParseError::ExpectedTag {
expected: "typ_id value",
found: args[0].tag().map(|s| s.to_string()),
});
}
};
Ok(TypeVar(n))
}
}
impl FromSExpr<()> for Kind {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
match s.tag() {
Some("type") => Ok(Kind::Type),
Some("row") => Ok(Kind::Row),
_ => Err(ParseError::ExpectedTag {
expected: "type or row",
found: s.tag().map(|s| s.to_string()),
}),
}
}
}
impl FromSExpr<()> for Symbol {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let args: &[SExpr; 2] = expect_n("symbol", s.args())?;
let module = match &args[0] {
SExpr::Atom(s) => s.clone(),
_ => {
return Err(ParseError::ExpectedTag {
expected: "module",
found: args[0].tag().map(|s| s.to_string()),
});
}
};
let field = match &args[1] {
SExpr::Atom(s) => s.clone(),
_ => {
return Err(ParseError::ExpectedTag {
expected: "field",
found: args[1].tag().map(|s| s.to_string()),
});
}
};
Ok(Symbol { module, field })
}
}
impl FromSExpr<()> for Var {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "var",
found: None,
})?;
let id = VarId::from_sexp(&args[0], ctx)?;
let typ = if args.len() > 1 {
Type::from_sexp(&args[1], ctx)?
} else {
Type::Unit
};
Ok(Var { id, typ })
}
}
impl FromSExpr<()> for Row {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
match s.tag() {
Some("open") => {
let args: &[SExpr; 1] = expect_n("open", s.args())?;
let tv = TypeVar::from_sexp(&args[0], ctx)?;
Ok(Row::Open(tv))
}
Some("closed") => {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "closed",
found: None,
})?;
let mut fields = Vec::new();
let mut iter = args.iter();
while let Some(name) = iter.next() {
let typ = iter.next().ok_or(ParseError::ExpectedArgs {
expected: 2,
found: args.len(),
})?;
let name_str = match name {
SExpr::Atom(s) => s.clone(),
_ => {
return Err(ParseError::ExpectedTag {
expected: "field name",
found: name.tag().map(|s| s.to_string()),
});
}
};
let typ = Type::from_sexp(typ, ctx)?;
fields.push((name_str, typ));
}
Ok(Row::Closed(fields))
}
_ => Err(ParseError::ExpectedTag {
expected: "open or closed",
found: s.tag().map(|s| s.to_string()),
}),
}
}
}
impl FromSExpr<()> for Type {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
match s.tag() {
Some("unit") => Ok(Type::Unit),
Some("int") => Ok(Type::Int),
Some("float") => Ok(Type::Float),
Some("string") => Ok(Type::String),
Some("dataframe") => Ok(Type::DataFrame),
Some("typ_id") => {
let args: &[SExpr; 1] = expect_n("typ_id", s.args())?;
let n = match &args[0] {
SExpr::Atom(s) => s.parse::<usize>().map_err(|_| ParseError::ParseValue {
type_name: "usize",
reason: s.clone(),
})?,
_ => {
return Err(ParseError::ExpectedTag {
expected: "typ_id value",
found: args[0].tag().map(|s| s.to_string()),
});
}
};
Ok(Type::Var(TypeVar(n)))
}
Some("fn") => {
let args: &[SExpr; 2] = expect_n("fn", s.args())?;
let param = Type::from_sexp(&args[0], ctx)?;
let ret = Type::from_sexp(&args[1], ctx)?;
Ok(Type::Abs(Box::new(param), Box::new(ret)))
}
Some("typ_abs") => {
let args: &[SExpr; 2] = expect_n("typ_abs", s.args())?;
let kind = Kind::from_sexp(&args[0], ctx)?;
let body = Type::from_sexp(&args[1], ctx)?;
Ok(Type::TypAbs(kind, Box::new(body)))
}
Some("prd") => {
let args: &[SExpr; 1] = expect_n("prd", s.args())?;
let row = Row::from_sexp(&args[0], ctx)?;
Ok(Type::Prod(row))
}
Some("sum") => {
let args: &[SExpr; 1] = expect_n("sum", s.args())?;
let row = Row::from_sexp(&args[0], ctx)?;
Ok(Type::Sum(row))
}
_ => Err(ParseError::ExpectedTag {
expected: "type tag",
found: s.tag().map(|s| s.to_string()),
}),
}
}
}
impl FromSExpr<()> for TypApp {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
match s.tag() {
Some("ty") => {
let args: &[SExpr; 1] = expect_n("ty", s.args())?;
let ty = Type::from_sexp(&args[0], ctx)?;
Ok(TypApp::Ty(ty))
}
Some("row") => {
let args: &[SExpr; 1] = expect_n("row", s.args())?;
let row = Row::from_sexp(&args[0], ctx)?;
Ok(TypApp::Row(row))
}
_ => Err(ParseError::ExpectedTag {
expected: "ty or row",
found: s.tag().map(|s| s.to_string()),
}),
}
}
}
impl FromSExpr<()> for Expr {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
match s.tag() {
Some("unit") => Ok(Expr::Unit),
Some("i") => {
let args: &[SExpr; 1] = expect_n("i", s.args())?;
let n = match &args[0] {
SExpr::Atom(s) => s.parse::<i64>().map_err(|_| ParseError::ParseValue {
type_name: "i64",
reason: s.clone(),
})?,
_ => {
return Err(ParseError::ExpectedTag {
expected: "integer value",
found: args[0].tag().map(|s| s.to_string()),
});
}
};
Ok(Expr::Integer(n))
}
Some("f") => {
let args: &[SExpr; 1] = expect_n("f", s.args())?;
let n = match &args[0] {
SExpr::Atom(s) => s.parse::<f64>().map_err(|_| ParseError::ParseValue {
type_name: "f64",
reason: s.clone(),
})?,
_ => {
return Err(ParseError::ExpectedTag {
expected: "float value",
found: args[0].tag().map(|s| s.to_string()),
});
}
};
Ok(Expr::Float(n))
}
Some("s") => {
let args: &[SExpr; 1] = expect_n("s", s.args())?;
let s = match &args[0] {
SExpr::Atom(s) => s.clone(),
_ => {
return Err(ParseError::ExpectedTag {
expected: "string value",
found: args[0].tag().map(|s| s.to_string()),
});
}
};
Ok(Expr::String(s))
}
Some("var") => Var::from_sexp(s, ctx).map(Expr::Variable),
Some("abs") => {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "abs",
found: None,
})?;
if args.len() < 2 {
return Err(ParseError::ExpectedArgs {
expected: 2,
found: args.len(),
});
}
let param = Var::from_sexp(&args[0], ctx)?;
let body = Expr::from_sexp(&args[1], ctx)?;
Ok(Expr::Abstraction(param, Box::new(body)))
}
Some("app") => {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "app",
found: None,
})?;
if args.is_empty() {
return Err(ParseError::ExpectedArgs {
expected: 2,
found: 0,
});
}
let function = Expr::from_sexp(&args[0], ctx)?;
let mut parameters = Vec::new();
for arg in &args[1..] {
parameters.push(Expr::from_sexp(arg, ctx)?);
}
let mut result = function;
for param in parameters {
result = Expr::Application(Box::new(result), Box::new(param));
}
Ok(result)
}
Some("typ_abs") => {
let args: &[SExpr; 2] = expect_n("typ_abs", s.args())?;
let kind = Kind::from_sexp(&args[0], ctx)?;
let body = Expr::from_sexp(&args[1], ctx)?;
Ok(Expr::TypAbs(kind, Box::new(body)))
}
Some("ty_app") => {
let args: &[SExpr; 2] = expect_n("ty_app", s.args())?;
let fn_expr = Expr::from_sexp(&args[0], ctx)?;
let ty_app = TypApp::from_sexp(&args[1], ctx)?;
Ok(Expr::TypApp(Box::new(fn_expr), ty_app))
}
Some("let") => {
let args: &[SExpr; 3] = expect_n("let", s.args())?;
let var = Var::from_sexp(&args[0], ctx)?;
let init = Expr::from_sexp(&args[1], ctx)?;
let body = Expr::from_sexp(&args[2], ctx)?;
Ok(Expr::Local(var, Box::new(init), Box::new(body)))
}
Some("tuple") => {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "tuple",
found: None,
})?;
let mut fields = Vec::new();
let mut iter = args.iter();
while let Some(name) = iter.next() {
let expr = iter.next().ok_or(ParseError::ExpectedArgs {
expected: 2,
found: args.len(),
})?;
let name_str = match name {
SExpr::Atom(s) => s.clone(),
_ => {
return Err(ParseError::ExpectedTag {
expected: "field name",
found: name.tag().map(|s| s.to_string()),
});
}
};
let expr = Expr::from_sexp(expr, ctx)?;
fields.push((name_str, expr));
}
Ok(Expr::Tuple(fields))
}
Some("field") => {
let args: &[SExpr; 2] = expect_n("field", s.args())?;
let expr = Expr::from_sexp(&args[0], ctx)?;
let index = match &args[1] {
SExpr::Atom(s) => s.parse::<usize>().map_err(|_| ParseError::ParseValue {
type_name: "usize",
reason: s.clone(),
})?,
_ => {
return Err(ParseError::ExpectedTag {
expected: "index",
found: args[1].tag().map(|s| s.to_string()),
});
}
};
Ok(Expr::Field(Box::new(expr), index))
}
Some("tag") => {
let args: &[SExpr; 3] = expect_n("tag", s.args())?;
let ty = Type::from_sexp(&args[0], ctx)?;
let index = match &args[1] {
SExpr::Atom(s) => s.parse::<usize>().map_err(|_| ParseError::ParseValue {
type_name: "usize",
reason: s.clone(),
})?,
_ => {
return Err(ParseError::ExpectedTag {
expected: "index",
found: args[1].tag().map(|s| s.to_string()),
});
}
};
let body = Expr::from_sexp(&args[2], ctx)?;
Ok(Expr::Tag(ty, index, Box::new(body)))
}
Some("item") => {
let args: &[SExpr; 3] = expect_n("item", s.args())?;
let id = ItemId::from_sexp(&args[0], ctx)?;
let symbol = Symbol::from_sexp(&args[1], ctx)?;
let ty = Type::from_sexp(&args[2], ctx)?;
Ok(Expr::Item(ty, id, symbol))
}
_ => Err(ParseError::ExpectedTag {
expected: "expr tag",
found: s.tag().map(|s| s.to_string()),
}),
}
}
}
impl FromSExpr<()> for NativeItem {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
let args: &[SExpr; 3] = expect_n("pub", s.args())?;
let symbol = Symbol::from_sexp(&args[0], ctx)?;
let expr = Expr::from_sexp(&args[1], ctx)?;
let typ = Type::from_sexp(&args[2], ctx)?;
Ok(NativeItem { symbol, expr, typ })
}
}
impl FromSExpr<()> for ExternalItem {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
let args: &[SExpr; 3] = expect_n("pub", s.args())?;
if let SExpr::Atom(tag) = &args[0] {
if tag != "ext" {
return Err(ParseError::ExpectedTag {
expected: "ext",
found: Some(tag.clone()),
});
}
} else {
return Err(ParseError::ExpectedTag {
expected: "ext",
found: args[0].tag().map(|s| s.to_string()),
});
}
let symbol = Symbol::from_sexp(&args[1], ctx)?;
let external_type = FunctionType::from_sexp(&args[2], ctx)?;
Ok(ExternalItem {
symbol,
external_type,
})
}
}
impl FromSExpr<()> for Item {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
match s.tag() {
Some("pub") => {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "pub",
found: None,
})?;
if args.is_empty() {
return Err(ParseError::ExpectedArgs {
expected: 1,
found: 0,
});
}
if let SExpr::Atom(first) = &args[0] {
if first == "ext" {
ExternalItem::from_sexp(s, ctx).map(Item::External)
} else {
NativeItem::from_sexp(s, ctx).map(Item::Native)
}
} else {
NativeItem::from_sexp(s, ctx).map(Item::Native)
}
}
_ => Err(ParseError::ExpectedTag {
expected: "pub",
found: s.tag().map(|s| s.to_string()),
}),
}
}
}
impl FromSExpr<()> for Module {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "mod",
found: None,
})?;
let mut items = BTreeMap::new();
for arg in args {
let item = Item::from_sexp(arg, ctx)?;
let id = match &item {
Item::Native(native) => {
let hash = native.symbol.field.len();
ItemId(hash as u32)
}
Item::External(ext) => {
let hash = ext.symbol.field.len();
ItemId(hash as u32)
}
};
items.insert(id, item);
}
Ok(Module {
items,
instances: HashMap::new(),
item_supply: ItemSupply::default(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::compiler::sexpr::parse_one;
use expect_test::expect;
fn roundtrip<T>(expected: expect_test::Expect)
where
T: ToSExpr<()> + FromSExpr<()>,
{
let parsed = T::from_sexp(&parse_one(expected.data()).unwrap(), &mut ()).unwrap();
expected.assert_eq(&parsed.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_item_id() {
let item_id = ItemId(42);
let s = item_id.to_sexpr(&());
let output = s.to_string();
expect!["(itm_id 42)"].assert_eq(&output);
}
#[test]
fn from_sexp_item_id() {
let s = SExpr::List(vec![SExpr::Atom("id".into()), SExpr::Atom("42".into())]);
let result = ItemId::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.0, 42);
}
#[test]
fn item_id_roundtrip() {
roundtrip::<ItemId>(expect!["(itm_id 123)"]);
}
#[test]
fn to_sexpr_var_id() {
let var_id = VarId(7);
let s = var_id.to_sexpr(&());
let output = s.to_string();
expect!["(var_id 7)"].assert_eq(&output);
}
#[test]
fn from_sexp_var_id() {
let s = SExpr::List(vec![SExpr::Atom("id".into()), SExpr::Atom("7".into())]);
let result = VarId::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.0, 7);
}
#[test]
fn var_id_roundtrip() {
roundtrip::<VarId>(expect!["(var_id 99)"]);
}
#[test]
fn to_sexpr_typevar_id() {
let typevar = TypeVar(5);
let s = typevar.to_sexpr(&());
let output = s.to_string();
expect!["(typ_id 5)"].assert_eq(&output);
}
#[test]
fn from_sexp_typevar_id() {
let s = SExpr::List(vec![SExpr::Atom("id".into()), SExpr::Atom("5".into())]);
let result = TypeVar::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.0, 5);
}
#[test]
fn typevar_id_roundtrip() {
roundtrip::<TypeVar>(expect!["(typ_id 42)"]);
}
#[test]
fn to_sexpr_kind_type() {
let kind = Kind::Type;
let s = kind.to_sexpr(&());
let output = s.to_string();
expect!["(type)"].assert_eq(&output);
}
#[test]
fn to_sexpr_kind_row() {
let kind = Kind::Row;
let s = kind.to_sexpr(&());
let output = s.to_string();
expect!["(row)"].assert_eq(&output);
}
#[test]
fn from_sexp_kind_type() {
let s = SExpr::List(vec![SExpr::Atom("type".into())]);
let result = Kind::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result, Kind::Type);
}
#[test]
fn from_sexp_kind_row() {
let s = SExpr::List(vec![SExpr::Atom("row".into())]);
let result = Kind::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result, Kind::Row);
}
#[test]
fn kind_roundtrip() {
roundtrip::<Kind>(expect!["(type)"]);
}
#[test]
fn to_sexpr_symbol() {
let symbol = Symbol {
module: "std".into(),
field: "io".into(),
};
let s = symbol.to_sexpr(&());
let output = s.to_string();
expect!["(symbol std io)"].assert_eq(&output);
}
#[test]
fn from_sexp_symbol() {
let s = SExpr::List(vec![
SExpr::Atom("symbol".into()),
SExpr::Atom("std".into()),
SExpr::Atom("io".into()),
]);
let result = Symbol::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.module, "std");
assert_eq!(result.field, "io");
}
#[test]
fn symbol_roundtrip() {
roundtrip::<Symbol>(expect!["(symbol std io)"]);
}
#[test]
fn to_sexpr_var() {
let var = Var {
id: VarId(0),
typ: Type::Int,
};
let s = var.to_sexpr(&());
let output = s.to_string();
expect!["(var (var_id 0) (int))"].assert_eq(&output);
}
#[test]
fn from_sexp_var() {
let s = SExpr::List(vec![
SExpr::Atom("var".into()),
SExpr::List(vec![SExpr::Atom("id".into()), SExpr::Atom("0".into())]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]);
let result = Var::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.id.0, 0);
assert_eq!(result.typ, Type::Int);
}
#[test]
fn var_roundtrip() {
roundtrip::<Var>(expect!["(var (var_id 3) (int))"]);
}
#[test]
fn to_sexpr_row_open() {
let row = Row::Open(TypeVar(0));
let s = row.to_sexpr(&());
let output = s.to_string();
expect!["(open (typ_id 0))"].assert_eq(&output);
}
#[test]
fn to_sexpr_row_closed() {
let row = Row::Closed(vec![("x".into(), Type::Int), ("y".into(), Type::Float)]);
let s = row.to_sexpr(&());
let output = s.to_string();
expect!["(closed x (int) y (float))"].assert_eq(&output);
}
#[test]
fn from_sexp_row_open() {
let s = SExpr::List(vec![
SExpr::Atom("open".into()),
SExpr::List(vec![SExpr::Atom("id".into()), SExpr::Atom("0".into())]),
]);
let result = Row::from_sexp(&s, &mut ()).unwrap();
assert!(matches!(result, Row::Open(TypeVar(0))));
}
#[test]
fn from_sexp_row_closed() {
let s = SExpr::List(vec![
SExpr::Atom("closed".into()),
SExpr::Atom("x".into()),
SExpr::List(vec![SExpr::Atom("int".into())]),
SExpr::Atom("y".into()),
SExpr::List(vec![SExpr::Atom("float".into())]),
]);
let result = Row::from_sexp(&s, &mut ()).unwrap();
assert!(matches!(result, Row::Closed(_)));
if let Row::Closed(fields) = result {
assert_eq!(fields.len(), 2);
assert_eq!(fields[0].0, "x");
assert_eq!(fields[0].1, Type::Int);
}
}
#[test]
fn row_roundtrip_open() {
roundtrip::<Row>(expect!["(open (typ_id 2))"]);
}
#[test]
fn row_roundtrip_closed() {
roundtrip::<Row>(expect!["(closed a (int) b (float))"]);
}
#[test]
fn to_sexpr_type_unit() {
let ty = Type::Unit;
let s = ty.to_sexpr(&());
let output = s.to_string();
expect!["(unit)"].assert_eq(&output);
}
#[test]
fn to_sexpr_type_int() {
let ty = Type::Int;
let s = ty.to_sexpr(&());
let output = s.to_string();
expect!["(int)"].assert_eq(&output);
}
#[test]
fn to_sexpr_type_var() {
let ty = Type::Var(TypeVar(1));
let s = ty.to_sexpr(&());
let output = s.to_string();
expect!["(typ_id 1)"].assert_eq(&output);
}
#[test]
fn to_sexpr_type_abs() {
let ty = Type::Abs(Box::new(Type::Int), Box::new(Type::Float));
let s = ty.to_sexpr(&());
let output = s.to_string();
expect!["(fn (int) (float))"].assert_eq(&output);
}
#[test]
fn to_sexpr_type_ty_abs() {
let ty = Type::TypAbs(Kind::Type, Box::new(Type::Var(TypeVar(0))));
let s = ty.to_sexpr(&());
let output = s.to_string();
expect!["(typ_abs (type) (typ_id 0))"].assert_eq(&output);
}
#[test]
fn to_sexpr_type_prod() {
let ty = Type::Prod(Row::Closed(vec![("x".into(), Type::Int)]));
let s = ty.to_sexpr(&());
let output = s.to_string();
expect!["(prd (closed x (int)))"].assert_eq(&output);
}
#[test]
fn to_sexpr_type_sum() {
let ty = Type::Sum(Row::Closed(vec![("a".into(), Type::Int)]));
let s = ty.to_sexpr(&());
let output = s.to_string();
expect!["(sum (closed a (int)))"].assert_eq(&output);
}
#[test]
fn from_sexp_type_unit() {
let s = SExpr::List(vec![SExpr::Atom("unit".into())]);
let result = Type::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result, Type::Unit);
}
#[test]
fn from_sexp_type_abs() {
let s = SExpr::List(vec![
SExpr::Atom("fn".into()),
SExpr::List(vec![SExpr::Atom("int".into())]),
SExpr::List(vec![SExpr::Atom("float".into())]),
]);
let result = Type::from_sexp(&s, &mut ()).unwrap();
assert_eq!(
result,
Type::Abs(Box::new(Type::Int), Box::new(Type::Float))
);
}
#[test]
fn type_roundtrip_unit() {
roundtrip::<Type>(expect!["(unit)"]);
}
#[test]
fn type_roundtrip_abs() {
roundtrip::<Type>(expect!["(fn (int) (float))"]);
}
#[test]
fn to_sexpr_tyapp_ty() {
let ty_app = TypApp::Ty(Type::Int);
let s = ty_app.to_sexpr(&());
let output = s.to_string();
expect!["(ty (int))"].assert_eq(&output);
}
#[test]
fn to_sexpr_tyapp_row() {
let ty_app = TypApp::Row(Row::Open(TypeVar(0)));
let s = ty_app.to_sexpr(&());
let output = s.to_string();
expect!["(row (open (typ_id 0)))"].assert_eq(&output);
}
#[test]
fn tyapp_roundtrip() {
roundtrip::<TypApp>(expect!["(ty (float))"]);
}
#[test]
fn to_sexpr_expr_unit() {
let expr = Expr::Unit;
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(unit)"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_int() {
let expr = Expr::Integer(42);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(i 42)"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_float() {
let expr = Expr::Float(3.14);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(f 3.14)"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_string() {
let expr = Expr::String("hello".into());
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(s hello)"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_var() {
let expr = Expr::Variable(Var {
id: VarId(0),
typ: Type::Int,
});
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(var (var_id 0) (int))"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_abs() {
let expr = Expr::Abstraction(
Var {
id: VarId(0),
typ: Type::Int,
},
Box::new(Expr::Variable(Var {
id: VarId(0),
typ: Type::Int,
})),
);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(abs (var (var_id 0) (int)) (var (var_id 0) (int)))"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_app() {
let expr = Expr::Application(
Box::new(Expr::Variable(Var {
id: VarId(0),
typ: Type::Int,
})),
Box::new(Expr::Integer(42)),
);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(app (var (var_id 0) (int)) (i 42))"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_ty_abs() {
let expr = Expr::TypAbs(
Kind::Type,
Box::new(Expr::Variable(Var {
id: VarId(0),
typ: Type::Int,
})),
);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(typ_abs (type) (var (var_id 0) (int)))"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_ty_app() {
let expr = Expr::TypApp(
Box::new(Expr::Variable(Var {
id: VarId(0),
typ: Type::Int,
})),
TypApp::Ty(Type::Int),
);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(ty_app (var (var_id 0) (int)) (ty (int)))"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_local() {
let expr = Expr::Local(
Var {
id: VarId(0),
typ: Type::Int,
},
Box::new(Expr::Integer(42)),
Box::new(Expr::Variable(Var {
id: VarId(0),
typ: Type::Int,
})),
);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(let (var (var_id 0) (int)) (i 42) (var (var_id 0) (int)))"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_tuple() {
let expr = Expr::Tuple(vec![
("x".into(), Expr::Integer(1)),
("y".into(), Expr::Float(2.0)),
]);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(tuple x (i 1) y (f 2.0))"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_field() {
let expr = Expr::Field(
Box::new(Expr::Variable(Var {
id: VarId(0),
typ: Type::Int,
})),
0,
);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(field (var (var_id 0) (int)) 0)"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_tag() {
let expr = Expr::Tag(Type::Int, 0, Box::new(Expr::Integer(1)));
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(tag (int) 0 (i 1))"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_item() {
let expr = Expr::Item(
Type::Int,
ItemId(0),
Symbol {
module: "std".into(),
field: "add".into(),
},
);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(item (itm_id 0) (symbol std add) (int))"].assert_eq(&output);
}
#[test]
fn from_sexp_expr_unit() {
let s = SExpr::List(vec![SExpr::Atom("unit".into())]);
let result = Expr::from_sexp(&s, &mut ()).unwrap();
assert!(matches!(result, Expr::Unit));
}
#[test]
fn from_sexp_expr_int() {
let s = SExpr::List(vec![SExpr::Atom("i".into()), SExpr::Atom("42".into())]);
let result = Expr::from_sexp(&s, &mut ()).unwrap();
assert!(matches!(result, Expr::Integer(42)));
}
#[test]
fn from_sexp_expr_app() {
let s = SExpr::List(vec![
SExpr::Atom("app".into()),
SExpr::List(vec![
SExpr::Atom("var".into()),
SExpr::List(vec![SExpr::Atom("id".into()), SExpr::Atom("0".into())]),
]),
SExpr::List(vec![SExpr::Atom("i".into()), SExpr::Atom("1".into())]),
]);
let result = Expr::from_sexp(&s, &mut ()).unwrap();
assert!(matches!(result, Expr::Application(_, _)));
}
#[test]
fn expr_roundtrip_unit() {
roundtrip::<Expr>(expect!["(unit)"]);
}
#[test]
fn expr_roundtrip_int() {
roundtrip::<Expr>(expect!["(i 42)"]);
}
#[test]
fn to_sexpr_native_item() {
let item = NativeItem {
symbol: Symbol {
module: String::new(),
field: "main".into(),
},
expr: Expr::Abstraction(
Var {
id: VarId(0),
typ: Type::Int,
},
Box::new(Expr::Variable(Var {
id: VarId(0),
typ: Type::Int,
})),
),
typ: Type::Int,
};
let s = item.to_sexpr(&());
let output = s.to_string();
expect![[r#"(pub (symbol "" main) (abs (var (var_id 0) (int)) (var (var_id 0) (int))) (int))"#]]
.assert_eq(&output);
}
#[test]
fn from_sexp_native_item() {
let s = SExpr::List(vec![
SExpr::Atom("pub".into()),
SExpr::List(vec![
SExpr::Atom("symbol".into()),
SExpr::Atom("".into()),
SExpr::Atom("main".into()),
]),
SExpr::List(vec![
SExpr::Atom("abs".into()),
SExpr::List(vec![
SExpr::Atom("var".into()),
SExpr::List(vec![SExpr::Atom("id".into()), SExpr::Atom("0".into())]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]),
SExpr::List(vec![
SExpr::Atom("var".into()),
SExpr::List(vec![SExpr::Atom("id".into()), SExpr::Atom("0".into())]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]),
]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]);
let result = NativeItem::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.symbol.field, "main");
}
#[test]
fn to_sexpr_item_native() {
let item = Item::Native(NativeItem {
symbol: Symbol {
module: String::new(),
field: "main".into(),
},
expr: Expr::Abstraction(
Var {
id: VarId(0),
typ: Type::Int,
},
Box::new(Expr::Variable(Var {
id: VarId(0),
typ: Type::Int,
})),
),
typ: Type::Int,
});
let s = item.to_sexpr(&());
let output = s.to_string();
expect![[r#"(pub (symbol "" main) (abs (var (var_id 0) (int)) (var (var_id 0) (int))) (int))"#]]
.assert_eq(&output);
}
#[test]
fn from_sexp_item_native() {
let s = SExpr::List(vec![
SExpr::Atom("pub".into()),
SExpr::List(vec![
SExpr::Atom("symbol".into()),
SExpr::Atom("".into()),
SExpr::Atom("main".into()),
]),
SExpr::List(vec![
SExpr::Atom("abs".into()),
SExpr::List(vec![
SExpr::Atom("var".into()),
SExpr::List(vec![SExpr::Atom("id".into()), SExpr::Atom("0".into())]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]),
SExpr::List(vec![
SExpr::Atom("var".into()),
SExpr::List(vec![SExpr::Atom("id".into()), SExpr::Atom("0".into())]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]),
]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]);
let result = Item::from_sexp(&s, &mut ()).unwrap();
assert!(matches!(result, Item::Native(_)));
}
#[test]
fn to_sexpr_module() {
let mut items = BTreeMap::new();
items.insert(
ItemId(0),
Item::Native(NativeItem {
symbol: Symbol {
module: String::new(),
field: "main".into(),
},
expr: Expr::Abstraction(
Var {
id: VarId(0),
typ: Type::Int,
},
Box::new(Expr::Variable(Var {
id: VarId(0),
typ: Type::Int,
})),
),
typ: Type::Int,
}),
);
let module = Module {
items,
instances: HashMap::new(),
item_supply: ItemSupply::default(),
};
let s = module.to_sexpr(&());
let output = s.to_string();
expect![[r#"
(mod
(pub
(symbol "" main)
(abs (var (var_id 0) (int)) (var (var_id 0) (int)))
(int)))"#]]
.assert_eq(&output);
}
#[test]
fn from_sexp_module() {
let s = SExpr::List(vec![
SExpr::Atom("mod".into()),
SExpr::List(vec![
SExpr::Atom("pub".into()),
SExpr::List(vec![
SExpr::Atom("symbol".into()),
SExpr::Atom("".into()),
SExpr::Atom("main".into()),
]),
SExpr::List(vec![
SExpr::Atom("abs".into()),
SExpr::List(vec![
SExpr::Atom("var".into()),
SExpr::List(vec![SExpr::Atom("id".into()), SExpr::Atom("0".into())]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]),
SExpr::List(vec![
SExpr::Atom("var".into()),
SExpr::List(vec![SExpr::Atom("id".into()), SExpr::Atom("0".into())]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]),
]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]),
]);
let result = Module::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.items.len(), 1);
}
#[test]
fn kind_roundtrip_row() {
roundtrip::<Kind>(expect!["(row)"]);
}
#[test]
fn type_roundtrip_int() {
roundtrip::<Type>(expect!["(int)"]);
}
#[test]
fn type_roundtrip_var() {
roundtrip::<Type>(expect!["(typ_id 5)"]);
}
#[test]
fn type_roundtrip_ty_abs() {
roundtrip::<Type>(expect!["(typ_abs (row) (int))"]);
}
#[test]
fn type_roundtrip_prod() {
roundtrip::<Type>(expect!["(prd (closed x (int)))"]);
}
#[test]
fn type_roundtrip_sum() {
roundtrip::<Type>(expect!["(sum (closed a (int)))"]);
}
#[test]
fn tyapp_roundtrip_row() {
roundtrip::<TypApp>(expect!["(row (open (typ_id 0)))"]);
}
#[test]
fn expr_roundtrip_float() {
roundtrip::<Expr>(expect!["(f 3.14)"]);
}
#[test]
fn expr_roundtrip_string() {
roundtrip::<Expr>(expect!["(s hello)"]);
}
#[test]
fn expr_roundtrip_var() {
roundtrip::<Expr>(expect!["(var (var_id 0) (int))"]);
}
#[test]
fn expr_roundtrip_abs() {
roundtrip::<Expr>(expect!["(abs (var (var_id 0) (int)) (var (var_id 0) (int)))"]);
}
#[test]
fn expr_roundtrip_app() {
roundtrip::<Expr>(expect!["(app (var (var_id 0) (int)) (i 42))"]);
}
#[test]
fn expr_roundtrip_ty_abs() {
roundtrip::<Expr>(expect!["(typ_abs (type) (var (var_id 0) (int)))"]);
}
#[test]
fn expr_roundtrip_ty_app() {
roundtrip::<Expr>(expect!["(ty_app (var (var_id 0) (int)) (ty (int)))"]);
}
#[test]
fn expr_roundtrip_local() {
roundtrip::<Expr>(expect![
"(let (var (var_id 0) (int)) (i 42) (var (var_id 0) (int)))"
]);
}
#[test]
fn expr_roundtrip_tuple() {
roundtrip::<Expr>(expect!["(tuple x (i 1) y (f 2.0))"]);
}
#[test]
fn expr_roundtrip_field() {
roundtrip::<Expr>(expect!["(field (var (var_id 0) (int)) 0)"]);
}
#[test]
fn expr_roundtrip_tag() {
roundtrip::<Expr>(expect!["(tag (int) 0 (i 1))"]);
}
#[test]
fn expr_roundtrip_item() {
roundtrip::<Expr>(expect!["(item (itm_id 0) (symbol std add) (int))"]);
}
#[test]
fn native_item_roundtrip() {
roundtrip::<NativeItem>(expect![[r#"(pub (symbol "" main) (abs (var (var_id 0) (int)) (var (var_id 0) (int))) (int))"#]]);
}
#[test]
fn item_roundtrip_native() {
roundtrip::<Item>(expect![[r#"(pub (symbol "" main) (abs (var (var_id 0) (int)) (var (var_id 0) (int))) (int))"#]]);
}
#[test]
fn module_roundtrip() {
roundtrip::<Module>(expect![[r#"
(mod
(pub
(symbol "" main)
(abs (var (var_id 0) (int)) (var (var_id 0) (int)))
(int)))"#]]);
}
#[test]
fn external_item_roundtrip() {
roundtrip::<ExternalItem>(expect![[
r#"(pub ext (symbol std add) (fn ((x (int)) (y (float))) (string)))"#
]]);
}
}