Tutorial 10: Objects & OOP in FreshLib

0
#
20
27.12.25 16:25

Tutorial 10: Objects & OOP in FreshLib

Overview

FreshLib provides a complete object-oriented programming system for assembly language. This tutorial covers how to define objects with fields and methods, use inheritance and polymorphism, and leverage properties for encapsulated data access.

Topics Covered

  1. Object Definition - object, endobj, fields

  2. Methods - Declaring and implementing object methods

  3. Parameters (Properties) - param with getters and setters

  4. Object Lifecycle - create, destroy

  5. Method Execution - exec, pexec

  6. Properties Access - get, set

  7. Inheritance - Parent-child relationships

  8. Polymorphism - Same interface, different behavior

  9. Type Checking - istype macro


Object Definition

object / endobj

The object macro defines an object type with optional inheritance:

object TAnimal
; Fields (private data storage)
  .name     dd ?          ; Pointer to name string
  .age      dd ?          ; Age in years
  .weight   dd ?          ; Weight in kg

; Methods
  method .Create, .pName, .nAge
  method .Destroy
  method .Speak
  method .GetInfo
endobj

Key Points:

  • Object names should start with T prefix (convention)

  • Fields are like structure members with dot prefix

  • Methods are declared with method macro

  • The first dword is reserved for the vtable pointer

Inheritance

To inherit from a parent object, specify the parent as second argument:

object TDog, TAnimal      ; TDog inherits from TAnimal
; Additional fields
  .breed    dd ?

; Override parent method (same name = override)
  method .Speak

; New method specific to TDog
  method .Fetch
endobj

NOTE

Child objects inherit all fields and methods from parents. Redefining a method with the same name creates an override.


Methods

Declaring Methods

object TRectangle
  ._width   dd ?
  ._height  dd ?

  method .Create, .w, .h          ; Method with parameters
  method .GetArea                  ; Method without parameters
  method .SetSize, .newW, .newH   ; Method with multiple parameters
endobj

Implementing Methods

Methods are implemented outside the object definition using the method macro:

method TRectangle.Create
begin
        pushad
        mov     esi, [.self]          ; .self is always available!

        mov     eax, [.w]
        mov     [esi+TRectangle._width], eax

        mov     eax, [.h]
        mov     [esi+TRectangle._height], eax

        popad
        return
endp

Key Points:

  • .self is an implicit parameter (pointer to object instance)

  • Use pushad/popad to preserve registers

  • Access fields via [.self + ObjectType.fieldname]

Return Values

method TRectangle.GetArea
begin
        push    ecx
        mov     eax, [.self]
        mov     ecx, [eax+TRectangle._width]
        mov     eax, [eax+TRectangle._height]
        imul    eax, ecx              ; EAX = width * height
        pop     ecx
        return                        ; Result in EAX
endp

Parameters (Properties)

The param macro creates properties with controlled access:

object TRectangle
  ._width   dd ?
  ._height  dd ?

; param .Name, GET_METHOD, SET_METHOD
; GET/SET can be: field name, method name, or NONE

; Direct field access (fastest)
  param .Width,  ._width,  ._width
  param .Height, ._height, ._height

; Computed property (read-only via method)
  param .Area, .GetArea, NONE

; Validated setter (write via method)
  param .ValidatedWidth, ._width, .SetWidth

  method .GetArea
  method .SetWidth, .value
endobj

Access Types:

GET/SET Value Behavior
Field name (._width) Direct memory access
Method name (.GetArea) Calls the method
NONE Not supported (read-only/write-only)

Object Lifecycle

create

The create macro allocates memory and initializes an object:

; Syntax: create TARGET, TYPE, [ARGUMENTS]

create  eax, TAnimal, txt "Buddy", 5      ; EAX = pointer to new TAnimal
create  [pDog], TDog, sDogName, 3, sBreed ; Store in memory variable

What create does:

  1. Allocates memory: sizeof.TYPE bytes

  2. Sets vtable pointer: [object] = vtables.TYPE

  3. Calls .Create method if defined, passing arguments

destroy

The destroy macro frees an object:

destroy [pDog]
destroy eax

