mirror of
https://github.com/irmen/prog8.git
synced 2026-10-22 05:02:58 +00:00
Require explicit via for linked-list for loops
This commit is contained in:
1 parent
6076b01f6d
commit
63e2a45f09
4 files changed
+84
-44
No files matched your search
@@ -14,16 +14,18 @@ import prog8.code.core.Position
|
||||
|
||||
internal fun checkLinkedForLoop(
|
||||
forLoop: ForLoop,
|
||||
nodeType: DataType,
|
||||
nodeTypeIn: DataType,
|
||||
program: Program,
|
||||
errors: IErrorReporter
|
||||
): Boolean {
|
||||
val nodeType = resolveDt(nodeTypeIn, forLoop.definingScope, program)
|
||||
if (!nodeType.isPointer) {
|
||||
errors.err("linked-list for loop requires a pointer loop variable", forLoop.position)
|
||||
return false
|
||||
}
|
||||
|
||||
val iterableType = forLoop.iterable.inferType(program).getOrUndef()
|
||||
val iterableTypeRaw = forLoop.iterable.inferType(program).getOrUndef()
|
||||
val iterableType = resolveDt(iterableTypeRaw, forLoop.definingScope, program)
|
||||
if (!iterableType.isPointer) {
|
||||
errors.err("linked-list for loop start must be a pointer", forLoop.position)
|
||||
return false
|
||||
@@ -98,3 +100,40 @@ internal fun resolveDeferredType(
|
||||
}
|
||||
|
||||
|
||||
private fun resolveDt(dt: DataType, scope: INameScope, program: Program): DataType {
|
||||
val antlrName = dt.subTypeFromAntlr ?: return dt
|
||||
// Try the scope first, then search all modules/blocks for a struct with that name.
|
||||
var resolved = scope.lookup(antlrName) as? ISubType
|
||||
if (resolved == null && antlrName.size == 1) {
|
||||
for (module in program.modules) {
|
||||
val block = findStructInScope(module, antlrName[0])
|
||||
if (block != null) {
|
||||
resolved = block
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return if (resolved != null) {
|
||||
when {
|
||||
dt.isPointer -> DataType.pointer(resolved)
|
||||
dt.isStructInstance -> DataType.structInstance(resolved)
|
||||
else -> dt
|
||||
}
|
||||
} else {
|
||||
dt
|
||||
}
|
||||
}
|
||||
|
||||
private fun findStructInScope(scope: INameScope, name: String): ISubType? {
|
||||
val direct = scope.lookup(name) as? ISubType
|
||||
if (direct != null) return direct
|
||||
for (stmt in scope.statements) {
|
||||
if (stmt is INameScope) {
|
||||
val found = findStructInScope(stmt, name)
|
||||
if (found != null) return found
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -296,7 +296,7 @@ class TestCompilerOnExamplesBothC64andCx16: FunSpec({
|
||||
ExampleSizes("pointers/animalgame", c64SizeOptimized=1965, c64SizeUnoptimized=2521, cx16SizeOptimized=1991, cx16SizeUnoptimized=2801),
|
||||
ExampleSizes("pointers/binarytree", c64SizeOptimized=2672, c64SizeUnoptimized=2735, cx16SizeOptimized=2175, cx16SizeUnoptimized=2487),
|
||||
ExampleSizes("pointers/hashtable", c64SizeOptimized=3388, c64SizeUnoptimized=4207, cx16SizeOptimized=2911, cx16SizeUnoptimized=3782),
|
||||
ExampleSizes("pointers/sortedlist", c64SizeOptimized=1361, c64SizeUnoptimized=3149, cx16SizeOptimized=1291, cx16SizeUnoptimized=3358),
|
||||
ExampleSizes("pointers/sortedlist", c64SizeOptimized=1353, c64SizeUnoptimized=3137, cx16SizeOptimized=1291, cx16SizeUnoptimized=3358),
|
||||
ExampleSizes("pointers/sorting", c64SizeOptimized=1776, c64SizeUnoptimized=2523, cx16SizeOptimized=1788, cx16SizeUnoptimized=2653),
|
||||
),
|
||||
listOf(false, true),
|
||||
|
||||
+41
-39
@@ -1193,45 +1193,6 @@ to the header::
|
||||
}
|
||||
}
|
||||
|
||||
.. _linked-list-iteration:
|
||||
|
||||
Linked-list iteration
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Prog8 can desugar linked-list ``for`` loops into ordinary ``while`` loops.
|
||||
The explicit form works for arbitrary node layouts and link field names::
|
||||
|
||||
main {
|
||||
^^MyList mylist = [] ; zero-initialized header
|
||||
^^MyNode n1 = [0, 0, 42]
|
||||
^^MyNode n2 = [0, 0, 99]
|
||||
lists.init(mylist)
|
||||
lists.add_tail(mylist, n1)
|
||||
lists.add_tail(mylist, n2)
|
||||
|
||||
; forward iteration over an Exec/MinList
|
||||
for node in mylist.Head via .Succ until &mylist.Tail {
|
||||
txt.print_ub(node.value)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
; backward iteration
|
||||
for node in mylist.TailPred via .Pred until &mylist.Head {
|
||||
txt.print_ub(node.value)
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
||||
For simple null-terminated lists, ``until`` may be omitted and defaults to ``0``::
|
||||
|
||||
for node in head via .next {
|
||||
; use node
|
||||
}
|
||||
|
||||
Exec-compatible lists use uppercase field names (``Succ``, ``Pred``, ``Head``,
|
||||
``Tail``), so use the explicit ``via`` form for them. Linked-list iteration always
|
||||
requires this explicit field selection, regardless of the target or field names.
|
||||
|
||||
User-defined node structs work the same way as long as the link pointers are the first fields at
|
||||
offset 0; add ``Type``/``Pri``/``Name`` after them if you need ``enqueue`` or
|
||||
``find_name`` (the ``exec.Node``/``FullNode`` layout).
|
||||
@@ -1245,6 +1206,47 @@ suitably aligned (even address on 6502, long-aligned on m68k).
|
||||
Read the :source:`lists source code <compiler/res/prog8lib/lists.p8>` and
|
||||
:source:`amiga lists source code <compiler/res/prog8lib/shared_amiga_lists.p8>` for details.
|
||||
|
||||
|
||||
.. _linked-list-iteration:
|
||||
|
||||
Linked-list iteration
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Prog8 has some convenience syntax to iterate through a linked-list via a ``for`` loop.
|
||||
The for loop's ``via .field`` clause selects which pointer field in the node struct to follow
|
||||
from one node to the next (usually called 'next' or 'succ'). The ``until`` clause
|
||||
gives the sentinel value where iteration stops (when 0, it can be omitted)::
|
||||
|
||||
; iteration over an Amiga Exec list.
|
||||
|
||||
main {
|
||||
^^MyList mylist = []
|
||||
^^MyNode n1 = [0, 0, 42]
|
||||
^^MyNode n2 = [0, 0, 99]
|
||||
lists.init(mylist)
|
||||
lists.add_tail(mylist, n1)
|
||||
lists.add_tail(mylist, n2)
|
||||
|
||||
; forward iteration
|
||||
for node in mylist.Head via .Succ until &mylist.Tail {
|
||||
txt.print_ub(node.value)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
; backward iteration
|
||||
for node in mylist.TailPred via .Pred until &mylist.Head {
|
||||
txt.print_ub(node.value)
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
||||
For simple null-terminated lists, ``until`` may be omitted and then the stop value defaults to ``0``::
|
||||
|
||||
for node in head via .next {
|
||||
; use node
|
||||
}
|
||||
|
||||
|
||||
math
|
||||
^^^^
|
||||
.. index:: pair: Libraries; math
|
||||
|
||||
@@ -31,8 +31,7 @@ main {
|
||||
|
||||
sub printlist() {
|
||||
ubyte count = 0
|
||||
^^slist.Node head = slist.head
|
||||
for ^^slist.Node n in head via .next {
|
||||
for ^^slist.Node n in slist.head via .next {
|
||||
txt.print_uw(n.size)
|
||||
txt.chrout(':')
|
||||
txt.chrout(n.letter)
|
||||
|
||||
Reference in new issue
Block a user