diff --git a/include/xo/expression/Apply.hpp b/include/xo/expression/Apply.hpp index 0dd1137a..a4eac339 100644 --- a/include/xo/expression/Apply.hpp +++ b/include/xo/expression/Apply.hpp @@ -28,6 +28,13 @@ namespace xo { static rp make(const rp & fn, const std::vector> & argv); + /** create apply-expression to compare two 64-bit integers **/ + static rp make_cmp_eq_i64(const rp & lhs, + const rp & rhs); + /** create apply-expression to compare two 64-bit integers **/ + static rp make_cmp_ne_i64(const rp & lhs, + const rp & rhs); + /** create apply-expression to add two 64-bit floating-point numbers **/ static rp make_add2_f64(const rp & lhs, const rp & rhs); @@ -103,7 +110,7 @@ namespace xo { virtual void display(std::ostream & os) const override; virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const override; - private: + protected: Apply(TypeDescr apply_valuetype, const rp & fn, const std::vector> & argv) @@ -111,7 +118,7 @@ namespace xo { fn_{fn}, argv_(argv) {} - private: + protected: /** function to invoke **/ rp fn_; /** argument expressions, in l-to-r order **/ @@ -152,6 +159,33 @@ namespace xo { return Apply::make(fn, argv); } /*make_apply*/ + /** @class ApplyAccess + * @brief Apply with writeable members + * + * Convenient when scaffolding a parser, + * e.g. see xo-parser + **/ + class ApplyAccess : public Apply { + public: + static rp make_empty(); + + /** assign function being called to @p fn **/ + void assign_fn(const rp& fn); + /** assign expression for argument i, counting from 1. + * can use @p i = 0 as alternative to @ ref assign_fn + **/ + void assign_arg(size_t i, const rp& arg); + + // inherited from GeneralizedExpression.. + // void assign_valuetype(TypeDescr apply_valuetype); + + private: + ApplyAccess(TypeDescr apply_valuetype, + const rp& fn, + const std::vector>& argv) + : Apply(apply_valuetype, fn, argv) {} + }; + } /*namespace ast*/ } /*namespace xo*/ diff --git a/include/xo/expression/DefineExpr.hpp b/include/xo/expression/DefineExpr.hpp index 1dc7fad7..ce6e84ec 100644 --- a/include/xo/expression/DefineExpr.hpp +++ b/include/xo/expression/DefineExpr.hpp @@ -21,6 +21,10 @@ namespace xo { * is equivalent to * * (lambda (foo) body...)(rhsexpr) + * + * Promise: + * - memory location of @ref lhs_var_ is determined when parent DefineExpr + * constructed, and is stable across calls to @ref DefineExpr::assign_lhs_name **/ class DefineExpr : public Expression { public: @@ -32,10 +36,10 @@ namespace xo { return bp::from(x); } - const std::string & lhs_name() const { return lhs_name_; } + const std::string & lhs_name() const; const rp & rhs() const { return rhs_; } - rp lhs_variable() const; + const rp& lhs_variable() const { return lhs_var_; } std::set calc_free_variables() const; @@ -88,7 +92,7 @@ namespace xo { protected: /** symbol name for this definition **/ - std::string lhs_name_; + rp lhs_var_; /** right-hand side of definition **/ rp rhs_; @@ -108,10 +112,7 @@ namespace xo { rp rhs); static rp make_empty(); - void assign_lhs_name(const std::string & x) { - this->lhs_name_ = x; - } - + void assign_lhs_name(const std::string & x); void assign_rhs(const rp & x); private: diff --git a/include/xo/expression/Primitive.hpp b/include/xo/expression/Primitive.hpp index 27c265d9..29409209 100644 --- a/include/xo/expression/Primitive.hpp +++ b/include/xo/expression/Primitive.hpp @@ -191,6 +191,19 @@ namespace xo { return Primitive::make(name, x, explicit_symbol_def, intrinsic); } + /** builtin primitives :: i64 x i64 -> bool **/ + class Primitive_cmp_i64 : public Primitive { + public: + using PrimitiveType = Primitive; + + public: + /** eq2_i64: compare two 64-bit integers for equality **/ + static rp make_cmp_eq2_i64(); + /** ne2_i64: compare two 64-bit integers for inequality **/ + static rp make_cmp_ne2_i64(); + }; + + /** builtin primitives :: f64 x f64 -> f64 **/ class Primitive_f64 : public Primitive { public: using PrimitiveType = Primitive; diff --git a/include/xo/expression/Variable.hpp b/include/xo/expression/Variable.hpp index 21f7d90b..2b4d70df 100644 --- a/include/xo/expression/Variable.hpp +++ b/include/xo/expression/Variable.hpp @@ -40,6 +40,8 @@ namespace xo { return bp::from(x); } + void assign_name(const std::string & name) { name_ = name; } + const std::string & name() const { return name_; } virtual std::set get_free_variables() const override { @@ -76,8 +78,10 @@ namespace xo { private: /** variable name **/ std::string name_; - /** navigate environment via this path to find runtime memory - * location for this variable + /** Eventually: navigate environment via this path to find runtime memory + * location for this variable. + * + * Establish via @ref attach_envs **/ binding_path path_; }; /*Variable*/ diff --git a/include/xo/expression/llvmintrinsic.hpp b/include/xo/expression/llvmintrinsic.hpp index bc484640..b13bccac 100644 --- a/include/xo/expression/llvmintrinsic.hpp +++ b/include/xo/expression/llvmintrinsic.hpp @@ -62,6 +62,26 @@ namespace xo { /** -> IRBuilder::CreateUdiv (divide 2 unsigned integers) **/ i_udiv, + /** -> IRBuilder::CreateICmpEQ (test integers for equality) **/ + i_eq, + + /** -> IRBuilder::CreateICmpNE (test integers for inequality) **/ + i_ne, + + /** -> IRBuilder::CreateICmpSGT (test signed integers for greater) **/ + i_sgt, + + /** -> IRBuilder::CreateICmpSGE (test signed integers for greater-or-equal) **/ + i_sge, + + /** -> IRBuilder::CreateICmpSLT (test signed integers for lesser) **/ + i_slt, + + /** -> IRBuilder::CreateCmpSLE (test signed integers for lesser-or-equal) **/ + i_sle, + + // TODO: unsigned comparisons + /** -> IRBuilder::CreateFadd (add 2 floating-point numbers) **/ fp_add, @@ -74,6 +94,8 @@ namespace xo { /** -> IRBuilder::CreateFdiv (divide 2 floating-point numbers) **/ fp_div, + // TODO: floating-point comparisons + /** * want to do whatever llvm IR @c llvm.sqrt.f64 and friends do. * Not sure if that's an always-available function of something else @@ -107,6 +129,14 @@ namespace xo { case llvmintrinsic::i_mul: return "i_mul"; case llvmintrinsic::i_sdiv: return "i_sdiv"; case llvmintrinsic::i_udiv: return "i_udiv"; + + case llvmintrinsic::i_eq: return "i_eq"; + case llvmintrinsic::i_ne: return "i_ne"; + case llvmintrinsic::i_sgt: return "i_sgt"; + case llvmintrinsic::i_sge: return "i_sge"; + case llvmintrinsic::i_slt: return "i_slt"; + case llvmintrinsic::i_sle: return "i_sle"; + case llvmintrinsic::fp_add: return "fp_add"; case llvmintrinsic::fp_sub: return "fp_sub"; case llvmintrinsic::fp_mul: return "fp_mul"; diff --git a/include/xo/expression/pretty_localenv.hpp b/include/xo/expression/pretty_localenv.hpp index 14caebf5..83670af8 100644 --- a/include/xo/expression/pretty_localenv.hpp +++ b/include/xo/expression/pretty_localenv.hpp @@ -14,5 +14,19 @@ namespace xo { return x.pretty_print(ppii); } }; + + template <> + struct ppdetail { + static bool print_pretty(const ppindentinfo & ppii, const xo::ast::LocalEnv* x) { + if (x) { + return x->pretty_print(ppii); + } else { + ppii.pps()->write("write(reflect::type_name()); + ppii.pps()->write(">"); + return ppii.pps()->has_margin(); + } + } + }; } } diff --git a/src/expression/Apply.cpp b/src/expression/Apply.cpp index 7cb039b4..220b5aa5 100644 --- a/src/expression/Apply.cpp +++ b/src/expression/Apply.cpp @@ -30,6 +30,22 @@ namespace xo { return new Apply(fn_retval_type, fn, argv); } + rp + Apply::make_cmp_eq_i64(const rp & lhs, + const rp & rhs) + { + return Apply::make(Primitive_cmp_i64::make_cmp_eq2_i64(), + {lhs, rhs}); + } + + rp + Apply::make_cmp_ne_i64(const rp & lhs, + const rp & rhs) + { + return Apply::make(Primitive_cmp_i64::make_cmp_ne2_i64(), + {lhs, rhs}); + } + rp Apply::make_add2_f64(const rp & lhs, const rp & rhs) diff --git a/src/expression/DefineExpr.cpp b/src/expression/DefineExpr.cpp index 3b2dbaf6..1d9ce563 100644 --- a/src/expression/DefineExpr.cpp +++ b/src/expression/DefineExpr.cpp @@ -28,17 +28,14 @@ namespace xo { std::string lhs_name, rp rhs) : Expression(exprtype::define, rhs_valuetype), - lhs_name_{std::move(lhs_name)}, + lhs_var_{Variable::make(lhs_name, rhs_valuetype)}, rhs_{std::move(rhs)} { this->free_var_set_ = this->calc_free_variables(); } - rp - DefineExpr::lhs_variable() const - { - return Variable::make(lhs_name(), valuetype()); - } + const std::string & + DefineExpr::lhs_name() const { return lhs_var_->name(); } std::set DefineExpr::calc_free_variables() const @@ -58,7 +55,7 @@ namespace xo { void DefineExpr::display(std::ostream & os) const { os << "name()) << xtag("rhs", rhs_) << ">"; } /*display*/ @@ -67,30 +64,8 @@ namespace xo { DefineExpr::pretty_print(const ppindentinfo & ppii) const { return ppii.pps()->pretty_struct(ppii, "Define", - refrtag("name", lhs_name_), + refrtag("name", lhs_var_->name()), refrtag("rhs", rhs_)); - -#ifdef OBSOLETE - ppstate * pps = ppii.pps(); - - if (ppii.upto()) { - if (!pps->print_upto("print_upto_tag("name", lhs_name_)) - return false; - if (!pps->print_upto_tag("rhs", rhs_)) - return false; - - return true; - } else { - pps->write("newline_pretty_tag(ppii.ci1(), "name", lhs_name_); - pps->newline_pretty_tag(ppii.ci1(), "rhs", rhs_); - pps->write(">"); - - return false; - } -#endif } // ----- DefineExprAccess ----- @@ -117,6 +92,12 @@ namespace xo { nullptr /*rhs*/); } + void + DefineExprAccess::assign_lhs_name(const std::string & x) + { + this->lhs_var_->assign_name(x); + } + void DefineExprAccess::assign_rhs(const rp & x) { @@ -125,6 +106,10 @@ namespace xo { this->rhs_ = x; if (x) { + if (lhs_var_ && !lhs_var_->valuetype()) { + this->lhs_var_->assign_valuetype(x->valuetype()); + } + this->assign_valuetype(x->valuetype()); } diff --git a/src/expression/LocalEnv.cpp b/src/expression/LocalEnv.cpp index 8e6ab0e7..f0458cbc 100644 --- a/src/expression/LocalEnv.cpp +++ b/src/expression/LocalEnv.cpp @@ -97,7 +97,7 @@ namespace xo { LocalEnv::upsert_local(bp target) { for (auto & var : this->argv_) { if (var->name() == target->name()) { - /* replace existing variable. May change its type */ + /* replace existing variable. This may change its type */ var = target.promote(); return; } diff --git a/src/expression/Primitive.cpp b/src/expression/Primitive.cpp index 350edae8..bc73ebd7 100644 --- a/src/expression/Primitive.cpp +++ b/src/expression/Primitive.cpp @@ -3,6 +3,16 @@ #include "Primitive.hpp" extern "C" { + bool + cmp_eq2_i64(std::int64_t x, std::int64_t y) { + return x == y; + } + + bool + cmp_ne2_i64(std::int64_t x, std::int64_t y) { + return x != y; + } + double add2_f64(double x, double y) { return x + y; @@ -26,6 +36,34 @@ extern "C" { namespace xo { namespace ast { + auto + Primitive_cmp_i64::make_cmp_eq2_i64() -> rp + { + static rp s_retval; + + if (!s_retval) + s_retval = Primitive::make("cmp_eq2_i64", + &cmp_eq2_i64, + true /*explicit_symbol_def*/, + llvmintrinsic::i_eq); + + return s_retval; + } + + auto + Primitive_cmp_i64::make_cmp_ne2_i64() -> rp + { + static rp s_retval; + + if (!s_retval) + s_retval = Primitive::make("cmp_ne2_i64", + &cmp_ne2_i64, + true /*explicit_symbol_def*/, + llvmintrinsic::i_ne); + + return s_retval; + } + auto Primitive_f64::make_add2_f64() -> rp { diff --git a/src/expression/Variable.cpp b/src/expression/Variable.cpp index 663be6c6..4ad50357 100644 --- a/src/expression/Variable.cpp +++ b/src/expression/Variable.cpp @@ -49,47 +49,6 @@ namespace xo { rtag("type", print::quot(this->valuetype() ? this->valuetype()->short_name() : "nullptr"))); - -#ifdef OBSOLETE - ppstate * pps = ppii.pps(); - - if (ppii.upto()) { - if (!pps->print_upto("print_upto_tag("name", name_)) - return false; - - if (this->valuetype()) { - if (!pps->print_upto_tag("type", this->valuetype()->short_name())) - return false; - } else { - if (!pps->print_upto_tag("type", "nullptr")) - return false; - } - - pps->write(">"); - - return true; - } else { - pps->write("newline_pretty_tag(ppii.ci1(), "name", name_); - - /* use tag instead of rtag for type, - * since not guaranteed to print machine-readably - */ - if (this->valuetype()) { - pps->newline_indent(ppii.ci1()); - pps->pretty(xtag("type", this->valuetype()->short_name())); - } else { - pps->newline_pretty_tag(ppii.ci1(), "type", "nullptr"); - } - pps->write(">"); - - return false; - } -#endif } } /*namespace ast*/ } /*namespace xo*/