Making YS be Valid YAML
I'll say it again. All YS syntax is 100% YAML. The YS compiler uses a third party YAML parser so there is no way that YS code cannot be YAML.
YS code also uses a lot of Clojure syntax. This makes sense since the code gets compiled to Clojure in the end.
Some Clojure code looks a lot like YAML but with subtle differences.
Today we'll talk about the little gotchas that can trip you up when you're writing YS code, and how to work around them.
YS +
escaping🔗
The *
operator is polymorphic.
If you "multiply" a string by a number, it will repeat the string that many
times.
$ ys -e 'say: "X" * 3'
Compile error: while scanning an alias
in reader, line 2, column 10:
say: "X" * 3
^
That didn't go as expected. What happened?
Well, that is simply not valid YAML. You can't have extra text after the end of a quoted string (except for comments).
We want the value of the key say
to be a YS expression, which means that it
needs to be a YAML plain (unquoted) scalar.
Plain scalars can't start with a YAML syntax character like #%[{'"!&*|>
.
One way to get around this particular case is to use parens. Plain scalars can start with a paren.
$ ys -e 'say: ("X" * 3)'
XXX
A more general way is to use the +
YS escape character.
$ ys -e 'say: +"X" * 3'
XXX
The +
makes the value be a valid YAML plain scalar.
YS will then ignore a +
that precedes a YAML syntax character.
You can have whitespace after the +
, so this is valid:
$ ys -e '
say: +
"X" * 3'
XXX
Map and Vector Literals🔗
How about this?
$ ys -mc -Ye '=>: {a: 1, b: 2}'
Compile error: Flow mappings not allowed in code mode
The -mc
flag tells YS to start in code mode.
This is the default for -e
but we use it here to make it clear.
YS does not allow YAML flow mappings or flow sequences in code mode.
We can use the +
escape character to get around this:
$ ys -mc -Ye '=>: +{a: 1, b: 2}'
Compile error: mapping values are not allowed here
in reader, line 2, column 8:
=>: +{a: 1, b: 2}
Oops! What happened now?
Well, the +
makes this a YAML plain scalar, but YAML plain scalars can't have
:
in them.
Also this is not the correct way to express a map literal in YS or Clojure. It's close, but:
- No
:
is used - Strings need to be quoted
- Commas are optional whitespace
Let's try again:
$ ys -mc -Ye '=>: +{"a" 1, "b" 2}'
a: 1
b: 2
There we go.
We could also have switched to data mode for the value, which has to allow YAML flow mappings and sequences.
$ ys -mc -Ye '=>:: {a: 1, b: 2}'
a: 1
b: 2
Sometimes normal YAML syntax (via data mode) is the best way to go.
We could even use a YAML block mapping here instead:
$ ys -mc -Ye '=>::
a: 1
b: 2'
a: 1
b: 2
There are more gotchas to talk about, but I'll save them for another time.
If you come across gotchas of your own, please share them in the comments!