This idea may work, or may not
This commit is contained in:
parent
c9ecbdde08
commit
31f6e7165d
@ -9,6 +9,8 @@ type Token struct {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
K_SPACES = "\t\n\r "
|
K_SPACES = "\t\n\r "
|
||||||
|
// Must be defined in pairs with
|
||||||
|
// open bracket on left and close bracket on right
|
||||||
K_BRACKETS = "()[]{}"
|
K_BRACKETS = "()[]{}"
|
||||||
K_QUOTES = "'\"`"
|
K_QUOTES = "'\"`"
|
||||||
)
|
)
|
||||||
@ -46,6 +48,6 @@ var KEYWORDS = []string {
|
|||||||
"WITH",
|
"WITH",
|
||||||
}
|
}
|
||||||
|
|
||||||
var STATEMENTS = map[string] func() ( IStatement, error ) {
|
var STATEMENTS = map[string] func( *Lexer ) ( IStatement, error ) {
|
||||||
"BUY": _buyStatement,
|
"BUY": _buyStatement,
|
||||||
}
|
}
|
||||||
|
115
mmql/lexer.go
115
mmql/lexer.go
@ -1,14 +1,119 @@
|
|||||||
package mmql
|
package mmql
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LexerExpect struct {
|
||||||
|
statements bool
|
||||||
|
keywords bool
|
||||||
|
brackets bool
|
||||||
|
quotes bool
|
||||||
|
key string
|
||||||
|
}
|
||||||
|
|
||||||
type Lexer struct {
|
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 {
|
this.reader = strings.NewReader( line )
|
||||||
fmt.Printf( "%d: %s\n", i, string( r ) )
|
|
||||||
|
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
|
package mmql
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
// "fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
func TestParse( t *testing.T ) {
|
func TestParse( t *testing.T ) {
|
||||||
lexer := Lexer{}
|
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
|
BUY 1 SHARES OF BTC_ETF
|
||||||
FOR 10 USD
|
FOR 10 USD
|
||||||
FROM "MyBrokerAccount"
|
FROM "MyBrokerAccount"
|
||||||
@ -13,5 +43,7 @@ BUY 1 SHARES OF BTC_ETF
|
|||||||
1 BTC OF USD_BTC SOLD
|
1 BTC OF USD_BTC SOLD
|
||||||
FROM "CoinBase"
|
FROM "CoinBase"
|
||||||
` )
|
` )
|
||||||
|
if err != nil {
|
||||||
|
t.Error( err )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,31 @@
|
|||||||
package mmql
|
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 {
|
type ActionStatement struct {
|
||||||
IStatement
|
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]
|
THEN EXPECT: [SOLD|BOUGHT] FROM [ExchangeType]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func _buyStatement() ( IStatement, error ) {
|
func _buyStatement( lexer *Lexer ) ( IStatement, error ) {
|
||||||
a := ActionStatement{}
|
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
|
var b IStatement = a
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
func _buyStatement( lexer *Lexer ) ( ActionStatement, error ) {
|
|
||||||
|
|
||||||
token := lexer.GetToken()
|
|
||||||
if token.Type == KeywordToken && token.Value == "BUY" {
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
50
specifications/0002_statement_structurs.md
Normal file
50
specifications/0002_statement_structurs.md
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#### Example Statement
|
||||||
|
```
|
||||||
|
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"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Yield Structure
|
||||||
|
```
|
||||||
|
{
|
||||||
|
Statement: BUY
|
||||||
|
Product: {
|
||||||
|
Name: BTC_ETF
|
||||||
|
Amount: {
|
||||||
|
Value: 1
|
||||||
|
Unit: SHARES
|
||||||
|
}
|
||||||
|
}
|
||||||
|
For: {
|
||||||
|
Value: 10
|
||||||
|
Unit: USD
|
||||||
|
}
|
||||||
|
From: MyBrokerAccount
|
||||||
|
Limit: {
|
||||||
|
Amount: {
|
||||||
|
Func: {
|
||||||
|
Name: PURCHASING_POWER
|
||||||
|
Params [
|
||||||
|
MyBrokerAccount
|
||||||
|
QQQ
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
When: [{
|
||||||
|
Event: SOLD
|
||||||
|
Params: {
|
||||||
|
Amount: {
|
||||||
|
Value: 1
|
||||||
|
Unit: BTC
|
||||||
|
}
|
||||||
|
From: CoinBase
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
```
|
Loading…
Reference in New Issue
Block a user