diff --git a/ARCHITECTURE_REVIEW.md b/ARCHITECTURE_REVIEW.md deleted file mode 100644 index da312d0..0000000 --- a/ARCHITECTURE_REVIEW.md +++ /dev/null @@ -1,66 +0,0 @@ -# ProXPL Architecture Review - -Date: 2025-12-13 - -Overview --------- -This document provides a high-level review of the ProXPL repository and architectural recommendations focused on modernizing, modularizing, and preparing the codebase for a production-grade VM and ecosystem. - -Current Layout --------------- -- Top-level: `src/` contains the primary C implementation (lexer, parser, runtime, stdlib). -- Public headers: `include/` exposes the VM and compiler APIs. -- Tests: `tests/` covers bytecode and scanner tests. -- Docs: `docs/` and `ARCHITECTURE.md` contain comprehensive design and language details. - -Key Observations ----------------- -- The code is separated into front-end (lexer/parser/type checker) and runtime (compiler, vm, chunk, intrinsics), which is a good foundation. -- VM implementation is a working stack-based interpreter with bytecode and a simple chunk system; opcode definitions are centralized in `include/bytecode.h`. -- There are separate `src/runtime` and `src/vm` directories; unify or clearly separate their responsibilities (runtime = primtiive runtime helpers, vm = dispatch & optimizations). -- Missing/partial features: GC, IR, optimizer, JIT, module system, FFI, concurrency, standard library modules, tooling. - -Risks & Architectural Trade-offs --------------------------------- -- Monolithic vs Modular: The current structure scales slowly (many top-level sources with cross-cutting includes). A clearer modular split (frontend/compiler/vm/runtime/stdlib/tools) will improve maintainability. -- Versioning & ABI: As this project evolves, design public stable headers and internal headers; add `include/proxpl_api.h` that documents stable APIs. -- GC/Heap: The current memory model is simple; target runtime should implement a generational GC with write barriers for performance and correctness in concurrency. - -Recommended Modular Structure ------------------------------ -- `frontend/` — lexer, parser, type-checker, AST, semantic analysis. -- `compiler/` — IR, optimizations, bytecode emitter, linking. -- `vm/` — bytecode format, bytecode interpreter, debugger hooks. -- `runtime/` — memory management, GC, object model, compact object representation, GC safety wrappers. -- `stdlib/` — native modules and bindings. -- `tools/` — bench, build scripts, LSP, REPL utilities. -- `ffi/` — C/Python bridge, FFI design and wrappers. - -Short-term Action Items (Phase 0) --------------------------------- -1. Add a `TICKET-001: ir/opcodes.md` spec from `include/bytecode.h` and commit as canonical spec. -2. Add `include/proxpl_api.h` and define the public stable API for VM and runtime. -3. Create `scripts/` with `build_unix.sh` and `build_windows.ps1` that use CMake for cross-platform builds; add `CI` workflows to GitHub Actions. -4. Move test harness to `tests/` and provide a `tests/CMakeLists.txt` to allow running tests with `ctest`. -5. Add a `tools/bench` harness that executes core micro-benchmarks and produces a simple JSON report. - -Longer-term Priorities ----------------------- -- Implement generational GC with write barriers and a memory profiler. -- Implement the IR and an optimizer pipeline with canonical IR passes (constant folding, DCE, inlining, escape analysis). -- Add a JIT backend (start with a simple tracing JIT prototype or LLVM). Provide hooks in the VM for hot-trace extraction. -- Add concurrency primitives: coroutines, channels, and threads backed by a scheduler. -- Implement FFI for C and Python (MLVM-style embedding) with security hardening. -- Ship an LSP server + VSCode extension with DAP instrumentation for the VM. - -Acceptance Criteria / Metrics ---------------------------- -- The repo should build via CMake on Linux/macOS/Windows using standard toolchains (GCC/Clang/MSVC). -- The VM should provide consistent API across versions; header stability maintained via `include/proxpl_api.h`. -- Micro-bench suite should show a reproducible baseline for CPU-bound and IO-bound tests. - -Next Steps I'm Prepared To Implement ------------------------------------ -- Add `ir/opcodes.md` and a clean, canonical opcode spec. -- Add CMake test configuration and a sample GitHub Actions workflow. -- Add `scripts/build_*.sh/.ps1` build helpers and a `tools/bench` harness. diff --git a/BASELINE_REPORT.md b/BASELINE_REPORT.md deleted file mode 100644 index e5e0375..0000000 --- a/BASELINE_REPORT.md +++ /dev/null @@ -1,56 +0,0 @@ -# ProXPL Baseline Report - -Date: 2025-12-13 - -Summary -------- -- Repository contains a working C implementation in `src/` and comprehensive documentation (ARCHITECTURE.md, docs/*). -- Build support exists via `Makefile` (root and `src/`) and `CMakeLists.txt`. -- Unit and integration tests exist under `tests/` (bytecode tests and scanner unit templates). - -What I verified ---------------- -- Inspected project layout (`src`, `include`, `tests`, `docs`, `examples`). -- Opened main entry (`src/main.c`) and confirmed the VM/lexer/parser modules exist and are partially implemented. -- Found bytecode support (`include/bytecode.h`, `src/vm/*`, `src/runtime/*`) and test harnesses (`tests/bytecode_tests.c`). - -Build & Test Attempt --------------------- -- Attempted to build the C runtime locally in this environment using `make` in `src/`. -- The environment lacks required developer tools: `make`, `gcc/clang` or MSVC are not available, so a local build could not be completed here. - -Current Gaps / Shortcomings ---------------------------- -- `Makefile` and `CMakeLists.txt` present, but CI and platform-specific build scripts are missing (Windows PowerShell + GitHub Actions matrix should be added). -- Garbage collector, IR, optimizer and JIT are noted as TODOs in `src/`. -- Standard library modules are partially implemented; collections and datetime are missing. -- Test coverage exists but needs automation and coverage reports (e.g., `gcov`, `lcov`, `coverity` integration). - -Immediate Next Steps (recommended) ----------------------------------- -1. Add a reproducible CI matrix (GitHub Actions) that builds on Linux/macOS/Windows and runs tests. -2. Add cross-platform build scripts: `scripts/build_windows.ps1` (MSVC), `scripts/build_unix.sh` (gcc/clang) that use CMake. -3. Add a diagnostics `make ci-check` that runs static analyzers (clang-tidy), formatters (clang-format), and tests. -4. Create an `ir/opcodes.md` documenting the opcode set (source of truth for the VM and bytecode format). -5. Start a lightweight profiler benchmark harness and micro-benchmarks (e.g., eval loops, arithmetic, function calls). - -Notes about this environment ----------------------------- -- I could not perform a runtime build or run the tests because the build tools are not installed in this environment. The repository is otherwise self-contained and appears buildable on a properly provisioned developer machine. - -Files added/updated during baseline work --------------------------------------- -- `BASELINE_REPORT.md` (this file) - -If you want, I can: -- Add the CI workflow and cross-platform build scripts. -- Write `ir/opcodes.md` and an initial `TICKET-001` draft in `tickets/`. -- Create a minimal benchmark harness under `tools/bench/` to start profiling. - -Progress updates (2025-12-13) -- Added GitHub Actions CI workflow and cross-platform scripts. -- Created `tests/test_opcode_roundtrip.c` and `tests/test_opcode_values.c` and wired them into CMake. -- Added a micro-benchmark `tools/bench/bench_simple.c` and CMake target. - ---- -Generated by automation on behalf of the ProXPL modernization plan. diff --git a/CMakeLists.txt b/CMakeLists.txt index f3f688f..0dc5c76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,28 +1,53 @@ -cmake_minimum_required(VERSION 3.10) -project(ProXPL C) +cmake_minimum_required(VERSION 3.13) +project(ProXPL) +# Enable C and C++ +enable_language(C CXX) set(CMAKE_C_STANDARD 99) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -g") +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) -# Include directories +# --- LLVM Configuration --- +find_package(LLVM REQUIRED CONFIG) + +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +# Include LLVM directories +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) + +# Link directories +link_directories(${LLVM_LIBRARY_DIRS}) + +# Map generic components to specific libs +llvm_map_components_to_libnames(llvm_libs core support executionengine native ipo) + +# --- Project Source --- +# Export symbols for Windows DLL +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + +# --- Project Source --- include_directories(include) -# Source files -# Source files -file(GLOB_RECURSE SOURCES "src/*.c") +# Gather sources (excluding main.c for library) +file(GLOB_RECURSE LIB_SOURCES + "src/*.c" + "src/compiler/*.cpp" +) +list(FILTER LIB_SOURCES EXCLUDE REGEX ".*main\\.c$") -# Core library (exposed to tests and tools) -add_library(prox_core STATIC ${SOURCES}) -target_include_directories(prox_core PUBLIC ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/src) +# --- Shared Library --- +add_library(proxpl_lib SHARED ${LIB_SOURCES}) +target_link_libraries(proxpl_lib PRIVATE ${llvm_libs}) -# Executable -add_executable(prox src/main.c) -target_link_libraries(prox PRIVATE prox_core) +# --- Executable --- +add_executable(proxpl src/main.c ${LIB_SOURCES}) -# Optional targets: tools and tests -add_subdirectory(tests) -add_subdirectory(tools/bench) +# Link LLVM and standard libraries +target_link_libraries(proxpl PRIVATE ${llvm_libs}) -# Tests -enable_testing() -add_subdirectory(tests) +if(UNIX) + target_link_libraries(proxpl PRIVATE pthread dl z tinfo) + target_link_libraries(proxpl_lib PRIVATE pthread dl z tinfo) +endif() diff --git a/CMakeLists_IMPROVED.txt b/CMakeLists_IMPROVED.txt deleted file mode 100644 index 911e816..0000000 --- a/CMakeLists_IMPROVED.txt +++ /dev/null @@ -1,164 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -project(ProXPL - VERSION 0.1.0 - DESCRIPTION "A Modern, Production-Ready Programming Language" - HOMEPAGE_URL "https://github.com/ProgrammerKR/ProXPL" - LANGUAGES C -) - -set(CMAKE_C_STANDARD 99) -set(CMAKE_C_STANDARD_REQUIRED ON) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic") - -# Optional: Add sanitizers in Debug mode -if(CMAKE_BUILD_TYPE MATCHES Debug) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fsanitize=address -fsanitize=undefined") -endif() - -# Version -set(PROXPL_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) -set(PROXPL_VERSION_MINOR ${PROJECT_VERSION_MINOR}) -set(PROXPL_VERSION_PATCH ${PROJECT_VERSION_PATCH}) - -# Include directories -include_directories(${CMAKE_SOURCE_DIR}/include) - -# Gather all source files -file(GLOB_RECURSE SOURCES - "src/main.c" - "src/lexer/*.c" - "src/parser/*.c" - "src/runtime/*.c" - "src/stdlib/*.c" -) - -# Create main executable -add_executable(prox ${SOURCES}) - -# Link math library (needed for math functions) -target_link_libraries(prox m) - -# Set output directory -set_target_properties(prox PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" - VERSION ${PROJECT_VERSION} -) - -# Add compile definitions -target_compile_definitions(prox PRIVATE - PROXPL_VERSION_MAJOR=${PROXPL_VERSION_MAJOR} - PROXPL_VERSION_MINOR=${PROXPL_VERSION_MINOR} - PROXPL_VERSION_PATCH=${PROXPL_VERSION_PATCH} -) - -# Optional: Test support -enable_testing() - -# Find or build test framework (Unity) -find_package(Unity QUIET) - -if(NOT Unity_FOUND) - # If Unity not found, tests are skipped - message(STATUS "Unity test framework not found - tests will be skipped") - message(STATUS "To install: sudo apt-get install libunity-dev") -else() - # Discover and add test files - file(GLOB_RECURSE TEST_SOURCES "tests/unit/*.c" "tests/integration/*.c") - - if(TEST_SOURCES) - foreach(test_file ${TEST_SOURCES}) - get_filename_component(test_name ${test_file} NAME_WE) - add_executable(${test_name} ${test_file}) - target_link_libraries(${test_name} Unity::Unity) - add_test(NAME ${test_name} COMMAND ${test_name}) - endforeach() - endif() -endif() - -# Custom targets - -# Make clean -add_custom_target(clean_all - COMMAND ${CMAKE_MAKE_PROGRAM} clean - COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_SOURCE_DIR}/cmake/clean.cmake" -) - -# Format code -add_custom_target(format - COMMAND clang-format -i ${SOURCES} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} -) - -# Lint code -add_custom_target(lint - COMMAND clang-tidy ${SOURCES} -- -I${CMAKE_SOURCE_DIR}/include - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} -) - -# Run tests -add_custom_target(test_run - COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure - DEPENDS prox -) - -# Build documentation -find_package(Doxygen) -if(DOXYGEN_FOUND) - set(DOXYGEN_INPUT_DIR ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/include) - set(DOXYGEN_OUTPUT_DIR ${CMAKE_BINARY_DIR}/docs) - - configure_file( - ${CMAKE_SOURCE_DIR}/Doxyfile.in - ${CMAKE_BINARY_DIR}/Doxyfile - @ONLY - ) - - add_custom_target(docs - COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - COMMENT "Generating API documentation with Doxygen" - ) -else() - message(STATUS "Doxygen not found - documentation generation will be skipped") - message(STATUS "To install: sudo apt-get install doxygen") -endif() - -# Installation targets -install(TARGETS prox - RUNTIME DESTINATION bin -) - -install(DIRECTORY docs/ - DESTINATION share/doc/proxpl - OPTIONAL -) - -install(FILES README.md LANGUAGE_SPEC.md STDLIB_DOC.md CODING_STANDARD.md - DESTINATION share/doc/proxpl -) - -# Print configuration summary -message(STATUS "") -message(STATUS "========== ProXPL Build Configuration ==========") -message(STATUS "Project: ${PROJECT_NAME} ${PROJECT_VERSION}") -message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") -message(STATUS "C Compiler: ${CMAKE_C_COMPILER}") -message(STATUS "C Standard: ${CMAKE_C_STANDARD}") -message(STATUS "Source directory: ${CMAKE_SOURCE_DIR}") -message(STATUS "Binary directory: ${CMAKE_BINARY_DIR}") -message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}") -message(STATUS "") -message(STATUS "Available targets:") -message(STATUS " prox - Main executable") -message(STATUS " format - Format code with clang-format") -message(STATUS " lint - Lint code with clang-tidy") -message(STATUS " test_run - Run all tests") -message(STATUS " docs - Generate documentation (requires Doxygen)") -message(STATUS " install - Install to system") -message(STATUS "") -message(STATUS "Quick start:") -message(STATUS " cmake .. -DCMAKE_BUILD_TYPE=Release") -message(STATUS " make") -message(STATUS " ./bin/prox ../examples/hello.prox") -message(STATUS "") diff --git a/INDEX.md b/INDEX.md deleted file mode 100644 index c7592bb..0000000 --- a/INDEX.md +++ /dev/null @@ -1,533 +0,0 @@ -# ProXPL Complete Refactoring Deliverables Index - -**Refactoring Completed: December 2024** -**Version: 0.1.0** - -This document indexes all deliverables from the comprehensive ProXPL refactoring project. - ---- - -## 📚 Quick Navigation - -### For Users & Learners -→ Start with [README_IMPROVED.md](README_IMPROVED.md) -→ Learn syntax from [LANGUAGE_SPEC.md](LANGUAGE_SPEC.md) -→ Reference functions in [STDLIB_DOC.md](STDLIB_DOC.md) -→ Build with [docs/BUILD_GUIDE.md](docs/BUILD_GUIDE.md) -→ Explore [examples/](examples/) folder - -### For Developers -→ Read [CODING_STANDARD.md](CODING_STANDARD.md) -→ Understand [ARCHITECTURE.md](ARCHITECTURE.md) -→ Build with [CMakeLists_IMPROVED.txt](CMakeLists_IMPROVED.txt) -→ Test with [tests/unit/test_scanner_template.c](tests/unit/test_scanner_template.c) - -### For Contributors -→ See [CONTRIBUTING.md](CONTRIBUTING.md) -→ Follow [CODING_STANDARD.md](CODING_STANDARD.md) -→ Check [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) - -### For Maintainers -→ Review [VERSIONING.md](VERSIONING.md) -→ Understand CI/CD [.github/workflows/ci.yml](.github/workflows/ci.yml) -→ Check roadmap in [VERSIONING.md#roadmap](VERSIONING.md) -→ See deployment checklist in [REFACTOR_REPORT.md](REFACTOR_REPORT.md) - ---- - -## 📋 Complete Deliverables List - -### 🎯 Core Documentation (NEW) - -#### 1. **README_IMPROVED.md** (500 lines) -**Purpose**: Professional project overview and getting started guide - -**Contents**: -- Project philosophy and goals -- Complete feature list -- Installation instructions (3 methods) -- 5 practical code examples -- Architecture overview -- Documentation index -- Contribution guidelines -- Community support information -- Roadmap through v1.0.0 - -**When to Use**: First resource for new users and contributors - -**Key Sections**: -- About ProXPL -- Key Features -- Language Goals -- Quick Start (with code examples) -- Installation & Building -- Usage Examples -- Architecture Overview -- Documentation Links -- Contributing -- Support & Community -- Roadmap -- License - ---- - -#### 2. **LANGUAGE_SPEC.md** (800 lines) -**Purpose**: Complete formal language specification - -**Contents**: -- Language design overview -- Lexical structure (identifiers, keywords, literals, comments) -- Data types (all 12 types with examples) -- Operators (42 operators with precedence table) -- Statements (if, loops, try-catch, defer, etc.) -- Expressions (literals, operators, calls) -- Functions (declaration, recursion, closures) -- Type system and type checking -- Memory, scope, and garbage collection -- Standard library overview -- 5 code examples - -**When to Use**: Language reference during programming - -**Key Sections**: -- Overview & Design Goals -- Lexical Structure -- Data Types (12 types) -- Operators (42 operators) -- Statements -- Expressions -- Functions -- Type System -- Memory and Scope -- Standard Library Overview -- Examples - ---- - -#### 3. **STDLIB_DOC.md** (1500 lines) -**Purpose**: Complete standard library reference with examples - -**Contents**: -- All 75+ built-in functions -- Organized into 8 modules: - - I/O (5 functions) - - Math (15 functions) - - Strings (15 functions) - - Collections (15 functions) - - Type Conversion (10 functions) - - System (5 functions) - - DateTime (5 functions) - - Runtime (5 functions) -- Each function includes: - - Full signature - - Parameter documentation - - Return type - - 2+ usage examples - - Important notes - -**When to Use**: Look up function documentation and examples - -**Key Sections**: -- I/O Functions (print, input, file operations) -- Math Functions (sqrt, pow, sin, cos, random, etc.) -- String Functions (split, join, replace, substring, etc.) -- Collections (list/dict operations) -- Type Conversion -- System Functions -- DateTime Functions -- Runtime Functions -- Quick Reference - ---- - -#### 4. **CODING_STANDARD.md** (600 lines) -**Purpose**: Development guidelines and best practices - -**Contents**: -- General coding principles -- C code style (indentation, line length, spacing) -- Naming conventions (snake_case, PascalCase, UPPER_SNAKE_CASE) -- Header file organization -- Source file structure -- Memory management patterns -- Error handling practices -- Comments and documentation -- Module organization -- Testing standards -- Git workflow -- Code review checklist -- Tool integration (clang-format, clang-tidy, valgrind) - -**When to Use**: Before writing code or reviewing PRs - -**Key Sections**: -- General Principles -- C Code Style -- Naming Conventions -- Header Files -- Source Files -- Memory Management -- Error Handling -- Comments and Documentation -- Code Organization -- Testing Standards -- Git Workflow -- Code Review Checklist - ---- - -#### 5. **VERSIONING.md** (400 lines) -**Purpose**: Version management and release strategy - -**Contents**: -- Semantic versioning (SemVer 2.0.0) compliance -- Version history and current state -- Release procedure documentation -- Release types (alpha, beta, RC, stable) -- Backward compatibility guarantees -- Deprecation policy -- Version management in code -- Release schedule (0.1.0 → 1.0.0) -- Maintenance policy -- Build artifact naming - -**When to Use**: Planning releases and managing versions - -**Key Sections**: -- Semantic Versioning -- Version History -- Release Procedure -- Release Types -- Backward Compatibility -- Deprecation Policy -- Version Management -- Roadmap -- Release Calendar -- Maintenance Policy - ---- - -### 🔧 Infrastructure Files (NEW) - -#### 6. **.github/workflows/ci.yml** (200 lines) -**Purpose**: Automated CI/CD pipeline - -**Features**: -- Builds on Ubuntu, macOS, Windows -- Compiler variants (GCC, Clang, MSVC) -- Automated testing (unit + integration) -- Code quality checks (clang-format, clang-tidy, cppcheck) -- Memory checking with Valgrind -- Documentation generation (Doxygen) -- Automated releases with artifacts -- Build artifacts uploaded to releases - -**When to Use**: Automatic validation on every commit - -**Build Matrix**: -- OS: Ubuntu, macOS, Windows -- Compilers: GCC, Clang, MSVC -- Build Types: Release -- Artifacts: Retained 5 days (PR) or 30 days (releases) - ---- - -#### 7. **Doxyfile** (200 lines) -**Purpose**: Configure API documentation generation - -**Features**: -- C source code documentation extraction -- HTML output (main) -- LaTeX/PDF generation -- Man page generation -- Source code browsing -- Call and dependency graphs -- Search functionality -- Cross-referenced documentation - -**When to Use**: Generate API documentation with `doxygen` - -**Output**: -- `build/docs/html/index.html` - Browse docs -- `build/docs/latex/refman.pdf` - PDF manual -- Search-enabled HTML - ---- - -#### 8. **CMakeLists_IMPROVED.txt** (150 lines) -**Purpose**: Modern CMake build configuration - -**Features**: -- CMake 3.10+ compatibility -- Version management integration -- Multiple build types (Debug, Release) -- Optional sanitizers in Debug -- Automatic test discovery -- Custom targets: - - `make format` - Code formatting - - `make lint` - Static analysis - - `make test_run` - Run tests - - `make docs` - Generate docs -- Installation targets -- Compiler optimization - -**When to Use**: Building the project - -**Usage**: -```bash -mkdir build && cd build -cmake .. -DCMAKE_BUILD_TYPE=Release -make -make test_run -make docs -``` - ---- - -### 📖 Enhanced Documentation - -#### 9. **docs/BUILD_GUIDE.md** (Enhanced) -**Purpose**: Platform-specific build instructions - -**New Content**: -- Quick start for all platforms -- Linux/WSL detailed setup -- macOS (Intel and Apple Silicon) -- Windows (MinGW and Visual Studio) -- Docker containerization -- Code quality tools -- Cross-compilation examples -- Troubleshooting guide - -**Platforms Covered**: -- Linux/WSL2 -- macOS (Intel + Apple Silicon) -- Windows (MinGW/MSVC) -- Docker - ---- - -### 🧪 Test Framework - -#### 10. **tests/unit/test_scanner_template.c** (400 lines) -**Purpose**: Test framework example using Unity - -**Contents**: -- 25+ test cases demonstrating: - - Identifier tokenization - - Number scanning (integers, floats, scientific notation) - - String literals and escape sequences - - Keyword recognition - - Operator and punctuation parsing - - Comment handling - - Token sequences - - Line/column tracking - - Error cases - - EOF detection - -**When to Use**: Reference for writing your own tests - -**Test Categories**: -1. Basic tokenization (3 tests) -2. Numbers (4 tests) -3. Strings (3 tests) -4. Keywords (4 tests) -5. Operators (4 tests) -6. Punctuation (3 tests) -7. Comments (2 tests) -8. Sequences (1 test) -9. Line tracking (1 test) -10. Errors (2 tests) -11. EOF (2 tests) - ---- - -### 📊 Summary & Analysis - -#### 11. **REFACTOR_REPORT.md** (2000 lines) -**Purpose**: Complete refactoring summary with analysis - -**Contents**: -- Executive summary -- Task-by-task completion details -- Before/after comparison -- Project structure after refactoring -- Key improvements and metrics -- How to use improvements -- File change history -- Quality metrics -- Deployment checklist -- Next steps and roadmap -- Appendix with file statistics - -**Sections**: -1. Executive Summary -2. Tasks Completed (9 major tasks) -3. Comparison Tables -4. Project Structure -5. Key Improvements -6. How to Use -7. Deployment Checklist -8. Next Steps -9. File Statistics - ---- - -#### 12. **REFACTORING_SUMMARY.md** (1000 lines) -**Purpose**: Executive summary and quick reference - -**Contents**: -- Mission accomplished statement -- What was done (9 tasks) -- Files created/modified count -- Key features for different audiences -- Documentation coverage statistics -- Technology stack used -- Quality improvements table -- Learning resources organized by audience -- Implementation workflows -- Highlights and features -- Support and community links -- File reference table -- Achievement summary - ---- - -## 🗂️ Complete File Structure - -``` -ProXPL/ -│ -├── 📄 Core Documentation (NEW) -│ ├── README_IMPROVED.md ← Start here! -│ ├── LANGUAGE_SPEC.md ← Language reference -│ ├── STDLIB_DOC.md ← Function docs -│ ├── CODING_STANDARD.md ← Dev guidelines -│ ├── VERSIONING.md ← Version strategy -│ ├── REFACTOR_REPORT.md ← Full analysis -│ └── REFACTORING_SUMMARY.md ← Quick overview -│ -├── 📂 Infrastructure (NEW) -│ ├── .github/workflows/ -│ │ └── ci.yml ← CI/CD pipeline -│ ├── Doxyfile ← Documentation config -│ └── CMakeLists_IMPROVED.txt ← Enhanced build -│ -├── 📂 Tests (ENHANCED) -│ ├── unit/ -│ │ └── test_scanner_template.c ← Test examples -│ └── integration/ -│ -├── 📂 Documentation -│ ├── BUILD_GUIDE.md ← Platform builds -│ ├── ARCHITECTURE.md ← Design docs -│ ├── language-spec/ ← Language docs -│ ├── architecture/ ← System design -│ ├── ir-spec/ ← Bytecode spec -│ └── tutorials/ ← Learning guides -│ -├── 📂 Source Code (EXISTING) -│ ├── include/ ← Headers -│ ├── src/ ← Implementation -│ └── examples/ ← Code examples -│ -├── 📂 Build System (ENHANCED) -│ ├── CMakeLists.txt ← Original -│ ├── CMakeLists_IMPROVED.txt ← Enhanced version -│ └── Makefile ← Traditional build -│ -└── 📄 Other Files (EXISTING) - ├── ARCHITECTURE.md - ├── CHANGELOG.md - ├── CONTRIBUTING.md - ├── CODE_OF_CONDUCT.md - └── LICENSE -``` - ---- - -## 🎯 How to Navigate This Documentation - -### I want to... - -**...learn to use ProXPL** -→ [README_IMPROVED.md](README_IMPROVED.md) → [examples/](examples/) → [LANGUAGE_SPEC.md](LANGUAGE_SPEC.md) → [STDLIB_DOC.md](STDLIB_DOC.md) - -**...build ProXPL from source** -→ [docs/BUILD_GUIDE.md](docs/BUILD_GUIDE.md) → [CMakeLists_IMPROVED.txt](CMakeLists_IMPROVED.txt) - -**...contribute code** -→ [CONTRIBUTING.md](CONTRIBUTING.md) → [CODING_STANDARD.md](CODING_STANDARD.md) → [tests/](tests/) - -**...understand the language** -→ [LANGUAGE_SPEC.md](LANGUAGE_SPEC.md) → [ARCHITECTURE.md](ARCHITECTURE.md) - -**...reference built-in functions** -→ [STDLIB_DOC.md](STDLIB_DOC.md) (75+ functions documented) - -**...set up development environment** -→ [CODING_STANDARD.md](CODING_STANDARD.md) → [docs/BUILD_GUIDE.md](docs/BUILD_GUIDE.md) - -**...manage releases** -→ [VERSIONING.md](VERSIONING.md) → [.github/workflows/ci.yml](.github/workflows/ci.yml) - -**...understand refactoring** -→ [REFACTOR_REPORT.md](REFACTOR_REPORT.md) or [REFACTORING_SUMMARY.md](REFACTORING_SUMMARY.md) - ---- - -## 📊 Content Statistics - -| Category | Files | Lines | Purpose | -|----------|-------|-------|---------| -| **User Docs** | 3 | 1800 | Learning and reference | -| **Developer Docs** | 2 | 1000 | Development guidance | -| **Infrastructure** | 3 | 550 | Build & CI/CD | -| **Tests** | 1 | 400 | Testing examples | -| **Analysis** | 2 | 3000 | Refactoring summary | -| **TOTAL** | 11 | 6750 | Professional project | - ---- - -## ✅ Verification Checklist - -All deliverables have been completed: - -- ✅ Professional README (500 lines) -- ✅ Language specification (800 lines) -- ✅ Standard library docs (1500 lines) -- ✅ Coding standards (600 lines) -- ✅ Version management (400 lines) -- ✅ CI/CD pipeline (200 lines) -- ✅ Doxygen config (200 lines) -- ✅ Enhanced CMake (150 lines) -- ✅ Test templates (400 lines) -- ✅ Build guide (enhanced) -- ✅ Refactor report (2000 lines) -- ✅ Summary document (1000 lines) - -**Total: 6750+ lines of professional documentation and infrastructure** - ---- - -## 🚀 Next Steps - -1. **Review**: Read [REFACTOR_REPORT.md](REFACTOR_REPORT.md) for complete details -2. **Deploy**: Copy files to your ProXPL repository -3. **Test**: Run CI/CD pipeline on your GitHub -4. **Celebrate**: You now have a professional project! 🎉 - ---- - -## 📞 Support - -Questions about the refactoring? -- See [REFACTOR_REPORT.md](REFACTOR_REPORT.md) for details -- Check [REFACTORING_SUMMARY.md](REFACTORING_SUMMARY.md) for overview -- Review individual documentation files above - ---- - -**Document Version**: 1.0 -**Generated**: December 2024 -**Status**: ✅ Complete and Ready to Use diff --git a/README.md b/README.md index 0e568ea..fb2c96c 100644 --- a/README.md +++ b/README.md @@ -1,175 +1,260 @@ # ProXPL Programming Language -

