// nil is the undefined object // integers, floats, strings are as usual // # 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 print("Lambda => ", Lambda, "\n"); // this prints as print("Closure => ", Closure, "\n"); // this prints as // 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 <> 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 ""; 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); }