Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 09:02 30 Dec 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : MMbasic RP2350 V6.01.00EXP with user-defined structures

     Page 1 of 2    
Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10756
Posted: 01:16pm 28 Dec 2025
Copy link to clipboard 
Print this post

Attached the manual and firmware for the next experimental version of the RP2350 firmware with user-defined structures

MMBasic_Structures_Manual.pdf

PicoMiteRP2350V6.01.00EXP2.zip

Changes from 6.01.00EXP:

You can now use simple assignment of one structure to another, including records within an array rather than having to use STRUCT COPY (see tests 69 to 78).

STRUCT LOAD and SAVE now work on either a single record in an array or the whole array (see tests 64 to 67)

New subfunction STRUCT(SIZEOF returns the size of a type in bytes (see tests 60-63)

Manual updated. Note specifically the section on alignment of data within a type.

' Comprehensive Structure Test for PicoMite
' Tests all implemented struct features

Option Explicit
Option Default None

Print "=== Structure Tests ==="
Print

' ============================================
' TEST 1: Basic TYPE definition and simple struct
' ============================================
Print "TEST 1: Basic struct definition and access"

Type Point
 x As INTEGER
 y As INTEGER
End Type

Dim p1 As Point
p1.x = 100
p1.y = 200

If p1.x = 100 And p1.y = 200 Then
 Print "  PASS: Simple struct assignment and read"
Else
 Print "  FAIL: Expected 100,200 got"; p1.x; ","; p1.y
EndIf

' ============================================
' TEST 2: Struct with different member types
' ============================================
Print "TEST 2: Struct with mixed types"

Type Person
 age As INTEGER
 height As FLOAT
 name As STRING
End Type

Dim person1 As Person
person1.age = 42
person1.height = 1.85
person1.name = "John"

If person1.age = 42 And person1.height = 1.85 And person1.name = "John" Then
 Print "  PASS: Mixed type struct"
Else
 Print "  FAIL: Mixed type struct failed"
EndIf

' ============================================
' TEST 3: Array of structures
' ============================================
Print "TEST 3: Array of structures"

Dim points(5) As Point
points(0).x = 10 : points(0).y = 11
points(1).x = 20 : points(1).y = 21
points(2).x = 30 : points(2).y = 31
points(3).x = 40 : points(3).y = 41
points(4).x = 50 : points(4).y = 51
points(5).x = 60 : points(5).y = 61

Dim ok% = 1
Dim i%
For i% = 0 To 5
 If points(i%).x <> (i% + 1) * 10 Or points(i%).y <> (i% + 1) * 10 + 1 Then
   ok% = 0
 EndIf
Next i%

If ok% Then
 Print "  PASS: Array of structs"
Else
 Print "  FAIL: Array of structs"
EndIf

' ============================================
' TEST 4: Pass struct to SUB by reference
' ============================================
Print "TEST 4: Pass struct to SUB by reference"

Sub DoublePoint(pt As Point)
 pt.x = pt.x * 2
 pt.y = pt.y * 2
End Sub

Dim p2 As Point
p2.x = 5
p2.y = 7
DoublePoint p2

If p2.x = 10 And p2.y = 14 Then
 Print "  PASS: Struct passed by reference modified caller"
Else
 Print "  FAIL: Expected 10,14 got"; p2.x; ","; p2.y
EndIf

' ============================================
' TEST 5: Pass array element to SUB
' ============================================
Print "TEST 5: Pass array element to SUB"

Dim arr(3) As Point
arr(1).x = 100
arr(1).y = 200
DoublePoint arr(1)

If arr(1).x = 200 And arr(1).y = 400 Then
 Print "  PASS: Array element passed by reference"
Else
 Print "  FAIL: Expected 200,400 got"; arr(1).x; ","; arr(1).y
EndIf

' ============================================
' TEST 6: Pass struct array to SUB
' ============================================
Print "TEST 6: Pass struct array to SUB"

Sub SumPoints(pts() As Point, count%)
 Local sum_x% = 0, sum_y% = 0
 Local j%
 For j% = 0 To count% - 1
   sum_x% = sum_x% + pts(j%).x
   sum_y% = sum_y% + pts(j%).y
 Next j%
 Print "    Sum X ="; sum_x%; ", Sum Y ="; sum_y%
End Sub

Dim testArr(2) As Point
testArr(0).x = 1 : testArr(0).y = 2
testArr(1).x = 3 : testArr(1).y = 4
testArr(2).x = 5 : testArr(2).y = 6

Print "  Calling SumPoints (expect Sum X=9, Sum Y=12):"
SumPoints testArr(), 3
Print "  PASS: Array of structs passed to SUB (verify output above)"

' ============================================
' TEST 7: Modify struct array in SUB
' ============================================
Print "TEST 7: Modify struct array elements in SUB"

Sub ZeroPoints(pts() As Point, count%)
 Local k%
 For k% = 0 To count% - 1
   pts(k%).x = 0
   pts(k%).y = 0
 Next k%
End Sub

ZeroPoints testArr(), 3

ok% = 1
For i% = 0 To 2
 If testArr(i%).x <> 0 Or testArr(i%).y <> 0 Then ok% = 0
Next i%

If ok% Then
 Print "  PASS: SUB modified caller's struct array"
Else
 Print "  FAIL: Array not properly zeroed"
EndIf

' ============================================
' TEST 8: STRUCT COPY command
' ============================================
Print "TEST 8: STRUCT COPY command"

Dim src As Point, dst As Point
src.x = 999
src.y = 888
dst.x = 0
dst.y = 0

Struct Copy src To dst

If dst.x = 999 And dst.y = 888 Then
 Print "  PASS: STRUCT COPY works"
Else
 Print "  FAIL: Expected 999,888 got"; dst.x; ","; dst.y
EndIf

' ============================================
' TEST 9: STRUCT COPY with mixed types
' ============================================
Print "TEST 9: STRUCT COPY with mixed types"

Dim src_person As Person, dst_person As Person
src_person.age = 25
src_person.height = 1.75
src_person.name = "Alice"

Struct Copy src_person To dst_person

If dst_person.age = 25 And dst_person.height = 1.75 And dst_person.name = "Alice" Then
 Print "  PASS: STRUCT COPY with mixed types"
Else
 Print "  FAIL: STRUCT COPY mixed types failed"
EndIf

' ============================================
' TEST 10: Function returning value from struct member
' ============================================
Print "TEST 10: Function using struct member"

Function GetDistance(pt As Point) As FLOAT
 GetDistance = Sqr(pt.x * pt.x + pt.y * pt.y)
End Function

Dim p3 As Point
p3.x = 3
p3.y = 4
Dim dist! = GetDistance(p3)

If dist! = 5 Then
 Print "  PASS: Function with struct parameter"
Else
 Print "  FAIL: Expected 5 got"; dist!
EndIf

' ============================================
' TEST 11: Nested struct access in expressions
' ============================================
Print "TEST 11: Struct members in expressions"

Dim pA As Point, pB As Point
pA.x = 10 : pA.y = 20
pB.x = 30 : pB.y = 40

Dim sum_expr% = pA.x + pB.x + pA.y + pB.y

If sum_expr% = 100 Then
 Print "  PASS: Struct members in expressions"
Else
 Print "  FAIL: Expected 100 got"; sum_expr%
EndIf

' ============================================
' TEST 12: Array index with variable
' ============================================
Print "TEST 12: Array of structs with variable index"

Dim dynArr(9) As Point
For i% = 0 To 9
 dynArr(i%).x = i% * 2
 dynArr(i%).y = i% * 3
Next i%

ok% = 1
For i% = 0 To 9
 If dynArr(i%).x <> i% * 2 Or dynArr(i%).y <> i% * 3 Then
   ok% = 0
 EndIf
Next i%

If ok% Then
 Print "  PASS: Variable index into struct array"
Else
 Print "  FAIL: Variable index failed"
EndIf

' ============================================
' TEST 13: Multiple struct types
' ============================================
Print "TEST 13: Multiple struct type definitions"

Type Rectangle
 left As INTEGER
 top As INTEGER
 width As INTEGER
 height As INTEGER
End Type

Type Circle
 cx As INTEGER
 cy As INTEGER
 radius As FLOAT
End Type

Dim rect As Rectangle
Dim circ As Circle

rect.left = 10 : rect.top = 20 : rect.width = 100 : rect.height = 50
circ.cx = 50 : circ.cy = 50 : circ.radius = 25.5

If rect.left = 10 And rect.width = 100 And circ.radius = 25.5 Then
 Print "  PASS: Multiple struct types"
Else
 Print "  FAIL: Multiple struct types"
EndIf

' ============================================
' TEST 14: Struct parameter not modified without assignment
' ============================================
Print "TEST 14: Read-only access in SUB"

Sub ReadOnlyTest(pt As Point)
 Local val% = pt.x + pt.y
 Print "    Read value:"; val%
End Sub

Dim p4 As Point
p4.x = 111
p4.y = 222
ReadOnlyTest p4

If p4.x = 111 And p4.y = 222 Then
 Print "  PASS: Struct unchanged after read-only access"
Else
 Print "  FAIL: Struct was unexpectedly modified"
EndIf

' ============================================
' TEST 15: Simple struct initialization
' ============================================
Print "TEST 15: Simple struct initialization"

Dim initPoint As Point = (42, 99)

If initPoint.x = 42 And initPoint.y = 99 Then
 Print "  PASS: Simple struct initialization"
Else
 Print "  FAIL: Expected 42,99 got"; initPoint.x; ","; initPoint.y
EndIf

' ============================================
' TEST 16: Struct with string initialization
' ============================================
Print "TEST 16: Struct with string initialization"

Dim initPerson As Person = (30, 1.80, "Bob")

If initPerson.age = 30 And initPerson.height = 1.80 And initPerson.name = "Bob" Then
 Print "  PASS: Struct with string initialization"
Else
 Print "  FAIL: Struct with string init failed"
EndIf

' ============================================
' TEST 17: Array of structs initialization
' ============================================
Print "TEST 17: Array of structs initialization"

Dim initArr(1) As Point = (10, 20, 30, 40)

If initArr(0).x = 10 And initArr(0).y = 20 And initArr(1).x = 30 And initArr(1).y = 40 Then
 Print "  PASS: Array of structs initialization"
Else
 Print "  FAIL: Array init got"; initArr(0).x; ","; initArr(0).y; ","; initArr(1).x; ","; initArr(1).y
EndIf

' ============================================
' TEST 18: Mixed type struct array initialization
' ============================================
Print "TEST 18: Mixed type struct array initialization"

Type TestStruct
 num As INTEGER
 txt As STRING
End Type

Dim mixArr(1) As TestStruct = (100, "first", 200, "second")

If mixArr(0).num = 100 And mixArr(0).txt = "first" And mixArr(1).num = 200 And mixArr(1).txt = "second" Then
 Print "  PASS: Mixed type struct array initialization"
Else
 Print "  FAIL: Mixed init failed"
EndIf

' ============================================
' TEST 19: LOCAL struct in subroutine
' ============================================
Print "TEST 19: LOCAL struct in subroutine"

Sub TestLocalStruct
 Local localPt As Point
 localPt.x = 555
 localPt.y = 666
 Print "    Local struct values:"; localPt.x; ","; localPt.y
 If localPt.x = 555 And localPt.y = 666 Then
   Print "  PASS: LOCAL struct works"
 Else
   Print "  FAIL: LOCAL struct failed"
 EndIf
End Sub

TestLocalStruct

' ============================================
' TEST 20: LOCAL struct array in subroutine
' ============================================
Print "TEST 20: LOCAL struct array in subroutine"

Sub TestLocalStructArray
 Local localArr(2) As Point
 localArr(0).x = 1 : localArr(0).y = 2
 localArr(1).x = 3 : localArr(1).y = 4
 localArr(2).x = 5 : localArr(2).y = 6
 
 Local ok% = 1
 If localArr(0).x <> 1 Or localArr(0).y <> 2 Then ok% = 0
 If localArr(1).x <> 3 Or localArr(1).y <> 4 Then ok% = 0
 If localArr(2).x <> 5 Or localArr(2).y <> 6 Then ok% = 0
 
 If ok% Then
   Print "  PASS: LOCAL struct array works"
 Else
   Print "  FAIL: LOCAL struct array failed"
 EndIf
End Sub

TestLocalStructArray

' ============================================
' TEST 21: LOCAL struct with initialization
' ============================================
Print "TEST 21: LOCAL struct with initialization"

Sub TestLocalStructInit
 Local initPt As Point = (777, 888)
 If initPt.x = 777 And initPt.y = 888 Then
   Print "  PASS: LOCAL struct initialization works"
 Else
   Print "  FAIL: Expected 777,888 got"; initPt.x; ","; initPt.y
 EndIf
End Sub

TestLocalStructInit

' ============================================
' TEST 22: Multiple LOCAL struct calls (memory test)
' ============================================
Print "TEST 22: Multiple LOCAL struct calls (memory test)"

Sub MemTest
 Local tmp As Point
 tmp.x = 123
 tmp.y = 456
End Sub

' Call multiple times to verify memory is properly freed
MemTest
MemTest
MemTest
MemTest
MemTest
Print "  PASS: Multiple LOCAL struct calls completed (no memory error)"

' ============================================
' TEST 23: STRUCT SORT by integer field
' ============================================
Print "TEST 23: STRUCT SORT by integer field"

Dim sortArr(4) As Point
sortArr(0).x = 50 : sortArr(0).y = 5
sortArr(1).x = 20 : sortArr(1).y = 2
sortArr(2).x = 40 : sortArr(2).y = 4
sortArr(3).x = 10 : sortArr(3).y = 1
sortArr(4).x = 30 : sortArr(4).y = 3

Struct Sort sortArr(), x

If sortArr(0).x = 10 And sortArr(1).x = 20 And sortArr(2).x = 30 And sortArr(3).x = 40 And sortArr(4).x = 50 Then
 Print "  PASS: STRUCT SORT by integer ascending"
Else
 Print "  FAIL: Sort order wrong"
EndIf

' ============================================
' TEST 24: STRUCT SORT reverse
' ============================================
Print "TEST 24: STRUCT SORT reverse"

Struct Sort sortArr(), x, 1

If sortArr(0).x = 50 And sortArr(1).x = 40 And sortArr(2).x = 30 And sortArr(3).x = 20 And sortArr(4).x = 10 Then
 Print "  PASS: STRUCT SORT reverse"
Else
 Print "  FAIL: Reverse sort order wrong"
EndIf

' ============================================
' TEST 25: STRUCT SORT by string field
' ============================================
Print "TEST 25: STRUCT SORT by string field"

Type NamedItem
 id As INTEGER
 name As STRING
End Type

Dim items(4) As NamedItem
items(0).id = 1 : items(0).name = "Cherry"
items(1).id = 2 : items(1).name = "Apple"
items(2).id = 3 : items(2).name = "Elderberry"
items(3).id = 4 : items(3).name = "Banana"
items(4).id = 5 : items(4).name = "Date"

Struct Sort items(), name

If items(0).name = "Apple" And items(1).name = "Banana" And items(2).name = "Cherry" And items(3).name = "Date" And items(4).name = "Elderberry" Then
 Print "  PASS: STRUCT SORT by string"
Else
 Print "  FAIL: String sort wrong:"; items(0).name; ","; items(1).name; ","; items(2).name
EndIf

' Verify ID followed the sort
If items(0).id = 2 And items(1).id = 4 And items(2).id = 1 Then
 Print "  PASS: Other fields preserved during sort"
Else
 Print "  FAIL: ID values not preserved"
EndIf

' ============================================
' TEST 26: STRUCT SORT case insensitive
' ============================================
Print "TEST 26: STRUCT SORT case insensitive"

items(0).name = "cherry"
items(1).name = "APPLE"
items(2).name = "Elderberry"
items(3).name = "banana"
items(4).name = "DATE"

Struct Sort items(), name, 2

If Left$(items(0).name, 1) = "A" Or Left$(items(0).name, 1) = "a" Then
 Print "  PASS: STRUCT SORT case insensitive (Apple/APPLE first)"
Else
 Print "  FAIL: Case insensitive sort wrong, first="; items(0).name
EndIf

' ============================================
' TEST 27: STRUCT SORT by float field
' ============================================
Print "TEST 27: STRUCT SORT by float field"

Type Measurement
 value As FLOAT
 label As STRING
End Type

Dim measurements(3) As Measurement
measurements(0).value = 3.14 : measurements(0).label = "pi"
measurements(1).value = 1.41 : measurements(1).label = "sqrt2"
measurements(2).value = 2.71 : measurements(2).label = "e"
measurements(3).value = 0.57 : measurements(3).label = "euler"

Struct Sort measurements(), value

If measurements(0).value < measurements(1).value And measurements(1).value < measurements(2).value And measurements(2).value < measurements(3).value Then
 Print "  PASS: STRUCT SORT by float"
Else
 Print "  FAIL: Float sort wrong"
EndIf

' ============================================
' TEST 28: STRUCT SORT empty strings at end
' ============================================
Print "TEST 28: STRUCT SORT empty strings at end"

items(0).name = "Zebra"
items(1).name = ""
items(2).name = "Apple"
items(3).name = ""
items(4).name = "Mango"

Struct Sort items(), name, 4

If items(3).name = "" And items(4).name = "" And items(0).name <> "" Then
 Print "  PASS: STRUCT SORT empty strings at end"
Else
 Print "  FAIL: Empty strings not at end"
EndIf

' ============================================
' TEST 29: Function returning struct
' ============================================
Print "TEST 29: Function returning struct"

Dim p29 As Point
p29 = MakePoint(123, 456)

If p29.x = 123 And p29.y = 456 Then
 Print "  PASS: Function returning struct"
Else
 Print "  FAIL: Expected 123,456 got"; p29.x; ","; p29.y
EndIf

' ============================================
' TEST 30: Function returning struct with Person (multiple types)
' ============================================
Print "TEST 30: Function returning struct with mixed types"

Dim p30 As Person
p30 = MakePerson("Bob", 35, 1.75)

If p30.name = "Bob" And p30.age = 35 And Abs(p30.height - 1.75) < 0.01 Then
 Print "  PASS: Function returning struct with mixed types"
Else
 Print "  FAIL: Expected Bob,35,1.75 got"; p30.name; ","; p30.age; ","; p30.height
EndIf

' ============================================
' TEST 31: Struct packing - string followed by int/float (non-8 aligned)
' ============================================
Print "TEST 31: Struct packing with short string before int/float"

Type PackTest
 label As STRING LENGTH 5
 value As INTEGER
 ratio As FLOAT
End Type

Dim pk As PackTest
pk.label = "Test"
pk.value = 12345
pk.ratio = 3.14

If pk.label = "Test" And pk.value = 12345 And Abs(pk.ratio - 3.14) < 0.01 Then
 Print "  PASS: Struct packing with short string"
Else
 Print "  FAIL: Got label="; pk.label; " value="; pk.value; " ratio="; pk.ratio
EndIf

' ============================================
' TEST 32: Function returning struct with array member
' ============================================
Print "TEST 32: Function returning struct with array member"

Type WithArray
 id As INTEGER
 values(3) As INTEGER
End Type

Dim wa As WithArray
wa = MakeWithArray(99, 10, 20, 30, 40)

If wa.id = 99 And wa.values(0) = 10 And wa.values(1) = 20 And wa.values(2) = 30 And wa.values(3) = 40 Then
 Print "  PASS: Function returning struct with array member"
Else
 Print "  FAIL: Got id="; wa.id; " values="; wa.values(0); ","; wa.values(1); ","; wa.values(2); ","; wa.values(3)
EndIf

' ============================================
' TEST 33: STRUCT CLEAR - single struct
' ============================================
Print "TEST 33: STRUCT CLEAR - single struct"

Dim clearTest As Person
clearTest.age = 42
clearTest.height = 1.85
clearTest.name = "TestName"

Struct Clear clearTest

If clearTest.age = 0 And clearTest.height = 0 And clearTest.name = "" Then
 Print "  PASS: STRUCT CLEAR single struct"
Else
 Print "  FAIL: Got age="; clearTest.age; " height="; clearTest.height; " name="; clearTest.name
EndIf

' ============================================
' TEST 34: STRUCT CLEAR - array of structs
' ============================================
Print "TEST 34: STRUCT CLEAR - array of structs"

Dim clearArr(2) As Point
clearArr(0).x = 1 : clearArr(0).y = 2
clearArr(1).x = 3 : clearArr(1).y = 4
clearArr(2).x = 5 : clearArr(2).y = 6

Struct Clear clearArr()

ok% = 1
For i% = 0 To 2
 If clearArr(i%).x <> 0 Or clearArr(i%).y <> 0 Then ok% = 0
Next i%

If ok% Then
 Print "  PASS: STRUCT CLEAR array of structs"
Else
 Print "  FAIL: Array not properly cleared"
EndIf

' ============================================
' TEST 35: STRUCT SWAP
' ============================================
Print "TEST 35: STRUCT SWAP"

Dim swapA As Point, swapB As Point
swapA.x = 100 : swapA.y = 200
swapB.x = 300 : swapB.y = 400

Struct Swap swapA, swapB

If swapA.x = 300 And swapA.y = 400 And swapB.x = 100 And swapB.y = 200 Then
 Print "  PASS: STRUCT SWAP"
Else
 Print "  FAIL: Got A="; swapA.x; ","; swapA.y; " B="; swapB.x; ","; swapB.y
EndIf

' ============================================
' TEST 36: STRUCT SWAP with array elements
' ============================================
Print "TEST 36: STRUCT SWAP with array elements"

Dim swapArr(1) As Person
swapArr(0).name = "Alice" : swapArr(0).age = 25 : swapArr(0).height = 1.60
swapArr(1).name = "Bob" : swapArr(1).age = 30 : swapArr(1).height = 1.80

Struct Swap swapArr(0), swapArr(1)

If swapArr(0).name = "Bob" And swapArr(0).age = 30 And swapArr(1).name = "Alice" And swapArr(1).age = 25 Then
 Print "  PASS: STRUCT SWAP array elements"
Else
 Print "  FAIL: Swap array elements failed"
EndIf

' ============================================
' TEST 37: STRUCT(FIND) - find by integer member
' ============================================
Print "TEST 37: STRUCT(FIND) - find by integer"

Dim findArr(4) As Person
findArr(0).name = "Alice" : findArr(0).age = 25
findArr(1).name = "Bob" : findArr(1).age = 30
findArr(2).name = "Charlie" : findArr(2).age = 35
findArr(3).name = "Diana" : findArr(3).age = 40
findArr(4).name = "Eve" : findArr(4).age = 45

Dim foundIdx% = Struct(FIND, findArr(), "age", 35)

If foundIdx% = 2 Then
 Print "  PASS: STRUCT(FIND) by integer found at index 2"
Else
 Print "  FAIL: Expected index 2, got"; foundIdx%
EndIf

' ============================================
' TEST 38: STRUCT(FIND) - find by string member
' ============================================
Print "TEST 38: STRUCT(FIND) - find by string"

foundIdx% = Struct(FIND, findArr(), "name", "Diana")

If foundIdx% = 3 Then
 Print "  PASS: STRUCT(FIND) by string found at index 3"
Else
 Print "  FAIL: Expected index 3, got"; foundIdx%
EndIf

' ============================================
' TEST 39: STRUCT(FIND) - not found returns -1
' ============================================
Print "TEST 39: STRUCT(FIND) - not found"

foundIdx% = Struct(FIND, findArr(), "name", "Zara")

If foundIdx% = -1 Then
 Print "  PASS: STRUCT(FIND) returns -1 when not found"
Else
 Print "  FAIL: Expected -1, got"; foundIdx%
EndIf

' ============================================
' TEST 40: STRUCT(FIND) - find by float member
' ============================================
Print "TEST 40: STRUCT(FIND) - find by float"

findArr(2).height = 1.77
foundIdx% = Struct(FIND, findArr(), "height", 1.77)

If foundIdx% = 2 Then
 Print "  PASS: STRUCT(FIND) by float"
Else
 Print "  FAIL: Expected index 2, got"; foundIdx%
EndIf

' ============================================
' TEST 42: STRUCT(FIND) with start parameter - iterate through duplicates
' ============================================
Print "TEST 42: STRUCT(FIND) with start parameter"

' Add duplicate ages
findArr(0).age = 30  ' Alice now 30
findArr(1).age = 30  ' Bob already 30
findArr(4).age = 30  ' Eve now 30

' Find first person with age 30
foundIdx% = Struct(FIND, findArr(), "age", 30)
If foundIdx% <> 0 Then
 Print "  FAIL: First match should be index 0, got"; foundIdx%
Else
 ' Find next person with age 30 starting after first match
 foundIdx% = Struct(FIND, findArr(), "age", 30, foundIdx% + 1)
 If foundIdx% <> 1 Then
   Print "  FAIL: Second match should be index 1, got"; foundIdx%
 Else
   ' Find next person with age 30 starting after second match
   foundIdx% = Struct(FIND, findArr(), "age", 30, foundIdx% + 1)
   If foundIdx% <> 4 Then
     Print "  FAIL: Third match should be index 4, got"; foundIdx%
   Else
     ' Try to find another - should return -1
     foundIdx% = Struct(FIND, findArr(), "age", 30, foundIdx% + 1)
     If foundIdx% = -1 Then
       Print "  PASS: STRUCT(FIND) with start parameter iterates correctly"
     Else
       Print "  FAIL: Should return -1 after last match, got"; foundIdx%
     EndIf
   EndIf
 EndIf
EndIf

' Restore original ages for remaining tests
findArr(0).age = 25 : findArr(1).age = 30 : findArr(4).age = 45

' ============================================
' TEST 41: STRUCT SAVE and LOAD
' ============================================
Print "TEST 41: STRUCT SAVE and LOAD"

' Create test data
Dim saveArr(2) As Person
saveArr(0).name = "Alice" : saveArr(0).age = 25 : saveArr(0).height = 1.65
saveArr(1).name = "Bob" : saveArr(1).age = 30 : saveArr(1).height = 1.75
saveArr(2).name = "Charlie" : saveArr(2).age = 35 : saveArr(2).height = 1.85

' Save to file
Open "structtest.dat" For Output As #1
Struct Save #1, saveArr()
Close #1

' Clear the array
Struct Clear saveArr()

' Verify cleared
ok% = 1
For i% = 0 To 2
 If saveArr(i%).name <> "" Or saveArr(i%).age <> 0 Then ok% = 0
Next i%

If ok% = 0 Then
 Print "  FAIL: Array not cleared before load test"
Else
 ' Load back from file
 Open "structtest.dat" For Input As #1
 Struct Load #1, saveArr()
 Close #1
 
 ' Verify data - check each condition separately to avoid line continuation issues
 Dim loadOk% = 1
 If saveArr(0).name <> "Alice" Or saveArr(0).age <> 25 Then loadOk% = 0
 If Abs(saveArr(0).height - 1.65) >= 0.01 Then loadOk% = 0
 If saveArr(1).name <> "Bob" Or saveArr(1).age <> 30 Then loadOk% = 0
 If Abs(saveArr(1).height - 1.75) >= 0.01 Then loadOk% = 0
 If saveArr(2).name <> "Charlie" Or saveArr(2).age <> 35 Then loadOk% = 0
 If Abs(saveArr(2).height - 1.85) >= 0.01 Then loadOk% = 0
 
 If loadOk% Then
   Print "  PASS: STRUCT SAVE/LOAD"
 Else
   Print "  FAIL: Data mismatch after load"
   Print "    [0] "; saveArr(0).name; ","; saveArr(0).age; ","; saveArr(0).height
   Print "    [1] "; saveArr(1).name; ","; saveArr(1).age; ","; saveArr(1).height
   Print "    [2] "; saveArr(2).name; ","; saveArr(2).age; ","; saveArr(2).height
 EndIf
EndIf

' Clean up test file
Kill "structtest.dat"

' ============================================
' TEST 43: STRUCT PRINT - single struct
' ============================================
Print "TEST 43: STRUCT PRINT - single struct"
Print "  Output should show Person structure with Alice, 25, 1.65:"

Dim printTest As Person
printTest.name = "Alice"
printTest.age = 25
printTest.height = 1.65

Struct Print printTest
Print "  PASS: (verify output above manually)"

' ============================================
' TEST 44: STRUCT PRINT - array element
' ============================================
Print "TEST 44: STRUCT PRINT - array element"
Print "  Output should show Point structure with x=100, y=200:"

Dim printArr(2) As Point
printArr(0).x = 100 : printArr(0).y = 200
printArr(1).x = 300 : printArr(1).y = 400

Struct Print printArr(0)
Print "  PASS: (verify output above manually)"

' ============================================
' TEST 45: STRUCT PRINT - whole array
' ============================================
Print "TEST 45: STRUCT PRINT - whole array"
Print "  Output should show 2 Point elements:"

Struct Print printArr()
Print "  PASS: (verify output above manually)"

' ============================================
' TEST 46: STRUCT(SIZE) - basic 1D array
' ============================================
Print "TEST 46: STRUCT(SIZE) - basic 1D array"

Dim boundArr1(9) As Point
Dim bound1% = Struct(SIZE, boundArr1())
If bound1% = 9 Then
 Print "  PASS: STRUCT(SIZE) returned "; bound1%
Else
 Print "  FAIL: Expected 9, got "; bound1%
EndIf

' ============================================
' TEST 47: STRUCT(SIZE) - with dimension parameter
' ============================================
Print "TEST 47: STRUCT(SIZE) - 2D array with dimension"

Dim boundArr2(4, 7) As Point
Dim dim1% = Struct(SIZE, boundArr2(), 1)
Dim dim2% = Struct(SIZE, boundArr2(), 2)
If dim1% = 4 And dim2% = 7 Then
 Print "  PASS: Dimension 1 = "; dim1%; ", Dimension 2 = "; dim2%
Else
 Print "  FAIL: Expected (4,7), got ("; dim1%; ","; dim2%; ")"
EndIf

' ============================================
' TEST 48: STRUCT(SIZE) - default dimension
' ============================================
Print "TEST 48: STRUCT(SIZE) - default dimension (1)"

Dim dim1b% = Struct(SIZE, boundArr2())
If dim1b% = 4 Then
 Print "  PASS: Default dimension returned "; dim1b%
Else
 Print "  FAIL: Expected 4, got "; dim1b%
EndIf

' ============================================
' TEST 49: STRUCT COPY array() TO array()
' ============================================
Print "TEST 49: STRUCT COPY array() TO array()"

Dim srcCopy(2) As Point
srcCopy(0).x = 10 : srcCopy(0).y = 11
srcCopy(1).x = 20 : srcCopy(1).y = 21
srcCopy(2).x = 30 : srcCopy(2).y = 31

Dim dstCopy(4) As Point  ' Larger destination
Struct Copy srcCopy() To dstCopy()

Dim copyOk% = 1
If dstCopy(0).x <> 10 Or dstCopy(0).y <> 11 Then copyOk% = 0
If dstCopy(1).x <> 20 Or dstCopy(1).y <> 21 Then copyOk% = 0
If dstCopy(2).x <> 30 Or dstCopy(2).y <> 31 Then copyOk% = 0

If copyOk% Then
 Print "  PASS: Array copy successful"
Else
 Print "  FAIL: Array copy data mismatch"
 Print "    [0] "; dstCopy(0).x; ","; dstCopy(0).y
 Print "    [1] "; dstCopy(1).x; ","; dstCopy(1).y
 Print "    [2] "; dstCopy(2).x; ","; dstCopy(2).y
EndIf

' ============================================
' TEST 50: STRUCT COPY array preserves extra elements
' ============================================
Print "TEST 50: STRUCT COPY array preserves extra dest elements"

' Set destination element 3 and 4 before copy
Dim srcCopy2(1) As Point
srcCopy2(0).x = 100 : srcCopy2(0).y = 101
srcCopy2(1).x = 200 : srcCopy2(1).y = 201

Dim dstCopy2(3) As Point
dstCopy2(2).x = 999 : dstCopy2(2).y = 998
dstCopy2(3).x = 888 : dstCopy2(3).y = 887

Struct Copy srcCopy2() To dstCopy2()

Dim copy2Ok% = 1
If dstCopy2(0).x <> 100 Or dstCopy2(0).y <> 101 Then copy2Ok% = 0
If dstCopy2(1).x <> 200 Or dstCopy2(1).y <> 201 Then copy2Ok% = 0
If dstCopy2(2).x <> 999 Or dstCopy2(2).y <> 998 Then copy2Ok% = 0
If dstCopy2(3).x <> 888 Or dstCopy2(3).y <> 887 Then copy2Ok% = 0

If copy2Ok% Then
 Print "  PASS: Extra elements preserved"
Else
 Print "  FAIL: Extra elements overwritten"
 Print "    [2] "; dstCopy2(2).x; ","; dstCopy2(2).y; " (expected 999,998)"
 Print "    [3] "; dstCopy2(3).x; ","; dstCopy2(3).y; " (expected 888,887)"
EndIf

' ============================================
' TEST 51: Nested structure - basic access
' ============================================
Print "TEST 51: Nested structure - basic access"

' Define inner struct (Point already defined above)
' Define outer struct with nested Point
Type Line
 startPt As Point
 endPt As Point
 thickness As INTEGER
End Type

Dim testLine As Line
testLine.startPt.x = 10
testLine.startPt.y = 20
testLine.endPt.x = 100
testLine.endPt.y = 200
testLine.thickness = 3

Dim nestedOk% = 1
If testLine.startPt.x <> 10 Or testLine.startPt.y <> 20 Then nestedOk% = 0
If testLine.endPt.x <> 100 Or testLine.endPt.y <> 200 Then nestedOk% = 0
If testLine.thickness <> 3 Then nestedOk% = 0

If nestedOk% Then
 Print "  PASS: Nested structure access works"
Else
 Print "  FAIL: Nested structure access failed"
 Print "    startPt: "; testLine.startPt.x; ","; testLine.startPt.y
 Print "    endPt: "; testLine.endPt.x; ","; testLine.endPt.y
 Print "    thickness: "; testLine.thickness
EndIf

' ============================================
' TEST 52: Nested structure in array
' ============================================
Print "TEST 52: Nested structure in array of structs"

Dim lines(2) As Line
lines(0).startPt.x = 1
lines(0).startPt.y = 2
lines(0).endPt.x = 3
lines(0).endPt.y = 4
lines(1).startPt.x = 10
lines(1).startPt.y = 20
lines(1).endPt.x = 30
lines(1).endPt.y = 40

Dim arrNestedOk% = 1
If lines(0).startPt.x <> 1 Or lines(0).endPt.y <> 4 Then arrNestedOk% = 0
If lines(1).startPt.x <> 10 Or lines(1).endPt.y <> 40 Then arrNestedOk% = 0

If arrNestedOk% Then
 Print "  PASS: Array of structs with nested access"
Else
 Print "  FAIL: Array nested access failed"
EndIf

' ============================================
' TEST 53: Array of nested structure members (Phase 2)
' ============================================
Print "TEST 53: Array of nested structure members"

Type DataPoint
 values(4) As FLOAT
End Type

Type DataSet
 points(2) As DataPoint
 name As STRING
End Type

Dim mydata As DataSet
mydata.name = "Test"
mydata.points(0).values(0) = 1.1
mydata.points(0).values(2) = 1.3
mydata.points(1).values(1) = 2.2
mydata.points(2).values(4) = 3.5

Dim phase2Ok% = 1
If mydata.points(0).values(0) <> 1.1 Then phase2Ok% = 0
If mydata.points(0).values(2) <> 1.3 Then phase2Ok% = 0
If mydata.points(1).values(1) <> 2.2 Then phase2Ok% = 0
If mydata.points(2).values(4) <> 3.5 Then phase2Ok% = 0

If phase2Ok% Then
 Print "  PASS: Array of nested structure members"
Else
 Print "  FAIL: Array of nested structure members failed"
EndIf

' ============================================
' TEST 54: Arrays of structs with array of nested members
' ============================================
Print "TEST 54: Full nesting: arr(i).member(j).member(k)"

Dim mydatasets(1) As DataSet
mydatasets(0).name = "Set0"
mydatasets(0).points(1).values(3) = 42.5
mydatasets(1).name = "Set1"
mydatasets(1).points(2).values(0) = 99.9

Dim fullNestOk% = 1
If mydatasets(0).points(1).values(3) <> 42.5 Then fullNestOk% = 0
If mydatasets(1).points(2).values(0) <> 99.9 Then fullNestOk% = 0
If mydatasets(0).name <> "Set0" Then fullNestOk% = 0
If mydatasets(1).name <> "Set1" Then fullNestOk% = 0

If fullNestOk% Then
 Print "  PASS: Full nesting array(i).array(j).array(k)"
Else
 Print "  FAIL: Full nesting failed"
EndIf

' ============================================
' TEST 55: Variables with dots in names (legacy MMBasic feature)
' ============================================
Print "TEST 55: Variables with dots in names (non-struct)"

Dim My.Variable% = 42
Dim Another.Dotted.Name! = 3.14159
Dim String.With.Dots$ = "Hello"

Dim dotVarOk% = 1
If My.Variable% <> 42 Then dotVarOk% = 0
If Another.Dotted.Name! <> 3.14159 Then dotVarOk% = 0
If String.With.Dots$ <> "Hello" Then dotVarOk% = 0

' Modify and check
My.Variable% = 100
Another.Dotted.Name! = 2.718
String.With.Dots$ = "World"

If My.Variable% <> 100 Then dotVarOk% = 0
If Another.Dotted.Name! <> 2.718 Then dotVarOk% = 0
If String.With.Dots$ <> "World" Then dotVarOk% = 0

If dotVarOk% Then
 Print "  PASS: Dotted variable names work correctly"
Else
 Print "  FAIL: Dotted variable names broken"
EndIf

' ============================================
' TEST 56: Subroutines with dots in names
' ============================================
Print "TEST 56: Subroutines with dots in names"

Dim subTestResult% = 0
My.Test.Sub 10, 20
If subTestResult% = 30 Then
 Print "  PASS: Dotted subroutine names work"
Else
 Print "  FAIL: Dotted subroutine call failed"
EndIf

' ============================================
' TEST 57: Functions with dots in names
' ============================================
Print "TEST 57: Functions with dots in names"

Dim funResult% = My.Test.Function%(5, 7)
If funResult% = 35 Then
 Print "  PASS: Dotted function names work"
Else
 Print "  FAIL: Dotted function call failed, got"; funResult%
EndIf

' ============================================
' TEST 58: Mix of dotted variables and struct members
' ============================================
Print "TEST 58: Dotted variables alongside struct members"

Dim coord.offset% = 50
Dim pt As Point
pt.x = 10
pt.y = 20

Dim mixOk% = 1
' Use dotted variable and struct in same expression
Dim result% = pt.x + coord.offset%
If result% <> 60 Then mixOk% = 0

' Assign from one to other
pt.x = coord.offset%
If pt.x <> 50 Then mixOk% = 0

coord.offset% = pt.y
If coord.offset% <> 20 Then mixOk% = 0

If mixOk% Then
 Print "  PASS: Mixed dotted vars and struct members"
Else
 Print "  FAIL: Mixed usage broken"
EndIf

' ============================================
' TEST 59: Arrays with dots in names
' ============================================
Print "TEST 59: Arrays with dots in names"

Dim Data.Array%(5)
Data.Array%(0) = 100
Data.Array%(3) = 300
Data.Array%(5) = 500

Dim arrDotOk% = 1
If Data.Array%(0) <> 100 Then arrDotOk% = 0
If Data.Array%(3) <> 300 Then arrDotOk% = 0
If Data.Array%(5) <> 500 Then arrDotOk% = 0

If arrDotOk% Then
 Print "  PASS: Dotted array names work"
Else
 Print "  FAIL: Dotted array names broken"
EndIf

' ============================================
' TEST 60: STRUCT(SIZEOF) - basic types
' ============================================
Print "TEST 60: STRUCT(SIZEOF) - basic types"

' Point has 2 x INTEGER (8 bytes each) = 16 bytes
Dim sizePoint% = Struct(SIZEOF, "Point")
If sizePoint% = 16 Then
 Print "  PASS: SIZEOF Point = "; sizePoint%; " bytes"
Else
 Print "  FAIL: Expected 16, got "; sizePoint%
EndIf

' ============================================
' TEST 61: STRUCT(SIZEOF) - with string
' ============================================
Print "TEST 61: STRUCT(SIZEOF) - with string"

' Person has: age(8) + height(8) + name(256) = 272 bytes
Dim sizePerson% = Struct(SIZEOF, "Person")
If sizePerson% = 272 Then
 Print "  PASS: SIZEOF Person = "; sizePerson%; " bytes"
Else
 Print "  FAIL: Expected 272, got "; sizePerson%
EndIf

' ============================================
' TEST 62: STRUCT(SIZEOF) - case insensitive
' ============================================
Print "TEST 62: STRUCT(SIZEOF) - case insensitive"

Dim sizeLower% = Struct(SIZEOF, "point")
Dim sizeUpper% = Struct(SIZEOF, "POINT")
Dim sizeMixed% = Struct(SIZEOF, "PoInT")

If sizeLower% = 16 And sizeUpper% = 16 And sizeMixed% = 16 Then
 Print "  PASS: SIZEOF case insensitive"
Else
 Print "  FAIL: Case sensitivity issue"
EndIf

' ============================================
' TEST 63: STRUCT(SIZEOF) - with variable typename
' ============================================
Print "TEST 63: STRUCT(SIZEOF) - with variable typename"

Dim typename$ = "Point"
Dim sizeVar% = Struct(SIZEOF, typename$)
If sizeVar% = 16 Then
 Print "  PASS: SIZEOF with variable typename"
Else
 Print "  FAIL: Expected 16, got "; sizeVar%
EndIf

' ============================================
' TEST 64: STRUCT SAVE/LOAD individual element
' ============================================
Print "TEST 64: STRUCT SAVE/LOAD individual element"

Dim elemArr(4) As Point
elemArr(0).x = 10 : elemArr(0).y = 11
elemArr(1).x = 20 : elemArr(1).y = 21
elemArr(2).x = 30 : elemArr(2).y = 31
elemArr(3).x = 40 : elemArr(3).y = 41
elemArr(4).x = 50 : elemArr(4).y = 51

' Save only element 2
Open "elem_test.dat" For Output As #1
Struct Save #1, elemArr(2)
Close #1

' Load into a different element
elemArr(4).x = 0 : elemArr(4).y = 0
Open "elem_test.dat" For Input As #1
Struct Load #1, elemArr(4)
Close #1

If elemArr(4).x = 30 And elemArr(4).y = 31 Then
 Print "  PASS: Save/Load individual element"
Else
 Print "  FAIL: Expected 30,31 got "; elemArr(4).x; ","; elemArr(4).y
EndIf

Kill "elem_test.dat"

' ============================================
' TEST 65: STRUCT SAVE/LOAD multiple individual elements
' ============================================
Print "TEST 65: STRUCT SAVE/LOAD multiple elements sequentially"

' Save elements 0, 2, 4 to file
Open "multi_elem.dat" For Output As #1
Struct Save #1, elemArr(0)
Struct Save #1, elemArr(2)
Struct Save #1, elemArr(4)
Close #1

' Create new array and load back
Dim loadArr(2) As Point
Open "multi_elem.dat" For Input As #1
Struct Load #1, loadArr(0)
Struct Load #1, loadArr(1)
Struct Load #1, loadArr(2)
Close #1

Dim multiOk% = 1
If loadArr(0).x <> 10 Or loadArr(0).y <> 11 Then multiOk% = 0
If loadArr(1).x <> 30 Or loadArr(1).y <> 31 Then multiOk% = 0
If loadArr(2).x <> 30 Or loadArr(2).y <> 31 Then multiOk% = 0

If multiOk% Then
 Print "  PASS: Multiple sequential element save/load"
Else
 Print "  FAIL: Data mismatch"
 Print "    [0] "; loadArr(0).x; ","; loadArr(0).y
 Print "    [1] "; loadArr(1).x; ","; loadArr(1).y
 Print "    [2] "; loadArr(2).x; ","; loadArr(2).y
EndIf

Kill "multi_elem.dat"

' ============================================
' TEST 66: STRUCT SAVE/LOAD single struct to array element
' ============================================
Print "TEST 66: STRUCT SAVE single struct, LOAD to array element"

Dim singlePt As Point
singlePt.x = 999
singlePt.y = 888

Open "single_to_arr.dat" For Output As #1
Struct Save #1, singlePt
Close #1

Dim targetArr(3) As Point
Open "single_to_arr.dat" For Input As #1
Struct Load #1, targetArr(2)
Close #1

If targetArr(2).x = 999 And targetArr(2).y = 888 Then
 Print "  PASS: Single struct to array element"
Else
 Print "  FAIL: Expected 999,888 got "; targetArr(2).x; ","; targetArr(2).y
EndIf

Kill "single_to_arr.dat"

' ============================================
' TEST 67: STRUCT SAVE array element, LOAD to single struct
' ============================================
Print "TEST 67: STRUCT SAVE array element, LOAD to single struct"

Open "arr_to_single.dat" For Output As #1
Struct Save #1, elemArr(1)
Close #1

Dim loadSingle As Point
Open "arr_to_single.dat" For Input As #1
Struct Load #1, loadSingle
Close #1

If loadSingle.x = 20 And loadSingle.y = 21 Then
 Print "  PASS: Array element to single struct"
Else
 Print "  FAIL: Expected 20,21 got "; loadSingle.x; ","; loadSingle.y
EndIf

Kill "arr_to_single.dat"

' ============================================
' TEST 68: STRUCT(SIZEOF) for memory calculation
' ============================================
Print "TEST 68: STRUCT(SIZEOF) for memory calculation"

' Calculate expected file size for array
Dim arrSize% = 5  ' 0 to 4 = 5 elements
Dim expectedBytes% = (arrSize%) * Struct(SIZEOF, "Point")

' Save array and check file size
Open "size_test.dat" For Output As #1
Struct Save #1, elemArr()
Close #1

' Verify we can read it back correctly (confirms size is right)
Dim verifyArr(4) As Point
Open "size_test.dat" For Input As #1
Struct Load #1, verifyArr()
Close #1

Dim sizeOk% = 1
For i% = 0 To 4
 If verifyArr(i%).x <> elemArr(i%).x Or verifyArr(i%).y <> elemArr(i%).y Then
   sizeOk% = 0
 EndIf
Next i%

If sizeOk% Then
 Print "  PASS: Array of "; arrSize%; " elements = "; expectedBytes%; " bytes"
Else
 Print "  FAIL: Array save/load size mismatch"
EndIf

Kill "size_test.dat"

' ============================================
' TEST 69: Direct struct assignment (single variables)
' ============================================
Print "TEST 69: Direct struct assignment (single variables)"

Dim assignSrc As Point
Dim assignDst As Point
assignSrc.x = 111
assignSrc.y = 222

assignDst = assignSrc

If assignDst.x = 111 And assignDst.y = 222 Then
 Print "  PASS: Direct struct assignment"
Else
 Print "  FAIL: Expected 111,222 got "; assignDst.x; ","; assignDst.y
EndIf

' ============================================
' TEST 70: Direct struct assignment (array elements)
' ============================================
Print "TEST 70: Direct struct assignment (array elements)"

Dim assignArr(5) As Point
assignArr(0).x = 10 : assignArr(0).y = 20
assignArr(1).x = 30 : assignArr(1).y = 40

assignArr(3) = assignArr(0)
assignArr(4) = assignArr(1)

Dim arrAssignOk% = 1
If assignArr(3).x <> 10 Or assignArr(3).y <> 20 Then arrAssignOk% = 0
If assignArr(4).x <> 30 Or assignArr(4).y <> 40 Then arrAssignOk% = 0

If arrAssignOk% Then
 Print "  PASS: Direct array element assignment"
Else
 Print "  FAIL: Array element assignment failed"
EndIf

' ============================================
' TEST 71: Direct assignment between different arrays
' ============================================
Print "TEST 71: Direct assignment between different arrays"

Dim srcArr2(3) As Point
Dim dstArr2(3) As Point
srcArr2(1).x = 500 : srcArr2(1).y = 600

dstArr2(2) = srcArr2(1)

If dstArr2(2).x = 500 And dstArr2(2).y = 600 Then
 Print "  PASS: Cross-array element assignment"
Else
 Print "  FAIL: Expected 500,600 got "; dstArr2(2).x; ","; dstArr2(2).y
EndIf

' ============================================
' TEST 72: Direct assignment with mixed types struct
' ============================================
Print "TEST 72: Direct assignment with mixed types struct"

Dim persSrc As Person
Dim persDst As Person
persSrc.name = "TestPerson"
persSrc.age = 42
persSrc.height = 1.85

persDst = persSrc

Dim persOk% = 1
If persDst.name <> "TestPerson" Then persOk% = 0
If persDst.age <> 42 Then persOk% = 0
If Abs(persDst.height - 1.85) >= 0.01 Then persOk% = 0

If persOk% Then
 Print "  PASS: Mixed type struct assignment"
Else
 Print "  FAIL: Mixed type struct assignment failed"
EndIf

' ============================================
' TEST 73: Direct assignment from function return
' ============================================
Print "TEST 73: Direct assignment from function return"

Dim funcResult As Point
funcResult = MakePoint(777, 888)

If funcResult.x = 777 And funcResult.y = 888 Then
 Print "  PASS: Assignment from function return"
Else
 Print "  FAIL: Expected 777,888 got "; funcResult.x; ","; funcResult.y
EndIf

' ============================================
' TEST 74: Chained assignment (a = b, then c = a)
' ============================================
Print "TEST 74: Chained assignment"

Dim chainA As Point, chainB As Point, chainC As Point
chainA.x = 1000 : chainA.y = 2000
chainB = chainA
chainC = chainB

If chainC.x = 1000 And chainC.y = 2000 Then
 Print "  PASS: Chained struct assignment"
Else
 Print "  FAIL: Expected 1000,2000 got "; chainC.x; ","; chainC.y
EndIf

' ============================================
' Summary
' ============================================
Print
Print "=== All Tests Complete ==="
Print "Review output above for any FAIL messages"

End

' ============================================
' Function definitions (must be after END)
' ============================================

Function MakePoint(xval%, yval%) As Point
 MakePoint.x = xval%
 MakePoint.y = yval%
End Function

Function MakePerson(n$, a%, h!) As Person
 MakePerson.age = a%
 MakePerson.height = h!
 MakePerson.name = n$
End Function

Function MakeWithArray(id%, v0%, v1%, v2%, v3%) As WithArray
 MakeWithArray.id = id%
 MakeWithArray.values(0) = v0%
 MakeWithArray.values(1) = v1%
 MakeWithArray.values(2) = v2%
 MakeWithArray.values(3) = v3%
End Function

' Subroutine with dots in name (Test 56)
Sub My.Test.Sub(a%, b%)
 subTestResult% = a% + b%
End Sub

' Function with dots in name (Test 57)
Function My.Test.Function%(x%, y%)
 My.Test.Function% = x% * y%
End Function

Edited 2025-12-28 23:24 by matherp
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10756
Posted: 06:05pm 28 Dec 2025
Copy link to clipboard 
Print this post

I've spent some time minimising the memory footprint of the structure code so it now works on the RP2040 as well as the RP2350. All versions attached. The standard PicoMiteRP2040 has been tested and passes all tests as above
PicoMiteV6.01.00EXP2.zip
 
stanleyella

Guru

Joined: 25/06/2022
Location: United Kingdom
Posts: 2710
Posted: 06:39pm 28 Dec 2025
Copy link to clipboard 
Print this post

over my head sir but thankyou.
 
bfwolf
Regular Member

Joined: 03/01/2025
Location: Germany
Posts: 98
Posted: 07:13pm 28 Dec 2025
Copy link to clipboard 
Print this post

  matherp said  Attached the manual and firmware for the next experimental version of the RP2350 firmware with user-defined structures

MMBasic_Structures_Manual.pdf

PicoMiteRP2350V6.01.00EXP2.zip

Changes from 6.01.00EXP:

You can now use simple assignment of one structure to another, including records within an array rather than having to use STRUCT COPY (see tests 69 to 78).

STRUCT LOAD and SAVE now work on either a single record in an array or the whole array (see tests 64 to 67)

New subfunction STRUCT(SIZEOF returns the size of a type in bytes (see tests 60-63)

Manual updated. Note specifically the section on alignment of data within a type.

...


 

Thank you very much for the explanations in the manual regarding the memory requirements of the structs and about padding and alignment!  

And a huge thank you for taking my suggestion and implementing the "SIZEOF" subfunction! I think it will be very useful! Of course, you can also "calculate it manually" using the explanations about memory allocation, but that's always very error-prone. You might change something in one struct (add a member or change the order or size of string members) and, of course, forget to adjust it, for example, for the factor in 'SEEK #fn, rec%*rec_size'.

I've also tested 'PEEK(VARADDR typeArray())' and 'PEEK(VARADDR typeArray(n%))': Wonderful! It works for the entire array as well as for a single array element!

  matherp said  I've spent some time minimising the memory footprint of the structure code so it now works on the RP2040 as well as the RP2350. All versions attached. The standard PicoMiteRP2040 has been tested and passes all tests as above
PicoMiteV6.01.00EXP2.zip


Wow!   Many RP2040 users will be happy to have the very useful new UDT (Type .. End Type) feature!

Thank You, Peter !!!
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9800
Posted: 01:57am 29 Dec 2025
Copy link to clipboard 
Print this post

  stanleyella said  over my head sir but thankyou.


Mine too.  

I have ZERO understanding as to what this actually is, or how it would be useful.
That's not to say it isn't - Peter would not have spent all that time doing this for nothing - simply that I don't understand what this is all about.

If anyone has the time to elaborate as to what this feature does and why it is useful over and above what MMBASIC already does, please do comment here, or link me to another site where I can read about this concept.

My ignorance is showing here, I have to say, but I make no apologies for that!  
I WOULD like to understand what this is all about though.  
Smoke makes things work. When the smoke gets out, it stops!
 
Chopperp

Guru

Joined: 03/01/2018
Location: Australia
Posts: 1112
Posted: 03:06am 29 Dec 2025
Copy link to clipboard 
Print this post

Ditto Stanleyella & Grogster
ChopperP
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6409
Posted: 04:18am 29 Dec 2025
Copy link to clipboard 
Print this post

Structures are very useful when you have a number of 'objects' that have the same attributes.
If the attributes are all integers or all strings, you can just add another dimension to your array.
If you have a mix of strings and numbers, structures are your friend.

In MMEdit, each tab has a structured variable holding all sorts of info.
Delete a tab and just delete the structured variable instead of a dozen deletes.
Add a new tab and just create a new variable with the same structure.

In MMCC,
The terminal consists a single dimension array of lines. (actually a list but we don't have lists yet?)
The structure of a line is a couple of integers and an array of 256 characters.
Each character is a structure containing the character, foreground colour, background colour and attributes.
So I have a structure inside a structure inside a list (or array).
I can delete or move a single character or a whole line or whole screen with one command.
VK7JH
MMedit
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3330
Posted: 04:33am 29 Dec 2025
Copy link to clipboard 
Print this post

Structures are a simplified way of organizing data, you don't need to use them but, if you do, it is more convenient and intuitive than the old ways.  And generally, these features mean less bugs.

For example, assume that you need to track a number of alarms.  Each alarm has a number of properties; the time of the alarm, its level (1, 2. 3, etc) and the action taken.  To do this using old way you would define three arrays:
  DIM AlarmTime(nbr) AS FLOAT, AlarmLevel(nbr) AS INTEGER, AlarmAction(nbr) AS STRING
Then you would access each array individually, for example:
  IF AlarmTine(i) < sometime) AND AlarmLevel(i) < somelevel THEN CallSomeSub

This is fine and if you are happy with this then there is no need to change.  

But, using structures enables you to treat the data as a single "thing" rather than a bunch of loosely related arrays.  For example:
  TYPE StructAlarm
     time AS FLOAT
     level AS INTEGER
     action AS STRING
  END TYPE


Then you would define your array of alarms as follows:
  DIM alarm(nbr) AS StructAlarm
And then you could access the properties of each alarm, for example:
  IF alarm(i).timer < sometime) AND alarm(i).level < somelevel THEN CallSomeSub

At this point you are probably thinking that this is more complicated than the old way.  BUT consider if you need to pass the alarm to a subroutine.  Using the old way you might use:
  MySub AlarmTime(i), AlarmLevel(i), AlarmAction(i)
Using a structure you would do:
  MySub alarm(i)

And what if you need to copy alarms?  For example, when swapping elements while sorting an array of alarms:
  DIM alarm(nbr) AS StructAlarm
  DIM tmp AS StructAlarm
  …
  tmp = alarm(i + 1)
  alarm((i + 1) = alarm(i)
  alarm(i) = tmp


There are a lot of features in MMBasic that are "new" and "convenient" but you can still use the old ways if you want to.  For example, you might want to stick to using line numbers, or GOSUB…RETURN, or not bother with OPTION EXPLICIT, and so on, and that is fine.  But the new features will make your code easier to read, easier to follow and as a result, less buggy.

Not that I would ever say that your code is buggy  

Geoff
Geoff Graham - http://geoffg.net
 
toml_12953
Guru

Joined: 13/02/2015
Location: United States
Posts: 528
Posted: 04:56am 29 Dec 2025
Copy link to clipboard 
Print this post

I'm having a hard time running the test program. Mine fails like so:

TEST 68: STRUCT(SIZEOF) for memory calculation
[1407] STRUCT Load #1, verifyArr()
Error : Cannot find VERIFYARR


size_test.dat is created, though.

I copy/pasted the program into TeraTerm. It dropped the line

Dim verrArr(4) as point


when I manually added that line back in, everything worked again.
Edited 2025-12-29 16:02 by toml_12953
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 8399
Posted: 08:13am 29 Dec 2025
Copy link to clipboard 
Print this post

Thanks Geoff. :)
I was pretty much in the same boat, never having used a Structure in my life. I can see the advantages now. I remember using something similar for Disk BASIC random files on my Tandy Model 1, but it wasn't referred to as Structures at that time and there was less flexibility. :)
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
karlelch

Senior Member

Joined: 30/10/2014
Location: Germany
Posts: 298
Posted: 08:25am 29 Dec 2025
Copy link to clipboard 
Print this post

Hi,

there may be something brocken with XMODEM again:

(1) In the latest experimental version (PicoMiteRP2350V6.01.00EXP2.uf2), xmodem `receive "miiha.bas"' causes the PicoMite to hang (no response, reset required)

(2) In the previous experimental version (PicoMiteRP2350V6.01.00EXP.uf2), the same command seems to finish but ends up with an empty file.

In the latest official release (PicoMiteRP2350V6.01.00.uf2), it works.

PicoMite MMBasic RP2350B V6.01.00
OPTION FLASH SIZE 16777216
OPTION COLOURCODE ON
OPTION PICO OFF
OPTION CPUSPEED (KHz) 200000

Best
Thomas

Footnote added 2025-12-29 18:30 by karlelch
P.S.: "xmodem r" works

Footnote added 2025-12-29 19:13 by karlelch
P.S.: I checked again and found that with PicoMiteRP2350V6.01.00.uf2, the same problem occurs as with PicoMiteRP2350V6.01.00EXP.uf2 - empty file. The respective receive versions (xmodem receive "miiha.bas") work as expected

Footnote added 2025-12-29 19:24 by karlelch
P.S.: IGNORE - see my message below
 
toml_12953
Guru

Joined: 13/02/2015
Location: United States
Posts: 528
Posted: 08:47am 29 Dec 2025
Copy link to clipboard 
Print this post

  Mixtel90 said  Thanks Geoff. :)
I was pretty much in the same boat, never having used a Structure in my life. I can see the advantages now. I remember using something similar for Disk BASIC random files on my Tandy Model 1, but it wasn't referred to as Structures at that time and there was less flexibility. :)

Weren't FIELD statements fun?
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6409
Posted: 09:07am 29 Dec 2025
Copy link to clipboard 
Print this post

  karlelch said  Hi,

there may be something brocken with XMODEM again:
xmodem `receive "miiha.bas"' causes the PicoMite to hang (no response, reset required)

Are the single quotes there for a reason?
without the single quotes XMODEM RECEIVE works as expected on the webmiteV6.1.0EXP2

Jim
VK7JH
MMedit
 
karlelch

Senior Member

Joined: 30/10/2014
Location: Germany
Posts: 298
Posted: 09:16am 29 Dec 2025
Copy link to clipboard 
Print this post

  TassyJim said  Are the single quotes there for a reason?
without the single quotes XMODEM RECEIVE works as expected on the webmiteV6.1.0EXP2
Jim

The single quotes were just to indicate what's the command I entered ... Hmm, now I am utterly confused. Will explore more.

Thanks Jim.

Best
Thomas
 
karlelch

Senior Member

Joined: 30/10/2014
Location: Germany
Posts: 298
Posted: 09:27am 29 Dec 2025
Copy link to clipboard 
Print this post

Hi,

I tested XMODEM again - now everything works as expected also with PicoMiteRP2350V6.01.00EXP2.uf2 ... I am not sure what happened before, but in between my first tests and now I did a few nukes and uploaded a few different firmware versions. Self-healing?

Sorry for the confusion.

Best
Thomas
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10756
Posted: 11:27am 29 Dec 2025
Copy link to clipboard 
Print this post

I need to decide whether to include the struct functionality in the final RP2040 builds.Please could those who still use the rp2040 test out the builds above and check for any oddities or signifiocant performance impact - thanks
 
ville56
Guru

Joined: 08/06/2022
Location: Austria
Posts: 366
Posted: 04:06pm 29 Dec 2025
Copy link to clipboard 
Print this post

tested

PicoMiteRP2040V6.01.00EXP2.uf2 (complex app with heavy GUI usage)
WebMiteRP2040V6.01.00EXP2.uf2 (simple app with 18B20 temp sensors)

so far no issues found.

I would strongly suggest to leave the struct functionality in the RP2040 code as it makes many things easier to code. As far as I could test it, it seems that a TYPEed variable is counted only as one variable no matter how many members the structure has. This has some advantages when using lots of variables and constants ... as I like to do  . One has just to apply a litte "object thinking".
                                                                 
73 de OE1HGA, Gerald
 
mozzie
Senior Member

Joined: 15/06/2020
Location: Australia
Posts: 186
Posted: 04:53pm 29 Dec 2025
Copy link to clipboard 
Print this post

G'day,
Some simple testing with:
PicoMite RP2040 V6.01.00EXP2
PicoMite RP2040 V6.01.00

V6.01.00
Test 1  116.273ms 1000 x bit shifting 4 bytes (written before byte command existed)
Test 2  153.439ms 1000 x peeking 4 bytes instead
Test 3  892.041ms 200 x drawing moving triangles across the LCD

V6.01.00EXP2
Test 1  124.041ms
Test 2  161.4ms
Test 3  896.288ms

Shows a slight reduction in speed (approx 5%) with EXP2 with general accessing registers etc and no real difference with LCD usage (ILI9488)

More testing to follow but I can see the advantages outweighing the slight speed penalty.

As a side note, being able to play around with structures in MMBasic has finally allowed me to get a grip on the whole idea, now CircuitPython is starting to make sense at last, they use structures all over and its been the cause of a monumental amount of swearing whilst trying to get my head around them  

Thanks to Peter for the xmas present and Geoff for the explanation.
Thankyou both for MMbasic and the Mites.  

Regards,
Lyle.
 
stanleyella

Guru

Joined: 25/06/2022
Location: United Kingdom
Posts: 2710
Posted: 07:16pm 29 Dec 2025
Copy link to clipboard 
Print this post

I looked up srtuctured coding/basic and the bbc basic I installed on rpi 400 has opengl and structures. Don't personally see the point but that's cos I don't know enough to say out.

 
stanleyella

Guru

Joined: 25/06/2022
Location: United Kingdom
Posts: 2710
Posted: 08:16pm 29 Dec 2025
Copy link to clipboard 
Print this post

I can get my head around "structured" basic ie simple flow with subs, no goto, but not structures. functions never used. I can't see any of this is would make any code I wrote better if I used structures.
I use option explicit and declare var types as.
I'm willing to learn though.
 
     Page 1 of 2    
Print this page
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025