1// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers 2// 3// SPDX-License-Identifier: MPL-2.0 4 5struct Evaluator { 6 let globals: [Name: Term.TypedTerm] 7 let locals: [Value] 8 9 init(globals: [Name : Term.TypedTerm], locals: [Value]) { 10 self.globals = globals 11 self.locals = locals 12 } 13 14 init() { 15 self.init(globals: [:], locals: []) 16 } 17 18 func extendedBy(value: Value) -> Self { 19 Self(globals: globals, locals: CollectionOfOne(value) + locals) 20 } 21 22 func close<Body>(body: Body) -> Closure<Body> { 23 Closure(evaluator: self, body: body) 24 } 25 26 func close(fieldSpec: Term.FieldSpec) -> Value.FieldSpec { 27 Value.FieldSpec( 28 type: close(body: fieldSpec.type), 29 manifest: fieldSpec.manifest.map(close(body:)) 30 ) 31 } 32 33 func close(fieldImpl: Term.FieldImpl) -> Value.FieldImpl { 34 Value.FieldImpl( 35 type: close(body: fieldImpl.type), 36 value: close(body: fieldImpl.value) 37 ) 38 } 39 40 func evaluate(frame: Term.Frame) -> Value.Frame { 41 switch frame { 42 case let .app(arg: arg): .app(arg: evaluate(term: arg)) 43 case let .proj(fieldName: fieldName): .proj(fieldName: fieldName) 44 } 45 } 46 47 func evaluate(term: Term) -> Value { 48 switch term { 49 case let .local(index: index): 50 return locals[index] 51 case let .global(name: name): 52 let neutral = Value.Neutral( 53 head: .global(name: name), 54 spine: [], 55 boundary: AsyncThunk { 56 let typedTerm = globals[name]! 57 return Value.Boundary( 58 type: evaluate(type: typedTerm.type), 59 value: evaluate(term: typedTerm.term) 60 ) 61 } 62 ) 63 return .shift(neutral: neutral) 64 case let .cut(term: term, frame: frame): 65 return evaluate(term: term) 66 .plug(frame: evaluate(frame: frame)) 67 case let .fun(dom: dom, boundName: boundName, body: body): 68 return .fun( 69 dom: AsyncThunk { await evaluate(type: dom.value()) }, 70 boundName: boundName, 71 closure: close(body: body) 72 ) 73 case let .record(boundName: boundName, fields: fields): 74 return .record( 75 boundName: boundName, 76 fields: fields.map(close(fieldImpl:)) 77 ) 78 } 79 } 80 81 func evaluate(type: Term.Type_) -> Value.Type_ { 82 switch type { 83 case let .funType(dom: dom, boundName: boundName, fam: fam): 84 .funType( 85 dom: evaluate(type: dom), 86 boundName: boundName, 87 fam: close(body: fam) 88 ) 89 case let .recordType(boundName: boundName, fields: fields): 90 .recordType(boundName: boundName, fields: fields.map(close(fieldSpec:))) 91 } 92 } 93} 94 95extension Closure where Body == Term { 96 func instantiate(with value: Value) -> Value { 97 evaluator.extendedBy(value: value).evaluate(term: body) 98 } 99} 100 101extension Closure where Body == Term.Type_ { 102 func instantiate(with value: Value) -> Value.Type_ { 103 evaluator.extendedBy(value: value).evaluate(type: body) 104 } 105}