diff --git a/doc/beta-style inner.txt b/doc/beta-style inner.txt new file mode 100644 index 00000000..c2c5c799 --- /dev/null +++ b/doc/beta-style inner.txt @@ -0,0 +1,55 @@ +class Base { + foo { + io.write("a") + inner + io.write("b") + } +} + +class Mid is Base {} + +class Derived is Mid { + foo { + io.write("c") + } +} + +var d = Derived.new +d.foo + +// find base-most method "foo" (on Base) +// invoke it +// when inner is hit, walk down inheritance chain to find nearest override +// (in Derived) +// invoke it + + +for every class, store two lists: + +1. list of methods this class defines. +2. mapping of method name to which method body should be invoked first for + that method. this will be the base-most class's definition of a given + method name. + +typedef struct +{ + // The method body to invoke. This will be the base-most definition of a + // method for a given name. + Method* method; + + // If [method] calls `inner`, this is the class whose inner method is invoked. + // If *that* method in turn calls `inner`, we look up the [inner] property of + // this method on that class's dispatch table to chain to the next one. + // + // This is `NULL` if there is no inner method to call. + ClassObj* inner; +} Dispatch; + +typedef struct +{ + Dispatch dispatchTable[MAX_SYMBOLS]; +} ClassObj; + +with normal overridding, can unify those. with inner(), need both. + +whenever a method is invoked, look it up in 2, then call that method body. diff --git a/doc/receiver-less calls.txt b/doc/receiver-less calls.txt new file mode 100644 index 00000000..8378feab --- /dev/null +++ b/doc/receiver-less calls.txt @@ -0,0 +1,76 @@ +Q1: What does this resolve to: + + foo(arg) + + It could be: + 1. this.foo(bar) + 2. EnclosingClass.foo(bar) // i.e. a static method call + 3. a call to a top-level function foo() + +If we adopt the idea that a module is just a class definition (with some +syntactic differences) and classes can be nested, then 3 really means "a call +to a static method on the class surrounding the enclosing class". + +I *don't* think we want the answer to the question to vary based on the name +in question. We can't rely on name resolution to disambiguate because we don't +know the full set of surrounding names in a single pass compiler. Also, it's +semantically squishier. + +I think the right answer is 1, it's an implicit call on this. That's what you +want most often, I think. For imported modules, we could import them with a +"prefix" (really import them as objects bound to named variables), so calling +a top-level function in another module would be something like: + + someModule.foo(arg) + +This leaves the question of how *do* you call top level functions in your own +module? I.e., how do we call foo here: + + def foo(arg) { io.write("called foo!") } + + class SomeClass { + bar { + // Want to call foo here... + } + } + +This is analogous to: + + class SomeModule { + static foo(arg) { io.write("called foo!") } + + class SomeClass { + bar { + // Want to call foo here... + } + } + } + +The obvious solution is to use the class name: + + class SomeModule { + static foo(arg) { io.write("called foo!") } + + class SomeClass { + bar { + SomeModule.foo(arg) + } + } + } + +Which just leaves the question of what the class name of a top-level "module +class" is. + +Idea: it's unnamed, so you just use a leading ".": + + def foo(arg) { io.write("called foo!") } + + class SomeClass { + bar { + .foo(arg) + } + } + +This mirrors C++'s unnamed scope thing: + + ::foo(arg);