为什么80%的码农都做不了架构师?>>>   

文件组成

  1. lex.go       词法定义与解析
  2. node.go     node 定义与创建
  3. parse.go    生成 template 语法树 tree

lex.go 要点

itemType 常量表次序规则:itemKeyword 用来分界词法中的关键字和其他词法元素,参见下列实现

func (i item) String() string
func lexIdentifier(l *lexer) stateFn

node.go 要点

各种 NodeType 要实现 Node 接口

type Node interface {Type() NodeTypeString() stringCopy() NodePosition() Pos unexported()
}

parse.go 要点

每个模板都有唯一的模板名,并对应生成一个 Tree

type Tree struct {Name      stringParseName stringRoot      *ListNodetext      stringfuncs     []map[string]interface{}lex       *lexertoken     [3]itempeekCount intvars      []string
}

Tree 的 Parse 方法中 defer t.recover(&err) 捕获解析过程中发生的 error ,如果是 runtime.Error 就 panic,否则 stopParse
Parse方法首先进行的是词法分析(内部使用goroutine和chan并行完成,其实和节点的生成是同步的)

t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim))

lex.go 中的 lexer定义

type lexer struct {name       string    // the name of the input; used only for error reportsinput      string    // the string being scannedleftDelim  string    // start of actionrightDelim string    // end of actionstate      stateFn   // the next lexing function to enterpos        Pos       // current position in the inputstart      Pos       // start position of this itemwidth      Pos       // width of last rune read from inputlastPos    Pos       // position of most recent item returned by nextItemitems      chan item // channel of scanned itemsparenDepth int       // nesting depth of ( ) exprs
}

lexer在解析过程中的顺序总是从一个 lexText 开始,遍历 input 。lexText 负责查找

  • itemLeftDelim 默认"{{",可以自定义

把处理过程交给 func lexLeftDelim,lexLeftDelim 负责查找注释和非注释(被称做lexInsideAction),处理过程交给 func lexComment,lexComment 解析到注释结束后,又把处理过程交给lexText,进行 lexInsideAction 解析。

lexInsideAction 要点

所有定义的词法都在这个函数中处理,根据词法定义交给具体的词法处理函数,形成词法处理链,完成遍历。每一个词法处理函数负责检查词法有效性。这个过程仅仅是一个词法处理链,遍历 input

某个词法分析通过后,会生成对应的节点,私有方法 parse 完成此过程。

t.parse(treeSet)

第一个节点 Tree.Root 要点

type ListNode struct {NodeTypePosNodes []Node // The element nodes in lexical order.
}

Root 是一个 ListNode ,保存 Tree 解析所有的 Node.
前面说过lex分析的时候分只有两种情况 lexText , lexInsideAction ,因此 parse 中

n := t.textOrAction()

这是所有的节点生成的入口点

