Introduction
Jako is a simple malleable language. It has very little built-in functionality, but it is very easy to build a reasonable language out of it.
Constructs
The basic constructs of Jako are predefined, but the ways in which they combine are programmer-defined.
Words
A word is a contiguous string of characters matching the Perl regular expression m/[A-Za-z][A-Za-z0-9_]*/
. Words can be used as the names of types, variables and constants, and can also be used as key words.
Symbols
Symbols are
Expressions
Blocks / Environments
A named block can be executed by passing it to eval
.
The section "A Mathematical Note" of [MEYER-2001] presents a model of a class as a set of name-value bindings.
Lesson 3, "Semantic Building Blocks" of [MEAD-2001] describes the environment (or context) of a program at a specific point in its execution in a similar way.
A block is an environment. Names not explicitly bound in that environment are implicitly bound if they are explicitly bound in an ancestor environment.
bind env E word N any V := { E.N = V; }
Blocklists
Parentheses are used to delimit blocklists. A parenthetical list of expressions is semantically equivalent to the same number of single-expression blocks, one after the other. That is,
(a < b, 5, i++)
is exactly the same as
{a < b} {5} {i++}
Definitions
def
Intrinsic Flow Control Statements
if
goto
def goto label L := ...
Defining Conventional Constructs
Even though Jako doesn't have conventional constructs built-in, it is very easy to define them using the facilities Jako does provide:
Eiffel-like loops
Translating from Eiffel notation to a Perl-like notation yields something like this:
from {...} invariant (...) variant {...} until (...) loop {...} end;
where each {...}
represents a block of statements and each (...)
represents a single boolean expression.
Since the body of the loop is delimited by the braces, we can get rid of the end
keyword:
from {...} invariant (...) variant {...} until (...) loop {...};
Since we are used to using redo
to go back to the top of the loop block and re-do the current iteration, we'll replace loop
with do
:
from {...} invariant (...) variant {...} until (...) do {...};
Eiffel's variant
clause is equivalent to the Perl continue
clause:
from {...} invariant (...) continue {...} until (...) do {...};
But, we like to see that clause at the end:
from {...} invariant (...) until (...) do {...} continue {...};
Since we've adopted the Perlish continue
in place of variant
, now invariant
seems out of place, but check
seems to fit nicely:
from {...} check (...) until (...) do {...} continue {...};
while
With this Jako definition:
def while block W ( do? block D ( continue? block C )? )? := {
var R: typeof(D); # TODO: typeof(D) == block, we want type of *last statement of* D.
CONT: goto :LAST unless eval W;
REDO: R = eval D;
NEXT: eval C;
goto :CONT;
LAST: return R;
}
we can write Perlish while loops:
i = 0;
while (x[i] < y[i]) do {
print "$i\n";
} continue {
i++
}
In fact, we can even write very concise while
loops, given the optionality of the do
and continue
blocks and the equivalence of (x;y)
to {x} {y}
:
i = 0;
while (x[i] < y[i]; print "$i\n"; i++);
(which almost looks like a for
loop).
for
This Jako definition:
def for block F while? block W continue? block C do? block D := {
var R: typeof(D); # TODO: typeof(D) == block, we want type of *last statement of* D.
FOR: eval F;
CONT: goto :LAST unless eval W;
REDO: R = eval D;
NEXT: eval C;
goto :CONT;
LAST: return R;
}
allows us to write for
loops the way we are used to, such as:
for (i = 0; i < l; i++) { print x[i], "\n" }
which is really shorthand for:
for { i = 0 } { i < l } { i++ } { print x[i], "\n" }
or, more verbosely:
for {
i = 0;
} while {
i < l
} continue {
i++
} do {
print x[i], "\n"
}
redo, next and last
We can define the familiar loop control statements given the consistency of label definitions above:
def redo ( label L )? := {
goto L:REDO; # if L not given, means "goto :REDO"
}
def next ( label L )? := {
goto L:NEXT; # if L not given, means "goto :NEXT"
}
def last ( label L )? := {
goto L:LAST; # if L not given, means "goto :LAST"
}
TODO: Allow x = next
? -- What would that mean?
if, then, elseif and else
def if block I then? block T ( elsif block EI then? block ET )* (else block E)? := {
var R: typeof(...);
IF: goto +:NEXT unless eval I; # "+" --> forward-only
REDO: R = eval T;
goto +:LAST;
NEXT: {
*:IF: goto :*:NEXT unless eval *EI;
*:REDO: R = eval *ET;
goto LAST;
*:NEXT:
} over elsif
REDO: R = eval E;
LAST: return R;
}
Object-Oriented Programming
A class is an environment template. An instance is an environment built from such a template. Method application is the execution of code within the instance's environment. For example:
y = foo.x
means to find 'x' in the environment 'foo' and point 'y' in the current environment at it.
Issues: Multiple inheritance for blocks that represent classes vs. single parents for blocks that represent general code sequences.
Analogy:
closure : block :: instance : class
Instantiation as environment cloning.
self
The word 'self' means the enclosing environment (instance, in the case of an object method).
The word 'class' means the enclosing environment's enclosing environment.
Problem:
class {
method x {
{
self.y; # Looks in method
}
self.z; # Looks in instance
}
int y;
int z;
}
To Do
Templates and generic programming
Multiple inheritance, renaming and redefinition.
Run-time definition and modification of environments.
References
- [MEAD-2001]
-
Mead, Jerud J. and Shende, Anil M. Persuasive Programming, A|B|F Content, Wilsonville, OR, 2001.
- [MEYER-1997]
-
Meyer, Bertrand. "Object-Oriented Software Construction, Second Edition," Prentice Hall PTR, Upper Saddle River, NJ, 1997.
- [MEYER-2001]
-
Meyer, Bertrand. "Overloading vs. Object Technology," Journal of Object-Oriented Programming, October/November 2001 (Vol 14, No. 4).