xo-reader2: + assemble lambda function type in DLambdaSsm

This commit is contained in:
Roland Conybeare 2026-01-30 12:41:09 -05:00
commit fcf171dfb6
8 changed files with 97 additions and 137 deletions

View file

@ -32,8 +32,7 @@ namespace xo {
bool allow_defs,
bool cxl_on_rightparen,
ParserStateMachine * p_psm);
static void start(DArena & parser_mm,
ParserStateMachine * p_psm);
static void start(ParserStateMachine * p_psm);
/** @defgroup scm-expectexpr-access-methods access methods **/
///@{

View file

@ -88,6 +88,12 @@ namespace xo {
void on_lambda_token(const Token & tk,
ParserStateMachine * p_psm);
/** update ssm on yield token @p tk,
* with overall parser state in @p p_psm
**/
void on_yields_token(const Token & tk,
ParserStateMachine * p_psm);
///@}
/** @defgroup scm-lambdassm-syntaxstatemachine-facet **/
///@{
@ -174,13 +180,11 @@ namespace xo {
/** lambda environment (for formal parameters) **/
DLocalSymtab * local_symtab_ = nullptr;
#ifdef NOT_YET
/** explicit return type (if supplied) **/
TypeDescr explicit_return_td_ = nullptr;
/** lambda signature (when known) **/
TypeDescr lambda_td_ = nullptr;
#endif
/** body expression **/
obj<AExpression> body_;

View file

@ -643,8 +643,7 @@ namespace xo {
{
this->defstate_ = defexprstatetype::def_5;
DExpectExprSsm::start(p_psm->parser_alloc(),
p_psm);
DExpectExprSsm::start(p_psm);
return;
}

View file

@ -83,10 +83,9 @@ namespace xo {
}
void
DExpectExprSsm::start(DArena & mm,
ParserStateMachine * p_psm)
DExpectExprSsm::start(ParserStateMachine * p_psm)
{
start(mm,
start(p_psm->parser_alloc(),
false /*!allow_defs*/,
false /*!cxl_on_rightbrace*/,
p_psm);

View file

@ -215,8 +215,7 @@ namespace xo {
if (ifstate_ == ifexprstatetype::if_0) {
this->ifstate_ = ifexprstatetype::if_1;
DExpectExprSsm::start(p_psm->parser_alloc(),
p_psm);
DExpectExprSsm::start(p_psm);
return;
}
@ -236,7 +235,7 @@ namespace xo {
if (ifstate_ == ifexprstatetype::if_2) {
this->ifstate_ = ifexprstatetype::if_3;
DExpectExprSsm::start(p_psm->parser_alloc(), p_psm);
DExpectExprSsm::start(p_psm);
return;
}
@ -279,7 +278,7 @@ namespace xo {
if (ifstate_ == ifexprstatetype::if_4) {
this->ifstate_ = ifexprstatetype::if_5;
DExpectExprSsm::start(p_psm->parser_alloc(), p_psm);
DExpectExprSsm::start(p_psm);
return;
}

View file

@ -7,6 +7,8 @@
#include "ssm/ISyntaxStateMachine_DLambdaSsm.hpp"
#include "DExpectFormalArglistSsm.hpp"
#include "ssm/ISyntaxStateMachine_DExpectFormalArglistSsm.hpp"
#include "DExpectTypeSsm.hpp"
#include "DExpectExprSsm.hpp"
#include "ParserStateMachine.hpp"
#include "syntaxstatetype.hpp"
#include <xo/expression2/DVariable.hpp>
@ -89,11 +91,11 @@ namespace xo {
DLambdaSsm::get_expect_str() const noexcept
{
/*
* lambda (x : f64) : f64 { ... } ;
* ^ ^ ^ ^ ^ ^
* | | | | | lm_5
* | | | | lm_4:expect_expression
* | | | lm_3
* lambda (x : f64) -> f64 { ... } ;
* ^ ^ ^ ^ ^ ^
* | | | | | lm_5
* | | | | lm_4:expect_expression
* | | | lm_3
* | | lm_2
* | lm_1:
* expect_expression
@ -108,7 +110,7 @@ namespace xo {
case lambdastatetype::lm_1:
return "lambda-params";
case lambdastatetype::lm_2:
return "colon|lambda-body";
return "yields|lambda-body";
case lambdastatetype::lm_3:
return "type";
case lambdastatetype::lm_4:
@ -129,6 +131,10 @@ namespace xo {
this->on_lambda_token(tk, p_psm);
return;
case tokentype::tk_yields:
this->on_yields_token(tk, p_psm);
return;
// all the not-yet-handled cases
case tokentype::tk_def:
case tokentype::tk_if:
@ -155,7 +161,6 @@ namespace xo {
case tokentype::tk_comma:
case tokentype::tk_doublecolon:
case tokentype::tk_assign:
case tokentype::tk_yields:
case tokentype::tk_plus:
case tokentype::tk_minus:
case tokentype::tk_star:
@ -194,25 +199,44 @@ namespace xo {
this->get_expect_str());
}
#ifdef NOT_YET
void
lambda_xs::on_formal_arglist(const std::vector<rp<Variable>> & argl,
parserstatemachine * p_psm)
DLambdaSsm::on_yields_token(const Token & tk,
ParserStateMachine * p_psm)
{
if (lmxs_type_ == lambdastatetype::lm_1) {
this->lmxs_type_ = lambdastatetype::lm_2;
this->parent_env_ = p_psm->top_envframe().promote();
this->local_env_ = LocalSymtab::make(argl, parent_env_);
if (lmstate_ == lambdastatetype::lm_2) {
this->lmstate_ = lambdastatetype::lm_3;
p_psm->push_envframe(local_env_);
DExpectTypeSsm::start(p_psm);
//expect_expr_xs::start(p_psm);
} else {
exprstate::on_formal_arglist(argl, p_psm);
/* control reenters via .on_parsed_typedescr() */
return;
}
p_psm->illegal_input_on_token("DLambdaSsm::on_yields_token",
tk,
this->get_expect_str());
}
void
DLambdaSsm::on_parsed_typedescr(TypeDescr td,
ParserStateMachine * p_psm)
{
if (lmstate_ == lambdastatetype::lm_3) {
this->lmstate_ = lambdastatetype::lm_4;
this->explicit_return_td_ = td;
this->lambda_td_ = DLambdaExpr::assemble_lambda_td(local_symtab_, td);
DExpectExprSsm::start(p_psm);
return;
}
p_psm->illegal_input_on_typedescr("DLambdaSsm::on_parsed_typedescr",
td,
this->get_expect_str());
}
#ifdef NOT_YET
void
lambda_xs::on_expr_with_semicolon(bp<Expression> expr,
parserstatemachine * p_psm)
@ -221,21 +245,6 @@ namespace xo {
this->on_semicolon_token(token_type::semicolon(), p_psm);
}
void
lambda_xs::on_colon_token(const token_type & tk,
parserstatemachine * p_psm)
{
constexpr const char * c_self_name = "lambda_xs::on_colon_token";
if (lmxs_type_ == lambdastatetype::lm_2) {
this->lmxs_type_ = lambdastatetype::lm_3;
expect_type_xs::start(p_psm);
/* control reenters via .on_typedescr() */
} else {
this->illegal_input_on_token(c_self_name, tk, this->get_expect_str(), p_psm);
}
}
void
lambda_xs::on_leftbrace_token(const token_type & tk,
parserstatemachine * p_psm)
@ -255,84 +264,6 @@ namespace xo {
}
#endif
void
DLambdaSsm::on_parsed_typedescr(TypeDescr td,
ParserStateMachine * p_psm)
{
p_psm->illegal_input_on_typedescr("DLambdaSsm::on_parsed_typedescr",
td,
this->get_expect_str());
}
#ifdef NOT_YET
void
lambda_xs::on_typedescr(TypeDescr td,
parserstatemachine * p_psm)
{
constexpr const char * c_self_name = "lambda_xs::on_typedescr";
scope log(XO_DEBUG(p_psm->debug_flag()));
assert(td);
if (lmxs_type_ == lambdastatetype::lm_3) {
this->lmxs_type_ = lambdastatetype::lm_4;
this->explicit_return_td_ = td;
this->lambda_td_ = Lambda::assemble_lambda_td(local_env_->argv(),
explicit_return_td_);
/* 1. at this point we know function signature (@ref lambda_td_)
* 2. if this lambda appears on the rhs of a define,
* propagate function signature to the define.
* 3. this makes recursive function definitions like this work
* without relying on type inference:
* def fact = lambda (n : i64) : i64 {
* if (n == 0) then
* 1
* else
* n * fact(n - 1)
* }
* 4. while parsing the body of the lambda, we want environment
* to already associate the lambda's signature with variable 'fact',
* so that when parser encounters 'fact(n - 1)' the expression has
* known valuetype.
*/
if ((p_psm->exprstate_stack_size() >= 3)
&& (p_psm->lookup_exprstate(1).exs_type() == exprstatetype::expect_rhs_expression)
&& (p_psm->lookup_exprstate(2).exs_type() == exprstatetype::defexpr)
&& (p_psm->env_stack_size() >= 2)
)
{
const define_xs * def_xs = dynamic_cast<const define_xs*>(&(p_psm->lookup_exprstate(2)));
assert(def_xs);
bp<Variable> def_var = def_xs->lhs_variable();
if (def_var->valuetype() == nullptr) {
log && log("assign discovered lambda type T to enclosing define",
xtag("lhs", def_var.get()),
xtag("T", print::unq(this->lambda_td_->canonical_name())));
def_var->assign_valuetype(lambda_td_);
} else {
/* don't need to unify here. if def already hasa a type,
* that's because it was explicitly specified.
* will discover any conflict after reporting parsed lambda
* to define_xs
*/
}
}
expect_expr_xs::start(p_psm);
/* control reenters via .on_expr() or .on_expr_with_semicolon() */
} else {
this->illegal_input_on_type(c_self_name, td, this->get_expect_str(), p_psm);
}
}
#endif
void
DLambdaSsm::on_parsed_symbol(std::string_view sym,
ParserStateMachine * p_psm)
@ -376,8 +307,9 @@ namespace xo {
for (DArray::size_type i = 0, n = arglist->size(); i < n; ++i) {
obj<AGCObject> param = arglist->at(i);
// TODO:
// sad! runtime poly conversion from obj<AGCObject>
// We on need this because of (suboptimally) using DArray to store arglist
// We need this because of (suboptimally) using DArray to store arglist
obj<AExpression> param_expr
= FacetRegistry::instance().variant<AExpression,AGCObject>(param);
@ -503,12 +435,6 @@ namespace xo {
// TODO: on_i64_token, on_bool token
void
lambda_xs::print(std::ostream & os) const {
os << "<lambda_xs"
<< xtag("lmxs_type", lmxs_type_)
<< ">";
}
#endif
bool

View file

@ -398,7 +398,7 @@ namespace xo {
// tk is the operator this instance was waiting for
this->op_type_ = tk2op(tk.tk_type());
DExpectExprSsm::start(p_psm->parser_alloc(), p_psm);
DExpectExprSsm::start(p_psm);
return;
} else if (rhs_) {
optype op_type2 = tk2op(tk.tk_type());
@ -441,15 +441,13 @@ namespace xo {
lhs_,
op_type_,
p_psm);
DExpectExprSsm::start(p_psm->parser_alloc(),
p_psm);
DExpectExprSsm::start(p_psm);
/* (b * ..) */
DProgressSsm::start(p_psm->parser_alloc(),
rhs_,
op_type2,
p_psm);
DExpectExprSsm::start(p_psm->parser_alloc(),
p_psm);
DExpectExprSsm::start(p_psm);
return;
}
}

View file

@ -339,7 +339,43 @@ namespace xo {
REQUIRE(result.is_incomplete());
}
{
auto & result = parser.on_token(Token::yields_token());
log && log("after yields token:");
log && log(xtag("parser", &parser));
log && log(xtag("result", result));
REQUIRE(parser.has_incomplete_expr() == true);
REQUIRE(!result.is_error());
REQUIRE(result.is_incomplete());
}
{
auto & result = parser.on_token(Token::symbol_token("i64"));
log && log("after symbol(i64) token:");
log && log(xtag("parser", &parser));
log && log(xtag("result", result));
REQUIRE(parser.has_incomplete_expr() == true);
REQUIRE(!result.is_error());
REQUIRE(result.is_incomplete());
}
#ifdef NOT_YET
{
auto & result = parser.on_token(Token::leftbrace_token());
log && log("after leftbrace token:");
log && log(xtag("parser", &parser));
log && log(xtag("result", result));
REQUIRE(parser.has_incomplete_expr() == true);
REQUIRE(!result.is_error());
REQUIRE(result.is_incomplete());
}
{
auto & result = parser.on_token(Token::string_token("fooey"));