Moved things around
This commit is contained in:
		@@ -41,6 +41,10 @@ func ( this *Lexer ) SetReader( reader *strings.Reader ) {
 | 
			
		||||
    this.reader = reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ( this *Lexer ) GetPos() int {
 | 
			
		||||
    return this.reader.Len()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Reads
 | 
			
		||||
 *    123,456,789.00001
 | 
			
		||||
@@ -50,6 +54,8 @@ func ( this *Lexer ) SetReader( reader *strings.Reader ) {
 | 
			
		||||
 */
 | 
			
		||||
func ( this *Lexer ) ReadDecimal() ( f float64, err error ) {
 | 
			
		||||
    reader := this.reader
 | 
			
		||||
    defer this.Rollback( reader.Len(), &err )
 | 
			
		||||
 | 
			
		||||
    var b strings.Builder
 | 
			
		||||
 | 
			
		||||
    dot := false
 | 
			
		||||
@@ -77,14 +83,16 @@ func ( this *Lexer ) ReadDecimal() ( f float64, err error ) {
 | 
			
		||||
            if k {
 | 
			
		||||
                b.WriteRune( 'k' )
 | 
			
		||||
            }
 | 
			
		||||
            b.WriteRune( r )
 | 
			
		||||
            err = fmt.Errorf( "Cannot parse '%s'", b.String() )
 | 
			
		||||
            err = fmt.Errorf(
 | 
			
		||||
                "Cannot parse '%s' in ReadDecimal",
 | 
			
		||||
                this.ReadUntilNot( K_STATEMENT_CHARS, true, r ),
 | 
			
		||||
            )
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if r == ',' {
 | 
			
		||||
            if comma || dot {
 | 
			
		||||
                err = fmt.Errorf( "Unexpected ',' char" )
 | 
			
		||||
                err = fmt.Errorf( "Unexpected ',' char in ReadDecimal" )
 | 
			
		||||
                return
 | 
			
		||||
            }
 | 
			
		||||
            comma = true
 | 
			
		||||
@@ -93,7 +101,7 @@ func ( this *Lexer ) ReadDecimal() ( f float64, err error ) {
 | 
			
		||||
 | 
			
		||||
        if strings.ContainsRune( K_SPACES, r ) {
 | 
			
		||||
            if comma {
 | 
			
		||||
                err = fmt.Errorf( "Unexpected ',' char" )
 | 
			
		||||
                err = fmt.Errorf( "Unexpected ',' char in ReadDecimal" )
 | 
			
		||||
                return
 | 
			
		||||
            }
 | 
			
		||||
            if 0 < b.Len() {
 | 
			
		||||
@@ -108,7 +116,7 @@ func ( this *Lexer ) ReadDecimal() ( f float64, err error ) {
 | 
			
		||||
                dot = true
 | 
			
		||||
                continue
 | 
			
		||||
            }
 | 
			
		||||
            err = fmt.Errorf( "Unexpected '.' char" )
 | 
			
		||||
            err = fmt.Errorf( "Unexpected '.' char in ReadDecimal" )
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -122,8 +130,10 @@ func ( this *Lexer ) ReadDecimal() ( f float64, err error ) {
 | 
			
		||||
            b.WriteRune( r )
 | 
			
		||||
            comma = false
 | 
			
		||||
        } else {
 | 
			
		||||
            b.WriteRune( r )
 | 
			
		||||
            err = fmt.Errorf( "Cannot parse '%s'", b.String() )
 | 
			
		||||
            err = fmt.Errorf(
 | 
			
		||||
                "Cannot parse '%s' in ReadDecimal",
 | 
			
		||||
                this.ReadUntilNot( K_STATEMENT_CHARS, true, r ),
 | 
			
		||||
            )
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -135,11 +145,19 @@ func ( this *Lexer ) ReadDecimal() ( f float64, err error ) {
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ( this *Lexer ) Rollback( oPos int, err *error ) {
 | 
			
		||||
    if *err != nil {
 | 
			
		||||
        this.reader.Seek( int64( this.reader.Len() - oPos ), io.SeekCurrent )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ( this *Lexer ) ReadKeyword( Keyword string ) ( err error ) {
 | 
			
		||||
 | 
			
		||||
    reader := this.reader
 | 
			
		||||
    kReader := strings.NewReader( Keyword )
 | 
			
		||||
 | 
			
		||||
    defer this.Rollback( reader.Len(), &err )
 | 
			
		||||
 | 
			
		||||
    var b strings.Builder
 | 
			
		||||
    for {
 | 
			
		||||
        r, _, _err := reader.ReadRune()
 | 
			
		||||
@@ -186,6 +204,8 @@ func ( this *Lexer ) ReadKeyword( Keyword string ) ( err error ) {
 | 
			
		||||
func ( this *Lexer ) ReadAlpha() ( s string, err error ) {
 | 
			
		||||
    reader := this.reader
 | 
			
		||||
 | 
			
		||||
    defer this.Rollback( reader.Len(), &err )
 | 
			
		||||
 | 
			
		||||
    var b strings.Builder
 | 
			
		||||
 | 
			
		||||
    for {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								mmql/engine/parsers/amount.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								mmql/engine/parsers/amount.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
package parsers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
    // "fmt"
 | 
			
		||||
    engine "github.com/tgckpg/mmqlengine/mmql/engine"
 | 
			
		||||
    stmtd "github.com/tgckpg/mmqlengine/mmql/statements"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
EXPECT: [Number] [Units]
 | 
			
		||||
OR
 | 
			
		||||
EXPECT: [FUNCTION]( ...params )
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
func AmountStatement( lexer *engine.Lexer ) ( istmt stmtd.IStatement, err error ) {
 | 
			
		||||
    stmt := stmtd.AmountStatement{}
 | 
			
		||||
 | 
			
		||||
    val, err := lexer.ReadDecimal()
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
    stmt.SetValue( val )
 | 
			
		||||
 | 
			
		||||
    unit, err := lexer.ReadAlpha()
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
    stmt.SetUnit( unit )
 | 
			
		||||
 | 
			
		||||
    istmt = stmt
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								mmql/engine/parsers/amount_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								mmql/engine/parsers/amount_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
package parsers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
    // "fmt"
 | 
			
		||||
    "strings"
 | 
			
		||||
    "testing"
 | 
			
		||||
    engine "github.com/tgckpg/mmqlengine/mmql/engine"
 | 
			
		||||
    stmtd "github.com/tgckpg/mmqlengine/mmql/statements"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type _p struct {
 | 
			
		||||
    amount float64
 | 
			
		||||
    unit string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAmountStatement( t *testing.T ) {
 | 
			
		||||
    lexer := engine.Lexer{}
 | 
			
		||||
    supportedStmts := map[string] func( *engine.Lexer ) ( stmtd.IStatement, error ) {
 | 
			
		||||
        "AMOUNT": AmountStatement,
 | 
			
		||||
    }
 | 
			
		||||
    lexer.SupportedStmts = &supportedStmts
 | 
			
		||||
 | 
			
		||||
    read_oks := map[string] _p {
 | 
			
		||||
        "1 SHARES OF QQQ": _p{ 1, "SHARES" },
 | 
			
		||||
        "1 QQQ": _p{ 1, "QQQ" },
 | 
			
		||||
        "1 UNIT OF QQQ": _p{ 1, "UNIT" },
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    readAmount := engine.LexerExpect{
 | 
			
		||||
        Statements: true,
 | 
			
		||||
        Keywords: false,
 | 
			
		||||
        Brackets: false,
 | 
			
		||||
        Quotes: false,
 | 
			
		||||
        Key: "AMOUNT",
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for k := range read_oks {
 | 
			
		||||
        lexer.SetReader( strings.NewReader( k ) )
 | 
			
		||||
        stmt, err := lexer.ReadStatement( &readAmount )
 | 
			
		||||
        if err != nil {
 | 
			
		||||
            t.Error( err )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        aStmt := any( stmt ).( stmtd.AmountStatement )
 | 
			
		||||
        p, _ := read_oks[ k ]
 | 
			
		||||
        if aStmt.Unit() != p.unit {
 | 
			
		||||
            t.Errorf( "Expected \"%s\", got \"%s\" instead", p.unit, aStmt.Unit() )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										96
									
								
								mmql/engine/parsers/buy.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								mmql/engine/parsers/buy.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
package parsers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
    engine "github.com/tgckpg/mmqlengine/mmql/engine"
 | 
			
		||||
    stmtd "github.com/tgckpg/mmqlengine/mmql/statements"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
EXPECT: BUY
 | 
			
		||||
THEN EXPECT: [AmountStatement] OF [FinancialInstrumentStatement]
 | 
			
		||||
THEN EXPECT: FOR [AmountStatement]
 | 
			
		||||
THEN EXPECT: FROM [ExchangeType]
 | 
			
		||||
THEN OPT EXPECT: [ExchangeType]
 | 
			
		||||
THEN OPT EXPECT: [AND|OR]
 | 
			
		||||
    THEN EXPECT: [ActionExpression]
 | 
			
		||||
THEN OPT EXPECT: FOR EVERY
 | 
			
		||||
    THEN EXPECT: [AmountType] OF [FinancialInstrumentType]
 | 
			
		||||
    THEN EXPECT: [SOLD|BOUGHT] FROM [ExchangeType]
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
func BuyStatement( lexer *engine.Lexer ) ( istmt stmtd.IStatement, err error ) {
 | 
			
		||||
    orderStmt := stmtd.OrderStatement{}
 | 
			
		||||
    orderStmt.Action = "BUY"
 | 
			
		||||
 | 
			
		||||
    // AmountStatement
 | 
			
		||||
    readAmount := engine.LexerExpect{
 | 
			
		||||
        Statements: true,
 | 
			
		||||
        Keywords: false,
 | 
			
		||||
        Brackets: false,
 | 
			
		||||
        Quotes: false,
 | 
			
		||||
        Key: "AMOUNT",
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _amountStmt, err := lexer.ReadStatement( &readAmount )
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    amountStmt := any( _amountStmt ).( stmtd.AmountStatement )
 | 
			
		||||
    orderStmt.SetAmount( &amountStmt )
 | 
			
		||||
 | 
			
		||||
    var fiStmt stmtd.FinancialInstrumentStatement
 | 
			
		||||
 | 
			
		||||
    // OF
 | 
			
		||||
    err = lexer.ReadKeyword( "OF" )
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        // try read FOR
 | 
			
		||||
        err = lexer.ReadKeyword( "FOR" )
 | 
			
		||||
        if err != nil {
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // BUY 1 QQQ
 | 
			
		||||
        fiStmt := stmtd.FinancialInstrumentStatement{}
 | 
			
		||||
        fiStmt.Name = amountStmt.Unit()
 | 
			
		||||
 | 
			
		||||
        // Equivalent to BUY 1 UNIT OF QQQ
 | 
			
		||||
        amountStmt.SetUnit( "UNITS" )
 | 
			
		||||
    } else {
 | 
			
		||||
        // BUY 1 UNIT OF QQQ
 | 
			
		||||
        readFI := engine.LexerExpect{
 | 
			
		||||
            Statements: true,
 | 
			
		||||
            Keywords: false,
 | 
			
		||||
            Brackets: false,
 | 
			
		||||
            Quotes: false,
 | 
			
		||||
            Key: "FINANCIAL_INSTRUMENT",
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        _fiStmt, _err := lexer.ReadStatement( &readFI )
 | 
			
		||||
        if _err != nil {
 | 
			
		||||
            err = _err
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        fiStmt = any( _fiStmt ).( stmtd.FinancialInstrumentStatement )
 | 
			
		||||
 | 
			
		||||
        // FOR
 | 
			
		||||
        err = lexer.ReadKeyword( "FOR" )
 | 
			
		||||
        if err != nil {
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    orderStmt.SetFinancialInstrument( &fiStmt )
 | 
			
		||||
 | 
			
		||||
    // FOR [AmountStatement]
 | 
			
		||||
    _forStmt, err := lexer.ReadStatement( &readAmount )
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    forStmt := any( _forStmt ).( stmtd.AmountStatement )
 | 
			
		||||
    orderStmt.SetFor( &forStmt )
 | 
			
		||||
 | 
			
		||||
    istmt = orderStmt
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								mmql/engine/parsers/buy_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								mmql/engine/parsers/buy_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
package parsers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
    // "fmt"
 | 
			
		||||
    "testing"
 | 
			
		||||
    engine "github.com/tgckpg/mmqlengine/mmql/engine"
 | 
			
		||||
    stmtd "github.com/tgckpg/mmqlengine/mmql/statements"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestBuyStatement( t *testing.T ) {
 | 
			
		||||
    lexer := engine.Lexer{}
 | 
			
		||||
    supportedStmts := map[string] func( *engine.Lexer ) ( stmtd.IStatement, error ) {
 | 
			
		||||
        "BUY": BuyStatement,
 | 
			
		||||
        "AMOUNT": AmountStatement,
 | 
			
		||||
        "FINANCIAL_INSTRUMENT": FinancialInstrumentStatement,
 | 
			
		||||
    }
 | 
			
		||||
    lexer.SupportedStmts = &supportedStmts
 | 
			
		||||
 | 
			
		||||
    var stmt stmtd.OrderStatement
 | 
			
		||||
    _stmt, err := lexer.Parse( "BUY 1 SHARES OF QQQ FOR 10 USD FROM \"MyBrokerAccount\"" )
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        t.Error( err )
 | 
			
		||||
    } else {
 | 
			
		||||
        stmt = any( _stmt ).( stmtd.OrderStatement )
 | 
			
		||||
        if stmt.Amount().Unit() != "SHARES" {
 | 
			
		||||
            t.Errorf( "Expected 1 SHARES Amount, got \"%s\" Amount", stmt.Amount().Unit() )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _stmt, err = lexer.Parse( "BUY 1 QQQ FOR MARKET_PRICE() FROM \"MyBrokerAccount\"" )
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        t.Error( err )
 | 
			
		||||
    } else {
 | 
			
		||||
        stmt = any( _stmt ).( stmtd.OrderStatement )
 | 
			
		||||
        if stmt.Amount().Unit() != "UNITS" {
 | 
			
		||||
            t.Errorf( "Expected 1 UNITS Amount, got \"%s\" Amount", stmt.Amount().Unit() )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _, err = lexer.Parse( "BUY 1 QQQ FOR 10 USD FROM \"MyBrokerAccount\"" )
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        t.Error( err )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _, err = lexer.Parse( `
 | 
			
		||||
BUY 1 SHARES OF BTC_ETF
 | 
			
		||||
  FOR 10 USD
 | 
			
		||||
  FROM "MyBrokerAccount"
 | 
			
		||||
  WITH LIMIT OF PURCHASING_POWER( "MyBrokerAccount", "QQQ" )
 | 
			
		||||
  FOR EVERY
 | 
			
		||||
    1 BTC OF USD_BTC SOLD
 | 
			
		||||
        FROM "CoinBase"
 | 
			
		||||
` )
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        t.Error( err )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								mmql/engine/parsers/financial_instrument.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								mmql/engine/parsers/financial_instrument.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
package parsers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
    // "fmt"
 | 
			
		||||
    engine "github.com/tgckpg/mmqlengine/mmql/engine"
 | 
			
		||||
    stmtd "github.com/tgckpg/mmqlengine/mmql/statements"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
EXPECT: [NAME]
 | 
			
		||||
OR
 | 
			
		||||
EXPECT: [FUNCTION]( ...params )
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
func FinancialInstrumentStatement( lexer *engine.Lexer ) ( istmt stmtd.IStatement, err error ) {
 | 
			
		||||
    stmt := stmtd.FinancialInstrumentStatement{}
 | 
			
		||||
 | 
			
		||||
    name, err := lexer.ReadAlpha()
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
    stmt.Name = name
 | 
			
		||||
 | 
			
		||||
    istmt = stmt
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user