diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 13:18:25 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 13:18:25 +0000 |
commit | 109be507377fe7f6e8819ac94041d3fdcdf6fd2f (patch) | |
tree | 2806a689f8fab4a2ec9fc949830ef270a91d667d /src/cmd/asm/internal/lex/lex_test.go | |
parent | Initial commit. (diff) | |
download | golang-1.19-109be507377fe7f6e8819ac94041d3fdcdf6fd2f.tar.xz golang-1.19-109be507377fe7f6e8819ac94041d3fdcdf6fd2f.zip |
Adding upstream version 1.19.8.upstream/1.19.8upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cmd/asm/internal/lex/lex_test.go')
-rw-r--r-- | src/cmd/asm/internal/lex/lex_test.go | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/src/cmd/asm/internal/lex/lex_test.go b/src/cmd/asm/internal/lex/lex_test.go new file mode 100644 index 0000000..51679d2 --- /dev/null +++ b/src/cmd/asm/internal/lex/lex_test.go @@ -0,0 +1,365 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package lex + +import ( + "bytes" + "strings" + "testing" + "text/scanner" +) + +type lexTest struct { + name string + input string + output string +} + +var lexTests = []lexTest{ + { + "empty", + "", + "", + }, + { + "simple", + "1 (a)", + "1.(.a.)", + }, + { + "simple define", + lines( + "#define A 1234", + "A", + ), + "1234.\n", + }, + { + "define without value", + "#define A", + "", + }, + { + "macro without arguments", + "#define A() 1234\n" + "A()\n", + "1234.\n", + }, + { + "macro with just parens as body", + "#define A () \n" + "A\n", + "(.).\n", + }, + { + "macro with parens but no arguments", + "#define A (x) \n" + "A\n", + "(.x.).\n", + }, + { + "macro with arguments", + "#define A(x, y, z) x+z+y\n" + "A(1, 2, 3)\n", + "1.+.3.+.2.\n", + }, + { + "argumented macro invoked without arguments", + lines( + "#define X() foo ", + "X()", + "X", + ), + "foo.\n.X.\n", + }, + { + "multiline macro without arguments", + lines( + "#define A 1\\", + "\t2\\", + "\t3", + "before", + "A", + "after", + ), + "before.\n.1.\n.2.\n.3.\n.after.\n", + }, + { + "multiline macro with arguments", + lines( + "#define A(a, b, c) a\\", + "\tb\\", + "\tc", + "before", + "A(1, 2, 3)", + "after", + ), + "before.\n.1.\n.2.\n.3.\n.after.\n", + }, + { + "LOAD macro", + lines( + "#define LOAD(off, reg) \\", + "\tMOVBLZX (off*4)(R12), reg \\", + "\tADDB reg, DX", + "", + "LOAD(8, AX)", + ), + "\n.\n.MOVBLZX.(.8.*.4.).(.R12.).,.AX.\n.ADDB.AX.,.DX.\n", + }, + { + "nested multiline macro", + lines( + "#define KEYROUND(xmm, load, off, r1, r2, index) \\", + "\tMOVBLZX (BP)(DX*4), R8 \\", + "\tload((off+1), r2) \\", + "\tMOVB R8, (off*4)(R12) \\", + "\tPINSRW $index, (BP)(R8*4), xmm", + "#define LOAD(off, reg) \\", + "\tMOVBLZX (off*4)(R12), reg \\", + "\tADDB reg, DX", + "KEYROUND(X0, LOAD, 8, AX, BX, 0)", + ), + "\n.MOVBLZX.(.BP.).(.DX.*.4.).,.R8.\n.\n.MOVBLZX.(.(.8.+.1.).*.4.).(.R12.).,.BX.\n.ADDB.BX.,.DX.\n.MOVB.R8.,.(.8.*.4.).(.R12.).\n.PINSRW.$.0.,.(.BP.).(.R8.*.4.).,.X0.\n", + }, + { + "taken #ifdef", + lines( + "#define A", + "#ifdef A", + "#define B 1234", + "#endif", + "B", + ), + "1234.\n", + }, + { + "not taken #ifdef", + lines( + "#ifdef A", + "#define B 1234", + "#endif", + "B", + ), + "B.\n", + }, + { + "taken #ifdef with else", + lines( + "#define A", + "#ifdef A", + "#define B 1234", + "#else", + "#define B 5678", + "#endif", + "B", + ), + "1234.\n", + }, + { + "not taken #ifdef with else", + lines( + "#ifdef A", + "#define B 1234", + "#else", + "#define B 5678", + "#endif", + "B", + ), + "5678.\n", + }, + { + "nested taken/taken #ifdef", + lines( + "#define A", + "#define B", + "#ifdef A", + "#ifdef B", + "#define C 1234", + "#else", + "#define C 5678", + "#endif", + "#endif", + "C", + ), + "1234.\n", + }, + { + "nested taken/not-taken #ifdef", + lines( + "#define A", + "#ifdef A", + "#ifdef B", + "#define C 1234", + "#else", + "#define C 5678", + "#endif", + "#endif", + "C", + ), + "5678.\n", + }, + { + "nested not-taken/would-be-taken #ifdef", + lines( + "#define B", + "#ifdef A", + "#ifdef B", + "#define C 1234", + "#else", + "#define C 5678", + "#endif", + "#endif", + "C", + ), + "C.\n", + }, + { + "nested not-taken/not-taken #ifdef", + lines( + "#ifdef A", + "#ifdef B", + "#define C 1234", + "#else", + "#define C 5678", + "#endif", + "#endif", + "C", + ), + "C.\n", + }, + { + "nested #define", + lines( + "#define A #define B THIS", + "A", + "B", + ), + "THIS.\n", + }, + { + "nested #define with args", + lines( + "#define A #define B(x) x", + "A", + "B(THIS)", + ), + "THIS.\n", + }, + /* This one fails. See comment in Slice.Col. + { + "nested #define with args", + lines( + "#define A #define B (x) x", + "A", + "B(THIS)", + ), + "x.\n", + }, + */ +} + +func TestLex(t *testing.T) { + for _, test := range lexTests { + input := NewInput(test.name) + input.Push(NewTokenizer(test.name, strings.NewReader(test.input), nil)) + result := drain(input) + if result != test.output { + t.Errorf("%s: got %q expected %q", test.name, result, test.output) + } + } +} + +// lines joins the arguments together as complete lines. +func lines(a ...string) string { + return strings.Join(a, "\n") + "\n" +} + +// drain returns a single string representing the processed input tokens. +func drain(input *Input) string { + var buf bytes.Buffer + for { + tok := input.Next() + if tok == scanner.EOF { + return buf.String() + } + if tok == '#' { + continue + } + if buf.Len() > 0 { + buf.WriteByte('.') + } + buf.WriteString(input.Text()) + } +} + +type badLexTest struct { + input string + error string +} + +var badLexTests = []badLexTest{ + { + "3 #define foo bar\n", + "'#' must be first item on line", + }, + { + "#ifdef foo\nhello", + "unclosed #ifdef or #ifndef", + }, + { + "#ifndef foo\nhello", + "unclosed #ifdef or #ifndef", + }, + { + "#ifdef foo\nhello\n#else\nbye", + "unclosed #ifdef or #ifndef", + }, + { + "#define A() A()\nA()", + "recursive macro invocation", + }, + { + "#define A a\n#define A a\n", + "redefinition of macro", + }, + { + "#define A a", + "no newline after macro definition", + }, +} + +func TestBadLex(t *testing.T) { + for _, test := range badLexTests { + input := NewInput(test.error) + input.Push(NewTokenizer(test.error, strings.NewReader(test.input), nil)) + err := firstError(input) + if err == nil { + t.Errorf("%s: got no error", test.error) + continue + } + if !strings.Contains(err.Error(), test.error) { + t.Errorf("got error %q expected %q", err.Error(), test.error) + } + } +} + +// firstError returns the first error value triggered by the input. +func firstError(input *Input) (err error) { + panicOnError = true + defer func() { + panicOnError = false + switch e := recover(); e := e.(type) { + case nil: + case error: + err = e + default: + panic(e) + } + }() + + for { + tok := input.Next() + if tok == scanner.EOF { + return + } + } +} |