Pre class implementation commit
This commit is contained in:
parent
266cca5b42
commit
7a9c0b7ea9
@ -4,6 +4,7 @@
|
|||||||
#include "BobStdLib.h"
|
#include "BobStdLib.h"
|
||||||
#include "ErrorReporter.h"
|
#include "ErrorReporter.h"
|
||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
|
#include "Expression.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
Interpreter::Interpreter(bool isInteractive)
|
Interpreter::Interpreter(bool isInteractive)
|
||||||
@ -107,13 +108,13 @@ void Interpreter::forceCleanup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Value Interpreter::evaluateCallExprInline(const std::shared_ptr<CallExpr>& expression) {
|
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()) {
|
if (callee.isBuiltinFunction()) {
|
||||||
// Handle builtin functions with direct evaluation
|
// Handle builtin functions with direct evaluation
|
||||||
std::vector<Value> arguments;
|
std::vector<Value> arguments;
|
||||||
for (const auto& argument : expression->arguments) {
|
for (const auto& argument : expression->arguments) {
|
||||||
arguments.push_back(evaluate(argument)); // Direct call
|
arguments.push_back(evaluate(argument));
|
||||||
}
|
}
|
||||||
BuiltinFunction* builtinFunction = callee.asBuiltinFunction();
|
BuiltinFunction* builtinFunction = callee.asBuiltinFunction();
|
||||||
return builtinFunction->func(arguments, expression->paren.line, expression->paren.column);
|
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;
|
std::vector<Value> arguments;
|
||||||
for (const auto& argument : expression->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)
|
// 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