Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement _IIF and fix _ROR & _ROL #574

Merged
merged 1 commit into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 4 additions & 45 deletions internal/c/libqb/include/bitops.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T> 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 <typename T> 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;
}
Expand Down
80 changes: 59 additions & 21 deletions source/qb64pe.bas
Original file line number Diff line number Diff line change
Expand Up @@ -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$ + "<uint8_t>(" + 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$ + "<uint16_t>(" + e$
typ& = UINTEGERTYPE - ISPOINTER
ELSEIF (sourcetyp AND 511) = 32 THEN
e$ = "func__" + rotlr_n$ + "32(" + e$
e$ = "func__" + rotlr_n$ + "<uint32_t>(" + e$
typ& = ULONGTYPE - ISPOINTER
ELSEIF (sourcetyp AND 511) = 64 THEN
e$ = "func__" + rotlr_n$ + "64(" + e$
e$ = "func__" + rotlr_n$ + "<uint64_t>(" + 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

Expand Down Expand Up @@ -23690,15 +23734,9 @@ FUNCTION SCase2$ (t$)
CASE "_ANDALSO"
SCase2$ = "_AndAlso"

CASE "ANDALSO"
SCase2$ = "AndAlso"

a740g marked this conversation as resolved.
Show resolved Hide resolved
CASE "_ORELSE"
SCase2$ = "_OrElse"

CASE "ORELSE"
SCase2$ = "OrElse"

CASE ELSE
newWord = -1
temp$ = ""
Expand Down
10 changes: 10 additions & 0 deletions source/subs_functions/subs_functions.bas
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion source/subs_functions/syntax_highlighter_list.bas
Original file line number Diff line number Diff line change
Expand Up @@ -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@"

Expand Down
60 changes: 60 additions & 0 deletions tests/compile_tests/iif/iif_test.bas
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions tests/compile_tests/iif/iif_test.output
Original file line number Diff line number Diff line change
@@ -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