Skip to content
Permalink
Browse files

Implemented date expression parsing.

  • Loading branch information...
renato
renato committed Mar 28, 2019
1 parent b9d8621 commit a05256a51a0fcb20c1015647df8ff34fc12c5983
Showing with 96 additions and 0 deletions.
  1. +48 −0 mg/expression/parser.go
  2. +48 −0 tests/expression/date_expr_test.go
@@ -8,6 +8,7 @@ import (
"go/token"
"strconv"
"strings"
"time"
)

// Expression is a parsed Magnanimous expression.
@@ -77,6 +78,8 @@ func eval(e ast.Expr, context Context) (interface{}, error) {
return resolveUnary(ex, context)
case *ast.SelectorExpr:
return resolveAccessField(ex, context)
case *ast.IndexExpr:
return resolveIndexExpr(ex, context)
}

return nil, errors.New(fmt.Sprintf("Unrecognized expression: %s", e))
@@ -195,6 +198,51 @@ func resolveAccessField(expr *ast.SelectorExpr, ctx Context) (interface{}, error
return nil, errors.New(fmt.Sprintf("cannot access properties of object: %v", rcv))
}

func resolveIndexExpr(expr *ast.IndexExpr, ctx Context) (interface{}, error) {
// the only supported index expression is of form 'date["2016-05-04"]'
var rcvName string
switch rcv := expr.X.(type) {
case *ast.Ident:
rcvName = rcv.Name
default:
return nil, errors.New(fmt.Sprintf("Malformed index expression (only date[] is supported): %v", rcv))
}

if rcvName == "date" {
idx, err := eval(expr.Index, ctx)
if err != nil {
return nil, err
}
switch date := idx.(type) {
case string:
return parseDate(date)
default:
// format: Mon Jan 2 15:04:05 -0700 MST 2006
return nil, errors.New(fmt.Sprintf(
"Malformed date expression (should be like date[\"2006-01-02T15:04:05\"]): %v", idx))
}
} else {
return nil, errors.New(fmt.Sprintf("Unknown index expression (only date[] is supported): %s", rcvName))
}
}

func parseDate(idx string) (interface{}, error) {
date, err := time.Parse("2006-01-02T15:04:05", idx)
if err == nil {
return date, nil
}
date, err = time.Parse("2006-01-02T15:04", idx)
if err == nil {
return date, nil
}
date, err = time.Parse("2006-01-02", idx)
if err == nil {
return date, nil
}
return nil, errors.New("invalid date: %v (valid formats are: \"2006-01-02T15:04:05\", " +
"\"2006-01-02T15:04\", \"2006-01-02\"")
}

// ToContext attempts to convert a variable to a [Context].
func ToContext(ctx interface{}) (Context, bool) {
if v, ok := ctx.(Context); ok {
@@ -0,0 +1,48 @@
package expression

import (
"fmt"
"github.com/renatoathaydes/magnanimous/mg/expression"
"testing"
"time"
)

func TestDateExpr(t *testing.T) {
expected := "2017-02-03"
checkDate(t, fmt.Sprintf(`date["%s"]`, expected), expected, "2006-01-02")
}

func TestDateExprMid(t *testing.T) {
expected := "2017-02-03T10:40"
checkDate(t, fmt.Sprintf(`date["%s"]`, expected), expected, "2006-01-02T15:04")
}

func TestDateExprLong(t *testing.T) {
expected := "2017-02-03T10:40:32"
checkDate(t, fmt.Sprintf(`date["%s"]`, expected), expected, "2006-01-02T15:04:05")
}

// Go format: Mon Jan 2 15:04:05 -0700 MST 2006

func checkDate(t *testing.T, dateExpr, expected, format string) {
e, err := expression.ParseExpr(dateExpr)

if err != nil {
t.Fatalf("Could not parse: %v", err)
}

v, err := expression.EvalExpr(e, nil)

if err != nil {
t.Fatalf("Could not evaluate: %v", err)
}

expectedTime, err := time.Parse(format, expected)
if err != nil {
panic(err)
}

if v != expectedTime {
t.Errorf("Expected '%v' but got '%v'", expectedTime, v)
}
}

0 comments on commit a05256a

Please sign in to comment.
You can’t perform that action at this time.