Moved things around

This commit is contained in:
斟酌 鵬兄 2022-10-22 05:58:19 +08:00
parent 49043117e2
commit ff8ba52a75
12 changed files with 297 additions and 123 deletions

View File

@ -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 {

View File

@ -1,4 +1,4 @@
package actions
package parsers
import (
// "fmt"
@ -19,13 +19,13 @@ func AmountStatement( lexer *engine.Lexer ) ( istmt stmtd.IStatement, err error
if err != nil {
return
}
stmt.Value = val
stmt.SetValue( val )
unit, err := lexer.ReadAlpha()
if err != nil {
return
}
stmt.Unit = unit
stmt.SetUnit( unit )
istmt = stmt
return

View 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() )
}
}
}

View 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
}

View 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 )
}
}

View File

@ -1,4 +1,4 @@
package actions
package parsers
import (
// "fmt"

View File

@ -1,62 +0,0 @@
package actions
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
}
orderStmt.For( amountStmt )
// OF
err = lexer.ReadKeyword( "OF" )
if err != nil {
return
}
// FinancialInstrumentStatement
readFI := engine.LexerExpect{
Statements: true,
Keywords: false,
Brackets: false,
Quotes: false,
Key: "FINANCIAL_INSTRUMENT",
}
productStmt, err := lexer.ReadStatement( &readFI )
if err != nil {
return
}
orderStmt.FinancialInstrument( productStmt )
istmt = orderStmt
return
}

View File

@ -1,31 +0,0 @@
package actions
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
_, 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 )
}
}

24
mmql/statements/amount.go Normal file
View File

@ -0,0 +1,24 @@
package statements
type AmountStatement struct {
IStatement
_value float64
_unit string
_func *FunctionStatement
}
func ( this *AmountStatement ) SetValue( v float64 ) {
this._value = v
}
func ( this *AmountStatement ) Value() float64 {
return this._value
}
func ( this *AmountStatement ) SetUnit( v string ) {
this._unit = v
}
func ( this *AmountStatement ) Unit() string {
return this._unit
}

35
mmql/statements/order.go Normal file
View File

@ -0,0 +1,35 @@
package statements
type OrderStatement struct {
IStatement
IActionStatement
Action string
_amount *AmountStatement
_for *AmountStatement
_fi *FinancialInstrumentStatement
}
func ( this *OrderStatement ) SetAmount( stmt *AmountStatement ) {
this._amount = stmt
}
func ( this *OrderStatement ) Amount() *AmountStatement {
return this._amount
}
func ( this *OrderStatement ) SetFor( stmt *AmountStatement ) {
this._for = stmt
}
func ( this *OrderStatement ) For() *AmountStatement {
return this._for
}
func ( this *OrderStatement ) SetFinancialInstrument( stmt *FinancialInstrumentStatement ) {
this._fi = stmt
}
func ( this *OrderStatement ) FinancialInstrument() *FinancialInstrumentStatement {
return this._fi
}

View File

@ -19,10 +19,10 @@ type BracketedValue struct {
Brackets string
}
type AmountStatement struct {
type FunctionStatement struct {
IStatement
Value float64
Unit string
Name string
Params *[] string
}
type FinancialInstrumentStatement struct {
@ -31,18 +31,3 @@ type FinancialInstrumentStatement struct {
}
type IActionStatement interface { }
type OrderStatement struct {
IStatement
IActionStatement
Action string
}
func ( this *OrderStatement ) For( stmt IStatement ) {
}
func ( this *OrderStatement ) FinancialInstrument( stmt IStatement ) {
}

View File

@ -128,7 +128,7 @@ Returns the maximum [Amounts] of [FinancialInstrument] can purchase from [Exchan
`CURRENT_PRICE( Exchange, FinancialInstrument )`
Returns the current price of a product from exchange
Returns the current price of a financial instrument from exchange
# Examples