Skip to content

Commit

Permalink
fbc: allow UDT operators to support array() parameters
Browse files Browse the repository at this point in the history
- add sf.net feature request # 273: Let overloads should support
  array parameters; allow UDT operators (LET, +=, etc) to support
  array parameters
- fix sf.net # 991: Missing error check for unsupported overloaded
  operators. Solve this bug by adding the feature to support array
  parameters; parse empty parens '()' for arrays when used in UDT
  operator expressions (LET, +=, etc)
- internal: replace cBydescArrayArgParens() with astBydescArrayArg()

  Example:

    type UDT
        i as integer
        declare operator let( (any) as integer )
    end type

    operator UDT.let( array(any) as integer )
        print "UDT.let( (any) as integer )"
    end operator

    dim array(any) as integer
    dim x as UDT
    x = array()
  • Loading branch information
jayrm committed Mar 31, 2024
1 parent 8592eb2 commit d381789
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 47 deletions.
2 changes: 2 additions & 0 deletions changelog.txt
Expand Up @@ -49,6 +49,7 @@ Version 1.20.0
- fbc: '-print fork-id' command line option to report the fork-id version of fbc
- fbc: '-nolib fbrt0.o' and '-nolib fbrt0pic.o' can be used to omit fb's startup files from the link. Implied by '-nodeflibs'.
- fbc: '-z nobuiltins' command line option to disable all non-required built-in procedure definitions
- sf.net feature #273 fbc: allow UDT operators (LET, +=, etc) to support array parameters

[fixed]
- github #410: give consistent floating point comparisons results involving NaNs.
Expand All @@ -73,6 +74,7 @@ Version 1.20.0
- fbc: when compiling with "-e -gen clang", work around a "indirect goto in function with no address-of-label expressions" clang error
- fbc/gas/gas64: truncate string literals that are too big for the assigned destination on the last full escape sequence instead of in the middle of an escape sequence (which would cause gas assembly errors)
- sf.net #372: Bad Fixed length strings in UDT
- sf.net #991: fbc: parse empty parens '()' for arrays when used in UDT operator expressions (LET, +=, etc)


Version 1.10.3
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/ast-helper.bas
Expand Up @@ -665,6 +665,14 @@ function astBuildImplicitCtorCall _

end function

'':::::
function astBydescArrayArg( byval arg as ASTNODE ptr ) as FB_PARAMMODE
function = INVALID
if( astIsNIDXARRAY( arg ) ) then
function = FB_PARAMMODE_BYDESC
end if
end function

'':::::
function astBuildImplicitCtorCallEx _
( _
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/ast.bi
Expand Up @@ -1289,6 +1289,11 @@ declare function astBuildImplicitCtorCall _
byref is_ctorcall as integer _
) as ASTNODE ptr

declare function astBydescArrayArg _
( _
byval arg as ASTNODE ptr _
) as FB_PARAMMODE

