I’m adding this to share my thoughts, especially the quirks that QBJS 0.10.0 has at the time of writing.
Constants
All consts in QBJS should not have sigil suffixes:
const maxHealth = 100
const vgaWidth = 320
' Valid in QB64 but not in QBJS
const maxHealth% = 100
const vgaWidth& = 320The interpreter will throw an error if you add a suffix. An example error message is something like this:
ERROR : 0 : Missing initializer in const declaration
This is due to how dynamic typing is implemented in its backend language (JS)
Variables
This of QBJS as a QB64-to-JS transpiler with the full power of JS
This makes dynamic typing possible, which is similar to Lua
Known Issue
Some variables with the system prefix may cause the transpiler to break
For example, with the name systemFont being used as a variable:
dim as TBMFont systemFontThis will cause the transpiler to sometimes produce an incomplete object string in JS, but this only happens occasionally
If this happens, just reorder your variable declarations — there may be occasional ordering-dependent bugs in the QBJS-to-JS transpiler
Image Handling
Image handles start at 1000 instead of a negative value
With the same example code
Option _Explicit
Dim As Long imgGasolineMaid
imgGasolineMaid = _LoadImage("IMG\gasoline_maid_256px.png")
Print "image handle:", imgGasolineMaid
_FreeImage imgGasolineMaidThis is the comparison:
QB64: image handle: -10
QBJS: image handle: 1000
Non-existent image
Loading a non-existent image is also possible, which is dangerous:
Option _Explicit
Dim As Long imgInvalid
imgInvalid = _loadImage("invalid_image.jpg")
Print "image handle:", imgInvalidOutput (QBJS):
image handle: 1000
This can be prevented with the _FileExists statement
Option _Explicit
Dim As Long imgInvalid
If Not _FileExists("invalid_image.jpg") Then
Print "Invalid image doesn't exist!"
Else
imgInvalid = _LoadImage("invalid_image.jpg")
Print "image handle:", imgInvalid
End IfOutput:
Invalid image doesn't exist!
Precompiler
$Let doesn’t work with QBJS
$If precompiler only works with either:
$If WEB then$If Javascript then
Use $If WEB to use the functionalities that only exist in QBJS
Option _Explicit
$if WEB then
import console from "lib\web\console.bas"
console.log "Hello QBJS!"
$else
print "Hello QB64!"
$endifUse $If Javascript block to execute any JS code in it:
Option _Explicit
Dim As Long a, b, c
$if javascript then
a = 1
b = 2
c = a + b
$endif
print cOutput:
3
This makes it possible to use fetch API and BigInt along with QB64
Console / Debugging
$Debug and any Log statements (_LogError, _LogWarn, _LogTrace, and so on) don’t work in QBJS
Instead, use the Console import
Option _Explicit
$if web then
import console from "lib\web\console.bas"
console.log "Hello QBJS!"
console.warn "This is a warning"
console.error "This is an error log"
$endifThis makes it possible to use console in QBJS, but since everything is async under the hood, using console.log in Javascript context will throw an error
Function Return Value
Since QBJS uses JavaScript as its backend, it can return an object, or even a UDT
Option _Explicit
Type TCat
name As String
colour As String
End Type
Dim cat As TCat
cat = newCat("Honey", "orange")
Print cat.name, cat.colour
' implementation
Function newCat(name$, colour$)
Dim c As TCat
c.name = name$
c.colour = colour$
newCat = c
End FunctionThis makes it similar to VBScript but with full browser support
Module System
QBJS is more like the OOP in JS, which makes it also similar to Lua
MAIN.BAS
import console from "lib\web\console.bas"
import YourModule from "modules\hi.bas"
YourModule.sayHi
print YourModule.add(2, 3)MODULES\HI.BAS
option _explicit
export sayHi, add
sub sayHi
print "Hi from another module!"
end sub
function add(a, b)
add = a + b
end functionJavaScript Interop
(TBA)
Sound Handling
(TBA)
MapTriangle
It’s not possible to use _MapTriangle statement in QBJS, so drawing a rotated image + scaled image is still a dream at the moment of writing
ByRef or ByVal?
QBJS always uses pass-by-value instead of pass-by-reference like what QB64 uses
Therefore, loadImage in QBJS returns a value instead of assigning to the target image handle
Boolean value
The values true & false can be used immediately from JS
The AND, OR, and NOT operators in QBJS use JS bitwise operators under the hood (Ref: https://qb64phoenix.com/forum/showthread.php?tid=3376)
import console from "lib\web\console.bas"
console.log "What is TRUE? " + i32str(1 > 0)
console.log "What is FALSE? " + i32str(1 < 0)true is 1, false is 0
This makes casting to strings can be easier instead of using the usual STR$
console.log "What is TRUE? " + (1 > 0)Not operator in QBJS
The transpiler uses the ~ operator under the hood, which basically flips all the bits in the 64-bit integer. This makes it harder to track a boolean value & an actual integer
So, instead of using the usual
If Not isImageSet(imgHandle) Then Exit SubIt’s better to use:
If isImageSet(imgHandle) = false Then Exit SubBut in my case of returning an integer (supposedly), I’ll use an integer return value instead of a boolean. Something like this:
Function isImageSet% (imgHandle As Long)
isImageSet = -(imgHandle >= 1000)
End Functiontrue is 1 in JS, while false is the same: 0
About _PutImage
Compared to QB64, it uses destX + destW - 1 and also destY + destH - 1 because of how the decrement is handled automatically under the hood
So this is the acceptable version in QBJS:
Sub sprRegion (imgHandle As Long, srcX%, srcY%, srcW%, srcH%, destX%, destY%)
_PutImage (destX%, destY%)-(destX% + srcW%, destY% + srcH%), imgHandle, , (srcX%, srcY%)-(srcX% + srcW%, srcY% + srcH%)
End SubAbout copying a UDT
UDT’s (User-defined Types) in QBJS are basically just a JS object
It doesn’t support copying as if it’s a record in Pascal, since the object reference remains the same
I found this problem when calling loadBMFont, but the output is just ~~~~~~, while it should be something like "Hello QBJS!" but with PICO-8 font
So, instead of declaring tempGlyph at the beginning like what I usually do in Pascal, something like this:
sub loadBMFont ' procedure signature
dim as TBMFontGlyph tempGlyph
' the rest of the implementation
end subIt’s better to declare the variable inside the block it’s supposed to be
elseif startsWith(txtLine, "char") and not startsWith(txtLine, "chars") then
dim as TBMFontGlyph tempGlyph
' the rest of the implementation
end if
Leave a Reply