mirror of
https://github.com/irmen/prog8.git
synced 2025-02-19 11:31:07 +00:00
allow Python-style negative array indexing to count from the end
This commit is contained in:
parent
ad9eaeafeb
commit
4cd9bb8f99
@ -170,7 +170,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
if(arrayIx.usesPointerVariable) {
|
if(arrayIx.usesPointerVariable) {
|
||||||
if(eltSize!=1)
|
if(eltSize!=1)
|
||||||
throw AssemblyError("non-array var indexing requires bytes dt")
|
throw AssemblyError("non-array var indexing requires bytes dt")
|
||||||
if(arrayIx.index.type!=DataType.UBYTE)
|
if(arrayIx.index.type !in ByteDatatypes)
|
||||||
throw AssemblyError("non-array var indexing requires bytes index")
|
throw AssemblyError("non-array var indexing requires bytes index")
|
||||||
val tr = translateExpression(arrayIx.index)
|
val tr = translateExpression(arrayIx.index)
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
|
@ -1374,11 +1374,10 @@ internal class AstChecker(private val program: Program,
|
|||||||
if(target.datatype !in IterableDatatypes && target.datatype!=DataType.UWORD)
|
if(target.datatype !in IterableDatatypes && target.datatype!=DataType.UWORD)
|
||||||
errors.err("indexing requires an iterable or address uword variable", arrayIndexedExpression.position)
|
errors.err("indexing requires an iterable or address uword variable", arrayIndexedExpression.position)
|
||||||
val arraysize = target.arraysize?.constIndex()
|
val arraysize = target.arraysize?.constIndex()
|
||||||
|
val index = arrayIndexedExpression.indexer.constIndex()
|
||||||
if(arraysize!=null) {
|
if(arraysize!=null) {
|
||||||
// check out of bounds
|
|
||||||
val index = arrayIndexedExpression.indexer.constIndex()
|
|
||||||
if(index!=null && (index<0 || index>=arraysize))
|
if(index!=null && (index<0 || index>=arraysize))
|
||||||
errors.err("array index out of bounds", arrayIndexedExpression.indexer.position)
|
errors.err("index out of bounds", arrayIndexedExpression.indexer.position)
|
||||||
} else if(target.datatype == DataType.STR) {
|
} else if(target.datatype == DataType.STR) {
|
||||||
if(target.value is StringLiteral) {
|
if(target.value is StringLiteral) {
|
||||||
// check string lengths for non-memory mapped strings
|
// check string lengths for non-memory mapped strings
|
||||||
@ -1387,6 +1386,8 @@ internal class AstChecker(private val program: Program,
|
|||||||
if (index != null && (index < 0 || index >= stringLen))
|
if (index != null && (index < 0 || index >= stringLen))
|
||||||
errors.err("index out of bounds", arrayIndexedExpression.indexer.position)
|
errors.err("index out of bounds", arrayIndexedExpression.indexer.position)
|
||||||
}
|
}
|
||||||
|
} else if(index!=null && index<0) {
|
||||||
|
errors.err("index out of bounds", arrayIndexedExpression.indexer.position)
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
errors.err("indexing requires a variable to act upon", arrayIndexedExpression.position)
|
errors.err("indexing requires a variable to act upon", arrayIndexedExpression.position)
|
||||||
|
@ -262,5 +262,20 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
|||||||
}
|
}
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
|
||||||
|
val index = arrayIndexedExpression.indexer.constIndex()
|
||||||
|
if(index!=null && index<0) {
|
||||||
|
val target = arrayIndexedExpression.arrayvar.targetVarDecl(program)
|
||||||
|
val arraysize = target?.arraysize?.constIndex()
|
||||||
|
if(arraysize!=null) {
|
||||||
|
// replace the negative index by the normal index
|
||||||
|
val newIndex = NumericLiteral.optimalNumeric(arraysize+index, arrayIndexedExpression.indexer.position)
|
||||||
|
arrayIndexedExpression.indexer.indexExpr = newIndex
|
||||||
|
newIndex.linkParents(arrayIndexedExpression.indexer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return noModifications
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,6 +294,7 @@ Here are some examples of arrays::
|
|||||||
|
|
||||||
value = array[3] ; the fourth value in the array (index is 0-based)
|
value = array[3] ; the fourth value in the array (index is 0-based)
|
||||||
char = string[4] ; the fifth character (=byte) in the string
|
char = string[4] ; the fifth character (=byte) in the string
|
||||||
|
char = string[-2] ; the second-to-last character in the string (Python-style indexing from the end)
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Right now, the array should be small enough to be indexable by a single byte index.
|
Right now, the array should be small enough to be indexable by a single byte index.
|
||||||
@ -329,6 +330,7 @@ An uword variable can be used in limited scenarios as a 'pointer' to a byte in m
|
|||||||
dynamic, location. You can use array indexing on a pointer variable to use it as a byte array at
|
dynamic, location. You can use array indexing on a pointer variable to use it as a byte array at
|
||||||
a dynamic location in memory: currently this is equivalent to directly referencing the bytes in
|
a dynamic location in memory: currently this is equivalent to directly referencing the bytes in
|
||||||
memory at the given index. In contrast to a real array variable, the index value can be the size of a word.
|
memory at the given index. In contrast to a real array variable, the index value can be the size of a word.
|
||||||
|
Unlike array variables, you cannot use a negative index to count from the end, because the size of the array is unknown.
|
||||||
See also :ref:`pointervars_programming`
|
See also :ref:`pointervars_programming`
|
||||||
|
|
||||||
**LSB/MSB split word arrays:**
|
**LSB/MSB split word arrays:**
|
||||||
|
@ -507,10 +507,13 @@ Array indexing
|
|||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Strings and arrays are a sequence of values. You can access the individual values by indexing.
|
Strings and arrays are a sequence of values. You can access the individual values by indexing.
|
||||||
Syntax is familiar with brackets: ``arrayvar[x]`` ::
|
Negative index means counted from the end of the array rather than the beginning, where -1 means
|
||||||
|
the last element in the array, -2 the second-to-last, etc. (Python uses this same scheme)
|
||||||
|
Use brackets to index into an array: ``arrayvar[x]`` ::
|
||||||
|
|
||||||
array[2] ; the third byte in the array (index is 0-based)
|
array[2] ; the third byte in the array (index is 0-based)
|
||||||
string[4] ; the fifth character (=byte) in the string
|
string[4] ; the fifth character (=byte) in the string
|
||||||
|
array[-2] ; the second-to-last element
|
||||||
|
|
||||||
Note: you can also use array indexing on a 'pointer variable', which is basically an uword variable
|
Note: you can also use array indexing on a 'pointer variable', which is basically an uword variable
|
||||||
containing a memory address. Currently this is equivalent to directly referencing the bytes in
|
containing a memory address. Currently this is equivalent to directly referencing the bytes in
|
||||||
|
@ -84,4 +84,3 @@ Other language/syntax features to think about
|
|||||||
challenges: how to not make this too X16 specific? How does the compiler know what bank to switch (ram/rom)?
|
challenges: how to not make this too X16 specific? How does the compiler know what bank to switch (ram/rom)?
|
||||||
How to make it performant when we want to (i.e. NOT have it use callfar/auto bank switching) ?
|
How to make it performant when we want to (i.e. NOT have it use callfar/auto bank switching) ?
|
||||||
- chained comparisons `10<x<20` , `x==y==z` (desugars to `10<x and x<20`, `x==y and y==z`) BUT this changes the semantics of what it is right now ! (x==(y==z) --> x==true)
|
- chained comparisons `10<x<20` , `x==y==z` (desugars to `10<x and x<20`, `x==y and y==z`) BUT this changes the semantics of what it is right now ! (x==(y==z) --> x==true)
|
||||||
- negative array index to refer to an element from the end of the array. Python `[-1]` or Raku syntax `[\*-1]` , `[\*/2]` .... \*=size of the array
|
|
||||||
|
@ -3,16 +3,22 @@
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
uword function = &test
|
ubyte[] barr = [1,2,3,4,5,6,7,8,9]
|
||||||
uword @shared derp = call(function)
|
uword[] warr = [111,222,333,444,555,666,777,888,999]
|
||||||
txt.print_uw(derp)
|
uword pointer = &barr
|
||||||
txt.nl()
|
byte index = 2
|
||||||
void call(function)
|
|
||||||
}
|
|
||||||
|
|
||||||
sub test() -> uword {
|
txt.print_ub(barr[7])
|
||||||
txt.print("test\n")
|
txt.nl()
|
||||||
cx16.r0++
|
txt.print_ub(barr[-2])
|
||||||
return 999
|
txt.nl()
|
||||||
|
txt.print_ub(pointer[7])
|
||||||
|
txt.nl()
|
||||||
|
txt.print_ub(pointer[index])
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(warr[7])
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(warr[-2])
|
||||||
|
txt.nl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user