What destroy does:

  1. Calls TObject.Destroy if object inherits from TObject

  2. Frees the allocated memory

CAUTION

Always destroy objects you create to avoid memory leaks!


Method Execution

exec

The exec macro calls a method on an object:

; Syntax: exec OBJECT, TYPE:METHOD, [ARGUMENTS]

exec    [pAnimal], TAnimal:Speak
exec    [pRect], TRectangle:SetSize, 100, 200
exec    eax, TDog:Fetch

Key Points:

  • Uses TYPE:METHOD syntax (colon separator)

  • Automatically passes .self as first parameter

  • Looks up method in vtable for polymorphic dispatch

pexec (Parent Execute)

Call the parent's version of an overridden method:

; Inside TDog.Speak, call TAnimal.Speak first
pexec   [.self], TAnimal:Speak
; Then add dog-specific behavior

Properties Access

get

The get macro retrieves a property value:

; Syntax: get TARGET, OBJECT, TYPE:PARAMETER

get     eax, [pRect], TRectangle:Width    ; Direct field access
get     ecx, [pRect], TRectangle:Area     ; Calls GetArea method
get     [localVar], esi, TAnimal:Age      ; Store to memory

set

The set macro assigns a property value:

; Syntax: set OBJECT, TYPE:PARAMETER, VALUE

set     [pRect], TRectangle:Width, 50     ; Direct field assignment
set     [pRect], TRectangle:Height, eax   ; Use register value
set     esi, TAnimal:Age, 10              ; When object is in register

NOTE

get and set generate optimal code. For direct field access, they compile to a single mov instruction!


Type Checking

istype

Check if an object is of a specific type (or inherits from it):

; Syntax: istype OBJECT, TYPE
; Returns: ZF=1 if type matches, ZF=0 if not

istype  [pDog], TDog
je      .is_a_dog           ; ZF=1: It IS a TDog

istype  [pDog], TAnimal
je      .is_an_animal       ; ZF=1: Also a TAnimal (inheritance!)

istype  [pDog], TCat
je      .is_a_cat           ; ZF=0: NOT a TCat
jmp     .not_a_cat

How It Works:

  • Walks the vtable parent chain

  • Returns ZF=1 if target type is found anywhere in the chain


Polymorphism

Polymorphism means the same method call executes different code based on object type:

; Define objects with same method name
object TAnimal
  method .Speak
endobj

object TDog, TAnimal
  method .Speak         ; Override
endobj

object TCat, TAnimal
  method .Speak         ; Override
endobj

; Different implementations
method TAnimal.Speak
begin
        stdcall FileWriteString, [STDOUT], txt "*Generic sound*", 13, 10
        return
endp

method TDog.Speak
begin
        stdcall FileWriteString, [STDOUT], txt "Woof!", 13, 10
        return
endp

method TCat.Speak
begin
        stdcall FileWriteString, [STDOUT], txt "Meow!", 13, 10
        return
endp

; Polymorphic usage - same code, different behavior
create  [pDog], TDog
create  [pCat], TCat

exec    [pDog], TAnimal:Speak     ; Prints "Woof!"
exec    [pCat], TAnimal:Speak     ; Prints "Meow!"

IMPORTANT

Using TAnimal:Speak works for any object inheriting from TAnimal. The actual method called depends on the runtime type!


Demo Programs

Demo 26: Object Basics

File: demo26_object_basics.asm

Demonstrates:

  • Object definition with fields and methods

  • create and destroy macros

  • exec for method calls

  • Basic method implementation

Demo 27: Inheritance & Polymorphism

File: demo27_inheritance.asm

Demonstrates:

  • Parent-child object relationships

  • Method overriding

  • Polymorphic method dispatch

  • istype for runtime type checking

Demo 28: Parameters (Properties)

File: demo28_parameters.asm

Demonstrates:

  • param for property definitions

  • get and set macros

  • Direct field vs method-based accessors

  • Computed (read-only) properties


AsmBB Reference Patterns

While AsmBB is primarily a server application (not GUI), it uses similar patterns with structures:

Structure Patterns from AsmBB

