From 4d399e10dba5e9bb2507fcbb378321ed593102f2 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Wed, 1 May 2024 10:39:18 +0200 Subject: [PATCH] Split result into symboltable and types --- CMakeLists.txt | 9 +- TODO | 13 +- backend/target.cpp | 1 + include/elna/shell/history.hpp | 28 --- include/elna/shell/interactive.hpp | 89 --------- include/elna/shell/state.hpp | 170 ---------------- include/elna/source/optimizer.hpp | 2 + include/elna/source/result.hpp | 178 ----------------- include/elna/source/semantic.hpp | 1 + include/elna/source/symbol_table.hpp | 151 ++++++++++++++ include/elna/source/types.hpp | 41 ++++ include/elna/tester.hpp | 1 + shell/history.cpp | 54 ----- shell/interactive.cpp | 286 --------------------------- shell/main.cpp | 16 -- shell/state.cpp | 254 ------------------------ source/result.cpp | 153 +------------- source/semantic.cpp | 2 +- source/symbol_table.cpp | 142 +++++++++++++ source/types.cpp | 19 ++ tests/tester.cpp | 48 +++-- 21 files changed, 400 insertions(+), 1258 deletions(-) delete mode 100644 include/elna/shell/history.hpp delete mode 100644 include/elna/shell/interactive.hpp delete mode 100644 include/elna/shell/state.hpp create mode 100644 include/elna/source/symbol_table.hpp create mode 100644 include/elna/source/types.hpp delete mode 100644 shell/history.cpp delete mode 100644 shell/interactive.cpp delete mode 100644 shell/main.cpp delete mode 100644 shell/state.cpp create mode 100644 source/symbol_table.cpp create mode 100644 source/types.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0322664..9461ef6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,16 +14,11 @@ target_include_directories(tester PRIVATE include) FLEX_TARGET(scanner source/scanner.l ${CMAKE_CURRENT_BINARY_DIR}/scanner.cpp) -add_executable(elnsh shell/main.cpp - shell/interactive.cpp include/elna/shell/interactive.hpp - shell/history.cpp include/elna/shell/history.hpp - shell/state.cpp include/elna/shell/state.hpp -) -target_include_directories(elnsh PRIVATE include) - add_executable(elna cli/main.cpp source/lexer.cpp include/elna/source/lexer.hpp source/parser.cpp include/elna/source/parser.hpp + source/types.cpp include/elna/source/types.hpp + source/symbol_table.cpp include/elna/source/symbol_table.hpp source/result.cpp include/elna/source/result.hpp source/semantic.cpp include/elna/source/semantic.hpp source/optimizer.cpp include/elna/source/optimizer.hpp diff --git a/TODO b/TODO index d87a6d0..593f42e 100644 --- a/TODO +++ b/TODO @@ -12,14 +12,5 @@ - Syscalls. - Error message with an empty file wrongly says that a ")" is expected. - Support any expressions for constants. - -# Shell -- Replace hard coded ANSI codes with constants or functions. - -## Completion - -- Configure fzf to show only the current directory files -- Support multiple selections for insertion in fzf. -- Don't hardcode fzf binary path. -- Send the word under the cursor to fzf as initial input. -- Home directory expansion. +- Built-in types are added in the symbol table constructor. It would be better to + add them outside, before the type analysis begins. diff --git a/backend/target.cpp b/backend/target.cpp index f52163d..5ab5d04 100644 --- a/backend/target.cpp +++ b/backend/target.cpp @@ -155,6 +155,7 @@ namespace elna::riscv writer.set_os_abi(ELFIO::ELFOSABI_NONE); writer.set_type(ELFIO::ET_REL); + writer.set_flags(0x4); // EF_RISCV_FLOAT_ABI_DOUBLE writer.set_machine(ELFIO::EM_RISCV); // Create code section diff --git a/include/elna/shell/history.hpp b/include/elna/shell/history.hpp deleted file mode 100644 index c7fb3d4..0000000 --- a/include/elna/shell/history.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace elna -{ - struct editor_history : public boost::noncopyable - { - using const_iterator = std::list::const_iterator; - - editor_history(); - - void push(const std::string& entry); - void clear(); - - const_iterator next() noexcept; - const_iterator prev() noexcept; - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; - const_iterator current() const noexcept; - - private: - std::list commands; - std::list::const_iterator current_pointer; - }; -} diff --git a/include/elna/shell/interactive.hpp b/include/elna/shell/interactive.hpp deleted file mode 100644 index bd3f94c..0000000 --- a/include/elna/shell/interactive.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "elna/shell/state.hpp" -#include "elna/shell/history.hpp" - -#define BOOST_PROCESS_USE_STD_FS - -namespace elna -{ - /** - * Runtime exception for non recoverable errors. - */ - struct interactive_exception : public std::runtime_error - { - /** - * Constructor. - */ - interactive_exception(); - }; - - /** - * Main loop. - */ - void loop(); - - /** - * Reads the next line. - * Returns no value upon receiving end of file. - * - * \param history Shell history. - * \return The read line. - */ - std::optional read_line(editor_history& history); - - /** - * Runs a built-in or a command. - * - * \param line The command and arguments. - * \return Whether the input shoud continued (no exit requested). - */ - bool execute(const std::string& line); - - /** - * Runs the binary specified in its argument. - * - * \param program Program name in PATH. - */ - void launch(const std::string& program); - - /** - * Enables the raw mode. - * - * \return Whether the operation was successful. - */ - bool enable_raw_mode(); - - /** - * Disables the raw mode. - */ - void disable_raw_mode(); - - /** - * Reads a key. - * - * \return Read character. - */ - key read_key(); - - /** - * Calls autocompletion. - * - * \param User input. - * \param Cursor position in the user input. - * \return Selected item. - */ - std::string complete(const std::string& input, const std::size_t position); - - /** - * Prints the message from the exception. - * - * \param exception The exception to print. - */ - void print_exception(const std::exception& exception); -} diff --git a/include/elna/shell/state.hpp b/include/elna/shell/state.hpp deleted file mode 100644 index 4c7e8f4..0000000 --- a/include/elna/shell/state.hpp +++ /dev/null @@ -1,170 +0,0 @@ -#include -#include -#include -#include - -namespace elna -{ - constexpr const char *erase_line = "\x1b[2K"; - constexpr const char *start_kitty_keybaord = "\x1b[>1u"; - constexpr const char *end_kitty_keybaord = "\x1b[ store; - std::uint8_t modifiers; - }; - - /** - * The action should be performed after updating the editor state. - */ - enum class action - { - redraw, ///< Redraw everything. - write, ///< Write a single character. - finalize, ///< Finalize command input. - move, ///< Move the cursor. - ignore, ///< Do nothing. - complete, ///< Complete the input. - history, ///< Navigate the history. - }; - - /** - * The line editor with its state. - */ - class editor_state - { - std::string input; - std::string prompt = "> "; - std::size_t position{ 1 }; - - public: - editor_state(); - - /** - * Returns the current input gathered by the lin editor. - * - * \return User input. - */ - const std::string& command_line() const noexcept; - - /** - * Processes the next keypress by changing the line editor state. - * - * \param key Pressed key. - * \return Action to do after the key was pressed. - */ - action process_keypress(const key& press); - - /** - * Clears editors working area and writes drawing sequences into the - * buffer. - * - * \param T Output range for bytes. - * \param output Output buffer. - */ - template - void draw(T output) const - { - std::string code; - - std::copy(erase_line, erase_line + strlen(erase_line), output); - - code = cursor_to_column(); - std::copy(std::cbegin(code), std::cend(code), output); - - std::copy(std::cbegin(this->prompt), std::cend(this->prompt), output); - std::copy(std::cbegin(this->input), std::cend(this->input), output); - - code = cursor_to_column(absolute_position()); - std::copy(std::cbegin(code), std::cend(code), output); - } - - /** - * Computes the position in the terminal line. - * - * \return Position in the terminal line. - */ - std::size_t absolute_position() const noexcept; - - /** - * Cursor position relative to the start of the user input. - * - * \returns Cursor position. - */ - std::size_t relative_position() const noexcept; - - /** - * Inserts text at cursor position. - * - * \param text Text to insert. - */ - void insert(const std::string& text); - void insert(const key::char_t text); - - /** - * Replaces the user input with the given string. - * - * \param text New user input string. - */ - void load(const std::string& text); - }; -} diff --git a/include/elna/source/optimizer.hpp b/include/elna/source/optimizer.hpp index 3763e85..e276c0b 100644 --- a/include/elna/source/optimizer.hpp +++ b/include/elna/source/optimizer.hpp @@ -1,6 +1,8 @@ #pragma once +#include #include "elna/source/parser.hpp" +#include "elna/source/symbol_table.hpp" namespace elna::source { diff --git a/include/elna/source/result.hpp b/include/elna/source/result.hpp index 1602db4..4ba775a 100644 --- a/include/elna/source/result.hpp +++ b/include/elna/source/result.hpp @@ -1,15 +1,12 @@ #pragma once #include -#include #include #include #include #include #include #include -#include -#include namespace elna::source { @@ -126,181 +123,6 @@ namespace elna::source std::string what() const override; }; - class symbol_table; - - /** - * Type representation. - */ - struct type - { - const std::size_t byte_size; - - protected: - explicit type(const std::size_t byte_size); - }; - - /** - * Built-in type representation. - */ - struct primitive_type : public type - { - const std::string type_name; - - primitive_type(const std::string& type_name, const std::size_t byte_size); - }; - - /** - * Typed pointer. - */ - struct pointer_type : public type - { - std::shared_ptr base_type; - - pointer_type(std::shared_ptr base_type, const std::size_t byte_size); - }; - - inline const primitive_type boolean_type{ "Boolean", 1 }; - inline const primitive_type int_type{ "Int", 4 }; - - /** - * Generic language entity information. - */ - class info - { - public: - virtual ~info() = 0; - - protected: - info(); - }; - - /** - * Type information. - */ - class type_info final : public info - { - std::shared_ptr m_type; - - public: - explicit type_info(const class type& type); - ~type_info() override; - std::shared_ptr type() const noexcept; - }; - - /** - * Constant information. - */ - class constant_info final : public info - { - std::int32_t m_value; - - public: - constant_info(const std::int32_t value); - ~constant_info() override; - std::int32_t value() const noexcept; - }; - - /** - * Variable information. - */ - class variable_info final : public info - { - std::shared_ptr m_type; - - public: - std::ptrdiff_t offset{ 0 }; - - explicit variable_info(std::shared_ptr type); - ~variable_info() override; - std::shared_ptr type() noexcept; - }; - - /** - * Procedure parameter information. - */ - class parameter_info final : public info - { - std::shared_ptr m_type; - - public: - std::ptrdiff_t offset{ 0 }; - - explicit parameter_info(std::shared_ptr type); - ~parameter_info() override; - std::shared_ptr type() const noexcept; - }; - - /** - * Intrinsic and external procedure information. - */ - class intrinsic_info : public info - { - public: - std::vector parameter_infos; - - ~intrinsic_info() override; - std::size_t parameter_stack_size() const noexcept; - }; - - /** - * Procedure information. - */ - class procedure_info final : public intrinsic_info - { - std::shared_ptr local_table; - - public: - std::size_t local_stack_size{ 0 }; - std::size_t argument_stack_size{ 0 }; - - explicit procedure_info(std::shared_ptr outer_scope); - ~procedure_info() override; - - std::shared_ptr scope(); - std::size_t stack_size() const noexcept; - }; - - /** - * Symbol table. - */ - class symbol_table - { - std::unordered_map> entries; - std::shared_ptr outer_scope; - - public: - /** - * Constructs a new symbol with an optional outer scope. - * - * \param scope Outer scope. - */ - explicit symbol_table(std::shared_ptr scope = nullptr); - - /** - * Looks for symbol in the table by name. Returns nullptr if the symbol - * can not be found. - * - * \param name Symbol name. - * \return Symbol from the table if found. - */ - std::shared_ptr lookup(const std::string& name); - - /** - * Registers new symbol. - * - * \param name Symbol name. - * \param entry Symbol information. - */ - void enter(const std::string& name, std::shared_ptr entry); - - /** - * Returns the outer scope or nullptr if the this is the global scope. - * - * \return Outer scope. - */ - std::shared_ptr scope(); - }; - template struct writer { diff --git a/include/elna/source/semantic.hpp b/include/elna/source/semantic.hpp index d4aaaa6..6e6e42b 100644 --- a/include/elna/source/semantic.hpp +++ b/include/elna/source/semantic.hpp @@ -1,6 +1,7 @@ #pragma once #include "elna/source/parser.hpp" +#include "elna/source/symbol_table.hpp" namespace elna::source { diff --git a/include/elna/source/symbol_table.hpp b/include/elna/source/symbol_table.hpp new file mode 100644 index 0000000..73b4110 --- /dev/null +++ b/include/elna/source/symbol_table.hpp @@ -0,0 +1,151 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace elna::source +{ + class symbol_table; + + /** + * Generic language entity information. + */ + class info + { + public: + virtual ~info() = 0; + + protected: + info(); + }; + + /** + * Type information. + */ + class type_info final : public info + { + std::shared_ptr m_type; + + public: + explicit type_info(const class type& type); + ~type_info() override; + std::shared_ptr type() const noexcept; + }; + + /** + * Constant information. + */ + class constant_info final : public info + { + std::int32_t m_value; + + public: + constant_info(const std::int32_t value); + ~constant_info() override; + std::int32_t value() const noexcept; + }; + + /** + * Variable information. + */ + class variable_info final : public info + { + std::shared_ptr m_type; + + public: + std::ptrdiff_t offset{ 0 }; + + explicit variable_info(std::shared_ptr type); + ~variable_info() override; + std::shared_ptr type() noexcept; + }; + + /** + * Procedure parameter information. + */ + class parameter_info final : public info + { + std::shared_ptr m_type; + + public: + std::ptrdiff_t offset{ 0 }; + + explicit parameter_info(std::shared_ptr type); + ~parameter_info() override; + std::shared_ptr type() const noexcept; + }; + + /** + * Intrinsic and external procedure information. + */ + class intrinsic_info : public info + { + public: + std::vector parameter_infos; + + ~intrinsic_info() override; + std::size_t parameter_stack_size() const noexcept; + }; + + /** + * Procedure information. + */ + class procedure_info final : public intrinsic_info + { + std::shared_ptr local_table; + + public: + std::size_t local_stack_size{ 0 }; + std::size_t argument_stack_size{ 0 }; + + explicit procedure_info(std::shared_ptr outer_scope); + ~procedure_info() override; + + std::shared_ptr scope(); + std::size_t stack_size() const noexcept; + }; + + /** + * Symbol table. + */ + class symbol_table + { + std::unordered_map> entries; + std::shared_ptr outer_scope; + + public: + /** + * Constructs a new symbol with an optional outer scope. + * + * \param scope Outer scope. + */ + explicit symbol_table(std::shared_ptr scope = nullptr); + + /** + * Looks for symbol in the table by name. Returns nullptr if the symbol + * can not be found. + * + * \param name Symbol name. + * \return Symbol from the table if found. + */ + std::shared_ptr lookup(const std::string& name); + + /** + * Registers new symbol. + * + * \param name Symbol name. + * \param entry Symbol information. + */ + void enter(const std::string& name, std::shared_ptr entry); + + /** + * Returns the outer scope or nullptr if the this is the global scope. + * + * \return Outer scope. + */ + std::shared_ptr scope(); + }; +} diff --git a/include/elna/source/types.hpp b/include/elna/source/types.hpp new file mode 100644 index 0000000..2e7043d --- /dev/null +++ b/include/elna/source/types.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +namespace elna::source +{ + /** + * Type representation. + */ + struct type + { + const std::size_t byte_size; + + protected: + explicit type(const std::size_t byte_size); + }; + + /** + * Built-in type representation. + */ + struct primitive_type : public type + { + const std::string type_name; + + primitive_type(const std::string& type_name, const std::size_t byte_size); + }; + + /** + * Typed pointer. + */ + struct pointer_type : public type + { + std::shared_ptr base_type; + + pointer_type(std::shared_ptr base_type, const std::size_t byte_size); + }; + + inline const primitive_type boolean_type{ "Boolean", 1 }; + inline const primitive_type int_type{ "Int", 4 }; +} diff --git a/include/elna/tester.hpp b/include/elna/tester.hpp index a9b7fd1..e483ce5 100644 --- a/include/elna/tester.hpp +++ b/include/elna/tester.hpp @@ -48,6 +48,7 @@ namespace elna boost::asio::readable_pipe& read_pipe); test_result run_for_output(boost::asio::io_context& context, const std::uint8_t stream_number, const std::filesystem::path& binary, std::initializer_list arguments); + std::string find_object(const std::vector& environment, const std::string& object); test_result build_test(boost::asio::io_context& context, const std::filesystem::directory_entry& test_entry); test_result run_test(boost::asio::io_context& context, const std::filesystem::directory_entry& test_entry); void print_result(const std::filesystem::directory_entry& test_entry, const test_result& result); diff --git a/shell/history.cpp b/shell/history.cpp deleted file mode 100644 index 986e068..0000000 --- a/shell/history.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "elna/shell/history.hpp" - -namespace elna -{ - editor_history::editor_history() - : commands{}, current_pointer(commands.cend()) - { - } - - void editor_history::push(const std::string& entry) - { - commands.push_back(entry); - current_pointer = commands.cend(); - } - - void editor_history::clear() - { - commands.clear(); - current_pointer = commands.cend(); - } - - editor_history::const_iterator editor_history::prev() noexcept - { - if (this->current_pointer != cbegin()) - { - this->current_pointer = std::prev(this->current_pointer); - } - return this->current_pointer; - } - - editor_history::const_iterator editor_history::next() noexcept - { - if (this->current_pointer != cend()) - { - this->current_pointer = std::next(this->current_pointer); - } - return this->current_pointer; - } - - editor_history::const_iterator editor_history::cbegin() const noexcept - { - return this->commands.cbegin(); - } - - editor_history::const_iterator editor_history::cend() const noexcept - { - return this->commands.cend(); - } - - editor_history::const_iterator editor_history::current() const noexcept - { - return this->current_pointer; - } -} diff --git a/shell/interactive.cpp b/shell/interactive.cpp deleted file mode 100644 index 4cca5ae..0000000 --- a/shell/interactive.cpp +++ /dev/null @@ -1,286 +0,0 @@ -#include "elna/shell/interactive.hpp" - -#include -#include -#include -#include - -namespace elna -{ - static termios original_termios; - - interactive_exception::interactive_exception() - : runtime_error("read") - { - } - - template - static std::pair read_number() - { - T position{ 0 }; - unsigned char c{ 0 }; - - while (read(STDIN_FILENO, &c, 1) == 1 && std::isdigit(c)) - { - position = position * 10 + (c - '0'); - } - return std::make_pair(position, c); - } - - void loop() - { - editor_history history; - do - { - auto line = read_line(history); - - if (!line.has_value()) - { - write(STDOUT_FILENO, "\r\n", 2); - break; - } - history.push(line.value().command_line()); - - if (!execute(line.value().command_line())) - { - break; - } - } - while (true); - } - - std::optional read_line(editor_history& history) - { - editor_state state; - std::string buffer; - std::string saved; - - state.draw(std::back_inserter(buffer)); - write(STDOUT_FILENO, buffer.data(), buffer.size()); - - while (true) - { - buffer.clear(); - auto pressed_key = read_key(); - - if (pressed_key.empty()) - { - continue; - } - switch (state.process_keypress(pressed_key)) - { - case action::finalize: - if (pressed_key == key('d', modifier::ctrl)) - { - return std::optional(); - } - else if (pressed_key == '\r') - { - write(STDOUT_FILENO, "\r\n", 2); - return std::make_optional(state); - } - break; - case action::complete: - write(STDOUT_FILENO, "\x1b[1E\x1b[2K", 8); - state.insert(complete(state.command_line(), state.relative_position())); - write(STDOUT_FILENO, "\x1b[1A", 4); - state.draw(std::back_inserter(buffer)); - write(STDOUT_FILENO, buffer.data(), buffer.size()); - break; - case action::redraw: - state.draw(std::back_inserter(buffer)); - write(STDOUT_FILENO, buffer.data(), buffer.size()); - break; - case action::write: - write(STDOUT_FILENO, &pressed_key, 1); - break; - case action::move: - buffer = cursor_to_column(state.absolute_position()); - write(STDOUT_FILENO, buffer.data(), buffer.size()); - break; - case action::ignore: - break; - case action::history: - editor_history::const_iterator history_iterator = history.cend(); - - if (pressed_key == key(special_key::arrow_up, modifier::ctrl)) - { - if (history.current() == history.cend()) - { - saved = state.command_line(); - } - history_iterator = history.prev(); - } - else if (pressed_key == key(special_key::arrow_down, modifier::ctrl)) - { - history_iterator = history.next(); - if (history_iterator == history.cend()) - { - state.load(saved); - } - } - if (history_iterator != history.cend()) - { - state.load(*history_iterator); - } - state.draw(std::back_inserter(buffer)); - write(STDOUT_FILENO, buffer.data(), buffer.size()); - break; - } - } - } - - key read_key() - { - char c{ 0 }; - - if (read(STDIN_FILENO, &c, 1) == -1 && errno != EAGAIN) - { - throw interactive_exception(); - } - if (c != '\x1b') - { - return key(c); - } - if (read(STDIN_FILENO, &c, 1) != 1 || c != '[') - { - return key(); - } - auto [number, last_char] = read_number(); - std::uint8_t modifiers{ 0 }; - - if (last_char == ';') - { - auto modifier_response = read_number(); - modifiers = modifier_response.first; - last_char = modifier_response.second; - } - if (number == 0 || number == 1) - { - switch (last_char) - { - case 'A': - return key(special_key::arrow_up, modifiers); - case 'B': - return key(special_key::arrow_down, modifiers); - case 'C': - return key(special_key::arrow_right, modifiers); - case 'D': - return key(special_key::arrow_left, modifiers); - case 'H': - return key(special_key::home_key, modifiers); - case 'F': - return key(special_key::end_key, modifiers); - } - } - else if (last_char == '~') - { - switch (number) - { - case 5: - return key(special_key::page_up, modifiers); - case 6: - return key(special_key::page_up, modifiers); - case 7: - return key(special_key::home_key, modifiers); - case 8: - return key(special_key::end_key, modifiers); - } - } - else if (last_char == 'u') - { - return key(number, modifiers); - } - return key(); - } - - void print_exception(const std::exception& exception) - { - std::string message{ exception.what() }; - message += "\r\n"; - write(STDERR_FILENO, message.data(), message.size()); - } - - bool execute(const std::string& line) - { - if (line.empty()) - { - return true; - } - if (line == "exit") - { - return false; - } - else if (boost::starts_with(line, "cd ")) - { - try - { - std::filesystem::current_path(line.substr(strlen("cd "))); - } - catch (const std::filesystem::filesystem_error& exception) - { - print_exception(exception); - } - - return true; - } - launch(line); - return true; - } - - void launch(const std::string& program) - { - try - { - boost::process::system(program); - } - catch (const boost::process::process_error& exception) - { - print_exception(exception); - } - enable_raw_mode(); - } - - bool enable_raw_mode() - { - if (tcgetattr(STDIN_FILENO, &original_termios) == -1) - { - return false; - } - termios raw = original_termios; - - raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); - raw.c_oflag &= ~(OPOST); - raw.c_cflag |= CS8; - raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); - - write(STDOUT_FILENO, start_kitty_keybaord, strlen(start_kitty_keybaord)); - - return tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) != -1; - } - - void disable_raw_mode() - { - write(STDOUT_FILENO, end_kitty_keybaord, strlen(end_kitty_keybaord)); - tcsetattr(STDIN_FILENO, TCSAFLUSH, &original_termios); - } - - std::string complete(const std::string& input, const std::size_t position) - { - std::filesystem::path program = boost::process::search_path("fzf"); - - if (program.empty()) - { - return ""; - } - boost::process::ipstream output; - boost::process::system(program, - "--height=10", "--layout=reverse", "-1", "--no-multi", - boost::process::std_out > output); - - std::string selections; - std::getline(output, selections, '\n'); - - return selections; - } -} diff --git a/shell/main.cpp b/shell/main.cpp deleted file mode 100644 index c30c4a2..0000000 --- a/shell/main.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include -#include "elna/shell/interactive.hpp" - -int main() -{ - if (!elna::enable_raw_mode()) - { - std::perror("tcsetattr"); - return EXIT_FAILURE; - } - std::atexit(elna::disable_raw_mode); - elna::loop(); - - return EXIT_SUCCESS; -} diff --git a/shell/state.cpp b/shell/state.cpp deleted file mode 100644 index 1aef61b..0000000 --- a/shell/state.cpp +++ /dev/null @@ -1,254 +0,0 @@ -#include -#include - -#include "elna/shell/state.hpp" - -namespace elna -{ - std::string cursor_to_column(const std::uint16_t position) - { - std::string code = std::to_string(position); - code.insert(0, "\x1b["); - code.push_back('G'); - - return code; - } - - key::key() - : store(0x1bu) - { - } - - key::key(const char_t c, const std::uint8_t modifiers) - : store(c), modifiers(modifiers == 0 ? 0 : modifiers - 1) - { - } - - key::key(const char_t c, const modifier modifiers) - : store(c), modifiers(static_cast(modifiers)) - { - } - - key::key(const special_key control, const std::uint8_t modifiers) - : store(control), modifiers(modifiers == 0 ? 0 : modifiers - 1) - { - } - - key::key(const special_key control, const modifier modifiers) - : store(control), modifiers(static_cast(modifiers)) - { - } - - key::char_t key::character() const - { - return std::get(this->store); - } - - special_key key::control() const - { - return std::get(this->store); - } - - bool key::modified(const std::uint8_t modifiers) const noexcept - { - return this->modifiers == modifiers; - } - - bool key::modified(const modifier modifiers) const noexcept - { - return this->modifiers == static_cast(modifiers); - } - - bool key::operator==(const char_t c) const - { - return std::holds_alternative(this->store) - && std::get(this->store) == c; - } - - bool key::operator==(const special_key control) const - { - return std::holds_alternative(this->store) - && std::get(this->store) == control; - } - - bool key::operator==(const key& that) const - { - return this->store == that.store; - } - - bool key::operator!=(const char_t c) const - { - return !(*this == c); - } - - bool key::operator!=(const special_key control) const - { - return !(*this == control); - } - - bool key::operator!=(const key& that) const - { - return !(*this == that); - } - - bool key::is_character() const noexcept - { - return std::holds_alternative(this->store); - } - - bool key::is_control() const noexcept - { - return std::holds_alternative(this->store); - } - - bool key::empty() const noexcept - { - return *this == '\x1b'; - } - - bool operator==(const special_key control, const key& that) - { - return that == control; - } - - bool operator==(const char c, const key& that) - { - return that == c; - } - - bool operator!=(const special_key control, const key& that) - { - return that != control; - } - - bool operator!=(const char c, const key& that) - { - return that != c; - } - - editor_state::editor_state() - { - this->input.reserve(1024); - } - - void editor_state::load(const std::string& text) - { - this->input = text; - this->position = this->input.size() + 1; - } - - const std::string& editor_state::command_line() const noexcept - { - return this->input; - } - - std::size_t editor_state::absolute_position() const noexcept - { - return this->prompt.size() + this->position; - } - - std::size_t editor_state::relative_position() const noexcept - { - return this->position; - } - - void editor_state::insert(const std::string& text) - { - this->input.insert(this->position - 1, text); - this->position += text.size(); - } - - void editor_state::insert(const key::char_t text) - { - if (text == 0u) - { - this->input.insert(this->position - 1, '\0', 1); - ++this->position; - return; - } - key::char_t buffer = boost::endian::native_to_big(text); - - const char *begin = reinterpret_cast(&buffer); - const char *end = begin + sizeof(key::char_t); - const char *significant = std::find_if(begin, end, - [](const char byte) { - return byte != 0; - }); - - this->input.insert(this->position - 1, significant, end - significant); - this->position += end - significant; - } - - action editor_state::process_keypress(const key& press) - { - if (press.is_control()) - { - switch (press.control()) - { - case special_key::arrow_left: - if (this->position > 1) - { - --this->position; - } - return action::move; - case special_key::arrow_right: - if (this->position + 1 < this->input.size() + this->prompt.size()) - { - ++this->position; - } - return action::move; - case special_key::arrow_up: - case special_key::arrow_down: - return action::history; - case special_key::home_key: - this->position = 1; - return action::move; - case special_key::end_key: - this->position = this->input.size() + 1; - return action::move; - default: - return action::ignore; - } - } - else if (press.modified(modifier::ctrl)) - { - switch (press.character()) - { - case 'd': - return action::finalize; - case 't': - return action::complete; - default: - return action::ignore; - } - } - else - { - switch (press.character()) - { - case 127: // Backspace. - if (this->position <= this->input.size() + 1 && this->position > 1) - { - --this->position; - this->input.erase(this->position - 1, 1); - } - return action::redraw; - case 9: // Tab. - return action::complete; - case '\r': - return action::finalize; - default: - if (this->position - 1 < input.size()) - { - insert(press.character()); - return action::redraw; - } - else - { - insert(press.character()); - return action::write; - } - } - } - } -} diff --git a/source/result.cpp b/source/result.cpp index 9d8bda0..3740254 100644 --- a/source/result.cpp +++ b/source/result.cpp @@ -1,4 +1,5 @@ #include "elna/source/result.hpp" +#include "elna/source/types.hpp" namespace elna::source { @@ -32,156 +33,4 @@ namespace elna::source { return "Name '" + name + "' was already defined"; } - - type::type(const std::size_t byte_size) - : byte_size(byte_size) - { - } - - primitive_type::primitive_type(const std::string& type_name, const std::size_t byte_size) - : type(byte_size), type_name(type_name) - { - } - - pointer_type::pointer_type(std::shared_ptr base_type, const std::size_t byte_size) - : type(byte_size), base_type(base_type) - { - } - - symbol_table::symbol_table(std::shared_ptr scope) - : outer_scope(scope) - { - if (scope == nullptr) - { - auto boolean_info = std::make_shared(boolean_type); - auto int_info = std::make_shared(int_type); - enter("Boolean", boolean_info); - enter("Int", int_info); - - auto writei = std::make_shared(); - writei->parameter_infos.emplace_back(int_info->type()); - enter("writei", writei); - - auto writeb = std::make_shared(); - writeb->parameter_infos.emplace_back(boolean_info->type()); - enter("writeb", writeb); - } - } - - std::shared_ptr symbol_table::lookup(const std::string& name) - { - auto entry = entries.find(name); - - if (entry != entries.cend()) - { - return entry->second; - } - if (this->outer_scope != nullptr) - { - return this->outer_scope->lookup(name); - } - return nullptr; - } - - void symbol_table::enter(const std::string& name, std::shared_ptr entry) - { - entries.insert_or_assign(name, entry); - } - - std::shared_ptr symbol_table::scope() - { - return this->outer_scope; - } - - info::~info() - { - } - - info::info() - { - } - - type_info::type_info(const class type& type) - : info(), m_type(std::make_shared(type)) - { - } - - type_info::~type_info() - { - } - - std::shared_ptr type_info::type() const noexcept - { - return m_type; - } - - constant_info::constant_info(const std::int32_t value) - : m_value(value) - { - } - - constant_info::~constant_info() - { - } - - std::int32_t constant_info::value() const noexcept - { - return m_value; - } - - variable_info::variable_info(std::shared_ptr type) - : m_type(type) - { - } - - variable_info::~variable_info() - { - } - - std::shared_ptr variable_info::type() noexcept - { - return m_type; - } - - parameter_info::parameter_info(std::shared_ptr type) - : m_type(type) - { - } - - parameter_info::~parameter_info() - { - } - - std::shared_ptr parameter_info::type() const noexcept - { - return m_type; - } - - intrinsic_info::~intrinsic_info() - { - } - - std::size_t intrinsic_info::parameter_stack_size() const noexcept - { - return this->parameter_infos.size() * sizeof(std::int32_t); - } - - procedure_info::procedure_info(std::shared_ptr outer_scope) - : local_table(std::make_shared(outer_scope)) - { - } - - procedure_info::~procedure_info() - { - } - - std::shared_ptr procedure_info::scope() - { - return local_table; - } - - std::size_t procedure_info::stack_size() const noexcept - { - return local_stack_size + argument_stack_size; - } } diff --git a/source/semantic.cpp b/source/semantic.cpp index 5275ccb..2b694ef 100644 --- a/source/semantic.cpp +++ b/source/semantic.cpp @@ -1,5 +1,5 @@ #include "elna/source/semantic.hpp" -#include "elna/source/result.hpp" +#include "elna/source/types.hpp" #include namespace elna::source diff --git a/source/symbol_table.cpp b/source/symbol_table.cpp new file mode 100644 index 0000000..fe6ae7e --- /dev/null +++ b/source/symbol_table.cpp @@ -0,0 +1,142 @@ +#include "elna/source/types.hpp" +#include "elna/source/symbol_table.hpp" + +namespace elna::source +{ + symbol_table::symbol_table(std::shared_ptr scope) + : outer_scope(scope) + { + if (scope == nullptr) + { + auto boolean_info = std::make_shared(boolean_type); + auto int_info = std::make_shared(int_type); + enter("Boolean", boolean_info); + enter("Int", int_info); + + auto writei = std::make_shared(); + writei->parameter_infos.emplace_back(int_info->type()); + enter("writei", writei); + + auto writeb = std::make_shared(); + writeb->parameter_infos.emplace_back(boolean_info->type()); + enter("writeb", writeb); + } + } + + std::shared_ptr symbol_table::lookup(const std::string& name) + { + auto entry = entries.find(name); + + if (entry != entries.cend()) + { + return entry->second; + } + if (this->outer_scope != nullptr) + { + return this->outer_scope->lookup(name); + } + return nullptr; + } + + void symbol_table::enter(const std::string& name, std::shared_ptr entry) + { + entries.insert_or_assign(name, entry); + } + + std::shared_ptr symbol_table::scope() + { + return this->outer_scope; + } + + info::~info() + { + } + + info::info() + { + } + + type_info::type_info(const class type& type) + : info(), m_type(std::make_shared(type)) + { + } + + type_info::~type_info() + { + } + + std::shared_ptr type_info::type() const noexcept + { + return m_type; + } + + constant_info::constant_info(const std::int32_t value) + : m_value(value) + { + } + + constant_info::~constant_info() + { + } + + std::int32_t constant_info::value() const noexcept + { + return m_value; + } + + variable_info::variable_info(std::shared_ptr type) + : m_type(type) + { + } + + variable_info::~variable_info() + { + } + + std::shared_ptr variable_info::type() noexcept + { + return m_type; + } + + parameter_info::parameter_info(std::shared_ptr type) + : m_type(type) + { + } + + parameter_info::~parameter_info() + { + } + + std::shared_ptr parameter_info::type() const noexcept + { + return m_type; + } + + intrinsic_info::~intrinsic_info() + { + } + + std::size_t intrinsic_info::parameter_stack_size() const noexcept + { + return this->parameter_infos.size() * sizeof(std::int32_t); + } + + procedure_info::procedure_info(std::shared_ptr outer_scope) + : local_table(std::make_shared(outer_scope)) + { + } + + procedure_info::~procedure_info() + { + } + + std::shared_ptr procedure_info::scope() + { + return local_table; + } + + std::size_t procedure_info::stack_size() const noexcept + { + return local_stack_size + argument_stack_size; + } +} diff --git a/source/types.cpp b/source/types.cpp new file mode 100644 index 0000000..1daa363 --- /dev/null +++ b/source/types.cpp @@ -0,0 +1,19 @@ +#include + +namespace elna::source +{ + type::type(const std::size_t byte_size) + : byte_size(byte_size) + { + } + + primitive_type::primitive_type(const std::string& type_name, const std::size_t byte_size) + : type(byte_size), type_name(type_name) + { + } + + pointer_type::pointer_type(std::shared_ptr base_type, const std::size_t byte_size) + : type(byte_size), base_type(base_type) + { + } +} diff --git a/tests/tester.cpp b/tests/tester.cpp index 284a67d..8e53b0e 100755 --- a/tests/tester.cpp +++ b/tests/tester.cpp @@ -1,6 +1,8 @@ #include "elna/tester.hpp" #include +#include +#include namespace elna { @@ -88,6 +90,22 @@ namespace elna return result; } + std::string find_object(const std::vector& environment, const std::string& object) + { + auto variable = std::find(environment.cbegin(), environment.cend(), object); + + for (const auto& variable : environment) + { + auto full_path = variable / object; + + if (std::filesystem::exists(full_path)) + { + return full_path.native(); + } + } + return object; + } + test_result build_test(boost::asio::io_context& context, const std::filesystem::directory_entry& test_entry) { const std::filesystem::path test_filename = test_entry.path().filename(); @@ -108,18 +126,24 @@ namespace elna result.status = test_status::compile_failed; return result; } - boost::process::v2::execute(boost::process::v2::process( - context, "/opt/riscv/bin/riscv32-unknown-elf-ld", - { - "-o", test_binary.string(), - "-L/opt/riscv/lib/gcc/riscv32-unknown-elf/13.2.0/", - "-L/opt/riscv/riscv32-unknown-elf/lib", - "/opt/riscv/riscv32-unknown-elf/lib/crt0.o", - "/opt/riscv/lib/gcc/riscv32-unknown-elf/13.2.0/crtbegin.o", - test_object.string(), - "--start-group", "-lgcc", "-lc", "-lgloss", "--end-group", - "/opt/riscv/lib/gcc/riscv32-unknown-elf/13.2.0/crtend.o" - } + std::vector environment; + std::vector linker_arguments = { "-o", test_binary.string() }; + + for (const auto segment : boost::this_process::environment()["LIBRARY_PATH"].to_vector()) + { + linker_arguments.push_back("-L" + segment); + environment.push_back(std::filesystem::path(segment)); + } + linker_arguments.push_back(find_object(environment, "crt0.o")); + linker_arguments.push_back(find_object(environment, "crtbegin.o")); + linker_arguments.push_back(test_object.string()); + linker_arguments.insert(linker_arguments.cend(), + { "--start-group", "-lgcc", "-lc", "-lgloss", "--end-group" }); + linker_arguments.push_back(find_object(environment, "crtend.o")); + + boost::process::v2::execute(boost::process::v2::process(context, + boost::process::search_path("ld"), + linker_arguments )); return test_result{}; }