mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
reverse() added (byte+word)
This commit is contained in:
parent
d837cc11f9
commit
1cc1f2d91d
@ -26,7 +26,7 @@ which aims to provide many conveniences over raw assembly code (even when using
|
|||||||
- abstracting away low level aspects such as ZeroPage handling, program startup, explicit memory addresses
|
- abstracting away low level aspects such as ZeroPage handling, program startup, explicit memory addresses
|
||||||
- various code optimizations (code structure, logical and numerical expressions, unused code removal...)
|
- various code optimizations (code structure, logical and numerical expressions, unused code removal...)
|
||||||
- inline assembly allows you to have full control when every cycle or byte matters
|
- inline assembly allows you to have full control when every cycle or byte matters
|
||||||
- many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``memset``, ``memcopy``
|
- many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``memset``, ``memcopy``, ``sort`` and ``reverse``
|
||||||
|
|
||||||
Rapid edit-compile-run-debug cycle:
|
Rapid edit-compile-run-debug cycle:
|
||||||
|
|
||||||
|
@ -1535,14 +1535,15 @@ _sort_loop ldy c64.SCRATCH_ZPB1 ;start of subroutine sort
|
|||||||
_l1 dey
|
_l1 dey
|
||||||
dey
|
dey
|
||||||
beq _l3
|
beq _l3
|
||||||
|
lda (c64.SCRATCH_ZPWORD1),y
|
||||||
|
cmp c64.SCRATCH_ZPWORD2
|
||||||
iny
|
iny
|
||||||
lda (c64.SCRATCH_ZPWORD1),y
|
lda (c64.SCRATCH_ZPWORD1),y
|
||||||
dey
|
dey
|
||||||
cmp c64.SCRATCH_ZPWORD2+1
|
sbc c64.SCRATCH_ZPWORD2+1
|
||||||
bne +
|
bvc +
|
||||||
lda (c64.SCRATCH_ZPWORD1),y
|
eor #$80
|
||||||
cmp c64.SCRATCH_ZPWORD2
|
+ bmi _l1
|
||||||
+ bmi _l1
|
|
||||||
_l2 sty _work1 ;index of potentially largest value
|
_l2 sty _work1 ;index of potentially largest value
|
||||||
lda (c64.SCRATCH_ZPWORD1),y
|
lda (c64.SCRATCH_ZPWORD1),y
|
||||||
sta c64.SCRATCH_ZPWORD2 ;potentially largest value
|
sta c64.SCRATCH_ZPWORD2 ;potentially largest value
|
||||||
@ -1571,3 +1572,102 @@ _l3 ldy c64.SCRATCH_ZPB1 ;where the largest value shall be put
|
|||||||
_work1 .byte 0
|
_work1 .byte 0
|
||||||
_work3 .word 0
|
_work3 .word 0
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
|
||||||
|
reverse_b .proc
|
||||||
|
; --- reverse an array of bytes (in-place)
|
||||||
|
; inputs: pointer to array in c64.SCRATCH_ZPWORD1, length in A
|
||||||
|
_left_index = c64.SCRATCH_ZPWORD2
|
||||||
|
_right_index = c64.SCRATCH_ZPWORD2+1
|
||||||
|
pha
|
||||||
|
sec
|
||||||
|
sbc #1
|
||||||
|
sta _left_index
|
||||||
|
lda #0
|
||||||
|
sta _right_index
|
||||||
|
pla
|
||||||
|
lsr a
|
||||||
|
tay
|
||||||
|
_loop sty c64.SCRATCH_ZPREG
|
||||||
|
ldy _left_index
|
||||||
|
lda (c64.SCRATCH_ZPWORD1),y
|
||||||
|
pha
|
||||||
|
ldy _right_index
|
||||||
|
lda (c64.SCRATCH_ZPWORD1),y
|
||||||
|
ldy _left_index
|
||||||
|
sta (c64.SCRATCH_ZPWORD1),y
|
||||||
|
pla
|
||||||
|
ldy _right_index
|
||||||
|
sta (c64.SCRATCH_ZPWORD1),y
|
||||||
|
inc _right_index
|
||||||
|
dec _left_index
|
||||||
|
ldy c64.SCRATCH_ZPREG
|
||||||
|
dey
|
||||||
|
bne _loop
|
||||||
|
rts
|
||||||
|
.pend
|
||||||
|
|
||||||
|
|
||||||
|
reverse_w .proc
|
||||||
|
; --- reverse an array of words (in-place)
|
||||||
|
; inputs: pointer to array in c64.SCRATCH_ZPWORD1, length in A
|
||||||
|
_left_index = c64.SCRATCH_ZPWORD2
|
||||||
|
_right_index = c64.SCRATCH_ZPWORD2+1
|
||||||
|
pha
|
||||||
|
asl a ; *2 because words
|
||||||
|
sec
|
||||||
|
sbc #2
|
||||||
|
sta _left_index
|
||||||
|
lda #0
|
||||||
|
sta _right_index
|
||||||
|
pla
|
||||||
|
lsr a
|
||||||
|
pha
|
||||||
|
tay
|
||||||
|
; first reverse the lsbs
|
||||||
|
_loop_lo sty c64.SCRATCH_ZPREG
|
||||||
|
ldy _left_index
|
||||||
|
lda (c64.SCRATCH_ZPWORD1),y
|
||||||
|
pha
|
||||||
|
ldy _right_index
|
||||||
|
lda (c64.SCRATCH_ZPWORD1),y
|
||||||
|
ldy _left_index
|
||||||
|
sta (c64.SCRATCH_ZPWORD1),y
|
||||||
|
pla
|
||||||
|
ldy _right_index
|
||||||
|
sta (c64.SCRATCH_ZPWORD1),y
|
||||||
|
inc _right_index
|
||||||
|
inc _right_index
|
||||||
|
dec _left_index
|
||||||
|
dec _left_index
|
||||||
|
ldy c64.SCRATCH_ZPREG
|
||||||
|
dey
|
||||||
|
bne _loop_lo
|
||||||
|
; now reverse the msbs
|
||||||
|
dec _right_index
|
||||||
|
inc _left_index
|
||||||
|
inc _left_index
|
||||||
|
inc _left_index
|
||||||
|
pla
|
||||||
|
tay
|
||||||
|
_loop_hi sty c64.SCRATCH_ZPREG
|
||||||
|
ldy _left_index
|
||||||
|
lda (c64.SCRATCH_ZPWORD1),y
|
||||||
|
pha
|
||||||
|
ldy _right_index
|
||||||
|
lda (c64.SCRATCH_ZPWORD1),y
|
||||||
|
ldy _left_index
|
||||||
|
sta (c64.SCRATCH_ZPWORD1),y
|
||||||
|
pla
|
||||||
|
ldy _right_index
|
||||||
|
sta (c64.SCRATCH_ZPWORD1),y
|
||||||
|
dec _right_index
|
||||||
|
dec _right_index
|
||||||
|
inc _left_index
|
||||||
|
inc _left_index
|
||||||
|
ldy c64.SCRATCH_ZPREG
|
||||||
|
dey
|
||||||
|
bne _loop_hi
|
||||||
|
|
||||||
|
rts
|
||||||
|
.pend
|
||||||
|
@ -832,7 +832,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
printWarning("result values of subroutine call are discarded", functionCallStatement.position)
|
printWarning("result values of subroutine call are discarded", functionCallStatement.position)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(functionCallStatement.target.nameInSource.last() in setOf("lsl", "lsr", "rol", "ror", "rol2", "ror2", "swap", "sort")) {
|
if(functionCallStatement.target.nameInSource.last() in setOf("lsl", "lsr", "rol", "ror", "rol2", "ror2", "swap", "sort", "reverse")) {
|
||||||
// in-place modification, can't be done on literals
|
// in-place modification, can't be done on literals
|
||||||
if(functionCallStatement.arglist.any { it !is IdentifierReference && it !is RegisterExpr && it !is ArrayIndexedExpression && it !is DirectMemoryRead }) {
|
if(functionCallStatement.arglist.any { it !is IdentifierReference && it !is RegisterExpr && it !is ArrayIndexedExpression && it !is DirectMemoryRead }) {
|
||||||
checkResult.add(ExpressionError("can't use that as argument to a in-place modifying function", functionCallStatement.position))
|
checkResult.add(ExpressionError("can't use that as argument to a in-place modifying function", functionCallStatement.position))
|
||||||
|
@ -336,6 +336,38 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
else
|
else
|
||||||
throw AssemblyError("weird type")
|
throw AssemblyError("weird type")
|
||||||
}
|
}
|
||||||
|
"reverse" -> {
|
||||||
|
val variable = fcall.arglist.single()
|
||||||
|
if (variable is IdentifierReference) {
|
||||||
|
val decl = variable.targetVarDecl(program.namespace)!!
|
||||||
|
val varName = asmgen.asmIdentifierName(variable)
|
||||||
|
val numElements = decl.arraysize!!.size()
|
||||||
|
when (decl.datatype) {
|
||||||
|
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
||||||
|
asmgen.out("""
|
||||||
|
lda #<$varName
|
||||||
|
ldy #>$varName
|
||||||
|
sta ${C64Zeropage.SCRATCH_W1}
|
||||||
|
sty ${C64Zeropage.SCRATCH_W1 + 1}
|
||||||
|
lda #$numElements
|
||||||
|
jsr prog8_lib.reverse_b
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||||
|
asmgen.out("""
|
||||||
|
lda #<$varName
|
||||||
|
ldy #>$varName
|
||||||
|
sta ${C64Zeropage.SCRATCH_W1}
|
||||||
|
sty ${C64Zeropage.SCRATCH_W1 + 1}
|
||||||
|
lda #$numElements
|
||||||
|
jsr prog8_lib.reverse_w
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
DataType.ARRAY_F -> TODO("reverse floats (consider another solution if possible - this will be quite slow, if ever implemented)")
|
||||||
|
else -> throw AssemblyError("weird type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
translateFunctionArguments(fcall.arglist, func)
|
translateFunctionArguments(fcall.arglist, func)
|
||||||
asmgen.out(" jsr prog8_lib.func_$functionName")
|
asmgen.out(" jsr prog8_lib.func_$functionName")
|
||||||
|
@ -28,6 +28,7 @@ val BuiltinFunctions = mapOf(
|
|||||||
"lsl" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), null),
|
"lsl" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), null),
|
||||||
"lsr" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), null),
|
"lsr" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), null),
|
||||||
"sort" to FunctionSignature(false, listOf(BuiltinFunctionParam("array", ArrayDatatypes)), null),
|
"sort" to FunctionSignature(false, listOf(BuiltinFunctionParam("array", ArrayDatatypes)), null),
|
||||||
|
"reverse" to FunctionSignature(false, listOf(BuiltinFunctionParam("array", ArrayDatatypes)), null),
|
||||||
// these few have a return value depending on the argument(s):
|
// these few have a return value depending on the argument(s):
|
||||||
"max" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMax) }, // type depends on args
|
"max" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMax) }, // type depends on args
|
||||||
"min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMin) }, // type depends on args
|
"min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMin) }, // type depends on args
|
||||||
|
@ -158,7 +158,7 @@ Design principles and features
|
|||||||
- The compiler tries to optimize the program and generated code, but hand-tuning of the
|
- The compiler tries to optimize the program and generated code, but hand-tuning of the
|
||||||
performance or space-critical parts will likely still be required. This is supported by
|
performance or space-critical parts will likely still be required. This is supported by
|
||||||
the ability to easily write embedded assembly code directly in the program source code.
|
the ability to easily write embedded assembly code directly in the program source code.
|
||||||
- There are many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``memset``, ``memcopy``
|
- There are many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``memset``, ``memcopy``, ``sort`` and ``reverse``
|
||||||
|
|
||||||
|
|
||||||
.. _requirements:
|
.. _requirements:
|
||||||
|
@ -663,52 +663,58 @@ cos16u(x)
|
|||||||
Fast 16-bit uword cosine of angle 0..255, result is in range 0..65535
|
Fast 16-bit uword cosine of angle 0..255, result is in range 0..65535
|
||||||
|
|
||||||
cos16(x)
|
cos16(x)
|
||||||
Fast 16-bit word cosine of angle 0..255, result is in range -32767..32767
|
Fast 16-bit word cosine of angle 0..255, result is in range -32767..32767
|
||||||
|
|
||||||
abs(x)
|
abs(x)
|
||||||
Absolute value.
|
Absolute value.
|
||||||
|
|
||||||
tan(x)
|
tan(x)
|
||||||
Tangent.
|
Tangent.
|
||||||
|
|
||||||
atan(x)
|
atan(x)
|
||||||
Arctangent.
|
Arctangent.
|
||||||
|
|
||||||
ln(x)
|
ln(x)
|
||||||
Natural logarithm (base e).
|
Natural logarithm (base e).
|
||||||
|
|
||||||
log2(x)
|
log2(x)
|
||||||
Base 2 logarithm.
|
Base 2 logarithm.
|
||||||
|
|
||||||
sqrt16(w)
|
sqrt16(w)
|
||||||
16 bit unsigned integer Square root. Result is unsigned byte.
|
16 bit unsigned integer Square root. Result is unsigned byte.
|
||||||
|
|
||||||
sqrt(x)
|
sqrt(x)
|
||||||
Floating point Square root.
|
Floating point Square root.
|
||||||
|
|
||||||
round(x)
|
round(x)
|
||||||
Rounds the floating point to the closest integer.
|
Rounds the floating point to the closest integer.
|
||||||
|
|
||||||
floor (x)
|
floor (x)
|
||||||
Rounds the floating point down to an integer towards minus infinity.
|
Rounds the floating point down to an integer towards minus infinity.
|
||||||
|
|
||||||
ceil(x)
|
ceil(x)
|
||||||
Rounds the floating point up to an integer towards positive infinity.
|
Rounds the floating point up to an integer towards positive infinity.
|
||||||
|
|
||||||
rad(x)
|
rad(x)
|
||||||
Degrees to radians.
|
Degrees to radians.
|
||||||
|
|
||||||
deg(x)
|
deg(x)
|
||||||
Radians to degrees.
|
Radians to degrees.
|
||||||
|
|
||||||
max(x)
|
max(x)
|
||||||
Maximum of the values in the array value x
|
Maximum of the values in the array value x
|
||||||
|
|
||||||
min(x)
|
min(x)
|
||||||
Minimum of the values in the array value x
|
Minimum of the values in the array value x
|
||||||
|
|
||||||
sum(x)
|
sum(x)
|
||||||
Sum of the values in the array value x
|
Sum of the values in the array value x
|
||||||
|
|
||||||
|
sort(array)
|
||||||
|
Sort the array in ascending order (in-place)
|
||||||
|
|
||||||
|
reverse(array)
|
||||||
|
Reverse the values in the array (in-place). Can be used after sort() to sort an array in descending order.
|
||||||
|
|
||||||
len(x)
|
len(x)
|
||||||
Number of values in the array value x, or the number of characters in a string (excluding the size or 0-byte).
|
Number of values in the array value x, or the number of characters in a string (excluding the size or 0-byte).
|
||||||
|
@ -135,18 +135,16 @@ main {
|
|||||||
|
|
||||||
; first sort vertices to sprite order so the back/front order is correct as well
|
; first sort vertices to sprite order so the back/front order is correct as well
|
||||||
; (simple bubble sort as it's only 8 items to sort)
|
; (simple bubble sort as it's only 8 items to sort)
|
||||||
; TODO make a builtin function sort()
|
for ubyte sorti in 6 to 0 step -1 {
|
||||||
sort(rotatedz)
|
for ubyte i1 in 0 to sorti {
|
||||||
; for ubyte sorti in 6 to 0 step -1 {
|
ubyte i2 = i1+1
|
||||||
; for ubyte i1 in 0 to sorti {
|
if(rotatedz[i1] > rotatedz[i2]) {
|
||||||
; ubyte i2 = i1+1
|
swap(rotatedx[i1], rotatedx[i2])
|
||||||
; if(rotatedz[i1] > rotatedz[i2]) {
|
swap(rotatedy[i1], rotatedy[i2])
|
||||||
; swap(rotatedx[i1], rotatedx[i2])
|
swap(rotatedz[i1], rotatedz[i2])
|
||||||
; swap(rotatedy[i1], rotatedy[i2])
|
}
|
||||||
; swap(rotatedz[i1], rotatedz[i2])
|
}
|
||||||
; }
|
}
|
||||||
; }
|
|
||||||
; }
|
|
||||||
|
|
||||||
ubyte[] spritecolors = [1,1,7,15,12,11,9,9]
|
ubyte[] spritecolors = [1,1,7,15,12,11,9,9]
|
||||||
|
|
||||||
|
62
examples/sorting.p8
Normal file
62
examples/sorting.p8
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
%import c64lib
|
||||||
|
%import c64utils
|
||||||
|
%zeropage basicsafe
|
||||||
|
|
||||||
|
main {
|
||||||
|
|
||||||
|
sub start() {
|
||||||
|
|
||||||
|
ubyte[] uba = [10,0,2,8,5,4,3,9]
|
||||||
|
uword[] uwa = [1000,0,200,8000,50,40000,3,900]
|
||||||
|
byte[] ba = [-10,0,-2,8,5,4,-3,9,-99]
|
||||||
|
word[] wa = [-1000,0,-200,8000,50,31111,3,-900]
|
||||||
|
|
||||||
|
c64scr.print("original\n")
|
||||||
|
print_arrays()
|
||||||
|
|
||||||
|
sort(uba)
|
||||||
|
sort(uwa)
|
||||||
|
sort(ba)
|
||||||
|
sort(wa)
|
||||||
|
|
||||||
|
c64scr.print("sorted\n")
|
||||||
|
print_arrays()
|
||||||
|
|
||||||
|
reverse(uba)
|
||||||
|
reverse(uwa)
|
||||||
|
reverse(ba)
|
||||||
|
reverse(wa)
|
||||||
|
|
||||||
|
c64scr.print("reversed\n")
|
||||||
|
print_arrays()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
sub print_arrays() {
|
||||||
|
for ubyte ub in uba {
|
||||||
|
c64scr.print_ub(ub)
|
||||||
|
c64.CHROUT(',')
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
for uword uw in uwa {
|
||||||
|
c64scr.print_uw(uw)
|
||||||
|
c64.CHROUT(',')
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
for byte bb in ba {
|
||||||
|
c64scr.print_b(bb)
|
||||||
|
c64.CHROUT(',')
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
for word ww in wa {
|
||||||
|
c64scr.print_w(ww)
|
||||||
|
c64.CHROUT(',')
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
%import c64lib
|
%import c64lib
|
||||||
%import c64utils
|
%import c64utils
|
||||||
%import c64flt
|
%zeropage basicsafe
|
||||||
%zeropage dontuse
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
@ -9,9 +8,8 @@ main {
|
|||||||
|
|
||||||
ubyte[] uba = [10,0,2,8,5,4,3,9]
|
ubyte[] uba = [10,0,2,8,5,4,3,9]
|
||||||
uword[] uwa = [1000,0,200,8000,50,40000,3,900]
|
uword[] uwa = [1000,0,200,8000,50,40000,3,900]
|
||||||
byte[] ba = [-10,0,-2,8,5,4,-3,9]
|
byte[] ba = [-10,0,-2,8,5,4,-3,9,-99]
|
||||||
word[] wa = [-1000,0,-200,8000,50,31111,3,-900]
|
word[] wa = [-1000,0,-200,8000,50,31111,3,-900]
|
||||||
float[] fla = [-2.2, 1.1, 3.3, 0.0]
|
|
||||||
|
|
||||||
for ubyte ub in uba {
|
for ubyte ub in uba {
|
||||||
c64scr.print_ub(ub)
|
c64scr.print_ub(ub)
|
||||||
@ -66,11 +64,41 @@ main {
|
|||||||
c64.CHROUT(',')
|
c64.CHROUT(',')
|
||||||
}
|
}
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
reverse(uba)
|
||||||
|
reverse(uwa)
|
||||||
|
reverse(ba)
|
||||||
|
reverse(wa)
|
||||||
|
|
||||||
|
for ubyte ub3 in uba {
|
||||||
|
c64scr.print_ub(ub3)
|
||||||
|
c64.CHROUT(',')
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
for uword uw3 in uwa {
|
||||||
|
c64scr.print_uw(uw3)
|
||||||
|
c64.CHROUT(',')
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
for byte bb3 in ba {
|
||||||
|
c64scr.print_b(bb3)
|
||||||
|
c64.CHROUT(',')
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
for word ww3 in wa {
|
||||||
|
c64scr.print_w(ww3)
|
||||||
|
c64.CHROUT(',')
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
ubyte qq=X
|
|
||||||
c64scr.print_ub(qq)
|
|
||||||
|
|
||||||
; TODO 2 for loops that both define the same loopvar -> double definition -> fix second for -> 'unknown symbol' ????
|
; TODO 2 for loops that both define the same loopvar -> double definition -> fix second for -> 'unknown symbol' ????
|
||||||
|
; TODO code runs into a subroutine that follows it instead of inserting an implicit return
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user