From bcf12d19f775b3da2059065ed1932be04a006b7f Mon Sep 17 00:00:00 2001 From: bog Date: Wed, 20 Sep 2023 17:17:13 +0200 Subject: [PATCH] ADD: native function support. --- doc/grammar.bnf | 3 ++ libstd/commons.hpp | 12 ++++++++ libstd/fun.cpp | 26 +++++++++++++++++ libstd/fun.hpp | 10 +++++++ libstd/lib.cpp | 7 +++++ meson.build | 26 ++++++++++++++++- src/Compiler.cpp | 43 +++++++++++++++++++++++---- src/Compiler.hpp | 9 ++++-- src/Constant.cpp | 1 + src/Constant.hpp | 2 +- src/Lexer.cpp | 48 +++++++++++++++++++++++++++++- src/Lexer.hpp | 2 ++ src/Module.cpp | 27 +++++++++++++++++ src/Module.hpp | 9 +++++- src/NativeFunction.cpp | 19 ++++++++++++ src/NativeFunction.hpp | 26 +++++++++++++++++ src/Node.hpp | 3 +- src/Parser.cpp | 21 ++++++++++++++ src/Parser.hpp | 1 + src/Program.cpp | 6 ++++ src/Program.hpp | 1 + src/SymEntry.cpp | 26 +++++++++++++++++ src/SymEntry.hpp | 35 ++++++++++++++++++++++ src/SymTable.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++ src/SymTable.hpp | 34 ++++++++++++++++++++++ src/VM.cpp | 43 +++++++++++++++++++++++++++ src/VM.hpp | 9 ++++++ src/conf.in.hpp | 2 ++ src/opcodes.hpp | 3 +- src/types.hpp | 3 +- tests/Lexer.cpp | 25 ++++++++++++++++ tests/Parser.cpp | 6 ++++ tests/SymTable.cpp | 29 +++++++++++++++++++ 33 files changed, 568 insertions(+), 15 deletions(-) create mode 100644 libstd/commons.hpp create mode 100644 libstd/fun.cpp create mode 100644 libstd/fun.hpp create mode 100644 libstd/lib.cpp create mode 100644 src/NativeFunction.cpp create mode 100644 src/NativeFunction.hpp create mode 100644 src/SymEntry.cpp create mode 100644 src/SymEntry.hpp create mode 100644 src/SymTable.cpp create mode 100644 src/SymTable.hpp create mode 100644 tests/SymTable.cpp diff --git a/doc/grammar.bnf b/doc/grammar.bnf index a6be922..a5cbc9f 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -1,3 +1,6 @@ MODULE ::= EXPR* EXPR ::= | int | float | bool | string +| ident +| CALL +CALL opar ident EXPR* cpar diff --git a/libstd/commons.hpp b/libstd/commons.hpp new file mode 100644 index 0000000..2b48253 --- /dev/null +++ b/libstd/commons.hpp @@ -0,0 +1,12 @@ +#ifndef fkstd_COMMONS_HPP +#define fkstd_COMMONS_HPP + +#include "../src/Module.hpp" +#include "../src/Constant.hpp" + +using namespace fk; + +#define STDARGS std::vector> +#define STDRET std::shared_ptr + +#endif diff --git a/libstd/fun.cpp b/libstd/fun.cpp new file mode 100644 index 0000000..c6473e8 --- /dev/null +++ b/libstd/fun.cpp @@ -0,0 +1,26 @@ +#include "fun.hpp" + +namespace fkstd +{ + STDRET println(STDARGS args) + { + std::string sep; + + for (auto arg: args) + { + std::cout << sep << arg->string(); + sep = " "; + } + + Loc loc {"???"}; + + if (args.size() > 0) + { + loc = args.front()->loc(); + } + + std::cout << std::endl; + + return std::make_shared(TYPE_INT, 0, loc); + } +} diff --git a/libstd/fun.hpp b/libstd/fun.hpp new file mode 100644 index 0000000..fc00f91 --- /dev/null +++ b/libstd/fun.hpp @@ -0,0 +1,10 @@ +#ifndef fkstd_FUN_HPP +#define fkstd_FUN_HPP +#include "commons.hpp" + +namespace fkstd +{ + STDRET println(STDARGS args); +} + +#endif diff --git a/libstd/lib.cpp b/libstd/lib.cpp new file mode 100644 index 0000000..36b79d5 --- /dev/null +++ b/libstd/lib.cpp @@ -0,0 +1,7 @@ +#include "commons.hpp" +#include "fun.hpp" + +extern "C" void lib(Module& mod) +{ + mod.register_function("println", fkstd::println); +} diff --git a/meson.build b/meson.build index 6b3d430..4d2e546 100644 --- a/meson.build +++ b/meson.build @@ -7,10 +7,13 @@ project('fakir', 'prefix=/usr', ]) +extra_libs = get_option('prefix') / get_option('libdir') / 'fakir' + # CONFIGURATION # ============= conf = configuration_data() conf.set('version', meson.project_version()) +conf.set('libs', extra_libs) configure_file(input: 'src/conf.in.hpp', output: 'conf.hpp', @@ -25,6 +28,9 @@ fakir_cpp = [ 'src/Lexer.cpp', 'src/Parser.cpp', 'src/Constant.cpp', + 'src/NativeFunction.cpp', + 'src/SymTable.cpp', + 'src/SymEntry.cpp', 'src/Compiler.cpp', 'src/VM.cpp', @@ -38,12 +44,14 @@ fakir_hpp = [ 'src/Lexer.hpp', 'src/Parser.hpp', 'src/Constant.hpp', + 'src/SymTable.hpp', + 'src/SymEntry.hpp', 'src/Compiler.hpp', 'src/VM.hpp', 'src/Program.hpp', 'src/Module.hpp', - + 'src/NativeFunction.hpp', 'src/opcodes.hpp', 'src/commons.hpp', 'src/types.hpp', @@ -59,6 +67,21 @@ fakir_dep = declare_dependency( link_with: fakir_lib ) +# STD LIB +# ======= + +shared_library('fakir-std', + sources: [ + 'libstd/lib.cpp', + 'libstd/fun.cpp', + ], + dependencies: [ + fakir_dep + ], + install_dir: extra_libs, + install: true) + + # COMPILER # ======== executable('fakir', @@ -77,6 +100,7 @@ executable('fakir-tests', 'tests/main.cpp', 'tests/Lexer.cpp', 'tests/Parser.cpp', + 'tests/SymTable.cpp', ], dependencies: [ fakir_dep, diff --git a/src/Compiler.cpp b/src/Compiler.cpp index e57182d..38ff21f 100644 --- a/src/Compiler.cpp +++ b/src/Compiler.cpp @@ -2,7 +2,8 @@ namespace fk { - /*explicit*/ Compiler::Compiler() + /*explicit*/ Compiler::Compiler(std::shared_ptr sym) + : m_sym { sym } { } @@ -13,23 +14,55 @@ namespace fk std::shared_ptr Compiler::compile(std::shared_ptr node) { auto prog = std::make_shared(); - compile(node, prog); + compile_prog(node, prog); return prog; } - void Compiler::compile(std::shared_ptr node, - std::shared_ptr prog) + void Compiler::compile_prog(std::shared_ptr node, + std::shared_ptr prog) { switch (node->type()) { case NODE_MODULE: { for (size_t i=0; isize(); i++) { - compile(node->child(i), prog); + compile_prog(node->child(i), prog); prog->add(OP_POP); } } break; + case NODE_CALL: { + std::string ident = node->child(0)->repr(); + for (size_t i=0; isize(); i++) + { + compile_prog(node->child(i), prog); + } + + prog->add(OP_CALL_NATIVE, node->size() - 1); + } break; + + case NODE_IDENT: { + auto entry = m_sym->find(node->repr()); + + if (!entry) + { + std::stringstream ss; + ss << "'" + << node->repr() + << "' is undefined"; + + node->loc().error(LOG_ERROR, ss.str()); + } + + if (!entry->is_global()) + { + throw std::runtime_error { "not implemented yet" }; + } + + prog->add(OP_LOAD_GLOBAL, entry->addr()); + + } break; + case NODE_INT: { prog->load_const(std::make_shared(TYPE_INT, stoi(node->repr()), diff --git a/src/Compiler.hpp b/src/Compiler.hpp index ea1406a..55546e9 100644 --- a/src/Compiler.hpp +++ b/src/Compiler.hpp @@ -4,6 +4,7 @@ #include "commons.hpp" #include "Program.hpp" #include "Node.hpp" +#include "SymTable.hpp" namespace fk { @@ -12,14 +13,16 @@ namespace fk class Compiler { public: - explicit Compiler(); + explicit Compiler(std::shared_ptr sym); virtual ~Compiler(); std::shared_ptr compile(std::shared_ptr node); private: - void compile(std::shared_ptr node, - std::shared_ptr prog); + std::shared_ptr m_sym; + + void compile_prog(std::shared_ptr node, + std::shared_ptr prog); }; } diff --git a/src/Constant.cpp b/src/Constant.cpp index 73d6218..575acd9 100644 --- a/src/Constant.cpp +++ b/src/Constant.cpp @@ -21,6 +21,7 @@ namespace fk case TYPE_FLOAT: return std::to_string(std::get(m_value)); case TYPE_BOOL: return std::get(m_value) ? "true" : "false"; case TYPE_STRING: return std::get(m_value); + case TYPE_REF: return std::to_string(std::get(m_value)); default: { std::stringstream ss; diff --git a/src/Constant.hpp b/src/Constant.hpp index fadf224..1546e42 100644 --- a/src/Constant.hpp +++ b/src/Constant.hpp @@ -9,7 +9,7 @@ namespace fk { FK_ERROR(constant_error); - using constant_t = std::variant; + using constant_t = std::variant; class Constant { diff --git a/src/Lexer.cpp b/src/Lexer.cpp index 301f93c..d4990fc 100644 --- a/src/Lexer.cpp +++ b/src/Lexer.cpp @@ -7,12 +7,19 @@ namespace fk : m_loc { loc } { std::vector> text = { + {NODE_OPAR, "(", false}, + {NODE_CPAR, ")", false}, {NODE_BOOL, "true", true}, {NODE_BOOL, "false", true} }; for (auto txt: text) { + if (std::get<1>(txt).size() == 1) + { + m_separators.push_back(std::get<1>(txt)[0]); + } + m_scanners.push_back(std::bind(&Lexer::scan_text, this, std::get<1>(txt), @@ -23,6 +30,7 @@ namespace fk m_scanners.push_back(std::bind(&Lexer::scan_int, this)); m_scanners.push_back(std::bind(&Lexer::scan_float, this)); m_scanners.push_back(std::bind(&Lexer::scan_string, this)); + m_scanners.push_back(std::bind(&Lexer::scan_ident, this)); } /*virtual*/ Lexer::~Lexer() @@ -84,12 +92,25 @@ namespace fk } m_loc.error(LOG_ERROR, - "unexpected end near '" + text + "'"); + "unexpected text '" + text + "'"); } return nullptr; } + bool Lexer::is_sep(size_t index) const + { + if (index >= m_source.size() + || std::isspace(m_source[index])) + { + return true; + } + + return std::find(std::begin(m_separators), + std::end(m_separators), + m_source[index]) != std::end(m_separators); + } + void Lexer::skip_spaces() { while (m_cursor < m_source.size() @@ -227,6 +248,31 @@ namespace fk return std::nullopt; } + std::optional Lexer::scan_ident() + { + size_t cursor = m_cursor; + std::string repr; + + while (cursor < m_source.size() + && !is_sep(cursor)) + { + repr += m_source[cursor]; + cursor++; + } + + if (repr.empty() == false + && !std::isdigit(repr[0])) + { + return ScanInfo { + cursor, + NODE_IDENT, + repr + }; + } + + return std::nullopt; + } + std::optional Lexer::scan_text(std::string const& text, NodeType type, bool has_value) diff --git a/src/Lexer.hpp b/src/Lexer.hpp index f474726..4dcc439 100644 --- a/src/Lexer.hpp +++ b/src/Lexer.hpp @@ -33,11 +33,13 @@ namespace fk std::vector m_scanners; std::vector m_separators; + bool is_sep(size_t index) const; void skip_spaces(); std::optional scan_int(); std::optional scan_float(); std::optional scan_string(); + std::optional scan_ident(); std::optional scan_text(std::string const& text, NodeType type, bool has_value); diff --git a/src/Module.cpp b/src/Module.cpp index 90904e0..aebb15f 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -1,3 +1,5 @@ +#include +#include "conf.hpp" #include "Module.hpp" #include "Loc.hpp" @@ -14,6 +16,7 @@ namespace fk void Module::build() { + import_std(); m_source = load_sources(); m_ast = m_parser->parse(m_source); @@ -22,6 +25,30 @@ namespace fk m_vm->run(); } + void Module::import_std() + { + import_library(FK_LIBDIR / "libfakir-std.so"); + } + + void Module::import_library(std::filesystem::path lib_path) + { + void* handle = dlopen(lib_path.c_str(), RTLD_NOW); + assert(handle); + + typedef void(*fun)(Module&); + fun f = (fun) dlsym(handle, "lib"); + assert(f); + + f(*this); + } + + void Module::register_function(std::string const& name, native_t native) + { + auto fun = std::make_shared(native); + addr_t addr = m_vm->store_global(fun); + m_sym->declare_global(name, addr, Loc {"extern"}); + } + std::string Module::load_sources() { std::ifstream file { m_source_path }; diff --git a/src/Module.hpp b/src/Module.hpp index 5504840..a8a089f 100644 --- a/src/Module.hpp +++ b/src/Module.hpp @@ -6,6 +6,7 @@ #include "Parser.hpp" #include "Compiler.hpp" #include "VM.hpp" +#include "SymTable.hpp" namespace fk { @@ -19,13 +20,19 @@ namespace fk void build(); + void import_std(); + void import_library(std::filesystem::path lib_path); + + void register_function(std::string const& name, native_t native); + private: std::filesystem::path m_source_path; std::string m_source; Loc m_loc {m_source_path}; std::shared_ptr m_lexer = std::make_shared(m_loc); std::shared_ptr m_parser = std::make_shared(*m_lexer); - std::shared_ptr m_compiler = std::make_shared(); + std::shared_ptr m_sym = std::make_shared(); + std::shared_ptr m_compiler = std::make_shared(m_sym); std::shared_ptr m_ast; std::shared_ptr m_vm = std::make_shared(); diff --git a/src/NativeFunction.cpp b/src/NativeFunction.cpp new file mode 100644 index 0000000..f9d118f --- /dev/null +++ b/src/NativeFunction.cpp @@ -0,0 +1,19 @@ +#include "NativeFunction.hpp" + +namespace fk +{ + /*explicit*/ NativeFunction::NativeFunction(native_t native) + : m_native { native } + { + } + + /*virtual*/ NativeFunction::~NativeFunction() + { + } + + std::shared_ptr + NativeFunction::call(std::vector> args) + { + return m_native(args); + } +} diff --git a/src/NativeFunction.hpp b/src/NativeFunction.hpp new file mode 100644 index 0000000..f9e0db9 --- /dev/null +++ b/src/NativeFunction.hpp @@ -0,0 +1,26 @@ +#ifndef fk_NATIVEFUNCTION_HPP +#define fk_NATIVEFUNCTION_HPP + +#include "commons.hpp" +#include "Constant.hpp" + +namespace fk +{ + using native_t = std::function + (std::vector>)>; + + class NativeFunction + { + public: + explicit NativeFunction(native_t native); + virtual ~NativeFunction(); + + std::shared_ptr + call(std::vector> args); + + private: + native_t m_native; + }; +} + +#endif diff --git a/src/Node.hpp b/src/Node.hpp index c19d43b..72c02d1 100644 --- a/src/Node.hpp +++ b/src/Node.hpp @@ -5,7 +5,8 @@ #include "Loc.hpp" #define NODE_TYPES(G) \ - G(NODE_MODULE), G(NODE_INT), G(NODE_FLOAT), G(NODE_BOOL), G(NODE_STRING), + G(NODE_MODULE), G(NODE_INT), G(NODE_FLOAT), G(NODE_BOOL), G(NODE_STRING),\ + G(NODE_IDENT), G(NODE_OPAR), G(NODE_CPAR), G(NODE_CALL) namespace fk { diff --git a/src/Parser.cpp b/src/Parser.cpp index 23d3107..9ca24d3 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -53,6 +53,11 @@ namespace fk return consume(); } + if (type_is(NODE_OPAR)) + { + return parse_call(); + } + std::stringstream ss; ss << "unknown expression '" << (NodeTypeStr[m_tokens[m_cursor]->type()] + strlen("NODE_")) @@ -63,6 +68,22 @@ namespace fk return nullptr; } + std::shared_ptr Parser::parse_call() + { + auto node = make_node(NODE_CALL); + consume(NODE_OPAR); + node->add_child(consume(NODE_IDENT)); + + while (type_isnt(NODE_CPAR)) + { + node->add_child(parse_expr()); + } + + consume(NODE_CPAR); + + return node; + } + std::shared_ptr Parser::make_node(NodeType type) { return std::make_shared(type, "", loc()); diff --git a/src/Parser.hpp b/src/Parser.hpp index 6e23596..b1d21e9 100644 --- a/src/Parser.hpp +++ b/src/Parser.hpp @@ -22,6 +22,7 @@ namespace fk std::shared_ptr parse_module(); std::shared_ptr parse_expr(); + std::shared_ptr parse_call(); std::shared_ptr make_node(NodeType type); Loc loc() const; diff --git a/src/Program.cpp b/src/Program.cpp index 45ad0cf..31b2f9d 100644 --- a/src/Program.cpp +++ b/src/Program.cpp @@ -22,6 +22,12 @@ namespace fk return m_instrs[index]; } + std::shared_ptr Program::get_const(addr_t addr) const + { + assert(addr < const_size()); + return m_consts[addr]; + } + size_t Program::add(std::shared_ptr constant) { for (size_t i=0; i get_const(addr_t addr) const; size_t add(std::shared_ptr constant); diff --git a/src/SymEntry.cpp b/src/SymEntry.cpp new file mode 100644 index 0000000..73cf759 --- /dev/null +++ b/src/SymEntry.cpp @@ -0,0 +1,26 @@ +#include "SymEntry.hpp" + +namespace fk +{ + /*explicit*/ SymEntry::SymEntry(std::string const& name, + addr_t addr, + bool is_global, + Loc const& loc) + : m_name { name } + , m_addr { addr } + , m_is_global { is_global } + , m_loc { loc } + { + } + + /*virtual*/ SymEntry::~SymEntry() + { + } + + std::string SymEntry::string() const + { + std::stringstream ss; + ss << m_name << "\t" << m_addr << "\t" << m_is_global; + return ss.str(); + } +} diff --git a/src/SymEntry.hpp b/src/SymEntry.hpp new file mode 100644 index 0000000..73f92b7 --- /dev/null +++ b/src/SymEntry.hpp @@ -0,0 +1,35 @@ +#ifndef fk_SYMENTRY_HPP +#define fk_SYMENTRY_HPP + +#include "commons.hpp" +#include "Loc.hpp" + +namespace fk +{ + class SymEntry + { + public: + explicit SymEntry(std::string const& name, + addr_t addr, + bool is_global, + Loc const& loc); + virtual ~SymEntry(); + + std::string name() const { return m_name; } + addr_t addr() const { return m_addr; } + bool is_global() const { return m_is_global; } + Loc loc() const { return m_loc; } + + void set_global(bool global) { m_is_global = global; } + + std::string string() const; + + private: + std::string m_name; + addr_t m_addr; + bool m_is_global = false; + Loc m_loc; + }; +} + +#endif diff --git a/src/SymTable.cpp b/src/SymTable.cpp new file mode 100644 index 0000000..ab1a49b --- /dev/null +++ b/src/SymTable.cpp @@ -0,0 +1,66 @@ +#include "SymTable.hpp" +#include "src/Loc.hpp" + +namespace fk +{ + /*explicit*/ SymTable::SymTable() + { + } + + /*virtual*/ SymTable::~SymTable() + { + } + + void SymTable::declare_local(std::string const& name, + addr_t addr, + Loc const& loc) + { + auto entry = find(name); + + if (entry) + { + std::stringstream ss; + ss << "cannot declare existing variable '" + << name + << "'"; + + entry->loc().error(LOG_ERROR, ss.str()); + } + + m_entries.push_back(SymEntry {name, addr, false, loc}); + } + + void SymTable::declare_global(std::string const& name, + addr_t addr, + Loc const& loc) + { + declare_local(name, addr, loc); + m_entries.back().set_global(true); + } + + std::optional SymTable::find(std::string const& name) + { + for (auto& entry: m_entries) + { + if (entry.name() == name) + { + return entry; + } + } + + return std::nullopt; + } + + std::string SymTable::string() const + { + std::stringstream ss; + + ss << "======== SymTable ========\n"; + for (auto const& entry: m_entries) + { + ss << entry.string() << std::endl; + } + + return ss.str(); + } +} diff --git a/src/SymTable.hpp b/src/SymTable.hpp new file mode 100644 index 0000000..2ffcdb3 --- /dev/null +++ b/src/SymTable.hpp @@ -0,0 +1,34 @@ +#ifndef fk_SYMTABLE_HPP +#define fk_SYMTABLE_HPP + +#include "commons.hpp" +#include "SymEntry.hpp" + +namespace fk +{ + FK_ERROR(symbol_error); + + class SymTable + { + public: + explicit SymTable(); + virtual ~SymTable(); + + void declare_local(std::string const& name, + addr_t addr, + Loc const& loc); + + void declare_global(std::string const& name, + addr_t addr, + Loc const& loc); + + std::optional find(std::string const& name); + + std::string string() const; + + private: + std::vector m_entries; + }; +} + +#endif diff --git a/src/VM.cpp b/src/VM.cpp index 8ba3275..ee59e8d 100644 --- a/src/VM.cpp +++ b/src/VM.cpp @@ -25,6 +25,32 @@ namespace fk switch (instr.opcode) { + case OP_CALL_NATIVE: { + std::vector> args; + + for (size_t i=0; iget_const(pop())); + } + + auto ref = std::get(frame().program + ->get_const(pop())->value()); + auto fun = std::get> + (load_global(ref)); + + push(frame().program->add(fun->call(args))); + + m_pc++; + } break; + + case OP_LOAD_GLOBAL: { + auto ref = std::make_shared(TYPE_REF, + (size_t) instr.param, + Loc {"???"}); + push(frame().program->add(ref)); + m_pc++; + } break; case OP_LOAD_CONST: { push(instr.param); @@ -46,6 +72,23 @@ namespace fk } } + global_t VM::load_global(addr_t addr) const + { + return m_globals.at(addr); + } + + void VM::store_global(addr_t addr, global_t value) + { + m_globals[addr] = value; + } + + size_t VM::store_global(global_t value) + { + addr_t addr = m_globals.size(); + store_global(addr, value); + return addr; + } + std::string VM::string() const { std::stringstream ss; diff --git a/src/VM.hpp b/src/VM.hpp index 62bb578..78a7089 100644 --- a/src/VM.hpp +++ b/src/VM.hpp @@ -3,9 +3,12 @@ #include "commons.hpp" #include "Program.hpp" +#include "NativeFunction.hpp" namespace fk { + using global_t = std::variant>; + struct Frame { std::shared_ptr program; }; @@ -21,11 +24,17 @@ namespace fk void mount(std::shared_ptr program); void run(); + global_t load_global(addr_t addr) const; + void store_global(addr_t addr, global_t value); + size_t store_global(global_t value); + std::string string() const; + private: addr_t m_pc = 0; std::vector m_frames; std::vector m_stack; + std::unordered_map m_globals; void push(addr_t addr); addr_t top(); diff --git a/src/conf.in.hpp b/src/conf.in.hpp index d3f8c8e..bb31355 100644 --- a/src/conf.in.hpp +++ b/src/conf.in.hpp @@ -1,6 +1,8 @@ #ifndef fk_CONF_HPP #define fk_CONF_HPP +#include #define FK_VERSION "@version@" +#define FK_LIBDIR std::filesystem::path("@libs@") #endif diff --git a/src/opcodes.hpp b/src/opcodes.hpp index 4e22c96..6e18880 100644 --- a/src/opcodes.hpp +++ b/src/opcodes.hpp @@ -1,7 +1,8 @@ #ifndef fk_OPCODES_HPP #define fk_OPCODES_HPP -#define OPCODES(G) G(OP_LOAD_CONST), G(OP_POP) +#define OPCODES(G) G(OP_LOAD_CONST), G(OP_POP), G(OP_CALL_NATIVE), \ + G(OP_LOAD_GLOBAL) #include "commons.hpp" diff --git a/src/types.hpp b/src/types.hpp index f99ce2a..7fb0ced 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -3,7 +3,8 @@ #include "commons.hpp" -#define TYPES(G) G(TYPE_INT), G(TYPE_FLOAT), G(TYPE_BOOL), G(TYPE_STRING) +#define TYPES(G) G(TYPE_INT), G(TYPE_FLOAT), G(TYPE_BOOL), G(TYPE_STRING), \ + G(TYPE_REF) namespace fk { diff --git a/tests/Lexer.cpp b/tests/Lexer.cpp index 19a4f61..b56f6e1 100644 --- a/tests/Lexer.cpp +++ b/tests/Lexer.cpp @@ -63,3 +63,28 @@ TEST_CASE_METHOD(LexerTest, "Lexer_string") test_next("STRING['false']"); test_end(); } + +TEST_CASE_METHOD(LexerTest, "Lexer_ident") +{ + m_lexer.scan(" odd? hello-world! Aze06 _gdb "); + + test_next("IDENT[odd?]"); + test_next("IDENT[hello-world!]"); + test_next("IDENT[Aze06]"); + test_next("IDENT[_gdb]"); + + test_end(); +} + +TEST_CASE_METHOD(LexerTest, "Lexer_parenthesis") +{ + m_lexer.scan(" () (aze) "); + + test_next("OPAR"); + test_next("CPAR"); + + test_next("OPAR"); + test_next("IDENT[aze]"); + test_next("CPAR"); + test_end(); +} diff --git a/tests/Parser.cpp b/tests/Parser.cpp index 2763ad8..909f4e9 100644 --- a/tests/Parser.cpp +++ b/tests/Parser.cpp @@ -29,3 +29,9 @@ TEST_CASE_METHOD(ParserTest, "Parser_builtins") test_parse("MODULE(INT[4],FLOAT[3.0],BOOL[false],STRING['salut'])", "4 3. false 'salut'"); } + +TEST_CASE_METHOD(ParserTest, "Parser_call") +{ + test_parse("MODULE(CALL(IDENT[bim],INT[2],STRING['3'],BOOL[false]))", + " (bim 2 '3' false) "); +} diff --git a/tests/SymTable.cpp b/tests/SymTable.cpp new file mode 100644 index 0000000..5aa9960 --- /dev/null +++ b/tests/SymTable.cpp @@ -0,0 +1,29 @@ +#include +#include "../src/SymTable.hpp" + +class SymTableTest +{ +public: + explicit SymTableTest() {} + virtual ~SymTableTest() {} + +protected: + fk::Loc m_loc {"tests/symtable"}; + fk::SymTable m_sym; +}; + +TEST_CASE_METHOD(SymTableTest, "SymTable_declare_var") +{ + REQUIRE(std::nullopt == m_sym.find("hello")); + + m_sym.declare_local("hello", 404, m_loc); + auto entry = m_sym.find("hello"); + + REQUIRE(std::nullopt != entry); + REQUIRE("hello" == entry->name()); + REQUIRE(404 == entry->addr()); + REQUIRE(false == entry->is_global()); + + REQUIRE_THROWS_AS(m_sym.declare_local("hello", 407, m_loc), + fk::symbol_error); +}