From 520bf02582be7ab36b17fd78f8931cfdb702b07f Mon Sep 17 00:00:00 2001 From: Ryo Nihei Date: Tue, 25 May 2021 21:55:17 +0900 Subject: Add fragment expression A fragment entry is defined by an entry whose `fragment` field is `true`, and is referenced by a fragment expression (`\f{...}`). --- compiler/parser_test.go | 134 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 126 insertions(+), 8 deletions(-) (limited to 'compiler/parser_test.go') diff --git a/compiler/parser_test.go b/compiler/parser_test.go index aca08ec..3394845 100644 --- a/compiler/parser_test.go +++ b/compiler/parser_test.go @@ -1,7 +1,6 @@ package compiler import ( - "bytes" "fmt" "reflect" "testing" @@ -23,9 +22,10 @@ func endPos(n uint16) symbolPosition { return pos } -func TestParser_parse(t *testing.T) { +func TestParse(t *testing.T) { tests := []struct { pattern string + fragments map[string]string ast astNode syntaxError *SyntaxError @@ -91,6 +91,24 @@ func TestParser_parse(t *testing.T) { pattern: "\\p{Letter}?", skipTestAST: true, }, + { + pattern: "\\f{a2c}?", + fragments: map[string]string{ + "a2c": "abc", + }, + ast: genConcatNode( + newOptionNode( + newFragmentNode("a2c", + genConcatNode( + newSymbolNodeWithPos(byte('a'), symPos(1)), + newSymbolNodeWithPos(byte('b'), symPos(2)), + newSymbolNodeWithPos(byte('c'), symPos(3)), + ), + ), + ), + newEndMarkerNodeWithPos(1, endPos(4)), + ), + }, { pattern: "(a)?", ast: genConcatNode( @@ -197,6 +215,24 @@ func TestParser_parse(t *testing.T) { pattern: "\\p{Letter}*", skipTestAST: true, }, + { + pattern: "\\f{a2c}*", + fragments: map[string]string{ + "a2c": "abc", + }, + ast: genConcatNode( + newRepeatNode( + newFragmentNode("a2c", + genConcatNode( + newSymbolNodeWithPos(byte('a'), symPos(1)), + newSymbolNodeWithPos(byte('b'), symPos(2)), + newSymbolNodeWithPos(byte('c'), symPos(3)), + ), + ), + ), + newEndMarkerNodeWithPos(1, endPos(4)), + ), + }, { pattern: "((a*)*)*", ast: genConcatNode( @@ -305,6 +341,31 @@ func TestParser_parse(t *testing.T) { pattern: "\\p{Letter}+", skipTestAST: true, }, + { + pattern: "\\f{a2c}+", + fragments: map[string]string{ + "a2c": "abc", + }, + ast: genConcatNode( + newFragmentNode("a2c", + genConcatNode( + newSymbolNodeWithPos(byte('a'), symPos(1)), + newSymbolNodeWithPos(byte('b'), symPos(2)), + newSymbolNodeWithPos(byte('c'), symPos(3)), + ), + ), + newRepeatNode( + newFragmentNode("a2c", + genConcatNode( + newSymbolNodeWithPos(byte('a'), symPos(4)), + newSymbolNodeWithPos(byte('b'), symPos(5)), + newSymbolNodeWithPos(byte('c'), symPos(6)), + ), + ), + ), + newEndMarkerNodeWithPos(1, endPos(7)), + ), + }, { pattern: "((a+)+)+", ast: genConcatNode( @@ -916,6 +977,53 @@ func TestParser_parse(t *testing.T) { pattern: "\\p{}", syntaxError: synErrCharPropExpInvalidForm, }, + { + pattern: "\\f{a2c}", + fragments: map[string]string{ + "a2c": "abc", + }, + ast: genConcatNode( + newFragmentNode("a2c", + genConcatNode( + newSymbolNodeWithPos(byte('a'), symPos(1)), + newSymbolNodeWithPos(byte('b'), symPos(2)), + newSymbolNodeWithPos(byte('c'), symPos(3)), + ), + ), + newEndMarkerNodeWithPos(1, endPos(4)), + ), + }, + { + pattern: "\\f{ a2c }", + fragments: map[string]string{ + "a2c": "abc", + }, + ast: genConcatNode( + newFragmentNode("a2c", + genConcatNode( + newSymbolNodeWithPos(byte('a'), symPos(1)), + newSymbolNodeWithPos(byte('b'), symPos(2)), + newSymbolNodeWithPos(byte('c'), symPos(3)), + ), + ), + newEndMarkerNodeWithPos(1, endPos(4)), + ), + }, + { + pattern: "\\f", + syntaxError: synErrFragmentExpInvalidForm, + }, + { + pattern: "\\f{", + syntaxError: synErrFragmentExpInvalidForm, + }, + { + pattern: "\\f{a2c", + fragments: map[string]string{ + "a2c": "abc", + }, + syntaxError: synErrFragmentExpInvalidForm, + }, { pattern: "(a)", ast: newConcatNode( @@ -1085,16 +1193,26 @@ func TestParser_parse(t *testing.T) { } for i, tt := range tests { t.Run(fmt.Sprintf("#%v %v", i, tt.pattern), func(t *testing.T) { - p := newParser(1, symbolPositionMin, bytes.NewReader([]byte(tt.pattern))) - ast, err := p.parse() + fragments := map[string][]byte{} + for kind, pattern := range tt.fragments { + fragments[kind] = []byte(pattern) + } + ast, _, err := parse(map[int][]byte{ + 1: []byte(tt.pattern), + }, fragments) if tt.syntaxError != nil { // printAST(os.Stdout, ast, "", "", false) if err == nil { t.Fatalf("expected syntax error; got: nil") } - synErr, ok := err.(*SyntaxError) + parseErrs, ok := err.(*ParseErrors) + if !ok { + t.Fatalf("expected ParseErrors; got: %v (type: %T)", err, err) + } + parseErr := parseErrs.Errors[0].Cause + synErr, ok := parseErr.(*SyntaxError) if !ok { - t.Fatalf("expected SyntaxError; got: %v (type: %T)", err, err) + t.Fatalf("expected SyntaxError; got: %v (type: %T)", parseErr, parseErr) } if synErr != tt.syntaxError { t.Fatalf("unexpected syntax error; want: %v, got: %v", tt.syntaxError, synErr) @@ -1118,10 +1236,10 @@ func TestParser_parse(t *testing.T) { } } -func TestParse(t *testing.T) { +func TestParse_FollowAndSymbolTable(t *testing.T) { root, symTab, err := parse(map[int][]byte{ 1: []byte("(a|b)*abb"), - }) + }, nil) if err != nil { t.Fatal(err) } -- cgit v1.2.3