use std::str::FromStr;
use super::*;
use crate::compiler::sexpr::{
FromSExpr, ParseError, SExpr, ToSExpr, expect_n, format_box_for, format_sexpr_for,
};
use ryu::Buffer;
impl ToSExpr<()> for Module {
fn to_sexpr(&self, _config: &()) -> SExpr {
let mut elements: Vec<SExpr> = self.imports.iter().map(|imp| imp.to_sexpr(&())).collect();
for item in &self.items {
elements.push(item.to_sexpr(&()));
}
let mut all = vec![SExpr::Atom("module".into())];
all.extend(elements);
SExpr::List(all)
}
}
impl ToSExpr<()> for Import {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("import".into()),
SExpr::Atom(self.path.clone()),
])
}
}
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 NativeItem {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("native".into()),
self.symbol.to_sexpr(&()),
self.function.to_sexpr(&()),
self.typ.to_sexpr(&()),
])
}
}
impl ToSExpr<()> for ExternalItem {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::List(vec![
SExpr::Atom("external".into()),
self.symbol.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::Integer(n) => {
SExpr::List(vec![SExpr::Atom("int".into()), SExpr::Atom(n.to_string())])
}
Expr::Float(f) => SExpr::List(vec![
SExpr::Atom("float".into()),
SExpr::Atom(Buffer::new().format(*f).to_string()),
]),
Expr::Variable(name) => {
SExpr::List(vec![SExpr::Atom("var".into()), SExpr::Atom(name.clone())])
}
Expr::String(s) => SExpr::List(vec![SExpr::Atom("str".into()), SExpr::Atom(s.clone())]),
Expr::Let {
pattern,
init,
body,
} => SExpr::List(vec![
SExpr::Atom("let".into()),
match pattern {
Pattern::Identifier(name) => SExpr::Atom(name.clone()),
Pattern::Variant(label, inner) => SExpr::List(vec![
SExpr::Atom("variant".into()),
SExpr::Atom(format!("`{}`", label)),
inner.to_sexpr(&()),
]),
},
init.to_sexpr(&()),
body.to_sexpr(&()),
]),
Expr::Function(func) => func.to_sexpr(&()),
Expr::Binary { left, op, right } => SExpr::List(vec![
SExpr::Atom("bin".into()),
left.to_sexpr(&()),
SExpr::Atom(op.to_string()),
right.to_sexpr(&()),
]),
Expr::Forward { parameter, call } => SExpr::List(vec![
SExpr::Atom("forward".into()),
parameter.to_sexpr(&()),
call.to_sexpr(&()),
]),
Expr::Application {
function,
parameters,
} => {
let mut elements = vec![SExpr::Atom("app".into()), function.to_sexpr(&())];
elements.extend(parameters.iter().map(|p| p.to_sexpr(&())));
SExpr::List(elements)
}
Expr::RecordSelect { record, label } => SExpr::List(vec![
SExpr::Atom("record-select".into()),
record.to_sexpr(&()),
SExpr::Atom(label.clone()),
]),
Expr::Record { fields } => {
let field_sexprs: Vec<SExpr> = fields
.iter()
.map(|(name, expr)| {
SExpr::List(vec![SExpr::Atom(name.clone()), expr.to_sexpr(&())])
})
.collect();
SExpr::List(vec![
SExpr::Atom("record".into()),
SExpr::List(field_sexprs),
])
}
Expr::Parenthesized(inner) => SExpr::List(vec![
SExpr::Atom("parenthesized".into()),
inner.to_sexpr(&()),
]),
Expr::Item(symbol) => {
let mut elements = vec![SExpr::Atom("item".into())];
elements.extend(symbol.to_sexpr(&()).elements().unwrap().to_vec());
SExpr::List(elements)
}
Expr::Variant(label, inner) => SExpr::List(vec![
SExpr::Atom("variant".into()),
SExpr::Atom(format!("`{}`", label)),
inner.to_sexpr(&()),
]),
Expr::Match(scrutinee, branches) => {
let mut elements = vec![SExpr::Atom("match".into()), scrutinee.to_sexpr(&())];
for (pattern, expr) in branches {
elements.push(SExpr::List(vec![pattern.to_sexpr(&()), expr.to_sexpr(&())]));
}
SExpr::List(elements)
}
}
}
}
impl ToSExpr<()> for Function {
fn to_sexpr(&self, _config: &()) -> SExpr {
let params: Vec<SExpr> = self
.parameters
.iter()
.map(|p| SExpr::Atom(p.clone()))
.collect();
SExpr::List(vec![
SExpr::Atom("function".into()),
SExpr::List(params),
self.body.to_sexpr(&()),
])
}
}
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 std::fmt::Display for BinaryOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BinaryOperator::Addition => write!(f, "+"),
BinaryOperator::Subtraction => write!(f, "-"),
BinaryOperator::Multiplication => write!(f, "*"),
BinaryOperator::Division => write!(f, "/"),
BinaryOperator::Concat => write!(f, ".."),
}
}
}
impl ToSExpr<()> for BinaryOperator {
fn to_sexpr(&self, _config: &()) -> SExpr {
SExpr::Atom(self.to_string())
}
}
impl ToSExpr<()> for Pattern {
fn to_sexpr(&self, _config: &()) -> SExpr {
match self {
Pattern::Identifier(name) => SExpr::Atom(name.clone()),
Pattern::Variant(label, inner) => SExpr::List(vec![
SExpr::Atom("variant".into()),
SExpr::Atom(format!("`{}`", label)),
inner.to_sexpr(&()),
]),
}
}
}
impl ToSExpr<()> for TypeExpr {
fn to_sexpr(&self, _config: &()) -> SExpr {
match self {
TypeExpr::Unit => SExpr::List(vec![SExpr::Atom("unit".into())]),
TypeExpr::Int => SExpr::List(vec![SExpr::Atom("int".into())]),
TypeExpr::Float => SExpr::List(vec![SExpr::Atom("float".into())]),
TypeExpr::String => SExpr::List(vec![SExpr::Atom("string".into())]),
TypeExpr::Var(name) => {
SExpr::List(vec![SExpr::Atom("var".into()), SExpr::Atom(name.clone())])
}
TypeExpr::Fun(ft) => ft.to_sexpr(&()),
TypeExpr::Sum(row) => row.to_sexpr(&()),
TypeExpr::Prod(row) => row.to_sexpr(&()),
TypeExpr::Nominal(name, typ) => SExpr::List(vec![
SExpr::Atom("nominal".into()),
SExpr::Atom(name.clone()),
typ.to_sexpr(&()),
]),
TypeExpr::DataFrame => SExpr::List(vec![SExpr::Atom("dataframe".into())]),
}
}
}
impl ToSExpr<()> for FunctionType {
fn to_sexpr(&self, _config: &()) -> SExpr {
let mut elements: Vec<SExpr> = Vec::new();
for (name, typ) in self.parameter_names.iter().zip(&self.parameter_typs) {
elements.push(SExpr::Atom(name.clone()));
elements.push(typ.to_sexpr(&()));
}
SExpr::List(vec![
SExpr::Atom("type".into()),
SExpr::List(elements),
self.ret.to_sexpr(&()),
])
}
}
impl ToSExpr<()> for Row {
fn to_sexpr(&self, _config: &()) -> SExpr {
let fields: Vec<SExpr> = self
.fields
.iter()
.map(|(label, typ)| {
SExpr::List(vec![SExpr::Atom(format!("`{}`", label)), typ.to_sexpr(&())])
})
.collect();
SExpr::List(vec![SExpr::Atom("row".into()), SExpr::List(fields)])
}
}
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 std::fmt::Debug for Import {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for Import {
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 NativeItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for NativeItem {
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 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 Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for Symbol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for Symbol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for Pattern {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for Pattern {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for TypeExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for TypeExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for FunctionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for FunctionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl std::fmt::Debug for Row {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_sexpr_for(self, &(), f)
}
}
impl std::fmt::Display for Row {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
format_box_for(self, &(), f)
}
}
impl FromSExpr<()> for Module {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "module",
found: None,
})?;
let mut imports = Vec::new();
let mut module_items = Vec::new();
for item in args {
match item.tag() {
Some("import") => {
imports.push(Import::from_sexp(item, &mut ())?);
}
Some("native") | Some("external") => {
module_items.push(Item::from_sexp(item, &mut ())?);
}
_ => {
return Err(ParseError::ExpectedTag {
expected: "import, native, or external",
found: item.tag().map(|s| s.to_string()),
});
}
}
}
Ok(Module {
imports,
items: module_items,
})
}
}
impl FromSExpr<()> for Import {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let [SExpr::Atom(path)] = expect_n("import", s.args())? else {
return Err(ParseError::ExpectedArgs {
expected: 1,
found: s.args().map_or(0, |a| a.len()),
});
};
let path = path.trim_matches('"').to_string();
Ok(Import { path })
}
}
impl FromSExpr<()> for Item {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
match s.tag() {
Some("native") => NativeItem::from_sexp(s, &mut ()).map(Item::Native),
Some("external") => ExternalItem::from_sexp(s, &mut ()).map(Item::External),
other => Err(ParseError::ExpectedTag {
expected: "native or external",
found: other.map(|s| s.to_string()),
}),
}
}
}
impl FromSExpr<()> for NativeItem {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let [symbol, function, typ] = expect_n("native", s.args())?;
Ok(NativeItem {
symbol: Symbol::from_sexp(symbol, &mut ())?,
function: Function::from_sexp(function, &mut ())?,
typ: FunctionType::from_sexp(typ, &mut ())?,
})
}
}
impl FromSExpr<()> for ExternalItem {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let [symbol, typ] = expect_n("external", s.args())?;
Ok(ExternalItem {
symbol: Symbol::from_sexp(symbol, &mut ())?,
typ: FunctionType::from_sexp(typ, &mut ())?,
})
}
}
impl FromSExpr<()> for Expr {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
match s.tag() {
Some("unit") => Ok(Expr::Unit),
Some("int") => {
let [SExpr::Atom(n)] = expect_n("int", s.args())? else {
return Err(ParseError::ExpectedArgs {
expected: 1,
found: s.args().map_or(0, |a| a.len()),
});
};
let n = i64::from_str(n).map_err(|_| ParseError::ParseValue {
type_name: "i64",
reason: n.clone(),
})?;
Ok(Expr::Integer(n))
}
Some("float") => {
let [SExpr::Atom(f)] = expect_n("float", s.args())? else {
return Err(ParseError::ExpectedArgs {
expected: 1,
found: s.args().map_or(0, |a| a.len()),
});
};
let f = f64::from_str(f).map_err(|_| ParseError::ParseValue {
type_name: "f64",
reason: f.clone(),
})?;
Ok(Expr::Float(f))
}
Some("var") => {
let [SExpr::Atom(name)] = expect_n("var", s.args())? else {
return Err(ParseError::ExpectedArgs {
expected: 1,
found: s.args().map_or(0, |a| a.len()),
});
};
Ok(Expr::Variable(name.clone()))
}
Some("str") => {
let [SExpr::Atom(s)] = expect_n("str", s.args())? else {
return Err(ParseError::ExpectedArgs {
expected: 1,
found: s.args().map_or(0, |a| a.len()),
});
};
Ok(Expr::String(s.trim_matches('"').to_string()))
}
Some("let") => {
let [ident, init, body] = expect_n("let", s.args())?;
let pattern = match ident {
SExpr::Atom(s) => Pattern::Identifier(s.clone()),
_ => {
return Err(ParseError::ExpectedTag {
expected: "let pattern",
found: Some("atom".into()),
});
}
};
Ok(Expr::Let {
pattern,
init: Box::new(Expr::from_sexp(init, &mut ())?),
body: Box::new(Expr::from_sexp(body, &mut ())?),
})
}
Some("function") => Function::from_sexp(s, &mut ()).map(Expr::Function),
Some("bin") => {
let [left, op, right] = expect_n("bin", s.args())?;
let op = match op {
SExpr::Atom(a) => match a.as_str() {
"+" => BinaryOperator::Addition,
"-" => BinaryOperator::Subtraction,
"*" => BinaryOperator::Multiplication,
"/" => BinaryOperator::Division,
".." => BinaryOperator::Concat,
_ => {
return Err(ParseError::ParseValue {
type_name: "BinaryOperator",
reason: a.clone(),
});
}
},
_ => {
return Err(ParseError::ParseValue {
type_name: "BinaryOperator",
reason: "expected atom".into(),
});
}
};
Ok(Expr::Binary {
left: Box::new(Expr::from_sexp(left, &mut ())?),
op,
right: Box::new(Expr::from_sexp(right, &mut ())?),
})
}
Some("forward") => {
let [parameter, call] = expect_n("forward", s.args())?;
Ok(Expr::Forward {
parameter: Box::new(Expr::from_sexp(parameter, &mut ())?),
call: Box::new(Expr::from_sexp(call, &mut ())?),
})
}
Some("app") => {
let args = s.args().ok_or(ParseError::ExpectedTag {
expected: "app",
found: None,
})?;
if args.is_empty() {
return Err(ParseError::ExpectedTag {
expected: "app",
found: None,
});
}
let function = Expr::from_sexp(&args[0], &mut ())?;
let parameters: Vec<Expr> = args[1..]
.iter()
.map(|e| Expr::from_sexp(e, &mut ()))
.collect::<Result<_, _>>()?;
Ok(Expr::Application {
function: Box::new(function),
parameters,
})
}
Some("record-select") => {
let [record, label] = expect_n("record-select", s.args())?;
let label = match label {
SExpr::Atom(s) => s.trim_matches('"').to_string(),
_ => {
return Err(ParseError::ParseValue {
type_name: "label",
reason: "expected string".into(),
});
}
};
Ok(Expr::RecordSelect {
record: Box::new(Expr::from_sexp(record, &mut ())?),
label,
})
}
Some("record") => {
let [SExpr::List(fields)] = expect_n("record", s.args())? else {
return Err(ParseError::ExpectedArgs {
expected: 1,
found: s.args().map_or(0, |a| a.len()),
});
};
let mut result = Vec::new();
for field in fields.iter() {
let [SExpr::Atom(name), value] = expect_n("field", field.elements())? else {
return Err(ParseError::ExpectedArgs {
expected: 2,
found: field.elements().map_or(0, |e| e.len()),
});
};
let name = name.trim_matches('"').to_string();
result.push((name, Expr::from_sexp(value, &mut ())?));
}
Ok(Expr::Record { fields: result })
}
Some("parenthesized") => {
let [inner] = expect_n("parenthesized", s.args())?;
Ok(Expr::Parenthesized(Box::new(Expr::from_sexp(
inner,
&mut (),
)?)))
}
Some("item") => {
let [
SExpr::Atom(symbol_keyword),
SExpr::Atom(module),
SExpr::Atom(field),
] = expect_n("item", s.args())?
else {
return Err(ParseError::ExpectedArgs {
expected: 3,
found: s.args().map_or(0, |a| a.len()),
});
};
if symbol_keyword != "symbol" {
return Err(ParseError::ExpectedTag {
expected: "symbol",
found: Some(symbol_keyword.clone()),
});
}
Ok(Expr::Item(Symbol {
module: module.clone(),
field: field.clone(),
}))
}
other => Err(ParseError::ExpectedTag {
expected: "expr",
found: other.map(|s| s.to_string()),
}),
}
}
}
impl FromSExpr<()> for Function {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let [SExpr::List(params), body] = expect_n("function", s.args())? else {
return Err(ParseError::ExpectedArgs {
expected: 2,
found: s.args().map_or(0, |a| a.len()),
});
};
let parameters: Vec<String> = params
.iter()
.map(|p| match p {
SExpr::Atom(s) => Ok(s.clone()),
_ => Err(ParseError::ParseValue {
type_name: "parameter",
reason: "expected atom".into(),
}),
})
.collect::<Result<_, _>>()?;
Ok(Function {
parameters,
body: Box::new(Expr::from_sexp(body, &mut ())?),
})
}
}
impl FromSExpr<()> for Symbol {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let [SExpr::Atom(module), SExpr::Atom(field)] = expect_n("symbol", s.args())? else {
return Err(ParseError::ExpectedArgs {
expected: 2,
found: s.args().map_or(0, |a| a.len()),
});
};
Ok(Symbol {
module: module.clone(),
field: field.clone(),
})
}
}
impl FromSExpr<()> for BinaryOperator {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
match s {
SExpr::Atom(op) => match op.as_str() {
"+" => Ok(BinaryOperator::Addition),
"-" => Ok(BinaryOperator::Subtraction),
"*" => Ok(BinaryOperator::Multiplication),
"/" => Ok(BinaryOperator::Division),
".." => Ok(BinaryOperator::Concat),
_ => Err(ParseError::ParseValue {
type_name: "BinaryOperator",
reason: op.clone(),
}),
},
_ => Err(ParseError::ParseValue {
type_name: "BinaryOperator",
reason: "expected operator atom".into(),
}),
}
}
}
impl FromSExpr<()> for TypeExpr {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
match s.tag() {
Some("unit") => Ok(TypeExpr::Unit),
Some("int") => Ok(TypeExpr::Int),
Some("float") => Ok(TypeExpr::Float),
Some("string") => Ok(TypeExpr::String),
Some("var") => {
let [SExpr::Atom(name)] = expect_n("var", s.args())? else {
return Err(ParseError::ExpectedArgs {
expected: 1,
found: s.args().map_or(0, |a| a.len()),
});
};
Ok(TypeExpr::Var(name.clone()))
}
Some("type") => FunctionType::from_sexp(s, &mut ()).map(TypeExpr::Fun),
Some("row") => Row::from_sexp(s, &mut ()).map(TypeExpr::Prod),
Some("nominal") => {
let [SExpr::Atom(name), typ] = expect_n("nominal", s.args())? else {
return Err(ParseError::ExpectedArgs {
expected: 2,
found: s.args().map_or(0, |a| a.len()),
});
};
Ok(TypeExpr::Nominal(
name.clone(),
Box::new(TypeExpr::from_sexp(typ, &mut ())?),
))
}
Some("dataframe") => Ok(TypeExpr::DataFrame),
other => Err(ParseError::ExpectedTag {
expected: "type",
found: other.map(|s| s.to_string()),
}),
}
}
}
impl FromSExpr<()> for FunctionType {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let [SExpr::List(named_types), ret] = expect_n("type", s.args())? else {
return Err(ParseError::ExpectedArgs {
expected: 2,
found: s.args().map_or(0, |a| a.len()),
});
};
let named_types = named_types.as_slice();
if named_types.len() % 2 != 0 {
return Err(ParseError::ParseValue {
type_name: "FunctionType",
reason: "odd number of named types".into(),
});
}
let mut parameter_names = Vec::new();
let mut parameter_typs = Vec::new();
let mut iter = named_types.iter();
while let Some(name) = iter.next() {
let typ = iter.next().ok_or(ParseError::ParseValue {
type_name: "FunctionType",
reason: "missing type for name".into(),
})?;
match name {
SExpr::Atom(n) => parameter_names.push(n.clone()),
_ => {
return Err(ParseError::ParseValue {
type_name: "parameter name",
reason: "expected atom".into(),
});
}
}
parameter_typs.push(TypeExpr::from_sexp(typ, &mut ())?);
}
Ok(FunctionType {
parameter_names,
parameter_typs,
ret: Box::new(TypeExpr::from_sexp(ret, &mut ())?),
})
}
}
impl FromSExpr<()> for Row {
fn from_sexp(s: &SExpr, _ctx: &mut ()) -> Result<Self, ParseError> {
let [SExpr::List(fields)] = expect_n("row", s.args())? else {
return Err(ParseError::ExpectedArgs {
expected: 1,
found: s.args().map_or(0, |a| a.len()),
});
};
let mut result = Vec::new();
for field in fields.iter() {
let [SExpr::Atom(label), typ] = expect_n("field", field.elements())? else {
return Err(ParseError::ExpectedArgs {
expected: 2,
found: field.elements().map_or(0, |e| e.len()),
});
};
let label = label.trim_matches('`').to_string();
result.push((label, TypeExpr::from_sexp(typ, &mut ())?));
}
Ok(Row { fields: result })
}
}
#[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_unit() {
let expr = Expr::Unit;
expect!["(unit)"].assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_integer() {
let expr = Expr::Integer(42);
expect!["(int 42)"].assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_float() {
let expr = Expr::Float(3.24);
let output = expr.to_sexpr(&()).to_string();
assert!(output.starts_with("(float 3.24"));
assert!(output.ends_with(")"));
}
#[test]
fn to_sexpr_variable() {
let expr = Expr::Variable("x".into());
expect!["(var x)"].assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_string() {
let expr = Expr::String("hello".into());
expect!["(str hello)"].assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_let() {
let expr = Expr::Let {
pattern: Pattern::Identifier("x".into()),
init: Box::new(Expr::Integer(1)),
body: Box::new(Expr::Variable("x".into())),
};
expect![[r#"(let x (int 1) (var x))"#]].assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_function() {
let expr = Expr::Function(Function {
parameters: vec!["x".into(), "y".into()],
body: Box::new(Expr::Variable("x".into())),
});
expect![[r#"(function (x y) (var x))"#]].assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_binary() {
let expr = Expr::Binary {
left: Box::new(Expr::Integer(1)),
op: BinaryOperator::Addition,
right: Box::new(Expr::Integer(2)),
};
expect!["(bin (int 1) + (int 2))"].assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_forward() {
let expr = Expr::Forward {
parameter: Box::new(Expr::Variable("x".into())),
call: Box::new(Expr::Application {
function: Box::new(Expr::Variable("f".into())),
parameters: vec![Expr::Variable("x".into())],
}),
};
expect![[r#"(forward (var x) (app (var f) (var x)))"#]]
.assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_application() {
let expr = Expr::Application {
function: Box::new(Expr::Variable("f".into())),
parameters: vec![Expr::Variable("x".into()), Expr::Variable("y".into())],
};
expect!["(app (var f) (var x) (var y))"].assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_record_select() {
let expr = Expr::RecordSelect {
record: Box::new(Expr::Variable("r".into())),
label: "field".into(),
};
expect!["(record-select (var r) field)"].assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_record() {
let expr = Expr::Record {
fields: vec![
("name".into(), Expr::String("Alice".into())),
("age".into(), Expr::Integer(30)),
],
};
expect!["(record ((name (str Alice)) (age (int 30))))"]
.assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_parenthesized() {
let expr = Expr::Parenthesized(Box::new(Expr::Integer(42)));
expect!["(parenthesized (int 42))"].assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_item() {
let expr = Expr::Item(Symbol {
module: "std".into(),
field: "println".into(),
});
expect![[r#"(item symbol std println)"#]].assert_eq(&expr.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_symbol() {
let symbol = Symbol {
module: "std".into(),
field: "println".into(),
};
expect![[r#"(symbol std println)"#]].assert_eq(&symbol.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_binary_operators() {
expect!["+"].assert_eq(&BinaryOperator::Addition.to_sexpr(&()).to_string());
expect!["-"].assert_eq(&BinaryOperator::Subtraction.to_sexpr(&()).to_string());
expect!["*"].assert_eq(&BinaryOperator::Multiplication.to_sexpr(&()).to_string());
expect!["/"].assert_eq(&BinaryOperator::Division.to_sexpr(&()).to_string());
expect![".."].assert_eq(&BinaryOperator::Concat.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_type_unit() {
let typ = TypeExpr::Unit;
expect!["(unit)"].assert_eq(&typ.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_type_int() {
let typ = TypeExpr::Int;
expect!["(int)"].assert_eq(&typ.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_type_float() {
let typ = TypeExpr::Float;
expect!["(float)"].assert_eq(&typ.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_type_string() {
let typ = TypeExpr::String;
expect!["(string)"].assert_eq(&typ.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_type_var() {
let typ = TypeExpr::Var("T".into());
expect!["(var T)"].assert_eq(&typ.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_type_fun() {
let typ = TypeExpr::Fun(FunctionType {
parameter_names: vec!["x".into()],
parameter_typs: vec![TypeExpr::Int],
ret: Box::new(TypeExpr::Int),
});
expect![[r#"(type (x (int)) (int))"#]].assert_eq(&typ.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_type_prod() {
let typ = TypeExpr::Prod(Row {
fields: vec![
("name".into(), TypeExpr::String),
("age".into(), TypeExpr::Int),
],
});
expect![[r#"(row ((`name` (string)) (`age` (int))))"#]]
.assert_eq(&typ.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_type_nominal() {
let typ = TypeExpr::Nominal(
"Point".into(),
Box::new(TypeExpr::Fun(FunctionType {
parameter_names: vec!["x".into(), "y".into()],
parameter_typs: vec![TypeExpr::Float, TypeExpr::Float],
ret: Box::new(TypeExpr::Unit),
})),
);
expect![[r#"(nominal Point (type (x (float) y (float)) (unit)))"#]]
.assert_eq(&typ.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_type_dataframe() {
let typ = TypeExpr::DataFrame;
expect!["(dataframe)"].assert_eq(&typ.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_function_type() {
let typ = FunctionType {
parameter_names: vec!["x".into(), "y".into()],
parameter_typs: vec![TypeExpr::Int, TypeExpr::Float],
ret: Box::new(TypeExpr::Int),
};
expect![[r#"(type (x (int) y (float)) (int))"#]].assert_eq(&typ.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_row() {
let row = Row {
fields: vec![
("name".into(), TypeExpr::String),
("age".into(), TypeExpr::Int),
],
};
expect![[r#"(row ((`name` (string)) (`age` (int))))"#]]
.assert_eq(&row.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_native_item() {
let item = NativeItem {
symbol: Symbol {
module: "".into(),
field: "main".into(),
},
function: Function {
parameters: vec!["_".to_string()],
body: Box::new(Expr::Integer(0)),
},
typ: FunctionType {
parameter_names: vec!["_".to_string()],
parameter_typs: vec![TypeExpr::Unit],
ret: Box::new(TypeExpr::Var("_".into())),
},
};
expect!["(native (symbol \"\" main) (function (_) (int 0)) (type (_ (unit)) (var _)))"]
.assert_eq(&item.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_external_item() {
let item = ExternalItem {
symbol: Symbol {
module: "".into(),
field: "println".into(),
},
typ: FunctionType {
parameter_names: vec!["s".to_string()],
parameter_typs: vec![TypeExpr::String],
ret: Box::new(TypeExpr::Unit),
},
};
expect!["(external (symbol \"\" println) (type (s (string)) (unit)))"]
.assert_eq(&item.to_sexpr(&()).to_string());
}
#[test]
fn to_sexpr_module() {
let module = Module {
imports: vec![Import {
path: "std::io".into(),
}],
items: vec![Item::Native(NativeItem {
symbol: Symbol {
module: "".into(),
field: "main".into(),
},
function: Function {
parameters: vec!["_".to_string()],
body: Box::new(Expr::Integer(0)),
},
typ: FunctionType {
parameter_names: vec!["_".to_string()],
parameter_typs: vec![TypeExpr::Unit],
ret: Box::new(TypeExpr::Var("_".into())),
},
})],
};
let output = module.to_sexpr(&()).to_string();
println!("MODULE OUTPUT: {}", output);
assert!(output.starts_with("(module"));
assert!(output.contains("(import std::io)"));
assert!(output.contains("(native"));
}
#[test]
fn from_sexp_unit() {
let s = SExpr::List(vec![SExpr::Atom("unit".into())]);
assert_eq!(Expr::from_sexp(&s, &mut ()).unwrap(), Expr::Unit);
}
#[test]
fn from_sexp_integer() {
let s = SExpr::List(vec![SExpr::Atom("int".into()), SExpr::Atom("42".into())]);
assert_eq!(Expr::from_sexp(&s, &mut ()).unwrap(), Expr::Integer(42));
}
#[test]
fn from_sexp_float() {
let s = SExpr::List(vec![
SExpr::Atom("float".into()),
SExpr::Atom("3.24".into()),
]);
assert_eq!(Expr::from_sexp(&s, &mut ()).unwrap(), Expr::Float(3.24));
}
#[test]
fn from_sexp_variable() {
let s = SExpr::List(vec![SExpr::Atom("var".into()), SExpr::Atom("x".into())]);
assert_eq!(
Expr::from_sexp(&s, &mut ()).unwrap(),
Expr::Variable("x".into())
);
}
#[test]
fn from_sexp_string() {
let s = SExpr::List(vec![SExpr::Atom("str".into()), SExpr::Atom("hello".into())]);
assert_eq!(
Expr::from_sexp(&s, &mut ()).unwrap(),
Expr::String("hello".into())
);
}
#[test]
fn from_sexp_let() {
let s = SExpr::List(vec![
SExpr::Atom("let".into()),
SExpr::Atom("x".into()),
SExpr::List(vec![SExpr::Atom("int".into()), SExpr::Atom("1".into())]),
SExpr::List(vec![SExpr::Atom("var".into()), SExpr::Atom("x".into())]),
]);
let result = Expr::from_sexp(&s, &mut ()).unwrap();
match result {
Expr::Let {
pattern,
init,
body,
} => {
assert_eq!(pattern, Pattern::Identifier("x".into()));
assert_eq!(*init, Expr::Integer(1));
assert_eq!(*body, Expr::Variable("x".into()));
}
_ => panic!("expected Let"),
}
}
#[test]
fn from_sexp_binary() {
let s = SExpr::List(vec![
SExpr::Atom("bin".into()),
SExpr::List(vec![SExpr::Atom("int".into()), SExpr::Atom("1".into())]),
SExpr::Atom("+".into()),
SExpr::List(vec![SExpr::Atom("int".into()), SExpr::Atom("2".into())]),
]);
let result = Expr::from_sexp(&s, &mut ()).unwrap();
match result {
Expr::Binary { left, op, right } => {
assert_eq!(*left, Expr::Integer(1));
assert_eq!(op, BinaryOperator::Addition);
assert_eq!(*right, Expr::Integer(2));
}
_ => panic!("expected Binary"),
}
}
#[test]
fn from_sexp_application() {
let s = SExpr::List(vec![
SExpr::Atom("app".into()),
SExpr::List(vec![SExpr::Atom("var".into()), SExpr::Atom("f".into())]),
SExpr::List(vec![SExpr::Atom("var".into()), SExpr::Atom("x".into())]),
]);
let result = Expr::from_sexp(&s, &mut ()).unwrap();
match result {
Expr::Application {
function,
parameters,
} => {
assert_eq!(*function, Expr::Variable("f".into()));
assert_eq!(parameters.len(), 1);
assert_eq!(parameters[0], Expr::Variable("x".into()));
}
_ => panic!("expected Application"),
}
}
#[test]
fn from_sexp_record() {
let s = SExpr::List(vec![
SExpr::Atom("record".into()),
SExpr::List(vec![SExpr::List(vec![
SExpr::Atom("name".into()),
SExpr::List(vec![SExpr::Atom("str".into()), SExpr::Atom("Alice".into())]),
])]),
]);
let result = Expr::from_sexp(&s, &mut ()).unwrap();
match result {
Expr::Record { fields } => {
assert_eq!(fields.len(), 1);
assert_eq!(fields[0].0, "name");
assert_eq!(fields[0].1, Expr::String("Alice".into()));
}
_ => panic!("expected Record"),
}
}
#[test]
fn from_sexp_item() {
let s = SExpr::List(vec![
SExpr::Atom("item".into()),
SExpr::Atom("symbol".into()),
SExpr::Atom("std".into()),
SExpr::Atom("println".into()),
]);
let result = Expr::from_sexp(&s, &mut ()).unwrap();
match result {
Expr::Item(symbol) => {
assert_eq!(symbol.module, "std");
assert_eq!(symbol.field, "println");
}
_ => panic!("expected Item"),
}
}
#[test]
fn from_sexp_symbol() {
let s = SExpr::List(vec![
SExpr::Atom("symbol".into()),
SExpr::Atom("std".into()),
SExpr::Atom("println".into()),
]);
let result = Symbol::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.module, "std");
assert_eq!(result.field, "println");
}
#[test]
fn from_sexp_type_unit() {
let s = SExpr::List(vec![SExpr::Atom("unit".into())]);
assert_eq!(TypeExpr::from_sexp(&s, &mut ()).unwrap(), TypeExpr::Unit);
}
#[test]
fn from_sexp_type_int() {
let s = SExpr::List(vec![SExpr::Atom("int".into())]);
assert_eq!(TypeExpr::from_sexp(&s, &mut ()).unwrap(), TypeExpr::Int);
}
#[test]
fn from_sexp_type_var() {
let s = SExpr::List(vec![SExpr::Atom("var".into()), SExpr::Atom("T".into())]);
assert_eq!(
TypeExpr::from_sexp(&s, &mut ()).unwrap(),
TypeExpr::Var("T".into())
);
}
#[test]
fn from_sexp_type_fun() {
let s = SExpr::List(vec![
SExpr::Atom("type".into()),
SExpr::List(vec![
SExpr::Atom("x".into()),
SExpr::List(vec![SExpr::Atom("int".into())]),
]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]);
let result = TypeExpr::from_sexp(&s, &mut ()).unwrap();
match result {
TypeExpr::Fun(ft) => {
assert_eq!(ft.parameter_names, vec!["x".to_string()]);
assert_eq!(ft.parameter_typs, vec![TypeExpr::Int]);
assert_eq!(*ft.ret, TypeExpr::Int);
}
_ => panic!("expected Fun"),
}
}
#[test]
fn from_sexp_type_prod() {
let s = SExpr::List(vec![
SExpr::Atom("row".into()),
SExpr::List(vec![SExpr::List(vec![
SExpr::Atom("name".into()),
SExpr::List(vec![SExpr::Atom("string".into())]),
])]),
]);
let result = TypeExpr::from_sexp(&s, &mut ()).unwrap();
match result {
TypeExpr::Prod(row) => {
assert_eq!(row.fields.len(), 1);
assert_eq!(row.fields[0].0, "name");
assert_eq!(row.fields[0].1, TypeExpr::String);
}
_ => panic!("expected Prod"),
}
}
#[test]
fn from_sexp_function() {
let s = SExpr::List(vec![
SExpr::Atom("function".into()),
SExpr::List(vec![SExpr::Atom("x".into()), SExpr::Atom("y".into())]),
SExpr::List(vec![SExpr::Atom("var".into()), SExpr::Atom("x".into())]),
]);
let result = Function::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.parameters, vec!["x".to_string(), "y".to_string()]);
assert_eq!(*result.body, Expr::Variable("x".into()));
}
#[test]
fn from_sexp_function_type() {
let s = SExpr::List(vec![
SExpr::Atom("type".into()),
SExpr::List(vec![
SExpr::Atom("x".into()),
SExpr::List(vec![SExpr::Atom("int".into())]),
]),
SExpr::List(vec![SExpr::Atom("int".into())]),
]);
let result = FunctionType::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.parameter_names, vec!["x".to_string()]);
assert_eq!(result.parameter_typs, vec![TypeExpr::Int]);
assert_eq!(*result.ret, TypeExpr::Int);
}
#[test]
fn from_sexp_row() {
let s = SExpr::List(vec![
SExpr::Atom("row".into()),
SExpr::List(vec![SExpr::List(vec![
SExpr::Atom("name".into()),
SExpr::List(vec![SExpr::Atom("string".into())]),
])]),
]);
let result = Row::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.fields.len(), 1);
assert_eq!(result.fields[0].0, "name");
assert_eq!(result.fields[0].1, TypeExpr::String);
}
#[test]
fn from_sexp_native_item() {
let s = SExpr::List(vec![
SExpr::Atom("native".into()),
SExpr::List(vec![
SExpr::Atom("symbol".into()),
SExpr::Atom("".to_string()),
SExpr::Atom("main".into()),
]),
SExpr::List(vec![
SExpr::Atom("function".into()),
SExpr::List(vec![SExpr::Atom("_".into())]),
SExpr::List(vec![SExpr::Atom("int".into()), SExpr::Atom("0".into())]),
]),
SExpr::List(vec![
SExpr::Atom("type".into()),
SExpr::List(vec![
SExpr::Atom("_".into()),
SExpr::List(vec![SExpr::Atom("unit".into())]),
]),
SExpr::List(vec![SExpr::Atom("var".into()), SExpr::Atom("_".into())]),
]),
]);
let result = NativeItem::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.symbol.field, "main");
assert_eq!(result.function.parameters, vec!["_".to_string()]);
assert_eq!(*result.function.body, Expr::Integer(0));
}
#[test]
fn from_sexp_external_item() {
let s = SExpr::List(vec![
SExpr::Atom("external".into()),
SExpr::List(vec![
SExpr::Atom("symbol".into()),
SExpr::Atom("".to_string()),
SExpr::Atom("println".into()),
]),
SExpr::List(vec![
SExpr::Atom("type".into()),
SExpr::List(vec![
SExpr::Atom("s".into()),
SExpr::List(vec![SExpr::Atom("string".into())]),
]),
SExpr::List(vec![SExpr::Atom("unit".into())]),
]),
]);
let result = ExternalItem::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.symbol.field, "println");
assert_eq!(result.typ.parameter_names, vec!["s".to_string()]);
assert_eq!(result.typ.parameter_typs, vec![TypeExpr::String]);
assert_eq!(*result.typ.ret, TypeExpr::Unit);
}
#[test]
fn from_sexp_module() {
let s = SExpr::List(vec![
SExpr::Atom("module".into()),
SExpr::List(vec![
SExpr::Atom("import".into()),
SExpr::Atom("std::io".into()),
]),
SExpr::List(vec![
SExpr::Atom("native".into()),
SExpr::List(vec![
SExpr::Atom("symbol".into()),
SExpr::Atom("".to_string()),
SExpr::Atom("main".into()),
]),
SExpr::List(vec![
SExpr::Atom("function".into()),
SExpr::List(vec![SExpr::Atom("_".into())]),
SExpr::List(vec![SExpr::Atom("int".into()), SExpr::Atom("0".into())]),
]),
SExpr::List(vec![
SExpr::Atom("type".into()),
SExpr::List(vec![
SExpr::Atom("_".into()),
SExpr::List(vec![SExpr::Atom("unit".into())]),
]),
SExpr::List(vec![SExpr::Atom("var".into()), SExpr::Atom("_".into())]),
]),
]),
]);
let result = Module::from_sexp(&s, &mut ()).unwrap();
assert_eq!(result.imports.len(), 1);
assert_eq!(result.imports[0].path, "std::io");
assert_eq!(result.items.len(), 1);
match &result.items[0] {
Item::Native(native) => assert_eq!(native.symbol.field, "main"),
_ => panic!("expected Native"),
}
}
#[test]
fn roundtrip_complex_expr() {
roundtrip::<Expr>(expect![[r#"
(let
x
(app (var f) (int 1) (int 2))
(record ((name (str Alice)) (age (int 30)))))"#]]);
}
#[test]
fn roundtrip_type() {
roundtrip::<TypeExpr>(expect![
"(type (x (int) y (float)) (row ((`result` (int)) (`success` (int)))))"
]);
}
#[test]
fn roundtrip_module() {
roundtrip::<Module>(expect![[r#"
(module
(import std::io)
(import std::math)
(native (symbol "" main) (function (_) (int 0)) (type (_ (unit)) (var _)))
(external (symbol "" println) (type (s (string)) (unit))))"#]]);
}
#[test]
fn display_module() {
let expected = expect![[r#"
(module
(import std::io)
(native (symbol "" main) (function (_) (int 0)) (type (_ (unit)) (var _))))"#]];
let parsed = parse_one(expected.data()).unwrap();
let ast = Module::from_sexp(&parsed, &mut ()).unwrap();
expected.assert_eq(&ast.to_sexpr(&()).to_string());
}
#[test]
fn display_long_module_wraps() {
let module = Module {
imports: vec![],
items: vec![Item::Native(NativeItem {
symbol: Symbol {
module: "".into(),
field: "very_long_function_name_that_should_cause_wrapping".into(),
},
function: Function {
parameters: vec![
"very_long_parameter_name_1".to_string(),
"very_long_parameter_name_2".to_string(),
"very_long_parameter_name_3".to_string(),
],
body: Box::new(Expr::Binary {
left: Box::new(Expr::Application {
function: Box::new(Expr::Item(Symbol {
module: "".into(),
field: "very_long_function_name_that_should_cause_wrapping".into(),
})),
parameters: vec![
Expr::Variable("very_long_parameter_name_1".into()),
Expr::Variable("very_long_parameter_name_2".into()),
Expr::Variable("very_long_parameter_name_3".into()),
],
}),
op: BinaryOperator::Addition,
right: Box::new(Expr::Integer(42)),
}),
},
typ: FunctionType {
parameter_names: vec![
"very_long_parameter_name_1".to_string(),
"very_long_parameter_name_2".to_string(),
"very_long_parameter_name_3".to_string(),
],
parameter_typs: vec![TypeExpr::Int, TypeExpr::Int, TypeExpr::Int],
ret: Box::new(TypeExpr::Int),
},
})],
};
expect![[r#"
(module
(native
(symbol "" very_long_function_name_that_should_cause_wrapping)
(function
(very_long_parameter_name_1
very_long_parameter_name_2
very_long_parameter_name_3)
(bin
(app
(item symbol "" very_long_function_name_that_should_cause_wrapping)
(var very_long_parameter_name_1)
(var very_long_parameter_name_2)
(var very_long_parameter_name_3))
+
(int 42)))
(type
(very_long_parameter_name_1
(int)
very_long_parameter_name_2
(int)
very_long_parameter_name_3
(int))
(int))))"#]]
.assert_eq(&module.to_sexpr(&()).to_string());
}
#[test]
fn roundtrip_import() {
roundtrip::<Import>(expect!["(import std::io)"]);
}
#[test]
fn roundtrip_item_native() {
roundtrip::<Item>(expect![
"(native (symbol \"\" main) (function (_) (int 0)) (type (_ (unit)) (var _)))"
]);
}
#[test]
fn roundtrip_item_external() {
roundtrip::<Item>(expect![
"(external (symbol \"\" println) (type (s (string)) (unit)))"
]);
}
#[test]
fn roundtrip_native_item() {
roundtrip::<NativeItem>(expect![
"(native (symbol \"\" main) (function (_) (int 0)) (type (_ (unit)) (var _)))"
]);
}
#[test]
fn roundtrip_external_item() {
roundtrip::<ExternalItem>(expect![
"(external (symbol \"\" println) (type (s (string)) (unit)))"
]);
}
#[test]
fn roundtrip_expr_unit() {
roundtrip::<Expr>(expect!["(unit)"]);
}
#[test]
fn roundtrip_expr_int() {
roundtrip::<Expr>(expect!["(int 42)"]);
}
#[test]
fn roundtrip_expr_float() {
roundtrip::<Expr>(expect!["(float 3.24)"]);
}
#[test]
fn roundtrip_expr_variable() {
roundtrip::<Expr>(expect!["(var x)"]);
}
#[test]
fn roundtrip_expr_string() {
roundtrip::<Expr>(expect!["(str hello)"]);
}
#[test]
fn roundtrip_expr_let() {
roundtrip::<Expr>(expect!["(let x (int 1) (var x))"]);
}
#[test]
fn roundtrip_expr_function() {
roundtrip::<Expr>(expect!["(function (x y) (var x))"]);
}
#[test]
fn roundtrip_expr_binary() {
roundtrip::<Expr>(expect!["(bin (int 1) + (int 2))"]);
}
#[test]
fn roundtrip_expr_forward() {
roundtrip::<Expr>(expect!["(forward (var x) (app (var f) (var x)))"]);
}
#[test]
fn roundtrip_expr_application() {
roundtrip::<Expr>(expect!["(app (var f) (var x) (var y))"]);
}
#[test]
fn roundtrip_expr_record_select() {
roundtrip::<Expr>(expect!["(record-select (var r) field)"]);
}
#[test]
fn roundtrip_expr_record() {
roundtrip::<Expr>(expect!["(record ((name (str Alice)) (age (int 30))))"]);
}
#[test]
fn roundtrip_expr_parenthesized() {
roundtrip::<Expr>(expect!["(parenthesized (int 42))"]);
}
#[test]
fn roundtrip_expr_item() {
roundtrip::<Expr>(expect!["(item symbol std println)"]);
}
#[test]
fn roundtrip_function() {
roundtrip::<Function>(expect!["(function (x y) (var x))"]);
}
#[test]
fn roundtrip_symbol() {
roundtrip::<Symbol>(expect!["(symbol std println)"]);
}
#[test]
fn roundtrip_binary_operator_addition() {
roundtrip::<BinaryOperator>(expect!["+"]);
}
#[test]
fn roundtrip_binary_operator_subtraction() {
roundtrip::<BinaryOperator>(expect!["-"]);
}
#[test]
fn roundtrip_binary_operator_multiplication() {
roundtrip::<BinaryOperator>(expect!["*"]);
}
#[test]
fn roundtrip_binary_operator_division() {
roundtrip::<BinaryOperator>(expect!["/"]);
}
#[test]
fn roundtrip_binary_operator_concat() {
roundtrip::<BinaryOperator>(expect![".."]);
}
#[test]
fn roundtrip_type_expr_unit() {
roundtrip::<TypeExpr>(expect!["(unit)"]);
}
#[test]
fn roundtrip_type_expr_int() {
roundtrip::<TypeExpr>(expect!["(int)"]);
}
#[test]
fn roundtrip_type_expr_float() {
roundtrip::<TypeExpr>(expect!["(float)"]);
}
#[test]
fn roundtrip_type_expr_string() {
roundtrip::<TypeExpr>(expect!["(string)"]);
}
#[test]
fn roundtrip_type_expr_var() {
roundtrip::<TypeExpr>(expect!["(var T)"]);
}
#[test]
fn roundtrip_type_expr_fun() {
roundtrip::<TypeExpr>(expect!["(type (x (int)) (int))"]);
}
#[test]
fn roundtrip_type_expr_prod() {
roundtrip::<TypeExpr>(expect!["(row ((`name` (string)) (`age` (int))))"]);
}
#[test]
fn roundtrip_type_expr_nominal() {
roundtrip::<TypeExpr>(expect![
"(nominal Point (type (x (float) y (float)) (unit)))"
]);
}
#[test]
fn roundtrip_type_expr_dataframe() {
roundtrip::<TypeExpr>(expect!["(dataframe)"]);
}
#[test]
fn roundtrip_function_type() {
roundtrip::<FunctionType>(expect!["(type (x (int) y (float)) (int))"]);
}
#[test]
fn roundtrip_row() {
roundtrip::<Row>(expect!["(row ((`name` (string)) (`age` (int))))"]);
}
}