; From commands.asm - Custom structure
struct TSpecialParams
  .hJSON          dd ?
  .pPostData      dd ?
  .pPostFiles     dd ?
ends

; From post_data.asm - Data container
struct TPostDataItem
  .hKey   dd ?
  .hValue dd ?
ends

; Usage pattern
mov     esi, [.pSpecial]
mov     eax, [esi+TSpecialParams.hJSON]

TArray Usage (Object-like)

; TArray structure (from FreshLib)
struct TArray
  .count    dd ?
  .capacity dd ?
  .itemSize dd ?
  .array    dd ?        ; Variable size data follows
ends

; Iteration pattern
mov     ebx, [edx+TArray.count]
lea     esi, [edx+TArray.array]
.loop:
        dec     ebx
        js      .done
; Process [esi + ebx*itemSize]
        jmp     .loop

Complete Example

; Define a simple counter object
object TCounter
  ._value   dd ?

  param .Value, ._value, ._value

  method .Create
  method .Increment
  method .Decrement
  method .Reset
endobj

method TCounter.Create
begin
        mov     eax, [.self]
        mov     [eax+TCounter._value], 0
        return
endp

method TCounter.Increment
begin
        mov     eax, [.self]
        inc     [eax+TCounter._value]
        return
endp

method TCounter.Decrement
begin
        mov     eax, [.self]
        dec     [eax+TCounter._value]
        return
endp

method TCounter.Reset
begin
        mov     eax, [.self]
        mov     [eax+TCounter._value], 0
        return
endp

; Usage
start:
        InitializeAll

        create  [pCounter], TCounter

        exec    [pCounter], TCounter:Increment
        exec    [pCounter], TCounter:Increment
        exec    [pCounter], TCounter:Increment

        get     eax, [pCounter], TCounter:Value  ; EAX = 3

        exec    [pCounter], TCounter:Reset

        get     eax, [pCounter], TCounter:Value  ; EAX = 0

        destroy [pCounter]

        FinalizeAll
        stdcall TerminateAll, 0

Building and Running

cd 10-objects
./build.sh

Reference

  • FreshLib OOP Documentation: ~/Documents/fossil/FreshIDE/freshlib/_doc/real_objects.md

  • FreshLib Macros:

    • freshlib/macros/_realobjects.inc - Object macros

    • freshlib/gui/TObject.asm - Base object class

  • AsmBB Examples:

    • ~/Documents/fossil/asmbb/source/commands.asm - struct patterns

    • ~/Documents/fossil/asmbb/source/post_data.asm - TArray usage

19
27.12.25 16:25
; _______________________________________________________________________________________
;|                                                                                       |
;| ..:: FreshLib Tutorials ::..                                                          |
;|_______________________________________________________________________________________|
;
;  Description: Tutorial 10, Demo 26: Object Definition and Creation.
;  Demonstrates: object/endobj, fields, method, create, destroy, exec
;_________________________________________________________________________________________

include "%lib%/freshlib.inc"

LINUX_INTERPRETER equ './ld-musl-i386.so'

@BinaryType console, compact
LIB_MODE equ NOGUI

options.DebugMode = 0

include "%lib%/freshlib.asm"

; ========================================
; Object Definition
; ========================================
; Define a simple TAnimal object with fields and methods

object TAnimal
; Fields (private data storage)
  .name     dd ?              ; Pointer to name string
  .species  dd ?              ; Pointer to species string
  .age      dd ?              ; Age in years
  .weight   dd ?              ; Weight in kg

; Methods
  method .Create, .pName, .pSpecies, .nAge
  method .Destroy
  method .Speak
  method .GetInfo
endobj

; ========================================
; Method Implementations
; ========================================

method TAnimal.Create
begin
        pushad
        mov     esi, [.self]

; Store name (duplicate string to own it)
        stdcall StrDup, [.pName]
        mov     [esi+TAnimal.name], eax

; Store species
        stdcall StrDup, [.pSpecies]
        mov     [esi+TAnimal.species], eax

; Store age
        mov     eax, [.nAge]
        mov     [esi+TAnimal.age], eax

; Initialize weight to 0
        mov     [esi+TAnimal.weight], 0

        popad
        return
