Skip to content

Commit

Permalink
Save statement implementation (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
ascandone authored Nov 8, 2024
1 parent db8980f commit 4293e52
Show file tree
Hide file tree
Showing 24 changed files with 1,452 additions and 386 deletions.
2 changes: 2 additions & 0 deletions Numscript.g4
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ ALLOWING: 'allowing';
UNBOUNDED: 'unbounded';
OVERDRAFT: 'overdraft';
KEPT: 'kept';
SAVE: 'save';
LPARENS: '(';
RPARENS: ')';
LBRACKET: '[';
Expand Down Expand Up @@ -100,4 +101,5 @@ sentValue: literal # sentLiteral | sentAllLit # sentAll;
statement:
SEND sentValue LPARENS SOURCE EQ source DESTINATION EQ destination RPARENS # sendStatement
| SAVE sentValue FROM literal # saveStatement
| functionCall # fnCallStatement;
4 changes: 4 additions & 0 deletions internal/analysis/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ func (res *CheckResult) checkStatement(statement parser.Statement) {
res.emptiedAccount = make(map[string]struct{})

switch statement := statement.(type) {
case *parser.SaveStatement:
res.checkSentValue(statement.SentValue)
res.checkLiteral(statement.Literal, TypeAccount)

case *parser.SendStatement:
_, isSendAll := statement.SentValue.(*parser.SentValueAll)
res.unboundedSend = isSendAll
Expand Down
56 changes: 56 additions & 0 deletions internal/analysis/check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,62 @@ func TestDuplicateVariable(t *testing.T) {
)
}

func TestUnboundVarInSaveAccount(t *testing.T) {
t.Parallel()

input := `save $unbound_mon from $unbound_acc`

program := parser.Parse(input).Value

diagnostics := analysis.CheckProgram(program).Diagnostics
require.Len(t, diagnostics, 2)

assert.Equal(t,
[]analysis.Diagnostic{
{
Kind: &analysis.UnboundVariable{Name: "unbound_mon"},
Range: parser.RangeOfIndexed(input, "$unbound_mon", 0),
},
{
Kind: &analysis.UnboundVariable{Name: "unbound_acc"},
Range: parser.RangeOfIndexed(input, "$unbound_acc", 0),
},
},
diagnostics,
)
}

func TestMismatchedTypeInSave(t *testing.T) {
t.Parallel()

input := `vars {
string $str
number $n
}
save $str from $n
`

program := parser.Parse(input).Value

diagnostics := analysis.CheckProgram(program).Diagnostics
require.Len(t, diagnostics, 2)

assert.Equal(t,
[]analysis.Diagnostic{
{
Kind: &analysis.TypeMismatch{Expected: "monetary", Got: "string"},
Range: parser.RangeOfIndexed(input, "$str", 1),
},
{
Kind: &analysis.TypeMismatch{Expected: "account", Got: "number"},
Range: parser.RangeOfIndexed(input, "$n", 1),
},
},
diagnostics,
)
}

func TestUnboundVarInSource(t *testing.T) {
t.Parallel()

Expand Down
3 changes: 2 additions & 1 deletion internal/analysis/goto_definition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/formancehq/numscript/internal/parser"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGotoDefinitionOnSendMonetaryVar(t *testing.T) {
Expand All @@ -23,7 +24,7 @@ send $amt (
checkResult := analysis.CheckProgram(program)

res := analysis.GotoDefinition(program, rng.Start, checkResult)
assert.NotNil(t, res)
require.NotNil(t, res)

assert.Equal(t, &analysis.GotoDefinitionResult{
Range: parser.RangeOfIndexed(input, "$amt", 0),
Expand Down
24 changes: 24 additions & 0 deletions internal/analysis/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ func HoverOn(program parser.Program, position parser.Position) Hover {
return hover
}

case *parser.SaveStatement:
hover := hoverOnSaveStatement(*statement, position)
if hover != nil {
return hover
}

case *parser.FnCall:
hover := hoverOnFnCall(*statement, position)
if hover != nil {
Expand Down Expand Up @@ -92,6 +98,24 @@ func hoverOnSentValue(sentValue parser.SentValue, position parser.Position) Hove
}
}

func hoverOnSaveStatement(saveStatement parser.SaveStatement, position parser.Position) Hover {
if !saveStatement.Range.Contains(position) {
return nil
}

hover := hoverOnSentValue(saveStatement.SentValue, position)
if hover != nil {
return hover
}

hover = hoverOnLiteral(saveStatement.Literal, position)
if hover != nil {
return hover
}

return nil
}

func hoverOnSendStatement(sendStatement parser.SendStatement, position parser.Position) Hover {
if !sendStatement.Range.Contains(position) {
return nil
Expand Down
Loading

0 comments on commit 4293e52

Please sign in to comment.