Skip to content

Commit

Permalink
feat: Numscript: save from account (#199)
Browse files Browse the repository at this point in the history
  • Loading branch information
Antoine Gelloz authored and flemzord committed May 12, 2023
1 parent 728bbab commit a8b940a
Show file tree
Hide file tree
Showing 14 changed files with 1,161 additions and 401 deletions.
2 changes: 2 additions & 0 deletions pkg/machine/script/NumScript.g4
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ PORTION:
REMAINING: 'remaining';
KEPT: 'kept';
BALANCE: 'balance';
SAVE: 'save';
NUMBER: [0-9]+;
PERCENT: '%';
VARIABLE_NAME: '$' [a-z_]+ [a-z0-9_]*;
Expand Down Expand Up @@ -132,6 +133,7 @@ valueAwareSource

statement
: PRINT expr=expression # Print
| SAVE (mon=expression | monAll=monetaryAll) FROM acc=expression # SaveFromAccount
| SET_TX_META '(' key=STRING ',' value=expression ')' # SetTxMeta
| SET_ACCOUNT_META '(' acc=expression ',' key=STRING ',' value=expression ')' # SetAccountMeta
| FAIL # Fail
Expand Down
48 changes: 45 additions & 3 deletions pkg/machine/script/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ func (p *parseVisitor) VisitSetAccountMeta(ctx *parser.SetAccountMetaContext) *C
}
if ty != internal.TypeAccount {
return LogicError(ctx, fmt.Errorf(
"variable is of type %s, and should be of type account", ty))
"set_account_meta: expression is of type %s, and should be of type account", ty))
}
p.PushAddress(*accAddr)

Expand All @@ -419,7 +419,48 @@ func (p *parseVisitor) VisitSetAccountMeta(ctx *parser.SetAccountMetaContext) *C
return nil
}

// print statement
func (p *parseVisitor) VisitSaveFromAccount(c *parser.SaveFromAccountContext) *CompileError {
var (
typ internal.Type
addr *internal.Address
compErr *CompileError
)
if monAll := c.GetMonAll(); monAll != nil {
typ, addr, compErr = p.VisitExpr(monAll.GetAsset(), false)
if compErr != nil {
return compErr
}
if typ != internal.TypeAsset {
return LogicError(c, fmt.Errorf(
"save monetary all from account: the first expression should be of type 'asset' instead of '%s'", typ))
}
} else if mon := c.GetMon(); mon != nil {
typ, addr, compErr = p.VisitExpr(mon, false)
if compErr != nil {
return compErr
}
if typ != internal.TypeMonetary {
return LogicError(c, fmt.Errorf(
"save monetary from account: the first expression should be of type 'monetary' instead of '%s'", typ))
}
}
p.PushAddress(*addr)

typ, addr, compErr = p.VisitExpr(c.GetAcc(), false)
if compErr != nil {
return compErr
}
if typ != internal.TypeAccount {
return LogicError(c, fmt.Errorf(
"save monetary from account: the second expression should be of type 'account' instead of '%s'", typ))
}
p.PushAddress(*addr)

p.AppendInstruction(program.OP_SAVE)

return nil
}

