# Understanding Dusk's code

Dusk's code is not the easiest to read. Before a piece of code can be read, it
has to be properly contextualized and that context is large.

First of all, a solid knowledge of [doc/usage] and [doc/dict] is assumed. You're
supposed to know the basic mechanisms of Dusk (for example, structs and width
modulation).

Then come general patterns in code that only make sense when you're aware of
them. This document can help.

Then, when you want to understand a particular unit, you'll also want to read
documentation about it which is generally in doc/ (not in code comments).

## Patterns in code

@ means "fetch". Its presence in a word indicate that we fetch a value from
somewhere.

! means "store", the opposite of "fetch".

, means "write", that is, storing a value to "here" and increment here by that
value's width.

Those symbols above are sometimes accompanied by letters such as "c" (character)
or "w" (word), which means that instead of being 4 bytes wide (the default
width everywhere), it's 1 or 2 bytes wide.

' means "address of".

. means "print".

_ means "anonymous definitions" that are meant to be used locally and once.

_ as a prefix indicates a private word that is meant to be only used in the
context of the local unit.

? at the beginning of the word means "maybe we'll do it maybe we won't". For
example, "?dup" is meant as "maybe dup".

? at the end of a word indicate a yes/no answer. For example, "ws?" means "is
it a whitespace?".

# means "assert", meaning that an abort will take place in case of failure. For
example, "findpath#" means "try to find specified path and abort if not found".

^ means "opposite order". For now, it's only used in "-^" as a shortcut to
"swap -". Maybe we'll drop this...

[] indicates a range. For example, "[]=" means "compare ranges for equality".

[ as a suffix indicates the beginning of a special interpretation of words. For
example, "foo scratch[" overrides the default scratchpad until "]scratch" is
reached.

] as a prefix indicates the end of a special interpretation loop.

( as a suffix indicates the beginning of a buffer. For example, "in(" is the
address of the first char of the input buffer in sys/rdln.

) as a prefix indicates the end of a buffer, exclusively. For example, ")in c@"
is an out- of bounds fetch. ")in 1- c@" fetches the last char of the buffer.

> has ambiguous meaning. It's generally meant as "movement" or
"transformation". ">r" means "move element from PS to RS" and "[]>str" means
"transform a range into a string".

(words), that is, words inside parens, are "false words", that is, words that
you aren't expected to call directly, but rather to compile in a special
context. For example, calling "(cell)" makes no sense. "(cell)" is compiled by
"create".

## Underscores and namespace pollution

You see more underscores in Dusk than in most Forths, that's because I am being
defensive about namespace pollution. It's true that the way name shadowing works
in Forth makes namespace pollution less of an issue than in some other
languages, but it can still be a tricky issue, the trickiest in my mind is
assumptions about unit loading order.

For example, text/ged will almost always be loaded right after text/ed. But
text/ged uses a lot of words from text/ed. This means that if some other unit in
Dusk shadows something from text/ed that is also used in text/ged, it won't be a
problem... until it is! The rare time where to need to load text/ged later, you
hit that problem and you're stuck.

Sure, it's not a super big deal, you rename and you're done, but those are
"submarine" bugs that compound with each other without being noticed and might
render Dusk fragile in terms of loading order, as a whole. I'd like to avoid
that.

## Understanding a unit

Units are generally accompanied by a documentation page and this is where you'll
have high level information about that code. The code is often commented, but
it's generally for something specific to those few lines of code, not macro
information.

## Understanding drivers

To understand a driver, it is absolutely necessary to understand the target
hardware, otherwise the code is gibberish. This is true not only of Dusk, but of
a whole bunch of operating systems. Don't expect driver code to teach you about
hardware. Dusk doesn't contain this information, you'll have to get this
elsewhere.

## Understanding C/Forth interoperability

One of Dusk's primary goals is to elegantly marry C and Forth, so having C and
Forth together is common in the code. All pieces of C code are wrapped in Forth.
Invoking "cc<<" directly is a bit awkward for the operator, so even the purest
of C unit, for example "foo.c", will not exist alone. It will always be
accompanied by a "foo.fs" unit that takes care of compiling the unit. But more
often than not, that's not the only thing that "foo.fs" will do. It will also
include words that are easier to implement in Forth than in C. If some
structures in C are useful to have in Forth, then that unit will also export
those structures.

## Structure conventions

If you look at how structures are used in Dusk OS, you'll see some patterns
emerge that aren't described in doc/usage. Those are conventions. You don't have
to follow them in your own code, but if you want to interact with Dusk
structures, you need to know about them.

A structure begins with an uppercase letter and a word in a namespace that is
intended to be called from the outside (so, not only methods) begin with a ":".

A structure "constructor" has the name ":new". It is expected to consume
initialization arguments from PS and yield a single element: the address of the
created structure.

Structure allocation is often made directly to "here" (with dynamic allocation
details left to the caller), but not always.

## Understanding xcomp/boot

xcomp/boot.fs is one of the more complex units of Dusk and its trickiest
parts, the beginning, can't be commented because we don't have comments yet.
Here's a walkthrough to that code.

First, the context. When we begin running the payload, all we have is the kernel
and that's quite limited. We don't even have @ and ! yet! We do, however, have
the HAL, which allows us to compile anything. We also have "code", "]" and the
intepret loop. That's enough to get us started!

First comes a whitespace. It's needed for the kernel's "word" to work properly.
See [doc/kernel].

Then, the first task of the payload is to create the SYSVARS word, whose address
lives in PS at boot time. This is why that "i)" there doesn't have an argument:
it's PS top!

"immediate" needs to be implemented in HAL because we need to implement our
first immediate word, "[", before we have the luxury of having ":"!

"[" does a simple thing: setting COMPILING to 0. However, we don't have a
COMPILING constant yet, so we hardcode its SYSVARS offset.

Then comes ":". This is a good lesson for what constitutes a word in Dusk: same
as "code", but wrapped around "pushret," and "popret,". The important difference
with "code" is that it places us in compile mode using "]".

";" has the same constraint as "[", we don't have a COMPILING constant yet.

With all those fancy words implemented, this is beginning to actually look like
a Forth!

Right after that come the "8b", "16b" and ":compiling" implementations, preceded
by their required words. Those implementations are a bit less straightforward
than they would otherwise be because we still lack "@" and "!". Therefore, we
need the HAL.

We then use this nice ":compiling" word right away for basic stack words, thus
making those core words inlining (see [doc/usage/imm]).

Then, we prepare for implementing the "memory" family of words (@, !, etc.).
Before we can get to the meat of it, we need an additional mechanism:
modulablecode.

The problem with the implementation of the memory words is that they're a 6-wide
matrix of functionality. Each of the memory words can be called in 8b, 16b or
32b and each of these possiblities can be ran or compiled. We won't settle for
boring repetition, so we tool ourselves out of this predicament!

This mechanism parametrizes MOD to generate a HAL-compiled word thrice in one
fell swoop. Because MODsz needs "@" at runtime, it intertwined with actual
memory word implementation.

Again, because we're still early in the boot process, we don't have branching at
the Forth level, so we need the HAL and it's a bit awkward. However, it's a
pretty good show of the power of the HAL.

The rest is self-explanatory. The first few words are implemented in a "need
first" basis, but soon enough, critical words have been implemented and we can
begin organizing words in themes.

We try to keep these words to a minimum. Some of these words might appear like
they don't belong in the boot payload. The reason why they're there there is
usually that they're too close to one of the words already there and it's
awkward to but them elsewhere. For example, we might need "0<" and not "0>=",
but do we really want those words not to live close by?
