diff --git a/docs/REFERENCE.md b/docs/REFERENCE.md index c0c6de3..ded922a 100644 --- a/docs/REFERENCE.md +++ b/docs/REFERENCE.md @@ -70,7 +70,7 @@ sidebar: ## Variables & Constants {#variables} Jam has two binding forms inside functions: `var` for mutable storage and `const` for -single-assignment values. Every binding must be initialized at its declaration — Jam has +single-assignment values. Every binding must be initialized at its declaration, Jam has no `undefined` placeholder. ```jam @@ -84,7 +84,7 @@ fn example() { ``` At module scope, `const` declarations bind a name to a compile-time value. They are -*inlined* at every use site — referring to one costs the same as a literal. The type may +*inlined* at every use site, referring to one costs the same as a literal. The type may be inferred when an initializer alone determines it. ```jam @@ -98,7 +98,7 @@ fn isZSet(f: u8) bool { ``` Module-scope `const` is also how top-level types, imports, and function pointers are -named — Jam funnels every top-level declaration through the same form. +named, Jam funnels every top-level declaration through the same form. --- @@ -136,7 +136,7 @@ the standard `0x`, `0o`, `0b` prefixes.

Choosing Integer Types

- Use unsigned types (u8, u16, etc.) for values that are never negative — indices, counts, byte sizes. + Use unsigned types (u8, u16, etc.) for values that are never negative, indices, counts, byte sizes. Use signed types (i8, i16, etc.) when you need to represent negative values.

@@ -234,7 +234,7 @@ const earth: str = "\u{1F30D}"; // 🌍 Jam distinguishes three reference families. Pointer types take a *required* `const` or `mut` qualifier marking whether the pointee may be written. Slices and fixed arrays carry -no qualifier — their element mutability follows the binding. +no qualifier, their element mutability follows the binding. | Type | Description | |---------------|----------------------------------------------------------------------------------| @@ -269,7 +269,7 @@ fn indexThroughMany() u8 {

No bare *T

- The mutability qualifier is part of the pointer type — there is no shorthand + The mutability qualifier is part of the pointer type, there is no shorthand *T. Writing *const u8 vs *mut u8 documents intent at every signature.

@@ -285,7 +285,7 @@ comma-separated, fill-with-count, and empty (which produces a zero-length slice) ```jam var a: [4]u8 = [10, 20, 30, 40]; // [a, b, c, d] -var b: [16]u8 = [0; 16]; // [expr; N] — fill 16 slots with 0 +var b: [16]u8 = [0; 16]; // [expr; N], fill 16 slots with 0 const empty: []u8 = []; // empty slice // Index with []. Out-of-bounds is undefined at runtime — @@ -333,7 +333,7 @@ fn fillIndices() [16]u8 { } ``` -The `for` loop iterates a half-open integer range — `for i in 0:N` binds `i = 0, 1, …, N-1`. +The `for` loop iterates a half-open integer range, `for i in 0:N` binds `i = 0, 1, …, N-1`. --- @@ -349,14 +349,14 @@ fn mixIngredients(sugar: i32, fruit: i32) i32 { return sugar + fruit; } -// No return value — omit the return type. +// No return value, omit the return type. fn greet() { std.fmt.println("Hello!"); } ``` Functions can be prefixed with `pub` (visible outside the defining module) and `extern` -(declared but defined elsewhere — typically libc). +(declared but defined elsewhere, typically libc). ```jam pub fn add(a: i32, b: i32) i32 { return a + b; } @@ -371,7 +371,7 @@ pub extern fn free(ptr: *mut[] u8);

Void Functions

A function with no declared return type returns nothing. Don't write - void — just omit the return-type slot. + void, just omit the return-type slot.

