Skip to content

Commit d20a63b

Browse files
authored
Merge pull request #80 from jayrm/select-case-const
Fix #878: select case as const
2 parents 8a76540 + 9cbb288 commit d20a63b

File tree

10 files changed

+7763
-420
lines changed

10 files changed

+7763
-420
lines changed

src/compiler/parser-decl-symbtype.bas

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,21 @@ function cConstIntExpr _
1515
byval dtype as integer _
1616
) as longint
1717

18+
'' bad expression? fake a constant value
1819
if( expr = NULL ) then
1920
errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
2021
expr = astNewCONSTi( 0, dtype )
2122
end if
2223

24+
'' not a CONST? delete the tree and fake a constant value
2325
if( astIsCONST( expr ) = FALSE ) then
2426
errReport( FB_ERRMSG_EXPECTEDCONST )
2527
astDelTree( expr )
2628
expr = astNewCONSTi( 0, dtype )
2729
end if
2830

31+
'' flush the expr to the specified dtype.
32+
'' default is FB_DATATYPE_INTEGER, if not specified in call to cConstIntExpr()
2933
function = astConstFlushToInt( expr, dtype )
3034
end function
3135

@@ -36,71 +40,92 @@ type RANGEVALUES
3640
as ulongint umax
3741
end type
3842

43+
function hIsConstInRange _
44+
( _
45+
byval dtype as integer, _
46+
byval value as longint, _
47+
byval todtype as integer _
48+
) as integer
49+
50+
'' TODO:
51+
'' - consider moving this table to symb-data.bas
52+
'' - consider using in astCheckConst(), possibly? with -w pedantic
53+
'' - consider adding src/compiler/fb-limit.bi or inc/fb-limit.bi. These
54+
'' limit values are used in several locations in fbc compiler source.
55+
56+
static range( FB_SIZETYPE_BOOLEAN to FB_SIZETYPE_UINT64 ) as RANGEVALUES = _
57+
{ _
58+
/' FB_SIZETYPE_BOOLEAN '/ ( -1ull, 0ll, 0ull ), _
59+
/' FB_SIZETYPE_INT8 '/ ( -&h80ull, &h7fll, &h7full ), _
60+
/' FB_SIZETYPE_UINT8 '/ ( 0ll , &h7fll, &hffull ), _
61+
/' FB_SIZETYPE_INT16 '/ ( -&h8000ull, &h7fffll, &h7fffull ), _
62+
/' FB_SIZETYPE_UINT16 '/ ( 0ll , &h7fffll, &hffffull ), _
63+
/' FB_SIZETYPE_INT32 '/ ( -&h80000000ull, &h7fffffffll, &h7fffffffull ), _
64+
/' FB_SIZETYPE_UINT32 '/ ( 0ll , &h7fffffffll, &hffffffffull ), _
65+
/' FB_SIZETYPE_INT64 '/ ( -&h8000000000000000ull, &h7fffffffffffffffll, &h7fffffffffffffffull ), _
66+
/' FB_SIZETYPE_UINT64 '/ ( 0ll , &h7fffffffffffffffll, &hffffffffffffffffull ) _
67+
}
68+
69+
dim as RANGEVALUES ptr r = @range( typeGetSizeType( todtype ) )
70+
71+
if( typeIsSigned( dtype ) ) then
72+
if( typeIsSigned( todtype ) ) then
73+
function = (value >= r->smin) and (value <= r->smax)
74+
else
75+
if( typeGetSizeType(dtype) = FB_SIZETYPE_INT64 and typeGetSizeType(todtype) = FB_SIZETYPE_UINT64 ) then
76+
function = (value >= 0) and (culngint(value) <= culngint(r->smax))
77+
else
78+
function = (value >= 0) and (culngint(value) <= r->umax)
79+
end if
80+
endif
81+
else
82+
if( typeIsSigned( todtype ) ) then
83+
if( typeGetSizeType(dtype) = FB_SIZETYPE_UINT64 and typeGetSizeType(todtype) = FB_SIZETYPE_INT64 ) then
84+
function = (culngint(value) <= culngint(r->smax))
85+
else
86+
function = (culngint(value) <= r->umax)
87+
end if
88+
else
89+
function = (culngint(value) <= r->umax)
90+
endif
91+
end if
92+
93+
end function
94+
3995
''
4096
function cConstIntExprRanged _
4197
( _
4298
byval expr as ASTNODE ptr, _
4399
byval todtype as integer _
44100
) as longint
45101

46-
static range( FB_SIZETYPE_BOOLEAN to FB_SIZETYPE_UINT64 ) as RANGEVALUES = _
47-
{ _
48-
/' FB_SIZETYPE_BOOLEAN '/ ( -1, 0, 0 ), _
49-
/' FB_SIZETYPE_INT8 '/ ( -128, 127, 127 ), _
50-
/' FB_SIZETYPE_UINT8 '/ ( 0, 127, 255 ), _
51-
/' FB_SIZETYPE_INT16 '/ ( -32768, 32767, 32767 ), _
52-
/' FB_SIZETYPE_UINT16 '/ ( 0, 32767, 65535 ), _
53-
/' FB_SIZETYPE_INT32 '/ ( -2147483648ll, 2147483647ll, 2147483647ull ), _
54-
/' FB_SIZETYPE_UINT32 '/ ( 0, 2147483647ll, 4294967295ull ), _
55-
/' FB_SIZETYPE_INT64 '/ ( -9223372036854775808ll, 9223372036854775807ll, 9223372036854775807ull ), _
56-
/' FB_SIZETYPE_UINT64 '/ ( 0, 9223372036854775807ll, 18446744073709551615ull ) _
57-
}
102+
'' - this function is very similar cConstIntExpr() except that
103+
'' we need to save the dtype of expr before it is flushed, but
104+
'' if expr was invalid it might be NULL
58105

59106
dim as longint value = any
60107
dim as integer dtype = any
61-
dim as integer result = any
62-
dim as RANGEVALUES ptr r = any
63-
64-
r = @range( typeGetSizeType( todtype ) )
65108

109+
'' bad expression? fake a constant value
66110
if( expr = NULL ) then
67111
errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
68112
expr = astNewCONSTi( 0, todtype )
69113
end if
70114

115+
'' not a CONST? delete the tree and fake a longint constant value
71116
if( astIsCONST( expr ) = FALSE ) then
72117
errReport( FB_ERRMSG_EXPECTEDCONST )
73118
astDelTree( expr )
74119
expr = astNewCONSTi( 0, FB_DATATYPE_LONGINT )
75120
end if
76121

122+
'' save the dtype of the expression before we flush the ast to longint
77123
dtype = astGetDataType( expr )
78124

125+
'' flush the expr to longint, it's the largest signed integer datatype we have
79126
value = astConstFlushToInt( expr, FB_DATATYPE_LONGINT )
80127

81-
if( typeIsSigned( dtype ) ) then
82-
if( typeIsSigned( todtype ) ) then
83-
result = (value >= r->smin) and (value <= r->smax)
84-
else
85-
if( dtype = FB_DATATYPE_LONGINT and todtype = FB_DATATYPE_ULONGINT ) then
86-
result = (value >= 0) and (culngint(value) <= culngint(r->smax))
87-
else
88-
result = (value >= 0) and (culngint(value) <= culngint(r->umax))
89-
end if
90-
endif
91-
else
92-
if( typeIsSigned( todtype ) ) then
93-
if( dtype = FB_DATATYPE_ULONGINT and todtype = FB_DATATYPE_LONGINT ) then
94-
result = (culngint(value) <= culngint(r->smax))
95-
else
96-
result = (culngint(value) <= culngint(r->umax))
97-
end if
98-
else
99-
result = (culngint(value) <= r->umax)
100-
endif
101-
end if
102-
103-
if( not result ) then
128+
if( not hIsConstInRange( dtype, value, todtype ) ) then
104129
errReportWarn( FB_WARNINGMSG_CONVOVERFLOW )
105130
end if
106131

