xo-expression: add explicit types to all Expressions
This commit is contained in:
parent
b18de1b0ce
commit
9ff173f68a
12 changed files with 223 additions and 54 deletions
|
|
@ -20,11 +20,13 @@ namespace xo {
|
|||
**/
|
||||
class Apply : public Expression {
|
||||
public:
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
|
||||
public:
|
||||
/** create new apply-expression instance
|
||||
**/
|
||||
static ref::rp<Apply> make(const ref::rp<Expression> & fn,
|
||||
const std::vector<ref::rp<Expression>> & argv)
|
||||
{
|
||||
return new Apply(fn, argv);
|
||||
}
|
||||
const std::vector<ref::rp<Expression>> & argv);
|
||||
|
||||
/** downcast from Expression **/
|
||||
static ref::brw<Apply> from(ref::brw<Expression> x) {
|
||||
|
|
@ -37,9 +39,11 @@ namespace xo {
|
|||
virtual void display(std::ostream & os) const;
|
||||
|
||||
private:
|
||||
Apply(const ref::rp<Expression> & fn,
|
||||
Apply(TypeDescr apply_valuetype,
|
||||
const ref::rp<Expression> & fn,
|
||||
const std::vector<ref::rp<Expression>> & argv)
|
||||
: Expression(exprtype::apply), fn_{fn}, argv_(argv)
|
||||
: Expression(exprtype::apply, apply_valuetype),
|
||||
fn_{fn}, argv_(argv)
|
||||
{}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -29,13 +29,12 @@ namespace xo {
|
|||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
|
||||
public:
|
||||
explicit Constant(const T & x)
|
||||
: ConstantInterface(exprtype::constant),
|
||||
value_td_{Reflect::require<T>()},
|
||||
value_(x)
|
||||
{
|
||||
static_assert(std::is_standard_layout_v<T> && std::is_trivial_v<T>);
|
||||
}
|
||||
/** create constant expression representing literal value x **/
|
||||
static ref::rp<Constant> make(const T & x) {
|
||||
TypeDescr x_valuetype = Reflect::require<T>();
|
||||
|
||||
return new Constant(x_valuetype, x);
|
||||
}
|
||||
|
||||
const T & value() const { return value_; }
|
||||
|
||||
|
|
@ -59,6 +58,15 @@ namespace xo {
|
|||
<< ">";
|
||||
}
|
||||
|
||||
private:
|
||||
explicit Constant(TypeDescr x_type, const T & x)
|
||||
: ConstantInterface(exprtype::constant, x_type),
|
||||
value_td_{Reflect::require<T>()},
|
||||
value_(x)
|
||||
{
|
||||
static_assert(std::is_standard_layout_v<T> && std::is_trivial_v<T>);
|
||||
}
|
||||
|
||||
private:
|
||||
/** type description for T **/
|
||||
TypeDescr value_td_;
|
||||
|
|
@ -69,7 +77,7 @@ namespace xo {
|
|||
template <typename T>
|
||||
ref::rp<Constant<std::remove_reference_t<T>>>
|
||||
make_constant(const T & x) {
|
||||
return new Constant(x);
|
||||
return Constant<T>::make(x);
|
||||
}
|
||||
|
||||
} /*namespace ast*/
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace xo {
|
|||
|
||||
public:
|
||||
/** @p extype sets expression-type; could be constant|primitive **/
|
||||
ConstantInterface(exprtype extype) : Expression{extype} {}
|
||||
ConstantInterface(exprtype extype, TypeDescr valuetype) : Expression{extype, valuetype} {}
|
||||
|
||||
/** downcast from Expression **/
|
||||
static ref::brw<ConstantInterface> from(ref::brw<Expression> x) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "xo/reflect/TypeDescr.hpp"
|
||||
#include "xo/refcnt/Refcounted.hpp"
|
||||
#include "exprtype.hpp"
|
||||
|
||||
|
|
@ -23,12 +24,19 @@ namespace xo {
|
|||
*
|
||||
* Expressions are immutable. This means they can resused
|
||||
* across jit interactions
|
||||
*
|
||||
* Every expression evaluates to a value with a particular type
|
||||
**/
|
||||
class Expression : public ref::Refcount {
|
||||
public:
|
||||
explicit Expression(exprtype extype) : extype_{extype} {}
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
|
||||
public:
|
||||
explicit Expression(exprtype extype, TypeDescr valuetype)
|
||||
: extype_{extype}, valuetype_{valuetype}{}
|
||||
|
||||
exprtype extype() const { return extype_; }
|
||||
TypeDescr valuetype() const { return valuetype_; }
|
||||
|
||||
/** write human-readable representation to stream **/
|
||||
virtual void display(std::ostream & os) const = 0;
|
||||
|
|
@ -38,6 +46,10 @@ namespace xo {
|
|||
private:
|
||||
/** expression type (constant | apply | ..) for this expression **/
|
||||
exprtype extype_ = exprtype::invalid;
|
||||
/** type information (when available) for values produced by this
|
||||
* expression.
|
||||
**/
|
||||
TypeDescr valuetype_ = nullptr;
|
||||
}; /*Expression*/
|
||||
|
||||
inline std::ostream &
|
||||
|
|
|
|||
|
|
@ -18,17 +18,16 @@ namespace xo {
|
|||
**/
|
||||
class IfExpr : public Expression {
|
||||
public:
|
||||
/** @p test test-expression; always execute
|
||||
* @p when_true then-branch; executes only when test succeeds
|
||||
* @p when_false else-branch; executes only when test fails
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
|
||||
public:
|
||||
/** create expression for conditional execution of
|
||||
* @p when_true or @p when_false, depending on result
|
||||
* of evaluating expression @p test
|
||||
**/
|
||||
IfExpr(const ref::rp<Expression> & test,
|
||||
const ref::rp<Expression> & when_true,
|
||||
const ref::rp<Expression> & when_false)
|
||||
: Expression(exprtype::ifexpr),
|
||||
test_{test},
|
||||
when_true_{when_true},
|
||||
when_false_{when_false} {}
|
||||
static ref::rp<IfExpr> make(const ref::rp<Expression> & test,
|
||||
const ref::rp<Expression> & when_true,
|
||||
const ref::rp<Expression> & when_false);
|
||||
|
||||
/** downcast from Expression **/
|
||||
static ref::brw<IfExpr> from(ref::brw<Expression> x) {
|
||||
|
|
@ -43,6 +42,24 @@ namespace xo {
|
|||
|
||||
virtual void display(std::ostream & os) const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @p ifexpr_type type for value produced by if-expression.
|
||||
* same as both when_true->valuetype() and
|
||||
* when_false->valuetype().
|
||||
* @p test test-expression; always execute
|
||||
* @p when_true then-branch; executes only when test succeeds
|
||||
* @p when_false else-branch; executes only when test fails
|
||||
**/
|
||||
IfExpr(TypeDescr ifexpr_type,
|
||||
const ref::rp<Expression> & test,
|
||||
const ref::rp<Expression> & when_true,
|
||||
const ref::rp<Expression> & when_false)
|
||||
: Expression(exprtype::ifexpr, ifexpr_type),
|
||||
test_{test},
|
||||
when_true_{when_true},
|
||||
when_false_{when_false} {}
|
||||
|
||||
private:
|
||||
/** if:
|
||||
* (if x y z)
|
||||
|
|
@ -59,7 +76,7 @@ namespace xo {
|
|||
const ref::rp<Expression> & when_true,
|
||||
const ref::rp<Expression> & when_false)
|
||||
{
|
||||
return new IfExpr(test, when_true, when_false);
|
||||
return IfExpr::make(test, when_true, when_false);
|
||||
}
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@ namespace xo {
|
|||
**/
|
||||
class Lambda : public Expression {
|
||||
public:
|
||||
/** @p argv Formal parameters, in left-to-right order
|
||||
/**
|
||||
* @p name Name for this lambda -- must be unique
|
||||
* @p argv Formal parameters, in left-to-right order
|
||||
* @p body Expression for body of this function
|
||||
**/
|
||||
Lambda(const std::string & name,
|
||||
const std::vector<std::string> & argv,
|
||||
const ref::rp<Expression> & body);
|
||||
static ref::rp<Lambda> make(const std::string & name,
|
||||
const std::vector<ref::rp<Expression>> & argv,
|
||||
const ref::rp<Expression> & body);
|
||||
|
||||
/** downcast from Expression **/
|
||||
static ref::brw<Lambda> from(ref::brw<Expression> x) {
|
||||
|
|
@ -32,7 +34,7 @@ namespace xo {
|
|||
|
||||
const std::string & name() const { return name_; }
|
||||
const std::string & type_str() const { return type_str_; }
|
||||
const std::vector<std::string> & argv() const { return argv_; }
|
||||
const std::vector<ref::rp<Expression>> & argv() const { return argv_; }
|
||||
const ref::rp<Expression> & body() const { return body_; }
|
||||
|
||||
/** return number of arguments expected by this function **/
|
||||
|
|
@ -42,6 +44,15 @@ namespace xo {
|
|||
|
||||
virtual void display(std::ostream & os) const override;
|
||||
|
||||
private:
|
||||
/** @param lambda_type. function type for this lambda.
|
||||
* We arbitrarily choose the form "Retval(*)(Args...)"
|
||||
**/
|
||||
Lambda(const std::string & name,
|
||||
TypeDescr lambda_type,
|
||||
const std::vector<ref::rp<Expression>> & argv,
|
||||
const ref::rp<Expression> & body);
|
||||
|
||||
private:
|
||||
/** lambda name. Initially supporting only form like
|
||||
* (define (foo x y z)
|
||||
|
|
@ -56,17 +67,17 @@ namespace xo {
|
|||
**/
|
||||
std::string type_str_;
|
||||
/** formal argument names **/
|
||||
std::vector<std::string> argv_;
|
||||
std::vector<ref::rp<Expression>> argv_;
|
||||
/** function body **/
|
||||
ref::rp<Expression> body_;
|
||||
}; /*Lambda*/
|
||||
|
||||
inline ref::rp<Lambda>
|
||||
make_lambda(const std::string & name,
|
||||
const std::vector<std::string> & argv,
|
||||
const std::vector<ref::rp<Expression>> & argv,
|
||||
const ref::rp<Expression> & body)
|
||||
{
|
||||
return new Lambda(name, argv, body);
|
||||
return Lambda::make(name, argv, body);
|
||||
}
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ namespace xo {
|
|||
*
|
||||
* In any case, a primitive serves as both declaration and definition
|
||||
* (May be possible to relax this to declaration-only using null value_ as sentinel..?)
|
||||
*
|
||||
* @tparam FunctionPointer a function-pointer type, e.g. double(*)(double).
|
||||
* Must be in this "canonical form". std::function<double(double)>
|
||||
* won't work here.
|
||||
**/
|
||||
template <typename FunctionPointer>
|
||||
class Primitive: public PrimitiveInterface {
|
||||
|
|
@ -29,18 +33,12 @@ namespace xo {
|
|||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
|
||||
public:
|
||||
Primitive(const std::string & name,
|
||||
FunctionPointer fnptr)
|
||||
: PrimitiveInterface(),
|
||||
name_{name},
|
||||
value_td_{Reflect::require_function<FunctionPointer>()},
|
||||
value_{fnptr}
|
||||
{
|
||||
if (!value_td_->is_function())
|
||||
throw std::runtime_error("Primitive: expected function pointer");
|
||||
if (!value_td_->fn_retval())
|
||||
throw std::runtime_error("Primitive: expected non-null function return value");
|
||||
}
|
||||
static ref::rp<Primitive> make(const std::string & name,
|
||||
FunctionPointer fnptr) {
|
||||
TypeDescr fn_type = Reflect::require<FunctionPointer>();
|
||||
|
||||
return new Primitive(fn_type, name, fnptr);
|
||||
}
|
||||
|
||||
FunctionPointer value() const { return value_; }
|
||||
|
||||
|
|
@ -69,6 +67,22 @@ namespace xo {
|
|||
<< ">";
|
||||
}
|
||||
|
||||
private:
|
||||
Primitive(TypeDescr fn_type,
|
||||
const std::string & name,
|
||||
FunctionPointer fnptr)
|
||||
: PrimitiveInterface(fn_type),
|
||||
name_{name},
|
||||
value_td_{Reflect::require_function<FunctionPointer>()},
|
||||
value_{fnptr}
|
||||
{
|
||||
if (!value_td_->is_function())
|
||||
throw std::runtime_error("Primitive: expected function pointer");
|
||||
if (!value_td_->fn_retval())
|
||||
throw std::runtime_error("Primitive: expected non-null function return value");
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// from Expression:
|
||||
// exprtype extype_
|
||||
|
|
@ -85,7 +99,7 @@ namespace xo {
|
|||
template <typename FunctionPointer>
|
||||
ref::rp<Primitive<FunctionPointer>>
|
||||
make_primitive(const std::string & name, FunctionPointer x) {
|
||||
return new Primitive(name, x);
|
||||
return Primitive<FunctionPointer>::make(name, x);
|
||||
}
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ namespace xo {
|
|||
namespace ast {
|
||||
class PrimitiveInterface : public ConstantInterface {
|
||||
public:
|
||||
PrimitiveInterface() : ConstantInterface(exprtype::primitive) {}
|
||||
PrimitiveInterface(TypeDescr fn_type)
|
||||
: ConstantInterface(exprtype::primitive, fn_type) {}
|
||||
|
||||
/** downcast from Expression **/
|
||||
static ref::brw<PrimitiveInterface> from(ref::brw<Expression> x) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,14 @@ namespace xo {
|
|||
**/
|
||||
class Variable : public Expression {
|
||||
public:
|
||||
Variable(const std::string & name) : Expression(exprtype::variable), name_{name} {}
|
||||
/** create expression representing a variable
|
||||
* identified by @p name, that can take on values
|
||||
* described by @p var_type.
|
||||
**/
|
||||
static ref::rp<Variable> make(const std::string & name,
|
||||
TypeDescr var_type) {
|
||||
return new Variable(name, var_type);
|
||||
}
|
||||
|
||||
/** downcast from Expression **/
|
||||
static ref::brw<Variable> from(ref::brw<Expression> x) {
|
||||
|
|
@ -26,14 +33,21 @@ namespace xo {
|
|||
|
||||
virtual void display(std::ostream & os) const;
|
||||
|
||||
private:
|
||||
Variable(const std::string & name,
|
||||
TypeDescr var_type)
|
||||
: Expression(exprtype::variable, var_type),
|
||||
name_{name} {}
|
||||
|
||||
private:
|
||||
/** variable name **/
|
||||
std::string name_;
|
||||
}; /*Variable*/
|
||||
|
||||
inline ref::rp<Variable>
|
||||
make_var(const std::string & name) {
|
||||
return new Variable(name);
|
||||
make_var(const std::string & name,
|
||||
reflect::TypeDescr var_type) {
|
||||
return Variable::make(name, var_type);
|
||||
}
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
|
|
@ -4,7 +4,29 @@
|
|||
#include "xo/indentlog/print/vector.hpp"
|
||||
|
||||
namespace xo {
|
||||
using xo::ref::rp;
|
||||
|
||||
namespace ast {
|
||||
rp<Apply>
|
||||
Apply::make(const rp<Expression> & fn,
|
||||
const std::vector<rp<Expression>> & argv)
|
||||
{
|
||||
/* extract result type from function type */
|
||||
TypeDescr fn_valuetype = fn->valuetype();
|
||||
|
||||
if (!fn_valuetype->is_function()) {
|
||||
throw std::runtime_error
|
||||
(tostr("Apply::make: found expression F in function position,"
|
||||
" with value-type FT where a function type expected",
|
||||
xtag("FT", fn_valuetype->short_name()),
|
||||
xtag("F", fn_valuetype)));
|
||||
}
|
||||
|
||||
TypeDescr fn_retval_type = fn_valuetype->fn_retval();
|
||||
|
||||
return new Apply(fn_retval_type, fn, argv);
|
||||
}
|
||||
|
||||
void
|
||||
Apply::display(std::ostream & os) const {
|
||||
os << "<Apply"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,34 @@
|
|||
#include "xo/indentlog/print/vector.hpp"
|
||||
|
||||
namespace xo {
|
||||
using xo::ref::rp;
|
||||
|
||||
namespace ast {
|
||||
rp<IfExpr>
|
||||
IfExpr::make(const rp<Expression> & test,
|
||||
const rp<Expression> & when_true,
|
||||
const rp<Expression> & when_false)
|
||||
{
|
||||
/** TODO: verify test returns _boolean_ type **/
|
||||
|
||||
if (when_true->valuetype() != when_false->valuetype()) {
|
||||
throw std::runtime_error
|
||||
(tostr("IfExpr::make:"
|
||||
" types {T1,T2} found for branches of if-expr"
|
||||
" where equal types expected",
|
||||
xtag("T1", when_true->valuetype()->canonical_name()),
|
||||
xtag("T2", when_false->valuetype()->canonical_name())));
|
||||
}
|
||||
|
||||
/* arbitrary choice here */
|
||||
auto ifexpr_type = when_true->valuetype();
|
||||
|
||||
return new IfExpr(ifexpr_type,
|
||||
test,
|
||||
when_true,
|
||||
when_false);
|
||||
} /*make*/
|
||||
|
||||
void
|
||||
IfExpr::display(std::ostream & os) const {
|
||||
os << "<IfExpr"
|
||||
|
|
|
|||
|
|
@ -1,16 +1,55 @@
|
|||
/* @file Lambda.cpp */
|
||||
|
||||
#include "Lambda.hpp"
|
||||
#include "xo/reflect/TypeDescr.hpp"
|
||||
#include "xo/reflect/function/FunctionTdx.hpp"
|
||||
#include "xo/indentlog/print/vector.hpp"
|
||||
|
||||
namespace xo {
|
||||
using xo::reflect::TypeDescrBase;
|
||||
using xo::reflect::FunctionTdxInfo;
|
||||
using xo::ref::rp;
|
||||
using std::stringstream;
|
||||
|
||||
namespace ast {
|
||||
rp<Lambda>
|
||||
Lambda::make(const std::string & name,
|
||||
const std::vector<rp<Expression>> & argv,
|
||||
const ref::rp<Expression> & body)
|
||||
{
|
||||
using xo::reflect::FunctionTdx;
|
||||
|
||||
/** assemble function type.
|
||||
*
|
||||
* NOTE: need this to be unique!
|
||||
**/
|
||||
|
||||
std::vector<TypeDescr> arg_td_v;
|
||||
arg_td_v.reserve(argv.size());
|
||||
|
||||
for (const auto & arg : argv) {
|
||||
arg_td_v.push_back(arg->valuetype());
|
||||
}
|
||||
|
||||
auto function_info
|
||||
= FunctionTdxInfo(body->valuetype(),
|
||||
arg_td_v,
|
||||
false /*!is_noexcept*/);
|
||||
|
||||
TypeDescr lambda_td
|
||||
= TypeDescrBase::require_by_fn_info(function_info);
|
||||
|
||||
return new Lambda(name,
|
||||
lambda_td,
|
||||
argv,
|
||||
body);
|
||||
} /*make*/
|
||||
|
||||
Lambda::Lambda(const std::string & name,
|
||||
const std::vector<std::string> & argv,
|
||||
TypeDescr lambda_type,
|
||||
const std::vector<rp<Expression>> & argv,
|
||||
const ref::rp<Expression> & body)
|
||||
: Expression(exprtype::lambda),
|
||||
: Expression(exprtype::lambda, lambda_type),
|
||||
name_{name},
|
||||
argv_{argv},
|
||||
body_{body}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue