-
Notifications
You must be signed in to change notification settings - Fork 2
Description
There are some cases where you want to have PlatformScript not evaluate a data structure. Consider the following snippet of Open API specification
responses:
'200':
description: The response
schema:
$ref: '#/components/schemas/User'How would we represent this as data in PlatformScript so that we could do things like make it the return value of a function? We cannot do it currently because evaluating the following function:
createResponses():
responses:
'200':
description: The response
schema:
$ref: '#/components/schemas/User'would raise a ReferenceError: $ref is not defined. This is because normal PlatformScript evaluation rules would dictate that the mapping$ref: '#/components/schemas/Users' is a call to a function named ref passing the string argument '#/components/schemas/Users'.
We need some way to say "don't evaluate stuff", just read it as a raw PlatformScript values, and return it.
Following LISP implementations, the answer is to have a quote form that evaluates to the raw argument. It is represented as a single quote operator '. Thus the expression (sum 1 2 3) evaluates to 6, but the expression '(sum 1 2 3) evaluates to a list containing the symbol sum and the integers 1, 2, and 3.
We can replicate this with our own ' function, so that the createResponses function would be represented as:
createResponses():
$':
responses:
'200':
description: The response
schema:
$ref: '#/components/schemas/User'But this is not the end of the story. What if we want to transform this response and actually say that some parts of the data structure should be evaluated, but others should be left alone. To see why, let's consider our createResponses() function again. It's doubtful that it would be useful in this form because we are hard-coding all of the structure, but in reality, we would want to do things like parameterize the description and entity name so that we could call it like:
$createResponses:
description: find a user by id
entityName: UserTo make this happen, we'd want to define the function with a variable substitution:
createResponses(options):
$':
responses:
'200':
description: $options.description
schema:
$ref: '#/components/schemas/%($options.entityName)'but this won't work because we told PlatformScript not to evaluate anything! Again, this is well trodden territory when it comes to LISP. It has the mechanisms of quasiquote and unquote. And it uses the ` and , symbols.
So, `(sum 1 ,(sum 1 1) 3) would evaluate to a list with the symbol sum followed by the integers 1, 2, and 3 because the ,(sum 1 1) tells the interpreter to evaluate the result of this and plug it back into the tree.
By the same token, we can introduce a quasi quote function ` and an unquote function , that can be used to turn on / turn off evaluation in PlatformScript. Our createResponses function could then look like.
createResponses(options):
$`:
responses:
'200':
description: {$,: $options.description}
schema:
$ref: {$,: '#/components/schemas/%($options.entityName)' }the quasi-quote and unquote functionality from LISP is equivalent to JavaScript String templating's `` and ${} except instead of producing strings, it produces syntax trees. As such, this syntax can (and will) be used for macros.
Importing Quoted data
What if you have a file on disk or a open api spec that is sitting at a URL that you would like to work with like https://example.com/open-api-spec.yaml? we'd like to be able to just say: "import this as a module, but don't bother interpreting it because I'm going to be transforming it for some purpose" What would that look like? Here are some possibilities:
separate import
This has a separate function $import' (import quoted) for importing modules as quoted PlatformScript.
$import:
transform: https://pls.pub/x/open-api-gen.yaml
$import':
spec<<: https://example.com/open-api-spec.yaml
$transform: $specparameterized module spec:
Currently, the value of a module mapping is a string corresponding to a url, but this proposal would allow it to be parameterized in order to pass additional attributes describing how the module is to be loaded. In this case, we would add a "quote" option to tell platformscript to just load the module.
$import:
transform: https://pls.pub/x/open-api-gen.yaml
spec<<:
url: https://example.com/open-api-spec.yaml
quote: true
$transform: $specother?
What are other possibilities to tell PS to just read the value, and not interpret it?
Learning
- concise writeup of quoting and quasi quoting in scheme https://courses.cs.washington.edu/courses/cse341/04wi/lectures/14-scheme-quote.html
- More involved examples of quoting and quasi quoting in Racket https://docs.racket-lang.org/guide/qq.html