diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.go | 3 | ||||
-rw-r--r-- | compiler/ast_test.go | 119 |
2 files changed, 122 insertions, 0 deletions
diff --git a/compiler/ast.go b/compiler/ast.go index d4b8956..17054d0 100644 --- a/compiler/ast.go +++ b/compiler/ast.go @@ -260,6 +260,9 @@ func (n *concatNode) first() symbolPositionSet { func (n *concatNode) last() symbolPositionSet { s := newSymbolPositionSet() s.merge(n.right.last()) + if n.right.nullable() { + s.merge(n.left.last()) + } return s } diff --git a/compiler/ast_test.go b/compiler/ast_test.go new file mode 100644 index 0000000..61d6064 --- /dev/null +++ b/compiler/ast_test.go @@ -0,0 +1,119 @@ +package compiler + +import ( + "fmt" + "testing" +) + +func TestASTNode(t *testing.T) { + tests := []struct { + root astNode + nullable bool + first symbolPositionSet + last symbolPositionSet + }{ + { + root: newSymbolNode(nil, 0, 1), + nullable: false, + first: newSymbolPositionSet().add(1), + last: newSymbolPositionSet().add(1), + }, + { + root: newEndMarkerNode(1, 1), + nullable: false, + first: newSymbolPositionSet().add(1), + last: newSymbolPositionSet().add(1), + }, + { + root: newConcatNode( + newSymbolNode(nil, 0, 1), + newSymbolNode(nil, 0, 2), + ), + nullable: false, + first: newSymbolPositionSet().add(1), + last: newSymbolPositionSet().add(2), + }, + { + root: newConcatNode( + newRepeatNode(newSymbolNode(nil, 0, 1)), + newSymbolNode(nil, 0, 2), + ), + nullable: false, + first: newSymbolPositionSet().add(1).add(2), + last: newSymbolPositionSet().add(2), + }, + { + root: newConcatNode( + newSymbolNode(nil, 0, 1), + newRepeatNode(newSymbolNode(nil, 0, 2)), + ), + nullable: false, + first: newSymbolPositionSet().add(1), + last: newSymbolPositionSet().add(1).add(2), + }, + { + root: newConcatNode( + newRepeatNode(newSymbolNode(nil, 0, 1)), + newRepeatNode(newSymbolNode(nil, 0, 2)), + ), + nullable: true, + first: newSymbolPositionSet().add(1).add(2), + last: newSymbolPositionSet().add(1).add(2), + }, + { + root: newAltNode( + newSymbolNode(nil, 0, 1), + newSymbolNode(nil, 0, 2), + ), + nullable: false, + first: newSymbolPositionSet().add(1).add(2), + last: newSymbolPositionSet().add(1).add(2), + }, + { + root: newAltNode( + newRepeatNode(newSymbolNode(nil, 0, 1)), + newSymbolNode(nil, 0, 2), + ), + nullable: true, + first: newSymbolPositionSet().add(1).add(2), + last: newSymbolPositionSet().add(1).add(2), + }, + { + root: newAltNode( + newSymbolNode(nil, 0, 1), + newRepeatNode(newSymbolNode(nil, 0, 2)), + ), + nullable: true, + first: newSymbolPositionSet().add(1).add(2), + last: newSymbolPositionSet().add(1).add(2), + }, + { + root: newAltNode( + newRepeatNode(newSymbolNode(nil, 0, 1)), + newRepeatNode(newSymbolNode(nil, 0, 2)), + ), + nullable: true, + first: newSymbolPositionSet().add(1).add(2), + last: newSymbolPositionSet().add(1).add(2), + }, + { + root: newRepeatNode(newSymbolNode(nil, 0, 1)), + nullable: true, + first: newSymbolPositionSet().add(1), + last: newSymbolPositionSet().add(1), + }, + } + for i, tt := range tests { + t.Run(fmt.Sprintf("#%v", i), func(t *testing.T) { + if tt.root.nullable() != tt.nullable { + t.Errorf("unexpected nullable attribute; want: %v, got: %v", tt.nullable, tt.root.nullable()) + } + if tt.first.hash() != tt.root.first().hash() { + t.Errorf("unexpected first positions attribute; want: %v, got: %v", tt.first, tt.root.first()) + } + if tt.last.hash() != tt.root.last().hash() { + t.Errorf("unexpected last positions attribute; want: %v, got: %v", tt.last, tt.root.last()) + } + }) + } +} |