Vue编译器AST抽象语法树源码分析

 直接进入核心现在说说baseCompile核心代码: 

 // `createCompilerCreator` allows creating compilers that use alternative
  // parser/optimizer/codegen, e.g the SSR optimizing compiler.
  // Here we just export a default compiler using the default parts.
  var createCompiler = createCompilerCreator(function baseCompile(
  template,
  options
  ) {
  var ast = parse(template.trim(), options);
  if (options.optimize !== false) {
  }
  var code = generate(ast, options);
  return {
  ast: ast,
  render: code.render,
  staticRenderFns: code.staticRenderFns
  }
  });

  在 baseCompile核心代码中,var ast =parse(template.trim(), options); parse 是通过用等方式解析 template 模板中的指令、class、style等数据,形成AST。

  其中有一处优化节点就是optimize(ast, options); optimize ,这样可以标记 static 静态节点,可以当 update 更新界面时,会产生一个 patch 的过程, diff 算法会直接跳过静态节点,这样极大的减少比较的过程,从而优化了 patch 的性能。

  而var code =generate(ast, options); 主要就是为了生成目标平台所需的代码,这样可以让 AST 转变成 render function 字符串的过程,最终得到 render 的字符串以及 staticRenderFns 字符串。

  最终 baseCompile 的返回值

  {
  ast: ast,
  render: code.render,
  staticRenderFns: code.staticRenderFns
  }

  最终返回了抽象语法树( ast ),渲染函数( render ),静态渲染函数( staticRenderFns ),且render 的值为code.render ,staticRenderFns 的值为code.staticRenderFns ,也就是说通过 generate 处理 ast 之后得到的返回值 code 是一个对象 …

  现在我们主要讲讲在 Vue 的 parser,如何将它字符串模板解析为抽象语法树(AST)的。

  var ast = parse(template.trim(), options);

  在讲解parse之前,我们先要了解下对于编译过程以及其中一些详细技术要点。

  引用自维基百科:

  它主要的目的是将便于人编写、阅读、维护的高级计算机语言所写作的源代码程序,翻译为计算机能解读、运行的低阶机器语言的程序。源代码一般为高阶语言(High-level language),如Pascal、C、C++、C# 、Java等,而目标语言则是汇编语言或目标机器的目标代码(Object code)。

  编译器的技术分为词法分析、语法分析和语义分析三个部分,通常编译器的第一项工作叫做词法分析。其实就如同读一篇文章,文章的内容就是由一个个的中文单词组成的。换而言之我们可以将程序处理也这样想,它叫做“词法记号”,英文叫 Token。

  <div id="app" v-if="ret">{{ message }}</div>

  编译器会识别出 div a span 这些标签,id class style v-if v-for 这样的属性、指令,还有花括号符号这样的插值操作…等。这些都是 Token。

  如何写一个程序来识别 Token

  那么,如何写一个程序来识别 Token 呢?

  在编写程序时,我们要区分不同的Token,在此之中要利用一些规则来表达“正则文法”。主要就是符合正则文法的表达式称为“正则表达式”。以此来完成词法分析工作。

  编译器下一个阶段的工作是语法分析。词法分析是识别一个个的单词,而语法分析就是在词法分析的基础上识别出程序的语法结构。这个结构是一个树状结构,是计算机容易理解和执行的。

  程序也要定义良好的语法结构,它的语法分析过程,就是构造这么一棵树。一个程序就是一棵树,这棵树叫做抽象语法树(Abstract Syntax Tree,AST)。树的每个节点(子树)是一个语法单元,这个单元的构成规则就叫“语法”。

  现在我们来说说parser, 这是在编译器对源代码处理的第一步,parser主要就是用来把某种特定格式的文本(字符串)转换成某种数据结构的程序(对象),而且编译器能够理解这个数值。可以不想编译器在后续步骤中的做有用,举例上面提到的 句法分析,类型检查/推导,代码优化,代码生成 等等都依赖于该数据结构。

  注:parse & parser 这两个单词,不要混淆,parse 是动词,代表“解析”的过程,parser 是名词,代表“解析器”。

  Vue 的编译器也不例外, 在词法分析阶段 Vue 会把字符串模板解析成一个个的令牌(token),该令牌将用于句法分析阶段,在句法分析阶段会根据令牌生成一棵 AST,最后再根据该 AST生成最终的渲染函数,这样就完成了代码的生成。

  var ast = parse(template.trim(), options);

  parse 函数解析模板字符串

  回归到刚刚的代码,已知 parse 函数就是用来解析模板字符串的,最终生成AST。

  function parse(template, options) {
  // 省略...
  parseHTML(template, {
  warn,
  expectHTML: options.expectHTML,
  isUnaryTag: options.isUnaryTag,
  canBeLeftOpenTag: options.canBeLeftOpenTag,
  shouldDecodeNewlines: options.shouldDecodeNewlines,
  shouldDecodeNewlinesForHref: options.shouldDecodeNewlinesForHref,
  shouldKeepComment: options.comments,
  start (tag, attrs, unary) {
  // 省略...
  },
  end () {
  // 省略...
  },
  chars (text: string) {
  // 省略...
  },
  comment (text: string) {
  // 省略...
  }
  })
  return root
  }

  parse 函数内部主要通过调用parseHTML 函数对模板字符串进行解析,简单来说就是用来做词法分析的。不同的是而arse函数的作用则是在词法分析的基础上做句法分析从而生成一棵AST。

  以上就是Vue编译器AST抽象语法树源码分析的详细内容,请大家关注更多后续精彩内容。

原创文章,作者:网友投稿,如若转载,请注明出处:https://www.cloudads.cn/archives/3952.html

发表评论

登录后才能评论