This idea may work, or may not
This commit is contained in:
		@@ -9,6 +9,8 @@ type Token struct {
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
    K_SPACES = "\t\n\r "
 | 
			
		||||
    // Must be defined in pairs with
 | 
			
		||||
    // open bracket on left and close bracket on right
 | 
			
		||||
    K_BRACKETS = "()[]{}"
 | 
			
		||||
    K_QUOTES = "'\"`"
 | 
			
		||||
)
 | 
			
		||||
@@ -46,6 +48,6 @@ var KEYWORDS = []string {
 | 
			
		||||
    "WITH",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var STATEMENTS = map[string] func() ( IStatement, error ) {
 | 
			
		||||
var STATEMENTS = map[string] func( *Lexer ) ( IStatement, error ) {
 | 
			
		||||
    "BUY": _buyStatement,
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										115
									
								
								mmql/lexer.go
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								mmql/lexer.go
									
									
									
									
									
								
							@@ -1,14 +1,119 @@
 | 
			
		||||
package mmql
 | 
			
		||||
 | 
			
		||||
import "fmt"
 | 
			
		||||
import (
 | 
			
		||||
    "fmt"
 | 
			
		||||
    "io"
 | 
			
		||||
    "strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type LexerExpect struct {
 | 
			
		||||
    statements bool
 | 
			
		||||
    keywords bool
 | 
			
		||||
    brackets bool
 | 
			
		||||
    quotes bool
 | 
			
		||||
    key string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Lexer struct {
 | 
			
		||||
    expect TokenType
 | 
			
		||||
    reader *strings.Reader
 | 
			
		||||
    readToken bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ( this *Lexer ) Parse( line string ) {
 | 
			
		||||
func ( this *Lexer ) Parse( line string ) ( IStatement, error ) {
 | 
			
		||||
 | 
			
		||||
    for i, r := range line {
 | 
			
		||||
        fmt.Printf( "%d: %s\n", i, string( r ) )
 | 
			
		||||
    this.reader = strings.NewReader( line )
 | 
			
		||||
 | 
			
		||||
    ex := LexerExpect{
 | 
			
		||||
        statements: true,
 | 
			
		||||
        keywords: false,
 | 
			
		||||
        brackets: true,
 | 
			
		||||
        quotes: true,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return this.ReadStatement( &ex )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ( this *Lexer ) ReadStatement( expecting *LexerExpect ) ( IStatement, error ) {
 | 
			
		||||
    reader := this.reader
 | 
			
		||||
 | 
			
		||||
    var stmt IStatement
 | 
			
		||||
 | 
			
		||||
    for {
 | 
			
		||||
        r, _, err := reader.ReadRune()
 | 
			
		||||
        if err != nil {
 | 
			
		||||
            return nil, err
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if expecting.quotes && strings.ContainsRune( K_QUOTES, r ) {
 | 
			
		||||
            s, err := this.ReadUntilClose( r, true, '\\' )
 | 
			
		||||
            if err != nil {
 | 
			
		||||
                return nil, err
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            stmt = QuotedValue{
 | 
			
		||||
                RawStatement: &RawStatement{ Value: s },
 | 
			
		||||
                Quote: string( r ),
 | 
			
		||||
            }
 | 
			
		||||
            return stmt, nil
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bracketIndex := strings.IndexRune( K_BRACKETS, r )
 | 
			
		||||
        if expecting.brackets && bracketIndex % 2 == 0 {
 | 
			
		||||
            cl := rune( K_BRACKETS[ bracketIndex + 1 ] )
 | 
			
		||||
            s, err := this.ReadUntilClose( cl, false, 'A' )
 | 
			
		||||
            if err != nil {
 | 
			
		||||
                return nil, err
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var b strings.Builder
 | 
			
		||||
            b.WriteRune( r )
 | 
			
		||||
            b.WriteRune( cl )
 | 
			
		||||
 | 
			
		||||
            stmt = BracketedValue{
 | 
			
		||||
                RawStatement: &RawStatement{ Value: s },
 | 
			
		||||
                Brackets: b.String(),
 | 
			
		||||
            }
 | 
			
		||||
            return stmt, nil
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if expecting.statements {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return nil, fmt.Errorf( "Nothing to read" )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ( this *Lexer ) ReadUntilClose( closing rune, canEsc bool, escRune rune ) ( string, error ) {
 | 
			
		||||
    var b strings.Builder
 | 
			
		||||
 | 
			
		||||
    reader := this.reader
 | 
			
		||||
    for {
 | 
			
		||||
        r, _, err := reader.ReadRune()
 | 
			
		||||
 | 
			
		||||
        if err != nil {
 | 
			
		||||
            if err == io.EOF {
 | 
			
		||||
                return "", fmt.Errorf( "Unexpected end of data after opening %s", string( closing ) )
 | 
			
		||||
            }
 | 
			
		||||
            return "", err
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if r == closing {
 | 
			
		||||
            break
 | 
			
		||||
        } else if canEsc && r == escRune {
 | 
			
		||||
            r2, _, err := reader.ReadRune()
 | 
			
		||||
            if err != nil {
 | 
			
		||||
                return "", err
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if r2 != closing {
 | 
			
		||||
                b.WriteRune( r )
 | 
			
		||||
                b.WriteRune( r2 )
 | 
			
		||||
                continue
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        b.WriteRune( r )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return b.String(), nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,40 @@
 | 
			
		||||
package mmql
 | 
			
		||||
 | 
			
		||||
import "testing"
 | 
			
		||||
import (
 | 
			
		||||
    // "fmt"
 | 
			
		||||
    "testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestParse( t *testing.T ) {
 | 
			
		||||
    lexer := Lexer{}
 | 
			
		||||
    lexer.Parse( `
 | 
			
		||||
    s, err := lexer.Parse( "\"ABC\"" )
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        t.Error( err )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    got := (*any( s ).( QuotedValue ).RawStatement).Value
 | 
			
		||||
    if got != "ABC" {
 | 
			
		||||
        t.Errorf( "Expected ABC, got %s", got )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s, err = lexer.Parse( "\"ABC" )
 | 
			
		||||
    if err == nil {
 | 
			
		||||
        t.Errorf( "Expected error, got value %s", s )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s, err = lexer.Parse( "( ABC )" )
 | 
			
		||||
 | 
			
		||||
    got = (*any( s ).( BracketedValue ).RawStatement).Value
 | 
			
		||||
    if got != " ABC " {
 | 
			
		||||
        t.Errorf( "Expected ABC, got %s", got )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s, err = lexer.Parse( "( ABC" )
 | 
			
		||||
    if err == nil {
 | 
			
		||||
        t.Errorf( "Expected error, got value %s", s )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s, err = lexer.Parse( `
 | 
			
		||||
BUY 1 SHARES OF BTC_ETF
 | 
			
		||||
  FOR 10 USD
 | 
			
		||||
  FROM "MyBrokerAccount"
 | 
			
		||||
@@ -13,5 +43,7 @@ BUY 1 SHARES OF BTC_ETF
 | 
			
		||||
    1 BTC OF USD_BTC SOLD
 | 
			
		||||
        FROM "CoinBase"
 | 
			
		||||
` )
 | 
			
		||||
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        t.Error( err )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,31 @@
 | 
			
		||||
package mmql
 | 
			
		||||
 | 
			
		||||
type IStatement interface {
 | 
			
		||||
type IStatement interface { }
 | 
			
		||||
 | 
			
		||||
type RawStatement struct {
 | 
			
		||||
    IStatement
 | 
			
		||||
    Value string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuotedValue struct {
 | 
			
		||||
    IStatement
 | 
			
		||||
    RawStatement *RawStatement
 | 
			
		||||
    Quote string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type BracketedValue struct {
 | 
			
		||||
    IStatement
 | 
			
		||||
    RawStatement *RawStatement
 | 
			
		||||
    Brackets string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ActionStatement struct {
 | 
			
		||||
    IStatement
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type OrderStatement struct {
 | 
			
		||||
    *ActionStatement
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ( this *OrderStatement ) For( stmt IStatement ) {
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,18 +13,23 @@ THEN OPT EXPECT: FOR EVERY
 | 
			
		||||
    THEN EXPECT: [SOLD|BOUGHT] FROM [ExchangeType]
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
func _buyStatement() ( IStatement, error ) {
 | 
			
		||||
    a := ActionStatement{}
 | 
			
		||||
func _buyStatement( lexer *Lexer ) ( IStatement, error ) {
 | 
			
		||||
    a := OrderStatement{}
 | 
			
		||||
 | 
			
		||||
    ex := LexerExpect{
 | 
			
		||||
        statements: true,
 | 
			
		||||
        keywords: false,
 | 
			
		||||
        brackets: false,
 | 
			
		||||
        quotes: false,
 | 
			
		||||
        key: "AMOUNT",
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    stmt, err := lexer.ReadStatement( &ex )
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        return nil, err
 | 
			
		||||
    }
 | 
			
		||||
    a.For( stmt )
 | 
			
		||||
 | 
			
		||||
    var b IStatement = a
 | 
			
		||||
    return b, nil
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
func _buyStatement( lexer *Lexer ) ( ActionStatement, error ) {
 | 
			
		||||
 | 
			
		||||
    token := lexer.GetToken()
 | 
			
		||||
    if token.Type == KeywordToken && token.Value == "BUY" {
 | 
			
		||||
    } else {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user