From 8e5657d67cad7f09fd3af4ece60eb99cf00c69e5 Mon Sep 17 00:00:00 2001 From: Daniel Kang Date: Thu, 10 Jan 2019 02:45:20 -0800 Subject: [PATCH] fix CharLit parser bug --- parser/parser.go | 30 +++++++++++++++++++++++------- parser/parser_char_test.go | 24 ++++++++++++++++++++++++ parser/parser_test.go | 4 ++++ vm/vm_char_test.go | 9 +++++++++ 4 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 parser/parser_char_test.go create mode 100644 vm/vm_char_test.go diff --git a/parser/parser.go b/parser/parser.go index f98e63e..c983727 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -285,13 +285,7 @@ func (p *Parser) parseOperand() ast.Expr { return x case token.Char: - x := &ast.CharLit{ - Value: rune(p.tokenLit[1]), - ValuePos: p.pos, - Literal: p.tokenLit, - } - p.next() - return x + return p.parseCharLit() case token.String: v, _ := strconv.Unquote(p.tokenLit) @@ -355,6 +349,28 @@ func (p *Parser) parseOperand() ast.Expr { return &ast.BadExpr{From: pos, To: p.pos} } +func (p *Parser) parseCharLit() ast.Expr { + if n := len(p.tokenLit); n >= 3 { + if code, _, _, err := strconv.UnquoteChar(p.tokenLit[1:n-1], '\''); err == nil { + x := &ast.CharLit{ + Value: rune(code), + ValuePos: p.pos, + Literal: p.tokenLit, + } + p.next() + return x + } + } + + pos := p.pos + p.error(pos, "illegal char literal") + p.next() + return &ast.BadExpr{ + From: pos, + To: p.pos, + } +} + func (p *Parser) parseFuncLit() ast.Expr { if p.trace { defer un(trace(p, "FuncLit")) diff --git a/parser/parser_char_test.go b/parser/parser_char_test.go new file mode 100644 index 0000000..0627342 --- /dev/null +++ b/parser/parser_char_test.go @@ -0,0 +1,24 @@ +package parser_test + +import ( + "testing" + + "github.com/d5/tengo/ast" +) + +func TestChar(t *testing.T) { + expect(t, `'A'`, func(p pfn) []ast.Stmt { + return stmts( + exprStmt( + charLit('A', 1))) + }) + expect(t, `'九'`, func(p pfn) []ast.Stmt { + return stmts( + exprStmt( + charLit('九', 1))) + }) + + expectError(t, `''`) + expectError(t, `'AB'`) + expectError(t, `'A九'`) +} diff --git a/parser/parser_test.go b/parser/parser_test.go index 650108c..f04faed 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -207,6 +207,10 @@ func stringLit(value string, pos scanner.Pos) *ast.StringLit { return &ast.StringLit{Value: value, ValuePos: pos} } +func charLit(value rune, pos scanner.Pos) *ast.CharLit { + return &ast.CharLit{Value: value, ValuePos: pos, Literal: fmt.Sprintf("'%c'", value)} +} + func boolLit(value bool, pos scanner.Pos) *ast.BoolLit { return &ast.BoolLit{Value: value, ValuePos: pos} } diff --git a/vm/vm_char_test.go b/vm/vm_char_test.go new file mode 100644 index 0000000..a14f327 --- /dev/null +++ b/vm/vm_char_test.go @@ -0,0 +1,9 @@ +package vm_test + +import "testing" + +func TestChar(t *testing.T) { + expect(t, `out = 'a'`, 'a') + expect(t, `out = '九'`, rune(20061)) + expect(t, `out = 'Æ'`, rune(198)) +}