endp


method TAnimal.Destroy
begin
        pushad
        mov     esi, [.self]

; Free owned strings
        stdcall StrDel, [esi+TAnimal.name]
        stdcall StrDel, [esi+TAnimal.species]

        popad
        return
endp


method TAnimal.Speak
begin
        pushad

        stdcall FileWriteString, [STDOUT], msg_speak

        popad
        return
endp


method TAnimal.GetInfo
begin
        pushad
        mov     esi, [.self]

; Print name
        stdcall FileWriteString, [STDOUT], msg_name
        stdcall FileWriteString, [STDOUT], [esi+TAnimal.name]
        stdcall FileWriteString, [STDOUT], cCRLF

; Print species
        stdcall FileWriteString, [STDOUT], msg_species
        stdcall FileWriteString, [STDOUT], [esi+TAnimal.species]
        stdcall FileWriteString, [STDOUT], cCRLF

; Print age
        stdcall FileWriteString, [STDOUT], msg_age
        stdcall NumToStr, [esi+TAnimal.age], ntsDec or ntsUnsigned
        push    eax
        stdcall StrPtr, eax
        stdcall FileWriteString, [STDOUT], eax
        pop     eax
        stdcall StrDel, eax
        stdcall FileWriteString, [STDOUT], cCRLF

        popad
        return
endp

; ========================================
; Initialized Data
; ========================================
iglobal
  cCRLF       text 13, 10

  msg_title   text "--- Demo 26: Object Basics ---", 13, 10, 13, 10
  msg_create  text "Creating TAnimal object...", 13, 10
  msg_info    text "Object info:", 13, 10
  msg_method  text "Calling Speak method:", 13, 10
  msg_destroy text "Destroying object...", 13, 10
  msg_done    text 13, 10, "Demo complete!", 13, 10

  msg_speak   text "  *Animal sound*", 13, 10

  msg_name    text "  Name: "
  msg_species text "  Species: "
  msg_age     text "  Age: "

; Test data
  sName       text "Buddy"
  sSpecies    text "Dog"
endg

; ========================================
; Uninitialized Data
; ========================================
uglobal
  pAnimal     dd ?            ; Pointer to TAnimal instance
endg

; ========================================
; Entry Point
; ========================================
start:
        InitializeAll
        stdcall FileWriteString, [STDOUT], msg_title

; ========================================
; 1. Create an object instance
; ========================================
        stdcall FileWriteString, [STDOUT], msg_create

; The 'create' macro:
;   1. Allocates memory for sizeof.TAnimal
;   2. Sets vtable pointer
;   3. Calls TAnimal.Create method with arguments
        create  [pAnimal], TAnimal, sName, sSpecies, 5

        stdcall FileWriteString, [STDOUT], cCRLF

; ========================================
; 2. Call methods on the object
; ========================================
        stdcall FileWriteString, [STDOUT], msg_info

; The 'exec' macro calls a method on an object
; Syntax: exec OBJECT, TYPE:METHOD, [ARGUMENTS]
        exec    [pAnimal], TAnimal:GetInfo

        stdcall FileWriteString, [STDOUT], cCRLF
        stdcall FileWriteString, [STDOUT], msg_method

        exec    [pAnimal], TAnimal:Speak

; ========================================
; 3. Destroy the object
; ========================================
        stdcall FileWriteString, [STDOUT], cCRLF
        stdcall FileWriteString, [STDOUT], msg_destroy

; The 'destroy' macro:
;   1. Calls TObject.Destroy if defined
;   2. Frees the allocated memory
        destroy [pAnimal]

        stdcall FileWriteString, [STDOUT], msg_done

.finish:
        FinalizeAll
        stdcall TerminateAll, 0
18
27.12.25 16:26
; _______________________________________________________________________________________
;|                                                                                       |
;| ..:: FreshLib Tutorials ::..                                                          |
;|_______________________________________________________________________________________|
;
;  Description: Tutorial 10, Demo 27: Object Inheritance and Polymorphism.
;  Demonstrates: Inheritance, method override, polymorphism, istype
;_________________________________________________________________________________________

