Skip to content

fix/feat: dev branch sync — parser fixes, optimizations & repo templates#24

Open
senioritaelizabeth wants to merge 53 commits into
mainfrom
dev
Open

fix/feat: dev branch sync — parser fixes, optimizations & repo templates#24
senioritaelizabeth wants to merge 53 commits into
mainfrom
dev

Conversation

@senioritaelizabeth
Copy link
Copy Markdown
Collaborator

Merges accumulated dev changes into main. Highlights:

Fixes:

  • Number to Bool coercion
  • Invalid switch-case syntax
  • Early return syntax
  • Anonymous functions (function/func keywords)
  • Default function arguments (Default Function Arguments are Invalid #21)
  • Switch statements accepting both : and => syntax
  • Safety checks with performance considerations

Optimizations:

  • Hot path improvements
  • Native object field caching
  • Member-by-ID cache to bypass name resolution
  • Compiler optimizations added (disabled by default, exported to Interpreter)

Misc:

  • Added GitHub issue & PR templates
  • All tests passing

senioritaelizabeth and others added 30 commits May 2, 2026 20:16
Patch a bug where property getters fields would not be fetched.
Fix Field Returns for Getters and Setters
Unmerged change fixing returning null and bool for values.
Small oversight on syntax format where the parser would expect only ```switch (b) {}```
Edge case with return not working when Void.

```if(true) return; // Invalid```
Patch Invalid Switch and Return Syntax
- Added parseAnonymousFunc() to handle Haxe-style anonymous functions
- Updated parsePrimary() to recognize TKeyword(KFunction) and TKeyword(KFunc)
- Added test cases in BugFixTest for issue #22
- Both function(x) { } and func(x) { } syntax now work correctly
- Added defaultValue field to Param typedef in AST.hx
- Modified parseParameters() to parse optional = expression after type hints
- Added paramDefaults field to FunctionChunk to store default values
- Updated Compiler to pre-compile default values as constants
- Modified VM (callFunction and OP_CALL) to use defaults when args are missing
- Updated BytecodeSerializer to serialize/deserialize paramDefaults
- Added Issue21Test with comprehensive test cases

Both simple literals (numbers, strings, bools, null) and the example from the issue now work correctly.
- Updated parseMatchExpression() to accept ':' or '=>' after case patterns
- Updated parseMatch() to accept ':' or '=>' after case/default patterns
- Fixes 17 failing tests in TestSuite that use => syntax

Optimization: Cache Type.getInstanceFields() calls in MemberResolver

- Added static nativeFieldsCache to store instance fields by class name
- Added getNativeInstanceFields() helper that uses the cache
- Replaces expensive Type.getInstanceFields() call in hot path
- Critical performance fix: avoids scanning class fields on every native object access
- Cache persists across flush() calls for maximum performance
VM Optimizations:
- Optimized callFunction: single loop for args+defaults instead of multiple loops
- Optimized OP_CALL: combined defaults+locals initialization loop
- Removed redundant variable declarations in hot paths
- Added #if nx_profile profiling support:
  * instructionCount: tracks execution frequency per opcode
  * callCount: total function calls
  * nativeCallCount: native function calls
  * memberAccessCount: member access operations
  * printProfileReport(): prints detailed profiling report

Main.hx Changes:
- Watch mode (hot reload) now requires #if SYS compilation flag
- Prevents accidental use in production builds
- Shows error message when watch mode unavailable

Profiling Usage:
  haxe -D nx_profile build.hxml
  Then call vm.printProfileReport() to see breakdown

Performance impact: Zero overhead when nx_profile not enabled
Bug Fixes:
- Fixed syntax error in VM.hx (misplaced printProfileReport function)
- All 243 tests now passing (previously 3 sandbox tests were failing)

Optimization - Native Object Field Caching (MemberResolver.hx):
- Added nativeFieldValueCache for direct field value caching
- Avoids Reflection.getField() calls on repeated field access
- Cache invalidation on setMember for consistency
- Significant performance improvement for native object hot paths

Profiling Support (VM.hx):
- Fixed printProfileReport() placement in VM class
- Added profiling counters for native calls and member accesses
- Usage: compile with -D nx_profile, call vm.printProfileReport()

Test Coverage:
- Added ProfileTest.hx for profiling demonstration
1. Stack Overflow Check (NXDEBUG only):
   - Added checkStackOverflow() inline function
   - Only active in debug builds (-D NXDEBUG)
   - Zero overhead in release builds

2. Code IP Bounds Check (NXDEBUG only):
   - Validates ip < code.length before access
   - Prevents crash on corrupt bytecode
   - Debug-only for performance

3. Division by Zero (NXDEBUG only):
   - Throws 'Are we, are.... are... are we deadass?' in debug mode
   - Release mode: IEEE 754 behavior (Inf/NaN)
   - Matches JS/Haxe float behavior in production

4. Constant Index Bounds (NXDEBUG only):
   - Validates constants[arg] access
   - Debug-only for performance

5. Null Check for currentLocalVars:
   - Added null check before EMPTY_MAP comparison
   - Always active (minimal overhead)
   - Prevents null pointer exception

Performance Impact:
- All bounds checks wrapped in #if NXDEBUG
- Zero overhead in release builds
- Debug builds get full safety validation

Tests: 243/243 passing ✅
Added optimization passes to the compiler:

1. Constant Folding:
   - Arithmetic on literals computed at compile time
   - Supports: +, -, *, / for numbers
   - String concatenation folding
   - Boolean && and || folding

2. Peephole Optimization:
   - Removes redundant POP + LOAD_NULL sequences
   - Folds consecutive LOAD_CONST + arithmetic
   - Removes no-op JUMP instructions
   - Multiple pass optimization (up to 10 iterations)

3. Dead Code Elimination:
   - Removes unreachable code after RETURN/THROW
   - Detects jump targets to avoid removing labels

Configuration:
- compiler.optimize = false (default, safe)
- compiler.dce = true
- compiler.constantFolding = true
- compiler.peephole = true

To enable: var compiler = new Compiler(); compiler.optimize = true;

Performance:
- Zero overhead when disabled (default)
- Expected 10-30% improvement on compute-heavy code when enabled
- Safe mode: all tests pass with optimizations disabled

Future work:
- Debug enum handling with optimizations enabled
- Add more folding operations (comparison, etc.)
- Benchmark performance gains
Added public optimization flags to Interpreter:
- optimize: Bool (default false)
- optimizeDCE: Bool (default true)
- optimizeConstantFolding: Bool (default true)
- optimizePeephole: Bool (default true)

Usage:
  var interp = new Interpreter();
  interp.optimize = true;  // Enable all optimizations
  interp.run(sourceCode);

The compile() and run() methods now apply these settings
to the Compiler instance automatically.

All tests pass with optimizations enabled (243/243) ✅

Added enum optimization tests to verify enum variant
access works correctly with optimizations enabled.
Added nativeMemberByIdCache: IntMap<Value> per native object that maps
memberId directly to cached Value, completely bypassing:
- vm.resolveMemberName() string lookup
- instanceFields.indexOf() linear search
- Reflection.getField() on subsequent accesses

Cache hierarchy (checked in order):
1. nativeMemberByIdCache (FASTEST - direct memberId lookup)
2. nativeObjectMethodCache (method wrappers)
3. nativeFieldValueCache (field values by memberId)
4. Fallback to reflection (slow path)

All caches are populated on first access and invalidated on setMember.

Expected performance improvement:
- 50-70% reduction in getMemberById overhead
- Eliminates string operations in hot path
- O(1) direct integer key lookup vs O(n) string search

Tests: 243/243 passing ✅
Add .github templates for community contributions:

- bug_report
- feature_request
- support
- rfc
- pull_request
Major performance improvements for native object member access:

- VM.hx: Inline GET_MEMBER/SET_MEMBER for VNativeObject - bypasses MemberResolver overhead entirely
  - Direct __Field/__SetField calls with paccAlways
  - No more function call overhead for native field access
  - ~20% performance improvement on native-heavy workloads

- Reflection.hx: Simplified getField() and isFunction()
  - getField: Only paccAlways (no fallback chain)
  - isFunction: Uses ObjectType.vtFunction directly

- MemberResolver.hx: Simplified to single nativeCache
  - Removed complex cache hierarchy (nativeFieldValueCache, nativeFieldKindCache, etc)
  - Single obj -> (memberId -> Value) cache

Thanks to @RapperGF for changing the code and helping with this

- Tokenizer.hx: Added 'final' as KVar alias for Haxe compatibility  - Thx @toffeecaramel to report

- Parser.hx: Fixed switch statement body parsing
  - Removed unnecessary semicolon requirement after switch cases - Thx to Jake to report it

All 243 tests passing.
- Add Interpreter.parent and VM.parent for Haxe object scope chain
- Variable lookup: local → parent object fields → global scope
- Variable assignment writes back to parent object fields when they exist
- Add sandbox blocklist checks in GET_MEMBER opcode and MemberResolver
- Parent reference preserved across reset_context()
- Add withParent() fluent API
Test organization:
- Create unit/, integration/, regression/, benchmarks/ folders
- Move ParentScopeTest to integration/ (formerly MyFuckingSillyAss.hx)
- Move ScriptData to unit/ (formerly script.hx)
- Move Issue21/22 and BugFix tests to regression/
- Move SpeedCheck to benchmarks/
- Add README.md with test organization docs

API improvements:
- Change parent scope API from withParent() to property setter
- Usage: interp.parent = obj (cleaner, more idiomatic)
- Add getter/setter to sync VM.parent automatically
- Improve documentation with examples

Test improvements:
- Rename MyFuckingSillyAss → ParentScopeTest
- Clean up test code, remove profanity
- Add proper trace output (PASS/FAIL format)
- Test all three features: var assignment, function calls
Test folder structure:
- test/tests/unit/ - Unit tests (BasicTest, ClassesTest, MethodsTest, etc.)
- test/tests/integration/ - Haxe↔Script integration tests
- test/tests/regression/ - Bug fixes and issue tests
- test/tests/benchmarks/ - Performance benchmarks
- test/tests/config/ - .hxml configuration files

New tool:
- tools/FixTestPackages.hx - Auto-fixes package statements
  Usage: haxe -main FixTestPackages --interp -cp tools

Changes:
- Move 14 unit tests to unit/ folder
- Move TestSuite to unit/ and update package
- Move .hxml files to config/ with corrected paths
- All packages now match folder structure
- README.md documents test organization

Run tests:
  cd test/tests
  haxe config/test_suite.hxml
- Main.hx: test command now uses config/test_suite.hxml
- ci.yml: Updated test_suite.hxml and static_preprocessor.hxml paths
- Both now correctly reference test/tests/config/*.hxml
senioritaelizabeth and others added 23 commits May 14, 2026 16:12
Split test execution into separate steps for better visibility:
- basic, classes, methods, switchcases
- bugfix (regression tests)
- imports, errors, haxeparser
- bridge_using, static_preprocessor

This way each test suite shows individually in GitHub Actions
and failures are easier to diagnose.
When resolving variable names, built-in natives (trace, print, etc) should
always take priority over parent scope fields. This prevents shadowing issues
where a parent object has a field with the same name as a builtin.

Changes:
- VM.hx LOAD_VAR: Check globals/natives BEFORE parent
- VM.hx getVariable: Check globals/natives BEFORE parent
- VM.hx getById: Prefer natives over slot values for same name
- VM.hx getGlobalId: Allocate slots for natives on demand
- VM.hx bindGlobalSlots: Initialize slots from natives if available
- VM.hx syncGlobalSlotsFromMap: Sync from natives too

Fixes regression where parent.trace (Int) shadows the trace() builtin.
- callMethod() now uses getVariableNoParent() to avoid resolving parent fields like FlxSignal
- Added getVariableNoParent() for script-only variable resolution
- Added getVariableOnlyParent() for fallback parent-only resolution (unused currently)
- LOAD_VAR now throws 'Undefined variable' when variable not found (was returning null)
- All 243 tests passing
- 1/0 returns INF, doesn't crash
- Changed test to use explicit throw for runtime error test
Refactor type checking for cpp to always return 'Object'.
Simplify cpp type check to always return 'Object'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants