Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/asm/internal/lex/lex_test.go

Documentation: cmd/asm/internal/lex

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package lex
     6  
     7  import (
     8  	"bytes"
     9  	"strings"
    10  	"testing"
    11  	"text/scanner"
    12  )
    13  
    14  type lexTest struct {
    15  	name   string
    16  	input  string
    17  	output string
    18  }
    19  
    20  var lexTests = []lexTest{
    21  	{
    22  		"empty",
    23  		"",
    24  		"",
    25  	},
    26  	{
    27  		"simple",
    28  		"1 (a)",
    29  		"1.(.a.)",
    30  	},
    31  	{
    32  		"simple define",
    33  		lines(
    34  			"#define A 1234",
    35  			"A",
    36  		),
    37  		"1234.\n",
    38  	},
    39  	{
    40  		"define without value",
    41  		"#define A",
    42  		"",
    43  	},
    44  	{
    45  		"macro without arguments",
    46  		"#define A() 1234\n" + "A()\n",
    47  		"1234.\n",
    48  	},
    49  	{
    50  		"macro with just parens as body",
    51  		"#define A () \n" + "A\n",
    52  		"(.).\n",
    53  	},
    54  	{
    55  		"macro with parens but no arguments",
    56  		"#define A (x) \n" + "A\n",
    57  		"(.x.).\n",
    58  	},
    59  	{
    60  		"macro with arguments",
    61  		"#define A(x, y, z) x+z+y\n" + "A(1, 2, 3)\n",
    62  		"1.+.3.+.2.\n",
    63  	},
    64  	{
    65  		"argumented macro invoked without arguments",
    66  		lines(
    67  			"#define X() foo ",
    68  			"X()",
    69  			"X",
    70  		),
    71  		"foo.\n.X.\n",
    72  	},
    73  	{
    74  		"multiline macro without arguments",
    75  		lines(
    76  			"#define A 1\\",
    77  			"\t2\\",
    78  			"\t3",
    79  			"before",
    80  			"A",
    81  			"after",
    82  		),
    83  		"before.\n.1.\n.2.\n.3.\n.after.\n",
    84  	},
    85  	{
    86  		"multiline macro with arguments",
    87  		lines(
    88  			"#define A(a, b, c) a\\",
    89  			"\tb\\",
    90  			"\tc",
    91  			"before",
    92  			"A(1, 2, 3)",
    93  			"after",
    94  		),
    95  		"before.\n.1.\n.2.\n.3.\n.after.\n",
    96  	},
    97  	{
    98  		"LOAD macro",
    99  		lines(
   100  			"#define LOAD(off, reg) \\",
   101  			"\tMOVBLZX	(off*4)(R12),	reg \\",
   102  			"\tADDB	reg,		DX",
   103  			"",
   104  			"LOAD(8, AX)",
   105  		),
   106  		"\n.\n.MOVBLZX.(.8.*.4.).(.R12.).,.AX.\n.ADDB.AX.,.DX.\n",
   107  	},
   108  	{
   109  		"nested multiline macro",
   110  		lines(
   111  			"#define KEYROUND(xmm, load, off, r1, r2, index) \\",
   112  			"\tMOVBLZX	(BP)(DX*4),	R8 \\",
   113  			"\tload((off+1), r2) \\",
   114  			"\tMOVB	R8,		(off*4)(R12) \\",
   115  			"\tPINSRW	$index, (BP)(R8*4), xmm",
   116  			"#define LOAD(off, reg) \\",
   117  			"\tMOVBLZX	(off*4)(R12),	reg \\",
   118  			"\tADDB	reg,		DX",
   119  			"KEYROUND(X0, LOAD, 8, AX, BX, 0)",
   120  		),
   121  		"\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",
   122  	},
   123  	{
   124  		"taken #ifdef",
   125  		lines(
   126  			"#define A",
   127  			"#ifdef A",
   128  			"#define B 1234",
   129  			"#endif",
   130  			"B",
   131  		),
   132  		"1234.\n",
   133  	},
   134  	{
   135  		"not taken #ifdef",
   136  		lines(
   137  			"#ifdef A",
   138  			"#define B 1234",
   139  			"#endif",
   140  			"B",
   141  		),
   142  		"B.\n",
   143  	},
   144  	{
   145  		"taken #ifdef with else",
   146  		lines(
   147  			"#define A",
   148  			"#ifdef A",
   149  			"#define B 1234",
   150  			"#else",
   151  			"#define B 5678",
   152  			"#endif",
   153  			"B",
   154  		),
   155  		"1234.\n",
   156  	},
   157  	{
   158  		"not taken #ifdef with else",
   159  		lines(
   160  			"#ifdef A",
   161  			"#define B 1234",
   162  			"#else",
   163  			"#define B 5678",
   164  			"#endif",
   165  			"B",
   166  		),
   167  		"5678.\n",
   168  	},
   169  	{
   170  		"nested taken/taken #ifdef",
   171  		lines(
   172  			"#define A",
   173  			"#define B",
   174  			"#ifdef A",
   175  			"#ifdef B",
   176  			"#define C 1234",
   177  			"#else",
   178  			"#define C 5678",
   179  			"#endif",
   180  			"#endif",
   181  			"C",
   182  		),
   183  		"1234.\n",
   184  	},
   185  	{
   186  		"nested taken/not-taken #ifdef",
   187  		lines(
   188  			"#define A",
   189  			"#ifdef A",
   190  			"#ifdef B",
   191  			"#define C 1234",
   192  			"#else",
   193  			"#define C 5678",
   194  			"#endif",
   195  			"#endif",
   196  			"C",
   197  		),
   198  		"5678.\n",
   199  	},
   200  	{
   201  		"nested not-taken/would-be-taken #ifdef",
   202  		lines(
   203  			"#define B",
   204  			"#ifdef A",
   205  			"#ifdef B",
   206  			"#define C 1234",
   207  			"#else",
   208  			"#define C 5678",
   209  			"#endif",
   210  			"#endif",
   211  			"C",
   212  		),
   213  		"C.\n",
   214  	},
   215  	{
   216  		"nested not-taken/not-taken #ifdef",
   217  		lines(
   218  			"#ifdef A",
   219  			"#ifdef B",
   220  			"#define C 1234",
   221  			"#else",
   222  			"#define C 5678",
   223  			"#endif",
   224  			"#endif",
   225  			"C",
   226  		),
   227  		"C.\n",
   228  	},
   229  	{
   230  		"nested #define",
   231  		lines(
   232  			"#define A #define B THIS",
   233  			"A",
   234  			"B",
   235  		),
   236  		"THIS.\n",
   237  	},
   238  	{
   239  		"nested #define with args",
   240  		lines(
   241  			"#define A #define B(x) x",
   242  			"A",
   243  			"B(THIS)",
   244  		),
   245  		"THIS.\n",
   246  	},
   247  	/* This one fails. See comment in Slice.Col.
   248  	{
   249  		"nested #define with args",
   250  		lines(
   251  			"#define A #define B (x) x",
   252  			"A",
   253  			"B(THIS)",
   254  		),
   255  		"x.\n",
   256  	},
   257  	*/
   258  }
   259  
   260  func TestLex(t *testing.T) {
   261  	for _, test := range lexTests {
   262  		input := NewInput(test.name)
   263  		input.Push(NewTokenizer(test.name, strings.NewReader(test.input), nil))
   264  		result := drain(input)
   265  		if result != test.output {
   266  			t.Errorf("%s: got %q expected %q", test.name, result, test.output)
   267  		}
   268  	}
   269  }
   270  
   271  // lines joins the arguments together as complete lines.
   272  func lines(a ...string) string {
   273  	return strings.Join(a, "\n") + "\n"
   274  }
   275  
   276  // drain returns a single string representing the processed input tokens.
   277  func drain(input *Input) string {
   278  	var buf bytes.Buffer
   279  	for {
   280  		tok := input.Next()
   281  		if tok == scanner.EOF {
   282  			return buf.String()
   283  		}
   284  		if tok == '#' {
   285  			continue
   286  		}
   287  		if buf.Len() > 0 {
   288  			buf.WriteByte('.')
   289  		}
   290  		buf.WriteString(input.Text())
   291  	}
   292  }
   293  
   294  type badLexTest struct {
   295  	input string
   296  	error string
   297  }
   298  
   299  var badLexTests = []badLexTest{
   300  	{
   301  		"3 #define foo bar\n",
   302  		"'#' must be first item on line",
   303  	},
   304  	{
   305  		"#ifdef foo\nhello",
   306  		"unclosed #ifdef or #ifndef",
   307  	},
   308  	{
   309  		"#ifndef foo\nhello",
   310  		"unclosed #ifdef or #ifndef",
   311  	},
   312  	{
   313  		"#ifdef foo\nhello\n#else\nbye",
   314  		"unclosed #ifdef or #ifndef",
   315  	},
   316  	{
   317  		"#define A() A()\nA()",
   318  		"recursive macro invocation",
   319  	},
   320  	{
   321  		"#define A a\n#define A a\n",
   322  		"redefinition of macro",
   323  	},
   324  	{
   325  		"#define A a",
   326  		"no newline after macro definition",
   327  	},
   328  }
   329  
   330  func TestBadLex(t *testing.T) {
   331  	for _, test := range badLexTests {
   332  		input := NewInput(test.error)
   333  		input.Push(NewTokenizer(test.error, strings.NewReader(test.input), nil))
   334  		err := firstError(input)
   335  		if err == nil {
   336  			t.Errorf("%s: got no error", test.error)
   337  			continue
   338  		}
   339  		if !strings.Contains(err.Error(), test.error) {
   340  			t.Errorf("got error %q expected %q", err.Error(), test.error)
   341  		}
   342  	}
   343  }
   344  
   345  // firstError returns the first error value triggered by the input.
   346  func firstError(input *Input) (err error) {
   347  	panicOnError = true
   348  	defer func() {
   349  		panicOnError = false
   350  		switch e := recover(); e := e.(type) {
   351  		case nil:
   352  		case error:
   353  			err = e
   354  		default:
   355  			panic(e)
   356  		}
   357  	}()
   358  
   359  	for {
   360  		tok := input.Next()
   361  		if tok == scanner.EOF {
   362  			return
   363  		}
   364  	}
   365  }
   366  

View as plain text