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

Support for runtime context object? #666

Open
cleverplatypus opened this issue Apr 12, 2021 · 3 comments
Open

Support for runtime context object? #666

cleverplatypus opened this issue Apr 12, 2021 · 3 comments

Comments

@cleverplatypus
Copy link

cleverplatypus commented Apr 12, 2021

Issue type

  • Bug Report:
  • Feature Request:
  • Question: yes
  • Not an issue:

Prerequisites

  • Can you reproduce the issue?: yes
  • Did you search the repository issues?: yes
  • Did you check the forums?: yes
  • Did you perform a web search (google, yahoo, etc)?: yes

Description

Is there any reason that context data can only be set at compile time?
I see many situations where the compiled grammar would need to access a context that changes at runtime.
Compiling the grammar for every use case doesn't seem to be a viable solution.

Unless I'm missing something....

Example code:

I'm using PEG for a decorator in ExpressJS that controls access to endpoints:

@Auth('role(admin) || adgroup(ACME_Developer)')
myEndpointMethod() {
}

The grammar relies on a profile variable that is supposed to contain the current user's profile containing roles and adgroups.
The profile is only available when the endpoint is hit.
I'd expect the compiled grammar to work something like this:

const isAuthorised = myAuthGrammar.parse('role(admin) || adgroup(ACME_Developer)', {
    profile : {
          roles : ['tester'],
          adgroups : ['ACME_Tester']
    }
});

Software

  • PEG.js:
@hildjj
Copy link

hildjj commented Apr 12, 2021

This might be a good place for a & {predicate} block. Parse a token with something like $[a-z_]i+, then check it in a list of valid tokens in the predicate. Here is an intentionally-simplified example (no paren grouping) that parses your inputs and rejects invalid roles/adgroups:

'use strict'

const pegjs = require('pegjs')

const src = `
authorized
  = perm:perm rest:(_ o:op _ p:perm { return [o, p]})* { rest.unshift(perm); return rest }

perm = pn:permname _ "(" _ n:name & { return options[pn].includes(n) } _")" {
  return { [pn]: n }
}

permname
  = "role"i { return "roles" }
  / "adgroup"i { return "adgroups" }

name = $[a-z_]i+

op
  = $"||"
  / $"&&"

_ = $[ \t]*
`
const parser = pegjs.generate(src)

for (const a of process.argv.slice(2)) {
  console.log(parser.parse(a, {
    roles: ['admin'],
    adgroups: ['ACME_Developer']
  }))
}

@cleverplatypus
Copy link
Author

Thanks @hildjj.

Are you saying that the options object is available in the grammar and it contains whatever I pass in as a second parameter of parser.parse()?

That's not clear from the docs. Is it a "hack" or is it going to be working in future versions of PEG?

I ended up creating a grammar that outputs and AST that then is interpreted by my code.

{
   "any": [
      {
         "all": [
            {
               "adgroup": "ACME_Developer"
            },
            {
               "role": "admin"
            }
         ]
      },
      {
         "adgroup": "supergod"
      }
   ]
}

@hildjj
Copy link

hildjj commented Apr 13, 2021

Yes, the docs are a little unclear about this, but it's supported behavior. I'll create a bug on peggyjs/peggy to improve the docs.

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