declare function astBuildImplicitCtorCallEx _
( _
byval sym as FBSYMBOL ptr, _
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/parser-decl-symb-init.bas
Expand Up @@ -413,7 +413,7 @@ private function hUDTInit( byref ctx as FB_INITCTX ) as integer
end if

dim as integer is_ctorcall = any
expr = astBuildImplicitCtorCallEx( ctx.sym, expr, cBydescArrayArgParens( expr ), is_ctorcall )
expr = astBuildImplicitCtorCallEx( ctx.sym, expr, astBydescArrayArg( expr ), is_ctorcall )
if( expr = NULL ) then
exit function
end if
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/parser-decl-var.bas
Expand Up @@ -2120,7 +2120,7 @@ private function hBuildAutoVarInitializer( byval sym as FBSYMBOL ptr, byval expr
'' handle constructors..
else
dim as integer is_ctorcall = any
expr = astBuildImplicitCtorCallEx( sym, expr, cBydescArrayArgParens( expr ), is_ctorcall )
expr = astBuildImplicitCtorCallEx( sym, expr, astBydescArrayArg( expr ), is_ctorcall )

if( expr <> NULL ) then
if( is_ctorcall ) then
Expand Down
15 changes: 15 additions & 0 deletions src/compiler/parser-expr-variable.bas
Expand Up @@ -1188,6 +1188,21 @@ function cVariableEx overload _
else
if( is_nidxarray ) then
varexpr = astNewNIDXARRAY( varexpr )

if( check_array ) then
'' and (not fbGetIdxInParensOnly( )) ) then
if( lexGetToken( ) = CHAR_LPRNT ) then
if( lexGetLookAhead( 1 ) <> CHAR_RPRNT ) then
errReport( FB_ERRMSG_EXPECTEDARRAY )
else
lexSkipToken()
lexSkipToken()
end if
else
errReport( FB_ERRMSG_EXPECTEDARRAY )
end if
end if

end if
end if

Expand Down
27 changes: 3 additions & 24 deletions src/compiler/parser-proccall.bas
Expand Up @@ -14,21 +14,6 @@ declare sub hBaseInit( )
declare function hBaseMemberAccess( ) as integer
declare function hForwardCall( ) as integer

function cBydescArrayArgParens( byval arg as ASTNODE ptr ) as FB_PARAMMODE
function = INVALID
if( lexGetToken( ) = CHAR_LPRNT ) then
if( lexGetLookAhead( 1 ) = CHAR_RPRNT ) then
if( astGetSymbol( arg ) <> NULL ) then
if( symbIsArray( astGetSymbol( arg ) ) ) then
lexSkipToken( )
lexSkipToken( )
function = FB_PARAMMODE_BYDESC
end if
end if
end if
end if
end function

function cAssignFunctResult( byval is_return as integer ) as integer
dim as FBSYMBOL ptr res = any, subtype = any
dim as ASTNODE ptr rhs = any, expr = any
Expand Down Expand Up @@ -136,7 +121,7 @@ function cAssignFunctResult( byval is_return as integer ) as integer
if( is_return and (not returns_byref) ) then
if( has_ctor ) then
dim as integer is_ctorcall = any
rhs = astBuildImplicitCtorCallEx( res, rhs, cBydescArrayArgParens( rhs ), is_ctorcall )
rhs = astBuildImplicitCtorCallEx( res, rhs, astBydescArrayArg( rhs ), is_ctorcall )
if( rhs = NULL ) then
exit function
end if
Expand Down Expand Up @@ -1100,14 +1085,8 @@ function hForwardCall( ) as integer
end if

dim as FB_PARAMMODE mode = FB_PARAMMODE_BYREF

'' ('('')')?
if( lexGetToken( ) = CHAR_LPRNT ) then
if( lexGetLookAhead( 1 ) = CHAR_RPRNT ) then
lexSkipToken( )
lexSkipToken( )
mode = FB_PARAMMODE_BYDESC
end if
if( astIsNIDXARRAY( expr ) ) then
mode = FB_PARAMMODE_BYDESC
end if

''
Expand Down
30 changes: 11 additions & 19 deletions src/compiler/parser-quirk-file.bas
Expand Up @@ -695,26 +695,18 @@ private function hFileGet _
end if

isarray = FALSE
if( lexGetToken( ) = CHAR_LPRNT ) then
if( lexGetLookAhead( 1 ) = CHAR_RPRNT ) then
s = astGetSymbol( dstexpr )
if( s <> NULL ) then
isarray = symbIsArray( s )
if( isarray ) then
'' don't allow var-len strings
if( symbGetType( s ) = FB_DATATYPE_STRING ) then
errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
if( isfunc ) then
hSkipUntil( CHAR_RPRNT )
else
hSkipStmt( )
end if
return astNewCONSTi( 0 )
end if
lexSkipToken( )
lexSkipToken( )
end if
if( astIsNIDXARRAY( dstexpr ) ) then
s = astGetSymbol( dstexpr )
isarray = TRUE
'' don't allow var-len strings
if( symbGetType( s ) = FB_DATATYPE_STRING ) then
errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
if( isfunc ) then
hSkipUntil( CHAR_RPRNT )
else
hSkipStmt( )
end if
return astNewCONSTi( 0 )
end if
end if

Expand Down
1 change: 0 additions & 1 deletion src/compiler/parser.bi
Expand Up @@ -757,7 +757,6 @@ declare function cStrIdxOrMemberDeref _
) as ASTNODE ptr

declare sub cAssignment(byval assgexpr as ASTNODE ptr)
declare function cBydescArrayArgParens( byval arg as ASTNODE ptr ) as FB_PARAMMODE
declare function cAssignFunctResult( byval is_return as integer ) as integer

declare function cGfxStmt _
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/symb-proc.bas
Expand Up @@ -2528,7 +2528,7 @@ function symbFindSelfBopOvlProc _

'' try (l, r) -- don't pass the instance ptr
arg1.expr = r
arg1.mode = INVALID
arg1.mode = astBydescArrayArg(r)
arg1.next = NULL

