PageRenderTime 7ms CodeModel.GetById 1ms app.highlight 2ms RepoModel.GetById 2ms app.codeStats 0ms

/source/core/ast/FuncDecl.ooc

http://github.com/nddrylliog/oc
Unknown | 152 lines | 124 code | 28 blank | 0 comment | 0 complexity | 95cfe8c6dc32b1e0fca3f6e772658488 MD5 | raw file
  1
  2import structs/[ArrayList, HashMap]
  3
  4import Expression, Statement, Scope, Var, Type, Access, Return, Call
  5import middle/Resolver
  6
  7FuncDecl: class extends Expression {
  8
  9    global := false
 10
 11    resolved := false
 12    body := Scope new()
 13    args := HashMap<String, Var> new()
 14    
 15    retType := VoidType new()
 16    _type: FuncType
 17    
 18    externName: String { get set }
 19    name: String { get set }
 20    
 21    // for closures
 22    accesses: ArrayList<Access>
 23
 24    init: func ~fDecl {
 25        name = ""
 26        externName = null
 27        _type = FuncType new(this)
 28    }
 29    
 30    anon?: func -> Bool {
 31        name empty?()
 32    }
 33    
 34    markAccess: func (acc: Access) {
 35        if(!accesses) {
 36            accesses = ArrayList<Access> new()
 37        } else {
 38            for(acc2 in accesses) {
 39                if(acc name == acc2 name) return
 40            }
 41        }
 42        "%s is accessing %s" printfln(toString(), acc toString())
 43        accesses add(acc)
 44    }
 45
 46    resolve: func (task: Task) {
 47        task queueList(args)
 48        task queue(retType)
 49        resolved = true // artificial testing
 50        
 51        task queue(body)
 52
 53        match (task parent node) {
 54            case c: Call =>
 55                "Parent of %s is call %s" printfln(toString(), c toString())
 56		while(c subject ref == null) {
 57		    "ref = %s" printfln(c subject ref ? c subject ref toString() : "(nil)")
 58		    "C subject's ref is null, yielding" println()
 59		    task parent queue(c subject)
 60		    "Back here!" println()
 61		}
 62		inferType(c)
 63        }
 64
 65        autoReturn(task)
 66    }
 67    
 68    inferType: func (outerCall: Call) {
 69	"outerCall = %s" printfln(outerCall toString())
 70
 71	// idx is our position in the call arguments, or -1 if we're not an argument of outerCall
 72	idx := outerCall args indexOf(this)
 73	if(idx == -1) {
 74	    "Decl %s is a child of task for call %s but it's not in its arguments!" printfln(toString(), outerCall toString())
 75	    return
 76	}
 77	"idx = %d" printfln(idx)
 78
 79	// callRef is the Var that our outer call's subject has been resolved to
 80	callRef := outerCall subject ref
 81	if(!callRef getType() instanceOf?(FuncType)) {
 82	    Exception new("Should never happen: outer call %s was resolved to something that's not a function! (ie. %s)" \
 83		format(outerCall toString(), callRef getType() toString())) throw()
 84	}
 85	"callRef = %s" printfln(callRef toString())
 86
 87	// callProto is the FuncDecl which defines the argument types of the reference of the outer call
 88	callProto := callRef getType() as FuncType proto
 89	"callProto = %s" printfln(callRef toString())
 90
 91	// outerType is the type that the outer call expects us to be. Our actual type is getType()
 92	outerType := callProto args get(callProto args getKeys() get(idx)) getType()
 93	if(!outerType instanceOf?(FuncType)) {
 94	    Exception new("Passing a function (ie. %s) to a %s where expecting a %s (%s)" format(toString(), callProto toString(), outerType toString(), outerType class name)) throw()
 95	}
 96	"outerType = %s" printfln(outerType toString())
 97
 98	outerProto := outerType as FuncType proto
 99	"outerProto = %s" printfln(outerProto toString())
100
101	if(outerProto args size != args size) {
102	    Exception new("Function %s is not compatible with type %s" format(toString(), outerProto toString())) throw()
103	}
104
105	"Inferring return type of %s to be %s" printfln(toString(), outerProto retType toString())
106	retType = outerProto retType
107    }
108    
109    autoReturn: func (task: Task) {
110        if(!retType void?()) {
111            list := body body
112            if(list empty?()) {
113                "Expected return expression in non-void function %s" printfln(name)
114                exit(1)
115            } else {
116                last := list last()
117                if(last class == Return) {
118                    // all good
119                } else if(last instanceOf?(Expression)) {
120                    list set(list size - 1, Return new(last as Expression))
121                } else {
122                    "Expected return expression in non-void function %s" printfln(name)
123                    exit(1)
124                }
125            }
126        }
127    }
128    
129    resolveAccess: func (acc: Access, task: Task, suggest: Func (Var)) {
130        v := args get(acc name)
131        if(v) suggest(v)
132    }
133
134    toString: func -> String {
135        b := Buffer new()
136        b append("func (")
137        first := true
138        for(arg in args) {
139            if(first) first = false
140            else      b append(", ")
141            b append(arg toString())
142        }
143        b append(") -> ")
144        b append(retType toString())
145        b toString()
146    }
147
148    getType: func -> Type {
149        _type
150    }
151
152}