include "%lib%/freshlib.inc"

LINUX_INTERPRETER equ './ld-musl-i386.so'

@BinaryType console, compact
LIB_MODE equ NOGUI

options.DebugMode = 0

include "%lib%/freshlib.asm"

; ========================================
; Base Object: TAnimal
; ========================================
object TAnimal
; Fields
  .name     dd ?
  .age      dd ?

; Methods
  method .Create, .pName, .nAge
  method .Destroy
  method .Speak                 ; Will be overridden by child classes
  method .GetName
endobj

; ========================================
; Child Object: TDog (inherits from TAnimal)
; ========================================
object TDog, TAnimal            ; Second argument specifies parent
; Additional field specific to TDog
  .breed    dd ?

; Override parent method
  method .Speak                 ; Same name = override

; New method specific to TDog
  method .Create, .pName, .nAge, .pBreed
  method .Destroy
  method .Fetch
endobj

; ========================================
; Child Object: TCat (inherits from TAnimal)
; ========================================
object TCat, TAnimal
; Additional field
  .indoor   dd ?                ; Boolean: indoor cat?

; Override parent method
  method .Speak

; New methods
  method .Create, .pName, .nAge, .bIndoor
  method .Purr
endobj

; ========================================
; TAnimal Method Implementations
; ========================================

method TAnimal.Create
begin
        pushad
        mov     esi, [.self]

        stdcall StrDup, [.pName]
        mov     [esi+TAnimal.name], eax

        mov     eax, [.nAge]
        mov     [esi+TAnimal.age], eax

        popad
        return
endp

method TAnimal.Destroy
begin
        pushad
        mov     esi, [.self]
        stdcall StrDel, [esi+TAnimal.name]
        popad
        return
endp

method TAnimal.Speak
begin
        stdcall FileWriteString, [STDOUT], txt "  *Generic animal sound*", 13, 10
        return
endp

method TAnimal.GetName
begin
        mov     eax, [.self]
        mov     eax, [eax+TAnimal.name]
        return
endp

; ========================================
; TDog Method Implementations
; ========================================

method TDog.Create
begin
        pushad
        mov     esi, [.self]

; Initialize parent fields
        stdcall StrDup, [.pName]
        mov     [esi+TAnimal.name], eax
        mov     eax, [.nAge]
        mov     [esi+TAnimal.age], eax

; Initialize TDog-specific field
        stdcall StrDup, [.pBreed]
        mov     [esi+TDog.breed], eax

        popad
        return
endp

method TDog.Destroy
begin
        pushad
        mov     esi, [.self]

; Free TDog-specific data
        stdcall StrDel, [esi+TDog.breed]

; Free parent data
        stdcall StrDel, [esi+TAnimal.name]

        popad
        return
endp

; Override: TDog.Speak (replaces TAnimal.Speak)
method TDog.Speak
begin
        stdcall FileWriteString, [STDOUT], txt "  Woof! Woof!", 13, 10
        return
endp

method TDog.Fetch
begin
        stdcall FileWriteString, [STDOUT], txt "  *Dog fetches the ball*", 13, 10
        return
endp

; ========================================
; TCat Method Implementations
; ========================================

method TCat.Create
begin
        pushad
        mov     esi, [.self]

; Initialize parent fields
        stdcall StrDup, [.pName]
        mov     [esi+TAnimal.name], eax
        mov     eax, [.nAge]
        mov     [esi+TAnimal.age], eax

; Initialize TCat-specific field
        mov     eax, [.bIndoor]
        mov     [esi+TCat.indoor], eax

        popad
        return
endp

; Override: TCat.Speak
method TCat.Speak
begin
        stdcall FileWriteString, [STDOUT], txt "  Meow!", 13, 10
        return
endp

method TCat.Purr
begin
        stdcall FileWriteString, [STDOUT], txt "  *Purrrr...*", 13, 10
        return
endp

