Split result into symboltable and types
This commit is contained in:
		@@ -14,16 +14,11 @@ target_include_directories(tester PRIVATE include)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
FLEX_TARGET(scanner source/scanner.l ${CMAKE_CURRENT_BINARY_DIR}/scanner.cpp)
 | 
					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
 | 
					add_executable(elna cli/main.cpp
 | 
				
			||||||
	source/lexer.cpp include/elna/source/lexer.hpp
 | 
						source/lexer.cpp include/elna/source/lexer.hpp
 | 
				
			||||||
	source/parser.cpp include/elna/source/parser.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/result.cpp include/elna/source/result.hpp
 | 
				
			||||||
	source/semantic.cpp include/elna/source/semantic.hpp
 | 
						source/semantic.cpp include/elna/source/semantic.hpp
 | 
				
			||||||
	source/optimizer.cpp include/elna/source/optimizer.hpp
 | 
						source/optimizer.cpp include/elna/source/optimizer.hpp
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								TODO
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								TODO
									
									
									
									
									
								
							@@ -12,14 +12,5 @@
 | 
				
			|||||||
- Syscalls.
 | 
					- Syscalls.
 | 
				
			||||||
- Error message with an empty file wrongly says that a ")" is expected.
 | 
					- Error message with an empty file wrongly says that a ")" is expected.
 | 
				
			||||||
- Support any expressions for constants.
 | 
					- Support any expressions for constants.
 | 
				
			||||||
 | 
					- Built-in types are added in the symbol table constructor. It would be better to
 | 
				
			||||||
# Shell
 | 
					  add them outside, before the type analysis begins.
 | 
				
			||||||
- 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.
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -155,6 +155,7 @@ namespace elna::riscv
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        writer.set_os_abi(ELFIO::ELFOSABI_NONE);
 | 
					        writer.set_os_abi(ELFIO::ELFOSABI_NONE);
 | 
				
			||||||
        writer.set_type(ELFIO::ET_REL);
 | 
					        writer.set_type(ELFIO::ET_REL);
 | 
				
			||||||
 | 
					        writer.set_flags(0x4); // EF_RISCV_FLOAT_ABI_DOUBLE
 | 
				
			||||||
        writer.set_machine(ELFIO::EM_RISCV);
 | 
					        writer.set_machine(ELFIO::EM_RISCV);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Create code section
 | 
					        // Create code section
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,28 +0,0 @@
 | 
				
			|||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <boost/core/noncopyable.hpp>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <list>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace elna
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    struct editor_history : public boost::noncopyable
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        using const_iterator = std::list<std::string>::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<std::string> commands;
 | 
					 | 
				
			||||||
        std::list<std::string>::const_iterator current_pointer;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,89 +0,0 @@
 | 
				
			|||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <boost/core/noncopyable.hpp>
 | 
					 | 
				
			||||||
#include <stdexcept>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <optional>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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<editor_state> 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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,170 +0,0 @@
 | 
				
			|||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <cstring>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <variant>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace elna
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    constexpr const char *erase_line = "\x1b[2K";
 | 
					 | 
				
			||||||
    constexpr const char *start_kitty_keybaord = "\x1b[>1u";
 | 
					 | 
				
			||||||
    constexpr const char *end_kitty_keybaord = "\x1b[<u";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::string cursor_to_column(const std::uint16_t position = 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    enum class special_key
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        arrow_left,
 | 
					 | 
				
			||||||
        arrow_right,
 | 
					 | 
				
			||||||
        arrow_up,
 | 
					 | 
				
			||||||
        arrow_down,
 | 
					 | 
				
			||||||
        page_up,
 | 
					 | 
				
			||||||
        page_down,
 | 
					 | 
				
			||||||
        home_key,
 | 
					 | 
				
			||||||
        end_key,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Key modifiers.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    enum class modifier : std::uint8_t
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        shift = 0b1, ///< 1
 | 
					 | 
				
			||||||
        alt = 0b10, ///< 2
 | 
					 | 
				
			||||||
        ctrl = 0b100, ///< 4
 | 
					 | 
				
			||||||
        super = 0b1000, ///< 8
 | 
					 | 
				
			||||||
        hyper = 0b10000, ///< 16
 | 
					 | 
				
			||||||
        meta = 0b100000, ///< 32
 | 
					 | 
				
			||||||
        caps_lock = 0b1000000, ///< 64
 | 
					 | 
				
			||||||
        num_lock = 0b10000000, ///< 128
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct key
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        using char_t = std::uint32_t;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        key();
 | 
					 | 
				
			||||||
        explicit key(const char_t c, const std::uint8_t modifiers = 0);
 | 
					 | 
				
			||||||
        explicit key(const char_t c, const modifier modifiers);
 | 
					 | 
				
			||||||
        explicit key(const special_key control, const std::uint8_t modifiers = 0);
 | 
					 | 
				
			||||||
        explicit key(const special_key control, const modifier modifiers);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bool operator==(const char_t c) const;
 | 
					 | 
				
			||||||
        friend bool operator==(const char_t c, const key& that);
 | 
					 | 
				
			||||||
        bool operator==(const special_key control) const;
 | 
					 | 
				
			||||||
        friend bool operator==(const special_key control, const key& that);
 | 
					 | 
				
			||||||
        bool operator==(const key& that) const;
 | 
					 | 
				
			||||||
        bool operator!=(const char_t c) const;
 | 
					 | 
				
			||||||
        friend bool operator!=(const char_t c, const key& that);
 | 
					 | 
				
			||||||
        bool operator!=(const special_key control) const;
 | 
					 | 
				
			||||||
        friend bool operator!=(const special_key control, const key& that);
 | 
					 | 
				
			||||||
        bool operator!=(const key& that) const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        char_t character() const;
 | 
					 | 
				
			||||||
        special_key control() const;
 | 
					 | 
				
			||||||
        bool modified(const std::uint8_t modifiers) const noexcept;
 | 
					 | 
				
			||||||
        bool modified(const modifier modifiers) const noexcept;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bool is_character() const noexcept;
 | 
					 | 
				
			||||||
        bool is_control() const noexcept;
 | 
					 | 
				
			||||||
        bool empty() const noexcept;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private:
 | 
					 | 
				
			||||||
        std::variant<special_key, char_t> 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<typename T>
 | 
					 | 
				
			||||||
        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);
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <unordered_map>
 | 
				
			||||||
#include "elna/source/parser.hpp"
 | 
					#include "elna/source/parser.hpp"
 | 
				
			||||||
 | 
					#include "elna/source/symbol_table.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace elna::source
 | 
					namespace elna::source
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,12 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <cstddef>
 | 
					#include <cstddef>
 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					#include <filesystem>
 | 
				
			||||||
#include <variant>
 | 
					#include <variant>
 | 
				
			||||||
#include <list>
 | 
					#include <list>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <type_traits>
 | 
					#include <type_traits>
 | 
				
			||||||
#include <unordered_map>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace elna::source
 | 
					namespace elna::source
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -126,181 +123,6 @@ namespace elna::source
 | 
				
			|||||||
        std::string what() const override;
 | 
					        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<const type> base_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        pointer_type(std::shared_ptr<const type> 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<class type> m_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        explicit type_info(const class type& type);
 | 
					 | 
				
			||||||
        ~type_info() override;
 | 
					 | 
				
			||||||
        std::shared_ptr<const class type> 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<const class type> m_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        std::ptrdiff_t offset{ 0 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        explicit variable_info(std::shared_ptr<const class type> type);
 | 
					 | 
				
			||||||
        ~variable_info() override;
 | 
					 | 
				
			||||||
        std::shared_ptr<const class type> type() noexcept;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Procedure parameter information.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    class parameter_info final : public info
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::shared_ptr<const class type> m_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        std::ptrdiff_t offset{ 0 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        explicit parameter_info(std::shared_ptr<const class type> type);
 | 
					 | 
				
			||||||
        ~parameter_info() override;
 | 
					 | 
				
			||||||
        std::shared_ptr<const class type> type() const noexcept;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Intrinsic and external procedure information.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    class intrinsic_info : public info
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        std::vector<parameter_info> 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<symbol_table> local_table;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        std::size_t local_stack_size{ 0 };
 | 
					 | 
				
			||||||
        std::size_t argument_stack_size{ 0 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        explicit procedure_info(std::shared_ptr<symbol_table> outer_scope);
 | 
					 | 
				
			||||||
        ~procedure_info() override;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::shared_ptr<symbol_table> scope();
 | 
					 | 
				
			||||||
        std::size_t stack_size() const noexcept;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Symbol table.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    class symbol_table
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::unordered_map<std::string, std::shared_ptr<info>> entries;
 | 
					 | 
				
			||||||
        std::shared_ptr<symbol_table> outer_scope;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        /**
 | 
					 | 
				
			||||||
         * Constructs a new symbol with an optional outer scope.
 | 
					 | 
				
			||||||
         *
 | 
					 | 
				
			||||||
         * \param scope Outer scope.
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        explicit symbol_table(std::shared_ptr<symbol_table> 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<info> 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<info> entry);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /**
 | 
					 | 
				
			||||||
         * Returns the outer scope or nullptr if the this is the global scope.
 | 
					 | 
				
			||||||
         *
 | 
					 | 
				
			||||||
         * \return Outer scope.
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        std::shared_ptr<symbol_table> scope();
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    template<typename T>
 | 
					    template<typename T>
 | 
				
			||||||
    struct writer
 | 
					    struct writer
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "elna/source/parser.hpp"
 | 
					#include "elna/source/parser.hpp"
 | 
				
			||||||
 | 
					#include "elna/source/symbol_table.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace elna::source
 | 
					namespace elna::source
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										151
									
								
								include/elna/source/symbol_table.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								include/elna/source/symbol_table.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,151 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					#include <unordered_map>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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<class type> m_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        explicit type_info(const class type& type);
 | 
				
			||||||
 | 
					        ~type_info() override;
 | 
				
			||||||
 | 
					        std::shared_ptr<const class type> 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<const class type> m_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        std::ptrdiff_t offset{ 0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        explicit variable_info(std::shared_ptr<const class type> type);
 | 
				
			||||||
 | 
					        ~variable_info() override;
 | 
				
			||||||
 | 
					        std::shared_ptr<const class type> type() noexcept;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Procedure parameter information.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    class parameter_info final : public info
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::shared_ptr<const class type> m_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        std::ptrdiff_t offset{ 0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        explicit parameter_info(std::shared_ptr<const class type> type);
 | 
				
			||||||
 | 
					        ~parameter_info() override;
 | 
				
			||||||
 | 
					        std::shared_ptr<const class type> type() const noexcept;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Intrinsic and external procedure information.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    class intrinsic_info : public info
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        std::vector<parameter_info> 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<symbol_table> local_table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        std::size_t local_stack_size{ 0 };
 | 
				
			||||||
 | 
					        std::size_t argument_stack_size{ 0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        explicit procedure_info(std::shared_ptr<symbol_table> outer_scope);
 | 
				
			||||||
 | 
					        ~procedure_info() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::shared_ptr<symbol_table> scope();
 | 
				
			||||||
 | 
					        std::size_t stack_size() const noexcept;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Symbol table.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    class symbol_table
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::unordered_map<std::string, std::shared_ptr<info>> entries;
 | 
				
			||||||
 | 
					        std::shared_ptr<symbol_table> outer_scope;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Constructs a new symbol with an optional outer scope.
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * \param scope Outer scope.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        explicit symbol_table(std::shared_ptr<symbol_table> 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<info> 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<info> entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Returns the outer scope or nullptr if the this is the global scope.
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * \return Outer scope.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        std::shared_ptr<symbol_table> scope();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										41
									
								
								include/elna/source/types.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								include/elna/source/types.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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<const type> base_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pointer_type(std::shared_ptr<const type> base_type, const std::size_t byte_size);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline const primitive_type boolean_type{ "Boolean", 1 };
 | 
				
			||||||
 | 
					    inline const primitive_type int_type{ "Int", 4 };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -48,6 +48,7 @@ namespace elna
 | 
				
			|||||||
            boost::asio::readable_pipe& read_pipe);
 | 
					            boost::asio::readable_pipe& read_pipe);
 | 
				
			||||||
    test_result run_for_output(boost::asio::io_context& context, const std::uint8_t stream_number,
 | 
					    test_result run_for_output(boost::asio::io_context& context, const std::uint8_t stream_number,
 | 
				
			||||||
            const std::filesystem::path& binary, std::initializer_list<boost::string_view> arguments);
 | 
					            const std::filesystem::path& binary, std::initializer_list<boost::string_view> arguments);
 | 
				
			||||||
 | 
					    std::string find_object(const std::vector<std::filesystem::path>& environment, const std::string& object);
 | 
				
			||||||
    test_result build_test(boost::asio::io_context& context, const std::filesystem::directory_entry& test_entry);
 | 
					    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);
 | 
					    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);
 | 
					    void print_result(const std::filesystem::directory_entry& test_entry, const test_result& result);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,286 +0,0 @@
 | 
				
			|||||||
#include "elna/shell/interactive.hpp"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <boost/algorithm/string/predicate.hpp>
 | 
					 | 
				
			||||||
#include <boost/process.hpp>
 | 
					 | 
				
			||||||
#include <termios.h>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace elna
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    static termios original_termios;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    interactive_exception::interactive_exception()
 | 
					 | 
				
			||||||
        : runtime_error("read")
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    template<typename T>
 | 
					 | 
				
			||||||
    static std::pair<T, unsigned char> 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<editor_state> 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<editor_state>();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    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<key::char_t>();
 | 
					 | 
				
			||||||
        std::uint8_t modifiers{ 0 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (last_char == ';')
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            auto modifier_response = read_number<std::uint8_t>();
 | 
					 | 
				
			||||||
            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;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,16 +0,0 @@
 | 
				
			|||||||
#include <cstdlib>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										254
									
								
								shell/state.cpp
									
									
									
									
									
								
							
							
						
						
									
										254
									
								
								shell/state.cpp
									
									
									
									
									
								
							@@ -1,254 +0,0 @@
 | 
				
			|||||||
#include <algorithm>
 | 
					 | 
				
			||||||
#include <boost/endian.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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<uint8_t>(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<uint8_t>(modifiers))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    key::char_t key::character() const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return std::get<char_t>(this->store);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    special_key key::control() const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return std::get<special_key>(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<std::uint8_t>(modifiers);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool key::operator==(const char_t c) const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return std::holds_alternative<char_t>(this->store)
 | 
					 | 
				
			||||||
            && std::get<char_t>(this->store) == c;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool key::operator==(const special_key control) const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return std::holds_alternative<special_key>(this->store)
 | 
					 | 
				
			||||||
            && std::get<special_key>(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<char_t>(this->store);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool key::is_control() const noexcept
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return std::holds_alternative<special_key>(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<key::char_t>(text);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const char *begin = reinterpret_cast<char *>(&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;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
#include "elna/source/result.hpp"
 | 
					#include "elna/source/result.hpp"
 | 
				
			||||||
 | 
					#include "elna/source/types.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace elna::source
 | 
					namespace elna::source
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -32,156 +33,4 @@ namespace elna::source
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return "Name '" + name + "' was already defined";
 | 
					        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<const type> base_type, const std::size_t byte_size)
 | 
					 | 
				
			||||||
        : type(byte_size), base_type(base_type)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    symbol_table::symbol_table(std::shared_ptr<symbol_table> scope)
 | 
					 | 
				
			||||||
        : outer_scope(scope)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (scope == nullptr)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            auto boolean_info = std::make_shared<type_info>(boolean_type);
 | 
					 | 
				
			||||||
            auto int_info = std::make_shared<type_info>(int_type);
 | 
					 | 
				
			||||||
            enter("Boolean", boolean_info);
 | 
					 | 
				
			||||||
            enter("Int", int_info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            auto writei = std::make_shared<intrinsic_info>();
 | 
					 | 
				
			||||||
            writei->parameter_infos.emplace_back(int_info->type());
 | 
					 | 
				
			||||||
            enter("writei", writei);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            auto writeb = std::make_shared<intrinsic_info>();
 | 
					 | 
				
			||||||
            writeb->parameter_infos.emplace_back(boolean_info->type());
 | 
					 | 
				
			||||||
            enter("writeb", writeb);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::shared_ptr<info> 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<info> entry)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        entries.insert_or_assign(name, entry);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::shared_ptr<symbol_table> 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<class type>(type))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    type_info::~type_info()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::shared_ptr<const class type> 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<const class type> type)
 | 
					 | 
				
			||||||
        : m_type(type)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    variable_info::~variable_info()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::shared_ptr<const class type> variable_info::type() noexcept
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return m_type;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    parameter_info::parameter_info(std::shared_ptr<const class type> type)
 | 
					 | 
				
			||||||
        : m_type(type)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    parameter_info::~parameter_info()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::shared_ptr<const class type> 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<symbol_table> outer_scope)
 | 
					 | 
				
			||||||
        : local_table(std::make_shared<symbol_table>(outer_scope))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    procedure_info::~procedure_info()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::shared_ptr<symbol_table> procedure_info::scope()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return local_table;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::size_t procedure_info::stack_size() const noexcept
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return local_stack_size + argument_stack_size;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
#include "elna/source/semantic.hpp"
 | 
					#include "elna/source/semantic.hpp"
 | 
				
			||||||
#include "elna/source/result.hpp"
 | 
					#include "elna/source/types.hpp"
 | 
				
			||||||
#include <cstdlib>
 | 
					#include <cstdlib>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace elna::source
 | 
					namespace elna::source
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										142
									
								
								source/symbol_table.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								source/symbol_table.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -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<symbol_table> scope)
 | 
				
			||||||
 | 
					        : outer_scope(scope)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (scope == nullptr)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            auto boolean_info = std::make_shared<type_info>(boolean_type);
 | 
				
			||||||
 | 
					            auto int_info = std::make_shared<type_info>(int_type);
 | 
				
			||||||
 | 
					            enter("Boolean", boolean_info);
 | 
				
			||||||
 | 
					            enter("Int", int_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            auto writei = std::make_shared<intrinsic_info>();
 | 
				
			||||||
 | 
					            writei->parameter_infos.emplace_back(int_info->type());
 | 
				
			||||||
 | 
					            enter("writei", writei);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            auto writeb = std::make_shared<intrinsic_info>();
 | 
				
			||||||
 | 
					            writeb->parameter_infos.emplace_back(boolean_info->type());
 | 
				
			||||||
 | 
					            enter("writeb", writeb);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::shared_ptr<info> 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<info> entry)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        entries.insert_or_assign(name, entry);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::shared_ptr<symbol_table> 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<class type>(type))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    type_info::~type_info()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::shared_ptr<const class type> 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<const class type> type)
 | 
				
			||||||
 | 
					        : m_type(type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    variable_info::~variable_info()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::shared_ptr<const class type> variable_info::type() noexcept
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return m_type;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parameter_info::parameter_info(std::shared_ptr<const class type> type)
 | 
				
			||||||
 | 
					        : m_type(type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parameter_info::~parameter_info()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::shared_ptr<const class type> 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<symbol_table> outer_scope)
 | 
				
			||||||
 | 
					        : local_table(std::make_shared<symbol_table>(outer_scope))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    procedure_info::~procedure_info()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::shared_ptr<symbol_table> procedure_info::scope()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return local_table;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::size_t procedure_info::stack_size() const noexcept
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return local_stack_size + argument_stack_size;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								source/types.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								source/types.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					#include <elna/source/types.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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<const type> base_type, const std::size_t byte_size)
 | 
				
			||||||
 | 
					        : type(byte_size), base_type(base_type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
#include "elna/tester.hpp"
 | 
					#include "elna/tester.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <boost/process/env.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace elna
 | 
					namespace elna
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -88,6 +90,22 @@ namespace elna
 | 
				
			|||||||
        return result;
 | 
					        return result;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::string find_object(const std::vector<std::filesystem::path>& 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)
 | 
					    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();
 | 
					        const std::filesystem::path test_filename = test_entry.path().filename();
 | 
				
			||||||
@@ -108,18 +126,24 @@ namespace elna
 | 
				
			|||||||
            result.status = test_status::compile_failed;
 | 
					            result.status = test_status::compile_failed;
 | 
				
			||||||
            return result;
 | 
					            return result;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        boost::process::v2::execute(boost::process::v2::process(
 | 
					        std::vector<std::filesystem::path> environment;
 | 
				
			||||||
                    context, "/opt/riscv/bin/riscv32-unknown-elf-ld",
 | 
					        std::vector<std::string> linker_arguments = { "-o", test_binary.string() };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (const auto segment : boost::this_process::environment()["LIBRARY_PATH"].to_vector())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
                        "-o", test_binary.string(),
 | 
					            linker_arguments.push_back("-L" + segment);
 | 
				
			||||||
                        "-L/opt/riscv/lib/gcc/riscv32-unknown-elf/13.2.0/",
 | 
					            environment.push_back(std::filesystem::path(segment));
 | 
				
			||||||
                        "-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"
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        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{};
 | 
					        return test_result{};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user