Pre class implementation commit
This commit is contained in:
parent
266cca5b42
commit
7a9c0b7ea9
@ -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)
|
||||
|
||||
77
tests/test_class_and_extension.bob
Normal file
77
tests/test_class_and_extension.bob
Normal 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).");
|
||||
|
||||
|
||||
28
tests/test_method_calls.bob
Normal file
28
tests/test_method_calls.bob
Normal 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");
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user