Commit aea348a3 authored by Rob Pike's avatar Rob Pike

cmd/asm: add tests for erroneous expressions

Also add a couple more errors, such as modulo with a zero divisor.

Change-Id: If24c95477f7ae86cf4aef5b3460e9ec249ea5ae2
Reviewed-on: https://go-review.googlesource.com/11535Reviewed-by: 's avatarRuss Cox <rsc@golang.org>
parent 2b3b7dc1
// +build ignore
// Copyright 2015 The Go Authors. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -8,6 +6,7 @@ package asm ...@@ -8,6 +6,7 @@ package asm
import ( import (
"cmd/asm/internal/lex" "cmd/asm/internal/lex"
"strings"
"testing" "testing"
"text/scanner" "text/scanner"
) )
...@@ -53,6 +52,8 @@ var exprTests = []exprTest{ ...@@ -53,6 +52,8 @@ var exprTests = []exprTest{
{"3<<(2+4)", 3 << (2 + 4), true}, {"3<<(2+4)", 3 << (2 + 4), true},
// Junk at EOF. // Junk at EOF.
{"3 x", 3, false}, {"3 x", 3, false},
// Big number
{"4611686018427387904", 4611686018427387904, true},
} }
func TestExpr(t *testing.T) { func TestExpr(t *testing.T) {
...@@ -71,3 +72,60 @@ func TestExpr(t *testing.T) { ...@@ -71,3 +72,60 @@ func TestExpr(t *testing.T) {
} }
} }
} }
type badExprTest struct {
input string
error string // Empty means no error.
}
var badExprTests = []badExprTest{
{"0/0", "division by zero"},
{"3/0", "division by zero"},
{"(1<<63)/0", "divide of value with high bit set"},
{"3%0", "modulo by zero"},
{"(1<<63)%0", "modulo of value with high bit set"},
{"3<<-4", "negative left shift count"},
{"3<<(1<<63)", "negative left shift count"},
{"3>>-4", "negative right shift count"},
{"3>>(1<<63)", "negative right shift count"},
{"(1<<63)>>2", "right shift of value with high bit set"},
{"(1<<62)>>2", ""},
{`'\x80'`, "illegal UTF-8 encoding for character constant"},
{"(23*4", "missing closing paren"},
{")23*4", "unexpected ) evaluating expression"},
{"18446744073709551616", "value out of range"},
}
func TestBadExpr(t *testing.T) {
panicOnError = true
defer func() {
panicOnError = false
}()
for i, test := range badExprTests {
err := runBadTest(i, test, t)
if err == nil {
if test.error != "" {
t.Errorf("#%d: %q: expected error %q; got none", i, test.input, test.error)
}
continue
}
if !strings.Contains(err.Error(), test.error) {
t.Errorf("#%d: expected error %q; got %q", i, test.error, err)
continue
}
}
}
func runBadTest(i int, test badExprTest, t *testing.T) (err error) {
p := NewParser(nil, nil, nil) // Expression evaluation uses none of these fields of the parser.
p.start(lex.Tokenize(test.input))
defer func() {
e := recover()
var ok bool
if err, ok = e.(error); e != nil && !ok {
t.Fatal(e)
}
}()
p.expr()
return nil
}
...@@ -54,7 +54,14 @@ func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser { ...@@ -54,7 +54,14 @@ func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser {
} }
} }
// panicOnError is enable when testing to abort execution on the first error
// and turn it into a recoverable panic.
var panicOnError bool
func (p *Parser) errorf(format string, args ...interface{}) { func (p *Parser) errorf(format string, args ...interface{}) {
if panicOnError {
panic(fmt.Errorf(format, args...))
}
if p.histLineNum == p.errorLine { if p.histLineNum == p.errorLine {
// Only one error per line. // Only one error per line.
return return
...@@ -800,10 +807,23 @@ func (p *Parser) term() uint64 { ...@@ -800,10 +807,23 @@ func (p *Parser) term() uint64 {
if int64(value) < 0 { if int64(value) < 0 {
p.errorf("divide of value with high bit set") p.errorf("divide of value with high bit set")
} }
value /= p.factor() divisor := p.factor()
if divisor == 0 {
p.errorf("division by zero")
} else {
value /= divisor
}
case '%': case '%':
p.next() p.next()
value %= p.factor() divisor := p.factor()
if int64(value) < 0 {
p.errorf("modulo of value with high bit set")
}
if divisor == 0 {
p.errorf("modulo by zero")
} else {
value %= divisor
}
case lex.LSH: case lex.LSH:
p.next() p.next()
shift := p.factor() shift := p.factor()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment