Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b4573fe
chore: update subproject commit reference in examples
bialger Jan 12, 2026
74b43f0
build: add ArgParser as a dependency and link it to the compiler_ui l…
bialger Jan 12, 2026
fdf5afb
refactor: rename GetMessage to GetDiagnosticsMessage to avoid ambigui…
bialger Jan 12, 2026
54aa250
feat: enhance compiler UI with argument parsing and diagnostic messag…
bialger Jan 12, 2026
97b585e
fix: convertion amd globals
biqiboqi Jan 12, 2026
4771c32
fix: some fixes....
biqiboqi Jan 13, 2026
d2a2dd3
feat: add quadratic calculation and bitwise operations examples in ne…
bialger Jan 13, 2026
910c754
refactor: simplify diagnostic message printing logic in compiler UI
bialger Jan 13, 2026
d703032
refactor: optimize diagnostic message formatting by reducing redundan…
bialger Jan 13, 2026
c557388
Merge branch 'parser' into integration
bialger Jan 13, 2026
a354639
chore: update subproject commit reference in examples
bialger Jan 13, 2026
339aeb7
feat: enhance BytecodeVisitor to handle String type conversions and i…
bialger Jan 13, 2026
8057cfe
chore: format CI workflow configuration for improved readability and …
bialger Jan 13, 2026
0ce3fd8
feat: expand ProjectIntegrationTestSuite with comprehensive tests for…
bialger Jan 13, 2026
0444a68
feat: introduce ParserBytecodeTestSuite and VisitorTestSuite for enha…
bialger Jan 13, 2026
181e38f
refactor: streamline diagnostic message handling and improve type dec…
bialger Jan 13, 2026
5416a58
feat: add detailed help message and improve error handling in Project…
bialger Jan 13, 2026
088f899
refactor: utilize std::ranges for improved line ending normalization …
bialger Jan 13, 2026
708225c
feat: enhance BytecodeVisitor with new built-in functions and improve…
bialger Jan 14, 2026
d707550
feat: implement function overloading support in BytecodeVisitor and e…
bialger Jan 14, 2026
6fb03ab
chore: update subproject commit reference in examples
bialger Jan 14, 2026
df4ca94
feat: implement function overloading and built-in method support in T…
bialger Jan 14, 2026
d3767ee
refactor: simplify bytecode generation in ParserBytecodeTestSuite and…
bialger Jan 14, 2026
23d9a9e
feat: enhance BytecodeVisitor and TypeChecker with new file operation…
bialger Jan 14, 2026
0991f61
refactor: encapsulate BuiltinMethodSignature initialization in TypeCh…
bialger Jan 14, 2026
c7ebb2b
fix: correct comment formatting in BytecodeVisitor for clarity
bialger Jan 14, 2026
a157d06
feat: improve float output precision in BytecodeVisitor
bialger Jan 14, 2026
fa0a1ca
fix: enhance error reporting in PrattExpressionParser by including so…
bialger Jan 14, 2026
879fef9
fix: enhance linting error reporting by including source span informa…
bialger Jan 14, 2026
ce8e659
feat: enhance BytecodeVisitor with improved type resolution for chain…
bialger Jan 14, 2026
23fb2d7
refactor: improve code readability in BytecodeVisitor by adjusting fo…
bialger Jan 14, 2026
e3ec1a6
feat: enhance TypeChecker with argument type validation for function …
bialger Jan 14, 2026
6f779e1
fix: update destructor ID generation in BytecodeVisitor to include a …
bialger Jan 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 34 additions & 19 deletions .github/workflows/ci_tests.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: "CI tests"

on: [ push, workflow_dispatch ]
on: [push, workflow_dispatch]

jobs:
build-matrix:
Expand All @@ -11,22 +11,31 @@ jobs:
matrix:
config:
- {
name: "Windows Latest MSVC", artifact: "Windows-MSVC.tar.xz",
os: windows-latest,
build_type: "Release", cc: "cl", cxx: "cl",
environment_script: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat"
}
name: "Windows Latest MSVC",
artifact: "Windows-MSVC.tar.xz",
os: windows-latest,
build_type: "Release",
cc: "cl",
cxx: "cl",
environment_script: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat",
}
- {
name: "Ubuntu Latest GCC", artifact: "Linux.tar.xz",
os: ubuntu-latest,
build_type: "Release", cc: "gcc", cxx: "g++"
}
name: "Ubuntu Latest GCC",
artifact: "Linux.tar.xz",
os: ubuntu-latest,
build_type: "Release",
cc: "gcc",
cxx: "g++",
}
- {
name: "macOS Latest Clang", artifact: "macOS.tar.xz",
os: macos-latest,
build_type: "Release", cc: "clang", cxx: "clang++"
}

name: "macOS Latest Clang",
artifact: "macOS.tar.xz",
os: macos-latest,
build_type: "Release",
cc: "clang",
cxx: "clang++",
}

steps:
- uses: actions/checkout@v4

Expand Down Expand Up @@ -196,7 +205,7 @@ jobs:
echo "Running clang-tidy-19 on ${#files[@]} files..."
# Use clang-tidy-19 for better C++23 support and --extra-arg-before to ensure C++23 standard is set before other flags
clang-tidy-19 "${files[@]}" -p cmake-build-tidy --format-style=file > tidy_output.txt 2>&1 || true

# Ensure file exists and is readable
if [ ! -f tidy_output.txt ]; then
echo "" > tidy_output.txt
Expand All @@ -213,11 +222,11 @@ jobs:
errors=$(grep -c "error:" tidy_output.txt 2>/dev/null || echo "0")
warnings=$(grep -c "warning:" tidy_output.txt 2>/dev/null || echo "0")
fi

# Ensure we have clean integer values
errors=$(echo "$errors" | tr -d '\n' | head -c 10)
warnings=$(echo "$warnings" | tr -d '\n' | head -c 10)

# Default to 0 if empty or non-numeric
errors=${errors:-0}
warnings=${warnings:-0}
Expand All @@ -227,6 +236,12 @@ jobs:

echo "Found $errors errors and $warnings warnings"

if [ "$errors" -eq 0 ] && [ "$warnings" -le 3 ]; then
echo "clang-tidy found $warnings warnings"
cat tidy_output.txt
exit 0
fi

# Fail if more than 3 warnings or any errors
if [ "$errors" -gt 0 ] || [ "$warnings" -gt 3 ]; then
echo "clang-tidy found $errors errors and $warnings warnings"
Expand All @@ -240,7 +255,7 @@ jobs:
with:
script: |
const fs = require('fs');

