百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

flutter之dartsdk--CFE(公共前端),AST(语法)

toyiye 2024-06-21 11:56 14 浏览 0 评论

文档路径pkg/analyzer/doc/md

一,AST的结构

1,AST由排列成树的节点(“AstNode”的实例)组成。也就是说,每个节点可以有零个或多个子节点,每个子节点也是一个节点,而根节点以外的每个节点都只有一个父节点。

2,树的根通常是“CompilationUnit”。编译单元具有表示语言构造(如导入指令和类声明)的子级。类声明包含表示类的每个成员的子级。节点的结构与Dart语言语法相似,但不完全相同

3,如上所述,语法中的每个生成都有“AstNode”的子类。子类在“package:analyszer/dart/ast/ast.dart”中定义。

4,每个节点类都通过getter提供对其父节点和子节点的访问。例如,类“BinaryExpression”定义了getter“parent”、“leftOperand”和“rightOperand”。它还为作为构造一部分(但不是子构造的一部分)的token提供getter。例如,在二进制表达式中,有一个getter来访问“operator”。

5,每个节点类和每个token都携带位置信息。您可以要求从包含文件的开头开始输入entity开头的字符“offset”,以及字符“length”。对于AST节点,偏移量是结构中第一个token的偏移量,长度包括结构中最后一个token的结尾。第一个标记之前或最后一个标记之后的任何空格都被视为父节点的一部分。

6,类定义:

AstNode类,继承SyntacticEntity(语法实体),一个AST结构代表一个a Dart program

路径:pkg/analyzer/lib/dart/ast/ast.dart

备注: 客户端不能在此类中扩展、实现或混合

abstract class AstNode implements SyntacticEntity {

/// Return the first token included in this node's source range.

Token get beginToken;

返回一个迭代器,该迭代器可用于遍历构成该节点内容的所有实体(AST节点或token),包括文档注释,但不包括其他注释

Iterable<SyntacticEntity> get childEntities;

返回此节点源范围的最后一个字符之后的字符的偏移量。这相当于“node.getOffset()+node.getLength()”。对于编译单元,这将等于 该单元源代码的长度。对于合成节点,这将等同于节点的偏移量(因为长度定义为零(0))

@override

int get end;

/// Return the last token included in this node's source range.

Token get endToken;

如果此节点是合成节点,则返回“true”。合成节点是解析器为了从代码中的错误中恢复而引入的节点。合成节点的长度始终为零(“0”)

bool get isSynthetic;

@override

int get length;

@override

int get offset;

返回此节点的最直接祖先,对于该节点,[predice]返回“true”,如果没有这样的祖先,则返回“null”。请注意,永远不会返回此节点

@deprecated

E getAncestor<E extends AstNode>(Predicate<AstNode> predicate);

以近似有效源的形式返回此节点的文本描述。返回的字符串将不是有效的源,主要是在节点本身格式不正确的情况下

String toSource();

用给定的[visitor]访问此节点的所有子节点。孩子们将按词汇顺序进行访问

void visitChildren(AstVisitor visitor);

}


7,结构图:



二,类型

1,类型模型表示语言规范定义的类型信息

2,类型的种类(有四个类型类,它们都是抽象类“DartType”的子类型)

### Interface Types

### Function Types

### The Void Type

### The Type Dynamic

## Accessing Types

3,有两种方法可以获取“DartType”的实例:从[AST][AST]和来自[element][element]模型

在已解析的AST中,每个表达式都有一个非“null”“staticType”。

三,element

1,element模型:

元素模型与[type][type]模型一起描述了Dart代码的语义(而不是句法)结构。代码的语法结构由[AST][AST]建模。

一般来说,元素表示代码中声明的东西,例如类、方法或变量。元素可以显式声明,例如由类声明定义的类,也可以隐式声明,比如为没有任何显式构造函数声明的类定义的默认构造函数。隐式声明的元素称为_synthetic_元素。

有几个元素表示未声明的实体。例如,有一个元素表示编译单元(`.dart`文件)和另一个表示库。

2,element模型结构

元素以树结构组织,其中元素的子元素是父元素声明的逻辑(通常是语法)部分。

例如,表示类中方法和字段的元素是表示类的元素的子元素。

每个完整的元素结构都是由类“LibraryElement”的一个实例创建的。

库元素表示单个Dart库。每个库由一个或多个编译单元(库及其所有部分)定义。

编译单元由类“CompilationUnitElement”表示,并且是由它们定义的库的子级。每个编译单元可以包含零个或多个顶级声明,例如类、函数和变量。这些元素中的每一个依次表示为编译单元的子元素。类包含方法和字段,方法可以包含局部变量等。

