use crate::compiler::sexpr::{
FromSExpr, ParseError, SExpr, ToSExpr, expect_n, format_box_for, format_sexpr_for,
};
use super::{Expr, ExternalItem, Item, ItemId, LocalItem, Module, RemoteItem, Type, Var, VarId};
use crate::compiler::mantle::Symbol;
use crate::external_type::{ExternalType, FunctionType};
use std::collections::BTreeMap;
impl ToSExpr<()> for ItemId {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("id".into()),
SExpr::Atom(self.0.to_string()),
])
}
}
impl ToSExpr<()> for VarId {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("id".into()),
SExpr::Atom(self.0.to_string()),
])
}
}
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::Closure(arg, ret) => SExpr::List(vec![
SExpr::Atom("closure".into()),
arg.to_sexpr(&()),
ret.to_sexpr(&()),
]),
Type::Abstraction(params, ret) => {
let mut elements = vec![SExpr::Atom("abs".into())];
for param in params {
elements.push(param.to_sexpr(&()));
}
elements.push(ret.to_sexpr(&()));
SExpr::List(elements)
}
Type::Tuple(fields, labels) => {
let mut elements = vec![SExpr::Atom("tup".into())];
for field in fields {
elements.push(field.to_sexpr(&()));
}
if let Some(labels) = labels {
for label in labels {
elements.push(SExpr::Atom(label.clone()));
}
}
SExpr::List(elements)
}
Type::Variant(cases, labels) => {
let mut elements = vec![SExpr::Atom("variant".into())];
for case in cases {
elements.push(case.to_sexpr(&()));
}
if let Some(labels) = labels {
for label in labels {
elements.push(SExpr::Atom(label.clone()));
}
}
SExpr::List(elements)
}
}
}
}
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 Expr {
fn to_sexpr(&self, _config: &()) -> SExpr {
match self {
Expr::Unit => SExpr::List(vec![SExpr::Atom("unit".into())]),
Expr::Int(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::Var(v) => v.to_sexpr(&()),
Expr::Closure(ty, item_id, vars) => {
let mut elements = vec![
SExpr::Atom("closure".into()),
ty.to_sexpr(&()),
item_id.to_sexpr(&()),
];
for var in vars {
elements.push(var.to_sexpr(&()));
}
SExpr::List(elements)
}
Expr::AppClosure(fn_expr, arg) => SExpr::List(vec![
SExpr::Atom("app_closure".into()),
fn_expr.to_sexpr(&()),
arg.to_sexpr(&()),
]),
Expr::AppExternal(ty, fn_type, item_id, args) => {
let mut elements = vec![
SExpr::Atom("app_external".into()),
ty.to_sexpr(&()),
fn_type.to_sexpr(&()),
item_id.to_sexpr(&()),
];
for arg in args {
elements.push(arg.to_sexpr(&()));
}
SExpr::List(elements)
}
Expr::Local(var, init, body) => SExpr::List(vec![
SExpr::Atom("let".into()),
var.to_sexpr(&()),
init.to_sexpr(&()),
body.to_sexpr(&()),
]),
Expr::Access(tuple, index) => SExpr::List(vec![
SExpr::Atom("acc".into()),
tuple.to_sexpr(&()),
SExpr::Atom(index.to_string()),
]),
Expr::Tuple(fields, labels) => {
let mut elements = vec![SExpr::Atom("tup".into())];
for field in fields {
elements.push(field.to_sexpr(&()));
}
for label in labels {
elements.push(SExpr::Atom(label.clone()));
}
SExpr::List(elements)
}
Expr::Tag(typ, index, body) => SExpr::List(vec![
SExpr::Atom("tag".into()),
typ.to_sexpr(&()),
SExpr::Atom(index.to_string()),
body.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(branch.to_sexpr(&()));
}
SExpr::List(elements)
}
}
}
}
impl ToSExpr<()> for LocalItem {
fn to_sexpr(&self, _config: &()) -> SExpr {
let mut elements = vec![SExpr::Atom("local".into()), SExpr::Atom(self.name.clone())];
for param in &self.params {
elements.push(param.to_sexpr(&()));
}
elements.push(self.ret_typ.to_sexpr(&()));
elements.push(self.body.to_sexpr(&()));
SExpr::List(elements)
}
}
impl ToSExpr<()> for RemoteItem {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("remote".into()),
self.symbol.to_sexpr(&()),
self.param_typ.to_sexpr(&()),
self.ret_typ.to_sexpr(&()),
])
}
}
impl ToSExpr<()> for ExternalItem {
fn to_sexpr(&self, _config: &()) -> SExpr {
let mut elements = vec![SExpr::Atom("external".into()), self.symbol.to_sexpr(&())];
let param_elements: Vec<SExpr> = self.param_typs.iter().map(|t| t.to_sexpr(&())).collect();
if !param_elements.is_empty() {
elements.push(SExpr::List(
std::iter::once(SExpr::Atom("params".into()))
.chain(param_elements)
.collect(),
));
}
let ret_elements: Vec<SExpr> = self.ret_typs.iter().map(|t| t.to_sexpr(&())).collect();
if !ret_elements.is_empty() {
elements.push(SExpr::List(
std::iter::once(SExpr::Atom("returns".into()))
.chain(ret_elements)
.collect(),
));
}
elements.push(SExpr::List(vec![
SExpr::Atom("external_typ".into()),
self.external_typ.to_sexpr(&()),
]));
SExpr::List(elements)
}
}
impl ToSExpr<()> for Item {
fn to_sexpr(&self, _config: &()) -> SExpr {
match self {
Item::Local(item) => item.to_sexpr(&()),
Item::Remote(item) => item.to_sexpr(&()),
Item::External(item) => item.to_sexpr(&()),
}
}
}
impl ToSExpr<()> for Module {
fn to_sexpr(&self, _config: &()) -> SExpr {
let mut elements = vec![SExpr::Atom("mod".into())];
for item in self.closure_items.values() {
elements.push(item.to_sexpr(&()));
}
SExpr::List(elements)
}
}
impl std::fmt::Debug for ItemId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for ItemId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for VarId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for VarId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for Var {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for Var {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for LocalItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for LocalItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for RemoteItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for RemoteItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for ExternalItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for ExternalItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for Item {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for Item {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for Module {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for Module {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl FromSExpr<()> for ItemId {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let args: &[SExpr; 1] = expect_n("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: "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("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: "id value",
found: args[0].tag().map(|s| s.to_string()),
});
}
};
Ok(VarId(n))
}
}
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("closure") => {
let args: &[SExpr; 2] = expect_n("closure", s.args())?;
let arg = Type::from_sexp(&args[0], _ctx)?;
let ret = Type::from_sexp(&args[1], _ctx)?;
Ok(Type::Closure(Box::new(arg), Box::new(ret)))
}
Some("abs") => {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "abs",
found: None,
})?;
if args.is_empty() {
return Err(ParseError::ExpectedArgs {
expected: 2,
found: 0,
});
}
let ret = Type::from_sexp(&args[args.len() - 1], _ctx)?;
let params: Vec<Type> = args[..args.len() - 1]
.iter()
.map(|arg| Type::from_sexp(arg, _ctx))
.collect::<Result<Vec<_>, _>>()?;
Ok(Type::Abstraction(params, Box::new(ret)))
}
Some("tup") => {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "tup",
found: None,
})?;
if args.is_empty() {
return Err(ParseError::ExpectedArgs {
expected: 1,
found: 0,
});
}
let mut fields = Vec::new();
let mut labels = Vec::new();
let mut i = 0;
while i < args.len() {
let arg = &args[i];
if matches!(
arg.tag(),
Some("unit")
| Some("int")
| Some("float")
| Some("string")
| Some("dataframe")
| Some("closure")
| Some("abs")
| Some("tup")
) {
fields.push(Type::from_sexp(arg, _ctx)?);
i += 1;
} else {
break;
}
}
while i < args.len() {
let label = match &args[i] {
SExpr::Atom(s) => s.clone(),
_ => {
return Err(ParseError::ExpectedTag {
expected: "label",
found: args[i].tag().map(|s| s.to_string()),
});
}
};
labels.push(label);
i += 1;
}
Ok(Type::Tuple(
fields,
if labels.is_empty() {
None
} else {
Some(labels)
},
))
}
_ => Err(ParseError::ExpectedTag {
expected: "type tag",
found: s.tag().map(|s| s.to_string()),
}),
}
}
}
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,
})?;
if args.len() < 2 {
return Err(ParseError::ExpectedArgs {
expected: 2,
found: args.len(),
});
}
let id = VarId::from_sexp(&args[0], ctx)?;
let typ = Type::from_sexp(&args[1], ctx)?;
Ok(Var { id, typ })
}
}
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::Int(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::Var),
Some("closure") => {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "closure",
found: None,
})?;
if args.len() < 3 {
return Err(ParseError::ExpectedArgs {
expected: 3,
found: args.len(),
});
}
let ty = Type::from_sexp(&args[0], ctx)?;
let item_id = ItemId::from_sexp(&args[1], ctx)?;
let vars: Vec<Var> = args[2..]
.iter()
.map(|arg| Var::from_sexp(arg, ctx))
.collect::<Result<Vec<_>, _>>()?;
Ok(Expr::Closure(ty, item_id, vars))
}
Some("app_closure") => {
let args: &[SExpr; 2] = expect_n("app_closure", s.args())?;
let fn_expr = Expr::from_sexp(&args[0], ctx)?;
let arg = Expr::from_sexp(&args[1], ctx)?;
Ok(Expr::AppClosure(Box::new(fn_expr), Box::new(arg)))
}
Some("app_external") => {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "app_external",
found: None,
})?;
if args.len() < 4 {
return Err(ParseError::ExpectedArgs {
expected: 4,
found: args.len(),
});
}
let ty = Type::from_sexp(&args[0], ctx)?;
let fn_type = FunctionType::from_sexp(&args[1], ctx)?;
let item_id = ItemId::from_sexp(&args[2], ctx)?;
let args: Vec<Expr> = args[3..]
.iter()
.map(|arg| Expr::from_sexp(arg, ctx))
.collect::<Result<Vec<_>, _>>()?;
Ok(Expr::AppExternal(ty, fn_type, item_id, args))
}
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("acc") => {
let args: &[SExpr; 2] = expect_n("acc", s.args())?;
let tuple = 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::Access(Box::new(tuple), index))
}
Some("tup") => {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "tup",
found: None,
})?;
if args.is_empty() {
return Err(ParseError::ExpectedArgs {
expected: 1,
found: 0,
});
}
let mut fields = Vec::new();
let mut labels = Vec::new();
let mut i = 0;
while i < args.len() {
let arg = &args[i];
if matches!(arg, SExpr::List(_)) {
fields.push(Expr::from_sexp(arg, ctx)?);
i += 1;
} else {
break;
}
}
while i < args.len() {
let label = match &args[i] {
SExpr::Atom(s) => s.clone(),
_ => {
return Err(ParseError::ExpectedTag {
expected: "label",
found: args[i].tag().map(|s| s.to_string()),
});
}
};
labels.push(label);
i += 1;
}
Ok(Expr::Tuple(fields, labels))
}
_ => Err(ParseError::ExpectedTag {
expected: "expr tag",
found: s.tag().map(|s| s.to_string()),
}),
}
}
}
impl FromSExpr<()> for LocalItem {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "local",
found: None,
})?;
if args.len() < 3 {
return Err(ParseError::ExpectedArgs {
expected: 3,
found: args.len(),
});
}
let name = match &args[0] {
SExpr::Atom(s) => s.clone(),
_ => {
return Err(ParseError::ExpectedTag {
expected: "name",
found: args[0].tag().map(|s| s.to_string()),
});
}
};
let mut params = Vec::new();
let mut i = 1;
while i < args.len() - 1 {
match args[i].tag() {
Some("unit") | Some("int") | Some("float") | Some("string") | Some("dataframe")
| Some("closure") | Some("abs") | Some("tup") => {
break;
}
_ => {
params.push(Var::from_sexp(&args[i], ctx)?);
i += 1;
}
}
}
let ret_typ = Type::from_sexp(&args[i], ctx)?;
let body = Expr::from_sexp(&args[i + 1], ctx)?;
Ok(LocalItem {
name,
params,
ret_typ,
body,
})
}
}
impl FromSExpr<()> for RemoteItem {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
let args: &[SExpr; 3] = expect_n("remote", s.args())?;
let symbol = Symbol::from_sexp(&args[0], ctx)?;
let param_typ = Type::from_sexp(&args[1], ctx)?;
let ret_typ = Type::from_sexp(&args[2], ctx)?;
Ok(RemoteItem {
symbol,
param_typ,
ret_typ,
})
}
}
impl FromSExpr<()> for ExternalItem {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "external",
found: None,
})?;
if args.len() < 2 {
return Err(ParseError::ExpectedArgs {
expected: 2,
found: args.len(),
});
}
let symbol = Symbol::from_sexp(&args[0], ctx)?;
let mut param_typs = Vec::new();
let mut ret_typs = Vec::new();
let mut external_typ = None;
for arg in &args[1..] {
match arg.tag() {
Some("params") => {
let inner = arg.args().ok_or(ParseError::ExpectedTag {
expected: "params",
found: None,
})?;
for inner_arg in inner {
param_typs.push(Type::from_sexp(inner_arg, ctx)?);
}
}
Some("returns") => {
let inner = arg.args().ok_or(ParseError::ExpectedTag {
expected: "returns",
found: None,
})?;
for inner_arg in inner {
ret_typs.push(Type::from_sexp(inner_arg, ctx)?);
}
}
Some("external_typ") => {
let inner = arg.args().ok_or(ParseError::ExpectedTag {
expected: "external_typ",
found: None,
})?;
if let Some(fn_expr) = inner.first() {
external_typ = Some(FunctionType::from_sexp(fn_expr, ctx)?);
}
}
_ => {
param_typs.push(Type::from_sexp(arg, ctx)?);
}
}
}
let external_typ = external_typ.ok_or(ParseError::ExpectedTag {
expected: "fn",
found: None,
})?;
if ret_typs.is_empty() {
let ret_typ = convert_external_type_to_core(&external_typ.ret);
ret_typs = vec![ret_typ];
}
Ok(ExternalItem {
symbol,
param_typs,
ret_typs,
external_typ,
})
}
}
fn convert_external_type_to_core(typ: &ExternalType) -> Type {
match typ {
ExternalType::Unit => Type::Unit,
ExternalType::Int => Type::Int,
ExternalType::Float => Type::Float,
ExternalType::String => Type::String,
ExternalType::Resource(_) => Type::DataFrame,
ExternalType::Fun(FunctionType {
parameter_names: _,
parameter_typs,
ret,
}) => Type::abs(
parameter_typs.iter().map(convert_external_type_to_core),
convert_external_type_to_core(ret),
),
ExternalType::Record(_, fields) => {
Type::labeled_tuple(fields.iter().map(|(label, field_typ)| {
(label.clone(), convert_external_type_to_core(field_typ))
}))
}
}
}
impl FromSExpr<()> for Item {
fn from_sexp(s: &SExpr, ctx: &mut ()) -> Result<Self, ParseError> {
match s.tag() {
Some("local") => LocalItem::from_sexp(s, ctx).map(Item::Local),
Some("remote") => RemoteItem::from_sexp(s, ctx).map(Item::Remote),
Some("external") => ExternalItem::from_sexp(s, ctx).map(Item::External),
_ => Err(ParseError::ExpectedTag {
expected: "local, remote, or external",
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::Local(local) => {
let hash = local.name.len();
ItemId(hash as u32)
}
Item::Remote(remote) => {
let hash = remote.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 {
closure_items: items,
})
}
}
#[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!["(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!["(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!["(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!["(id 99)"]);
}
#[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_closure() {
let ty = Type::Closure(Box::new(Type::Int), Box::new(Type::Float));
let s = ty.to_sexpr(&());
let output = s.to_string();
expect!["(closure (int) (float))"].assert_eq(&output);
}
#[test]
fn to_sexpr_type_abstraction() {
let ty = Type::Abstraction(vec![Type::Int, Type::Float], Box::new(Type::String));
let s = ty.to_sexpr(&());
let output = s.to_string();
expect!["(abs (int) (float) (string))"].assert_eq(&output);
}
#[test]
fn to_sexpr_type_tuple() {
let ty = Type::Tuple(
vec![Type::Int, Type::Float],
Some(vec!["x".into(), "y".into()]),
);
let s = ty.to_sexpr(&());
let output = s.to_string();
expect!["(tup (int) (float) x y)"].assert_eq(&output);
}
#[test]
fn to_sexpr_type_tuple_no_labels() {
let ty = Type::Tuple(vec![Type::Int, Type::String], None);
let s = ty.to_sexpr(&());
let output = s.to_string();
expect!["(tup (int) (string))"].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_closure() {
let s = SExpr::List(vec![
SExpr::Atom("closure".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::Closure(Box::new(Type::Int), Box::new(Type::Float))
);
}
#[test]
fn type_roundtrip_unit() {
roundtrip::<Type>(expect!["(unit)"]);
}
#[test]
fn type_roundtrip_closure() {
roundtrip::<Type>(expect!["(closure (int) (float))"]);
}
#[test]
fn type_roundtrip_tuple() {
roundtrip::<Type>(expect!["(tup (int) (float) x y)"]);
}
#[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 (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 (id 3) (int))"]);
}
#[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::Int(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_float_whole() {
let expr = Expr::Float(5.0);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(f 5.0)"].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::Var(Var {
id: VarId(0),
typ: Type::Int,
});
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(var (id 0) (int))"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_closure() {
let expr = Expr::Closure(
Type::Closure(Box::new(Type::Int), Box::new(Type::Float)),
ItemId(0),
vec![Var {
id: VarId(1),
typ: Type::Int,
}],
);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(closure (closure (int) (float)) (id 0) (var (id 1) (int)))"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_app_closure() {
let expr = Expr::AppClosure(
Box::new(Expr::Var(Var {
id: VarId(0),
typ: Type::Int,
})),
Box::new(Expr::Int(42)),
);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(app_closure (var (id 0) (int)) (i 42))"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_local() {
let expr = Expr::Local(
Var {
id: VarId(0),
typ: Type::Int,
},
Box::new(Expr::Int(42)),
Box::new(Expr::Var(Var {
id: VarId(0),
typ: Type::Int,
})),
);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(let (var (id 0) (int)) (i 42) (var (id 0) (int)))"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_access() {
let expr = Expr::Access(
Box::new(Expr::Var(Var {
id: VarId(0),
typ: Type::Int,
})),
2,
);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(acc (var (id 0) (int)) 2)"].assert_eq(&output);
}
#[test]
fn to_sexpr_expr_tuple() {
let expr = Expr::Tuple(
vec![Expr::Int(1), Expr::Float(2.0)],
vec!["x".into(), "y".into()],
);
let s = expr.to_sexpr(&());
let output = s.to_string();
expect!["(tup (i 1) (f 2.0) x y)"].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::Int(42)));
}
#[test]
fn from_sexp_expr_app_closure() {
let s = SExpr::List(vec![
SExpr::Atom("app_closure".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("i".into()), SExpr::Atom("1".into())]),
]);
let result = Expr::from_sexp(&s, &mut ()).unwrap();
assert!(matches!(result, Expr::AppClosure(_, _)));
}
#[test]
fn expr_roundtrip_unit() {
roundtrip::<Expr>(expect!["(unit)"]);
}
#[test]
fn expr_roundtrip_int() {
roundtrip::<Expr>(expect!["(i 42)"]);
}
#[test]
fn expr_roundtrip_local() {
roundtrip::<Expr>(expect![
"(let (var (id 0) (int)) (i 42) (var (id 0) (int)))"
]);
}
#[test]
fn to_sexpr_local_item() {
let item = LocalItem {
name: "main".into(),
params: vec![Var {
id: VarId(0),
typ: Type::Int,
}],
ret_typ: Type::Float,
body: Expr::Var(Var {
id: VarId(0),
typ: Type::Int,
}),
};
let s = item.to_sexpr(&());
let output = s.to_string();
expect![[r#"(local main (var (id 0) (int)) (float) (var (id 0) (int)))"#]]
.assert_eq(&output);
}
#[test]
fn from_sexp_local_item() {
let s = SExpr::List(vec![
SExpr::Atom("local".into()),
SExpr::Atom("main".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("float".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())]),
]),
]);
let result = LocalItem::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.name, "main");
assert_eq!(result.params.len(), 1);
assert_eq!(result.ret_typ, Type::Float);
}
#[test]
fn local_item_roundtrip() {
roundtrip::<LocalItem>(expect![[
r#"(local add (var (id 0) (int)) (var (id 1) (int)) (int) (unit))"#
]]);
}
#[test]
fn to_sexpr_remote_item() {
let item = RemoteItem {
symbol: Symbol {
module: "std".into(),
field: "println".into(),
},
param_typ: Type::String,
ret_typ: Type::Unit,
};
let s = item.to_sexpr(&());
let output = s.to_string();
expect![[r#"(remote (symbol std println) (string) (unit))"#]].assert_eq(&output);
}
#[test]
fn from_sexp_remote_item() {
let s = SExpr::List(vec![
SExpr::Atom("remote".into()),
SExpr::List(vec![
SExpr::Atom("symbol".into()),
SExpr::Atom("std".into()),
SExpr::Atom("println".into()),
]),
SExpr::List(vec![SExpr::Atom("string".into())]),
SExpr::List(vec![SExpr::Atom("unit".into())]),
]);
let result = RemoteItem::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.symbol.field, "println");
assert_eq!(result.param_typ, Type::String);
assert_eq!(result.ret_typ, Type::Unit);
}
#[test]
fn remote_item_roundtrip() {
roundtrip::<RemoteItem>(expect!["(remote (symbol net connect) (string) (int))"]);
}
#[test]
fn to_sexpr_external_item() {
let item = ExternalItem {
symbol: Symbol {
module: "wasi".into(),
field: "clock_time_get".into(),
},
param_typs: vec![Type::Int],
ret_typs: vec![Type::Int],
external_typ: FunctionType {
parameter_names: vec!["clock_id".into()],
parameter_typs: vec![ExternalType::Int],
ret: Box::new(ExternalType::Int),
},
};
let s = item.to_sexpr(&());
let output = s.to_string();
expect![[r#"
(external
(symbol wasi clock_time_get)
(params (int))
(returns (int))
(external_typ (fn ((clock_id (int))) (int))))"#]]
.assert_eq(&output);
}
#[test]
fn from_sexp_external_item() {
let s = SExpr::List(vec![
SExpr::Atom("external".into()),
SExpr::List(vec![
SExpr::Atom("symbol".into()),
SExpr::Atom("wasi".into()),
SExpr::Atom("clock_time_get".into()),
]),
SExpr::List(vec![
SExpr::Atom("params".into()),
SExpr::List(vec![SExpr::Atom("int".into())]),
]),
SExpr::List(vec![
SExpr::Atom("returns".into()),
SExpr::List(vec![SExpr::Atom("int".into())]),
]),
SExpr::List(vec![
SExpr::Atom("external_typ".into()),
SExpr::List(vec![
SExpr::Atom("fn".into()),
SExpr::List(vec![]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]),
]),
]);
let result = ExternalItem::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.symbol.field, "clock_time_get");
assert_eq!(result.param_typs.len(), 1);
assert_eq!(result.ret_typs.len(), 1);
}
#[test]
fn to_sexpr_item_local() {
let item = Item::Local(LocalItem {
name: "main".into(),
params: vec![],
ret_typ: Type::Unit,
body: Expr::Unit,
});
let s = item.to_sexpr(&());
let output = s.to_string();
expect!["(local main (unit) (unit))"].assert_eq(&output);
}
#[test]
fn to_sexpr_item_remote() {
let item = Item::Remote(RemoteItem {
symbol: Symbol {
module: "std".into(),
field: "log".into(),
},
param_typ: Type::Int,
ret_typ: Type::Unit,
});
let s = item.to_sexpr(&());
let output = s.to_string();
expect!["(remote (symbol std log) (int) (unit))"].assert_eq(&output);
}
#[test]
fn from_sexp_item_local() {
let s = SExpr::List(vec![
SExpr::Atom("local".into()),
SExpr::Atom("main".into()),
SExpr::List(vec![SExpr::Atom("unit".into())]),
SExpr::List(vec![SExpr::Atom("unit".into())]),
]);
let result = Item::from_sexp(&s, &mut ()).unwrap();
assert!(matches!(result, Item::Local(_)));
}
#[test]
fn from_sexp_item_remote() {
let s = SExpr::List(vec![
SExpr::Atom("remote".into()),
SExpr::List(vec![
SExpr::Atom("symbol".into()),
SExpr::Atom("std".into()),
SExpr::Atom("log".into()),
]),
SExpr::List(vec![SExpr::Atom("int".into())]),
SExpr::List(vec![SExpr::Atom("unit".into())]),
]);
let result = Item::from_sexp(&s, &mut ()).unwrap();
assert!(matches!(result, Item::Remote(_)));
}
#[test]
fn to_sexpr_module() {
let mut items = BTreeMap::new();
items.insert(
ItemId(0),
Item::Local(LocalItem {
name: "main".into(),
params: vec![],
ret_typ: Type::Unit,
body: Expr::Unit,
}),
);
let module = Module {
closure_items: items,
};
let s = module.to_sexpr(&());
let output = s.to_string();
expect!["(mod (local main (unit) (unit)))"].assert_eq(&output);
}
#[test]
fn from_sexp_module() {
let s = SExpr::List(vec![
SExpr::Atom("mod".into()),
SExpr::List(vec![
SExpr::Atom("local".into()),
SExpr::Atom("main".into()),
SExpr::List(vec![SExpr::Atom("unit".into())]),
SExpr::List(vec![SExpr::Atom("unit".into())]),
]),
]);
let result = Module::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.closure_items.len(), 1);
}
#[test]
fn module_roundtrip() {
roundtrip::<Module>(expect![
"(mod (local add (var (id 0) (int)) (var (id 1) (int)) (int) (unit)))"
]);
}
#[test]
fn type_roundtrip_int() {
roundtrip::<Type>(expect!["(int)"]);
}
#[test]
fn type_roundtrip_float() {
roundtrip::<Type>(expect!["(float)"]);
}
#[test]
fn type_roundtrip_string() {
roundtrip::<Type>(expect!["(string)"]);
}
#[test]
fn type_roundtrip_dataframe() {
roundtrip::<Type>(expect!["(dataframe)"]);
}
#[test]
fn type_roundtrip_abstraction() {
roundtrip::<Type>(expect!["(abs (int) (float) (string))"]);
}
#[test]
fn type_roundtrip_tuple_no_labels() {
roundtrip::<Type>(expect!["(tup (int) (string))"]);
}
#[test]
fn expr_roundtrip_float() {
roundtrip::<Expr>(expect!["(f 3.14)"]);
}
#[test]
fn expr_roundtrip_float_whole() {
roundtrip::<Expr>(expect!["(f 5.0)"]);
}
#[test]
fn expr_roundtrip_string() {
roundtrip::<Expr>(expect!["(s hello)"]);
}
#[test]
fn expr_roundtrip_var() {
roundtrip::<Expr>(expect!["(var (id 0) (int))"]);
}
#[test]
fn expr_roundtrip_closure() {
roundtrip::<Expr>(expect![
"(closure (closure (int) (float)) (id 0) (var (id 1) (int)))"
]);
}
#[test]
fn expr_roundtrip_app_closure() {
roundtrip::<Expr>(expect!["(app_closure (var (id 0) (int)) (i 42))"]);
}
#[test]
fn expr_roundtrip_access() {
roundtrip::<Expr>(expect!["(acc (var (id 0) (int)) 2)"]);
}
#[test]
fn item_roundtrip_local() {
roundtrip::<Item>(expect!["(local main (unit) (unit))"]);
}
#[test]
fn item_roundtrip_remote() {
roundtrip::<Item>(expect!["(remote (symbol std log) (int) (unit))"]);
}
#[test]
fn expr_roundtrip_tuple() {
roundtrip::<Expr>(expect!["(tup (i 1) (f 2.0) x y)"]);
}
#[test]
fn expr_roundtrip_app_external() {
roundtrip::<Expr>(expect![
"(app_external (int) (fn ((x (int))) (int)) (id 0) (i 1) (i 2))"
]);
}
#[test]
fn external_item_roundtrip() {
roundtrip::<ExternalItem>(expect![
r#"(external (symbol std add) (returns (int)) (external_typ (fn () (int))))"#
]);
}
#[test]
fn external_item_roundtrip_with_params_returns() {
roundtrip::<ExternalItem>(expect![[r#"
(external
(symbol std add)
(params (int))
(returns (float))
(external_typ (fn () (int))))"#]]);
}
}