|
#include <iostream> |
|
|
|
namespace ast{ |
|
|
|
//declare non-recursive nodes first |
|
|
|
struct NumberLit{ |
|
float v; |
|
}; |
|
struct Symbol{ |
|
std::string v; |
|
}; |
|
// pur forward declarations for recursive nodes |
|
|
|
struct App; |
|
struct Let; |
|
struct Lambda; |
|
|
|
// declare main variant |
|
|
|
using Expr = std::variant<NumberLit,Symbol,Box<App>,Box<Let>,Box<Lambda>>; |
|
|
|
struct App{ |
|
Expr callee; |
|
std::list<Expr> arg; |
|
}; |
|
struct Let{ |
|
std::string name; |
|
Expr expr; |
|
Expr newenv_expr; |
|
}; |
|
struct Lambda{ |
|
std::list<std::string> ids; |
|
Expr expr; |
|
}; |
|
|
|
std::string toString(std::string const& s){ |
|
return s; |
|
} |
|
std::string toString(float f){ |
|
return std::to_string(f); |
|
} |
|
template<template<class...> class C,typename T> |
|
std::string toStringList(C<T>const& list){ |
|
return std::accumulate(list.cbegin(),list.cend(),T{},[](auto const& a,auto const& b)->std::string{ |
|
return toString(a) + " " + toString(b); }); |
|
} |
|
template<template<class...> class C,typename T> |
|
std::string toStringList(C<Box<T>>const& list){ |
|
C<std::string> res; |
|
auto c = std::transform(list.cbegin(),list.cend(),std::back_inserter(res),[](auto& a){return toString(a);}); |
|
|
|
return std::accumulate(res.cbegin(),res.cend(),std::string{},[](auto const& a,auto const& b)->std::string{ |
|
return a + " " + b; }); |
|
} |
|
|
|
std::string toString(ast::Expr const& expr){ |
|
return std::visit(overloaded_rec{ |
|
[](ast::App const& node){ return "(app " + toString(node.callee) + " " + toStringList(node.arg)+ ")"; |
|
}, |
|
[](ast::Let const& node){ return "(let " + node.name + " "\ |
|
+ toString(node.expr) + " "\ |
|
+ toString(node.newenv_expr)+ ")"; |
|
}, |
|
[](ast::Lambda const& node){ return "(lambda " + toStringList(node.ids) + " " + toString(node.expr) + ")"; }, |
|
[](ast::NumberLit const& node){ return toString(node.v);}, |
|
[](ast::Symbol const& node){ return node.v;} |
|
},expr); |
|
} |
|
|
|
} |