Quasiliterals¶

Quasiliterals, or QLs, are an important part of Monte syntax which allows us to embed arbitrary DSLs into Monte. With the power of QLs, Monte can be extended into new territory in a very neat way.

What’s a Quasiliteral?¶

This is a quasiliteral:

````Backticks start and end quasiliterals`
```

A quasiliteral can have values mixed into it with `\$`. A value can be a name:

```def name :Str := "Todd"
`Hello, \$name!`
```

A value can also be an expression, using brackets:

````2 + 2 = \${2 + 2}`
```

Quasiliterals can be used as patterns:

```# Equivalent to: def =="self" := "self"
def `self` := "self"
```

Quasiliteral patterns also permit pattern-matching with `@` to retrieve single names:

```def `(@first, @second)` := "(42, 5)"
```

And any pattern can be used with brackets:

```def `x := @{var x}` := "x := 7"
x += "-11" # What? I like slushies!
```

Finally, there are different quasiparsers, or QPs, which each have different behavior:

```# `` makes strings
`def x := 42` :Str
# b`` makes bytestrings
b`def x := 42` :Bytes
# m`` makes Monte AST objects
m`def x := 42` :(astBuilder.getAstGuard())
```

How to Use QLs¶

A quasiliteral expression starts with the name of a quasiparser (which can be empty) followed by a backtick. Then, a mixture of strings and holes are allowed, followed by a final backtick. The holes can either be expression-holes, with `\$`, or pattern-holes, with `@`.

Warning

Pattern-holes cannot be used in QL expressions, only in QL patterns. Using a pattern-hole in a QL expression is a syntax error!

Builtin Quasiparsers¶

There are three common QPs included in Monte’s safe scope.

Simple¶

The simple or empty QP builds strings:

````string` == "string" # true
```

It can mix any value into a string, even values that don’t pass `Str`:

````\${7}` == "7" # true
```

The simple QP does this by calling `M.toString/1` on the values. Correspondingly, the value’s `_printOn/1` is called, and can be customized:

```object shirt { to _printOn(out) { out.print("tye-dye shirt") } }
def description :Str := `I am wearing a \$shirt.`
```

When used as a pattern, the simple QP performs very simple but straightforward and powerful string parsing:

```def container := "glass"
def `a \$container of @drink` := "a glass of lemonade"
```

Bytes¶

The bytes QP builds bytestrings:

```b`asdf`
```

The encoding of characters is unconditionally Latin-1. Non-Latin-1 characters cause errors to be thrown at runtime:

```b`ErrorRaiser™`
```

Other than that quirk, the bytes QP behaves much like the simple QP, including parsing:

```def b`@header:@value` := b`x:12`
```

Monte¶

Finally, the Monte QP builds Monte ASTs from literal Monte source:

```m`def x := 42`
```

The Monte QP can be used for code generation, since it evaluates to objects usable with `eval/2`:

```eval(m`2 + 2`, [].asMap())
```

Custom Quasiparsers¶

Anybody can write their own quasiparser.

Parsing with Values¶

The first half of the QP API deals with building the initial structure and including values.

`.valueHole(index :Int)` should create a value marker which can be used in place of some value which will be included later. ```.valueMaker(pieces :List)``` will be called with a list of pieces, which can be either strings or value markers, and it should return a partial structure. That structure can be completed with its `.substitute(values :List)`, which provides a list of values that can be swapped with the value markers.

To see how this API all comes together, let’s look at the kernel expansion of a simple QP call:

````Just another \$day for this humble \$string.`
```

What Monte actually does is call `.valueMaker/1`, like so:

```::"``".valueMaker(["Just another ", ::"``".valueHole(0),
" for this humble ", ::"``".valueHole(1),
"."]).substitute([day, string])
```

Parsing Patterns¶

The pattern API is similar and builds upon the expression API.

First, the `.patternHole/1` method allows pattern hole markers to be built, just like with value holes. Then, the structure is built with `.matchMaker/1` instead of `.valueMaker/1`. This structure should have a completion method, `.matchBind(values :List, specimen, ej)` which attempts to unify the specimen with the structure completed by the values or eject on failure.

Here’s a simple pattern:

```def `how \${hard} could it be to match @this?` := "not hard, just complex"
```

And its expansion:

```def via (_quasiMatcher.run(::"``".matchMaker(["how ", ::"``".valueHole(0),
" could it be to match ",
::"``".patternHole(0),
"?"]),
[hard])) [this] := "not hard, just complex"
```

Note how the `_quasiMatcher` helper in the safe scope takes care of the extra runtime plumbing.