Layout
The layout rules describe how indentation works.
Rules
- After a
do
,match
, orwhen
, emit a{
if one is not present and push the indentation of the next token onto the stack. - If a line starts at the same indentation as the top of the indentation stack
and the previous token was not a
;
, then emit a;
. - If a line starts at a smaller indentation than the top of the indentation
stack, then pop indentations off the stack until the current indentation is
seen, and emit one
}
for each pop minus the number of}
that were seen. - If a line starts at a greater indentation than the top of the stack, then do nothing.
Any emitted {
or }
has the current indentation attached to it. When {
and }
are inserted by the programmer, the layout rule is disabled within
these braces if they are the topmost braces on the indentation stack. In this
case, all ;
must be manually inserted.
The layout rules do not attempt to solve all possible layouts. They only work for layouts that are considered "well-formed."
As a general rule of thumb, if you write code that requires manual insertion of
a ;
in the middle of a line, then the layout rules are not guaranteed to work.
Tabs are not allowed
Tabs and spaces present challenges for whitespace-sensitive languages. Which do you use? Are both allowed? Can they be mixed? How wide is a tab? Different languages answer this question in different ways.
It is simple in Fuyu: literal tabs are not allowed in a Fuyu source text.
The reasoning is that literal tabs are not allowed anywhere that they may affect indentation. The emphasis is on may because even tabs that are not at the start of a line or are inside of string literals have the potential to affect indentation! For these reasons, tabs are completely disallowed, and the age-old tab versus spaces debate does not exist in Fuyu.
Example
For example, consider the following program.
import a/b/c for
a, b,
c
type Maybe a =
Yes a,
No
first_yes:
Maybe a ->
Maybe a ->
Maybe a ->
Maybe a
first_yes (Yes x) _ _ = Yes x
first_yes _ (Yes x) _ = Yes x
first_yes _ _ (Yes x) = Yes x
first_yes _ _ _ = No
last_yes: Maybe a -> Maybe a -> Maybe a -> Maybe a
last_yes
_ _ x = x match
(Yes z) -> Yes z
_ -> No
last_yes _ x _ = x match (Yes z) -> Yes z; _ -> No
last_yes x _ _ = x match (Yes z) -> Yes z
_ -> No
last_yes _ _ _ = No
Following the rules, the following {
, }
, and ;
are emitted.
import a/b/c for
a, b,
c;
type Maybe a =
Yes a,
No;
first_yes:
Maybe a ->
Maybe a ->
Maybe a ->
Maybe a;
first_yes (Yes x) _ _ = Yes x;
first_yes _ (Yes x) _ = Yes x;
first_yes _ _ (Yes x) = Yes x;
first_yes _ _ _ = No;
last_yes: Maybe a -> Maybe a -> Maybe a -> Maybe a;
last_yes
_ _ x = x match
{(Yes z) -> Yes z;
_ -> No;
};
last_yes _ x _ = x match {(Yes z) -> Yes z; _ -> No
};
last_yes x _ _ = x match {(Yes z) -> Yes z;
_ -> No;
};
last_yes _ _ _ = No;