Browse Source

interpreter now can interpret things with numbers in them, as well as other procedures

master
Ludovic 'Archivist' Lagouardette 1 year ago
parent
commit
2602fd84ed
14 changed files with 353 additions and 308 deletions
  1. +56
    -56
      .idea/codeStyles/Project.xml
  2. +4
    -4
      .idea/codeStyles/codeStyleConfig.xml
  3. +3
    -3
      .idea/misc.xml
  4. +7
    -7
      .idea/modules.xml
  5. +1
    -1
      .idea/sugar.iml
  6. +5
    -5
      .idea/vcs.xml
  7. +5
    -1
      CMakeLists.txt
  8. +85
    -0
      include/molasses/errors.h
  9. +4
    -184
      include/molasses/parser_primitives.h
  10. +126
    -0
      include/molasses/parser_types.h
  11. +13
    -18
      src/main.cpp
  12. +16
    -0
      src/molasses/generator_primitives.cpp
  13. +17
    -29
      src/molasses/generator_primitives_x86_64_linux.cpp
  14. +11
    -0
      src/molasses/parser_primitives.cpp

+ 56
- 56
.idea/codeStyles/Project.xml View File

@ -1,57 +1,57 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<Objective-C>
<option name="CLASS_CONSTRUCTOR_INIT_LIST_COMMA_ON_NEXT_LINE" value="true" />
<option name="SUPERCLASS_LIST_COMMA_ON_NEXT_LINE" value="true" />
</Objective-C>
<Objective-C-extensions>
<rules>
<rule entity="NAMESPACE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="MACRO" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="ENUM" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="ENUMERATOR" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="TYPEDEF" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="UNION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="GLOBAL_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="PARAMETER" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="LOCAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
</rules>
</Objective-C-extensions>
<Objective-C-extensions>
<rules>
<rule entity="NAMESPACE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="MACRO" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="ENUM" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="ENUMERATOR" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="TYPEDEF" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="UNION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="GLOBAL_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="PARAMETER" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="LOCAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
</rules>
</Objective-C-extensions>
<clangFormatSettings>
<option name="ENABLED" value="true" />
</clangFormatSettings>
<codeStyleSettings language="ObjectiveC">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<Objective-C>
<option name="CLASS_CONSTRUCTOR_INIT_LIST_COMMA_ON_NEXT_LINE" value="true" />
<option name="SUPERCLASS_LIST_COMMA_ON_NEXT_LINE" value="true" />
</Objective-C>
<Objective-C-extensions>
<rules>
<rule entity="NAMESPACE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="MACRO" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="ENUM" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="ENUMERATOR" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="TYPEDEF" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="UNION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="GLOBAL_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="PARAMETER" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="LOCAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
</rules>
</Objective-C-extensions>
<Objective-C-extensions>
<rules>
<rule entity="NAMESPACE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="MACRO" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="ENUM" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="ENUMERATOR" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="TYPEDEF" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="UNION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="GLOBAL_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="PARAMETER" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="LOCAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
</rules>
</Objective-C-extensions>
<clangFormatSettings>
<option name="ENABLED" value="true" />
</clangFormatSettings>
<codeStyleSettings language="ObjectiveC">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

+ 4
- 4
.idea/codeStyles/codeStyleConfig.xml View File

@ -1,5 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

+ 3
- 3
.idea/misc.xml View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

+ 7
- 7
.idea/modules.xml View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/sugar.iml" filepath="$PROJECT_DIR$/.idea/sugar.iml" />
</modules>
</component>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/sugar.iml" filepath="$PROJECT_DIR$/.idea/sugar.iml" />
</modules>
</component>
</project>

+ 1
- 1
.idea/sugar.iml View File

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

+ 5
- 5
.idea/vcs.xml View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

+ 5
- 1
CMakeLists.txt View File

