diff --git a/compiler/CMakeLists.txt b/compiler/CMakeLists.txt index bf37d8e..1e8dd60 100644 --- a/compiler/CMakeLists.txt +++ b/compiler/CMakeLists.txt @@ -1,9 +1,16 @@ add_library(caioc_compiler STATIC + parser.cxx ) target_sources(caioc_compiler PUBLIC FILE_SET caioc_compiler_modules TYPE CXX_MODULES FILES + declaration.ixx + expression.ixx + parser.ixx + program.ixx + statement.ixx token.ixx + ) target_compile_options(caioc_compiler PUBLIC -freflection -fcontracts -fcontract-evaluation-semantic=enforce) diff --git a/compiler/declaration.ixx b/compiler/declaration.ixx index e69de29..b2c9c77 100644 --- a/compiler/declaration.ixx +++ b/compiler/declaration.ixx @@ -0,0 +1,58 @@ +export module caioc.declaration; + +import std; + +import caioc.statement; +import caioc.expression; + +namespace caioc { + +export struct declaration { + virtual ~declaration() = default; +}; + +export struct function_declaration : declaration { + struct argument { + std::string name; + std::string type_name; + }; + + std::string name; + std::vector arguments; + std::string return_type; + std::unique_ptr body; +}; + +} // namespace caioc + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + auto format(const caioc::function_declaration& d, std::format_context& ctx) const { + auto out = std::format_to(ctx.out(), "Function({}, args: [", d.name); + bool first = true; + for (const auto& arg : d.arguments) { + if (!first) { + out = std::format_to(out, ", "); + } + first = false; + out = std::format_to(out, "{}", arg); + } + out = std::format_to(out, "], return_type: {}", d.return_type); + out = d.body ? std::format_to(out, ", body: {}", *d.body) : std::format_to(out, ", body: "); + return std::format_to(out, ")"); + } +}; + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + auto format(const caioc::declaration& d, std::format_context& ctx) const { + if (auto* p = dynamic_cast(&d)) { + return std::format_to(ctx.out(), "{}", *p); + } + return std::format_to(ctx.out(), ""); + } +}; diff --git a/compiler/expression.ixx b/compiler/expression.ixx index 8aa44df..84fd57f 100644 --- a/compiler/expression.ixx +++ b/compiler/expression.ixx @@ -5,7 +5,7 @@ import std; namespace caioc { export struct expression { - virtual expression() = default; + virtual ~expression() = default; }; export struct int_literal_expression : expression { @@ -20,7 +20,7 @@ export struct string_literal_expression : expression { export struct identifier_expression : expression { std::string name; -} +}; export struct call_expression : expression { std::unique_ptr callee; @@ -28,3 +28,84 @@ export struct call_expression : expression { }; } // namespace caioc + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + auto format(const caioc::int_literal_expression& e, std::format_context& ctx) const { + return std::format_to(ctx.out(), "IntLiteral({})", e.value); + } +}; + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + auto format(const caioc::bool_literal_expression& e, std::format_context& ctx) const { + return std::format_to(ctx.out(), "BoolLiteral({})", e.value); + } +}; + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + auto format(const caioc::string_literal_expression& e, std::format_context& ctx) const { + return std::format_to(ctx.out(), "StringLiteral(\"{}\")", e.value); + } +}; + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + auto format(const caioc::identifier_expression& e, std::format_context& ctx) const { + return std::format_to(ctx.out(), "Identifier({})", e.name); + } +}; + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + std::format_context::iterator format(const caioc::expression& e, std::format_context& ctx) const; +}; + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + std::format_context::iterator format(const caioc::call_expression& e, std::format_context& ctx) const; +}; + +inline std::format_context::iterator std::formatter::format(const caioc::expression& e, + std::format_context& ctx) const { + if (auto* p = dynamic_cast(&e)) { + return std::format_to(ctx.out(), "{}", *p); + } + if (auto* p = dynamic_cast(&e)) { + return std::format_to(ctx.out(), "{}", *p); + } + if (auto* p = dynamic_cast(&e)) { + return std::format_to(ctx.out(), "{}", *p); + } + if (auto* p = dynamic_cast(&e)) { + return std::format_to(ctx.out(), "{}", *p); + } + if (auto* p = dynamic_cast(&e)) { + return std::format_to(ctx.out(), "{}", *p); + } + return std::format_to(ctx.out(), ""); +} + +inline std::format_context::iterator std::formatter::format(const caioc::call_expression& e, + std::format_context& ctx) const { + auto out = std::format_to(ctx.out(), "Call("); + out = e.callee ? std::format_to(out, "{}", *e.callee) : std::format_to(out, ""); + for (const auto& arg : e.args) { + out = std::format_to(out, ", "); + out = arg ? std::format_to(out, "{}", *arg) : std::format_to(out, ""); + } + return std::format_to(out, ")"); +} diff --git a/compiler/parser.cxx b/compiler/parser.cxx new file mode 100644 index 0000000..3d0462f --- /dev/null +++ b/compiler/parser.cxx @@ -0,0 +1,14 @@ +module caioc.parser; + +import std; + +import caioc.program; +import caioc.token; + +namespace caioc { + +class parser {}; + +program_module parse(std::span tokens) { return {}; } + +} // namespace caioc diff --git a/compiler/parser.ixx b/compiler/parser.ixx new file mode 100644 index 0000000..f962eb8 --- /dev/null +++ b/compiler/parser.ixx @@ -0,0 +1,10 @@ +export module caioc.parser; + +import std; + +import caioc.program; +import caioc.token; + +namespace caioc { +export [[nodiscard]] program_module parse(std::span tokens); +} diff --git a/compiler/program.ixx b/compiler/program.ixx new file mode 100644 index 0000000..541912a --- /dev/null +++ b/compiler/program.ixx @@ -0,0 +1,20 @@ +export module caioc.program; + +import std; + +import caioc.declaration; + +namespace caioc { + +export struct program_module { + std::vector> declarations; +}; + +} // namespace caioc + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + auto format(const caioc::program_module& s, std::format_context& ctx) const {} +}; diff --git a/compiler/statement.ixx b/compiler/statement.ixx index e69de29..1f4ffec 100644 --- a/compiler/statement.ixx +++ b/compiler/statement.ixx @@ -0,0 +1,157 @@ +export module caioc.statement; + +import std; + +import caioc.expression; + +namespace caioc { +export struct statement { + virtual ~statement() = default; +}; + +export struct return_statement : statement { + std::unique_ptr value; +}; + +export struct expression_statement : statement { + std::unique_ptr value; +}; + +export struct block_statement : statement { + std::vector> statements; +}; + +export struct if_statement : statement { + std::unique_ptr condition; + std::unique_ptr then_branch; + std::unique_ptr else_branch; +}; + +export struct while_statement : statement { + std::unique_ptr condition; + std::unique_ptr body; +}; + +export struct let_statement : statement { + std::string name; + std::string type_name; + std::unique_ptr init; +}; + +} // namespace caioc + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + auto format(const caioc::return_statement& s, std::format_context& ctx) const { + return s.value ? std::format_to(ctx.out(), "Return({})", *s.value) : std::format_to(ctx.out(), "Return()"); + } +}; + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + auto format(const caioc::expression_statement& s, std::format_context& ctx) const { + return s.value ? std::format_to(ctx.out(), "ExprStmt({})", *s.value) + : std::format_to(ctx.out(), "ExprStmt()"); + } +}; + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + auto format(const caioc::let_statement& s, std::format_context& ctx) const { + auto out = std::format_to(ctx.out(), "Let({}: {}", s.name, s.type_name); + out = s.init ? std::format_to(out, " = {}", *s.init) : out; + return std::format_to(out, ")"); + } +}; + +// --- mutually-referencing cluster: declared here, defined out-of-line below --- + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + std::format_context::iterator format(const caioc::statement& s, std::format_context& ctx) const; +}; + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + std::format_context::iterator format(const caioc::block_statement& s, std::format_context& ctx) const; +}; + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + std::format_context::iterator format(const caioc::if_statement& s, std::format_context& ctx) const; +}; + +export template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + std::format_context::iterator format(const caioc::while_statement& s, std::format_context& ctx) const; +}; + +inline std::format_context::iterator std::formatter::format(const caioc::statement& s, + std::format_context& ctx) const { + if (auto* p = dynamic_cast(&s)) { + return std::format_to(ctx.out(), "{}", *p); + } + if (auto* p = dynamic_cast(&s)) { + return std::format_to(ctx.out(), "{}", *p); + } + if (auto* p = dynamic_cast(&s)) { + return std::format_to(ctx.out(), "{}", *p); + } + if (auto* p = dynamic_cast(&s)) { + return std::format_to(ctx.out(), "{}", *p); + } + if (auto* p = dynamic_cast(&s)) { + return std::format_to(ctx.out(), "{}", *p); + } + if (auto* p = dynamic_cast(&s)) { + return std::format_to(ctx.out(), "{}", *p); + } + return std::format_to(ctx.out(), ""); +} + +inline std::format_context::iterator std::formatter::format(const caioc::block_statement& s, + std::format_context& ctx) const { + auto out = std::format_to(ctx.out(), "Block["); + bool first = true; + for (const auto& stmt : s.statements) { + if (!first) { + out = std::format_to(out, ", "); + } + first = false; + out = stmt ? std::format_to(out, "{}", *stmt) : std::format_to(out, ""); + } + return std::format_to(out, "]"); +} + +inline std::format_context::iterator std::formatter::format(const caioc::if_statement& s, + std::format_context& ctx) const { + auto out = std::format_to(ctx.out(), + "If({}, then: ", s.condition ? std::format("{}", *s.condition) : std::string("")); + out = s.then_branch ? std::format_to(out, "{}", *s.then_branch) : std::format_to(out, ""); + if (s.else_branch) { + out = std::format_to(out, ", else: {}", *s.else_branch); + } + return std::format_to(out, ")"); +} + +inline std::format_context::iterator std::formatter::format(const caioc::while_statement& s, + std::format_context& ctx) const { + auto out = + std::format_to(ctx.out(), "While({}, ", s.condition ? std::format("{}", *s.condition) : std::string("")); + out = s.body ? std::format_to(out, "{}", *s.body) : std::format_to(out, ""); + return std::format_to(out, ")"); +} diff --git a/driver/main.cxx b/driver/main.cxx index 7557911..0d905c0 100644 --- a/driver/main.cxx +++ b/driver/main.cxx @@ -2,6 +2,7 @@ import std; import caioc.utils; import caioc.frontend.tokenizer; +import caioc.parser; auto main(int argc, char** argv) -> int { if (argc < 2) { @@ -20,9 +21,11 @@ auto main(int argc, char** argv) -> int { return -1; } - for (const auto token : tokens) { + for (const auto& token : tokens) { std::println("{}: {} @ {}:{}", caioc::enum_to_string(token.type), token.backing, token.line, token.column); } + const auto program = caioc::parse(tokens); + return 0; }