; ========================================
; Data
; ========================================
iglobal
  cCRLF       text 13, 10

  msg_title   text "--- Demo 27: Inheritance & Polymorphism ---", 13, 10, 13, 10

  msg_create  text "Creating objects:", 13, 10
  msg_dog     text "  Created TDog: "
  msg_cat     text "  Created TCat: "

  msg_poly    text 13, 10, "Polymorphism - calling Speak on different types:", 13, 10
  msg_call    text "  Calling TAnimal:Speak on "

  msg_type    text 13, 10, "Type checking with 'istype':", 13, 10
  msg_isdog   text "  Is dog a TDog? "
  msg_iscat   text "  Is dog a TCat? "
  msg_isanimal text "  Is dog a TAnimal? "
  msg_yes     text "YES", 13, 10
  msg_no      text "NO", 13, 10

  msg_specific text 13, 10, "Calling type-specific methods:", 13, 10

  msg_done    text 13, 10, "Demo complete!", 13, 10

  sDogName    text "Rex"
  sDogBreed   text "German Shepherd"
  sCatName    text "Whiskers"
endg

uglobal
  pDog        dd ?
  pCat        dd ?
endg

; ========================================
; Entry Point
; ========================================
start:
        InitializeAll
        stdcall FileWriteString, [STDOUT], msg_title

; ========================================
; 1. Create inherited objects
; ========================================
        stdcall FileWriteString, [STDOUT], msg_create

        create  [pDog], TDog, sDogName, 3, sDogBreed
        stdcall FileWriteString, [STDOUT], msg_dog
        exec    [pDog], TAnimal:GetName
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], cCRLF

        create  [pCat], TCat, sCatName, 2, 1
        stdcall FileWriteString, [STDOUT], msg_cat
        exec    [pCat], TAnimal:GetName
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], cCRLF

; ========================================
; 2. Demonstrate polymorphism
; ========================================
        stdcall FileWriteString, [STDOUT], msg_poly

; Same method call, different behavior!
        stdcall FileWriteString, [STDOUT], msg_call
        stdcall FileWriteString, [STDOUT], sDogName
        stdcall FileWriteString, [STDOUT], <":", 13, 10>
        exec    [pDog], TAnimal:Speak          ; Calls TDog.Speak

        stdcall FileWriteString, [STDOUT], msg_call
        stdcall FileWriteString, [STDOUT], sCatName
        stdcall FileWriteString, [STDOUT], <":", 13, 10>
        exec    [pCat], TAnimal:Speak          ; Calls TCat.Speak

; ========================================
; 3. Type checking with 'istype'
; ========================================
        stdcall FileWriteString, [STDOUT], msg_type

; Check if dog is TDog
        stdcall FileWriteString, [STDOUT], msg_isdog
        istype  [pDog], TDog
        je      .is_dog
        stdcall FileWriteString, [STDOUT], msg_no
        jmp     .check_cat
.is_dog:
        stdcall FileWriteString, [STDOUT], msg_yes

.check_cat:
; Check if dog is TCat (should be NO)
        stdcall FileWriteString, [STDOUT], msg_iscat
        istype  [pDog], TCat
        je      .is_cat
        stdcall FileWriteString, [STDOUT], msg_no
        jmp     .check_animal
.is_cat:
        stdcall FileWriteString, [STDOUT], msg_yes

.check_animal:
; Check if dog is TAnimal (should be YES - inheritance!)
        stdcall FileWriteString, [STDOUT], msg_isanimal
        istype  [pDog], TAnimal
        je      .is_animal
        stdcall FileWriteString, [STDOUT], msg_no
        jmp     .specific
.is_animal:
        stdcall FileWriteString, [STDOUT], msg_yes

; ========================================
; 4. Type-specific methods
; ========================================
.specific:
        stdcall FileWriteString, [STDOUT], msg_specific

        stdcall FileWriteString, [STDOUT], txt "  Dog fetches:", 13, 10
        exec    [pDog], TDog:Fetch

        stdcall FileWriteString, [STDOUT], txt "  Cat purrs:", 13, 10
        exec    [pCat], TCat:Purr

; ========================================
; 5. Cleanup
; ========================================
        destroy [pDog]
        destroy [pCat]

        stdcall FileWriteString, [STDOUT], msg_done

.finish:
        FinalizeAll
        stdcall TerminateAll, 0
