Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quote Syntax. #79

Open
cowboyd opened this issue Feb 13, 2023 · 1 comment
Open

Quote Syntax. #79

cowboyd opened this issue Feb 13, 2023 · 1 comment

Comments

@cowboyd
Copy link
Member

cowboyd commented Feb 13, 2023

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: User

To 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: $spec

parameterized 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: $spec

other?

What are other possibilities to tell PS to just read the value, and not interpret it?

Learning

@taras
Copy link
Member

taras commented Feb 13, 2023

This sounds great to me.

It would be very useful to have a mapping primitive to quote an import, apply a map to every key with $ref and transform the value.

cowboyd added a commit that referenced this issue Feb 14, 2023
Implement the quote system for imports documented in
#79
cowboyd added a commit that referenced this issue Feb 14, 2023
Implement the quote system for imports documented in
#79
cowboyd added a commit that referenced this issue Feb 14, 2023
Implement the quote system for imports documented in
#79
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants