From e94ef7cdca889981279df51de1987c6b7adc3f74 Mon Sep 17 00:00:00 2001 From: mido Date: Thu, 6 Feb 2025 07:38:32 -0800 Subject: [PATCH 1/2] Add append feature for arrays --- README.md | 8 ++++++++ compiler.go | 25 +++++++++++++++++++++++++ variables_test.go | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/README.md b/README.md index f2997d7..3c918fc 100644 --- a/README.md +++ b/README.md @@ -191,6 +191,14 @@ Arrays in Plush will get translated to the Go type `[]interface{}` when used. []interface{}{ 1, 2, "three", "four", h } ``` +Arrays in plush can be appended using the followg format: + +```erb +<% let a = [1, 2, "three", "four", h] %> <% a = a + "hello world"%> +``` + +If the array passed to plush is not of type `[]interface{}` and an attempt is made to append a value with a data type that does not match the underlying array type, an error will be returned. + ## For Loops There are three different types that can be looped over: maps, arrays/slices, and iterators. The format for them all looks the same: diff --git a/compiler.go b/compiler.go index 219c1f2..64824c4 100644 --- a/compiler.go +++ b/compiler.go @@ -499,11 +499,36 @@ func (c *compiler) evalInfixExpression(node *ast.InfixExpression) (interface{}, } case bool: return c.boolsOperator(lres, rres, node.Operator) + default: + if reflect.TypeOf(t).Kind() == reflect.Slice || reflect.TypeOf(t).Kind() == reflect.Array { + return c.arrayOperator(lres, rres, node.Operator) + } } return nil, fmt.Errorf("unable to operate (%s) on %T and %T ", node.Operator, lres, rres) } +func (c *compiler) arrayOperator(l interface{}, r interface{}, op string) (interface{}, error) { + var err error + switch op { + case "+": + elemType := reflect.TypeOf(l).Elem() + if elemType.Kind() != reflect.Interface { + t := reflect.ValueOf(r).Type() + if elemType != t { + err = fmt.Errorf("cannot append '%v' (untyped %s constant) as %s value in assignment", r, t, elemType) + } + } + if err == nil { + return reflect.Append(reflect.ValueOf(l), reflect.ValueOf(r)), nil + } + default: + err = fmt.Errorf("unkown operator (%s) on %T and %T ", op, l, r) + } + + return nil, err +} + func (c *compiler) nilsOperator(l interface{}, r interface{}, op string) (interface{}, error) { switch op { case "!=": diff --git a/variables_test.go b/variables_test.go index 351dbf8..c8ed4a8 100644 --- a/variables_test.go +++ b/variables_test.go @@ -2,6 +2,7 @@ package plush_test import ( "html/template" + "log" "strings" "testing" @@ -174,6 +175,37 @@ func Test_Render_Let_ArrayAsssign_AssignableToArrayInterface(t *testing.T) { r.NoError(err) } +func Test_Render_AppendArray_WithTypeIntArrayTypeString(t *testing.T) { + r := require.New(t) + ctx := plush.NewContext() + + ctx.Set("myArray", []string{"a", "b"}) + input := `<% let a = myArray %><% a = a + 1 %><%= a %>` + _, err := plush.Render(input, ctx) + r.Error(err) + r.Contains(err.Error(), "cannot append '1' (untyped int constant) as string value in assignment") +} + +func Test_Render_AppendArray_CreatedInPlush(t *testing.T) { + r := require.New(t) + + input := `<% let a = [1,2,"HelloWorld"] %><% a = a + 2.2 %><%= a %>` + s, err := plush.Render(input, plush.NewContext()) + r.NoError(err) + r.Equal(s, "12HelloWorld2.2") +} +func Test_Render_AppendArray_WithTypeInterface(t *testing.T) { + r := require.New(t) + ctx := plush.NewContext() + + ctx.Set("myArray", []interface{}{"a", "b"}) + input := `<% let a = myArray %><% a = a + 1 %><%= a %>` + s, err := plush.Render(input, ctx) + log.Println(s) + r.NoError(err) + r.Equal("ab1", s) +} + type Category1 struct { Products []Product1 } From 2135de2dd732674587904b2c153a9af3aae1ef87 Mon Sep 17 00:00:00 2001 From: mido Date: Thu, 6 Feb 2025 07:42:09 -0800 Subject: [PATCH 2/2] fix typo in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c918fc..9fbab45 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ Arrays in Plush will get translated to the Go type `[]interface{}` when used. []interface{}{ 1, 2, "three", "four", h } ``` -Arrays in plush can be appended using the followg format: +Arrays in plush can be appended using the following format: ```erb <% let a = [1, 2, "three", "four", h] %> <% a = a + "hello world"%>