# Macros and conditionals

[Start here](https://pegmatite.dev/guide/start.md). Fetch this topic when a script repeats a feature with different sizes, names a shape, or builds something only when a test holds.

## Macros

**Syntax:** **`def`** _%name_ [_$parameter_ …] _body_

A macro is a named compound solid or a named 2D shape. The `%` is part of the name in the definition and every call; `%cube` is valid. Arguments follow the name without parentheses or separators, and the next command ends the call. They are numbers, variables, negated values such as `-$size`, or parenthesized expressions. The count must match the definition. A macro with no parameters is called by its name alone.

```pegm
def %pillar $size $height {
  block $size $size $height
}

set $size 10
%pillar $size (5 * $size)
```

### Braceless bodies

A body of one statement needs no braces. Setters, the solid, its whole pipeline and an `on` in front of it belong to it, so `def %pin on #front color red cylinder 4 10 | rotate 90 about x` is one body, as a [pattern](https://pegmatite.dev/guide/patterns.md) body is. The next statement is the script's own, whatever the indentation. Use braces for two solids or more.

```pegm
def %b block 10 20 30

%b
@right color red %b
```

### Shape macros

A body can be a [2D shape](https://pegmatite.dev/guide/shapes.md). The macro names that shape, and a call stands wherever a shape is expected: before a sweep, as its profile, or as the shape a sweep takes as an argument.

```pegm
def %slot $width rect $width 10

%slot 20 | extrude 4
@right 5 %slot 30 | extrude 4
```

- A shape body is one shape, braced only when it is a [group](https://pegmatite.dev/guide/shape-operations.md), and may end with 2D modifiers, turns, flips and scales.
- A body that only calls a shape macro is a shape too: `def %wide %slot 40`, `def %lip %slot 40 | offset -1`. A body that sweeps its shape, `def %plate rect 40 30 | extrude 2`, is a solid.
- Settings are read where the shape is used, so a `text` shape takes the `font-size` in force where it is swept.
- Called before a sweep with one argument too few, a shape macro is a [varying profile](https://pegmatite.dev/guide/sweeps.md): the sweep supplies the last argument.
- Called as a statement of its own, a shape macro is a [sketch](https://pegmatite.dev/guide/shapes.md), drawn and not built.

A solid macro cannot stand where a shape is expected:

```pegm
/* Expected error: macro %block is a solid, a shape is expected here. */
def %block cube 10
%block | extrude 2
```

### Define before use

A definition stands among the root statements, wherever it reads best, never inside braces, a list or a branch of an `if`. A name is defined once; a second definition is an error.

A macro is known from its definition on. A statement calls macros defined above it, and a body may call any macro whose definition has been reached when the call runs, so two macros can call each other if both are defined before the first call.

```pegm
def %up $n {
  if $n > 0 {
    cube 4
    on #top %down ($n - 1)
  }
}

def %down $n {
  if $n > 0 {
    cylinder 4 4
    on #top %up ($n - 1)
  }
}

%up 4
```

```pegm
/* Expected error: Macro %base is defined on line 3, below this call. */
%base
def %base block 40 40 4
```

An unknown bare command is an error with a spelling suggestion:

```pegm
/* Expected error: unknown command "cilinder", did you mean "cylinder"? */
cilinder 20 10
```

### Macros are compounds

A call is placed, anchored and snapped onto as one solid, like a `{ … }` [compound](https://pegmatite.dev/guide/start.md#compounds-and-parts). Placement setters apply to the call as a whole, and appearance settings are inherited. The body is an isolated context: a list inside it closes inside it, and `on root` returns to the macro's own ground plane.

```pegm
def %tower $height {
  block 12 12 4
  on #top cylinder 6 $height
}

block 60 60 6
on #top
color red
x left %tower 14
```

### Variables

A body sees its parameters and the variables set above its definition, with their values at definition time. Later assignments and the caller's variables do not change them. A parameter of the same name stands over the variable. A `set` in the body does not escape.

```pegm
set $size 10
def %peg {
  cylinder 4 $size
}

%peg
set $size 20
on #top %peg   // still 10 high
```

```pegm
/* Expected error: Undefined variable: $size, a macro sees the variables set above its definition and its parameters. */
def %peg {
  cylinder 4 $size
}

set $size 10
%peg
```

### Recursion

A macro may call itself while a test stops it. Each call is a compound placed by the caller. More than 64 nested calls is an error.

```pegm
def %stack $n {
  cube $n
  if $n > 1 %stack ($n - 1)
}

%stack 4   // cubes 4, 3, 2, 1, each on the one before
```

## Conditionals

**Syntax:** **`if`** _test_ _body_ [**`else`** _body_]

`if` builds one branch. With no `else` and a false test it does nothing.

### The test

A bare test compares two arguments, each a number, variable, measure, call, text or parenthesized expression. Parenthesize arithmetic arguments: `if ($n + 1) > 2 …`, not `if $n + 1 > 2 …`. A test of several comparisons goes in parentheses with `and`, `or` and `not`, as in a [choice](https://pegmatite.dev/guide/expressions.md).

```pegm
set $width 60
set $holes 1
block $width 40 4
if ($width > 50 and $holes == 1) @center -cylinder 6 4
```

### Branches

Each branch is one statement with any `on` in front of it. A list `[ … ]` builds several statements from the same reference, and a boolean in it still reaches what was built before the `if`, which suits optional ears, bosses and holes. A compound `{ … }` builds one isolated volume.

```pegm
def %case $ears {
  block 40 30 20
  if $ears == 1 [
    on #left block 10 30 3
    on #right block 10 30 3
  ]
}

%case 1
```

An `if` is a statement, so `else if` chains:

```pegm
set $mount "flange"
block 40 30 20
if $mount == "ears" on #left block 10 30 3
else if $mount == "flange" on #bottom @center block 60 50 3
else on #bottom @center -cylinder 10 5
```

An `else` belongs to the nearest `if` that can still take one: in `if $a == 1 if $b == 1 cube 4 else cube 2` it is the inner one's. To give it to the outer one, invert the test, `if $a != 1 cube 2 else if $b == 1 cube 4`, or give the inner `if` its own `else`.

### What an if leaves behind

An `if` is no volume, so it opens no scope and keeps no slot.

- The next statement is placed against what the branch left: the volume a solid built, the box a pattern left, or after a list the reference the list opened from.
- With no branch picked, it is placed against what the `if` followed, as after `repeat 0`.
- A `set` or label in a branch is visible after it.
- To leave a reference whatever the test picks, write one in an `else`, such as `else slot block 40 40 0`.

```pegm
set $lid 0
block 40 40 20
if $lid == 1 block 40 40 3
cylinder 10 5   // on the lid if there is one, else on the box
```

One-shot setters before an `if` bind to the branch it picks. With no branch picked they bind to nothing, and the next solid is placed without them:

```pegm
set $ears 0
cube 20
@right 5 if $ears == 1 block 10 20 3
@right cube 4   // against the cube, with no gap
```
