Αναλυτής
Το Phasis εκθέτει τον αναλυτή JavaScript ως αυτόνομο PHP API. Μπορείτε να αναλύσετε πηγαίο κείμενο σε τυποποιημένο AST, να το διασχίσετε και να το εξαγάγετε ως πίνακες σε μορφή ESTree ή ως JSON, χωρίς να δημιουργήσετε Engine ή να εκτελέσετε οτιδήποτε.
parseSource
public static function parseSource(string $source, string $sourceType = 'script'): Program
Το σημείο εισόδου μιας κλήσης στο Phasis\Parser\Parser. Αναλύει το $source και επιστρέφει τον ριζικό κόμβο Phasis\Ast\Program.
use Phasis\Parser\Parser;
$program = Parser::parseSource('const x = [1, 2].map(n => n * 2);');
$module = Parser::parseSource('import { x } from "./x.js"; export default x;', 'module');
Το $sourceType επιλέγει τον στόχο γραμματικής, με όνομα ίδιο με την αντίστοιχη επιλογή στους αναλυτές JS:
| Τιμή | Στόχος |
|---|---|
script |
κλασικό Script. Τα import/export στο ανώτατο επίπεδο είναι συντακτικά σφάλματα· το await είναι αναγνωριστικό |
module |
ES Module. Σε αυστηρή λειτουργία εξ ορισμού· αναλύονται τα import/export και τα await στο ανώτατο επίπεδο |
Κάθε άλλη τιμή προκαλεί \InvalidArgumentException.
Για πιο λεπτομερή έλεγχο (ενεργοποίηση της αυστηρής λειτουργίας εκ των προτέρων για περιβάλλον άμεσης αξιολόγησης, ανάγνωση της οδηγίας //# sourceURL), κατασκευάστε απευθείας τον αναλυτή: new Parser($source) μαζί με τα setModuleMode(), setStrictMode() και parse().
Κόμβοι
Κάθε κλάση AST επεκτείνει το Phasis\Ast\Node και βρίσκεται κάτω από το Phasis\Ast\{Declaration, Expression, Pattern, Statement}. Οι κόμβοι είναι απλά αντικείμενα τιμών μόνο για ανάγνωση:
- Το
$node->type()επιστρέφει τη συμβολοσειρά τύπου του κόμβου, δηλαδή το βασικό όνομα της κλάσης ('BinaryExpression','ArrowFunction', ...). - Το
$node->locationείναιPhasis\Lexer\SourceLocationμεline(αρίθμηση από το 1),column(αρίθμηση από το 0) καιoffset(μετατόπιση byte). Αποθηκεύονται μόνο οι αρχικές θέσεις· οι κόμβοι δεν περιέχουν μετατόπιση τέλους. - Όλα τα άλλα δημόσια πεδία είναι τα παιδιά και τα χαρακτηριστικά του κόμβου (
$binary->left,$binary->operator,$binary->right).
Τα περισσότερα ονόματα τύπων αντιστοιχούν στο ESTree. Οι αποκλίσεις:
| Τύπος Phasis | Τύπος ESTree |
|---|---|
ArrowFunction |
ArrowFunctionExpression |
TaggedTemplate |
TaggedTemplateExpression |
ClassMethod |
MethodDefinition |
ClassProperty |
PropertyDefinition |
AssignmentProperty |
Property (μέσα στο ObjectPattern) |
ExportDeclaration |
ExportNamedDeclaration / ExportDefaultDeclaration / ExportAllDeclaration |
ImportSpecifier |
ImportSpecifier / ImportDefaultSpecifier / ImportNamespaceSpecifier |
Ορισμένες δομές διαφέρουν επίσης: τα σώματα κλάσεων είναι απλοί πίνακες στοιχείων στον κόμβο κλάσης (χωρίς περιτύλιγμα ClassBody), τα ονόματα εισαγωγής/εξαγωγής, οι ετικέτες εντολών και τα ονόματα FunctionExpression αποθηκεύονται ως συμβολοσειρές αντί για ένθετους κόμβους Identifier, ενώ το super αναλύεται ως Identifier με όνομα super (δεν υπάρχει κλάση κόμβου Super). Το Phasis\Ast\EstreeSerializer αναδιαμορφώνει όλα αυτά στη μορφή ESTree.
Συντακτικά σφάλματα
Η μη έγκυρη είσοδος προκαλεί Phasis\Exceptions\SyntaxError (συνήθως την υποκλάση του, Phasis\Parser\ParseError). Το μήνυμα εξαίρεσης τελειώνει με τη θέση, ενώ η δομημένη τοποθεσία είναι διαθέσιμη στην εξαίρεση:
use Phasis\Exceptions\SyntaxError;
use Phasis\Parser\Parser;
try {
Parser::parseSource("const a = 1;\nconst b = ;");
} catch (SyntaxError $e) {
echo $e->getMessage(); // Unexpected token (got ; ";") at line 2, column 10
echo $e->location->line; // 2
echo $e->location->column; // 10
echo $e->location->offset; // 23
}
Περιηγητής
Το Phasis\Ast\Walker διασχίζει ένα δέντρο κατά βάθος, με επανακλήσεις εισόδου/εξόδου, κατά το πρότυπο του estraverse:
public static function walk(Node $node, callable $enter, ?callable $leave = null): void
Και οι δύο επανακλήσεις λαμβάνουν (Node $node, ?Node $parent). Αν επιστρέψετε Walker::SKIP από το $enter, παραλείπονται τα παιδιά του κόμβου· η δική του επανακλήση $leave εξακολουθεί να εκτελείται.
use Phasis\Ast\Expression\Identifier;
use Phasis\Ast\Node;
use Phasis\Ast\Walker;
$names = [];
Walker::walk($program, function (Node $node) use (&$names) {
if ($node instanceof Identifier) {
$names[] = $node->name;
}
if ($node instanceof \Phasis\Ast\Expression\ArrowFunction) {
return Walker::SKIP;
}
});
Η διάσχιση είναι μόνο για ανάγνωση. Οι κόμβοι είναι αντικείμενα τιμών μόνο για ανάγνωση, επομένως δεν υποστηρίζεται αντικατάσταση ή τροποποίηση.
Σειριοποιητής
Το Phasis\Ast\Serializer μετατρέπει το τυποποιημένο AST σε πίνακες ή JSON, χρησιμοποιώντας τα ονόματα τύπων και τη διάταξη πεδίων του Phasis, αφού αφαιρεθούν τα εσωτερικά πεδία προσωρινής μνήμης του αναλυτή:
public static function toArray(Node $node): array
public static function toJson(Node $node, bool $pretty = false): string
Αυτή είναι η μορφή που εκτυπώνει το bin/phasis --ast.
EstreeSerializer
Το Phasis\Ast\EstreeSerializer μετατρέπει το τυποποιημένο AST σε πίνακες μορφής ESTree: ονόματα τύπων ESTree (σύμφωνα με τον παραπάνω πίνακα αποκλίσεων), ονόματα και σειρά πεδίων ESTree, συνθετικούς κόμβους ClassBody / specifier / source-Literal, καθώς και μετατόπιση byte start σε κάθε κόμβο που αναλύεται από πηγαίο κώδικα. Δεν υπάρχουν μετατοπίσεις end, επειδή οι κόμβοι αποθηκεύουν μόνο αρχικές θέσεις, ενώ οι κόμβοι συμβολοσειρών Literal δεν περιέχουν κείμενο raw.
public static function toArray(Node $node): array
public static function toJson(Node $node, bool $pretty = false): string
public static function summarize(Node $node): string
Το summarize() παράγει μια ντετερμινιστική σύνοψη μίας γραμμής ανά κόμβο (τύπος και χαρακτηριστικά name= / value= / op= / kind=, εσοχή δύο κενών ανά επίπεδο βάθους). Η μορφή είναι πανομοιότυπη σε επίπεδο byte με τη σύνοψη AST που παράγει το fixture acorn στο tests/Popular/acorn, ώστε το ίδιο oracle να αξιολογεί τόσο τη διαδρομή αναλυτή JS όσο και αυτή την εξαγωγή PHP:
use Phasis\Ast\EstreeSerializer;
use Phasis\Parser\Parser;
echo EstreeSerializer::summarize(Parser::parseSource('let x = a + 1;'));
// Program
// VariableDeclaration kind=let
// VariableDeclarator
// Identifier name=x
// BinaryExpression op=+
// Identifier name=a
// Literal value=1
CLI
Το bin/phasis --ast script.js αναλύει ένα αρχείο (στόχος script) και εκτυπώνει την αποτύπωση Serializer JSON με εσοχή δύο κενών. Δείτε το CLI για πλήρη αναφορά των σημαιών.