Skip to content

Commit

Permalink
Merge pull request #129 from Mido-sys/add_index_assignment
Browse files Browse the repository at this point in the history
Add index assignment
  • Loading branch information
paganotoni authored Apr 14, 2021
2 parents 3159ff3 + 0d09d44 commit 99f6eb9
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 1 deletion.
5 changes: 5 additions & 0 deletions ast/index_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type IndexExpression struct {
TokenAble
Left Expression
Index Expression
Value Expression
}

func (ie *IndexExpression) expressionNode() {}
Expand All @@ -20,6 +21,10 @@ func (ie *IndexExpression) String() string {
out.WriteString("[")
out.WriteString(ie.Index.String())
out.WriteString("])")
if ie.Value != nil {
out.WriteString("=")
out.WriteString(ie.Value.String())
}

return out.String()
}
28 changes: 27 additions & 1 deletion compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,16 +266,42 @@ func (c *compiler) evalIndexExpression(node *ast.IndexExpression) (interface{},
if err != nil {
return nil, err
}
var value interface{}

if node.Value != nil {

value, err = c.evalExpression(node.Value)
if err != nil {
return nil, err
}

}
rv := reflect.ValueOf(left)
switch rv.Kind() {
case reflect.Map:
val := rv.MapIndex(reflect.ValueOf(index))
if !val.IsValid() {
if !val.IsValid() && node.Value == nil {
return nil, nil
}
if node.Value != nil {
rv.SetMapIndex(reflect.ValueOf(index), reflect.ValueOf(value))
return nil, nil
}

return val.Interface(), nil
case reflect.Array, reflect.Slice:
if i, ok := index.(int); ok {

if node.Value != nil {

if rv.Len()-1 < i {

return nil, fmt.Errorf("array index out of bounds, got index %d, while array size is %v", i, rv.Len())

}
rv.Index(i).Set(reflect.ValueOf(value))
return nil, nil
}
return rv.Index(i).Interface(), nil
}
}
Expand Down
7 changes: 7 additions & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,13 @@ func (p *parser) parseIndexExpression(left ast.Expression) ast.Expression {
return nil
}

if p.peekTokenIs(token.ASSIGN) {
p.nextToken()
p.nextToken()

exp.Value = p.parseExpression(LOWEST)
}

return exp
}

Expand Down
16 changes: 16 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,22 @@ func Test_ArrayLiterals(t *testing.T) {
r.True(testInfixExpression(t, array.Elements[2], 3, "+", 3))
}

func Test_IndexExpressionsAssign(t *testing.T) {
r := require.New(t)
input := "<% myArray[2] = 1 %>"

program, err := Parse(input)
r.NoError(err)

stmt := program.Statements[0].(*ast.ExpressionStatement)
indexExp := stmt.Expression.(*ast.IndexExpression)

r.True(testIdentifier(t, indexExp.Left, "myArray"))
r.True(testIntegerLiteral(t, indexExp.Index, 2))
r.True(testIntegerLiteral(t, indexExp.Value, 1))
//r.True(testInfixExpression(t, indexExp.Index, 2, "=", 1))
}

func Test_IndexExpressions(t *testing.T) {
r := require.New(t)
input := "<% myArray[1 + 1] %>"
Expand Down
75 changes: 75 additions & 0 deletions variables_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,78 @@ func Test_Render_Let_Hash(t *testing.T) {
r.NoError(err)
r.Equal("<p>A</p>", s)
}

func Test_Render_Let_HashAssign(t *testing.T) {
r := require.New(t)

input := `<p><% let h = {"a": "A"} %><% h["a"] = "C"%><%= h["a"] %></p>`
s, err := Render(input, NewContext())
r.NoError(err)
r.Equal("<p>C</p>", s)
}

func Test_Render_Let_HashAssign_NewKey(t *testing.T) {
r := require.New(t)

input := `<p><% let h = {"a": "A"} %><% h["b"] = "d" %><%= h["b"] %></p>`
s, err := Render(input, NewContext())
r.NoError(err)
r.Equal("<p>d</p>", s)
}

func Test_Render_Let_HashAssign_Int(t *testing.T) {
r := require.New(t)

input := `<p><% let h = {"a": "A"} %><% h["b"] = 3 %><%= h["b"] %></p>`
s, err := Render(input, NewContext())
r.NoError(err)
r.Equal("<p>3</p>", s)
}

func Test_Render_Let_HashAssign_InvalidKey(t *testing.T) {
r := require.New(t)

input := `<p><% let h = {"a": "A"} %><% h["b"] = 3 %><%= h["c"] %></p>`
s, err := Render(input, NewContext())
r.NoError(err)
r.Equal("<p></p>", s)
}

func Test_Render_Let_ArrayAssign_InvalidKey(t *testing.T) {
r := require.New(t)

input := `<p><% let a = [1, 2, "three", "four", 3.75] %><% a["b"] = 3 %><%= a["c"] %></p>`
_, err := Render(input, NewContext())
r.Error(err)
//r.NoError(err)
//r.Equal("<p></p>", s)
}

func Test_Render_Let_ArrayAssign_ValidIndex(t *testing.T) {
r := require.New(t)

input := `<p><% let a = [1, 2, "three", "four", 3.75] %><% a[0] = 3 %><%= a[0] %></p>`
s, err := Render(input, NewContext())
//r.Error(err)
r.NoError(err)
r.Equal("<p>3</p>", s)
}

func Test_Render_Let_ArrayAssign_Resultaddition(t *testing.T) {
r := require.New(t)

input := `<p><% let a = [1, 2, "three", "four", 3.75] %><% a[4] = 3 %><%= a[4] + 2 %></p>`
s, err := Render(input, NewContext())
//r.Error(err)
r.NoError(err)
r.Equal("<p>5</p>", s)
}

func Test_Render_Let_ArrayAssign_OutofBoundsIndex(t *testing.T) {
r := require.New(t)

input := `<p><% let a = [1, 2, "three", "four", 3.75] %><% a[5] = 3 %><%= a[4] + 2 %></p>`
_, err := Render(input, NewContext())
r.Error(err)

}

0 comments on commit 99f6eb9

Please sign in to comment.