@@ -25,7 +25,7 @@ private function hPPDefinedExpr( ) as ASTNODE ptr
2525 end if
2626
2727 '' Identifier
28- is_defined = (cIdentifierIfDefined ( ) <> NULL)
28+ is_defined = (cIdentifierOrUDTMember ( ) <> NULL)
2929
3030 '' ')'
3131 if ( hMatch( CHAR_RPRNT ) = FALSE ) then
@@ -444,15 +444,39 @@ function cDerefExpression( ) as ASTNODE ptr
444444 function = astBuildMultiDeref( derefcnt, expr, astGetFullType( expr ), astGetSubType( expr ) )
445445end function
446446
447- private function hProcPtrBody _
447+ private function hProcPtrResolveOverload _
448448 ( _
449- byval base_parent as FBSYMBOL ptr, _
449+ byval ovl_head_proc as FBSYMBOL ptr, _
450450 byval proc as FBSYMBOL ptr, _
451451 byval check_exact as boolean = FALSE _
452- ) as ASTNODE ptr
452+ ) as FBSYMBOL ptr
453+
454+ dim as FBSYMBOL ptr sym = ovl_head_proc
453455
454- dim as FBSYMBOL ptr sym = any
456+ if ( symbIsOperator( ovl_head_proc ) ) then
457+ dim as AST_OP op = any
458+ op = symbGetProcOpOvl( ovl_head_proc )
459+ sym = symbFindOpOvlProc( op, ovl_head_proc, proc )
455460
461+ elseif ( symbIsProc( proc ) ) then
462+ dim findopts as FB_SYMBFINDOPT = FB_SYMBFINDOPT_NONE
463+
464+ '' if it is a property then let the function pointer decide
465+ '' if we are looking for the set or get procedure where
466+ '' get is expected to have a return type
467+ if ( symbIsProperty( ovl_head_proc ) ) then
468+ if ( symbGetType( proc ) <> FB_DATATYPE_VOID ) then
469+ findopts = FB_SYMBFINDOPT_PROPGET
470+ end if
471+ end if
472+ sym = symbFindOverloadProc( ovl_head_proc, proc, findopts )
473+
474+ end if
475+
476+ return sym
477+ end function
478+
479+ private sub hCheckEmptyProcParens()
456480 '' '('')'?
457481 if ( lexGetToken( ) = CHAR_LPRNT ) then
458482 lexSkipToken( )
@@ -461,26 +485,33 @@ private function hProcPtrBody _
461485 hSkipUntil( CHAR_RPRNT, TRUE )
462486 end if
463487 end if
488+ end sub
489+
490+ private function hProcPtrBody _
491+ ( _
492+ byval base_parent as FBSYMBOL ptr, _
493+ byval proc as FBSYMBOL ptr, _
494+ byval check_exact as boolean , _
495+ byval is_vtable_offset as integer _
496+ ) as ASTNODE ptr
497+
498+ assert( proc <> NULL )
499+ assert( symbIsProc( proc ) )
464500
465501 '' resolve overloaded procs
466- if ( (symbIsOverloaded( proc ) <> 0 ) or (check_exact <> FALSE ) ) then
467- if ( parser.ctxsym <> NULL ) then
468- if ( symbIsProc( parser.ctxsym ) ) then
469- sym = symbFindOverloadProc ( proc, parser.ctxsym )
470- if ( sym <> NULL ) then
471- proc = sym
472- elseif ( check_exact ) then
473- errReport( FB_ERRMSG_NOMATCHINGPROC, TRUE )
474- return astNewCONSTi( 0 )
475- end if
502+ if ( parser.ctxsym <> NULL ) then
503+ if ( symbIsOverloaded( proc ) or check_exact ) then
504+ dim as FBSYMBOL ptr sym = any
505+ sym = hProcPtrResolveOverload ( proc, parser.ctxsym )
506+
507+ if ( sym ) then
508+ proc = sym
509+ elseif ( check_exact ) then
510+ errReport( FB_ERRMSG_NOMATCHINGPROC, TRUE )
511+ return astNewCONSTi( 0 )
476512 end if
477513 end if
478- end if
479514
480- '' taking the address of an method? pointer to methods not supported yet..
481- if ( symbIsMethod( proc ) ) then
482- errReportEx( FB_ERRMSG_ACCESSTONONSTATICMEMBER, symbGetFullProcName( proc ) )
483- return astNewCONSTi( 0 )
484515 end if
485516
486517 '' Check visibility of the proc
@@ -494,7 +525,125 @@ private function hProcPtrBody _
494525 callback( proc )
495526 end if
496527
497- function = astBuildProcAddrof( proc )
528+ if ( is_vtable_offset ) then
529+ '' if not virtual or abstract then procedure doesn't exist in
530+ '' the virtual table. Don't throw an error, just return an
531+ '' invalid vtable offset. vtable offsets are something that
532+ '' the user will have to deal with anyway
533+ dim as integer vtableoffset = - 2147483648 u
534+
535+ if ( symbIsAbstract( proc ) or symbIsVirtual( proc ) ) then
536+ vtableoffset = ( symbProcGetVtableIndex( proc ) - 2 ) * env.pointersize
537+ endif
538+
539+ var expr = astNewCONSTi( vtableoffset )
540+ return expr
541+ end if
542+
543+ if ( symbIsAbstract( proc ) ) then
544+ '' member is abstract and is not something we can get the address of
545+ '' until a virtual lookup at runtime ...
546+ '' return a null pointer of the function pointer instead
547+
548+ var expr = astNewCONSTi( 0 )
549+ expr = astNewCONV( typeAddrOf( FB_DATATYPE_FUNCTION ), symbAddProcPtrFromFunction( proc ), expr )
550+ return expr
551+ end if
552+
553+ return astBuildProcAddrof( proc )
554+ end function
555+
556+ '' PROCPTR '(' Proc ('('')')? VIRTUAL? ( ',' signature )? ')'
557+ function cProcPtrBody _
558+ ( _
559+ byval dtype as integer , _
560+ byval subtype as FBSYMBOL ptr _
561+ ) as ASTNODE ptr
562+
563+ dim as FBSYMCHAIN ptr chain_ = any
564+ dim as FBSYMBOL ptr sym = any, base_parent = any
565+ dim as ASTNODE ptr expr = any
566+ dim as integer is_vtable_offset = FALSE
567+
568+ if ( dtype = FB_DATATYPE_STRUCT ) then
569+ base_parent = subtype
570+ chain_ = NULL
571+
572+ else
573+ chain_ = cIdentifier( base_parent, _
574+ FB_IDOPT_CHECKSTATIC or _
575+ FB_IDOPT_ALLOWSTRUCT or _
576+ FB_IDOPT_ALLOWOPERATOR )
577+
578+ end if
579+
580+ sym = cIdentifierOrUDTMember( base_parent, chain_ )
581+
582+ if ( sym = NULL ) then
583+ errReport( FB_ERRMSG_UNDEFINEDSYMBOL )
584+ '' error recovery: skip until ')' and fake a node
585+ hSkipUntil( CHAR_RPRNT, TRUE )
586+ return astNewCONSTi( 0 )
587+ end if
588+
589+ if ( symbGetClass( sym ) <> FB_SYMBCLASS_PROC ) then
590+ errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
591+ '' error recovery: skip until ')' and fake a node
592+ hSkipUntil( CHAR_RPRNT, TRUE )
593+ return astNewCONSTi( 0 )
594+ end if
595+
596+ hCheckEmptyProcParens()
597+
598+ '' ','?
599+ if ( hMatch( CHAR_COMMA ) ) then
600+ dim as integer dtype = FB_DATATYPE_VOID
601+ dim as FBSYMBOL ptr subtype = NULL
602+ dim as integer is_exact = FALSE
603+
604+ '' VIRTUAL?
605+ if ( lexGetToken( ) = FB_TK_VIRTUAL ) then
606+ is_vtable_offset = TRUE
607+ lexSkipToken( LEXCHECK_POST_SUFFIX )
608+ end if
609+
610+ '' only if anything but ')' follows...
611+ if ( lexGetToken( ) <> CHAR_RPRNT ) then
612+ if ( cSymbolType( dtype, subtype ) = FALSE ) then
613+ errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
614+ '' error recovery: skip until ')' and fake a node
615+ hSkipUntil( CHAR_RPRNT, TRUE )
616+ return astNewCONSTi( 0 )
617+ end if
618+
619+ select case typeGetDtAndPtrOnly( dtype )
620+ case FB_DATATYPE_VOID
621+ '' 'ANY' matches first declaration
622+ case typeAddrOf( FB_DATATYPE_FUNCTION )
623+ is_exact = TRUE
624+ case else
625+ errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
626+ '' error recovery: skip until ')' and fake a node
627+ hSkipUntil( CHAR_RPRNT, TRUE )
628+ return astNewCONSTi( 0 )
629+ end select
630+ end if
631+
632+ dim as FBSYMBOL ptr oldsym = parser.ctxsym
633+ dim as integer old_dtype = parser.ctx_dtype
634+ parser.ctxsym = subtype
635+ parser.ctx_dtype = dtype
636+
637+ expr = hProcPtrBody( base_parent, sym, is_exact, is_vtable_offset )
638+
639+ parser.ctxsym = oldsym
640+ parser.ctx_dtype = old_dtype
641+
642+ else
643+ expr = hProcPtrBody( base_parent, sym, FALSE , is_vtable_offset )
644+ end if
645+
646+ return expr
498647end function
499648
500649private function hVarPtrBody _
@@ -517,6 +666,7 @@ private function hVarPtrBody _
517666 '' hand, we need to make sure we don't prematurely optimize
518667 '' the CONST specifier away in the event that it is needed
519668 '' to be known with AST type checking later.
669+
520670 dim as ASTNODE ptr t = astSkipConstCASTs( expr )
521671
522672 select case as const astGetClass( t )
@@ -596,11 +746,12 @@ function cAddrOfExpression( ) as ASTNODE ptr
596746 '' proc?
597747 if ( sym <> NULL ) then
598748 lexSkipToken( LEXCHECK_POST_LANG_SUFFIX )
599- return hProcPtrBody( base_parent, sym )
600- '' anything else..
601- else
602- return hVarPtrBody( base_parent, chain_ )
749+ hCheckEmptyProcParens()
750+ return hProcPtrBody( base_parent, sym, FALSE , FALSE )
603751 end if
752+
753+ '' anything else
754+ return hVarPtrBody( base_parent, chain_ )
604755 end if
605756
606757 select case as const lexGetToken( )
@@ -625,7 +776,7 @@ function cAddrOfExpression( ) as ASTNODE ptr
625776 hSkipUntil( CHAR_RPRNT, TRUE )
626777 end if
627778
628- '' PROCPTR '(' Proc ('('')')? ')'
779+ '' PROCPTR '(' Proc ('('')')? VIRTUAL? ( ',' signature )? ')'
629780 case FB_TK_PROCPTR
630781 lexSkipToken( LEXCHECK_POST_SUFFIX )
631782
@@ -637,51 +788,7 @@ function cAddrOfExpression( ) as ASTNODE ptr
637788 return astNewCONSTi( 0 )
638789 end if
639790
640- '' proc?
641- dim as FBSYMCHAIN ptr chain_ = any
642- dim as FBSYMBOL ptr sym = any, base_parent = any
643-
644- chain_ = cIdentifier( base_parent, _
645- FB_IDOPT_DEFAULT or FB_IDOPT_ALLOWSTRUCT )
646- sym = symbFindByClass( chain_, FB_SYMBCLASS_PROC )
647- if ( sym = NULL ) then
648- errReport( FB_ERRMSG_UNDEFINEDSYMBOL )
649- '' error recovery: skip until ')' and fake a node
650- hSkipUntil( CHAR_RPRNT, TRUE )
651- return astNewCONSTi( 0 )
652- else
653- lexSkipToken( LEXCHECK_POST_LANG_SUFFIX )
654- end if
655-
656- '' ',' ?
657- if ( hMatch( CHAR_COMMA ) ) then
658- dim dtype as integer
659- dim subtype as FBSYMBOL ptr
660- if ( cSymbolType( dtype, subtype ) = FALSE ) then
661- errReport( FB_ERRMSG_SYNTAXERROR, TRUE )
662- '' error recovery: skip until ')' and fake a node
663- hSkipUntil( CHAR_RPRNT, TRUE )
664- return astNewCONSTi( 0 )
665- else
666- if ( typeGetDtAndPtrOnly( dtype ) = typeAddrOf( FB_DATATYPE_FUNCTION ) ) then
667- dim oldsym as FBSYMBOL ptr = parser.ctxsym
668- dim old_dtype as integer = parser.ctx_dtype
669- parser.ctxsym = subtype
670- parser.ctx_dtype = dtype
671- expr = hProcPtrBody( base_parent, sym, TRUE )
672- parser.ctxsym = oldsym
673- parser.ctx_dtype = old_dtype
674- else
675- errReport( FB_ERRMSG_SYNTAXERROR, TRUE )
676- '' error recovery: skip until ')' and fake a node
677- hSkipUntil( CHAR_RPRNT, TRUE )
678- return astNewCONSTi( 0 )
679- end if
680- end if
681-
682- else
683- expr = hProcPtrBody( base_parent, sym )
684- end if
791+ expr = cProcPtrBody( 0 , NULL )
685792
686793 '' ')'
687794 if ( hMatch( CHAR_RPRNT ) = FALSE ) then
0 commit comments