Browse Source

Add Transakcio new parser for the new lang spec

feature/sql-semaphore1
arnaucube 4 years ago
parent
commit
06ae1897d8
2 changed files with 202 additions and 107 deletions
  1. +122
    -73
      test/lang.go
  2. +80
    -34
      test/lang_test.go

+ 122
- 73
test/lang.go

@ -14,12 +14,16 @@ import (
var eof = rune(0)
var errof = fmt.Errorf("eof in parseline")
var errComment = fmt.Errorf("comment in parseline")
var errNewBatch = fmt.Errorf("newbatch")
var newEvent = fmt.Errorf("newEvent")
// TypeNewBatch is used for testing purposes only, and represents the
// common.TxType of a new batch
var TypeNewBatch common.TxType = "TxTypeNewBatch"
// TypeNewBlock is used for testing purposes only, and represents the
// common.TxType of a new ethereum block
var TypeNewBlock common.TxType = "TxTypeNewBlock"
//nolint
const (
ILLEGAL token = iota
@ -31,13 +35,14 @@ const (
// Instruction is the data structure that represents one line of code
type Instruction struct {
Literal string
From string
To string
Amount uint64
Fee uint8
TokenID common.TokenID
Type common.TxType // D: Deposit, T: Transfer, E: ForceExit
Literal string
From string
To string
Amount uint64
LoadAmount uint64
Fee uint8
TokenID common.TokenID
Type common.TxType // D: Deposit, T: Transfer, E: ForceExit
}
// Instructions contains the full Set of Instructions representing a full code
@ -49,42 +54,46 @@ type Instructions struct {
func (i Instruction) String() string {
buf := bytes.NewBufferString("")
switch i.Type {
case common.TxTypeCreateAccountDeposit:
fmt.Fprintf(buf, "Type: Create&Deposit, ")
case common.TxTypeTransfer:
fmt.Fprintf(buf, "Type: Transfer, ")
case common.TxTypeForceExit:
fmt.Fprintf(buf, "Type: ForceExit, ")
default:
}
fmt.Fprintf(buf, "Type: %s, ", i.Type)
fmt.Fprintf(buf, "From: %s, ", i.From)
if i.Type == common.TxTypeTransfer {
if i.Type == common.TxTypeTransfer ||
i.Type == common.TxTypeDepositTransfer ||
i.Type == common.TxTypeCreateAccountDepositTransfer {
fmt.Fprintf(buf, "To: %s, ", i.To)
}
if i.Type == common.TxTypeDepositTransfer ||
i.Type == common.TxTypeCreateAccountDepositTransfer {
fmt.Fprintf(buf, "LoadAmount: %d, ", i.LoadAmount)
}
fmt.Fprintf(buf, "Amount: %d, ", i.Amount)
if i.Type == common.TxTypeTransfer {
if i.Type == common.TxTypeTransfer ||
i.Type == common.TxTypeDepositTransfer ||
i.Type == common.TxTypeCreateAccountDepositTransfer {
fmt.Fprintf(buf, "Fee: %d, ", i.Fee)
}
fmt.Fprintf(buf, "TokenID: %d,\n", i.TokenID)
fmt.Fprintf(buf, "TokenID: %d\n", i.TokenID)
return buf.String()
}
// Raw returns a string with the raw representation of the Instruction
func (i Instruction) Raw() string {
buf := bytes.NewBufferString("")
fmt.Fprintf(buf, "%s", i.Type)
fmt.Fprintf(buf, "(%d)", i.TokenID)
fmt.Fprintf(buf, "%s", i.From)
if i.Type == common.TxTypeTransfer {
if i.Type == common.TxTypeTransfer ||
i.Type == common.TxTypeDepositTransfer ||
i.Type == common.TxTypeCreateAccountDepositTransfer {
fmt.Fprintf(buf, "-%s", i.To)
}
fmt.Fprintf(buf, " (%d)", i.TokenID)
if i.Type == common.TxTypeForceExit {
fmt.Fprintf(buf, "E")
}
fmt.Fprintf(buf, ":")
fmt.Fprintf(buf, " %d", i.Amount)
if i.Type == common.TxTypeDepositTransfer ||
i.Type == common.TxTypeCreateAccountDepositTransfer {
fmt.Fprintf(buf, "%d,", i.LoadAmount)
}
fmt.Fprintf(buf, "%d", i.Amount)
if i.Type == common.TxTypeTransfer {
fmt.Fprintf(buf, " %d", i.Fee)
fmt.Fprintf(buf, "(%d)", i.Fee)
}
return buf.String()
}
@ -229,15 +238,6 @@ func (p *Parser) scanIgnoreWhitespace() (tok token, lit string) {
// parseLine parses the current line
func (p *Parser) parseLine() (*Instruction, error) {
// line can be Deposit:
// A (1): 10
// or Transfer:
// A-B (1): 6
// or Withdraw:
// A (1) E: 4
// or NextBatch:
// > and here the comment
c := &Instruction{}
tok, lit := p.scanIgnoreWhitespace()
if tok == EOF {
@ -248,30 +248,45 @@ func (p *Parser) parseLine() (*Instruction, error) {
_, _ = p.s.r.ReadString('\n')
return nil, errComment
} else if lit == ">" {
_, _ = p.s.r.ReadString('\n')
return nil, errNewBatch
}
c.From = lit
_, lit = p.scanIgnoreWhitespace()
c.Literal += lit
if lit == "-" {
// transfer
_, lit = p.scanIgnoreWhitespace()
c.Literal += lit
c.To = lit
c.Type = common.TxTypeTransfer
_, lit = p.scanIgnoreWhitespace() // expect (
c.Literal += lit
if lit != "(" {
line, _ := p.s.r.ReadString('\n')
c.Literal += line
return c, fmt.Errorf("Expected '(', found '%s'", lit)
if lit == "batch" {
_, _ = p.s.r.ReadString('\n')
return &Instruction{Type: TypeNewBatch}, newEvent
} else if lit == "block" {
_, _ = p.s.r.ReadString('\n')
return &Instruction{Type: TypeNewBlock}, newEvent
} else {
return c, fmt.Errorf("Unexpected '> %s', expected '> batch' or '> block'", lit)
}
} else {
}
transfering := false
switch lit {
case "Deposit":
c.Type = common.TxTypeDeposit
case "Exit", "PoolExit":
c.Type = common.TxTypeExit
case "Transfer", "PoolTransfer":
c.Type = common.TxTypeTransfer
transfering = true
case "CreateAccountDeposit":
c.Type = common.TxTypeCreateAccountDeposit
case "CreateAccountDepositTransfer":
c.Type = common.TxTypeCreateAccountDepositTransfer
transfering = true
case "DepositTransfer":
c.Type = common.TxTypeDepositTransfer
transfering = true
case "ForceTransfer":
c.Type = common.TxTypeForceTransfer
case "ForceExit":
c.Type = common.TxTypeForceExit
default:
return c, fmt.Errorf("Unexpected tx type: %s", lit)
}
if err := p.expectChar(c, "("); err != nil {
return c, err
}
_, lit = p.scanIgnoreWhitespace()
c.Literal += lit
tidI, err := strconv.Atoi(lit)
@ -281,19 +296,22 @@ func (p *Parser) parseLine() (*Instruction, error) {
return c, err
}
c.TokenID = common.TokenID(tidI)
_, lit = p.scanIgnoreWhitespace() // expect )
c.Literal += lit
if lit != ")" {
line, _ := p.s.r.ReadString('\n')
c.Literal += line
return c, fmt.Errorf("Expected ')', found '%s'", lit)
if err := p.expectChar(c, ")"); err != nil {
return c, err
}
_, lit = p.scanIgnoreWhitespace() // expect ':' or 'E' (Exit type)
_, lit = p.scanIgnoreWhitespace()
c.Literal += lit
if lit == "E" {
c.Type = common.TxTypeForceExit
_, lit = p.scanIgnoreWhitespace() // expect ':'
c.From = lit
_, lit = p.scanIgnoreWhitespace()
c.Literal += lit
if lit == "-" {
if !transfering {
return c, fmt.Errorf("To defined, but not type {Transfer, CreateAccountDepositTransfer, DepositTransfer}")
}
_, lit = p.scanIgnoreWhitespace()
c.Literal += lit
c.To = lit
_, lit = p.scanIgnoreWhitespace()
c.Literal += lit
}
if lit != ":" {
@ -301,7 +319,22 @@ func (p *Parser) parseLine() (*Instruction, error) {
c.Literal += line
return c, fmt.Errorf("Expected ':', found '%s'", lit)
}
tok, lit = p.scanIgnoreWhitespace()
if c.Type == common.TxTypeDepositTransfer ||
c.Type == common.TxTypeCreateAccountDepositTransfer {
_, lit = p.scanIgnoreWhitespace()
c.Literal += lit
loadAmount, err := strconv.Atoi(lit)
if err != nil {
line, _ := p.s.r.ReadString('\n')
c.Literal += line
return c, err
}
c.LoadAmount = uint64(loadAmount)
if err := p.expectChar(c, ","); err != nil {
return c, err
}
}
_, lit = p.scanIgnoreWhitespace()
c.Literal += lit
amount, err := strconv.Atoi(lit)
if err != nil {
@ -310,9 +343,11 @@ func (p *Parser) parseLine() (*Instruction, error) {
return c, err
}
c.Amount = uint64(amount)
if c.Type == common.TxTypeTransfer {
tok, lit = p.scanIgnoreWhitespace()
if transfering {
if err := p.expectChar(c, "("); err != nil {
return c, err
}
_, lit = p.scanIgnoreWhitespace()
c.Literal += lit
fee, err := strconv.Atoi(lit)
if err != nil {
@ -326,6 +361,10 @@ func (p *Parser) parseLine() (*Instruction, error) {
return c, fmt.Errorf("Fee %d can not be bigger than 255", fee)
}
c.Fee = uint8(fee)
if err := p.expectChar(c, ")"); err != nil {
return c, err
}
}
if tok == EOF {
@ -334,6 +373,17 @@ func (p *Parser) parseLine() (*Instruction, error) {
return c, nil
}
func (p *Parser) expectChar(c *Instruction, ch string) error {
_, lit := p.scanIgnoreWhitespace()
c.Literal += lit
if lit != ch {
line, _ := p.s.r.ReadString('\n')
c.Literal += line
return fmt.Errorf("Expected '%s', found '%s'", ch, lit)
}
return nil
}
func idxTokenIDToString(idx string, tid common.TokenID) string {
return idx + strconv.Itoa(int(tid))
}
@ -353,10 +403,9 @@ func (p *Parser) Parse() (Instructions, error) {
i++
continue
}
if err == errNewBatch {
if err == newEvent {
i++
inst := &Instruction{Type: TypeNewBatch}
instructions.Instructions = append(instructions.Instructions, inst)
instructions.Instructions = append(instructions.Instructions, instruction)
continue
}
if err != nil {

+ 80
- 34
test/lang_test.go

@ -10,37 +10,47 @@ import (
var debug = false
func TestParse(t *testing.T) {
func TestParseBlockchainTxs(t *testing.T) {
s := `
// deposits
A (1): 10
A (2): 20
B (1): 5
Deposit(1) A: 10
Deposit(2) A: 20
Deposit(1) B: 5
CreateAccountDeposit(1) C: 5
CreateAccountDepositTransfer(1) D-A: 15, 10 (3)
// L2 transactions
A-B (1): 6 1
B-C (1): 3 1
Transfer(1) A-B: 6 (1)
Transfer(1) B-D: 3 (1)
// set new batch, label does not affect
> batch1
// set new batch
> batch
C-A (1): 3 1
A-B (2): 15 1
DepositTransfer(1) A-B: 15, 10 (1)
Transfer(1) C-A : 3 (1)
Transfer(2) A-B: 15 (1)
User0 (1): 20
User1 (3) : 20
User0-User1 (1): 15 1
User1-User0 (3): 15 1
Deposit(1) User0: 20
Deposit(3) User1: 20
Transfer(1) User0-User1: 15 (1)
Transfer(3) User1-User0: 15 (1)
> batch
Transfer(1) User1-User0: 1 (1)
> batch
> block
// Exits
A (1) E: 5
Exit(1) A: 5
`
parser := NewParser(strings.NewReader(s))
instructions, err := parser.Parse()
assert.Nil(t, err)
assert.Equal(t, 13, len(instructions.Instructions))
// assert.Equal(t, 5, len(instructions.Accounts))
fmt.Println(instructions.Accounts)
assert.Equal(t, 20, len(instructions.Instructions))
assert.Equal(t, 10, len(instructions.Accounts))
assert.Equal(t, 3, len(instructions.TokenIDs))
if debug {
@ -50,37 +60,73 @@ func TestParse(t *testing.T) {
}
}
assert.Equal(t, TypeNewBatch, instructions.Instructions[5].Type)
assert.Equal(t, "User0 (1): 20", instructions.Instructions[8].Raw())
assert.Equal(t, "Type: Create&Deposit, From: User0, Amount: 20, TokenID: 1,\n", instructions.Instructions[8].String())
assert.Equal(t, "User0-User1 (1): 15 1", instructions.Instructions[10].Raw())
assert.Equal(t, "Type: Transfer, From: User0, To: User1, Amount: 15, Fee: 1, TokenID: 1,\n", instructions.Instructions[10].String())
assert.Equal(t, "A (1)E: 5", instructions.Instructions[12].Raw())
assert.Equal(t, "Type: ForceExit, From: A, Amount: 5, TokenID: 1,\n", instructions.Instructions[12].String())
assert.Equal(t, TypeNewBatch, instructions.Instructions[7].Type)
assert.Equal(t, "Deposit(1)User0:20", instructions.Instructions[11].Raw())
assert.Equal(t, "Type: DepositTransfer, From: A, To: B, LoadAmount: 15, Amount: 10, Fee: 1, TokenID: 1\n", instructions.Instructions[8].String())
assert.Equal(t, "Type: Transfer, From: User1, To: User0, Amount: 15, Fee: 1, TokenID: 3\n", instructions.Instructions[14].String())
assert.Equal(t, "Transfer(2)A-B:15(1)", instructions.Instructions[10].Raw())
assert.Equal(t, "Type: Transfer, From: A, To: B, Amount: 15, Fee: 1, TokenID: 2\n", instructions.Instructions[10].String())
assert.Equal(t, "Exit(1)A:5", instructions.Instructions[19].Raw())
assert.Equal(t, "Type: Exit, From: A, Amount: 5, TokenID: 1\n", instructions.Instructions[19].String())
}
func TestParsePoolTxs(t *testing.T) {
s := `
PoolTransfer(1) A-B: 6 (1)
PoolTransfer(2) A-B: 3 (3)
PoolTransfer(1) B-D: 3 (1)
PoolTransfer(1) C-D: 3 (1)
Exit(1) A: 5
`
parser := NewParser(strings.NewReader(s))
instructions, err := parser.Parse()
assert.Nil(t, err)
assert.Equal(t, 5, len(instructions.Instructions))
assert.Equal(t, 6, len(instructions.Accounts))
assert.Equal(t, 2, len(instructions.TokenIDs))
if debug {
fmt.Println(instructions)
for _, instruction := range instructions.Instructions {
fmt.Println(instruction.Raw())
}
}
assert.Equal(t, "Transfer(1)A-B:6(1)", instructions.Instructions[0].Raw())
assert.Equal(t, "Transfer(2)A-B:3(3)", instructions.Instructions[1].Raw())
assert.Equal(t, "Transfer(1)B-D:3(1)", instructions.Instructions[2].Raw())
assert.Equal(t, "Transfer(1)C-D:3(1)", instructions.Instructions[3].Raw())
assert.Equal(t, "Exit(1)A:5", instructions.Instructions[4].Raw())
}
func TestParseErrors(t *testing.T) {
s := "A (1):: 10"
s := "Deposit(1) A:: 10"
parser := NewParser(strings.NewReader(s))
_, err := parser.Parse()
assert.Equal(t, "error parsing line 0: A(1):: 10, err: strconv.Atoi: parsing \":\": invalid syntax", err.Error())
assert.Equal(t, "error parsing line 0: Deposit(1)A:: 10, err: strconv.Atoi: parsing \":\": invalid syntax", err.Error())
s = "A (1): 10 20"
s = "Deposit(1) A: 10 20"
parser = NewParser(strings.NewReader(s))
_, err = parser.Parse()
assert.Equal(t, "error parsing line 1: 20, err: strconv.Atoi: parsing \"\": invalid syntax", err.Error())
assert.Equal(t, "error parsing line 1: 20, err: Unexpected tx type: 20", err.Error())
s = "A B (1): 10"
s = "Transfer(1) A B: 10"
parser = NewParser(strings.NewReader(s))
_, err = parser.Parse()
assert.Equal(t, "error parsing line 0: AB(1): 10, err: strconv.Atoi: parsing \"(\": invalid syntax", err.Error())
assert.Equal(t, "error parsing line 0: Transfer(1)AB: 10, err: Expected ':', found 'B'", err.Error())
s = "A-B (1): 10 255"
s = "Transfer(1) A-B: 10 (255)"
parser = NewParser(strings.NewReader(s))
_, err = parser.Parse()
assert.Nil(t, err)
s = "A-B (1): 10 256"
s = "Transfer(1) A-B: 10 (256)"
parser = NewParser(strings.NewReader(s))
_, err = parser.Parse()
assert.Equal(t, "error parsing line 0: Transfer(1)A-B:10(256), err: Fee 256 can not be bigger than 255", err.Error())
s = "> btch"
parser = NewParser(strings.NewReader(s))
_, err = parser.Parse()
assert.Equal(t, "error parsing line 0: A-B(1):10256, err: Fee 256 can not be bigger than 255", err.Error())
assert.Equal(t, "error parsing line 0: >, err: Unexpected '> btch', expected '> batch' or '> block'", err.Error())
}

Loading…
Cancel
Save