元素模型不包含代码中的所有内容,只有代码声明的那些东西。例如,它不包括方法体中语句的任何表示,但如果其中一个语句声明了局部变量,则该局部变量将由元素表示。

四,token 流

token是一个双链接列表,在开头和结尾都有特殊的“EOF”token。

结束处的EOFtoken指向自身作为下一个token,而开始处的EOF token指向自己作为上一个token。因此,对于一个格式正确的token流(我们通常假设总是这样),上一个和下一个都不能返回null。我们无法在类型系统中表达这一点,因为在构建列表时,这些字段将暂时为空。因此,整个代码库的惯例是在调用这两个getter的任何地方都用bang(!)作为后缀。token通常通过AST访问,参考源码文件:pkg/front_end/lib/src/scanner/token.dart

1,表示在源文件中具有位置和range的语法实体(token或AST节点)的接口。

abstract class SyntacticEntity {

/**

* Return the offset from the beginning of the file to the character after the

* last character of the syntactic entity.

*/

int get end;


/**

* Return the number of characters in the syntactic entity's source range.

*/

int get length;


/**

* Return the offset from the beginning of the file to the first character in

* the syntactic entity.

*/

int get offset;

}


2,从输入扫描的Token。每个Token都知道哪些Token在它之前和之后,充当双链接Token列表中的链接。

客户端不能在此类中扩展、实现或混合

abstract class Token implements SyntacticEntity {

/**

初始化新创建的Token,使其具有给定的[类型]和[偏移量]

*/

factory Token(TokenType type, int offset, [CommentToken preceedingComment]) =

SimpleToken;


/**

* The number of characters parsed by this token.

*/

int get charCount;


/**

* The character offset of the start of this token within the source text.

*/

int get charOffset;


/**

* The character offset of the end of this token within the source text.

*/

int get charEnd;


/**

* The token before this synthetic token,

* or `null` if this is not a synthetic `)`, `]`, `}`, or `>` token.

*/

Token get beforeSynthetic;


/**

* Set token before this synthetic `)`, `]`, `}`, or `>` token,

* and ignored otherwise.

*/

set beforeSynthetic(Token previous);


@override

int get end;


/**

* The token that corresponds to this token, or `null` if this token is not

* the first of a pair of matching tokens (such as parentheses).

*/

Token get endGroup => null;


/**

* Return `true` if this token represents an end of file.

*/

bool get isEof;


/**

* True if this token is an identifier. Some keywords allowed as identifiers,

* see implementation in [KeywordToken].

*/

bool get isIdentifier;


/**

* True if this token is a keyword. Some keywords allowed as identifiers,

* see implementation in [KeywordToken].

*/

bool get isKeyword;


/**

* True if this token is a keyword or an identifier.

*/

bool get isKeywordOrIdentifier;


/**

* Return `true` if this token is a modifier such as `abstract` or `const`.

*/

bool get isModifier;


/**

* Return `true` if this token represents an operator.

*/

bool get isOperator;


/**

* Return `true` if this token is a synthetic token. A synthetic token is a

* token that was introduced by the parser in order to recover from an error

* in the code.

*/

bool get isSynthetic;


/**

* Return `true` if this token is a keyword starting a top level declaration

* such as `class`, `enum`, `import`, etc.

*/

bool get isTopLevelKeyword;


/**

* Return `true` if this token represents an operator that can be defined by

* users.

*/

bool get isUserDefinableOperator;


/**

* Return the keyword, if a keyword token, or `null` otherwise.

*/

Keyword get keyword;


/**

* The kind enum of this token as determined by its [type].

*/

int get kind;


@override

int get length;


/**

* Return the lexeme that represents this token.

*

* For [StringToken]s the [lexeme] includes the quotes, explicit escapes, etc.

*/

String get lexeme;


/**

* Return the next token in the token stream.

*/

Token get next;


/**

* Return the next token in the token stream.

*/

void set next(Token next);


@override

int get offset;


/**

* Set the offset from the beginning of the file to the first character in

* the token to the given [offset].

*/

void set offset(int offset);


/**

返回此标记之前的注释列表中的第一个注释,如果此标记之前没有注释,则返回“null”。通过使用[next]跟踪token流,直到返回“null”,可以获得其他注释。例如,如果原始内容是“/*one*//*two*/id”,那么前面的第一个注释标记将具有“/*one*/”的词位,而下一个注释标记的词位将为“/*two*/”

*/

Token get precedingComments;


/**

对于符号和关键字标记,返回此标记表示的字符串值。对于[StringToken],此方法返回[:null:]。对于[SymbolToken]s和[KeywordToken]s,字符串值是源自[TokenType]或[Keyword]实例的编译时间常数。这允许使用[:idential:]测试关键字和符号,例如[:idential('class',token.value):]。请注意,为字符串标记返回[:null:]对于识别符号和关键字很重要,我们不能使用[lexeme]。字符串文字“$a($b)”产生…,SymbolToken($),StringToken(a),StringToken(()。。。

解析标识符“a”后,解析器使用[:idential(next.stringValue,'('):]测试函数声明,该声明(正确地)返回false,因为stringValue返回[:null:]。

*/

String get stringValue;


/**

* Return the type of the token.

*/

TokenType get type;


}