src/compiler/parser.bi

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,12 @@ declare function cConstIntExpr _
801801
byval expr as ASTNODE ptr, _
802802
byval dtype as integer = FB_DATATYPE_INTEGER _
803803
) as longint
804+
declare function hIsConstInRange _
805+
( _
806+
byval dtype as integer, _
807+
byval value as longint, _
808+
byval todtype as integer _
809+
) as integer
804810
declare function cConstIntExprRanged _
805811
( _
806812
byval expr as ASTNODE ptr, _

tests/compound/select_const.bas

Lines changed: 70 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -568,11 +568,18 @@ SUITE( fbc_tests.compound.select_const )
568568

569569
dim as integer ok, nok
570570

571-
#macro TEST_RANGE( T, a, b, c, d, p, f )
571+
#macro TEST_RANGE( T, a, b, c_, d_, p, f )
572572
scope
573573
ok = 0
574574
nok = 0
575575
dim v as T
576+
#if LITERAL
577+
#define c c_
578+
#define d d_
579+
#else
580+
const c as T = c_
581+
const d as T = d_
582+
#endif
576583
v = a
577584
do
578585
select case as const v
@@ -627,40 +634,68 @@ SUITE( fbc_tests.compound.select_const )
627634
TEST_RANGE( T, b-10, b-1, b-2, b-2, 1, 9 )
628635
#endmacro
629636

630-
'' byte range edges and near zero
631-
TEST_RANGE_EDGES( byte, -128, 127 )
632-
TEST_RANGE_EDGES( byte, -2, 2 )
633-
TEST_RANGE_EDGES( ubyte, 0, 255 )
634-
635-
TEST_RANGE_EDGES( short, -129, 128 )
636-
TEST_RANGE_EDGES( short, -1, 256 )
637-
TEST_RANGE_EDGES( long, -129, 128 )
638-
TEST_RANGE_EDGES( long, -1, 256 )
639-
TEST_RANGE_EDGES( longint, -129, 128 )
640-
TEST_RANGE_EDGES( longint, -1, 256 )
641-
642-
'' short range edges and near zero
643-
TEST_RANGE_EDGES( short, -32768, 32767 )
644-
TEST_RANGE_EDGES( short, -2, 2 )
645-
TEST_RANGE_EDGES( ushort, 0, 65535 )
646-
647-
TEST_RANGE_EDGES( long, -32769, 32768 )
648-
TEST_RANGE_EDGES( long, 0, 65536 )
649-
TEST_RANGE_EDGES( longint, -32769, 32768 )
650-
TEST_RANGE_EDGES( longint, 0, 65536 )
651-
652-
'' long range edges and near zero
653-
TEST_RANGE_EDGES( long, -2147483648, 2147483647 )
654-
TEST_RANGE_EDGES( long, -2, 2 )
655-
TEST_RANGE_EDGES( ulong, 0, 4294967295 )
656-
657-
TEST_RANGE_EDGES( longint, -2147483649ll, 2147483648ll )
658-
TEST_RANGE_EDGES( longint, 0, 4294967296ll )
659-
660-
'' longint range edges and near zero
661-
TEST_RANGE_EDGES( longint, -9223372036854775808ll, 9223372036854775807ll )
662-
TEST_RANGE_EDGES( longint, -2ll, 2ll )
663-
TEST_RANGE_EDGES( ulongint, 0, 18446744073709551615ull )
637+
#macro TEST_RANGES()
638+
'' byte range edges and near zero
639+
TEST_RANGE_EDGES( byte, -128, 127 )
640+
TEST_RANGE_EDGES( byte, -2, 2 )
641+
TEST_RANGE_EDGES( ubyte, 0, 255 )
642+
643+
TEST_RANGE_EDGES( short, -129, 128 )
644+
TEST_RANGE_EDGES( short, -1, 256 )
645+
TEST_RANGE_EDGES( long, -129, 128 )
646+
TEST_RANGE_EDGES( long, -1, 256 )
647+
TEST_RANGE_EDGES( integer, -129, 128 )
648+
TEST_RANGE_EDGES( integer, -1, 256 )
649+
TEST_RANGE_EDGES( longint, -129, 128 )
650+
TEST_RANGE_EDGES( longint, -1, 256 )
651+
652+
'' short range edges and near zero
653+
TEST_RANGE_EDGES( short, -32768, 32767 )
654+
TEST_RANGE_EDGES( short, -2, 2 )
655+
TEST_RANGE_EDGES( ushort, 0, 65535 )
656+
657+
TEST_RANGE_EDGES( long, -32769, 32768 )
658+
TEST_RANGE_EDGES( long, 0, 65536 )
659+
TEST_RANGE_EDGES( integer, -32769, 32768 )
660+
TEST_RANGE_EDGES( integer, 0, 65536 )
661+
TEST_RANGE_EDGES( longint, -32769, 32768 )
662+
TEST_RANGE_EDGES( longint, 0, 65536 )
663+
664+
'' long range edges and near zero
665+
TEST_RANGE_EDGES( long, -2147483648, 2147483647 )
666+
TEST_RANGE_EDGES( long, -2, 2 )
667+
TEST_RANGE_EDGES( ulong, 0, 4294967295 )
668+
669+
TEST_RANGE_EDGES( longint, -2147483649ll, 2147483648ll )
670+
TEST_RANGE_EDGES( longint, 0, 4294967296ll )
671+
672+
#ifdef __FB_64BIT__
673+
TEST_RANGE_EDGES( integer, -9223372036854775807ll-1ll, 9223372036854775807ll )
674+
TEST_RANGE_EDGES( integer, -2ll, 2ll )
675+
TEST_RANGE_EDGES( uinteger, 0, 18446744073709551615ull )
676+
#else
677+
TEST_RANGE_EDGES( integer, -2147483648, 2147483647 )
678+
TEST_RANGE_EDGES( integer, -2, 2 )
679+
TEST_RANGE_EDGES( uinteger, 0, 4294967295 )
680+
681+
TEST_RANGE_EDGES( longint, -2147483649ll, 2147483648ll )
682+
TEST_RANGE_EDGES( longint, 0, 4294967296ll )
683+
#endif
684+
685+
'' longint range edges and near zero
686+
TEST_RANGE_EDGES( longint, -9223372036854775807ll-1ll, 9223372036854775807ll )
687+
TEST_RANGE_EDGES( longint, -2ll, 2ll )
688+
TEST_RANGE_EDGES( ulongint, 0, 18446744073709551615ull )
689+
#endmacro
690+
691+
'' Test Ranges using literal values
692+
#define LITERAL TRUE
693+
TEST_RANGES()
694+
695+
'' Test Ranges using a CONST symbol
696+
#undef LITERAL
697+
#define LITERAL FALSE
698+
TEST_RANGES()
664699

665700
END_TEST
666701

0 commit comments

Comments
 (0)