Im vorherigen Artikel Vue3-Kompilierungsprozess – Quellcodeanalyse haben wir mit dem Eintrag 1. Generieren Sie einen abstrakten AST-Syntaxbaum Lassen Sie uns zunächst die Logik von ast in Exportfunktion baseCompile( Vorlage: Zeichenfolge | RootNode, Optionen: CompilerOptions = {} ): CodegenResult { /* Vorherige Logik ignorieren*/ const ast = isString(Vorlage) ? baseParse(Vorlage, Optionen) : Vorlage verwandeln( ast, {/* Parameter ignorieren */} ) Rückgabe generieren( ast, erweitern({}, Optionen, { Präfixkennungen }) ) } Da ich die Logik, auf die wir nicht achten müssen, auskommentiert habe, ist die Logik im Funktionskörper jetzt sehr klar:
Hier konzentrieren wir uns hauptsächlich auf die Generierung von AST. Es ist ersichtlich, dass die Generierung von ast eine ternäre Operatorbeurteilung hat. Wenn der übergebene Exportfunktion baseParse( Inhalt: Zeichenfolge, Optionen: ParserOptions = {} ): Stammknoten { const context = createParserContext(content, options) // Ein Parsing-Kontext-Objekt erstellen const start = getCursor(context) // Cursor-Informationen generieren um den Parsing-Prozess aufzuzeichnen return createRoot( // Stammknoten generieren und zurückgeben parseChildren(context, TextModes.DATA, []), // Kindknoten als untergeordnetes Attribut des Stammknotens analysieren getSelection(context, start) ) } Ich habe der Funktion 2. Erstellen Sie den Stammknoten von ASTExportfunktion createRoot( untergeordnete Elemente: TemplateChildNode[], loc = locStub ): Stammknoten { zurückkehren { Typ: NodeTypes.ROOT, Kinder, Helfer: [], Komponenten: [], Anweisungen: [], Hebezeuge: [], Importe: [], zwischengespeichert: 0, Temperaturen: 0, CodegenNode: undefiniert, loc } } Wenn wir uns den Code der Funktion 3. Untergeordnete Knoten analysierenFunktion parseChildren( Kontext: ParserContext, Modus: Textmodi, Vorfahren: ElementNode[] ): VorlageChildNode[] { const parent = last(ancestors) // Den übergeordneten Knoten des aktuellen Knotens abrufen const ns = parent ? parent.ns : Namespaces.HTML const nodes: TemplateChildNode[] = [] // Analysiere die analysierten Knoten // Wenn das Label nicht geschlossen ist, analysiere den entsprechenden Knoten while (!isEnd(context, mode, ancestors)) {/* Logik ignorieren*/} // Verarbeiten Sie Leerzeichen, um die Ausgabeeffizienz zu verbessern. let removedWhitespace = false if (mode !== TextModes.RAWTEXT && mode !== TextModes.RCDATA) {/* Logik ignorieren*/} // Leerzeichen entfernen und das analysierte Knoten-Array zurückgeben return removedWhitespace ? nodes.filter(Boolean) : nodes } Aus dem obigen Code können wir erkennen, dass In der While-Anweisung bestimmt der Parser den Typ der Textdaten und setzt die Analyse nur fort, wenn Der erste Fall besteht darin, zu bestimmen, ob die „ Wenn das erste Zeichen "<" und das zweite Zeichen '!' ist, wird als nächstes versucht, das Kommentar-Tag Anschließend wird ermittelt, dass „</“, wenn das zweite Zeichen „/“ ist, die Bedingungen eines schließenden Tags erfüllt und es wird versucht, eine Übereinstimmung mit dem schließenden Tag zu finden. Wenn das dritte Zeichen ">" ist, fehlt der Tag-Name, es wird ein Fehler gemeldet und der Parser geht drei Zeichen weiter und überspringt "</>". Wenn es mit „</“ beginnt und das dritte Zeichen ein englischer Kleinbuchstabe ist, analysiert der Parser das End-Tag. Wenn das erste Zeichen der Quellvorlagenzeichenfolge „<“ ist und das zweite Zeichen mit einem englischen Kleinbuchstaben beginnt, wird Wenn die Verzweigungsbedingung zur Beurteilung der Zeichenfolge endet und kein Knoten analysiert wird, wird der Knoten als Texttyp behandelt und zum Analysieren wird „parseText“ aufgerufen. Fügen Sie abschließend den generierten Knoten zum Dies ist die Logik innerhalb der while-Schleife und der wichtigste Teil von während (!isEnd(Kontext, Modus, Vorfahren)) { const s = Kontext.Quelle let-Knoten: TemplateChildNode | TemplateChildNode[] | undefined = undefiniert wenn (Modus === TextModes.DATA || Modus === TextModes.RCDATA) { wenn (!context.inVPre && startsWith(s, context.options.delimiters[0])) { /* Wenn das Tag keine v-pre-Direktive hat, beginnt die Quellvorlagenzeichenfolge mit doppelten geschweiften Klammern `{{` und wird gemäß der Syntax der doppelten geschweiften Klammern analysiert*/ Knoten = parseInterpolation(Kontext, Modus) } sonst wenn (Modus === TextModes.DATA && s[0] === '<') { // Wenn die erste Zeichenposition der Quellvorlagenzeichenfolge „!“ ist. wenn (s[1] === '!') { // Wenn es mit '<!--' beginnt, analysiere es als Kommentar if (startsWith(s, '<!--')) { Knoten = parseComment(Kontext) } sonst wenn (startetMit(s, '<!DOCTYPE')) { // Wenn es mit „<!DOCTYPE“ beginnt, ignoriere DOCTYPE und analysiere es als Pseudokommentar node = parseBogusComment(context) } sonst wenn (startetMit(s, '<![CDATA[')) { // Wenn es mit '<![CDATA[' beginnt und sich in einer HTML-Umgebung befindet, analysieren Sie CDATA wenn (ns !== Namespaces.HTML) { Knoten = parseCDATA(Kontext, Vorfahren) } } // Wenn die zweite Zeichenposition der Quellvorlagenzeichenfolge '/' ist } sonst wenn (s[1] === '/') { // Wenn die dritte Zeichenposition der Quellvorlagenzeichenfolge '>' ist, handelt es sich um ein selbstschließendes Tag, und die Scanposition wird um drei Zeichen nach vorne verschoben, wenn (s[2] === '>') { emitError(Kontext, Fehlercodes.FEHLENDE_END_TAG_NAME, 2) AdvanceBy(Kontext, 3) weitermachen // Wenn die dritte Zeichenposition ein englisches Zeichen ist, analysiere das End-Tag} else if (/[az]/i.test(s[2])) { parseTag(Kontext, TagType.Ende, übergeordnetes Element) weitermachen } anders { // Wenn dies oben nicht der Fall ist, analysieren Sie es als Pseudokommentar node = parseBogusComment(context) } // Wenn das zweite Zeichen des Tags ein englisches Kleinbuchstabe ist, wird es als Element-Tag analysiert} else if (/[az]/i.test(s[1])) { Knoten = ParseElement(Kontext, Vorfahren) // Wenn das zweite Zeichen '?' ist, interpretiere es als Pseudokommentar} else if (s[1] === '?') { Knoten = parseBogusComment(Kontext) } anders { // Wenn keine dieser Bedingungen erfüllt ist, wird eine Fehlermeldung ausgegeben, die darauf hinweist, dass das erste Zeichen kein gültiges Beschriftungszeichen ist. emitError(Kontext, Fehlercodes.UNGÜLTIGES ERSTES ZEICHEN DES TAGNAMENS, 1) } } } // Wenn nach der Analyse der obigen Situation kein entsprechender Knoten erstellt wird, analysieren Sie ihn als Text, wenn (! Knoten) { Knoten = parseText(Kontext, Modus) } // Wenn der Knoten ein Array ist, durchlaufe ihn und füge ihn dem Knoten-Array hinzu, andernfalls füge ihn direkt hinzu if (isArray(node)) { für (lass i = 0; i < Knotenlänge; i++) { pushNode(Knoten, Knoten[i]) } } anders { pushNode(Knoten, Knoten) } } 4. Vorlagenelemente analysieren In der Ich werde zuerst den Quellcode von Funktion parseElement( Kontext: ParserContext, Vorfahren: ElementNode[] ): ElementNode | undefiniert { //Start-Tag analysieren const parent = last(ancestors) const-Element = parseTag(Kontext, TagType.Start, übergeordnetes Element) // Wenn es ein selbstschließendes Tag oder ein leeres Tag ist, direkt zurückkehren. voidTagBeispiel: `<img>`, `<br>`, `<hr>` wenn (element.isSelfClosing || context.options.isVoidTag(element.tag)) { Rücklaufelement } // Untergeordnete Knoten rekursiv analysieren ancestors.push(element) const mode = context.options.getTextMode(Element, übergeordnetes Element) const children = parseChildren(Kontext, Modus, Vorfahren) Vorfahren.pop() element.children = Kinder // Analysiere das End-Tag if (startsWithEndTagOpen(context.source, element.tag)) { parseTag(Kontext, TagType.Ende, übergeordnetes Element) } anders { emitError(Kontext, ErrorCodes.X_MISSING_END_TAG, 0, Element.loc.start) wenn (context.source.length === 0 und element.tag.toLowerCase() === 'script') { const erste = Kinder[0] wenn (first && beginnt mit (first.loc.source, '<!--')) { emitError(Kontext, Fehlercodes.EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT) } } } // Holen Sie sich das Beschriftungspositionsobjekt element.loc = getSelection(context, element.loc.start) Rücklaufelement } Zuerst holen wir uns den übergeordneten Knoten des aktuellen Knotens und rufen dann Die Funktion parseTag wird gemäß dem folgenden Prozess ausgeführt:
Nach dem Abrufen Dann versuchen wir, die untergeordneten Knoten des const parent = letzte(Vorfahren) Wenn wir auf die Codezeilen in Passen Sie abschließend das End-Tag an, legen Sie die Positionsinformationen des Elements fest und geben Sie das analysierte 5. Beispiel: Analyse von VorlagenelementenBitte sehen Sie sich die Vorlage an, die wir unten analysieren werden. Das Bild zeigt die Speicherung des Knotenstapels nach der Analyse während des Analysevorgangs. <div> <p>Hallo Welt</p> </div> Das gelbe Rechteck in der Abbildung ist ein Stapel. Wenn die Analyse beginnt, stößt Nachdem dieser Der dem p-Tag entsprechende Knoten wird generiert und der entsprechende Knoten wird in Nachdem der Knoten vom p-Tag empfangen wurde, fügt das div-Tag ihn seinem eigenen untergeordneten Attribut hinzu und entfernt ihn vom Stapel. Zu diesem Zeitpunkt ist der Ahnenstapel leer. Nachdem das Div-Tag die geschlossene Analyselogik abgeschlossen hat, gibt es das Schließlich gibt der erste Aufruf von Dies ist das Ende dieses Artikels über die Quellcodeanalyse Das könnte Sie auch interessieren:
|
<<: So aktualisieren, verpacken und laden Sie Docker-Container in die Alibaba Cloud hoch
>>: Verstehen Sie einfach die Unterschiede in den Prinzipien gängiger SQL-Delete-Anweisungen
Die Installation des RPM-Pakets ist relativ einfa...
Inhaltsverzeichnis 1. Funktionseinführung 2. Schl...
Umsetzungsideen Erstellen Sie zunächst einen über...
Bei Verwendung des Tags <html:reset> stellen...
Inhaltsverzeichnis 1. Ursprüngliche Nachfrage 2. ...
Dieser Artikel wurde unter Bezugnahme auf die off...
1. Bearbeiten Sie die Datei docker.service vi /us...
Der Spread-Operator ermöglicht die Erweiterung ei...
Das <canvas>-Element ist für clientseitige ...
Erstellen Sie eine neue Konfigurationsdatei (gehe...
Geben Sie /usr/local/nginx/conf ein sudo cd /usr/...
Es ist sehr wichtig, den Betriebsstatus von Conta...
1. Überprüfen Sie, ob das Modul „Status prüfen“ i...
Schauen wir uns zunächst einige einfache Daten an:...