Minimal (?) protype-based language.
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 

427 wiersze
10 KiB

// nil is the undefined object
// integers, floats, strings are as usual
// #<identifier> is a symbol literal
print(nil, " ", 42, " ", 3.14, " string ", #Symbol, " newline \n");
// the prototypical object types used in the implementation have global names
// e.g., Object is the prototypical object at the root of the delegation hierarchy
print("Object => ", Object, "\n"); // this prints as <Object>
print("Lambda => ", Lambda, "\n"); // this prints as <Lambda>
print("Closure => ", Closure, "\n"); // this prints as <Closure>
// create a new object instance by asking an existing one to be the delegate for a new instance
// e.g., to create a new object that delegates to the prototype Object...
o = Object.new();
print("o = Object.new() => ", o, "\n");
// this prints as <<Object>> because the number of <> surrounding the name tells you
// how many levels of delegation were needed before the __name__ property was found
// arguments can be positional and/or key:value pairs
// for the new() method, the arguments become the properties of the newly created object
o = Object.new(foo: 42, bar: 666);
print("o = Object.new(foo:42, bar: 666) => ", o, "\n", full: 1);
print("o.foo => ", o.foo, "\n");
// to create a new type make a prototype with a __name__ that delegates to another prototype
Point = Object.new(__name__: #Point);
// objects can be created from the new prototype because it delegates to the Object prototype,
// in other words the new prototype 'inherits' Object.new()
// objects created from the new prototype will inherit its __name__ property
print("Point.new() => ", Point.new(), "\n");
print("Point.new(x: 3, y: 4) => ", Point.new(x: 3, y: 4), "\n", full: 1);
// anonymous functions are written: "(parameters...) { statements... }"
// all statements return values
// the last statement in a block provides a return value for the entire function
double = (x) { x+x };
print("twice 21 is ", double(21), "\n");
// use the keyword argument "full:x" (where x is non-nil) to make the print primitive
// recursively print the entire contents of any objects it encounters
print("double => ", double, "\n", full:1);
// anonymous functions installed as properties of a prototype become methods
// for all objects that delegate to the prototype
Point.magnitude() { sqrt(self.x * self.x + self.y * self.y) }
m = Point.new(x: 3, y: 4).magnitude();
print("Point.new(x:3, y:4).magnitude() => ", m, "\n");
// functions close over their dynamic environment when created
// (yes, I know, something needs to be done about all the nasty semicolons)
makeCounter(n)
{
n = n - 1; // make the counter return n the first time it is called
() { print(__env__(), "\n", full:1); n = n + 1 } // the counter is an anonymous function, closing over n, that increments n
}
counter = makeCounter(40);
print(counter(), "\n");
print(counter(), "\n");
print(counter(), "\n");
print(counter(), "\n");
print(Object, full:1, "\n");
test(x) { print(x, " "); if (x) print("yes\n") else print("no\n") }
test(nil);
test(1);
test("hello");
nfib(n) { if (n < 2) 1 else nfib(n-1) + nfib(n-2) + 1 }
print(nfib(5), "\n");
print(nfib(15), "\n");
/*
assert(x) {
if (!(eval(x))) {
print("\nassertion failed: ", codeString(x), "\n");
exit(1);
}
}
assert.fixed = #t; // do not evaluate arguments (x will be an AST suitable for eval())
*/
Symbol.macros.assert = (x) {
`{if (!(eval(@x))) {
print("\nassertion failed: ", @codeString(x), "\n");
exit(1);
}};
};
refute(x) {
if (eval(x)) {
print("\nrefutation failed: ", codeString(x), "\n");
exit(1);
}
}
refute.fixed = #t;
refute;
assert(1 == 1);
refute(1 == 0);
assert(0 < 1); refute(1 < 1); refute(2 < 1);
assert(0 <= 1); assert(1 <= 1); refute(2 <= 1);
refute(0 >= 1); assert(1 >= 1); assert(2 >= 1);
refute(0 > 1); refute(1 > 1); assert(2 > 1);
refute(0 == 1); assert(1 == 1); refute(2 == 1);
assert(0 != 1); refute(1 != 1); assert(2 != 1);
assert(16 << 0 == 16); assert(16 << 1 == 32); assert(16 << 2 == 64); assert(16 << 3 == 128);
assert(16 >> 0 == 16); assert(16 >> 1 == 8); assert(16 >> 2 == 4); assert(16 >> 3 == 2);
print(0b101010, " ");
print(052, " ");
print(42, " ");
print(0x2a, "\n");
bin__(n, b, w) {
if (n >= 2 || w > 1) bin__(truncate(n / 2), b, w - 1);
print(n % 2);
}
assert((0b1110 | 0b0111) == 0b1111);
assert((0b1110 ^ 0b0111) == 0b1001);
assert((0b1110 & 0b0111) == 0b0110);
nt = 0;
nf = 0;
t() { global nt += 1; #t }
f() { global nf += 1; nil }
refute(f() || f()); assert(nt == 0); assert(nf == 2);
assert(f() || t()); assert(nt == 1); assert(nf == 3);
assert(t() || f()); assert(nt == 2); assert(nf == 3);
assert(t() || t()); assert(nt == 3); assert(nf == 3);
refute(f() && f()); assert(nt == 3); assert(nf == 4);
refute(f() && t()); assert(nt == 3); assert(nf == 5);
refute(t() && f()); assert(nt == 4); assert(nf == 6);
assert(t() && t()); assert(nt == 6); assert(nf == 6);
1 || ({ print("fail\n"); exit(1) });
nil && ({ print("fail\n"); exit(1) });
nil || print("ok\n");
1 && print("ok\n");
i = 40;
assert(i++ == 40); assert(i == 41);
assert(i-- == 41); assert(i == 40);
assert(++i == 41); assert(i == 41);
assert(--i == 40); assert(i == 40);
assert((i *= 2) == 80); assert(i == 80);
assert((i /= 2) == 40); assert(i == 40);
assert((i %= 7) == 5); assert(i == 5);
assert((i <<= 4) == 80); assert(i == 80);
assert((i >>= 3) == 10); assert(i == 10);
i = 0;
assert((i |= 7) == 7); assert(i == 7);
assert((i |= 14) == 15); assert(i == 15);
assert((i ^= 6) == 9); assert(i == 9);
assert((i ^= 6) == 15); assert(i == 15);
assert((i &= 14) == 14); assert(i == 14);
assert((i &= 7) == 6); assert(i == 6);
i = [1, 2, 3];
assert(codeString(i) == "[1, 2, 3]");
assert(++i[1] == 3); assert(codeString(i) == "[1, 3, 3]");
assert(--i[2] == 2); assert(codeString(i) == "[1, 3, 2]");
assert(i[0]++ == 1); assert(codeString(i) == "[2, 3, 2]");
assert(i[2]-- == 2); assert(codeString(i) == "[2, 3, 1]");
print(eval(42), "\n");
MyType = Object.new(__name__: #MyType);
print("----\n");
MyType.__eval__(self) {
print("MyType.__eval__() invoked\n");
42;
}
myType = MyType.new();
print(eval(myType), "\n");
Object.print() { print(self) }
Object.println() { self.print(); print("\n") }
(){}.println();
x = 42;
print("====\n");
(42).println();
"hello".println();
nil.println();
nil.__delegate__.println();
nil.__delegate__.__delegate__.println();
nil.__delegate__.__delegate__.__delegate__.println();
Object.dump()
{
print("[");
keys = self.allKeys().sorted();
for (key in keys) print("KEY: ", key, "\n");
print("]\n");
}
p = Point.new(x: 3, y: 4);
p.dump();
#Symbol.println();
#Symbol.__delegate__.println();
#Symbol.__delegate__.__delegate__.println();
#Symbol.__delegate__.__delegate__.__delegate__.println();
print("POINT ", Point, "\n");
p = [x:5, y:12];
print("P ", p, "\n");
p[#__delegate__] = Point;
print("P ", p, "\n");
q = [__delegate__:Point, x:5, y:12];
print("Q ", q, "\n");
print("P.mag ", p.magnitude(), "\n");
o = [bar:666, 1, [2, 3, 6*7], foo:42];
print(o, "\n", full: 1);
o.dump();
print(len("Hello"), "\n");
print(len(#Goodbye), "\n");
print(len([]), "\n");
print(len([1]), "\n");
print(len([1, 2]), "\n");
printelts(x)
{
n = len(x);
print(n, "\n");
i = 0;
while (i < n) {
print(i, ": ", x[i], "\n");
i = i + 1;
}
x;
}
f() {
printelts(__env__());
}
f();
f("a");
f("a", "b");
f("a", "b", "c");
printelts("hello, world");
s = "hello, world\n"; print(s);
s[1] = 97; print(s);
s[4] = ord("y"); print(s);
s[8] = ord("i"); print(s);
print("READ = ", readfile("test2.txt"));
Object.subtype(name) { self.new(__name__: name) }
Stream = Object.subtype(#Stream);
newStream(string) {
self = Stream.new(
content: string,
position: 0,
limit: len(string)
);
print(self.position, " ", self.limit, " ", !self.atEnd(), "\n");
self;
}
Stream.atEnd() { self.position >= self.limit }
Stream.peek() { !self.atEnd() && self.content[self.position] }
Stream.next() {
!self.atEnd() && {
c = self.content[self.position];
self.position = self.position + 1;
c;
}
}
s = newStream(readfile("test2.txt"));
print(s, "\n");
while (!s.atEnd()) print(chr(s.peek()), " ", s.next(), " ");
print("\n");
x = (`6*7;);
print(x, "\n", full:1);
print(x.__eval__(), "\n", full:1);
print(eval(x), "\n");
print(codeString(x), "\n");
Symbol.macros.test = (x, y)
{
print("MACRO EVAL test with ", x, " and ", y, "\n");
`{print("REPLACEMENT ", @x, "\n"); @y }
};
print("MACRO table ", Symbol.macros, "\n", full:1);
print("define testfun\n");
testfun() {
test(1, 2);
test("three", "four");
}
print("call testfun\n");
testfun();
// used-defined AST nodes are evaluated the same way as built-in types
MakeSeven = Object.subtype(#MakeSeven);
MakeSeven.__eval__(exp, env) {
print("MakeSeven.__eval__ invoked\n");
7;
}
myNode = MakeSeven.new();
ast = (`6 * @myNode;); // user-defined node in AST
print("AST eval => ", eval(ast), "\n");
print("String to int conversion\n");
print("11111111".asInteger(2), "\n");
print("377".asInteger(8), "\n");
print("255".asInteger(), "\n");
print("FF".asInteger(16), "\n");
for (i from 0 to 10) print(i, " "); print("\n");
for (i from 10 to 0) print(i, " "); print("\n");
for (i in 10) print(i, " "); print("\n");
for (i in "ABCDE") print(i, " "); print("\n");
for (i in [1, "two", 3, "four"]) print(i, " "); print("\n");
factorial(n) { if (n < 2) nil else n * factorial(n-1) }
typeName(x) {
if (!x) return "<Undefined>";
name = "?";
level = 1;
while (x && !x.allKeys().includes(#__name__)) x = x.__delegate__;
if (x.allKeys().includes(#__name__)) name = x.__name__.asString();
"<" * level + name + ">" * level;
}
backtrace(e) {
pad(w, i) {
while (len(i) < w) i = " " + i;
i;
}
w = 2;
j = len(e);
while ((j /= 10) > 0) { ++w; } // w = 1+log10(j)
for (i from len(e) - 1 to 0)
print(pad(w, codeString(i)), ": ", codeString(e[i]), "\n");
}
try {
factorial(5);
}
catch (e) {
assert(e.__function__ == "*");
assert(e.__kind__ == "type error");
assert(e.__message__ == "illegal operand types");
assert(e.operand1 == 2);
assert(e.operand2 == nil);
print(e.__function__, ": ", e.__kind__, ": ", e.__message__, ": ", typeName(e.operand1), " and ", typeName(e.operand2), "\n");
backtrace(e);
}