490 lines
17 KiB
C++
490 lines
17 KiB
C++
/** @file DExprSeqState.cpp
|
|
*
|
|
* @author Roland Conybeare, Jan 2026
|
|
**/
|
|
|
|
#include "DExprSeqState.hpp"
|
|
#include "ssm/ISyntaxStateMachine_DExprSeqState.hpp"
|
|
#include "DDefineSsm.hpp"
|
|
#include "DLambdaSsm.hpp"
|
|
#include "DProgressSsm.hpp"
|
|
#include "DIfElseSsm.hpp"
|
|
|
|
#include <xo/expression2/DConstant.hpp>
|
|
#include <xo/expression2/detail/IExpression_DConstant.hpp>
|
|
#include <xo/object2/DString.hpp>
|
|
#include <xo/object2/string/IGCObject_DString.hpp>
|
|
#include <xo/object2/DFloat.hpp>
|
|
#include <xo/object2/number/IGCObject_DFloat.hpp>
|
|
#include <xo/object2/DBoolean.hpp>
|
|
#include <xo/object2/number/IGCObject_DInteger.hpp>
|
|
#include <xo/object2/DInteger.hpp>
|
|
#include <xo/object2/boolean/IGCObject_DBoolean.hpp>
|
|
#include <xo/gc/GCObject.hpp>
|
|
|
|
namespace xo {
|
|
using xo::scm::DProgressSsm;
|
|
using xo::scm::DConstant;
|
|
using xo::scm::DFloat;
|
|
using xo::mm::AGCObject;
|
|
using xo::mm::AAllocator;
|
|
using xo::facet::with_facet;
|
|
using xo::reflect::typeseq;
|
|
|
|
namespace scm {
|
|
const char *
|
|
exprseqtype_descr(exprseqtype x)
|
|
{
|
|
switch (x) {
|
|
case exprseqtype::toplevel_interactive:
|
|
return "toplevel-interactive";
|
|
case exprseqtype::toplevel_batch:
|
|
return "toplevel-batch";
|
|
case exprseqtype::N:
|
|
break;
|
|
}
|
|
|
|
return "exprseqtype?";
|
|
}
|
|
|
|
DExprSeqState::DExprSeqState(exprseqtype ty) : seqtype_{ty}
|
|
{}
|
|
|
|
namespace {
|
|
obj<ASyntaxStateMachine>
|
|
make_exprseq_ssm(obj<AAllocator> mm,
|
|
exprseqtype seqtype)
|
|
{
|
|
void * mem = mm.alloc(typeseq::id<DExprSeqState>(),
|
|
sizeof(DExprSeqState));
|
|
|
|
DExprSeqState * ssm = new (mem) DExprSeqState(seqtype);
|
|
|
|
return with_facet<ASyntaxStateMachine>::mkobj(ssm);
|
|
}
|
|
}
|
|
|
|
void
|
|
DExprSeqState::establish_interactive(obj<AAllocator> mm,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
p_psm->establish_toplevel_ssm(make_exprseq_ssm
|
|
(mm,
|
|
exprseqtype::toplevel_interactive));
|
|
}
|
|
|
|
void
|
|
DExprSeqState::establish_batch(obj<AAllocator> mm,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
p_psm->establish_toplevel_ssm(make_exprseq_ssm
|
|
(mm,
|
|
exprseqtype::toplevel_batch));
|
|
}
|
|
|
|
// SyntaxStateMachine facet methods
|
|
|
|
syntaxstatetype
|
|
DExprSeqState::ssm_type() const noexcept
|
|
{
|
|
return syntaxstatetype::expect_toplevel_expression_sequence;
|
|
}
|
|
|
|
std::string_view
|
|
DExprSeqState::get_expect_str() const noexcept
|
|
{
|
|
// TODO: provisional. Will expand as more syntax implemented
|
|
|
|
switch (seqtype_) {
|
|
case exprseqtype::toplevel_interactive:
|
|
return "def|expression|...";
|
|
case exprseqtype::toplevel_batch:
|
|
return "def|...";
|
|
case exprseqtype::N:
|
|
break;
|
|
}
|
|
|
|
assert(false);
|
|
return "impossible-DExprSeqState::get_expr_str";
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_token(const Token & tk,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk));
|
|
|
|
switch (tk.tk_type()) {
|
|
case tokentype::tk_symbol:
|
|
this->on_symbol_token(tk, p_psm);
|
|
return;
|
|
|
|
case tokentype::tk_def:
|
|
this->on_def_token(tk, p_psm);
|
|
return;
|
|
|
|
case tokentype::tk_lambda:
|
|
this->on_lambda_token(tk, p_psm);
|
|
return;
|
|
|
|
case tokentype::tk_if:
|
|
this->on_if_token(tk, p_psm);
|
|
return;
|
|
|
|
case tokentype::tk_colon:
|
|
this->on_colon_token(tk, p_psm);
|
|
return;
|
|
|
|
case tokentype::tk_singleassign:
|
|
this->on_singleassign_token(tk, p_psm);
|
|
return;
|
|
|
|
case tokentype::tk_string:
|
|
this->on_string_token(tk, p_psm);
|
|
return;
|
|
|
|
case tokentype::tk_f64:
|
|
this->on_f64_token(tk, p_psm);
|
|
return;
|
|
|
|
case tokentype::tk_i64:
|
|
this->on_i64_token(tk, p_psm);
|
|
return;
|
|
|
|
case tokentype::tk_bool:
|
|
this->on_bool_token(tk, p_psm);
|
|
return;
|
|
|
|
case tokentype::tk_semicolon:
|
|
this->on_semicolon_token(tk, p_psm);
|
|
return;
|
|
|
|
// all the not-yet handled cases
|
|
case tokentype::tk_invalid:
|
|
case tokentype::tk_leftparen:
|
|
case tokentype::tk_rightparen:
|
|
case tokentype::tk_leftbracket:
|
|
case tokentype::tk_rightbracket:
|
|
case tokentype::tk_leftbrace:
|
|
case tokentype::tk_rightbrace:
|
|
case tokentype::tk_leftangle:
|
|
case tokentype::tk_rightangle:
|
|
case tokentype::tk_lessequal:
|
|
case tokentype::tk_greatequal:
|
|
case tokentype::tk_dot:
|
|
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:
|
|
case tokentype::tk_slash:
|
|
case tokentype::tk_cmpeq:
|
|
case tokentype::tk_cmpne:
|
|
case tokentype::tk_type:
|
|
case tokentype::tk_then:
|
|
case tokentype::tk_else:
|
|
case tokentype::tk_let:
|
|
case tokentype::tk_in:
|
|
case tokentype::tk_end:
|
|
case tokentype::N:
|
|
break;
|
|
}
|
|
|
|
p_psm->illegal_input_on_token("DExprSeqState::on_token",
|
|
tk,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_symbol_token(const Token & tk,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
switch (seqtype_) {
|
|
case exprseqtype::toplevel_interactive:
|
|
{
|
|
#ifdef NOT_YET
|
|
obj<AExpression,DVariable> var = p_psm->lookup_var(tk.text());
|
|
|
|
if (var) {
|
|
DProgressSsm::start(var, p_psm);
|
|
} else {
|
|
p_psm->unknown_variable_error("DExprSeqState::on_symbol_token",
|
|
tk,
|
|
this->get_expect_str(),
|
|
p_psm);
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
case exprseqtype::toplevel_batch:
|
|
break;
|
|
case exprseqtype::N:
|
|
assert(false); // unreachable
|
|
break;
|
|
}
|
|
|
|
p_psm->illegal_input_on_token("DExprSeqState::on_symbol_token",
|
|
tk,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_def_token(const Token & tk,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
(void)tk;
|
|
|
|
DDefineSsm::start(p_psm->parser_alloc(),
|
|
p_psm->expr_alloc(),
|
|
p_psm);
|
|
|
|
/* keyword 'def' introduces a definition:
|
|
* def pi : f64 = 3.14159265
|
|
* def sq(x : f64) -> f64 { (x * x) }
|
|
*/
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_lambda_token(const Token & tk,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
(void)tk;
|
|
|
|
switch (seqtype_) {
|
|
case exprseqtype::toplevel_interactive:
|
|
DLambdaSsm::start(p_psm);
|
|
return;
|
|
case exprseqtype::toplevel_batch:
|
|
/* lambda not allowed at top-level in batch mode */
|
|
break;
|
|
case exprseqtype::N:
|
|
assert(false); // unreachable
|
|
break;
|
|
}
|
|
|
|
p_psm->illegal_input_on_token("DExprSeqState::on_lambda_token",
|
|
tk,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_if_token(const Token & tk,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
switch (seqtype_) {
|
|
case exprseqtype::toplevel_interactive:
|
|
DIfElseSsm::start(p_psm->parser_alloc(),
|
|
p_psm->expr_alloc(),
|
|
p_psm);
|
|
return;
|
|
case exprseqtype::toplevel_batch:
|
|
break;
|
|
case exprseqtype::N:
|
|
assert(false); // unreachable
|
|
break;
|
|
}
|
|
|
|
p_psm->illegal_input_on_token("DExprSeqState::on_if_token",
|
|
tk,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_colon_token(const Token & tk,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
p_psm->illegal_input_on_token("DExprSeqState::on_colon_token",
|
|
tk,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_singleassign_token(const Token & tk,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
p_psm->illegal_input_on_token("DExprSeqState::on_singleassign_token",
|
|
tk,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_string_token(const Token & tk,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
switch (seqtype_) {
|
|
case exprseqtype::toplevel_interactive:
|
|
{
|
|
DString * dstr = DString::from_cstr(p_psm->expr_alloc(),
|
|
tk.text().c_str());
|
|
obj<AGCObject,DString> str(dstr);
|
|
obj<AExpression,DConstant> expr = DConstant::make(p_psm->expr_alloc(), str);
|
|
|
|
DProgressSsm::start(p_psm->parser_alloc(),
|
|
expr,
|
|
p_psm);
|
|
return;
|
|
}
|
|
case exprseqtype::toplevel_batch:
|
|
break;
|
|
case exprseqtype::N:
|
|
assert(false); // unreachable
|
|
break;
|
|
}
|
|
|
|
p_psm->illegal_input_on_token("DExprSeqState::on_string_token",
|
|
tk,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_f64_token(const Token & tk,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
switch (seqtype_) {
|
|
case exprseqtype::toplevel_interactive:
|
|
{
|
|
auto f64o = DFloat::box<AGCObject>(p_psm->expr_alloc(),
|
|
tk.f64_value());
|
|
auto expr = DConstant::make(p_psm->expr_alloc(), f64o);
|
|
|
|
DProgressSsm::start(p_psm->parser_alloc(),
|
|
expr,
|
|
p_psm);
|
|
return;
|
|
}
|
|
case exprseqtype::toplevel_batch:
|
|
break;
|
|
case exprseqtype::N:
|
|
assert(false); // unreachable
|
|
break;
|
|
}
|
|
|
|
p_psm->illegal_input_on_token("DExprSeqState::on_f64_token",
|
|
tk,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_i64_token(const Token & tk,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
switch (seqtype_) {
|
|
case exprseqtype::toplevel_interactive:
|
|
{
|
|
auto i64o = DFloat::box<AGCObject>(p_psm->expr_alloc(),
|
|
tk.i64_value());
|
|
auto expr = DConstant::make(p_psm->expr_alloc(), i64o);
|
|
|
|
DProgressSsm::start(p_psm->parser_alloc(),
|
|
expr,
|
|
p_psm);
|
|
return;
|
|
}
|
|
case exprseqtype::toplevel_batch:
|
|
break;
|
|
case exprseqtype::N:
|
|
assert(false); // unreachable
|
|
break;
|
|
}
|
|
|
|
p_psm->illegal_input_on_token("DExprSeqState::on_i64_token",
|
|
tk,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_bool_token(const Token & tk,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
switch (seqtype_) {
|
|
case exprseqtype::toplevel_interactive:
|
|
{
|
|
auto dvalue = DBoolean::box<AGCObject>(p_psm->expr_alloc(),
|
|
tk.bool_value());
|
|
auto expr = DConstant::make(p_psm->expr_alloc(), dvalue);
|
|
|
|
DProgressSsm::start(p_psm->parser_alloc(),
|
|
expr,
|
|
p_psm);
|
|
return;
|
|
}
|
|
case exprseqtype::toplevel_batch:
|
|
break;
|
|
case exprseqtype::N:
|
|
assert(false); // unreachable
|
|
break;
|
|
}
|
|
|
|
p_psm->illegal_input_on_token("DExprSeqState::on_bool_token",
|
|
tk,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_semicolon_token(const Token & tk,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
p_psm->illegal_input_on_token("DExprSeqState::on_semicolon_token",
|
|
tk,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_parsed_symbol(std::string_view sym,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
p_psm->illegal_input_on_symbol("DExprSeqState::on_parsed_symbol",
|
|
sym,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_parsed_typedescr(TypeDescr td,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
p_psm->illegal_input_on_typedescr("DExprSeqState::on_parsed_typedescr",
|
|
td,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_parsed_formal(const DUniqueString * param_name,
|
|
TypeDescr param_type,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
p_psm->illegal_parsed_formal("DExprSeqState::on_parsed_formal",
|
|
param_name,
|
|
param_type,
|
|
this->get_expect_str());
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_parsed_expression(obj<AExpression> expr,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
// toplevel expr sequence accepts an arbitrary number of expressions.
|
|
|
|
p_psm->capture_result("DExprSeqState::on_parsed_expression", expr);
|
|
}
|
|
|
|
void
|
|
DExprSeqState::on_parsed_expression_with_semicolon(obj<AExpression> expr,
|
|
ParserStateMachine * p_psm)
|
|
{
|
|
p_psm->capture_result("DExprSeqState::on_parsed_expression_with_semicolon", expr);
|
|
}
|
|
|
|
bool
|
|
DExprSeqState::pretty(const ppindentinfo & ppii) const
|
|
{
|
|
return ppii.pps()->pretty_struct
|
|
(ppii,
|
|
"DExprSeqState",
|
|
refrtag("seqtype", seqtype_));
|
|
}
|
|
} /*namespace scm*/
|
|
} /*namespace xo*/
|
|
|
|
/* end DExprSeqState.cpp */
|