Next: Poking Structs, Previous: Defining Types, Up: Structuring Data [Contents][Index]
In Nomenclature we mentioned that poke, the program, implements a domain specific programming language called Poke, with a big p. In the examples so far we have already used the Poke language, somewhat extensively, while interacting with the program using the REPL.
For example, in:
(poke) 10 + 2 12
We are giving poke a Poke expression 10 + 2
to be
evaluated. Once the expression is evaluated, the REPL prints the
resulting value for us.
Similarly, when we define a variable or a type with var
and
type
respectively, we are providing poke definitions to be
evaluated. When we assign a value to a variable we are actually
providing a Poke statement to be executed.
So the REPL accepts poke commands, some of which happen to be
Poke expressions, definitions or statements. But we also have used
dot-commands like .file
or .info
. These dot-commands
are not part of the Poke programming language.
Every time we insert a line in the REPL and hit enter, poke recognizes the nature of the line, and then does the right thing. If the line is recognized as a Poke expression, for example, the Poke compiler is used to compile the statement into a routine, that is executed by the Poke Virtual Machine. The resulting value is then printed for the benefit of the user.
Poke programs are basically a collection of definitions and statements, which most often than not are stored in files, which avoids the need to type them again and again. By convention, we use the .pk file extension when naming files containing Poke programs.
Remember how we defined the foreground and background pixels for
p.sbm
in the REPL?
(poke) var bga = [255UB, 255UB, 255UB] (poke) var fga = [255UB, 99UB, 71UB]
Where bga
is a white pixel and fga
is a tomato colored
pixel. We could write these definitions in a file colors.pk
like this:
var white = [255UB, 255UB, 255UB]; var tomato = [255UB, 99UB, 71UB];
Note that variable definitions in Poke are terminated by a semicolon
(;
) character, but we didn’t need to specify them when we
issued the definitions in the REPL. This is because poke adds the
trailing semicolon for us when it detects a Poke construction
requiring it is introduced in the REPL.
Another difference is that Poke constructions can span for multiple lines, like in most programming languages. For example, we could have the following variable definition in a file:
var matrix = [[10, 20, 30], [40, 50, 60], [70, 80, 90]];
Once we have written our colors.pk file, how can we make poke
aware of it? A possibility is to use the load
construction:
(poke) load colors
Assuming a file named colors.pk exists in the current working directory, poke will load it and evaluate its contents. After this, we can use the colors:
(poke) tomato [0xffUB,0x63UB,0x47UB]
Before, we would need to define these colors every time we would like to poke SBM files or, in fact, any RGB24 data. Now we just have to load the file colors.pk and use the variables defined there.
If you try to load a file whose name contains a dash character
(-
) you will get an error message:
(poke) load my-colors <stdin>:1:8: error: syntax error, unexpected '-', expecting ';' load my-colors; ^
This is because the argument to load
is interpreted as a Poke
identifier, and dash characters are not allowed in identifiers. To
alleviate this problem, you can also specify the name of the file to
load encoded in a string, line in:
(poke) load "my-colors.pk"
If you use this form of load
, however, you are required to
specify the complete name of the file, including the .pk file
extension.
Since loading files is such a common operation, poke provides a
dot-command .load
that does auto-completion:
(poke) .load my-colors.pk
Which is equivalent to load "my-colors.pk"
.
Since load
is part of the Poke language, it can also be used in
Poke programs stored in files. We will explore this later.
In the last section we defined a couple of RGB colors white
and
tomato
in a file called colors.pk. If we keep adding
colors to the file, we may end with a nice collection of colors that
are available to us at any time, by just loading the file.
Since there are many ways to understand the notion of “color”, and also many ways to implement these many notions, it would be better to be more precise and call our file rgb24.pk, since the notion of color we are using is of that RGB24. While are at it, let’s also rename the variables to reflect the fact they denote not just any kind of colors, but RGB24 colors:
var rgb24_white = [255UB, 255UB, 255UB]; var rgb24_tomato = [255UB, 99UB, 71UB];
At this point, we can also add the definitions of a couple of types to our rgb24.pk:
type RGB_Color_Beam = byte; type RGB24_Color = RGB_Color_Beam[3]; var rgb24_white = [255UB, 255UB, 255UB]; var rgb24_tomato = [255UB, 99UB, 71UB];
Any time we want to manipulate RGB24 colors we can just load the file rgb24.pk and use these types and variables.
In poke parlance we call files like the above, that contain definitions of conceptually related entities, pickles. Pickles can be very simple, like the rgb24.pk sketched above, or fairly complicated like dwarf.pk.
It is common for pickles to load
other pickles. For example,
if we were to write a SBM pickle, we would load the RGB24 pickle from
it:
load rgb24; [… SBM definitions …]
This way, when we load sbm
from the repl, the dependencies
get loaded as well.
GNU poke includes several already written pickles for commonly used
file formats, and other domains. The load
construction knows
where these pickles are installed, so in order to load the pickle to
manipulate ELF files, for example, all you have to do is to:
(poke) load elf
When poke starts it loads the file .pokerc located in our home directory, if it exists. This initialization file contains poke commands, one per line.
If we wanted to get some Poke file loaded at startup, we could do it
by adding a load command to our .pokerc
. For example:
# My poke configuration - jemarch […] .load ~/.poke.d/mydefs.pk
Next: Poking Structs, Previous: Defining Types, Up: Structuring Data [Contents][Index]