Skip to content

ASFv3.1.2

Latest

Choose a tag to compare

@ws-garcia ws-garcia released this 18 Feb 03:11
· 24 commits to main since this release
32d9961

Summary

ASF v3.1.2 introduces groundbreaking COM Object Monkey Patching capabilities, allowing runtime extension of native Office objects with custom JavaScript-like methods. This release transforms how developers interact with Excel, Word, and PowerPoint objects by enabling modern functional programming patterns directly on COM interfaces.


Highlights

  • Added

    • COM Object Prototype System — Runtime monkey patching for native Office objects with JavaScript-like method injection:

      // Extend Excel ListRow objects with custom methods
      prototype.COM.ListRow asDictionary() {
          let headers = this.parent.listcolumns;
          let values = this.range.value2;
          let result = {};
          for (let i = 1, i <= headers.count, i+=1) {
              result.set(headers.item(i).name, values[1][i]);
          };
          return result;
      };
      
      // Usage: Native ListRows now have .asDictionary() method
      let data = $1.Sheets(1).ListObjects('Table1').ListRows.map(
          fun(row) { return row.asDictionary().get('email'); }
      );
    • Context-Aware this Binding — Proper this context preservation for COM prototype methods:

      prototype.COM.Range formatCurrency() {
          this.NumberFormat = "$#,##0.00";
          this.Font.Bold = true;
          return this;  // Enable method chaining
      };
      
      // `this` correctly references the Range object
      $1.Sheets(1).Range('A1:A10').formatCurrency();
    • Collection Method Override — Transform VBA Collections into JavaScript-like arrays:

      ' Enable dangerous but powerful collection override
      engine.OverrideCollMethods = True
      
      ' Now VBA Collections support array methods
      engine.Compile("$1.Sheets(1).ListObjects('Table1').ListRows.filter(fun(row) { return row.Range.Cells(1,1).Value > 100; })")
    • Dynamic Method Registration API — Programmatic registration of COM prototype methods:

      ' Internal API for method registration
      VM.RegisterCOMPrototype "ListRow", "asDictionary", funcIndex, params
      
      ' Automatic registration via prototype syntax
      engine.Compile("prototype.COM.Range highlight() { this.Interior.Color = 65535; return this; }")
  • Fixed

    • Option Base Inconsistency — Resolved __option_base mismatch causing "Index out of bounds" errors
    • Scope Context Isolation — Proper scope management for COM prototype method execution
  • Enhanced

    • Office Object Integration — Seamless integration with all Office application object models
    • Method Chaining Support — Enable fluent interfaces on COM objects
  • Internal core changes:

    • Compiler (ASF_Compiler.cls):

      • Added ParsePrototypeStatement() for prototype.COM.<Type> method() syntax
      • Enhanced AST generation with Prototype nodes
      • Implemented automatic method name generation for prototype registration
    • VM (ASF_VM.cls):

      • Added RegisterCOMPrototype() and GetCOMPrototype() for method registry
      • Enhanced CallObjectMethod() to check for registered prototype methods first
      • Fixed CallFuncByIndex_AST() to properly bind this context for COM methods
      • Added __option_base consistency in function scopes
      • Implemented COM object type detection via GetCOMObjectType()
  • Technical Implementation Details:

    • Prototype Registration Flow:

      1. Parse: prototype.COM.ListRow asDictionary() { ... }
      2. Compile: Generate internal function __PROTOTYPE_LISTROW_ASDICTIONARY
      3. Register: Store mapping (ListRow → asDictionary → funcIndex)
      4. Execute: When obj.asDictionary() called:
         - Check HasCOMPrototype(obj, "asDictionary")
         - Call CallFuncByIndex_AST(funcIndex, args, obj)
         - Bind obj as 'this' in function scope
      
    • this Binding Architecture:

      CallObjectMethod() detects prototype method:
        1. GetCOMPrototype(obj, methodName) → methodInfo
        2. Extract funcIndex from methodInfo
        3. CallFuncByIndex_AST(funcIndex, args, obj)  ← obj passed as thisVal
        4. callScope.SetLocalValue("this", obj)       ← Critical fix
        5. callScope.SetLocalValue("__option_base", 1) ← Consistency fix
      
      Result: Inside method body, 'this' correctly references COM object
      
    • Collection Override Mechanism:

      When OverrideCollMethods = True:
        1. VBA Collection objects intercepted in EvalExprNode
        2. Collection → Array conversion via CollToASF()
        3. JavaScript array methods enabled (.map, .filter, etc.)
        4. Result arrays marshalled back to VBA as needed
      
      Warning: Modifies fundamental VBA Collection behavior
      
    • Scope Management:

      COM Prototype Method Scope Stack:
        Global Scope (program variables)
        ↓
        Function Scope (parameters + locals)  
        ↓  
        Prototype Scope (this + __option_base) ← New layer
        
      Ensures: this binding + consistent indexing + variable resolution
      
  • Breaking Changes:

    • None. Full backward compatibility maintained.
    • OverrideCollMethods is opt-in and disabled by default
  • Compatibility:

    • Office Versions: 2016, 2019, 2021, 365 (Windows & Mac)
    • Architecture: 32-bit and 64-bit Office
    • Applications: Excel, Word, PowerPoint, Access, Outlook
    • VBA Version: 7.0+ required

Collection Override Example

' VBA setup
engine.OverrideCollMethods = True  ' Enable dangerous mode

' JavaScript-like operations on VBA Collections
engine.Compile(_
    "let sheets = $1.Sheets;" & _
    "let visibleSheets = sheets.filter(fun(sheet) { return sheet.Visible; });" & _
    "let sheetNames = visibleSheets.map(fun(sheet) { return sheet.Name; });" & _
    "print('Visible sheets: ' + sheetNames.join(', '));"_
)

Breaking Changes

None. This release maintains full backward compatibility.

Optional Breaking Behavior:

  • OverrideCollMethods = True changes Collection behavior (opt-in)

Full Changelog: v3.1.1...v3.1.2