Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
161 lines (117 sloc) 4.59 KB
possible syntax for mole ("M0 Overlay LanguagE")
I propose that we have 5 types; INSP for registers and cs, which is a C-like
string. (This probably won't be exactly like a C-string, but close enough that
C code can use it if needed.)
registers: I, N, S, P
primitive string: cs
*constant values*
This describes what kind of constants can be used in mole code.
int: [1-9]\d*
float: ...
hex: 0[xX][0-9a-fA-F]+
octal: 0[0-7]+
string: "[...]" (with escapes)
*compile-time constants*
*working with strings*
Strings pretend to be 0-indexed. They actually also store their length and
encoding as the first five values. The length is stored as a 4B int and the
encoding is stored in one byte, with 3 unused bytes for padding. The string
for "hello, worlds?" would look as follows in memory:
0x0 0x4 0x8 0xA 0x10 0x14
|0x0|0x0|0x0|0xC|0x0|0x0|0x0|0x1| h | e | l | l | o | , | | w | o | r | l | d | s | ? |\0 |
size encoding 0x0 0x4 0x8 0xA
Structs may be defined as below. Once a struct is defined, it can be used
wherever any other type can be used. If a register is of a struct type, it is
assumed to point to a region of memory with the specified layout. Struct
members are accessed using the '->' notation, as in C. sizeof() can be used to
determine the number of bytes required by the struct. This is similar to C,
except that sizeof() is purely a compile-time construct and can not be used to
calculate the length of an array.
struct {
I int_thingy;
N n_thingy;
} struct_thingy;
var I quux;
var struct_thingy st;
st = m0::sys_alloc sizeof(struct_thingy);
st->int_thingy = 39292934;
st->n_thingy = 332.66;
Chunks are similar to functions. They have a constants table, a metadata table
and a bytecode segment. Values can be added to the constants table by
declaring a value with the keyword "const". Annotations may be added
automatically by the mole compiler and can also be added manually with the .ann
"key" "value" syntax.
chunk main (I a1, I a2, I a3) {
const I stdout 1;
const cs hello "ohai. im in ur m0";
// annotation for the right file will be added by m1 compiler
m0::print_i stdout, hello;
var I i_thingy;
i_thingy += a3++;
c::fprintf(stdout, "asdfw %d\n", i_thingy);
call_chunk "chunk_name", arg_array;
*calling conventions*
I don't know. There are a couple options:
1) The first is that all calling conventions need to be dealt with explicitly.
This isn't nearly as bad as it'd be under M0 because of composed ops and it
would allow a very high degree of control without requiring the management of
all the minutae of the calling conventions more than once.
2) The second option is to have a default set of calling conventions that are
used with a simple minimalist syntax, but to allow them to be overridden with
composed ops.
3) The third option is to say that only the builtins can be used for control
flow. For a very experimental language like mole, this approach is probably
*composed ops*
mole supports syntax to create composed ops which behave similarly to built-in
M0 ops. The syntax is similar to chunnks with a few differences. Composed ops
are declared using the "composed" keyword and do not have return statements.
Any values that the composed op needs to modify should passed as arguments.
Using a return statement in composed op is a syntax error. Composed ops may
take an arbitrary number of arguments. Variables may be declared in composed
ops as in functions. composed ops are similar to inlined functions in C.
composed init_cf(P new_cf, I retpc_label) {
I cf_size = 256;
I flags = 0;
new_cf = m0::gc_alloc cf_size, flags;
new_cf[INTERP] = cf[INTERP];
new_cf[CHUNK] = cf[CHUNK];
new_cf[CONSTS] = cf[CONSTS];
new_cf[MDS] = cf[MDS];
new_cf[BCS] = cf[BCS];
new_cf[PCF] = cf[CF];
new_cf[CF] = new_cf;
new_cf[EH] = 0;
new_cf[RETPC] = 0;
new_cf[SPILLCF] = 0;
RETPC = retpc_label;
new_cf[PC] = post_set;
CF = new_cf;