Add 'xo-reader/' from commit 'c46c0f1cc4'
git-subtree-dir: xo-reader git-subtree-mainline:dacdeb2cd7git-subtree-split:c46c0f1cc4
This commit is contained in:
commit
0ae98c211d
48 changed files with 5184 additions and 0 deletions
121
xo-reader/include/xo/reader/define_xs.hpp
Normal file
121
xo-reader/include/xo/reader/define_xs.hpp
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/** @file define_xs.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xo/expression/DefineExpr.hpp"
|
||||
#include "xo/expression/ConvertExpr.hpp"
|
||||
#include "exprstate.hpp"
|
||||
//#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/**
|
||||
* def foo : f64 = 1 ;
|
||||
* ^ ^ ^ ^ ^ ^ ^ ^
|
||||
* | | | | | | | (done)
|
||||
* | | | | | | def_6:expect_rhs_expression:expr_progress
|
||||
* | | | | | def_5:expect_rhs_expression
|
||||
* | | | | def_4
|
||||
* | | | def_3:expect_type
|
||||
* | | def_2
|
||||
* | def_1:expect_symbol
|
||||
* def_0
|
||||
* expect_toplevel_expression_sequence
|
||||
*
|
||||
* def_0 --on_def_token()--> def_1
|
||||
* def_1 --on_symbol()--> def_2
|
||||
* def_2 --on_colon_token()--> def_3
|
||||
* --on_singleassign_token()--> def_5
|
||||
* def_3 --on_typedescr()--> def_4
|
||||
* def_4 --on_singleassign_token()--> def_5
|
||||
* def_5 --on_expr()--> def_6
|
||||
* def_6 --on_semicolon_token()--> (done)
|
||||
*
|
||||
* def_1:expect_symbol: got 'def' keyword, symbol to follow
|
||||
* def_1: got symbol name
|
||||
* def_3:expect_symbol got (optional) colon, type name to follow
|
||||
* def_4: got symbol type
|
||||
* def_6:expect_rhs_expression got (optional) equal sign, value to follow
|
||||
* (done): definition complete, pop exprstate from stack
|
||||
*
|
||||
**/
|
||||
enum class defexprstatetype {
|
||||
invalid = -1,
|
||||
|
||||
def_0,
|
||||
def_1,
|
||||
def_2,
|
||||
def_3,
|
||||
def_4,
|
||||
def_5,
|
||||
def_6,
|
||||
|
||||
n_defexprstatetype,
|
||||
};
|
||||
|
||||
extern const char * defexprstatetype_descr(defexprstatetype x);
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream & os, defexprstatetype x);
|
||||
|
||||
/** @class define_xs
|
||||
* @brief state to provide parsing of a define-expression
|
||||
**/
|
||||
class define_xs : public exprstate {
|
||||
public:
|
||||
using DefineExprAccess = xo::ast::DefineExprAccess;
|
||||
using ConvertExprAccess = xo::ast::ConvertExprAccess;
|
||||
|
||||
public:
|
||||
define_xs(rp<DefineExprAccess> def_expr);
|
||||
virtual ~define_xs() = default;
|
||||
|
||||
static const define_xs * from(const exprstate * x) { return dynamic_cast<const define_xs *>(x); }
|
||||
|
||||
static void start(parserstatemachine * p_psm);
|
||||
|
||||
defexprstatetype defxs_type() const { return defxs_type_; }
|
||||
|
||||
virtual void on_expr(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_expr_with_semicolon(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_symbol(const std::string & symbol_name,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_typedescr(TypeDescr td,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_def_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_colon_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_semicolon_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_singleassign_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_rightparen_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_f64_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void print(std::ostream & os) const override;
|
||||
|
||||
private:
|
||||
static std::unique_ptr<define_xs> make();
|
||||
|
||||
private:
|
||||
defexprstatetype defxs_type_;
|
||||
/** scaffold a define-expression here **/
|
||||
rp<DefineExprAccess> def_expr_;
|
||||
/** scafford a convert-expression here.
|
||||
* May be nested within a def_expr
|
||||
**/
|
||||
rp<ConvertExprAccess> cvt_expr_;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end define_xs.hpp **/
|
||||
48
xo-reader/include/xo/reader/envframe.hpp
Normal file
48
xo-reader/include/xo/reader/envframe.hpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* file envframe.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xo/expression/Variable.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @class envframe
|
||||
* @brief names/types of formal paremeters introduced by a function
|
||||
*
|
||||
*
|
||||
**/
|
||||
class envframe {
|
||||
public:
|
||||
using Variable = xo::ast::Variable;
|
||||
|
||||
public:
|
||||
envframe() = default;
|
||||
envframe(const std::vector<rp<Variable>> & argl) : argl_(argl) {}
|
||||
|
||||
const std::vector<rp<Variable>> & argl() const { return argl_; }
|
||||
|
||||
/** lookup variable by name. If found, return it.
|
||||
* Otherwise return nullptr
|
||||
**/
|
||||
rp<Variable> lookup(const std::string & name) const;
|
||||
|
||||
void print (std::ostream & os) const;
|
||||
|
||||
private:
|
||||
std::vector<rp<Variable>> argl_;
|
||||
};
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, const envframe & x) {
|
||||
x.print(os);
|
||||
return os;
|
||||
}
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end envframe.hpp */
|
||||
78
xo-reader/include/xo/reader/envframestack.hpp
Normal file
78
xo-reader/include/xo/reader/envframestack.hpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/* file envframestack.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "envframe.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @class envframestack
|
||||
* @brief A stack of envframe objects
|
||||
**/
|
||||
class envframestack {
|
||||
public:
|
||||
using Variable = xo::ast::Variable;
|
||||
|
||||
public:
|
||||
envframestack() {}
|
||||
|
||||
bool empty() const { return stack_.empty(); }
|
||||
std::size_t size() const { return stack_.size(); }
|
||||
|
||||
/** lookup variable in environment stack.
|
||||
* Visit frames in fifo order, report first match;
|
||||
* nullptr if no matches.
|
||||
**/
|
||||
rp<Variable> lookup(const std::string & x) const;
|
||||
|
||||
envframe & top_envframe();
|
||||
void push_envframe(envframe x);
|
||||
void pop_envframe();
|
||||
|
||||
/** relative to top-of-stack.
|
||||
* 0 -> top (last in), z-1 -> bottom (first in)
|
||||
**/
|
||||
envframe & operator[](std::size_t i) {
|
||||
std::size_t z = stack_.size();
|
||||
|
||||
assert(i < z);
|
||||
|
||||
return stack_[z - i - 1];
|
||||
}
|
||||
|
||||
const envframe & operator[](std::size_t i) const {
|
||||
std::size_t z = stack_.size();
|
||||
|
||||
assert(i < z);
|
||||
|
||||
return stack_[z - i - 1];
|
||||
}
|
||||
|
||||
void print (std::ostream & os) const;
|
||||
|
||||
private:
|
||||
std::vector<envframe> stack_;
|
||||
};
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, const envframestack & x) {
|
||||
x.print(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, const envframestack * x) {
|
||||
if (x)
|
||||
x->print(os);
|
||||
else
|
||||
os << "nullptr";
|
||||
return os;
|
||||
}
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end envframestack.hpp */
|
||||
77
xo-reader/include/xo/reader/expect_expr_xs.hpp
Normal file
77
xo-reader/include/xo/reader/expect_expr_xs.hpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/* file expect_expr_xs.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
|
||||
/** @class expect_expr_xs
|
||||
* @brief state machine to expect + capture an expression
|
||||
**/
|
||||
class expect_expr_xs : public exprstate {
|
||||
public:
|
||||
explicit expect_expr_xs(bool allow_defs,
|
||||
bool cxl_on_rightbrace);
|
||||
|
||||
static void start(parserstatemachine * p_psm);
|
||||
static void start(bool allow_defs,
|
||||
bool cxl_on_rightbrace,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
virtual void on_lambda_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void on_def_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_leftbrace_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void on_rightbrace_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void on_symbol_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void on_f64_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
/** update exprstate in response to a successfully-parsed subexpression **/
|
||||
virtual void on_expr(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm) override;
|
||||
/** update exprstate in response to a successfully-parsed subexpression,
|
||||
* that's terminated by semicolon ';'
|
||||
**/
|
||||
virtual void on_expr_with_semicolon(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
|
||||
private:
|
||||
static std::unique_ptr<expect_expr_xs> make(bool allow_defs,
|
||||
bool cxl_on_rightbrace);
|
||||
|
||||
private:
|
||||
/* if true: allow a define-expression here */
|
||||
bool allow_defs_ = false;
|
||||
/* if true: expecting either:
|
||||
* - expression
|
||||
* - right brace '}', in which case no expression
|
||||
* if false: expecting
|
||||
* - expression
|
||||
*/
|
||||
bool cxl_on_rightbrace_ = false;
|
||||
};
|
||||
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end expect_expr_xs.hpp */
|
||||
83
xo-reader/include/xo/reader/expect_formal_arglist_xs.hpp
Normal file
83
xo-reader/include/xo/reader/expect_formal_arglist_xs.hpp
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/* file expect_formal_arglist_xs.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
#include "formal_arg.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/**
|
||||
* ( name(1) : type(1) , ..., )
|
||||
* ^ ^ ^ ^ ^
|
||||
* | | | | |
|
||||
* | | | | argl_1b
|
||||
* | argl_1a | argla
|
||||
* argl_0 argl_1b
|
||||
*
|
||||
* argl_0 --on_leftparen_token()--> argl_1a
|
||||
* argl_1a --on_formal()--> argl_1b
|
||||
* argl_1b -+-on_comma_token()--> argl_1a
|
||||
* \-on_rightparen_token()--> (done)
|
||||
**/
|
||||
enum class formalarglstatetype {
|
||||
invalid = -1,
|
||||
|
||||
argl_0,
|
||||
argl_1a,
|
||||
argl_1b,
|
||||
|
||||
n_formalarglstatetype,
|
||||
};
|
||||
|
||||
extern const char *
|
||||
formalarglstatetype_descr(formalarglstatetype x);
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, formalarglstatetype x) {
|
||||
os << formalarglstatetype_descr(x);
|
||||
return os;
|
||||
}
|
||||
|
||||
/** @class expect_formal_arglist
|
||||
* @brief parser state-machine for a formal parameter list
|
||||
**/
|
||||
class expect_formal_arglist_xs : public exprstate {
|
||||
public:
|
||||
using Variable = xo::ast::Variable;
|
||||
|
||||
public:
|
||||
expect_formal_arglist_xs();
|
||||
|
||||
static void start(parserstatemachine * p_psm);
|
||||
|
||||
virtual void on_leftparen_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_formal(const rp<Variable> & formal,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_comma_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<expect_formal_arglist_xs> make();
|
||||
|
||||
private:
|
||||
/** parsing state-machine state **/
|
||||
formalarglstatetype farglxs_type_ = formalarglstatetype::argl_0;
|
||||
/** populate with (parmaeter-name, parameter-type) list
|
||||
* as they're encountered
|
||||
**/
|
||||
std::vector<rp<Variable>> argl_;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end expect_formal_arglist_xs.hpp */
|
||||
85
xo-reader/include/xo/reader/expect_formal_xs.hpp
Normal file
85
xo-reader/include/xo/reader/expect_formal_xs.hpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/* file expect_formal_xs.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
#include "formal_arg.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/**
|
||||
* name : type
|
||||
* ^ ^ ^
|
||||
* | | formal_2
|
||||
* | formal_1
|
||||
* formal_0
|
||||
*
|
||||
* formal_0 --on_symbol()--> formal_1
|
||||
* formal_1 --on_colon_token()--> formal_2
|
||||
* formal_2 --on_typedescr()--> (done)
|
||||
**/
|
||||
enum class formalstatetype {
|
||||
invalid = -1,
|
||||
|
||||
formal_0,
|
||||
formal_1,
|
||||
formal_2,
|
||||
|
||||
n_formalstatetype,
|
||||
};
|
||||
|
||||
extern const char *
|
||||
formalstatetype_descr(formalstatetype x);
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, formalstatetype x) {
|
||||
os << formalstatetype_descr(x);
|
||||
return os;
|
||||
}
|
||||
|
||||
/** @class expect_formal_xs
|
||||
* @brief parser state-machine for a typed formal parameter
|
||||
**/
|
||||
class expect_formal_xs : public exprstate {
|
||||
public:
|
||||
expect_formal_xs();
|
||||
|
||||
static void start(parserstatemachine * p_psm);
|
||||
|
||||
virtual void on_symbol(const std::string & symbol_name,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void on_colon_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
// virtual void on_comma_token(...) override;
|
||||
|
||||
#ifdef PROBABLY_NOT
|
||||
virtual void on_rightparen_token(const token_type & tk,
|
||||
exprstatestack * p_stack,
|
||||
rp<Expression> * p_emit_expr) override;
|
||||
#endif
|
||||
|
||||
virtual void on_typedescr(TypeDescr td,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void print(std::ostream & os) const override;
|
||||
|
||||
private:
|
||||
static std::unique_ptr<expect_formal_xs> make();
|
||||
|
||||
private:
|
||||
/** parsing state-machine state **/
|
||||
formalstatetype formalxs_type_ = formalstatetype::formal_0;
|
||||
/** populate with {parameter-name, parameter-type}
|
||||
* as they're encountered
|
||||
**/
|
||||
formal_arg result_;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end expect_formal_xs.hpp */
|
||||
32
xo-reader/include/xo/reader/expect_symbol_xs.hpp
Normal file
32
xo-reader/include/xo/reader/expect_symbol_xs.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* file expect_symbol_xs.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @class expect_symbol_xs
|
||||
* @brief state machine to expect + capture a symbol
|
||||
*
|
||||
* For example, lhs in a define-expression
|
||||
**/
|
||||
class expect_symbol_xs : public exprstate {
|
||||
public:
|
||||
expect_symbol_xs();
|
||||
|
||||
static std::unique_ptr<expect_symbol_xs> make();
|
||||
|
||||
static void start(parserstatemachine * p_psm);
|
||||
|
||||
virtual void on_symbol_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end expect_symbol_xs.hpp */
|
||||
31
xo-reader/include/xo/reader/expect_type_xs.hpp
Normal file
31
xo-reader/include/xo/reader/expect_type_xs.hpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* file expect_type_xs.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @class expect_type_xs
|
||||
* @brief state-machine for accepting a typename-expression
|
||||
**/
|
||||
class expect_type_xs : public exprstate {
|
||||
public:
|
||||
expect_type_xs();
|
||||
|
||||
static void start(parserstatemachine * p_stack);
|
||||
|
||||
virtual void on_symbol_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
private:
|
||||
static std::unique_ptr<expect_type_xs> make();
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end expect_type_xs.hpp */
|
||||
45
xo-reader/include/xo/reader/exprseq_xs.hpp
Normal file
45
xo-reader/include/xo/reader/exprseq_xs.hpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/** @file exprseq_xs.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
//#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @class exprseq_xs
|
||||
* @brief parsing state-machine for top-level expression sequence
|
||||
*
|
||||
**/
|
||||
class exprseq_xs : public exprstate {
|
||||
public:
|
||||
exprseq_xs();
|
||||
|
||||
static void start(parserstatemachine * p_psm);
|
||||
|
||||
public:
|
||||
// ----- token input methods -----
|
||||
|
||||
virtual void on_def_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_symbol_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
// ----- victory methods -----
|
||||
|
||||
virtual void on_typedescr(TypeDescr td,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_expr(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
private:
|
||||
static std::unique_ptr<exprseq_xs> make();
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end exprseq_xs.hpp **/
|
||||
208
xo-reader/include/xo/reader/exprstate.hpp
Normal file
208
xo-reader/include/xo/reader/exprstate.hpp
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/** @file exprstate.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xo/expression/Expression.hpp"
|
||||
#include "xo/tokenizer/token.hpp"
|
||||
#include <stack>
|
||||
//#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
enum class exprstatetype {
|
||||
invalid = -1,
|
||||
|
||||
/** toplevel of some translation unit **/
|
||||
expect_toplevel_expression_sequence,
|
||||
|
||||
/** handle define-expression
|
||||
* see @ref define_xs
|
||||
**/
|
||||
defexpr,
|
||||
|
||||
/** handle lambda-expression
|
||||
* see @ref lambda_xs
|
||||
**/
|
||||
lambdaexpr,
|
||||
|
||||
/** handle parenthesized expression
|
||||
* see @ref paren_xs
|
||||
**/
|
||||
parenexpr,
|
||||
|
||||
/** handle sequence expression (aka block)
|
||||
* see @ref sequence_xs
|
||||
**/
|
||||
sequenceexpr,
|
||||
|
||||
/** handle let1 (single local variable)
|
||||
* see @ref let1_xs
|
||||
**/
|
||||
let1expr,
|
||||
|
||||
expect_rhs_expression,
|
||||
expect_symbol,
|
||||
expect_type,
|
||||
/** handle formal argument list
|
||||
* see @ref expect_formal_arglist_xs
|
||||
**/
|
||||
expect_formal_arglist,
|
||||
/** handle formal argument
|
||||
* see @ref expec_formal_xs
|
||||
**/
|
||||
expect_formal,
|
||||
|
||||
/** handle expression-in-progress,
|
||||
* in case infix operators to follow
|
||||
* see @ref progress_xs
|
||||
**/
|
||||
expr_progress,
|
||||
|
||||
n_exprstatetype
|
||||
};
|
||||
|
||||
extern const char *
|
||||
exprstatetype_descr(exprstatetype x);
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, exprstatetype x) {
|
||||
os << exprstatetype_descr(x);
|
||||
return os;
|
||||
}
|
||||
|
||||
class parserstatemachine; /* see parserstatemachine.hpp */
|
||||
class exprstatestack;
|
||||
|
||||
class formal_arg;
|
||||
|
||||
/** state associated with a partially-parsed expression.
|
||||
**/
|
||||
class exprstate {
|
||||
public:
|
||||
using Expression = xo::ast::Expression;
|
||||
using Variable = xo::ast::Variable;
|
||||
using exprtype = xo::ast::exprtype;
|
||||
using token_type = token<char>;
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
|
||||
public:
|
||||
exprstate() = default;
|
||||
exprstate(exprstatetype exs_type)
|
||||
: exs_type_{exs_type}
|
||||
{}
|
||||
virtual ~exprstate() = default;
|
||||
|
||||
exprstatetype exs_type() const { return exs_type_; }
|
||||
|
||||
/** update exprstate in response to incoming token @p tk,
|
||||
* forward instructions to parent parser
|
||||
**/
|
||||
void on_input(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
/** update exprstate in response to a successfully-parsed subexpression **/
|
||||
virtual void on_expr(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
/** update exprstate in response to a successfully-parsed subexpression, that ends with semicolon **/
|
||||
virtual void on_expr_with_semicolon(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
/** update exprstate when expecting a symbol **/
|
||||
virtual void on_symbol(const std::string & symbol,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
/** update exprstate when expeccting a typedescr **/
|
||||
virtual void on_typedescr(TypeDescr td,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
/** update exprstate when expecting a formal parameter **/
|
||||
virtual void on_formal(const rp<Variable> & formal,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
/** update expression when epecting a formal parameter list **/
|
||||
virtual void on_formal_arglist(const std::vector<rp<Variable>> & argl,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
/** print human-readable representation on @p os **/
|
||||
virtual void print(std::ostream & os) const;
|
||||
|
||||
// ----- input methods -----
|
||||
|
||||
/** handle incoming 'def' token **/
|
||||
virtual void on_def_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
/** handle incoming 'lambda' token **/
|
||||
virtual void on_lambda_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
/** handle incoming symbol token **/
|
||||
virtual void on_symbol_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
/** handle incoming ',' token **/
|
||||
virtual void on_comma_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
/** handle incoming ':' token **/
|
||||
virtual void on_colon_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
/** handle incoming ';' token **/
|
||||
virtual void on_semicolon_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
/** handle incoming '=' token **/
|
||||
virtual void on_singleassign_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
/** handle incoming '(' token **/
|
||||
virtual void on_leftparen_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
/** handle incoming ')' token **/
|
||||
virtual void on_rightparen_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
/** handle incoming '{' token **/
|
||||
virtual void on_leftbrace_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
/** handle incoming '}' token **/
|
||||
virtual void on_rightbrace_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
/** handle incoming operator token **/
|
||||
virtual void on_operator_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
/** handle incoming floating-point-literal token **/
|
||||
virtual void on_f64_token(const token_type & tk,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
protected:
|
||||
/** throw exception when next token is inconsistent with
|
||||
* parsing state
|
||||
**/
|
||||
void illegal_input_error(const char * self_name,
|
||||
const token_type & tk) const;
|
||||
|
||||
protected:
|
||||
/** explicit subtype: identifies derived class **/
|
||||
exprstatetype exs_type_;
|
||||
}; /*exprstate*/
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, const exprstate & x) {
|
||||
x.print(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, const exprstate * x) {
|
||||
if (x)
|
||||
x->print(os);
|
||||
else
|
||||
os << "nullptr";
|
||||
return os;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end exprstate.hpp **/
|
||||
70
xo-reader/include/xo/reader/exprstatestack.hpp
Normal file
70
xo-reader/include/xo/reader/exprstatestack.hpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* file exprstatestack.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
#include "xo/indentlog/print/vector.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @class exprstatestack
|
||||
* @brief A stack of exprstate objects
|
||||
**/
|
||||
class exprstatestack {
|
||||
public:
|
||||
exprstatestack() {}
|
||||
|
||||
bool empty() const { return stack_.empty(); }
|
||||
std::size_t size() const { return stack_.size(); }
|
||||
|
||||
exprstate & top_exprstate();
|
||||
void push_exprstate(std::unique_ptr<exprstate> exs);
|
||||
std::unique_ptr<exprstate> pop_exprstate();
|
||||
|
||||
/** relative to top-of-stack.
|
||||
* 0 -> top (last in), z-1 -> bottom (first in)
|
||||
**/
|
||||
std::unique_ptr<exprstate> & operator[](std::size_t i) {
|
||||
std::size_t z = stack_.size();
|
||||
|
||||
assert(i < z);
|
||||
|
||||
return stack_[z - i - 1];
|
||||
}
|
||||
|
||||
const std::unique_ptr<exprstate> & operator[](std::size_t i) const {
|
||||
std::size_t z = stack_.size();
|
||||
|
||||
assert(i < z);
|
||||
|
||||
return stack_[z - i - 1];
|
||||
}
|
||||
|
||||
void print (std::ostream & os) const;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<exprstate>> stack_;
|
||||
};
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, const exprstatestack & x) {
|
||||
x.print(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, const exprstatestack * x) {
|
||||
if (x)
|
||||
x->print(os);
|
||||
else
|
||||
os << "nullptr";
|
||||
return os;
|
||||
}
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end exprstatestack.hpp */
|
||||
58
xo-reader/include/xo/reader/formal_arg.hpp
Normal file
58
xo-reader/include/xo/reader/formal_arg.hpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/* file formal_arg.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TypeDescr.hpp"
|
||||
#include "xo/indentlog/print/tag.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @class formal_arg
|
||||
* @brief description of formal parameter in an argument list
|
||||
*
|
||||
* Terminated by an argument separator ',' or rightparen ')'
|
||||
**/
|
||||
class formal_arg {
|
||||
public:
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
|
||||
public:
|
||||
formal_arg() = default;
|
||||
formal_arg(const std::string & n, TypeDescr td) : name_{n}, td_{td} {}
|
||||
|
||||
const std::string & name() const { return name_; }
|
||||
TypeDescr td() const { return td_; }
|
||||
|
||||
void assign_name(const std::string & x) { name_ = x; }
|
||||
void assign_td(TypeDescr x) { td_ = x; }
|
||||
|
||||
void print(std::ostream & os) const {
|
||||
os << "<formal_arg";
|
||||
if (!name_.empty())
|
||||
os << xtag("name", name_);
|
||||
if (td_)
|
||||
os << xtag("td", td_);
|
||||
os << ">";
|
||||
}
|
||||
|
||||
private:
|
||||
/** formal parameter name **/
|
||||
std::string name_;
|
||||
/** type description for variable @p name **/
|
||||
TypeDescr td_;
|
||||
};
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os,
|
||||
const formal_arg & x) {
|
||||
x.print(os);
|
||||
return os;
|
||||
}
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end formal_arg.hpp */
|
||||
84
xo-reader/include/xo/reader/lambda_xs.hpp
Normal file
84
xo-reader/include/xo/reader/lambda_xs.hpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/** @file lambda_xs.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
//#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/**
|
||||
* lambda ( name(1) : type(1), ..., ) body-expr ;
|
||||
* ^ ^ ^ ^
|
||||
* | | | |
|
||||
* lm_0 lm_1 lm_2 lm_3
|
||||
*
|
||||
* lm_0 --on_lambda_token()--> lm_1
|
||||
* lm_1 --on_formal_arglist()--> lm_2
|
||||
* lm_2 --on_expr()--> lm_3
|
||||
* lm_3 --on_semicolon_token()--> (done)
|
||||
**/
|
||||
enum class lambdastatetype {
|
||||
invalid = -1,
|
||||
|
||||
lm_0,
|
||||
lm_1,
|
||||
lm_2,
|
||||
lm_3,
|
||||
|
||||
n_lambdastatetype
|
||||
};
|
||||
|
||||
extern const char *
|
||||
lambdastatetype_descr(lambdastatetype x);
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, lambdastatetype x) {
|
||||
os << lambdastatetype_descr(x);
|
||||
return os;
|
||||
}
|
||||
|
||||
/** @class lambda_xs
|
||||
* @brief parsing state-machine for a lambda-expression
|
||||
*
|
||||
**/
|
||||
class lambda_xs : public exprstate {
|
||||
public:
|
||||
lambda_xs();
|
||||
|
||||
static void start(parserstatemachine * p_psm);
|
||||
|
||||
virtual void on_lambda_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_formal_arglist(const std::vector<rp<Variable>> & argl,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_expr(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_expr_with_semicolon(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_semicolon_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void print(std::ostream & os) const override;
|
||||
|
||||
private:
|
||||
static std::unique_ptr<lambda_xs> make();
|
||||
|
||||
private:
|
||||
/** parsing state-machine state **/
|
||||
lambdastatetype lmxs_type_ = lambdastatetype::lm_0;
|
||||
|
||||
/** formal parameter list **/
|
||||
std::vector<rp<Variable>> argl_;
|
||||
|
||||
/** body expression **/
|
||||
rp<Expression> body_;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end lambda_xs.hpp **/
|
||||
57
xo-reader/include/xo/reader/let1_xs.hpp
Normal file
57
xo-reader/include/xo/reader/let1_xs.hpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* file let1_xs.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
class let1_xs : public exprstate {
|
||||
public:
|
||||
|
||||
/** given local definition equivalent to
|
||||
* def lhs_name = rhs
|
||||
* rest...
|
||||
* parse sequence of incoming expressions rest... (until '}')
|
||||
*
|
||||
* Result expression creates and inits @p lhs_name,
|
||||
* then evaluates expressions that follow definition
|
||||
* up to same-level '}'
|
||||
**/
|
||||
static void start(const std::string & lhs_name,
|
||||
const rp<Expression> & rhs,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
virtual void on_expr(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void on_rightbrace_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
private:
|
||||
let1_xs(std::string lhs_name,
|
||||
rp<Expression> rhs);
|
||||
|
||||
/** named ctor idiom **/
|
||||
static std::unique_ptr<let1_xs> make(std::string lhs_name,
|
||||
rp<Expression> rhs);
|
||||
|
||||
private:
|
||||
/** name for new local variable **/
|
||||
std::string lhs_name_;
|
||||
/** set initial value for @ref lhs_name_ from value of this expression **/
|
||||
rp<Expression> rhs_;
|
||||
|
||||
/** evaluate expressions in this sequence, in order, in environment
|
||||
* with variable @ref lhs_name_ defined
|
||||
**/
|
||||
std::vector<rp<Expression>> expr_v_;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end let1_xs.hpp */
|
||||
90
xo-reader/include/xo/reader/paren_xs.hpp
Normal file
90
xo-reader/include/xo/reader/paren_xs.hpp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/** @file paren_xs.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
//#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
enum class parenexprstatetype {
|
||||
invalid = -1,
|
||||
|
||||
lparen_0,
|
||||
lparen_1,
|
||||
|
||||
n_parenexprstatetype,
|
||||
};
|
||||
|
||||
extern const char *
|
||||
parenexprstatetype_descr(parenexprstatetype x);
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, parenexprstatetype x) {
|
||||
os << parenexprstatetype_descr(x);
|
||||
return os;
|
||||
}
|
||||
|
||||
/** @class paren_xs
|
||||
* @brief state machine for handling parentheses in expressions
|
||||
**/
|
||||
class paren_xs : public exprstate {
|
||||
public:
|
||||
paren_xs();
|
||||
virtual ~paren_xs() = default;
|
||||
|
||||
static const paren_xs * from(const exprstate * x) { return dynamic_cast<const paren_xs *>(x); }
|
||||
|
||||
static void start(parserstatemachine * p_psm);
|
||||
|
||||
bool admits_f64() const;
|
||||
bool admits_rightparen() const;
|
||||
|
||||
virtual void on_expr(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_symbol(const std::string & symbol,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_typedescr(TypeDescr td,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void on_def_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_symbol_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_colon_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_semicolon_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_singleassign_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 on_f64_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void print(std::ostream & os) const override;
|
||||
|
||||
private:
|
||||
static std::unique_ptr<paren_xs> make();
|
||||
|
||||
private:
|
||||
/**
|
||||
* ( foo ... )
|
||||
* ^
|
||||
* |
|
||||
* lparen_0
|
||||
**/
|
||||
parenexprstatetype parenxs_type_;
|
||||
/** populate expression (representing parenthesized value) here **/
|
||||
rp<Expression> gen_expr_;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end paren_xs.hpp **/
|
||||
234
xo-reader/include/xo/reader/parser.hpp
Normal file
234
xo-reader/include/xo/reader/parser.hpp
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
/* file parser.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Jul 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstatestack.hpp"
|
||||
#include "envframestack.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** schematica parser
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* decltype point
|
||||
*
|
||||
* // forward declarations
|
||||
* decl pi : f64;
|
||||
* decl fib(n : i32) -> i32;
|
||||
*
|
||||
* def pi = 3.14159265; // constant. = is single assignment
|
||||
*
|
||||
* def fib(n : i32) -> i32 {
|
||||
* // nested defs ok
|
||||
* def aux(n : i32, s1 : i32, s2 : i32) -> i32 {
|
||||
* // or:
|
||||
* // (n == 0) ? s1 : aux(n - 1, s1 + s2, s1)
|
||||
* //
|
||||
* if (n == 0) {
|
||||
* s1;
|
||||
* } else {
|
||||
* aux(n - 1, s1 + s2, s1);
|
||||
* }
|
||||
*
|
||||
* // or:
|
||||
* // if (n == 0) ? s1 : aux(n - 1, s1 + s2, s1)
|
||||
* }
|
||||
*
|
||||
* aux(n=n, s1=1, s2=0);
|
||||
* }
|
||||
*
|
||||
* def x := "fu"; // non-constant
|
||||
* x += "bar";
|
||||
*
|
||||
* def anotherfib = lambda(n : i32) { fib(n) };
|
||||
*
|
||||
* def any : object;
|
||||
* def l : list<object> = '();
|
||||
*
|
||||
* deftype point :: {x : f64, y : f64};
|
||||
* deftype polar :: {arg : f64, mag : f64};
|
||||
*
|
||||
* def polar2rect(pt : polar) -> point {
|
||||
* point(x = pt.mag * cos(arg),
|
||||
* y = pt.mag * sin(arg));
|
||||
* }
|
||||
*
|
||||
* Grammar:
|
||||
* toplevel-program = $expression(1); ..; $expression(n)
|
||||
*
|
||||
* type-decl = decltype $typename [<$tp1 .. $tpn>]
|
||||
* expression = define-expr
|
||||
* | literal-expr
|
||||
* | variable-expr
|
||||
* | apply-expr
|
||||
* | if-expr
|
||||
* | lambda-expr
|
||||
* | arithmetic-expr
|
||||
* | block
|
||||
*
|
||||
* define-expr = type-decl
|
||||
* | type-def
|
||||
* | variable-def
|
||||
* | function-decl
|
||||
* | function-def
|
||||
*
|
||||
* type-def = deftype $typename [<$tp1 .. $tpn>] :: type-def-rhs
|
||||
* type-def-rhs = object
|
||||
* | bool
|
||||
* | i128 | i64 | i32 | i16 | i8
|
||||
* | f128 | f64 | f32 | f16
|
||||
* | struct $typename { ($membername(i) : $typename(i))* }
|
||||
* [end $typename]
|
||||
* | tuple $typename { $typename(1), .., $typename(n) }
|
||||
* [end $typename]
|
||||
* | copytype $typename
|
||||
* | subtype $typename { ($member(i) : $typename(i))* }
|
||||
*
|
||||
* variable-def = decl $varname [: $typename] [= expression]
|
||||
* function-decl = decl $functionname($varname(1) : $typename(1),
|
||||
* ..,
|
||||
* $varname(n) : $typename(n)) -> $typename[ret]
|
||||
* function-def = def $functionname($varname(1) : $typename(1),
|
||||
* ..,
|
||||
* $varname(n) : $typename(n)) [-> $typename[ret]]
|
||||
* body-expr
|
||||
* [ end $functionname ]
|
||||
* literal-expr = integer-literal
|
||||
* | fp-literal
|
||||
* | string-literal
|
||||
* | symbol-literal
|
||||
* | struct-literal
|
||||
*
|
||||
* variable-expr = $varname
|
||||
* apply-expr = fn-expr(arg-expr(1), .., arg-expr(n))
|
||||
* fn-expr = expression
|
||||
* arg-expr(i) = expression
|
||||
*
|
||||
* if-expr = if (test-expr) then-block else else-block
|
||||
* | ((test-expr) ? then-expr : else-expr)
|
||||
* test-expr = expression
|
||||
* then-block = block
|
||||
* else-block = block
|
||||
*
|
||||
* block = { (definition | expression)* }
|
||||
*
|
||||
* lambda-expr = lambda ($paramname(1) : $type(1),
|
||||
* ..,
|
||||
* $paramname(n) : $type(n)) body-expr
|
||||
* body-expr = expression
|
||||
*
|
||||
* arithmetic-expr = expression binop expression
|
||||
*
|
||||
* binop = +
|
||||
* | -
|
||||
* | *
|
||||
* | /
|
||||
* | |
|
||||
* | &
|
||||
* | ^
|
||||
* | ==
|
||||
* | !=
|
||||
* | <
|
||||
* | <=
|
||||
* | =>
|
||||
* | >
|
||||
*
|
||||
**/
|
||||
class parser {
|
||||
public:
|
||||
using Expression = xo::ast::Expression;
|
||||
using token_type = exprstate::token_type; // token<char>;
|
||||
|
||||
public:
|
||||
/** create parser in initial state;
|
||||
* parser is ready to receive tokens via @ref include_token
|
||||
**/
|
||||
parser() = default;
|
||||
|
||||
/** for diagnostics: number of entries in parser stack **/
|
||||
std::size_t stack_size() const { return xs_stack_.size(); }
|
||||
/** for diagnostics: exprstatetype at level @p i
|
||||
* (taken relative to top of stack)
|
||||
*
|
||||
* @pre 0 <= i < stack_size
|
||||
**/
|
||||
exprstatetype i_exstype(std::size_t i) const {
|
||||
std::size_t z = xs_stack_.size();
|
||||
|
||||
if (i < z) {
|
||||
return xs_stack_[i]->exs_type();
|
||||
}
|
||||
|
||||
/* out of bounds */
|
||||
return exprstatetype::invalid;
|
||||
}
|
||||
|
||||
exprstate const * i_exstate(std::size_t i) const {
|
||||
std::size_t z = xs_stack_.size();
|
||||
|
||||
if (i < z) {
|
||||
return xs_stack_[i].get();
|
||||
}
|
||||
|
||||
/* out of bounds */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** true iff parser contains state for an incomplete expression.
|
||||
* For this to be true, parser must have consumed at least one token
|
||||
* since end of last toplevel expression
|
||||
**/
|
||||
bool has_incomplete_expr() const;
|
||||
|
||||
/** put parser into state for beginning of a translation unit
|
||||
* (i.e. input stream)
|
||||
**/
|
||||
void begin_translation_unit();
|
||||
|
||||
/** include next token @p tk and increment parser state.
|
||||
*
|
||||
* @param tk next input token
|
||||
* @return parsed expression, if @p tk completes an expression.
|
||||
* otherwise nullptr
|
||||
**/
|
||||
rp<Expression> include_token(const token_type & tk);
|
||||
|
||||
/** print human-readable representation on stream @p os **/
|
||||
void print(std::ostream & os) const;
|
||||
|
||||
private:
|
||||
/** state recording state associated with enclosing expressions.
|
||||
*
|
||||
* Note: at least asof c++23, the std::stack api doesn't support access
|
||||
* to members other than the top.
|
||||
*
|
||||
* for stack with N elements (N = stack_.size()):
|
||||
* - bottom of stack is stack_[0]
|
||||
* - top of stack is stack_[N-1]
|
||||
**/
|
||||
exprstatestack xs_stack_;
|
||||
|
||||
/** environment frames for lexical context.
|
||||
* push a frame on each nested lambda;
|
||||
* pop when lambda body goes out of scope
|
||||
**/
|
||||
envframestack env_stack_;
|
||||
|
||||
}; /*parser*/
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os,
|
||||
const parser & x) {
|
||||
x.print(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end parser.hpp */
|
||||
85
xo-reader/include/xo/reader/parserstatemachine.hpp
Normal file
85
xo-reader/include/xo/reader/parserstatemachine.hpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/* file parserstatemachine.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
#include "envframestack.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @class parserstatemachine
|
||||
* @brief public parser state.
|
||||
*
|
||||
* Schematica parser state; sent to subsidiary single-feature state machines.
|
||||
* For example entry points for the lambda feature (@ref lambda_xs)
|
||||
* will accept a non-const parserstatemachine pointer argument
|
||||
**/
|
||||
class parserstatemachine {
|
||||
public:
|
||||
using Expression = xo::ast::Expression;
|
||||
using Variable = xo::ast::Variable;
|
||||
using token_type = token<char>;
|
||||
|
||||
public:
|
||||
parserstatemachine(exprstatestack * p_stack,
|
||||
envframestack * p_env_stack,
|
||||
rp<Expression> * p_emit_expr)
|
||||
: p_stack_{p_stack},
|
||||
p_env_stack_{p_env_stack},
|
||||
p_emit_expr_{p_emit_expr} {}
|
||||
|
||||
std::unique_ptr<exprstate> pop_exprstate();
|
||||
exprstate & top_exprstate();
|
||||
void push_exprstate(std::unique_ptr<exprstate> x);
|
||||
|
||||
/** lookup variable name in lexical context represented by
|
||||
* this psm. nullptr if not found
|
||||
**/
|
||||
rp<Variable> lookup_var(const std::string & x) const;
|
||||
|
||||
void push_envframe(envframe x);
|
||||
void pop_envframe();
|
||||
|
||||
// ----- parsing outputs -----
|
||||
|
||||
void on_expr(ref::brw<Expression> expr);
|
||||
void on_expr_with_semicolon(ref::brw<Expression> expr);
|
||||
void on_symbol(const std::string & symbol);
|
||||
|
||||
// ---- parsing inputs -----
|
||||
|
||||
void on_semicolon_token(const token_type & tk);
|
||||
void on_operator_token(const token_type & tk);
|
||||
void on_leftbrace_token(const token_type & tk);
|
||||
void on_rightbrace_token(const token_type & tk);
|
||||
|
||||
/** write human-readable representation on @p os **/
|
||||
void print(std::ostream & os) const;
|
||||
|
||||
public:
|
||||
/** stack of incomplete parser work.
|
||||
* generally speaking, push when to start new work for nested content;
|
||||
* pop when work complete
|
||||
**/
|
||||
exprstatestack * p_stack_;
|
||||
/** stack of environment frames, one for each enclosing lambda **/
|
||||
envframestack * p_env_stack_;
|
||||
/** if non-null, store next non-nested complete expressions in
|
||||
* *p_emit_expr
|
||||
**/
|
||||
rp<Expression> * p_emit_expr_;
|
||||
};
|
||||
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream & os, const parserstatemachine & x) {
|
||||
x.print(os);
|
||||
return os;
|
||||
}
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end parserstatemachine.hpp */
|
||||
126
xo-reader/include/xo/reader/progress_xs.hpp
Normal file
126
xo-reader/include/xo/reader/progress_xs.hpp
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/** @file progress_xs.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
#include <iostream>
|
||||
//#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** represent an infix operator.
|
||||
*
|
||||
* See @ref progress_xs::assemble_expr() for translation
|
||||
* to Expression
|
||||
**/
|
||||
enum class optype {
|
||||
invalid = -1,
|
||||
|
||||
op_assign,
|
||||
|
||||
op_add,
|
||||
op_subtract,
|
||||
|
||||
op_multiply,
|
||||
op_divide,
|
||||
|
||||
n_optype
|
||||
};
|
||||
|
||||
extern const char *
|
||||
optype_descr(optype x);
|
||||
|
||||
/** report operator precedence.
|
||||
* lowest operator precedence is 1
|
||||
**/
|
||||
extern int
|
||||
precedence(optype x);
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, optype x) {
|
||||
os << optype_descr(x);
|
||||
return os;
|
||||
}
|
||||
|
||||
/** @class progress_xs
|
||||
* @brief state machine for parsing a schematica runtime-value-expression
|
||||
**/
|
||||
class progress_xs : public exprstate {
|
||||
public:
|
||||
progress_xs(rp<Expression> valex, optype op);
|
||||
virtual ~progress_xs() = default;
|
||||
|
||||
static const progress_xs * from(const exprstate * x) {
|
||||
return dynamic_cast<const progress_xs *>(x);
|
||||
}
|
||||
|
||||
static void start(rp<Expression> valex,
|
||||
optype optype,
|
||||
parserstatemachine * p_psm);
|
||||
static void start(rp<Expression> valex,
|
||||
parserstatemachine * p_psm);
|
||||
|
||||
bool admits_f64() const;
|
||||
|
||||
virtual void on_expr(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_symbol_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_typedescr(TypeDescr td,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void on_def_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_colon_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_semicolon_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
virtual void on_singleassign_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;
|
||||
|
||||
/* entry point for an infix operator token */
|
||||
virtual void on_operator_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void on_f64_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void print(std::ostream & os) const override;
|
||||
|
||||
private:
|
||||
static std::unique_ptr<progress_xs> make(rp<Expression> valex,
|
||||
optype optype = optype::invalid);
|
||||
|
||||
private:
|
||||
/** assemble expression representing
|
||||
* value of
|
||||
* @code
|
||||
* f(lhs_, rhs_)
|
||||
* @endcode
|
||||
*
|
||||
* where f determined by @ref op_type_
|
||||
**/
|
||||
rp<Expression> assemble_expr();
|
||||
|
||||
private:
|
||||
/** populate an expression here, may be followed by an operator **/
|
||||
rp<Expression> lhs_;
|
||||
|
||||
/** infix operator, if supplied **/
|
||||
optype op_type_ = optype::invalid;
|
||||
|
||||
/** populate an expression here, following infix operator */
|
||||
rp<Expression> rhs_;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end progress_xs.hpp **/
|
||||
107
xo-reader/include/xo/reader/reader.hpp
Normal file
107
xo-reader/include/xo/reader/reader.hpp
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/* file reader.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "xo/expression/Expression.hpp"
|
||||
#include "xo/tokenizer/tokenizer.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @class parse_result
|
||||
* @brief Result object returned from reader::read_expr
|
||||
**/
|
||||
struct reader_result {
|
||||
using Expression = xo::ast::Expression;
|
||||
using span_type = span<const char>;
|
||||
|
||||
reader_result(rp<Expression> expr, span_type rem)
|
||||
: expr_{std::move(expr)}, rem_{rem} {}
|
||||
|
||||
/** parsed schematica expression **/
|
||||
rp<Expression> expr_;
|
||||
/** span giving text input consumed to construct expr,
|
||||
* including any leading whitespace.
|
||||
* This is the span returned in result of tokenizer<char>::scan()
|
||||
**/
|
||||
span_type rem_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Use:
|
||||
* @code
|
||||
* reader rdr;
|
||||
* rdr.begin_translation_unit()
|
||||
*
|
||||
* bool eof = false;
|
||||
* while (!eof) {
|
||||
* auto input = ins.read_some();
|
||||
* // eof: true if no more input will be forthcoming from this stream
|
||||
* eof = ins.eof();
|
||||
*
|
||||
* for (auto rem = input; !rem.empty();) {
|
||||
* // res: (parsed-expr, used)
|
||||
* auto res = rdr.read_expr(rem, eof);
|
||||
*
|
||||
* if (res.first) {
|
||||
* // do something with res.first (parsed expr)
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* rem = rem.suffix_after(res.second);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // expect !rdr.has_prefix()
|
||||
*
|
||||
* @endcode
|
||||
**/
|
||||
class reader {
|
||||
public:
|
||||
using tokenizer_type = tokenizer<char>;
|
||||
using span_type = tokenizer_type::span_type;
|
||||
|
||||
public:
|
||||
reader() = default;
|
||||
|
||||
/** call once before calling .read_expr():
|
||||
* 1. with new reader
|
||||
* 2. if last read_expr() call had eof=true
|
||||
**/
|
||||
void begin_translation_unit();
|
||||
|
||||
/** counterpart to .begin_translation_unit(),
|
||||
* provided for symmetry's sake
|
||||
*
|
||||
* Equivalent to:
|
||||
* @code
|
||||
* read_expr(span_type(nullptr, nullptr), true);
|
||||
* @endcode
|
||||
**/
|
||||
reader_result end_translation_unit();
|
||||
|
||||
/** Try to read one expression from @p input.
|
||||
* Return struct containing parsed expression
|
||||
* and span of characters comprising that expression
|
||||
*
|
||||
* @param input Supply this input span of chars
|
||||
* @param eof. True if input stream supplying @p input
|
||||
* reports end-of-file immediately after the last char
|
||||
* in @p input.
|
||||
**/
|
||||
reader_result read_expr(const span_type & input, bool eof);
|
||||
|
||||
private:
|
||||
/** tokenizer: text -> tokens **/
|
||||
tokenizer_type tokenizer_;
|
||||
|
||||
/** parser: tokens -> expressions **/
|
||||
parser parser_;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end reader.hpp */
|
||||
47
xo-reader/include/xo/reader/sequence_xs.hpp
Normal file
47
xo-reader/include/xo/reader/sequence_xs.hpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/** @file sequence_xs.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace xo {
|
||||
namespace ast { class Sequence; }
|
||||
namespace ast { class Lambda; }
|
||||
|
||||
namespace scm {
|
||||
class sequence_xs : public exprstate {
|
||||
public:
|
||||
using Sequence = xo::ast::Sequence;
|
||||
using Lambda = xo::ast::Lambda;
|
||||
|
||||
public:
|
||||
/** start parsing a sequence-expr.
|
||||
* input begins with first expression in the sequence.
|
||||
**/
|
||||
static void start(parserstatemachine * p_psm);
|
||||
|
||||
virtual void on_expr(ref::brw<Expression> expr,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
virtual void on_rightbrace_token(const token_type & tk,
|
||||
parserstatemachine * p_psm) override;
|
||||
|
||||
private:
|
||||
sequence_xs();
|
||||
|
||||
/** named ctor idiom **/
|
||||
static std::unique_ptr<sequence_xs> make();
|
||||
|
||||
private:
|
||||
/** will build SequenceExpr from in-order contents of this vector **/
|
||||
std::vector<rp<Expression>> expr_v_;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end sequence_xs.hpp **/
|
||||
Loading…
Add table
Add a link
Reference in a new issue