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.
The basic constructs of Jako are predefined, but the ways in which they combine are programmer-defined.
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.
m/[A-Za-z][A-Za-z0-9_]*/
Symbols are
A named block can be executed by passing it to eval.
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; }
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++}
def
def goto label L := ...
Even though Jako doesn't have conventional constructs built-in, it is very easy to define them using the facilities Jako does provide:
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:
end
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:
redo
loop
do
from {...} invariant (...) variant {...} until (...) do {...};
Eiffel's variant clause is equivalent to the Perl continue clause:
variant
continue
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:
invariant
check
from {...} check (...) until (...) do {...} continue {...};
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}:
while
(x;y)
{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" }
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?
x = next
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; }
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.
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; }
Templates and generic programming
Multiple inheritance, renaming and redefinition.
Run-time definition and modification of environments.
Mead, Jerud J. and Shende, Anil M. Persuasive Programming, A|B|F Content, Wilsonville, OR, 2001.
Meyer, Bertrand. "Object-Oriented Software Construction, Second Edition," Prentice Hall PTR, Upper Saddle River, NJ, 1997.
Meyer, Bertrand. "Overloading vs. Object Technology," Journal of Object-Oriented Programming, October/November 2001 (Vol 14, No. 4).
To install Ruby, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Ruby
CPAN shell
perl -MCPAN -e shell install Ruby
For more information on module installation, please visit the detailed CPAN module installation guide.