Pre class implementation commit

This commit is contained in:
Bobby Lucero 2025-08-10 16:50:18 -04:00
parent 266cca5b42
commit 7a9c0b7ea9
3 changed files with 109 additions and 3 deletions

View File

@ -4,6 +4,7 @@
#include "BobStdLib.h"
#include "ErrorReporter.h"
#include "Environment.h"
#include "Expression.h"
#include <iostream>
Interpreter::Interpreter(bool isInteractive)
@ -107,13 +108,13 @@ void Interpreter::forceCleanup() {
}
Value Interpreter::evaluateCallExprInline(const std::shared_ptr<CallExpr>& expression) {
Value callee = evaluate(expression->callee); // Direct call instead of through evaluator
Value callee = evaluate(expression->callee);
if (callee.isBuiltinFunction()) {
// Handle builtin functions with direct evaluation
std::vector<Value> arguments;
for (const auto& argument : expression->arguments) {
arguments.push_back(evaluate(argument)); // Direct call
arguments.push_back(evaluate(argument));
}
BuiltinFunction* builtinFunction = callee.asBuiltinFunction();
return builtinFunction->func(arguments, expression->paren.line, expression->paren.column);
@ -132,7 +133,7 @@ Value Interpreter::evaluateCallExprInline(const std::shared_ptr<CallExpr>& expre
std::vector<Value> arguments;
for (const auto& argument : expression->arguments) {
arguments.push_back(evaluate(argument)); // Direct call instead of through evaluator
arguments.push_back(evaluate(argument));
}
// Check arity (like original)

View File

@ -0,0 +1,77 @@
print("\n--- Class + Extension Syntax Proposal (Spec Tests) ---");
// These tests define the intended behavior and syntax. The parser/runtime
// will be implemented to satisfy them.
// Class declaration
class Person {
var name;
var age;
func init(name, age) {
this.name = name;
this.age = age;
}
func greet() {
print("Hi, I'm " + this.name + " (" + toString(this.age) + ")");
}
func birthday() {
this.age = this.age + 1;
}
}
// Instantiation + method calls
// var p = Person("Bob", 30);
// p.greet(); // "Hi, I'm Bob (30)"
// p.birthday();
// p.greet(); // "Hi, I'm Bob (31)"
// Extension: add methods to an existing class
extension Person {
func rename(newName) {
this.name = newName;
}
}
// p.rename("Robert");
// p.greet(); // "Hi, I'm Robert (31)"
// Extension on built-ins (string, array, dict are the type names)
extension string {
func repeat(n) {
var out = "";
var i = 0;
while (i < n) {
out = out + this;
i = i + 1;
}
return out;
}
}
// assert("ha".repeat(3) == "hahaha", "string.repeat should repeat string");
extension array {
func firstOr(defaultValue) {
if (len(this) == 0) return defaultValue;
return this[0];
}
}
// assert([].firstOr("none") == "none", "array.firstOr should return default on empty");
// Extension on any: adds a method to all objects
extension any {
func debug() {
return type(this) + ":" + toString(this);
}
}
// assert(42.debug() == "number:42", "any.debug should work on numbers");
// assert("x".debug() == "string:x", "any.debug should work on strings");
print("Class + Extension spec tests defined (pending parser/runtime support).");

View File

@ -0,0 +1,28 @@
print("\n--- Test: Method Calls on Objects ---");
// Setup a dictionary object
var obj = {};
// 1) Zero-arg method assigned to a property and invoked via dot call
obj.hello = func(){ print("hello-method"); };
obj.hello();
// 2) Method that uses the receiver as first implicit argument (self)
obj.set = func(self, key, value){ self[key] = value; };
obj.get = func(self, key){ return self[key]; };
obj.set(obj, "name", "Bob");
assert(obj.get(obj, "name") == "Bob", "obj.get should return value set via method using receiver");
// 3) Ensure taking a reference to a method and calling it as a plain function still works
var ref = obj.hello;
ref();
// 4) Ensure passing extra args still respects order after receiver injection
obj.concat3 = func(self, a, b){ return toString(a) + ":" + toString(b) + ":" + toString(self["name"]); };
var s = obj.concat3(obj, 1, 2);
assert(s == "1:2:Bob", "receiver should be last component in return value");
print("Method calls on objects: PASS");