mirror of
https://github.com/irmen/prog8.git
synced 2025-01-02 14:32:26 +00:00
implementing const long
This commit is contained in:
parent
ea1daa97d3
commit
a874aec6a1
@ -11,6 +11,7 @@ fun Number.toHex(): String {
|
||||
// 0..15 -> "0".."15"
|
||||
// 16..255 -> "$10".."$ff"
|
||||
// 256..65536 -> "$0100".."$ffff"
|
||||
// larger -> "$12345678"
|
||||
// negative values are prefixed with '-'.
|
||||
val integer = this.toInt()
|
||||
if(integer<0)
|
||||
@ -19,7 +20,7 @@ fun Number.toHex(): String {
|
||||
in 0 until 16 -> integer.toString()
|
||||
in 0 until 0x100 -> "$"+integer.toString(16).padStart(2,'0')
|
||||
in 0 until 0x10000 -> "$"+integer.toString(16).padStart(4,'0')
|
||||
else -> throw IllegalArgumentException("number too large for 16 bits $this")
|
||||
else -> "$"+integer.toString(16).padStart(8,'0')
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,11 +28,12 @@ fun UInt.toHex(): String {
|
||||
// 0..15 -> "0".."15"
|
||||
// 16..255 -> "$10".."$ff"
|
||||
// 256..65536 -> "$0100".."$ffff"
|
||||
// larger -> "$12345678"
|
||||
return when (this) {
|
||||
in 0u until 16u -> this.toString()
|
||||
in 0u until 0x100u -> "$"+this.toString(16).padStart(2,'0')
|
||||
in 0u until 0x10000u -> "$"+this.toString(16).padStart(4,'0')
|
||||
else -> throw IllegalArgumentException("number too large for 16 bits $this")
|
||||
else -> "$"+this.toString(16).padStart(8,'0')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,9 +38,10 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
|
||||
if(numLiteral.type==DataType.LONG) {
|
||||
// see if LONG values may be reduced to something smaller
|
||||
val smaller = NumericLiteral.optimalInteger(numLiteral.number.toInt(), numLiteral.position)
|
||||
if(smaller.type!=DataType.LONG)
|
||||
if(smaller.type!=DataType.LONG) {
|
||||
return listOf(IAstModification.ReplaceNode(numLiteral, smaller, parent))
|
||||
}
|
||||
}
|
||||
|
||||
if(parent is Assignment) {
|
||||
val iDt = parent.target.inferType(program)
|
||||
@ -437,10 +438,11 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
|
||||
}
|
||||
if(valueDt isnot decl.datatype) {
|
||||
val cast = numval.cast(decl.datatype, true)
|
||||
if (cast.isValid)
|
||||
if (cast.isValid) {
|
||||
return listOf(IAstModification.ReplaceNode(numval, cast.valueOrZero(), decl))
|
||||
}
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
|
@ -717,7 +717,7 @@ internal class AstChecker(private val program: Program,
|
||||
if(decl.names.size>1)
|
||||
throw InternalCompilerException("vardecls with multiple names should have been converted into individual vardecls")
|
||||
|
||||
if(decl.datatype==DataType.LONG)
|
||||
if(decl.datatype==DataType.LONG && decl.type!=VarDeclType.CONST)
|
||||
errors.err("integer overflow", decl.position)
|
||||
if(decl.type==VarDeclType.MEMORY) {
|
||||
if (decl.datatype == DataType.BOOL || decl.datatype == DataType.ARRAY_BOOL)
|
||||
@ -1691,12 +1691,14 @@ internal class AstChecker(private val program: Program,
|
||||
|
||||
private fun checkLongType(expression: Expression) {
|
||||
if(expression.inferType(program).istype(DataType.LONG)) {
|
||||
if((expression.parent as? VarDecl)?.type!=VarDeclType.CONST) {
|
||||
if (expression.parent !is RepeatLoop) {
|
||||
if (errors.noErrorForLine(expression.position))
|
||||
errors.err("integer overflow", expression.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkValueTypeAndRangeString(targetDt: DataType, value: StringLiteral) : Boolean {
|
||||
return if (targetDt == DataType.STR) {
|
||||
@ -1830,31 +1832,38 @@ internal class AstChecker(private val program: Program,
|
||||
DataType.UBYTE -> {
|
||||
if(value.type==DataType.FLOAT)
|
||||
err("unsigned byte value expected instead of float; possible loss of precision")
|
||||
val number=value.number.toInt()
|
||||
val number=value.number
|
||||
if (number < 0 || number > 255)
|
||||
return err("value '$number' out of range for unsigned byte")
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
if(value.type==DataType.FLOAT)
|
||||
err("byte value expected instead of float; possible loss of precision")
|
||||
val number=value.number.toInt()
|
||||
val number=value.number
|
||||
if (number < -128 || number > 127)
|
||||
return err("value '$number' out of range for byte")
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
if(value.type==DataType.FLOAT)
|
||||
err("unsigned word value expected instead of float; possible loss of precision")
|
||||
val number=value.number.toInt()
|
||||
val number=value.number
|
||||
if (number < 0 || number > 65535)
|
||||
return err("value '$number' out of range for unsigned word")
|
||||
}
|
||||
DataType.WORD -> {
|
||||
if(value.type==DataType.FLOAT)
|
||||
err("word value expected instead of float; possible loss of precision")
|
||||
val number=value.number.toInt()
|
||||
val number=value.number
|
||||
if (number < -32768 || number > 32767)
|
||||
return err("value '$number' out of range for word")
|
||||
}
|
||||
DataType.LONG -> {
|
||||
if(value.type==DataType.FLOAT)
|
||||
err("integer value expected instead of float; possible loss of precision")
|
||||
val number=value.number
|
||||
if (number < -2147483647 || number > 2147483647)
|
||||
return err("value '$number' out of range for long")
|
||||
}
|
||||
DataType.BOOL -> {
|
||||
if (value.type!=DataType.BOOL) {
|
||||
err("type of value ${value.type} doesn't match target $targetDt")
|
||||
|
@ -24,6 +24,50 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
// check and possibly adjust value datatype vs decl datatype
|
||||
val valueType = decl.value?.inferType(program)
|
||||
if(valueType!=null && !valueType.istype(decl.datatype)) {
|
||||
if(valueType.isUnknown) {
|
||||
errors.err("value has incompatible type for ${decl.datatype}", decl.value!!.position)
|
||||
return noModifications
|
||||
}
|
||||
val valueDt = valueType.getOr(DataType.UNDEFINED)
|
||||
when(decl.type) {
|
||||
VarDeclType.VAR -> {
|
||||
if(decl.isArray) {
|
||||
errors.err("value has incompatible type ($valueType) for the variable (${decl.datatype})", decl.value!!.position)
|
||||
} else {
|
||||
if (valueDt.largerThan(decl.datatype)) {
|
||||
val constValue = decl.value?.constValue(program)
|
||||
if (constValue != null)
|
||||
errors.err("value '$constValue' out of range for ${decl.datatype}", constValue.position)
|
||||
else
|
||||
errors.err("value out of range for ${decl.datatype}", decl.value!!.position)
|
||||
} else {
|
||||
throw FatalAstException("value dt differs from decl dt ${decl.position}")
|
||||
}
|
||||
}
|
||||
}
|
||||
VarDeclType.CONST -> {
|
||||
// change the vardecl type itself as well, but only if it's smaller
|
||||
if(valueDt.largerThan(decl.datatype)) {
|
||||
val constValue = decl.value!!.constValue(program)!!
|
||||
errors.err("value '${constValue.number}' out of range for ${decl.datatype}", constValue.position)
|
||||
} else {
|
||||
val changed = decl.copy(valueDt)
|
||||
return listOf(IAstModification.ReplaceNode(decl, changed, parent))
|
||||
}
|
||||
}
|
||||
VarDeclType.MEMORY -> if(!valueType.isWords && !valueType.isBytes)
|
||||
throw FatalAstException("value type for a memory var should be word or byte (address)")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> {
|
||||
return if(parent is IStatementContainer)
|
||||
listOf(ScopeFlatten(scope, parent as IStatementContainer))
|
||||
|
@ -46,8 +46,8 @@ class TestNumbers: FunSpec({
|
||||
(-50050).toHex() shouldBe "-\$c382"
|
||||
(-65535).toHex() shouldBe "-\$ffff"
|
||||
(-65535L).toHex() shouldBe "-\$ffff"
|
||||
shouldThrow<IllegalArgumentException> { 65536.toHex() }
|
||||
shouldThrow<IllegalArgumentException> { 65536L.toHex() }
|
||||
(65536).toHex() shouldBe "\$00010000"
|
||||
(-65536).toHex() shouldBe "-\$00010000"
|
||||
}
|
||||
|
||||
test("testFloatToMflpt5") {
|
||||
|
@ -17,7 +17,7 @@ import prog8tests.helpers.compileText
|
||||
|
||||
class TestSubroutines: FunSpec({
|
||||
|
||||
test("string arg for byte param proper errormessage and subroutineptr in array too") {
|
||||
test("string arg for byte param proper errormessage") {
|
||||
val text="""
|
||||
main {
|
||||
sub func(ubyte bb) {
|
||||
@ -26,14 +26,12 @@ class TestSubroutines: FunSpec({
|
||||
|
||||
sub start() {
|
||||
func("abc")
|
||||
uword[] commands = ["abc", 1.234]
|
||||
}
|
||||
}"""
|
||||
val errors = ErrorReporterForTests()
|
||||
compileText(C64Target(), false, text, writeAssembly = true, errors=errors) shouldBe null
|
||||
errors.errors.size shouldBe 2
|
||||
errors.errors.size shouldBe 1
|
||||
errors.errors[0] shouldContain "type mismatch, was: STR expected: UBYTE"
|
||||
errors.errors[1] shouldContain "value has incompatible type"
|
||||
}
|
||||
|
||||
test("stringParameter") {
|
||||
|
@ -22,6 +22,19 @@ import prog8tests.helpers.compileText
|
||||
class TestVariousCompilerAst: FunSpec({
|
||||
context("arrays") {
|
||||
|
||||
test("invalid array element proper errormessage") {
|
||||
val text="""
|
||||
main {
|
||||
sub start() {
|
||||
uword[] commands = ["abc", 1.234]
|
||||
}
|
||||
}"""
|
||||
val errors = ErrorReporterForTests()
|
||||
compileText(C64Target(), false, text, writeAssembly = true, errors=errors) shouldBe null
|
||||
errors.errors.size shouldBe 1
|
||||
errors.errors[0] shouldContain "value has incompatible type"
|
||||
}
|
||||
|
||||
test("array literals") {
|
||||
val text="""
|
||||
%zeropage basicsafe
|
||||
|
@ -293,7 +293,7 @@ class VarDecl(val type: VarDeclType,
|
||||
|
||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||
require(replacement is Expression && (value==null || node===value))
|
||||
value = replacement
|
||||
value = replacement // note: any datatype differences between the value and the decl itself, will be fixed by a separate ast walker step
|
||||
replacement.parent = this
|
||||
}
|
||||
|
||||
@ -311,10 +311,12 @@ class VarDecl(val type: VarDeclType,
|
||||
throw IllegalArgumentException("attempt to get zero value for vardecl that shouldn't get it")
|
||||
}
|
||||
|
||||
override fun copy(): VarDecl {
|
||||
override fun copy(): VarDecl = copy(datatype)
|
||||
|
||||
fun copy(newDatatype: DataType): VarDecl {
|
||||
if(names.size>1)
|
||||
throw FatalAstException("should not copy a vardecl that still has multiple names")
|
||||
val copy = VarDecl(type, origin, datatype, zeropage, arraysize?.copy(), name, names, value?.copy(),
|
||||
val copy = VarDecl(type, origin, newDatatype, zeropage, arraysize?.copy(), name, names, value?.copy(),
|
||||
sharedWithAsm, splitArray, alignment, dirty, position)
|
||||
copy.allowInitializeWithZero = this.allowInitializeWithZero
|
||||
return copy
|
||||
|
@ -167,7 +167,7 @@ constdecl: 'const' varinitializer ;
|
||||
|
||||
memoryvardecl: ADDRESS_OF varinitializer;
|
||||
|
||||
datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'float' | 'str' | 'bool' ;
|
||||
datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'long' | 'float' | 'str' | 'bool' ;
|
||||
|
||||
arrayindex: '[' expression ']' ;
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
</options>
|
||||
<keywords keywords="&;->;@;and;as;asmsub;break;clobbers;continue;do;downto;else;extsub;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;step;sub;to;true;unroll;until;when;while;xor;~" ignore_case="false" />
|
||||
<keywords2 keywords="%address;%align;%asm;%asmbinary;%asminclude;%breakpoint;%encoding;%import;%ir;%launcher;%memtop;%option;%output;%zeropage;%zpallowed;%zpreserved;@align64;@alignpage;@alignword;@bank;@dirty;@nozp;@requirezp;@shared;@split;@zp;atascii:;cp437:;default:;iso16:;iso5:;iso:;kata:;petscii:;sc:" />
|
||||
<keywords3 keywords="bool;byte;const;float;str;ubyte;uword;void;word" />
|
||||
<keywords3 keywords="bool;byte;const;float;long;str;ubyte;uword;void;word" />
|
||||
<keywords4 keywords="abs;call;callfar;callfar2;clamp;cmp;defer;divmod;len;lsb;max;memory;min;mkword;msb;peek;peekf;peekw;poke;pokef;pokew;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;setlsb;setmsb;sgn;sizeof;sqrt" />
|
||||
</highlighting>
|
||||
<extensionMap>
|
||||
|
@ -24,7 +24,7 @@
|
||||
<Keywords name="Folders in comment, open"></Keywords>
|
||||
<Keywords name="Folders in comment, middle"></Keywords>
|
||||
<Keywords name="Folders in comment, close"></Keywords>
|
||||
<Keywords name="Keywords1">void const
str
byte ubyte bool
word uword
float
zp shared split requirezp nozp</Keywords>
|
||||
<Keywords name="Keywords1">void const
str
byte ubyte bool
long word uword
float
zp shared split requirezp nozp</Keywords>
|
||||
<Keywords name="Keywords2">%address
%asm
%ir
%asmbinary
%asminclude
%align
%breakpoint
%encoding
%import
%memtop
%launcher
%option
%output
%zeropage
%zpreserved
%zpallowed</Keywords>
|
||||
<Keywords name="Keywords3">inline sub asmsub extsub
clobbers
asm
if
when else
if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z
for in step do while repeat unroll
break continue return goto</Keywords>
|
||||
<Keywords name="Keywords4">abs call callfar callfar2 clamp cmp defer divmod len lsb lsl lsr memory mkword min max msb peek peekw peekf poke pokew pokef rsave rsavex rrestore rrestorex rnd rndw rol rol2 ror ror2 setlsb setmsb sgn sizeof sqrtw</Keywords>
|
||||
|
@ -149,7 +149,7 @@ contexts:
|
||||
- match: (\b\w+\.)
|
||||
scope: entity.name.namespace.prog8
|
||||
storage:
|
||||
- match: (\b(ubyte|byte|word|uword|float|str)\b)
|
||||
- match: (\b(ubyte|byte|word|uword|long|float|str)\b)
|
||||
scope: storage.type.prog8
|
||||
- match: (\b(const)\b)
|
||||
scope: storage.modifier.prog8
|
||||
|
@ -38,7 +38,7 @@ syn match prog8Directive "\(^\|\s\)%\(zpreserved\|zpallowed\|address\|encoding\|
|
||||
syn match prog8Directive "\(^\|\s\)%\(align\|asmbinary\|asminclude\|breakpoint\)\>"
|
||||
syn match prog8Directive "\(^\|\s\)%\(asm\|ir\)\>"
|
||||
|
||||
syn match prog8Type "\<\%(u\?byte\|u\?word\|float\|str\|bool\)\>"
|
||||
syn match prog8Type "\<\%(u\?byte\|u\?word\|float\|str\|bool\|long\)\>"
|
||||
syn region prog8ArrayType matchgroup=prog8Type
|
||||
\ start="\<\%(u\?byte\|u\?word\|float\|str\|bool\)\[" end="\]"
|
||||
\ transparent
|
||||
|
Loading…
Reference in New Issue
Block a user