@@ -445,19 +445,19 @@ fn observe() u32 { var hits: u32 = 0; var c: Counter = { value: 5, sink: &hits }; return c.value; - // c.drop() fires automatically here — see Drop, below. + // c.drop() fires automatically here, see Drop, below. } ``` A method can also be invoked by-name on the type: `Counter.drop(&c)` calls it explicitly while `c` is still in scope (and the automatic drop will still fire at scope -exit — calling drop manually is currently a footgun). +exit, calling drop manually is currently a footgun). --- ## Enums {#enums} -Enums describe a closed set of named variants. The simplest form is *payload-less* — each +Enums describe a closed set of named variants. The simplest form is *payload-less*, each variant is a u8 discriminant. ```jam @@ -509,14 +509,14 @@ fn srcReg(op: Op) u8 { } ``` -Payload-carrying enums are how `Option(T)` and `Result(T, E)` are built — see +Payload-carrying enums are how `Option(T)` and `Result(T, E)` are built, see [Generics](#generics). --- ## Unions {#unions} -A `union` is *untagged* — every field shares the same storage. Use it for type punning +A `union` is *untagged*, every field shares the same storage. Use it for type punning (read float bits as `u32`, etc.) and for matching C-side `union { … }` types at FFI boundaries. @@ -533,7 +533,7 @@ fn floatBits(x: f32) u32 { ``` Unions size to their largest field; alignment is the max of all fields'. Unlike enums, -there is no discriminant — the compiler trusts the program to know which field is live. +there is no discriminant, the compiler trusts the program to know which field is live. --- @@ -554,7 +554,7 @@ fn dispatch(x: u8) u8 { } ``` -A `match` can also be used as an *expression* — each arm produces a value, and the result +A `match` can also be used as an *expression*, each arm produces a value, and the result is the value of the matched arm. ```jam @@ -596,7 +596,7 @@ fn main() { } ``` -A type alias `const Name = Generic(arg);` registers `Name` as a synonym — subsequent +A type alias `const Name = Generic(arg);` registers `Name` as a synonym, subsequent uses resolve to the same instantiated struct. ```jam @@ -620,7 +620,7 @@ fn Holder(T: type) type { } ``` -`Self` inside a struct body refers to the enclosing struct type — for a generic, that's +`Self` inside a struct body refers to the enclosing struct type, for a generic, that's the specific instantiation in play. ### Generic Enums @@ -644,7 +644,7 @@ Construct variants by qualifying with the instantiated type: `Option(i32).Some(4 ## Modules & Imports {#imports} -`import("name")` returns a *module value* — a compile-time record of the symbols another +`import("name")` returns a *module value*, a compile-time record of the symbols another file exports. Bind it through `const` either whole or destructured. ```jam @@ -655,7 +655,7 @@ fn show() { std.fmt.println("Hello!"); } -// Destructured binding — pulls specific names into the current scope. +// Destructured binding, pulls specific names into the current scope. const { Vec, Option } = import("collections"); const { assert } = import("test"); ``` @@ -678,7 +678,7 @@ results are substituted as constants before LLVM sees the code. ```jam fn bytesFor(n: u64) u64 { - return n * @sizeOf(u32); // n * 4 — fully constant-folded + return n * @sizeOf(u32); // n * 4, fully constant-folded } fn pointerSize() u64 { @@ -686,7 +686,7 @@ fn pointerSize() u64 { } fn sliceSize() u64 { - return @sizeOf([]u8); // 16 — {ptr, len} + return @sizeOf([]u8); // 16, {ptr, len} } ``` @@ -713,7 +713,7 @@ fn allocOne() *mut[] u32 { ``` Param types must match the C ABI. Slice arguments are passed as a `{ptr, len}` pair, and -struct arguments larger than two words use sret-style return ABI — these match the +struct arguments larger than two words use sret-style return ABI, these match the platform's C compiler. --- @@ -724,8 +724,8 @@ Jam is a *mutable value semantics* language. Every binding owns its value; passi value to a function does not silently share storage with the caller. Functions opt into a specific borrowing or transfer behavior via a per-parameter **mode** keyword. -The result is the same memory safety as Rust — no use-after-free, no double-free, no -data races, no reads of uninitialized memory — with no lifetime annotations. +The result is the same memory safety as Rust, no use-after-free, no double-free, no +data races, no reads of uninitialized memory, with no lifetime annotations. The design is inspired by Hylo's parameter-mode system and Rust's drop semantics. The compiler enforces three rules: *definite initialization* (every binding is written @@ -745,18 +745,18 @@ the type. | Consume ownership | `move` | read-write | becomes uninitialized | ```jam -// Default read-only borrow — caller's value is unchanged. +// Default read-only borrow, caller's value is unchanged. fn distance(a: Point, b: Point) f64 { return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); } -// Exclusive read-write — caller passes `&binding`. +// Exclusive read-write, caller passes `&binding`. fn scale(p: mut Point, factor: f64) { p.x = p.x * factor; p.y = p.y * factor; } -// Consume — caller's binding is uninitialized after the call. +// Consume, caller's binding is uninitialized after the call. fn storeIn(buf: move []u8, db: mut Database) { db.append(buf); } @@ -766,18 +766,18 @@ At the call site, a `mut` parameter is passed with `&` to make the borrow explic ```jam var p: Point = { x: 3.0, y: 4.0 }; -scale(&p, 2.0); // mut borrow — explicit & -distance(p, otherPoint); // read-only — no sigil +scale(&p, 2.0); // mut borrow, explicit & +distance(p, otherPoint); // read-only, no sigil ``` -`move` parameters take a plain expression — the binding is dead in the caller after the +`move` parameters take a plain expression, the binding is dead in the caller after the call. ## Exclusivity {#mvs-exclusivity} At any call boundary, at most one argument may be a `mut` borrow of a given binding, and a `mut` borrow cannot coexist with any other borrow of the same binding. The -compiler rejects programs that violate this rule — the same "law of exclusivity" +compiler rejects programs that violate this rule, the same "law of exclusivity" Rust's borrow checker enforces, applied locally at each call rather than across whole-program lifetimes. @@ -797,7 +797,7 @@ fn caller() u32 { A struct may define a `drop` method that runs automatically when an owned instance goes out of scope. The drop method takes `self: mut Self` and runs exactly once per owned -value — even on early returns, in match arms, and through nested control flow. There is +value, even on early returns, in match arms, and through nested control flow. There is no manual `defer` ceremony. ```jam @@ -817,4 +817,4 @@ fn readFile(path: []u8) i32 { ``` A value *moved* into another function (via the `move` mode) becomes uninitialized in -the caller, so the drop fires at the new owner's scope exit — never twice. +the caller, so the drop fires at the new owner's scope exit, never twice. diff --git a/src/ast.cpp b/src/ast.cpp index cd0cb45..1f8dae9 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -25,7 +25,7 @@ JamBasicBlockRef CurrentLoopBreak = nullptr; // loop. SIZE_MAX means "no enclosing loop body active here". size_t CurrentLoopBodyScopeIdx = SIZE_MAX; -// Forward declaration so codegenCall (P9.5 auto-address path) can call +// Forward declaration so codegenCall (auto-address path) can call // codegenAddressOf which is defined further down in the file. static JamValueRef codegenAddressOf(JamCodegenContext &ctx, const AstNode &n); @@ -225,7 +225,7 @@ static JamValueRef resolveIndexedElementPtr(JamCodegenContext &ctx, // keeps the codegen working uniformly whether the variable is // backed by an `alloca` (locals, value-passed params) or by a // function argument that's already a pointer to caller storage - // (P9 mode-aware ABI for `mut` / `undefined` params). + // (mode-aware ABI for `mut` / `undefined` params). JamTypeRef allocatedType = ctx.getLLVMType(varTy); if (k.kind == TypeKind::PtrMany) { @@ -1707,7 +1707,7 @@ static JamValueRef codegenVarDecl(JamCodegenContext &ctx, const AstNode &n) { return Alloca; } -// + P9: emit a single drop call for one tracked binding. P9's +// Emit a single drop call for one tracked binding. The // mode-aware ABI now lowers `fn drop(self: mut T)` as a pointer-typed // parameter, so the call site passes the binding's storage address // directly — no load-value-then-pass-by-value workaround. The drop fn @@ -1989,7 +1989,7 @@ static JamValueRef codegenFor(JamCodegenContext &ctx, const AstNode &n) { // // The Maranget decision-tree formalism degenerates to "specialize the only // column" in (one scrutinee, one column); the cascade is the canonical -// one-column lowering. M2+ replaces this with a multi-column tree. +// one-column lowering. A multi-column tree will replace this later. // Build a boolean (i1) value that is true iff the scrutinee matches the // given pattern node. `scrut` is the already-loaded scrutinee value; @@ -2058,7 +2058,7 @@ emitPatternTest(JamCodegenContext &ctx, NodeIdx patIdx, JamValueRef scrut, } uint32_t discrim = einfo->variants[idx].discriminant; // Extract the tag if the scrutinee is a {tag, payload} struct. - // For E1 (unit-only) enums the scrutinee is already i8. + // For unit-only enums the scrutinee is already i8. JamValueRef tagVal = scrut; JamTypeRef tagType = scrutType; if (JamLLVMTypeIsStruct(scrutType)) { @@ -2193,7 +2193,7 @@ static JamValueRef codegenMatch(JamCodegenContext &ctx, const AstNode &n) { if (!scrut) return nullptr; JamTypeRef scrutType = JamLLVMTypeOf(scrut); // Classify the scrutinee. Enum scrutinees may be either an integer - // (E1 unit-only enums lower to i8) or a struct (E2 payloaded enums + // (unit-only enums lower to i8) or a struct (payloaded enums // lower to a named struct). For struct scrutinees we MUST verify // the type matches a registered enum, otherwise a slice (which is // also a struct shape `{ptr, len}`) would silently route through @@ -2226,7 +2226,7 @@ static JamValueRef codegenMatch(JamCodegenContext &ctx, const AstNode &n) { JamBasicBlockRef mergeBB = JamLLVMAppendBasicBlock(func, "match.end"); - // Per-arm result for the M3 phi: pairs (basicBlock, value) where + // Per-arm result for the phi: pairs (basicBlock, value) where // the arm's body ended without terminating control flow. The // match's expression-form value is a phi over these. std::vector> armResults; @@ -2331,7 +2331,7 @@ static JamValueRef codegenMatch(JamCodegenContext &ctx, const AstNode &n) { } // Track each arm's last produced value (for match-as-expression - // support, M3). Arms that terminate via `return` / `break` / + // support). Arms that terminate via `return` / `break` / // `continue` don't fall through to merge and aren't recorded. JamValueRef lastValue = nullptr; ctx.pushDropScope(); diff --git a/src/ast_flat.h b/src/ast_flat.h index cf4ecba..1ef947d 100644 --- a/src/ast_flat.h +++ b/src/ast_flat.h @@ -116,7 +116,7 @@ enum class AstTag : uint8_t { // d.lhs = u32 (index into ModuleAST::AnonEnums) EnumExpr, - // Pattern match (M1: integer literals, ranges, or-patterns, wildcard). + // Pattern match (integer literals, ranges, or-patterns, wildcard). // The catch-all is the wildcard pattern `_`; there is no `else` arm. // d.lhs = NodeIdx (scrutinee expression) // d.rhs = ExtraIdx → [armCount, @@ -156,8 +156,8 @@ enum class AstTag : uint8_t { // d.lhs = lo32 of value, d.rhs = hi32 of value, flags bit 0 = isNeg. PatLit, - // d.lhs = lo32 of low bound, d.rhs = lo32 of high bound (M1 limits to - // values that fit in u32; M2+ may extend via ExtraIdx for u64). + // d.lhs = lo32 of low bound, d.rhs = lo32 of high bound (limited to + // values that fit in u32; may later extend via ExtraIdx for u64). PatRange, // No payload. PatWildcard, @@ -408,7 +408,7 @@ constexpr TypeIdx U64 = 9; constexpr TypeIdx I64 = 10; constexpr TypeIdx F32 = 11; constexpr TypeIdx F64 = 12; -constexpr TypeIdx Type = 13; // generics G1: the meta-type +constexpr TypeIdx Type = 13; // the meta-type constexpr TypeIdx U1 = Bool; // alias } // namespace BuiltinType diff --git a/src/codegen.cpp b/src/codegen.cpp index 874eb4b..5f2db63 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -160,7 +160,7 @@ JamTypeRef JamCodegenContext::getLLVMType(TypeIdx ty) const { } else if (const auto *uinfo = getUnion(name)) { result = uinfo->type; } else if (const auto *einfo = getEnum(name)) { - // (unit-only): lowers to i8. E2 (with payloads): lowers + // Unit-only enums lower to i8. Payloaded enums lower // to {i8, [N x i8]} via the named struct type set during // declaration. result = einfo->hasPayloadVariant ? einfo->type : getInt8Type(); @@ -598,7 +598,7 @@ uint64_t JamCodegenContext::typeSize(TypeIdx ty) const { return alignUp(maxSize, maxAlign); } case TypeKind::Enum: - return 1; // M2 E1 enums lower to u8 + return 1; // Unit-only enums lower to u8 case TypeKind::Type: // Meta-type has no runtime size. return 0; diff --git a/src/init_analysis.cpp b/src/init_analysis.cpp index b9d1105..5251e33 100644 --- a/src/init_analysis.cpp +++ b/src/init_analysis.cpp @@ -167,7 +167,7 @@ std::vector Analyzer::run(const FunctionAST &fn) { r = analyze(stmt, std::move(r.state)); } - // + P8.2: if control reaches the end of the body without an + // If control reaches the end of the body without an // explicit return, every drop-bearing local must have been // initialized. (Functions that always return on every path produce // r.terminated == true and skip this check; the per-return checks @@ -359,8 +359,8 @@ Result Analyzer::analyzeAssign(NodeIdx idx, NameMap state) { // trigger a read check. Sub-expressions like array indices *are* reads. // // In any write to a sub-path (`arr[i] = x`, `s.field = x`) marks the -// whole base binding as Init. This is intentionally imprecise: P2 does -// not track field-level init. A later phase can refine this to only mark +// whole base binding as Init. This is intentionally imprecise: field-level +// init isn't tracked. A later phase can refine this to only mark // the touched sub-path. Result Analyzer::analyzeAssignTarget(NodeIdx idx, NameMap state) { if (idx == kNoNode) return Result{std::move(state), false}; diff --git a/src/init_analysis.h b/src/init_analysis.h index 988c8dd..8f1a941 100644 --- a/src/init_analysis.h +++ b/src/init_analysis.h @@ -66,7 +66,7 @@ using FunctionRegistry = std::unordered_map; // vector on success; on failure, the vector contains every detected // uninit-read with location info. // -// Scope (cumulative through P4): +// Scope: // - Tracks per-binding init state for locals declared with // `var name: T = ...`. // - Parameter entry state: every parameter starts Init (the caller is diff --git a/src/main.cpp b/src/main.cpp index 056b9e3..fb30bff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -396,7 +396,7 @@ static int compileAndRun(const std::string &filename, } // Generic functions are still registered so call sites can // look them up for instantiation, but no LLVM is emitted - // until each instantiation is processed in G5. + // until each instantiation is processed. if (func->isPub) { codegenCtx.registerFunctionAST(func->Name, func.get()); } @@ -519,7 +519,7 @@ static int compileAndRun(const std::string &filename, } } - // MVS P2–P5.5 + P8 foundation/P8.1: definite-init + mode-aware + // Definite-init + mode-aware // callsite analysis runs after every prototype is in scope but // before any body is codegen'd. The drop registry is built here and // kept alive for the whole codegen pass — codegen reads it via the diff --git a/tests/cabi/README.md b/tests/cabi/README.md deleted file mode 100644 index 629f296..0000000 --- a/tests/cabi/README.md +++ /dev/null @@ -1,119 +0,0 @@ -# Jam C ABI Tests - -This directory contains tests for Jam's C Application Binary Interface (ABI) compatibility, demonstrating interoperability between Jam and C code. - -## Overview - -The C ABI is crucial for: -- Calling C libraries from Jam code -- Exposing Jam functions to C code -- System call interfaces -- FFI (Foreign Function Interface) compatibility - -## Test Files - -### C Helper Code -- **c_helpers.c** - C functions that can be called from Jam -- **c_helpers.h** - Header file for C functions -- **c_caller.c** - C program that calls Jam functions - -### Jam Test Code -- **test_call_c.jam** - Jam code calling C functions -- **jam_functions.jam** - Jam functions exposed to C - -## What We're Testing - -### 1. Calling Convention -- Verify Jam functions use C calling convention -- Check parameter passing (stack vs registers) -- Validate return value handling - -### 2. Data Type Compatibility -- Integer types (i8, i16, i32, i64) -- Unsigned types (u8, u16, u32, u64) -- Pointers and pointer arithmetic -- Struct layout and alignment - -### 3. ABI Details -- Pointer size (32-bit vs 64-bit) -- Struct padding and alignment -- Calling convention specifics (System V AMD64 ABI on Unix, Win64 ABI on Windows) - -### 4. Function Signatures -- Simple functions (primitives) -- Functions with pointers -- Functions with structs -- Variadic functions (future) - -## Running the Tests - -The previous `run_cabi_tests.sh` was removed — it masked failures with a final `exit 0`, so it provided no real signal. The `.jam` and `.c` fixtures in this directory are kept for a future, honest C-interop test harness. - -## Current Status - -✅ **Working:** -- Target information detection -- C calling convention setup -- LLVM IR generation with correct ABI -- Basic type compatibility - -🚧 **In Progress:** -- Extern function declarations in Jam syntax -- Direct linking with C object files -- Struct ABI compatibility - -📋 **Planned:** -- `extern "C"` keyword support in Jam -- Full FFI with type marshalling -- Callback support (C calling Jam) -- Complex struct handling - -## Example: Future Jam Syntax - -```jam -// Future syntax for calling C functions -extern "C" fn printf(format: *const u8, ...) i32; -extern "C" fn malloc(size: u64) *var u8; -extern "C" fn free(ptr: *var u8); - -fn main() u8 { - var msg: *const u8 = "Hello from Jam!\n"; - printf(msg); - return 0; -} -``` - -## C ABI Specifications - -### System V AMD64 ABI (Linux, macOS, BSD) -- First 6 integer arguments in registers: RDI, RSI, RDX, RCX, R8, R9 -- First 8 floating-point arguments in XMM0-XMM7 -- Additional arguments on stack (right to left) -- Return value in RAX (integers) or XMM0 (floats) - -### Microsoft x64 ABI (Windows) -- First 4 arguments in registers: RCX, RDX, R8, R9 -- Additional arguments on stack (right to left) -- Shadow space (32 bytes) required -- Return value in RAX or XMM0 - -### ARM64 (AArch64) -- First 8 integer arguments in X0-X7 -- First 8 floating-point arguments in V0-V7 -- Additional arguments on stack -- Return value in X0 or V0 - -## Debugging - -Test output is saved in `output/` directory: -- `*.log` - Test execution logs -- `*.ll` - LLVM IR files -- `*.o` - Object files -- `*.a` - Static libraries - -## References - -- [System V AMD64 ABI](https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf) -- [Microsoft x64 Calling Convention](https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention) -- [ARM64 ABI](https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst) -- [LLVM Calling Conventions](https://llvm.org/docs/LangRef.html#calling-conventions) diff --git a/tests/comprehensive_test.jam b/tests/comprehensive_test.jam deleted file mode 100644 index ef4708d..0000000 --- a/tests/comprehensive_test.jam +++ /dev/null @@ -1,46 +0,0 @@ -// Comprehensive test demonstrating u8, u16, u32, and u64 functionality -fn test_all_types() u64 { - // Test u8 (8-bit: 0-255) - const small_a: u8 = 100; - const small_b: u8 = 155; - const small_sum: u8 = small_a + small_b; // 255 - - // Test u16 (16-bit: 0-65535) - const medium_a: u16 = 30000; - const medium_b: u16 = 35535; - const medium_sum: u16 = medium_a + medium_b; // 65535 - - // Test u32 (32-bit: 0-4294967295) - const large_a: u32 = 2000000000; - const large_b: u32 = 2294967295; - const large_sum: u32 = large_a + large_b; // 4294967295 - - // Test u64 (64-bit: 0-18446744073709551615) - const huge_a: u64 = 9000000000000000000; - const huge_b: u64 = 1000000000000000000; - const huge_sum: u64 = huge_a + huge_b; // 10000000000000000000 - - return huge_sum; -} - -fn test_boundary_values() u64 { - // Test minimum values - const u8_min: u8 = 0; - const u16_min: u16 = 0; - const u32_min: u32 = 0; - const u64_min: u64 = 0; - - // Test maximum values - const u8_max: u8 = 255; - const u16_max: u16 = 65535; - const u32_max: u32 = 4294967295; - const u64_max: u64 = 18446744073709551615; - - return u64_max; -} - -fn test_type_promotion(small: u8, medium: u16, large: u32) u32 { - // All parameters are properly typed - // Return the largest value - return large; -} \ No newline at end of file diff --git a/tests/cpp/CMakeLists.txt b/tests/cpp/CMakeLists.txt index 42e49cd..d9ef200 100644 --- a/tests/cpp/CMakeLists.txt +++ b/tests/cpp/CMakeLists.txt @@ -1,18 +1,15 @@ cmake_minimum_required(VERSION 3.10) project(JamTests) -# Set C++ standard set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) -# Add test executable (no LLVM dependencies needed for external tests) add_executable(jam_tests external_tests.cpp test_print_functions.cpp test_loops.cpp ) -# Add separate executable for jam files IR tests add_executable(jam_files_ir_tests test_jam_files_ir.cpp ) \ No newline at end of file diff --git a/tests/cpp/build_and_run.sh b/tests/cpp/build_and_run.sh index 21fdf4e..692f465 100755 --- a/tests/cpp/build_and_run.sh +++ b/tests/cpp/build_and_run.sh @@ -1,24 +1,12 @@ #!/bin/bash -# Build and run C++ tests for Jam compiler - -echo "Building C++ Tests..." - -# Create build directory mkdir -p build cd build - -# Configure with CMake cmake .. -DCMAKE_BUILD_TYPE=Debug - -# Build cmake --build . if [ $? -eq 0 ]; then - echo "" - echo "Running C++ Tests..." ./jam_tests else - echo "Build failed!" exit 1 fi \ No newline at end of file diff --git a/tests/cpp/external_tests.cpp b/tests/cpp/external_tests.cpp index 243cb4c..e0b2ac1 100644 --- a/tests/cpp/external_tests.cpp +++ b/tests/cpp/external_tests.cpp @@ -3,7 +3,6 @@ #include #include -// Forward declaration class PrintFunctionTests { public: static void registerAllTests(TestFramework &framework); @@ -308,12 +307,10 @@ class CompilerExternalTests { int main() { TestFramework framework; - // Register all tests CompilerExternalTests::registerAllTests(framework); PrintFunctionTests::registerAllTests(framework); LoopTests::registerAllTests(framework); - // Run all tests framework.runAll(); return framework.allPassed() ? 0 : 1;