From 8865f2c5463327a71a371a687dc9e7745726dfbe Mon Sep 17 00:00:00 2001 From: Samuel Gomes Date: Sun, 24 Nov 2024 22:43:36 +0530 Subject: [PATCH] Implement _IIF and fix _ROR & _ROL --- internal/c/libqb/include/bitops.h | 49 +----------- source/qb64pe.bas | 80 ++++++++++++++----- source/subs_functions/subs_functions.bas | 10 +++ .../syntax_highlighter_list.bas | 2 +- tests/compile_tests/iif/iif_test.bas | 60 ++++++++++++++ tests/compile_tests/iif/iif_test.output | 17 ++++ 6 files changed, 151 insertions(+), 67 deletions(-) create mode 100644 tests/compile_tests/iif/iif_test.bas create mode 100644 tests/compile_tests/iif/iif_test.output diff --git a/internal/c/libqb/include/bitops.h b/internal/c/libqb/include/bitops.h index 4cab3e423..8d75876a6 100644 --- a/internal/c/libqb/include/bitops.h +++ b/internal/c/libqb/include/bitops.h @@ -8,59 +8,18 @@ uint64_t getubits(uint32_t bsize, uint8_t *base, intptr_t i); int64_t getbits(uint32_t bsize, uint8_t *base, intptr_t i); void setbits(uint32_t bsize, uint8_t *base, intptr_t i, int64_t val); -// The rotation functions below are the way they are for a couple of reasons: -// 1. They are safer (well folks seem to think so; see https://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts) -// 2. We are using C library constants and there is just 1 numeric literal - '1' -// 3. GGC recognizes the 'pattern' and will optimize it out to 'roX' and 3 more instructions when using O2 -static inline constexpr uint8_t func__rol8(uint8_t value, unsigned int count) { - const unsigned int mask = CHAR_BIT * sizeof(value) - 1; +template static inline constexpr T func__rol(T value, unsigned int count) { + const unsigned int mask = CHAR_BIT * sizeof(T) - 1; count &= mask; return (value << count) | (value >> (-count & mask)); } -static inline constexpr uint8_t func__ror8(uint8_t value, unsigned int count) { - const unsigned int mask = CHAR_BIT * sizeof(value) - 1; +template static inline constexpr T func__ror(T value, unsigned int count) { + const unsigned int mask = CHAR_BIT * sizeof(T) - 1; count &= mask; return (value >> count) | (value << (-count & mask)); } -static inline constexpr uint16_t func__rol16(uint16_t value, unsigned int count) { - const unsigned int mask = CHAR_BIT * sizeof(value) - 1; - count &= mask; - return (value << count) | (value >> (-count & mask)); -} - -static inline constexpr uint16_t func__ror16(uint16_t value, unsigned int count) { - const unsigned int mask = CHAR_BIT * sizeof(value) - 1; - count &= mask; - return (value >> count) | (value << (-count & mask)); -} - -static inline constexpr uint32_t func__rol32(uint32_t value, unsigned int count) { - const unsigned int mask = CHAR_BIT * sizeof(value) - 1; - count &= mask; - return (value << count) | (value >> (-count & mask)); -} - -static inline constexpr uint32_t func__ror32(uint32_t value, unsigned int count) { - const unsigned int mask = CHAR_BIT * sizeof(value) - 1; - count &= mask; - return (value >> count) | (value << (-count & mask)); -} - -static inline constexpr uint64_t func__rol64(uint64_t value, unsigned int count) { - const unsigned int mask = CHAR_BIT * sizeof(value) - 1; - count &= mask; - return (value << count) | (value >> (-count & mask)); -} - -static inline constexpr uint64_t func__ror64(uint64_t value, unsigned int count) { - const unsigned int mask = CHAR_BIT * sizeof(value) - 1; - count &= mask; - return (value >> count) | (value << (-count & mask)); -} - -// bit-shifting static inline constexpr uint64_t func__shl(uint64_t a1, int b1) { return a1 << b1; } diff --git a/source/qb64pe.bas b/source/qb64pe.bas index cd6041073..1d352b824 100644 --- a/source/qb64pe.bas +++ b/source/qb64pe.bas @@ -16676,41 +16676,85 @@ FUNCTION evaluatefunc$ (a2$, args AS LONG, typ AS LONG) IF Error_Happened THEN EXIT FUNCTION '------------------------------------------------------------------------------------------------------------ + ' IIF support + IF n$ = "_IIF" THEN + IF curarg = 1 THEN ' expression + r$ = r$ + "(" + nocomma = 1 + ELSEIF curarg = 2 THEN ' true part + IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0) + IF Error_Happened THEN EXIT FUNCTION + + typ& = sourcetyp ' return type is always derived from true part + r$ = r$ + ")?(" + e$ + "):" + e$ = "" + nocomma = 1 + + GOTO dontevaluate + ELSEIF curarg = 3 THEN ' false part + nocomma = 0 + + IF (sourcetyp AND ISSTRING) <> (typ& AND ISSTRING) THEN + Give_Error "falsePart and truePart must be of the same type" + EXIT FUNCTION + END IF + + IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0) + IF Error_Happened THEN EXIT FUNCTION + + r$ = r$ + "(" + e$ + "))" + + GOTO evalfuncspecial + END IF + END IF + ' ROR & ROL support - IF n$ = "_ROR" OR n$ = "_ROL" THEN - rotlr_n$ = LCASE$(RIGHT$(n$, 3)) ' Get the last 3 characters and convert to lower case. We'll need this to construct the C call - IF curarg = 1 THEN ' First parameter - IF (sourcetyp AND ISSTRING) OR (sourcetyp AND ISFLOAT) OR (sourcetyp AND ISOFFSET) OR (sourcetyp AND ISUDT) THEN ' Bad parameters types + IF n$ = "_ROR" _ORELSE n$ = "_ROL" THEN + rotlr_n$ = LCASE$(RIGHT$(n$, 3)) ' we'll need this to construct the C call + + IF curarg = 1 THEN ' first parameter + IF (sourcetyp AND ISSTRING) _ORELSE (sourcetyp AND ISFLOAT) THEN Give_Error "Expected non-floating-point value" EXIT FUNCTION END IF - IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0) ' This gets the C-style dereferencing syntax for an identifier (I think XD) + + IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0) IF Error_Happened THEN EXIT FUNCTION + ' Establish which function (if any!) should be used IF (sourcetyp AND 511) = 8 THEN ' sourcetyp is the type of data (bits can be examined to get more details) - e$ = "func__" + rotlr_n$ + "8(" + e$ - typ& = UBYTETYPE - ISPOINTER ' We force the return type here. This is passed back up to the caller + e$ = "func__" + rotlr_n$ + "(" + e$ + typ& = UBYTETYPE - ISPOINTER ' the return type is passed back up to the caller ELSEIF (sourcetyp AND 511) = 16 THEN - e$ = "func__" + rotlr_n$ + "16(" + e$ + e$ = "func__" + rotlr_n$ + "(" + e$ typ& = UINTEGERTYPE - ISPOINTER ELSEIF (sourcetyp AND 511) = 32 THEN - e$ = "func__" + rotlr_n$ + "32(" + e$ + e$ = "func__" + rotlr_n$ + "(" + e$ typ& = ULONGTYPE - ISPOINTER ELSEIF (sourcetyp AND 511) = 64 THEN - e$ = "func__" + rotlr_n$ + "64(" + e$ + e$ = "func__" + rotlr_n$ + "(" + e$ typ& = UINTEGER64TYPE - ISPOINTER ELSE Give_Error "Unknown data size" EXIT FUNCTION END IF - r$ = e$ ' Save whatever syntax he have so far - e$ = "" ' This must be cleared so that it is not repeated when we get to parameter 2 - GOTO dontevaluate ' Don't evaluate until we get the second parameter - ELSEIF curarg = 2 THEN ' Second parameter + + r$ = e$ ' save whatever syntax he have so far + e$ = "" ' this must be cleared so that it is not repeated when we get to parameter 2 + + GOTO dontevaluate ' don't evaluate until we get the second parameter + ELSEIF curarg = 2 THEN ' second parameter + IF (sourcetyp AND ISSTRING) _ORELSE (sourcetyp AND ISFLOAT) THEN + Give_Error "Expected non-floating-point value" + EXIT FUNCTION + END IF + IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0) IF Error_Happened THEN EXIT FUNCTION + r$ = r$ + e$ + ")" - GOTO evalfuncspecial ' Evaluate now that we have everything + + GOTO evalfuncspecial ' evaluate now that we have everything END IF END IF @@ -23690,15 +23734,9 @@ FUNCTION SCase2$ (t$) CASE "_ANDALSO" SCase2$ = "_AndAlso" - CASE "ANDALSO" - SCase2$ = "AndAlso" - CASE "_ORELSE" SCase2$ = "_OrElse" - CASE "ORELSE" - SCase2$ = "OrElse" - CASE ELSE newWord = -1 temp$ = "" diff --git a/source/subs_functions/subs_functions.bas b/source/subs_functions/subs_functions.bas index d972e0eeb..2cc8cd2aa 100644 --- a/source/subs_functions/subs_functions.bas +++ b/source/subs_functions/subs_functions.bas @@ -87,6 +87,16 @@ SUB reginternal clearid id.n = "_Continue": id.subfunc = 2: id.callname = "sub_stub": regid + clearid + id.n = "_IIf" + id.subfunc = 1 + id.args = 3 + id.arg = MKL$(OFFSETTYPE - ISPOINTER) + MKL$(STRINGTYPE - ISPOINTER) + MKL$(STRINGTYPE - ISPOINTER) ' overridden in qb64pe.bas + id.specialformat = "?,?,?" + id.ret = STRINGTYPE - ISPOINTER ' overridden in qb64pe.bas + id.hr_syntax = "_IIF(expression, truePart, falsePart)" + regid + clearid id.n = "_Resize" id.subfunc = 2 diff --git a/source/subs_functions/syntax_highlighter_list.bas b/source/subs_functions/syntax_highlighter_list.bas index 4d186c380..180fc1650 100644 --- a/source/subs_functions/syntax_highlighter_list.bas +++ b/source/subs_functions/syntax_highlighter_list.bas @@ -56,7 +56,7 @@ listOfKeywords$ = listOfKeywords$ +_ ' [I] - Keywords alphabetical (1st line = QB64, 2nd line = QB4.5, 3rd line = OpenGL) listOfKeywords$ = listOfKeywords$ +_ -"_ICON@_INCLERRORFILE$@_INCLERRORLINE@_INFLATE$@_INPUTBOX$@_INSTRREV@_INTEGER64@" +_ +"_ICON@_IIF@_INCLERRORFILE$@_INCLERRORLINE@_INFLATE$@_INPUTBOX$@_INSTRREV@_INTEGER64@" +_ "IF@IMP@INKEY$@INP@INPUT@INPUT$@INSTR@INT@INTEGER@INTERRUPT@INTERRUPTX@IOCTL@IOCTL$@IS@" +_ "_GLINDEXD@_GLINDEXDV@_GLINDEXF@_GLINDEXFV@_GLINDEXI@_GLINDEXIV@_GLINDEXMASK@_GLINDEXPOINTER@_GLINDEXS@_GLINDEXSV@_GLINDEXUB@_GLINDEXUBV@_GLINITNAMES@_GLINTERLEAVEDARRAYS@_GLISENABLED@_GLISLIST@_GLISTEXTURE@" diff --git a/tests/compile_tests/iif/iif_test.bas b/tests/compile_tests/iif/iif_test.bas new file mode 100644 index 000000000..f73fe9cfc --- /dev/null +++ b/tests/compile_tests/iif/iif_test.bas @@ -0,0 +1,60 @@ +$CONSOLE:ONLY + +OPTION _EXPLICIT + +CONST TEXT_HELLO = "hello" +CONST TEXT_WORLD = "world" + +TYPE t + f AS SINGLE + i AS _OFFSET +END TYPE + +DIM f AS SINGLE: f = 3.141592653589793239 +DIM i AS _OFFSET: i = 255 +DIM s AS STRING: s = TEXT_HELLO + +DIM t AS t +t.f = f +t.i = i + +DIM a(1) AS SINGLE +a(0) = f +a(1) = _IIF(_FALSE, 0, i) ' naughty! + +PRINT _IIF(f > 0, f, i) +PRINT _IIF(i > 0, i, f) + +PRINT _IIF(t.f > 0, t.f, t.i) +PRINT _IIF(t.i > 0, t.i, t.f) + +PRINT _IIF(a(0) > 0, a(0), a(1)) +PRINT _IIF(a(1) > 0, a(1), a(0)) + +PRINT _IIF(f > 0, 1.1!, 2) +PRINT _IIF(i > 0, 2, 1.1!) + +PRINT _IIF(f = 0, "f", "i") +PRINT _IIF(i = 0, "i", "f") + +' PRINT and LPRINT has bugs and throws error when using string comparisons +WRITE _IIF(s = TEXT_HELLO, TEXT_HELLO, TEXT_WORLD) +WRITE _IIF(s = TEXT_WORLD, 1, 2) + +PRINT _IIF(i > 0, foo, bar) +PRINT _IIF(i < 0, bar, foo) + +DIM age AS _BYTE: age = 17 +PRINT _IIF(age >= 18, "over 18", "under 18") + +SYSTEM + +FUNCTION foo& + PRINT "foo called!" + foo = 512 +END FUNCTION + +FUNCTION bar& + PRINT "bar called!" + bar = 128 +END FUNCTION diff --git a/tests/compile_tests/iif/iif_test.output b/tests/compile_tests/iif/iif_test.output new file mode 100644 index 000000000..283ad544f --- /dev/null +++ b/tests/compile_tests/iif/iif_test.output @@ -0,0 +1,17 @@ + 3.141593 + 255 + 3.141593 + 255 + 3.141593 + 255 + 1.1 + 2 +i +f +"hello" +2 +foo called! + 512 +foo called! + 512 +under 18