func (p *parseVisitor) VisitPrint(ctx *parser.PrintContext) *CompileError {
_, _, err := p.VisitExpr(ctx.GetExpr(), true)
if err != nil {
Expand All @@ -431,7 +472,6 @@ func (p *parseVisitor) VisitPrint(ctx *parser.PrintContext) *CompileError {
return nil
}

// vars declaration block
func (p *parseVisitor) VisitVars(c *parser.VarListDeclContext) *CompileError {
if len(c.GetV()) > 32768 {
return LogicError(c, fmt.Errorf("number of variables exceeded %v", 32768))
Expand Down Expand Up @@ -561,6 +601,8 @@ func (p *parseVisitor) VisitScript(c parser.IScriptContext) *CompileError {
err = p.VisitSetTxMeta(c)
case *parser.SetAccountMetaContext:
err = p.VisitSetAccountMeta(c)
case *parser.SaveFromAccountContext:
err = p.VisitSaveFromAccount(c)
default:
return InternalError(c)
}
Expand Down
255 changes: 242 additions & 13 deletions pkg/machine/script/compiler/compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1366,9 +1366,9 @@ func TestPrint(t *testing.T) {
program.OP_PRINT,
},
Resources: []program.Resource{
program.Constant{Inner: core.NewMonetaryInt(1)},
program.Constant{Inner: core.NewMonetaryInt(2)},
program.Constant{Inner: core.NewMonetaryInt(3)},
program.Constant{Inner: internal.NewMonetaryInt(1)},
program.Constant{Inner: internal.NewMonetaryInt(2)},
program.Constant{Inner: internal.NewMonetaryInt(3)},
},
},
})
Expand Down Expand Up @@ -1415,30 +1415,30 @@ func TestSendWithArithmetic(t *testing.T) {
},
Resources: []program.Resource{
program.Variable{
Typ: core.TypeAsset,
Typ: internal.TypeAsset,
Name: "ass",
},
program.Variable{
Typ: core.TypeMonetary,
Typ: internal.TypeMonetary,
Name: "mon",
},
program.Constant{Inner: core.Asset("EUR")},
program.Constant{Inner: internal.Asset("EUR")},
program.Monetary{
Asset: 2,
Amount: core.NewMonetaryInt(1),
Amount: internal.NewMonetaryInt(1),
},
program.Monetary{
Asset: 0,
Amount: core.NewMonetaryInt(3),
Amount: internal.NewMonetaryInt(3),
},
program.Monetary{
Asset: 2,
Amount: core.NewMonetaryInt(4),
Amount: internal.NewMonetaryInt(4),
},
program.Constant{Inner: core.AccountAddress("a")},
program.Constant{Inner: core.NewMonetaryInt(0)},
program.Constant{Inner: core.NewMonetaryInt(1)},
program.Constant{Inner: core.AccountAddress("b")},
program.Constant{Inner: internal.AccountAddress("a")},
program.Constant{Inner: internal.NewMonetaryInt(0)},
program.Constant{Inner: internal.NewMonetaryInt(1)},
program.Constant{Inner: internal.AccountAddress("b")},
},
},
})
Expand Down Expand Up @@ -1480,3 +1480,232 @@ func TestSendWithArithmetic(t *testing.T) {
})
})
}

