Skip to content

Instantly share code, notes, and snippets.

@richardbuckle
Last active January 17, 2020 22:43
Show Gist options
  • Save richardbuckle/ccc3cf78315074b39e4be83bf67dbb8a to your computer and use it in GitHub Desktop.
Save richardbuckle/ccc3cf78315074b39e4be83bf67dbb8a to your computer and use it in GitHub Desktop.

About Cottle templates in function arguments

I think I've got to the bottom of why EDDI is highlighting e.g. line 90 of the "Bodies to map" script in v3.5.2.

No built-in Cottle functions reparse their arguments

There is no equivalent of eval() in Cottle as far as I can see. That may well have been a conscious decision: I do not know. Anyhow, all arguments passed to functions are just inert strings and are not subject to further parsing by Cottle.

Proof: if I feed this to the demo app in the Cottle project:

{set mappedBodies to 1}
{set totalBodies to 5}
{if 1:
    {cat(
        "You have mapped all {if mappedBodies < totalBodies: {cat(\"worthwhile\", \"interesting\")}} bodies.",
        "All {cat( \"{if mappedBodies < totalBodies: worthwhile} bodies\", \"bodies of interest\" )} {cat( \"have been mapped.\", \"are now mapped.\" )}"
    )}
}

then I get this (white space elided):

You have mapped all {if mappedBodies < totalBodies: {cat("worthwhile", "interesting")}} bodies.All {cat( "{if mappedBodies < totalBodies: worthwhile} bodies", "bodies of interest" )} {cat( "have been mapped.", "are now mapped." )}

Custom functions don't reparse their arguments either

It doesn't matter whether the function is declared in Cottle or in C#, by default they all behave as above.

Example:

{set mappedBodies to 1}
{set totalBodies to 5}
{set MyCat(a, b) to :
   {echo a}¬{echo b}
}
{MyCat(
    "You have mapped all {if mappedBodies < totalBodies: {MyCat(\"worthwhile\", \"interesting\")}} bodies.",
    ""
)}
{MyCat(
    "All {MyCat( \"{if mappedBodies < totalBodies: worthwhile} bodies\", \"bodies of interest\" )} {MyCat( \"have been mapped.\", \"are now mapped.\" )}",
    ""
)}

produces this (white space elided):

   You have mapped all {if mappedBodies < totalBodies: {MyCat("worthwhile", "interesting")}} bodies.¬
   All {MyCat( "{if mappedBodies < totalBodies: worthwhile} bodies", "bodies of interest" )} {MyCat( "have been mapped.", "are now mapped." )}¬

What is different about the custom EDDI functions?

Short answer: the functions OneOf(), Occasionally() and Transmit() call EddiSpeechResponder.ScriptResolver.resolveScript() on their script arguments, and it's reasonably likely that we will want add similar functions that do the same.

Note again that Cottle has no eval(), nor a parameter type for an evaluable script. That might be a security decision.

Why is the text in question being highlighted?

Let's recap line 90:

        "All {OneOf( \"{if mappedBodies < totalBodies: worthwhile} bodies\", \"bodies of interest\" )} {OneOf( \"have been mapped.\", \"are now mapped.\" )}"

The XSHD grammar as it stands treats string literals within the params of the first OneOf()on line 90 as body text, that is, a mini Cottle template wherein{ will kick us back into into code mode. On reflection is is not generally correct because as discussed above, params are not usually reparsed as miniature Cottle templates except for the custom EDDI functions noted above.

Anyhow, the escaped opening double quote before {if mappedBodies is preventing the grammar from going into "string literal", which in turn is stopping it from perceiving the very next opening brace as the start of a code block.

Options

  1. Go hardcore and neuter all reparsing of string function arguments. While strictly correct, I don't like it because it would neuter syntax coloring of most of our script corpus.
  2. Keep the current XSHD, which is 99% good, and alternate double and single quote nesting within scripts to dodge the false positive highlighting. This is my preferred option at the time of writing.
  3. Enhance the grammar to express which functions reparse their string inputs and customize parsing of those few functions. That's (a) fragile and (b) extra busy-work that I'm not much up for.
  4. Something I haven't thought of yet. Thoughts welcomed!

Thoughts please!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment