From 93b2daab6ca9811f5a526d3ebad24a08315eb13c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 23 Jul 2025 23:19:16 -0500 Subject: [PATCH] xo-reader xo-expression xo-tokenizer xo-jit: comparison + apply --- xo-expression/include/xo/expression/Apply.hpp | 38 +++- .../include/xo/expression/DefineExpr.hpp | 15 +- .../include/xo/expression/Primitive.hpp | 13 ++ .../include/xo/expression/Variable.hpp | 8 +- .../include/xo/expression/llvmintrinsic.hpp | 30 +++ .../include/xo/expression/pretty_localenv.hpp | 14 ++ xo-expression/src/expression/Apply.cpp | 16 ++ xo-expression/src/expression/DefineExpr.cpp | 45 ++--- xo-expression/src/expression/LocalEnv.cpp | 2 +- xo-expression/src/expression/Primitive.cpp | 38 ++++ xo-expression/src/expression/Variable.cpp | 41 ----- xo-jit/src/jit/MachPipeline.cpp | 14 ++ xo-reader/include/xo/reader/apply_xs.hpp | 113 ++++++++++++ .../include/xo/reader/expect_expr_xs.hpp | 12 +- xo-reader/include/xo/reader/exprstate.hpp | 5 + xo-reader/include/xo/reader/progress_xs.hpp | 21 +++ xo-reader/src/reader/CMakeLists.txt | 1 + xo-reader/src/reader/apply_xs.cpp | 174 ++++++++++++++++++ xo-reader/src/reader/define_xs.cpp | 86 ++++----- xo-reader/src/reader/expect_expr_xs.cpp | 46 +++-- xo-reader/src/reader/expect_type_xs.cpp | 4 +- xo-reader/src/reader/exprseq_xs.cpp | 2 +- xo-reader/src/reader/exprstate.cpp | 4 + xo-reader/src/reader/progress_xs.cpp | 98 ++++++++-- xo-reader/src/reader/reader.cpp | 3 +- .../include/xo/tokenizer/tokenizer.hpp | 40 +++- .../include/xo/tokenizer/tokentype.hpp | 5 + xo-tokenizer/src/tokenizer/tokentype.cpp | 3 + 28 files changed, 720 insertions(+), 171 deletions(-) create mode 100644 xo-reader/include/xo/reader/apply_xs.hpp create mode 100644 xo-reader/src/reader/apply_xs.cpp diff --git a/xo-expression/include/xo/expression/Apply.hpp b/xo-expression/include/xo/expression/Apply.hpp index 0dd1137a..a4eac339 100644 --- a/xo-expression/include/xo/expression/Apply.hpp +++ b/xo-expression/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/xo-expression/include/xo/expression/DefineExpr.hpp b/xo-expression/include/xo/expression/DefineExpr.hpp index 1dc7fad7..ce6e84ec 100644 --- a/xo-expression/include/xo/expression/DefineExpr.hpp +++ b/xo-expression/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/xo-expression/include/xo/expression/Primitive.hpp b/xo-expression/include/xo/expression/Primitive.hpp index 27c265d9..29409209 100644 --- a/xo-expression/include/xo/expression/Primitive.hpp +++ b/xo-expression/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/xo-expression/include/xo/expression/Variable.hpp b/xo-expression/include/xo/expression/Variable.hpp index 21f7d90b..2b4d70df 100644 --- a/xo-expression/include/xo/expression/Variable.hpp +++ b/xo-expression/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/xo-expression/include/xo/expression/llvmintrinsic.hpp b/xo-expression/include/xo/expression/llvmintrinsic.hpp index bc484640..b13bccac 100644 --- a/xo-expression/include/xo/expression/llvmintrinsic.hpp +++ b/xo-expression/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/xo-expression/include/xo/expression/pretty_localenv.hpp b/xo-expression/include/xo/expression/pretty_localenv.hpp index 14caebf5..83670af8 100644 --- a/xo-expression/include/xo/expression/pretty_localenv.hpp +++ b/xo-expression/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/xo-expression/src/expression/Apply.cpp b/xo-expression/src/expression/Apply.cpp index 7cb039b4..220b5aa5 100644 --- a/xo-expression/src/expression/Apply.cpp +++ b/xo-expression/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/xo-expression/src/expression/DefineExpr.cpp b/xo-expression/src/expression/DefineExpr.cpp index 3b2dbaf6..1d9ce563 100644 --- a/xo-expression/src/expression/DefineExpr.cpp +++ b/xo-expression/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/xo-expression/src/expression/LocalEnv.cpp b/xo-expression/src/expression/LocalEnv.cpp index 8e6ab0e7..f0458cbc 100644 --- a/xo-expression/src/expression/LocalEnv.cpp +++ b/xo-expression/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/xo-expression/src/expression/Primitive.cpp b/xo-expression/src/expression/Primitive.cpp index 350edae8..bc73ebd7 100644 --- a/xo-expression/src/expression/Primitive.cpp +++ b/xo-expression/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/xo-expression/src/expression/Variable.cpp b/xo-expression/src/expression/Variable.cpp index 663be6c6..4ad50357 100644 --- a/xo-expression/src/expression/Variable.cpp +++ b/xo-expression/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*/ diff --git a/xo-jit/src/jit/MachPipeline.cpp b/xo-jit/src/jit/MachPipeline.cpp index 826cc7c2..85fcc7e6 100644 --- a/xo-jit/src/jit/MachPipeline.cpp +++ b/xo-jit/src/jit/MachPipeline.cpp @@ -603,6 +603,20 @@ namespace xo { return ir_builder.CreateSDiv(args[1], args[2]); case llvmintrinsic::i_udiv: return ir_builder.CreateUDiv(args[1], args[2]); + + case llvmintrinsic::i_eq: + return ir_builder.CreateICmpEQ(args[1], args[2]); + case llvmintrinsic::i_ne: + return ir_builder.CreateICmpNE(args[1], args[2]); + case llvmintrinsic::i_sgt: + return ir_builder.CreateICmpSGT(args[1], args[2]); + case llvmintrinsic::i_sge: + return ir_builder.CreateICmpSGE(args[1], args[2]); + case llvmintrinsic::i_slt: + return ir_builder.CreateICmpSLT(args[1], args[2]); + case llvmintrinsic::i_sle: + return ir_builder.CreateICmpSLE(args[1], args[2]); + case llvmintrinsic::fp_add: return ir_builder.CreateFAdd(args[1], args[2]); case llvmintrinsic::fp_sub: diff --git a/xo-reader/include/xo/reader/apply_xs.hpp b/xo-reader/include/xo/reader/apply_xs.hpp new file mode 100644 index 00000000..f3975dab --- /dev/null +++ b/xo-reader/include/xo/reader/apply_xs.hpp @@ -0,0 +1,113 @@ +/* @file apply_xs.hpp */ + +#pragma once + +#include "exprstate.hpp" +#include "xo/expression/Apply.hpp" + + +namespace xo { + namespace scm { + /** + * fn ( arg1 , arg2 , .. , argn ) + * ^ ^ ^ ^ ^ ^ ^ ^ ^ + * | | | | | | | | (done) + * | | | | | | | apply_3 + * | | | | | | apply_2:expect_rhs_expression + * | | | | | apply_3 + * | | | | apply_2:expect_rhs_expression + * | | | apply_3 + * | | apply_2:expect_rhs_expression + * | apply_1 + * apply_0:expect_rhs_expression + * + * apply_0 --on_expr()--> apply_1 + * apply_1 --on_leftparen()--> apply_2 + * apply_2 --on_expr()--> apply_3 + * apply_3 --on_comma()--> apply_2 + * --on_rightparen()-> (done) + * + * apply_0: start + * apply_1: leftparen following expr allows parser to recognize apply + * apply_2: expect next argument + * apply_3: got argument, expect comma or rightparen to continue + * (done): apply complete, pop exprstate from stack + * + * In practice will start in state apply_1 + **/ + enum class applyexprstatetype { + invalid = -1, + + apply_0, + apply_1, + apply_2, + apply_3, + + n_applyexprstatetype + }; + + extern const char * applyexprstatetype_descr(applyexprstatetype x); + + std::ostream & + operator<<(std::ostream & os, applyexprstatetype x); + + /** @class apply_xs + * @brief state machine for parsing a schematic function-call-expression + * + */ + class apply_xs : public exprstate { + public: + using Apply = xo::ast::Apply; + + public: + explicit apply_xs(); + virtual ~apply_xs() = default; + + /** downcast from parent type **/ + static const apply_xs * from(const exprstate * x) { + return dynamic_cast(x); + } + + /** + * Start apply. Will trigger this after input like + * "fn(" + * + * apply_xs remains on expr stack until closing right paren + * fn(arg1-expr, arg2-expr, ...) + * + * @p fnex expression in function position + * @p p_psm parser state machine + **/ + static void start(rp fnex, + parserstatemachine * p_psm); + + virtual const char * get_expect_str() const override; + + virtual void on_expr(bp expr, + parserstatemachine * p_psm) override; + + virtual void on_comma_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_leftparen_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_rightparen_token(const token_type & tk, + parserstatemachine * p_psm) override; + + virtual void print(std::ostream & os) const override; + + private: + static std::unique_ptr make(); + + private: + /** current state of parser for this apply expression **/ + applyexprstatetype applyxs_type_ = applyexprstatetype::apply_0; + /** evaluates to function to be invoked **/ + rp fn_expr_; + /** evaluates to the arguments to pass to @ref fn_ **/ + std::vector> args_expr_v_; + }; + + } /*namespace scm */ +} /*namespace xo*/ + +/* end apply_xs.hpp */ diff --git a/xo-reader/include/xo/reader/expect_expr_xs.hpp b/xo-reader/include/xo/reader/expect_expr_xs.hpp index 148d728f..bfca1603 100644 --- a/xo-reader/include/xo/reader/expect_expr_xs.hpp +++ b/xo-reader/include/xo/reader/expect_expr_xs.hpp @@ -35,9 +35,14 @@ namespace xo { bool cxl_on_rightbrace, parserstatemachine * p_psm); + virtual const char * get_expect_str() const override; + virtual void on_lambda_token(const token_type & tk, parserstatemachine * p_psm) override; + virtual void on_if_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_def_token(const token_type & tk, parserstatemachine * p_psm) override; @@ -71,20 +76,21 @@ namespace xo { virtual void on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) override; + virtual void print(std::ostream & os) const override; private: static std::unique_ptr make(bool allow_defs, bool cxl_on_rightbrace); private: - /* if true: allow a define-expression here */ + /** if true: allow a define-expression here **/ bool allow_defs_ = false; - /* if true: expecting either: + /** if true: expecting either: * - expression * - right brace '}', in which case no expression * if false: expecting * - expression - */ + **/ bool cxl_on_rightbrace_ = false; }; diff --git a/xo-reader/include/xo/reader/exprstate.hpp b/xo-reader/include/xo/reader/exprstate.hpp index 781026a1..6d3f8cd6 100644 --- a/xo-reader/include/xo/reader/exprstate.hpp +++ b/xo-reader/include/xo/reader/exprstate.hpp @@ -30,6 +30,11 @@ namespace xo { **/ lambdaexpr, + /** handle apply expression (aka function call) + * see @ref apply_xs + **/ + applyexpr, + /** handle parenthesized expression * see @ref paren_xs **/ diff --git a/xo-reader/include/xo/reader/progress_xs.hpp b/xo-reader/include/xo/reader/progress_xs.hpp index 808c964b..8713a9f0 100644 --- a/xo-reader/include/xo/reader/progress_xs.hpp +++ b/xo-reader/include/xo/reader/progress_xs.hpp @@ -19,12 +19,30 @@ namespace xo { enum class optype { invalid = -1, + /** op:= **/ op_assign, + /** op< **/ + op_less, + /** op<= **/ + op_less_equal, + /** op== **/ + op_equal, + /** op!= **/ + op_not_equal, + /** op> **/ + op_great, + /** op>= **/ + op_great_equal, + + /** op+ **/ op_add, + /** op- **/ op_subtract, + /** op* **/ op_multiply, + /** op/ **/ op_divide, n_optype @@ -104,6 +122,9 @@ namespace xo { virtual void on_operator_token(const token_type & tk, parserstatemachine * p_psm) override; + virtual void on_bool_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_i64_token(const token_type & tk, parserstatemachine * p_psm) override; diff --git a/xo-reader/src/reader/CMakeLists.txt b/xo-reader/src/reader/CMakeLists.txt index 89e2cf98..e8e8bf02 100644 --- a/xo-reader/src/reader/CMakeLists.txt +++ b/xo-reader/src/reader/CMakeLists.txt @@ -11,6 +11,7 @@ set(SELF_SRCS define_xs.cpp if_else_xs.cpp progress_xs.cpp + apply_xs.cpp paren_xs.cpp sequence_xs.cpp exprseq_xs.cpp diff --git a/xo-reader/src/reader/apply_xs.cpp b/xo-reader/src/reader/apply_xs.cpp new file mode 100644 index 00000000..d5f5daed --- /dev/null +++ b/xo-reader/src/reader/apply_xs.cpp @@ -0,0 +1,174 @@ +/* @file apply_xs.cpp */ + +#include "apply_xs.hpp" +#include "parserstatemachine.hpp" +#include "expect_expr_xs.hpp" + +namespace xo { + namespace scm { + // ----- applyexprstatetype ----- + + const char * + applyexprstatetype_descr(applyexprstatetype x) { + switch (x) { + case applyexprstatetype::invalid: return "invalid"; + case applyexprstatetype::apply_0: return "apply_0"; + case applyexprstatetype::apply_1: return "apply_1"; + case applyexprstatetype::apply_2: return "apply_2"; + case applyexprstatetype::apply_3: return "apply_3"; + case applyexprstatetype::n_applyexprstatetype: break; + } + + return "???applyexprstatetype"; + } + + std::ostream & + operator<<(std::ostream & os, applyexprstatetype x) { + os << applyexprstatetype_descr(x); + return os; + } + + // ----- apply_xs ----- + + std::unique_ptr + apply_xs::make() { + return std::make_unique(apply_xs()); + } + + void + apply_xs::start(rp fn_expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + p_psm->push_exprstate(apply_xs::make()); + p_psm->top_exprstate().on_expr(fn_expr.get(), p_psm); + p_psm->top_exprstate().on_leftparen_token(token_type::leftparen(), p_psm); + } + + apply_xs::apply_xs() + : exprstate(exprstatetype::applyexpr) + {} + + const char * + apply_xs::get_expect_str() const { + switch(applyxs_type_) { + case applyexprstatetype::invalid: return "invalid"; + case applyexprstatetype::apply_0: return "expr"; + case applyexprstatetype::apply_1: return "lparen"; + case applyexprstatetype::apply_2: return "expr"; + case applyexprstatetype::apply_3: return "comma|rparen"; + case applyexprstatetype::n_applyexprstatetype: break; + } + + return "?expect"; + } + + void + apply_xs::on_expr(bp expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + switch (applyxs_type_) { + case applyexprstatetype::invalid: + case applyexprstatetype::n_applyexprstatetype: + // unreachable + break; + case applyexprstatetype::apply_0: + this->fn_expr_ = expr.promote(); + this->applyxs_type_ = applyexprstatetype::apply_1; + return; + case applyexprstatetype::apply_1: + // error, expecting lparen + break; + case applyexprstatetype::apply_2: + this->args_expr_v_.push_back(expr.promote()); + this->applyxs_type_ = applyexprstatetype::apply_3; + return; + case applyexprstatetype::apply_3: + // error, expecting comma|rparen + break; + } + + /* control here --implies-> error state */ + + constexpr const char * c_self_name = "apply_xs::on_expr"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_expr(c_self_name, expr, exp, p_psm); + } + + void + apply_xs::on_comma_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + if (this->applyxs_type_ == applyexprstatetype::apply_3) { + this->applyxs_type_ = applyexprstatetype::apply_2; + } else { + constexpr const char * c_self_name = "apply_xs::on_comma_token"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + } + + void + apply_xs::on_leftparen_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("applyxs_type", applyxs_type_); + + if (this->applyxs_type_ == applyexprstatetype::apply_1) { + this->applyxs_type_ = applyexprstatetype::apply_2; + } else { + constexpr const char * c_self_name = "apply_xs::on_leftparen_token"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + } + + void + apply_xs::on_rightparen_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("applyxs_type", applyxs_type_); + + if (this->applyxs_type_ == applyexprstatetype::apply_3) { + /* (done) state */ + + rp apply_expr = Apply::make(this->fn_expr_, this->args_expr_v_); + + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->top_exprstate().on_expr(apply_expr, p_psm); + return; + } + + constexpr const char * c_self_name = "apply_xs::on_rightparen_token"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + + void + apply_xs::print(std::ostream & os) const + { + os << ""; + } + + } /*namespace scm*/ +} /*namespace xo*/ + + +/* end apply_xs.cpp */ diff --git a/xo-reader/src/reader/define_xs.cpp b/xo-reader/src/reader/define_xs.cpp index 502d5dc5..c4e1a4a4 100644 --- a/xo-reader/src/reader/define_xs.cpp +++ b/xo-reader/src/reader/define_xs.cpp @@ -1,7 +1,6 @@ /* @file define_xs.cpp */ #include "define_xs.hpp" -#include "exprstatestack.hpp" #include "parserstatemachine.hpp" #include "expect_symbol_xs.hpp" #include "expect_expr_xs.hpp" @@ -45,8 +44,7 @@ namespace xo { void define_xs::start(parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); p_psm->push_exprstate(define_xs::make()); p_psm->top_exprstate().on_def_token(token_type::def(), p_psm); @@ -103,8 +101,7 @@ namespace xo { define_xs::on_expr(bp expr, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); log && log(xtag("defxs_type", defxs_type_)); @@ -118,10 +115,12 @@ namespace xo { */ rp rhs_value = expr.promote(); - if (this->cvt_expr_) + if (this->cvt_expr_) { this->cvt_expr_->assign_arg(rhs_value); - else - this->def_expr_->assign_rhs(rhs_value);; + } else { + /* note: establishes .def_expr_ valuetype */ + this->def_expr_->assign_rhs(rhs_value); + } rp def_expr = this->def_expr_; @@ -139,8 +138,7 @@ namespace xo { define_xs::on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); log && log(xtag("defxs_type", defxs_type_)); @@ -153,14 +151,40 @@ namespace xo { define_xs::on_symbol(const std::string & symbol_name, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); log && log("defxs_type", defxs_type_); if (this->defxs_type_ == defexprstatetype::def_1) { this->defxs_type_ = defexprstatetype::def_2; this->def_expr_->assign_lhs_name(symbol_name); + + // if this is a genuine top-level define (i.e. nesting level = 0), + // then we need to upsert so we can refer to rhs later. + // + // In other contexts (e.g. body-of-lambda) will be rewriting + // { + // def y = foo(x,x); + // bar(y,y); + // } + // into something like + // { + // (lambda (y123) bar(y123,y123))(foo(x,x)); + // } + // + // This works in the body of lambda, because we don't evaluate anything + // until lambda definition is complete. + // + // For interactive top-level defs we want to evaluate as we go, + // so need incremental bindings. + + if (p_psm->env_stack_size() == 2) { + /* remember variable binding in lexical context, + * so we can refer to it later + */ + p_psm->upsert_var(this->def_expr_->lhs_variable()); + } + return; } @@ -174,8 +198,7 @@ namespace xo { define_xs::on_typedescr(TypeDescr td, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); log && log("defxs_type", defxs_type_); @@ -183,6 +206,7 @@ namespace xo { this->defxs_type_ = defexprstatetype::def_4; this->cvt_expr_ = ConvertExprAccess::make(td /*dest_type*/, nullptr /*source_expr*/); + /* note: establishes .def_expr_ valuetype */ this->def_expr_->assign_rhs(this->cvt_expr_); return; } @@ -243,8 +267,7 @@ namespace xo { { /* def expr consumes semicolon */ - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); log && log("defxs_type", defxs_type_); @@ -253,32 +276,6 @@ namespace xo { std::unique_ptr self = p_psm->pop_exprstate(); - // if this is a genuine top-level define (i.e. nesting level = 0), - // then we need to upsert so we can refer to rhs later. - // - // In other contexts (e.g. body-of-lambda) will be rewriting - // { - // def y = foo(x,x); - // bar(y,y); - // } - // into something like - // { - // (lambda (y123) bar(y123,y123))(foo(x,x)); - // } - // - // This works in the body of lambda, because we don't evaluate anything - // until lambda definition is complete. - // - // For interactive top-level defs we want to evaluate as we go, - // so need incremental bindings. - - if (p_psm->env_stack_size() == 1) { - /* remember variable binding in lexical context, - * so we can refer to it later - */ - p_psm->upsert_var(def_expr->lhs_variable()); - } - p_psm->top_exprstate().on_expr(def_expr, p_psm); return; } @@ -357,11 +354,6 @@ namespace xo { << xtag("this", (void*)this) //<< xtag("type", exs_type_) << xtag("defxs_type", defxs_type_); - - //if (def_expr_) - // os << xtag("def_expr", def_expr_); - //if (cvt_expr_) - // os << xtag("cvt_expr", cvt_expr_); os << ">"; } } /*namespace scm*/ diff --git a/xo-reader/src/reader/expect_expr_xs.cpp b/xo-reader/src/reader/expect_expr_xs.cpp index 68a489b0..e899f3cb 100644 --- a/xo-reader/src/reader/expect_expr_xs.cpp +++ b/xo-reader/src/reader/expect_expr_xs.cpp @@ -6,8 +6,9 @@ #include "expect_expr_xs.hpp" #include "parserstatemachine.hpp" #include "exprstatestack.hpp" -#include "lambda_xs.hpp" #include "define_xs.hpp" +#include "lambda_xs.hpp" +#include "if_else_xs.hpp" #include "paren_xs.hpp" #include "sequence_xs.hpp" #include "progress_xs.hpp" @@ -52,12 +53,21 @@ namespace xo { cxl_on_rightbrace_{cxl_on_rightbrace} {} + const char * + expect_expr_xs::get_expect_str() const + { + if (allow_defs_) { + return "def|lambda|lparen|lbrace|literal|var"; + } else { + return "lambda|lparen|lbrace|literal|var"; + } + } + void expect_expr_xs::on_def_token(const token_type & tk, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); if (allow_defs_) { define_xs::start(p_psm); @@ -70,20 +80,25 @@ namespace xo { expect_expr_xs::on_lambda_token(const token_type & /*tk*/, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); //constexpr const char * self_name = "exprstate::on_leftparen"; lambda_xs::start(p_psm); } + void + expect_expr_xs::on_if_token(const token_type & /*tk*/, + parserstatemachine * p_psm) + { + if_else_xs::start(p_psm); + } + void expect_expr_xs::on_leftparen_token(const token_type & /*tk*/, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); //constexpr const char * self_name = "exprstate::on_leftparen"; @@ -95,8 +110,7 @@ namespace xo { expect_expr_xs::on_leftbrace_token(const token_type & /*tk*/, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); /* push lparen_0 to remember to look for subsequent rightparen. */ sequence_xs::start(p_psm); @@ -124,8 +138,7 @@ namespace xo { expect_expr_xs::on_symbol_token(const token_type & tk, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); log && log(xtag("tk", tk)); @@ -199,8 +212,7 @@ namespace xo { expect_expr_xs::on_f64_token(const token_type & tk, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); //constexpr const char * self_name = "exprstate::on_f64_token"; @@ -243,6 +255,14 @@ namespace xo { p_psm->on_expr_with_semicolon(expr); } /*on_expr_with_semicolon*/ + void + expect_expr_xs::print(std::ostream & os) const { + os << ""; + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/xo-reader/src/reader/expect_type_xs.cpp b/xo-reader/src/reader/expect_type_xs.cpp index 430a7004..f986ab50 100644 --- a/xo-reader/src/reader/expect_type_xs.cpp +++ b/xo-reader/src/reader/expect_type_xs.cpp @@ -43,7 +43,9 @@ namespace xo { /* TODO: replace with typetable lookup */ - if (tk.text() == "f64") + if (tk.text() == "bool") + td = Reflect::require(); + else if (tk.text() == "f64") td = Reflect::require(); else if(tk.text() == "f32") td = Reflect::require(); diff --git a/xo-reader/src/reader/exprseq_xs.cpp b/xo-reader/src/reader/exprseq_xs.cpp index b689831e..03314cd7 100644 --- a/xo-reader/src/reader/exprseq_xs.cpp +++ b/xo-reader/src/reader/exprseq_xs.cpp @@ -72,7 +72,7 @@ namespace xo { { /* in interactive session, allow top-level if-expressions. * Could be: - * if sometest() do_something() do_otherthing(); + * if sometest() then do_something() else do_otherthing(); */ if_else_xs::start(p_psm); } else { diff --git a/xo-reader/src/reader/exprstate.cpp b/xo-reader/src/reader/exprstate.cpp index d4b5e34a..07612db4 100644 --- a/xo-reader/src/reader/exprstate.cpp +++ b/xo-reader/src/reader/exprstate.cpp @@ -34,6 +34,8 @@ namespace xo { return "defexpr"; case exprstatetype::lambdaexpr: return "lambdaexpr"; + case exprstatetype::applyexpr: + return "applyexpr"; case exprstatetype::parenexpr: return "parenexpr"; case exprstatetype::sequenceexpr: @@ -450,6 +452,8 @@ namespace xo { case tokentype::tk_minus: case tokentype::tk_star: case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: this->on_operator_token(tk, p_psm); return; diff --git a/xo-reader/src/reader/progress_xs.cpp b/xo-reader/src/reader/progress_xs.cpp index ca137fdd..a09b8c26 100644 --- a/xo-reader/src/reader/progress_xs.cpp +++ b/xo-reader/src/reader/progress_xs.cpp @@ -1,6 +1,7 @@ /* @file progress_xs.cpp */ #include "progress_xs.hpp" +#include "apply_xs.hpp" #include "exprstatestack.hpp" #include "expect_expr_xs.hpp" #include "parserstatemachine.hpp" @@ -23,6 +24,18 @@ namespace xo { return "?optype"; case optype::op_assign: return "op:="; + case optype::op_less: + return "op<"; + case optype::op_less_equal: + return "op<="; + case optype::op_equal: + return "op=="; + case optype::op_not_equal: + return "op!="; + case optype::op_great: + return "op>"; + case optype::op_great_equal: + return "op>="; case optype::op_add: return "op+"; case optype::op_subtract: @@ -47,13 +60,21 @@ namespace xo { case optype::op_assign: return 1; + case optype::op_less: + case optype::op_less_equal: + case optype::op_equal: + case optype::op_not_equal: + case optype::op_great: + case optype::op_great_equal: + return 2; + case optype::op_add: case optype::op_subtract: - return 2; + return 3; case optype::op_multiply: case optype::op_divide: - return 3; + return 4; } return 0; @@ -145,21 +166,27 @@ namespace xo { this->rhs_); } + case optype::op_equal: + return Apply::make_cmp_eq_i64(lhs_, rhs_); + + case optype::op_less: + case optype::op_less_equal: + case optype::op_not_equal: + case optype::op_great: + case optype::op_great_equal: + assert(false); + case optype::op_add: - return Apply::make_add2_f64(this->lhs_, - this->rhs_); + return Apply::make_add2_f64(lhs_, rhs_); case optype::op_subtract: - return Apply::make_sub2_f64(this->lhs_, - this->rhs_); + return Apply::make_sub2_f64(lhs_, rhs_); case optype::op_multiply: - return Apply::make_mul2_f64(this->lhs_, - this->rhs_); + return Apply::make_mul2_f64(lhs_, rhs_); case optype::op_divide: - return Apply::make_div2_f64(this->lhs_, - this->rhs_); + return Apply::make_div2_f64(lhs_, rhs_); case optype::n_optype: /* unreachable */ @@ -301,8 +328,25 @@ namespace xo { progress_xs::on_leftparen_token(const token_type & tk, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); + + /* input like: + * 'foo(' -> expect function call. might continue 'foo(a,b,c)' + * 'foo+(' -> expect parenthesized expression. might continue 'foo+(bar/2)' + */ + + if (op_type_ == optype::invalid) { + /* start function call */ + assert(rhs_.get() == nullptr); + + /* unwind this progress_xs + replace with function call */ + + rp fn_expr = lhs_; + std::unique_ptr self = p_psm->pop_exprstate(); + + apply_xs::start(fn_expr, p_psm); + return; + } constexpr const char * c_self_name = "exprstate::on_leftparen"; const char * exp = get_expect_str(); @@ -320,7 +364,7 @@ namespace xo { constexpr const char * self_name = "progress_xs::on_rightparen"; - auto p_stack = p_psm->p_stack_; + auto & xs_stack = p_psm->xs_stack_; /* stack may be something like: * @@ -338,12 +382,12 @@ namespace xo { std::unique_ptr self = p_psm->pop_exprstate(); - if (p_stack->empty()) { + if (xs_stack.empty()) { throw std::runtime_error(tostr(self_name, ": expected non-empty parsing stack")); } - log && log(xtag("stack", p_stack)); + log && log(xtag("stack", &xs_stack)); p_psm->top_exprstate().on_expr(expr, p_psm); @@ -406,6 +450,10 @@ namespace xo { return optype::op_multiply; case tokentype::tk_slash: return optype::op_divide; + case tokentype::tk_cmpeq: + return optype::op_equal; + case tokentype::tk_cmpne: + return optype::op_not_equal; default: assert(false); return optype::invalid; @@ -487,6 +535,22 @@ namespace xo { } } + void + progress_xs::on_bool_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + constexpr const char * c_self_name = "progress_xs::on_bool_token"; + const char * exp = get_expect_str(); + + if (this->op_type_ == optype::invalid) { + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } else { + exprstate::on_bool_token(tk, p_psm); + } + } + void progress_xs::on_i64_token(const token_type & tk, parserstatemachine * p_psm) @@ -494,7 +558,7 @@ namespace xo { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); - constexpr const char * c_self_name = "progress_xs::on_i64"; + constexpr const char * c_self_name = "progress_xs::on_i64_token"; const char * exp = get_expect_str(); if (this->op_type_ == optype::invalid) { @@ -511,7 +575,7 @@ namespace xo { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); - constexpr const char * c_self_name = "progress_xs::on_f64"; + constexpr const char * c_self_name = "progress_xs::on_f64_token"; const char * exp = get_expect_str(); if (this->op_type_ == optype::invalid) { diff --git a/xo-reader/src/reader/reader.cpp b/xo-reader/src/reader/reader.cpp index 7f1080f3..37a64d6b 100644 --- a/xo-reader/src/reader/reader.cpp +++ b/xo-reader/src/reader/reader.cpp @@ -128,7 +128,8 @@ namespace xo { } } - log && log(xtag("outcome", "noop")); + log && log(xtag("outcome", "noop"), + xtag("parser.stack_size", parser_.stack_size())); return reader_result(nullptr, expr_span, parser_.stack_size(), reader_error()); } diff --git a/xo-tokenizer/include/xo/tokenizer/tokenizer.hpp b/xo-tokenizer/include/xo/tokenizer/tokenizer.hpp index 8c1b131a..258d4900 100644 --- a/xo-tokenizer/include/xo/tokenizer/tokenizer.hpp +++ b/xo-tokenizer/include/xo/tokenizer/tokenizer.hpp @@ -211,7 +211,11 @@ namespace xo { /* can't be 1char punctuation -- can begin assignment token */ return false; case '=': - return true; + /* can't be 1char punctuation -- can begin comparison token '==' */ + return false; + case '!': + /* can't be 1char punctuation -- can begin comparison token '!=' */ + return false; case '-': /* can't be punctuation * - can appear inside f64 token: e.g. 1.23e-9. @@ -246,6 +250,12 @@ namespace xo { case ':': /* can begin := */ return true; + case '=': + /* can begin == */ + return true; + case '!': + /* can begin != */ + return true; } return false; @@ -446,6 +456,30 @@ namespace xo { ++ix; } break; + case '=': + log && log("singleassign or cmpeq token"); + + if (*(ix + 1) == '=') { + tk_type = tokentype::tk_cmpeq; + ++ix; + ++ix; + } else { + /* standalone '=' */ + tk_type = tokentype::tk_singleassign; + ++ix; + } + break; + case '!': + if (*(ix + 1) == '=') { + tk_type = tokentype::tk_cmpne; + ++ix; + ++ix; + } else { + /* standlone '!' */ + + // TODO + } + break; case '"': { log && log("recognize string-token"); @@ -638,10 +672,6 @@ namespace xo { } break; } - case '=': - tk_type = tokentype::tk_singleassign; - ++ix; - break; default: break; } diff --git a/xo-tokenizer/include/xo/tokenizer/tokentype.hpp b/xo-tokenizer/include/xo/tokenizer/tokentype.hpp index 81a852fa..92d9bf60 100644 --- a/xo-tokenizer/include/xo/tokenizer/tokentype.hpp +++ b/xo-tokenizer/include/xo/tokenizer/tokentype.hpp @@ -126,6 +126,11 @@ namespace xo { /** operator @c '/' **/ tk_slash, + /** operator @c '==' **/ + tk_cmpeq, + /** operator @c '!=' **/ + tk_cmpne, + /** keyword @c 'type' **/ tk_type, diff --git a/xo-tokenizer/src/tokenizer/tokentype.cpp b/xo-tokenizer/src/tokenizer/tokentype.cpp index c19d023b..745651a7 100644 --- a/xo-tokenizer/src/tokenizer/tokentype.cpp +++ b/xo-tokenizer/src/tokenizer/tokentype.cpp @@ -43,6 +43,9 @@ namespace xo { CASE(tk_star); CASE(tk_slash); + CASE(tk_cmpeq); + CASE(tk_cmpne); + CASE(tk_type); CASE(tk_def); CASE(tk_lambda);