func (t *Tree) textOrAction() Node {switch token := t.nextNonSpace(); token.typ {case itemText:return newText(token.pos, token.val)case itemLeftDelim:return t.action() //这里所有{{...}}中的代码都由action处理default:t.unexpected(token, "input")}return nil
}
func (t *Tree) action() (n Node) {switch token := t.nextNonSpace(); token.typ {case itemElse:return t.elseControl()case itemEnd:return t.endControl()case itemIf:return t.ifControl()case itemRange:return t.rangeControl()case itemTemplate:return t.templateControl()case itemWith:return t.withControl()}t.backup()// Do not pop variables; they persist until "end".return newAction(t.peek().pos, t.lex.lineNumber(), t.pipeline("command"))
}

而action方法把模板中的关键字划分为 xxxControl 处理,其他都由 newAction 生成 ActionNode ,

也可以理解为:template 的节点分两大类

  1. ActionNode,其实封装了各种pipline的识别信息,
  2. xxxxControl,流程控制类,IfNode,RangeNode,WithNode这些
return newAction(t.peek().pos, t.lex.lineNumber(), t.pipeline("command"))

这里面的要点:

t.pipeline("command")

看pipeline的实现,其实所有的 pipeline 节点都都封装为 NodeCommand, An element of a pipeline

pipeline 方法中对所有已知的 action 进行处理,阅读代码发现 template 的语法设计中使用这种pipeline的方式,使得解析器只需要向下分析,也就是所谓的 peek ,不需要回退,这种设计无疑简化了分析器,我不知道对以后的扩展是否会有所限制

从 Parse->parse->textOrAction->pipeline 递归向下生成了所有的节点,而最终 parse 中 t.Root.append(n) 把所有生成的节点全部添加到 Tree.Root

从struct来说,经过了一层层的封装 lex.go itemType -> node.go NodeType->node.go XxxxNode 进入Tree.Root.Nodes

转载于:https://my.oschina.net/achun/blog/131558

Go 源码阅读笔记 text/template/parse相关推荐

  1. syzkaller 源码阅读笔记1(syz-extract syz-sysgen)

    文章目录 1. syz-extract 1-0 总结 1-1. `main()` 1-2 `archList()` - `1-1 (3)` 获取架构 name list 1-3 `createArch ...

  2. Yii源码阅读笔记 - 日志组件

    2015-03-09 一 By youngsterxyf 使用 Yii框架为开发者提供两个静态方法进行日志记录: Yii::log($message, $level, $category); Yii: ...

  3. 【Flink】Flink 源码阅读笔记(15)- Flink SQL 整体执行框架

    1.概述 转载:Flink 源码阅读笔记(15)- Flink SQL 整体执行框架 在数据处理领域,无论是实时数据处理还是离线数据处理,使用 SQL 简化开发将会是未来的整体发展趋势.尽管 SQL ...

  4. Transformers包tokenizer.encode()方法源码阅读笔记

    Transformers包tokenizer.encode()方法源码阅读笔记_天才小呵呵的博客-CSDN博客_tokenizer.encode

  5. 源码阅读笔记 BiLSTM+CRF做NER任务 流程图

    源码阅读笔记 BiLSTM+CRF做NER任务(二) 源码地址:https://github.com/ZhixiuYe/NER-pytorch 本篇正式进入源码的阅读,按照流程顺序,一一解剖. 一.流 ...

  6. 代码分析:NASM源码阅读笔记

    NASM源码阅读笔记 NASM(Netwide Assembler)的使用文档和代码间的注释相当齐全,这给阅读源码 提供了很大的方便.按作者的说法,这是一个模块化的,可重用的x86汇编器, 而且能够被 ...

  7. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是"引导"文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http:// ...

  8. AQS源码阅读笔记(一)

    AQS源码阅读笔记 先看下这个类张非常重要的一个静态内部类Node.如下: static final class Node {//表示当前节点以共享模式等待锁static final Node SHA ...

  9. 【Flink】Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型

    1.概述 转载:Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型 相似文章:[Flink]Flink 基于 MailBox 实现的 StreamTask 线程模型 Fl ...

最新文章

  1. 算法设计与分析第3章 贪心算法
  2. http://www.cnblogs.com/youfan/articles/3216816.html
  3. python数组每个元素加1_python-根据键转换numpy数组中的每个元素
  4. QML基础类型之real
  5. es6-promise源码重点分析难点解析
  6. java网络编程 个人心得
  7. 计算一个时间,是否在规定的时期时间之间
  8. 客户关系管理之会员管理(转)
  9. Linux平台升级chrome浏览器后,再打开会提示:“您的个人资料来自新版 Google Chrome 浏览器,因此无法使用。某些功能可能无法使用。请指定其他个人资料目录,或使用新版本”
  10. 单片机学习笔记(一)——概述
  11. 助力操作系统国产化:Testin云测试服贸会首发鸿蒙系统测试平台
  12. 计算机网络存储设备有哪些,存储设备有哪些
  13. win10Ie重置.html默认应用设置,win10系统IE浏览器设置为默认浏览器的操作方法
  14. rds是什么云模式_IaaS、PaaS、SaaS、DaaS都是什么?
  15. VMware 8安装Mac OS X 10.7
  16. ConcurrentHashMap的锁
  17. 用TELNET登录QQ邮箱
  18. 手办商城app开发功能分析
  19. Camera摄像头模组硬件
  20. Clojure CLR 入门

热门文章

  1. 用OWA访问Exchange邮箱
  2. 合并的路径Path.Combine
  3. 【拒绝一问就懵】之Activity的启动流程
  4. 转 Hystrix入门指南 Introduction
  5. linux正则表达式sed
  6. 用UltraISO制作支持windows 7的U盘启动盘
  7. applet打包的MANIFEST.MF配置
  8. java实现简单的约瑟夫环问题(二)
  9. 摸清源头 让电脑运行不再迟缓
  10. MATLAB 的条件分支语句