Refactor to use new parser

This commit is contained in:
Anton Medvedev
2020-02-25 09:33:17 +03:00
parent 9025060692
commit 0809f2c91b
12 changed files with 97 additions and 57 deletions
+8 -3
View File
@@ -10,17 +10,22 @@ import (
// Node represents items of abstract syntax tree.
type Node interface {
Location() file.Location
SetLocation(file.Location)
Type() reflect.Type
SetType(reflect.Type)
}
type Base struct {
Loc file.Location
loc file.Location
nodeType reflect.Type
}
func (n *Base) Location() file.Location {
return n.Loc
return n.loc
}
func (n *Base) SetLocation(loc file.Location) {
n.loc = loc
}
func (n *Base) Type() reflect.Type {
@@ -32,7 +37,7 @@ func (n *Base) SetType(t reflect.Type) {
}
func Loc(l file.Location) Base {
return Base{Loc: l}
return Base{loc: l}
}
type NilNode struct {
+1 -1
View File
@@ -115,7 +115,7 @@ func (v *visitor) visit(node ast.Node) reflect.Type {
func (v *visitor) error(node ast.Node, format string, args ...interface{}) file.Error {
return file.Error{
Location: node.GetLocation(),
Location: node.Location(),
Message: fmt.Sprintf(format, args...),
}
}
+4 -4
View File
@@ -23,8 +23,8 @@ func (p *operatorPatcher) Exit(node *ast.Node) {
return
}
leftType := binaryNode.Left.GetType()
rightType := binaryNode.Right.GetType()
leftType := binaryNode.Left.Type()
rightType := binaryNode.Right.Type()
_, fn, ok := conf.FindSuitableOperatorOverload(fns, p.types, leftType, rightType)
if ok {
@@ -32,8 +32,8 @@ func (p *operatorPatcher) Exit(node *ast.Node) {
Name: fn,
Arguments: []ast.Node{binaryNode.Left, binaryNode.Right},
}
newNode.SetType((*node).GetType())
newNode.SetLocation((*node).GetLocation())
newNode.SetType((*node).Type())
newNode.SetLocation((*node).Location())
*node = newNode
}
}
+3 -3
View File
@@ -62,7 +62,7 @@ func (c *compiler) emit(op byte, b ...byte) int {
c.bytecode = append(c.bytecode, b...)
for i := 0; i < 1+len(b); i++ {
c.locations = append(c.locations, c.currentNode.GetLocation())
c.locations = append(c.locations, c.currentNode.Location())
}
return current
@@ -178,7 +178,7 @@ func (c *compiler) IdentifierNode(node *ast.IdentifierNode) {
}
func (c *compiler) IntegerNode(node *ast.IntegerNode) {
t := node.GetType()
t := node.Type()
if t == nil {
c.emitPush(node.Value)
return
@@ -632,7 +632,7 @@ func encode(i uint16) []byte {
}
func kind(node ast.Node) reflect.Kind {
t := node.GetType()
t := node.Type()
if t == nil {
return reflect.Invalid
}
+3 -3
View File
@@ -94,7 +94,7 @@ func ExampleEval_error() {
fmt.Printf("%v", output)
// Output: syntax error: mismatched input ']' expecting ')' (1:11)
// Output: unexpected token Bracket("]") (1:11)
// | (boo + bar]
// | ..........^
}
@@ -108,9 +108,9 @@ func ExampleEval_matches() {
fmt.Printf("%v", output)
// Output: error parsing regexp: missing closing ): `a(` (1:13)
// Output: error parsing regexp: missing closing ): `a(` (1:17)
// | "a" matches "a("
// | ............^
// | ................^
}
func ExampleCompile() {
+3 -3
View File
@@ -27,9 +27,9 @@ func (e *Error) Error() string {
return e.Message
}
func (e *Error) Format(source *Source) error {
func (e *Error) Format(source *Source) string {
if e.Location.Empty() {
return fmt.Errorf(e.Message)
return e.Message
}
var result = fmt.Sprintf(
"%s (%d:%d)",
@@ -58,5 +58,5 @@ func (e *Error) Format(source *Source) error {
}
result += srcLine + indLine
}
return fmt.Errorf(result)
return result
}
+3 -3
View File
@@ -47,7 +47,7 @@ func (*inArray) Exit(node *Node) {
if n.Operator == "in" || n.Operator == "not in" {
if array, ok := n.Right.(*ArrayNode); ok {
if len(array.Nodes) > 0 {
t := n.Left.GetType()
t := n.Left.Type()
if t == nil || t.Kind() != reflect.Int {
// This optimization can be only performed if left side is int type,
// as runtime.in func uses reflect.Map.MapIndex and keys of map must,
@@ -251,7 +251,7 @@ func (*constRange) Exit(node *Node) {
}
func patch(node *Node, newNode Node) {
newNode.SetType((*node).GetType())
newNode.SetLocation((*node).GetLocation())
newNode.SetType((*node).Type())
newNode.SetLocation((*node).Location())
*node = newNode
}
+7 -7
View File
@@ -17,11 +17,11 @@ func Lex(source *file.Source) ([]Token, error) {
state = state(l)
}
if l.err == nil {
return l.tokens, nil
if l.err != nil {
return nil, fmt.Errorf("%v", l.err.Format(source))
}
return nil, l.err.Format(source)
return l.tokens, nil
}
type lexer struct {
@@ -62,7 +62,7 @@ func (l *lexer) emit(t Kind) {
func (l *lexer) emitValue(t Kind, value string) {
l.tokens = append(l.tokens, Token{
Location: l.loc(),
Location: l.loc(l.start),
Kind: t,
Value: value,
})
@@ -105,17 +105,17 @@ func (l *lexer) acceptWord(word string) bool {
func (l *lexer) error(format string, args ...interface{}) stateFn {
if l.err == nil { // show first error
l.err = &file.Error{
Location: l.loc(),
Location: l.loc(l.end - 1),
Message: fmt.Sprintf(format, args...),
}
}
return nil
}
func (l *lexer) loc() file.Location {
func (l *lexer) loc(pos int) file.Location {
line, column := 1, 0
for i, ch := range []rune(l.input) {
if i == l.end-1 {
if i == pos {
break
}
if ch == '\n' {
+3 -1
View File
@@ -20,7 +20,7 @@ type lexErrorTest struct {
var lexTests = []lexTest{
{
".5 1 02 1e3 0xFF 1.2e-4 1_000_000 _42",
".5 1 02 1e3 0xFF 1.2e-4 1_000_000 _42 -.5",
[]Token{
{Kind: Number, Value: ".5"},
{Kind: Number, Value: "1"},
@@ -30,6 +30,8 @@ var lexTests = []lexTest{
{Kind: Number, Value: "1.2e-4"},
{Kind: Number, Value: "1_000_000"},
{Kind: Identifier, Value: "_42"},
{Kind: Operator, Value: "-"},
{Kind: Number, Value: ".5"},
{Kind: EOF},
},
},
+4 -11
View File
@@ -28,10 +28,10 @@ func root(l *lexer) stateFn {
l.emit(Bracket)
case strings.ContainsRune(")]}", r):
l.emit(Bracket)
case strings.ContainsRune(",?!:%&*+-/<=>^|", r):
l.backup()
return operator
case r == '#':
case strings.ContainsRune("#,?:%+-/", r): // single rune operator
l.emit(Operator)
case strings.ContainsRune("&|!=*<>", r): // possible double rune operator
l.accept("&|=*")
l.emit(Operator)
case r == '.':
l.backup()
@@ -87,13 +87,6 @@ func (l *lexer) scanNumber() bool {
return true
}
func operator(l *lexer) stateFn {
l.next()
l.accept(".|&=*")
l.emit(Operator)
return root
}
func dot(l *lexer) stateFn {
l.next()
if l.accept("0123456789") {
+40 -12
View File
@@ -104,7 +104,7 @@ func Parse(input string) (*Tree, error) {
}
if p.err != nil {
return nil, p.err.Format(source)
return nil, fmt.Errorf("%v", p.err.Format(source))
}
return &Tree{
@@ -203,7 +203,7 @@ func (p *parser) parsePrimary() Node {
p.next()
expr := p.parseExpression(op.precedence)
return p.parsePostfixExpression(&UnaryNode{
Base: Base{Loc: token.Location},
Base: Loc(token.Location),
Operator: token.Value,
Node: expr,
})
@@ -447,25 +447,53 @@ func (p *parser) parsePostfixExpression(node Node) Node {
} else if token.Value == "[" {
p.next()
arg := p.parseExpression(0)
if p.current.Is(Operator, ":") {
var from, to Node
if p.current.Is(Operator, ":") { // slice without from [:1]
p.next()
from := arg
to := p.parseExpression(0)
if !p.current.Is(Bracket, "]") { // slice without from and to [:]
to = p.parseExpression(0)
}
node = &SliceNode{
Base: Loc(p.current.Location),
Node: node,
From: from,
To: to,
}
p.expect(Bracket, "]")
} else {
node = &IndexNode{
Base: Loc(token.Location),
Node: node,
Index: arg,
from = p.parseExpression(0)
if p.current.Is(Operator, ":") {
p.next()
if !p.current.Is(Bracket, "]") { // slice without to [1:]
to = p.parseExpression(0)
}
node = &SliceNode{
Base: Loc(p.current.Location),
Node: node,
From: from,
To: to,
}
p.expect(Bracket, "]")
} else {
// Slice operator [:] was not found, it should by just index node.
node = &IndexNode{
Base: Loc(token.Location),
Node: node,
Index: from,
}
p.expect(Bracket, "]")
}
}
p.expect(Bracket, "]")
} else {
break
}
+18 -6
View File
@@ -198,6 +198,18 @@ func TestParse(t *testing.T) {
"array[1:2]",
&ast.SliceNode{Node: &ast.IdentifierNode{Value: "array"}, From: &ast.IntegerNode{Value: 1}, To: &ast.IntegerNode{Value: 2}},
},
{
"array[:2]",
&ast.SliceNode{Node: &ast.IdentifierNode{Value: "array"}, To: &ast.IntegerNode{Value: 2}},
},
{
"array[1:]",
&ast.SliceNode{Node: &ast.IdentifierNode{Value: "array"}, From: &ast.IntegerNode{Value: 1}},
},
{
"array[:]",
&ast.SliceNode{Node: &ast.IdentifierNode{Value: "array"}},
},
}
for _, test := range parseTests {
actual, err := parser.Parse(test.input)
@@ -215,14 +227,14 @@ func TestParse(t *testing.T) {
const errorTests = `
foo.
unexpected end of expression (1:4)
unexpected end of expression (1:5)
| foo.
| ...^
| ....^
a+
unexpected token EOF (1:2)
unexpected token EOF (1:3)
| a+
| .^
| ..^
a ? (1+2) c
unexpected token Identifier("c") (1:11)
@@ -245,9 +257,9 @@ a map key must be a quoted string, a number, a identifier, or an expression encl
| .^
a matches 'a:)b'
error parsing regexp: unexpected ): ` + "`a:)b`" + ` (1:16)
error parsing regexp: unexpected ): ` + "`a:)b`" + ` (1:17)
| a matches 'a:)b'
| ...............^
| ................^
foo({.bar})
a map key must be a quoted string, a number, a identifier, or an expression enclosed in parentheses (unexpected token Operator(".")) (1:6)