/
fmt.go
101 lines (82 loc) · 2.16 KB
/
fmt.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package core
import (
"bytes"
"errors"
"io"
"time"
"github.com/inoxlang/inox/internal/core/symbolic"
"github.com/inoxlang/inox/internal/utils"
)
const (
DATE_FORMAT_PATTERN_NAMESPACE = "date-format"
)
var (
_ = []Format{(*DateFormat)(nil)}
_ = []StringFormat{(*DateFormat)(nil)}
ErrInvalidFormattingArgument = errors.New("invalid formatting argument")
)
func init() {
RegisterSymbolicGoFunction(Fmt, func(ctx *symbolic.Context, format symbolic.Format, v symbolic.Value) (symbolic.Value, *symbolic.Error) {
return symbolic.ANY, nil
})
}
// A Format represents a string or binary format.
type Format interface {
Pattern
Format(ctx *Context, arg Value, w io.Writer) (int, error)
}
func Fmt(ctx *Context, format Format, arg Value) (Value, error) {
buf := bytes.NewBuffer(nil)
if _, err := format.Format(ctx, arg, buf); err != nil {
return nil, err
}
if _, ok := format.(StringFormat); ok {
return String(buf.String()), nil
}
panic(errors.New("only string formats are supported for now"))
}
type StringFormat interface {
Format
StringPattern
}
// TODO:
// type BinaryFormat interface {
// Format
// }
type DateFormat struct {
*ParserBasedPseudoPattern
layout string
NamespaceMemberPatternReprMixin
}
func NewDateFormat(layout, namespaceMemberName string) *DateFormat {
fmt := &DateFormat{
layout: layout,
ParserBasedPseudoPattern: NewParserBasePattern(&dateLayoutParser{layout: layout}),
NamespaceMemberPatternReprMixin: NamespaceMemberPatternReprMixin{
NamespaceName: DATE_FORMAT_PATTERN_NAMESPACE,
MemberName: namespaceMemberName,
},
}
return fmt
}
func (f *DateFormat) Format(ctx *Context, v Value, w io.Writer) (int, error) {
t, ok := v.(DateTime)
if !ok {
return -1, ErrInvalidFormattingArgument
}
return w.Write(utils.StringAsBytes(time.Time(t).Format(f.layout)))
}
type dateLayoutParser struct {
layout string
}
func (p *dateLayoutParser) Validate(ctx *Context, s string) bool {
_, err := time.Parse(p.layout, s)
return err == nil
}
func (p *dateLayoutParser) Parse(ctx *Context, s string) (Serializable, error) {
t, err := time.Parse(p.layout, s)
if err != nil {
return nil, err
}
return DateTime(t), nil
}