Closed davecamp closed 3 years ago
The expectation is for the compiler to issue an error at the != token in the BMax code.
wrapping the "f" into brackets ... and the error is detected.
SuperStrict
Function TestThis:Int(f:Byte Ptr, y:Int)
If (f) != y
EndIf
EndFunction
Print TestThis(Null, 0)
Also it does not need to happen in a function...
SuperStrict
Framework Brl.Standardio
Global f:Byte Ptr
Global y:Int
If f != y
EndIf
Type TBinaryCompareExpr Extends TBinaryExpr
Method Semant:TExpr(options:Int = 0)
...
ty=BalanceTypes( lhs.exprType,rhs.exprType )
op
is =
here - so somehow the exclamation mark is eaten.
Balance types ... lhs="Byte Ptr" rhs="Int" op="="
Type TParser.ParseCompareExpr() already just receives =
from _toke
.
This method then "falls back" to various other potential expressions - until it reaches "ParsePrimaryExpr"
parseandexpr "f"
ParseCompareExpr _toke="f"
ParseBitorExpr _toke="f"
ParseBitandExpr _toke="f"
ParseAddSubExpr _toke="f"
ParseMulDivExpr _toke="f"
ParsePowExpr _toke="f"
ParseUnaryExpr _toke="f"
ParsePrimaryExpr _toke="f"
inside this method there is:
Default
Select _tokeType
Case TOKE_IDENT
Local tok:TToker=New TToker.Copy( _toker )
Local ty:TType=CParseIdentType()
If ty
expr=New TIdentTypeExpr.Create( ty )
Else
_toker=tok
_toke=_toker.Toke()
which I extended to print out some stuff
print " default _tokeType="+_tokeType +" _toke=~q"+_toke+"~q"
Select _tokeType
Case TOKE_IDENT
Local tok:TToker=New TToker.Copy( _toker )
Local ty:TType=CParseIdentType()
If ty
expr=New TIdentTypeExpr.Create( ty )
Else
_toker=tok
print " else1: ~q"+_toke+"~q"
_toke=_toker.Toke()
print " else2: ~q"+_toke+"~q"
_tokeType=_toker.TokeType()
expr=New TIdentExpr.Create( ParseIdent(),,,unknownIdentsEvalFalse )
print " toke="+_toke
ty = ParseConstNumberType()
print " toke="+_toke
print " expr="+expr.toString()
print " ty="+ty.toString()
If TArrayType(ty) Then
If Not TArrayType(ty).elemType Then
TArrayType(ty).elemType = New TIdentType.Create(TIdentExpr(expr).ident)
expr=New TIdentTypeExpr.Create( ty )
End If
End If
EndIf
print " toke after="+_toke
output is:
default _tokeType=2 _toke="f"
else1: "!"
else2: "f"
toke=!
toke==
expr=TIdentExpr("f")
ty=Double
toke after==
So it seems as if ParseConstNumberType
is eating it ...
And of course this method is seeing !
as declaration for "Double" (hence the ty=Double
output).
So the real issue seems to be that "!" is an allowed "number type shortcut" - and that these things do not need the colon as the long versions require.
'for strings this does not work :D
'If "hi":String = "hi" Then Print "hi"
'If "hi"$ = "hi" Then Print "hi"
If 1:Int = 1 Then Print "1"
If 2% = 2 Then Print "2"
If 3! = 3:Double Then Print "3"
In our very specific case this is not a bug ... but simply a "cast".
Local x:Int = 1
If x:Double = 1 Then Print "1"
If x! = 1 Then Print "1"
If x != 1 Then Print "1"
it is not a cast - yet ... ah I hope @HurryStarfish can find the time to write what exactly it is :D
While @GWRon has already identified what's going on here, I want to clarify two more things:
If x:Double = 1
or If x! = 1
is not a cast. It is just a compile-time check that x
has the type Double
- it has no effect if it does, and produce a compile error if it doesn't.
Casts always have the form Typename(Expression)
(or, for built-in types, Typename Expression
).!
. The If f != y
from the original code should not compile, but neither should If f = y
.
Legacy BlitzMax does not allow comparing Byte Ptr
and Int
like that, and I see no reason why NG should relax this restriction. Conceptually, a pointer and an Int are two different things (a location in memory and a number) and it doesn't really make sense to directly compare those; if you want to do it, you should be forced to explicitly convert one to the other by using a cast.
This code compiles and runs with incorrectly generated c code.
The If statement becomes