bmx-ng / bcc

A next-generation bcc parser for BlitzMax
zlib License
33 stars 13 forks source link

Long %% and Short @@ shorthand issue #570

Open braxtonrivers opened 2 years ago

braxtonrivers commented 2 years ago

Bug Report

The following is a small example showing Long %% and Short @@ with their respective shorthand issue.

Could we also consider adding Bool and Void to ng since they are in the parser and making them reserved keywords?

SuperStrict

Framework brl.standardio

Print %1 'Int
Print Int(1)

Print

Print %%2 'Long <-- works only when 1 anything else gives 'Compiler Error Expecting expression but encountered '%'
Print Long(2)

Print

Print !3 'Double
Print Double(3)

Print

Print #4 'Float
Print Float(4)

Print

Print @5 'Byte
Print Byte(5)

Print

Print @@6 'Short <-- this line gives 'Compiler Error Expecting expression but encountered '@'
Print Short(6)

Expected Behavior

should print 2 and 6 respectively for Long %% and Short @@ shorthand forms but gives expression error

Actual Behavior

both lines give Expecting expression but encountered error

Environment

HurryStarfish commented 2 years ago

Support for "%%" and "@@" aside - you have indeed encountered a compiler bug here, but it's not what you think.

BlitzMax has a fairly obscure feature that allows you to write a type after a variable in an expression. This lets you make sure that the variable has this exact type, and you will get an error if it doesn't:

Local i:Int

Local x1:Int = i
Local x2:Int = i:Int   ' compiles because i is declared as an Int; does the same as the line above
Local x3:Int = i:Float ' Compile Error: Identifier type does not match declared type

The same thing can be done with the return type of functions:

Function F:Int()
    Return 1
End Function

Local y1:Int = F:Int()   ' compiles because F returns an Int
Local y2:Int = F:Float() ' Compile Error: Identifier type does not match declared type

So what does your code do? It does this kind of check on return type of Print. Print !3 is not the same as Print Double(3) (if you wanted to specify the type of the literal, you'd have to write Print 3:Double or Print 3!). Print !3 it is the same as Print!(3), and this is where the compiler bug is: such calls should give you compile errors because the return type of Print is void. But that feature is currently broken in BlitzMax-NG; and the compiler simply seems to ignore the !.

So why does Print %%2 a compile error, but Print %%1 doesn't? Because % also has another purpose - it is the prefix for binary literals. Print %%1 is the same as Print%(%1) and means "make sure Print returns an Int (which is broken) and call it with the binary number 1. Print %%2 gives you an error (albeit with a misleading message) because 2 is not a valid binary digit.

HurryStarfish commented 2 years ago

As for adding a Bool type: https://github.com/bmx-ng/bmx-ng/issues/118

braxtonrivers commented 2 years ago

Apologies the small example was made after discovering that the following did not work.

I thought that maybe Short and Long could also use shorthand to make it more readable and compact, and a little less wordy but I guess that is not currently possible due to the parser.

Also thank you, I did not notice your proposal, as it is present in the parser but not exposed, so I thought it would be a great addition as we now have UInt etc and ng has evolved far beyond its origins, not to mention it would also benefit with debugging on Windows when using and dealing with WinAPI.

Local A1ByteArray:Byte[]=[Byte($ff),Byte($ab),Byte($d5),Byte($ab),Byte($d5),Byte($ab),Byte($d5),Byte($ff)]

Local A2ByteArray:Byte[]=[$ff@,$ab@,$d5@,$ab@,$d5@,$ab@,$d5@,$ff@]

Local A1ShortArray:Short[]=[Short($ffff),Short($aaab),Short($d555),Short($aaab),Short($d555),Short($aaab), ..
Short($d555),Short($aaab),Short($d555),Short($aaab),Short($d555),Short($aaab),Short($d555),Short($aaab), ..
Short($d555),Short($ffff)]

Local A2ShortArray:Short[]=[$ffff@@,$aaab@@,$d555@@,$aaab@@,$d555@@,$aaab@@,$d555@@,$aaab@@, ..
$d555@@,$aaab@@,$d555@@,$aaab@@,$d555@@,$aaab@@,$d555@@,$ffff@@] 'does not work

Local A1LongArray:Long[]=[Long($ffff),Long($aaab),Long($d555),Long($aaab),Long($d555),Long($aaab),Long($d555), ..
Long($aaab),Long($d555),Long($aaab),Long($d555),Long($aaab),Long($d555),Long($aaab),Long($d555),Long($ffff)]

Local A2LongArray:Long[]=[$ffff%%,$aaab%%,$d555%%,$aaab%%,$d555%%,$aaab%%,$d555%%,$aaab%%, ..
$d555%%,$aaab%%,$d555%%,$aaab%%,$d555%%,$aaab%%,$d555%%,$ffff%%] 'does not work
HurryStarfish commented 2 years ago

Still, the "verbose" equivalent of e.g. $ff@ is $ff:Byte, and you should be using one of those forms to create Byte literals. Byte($ff) is not the same, it is an Int literal with a cast to Byte. It may not make a difference in this particular case, but it will with certain other types and values, for example:

Print 0.99999999:Double
Print Double(0.99999999)

If you run this in legacy BlitzMax, you'll see that the second line outputs 1.0000000000000000, because the number gets rounded to Float precision. (Not in NG currently, but that's because literals are bugged.)

braxtonrivers commented 2 years ago

Oh thank you very much for the explanation, I appreciate it I did not realise.