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
8
xo-reader/.gitignore
vendored
Normal file
8
xo-reader/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# emacs workspace config
|
||||||
|
.projectile
|
||||||
|
# clangd working space (see emacs+lsp)
|
||||||
|
.cache
|
||||||
|
# typical cmake build directory (source-tree-nephew)
|
||||||
|
.build*
|
||||||
|
# symlink to builddir/compile_commands.json; should be set manually in dev sandbox
|
||||||
|
compile_commands.json
|
||||||
27
xo-reader/CMakeLists.txt
Normal file
27
xo-reader/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# xo-reader/CMakeLists.txt
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
project(xo_reader VERSION 0.1)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
include(cmake/xo-bootstrap-macros.cmake)
|
||||||
|
|
||||||
|
xo_cxx_toplevel_options3()
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# c++ settings
|
||||||
|
|
||||||
|
set(PROJECT_CXX_FLAGS "")
|
||||||
|
#set(PROJECT_CXX_FLAGS "-fconcepts-diagnostics-depth=2")
|
||||||
|
add_definitions(${PROJECT_CXX_FLAGS})
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
|
||||||
|
add_subdirectory(src/reader)
|
||||||
|
add_subdirectory(utest)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# provide find_package() support
|
||||||
|
|
||||||
|
xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets)
|
||||||
35
xo-reader/cmake/xo-bootstrap-macros.cmake
Normal file
35
xo-reader/cmake/xo-bootstrap-macros.cmake
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# for example:
|
||||||
|
# $ PREFIX=/usr/local # for example
|
||||||
|
# $ cmake -DCMAKE_MODULE_PATH=prefix -DCMAKE_INSTALL_PREFIX=$PREFIX -B .build
|
||||||
|
#
|
||||||
|
# will get
|
||||||
|
# CMAKE_MODULE_PATH
|
||||||
|
# from xo-cmake-config --cmake-module-path
|
||||||
|
#
|
||||||
|
# and expect .cmake macros in
|
||||||
|
# CMAKE_MODULE_PATH/xo_macros/xo_cxx.cmake
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
|
||||||
|
find_program(XO_CMAKE_CONFIG_EXECUTABLE NAMES xo-cmake-config REQUIRED)
|
||||||
|
|
||||||
|
if ("${XO_CMAKE_CONFIG_EXECUTABLE}" STREQUAL "XO_CMAKE_CONFIG_EXECUTABLE-NOT_FOUND")
|
||||||
|
message(FATAL "could not find xo-cmake-config executable")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "XO_CMAKE_CONFIG_EXECUTABLE=${XO_CMAKE_CONFIG_EXECUTABLE}")
|
||||||
|
|
||||||
|
if (NOT XO_SUBMODULE_BUILD)
|
||||||
|
if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix))
|
||||||
|
# default to typical install location for xo-project-macros
|
||||||
|
execute_process(COMMAND ${XO_CMAKE_CONFIG_EXECUTABLE} --cmake-module-path OUTPUT_VARIABLE CMAKE_MODULE_PATH)
|
||||||
|
message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# needs to have been installed somewhere on CMAKE_MODULE_PATH,
|
||||||
|
# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX)
|
||||||
|
#
|
||||||
|
include(xo_macros/xo_cxx)
|
||||||
|
|
||||||
|
xo_cxx_bootstrap_message()
|
||||||
8
xo-reader/cmake/xo_readerConfig.cmake.in
Normal file
8
xo-reader/cmake/xo_readerConfig.cmake.in
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include(CMakeFindDependencyMacro)
|
||||||
|
find_dependency(xo_expression)
|
||||||
|
find_dependency(xo_tokenizer)
|
||||||
|
#find_dependency(subsys)
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||||
|
check_required_components("@PROJECT_NAME@")
|
||||||
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 **/
|
||||||
29
xo-reader/src/reader/CMakeLists.txt
Normal file
29
xo-reader/src/reader/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# parser/CMakeLists.txt
|
||||||
|
|
||||||
|
set(SELF_LIB xo_reader)
|
||||||
|
set(SELF_SRCS
|
||||||
|
parser.cpp
|
||||||
|
parserstatemachine.cpp
|
||||||
|
reader.cpp
|
||||||
|
exprstate.cpp
|
||||||
|
exprstatestack.cpp
|
||||||
|
define_xs.cpp
|
||||||
|
progress_xs.cpp
|
||||||
|
paren_xs.cpp
|
||||||
|
sequence_xs.cpp
|
||||||
|
exprseq_xs.cpp
|
||||||
|
expect_expr_xs.cpp
|
||||||
|
expect_symbol_xs.cpp
|
||||||
|
expect_formal_xs.cpp
|
||||||
|
expect_formal_arglist_xs.cpp
|
||||||
|
expect_type_xs.cpp
|
||||||
|
lambda_xs.cpp
|
||||||
|
let1_xs.cpp
|
||||||
|
envframestack.cpp
|
||||||
|
envframe.cpp)
|
||||||
|
|
||||||
|
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
|
||||||
|
xo_dependency(${SELF_LIB} xo_expression)
|
||||||
|
xo_dependency(${SELF_LIB} xo_tokenizer)
|
||||||
|
|
||||||
|
# end CMakeLists.txt
|
||||||
276
xo-reader/src/reader/define_xs.cpp
Normal file
276
xo-reader/src/reader/define_xs.cpp
Normal file
|
|
@ -0,0 +1,276 @@
|
||||||
|
/* @file define_xs.cpp */
|
||||||
|
|
||||||
|
#include "define_xs.hpp"
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "expect_symbol_xs.hpp"
|
||||||
|
#include "expect_expr_xs.hpp"
|
||||||
|
#include "expect_type_xs.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace scm {
|
||||||
|
// ----- defexprstatetype -----
|
||||||
|
|
||||||
|
const char *
|
||||||
|
defexprstatetype_descr(defexprstatetype x) {
|
||||||
|
switch(x) {
|
||||||
|
case defexprstatetype::invalid: return "invalid";
|
||||||
|
case defexprstatetype::def_0: return "def_0";
|
||||||
|
case defexprstatetype::def_1: return "def_1";
|
||||||
|
case defexprstatetype::def_2: return "def_2";
|
||||||
|
case defexprstatetype::def_3: return "def_3";
|
||||||
|
case defexprstatetype::def_4: return "def_4";
|
||||||
|
case defexprstatetype::def_5: return "def_5";
|
||||||
|
case defexprstatetype::def_6: return "def_6";
|
||||||
|
case defexprstatetype::n_defexprstatetype: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "???defexprstatetype";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &
|
||||||
|
operator<<(std::ostream & os, defexprstatetype x) {
|
||||||
|
os << defexprstatetype_descr(x);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- define_xs -----
|
||||||
|
|
||||||
|
std::unique_ptr<define_xs>
|
||||||
|
define_xs::make() {
|
||||||
|
return std::make_unique<define_xs>(define_xs(DefineExprAccess::make_empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::start(parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
p_psm->push_exprstate(define_xs::make());
|
||||||
|
p_psm->top_exprstate().on_def_token(token_type::def(), p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
define_xs::define_xs(rp<DefineExprAccess> def_expr)
|
||||||
|
: exprstate(exprstatetype::defexpr),
|
||||||
|
defxs_type_{defexprstatetype::def_0},
|
||||||
|
def_expr_{std::move(def_expr)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_expr(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("defxs_type", defxs_type_));
|
||||||
|
|
||||||
|
if (this->defxs_type_ == defexprstatetype::def_5) {
|
||||||
|
/* have all the ingredients to create an expression
|
||||||
|
* representing a definition
|
||||||
|
*
|
||||||
|
* 1. if ir_type is a symbol, interpret as variable name.
|
||||||
|
* Need to be able to locate variable by type
|
||||||
|
* 2. if ir_type is an expression, adopt as rhs
|
||||||
|
*/
|
||||||
|
rp<Expression> rhs_value = expr.promote();
|
||||||
|
|
||||||
|
if (this->cvt_expr_)
|
||||||
|
this->cvt_expr_->assign_arg(rhs_value);
|
||||||
|
else
|
||||||
|
this->def_expr_->assign_rhs(rhs_value);;
|
||||||
|
|
||||||
|
rp<Expression> def_expr = this->def_expr_;
|
||||||
|
|
||||||
|
this->defxs_type_ = defexprstatetype::def_6;
|
||||||
|
} else {
|
||||||
|
exprstate::on_expr(expr, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_expr_with_semicolon(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
this->on_expr(expr, p_psm);
|
||||||
|
/* semicolon is allowed to terminate def expr */
|
||||||
|
this->on_semicolon_token(token_type::semicolon(), p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
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));
|
||||||
|
|
||||||
|
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);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
exprstate::on_symbol(symbol_name, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_typedescr(TypeDescr td,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log("defxs_type", defxs_type_);
|
||||||
|
|
||||||
|
if (this->defxs_type_ == defexprstatetype::def_3) {
|
||||||
|
this->defxs_type_ = defexprstatetype::def_4;
|
||||||
|
this->cvt_expr_ = ConvertExprAccess::make(td /*dest_type*/,
|
||||||
|
nullptr /*source_expr*/);
|
||||||
|
this->def_expr_->assign_rhs(this->cvt_expr_);
|
||||||
|
//this->def_lhs_td_ = td;
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
exprstate::on_typedescr(td, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_def_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log("defxs_type", defxs_type_);
|
||||||
|
|
||||||
|
if (this->defxs_type_ == defexprstatetype::def_0) {
|
||||||
|
this->defxs_type_ = defexprstatetype::def_1;
|
||||||
|
|
||||||
|
expect_symbol_xs::start(p_psm);
|
||||||
|
} else {
|
||||||
|
exprstate::on_def_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_colon_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log("defxs_type", defxs_type_);
|
||||||
|
|
||||||
|
if (this->defxs_type_ == defexprstatetype::def_2) {
|
||||||
|
this->defxs_type_ = defexprstatetype::def_3;
|
||||||
|
|
||||||
|
expect_type_xs::start(p_psm);
|
||||||
|
} else {
|
||||||
|
exprstate::on_colon_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_semicolon_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
/* def expr consumes semicolon */
|
||||||
|
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log("defxs_type", defxs_type_);
|
||||||
|
|
||||||
|
if (this->defxs_type_ == defexprstatetype::def_6) {
|
||||||
|
rp<Expression> expr = this->def_expr_;
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
p_psm->top_exprstate().on_expr(expr, p_psm);
|
||||||
|
} else {
|
||||||
|
exprstate::on_semicolon_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_singleassign_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "define_xs::on_singleassign_token";
|
||||||
|
|
||||||
|
log && log("defxs_type", defxs_type_);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* def foo = 1 ;
|
||||||
|
* def foo : f64 = 1 ;
|
||||||
|
* ^ ^ ^ ^ ^ ^ ^ ^
|
||||||
|
* | | | | | | | (done)
|
||||||
|
* | | | | | | def_6
|
||||||
|
* | | | | | def_5:expect_rhs_expression
|
||||||
|
* | | | | def_4
|
||||||
|
* | | | def_3:expect_type
|
||||||
|
* | | def_2
|
||||||
|
* | def_1:expect_symbol
|
||||||
|
* expect_toplevel_expression_sequence
|
||||||
|
*
|
||||||
|
* note that we skip from def_2 -> def_5 if '=' instead of ':'
|
||||||
|
*/
|
||||||
|
if ((this->defxs_type_ == defexprstatetype::def_2)
|
||||||
|
|| (this->defxs_type_ == defexprstatetype::def_4))
|
||||||
|
{
|
||||||
|
this->defxs_type_ = defexprstatetype::def_5;
|
||||||
|
|
||||||
|
expect_expr_xs::start(p_psm);
|
||||||
|
} else {
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_rightparen_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "define_xs::on_rightparen";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_f64_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "define_xs::on_f64";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::print(std::ostream & os) const {
|
||||||
|
os << "<define_xs"
|
||||||
|
<< 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*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end define_xs.cpp */
|
||||||
34
xo-reader/src/reader/envframe.cpp
Normal file
34
xo-reader/src/reader/envframe.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* file envframe.cpp
|
||||||
|
*
|
||||||
|
* author: Roland Conybeare
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "envframe.hpp"
|
||||||
|
#include "xo/indentlog/print/vector.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::ast::Variable;
|
||||||
|
|
||||||
|
namespace scm {
|
||||||
|
rp<Variable>
|
||||||
|
envframe::lookup(const std::string & x) const {
|
||||||
|
for (const auto & var : argl_) {
|
||||||
|
if (x == var->name())
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
envframe::print(std::ostream & os) const {
|
||||||
|
os << "<envframe"
|
||||||
|
<< xtag("argl", argl_)
|
||||||
|
<< ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
} /*namespace scm */
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
/* end envframe.cpp */
|
||||||
86
xo-reader/src/reader/envframestack.cpp
Normal file
86
xo-reader/src/reader/envframestack.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
/* file envframestack.cpp
|
||||||
|
*
|
||||||
|
* author: Roland Conybeare
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "envframestack.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::ast::Variable;
|
||||||
|
|
||||||
|
namespace scm {
|
||||||
|
envframe &
|
||||||
|
envframestack::top_envframe() {
|
||||||
|
std::size_t z = stack_.size();
|
||||||
|
|
||||||
|
if (z == 0) {
|
||||||
|
throw std::runtime_error
|
||||||
|
("parser::top_exprstate: unexpected empty stack");
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack_[z-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
envframestack::push_envframe(envframe frame) {
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag),
|
||||||
|
xtag("frame", frame));
|
||||||
|
|
||||||
|
std::size_t z = stack_.size();
|
||||||
|
|
||||||
|
stack_.resize(z+1);
|
||||||
|
|
||||||
|
stack_[z] = std::move(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
envframestack::pop_envframe() {
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
std::size_t z = stack_.size();
|
||||||
|
|
||||||
|
if (z > 0) {
|
||||||
|
//std::unique_ptr<exprstate> top = std::move(stack_[z-1]);
|
||||||
|
|
||||||
|
stack_.resize(z-1);
|
||||||
|
|
||||||
|
//return top;
|
||||||
|
} else {
|
||||||
|
//return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rp<Variable>
|
||||||
|
envframestack::lookup(const std::string & x) const {
|
||||||
|
for (std::size_t i = 0, z = this->size(); i < z; ++i) {
|
||||||
|
const auto & frame = (*this)[i];
|
||||||
|
|
||||||
|
auto retval = frame.lookup(x);
|
||||||
|
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
envframestack::print(std::ostream & os) const {
|
||||||
|
os << "<envframestack"
|
||||||
|
<< xtag("size", stack_.size())
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
for (std::size_t i = 0, z = stack_.size(); i < z; ++i) {
|
||||||
|
os << " [" << z-i-1 << "] "
|
||||||
|
<< stack_[i]
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
os << ">" << std::endl;
|
||||||
|
}
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end envframestack.cpp */
|
||||||
227
xo-reader/src/reader/expect_expr_xs.cpp
Normal file
227
xo-reader/src/reader/expect_expr_xs.cpp
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
/* file expect_expr_xs.cpp
|
||||||
|
*
|
||||||
|
* author: Roland Conybeare
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "expect_expr_xs.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
#include "lambda_xs.hpp"
|
||||||
|
#include "define_xs.hpp"
|
||||||
|
#include "paren_xs.hpp"
|
||||||
|
#include "sequence_xs.hpp"
|
||||||
|
#include "progress_xs.hpp"
|
||||||
|
#include "xo/expression/Lambda.hpp"
|
||||||
|
#include "xo/expression/Constant.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::ast::Constant;
|
||||||
|
|
||||||
|
namespace scm {
|
||||||
|
|
||||||
|
std::unique_ptr<expect_expr_xs>
|
||||||
|
expect_expr_xs::make(bool allow_defs,
|
||||||
|
bool cxl_on_rightbrace)
|
||||||
|
{
|
||||||
|
return std::make_unique<expect_expr_xs>(expect_expr_xs(allow_defs,
|
||||||
|
cxl_on_rightbrace));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_expr_xs::start(bool allow_defs,
|
||||||
|
bool cxl_on_rightbrace,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
p_psm->push_exprstate(expect_expr_xs::make(allow_defs,
|
||||||
|
cxl_on_rightbrace));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_expr_xs::start(parserstatemachine * p_psm) {
|
||||||
|
start(false /*!allow_defs*/,
|
||||||
|
false /*!cxl_on_rightbrace*/,
|
||||||
|
p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_expr_xs::expect_expr_xs(bool allow_defs,
|
||||||
|
bool cxl_on_rightbrace)
|
||||||
|
: exprstate(exprstatetype::expect_rhs_expression),
|
||||||
|
allow_defs_{allow_defs},
|
||||||
|
cxl_on_rightbrace_{cxl_on_rightbrace}
|
||||||
|
{}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
if (allow_defs_) {
|
||||||
|
define_xs::start(p_psm);
|
||||||
|
} else {
|
||||||
|
exprstate::on_def_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
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));
|
||||||
|
|
||||||
|
//constexpr const char * self_name = "exprstate::on_leftparen";
|
||||||
|
|
||||||
|
lambda_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));
|
||||||
|
|
||||||
|
//constexpr const char * self_name = "exprstate::on_leftparen";
|
||||||
|
|
||||||
|
/* push lparen_0 to remember to look for subsequent rightparen. */
|
||||||
|
paren_xs::start(p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
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));
|
||||||
|
|
||||||
|
/* push lparen_0 to remember to look for subsequent rightparen. */
|
||||||
|
sequence_xs::start(p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_expr_xs::on_rightbrace_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
if (cxl_on_rightbrace_) {
|
||||||
|
auto self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
/* do not call .on_expr(), since '}' cancelled */
|
||||||
|
|
||||||
|
p_psm->on_rightbrace_token(tk);
|
||||||
|
} else {
|
||||||
|
exprstate::on_rightbrace_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
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));
|
||||||
|
|
||||||
|
log && log(xtag("tk", tk));
|
||||||
|
|
||||||
|
/* various possibilities when looking for rhs expression:
|
||||||
|
*
|
||||||
|
* x := y // (1)
|
||||||
|
* x := f(a) // (2)
|
||||||
|
* x := f(a,b) // (3)
|
||||||
|
*
|
||||||
|
* need lookahead token following symbol to distinguish
|
||||||
|
* between (1) (symbol completes rhs expression)
|
||||||
|
* and {(2), (3)} (symbol is function call)
|
||||||
|
*/
|
||||||
|
|
||||||
|
rp<Variable> var = p_psm->lookup_var(tk.text());
|
||||||
|
|
||||||
|
if (!var) {
|
||||||
|
throw std::runtime_error
|
||||||
|
(tostr("expect_expr_xs::on_symbol_token",
|
||||||
|
": unknown symbol",
|
||||||
|
xtag("name", tk.text())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* e.g.
|
||||||
|
* def pi = 3.14159265;
|
||||||
|
* def mypi = pi;
|
||||||
|
* ^
|
||||||
|
* def pi2 = pi * 2;
|
||||||
|
* ^
|
||||||
|
* def y = foo(pi2);
|
||||||
|
* ^
|
||||||
|
*/
|
||||||
|
progress_xs::start(var, p_psm);
|
||||||
|
|
||||||
|
#ifdef NOT_YET
|
||||||
|
p_stack->push_exprstate(exprstate(exprstatetype::expr_progress,
|
||||||
|
Variable::make(name, type)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LATER
|
||||||
|
p_psm->pop_exprstate();
|
||||||
|
p_psm->top_exprstate().on_symbol(tk.text(),
|
||||||
|
p_stack, p_emit_expr);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
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));
|
||||||
|
|
||||||
|
//constexpr const char * self_name = "exprstate::on_f64_token";
|
||||||
|
|
||||||
|
/* e.g.
|
||||||
|
* def pi = 3.14159265;
|
||||||
|
* \---tk---/
|
||||||
|
*/
|
||||||
|
progress_xs::start
|
||||||
|
(Constant<double>::make(tk.f64_value()),
|
||||||
|
p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_expr_xs::on_expr(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("exstype", this->exs_type_),
|
||||||
|
xtag("expr", expr.promote()));
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
p_psm->on_expr(expr);
|
||||||
|
} /*on_expr*/
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_expr_xs::on_expr_with_semicolon(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("exstype", this->exs_type_),
|
||||||
|
xtag("expr", expr.promote()));
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
p_psm->on_expr_with_semicolon(expr);
|
||||||
|
} /*on_expr_with_semicolon*/
|
||||||
|
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end expect_expr_xs.cpp */
|
||||||
113
xo-reader/src/reader/expect_formal_arglist_xs.cpp
Normal file
113
xo-reader/src/reader/expect_formal_arglist_xs.cpp
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
/* file expect_formal_arglist_xs.cpp
|
||||||
|
*
|
||||||
|
* author: Roland Conybeare
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "expect_formal_arglist_xs.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
#include "expect_formal_xs.hpp"
|
||||||
|
#include "expect_symbol_xs.hpp"
|
||||||
|
#include "xo/expression/Variable.hpp"
|
||||||
|
#include "xo/indentlog/print/vector.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace scm {
|
||||||
|
const char *
|
||||||
|
formalarglstatetype_descr(formalarglstatetype x) {
|
||||||
|
switch (x) {
|
||||||
|
case formalarglstatetype::invalid:
|
||||||
|
return "invalid";
|
||||||
|
case formalarglstatetype::argl_0:
|
||||||
|
return "argl_0";
|
||||||
|
case formalarglstatetype::argl_1a:
|
||||||
|
return "argl_1a";
|
||||||
|
case formalarglstatetype::argl_1b:
|
||||||
|
return "argl_1b";
|
||||||
|
case formalarglstatetype::n_formalarglstatetype:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "?formalarglstatetype";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<expect_formal_arglist_xs>
|
||||||
|
expect_formal_arglist_xs::make() {
|
||||||
|
return std::make_unique<expect_formal_arglist_xs>
|
||||||
|
(expect_formal_arglist_xs());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_formal_arglist_xs::start(parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
p_psm->push_exprstate(expect_formal_arglist_xs::make());
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_formal_arglist_xs::expect_formal_arglist_xs()
|
||||||
|
: exprstate(exprstatetype::expect_formal_arglist),
|
||||||
|
farglxs_type_{formalarglstatetype::argl_0}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_formal_arglist_xs::on_leftparen_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
if (farglxs_type_ == formalarglstatetype::argl_0) {
|
||||||
|
this->farglxs_type_ = formalarglstatetype::argl_1a;
|
||||||
|
/* TODO: refactor to have setup method on each exprstate */
|
||||||
|
expect_formal_xs::start(p_psm);
|
||||||
|
} else {
|
||||||
|
exprstate::on_leftparen_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_formal_arglist_xs::on_formal(const rp<Variable> & formal,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
if (farglxs_type_ == formalarglstatetype::argl_1a) {
|
||||||
|
this->farglxs_type_ = formalarglstatetype::argl_1b;
|
||||||
|
this->argl_.push_back(formal);
|
||||||
|
} else {
|
||||||
|
exprstate::on_formal(formal, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_formal_arglist_xs::on_comma_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
if (farglxs_type_ == formalarglstatetype::argl_1b) {
|
||||||
|
this->farglxs_type_ = formalarglstatetype::argl_1a;
|
||||||
|
expect_formal_xs::start(p_psm);
|
||||||
|
} else {
|
||||||
|
exprstate::on_comma_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_formal_arglist_xs::on_rightparen_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
if (farglxs_type_ == formalarglstatetype::argl_1b) {
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
p_psm->top_exprstate().on_formal_arglist(this->argl_, p_psm);
|
||||||
|
} else {
|
||||||
|
exprstate::on_rightparen_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_formal_arglist_xs::print(std::ostream & os) const {
|
||||||
|
os << "<expect_formal_arglist_xs"
|
||||||
|
<< xtag("type", farglxs_type_);
|
||||||
|
os << xtag("farglxs_type", farglxs_type_);
|
||||||
|
os << xtag("argl", argl_);
|
||||||
|
os << ">";
|
||||||
|
}
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
/* end expect_formal_arglist_xs.cpp */
|
||||||
109
xo-reader/src/reader/expect_formal_xs.cpp
Normal file
109
xo-reader/src/reader/expect_formal_xs.cpp
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
/* file expect_formal_xs.cpp
|
||||||
|
*
|
||||||
|
* author: Roland Conybeare
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "expect_formal_xs.hpp"
|
||||||
|
#include "expect_symbol_xs.hpp"
|
||||||
|
#include "expect_type_xs.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
#include "xo/expression/Variable.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::ast::Variable;
|
||||||
|
using xo::reflect::TypeDescr;
|
||||||
|
|
||||||
|
namespace scm{
|
||||||
|
const char *
|
||||||
|
formalstatetype_descr(formalstatetype x) {
|
||||||
|
switch (x) {
|
||||||
|
case formalstatetype::invalid:
|
||||||
|
case formalstatetype::n_formalstatetype:
|
||||||
|
return "?formalstatetype";
|
||||||
|
case formalstatetype::formal_0:
|
||||||
|
return "formal_0";
|
||||||
|
case formalstatetype::formal_1:
|
||||||
|
return "formal_1";
|
||||||
|
case formalstatetype::formal_2:
|
||||||
|
return "formal_2";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "???formalstatetype";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<expect_formal_xs>
|
||||||
|
expect_formal_xs::make() {
|
||||||
|
return std::make_unique<expect_formal_xs>(expect_formal_xs());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_formal_xs::start(parserstatemachine * p_psm) {
|
||||||
|
p_psm->push_exprstate(expect_formal_xs::make());
|
||||||
|
|
||||||
|
expect_symbol_xs::start(p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_formal_xs::expect_formal_xs()
|
||||||
|
: exprstate(exprstatetype::expect_formal)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_formal_xs::on_symbol(const std::string & symbol_name,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
if (this->formalxs_type_ == formalstatetype::formal_0) {
|
||||||
|
this->formalxs_type_ = formalstatetype::formal_1;
|
||||||
|
this->result_.assign_name(symbol_name);
|
||||||
|
} else {
|
||||||
|
exprstate::on_symbol(symbol_name, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_formal_xs::on_colon_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
if (this->formalxs_type_ == formalstatetype::formal_1) {
|
||||||
|
this->formalxs_type_ = formalstatetype::formal_2;
|
||||||
|
expect_type_xs::start(p_psm);
|
||||||
|
/* control reenters via expect_formal_xs::on_typedescr() */
|
||||||
|
} else {
|
||||||
|
exprstate::on_colon_token(tk,
|
||||||
|
p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_formal_xs::on_typedescr(TypeDescr td,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
if (this->formalxs_type_ == formalstatetype::formal_2) {
|
||||||
|
this->result_.assign_td(td);
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
rp<Variable> var = Variable::make(result_.name(),
|
||||||
|
result_.td());
|
||||||
|
|
||||||
|
p_psm->top_exprstate().on_formal(var, p_psm);
|
||||||
|
} else {
|
||||||
|
exprstate::on_typedescr(td, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_formal_xs::print(std::ostream & os) const {
|
||||||
|
os << "<expect_formal_xs"
|
||||||
|
<< xtag("type", formalxs_type_);
|
||||||
|
if (!result_.name().empty())
|
||||||
|
os << xtag("result.name", result_.name());
|
||||||
|
if (result_.td())
|
||||||
|
os << xtag("result.td", result_.td());
|
||||||
|
os << ">";
|
||||||
|
}
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
/* end expect_formal_xs.cpp */
|
||||||
47
xo-reader/src/reader/expect_symbol_xs.cpp
Normal file
47
xo-reader/src/reader/expect_symbol_xs.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
/* file expect_symbol_xs.cpp
|
||||||
|
*
|
||||||
|
* author: Roland Conybeare
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "expect_symbol_xs.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace scm {
|
||||||
|
std::unique_ptr<expect_symbol_xs>
|
||||||
|
expect_symbol_xs::make() {
|
||||||
|
return std::make_unique<expect_symbol_xs>(expect_symbol_xs());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_symbol_xs::start(parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
p_psm->push_exprstate(expect_symbol_xs::make());
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_symbol_xs::expect_symbol_xs()
|
||||||
|
: exprstate(exprstatetype::expect_symbol)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_symbol_xs::on_symbol_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("tk", tk));
|
||||||
|
|
||||||
|
/* have to do pop first, before sending symbol to
|
||||||
|
* the o.g. symbol-requester
|
||||||
|
*/
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
p_psm->on_symbol(tk.text());
|
||||||
|
}
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
/* end expect_symbol_xs.cpp */
|
||||||
66
xo-reader/src/reader/expect_type_xs.cpp
Normal file
66
xo-reader/src/reader/expect_type_xs.cpp
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* file expect_type_xs.cpp
|
||||||
|
*
|
||||||
|
* author: Roland Conybeare
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "expect_type_xs.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
#include "xo/reflect/Reflect.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::reflect::Reflect;
|
||||||
|
|
||||||
|
namespace scm {
|
||||||
|
|
||||||
|
std::unique_ptr<expect_type_xs>
|
||||||
|
expect_type_xs::make() {
|
||||||
|
return std::make_unique<expect_type_xs>(expect_type_xs());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_type_xs::start(parserstatemachine * p_psm) {
|
||||||
|
p_psm->push_exprstate(expect_type_xs::make());
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_type_xs::expect_type_xs()
|
||||||
|
: exprstate(exprstatetype::expect_type)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
expect_type_xs::on_symbol_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
const char * c_self_name = "expect_type_xs::on_symbol_token";
|
||||||
|
|
||||||
|
TypeDescr td = nullptr;
|
||||||
|
|
||||||
|
/* TODO: replace with typetable lookup */
|
||||||
|
|
||||||
|
if (tk.text() == "f64")
|
||||||
|
td = Reflect::require<double>();
|
||||||
|
else if(tk.text() == "f32")
|
||||||
|
td = Reflect::require<float>();
|
||||||
|
else if(tk.text() == "i16")
|
||||||
|
td = Reflect::require<std::int16_t>();
|
||||||
|
else if(tk.text() == "i32")
|
||||||
|
td = Reflect::require<std::int32_t>();
|
||||||
|
else if(tk.text() == "i64")
|
||||||
|
td = Reflect::require<std::int64_t>();
|
||||||
|
|
||||||
|
if (!td) {
|
||||||
|
throw std::runtime_error
|
||||||
|
(tostr(c_self_name,
|
||||||
|
": unknown type name",
|
||||||
|
" (expecting f64|f32|i16|i32|i64)",
|
||||||
|
xtag("typename", tk.text())));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
p_psm->top_exprstate().on_typedescr(td, p_psm);
|
||||||
|
}
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
/* end expect_type_xs.cpp */
|
||||||
81
xo-reader/src/reader/exprseq_xs.cpp
Normal file
81
xo-reader/src/reader/exprseq_xs.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
/* @file exprseq_xs.cpp */
|
||||||
|
|
||||||
|
#include "exprseq_xs.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
#include "define_xs.hpp"
|
||||||
|
#include "expect_symbol_xs.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace scm {
|
||||||
|
std::unique_ptr<exprseq_xs>
|
||||||
|
exprseq_xs::make()
|
||||||
|
{
|
||||||
|
return std::make_unique<exprseq_xs>(exprseq_xs());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprseq_xs::start(parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
p_psm->push_exprstate(exprseq_xs::make());
|
||||||
|
}
|
||||||
|
|
||||||
|
exprseq_xs::exprseq_xs()
|
||||||
|
: exprstate(exprstatetype::expect_toplevel_expression_sequence)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprseq_xs::on_def_token(const token_type & /*tk*/,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
//constexpr const char * c_self_name = "exprseq_xs::on_def_token";
|
||||||
|
|
||||||
|
define_xs::start(p_psm);
|
||||||
|
|
||||||
|
/* keyword 'def' introduces a definition:
|
||||||
|
* def pi : f64 = 3.14159265
|
||||||
|
* def sq(x : f64) -> f64 { (x * x) }
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprseq_xs::on_symbol_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr const char * c_self_name = "exprseq_xs::on_symbol_token";
|
||||||
|
|
||||||
|
this->illegal_input_error(c_self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprseq_xs::on_typedescr(TypeDescr /*td*/,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
/* unreachable - typedescr should never get delivered to exprseq */
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprseq_xs::on_expr(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
/* toplevel expression sequence accepts an
|
||||||
|
* arbitrary number of expressions.
|
||||||
|
*
|
||||||
|
* parser::include_token() returns
|
||||||
|
*/
|
||||||
|
|
||||||
|
auto p_emit_expr = p_psm->p_emit_expr_;
|
||||||
|
|
||||||
|
*p_emit_expr = expr.promote();
|
||||||
|
} /*on_expr*/
|
||||||
|
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end exprseq_xs.cpp */
|
||||||
448
xo-reader/src/reader/exprstate.cpp
Normal file
448
xo-reader/src/reader/exprstate.cpp
Normal file
|
|
@ -0,0 +1,448 @@
|
||||||
|
/* @file exprstate.cpp */
|
||||||
|
|
||||||
|
#include "exprstate.hpp"
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
//#include "formal_arg.hpp"
|
||||||
|
#include "xo/expression/Variable.hpp"
|
||||||
|
#include "xo/indentlog/print/vector.hpp"
|
||||||
|
#include <stdexcept>
|
||||||
|
//#include "define_xs.hpp"
|
||||||
|
//#include "progress_xs.hpp"
|
||||||
|
//#include "paren_xs.hpp"
|
||||||
|
//#include "expect_expr_xs.hpp"
|
||||||
|
//#include "xo/expression/Constant.hpp"
|
||||||
|
//#include "xo/reflect/Reflect.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
//using xo::ast::Constant;
|
||||||
|
//using xo::reflect::Reflect;
|
||||||
|
using xo::reflect::TypeDescr;
|
||||||
|
|
||||||
|
namespace scm {
|
||||||
|
const char *
|
||||||
|
exprstatetype_descr(exprstatetype x) {
|
||||||
|
switch (x) {
|
||||||
|
case exprstatetype::invalid:
|
||||||
|
return "?invalid";
|
||||||
|
case exprstatetype::expect_toplevel_expression_sequence:
|
||||||
|
return "expect_toplevel_expression_sequence";
|
||||||
|
case exprstatetype::defexpr:
|
||||||
|
return "defexpr";
|
||||||
|
case exprstatetype::lambdaexpr:
|
||||||
|
return "lambdaexpr";
|
||||||
|
case exprstatetype::parenexpr:
|
||||||
|
return "parenexpr";
|
||||||
|
case exprstatetype::sequenceexpr:
|
||||||
|
return "sequenceexpr";
|
||||||
|
case exprstatetype::let1expr:
|
||||||
|
return "let1expr";
|
||||||
|
case exprstatetype::expect_rhs_expression:
|
||||||
|
return "expect_rhs_expression";
|
||||||
|
case exprstatetype::expect_symbol:
|
||||||
|
return "expect_symbol";
|
||||||
|
case exprstatetype::expect_type:
|
||||||
|
return "expect_type";
|
||||||
|
case exprstatetype::expect_formal_arglist:
|
||||||
|
return "expect_formal_arglist";
|
||||||
|
case exprstatetype::expect_formal:
|
||||||
|
return "expect_formal";
|
||||||
|
case exprstatetype::expr_progress:
|
||||||
|
return "expr_progress";
|
||||||
|
case exprstatetype::n_exprstatetype:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "???";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_def_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
this->illegal_input_error("exprstate::on_def_token", tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_lambda_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
this->illegal_input_error("exprstate::on_lambda_token", tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_symbol_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("exstype", p_psm->top_exprstate().exs_type()));
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "exprstate::on_symbol_token";
|
||||||
|
|
||||||
|
this->illegal_input_error(c_self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_typedescr(TypeDescr td,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
/* returning type description to something that wants it */
|
||||||
|
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("exstype",
|
||||||
|
p_psm->top_exprstate().exs_type()));
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "exprstate::on_typedescr";
|
||||||
|
|
||||||
|
throw std::runtime_error(tostr(c_self_name,
|
||||||
|
": unexpected typedescr for parsing state",
|
||||||
|
xtag("td", td),
|
||||||
|
xtag("state", *this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_formal(const rp<Variable> & formal,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
/* returning type description to something that wants it */
|
||||||
|
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("exstype",
|
||||||
|
p_psm->top_exprstate().exs_type()));
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "exprstate::on_formal";
|
||||||
|
|
||||||
|
throw std::runtime_error(tostr(c_self_name,
|
||||||
|
": unexpected formal-arg for parsing state",
|
||||||
|
xtag("formal", formal.get()),
|
||||||
|
xtag("state", *this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_formal_arglist(const std::vector<rp<Variable>> & argl,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
/* returning type description to something that wants it */
|
||||||
|
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("exstype",
|
||||||
|
p_psm->top_exprstate().exs_type()));
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "exprstate::on_formal_arglist";
|
||||||
|
|
||||||
|
throw std::runtime_error(tostr(c_self_name,
|
||||||
|
": unexpected formal-arg for parsing state",
|
||||||
|
xtag("argl", argl),
|
||||||
|
xtag("state", *this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_colon_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "exprstate::on_colon";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_comma_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "exprstate::on_comma";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_semicolon_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "exprstate::on_semicolon";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_singleassign_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/) {
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "exprstate::on_singleassign_token";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_leftparen_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "exprstate::on_leftparen_token";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_rightparen_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "exprstate::on_rightparen";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_leftbrace_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "exprstate::on_leftbrace_token";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_rightbrace_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "exprstate::on_rightbrace_token";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_operator_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "exprstate::on_operator_token";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_f64_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "exprstate::on_f64";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_input(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
log && log(xtag("tk", tk));
|
||||||
|
log && log(xtag("state", *this));
|
||||||
|
log && log(xtag("psm", *p_psm));
|
||||||
|
|
||||||
|
switch (tk.tk_type()) {
|
||||||
|
|
||||||
|
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_i64:
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_f64:
|
||||||
|
this->on_f64_token(tk, p_psm);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_string:
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_symbol:
|
||||||
|
this->on_symbol_token(tk, p_psm);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_leftparen:
|
||||||
|
this->on_leftparen_token(tk, p_psm);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_rightparen:
|
||||||
|
this->on_rightparen_token(tk, p_psm);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_leftbracket:
|
||||||
|
case tokentype::tk_rightbracket:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case tokentype::tk_leftbrace:
|
||||||
|
this->on_leftbrace_token(tk, p_psm);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_rightbrace:
|
||||||
|
this->on_rightbrace_token(tk, p_psm);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_leftangle:
|
||||||
|
case tokentype::tk_rightangle:
|
||||||
|
case tokentype::tk_dot:
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_comma:
|
||||||
|
this->on_comma_token(tk, p_psm);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_colon:
|
||||||
|
this->on_colon_token(tk, p_psm);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_doublecolon:
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_semicolon:
|
||||||
|
this->on_semicolon_token(tk, p_psm);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_singleassign:
|
||||||
|
this->on_singleassign_token(tk, p_psm);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_assign:
|
||||||
|
case tokentype::tk_yields:
|
||||||
|
|
||||||
|
case tokentype::tk_plus:
|
||||||
|
case tokentype::tk_minus:
|
||||||
|
case tokentype::tk_star:
|
||||||
|
case tokentype::tk_slash:
|
||||||
|
this->on_operator_token(tk, p_psm);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_type:
|
||||||
|
case tokentype::tk_if:
|
||||||
|
case tokentype::tk_let:
|
||||||
|
|
||||||
|
case tokentype::tk_in:
|
||||||
|
case tokentype::tk_end:
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case tokentype::tk_invalid:
|
||||||
|
case tokentype::n_tokentype:
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_expr(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("exstype", this->exs_type_),
|
||||||
|
xtag("expr", expr));
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
} /*on_expr*/
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_expr_with_semicolon(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
const char * c_self_name = "exprstate::on_expr_with_semicolon";
|
||||||
|
|
||||||
|
log && log(xtag("exstype", this->exs_type_),
|
||||||
|
xtag("expr", expr));
|
||||||
|
|
||||||
|
throw std::runtime_error
|
||||||
|
(tostr(c_self_name,
|
||||||
|
": unexpected expression for parsing state",
|
||||||
|
xtag("expr", expr),
|
||||||
|
xtag("state", *this)));
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
} /*on_expr_with_semicolon*/
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::on_symbol(const std::string & symbol_name,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
/* unreachable - derived class that can receive
|
||||||
|
* will override this method
|
||||||
|
*/
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("exstype", this->exs_type_),
|
||||||
|
xtag("symbol_name", symbol_name));
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::print(std::ostream & os) const {
|
||||||
|
os << "<exprstate"
|
||||||
|
<< xtag("this", (void*)this)
|
||||||
|
<< xtag("type", exs_type_);
|
||||||
|
os << ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstate::illegal_input_error(const char * self_name,
|
||||||
|
const token_type & tk) const
|
||||||
|
{
|
||||||
|
throw std::runtime_error
|
||||||
|
(tostr(self_name,
|
||||||
|
": unexpected input token for parsing state",
|
||||||
|
xtag("token", tk),
|
||||||
|
xtag("state", *this)));
|
||||||
|
}
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end exprstate.cpp */
|
||||||
71
xo-reader/src/reader/exprstatestack.cpp
Normal file
71
xo-reader/src/reader/exprstatestack.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
/* file exprstatestack.cpp
|
||||||
|
*
|
||||||
|
* author: Roland Conybeare
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace scm {
|
||||||
|
exprstate &
|
||||||
|
exprstatestack::top_exprstate() {
|
||||||
|
std::size_t z = stack_.size();
|
||||||
|
|
||||||
|
if (z == 0) {
|
||||||
|
throw std::runtime_error
|
||||||
|
("parser::top_exprstate: unexpected empty stack");
|
||||||
|
}
|
||||||
|
|
||||||
|
return *(stack_[z-1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstatestack::push_exprstate(std::unique_ptr<exprstate> exs) {
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag),
|
||||||
|
xtag("exs", exs.get()));
|
||||||
|
|
||||||
|
std::size_t z = stack_.size();
|
||||||
|
|
||||||
|
stack_.resize(z+1);
|
||||||
|
|
||||||
|
stack_[z] = std::move(exs);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate>
|
||||||
|
exprstatestack::pop_exprstate() {
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag),
|
||||||
|
xtag("top.exstype", top_exprstate().exs_type()));
|
||||||
|
|
||||||
|
std::size_t z = stack_.size();
|
||||||
|
|
||||||
|
if (z > 0) {
|
||||||
|
std::unique_ptr<exprstate> top = std::move(stack_[z-1]);
|
||||||
|
|
||||||
|
stack_.resize(z-1);
|
||||||
|
|
||||||
|
return top;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exprstatestack::print(std::ostream & os) const {
|
||||||
|
os << "<exprstatestack"
|
||||||
|
<< xtag("size", stack_.size())
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
for (std::size_t i = 0, z = stack_.size(); i < z; ++i) {
|
||||||
|
os << " [" << z-i-1 << "] "
|
||||||
|
<< stack_[i].get()
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
os << ">" << std::endl;
|
||||||
|
}
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end exprstatestack.cpp */
|
||||||
128
xo-reader/src/reader/lambda_xs.cpp
Normal file
128
xo-reader/src/reader/lambda_xs.cpp
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
/* @file lambda_xs.cpp */
|
||||||
|
|
||||||
|
#include "lambda_xs.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
#include "expect_formal_arglist_xs.hpp"
|
||||||
|
#include "expect_expr_xs.hpp"
|
||||||
|
#include "xo/expression/Lambda.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::ast::Lambda;
|
||||||
|
|
||||||
|
namespace scm {
|
||||||
|
const char *
|
||||||
|
lambdastatetype_descr(lambdastatetype x) {
|
||||||
|
switch(x) {
|
||||||
|
case lambdastatetype::invalid: return "invalid";
|
||||||
|
case lambdastatetype::lm_0: return "lm_0";
|
||||||
|
case lambdastatetype::lm_1: return "lm_1";
|
||||||
|
case lambdastatetype::lm_2: return "lm_2";
|
||||||
|
case lambdastatetype::lm_3: return "lm_3";
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "???lambdastatetype";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- lambda_xs - ----
|
||||||
|
|
||||||
|
std::unique_ptr<lambda_xs>
|
||||||
|
lambda_xs::make() {
|
||||||
|
return std::make_unique<lambda_xs>(lambda_xs());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lambda_xs::start(parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
p_psm->push_exprstate(lambda_xs::make());
|
||||||
|
p_psm->top_exprstate()
|
||||||
|
.on_lambda_token(token_type::lambda(), p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
lambda_xs::lambda_xs() : exprstate(exprstatetype::lambdaexpr) {}
|
||||||
|
|
||||||
|
void
|
||||||
|
lambda_xs::on_lambda_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
if (lmxs_type_ == lambdastatetype::lm_0) {
|
||||||
|
this->lmxs_type_ = lambdastatetype::lm_1;
|
||||||
|
expect_formal_arglist_xs::start(p_psm);
|
||||||
|
} else {
|
||||||
|
exprstate::on_lambda_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lambda_xs::on_formal_arglist(const std::vector<rp<Variable>> & argl,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
if (lmxs_type_ == lambdastatetype::lm_1) {
|
||||||
|
this->lmxs_type_ = lambdastatetype::lm_2;
|
||||||
|
this->argl_ = argl;
|
||||||
|
|
||||||
|
p_psm->push_envframe(envframe(argl));
|
||||||
|
|
||||||
|
expect_expr_xs::start(p_psm);
|
||||||
|
} else {
|
||||||
|
exprstate::on_formal_arglist(argl, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lambda_xs::on_expr(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
if (lmxs_type_ == lambdastatetype::lm_2) {
|
||||||
|
this->lmxs_type_ = lambdastatetype::lm_3;
|
||||||
|
this->body_ = expr.promote();
|
||||||
|
} else {
|
||||||
|
exprstate::on_expr(expr, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lambda_xs::on_expr_with_semicolon(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
this->on_expr(expr, p_psm);
|
||||||
|
this->on_semicolon_token(token_type::semicolon(), p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lambda_xs::on_semicolon_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
if (lmxs_type_ == lambdastatetype::lm_3) {
|
||||||
|
/* done! */
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
std::string name = "fixmename";
|
||||||
|
|
||||||
|
rp<Lambda> lm = Lambda::make(name, argl_, body_);
|
||||||
|
|
||||||
|
p_psm->pop_envframe();
|
||||||
|
|
||||||
|
p_psm->top_exprstate().on_expr(lm, p_psm);
|
||||||
|
p_psm->top_exprstate().on_semicolon_token(tk, p_psm);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
exprstate::on_semicolon_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lambda_xs::print(std::ostream & os) const {
|
||||||
|
os << "<lambda_xs"
|
||||||
|
<< xtag("lmxs_type", lmxs_type_)
|
||||||
|
<< ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
/* end lambda_xs.cpp */
|
||||||
119
xo-reader/src/reader/let1_xs.cpp
Normal file
119
xo-reader/src/reader/let1_xs.cpp
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
/* file let1_xs.cpp
|
||||||
|
*
|
||||||
|
* author: Roland Conybeare
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "let1_xs.hpp"
|
||||||
|
#include "expect_expr_xs.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "xo/expression/Sequence.hpp"
|
||||||
|
#include "xo/expression/DefineExpr.hpp"
|
||||||
|
#include "xo/expression/Apply.hpp"
|
||||||
|
#include "xo/expression/Lambda.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using Sequence = xo::ast::Sequence;
|
||||||
|
using DefineExpr = xo::ast::DefineExpr;
|
||||||
|
using Apply = xo::ast::Apply;
|
||||||
|
using Lambda = xo::ast::Lambda;
|
||||||
|
using LambdaAccess = xo::ast::LambdaAccess;
|
||||||
|
using Variable = xo::ast::Variable;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::string gensym() {
|
||||||
|
return "genanotherxx";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace scm {
|
||||||
|
std::unique_ptr<let1_xs>
|
||||||
|
let1_xs::make(std::string lhs_name,
|
||||||
|
rp<Expression> rhs)
|
||||||
|
{
|
||||||
|
return std::make_unique<let1_xs>(let1_xs(std::move(lhs_name),
|
||||||
|
std::move(rhs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
let1_xs::start(const std::string & lhs_name,
|
||||||
|
const rp<Expression> & rhs,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
p_psm->push_exprstate(let1_xs::make(lhs_name, rhs));
|
||||||
|
|
||||||
|
expect_expr_xs::start(true /*allow_defs*/,
|
||||||
|
true /*cxl_on_rightbrace*/,
|
||||||
|
p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
let1_xs::let1_xs(std::string lhs_name,
|
||||||
|
rp<Expression> rhs)
|
||||||
|
: exprstate(),
|
||||||
|
lhs_name_{std::move(lhs_name)},
|
||||||
|
rhs_{std::move(rhs)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
let1_xs::on_expr(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
ref::brw<DefineExpr> def_expr = DefineExpr::from(expr);
|
||||||
|
|
||||||
|
if (def_expr) {
|
||||||
|
/** nested_start: control returns via
|
||||||
|
* .on_expr(x)
|
||||||
|
* with x something like:
|
||||||
|
* Apply(Lambda(gensym(),
|
||||||
|
* [Variable(def_expr->lhs_name(),
|
||||||
|
* def_expr->valuetype())],
|
||||||
|
* body...))
|
||||||
|
* followed immediately by
|
||||||
|
* .on_rightbrace_token()
|
||||||
|
**/
|
||||||
|
let1_xs::start(def_expr->lhs_name(),
|
||||||
|
def_expr->rhs(),
|
||||||
|
p_psm);
|
||||||
|
} else {
|
||||||
|
this->expr_v_.push_back(expr.promote());
|
||||||
|
|
||||||
|
expect_expr_xs::start(true /*allow_defs*/,
|
||||||
|
true /*cxl_on_rightbrace*/,
|
||||||
|
p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
let1_xs::on_rightbrace_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
auto self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
auto expr = Sequence::make(this->expr_v_);
|
||||||
|
|
||||||
|
std::string argname = gensym();
|
||||||
|
|
||||||
|
rp<Expression> lambda
|
||||||
|
= Lambda::make(this->lhs_name_,
|
||||||
|
{Variable::make(argname,
|
||||||
|
this->rhs_->valuetype())},
|
||||||
|
expr);
|
||||||
|
|
||||||
|
rp<Expression> result
|
||||||
|
= Apply::make(lambda, {this->rhs_});
|
||||||
|
|
||||||
|
p_psm->top_exprstate().on_expr(result, p_psm);
|
||||||
|
|
||||||
|
/* caller of let1_xs expects the same rightbrace '}'
|
||||||
|
* -- remember we pushed let1_xs to handle an embedded def-expr
|
||||||
|
* in a sequence
|
||||||
|
*/
|
||||||
|
p_psm->on_rightbrace_token(tk);
|
||||||
|
}
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
/* end let1_xs.cpp */
|
||||||
252
xo-reader/src/reader/paren_xs.cpp
Normal file
252
xo-reader/src/reader/paren_xs.cpp
Normal file
|
|
@ -0,0 +1,252 @@
|
||||||
|
/* @file paren_xs.cpp */
|
||||||
|
|
||||||
|
#include "paren_xs.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
#include "progress_xs.hpp"
|
||||||
|
#include "expect_expr_xs.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace scm {
|
||||||
|
const char *
|
||||||
|
parenexprstatetype_descr(parenexprstatetype x)
|
||||||
|
{
|
||||||
|
switch(x) {
|
||||||
|
case parenexprstatetype::invalid: return "invalid";
|
||||||
|
case parenexprstatetype::lparen_0: return "lparen_0";
|
||||||
|
case parenexprstatetype::lparen_1: return "lparen_1";
|
||||||
|
case parenexprstatetype::n_parenexprstatetype: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "???parenexprstatetype";
|
||||||
|
}
|
||||||
|
|
||||||
|
paren_xs::paren_xs()
|
||||||
|
: exprstate(exprstatetype::parenexpr),
|
||||||
|
parenxs_type_{parenexprstatetype::lparen_0}
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::unique_ptr<paren_xs>
|
||||||
|
paren_xs::make() {
|
||||||
|
return std::make_unique<paren_xs>(paren_xs());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::start(parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
p_psm->push_exprstate(paren_xs::make());
|
||||||
|
expect_expr_xs::start(p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
paren_xs::admits_rightparen() const {
|
||||||
|
switch (parenxs_type_) {
|
||||||
|
case parenexprstatetype::lparen_0:
|
||||||
|
/* unreachable */
|
||||||
|
assert(false);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case parenexprstatetype::lparen_1:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case parenexprstatetype::invalid:
|
||||||
|
case parenexprstatetype::n_parenexprstatetype:
|
||||||
|
/* unreachable */
|
||||||
|
assert(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
paren_xs::admits_f64() const {
|
||||||
|
switch (parenxs_type_) {
|
||||||
|
case parenexprstatetype::lparen_0:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case parenexprstatetype::lparen_1:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case parenexprstatetype::invalid:
|
||||||
|
case parenexprstatetype::n_parenexprstatetype:
|
||||||
|
/* unreachable */
|
||||||
|
assert(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::on_def_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr const char * c_self_name = "paren_xs::on_def";
|
||||||
|
|
||||||
|
this->illegal_input_error(c_self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::on_symbol_token(const token_type & /*tk*/,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("exstype", p_psm->top_exprstate().exs_type()));
|
||||||
|
|
||||||
|
//constexpr const char * self_name = "paren_xs::on_symbol";
|
||||||
|
|
||||||
|
/* TODO: lparen_0: treat as variable reference */
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::on_typedescr(TypeDescr /*td*/,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::on_colon_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr const char * c_self_name = "paren_xs::on_colon";
|
||||||
|
|
||||||
|
this->illegal_input_error(c_self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::on_semicolon_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr const char * c_self_name = "paren_xs::on_semicolon";
|
||||||
|
|
||||||
|
this->illegal_input_error(c_self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::on_singleassign_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr const char * c_self_name = "paren_xs::on_singleassign";
|
||||||
|
|
||||||
|
this->illegal_input_error(c_self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::on_leftparen_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr const char * c_self_name = "paren_xs::on_leftparen";
|
||||||
|
|
||||||
|
this->illegal_input_error(c_self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::on_rightparen_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "paren_xs::on_rightparen";
|
||||||
|
|
||||||
|
if (!this->admits_rightparen())
|
||||||
|
{
|
||||||
|
this->illegal_input_error(c_self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->parenxs_type_ == parenexprstatetype::lparen_1) {
|
||||||
|
rp<Expression> expr = this->gen_expr_;
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
p_psm->top_exprstate().on_expr(expr, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::on_f64_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "paren_xs::on_f64";
|
||||||
|
|
||||||
|
this->illegal_input_error(c_self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::on_expr(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("exstype", this->exs_type_),
|
||||||
|
xtag("expr", expr));
|
||||||
|
|
||||||
|
switch (this->parenxs_type_) {
|
||||||
|
case parenexprstatetype::lparen_0: {
|
||||||
|
this->parenxs_type_ = parenexprstatetype::lparen_1; /* wants on_rightparen */
|
||||||
|
progress_xs::start(expr.promote(), p_psm);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case parenexprstatetype::lparen_1: {
|
||||||
|
this->gen_expr_ = expr.promote();
|
||||||
|
|
||||||
|
/* expect immediate incoming call, this time to on_rightparen() */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* unreachable */
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} /*on_expr*/
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::on_symbol(const std::string & /*symbol_name*/,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
switch(this->parenxs_type_) {
|
||||||
|
case parenexprstatetype::lparen_0:
|
||||||
|
case parenexprstatetype::lparen_1:
|
||||||
|
/* NOT IMPLEMENTED */
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* unreachable */
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
paren_xs::print(std::ostream & os) const {
|
||||||
|
os << "<paren_xs"
|
||||||
|
<< xtag("this", (void*)this)
|
||||||
|
//<< xtag("type", exs_type_);
|
||||||
|
<< xtag("parenxs_type", parenxs_type_);
|
||||||
|
|
||||||
|
if (gen_expr_)
|
||||||
|
os << xtag("gen_expr", gen_expr_);
|
||||||
|
|
||||||
|
os << ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
/* end paren_xs.cpp */
|
||||||
81
xo-reader/src/reader/parser.cpp
Normal file
81
xo-reader/src/reader/parser.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
/* file parser.cpp
|
||||||
|
*
|
||||||
|
* author: Roland Conybeare
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "parser.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "define_xs.hpp"
|
||||||
|
#include "exprseq_xs.hpp"
|
||||||
|
#include "xo/expression/DefineExpr.hpp"
|
||||||
|
#include "xo/expression/Constant.hpp"
|
||||||
|
#include "xo/expression/ConvertExpr.hpp"
|
||||||
|
//#include <regex>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::ast::Expression;
|
||||||
|
//using xo::ast::DefineExpr;
|
||||||
|
//using xo::ast::ConvertExpr;
|
||||||
|
//using xo::ast::Constant;
|
||||||
|
//using xo::reflect::Reflect;
|
||||||
|
using xo::reflect::TypeDescr;
|
||||||
|
|
||||||
|
namespace scm {
|
||||||
|
// ----- parser -----
|
||||||
|
|
||||||
|
bool
|
||||||
|
parser::has_incomplete_expr() const {
|
||||||
|
return !xs_stack_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parser::begin_translation_unit() {
|
||||||
|
/* note: not using emit expr here */
|
||||||
|
parserstatemachine psm(&xs_stack_,
|
||||||
|
&env_stack_,
|
||||||
|
nullptr /*p_emit_expr*/);
|
||||||
|
|
||||||
|
exprseq_xs::start(&psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
rp<Expression>
|
||||||
|
parser::include_token(const token_type & tk)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag), xtag("tk", tk));
|
||||||
|
|
||||||
|
if (xs_stack_.empty()) {
|
||||||
|
throw std::runtime_error(tostr("parser::include_token",
|
||||||
|
": parser not expecting input"
|
||||||
|
"(call parser.begin_translation_unit()..?)",
|
||||||
|
xtag("token", tk)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stack_ is non-empty */
|
||||||
|
|
||||||
|
rp<Expression> retval;
|
||||||
|
|
||||||
|
parserstatemachine psm(&xs_stack_, &env_stack_, &retval);
|
||||||
|
|
||||||
|
xs_stack_.top_exprstate().on_input(tk, &psm);
|
||||||
|
|
||||||
|
log && log(xtag("retval", retval));
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
} /*include_token*/
|
||||||
|
|
||||||
|
void
|
||||||
|
parser::print(std::ostream & os) const {
|
||||||
|
os << "<parser"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
xs_stack_.print(os);
|
||||||
|
|
||||||
|
os << ">" << std::endl;
|
||||||
|
}
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
/* end parser.cpp */
|
||||||
154
xo-reader/src/reader/parserstatemachine.cpp
Normal file
154
xo-reader/src/reader/parserstatemachine.cpp
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
/* file parserstatemachine.cpp
|
||||||
|
*
|
||||||
|
* author: Roland Conybeare
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::ast::Variable;
|
||||||
|
|
||||||
|
namespace scm {
|
||||||
|
rp<Variable>
|
||||||
|
parserstatemachine::lookup_var(const std::string & x) const {
|
||||||
|
return p_env_stack_->lookup(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate>
|
||||||
|
parserstatemachine::pop_exprstate() {
|
||||||
|
return p_stack_->pop_exprstate();
|
||||||
|
}
|
||||||
|
|
||||||
|
exprstate &
|
||||||
|
parserstatemachine::top_exprstate() {
|
||||||
|
return p_stack_->top_exprstate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parserstatemachine::push_exprstate(std::unique_ptr<exprstate> x) {
|
||||||
|
p_stack_->push_exprstate(std::move(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parserstatemachine::push_envframe(envframe x) {
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("frame", x));
|
||||||
|
|
||||||
|
p_env_stack_->push_envframe(std::move(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parserstatemachine::pop_envframe() {
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
p_env_stack_->pop_envframe();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parserstatemachine::on_expr(ref::brw<Expression> x)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("x", x),
|
||||||
|
xtag("psm", *this));
|
||||||
|
|
||||||
|
this->p_stack_
|
||||||
|
->top_exprstate().on_expr(x, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parserstatemachine::on_expr_with_semicolon(ref::brw<Expression> x)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("x", x),
|
||||||
|
xtag("psm", *this));
|
||||||
|
|
||||||
|
this->p_stack_
|
||||||
|
->top_exprstate().on_expr_with_semicolon(x, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parserstatemachine::on_symbol(const std::string & x)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("x", x),
|
||||||
|
xtag("psm", *this));
|
||||||
|
|
||||||
|
this->p_stack_
|
||||||
|
->top_exprstate().on_symbol(x, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parserstatemachine::on_semicolon_token(const token_type & tk)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("tk", tk),
|
||||||
|
xtag("psm", *this));
|
||||||
|
|
||||||
|
this->p_stack_
|
||||||
|
->top_exprstate().on_semicolon_token(tk, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parserstatemachine::on_operator_token(const token_type & tk)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("tk", tk),
|
||||||
|
xtag("psm", *this));
|
||||||
|
|
||||||
|
this->p_stack_
|
||||||
|
->top_exprstate().on_operator_token(tk, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parserstatemachine::on_leftbrace_token(const token_type & tk)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("tk", tk),
|
||||||
|
xtag("psm", *this));
|
||||||
|
|
||||||
|
this->p_stack_
|
||||||
|
->top_exprstate().on_leftbrace_token(tk, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parserstatemachine::on_rightbrace_token(const token_type & tk)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("tk", tk),
|
||||||
|
xtag("psm", *this));
|
||||||
|
|
||||||
|
this->p_stack_
|
||||||
|
->top_exprstate().on_rightbrace_token(tk, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parserstatemachine::print(std::ostream & os) const {
|
||||||
|
os << "<psm";
|
||||||
|
os << xtag("stack", p_stack_);
|
||||||
|
os << xtag("env_stack", p_env_stack_);
|
||||||
|
os << xtag("emit_expr", p_emit_expr_);
|
||||||
|
os << ">";
|
||||||
|
}
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
/* end parserstatemachine.cpp */
|
||||||
439
xo-reader/src/reader/progress_xs.cpp
Normal file
439
xo-reader/src/reader/progress_xs.cpp
Normal file
|
|
@ -0,0 +1,439 @@
|
||||||
|
/* @file progress_xs.cpp */
|
||||||
|
|
||||||
|
#include "progress_xs.hpp"
|
||||||
|
#include "exprstatestack.hpp"
|
||||||
|
#include "expect_expr_xs.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "xo/expression/AssignExpr.hpp"
|
||||||
|
#include "xo/expression/Apply.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::ast::Expression;
|
||||||
|
using xo::ast::AssignExpr;
|
||||||
|
using xo::ast::Variable;
|
||||||
|
using xo::ast::Apply;
|
||||||
|
|
||||||
|
namespace scm {
|
||||||
|
const char *
|
||||||
|
optype_descr(optype x) {
|
||||||
|
switch (x) {
|
||||||
|
case optype::invalid:
|
||||||
|
return "?optype";
|
||||||
|
case optype::op_assign:
|
||||||
|
return "op:=";
|
||||||
|
case optype::op_add:
|
||||||
|
return "op+";
|
||||||
|
case optype::op_subtract:
|
||||||
|
return "op-";
|
||||||
|
case optype::op_multiply:
|
||||||
|
return "op*";
|
||||||
|
case optype::op_divide:
|
||||||
|
return "op/";
|
||||||
|
case optype::n_optype:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "???";
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
precedence(optype x) {
|
||||||
|
switch (x) {
|
||||||
|
case optype::invalid:
|
||||||
|
case optype::n_optype:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case optype::op_assign:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case optype::op_add:
|
||||||
|
case optype::op_subtract:
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
case optype::op_multiply:
|
||||||
|
case optype::op_divide:
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<progress_xs>
|
||||||
|
progress_xs::make(rp<Expression> valex, optype op) {
|
||||||
|
return std::make_unique<progress_xs>(progress_xs(std::move(valex), op));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::start(rp<Expression> valex, optype op, parserstatemachine * p_psm) {
|
||||||
|
p_psm->push_exprstate(progress_xs::make(valex, op));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::start(rp<Expression> valex, parserstatemachine * p_psm) {
|
||||||
|
p_psm->push_exprstate(progress_xs::make(valex));
|
||||||
|
}
|
||||||
|
|
||||||
|
progress_xs::progress_xs(rp<Expression> valex, optype op)
|
||||||
|
: exprstate(exprstatetype::expr_progress),
|
||||||
|
lhs_{std::move(valex)},
|
||||||
|
op_type_{op}
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool
|
||||||
|
progress_xs::admits_f64() const { return false; }
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::on_def_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_stack*/)
|
||||||
|
{
|
||||||
|
constexpr const char * self_name = "progress_xs::on_def";
|
||||||
|
|
||||||
|
/* nothing here - admits_definition unconditionally false */
|
||||||
|
this->illegal_input_error(self_name, tk) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
rp<Expression>
|
||||||
|
progress_xs::assemble_expr() {
|
||||||
|
/* need to defer building Apply incase expr followed by higher-precedence operator:
|
||||||
|
* consider input like
|
||||||
|
* 3.14 + 2.0 * ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "progress_xs::assemble_expr";
|
||||||
|
|
||||||
|
if ((op_type_ != optype::invalid) && (rhs_.get() == nullptr)) {
|
||||||
|
throw std::runtime_error(tostr(c_self_name,
|
||||||
|
": expected expr on rhs of operator",
|
||||||
|
xtag("lhs", lhs_),
|
||||||
|
xtag("op", op_type_)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* consecutive expressions not legal, e.g:
|
||||||
|
* 3.14 6.28
|
||||||
|
* but expressions surrounding an infix operators is:
|
||||||
|
* 3.14 / 6.28
|
||||||
|
*/
|
||||||
|
switch (op_type_) {
|
||||||
|
case optype::invalid:
|
||||||
|
return this->lhs_;
|
||||||
|
|
||||||
|
case optype::op_assign:
|
||||||
|
{
|
||||||
|
ref::brw<Variable> lhs = Variable::from(this->lhs_);
|
||||||
|
|
||||||
|
if (!lhs) {
|
||||||
|
throw std::runtime_error
|
||||||
|
(tostr("progress_xs::assemble_expr",
|
||||||
|
" expect variable on lhs of assignment operator :=",
|
||||||
|
xtag("lhs", lhs_),
|
||||||
|
xtag("rhs", rhs_)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return AssignExpr::make(lhs.promote(),
|
||||||
|
this->rhs_);
|
||||||
|
}
|
||||||
|
|
||||||
|
case optype::op_add:
|
||||||
|
return Apply::make_add2_f64(this->lhs_,
|
||||||
|
this->rhs_);
|
||||||
|
|
||||||
|
case optype::op_subtract:
|
||||||
|
return Apply::make_sub2_f64(this->lhs_,
|
||||||
|
this->rhs_);
|
||||||
|
|
||||||
|
case optype::op_multiply:
|
||||||
|
return Apply::make_mul2_f64(this->lhs_,
|
||||||
|
this->rhs_);
|
||||||
|
|
||||||
|
case optype::op_divide:
|
||||||
|
return Apply::make_div2_f64(this->lhs_,
|
||||||
|
this->rhs_);
|
||||||
|
|
||||||
|
case optype::n_optype:
|
||||||
|
/* unreachable */
|
||||||
|
assert(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::on_expr(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
/* note: previous token probably an operator,
|
||||||
|
* handled from progress_xs::on_operator_token(),
|
||||||
|
* which pushes expect_expr_xs::expect_rhs_expression()
|
||||||
|
*/
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "progress_xs::on_expr";
|
||||||
|
|
||||||
|
|
||||||
|
if (op_type_ == optype::invalid) {
|
||||||
|
throw std::runtime_error(tostr(c_self_name,
|
||||||
|
": consecutive unseparated exprs not legal"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef NOT_QUITE
|
||||||
|
assert(result.get());
|
||||||
|
|
||||||
|
/* this expression complete.. */
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
/* ..but more operators could follow, so don't commit yet */
|
||||||
|
p_stack->push_exprstate(progress_xs::make(result));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
this->rhs_ = expr.promote();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::on_symbol_token(const token_type & /*tk*/,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
/* illegal input, e.g.
|
||||||
|
* foo bar
|
||||||
|
*/
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::on_typedescr(TypeDescr /*td*/,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
/* unreachable */
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::on_colon_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr const char * self_name = "progress_xs::on_colon";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::on_semicolon_token(const token_type & /*tk*/,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
/* note: implementation parllels .on_rightparen_token() */
|
||||||
|
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
rp<Expression> expr = this->assemble_expr();
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
p_psm->on_expr_with_semicolon(expr);
|
||||||
|
|
||||||
|
/* control here on input like:
|
||||||
|
* (1.234;
|
||||||
|
*
|
||||||
|
* a. '(' sets up stack [lparen_0:expect_rhs_expression]
|
||||||
|
* (see exprstate::on_leftparen())
|
||||||
|
* b. 1.234 pushes (in case operators) [lparen_0:expect_rhs_expression:expr_progress]
|
||||||
|
* (see exprstate::on_f64())
|
||||||
|
* c. semicolon completes expr_progress [lparen_0:expect_rhs_expression]
|
||||||
|
* deliver expresssion to expect_rhs_expression.on_expr_with_semicolon()
|
||||||
|
* (see exprstate::on_expr_with_semicolon())
|
||||||
|
* d. expr_rhs_expression forwards expression to [lparen_0]
|
||||||
|
* e. lparen_0 would advance to [lparen_1], but rejects semicolon
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::on_singleassign_token(const token_type & tk,
|
||||||
|
parserstatemachine * /*p_psm*/)
|
||||||
|
{
|
||||||
|
constexpr const char * self_name = "progress_xs::on_singleassign";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
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));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "exprstate::on_leftparen";
|
||||||
|
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::on_rightparen_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
/* note: implementation parallels .on_semicolon_token() */
|
||||||
|
|
||||||
|
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "progress_xs::on_rightparen";
|
||||||
|
|
||||||
|
auto p_stack = p_psm->p_stack_;
|
||||||
|
|
||||||
|
/* stack may be something like:
|
||||||
|
*
|
||||||
|
* lparen_0
|
||||||
|
* expect_rhs_expression
|
||||||
|
* expr_progress
|
||||||
|
* <-- rightparen
|
||||||
|
*
|
||||||
|
* 1. rightparen completes expression-in-progress
|
||||||
|
* 2. rightparen must then match innermost waiting lparen_0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* right paren confirms stack expression */
|
||||||
|
rp<Expression> expr = this->assemble_expr();
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
if (p_stack->empty()) {
|
||||||
|
throw std::runtime_error(tostr(self_name,
|
||||||
|
": expected non-empty parsing stack"));
|
||||||
|
}
|
||||||
|
|
||||||
|
log && log(xtag("stack", p_stack));
|
||||||
|
|
||||||
|
p_psm->top_exprstate().on_expr(expr, p_psm);
|
||||||
|
|
||||||
|
/* now deliver rightparen */
|
||||||
|
p_psm->top_exprstate().on_rightparen_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
optype
|
||||||
|
tk2op(const tokentype & tktype) {
|
||||||
|
switch (tktype) {
|
||||||
|
case tokentype::tk_plus:
|
||||||
|
return optype::op_add;
|
||||||
|
case tokentype::tk_minus:
|
||||||
|
return optype::op_subtract;
|
||||||
|
case tokentype::tk_star:
|
||||||
|
return optype::op_multiply;
|
||||||
|
case tokentype::tk_slash:
|
||||||
|
return optype::op_divide;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
return optype::invalid;
|
||||||
|
}
|
||||||
|
return optype::invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::on_operator_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "progress_xs::on_operator_token";
|
||||||
|
|
||||||
|
if (op_type_ == optype::invalid) {
|
||||||
|
this->op_type_ = tk2op(tk.tk_type());
|
||||||
|
|
||||||
|
/* infix operator must be followed by non-empty expression */
|
||||||
|
expect_expr_xs::start(p_psm);
|
||||||
|
} else if (rhs_) {
|
||||||
|
/* already have complete expression stashed.
|
||||||
|
* behavior depends on operator precedence for tk with stored operator
|
||||||
|
* this->op_type_
|
||||||
|
*/
|
||||||
|
optype op2 = tk2op(tk.tk_type());
|
||||||
|
|
||||||
|
if (precedence(op2) <= precedence(this->op_type_)) {
|
||||||
|
/* e.g.
|
||||||
|
* 6.2 * 4.9 + ...
|
||||||
|
*
|
||||||
|
* in stack:
|
||||||
|
* 1. progress_xs lhs=6.2, op=*, rhs=4.9
|
||||||
|
*
|
||||||
|
* out stack
|
||||||
|
* 1. progress_xs lhs=apply(*,6.2,4.9), op=+
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 1. instantiate expression for *this */
|
||||||
|
auto expr = this->assemble_expr();
|
||||||
|
|
||||||
|
/* 2. remove from stack */
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
/* 3. replace with new progress_xs: */
|
||||||
|
progress_xs::start(expr, op2, p_psm);
|
||||||
|
|
||||||
|
/* infix operator must be followed by non-empty expression */
|
||||||
|
expect_expr_xs::start(p_psm);
|
||||||
|
} else {
|
||||||
|
/* e.g.
|
||||||
|
* 6.2 + 4.9 * ...
|
||||||
|
*
|
||||||
|
* in stack:
|
||||||
|
* 1. progress_xs lhs=6.2, op=+, rhs=4.9
|
||||||
|
*
|
||||||
|
* out stack:
|
||||||
|
* 1. progress_xs lhs=6.2, op=+
|
||||||
|
* 2. expect_rhs_expression
|
||||||
|
* 3. progress_xs lhs=4.9, op=*
|
||||||
|
* 4. expect_rhs_expression
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
/* 1. replace with nested incomplete infix exprs */
|
||||||
|
progress_xs::start(lhs_, op_type_, p_psm);
|
||||||
|
expect_expr_xs::start(p_psm);
|
||||||
|
progress_xs::start(rhs_, op2, p_psm);
|
||||||
|
expect_expr_xs::start(p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error(tostr(c_self_name,
|
||||||
|
": expected expression following operator",
|
||||||
|
xtag("tk", tk)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::on_f64_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
constexpr const char * self_name = "progress_xs::on_f64";
|
||||||
|
|
||||||
|
if (this->op_type_ == optype::invalid) {
|
||||||
|
this->illegal_input_error(self_name, tk);
|
||||||
|
} else {
|
||||||
|
exprstate::on_f64_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
progress_xs::print(std::ostream & os) const {
|
||||||
|
os << "<progress_xs"
|
||||||
|
<< xtag("this", (void*)this)
|
||||||
|
<< xtag("type", exs_type_);
|
||||||
|
if (lhs_)
|
||||||
|
os << xtag("lhs", lhs_);
|
||||||
|
if (op_type_ != optype::invalid)
|
||||||
|
os << xtag("op", op_type_);
|
||||||
|
if (rhs_)
|
||||||
|
os << xtag("rhs", rhs_);
|
||||||
|
os << ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
/* end progress_xs.cpp */
|
||||||
98
xo-reader/src/reader/reader.cpp
Normal file
98
xo-reader/src/reader/reader.cpp
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
/* @file reader.cpp */
|
||||||
|
|
||||||
|
#include "reader.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace scm {
|
||||||
|
void
|
||||||
|
reader::begin_translation_unit() {
|
||||||
|
parser_.begin_translation_unit();
|
||||||
|
}
|
||||||
|
|
||||||
|
reader_result
|
||||||
|
reader::end_translation_unit() {
|
||||||
|
return this->read_expr(span_type(nullptr, nullptr), true /*eof*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader_result
|
||||||
|
reader::read_expr(const span_type & input_arg, bool eof)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
span_type input = input_arg;
|
||||||
|
|
||||||
|
/* input text-span consumed by this call.
|
||||||
|
* Always comprises some number (possibly 0)
|
||||||
|
* of complete tokens, along with any leading
|
||||||
|
* whitespace
|
||||||
|
*/
|
||||||
|
span_type expr_span = input.prefix(0ul);
|
||||||
|
|
||||||
|
while (!input.empty()) {
|
||||||
|
/* read one token from input */
|
||||||
|
auto sr = this->tokenizer_.scan2(input, eof);
|
||||||
|
const auto & tk = sr.first;
|
||||||
|
const span_type & used_span = sr.second;
|
||||||
|
|
||||||
|
log && log(xtag("used_span", used_span));
|
||||||
|
log && log(xtag("input.pre", input));
|
||||||
|
|
||||||
|
input = input.after_prefix(used_span);
|
||||||
|
|
||||||
|
log && log(xtag("expr_span.pre", expr_span));
|
||||||
|
|
||||||
|
expr_span += used_span;
|
||||||
|
|
||||||
|
if (tk.is_valid()) {
|
||||||
|
/* forward just-read token to parser */
|
||||||
|
auto expr = this->parser_.include_token(tk);
|
||||||
|
|
||||||
|
if (expr) {
|
||||||
|
log && log(xtag("outcome", "victory!"),
|
||||||
|
xtag("expr", expr));
|
||||||
|
|
||||||
|
/* token completes an expression -> victory */
|
||||||
|
return reader_result(expr, expr_span);
|
||||||
|
} else {
|
||||||
|
/* token did not complete an expression
|
||||||
|
* (e.g. token for '[')
|
||||||
|
*
|
||||||
|
* input span may contain more tokens -> iterate
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(input.empty());
|
||||||
|
|
||||||
|
/* no more tokens in input */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* control here: either
|
||||||
|
* 1. input.empty (perhaps ate some whitespace, ok)
|
||||||
|
* 2. missing or incomplete token (ok unless eof)
|
||||||
|
*/
|
||||||
|
if (eof) {
|
||||||
|
if (parser_.has_incomplete_expr()) {
|
||||||
|
throw std::runtime_error
|
||||||
|
("reader::read_expr"
|
||||||
|
": eof reached with incomplete expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokenizer_.has_prefix()) {
|
||||||
|
throw std::runtime_error
|
||||||
|
("reader::read_expr"
|
||||||
|
": unintelligible input recognized at eof");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log && log(xtag("outcome", "noop"));
|
||||||
|
|
||||||
|
return reader_result(nullptr, expr_span);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end reader.cpp */
|
||||||
113
xo-reader/src/reader/sequence_xs.cpp
Normal file
113
xo-reader/src/reader/sequence_xs.cpp
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
/* @file sequence_xs.cpp */
|
||||||
|
|
||||||
|
#include "sequence_xs.hpp"
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "expect_expr_xs.hpp"
|
||||||
|
#include "let1_xs.hpp"
|
||||||
|
#include "xo/expression/DefineExpr.hpp"
|
||||||
|
#include "xo/expression/Sequence.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::ast::DefineExpr;
|
||||||
|
|
||||||
|
namespace scm {
|
||||||
|
std::unique_ptr<sequence_xs>
|
||||||
|
sequence_xs::make() {
|
||||||
|
return std::make_unique<sequence_xs>(sequence_xs());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sequence_xs::start(parserstatemachine * p_psm) {
|
||||||
|
p_psm->push_exprstate(sequence_xs::make());
|
||||||
|
/* want to accept anything that starts an expression,
|
||||||
|
* except that } ends it
|
||||||
|
*/
|
||||||
|
expect_expr_xs::start(true /*allow_defs*/,
|
||||||
|
true /*cxl_on_rightbrace*/,
|
||||||
|
p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
sequence_xs::sequence_xs()
|
||||||
|
: exprstate(exprstatetype::sequenceexpr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
sequence_xs::on_expr(ref::brw<Expression> expr,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log(xtag("expr", expr.promote()));
|
||||||
|
|
||||||
|
/* TODO: if expr is a DefineExpr,
|
||||||
|
* then need to rewrite...
|
||||||
|
*
|
||||||
|
* ...prefix
|
||||||
|
* DefineExpr(lhs_name, rhs)
|
||||||
|
* rest...
|
||||||
|
*
|
||||||
|
* becomes:
|
||||||
|
*
|
||||||
|
* /-- .outer_seq_expr_
|
||||||
|
* v
|
||||||
|
* Sequence(
|
||||||
|
* ...prefix,
|
||||||
|
*
|
||||||
|
* /-- .inner_lm_expr_
|
||||||
|
* v
|
||||||
|
* Apply(Lambda(gen999,
|
||||||
|
* [Variable(lhs_name, type(rhs))],
|
||||||
|
* /-- .expr_v_
|
||||||
|
* v
|
||||||
|
* sequencify(rest...)),
|
||||||
|
* rhs))
|
||||||
|
*
|
||||||
|
* so amongst other things,
|
||||||
|
* helpful to have nested seequence_xs that propagates '}'
|
||||||
|
* instead of swallowing it.
|
||||||
|
*/
|
||||||
|
ref::brw<DefineExpr> def_expr = DefineExpr::from(expr);
|
||||||
|
|
||||||
|
if (def_expr) {
|
||||||
|
/** nested_start: control returns via
|
||||||
|
* .on_expr(x)
|
||||||
|
* with x something like:
|
||||||
|
* Apply(Lambda(gensym(),
|
||||||
|
* [Variable(def_expr->lhs_name(),
|
||||||
|
* def_expr->valuetype())],
|
||||||
|
* body...))
|
||||||
|
* followed immediately by
|
||||||
|
* .on_rightbrace_token()
|
||||||
|
**/
|
||||||
|
let1_xs::start(def_expr->lhs_name(),
|
||||||
|
def_expr->rhs(),
|
||||||
|
p_psm);
|
||||||
|
} else {
|
||||||
|
this->expr_v_.push_back(expr.promote());
|
||||||
|
|
||||||
|
expect_expr_xs::start(true /*allow_defs*/,
|
||||||
|
true /*cxl_on_rightbrace*/,
|
||||||
|
p_psm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sequence_xs::on_rightbrace_token(const token_type & /*tk*/,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
auto self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
/* make sequence from expressions seen at this level,
|
||||||
|
* and report it to parent
|
||||||
|
*/
|
||||||
|
auto expr = Sequence::make(this->expr_v_);
|
||||||
|
|
||||||
|
p_psm->top_exprstate().on_expr(expr, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
/* end sequence_xs.cpp */
|
||||||
17
xo-reader/utest/CMakeLists.txt
Normal file
17
xo-reader/utest/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# xo-reader/utest/CMakeLists.txt
|
||||||
|
|
||||||
|
set(UTEST_EXE utest.reader)
|
||||||
|
set(UTEST_SRCS
|
||||||
|
reader_utest_main.cpp
|
||||||
|
parser.test.cpp
|
||||||
|
reader.test.cpp)
|
||||||
|
|
||||||
|
if (ENABLE_TESTING)
|
||||||
|
xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS})
|
||||||
|
xo_self_dependency(${UTEST_EXE} xo_reader)
|
||||||
|
#xo_dependency(${UTEST_EXE} xo_ratio)
|
||||||
|
#xo_dependency(${UTEST_EXE} xo_reflectutil)
|
||||||
|
xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# end CMakeLists.txt
|
||||||
279
xo-reader/utest/parser.test.cpp
Normal file
279
xo-reader/utest/parser.test.cpp
Normal file
|
|
@ -0,0 +1,279 @@
|
||||||
|
/* file parser.test.cpp
|
||||||
|
*
|
||||||
|
* author: Roland Conybeare
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xo/reader/parser.hpp"
|
||||||
|
#include "xo/reader/define_xs.hpp"
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using parser_type = xo::scm::parser;
|
||||||
|
using token_type = parser_type::token_type;
|
||||||
|
using xo::scm::exprstatetype;
|
||||||
|
using xo::scm::define_xs;
|
||||||
|
using xo::scm::defexprstatetype;
|
||||||
|
using std::cerr;
|
||||||
|
using std::endl;
|
||||||
|
|
||||||
|
//using xo::ast::Expression;
|
||||||
|
|
||||||
|
namespace ut {
|
||||||
|
TEST_CASE("parser", "[parser]") {
|
||||||
|
for (std::size_t i_tc = 0; i_tc < 2; ++i_tc) {
|
||||||
|
parser_type parser;
|
||||||
|
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag), xtag("i_tc", i_tc));
|
||||||
|
|
||||||
|
parser.begin_translation_unit();
|
||||||
|
|
||||||
|
REQUIRE(parser.stack_size() == 1);
|
||||||
|
REQUIRE(parser.i_exstype(0)
|
||||||
|
== exprstatetype::expect_toplevel_expression_sequence);
|
||||||
|
|
||||||
|
/* input:
|
||||||
|
* def
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
auto r1 = parser.include_token(token_type::def());
|
||||||
|
REQUIRE(r1.get() == nullptr);
|
||||||
|
|
||||||
|
/* stack should be:
|
||||||
|
*
|
||||||
|
* expect_toplevel_expression_sequence
|
||||||
|
* def_1
|
||||||
|
* expect_symbol
|
||||||
|
*/
|
||||||
|
CHECK(parser.stack_size() == 3);
|
||||||
|
if (parser.stack_size() > 0)
|
||||||
|
CHECK(parser.i_exstype(0) == exprstatetype::expect_symbol);
|
||||||
|
if (parser.stack_size() > 1) {
|
||||||
|
CHECK(parser.i_exstype(1) == exprstatetype::defexpr);
|
||||||
|
REQUIRE(define_xs::from(parser.i_exstate(1)) != nullptr);
|
||||||
|
CHECK(define_xs::from(parser.i_exstate(1))->defxs_type() == defexprstatetype::def_1);
|
||||||
|
}
|
||||||
|
if (parser.stack_size() > 2)
|
||||||
|
CHECK(parser.i_exstype(2)
|
||||||
|
== exprstatetype::expect_toplevel_expression_sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* input:
|
||||||
|
* def foo
|
||||||
|
* ^ ^
|
||||||
|
* 0 1
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
auto r2 = parser.include_token(token_type::symbol_token("foo"));
|
||||||
|
|
||||||
|
cerr << "parser state after [def foo]" << endl;
|
||||||
|
cerr << parser << endl;
|
||||||
|
|
||||||
|
REQUIRE(r2.get() == nullptr);
|
||||||
|
|
||||||
|
/* stack should be:
|
||||||
|
*
|
||||||
|
* expect_toplevel_expression_sequence
|
||||||
|
* def_1
|
||||||
|
*/
|
||||||
|
CHECK(parser.stack_size() == 2);
|
||||||
|
if (parser.stack_size() > 0) {
|
||||||
|
CHECK(parser.i_exstype(0) == exprstatetype::defexpr);
|
||||||
|
REQUIRE(define_xs::from(parser.i_exstate(0)) != nullptr);
|
||||||
|
CHECK(define_xs::from(parser.i_exstate(0))->defxs_type() == defexprstatetype::def_2);
|
||||||
|
}
|
||||||
|
if (parser.stack_size() > 1)
|
||||||
|
CHECK(parser.i_exstype(1)
|
||||||
|
== exprstatetype::expect_toplevel_expression_sequence);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_tc == 0) {
|
||||||
|
;
|
||||||
|
} else if (i_tc == 1) {
|
||||||
|
/* input:
|
||||||
|
* def foo :
|
||||||
|
* ^ ^
|
||||||
|
* 0 1
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
auto r3 = parser.include_token(token_type::colon());
|
||||||
|
|
||||||
|
cerr << "parser state after [def foo :]" << endl;
|
||||||
|
cerr << parser << endl;
|
||||||
|
|
||||||
|
REQUIRE(r3.get() == nullptr);
|
||||||
|
|
||||||
|
/* stack should be:
|
||||||
|
*
|
||||||
|
* expect_toplevel_expression_sequence
|
||||||
|
* def_3
|
||||||
|
* expect_symbol
|
||||||
|
*/
|
||||||
|
CHECK(parser.stack_size() == 3);
|
||||||
|
if (parser.stack_size() > 0)
|
||||||
|
CHECK(parser.i_exstype(0) == exprstatetype::expect_type);
|
||||||
|
if (parser.stack_size() > 1) {
|
||||||
|
CHECK(parser.i_exstype(1) == exprstatetype::defexpr);
|
||||||
|
REQUIRE(define_xs::from(parser.i_exstate(1)) != nullptr);
|
||||||
|
CHECK(define_xs::from(parser.i_exstate(1))->defxs_type() == defexprstatetype::def_3);
|
||||||
|
}
|
||||||
|
if (parser.stack_size() > 2)
|
||||||
|
CHECK(parser.i_exstype(2)
|
||||||
|
== exprstatetype::expect_toplevel_expression_sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* input:
|
||||||
|
* def foo : f64
|
||||||
|
* ^ ^
|
||||||
|
* 0 1
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
auto r4 = parser.include_token(token_type::symbol_token("f64"));
|
||||||
|
|
||||||
|
cerr << "parser state after [def foo : f64]" << endl;
|
||||||
|
cerr << parser << endl;
|
||||||
|
|
||||||
|
REQUIRE(r4.get() == nullptr);
|
||||||
|
|
||||||
|
CHECK(parser.stack_size() == 2);
|
||||||
|
|
||||||
|
/* stack should be:
|
||||||
|
*
|
||||||
|
* expect_toplevel_expression_sequence
|
||||||
|
* def_4
|
||||||
|
*/
|
||||||
|
CHECK(parser.stack_size() == 2);
|
||||||
|
if (parser.stack_size() > 0) {
|
||||||
|
CHECK(parser.i_exstype(0) == exprstatetype::defexpr);
|
||||||
|
REQUIRE(define_xs::from(parser.i_exstate(0)) != nullptr);
|
||||||
|
CHECK(define_xs::from(parser.i_exstate(0))->defxs_type() == defexprstatetype::def_4);
|
||||||
|
}
|
||||||
|
if (parser.stack_size() > 1)
|
||||||
|
CHECK(parser.i_exstype(1)
|
||||||
|
== exprstatetype::expect_toplevel_expression_sequence);
|
||||||
|
|
||||||
|
/* expecting either:
|
||||||
|
* = rhs-expression
|
||||||
|
* new-expression
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* input:
|
||||||
|
*
|
||||||
|
* i_tc==0:
|
||||||
|
* def foo =
|
||||||
|
* ^ ^
|
||||||
|
* 0 1
|
||||||
|
*
|
||||||
|
* i_tc==1:
|
||||||
|
* def foo : f64 =
|
||||||
|
* ^ ^
|
||||||
|
* 0 1
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
auto r5 = parser.include_token(token_type::singleassign());
|
||||||
|
|
||||||
|
cerr << "parser state after [def foo : f64 =]" << endl;
|
||||||
|
cerr << parser << endl;
|
||||||
|
|
||||||
|
REQUIRE(r5.get() == nullptr);
|
||||||
|
|
||||||
|
CHECK(parser.stack_size() == 3);
|
||||||
|
|
||||||
|
/* stack should be
|
||||||
|
*
|
||||||
|
* expect_toplevel_expression_sequence
|
||||||
|
* def_5
|
||||||
|
* expect_expression
|
||||||
|
*/
|
||||||
|
CHECK(parser.stack_size() == 3);
|
||||||
|
if (parser.stack_size() > 0)
|
||||||
|
CHECK(parser.i_exstype(0) == exprstatetype::expect_rhs_expression);
|
||||||
|
if (parser.stack_size() > 1) {
|
||||||
|
CHECK(parser.i_exstype(1) == exprstatetype::defexpr);
|
||||||
|
REQUIRE(define_xs::from(parser.i_exstate(1)) != nullptr);
|
||||||
|
CHECK(define_xs::from(parser.i_exstate(1))->defxs_type() == defexprstatetype::def_5);
|
||||||
|
}
|
||||||
|
if (parser.stack_size() > 2)
|
||||||
|
CHECK(parser.i_exstype(2)
|
||||||
|
== exprstatetype::expect_toplevel_expression_sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* input:
|
||||||
|
*
|
||||||
|
* i_tc==0:
|
||||||
|
* def foo = 3.14159265
|
||||||
|
* ^ ^
|
||||||
|
* 0 1
|
||||||
|
*
|
||||||
|
* i_tc==1:
|
||||||
|
* def foo : f64 = 3.14159265
|
||||||
|
* ^ ^
|
||||||
|
* 0 1
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
auto r6 = parser.include_token(token_type::f64_token("3.14159265"));
|
||||||
|
|
||||||
|
cerr << "parser state after [def foo : f64 = 3.14159265]" << endl;
|
||||||
|
cerr << parser << endl;
|
||||||
|
|
||||||
|
REQUIRE(r6.get() == nullptr);
|
||||||
|
|
||||||
|
/* stack should be
|
||||||
|
*
|
||||||
|
* expect_toplevel_expression_sequence
|
||||||
|
*/
|
||||||
|
CHECK(parser.stack_size() == 4);
|
||||||
|
if (parser.stack_size() > 0)
|
||||||
|
CHECK(parser.i_exstype(0) == exprstatetype::expr_progress);
|
||||||
|
if (parser.stack_size() > 1)
|
||||||
|
CHECK(parser.i_exstype(1) == exprstatetype::expect_rhs_expression);
|
||||||
|
if (parser.stack_size() > 2) {
|
||||||
|
CHECK(parser.i_exstype(2) == exprstatetype::defexpr);
|
||||||
|
REQUIRE(define_xs::from(parser.i_exstate(2)) != nullptr);
|
||||||
|
CHECK(define_xs::from(parser.i_exstate(2))->defxs_type() == defexprstatetype::def_5);
|
||||||
|
}
|
||||||
|
if (parser.stack_size() > 3)
|
||||||
|
CHECK(parser.i_exstype(3)
|
||||||
|
== exprstatetype::expect_toplevel_expression_sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* input:
|
||||||
|
*
|
||||||
|
* i_tc==0:
|
||||||
|
* def foo = 3.14159265 ;
|
||||||
|
* ^ ^
|
||||||
|
* 0 1
|
||||||
|
*
|
||||||
|
* i_tc==1:
|
||||||
|
* def foo : f64 = 3.14159265 ;
|
||||||
|
* ^ ^
|
||||||
|
* 0 1
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
auto r7 = parser.include_token(token_type::semicolon());
|
||||||
|
|
||||||
|
cerr << "parser state after [def foo : f64 = 3.14159265;]" << endl;
|
||||||
|
cerr << parser << endl;
|
||||||
|
|
||||||
|
REQUIRE(r7.get() != nullptr);
|
||||||
|
|
||||||
|
CHECK(parser.stack_size() == 1);
|
||||||
|
|
||||||
|
/* stack should be
|
||||||
|
*
|
||||||
|
* expect_toplevel_expression_sequence
|
||||||
|
*/
|
||||||
|
CHECK(parser.stack_size() == 1);
|
||||||
|
if (parser.stack_size() > 0)
|
||||||
|
CHECK(parser.i_exstype(0)
|
||||||
|
== exprstatetype::expect_toplevel_expression_sequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /*TEST_CASE(parser)*/
|
||||||
|
} /*namespace ut*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end parser.test.cpp */
|
||||||
67
xo-reader/utest/reader.test.cpp
Normal file
67
xo-reader/utest/reader.test.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* @file reader.test.cpp */
|
||||||
|
|
||||||
|
#include "xo/reader/reader.hpp"
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::scm::reader;
|
||||||
|
|
||||||
|
namespace ut {
|
||||||
|
namespace {
|
||||||
|
struct test_case {
|
||||||
|
const char * text_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<test_case> s_testcase_v = {
|
||||||
|
{"def foo : f64 = 3.14159265;"},
|
||||||
|
{"def foo : f64 = (3.14159265);"},
|
||||||
|
//{"def foo : f64 = 2.0 * 3.14159265;"},
|
||||||
|
{"def foo = lambda (x : f64) 3.1415965;"},
|
||||||
|
{"def foo = lambda (x : f64, y : f64) 3.1415965;"},
|
||||||
|
{"def foo = lambda (x : f64) x;"},
|
||||||
|
{"def foo = lambda (x : f64) { def y = x * x; y; }"},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("reader", "[reader]") {
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag), xtag("utest", "reader"));
|
||||||
|
|
||||||
|
for (std::size_t i_tc = 0; i_tc < s_testcase_v.size(); ++i_tc) {
|
||||||
|
const test_case & tc = s_testcase_v[i_tc];
|
||||||
|
|
||||||
|
reader rdr;
|
||||||
|
|
||||||
|
scope log(XO_ENTER2(always, c_debug_flag, "reader.testcase"),
|
||||||
|
xtag("i_tc", i_tc));
|
||||||
|
|
||||||
|
rdr.begin_translation_unit();
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto input
|
||||||
|
= reader::span_type::from_cstr(tc.text_);
|
||||||
|
auto rr
|
||||||
|
= rdr.read_expr(input, true /*eof*/);
|
||||||
|
|
||||||
|
REQUIRE(rr.expr_.get());
|
||||||
|
|
||||||
|
log && log(xtag("expr", rr.expr_));
|
||||||
|
|
||||||
|
input = input.after_prefix(rr.rem_);
|
||||||
|
|
||||||
|
log && log(xtag("post.input", input));
|
||||||
|
|
||||||
|
REQUIRE(input.empty());
|
||||||
|
} catch (std::exception & ex) {
|
||||||
|
log && log(ex.what());
|
||||||
|
|
||||||
|
INFO(ex.what());
|
||||||
|
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /*namespace ut*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end reader.test.cpp */
|
||||||
6
xo-reader/utest/reader_utest_main.cpp
Normal file
6
xo-reader/utest/reader_utest_main.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
/* file parser_utest_main.cpp */
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
/* end parser_utest_main.cpp */
|
||||||
Loading…
Add table
Add a link
Reference in a new issue