/source/core/middle/Resolver.ooc
Unknown | 215 lines | 172 code | 43 blank | 0 comment | 0 complexity | 264a07dfe01e5f98ed055ca0d82ac6b6 MD5 | raw file
1 2import os/Coro, structs/[ArrayList, List, Stack, HashBag] 3 4import ast/[Node, Module] 5import ../backend/Backend 6import ../frontend/BuildParams 7 8Task: class { 9 resolver: Resolver 10 11 id: Int { get set } 12 idSeed := static 0 13 14 parent: Task 15 parentCoro, coro: Coro 16 17 oldStackBase: Pointer 18 19 node: Node { get set } 20 done?: Bool { get set } 21 22 userdata: HashBag 23 24 lastFree := static Stack<This> new() 25 26 init: func ~real (=parent, .node, dummy: Bool) { 27 init(parent resolver, parent coro, node) 28 } 29 30 init: func ~onlyCoro (=resolver, =parentCoro, =node) { 31 idSeed += 1 32 id = idSeed 33 coro = Coro new() 34 done? = false 35 version(OOC_TASK_DEBUG) { "Creating new task %s" printfln(toString()) } 36 } 37 38 new: static func (.parent, .node) -> This { 39 if(lastFree empty?()) { 40 new~real(parent, node, false) 41 } else { 42 res := lastFree pop() 43 version(OOC_TASK_DEBUG) { ("Re-using last free task " + res toString()) println() } 44 res parent = parent 45 res node = node 46 res done? = false 47 res 48 } 49 } 50 51 /** 52 * Set userdata to this task 53 */ 54 set: func <T> (key: String, value: T) { 55 if(!userdata) userdata = HashBag new() 56 userdata put(key, value) 57 } 58 59 unset: func (key: String) { 60 if(!userdata) return 61 userdata remove(key) 62 } 63 64 has: func (key: String) -> Bool { 65 if(!userdata) return false 66 userdata contains?(key) 67 } 68 69 get: func <T> (key: String, T: Class) -> T { 70 if(userdata) { 71 return userdata get(key, T) 72 } else null 73 } 74 75 start: func { 76 version(OOC_TASK_DEBUG) { (toString() + " started") println() } 77 78 // Adjust the stackbottom and add our Coro's stack as a root for the GC 79 parentCoro startCoro(coro, || 80 // This allows us to reuse tasks 81 while(this node != null) { 82 version(OOC_TASK_DEBUG) { (toString() + " launching resolve of " + toString()) println() } 83 this node resolve(this) 84 version(OOC_TASK_DEBUG) { (toString() + " finished, yielding " + toString()) println() } 85 this done? = true 86 this node = null 87 This lastFree push(this) 88 yield() 89 } 90 ) 91 } 92 93 yield: func { 94 version(OOC_TASK_DEBUG) { (toString() + " yield") println() } 95 coro switchTo(parentCoro) 96 } 97 98 queue: func (n: Node) { 99 task := Task new(this, n) 100 version(OOC_TASK_DEBUG) { (toString() + " queuing " + n toString() + " with " + task toString()) println() } 101 task start() 102 while(!task done?) { 103 version(OOC_TASK_DEBUG) { (task toString() + " not done yet, looping") println() } 104 switchTo(task) 105 yield() 106 } 107 } 108 109 queueList: func (l: Iterable<Node>) { 110 pool := ArrayList<Node> new() 111 l each(|n, i| spawn(n, i, pool)) 112 exhaust(pool) 113 } 114 115 queueAll: func (f: Func (Func (Node, Int))) { 116 pool := ArrayList<Node> new() 117 f(|n, i| spawn(n, i, pool)) 118 exhaust(pool) 119 } 120 121 spawn: func (n: Node, index: Int, pool: List<Task>) { 122 version(OOC_TASK_DEBUG) { (toString() + " spawning for " + n toString()) } 123 task := Task new(this, n) 124 task set("index", index) 125 task start() 126 if(!task done?) pool add(task) 127 } 128 129 exhaust: func (pool: List<Task>) { 130 version(OOC_TASK_DEBUG) { (toString() + " exhausting pool ") println() } 131 while(!pool empty?()) { 132 oldPool := pool 133 pool = ArrayList<Task> new() 134 135 oldPool each(|task| 136 version(OOC_TASK_DEBUG) { (toString() + " switching to unfinished task " + task toString()) println() } 137 switchTo(task) 138 if(!task done?) pool add(task) 139 ) 140 141 if(!pool empty?()) yield() 142 } 143 } 144 145 need: func (f: Func -> Bool) { 146 while(!f()) { 147 yield() 148 } 149 } 150 151 switchTo: func (task: Task) { 152 coro switchTo(task coro) 153 } 154 155 toString: func -> String { 156 "[#%d %s]" format(id, node ? node toString() : "<no node>") 157 } 158 159 walkBackward: func (f: Func (Node) -> Bool) { 160 if(f(node)) return // true = break 161 if(parent) 162 parent walkBackward(f) 163 } 164 165 walkBackwardTasks: func ~withTask (f: Func (Task) -> Bool) { 166 if(f(this)) return // true = break 167 if(parent) 168 parent walkBackwardTasks(f) 169 } 170} 171 172ModuleTask: class extends Node { 173 module: Module 174 175 init: func (=module) {} 176 177 resolve: func (task: Task) { 178 task queue(module) 179 "Finished resolving %s!" printfln(module fullName) 180 task resolver params backend process(module, task resolver params) 181 } 182} 183 184Resolver: class extends Node { 185 186 modules: ArrayList<Module> { get set } 187 params: BuildParams 188 189 init: func (=params, mainModule: Module) { 190 modules = ArrayList<Module> new() 191 modules addAll(mainModule getDeps()) 192 } 193 194 start: func { 195 "Resolver started, with %d module(s)!" printfln(modules size) 196 197 mainCoro := Coro new() 198 mainCoro initializeMainCoro() 199 200 mainTask := Task new(this, mainCoro, this) 201 mainTask start() 202 while(!mainTask done?) { 203 "" println() 204 "========================== Looping! ===============" println() 205 "" println() 206 207 mainCoro switchTo(mainTask coro) 208 } 209 } 210 211 resolve: func (task: Task) { 212 task queueList(modules map(|m| ModuleTask new(m))) 213 } 214 215}