proc = symbFindClosestOvlProc( head_proc, 1, @arg1, err_num )
Expand Down
154 changes: 154 additions & 0 deletions tests/structs/udt-array-ops-1.bas
@@ -0,0 +1,154 @@
#include once "fbcunit.bi"

SUITE( fbc_tests.structs.udt_array_ops_1 )

#macro setArray( expr )
for i as integer = lbound(array) to ubound(array)
expr
next
#endmacro

#macro chkArray( expr1, expr2 )
for i as integer = 0 to 9
CU_ASSERT( (expr1) = (expr2) )
next
#endmacro

type T
myarray(any) as integer
declare constructor( array() as integer )
declare operator let( array() as integer )
declare operator +=( array() as integer )
declare operator -=( array() as integer )
declare constructor()
end type

constructor T()
end constructor

constructor T( array() as integer )
redim myarray( lbound(array) to ubound(array) )
setArray( myarray(i) = array(i) )
end constructor

operator T.let( array() as integer )
redim myarray( lbound(array) to ubound(array) )
setArray( myarray(i) = array(i) )
end operator

operator T.+=( array() as integer )
setArray( myarray(i) += array(i) )
end operator

operator T.-=( array() as integer )
setArray( myarray(i) -= array(i) )
end operator

TEST( default )
dim a( 0 to 9 ) as integer = { 2,3,5,7,11,13,17,19,23,29 }
dim b( 0 to 9 ) as integer = { 1,2,3,4, 5, 6, 7, 8, 9,10 }
dim c( 0 to 9 ) as integer = { 1,1,1,1, 1, 1, 1, 1, 1, 1 }

dim x as T = a( )
chkArray( x.myarray(i), a(i) )

dim y as T ptr = new T( b() )
chkArray( y->myarray(i), b(i) )

dim z as T = c()
z = a()
chkArray( z.myarray(i), a(i) )

dim pz as T ptr = @z
*pz = b()
chkArray( pz->myarray(i), b(i) )

x = c()
chkArray( x.myarray(i), c(i) )

x += a()
chkArray( x.myarray(i), a(i) + c(i) )

x -= c()
chkArray( x.myarray(i), a(i) )

*y = c()
chkArray( y->myarray(i), c(i) )

*y += a()
chkArray( y->myarray(i), a(i) + c(i) )

*y -= c()
chkArray( y->myarray(i), a(i) )

delete y

END_TEST

type U
dim a( 0 to 9 ) as integer = { 2,3,5,7,11,13,17,19,23,29 }
dim b( 0 to 9 ) as integer = { 1,2,3,4, 5, 6, 7, 8, 9,10 }
dim c( 0 to 9 ) as integer = { 1,1,1,1, 1, 1, 1, 1, 1, 1 }

redim o(any) as T
redim po(any) as T ptr

declare constructor()
end type

constructor U()
dim h( 0 to 9 ) as integer = { 2,3,5,7,11,13,17,19,23,29 }

redim o(1 to 3) as T
o(1) = h()
o(2) = b()
o(3) = this.c()

redim this.po(1 to 3) as T ptr
po(1) = @o(1)
po(2) = @o(2)
po(3) = @o(3)

end constructor

TEST( member )

dim x as U
x.o(1) = x.a()
chkArray( x.o(1).myarray(i), x.a(i) )

dim y as U ptr = new U
y->o(1) = x.b()
chkArray( y->o(1).myarray(i), x.b(i) )

dim z as U
z.o(1) = x.a()
chkArray( z.o(1).myarray(i), x.a(i) )

dim pz as U ptr = @z
pz->o(1) = x.b()
chkArray( pz->o(1).myarray(i), x.b(i) )

x.o(1) = x.c()
chkArray( x.o(1).myarray(i), x.c(i) )

x.o(1) += x.a()
chkArray( x.o(1).myarray(i), x.a(i) + x.c(i) )

x.o(1) -= x.c()
chkArray( x.o(1).myarray(i), x.a(i) )

y->o(1) = x.c()
chkArray( y->o(1).myarray(i), x.c(i) )

y->o(1) += x.a()
chkArray( y->o(1).myarray(i), x.a(i) + x.c(i) )

y->o(1) -= x.c()
chkArray( y->o(1).myarray(i), x.a(i) )

delete y

END_TEST

END_SUITE

0 comments on commit d381789

Please sign in to comment.