- A Modern, Educational, Production-Ready Programming Language Compiler -

+
-

- Clean Syntax • Strong Typing • Rich Standard Library • C-Based Runtime +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Build Status](https://img.shields.io/badge/build-passing-brightgreen.svg)](https://github.com/ProgrammerKR/ProXPL) +[![Version](https://img.shields.io/badge/version-1.0.0-blue.svg)](https://github.com/ProgrammerKR/ProXPL/releases) +[![Platform](https://img.shields.io/badge/platform-win%20%7C%20linux%20%7C%20macos-lightgrey.svg)]() + +A Modern, Statically-Typed Programming Language with a Bytecode VM Runtime + +

+ Clean Syntax • Strong Type System • Rich Standard Library • C-Based Runtime

---- +[Quick Start](#-quick-start) • +[Installation](#-installation) • +[Documentation](#-documentation) • +[Architecture](#-architecture-overview) • +[Contributing](#-contributing) -## 📋 Table of Contents - -1. [What is ProXPL?](#what-is-proxpl) -2. [Key Features](#key-features) -3. [Quick Start](#quick-start) -4. [Installation](#installation) -5. [Language Features](#language-features) -6. [Architecture Overview](#architecture-overview) -7. [Project Structure](#project-structure) -8. [Building from Source](#building-from-source) -9. [Documentation](#documentation) -10. [Contributing](#contributing) -11. [Roadmap](#roadmap) -12. [License](#license) +
--- -## What is ProXPL? +## 📖 About ProXPL -**ProXPL** is a modern programming language designed for: +**ProXPL** is a modern programming language designed to bridge the gap between the simplicity of interpreted languages like Python and the performance of C-based runtimes. It is built for a wide range of applications, from educational compiler theory to efficient system tooling. -- 🎓 **Educational Use**: Learn compiler design, interpreters, and language implementation -- 🏗️ **System Tools**: Build fast, efficient command-line tools and utilities -- 📚 **Language Exploration**: Experiment with language design paradigms -- ⚡ **Production**: Deploy with a powerful, type-safe runtime +### The Philosophy +* **Clarity First**: Familiar curly-brace syntax (similar to JavaScript/Go) ensures a low learning curve. +* **Type Safety**: A strong type system (Compile-time & Runtime) prevents common errors before they happen. +* **Performance**: Source code is compiled to bytecode and executed on a custom, optimized stack-based Virtual Machine. +* **Batteries Included**: A rich standard library allows you to build useful applications immediately without external dependencies. -ProXPL bridges the gap between **simplicity** (Python-like syntax) and **performance** (C-based runtime). It combines: -- **Familiar Syntax**: Inspired by Python and JavaScript -- **Strong Type System**: Compile-time and runtime type checking -- **Fast Runtime**: Bytecode-compiled and executed on a custom VM -- **Rich Standard Library**: 75+ built-in functions for common tasks -- **Modular Architecture**: Clear separation of lexer, parser, compiler, and VM +--- ## 🚀 Key Features -* **Clean & Modern Syntax**: Familiar curly-brace syntax with Python-like readability. -* **Rich Standard Library**: **75+ built-in functions** for I/O, Math, Strings, Collections, Date/Time, and System utilities. -* **Strong Core**: Supports functions, classes, async/await, and error handling. -* **Zero-Dependency Runtime**: Compiles to standalone executables (via PyInstaller). -* **Strict Specification**: Well-defined grammar with 45 keywords, 42 operators, and 12 core data types. +| Feature | Description | +|---------|-------------| +| 🔤 **Modern Syntax** | Clean, readable syntax inspired by Python and JavaScript. | +| ⚡ **Fast Runtime** | Zero-dependency binaries compiled to bytecode, executed on a custom VM. | +| 📦 **Rich Stdlib** | **75+ built-in functions** for I/O, Math, Strings, Collections, and System tasks. | +| 🛡️ **Strong Typing** | Statically typed with support for type inference and explicit conversion. | +| 🧩 **Modularity** | robust `use` keyword system for importing modules and local files. | +| 🛠️ **PRM Included** | Integrated **ProX Repository Manager** for managing packages. | +| 🏗️ **Architecture** | Classic Compiler Design: Lexer → Parser (AST) → Compiler → Bytecode → VM. | -## 📥 Installation +--- + +## ⚡ Quick Start -### Option 1: Download Binaries (Recommended) -No Python installation required. Download the latest release for your OS: +### 1. Your First Program +Create a file named `hello.prox`: + +```javascript +// hello.prox +func main() { + print("Welcome to ProXPL!"); -- **Windows**: [Download `prox.exe`](https://github.com/ProgrammerKR/ProXPL/releases/latest) -- **Linux/macOS**: [Download `prox`](https://github.com/ProgrammerKR/ProXPL/releases/latest) + let name = input("Enter your name: "); + print("Hello, " + name + "!"); -Add the downloaded file to your system `PATH` to run it from anywhere. + // Generate a random number using the standard library + let lucky = random(1, 100); + print("Your lucky number is: " + to_string(lucky)); +} -### Option 2: Install via Pip -If you have Python 3.8+ installed, you can install ProXPL as a package: +main(); +``` +### 2. Run It ```bash -pip install . +prox hello.prox +``` + +### 3. Output +```text +Welcome to ProXPL! +Enter your name: Alice +Hello, Alice! +Your lucky number is: 42 ``` -*(Run this command in the root directory of the repository)* -### Option 3: Run from Source -Clone the repository and run directly: +--- + +## 📥 Installation + +### Option 1: Pre-built Binaries (Recommended) +No compilation required. Download the latest release for your OS: + +* **Windows**: [Download `prox.exe`](https://github.com/ProgrammerKR/ProXPL/releases/latest) +* **Linux**: [Download `prox`](https://github.com/ProgrammerKR/ProXPL/releases/latest) +* **macOS**: [Download `prox-macos`](https://github.com/ProgrammerKR/ProXPL/releases/latest) + +Add the executable to your system `PATH` to run it from anywhere. + +### Option 2: Build from Source (CMake) +Requirements: **GCC/Clang** (C99+), **CMake** 3.10+, **Git**. + ```bash +# Clone the repository git clone https://github.com/ProgrammerKR/ProXPL.git cd ProXPL -pip install -r requirements.txt # If any -python -m cli.main examples/hello.prox + +# Create build directory +mkdir build && cd build + +# Configure and build +cmake -DCMAKE_BUILD_TYPE=Release .. +make + +# Install (Optional) +sudo make install ``` -## ⚡ Getting Started +--- -### 1. Your First Program -Create a file named `hello.prox`: +## 💻 Language Tour + +### Variables & Collections +ProXPL supports 12 core data types, including Lists and Dictionaries. ```javascript -// hello.prox +let message = "System Active"; +let count = 42; +let list = [1, 2, 3, 4]; +let config = {"host": "localhost", "port": 8080}; + +push(list, 5); +print(config["host"]); +``` + +### Functions & Control Flow +```javascript +func fibonacci(n) { + if (n <= 1) return n; + return fibonacci(n - 1) + fibonacci(n - 2); +} + func main() { - let name = input("Enter your name: "); - print("Hello, " + name + "!"); + for (let i = 0; i < 10; i = i + 1) { + print("fib(" + to_string(i) + ") = " + to_string(fibonacci(i))); + } } +``` -main(); +### Module System +ProXPL uses the `use` keyword for modularity. Circular imports are handled automatically. + +```javascript +use math; // Import standard library +use utils/io; // Import installed package +use local_helper; // Import local file + +print(math.sqrt(16)); ``` -### 2. Run It -Open your terminal and run: +### Package Manager (PRM) +Manage dependencies using the built-in **ProX Repository Manager**. ```bash -prox hello.prox +prm install utils/io # Install a package +prm list # List installed packages +prm search http # Search the registry ``` -### 3. Build It (Coming Soon) -ProXPL handles immediate execution today. Future versions will support compiling to bytecode. +--- -## 📚 Documentation +## 🏗️ Architecture Overview -Detailed documentation is available to help you master ProXPL: +ProXPL follows a professional three-phase compiler architecture aimed at maintainability and performance. -- **[Language Specification](docs/language-spec.md)**: Explore the complete syntax, keywords, types, and operator reference. -- **[Standard Library](docs/language-spec.md#standard-library)**: Reference for all built-in functions. +```mermaid +graph LR + A[Source Code] --> B[Lexer] + B --> C[Parser / AST] + C --> D[Type Checker] + D --> E[Compiler] + E --> F[Bytecode Chunk] + F --> G[Virtual Machine] + G --> H[Execution] +``` + +### Core Components +| Component | Location | Responsibility | +|-----------|----------|----------------| +| **Lexer** | `src/lexer/scanner.c` | Converts source code into tokens. | +| **Parser** | `src/parser/parser.c` | Constructs the Abstract Syntax Tree (AST). | +| **Compiler** | `src/runtime/compiler.c` | Emits optimized bytecode instructions. | +| **VM** | `src/runtime/vm.c` | Stack-based virtual machine that executes bytecode. | +| **Memory** | `src/runtime/memory.c` | Garbage collection and memory allocation. | + +--- ## 📂 Project Structure ```text ProXPL/ -├── cli/ # Command-line interface entry points -├── core/ # Compiler core (Lexer, Parser, AST, VM) -├── docs/ # Documentation and Specifications -├── examples/ # Example ProXPL programs -├── stdlib/ # Standard library implementation -├── tests/ # Unit and integration tests -└── scripts/ # Build and utility scripts +├── include/ # Header files (Interfaces) +│ ├── vm.h +│ ├── compiler.h +│ └── stdlib_native.h +├── src/ # Implementation Source +│ ├── main.c # Entry point +│ ├── lexer/ # Tokenizer logic +│ ├── parser/ # AST and Type Checking +│ ├── runtime/ # VM and Garbage Collector +│ └── stdlib/ # Native Standard Library impl +├── cli/ # PRM and CLI tools +├── examples/ # ProXPL code samples +├── docs/ # Specifications and Guides +└── tests/ # Unit and Integration tests ``` -## Modules & Packages - -ProXPL supports a robust module system using the `use` keyword. - -```prox -// Import standard library module -use math; +--- -// Import installed package -use utils/io; +## 📚 Documentation -// Import local file -use my_local_module; +Detailed documentation is available in the `docs/` directory: -print(PI); -``` +* **[Language Specification](docs/language-spec.md)**: Grammar, Keywords, and Operators. +* **[Standard Library Reference](docs/stdlib.md)**: Documentation for all 75+ built-in functions. +* **[Architecture Guide](docs/architecture.md)**: Deep dive into the VM and Compiler internals. +* **[Build Guide](docs/BUILD_GUIDE.md)**: Platform-specific instructions (Windows/Linux/Mac). -Circular imports are detected and prevent execution. Modules are executed only once. - -## Package Manager (PRM) +--- -ProXPL includes **PRM (ProX Repository Manager)** to manage dependencies. +## 🛣️ Roadmap -**Commands:** -- `prm install `: Download and install a package. -- `prm list`: List installed packages. -- `prm search `: Search the registry. -- `prm remove `: Uninstall a package. +* **v0.1.0** (Current): Core language, VM, Stdlib, Basic I/O. +* **v0.2.0**: Class-based OOP, Advanced Error Handling. +* **v0.3.0**: Native Foreign Function Interface (FFI). +* **v1.0.0**: Production Stability, Async/Await Support. -Example: -```bash -python cli/prm.py install utils/io -``` -(Note: You can alias `prm` to run this script directly) +--- ## 🛠️ Contributing -We welcome contributors! ProXPL is an educational project perfect for learning about compilers and interpreters. +We welcome contributors! ProXPL is an excellent project for learning compiler design. -1. Fork the repository. -2. Create your feature branch (`git checkout -b feature/AmazingFeature`). -3. Commit your changes (`git commit -m 'Add some AmazingFeature'`). -4. Push to the branch (`git push origin feature/AmazingFeature`). -5. Open a Pull Request. +1. **Fork** the repository. +2. Create a feature branch (`git checkout -b feature/AmazingFeature`). +3. Commit your changes following the [Coding Standard](CODING_STANDARD.md). +4. Push to the branch and Open a **Pull Request**. -Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct and development process. +Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct. + +--- ## 📄 License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +--- + +

+ Built with ❤️ by the ProXPL Community +

\ No newline at end of file diff --git a/README_IMPROVED.md b/README_IMPROVED.md deleted file mode 100644 index 4a8db01..0000000 --- a/README_IMPROVED.md +++ /dev/null @@ -1,568 +0,0 @@ -# ProXPL Programming Language - -

- A Modern, Production-Ready Programming Language with Bytecode VM Runtime -

- -

- Clean Syntax • Strong Type System • Rich Standard Library • C-Based Runtime -

- -

- Quick Start • - Installation • - Documentation • - Contributing • - License -

- ---- - -## Table of Contents - -1. [About ProXPL](#about-proxpl) -2. [Key Features](#key-features) -3. [Language Goals](#language-goals) -4. [Quick Start](#quick-start) -5. [Installation & Building](#installation--building) -6. [Usage Examples](#usage-examples) -7. [Architecture Overview](#architecture-overview) -8. [Documentation](#documentation) -9. [Project Structure](#project-structure) -10. [Contributing](#contributing) -11. [Support & Community](#support--community) -12. [Roadmap](#roadmap) -13. [License](#license) - ---- - -## About ProXPL - -**ProXPL** is a modern, statically-typed programming language designed for: - -- 🎓 **Educational Purpose**: Learn compiler design, interpreter implementation, and language architecture -- 🏗️ **System Tools**: Build efficient command-line utilities and system tools -- 💡 **Language Exploration**: Experiment with programming paradigms and language design -- ⚡ **Production Use**: Deploy type-safe, high-performance applications - -### The ProXPL Philosophy - -ProXPL bridges the gap between **Python-like simplicity** and **C-like performance**. It provides: - -- **Familiar Syntax**: Curly-brace syntax inspired by JavaScript/Go with Python readability -- **Strong Type System**: Compile-time type checking with runtime validation -- **Fast Execution**: Bytecode compilation to a custom stack-based virtual machine -- **Rich Standard Library**: 75+ built-in functions for common programming tasks -- **Clean Architecture**: Clear separation of lexer, parser, compiler, and VM components - ---- - -## Key Features - -| Feature | Description | -|---------|-------------| -| 🔤 **Clean Syntax** | Familiar C-style syntax with Python-like readability | -| 🔒 **Strong Types** | Compile-time and runtime type checking for safety | -| ⚡ **Fast Runtime** | Bytecode-compiled and executed on a custom VM | -| 📦 **Rich Standard Library** | 75+ built-in functions for I/O, math, strings, collections, datetime, and system | -| 🎯 **Focused Design** | 45 keywords, 42 operators, 12 core data types | -| 📚 **Well-Documented** | Comprehensive guides, tutorials, and API documentation | -| 🔧 **Easy to Extend** | Modular architecture for adding new features | -| 🧪 **Testable** | Full test suite with unit and integration tests | - -### Standard Library Highlights - -- **I/O Functions**: print, input, read_file, write_file -- **Math Functions**: sqrt, pow, sin, cos, log, random, and more -- **String Functions**: split, join, replace, upper, lower, trim, substring -- **Collections**: Lists, dictionaries, sets with native operations -- **System**: Platform detection, file operations, process execution -- **DateTime**: Timestamps, date formatting, sleep timers -- **Type Conversion**: Automatic and explicit type conversion utilities - ---- - -## Language Goals - -ProXPL was designed with these core principles: - -1. **Clarity First**: Code should be easy to read and understand -2. **Type Safety**: Catch errors at compile-time when possible -3. **Performance**: Bytecode VM provides fast execution -4. **Simplicity**: Learn the language in a weekend, not a year -5. **Modularity**: Components should be independent and reusable -6. **Community**: Foster learning and collaboration - ---- - -## Quick Start - -### 1. Your First Program - -Create a file named `hello.prox`: - -```javascript -// hello.prox - Your first ProXPL program -func main() { - print("Welcome to ProXPL!"); - - let name = input("What is your name? "); - print("Hello, " + name + "!"); - - let lucky = random(1, 100); - print("Your lucky number is: " + to_string(lucky)); -} - -main(); -``` - -### 2. Run It - -**Using the executable:** -```bash -prox hello.prox -``` - -**Output:** -``` -Welcome to ProXPL! -What is your name? Alice -Hello, Alice! -Your lucky number is: 42 -``` - -### 3. More Examples - -See the [examples/](examples/) directory for: -- [hello.prox](examples/hello.prox) - Hello World -- [fibonacci.prox](examples/fibonacci.prox) - Recursion demo -- [calculator.prox](examples/calculator.prox) - Interactive calculator -- [use_stdlib.prox](examples/use_stdlib.prox) - Standard library showcase - ---- - -## Installation & Building - -### Option 1: Download Pre-built Binaries - -Pre-built executables are available for all major platforms: - -- **Windows**: [Download prox.exe](https://github.com/ProgrammerKR/ProXPL/releases/latest) -- **Linux**: [Download prox](https://github.com/ProgrammerKR/ProXPL/releases/latest) -- **macOS**: [Download prox-macos](https://github.com/ProgrammerKR/ProXPL/releases/latest) - -Add to your system `PATH` and run anywhere: -```bash -prox your_script.prox -``` - -### Option 2: Build from Source - -#### Prerequisites - -- **GCC or Clang** compiler (C99 standard) -- **CMake** 3.10+ (recommended) -- **Make** (for Makefile method) -- **Git** (to clone the repository) - -#### Build Steps - -**Using CMake (Recommended):** - -```bash -# Clone the repository -git clone https://github.com/ProgrammerKR/ProXPL.git -cd ProXPL - -# Create build directory -mkdir build -cd build - -# Configure and build -cmake .. -make - -# Optional: Install to system -sudo make install -``` - -**Using Make:** - -```bash -git clone https://github.com/ProgrammerKR/ProXPL.git -cd ProXPL/src - -# Build -make - -# Run directly -./prox ../examples/hello.prox -``` - -**Platform-Specific Notes:** - -- **Linux**: Uses standard GCC toolchain -- **macOS**: Ensure Command Line Tools installed (`xcode-select --install`) -- **Windows**: Use MinGW or WSL2 - -See [BUILD_GUIDE.md](docs/BUILD_GUIDE.md) for detailed platform-specific instructions. - ---- - -## Usage Examples - -### Example 1: Variables and Types - -```javascript -// Variables and type system -let message = "Hello"; -let count = 42; -let pi = 3.14159; -let active = true; - -print(message + " " + to_string(count)); - -let list = [1, 2, 3, 4, 5]; -let dict = {"name": "Alice", "age": 30}; -``` - -### Example 2: Functions and Control Flow - -```javascript -// Function definition -func fibonacci(n) { - if (n <= 1) return n; - return fibonacci(n - 1) + fibonacci(n - 2); -} - -func main() { - for (let i = 0; i < 10; i = i + 1) { - print("fib(" + to_string(i) + ") = " + to_string(fibonacci(i))); - } -} - -main(); -``` - -### Example 3: Error Handling - -```javascript -func safe_divide(a, b) { - if (b == 0) { - return null; - } - return a / b; -} - -func main() { - let result = safe_divide(10, 2); - if (result != null) { - print("Result: " + to_string(result)); - } -} - -main(); -``` - -### Example 4: String Manipulation - -```javascript -func main() { - let text = " Hello, World! "; - - print(len(text)); // 17 - print(trim(text)); // "Hello, World!" - print(upper(text)); // " HELLO, WORLD! " - print(lower(text)); // " hello, world! " - - let words = split(trim(text), " "); - print(len(words)); // 2 - print(words[0]); // "Hello," -} - -main(); -``` - -### Example 5: Collections - -```javascript -func main() { - // Lists - let nums = [10, 20, 30]; - push(nums, 40); - print(nums); // [10, 20, 30, 40] - - // Dictionaries - let person = {"name": "Bob", "age": 25}; - print(person["name"]); // "Bob" - print(keys(person)); // ["name", "age"] - - // Range - let range = range(1, 5); // [1, 2, 3, 4] - print(range); -} - -main(); -``` - ---- - -## Architecture Overview - -ProXPL follows a classic **three-phase compiler architecture**: - -``` -SOURCE CODE - ↓ -LEXICAL ANALYSIS (Tokenization) - ↓ -PARSING (AST Construction) - ↓ -TYPE CHECKING - ↓ -COMPILATION (Bytecode Generation) - ↓ -EXECUTION (Virtual Machine) - ↓ -OUTPUT -``` - -### Core Components - -| Component | Purpose | File(s) | -|-----------|---------|---------| -| **Lexer** | Tokenize source code | `src/lexer/scanner.c` | -| **Parser** | Build Abstract Syntax Tree | `src/parser/parser.c`, `src/parser/ast.c` | -| **Type Checker** | Validate types | `src/parser/type_checker.c` | -| **Compiler** | Generate bytecode | `src/runtime/compiler.c` | -| **VM** | Execute bytecode | `src/runtime/vm.c` | -| **Standard Library** | Built-in functions | `src/stdlib/*.c` | -| **Memory Manager** | GC and allocation | `src/runtime/memory.c` | - -For detailed architecture, see [ARCHITECTURE.md](ARCHITECTURE.md). - ---- - -## Documentation - -### Core Documentation - -- **[README.md](README.md)** - This file; overview and getting started -- **[ARCHITECTURE.md](ARCHITECTURE.md)** - Detailed system architecture -- **[LANGUAGE_SPEC.md](docs/language-spec/grammar.md)** - Complete language specification -- **[STDLIB_DOC.md](STDLIB_DOC.md)** - Standard library reference -- **[CODING_STANDARD.md](CODING_STANDARD.md)** - Development guidelines - -### Getting Started Guides - -- **[BUILD_GUIDE.md](docs/BUILD_GUIDE.md)** - Platform-specific build instructions -- **[Tutorials](docs/tutorials/)** - Step-by-step learning guides -- **[CONTRIBUTING.md](CONTRIBUTING.md)** - How to contribute - -### Advanced Topics - -- **[Bytecode Format](docs/ir-spec/bytecode_format.md)** - VM bytecode specification -- **[Type System](docs/language-spec/reference_manual.md)** - Type checking details -- **[Security Model](docs/security/security_model.md)** - Security considerations - ---- - -## Project Structure - -``` -ProXPL/ -├── include/ # Header files -│ ├── vm.h # Virtual machine interface -│ ├── compiler.h # Compiler interface -│ ├── parser.h # Parser interface -│ ├── scanner.h # Lexer interface -│ ├── ast.h # AST definitions -│ ├── value.h # Value type system -│ ├── object.h # Runtime objects -│ ├── memory.h # Memory management -│ ├── stdlib_native.h # Standard library -│ └── ... -│ -├── src/ # Implementation files -│ ├── main.c # Entry point -│ ├── lexer/ -│ │ └── scanner.c # Tokenizer -│ ├── parser/ -│ │ ├── parser.c # Parser -│ │ ├── ast.c # AST builder -│ │ └── type_checker.c -│ ├── runtime/ -│ │ ├── vm.c # Virtual machine -│ │ ├── compiler.c # Bytecode compiler -│ │ ├── chunk.c # Bytecode chunks -│ │ ├── value.c # Values and types -│ │ ├── object.c # Runtime objects -│ │ ├── memory.c # Memory management -│ │ └── debug.c # Debugging utilities -│ └── stdlib/ -│ ├── stdlib_core.c # Core functions -│ ├── io_native.c # I/O functions -│ ├── math_native.c # Math functions -│ ├── string_native.c # String functions -│ ├── convert_native.c # Type conversion -│ └── system_native.c # System functions -│ -├── examples/ # Example programs -│ ├── hello.prox -│ ├── fibonacci.prox -│ ├── calculator.prox -│ └── ... -│ -├── tests/ # Test suite -│ ├── unit/ # Unit tests -│ ├── integration/ # Integration tests -│ └── fixtures/ # Test data -│ -├── docs/ # Documentation -│ ├── BUILD_GUIDE.md -│ ├── language-spec/ -│ ├── architecture/ -│ ├── ir-spec/ -│ ├── tutorials/ -│ └── ... -│ -├── CMakeLists.txt # CMake configuration -├── Makefile # Make configuration -├── ARCHITECTURE.md # Architecture guide -├── LANGUAGE_SPEC.md # Language specification -├── STDLIB_DOC.md # Standard library docs -├── CODING_STANDARD.md # Code guidelines -├── CONTRIBUTING.md # Contribution guide -└── LICENSE # MIT License -``` - ---- - -## Contributing - -We welcome contributions! Whether you want to: - -- 🐛 Report bugs or request features -- 📝 Improve documentation -- 💻 Contribute code -- 🧪 Add tests -- 📢 Help with community - -See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines. - -### Quick Contribution Steps - -1. **Fork** the repository -2. **Create** a feature branch (`git checkout -b feature/amazing-feature`) -3. **Make** your changes following [CODING_STANDARD.md](CODING_STANDARD.md) -4. **Test** thoroughly with `make test` -5. **Commit** with clear messages -6. **Push** to your fork -7. **Open** a Pull Request - -### Development Setup - -```bash -# Clone your fork -git clone https://github.com/YOUR_USERNAME/ProXPL.git -cd ProXPL - -# Create development build -mkdir build && cd build -cmake -DCMAKE_BUILD_TYPE=Debug .. -make - -# Run tests -make test - -# Run linter -make lint -``` - ---- - -## Support & Community - -### Getting Help - -- 📖 **Documentation**: See [docs/](docs/) for comprehensive guides -- 🐛 **Issue Tracker**: [GitHub Issues](https://github.com/ProgrammerKR/ProXPL/issues) -- 💬 **Discussions**: [GitHub Discussions](https://github.com/ProgrammerKR/ProXPL/discussions) -- 📧 **Email**: contact@proxpl.dev - -### Community Guidelines - -- Be respectful and inclusive -- Follow [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) -- Help others learn and grow -- Share your projects and ideas - ---- - -## Roadmap - -### Version 0.1.0 (Current) -- ✅ Core language features -- ✅ Standard library (75+ functions) -- ✅ Documentation and examples -- ✅ Build infrastructure - -### Version 0.2.0 (Planned) -- 📋 Class-based OOP -- 📋 Module system -- 📋 Advanced error handling -- 📋 Performance optimizations - -### Version 0.3.0 (Future) -- 📋 Async/await support -- 📋 Standard package manager -- 📋 FFI (Foreign Function Interface) -- 📋 Full Unicode support - -### Version 1.0.0 (Long Term) -- 📋 Production stability guarantee -- 📋 Extensive ecosystem -- 📋 Enterprise features - -For more details, see [CHANGELOG.md](CHANGELOG.md). - ---- - -## License - -ProXPL is released under the **MIT License**. See [LICENSE](LICENSE) for details. - -``` -MIT License - -Copyright (c) 2024-2025 ProXPL Contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -``` - ---- - -## Acknowledgments - -ProXPL is built on principles learned from: - -- **Lox** (Robert Nystrom's language learning project) -- **Python** (Clean syntax and standard library design) -- **Go** (Simplicity and pragmatism) -- **Rust** (Type safety and performance) - -Special thanks to all contributors and the community! - ---- - -**Happy coding with ProXPL!** 🚀 - -For the latest updates, visit: https://github.com/ProgrammerKR/ProXPL diff --git a/REFACTORING_SUMMARY.md b/REFACTORING_SUMMARY.md deleted file mode 100644 index 3878527..0000000 --- a/REFACTORING_SUMMARY.md +++ /dev/null @@ -1,460 +0,0 @@ -# ProXPL Professional Refactoring - Complete Summary - -**Status**: ✅ COMPLETE -**Date**: December 2024 -**Version**: 0.1.0 - ---- - -## 🎯 Mission Accomplished - -The ProXPL programming language has been successfully refactored from a basic prototype into a **professional, production-ready open-source project**. All 9 major refactoring tasks have been completed with industry-standard practices. - ---- - -## 📋 Executive Summary - -### What Was Done - -This comprehensive refactoring introduced: - -1. ✅ **Professional Documentation** (5000+ lines) - - Rewritten README.md with comprehensive guide - - Complete LANGUAGE_SPEC.md covering all language features - - Full STDLIB_DOC.md with 75+ functions documented - - CODING_STANDARD.md for development guidelines - - VERSIONING.md with semantic versioning strategy - - Enhanced BUILD_GUIDE.md with platform-specific instructions - -2. ✅ **Semantic Versioning & Release Infrastructure** - - Implemented SemVer 2.0.0 compliance - - Created release procedure documentation - - Automated artifact generation - - Version management in code - -3. ✅ **CI/CD Pipeline** - - GitHub Actions workflow for all major OS (Linux, macOS, Windows) - - Automated builds, tests, and linting - - Cross-platform binary generation - - Automated release creation - - Memory leak detection (Valgrind) - -4. ✅ **Testing Framework** - - Unity test framework integration - - Unit test templates for all components - - Integration test structure - - CMake test discovery - -5. ✅ **Development Standards** - - CODING_STANDARD.md (600+ lines) - - Naming conventions (snake_case, PascalCase, UPPER_SNAKE_CASE) - - Memory management patterns - - Code review checklist - - Git workflow guidelines - -6. ✅ **Build Infrastructure** - - Modern CMake configuration (with improvements) - - Custom build targets (format, lint, test, docs) - - Cross-platform compiler support - - Optimization control (Debug/Release) - -7. ✅ **Consistency & Quality** - - Header guards and organization standards - - Circular dependency elimination - - Module boundary clarity - - Static analysis integration - -8. ✅ **Documentation Generation** - - Doxygen configuration for API docs - - Source code browsing setup - - Dependency graphs - - HTML and PDF output - -9. ✅ **Professional Output** - - REFACTOR_REPORT.md (2000+ lines) - - Complete before/after comparison - - Deployment checklist - - Roadmap through v1.0.0 - ---- - -## 📁 Files Created/Modified - -### New Documentation Files -``` -✅ README_IMPROVED.md (500 lines) - Enhanced project overview -✅ LANGUAGE_SPEC.md (800 lines) - Complete language specification -✅ STDLIB_DOC.md (1500 lines) - Standard library reference -✅ CODING_STANDARD.md (600 lines) - Development guidelines -✅ VERSIONING.md (400 lines) - Version management strategy -✅ REFACTOR_REPORT.md (2000 lines) - This refactoring summary -``` - -### New Infrastructure Files -``` -✅ .github/workflows/ci.yml (200 lines) - CI/CD pipeline -✅ Doxyfile (200 lines) - Documentation generation -✅ CMakeLists_IMPROVED.txt (150 lines) - Enhanced build system -``` - -### New Test Files -``` -✅ tests/unit/test_scanner_template.c (400 lines) - Test framework example -``` - -### Enhanced Existing Files -``` -✅ docs/BUILD_GUIDE.md (Enhanced) - Platform-specific instructions -``` - -### Total New Content -``` -📊 ~6000+ lines of professional documentation and infrastructure code -``` - ---- - -## 🚀 Key Features - -### For Users -- **Clear Getting Started**: 5 code examples in README -- **Complete Language Reference**: LANGUAGE_SPEC.md covers syntax, types, operators -- **Function Documentation**: All 75+ stdlib functions documented with examples -- **Platform Support**: Linux, macOS, Windows, Docker instructions -- **Build Guide**: Platform-specific build instructions - -### For Developers -- **Code Standards**: Detailed naming, formatting, memory management rules -- **Architecture Guide**: ARCHITECTURE.md explains compiler pipeline -- **Development Setup**: Debug builds with sanitizers -- **Code Review Checklist**: 10-point checklist for quality -- **Git Workflow**: Semantic commits, branch naming, PR process - -### For Contributors -- **CONTRIBUTING.md**: Step-by-step contribution guide -- **CODE_OF_CONDUCT.md**: Community standards -- **Test Templates**: Ready-to-use Unity test examples -- **CI/CD Validation**: Automated testing on all platforms -- **Documentation**: How to document code - -### For Maintainers -- **Release Process**: Automated via CI/CD -- **Version Management**: SemVer compliance -- **Change Log**: Clear format for tracking changes -- **Roadmap**: v0.1.0 through v1.0.0 planned -- **Quality Metrics**: Testing, coverage, linting standards - ---- - -## 📊 Documentation Coverage - -### Before Refactoring -- README.md: ~100 lines -- ARCHITECTURE.md: ~900 lines (existing) -- CHANGELOG.md: ~300 lines (existing) -- Total: ~1300 lines - -### After Refactoring -- README_IMPROVED.md: ~500 lines -- LANGUAGE_SPEC.md: ~800 lines -- STDLIB_DOC.md: ~1500 lines -- CODING_STANDARD.md: ~600 lines -- VERSIONING.md: ~400 lines -- REFACTOR_REPORT.md: ~2000 lines -- BUILD_GUIDE.md: ~400 lines (enhanced) -- Doxyfile: ~200 lines -- CI/CD workflow: ~200 lines -- Test templates: ~400 lines -- **Total: ~6500+ lines** of new professional content - -**Increase**: 5× more documentation - ---- - -## 🔧 Technology Stack - -### Build & Compilation -- **CMake** 3.10+ for cross-platform builds -- **C99** standard for maximum compatibility -- **Make** as fallback build system -- **gcc/clang/msvc** compiler support - -### Quality Assurance -- **clang-format** for code formatting -- **clang-tidy** for static analysis -- **valgrind** for memory checking -- **unity** test framework - -### Documentation -- **Doxygen** for API documentation -- **Markdown** for guides and specs -- **GitHub Actions** for automated builds and docs - -### Version Control -- **Git** with semantic versioning -- **GitHub** with automated releases - ---- - -## 📈 Quality Improvements - -| Aspect | Before | After | Improvement | -|--------|--------|-------|-------------| -| Documentation | Basic | Comprehensive | 5× increase | -| Test Framework | None | Unity integrated | ✅ Added | -| CI/CD | Manual | Fully automated | ✅ Added | -| Code Standards | Informal | CODING_STANDARD.md | ✅ Documented | -| Build System | Make only | CMake + Make | ✅ Enhanced | -| API Docs | Manual | Doxygen auto | ✅ Added | -| Version Strategy | Ad-hoc | SemVer 2.0.0 | ✅ Formalized | -| Release Process | Manual | Automated | ✅ Automated | -| Build Platforms | Single | Multi-platform | ✅ Expanded | - ---- - -## 🎓 Learning Resources - -### For New Users -1. **Start Here**: [README_IMPROVED.md](README_IMPROVED.md) -2. **Learn Language**: [LANGUAGE_SPEC.md](LANGUAGE_SPEC.md) -3. **Use Functions**: [STDLIB_DOC.md](STDLIB_DOC.md) -4. **Try Examples**: [examples/](examples/) - -### For Developers -1. **Build Guide**: [docs/BUILD_GUIDE.md](docs/BUILD_GUIDE.md) -2. **Architecture**: [ARCHITECTURE.md](ARCHITECTURE.md) -3. **Standards**: [CODING_STANDARD.md](CODING_STANDARD.md) -4. **Contribute**: [CONTRIBUTING.md](CONTRIBUTING.md) - -### For Maintainers -1. **Version Strategy**: [VERSIONING.md](VERSIONING.md) -2. **Release Process**: [VERSIONING.md#release-procedure](VERSIONING.md) -3. **Roadmap**: [VERSIONING.md#roadmap](VERSIONING.md) -4. **Quality Goals**: [REFACTOR_REPORT.md#quality-metrics](REFACTOR_REPORT.md) - ---- - -## 🔄 Implementation Workflow - -### For Users -``` -1. Download/build from [docs/BUILD_GUIDE.md] -2. Read [README_IMPROVED.md] for overview -3. Learn from [examples/] folder -4. Reference [LANGUAGE_SPEC.md] for syntax -5. Look up functions in [STDLIB_DOC.md] -``` - -### For Contributors -``` -1. Fork repository -2. Read [CONTRIBUTING.md] -3. Follow [CODING_STANDARD.md] -4. Create feature branch -5. Write tests following [tests/unit/test_*] -6. Run: make format && make lint && make test -7. Submit pull request -8. CI/CD validates automatically -``` - -### For Releases -``` -1. Update version numbers -2. Update [CHANGELOG.md] -3. Run: make clean && make test -4. Tag: git tag -a v0.2.0 -5. Push: git push origin v0.2.0 -6. CI/CD automatically: - - Builds all platforms - - Runs all tests - - Generates documentation - - Creates GitHub Release -``` - ---- - -## ✨ Highlights - -### Professional Documentation -- 5000+ lines of comprehensive guides -- Examples for every feature -- Platform-specific instructions -- Multiple learning paths - -### Automated Quality -- Every commit is tested on 3 platforms -- Code formatting automatically checked -- Static analysis on all commits -- Memory leaks detected and reported - -### Developer Experience -- Clear coding guidelines -- Test framework integrated -- Build system optimized -- Documentation auto-generated - -### Community Ready -- CODE_OF_CONDUCT.md established -- CONTRIBUTING.md with clear steps -- Issue templates ready -- Discussion board enabled - -### Production Ready -- Semantic versioning implemented -- Release automation configured -- Backward compatibility policy -- Maintenance schedule defined - ---- - -## 🎯 Next Steps - -### Immediate (v0.1.x) -- [ ] Review and test all documentation -- [ ] Expand unit test coverage to 80% -- [ ] Community feedback integration -- [ ] Performance optimization - -### Short Term (v0.2.0 - Q1 2025) -- [ ] Implement class-based OOP -- [ ] Add module/import system -- [ ] Enhance error messages -- [ ] Expand standard library - -### Medium Term (v0.3.0 - Q2 2025) -- [ ] Async/await support -- [ ] Generator functions -- [ ] Decorator syntax -- [ ] Pattern matching - -### Long Term (v1.0.0 - Q3 2025) -- [ ] API freeze for stability -- [ ] Production-ready guarantee -- [ ] Comprehensive tooling -- [ ] Official language specification - ---- - -## 📞 Support & Community - -### Getting Help -- 📖 **Documentation**: See [docs/](docs/) for guides -- 🐛 **Issues**: [GitHub Issues](https://github.com/ProgrammerKR/ProXPL/issues) -- 💬 **Discussions**: [GitHub Discussions](https://github.com/ProgrammerKR/ProXPL/discussions) -- 📧 **Email**: contact@proxpl.dev - -### Community Resources -- **Examples**: [examples/](examples/) folder with 6+ programs -- **Tutorials**: [docs/tutorials/](docs/tutorials/) with step-by-step guides -- **Code of Conduct**: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) - ---- - -## 📋 Deployment Checklist - -Before v1.0.0, verify: - -- [ ] All tests pass (unit + integration) -- [ ] Code coverage ≥80% -- [ ] Zero compiler warnings -- [ ] Documentation complete and accurate -- [ ] Changelog entries for all changes -- [ ] Version numbers synchronized -- [ ] Release notes drafted -- [ ] Tested on Linux, macOS, Windows -- [ ] Performance benchmarked -- [ ] Security review completed -- [ ] API stable and documented -- [ ] Backward compatibility maintained - ---- - -## 📚 File Reference - -### Documentation Files -| File | Lines | Purpose | -|------|-------|---------| -| [README_IMPROVED.md](README_IMPROVED.md) | 500 | Project overview & getting started | -| [LANGUAGE_SPEC.md](LANGUAGE_SPEC.md) | 800 | Complete language specification | -| [STDLIB_DOC.md](STDLIB_DOC.md) | 1500 | Standard library reference | -| [CODING_STANDARD.md](CODING_STANDARD.md) | 600 | Development guidelines | -| [VERSIONING.md](VERSIONING.md) | 400 | Version management strategy | -| [REFACTOR_REPORT.md](REFACTOR_REPORT.md) | 2000 | This refactoring summary | -| [docs/BUILD_GUIDE.md](docs/BUILD_GUIDE.md) | 400 | Build instructions (enhanced) | - -### Infrastructure Files -| File | Purpose | -|------|---------| -| [.github/workflows/ci.yml](.github/workflows/ci.yml) | GitHub Actions CI/CD pipeline | -| [Doxyfile](Doxyfile) | Doxygen documentation config | -| [CMakeLists_IMPROVED.txt](CMakeLists_IMPROVED.txt) | Enhanced CMake build config | - -### Test Files -| File | Purpose | -|------|---------| -| [tests/unit/test_scanner_template.c](tests/unit/test_scanner_template.c) | Unity test framework example | - ---- - -## 🏆 Achievement Summary - -✅ **Documentation**: 5000+ lines of professional guides -✅ **Code Standards**: Complete guidelines with examples -✅ **CI/CD**: Automated on 3 platforms (Linux, macOS, Windows) -✅ **Testing**: Framework integrated with 30+ example tests -✅ **Build System**: Modern CMake with multiple targets -✅ **Version Management**: SemVer 2.0.0 compliant -✅ **API Documentation**: Doxygen configuration ready -✅ **Community**: CODE_OF_CONDUCT.md and CONTRIBUTING.md -✅ **Release Process**: Fully automated via CI/CD - -**Total**: 9/9 refactoring tasks completed ✨ - ---- - -## 🎓 How to Use This Refactoring - -### For the Project -Copy these files to your ProXPL repository: -- Replace README.md with content from README_IMPROVED.md -- Add all new documentation files -- Add .github/workflows/ci.yml for CI/CD -- Add/update Doxyfile for documentation generation -- Update CMakeLists.txt with improvements from CMakeLists_IMPROVED.txt - -### For Your Own Project -Use this refactoring as a template for: -- Professional language project setup -- Documentation structure -- CI/CD pipeline configuration -- Code standards documentation -- Test framework integration - -### For Education -Learn about: -- Language specification writing -- Professional project organization -- CI/CD pipeline design -- Code quality standards -- Release management - ---- - -## 📝 Final Notes - -This refactoring establishes ProXPL as a **professional, well-documented, community-ready programming language project**. The combination of comprehensive documentation, automated quality assurance, and clear development practices creates an excellent foundation for: - -- 👨‍🎓 Educational use (learning language design) -- 👥 Community contributions (clear standards and processes) -- 🚀 Production deployment (post-1.0.0) -- 📈 Continued evolution (roadmap through 1.0.0) - -**Status: Ready for community adoption and contribution!** - ---- - -**Document Generated**: December 2024 -**ProXPL Version**: 0.1.0 -**Refactoring Status**: ✅ COMPLETE - -For detailed information, see [REFACTOR_REPORT.md](REFACTOR_REPORT.md) diff --git a/VERSIONING.md b/VERSIONING.md index ab3a50a..a74cd59 100644 --- a/VERSIONING.md +++ b/VERSIONING.md @@ -1,6 +1,6 @@ # ProXPL Versioning and Release Guide -**Current Version: 0.1.0** +**Current Version: 1.0.0** **Release Date: December 2024** This document describes the versioning strategy, semantic versioning policy, and release procedures for ProXPL. diff --git a/benchmarks/PLAN.md b/benchmarks/PLAN.md new file mode 100644 index 0000000..e9babb8 --- /dev/null +++ b/benchmarks/PLAN.md @@ -0,0 +1,65 @@ +# ProXPL Benchmarking Plan + +## 1. Objectives +- Measure baseline performance of the current interpreter. +- Track improvements with the new Register VM and JIT. +- Compare against CPython 3.11, Lua 5.4, and Node.js. + +## 2. Benchmark Suite Strategy + +### 2.1 Microbenchmarks (CPU Core) +Focus on specific VM optimizations (dispatch, arithmetic, calls). + +| Benchmark | Description | Target Speedup (vs Current) | +|-----------|-------------|----------------------------| +| `fib.prox` | Recursive Fibonacci (Call overhead) | 3x | +| `loop_sum.prox` | Tight loop addition (1M iters) | 5x | +| `array_access.prox` | Read/Write array elements | 2x | +| `dict_get.prox` | Dictionary lookups (String keys) | 2x | + +### 2.2 Macrobenchmarks (Real Workload) +| Benchmark | Description | Target Speedup | +|-----------|-------------|----------------| +| `json_bench.prox` | Parse/Serialize simulated JSON | 3x | +| `http_sim.prox` | Simulated request routing/handling | 2x | +| `nbody.prox` | Physics simulation (Float math) | 10x (with JIT) | + +## 3. Tools & Methodology + +We will use `hyperfine` for statistical execution time measurement. + +### Pre-requisites +- `hyperfine` (install via `cargo install hyperfine` or `apt-get install hyperfine`) +- `python3` (CPython 3.11+) +- `lua` (Lua 5.4) +- `node` (Node.js 20+) + +### Execution Commands + +Run the following command from the repository root: + +```bash +# Example: Running the Fibonacci Benchmark +hyperfine --warmup 3 \ + "bin/proxpl run benchmarks/fib.prox" \ + "python3 benchmarks/reference/fib.py" \ + "lua benchmarks/reference/fib.lua" \ + --export-markdown benchmarks/results/fib_results.md +``` + +## 4. Directory Structure + +``` +benchmarks/ +├── micro/ +│ ├── fib.prox +│ ├── loop_sum.prox +│ └── ... +├── macro/ +│ └── nbody.prox +├── reference/ <-- Equivalents in Py/Lua/Node +│ ├── fib.py +│ ├── fib.lua +│ └── ... +└── run_all.sh +``` diff --git a/benchmarks/fibonacci.prox b/benchmarks/fibonacci.prox new file mode 100644 index 0000000..5f8d2e7 --- /dev/null +++ b/benchmarks/fibonacci.prox @@ -0,0 +1,14 @@ +// benchmarks/fibonacci.prox +// Stress Test: Recursion & Function Calls + +fun fib(n) { + if (n < 2) return n; + return fib(n - 1) + fib(n - 2); +} + +print("Starting Fib(30)..."); +start = clock(); +res = fib(30); +end = clock(); +print("Result: " + res); +print("Time: " + (end - start)); diff --git a/benchmarks/loop_math.prox b/benchmarks/loop_math.prox new file mode 100644 index 0000000..0081d1a --- /dev/null +++ b/benchmarks/loop_math.prox @@ -0,0 +1,17 @@ +// benchmarks/loop_math.prox +// Stress Test: Tight Loop & Arithmetic + +const ITERATIONS = 10000000; +print("Starting Loop Math..."); + +start = clock(); +sum = 0; +i = 0; +while (i < ITERATIONS) { + sum = sum + i; + i = i + 1; +} +end = clock(); + +print("Sum: " + sum); +print("Time: " + (end - start)); diff --git a/benchmarks/run_benchmarks.py b/benchmarks/run_benchmarks.py new file mode 100644 index 0000000..5543c7f --- /dev/null +++ b/benchmarks/run_benchmarks.py @@ -0,0 +1,48 @@ +# -------------------------------------------------- +# Project: ProX Programming Language (ProXPL) +# Author: ProgrammerKR +# Created: 2025-12-16 +# Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + +import subprocess +import time +import os +import sys + +def run_command(cmd): + start = time.time() + try: + subprocess.run(cmd, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except subprocess.CalledProcessError as e: + print(f"Error running {cmd}: {e}") + return None + end = time.time() + return end - start + +def main(): + benchmarks = [ + "benchmarks/fibonacci.prox", + "benchmarks/loop_math.prox", + "benchmarks/string_concat.prox" + ] + + # Assume we have compiled proxpl in bin/proxpl (or use python version for now if bin not ready) + # For now, we compare against CPython as specific in prompt (target numbers) + + print(f"{'Benchmark':<25} | {'ProXPL (s)':<10} | {'CPython (s)':<10} | {'Speedup':<10}") + print("-" * 65) + + for bench in benchmarks: + # Construct equivalent python command (assuming corresponding .py files exist or we generate them) + # For simplicity, we just run the prox file with current proxpl interpreter if it works, + # but since we are replacing it, we might not have a working one yet. + # This script is a template. + + prox_cmd = f"bin/proxpl run {bench}" + # py_cmd = f"python3 {bench.replace('.prox', '.py')}" + + # Placeholder Results + print(f"{bench:<25} | {'N/A':<10} | {'1.20':<10} | {'Pending'}") + +if __name__ == "__main__": + main() diff --git a/benchmarks/string_concat.prox b/benchmarks/string_concat.prox new file mode 100644 index 0000000..5d77058 --- /dev/null +++ b/benchmarks/string_concat.prox @@ -0,0 +1,17 @@ +// benchmarks/string_concat.prox +// Stress Test: Allocation & GC + +const ITERATIONS = 100000; +print("Starting String Concat..."); + +start = clock(); +s = ""; +i = 0; +while (i < ITERATIONS) { + s = s + "."; + i = i + 1; +} +end = clock(); + +print("String Length: " + len(s)); +print("Time: " + (end - start)); diff --git a/BYTECODE_SPEC.md b/docs/BYTECODE_SPEC.md similarity index 100% rename from BYTECODE_SPEC.md rename to docs/BYTECODE_SPEC.md diff --git a/DECODER_AND_DISPATCH_SPEC.md b/docs/DECODER_AND_DISPATCH_SPEC.md similarity index 100% rename from DECODER_AND_DISPATCH_SPEC.md rename to docs/DECODER_AND_DISPATCH_SPEC.md diff --git a/ARCHITECTURE.md b/docs/architecture/ARCHITECTURE.md similarity index 100% rename from ARCHITECTURE.md rename to docs/architecture/ARCHITECTURE.md diff --git a/docs/architecture/ARCHITECTURE_V2.md b/docs/architecture/ARCHITECTURE_V2.md new file mode 100644 index 0000000..dc88f1c --- /dev/null +++ b/docs/architecture/ARCHITECTURE_V2.md @@ -0,0 +1,78 @@ +# ProXPL V2 Architecture: High-Performance Runtime + +## 1. Executive Summary +This document outlines the architectural transformation of ProXPL from a tree-walking interpreter to a high-performance JIT-compiled runtime. +**Goal:** Achieve performance parity with LuaJIT/V8 and >3x speedup over CPython 3.11. + +## 2. Core Components + +### 2.1 Compiler (Frontend) +Separated from the runtime, responsible for: +- **Lexing/Parsing**: Producing an AST. +- **Bytecode Generation**: Traversing the AST and emitting Register Machine IR. +- **Optimization**: Constant folding, dead code elimination. + +### 2.2 Register-Based Virtual Machine (Runtime) +A register VM reduces instruction dispatch overhead compared to stack-based VMs. + +**Instruction Set Architecture (ISA)** +Fixed-width 32-bit instructions for cache locality. +Format: `[ OpCode (8) | A (8) | B (8) | C (8) ]` + +| Field | Bits | Purpose | +|-------|------|---------| +| OpCode| 0-7 | Operation identifier | +| A | 8-15 | Destination Register / Operand | +| B | 16-23| Source Register 1 | +| C | 24-31| Source Register 2 / Immediate | + +**Core Instructions:** +- `LOAD_CONST R(A), K(Bx)`: Load constant from pool at index Bx into R(A). +- `MOV R(A), R(B)`: Move value from R(B) to R(A). +- `ADD R(A), R(B), R(C)`: R(A) = R(B) + R(C) (Specialized for Int/Float). +- `CALL R(A), R(B), C`: Call function at R(A) with args starting at R(B), count C. +- `RETURN R(A)`: Return value in R(A). +- `JMP_IF R(A), Offset(sBx)`: Conditional Jump. + +### 2.3 Memory Model (NaN-Boxing) +All values are 64-bit doubles. +- **Doubles**: Standard IEEE 754 doubles. +- **Pointers/Tags**: Stored in the NaN space (top 16 bits). + - `0xFFF8` prefix indicates NaN. + - Low 48 bits are pointers or immediate values (Bool, Null, Int32). + +**Layout:** +``` +[ 111111111111 0000 | ... payload ... ] -> Double NaN +[ 111111111111 0001 | ... address ... ] -> Object Pointer +[ 111111111111 0010 | ... integer ... ] -> 32-bit Integer +[ 111111111111 0011 | 0/1 ] -> Boolean +``` + +### 2.4 Garbage Collection +- **Generational GC**: + - **Nursery**: Bump-pointer allocation (extremely fast). Logic: `ptr = top; top += size;` + - **Old Gen**: Mark-and-Sweep. + - **Write Barriers**: Required when Old Gen object points to Young Gen. + +### 2.5 JIT Compilation Strategy (Baseline) +- **Template JIT**: + - Pre-compile assembly snippets for each bytecode op. + - At JIT time ($$ > 100 runs $$), `memcpy` snippets into a specialized buffer. + - Patch jumps and immediate values. +- **Deoptimization**: Support bailing out to interpreter if assumptions fail (e.g., type check failure in optimized code - primarily for later tracing JIT, but relevant for simple type guards). + +## 3. Project Structure Refactor +``` +src/ +├── compiler/ # Frontend (Parser, AST, CodeGen) +│ ├── lexer/ +│ ├── parser/ +│ └── codegen/ +├── vm/ # Runtime (VM, GC, Loader) +│ ├── core/ # Loop, Dispatch +│ ├── gc/ # Allocator, Collector +│ └── jit/ # Baseline JIT +├── stdlib/ # Native implementations +└── include/ # Public headers +``` diff --git a/docs/design.md b/docs/design.md new file mode 100644 index 0000000..2f55128 --- /dev/null +++ b/docs/design.md @@ -0,0 +1,89 @@ +# ProXPL Performance Modernization Design Doc + +## 1. System Architecture (Target State) + +```text + +------------------+ + | Source Code | (.prox) + +--------+---------+ + | + +--------v---------+ + | Lexer/Parser | (C / Modernized) + +--------+---------+ + | + +--------v---------+ + | AST Builder | + +--------+---------+ + | + +--------v---------+ + | Bytecode Compiler| (AST -> REG-ISA) + | (Reg Allocator) | + +--------+---------+ + | + +--------v---------+ + | Bytecode Module|<-----+ Native Runtime | + | (Instructions) | | (C/Rust Strings, | + +--------+---------+ | Arrays, Dicts) | + | +-------------------+ + +-----------v-----------+ + | Register VM | <--- Profiling Events + | (Interpreter Loop) | + +-----------+-----------+ + | + [Hot Path?] + | + +-----------v-----------+ + | Baseline JIT (C) | (Template/Copying JIT) + | (Machine Code Gen) | + +-----------+-----------+ + | + [Very Hot?] + | + +-----------v-----------+ +------------------+ + | Optimizer (LLVM) | | Inline Caches | + | (Type Specialization) |<----+ (Polymorphic IC) | + +-----------------------+ +------------------+ +``` + +## 2. Design Doc Outline & Modules + +### 2.1 Register-Based VM ISA +**Motivation**: Reduce dispatch overhead (fewer instructions than stack VM) and improve cache locality. +**Structure**: +- `Instruction`: 32-bit word. +- `Opcode`: 8 bits. +- `A` (Dest): 8 bits. +- `B` (Src1): 8 bits. +- `C` (Src2/Imm): 8 bits. + +**Core Instructions**: +- `MOV R_dest, R_src` +- `ADD R_dest, R_src1, R_src2` +- `LOADK R_dest, K_idx` +- `CALL R_dest, R_func, NumArgs` +- `RET R_src` + +### 2.2 Baseline JIT (Template JIT) +**Strategy**: +- Pre-compile machine code snippets for each opcode (templates). +- **Benefit**: Very fast implementation, 2-5x speedup over interpreter. + +### 2.3 Optimizing JIT (LLVM / DynASM) +**Strategy**: +- Triggered for hot loops (>10k executions). +- **Type Specialization**: Guard checks for types. + +### 2.4 Data Model & Memory Layout +- **Value**: NaN-boxing (64-bit). +- **GC**: Generational Mark-and-Sweep. + +## 3. Risks & Tradeoffs +1. **Complexity**: LLVM is heavy. **Mitigation**: Start with Template JIT. +2. **GC Pauses**: Generational GC adds complexity. **Mitigation**: Incremental marking. + +## 4. Benchmark Plan + +**Microbenchmarks**: +1. `arith_loop.prox`: Tight loop summing integers. +2. `call_depth.prox`: Recursive fibonacci. +3. `str_cat.prox`: String concatenation. diff --git a/LANGUAGE_SPEC.md b/docs/language-spec/LANGUAGE_SPEC.md similarity index 100% rename from LANGUAGE_SPEC.md rename to docs/language-spec/LANGUAGE_SPEC.md diff --git a/docs/migration/PYTHON_TO_C.md b/docs/migration/PYTHON_TO_C.md deleted file mode 100644 index 95cd87c..0000000 --- a/docs/migration/PYTHON_TO_C.md +++ /dev/null @@ -1,650 +0,0 @@ -# Python to C Migration Blueprint - -## Overview - -This document outlines the complete strategy for migrating ProXPL from Python (reference implementation) to C (production implementation). This is already partially complete, and this blueprint provides a roadmap for finishing the migration and maintaining code quality. - -## Current Status - -### ✅ Completed (C Implementation) -- Core Lexer (Scanner) -- Core Parser -- Basic AST implementation -- Type Checker (partial) -- Bytecode Compiler -- Stack-based VM -- Runtime Value System -- Object System (partial) -- Memory Management (basic) -- Standard Library (partial - 44 functions) - -### 🔄 In Progress -- Type Checker completion -- Object system refinement -- Standard library expansion -- Error handling system -- Module/Import system - -### ⏳ Not Started (Future) -- Garbage Collector (advanced) -- Module system -- Package manager -- Debugger/Profiler -- Optimization passes -- WebAssembly target - ---- - -## Migration Strategy - -### Phase 1: Complete Core Language (Current) - -**Target**: Fully functional language with all basic features - -#### 1.1 Lexer (✅ Complete) -- File: `src/lexer/scanner.c` -- All 45 keywords recognized -- All 42 operators tokenized -- String/number parsing complete -- Position tracking for errors - -**Status**: Production-ready - -#### 1.2 Parser (✅ Complete) -- File: `src/parser/parser.c` -- All statement types parsed -- All expression types parsed -- Recursive descent implementation -- Error recovery - -**Status**: Production-ready - -#### 1.3 Type Checker (🔄 In Progress) -- File: `src/parser/type_checker.c` -- Type inference algorithm -- Type unification -- Scope management -- Error detection - -**TODO**: -``` -[ ] Complete inference rules for all expressions -[ ] Implement function type checking -[ ] Add class/interface checking -[ ] Add generic type support (future) -[ ] Better error messages -``` - -#### 1.4 Bytecode Compiler (✅ Complete) -- File: `src/runtime/compiler.c` -- All opcodes implemented (42+ instructions) -- Constant pooling -- Jump instruction handling -- Function compilation - -**Status**: Production-ready - -#### 1.5 Virtual Machine (✅ Complete) -- File: `src/runtime/vm.c` -- Stack-based execution -- Call stack management -- Native function dispatch -- Error handling - -**Status**: Production-ready with improvements needed - -**TODO**: -``` -[ ] Better error messages at runtime -[ ] Stack trace on error -[ ] REPL improvements -[ ] Debugger integration points -``` - ---- - -### Phase 2: Runtime System & Memory (Next Priority) - -#### 2.1 Value System (✅ Complete) -- File: `src/runtime/value.c` -- All 12 data types represented -- Type checking macros -- String interning - -**Status**: Production-ready - -#### 2.2 Object System (🔄 In Progress) -- File: `src/runtime/object.c` -- String objects -- Function objects -- Class objects -- Instance objects - -**TODO**: -``` -[ ] Method binding -[ ] Inheritance implementation -[ ] Static methods -[ ] Property access optimization -[ ] Garbage collection integration -``` - -#### 2.3 Memory Management (🔄 Partial) -- File: `src/runtime/memory.c` -- Basic allocation -- Deallocation - -**TODO**: -``` -[ ] Implement mark-and-sweep GC -[ ] String pool optimization -[ ] Memory profiling -[ ] Leak detection -``` - -#### 2.4 Collections (⏳ Not Started) -- Lists, Dictionaries, Sets - -**Plan**: -```c -// src/runtime/collections.c -typedef struct { - Value *elements; - int count; - int capacity; -} ObjList; - -typedef struct { - // Key-value pairs - struct { Value key; Value value; } *entries; - int count; - int capacity; -} ObjDict; - -typedef struct { - // Unique values using hashtable - Table table; -} ObjSet; -``` - ---- - -### Phase 3: Standard Library Expansion - -#### Current Coverage (44 functions) - -**I/O** (5 functions): -- print(), input(), open(), read(), write() - -**Math** (15 functions): -- sqrt(), sin(), cos(), tan(), floor(), ceil(), abs(), min(), max(), pow(), etc. - -**String** (9 functions): -- len(), substring(), toUpper(), toLower(), split(), trim(), contains(), etc. - -**Convert** (8 functions): -- toInt(), toFloat(), toString(), toBool(), typeof(), etc. - -**System** (7 functions): -- exit(), system(), getEnv(), setEnv(), etc. - -#### Planned Additions (30+ functions) - -**Collections** (12 functions): -```c -// map, filter, reduce, sort, reverse -// append, pop, push, insert, remove, find -``` - -**DateTime** (8 functions): -```c -// now, parse, format, sleep -// year, month, day, weekday -``` - -**File I/O** (6 functions): -```c -// exists, delete, rename, mkdir, listdir, getcwd -``` - -**Advanced** (6+ functions): -```c -// assert, hash, clone, freeze -// Custom error types -``` - -#### Implementation Plan - -Each function follows pattern: - -```c -// stdlib/category_native.c -Value category_function_name(int argc, Value *argv) { - // Validate argument count and types - if (argc != EXPECTED_COUNT) { - return ERROR_VAL("Wrong number of arguments"); - } - - // Type checking - if (!IS_NUMBER(argv[0])) { - return ERROR_VAL("Expected number"); - } - - // Implementation - double result = some_operation(AS_NUMBER(argv[0])); - - // Return result - return NUMBER_VAL(result); -} - -// Registration in stdlib_core.c -void register_category_functions(VM *vm) { - define_native(vm, "function_name", category_function_name); - // ... more functions -} -``` - ---- - -### Phase 4: Module System - -#### Module Loading - -```c -// src/runtime/importer.c -typedef struct { - Table loaded_modules; // Cache of loaded modules - char search_paths[10][256]; - int path_count; -} Importer; - -Value import_module(VM *vm, const char *name) { - // 1. Check cache - // 2. Search paths - // 3. Parse and compile - // 4. Execute - // 5. Return exports -} -``` - -#### Usage -```javascript -use math; -use collections as col; -from io import print, input; -``` - ---- - -### Phase 5: Advanced Features - -#### 5.1 Garbage Collector - -**Algorithm**: Mark-and-sweep - -```c -// src/runtime/gc.c -void collect_garbage(VM *vm) { - // 1. Mark roots - // - Global variables - // - Stack values - // - Function closures - - // 2. Mark reachable objects - // - Follow pointers - // - Recursive traversal - - // 3. Sweep unmarked objects - // - Free memory - // - Update linked list - - // 4. Reset GC threshold - vm->next_gc *= GC_GROWTH_FACTOR; -} -``` - -#### 5.2 Optimization Passes - -**Constant Folding**: -``` -5 + 3 → 8 (compile time) -``` - -**Dead Code Elimination**: -``` -if (false) { unreachable code } → removed -``` - -**Jump Optimization**: -``` -JUMP → forward → jump to target -``` - -**Peephole Optimization**: -``` -Multiple instructions → single instruction -``` - -#### 5.3 Debugger - -```c -// src/tools/debugger.c -typedef struct { - bool step_mode; - Table breakpoints; - Value *watch_vars; -} Debugger; - -void debug_hook(VM *vm, int opcode) { - if (vm->debug) { - // Check breakpoints - // Display state - // Read commands - } -} -``` - ---- - -## File Structure Migration - -### Python → C Mapping - -``` -Python C -──────────────────────────────────────────── -cli/ src/main.c (REPL + file execution) - main.py - -lexer/ src/lexer/ - scanner.py scanner.c - include/scanner.h - -parser/ src/parser/ - parser.py parser.c - include/parser.h - ast.py ast.c - include/ast.h - type_checker.py type_checker.c - include/type_checker.h - -compiler/ src/runtime/ - compiler.py compiler.c - include/compiler.h - chunk.py chunk.c - include/chunk.h - -vm/ src/runtime/ - vm.py vm.c - include/vm.h - value.py value.c - include/value.h - object.py object.c - include/object.h - -stdlib/ src/stdlib/ - __init__.py stdlib_core.c - io.py io_native.c - math.py math_native.c - string.py string_native.c - convert.py convert_native.c - system.py system_native.c - -memory/ src/runtime/ - memory.py memory.c - include/memory.h - gc.c (future) -``` - ---- - -## Build System - -### Current CMake Setup - -```cmake -# CMakeLists.txt (root) -cmake_minimum_required(VERSION 3.10) -project(ProXPL C) - -set(CMAKE_C_STANDARD 99) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -g") - -include_directories(include) - -file(GLOB_RECURSE SOURCES "src/*.c") -add_executable(prox ${SOURCES}) -``` - -### Make Alternative - -```makefile -# Makefile -CC = gcc -CFLAGS = -Wall -Wextra -Iinclude -std=c99 -SOURCES = $(wildcard src/**/*.c) src/main.c -OBJECTS = $(SOURCES:.c=.o) -TARGET = prox - -all: $(TARGET) - -$(TARGET): $(OBJECTS) - $(CC) $(CFLAGS) -o $@ $^ - -%.o: %.c - $(CC) $(CFLAGS) -c $< -o $@ - -clean: - rm -f $(OBJECTS) $(TARGET) - -test: - # Run test suite -``` - ---- - -## Testing Strategy - -### Unit Tests - -```c -// tests/unit/test_lexer.c -#include "unity.h" -#include "scanner.h" - -void test_tokenize_number() { - Scanner scanner; - init_scanner(&scanner, "42"); - Token token = next_token(&scanner); - - TEST_ASSERT_EQUAL(TOKEN_NUMBER, token.type); - TEST_ASSERT_EQUAL(2, token.length); -} - -void setUp(void) { - // Setup before each test -} - -void tearDown(void) { - // Cleanup after each test -} - -int main(void) { - UNITY_BEGIN(); - RUN_TEST(test_tokenize_number); - // ... more tests - return UNITY_END(); -} -``` - -### Integration Tests - -```c -// tests/integration/test_e2e.c -void test_fibonacci_program() { - const char *source = R"( - func fib(n) { - if (n <= 1) return n; - return fib(n-1) + fib(n-2); - } - print(fib(10)); - )"; - - // Compile and run - // Assert output matches expected -} -``` - -### Test Coverage - -**Target**: 80% code coverage - -```bash -# Generate coverage report -gcov src/**/*.c -lcov --capture --directory . --output-file coverage.info -genhtml coverage.info --output-directory coverage_html -``` - ---- - -## Performance Targets - -### Benchmarks to Achieve - -| Operation | Target | Method | -|-----------|--------|--------| -| Fibonacci(30) | < 1s | Time compiled code | -| Startup time | < 10ms | Time executable startup | -| Memory (simple program) | < 1MB | Measure heap size | -| Parsing large file | < 100ms | Parse 10K line file | -| Function call overhead | < 10us | Time 1M calls | - -### Optimization Techniques - -1. **Inline Functions**: Hot path functions -2. **String Interning**: Memory efficiency -3. **Bytecode Caching**: Avoid recompilation -4. **Jump Optimization**: Reduce instruction count -5. **Stack Allocation**: For temporary objects -6. **Object Pooling**: Reuse allocations - ---- - -## Release Planning - -### Version 0.9 (Current - December 2024) -- [x] Lexer, parser, compiler -- [x] Basic VM -- [x] Core stdlib (40+ functions) -- [ ] Complete type checker -- [ ] Module system (basic) -- [ ] Comprehensive tests - -### Version 1.0 (Q2 2025) -- [ ] Feature-complete language -- [ ] 80%+ test coverage -- [ ] Production-ready documentation -- [ ] Performance optimizations -- [ ] Full standard library (75+ functions) -- [ ] Error recovery -- [ ] REPL improvements - -### Version 1.1 (Q3 2025) -- [ ] Garbage collector -- [ ] Module system (complete) -- [ ] Package manager (ProXPL PM) -- [ ] Debugger -- [ ] IDE plugins (VS Code) - -### Version 2.0 (2026) -- [ ] JIT compiler -- [ ] Native code generation -- [ ] WebAssembly target -- [ ] Advanced optimizations - ---- - -## Code Quality Checklist - -- [ ] No compiler warnings (with -Wall -Wextra) -- [ ] All functions documented (Doxygen style) -- [ ] Memory leaks checked (valgrind/sanitizers) -- [ ] All tests passing (100% pass rate) -- [ ] Code review completed -- [ ] Performance benchmarks met -- [ ] Security audit passed -- [ ] Documentation up to date - ---- - -## Migration Metrics - -**Progress Tracking**: -``` -Lexer: 100% (✅ Complete) -Parser: 100% (✅ Complete) -Type Checker: 75% (🔄 In Progress) -Compiler: 100% (✅ Complete) -VM: 95% (✅ Nearly Complete) -Runtime: 70% (🔄 In Progress) -StdLib: 58% (🔄 In Progress, 44/75 functions) -Memory/GC: 20% (⏳ Not Started) -Module System: 10% (⏳ Not Started) -Debugger: 0% (⏳ Future) -──────────────────────────────── -Overall: ~62% Complete -``` - ---- - -## Development Priorities (Next 3 Months) - -1. **Complete Type Checker** (2 weeks) - - All expression types - - Function signatures - - Class definitions - - Better error messages - -2. **Finish Object System** (2 weeks) - - Method binding - - Inheritance - - Property access - -3. **Expand Standard Library** (3 weeks) - - Collections (lists, dicts, sets) - - File I/O - - DateTime - -4. **Implement Module System** (3 weeks) - - Module loading - - Circular dependency detection - - Module caching - -5. **Testing & Documentation** (Ongoing) - - Unit tests for all components - - Integration tests - - API documentation - - Tutorial updates - ---- - -## Resources & References - -### Language Implementation -- "Crafting Interpreters" by Robert Nystrom -- "Engineering a Compiler" by Cooper & Torczon -- LUA source code (reference implementation) - -### C Programming -- C99 Standard -- "The C Programming Language" by Kernighan & Ritchie -- Linux kernel coding style - -### Performance -- "Software Optimization" by Agner Fog -- Profiling with perf, gprof, valgrind - ---- - -This migration blueprint provides a clear roadmap for completing ProXPL's transition to C and achieving production-ready quality. diff --git a/docs/staff-notes/notes.md b/docs/staff-notes/notes.md deleted file mode 100644 index 8593622..0000000 --- a/docs/staff-notes/notes.md +++ /dev/null @@ -1 +0,0 @@ -# notes.md (auto-generated) diff --git a/STDLIB_DOC.md b/docs/stdlib/STDLIB_DOC.md similarity index 100% rename from STDLIB_DOC.md rename to docs/stdlib/STDLIB_DOC.md diff --git a/examples/test.prox b/examples/test.prox new file mode 100644 index 0000000..9c9b0ee --- /dev/null +++ b/examples/test.prox @@ -0,0 +1,4 @@ +func main() -> int { + int x = 10; + return x + 5; +} diff --git a/include/advanced.h b/include/advanced.h index 7e7a4f7..da52f59 100644 --- a/include/advanced.h +++ b/include/advanced.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * Advanced Features Header * Stub declarations for advanced ProXPL features diff --git a/include/ast.h b/include/ast.h index 06f425a..db1c21c 100644 --- a/include/ast.h +++ b/include/ast.h @@ -1,9 +1,38 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROX_AST_H #define PROX_AST_H #include "common.h" #include "value.h" +// --- Type System for Static Typing --- +typedef enum { + TYPE_UNKNOWN = 0, + TYPE_VOID, + TYPE_BOOL, + TYPE_INT, + TYPE_FLOAT, + TYPE_STRING, + TYPE_FUNCTION, + TYPE_CLASS +} TypeKind; + +typedef struct TypeInfo { + TypeKind kind; + char* name; // For classes or user types + + // For functions + struct TypeInfo* returnType; + struct TypeInfo* paramTypes; // Array or linked list? Let's use array for simplicity if fixed size, or pointer to array. + // For simplicity in C without templates, let's use a pointer to a dynamically allocated array of TypeInfos. + int paramCount; +} TypeInfo; + // Forward declarations typedef struct Expr Expr; typedef struct Stmt Stmt; @@ -44,7 +73,8 @@ typedef enum { STMT_BREAK, STMT_CONTINUE, STMT_SWITCH, - STMT_TRY_CATCH + STMT_TRY_CATCH, + STMT_PRINT } StmtType; // Dynamic array for expressions @@ -171,6 +201,7 @@ typedef struct { // Main expression structure struct Expr { ExprType type; + TypeInfo inferredType; // [NEW] For Type Checker int line; int column; union { @@ -201,6 +232,7 @@ typedef struct { typedef struct { char *name; Expr *initializer; + TypeInfo type; // [NEW] Explicit type declaration bool is_const; } VarDeclStmt; @@ -208,6 +240,7 @@ typedef struct { char *name; StringList *params; StmtList *body; + TypeInfo returnType; // [NEW] } FuncDeclStmt; typedef struct { @@ -262,6 +295,10 @@ typedef struct { StmtList *default_case; // Can be NULL } SwitchStmt; +typedef struct { + Expr *expression; +} PrintStmt; + typedef struct { StmtList *try_block; char *catch_var; @@ -289,6 +326,7 @@ struct Stmt { ContinueStmt continue_stmt; SwitchStmt switch_stmt; TryCatchStmt try_catch; + PrintStmt print; } as; }; @@ -339,6 +377,7 @@ Stmt *createSwitchStmt(Expr *value, SwitchCaseList *cases, StmtList *def, Stmt *createTryCatchStmt(StmtList *try_blk, const char *catch_var, StmtList *catch_blk, StmtList *finally_blk, int line, int column); +Stmt *createPrintStmt(Expr *expression, int line, int column); // List management functions ExprList *createExprList(); diff --git a/include/bytecode.h b/include/bytecode.h index 71575aa..8c301d7 100644 --- a/include/bytecode.h +++ b/include/bytecode.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROXPL_BYTECODE_H #define PROXPL_BYTECODE_H #include diff --git a/include/chunk.h b/include/chunk.h index 62496b0..57bc1fe 100644 --- a/include/chunk.h +++ b/include/chunk.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROX_CHUNK_H #define PROX_CHUNK_H @@ -7,10 +13,23 @@ // OpCodes typedef enum { OP_CONSTANT, + OP_NIL, OP_TRUE, OP_FALSE, - OP_NULL, OP_POP, + OP_GET_LOCAL, + OP_SET_LOCAL, + OP_GET_GLOBAL, + OP_DEFINE_GLOBAL, + OP_SET_GLOBAL, + OP_GET_UPVALUE, + OP_SET_UPVALUE, + OP_GET_PROPERTY, + OP_SET_PROPERTY, + OP_GET_SUPER, + OP_EQUAL, + OP_GREATER, + OP_LESS, OP_ADD, OP_SUBTRACT, OP_MULTIPLY, @@ -18,7 +37,18 @@ typedef enum { OP_NOT, OP_NEGATE, OP_PRINT, + OP_JUMP, + OP_JUMP_IF_FALSE, + OP_LOOP, + OP_CALL, + OP_INVOKE, + OP_SUPER_INVOKE, + OP_CLOSURE, + OP_CLOSE_UPVALUE, OP_RETURN, + OP_CLASS, + OP_INHERIT, + OP_METHOD } OpCode; // Chunk: Sequence of bytecode diff --git a/include/common.h b/include/common.h index ecbd5b0..15d36bd 100644 --- a/include/common.h +++ b/include/common.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROX_COMMON_H #define PROX_COMMON_H diff --git a/include/compiler.h b/include/compiler.h index 2538f20..a2db3cb 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROX_COMPILER_H #define PROX_COMPILER_H @@ -5,13 +11,7 @@ #include "vm.h" -typedef struct { - Token current; - Token previous; - bool hadError; - bool panicMode; - Scanner *scanner; -} Parser; +typedef struct Parser Parser; typedef enum { PREC_NONE, @@ -37,4 +37,7 @@ typedef struct { bool compile(const char *source, Chunk *chunk); +#include "ast.h" +void generateBytecode(StmtList* statements, Chunk* chunk); + #endif diff --git a/include/debug.h b/include/debug.h index e508802..971801e 100644 --- a/include/debug.h +++ b/include/debug.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROX_DEBUG_H #define PROX_DEBUG_H diff --git a/include/importer.h b/include/importer.h index a799c49..37293b4 100644 --- a/include/importer.h +++ b/include/importer.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * Module Importer for ProXPL * Handles "use" keyword and module loading diff --git a/include/memory.h b/include/memory.h index 6426513..76541c7 100644 --- a/include/memory.h +++ b/include/memory.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROX_MEMORY_H #define PROX_MEMORY_H diff --git a/include/object.h b/include/object.h index 6587abf..c36bfbd 100644 --- a/include/object.h +++ b/include/object.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROX_OBJECT_H #define PROX_OBJECT_H diff --git a/include/parser.h b/include/parser.h index a4d9b57..fcde4e9 100644 --- a/include/parser.h +++ b/include/parser.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROX_PARSER_H #define PROX_PARSER_H diff --git a/include/protos/register_vm.c b/include/protos/register_vm.c index ded1ff3..760df71 100644 --- a/include/protos/register_vm.c +++ b/include/protos/register_vm.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * protos/register_vm.c * diff --git a/include/proxpl_api.h b/include/proxpl_api.h index 894204a..8c35f2a 100644 --- a/include/proxpl_api.h +++ b/include/proxpl_api.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROXPL_API_H #define PROXPL_API_H diff --git a/include/scanner.h b/include/scanner.h index 7001ed9..0cde0ba 100644 --- a/include/scanner.h +++ b/include/scanner.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROX_SCANNER_H #define PROX_SCANNER_H diff --git a/include/stdlib_native.h b/include/stdlib_native.h index 9e6efa5..e5902ad 100644 --- a/include/stdlib_native.h +++ b/include/stdlib_native.h @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROX_STDLIB_H #define PROX_STDLIB_H diff --git a/include/table.h b/include/table.h new file mode 100644 index 0000000..cf5802a --- /dev/null +++ b/include/table.h @@ -0,0 +1,27 @@ +#ifndef PROX_TABLE_H +#define PROX_TABLE_H + +#include "common.h" +#include "value.h" + +typedef struct { + ObjString *key; + Value value; +} Entry; + +typedef struct { + int count; + int capacity; + Entry *entries; +} Table; + +void initTable(Table *table); +void freeTable(Table *table); +bool tableGet(Table *table, ObjString *key, Value *value); +bool tableSet(Table *table, ObjString *key, Value value); +bool tableDelete(Table *table, ObjString *key); +void tableAddAll(Table *from, Table *to); +ObjString *tableFindString(Table *table, const char *chars, int length, + uint32_t hash); + +#endif diff --git a/include/type_checker.h b/include/type_checker.h index 6b10d7b..6dd2cac 100644 --- a/include/type_checker.h +++ b/include/type_checker.h @@ -1,5 +1,13 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * Type Checker Header + * ------------------- + * Responsible for static analysis, type inference, and validation. */ #ifndef PROX_TYPE_CHECKER_H @@ -8,13 +16,31 @@ #include "ast.h" #include "common.h" +// --- Symbol Table for Scoping --- +typedef struct Symbol { + char* name; + TypeInfo type; + struct Symbol* next; // Hash collision chain +} Symbol; + +#define TABLE_SIZE 256 + +typedef struct Scope { + Symbol* table[TABLE_SIZE]; + struct Scope* parent; +} Scope; typedef struct { - int errorCount; + int errorCount; + Scope* currentScope; } TypeChecker; +// --- API --- void initTypeChecker(TypeChecker *checker); bool checkTypes(TypeChecker *checker, StmtList *statements); void freeTypeChecker(TypeChecker *checker); +// --- Helpers exposed for other compiler types --- +TypeInfo resolveVariableType(TypeChecker* checker, const char* name); + #endif diff --git a/include/value.h b/include/value.h index 2cda362..3ffa464 100644 --- a/include/value.h +++ b/include/value.h @@ -1,41 +1,65 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROX_VALUE_H #define PROX_VALUE_H #include "common.h" +#include + +// NaN-Boxing: +// IEEE 754 doubles have 52 bits of mantissa. +// specific NaN patterns can encode pointers (48 bits on x64) and tags. +// +// Mask: 0xFFFF000000000000 (Top 16 bits are tag/sign/exp) +// +// QNaN : 0x7ff8000000000000 +// SIGN : 0x8000000000000000 (Sign bit implies object pointer) +// TAGS : Lower 3 bits of the high 16 bits can be types. + +typedef uint64_t Value; + +// Masks +#define SIGN_BIT ((uint64_t)0x8000000000000000) +#define QNAN ((uint64_t)0x7ffc000000000000) -// For now, simpler Tagged Union. -// Phase 2 can introduce Nan-boxing. +#define TAG_NULL 1 // 01 +#define TAG_FALSE 2 // 10 +#define TAG_TRUE 3 // 11 typedef struct Obj Obj; -typedef struct ObjString ObjString; -typedef enum { VAL_BOOL, VAL_NULL, VAL_NUMBER, VAL_OBJ } ValueType; +// Classification Macros +#define IS_NUMBER(v) (((v) & QNAN) != QNAN) +#define IS_NULL(v) ((v) == (QNAN | TAG_NULL)) +#define IS_BOOL(v) (((v) | 1) == (QNAN | TAG_TRUE)) +#define IS_OBJ(v) (((v) & (QNAN | SIGN_BIT)) == (QNAN | SIGN_BIT)) -typedef struct { - ValueType type; - union { - bool boolean; - double number; - Obj *obj; - } as; -} Value; - -// Macros for checking type -#define IS_BOOL(value) ((value).type == VAL_BOOL) -#define IS_NULL(value) ((value).type == VAL_NULL) -#define IS_NUMBER(value) ((value).type == VAL_NUMBER) -#define IS_OBJ(value) ((value).type == VAL_OBJ) - -// Macros for unwrapping -#define AS_BOOL(value) ((value).as.boolean) -#define AS_NUMBER(value) ((value).as.number) -#define AS_OBJ(value) ((value).as.obj) - -// Macros for creating values -#define BOOL_VAL(value) ((Value){VAL_BOOL, {.boolean = value}}) -#define NULL_VAL ((Value){VAL_NULL, {.number = 0}}) -#define NUMBER_VAL(value) ((Value){VAL_NUMBER, {.number = value}}) -#define OBJ_VAL(object) ((Value){VAL_OBJ, {.obj = (Obj *)object}}) +// Conversion Macros +#define AS_NUMBER(v) valueToNum(v) +#define AS_BOOL(v) ((v) == (QNAN | TAG_TRUE)) +#define AS_OBJ(v) ((Obj*)(uintptr_t)((v) & ~(SIGN_BIT | QNAN))) + +// Value Constructors +static inline Value numToValue(double num) { + Value value; + memcpy(&value, &num, sizeof(double)); + return value; +} + +static inline double valueToNum(Value value) { + double num; + memcpy(&num, &value, sizeof(Value)); + return num; +} + +#define NUMBER_VAL(num) (numToValue(num)) +#define NULL_VAL ((Value)(QNAN | TAG_NULL)) +#define BOOL_VAL(b) ((b) ? (QNAN | TAG_TRUE) : (QNAN | TAG_FALSE)) +#define OBJ_VAL(obj) (Value)(SIGN_BIT | QNAN | (uint64_t)(uintptr_t)(obj)) // Value Array (for constants, stack etc.) typedef struct { diff --git a/include/vm.h b/include/vm.h index e6fa4d6..c575554 100644 --- a/include/vm.h +++ b/include/vm.h @@ -1,8 +1,13 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #ifndef PROX_VM_H #define PROX_VM_H -#include "chunk.h" -#include "value.h" +#include "table.h" #define STACK_MAX 256 @@ -11,8 +16,13 @@ typedef struct { u8 *ip; // Instruction Pointer Value stack[STACK_MAX]; Value *stackTop; + Table globals; + Table strings; + struct Obj *objects; } VM; +extern VM vm; + typedef enum { INTERPRET_OK, INTERPRET_COMPILE_ERROR, diff --git a/main.c b/main.c index 45014f5..19e3062 100644 --- a/main.c +++ b/main.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * ProXPL Main Entry Point * Handles REPL mode and file execution diff --git a/scripts/build_unix.sh b/scripts/build_unix.sh index de8d717..ec6ab57 100644 --- a/scripts/build_unix.sh +++ b/scripts/build_unix.sh @@ -1,4 +1,10 @@ #!/usr/bin/env bash +# -------------------------------------------------- +# Project: ProX Programming Language (ProXPL) +# Author: ProgrammerKR +# Created: 2025-12-16 +# Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" diff --git a/scripts/build_windows.ps1 b/scripts/build_windows.ps1 index fa045e2..77b84e8 100644 --- a/scripts/build_windows.ps1 +++ b/scripts/build_windows.ps1 @@ -1,3 +1,9 @@ +# -------------------------------------------------- +# Project: ProX Programming Language (ProXPL) +# Author: ProgrammerKR +# Created: 2025-12-16 +# Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + param( [string]$BuildDir = "$PSScriptRoot\..\build" ) diff --git a/src/compiler/bytecode_gen.c b/src/compiler/bytecode_gen.c new file mode 100644 index 0000000..b07145b --- /dev/null +++ b/src/compiler/bytecode_gen.c @@ -0,0 +1,243 @@ +#include +#include +#include + +#include "../../include/ast.h" +#include "../../include/chunk.h" +#include "../../include/common.h" +#include "../../include/value.h" +#include "../../include/object.h" + +typedef struct { + Chunk* chunk; + // Local scope management (simplified for now, will need full symbol table later) + // For now, we assume global scope if not handled. +} BytecodeGen; + +static void emitByte(BytecodeGen* gen, uint8_t byte, int line) { + writeChunk(gen->chunk, byte, line); +} + +static void emitBytes(BytecodeGen* gen, uint8_t byte1, uint8_t byte2, int line) { + emitByte(gen, byte1, line); + emitByte(gen, byte2, line); +} + +static void emitConstant(BytecodeGen* gen, Value value, int line) { + int constant = addConstant(gen->chunk, value); + if (constant > 255) { + // Handle long constants if needed + fprintf(stderr, "Too many constants in one chunk\n"); + return; + } + emitBytes(gen, OP_CONSTANT, (uint8_t)constant, line); +} + +static int emitJump(BytecodeGen *gen, uint8_t instruction, int line) { + emitByte(gen, instruction, line); + emitByte(gen, 0xff, line); + emitByte(gen, 0xff, line); + return gen->chunk->count - 2; +} + +static void patchJump(BytecodeGen *gen, int offset) { + // -2 to adjust for the bytecode for the jump offset itself. + int jump = gen->chunk->count - offset - 2; + + if (jump > UINT16_MAX) { + fprintf(stderr, "Too much code to jump over.\n"); + } + + gen->chunk->code[offset] = (jump >> 8) & 0xff; + gen->chunk->code[offset + 1] = jump & 0xff; +} + +static void emitLoop(BytecodeGen *gen, int loopStart, int line) { + emitByte(gen, OP_LOOP, line); + + int offset = gen->chunk->count - loopStart + 2; + if (offset > UINT16_MAX) fprintf(stderr, "Loop body too large.\n"); + + emitByte(gen, (offset >> 8) & 0xff, line); + emitByte(gen, offset & 0xff, line); +} + +// Forward declarations for recursive traversal +static void genExpr(BytecodeGen* gen, Expr* expr); +static void genStmt(BytecodeGen* gen, Stmt* stmt); + +static void genExpr(BytecodeGen* gen, Expr* expr) { + if (expr == NULL) return; + + switch (expr->type) { + case EXPR_LITERAL: + if (IS_NUMBER(expr->as.literal.value)) { + emitConstant(gen, expr->as.literal.value, expr->line); + } else if (IS_BOOL(expr->as.literal.value)) { + emitByte(gen, AS_BOOL(expr->as.literal.value) ? OP_TRUE : OP_FALSE, expr->line); + } else if (IS_NULL(expr->as.literal.value)) { + emitByte(gen, OP_NIL, expr->line); + } + break; + + case EXPR_BINARY: + genExpr(gen, expr->as.binary.left); + genExpr(gen, expr->as.binary.right); + + if (strcmp(expr->as.binary.operator, "+") == 0) emitByte(gen, OP_ADD, expr->line); + else if (strcmp(expr->as.binary.operator, "-") == 0) emitByte(gen, OP_SUBTRACT, expr->line); + else if (strcmp(expr->as.binary.operator, "*") == 0) emitByte(gen, OP_MULTIPLY, expr->line); + else if (strcmp(expr->as.binary.operator, "/") == 0) emitByte(gen, OP_DIVIDE, expr->line); + else if (strcmp(expr->as.binary.operator, "==") == 0) emitByte(gen, OP_EQUAL, expr->line); + else if (strcmp(expr->as.binary.operator, "!=") == 0) { + emitBytes(gen, OP_EQUAL, OP_NOT, expr->line); + } + else if (strcmp(expr->as.binary.operator, ">") == 0) emitByte(gen, OP_GREATER, expr->line); + else if (strcmp(expr->as.binary.operator, "<") == 0) emitByte(gen, OP_LESS, expr->line); + else if (strcmp(expr->as.binary.operator, ">=") == 0) { + emitBytes(gen, OP_LESS, OP_NOT, expr->line); + } + else if (strcmp(expr->as.binary.operator, "<=") == 0) { + emitBytes(gen, OP_GREATER, OP_NOT, expr->line); + } + break; + + case EXPR_UNARY: + genExpr(gen, expr->as.unary.right); + if (strcmp(expr->as.unary.operator, "!") == 0) emitByte(gen, OP_NOT, expr->line); + else if (strcmp(expr->as.unary.operator, "-") == 0) emitByte(gen, OP_NEGATE, expr->line); + break; + + case EXPR_GROUPING: + genExpr(gen, expr->as.grouping.expression); + break; + + case EXPR_VARIABLE: { + // Placeholder: Assume global for now + // In a real implementation, we'd lookup in scope and emit OP_GET_LOCAL if found + // For now, we'll need to store the variable name as a constant + Value nameVal = OBJ_VAL(copyString(expr->as.variable.name, strlen(expr->as.variable.name))); + int nameConst = addConstant(gen->chunk, nameVal); + emitBytes(gen, OP_GET_GLOBAL, (uint8_t)nameConst, expr->line); + break; + } + + case EXPR_ASSIGN: { + genExpr(gen, expr->as.assign.value); + Value nameVal = OBJ_VAL(copyString(expr->as.assign.name, strlen(expr->as.assign.name))); + int nameConst = addConstant(gen->chunk, nameVal); + emitBytes(gen, OP_SET_GLOBAL, (uint8_t)nameConst, expr->line); + break; + } + + case EXPR_LOGICAL: { + if (strcmp(expr->as.logical.operator, "&&") == 0) { + genExpr(gen, expr->as.logical.left); + int endJump = emitJump(gen, OP_JUMP_IF_FALSE, expr->line); + emitByte(gen, OP_POP, expr->line); + genExpr(gen, expr->as.logical.right); + patchJump(gen, endJump); + } else { // || + genExpr(gen, expr->as.logical.left); + int elseJump = emitJump(gen, OP_JUMP_IF_FALSE, expr->line); + int endJump = emitJump(gen, OP_JUMP, expr->line); + patchJump(gen, elseJump); + emitByte(gen, OP_POP, expr->line); + genExpr(gen, expr->as.logical.right); + patchJump(gen, endJump); + } + break; + } + + default: + fprintf(stderr, "Unimplemented expression type in BytecodeGen: %d\n", expr->type); + break; + } +} + +static void genStmt(BytecodeGen* gen, Stmt* stmt) { + if (stmt == NULL) return; + + switch (stmt->type) { + case STMT_EXPRESSION: + genExpr(gen, stmt->as.expression.expression); + emitByte(gen, OP_POP, stmt->line); + break; + + case STMT_PRINT: + genExpr(gen, stmt->as.print.expression); + emitByte(gen, OP_PRINT, stmt->line); + break; + + case STMT_RETURN: + if (stmt->as.return_stmt.value != NULL) { + genExpr(gen, stmt->as.return_stmt.value); + } else { + emitByte(gen, OP_NIL, stmt->line); + } + emitByte(gen, OP_RETURN, stmt->line); + break; + + case STMT_BLOCK: + for (int i = 0; i < stmt->as.block.statements->count; i++) { + genStmt(gen, stmt->as.block.statements->items[i]); + } + break; + + case STMT_IF: { + genExpr(gen, stmt->as.if_stmt.condition); + int thenJump = emitJump(gen, OP_JUMP_IF_FALSE, stmt->line); + emitByte(gen, OP_POP, stmt->line); + genStmt(gen, stmt->as.if_stmt.then_branch); + + int elseJump = emitJump(gen, OP_JUMP, stmt->line); + patchJump(gen, thenJump); + emitByte(gen, OP_POP, stmt->line); + + if (stmt->as.if_stmt.else_branch != NULL) { + genStmt(gen, stmt->as.if_stmt.else_branch); + } + patchJump(gen, elseJump); + break; + } + + case STMT_WHILE: { + int loopStart = gen->chunk->count; + genExpr(gen, stmt->as.while_stmt.condition); + + int exitJump = emitJump(gen, OP_JUMP_IF_FALSE, stmt->line); + emitByte(gen, OP_POP, stmt->line); + genStmt(gen, stmt->as.while_stmt.body); + emitLoop(gen, loopStart, stmt->line); + + patchJump(gen, exitJump); + emitByte(gen, OP_POP, stmt->line); + break; + } + + case STMT_VAR_DECL: { + if (stmt->as.var_decl.initializer != NULL) { + genExpr(gen, stmt->as.var_decl.initializer); + } else { + emitByte(gen, OP_NIL, stmt->line); + } + Value nameVal = OBJ_VAL(copyString(stmt->as.var_decl.name, strlen(stmt->as.var_decl.name))); + int nameConst = addConstant(gen->chunk, nameVal); + emitBytes(gen, OP_DEFINE_GLOBAL, (uint8_t)nameConst, stmt->line); + break; + } + + default: + fprintf(stderr, "Unimplemented statement type in BytecodeGen: %d\n", stmt->type); + break; + } +} + +void generateBytecode(StmtList* statements, Chunk* chunk) { + BytecodeGen gen; + gen.chunk = chunk; + + for (int i = 0; i < statements->count; i++) { + genStmt(&gen, statements->items[i]); + } +} diff --git a/src/lexer/scanner.c b/src/compiler/lexer/scanner.c similarity index 98% rename from src/lexer/scanner.c rename to src/compiler/lexer/scanner.c index 84ec02b..08dc842 100644 --- a/src/lexer/scanner.c +++ b/src/compiler/lexer/scanner.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #include #include diff --git a/src/compiler/llvm_backend.cpp b/src/compiler/llvm_backend.cpp new file mode 100644 index 0000000..8695ff5 --- /dev/null +++ b/src/compiler/llvm_backend.cpp @@ -0,0 +1,274 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include + +// Include C AST headers +extern "C" { + #include "ast.h" +} + +using namespace llvm; + +class ProXPLCompiler { +public: + ProXPLCompiler() { + Context = std::make_unique(); + ModuleOb = std::make_unique("ProXPL Module", *Context); + Builder = std::make_unique>(*Context); + } + + void compile(StmtList* program) { + // Create main function: int main() + FunctionType *MainFuncType = FunctionType::get(Builder->getInt32Ty(), false); + Function *MainFunc = Function::Create(MainFuncType, Function::ExternalLinkage, "main", ModuleOb.get()); + + BasicBlock *EntryBB = BasicBlock::Create(*Context, "entry", MainFunc); + Builder->SetInsertPoint(EntryBB); + + // Compile statements + if (program) { + for (int i = 0; i < program->count; i++) { + visitStmt(program->items[i]); + } + } + + // Return 0 if no explicit return + if (!MainFunc->back().getTerminator()) { + Builder->CreateRet(Builder->getInt32(0)); + } + + // Verify validity + verifyFunction(*MainFunc); + } + + void dump() { + ModuleOb->print(errs(), nullptr); + } + +private: + std::unique_ptr Context; + std::unique_ptr ModuleOb; + std::unique_ptr> Builder; + std::map NamedValues; // Stack variables + + // Helper: Create an alloca in the entry block of the function + AllocaInst* createEntryBlockAlloca(Function *TheFunction, const std::string &VarName, Type* type) { + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); + return TmpB.CreateAlloca(type, 0, VarName.c_str()); + } + + // Helper: Get LLVM Type from AST TypeKind + Type* getLLVMType(TypeKind kind) { + switch (kind) { + case TYPE_INT: return Builder->getInt32Ty(); // 32-bit int + case TYPE_FLOAT: return Builder->getDoubleTy(); // 64-bit float + case TYPE_BOOL: return Builder->getInt1Ty(); + case TYPE_VOID: return Builder->getVoidTy(); + // TODO: String, etc. + default: return Builder->getDoubleTy(); // Default to double (VM behavior) + } + } + + Value* visitExpr(Expr* expr) { + if (!expr) return nullptr; + + switch (expr->type) { + case EXPR_LITERAL: { + // Check value type from AST Literal Value + if (IS_BOOL(expr->as.literal.value)) { + return ConstantInt::get(*Context, APInt(1, AS_BOOL(expr->as.literal.value) ? 1 : 0, true)); + } else if (IS_NUMBER(expr->as.literal.value)) { + // Start as Double by default from VM value + return ConstantFP::get(*Context, APFloat(AS_NUMBER(expr->as.literal.value))); + } + return nullptr; + } + + case EXPR_VARIABLE: { + // Load from stack + AllocaInst* A = NamedValues[expr->as.variable.name]; + if (!A) { + std::cerr << "Unknown variable: " << expr->as.variable.name << "\n"; + return nullptr; + } + return Builder->CreateLoad(A->getAllocatedType(), A, expr->as.variable.name); + } + + case EXPR_ASSIGN: { + Value* Val = visitExpr(expr->as.assign.value); + if (!Val) return nullptr; + + AllocaInst* A = NamedValues[expr->as.assign.name]; + if (!A) { + std::cerr << "Unknown variable assignment: " << expr->as.assign.name << "\n"; + return nullptr; + } + + // Type Cast if necessary? + // Simple store for now + Builder->CreateStore(Val, A); + return Val; + } + + case EXPR_BINARY: { + Value *L = visitExpr(expr->as.binary.left); + Value *R = visitExpr(expr->as.binary.right); + if (!L || !R) return nullptr; + + // Determine Mode based on Inferred Type or Operand Types + // Assuming AST TypeChecker has run, we can look at logic. + // Or simply look at LLVM Value type + bool isFloat = L->getType()->isDoubleTy() || R->getType()->isDoubleTy(); + + // Auto-promote for mixed - simpler than checking AST + if (L->getType()->isIntegerTy() && R->getType()->isDoubleTy()) { + L = Builder->CreateSIToFP(L, Builder->getDoubleTy(), "intcast"); + } else if (L->getType()->isDoubleTy() && R->getType()->isIntegerTy()) { + R = Builder->CreateSIToFP(R, Builder->getDoubleTy(), "intcast"); + } + + std::string op = expr->as.binary.operator; + if (op == "+") return isFloat ? Builder->CreateFAdd(L, R, "addtmp") : Builder->CreateAdd(L, R, "addtmp"); + if (op == "-") return isFloat ? Builder->CreateFSub(L, R, "subtmp") : Builder->CreateSub(L, R, "subtmp"); + if (op == "*") return isFloat ? Builder->CreateFMul(L, R, "multmp") : Builder->CreateMul(L, R, "multmp"); + if (op == "/") return isFloat ? Builder->CreateFDiv(L, R, "divtmp") : Builder->CreateSDiv(L, R, "divtmp"); // SDiv for signed int + + if (op == "<") return isFloat ? Builder->CreateFCmpULT(L, R, "cmptmp") : Builder->CreateICmpSLT(L, R, "cmptmp"); + if (op == ">") return isFloat ? Builder->CreateFCmpUGT(L, R, "cmptmp") : Builder->CreateICmpSGT(L, R, "cmptmp"); + + return nullptr; + } + default: + std::cerr << "Unknown expression type: " << expr->type << "\n"; + return nullptr; + } + } + + void visitStmt(Stmt* stmt) { + if (!stmt) return; + + switch (stmt->type) { + case STMT_VAR_DECL: { + Function *TheFunction = Builder->GetInsertBlock()->getParent(); + const char* varName = stmt->as.var_decl.name; + + // Determine Type: + // 1. From explicit type in AST (set by TypeChecker) + // 2. Or default to Double + Type* llvmType = getLLVMType(stmt->as.var_decl.type.kind); + + // Initialize Value + Value* InitVal = nullptr; + if (stmt->as.var_decl.initializer) { + InitVal = visitExpr(stmt->as.var_decl.initializer); + // Match type if needed + if (InitVal->getType() != llvmType) { + // Cast logic here if strict + } + } else { + // Default init? + InitVal = Constant::getNullValue(llvmType); + } + + AllocaInst* Alloca = createEntryBlockAlloca(TheFunction, varName, llvmType); + Builder->CreateStore(InitVal, Alloca); + + // Remember valid variable in scope + NamedValues[varName] = Alloca; + break; + } + + case STMT_EXPRESSION: + visitExpr(stmt->as.expression.expression); + break; + + case STMT_RETURN: + if (stmt->as.return_stmt.value) { + Value* V = visitExpr(stmt->as.return_stmt.value); + // If main returns int, but V is double, Cast + if (V->getType()->isDoubleTy()) { + V = Builder->CreateFPToSI(V, Builder->getInt32Ty(), "cast_ret"); + } + Builder->CreateRet(V); + } else { + Builder->CreateRetVoid(); + } + break; + + case STMT_IF: { + Value* CondV = visitExpr(stmt->as.if_stmt.condition); + if (!CondV) return; + + // Convert to bool if needed + if (!CondV->getType()->isIntegerTy(1)) { + CondV = Builder->CreateFCmpONE(CondV, ConstantFP::get(*Context, APFloat(0.0)), "ifcond"); + } + + Function *TheFunction = Builder->GetInsertBlock()->getParent(); + + BasicBlock *ThenBB = BasicBlock::Create(*Context, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(*Context, "else"); + BasicBlock *MergeBB = BasicBlock::Create(*Context, "ifcont"); + + // Check if 'else' exists + bool hasElse = (stmt->as.if_stmt.else_branch != nullptr); + + Builder->CreateCondBr(CondV, ThenBB, hasElse ? ElseBB : MergeBB); + + // Emit Then + Builder->SetInsertPoint(ThenBB); + visitStmt(stmt->as.if_stmt.then_branch); + // Branch to Merge if not returned + if (!ThenBB->getTerminator()) Builder->CreateBr(MergeBB); + + // Emit Else + if (hasElse) { + TheFunction->getBasicBlockList().push_back(ElseBB); + Builder->SetInsertPoint(ElseBB); + visitStmt(stmt->as.if_stmt.else_branch); + // Branch to Merge if not returned + if (!ElseBB->getTerminator()) Builder->CreateBr(MergeBB); + } + + // Emit Merge + TheFunction->getBasicBlockList().push_back(MergeBB); + Builder->SetInsertPoint(MergeBB); + break; + } + + case STMT_BLOCK: { + // Scoping logic for NamedValues would be needed here for true block scope + // For now, flat scope + StmtList* list = stmt->as.block.statements; + for (int i=0; i < list->count; i++) { + visitStmt(list->items[i]); + } + break; + } + + default: + std::cerr << "Unknown statement type: " << stmt->type << "\n"; + break; + } + } +}; + +// --- C-Compatible API --- +extern "C" { + void generateCode(StmtList* program) { + ProXPLCompiler compiler; + compiler.compile(program); + compiler.dump(); // Print IR to stdout + } +} diff --git a/src/parser/ast.c b/src/compiler/parser/ast.c similarity index 96% rename from src/parser/ast.c rename to src/compiler/parser/ast.c index 3445748..9392df3 100644 --- a/src/parser/ast.c +++ b/src/compiler/parser/ast.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #include "ast.h" #include "memory.h" #include @@ -443,6 +449,15 @@ Stmt *createTryCatchStmt(StmtList *try_blk, const char *catch_var, return stmt; } +Stmt *createPrintStmt(Expr *expression, int line, int column) { + Stmt *stmt = ALLOCATE(Stmt, 1); + stmt->type = STMT_PRINT; + stmt->line = line; + stmt->column = column; + stmt->as.print.expression = expression; + return stmt; +} + // --- Free Functions --- void freeExpr(Expr *expr) { @@ -491,9 +506,8 @@ void freeExpr(Expr *expr) { freeExpr(expr->as.set.value); break; case EXPR_INDEX: - freeExpr(expr -\u003eas.index.target); - freeExpr(expr -\u003eas.index.index); - + freeExpr(expr->as.index.target); + freeExpr(expr->as.index.index); break; case EXPR_LIST: freeExprList(expr->as.list.elements); @@ -576,6 +590,9 @@ void freeStmt(Stmt *stmt) { freeStmtList(stmt->as.try_catch.catch_block); freeStmtList(stmt->as.try_catch.finally_block); break; + case STMT_PRINT: + freeExpr(stmt->as.print.expression); + break; } FREE(Stmt, stmt); diff --git a/src/parser/parser.c b/src/compiler/parser/parser.c similarity index 97% rename from src/parser/parser.c rename to src/compiler/parser/parser.c index e64e884..73ffb08 100644 --- a/src/parser/parser.c +++ b/src/compiler/parser/parser.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #include "parser.h" #include "memory.h" #include @@ -20,6 +26,7 @@ static Stmt *tryStmt(Parser *p); static Stmt *returnStmt(Parser *p); static Stmt *breakStmt(Parser *p); static Stmt *continueStmt(Parser *p); +static Stmt *printStmt(Parser *p); static Stmt *exprStmt(Parser *p); static StmtList *block(Parser *p); @@ -288,6 +295,8 @@ static Stmt *statement(Parser *p) { return breakStmt(p); if (match(p, 1, TOKEN_CONTINUE)) return continueStmt(p); + if (match(p, 1, TOKEN_PRINT)) + return printStmt(p); if (match(p, 1, TOKEN_LEFT_BRACE)) { StmtList *stmts = block(p); return createBlockStmt(stmts, previous(p).line, 0); @@ -453,6 +462,12 @@ static StmtList *block(Parser *p) { return statements; } +static Stmt *printStmt(Parser *p) { + Expr *value = expression(p); + consume(p, TOKEN_SEMICOLON, "Expect ';' after value."); + return createPrintStmt(value, previous(p).line, 0); +} + static Stmt *exprStmt(Parser *p) { Expr *expr = expression(p); consume(p, TOKEN_SEMICOLON, "Expect ';'."); diff --git a/src/parser/type_checker.c b/src/compiler/parser/type_checker.c similarity index 72% rename from src/parser/type_checker.c rename to src/compiler/parser/type_checker.c index bd9b116..07a43e3 100644 --- a/src/parser/type_checker.c +++ b/src/compiler/parser/type_checker.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * Type Checker - STUB IMPLEMENTATION * diff --git a/src/compiler/type_checker.c b/src/compiler/type_checker.c new file mode 100644 index 0000000..b2e2b9c --- /dev/null +++ b/src/compiler/type_checker.c @@ -0,0 +1,456 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + +#include "type_checker.h" +#include +#include +#include + +// --- Memory & Helper Functions --- + +static TypeInfo createType(TypeKind kind) { + TypeInfo t; + t.kind = kind; + t.name = NULL; + t.returnType = NULL; + t.paramTypes = NULL; + t.paramCount = 0; + return t; +} + +static bool isTypesEqual(TypeInfo t1, TypeInfo t2) { + if (t1.kind != t2.kind) return false; + // For structs/classes, check name + if (t1.kind == TYPE_CLASS) { + if (t1.name && t2.name) return strcmp(t1.name, t2.name) == 0; + } + // Deep check for functions could go here + return true; +} + +static const char* typeToString(TypeKind kind) { + switch (kind) { + case TYPE_UNKNOWN: return "Unknown"; + case TYPE_VOID: return "Void"; + case TYPE_BOOL: return "Bool"; + case TYPE_INT: return "Int"; + case TYPE_FLOAT: return "Float"; + case TYPE_STRING: return "String"; + case TYPE_FUNCTION: return "Function"; + case TYPE_CLASS: return "Class"; + default: return "Invalid"; + } +} + +// --- Symbol Table Helpers --- + +static Scope* beginScope(TypeChecker* checker) { + Scope* scope = (Scope*)malloc(sizeof(Scope)); + if (!scope) { + fprintf(stderr, "Fatal: Out of memory for scope.\n"); + exit(1); + } + memset(scope->table, 0, sizeof(scope->table)); + scope->parent = checker->currentScope; + checker->currentScope = scope; + return scope; +} + +static void endScope(TypeChecker* checker) { + Scope* scope = checker->currentScope; + checker->currentScope = scope->parent; + + // Free symbols in this scope + for (int i = 0; i < TABLE_SIZE; i++) { + Symbol* sym = scope->table[i]; + while (sym) { + Symbol* next = sym->next; + // TypeInfo might have allocated members, but for now we assume AST ownership + // or simple types. If we alloc param arrays, we should free them here. + if (sym->type.paramTypes) free(sym->type.paramTypes); + free(sym->type.returnType); + free(sym); + sym = next; + } + } + free(scope); +} + +static unsigned int hash(const char* name) { + unsigned int h = 2166136261u; + for (; *name; name++) { + h ^= *name; + h *= 16777619; + } + return h % TABLE_SIZE; +} + +static void defineSymbol(TypeChecker* checker, const char* name, TypeInfo type) { + Scope* scope = checker->currentScope; + unsigned int idx = hash(name); + + Symbol* sym = (Symbol*)malloc(sizeof(Symbol)); + sym->name = (char*)name; // Weak reference + sym->type = type; + sym->next = scope->table[idx]; + scope->table[idx] = sym; +} + +static TypeInfo lookupSymbol(TypeChecker* checker, const char* name) { + Scope* scope = checker->currentScope; + unsigned int idx = hash(name); + + while (scope) { + Symbol* sym = scope->table[idx]; + while (sym) { + if (strcmp(sym->name, name) == 0) return sym->type; + sym = sym->next; + } + scope = scope->parent; + } + + return createType(TYPE_UNKNOWN); +} + +// helpers exposed +TypeInfo resolveVariableType(TypeChecker* checker, const char* name) { + return lookupSymbol(checker, name); +} + +// --- Type Checking Logic --- + +static void error(TypeChecker* checker, int line, const char* msg) { + fprintf(stderr, "[Type Error] Line %d: %s\n", line, msg); + checker->errorCount++; +} + +static TypeInfo checkExpr(TypeChecker* checker, Expr* expr); +static void checkStmt(TypeChecker* checker, Stmt* stmt); + +static TypeInfo checkBinary(TypeChecker* checker, Expr* expr) { + TypeInfo l = checkExpr(checker, expr->as.binary.left); + TypeInfo r = checkExpr(checker, expr->as.binary.right); + + const char* op = expr->as.binary.operator; + + // If operands are unknown, we can't strict check, so we propagate unknown or assume valid? + // Let's be safe: if unknown, we can't guarantee safety, but usually in static analysis we warn. + // Here we will allow it to proceed as Unknown to avoid cascading errors. + if (l.kind == TYPE_UNKNOWN || r.kind == TYPE_UNKNOWN) { + return createType(TYPE_UNKNOWN); + } + + // Arithmetic: +, -, *, /, % + if (strcmp(op, "+") == 0 || strcmp(op, "-") == 0 || + strcmp(op, "*") == 0 || strcmp(op, "/") == 0) { + + if (l.kind == TYPE_INT && r.kind == TYPE_INT) return l; // Int + Int = Int + if (l.kind == TYPE_FLOAT && r.kind == TYPE_FLOAT) return l; // Float + Float = Float + + // Promotion + if ((l.kind == TYPE_INT && r.kind == TYPE_FLOAT) || + (l.kind == TYPE_FLOAT && r.kind == TYPE_INT)) { + return createType(TYPE_FLOAT); + } + + // String Concatenation + if (strcmp(op, "+") == 0) { + if (l.kind == TYPE_STRING && r.kind == TYPE_STRING) return l; + // Maybe allow String + Int -> String? + if (l.kind == TYPE_STRING || r.kind == TYPE_STRING) return createType(TYPE_STRING); + } + + error(checker, expr->line, "Type mismatch in binary operation."); + return createType(TYPE_UNKNOWN); + } + + // Comparisons: <, >, <=, >= + if (strcmp(op, "<") == 0 || strcmp(op, ">") == 0 || + strcmp(op, "<=") == 0 || strcmp(op, ">=") == 0) { + + if (l.kind == TYPE_INT || l.kind == TYPE_FLOAT) { + if (r.kind == TYPE_INT || r.kind == TYPE_FLOAT) { + return createType(TYPE_BOOL); + } + } + error(checker, expr->line, " Comparison operands must be numbers."); + return createType(TYPE_BOOL); // Return bool to recover + } + + // Equality: ==, != + if (strcmp(op, "==") == 0 || strcmp(op, "!=") == 0) { + if (!isTypesEqual(l, r)) { + // "1" == 1 is often false in static strict + // error(checker, expr->line, "Types must match for equality."); + // Actually, equality between different types is usually just 'false', not an error. + // But strict typing often forbids it. + } + return createType(TYPE_BOOL); + } + + return createType(TYPE_UNKNOWN); +} + +static TypeInfo checkUnary(TypeChecker* checker, Expr* expr) { + TypeInfo r = checkExpr(checker, expr->as.unary.right); + const char* op = expr->as.unary.operator; + + if (strcmp(op, "!") == 0) { + if (r.kind != TYPE_BOOL && r.kind != TYPE_UNKNOWN) { + error(checker, expr->line, "Example error: '!' requires boolean operand."); + } + return createType(TYPE_BOOL); + } + if (strcmp(op, "-") == 0) { + if (r.kind != TYPE_INT && r.kind != TYPE_FLOAT && r.kind != TYPE_UNKNOWN) { + error(checker, expr->line, "Negation requires numeric operand."); + } + return r; // Returns same type (Int or Float) + } + return createType(TYPE_UNKNOWN); +} + +static TypeInfo checkExpr(TypeChecker* checker, Expr* expr) { + if (!expr) return createType(TYPE_VOID); + + TypeInfo result = createType(TYPE_UNKNOWN); + + switch (expr->type) { + case EXPR_LITERAL: { + // Need to inspect Value type + Value v = expr->as.literal.value; + if (IS_BOOL(v)) result = createType(TYPE_BOOL); + else if (IS_NUMBER(v)) { + // In this VM, numbers are doubles, but let's pretend we have Ints if whole number? + // For now, always FLOAT to match VM. + result = createType(TYPE_FLOAT); + } + else if (IS_NIL(v)) result = createType(TYPE_VOID); + else if (IS_OBJ(v)) { + // Assume string for now if ObjString + result = createType(TYPE_STRING); + } + break; + } + + case EXPR_BINARY: + result = checkBinary(checker, expr); + break; + + case EXPR_UNARY: + result = checkUnary(checker, expr); + break; + + case EXPR_GROUPING: + result = checkExpr(checker, expr->as.grouping.expression); + break; + + case EXPR_VARIABLE: + result = lookupSymbol(checker, expr->as.variable.name); + if (result.kind == TYPE_UNKNOWN) { + // error(checker, expr->line, "Undefined variable."); + // Don't error if it's truly unknown (maybe from function param without type), + // but usually lookup returns UNKNOWN if NOT FOUND. + // We need to distinguish Not Found vs Unknown Type. + // For this simple implementation, UNKNOWN means either. + } + break; + + case EXPR_ASSIGN: { + TypeInfo varType = lookupSymbol(checker, expr->as.assign.name); + TypeInfo valType = checkExpr(checker, expr->as.assign.value); + + if (varType.kind == TYPE_UNKNOWN) { + // First assignment? Or undefined variable? + // If undefined, error. But lookupSymbol returns UNKNOWN if not found. + // We should probably check if it was declared. + error(checker, expr->line, "Assignment to undefined or untyped variable."); + } else { + if (!isTypesEqual(varType, valType) && valType.kind != TYPE_UNKNOWN) { + if (!(varType.kind == TYPE_FLOAT && valType.kind == TYPE_INT)) { + error(checker, expr->line, "Type mismatch in assignment."); + } + } + } + result = valType; + break; + } + + case EXPR_CALL: { + TypeInfo callee = checkExpr(checker, expr->as.call.callee); + // Verify args + // If callee is FUNCTION, check params + // Currently AST might not have function types populated fully. + ExprList* args = expr->as.call.arguments; + if (args) { + for (int i=0; icount; i++) { + checkExpr(checker, args->items[i]); + } + } + + if (callee.kind == TYPE_FUNCTION) { + if (callee.returnType) { + result = *callee.returnType; // Copy return type + } + // TODO: Check argument types against callee.paramTypes + } else if (callee.kind == TYPE_UNKNOWN) { + // Assume it works + } else { + error(checker, expr->line, "Attempt to call non-function."); + } + break; + } + + default: + // Relaxed for others + break; + } + + expr->inferredType = result; + return result; +} + +static void checkStmt(TypeChecker* checker, Stmt* stmt) { + if (!stmt) return; + + switch (stmt->type) { + case STMT_VAR_DECL: { + TypeInfo declaredType = stmt->as.var_decl.type; + + // If initialized, check compatibility + if (stmt->as.var_decl.initializer) { + TypeInfo initType = checkExpr(checker, stmt->as.var_decl.initializer); + + if (declaredType.kind == TYPE_UNKNOWN) { + // Inference + declaredType = initType; + stmt->as.var_decl.type = initType; + } else { + if (!isTypesEqual(declaredType, initType) && initType.kind != TYPE_UNKNOWN) { + // Allow Int -> Float + if (!(declaredType.kind == TYPE_FLOAT && initType.kind == TYPE_INT)) { + error(checker, stmt->line, "Variable initializer type mismatch."); + } + } + } + } else { + // No initializer. If type is unknown, that's an issue for static typing. + if (declaredType.kind == TYPE_UNKNOWN) { + // error(checker, stmt->line, "Variable requires type or initializer."); + // Allow for now, will be TYPE_UNKNOWN (dynamic) + } + } + + defineSymbol(checker, stmt->as.var_decl.name, declaredType); + break; + } + + case STMT_FUNC_DECL: { + // Function Name + TypeInfo funcType = createType(TYPE_FUNCTION); + // Setup signature + + // We need to capture return type if specified or inferred + if (stmt->as.func_decl.returnType.kind != TYPE_UNKNOWN) { + funcType.returnType = (TypeInfo*)malloc(sizeof(TypeInfo)); + *funcType.returnType = stmt->as.func_decl.returnType; + } else { + // Will try to infer from body later? + // For recursion, we need to define symbol first. + // Let's assume Void if not specified? Or Unknown. + } + + // Define function symbol in CURRENT scope (before entering body) + defineSymbol(checker, stmt->as.func_decl.name, funcType); + + // Enter Body Scope + beginScope(checker); + + // Define Parameters + if (stmt->as.func_decl.params) { + StringList* params = stmt->as.func_decl.params; + for (int i=0; i < params->count; i++) { + // Params are unknown/dynamic for now as Parser doesn't have types + defineSymbol(checker, params->items[i], createType(TYPE_UNKNOWN)); + } + } + + checkStmt(checker, (Stmt*)stmt->as.func_decl.body); // Cast BlockStmt* to Stmt*? No, BlockStmt is a union member. + // StmtList* is what body is + StmtList* body = stmt->as.func_decl.body; + if (body) { + for(int i=0; icount; i++) { + checkStmt(checker, body->items[i]); + } + } + + endScope(checker); + break; + } + + case STMT_EXPRESSION: + checkExpr(checker, stmt->as.expression.expression); + break; + + case STMT_BLOCK: + beginScope(checker); + StmtList* list = stmt->as.block.statements; + for (int i=0; i < list->count; i++) { + checkStmt(checker, list->items[i]); + } + endScope(checker); + break; + + case STMT_IF: + checkExpr(checker, stmt->as.if_stmt.condition); + // Expect Bool? + // if (condType.kind != TYPE_BOOL) ... + checkStmt(checker, stmt->as.if_stmt.then_branch); + if (stmt->as.if_stmt.else_branch) checkStmt(checker, stmt->as.if_stmt.else_branch); + break; + + case STMT_RETURN: { + TypeInfo retType; + if (stmt->as.return_stmt.value) { + retType = checkExpr(checker, stmt->as.return_stmt.value); + } else { + retType = createType(TYPE_VOID); + } + // TODO: Match validity against current function return type + break; + } + + default: + break; + } +} + +// --- Public Entry Points --- + +void initTypeChecker(TypeChecker *checker) { + checker->errorCount = 0; + checker->currentScope = NULL; + beginScope(checker); // Global Scope + + // Define Builtins? + // defineSymbol(checker, "print", ...); +} + +bool checkTypes(TypeChecker *checker, StmtList *statements) { + if (!statements) return true; + + for (int i = 0; i < statements->count; i++) { + checkStmt(checker, statements->items[i]); + } + + return checker->errorCount == 0; +} + +void freeTypeChecker(TypeChecker *checker) { + while (checker->currentScope) { + endScope(checker); + } +} diff --git a/src/main.c b/src/main.c index 45014f5..562ca82 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * ProXPL Main Entry Point * Handles REPL mode and file execution @@ -15,7 +21,11 @@ #include -static void repl(VM *vm) { +void registerStdLib(VM* vm); + +// Declare global VM instance - already in vm.c + +static void repl() { char line[1024]; printf("ProXPL v1.0 REPL\n"); @@ -80,11 +90,15 @@ static void repl(VM *vm) { continue; } - // TODO: Compile and execute - // For now, just indicate success - printf("Parsed successfully (%d statements)\n", statements->count); + // --- Pipeline: AST -> Bytecode -> VM --- + Chunk chunk; + initChunk(&chunk); + generateBytecode(statements, &chunk); + + interpret(&vm, &chunk); - // Free AST + // Free resources + freeChunk(&chunk); freeStmtList(statements); } } @@ -121,7 +135,10 @@ static char *readFile(const char *path) { return buffer; } -static void runFile(VM *vm, const char *path) { +extern void generateCode(StmtList* statements); // Defined in llvm_backend.cpp +#include "type_checker.h" + +static void runFile(const char *path) { char *source = readFile(path); if (source == NULL) { exit(74); @@ -168,21 +185,46 @@ static void runFile(VM *vm, const char *path) { printf("Successfully parsed %d statements from %s\n", statements->count, path); - // TODO: Compile and execute - // InterpretResult result = interpret(source); + // --- Pipeline Step 2: Type Checking --- + printf("Running Type Checker...\n"); + TypeChecker checker; + initTypeChecker(&checker); + + if (!checkTypes(&checker, statements)) { + fprintf(stderr, "Type Checking Failed with %d errors.\n", checker.errorCount); + freeTypeChecker(&checker); + freeStmtList(statements); + free(source); + exit(65); + } + freeTypeChecker(&checker); + printf("Type Check Passed.\n"); + + // --- Pipeline Step 3: Bytecode Gen & Execution --- + printf("Generating Bytecode...\n"); + Chunk chunk; + initChunk(&chunk); + generateBytecode(statements, &chunk); + + printf("Executing VM...\n"); + InterpretResult result = interpret(&vm, &chunk); + if (result != INTERPRET_OK) { + fprintf(stderr, "Execution Failed.\n"); + } + + // --- Pipeline Step 4: LLVM CodeGen (Optional/Future) --- + // printf("Generating LLVM IR...\n"); + // generateCode(statements); // Free resources + freeChunk(&chunk); freeStmtList(statements); free(source); - - // Exit based on result - // if (result == INTERPRET_COMPILE_ERROR) exit(65); - // if (result == INTERPRET_RUNTIME_ERROR) exit(70); } + int main(int argc, const char *argv[]) { // Initialize VM - VM vm; initVM(&vm); // Register standard library @@ -190,16 +232,16 @@ int main(int argc, const char *argv[]) { if (argc == 1) { // REPL mode - repl(&vm); + repl(); } else if (argc == 2) { // File execution mode - runFile(&vm, argv[1]); + runFile(argv[1]); } else if (argc >= 3) { // Handle subcommands const char *command = argv[1]; if (strcmp(command, "run") == 0) { - runFile(&vm, argv[2]); + runFile(argv[2]); } else if (strcmp(command, "build") == 0) { printf("Build command not yet implemented\n"); exit(1); diff --git a/src/protos/vm_register.c b/src/protos/vm_register.c new file mode 100644 index 0000000..60d9699 --- /dev/null +++ b/src/protos/vm_register.c @@ -0,0 +1,145 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + +/* + Prototype Register-Based VM for ProXPL + -------------------------------------- + Structure: 32-bit instructions (Opcode:8, A:8, B:8, C:8) +*/ + +#include +#include +#include + +// --- Instruction Format --- +// | Opcode (8) | A (8) | B (8) | C (8) | +// A: Destination Register +// B: Source Register 1 +// C: Source Register 2 / Immediate + +typedef uint32_t Instruction; + +#define OP_MASK 0xFF +#define REG_MASK 0xFF + +#define GET_OP(i) ((i) & OP_MASK) +#define GET_A(i) (((i) >> 8) & REG_MASK) +#define GET_B(i) (((i) >> 16) & REG_MASK) +#define GET_C(i) (((i) >> 24) & REG_MASK) + +#define MK_INS(op, a, b, c) \ + ((op) | ((a) << 8) | ((b) << 16) | ((c) << 24)) + +// --- Opcodes --- +enum OpCode { + OP_HALT = 0, + OP_LOADK, // R[A] = Consts[B] + OP_MOV, // R[A] = R[B] + OP_ADD, // R[A] = R[B] + R[C] + OP_SUB, + OP_PRINT // print R[A] +}; + +// --- VM State --- +#define MAX_REGS 256 +#define MAX_CONSTS 256 + +typedef struct { + double numbers[MAX_CONSTS]; +} ConstTable; + +typedef struct { + Instruction* code; + size_t count; + ConstTable* consts; +} ProtoChunk; + +typedef struct { + double registers[MAX_REGS]; // Simplified Value type for prototype + Instruction* ip; +} RegisterVM; + +// --- Interpreter Loop --- +void run_register_vm(RegisterVM* vm, ProtoChunk* chunk) { + vm->ip = chunk->code; + + printf("Starting Register VM execution...\n"); + + for (;;) { + Instruction ins = *vm->ip++; + uint8_t op = GET_OP(ins); + + // Computed goto would go here in production + switch (op) { + case OP_HALT: + printf("HALT encountered.\n"); + return; + + case OP_LOADK: { + uint8_t target = GET_A(ins); + uint8_t k_idx = GET_B(ins); + vm->registers[target] = chunk->consts->numbers[k_idx]; + // printf("LOADK R[%d] = %f\n", target, vm->registers[target]); + break; + } + + case OP_MOV: { + uint8_t dest = GET_A(ins); + uint8_t src = GET_B(ins); + vm->registers[dest] = vm->registers[src]; + break; + } + + case OP_ADD: { + uint8_t dest = GET_A(ins); + uint8_t src1 = GET_B(ins); + uint8_t src2 = GET_C(ins); + // Type checking would happen here in full VM + vm->registers[dest] = vm->registers[src1] + vm->registers[src2]; + // printf("ADD R[%d] = %f + %f = %f\n", dest, vm->registers[src1], vm->registers[src2], vm->registers[dest]); + break; + } + + case OP_PRINT: { + uint8_t src = GET_A(ins); + printf("OUT: %f\n", vm->registers[src]); + break; + } + + default: + printf("Unknown Opcode: %d\n", op); + return; + } + } +} + +// --- Test Driver --- +int main() { + // Defines a simple program: + // val1 = 10.5 + // val2 = 20.5 + // result = val1 + val2 + // print result + + Instruction code[] = { + MK_INS(OP_LOADK, 0, 0, 0), // R0 = Const[0] (10.5) + MK_INS(OP_LOADK, 1, 1, 0), // R1 = Const[1] (20.5) + MK_INS(OP_ADD, 2, 0, 1), // R2 = R0 + R1 + MK_INS(OP_PRINT, 2, 0, 0), // PRINT R2 + MK_INS(OP_HALT, 0, 0, 0) + }; + + ConstTable constants; + constants.numbers[0] = 10.5; + constants.numbers[1] = 20.5; + + ProtoChunk chunk = { .code = code, .count = 5, .consts = &constants }; + RegisterVM vm; + + run_register_vm(&vm, &chunk); + + return 0; +} diff --git a/src/proxpl_api.c b/src/proxpl_api.c index 64039c0..2599bc4 100644 --- a/src/proxpl_api.c +++ b/src/proxpl_api.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* proxpl_api.c - public API wrappers for stable ABI * Exposes a minimal C-style API that callers can use to embed runtime. */ diff --git a/src/runtime/chunk.c b/src/runtime/chunk.c index 2bedef2..988db96 100644 --- a/src/runtime/chunk.c +++ b/src/runtime/chunk.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #include #include "chunk.h" diff --git a/src/runtime/compiler.c b/src/runtime/compiler.c index 3a1995f..e0a6ab4 100644 --- a/src/runtime/compiler.c +++ b/src/runtime/compiler.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #include #include diff --git a/src/runtime/debug.c b/src/runtime/debug.c index 2f682b0..84d6395 100644 --- a/src/runtime/debug.c +++ b/src/runtime/debug.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #include #include "debug.h" diff --git a/src/runtime/memory.c b/src/runtime/memory.c index 637f01e..869d4b4 100644 --- a/src/runtime/memory.c +++ b/src/runtime/memory.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #include #include "memory.h" diff --git a/src/runtime/object.c b/src/runtime/object.c index e3292d1..0c68281 100644 --- a/src/runtime/object.c +++ b/src/runtime/object.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #include #include diff --git a/src/runtime/table.c b/src/runtime/table.c new file mode 100644 index 0000000..eb089d5 --- /dev/null +++ b/src/runtime/table.c @@ -0,0 +1,133 @@ +#include +#include + +#include "../../include/memory.h" +#include "../../include/object.h" +#include "../../include/table.h" +#include "../../include/value.h" + +#define TABLE_MAX_LOAD 0.75 + +void initTable(Table *table) { + table->count = 0; + table->capacity = 0; + table->entries = NULL; +} + +void freeTable(Table *table) { + FREE_ARRAY(Entry, table->entries, table->capacity); + initTable(table); +} + +static Entry *findEntry(Entry *entries, int capacity, ObjString *key) { + uint32_t index = key->hash % capacity; + Entry *tombstone = NULL; + + for (;;) { + Entry *entry = &entries[index]; + if (entry->key == NULL) { + if (IS_NULL(entry->value)) { + // Empty entry. + return tombstone != NULL ? tombstone : entry; + } else { + // We found a tombstone. + if (tombstone == NULL) tombstone = entry; + } + } else if (entry->key == key) { + // We found the key. + return entry; + } + + index = (index + 1) % capacity; + } +} + +static void adjustCapacity(Table *table, int capacity) { + Entry *entries = ALLOCATE(Entry, capacity); + for (int i = 0; i < capacity; i++) { + entries[i].key = NULL; + entries[i].value = NULL_VAL; + } + + table->count = 0; // Don't count tombstones anymore + for (int i = 0; i < table->capacity; i++) { + Entry *entry = &table->entries[i]; + if (entry->key == NULL) continue; + + Entry *dest = findEntry(entries, capacity, entry->key); + dest->key = entry->key; + dest->value = entry->value; + table->count++; + } + + FREE_ARRAY(Entry, table->entries, table->capacity); + table->entries = entries; + table->capacity = capacity; +} + +bool tableSet(Table *table, ObjString *key, Value value) { + if (table->count + 1 > table->capacity * TABLE_MAX_LOAD) { + int capacity = GROW_CAPACITY(table->capacity); + adjustCapacity(table, capacity); + } + + Entry *entry = findEntry(table->entries, table->capacity, key); + bool isNewKey = entry->key == NULL; + if (isNewKey && IS_NULL(entry->value)) table->count++; + + entry->key = key; + entry->value = value; + return isNewKey; +} + +bool tableGet(Table *table, ObjString *key, Value *value) { + if (table->count == 0) return false; + + Entry *entry = findEntry(table->entries, table->capacity, key); + if (entry->key == NULL) return false; + + *value = entry->value; + return true; +} + +bool tableDelete(Table *table, ObjString *key) { + if (table->count == 0) return false; + + // Find the entry. + Entry *entry = findEntry(table->entries, table->capacity, key); + if (entry->key == NULL) return false; + + // Place a tombstone in the entry. + entry->key = NULL; + entry->value = BOOL_VAL(true); // Tombstone + return true; +} + +void tableAddAll(Table *from, Table *to) { + for (int i = 0; i < from->capacity; i++) { + Entry *entry = &from->entries[i]; + if (entry->key != NULL) { + tableSet(to, entry->key, entry->value); + } + } +} + +ObjString *tableFindString(Table *table, const char *chars, int length, + uint32_t hash) { + if (table->count == 0) return NULL; + + uint32_t index = hash % table->capacity; + for (;;) { + Entry *entry = &table->entries[index]; + if (entry->key == NULL) { + // Stop if we find an empty non-tombstone entry. + if (IS_NULL(entry->value)) return NULL; + } else if (entry->key->length == length && entry->key->hash == hash && + memcmp(entry->key->chars, chars, length) == 0) { + // We found it. + return entry->key; + } + + index = (index + 1) % table->capacity; + } +} diff --git a/src/runtime/value.c b/src/runtime/value.c index 1849756..481c3f3 100644 --- a/src/runtime/value.c +++ b/src/runtime/value.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #include #include @@ -30,19 +36,13 @@ void freeValueArray(ValueArray *array) { } void printValue(Value value) { - switch (value.type) { - case VAL_BOOL: + if (IS_BOOL(value)) { printf(AS_BOOL(value) ? "true" : "false"); - break; - case VAL_NULL: + } else if (IS_NULL(value)) { printf("null"); - break; - case VAL_NUMBER: + } else if (IS_NUMBER(value)) { printf("%g", AS_NUMBER(value)); - break; - case VAL_OBJ: - // Placeholder until object system is implemented - printf(""); - break; + } else if (IS_OBJ(value)) { + printObject(value); } } diff --git a/src/runtime/vm.c b/src/runtime/vm.c index 5334758..cc1fd01 100644 --- a/src/runtime/vm.c +++ b/src/runtime/vm.c @@ -1,13 +1,33 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + #include #include "common.h" #include "debug.h" #include "vm.h" -void initVM(VM *vm) { vm->stackTop = vm->stack; } +void freeObjects(); + +#include "table.h" +#include "object.h" + +VM vm; + +void initVM(VM *pvm) { + pvm->stackTop = pvm->stack; + pvm->objects = NULL; + initTable(&pvm->globals); + initTable(&pvm->strings); +} void freeVM(VM *vm) { - // Nothing to free yet + freeTable(&vm->globals); + freeTable(&vm->strings); + // freeObjects(); } void push(VM *vm, Value value) { @@ -20,90 +40,309 @@ Value pop(VM *vm) { return *vm->stackTop; } +static Value peek(VM* vm, int distance) { + return vm->stackTop[-1 - distance]; +} + +static bool isFalsey(Value value) { + return IS_NULL(value) || (IS_BOOL(value) && !AS_BOOL(value)); +} + static InterpretResult run(VM *vm) { -#define READ_BYTE() (*vm->ip++) + register u8* ip = vm->ip; + register Value* sp = vm->stackTop; + +#define READ_BYTE() (*ip++) +#define READ_SHORT() (ip += 2, (uint16_t)((ip[-2] << 8) | ip[-1])) #define READ_CONSTANT() (vm->chunk->constants.values[READ_BYTE()]) -#define BINARY_OP(valueType, op) \ - do { \ - if (!IS_NUMBER((*(vm->stackTop - 1))) || \ - !IS_NUMBER((*(vm->stackTop - 2)))) { \ - printf("Operands must be numbers.\n"); \ - return INTERPRET_RUNTIME_ERROR; \ - } \ - double b = AS_NUMBER(pop(vm)); \ - double a = AS_NUMBER(pop(vm)); \ - push(vm, valueType(a op b)); \ - } while (false) +#define READ_STRING() AS_STRING(READ_CONSTANT()) - for (;;) { -#ifdef DEBUG_TRACE_EXECUTION - printf(" "); - for (Value *slot = vm->stack; slot < vm->stackTop; slot++) { - printf("[ "); - printValue(*slot); - printf(" ]"); - } - printf("\n"); - disassembleInstruction(vm->chunk, (int)(vm->ip - vm->chunk->code)); -#endif +#ifdef __GNUC__ + #define DISPATCH() goto *dispatch_table[*ip++] + + static void* dispatch_table[] = { + &&DO_OP_CONSTANT, &&DO_OP_NIL, &&DO_OP_TRUE, &&DO_OP_FALSE, + &&DO_OP_POP, &&DO_OP_GET_LOCAL, &&DO_OP_SET_LOCAL, + &&DO_OP_GET_GLOBAL, &&DO_OP_DEFINE_GLOBAL, &&DO_OP_SET_GLOBAL, + &&DO_OP_GET_UPVALUE, &&DO_OP_SET_UPVALUE, + &&DO_OP_GET_PROPERTY, &&DO_OP_SET_PROPERTY, &&DO_OP_GET_SUPER, + &&DO_OP_EQUAL, &&DO_OP_GREATER, &&DO_OP_LESS, + &&DO_OP_ADD, &&DO_OP_SUBTRACT, &&DO_OP_MULTIPLY, + &&DO_OP_DIVIDE, &&DO_OP_NOT, &&DO_OP_NEGATE, &&DO_OP_PRINT, + &&DO_OP_JUMP, &&DO_OP_JUMP_IF_FALSE, &&DO_OP_LOOP, + &&DO_OP_CALL, &&DO_OP_INVOKE, &&DO_OP_SUPER_INVOKE, + &&DO_OP_CLOSURE, &&DO_OP_CLOSE_UPVALUE, + &&DO_OP_RETURN, &&DO_OP_CLASS, &&DO_OP_INHERIT, &&DO_OP_METHOD + }; - u8 instruction; - switch (instruction = READ_BYTE()) { - case OP_CONSTANT: { + DISPATCH(); + + DO_OP_CONSTANT: { Value constant = READ_CONSTANT(); - push(vm, constant); - break; - } - case OP_TRUE: - push(vm, BOOL_VAL(true)); - break; - case OP_FALSE: - push(vm, BOOL_VAL(false)); - break; - case OP_NULL: - push(vm, NULL_VAL); - break; - case OP_POP: - pop(vm); - break; - case OP_ADD: - BINARY_OP(NUMBER_VAL, +); - break; - case OP_SUBTRACT: - BINARY_OP(NUMBER_VAL, -); - break; - case OP_MULTIPLY: - BINARY_OP(NUMBER_VAL, *); - break; - case OP_DIVIDE: - BINARY_OP(NUMBER_VAL, /); - break; - case OP_NOT: - push(vm, BOOL_VAL(IS_NULL(*(vm->stackTop - 1)) || - (IS_BOOL(*(vm->stackTop - 1)) && - !AS_BOOL(*(vm->stackTop - 1))))); - break; - case OP_NEGATE: - if (!IS_NUMBER(*(vm->stackTop - 1))) { - printf("Operand must be a number.\n"); + *sp++ = constant; + DISPATCH(); + } + DO_OP_NIL: { + *sp++ = NULL_VAL; + DISPATCH(); + } + DO_OP_TRUE: { + *sp++ = BOOL_VAL(true); + DISPATCH(); + } + DO_OP_FALSE: { + *sp++ = BOOL_VAL(false); + DISPATCH(); + } + DO_OP_POP: { + sp--; + DISPATCH(); + } + DO_OP_GET_LOCAL: { + u8 slot = READ_BYTE(); + // Placeholder: will need frame-relative indexing + DISPATCH(); + } + DO_OP_SET_LOCAL: { + u8 slot = READ_BYTE(); + DISPATCH(); + } + DO_OP_GET_GLOBAL: { + ObjString* name = READ_STRING(); + Value value; + if (!tableGet(&vm->globals, name, &value)) { + // runtimeError("Undefined variable '%s'.", name->chars); return INTERPRET_RUNTIME_ERROR; } - push(vm, NUMBER_VAL(-AS_NUMBER(pop(vm)))); - break; + *sp++ = value; + DISPATCH(); + } + DO_OP_DEFINE_GLOBAL: { + ObjString* name = READ_STRING(); + tableSet(&vm->globals, name, *(sp-1)); + sp--; + DISPATCH(); + } + DO_OP_SET_GLOBAL: { + ObjString* name = READ_STRING(); + if (tableSet(&vm->globals, name, *(sp-1))) { + tableDelete(&vm->globals, name); + // runtimeError("Undefined variable '%s'.", name->chars); + return INTERPRET_RUNTIME_ERROR; + } + DISPATCH(); + } + DO_OP_GET_UPVALUE: + DO_OP_SET_UPVALUE: + DO_OP_GET_PROPERTY: + DO_OP_SET_PROPERTY: + DO_OP_GET_SUPER: { + // Stubs + DISPATCH(); + } + DO_OP_EQUAL: { + Value b = *(--sp); + Value a = *(--sp); + *sp++ = BOOL_VAL(a == b); // Simplified for primitive types + DISPATCH(); + } + DO_OP_GREATER: { + double b = AS_NUMBER(*(--sp)); + double a = AS_NUMBER(*(--sp)); + *sp++ = BOOL_VAL(a > b); + DISPATCH(); + } + DO_OP_LESS: { + double b = AS_NUMBER(*(--sp)); + double a = AS_NUMBER(*(--sp)); + *sp++ = BOOL_VAL(a < b); + DISPATCH(); + } + DO_OP_ADD: { + double b = AS_NUMBER(*(sp - 1)); + double a = AS_NUMBER(*(sp - 2)); + sp -= 2; + *sp++ = NUMBER_VAL(a + b); + DISPATCH(); + } + DO_OP_SUBTRACT: { + double b = AS_NUMBER(*(sp - 1)); + double a = AS_NUMBER(*(sp - 2)); + sp -= 2; + *sp++ = NUMBER_VAL(a - b); + DISPATCH(); + } + DO_OP_MULTIPLY: { + double b = AS_NUMBER(*(sp - 1)); + double a = AS_NUMBER(*(sp - 2)); + sp -= 2; + *sp++ = NUMBER_VAL(a * b); + DISPATCH(); + } + DO_OP_DIVIDE: { + double b = AS_NUMBER(*(sp - 1)); + double a = AS_NUMBER(*(sp - 2)); + sp -= 2; + *sp++ = NUMBER_VAL(a / b); + DISPATCH(); + } + DO_OP_NOT: { + Value v = *(sp-1); + *(sp-1) = BOOL_VAL(isFalsey(v)); + DISPATCH(); + } + DO_OP_NEGATE: { + double a = AS_NUMBER(*(sp-1)); + *(sp-1) = NUMBER_VAL(-a); + DISPATCH(); + } + DO_OP_PRINT: { + printValue(*(sp-1)); + sp--; + printf("\n"); + DISPATCH(); + } + DO_OP_JUMP: { + uint16_t offset = READ_SHORT(); + ip += offset; + DISPATCH(); + } + DO_OP_JUMP_IF_FALSE: { + uint16_t offset = READ_SHORT(); + if (isFalsey(*(sp-1))) ip += offset; + DISPATCH(); + } + DO_OP_LOOP: { + uint16_t offset = READ_SHORT(); + ip -= offset; + DISPATCH(); + } + DO_OP_CALL: + DO_OP_INVOKE: + DO_OP_SUPER_INVOKE: + DO_OP_CLOSURE: + DO_OP_CLOSE_UPVALUE: { + // Stubs + DISPATCH(); + } + DO_OP_RETURN: { + vm->stackTop = sp; + vm->ip = ip; + return INTERPRET_OK; + } + DO_OP_CLASS: + DO_OP_INHERIT: + DO_OP_METHOD: { + // Stubs + DISPATCH(); + } + +#else + // Fallback for MSVC / Standard C + for (;;) { + u8 instruction; + switch (instruction = READ_BYTE()) { + case OP_CONSTANT: push(vm, READ_CONSTANT()); break; + case OP_NIL: push(vm, NULL_VAL); break; + case OP_TRUE: push(vm, BOOL_VAL(true)); break; + case OP_FALSE: push(vm, BOOL_VAL(false)); break; + case OP_POP: pop(vm); break; + case OP_GET_GLOBAL: { + ObjString* name = READ_STRING(); + Value value; + if (!tableGet(&vm->globals, name, &value)) return INTERPRET_RUNTIME_ERROR; + push(vm, value); + break; + } + case OP_DEFINE_GLOBAL: { + ObjString* name = READ_STRING(); + tableSet(&vm->globals, name, peek(vm, 0)); + pop(vm); + break; + } + case OP_SET_GLOBAL: { + ObjString* name = READ_STRING(); + if (tableSet(&vm->globals, name, peek(vm, 0))) { + tableDelete(&vm->globals, name); + return INTERPRET_RUNTIME_ERROR; + } + break; + } + case OP_EQUAL: { + Value b = pop(vm); + Value a = pop(vm); + push(vm, BOOL_VAL(a == b)); + break; + } + case OP_GREATER: { + double b = AS_NUMBER(pop(vm)); + double a = AS_NUMBER(pop(vm)); + push(vm, BOOL_VAL(a > b)); + break; + } + case OP_LESS: { + double b = AS_NUMBER(pop(vm)); + double a = AS_NUMBER(pop(vm)); + push(vm, BOOL_VAL(a < b)); + break; + } + case OP_ADD: { + double b = AS_NUMBER(pop(vm)); + double a = AS_NUMBER(pop(vm)); + push(vm, NUMBER_VAL(a + b)); + break; + } + case OP_SUBTRACT: { + double b = AS_NUMBER(pop(vm)); + double a = AS_NUMBER(pop(vm)); + push(vm, NUMBER_VAL(a - b)); + break; + } + case OP_MULTIPLY: { + double b = AS_NUMBER(pop(vm)); + double a = AS_NUMBER(pop(vm)); + push(vm, NUMBER_VAL(a * b)); + break; + } + case OP_DIVIDE: { + double b = AS_NUMBER(pop(vm)); + double a = AS_NUMBER(pop(vm)); + push(vm, NUMBER_VAL(a / b)); + break; + } + case OP_NOT: push(vm, BOOL_VAL(isFalsey(pop(vm)))); break; + case OP_NEGATE: push(vm, NUMBER_VAL(-AS_NUMBER(pop(vm)))); break; case OP_PRINT: { printValue(pop(vm)); printf("\n"); break; } - case OP_RETURN: { - return INTERPRET_OK; + case OP_JUMP: { + uint16_t offset = READ_SHORT(); + vm->ip += offset; + break; + } + case OP_JUMP_IF_FALSE: { + uint16_t offset = READ_SHORT(); + if (isFalsey(peek(vm, 0))) vm->ip += offset; + break; } + case OP_LOOP: { + uint16_t offset = READ_SHORT(); + vm->ip -= offset; + break; + } + case OP_RETURN: return INTERPRET_OK; + default: return INTERPRET_COMPILE_ERROR; } } +#endif #undef READ_BYTE +#undef READ_SHORT #undef READ_CONSTANT -#undef BINARY_OP +#undef READ_STRING +#undef DISPATCH } InterpretResult interpret(VM *vm, Chunk *chunk) { diff --git a/src/stdlib/convert_native.c b/src/stdlib/convert_native.c index 032a630..5ba86bd 100644 --- a/src/stdlib/convert_native.c +++ b/src/stdlib/convert_native.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * ProXPL Standard Library - Type Conversion Module * Native C implementation of type conversion functions diff --git a/src/stdlib/io_native.c b/src/stdlib/io_native.c index 2c8e7b5..fb423f6 100644 --- a/src/stdlib/io_native.c +++ b/src/stdlib/io_native.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * ProXPL Standard Library - I/O Module * Native C implementation of I/O functions diff --git a/src/stdlib/math_native.c b/src/stdlib/math_native.c index 45ce6c4..8547458 100644 --- a/src/stdlib/math_native.c +++ b/src/stdlib/math_native.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * ProXPL Standard Library - Math Module * Native C implementation of mathematical functions diff --git a/src/stdlib/stdlib_core.c b/src/stdlib/stdlib_core.c index 07a6683..e01dd3b 100644 --- a/src/stdlib/stdlib_core.c +++ b/src/stdlib/stdlib_core.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * ProXPL Standard Library - Main Registry * Registers all standard library modules with the VM diff --git a/src/stdlib/string_native.c b/src/stdlib/string_native.c index 9e4b3b7..d10645d 100644 --- a/src/stdlib/string_native.c +++ b/src/stdlib/string_native.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * ProXPL Standard Library - String Module * Native C implementation of string manipulation functions diff --git a/src/stdlib/system_native.c b/src/stdlib/system_native.c index 637c197..64ec11f 100644 --- a/src/stdlib/system_native.c +++ b/src/stdlib/system_native.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * ProXPL Standard Library - System Module * Native C implementation of system functions diff --git a/src/vm/bytecode.c b/src/vm/bytecode.c index 4813883..3b462b3 100644 --- a/src/vm/bytecode.c +++ b/src/vm/bytecode.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* Minimal but complete bytecode helper implementation. Implements chunk growth, LEB128 emit/read, constants management, diff --git a/src/vm/disasm.c b/src/vm/disasm.c index 13c2723..2c53402 100644 --- a/src/vm/disasm.c +++ b/src/vm/disasm.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* Disassembler utility: reads a chunk and prints a human-readable listing of instructions with constant annotations. diff --git a/src/vm/instr_handlers_template.c b/src/vm/instr_handlers_template.c index db2ae78..9b041eb 100644 --- a/src/vm/instr_handlers_template.c +++ b/src/vm/instr_handlers_template.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* Instruction handlers template. Each handler receives a VMState* and decoded operands. diff --git a/src/vm/vm_core_opt.c b/src/vm/vm_core_opt.c index 5fdecd9..3d4148d 100644 --- a/src/vm/vm_core_opt.c +++ b/src/vm/vm_core_opt.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * vm_core_opt.c * diff --git a/src/vm/vm_dispatch.c b/src/vm/vm_dispatch.c index 72766e5..3a1ab4f 100644 --- a/src/vm/vm_dispatch.c +++ b/src/vm/vm_dispatch.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* Dispatch loop example implementing both computed-goto (for compilers supporting it) and switch fallback. This is a compact, clear demonstration; diff --git a/src/vm/vm_v2.c b/src/vm/vm_v2.c new file mode 100644 index 0000000..7ef610c --- /dev/null +++ b/src/vm/vm_v2.c @@ -0,0 +1,227 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + +/* + * ProXPL V2: High-Performance Register VM + * --------------------------------------- + * This file implements the core execution loop using a register-based architecture. + * Features: + * - NaN-Boxing for values (64-bit doubles + tags) + * - Computed Gotos for instruction dispatch (GCC/Clang) + * - Fixed-width 32-bit instructions + */ + +#include +#include +#include +#include + +// --- Configuration --- +#define PREDICTED_STACK_SIZE 1024 +#define MAX_REGISTERS 256 + +// --- Type System (NaN Boxing) --- +typedef uint64_t Value; + +#define QNAN ((uint64_t)0x7ffc000000000000) +#define TAG_NIL 1 // 01. +#define TAG_FALSE 2 // 10. +#define TAG_TRUE 3 // 11. + +#define NIL_VAL ((Value)(QNAN | TAG_NIL)) +#define FALSE_VAL ((Value)(QNAN | TAG_FALSE)) +#define TRUE_VAL ((Value)(QNAN | TAG_TRUE)) + +// Helper macros for value manipulation +#define IS_NUMBER(v) (((v) & QNAN) != QNAN) +#define IS_NIL(v) ((v) == NIL_VAL) +#define IS_BOOL(v) (((v) | 1) == TRUE_VAL) + +#define AS_NUMBER(v) valueToNum(v) +#define NUMBER_VAL(n) numToValue(n) + +static inline double valueToNum(Value v) { + union { uint64_t bits; double num; } u; + u.bits = v; + return u.num; +} + +static inline Value numToValue(double n) { + union { uint64_t bits; double num; } u; + u.num = n; + return u.bits; +} + +// --- Instructions --- +// Format: | OpCode (8) | A (8) | B (8) | C (8) | +typedef uint32_t Instruction; + +#define GET_OP(i) ((i) & 0xFF) +#define GET_A(i) (((i) >> 8) & 0xFF) +#define GET_B(i) (((i) >> 16) & 0xFF) +#define GET_C(i) (((i) >> 24) & 0xFF) + +enum OpCode { + OP_HALT = 0, + OP_LOAD_CONST, + OP_ADD, + OP_RETURN, + OP_MOV +}; + +// --- VM Structure --- +typedef struct { + Instruction* ip; + Value registers[MAX_REGISTERS]; + Value* constants; + int const_count; +} VM; + +// --- VM Execution Loop --- +// Returns: Exit code (0 = success) +int vm_run(VM* vm) { + // Cache IP in register for speed + register Instruction* ip = vm->ip; + register Value* regs = vm->registers; + + #ifdef __GNUC__ + // Computed Goto Dispatch Table + static void* dispatch_table[] = { + &&HANDLE_HALT, + &&HANDLE_LOAD_CONST, + &&HANDLE_ADD, + &&HANDLE_RETURN, + &&HANDLE_MOV + }; + #define DISPATCH() goto *dispatch_table[GET_OP(*ip)] + #else + // Switch Fallback + #define DISPATCH() switch(GET_OP(*ip)) + #endif + + // Initial dispatch + DISPATCH(); + + // --- Opcode Handlers --- + + HANDLE_HALT: + { + return 0; + } + + HANDLE_LOAD_CONST: + { + Instruction ins = *ip++; + uint8_t r_dest = GET_A(ins); + uint8_t k_idx = GET_B(ins); + regs[r_dest] = vm->constants[k_idx]; + + #ifndef __GNUC__ + break; + #endif + DISPATCH(); + } + + HANDLE_ADD: + { + Instruction ins = *ip++; + uint8_t r_dest = GET_A(ins); + uint8_t r_b = GET_B(ins); + uint8_t r_c = GET_C(ins); + + Value val_b = regs[r_b]; + Value val_c = regs[r_c]; + + // Type specialization: Optimistic Float Add + if (IS_NUMBER(val_b) && IS_NUMBER(val_c)) { + double res = AS_NUMBER(val_b) + AS_NUMBER(val_c); + regs[r_dest] = NUMBER_VAL(res); + } else { + // Fallback for strings/other types (stub) + // runtime_add_generic(vm, r_dest, val_b, val_c); + printf("Runtime Error: Invalid operands for ADD\n"); + return 1; + } + + #ifndef __GNUC__ + break; + #endif + DISPATCH(); + } + + HANDLE_MOV: + { + Instruction ins = *ip++; + uint8_t r_dest = GET_A(ins); + uint8_t r_src = GET_B(ins); + regs[r_dest] = regs[r_src]; + + #ifndef __GNUC__ + break; + #endif + DISPATCH(); + } + + HANDLE_RETURN: + { + Instruction ins = *ip++; // consume + uint8_t r_res = GET_A(ins); + Value res = regs[r_res]; + + // In real VM, this would pop frame or return to caller + // For prototype, we print and exit + if (IS_NUMBER(res)) { + printf("VM Return: Number(%f)\n", AS_NUMBER(res)); + } else { + printf("VM Return: Value(%llu)\n", res); + } + return 0; + } + + // Switch closing brace if needed + #ifndef __GNUC__ + } + // fallback loop for switch + goto start_loop; + #endif + + return 0; +} + +// --- Test Main --- +int main() { + printf("ProXPL V2 Register VM Prototype\n"); + printf("-------------------------------\n"); + + // Constants + Value consts[] = { + NUMBER_VAL(10.0), // 0 + NUMBER_VAL(32.0), // 1 + NUMBER_VAL(5.5) // 2 + }; + + // Program: 10 + 32 = 42 + // R0 = 10.0 + // R1 = 32.0 + // R2 = R0 + R1 + // RETURN R2 + uint32_t code[] = { + // Op | A | B | C + (OP_LOAD_CONST) | (0 << 8) | (0 << 16), + (OP_LOAD_CONST) | (1 << 8) | (1 << 16), + (OP_ADD) | (2 << 8) | (0 << 16) | (1 << 24), + (OP_RETURN) | (2 << 8) + }; + + VM vm; + vm.ip = code; + vm.constants = consts; + vm.const_count = 3; + + vm_run(&vm); + + return 0; +} diff --git a/tests/bytecode_tests.c b/tests/bytecode_tests.c index 94d1d6e..8fe28d3 100644 --- a/tests/bytecode_tests.c +++ b/tests/bytecode_tests.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* Test runner for bytecode serialization, deserialization, disassembly, and a minimal dispatch execution (no GC). diff --git a/tests/test_opcode_roundtrip.c b/tests/test_opcode_roundtrip.c index f9b3bd7..766ef23 100644 --- a/tests/test_opcode_roundtrip.c +++ b/tests/test_opcode_roundtrip.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* test_opcode_roundtrip.c * Verifies that a chunk with opcodes and constants round-trips through * write_chunk_to_file() and read_chunk_from_file() preserving bytes. diff --git a/tests/test_opcode_values.c b/tests/test_opcode_values.c index 1f85820..07699dd 100644 --- a/tests/test_opcode_values.c +++ b/tests/test_opcode_values.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* test_opcode_values.c * Verifies opcode enum numeric assignments match documented values */ diff --git a/tests/unit/test_scanner_template.c b/tests/unit/test_scanner_template.c index 26cdb44..6cb5e1f 100644 --- a/tests/unit/test_scanner_template.c +++ b/tests/unit/test_scanner_template.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* * test_scanner.c * Unit tests for the lexical analyzer (scanner/tokenizer) diff --git a/tools/bench/bench_simple.c b/tools/bench/bench_simple.c index 19b932f..7548feb 100644 --- a/tools/bench/bench_simple.c +++ b/tools/bench/bench_simple.c @@ -1,3 +1,9 @@ +// -------------------------------------------------- +// Project: ProX Programming Language (ProXPL) +// Author: ProgrammerKR +// Created: 2025-12-16 +// Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + /* bench_simple.c * A tiny microbenchmark that constructs a numeric-add heavy Chunk and * executes it repeatedly to measure interpreter throughput. diff --git a/tools/bench/build_msvc.ps1 b/tools/bench/build_msvc.ps1 index 36e4eac..275f032 100644 --- a/tools/bench/build_msvc.ps1 +++ b/tools/bench/build_msvc.ps1 @@ -1,4 +1,10 @@ #!/usr/bin/env pwsh +# -------------------------------------------------- +# Project: ProX Programming Language (ProXPL) +# Author: ProgrammerKR +# Created: 2025-12-16 +# Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved. + <# build_msvc.ps1 Build the bench_simple.exe using MSVC `cl.exe`. diff --git a/wrappers/proxpl_wrapper.py b/wrappers/proxpl_wrapper.py new file mode 100644 index 0000000..1372bae --- /dev/null +++ b/wrappers/proxpl_wrapper.py @@ -0,0 +1,137 @@ +import ctypes +import os +import sys + +# Define types +c_uint8 = ctypes.c_uint8 +c_int = ctypes.c_int +c_uint64 = ctypes.c_uint64 +c_void_p = ctypes.c_void_p + +# Value is uint64_t (NaN-boxed) +Value = c_uint64 + +# Constants matching C +STACK_MAX = 256 + +class ValueArray(ctypes.Structure): + _fields_ = [ + ("capacity", c_int), + ("count", c_int), + ("values", ctypes.POINTER(Value)), + ] + +class Chunk(ctypes.Structure): + _fields_ = [ + ("count", c_int), + ("capacity", c_int), + ("code", ctypes.POINTER(c_uint8)), + ("lines", ctypes.POINTER(c_int)), + ("constants", ValueArray), + ] + +class VM(ctypes.Structure): + _fields_ = [ + ("chunk", ctypes.POINTER(Chunk)), + ("ip", ctypes.POINTER(c_uint8)), + ("stack", Value * STACK_MAX), + ("stackTop", ctypes.POINTER(Value)), + ] + +# Load Library +def load_proxpl_lib(dll_path=None): + if not dll_path: + # Default to current dir or build dir + base_dir = os.path.dirname(os.path.abspath(__file__)) + dll_name = "proxpl.dll" if os.name == 'nt' else "libproxpl.so" + # Try a few common locations + paths = [ + os.path.join(base_dir, dll_name), + os.path.join(base_dir, "..", "build", dll_name), + os.path.join(base_dir, "..", "src", dll_name), + ] + for p in paths: + if os.path.exists(p): + dll_path = p + break + + if not dll_path: + raise FileNotFoundError(f"Could not find {dll_name}. Please build it first.") + + lib = ctypes.CDLL(dll_path) + + # Define Signatures + lib.initVM.argtypes = [ctypes.POINTER(VM)] + lib.initVM.restype = None + + lib.freeVM.argtypes = [ctypes.POINTER(VM)] + lib.freeVM.restype = None + + lib.interpret.argtypes = [ctypes.POINTER(VM), ctypes.POINTER(Chunk)] + lib.interpret.restype = c_int # InterpretResult enum + + lib.initChunk.argtypes = [ctypes.POINTER(Chunk)] + lib.initChunk.restype = None + + lib.freeChunk.argtypes = [ctypes.POINTER(Chunk)] + lib.freeChunk.restype = None + + lib.writeChunk.argtypes = [ctypes.POINTER(Chunk), c_uint8, c_int] + lib.writeChunk.restype = None + + lib.addConstant.argtypes = [ctypes.POINTER(Chunk), Value] + lib.addConstant.restype = c_int + + return lib + +class ProXVM: + def __init__(self, dll_path=None): + self.lib = load_proxpl_lib(dll_path) + self.vm = VM() + self.lib.initVM(ctypes.byref(self.vm)) + + def __del__(self): + # self.lib.freeVM(ctypes.byref(self.vm)) # Careful with GC order + pass + + def run_bytecode(self, opcodes, constants_list): + # Create a new chunk + chunk = Chunk() + self.lib.initChunk(ctypes.byref(chunk)) + + # Add constants + # Note: We need a helper to convert Py objects to Value (NaN boxed) + # For now, simplistic number support + for c in constants_list: + val = self._to_value(c) + self.lib.addConstant(ctypes.byref(chunk), val) + + # Write opcodes + for op in opcodes: + self.lib.writeChunk(ctypes.byref(chunk), op, 1) # line 1 + + # Run + result = self.lib.interpret(ctypes.byref(self.vm), ctypes.byref(chunk)) + + # Clean + self.lib.freeChunk(ctypes.byref(chunk)) + return result + + def _to_value(self, py_obj): + # Implement NaN boxing encoding here or call a C helper if exposed + # This is tricky in pure Python without bit manipulation helper. + # But for double (Number), we can use struct.pack + import struct + if isinstance(py_obj, (int, float)): + # Just a double + return struct.unpack('