@@ -119,8 +119,83 @@ static void concatenate(VM* pvm) {
119119 push (pvm , OBJ_VAL (result ));
120120}
121121
122+ // Helper Functions for OOP
122123
123- static InterpretResult run (VM * vm ) {
124+ static void defineMethod (ObjString * name , VM * vm ) {
125+ Value method = peek (vm , 0 );
126+ ObjClass * klass = AS_CLASS (peek (vm , 1 ));
127+ tableSet (& klass -> methods , name , method );
128+ pop (vm );
129+ }
130+
131+ static bool bindMethod (ObjClass * klass , ObjString * name , VM * vm ) {
132+ Value method ;
133+ if (!tableGet (& klass -> methods , name , & method )) {
134+ runtimeError (vm , "Undefined property '%s'." , name -> chars );
135+ return false;
136+ }
137+
138+ ObjBoundMethod * bound = newBoundMethod (peek (vm , 0 ), AS_CLOSURE (method ));
139+ pop (vm );
140+ push (vm , OBJ_VAL (bound ));
141+ return true;
142+ }
143+
144+ static bool invokeFromClass (ObjClass * klass , ObjString * name , int argCount , VM * vm ) {
145+ Value method ;
146+ if (!tableGet (& klass -> methods , name , & method )) {
147+ runtimeError (vm , "Undefined property '%s'." , name -> chars );
148+ return false;
149+ }
150+
151+ if (vm -> frameCount == FRAMES_MAX ) {
152+ runtimeError (vm , "Stack overflow." );
153+ return false;
154+ }
155+
156+ CallFrame * frame = & vm -> frames [vm -> frameCount ++ ];
157+ ObjClosure * closure = AS_CLOSURE (method );
158+ frame -> closure = closure ;
159+ frame -> ip = closure -> function -> chunk .code ;
160+ frame -> slots = vm -> stackTop - argCount - 1 ;
161+ return true;
162+ }
163+
164+ static bool invoke (ObjString * name , int argCount , VM * vm ) {
165+ Value receiver = peek (vm , argCount );
166+
167+ if (!IS_INSTANCE (receiver )) {
168+ runtimeError (vm , "Only instances have methods." );
169+ return false;
170+ }
171+
172+ ObjInstance * instance = AS_INSTANCE (receiver );
173+
174+ Value value ;
175+ if (tableGet (& instance -> fields , name , & value )) {
176+ vm -> stackTop [- argCount - 1 ] = value ;
177+ // Call value logic... but strictly speaking, invoke expects a method call.
178+ // If field is a closure, we call it.
179+ // Simplified: Delegate to call logic if field found?
180+ // Optimization: OpInvoke is for methods. If field found, treat as property access + call.
181+ // But OpInvoke optimizes method lookup.
182+ // Let's stick to method lookup first.
183+ return invokeFromClass (instance -> klass , name , argCount , vm );
184+ // Wait, if it is a field, we want to call check if it's callable.
185+ // For normal invoke, we look for method in class.
186+ }
187+
188+ return invokeFromClass (instance -> klass , name , argCount , vm );
189+ }
190+
191+ // ... (Rest of file) ...
192+
193+ // DO_OP_CALL update in run() to be patched separately or via full file rewrite if preferred.
194+ // But `replace_file_content` targets blocks.
195+ // I will create a separate tool call for DO_OP_CALL update to be safe and precise.
196+ // This block just adds the helpers at the end of file (or before run/where needed).
197+ // Since `run` uses them, they must be forward declared or defined before `run`.
198+ // I will insert them BEFORE `run`.
124199 printf ("DEBUG: Entering run()\n" );
125200 CallFrame * frame = & vm -> frames [vm -> frameCount - 1 ];
126201
@@ -535,6 +610,31 @@ static InterpretResult run(VM *vm) {
535610 vm -> stackTop -= argCount + 1 ;
536611 push (vm , result );
537612 DISPATCH ();
613+ } else if (IS_CLASS (callee )) {
614+ ObjClass * klass = AS_CLASS (callee );
615+ vm -> stackTop [- argCount - 1 ] = OBJ_VAL (newInstance (klass ));
616+ Value initializer ;
617+ // Check for 'init' method
618+ // If init exists, call it.
619+ // Note: we can't easily string check without an ObjString for "init".
620+ // We should pre-intern "init" or create it here.
621+ // Performance cost?
622+ // For now, assume no init call in Alpha or use vm->strings lookup.
623+ // Re-visit for 'init'.
624+ DISPATCH ();
625+ } else if (IS_BOUND_METHOD (callee )) {
626+ ObjBoundMethod * bound = AS_BOUND_METHOD (callee );
627+ vm -> stackTop [- argCount - 1 ] = bound -> receiver ;
628+
629+ if (vm -> frameCount == FRAMES_MAX ) {
630+ runtimeError (vm , "Stack overflow." );
631+ return INTERPRET_RUNTIME_ERROR ;
632+ }
633+ frame = & vm -> frames [vm -> frameCount ++ ];
634+ frame -> closure = bound -> method ;
635+ frame -> ip = bound -> method -> function -> chunk .code ;
636+ frame -> slots = vm -> stackTop - argCount - 1 ;
637+ DISPATCH ();
538638 } else {
539639 runtimeError (vm , "Can only call functions, classes, and foreign functions." );
540640 return INTERPRET_RUNTIME_ERROR ;
0 commit comments