func TestSaveFromAccount(t *testing.T) {
t.Run("simple", func(t *testing.T) {
test(t, TestCase{
Case: `
save [EUR 10] from @alice
send [EUR 20] (
source = @alice
destination = @bob
)`,
Expected: CaseResult{
Instructions: []byte{
program.OP_APUSH, 01, 00,
program.OP_APUSH, 02, 00,
program.OP_SAVE,
program.OP_APUSH, 02, 00,
program.OP_APUSH, 03, 00,
program.OP_ASSET,
program.OP_APUSH, 04, 00,
program.OP_MONETARY_NEW,
program.OP_TAKE_ALL,
program.OP_APUSH, 03, 00,
program.OP_TAKE,
program.OP_APUSH, 05, 00,
program.OP_BUMP,
program.OP_REPAY,
program.OP_FUNDING_SUM,
program.OP_TAKE,
program.OP_APUSH, 06, 00,
program.OP_SEND,
program.OP_REPAY,
},
Resources: []program.Resource{
program.Constant{Inner: internal.Asset("EUR")},
program.Monetary{
Asset: 0,
Amount: internal.NewMonetaryInt(10),
},
program.Constant{Inner: internal.AccountAddress("alice")},
program.Monetary{
Asset: 0,
Amount: internal.NewMonetaryInt(20),
},
program.Constant{Inner: internal.NewMonetaryInt(0)},
program.Constant{Inner: internal.NewMonetaryInt(1)},
program.Constant{Inner: internal.AccountAddress("bob")},
},
},
})
})

t.Run("save all", func(t *testing.T) {
test(t, TestCase{
Case: `
save [EUR *] from @alice
send [EUR 20] (
source = @alice
destination = @bob
)`,
Expected: CaseResult{
Instructions: []byte{
program.OP_APUSH, 00, 00,
program.OP_APUSH, 01, 00,
program.OP_SAVE,
program.OP_APUSH, 01, 00,
program.OP_APUSH, 02, 00,
program.OP_ASSET,
program.OP_APUSH, 03, 00,
program.OP_MONETARY_NEW,
program.OP_TAKE_ALL,
program.OP_APUSH, 02, 00,
program.OP_TAKE,
program.OP_APUSH, 04, 00,
program.OP_BUMP,
program.OP_REPAY,
program.OP_FUNDING_SUM,
program.OP_TAKE,
program.OP_APUSH, 05, 00,
program.OP_SEND,
program.OP_REPAY,
},
Resources: []program.Resource{
program.Constant{Inner: internal.Asset("EUR")},
program.Constant{Inner: internal.AccountAddress("alice")},
program.Monetary{
Asset: 0,
Amount: internal.NewMonetaryInt(20),
},
program.Constant{Inner: internal.NewMonetaryInt(0)},
program.Constant{Inner: internal.NewMonetaryInt(1)},
program.Constant{Inner: internal.AccountAddress("bob")},
},
},
})
})

t.Run("with asset var", func(t *testing.T) {
test(t, TestCase{
Case: `
vars {
asset $ass
}
save [$ass 10] from @alice
send [$ass 20] (
source = @alice
destination = @bob
)`,
Expected: CaseResult{
Instructions: []byte{
program.OP_APUSH, 01, 00,
program.OP_APUSH, 02, 00,
program.OP_SAVE,
program.OP_APUSH, 02, 00,
program.OP_APUSH, 03, 00,
program.OP_ASSET,
program.OP_APUSH, 04, 00,
program.OP_MONETARY_NEW,
program.OP_TAKE_ALL,
program.OP_APUSH, 03, 00,
program.OP_TAKE,
program.OP_APUSH, 05, 00,
program.OP_BUMP,
program.OP_REPAY,
program.OP_FUNDING_SUM,
program.OP_TAKE,
program.OP_APUSH, 06, 00,
program.OP_SEND,
program.OP_REPAY,
},
Resources: []program.Resource{
program.Variable{Typ: internal.TypeAsset, Name: "ass"},
program.Monetary{
Asset: 0,
Amount: internal.NewMonetaryInt(10),
},
program.Constant{Inner: internal.AccountAddress("alice")},
program.Monetary{
Asset: 0,
Amount: internal.NewMonetaryInt(20),
},
program.Constant{Inner: internal.NewMonetaryInt(0)},
program.Constant{Inner: internal.NewMonetaryInt(1)},
program.Constant{Inner: internal.AccountAddress("bob")},
},
},
})
})

t.Run("with monetary var", func(t *testing.T) {
test(t, TestCase{
Case: `
vars {
monetary $mon
}
save $mon from @alice
send [EUR 20] (
source = @alice
destination = @bob
)`,
Expected: CaseResult{
Instructions: []byte{
program.OP_APUSH, 00, 00,
program.OP_APUSH, 01, 00,
program.OP_SAVE,
program.OP_APUSH, 01, 00,
program.OP_APUSH, 03, 00,
program.OP_ASSET,
program.OP_APUSH, 04, 00,
program.OP_MONETARY_NEW,
program.OP_TAKE_ALL,
program.OP_APUSH, 03, 00,
program.OP_TAKE,
program.OP_APUSH, 05, 00,
program.OP_BUMP,
program.OP_REPAY,
program.OP_FUNDING_SUM,
program.OP_TAKE,
program.OP_APUSH, 06, 00,
program.OP_SEND,
program.OP_REPAY,
},
Resources: []program.Resource{
program.Variable{Typ: internal.TypeMonetary, Name: "mon"},
program.Constant{Inner: internal.AccountAddress("alice")},
program.Constant{Inner: internal.Asset("EUR")},
program.Monetary{
Asset: 2,
Amount: internal.NewMonetaryInt(20),
},
program.Constant{Inner: internal.NewMonetaryInt(0)},
program.Constant{Inner: internal.NewMonetaryInt(1)},
program.Constant{Inner: internal.AccountAddress("bob")},
},
},
})
})

t.Run("error wrong type monetary", func(t *testing.T) {
test(t, TestCase{
Case: `
save 30 from @alice
`,
Expected: CaseResult{
Instructions: []byte{},
Resources: []program.Resource{},
Error: "save monetary from account: the first expression should be of type 'monetary' instead of 'number'",
},
})
})

t.Run("error wrong type account", func(t *testing.T) {
test(t, TestCase{
Case: `
save [EUR 30] from ALICE
`,
Expected: CaseResult{
Instructions: []byte{},
Resources: []program.Resource{},
Error: "save monetary from account: the second expression should be of type 'account' instead of 'asset'",
},
})
})
}
4 changes: 3 additions & 1 deletion pkg/machine/script/parser/NumScript.interp

Large diffs are not rendered by default.

Loading

0 comments on commit a8b940a

Please sign in to comment.