Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Symfony Expression: Parse without context #50105

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

Closed
homersimpsons opened this issue Apr 21, 2023 · 2 comments
Closed

Symfony Expression: Parse without context #50105

homersimpsons opened this issue Apr 21, 2023 · 2 comments

Comments

@homersimpsons
Copy link
Contributor

Description

Current parse function requires full context to complete successfully. It needs to know about declared functions and names.

I would like to be able to parse the nodes without those details. I have 2 use case for this:

  • Execute the expression in another engine such a JavaScript directly in the browser
  • Validate certain properties for a given expression, for instance that is_granted() receives 2 arguments

From my understanding, the parser need to be updated to avoid throwing on the following lines:

https://github.com/symfony/expression-language/blob/83e1fee4c018aa60bcbbecd585a2c54af6aca905/Parser.php#L228-L249

Alternatively it could be possible to code my own parser based on the existing one, but it cannot be overridden:

https://github.com/symfony/expression-language/blob/83e1fee4c018aa60bcbbecd585a2c54af6aca905/ExpressionLanguage.php#L150

Implementation

About the implementation, I guess that a parseWithoutContext(TokenStream $stream) function could be the easier, it would just update an internal flag such as the current lint flag and will use this flag during function / name resolution.

Example

The following code would then be valid and its results could be used to construct what I want to achieve.

$parsed = (new ExpressionLanguage())->parseWithoutContext('is_granted("ROLE_EDIT", subject)');
//^ Symfony\Component\ExpressionLanguage\ParsedExpression {#1213 ▼
//    #expression: "is_granted("ROLE_EDIT", subject)"
//    -nodes: Symfony\Component\ExpressionLanguage\Node\FunctionNode {#1214 ▼
//        +nodes: array:1 [▼
//      "arguments" => Symfony\Component\ExpressionLanguage\Node\Node {#1217 ▼
//            +nodes: array:2 [▼
//          0 => Symfony\Component\ExpressionLanguage\Node\ConstantNode {#1215 ▼
//                +nodes: []
//                +attributes: array:1 [▼
//              "value" => "ROLE_EDIT"
//            ]
//            -isIdentifier: false
//          }
//          1 => Symfony\Component\ExpressionLanguage\Node\NameNode {#1216 ▼
//                +nodes: []
//                +attributes: array:1 [▼
//              "name" => "subject"
//            ]
//          }
//        ]
//        +attributes: []
//      }
//    ]
//    +attributes: array:1 [▼
//      "name" => "is_granted"
//    ]
//  }
//}

// Analyze the above output as an AST
// Dump the above output to evaluate it somewhere else
@homersimpsons
Copy link
Contributor Author

homersimpsons commented Sep 4, 2023

For the record, this is my function to be able to parse without giving names context. This can be extended to create a simple "variable extractor" that can fetch variable values from another source:

use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\ExpressionLanguage\ParsedExpression;
use Symfony\Component\ExpressionLanguage\SyntaxError;

use function preg_match;

private function parseExpressionWithoutContext(string $expression): ParsedExpression
{
    $expressionLanguage = new ExpressionLanguage();
    $names = [];

    while (true) {
        try {
            return $expressionLanguage->parse($expression, $names);
        } catch (SyntaxError $e) {
            $matches = [];
            if (! preg_match('/^Variable "(?<variable>[^"]+)" is not valid/', $e->getMessage(), $matches)) {
                throw $e;
            }

            $names[] = $matches['variable'];
        }
    }
}

@homersimpsons
Copy link
Contributor Author

Fixed by #53806

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

Successfully merging a pull request may close this issue.

2 participants