Improve semantics of tokens and values obtained from them.
Now gg.Values can carry the token used to parse them, which will be useful later when generating errors.
This commit is contained in:
parent
33e59a3836
commit
c5aa582226
@ -19,7 +19,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func decoderErr(tok LexerToken, err error) error {
|
func decoderErr(tok LexerToken, err error) error {
|
||||||
return fmt.Errorf("%d:%d: %w", tok.Row, tok.Col, err)
|
return fmt.Errorf("%s: %w", tok.errPrefix(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func decoderErrf(tok LexerToken, str string, args ...interface{}) error {
|
func decoderErrf(tok LexerToken, str string, args ...interface{}) error {
|
||||||
@ -53,7 +53,7 @@ func (d *decoder) parseSingleValue(
|
|||||||
tok, rest := toks[0], toks[1:]
|
tok, rest := toks[0], toks[1:]
|
||||||
|
|
||||||
if len(rest) == 0 {
|
if len(rest) == 0 {
|
||||||
return Value{}, nil, false, decoderErrf(tok, "cannot be final token, possibly missing %q", punctTerm)
|
return ZeroValue, nil, false, decoderErrf(tok, "cannot be final token, possibly missing %q", punctTerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
termed := isTerm(rest[0])
|
termed := isTerm(rest[0])
|
||||||
@ -65,20 +65,20 @@ func (d *decoder) parseSingleValue(
|
|||||||
switch tok.Kind {
|
switch tok.Kind {
|
||||||
|
|
||||||
case LexerTokenKindName:
|
case LexerTokenKindName:
|
||||||
return Value{Name: &tok.Value}, rest, termed, nil
|
return Value{Name: &tok.Value, LexerToken: &tok}, rest, termed, nil
|
||||||
|
|
||||||
case LexerTokenKindNumber:
|
case LexerTokenKindNumber:
|
||||||
|
|
||||||
i, err := strconv.ParseInt(tok.Value, 10, 64)
|
i, err := strconv.ParseInt(tok.Value, 10, 64)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Value{}, nil, false, decoderErrf(tok, "parsing %q as integer: %w", tok.Value, err)
|
return ZeroValue, nil, false, decoderErrf(tok, "parsing %q as integer: %w", tok.Value, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Value{Number: &i}, rest, termed, nil
|
return Value{Number: &i, LexerToken: &tok}, rest, termed, nil
|
||||||
|
|
||||||
case LexerTokenKindPunctuation:
|
case LexerTokenKindPunctuation:
|
||||||
return Value{}, nil, false, decoderErrf(tok, "expected value, found punctuation %q", tok.Value)
|
return ZeroValue, nil, false, decoderErrf(tok, "expected value, found punctuation %q", tok.Value)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unexpected token kind %q", tok.Kind))
|
panic(fmt.Sprintf("unexpected token kind %q", tok.Kind))
|
||||||
@ -116,7 +116,7 @@ func (d *decoder) parseOpenEdge(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if termed {
|
if termed {
|
||||||
return ValueOut(val, Value{}), toks, nil
|
return ValueOut(val, ZeroValue), toks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
opTok, toks := toks[0], toks[1:]
|
opTok, toks := toks[0], toks[1:]
|
||||||
@ -181,7 +181,7 @@ func (d *decoder) parseTuple(
|
|||||||
toks = toks[1:]
|
toks = toks[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return TupleOut(edges, Value{}), toks, nil
|
return TupleOut(edges, ZeroValue), toks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// returned boolean value indicates if the token following the graph is a term.
|
// returned boolean value indicates if the token following the graph is a term.
|
||||||
@ -211,18 +211,18 @@ func (d *decoder) parseGraphValue(
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return Value{}, nil, false, decoderErrf(openTok, "no matching %q", punctCloseGraph)
|
return ZeroValue, nil, false, decoderErrf(openTok, "no matching %q", punctCloseGraph)
|
||||||
|
|
||||||
} else if closingTok := toks[0]; isPunct(closingTok, punctCloseGraph) {
|
} else if closingTok := toks[0]; isPunct(closingTok, punctCloseGraph) {
|
||||||
|
|
||||||
if !expectWrappers {
|
if !expectWrappers {
|
||||||
return Value{}, nil, false, decoderErrf(closingTok, "unexpected %q", punctCloseGraph)
|
return ZeroValue, nil, false, decoderErrf(closingTok, "unexpected %q", punctCloseGraph)
|
||||||
}
|
}
|
||||||
|
|
||||||
toks = toks[1:]
|
toks = toks[1:]
|
||||||
|
|
||||||
if len(toks) == 0 {
|
if len(toks) == 0 {
|
||||||
return Value{}, nil, false, decoderErrf(closingTok, "cannot be final token, possibly missing %q", punctTerm)
|
return ZeroValue, nil, false, decoderErrf(closingTok, "cannot be final token, possibly missing %q", punctTerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
@ -231,7 +231,7 @@ func (d *decoder) parseGraphValue(
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
if g, toks, err = d.parseValIn(g, toks); err != nil {
|
if g, toks, err = d.parseValIn(g, toks); err != nil {
|
||||||
return Value{}, nil, false, err
|
return ZeroValue, nil, false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,6 +241,8 @@ func (d *decoder) parseGraphValue(
|
|||||||
return val, toks, true, nil
|
return val, toks, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val.LexerToken = &openTok
|
||||||
|
|
||||||
termed := isTerm(toks[0])
|
termed := isTerm(toks[0])
|
||||||
|
|
||||||
if termed {
|
if termed {
|
||||||
@ -276,7 +278,7 @@ func (d *decoder) parseValIn(into *Graph, toks []LexerToken) (*Graph, []LexerTok
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dstVal := Value{Name: &dst.Value}
|
dstVal := Value{Name: &dst.Value, LexerToken: &dst}
|
||||||
|
|
||||||
return into.AddValueIn(oe, dstVal), toks, nil
|
return into.AddValueIn(oe, dstVal), toks, nil
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ func TestDecoder(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: "out = 1;",
|
in: "out = 1;",
|
||||||
exp: ZeroGraph.AddValueIn(ValueOut(i(1), Value{}), n("out")),
|
exp: ZeroGraph.AddValueIn(ValueOut(i(1), ZeroValue), n("out")),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: "out = incr < 1;",
|
in: "out = incr < 1;",
|
||||||
@ -49,7 +49,7 @@ func TestDecoder(t *testing.T) {
|
|||||||
TupleOut(
|
TupleOut(
|
||||||
[]OpenEdge{TupleOut(
|
[]OpenEdge{TupleOut(
|
||||||
[]OpenEdge{
|
[]OpenEdge{
|
||||||
ValueOut(i(1), Value{}),
|
ValueOut(i(1), ZeroValue),
|
||||||
ValueOut(i(2), n("c")),
|
ValueOut(i(2), n("c")),
|
||||||
TupleOut(
|
TupleOut(
|
||||||
[]OpenEdge{ValueOut(i(3), n("e"))},
|
[]OpenEdge{ValueOut(i(3), n("e"))},
|
||||||
@ -69,11 +69,11 @@ func TestDecoder(t *testing.T) {
|
|||||||
TupleOut(
|
TupleOut(
|
||||||
[]OpenEdge{TupleOut(
|
[]OpenEdge{TupleOut(
|
||||||
[]OpenEdge{
|
[]OpenEdge{
|
||||||
ValueOut(i(1), Value{}),
|
ValueOut(i(1), ZeroValue),
|
||||||
TupleOut(
|
TupleOut(
|
||||||
[]OpenEdge{
|
[]OpenEdge{
|
||||||
ValueOut(i(2), n("d")),
|
ValueOut(i(2), n("d")),
|
||||||
ValueOut(i(3), Value{}),
|
ValueOut(i(3), ZeroValue),
|
||||||
},
|
},
|
||||||
n("c"),
|
n("c"),
|
||||||
),
|
),
|
||||||
@ -90,7 +90,7 @@ func TestDecoder(t *testing.T) {
|
|||||||
exp: ZeroGraph.AddValueIn(
|
exp: ZeroGraph.AddValueIn(
|
||||||
ValueOut(
|
ValueOut(
|
||||||
Value{Graph: ZeroGraph.
|
Value{Graph: ZeroGraph.
|
||||||
AddValueIn(ValueOut(i(1), Value{}), n("a")).
|
AddValueIn(ValueOut(i(1), ZeroValue), n("a")).
|
||||||
AddValueIn(
|
AddValueIn(
|
||||||
TupleOut(
|
TupleOut(
|
||||||
[]OpenEdge{
|
[]OpenEdge{
|
||||||
@ -101,7 +101,7 @@ func TestDecoder(t *testing.T) {
|
|||||||
n("b"),
|
n("b"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
Value{},
|
ZeroValue,
|
||||||
),
|
),
|
||||||
n("out"),
|
n("out"),
|
||||||
),
|
),
|
||||||
@ -114,7 +114,7 @@ func TestDecoder(t *testing.T) {
|
|||||||
ValueOut(
|
ValueOut(
|
||||||
i(2),
|
i(2),
|
||||||
Value{Graph: ZeroGraph.
|
Value{Graph: ZeroGraph.
|
||||||
AddValueIn(ValueOut(i(1), Value{}), n("b")),
|
AddValueIn(ValueOut(i(1), ZeroValue), n("b")),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -126,8 +126,8 @@ func TestDecoder(t *testing.T) {
|
|||||||
{
|
{
|
||||||
in: "a = 1; b = 2;",
|
in: "a = 1; b = 2;",
|
||||||
exp: ZeroGraph.
|
exp: ZeroGraph.
|
||||||
AddValueIn(ValueOut(i(1), Value{}), n("a")).
|
AddValueIn(ValueOut(i(1), ZeroValue), n("a")).
|
||||||
AddValueIn(ValueOut(i(2), Value{}), n("b")),
|
AddValueIn(ValueOut(i(2), ZeroValue), n("b")),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
gg/gg.go
33
gg/gg.go
@ -6,22 +6,37 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Value represents a value being stored in a Graph. No more than one field may
|
// ZeroValue is a Value with no fields set.
|
||||||
// be non-nil. No fields being set indicates lack of value.
|
var ZeroValue Value
|
||||||
|
|
||||||
|
// Value represents a value being stored in a Graph.
|
||||||
type Value struct {
|
type Value struct {
|
||||||
|
|
||||||
|
// Only one of these fields may be set
|
||||||
Name *string
|
Name *string
|
||||||
Number *int64
|
Number *int64
|
||||||
Graph *Graph
|
Graph *Graph
|
||||||
|
|
||||||
// TODO coming soon!
|
// TODO coming soon!
|
||||||
// String *string
|
// String *string
|
||||||
|
|
||||||
|
// Optional fields indicating the token which was used to construct this
|
||||||
|
// Value, if any.
|
||||||
|
LexerToken *LexerToken
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero returns true if the Value is the zero value (none of the sub-value
|
||||||
|
// fields are set). LexerToken is ignored for this check.
|
||||||
|
func (v Value) IsZero() bool {
|
||||||
|
v.LexerToken = nil
|
||||||
|
return v == Value{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equal returns true if the passed in Value is equivalent.
|
// Equal returns true if the passed in Value is equivalent.
|
||||||
func (v Value) Equal(v2 Value) bool {
|
func (v Value) Equal(v2 Value) bool {
|
||||||
switch {
|
switch {
|
||||||
|
|
||||||
case v == Value{} && v2 == Value{}:
|
case v.IsZero() && v2.IsZero():
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case v.Name != nil && v2.Name != nil && *v.Name == *v2.Name:
|
case v.Name != nil && v2.Name != nil && *v.Name == *v2.Name:
|
||||||
@ -42,8 +57,8 @@ func (v Value) String() string {
|
|||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
||||||
case v == Value{}:
|
case v.IsZero():
|
||||||
return "<noval>"
|
return "<zero>"
|
||||||
|
|
||||||
case v.Name != nil:
|
case v.Name != nil:
|
||||||
return *v.Name
|
return *v.Name
|
||||||
@ -105,24 +120,24 @@ func ValueOut(val, edgeVal Value) OpenEdge {
|
|||||||
// represents an edge (with edgeVal attached to it) coming from the
|
// represents an edge (with edgeVal attached to it) coming from the
|
||||||
// TupleVertex comprised of the given ordered-set of input edges.
|
// TupleVertex comprised of the given ordered-set of input edges.
|
||||||
//
|
//
|
||||||
// If len(ins) == 1 and edgeVal == Value{}, then that single OpenEdge is
|
// If len(ins) == 1 && edgeVal.IsZero(), then that single OpenEdge is
|
||||||
// returned as-is.
|
// returned as-is.
|
||||||
func TupleOut(ins []OpenEdge, edgeVal Value) OpenEdge {
|
func TupleOut(ins []OpenEdge, edgeVal Value) OpenEdge {
|
||||||
|
|
||||||
if len(ins) == 1 {
|
if len(ins) == 1 {
|
||||||
|
|
||||||
if edgeVal == (Value{}) {
|
if edgeVal.IsZero() {
|
||||||
return ins[0]
|
return ins[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
if ins[0].val == (Value{}) {
|
if ins[0].val.IsZero() {
|
||||||
return ins[0].WithEdgeVal(edgeVal)
|
return ins[0].WithEdgeVal(edgeVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return OpenEdge{
|
return OpenEdge{
|
||||||
fromV: mkVertex(TupleVertex, Value{}, ins...),
|
fromV: mkVertex(TupleVertex, ZeroValue, ins...),
|
||||||
val: edgeVal,
|
val: edgeVal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ func TestEqual(t *testing.T) {
|
|||||||
// equivalent to just that edge.
|
// equivalent to just that edge.
|
||||||
a: ZeroGraph.AddValueIn(TupleOut([]OpenEdge{
|
a: ZeroGraph.AddValueIn(TupleOut([]OpenEdge{
|
||||||
ValueOut(i(1), n("ident")),
|
ValueOut(i(1), n("ident")),
|
||||||
}, Value{}), n("out")),
|
}, ZeroValue), n("out")),
|
||||||
b: ZeroGraph.AddValueIn(ValueOut(i(1), n("ident")), n("out")),
|
b: ZeroGraph.AddValueIn(ValueOut(i(1), n("ident")), n("out")),
|
||||||
exp: true,
|
exp: true,
|
||||||
},
|
},
|
||||||
@ -70,7 +70,7 @@ func TestEqual(t *testing.T) {
|
|||||||
// edgeVal should be equivalent to just that edge with the tuple's
|
// edgeVal should be equivalent to just that edge with the tuple's
|
||||||
// edge value.
|
// edge value.
|
||||||
a: ZeroGraph.AddValueIn(TupleOut([]OpenEdge{
|
a: ZeroGraph.AddValueIn(TupleOut([]OpenEdge{
|
||||||
ValueOut(i(1), Value{}),
|
ValueOut(i(1), ZeroValue),
|
||||||
}, n("ident")), n("out")),
|
}, n("ident")), n("out")),
|
||||||
b: ZeroGraph.AddValueIn(ValueOut(i(1), n("ident")), n("out")),
|
b: ZeroGraph.AddValueIn(ValueOut(i(1), n("ident")), n("out")),
|
||||||
exp: true,
|
exp: true,
|
||||||
|
43
gg/lexer.go
43
gg/lexer.go
@ -8,15 +8,26 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LexerError is returned by Lexer when an unexpected error occurs parsing a
|
// LexerLocation describes the location in a file where a particular token was
|
||||||
// stream of LexerTokens.
|
// parsed from.
|
||||||
type LexerError struct {
|
type LexerLocation struct {
|
||||||
Err error
|
|
||||||
Row, Col int
|
Row, Col int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l LexerLocation) String() string {
|
||||||
|
return fmt.Sprintf("%d:%d", l.Row, l.Col)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LexerError is returned by Lexer when an unexpected error occurs parsing a
|
||||||
|
// stream of LexerTokens.
|
||||||
|
type LexerError struct {
|
||||||
|
Err error
|
||||||
|
|
||||||
|
Location LexerLocation
|
||||||
|
}
|
||||||
|
|
||||||
func (e *LexerError) Error() string {
|
func (e *LexerError) Error() string {
|
||||||
return fmt.Sprintf("%d:%d: %s", e.Row, e.Col, e.Err.Error())
|
return fmt.Sprintf("%s: %s", e.Location.String(), e.Err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *LexerError) Unwrap() error {
|
func (e *LexerError) Unwrap() error {
|
||||||
@ -39,7 +50,11 @@ type LexerToken struct {
|
|||||||
Kind LexerTokenKind
|
Kind LexerTokenKind
|
||||||
Value string // never empty string
|
Value string // never empty string
|
||||||
|
|
||||||
Row, Col int
|
Location LexerLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t LexerToken) errPrefix() string {
|
||||||
|
return fmt.Sprintf("%s: at %q", t.Location.String(), t.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lexer is used to parse a string stream into a sequence of tokens which can
|
// Lexer is used to parse a string stream into a sequence of tokens which can
|
||||||
@ -90,8 +105,10 @@ func (l *lexer) fmtErr(err error) *LexerError {
|
|||||||
|
|
||||||
return &LexerError{
|
return &LexerError{
|
||||||
Err: err,
|
Err: err,
|
||||||
Row: row,
|
Location: LexerLocation{
|
||||||
Col: col,
|
Row: row,
|
||||||
|
Col: col,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +184,9 @@ func (l *lexer) readWhile(
|
|||||||
return LexerToken{
|
return LexerToken{
|
||||||
Kind: kind,
|
Kind: kind,
|
||||||
Value: l.stringBuilder.String(),
|
Value: l.stringBuilder.String(),
|
||||||
Row: row, Col: col,
|
Location: LexerLocation{
|
||||||
|
Row: row, Col: col,
|
||||||
|
},
|
||||||
}, lexErr
|
}, lexErr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,8 +255,10 @@ func (l *lexer) next() (LexerToken, *LexerError) {
|
|||||||
return LexerToken{
|
return LexerToken{
|
||||||
Kind: LexerTokenKindPunctuation,
|
Kind: LexerTokenKindPunctuation,
|
||||||
Value: string(r),
|
Value: string(r),
|
||||||
Row: l.lastRow,
|
Location: LexerLocation{
|
||||||
Col: l.lastCol,
|
Row: l.lastRow,
|
||||||
|
Col: l.lastCol,
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
case unicode.IsSpace(r):
|
case unicode.IsSpace(r):
|
||||||
|
100
gg/lexer_test.go
100
gg/lexer_test.go
@ -23,9 +23,9 @@ func TestLexer(t *testing.T) {
|
|||||||
in: "foo",
|
in: "foo",
|
||||||
exp: []LexerToken{
|
exp: []LexerToken{
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindName,
|
Kind: LexerTokenKindName,
|
||||||
Value: "foo",
|
Value: "foo",
|
||||||
Row: 0, Col: 0,
|
Location: LexerLocation{Row: 0, Col: 0},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -33,29 +33,29 @@ func TestLexer(t *testing.T) {
|
|||||||
in: "foo bar\nf-o f0O Foo",
|
in: "foo bar\nf-o f0O Foo",
|
||||||
exp: []LexerToken{
|
exp: []LexerToken{
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindName,
|
Kind: LexerTokenKindName,
|
||||||
Value: "foo",
|
Value: "foo",
|
||||||
Row: 0, Col: 0,
|
Location: LexerLocation{Row: 0, Col: 0},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindName,
|
Kind: LexerTokenKindName,
|
||||||
Value: "bar",
|
Value: "bar",
|
||||||
Row: 0, Col: 4,
|
Location: LexerLocation{Row: 0, Col: 4},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindName,
|
Kind: LexerTokenKindName,
|
||||||
Value: "f-o",
|
Value: "f-o",
|
||||||
Row: 1, Col: 0,
|
Location: LexerLocation{Row: 1, Col: 0},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindName,
|
Kind: LexerTokenKindName,
|
||||||
Value: "f0O",
|
Value: "f0O",
|
||||||
Row: 1, Col: 4,
|
Location: LexerLocation{Row: 1, Col: 4},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindName,
|
Kind: LexerTokenKindName,
|
||||||
Value: "Foo",
|
Value: "Foo",
|
||||||
Row: 1, Col: 8,
|
Location: LexerLocation{Row: 1, Col: 8},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -63,19 +63,19 @@ func TestLexer(t *testing.T) {
|
|||||||
in: "1 100 -100",
|
in: "1 100 -100",
|
||||||
exp: []LexerToken{
|
exp: []LexerToken{
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindNumber,
|
Kind: LexerTokenKindNumber,
|
||||||
Value: "1",
|
Value: "1",
|
||||||
Row: 0, Col: 0,
|
Location: LexerLocation{Row: 0, Col: 0},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindNumber,
|
Kind: LexerTokenKindNumber,
|
||||||
Value: "100",
|
Value: "100",
|
||||||
Row: 0, Col: 2,
|
Location: LexerLocation{Row: 0, Col: 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindNumber,
|
Kind: LexerTokenKindNumber,
|
||||||
Value: "-100",
|
Value: "-100",
|
||||||
Row: 0, Col: 6,
|
Location: LexerLocation{Row: 0, Col: 6},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -83,39 +83,39 @@ func TestLexer(t *testing.T) {
|
|||||||
in: "1<2!-3 ()",
|
in: "1<2!-3 ()",
|
||||||
exp: []LexerToken{
|
exp: []LexerToken{
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindNumber,
|
Kind: LexerTokenKindNumber,
|
||||||
Value: "1",
|
Value: "1",
|
||||||
Row: 0, Col: 0,
|
Location: LexerLocation{Row: 0, Col: 0},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindPunctuation,
|
Kind: LexerTokenKindPunctuation,
|
||||||
Value: "<",
|
Value: "<",
|
||||||
Row: 0, Col: 1,
|
Location: LexerLocation{Row: 0, Col: 1},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindNumber,
|
Kind: LexerTokenKindNumber,
|
||||||
Value: "2",
|
Value: "2",
|
||||||
Row: 0, Col: 2,
|
Location: LexerLocation{Row: 0, Col: 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindPunctuation,
|
Kind: LexerTokenKindPunctuation,
|
||||||
Value: "!",
|
Value: "!",
|
||||||
Row: 0, Col: 3,
|
Location: LexerLocation{Row: 0, Col: 3},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindNumber,
|
Kind: LexerTokenKindNumber,
|
||||||
Value: "-3",
|
Value: "-3",
|
||||||
Row: 0, Col: 4,
|
Location: LexerLocation{Row: 0, Col: 4},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindPunctuation,
|
Kind: LexerTokenKindPunctuation,
|
||||||
Value: "(",
|
Value: "(",
|
||||||
Row: 0, Col: 7,
|
Location: LexerLocation{Row: 0, Col: 7},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: LexerTokenKindPunctuation,
|
Kind: LexerTokenKindPunctuation,
|
||||||
Value: ")",
|
Value: ")",
|
||||||
Row: 0, Col: 8,
|
Location: LexerLocation{Row: 0, Col: 8},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -142,8 +142,8 @@ func TestLexer(t *testing.T) {
|
|||||||
inParts := strings.Split(test.in, "\n")
|
inParts := strings.Split(test.in, "\n")
|
||||||
|
|
||||||
assert.ErrorIs(t, lexErr, expErr)
|
assert.ErrorIs(t, lexErr, expErr)
|
||||||
assert.Equal(t, lexErr.Row, len(inParts)-1)
|
assert.Equal(t, lexErr.Location.Row, len(inParts)-1)
|
||||||
assert.Equal(t, lexErr.Col, len(inParts[len(inParts)-1]))
|
assert.Equal(t, lexErr.Location.Col, len(inParts[len(inParts)-1]))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user