Language Basics¶
Basic syntax¶
GCL is built around named tuples, written with curly braces:
{
# This is a comment
number = 1;
string = 'value'; # Strings can be doubly-quoted as well
bool = true; # Note: lowercase
expression = number * 2;
list = [ 1, 2, 3 ];
}
The top-level of a file will be parsed as a tuple automatically, so you don’t write the braces there. Semicolons are considered separators. They may be ommitted after the last statement if that aids readability.
The basic types you’d expect are supported: strings, ints, floats, bools and mapped onto their Python equivalents. Lists are supported, but can’t really be manipulated in GCL right now.
Expressions¶
a = 1 + 1;
b = 'foo' + 'bar';
c = 80 * '-';
GCL has an expression language, looking much like other languages you’re used
to. The evaluation model is mostly borrowed from Python, so things you expect
from Python (such as being able to use +
for both addition and string
concatenation).
Calling functions¶
inc(1)
Function application also looks the same as in Python. There’s currently no way to define functions in GCL, but you can invoke functions passed in from the external environment.
inc 1
If a function only has one argument, you can omit the parentheses and simply put a space between the function and the argument.
Accessing values in tuples¶
tuple = {
foo = 3;
};
that_foo = tuple.foo;
Periods are used to dereference tuples using constant keys. If the key is in a variable, tuples can be treated as maps (functions) to get a single key out:
tuple = {
foo = 3;
}
that_foo1 = tuple('foo');
which_key = 'foo';
that_foo2 = tuple(which_key);
Including other files¶
http = include 'library/http.gcl';
server = http.Server {
port = 8080;
}
External files can be included with the built-in include()
function. The
result of that expression is the result of parsing that file (which will be
parsed as a tuple using the default environment). Relative filenames are
resolved with respect to the including file.
‘if’ expressions¶
Expressions can also include conditions, using the if
statement:
allow_test_commands = if stage == 'alpha' then true else false;
# Of course, since these are booleans, the above could also be written as:
allow_test_commands = stage == 'alpha';
List comprehensions¶
Lists can be manipulated using list comprehensions:
[ x * 2 for x in [1, 2, 3, 4, 5] if x % 2 == 0 ]
Tuple composition¶
As a special case, a tuple can be applied to another tuple, yielding a new tuple thats the merge of both (with the right tuple overwriting existing keys in the left one).
This looks especially convenient when A is a reference and B is a tuple literal, and you use the paren-less function invocation:
FooApp = {
program = 'foo';
cwd = '/tmp';
}
my_foo = FooApp {
cwd = '/home';
}
my_foo
is now a tuple with 2 fields, program = 'foo'
(unchanged) and
cwd = '/home'
(overwritten).
This makes it possible to do abstraction: just define tuples with the common components and inherit specializations from them.
Parameterized tuples¶
Because tuple elements are lazily evaluated (i.e., only when requested), you can also use this for parameterization. Declare keys without giving them a value, to signal that inheriting tuples should fill these values:
greet = {
greeting;
message = greeting + ' world';
};
hello_world = greet { greeting = 'hello' }
If message
is evaluated, but greeting
happens to not be filled in, an
error will be thrown. To force eager evaluation (to try and catch typos), use
eager()
on a tuple.
Accessing inherited values¶
Normally in a tuple composition, variables that you set are completely replaced
with the new value you’re setting. Sometimes you don’t want this; you may want
to take an existing object or list and add some values to it. In that case, you
can refer to the “original” value (values to the left of the current tuple
inside the composition) by referring to a tuple called base.
. For example:
parent = {
attributes = {
food = 'fast';
speed = 'slow';
}
};
final = parent {
attributes = base.attributes {
speed = 'fast';
}
};
Identifiers¶
Identifiers should start with a letter, may contain the special characters -
and :
, but may not
end in those characters (and because we’re all programmers, _
counts as a letter ;). For
arbitrary identifiers, quote them with ````.
Valid identifiers:
hello
hell0
_hello
hello-world
hello:world
he110-1ord # This is NOT a subtraction
The following identifiers need quoting:
`hello:`
`world-`
`1-1ello`