@ -13,7 +13,11 @@ add_executable(sugar
include/molasses/lexer.h
src/molasses/parser_primitives.cpp
include/molasses/parser_primitives.h
include/molasses/generator_primitives.h src/molasses/interpreter.cpp)
include/molasses/generator_primitives.h
src/molasses/interpreter.cpp
include/molasses/errors.h
include/molasses/parser_types.h
src/molasses/generator_primitives.cpp)
function(add_expect_test [testname filename])
add_test(

+ 85
- 0
include/molasses/errors.h View File

@ -0,0 +1,85 @@
#pragma once
#include "lexer.h"
#include <sstream>
#include <stdexcept>
namespace molasses {
namespace details {
template<typename... RestT>
std::string concatenate_builder_impl(std::stringstream& stream)
requires(sizeof...(RestT) == 0)
{
return stream.str();
}
template<typename FirstT, typename... RestT>
std::string concatenate_builder_impl(std::stringstream& stream, FirstT first, RestT... rest) {
stream << first;
return concatenate_builder_impl(stream, rest...);
}
template<typename... RestT>
std::string concatenate_builder(RestT... rest) {
std::stringstream stream{};
return concatenate_builder_impl(stream, rest...);
}
}
struct build_system_error : std::runtime_error {
explicit build_system_error(const std::string& message)
: std::runtime_error(message) {}
};
struct interpreter_error : std::runtime_error {
explicit interpreter_error(const std::string& message)
: std::runtime_error(message) {}
};
struct parser_error : public std::runtime_error {
explicit parser_error(const std::string& str)
: std::runtime_error(str) {}
};
struct type_input_error : public parser_error {
type_input_error()
: parser_error("Bad type provided") {}
// TODO: Better error message
};
struct value_missing_error : public parser_error {
value_missing_error()
: parser_error("Expected value, none provided") {}
// TODO: Better error message
};
struct procedure_stack_error : public parser_error {
procedure_stack_error()
: parser_error("Expected the stack to look like the return stack upon completion\n") {}
// TODO: Better error message
};
struct unexpected_token_error : public parser_error {
unexpected_token_error(const symbol& sym, const std::string& found, const std::string& expected)
: parser_error(details::concatenate_builder(
"Unexpected token encountered\n", "\tAt ", sym.file_name, ":", sym.line, ":", sym.column, "\n",
"\tExpected ", expected, "\n", "\tFound ", found, "\n"
)) {}
};
struct expecting_token_error : public parser_error {
expecting_token_error(const std::string& expected, const std::string& context)
: parser_error(details::concatenate_builder(
"An expected token has not been encountered before the end of the input\n", "\tExpected ", expected,
"\n", "\t", context, "\n"
)) {}
// TODO: Better error message
};
struct unknown_token_error : public parser_error {
explicit unknown_token_error(const symbol& sym)
: parser_error(details::concatenate_builder(
"An unknown token has been encountered\n", "\tAt ", sym.file_name, ":", sym.line, ":", sym.column,
"\n"
)) {}
// TODO: Better error message
};
struct type_expected_with_modifier_error : public parser_error {
type_expected_with_modifier_error()
: parser_error("A type is expected before a modifier") {}
// TODO: Better error message
};
}

+ 4
- 184
include/molasses/parser_primitives.h View File

@ -13,6 +13,7 @@
#include <vector>
#include "molasses/lexer.h"
#include "parser_types.h"
enum class architecture_t {
@ -29,193 +30,11 @@ constexpr size_t architecture_ptr_size = 4;
#endif
namespace molasses {
namespace details {
template<typename ...RestT>
std::string concatenate_builder_impl(std::stringstream& stream)
requires (sizeof...(RestT) == 0)
{
return stream.str();
}
template<typename FirstT, typename ...RestT>
std::string concatenate_builder_impl(std::stringstream& stream, FirstT first, RestT... rest) {
stream << first;
return concatenate_builder_impl(stream, rest...);
}
template<typename ...RestT>
std::string concatenate_builder(RestT... rest) {
std::stringstream stream{};
return concatenate_builder_impl(stream, rest...);
}
}
struct type {
[[nodiscard]] virtual std::string name() const = 0;
[[nodiscard]] virtual size_t byte_size() const = 0;
};
inline auto operator<=>(const type& lhs, const type& rhs) {
return lhs.name() <=> rhs.name();
}
struct primitive_type : public type {
std::string _name;
size_t _byte_size;
primitive_type(std::string name, size_t byte_size)
: _name(std::forward<std::string>(name))
, _byte_size(byte_size)
{}
[[nodiscard]] std::string name() const final {
return _name;
}
[[nodiscard]] size_t byte_size() const final {
return _byte_size;
};
};
struct parser_context;
struct ptr_type{
void* ptr;
std::shared_ptr<type> pointed;
};
using stack_element = std::variant<int32_t, int64_t, ptr_type>;
using interpreter_stack = std::stack<stack_element>;
struct generate_context;
struct operation {
[[nodiscard]] virtual std::string name() const = 0;
[[nodiscard]] virtual std::vector<std::string> argument_types() const = 0;
[[nodiscard]] virtual std::vector<std::string> return_types() const = 0;
[[nodiscard]] virtual std::vector<std::string> generate(const parser_context&, const lexed_output& lexer_data) const = 0;
[[nodiscard]] virtual std::vector<std::string> emit(const parser_context&) const = 0;
virtual void execute(const generate_context&, interpreter_stack&) const = 0;
};
struct primitive_operation : public operation {
std::string _name;
std::vector<std::string> _args;
std::vector<std::string> _rets;
std::vector<std::string> _instructions;
std::function<void(const generate_context&, interpreter_stack&)> _executable;
primitive_operation(std::string name, std::vector<std::string> args, std::vector<std::string> rets, std::vector<std::string> body, std::function<void(const generate_context&,interpreter_stack&)> executable)
: _name(std::forward<std::string>(name))
, _args(std::forward<std::vector<std::string>>(args))
, _rets(std::forward<std::vector<std::string>>(rets))
, _instructions(std::forward<std::vector<std::string>>(body))
, _executable(std::move(executable))
{}
[[nodiscard]] std::string name() const final {
return _name;
}
[[nodiscard]] std::vector<std::string> argument_types() const final {
return _args;
}
[[nodiscard]] std::vector<std::string> return_types() const final {
return _rets;
}
[[nodiscard]] std::vector<std::string> generate(const parser_context&, const lexed_output& lexer_data) const final {
return {};
}
[[nodiscard]] std::vector<std::string> emit(const parser_context&) const final {
return _instructions;
}
void execute(const generate_context& ctx, interpreter_stack& stack) const override {
_executable(ctx, stack);
};
};
struct procedure_operation : public operation {
std::string _name;
std::vector<std::string> _args;
std::vector<std::string> _rets;
std::vector<symbol> _body;
procedure_operation(std::string name, std::vector<std::string> args, std::vector<std::string> rets, std::vector<symbol> body)
: _name(std::forward<std::string>(name))
, _args(std::forward<std::vector<std::string>>(args))
, _rets(std::forward<std::vector<std::string>>(rets))
, _body(std::forward<std::vector<symbol>>(body))
{}
[[nodiscard]] std::string name() const final {
return _name;
}
[[nodiscard]] std::vector<std::string> argument_types() const final {
return _args;
}
[[nodiscard]] std::vector<std::string> return_types() const final {
return _rets;
}
[[nodiscard]] std::vector<std::string> generate(const parser_context&, const lexed_output& lexer_data) const final;
[[nodiscard]] std::vector<std::string> emit(const parser_context&) const final;
void execute(const generate_context&, interpreter_stack&) const final;
};
inline auto operator<=>(const operation& lhs, const operation& rhs) {
return lhs.name() <=> rhs.name();
}
struct parser_error : public std::runtime_error {
explicit parser_error(const std::string& str) : std::runtime_error(str) {}
};
struct type_input_error : public parser_error {
type_input_error() : parser_error("Bad type provided") {}
// TODO: Better error message
};
struct value_missing_error : public parser_error {
value_missing_error() : parser_error("Expected value, none provided") {}
// TODO: Better error message
};
struct procedure_stack_error : public parser_error {
procedure_stack_error() : parser_error("Expected the stack to look like the return stack upon completion\n") {}
// TODO: Better error message
};
struct unexpected_token_error : public parser_error {
unexpected_token_error(const symbol& sym, const std::string& found, const std::string& expected)
: parser_error (
details::concatenate_builder(
"Unexpected token encountered\n",
"\tAt ", sym.file_name,":",sym.line,":",sym.column,"\n",
"\tExpected ", expected, "\n",
"\tFound ", found, "\n"
)
) {}
};
struct expecting_token_error : public parser_error {
expecting_token_error(const std::string& expected, const std::string& context)
: parser_error(
details::concatenate_builder(
"An expected token has not been encountered before the end of the input\n",
"\tExpected ", expected,"\n",
"\t", context,"\n"
)
)
{}
// TODO: Better error message
};
struct unknown_token_error : public parser_error {
explicit unknown_token_error(const symbol& sym) : parser_error(details::concatenate_builder("An unknown token has been encountered\n", "\tAt ", sym.file_name,":",sym.line,":",sym.column,"\n")) {}
// TODO: Better error message
};
struct type_expected_with_modifier_error : public parser_error {
type_expected_with_modifier_error() : parser_error("A type is expected before a modifier") {}
// TODO: Better error message
};
std::vector<std::string> operator>>(std::vector<std::string> current_stack, const operation& next_op);
std::optional<int32_t> try_parse_int32(const std::string& str);
std::optional<int64_t> try_parse_int64(const std::string& str);
struct parser_context {
std::vector<std::shared_ptr<type>> types;
std::vector<std::shared_ptr<operation>> operations;
@ -235,6 +54,7 @@ namespace molasses {
std::tuple<interpreter_stack, generate_context, std::optional<std::shared_ptr<std::runtime_error>>> interpret(interpreter_stack, generate_context, std::string );
std::optional<int32_t> try_parse_int32(const std::string& str);
generate_context parse(parser_context, const lexed_output&);
std::vector<std::string> generate(const generate_context&);

+ 126
- 0
include/molasses/parser_types.h View File

@ -0,0 +1,126 @@
#pragma once
#include "lexer.h"
#include <functional>
#include <memory>
#include <stack>
#include <string>
#include <variant>
#include <vector>
namespace molasses {
struct type {
[[nodiscard]] virtual std::string name() const = 0;
[[nodiscard]] virtual size_t byte_size() const = 0;
};
inline auto operator<=>(const type& lhs, const type& rhs) {
return lhs.name() <=> rhs.name();
}
struct primitive_type : public type {
std::string _name;
size_t _byte_size;
primitive_type(std::string name, size_t byte_size)
: _name(std::forward<std::string>(name))
, _byte_size(byte_size)
{}
[[nodiscard]] std::string name() const final {
return _name;
}
[[nodiscard]] size_t byte_size() const final {
return _byte_size;
};
};
struct parser_context;
struct ptr_type{
void* ptr;
std::shared_ptr<type> pointed;
};
using stack_element = std::variant<int32_t, int64_t, ptr_type>;
using interpreter_stack = std::stack<stack_element>;
struct generate_context;
struct operation {
[[nodiscard]] virtual std::string name() const = 0;
[[nodiscard]] virtual std::vector<std::string> argument_types() const = 0;
[[nodiscard]] virtual std::vector<std::string> return_types() const = 0;
[[nodiscard]] virtual std::vector<std::string> generate(const parser_context&, const lexed_output& lexer_data) const = 0;
[[nodiscard]] virtual std::vector<std::string> emit(const parser_context&) const = 0;
virtual void execute(const generate_context&, interpreter_stack&) const = 0;
};
struct primitive_operation : public operation {
std::string _name;
std::vector<std::string> _args;
std::vector<std::string> _rets;
std::vector<std::string> _instructions;
std::function<void(const generate_context&, interpreter_stack&)> _executable;
primitive_operation(std::string name, std::vector<std::string> args, std::vector<std::string> rets, std::vector<std::string> body, std::function<void(const generate_context&,interpreter_stack&)> executable)
: _name(std::forward<std::string>(name))
, _args(std::forward<std::vector<std::string>>(args))
, _rets(std::forward<std::vector<std::string>>(rets))
, _instructions(std::forward<std::vector<std::string>>(body))
, _executable(std::move(executable))
{}
[[nodiscard]] std::string name() const final {
return _name;
}
[[nodiscard]] std::vector<std::string> argument_types() const final {
return _args;
}
[[nodiscard]] std::vector<std::string> return_types() const final {
return _rets;
}
[[nodiscard]] std::vector<std::string> generate(const parser_context&, const lexed_output& lexer_data) const final {
return {};
}
[[nodiscard]] std::vector<std::string> emit(const parser_context&) const final {
return _instructions;
}
void execute(const generate_context& ctx, interpreter_stack& stack) const override {
_executable(ctx, stack);
};
};
struct procedure_operation : public operation {
std::string _name;
std::vector<std::string> _args;
std::vector<std::string> _rets;
std::vector<symbol> _body;
procedure_operation(std::string name, std::vector<std::string> args, std::vector<std::string> rets, std::vector<symbol> body)
: _name(std::forward<std::string>(name))
, _args(std::forward<std::vector<std::string>>(args))
, _rets(std::forward<std::vector<std::string>>(rets))
, _body(std::forward<std::vector<symbol>>(body))
{}
[[nodiscard]] std::string name() const final {
return _name;
}
[[nodiscard]] std::vector<std::string> argument_types() const final {
return _args;
}
[[nodiscard]] std::vector<std::string> return_types() const final {
return _rets;
}
[[nodiscard]] std::vector<std::string> generate(const parser_context&, const lexed_output& lexer_data) const final;
[[nodiscard]] std::vector<std::string> emit(const parser_context&) const final;
void execute(const generate_context&, interpreter_stack&) const final;
};
inline auto operator<=>(const operation& lhs, const operation& rhs) {
return lhs.name() <=> rhs.name();
}
}

+ 13
- 18
src/main.cpp View File

@ -1,5 +1,6 @@
#include "molasses/lexer.h"
#include "molasses/parser_primitives.h"
#include "molasses/errors.h"
#include <cstring>
#include <filesystem>
#include <fstream>
@ -10,12 +11,6 @@
using compile_element = std::variant<molasses::lexed_output, molasses::generate_context, std::string>;
struct build_system_error : std::runtime_error {
explicit build_system_error(const std::string& message)
: std::runtime_error(message)
{}
};
int main(int argc, char** argv) {
std::vector<std::string> arguments;
while(argc > 1) {
@ -43,9 +38,9 @@ int main(int argc, char** argv) {
}
compile_stack.emplace(filename);
} else
throw f">build_system_error("generate expects a parsed output\n");
throw ">molasses::build_system_error("generate expects a parsed output\n");
} else
throw f">build_system_error("generate expects a filename\n");
throw ">molasses::build_system_error("generate expects a filename\n");
} else if(elem == "parse") {
molasses::parser_context ctx;
ctx = molasses::register_integers(ctx);
@ -57,27 +52,27 @@ int main(int argc, char** argv) {
auto generator = molasses::parse(ctx, lexer);
compile_stack.emplace(generator);
} else
throw f">build_system_error("parse expects a lexed output\n");
throw ">molasses::build_system_error("parse expects a lexed output\n");
} else if(elem == "lex") {
if(not compile_stack.empty() and std::holds_alternative<std::string>(compile_stack.top())) {
auto filename = std::get<std::string>(compile_stack.top());
compile_stack.pop();
if(not std::filesystem::exists(filename))
throw f">build_system_error("file " + filename + " does not exist\n");
throw ">molasses::build_system_error("file " + filename + " does not exist\n");
std::ifstream t(filename);
std::stringstream buffer;
buffer << t.rdbuf();
auto lexed = molasses::lex(filename, buffer.str());
compile_stack.emplace(lexed);
} else
throw f">build_system_error("lex expects a filename\n");
throw ">molasses::build_system_error("lex expects a filename\n");
} else if(elem == "lex-all") {
std::vector<molasses::lexed_output> lexed_list;
while(not compile_stack.empty() and std::holds_alternative<std::string>(compile_stack.top())) {
auto filename = std::get<std::string>(compile_stack.top());
compile_stack.pop();
if(not std::filesystem::exists(filename))
throw f">build_system_error("file " + filename + " does not exist\n");
throw ">molasses::build_system_error("file " + filename + " does not exist\n");
std::ifstream t(filename);
std::stringstream buffer;
buffer << t.rdbuf();
@ -96,9 +91,9 @@ int main(int argc, char** argv) {
compile_stack.pop();
compile_stack.emplace(molasses::concatenate(lexer_1, lexer_2));
} else
throw f">build_system_error("merge expects 2 lexed outputs\n");
throw ">molasses::build_system_error("merge expects 2 lexed outputs\n");
} else
throw f">build_system_error("merge expects 2 lexed outputs\n");
throw ">molasses::build_system_error("merge expects 2 lexed outputs\n");
} else if(elem == "merge-all") {
if(not compile_stack.empty() and std::holds_alternative<molasses::lexed_output>(compile_stack.top())) {
auto lexer_1 = std::get<molasses::lexed_output>(compile_stack.top());
@ -110,7 +105,7 @@ int main(int argc, char** argv) {
}
compile_stack.emplace(lexer_1);
} else
throw f">build_system_error("merge-all expects at least 1 lexed outputs\n");
throw ">molasses::build_system_error("merge-all expects at least 1 lexed outputs\n");
} else if(elem == "interpret") {
if(not compile_stack.empty() and std::holds_alternative<molasses::generate_context>(compile_stack.top())) {
auto context = std::get<molasses::generate_context>(compile_stack.top());
@ -123,7 +118,7 @@ int main(int argc, char** argv) {
molasses::interpret(stack, context, contents);
}
} else
throw f">build_system_error("merge-all expects at least 1 lexed outputs\n");
throw ">molasses::build_system_error("interpreter expects 1 generated context\n");
} else if(elem == "assemble") {
if(not compile_stack.empty() and std::holds_alternative<std::string>(compile_stack.top())) {
auto filename = std::get<std::string>(compile_stack.top());
@ -137,7 +132,7 @@ int main(int argc, char** argv) {
std::cout << link.str() << std::endl;
system(link.str().c_str());
} else
throw f">build_system_error("assemble expects an assembly file\n");
throw ">molasses::build_system_error("assemble expects an assembly file\n");
} else if(elem == "help" or elem == "--help") {
std::cout << "# Sugar\n\n";
std::cout << "## Commands\n\n";
@ -202,7 +197,7 @@ int main(int argc, char** argv) {
} catch (molasses::parser_error& error) {
std::cerr << "COMPILER ERROR:\n" << error.what();
return 1;
} catch (build_system_error& error) {
} catch (molasses::build_system_error& error) {
std::cerr << "BUILD SYSTEM ERROR:\n" << error.what();
return 1;
}

+ 16
- 0
src/molasses/generator_primitives.cpp View File

@ -0,0 +1,16 @@
#include "molasses/parser_primitives.h"
namespace molasses {
parser_context register_integers(parser_context ctx) {
ctx.types.push_back(std::make_shared<primitive_type>("i8", 1));
ctx.types.push_back(std::make_shared<primitive_type>("i16", 2));
ctx.types.push_back(std::make_shared<primitive_type>("i32", 4));
ctx.types.push_back(std::make_shared<primitive_type>("i64", 8));
ctx.types.push_back(std::make_shared<primitive_type>("u8", 1));
ctx.types.push_back(std::make_shared<primitive_type>("u16", 2));
ctx.types.push_back(std::make_shared<primitive_type>("u32", 4));
ctx.types.push_back(std::make_shared<primitive_type>("u64", 8));
return ctx;
}
}

+ 17
- 29
src/molasses/generator_primitives_x86_64_linux.cpp View File

@ -1,5 +1,6 @@
#include "molasses/parser_primitives.h"
#include "molasses/generator_primitives.h"
#include "molasses/errors.h"
namespace molasses {
@ -117,21 +118,6 @@ namespace molasses {
return builder.str();
}
// TODO: move to a platform independent file
parser_context register_integers(parser_context ctx)
{
ctx.types.push_back(std::make_shared<primitive_type>("i8", 1));
ctx.types.push_back(std::make_shared<primitive_type>("i16", 2));
ctx.types.push_back(std::make_shared<primitive_type>("i32", 4));
ctx.types.push_back(std::make_shared<primitive_type>("i64", 8));
ctx.types.push_back(std::make_shared<primitive_type>("u8", 1));
ctx.types.push_back(std::make_shared<primitive_type>("u16", 2));
ctx.types.push_back(std::make_shared<primitive_type>("u32", 4));
ctx.types.push_back(std::make_shared<primitive_type>("u64", 8));
return ctx;
}
template<>
parser_context register_i32_operations<architecture_t::x86_64_linux>(parser_context ctx) {
ctx.operations.emplace_back(
@ -150,7 +136,7 @@ namespace molasses {
auto value_a = current_stack.top();current_stack.pop();
auto value_b = current_stack.top();current_stack.pop();
if(not std::holds_alternative<int32_t>(value_a) or not std::holds_alternative<int32_t>(value_b)) {
c1">// TODO: handle errors
k">throw interpreter_error("+ expects i32 i32 as input");
}
current_stack.emplace(get<int32_t>(value_a) + get<int32_t>(value_b));
}
@ -171,7 +157,7 @@ namespace molasses {
auto value_a = current_stack.top();current_stack.pop();
auto value_b = current_stack.top();current_stack.pop();
if(not std::holds_alternative<int64_t>(value_a) or not std::holds_alternative<int64_t>(value_b)) {
c1">// TODO: handle errors
k">throw interpreter_error("+_i64 expects i64 i64 as input");
}
current_stack.emplace(get<int64_t>(value_a) + get<int64_t>(value_b));
}
@ -194,7 +180,9 @@ namespace molasses {
auto value_a = current_stack.top();current_stack.pop();
auto value_b = current_stack.top();current_stack.pop();
if(not std::holds_alternative<int64_t>(value_a) or not std::holds_alternative<int64_t>(value_b)) {
// TODO: handle errors
throw interpreter_error("/%_i64 expects i64 i64 as input");
} else if(get<int64_t>(value_b) == 0) {
throw interpreter_error("/%_i64 division by zero");
}
current_stack.emplace(get<int64_t>(value_a) / get<int64_t>(value_b));
current_stack.emplace(get<int64_t>(value_a) % get<int64_t>(value_b));
@ -211,7 +199,7 @@ namespace molasses {
[](const generate_context&, interpreter_stack& current_stack){
auto value = current_stack.top();current_stack.pop();
if(not std::holds_alternative<ptr_type>(value) && not (get<ptr_type>(value).pointed->name() == "u8 ptr")) {
c1">// TODO: handle errors
k">throw interpreter_error("u8-ptr_to_i64 expects u8 ptr as input");
}
current_stack.emplace(intptr_t(get<ptr_type>(value).ptr));
}
@ -233,7 +221,7 @@ namespace molasses {
auto value_a = current_stack.top();current_stack.pop();
auto value_b = current_stack.top();current_stack.pop();
if(not std::holds_alternative<int32_t>(value_a) or not std::holds_alternative<int32_t>(value_b)) {
c1">// TODO: handle errors
k">throw interpreter_error("* expects i32 i32 as input");
}
current_stack.emplace(get<int32_t>(value_a) * get<int32_t>(value_b));
}
@ -255,7 +243,7 @@ namespace molasses {
auto value_a = current_stack.top();current_stack.pop();
auto value_b = current_stack.top();current_stack.pop();
if(not std::holds_alternative<int32_t>(value_a) or not std::holds_alternative<int32_t>(value_b)) {
c1">// TODO: handle errors
k">throw interpreter_error("- expects i32 i32 as input");
}
current_stack.emplace(get<int32_t>(value_a) - get<int32_t>(value_b));
}
@ -274,7 +262,7 @@ namespace molasses {
[](const generate_context&, interpreter_stack& current_stack){
auto value = current_stack.top();current_stack.pop();
if(not std::holds_alternative<int32_t>(value)) {
c1">// TODO: handle errors
k">throw interpreter_error("i32-to-i64 expects i32 as input");
}
current_stack.emplace(int64_t(get<int32_t>(value)));
}
@ -292,7 +280,7 @@ namespace molasses {
[](const generate_context&, interpreter_stack& current_stack){
auto value = current_stack.top();current_stack.pop();
if(not std::holds_alternative<int64_t>(value)) {
c1">// TODO: handle errors
k">throw interpreter_error("i32-to-i64 expects i32 as input");
}
}
)
@ -316,7 +304,7 @@ namespace molasses {
not std::holds_alternative<int64_t>(value_0) or
not std::holds_alternative<int64_t>(value_1)
) {
c1">// TODO: handle errors
k">throw interpreter_error("syscall1 expects i64 i64 as input");
}
#ifdef linux
unix_system::syscall1{}(get<int64_t>(value_0), get<int64_t>(value_1));
@ -345,7 +333,7 @@ namespace molasses {
not std::holds_alternative<int64_t>(value_1) or
not std::holds_alternative<int64_t>(value_2)
) {
c1">// TODO: handle errors
k">throw interpreter_error("syscall2 expects i64 i64 i64 as input");
}
#ifdef linux
unix_system::syscall2{}(get<int64_t>(value_0), get<int64_t>(value_1), get<int64_t>(value_2));
@ -377,7 +365,7 @@ namespace molasses {
not std::holds_alternative<int64_t>(value_2) or
not std::holds_alternative<int64_t>(value_3)
) {
c1">// TODO: handle errors
k">throw interpreter_error("syscall3 expects i64 i64 i64 i64 as input");
}
#ifdef linux
unix_system::syscall3{}(get<int64_t>(value_0), get<int64_t>(value_1), get<int64_t>(value_2), get<int64_t>(value_3));
@ -412,7 +400,7 @@ namespace molasses {
not std::holds_alternative<int64_t>(value_3) or
not std::holds_alternative<int64_t>(value_4)
) {
c1">// TODO: handle errors
k">throw interpreter_error("syscall4 expects i64 i64 i64 i64 i64 as input");
}
#ifdef linux
unix_system::syscall4{}(get<int64_t>(value_0), get<int64_t>(value_1), get<int64_t>(value_2), get<int64_t>(value_3), get<int64_t>(value_4));
@ -450,7 +438,7 @@ namespace molasses {
not std::holds_alternative<int64_t>(value_4) or
not std::holds_alternative<int64_t>(value_5)
) {
c1">// TODO: handle errors
k">throw interpreter_error("syscall5 expects i64 i64 i64 i64 i64 i64 as input");
}
#ifdef linux
unix_system::syscall5{}(get<int64_t>(value_0), get<int64_t>(value_1), get<int64_t>(value_2), get<int64_t>(value_3), get<int64_t>(value_4), get<int64_t>(value_5));
@ -491,7 +479,7 @@ namespace molasses {
not std::holds_alternative<int64_t>(value_5) or
not std::holds_alternative<int64_t>(value_6)
) {
c1">// TODO: handle errors
k">throw interpreter_error("syscall6 expects i64 i64 i64 i64 i64 i64 i64 as input");
}
#ifdef linux
unix_system::syscall6{}(

+ 11
- 0
src/molasses/parser_primitives.cpp View File

@ -2,6 +2,7 @@
#include <iostream>
#include "molasses/parser_primitives.h"
#include "molasses/generator_primitives.h"
#include "molasses/errors.h"
namespace molasses {
std::vector<std::string> operator>>(std::vector<std::string> current_stack, const operation& next_op) {
@ -299,7 +300,17 @@ namespace molasses {
}
void procedure_operation::execute(const generate_context& ctx, interpreter_stack& stack) const {
for(const auto& elem : _body) {
if(auto n = ctx.parser.lookup_operation(ctx.lexer.dictionary.at(elem)); n)
n->execute(ctx, stack);
else if(auto maybe_i64 = try_parse_int64(ctx.lexer.dictionary.at(elem)); maybe_i64)
stack.emplace(int64_t(maybe_i64.value()));
else if(auto maybe_i32 = try_parse_int32(ctx.lexer.dictionary.at(elem)); maybe_i32)
stack.emplace(int32_t(maybe_i32.value()));
else
std::cerr << "OPERATION NOT FOUND: " << elem <<"\n";
}
}
}

Loading…
Cancel
Save