17
27.12.25 16:26
; _______________________________________________________________________________________
;|                                                                                       |
;| ..:: FreshLib Tutorials ::..                                                          |
;|_______________________________________________________________________________________|
;
;  Description: Tutorial 10, Demo 28: Parameters and Properties.
;  Demonstrates: param macro for get/set properties, computed properties
;_________________________________________________________________________________________

include "%lib%/freshlib.inc"

LINUX_INTERPRETER equ './ld-musl-i386.so'

@BinaryType console, compact
LIB_MODE equ NOGUI

options.DebugMode = 0

include "%lib%/freshlib.asm"

; ========================================
; Object with Parameters (Properties)
; ========================================
; Parameters provide controlled access to object data.
; They can be:
;   - Direct field access (fast)
;   - Method-based (computed, validated)
;   - Read-only or write-only

object TRectangle
; Private fields (convention: use underscore prefix)
  ._width   dd ?
  ._height  dd ?
  ._color   dd ?

; Parameters (properties)
; Syntax: param .Name, GET_METHOD, SET_METHOD
;
; GET_METHOD / SET_METHOD can be:
;   - Field name: direct memory access
;   - Method name: calls the method
;   - NONE: not supported (read-only or write-only)

; Direct field access (fastest)
  param .Width,  ._width,  ._width
  param .Height, ._height, ._height
  param .Color,  ._color,  ._color

; Computed property (read-only via method)
  param .Area, .GetArea, NONE

; Validated property (write via method)
  param .Size, .GetSize, .SetSize

; Methods
  method .Create, .w, .h
  method .GetArea                      ; Returns width * height
  method .GetSize                      ; Returns total size info
  method .SetSize, .newW, .newH        ; Sets with validation
  method .PrintInfo
endobj

; ========================================
; Method Implementations
; ========================================

method TRectangle.Create
begin
        pushad
        mov     esi, [.self]

        mov     eax, [.w]
        mov     [esi+TRectangle._width], eax

        mov     eax, [.h]
        mov     [esi+TRectangle._height], eax

        mov     [esi+TRectangle._color], 0xFF0000    ; Default: red

        popad
        return
endp

; Computed property getter
method TRectangle.GetArea
begin
        push    ecx
        mov     eax, [.self]
        mov     ecx, [eax+TRectangle._width]
        mov     eax, [eax+TRectangle._height]
        imul    eax, ecx              ; EAX = width * height
        pop     ecx
        return
endp

; Property getter that returns multiple values
method TRectangle.GetSize
begin
        push    esi
        mov     esi, [.self]
        mov     eax, [esi+TRectangle._width]
        mov     edx, [esi+TRectangle._height]
        pop     esi
        return                        ; Returns width in EAX, height in EDX
endp

; Validated setter
method TRectangle.SetSize
begin
        pushad
        mov     esi, [.self]

; Validate: width must be > 0
        mov     eax, [.newW]
        test    eax, eax
        jle     .invalid
        mov     [esi+TRectangle._width], eax

; Validate: height must be > 0
        mov     eax, [.newH]
        test    eax, eax
        jle     .invalid
        mov     [esi+TRectangle._height], eax

        clc                           ; Success
        popad
        return

.invalid:
        stc                           ; Error: invalid dimensions
        popad
        return
endp

method TRectangle.PrintInfo
begin
        pushad
        mov     esi, [.self]

        stdcall FileWriteString, [STDOUT], msg_dims

; Get width using 'get' macro
        get     eax, esi, TRectangle:Width
        stdcall NumToStr, eax, ntsDec or ntsUnsigned
        push    eax
        stdcall StrPtr, eax
        stdcall FileWriteString, [STDOUT], eax
        pop     eax
        stdcall StrDel, eax

        stdcall FileWriteString, [STDOUT], txt " x "

; Get height
        get     eax, esi, TRectangle:Height
        stdcall NumToStr, eax, ntsDec or ntsUnsigned
        push    eax
        stdcall StrPtr, eax
        stdcall FileWriteString, [STDOUT], eax
        pop     eax
        stdcall StrDel, eax

        stdcall FileWriteString, [STDOUT], cCRLF

