Go Tool学习(一)scanner(2)TestSemis方法

本文深入探讨了GoTool中scanner的TestSemis方法,解析了如何使用该方法对一系列字符串进行扫描,检查分号的正确性,并详细解释了checkSemi函数的工作原理。文章重点介绍了scanner初始化、自动插入分号机制及非法标记的处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Go Tool学习(一)scanner(2)TestSemis方法

测试输入——全局变量lines:

var lines = []string{
	// # indicates a semicolon present in the source
	// $ indicates an automatically inserted semicolon
	"",
	"\ufeff#;", // first BOM is ignored
	"#;",
	"foo$\n",
	"123$\n",
	...

TestSemis方法很简单,对lines中的每一个元素都会创建多个scanner去scan,创建scanner的操作再checkSmi方法中。

func TestSemis(t *testing.T) {
	for _, line := range lines {
		checkSemi(t, line, 0)
		checkSemi(t, line, ScanComments) // 不忽略注释

		// 如果输入以换行符结束,那么去掉换行符的输入进行checkSemi应该也
		// 能通过。所以这里将换行符去掉后再进行checkSemi
		for i := len(line) - 1; i >= 0 && line[i] == '\n'; i-- {
			checkSemi(t, line[0:i], 0)
			checkSemi(t, line[0:i], ScanComments)
		}
	}
}

checkSemi:

首先初始化一个scanner
var S Scanner
file := fset.AddFile("TestSemis", fset.Base(), len(line))
S.Init(file, []byte(line), nil, mode)

这里提一下fset的base,看了一下fset.AddFile实现,每次调用后都会将fset.base改为fset.base + size + 1,这里的size即文件长度。

进行check
for tok != token.EOF {
	if tok == token.ILLEGAL {
		// illegal token即无法识别的token,checkSemi主要的逻辑就在这里
		// 主要两种情况:
		// 1.illegal token是'#',那么semiLit(semicolon literal,“分号”序列)应该是';'
		// 2.否则semiLit应该是'\n'
		// 至于为什么是这样,还不清楚 <_<
		// 还有一点要提一下:前面有说如果是'\n'结束的输入删去'\n'后也要能通过checkSemi,
		// 主要是因为scanner会自动插入semicolon,scanner有个属性insertSemi默认false,即
		// 默认不会自动插入,但是在scanner.Scan方法625行可以看到,比如如果当前token是一个
		// 数字,scanner会把insertSemi设置为true,在637行发现当前token是'\n'时又会把insertSemi
		// 设置为false
		semiLit := "\n"
		if lit[0] == '#' {
			semiLit = ";"
		}
		
		// illegal token的后一个token一定是一个semicolon
		// 所以先对semiPos的Offset和Column都加1
		// 有可能semiLit是'\n'的情况,但这里并没有对semiPos.Line加1的处理,这说明'\n'字符
		// 本身应该是属于当前的,其后续字符是属于下一行的(总不能是程序bug吧<_<)
		semiPos := file.Position(pos)
		semiPos.Offset++
		semiPos.Column++
		pos, tok, lit = S.Scan() // 读下一个token,然后check
		if tok == token.SEMICOLON {
			if lit != semiLit {
				t.Errorf(`bad literal for %q: got %q, expected %q`, line, lit, semiLit)
			}
			checkPos(t, line, pos, semiPos)
		} else {
			t.Errorf("bad token for %q: got %s, expected ;", line, tok)
		}
	} else if tok == token.SEMICOLON {
		// 这里的条件判断,意味着只有illegal token后能够跟SEMICOLON Token
		t.Errorf("bad token for %q: got ;, expected no ;", line)
	}
	// 其他token都被忽略了
	pos, tok, lit = S.Scan()
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值