newLocation_fromUnit

ParseStringResultImpl

StackListener

beginCompilationUnit

ast_to_binary,ast_from_binary

ast_binary_writer.dart


六,从源码到ast流程

1,源码->token(scanner)->ast(parse)

2,几个重要的类定义

CompilationUnit类(编译单元)。

虽然语法限制编译单元中指令和声明的顺序,但此类不强制执行这些限制。特别是,即使词汇顺序不符合语法的限制,也将按词汇顺序访问编译单元的子级.

/*

compilationUnit ::= directives declarations

directives ::= [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]* | [PartOfDirective]

namespaceDirective ::= [ImportDirective] | [ExportDirective]

declarations ::= [CompilationUnitMember]

*/

路径pkg/analyzer/lib/dart/ast/ast.dart

abstract class CompilationUnit implements AstNode {

/// Set the first token included in this node's source range to the given

/// [token].

void set beginToken(Token token);


/// Return the declarations contained in this compilation unit.

NodeList<CompilationUnitMember> get declarations;


/// Return the element associated with this compilation unit, or `null` if the

/// AST structure has not been resolved.

CompilationUnitElement get declaredElement;


/// Return the directives contained in this compilation unit.

NodeList<Directive> get directives;


/// Return the element associated with this compilation unit, or `null` if the

/// AST structure has not been resolved.

@deprecated

CompilationUnitElement get element;


/// Set the element associated with this compilation unit to the given

/// [element].

void set element(CompilationUnitElement element);


/// Set the last token included in this node's source range to the given

/// [token].

void set endToken(Token token);


此编译单元可用的一组功能,如果未知,则为“null”,由.packages文件、封装包的SDK版本约束和/或文件顶部注释中存在“@dart”指令的某种组合决定。例如,这个’null’就是根据[CompilationUnit]重新合成的

FeatureSet get featureSet;


/// Return the line information for this compilation unit.

LineInfo get lineInfo;


/// Set the line information for this compilation unit to the given [info].

void set lineInfo(LineInfo info);


/// Return the script tag at the beginning of the compilation unit, or `null`

/// if there is no script tag in this compilation unit.

ScriptTag get scriptTag;


/// Set the script tag at the beginning of the compilation unit to the given

/// [scriptTag].

void set scriptTag(ScriptTag scriptTag);


/// Return a list containing all of the directives and declarations in this

/// compilation unit, sorted in lexical order.

List<AstNode> get sortedDirectivesAndDeclarations;

}


ParserAstNode类

abstract class ParserAstNode {

final String what;

final ParserAstType type;

Map<String, Object?> get deprecatedArguments;

List<ParserAstNode>? children;

ParserAstNode? parent;


ParserAstNode(this.what, this.type);


// TODO(jensj): Compare two ASTs.

}

CompilationUnitEnd类

路径:front_end/lib/src/fasta/util/parser_ast_helper.dart

class CompilationUnitEnd extends ParserAstNode {

final int count;

final Token token;


CompilationUnitEnd(ParserAstType type,

{required this.count, required this.token})

: super("CompilationUnit", type);


@override

Map<String, Object?> get deprecatedArguments => {

"count": count,


"token": token,

};

}

源码到AST流程图:



八,从ast到CFG(控制流图(Control Flow Graph))

正统做法推荐的是在做数据流分析之前,先把AST转换为一种更细粒度的、把控制流显式暴露出来的中间表示(IR)

九:补充dill文件

源码:

void main() {

ConsolePrinter cp= new ConsolePrinter();

cp.print_data();

}

printMsg()=>print("hello");

int test()=>123;

class Printer {

void print_data() {

print(test());

}

}

class ConsolePrinter implements Printer {

void print_data() {

printMsg();

}

}

dill文件:



dart支持增量编译(incremental compilation),修改部分代码,不需要全部重新编译,只编译相关部分.支持热重载(hotReload),可参考博客:https://cloud.tencent.com/developer/article/1964443?from=article.detail.1405079&areaSource=106000.1&traceId=NJ7ptKaT4spfIAxVSAWsa,本人未实践

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码