github.com/NeowayLabs/nash@v0.2.2-0.20200127205349-a227041ffd50/scanner/lex_test.go (about)

     1  package scanner
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  
     7  	"github.com/madlambda/nash/token"
     8  )
     9  import "testing"
    10  
    11  func testTable(name, content string, expected []Token, t *testing.T) {
    12  	l := Lex(name, content)
    13  
    14  	if l == nil {
    15  		t.Errorf("Failed to initialize lexer")
    16  		return
    17  	}
    18  
    19  	if l.Tokens == nil {
    20  		t.Errorf("Failed to initialize lexer")
    21  		return
    22  	}
    23  
    24  	result := make([]Token, 0, 1024)
    25  
    26  	for i := range l.Tokens {
    27  		result = append(result, i)
    28  	}
    29  
    30  	if len(result) != len(expected) {
    31  		t.Errorf("Failed to parse commands, length differs %d != %d",
    32  			len(result), len(expected))
    33  
    34  		fmt.Printf("Parsing content: %s\n", content)
    35  
    36  		for _, res := range result {
    37  			fmt.Printf("parsed: %+v\n", res)
    38  		}
    39  
    40  		fmt.Printf("\n")
    41  
    42  		for _, exp := range expected {
    43  			fmt.Printf("expect: %+v\n", exp)
    44  		}
    45  
    46  		return
    47  	}
    48  
    49  	for i := 0; i < len(expected); i++ {
    50  		if expected[i].typ != result[i].typ {
    51  			t.Errorf("'%s (%s)' != '%s (%s)'", expected[i].typ, expected[i].val, result[i].typ, result[i].val)
    52  			return
    53  		}
    54  
    55  		if expected[i].val != result[i].val {
    56  			t.Errorf("Parsing '%s':\n\terror: '%s' != '%s'", content, expected[i].val, result[i].val)
    57  			return
    58  		}
    59  	}
    60  }
    61  
    62  func TestLexerCommandStringArgs(t *testing.T) {
    63  	expected := []Token{
    64  		{typ: token.Ident, val: "echo"},
    65  		{typ: token.Ident, val: "hello"},
    66  		{typ: token.Semicolon, val: ";"},
    67  		{typ: token.Ident, val: "echo"},
    68  		{typ: token.String, val: "hello"},
    69  		{typ: token.Semicolon, val: ";"},
    70  		{typ: token.EOF},
    71  	}
    72  
    73  	testTable("test args", `echo hello
    74  echo "hello"`, expected, t)
    75  }
    76  
    77  func TestLexerTokenToString(t *testing.T) {
    78  	it := Token{
    79  		typ: token.EOF,
    80  	}
    81  
    82  	if it.String() != "EOF" {
    83  		t.Errorf("Wrong eof string: %s", it.String())
    84  	}
    85  
    86  	it = Token{
    87  		typ: token.Illegal,
    88  		val: "some error",
    89  	}
    90  
    91  	if it.String() != "ERROR: some error" {
    92  		t.Errorf("wrong error string: %s", it.String())
    93  	}
    94  
    95  	it = Token{
    96  		typ: token.Ident,
    97  		val: "echo",
    98  	}
    99  
   100  	if it.String() != "IDENT" {
   101  		t.Errorf("wrong command name: %s", it.String())
   102  	}
   103  
   104  	it = Token{
   105  		typ: token.Ident,
   106  		val: "echoooooooooooooooooooooooo",
   107  	}
   108  
   109  	// test if long names are truncated
   110  	if it.String() != "IDENT" {
   111  		t.Errorf("wrong command name: %s", it.String())
   112  	}
   113  }
   114  
   115  func TestLexerShebangOnly(t *testing.T) {
   116  	expected := []Token{
   117  		{
   118  			typ: token.Comment,
   119  			val: "#!/bin/nash",
   120  		},
   121  		{
   122  			typ: token.EOF,
   123  		},
   124  	}
   125  
   126  	testTable("testShebangonly", "#!/bin/nash\n", expected, t)
   127  }
   128  
   129  func TestLexerSimpleSetEnvAssignment(t *testing.T) {
   130  	expected := []Token{
   131  		{typ: token.SetEnv, val: "setenv"},
   132  		{typ: token.Ident, val: "name"},
   133  		{typ: token.Semicolon, val: ";"},
   134  		{typ: token.EOF},
   135  	}
   136  
   137  	testTable("testSet", `setenv name`, expected, t)
   138  }
   139  
   140  func TestLexerSimpleAssignment(t *testing.T) {
   141  	expected := []Token{
   142  		{typ: token.Ident, val: "test"},
   143  		{typ: token.Assign, val: "="},
   144  		{typ: token.String, val: "value"},
   145  		{typ: token.Semicolon, val: ";"},
   146  		{typ: token.EOF},
   147  	}
   148  
   149  	testTable("testAssignment", `test="value"`, expected, t)
   150  	testTable("testAssignment spacy", `test = "value"`, expected, t)
   151  	testTable("testAssignment spacy", `test          ="value"`, expected, t)
   152  	testTable("testAssignment spacy", `test=           "value"`, expected, t)
   153  	testTable("testAssignment spacy", `test	="value"`, expected, t)
   154  	testTable("testAssignment spacy", `test		="value"`, expected, t)
   155  	testTable("testAssignment spacy", `test =	"value"`, expected, t)
   156  
   157  	expected = []Token{
   158  		{typ: token.Ident, val: "test"},
   159  		{typ: token.Assign, val: "="},
   160  		{typ: token.String, val: "value"},
   161  		{typ: token.Semicolon, val: ";"},
   162  		{typ: token.Ident, val: "other"},
   163  		{typ: token.Assign, val: "="},
   164  		{typ: token.String, val: "other"},
   165  		{typ: token.Semicolon, val: ";"},
   166  		{typ: token.EOF},
   167  	}
   168  
   169  	testTable("test multiple separate assignments", `
   170          test="value"
   171          other="other"`, expected, t)
   172  
   173  	expected = []Token{
   174  		{typ: token.Ident, val: "test"},
   175  		{typ: token.Assign, val: "="},
   176  		{typ: token.String, val: "value"},
   177  		{typ: token.Semicolon, val: ";"},
   178  		{typ: token.Ident, val: "other"},
   179  		{typ: token.Assign, val: "="},
   180  		{typ: token.Variable, val: "$test"},
   181  		{typ: token.Semicolon, val: ";"},
   182  		{typ: token.Ident, val: "echo"},
   183  		{typ: token.Variable, val: "$other"},
   184  		{typ: token.Semicolon, val: ";"},
   185  		{typ: token.EOF},
   186  	}
   187  
   188  	testTable("test multiple separate assignments", `
   189          test="value"
   190          other=$test
   191          echo $other`, expected, t)
   192  
   193  	expected = []Token{
   194  		{typ: token.Ident, val: "STALI_SRC"},
   195  		{typ: token.Assign, val: "="},
   196  		{typ: token.Variable, val: "$PWD"},
   197  		{typ: token.Plus, val: "+"},
   198  		{typ: token.String, val: "/src"},
   199  		{typ: token.Semicolon, val: ";"},
   200  		{typ: token.EOF},
   201  	}
   202  
   203  	testTable("test underscore", `STALI_SRC = $PWD + "/src"`, expected, t)
   204  
   205  	expected = []Token{
   206  		{typ: token.Ident, val: "PROMPT"},
   207  		{typ: token.Assign, val: "="},
   208  		{typ: token.String, val: "("},
   209  		{typ: token.Plus, val: "+"},
   210  		{typ: token.Variable, val: "$path"},
   211  		{typ: token.Plus, val: "+"},
   212  		{typ: token.String, val: ")"},
   213  		{typ: token.Plus, val: "+"},
   214  		{typ: token.Variable, val: "$PROMPT"},
   215  		{typ: token.Semicolon, val: ";"},
   216  		{typ: token.EOF},
   217  	}
   218  
   219  	testTable("test concat with parenthesis", `PROMPT = "("+$path+")"+$PROMPT`, expected, t)
   220  
   221  	expected = []Token{
   222  		{typ: token.Ident, val: "a"},
   223  		{typ: token.LBrack, val: "["},
   224  		{typ: token.Number, val: "0"},
   225  		{typ: token.RBrack, val: "]"},
   226  		{typ: token.Assign, val: "="},
   227  		{typ: token.String, val: "test"},
   228  		{typ: token.Semicolon, val: ";"},
   229  		{typ: token.EOF},
   230  	}
   231  
   232  	testTable("test index assignment", `a[0] = "test"`, expected, t)
   233  
   234  }
   235  
   236  func TestLexerListAssignment(t *testing.T) {
   237  	expected := []Token{
   238  		{typ: token.Ident, val: "test"},
   239  		{typ: token.Assign, val: "="},
   240  		{typ: token.LParen, val: "("},
   241  		{typ: token.Ident, val: "plan9"},
   242  		{typ: token.Ident, val: "from"},
   243  		{typ: token.Ident, val: "bell"},
   244  		{typ: token.Ident, val: "labs"},
   245  		{typ: token.RParen, val: ")"},
   246  		{typ: token.Semicolon, val: ";"},
   247  		{typ: token.EOF},
   248  	}
   249  
   250  	testTable("testListAssignment", "test=( plan9 from bell labs )", expected, t)
   251  	testTable("testListAssignment no space", "test=(plan9 from bell labs)", expected, t)
   252  	testTable("testListAssignment multiline", `test = (
   253  	plan9
   254  	from
   255  	bell
   256  	labs
   257  )`, expected, t)
   258  
   259  	expected = []Token{
   260  		{typ: token.Ident, val: "test"},
   261  		{typ: token.Assign, val: "="},
   262  		{typ: token.LParen, val: "("},
   263  		{typ: token.String, val: "plan9"},
   264  		{typ: token.Ident, val: "from"},
   265  		{typ: token.String, val: "bell"},
   266  		{typ: token.Ident, val: "labs"},
   267  		{typ: token.RParen, val: ")"},
   268  		{typ: token.Semicolon, val: ";"},
   269  		{typ: token.EOF},
   270  	}
   271  
   272  	testTable("testListAssignment mixed args", `test=( "plan9" from "bell" labs )`, expected, t)
   273  	testTable("testListAssignment mixed args", `test=("plan9" from "bell" labs)`, expected, t)
   274  	testTable("testListAssignment mixed args", `test = (
   275          "plan9"
   276          from
   277          "bell"
   278          labs
   279  )`, expected, t)
   280  
   281  	expected = []Token{
   282  		{typ: token.Ident, val: "test"},
   283  		{typ: token.Assign, val: "="},
   284  		{typ: token.LParen, val: "("},
   285  		{typ: token.Variable, val: "$plan9"},
   286  		{typ: token.Ident, val: "from"},
   287  		{typ: token.Variable, val: "$bell"},
   288  		{typ: token.Ident, val: "labs"},
   289  		{typ: token.RParen, val: ")"},
   290  		{typ: token.Semicolon, val: ";"},
   291  		{typ: token.EOF},
   292  	}
   293  
   294  	testTable("testListAssignment mixed args", `test=( $plan9 from $bell labs )`, expected, t)
   295  	testTable("testListAssignment mixed args", `test=($plan9 from $bell labs)`, expected, t)
   296  	testTable("testListAssignment mixed args", `test = (
   297          $plan9
   298          from
   299          $bell
   300          labs
   301  )`, expected, t)
   302  }
   303  
   304  func TestLexerListOfLists(t *testing.T) {
   305  	expected := []Token{
   306  		{typ: token.Ident, val: "l"},
   307  		{typ: token.Assign, val: "="},
   308  		{typ: token.LParen, val: "("},
   309  		{typ: token.LParen, val: "("},
   310  		{typ: token.RParen, val: ")"},
   311  		{typ: token.RParen, val: ")"},
   312  		{typ: token.Semicolon, val: ";"},
   313  		{typ: token.EOF},
   314  	}
   315  
   316  	testTable("testlistoflists", `l = (())`, expected, t)
   317  	testTable("testlistoflists", `l = (
   318  		()
   319  	)`, expected, t)
   320  
   321  	expected = []Token{
   322  		{typ: token.Ident, val: "l"},
   323  		{typ: token.Assign, val: "="},
   324  		{typ: token.LParen, val: "("},
   325  
   326  		{typ: token.LParen, val: "("},
   327  		{typ: token.Ident, val: "plan9"},
   328  		{typ: token.Ident, val: "from"},
   329  		{typ: token.Ident, val: "bell"},
   330  		{typ: token.Ident, val: "labs"},
   331  		{typ: token.RParen, val: ")"},
   332  
   333  		{typ: token.LParen, val: "("},
   334  		{typ: token.Ident, val: "linux"},
   335  		{typ: token.RParen, val: ")"},
   336  
   337  		{typ: token.RParen, val: ")"},
   338  		{typ: token.Semicolon, val: ";"},
   339  		{typ: token.EOF},
   340  	}
   341  
   342  	testTable("testlistoflists", `l = ((plan9 from bell labs) (linux))`, expected, t)
   343  	testTable("testlistoflists", `l = (
   344  		(plan9 from bell labs)
   345  		(linux)
   346  	)`, expected, t)
   347  
   348  }
   349  
   350  func TestLexerInvalidAssignments(t *testing.T) {
   351  	expected := []Token{
   352  		{typ: token.Ident, val: "test"},
   353  		{typ: token.Assign, val: "="},
   354  		{typ: token.String, val: "value"},
   355  		{typ: token.Ident, val: "other"},
   356  		{typ: token.Semicolon, val: ";"},
   357  		{typ: token.EOF},
   358  	}
   359  
   360  	testTable("testInvalidAssignments", `test="value" other`, expected, t)
   361  }
   362  
   363  func TestLexerSimpleCommand(t *testing.T) {
   364  	expected := []Token{
   365  		{typ: token.Ident, val: "echo"},
   366  		{typ: token.String, val: "hello world"},
   367  		{typ: token.Semicolon, val: ";"},
   368  		{typ: token.EOF},
   369  	}
   370  
   371  	testTable("testSimpleCommand", `echo "hello world"`, expected, t)
   372  
   373  	expected = []Token{
   374  		{typ: token.Ident, val: "echo"},
   375  		{typ: token.Arg, val: "rootfs-x86_64"},
   376  		{typ: token.Semicolon, val: ";"},
   377  		{typ: token.EOF},
   378  	}
   379  
   380  	testTable("testSimpleCommand", `echo rootfs-x86_64`, expected, t)
   381  
   382  	expected = []Token{
   383  		{typ: token.Ident, val: "git"},
   384  		{typ: token.Ident, val: "clone"},
   385  		{typ: token.Arg, val: "--depth=1"},
   386  		{typ: token.Arg, val: "http://git.sta.li/toolchain"},
   387  		{typ: token.Semicolon, val: ";"},
   388  		{typ: token.EOF},
   389  	}
   390  
   391  	testTable("testSimpleCommand", `git clone --depth=1 http://git.sta.li/toolchain`, expected, t)
   392  
   393  	expected = []Token{
   394  		{typ: token.Ident, val: "ls"},
   395  		{typ: token.Variable, val: "$GOPATH"},
   396  		{typ: token.Semicolon, val: ";"},
   397  		{typ: token.EOF},
   398  	}
   399  
   400  	testTable("testSimpleCommand", `ls $GOPATH`, expected, t)
   401  
   402  	expected = []Token{
   403  		{typ: token.Ident, val: "ls"},
   404  		{typ: token.Variable, val: "$GOPATH"},
   405  		{typ: token.Plus, val: "+"},
   406  		{typ: token.String, val: "/src/github.com"},
   407  		{typ: token.Semicolon, val: ";"},
   408  		{typ: token.EOF},
   409  	}
   410  
   411  	testTable("testSimpleCommand", `ls $GOPATH+"/src/github.com"`, expected, t)
   412  
   413  	expected = []Token{
   414  		{typ: token.Ident, val: "ls"},
   415  		{typ: token.String, val: "/src/github.com"},
   416  		{typ: token.Plus, val: "+"},
   417  		{typ: token.Variable, val: "$GOPATH"},
   418  		{typ: token.Semicolon, val: ";"},
   419  		{typ: token.EOF},
   420  	}
   421  
   422  	testTable("testSimpleCommand", `ls "/src/github.com"+$GOPATH`, expected, t)
   423  
   424  	expected = []Token{
   425  		{typ: token.Ident, val: "ls"},
   426  		{typ: token.String, val: "/home/user"},
   427  		{typ: token.Plus, val: "+"},
   428  		{typ: token.String, val: "/.gvm/pkgsets/global/src"},
   429  		{typ: token.Semicolon, val: ";"},
   430  		{typ: token.EOF},
   431  	}
   432  
   433  	testTable("testSimpleCommand", `ls "/home/user" + "/.gvm/pkgsets/global/src"`, expected, t)
   434  
   435  	expected = []Token{
   436  		{typ: token.Arg, val: "./rkt"},
   437  		{typ: token.Semicolon, val: ";"}, // automatic semicolon insertion
   438  		{typ: token.EOF},
   439  	}
   440  
   441  	testTable("test local command", "./rkt", expected, t)
   442  
   443  }
   444  
   445  func TestLexerPipe(t *testing.T) {
   446  	expected := []Token{
   447  		{typ: token.Ident, val: "ls"},
   448  		{typ: token.Pipe, val: "|"},
   449  		{typ: token.Ident, val: "wc"},
   450  		{typ: token.Arg, val: "-l"},
   451  		{typ: token.Semicolon, val: ";"},
   452  		{typ: token.EOF},
   453  	}
   454  
   455  	testTable("testPipe", `ls | wc -l`, expected, t)
   456  
   457  	expected = []Token{
   458  		{typ: token.Ident, val: "ls"},
   459  		{typ: token.Arg, val: "-l"},
   460  		{typ: token.Pipe, val: "|"},
   461  		{typ: token.Ident, val: "wc"},
   462  		{typ: token.Pipe, val: "|"},
   463  		{typ: token.Ident, val: "awk"},
   464  		{typ: token.String, val: "{print $1}"},
   465  		{typ: token.Semicolon, val: ";"},
   466  		{typ: token.EOF},
   467  	}
   468  
   469  	testTable("testPipe", `ls -l | wc | awk "{print $1}"`, expected, t)
   470  
   471  	expected = []Token{
   472  		{typ: token.Ident, val: "go"},
   473  		{typ: token.Ident, val: "tool"},
   474  		{typ: token.Ident, val: "vet"},
   475  		{typ: token.Arg, val: "-h"},
   476  		{typ: token.Gt, val: ">"},
   477  		{typ: token.LBrack, val: "["},
   478  		{typ: token.Number, val: "2"},
   479  		{typ: token.Assign, val: "="},
   480  		{typ: token.Number, val: "1"},
   481  		{typ: token.RBrack, val: "]"},
   482  		{typ: token.Pipe, val: "|"},
   483  		{typ: token.Ident, val: "grep"},
   484  		{typ: token.Ident, val: "log"},
   485  		{typ: token.Semicolon, val: ";"},
   486  		{typ: token.EOF},
   487  	}
   488  
   489  	testTable("testPipe with redirection", `go tool vet -h >[2=1] | grep log`, expected, t)
   490  
   491  	expected = []Token{
   492  		{typ: token.Ident, val: "go"},
   493  		{typ: token.Ident, val: "tool"},
   494  		{typ: token.Ident, val: "vet"},
   495  		{typ: token.Arg, val: "-h"},
   496  		{typ: token.Gt, val: ">"},
   497  		{typ: token.Arg, val: "out.log"},
   498  		{typ: token.Pipe, val: "|"},
   499  		{typ: token.Ident, val: "grep"},
   500  		{typ: token.Ident, val: "log"},
   501  		{typ: token.Semicolon, val: ";"},
   502  		{typ: token.EOF},
   503  	}
   504  
   505  	testTable("testPipe with redirection", `go tool vet -h > out.log | grep log`, expected, t)
   506  }
   507  
   508  func TestPipeFunctions(t *testing.T) {
   509  	expected := []Token{
   510  		{typ: token.Ident, val: "echo"},
   511  		{typ: token.String, val: "some thing"},
   512  		{typ: token.Pipe, val: "|"},
   513  		{typ: token.Ident, val: "replace"},
   514  		{typ: token.LParen, val: "("},
   515  		{typ: token.String, val: " "},
   516  		{typ: token.Comma, val: ","},
   517  		{typ: token.String, val: "|"},
   518  		{typ: token.RParen, val: ")"},
   519  		{typ: token.Semicolon, val: ";"},
   520  		{typ: token.EOF},
   521  	}
   522  
   523  	testTable("test pipe with function",
   524  		`echo "some thing" | replace(" ", "|")`,
   525  		expected, t)
   526  }
   527  
   528  func TestLexerUnquoteArg(t *testing.T) {
   529  	expected := []Token{
   530  		{typ: token.Ident, val: "echo"},
   531  		{typ: token.Ident, val: "hello"},
   532  		{typ: token.Semicolon, val: ";"},
   533  		{typ: token.EOF},
   534  	}
   535  
   536  	testTable("testSimpleCommand", `echo hello`, expected, t)
   537  
   538  	expected = []Token{
   539  		{typ: token.Ident, val: "echo"},
   540  		{typ: token.Arg, val: "hello-world"},
   541  		{typ: token.Semicolon, val: ";"},
   542  		{typ: token.EOF},
   543  	}
   544  
   545  	testTable("testSimpleCommand", `echo hello-world`, expected, t)
   546  
   547  	expected = []Token{
   548  		{typ: token.Ident, val: "echo"},
   549  		{typ: token.Comment, val: "#hello-world"},
   550  		{typ: token.Semicolon, val: ";"},
   551  		{typ: token.EOF},
   552  	}
   553  
   554  	testTable("testSimpleCommand", `echo #hello-world`, expected, t)
   555  }
   556  
   557  func TestLexerDashedCommand(t *testing.T) {
   558  	expected := []Token{
   559  		{typ: token.Arg, val: "google-chrome"},
   560  		{typ: token.Semicolon, val: ";"},
   561  		{typ: token.EOF},
   562  	}
   563  
   564  	testTable("testDashedCommand", `google-chrome`, expected, t)
   565  }
   566  
   567  func TestLexerPathCommand(t *testing.T) {
   568  	expected := []Token{
   569  		{typ: token.Arg, val: "/bin/echo"},
   570  		{typ: token.String, val: "hello world"},
   571  		{typ: token.Semicolon, val: ";"},
   572  		{typ: token.EOF},
   573  	}
   574  
   575  	testTable("testPathCommand", `/bin/echo "hello world"`, expected, t)
   576  }
   577  
   578  func TestLexerInvalidBlock(t *testing.T) {
   579  	expected := []Token{
   580  		{typ: token.LBrace, val: "{"},
   581  		{typ: token.EOF},
   582  	}
   583  
   584  	testTable("testInvalidBlock", "{", expected, t)
   585  }
   586  
   587  func TestLexerQuotedStringNotFinished(t *testing.T) {
   588  	expected := []Token{
   589  		{
   590  			typ: token.Ident,
   591  			val: "echo",
   592  		},
   593  		{
   594  			typ: token.Illegal,
   595  			val: "testQuotedstringnotfinished:1:17: Quoted string not finished: hello world",
   596  		},
   597  		{
   598  			typ: token.EOF,
   599  		},
   600  	}
   601  
   602  	testTable("testQuotedstringnotfinished", "echo \"hello world", expected, t)
   603  }
   604  
   605  func TestLexerVariousCommands(t *testing.T) {
   606  	content := `
   607              echo "hello world"
   608              mount -t proc proc /proc
   609          `
   610  
   611  	expected := []Token{
   612  		{typ: token.Ident, val: "echo"},
   613  		{typ: token.String, val: "hello world"},
   614  		{typ: token.Semicolon, val: ";"},
   615  
   616  		{typ: token.Ident, val: "mount"},
   617  		{typ: token.Arg, val: "-t"},
   618  		{typ: token.Ident, val: "proc"},
   619  		{typ: token.Ident, val: "proc"},
   620  		{typ: token.Arg, val: "/proc"},
   621  		{typ: token.Semicolon, val: ";"},
   622  		{typ: token.EOF},
   623  	}
   624  
   625  	testTable("testVariouscommands", content, expected, t)
   626  }
   627  
   628  func TestLexerRfork(t *testing.T) {
   629  	expected := []Token{
   630  		{typ: token.Rfork, val: "rfork"},
   631  		{typ: token.Ident, val: "u"},
   632  		{typ: token.Semicolon, val: ";"},
   633  		{typ: token.EOF},
   634  	}
   635  
   636  	testTable("testRfork", "rfork u\n", expected, t)
   637  
   638  	expected = []Token{
   639  		{typ: token.Rfork, val: "rfork"},
   640  		{typ: token.Ident, val: "usnm"},
   641  		{typ: token.LBrace, val: "{"},
   642  		{typ: token.Ident, val: "echo"},
   643  		{typ: token.String, val: "inside namespace :)"},
   644  		{typ: token.Semicolon, val: ";"},
   645  		{typ: token.RBrace, val: "}"},
   646  		{typ: token.EOF},
   647  	}
   648  
   649  	testTable("testRforkWithBlock", `
   650              rfork usnm {
   651                  echo "inside namespace :)"
   652              }
   653          `, expected, t)
   654  
   655  }
   656  
   657  func TestLexerSomethingIdontcareanymore(t *testing.T) {
   658  	// maybe oneliner rfork isnt a good idea
   659  	expected := []Token{
   660  		{typ: token.Rfork, val: "rfork"},
   661  		{typ: token.Ident, val: "u"},
   662  		{typ: token.LBrace, val: "{"},
   663  		{typ: token.Ident, val: "ls"},
   664  		{typ: token.RBrace, val: "}"},
   665  		{typ: token.EOF},
   666  	}
   667  
   668  	testTable("test whatever", "rfork u { ls }", expected, t)
   669  }
   670  
   671  func TestLexerBuiltinCd(t *testing.T) {
   672  	expected := []Token{
   673  		{typ: token.Ident, val: "cd"},
   674  		{typ: token.String, val: "some place"},
   675  		{typ: token.Semicolon, val: ";"},
   676  		{typ: token.EOF},
   677  	}
   678  
   679  	testTable("testBuiltinCd", `cd "some place"`, expected, t)
   680  
   681  	expected = []Token{
   682  		{typ: token.Ident, val: "cd"},
   683  		{typ: token.Arg, val: "/proc"},
   684  		{typ: token.Semicolon, val: ";"},
   685  		{typ: token.EOF},
   686  	}
   687  
   688  	testTable("testBuiltinCdNoQuote", `cd /proc`, expected, t)
   689  
   690  	expected = []Token{
   691  		{typ: token.Ident, val: "cd"},
   692  		{typ: token.Semicolon, val: ";"},
   693  		{typ: token.EOF},
   694  	}
   695  
   696  	testTable("testBuiltincd home", `cd`, expected, t)
   697  
   698  	expected = []Token{
   699  		{typ: token.Ident, val: "HOME"},
   700  		{typ: token.Assign, val: "="},
   701  		{typ: token.String, val: "/"},
   702  		{typ: token.Semicolon, val: ";"},
   703  		{typ: token.SetEnv, val: "setenv"},
   704  		{typ: token.Ident, val: "HOME"},
   705  		{typ: token.Semicolon, val: ";"},
   706  		{typ: token.Ident, val: "cd"},
   707  		{typ: token.Semicolon, val: ";"},
   708  		{typ: token.Ident, val: "pwd"},
   709  		{typ: token.Semicolon, val: ";"},
   710  		{typ: token.EOF},
   711  	}
   712  
   713  	testTable("testBuiltin cd bug", `
   714  	               HOME="/"
   715                         setenv HOME
   716  	               cd
   717  	               pwd
   718  	           `, expected, t)
   719  
   720  	expected = []Token{
   721  		{typ: token.Ident, val: "cd"},
   722  		{typ: token.Variable, val: "$GOPATH"},
   723  		{typ: token.Semicolon, val: ";"},
   724  		{typ: token.EOF},
   725  	}
   726  
   727  	testTable("test builtin cd into variable", `cd $GOPATH`, expected, t)
   728  
   729  	expected = []Token{
   730  		{typ: token.Ident, val: "cd"},
   731  		{typ: token.Variable, val: "$GOPATH"},
   732  		{typ: token.Plus, val: "+"},
   733  		{typ: token.String, val: "/src/github.com"},
   734  		{typ: token.Semicolon, val: ";"},
   735  		{typ: token.EOF},
   736  	}
   737  
   738  	testTable("test cd with concat", `cd $GOPATH+"/src/github.com"`, expected, t)
   739  }
   740  
   741  func TestLexerRedirectSimple(t *testing.T) {
   742  	expected := []Token{
   743  		{typ: token.Ident, val: "cmd"},
   744  		{typ: token.Gt, val: ">"},
   745  		{typ: token.Arg, val: "file.out"},
   746  		{typ: token.Semicolon, val: ";"},
   747  		{typ: token.EOF},
   748  	}
   749  
   750  	testTable("test simple redirect", "cmd > file.out", expected, t)
   751  
   752  	expected = []Token{
   753  		{typ: token.Ident, val: "cmd"},
   754  		{typ: token.Gt, val: ">"},
   755  		{typ: token.String, val: "tcp://localhost:8888"},
   756  		{typ: token.Semicolon, val: ";"},
   757  		{typ: token.EOF},
   758  	}
   759  
   760  	testTable("test simple redirect", `cmd > "tcp://localhost:8888"`, expected, t)
   761  
   762  	expected = []Token{
   763  		{typ: token.Ident, val: "cmd"},
   764  		{typ: token.Gt, val: ">"},
   765  		{typ: token.String, val: "udp://localhost:8888"},
   766  		{typ: token.Semicolon, val: ";"},
   767  		{typ: token.EOF},
   768  	}
   769  
   770  	testTable("test simple redirect", `cmd > "udp://localhost:8888"`, expected, t)
   771  
   772  	expected = []Token{
   773  		{typ: token.Ident, val: "cmd"},
   774  		{typ: token.Gt, val: ">"},
   775  		{typ: token.String, val: "unix:///tmp/sock.txt"},
   776  		{typ: token.Semicolon, val: ";"},
   777  		{typ: token.EOF},
   778  	}
   779  
   780  	testTable("test simple redirect", `cmd > "unix:///tmp/sock.txt"`, expected, t)
   781  
   782  }
   783  
   784  func TestLexerRedirectMap(t *testing.T) {
   785  
   786  	// Suppress stderr output
   787  	expected := []Token{
   788  		{typ: token.Ident, val: "cmd"},
   789  		{typ: token.Gt, val: ">"},
   790  		{typ: token.LBrack, val: "["},
   791  		{typ: token.Number, val: "2"},
   792  		{typ: token.Assign, val: "="},
   793  		{typ: token.RBrack, val: "]"},
   794  		{typ: token.Semicolon, val: ";"},
   795  		{typ: token.EOF},
   796  	}
   797  
   798  	testTable("test suppress stderr", "cmd >[2=]", expected, t)
   799  
   800  	// points stderr to stdout
   801  	expected = []Token{
   802  		{typ: token.Ident, val: "cmd"},
   803  		{typ: token.Gt, val: ">"},
   804  		{typ: token.LBrack, val: "["},
   805  		{typ: token.Number, val: "2"},
   806  		{typ: token.Assign, val: "="},
   807  		{typ: token.Number, val: "1"},
   808  		{typ: token.RBrack, val: "]"},
   809  		{typ: token.Semicolon, val: ";"},
   810  		{typ: token.EOF},
   811  	}
   812  
   813  	testTable("test stderr=stdout", "cmd >[2=1]", expected, t)
   814  }
   815  
   816  func TestLexerRedirectMapToLocation(t *testing.T) {
   817  	// Suppress stderr output
   818  	expected := []Token{
   819  		{typ: token.Ident, val: "cmd"},
   820  		{typ: token.Gt, val: ">"},
   821  		{typ: token.LBrack, val: "["},
   822  		{typ: token.Number, val: "2"},
   823  		{typ: token.Assign, val: "="},
   824  		{typ: token.RBrack, val: "]"},
   825  		{typ: token.Arg, val: "file.out"},
   826  		{typ: token.Semicolon, val: ";"},
   827  		{typ: token.EOF},
   828  	}
   829  
   830  	testTable("test suppress stderr", "cmd >[2=] file.out", expected, t)
   831  
   832  	// points stderr to stdout
   833  	expected = []Token{
   834  		{typ: token.Ident, val: "cmd"},
   835  		{typ: token.Gt, val: ">"},
   836  		{typ: token.LBrack, val: "["},
   837  		{typ: token.Number, val: "2"},
   838  		{typ: token.Assign, val: "="},
   839  		{typ: token.Number, val: "1"},
   840  		{typ: token.RBrack, val: "]"},
   841  		{typ: token.Arg, val: "file.out"},
   842  		{typ: token.Semicolon, val: ";"},
   843  		{typ: token.EOF},
   844  	}
   845  
   846  	testTable("test stderr=stdout", "cmd >[2=1] file.out", expected, t)
   847  
   848  	expected = []Token{
   849  		{typ: token.Ident, val: "cmd"},
   850  		{typ: token.Gt, val: ">"},
   851  		{typ: token.LBrack, val: "["},
   852  		{typ: token.Number, val: "2"},
   853  		{typ: token.RBrack, val: "]"},
   854  		{typ: token.Arg, val: "/var/log/service.log"},
   855  		{typ: token.Semicolon, val: ";"},
   856  		{typ: token.EOF},
   857  	}
   858  
   859  	testTable("test suppress stderr", `cmd >[2] /var/log/service.log`, expected, t)
   860  }
   861  
   862  func TestLexerRedirectMultipleMaps(t *testing.T) {
   863  	expected := []Token{
   864  		{typ: token.Ident, val: "cmd"},
   865  		{typ: token.Gt, val: ">"},
   866  		{typ: token.LBrack, val: "["},
   867  		{typ: token.Number, val: "1"},
   868  		{typ: token.RBrack, val: "]"},
   869  		{typ: token.Arg, val: "file.out"},
   870  		{typ: token.Gt, val: ">"},
   871  		{typ: token.LBrack, val: "["},
   872  		{typ: token.Number, val: "2"},
   873  		{typ: token.RBrack, val: "]"},
   874  		{typ: token.Arg, val: "file.err"},
   875  		{typ: token.Semicolon, val: ";"},
   876  		{typ: token.EOF},
   877  	}
   878  
   879  	testTable("test suppress stderr", `cmd >[1] file.out >[2] file.err`, expected, t)
   880  
   881  	expected = []Token{
   882  		{typ: token.Ident, val: "cmd"},
   883  		{typ: token.Gt, val: ">"},
   884  		{typ: token.LBrack, val: "["},
   885  		{typ: token.Number, val: "2"},
   886  		{typ: token.Assign, val: "="},
   887  		{typ: token.Number, val: "1"},
   888  		{typ: token.RBrack, val: "]"},
   889  		{typ: token.Gt, val: ">"},
   890  		{typ: token.LBrack, val: "["},
   891  		{typ: token.Number, val: "1"},
   892  		{typ: token.RBrack, val: "]"},
   893  		{typ: token.Arg, val: "/var/log/service.log"},
   894  		{typ: token.Semicolon, val: ";"},
   895  		{typ: token.EOF},
   896  	}
   897  
   898  	testTable("test suppress stderr", `cmd >[2=1] >[1] /var/log/service.log`, expected, t)
   899  
   900  	expected = []Token{
   901  		{typ: token.Ident, val: "cmd"},
   902  		{typ: token.Gt, val: ">"},
   903  		{typ: token.LBrack, val: "["},
   904  		{typ: token.Number, val: "1"},
   905  		{typ: token.Assign, val: "="},
   906  		{typ: token.Number, val: "2"},
   907  		{typ: token.RBrack, val: "]"},
   908  		{typ: token.Gt, val: ">"},
   909  		{typ: token.LBrack, val: "["},
   910  		{typ: token.Number, val: "2"},
   911  		{typ: token.Assign, val: "="},
   912  		{typ: token.RBrack, val: "]"},
   913  		{typ: token.Semicolon, val: ";"},
   914  		{typ: token.EOF},
   915  	}
   916  
   917  	testTable("test suppress stderr", `cmd >[1=2] >[2=]`, expected, t)
   918  }
   919  
   920  func TestLexerImport(t *testing.T) {
   921  	expected := []Token{
   922  		{typ: token.Import, val: "import"},
   923  		{typ: token.Arg, val: "env.sh"},
   924  		{typ: token.Semicolon, val: ";"},
   925  		{typ: token.EOF},
   926  	}
   927  
   928  	testTable("test import", `import env.sh`, expected, t)
   929  }
   930  
   931  func TestLexerSimpleIf(t *testing.T) {
   932  	expected := []Token{
   933  		{typ: token.If, val: "if"},
   934  		{typ: token.String, val: "test"},
   935  		{typ: token.Equal, val: "=="},
   936  		{typ: token.String, val: "other"},
   937  		{typ: token.LBrace, val: "{"},
   938  		{typ: token.Ident, val: "rm"},
   939  		{typ: token.Arg, val: "-rf"},
   940  		{typ: token.Arg, val: "/"},
   941  		{typ: token.RBrace, val: "}"},
   942  		{typ: token.EOF},
   943  	}
   944  
   945  	testTable("test simple if", `if "test" == "other" { rm -rf / }`, expected, t)
   946  
   947  	expected = []Token{
   948  		{typ: token.If, val: "if"},
   949  		{typ: token.String, val: "test"},
   950  		{typ: token.NotEqual, val: "!="},
   951  		{typ: token.Variable, val: "$test"},
   952  		{typ: token.LBrace, val: "{"},
   953  		{typ: token.Ident, val: "rm"},
   954  		{typ: token.Arg, val: "-rf"},
   955  		{typ: token.Arg, val: "/"},
   956  		{typ: token.Semicolon, val: ";"},
   957  		{typ: token.RBrace, val: "}"},
   958  		{typ: token.EOF},
   959  	}
   960  
   961  	testTable("test simple if", `if "test" != $test {
   962              rm -rf /
   963          }`, expected, t)
   964  
   965  	testTable("test simple if", `
   966  
   967          if "test" != $test {
   968              rm -rf /
   969          }`, expected, t)
   970  }
   971  
   972  func TestLexerIfWithConcat(t *testing.T) {
   973  	expected := []Token{
   974  		{typ: token.If, val: "if"},
   975  		{typ: token.Variable, val: "$test"},
   976  		{typ: token.Plus, val: "+"},
   977  		{typ: token.String, val: "001"},
   978  		{typ: token.NotEqual, val: "!="},
   979  		{typ: token.String, val: "value001"},
   980  		{typ: token.LBrace, val: "{"},
   981  		{typ: token.Ident, val: "rm"},
   982  		{typ: token.Arg, val: "-rf"},
   983  		{typ: token.Arg, val: "/"},
   984  		{typ: token.Semicolon, val: ";"},
   985  		{typ: token.RBrace, val: "}"},
   986  		{typ: token.EOF},
   987  	}
   988  
   989  	testTable("test if concat", `if $test + "001" != "value001" {
   990          rm -rf /
   991  }`, expected, t)
   992  }
   993  
   994  func TestLexerIfWithFuncInvocation(t *testing.T) {
   995  	expected := []Token{
   996  		{typ: token.If, val: "if"},
   997  		{typ: token.Ident, val: "test"},
   998  		{typ: token.LParen, val: "("},
   999  		{typ: token.String, val: "some val"},
  1000  		{typ: token.RParen, val: ")"},
  1001  		{typ: token.NotEqual, val: "!="},
  1002  		{typ: token.String, val: "value001"},
  1003  		{typ: token.LBrace, val: "{"},
  1004  		{typ: token.Ident, val: "rm"},
  1005  		{typ: token.Arg, val: "-rf"},
  1006  		{typ: token.Arg, val: "/"},
  1007  		{typ: token.Semicolon, val: ";"},
  1008  		{typ: token.RBrace, val: "}"},
  1009  		{typ: token.EOF},
  1010  	}
  1011  
  1012  	testTable("test if concat", `if test("some val") != "value001" {
  1013          rm -rf /
  1014  }`, expected, t)
  1015  }
  1016  
  1017  func TestLexerIfElse(t *testing.T) {
  1018  	expected := []Token{
  1019  		{typ: token.If, val: "if"},
  1020  		{typ: token.String, val: "test"},
  1021  		{typ: token.Equal, val: "=="},
  1022  		{typ: token.String, val: "other"},
  1023  		{typ: token.LBrace, val: "{"},
  1024  		{typ: token.Ident, val: "rm"},
  1025  		{typ: token.Arg, val: "-rf"},
  1026  		{typ: token.Arg, val: "/"},
  1027  		{typ: token.RBrace, val: "}"},
  1028  		{typ: token.Else, val: "else"},
  1029  		{typ: token.LBrace, val: "{"},
  1030  		{typ: token.Ident, val: "pwd"},
  1031  		{typ: token.RBrace, val: "}"},
  1032  		{typ: token.EOF},
  1033  	}
  1034  
  1035  	testTable("test simple if", `if "test" == "other" { rm -rf / } else { pwd }`, expected, t)
  1036  }
  1037  
  1038  func TestLexerIfElseIf(t *testing.T) {
  1039  	expected := []Token{
  1040  		{typ: token.If, val: "if"},
  1041  		{typ: token.String, val: "test"},
  1042  		{typ: token.Equal, val: "=="},
  1043  		{typ: token.String, val: "other"},
  1044  		{typ: token.LBrace, val: "{"},
  1045  		{typ: token.Ident, val: "rm"},
  1046  		{typ: token.Arg, val: "-rf"},
  1047  		{typ: token.Arg, val: "/"},
  1048  		{typ: token.Semicolon, val: ";"},
  1049  		{typ: token.RBrace, val: "}"},
  1050  		{typ: token.Else, val: "else"},
  1051  		{typ: token.If, val: "if"},
  1052  		{typ: token.String, val: "test"},
  1053  		{typ: token.Equal, val: "=="},
  1054  		{typ: token.Variable, val: "$var"},
  1055  		{typ: token.LBrace, val: "{"},
  1056  		{typ: token.Ident, val: "pwd"},
  1057  		{typ: token.Semicolon, val: ";"},
  1058  		{typ: token.RBrace, val: "}"},
  1059  		{typ: token.Else, val: "else"},
  1060  		{typ: token.LBrace, val: "{"},
  1061  		{typ: token.Ident, val: "exit"},
  1062  		{typ: token.Number, val: "1"},
  1063  		{typ: token.Semicolon, val: ";"},
  1064  		{typ: token.RBrace, val: "}"},
  1065  		{typ: token.EOF},
  1066  	}
  1067  
  1068  	testTable("test simple if", `
  1069          if "test" == "other" {
  1070                  rm -rf /
  1071          } else if "test" == $var {
  1072                  pwd
  1073          } else {
  1074                  exit 1
  1075          }`, expected, t)
  1076  }
  1077  
  1078  func TestLexerFnBasic(t *testing.T) {
  1079  	expected := []Token{
  1080  		{typ: token.Fn, val: "fn"},
  1081  		{typ: token.Ident, val: "build"},
  1082  		{typ: token.LParen, val: "("},
  1083  		{typ: token.RParen, val: ")"},
  1084  		{typ: token.LBrace, val: "{"},
  1085  		{typ: token.RBrace, val: "}"},
  1086  		{typ: token.EOF},
  1087  	}
  1088  
  1089  	testTable("test empty fn", `fn build() {}`, expected, t)
  1090  
  1091  	// lambda
  1092  	expected = []Token{
  1093  		{typ: token.Fn, val: "fn"},
  1094  		{typ: token.LParen, val: "("},
  1095  		{typ: token.RParen, val: ")"},
  1096  		{typ: token.LBrace, val: "{"},
  1097  		{typ: token.RBrace, val: "}"},
  1098  		{typ: token.EOF},
  1099  	}
  1100  
  1101  	testTable("test empty fn", `fn () {}`, expected, t)
  1102  
  1103  	// IIFE
  1104  	expected = []Token{
  1105  		{typ: token.Fn, val: "fn"},
  1106  		{typ: token.LParen, val: "("},
  1107  		{typ: token.RParen, val: ")"},
  1108  		{typ: token.LBrace, val: "{"},
  1109  		{typ: token.RBrace, val: "}"},
  1110  		{typ: token.LParen, val: "("},
  1111  		{typ: token.RParen, val: ")"},
  1112  		{typ: token.Semicolon, val: ";"},
  1113  		{typ: token.EOF},
  1114  	}
  1115  
  1116  	testTable("test empty fn", `fn () {}()`, expected, t)
  1117  
  1118  	expected = []Token{
  1119  		{typ: token.Fn, val: "fn"},
  1120  		{typ: token.Ident, val: "build"},
  1121  		{typ: token.LParen, val: "("},
  1122  		{typ: token.Ident, val: "image"},
  1123  		{typ: token.Comma, val: ","},
  1124  		{typ: token.Ident, val: "debug"},
  1125  		{typ: token.RParen, val: ")"},
  1126  		{typ: token.LBrace, val: "{"},
  1127  		{typ: token.RBrace, val: "}"},
  1128  		{typ: token.EOF},
  1129  	}
  1130  
  1131  	testTable("test empty fn with args", `fn build(image, debug) {}`, expected, t)
  1132  
  1133  	expected = []Token{
  1134  		{typ: token.Fn, val: "fn"},
  1135  		{typ: token.Ident, val: "build"},
  1136  		{typ: token.LParen, val: "("},
  1137  		{typ: token.Ident, val: "image"},
  1138  		{typ: token.Comma, val: ","},
  1139  		{typ: token.Ident, val: "debug"},
  1140  		{typ: token.RParen, val: ")"},
  1141  		{typ: token.LBrace, val: "{"},
  1142  		{typ: token.Ident, val: "ls"},
  1143  		{typ: token.Semicolon, val: ";"},
  1144  		{typ: token.Ident, val: "tar"},
  1145  		{typ: token.Semicolon, val: ";"},
  1146  		{typ: token.RBrace, val: "}"},
  1147  		{typ: token.EOF},
  1148  	}
  1149  
  1150  	testTable("test empty fn with args and body", `fn build(image, debug) {
  1151              ls
  1152              tar
  1153          }`, expected, t)
  1154  
  1155  	expected = []Token{
  1156  		{typ: token.Fn, val: "fn"},
  1157  		{typ: token.Ident, val: "cd"},
  1158  		{typ: token.LParen, val: "("},
  1159  		{typ: token.Ident, val: "path"},
  1160  		{typ: token.RParen, val: ")"},
  1161  		{typ: token.LBrace, val: "{"},
  1162  		{typ: token.Ident, val: "cd"},
  1163  		{typ: token.Variable, val: "$path"},
  1164  		{typ: token.Semicolon, val: ";"},
  1165  		{typ: token.Ident, val: "PROMPT"},
  1166  		{typ: token.Assign, val: "="},
  1167  		{typ: token.String, val: "("},
  1168  		{typ: token.Plus, val: "+"},
  1169  		{typ: token.Variable, val: "$path"},
  1170  		{typ: token.Plus, val: "+"},
  1171  		{typ: token.String, val: ")"},
  1172  		{typ: token.Plus, val: "+"},
  1173  		{typ: token.Variable, val: "$PROMPT"},
  1174  		{typ: token.Semicolon, val: ";"},
  1175  		{typ: token.SetEnv, val: "setenv"},
  1176  		{typ: token.Ident, val: "PROMPT"},
  1177  		{typ: token.Semicolon, val: ";"},
  1178  		{typ: token.RBrace, val: "}"},
  1179  		{typ: token.EOF},
  1180  	}
  1181  
  1182  	testTable("test cd fn with PROMPT update", `fn cd(path) {
  1183      cd $path
  1184      PROMPT="(" + $path + ")"+$PROMPT
  1185      setenv PROMPT
  1186  }`, expected, t)
  1187  }
  1188  
  1189  func TestLexerFuncall(t *testing.T) {
  1190  	expected := []Token{
  1191  		{typ: token.Ident, val: "build"},
  1192  		{typ: token.LParen, val: "("},
  1193  		{typ: token.RParen, val: ")"},
  1194  		{typ: token.Semicolon, val: ";"},
  1195  		{typ: token.EOF},
  1196  	}
  1197  
  1198  	testTable("test fn invocation", `build()`, expected, t)
  1199  
  1200  	expected = []Token{
  1201  		{typ: token.Ident, val: "build"},
  1202  		{typ: token.LParen, val: "("},
  1203  		{typ: token.String, val: "ubuntu"},
  1204  		{typ: token.RParen, val: ")"},
  1205  		{typ: token.Semicolon, val: ";"},
  1206  		{typ: token.EOF},
  1207  	}
  1208  
  1209  	testTable("test fn invocation", `build("ubuntu")`, expected, t)
  1210  
  1211  	expected = []Token{
  1212  		{typ: token.Ident, val: "build"},
  1213  		{typ: token.LParen, val: "("},
  1214  		{typ: token.String, val: "ubuntu"},
  1215  		{typ: token.Comma, val: ","},
  1216  		{typ: token.Variable, val: "$debug"},
  1217  
  1218  		{typ: token.RParen, val: ")"},
  1219  		{typ: token.Semicolon, val: ";"},
  1220  		{typ: token.EOF},
  1221  	}
  1222  
  1223  	testTable("test fn invocation", `build("ubuntu", $debug)`, expected, t)
  1224  
  1225  	expected = []Token{
  1226  		{typ: token.Ident, val: "build"},
  1227  		{typ: token.LParen, val: "("},
  1228  		{typ: token.Variable, val: "$debug"},
  1229  
  1230  		{typ: token.RParen, val: ")"},
  1231  		{typ: token.Semicolon, val: ";"},
  1232  		{typ: token.EOF},
  1233  	}
  1234  
  1235  	testTable("test fn invocation", `build($debug)`, expected, t)
  1236  
  1237  	expected = []Token{
  1238  		{typ: token.Ident, val: "a"},
  1239  		{typ: token.LParen, val: "("},
  1240  		{typ: token.Ident, val: "b"},
  1241  		{typ: token.LParen, val: "("},
  1242  		{typ: token.RParen, val: ")"},
  1243  		{typ: token.RParen, val: ")"},
  1244  		{typ: token.Semicolon, val: ";"},
  1245  		{typ: token.EOF},
  1246  	}
  1247  
  1248  	testTable("test fn composition", `a(b())`, expected, t)
  1249  
  1250  	expected = []Token{
  1251  		{typ: token.Ident, val: "ids_luns"},
  1252  		{typ: token.AssignCmd, val: "<="},
  1253  		{typ: token.Ident, val: "append"},
  1254  		{typ: token.LParen, val: "("},
  1255  		{typ: token.Variable, val: "$ids_luns"},
  1256  		{typ: token.Comma, val: ","},
  1257  		{typ: token.LParen, val: "("},
  1258  		{typ: token.Variable, val: "$id"},
  1259  		{typ: token.Variable, val: "$lun"},
  1260  		{typ: token.RParen, val: ")"},
  1261  		{typ: token.RParen, val: ")"},
  1262  		{typ: token.Semicolon, val: ";"},
  1263  		{typ: token.EOF},
  1264  	}
  1265  
  1266  	testTable("test katcipis bad mood", `ids_luns <= append($ids_luns, ($id $lun))`,
  1267  		expected, t)
  1268  }
  1269  
  1270  func TestLexerAssignCmdOut(t *testing.T) {
  1271  	expected := []Token{
  1272  		{typ: token.Ident, val: "ipaddr"},
  1273  		{typ: token.AssignCmd, val: "<="},
  1274  		{typ: token.Ident, val: "someprogram"},
  1275  		{typ: token.Semicolon, val: ";"},
  1276  		{typ: token.EOF},
  1277  	}
  1278  
  1279  	testTable("test assignCmdOut", `ipaddr <= someprogram`, expected, t)
  1280  }
  1281  
  1282  func TestLexerMultipleAssignCmdOut(t *testing.T) {
  1283  	expected := []Token{
  1284  		{typ: token.Ident, val: "ret"},
  1285  		{typ: token.Comma, val: ","},
  1286  		{typ: token.Ident, val: "status"},
  1287  		{typ: token.AssignCmd, val: "<="},
  1288  		{typ: token.Ident, val: "someprogram"},
  1289  		{typ: token.Semicolon, val: ";"},
  1290  		{typ: token.EOF},
  1291  	}
  1292  
  1293  	testTable("test multiple return assignCmdOut", `ret, status <= someprogram`, expected, t)
  1294  
  1295  	expected = []Token{
  1296  		{typ: token.Ident, val: "ret"},
  1297  		{typ: token.Comma, val: ","},
  1298  		{typ: token.Ident, val: "_"},
  1299  		{typ: token.AssignCmd, val: "<="},
  1300  		{typ: token.Ident, val: "someprogram"},
  1301  		{typ: token.Semicolon, val: ";"},
  1302  		{typ: token.EOF},
  1303  	}
  1304  
  1305  	testTable("test multiple return assignCmdOut", `ret, _ <= someprogram`, expected, t)
  1306  
  1307  	expected = []Token{
  1308  		{typ: token.Ident, val: "ret"},
  1309  		{typ: token.Comma, val: ","},
  1310  		{typ: token.Ident, val: "obj"},
  1311  		{typ: token.Comma, val: ","},
  1312  		{typ: token.Ident, val: "err"},
  1313  		{typ: token.AssignCmd, val: "<="},
  1314  		{typ: token.Ident, val: "somefn"},
  1315  		{typ: token.LParen, val: "("},
  1316  		{typ: token.RParen, val: ")"},
  1317  		{typ: token.Semicolon, val: ";"},
  1318  		{typ: token.EOF},
  1319  	}
  1320  
  1321  	testTable("test multiple return assignCmdOut", `ret, obj, err <= somefn()`, expected, t)
  1322  }
  1323  
  1324  func TestMultipleAssignments(t *testing.T) {
  1325  	expected := []Token{
  1326  		{typ: token.Ident, val: "a"},
  1327  		{typ: token.Comma, val: ","},
  1328  		{typ: token.Ident, val: "b"},
  1329  		{typ: token.Assign, val: "="},
  1330  		{typ: token.String, val: "1"},
  1331  		{typ: token.Comma, val: ","},
  1332  		{typ: token.String, val: "2"},
  1333  		{typ: token.Semicolon, val: ";"},
  1334  		{typ: token.EOF},
  1335  	}
  1336  
  1337  	testTable("test multiple assign", `a, b = "1", "2"`, expected, t)
  1338  }
  1339  
  1340  func TestLexerBindFn(t *testing.T) {
  1341  	expected := []Token{
  1342  		{typ: token.BindFn, val: "bindfn"},
  1343  		{typ: token.Ident, val: "cd"},
  1344  		{typ: token.Ident, val: "cd2"},
  1345  		{typ: token.Semicolon, val: ";"},
  1346  		{typ: token.EOF},
  1347  	}
  1348  
  1349  	testTable("test bindfn", `bindfn cd cd2`, expected, t)
  1350  
  1351  }
  1352  
  1353  func TestLexerRedirectionNetwork(t *testing.T) {
  1354  	expected := []Token{
  1355  		{typ: token.Ident, val: "echo"},
  1356  		{typ: token.String, val: "hello world"},
  1357  		{typ: token.Gt, val: ">"},
  1358  		{typ: token.LBrack, val: "["},
  1359  		{typ: token.Number, val: "1"},
  1360  		{typ: token.RBrack, val: "]"},
  1361  		{typ: token.String, val: "tcp://localhost:6667"},
  1362  		{typ: token.Semicolon, val: ";"},
  1363  		{typ: token.EOF},
  1364  	}
  1365  
  1366  	testTable("test redirection network", `echo "hello world" >[1] "tcp://localhost:6667"`, expected, t)
  1367  }
  1368  
  1369  func TestLexerDump(t *testing.T) {
  1370  	expected := []Token{
  1371  		{typ: token.Dump, val: "dump"},
  1372  		{typ: token.Semicolon, val: ";"},
  1373  		{typ: token.EOF},
  1374  	}
  1375  
  1376  	testTable("test dump", `dump`, expected, t)
  1377  
  1378  	expected = []Token{
  1379  		{typ: token.Dump, val: "dump"},
  1380  		{typ: token.Ident, val: "out"},
  1381  		{typ: token.Semicolon, val: ";"},
  1382  		{typ: token.EOF},
  1383  	}
  1384  
  1385  	testTable("test dump", `dump out`, expected, t)
  1386  
  1387  	expected = []Token{
  1388  		{typ: token.Dump, val: "dump"},
  1389  		{typ: token.Variable, val: "$out"},
  1390  		{typ: token.Semicolon, val: ";"},
  1391  		{typ: token.EOF},
  1392  	}
  1393  
  1394  	testTable("test dump", `dump $out`, expected, t)
  1395  }
  1396  
  1397  func TestLexerReturn(t *testing.T) {
  1398  	expected := []Token{
  1399  		{typ: token.Return, val: "return"},
  1400  		{typ: token.Semicolon, val: ";"},
  1401  		{typ: token.EOF},
  1402  	}
  1403  
  1404  	testTable("test return", "return", expected, t)
  1405  
  1406  	expected = []Token{
  1407  		{typ: token.Fn, val: "fn"},
  1408  		{typ: token.Ident, val: "test"},
  1409  		{typ: token.LParen, val: "("},
  1410  		{typ: token.RParen, val: ")"},
  1411  		{typ: token.LBrace, val: "{"},
  1412  		{typ: token.Return, val: "return"},
  1413  		{typ: token.RBrace, val: "}"},
  1414  		{typ: token.EOF},
  1415  	}
  1416  
  1417  	testTable("test return", "fn test() { return }", expected, t)
  1418  
  1419  	expected = []Token{
  1420  		{typ: token.Fn, val: "fn"},
  1421  		{typ: token.Ident, val: "test"},
  1422  		{typ: token.LParen, val: "("},
  1423  		{typ: token.RParen, val: ")"},
  1424  		{typ: token.LBrace, val: "{"},
  1425  		{typ: token.Return, val: "return"},
  1426  		{typ: token.Semicolon, val: ";"},
  1427  		{typ: token.RBrace, val: "}"},
  1428  		{typ: token.EOF},
  1429  	}
  1430  
  1431  	testTable("test return", `fn test() {
  1432  	return
  1433  }`, expected, t)
  1434  
  1435  	expected = []Token{
  1436  		{typ: token.Fn, val: "fn"},
  1437  		{typ: token.Ident, val: "test"},
  1438  		{typ: token.LParen, val: "("},
  1439  		{typ: token.RParen, val: ")"},
  1440  		{typ: token.LBrace, val: "{"},
  1441  		{typ: token.Return, val: "return"},
  1442  		{typ: token.String, val: "some value"},
  1443  		{typ: token.RBrace, val: "}"},
  1444  		{typ: token.EOF},
  1445  	}
  1446  
  1447  	testTable("test return", `fn test() { return "some value"}`, expected, t)
  1448  
  1449  	expected = []Token{
  1450  		{typ: token.Fn, val: "fn"},
  1451  		{typ: token.Ident, val: "test"},
  1452  		{typ: token.LParen, val: "("},
  1453  		{typ: token.RParen, val: ")"},
  1454  		{typ: token.LBrace, val: "{"},
  1455  		{typ: token.Return, val: "return"},
  1456  		{typ: token.String, val: "some value"},
  1457  		{typ: token.Semicolon, val: ";"},
  1458  		{typ: token.RBrace, val: "}"},
  1459  		{typ: token.EOF},
  1460  	}
  1461  
  1462  	testTable("test return", `fn test() {
  1463  	return "some value"
  1464  }`, expected, t)
  1465  
  1466  	expected = []Token{
  1467  		{typ: token.Fn, val: "fn"},
  1468  		{typ: token.Ident, val: "test"},
  1469  		{typ: token.LParen, val: "("},
  1470  		{typ: token.RParen, val: ")"},
  1471  		{typ: token.LBrace, val: "{"},
  1472  		{typ: token.Ident, val: "value"},
  1473  		{typ: token.Assign, val: "="},
  1474  		{typ: token.String, val: "some value"},
  1475  		{typ: token.Semicolon, val: ";"},
  1476  		{typ: token.Return, val: "return"},
  1477  		{typ: token.Variable, val: "$value"},
  1478  		{typ: token.Semicolon, val: ";"},
  1479  		{typ: token.RBrace, val: "}"},
  1480  		{typ: token.EOF},
  1481  	}
  1482  
  1483  	testTable("test return", `fn test() {
  1484  	value = "some value"
  1485  	return $value
  1486  }`, expected, t)
  1487  
  1488  	expected = []Token{
  1489  		{typ: token.Fn, val: "fn"},
  1490  		{typ: token.Ident, val: "test"},
  1491  		{typ: token.LParen, val: "("},
  1492  		{typ: token.RParen, val: ")"},
  1493  		{typ: token.LBrace, val: "{"},
  1494  		{typ: token.Return, val: "return"},
  1495  		{typ: token.LParen, val: "("},
  1496  		{typ: token.String, val: "test"},
  1497  		{typ: token.String, val: "test2"},
  1498  		{typ: token.RParen, val: ")"},
  1499  		{typ: token.Semicolon, val: ";"},
  1500  		{typ: token.RBrace, val: "}"},
  1501  		{typ: token.EOF},
  1502  	}
  1503  
  1504  	testTable("test return", `fn test() {
  1505  	return ("test" "test2")
  1506  }`, expected, t)
  1507  
  1508  	expected = []Token{
  1509  		{typ: token.Fn, val: "fn"},
  1510  		{typ: token.Ident, val: "test"},
  1511  		{typ: token.LParen, val: "("},
  1512  		{typ: token.RParen, val: ")"},
  1513  		{typ: token.LBrace, val: "{"},
  1514  		{typ: token.Return, val: "return"},
  1515  		{typ: token.Variable, val: "$PWD"},
  1516  		{typ: token.Semicolon, val: ";"},
  1517  		{typ: token.RBrace, val: "}"},
  1518  		{typ: token.EOF},
  1519  	}
  1520  
  1521  	testTable("test return", `fn test() {
  1522  	return $PWD
  1523  }`, expected, t)
  1524  }
  1525  
  1526  func TestLexerFor(t *testing.T) {
  1527  	expected := []Token{
  1528  		{typ: token.For, val: "for"},
  1529  		{typ: token.LBrace, val: "{"},
  1530  		{typ: token.RBrace, val: "}"},
  1531  		{typ: token.EOF},
  1532  	}
  1533  
  1534  	testTable("test inf loop", `for {}`, expected, t)
  1535  
  1536  	expected = []Token{
  1537  		{typ: token.For, val: "for"},
  1538  		{typ: token.Ident, val: "f"},
  1539  		{typ: token.Ident, val: "in"},
  1540  		{typ: token.Variable, val: "$files"},
  1541  		{typ: token.LBrace, val: "{"},
  1542  		{typ: token.RBrace, val: "}"},
  1543  		{typ: token.EOF},
  1544  	}
  1545  
  1546  	testTable("test inf loop", `for f in $files {}`, expected, t)
  1547  
  1548  	expected = []Token{
  1549  		{typ: token.For, val: "for"},
  1550  		{typ: token.Ident, val: "f"},
  1551  		{typ: token.Ident, val: "in"},
  1552  		{typ: token.Ident, val: "getfiles"},
  1553  		{typ: token.LParen, val: "("},
  1554  		{typ: token.String, val: "/"},
  1555  		{typ: token.RParen, val: ")"},
  1556  		{typ: token.LBrace, val: "{"},
  1557  		{typ: token.RBrace, val: "}"},
  1558  		{typ: token.EOF},
  1559  	}
  1560  
  1561  	testTable("test inf loop", `for f in getfiles("/") {}`, expected, t)
  1562  
  1563  	expected = []Token{
  1564  		{typ: token.For, val: "for"},
  1565  		{typ: token.Ident, val: "f"},
  1566  		{typ: token.Ident, val: "in"},
  1567  		{typ: token.LParen, val: "("},
  1568  		{typ: token.Number, val: "1"},
  1569  		{typ: token.Number, val: "2"},
  1570  		{typ: token.Number, val: "3"},
  1571  		{typ: token.Number, val: "4"},
  1572  		{typ: token.Number, val: "5"},
  1573  		{typ: token.RParen, val: ")"},
  1574  		{typ: token.LBrace, val: "{"},
  1575  		{typ: token.RBrace, val: "}"},
  1576  		{typ: token.EOF},
  1577  	}
  1578  
  1579  	testTable("test inf loop", `for f in (1 2 3 4 5) {}`, expected, t)
  1580  }
  1581  
  1582  func TestLexerFnAsFirstClass(t *testing.T) {
  1583  	expected := []Token{
  1584  		{typ: token.Fn, val: "fn"},
  1585  		{typ: token.Ident, val: "printer"},
  1586  		{typ: token.LParen, val: "("},
  1587  		{typ: token.Ident, val: "val"},
  1588  		{typ: token.RParen, val: ")"},
  1589  		{typ: token.LBrace, val: "{"},
  1590  		{typ: token.Ident, val: "echo"},
  1591  		{typ: token.Arg, val: "-n"},
  1592  		{typ: token.Variable, val: "$val"},
  1593  		{typ: token.Semicolon, val: ";"},
  1594  		{typ: token.RBrace, val: "}"},
  1595  		{typ: token.Fn, val: "fn"},
  1596  		{typ: token.Ident, val: "success"},
  1597  		{typ: token.LParen, val: "("},
  1598  		{typ: token.Ident, val: "print"},
  1599  		{typ: token.Comma, val: ","},
  1600  		{typ: token.Ident, val: "val"},
  1601  		{typ: token.RParen, val: ")"},
  1602  		{typ: token.LBrace, val: "{"},
  1603  		{typ: token.Variable, val: "$print"},
  1604  		{typ: token.LParen, val: "("},
  1605  		{typ: token.String, val: "[SUCCESS] "},
  1606  		{typ: token.Plus, val: "+"},
  1607  		{typ: token.Variable, val: "$val"},
  1608  		{typ: token.RParen, val: ")"},
  1609  		{typ: token.Semicolon, val: ";"},
  1610  		{typ: token.RBrace, val: "}"},
  1611  		{typ: token.Ident, val: "success"},
  1612  		{typ: token.LParen, val: "("},
  1613  		{typ: token.Variable, val: "$printer"},
  1614  		{typ: token.Comma, val: ","},
  1615  		{typ: token.String, val: "Command executed!"},
  1616  		{typ: token.RParen, val: ")"},
  1617  		{typ: token.Semicolon, val: ";"},
  1618  
  1619  		{typ: token.EOF},
  1620  	}
  1621  
  1622  	testTable("test fn as first class", `
  1623          fn printer(val) {
  1624                  echo -n $val
  1625          }
  1626  
  1627          fn success(print, val) {
  1628                  $print("[SUCCESS] " + $val)
  1629          }
  1630  
  1631          success($printer, "Command executed!")
  1632          `, expected, t)
  1633  }
  1634  
  1635  func TestLexerListIndexing(t *testing.T) {
  1636  	expected := []Token{
  1637  		{typ: token.Ident, val: "cmd"},
  1638  		{typ: token.Assign, val: "="},
  1639  		{typ: token.Variable, val: "$commands"},
  1640  		{typ: token.LBrack, val: "["},
  1641  		{typ: token.Number, val: "0"},
  1642  		{typ: token.RBrack, val: "]"},
  1643  		{typ: token.Semicolon, val: ";"},
  1644  		{typ: token.EOF},
  1645  	}
  1646  
  1647  	for i := 0; i < 1000; i++ {
  1648  		expected[4] = Token{
  1649  			typ: token.Number,
  1650  			val: strconv.Itoa(i),
  1651  		}
  1652  
  1653  		testTable("test variable indexing", `cmd = $commands[`+strconv.Itoa(i)+`]`, expected, t)
  1654  	}
  1655  
  1656  	expected = []Token{
  1657  		{typ: token.Ident, val: "cmd"},
  1658  		{typ: token.Assign, val: "="},
  1659  		{typ: token.Variable, val: "$commands"},
  1660  		{typ: token.LBrack, val: "["},
  1661  		{typ: token.Arg, val: "a"},
  1662  		{typ: token.RBrack, val: "]"},
  1663  		{typ: token.Semicolon, val: ";"},
  1664  		{typ: token.EOF},
  1665  	}
  1666  
  1667  	testTable("test invalid number", `cmd = $commands[a]`, expected, t)
  1668  
  1669  	expected = []Token{
  1670  		{typ: token.Ident, val: "cmd"},
  1671  		{typ: token.Assign, val: "="},
  1672  		{typ: token.Variable, val: "$commands"},
  1673  		{typ: token.LBrack, val: "["},
  1674  		{typ: token.RBrack, val: "]"},
  1675  		{typ: token.Semicolon, val: ";"},
  1676  		{typ: token.EOF},
  1677  	}
  1678  
  1679  	testTable("test invalid number", `cmd = $commands[]`, expected, t)
  1680  
  1681  	expected = []Token{
  1682  		{typ: token.Ident, val: "echo"},
  1683  		{typ: token.Ident, val: "test"},
  1684  		{typ: token.Variable, val: "$names"},
  1685  		{typ: token.LBrack, val: "["},
  1686  		{typ: token.Number, val: "666"},
  1687  		{typ: token.RBrack, val: "]"},
  1688  		{typ: token.Semicolon, val: ";"},
  1689  		{typ: token.EOF},
  1690  	}
  1691  
  1692  	testTable("test variable index on commands", `echo test $names[666]`, expected, t)
  1693  
  1694  	expected = []Token{
  1695  		{typ: token.If, val: "if"},
  1696  		{typ: token.Variable, val: "$crazies"},
  1697  		{typ: token.LBrack, val: "["},
  1698  		{typ: token.Number, val: "0"},
  1699  		{typ: token.RBrack, val: "]"},
  1700  		{typ: token.Equal, val: "=="},
  1701  		{typ: token.String, val: "patito"},
  1702  		{typ: token.LBrace, val: "{"},
  1703  		{typ: token.Ident, val: "echo"},
  1704  		{typ: token.String, val: ":D"},
  1705  		{typ: token.RBrace, val: "}"},
  1706  		{typ: token.EOF},
  1707  	}
  1708  
  1709  	testTable("test if with indexing", `if $crazies[0] == "patito" { echo ":D" }`, expected, t)
  1710  }
  1711  
  1712  func TestLexerMultilineCmdExecution(t *testing.T) {
  1713  	expected := []Token{
  1714  		{typ: token.LParen, val: "("},
  1715  		{typ: token.RParen, val: ")"},
  1716  		{typ: token.Semicolon, val: ";"},
  1717  		{typ: token.EOF},
  1718  	}
  1719  
  1720  	testTable("multiline", `()`, expected, t)
  1721  
  1722  	expected = []Token{
  1723  		{typ: token.LParen, val: "("},
  1724  		{typ: token.Ident, val: "echo"},
  1725  		{typ: token.RParen, val: ")"},
  1726  		{typ: token.Semicolon, val: ";"},
  1727  		{typ: token.EOF},
  1728  	}
  1729  
  1730  	testTable("multiline", `(echo)`, expected, t)
  1731  
  1732  	expected = []Token{
  1733  		{typ: token.LParen, val: "("},
  1734  		{typ: token.Ident, val: "echo"},
  1735  		{typ: token.Ident, val: "AAAAA"},
  1736  		{typ: token.Ident, val: "AAAAA"},
  1737  		{typ: token.Ident, val: "AAAAA"},
  1738  		{typ: token.Ident, val: "AAAAA"},
  1739  		{typ: token.Ident, val: "AAAAA"},
  1740  		{typ: token.Ident, val: "AAAAA"},
  1741  		{typ: token.Ident, val: "BBBBB"},
  1742  		{typ: token.Ident, val: "BBBBB"},
  1743  		{typ: token.RParen, val: ")"},
  1744  		{typ: token.Semicolon, val: ";"},
  1745  		{typ: token.EOF},
  1746  	}
  1747  
  1748  	testTable("test multiline cmd execution", `(echo AAAAA AAAAA
  1749  	AAAAA AAAAA
  1750  	AAAAA AAAAA
  1751  	BBBBB BBBBB)`, expected, t)
  1752  }
  1753  
  1754  func TestLexerMultilineCmdAssign(t *testing.T) {
  1755  	expected := []Token{
  1756  		{typ: token.Ident, val: "some"},
  1757  		{typ: token.AssignCmd, val: "<="},
  1758  		{typ: token.LParen, val: "("},
  1759  		{typ: token.RParen, val: ")"},
  1760  		{typ: token.Semicolon, val: ";"},
  1761  		{typ: token.EOF},
  1762  	}
  1763  
  1764  	testTable("multiline", `some <= ()`, expected, t)
  1765  
  1766  	expected = []Token{
  1767  		{typ: token.Ident, val: "some"},
  1768  		{typ: token.AssignCmd, val: "<="},
  1769  		{typ: token.LParen, val: "("},
  1770  		{typ: token.Ident, val: "echo"},
  1771  		{typ: token.RParen, val: ")"},
  1772  		{typ: token.Semicolon, val: ";"},
  1773  		{typ: token.EOF},
  1774  	}
  1775  
  1776  	testTable("multiline", `some <= (echo)`, expected, t)
  1777  
  1778  	expected = []Token{
  1779  		{typ: token.Ident, val: "some"},
  1780  		{typ: token.AssignCmd, val: "<="},
  1781  		{typ: token.LParen, val: "("},
  1782  		{typ: token.Ident, val: "echo"},
  1783  		{typ: token.Ident, val: "AAAAA"},
  1784  		{typ: token.Ident, val: "AAAAA"},
  1785  		{typ: token.Ident, val: "AAAAA"},
  1786  		{typ: token.Ident, val: "AAAAA"},
  1787  		{typ: token.Ident, val: "AAAAA"},
  1788  		{typ: token.Ident, val: "AAAAA"},
  1789  		{typ: token.Ident, val: "BBBBB"},
  1790  		{typ: token.Ident, val: "BBBBB"},
  1791  		{typ: token.RParen, val: ")"},
  1792  		{typ: token.Semicolon, val: ";"},
  1793  		{typ: token.EOF},
  1794  	}
  1795  
  1796  	testTable("multiline", `some <= (echo AAAAA AAAAA
  1797  	AAAAA AAAAA
  1798  	AAAAA AAAAA
  1799  	BBBBB BBBBB)`, expected, t)
  1800  
  1801  	testTable("multiline", `some <= (
  1802  	echo AAAAA AAAAA
  1803  	AAAAA AAAAA
  1804  	AAAAA AAAAA
  1805  	BBBBB BBBBB
  1806  )`, expected, t)
  1807  }
  1808  
  1809  func TestLexerCommandDelimiter(t *testing.T) {
  1810  	expected := []Token{
  1811  		{typ: token.Ident, val: "echo"},
  1812  		{typ: token.String, val: "hello"},
  1813  		{typ: token.Semicolon, val: ";"},
  1814  		{typ: token.Ident, val: "echo"},
  1815  		{typ: token.String, val: "world"},
  1816  		{typ: token.Semicolon, val: ";"},
  1817  		{typ: token.EOF},
  1818  	}
  1819  
  1820  	testTable("semicolons to separate commands",
  1821  		`echo "hello"; echo "world"`, expected, t)
  1822  }
  1823  
  1824  func TestLexerLongAssignment(t *testing.T) {
  1825  	expected := []Token{
  1826  		{typ: token.Ident, val: "grpid"},
  1827  		{typ: token.AssignCmd, val: "<="},
  1828  		{typ: token.LParen, val: "("},
  1829  		{typ: token.Ident, val: "aws"},
  1830  		{typ: token.Ident, val: "ec2"},
  1831  		{typ: token.Arg, val: "create-security-group"},
  1832  		{typ: token.Arg, val: "--group-name"},
  1833  		{typ: token.Variable, val: "$name"},
  1834  		{typ: token.Arg, val: "--description"},
  1835  		{typ: token.Variable, val: "$desc"},
  1836  		{typ: token.Variable, val: "$vpcarg"},
  1837  		{typ: token.Pipe, val: "|"},
  1838  		{typ: token.Ident, val: "jq"},
  1839  		{typ: token.String, val: ".GroupId"},
  1840  		{typ: token.Pipe, val: "|"},
  1841  		{typ: token.Ident, val: "xargs"},
  1842  		{typ: token.Ident, val: "echo"},
  1843  		{typ: token.Arg, val: "-n"},
  1844  		{typ: token.RParen, val: ")"},
  1845  		{typ: token.Semicolon, val: ";"},
  1846  		{typ: token.EOF},
  1847  	}
  1848  
  1849  	testTable("test xxx", `grpid <= (
  1850  	aws ec2 create-security-group
  1851  				--group-name $name
  1852  				--description $desc
  1853  				$vpcarg |
  1854  	jq ".GroupId" |
  1855  	xargs echo -n)`, expected, t)
  1856  }
  1857  
  1858  func TestLexerVarArgs(t *testing.T) {
  1859  	expected := []Token{
  1860  		{typ: token.Ident, val: "println"},
  1861  		{typ: token.LParen, val: "("},
  1862  		{typ: token.Ident, val: "fmt"},
  1863  		{typ: token.Comma, val: ","},
  1864  		{typ: token.Ident, val: "args"},
  1865  		{typ: token.Dotdotdot, val: "..."},
  1866  		{typ: token.RParen, val: ")"},
  1867  		{typ: token.LBrace, val: "{"},
  1868  		{typ: token.Ident, val: "print"},
  1869  		{typ: token.LParen, val: "("},
  1870  		{typ: token.Variable, val: "$fmt"},
  1871  		{typ: token.Comma, val: ","},
  1872  		{typ: token.Variable, val: "$args"},
  1873  		{typ: token.Dotdotdot, val: "..."},
  1874  		{typ: token.RParen, val: ")"},
  1875  		{typ: token.Semicolon, val: ";"},
  1876  		{typ: token.RBrace, val: "}"},
  1877  		{typ: token.EOF},
  1878  	}
  1879  
  1880  	testTable("test var args", `println(fmt, args...) {
  1881  	print($fmt, $args...)
  1882  }`, expected, t)
  1883  	testTable("test var args", `println(fmt, args ...) {
  1884  	print($fmt, $args...)
  1885  }`, expected, t)
  1886  
  1887  	expected = []Token{
  1888  		{typ: token.Ident, val: "print"},
  1889  		{typ: token.LParen, val: "("},
  1890  		{typ: token.String, val: "%s:%s:%s"},
  1891  		{typ: token.Comma, val: ","},
  1892  		{typ: token.LParen, val: "("},
  1893  		{typ: token.String, val: "a"},
  1894  		{typ: token.String, val: "b"},
  1895  		{typ: token.String, val: "c"},
  1896  		{typ: token.RParen, val: ")"},
  1897  		{typ: token.Dotdotdot, val: "..."},
  1898  		{typ: token.RParen, val: ")"},
  1899  		{typ: token.Semicolon, val: ";"},
  1900  		{typ: token.EOF},
  1901  	}
  1902  
  1903  	testTable("test literal expansion", `print("%s:%s:%s", ("a" "b" "c")...)`,
  1904  		expected, t)
  1905  	testTable("test literal expansion", `print("%s:%s:%s", ("a" "b" "c") ...)`,
  1906  		expected, t)
  1907  }
  1908  
  1909  func TestLexerVar(t *testing.T) {
  1910  	expected := []Token{
  1911  		{typ: token.Var, val: "var"},
  1912  		{typ: token.Ident, val: "a"},
  1913  		{typ: token.Assign, val: "="},
  1914  		{typ: token.String, val: "hello world"},
  1915  		{typ: token.Semicolon, val: ";"},
  1916  		{typ: token.EOF},
  1917  	}
  1918  
  1919  	testTable("test simple var decl", `var a = "hello world"`, expected, t)
  1920  }