@@ -107,7 +107,148 @@ static void concatenate(VM* pvm) {
107107 push (pvm , OBJ_VAL (result ));
108108}
109109
110+
111+ void closeUpvalues (VM * vm , Value * last ) {
112+ while (vm -> openUpvalues != NULL &&
113+ vm -> openUpvalues -> location >= last ) {
114+ ObjUpvalue * upvalue = vm -> openUpvalues ;
115+ upvalue -> closed = * upvalue -> location ;
116+ upvalue -> location = & upvalue -> closed ;
117+ vm -> openUpvalues = upvalue -> next ;
118+ }
119+ }
120+
121+ ObjUpvalue * captureUpvalue (Value * local , VM * vm ) {
122+ ObjUpvalue * prevUpvalue = NULL ;
123+ ObjUpvalue * upvalue = vm -> openUpvalues ;
124+ while (upvalue != NULL && upvalue -> location > local ) {
125+ prevUpvalue = upvalue ;
126+ upvalue = upvalue -> next ;
127+ }
128+
129+ if (upvalue != NULL && upvalue -> location == local ) {
130+ return upvalue ;
131+ }
132+
133+ ObjUpvalue * createdUpvalue = newUpvalue (local );
134+ createdUpvalue -> next = upvalue ;
135+
136+ if (prevUpvalue == NULL ) {
137+ vm -> openUpvalues = createdUpvalue ;
138+ } else {
139+ prevUpvalue -> next = createdUpvalue ;
140+ }
141+
142+ return createdUpvalue ;
143+ }
144+
145+ void defineMethod (ObjString * name , VM * vm ) {
146+ Value method = peek (vm , 0 );
147+ ObjClass * klass = AS_CLASS (peek (vm , 1 ));
148+ tableSet (& klass -> methods , name , method );
149+ pop (vm );
150+ }
151+
152+ bool bindMethod (struct ObjClass * klass , ObjString * name , VM * vm ) {
153+ Value method ;
154+ if (!tableGet (& klass -> methods , name , & method )) {
155+ runtimeError (vm , "Undefined property '%s'." , name -> chars );
156+ return false;
157+ }
158+
159+ ObjBoundMethod * bound = newBoundMethod (peek (vm , 0 ), AS_CLOSURE (method ));
160+ pop (vm );
161+ push (vm , OBJ_VAL (bound ));
162+ return true;
163+ }
164+
165+ bool call (ObjClosure * closure , int argCount , VM * vm ) {
166+ if (argCount != closure -> function -> arity ) {
167+ runtimeError (vm , "Expected %d arguments but got %d." ,
168+ closure -> function -> arity , argCount );
169+ return false;
170+ }
171+
172+ if (vm -> frameCount == 64 ) {
173+ runtimeError (vm , "Stack overflow." );
174+ return false;
175+ }
176+
177+ CallFrame * frame = & vm -> frames [vm -> frameCount ++ ];
178+ frame -> closure = closure ;
179+ frame -> ip = closure -> function -> chunk .code ;
180+ frame -> slots = vm -> stackTop - argCount - 1 ;
181+ return true;
182+ }
183+
184+ bool callValue (Value callee , int argCount , VM * vm ) {
185+ if (IS_OBJ (callee )) {
186+ switch (OBJ_TYPE (callee )) {
187+ case OBJ_BOUND_METHOD : {
188+ ObjBoundMethod * bound = AS_BOUND_METHOD (callee );
189+ vm -> stackTop [- argCount - 1 ] = bound -> receiver ;
190+ return call (bound -> method , argCount , vm );
191+ }
192+ case OBJ_CLASS : {
193+ ObjClass * klass = AS_CLASS (callee );
194+ vm -> stackTop [- argCount - 1 ] = OBJ_VAL (newInstance (klass ));
195+ Value initializer ;
196+ if (tableGet (& klass -> methods , copyString ("init" , 4 ), & initializer )) {
197+ return call (AS_CLOSURE (initializer ), argCount , vm );
198+ } else if (argCount != 0 ) {
199+ runtimeError (vm , "Expected 0 arguments but got %d." , argCount );
200+ return false;
201+ }
202+ return true;
203+ }
204+ case OBJ_CLOSURE :
205+ return call (AS_CLOSURE (callee ), argCount , vm );
206+ case OBJ_NATIVE : {
207+ NativeFn native = AS_NATIVE (callee );
208+ Value result = native (argCount , vm -> stackTop - argCount );
209+ vm -> stackTop -= argCount + 1 ;
210+ push (vm , result );
211+ return true;
212+ }
213+ default :
214+ break ; // Non-callable object type
215+ }
216+ }
217+ runtimeError (vm , "Can only call functions and classes." );
218+ return false;
219+ }
220+
221+ bool invokeFromClass (struct ObjClass * klass , ObjString * name ,
222+ int argCount , VM * vm ) {
223+ Value method ;
224+ if (!tableGet (& klass -> methods , name , & method )) {
225+ runtimeError (vm , "Undefined property '%s'." , name -> chars );
226+ return false;
227+ }
228+ return call (AS_CLOSURE (method ), argCount , vm );
229+ }
230+
231+ bool invoke (ObjString * name , int argCount , VM * vm ) {
232+ Value receiver = peek (vm , argCount );
233+
234+ if (!IS_INSTANCE (receiver )) {
235+ runtimeError (vm , "Only instances have methods." );
236+ return false;
237+ }
238+
239+ struct ObjInstance * instance = AS_INSTANCE (receiver );
240+
241+ Value value ;
242+ if (tableGet (& instance -> fields , name , & value )) {
243+ vm -> stackTop [- argCount - 1 ] = value ;
244+ return callValue (value , argCount , vm );
245+ }
246+
247+ return invokeFromClass (instance -> klass , name , argCount , vm );
248+ }
249+
110250static InterpretResult run (VM * vm ) {
251+
111252 CallFrame * frame = & vm -> frames [vm -> frameCount - 1 ];
112253
113254#define READ_BYTE () (*frame->ip++)
0 commit comments