xo-reader2: corrections to toplevel SchematikaParser setup

This commit is contained in:
Roland Conybeare 2026-01-18 20:23:00 -05:00
commit 846071a4fb
8 changed files with 95 additions and 35 deletions

View file

@ -64,8 +64,9 @@ namespace xo {
/** @brief Checkpoint for unwinding arena state **/
struct Checkpoint {
Checkpoint() = default;
explicit Checkpoint(std::byte * x) : free_{x} {}
std::byte * free_;
std::byte * free_ = nullptr;
};
///@}

View file

@ -38,11 +38,11 @@ namespace xo {
explicit DExprSeqState(exprseqtype ty);
/** start interactive top-level session **/
static void start_interactive(obj<AAllocator> mm,
ParserStateMachine * p_psm);
static void establish_interactive(obj<AAllocator> mm,
ParserStateMachine * p_psm);
/** start non-interactive top-level session **/
static void start_batch(obj<AAllocator> mm,
ParserStateMachine * p_psm);
static void establish_batch(obj<AAllocator> mm,
ParserStateMachine * p_psm);
public:
/** @defgroup scm-exprseq-ssm-facet syntaxstatemachine facet methods **/

View file

@ -28,8 +28,9 @@ namespace xo {
/** create new top of stack for syntax @p ssm, using memory from @p mm.
* previous stack given by @p parent
**/
ParserStack * push(obj<AAllocator> mm,
obj<ASyntaxStateMachine> ssm);
static ParserStack * push(ParserStack * stack,
obj<AAllocator> mm,
obj<ASyntaxStateMachine> ssm);
obj<ASyntaxStateMachine> top() const noexcept { return ssm_; }
ParserStack * parent() const noexcept { return parent_; }

View file

@ -41,16 +41,28 @@ namespace xo {
const ParserResult & result() const noexcept { return result_; }
obj<AAllocator> expr_alloc() const noexcept { return expr_alloc_; }
/** true iff state machine is currently idle (at top-level) **/
bool is_at_toplevel() const noexcept;
/** true iff state machine currently has incomplete expression **/
bool has_incomplete_expr() const noexcept;
///@}
/** @defgroup scm-parserstatemachine-bookkeeping bookkeeping methods **/
///@{
/** establish toplevel @p ssm. Must have empty stack **/
void establish_toplevel_ssm(obj<ASyntaxStateMachine> ssm);
/** push syntax @p ssm onto @ref stack_ **/
void push_ssm(obj<ASyntaxStateMachine> ssm);
/** reset result to none **/
void reset_result() { result_ = ParserResult(); }
void reset_result();
/** reset after reporting error **/
void clear_error_reset();
///@}
@ -89,6 +101,7 @@ namespace xo {
///@}
private:
/** Arena for internal parsing stack.
* Must be owned exclusively because destructively
* modified as parser completes parsing of each sub-expression
@ -97,6 +110,12 @@ namespace xo {
**/
DArena parser_alloc_;
/** Checkpoint of toplevel parser allocator.
* Retore parser_alloc to this checkpoint to proceed
* after encountering a parsing error.
**/
DArena::Checkpoint parser_alloc_ckp_;
/** parser stack. Memory from @ref parser_alloc_ **/
ParserStack * stack_ = nullptr;

View file

@ -30,25 +30,21 @@ namespace xo {
}
void
DExprSeqState::start_interactive(obj<AAllocator> mm,
ParserStateMachine * p_psm)
DExprSeqState::establish_interactive(obj<AAllocator> mm,
ParserStateMachine * p_psm)
{
p_psm->push_ssm(make_exprseq_ssm(mm,
exprseqtype::toplevel_interactive));
p_psm->establish_toplevel_ssm(make_exprseq_ssm
(mm,
exprseqtype::toplevel_interactive));
}
void
DExprSeqState::start_batch(obj<AAllocator> mm,
ParserStateMachine * p_psm)
DExprSeqState::establish_batch(obj<AAllocator> mm,
ParserStateMachine * p_psm)
{
(void)mm;
(void)p_psm;
#ifdef NOT_YET
p_psm->push_ssm(make_exprseq_ssm(mm,
exprseqtype::toplevel_batch));
#endif
p_psm->establish_toplevel_ssm(make_exprseq_ssm
(mm,
exprseqtype::toplevel_batch));
}
// SyntaxStateMachine facet methods

View file

@ -16,14 +16,15 @@ namespace xo {
{}
ParserStack *
ParserStack::push(obj<AAllocator> mm,
ParserStack::push(ParserStack * stack,
obj<AAllocator> mm,
obj<ASyntaxStateMachine> ssm)
{
void * mem = mm.alloc(typeseq::id<ParserStack>(),
sizeof(ParserStack));
return new (mem) ParserStack(ssm, parent_);
return new (mem) ParserStack(ssm, stack);
}
} /*namespace scm*/

View file

@ -23,6 +23,35 @@ namespace xo {
{
}
bool
ParserStateMachine::is_at_toplevel() const noexcept
{
return ((stack_ == nullptr)
|| (stack_->parent() == nullptr));
}
bool
ParserStateMachine::has_incomplete_expr() const noexcept
{
// don't count toplevel expression
return !(this->is_at_toplevel());
}
void
ParserStateMachine::establish_toplevel_ssm(obj<ASyntaxStateMachine> ssm)
{
scope log(XO_DEBUG(debug_flag_));
assert(stack_ == nullptr);
auto alloc = with_facet<AAllocator>::mkobj(&parser_alloc_);
this->stack_ = ParserStack::push(nullptr /*stack*/,
alloc, ssm);
this->parser_alloc_ckp_ = parser_alloc_.checkpoint();
}
void
ParserStateMachine::push_ssm(obj<ASyntaxStateMachine> ssm)
{
@ -32,7 +61,24 @@ namespace xo {
auto alloc = with_facet<AAllocator>::mkobj(&parser_alloc_);
this->stack_ = stack_->push(alloc, ssm);
this->stack_ = ParserStack::push(stack_, alloc, ssm);
}
void
ParserStateMachine::reset_result()
{
this->result_ = ParserResult();
}
void
ParserStateMachine::clear_error_reset()
{
this->reset_result();
while (stack_ && stack_->parent())
stack_ = stack_->parent();
this->parser_alloc_.restore(parser_alloc_ckp_);
}
void

View file

@ -25,26 +25,23 @@ namespace xo {
bool
SchematikaParser::is_at_toplevel() const {
return psm_.stack() == nullptr;
return psm_.is_at_toplevel();
}
bool
SchematikaParser::has_incomplete_expr() const {
/* (don't count toplevel exprseq) */
ParserStack * stack = psm_.stack();
if (!stack)
return false;
return stack->parent() != nullptr;
return !(this->is_at_toplevel());
}
void
SchematikaParser::begin_interactive_session() {
DExprSeqState::start_interactive(psm_.expr_alloc(), &psm_);
DExprSeqState::establish_interactive(psm_.expr_alloc(), &psm_);
}
void
SchematikaParser::begin_translation_unit() {
DExprSeqState::start_batch(psm_.expr_alloc(), &psm_);
DExprSeqState::establish_batch(psm_.expr_alloc(), &psm_);
}
const ParserResult &
@ -75,8 +72,7 @@ namespace xo {
void
SchematikaParser::reset_to_idle_toplevel()
{
psm_.reset_stack();
psm_.reset_result();
psm_.clear_error_reset();
} /*reset_to_idle_toplevel*/
void