#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include "molasses/lexer.h" enum class architecture_t { x86_64_linux, x86_linux }; #if defined(__x86_64__) && __linux__ constexpr architecture_t architecture = architecture_t::x86_64_linux; constexpr size_t architecture_ptr_size = 8; #elif defined(__i386) || defined(__i386__) || defined(i386) && __linux__ constexpr architecture_t architecture = architecture_t::x86_linux; constexpr size_t architecture_ptr_size = 4; #endif namespace molasses { namespace details { template std::string concatenate_builder_impl(std::stringstream& stream) requires (sizeof...(RestT) == 0) { return stream.str(); } template std::string concatenate_builder_impl(std::stringstream& stream, FirstT first, RestT... rest) { stream << first; return concatenate_builder_impl(stream, rest...); } template 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(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 pointed; }; using stack_element = std::variant; using interpreter_stack = std::stack; struct generate_context; struct operation { [[nodiscard]] virtual std::string name() const = 0; [[nodiscard]] virtual std::vector argument_types() const = 0; [[nodiscard]] virtual std::vector return_types() const = 0; [[nodiscard]] virtual std::vector generate(const parser_context&, const lexed_output& lexer_data) const = 0; [[nodiscard]] virtual std::vector 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 _args; std::vector _rets; std::vector _instructions; std::function _executable; primitive_operation(std::string name, std::vector args, std::vector rets, std::vector body, std::function executable) : _name(std::forward(name)) , _args(std::forward>(args)) , _rets(std::forward>(rets)) , _instructions(std::forward>(body)) , _executable(std::move(executable)) {} [[nodiscard]] std::string name() const final { return _name; } [[nodiscard]] std::vector argument_types() const final { return _args; } [[nodiscard]] std::vector return_types() const final { return _rets; } [[nodiscard]] std::vector generate(const parser_context&, const lexed_output& lexer_data) const final { return {}; } [[nodiscard]] std::vector 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 _args; std::vector _rets; std::vector _body; procedure_operation(std::string name, std::vector args, std::vector rets, std::vector body) : _name(std::forward(name)) , _args(std::forward>(args)) , _rets(std::forward>(rets)) , _body(std::forward>(body)) {} [[nodiscard]] std::string name() const final { return _name; } [[nodiscard]] std::vector argument_types() const final { return _args; } [[nodiscard]] std::vector return_types() const final { return _rets; } [[nodiscard]] std::vector generate(const parser_context&, const lexed_output& lexer_data) const final; [[nodiscard]] std::vector 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 operator>>(std::vector current_stack, const operation& next_op); std::optional try_parse_int32(const std::string& str); struct parser_context { std::vector> types; std::vector> operations; std::vector> procedures; [[nodiscard]] std::shared_ptr lookup_type(const std::string&) const; [[nodiscard]] std::shared_ptr lookup_operation(const std::string&) const; }; struct generate_context { lexed_output lexer; parser_context parser; std::vector> procedures; }; generate_context parse(parser_context, const lexed_output&); std::vector generate(const generate_context&); parser_context register_integers(parser_context); template parser_context register_i32_operations(parser_context); bool type_check(const parser_context&, const lexed_output&, const std::vector&, std::vector execution_input, const std::vector& execution_output); }