try {
let comment = '## 🔍 Code Quality Issues Found\n\n';

Expand Down
11 changes: 11 additions & 0 deletions cmake/IncludeExternalLibraries.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ FetchContent_Declare(

FetchContent_MakeAvailable(googletest)


# ArgParser
FetchContent_Declare(
argparser
GIT_REPOSITORY https://github.com/bialger/ArgParser.git
GIT_TAG v1.3.5
)

FetchContent_MakeAvailable(argparser)


# Ovum Common
FetchContent_Declare(
ovumcommon
Expand Down
2 changes: 2 additions & 0 deletions lib/compiler_ui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ add_library(compiler_ui STATIC
target_link_libraries(compiler_ui PUBLIC
lexer
preprocessor
parser
argparser
)

target_include_directories(compiler_ui PUBLIC ${PROJECT_SOURCE_DIR})
163 changes: 147 additions & 16 deletions lib/compiler_ui/compiler_ui_functions.cpp
Original file line number Diff line number Diff line change
@@ -1,31 +1,114 @@
#include "argparser/Argument.hpp"
#include "compiler_ui_functions.hpp"

#include <fstream>
#include <memory>

#include <argparser/ArgParser.hpp>

#include "lib/parser/ParserFsm.hpp"
#include "lib/parser/ast/BuilderAstFactory.hpp"
#include "lib/parser/ast/visitors/BytecodeVisitor.hpp"
#include "lib/parser/ast/visitors/LintVisitor.hpp"
#include "lib/parser/ast/visitors/TypeChecker.hpp"
#include "lib/parser/diagnostics/DiagnosticCollector.hpp"
#include "lib/parser/pratt/DefaultOperatorResolver.hpp"
#include "lib/parser/pratt/PrattExpressionParser.hpp"
#include "lib/parser/tokens/token_streams/VectorTokenStream.hpp"
#include "lib/parser/type_parser/QNameTypeParser.hpp"
#include "lib/preprocessor/Preprocessor.hpp"

static void PrintDiagnosticMessage(const ovum::compiler::parser::Diagnostic& diag, std::ostream& out) {
if (diag.IsSuppressed()) {
return;
}

std::string severity_str = diag.GetSeverity() ? diag.GetSeverity()->Name().data() : "UNKNOWN";

out << "[" << severity_str << "]";

if (!diag.GetCode().empty()) {
out << " " << diag.GetCode();
}

out << ": " << diag.GetDiagnosticsMessage();
const std::optional<ovum::compiler::parser::SourceSpan>& where_opt = diag.GetWhere();

if (where_opt.has_value()) {
const ovum::compiler::parser::SourceSpan& where = where_opt.value();

if (!where.GetSourceId().Path().empty()) {
out << " \nAt " << where.GetSourceId().Path();
}

if (where.GetStart() == where.GetEnd()) {
out << " line " << where.GetStart().GetLine() << " column " << where.GetStart().GetColumn();
} else {
out << " from line " << where.GetStart().GetLine() << " column " << where.GetStart().GetColumn() << " to line "
<< where.GetEnd().GetLine() << " column " << where.GetEnd().GetColumn();
}
}

out << "\n";
}

int32_t StartCompilerConsoleUI(const std::vector<std::string>& args, std::ostream& out, std::ostream& err) {
if (args.size() < 2) {
err << "Usage: ovumc <main_file.ovum> [include_path1] [include_path2] ...\n";
err << "Example: ovumc sample.ovum /path/to/includes\n";
const CompositeString default_output_name = "Same as input file but with .oil extension";
auto is_file = [](std::string& arg) { return std::filesystem::exists(arg); };
auto is_directory = [](std::string& arg) { return std::filesystem::is_directory(arg); };
std::string description = "Ovum Compiler that compiles Ovum source code to Ovum Intermediate Language.";
std::vector<CompositeString> include_dirs;
std::vector<std::string> define_symbols;
std::vector<bool> no_lint;

ArgumentParser::ArgParser arg_parser("ovumc", PassArgumentTypes());
arg_parser.AddCompositeArgument('m', "main-file", "Path to the main file").AddIsGood(is_file).AddValidate(is_file);
arg_parser.AddCompositeArgument('o', "output-file", "Path to the output file").Default(default_output_name);
arg_parser.AddCompositeArgument('I', "include-dirs", "Path to directories where include files are located")
.AddIsGood(is_directory)
.AddValidate(is_directory)
.MultiValue(0)
.StoreValues(include_dirs);
arg_parser.AddStringArgument('D', "define-symbols", "Defined symbols").MultiValue(0).StoreValues(define_symbols);
arg_parser.AddFlag('n', "no-lint", "Disable linter").MultiValue(0).StoreValues(no_lint);
arg_parser.AddHelp('h', "help", description);

bool parse_result = arg_parser.Parse(args, {.out_stream = err, .print_messages = true});
if (!parse_result) {
err << arg_parser.HelpDescription();
return 1;
}

if (args[1] == "--help") {
out << "Usage: ovumc <main_file.ovum> [include_path1] [include_path2] ...\n";
out << "Example: ovumc sample.ovum /path/to/includes\n";
if (arg_parser.Help()) {
out << arg_parser.HelpDescription();
return 0;
}

std::filesystem::path main_file = args[1];
std::set<std::filesystem::path> include_paths;
std::filesystem::path main_file = arg_parser.GetCompositeValue("main-file").c_str();
std::filesystem::path output_file;
const CompositeString& output_file_value = arg_parser.GetCompositeValue("output-file");

include_paths.emplace(main_file.parent_path());
if (output_file_value == default_output_name) {
output_file = main_file;
output_file.replace_extension(".oil");
} else {
output_file = output_file_value.c_str();
}

for (size_t i = 2; i < args.size(); ++i) {
include_paths.emplace(args[i]);
std::set<std::filesystem::path> include_paths;

for (const auto& include_dir : include_dirs) {
include_paths.emplace(include_dir.c_str());
}

std::unordered_set<std::string> predefined_symbols;

for (const auto& define_symbol : define_symbols) {
predefined_symbols.emplace(define_symbol.c_str());
}

include_paths.emplace(main_file.parent_path());

ovum::compiler::preprocessor::PreprocessingParameters params{
.include_paths = include_paths, .predefined_symbols = predefined_symbols, .main_file = main_file};

Expand All @@ -35,16 +118,64 @@ int32_t StartCompilerConsoleUI(const std::vector<std::string>& args, std::ostrea

if (!result) {
err << result.error().what() << "\n";
return 1;
return 2;
}

std::vector<ovum::TokenPtr> tokens = std::move(result.value());

// Set up parser
auto factory = std::make_shared<ovum::compiler::parser::BuilderAstFactory>();
auto type_parser = std::make_unique<ovum::compiler::parser::QNameTypeParser>(*factory);
auto resolver = std::make_unique<ovum::compiler::parser::DefaultOperatorResolver>();
auto expr_parser =
std::make_unique<ovum::compiler::parser::PrattExpressionParser>(std::move(resolver), factory, type_parser.get());
auto parser =
std::make_unique<ovum::compiler::parser::ParserFsm>(std::move(expr_parser), std::move(type_parser), factory);

// Parse
ovum::compiler::parser::DiagnosticCollector diags;
ovum::compiler::parser::VectorTokenStream stream(tokens);
auto module = parser->Parse(stream, diags);

if (!module) {
err << "Parsing failed\n";
return 3;
}

// Linting
if (no_lint.empty() || !no_lint[0]) {
ovum::compiler::parser::LintVisitor lint_visitor(diags);
module->Accept(lint_visitor);
}

// Type checking
if (no_lint.size() <= 1 || !no_lint[1]) {
ovum::compiler::parser::TypeChecker type_checker(diags);
module->Accept(type_checker);
}

const auto& tokens = result.value();
// Check all diagnostics
if (diags.Count() > 0) {
for (const auto& diag : diags.All()) {
PrintDiagnosticMessage(diag, out);
}

for (const auto& t : tokens) {
out << t->ToString() << "\n";
if (diags.ErrorCount() > 0) {
return 4;
}
}

out << "\nPreprocessed " << tokens.size() << " tokens successfully.\n";
// Generate bytecode
std::ofstream output_stream(output_file, std::ios::out | std::ios::trunc);
if (!output_stream.is_open()) {
err << "Failed to open output file: " << output_file.string() << "\n";
return 1;
}

ovum::compiler::parser::BytecodeVisitor visitor(output_stream);
module->Accept(visitor);

output_stream.close();

return 0;
}
Loading