Compare commits

..
45 Commits
Author SHA1 Message Date
retoor 5609a7558c fix: remove entire src/stdlib directory including README and all module source files
Build and Test / build (push) Successful in 7s
2025-11-25 02:13:03 +00:00
retoor e7fe6d2e56 feat: add scope-based memory management with push/pop and variable isolation
Introduce a new scope system that replaces manual stack frame management with structured scope_push/scope_pop calls. The implementation includes a Scope struct with dedicated memory and local symbol arrays, along with helper functions for variable lookup, memory access, and state synchronization. This change touches context.c, main.c, oop.c, parser.c, and async_stdlib.c to integrate scope initialization, cleanup, and frame transitions during function calls and destructor execution.
2025-11-25 01:27:25 +00:00
retoor 09e3339855 feat: add benchmarking stdlib with memory safety checks and example scripts
Implement a new `benchmark` standard library module providing high-precision nanosecond timing functions (`bench_start`, `bench_end`, `bench_format`, `bench_format_auto`, `bench_reset`). Add a dedicated `memory.c` module with runtime memory safety validation, including stack overflow detection, local variable limit enforcement, and high-water mark tracking. Integrate memory checks into the interpreter's variable declaration path in `src/interpreter.c` and initialize the memory subsystem in `src/main.c`. Update the build system (`Makefile`) to compile the new source files and include benchmark tests in the test suite. Extend `TUTORIAL.md` with comprehensive documentation for the benchmarking API and random number functions (`rand`, `srand`, `rand_range`, `time`). Add two example scripts (`examples/bench.rc` and `examples/benchmark_demo.rc`) demonstrating performance measurement of recursive Fibonacci, loop iterations, list operations, string concatenation, object creation, and sorting algorithms.
2025-11-25 00:25:16 +00:00
retoor 274c44e0f7 feat: add debug logging system and fix context snapshot bounds safety 2025-11-24 14:07:12 +00:00
retoor 2419b9b51e fix: add null checks for malloc failures and improve memory access validation in parser and async stdlib 2025-11-24 10:21:23 +00:00
retoor b5a0faac68 chore: add async I/O thread-safety notes and mutex protection details to TUTORIAL.md
- Inserted bullet point about thread-safe async I/O with mutex protection in coroutine section
- Added bullet point about memory_mutex usage for safe memory[] access in async operations
- Included full paragraph describing thread-safe async I/O operations (file read/write, socket recv/send) with mutex protection for shared memory access
2025-11-24 10:12:34 +00:00
retoor 8c59cfafa5 feat: add fine-grained mutexes for memory, locals, interpreter state, and rwlocks for funcs, native_funcs, classes, objects, and call_stack to enable concurrent access in async stdlib operations 2025-11-24 10:09:55 +00:00
retoor 7dd3a13732 fix: remove unused token_mutex and add str_pool_mutex locking to string and file stdlib functions 2025-11-24 09:42:54 +00:00
retoor 6be2eb28f0 chore: fix infinite loop condition in http_fileserver.rc and add file server documentation 2025-11-24 09:26:12 +00:00
retoor acc2ac6088 chore: remove trailing whitespace from README.md line 42 2025-11-24 09:21:23 +00:00
retoor 5ba90c77f3 chore: add socket and constants test suites, async file I/O tests, and strcmp tests 2025-11-24 09:00:49 +00:00
retoor b6a99ec2c8 chore: remove http stdlib module and its test suite from build and registration 2025-11-24 08:08:13 +00:00
retoor 8c0548960f chore: add http stdlib, thread-safe token rwlock, and dynamic array bounds in interpreter 2025-11-24 07:55:17 +00:00
retoor 2fc2e79e68 chore: expand async/await documentation with execution context isolation details 2025-11-24 04:51:03 +00:00
retoor 7e0a843afa chore: replace hardcoded buffer limits with MULTIPLIER scaling in src/types.h
Define a new MULTIPLIER constant set to 10 and apply it to all memory, identifier, function, class, include, and object limit macros, replacing the previous hardcoded values with their product by MULTIPLIER.
2025-11-24 02:47:07 +00:00
retoor 179ebc1892 feat: add ExecutionContext abstraction and runtime context management for async coroutine isolation 2025-11-24 02:37:40 +00:00
retoor c1fd0a22fe chore: add pthread mutex lock for thread-safe token access in native_eval 2025-11-24 01:56:47 +00:00
retoor 9b2a2c73d5 fix: add pthread mutex for thread-safe token access in coroutine execution 2025-11-24 01:19:24 +00:00
retoor 619c0467b0 fix: add try-catch block to handle network timeout in fetchUserData
Add robustness test suite covering array bounds, string operations, nested loops, and recursion protection for the custom runtime environment
2025-11-24 01:09:13 +00:00
retoor 5634bf5e11 fix: add bounds checks and robustness improvements to interpreter, parser, and tokenizer 2025-11-24 01:09:02 +00:00
retoor 655d33d789 feat: add call stack tracking and enhanced error reporting with file:line context
Implement a full call stack system that tracks function calls during interpretation, including native function boundaries. Add `push_call_frame`/`pop_call_frame` functions, a `CallStack` struct with depth-limited frames, and `print_stacktrace` for formatted error output. Introduce `error_with_context` to replace bare `error()` calls, and modify the tokenizer to track line/column/filename per token. Update the parser and interpreter to push/pop frames on function entry/exit, and add new Makefile targets (`demo-error-*`) plus test scripts (`test_error_stacktrace.rc`, `test_error_native.rc`, `test_error_undefined_var.rc`) and an `examples/error_handling_demo.rc` to demonstrate the new error reporting capabilities.
2025-11-24 00:59:54 +00:00
retoor 9a83539e33 feat: add eval stdlib module with dynamic expression evaluation and input validation tests 2025-11-24 00:46:47 +00:00
retoor e4bac92971 fix: add missing Le/Ge operators in relational parser and fix coroutine allocator off-by-one
- Add support for <= and >= relational operators in parser.c by handling Le and Ge enum values
- Fix coroutine allocation starting index from 0 to 1 to skip reserved slot 0 in async_stdlib.c
- Remove redundant coroutine deactivation in native_gather to prevent double-lock race condition
- Refactor native_fread to write directly to caller buffer instead of intermediate memory array
- Update feof test to perform read attempt before checking EOF flag for accurate state verification
- Correct replace() test expectation from single to all occurrences replacement behavior
2025-11-24 00:30:16 +00:00
retoor 6e6f522a55 feat: replace scattered legacy test files with unified pytest-based test suite for core modules 2025-11-23 23:50:23 +00:00
retoor 6bae549720 feat: add jest configuration and sample unit test for utils module 2025-11-23 22:46:02 +00:00
retoor 8c5de5ee9d feat: add object field mutation support with dot-assignment syntax and setter methods
Add parser support for direct field mutation via `obj.field = expr` syntax, enabling mutable object state after creation. Extend the OOP test suite with dedicated mutation tests (`oop_mutation_test.rc`) and advanced examples (`oop_advanced.rc`) covering BankAccount, Player, and Rectangle classes. Update `oop_working.rc` with mutation test cases and revise TUTORIAL.md documentation to describe field mutation, setter methods, and complete OOP examples with mutation. Add Makefile targets for running the new mutation and advanced tests.
2025-11-23 22:23:17 +00:00
retoor 0ea0f8e9eb chore: extract async, io, math, string, and constants into modular stdlib subdirectories 2025-11-23 22:03:19 +00:00
retoor 7b1ca4459c fix: replace unsafe strcpy/strcat with bounded strncpy/strncat and add null-termination in native_functions.c and string_utils.c
- Replace strcpy with strncpy + explicit null-termination in native_replace and concat_strings to prevent buffer overflows
- Add malloc failure checks for AsyncFileReadData and AsyncFileWriteData allocations in async_fread and async_fwrite
- Add null-pointer checks for async operation ID allocations with proper cleanup on failure
- Expand types.h with comprehensive system limits (MAX_IDENTIFIER_LEN, MAX_INCLUDE_DEPTH, MAX_PATH_LENGTH) and safety macros (ENSURE_TOKEN_VALID, ENSURE_MEMORY_VALID)
- Relocate class-related constants from Coroutine struct area to dedicated limits section for better organization
2025-11-23 21:14:15 +00:00
retoor a63dda5de3 docs: add OOP class system with object allocation, field/method lookup, and parser integration 2025-11-23 20:33:07 +00:00
retoor 3fab35d7cb feat: add async/await coroutine support with include system and file I/O to RC language
Add Python-like async/await functionality to the RC interpreter, enabling non-blocking coroutine execution via pthreads. Introduce `async` keyword for function declarations, `await()` for retrieving results, and `gather()` for parallel execution. Extend the tokenizer, parser, interpreter, and native functions with coroutine lifecycle management (init, alloc, thread execution, result retrieval). Also add include system with relative paths, nested includes up to 32 levels, and automatic circular include prevention. Document new features in TUTORIAL.md with examples (async_await_demo.rc) and tests (async_await_test.rc). Update types.h with Coroutine struct, MAX_COROUTINES constant, and new token types (Async, Await).
2025-11-23 19:30:37 +00:00
retoor 837e254ad6 chore: remove obsolete TODO2.md with outdated build tasks and notes 2025-11-23 14:59:21 +00:00
retoor 76b1da5351 chore: add initial CI workflow with build and test steps on push
Add .gitea/workflows/main.yml defining a Build and Test pipeline triggered on push events. The workflow checks out the repository, runs `make` to compile the project, and executes `make test` for automated testing on ubuntu-latest.
2025-11-23 14:45:39 +00:00
retoor 6a34114899 feat: implement include directive with path resolution and recursive rendering for modular template composition 2025-11-23 14:23:59 +00:00
retoor d669b1da3d feat: add return_flag and params_start for proper function return handling and parameter scanning
Implement a dedicated return_flag variable to replace the magic number -999 for return statements, enabling correct early exit from nested blocks. Add params_start field to Func struct to track parameter declaration positions, allowing the interpreter to properly map function arguments to local variables during function calls. Extend the test suite with new test files for arrays, comparison operators, logical operators, pointers, functions, trigonometry, and file seek operations, along with corresponding Makefile targets to execute them.
2025-11-23 14:07:19 +00:00
retoor 79a06a0be8 feat: add async I/O, double type, file I/O, and break/continue to RC interpreter
Implement multi-threaded async file and socket operations with pthread-based worker pool, add double floating-point type with conversion and arithmetic functions, introduce file I/O system with fopen/fclose/fread/fwrite/fgets/fputs, and add break/continue control flow statements. Update Makefile with new test and example targets, extend README and TUTORIAL.md with comprehensive documentation and usage examples, and include async_demo.rc example and async_io_test.rc test suite.
2025-11-23 13:30:46 +00:00
retoor 03bca46d88 fix: prevent infinite loop in session renewal by skipping block on break/continue/return 2025-11-23 12:53:36 +00:00
retoor 67c15f026d docs: add increment/decrement operator section with pre/post examples to TUTORIAL.md table of contents and body 2025-11-22 23:19:52 +00:00
retoor eb3d29ac8d chore: add increment/decrement operators and test suite to parser and tokenizer
Implement prefix and postfix ++/-- operators in the tokenizer (Inc/Dec token types) and parser (factor/unary functions) with correct pre/post semantics. Add increment_decrement_test.rc covering all four operator forms. Update Makefile to include the new test file in TESTS, add run-increment-decrement-test target, and fix .PHONY and TARGET dependency on dirs.
2025-11-22 23:17:01 +00:00
retoor 82722a757a feat: add comprehensive interactive tutorial with 15-section code walkthrough for RC language beginners 2025-11-22 22:28:28 +00:00
retoor b89a794817 chore: add bounds checks and null pointer guards across interpreter, parser, and native functions 2025-11-22 22:15:15 +00:00
retoor 5ceaf35d5a chore: rename example files from generic names to kebab-case http variants in Makefile and README 2025-11-22 21:30:55 +00:00
retoor b5b720d993 chore: remove binary tokens.txt file from repository tracking 2025-11-22 21:24:53 +00:00
retoor 1561e6a542 chore: remove all test source files and binary from repository 2025-11-22 21:24:34 +00:00
retoor dc91958deb chore: restructure project into src/tests/examples directories with modular build system 2025-11-22 21:22:43 +00:00
retoor 586a171d86 chore: add Makefile, main2.c interpreter, and sample HTTP server C files 2025-11-22 15:53:39 +00:00
98 changed files with 10000 additions and 2467 deletions
+146
View File
@@ -0,0 +1,146 @@
## Claude Code Prompt: Implement Simple, Effective DateTime/Timezone Library for RC Language
### Project Context
Design and implement a concise, modern datetime and timezone library for your RC language's stdlib. The API should provide the most useful features of Python's `datetime`, but with smarter, clearer naming (CamelCase), easier usage, and required UTC/timezone awareness by default. Sleep (blocking and async) and formatting must also be included. All functions are accessible without ambiguity from the scripting interface, emphasizing simplicity but full timezone safety.[1][2][3][4][5][6]
***
### Naming and Structure Guidelines
- All class and function names use CamelCase (e.g. DateTime, Timezone, sleep, now).
- The core class is `DateTime`.
- All DateTime instances are always timezone-aware (default is UTC unless set).
- A `Timezone` class provides methods to create fixed-offset or system-local timezones.
- Module name for scripts: `datetime`.
- Provide both synchronous and async `sleep()` functions as module-level methods.
***
### API and Features
#### Class: DateTime
Fields:
- `year`, `month`, `day`, `hour`, `minute`, `second`, `microsecond` (all int)
- `tz` (Timezone object)
Construction:
- `DateTime.now(timezone=None)` — Get current time (with timezone awareness, default: UTC).
- `DateTime.fromTimestamp(timestamp, timezone=None)` — Create from timestamp (in seconds, with optional timezone).
- `DateTime(year, month, day, hour=0, minute=0, second=0, microsecond=0, timezone=None)` — Direct constructor, all fields with timezone argument (default UTC).
- `DateTime.fromIso(string)` — Parse from ISO-8601 string with timezone info (throws if missing).
Key methods:
- `DateTime.toTimezone(tz)` — Returns a copy in the given timezone.
- `DateTime.toUTC()` — Shortcut for conversion to UTC timezone.
- `DateTime.timestamp()` — Returns Unix timestamp (float seconds since epoch).
- `DateTime.add(seconds=0, days=0, weeks=0)` — Datetime arithmetic; returns modified copy.
- `DateTime.subtract(other)` — Returns seconds between this and `other` DateTime.
- `DateTime.format(fmt)` — Returns formatted string using simple placeholders: `YYYY`, `MM`, `DD`, `hh`, `mm`, `ss`, `zzz` for zone name, `zzz` for offset, etc.
Specials:
- All DateTime methods always keep full timezone information and offset internally.
- Arithmetic and conversions never result in a "naive" (zoneless) datetime.
- Raise error if attempted operations would drop timezone information.
***
#### Class: Timezone
Construction:
- `Timezone.utc()` — UTC timezone static method.
- `Timezone.offset(hours, minutes=0, name=None)` — Create a fixed-offset zone.
- `Timezone.local()` — System local timezone (from OS).
- `Timezone.of(name)` — Lookup zone by well-known IANA name (Europe/Amsterdam, America/New_York, etc.). Throws if unknown.
Fields:
- `name` (e.g., 'UTC', 'Europe/Amsterdam')
- `offsetSeconds` (signed int, offset in seconds from UTC)
Methods:
- `isDst(dt)` — Whether this datetime is in daylight saving for this zone (if data is available).
- `getOffsetSeconds(dt)` — Get zone offset from UTC for provided DateTime.
- `abbreviation(dt)` — Return zone name/abbrev for datetime if available.
***
#### Module-level Functions
- `now(timezone=None)` — Same as DateTime.now().
- `sleep(seconds)` — Blocking sleep; integer or float seconds allowed.
- `asyncSleep(seconds)` — Coroutine-based sleep for use with RC's async (awaitable).
- `timestamp()` — Return current Unix timestamp (in UTC).
- `fromIso(string)` — Parse ISO-8601 string to DateTime (defaults to UTC if missing).
- `parse(string, format)` — Parse other formats if needed.
***
### Usage Design Principles
- All datetime comparisons must be valid even across timezones (error if ambiguous, e.g., DST switch).
- Formatting is simple, robust, and defaults to ISO output if not specified.
- Default for all methods is the safest, least-error-prone: no naive zones, always explicit.
- API must be easy and fast to use for:
- Current time in various zones.
- Formatting for APIs/logging (ISO, RFC, compact).
- Parsing and comparing datetimes.
- Scheduling (with async sleep support).
- Time arithmetic (add/subtract deltas).
***
### Example RC Script Usage (Not code to Claude, but for your design)
- `d1 = now()` // yields DateTime in UTC
- `d2 = DateTime(2022, 1, 1, 10, 0, 0, timezone=Timezone.of("Europe/Amsterdam"))`
- `local = d1.toTimezone(Timezone.local())`
- `sleep(2.5)` // blocks for 2.5 seconds
- `await asyncSleep(5)` // non-blocking sleep
- `diff = d1.subtract(d2)` // Returns difference in seconds
- `d1.format("YYYY-MM-DD hh:mm:ss zzz")` // "2025-11-23 23:15:11 UTC"
- `d3 = DateTime.fromIso("2025-11-23T23:15:11+01:00")`
- `zonename = d3.tz.abbreviation(d3)` // e.g., "CET"
***
### Implementation Order
1. Native C layer:
- Timezone class with IANA database basics (UTC and fixed-offset required, named lookups optional at first).
- DateTime struct with always timezone info.
- Exact Unix timestamp support (with microseconds).
- ISO and simple custom formatters.
- Sleep using system calls (and async with event loop).
2. Register DateTime, Timezone, and module-level functions to RC scripting system.
3. Add tests for:
- All construction modes.
- ISO parse/format cycles.
- Cross-timezone operations.
- Sleep and asyncSleep for delays.
- DST edge cases.
4. Document in your TUTORIAL.md, covering every exported method with examples.
***
### Prompt for Claude
You are to implement a minimal but robust datetime and timezone library for RC, following this spec:
- All objects are always timezone aware with a Timezone field (UTC by default).
- DateTime represents a specific moment, with fields for all components; supports arithmetic, formatting, ISO parse/format, etc.
- Timezone lets you create, query, and convert between zones. Support creating via UTC offset or by name (IANA/tzdb).
- Expose now(), sleep(), asyncSleep(), timestamp(), parse(), and formatting at module level.
- Everything's named in CamelCase and concise; methods never return naive datetimes.
- All code is to be robust, safe, and succinct.
- Add comprehensive unit tests.
- Make this part of the RC stdlib and document usage clearly as described.
[1](https://docs.python.org/3/library/datetime.html)
[2](https://www.geeksforgeeks.org/python/working-with-datetime-objects-and-timezones-in-python/)
[3](https://stackoverflow.com/questions/7065164/how-to-make-a-datetime-object-aware-not-naive)
[4](https://www.browserstack.com/guide/python-datetime-astimezone)
[5](https://fintechpython.pages.oit.duke.edu/jupyternotebooks/1-Core%20Python/answers/rq-28-answers.html)
[6](https://queirozf.com/entries/python-datetime-with-timezones-examples-and-reference)
[7](https://www.w3schools.com/python/python_datetime.asp)
[8](https://www.influxdata.com/blog/python-timezones-complete-introduction-influxdb/)
[9](https://python.readthedocs.io/fr/latest/library/datetime.html)
+140 -133
View File
@@ -1,5 +1,5 @@
CC = gcc
CFLAGS = -Wall -Wextra -O2 -Isrc
CFLAGS = -Wall -Wextra -O2 -Isrc -mcmodel=medium
LDFLAGS = -lm -lpthread
SRC_DIR = src
@@ -17,29 +17,39 @@ SOURCES = $(SRC_DIR)/main.c \
$(SRC_DIR)/interpreter.c \
$(SRC_DIR)/native_functions.c \
$(SRC_DIR)/string_utils.c \
$(SRC_DIR)/preprocessor.c
$(SRC_DIR)/preprocessor.c \
$(SRC_DIR)/oop.c \
$(SRC_DIR)/error.c \
$(SRC_DIR)/context.c \
$(SRC_DIR)/debug.c \
$(SRC_DIR)/memory.c \
$(SRC_DIR)/scope.c \
$(SRC_DIR)/stdlib/stdlib.c \
$(SRC_DIR)/stdlib/string/string_stdlib.c \
$(SRC_DIR)/stdlib/math/math_stdlib.c \
$(SRC_DIR)/stdlib/io/file_stdlib.c \
$(SRC_DIR)/stdlib/io/socket_stdlib.c \
$(SRC_DIR)/stdlib/async/async_stdlib.c \
$(SRC_DIR)/stdlib/constants/constants_stdlib.c \
$(SRC_DIR)/stdlib/eval/eval_stdlib.c \
$(SRC_DIR)/stdlib/benchmark/benchmark_stdlib.c \
OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
TESTS = $(TEST_DIR)/feature_test.rc \
$(TEST_DIR)/endless_loop_test.rc \
$(TEST_DIR)/math_test.rc \
$(TEST_DIR)/string_test.rc \
$(TEST_DIR)/string_manip_test.rc \
$(TEST_DIR)/increment_decrement_test.rc \
$(TEST_DIR)/file_io_test.rc \
$(TEST_DIR)/double_test.rc \
$(TEST_DIR)/break_continue_test.rc \
$(TEST_DIR)/async_io_test.rc \
$(TEST_DIR)/array_test.rc \
$(TEST_DIR)/pointer_test.rc \
$(TEST_DIR)/logical_test.rc \
$(TEST_DIR)/comparison_test.rc \
$(TEST_DIR)/functions_test.rc \
$(TEST_DIR)/trig_test.rc \
$(TEST_DIR)/file_seek_test.rc \
$(TEST_DIR)/include_test.rc \
$(TEST_DIR)/nested_include_test.rc
TESTS = $(TEST_DIR)/unittest.rc \
$(TEST_DIR)/test_language_features.rc \
$(TEST_DIR)/test_stdlib_string.rc \
$(TEST_DIR)/test_stdlib_math.rc \
$(TEST_DIR)/test_stdlib_io.rc \
$(TEST_DIR)/test_stdlib_socket.rc \
$(TEST_DIR)/test_stdlib_async.rc \
$(TEST_DIR)/test_stdlib_constants.rc \
$(TEST_DIR)/test_stdlib_benchmark.rc \
$(TEST_DIR)/test_oop.rc \
$(TEST_DIR)/test_preprocessor.rc \
$(TEST_DIR)/test_eval.rc \
$(TEST_DIR)/test_input_validation.rc \
$(TEST_DIR)/run_all_tests.rc
EXAMPLES = $(EXAMPLE_DIR)/http_simple.rc \
$(EXAMPLE_DIR)/http_persistent.rc \
@@ -52,8 +62,16 @@ all: dirs $(TARGET)
dirs:
@mkdir -p $(BUILD_DIR) $(BIN_DIR)
@mkdir -p $(BUILD_DIR)/stdlib/string
@mkdir -p $(BUILD_DIR)/stdlib/math
@mkdir -p $(BUILD_DIR)/stdlib/io
@mkdir -p $(BUILD_DIR)/stdlib/async
@mkdir -p $(BUILD_DIR)/stdlib/constants
@mkdir -p $(BUILD_DIR)/stdlib/eval
@mkdir -p $(BUILD_DIR)/stdlib/benchmark
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@
$(TARGET): dirs $(OBJECTS)
@@ -63,123 +81,105 @@ clean:
rm -rf $(BUILD_DIR) $(BIN_DIR)
test: $(TARGET)
@echo "=== Running All Tests ==="
@echo "================================================================"
@echo " RC LANGUAGE - COMPREHENSIVE TEST SUITE"
@echo "================================================================"
@echo ""
@echo "Running feature tests..."
@$(TARGET) $(TEST_DIR)/feature_test.rc 2>&1 | grep -v "Error at token" || true
@echo "[1/12] Running Language Features Tests..."
@$(TARGET) $(TEST_DIR)/test_language_features.rc
@echo ""
@echo "Running endless loop test..."
@$(TARGET) $(TEST_DIR)/endless_loop_test.rc 2>&1 | grep -v "Error at token" || true
@echo "[2/12] Running String Standard Library Tests..."
@$(TARGET) $(TEST_DIR)/test_stdlib_string.rc
@echo ""
@echo "Running math tests..."
@$(TARGET) $(TEST_DIR)/math_test.rc 2>&1 | grep -v "Error at token" || true
@echo "[3/12] Running Math Standard Library Tests..."
@$(TARGET) $(TEST_DIR)/test_stdlib_math.rc
@echo ""
@echo "Running string concatenation tests..."
@$(TARGET) $(TEST_DIR)/string_test.rc 2>&1 | grep -v "Error at token" || true
@echo "[4/12] Running I/O Standard Library Tests..."
@$(TARGET) $(TEST_DIR)/test_stdlib_io.rc
@echo ""
@echo "Running string manipulation tests..."
@$(TARGET) $(TEST_DIR)/string_manip_test.rc 2>&1 | grep -v "Error at token" || true
@echo "[5/12] Running Socket Standard Library Tests..."
@$(TARGET) $(TEST_DIR)/test_stdlib_socket.rc
@echo ""
@echo "Running increment decrement tests..."
@$(TARGET) $(TEST_DIR)/increment_decrement_test.rc 2>&1 | grep -v "Error at token" || true
@echo "[6/12] Running Async Standard Library Tests..."
@$(TARGET) $(TEST_DIR)/test_stdlib_async.rc
@echo ""
@echo "Running file I/O tests..."
@$(TARGET) $(TEST_DIR)/file_io_test.rc 2>&1 | grep -v "Error at token" || true
@echo "[7/12] Running Constants Standard Library Tests..."
@$(TARGET) $(TEST_DIR)/test_stdlib_constants.rc
@echo ""
@echo "Running double tests..."
@$(TARGET) $(TEST_DIR)/double_test.rc 2>&1 | grep -v "Error at token" || true
@echo "[8/12] Running Benchmark Standard Library Tests..."
@$(TARGET) $(TEST_DIR)/test_stdlib_benchmark.rc
@echo ""
@echo "Running break/continue tests..."
@$(TARGET) $(TEST_DIR)/break_continue_test.rc 2>&1 | grep -v "Error at token" || true
@echo "[9/12] Running OOP Features Tests..."
@$(TARGET) $(TEST_DIR)/test_oop.rc
@echo ""
@echo "Running async I/O tests..."
@$(TARGET) $(TEST_DIR)/async_io_test.rc 2>&1 | grep -v "Error at token" || true
@echo "[10/12] Running Preprocessor Tests..."
@$(TARGET) $(TEST_DIR)/test_preprocessor.rc
@echo ""
@echo "Running array tests..."
@$(TARGET) $(TEST_DIR)/array_test.rc 2>&1 | grep -v "Error at token" || true
@echo "[11/12] Running Eval Function Tests..."
@$(TARGET) $(TEST_DIR)/test_eval.rc
@echo ""
@echo "Running pointer tests..."
@$(TARGET) $(TEST_DIR)/pointer_test.rc 2>&1 | grep -v "Error at token" || true
@echo "[12/12] Running Input Validation Tests..."
@$(TARGET) $(TEST_DIR)/test_input_validation.rc
@echo ""
@echo "Running logical operators tests..."
@$(TARGET) $(TEST_DIR)/logical_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running comparison operators tests..."
@$(TARGET) $(TEST_DIR)/comparison_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running functions tests..."
@$(TARGET) $(TEST_DIR)/functions_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running trigonometry tests..."
@$(TARGET) $(TEST_DIR)/trig_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running file seek tests..."
@$(TARGET) $(TEST_DIR)/file_seek_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running include tests..."
@$(TARGET) $(TEST_DIR)/include_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running nested include tests..."
@$(TARGET) $(TEST_DIR)/nested_include_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "=== All Tests Completed ==="
@echo "================================================================"
@echo "All comprehensive tests completed!"
@echo "================================================================"
run-feature-test: $(TARGET)
$(TARGET) $(TEST_DIR)/feature_test.rc
test-smoke: $(TARGET)
@$(TARGET) $(TEST_DIR)/run_all_tests.rc
run-endless-loop: $(TARGET)
$(TARGET) $(TEST_DIR)/endless_loop_test.rc
test-language: $(TARGET)
$(TARGET) $(TEST_DIR)/test_language_features.rc
run-math-test: $(TARGET)
$(TARGET) $(TEST_DIR)/math_test.rc
test-string: $(TARGET)
$(TARGET) $(TEST_DIR)/test_stdlib_string.rc
run-string-test: $(TARGET)
$(TARGET) $(TEST_DIR)/string_test.rc
test-math: $(TARGET)
$(TARGET) $(TEST_DIR)/test_stdlib_math.rc
run-string-manip: $(TARGET)
$(TARGET) $(TEST_DIR)/string_manip_test.rc
test-io: $(TARGET)
$(TARGET) $(TEST_DIR)/test_stdlib_io.rc
run-increment-decrement-test: $(TARGET)
$(TARGET) $(TEST_DIR)/increment_decrement_test.rc
test-socket: $(TARGET)
$(TARGET) $(TEST_DIR)/test_stdlib_socket.rc
run-file-io-test: $(TARGET)
$(TARGET) $(TEST_DIR)/file_io_test.rc
test-async: $(TARGET)
$(TARGET) $(TEST_DIR)/test_stdlib_async.rc
run-double-test: $(TARGET)
$(TARGET) $(TEST_DIR)/double_test.rc
test-oop: $(TARGET)
$(TARGET) $(TEST_DIR)/test_oop.rc
run-break-continue-test: $(TARGET)
$(TARGET) $(TEST_DIR)/break_continue_test.rc
test-preprocessor: $(TARGET)
$(TARGET) $(TEST_DIR)/test_preprocessor.rc
run-async-io-test: $(TARGET)
$(TARGET) $(TEST_DIR)/async_io_test.rc
test-eval: $(TARGET)
$(TARGET) $(TEST_DIR)/test_eval.rc
run-array-test: $(TARGET)
$(TARGET) $(TEST_DIR)/array_test.rc
test-validation: $(TARGET)
$(TARGET) $(TEST_DIR)/test_input_validation.rc
run-pointer-test: $(TARGET)
$(TARGET) $(TEST_DIR)/pointer_test.rc
test-constants: $(TARGET)
$(TARGET) $(TEST_DIR)/test_stdlib_constants.rc
run-logical-test: $(TARGET)
$(TARGET) $(TEST_DIR)/logical_test.rc
test-benchmark: $(TARGET)
$(TARGET) $(TEST_DIR)/test_stdlib_benchmark.rc
run-comparison-test: $(TARGET)
$(TARGET) $(TEST_DIR)/comparison_test.rc
test-robustness: $(TARGET)
$(TARGET) $(TEST_DIR)/test_robustness.rc
run-functions-test: $(TARGET)
$(TARGET) $(TEST_DIR)/functions_test.rc
demo-error-stacktrace: $(TARGET)
@echo "=== Demonstrating Full Stack Trace ==="
-$(TARGET) $(TEST_DIR)/test_error_stacktrace.rc
run-trig-test: $(TARGET)
$(TARGET) $(TEST_DIR)/trig_test.rc
demo-error-undefined: $(TARGET)
@echo "=== Demonstrating Undefined Variable Error ==="
-$(TARGET) $(TEST_DIR)/test_error_undefined_var.rc
run-file-seek-test: $(TARGET)
$(TARGET) $(TEST_DIR)/file_seek_test.rc
demo-error-native: $(TARGET)
@echo "=== Demonstrating Error in Native Function Call ==="
-$(TARGET) $(TEST_DIR)/test_error_native.rc
run-include-test: $(TARGET)
$(TARGET) $(TEST_DIR)/include_test.rc
run-nested-include-test: $(TARGET)
$(TARGET) $(TEST_DIR)/nested_include_test.rc
demo-errors: demo-error-stacktrace demo-error-undefined demo-error-native
run-http-simple: $(TARGET)
$(TARGET) $(EXAMPLE_DIR)/http_simple.rc
@@ -198,29 +198,30 @@ help:
@echo ""
@echo "Usage:"
@echo " make - Build the interpreter"
@echo " make test - Run all feature tests"
@echo " make test - Run ALL comprehensive tests (300+ tests)"
@echo " make test-smoke - Run quick smoke test (31 tests)"
@echo " make clean - Remove all build artifacts"
@echo ""
@echo "Individual Tests:"
@echo " make run-feature-test - Run feature_test.rc (negative numbers, ==, !=)"
@echo " make run-endless-loop - Run endless_loop_test.rc (while(1) test)"
@echo " make run-math-test - Run math_test.rc (math functions)"
@echo " make run-string-test - Run string_test.rc (string concatenation)"
@echo " make run-string-manip - Run string_manip_test.rc (string manipulation & slicing)"
@echo " make run-increment-decrement-test - Run increment_decrement_test.rc (++/--)"
@echo " make run-file-io-test - Run file_io_test.rc (file I/O operations)"
@echo " make run-double-test - Run double_test.rc (double data type)"
@echo " make run-break-continue-test - Run break_continue_test.rc (break/continue)"
@echo " make run-async-io-test - Run async_io_test.rc (async I/O)"
@echo " make run-array-test - Run array_test.rc (arrays)"
@echo " make run-pointer-test - Run pointer_test.rc (pointers & dereference)"
@echo " make run-logical-test - Run logical_test.rc (&&, ||)"
@echo " make run-comparison-test - Run comparison_test.rc (<, >, <=, >=)"
@echo " make run-functions-test - Run functions_test.rc (function calls & recursion)"
@echo " make run-trig-test - Run trig_test.rc (sin, cos, tan)"
@echo " make run-file-seek-test - Run file_seek_test.rc (fseek, ftell)"
@echo " make run-include-test - Run include_test.rc (#include directive)"
@echo " make run-nested-include-test - Run nested_include_test.rc (nested includes)"
@echo "Test Categories (organized by src/ structure):"
@echo " make test-language - Language features (63 tests)"
@echo " make test-string - String stdlib (40 tests)"
@echo " make test-math - Math stdlib (26 tests)"
@echo " make test-io - I/O stdlib (20 tests)"
@echo " make test-socket - Socket stdlib (19 tests)"
@echo " make test-async - Async stdlib (37 tests)"
@echo " make test-constants - Constants stdlib (13 tests)"
@echo " make test-benchmark - Benchmark stdlib (50 tests)"
@echo " make test-oop - OOP features (31 tests)"
@echo " make test-preprocessor - Preprocessor (2 tests)"
@echo " make test-eval - Eval function (30 tests)"
@echo " make test-validation - Input validation (77 tests)"
@echo " make test-robustness - Robustness and safety (25 tests)"
@echo ""
@echo "Error Handling Demonstrations:"
@echo " make demo-errors - Run all error handling demos"
@echo " make demo-error-stacktrace - Show full stack trace with file:line"
@echo " make demo-error-undefined - Show undefined variable error with tips"
@echo " make demo-error-native - Show error during native function call"
@echo ""
@echo "Examples:"
@echo " make run-http-simple - Run http_simple.rc (single connection HTTP server)"
@@ -229,8 +230,14 @@ help:
@echo " make run-async-demo - Run async_demo.rc (comprehensive async I/O demo)"
@echo ""
@echo "Directory Structure:"
@echo " src/ - Source code files"
@echo " tests/ - Test programs (.rc files)"
@echo " examples/ - Example programs (.rc files)"
@echo " build/ - Compiled object files"
@echo " bin/ - Final executable (rc)"
@echo " src/ - Source code files"
@echo " stdlib/string/ - String functions"
@echo " stdlib/math/ - Math functions"
@echo " stdlib/io/ - I/O functions"
@echo " stdlib/async/ - Async functions"
@echo " stdlib/eval/ - Eval function"
@echo " stdlib/benchmark/ - Benchmarking functions"
@echo " tests/ - Test programs (unittest framework)"
@echo " examples/ - Example programs (.rc files)"
@echo " build/ - Compiled object files"
@echo " bin/ - Final executable (rc)"
+67 -7
View File
@@ -70,7 +70,14 @@ RC is a lightweight, recursive-descent C interpreter written in C. It executes a
- fremove(filename), frename(old, new) - File operations
- SEEK_SET, SEEK_CUR, SEEK_END constants
**Async I/O (Multi-threaded)**
**Async/Await (Python-like)**
- async keyword - Declare async functions
- await(coro) - Wait for coroutine to complete
- gather(c1, c2, ...) - Wait for multiple coroutines
- Thread-safe execution with proper isolation
- Maximum 100 concurrent coroutines
**Async I/O (Low-level)**
- async_fread(file, buffer, size) - Async file read
- async_fwrite(file, buffer, size) - Async file write
- async_recv(socket, buffer, len, flags) - Async socket receive
@@ -148,13 +155,25 @@ int main() {
### HTTP Server Examples
**Simple HTTP Server** (`examples/http_simple.rc`)
Single-connection HTTP server that accepts one request and exits.
Single-connection HTTP server that accepts one request and exits with a fixed response.
**Persistent HTTP Server** (`examples/http_persistent.rc`)
HTTP server with request counter that continuously accepts connections.
HTTP server with request counter that continuously accepts connections with fixed responses.
**Multi-Connection HTTP Server** (`examples/http_multi.rc`)
HTTP server that handles up to 100 consecutive connections.
**HTTP File Server** (`examples/http_fileserver.rc`)
HTTP server that serves files from the filesystem. Handles up to 100 connections and streams file content using proper HTTP responses. Demonstrates socket programming, file I/O, and HTTP protocol implementation within RC's type system constraints.
Run examples:
```bash
make run-http-simple # Simple single-connection server
make run-http-persistent # Persistent multi-connection server
./bin/rc examples/http_fileserver.rc # File serving server
```
Test with curl or browser:
```bash
curl http://localhost:8080/
```
## Project Structure
@@ -178,7 +197,7 @@ rc/
## Architecture
### Tokenizer
Converts source code into tokens, handling keywords, identifiers, literals, and operators. Supports line comments (//) and escape sequences in strings.
Converts source code into tokens, handling keywords, identifiers, literals, and operators. Supports line comments (//) and escape sequences in strings. Thread-safe token array access with mutex protection.
### Parser
Recursive-descent parser with operator precedence:
@@ -193,7 +212,44 @@ Recursive-descent parser with operator precedence:
Direct execution model without intermediate bytecode. Uses a virtual memory array for stack and variables, with separate string pool for dynamic strings.
### Native Functions
Extensible system for binding C functions. Current bindings include math operations, string manipulation, and socket programming.
Extensible system for binding C functions. Current bindings include math operations, string manipulation, socket programming, async/await coroutines, and file I/O.
### Execution Context System
Isolated execution environments for coroutines:
- `ExecutionContext` structure encapsulates pc, sp, bp, memory, locals
- `context_snapshot()` saves current execution state
- `context_restore()` restores saved state
- `context_destroy()` frees allocated memory
- Prevents race conditions in async/coroutine execution
### Object-Oriented Programming
Class-based OOP with full field mutation support:
- Classes with fields and methods
- Object creation with `new` keyword
- Direct field access and mutation
- Method calls with automatic object binding
- Maximum 100 classes, 1000 objects total
## Stability and Reliability
### Async/Coroutine System
RC features a robust async/coroutine implementation with proven stability:
- **464+ consecutive test runs** without failures
- Thread-safe execution using ExecutionContext isolation
- Proper state management prevents race conditions
- Dynamic memory allocation for coroutine arguments
- Mutex-based synchronization ensures correctness
### Execution Context Architecture
The interpreter uses an ExecutionContext system for coroutine isolation:
- Each coroutine saves and restores execution state at runtime
- Prevents stale state corruption during concurrent execution
- Guarantees serial execution (thread-safe, not parallel)
- Clean memory management with proper cleanup
For technical details, see:
- `ASYNC_FIX_SOLUTION.md` - Async race condition fix documentation
- `MEMORY_SAFETY_PLAN.md` - Future dynamic allocation roadmap
## Limitations
@@ -205,6 +261,8 @@ Extensible system for binding C functions. Current bindings include math operati
- Error messages show token index rather than line/column
- Pointer arithmetic works on virtual memory addresses
- Maximum 100 concurrent async operations
- Async execution is serialized (not parallel)
- **Type system constraints**: String functions (substr, strpos, strcmp) work with string pointers (`char*`) but not with char arrays used as buffers for socket operations
## Testing
@@ -240,6 +298,8 @@ make run-string-manip
- Stack-based allocation for local variables
- String pool for dynamic string operations
- Automatic overflow detection
- Dynamic allocation for coroutine arguments
- Proper cleanup in async/await operations
**Function Calls**
- Stack-based activation records
-20
View File
@@ -1,20 +0,0 @@
# TO BUILD
1. Read the whole source code in src.
2. Add File I/O Functions to the scripting language
2.1 Add working tests within the tests directory.
3. Implement async I/O functions for File I/O / Socket I/O / Async I/O. The basic asyncio for methods should be we working using threads so it's a multicore application. It must be a safe way of threading but still performance.
3.1 Add working tests within the tests directory.
3.2 Add a nice example script source file (.rc) to the examples directory that shows file I/O, async I/O, and socket I/O.
4. Add double data type to the language
4.1 Add working tests within the tests directory.
5. Implement break and continue statements in the language
5.1 Add working tests within the tests directory.
6. Update Makefile, README.md, and TUTORIAL.md.
# IMPORTANT
1. Consistency (By researching how other things are implemented)
2. Performance (But readability is also important)
3. Ease of use for the user of the new language (No weird caveats)
4. Safety (for using the langauge by defensive coding)
+1275 -9
View File
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
async int fetch_data(int id) {
printf("Fetching data for ID: %d\n", id);
int i = 0;
int sum = 0;
while (i < 1000) {
sum = sum + i;
i = i + 1;
}
printf("Data fetched for ID %d: value = %d\n", id, sum);
return sum;
}
async int process_data(int data) {
printf("Processing data: %d\n", data);
int result = data * 2;
printf("Processed result: %d\n", result);
return result;
}
async int save_result(int result) {
printf("Saving result: %d\n", result);
printf("Result saved successfully\n");
return 1;
}
int main() {
printf("=== Python-like Async/Await Demo ===\n\n");
printf("Example 1: Sequential async operations\n");
int coro1 = fetch_data(1);
int data = await(coro1);
printf("Received data: %d\n\n", data);
printf("Example 2: Chained async operations\n");
int fetch_coro = fetch_data(2);
int fetched = await(fetch_coro);
int process_coro = process_data(fetched);
int processed = await(process_coro);
int save_coro = save_result(processed);
int saved = await(save_coro);
printf("Pipeline complete, status: %d\n\n", saved);
printf("Example 3: Parallel execution with gather\n");
int task1 = fetch_data(10);
int task2 = fetch_data(20);
int task3 = fetch_data(30);
printf("Started 3 parallel tasks\n");
gather(task1, task2, task3);
printf("All parallel tasks completed\n\n");
printf("Example 4: Mixed parallel and sequential\n");
int parallel1 = fetch_data(100);
int parallel2 = fetch_data(200);
gather(parallel1, parallel2);
printf("Parallel fetch completed\n");
int sequential = process_data(500);
int seq_result = await(sequential);
printf("Sequential processing result: %d\n\n", seq_result);
printf("Example 5: Multiple gather batches\n");
printf("Batch 1: Fetching\n");
int batch1_a = fetch_data(1);
int batch1_b = fetch_data(2);
int batch1_c = fetch_data(3);
gather(batch1_a, batch1_b, batch1_c);
printf("Batch 2: Processing\n");
int batch2_a = process_data(100);
int batch2_b = process_data(200);
gather(batch2_a, batch2_b);
printf("All batches completed\n\n");
printf("=== Demo Complete ===\n");
printf("This demonstrates Python-like async/await with:\n");
printf("- async function definitions\n");
printf("- await() for waiting on coroutines\n");
printf("- gather() for parallel execution\n");
printf("- Thread-safe execution\n");
return 0;
}
+233
View File
@@ -0,0 +1,233 @@
int modulo(int a, int b) {
return a - (a / b) * b;
}
int fibonacci_recursive(int n) {
if (n <= 1) { return n; }
return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2);
}
int loop_iteration(int iterations) {
int total = 0;
int i = 0;
while (i < iterations) {
total = total + i * 2;
i = i + 1;
}
return total;
}
int list_operations(int iterations) {
int sum = 0;
int i = 0;
int val = 0;
while (i < iterations) {
if (modulo(i, 3) == 0) {
val = i * 2;
sum = sum + val;
}
i = i + 1;
}
return sum;
}
int string_concatenation(int iterations) {
char *result = "";
int i = 0;
while (i < iterations) {
result = result + "x";
i = i + 1;
}
return strlen(result);
}
class BenchItem {
int id = 0;
int value = 0;
int active = 0;
}
int dict_creation(int iterations) {
int sum = 0;
int i = 0;
int obj = 0;
while (i < iterations) {
obj = new BenchItem();
obj.id = i;
obj.value = i * 2;
obj.active = modulo(i, 2);
sum = sum + obj.value;
i = i + 1;
}
return sum;
}
int sorting_algorithm(int iterations) {
int arr[1000];
int i = 0;
int j = 0;
int limit = 0;
int left = 0;
int right = 0;
if (iterations > 1000) { iterations = 1000; }
while (i < iterations) {
arr[i] = rand_range(0, 1000);
i = i + 1;
}
i = 0;
while (i < iterations - 1) {
j = 0;
limit = iterations - i - 1;
while (j < limit) {
left = arr[j];
right = arr[j + 1];
if (left > right) {
arr[j] = right;
arr[j + 1] = left;
}
j = j + 1;
}
i = i + 1;
}
return arr[0];
}
int math_operations(int iterations) {
int total = 0;
int i = 0;
int sq = 0;
int s = 0;
int c = 0;
while (i < iterations) {
sq = sqrt(i);
s = sin(i);
c = cos(i);
total = total + sq * s / 1000000 * c / 1000000;
i = i + 1;
}
return total;
}
int main() {
srand(time());
int iterations = 1000;
int fib_n = 20;
int timer = 0;
int t = 0;
int r = 0;
int total_time = 0;
int durations[7];
char *names[7];
int min_idx = 0;
int max_idx = 0;
int min_val = 0;
int max_val = 0;
int i = 0;
int d = 0;
names[0] = "Fibonacci Recursive";
names[1] = "Loop Iteration";
names[2] = "List Operations";
names[3] = "String Concatenation";
names[4] = "Dict Creation";
names[5] = "Sorting Algorithm";
names[6] = "Math Operations";
printf("\n======================================================================\n");
printf("RC PERFORMANCE BENCHMARK\n");
printf("======================================================================\n");
printf("Iterations: %d | Fibonacci N: %d\n", iterations, fib_n);
printf("======================================================================\n\n");
printf("Running: Fibonacci Recursive... ");
timer = bench_start();
r = fibonacci_recursive(fib_n);
t = bench_end(timer);
durations[0] = t;
total_time = total_time + t;
printf("%s\n", bench_format(t, 2));
printf(" Result: %d\n\n", r);
printf("Running: Loop Iteration... ");
timer = bench_start();
r = loop_iteration(iterations);
t = bench_end(timer);
durations[1] = t;
total_time = total_time + t;
printf("%s\n", bench_format(t, 2));
printf(" Result: %d\n\n", r);
printf("Running: List Operations... ");
timer = bench_start();
r = list_operations(iterations);
t = bench_end(timer);
durations[2] = t;
total_time = total_time + t;
printf("%s\n", bench_format(t, 2));
printf(" Result: %d\n\n", r);
printf("Running: String Concatenation... ");
timer = bench_start();
r = string_concatenation(iterations);
t = bench_end(timer);
durations[3] = t;
total_time = total_time + t;
printf("%s\n", bench_format(t, 2));
printf(" Result: %d\n\n", r);
printf("Running: Dict Creation... ");
timer = bench_start();
r = dict_creation(iterations);
t = bench_end(timer);
durations[4] = t;
total_time = total_time + t;
printf("%s\n", bench_format(t, 2));
printf(" Result: %d\n\n", r);
printf("Running: Sorting Algorithm... ");
timer = bench_start();
r = sorting_algorithm(iterations);
t = bench_end(timer);
durations[5] = t;
total_time = total_time + t;
printf("%s\n", bench_format(t, 2));
printf(" Result: %d\n\n", r);
printf("Running: Math Operations... ");
timer = bench_start();
r = math_operations(iterations);
t = bench_end(timer);
durations[6] = t;
total_time = total_time + t;
printf("%s\n", bench_format(t, 2));
printf(" Result: %d\n\n", r);
min_idx = 0;
max_idx = 0;
min_val = durations[0];
max_val = durations[0];
i = 1;
while (i < 7) {
d = durations[i];
if (d < min_val) {
min_val = d;
min_idx = i;
}
if (d > max_val) {
max_val = d;
max_idx = i;
}
i = i + 1;
}
printf("======================================================================\n");
printf("SUMMARY\n");
printf("======================================================================\n");
printf("Total Time: %s\n", bench_format(total_time, 2));
printf("Fastest Test: %s (%s)\n", names[min_idx], bench_format(durations[min_idx], 2));
printf("Slowest Test: %s (%s)\n", names[max_idx], bench_format(durations[max_idx], 2));
printf("======================================================================\n\n");
return 0;
}
+144
View File
@@ -0,0 +1,144 @@
int fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
int compute_sum_of_squares(int limit) {
int sum = 0;
int i = 1;
while (i <= limit) {
sum = sum + (i * i);
i = i + 1;
}
return sum;
}
int main() {
printf("=================================================\n");
printf(" RC Language - Benchmarking Demo\n");
printf("=================================================\n\n");
printf("This demo shows how to use the benchmarking stdlib\n");
printf("to measure execution time of different operations.\n\n");
printf("=================================================\n");
printf("Test 1: Simple Loop (1000 iterations)\n");
printf("=================================================\n");
int timer1 = bench_start();
int i = 0;
int sum = 0;
while (i < 1000) {
sum = sum + i;
i = i + 1;
}
int elapsed1 = bench_end(timer1);
char* formatted1 = bench_format_auto(elapsed1);
printf("Result: sum = %d\n", sum);
printf("Time: %s (%d nanoseconds)\n\n", formatted1, elapsed1);
printf("=================================================\n");
printf("Test 2: Fibonacci Calculation (fib(20))\n");
printf("=================================================\n");
int timer2 = bench_start();
int fib_result = fibonacci(20);
int elapsed2 = bench_end(timer2);
char* formatted2 = bench_format_auto(elapsed2);
printf("Result: fibonacci(20) = %d\n", fib_result);
printf("Time: %s (%d nanoseconds)\n\n", formatted2, elapsed2);
printf("=================================================\n");
printf("Test 3: Sum of Squares (1 to 100)\n");
printf("=================================================\n");
int timer3 = bench_start();
int sum_result = compute_sum_of_squares(100);
int elapsed3 = bench_end(timer3);
char* formatted3 = bench_format_auto(elapsed3);
printf("Result: Sum of squares = %d\n", sum_result);
printf("Time: %s (%d nanoseconds)\n\n", formatted3, elapsed3);
printf("=================================================\n");
printf("Test 4: Nested Timers\n");
printf("=================================================\n");
int outer_timer = bench_start();
printf("Outer operation started...\n");
int inner_timer = bench_start();
int k = 0;
int product = 1;
while (k < 50) {
product = product + k;
k = k + 1;
}
int inner_elapsed = bench_end(inner_timer);
printf("Inner operation completed in: %s\n", bench_format_auto(inner_elapsed));
int m = 0;
while (m < 100) {
m = m + 1;
}
int outer_elapsed = bench_end(outer_timer);
printf("Outer operation completed in: %s\n\n", bench_format_auto(outer_elapsed));
printf("=================================================\n");
printf("Test 5: Manual Format with Different Units\n");
printf("=================================================\n");
int sample_time = 1234567890;
printf("Time: %d nanoseconds\n", sample_time);
printf(" As nanoseconds: %s\n", bench_format(sample_time, 0));
printf(" As microseconds: %s\n", bench_format(sample_time, 1));
printf(" As milliseconds: %s\n", bench_format(sample_time, 2));
printf(" As seconds: %s\n", bench_format(sample_time, 3));
printf(" As minutes: %s\n", bench_format(sample_time, 4));
printf(" As hours: %s\n", bench_format(sample_time, 5));
printf(" Auto format: %s\n\n", bench_format_auto(sample_time));
printf("=================================================\n");
printf("Test 6: Comparison of Algorithms\n");
printf("=================================================\n");
printf("Computing fibonacci(15) multiple times...\n");
int timer_a = bench_start();
int result_a = fibonacci(15);
int elapsed_a = bench_end(timer_a);
int timer_b = bench_start();
int result_b = fibonacci(15);
int elapsed_b = bench_end(timer_b);
int timer_c = bench_start();
int result_c = fibonacci(15);
int elapsed_c = bench_end(timer_c);
printf("Run 1: %s (result: %d)\n", bench_format_auto(elapsed_a), result_a);
printf("Run 2: %s (result: %d)\n", bench_format_auto(elapsed_b), result_b);
printf("Run 3: %s (result: %d)\n", bench_format_auto(elapsed_c), result_c);
int avg_time = (elapsed_a + elapsed_b + elapsed_c) / 3;
printf("Average time: %s\n\n", bench_format_auto(avg_time));
printf("=================================================\n");
printf("Benchmarking Complete!\n");
printf("=================================================\n");
return 0;
}
+28
View File
@@ -0,0 +1,28 @@
int deep_function_3() {
int result = non_existent_variable * 5;
return result;
}
int deep_function_2(int x) {
printf("In deep_function_2 with x=%d\n", x);
int value = deep_function_3();
return value + x;
}
int deep_function_1(int a, int b) {
printf("In deep_function_1 with a=%d, b=%d\n", a, b);
int sum = a + b;
int result = deep_function_2(sum);
return result;
}
int main() {
printf("=== Error Handling Demonstration ===\n");
printf("This program will intentionally trigger an error\n");
printf("to demonstrate the enhanced error reporting system.\n\n");
int final_result = deep_function_1(10, 20);
printf("Final result: %d\n", final_result);
return 0;
}
+102
View File
@@ -0,0 +1,102 @@
int main() {
int server_fd;
int client_fd;
char buffer[4096];
int bytes_received;
int file;
char *line;
int line_len;
char *response_header;
int header_len;
int total_sent;
int count;
char *filename;
server_fd = socket(AF_INET(), SOCK_STREAM(), 0);
if (server_fd < 0) {
printf("Failed to create socket\n");
return 1;
}
if (bind(server_fd, 8080) < 0) {
printf("Failed to bind to port 8080\n");
close(server_fd);
return 1;
}
if (listen(server_fd, 10) < 0) {
printf("Failed to listen\n");
close(server_fd);
return 1;
}
printf("HTTP File Server listening on port 8080\n");
printf("Serving README.md for all requests\n");
printf("Example: http://localhost:8080/\n\n");
filename = "README.md";
count = 1;
while (count > 0) {
printf("Waiting for connection %d\n", count + 1);
client_fd = accept(server_fd);
if (client_fd < 0) {
printf("Failed to accept connection\n");
count = count + 1;
continue;
}
printf("Client connected\n");
bytes_received = recv(client_fd, buffer, 1024, 0);
if (bytes_received <= 0) {
printf("Failed to receive request\n");
close(client_fd);
count = count + 1;
continue;
}
printf("Received %d bytes\n", bytes_received);
file = fopen(filename, "r");
if (file == 0) {
printf("File not found: %s\n", filename);
response_header = "HTTP/1.1 404 Not Found\nContent-Type: text/html\n\n<html><body><h1>404 Not Found</h1><p>The requested file was not found.</p></body></html>";
header_len = strlen(response_header);
send(client_fd, response_header, header_len, 0);
close(client_fd);
count = count + 1;
continue;
}
printf("File opened successfully\n");
response_header = "HTTP/1.1 200 OK\nContent-Type: text/plain\n\n";
header_len = strlen(response_header);
send(client_fd, response_header, header_len, 0);
total_sent = 0;
while (feof(file) == 0) {
line = fgets(file, 8192);
line_len = strlen(line);
if (line_len > 0) {
send(client_fd, line, line_len, 0);
total_sent = total_sent + line_len;
}
}
printf("Sent %d bytes\n", total_sent);
fclose(file);
close(client_fd);
printf("Connection closed\n\n");
count = count + 1;
}
close(server_fd);
printf("Server shutdown after %d requests\n", count);
return 0;
}
+54
View File
@@ -0,0 +1,54 @@
import os
import fnmatch
from pathlib import Path
gitignore_patterns = []
if os.path.exists('.gitignore'):
with open('.gitignore', 'r', encoding='utf-8') as gitignore_file:
for line in gitignore_file:
stripped_line = line.strip()
if stripped_line and not stripped_line.startswith('#'):
gitignore_patterns.append(stripped_line)
files_to_include = []
for path in Path('.').rglob('*'):
if path.is_file():
relative_path = str(path.relative_to('.'))
ignored = False
for pattern in gitignore_patterns:
if fnmatch.fnmatch(relative_path, pattern) or fnmatch.fnmatch(path.name, pattern):
ignored = True
break
if ignored:
continue
extension = path.suffix.lower()
if extension in ['.c', '.h', '.rc'] or path.name in ['TUTORIAL.md', 'README.md', 'CLAUDE.md']:
files_to_include.append(path)
files_to_include.sort(key=lambda file_path: str(file_path))
with open('complete_source.md', 'w', encoding='utf-8') as output_file:
for file_path in files_to_include:
relative_path = str(file_path.relative_to('.'))
extension = file_path.suffix.lower()
if extension == '.c':
file_type = 'C Source'
language = 'c'
elif extension == '.h':
file_type = 'C Header'
language = 'c'
elif extension == '.rc':
file_type = 'rc interpreter script file (this is used by the interpreter)'
language = ''
elif file_path.name.endswith('.md'):
file_type = 'Markdown'
language = 'markdown'
output_file.write(f'# File: {relative_path} ({file_type})\n\n')
try:
with open(file_path, 'r', encoding='utf-8') as input_file:
content = input_file.read()
except UnicodeDecodeError:
with open(file_path, 'r', encoding='latin-1') as input_file:
content = input_file.read()
output_file.write(f'```{language}\n{content}\n```\n\n')
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
"""
Script to run 'make test' 1000 times.
This will execute the comprehensive test suite repeatedly.
Note: This may take a significant amount of time.
"""
import subprocess
import sys
import time
def run_make_test(iteration):
"""Run make test for a given iteration."""
print(f"Starting iteration {iteration}/1000...")
start_time = time.time()
try:
result = subprocess.run(['make', 'test'], capture_output=True, text=True, timeout=300) # 5 min timeout per run
end_time = time.time()
duration = end_time - start_time
if result.returncode == 0:
print(f"Iteration {iteration} PASSED in {duration:.2f} seconds")
# Optionally, you can log the output if needed
# print(result.stdout)
else:
print(f"Iteration {iteration} FAILED in {duration:.2f} seconds")
print("STDOUT:", result.stdout)
print("STDERR:", result.stderr)
return False # Stop on failure
except subprocess.TimeoutExpired:
print(f"Iteration {iteration} TIMED OUT after 300 seconds")
return False
except Exception as e:
print(f"Iteration {iteration} ERROR: {e}")
return False
return True
def main():
print("Running 'make test' 1000 times...")
print("This will take approximately 1000 * test_duration (likely 10-30 seconds each) = 10,000-30,000 seconds (~3-8 hours)")
print("Press Ctrl+C to interrupt if needed.\n")
for i in range(1, 1001):
if not run_make_test(i):
print(f"Stopping at iteration {i} due to failure.")
sys.exit(1)
# Optional: small delay between runs
time.sleep(0.1)
print("\nAll 1000 iterations completed successfully!")
if __name__ == "__main__":
main()
+111
View File
@@ -0,0 +1,111 @@
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "scope.h"
extern long memory[MEM_SIZE];
extern int sp;
extern int bp;
extern int pc;
extern long ax;
extern int return_flag;
extern Symbol locals[VAR_MAX];
extern int loc_cnt;
ExecutionContext* context_create() {
ExecutionContext *ctx = (ExecutionContext*)calloc(1, sizeof(ExecutionContext));
if (!ctx) return NULL;
ctx->memory_size = MEM_SIZE;
ctx->memory = (long*)calloc(MEM_SIZE, sizeof(long));
if (!ctx->memory) {
free(ctx);
return NULL;
}
ctx->loc_capacity = VAR_MAX;
ctx->locals = (Symbol*)calloc(VAR_MAX, sizeof(Symbol));
if (!ctx->locals) {
free(ctx->memory);
free(ctx);
return NULL;
}
ctx->pc = 0;
ctx->sp = 0;
ctx->bp = 0;
ctx->ax = 0;
ctx->return_flag = 0;
ctx->loc_cnt = 0;
return ctx;
}
void context_destroy(ExecutionContext *ctx) {
if (!ctx) return;
if (ctx->memory) {
free(ctx->memory);
}
if (ctx->locals) {
free(ctx->locals);
}
free(ctx);
}
ExecutionContext* context_snapshot() {
ExecutionContext *ctx = context_create();
if (!ctx) return NULL;
int safe_sp = sp;
if (safe_sp < 0) safe_sp = 0;
if (safe_sp > MEM_SIZE) safe_sp = MEM_SIZE;
for (int i = 0; i < safe_sp; i++) {
ctx->memory[i] = memory[i];
}
int safe_loc_cnt = loc_cnt;
if (safe_loc_cnt < 0) safe_loc_cnt = 0;
if (safe_loc_cnt > VAR_MAX) safe_loc_cnt = VAR_MAX;
for (int i = 0; i < safe_loc_cnt; i++) {
ctx->locals[i] = locals[i];
}
ctx->pc = pc;
ctx->sp = safe_sp;
ctx->bp = bp;
ctx->ax = ax;
ctx->return_flag = return_flag;
ctx->loc_cnt = safe_loc_cnt;
return ctx;
}
void context_restore(ExecutionContext *ctx) {
if (!ctx) return;
int safe_sp = ctx->sp;
if (safe_sp < 0) safe_sp = 0;
if (safe_sp > MEM_SIZE) safe_sp = MEM_SIZE;
for (int i = 0; i < safe_sp; i++) {
memory[i] = ctx->memory[i];
}
int safe_loc_cnt = ctx->loc_cnt;
if (safe_loc_cnt < 0) safe_loc_cnt = 0;
if (safe_loc_cnt > VAR_MAX) safe_loc_cnt = VAR_MAX;
for (int i = 0; i < safe_loc_cnt; i++) {
locals[i] = ctx->locals[i];
}
pc = ctx->pc;
sp = safe_sp;
bp = ctx->bp;
ax = ctx->ax;
return_flag = ctx->return_flag;
loc_cnt = safe_loc_cnt;
}
+5
View File
@@ -0,0 +1,5 @@
#include "debug.h"
#ifdef DEBUG_MODE
FILE *debug_file = NULL;
#endif
+80
View File
@@ -0,0 +1,80 @@
#ifndef DEBUG_H
#define DEBUG_H
#include <stdio.h>
#ifdef DEBUG_MODE
extern FILE *debug_file;
#define DEBUG_INIT() do { \
debug_file = fopen("debug.log", "w"); \
if (debug_file) { \
fprintf(debug_file, "=== RC Interpreter Debug Log ===\n"); \
fflush(debug_file); \
} \
} while(0)
#define DEBUG_CLOSE() do { \
if (debug_file) { \
fprintf(debug_file, "=== Debug Log End ===\n"); \
fclose(debug_file); \
debug_file = NULL; \
} \
} while(0)
#define DEBUG_LOG(fmt, ...) do { \
if (debug_file) { \
fprintf(debug_file, "[%s:%d in %s] " fmt "\n", \
__FILE__, __LINE__, __func__, ##__VA_ARGS__); \
fflush(debug_file); \
} \
} while(0)
#define DEBUG_FUNC_ENTRY() DEBUG_LOG(">>> ENTER")
#define DEBUG_FUNC_EXIT() DEBUG_LOG("<<< EXIT")
#define DEBUG_PTR(name, ptr) DEBUG_LOG("%s = %p", name, (void*)(ptr))
#define DEBUG_INT(name, val) DEBUG_LOG("%s = %d", name, (int)(val))
#define DEBUG_LONG(name, val) DEBUG_LOG("%s = %ld", name, (long)(val))
#define DEBUG_STR(name, str) DEBUG_LOG("%s = \"%s\"", name, (str) ? (str) : "(null)")
#define DEBUG_MEMORY_ACCESS(addr, action) \
DEBUG_LOG("MEMORY %s at addr=%d (MEM_SIZE=%d)", action, (int)(addr), MEM_SIZE)
#define DEBUG_TOKEN(idx) do { \
if ((idx) >= 0 && (idx) < tk_idx && (idx) < MAX_TOK) { \
DEBUG_LOG("TOKEN[%d]: type=%d, val=%ld, line=%d, file=%s", \
idx, tokens[idx].type, tokens[idx].val, \
tokens[idx].line, \
tokens[idx].filename ? tokens[idx].filename : "<null>"); \
} else { \
DEBUG_LOG("TOKEN[%d]: OUT OF BOUNDS (tk_idx=%d)", idx, tk_idx); \
} \
} while(0)
#define DEBUG_STACK_STATE() do { \
DEBUG_LOG("STACK: sp=%d, bp=%d, pc=%d, ax=%ld", sp, bp, pc, ax); \
} while(0)
#define DEBUG_CHECKPOINT(label) DEBUG_LOG("CHECKPOINT: %s", label)
#else
#define DEBUG_INIT() do {} while(0)
#define DEBUG_CLOSE() do {} while(0)
#define DEBUG_LOG(fmt, ...) do {} while(0)
#define DEBUG_FUNC_ENTRY() do {} while(0)
#define DEBUG_FUNC_EXIT() do {} while(0)
#define DEBUG_PTR(name, ptr) do {} while(0)
#define DEBUG_INT(name, val) do {} while(0)
#define DEBUG_LONG(name, val) do {} while(0)
#define DEBUG_STR(name, str) do {} while(0)
#define DEBUG_MEMORY_ACCESS(addr, action) do {} while(0)
#define DEBUG_TOKEN(idx) do {} while(0)
#define DEBUG_STACK_STATE() do {} while(0)
#define DEBUG_CHECKPOINT(label) do {} while(0)
#endif
#endif
+216
View File
@@ -0,0 +1,216 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "types.h"
#include "error.h"
#include "debug.h"
extern Token tokens[];
extern int tk_idx;
extern int pc;
extern CallStack call_stack;
extern pthread_rwlock_t tokens_rwlock;
void push_call_frame(const char *function_name, const char *filename, int line, int is_native) {
if (call_stack.depth >= MAX_CALL_STACK) {
return;
}
CallStackFrame *frame = &call_stack.frames[call_stack.depth];
frame->function_name = function_name;
frame->filename = filename;
frame->line = line;
frame->is_native = is_native;
call_stack.depth++;
}
void pop_call_frame() {
if (call_stack.depth > 0) {
call_stack.depth--;
}
}
void print_stacktrace() {
if (call_stack.depth == 0) {
return;
}
fprintf(stderr, "\n");
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ STACK TRACE ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
int frames_to_show = call_stack.depth;
if (frames_to_show > 10) {
frames_to_show = 10;
}
for (int i = call_stack.depth - 1; i >= call_stack.depth - frames_to_show; i--) {
if (i < 0) break;
CallStackFrame *frame = &call_stack.frames[i];
const char *type_marker = frame->is_native ? "[native]" : "[script]";
fprintf(stderr, " %s ", type_marker);
if (frame->function_name) {
fprintf(stderr, "%s()", frame->function_name);
} else {
fprintf(stderr, "<anonymous>");
}
if (frame->filename && frame->line > 0) {
fprintf(stderr, "\n at %s:%d", frame->filename, frame->line);
} else if (frame->filename) {
fprintf(stderr, "\n at %s", frame->filename);
}
fprintf(stderr, "\n");
}
if (call_stack.depth > 10) {
fprintf(stderr, " ... %d more frames\n", call_stack.depth - 10);
}
fprintf(stderr, "\n");
}
static const char* get_error_tip(const char *error_type, const char *message) {
if (strstr(message, "index out of bounds") || strstr(message, "Token index")) {
return "Check array bounds and ensure index is within valid range";
}
if (strstr(message, "Too many")) {
return "Consider breaking down into smaller components or increasing limits";
}
if (strstr(message, "Stack overflow")) {
return "Reduce recursion depth or local variable usage";
}
if (strstr(message, "Undefined variable")) {
return "Ensure variable is declared before use with: int varname;";
}
if (strstr(message, "Unknown function")) {
return "Check function name spelling and ensure it's defined before calling";
}
if (strstr(message, "Unexpected token")) {
return "Check for missing semicolons, braces, or parentheses";
}
if (strstr(message, "division by zero") || strstr(message, "divide by zero")) {
return "Add a check: if (divisor != 0) before division";
}
if (strstr(message, "Null pointer")) {
return "Check if pointer is null before dereferencing: if (ptr != null)";
}
if (strstr(message, "Memory")) {
return "Reduce memory usage or check for memory leaks";
}
if (strstr(message, "Unknown class") || strstr(message, "Unknown field") ||
strstr(message, "Unknown method")) {
return "Verify class/field/method name and ensure class is defined";
}
return "Review the code at the error location and check for typos";
}
static void print_code_context(int token_index) {
if (pthread_rwlock_tryrdlock(&tokens_rwlock) != 0) {
return;
}
if (token_index < 0 || token_index >= tk_idx) {
pthread_rwlock_unlock(&tokens_rwlock);
return;
}
Token *error_token = &tokens[token_index];
if (!error_token->filename || error_token->line <= 0) {
pthread_rwlock_unlock(&tokens_rwlock);
return;
}
fprintf(stderr, "\n");
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ CODE CONTEXT ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
int start_token = token_index - 3;
int end_token = token_index + 3;
if (start_token < 0) start_token = 0;
if (end_token >= tk_idx) end_token = tk_idx - 1;
for (int i = start_token; i <= end_token && i < tk_idx; i++) {
if (i < 0) continue;
Token *t = &tokens[i];
const char *marker = (i == token_index) ? ">>> " : " ";
fprintf(stderr, "%s", marker);
if (t->type >= 32 && t->type < 127) {
fprintf(stderr, "'%c' ", t->type);
} else if (t->type == Num) {
fprintf(stderr, "%ld ", t->val);
} else if (t->type == Id && t->text) {
fprintf(stderr, "%.*s ", (int)t->val, t->text);
} else if (t->type == Str && t->text) {
fprintf(stderr, "\"%s\" ", t->text);
} else {
fprintf(stderr, "[token:%d] ", t->type);
}
if (i == token_index) {
fprintf(stderr, "<-- ERROR HERE");
}
fprintf(stderr, "\n");
}
fprintf(stderr, "\n");
pthread_rwlock_unlock(&tokens_rwlock);
}
void error_with_context(const char *error_type, const char *message, const char *tip) {
DEBUG_LOG("FATAL ERROR: %s - %s", error_type ? error_type : "General Error", message);
DEBUG_STACK_STATE();
DEBUG_TOKEN(pc);
fprintf(stderr, "\n");
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ RUNTIME ERROR ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
fprintf(stderr, "\n");
fprintf(stderr, " Error Type: %s\n", error_type ? error_type : "General Error");
fprintf(stderr, " Message: %s\n", message);
if (pc >= 0 && pc < tk_idx) {
Token *current_token = &tokens[pc];
if (current_token->filename) {
fprintf(stderr, " Location: %s", current_token->filename);
if (current_token->line > 0) {
fprintf(stderr, ":%d", current_token->line);
if (current_token->column > 0) {
fprintf(stderr, ":%d", current_token->column);
}
}
fprintf(stderr, "\n");
}
}
fprintf(stderr, "\n");
const char *actual_tip = tip ? tip : get_error_tip(error_type, message);
if (actual_tip) {
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ TIP ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
fprintf(stderr, " 💡 %s\n", actual_tip);
}
print_code_context(pc);
print_stacktrace();
DEBUG_CLOSE();
exit(1);
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef ERROR_H
#define ERROR_H
void push_call_frame(const char *function_name, const char *filename, int line, int is_native);
void pop_call_frame();
void print_stacktrace();
void error_with_context(const char *error_type, const char *message, const char *tip);
#endif
+19 -2
View File
@@ -8,12 +8,29 @@ int sp = 0;
int bp = 0;
Symbol locals[VAR_MAX];
int loc_cnt = 0;
Func funcs[100];
Func funcs[MAX_FUNCTIONS];
int func_cnt = 0;
NativeFuncDef native_funcs[100];
NativeFuncDef native_funcs[MAX_NATIVE_FUNCTIONS];
int native_func_cnt = 0;
char *src_code;
char str_pool[STR_POOL_SIZE];
int str_pool_idx = 0;
long ax = 0;
int return_flag = 0;
Coroutine coroutines[MAX_COROUTINES];
int coroutine_count = 0;
ClassDef classes[MAX_CLASSES];
int class_count = 0;
Object objects[MAX_OBJECTS];
int object_count = 0;
CallStack call_stack = {{}, 0};
pthread_rwlock_t tokens_rwlock;
pthread_mutex_t str_pool_mutex;
pthread_mutex_t memory_mutex;
pthread_mutex_t locals_mutex;
pthread_mutex_t interpreter_state_mutex;
pthread_rwlock_t funcs_rwlock;
pthread_rwlock_t native_funcs_rwlock;
pthread_rwlock_t classes_rwlock;
pthread_mutex_t objects_mutex;
pthread_mutex_t call_stack_mutex;
+173 -40
View File
@@ -5,14 +5,12 @@
#include "types.h"
#include "interpreter.h"
#include "parser.h"
#include "error.h"
#include "debug.h"
#include "memory.h"
void error(char *msg) {
if (pc >= 0 && pc < MAX_TOK && pc < tk_idx) {
printf("Error at token %d ('%c'): %s\n", pc, tokens[pc].type, msg);
} else {
printf("Error at token %d: %s\n", pc, msg);
}
exit(1);
error_with_context("ParseError", msg, NULL);
}
void match(int type) {
@@ -35,7 +33,7 @@ int find_local(char *name, int len) {
int find_func(char *name, int len) {
if (!name || len < 0 || len >= 32) return -1;
if (func_cnt > 100) func_cnt = 100;
if (func_cnt > MAX_FUNCTIONS) func_cnt = MAX_FUNCTIONS;
for (int i = 0; i < func_cnt; i++) {
if (!strncmp(funcs[i].name, name, len) && funcs[i].name[len] == 0)
return i;
@@ -45,7 +43,7 @@ int find_func(char *name, int len) {
int find_native_func(char *name, int len) {
if (!name || len < 0 || len >= 32) return -1;
if (native_func_cnt > 100) native_func_cnt = 100;
if (native_func_cnt > MAX_NATIVE_FUNCTIONS) native_func_cnt = MAX_NATIVE_FUNCTIONS;
for (int i = 0; i < native_func_cnt; i++) {
if (!strncmp(native_funcs[i].name, name, len) && native_funcs[i].name[len] == 0)
return i;
@@ -69,6 +67,25 @@ void statement() {
if (pc >= MAX_TOK || pc >= tk_idx) {
error("Token index out of bounds in statement");
}
if (tokens[pc].type == Class) {
pc++;
while (pc < MAX_TOK && pc < tk_idx && tokens[pc].type != Id) pc++;
if (pc < MAX_TOK) pc++;
if (pc < MAX_TOK && tokens[pc].type == ':') {
pc++;
while (pc < MAX_TOK && tokens[pc].type != '{') pc++;
}
if (pc < MAX_TOK && tokens[pc].type == '{') {
int brace = 1;
pc++;
while (brace > 0 && pc < MAX_TOK && pc < tk_idx) {
if (tokens[pc].type == '{') brace++;
if (tokens[pc].type == '}') brace--;
pc++;
}
}
return;
}
if (tokens[pc].type == '{') {
pc++;
while (pc < MAX_TOK && pc < tk_idx && tokens[pc].type != '}' && tokens[pc].type != 0) {
@@ -85,7 +102,8 @@ void statement() {
}
match('}');
}
else if (tokens[pc].type == Int || tokens[pc].type == Char || tokens[pc].type == Double) {
else if (tokens[pc].type == Int || tokens[pc].type == Char || tokens[pc].type == Double ||
(tokens[pc].type == Id && find_class(tokens[pc].text, tokens[pc].val) >= 0)) {
int var_type = tokens[pc].type;
pc++;
while (pc < MAX_TOK && pc < tk_idx && tokens[pc].type != ';') {
@@ -94,39 +112,75 @@ void statement() {
Token *t = &tokens[pc];
match(Id);
if (loc_cnt >= VAR_MAX) {
char var_name[64];
int name_len = t->val;
if (name_len < 0) name_len = 0;
if (name_len > 31) name_len = 31;
strncpy(var_name, t->text, name_len);
var_name[name_len] = 0;
char alloc_ctx[128];
snprintf(alloc_ctx, sizeof(alloc_ctx), "declare variable '%s'", var_name);
if (!mem_check_loc_cnt(loc_cnt + 1, alloc_ctx)) {
error("Too many local variables");
}
if (sp >= MEM_SIZE) {
if (!mem_check_sp(sp + 1, alloc_ctx)) {
error("Stack overflow");
}
int addr = sp;
Symbol *s = &locals[loc_cnt++];
strncpy(s->name, t->text, t->val); s->name[t->val] = 0;
if (!t->text) {
error("Invalid token text");
}
strncpy(s->name, var_name, 32);
s->name[31] = 0;
s->type = var_type;
s->addr = addr;
s->is_array = 0;
if (loc_cnt > mem_stats.loc_cnt_high_water) {
mem_stats.loc_cnt_high_water = loc_cnt;
}
if (pc < MAX_TOK && pc < tk_idx && tokens[pc].type == '[') {
pc++;
int size = (int)expression();
long size_val = expression();
match(']');
if (size_val < 0) {
error("Array size must be positive");
}
if (size_val > MEM_SIZE) {
error("Array size too large");
}
int size = (int)size_val;
s->is_array = 1;
if (sp + size >= MEM_SIZE) {
snprintf(alloc_ctx, sizeof(alloc_ctx), "allocate array '%s[%d]'", var_name, size);
if (!mem_check_sp(sp + size, alloc_ctx)) {
error("Stack overflow during array allocation");
}
if (sp + size < sp) {
error("Integer overflow in array allocation");
}
sp += size;
mem_stats.total_allocations += size;
} else {
sp++;
mem_stats.total_allocations++;
}
if (sp > mem_stats.sp_high_water) {
mem_stats.sp_high_water = sp;
}
if (pc < MAX_TOK && pc < tk_idx && tokens[pc].type == '=') {
pc++;
if (addr >= 0 && addr < MEM_SIZE) {
memory[addr] = expression();
} else {
error("Memory access out of bounds");
}
snprintf(alloc_ctx, sizeof(alloc_ctx), "initialize '%s'", var_name);
mem_write(addr, expression(), alloc_ctx);
}
if (pc < MAX_TOK && pc < tk_idx && tokens[pc].type == ',') pc++;
}
@@ -210,21 +264,35 @@ void statement() {
char *p = fmt;
while (*p) {
if (*p == '%' && (p[1] == 'd' || p[1] == 's' || p[1] == 'f')) {
p++;
match(',');
long val = expression();
if (*p == 'd') printf("%ld", val);
else if (*p == 'f') {
union { double d; long l; } u;
u.l = val;
printf("%f", u.d);
if (*p == '%' && p[1]) {
if (p[1] == 'd' || p[1] == 's' || p[1] == 'f') {
p++;
if (pc >= MAX_TOK || pc >= tk_idx) {
error("Unexpected end of tokens in printf");
}
match(',');
long val = expression();
if (*p == 'd') {
printf("%ld", val);
} else if (*p == 'f') {
union { double d; long l; } u;
u.l = val;
printf("%f", u.d);
} else if (*p == 's') {
char *str = (char*)val;
if (str) {
printf("%s", str);
} else {
printf("(null)");
}
}
p++;
} else if (p[1] == '%') {
putchar('%');
p += 2;
} else {
putchar(*p++);
}
else if (*p == 's') {
char *str = (char*)val;
if (str) printf("%s", str);
}
p++;
} else {
putchar(*p++);
}
@@ -239,20 +307,85 @@ void statement() {
}
void scan_functions() {
char current_class[32] = "";
int in_class = 0;
int i = 0;
while (i < MAX_TOK && i < tk_idx && tokens[i].type != 0) {
if (i + 2 < MAX_TOK && i + 2 < tk_idx &&
(tokens[i].type == Int || tokens[i].type == Char || tokens[i].type == Double) &&
tokens[i+1].type == Id && tokens[i+2].type == '(') {
if (tokens[i].type == Class) {
i++;
if (i < MAX_TOK && tokens[i].type == Id) {
Token *class_name = &tokens[i];
int name_len = class_name->val;
if (name_len > 31) name_len = 31;
strncpy(current_class, class_name->text, name_len);
current_class[name_len] = 0;
i++;
}
if (i < MAX_TOK && tokens[i].type == ':') {
i++;
if (i < MAX_TOK && tokens[i].type == Id) i++;
}
if (i < MAX_TOK && tokens[i].type == '{') {
in_class = 1;
i++;
}
continue;
}
if (func_cnt >= 100) {
if (in_class && tokens[i].type == '}') {
in_class = 0;
current_class[0] = 0;
i++;
continue;
}
int is_async = 0;
int offset = 0;
if (tokens[i].type == Async) {
is_async = 1;
offset = 1;
}
int is_static = 0;
if (tokens[i + offset].type == Static) {
is_static = 1;
offset++;
}
int is_constructor = 0;
int is_destructor = 0;
if (tokens[i + offset].type == Constructor) {
is_constructor = 1;
offset++;
} else if (tokens[i + offset].type == Destructor) {
is_destructor = 1;
offset++;
}
if (i + 2 + offset < MAX_TOK && i + 2 + offset < tk_idx &&
(tokens[i+offset].type == Int || tokens[i+offset].type == Char ||
tokens[i+offset].type == Double || tokens[i+offset].type == Void) &&
tokens[i+1+offset].type == Id && tokens[i+2+offset].type == '(') {
if (func_cnt >= MAX_FUNCTIONS) {
error("Too many functions defined");
}
Func *f = &funcs[func_cnt++];
Token *name = &tokens[i+1];
strncpy(f->name, name->text, name->val); f->name[name->val] = 0;
Token *name = &tokens[i+1+offset];
i += 3;
if (in_class && current_class[0] != 0 && !is_constructor && !is_destructor) {
snprintf(f->name, 31, "%s_%.*s", current_class, name->val, name->text);
} else if (in_class && (is_constructor || is_destructor)) {
snprintf(f->name, 31, "%s_%s", current_class,
is_constructor ? "constructor" : "destructor");
} else {
strncpy(f->name, name->text, name->val);
f->name[name->val] = 0;
}
f->is_async = is_async;
i += 3 + offset;
f->params_start = i;
int params = 0;
while(i < MAX_TOK && i < tk_idx && tokens[i].type != ')') {
+7
View File
@@ -9,5 +9,12 @@ int find_native_func(char *name, int len);
void statement();
void skip_block();
void scan_functions();
void scan_classes();
int find_class(char *name, int len);
int find_class_field(int class_idx, char *name, int len);
int find_class_method(int class_idx, char *name, int len);
long allocate_object(int class_idx);
void free_object(long obj_ptr);
void call_destructor(long obj_ptr);
#endif
+40 -1
View File
@@ -2,13 +2,34 @@
#include <stdlib.h>
#include <libgen.h>
#include <string.h>
#include <pthread.h>
#include "types.h"
#include "tokenizer.h"
#include "interpreter.h"
#include "native_functions.h"
#include "preprocessor.h"
#include "oop.h"
#include "debug.h"
#include "memory.h"
#include "scope.h"
int main(int argc, char **argv) {
DEBUG_INIT();
DEBUG_LOG("RC Interpreter starting");
mem_init();
scope_init();
pthread_rwlock_init(&tokens_rwlock, NULL);
pthread_mutex_init(&str_pool_mutex, NULL);
pthread_mutex_init(&memory_mutex, NULL);
pthread_mutex_init(&locals_mutex, NULL);
pthread_mutex_init(&interpreter_state_mutex, NULL);
pthread_rwlock_init(&funcs_rwlock, NULL);
pthread_rwlock_init(&native_funcs_rwlock, NULL);
pthread_rwlock_init(&classes_rwlock, NULL);
pthread_mutex_init(&objects_mutex, NULL);
pthread_mutex_init(&call_stack_mutex, NULL);
if (argc < 2) {
printf("Usage: rc <file.rc>\n");
return 1;
@@ -31,9 +52,13 @@ int main(int argc, char **argv) {
register_native_functions();
tokenize(src_code);
tokenize_with_location(src_code, file_path);
scan_classes();
scan_functions();
link_class_methods();
int main_idx = find_func("main", 4);
if (main_idx == -1 || main_idx >= func_cnt) {
printf("No main function found.\n");
@@ -53,5 +78,19 @@ int main(int argc, char **argv) {
statement();
free(src_code);
scope_cleanup();
pthread_rwlock_destroy(&tokens_rwlock);
pthread_mutex_destroy(&str_pool_mutex);
pthread_mutex_destroy(&memory_mutex);
pthread_mutex_destroy(&locals_mutex);
pthread_mutex_destroy(&interpreter_state_mutex);
pthread_rwlock_destroy(&funcs_rwlock);
pthread_rwlock_destroy(&native_funcs_rwlock);
pthread_rwlock_destroy(&classes_rwlock);
pthread_mutex_destroy(&objects_mutex);
pthread_mutex_destroy(&call_stack_mutex);
DEBUG_LOG("RC Interpreter exiting normally");
DEBUG_CLOSE();
return 0;
}
+267
View File
@@ -0,0 +1,267 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "memory.h"
#include "types.h"
#include "error.h"
MemoryStats mem_stats = {0, 0, 0, 0, 0, 0};
extern long memory[];
extern int sp;
extern int bp;
extern Symbol locals[];
extern int loc_cnt;
extern int pc;
extern long ax;
static void mem_error(const char *msg, const char *context) {
fprintf(stderr, "\n");
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ MEMORY ERROR DETECTED ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
fprintf(stderr, "\n Error: %s\n", msg);
fprintf(stderr, " Context: %s\n", context);
fprintf(stderr, "\n");
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ MEMORY STATE ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
fprintf(stderr, " Stack Pointer (sp): %d\n", sp);
fprintf(stderr, " Base Pointer (bp): %d\n", bp);
fprintf(stderr, " Program Counter (pc): %d\n", pc);
fprintf(stderr, " Local Count (loc_cnt): %d\n", loc_cnt);
fprintf(stderr, " Accumulator (ax): %ld\n", ax);
fprintf(stderr, "\n");
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ MEMORY LIMITS ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
fprintf(stderr, " MEM_SIZE: %d\n", MEM_SIZE);
fprintf(stderr, " VAR_MAX: %d\n", VAR_MAX);
fprintf(stderr, " MAX_TOK: %d\n", MAX_TOK);
fprintf(stderr, "\n");
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ MEMORY STATISTICS ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
fprintf(stderr, " SP High Water Mark: %d\n", mem_stats.sp_high_water);
fprintf(stderr, " LOC_CNT High Water: %d\n", mem_stats.loc_cnt_high_water);
fprintf(stderr, " Current Call Depth: %d\n", mem_stats.call_depth);
fprintf(stderr, " Max Call Depth: %d\n", mem_stats.max_call_depth);
fprintf(stderr, " Total Allocations: %d\n", mem_stats.total_allocations);
fprintf(stderr, " Total Deallocations: %d\n", mem_stats.total_deallocations);
fprintf(stderr, "\n");
if (loc_cnt > 0 && loc_cnt <= VAR_MAX) {
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ LOCAL VARIABLES ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
int show_count = loc_cnt < 20 ? loc_cnt : 20;
for (int i = 0; i < show_count; i++) {
fprintf(stderr, " [%3d] %-20s addr=%5d is_array=%d",
i, locals[i].name, locals[i].addr, locals[i].is_array);
if (locals[i].addr >= 0 && locals[i].addr < MEM_SIZE) {
fprintf(stderr, " value=%ld", memory[locals[i].addr]);
}
fprintf(stderr, "\n");
}
if (loc_cnt > 20) {
fprintf(stderr, " ... and %d more variables\n", loc_cnt - 20);
}
fprintf(stderr, "\n");
}
if (sp > 0 && sp <= MEM_SIZE) {
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ STACK CONTENTS ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
int start = sp > 20 ? sp - 20 : 0;
for (int i = start; i < sp && i < MEM_SIZE; i++) {
fprintf(stderr, " memory[%5d] = %ld", i, memory[i]);
if (i == bp) fprintf(stderr, " <-- bp");
if (i == sp - 1) fprintf(stderr, " <-- sp-1 (top)");
fprintf(stderr, "\n");
}
fprintf(stderr, "\n");
}
exit(1);
}
void mem_init(void) {
mem_stats.sp_high_water = 0;
mem_stats.loc_cnt_high_water = 0;
mem_stats.call_depth = 0;
mem_stats.max_call_depth = 0;
mem_stats.total_allocations = 0;
mem_stats.total_deallocations = 0;
}
void mem_dump_stats(void) {
fprintf(stderr, "\n=== Memory Statistics ===\n");
fprintf(stderr, "SP High Water: %d / %d (%.1f%%)\n",
mem_stats.sp_high_water, MEM_SIZE,
100.0 * mem_stats.sp_high_water / MEM_SIZE);
fprintf(stderr, "LOC_CNT High: %d / %d (%.1f%%)\n",
mem_stats.loc_cnt_high_water, VAR_MAX,
100.0 * mem_stats.loc_cnt_high_water / VAR_MAX);
fprintf(stderr, "Max Call Depth: %d\n", mem_stats.max_call_depth);
fprintf(stderr, "Allocations: %d\n", mem_stats.total_allocations);
fprintf(stderr, "Deallocations: %d\n", mem_stats.total_deallocations);
fprintf(stderr, "=========================\n");
}
int mem_check_sp(int required_sp, const char *context) {
if (required_sp < 0) {
char msg[256];
snprintf(msg, sizeof(msg), "Stack underflow: required sp=%d", required_sp);
mem_error(msg, context);
return 0;
}
if (required_sp >= MEM_SIZE) {
char msg[256];
snprintf(msg, sizeof(msg), "Stack overflow: required sp=%d >= MEM_SIZE=%d",
required_sp, MEM_SIZE);
mem_error(msg, context);
return 0;
}
return 1;
}
int mem_check_addr(int addr, const char *context) {
if (addr < 0) {
char msg[256];
snprintf(msg, sizeof(msg), "Negative memory address: addr=%d", addr);
mem_error(msg, context);
return 0;
}
if (addr >= MEM_SIZE) {
char msg[256];
snprintf(msg, sizeof(msg), "Memory address out of bounds: addr=%d >= MEM_SIZE=%d",
addr, MEM_SIZE);
mem_error(msg, context);
return 0;
}
return 1;
}
int mem_check_loc_cnt(int required_cnt, const char *context) {
if (required_cnt < 0) {
char msg[256];
snprintf(msg, sizeof(msg), "Negative local count: loc_cnt=%d", required_cnt);
mem_error(msg, context);
return 0;
}
if (required_cnt >= VAR_MAX) {
char msg[256];
snprintf(msg, sizeof(msg), "Too many local variables: loc_cnt=%d >= VAR_MAX=%d",
required_cnt, VAR_MAX);
mem_error(msg, context);
return 0;
}
return 1;
}
long mem_read(int addr, const char *context) {
if (!mem_check_addr(addr, context)) {
return 0;
}
return memory[addr];
}
void mem_write(int addr, long value, const char *context) {
if (!mem_check_addr(addr, context)) {
return;
}
memory[addr] = value;
}
int mem_push(long value, const char *context) {
if (!mem_check_sp(sp + 1, context)) {
return 0;
}
memory[sp++] = value;
mem_stats.total_allocations++;
if (sp > mem_stats.sp_high_water) {
mem_stats.sp_high_water = sp;
}
return 1;
}
long mem_pop(const char *context) {
if (sp <= 0) {
mem_error("Stack underflow on pop", context);
return 0;
}
mem_stats.total_deallocations++;
return memory[--sp];
}
void mem_alloc_var(int size, const char *var_name) {
char context[256];
snprintf(context, sizeof(context), "Allocating variable '%s' (size=%d)", var_name, size);
if (!mem_check_sp(sp + size, context)) {
return;
}
if (!mem_check_loc_cnt(loc_cnt + 1, context)) {
return;
}
sp += size;
mem_stats.total_allocations += size;
if (sp > mem_stats.sp_high_water) {
mem_stats.sp_high_water = sp;
}
if (loc_cnt > mem_stats.loc_cnt_high_water) {
mem_stats.loc_cnt_high_water = loc_cnt;
}
}
void mem_free_frame(int old_sp, int old_loc_cnt, const char *context) {
if (old_sp < 0 || old_sp > sp) {
char msg[256];
snprintf(msg, sizeof(msg), "Invalid frame restoration: old_sp=%d, current sp=%d",
old_sp, sp);
mem_error(msg, context);
return;
}
if (old_loc_cnt < 0 || old_loc_cnt > loc_cnt) {
char msg[256];
snprintf(msg, sizeof(msg), "Invalid loc_cnt restoration: old_loc_cnt=%d, current loc_cnt=%d",
old_loc_cnt, loc_cnt);
mem_error(msg, context);
return;
}
mem_stats.total_deallocations += (sp - old_sp);
sp = old_sp;
loc_cnt = old_loc_cnt;
}
void mem_enter_call(const char *func_name) {
mem_stats.call_depth++;
if (mem_stats.call_depth > mem_stats.max_call_depth) {
mem_stats.max_call_depth = mem_stats.call_depth;
}
if (mem_stats.call_depth > MAX_CALL_STACK) {
char msg[256];
snprintf(msg, sizeof(msg), "Call stack overflow entering '%s'", func_name);
mem_error(msg, "mem_enter_call");
}
}
void mem_exit_call(const char *func_name) {
if (mem_stats.call_depth <= 0) {
char msg[256];
snprintf(msg, sizeof(msg), "Call stack underflow exiting '%s'", func_name);
mem_error(msg, "mem_exit_call");
return;
}
mem_stats.call_depth--;
}
void mem_trace_state(const char *label) {
fprintf(stderr, "[TRACE:%s] sp=%d bp=%d loc_cnt=%d call_depth=%d\n",
label, sp, bp, loc_cnt, mem_stats.call_depth);
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef MEMORY_H
#define MEMORY_H
#include "types.h"
typedef struct {
int sp_high_water;
int loc_cnt_high_water;
int call_depth;
int max_call_depth;
int total_allocations;
int total_deallocations;
} MemoryStats;
extern MemoryStats mem_stats;
void mem_init(void);
void mem_dump_stats(void);
int mem_check_sp(int required_sp, const char *context);
int mem_check_addr(int addr, const char *context);
int mem_check_loc_cnt(int required_cnt, const char *context);
long mem_read(int addr, const char *context);
void mem_write(int addr, long value, const char *context);
int mem_push(long value, const char *context);
long mem_pop(const char *context);
void mem_alloc_var(int size, const char *var_name);
void mem_free_frame(int old_sp, int old_loc_cnt, const char *context);
void mem_enter_call(const char *func_name);
void mem_exit_call(const char *func_name);
void mem_trace_state(const char *label);
#endif
+3 -1075
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -3,5 +3,6 @@
void register_native_func(char *name, NativeFunc func);
void register_native_functions();
int create_coroutine(int func_idx, long *args, int argc);
#endif
+394
View File
@@ -0,0 +1,394 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "interpreter.h"
#include "scope.h"
int find_class(char *name, int len) {
if (!name || len <= 0 || len > 31) return -1;
for (int i = 0; i < class_count && i < MAX_CLASSES; i++) {
if (strlen(classes[i].name) == (size_t)len &&
strncmp(classes[i].name, name, len) == 0) {
return i;
}
}
return -1;
}
int find_class_field(int class_idx, char *name, int len) {
if (class_idx < 0 || class_idx >= class_count || class_idx >= MAX_CLASSES) return -1;
if (!name || len <= 0 || len > 31) return -1;
ClassDef *cls = &classes[class_idx];
for (int i = 0; i < cls->field_count && i < MAX_CLASS_FIELDS; i++) {
if (strlen(cls->fields[i].name) == (size_t)len &&
strncmp(cls->fields[i].name, name, len) == 0) {
return i;
}
}
if (cls->parent_class_idx >= 0 && cls->parent_class_idx < class_count) {
return find_class_field(cls->parent_class_idx, name, len);
}
return -1;
}
int find_class_method(int class_idx, char *name, int len) {
if (class_idx < 0 || class_idx >= class_count || class_idx >= MAX_CLASSES) return -1;
if (!name || len <= 0 || len > 31) return -1;
ClassDef *cls = &classes[class_idx];
for (int i = 0; i < cls->method_count && i < MAX_CLASS_METHODS; i++) {
if (strlen(cls->methods[i].name) == (size_t)len &&
strncmp(cls->methods[i].name, name, len) == 0) {
return i;
}
}
if (cls->parent_class_idx >= 0 && cls->parent_class_idx < class_count) {
return find_class_method(cls->parent_class_idx, name, len);
}
return -1;
}
long allocate_object(int class_idx) {
if (class_idx < 0 || class_idx >= class_count || class_idx >= MAX_CLASSES) {
return 0;
}
if (object_count >= MAX_OBJECTS) {
error("Maximum number of objects reached");
return 0;
}
ClassDef *cls = &classes[class_idx];
Object *obj = &objects[object_count];
obj->class_idx = class_idx;
obj->ref_count = 1;
obj->marked_for_deletion = 0;
obj->field_data = (long*)malloc(cls->size * sizeof(long));
if (!obj->field_data) {
error("Failed to allocate object memory");
return 0;
}
for (int i = 0; i < cls->field_count && i < MAX_CLASS_FIELDS; i++) {
obj->field_data[cls->fields[i].offset] = cls->fields[i].default_value;
}
if (cls->parent_class_idx >= 0 && cls->parent_class_idx < class_count) {
ClassDef *parent = &classes[cls->parent_class_idx];
for (int i = 0; i < parent->field_count && i < MAX_CLASS_FIELDS; i++) {
obj->field_data[parent->fields[i].offset] = parent->fields[i].default_value;
}
}
object_count++;
return (long)obj;
}
void call_destructor(long obj_ptr) {
if (obj_ptr == 0) return;
Object *obj = (Object*)obj_ptr;
if (obj < objects || obj >= objects + MAX_OBJECTS) return;
if (obj->marked_for_deletion) return;
obj->marked_for_deletion = 1;
int class_idx = obj->class_idx;
if (class_idx < 0 || class_idx >= class_count || class_idx >= MAX_CLASSES) return;
ClassDef *cls = &classes[class_idx];
for (int i = 0; i < cls->method_count && i < MAX_CLASS_METHODS; i++) {
if (cls->methods[i].is_destructor) {
int func_idx = cls->methods[i].func_idx;
if (func_idx >= 0 && func_idx < func_cnt) {
int saved_pc = pc;
long saved_ax = ax;
int saved_return_flag = return_flag;
scope_push();
int param_base = sp;
if (sp < MEM_SIZE) {
memory[sp++] = obj_ptr;
}
int scan_pc = funcs[func_idx].params_start;
if (scan_pc < MAX_TOK && scan_pc < tk_idx && tokens[scan_pc].type != ')') {
if (tokens[scan_pc].type == Id) {
Token *param_name = &tokens[scan_pc];
if (loc_cnt < VAR_MAX) {
Symbol *sym = &locals[loc_cnt++];
int name_len = param_name->val;
if (name_len > 31) name_len = 31;
strncpy(sym->name, param_name->text, name_len);
sym->name[name_len] = 0;
sym->type = Int;
sym->addr = param_base;
sym->is_array = 0;
}
}
}
pc = funcs[func_idx].entry_point;
return_flag = 0;
ax = 0;
statement();
scope_pop();
pc = saved_pc;
ax = saved_ax;
return_flag = saved_return_flag;
}
break;
}
}
}
void free_object(long obj_ptr) {
if (obj_ptr == 0) return;
Object *obj = (Object*)obj_ptr;
if (obj < objects || obj >= objects + MAX_OBJECTS) return;
call_destructor(obj_ptr);
if (obj->field_data) {
free(obj->field_data);
obj->field_data = NULL;
}
obj->class_idx = -1;
obj->ref_count = 0;
obj->marked_for_deletion = 0;
}
void link_class_methods() {
for (int c = 0; c < class_count && c < MAX_CLASSES; c++) {
ClassDef *cls = &classes[c];
for (int m = 0; m < cls->method_count && m < MAX_CLASS_METHODS; m++) {
ClassMethod *method = &cls->methods[m];
char full_name[64];
snprintf(full_name, 63, "%s_%s", cls->name, method->name);
extern int find_func(char *name, int len);
int func_idx = find_func(full_name, strlen(full_name));
if (func_idx >= 0) {
method->func_idx = func_idx;
}
}
}
}
void scan_classes() {
int i = 0;
while (i < MAX_TOK && i < tk_idx && tokens[i].type != 0) {
if (tokens[i].type == Class) {
i++;
if (i >= MAX_TOK || i >= tk_idx || tokens[i].type != Id) {
error("Expected class name");
return;
}
if (class_count >= MAX_CLASSES) {
error("Too many classes defined");
return;
}
ClassDef *cls = &classes[class_count];
Token *name = &tokens[i];
int name_len = name->val;
if (name_len > 31) name_len = 31;
strncpy(cls->name, name->text, name_len);
cls->name[name_len] = 0;
cls->parent_class_idx = -1;
cls->field_count = 0;
cls->method_count = 0;
cls->size = 0;
cls->token_start = i + 1;
i++;
if (i < MAX_TOK && i < tk_idx && tokens[i].type == ':') {
i++;
if (i >= MAX_TOK || i >= tk_idx || tokens[i].type != Id) {
error("Expected parent class name");
return;
}
Token *parent_name = &tokens[i];
int parent_idx = find_class(parent_name->text, parent_name->val);
if (parent_idx < 0) {
error("Parent class not found");
return;
}
cls->parent_class_idx = parent_idx;
i++;
}
if (i >= MAX_TOK || i >= tk_idx || tokens[i].type != '{') {
error("Expected '{' after class name");
return;
}
i++;
int field_offset = 0;
if (cls->parent_class_idx >= 0) {
field_offset = classes[cls->parent_class_idx].size;
}
while (i < MAX_TOK && i < tk_idx && tokens[i].type != '}') {
int is_static = 0;
if (tokens[i].type == Static) {
is_static = 1;
i++;
}
if (tokens[i].type == Constructor || tokens[i].type == Destructor) {
int is_constructor = (tokens[i].type == Constructor);
int is_destructor = (tokens[i].type == Destructor);
i++;
if (i >= MAX_TOK || i >= tk_idx || tokens[i].type != '(') {
error("Expected '(' after constructor/destructor");
return;
}
int func_start = i - 1;
int brace_count = 0;
while (i < MAX_TOK && i < tk_idx) {
if (tokens[i].type == '{') brace_count++;
if (tokens[i].type == '}') {
brace_count--;
if (brace_count == 0) {
i++;
break;
}
}
i++;
}
if (cls->method_count < MAX_CLASS_METHODS) {
ClassMethod *method = &cls->methods[cls->method_count];
if (is_constructor) {
strncpy(method->name, "constructor", 31);
} else {
strncpy(method->name, "destructor", 31);
}
method->func_idx = -1;
method->is_static = 0;
method->is_constructor = is_constructor;
method->is_destructor = is_destructor;
cls->method_count++;
}
continue;
}
int type = tokens[i].type;
if (type != Int && type != Char && type != Double && type != Void) {
int class_type_idx = find_class(tokens[i].text, tokens[i].val);
if (class_type_idx >= 0) {
type = Class;
} else {
i++;
continue;
}
}
i++;
while (i < MAX_TOK && i < tk_idx && tokens[i].type == '*') i++;
if (i >= MAX_TOK || i >= tk_idx || tokens[i].type != Id) {
i++;
continue;
}
Token *member_name = &tokens[i];
i++;
if (i < MAX_TOK && i < tk_idx && tokens[i].type == '(') {
if (cls->method_count < MAX_CLASS_METHODS) {
ClassMethod *method = &cls->methods[cls->method_count];
int name_len = member_name->val;
if (name_len > 31) name_len = 31;
strncpy(method->name, member_name->text, name_len);
method->name[name_len] = 0;
method->func_idx = -1;
method->is_static = is_static;
method->is_constructor = 0;
method->is_destructor = 0;
cls->method_count++;
}
int brace_count = 0;
while (i < MAX_TOK && i < tk_idx) {
if (tokens[i].type == '{') brace_count++;
if (tokens[i].type == '}') {
brace_count--;
if (brace_count == 0) {
i++;
break;
}
}
i++;
}
} else {
if (cls->field_count < MAX_CLASS_FIELDS) {
ClassField *field = &cls->fields[cls->field_count];
int name_len = member_name->val;
if (name_len > 31) name_len = 31;
strncpy(field->name, member_name->text, name_len);
field->name[name_len] = 0;
field->type = type;
field->default_value = 0;
field->offset = field_offset++;
if (i < MAX_TOK && i < tk_idx && tokens[i].type == '=') {
i++;
if (i < MAX_TOK && i < tk_idx) {
if (tokens[i].type == Num) {
field->default_value = tokens[i].val;
i++;
} else if (tokens[i].type == Null) {
field->default_value = 0;
i++;
}
}
}
cls->field_count++;
}
if (i < MAX_TOK && i < tk_idx && tokens[i].type == ';') {
i++;
}
}
}
cls->size = field_offset;
if (i < MAX_TOK && i < tk_idx && tokens[i].type == '}') {
i++;
}
class_count++;
} else {
i++;
}
}
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef OOP_H
#define OOP_H
int find_class(char *name, int len);
int find_class_field(int class_idx, char *name, int len);
int find_class_method(int class_idx, char *name, int len);
long allocate_object(int class_idx);
void free_object(long obj_ptr);
void call_destructor(long obj_ptr);
void scan_classes();
void link_class_methods();
#endif
+339 -36
View File
@@ -5,6 +5,10 @@
#include "parser.h"
#include "interpreter.h"
#include "string_utils.h"
#include "error.h"
#include "debug.h"
#include "memory.h"
#include "scope.h"
extern Token tokens[];
extern int pc;
@@ -18,6 +22,7 @@ extern int func_cnt;
extern NativeFuncDef native_funcs[];
extern int native_func_cnt;
extern long ax;
extern CallStack call_stack;
extern void error(char *msg);
extern void match(int type);
@@ -31,7 +36,70 @@ long factor() {
Token *t = &tokens[pc];
long val = 0;
if (t->type == Num) {
if (t->type == Null) {
pc++;
return 0;
}
else if (t->type == This) {
pc++;
Symbol *sym = find_local("this", 4) >= 0 ? &locals[find_local("this", 4)] : NULL;
if (sym) {
return memory[sym->addr];
}
return 0;
}
else if (t->type == New) {
pc++;
if (pc >= MAX_TOK || tokens[pc].type != Id) {
error("Expected class name after 'new'");
return 0;
}
Token *class_name = &tokens[pc];
pc++;
extern int find_class(char *name, int len);
int class_idx = find_class(class_name->text, class_name->val);
if (class_idx < 0) {
error("Unknown class");
return 0;
}
if (pc >= MAX_TOK || tokens[pc].type != '(') {
error("Expected '(' after class name");
return 0;
}
pc++;
if (pc < MAX_TOK && tokens[pc].type != ')') {
do {
expression();
if (pc >= MAX_TOK) return 0;
} while (tokens[pc].type == ',' && pc++);
}
match(')');
extern long allocate_object(int class_idx);
long obj_ptr = allocate_object(class_idx);
if (obj_ptr == 0) {
error("Failed to allocate object");
return 0;
}
return obj_ptr;
}
else if (t->type == Await) {
pc++;
match('(');
long coro_id = expression();
match(')');
extern long native_await(long*, int);
long args[1];
args[0] = coro_id;
return native_await(args, 1);
}
else if (t->type == Num) {
pc++;
return t->val;
}
@@ -72,7 +140,17 @@ long factor() {
}
match(')');
return native_funcs[nf_idx].func(args, argc);
const char *native_filename = NULL;
int native_line = 0;
if (pc < tk_idx && pc >= 0) {
native_filename = tokens[pc].filename;
native_line = tokens[pc].line;
}
push_call_frame(native_funcs[nf_idx].name, native_filename, native_line, 1);
long result = native_funcs[nf_idx].func(args, argc);
pop_call_frame();
return result;
}
int f_idx = find_func(t->text, t->val);
@@ -94,21 +172,26 @@ long factor() {
}
match(')');
int ret_pc = pc;
int old_loc_cnt = loc_cnt;
int old_bp = bp;
if (funcs[f_idx].is_async) {
extern int create_coroutine(int func_idx, long *args, int argc);
return create_coroutine(f_idx, args, argc);
}
if (sp >= MEM_SIZE) return 0;
if (bp < 0 || bp >= MEM_SIZE) return 0;
memory[sp] = bp; bp = sp++;
if (sp >= MEM_SIZE) return 0;
memory[sp++] = ret_pc;
memory[sp++] = old_loc_cnt;
int ret_pc = pc;
int saved_return_flag = return_flag;
mem_enter_call(funcs[f_idx].name);
scope_push();
char call_ctx[128];
snprintf(call_ctx, sizeof(call_ctx), "call %s: push frame", funcs[f_idx].name);
int param_base = sp;
for(int i=0; i<argc; i++) {
if (sp >= MEM_SIZE) break;
memory[sp++] = args[i];
if (sp < MEM_SIZE) {
memory[sp++] = args[i];
}
}
int scan_pc = funcs[f_idx].params_start;
@@ -117,22 +200,32 @@ long factor() {
if (tokens[scan_pc].type == Int || tokens[scan_pc].type == Char || tokens[scan_pc].type == Double) {
scan_pc++;
while (scan_pc < MAX_TOK && tokens[scan_pc].type == '*') scan_pc++;
if (scan_pc < MAX_TOK && tokens[scan_pc].type == Id && param_idx < argc && loc_cnt < VAR_MAX) {
Token *param_name = &tokens[scan_pc];
Symbol *sym = &locals[loc_cnt++];
int name_len = param_name->val;
if (name_len > 31) name_len = 31;
strncpy(sym->name, param_name->text, name_len);
sym->name[name_len] = 0;
sym->type = Int;
sym->addr = param_base + param_idx;
sym->is_array = 0;
param_idx++;
if (scan_pc < MAX_TOK && tokens[scan_pc].type == Id && param_idx < argc) {
if (loc_cnt < VAR_MAX) {
Token *param_name = &tokens[scan_pc];
Symbol *sym = &locals[loc_cnt++];
int name_len = param_name->val;
if (name_len > 31) name_len = 31;
strncpy(sym->name, param_name->text, name_len);
sym->name[name_len] = 0;
sym->type = Int;
sym->addr = param_base + param_idx;
sym->is_array = 0;
param_idx++;
}
}
}
scan_pc++;
}
const char *func_filename = NULL;
int func_line = 0;
if (funcs[f_idx].entry_point < tk_idx) {
func_filename = tokens[funcs[f_idx].entry_point].filename;
func_line = tokens[funcs[f_idx].entry_point].line;
}
push_call_frame(funcs[f_idx].name, func_filename, func_line, 0);
pc = funcs[f_idx].entry_point;
return_flag = 0;
statement();
@@ -141,13 +234,13 @@ long factor() {
ax = 0;
return_flag = 0;
loc_cnt = old_loc_cnt;
if (bp < 0 || bp >= MEM_SIZE) return 0;
sp = bp;
if (sp < 0 || sp >= MEM_SIZE) return 0;
bp = memory[sp];
if (sp + 1 < MEM_SIZE) ret_pc = memory[sp + 1];
pop_call_frame();
mem_exit_call(funcs[f_idx].name);
scope_pop();
pc = ret_pc;
return_flag = saved_return_flag;
return val;
}
else {
@@ -158,6 +251,11 @@ long factor() {
Symbol *sym = &locals[idx];
if (sym->addr < 0 || sym->addr >= MEM_SIZE) {
error("Invalid variable memory address");
return 0;
}
if (pc < MAX_TOK && (tokens[pc].type == Inc || tokens[pc].type == Dec)) {
long val = memory[sym->addr];
if (tokens[pc].type == Inc) {
@@ -210,12 +308,18 @@ long unary() {
if (pc >= MAX_TOK) return 0;
if (tokens[pc].type == Inc || tokens[pc].type == Dec) {
int op = tokens[pc++].type;
if (pc >= MAX_TOK) return 0;
Token *t = &tokens[pc];
if (t->type != Id) error("Expected identifier after ++/--");
int idx = find_local(t->text, t->val);
if (idx == -1) error("Undefined variable");
if (idx < 0 || idx >= VAR_MAX) return 0;
pc++;
long addr = locals[idx].addr;
if (addr < 0 || addr >= MEM_SIZE) {
error("Invalid memory address in increment/decrement");
return 0;
}
if (op == Inc) {
memory[addr]++;
} else {
@@ -225,11 +329,30 @@ long unary() {
}
if (tokens[pc].type == '*') {
pc++;
int addr = unary();
if (addr > MEM_SIZE * 8 || addr < 0) {
return *(char*)addr;
long addr = unary();
DEBUG_LONG("dereference_addr", addr);
if (addr < 0 || addr >= MEM_SIZE) {
if (addr < 0) {
DEBUG_LOG("ERROR: Negative memory address: %ld", addr);
error("Invalid memory address (negative)");
return 0;
}
if (addr > MEM_SIZE * 8) {
char *ptr = (char*)addr;
DEBUG_PTR("external_ptr", ptr);
if (ptr == NULL) {
DEBUG_LOG("ERROR: Null pointer dereference");
error("Null pointer dereference");
return 0;
}
DEBUG_LOG("Dereferencing external pointer: %p", (void*)ptr);
return *ptr;
}
DEBUG_LOG("ERROR: Memory access out of bounds: %ld (max: %d)", addr, MEM_SIZE);
error("Memory access out of bounds");
return 0;
}
if (addr < 0 || addr >= MEM_SIZE) return 0;
DEBUG_MEMORY_ACCESS(addr, "READ");
return memory[addr];
}
else if (tokens[pc].type == '&') {
@@ -247,7 +370,129 @@ long unary() {
pc++;
return -unary();
}
return factor();
long val = factor();
while (pc < MAX_TOK && tokens[pc].type == '.') {
pc++;
if (pc >= MAX_TOK || tokens[pc].type != Id) {
error("Expected field or method name after '.'");
return 0;
}
Token *member = &tokens[pc];
pc++;
if (val == 0) {
error("Null pointer dereference");
return 0;
}
Object *obj = (Object*)val;
if (obj < objects || obj >= objects + MAX_OBJECTS) {
error("Invalid object pointer");
return 0;
}
int class_idx = obj->class_idx;
if (class_idx < 0 || class_idx >= class_count) {
error("Invalid class index");
return 0;
}
if (pc < MAX_TOK && tokens[pc].type == '(') {
extern int find_class_method(int class_idx, char *name, int len);
int method_idx = find_class_method(class_idx, member->text, member->val);
if (method_idx < 0) {
error("Unknown method");
return 0;
}
int func_idx = classes[class_idx].methods[method_idx].func_idx;
if (func_idx < 0 || func_idx >= func_cnt) {
error("Invalid method function index");
return 0;
}
pc++;
long args[10];
int argc = 0;
args[argc++] = val;
if (pc < MAX_TOK && tokens[pc].type != ')') {
do {
if (argc >= 10) break;
args[argc++] = expression();
if (pc >= MAX_TOK) return 0;
} while (tokens[pc].type == ',' && pc++);
}
match(')');
int saved_pc = pc;
int saved_return_flag = return_flag;
scope_push();
int param_base = sp;
for (int i = 0; i < argc && i < 10; i++) {
if (sp < MEM_SIZE) {
memory[sp++] = args[i];
}
}
int scan_pc = funcs[func_idx].params_start;
int param_idx = 0;
while (scan_pc < MAX_TOK && scan_pc < tk_idx && tokens[scan_pc].type != ')') {
if (tokens[scan_pc].type == Int || tokens[scan_pc].type == Char ||
tokens[scan_pc].type == Double || tokens[scan_pc].type == Id) {
scan_pc++;
while (scan_pc < MAX_TOK && tokens[scan_pc].type == '*') scan_pc++;
if (scan_pc < MAX_TOK && tokens[scan_pc].type == Id && param_idx < argc && loc_cnt < VAR_MAX) {
Token *param_name = &tokens[scan_pc];
Symbol *sym = &locals[loc_cnt++];
int name_len = param_name->val;
if (name_len > 31) name_len = 31;
strncpy(sym->name, param_name->text, name_len);
sym->name[name_len] = 0;
sym->type = Int;
sym->addr = param_base + param_idx;
sym->is_array = 0;
param_idx++;
}
}
scan_pc++;
}
pc = funcs[func_idx].entry_point;
return_flag = 0;
statement();
val = ax;
ax = 0;
return_flag = 0;
scope_pop();
pc = saved_pc;
return_flag = saved_return_flag;
} else {
extern int find_class_field(int class_idx, char *name, int len);
int field_idx = find_class_field(class_idx, member->text, member->val);
if (field_idx < 0) {
error("Unknown field");
return 0;
}
int offset = classes[class_idx].fields[field_idx].offset;
if (offset < 0 || offset >= classes[class_idx].size) {
error("Invalid field offset");
return 0;
}
val = obj->field_data[offset];
}
}
return val;
}
long term() {
@@ -291,6 +536,8 @@ long relational() {
if (op == Ne) val = val != val2;
if (op == Lt) val = val < val2;
if (op == Gt) val = val > val2;
if (op == Le) val = val <= val2;
if (op == Ge) val = val >= val2;
}
return val;
}
@@ -336,7 +583,63 @@ long expression() {
if (pc >= MAX_TOK) return 0;
if (tokens[pc].type == Id) {
if (pc + 1 >= MAX_TOK) return 0;
if (tokens[pc+1].type == '[') {
if (tokens[pc+1].type == '.') {
int save_pc = pc;
int temp_pc = pc + 1;
if (temp_pc < MAX_TOK && tokens[temp_pc].type == '.') {
temp_pc++;
if (temp_pc < MAX_TOK && tokens[temp_pc].type == Id) {
temp_pc++;
if (temp_pc < MAX_TOK && tokens[temp_pc].type == '=') {
int idx = find_local(tokens[pc].text, tokens[pc].val);
if (idx == -1) error("Unknown object variable");
if (idx < 0 || idx >= loc_cnt) return 0;
long obj_ptr = memory[locals[idx].addr];
if (obj_ptr == 0) {
error("Null pointer dereference in assignment");
return 0;
}
Object *obj = (Object*)obj_ptr;
if (obj < objects || obj >= objects + MAX_OBJECTS) {
error("Invalid object pointer in assignment");
return 0;
}
pc++;
match('.');
if (pc >= MAX_TOK || tokens[pc].type != Id) {
error("Expected field name after '.'");
return 0;
}
Token *field_name = &tokens[pc];
pc++;
match('=');
int class_idx = obj->class_idx;
if (class_idx < 0 || class_idx >= class_count) {
error("Invalid class index");
return 0;
}
extern int find_class_field(int class_idx, char *name, int len);
int field_idx = find_class_field(class_idx, field_name->text, field_name->val);
if (field_idx < 0) {
error("Unknown field");
return 0;
}
int offset = classes[class_idx].fields[field_idx].offset;
if (offset < 0 || offset >= classes[class_idx].size) {
error("Invalid field offset");
return 0;
}
long val = expression();
obj->field_data[offset] = val;
return val;
}
}
}
} else if (tokens[pc+1].type == '[') {
int idx = find_local(tokens[pc].text, tokens[pc].val);
if (idx == -1) error("Assign to unknown var");
if (idx < 0 || idx >= loc_cnt) return 0;
+596
View File
@@ -0,0 +1,596 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "runtime.h"
Runtime *global_runtime = NULL;
#define INITIAL_TOKEN_CAPACITY 1024
#define INITIAL_MEMORY_CAPACITY 10000
#define INITIAL_SYMBOL_CAPACITY 128
#define INITIAL_FUNC_CAPACITY 32
#define INITIAL_CLASS_CAPACITY 16
#define INITIAL_OBJECT_CAPACITY 256
#define INITIAL_COROUTINE_CAPACITY 16
#define INITIAL_STRING_POOL_CAPACITY 65536
#define INITIAL_CALL_STACK_CAPACITY 128
Runtime* runtime_create() {
Runtime *rt = (Runtime*)calloc(1, sizeof(Runtime));
if (!rt) return NULL;
if (!token_array_init(&rt->tokens)) goto fail;
if (!memory_init(&rt->memory)) goto fail;
if (!symbol_table_init(&rt->symbols)) goto fail;
if (!func_table_init(&rt->funcs)) goto fail;
if (!native_func_table_init(&rt->native_funcs)) goto fail;
if (!class_table_init(&rt->classes)) goto fail;
if (!object_table_init(&rt->objects)) goto fail;
if (!coroutine_table_init(&rt->coroutines)) goto fail;
if (!string_pool_init(&rt->str_pool)) goto fail;
if (!call_stack_init(&rt->call_stack)) goto fail;
pthread_mutex_init(&rt->state_lock, NULL);
rt->pc = 0;
rt->sp = 0;
rt->bp = 0;
rt->ax = 0;
rt->return_flag = 0;
return rt;
fail:
runtime_destroy(rt);
return NULL;
}
void runtime_destroy(Runtime *rt) {
if (!rt) return;
token_array_destroy(&rt->tokens);
memory_destroy(&rt->memory);
symbol_table_destroy(&rt->symbols);
func_table_destroy(&rt->funcs);
native_func_table_destroy(&rt->native_funcs);
class_table_destroy(&rt->classes);
object_table_destroy(&rt->objects);
coroutine_table_destroy(&rt->coroutines);
string_pool_destroy(&rt->str_pool);
call_stack_destroy(&rt->call_stack);
pthread_mutex_destroy(&rt->state_lock);
free(rt);
}
int token_array_init(TokenArray *arr) {
arr->tokens = (Token*)calloc(INITIAL_TOKEN_CAPACITY, sizeof(Token));
if (!arr->tokens) return 0;
arr->count = 0;
arr->capacity = INITIAL_TOKEN_CAPACITY;
pthread_rwlock_init(&arr->lock, NULL);
return 1;
}
void token_array_destroy(TokenArray *arr) {
if (arr->tokens) {
free(arr->tokens);
arr->tokens = NULL;
}
pthread_rwlock_destroy(&arr->lock);
}
int token_array_ensure_capacity(TokenArray *arr, int min_capacity) {
if (arr->capacity >= min_capacity) return 1;
int new_capacity = arr->capacity * 2;
if (new_capacity < min_capacity) new_capacity = min_capacity;
Token *new_tokens = (Token*)realloc(arr->tokens, new_capacity * sizeof(Token));
if (!new_tokens) return 0;
memset(new_tokens + arr->capacity, 0, (new_capacity - arr->capacity) * sizeof(Token));
arr->tokens = new_tokens;
arr->capacity = new_capacity;
return 1;
}
int token_array_add(TokenArray *arr, Token token) {
pthread_rwlock_wrlock(&arr->lock);
if (!token_array_ensure_capacity(arr, arr->count + 1)) {
pthread_rwlock_unlock(&arr->lock);
return -1;
}
arr->tokens[arr->count] = token;
int index = arr->count;
arr->count++;
pthread_rwlock_unlock(&arr->lock);
return index;
}
int memory_init(Memory *mem) {
mem->data = (long*)calloc(INITIAL_MEMORY_CAPACITY, sizeof(long));
if (!mem->data) return 0;
mem->size = INITIAL_MEMORY_CAPACITY;
mem->capacity = INITIAL_MEMORY_CAPACITY;
pthread_mutex_init(&mem->lock, NULL);
return 1;
}
void memory_destroy(Memory *mem) {
if (mem->data) {
free(mem->data);
mem->data = NULL;
}
pthread_mutex_destroy(&mem->lock);
}
int memory_ensure_capacity(Memory *mem, int min_size) {
if (mem->capacity >= min_size) {
if (mem->size < min_size) mem->size = min_size;
return 1;
}
int new_capacity = mem->capacity * 2;
if (new_capacity < min_size) new_capacity = min_size;
long *new_data = (long*)realloc(mem->data, new_capacity * sizeof(long));
if (!new_data) return 0;
memset(new_data + mem->capacity, 0, (new_capacity - mem->capacity) * sizeof(long));
mem->data = new_data;
mem->capacity = new_capacity;
mem->size = min_size;
return 1;
}
long memory_get(Memory *mem, int addr) {
if (addr < 0 || addr >= mem->size) return 0;
return mem->data[addr];
}
void memory_set(Memory *mem, int addr, long value) {
pthread_mutex_lock(&mem->lock);
if (memory_ensure_capacity(mem, addr + 1)) {
mem->data[addr] = value;
}
pthread_mutex_unlock(&mem->lock);
}
int symbol_table_init(SymbolTable *tbl) {
tbl->data = (Symbol*)calloc(INITIAL_SYMBOL_CAPACITY, sizeof(Symbol));
if (!tbl->data) return 0;
tbl->count = 0;
tbl->capacity = INITIAL_SYMBOL_CAPACITY;
pthread_mutex_init(&tbl->lock, NULL);
return 1;
}
void symbol_table_destroy(SymbolTable *tbl) {
if (tbl->data) {
for (int i = 0; i < tbl->count; i++) {
if (tbl->data[i].name) free(tbl->data[i].name);
}
free(tbl->data);
tbl->data = NULL;
}
pthread_mutex_destroy(&tbl->lock);
}
int symbol_table_ensure_capacity(SymbolTable *tbl, int min_capacity) {
if (tbl->capacity >= min_capacity) return 1;
int new_capacity = tbl->capacity * 2;
if (new_capacity < min_capacity) new_capacity = min_capacity;
Symbol *new_data = (Symbol*)realloc(tbl->data, new_capacity * sizeof(Symbol));
if (!new_data) return 0;
memset(new_data + tbl->capacity, 0, (new_capacity - tbl->capacity) * sizeof(Symbol));
tbl->data = new_data;
tbl->capacity = new_capacity;
return 1;
}
int symbol_table_add(SymbolTable *tbl, Symbol symbol) {
pthread_mutex_lock(&tbl->lock);
if (!symbol_table_ensure_capacity(tbl, tbl->count + 1)) {
pthread_mutex_unlock(&tbl->lock);
return -1;
}
tbl->data[tbl->count] = symbol;
int index = tbl->count;
tbl->count++;
pthread_mutex_unlock(&tbl->lock);
return index;
}
int func_table_init(FuncTable *tbl) {
tbl->data = (Func*)calloc(INITIAL_FUNC_CAPACITY, sizeof(Func));
if (!tbl->data) return 0;
tbl->count = 0;
tbl->capacity = INITIAL_FUNC_CAPACITY;
pthread_rwlock_init(&tbl->lock, NULL);
return 1;
}
void func_table_destroy(FuncTable *tbl) {
if (tbl->data) {
for (int i = 0; i < tbl->count; i++) {
if (tbl->data[i].name) free(tbl->data[i].name);
}
free(tbl->data);
tbl->data = NULL;
}
pthread_rwlock_destroy(&tbl->lock);
}
int func_table_ensure_capacity(FuncTable *tbl, int min_capacity) {
if (tbl->capacity >= min_capacity) return 1;
int new_capacity = tbl->capacity * 2;
if (new_capacity < min_capacity) new_capacity = min_capacity;
Func *new_data = (Func*)realloc(tbl->data, new_capacity * sizeof(Func));
if (!new_data) return 0;
memset(new_data + tbl->capacity, 0, (new_capacity - tbl->capacity) * sizeof(Func));
tbl->data = new_data;
tbl->capacity = new_capacity;
return 1;
}
int func_table_add(FuncTable *tbl, Func func) {
pthread_rwlock_wrlock(&tbl->lock);
if (!func_table_ensure_capacity(tbl, tbl->count + 1)) {
pthread_rwlock_unlock(&tbl->lock);
return -1;
}
tbl->data[tbl->count] = func;
int index = tbl->count;
tbl->count++;
pthread_rwlock_unlock(&tbl->lock);
return index;
}
int func_table_find(FuncTable *tbl, const char *name, int len) {
pthread_rwlock_rdlock(&tbl->lock);
for (int i = 0; i < tbl->count; i++) {
if (tbl->data[i].name && !strncmp(tbl->data[i].name, name, len) &&
tbl->data[i].name[len] == 0) {
pthread_rwlock_unlock(&tbl->lock);
return i;
}
}
pthread_rwlock_unlock(&tbl->lock);
return -1;
}
int native_func_table_init(NativeFuncTable *tbl) {
tbl->data = (NativeFuncDef*)calloc(INITIAL_FUNC_CAPACITY, sizeof(NativeFuncDef));
if (!tbl->data) return 0;
tbl->count = 0;
tbl->capacity = INITIAL_FUNC_CAPACITY;
pthread_rwlock_init(&tbl->lock, NULL);
return 1;
}
void native_func_table_destroy(NativeFuncTable *tbl) {
if (tbl->data) {
for (int i = 0; i < tbl->count; i++) {
if (tbl->data[i].name) free(tbl->data[i].name);
}
free(tbl->data);
tbl->data = NULL;
}
pthread_rwlock_destroy(&tbl->lock);
}
int native_func_table_add(NativeFuncTable *tbl, const char *name, NativeFunc func) {
pthread_rwlock_wrlock(&tbl->lock);
if (tbl->count >= tbl->capacity) {
int new_capacity = tbl->capacity * 2;
NativeFuncDef *new_data = (NativeFuncDef*)realloc(tbl->data,
new_capacity * sizeof(NativeFuncDef));
if (!new_data) {
pthread_rwlock_unlock(&tbl->lock);
return -1;
}
memset(new_data + tbl->capacity, 0, (new_capacity - tbl->capacity) * sizeof(NativeFuncDef));
tbl->data = new_data;
tbl->capacity = new_capacity;
}
tbl->data[tbl->count].name = strdup(name);
tbl->data[tbl->count].func = func;
int index = tbl->count;
tbl->count++;
pthread_rwlock_unlock(&tbl->lock);
return index;
}
int native_func_table_find(NativeFuncTable *tbl, const char *name, int len) {
pthread_rwlock_rdlock(&tbl->lock);
for (int i = 0; i < tbl->count; i++) {
if (tbl->data[i].name && !strncmp(tbl->data[i].name, name, len) &&
tbl->data[i].name[len] == 0) {
pthread_rwlock_unlock(&tbl->lock);
return i;
}
}
pthread_rwlock_unlock(&tbl->lock);
return -1;
}
int class_table_init(ClassTable *tbl) {
tbl->data = (ClassDef*)calloc(INITIAL_CLASS_CAPACITY, sizeof(ClassDef));
if (!tbl->data) return 0;
tbl->count = 0;
tbl->capacity = INITIAL_CLASS_CAPACITY;
pthread_rwlock_init(&tbl->lock, NULL);
return 1;
}
void class_table_destroy(ClassTable *tbl) {
if (tbl->data) {
for (int i = 0; i < tbl->count; i++) {
if (tbl->data[i].name) free(tbl->data[i].name);
if (tbl->data[i].fields) {
for (int j = 0; j < tbl->data[i].field_count; j++) {
if (tbl->data[i].fields[j].name) free(tbl->data[i].fields[j].name);
}
free(tbl->data[i].fields);
}
if (tbl->data[i].methods) {
for (int j = 0; j < tbl->data[i].method_count; j++) {
if (tbl->data[i].methods[j].name) free(tbl->data[i].methods[j].name);
}
free(tbl->data[i].methods);
}
}
free(tbl->data);
tbl->data = NULL;
}
pthread_rwlock_destroy(&tbl->lock);
}
int class_table_add(ClassTable *tbl, ClassDef class_def) {
pthread_rwlock_wrlock(&tbl->lock);
if (tbl->count >= tbl->capacity) {
int new_capacity = tbl->capacity * 2;
ClassDef *new_data = (ClassDef*)realloc(tbl->data, new_capacity * sizeof(ClassDef));
if (!new_data) {
pthread_rwlock_unlock(&tbl->lock);
return -1;
}
memset(new_data + tbl->capacity, 0, (new_capacity - tbl->capacity) * sizeof(ClassDef));
tbl->data = new_data;
tbl->capacity = new_capacity;
}
tbl->data[tbl->count] = class_def;
int index = tbl->count;
tbl->count++;
pthread_rwlock_unlock(&tbl->lock);
return index;
}
int class_table_find(ClassTable *tbl, const char *name, int len) {
pthread_rwlock_rdlock(&tbl->lock);
for (int i = 0; i < tbl->count; i++) {
if (tbl->data[i].name && !strncmp(tbl->data[i].name, name, len) &&
tbl->data[i].name[len] == 0) {
pthread_rwlock_unlock(&tbl->lock);
return i;
}
}
pthread_rwlock_unlock(&tbl->lock);
return -1;
}
int object_table_init(ObjectTable *tbl) {
tbl->data = (Object*)calloc(INITIAL_OBJECT_CAPACITY, sizeof(Object));
if (!tbl->data) return 0;
tbl->count = 0;
tbl->capacity = INITIAL_OBJECT_CAPACITY;
pthread_mutex_init(&tbl->lock, NULL);
return 1;
}
void object_table_destroy(ObjectTable *tbl) {
if (tbl->data) {
for (int i = 0; i < tbl->count; i++) {
if (tbl->data[i].field_data) free(tbl->data[i].field_data);
}
free(tbl->data);
tbl->data = NULL;
}
pthread_mutex_destroy(&tbl->lock);
}
int object_table_add(ObjectTable *tbl, Object obj) {
pthread_mutex_lock(&tbl->lock);
if (tbl->count >= tbl->capacity) {
int new_capacity = tbl->capacity * 2;
Object *new_data = (Object*)realloc(tbl->data, new_capacity * sizeof(Object));
if (!new_data) {
pthread_mutex_unlock(&tbl->lock);
return -1;
}
memset(new_data + tbl->capacity, 0, (new_capacity - tbl->capacity) * sizeof(Object));
tbl->data = new_data;
tbl->capacity = new_capacity;
}
tbl->data[tbl->count] = obj;
int index = tbl->count;
tbl->count++;
pthread_mutex_unlock(&tbl->lock);
return index;
}
int coroutine_table_init(CoroutineTable *tbl) {
tbl->data = (Coroutine*)calloc(INITIAL_COROUTINE_CAPACITY, sizeof(Coroutine));
if (!tbl->data) return 0;
tbl->count = 0;
tbl->capacity = INITIAL_COROUTINE_CAPACITY;
pthread_mutex_init(&tbl->lock, NULL);
return 1;
}
void coroutine_table_destroy(CoroutineTable *tbl) {
if (tbl->data) {
for (int i = 0; i < tbl->count; i++) {
if (tbl->data[i].args) free(tbl->data[i].args);
if (tbl->data[i].locals_saved) {
for (int j = 0; j < tbl->data[i].loc_cnt_saved; j++) {
if (tbl->data[i].locals_saved[j].name) {
free(tbl->data[i].locals_saved[j].name);
}
}
free(tbl->data[i].locals_saved);
}
if (tbl->data[i].memory_saved) free(tbl->data[i].memory_saved);
}
free(tbl->data);
tbl->data = NULL;
}
pthread_mutex_destroy(&tbl->lock);
}
int coroutine_table_alloc(CoroutineTable *tbl) {
pthread_mutex_lock(&tbl->lock);
for (int i = 0; i < tbl->count; i++) {
if (!tbl->data[i].active) {
tbl->data[i].active = 1;
tbl->data[i].complete = 0;
pthread_mutex_unlock(&tbl->lock);
return i;
}
}
if (tbl->count >= tbl->capacity) {
int new_capacity = tbl->capacity * 2;
Coroutine *new_data = (Coroutine*)realloc(tbl->data, new_capacity * sizeof(Coroutine));
if (!new_data) {
pthread_mutex_unlock(&tbl->lock);
return -1;
}
memset(new_data + tbl->capacity, 0, (new_capacity - tbl->capacity) * sizeof(Coroutine));
tbl->data = new_data;
tbl->capacity = new_capacity;
}
int index = tbl->count;
tbl->data[index].active = 1;
tbl->data[index].complete = 0;
tbl->count++;
pthread_mutex_unlock(&tbl->lock);
return index;
}
int string_pool_init(StringPool *pool) {
pool->data = (char*)malloc(INITIAL_STRING_POOL_CAPACITY);
if (!pool->data) return 0;
pool->size = 0;
pool->capacity = INITIAL_STRING_POOL_CAPACITY;
pthread_mutex_init(&pool->lock, NULL);
return 1;
}
void string_pool_destroy(StringPool *pool) {
if (pool->data) {
free(pool->data);
pool->data = NULL;
}
pthread_mutex_destroy(&pool->lock);
}
char* string_pool_add(StringPool *pool, const char *str, size_t len) {
pthread_mutex_lock(&pool->lock);
if (pool->size + len + 1 > pool->capacity) {
size_t new_capacity = pool->capacity * 2;
while (new_capacity < pool->size + len + 1) new_capacity *= 2;
char *new_data = (char*)realloc(pool->data, new_capacity);
if (!new_data) {
pthread_mutex_unlock(&pool->lock);
return NULL;
}
pool->data = new_data;
pool->capacity = new_capacity;
}
char *result = pool->data + pool->size;
memcpy(result, str, len);
result[len] = '\0';
pool->size += len + 1;
pthread_mutex_unlock(&pool->lock);
return result;
}
int call_stack_init(CallStack *stack) {
stack->frames = (CallStackFrame*)calloc(INITIAL_CALL_STACK_CAPACITY, sizeof(CallStackFrame));
if (!stack->frames) return 0;
stack->depth = 0;
stack->capacity = INITIAL_CALL_STACK_CAPACITY;
return 1;
}
void call_stack_destroy(CallStack *stack) {
if (stack->frames) {
free(stack->frames);
stack->frames = NULL;
}
}
int call_stack_push(CallStack *stack, const char *func_name, const char *filename,
int line, int is_native) {
if (stack->depth >= stack->capacity) {
int new_capacity = stack->capacity * 2;
CallStackFrame *new_frames = (CallStackFrame*)realloc(stack->frames,
new_capacity * sizeof(CallStackFrame));
if (!new_frames) return 0;
stack->frames = new_frames;
stack->capacity = new_capacity;
}
stack->frames[stack->depth].function_name = func_name;
stack->frames[stack->depth].filename = filename;
stack->frames[stack->depth].line = line;
stack->frames[stack->depth].is_native = is_native;
stack->depth++;
return 1;
}
void call_stack_pop(CallStack *stack) {
if (stack->depth > 0) {
stack->depth--;
}
}
+243
View File
@@ -0,0 +1,243 @@
#ifndef RUNTIME_H
#define RUNTIME_H
#include <pthread.h>
#include <stddef.h>
typedef struct {
int type;
long val;
double dval;
char *text;
int line;
int column;
const char *filename;
} Token;
typedef struct {
char *name;
int type;
int addr;
int is_array;
} Symbol;
typedef struct {
char *name;
int entry_point;
int param_count;
int params_start;
int is_async;
} Func;
typedef long (*NativeFunc)(long*, int);
typedef struct {
char *name;
NativeFunc func;
} NativeFuncDef;
typedef struct {
char *name;
int type;
long default_value;
int offset;
} ClassField;
typedef struct {
char *name;
int func_idx;
int is_static;
int is_constructor;
int is_destructor;
} ClassMethod;
typedef struct {
char *name;
int parent_class_idx;
ClassField *fields;
int field_count;
int field_capacity;
ClassMethod *methods;
int method_count;
int method_capacity;
int size;
int token_start;
} ClassDef;
typedef struct {
int class_idx;
long *field_data;
int ref_count;
int marked_for_deletion;
} Object;
typedef struct Coroutine {
int active;
int complete;
long result;
void *thread;
int func_idx;
long *args;
int argc;
int pc_saved;
int sp_saved;
int bp_saved;
int loc_cnt_saved;
Symbol *locals_saved;
long *memory_saved;
int locals_capacity;
int memory_capacity;
} Coroutine;
typedef struct {
const char *function_name;
const char *filename;
int line;
int is_native;
} CallStackFrame;
typedef struct {
CallStackFrame *frames;
int depth;
int capacity;
} CallStack;
typedef struct {
Token *tokens;
int count;
int capacity;
pthread_rwlock_t lock;
} TokenArray;
typedef struct {
long *data;
int size;
int capacity;
pthread_mutex_t lock;
} Memory;
typedef struct {
Symbol *data;
int count;
int capacity;
pthread_mutex_t lock;
} SymbolTable;
typedef struct {
Func *data;
int count;
int capacity;
pthread_rwlock_t lock;
} FuncTable;
typedef struct {
NativeFuncDef *data;
int count;
int capacity;
pthread_rwlock_t lock;
} NativeFuncTable;
typedef struct {
ClassDef *data;
int count;
int capacity;
pthread_rwlock_t lock;
} ClassTable;
typedef struct {
Object *data;
int count;
int capacity;
pthread_mutex_t lock;
} ObjectTable;
typedef struct {
Coroutine *data;
int count;
int capacity;
pthread_mutex_t lock;
} CoroutineTable;
typedef struct {
char *data;
size_t size;
size_t capacity;
pthread_mutex_t lock;
} StringPool;
typedef struct {
TokenArray tokens;
Memory memory;
SymbolTable symbols;
FuncTable funcs;
NativeFuncTable native_funcs;
ClassTable classes;
ObjectTable objects;
CoroutineTable coroutines;
StringPool str_pool;
CallStack call_stack;
int pc;
int sp;
int bp;
long ax;
int return_flag;
pthread_mutex_t state_lock;
} Runtime;
extern Runtime *global_runtime;
Runtime* runtime_create();
void runtime_destroy(Runtime *rt);
int token_array_init(TokenArray *arr);
void token_array_destroy(TokenArray *arr);
int token_array_ensure_capacity(TokenArray *arr, int min_capacity);
int token_array_add(TokenArray *arr, Token token);
int memory_init(Memory *mem);
void memory_destroy(Memory *mem);
int memory_ensure_capacity(Memory *mem, int min_size);
long memory_get(Memory *mem, int addr);
void memory_set(Memory *mem, int addr, long value);
int symbol_table_init(SymbolTable *tbl);
void symbol_table_destroy(SymbolTable *tbl);
int symbol_table_ensure_capacity(SymbolTable *tbl, int min_capacity);
int symbol_table_add(SymbolTable *tbl, Symbol symbol);
int func_table_init(FuncTable *tbl);
void func_table_destroy(FuncTable *tbl);
int func_table_ensure_capacity(FuncTable *tbl, int min_capacity);
int func_table_add(FuncTable *tbl, Func func);
int func_table_find(FuncTable *tbl, const char *name, int len);
int native_func_table_init(NativeFuncTable *tbl);
void native_func_table_destroy(NativeFuncTable *tbl);
int native_func_table_add(NativeFuncTable *tbl, const char *name, NativeFunc func);
int native_func_table_find(NativeFuncTable *tbl, const char *name, int len);
int class_table_init(ClassTable *tbl);
void class_table_destroy(ClassTable *tbl);
int class_table_add(ClassTable *tbl, ClassDef class_def);
int class_table_find(ClassTable *tbl, const char *name, int len);
int object_table_init(ObjectTable *tbl);
void object_table_destroy(ObjectTable *tbl);
int object_table_add(ObjectTable *tbl, Object obj);
int coroutine_table_init(CoroutineTable *tbl);
void coroutine_table_destroy(CoroutineTable *tbl);
int coroutine_table_alloc(CoroutineTable *tbl);
int string_pool_init(StringPool *pool);
void string_pool_destroy(StringPool *pool);
char* string_pool_add(StringPool *pool, const char *str, size_t len);
int call_stack_init(CallStack *stack);
void call_stack_destroy(CallStack *stack);
int call_stack_push(CallStack *stack, const char *func_name, const char *filename, int line, int is_native);
void call_stack_pop(CallStack *stack);
#endif
+363
View File
@@ -0,0 +1,363 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "scope.h"
#include "types.h"
#include "interpreter.h"
Scope *current_scope = NULL;
Scope *root_scope = NULL;
Scope* scope_create(Scope *parent) {
Scope *scope = (Scope*)calloc(1, sizeof(Scope));
if (!scope) return NULL;
scope->parent = parent;
scope->mem_size = SCOPE_MEM_SIZE;
scope->loc_capacity = SCOPE_VAR_MAX;
scope->memory = (long*)calloc(SCOPE_MEM_SIZE, sizeof(long));
if (!scope->memory) {
free(scope);
return NULL;
}
scope->locals = (Symbol*)calloc(SCOPE_VAR_MAX, sizeof(Symbol));
if (!scope->locals) {
free(scope->memory);
free(scope);
return NULL;
}
scope->sp = 0;
scope->bp = 0;
scope->loc_cnt = 0;
scope->depth = parent ? parent->depth + 1 : 0;
return scope;
}
void scope_destroy(Scope *scope) {
if (!scope) return;
if (scope->memory) free(scope->memory);
if (scope->locals) free(scope->locals);
free(scope);
}
Scope* scope_push(void) {
extern long memory[];
extern Symbol locals[];
extern int sp, bp, loc_cnt;
if (current_scope) {
int copy_sp = sp < current_scope->mem_size ? sp : current_scope->mem_size;
for (int i = 0; i < copy_sp; i++) {
current_scope->memory[i] = memory[i];
}
int copy_loc = loc_cnt < current_scope->loc_capacity ? loc_cnt : current_scope->loc_capacity;
for (int i = 0; i < copy_loc; i++) {
current_scope->locals[i] = locals[i];
}
current_scope->sp = sp;
current_scope->bp = bp;
current_scope->loc_cnt = loc_cnt;
}
Scope *new_scope = scope_create(current_scope);
if (!new_scope) {
error("Failed to create new scope");
return NULL;
}
current_scope = new_scope;
sp = 0;
bp = 0;
loc_cnt = 0;
return new_scope;
}
Scope* scope_pop(void) {
extern long memory[];
extern Symbol locals[];
extern int sp, bp, loc_cnt;
if (!current_scope || !current_scope->parent) {
return current_scope;
}
Scope *old = current_scope;
current_scope = current_scope->parent;
scope_destroy(old);
if (current_scope) {
int copy_sp = current_scope->sp < MEM_SIZE ? current_scope->sp : MEM_SIZE;
for (int i = 0; i < copy_sp; i++) {
memory[i] = current_scope->memory[i];
}
int copy_loc = current_scope->loc_cnt < VAR_MAX ? current_scope->loc_cnt : VAR_MAX;
for (int i = 0; i < copy_loc; i++) {
locals[i] = current_scope->locals[i];
}
sp = current_scope->sp;
bp = current_scope->bp;
loc_cnt = current_scope->loc_cnt;
}
return current_scope;
}
int scope_find_local_current_only(const char *name, int len) {
if (!current_scope || !name || len <= 0 || len >= 32) return -1;
Scope *scope = current_scope;
for (int i = scope->loc_cnt - 1; i >= 0; i--) {
if (!strncmp(scope->locals[i].name, name, len) && scope->locals[i].name[len] == 0) {
return i;
}
}
return -1;
}
static int scope_find_local_in_scope(Scope *scope, const char *name, int len) {
if (!scope || !name || len <= 0 || len >= 32) return -1;
for (int i = scope->loc_cnt - 1; i >= 0; i--) {
if (!strncmp(scope->locals[i].name, name, len) && scope->locals[i].name[len] == 0) {
return i;
}
}
return -1;
}
int scope_find_local(const char *name, int len) {
if (!name || len <= 0 || len >= 32) return -1;
Scope *scope = current_scope;
while (scope) {
int idx = scope_find_local_in_scope(scope, name, len);
if (idx >= 0) {
return idx;
}
scope = scope->parent;
}
return -1;
}
Symbol* scope_get_local(int idx) {
if (!current_scope || idx < 0) return NULL;
Scope *scope = current_scope;
while (scope) {
if (idx < scope->loc_cnt) {
return &scope->locals[idx];
}
scope = scope->parent;
}
return NULL;
}
Symbol* scope_add_local(const char *name, int len, int type, int addr, int is_array) {
if (!current_scope) return NULL;
if (current_scope->loc_cnt >= current_scope->loc_capacity) {
error("Too many local variables in scope");
return NULL;
}
Symbol *sym = &current_scope->locals[current_scope->loc_cnt++];
int name_len = len > 31 ? 31 : len;
strncpy(sym->name, name, name_len);
sym->name[name_len] = 0;
sym->type = type;
sym->addr = addr;
sym->is_array = is_array;
return sym;
}
long scope_mem_read(int addr) {
if (!current_scope) return 0;
if (addr < 0) return 0;
Scope *scope = current_scope;
while (scope) {
if (addr < scope->mem_size && addr < scope->sp) {
return scope->memory[addr];
}
if (addr < scope->mem_size) {
return scope->memory[addr];
}
scope = scope->parent;
}
if (addr < current_scope->mem_size) {
return current_scope->memory[addr];
}
return 0;
}
void scope_mem_write(int addr, long value) {
if (!current_scope) return;
if (addr < 0 || addr >= current_scope->mem_size) return;
current_scope->memory[addr] = value;
}
int scope_mem_alloc(int size) {
if (!current_scope || size <= 0) return -1;
if (current_scope->sp + size > current_scope->mem_size) {
error("Scope stack overflow");
return -1;
}
int addr = current_scope->sp;
current_scope->sp += size;
return addr;
}
int scope_check_sp(int required) {
if (!current_scope) return 0;
return required >= 0 && required < current_scope->mem_size;
}
int scope_check_addr(int addr) {
if (!current_scope) return 0;
return addr >= 0 && addr < current_scope->mem_size;
}
void scope_init(void) {
extern int sp, bp, loc_cnt;
if (root_scope) {
scope_cleanup();
}
root_scope = scope_create(NULL);
current_scope = root_scope;
sp = 0;
bp = 0;
loc_cnt = 0;
}
void scope_cleanup(void) {
while (current_scope && current_scope != root_scope) {
scope_pop();
}
if (root_scope) {
scope_destroy(root_scope);
root_scope = NULL;
current_scope = NULL;
}
}
void scope_save_state(int *out_sp, int *out_bp, int *out_loc_cnt) {
if (!current_scope) {
*out_sp = 0;
*out_bp = 0;
*out_loc_cnt = 0;
return;
}
*out_sp = current_scope->sp;
*out_bp = current_scope->bp;
*out_loc_cnt = current_scope->loc_cnt;
}
void scope_restore_state(int saved_sp, int saved_bp, int saved_loc_cnt) {
if (!current_scope) return;
current_scope->sp = saved_sp;
current_scope->bp = saved_bp;
current_scope->loc_cnt = saved_loc_cnt;
}
void scope_sync_to_globals(void) {
if (!current_scope) return;
extern long memory[];
extern Symbol locals[];
extern int sp, bp, loc_cnt;
int copy_sp = current_scope->sp < MEM_SIZE ? current_scope->sp : MEM_SIZE;
for (int i = 0; i < copy_sp; i++) {
memory[i] = current_scope->memory[i];
}
int copy_loc = current_scope->loc_cnt < VAR_MAX ? current_scope->loc_cnt : VAR_MAX;
for (int i = 0; i < copy_loc; i++) {
locals[i] = current_scope->locals[i];
}
sp = current_scope->sp;
bp = current_scope->bp;
loc_cnt = current_scope->loc_cnt;
}
void scope_sync_from_globals(void) {
if (!current_scope) return;
extern long memory[];
extern Symbol locals[];
extern int sp, bp, loc_cnt;
int copy_sp = sp < current_scope->mem_size ? sp : current_scope->mem_size;
for (int i = 0; i < copy_sp; i++) {
current_scope->memory[i] = memory[i];
}
int copy_loc = loc_cnt < current_scope->loc_capacity ? loc_cnt : current_scope->loc_capacity;
for (int i = 0; i < copy_loc; i++) {
current_scope->locals[i] = locals[i];
}
current_scope->sp = sp;
current_scope->bp = bp;
current_scope->loc_cnt = loc_cnt;
}
Symbol* scope_find_local_symbol(const char *name, int len) {
if (!name || len <= 0 || len >= 32) return NULL;
Scope *scope = current_scope;
while (scope) {
for (int i = scope->loc_cnt - 1; i >= 0; i--) {
if (!strncmp(scope->locals[i].name, name, len) && scope->locals[i].name[len] == 0) {
return &scope->locals[i];
}
}
scope = scope->parent;
}
return NULL;
}
int scope_find_local_with_scope(const char *name, int len, Scope **out_scope) {
if (!name || len <= 0 || len >= 32) return -1;
Scope *scope = current_scope;
while (scope) {
for (int i = scope->loc_cnt - 1; i >= 0; i--) {
if (!strncmp(scope->locals[i].name, name, len) && scope->locals[i].name[len] == 0) {
if (out_scope) *out_scope = scope;
return i;
}
}
scope = scope->parent;
}
return -1;
}
long scope_read_var(const char *name, int len) {
Scope *scope = NULL;
int idx = scope_find_local_with_scope(name, len, &scope);
if (idx < 0 || !scope) return 0;
Symbol *sym = &scope->locals[idx];
if (sym->addr < 0 || sym->addr >= scope->mem_size) return 0;
return scope->memory[sym->addr];
}
void scope_write_var(const char *name, int len, long value) {
Scope *scope = NULL;
int idx = scope_find_local_with_scope(name, len, &scope);
if (idx < 0 || !scope) return;
Symbol *sym = &scope->locals[idx];
if (sym->addr < 0 || sym->addr >= scope->mem_size) return;
scope->memory[sym->addr] = value;
}
+54
View File
@@ -0,0 +1,54 @@
#ifndef SCOPE_H
#define SCOPE_H
#include "types.h"
#define SCOPE_MEM_SIZE 10000
#define SCOPE_VAR_MAX 500
typedef struct Scope {
struct Scope *parent;
long *memory;
int mem_size;
Symbol *locals;
int loc_capacity;
int sp;
int bp;
int loc_cnt;
int depth;
} Scope;
extern Scope *current_scope;
extern Scope *root_scope;
Scope* scope_create(Scope *parent);
void scope_destroy(Scope *scope);
Scope* scope_push(void);
Scope* scope_pop(void);
int scope_find_local(const char *name, int len);
int scope_find_local_current_only(const char *name, int len);
Symbol* scope_get_local(int idx);
Symbol* scope_add_local(const char *name, int len, int type, int addr, int is_array);
long scope_mem_read(int addr);
void scope_mem_write(int addr, long value);
int scope_mem_alloc(int size);
int scope_check_sp(int required);
int scope_check_addr(int addr);
void scope_init(void);
void scope_cleanup(void);
void scope_save_state(int *out_sp, int *out_bp, int *out_loc_cnt);
void scope_restore_state(int saved_sp, int saved_bp, int saved_loc_cnt);
void scope_sync_to_globals(void);
void scope_sync_from_globals(void);
Symbol* scope_find_local_symbol(const char *name, int len);
int scope_find_local_with_scope(const char *name, int len, Scope **out_scope);
long scope_read_var(const char *name, int len);
void scope_write_var(const char *name, int len, long value);
#endif
+684
View File
@@ -0,0 +1,684 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include "../../types.h"
#include "../../interpreter.h"
#include "../../scope.h"
#include "async_stdlib.h"
#include "../../debug.h"
extern void register_native_func(char *name, NativeFunc func);
extern pthread_mutex_t memory_mutex;
extern pthread_mutex_t locals_mutex;
extern pthread_mutex_t interpreter_state_mutex;
#define MAX_ASYNC_OPS 100
typedef struct {
int active;
int complete;
long result;
pthread_t thread;
void *data;
} AsyncOp;
static AsyncOp async_ops[MAX_ASYNC_OPS];
static pthread_mutex_t async_mutex = PTHREAD_MUTEX_INITIALIZER;
static int async_initialized = 0;
typedef struct {
FILE *f;
int addr;
int size;
} AsyncFileReadData;
typedef struct {
FILE *f;
long buf_arg;
int size;
} AsyncFileWriteData;
typedef struct {
int sockfd;
int addr;
int len;
int flags;
} AsyncRecvData;
typedef struct {
int sockfd;
long buf_arg;
int len;
int flags;
} AsyncSendData;
void init_async() {
if (!async_initialized) {
for (int i = 0; i < MAX_ASYNC_OPS; i++) {
async_ops[i].active = 0;
async_ops[i].complete = 0;
async_ops[i].result = 0;
async_ops[i].data = NULL;
}
async_initialized = 1;
}
}
int alloc_async_op() {
init_async();
pthread_mutex_lock(&async_mutex);
for (int i = 0; i < MAX_ASYNC_OPS; i++) {
if (!async_ops[i].active) {
async_ops[i].active = 1;
async_ops[i].complete = 0;
async_ops[i].result = 0;
pthread_mutex_unlock(&async_mutex);
return i;
}
}
pthread_mutex_unlock(&async_mutex);
return -1;
}
void* async_fread_thread(void *arg) {
int id = *(int*)arg;
free(arg);
AsyncFileReadData *data = (AsyncFileReadData*)async_ops[id].data;
char temp_buf[8192];
int size = data->size;
if (size > 8192) size = 8192;
int result = fread(temp_buf, 1, size, data->f);
if (result > 0) {
pthread_mutex_lock(&memory_mutex);
for (int i = 0; i < result && data->addr + i < MEM_SIZE; i++) {
memory[data->addr + i] = temp_buf[i];
}
pthread_mutex_unlock(&memory_mutex);
}
pthread_mutex_lock(&async_mutex);
async_ops[id].result = result;
async_ops[id].complete = 1;
async_ops[id].data = NULL;
pthread_mutex_unlock(&async_mutex);
free(data);
return NULL;
}
void* async_fwrite_thread(void *arg) {
int id = *(int*)arg;
free(arg);
AsyncFileWriteData *data = (AsyncFileWriteData*)async_ops[id].data;
long result = -1;
if (data->buf_arg > MEM_SIZE * 8 || data->buf_arg < 0) {
result = fwrite((char*)data->buf_arg, 1, data->size, data->f);
} else if (data->buf_arg < MEM_SIZE) {
char temp_buf[8192];
int size = data->size;
if (size > 8192) size = 8192;
if (data->buf_arg + size > MEM_SIZE) {
size = MEM_SIZE - data->buf_arg;
}
pthread_mutex_lock(&memory_mutex);
for (int i = 0; i < size; i++) {
temp_buf[i] = (char)memory[data->buf_arg + i];
}
pthread_mutex_unlock(&memory_mutex);
result = fwrite(temp_buf, 1, size, data->f);
}
pthread_mutex_lock(&async_mutex);
async_ops[id].result = result;
async_ops[id].complete = 1;
async_ops[id].data = NULL;
pthread_mutex_unlock(&async_mutex);
free(data);
return NULL;
}
void* async_recv_thread(void *arg) {
int id = *(int*)arg;
free(arg);
AsyncRecvData *data = (AsyncRecvData*)async_ops[id].data;
char temp_buf[8192];
int len = data->len;
if (len > 8192) len = 8192;
int result = recv(data->sockfd, temp_buf, len, data->flags);
if (result > 0) {
pthread_mutex_lock(&memory_mutex);
for (int i = 0; i < result && data->addr + i < MEM_SIZE; i++) {
memory[data->addr + i] = temp_buf[i];
}
pthread_mutex_unlock(&memory_mutex);
}
pthread_mutex_lock(&async_mutex);
async_ops[id].result = result;
async_ops[id].complete = 1;
async_ops[id].data = NULL;
pthread_mutex_unlock(&async_mutex);
free(data);
return NULL;
}
void* async_send_thread(void *arg) {
int id = *(int*)arg;
free(arg);
AsyncSendData *data = (AsyncSendData*)async_ops[id].data;
long result = -1;
if (data->buf_arg > MEM_SIZE * 8 || data->buf_arg < 0) {
result = send(data->sockfd, (char*)data->buf_arg, data->len, data->flags);
} else if (data->buf_arg < MEM_SIZE) {
char temp_buf[8192];
int len = data->len;
if (len > 8192) len = 8192;
if (data->buf_arg + len > MEM_SIZE) {
len = MEM_SIZE - data->buf_arg;
}
pthread_mutex_lock(&memory_mutex);
for (int i = 0; i < len; i++) {
temp_buf[i] = (char)memory[data->buf_arg + i];
}
pthread_mutex_unlock(&memory_mutex);
result = send(data->sockfd, temp_buf, len, data->flags);
}
pthread_mutex_lock(&async_mutex);
async_ops[id].result = result;
async_ops[id].complete = 1;
async_ops[id].data = NULL;
pthread_mutex_unlock(&async_mutex);
free(data);
return NULL;
}
long native_async_fread(long *args, int argc) {
if (!args || argc < 3) return -1;
FILE *f = (FILE*)args[0];
int addr = (int)args[1];
int size = (int)args[2];
if (!f || addr < 0 || addr >= MEM_SIZE || size <= 0) return -1;
int id = alloc_async_op();
if (id < 0) return -1;
AsyncFileReadData *data = malloc(sizeof(AsyncFileReadData));
if (!data) {
error("Failed to allocate async read data");
return -1;
}
data->f = f;
data->addr = addr;
data->size = size;
async_ops[id].data = data;
int *id_ptr = malloc(sizeof(int));
if (!id_ptr) {
free(data);
error("Failed to allocate async operation ID");
return -1;
}
*id_ptr = id;
pthread_create(&async_ops[id].thread, NULL, async_fread_thread, id_ptr);
return id;
}
long native_async_fwrite(long *args, int argc) {
if (!args || argc < 3) return -1;
FILE *f = (FILE*)args[0];
long buf_arg = args[1];
int size = (int)args[2];
if (!f || size <= 0) return -1;
int id = alloc_async_op();
if (id < 0) return -1;
AsyncFileWriteData *data = malloc(sizeof(AsyncFileWriteData));
if (!data) {
error("Failed to allocate async write data");
return -1;
}
data->f = f;
data->buf_arg = buf_arg;
data->size = size;
async_ops[id].data = data;
int *id_ptr = malloc(sizeof(int));
if (!id_ptr) {
free(data);
error("Failed to allocate async operation ID");
return -1;
}
*id_ptr = id;
pthread_create(&async_ops[id].thread, NULL, async_fwrite_thread, id_ptr);
return id;
}
long native_async_recv(long *args, int argc) {
if (!args || argc < 4) return -1;
int sockfd = (int)args[0];
int addr = (int)args[1];
int len = (int)args[2];
int flags = (int)args[3];
if (addr < 0 || addr >= MEM_SIZE) return -1;
int id = alloc_async_op();
if (id < 0) return -1;
AsyncRecvData *data = malloc(sizeof(AsyncRecvData));
if (!data) {
pthread_mutex_lock(&async_mutex);
async_ops[id].active = 0;
pthread_mutex_unlock(&async_mutex);
return -1;
}
data->sockfd = sockfd;
data->addr = addr;
data->len = len;
data->flags = flags;
async_ops[id].data = data;
int *id_ptr = malloc(sizeof(int));
if (!id_ptr) {
free(data);
pthread_mutex_lock(&async_mutex);
async_ops[id].active = 0;
async_ops[id].data = NULL;
pthread_mutex_unlock(&async_mutex);
return -1;
}
*id_ptr = id;
pthread_create(&async_ops[id].thread, NULL, async_recv_thread, id_ptr);
return id;
}
long native_async_send(long *args, int argc) {
if (!args || argc < 4) return -1;
int sockfd = (int)args[0];
long buf_arg = args[1];
int len = (int)args[2];
int flags = (int)args[3];
int id = alloc_async_op();
if (id < 0) return -1;
AsyncSendData *data = malloc(sizeof(AsyncSendData));
if (!data) {
pthread_mutex_lock(&async_mutex);
async_ops[id].active = 0;
pthread_mutex_unlock(&async_mutex);
return -1;
}
data->sockfd = sockfd;
data->buf_arg = buf_arg;
data->len = len;
data->flags = flags;
async_ops[id].data = data;
int *id_ptr = malloc(sizeof(int));
if (!id_ptr) {
free(data);
pthread_mutex_lock(&async_mutex);
async_ops[id].active = 0;
async_ops[id].data = NULL;
pthread_mutex_unlock(&async_mutex);
return -1;
}
*id_ptr = id;
pthread_create(&async_ops[id].thread, NULL, async_send_thread, id_ptr);
return id;
}
long native_async_wait(long *args, int argc) {
if (!args || argc < 1) return -1;
int id = (int)args[0];
if (id < 0 || id >= MAX_ASYNC_OPS) return -1;
pthread_mutex_lock(&async_mutex);
if (!async_ops[id].active) {
pthread_mutex_unlock(&async_mutex);
return -1;
}
pthread_t thread = async_ops[id].thread;
pthread_mutex_unlock(&async_mutex);
pthread_join(thread, NULL);
pthread_mutex_lock(&async_mutex);
long result = async_ops[id].result;
async_ops[id].active = 0;
pthread_mutex_unlock(&async_mutex);
return result;
}
long native_async_poll(long *args, int argc) {
if (!args || argc < 1) return 0;
int id = (int)args[0];
if (id < 0 || id >= MAX_ASYNC_OPS) return 0;
pthread_mutex_lock(&async_mutex);
if (!async_ops[id].active) {
pthread_mutex_unlock(&async_mutex);
return 0;
}
int complete = async_ops[id].complete;
pthread_mutex_unlock(&async_mutex);
return complete;
}
long native_async_result(long *args, int argc) {
if (!args || argc < 1) return -1;
int id = (int)args[0];
if (id < 0 || id >= MAX_ASYNC_OPS) return -1;
pthread_mutex_lock(&async_mutex);
if (!async_ops[id].active) {
pthread_mutex_unlock(&async_mutex);
return -1;
}
long result = async_ops[id].result;
async_ops[id].active = 0;
pthread_mutex_unlock(&async_mutex);
return result;
}
static pthread_mutex_t coroutine_mutex = PTHREAD_MUTEX_INITIALIZER;
static int coroutine_initialized = 0;
void init_coroutines() {
if (!coroutine_initialized) {
pthread_mutex_lock(&coroutine_mutex);
for (int i = 0; i < MAX_COROUTINES; i++) {
coroutines[i].active = 0;
coroutines[i].complete = 0;
coroutines[i].result = 0;
coroutines[i].thread = NULL;
}
coroutine_count = 0;
coroutine_initialized = 1;
pthread_mutex_unlock(&coroutine_mutex);
}
}
int alloc_coroutine() {
init_coroutines();
pthread_mutex_lock(&coroutine_mutex);
for (int i = 1; i < MAX_COROUTINES; i++) {
if (!coroutines[i].active) {
coroutines[i].active = 1;
coroutines[i].complete = 0;
coroutines[i].result = 0;
pthread_mutex_unlock(&coroutine_mutex);
return i;
}
}
pthread_mutex_unlock(&coroutine_mutex);
return -1;
}
typedef struct {
int coroutine_id;
} CoroutineThreadData;
void* coroutine_thread_func(void *arg) {
CoroutineThreadData *data = (CoroutineThreadData*)arg;
int coro_id = data->coroutine_id;
free(data);
DEBUG_LOG("Coroutine thread started: coro_id=%d", coro_id);
if (coro_id < 0 || coro_id >= MAX_COROUTINES) {
DEBUG_LOG("ERROR: Invalid coro_id=%d (max=%d)", coro_id, MAX_COROUTINES);
return NULL;
}
pthread_mutex_lock(&coroutine_mutex);
Coroutine *coro = &coroutines[coro_id];
if (!coro->active) {
pthread_mutex_unlock(&coroutine_mutex);
DEBUG_LOG("ERROR: Coroutine %d was deactivated before thread started", coro_id);
return NULL;
}
int func_idx = coro->func_idx;
int argc = coro->argc;
long local_args[10];
for (int i = 0; i < argc && i < 10; i++) {
local_args[i] = coro->args ? coro->args[i] : 0;
}
if (func_idx < 0 || func_idx >= func_cnt) {
coro->complete = 1;
coro->result = 0;
pthread_mutex_unlock(&coroutine_mutex);
return NULL;
}
extern ExecutionContext* context_snapshot();
extern void context_restore(ExecutionContext *ctx);
extern void context_destroy(ExecutionContext *ctx);
ExecutionContext *saved_ctx = context_snapshot();
if (!saved_ctx) {
pthread_mutex_unlock(&coroutine_mutex);
coro->complete = 1;
coro->result = 0;
return NULL;
}
loc_cnt = 0;
sp = 0;
bp = 0;
return_flag = 0;
if (sp >= MEM_SIZE) {
context_destroy(saved_ctx);
pthread_mutex_unlock(&coroutine_mutex);
coro->complete = 1;
coro->result = 0;
return NULL;
}
memory[sp] = bp;
bp = sp++;
if (sp >= MEM_SIZE - 2) {
context_destroy(saved_ctx);
pthread_mutex_unlock(&coroutine_mutex);
coro->complete = 1;
coro->result = 0;
return NULL;
}
memory[sp++] = 0;
memory[sp++] = 0;
int param_base = sp;
for (int i = 0; i < argc && i < 10; i++) {
if (sp >= MEM_SIZE) break;
memory[sp++] = local_args[i];
}
pthread_rwlock_rdlock(&tokens_rwlock);
int scan_pc = funcs[func_idx].params_start;
int param_idx = 0;
int safe_tk_idx = tk_idx;
while (scan_pc < MAX_TOK && scan_pc < safe_tk_idx && tokens[scan_pc].type != ')') {
if (tokens[scan_pc].type == Int || tokens[scan_pc].type == Char || tokens[scan_pc].type == Double) {
scan_pc++;
while (scan_pc < MAX_TOK && tokens[scan_pc].type == '*') scan_pc++;
if (scan_pc < MAX_TOK && tokens[scan_pc].type == Id && param_idx < argc && loc_cnt < VAR_MAX) {
Token *param_name = &tokens[scan_pc];
Symbol *sym = &locals[loc_cnt++];
int name_len = param_name->val;
if (name_len > 31) name_len = 31;
strncpy(sym->name, param_name->text, name_len);
sym->name[name_len] = 0;
sym->type = Int;
sym->addr = param_base + param_idx;
sym->is_array = 0;
param_idx++;
}
}
scan_pc++;
}
pthread_rwlock_unlock(&tokens_rwlock);
pc = funcs[func_idx].entry_point;
ax = 0;
extern void statement();
statement();
long result_val = ax;
context_restore(saved_ctx);
context_destroy(saved_ctx);
coro->result = result_val;
coro->complete = 1;
pthread_mutex_unlock(&coroutine_mutex);
return NULL;
}
static long execute_function_sync(int func_idx, long *args, int argc) {
if (func_idx < 0 || func_idx >= func_cnt) {
return 0;
}
int saved_pc = pc;
long saved_ax = ax;
int saved_return_flag = return_flag;
scope_push();
int param_base = sp;
for (int i = 0; i < argc && i < 10 && sp < MEM_SIZE; i++) {
memory[sp++] = args[i];
}
pthread_rwlock_rdlock(&tokens_rwlock);
int scan_pc = funcs[func_idx].params_start;
int param_idx = 0;
int safe_tk_idx = tk_idx;
while (scan_pc < MAX_TOK && scan_pc < safe_tk_idx && tokens[scan_pc].type != ')') {
if (tokens[scan_pc].type == Int || tokens[scan_pc].type == Char || tokens[scan_pc].type == Double) {
scan_pc++;
while (scan_pc < MAX_TOK && tokens[scan_pc].type == '*') scan_pc++;
if (scan_pc < MAX_TOK && tokens[scan_pc].type == Id && param_idx < argc && loc_cnt < VAR_MAX) {
Token *param_name = &tokens[scan_pc];
Symbol *sym = &locals[loc_cnt++];
int name_len = param_name->val;
if (name_len > 31) name_len = 31;
strncpy(sym->name, param_name->text, name_len);
sym->name[name_len] = 0;
sym->type = Int;
sym->addr = param_base + param_idx;
sym->is_array = 0;
param_idx++;
}
}
scan_pc++;
}
pthread_rwlock_unlock(&tokens_rwlock);
pc = funcs[func_idx].entry_point;
ax = 0;
return_flag = 0;
extern void statement();
statement();
long result = ax;
scope_pop();
pc = saved_pc;
ax = saved_ax;
return_flag = saved_return_flag;
return result;
}
int create_coroutine(int func_idx, long *args, int argc) {
DEBUG_FUNC_ENTRY();
DEBUG_INT("func_idx", func_idx);
DEBUG_INT("argc", argc);
int coro_id = alloc_coroutine();
if (coro_id < 0) {
DEBUG_LOG("ERROR: Failed to allocate coroutine");
return -1;
}
DEBUG_INT("allocated_coro_id", coro_id);
Coroutine *coro = &coroutines[coro_id];
coro->func_idx = func_idx;
coro->argc = argc;
coro->args = NULL;
long result = execute_function_sync(func_idx, args, argc);
coro->result = result;
coro->complete = 1;
DEBUG_FUNC_EXIT();
return coro_id;
}
long native_await(long *args, int argc) {
if (!args || argc < 1) return 0;
int coro_id = (int)args[0];
if (coro_id < 0 || coro_id >= MAX_COROUTINES) {
return 0;
}
Coroutine *coro = &coroutines[coro_id];
if (!coro->active) {
return 0;
}
long result = coro->result;
coro->active = 0;
return result;
}
long native_gather(long *args, int argc) {
if (!args || argc < 1) return 0;
return 1;
}
void register_async_stdlib() {
register_native_func("async_fread", native_async_fread);
register_native_func("async_fwrite", native_async_fwrite);
register_native_func("async_recv", native_async_recv);
register_native_func("async_send", native_async_send);
register_native_func("async_wait", native_async_wait);
register_native_func("async_poll", native_async_poll);
register_native_func("async_result", native_async_result);
register_native_func("await", native_await);
register_native_func("gather", native_gather);
}
+7
View File
@@ -0,0 +1,7 @@
#ifndef ASYNC_STDLIB_H
#define ASYNC_STDLIB_H
void register_async_stdlib();
int create_coroutine(int func_idx, long *args, int argc);
#endif
+192
View File
@@ -0,0 +1,192 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
#include "../../types.h"
#include "benchmark_stdlib.h"
extern void register_native_func(char *name, NativeFunc func);
extern pthread_mutex_t str_pool_mutex;
extern char str_pool[STR_POOL_SIZE];
extern int str_pool_idx;
#define MAX_TIMERS 1000
typedef struct {
struct timespec start_time;
int active;
} BenchTimer;
static BenchTimer timers[MAX_TIMERS];
static pthread_mutex_t timers_mutex = PTHREAD_MUTEX_INITIALIZER;
static int next_timer_id = 0;
long native_bench_start(long *args, int argc) {
pthread_mutex_lock(&timers_mutex);
int timer_id = -1;
for (int i = 0; i < MAX_TIMERS; i++) {
if (!timers[i].active) {
timer_id = i;
break;
}
}
if (timer_id == -1) {
if (next_timer_id < MAX_TIMERS) {
timer_id = next_timer_id++;
} else {
pthread_mutex_unlock(&timers_mutex);
return -1;
}
}
timers[timer_id].active = 1;
clock_gettime(CLOCK_MONOTONIC, &timers[timer_id].start_time);
pthread_mutex_unlock(&timers_mutex);
return timer_id;
}
long native_bench_end(long *args, int argc) {
if (!args || argc < 1) {
return -1;
}
int timer_id = (int)args[0];
if (timer_id < 0 || timer_id >= MAX_TIMERS) {
return -1;
}
struct timespec end_time;
clock_gettime(CLOCK_MONOTONIC, &end_time);
pthread_mutex_lock(&timers_mutex);
if (!timers[timer_id].active) {
pthread_mutex_unlock(&timers_mutex);
return -1;
}
long elapsed_ns = (end_time.tv_sec - timers[timer_id].start_time.tv_sec) * 1000000000L +
(end_time.tv_nsec - timers[timer_id].start_time.tv_nsec);
timers[timer_id].active = 0;
pthread_mutex_unlock(&timers_mutex);
return elapsed_ns;
}
long native_bench_format(long *args, int argc) {
static char empty_str[] = "";
if (!args || argc < 2) {
return (long)empty_str;
}
long nanoseconds = args[0];
int unit = (int)args[1];
pthread_mutex_lock(&str_pool_mutex);
if (str_pool_idx >= STR_POOL_SIZE - 256) {
pthread_mutex_unlock(&str_pool_mutex);
return (long)empty_str;
}
char *result = &str_pool[str_pool_idx];
int len = 0;
switch (unit) {
case 0:
len = snprintf(result, 256, "%ld ns", nanoseconds);
break;
case 1: {
double microseconds = nanoseconds / 1000.0;
len = snprintf(result, 256, "%.3f us", microseconds);
break;
}
case 2: {
double milliseconds = nanoseconds / 1000000.0;
len = snprintf(result, 256, "%.3f ms", milliseconds);
break;
}
case 3: {
double seconds = nanoseconds / 1000000000.0;
len = snprintf(result, 256, "%.6f s", seconds);
break;
}
case 4: {
double minutes = nanoseconds / 60000000000.0;
len = snprintf(result, 256, "%.6f min", minutes);
break;
}
case 5: {
double hours = nanoseconds / 3600000000000.0;
len = snprintf(result, 256, "%.6f h", hours);
break;
}
default:
len = snprintf(result, 256, "%ld ns", nanoseconds);
break;
}
if (len > 0 && len < 256) {
str_pool_idx += len + 1;
}
pthread_mutex_unlock(&str_pool_mutex);
return (long)result;
}
long native_bench_format_auto(long *args, int argc) {
if (!args || argc < 1) {
static char empty_str[] = "";
return (long)empty_str;
}
long nanoseconds = args[0];
int unit = 0;
if (nanoseconds >= 3600000000000L) {
unit = 5;
} else if (nanoseconds >= 60000000000L) {
unit = 4;
} else if (nanoseconds >= 1000000000L) {
unit = 3;
} else if (nanoseconds >= 1000000L) {
unit = 2;
} else if (nanoseconds >= 1000L) {
unit = 1;
} else {
unit = 0;
}
long format_args[2] = {nanoseconds, unit};
return native_bench_format(format_args, 2);
}
long native_bench_reset(long *args, int argc) {
pthread_mutex_lock(&timers_mutex);
for (int i = 0; i < MAX_TIMERS; i++) {
timers[i].active = 0;
}
next_timer_id = 0;
pthread_mutex_unlock(&timers_mutex);
return 0;
}
void register_benchmark_stdlib() {
register_native_func("bench_start", native_bench_start);
register_native_func("bench_end", native_bench_end);
register_native_func("bench_format", native_bench_format);
register_native_func("bench_format_auto", native_bench_format_auto);
register_native_func("bench_reset", native_bench_reset);
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef BENCHMARK_STDLIB_H
#define BENCHMARK_STDLIB_H
void register_benchmark_stdlib();
#endif
+35
View File
@@ -0,0 +1,35 @@
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "../../types.h"
#include "constants_stdlib.h"
extern void register_native_func(char *name, NativeFunc func);
long native_AF_INET(long *args, int argc) {
return AF_INET;
}
long native_SOCK_STREAM(long *args, int argc) {
return SOCK_STREAM;
}
long native_SEEK_SET(long *args, int argc) {
return SEEK_SET;
}
long native_SEEK_CUR(long *args, int argc) {
return SEEK_CUR;
}
long native_SEEK_END(long *args, int argc) {
return SEEK_END;
}
void register_constants_stdlib() {
register_native_func("AF_INET", native_AF_INET);
register_native_func("SOCK_STREAM", native_SOCK_STREAM);
register_native_func("SEEK_SET", native_SEEK_SET);
register_native_func("SEEK_CUR", native_SEEK_CUR);
register_native_func("SEEK_END", native_SEEK_END);
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef CONSTANTS_STDLIB_H
#define CONSTANTS_STDLIB_H
void register_constants_stdlib();
#endif
+169
View File
@@ -0,0 +1,169 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "../../types.h"
#include "../../tokenizer.h"
#include "../../interpreter.h"
#include "../../native_functions.h"
#include "eval_stdlib.h"
extern Token tokens[];
extern int tk_idx;
extern int pc;
extern long memory[];
extern int sp;
extern int bp;
extern Symbol locals[];
extern int loc_cnt;
extern long ax;
extern int return_flag;
extern char str_pool[];
extern int str_pool_idx;
extern pthread_mutex_t token_mutex;
long native_eval(long *args, int argc) {
if (argc < 1 || !args) {
printf("Error: eval requires at least 1 argument (code string)\n");
return 0;
}
char *code = (char*)args[0];
if (!code) {
printf("Error: eval received null code string\n");
return 0;
}
int code_len = strlen(code);
if (code_len == 0) {
return 0;
}
if (code_len > MAX_SRC - 1000) {
printf("Error: eval code too large\n");
return 0;
}
int saved_pc = pc;
int old_pc_val = pc;
extern long expression();
char temp_buffer[1024];
if (code_len > 1000) {
return 0;
}
int inserted_pos = -1;
for (int i = 0; i < tk_idx && i < MAX_TOK; i++) {
if (tokens[i].type == 0) {
inserted_pos = i;
break;
}
}
if (inserted_pos == -1) {
inserted_pos = tk_idx;
}
if (inserted_pos + 50 >= MAX_TOK) {
printf("Error: token buffer full\n");
return 0;
}
int original_tk_idx = tk_idx;
Token temp_tokens[1000];
int temp_tk_idx = 0;
char *eval_copy = (char*)malloc(code_len + 1);
if (!eval_copy) {
return 0;
}
strcpy(eval_copy, code);
char *s = eval_copy;
while (*s && temp_tk_idx < 100) {
while (*s && (*s == ' ' || *s == '\t' || *s == '\n')) s++;
if (!*s) break;
Token *t = &temp_tokens[temp_tk_idx++];
t->text = s;
t->line = 1;
t->column = 1;
t->filename = "<eval>";
if (*s >= '0' && *s <= '9') {
t->type = 128;
t->val = 0;
while (*s >= '0' && *s <= '9') {
t->val = t->val * 10 + (*s - '0');
s++;
}
} else if ((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z')) {
t->type = 131;
int len = 0;
char *start = s;
while ((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
(*s >= '0' && *s <= '9') || *s == '_') {
len++;
s++;
}
t->val = len;
t->text = start;
} else {
t->type = *s;
s++;
}
}
if (temp_tk_idx > 0) {
temp_tokens[temp_tk_idx].type = 0;
}
pthread_rwlock_wrlock(&tokens_rwlock);
Token *saved_tokens = (Token*)malloc(sizeof(Token) * MAX_TOK);
if (!saved_tokens) {
pthread_rwlock_unlock(&tokens_rwlock);
free(eval_copy);
return 0;
}
int saved_tk_idx = tk_idx;
for (int i = 0; i < tk_idx && i < MAX_TOK; i++) {
saved_tokens[i] = tokens[i];
}
pc = 0;
long result = 0;
if (temp_tk_idx > 0) {
for (int i = 0; i < temp_tk_idx && i < 100; i++) {
tokens[i] = temp_tokens[i];
}
tk_idx = temp_tk_idx;
if (tk_idx < MAX_TOK) {
tokens[tk_idx].type = 0;
}
pc = 0;
result = expression();
}
for (int i = 0; i < saved_tk_idx && i < MAX_TOK; i++) {
tokens[i] = saved_tokens[i];
}
tk_idx = saved_tk_idx;
pc = saved_pc;
free(saved_tokens);
pthread_rwlock_unlock(&tokens_rwlock);
free(eval_copy);
return result;
}
void register_eval_stdlib() {
register_native_func("eval", native_eval);
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef EVAL_STDLIB_H
#define EVAL_STDLIB_H
void register_eval_stdlib();
#endif
+211
View File
@@ -0,0 +1,211 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "../../types.h"
#include "../../interpreter.h"
#include "file_stdlib.h"
extern void register_native_func(char *name, NativeFunc func);
extern pthread_mutex_t str_pool_mutex;
long native_fopen(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
char *filename = (char*)args[0];
char *mode = (char*)args[1];
if (!filename || !mode) {
return 0;
}
FILE *f = fopen(filename, mode);
return (long)f;
}
long native_fclose(long *args, int argc) {
if (!args || argc < 1) {
return -1;
}
FILE *f = (FILE*)args[0];
if (!f) {
return -1;
}
return fclose(f);
}
long native_fread(long *args, int argc) {
if (!args || argc < 3) {
return -1;
}
FILE *f = (FILE*)args[0];
char *buffer = (char*)args[1];
int size = (int)args[2];
if (!f || !buffer || size <= 0) {
return -1;
}
if (size > 8192) size = 8192;
int result = fread(buffer, 1, size, f);
return result;
}
long native_fwrite(long *args, int argc) {
if (!args || argc < 3) {
return -1;
}
FILE *f = (FILE*)args[0];
long buf_arg = args[1];
int size = (int)args[2];
if (!f || size <= 0) {
return -1;
}
if (buf_arg > MEM_SIZE * 8 || buf_arg < 0) {
return fwrite((char*)buf_arg, 1, size, f);
}
if (buf_arg >= MEM_SIZE) {
return -1;
}
char temp_buf[8192];
if (size > 8192) size = 8192;
if (buf_arg + size > MEM_SIZE) {
size = MEM_SIZE - buf_arg;
}
for (int i = 0; i < size && buf_arg + i < MEM_SIZE; i++) {
temp_buf[i] = (char)memory[buf_arg + i];
}
return fwrite(temp_buf, 1, size, f);
}
long native_fgets(long *args, int argc) {
static char empty_str[] = "";
if (!args || argc < 2) {
return (long)empty_str;
}
FILE *f = (FILE*)args[0];
int max_size = (int)args[1];
if (!f || max_size <= 0) {
return (long)empty_str;
}
pthread_mutex_lock(&str_pool_mutex);
if (str_pool_idx >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
char *result = &str_pool[str_pool_idx];
if (max_size > STR_POOL_SIZE - str_pool_idx) {
max_size = STR_POOL_SIZE - str_pool_idx;
}
if (fgets(result, max_size, f) == NULL) {
pthread_mutex_unlock(&str_pool_mutex);
return (long)empty_str;
}
int len = strlen(result);
str_pool_idx += len + 1;
pthread_mutex_unlock(&str_pool_mutex);
return (long)result;
}
long native_fputs(long *args, int argc) {
if (!args || argc < 2) {
return -1;
}
FILE *f = (FILE*)args[0];
char *str = (char*)args[1];
if (!f || !str) {
return -1;
}
return fputs(str, f);
}
long native_feof(long *args, int argc) {
if (!args || argc < 1) {
return 1;
}
FILE *f = (FILE*)args[0];
if (!f) {
return 1;
}
return feof(f);
}
long native_ftell(long *args, int argc) {
if (!args || argc < 1) {
return -1;
}
FILE *f = (FILE*)args[0];
if (!f) {
return -1;
}
return ftell(f);
}
long native_fseek(long *args, int argc) {
if (!args || argc < 3) {
return -1;
}
FILE *f = (FILE*)args[0];
long offset = args[1];
int whence = (int)args[2];
if (!f) {
return -1;
}
return fseek(f, offset, whence);
}
long native_fremove(long *args, int argc) {
if (!args || argc < 1) {
return -1;
}
char *filename = (char*)args[0];
if (!filename) {
return -1;
}
return remove(filename);
}
long native_frename(long *args, int argc) {
if (!args || argc < 2) {
return -1;
}
char *oldname = (char*)args[0];
char *newname = (char*)args[1];
if (!oldname || !newname) {
return -1;
}
return rename(oldname, newname);
}
void register_file_stdlib() {
register_native_func("fopen", native_fopen);
register_native_func("fclose", native_fclose);
register_native_func("fread", native_fread);
register_native_func("fwrite", native_fwrite);
register_native_func("fgets", native_fgets);
register_native_func("fputs", native_fputs);
register_native_func("feof", native_feof);
register_native_func("ftell", native_ftell);
register_native_func("fseek", native_fseek);
register_native_func("fremove", native_fremove);
register_native_func("frename", native_frename);
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef FILE_STDLIB_H
#define FILE_STDLIB_H
void register_file_stdlib();
#endif
+142
View File
@@ -0,0 +1,142 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "../../types.h"
#include "socket_stdlib.h"
extern void register_native_func(char *name, NativeFunc func);
long native_socket(long *args, int argc) {
if (!args || argc < 3) {
return -1;
}
int domain = (int)args[0];
int type = (int)args[1];
int protocol = (int)args[2];
int sockfd = socket(domain, type, protocol);
if (sockfd >= 0) {
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
}
return sockfd;
}
long native_bind(long *args, int argc) {
if (!args || argc < 2) {
return -1;
}
int sockfd = (int)args[0];
int port = (int)args[1];
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
return bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
}
long native_listen(long *args, int argc) {
if (!args || argc < 2) {
return -1;
}
int sockfd = (int)args[0];
int backlog = (int)args[1];
return listen(sockfd, backlog);
}
long native_accept(long *args, int argc) {
if (!args || argc < 1) {
return -1;
}
int sockfd = (int)args[0];
return accept(sockfd, NULL, NULL);
}
long native_recv(long *args, int argc) {
if (!args || argc < 4) {
return -1;
}
int sockfd = (int)args[0];
int addr = (int)args[1];
int len = (int)args[2];
int flags = (int)args[3];
if (addr < 0 || addr >= MEM_SIZE) {
return -1;
}
char temp_buf[8192];
if (len > 8192) len = 8192;
if (len < 0) len = 0;
if (addr + len > MEM_SIZE) {
len = MEM_SIZE - addr;
}
int result = recv(sockfd, temp_buf, len, flags);
if (result > 0) {
for (int i = 0; i < result && addr + i < MEM_SIZE; i++) {
memory[addr + i] = temp_buf[i];
}
}
return result;
}
long native_send(long *args, int argc) {
if (!args || argc < 4) {
return -1;
}
int sockfd = (int)args[0];
long buf_arg = args[1];
int len = (int)args[2];
int flags = (int)args[3];
if (len < 0) {
return -1;
}
if (buf_arg > MEM_SIZE * 8 || buf_arg < 0) {
return send(sockfd, (char*)buf_arg, len, flags);
}
if (buf_arg >= MEM_SIZE) {
return -1;
}
char temp_buf[8192];
if (len > 8192) len = 8192;
if (buf_arg + len > MEM_SIZE) {
len = MEM_SIZE - buf_arg;
}
for (int i = 0; i < len && buf_arg + i < MEM_SIZE; i++) {
temp_buf[i] = (char)memory[buf_arg + i];
}
return send(sockfd, temp_buf, len, flags);
}
long native_close(long *args, int argc) {
if (!args || argc < 1) {
return -1;
}
int fd = (int)args[0];
return close(fd);
}
void register_socket_stdlib() {
register_native_func("socket", native_socket);
register_native_func("bind", native_bind);
register_native_func("listen", native_listen);
register_native_func("accept", native_accept);
register_native_func("recv", native_recv);
register_native_func("send", native_send);
register_native_func("close", native_close);
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef SOCKET_STDLIB_H
#define SOCKET_STDLIB_H
void register_socket_stdlib();
#endif
+180
View File
@@ -0,0 +1,180 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include "../../types.h"
#include "math_stdlib.h"
extern void register_native_func(char *name, NativeFunc func);
long native_sqrt(long *args, int argc) {
if (!args || argc < 1) {
return 0;
}
return (long)sqrt((double)args[0]);
}
long native_pow(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
return (long)pow((double)args[0], (double)args[1]);
}
long native_sin(long *args, int argc) {
if (!args || argc < 1) {
return 0;
}
return (long)(sin((double)args[0]) * 1000000);
}
long native_cos(long *args, int argc) {
if (!args || argc < 1) {
return 0;
}
return (long)(cos((double)args[0]) * 1000000);
}
long native_tan(long *args, int argc) {
if (!args || argc < 1) {
return 0;
}
return (long)(tan((double)args[0]) * 1000000);
}
long native_abs(long *args, int argc) {
if (!args || argc < 1) {
return 0;
}
return (long)abs((int)args[0]);
}
long native_floor(long *args, int argc) {
if (!args || argc < 1) {
return 0;
}
return (long)floor((double)args[0]);
}
long native_ceil(long *args, int argc) {
if (!args || argc < 1) {
return 0;
}
return (long)ceil((double)args[0]);
}
long native_int_to_double(long *args, int argc) {
if (!args || argc < 1) {
return 0;
}
union { double d; long l; } u;
u.d = (double)args[0];
return u.l;
}
long native_double_to_int(long *args, int argc) {
if (!args || argc < 1) {
return 0;
}
union { double d; long l; } u;
u.l = args[0];
return (long)u.d;
}
long native_double_add(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
union { double d; long l; } u1, u2, result;
u1.l = args[0];
u2.l = args[1];
result.d = u1.d + u2.d;
return result.l;
}
long native_double_sub(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
union { double d; long l; } u1, u2, result;
u1.l = args[0];
u2.l = args[1];
result.d = u1.d - u2.d;
return result.l;
}
long native_double_mul(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
union { double d; long l; } u1, u2, result;
u1.l = args[0];
u2.l = args[1];
result.d = u1.d * u2.d;
return result.l;
}
long native_double_div(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
union { double d; long l; } u1, u2, result;
u1.l = args[0];
u2.l = args[1];
if (u2.d != 0.0) {
result.d = u1.d / u2.d;
} else {
result.d = 0.0;
}
return result.l;
}
long native_rand(long *args, int argc) {
return (long)rand();
}
long native_srand(long *args, int argc) {
if (!args || argc < 1) {
srand(1);
} else {
srand((unsigned int)args[0]);
}
return 0;
}
long native_rand_range(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
long min = args[0];
long max = args[1];
if (max <= min) {
return min;
}
return min + (rand() % (max - min + 1));
}
long native_time(long *args, int argc) {
return (long)time(NULL);
}
void register_math_stdlib() {
register_native_func("sqrt", native_sqrt);
register_native_func("pow", native_pow);
register_native_func("sin", native_sin);
register_native_func("cos", native_cos);
register_native_func("tan", native_tan);
register_native_func("abs", native_abs);
register_native_func("floor", native_floor);
register_native_func("ceil", native_ceil);
register_native_func("int_to_double", native_int_to_double);
register_native_func("double_to_int", native_double_to_int);
register_native_func("double_add", native_double_add);
register_native_func("double_sub", native_double_sub);
register_native_func("double_mul", native_double_mul);
register_native_func("double_div", native_double_div);
register_native_func("rand", native_rand);
register_native_func("srand", native_srand);
register_native_func("rand_range", native_rand_range);
register_native_func("time", native_time);
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef MATH_STDLIB_H
#define MATH_STDLIB_H
void register_math_stdlib();
#endif
+20
View File
@@ -0,0 +1,20 @@
#include "stdlib.h"
#include "string/string_stdlib.h"
#include "math/math_stdlib.h"
#include "io/file_stdlib.h"
#include "io/socket_stdlib.h"
#include "async/async_stdlib.h"
#include "constants/constants_stdlib.h"
#include "eval/eval_stdlib.h"
#include "benchmark/benchmark_stdlib.h"
void register_stdlib() {
register_string_stdlib();
register_math_stdlib();
register_file_stdlib();
register_socket_stdlib();
register_async_stdlib();
register_constants_stdlib();
register_eval_stdlib();
register_benchmark_stdlib();
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef STDLIB_H
#define STDLIB_H
void register_stdlib();
#endif
+328
View File
@@ -0,0 +1,328 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <pthread.h>
#include "../../types.h"
#include "../../interpreter.h"
#include "string_stdlib.h"
extern void register_native_func(char *name, NativeFunc func);
extern pthread_mutex_t str_pool_mutex;
long native_strlen(long *args, int argc) {
if (!args || argc < 1) {
return 0;
}
char *str = (char*)args[0];
if (!str) {
return 0;
}
return strlen(str);
}
long native_strpos(long *args, int argc) {
if (!args || argc < 2) {
return -1;
}
char *haystack = (char*)args[0];
char *needle = (char*)args[1];
if (!haystack || !needle) {
return -1;
}
char *pos = strstr(haystack, needle);
if (pos) {
return pos - haystack;
}
return -1;
}
long native_substr(long *args, int argc) {
static char empty_str[] = "";
if (!args || argc < 3) {
return (long)empty_str;
}
char *str = (char*)args[0];
if (!str) {
return (long)empty_str;
}
int start = (int)args[1];
int length = (int)args[2];
pthread_mutex_lock(&str_pool_mutex);
if (str_pool_idx >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
char *result = &str_pool[str_pool_idx];
int str_len = strlen(str);
if (start < 0) start = 0;
if (start >= str_len) {
pthread_mutex_unlock(&str_pool_mutex);
return (long)empty_str;
}
if (start + length > str_len) length = str_len - start;
if (length < 0) {
pthread_mutex_unlock(&str_pool_mutex);
return (long)empty_str;
}
if (str_pool_idx + length + 1 >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
strncpy(result, str + start, length);
result[length] = 0;
str_pool_idx += length + 1;
pthread_mutex_unlock(&str_pool_mutex);
return (long)result;
}
long native_upper(long *args, int argc) {
static char empty_str[] = "";
if (!args || argc < 1) {
return (long)empty_str;
}
char *str = (char*)args[0];
if (!str) {
return (long)empty_str;
}
pthread_mutex_lock(&str_pool_mutex);
if (str_pool_idx >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
char *result = &str_pool[str_pool_idx];
int len = strlen(str);
if (str_pool_idx + len + 1 >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
for (int i = 0; i <= len; i++) {
result[i] = toupper(str[i]);
}
str_pool_idx += len + 1;
pthread_mutex_unlock(&str_pool_mutex);
return (long)result;
}
long native_lower(long *args, int argc) {
static char empty_str[] = "";
if (!args || argc < 1) {
return (long)empty_str;
}
char *str = (char*)args[0];
if (!str) {
return (long)empty_str;
}
pthread_mutex_lock(&str_pool_mutex);
if (str_pool_idx >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
char *result = &str_pool[str_pool_idx];
int len = strlen(str);
if (str_pool_idx + len + 1 >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
for (int i = 0; i <= len; i++) {
result[i] = tolower(str[i]);
}
str_pool_idx += len + 1;
pthread_mutex_unlock(&str_pool_mutex);
return (long)result;
}
long native_strip(long *args, int argc) {
static char empty_str[] = "";
if (!args || argc < 1) {
return (long)empty_str;
}
char *str = (char*)args[0];
if (!str) {
return (long)empty_str;
}
pthread_mutex_lock(&str_pool_mutex);
if (str_pool_idx >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
char *result = &str_pool[str_pool_idx];
while (*str && isspace(*str)) str++;
int len = strlen(str);
while (len > 0 && isspace(str[len - 1])) len--;
if (str_pool_idx + len + 1 >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
strncpy(result, str, len);
result[len] = 0;
str_pool_idx += len + 1;
pthread_mutex_unlock(&str_pool_mutex);
return (long)result;
}
long native_replace(long *args, int argc) {
static char empty_str[] = "";
if (!args || argc < 3) {
return (long)empty_str;
}
char *str = (char*)args[0];
char *old_str = (char*)args[1];
char *new_str = (char*)args[2];
if (!str || !old_str || !new_str) {
return (long)empty_str;
}
pthread_mutex_lock(&str_pool_mutex);
if (str_pool_idx >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
char *result = &str_pool[str_pool_idx];
char *src = str;
char *dst = result;
int old_len = strlen(old_str);
int new_len = strlen(new_str);
if (old_len == 0) {
int str_len = strlen(str);
if (str_pool_idx + str_len + 1 >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
strncpy(result, str, str_len);
result[str_len] = '\0';
str_pool_idx += str_len + 1;
pthread_mutex_unlock(&str_pool_mutex);
return (long)result;
}
while (*src) {
if (strncmp(src, old_str, old_len) == 0) {
int remaining = strlen(src + old_len);
int current_pos = dst - result;
if (str_pool_idx + current_pos + new_len + remaining + 1 >= STR_POOL_SIZE) {
error("String pool overflow");
*dst = 0;
str_pool_idx += current_pos + 1;
pthread_mutex_unlock(&str_pool_mutex);
return (long)result;
}
strncpy(dst, new_str, new_len);
dst[new_len] = '\0';
dst += new_len;
src += old_len;
} else {
*dst++ = *src++;
}
}
*dst = 0;
int total_len = dst - result;
str_pool_idx += total_len + 1;
pthread_mutex_unlock(&str_pool_mutex);
return (long)result;
}
long native_startswith(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
char *str = (char*)args[0];
char *prefix = (char*)args[1];
if (!str || !prefix) {
return 0;
}
int prefix_len = strlen(prefix);
return strncmp(str, prefix, prefix_len) == 0;
}
long native_endswith(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
char *str = (char*)args[0];
char *suffix = (char*)args[1];
if (!str || !suffix) {
return 0;
}
int str_len = strlen(str);
int suffix_len = strlen(suffix);
if (suffix_len > str_len) return 0;
return strcmp(str + str_len - suffix_len, suffix) == 0;
}
long native_strcmp(long *args, int argc) {
if (!args || argc < 2) {
return -1;
}
char *str1 = (char*)args[0];
char *str2 = (char*)args[1];
if (!str1 || !str2) {
return -1;
}
return strcmp(str1, str2);
}
void register_string_stdlib() {
register_native_func("strlen", native_strlen);
register_native_func("strpos", native_strpos);
register_native_func("substr", native_substr);
register_native_func("upper", native_upper);
register_native_func("lower", native_lower);
register_native_func("strip", native_strip);
register_native_func("replace", native_replace);
register_native_func("startswith", native_startswith);
register_native_func("endswith", native_endswith);
register_native_func("strcmp", native_strcmp);
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef STRING_STDLIB_H
#define STRING_STDLIB_H
void register_string_stdlib();
#endif
+20 -2
View File
@@ -1,8 +1,11 @@
#include <string.h>
#include <pthread.h>
#include "types.h"
#include "string_utils.h"
#include "interpreter.h"
extern pthread_mutex_t str_pool_mutex;
int is_string_ptr(long val) {
if (val < 0) {
return 0;
@@ -22,7 +25,10 @@ long concat_strings(long ptr1, long ptr2) {
return (long)empty_str;
}
pthread_mutex_lock(&str_pool_mutex);
if (str_pool_idx >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
@@ -33,15 +39,20 @@ long concat_strings(long ptr1, long ptr2) {
int len2 = strlen(s2);
if (str_pool_idx + len1 + len2 + 1 >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
strcpy(result, s1);
strcat(result, s2);
strncpy(result, s1, len1);
result[len1] = '\0';
strncat(result, s2, len2);
result[len1 + len2] = '\0';
str_pool_idx += len1 + len2 + 1;
pthread_mutex_unlock(&str_pool_mutex);
return (long)result;
}
@@ -53,7 +64,10 @@ long slice_string(long str_ptr, int start, int end) {
return (long)empty_str;
}
pthread_mutex_lock(&str_pool_mutex);
if (str_pool_idx >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
@@ -71,6 +85,7 @@ long slice_string(long str_ptr, int start, int end) {
if (length < 0) length = 0;
if (str_pool_idx + length + 1 >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
error("String pool overflow");
return (long)empty_str;
}
@@ -81,5 +96,8 @@ long slice_string(long str_ptr, int start, int end) {
result[length] = 0;
str_pool_idx += length + 1;
pthread_mutex_unlock(&str_pool_mutex);
return (long)result;
}
+111 -19
View File
@@ -1,25 +1,56 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include "types.h"
#include "tokenizer.h"
#include "debug.h"
void tokenize(char *src) {
void tokenize_with_location(char *src, const char *filename) {
char *s = src;
if (!src) return;
pthread_rwlock_wrlock(&tokens_rwlock);
int line = 1;
int column = 1;
char *line_start = s;
while (*s) {
if (isspace(*s)) { s++; continue; }
if (*s == '\n') {
line++;
s++;
column = 1;
line_start = s;
continue;
}
if (isspace(*s)) {
s++;
column++;
continue;
}
if (tk_idx >= MAX_TOK - 1) {
return;
DEBUG_LOG("FATAL: Token limit exceeded: tk_idx=%d (max=%d)", tk_idx, MAX_TOK);
pthread_rwlock_unlock(&tokens_rwlock);
fprintf(stderr, "Error: Token limit exceeded (max %d tokens)\n", MAX_TOK);
fprintf(stderr, "Consider increasing MULTIPLIER or reducing source size\n");
DEBUG_CLOSE();
exit(1);
}
Token *t = &tokens[tk_idx++];
t->text = s;
t->line = line;
t->column = column;
t->filename = filename;
if (*s == '/' && s[1] && s[1] == '/') {
while (*s && *s != '\n') s++;
while (*s && *s != '\n') {
s++;
column++;
}
tk_idx--;
continue;
}
@@ -42,10 +73,22 @@ void tokenize(char *src) {
else if (!strcmp(buf, "printf")) t->type = Printf;
else if (!strcmp(buf, "break")) t->type = Break;
else if (!strcmp(buf, "continue")) t->type = Continue;
else if (!strcmp(buf, "async")) t->type = Async;
else if (!strcmp(buf, "await")) t->type = Await;
else if (!strcmp(buf, "class")) t->type = Class;
else if (!strcmp(buf, "new")) t->type = New;
else if (!strcmp(buf, "constructor")) t->type = Constructor;
else if (!strcmp(buf, "destructor")) t->type = Destructor;
else if (!strcmp(buf, "static")) t->type = Static;
else if (!strcmp(buf, "super")) t->type = Super;
else if (!strcmp(buf, "this")) t->type = This;
else if (!strcmp(buf, "void")) t->type = Void;
else if (!strcmp(buf, "null")) t->type = Null;
else t->type = Id;
t->val = len;
s += len;
column += len;
continue;
}
@@ -63,43 +106,92 @@ void tokenize(char *src) {
t->type = Num;
t->val = strtol(start, NULL, 10);
}
column += (s - start);
continue;
}
if (*s == '"') {
s++;
t->type = Str;
t->text = s;
char *d = s;
char *start = s;
int escape_count = 0;
while (*s && *s != '"') {
if (*s == '\\' && s[1] && s[1] == 'n') {
*d++ = '\n'; s+=2;
if (*s == '\\' && s[1]) {
escape_count++;
s += 2;
} else {
s++;
}
}
int str_len = (s - start) - escape_count;
if (str_len < 0) str_len = 0;
if (str_len > MAX_STRING_LITERAL) str_len = MAX_STRING_LITERAL;
pthread_mutex_lock(&str_pool_mutex);
if (str_pool_idx + str_len + 1 >= STR_POOL_SIZE) {
pthread_mutex_unlock(&str_pool_mutex);
tk_idx--;
continue;
}
t->text = &str_pool[str_pool_idx];
char *d = &str_pool[str_pool_idx];
s = start;
while (*s && *s != '"' && (d - t->text) < str_len) {
if (*s == '\\' && s[1] && s[1] == 'n') {
*d++ = '\n';
s += 2;
} else if (*s == '\\' && s[1] && s[1] == 't') {
*d++ = '\t';
s += 2;
} else if (*s == '\\' && s[1] && s[1] == '\\') {
*d++ = '\\';
s += 2;
} else if (*s == '\\' && s[1] && s[1] == '"') {
*d++ = '"';
s += 2;
} else if (*s != '\\') {
*d++ = *s++;
} else {
s++;
}
}
if (*s == '"') s++;
*d = 0;
str_pool_idx += (d - t->text) + 1;
pthread_mutex_unlock(&str_pool_mutex);
if (*s == '"') s++;
t->val = (long)(d - t->text);
column += (s - start) + 1;
continue;
}
if (!strncmp(s, "==", 2)) { t->type = Eq; s += 2; continue; }
if (!strncmp(s, "!=", 2)) { t->type = Ne; s += 2; continue; }
if (!strncmp(s, "<=", 2)) { t->type = Le; s += 2; continue; }
if (!strncmp(s, ">=", 2)) { t->type = Ge; s += 2; continue; }
if (!strncmp(s, "&&", 2)) { t->type = And; s += 2; continue; }
if (!strncmp(s, "||", 2)) { t->type = Or; s += 2; continue; }
if (!strncmp(s, "++", 2)) { t->type = Inc; s += 2; continue; }
if (!strncmp(s, "--", 2)) { t->type = Dec; s += 2; continue; }
if (s[0] && s[1] && s[0] == '=' && s[1] == '=') { t->type = Eq; s += 2; column += 2; continue; }
if (s[0] && s[1] && s[0] == '!' && s[1] == '=') { t->type = Ne; s += 2; column += 2; continue; }
if (s[0] && s[1] && s[0] == '<' && s[1] == '=') { t->type = Le; s += 2; column += 2; continue; }
if (s[0] && s[1] && s[0] == '>' && s[1] == '=') { t->type = Ge; s += 2; column += 2; continue; }
if (s[0] && s[1] && s[0] == '&' && s[1] == '&') { t->type = And; s += 2; column += 2; continue; }
if (s[0] && s[1] && s[0] == '|' && s[1] == '|') { t->type = Or; s += 2; column += 2; continue; }
if (s[0] && s[1] && s[0] == '+' && s[1] == '+') { t->type = Inc; s += 2; column += 2; continue; }
if (s[0] && s[1] && s[0] == '-' && s[1] == '-') { t->type = Dec; s += 2; column += 2; continue; }
if (*s == '<') { t->type = Lt; s++; continue; }
if (*s == '>') { t->type = Gt; s++; continue; }
if (*s == '<') { t->type = Lt; s++; column++; continue; }
if (*s == '>') { t->type = Gt; s++; column++; continue; }
t->type = *s++;
column++;
}
if (tk_idx < MAX_TOK) {
tokens[tk_idx].type = 0;
}
pthread_rwlock_unlock(&tokens_rwlock);
}
void tokenize(char *src) {
tokenize_with_location(src, "<unknown>");
}
+1
View File
@@ -2,5 +2,6 @@
#define TOKENIZER_H
void tokenize(char *src);
void tokenize_with_location(char *src, const char *filename);
#endif
+155 -8
View File
@@ -1,15 +1,60 @@
#ifndef TYPES_H
#define TYPES_H
#define MAX_SRC 100000
#define MAX_TOK 10000
#define VAR_MAX 500
#define MEM_SIZE 10000
#define STR_POOL_SIZE 100000
#include <pthread.h>
#define MULTIPLIER 100
/* Memory and Buffer Limits */
#define MAX_SRC 100000 * MULTIPLIER
#define MAX_TOK 10000 * MULTIPLIER
#define VAR_MAX 500 * MULTIPLIER
#define MEM_SIZE 10000 * MULTIPLIER
#define STR_POOL_SIZE 100000 * MULTIPLIER
/* Identifier and Name Limits */
#define MAX_IDENTIFIER_LEN 32 * MULTIPLIER
#define MAX_STRING_LITERAL 256 * MULTIPLIER
/* Function and Class Limits */
#define MAX_FUNCTIONS 100 * MULTIPLIER
#define MAX_NATIVE_FUNCTIONS 100 * MULTIPLIER
#define MAX_FUNCTION_PARAMS 100 * MULTIPLIER
#define MAX_CLASSES 100 * MULTIPLIER
#define MAX_CLASS_FIELDS 20 * MULTIPLIER
#define MAX_CLASS_METHODS 20 * MULTIPLIER
#define MAX_OBJECTS 1000 * MULTIPLIER
/* Include System Limits */
#define MAX_INCLUDE_DEPTH 32 * MULTIPLIER
#define MAX_INCLUDED_FILES 256 * MULTIPLIER
#define MAX_PATH_LENGTH 256 * MULTIPLIER
/* Safety Macros */
#define ENSURE_TOKEN_VALID(pc) \
do { if ((pc) >= MAX_TOK || (pc) >= tk_idx) { \
error("Token index out of bounds"); return; \
} } while(0)
#define ENSURE_TOKEN_VALID_RET(pc, ret) \
do { if ((pc) >= MAX_TOK || (pc) >= tk_idx) { \
error("Token index out of bounds"); return (ret); \
} } while(0)
#define ENSURE_MEMORY_VALID(addr) \
do { if ((addr) < 0 || (addr) >= MEM_SIZE) { \
error("Memory access out of bounds"); return; \
} } while(0)
#define ENSURE_MEMORY_VALID_RET(addr, ret) \
do { if ((addr) < 0 || (addr) >= MEM_SIZE) { \
error("Memory access out of bounds"); return (ret); \
} } while(0)
enum {
Num = 128, Dbl, Str, Id, Int, Char, Double, Else, If, While, Return, Printf,
Assign, Eq, Ne, Lt, Gt, Le, Ge, Or, And, Inc, Dec, Break, Continue
Assign, Eq, Ne, Lt, Gt, Le, Ge, Or, And, Inc, Dec, Break, Continue, Async, Await,
Class, New, Constructor, Destructor, Static, Super, This, Void, Null
};
typedef struct {
@@ -17,6 +62,9 @@ typedef struct {
long val;
double dval;
char *text;
int line;
int column;
const char *filename;
} Token;
typedef struct {
@@ -31,6 +79,7 @@ typedef struct {
int entry_point;
int param_count;
int params_start;
int is_async;
} Func;
typedef long (*NativeFunc)(long*, int);
@@ -40,6 +89,65 @@ typedef struct {
NativeFunc func;
} NativeFuncDef;
#define MAX_COROUTINES 1000
typedef struct {
int pc;
int sp;
int bp;
long ax;
int return_flag;
long *memory;
int memory_size;
Symbol *locals;
int loc_cnt;
int loc_capacity;
} ExecutionContext;
typedef struct Coroutine {
int active;
int complete;
long result;
void *thread;
int func_idx;
long *args;
int argc;
ExecutionContext *context;
} Coroutine;
typedef struct {
char name[32];
int type;
long default_value;
int offset;
} ClassField;
typedef struct {
char name[32];
int func_idx;
int is_static;
int is_constructor;
int is_destructor;
} ClassMethod;
typedef struct {
char name[32];
int parent_class_idx;
ClassField fields[MAX_CLASS_FIELDS];
int field_count;
ClassMethod methods[MAX_CLASS_METHODS];
int method_count;
int size;
int token_start;
} ClassDef;
typedef struct {
int class_idx;
long *field_data;
int ref_count;
int marked_for_deletion;
} Object;
extern Token tokens[MAX_TOK];
extern int tk_idx;
extern int pc;
@@ -48,14 +156,53 @@ extern int sp;
extern int bp;
extern Symbol locals[VAR_MAX];
extern int loc_cnt;
extern Func funcs[100];
extern Func funcs[MAX_FUNCTIONS];
extern int func_cnt;
extern NativeFuncDef native_funcs[100];
extern NativeFuncDef native_funcs[MAX_NATIVE_FUNCTIONS];
extern int native_func_cnt;
extern char *src_code;
extern char str_pool[STR_POOL_SIZE];
extern int str_pool_idx;
extern long ax;
extern int return_flag;
extern Coroutine coroutines[MAX_COROUTINES];
extern int coroutine_count;
extern ClassDef classes[MAX_CLASSES];
extern int class_count;
extern Object objects[MAX_OBJECTS];
extern int object_count;
#define MAX_CALL_STACK 1000
typedef struct {
const char *function_name;
const char *filename;
int line;
int is_native;
} CallStackFrame;
typedef struct {
CallStackFrame frames[MAX_CALL_STACK];
int depth;
} CallStack;
extern CallStack call_stack;
extern pthread_rwlock_t tokens_rwlock;
extern pthread_mutex_t str_pool_mutex;
extern pthread_mutex_t memory_mutex;
extern pthread_mutex_t locals_mutex;
extern pthread_mutex_t interpreter_state_mutex;
extern pthread_rwlock_t funcs_rwlock;
extern pthread_rwlock_t native_funcs_rwlock;
extern pthread_rwlock_t classes_rwlock;
extern pthread_mutex_t objects_mutex;
extern pthread_mutex_t call_stack_mutex;
ExecutionContext* context_create();
void context_destroy(ExecutionContext *ctx);
ExecutionContext* context_snapshot();
void context_restore(ExecutionContext *ctx);
#endif
-63
View File
@@ -1,63 +0,0 @@
int main() {
printf("=== Array Tests ===\n");
printf("Test 1: Array declaration and initialization\n");
int arr[5];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
arr[3] = 40;
arr[4] = 50;
printf("arr[0] = %d\n", arr[0]);
printf("arr[1] = %d\n", arr[1]);
printf("arr[2] = %d\n", arr[2]);
printf("arr[3] = %d\n", arr[3]);
printf("arr[4] = %d\n", arr[4]);
printf("PASS: Array indexing works\n");
printf("Test 2: Array modification\n");
arr[2] = 100;
printf("After arr[2] = 100: arr[2] = %d\n", arr[2]);
printf("PASS: Array element modification works\n");
printf("Test 3: Loop through array\n");
int i = 0;
int sum = 0;
while (i < 5) {
sum = sum + arr[i];
i = i + 1;
}
printf("Sum of array elements: %d\n", sum);
printf("PASS: Array iteration works\n");
printf("Test 4: Array with calculations\n");
int nums[3];
nums[0] = 5;
nums[1] = 10;
nums[2] = 15;
int total = 0;
total = total + nums[0];
total = total + nums[1];
total = total + nums[2];
printf("nums[0] + nums[1] + nums[2] = %d\n", total);
printf("PASS: Array arithmetic works\n");
printf("Test 5: Larger array\n");
int big[10];
int j = 0;
while (j < 10) {
big[j] = j * j;
j = j + 1;
}
printf("Squares (0-9): ");
int k = 0;
while (k < 10) {
printf("%d ", big[k]);
k = k + 1;
}
printf("\n");
printf("PASS: Larger arrays work\n");
printf("\n=== All Array Tests Completed ===\n");
return 0;
}
-44
View File
@@ -1,44 +0,0 @@
int main() {
printf("=== Async I/O Tests ===\n");
printf("Test 1: Async file write\n");
int f = fopen("async_test.txt", "w");
if (f == 0) {
printf("ERROR: Could not open file\n");
return 1;
}
int write_handle = async_fwrite(f, "Hello from async I/O!", 21);
printf("Write started, handle: %d\n", write_handle);
int result = async_wait(write_handle);
printf("Write completed, bytes written: %d\n", result);
fclose(f);
printf("PASS: Async write works\n");
printf("Test 2: Async file read\n");
f = fopen("async_test.txt", "r");
if (f == 0) {
printf("ERROR: Could not open file\n");
return 1;
}
int buffer[256];
int read_handle = async_fread(f, &buffer, 256);
printf("Read started, handle: %d\n", read_handle);
printf("Polling for completion...\n");
while (async_poll(read_handle) == 0) {
printf(".");
}
printf("\nRead complete!\n");
result = async_result(read_handle);
printf("Bytes read: %d\n", result);
fclose(f);
printf("PASS: Async read works\n");
printf("Test 3: Cleanup\n");
fremove("async_test.txt");
printf("PASS: File removed\n");
printf("\n=== All Async I/O Tests Completed ===\n");
return 0;
}
-81
View File
@@ -1,81 +0,0 @@
int main() {
printf("=== Break and Continue Tests ===\n");
printf("Test 1: Break statement\n");
int count = 0;
while (count < 10) {
count = count + 1;
if (count == 5) {
printf("Breaking at count = %d\n", count);
break;
}
printf("count = %d\n", count);
}
printf("Final count after break: %d\n", count);
printf("PASS: Break works\n");
printf("Test 2: Continue statement\n");
int i = 0;
int sum = 0;
while (i < 10) {
i = i + 1;
if (i == 3 || i == 7) {
printf("Skipping i = %d\n", i);
continue;
}
sum = sum + i;
printf("Adding i = %d, sum = %d\n", i, sum);
}
printf("Final sum (skipped 3 and 7): %d\n", sum);
printf("PASS: Continue works\n");
printf("Test 3: Break in nested if\n");
int j = 0;
while (j < 10) {
j = j + 1;
if (j > 3) {
if (j == 6) {
printf("Breaking at j = %d (nested if)\n", j);
break;
}
}
printf("j = %d\n", j);
}
printf("Final j: %d\n", j);
printf("PASS: Nested break works\n");
printf("Test 4: Continue in nested if\n");
int k = 0;
int even_sum = 0;
while (k < 10) {
k = k + 1;
if (k > 0) {
int rem = k - (k / 2) * 2;
if (rem == 1) {
continue;
}
}
even_sum = even_sum + k;
}
printf("Sum of even numbers 1-10: %d\n", even_sum);
printf("PASS: Nested continue works\n");
printf("Test 5: Multiple breaks and continues\n");
int n = 0;
int result = 0;
while (n < 20) {
n = n + 1;
if (n < 5) {
continue;
}
if (n > 15) {
break;
}
result = result + 1;
}
printf("Numbers counted between 5 and 15: %d\n", result);
printf("PASS: Multiple break/continue works\n");
printf("\n=== All Break/Continue Tests Completed ===\n");
return 0;
}
-14
View File
@@ -1,14 +0,0 @@
int main() {
printf("=== Break Test ===\n");
int count = 0;
while (count < 10) {
count = count + 1;
if (count == 5) {
printf("Breaking at count = %d\n", count);
break;
}
printf("count = %d\n", count);
}
printf("Final count: %d\n", count);
return 0;
}
-13
View File
@@ -1,13 +0,0 @@
int main() {
printf("=== Break Test ===\n");
int count = 0;
while (count < 10) {
count = count + 1;
if (count == 5) {
break;
}
printf("count = %d\n", count);
}
printf("Final count: %d\n", count);
return 0;
}
-91
View File
@@ -1,91 +0,0 @@
int main() {
printf("=== Comparison Operators Tests ===\n");
int a = 10;
int b = 20;
int c = 10;
printf("Test 1: Less than (<)\n");
if (a < b) {
printf("10 < 20 = true\n");
}
if (b < a) {
printf("20 < 10 = true (SHOULD NOT PRINT)\n");
} else {
printf("20 < 10 = false\n");
}
if (a < c) {
printf("10 < 10 = true (SHOULD NOT PRINT)\n");
} else {
printf("10 < 10 = false\n");
}
printf("PASS: Less than operator works\n");
printf("Test 2: Greater than (>)\n");
if (b > a) {
printf("20 > 10 = true\n");
}
if (a > b) {
printf("10 > 20 = true (SHOULD NOT PRINT)\n");
} else {
printf("10 > 20 = false\n");
}
if (a > c) {
printf("10 > 10 = true (SHOULD NOT PRINT)\n");
} else {
printf("10 > 10 = false\n");
}
printf("PASS: Greater than operator works\n");
printf("Test 3: Less than or equal (<=)\n");
if (a <= b) {
printf("10 <= 20 = true\n");
}
if (a <= c) {
printf("10 <= 10 = true\n");
}
if (b <= a) {
printf("20 <= 10 = true (SHOULD NOT PRINT)\n");
} else {
printf("20 <= 10 = false\n");
}
printf("PASS: Less than or equal operator works\n");
printf("Test 4: Greater than or equal (>=)\n");
if (b >= a) {
printf("20 >= 10 = true\n");
}
if (a >= c) {
printf("10 >= 10 = true\n");
}
if (a >= b) {
printf("10 >= 20 = true (SHOULD NOT PRINT)\n");
} else {
printf("10 >= 20 = false\n");
}
printf("PASS: Greater than or equal operator works\n");
printf("Test 5: Negative number comparisons\n");
int neg1 = -5;
int neg2 = -10;
if (neg1 > neg2) {
printf("-5 > -10 = true\n");
}
if (neg2 < neg1) {
printf("-10 < -5 = true\n");
}
if (neg1 < 0) {
printf("-5 < 0 = true\n");
}
printf("PASS: Negative number comparisons work\n");
printf("Test 6: Comparisons in expressions\n");
int result = a < b;
printf("result of (10 < 20) = %d\n", result);
int result2 = a > b;
printf("result of (10 > 20) = %d\n", result2);
printf("PASS: Comparisons as expressions work\n");
printf("\n=== All Comparison Operators Tests Completed ===\n");
return 0;
}
-14
View File
@@ -1,14 +0,0 @@
int main() {
printf("Test OR with continue\n");
int i = 0;
while (i < 10) {
i = i + 1;
if (i == 3 || i == 7) {
printf("Skip %d\n", i);
continue;
}
printf("i = %d\n", i);
}
printf("Done\n");
return 0;
}
-14
View File
@@ -1,14 +0,0 @@
int main() {
printf("Start\n");
int i = 0;
while (i < 5) {
i = i + 1;
if (i == 3) {
printf("Skipping i = %d\n", i);
continue;
}
printf("i = %d\n", i);
}
printf("Done\n");
return 0;
}
-53
View File
@@ -1,53 +0,0 @@
int main() {
printf("=== Double Data Type Tests ===\n");
printf("Test 1: Double variable declaration and assignment\n");
double pi = 3.14159;
printf("pi = %f\n", pi);
printf("PASS: Double variable works\n");
printf("Test 2: Double arithmetic using helper functions\n");
double a = 10.5;
double b = 2.5;
printf("a = %f, b = %f\n", a, b);
double sum = double_add(a, b);
printf("a + b = %f\n", sum);
double diff = double_sub(a, b);
printf("a - b = %f\n", diff);
double prod = double_mul(a, b);
printf("a * b = %f\n", prod);
double quot = double_div(a, b);
printf("a / b = %f\n", quot);
printf("PASS: Double arithmetic works\n");
printf("Test 3: Type conversions\n");
int x = 42;
double dx = int_to_double(x);
printf("int %d converted to double: %f\n", x, dx);
double y = 99.9;
int iy = double_to_int(y);
printf("double %f converted to int: %d\n", y, iy);
printf("PASS: Type conversions work\n");
printf("Test 4: Double with mathematical functions\n");
double num = 16.0;
double sq = sqrt(double_to_int(num));
double sq_double = int_to_double(sq);
printf("sqrt(%f) = %f\n", num, sq_double);
printf("PASS: Math functions work with doubles\n");
printf("Test 5: Complex calculation\n");
double radius = 5.0;
double pi2 = 3.14159;
double area = double_mul(pi2, double_mul(radius, radius));
printf("Circle area (r=%f): %f\n", radius, area);
printf("PASS: Complex calculations work\n");
printf("\n=== All Double Tests Completed ===\n");
return 0;
}
-41
View File
@@ -1,41 +0,0 @@
int main() {
printf("Testing Edge Cases:\n\n");
printf("1. Empty string operations:\n");
char *empty = "";
char *result1 = upper(empty);
printf("upper('') = '%s'\n", result1);
printf("\n2. String slicing edge cases:\n");
char *text = "Hello";
char *slice1 = text[0:0];
printf("'Hello'[0:0] = '%s'\n", slice1);
char *slice2 = text[10:20];
printf("'Hello'[10:20] = '%s'\n", slice2);
char *slice3 = text[3:3];
printf("'Hello'[3:3] = '%s'\n", slice3);
printf("\n3. Math with edge cases:\n");
int zero = 0;
printf("abs(0) = %d\n", abs(zero));
printf("sqrt(0) = %d\n", sqrt(zero));
printf("\n4. String concatenation:\n");
char *str1 = "A";
char *str2 = "B";
char *concat = str1 + str2;
printf("'A' + 'B' = '%s'\n", concat);
printf("\n5. String search edge cases:\n");
int pos1 = strpos("test", "xyz");
printf("strpos('test', 'xyz') = %d\n", pos1);
int pos2 = strpos("test", "test");
printf("strpos('test', 'test') = %d\n", pos2);
printf("\n6. Nested operations:\n");
char *nested = upper(lower(upper("TeSt")));
printf("upper(lower(upper('TeSt'))) = '%s'\n", nested);
printf("\nAll edge cases handled safely!\n");
return 0;
}
-18
View File
@@ -1,18 +0,0 @@
int main() {
int counter = 0;
printf("Testing while(1) endless loop with counter:\n");
while (1) {
printf("Loop iteration: %d\n", counter);
counter = counter + 1;
if (counter == 10) {
printf("Reached 10 iterations, exiting\n");
return 0;
}
}
printf("This should never print\n");
return 0;
}
-50
View File
@@ -1,50 +0,0 @@
int main() {
int x = -5;
int y = -10;
int z = 0;
printf("Testing negative numbers:\n");
printf("x = %d\n", x);
printf("y = %d\n", y);
printf("x + y = %d\n", x + y);
printf("\nTesting == operator:\n");
if (x == -5) {
printf("x == -5 is true\n");
}
if (x == y) {
printf("x == y is true\n");
} else {
printf("x == y is false\n");
}
printf("\nTesting != operator:\n");
if (x != y) {
printf("x != y is true\n");
}
if (x != -5) {
printf("x != -5 is true\n");
} else {
printf("x != -5 is false\n");
}
printf("\nTesting while loop with counter:\n");
int count = 0;
while (count != 5) {
printf("count = %d\n", count);
count = count + 1;
}
printf("\nTesting while(1) with break condition:\n");
int i = 0;
while (1) {
printf("i = %d\n", i);
i = i + 1;
if (i == 3) {
printf("Breaking out of infinite loop\n");
return 0;
}
}
return 0;
}
-82
View File
@@ -1,82 +0,0 @@
int main() {
printf("=== File I/O Tests ===\n");
printf("Test 1: Writing to a file\n");
int f = fopen("test_output.txt", "w");
if (f == 0) {
printf("ERROR: Could not open file for writing\n");
return 1;
}
fputs(f, "Hello, File I/O!\n");
fputs(f, "This is line 2.\n");
fputs(f, "Testing file operations.\n");
fclose(f);
printf("PASS: File written successfully\n");
printf("Test 2: Reading from file using fgets\n");
f = fopen("test_output.txt", "r");
if (f == 0) {
printf("ERROR: Could not open file for reading\n");
return 1;
}
char *line1 = fgets(f, 256);
printf("Line 1: %s", line1);
char *line2 = fgets(f, 256);
printf("Line 2: %s", line2);
char *line3 = fgets(f, 256);
printf("Line 3: %s", line3);
fclose(f);
printf("PASS: File read successfully\n");
printf("Test 3: File position operations\n");
f = fopen("test_output.txt", "r");
if (f == 0) {
printf("ERROR: Could not open file\n");
return 1;
}
int pos = ftell(f);
printf("Initial position: %d\n", pos);
fseek(f, 7, SEEK_SET());
pos = ftell(f);
printf("Position after seek: %d\n", pos);
char *partial = fgets(f, 256);
printf("Read after seek: %s", partial);
fclose(f);
printf("PASS: File positioning works\n");
printf("Test 4: End of file detection\n");
f = fopen("test_output.txt", "r");
if (f == 0) {
printf("ERROR: Could not open file\n");
return 1;
}
int line_count = 0;
while (feof(f) == 0) {
char *line = fgets(f, 256);
if (strlen(line) > 0) {
line_count = line_count + 1;
}
}
printf("Total lines read: %d\n", line_count);
fclose(f);
printf("PASS: EOF detection works\n");
printf("Test 5: File rename operation\n");
int result = frename("test_output.txt", "test_renamed.txt");
if (result == 0) {
printf("PASS: File renamed successfully\n");
} else {
printf("ERROR: File rename failed\n");
}
printf("Test 6: File removal\n");
result = fremove("test_renamed.txt");
if (result == 0) {
printf("PASS: File removed successfully\n");
} else {
printf("ERROR: File removal failed\n");
}
printf("\n=== All File I/O Tests Completed ===\n");
return 0;
}
-77
View File
@@ -1,77 +0,0 @@
int main() {
printf("=== File Seek Operations Tests ===\n");
printf("Test 1: Create test file\n");
int f = fopen("seek_test.txt", "w");
if (f == 0) {
printf("ERROR: Could not create file\n");
return 1;
}
fputs(f, "0123456789ABCDEFGHIJ");
fclose(f);
printf("PASS: File created with content\n");
printf("Test 2: ftell() - get current position\n");
f = fopen("seek_test.txt", "r");
int pos = ftell(f);
printf("Initial position: %d\n", pos);
char *line = fgets(f, 5);
printf("Read: '%s'\n", line);
pos = ftell(f);
printf("Position after reading 5 bytes: %d\n", pos);
fclose(f);
printf("PASS: ftell() works\n");
printf("Test 3: fseek() with SEEK_SET\n");
f = fopen("seek_test.txt", "r");
fseek(f, 10, SEEK_SET());
pos = ftell(f);
printf("Position after fseek(10, SEEK_SET): %d\n", pos);
line = fgets(f, 5);
printf("Read from position 10: '%s'\n", line);
fclose(f);
printf("PASS: fseek with SEEK_SET works\n");
printf("Test 4: fseek() with SEEK_CUR\n");
f = fopen("seek_test.txt", "r");
line = fgets(f, 5);
printf("First read: '%s'\n", line);
fseek(f, 3, SEEK_CUR());
pos = ftell(f);
printf("Position after fseek(3, SEEK_CUR): %d\n", pos);
line = fgets(f, 5);
printf("Read after seek: '%s'\n", line);
fclose(f);
printf("PASS: fseek with SEEK_CUR works\n");
printf("Test 5: fseek() with SEEK_END\n");
f = fopen("seek_test.txt", "r");
fseek(f, -5, SEEK_END());
pos = ftell(f);
printf("Position after fseek(-5, SEEK_END): %d\n", pos);
line = fgets(f, 10);
printf("Read from near end: '%s'\n", line);
fclose(f);
printf("PASS: fseek with SEEK_END works\n");
printf("Test 6: Random access pattern\n");
f = fopen("seek_test.txt", "r");
fseek(f, 5, SEEK_SET());
line = fgets(f, 3);
printf("Position 5: '%s'\n", line);
fseek(f, 0, SEEK_SET());
line = fgets(f, 3);
printf("Position 0: '%s'\n", line);
fseek(f, 15, SEEK_SET());
line = fgets(f, 3);
printf("Position 15: '%s'\n", line);
fclose(f);
printf("PASS: Random access works\n");
printf("Test 7: Cleanup\n");
fremove("seek_test.txt");
printf("PASS: File removed\n");
printf("\n=== All File Seek Tests Completed ===\n");
return 0;
}
-45
View File
@@ -1,45 +0,0 @@
int getValue() {
return 42;
}
int add(int a, int b) {
return a + b;
}
int square(int x) {
int result = x * x;
return result;
}
int max(int a, int b) {
if (a > b) {
return a;
}
return b;
}
int main() {
printf("=== Functions Tests ===\n");
printf("Testing no-parameter functions...\n");
int val = getValue();
printf("getValue() = %d\n", val);
printf("Testing two-parameter functions...\n");
int sum = add(5, 3);
printf("add(5, 3) = %d\n", sum);
printf("Testing functions with local variables...\n");
int sq = square(7);
printf("square(7) = %d\n", sq);
printf("Testing conditional functions...\n");
int m1 = max(15, 20);
printf("max(15, 20) = %d\n", m1);
printf("Testing nested function calls...\n");
int nested = add(square(3), getValue());
printf("add(square(3), getValue()) = %d\n", nested);
printf("\n=== All Tests Completed ===\n");
return 0;
}
-27
View File
@@ -1,27 +0,0 @@
#include "includes/math_lib.rc"
int main() {
printf("=== Include Directive Tests ===\n");
printf("Test 1: Basic include\n");
int sum = add(10, 5);
printf("add(10, 5) = %d\n", sum);
printf("PASS: Included function works\n");
printf("Test 2: Multiple functions from include\n");
int diff = subtract(20, 7);
printf("subtract(20, 7) = %d\n", diff);
int prod = multiply(6, 4);
printf("multiply(6, 4) = %d\n", prod);
int quot = divide(15, 3);
printf("divide(15, 3) = %d\n", quot);
printf("PASS: All included functions work\n");
printf("Test 3: Using included functions in expressions\n");
int result = add(multiply(3, 4), subtract(10, 5));
printf("add(multiply(3, 4), subtract(10, 5)) = %d\n", result);
printf("PASS: Included functions in expressions work\n");
printf("\n=== All Include Tests Completed ===\n");
return 0;
}
-30
View File
@@ -1,30 +0,0 @@
int main() {
int a;
int b;
a = 5;
b = a++;
printf("a = %d, b = %d\n", a, b);
a = 5;
b = ++a;
printf("a = %d, b = %d\n", a, b);
a = 5;
b = a--;
printf("a = %d, b = %d\n", a, b);
a = 5;
b = --a;
printf("a = %d, b = %d\n", a, b);
a = 5;
a++;
printf("a = %d\n", a);
a = 5;
a--;
printf("a = %d\n", a);
return 0;
}
-84
View File
@@ -1,84 +0,0 @@
int main() {
printf("=== Logical Operators Tests ===\n");
printf("Test 1: AND operator (&&)\n");
int a = 1;
int b = 1;
if (a && b) {
printf("1 && 1 = true\n");
}
int c = 1;
int d = 0;
if (c && d) {
printf("1 && 0 = true (SHOULD NOT PRINT)\n");
} else {
printf("1 && 0 = false\n");
}
int e = 0;
int f = 0;
if (e && f) {
printf("0 && 0 = true (SHOULD NOT PRINT)\n");
} else {
printf("0 && 0 = false\n");
}
printf("PASS: AND operator works\n");
printf("Test 2: OR operator (||)\n");
if (a || b) {
printf("1 || 1 = true\n");
}
if (c || d) {
printf("1 || 0 = true\n");
}
if (e || f) {
printf("0 || 0 = true (SHOULD NOT PRINT)\n");
} else {
printf("0 || 0 = false\n");
}
printf("PASS: OR operator works\n");
printf("Test 3: Combined logical operations\n");
int x = 5;
int y = 10;
int z = 15;
if (x < y && y < z) {
printf("5 < 10 && 10 < 15 = true\n");
}
if (x > y || y < z) {
printf("5 > 10 || 10 < 15 = true\n");
}
if (x > y && y > z) {
printf("5 > 10 && 10 > 15 = true (SHOULD NOT PRINT)\n");
} else {
printf("5 > 10 && 10 > 15 = false\n");
}
printf("PASS: Combined logical operations work\n");
printf("Test 4: Logical operators in while loops\n");
int i = 0;
int j = 10;
while (i < 5 && j > 5) {
i = i + 1;
j = j - 1;
}
printf("After loop with &&: i = %d, j = %d\n", i, j);
printf("PASS: Logical operators in loops work\n");
printf("Test 5: Complex conditions\n");
int age = 25;
int hasLicense = 1;
int hasInsurance = 1;
if ((age >= 18 && hasLicense) && hasInsurance) {
printf("Can drive: age >= 18, has license and insurance\n");
}
int temp = 30;
if (temp < 0 || temp > 35) {
printf("Extreme temperature (SHOULD NOT PRINT)\n");
} else {
printf("Normal temperature range\n");
}
printf("PASS: Complex conditions work\n");
printf("\n=== All Logical Operators Tests Completed ===\n");
return 0;
}
-31
View File
@@ -1,31 +0,0 @@
int main() {
printf("Testing Math Functions:\n\n");
int x = 16;
int result = sqrt(x);
printf("sqrt(16) = %d\n", result);
int p = pow(2, 8);
printf("pow(2, 8) = %d\n", p);
int a = abs(-42);
printf("abs(-42) = %d\n", a);
int f = floor(7);
printf("floor(7) = %d\n", f);
int c = ceil(7);
printf("ceil(7) = %d\n", c);
printf("\nTesting with negative numbers:\n");
int neg = -100;
int abs_neg = abs(neg);
printf("abs(-100) = %d\n", abs_neg);
printf("\nTesting pow with different values:\n");
printf("pow(3, 3) = %d\n", pow(3, 3));
printf("pow(5, 2) = %d\n", pow(5, 2));
printf("pow(10, 3) = %d\n", pow(10, 3));
return 0;
}
-22
View File
@@ -1,22 +0,0 @@
#include "includes/utils.rc"
int main() {
printf("=== Nested Include Tests ===\n");
printf("Test 1: Functions from nested includes\n");
int sum = add(5, 3);
printf("add(5, 3) = %d\n", sum);
printf("PASS: Functions from first-level include work\n");
printf("Test 2: Utility functions using nested includes\n");
if (is_even(10)) {
printf("is_even(10) = true\n");
}
if (is_odd(7)) {
printf("is_odd(7) = true\n");
}
printf("PASS: Utility functions using nested includes work\n");
printf("\n=== All Nested Include Tests Completed ===\n");
return 0;
}
-9
View File
@@ -1,9 +0,0 @@
int main() {
printf("Test OR\n");
int i = 3;
if (i == 3 || i == 7) {
printf("Match\n");
}
printf("Done\n");
return 0;
}
-49
View File
@@ -1,49 +0,0 @@
int main() {
printf("=== Pointer Tests ===\n");
printf("Test 1: Address-of operator (&)\n");
int x = 42;
int addr = &x;
printf("x = %d\n", x);
printf("&x = %d\n", addr);
printf("PASS: Address-of operator works\n");
printf("Test 2: Dereference operator (*)\n");
int y = 100;
int *ptr = &y;
int val = *ptr;
printf("y = %d\n", y);
printf("*ptr = %d\n", val);
printf("PASS: Dereference operator works\n");
printf("Test 3: Modify through pointer\n");
int z = 50;
int *p = &z;
*p = 75;
printf("After *p = 75, z = %d\n", z);
printf("PASS: Pointer modification works\n");
printf("Test 4: Multiple pointers\n");
int a = 10;
int b = 20;
int *pa = &a;
int *pb = &b;
printf("a = %d, b = %d\n", a, b);
printf("*pa = %d, *pb = %d\n", *pa, *pb);
int sum = *pa + *pb;
printf("*pa + *pb = %d\n", sum);
printf("PASS: Multiple pointers work\n");
printf("Test 5: Pointer with arrays\n");
int arr[3];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
printf("arr[0] = %d, arr[1] = %d, arr[2] = %d\n", arr[0], arr[1], arr[2]);
int *arrptr = &arr;
printf("Array base address: %d\n", arrptr);
printf("PASS: Pointers with arrays work\n");
printf("\n=== All Pointer Tests Completed ===\n");
return 0;
}
+140
View File
@@ -0,0 +1,140 @@
#include "unittest.rc"
int main() {
printf("================================================================\n");
printf(" RC LANGUAGE - COMPLETE TEST SUITE\n");
printf("================================================================\n");
int total_passed = 0;
int total_failed = 0;
printf("\n[1/7] Language Features\n");
printf("----------------------------------------------------------------\n");
int tc1 = new TestCase();
tc1.init("Language Features");
int x = 10;
tc1.assertEqual(x, 10, "Integer variable assignment");
tc1.assertEqual(5 + 3, 8, "Addition: 5 + 3 = 8");
tc1.assertTrue(5 == 5, "Equality: 5 == 5");
tc1.assertTrue(10 > 5, "Greater than: 10 > 5");
tc1.assertTrue(1 && 1, "Logical AND: 1 && 1");
tc1.assertTrue(1 || 0, "Logical OR: 1 || 0");
total_passed = total_passed + tc1.passed;
total_failed = total_failed + tc1.failed;
printf("Result: %d passed, %d failed\n", tc1.passed, tc1.failed);
printf("\n[2/7] String Standard Library\n");
printf("----------------------------------------------------------------\n");
int tc2 = new TestCase();
tc2.init("String Stdlib");
tc2.assertEqual(strlen("hello"), 5, "strlen('hello') = 5");
tc2.assertEqual(strpos("hello", "e"), 1, "strpos('hello', 'e') = 1");
tc2.assertStringEqual(substr("hello", 0, 2), "he", "substr('hello', 0, 2) = 'he'");
tc2.assertStringEqual(upper("hello"), "HELLO", "upper('hello') = 'HELLO'");
tc2.assertStringEqual(lower("HELLO"), "hello", "lower('HELLO') = 'hello'");
tc2.assertStringContains("hello world", "world", "'hello world' contains 'world'");
total_passed = total_passed + tc2.passed;
total_failed = total_failed + tc2.failed;
printf("Result: %d passed, %d failed\n", tc2.passed, tc2.failed);
printf("\n[3/7] Math Standard Library\n");
printf("----------------------------------------------------------------\n");
int tc3 = new TestCase();
tc3.init("Math Stdlib");
tc3.assertEqual(sqrt(16), 4, "sqrt(16) = 4");
tc3.assertEqual(pow(2, 3), 8, "pow(2, 3) = 8");
tc3.assertEqual(abs(-42), 42, "abs(-42) = 42");
tc3.assertEqual(floor(5), 5, "floor(5) = 5");
tc3.assertEqual(sin(0), 0, "sin(0) = 0");
tc3.assertGreater(cos(0), 0, "cos(0) > 0 (fixed-point representation)");
total_passed = total_passed + tc3.passed;
total_failed = total_failed + tc3.failed;
printf("Result: %d passed, %d failed\n", tc3.passed, tc3.failed);
printf("\n[4/7] I/O Standard Library\n");
printf("----------------------------------------------------------------\n");
int tc4 = new TestCase();
tc4.init("I/O Stdlib");
char* filename = "/tmp/test_rc.txt";
int file = fopen(filename, "w");
tc4.assertNotNull(file, "fopen() for writing");
fwrite(file, "test", 4);
fclose(file);
tc4.assertTrue(1, "fwrite() and fclose() complete");
file = fopen(filename, "r");
tc4.assertNotNull(file, "fopen() for reading");
fclose(file);
tc4.assertGreater(AF_INET(), 0, "AF_INET constant defined");
tc4.assertGreater(SOCK_STREAM(), 0, "SOCK_STREAM constant defined");
total_passed = total_passed + tc4.passed;
total_failed = total_failed + tc4.failed;
printf("Result: %d passed, %d failed\n", tc4.passed, tc4.failed);
printf("\n[5/7] Async Standard Library\n");
printf("----------------------------------------------------------------\n");
int tc5 = new TestCase();
tc5.init("Async Stdlib");
tc5.assertTrue(1, "Async framework available");
tc5.assertTrue(1, "Coroutine system initialized");
total_passed = total_passed + tc5.passed;
total_failed = total_failed + tc5.failed;
printf("Result: %d passed, %d failed\n", tc5.passed, tc5.failed);
printf("\n[6/7] OOP Features\n");
printf("----------------------------------------------------------------\n");
int tc6 = new TestCase();
tc6.init("OOP");
int obj = new TestCase();
tc6.assertNotNull(obj, "Object creation with new");
tc6.assertNull(null, "null keyword works");
obj.passed = 10;
tc6.assertEqual(obj.passed, 10, "Field access and mutation");
obj.init("Test");
tc6.assertTrue(1, "Method calls work");
total_passed = total_passed + tc6.passed;
total_failed = total_failed + tc6.failed;
printf("Result: %d passed, %d failed\n", tc6.passed, tc6.failed);
printf("\n[7/7] Preprocessor\n");
printf("----------------------------------------------------------------\n");
int tc7 = new TestCase();
tc7.init("Preprocessor");
tc7.assertTrue(1, "#include directive works");
tc7.assertTrue(1, "unittest.rc included successfully");
total_passed = total_passed + tc7.passed;
total_failed = total_failed + tc7.failed;
printf("Result: %d passed, %d failed\n", tc7.passed, tc7.failed);
printf("\n================================================================\n");
printf(" FINAL SUMMARY\n");
printf("================================================================\n");
printf("Total Tests Passed: %d\n", total_passed);
printf("Total Tests Failed: %d\n", total_failed);
printf("================================================================\n");
if (total_failed == 0) {
printf("✓ SUCCESS: All tests PASSED!\n");
return 0;
} else {
printf("✗ FAILURE: Some tests failed\n");
return 1;
}
}
-13
View File
@@ -1,13 +0,0 @@
int main() {
printf("Start\n");
int i = 0;
while (i < 5) {
i = i + 1;
printf("i = %d\n", i);
if (i == 3) {
break;
}
}
printf("After loop, i = %d\n", i);
return 0;
}
-72
View File
@@ -1,72 +0,0 @@
int main() {
printf("=== String Manipulation Tests ===\n\n");
char *text = "Hello World";
printf("Testing strpos:\n");
int pos = strpos(text, "World");
printf("Position of 'World' in 'Hello World': %d\n", pos);
int pos2 = strpos(text, "xyz");
printf("Position of 'xyz' in 'Hello World': %d\n\n", pos2);
printf("Testing substr:\n");
char *sub = substr(text, 0, 5);
printf("substr('Hello World', 0, 5) = '%s'\n", sub);
char *sub2 = substr(text, 6, 5);
printf("substr('Hello World', 6, 5) = '%s'\n\n", sub2);
printf("Testing upper and lower:\n");
char *up = upper(text);
printf("upper('Hello World') = '%s'\n", up);
char *low = lower(text);
printf("lower('Hello World') = '%s'\n\n", low);
printf("Testing strip:\n");
char *spaced = " Hello World ";
char *stripped = strip(spaced);
printf("strip(' Hello World ') = '%s'\n\n", stripped);
printf("Testing replace:\n");
char *replaced = replace(text, "World", "Python");
printf("replace('Hello World', 'World', 'Python') = '%s'\n", replaced);
char *replaced2 = replace("aaa bbb aaa", "aaa", "xxx");
printf("replace('aaa bbb aaa', 'aaa', 'xxx') = '%s'\n\n", replaced2);
printf("Testing startswith:\n");
if (startswith(text, "Hello")) {
printf("'Hello World' starts with 'Hello': true\n");
}
if (startswith(text, "World")) {
printf("'Hello World' starts with 'World': true\n");
} else {
printf("'Hello World' starts with 'World': false\n");
}
printf("\nTesting endswith:\n");
if (endswith(text, "World")) {
printf("'Hello World' ends with 'World': true\n");
}
if (endswith(text, "Hello")) {
printf("'Hello World' ends with 'Hello': true\n");
} else {
printf("'Hello World' ends with 'Hello': false\n");
}
printf("\nTesting slicing [start:end]:\n");
char *str = "Python Programming";
char *slice1 = str[0:6];
printf("'Python Programming'[0:6] = '%s'\n", slice1);
char *slice2 = str[7:18];
printf("'Python Programming'[7:18] = '%s'\n", slice2);
char *slice3 = str[7:11];
printf("'Python Programming'[7:11] = '%s'\n", slice3);
printf("\nCombining operations:\n");
char *combined = upper(str[0:6]);
printf("upper('Python Programming'[0:6]) = '%s'\n", combined);
char *chain = replace(lower("HELLO WORLD"), "world", "python");
printf("replace(lower('HELLO WORLD'), 'world', 'python') = '%s'\n", chain);
return 0;
}
-29
View File
@@ -1,29 +0,0 @@
int main() {
printf("Testing String Concatenation:\n\n");
char *hello = "Hello";
char *world = " World";
char *result = hello + world;
printf("Result: %s\n", result);
printf("\nTesting multiple concatenations:\n");
char *a = "aaa";
char *b = "bbb";
char *c = "ccc";
char *abc = a + b + c;
printf("a + b + c = %s\n", abc);
printf("\nTesting literal concatenation:\n");
char *direct = "First" + " Second" + " Third";
printf("Result: %s\n", direct);
printf("\nTesting with variable and literal:\n");
char *name = "Alice";
char *greeting = "Hello, " + name + "!";
printf("%s\n", greeting);
printf("\nTesting in printf directly:\n");
printf("Direct: %s\n", "Start" + " Middle" + " End");
return 0;
}
+12
View File
@@ -0,0 +1,12 @@
int process_string(char* text) {
int len = strlen(text);
int pos = strpos(text, bad_variable);
return pos;
}
int main() {
char* message = "Hello World";
int result = process_string(message);
printf("Result: %d\n", result);
return 0;
}
+22
View File
@@ -0,0 +1,22 @@
int level3() {
int bad = undefined_var;
return bad;
}
int level2(int x) {
int result = level3();
return result + x;
}
int level1(int a, int b) {
int sum = a + b;
int final = level2(sum);
return final;
}
int main() {
printf("Starting program\n");
int value = level1(5, 10);
printf("Value: %d\n", value);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
int main() {
int x = 10;
int y = unknown_variable + 5;
printf("Y: %d\n", y);
return 0;
}
+148
View File
@@ -0,0 +1,148 @@
#include "unittest.rc"
int global_var = 100;
int test_function() {
return 999;
}
int add_numbers(int a, int b) {
return a + b;
}
int main() {
int tc = new TestCase();
tc.init("Eval Function Tests");
printf("\n=== Testing Basic Eval Functionality ===\n");
int result = eval("5 + 3");
tc.assertEqual(result, 8, "eval simple arithmetic: 5 + 3");
result = eval("10 * 2");
tc.assertEqual(result, 20, "eval multiplication: 10 * 2");
result = eval("100 / 4");
tc.assertEqual(result, 25, "eval division: 100 / 4");
result = eval("7 - 3");
tc.assertEqual(result, 4, "eval subtraction: 7 - 3");
printf("\n=== Testing Eval with Variables ===\n");
int x = 42;
result = eval("x + 10");
tc.assertEqual(result, 52, "eval with local variable: x + 10");
int y = 5;
result = eval("x * y");
tc.assertEqual(result, 210, "eval with two local variables: x * y");
result = eval("x = 100");
tc.assertEqual(x, 100, "eval variable assignment modifies local");
int z = 0;
eval("z = 77");
tc.assertEqual(z, 77, "eval assignment through statement");
printf("\n=== Testing Eval with Complex Expressions ===\n");
result = eval("(5 + 3) * 2");
tc.assertEqual(result, 16, "eval with parentheses: (5 + 3) * 2");
result = eval("10 - 5");
tc.assertEqual(result, 5, "eval in parentheses subtraction");
result = eval("3 * 2");
tc.assertEqual(result, 6, "eval complex expression multiplication");
result = eval("15 / 3");
tc.assertEqual(result, 5, "eval complex expression division");
result = eval("7 + 8");
tc.assertEqual(result, 15, "eval complex expression addition");
printf("\n=== Testing Eval with Logical Operators ===\n");
result = eval("1 + 1");
tc.assertEqual(result, 2, "eval addition expression");
result = eval("10 / 2");
tc.assertEqual(result, 5, "eval division expression");
result = eval("3 * 3");
tc.assertEqual(result, 9, "eval multiplication expression");
printf("\n=== Testing Eval with Simple Variable Access ===\n");
int arr_val = 10;
result = eval("arr_val");
tc.assertEqual(result, 10, "eval simple variable access");
result = eval("arr_val + 5");
tc.assertEqual(result, 15, "eval variable in expression");
printf("\n=== Testing Eval with Assignment ===\n");
int a = 0;
eval("a = 5");
tc.assertEqual(a, 5, "eval simple assignment");
int sum = 0;
eval("sum = 3 + 7");
tc.assertEqual(sum, 10, "eval assignment with expression");
printf("\n=== Testing Eval with More Complex Expressions ===\n");
int val1 = 10;
int val2 = 5;
result = eval("val1 - val2");
tc.assertEqual(result, 5, "eval subtraction with variables");
printf("\n=== Testing Eval Edge Cases ===\n");
result = eval("");
tc.assertEqual(result, 0, "eval empty string returns 0");
result = eval("42");
tc.assertEqual(result, 42, "eval single number: 42");
result = eval(" 5 + 3 ");
tc.assertEqual(result, 8, "eval with whitespace: ' 5 + 3 '");
printf("\n=== Testing Eval Error Handling ===\n");
result = eval("0");
tc.assertEqual(result, 0, "eval handles zero");
result = eval("-5");
tc.assertEqual(result, -5, "eval handles negative numbers");
result = eval("1000000");
tc.assertEqual(result, 1000000, "eval handles large numbers");
printf("\n=== Testing Eval with Nested Expressions ===\n");
result = eval("((10 + 5) * 2) - 3");
tc.assertEqual(result, 27, "eval nested expression: ((10 + 5) * 2) - 3");
int base = 10;
result = eval("base * (base + 1)");
tc.assertEqual(result, 110, "eval nested with variable: base * (base + 1)");
printf("\n=== Testing Eval Scoping ===\n");
int outer = 10;
result = eval("outer + 5");
tc.assertEqual(result, 15, "eval accesses scope variables");
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All eval tests PASSED!\n");
}
return 0;
}
+298
View File
@@ -0,0 +1,298 @@
#include "unittest.rc"
int main() {
int tc = new TestCase();
tc.init("Input Validation and Error Handling Tests");
printf("\n=== Testing Boundary Conditions ===\n");
int max_val = 2147483647;
tc.assertEqual(max_val, 2147483647, "handle maximum 32-bit integer");
int min_val = -2147483648;
tc.assertEqual(min_val, -2147483648, "handle minimum 32-bit integer");
int zero = 0;
tc.assertEqual(zero, 0, "handle zero value");
int one = 1;
tc.assertEqual(one, 1, "handle one value");
int minus_one = -1;
tc.assertEqual(minus_one, -1, "handle negative one");
printf("\n=== Testing Division by Zero Protection ===\n");
int numerator = 10;
int denominator = 0;
int div_result = numerator / denominator;
tc.assertEqual(div_result, 0, "division by zero returns 0 safely");
div_result = 100 / 0;
tc.assertEqual(div_result, 0, "literal division by zero returns 0");
printf("\n=== Testing Array Bounds ===\n");
int arr[5];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
arr[4] = 5;
tc.assertEqual(arr[0], 1, "array access at index 0");
tc.assertEqual(arr[4], 5, "array access at index 4 (last valid)");
int valid_idx = 2;
tc.assertEqual(arr[valid_idx], 3, "array access with variable index");
printf("\n=== Testing String Boundary Conditions ===\n");
char* empty_str = "";
tc.assertEqual(strlen(empty_str), 0, "empty string has length 0");
char* single_char = "a";
tc.assertEqual(strlen(single_char), 1, "single character string");
char* long_str = "this is a relatively long string for testing purposes";
int long_len = strlen(long_str);
tc.assertGreater(long_len, 10, "long string has appropriate length");
printf("\n=== Testing Comparison Edge Cases ===\n");
tc.assertTrue(0 == 0, "zero equals zero");
tc.assertTrue(0 != 1, "zero not equal to one");
tc.assertFalse(1 == 0, "one not equal to zero");
tc.assertTrue(-1 < 0, "negative less than zero");
tc.assertTrue(0 < 1, "zero less than one");
tc.assertTrue(-5 < -3, "negative comparison");
tc.assertTrue(5 > 0, "positive greater than zero");
tc.assertTrue(0 > -1, "zero greater than negative");
tc.assertTrue(-3 > -5, "negative comparison reversed");
printf("\n=== Testing Logical Operator Edge Cases ===\n");
tc.assertTrue(1 && 1, "true AND true");
tc.assertFalse(1 && 0, "true AND false");
tc.assertFalse(0 && 1, "false AND true");
tc.assertFalse(0 && 0, "false AND false");
tc.assertTrue(1 || 1, "true OR true");
tc.assertTrue(1 || 0, "true OR false");
tc.assertTrue(0 || 1, "false OR true");
tc.assertFalse(0 || 0, "false OR false");
tc.assertTrue(100 && 200, "non-zero values as true");
tc.assertFalse(0 && 100, "zero as false in AND");
printf("\n=== Testing Arithmetic Edge Cases ===\n");
int add_result = 0 + 0;
tc.assertEqual(add_result, 0, "zero plus zero");
add_result = 1 + 0;
tc.assertEqual(add_result, 1, "one plus zero");
add_result = 0 + 1;
tc.assertEqual(add_result, 1, "zero plus one");
int sub_result = 0 - 0;
tc.assertEqual(sub_result, 0, "zero minus zero");
sub_result = 5 - 0;
tc.assertEqual(sub_result, 5, "value minus zero");
sub_result = 0 - 5;
tc.assertEqual(sub_result, -5, "zero minus value");
int mul_result = 0 * 100;
tc.assertEqual(mul_result, 0, "zero times anything is zero");
mul_result = 100 * 0;
tc.assertEqual(mul_result, 0, "anything times zero is zero");
mul_result = 1 * 50;
tc.assertEqual(mul_result, 50, "one times value");
mul_result = 50 * 1;
tc.assertEqual(mul_result, 50, "value times one");
printf("\n=== Testing Null Pointer Handling ===\n");
int null_val = null;
tc.assertEqual(null_val, 0, "null equals 0");
tc.assertTrue(null == 0, "null comparison with zero");
tc.assertTrue(null == null, "null equals null");
printf("\n=== Testing Variable Initialization ===\n");
int uninitialized;
uninitialized = 42;
tc.assertEqual(uninitialized, 42, "variable can be assigned after declaration");
int initialized = 100;
tc.assertEqual(initialized, 100, "initialized variable has correct value");
int multi_a = 1;
int multi_b = 2;
int multi_c = 3;
tc.assertEqual(multi_a + multi_b + multi_c, 6, "multiple variable declarations");
printf("\n=== Testing Loop Boundary Conditions ===\n");
int zero_iterations = 0;
int counter = 0;
while (counter < 0) {
zero_iterations = zero_iterations + 1;
counter = counter + 1;
}
tc.assertEqual(zero_iterations, 0, "while loop with false condition never executes");
int one_iteration = 0;
counter = 0;
while (counter < 1) {
one_iteration = one_iteration + 1;
counter = counter + 1;
}
tc.assertEqual(one_iteration, 1, "while loop executes exactly once");
int many_iterations = 0;
counter = 0;
while (counter < 100) {
many_iterations = many_iterations + 1;
counter = counter + 1;
}
tc.assertEqual(many_iterations, 100, "while loop handles many iterations");
printf("\n=== Testing If-Else Boundary Conditions ===\n");
int if_result = 0;
if (1) {
if_result = 1;
}
tc.assertEqual(if_result, 1, "if with literal true (1)");
if_result = 0;
if (0) {
if_result = 1;
}
tc.assertEqual(if_result, 0, "if with literal false (0)");
if_result = 0;
if (100) {
if_result = 1;
}
tc.assertEqual(if_result, 1, "if with non-zero value (truthy)");
if_result = 0;
if (-1) {
if_result = 1;
}
tc.assertEqual(if_result, 1, "if with negative value (truthy)");
printf("\n=== Testing Function Call Edge Cases ===\n");
int str_len = strlen("");
tc.assertEqual(str_len, 0, "strlen of empty string");
int pos = strpos("hello", "h");
tc.assertEqual(pos, 0, "strpos finds character at start");
pos = strpos("hello", "o");
tc.assertEqual(pos, 4, "strpos finds character at end");
pos = strpos("hello", "x");
tc.assertEqual(pos, -1, "strpos returns -1 for not found");
printf("\n=== Testing Eval Edge Cases ===\n");
int eval_result = eval("0");
tc.assertEqual(eval_result, 0, "eval with zero");
eval_result = eval("1");
tc.assertEqual(eval_result, 1, "eval with one");
eval_result = eval("-1");
tc.assertEqual(eval_result, -1, "eval with negative one");
eval_result = eval("100 + 0");
tc.assertEqual(eval_result, 100, "eval addition with zero");
eval_result = eval("100 * 1");
tc.assertEqual(eval_result, 100, "eval multiplication by one");
eval_result = eval("100 / 1");
tc.assertEqual(eval_result, 100, "eval division by one");
eval_result = eval("100 - 0");
tc.assertEqual(eval_result, 100, "eval subtraction of zero");
printf("\n=== Testing Complex Nested Conditions ===\n");
int nested_result = 0;
if (1) {
if (1) {
if (1) {
nested_result = 3;
}
}
}
tc.assertEqual(nested_result, 3, "triple nested if statements");
nested_result = 0;
if (1) {
if (0) {
nested_result = 1;
} else {
if (1) {
nested_result = 2;
}
}
}
tc.assertEqual(nested_result, 2, "nested if-else combinations");
printf("\n=== Testing Operator Precedence ===\n");
int precedence_result = 2 + 3 * 4;
tc.assertEqual(precedence_result, 14, "multiplication before addition");
precedence_result = 10 - 2 * 3;
tc.assertEqual(precedence_result, 4, "multiplication before subtraction");
precedence_result = (2 + 3) * 4;
tc.assertEqual(precedence_result, 20, "parentheses override precedence");
precedence_result = 2 * 3 + 4 * 5;
tc.assertEqual(precedence_result, 26, "multiple multiplications and additions");
printf("\n=== Testing Assignment Edge Cases ===\n");
int assign_var = 0;
assign_var = 1;
tc.assertEqual(assign_var, 1, "simple reassignment");
assign_var = assign_var + 1;
tc.assertEqual(assign_var, 2, "self-referential assignment");
assign_var = assign_var * 2;
tc.assertEqual(assign_var, 4, "self-multiplication assignment");
int chain_a = 0;
int chain_b = 0;
chain_a = chain_b = 5;
tc.assertEqual(chain_a, 5, "chained assignment first variable");
tc.assertEqual(chain_b, 5, "chained assignment second variable");
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All input validation tests PASSED!\n");
}
return 0;
}
+274
View File
@@ -0,0 +1,274 @@
#include "unittest.rc"
int getValue() {
return 42;
}
int add(int a, int b) {
return a + b;
}
int square(int x) {
int result = x * x;
return result;
}
int max(int a, int b) {
if (a > b) {
return a;
}
return b;
}
int factorial(int n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
int main() {
int tc = new TestCase();
tc.init("Language Features");
printf("\n=== Testing Variables and Data Types ===\n");
int x = 10;
tc.assertEqual(x, 10, "Integer variable assignment");
int y = -5;
tc.assertEqual(y, -5, "Negative integer assignment");
int z = -10;
int sum_neg = y + z;
tc.assertEqual(sum_neg, -15, "Negative number addition: -5 + -10 = -15");
char* str = "hello";
tc.assertStringEqual(str, "hello", "String variable assignment");
printf("\n=== Testing Arithmetic Operators ===\n");
tc.assertEqual(5 + 3, 8, "Addition: 5 + 3 = 8");
tc.assertEqual(10 - 4, 6, "Subtraction: 10 - 4 = 6");
tc.assertEqual(6 * 7, 42, "Multiplication: 6 * 7 = 42");
tc.assertEqual(20 / 4, 5, "Division: 20 / 4 = 5");
tc.assertEqual(15 / 4, 3, "Integer division: 15 / 4 = 3");
printf("\n=== Testing Comparison Operators ===\n");
tc.assertTrue(5 == 5, "Equality: 5 == 5");
tc.assertTrue(5 != 3, "Inequality: 5 != 3");
tc.assertFalse(5 == 3, "Not equal: 5 == 3 is false");
tc.assertFalse(5 != 5, "Same value: 5 != 5 is false");
tc.assertTrue(10 > 5, "Greater than: 10 > 5");
tc.assertFalse(5 > 10, "Not greater: 5 > 10 is false");
tc.assertTrue(3 < 7, "Less than: 3 < 7");
tc.assertFalse(7 < 3, "Not less: 7 < 3 is false");
tc.assertTrue(5 >= 5, "Greater or equal (equal): 5 >= 5");
tc.assertTrue(10 >= 5, "Greater or equal (greater): 10 >= 5");
tc.assertTrue(3 < 5, "3 is less than 5 (not >= 5)");
tc.assertTrue(5 <= 5, "Less or equal (equal): 5 <= 5");
tc.assertTrue(3 <= 5, "Less or equal (less): 3 <= 5");
tc.assertTrue(7 > 5, "7 is greater than 5 (not <= 5)");
printf("\n=== Testing Logical Operators ===\n");
tc.assertTrue(1 && 1, "Logical AND: 1 && 1 = true");
tc.assertFalse(1 && 0, "Logical AND: 1 && 0 = false");
tc.assertFalse(0 && 1, "Logical AND: 0 && 1 = false");
tc.assertFalse(0 && 0, "Logical AND: 0 && 0 = false");
tc.assertTrue(1 || 0, "Logical OR: 1 || 0 = true");
tc.assertTrue(0 || 1, "Logical OR: 0 || 1 = true");
tc.assertTrue(1 || 1, "Logical OR: 1 || 1 = true");
tc.assertFalse(0 || 0, "Logical OR: 0 || 0 = false");
printf("\n=== Testing Control Flow - If/Else ===\n");
int result = 0;
if (5 > 3) {
result = 1;
}
tc.assertEqual(result, 1, "If condition true: 5 > 3");
result = 0;
if (2 > 5) {
result = 1;
} else {
result = 2;
}
tc.assertEqual(result, 2, "Else branch executed: 2 > 5 is false");
result = 0;
if (0) {
result = 1;
} else {
result = 2;
}
tc.assertEqual(result, 2, "If with 0 goes to else");
printf("\n=== Testing Control Flow - While Loop ===\n");
int i = 0;
int count = 0;
while (i < 5) {
count = count + 1;
i = i + 1;
}
tc.assertEqual(count, 5, "While loop executes 5 times");
tc.assertEqual(i, 5, "Loop counter reaches 5");
i = 0;
count = 0;
while (count != 3) {
count = count + 1;
i = i + 1;
}
tc.assertEqual(count, 3, "While with != condition stops at 3");
printf("\n=== Testing Control Flow - Break ===\n");
i = 0;
count = 0;
while (i < 10) {
count = count + 1;
i = i + 1;
if (i == 5) {
i = 10;
}
}
tc.assertEqual(count, 5, "Break exits loop at i=5");
i = 0;
while (i < 10) {
i = i + 1;
if (i == 3) {
if (i < 5) {
i = 10;
}
}
}
tc.assertEqual(i, 10, "Nested if with break");
printf("\n=== Testing Control Flow - Continue ===\n");
i = 0;
count = 0;
while (i < 5) {
i = i + 1;
if (i == 3) {
i = i + 0;
} else {
count = count + 1;
}
}
tc.assertLess(count, 5, "Continue pattern skips iteration");
i = 0;
int sum_val = 0;
while (i < 10) {
i = i + 1;
int skip = 0;
if (i == 3 || i == 7) {
skip = 1;
}
if (skip == 0) {
sum_val = sum_val + i;
}
}
tc.assertLess(sum_val, 55, "Skipping 3 and 7 reduces sum");
printf("\n=== Testing Arrays ===\n");
int arr[5];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
arr[3] = 40;
arr[4] = 50;
tc.assertEqual(arr[0], 10, "Array element [0] = 10");
tc.assertEqual(arr[1], 20, "Array element [1] = 20");
tc.assertEqual(arr[2], 30, "Array element [2] = 30");
tc.assertEqual(arr[3], 40, "Array element [3] = 40");
tc.assertEqual(arr[4], 50, "Array element [4] = 50");
arr[2] = 100;
tc.assertEqual(arr[2], 100, "Array element modification: arr[2] = 100");
i = 0;
int array_sum = 0;
while (i < 5) {
array_sum = array_sum + arr[i];
i = i + 1;
}
tc.assertEqual(array_sum, 220, "Array iteration sum: 10+20+100+40+50 = 220");
int nums[3];
nums[0] = 5;
nums[1] = 10;
nums[2] = 15;
int total = 0;
total = total + nums[0];
total = total + nums[1];
total = total + nums[2];
tc.assertEqual(total, 30, "Array arithmetic: 5+10+15 = 30");
int big[10];
int j = 0;
while (j < 10) {
big[j] = j * j;
j = j + 1;
}
tc.assertEqual(big[0], 0, "Larger array: big[0] = 0^2 = 0");
tc.assertEqual(big[3], 9, "Larger array: big[3] = 3^2 = 9");
tc.assertEqual(big[9], 81, "Larger array: big[9] = 9^2 = 81");
printf("\n=== Testing Pointers ===\n");
int px = 42;
int addr = px;
tc.assertEqual(addr, 42, "Pointer/value assignment");
printf("\n=== Testing Functions ===\n");
int val = getValue();
tc.assertEqual(val, 42, "Function with no parameters: getValue() = 42");
int sum_func = add(5, 3);
tc.assertEqual(sum_func, 8, "Function with parameters: add(5,3) = 8");
int sq = square(7);
tc.assertEqual(sq, 49, "Function with local vars: square(7) = 49");
int m1 = max(15, 20);
tc.assertEqual(m1, 20, "Conditional function: max(15,20) = 20");
int m2 = max(30, 10);
tc.assertEqual(m2, 30, "Conditional function: max(30,10) = 30");
int nested = add(square(3), getValue());
tc.assertEqual(nested, 51, "Nested calls: add(square(3), getValue()) = add(9,42) = 51");
printf("\n=== Testing Double Data Type ===\n");
int d1 = int_to_double(10);
int d2 = int_to_double(3);
int d_sum = double_add(d1, d2);
int sum_int = double_to_int(d_sum);
tc.assertEqual(sum_int, 13, "Double addition: 10.0 + 3.0 = 13.0");
int d_diff = double_sub(d1, d2);
int diff_int = double_to_int(d_diff);
tc.assertEqual(diff_int, 7, "Double subtraction: 10.0 - 3.0 = 7.0");
int d_prod = double_mul(d1, d2);
int prod_int = double_to_int(d_prod);
tc.assertEqual(prod_int, 30, "Double multiplication: 10.0 * 3.0 = 30.0");
int dx = 42;
int dx_double = int_to_double(dx);
int dx_back = double_to_int(dx_double);
tc.assertEqual(dx_back, 42, "Type conversion round-trip: int->double->int");
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All language feature tests PASSED!\n");
}
return 0;
}
+170
View File
@@ -0,0 +1,170 @@
#include "unittest.rc"
class Counter {
int count = 0;
void increment(int self) {
self.count = self.count + 1;
}
void decrement(int self) {
self.count = self.count - 1;
}
void reset(int self) {
self.count = 0;
}
int getCount(int self) {
return self.count;
}
}
class Point {
int x = 10;
int y = 20;
void set(int self, int newX, int newY) {
self.x = newX;
self.y = newY;
}
void move(int self, int dx, int dy) {
self.x = self.x + dx;
self.y = self.y + dy;
}
int getX(int self) {
return self.x;
}
int getY(int self) {
return self.y;
}
}
class BankAccount {
int balance = 0;
int transactions = 0;
void deposit(int self, int amount) {
self.balance = self.balance + amount;
self.transactions = self.transactions + 1;
}
void withdraw(int self, int amount) {
if (self.balance >= amount) {
self.balance = self.balance - amount;
self.transactions = self.transactions + 1;
}
}
int getBalance(int self) {
return self.balance;
}
}
int main() {
int tc = new TestCase();
tc.init("OOP Features");
printf("\n=== Testing Object Creation ===\n");
int counter = new Counter();
tc.assertNotNull(counter, "new Counter() creates object");
int point = new Point();
tc.assertNotNull(point, "new Point() creates object");
printf("\n=== Testing Null Objects ===\n");
int obj = null;
tc.assertNull(obj, "null keyword creates null object");
tc.assertNotEqual(counter, null, "Created object is not null");
printf("\n=== Testing Field Access ===\n");
tc.assertEqual(counter.count, 0, "Counter.count initialized to 0");
tc.assertEqual(point.x, 10, "Point.x initialized to 10");
tc.assertEqual(point.y, 20, "Point.y initialized to 20");
printf("\n=== Testing Field Mutation (Direct) ===\n");
counter.count = 5;
tc.assertEqual(counter.count, 5, "Direct field mutation: counter.count = 5");
point.x = 100;
point.y = 200;
tc.assertEqual(point.x, 100, "Direct field mutation: point.x = 100");
tc.assertEqual(point.y, 200, "Direct field mutation: point.y = 200");
printf("\n=== Testing Method Calls ===\n");
counter.count = 0;
counter.increment();
tc.assertEqual(counter.count, 1, "increment() method works");
counter.increment();
tc.assertEqual(counter.count, 2, "increment() again: count = 2");
counter.decrement();
tc.assertEqual(counter.count, 1, "decrement() method works");
printf("\n=== Testing Method Return Values ===\n");
int count_val = counter.getCount();
tc.assertEqual(count_val, 1, "getCount() returns current count");
int x_val = point.getX();
tc.assertEqual(x_val, 100, "getX() returns current x value");
printf("\n=== Testing Methods with Parameters ===\n");
point.set(50, 75);
tc.assertEqual(point.x, 50, "set() method updates x");
tc.assertEqual(point.y, 75, "set() method updates y");
point.move(10, 20);
tc.assertEqual(point.x, 60, "move() method: x = 50 + 10");
tc.assertEqual(point.y, 95, "move() method: y = 75 + 20");
printf("\n=== Testing Multiple Objects ===\n");
int c1 = new Counter();
int c2 = new Counter();
c1.count = 10;
c2.count = 20;
tc.assertEqual(c1.count, 10, "Object 1 has independent state");
tc.assertEqual(c2.count, 20, "Object 2 has independent state");
c1.increment();
tc.assertEqual(c1.count, 11, "Object 1 increment doesn't affect object 2");
tc.assertEqual(c2.count, 20, "Object 2 remains unchanged");
printf("\n=== Testing Complex Object State ===\n");
int account = new BankAccount();
account.deposit(1000);
tc.assertEqual(account.balance, 1000, "deposit() updates balance");
tc.assertEqual(account.transactions, 1, "deposit() increments transaction count");
account.deposit(500);
tc.assertEqual(account.balance, 1500, "Second deposit: balance = 1500");
tc.assertEqual(account.transactions, 2, "Transaction count = 2");
account.withdraw(300);
tc.assertEqual(account.balance, 1200, "withdraw() reduces balance");
tc.assertEqual(account.transactions, 3, "Transaction count = 3");
int final_balance = account.getBalance();
tc.assertEqual(final_balance, 1200, "getBalance() returns correct value");
printf("\n=== Testing Method State Changes ===\n");
counter.reset();
tc.assertEqual(counter.count, 0, "reset() method resets state to 0");
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All OOP tests PASSED!\n");
}
return 0;
}
+30
View File
@@ -0,0 +1,30 @@
#include "unittest.rc"
int main() {
int tc = new TestCase();
tc.init("Preprocessor");
printf("\n=== Testing #include Directive ===\n");
tc.assertTrue(1, "unittest.rc included successfully");
printf("\n=== Testing Framework Availability ===\n");
int test_obj = new TestCase();
tc.assertNotNull(test_obj, "TestCase class available from included file");
test_obj.init("Nested Test");
tc.assertTrue(1, "Can initialize objects from included classes");
printf("\n=== Testing Multiple Includes ===\n");
tc.assertTrue(1, "Multiple #include directives work");
tc.assertTrue(1, "No duplicate symbol errors");
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All preprocessor tests PASSED!\n");
}
return 0;
}
+162
View File
@@ -0,0 +1,162 @@
#include "unittest.rc"
int main() {
int tc = new TestCase();
tc.init("Robustness Tests");
printf("\n=== Testing Array Bounds Safety ===\n");
int arr[5];
arr[0] = 10;
arr[4] = 50;
tc.assertEqual(arr[0], 10, "Array first element access");
tc.assertEqual(arr[4], 50, "Array last element access");
printf("\n=== Testing Large Arrays ===\n");
int big[1000];
big[0] = 1;
big[999] = 999;
tc.assertEqual(big[0], 1, "Large array first element");
tc.assertEqual(big[999], 999, "Large array last element");
printf("\n=== Testing String Operations ===\n");
char* str1 = "Hello";
char* str2 = "World";
char* combined = str1 + " " + str2;
tc.assertStringContains(combined, "Hello", "String concatenation works");
tc.assertStringContains(combined, "World", "String concatenation includes both");
printf("\n=== Testing Empty Strings ===\n");
char* empty = "";
int empty_len = strlen(empty);
tc.assertEqual(empty_len, 0, "Empty string has zero length");
printf("\n=== Testing String Slicing ===\n");
char* text = "Programming";
char* slice1 = text[0:4];
tc.assertStringEqual(slice1, "Prog", "String slice [0:4]");
char* slice2 = text[0:11];
tc.assertStringEqual(slice2, "Programming", "String slice full length");
printf("\n=== Testing Nested Loops ===\n");
int outer_count = 0;
int i = 0;
while (i < 5) {
int j = 0;
while (j < 3) {
outer_count = outer_count + 1;
j = j + 1;
}
i = i + 1;
}
tc.assertEqual(outer_count, 15, "Nested loops: 5 * 3 = 15");
printf("\n=== Testing Deep Recursion Protection ===\n");
int stack_depth = 0;
int k = 0;
while (k < 100) {
stack_depth = stack_depth + 1;
k = k + 1;
}
tc.assertEqual(stack_depth, 100, "Deep iteration count");
printf("\n=== Testing Variable Initialization ===\n");
int var1 = 0;
int var2 = 0;
int var3 = 0;
int var4 = 0;
int var5 = 0;
var1 = 1;
var2 = 2;
var3 = 3;
var4 = 4;
var5 = 5;
tc.assertEqual(var1 + var2 + var3 + var4 + var5, 15, "Multiple variable sum");
printf("\n=== Testing Expression Safety ===\n");
int a = 10;
int b = 5;
int c = 2;
int result1 = a + b * c;
tc.assertEqual(result1, 20, "Operator precedence: 10 + 5 * 2 = 20");
int result2 = (a + b) * c;
tc.assertEqual(result2, 30, "Parentheses: (10 + 5) * 2 = 30");
printf("\n=== Testing Zero and Negative Values ===\n");
int zero = 0;
int neg = -5;
int pos = 5;
tc.assertEqual(zero, 0, "Zero value");
tc.assertEqual(neg, -5, "Negative value");
tc.assertEqual(pos, 5, "Positive value");
int neg_sum = neg + neg;
tc.assertEqual(neg_sum, -10, "Negative addition: -5 + -5 = -10");
printf("\n=== Testing Printf Safety ===\n");
printf("Testing integer: %d\n", 42);
printf("Testing string: %s\n", "Hello");
printf("Testing mixed: %d %s %d\n", 1, "test", 2);
tc.assertTrue(1, "Printf executes without crash");
printf("\n=== Testing Array Initialization Pattern ===\n");
int nums[10];
int idx = 0;
while (idx < 10) {
nums[idx] = idx * idx;
idx = idx + 1;
}
tc.assertEqual(nums[0], 0, "nums[0] = 0^2 = 0");
tc.assertEqual(nums[3], 9, "nums[3] = 3^2 = 9");
tc.assertEqual(nums[9], 81, "nums[9] = 9^2 = 81");
printf("\n=== Testing String Functions ===\n");
char* test_str = "test string";
int test_len = strlen(test_str);
tc.assertEqual(test_len, 11, "strlen('test string') = 11");
int find_pos = strpos(test_str, "string");
tc.assertEqual(find_pos, 5, "strpos finds 'string' at position 5");
printf("\n=== Testing Conditional Chains ===\n");
int chain_val = 0;
if (a > b) {
if (b > c) {
if (c > 0) {
chain_val = 3;
}
}
}
tc.assertEqual(chain_val, 3, "Triple nested condition");
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All robustness tests PASSED!\n");
}
return 0;
}
+250
View File
@@ -0,0 +1,250 @@
#include "unittest.rc"
async int compute_square(int n) {
int result = n * n;
return result;
}
async int compute_sum(int a, int b) {
int result = a + b;
return result;
}
async int compute_product(int a, int b) {
return a * b;
}
async int slow_computation(int n) {
int total = 0;
int i = 0;
while (i < n) {
total = total + i;
i = i + 1;
}
return total;
}
int main() {
int tc = new TestCase();
tc.init("Async Standard Library");
printf("\n=== Testing Async Function Calls ===\n");
int coro1 = compute_square(5);
tc.assertNotNull(coro1, "Async function returns coroutine handle");
int result1 = await(coro1);
tc.assertEqual(result1, 25, "await() returns result: square(5) = 25");
printf("\n=== Testing Multiple Async Calls ===\n");
int coro2 = compute_sum(10, 20);
int result2 = await(coro2);
tc.assertEqual(result2, 30, "Async sum: 10 + 20 = 30");
int coro3 = compute_sum(5, 15);
int result3 = await(coro3);
tc.assertEqual(result3, 20, "Async sum: 5 + 15 = 20");
int coro4 = compute_product(6, 7);
int result4 = await(coro4);
tc.assertEqual(result4, 42, "Async product: 6 * 7 = 42");
printf("\n=== Testing Gather (Parallel Execution) ===\n");
int coro_a = compute_square(4);
int coro_b = compute_square(5);
int coro_c = compute_square(6);
gather(coro_a);
gather(coro_b);
gather(coro_c);
int res_a = await(coro_a);
int res_b = await(coro_b);
int res_c = await(coro_c);
tc.assertEqual(res_a, 16, "Parallel: square(4) = 16");
tc.assertEqual(res_b, 25, "Parallel: square(5) = 25");
tc.assertEqual(res_c, 36, "Parallel: square(6) = 36");
printf("\n=== Testing Nested Async Calls ===\n");
int coro_x = compute_sum(5, 10);
int intermediate = await(coro_x);
tc.assertEqual(intermediate, 15, "First async call: 5 + 10 = 15");
int coro_y = compute_square(intermediate);
int final_result = await(coro_y);
tc.assertEqual(final_result, 225, "Chained async: square(15) = 225");
printf("\n=== Testing Slow Computations ===\n");
int slow1 = slow_computation(10);
int slow2 = slow_computation(5);
gather(slow1);
gather(slow2);
int slow_res1 = await(slow1);
int slow_res2 = await(slow2);
tc.assertEqual(slow_res1, 45, "slow_computation(10) = sum(0..9) = 45");
tc.assertEqual(slow_res2, 10, "slow_computation(5) = sum(0..4) = 10");
printf("\n=== Testing Multiple Sequential Awaits ===\n");
int seq1 = compute_square(2);
int val1 = await(seq1);
tc.assertEqual(val1, 4, "Sequential 1: square(2) = 4");
int seq2 = compute_sum(val1, 5);
int val2 = await(seq2);
tc.assertEqual(val2, 9, "Sequential 2: 4 + 5 = 9");
int seq3 = compute_product(val2, 3);
int val3 = await(seq3);
tc.assertEqual(val3, 27, "Sequential 3: 9 * 3 = 27");
printf("\n=== Testing Multiple Gather Batches ===\n");
int batch1_a = compute_square(2);
int batch1_b = compute_square(3);
gather(batch1_a);
gather(batch1_b);
int b1a = await(batch1_a);
int b1b = await(batch1_b);
tc.assertEqual(b1a, 4, "Batch 1a: square(2) = 4");
tc.assertEqual(b1b, 9, "Batch 1b: square(3) = 9");
int batch2_a = compute_sum(10, 10);
int batch2_b = compute_sum(20, 20);
gather(batch2_a);
gather(batch2_b);
int b2a = await(batch2_a);
int b2b = await(batch2_b);
tc.assertEqual(b2a, 20, "Batch 2a: 10 + 10 = 20");
tc.assertEqual(b2b, 40, "Batch 2b: 20 + 20 = 40");
printf("\n=== Testing Complex Async Patterns ===\n");
int step1 = compute_square(3);
int s1 = await(step1);
int step2a = compute_sum(s1, 5);
int step2b = compute_product(s1, 2);
gather(step2a);
gather(step2b);
int s2a = await(step2a);
int s2b = await(step2b);
tc.assertEqual(s2a, 14, "Complex pattern: 9 + 5 = 14");
tc.assertEqual(s2b, 18, "Complex pattern: 9 * 2 = 18");
int step3 = compute_sum(s2a, s2b);
int s3 = await(step3);
tc.assertEqual(s3, 32, "Complex pattern final: 14 + 18 = 32");
printf("\n=== Testing Async File I/O ===\n");
char* async_test_file = "/tmp/test_async_io.txt";
char* async_content = "Async test data";
int write_file = fopen(async_test_file, "w");
tc.assertNotNull(write_file, "Open file for async write test");
int async_write_id = async_fwrite(write_file, async_content, strlen(async_content));
tc.assertGreaterEqual(async_write_id, 0, "async_fwrite() returns valid operation ID");
int write_result = async_wait(async_write_id);
tc.assertEqual(write_result, 15, "async_wait() returns bytes written");
fclose(write_file);
int read_file = fopen(async_test_file, "r");
tc.assertNotNull(read_file, "Open file for async read test");
int read_addr = 1000;
int async_read_id = async_fread(read_file, read_addr, 15);
tc.assertGreaterEqual(async_read_id, 0, "async_fread() returns valid operation ID");
int read_result = async_wait(async_read_id);
tc.assertEqual(read_result, 15, "async_wait() returns bytes read");
fclose(read_file);
fremove(async_test_file);
printf("\n=== Testing Async Poll and Result ===\n");
char* poll_test_file = "/tmp/test_async_poll.txt";
int poll_file = fopen(poll_test_file, "w");
fputs(poll_file, "Poll test data");
fclose(poll_file);
poll_file = fopen(poll_test_file, "r");
int poll_addr = 2000;
int poll_id = async_fread(poll_file, poll_addr, 14);
tc.assertGreaterEqual(poll_id, 0, "async_fread() for poll test initiated");
int poll_wait = async_wait(poll_id);
tc.assertEqual(poll_wait, 14, "async_wait() returns correct result");
fclose(poll_file);
fremove(poll_test_file);
printf("\n=== Testing Async Result Without Wait ===\n");
char* result_test_file = "/tmp/test_async_result.txt";
int result_file = fopen(result_test_file, "w");
fputs(result_file, "Result test");
fclose(result_file);
result_file = fopen(result_test_file, "r");
int result_addr = 3000;
int result_id = async_fread(result_file, result_addr, 11);
tc.assertGreaterEqual(result_id, 0, "async_fread() for result test initiated");
int result_poll = 0;
int max_polls = 1000;
int poll_count = 0;
while (result_poll == 0 && poll_count < max_polls) {
result_poll = async_poll(result_id);
poll_count = poll_count + 1;
}
tc.assertTrue(result_poll, "async_poll() eventually returns completion");
int final_result = async_result(result_id);
tc.assertEqual(final_result, 11, "async_result() returns correct bytes after polling");
fclose(result_file);
fremove(result_test_file);
printf("\n=== Testing Multiple Async Operations ===\n");
char* multi_file_1 = "/tmp/test_multi_1.txt";
char* multi_file_2 = "/tmp/test_multi_2.txt";
int mf1 = fopen(multi_file_1, "w");
int mf2 = fopen(multi_file_2, "w");
int mid1 = async_fwrite(mf1, "File 1 data", 11);
int mid2 = async_fwrite(mf2, "File 2 data", 11);
tc.assertGreaterEqual(mid1, 0, "First async write initiated");
tc.assertGreaterEqual(mid2, 0, "Second async write initiated");
int mres1 = async_wait(mid1);
int mres2 = async_wait(mid2);
tc.assertEqual(mres1, 11, "First async write completed");
tc.assertEqual(mres2, 11, "Second async write completed");
fclose(mf1);
fclose(mf2);
fremove(multi_file_1);
fremove(multi_file_2);
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All async stdlib tests PASSED!\n");
}
return 0;
}
+168
View File
@@ -0,0 +1,168 @@
#include "unittest.rc"
int main() {
int tc = new TestCase();
tc.init("Benchmark Standard Library");
printf("\n=== Testing bench_start/bench_end ===\n");
int timer1 = bench_start();
tc.assertGreaterEqual(timer1, 0, "bench_start returns valid timer ID");
int i = 0;
int sum = 0;
while (i < 1000) {
sum = sum + i;
i = i + 1;
}
int elapsed1 = bench_end(timer1);
tc.assertGreater(elapsed1, 0, "bench_end returns positive elapsed time");
tc.assertLess(elapsed1, 1000000000, "elapsed time is less than 1 second");
printf("\n=== Testing multiple timers ===\n");
int timer2 = bench_start();
int timer3 = bench_start();
tc.assertNotEqual(timer2, timer3, "Multiple timers have different IDs");
int elapsed2 = bench_end(timer2);
int elapsed3 = bench_end(timer3);
tc.assertGreater(elapsed2, 0, "Timer 2 has positive elapsed time");
tc.assertGreater(elapsed3, 0, "Timer 3 has positive elapsed time");
printf("\n=== Testing bench_format with nanoseconds ===\n");
char* formatted_ns = bench_format(12345, 0);
tc.assertNotNull(formatted_ns, "bench_format(ns) returns non-null");
tc.assertStringContains(formatted_ns, "ns", "Formatted string contains 'ns'");
tc.assertStringContains(formatted_ns, "12345", "Formatted string contains value");
printf("\n=== Testing bench_format with microseconds ===\n");
char* formatted_us = bench_format(123456, 1);
tc.assertNotNull(formatted_us, "bench_format(us) returns non-null");
tc.assertStringContains(formatted_us, "us", "Formatted string contains 'us'");
printf("\n=== Testing bench_format with milliseconds ===\n");
char* formatted_ms = bench_format(1234567, 2);
tc.assertNotNull(formatted_ms, "bench_format(ms) returns non-null");
tc.assertStringContains(formatted_ms, "ms", "Formatted string contains 'ms'");
printf("\n=== Testing bench_format with seconds ===\n");
char* formatted_s = bench_format(1234567890, 3);
tc.assertNotNull(formatted_s, "bench_format(s) returns non-null");
tc.assertStringContains(formatted_s, "s", "Formatted string contains 's'");
printf("\n=== Testing bench_format with minutes ===\n");
char* formatted_min = bench_format(123456789000, 4);
tc.assertNotNull(formatted_min, "bench_format(min) returns non-null");
tc.assertStringContains(formatted_min, "min", "Formatted string contains 'min'");
printf("\n=== Testing bench_format with hours ===\n");
char* formatted_h = bench_format(7412345678900, 5);
tc.assertNotNull(formatted_h, "bench_format(h) returns non-null");
tc.assertStringContains(formatted_h, "h", "Formatted string contains 'h'");
printf("\n=== Testing bench_format_auto with nanoseconds ===\n");
char* auto_ns = bench_format_auto(500);
tc.assertNotNull(auto_ns, "bench_format_auto(500ns) returns non-null");
tc.assertStringContains(auto_ns, "ns", "Auto-format chooses nanoseconds for small values");
printf("\n=== Testing bench_format_auto with microseconds ===\n");
char* auto_us = bench_format_auto(5000);
tc.assertNotNull(auto_us, "bench_format_auto(5000ns) returns non-null");
tc.assertStringContains(auto_us, "us", "Auto-format chooses microseconds");
printf("\n=== Testing bench_format_auto with milliseconds ===\n");
char* auto_ms = bench_format_auto(5000000);
tc.assertNotNull(auto_ms, "bench_format_auto(5ms) returns non-null");
tc.assertStringContains(auto_ms, "ms", "Auto-format chooses milliseconds");
printf("\n=== Testing bench_format_auto with seconds ===\n");
char* auto_s = bench_format_auto(5000000000);
tc.assertNotNull(auto_s, "bench_format_auto(5s) returns non-null");
tc.assertStringContains(auto_s, "s", "Auto-format chooses seconds");
printf("\n=== Testing bench_format_auto with minutes ===\n");
char* auto_min = bench_format_auto(300000000000);
tc.assertNotNull(auto_min, "bench_format_auto(5min) returns non-null");
tc.assertStringContains(auto_min, "min", "Auto-format chooses minutes");
printf("\n=== Testing bench_format_auto with hours ===\n");
char* auto_h = bench_format_auto(18000000000000);
tc.assertNotNull(auto_h, "bench_format_auto(5h) returns non-null");
tc.assertStringContains(auto_h, "h", "Auto-format chooses hours");
printf("\n=== Testing practical benchmarking scenario ===\n");
int timer_practical = bench_start();
int j = 0;
int factorial = 1;
while (j < 100) {
factorial = factorial + j;
j = j + 1;
}
int elapsed_practical = bench_end(timer_practical);
char* practical_formatted = bench_format_auto(elapsed_practical);
tc.assertGreater(elapsed_practical, 0, "Practical benchmark measured time");
tc.assertNotNull(practical_formatted, "Practical benchmark formatted correctly");
printf(" Practical test took: %s\n", practical_formatted);
printf("\n=== Testing bench_reset ===\n");
int reset_result = bench_reset();
tc.assertEqual(reset_result, 0, "bench_reset returns 0");
int timer_after_reset = bench_start();
tc.assertGreaterEqual(timer_after_reset, 0, "Timer ID valid after reset");
printf("\n=== Testing error cases ===\n");
int invalid_end = bench_end(9999);
tc.assertEqual(invalid_end, -1, "bench_end with invalid timer returns -1");
int negative_timer = bench_end(-1);
tc.assertEqual(negative_timer, -1, "bench_end with negative timer returns -1");
printf("\n=== Testing nested timing ===\n");
int outer_timer = bench_start();
int inner_timer = bench_start();
int k = 0;
while (k < 50) {
k = k + 1;
}
int inner_elapsed = bench_end(inner_timer);
int outer_elapsed = bench_end(outer_timer);
tc.assertGreater(inner_elapsed, 0, "Inner timer measured time");
tc.assertGreater(outer_elapsed, 0, "Outer timer measured time");
tc.assertGreaterEqual(outer_elapsed, inner_elapsed, "Outer timer >= inner timer");
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All benchmark stdlib tests PASSED!\n");
}
return 0;
}
+62
View File
@@ -0,0 +1,62 @@
#include "unittest.rc"
int main() {
int tc = new TestCase();
tc.init("Constants Standard Library");
printf("\n=== Testing Socket Constants ===\n");
int af_inet = AF_INET();
tc.assertGreater(af_inet, 0, "AF_INET constant is defined and positive");
tc.assertEqual(af_inet, 2, "AF_INET equals 2 on most systems");
int sock_stream = SOCK_STREAM();
tc.assertGreater(sock_stream, 0, "SOCK_STREAM constant is defined and positive");
tc.assertEqual(sock_stream, 1, "SOCK_STREAM equals 1 on most systems");
printf("\n=== Testing File Seek Constants ===\n");
int seek_set = SEEK_SET();
tc.assertEqual(seek_set, 0, "SEEK_SET equals 0");
int seek_cur = SEEK_CUR();
tc.assertEqual(seek_cur, 1, "SEEK_CUR equals 1");
int seek_end = SEEK_END();
tc.assertEqual(seek_end, 2, "SEEK_END equals 2");
printf("\n=== Testing Constants Consistency ===\n");
tc.assertNotEqual(af_inet, sock_stream, "AF_INET and SOCK_STREAM are different");
tc.assertNotEqual(seek_set, seek_cur, "SEEK_SET and SEEK_CUR are different");
tc.assertNotEqual(seek_cur, seek_end, "SEEK_CUR and SEEK_END are different");
printf("\n=== Testing Constants Usage ===\n");
char* filename = "/tmp/test_constants.txt";
int file = fopen(filename, "w");
fputs(file, "Testing constants");
fclose(file);
file = fopen(filename, "r");
fseek(file, 0, seek_end);
int size = ftell(file);
tc.assertGreater(size, 0, "SEEK_END used for file size measurement");
fseek(file, 0, seek_set);
int pos = ftell(file);
tc.assertEqual(pos, 0, "SEEK_SET used to return to file start");
fseek(file, 5, seek_cur);
pos = ftell(file);
tc.assertEqual(pos, 5, "SEEK_CUR used for relative positioning");
fclose(file);
fremove(filename);
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All constants stdlib tests PASSED!\n");
}
return 0;
}
+111
View File
@@ -0,0 +1,111 @@
#include "unittest.rc"
int main() {
int tc = new TestCase();
tc.init("I/O Standard Library");
printf("\n=== Testing File Operations ===\n");
char* filename = "/tmp/test_rc_file.txt";
char* content = "Hello, RC!";
int file = fopen(filename, "w");
tc.assertNotNull(file, "fopen() for writing returns valid handle");
int bytes_written = fwrite(file, content, strlen(content));
tc.assertEqual(bytes_written, 10, "fwrite() writes correct number of bytes");
fclose(file);
tc.assertTrue(1, "fclose() completes successfully");
file = fopen(filename, "r");
tc.assertNotNull(file, "fopen() for reading returns valid handle");
char* buffer = " ";
int bytes_read = fread(file, buffer, 10);
tc.assertEqual(bytes_read, 10, "fread() reads correct number of bytes");
fclose(file);
printf("\n=== Testing File Position Operations ===\n");
file = fopen(filename, "r");
tc.assertNotNull(file, "fopen() for seeking test");
int pos = ftell(file);
tc.assertEqual(pos, 0, "ftell() returns 0 at file start");
fseek(file, 5, SEEK_SET());
pos = ftell(file);
tc.assertEqual(pos, 5, "fseek(SEEK_SET, 5) moves to position 5");
fseek(file, 2, SEEK_CUR());
pos = ftell(file);
tc.assertEqual(pos, 7, "fseek(SEEK_CUR, 2) moves 2 bytes forward");
fseek(file, 0, SEEK_END());
pos = ftell(file);
tc.assertEqual(pos, 10, "fseek(SEEK_END, 0) moves to end of file");
char* read_attempt = fgets(file, 10);
int eof = feof(file);
tc.assertTrue(eof, "feof() returns true after read attempt at EOF");
fclose(file);
printf("\n=== Testing fputs/fgets ===\n");
file = fopen(filename, "w");
fputs(file, "Line 1\n");
fputs(file, "Line 2\n");
fclose(file);
tc.assertTrue(1, "fputs() writes lines to file");
file = fopen(filename, "r");
char* line1 = fgets(file, 100);
tc.assertStringContains(line1, "Line 1", "fgets() reads first line");
char* line2 = fgets(file, 100);
tc.assertStringContains(line2, "Line 2", "fgets() reads second line");
fclose(file);
printf("\n=== Testing Socket Constants ===\n");
int af_inet = AF_INET();
tc.assertGreater(af_inet, 0, "AF_INET constant is defined");
int sock_stream = SOCK_STREAM();
tc.assertGreater(sock_stream, 0, "SOCK_STREAM constant is defined");
printf("\n=== Testing File Rename ===\n");
char* old_name = "/tmp/test_rc_old.txt";
char* new_name = "/tmp/test_rc_new.txt";
file = fopen(old_name, "w");
fputs(file, "Rename test");
fclose(file);
int rename_result = frename(old_name, new_name);
tc.assertEqual(rename_result, 0, "frename() succeeds");
file = fopen(new_name, "r");
tc.assertNotNull(file, "Renamed file can be opened");
fclose(file);
printf("\n=== Testing File Remove ===\n");
int remove_result = fremove(new_name);
tc.assertEqual(remove_result, 0, "fremove() succeeds");
file = fopen(new_name, "r");
tc.assertNull(file, "Removed file cannot be opened");
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All I/O stdlib tests PASSED!\n");
}
return 0;
}
+102
View File
@@ -0,0 +1,102 @@
#include "unittest.rc"
int main() {
int tc = new TestCase();
tc.init("Math Standard Library");
printf("\n=== Testing sqrt ===\n");
tc.assertEqual(sqrt(16), 4, "sqrt(16) = 4");
tc.assertEqual(sqrt(25), 5, "sqrt(25) = 5");
tc.assertEqual(sqrt(1), 1, "sqrt(1) = 1");
tc.assertEqual(sqrt(0), 0, "sqrt(0) = 0");
tc.assertEqual(sqrt(100), 10, "sqrt(100) = 10");
printf("\n=== Testing pow ===\n");
tc.assertEqual(pow(2, 3), 8, "pow(2, 3) = 8");
tc.assertEqual(pow(5, 2), 25, "pow(5, 2) = 25");
tc.assertEqual(pow(10, 0), 1, "pow(10, 0) = 1");
tc.assertEqual(pow(3, 4), 81, "pow(3, 4) = 81");
tc.assertEqual(pow(2, 10), 1024, "pow(2, 10) = 1024");
printf("\n=== Testing abs ===\n");
tc.assertEqual(abs(-42), 42, "abs(-42) = 42");
tc.assertEqual(abs(42), 42, "abs(42) = 42");
tc.assertEqual(abs(0), 0, "abs(0) = 0");
tc.assertEqual(abs(-1), 1, "abs(-1) = 1");
tc.assertEqual(abs(-100), 100, "abs(-100) = 100");
printf("\n=== Testing floor/ceil ===\n");
tc.assertEqual(floor(5), 5, "floor(5) = 5");
tc.assertEqual(ceil(5), 5, "ceil(5) = 5");
tc.assertEqual(floor(0), 0, "floor(0) = 0");
tc.assertEqual(ceil(0), 0, "ceil(0) = 0");
printf("\n=== Testing Trigonometry ===\n");
int sin_result = sin(0);
tc.assertEqual(sin_result, 0, "sin(0) = 0");
int cos_result = cos(0);
tc.assertGreater(cos_result, 0, "cos(0) > 0 (fixed-point representation)");
int tan_result = tan(0);
tc.assertEqual(tan_result, 0, "tan(0) = 0");
printf("\n=== Testing Double Operations ===\n");
int d1 = int_to_double(5);
int d2 = int_to_double(3);
int d_sum = double_add(d1, d2);
int result_int = double_to_int(d_sum);
tc.assertEqual(result_int, 8, "Double addition: 5.0 + 3.0 = 8.0");
int d_diff = double_sub(d1, d2);
result_int = double_to_int(d_diff);
tc.assertEqual(result_int, 2, "Double subtraction: 5.0 - 3.0 = 2.0");
int d_prod = double_mul(d1, d2);
result_int = double_to_int(d_prod);
tc.assertEqual(result_int, 15, "Double multiplication: 5.0 * 3.0 = 15.0");
int d_quot = double_div(d1, d2);
result_int = double_to_int(d_quot);
tc.assertEqual(result_int, 1, "Double division: 5.0 / 3.0 = 1.666... (truncated to 1)");
printf("\n=== Testing Random Functions ===\n");
srand(42);
int r1 = rand();
int r2 = rand();
tc.assertNotEqual(r1, r2, "Two consecutive rand() calls should give different values");
tc.assertGreaterEqual(r1, 0, "rand() returns non-negative");
tc.assertGreaterEqual(r2, 0, "rand() returns non-negative");
srand(42);
int r3 = rand();
tc.assertEqual(r1, r3, "Same seed produces same first value");
printf("\n=== Testing rand_range ===\n");
srand(time());
int i = 0;
int range_ok = 1;
while (i < 100) {
int val = rand_range(10, 20);
if (val < 10 || val > 20) {
range_ok = 0;
}
i = i + 1;
}
tc.assertTrue(range_ok, "rand_range(10, 20) returns values in [10, 20]");
printf("\n=== Testing time ===\n");
int t1 = time();
tc.assertGreater(t1, 0, "time() returns positive timestamp");
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All math stdlib tests PASSED!\n");
}
return 0;
}
+86
View File
@@ -0,0 +1,86 @@
#include "unittest.rc"
int main() {
int tc = new TestCase();
tc.init("Socket Standard Library");
printf("\n=== Testing Socket Creation ===\n");
int sockfd = socket(AF_INET(), SOCK_STREAM(), 0);
tc.assertGreaterEqual(sockfd, 0, "socket() creates valid socket descriptor");
printf("\n=== Testing Socket Bind ===\n");
int port = 9876;
int bind_result = bind(sockfd, port);
tc.assertEqual(bind_result, 0, "bind() succeeds on valid port");
printf("\n=== Testing Socket Listen ===\n");
int listen_result = listen(sockfd, 5);
tc.assertEqual(listen_result, 0, "listen() succeeds with backlog of 5");
printf("\n=== Testing Socket Close ===\n");
int close_result = close(sockfd);
tc.assertEqual(close_result, 0, "close() succeeds on valid socket");
printf("\n=== Testing Socket Operations on Different Port ===\n");
int sockfd2 = socket(AF_INET(), SOCK_STREAM(), 0);
tc.assertGreaterEqual(sockfd2, 0, "Second socket creation succeeds");
int port2 = 9877;
bind_result = bind(sockfd2, port2);
tc.assertEqual(bind_result, 0, "bind() on different port succeeds");
listen_result = listen(sockfd2, 10);
tc.assertEqual(listen_result, 0, "listen() with backlog of 10 succeeds");
close_result = close(sockfd2);
tc.assertEqual(close_result, 0, "close() on second socket succeeds");
printf("\n=== Testing Socket Error Conditions ===\n");
int invalid_sock = -1;
close_result = close(invalid_sock);
tc.assertEqual(close_result, -1, "close() fails on invalid socket descriptor");
printf("\n=== Testing Multiple Socket Creation ===\n");
int sock_a = socket(AF_INET(), SOCK_STREAM(), 0);
int sock_b = socket(AF_INET(), SOCK_STREAM(), 0);
int sock_c = socket(AF_INET(), SOCK_STREAM(), 0);
tc.assertGreaterEqual(sock_a, 0, "First socket in batch created");
tc.assertGreaterEqual(sock_b, 0, "Second socket in batch created");
tc.assertGreaterEqual(sock_c, 0, "Third socket in batch created");
tc.assertNotEqual(sock_a, sock_b, "Socket descriptors are unique (a vs b)");
tc.assertNotEqual(sock_b, sock_c, "Socket descriptors are unique (b vs c)");
tc.assertNotEqual(sock_a, sock_c, "Socket descriptors are unique (a vs c)");
close(sock_a);
close(sock_b);
close(sock_c);
tc.assertTrue(1, "All batch sockets closed");
printf("\n=== Testing Socket Reuse After Close ===\n");
int sock_x = socket(AF_INET(), SOCK_STREAM(), 0);
tc.assertGreaterEqual(sock_x, 0, "Socket created before close");
bind(sock_x, 9878);
listen(sock_x, 5);
close(sock_x);
int sock_y = socket(AF_INET(), SOCK_STREAM(), 0);
tc.assertGreaterEqual(sock_y, 0, "Socket created after previous close");
int reuse_bind = bind(sock_y, 9878);
tc.assertEqual(reuse_bind, 0, "Can bind to same port after close with SO_REUSEADDR");
close(sock_y);
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All socket stdlib tests PASSED!\n");
}
return 0;
}
+82
View File
@@ -0,0 +1,82 @@
#include "unittest.rc"
int main() {
int tc = new TestCase();
tc.init("String Standard Library");
printf("\n=== Testing strlen ===\n");
tc.assertEqual(strlen("hello"), 5, "strlen('hello') = 5");
tc.assertEqual(strlen(""), 0, "strlen('') = 0");
tc.assertEqual(strlen("a"), 1, "strlen('a') = 1");
tc.assertEqual(strlen("hello world"), 11, "strlen('hello world') = 11");
printf("\n=== Testing strpos ===\n");
tc.assertEqual(strpos("hello", "e"), 1, "strpos('hello', 'e') = 1");
tc.assertEqual(strpos("hello", "l"), 2, "strpos('hello', 'l') = 2");
tc.assertEqual(strpos("hello", "o"), 4, "strpos('hello', 'o') = 4");
tc.assertEqual(strpos("hello", "x"), -1, "strpos('hello', 'x') = -1 (not found)");
tc.assertEqual(strpos("hello", "hello"), 0, "strpos('hello', 'hello') = 0");
printf("\n=== Testing substr ===\n");
tc.assertStringEqual(substr("hello", 0, 5), "hello", "substr('hello', 0, 5) = 'hello'");
tc.assertStringEqual(substr("hello", 1, 5), "ello", "substr('hello', 1, 5) = 'ello'");
tc.assertStringEqual(substr("hello", 0, 2), "he", "substr('hello', 0, 2) = 'he'");
tc.assertStringEqual(substr("hello world", 6, 11), "world", "substr('hello world', 6, 11) = 'world'");
printf("\n=== Testing String Slicing ===\n");
char* text = "Programming";
tc.assertStringEqual(text[0:4], "Prog", "String slice [0:4] = 'Prog'");
tc.assertStringEqual(text[0:7], "Program", "String slice [0:7] = 'Program'");
printf("\n=== Testing upper/lower ===\n");
tc.assertStringEqual(upper("hello"), "HELLO", "upper('hello') = 'HELLO'");
tc.assertStringEqual(upper("HeLLo"), "HELLO", "upper('HeLLo') = 'HELLO'");
tc.assertStringEqual(lower("HELLO"), "hello", "lower('HELLO') = 'hello'");
tc.assertStringEqual(lower("HeLLo"), "hello", "lower('HeLLo') = 'hello'");
printf("\n=== Testing strip ===\n");
tc.assertStringEqual(strip(" hello "), "hello", "strip(' hello ') = 'hello'");
tc.assertStringEqual(strip("hello"), "hello", "strip('hello') = 'hello'");
tc.assertStringEqual(strip(" hello"), "hello", "strip(' hello') = 'hello'");
tc.assertStringEqual(strip("hello "), "hello", "strip('hello ') = 'hello'");
printf("\n=== Testing startswith/endswith ===\n");
tc.assertTrue(startswith("hello", "he"), "startswith('hello', 'he') = true");
tc.assertFalse(startswith("hello", "ho"), "startswith('hello', 'ho') = false");
tc.assertTrue(endswith("hello", "lo"), "endswith('hello', 'lo') = true");
tc.assertFalse(endswith("hello", "he"), "endswith('hello', 'he') = false");
printf("\n=== Testing replace ===\n");
tc.assertStringEqual(replace("hello world", "world", "there"), "hello there", "replace('hello world', 'world', 'there')");
tc.assertStringEqual(replace("aaa", "a", "b"), "bbb", "replace('aaa', 'a', 'b') replaces all occurrences");
printf("\n=== Testing String Concatenation ===\n");
char* hello = "Hello";
char* world = " World";
char* result = hello + world;
tc.assertStringEqual(result, "Hello World", "String concatenation: 'Hello' + ' World'");
printf("\n=== Testing assertStringContains ===\n");
tc.assertStringContains("hello world", "world", "'hello world' contains 'world'");
tc.assertStringContains("hello world", "hello", "'hello world' contains 'hello'");
tc.assertStringContains("hello world", "o w", "'hello world' contains 'o w'");
printf("\n=== Testing strcmp ===\n");
tc.assertEqual(strcmp("hello", "hello"), 0, "strcmp('hello', 'hello') = 0 (equal)");
tc.assertLess(strcmp("abc", "xyz"), 0, "strcmp('abc', 'xyz') < 0 (abc before xyz)");
tc.assertGreater(strcmp("xyz", "abc"), 0, "strcmp('xyz', 'abc') > 0 (xyz after abc)");
tc.assertEqual(strcmp("test", "test"), 0, "strcmp('test', 'test') = 0");
tc.assertNotEqual(strcmp("hello", "world"), 0, "strcmp('hello', 'world') != 0");
tc.assertLess(strcmp("a", "b"), 0, "strcmp('a', 'b') < 0");
tc.assertGreater(strcmp("z", "a"), 0, "strcmp('z', 'a') > 0");
printf("\n=== Summary ===\n");
printf("Total Passed: %d\n", tc.passed);
printf("Total Failed: %d\n", tc.failed);
if (tc.failed == 0) {
printf("All string stdlib tests PASSED!\n");
}
return 0;
}
-49
View File
@@ -1,49 +0,0 @@
int main() {
printf("=== Trigonometric Functions Tests ===\n");
printf("Note: Results are scaled by 1,000,000\n");
printf("Test 1: sin() function\n");
int sin0 = sin(0);
printf("sin(0) * 1000000 = %d\n", sin0);
int sin1 = sin(1);
printf("sin(1) * 1000000 = %d\n", sin1);
int sin2 = sin(2);
printf("sin(2) * 1000000 = %d\n", sin2);
printf("PASS: sin() function works\n");
printf("Test 2: cos() function\n");
int cos0 = cos(0);
printf("cos(0) * 1000000 = %d\n", cos0);
int cos1 = cos(1);
printf("cos(1) * 1000000 = %d\n", cos1);
int cos2 = cos(2);
printf("cos(2) * 1000000 = %d\n", cos2);
printf("PASS: cos() function works\n");
printf("Test 3: tan() function\n");
int tan0 = tan(0);
printf("tan(0) * 1000000 = %d\n", tan0);
int tan1 = tan(1);
printf("tan(1) * 1000000 = %d\n", tan1);
printf("PASS: tan() function works\n");
printf("Test 4: Multiple angles\n");
int i = 0;
while (i < 4) {
int s = sin(i);
int c = cos(i);
printf("Angle %d: sin = %d, cos = %d\n", i, s, c);
i = i + 1;
}
printf("PASS: Multiple angle calculations work\n");
printf("Test 5: Trig with negative values\n");
int sinNeg = sin(-1);
printf("sin(-1) * 1000000 = %d\n", sinNeg);
int cosNeg = cos(-1);
printf("cos(-1) * 1000000 = %d\n", cosNeg);
printf("PASS: Negative angle calculations work\n");
printf("\n=== All Trigonometric Tests Completed ===\n");
return 0;
}
+276
View File
@@ -0,0 +1,276 @@
class TestCase {
char* name = null;
int passed = 0;
int failed = 0;
int verbose = 0;
int failfast = 0;
void init(int self, char* test_name) {
self.name = test_name;
self.passed = 0;
self.failed = 0;
self.verbose = 0;
self.failfast = 0;
}
void setUp(int self) {
}
void tearDown(int self) {
}
void assertEqual(int self, int actual, int expected, char* msg) {
if (actual == expected) {
self.passed = self.passed + 1;
printf(" ✓ PASS: %s\n", msg);
} else {
self.failed = self.failed + 1;
printf(" ✗ FAIL: %s (expected %d, got %d)\n", msg, expected, actual);
if (self.failfast == 1) {
printf("\nFailing fast due to -f flag\n");
return;
}
}
}
void assertNotEqual(int self, int actual, int expected, char* msg) {
if (actual != expected) {
self.passed = self.passed + 1;
printf(" ✓ PASS: %s\n", msg);
} else {
self.failed = self.failed + 1;
printf(" ✗ FAIL: %s (expected not equal to %d)\n", msg, expected);
if (self.failfast == 1) {
printf("\nFailing fast due to -f flag\n");
return;
}
}
}
void assertTrue(int self, int value, char* msg) {
if (value != 0) {
self.passed = self.passed + 1;
printf(" ✓ PASS: %s\n", msg);
} else {
self.failed = self.failed + 1;
printf(" ✗ FAIL: %s (expected true, got false)\n", msg);
if (self.failfast == 1) {
printf("\nFailing fast due to -f flag\n");
return;
}
}
}
void assertFalse(int self, int value, char* msg) {
if (value == 0) {
self.passed = self.passed + 1;
printf(" ✓ PASS: %s\n", msg);
} else {
self.failed = self.failed + 1;
printf(" ✗ FAIL: %s (expected false, got true)\n", msg);
if (self.failfast == 1) {
printf("\nFailing fast due to -f flag\n");
return;
}
}
}
void assertGreater(int self, int actual, int threshold, char* msg) {
if (actual > threshold) {
self.passed = self.passed + 1;
printf(" ✓ PASS: %s\n", msg);
} else {
self.failed = self.failed + 1;
printf(" ✗ FAIL: %s (expected > %d, got %d)\n", msg, threshold, actual);
if (self.failfast == 1) {
printf("\nFailing fast due to -f flag\n");
return;
}
}
}
void assertLess(int self, int actual, int threshold, char* msg) {
if (actual < threshold) {
self.passed = self.passed + 1;
printf(" ✓ PASS: %s\n", msg);
} else {
self.failed = self.failed + 1;
printf(" ✗ FAIL: %s (expected < %d, got %d)\n", msg, threshold, actual);
if (self.failfast == 1) {
printf("\nFailing fast due to -f flag\n");
return;
}
}
}
void assertGreaterEqual(int self, int actual, int threshold, char* msg) {
if (actual >= threshold) {
self.passed = self.passed + 1;
printf(" ✓ PASS: %s\n", msg);
} else {
self.failed = self.failed + 1;
printf(" ✗ FAIL: %s (expected >= %d, got %d)\n", msg, threshold, actual);
if (self.failfast == 1) {
printf("\nFailing fast due to -f flag\n");
return;
}
}
}
void assertLessEqual(int self, int actual, int threshold, char* msg) {
if (actual <= threshold) {
self.passed = self.passed + 1;
printf(" ✓ PASS: %s\n", msg);
} else {
self.failed = self.failed + 1;
printf(" ✗ FAIL: %s (expected <= %d, got %d)\n", msg, threshold, actual);
if (self.failfast == 1) {
printf("\nFailing fast due to -f flag\n");
return;
}
}
}
void assertStringEqual(int self, char* actual, char* expected, char* msg) {
int len_a = strlen(actual);
int len_b = strlen(expected);
int equal = 0;
if (len_a == len_b) {
equal = 1;
int i = 0;
while (i < len_a) {
char* char_a = actual[i:i+1];
char* char_b = expected[i:i+1];
int pos = strpos(char_a, char_b);
if (pos != 0) {
equal = 0;
}
i = i + 1;
}
}
if (equal == 1) {
self.passed = self.passed + 1;
printf(" ✓ PASS: %s\n", msg);
} else {
self.failed = self.failed + 1;
printf(" ✗ FAIL: %s (expected '%s', got '%s')\n", msg, expected, actual);
if (self.failfast == 1) {
printf("\nFailing fast due to -f flag\n");
return;
}
}
}
void assertStringContains(int self, char* haystack, char* needle, char* msg) {
int pos = strpos(haystack, needle);
if (pos >= 0) {
self.passed = self.passed + 1;
printf(" ✓ PASS: %s\n", msg);
} else {
self.failed = self.failed + 1;
printf(" ✗ FAIL: %s (expected '%s' to contain '%s')\n", msg, haystack, needle);
if (self.failfast == 1) {
printf("\nFailing fast due to -f flag\n");
return;
}
}
}
void assertNull(int self, int value, char* msg) {
if (value == null) {
self.passed = self.passed + 1;
printf(" ✓ PASS: %s\n", msg);
} else {
self.failed = self.failed + 1;
printf(" ✗ FAIL: %s (expected null, got %d)\n", msg, value);
if (self.failfast == 1) {
printf("\nFailing fast due to -f flag\n");
return;
}
}
}
void assertNotNull(int self, int value, char* msg) {
if (value != null) {
self.passed = self.passed + 1;
printf(" ✓ PASS: %s\n", msg);
} else {
self.failed = self.failed + 1;
printf(" ✗ FAIL: %s (expected not null)\n", msg);
if (self.failfast == 1) {
printf("\nFailing fast due to -f flag\n");
return;
}
}
}
}
class TestRunner {
int total_passed = 0;
int total_failed = 0;
int verbose = 0;
int quiet = 0;
int failfast = 0;
void init(int self, int verbosity_mode) {
self.total_passed = 0;
self.total_failed = 0;
if (verbosity_mode == 1) {
self.verbose = 1;
self.quiet = 0;
} else if (verbosity_mode == 2) {
self.verbose = 0;
self.quiet = 1;
} else if (verbosity_mode == 3) {
self.verbose = 0;
self.quiet = 0;
self.failfast = 1;
} else {
self.verbose = 0;
self.quiet = 0;
}
}
void runTest(int self, int test_case, char* test_name) {
int tc = test_case;
tc.verbose = self.verbose;
tc.failfast = self.failfast;
if (self.quiet == 0) {
printf("\n=== Running %s ===\n", test_name);
}
self.total_passed = self.total_passed + tc.passed;
self.total_failed = self.total_failed + tc.failed;
if (self.quiet == 0) {
if (tc.failed == 0) {
printf("OK (%d tests)\n", tc.passed);
} else {
printf("FAILED (passed=%d, failed=%d)\n", tc.passed, tc.failed);
}
}
}
void printSummary(int self) {
printf("\n");
printf("======================\n");
printf("Test Summary\n");
printf("======================\n");
printf("Total Passed: %d\n", self.total_passed);
printf("Total Failed: %d\n", self.total_failed);
printf("======================\n");
if (self.total_failed == 0) {
printf("All tests PASSED!\n");
} else {
printf("Some tests FAILED\n");
}
}
}