Runtime: add method dispatch for array/string/dict/number (.len, .push, .pop, .keys, .values, .has, .toInt) Stdlib: delete global len/push/pop/keys/values/has Tests/docs/examples: migrate to method style; add tests/test_builtin_methods_style.bob All tests pass Breaking: global len/push/pop/keys/values/has removed; use methods instead Parser/AST: add class/extends/extension/super, field initializers Runtime: shared methods with this injection; classParents/classTemplates; super resolution; ownerClass/currentClass; extension lookup order Builtins: method dispatch for array/string/dict/number (.len/.push/.pop/.keys/.values/.has/.toInt); remove global forms Tests/docs/examples: add/refresh for classes, inheritance, super, polymorphism; migrate to method style; all tests pass VS Code extension: update grammar/readme/snippets for new features
45 lines
2.2 KiB
Plaintext
45 lines
2.2 KiB
Plaintext
print("\n--- Test: Practical Polymorphism ---");
|
|
|
|
// Example 1: Shapes - compute total area
|
|
class Shape { func area() { return 0; } }
|
|
class Rectangle extends Shape { func init(w, h) { this.w = w; this.h = h; } func area() { return this.w * this.h; } }
|
|
class Triangle extends Shape { func init(b, h) { this.b = b; this.h = h; } func area() { return (this.b * this.h) / 2; } }
|
|
|
|
var shapes = [ Rectangle(3, 4), Triangle(10, 2), Rectangle(5, 2) ];
|
|
var total = 0;
|
|
for (var i = 0; i < shapes.len(); i = i + 1) { total = total + shapes[i].area(); }
|
|
assert(total == (3*4) + (10*2)/2 + (5*2), "shapes total area");
|
|
|
|
// Example 2: Logger hierarchy - override behavior
|
|
class Logger { func log(msg) { return "[LOG] " + msg; } }
|
|
class ConsoleLogger extends Logger { func log(msg) { return "[CONSOLE] " + msg; } }
|
|
class FileLogger extends Logger { func log(msg) { return "[FILE] " + msg; } }
|
|
var loggers = [ Logger(), ConsoleLogger(), FileLogger() ];
|
|
assert(loggers[0].log("ok") == "[LOG] ok", "base logger");
|
|
assert(loggers[1].log("ok") == "[CONSOLE] ok", "console logger");
|
|
assert(loggers[2].log("ok") == "[FILE] ok", "file logger");
|
|
|
|
// Example 3: Notifier with extension-based specialization
|
|
class Notifier { func send(msg) { return "sent:" + msg; } }
|
|
class EmailNotifier extends Notifier {}
|
|
class SmsNotifier extends Notifier {}
|
|
extension EmailNotifier { func send(msg) { return super.send("EMAIL:" + msg); } }
|
|
extension SmsNotifier { func send(msg) { return super.send("SMS:" + msg); } }
|
|
var n = [ EmailNotifier(), SmsNotifier(), Notifier() ];
|
|
assert(n[0].send("hello") == "sent:EMAIL:hello", "email notify");
|
|
assert(n[1].send("hello") == "sent:SMS:hello", "sms notify");
|
|
assert(n[2].send("hello") == "sent:hello", "base notify");
|
|
|
|
// Example 4: Processor pipeline - same method name, different implementations
|
|
class Processor { func process(x) { return x; } }
|
|
class DoubleProc extends Processor { func process(x) { return x * 2; } }
|
|
class IncProc extends Processor { func process(x) { return x + 1; } }
|
|
var pipeline = [ DoubleProc(), IncProc(), DoubleProc() ]; // (((3*2)+1)*2) = 14
|
|
var value = 3;
|
|
for (var i = 0; i < pipeline.len(); i = i + 1) { value = pipeline[i].process(value); }
|
|
assert(value == 14, "processor pipeline");
|
|
|
|
print("Practical polymorphism: PASS");
|
|
|
|
|