; Get computed area
        stdcall FileWriteString, [STDOUT], msg_area
        get     eax, esi, TRectangle:Area
        stdcall NumToStr, eax, ntsDec or ntsUnsigned
        push    eax
        stdcall StrPtr, eax
        stdcall FileWriteString, [STDOUT], eax
        pop     eax
        stdcall StrDel, eax

        stdcall FileWriteString, [STDOUT], cCRLF

        popad
        return
endp

; ========================================
; Data
; ========================================
iglobal
  cCRLF       text 13, 10

  msg_title   text "--- Demo 28: Parameters (Properties) ---", 13, 10, 13, 10

  msg_create  text "1. Creating rectangle (10 x 20):", 13, 10
  msg_dims    text "  Dimensions: "
  msg_area    text "  Area: "

  msg_get     text 13, 10, "2. Using 'get' macro:", 13, 10
  msg_width   text "  Width = "
  msg_height  text "  Height = "

  msg_set     text 13, 10, "3. Using 'set' macro to change width to 50:", 13, 10

  msg_compute text 13, 10, "4. Computed property (Area):", 13, 10
  msg_areais  text "  New area = "

  msg_method  text 13, 10, "5. Validated setter (SetSize to 100x200):", 13, 10

  msg_done    text 13, 10, "Demo complete!", 13, 10
endg

uglobal
  pRect       dd ?
endg

; ========================================
; Entry Point
; ========================================
start:
        InitializeAll
        stdcall FileWriteString, [STDOUT], msg_title

; ========================================
; 1. Create rectangle
; ========================================
        stdcall FileWriteString, [STDOUT], msg_create

        create  [pRect], TRectangle, 10, 20
        exec    [pRect], TRectangle:PrintInfo

; ========================================
; 2. Use 'get' macro for properties
; ========================================
        stdcall FileWriteString, [STDOUT], msg_get

        stdcall FileWriteString, [STDOUT], msg_width
        get     eax, [pRect], TRectangle:Width
        stdcall NumToStr, eax, ntsDec or ntsUnsigned
        push    eax
        stdcall StrPtr, eax
        stdcall FileWriteString, [STDOUT], eax
        pop     eax
        stdcall StrDel, eax
        stdcall FileWriteString, [STDOUT], cCRLF

        stdcall FileWriteString, [STDOUT], msg_height
        get     eax, [pRect], TRectangle:Height
        stdcall NumToStr, eax, ntsDec or ntsUnsigned
        push    eax
        stdcall StrPtr, eax
        stdcall FileWriteString, [STDOUT], eax
        pop     eax
        stdcall StrDel, eax
        stdcall FileWriteString, [STDOUT], cCRLF

; ========================================
; 3. Use 'set' macro for properties
; ========================================
        stdcall FileWriteString, [STDOUT], msg_set

; Direct field access via param
        set     [pRect], TRectangle:Width, 50

        exec    [pRect], TRectangle:PrintInfo

; ========================================
; 4. Computed property (read-only)
; ========================================
        stdcall FileWriteString, [STDOUT], msg_compute

        stdcall FileWriteString, [STDOUT], msg_areais
        get     eax, [pRect], TRectangle:Area    ; Calls GetArea method
        stdcall NumToStr, eax, ntsDec or ntsUnsigned
        push    eax
        stdcall StrPtr, eax
        stdcall FileWriteString, [STDOUT], eax
        pop     eax
        stdcall StrDel, eax
        stdcall FileWriteString, [STDOUT], cCRLF

; ========================================
; 5. Validated setter via method (use exec for multi-arg)
; ========================================
        stdcall FileWriteString, [STDOUT], msg_method

; For methods with multiple arguments, use exec directly
; The 'set' macro only supports single value
        exec    [pRect], TRectangle:SetSize, 100, 200

        exec    [pRect], TRectangle:PrintInfo

; ========================================
; Cleanup
; ========================================
        destroy [pRect]

        stdcall FileWriteString, [STDOUT], msg_done

.finish:
        FinalizeAll
        stdcall TerminateAll, 0

Tutorial 10: Objects & OOP in FreshLib

0
#