1package ast
2
3import (
4	"fmt"
5	"reflect"
6)
7
8// LiteralNode represents a single literal value, such as "foo" or
9// 42 or 3.14159. Based on the Type, the Value can be safely cast.
10type LiteralNode struct {
11	Value interface{}
12	Typex Type
13	Posx  Pos
14}
15
16// NewLiteralNode returns a new literal node representing the given
17// literal Go value, which must correspond to one of the primitive types
18// supported by HIL. Lists and maps cannot currently be constructed via
19// this function.
20//
21// If an inappropriately-typed value is provided, this function will
22// return an error. The main intended use of this function is to produce
23// "synthetic" literals from constants in code, where the value type is
24// well known at compile time. To easily store these in global variables,
25// see also MustNewLiteralNode.
26func NewLiteralNode(value interface{}, pos Pos) (*LiteralNode, error) {
27	goType := reflect.TypeOf(value)
28	var hilType Type
29
30	switch goType.Kind() {
31	case reflect.Bool:
32		hilType = TypeBool
33	case reflect.Int:
34		hilType = TypeInt
35	case reflect.Float64:
36		hilType = TypeFloat
37	case reflect.String:
38		hilType = TypeString
39	default:
40		return nil, fmt.Errorf("unsupported literal node type: %T", value)
41	}
42
43	return &LiteralNode{
44		Value: value,
45		Typex: hilType,
46		Posx:  pos,
47	}, nil
48}
49
50// MustNewLiteralNode wraps NewLiteralNode and panics if an error is
51// returned, thus allowing valid literal nodes to be easily assigned to
52// global variables.
53func MustNewLiteralNode(value interface{}, pos Pos) *LiteralNode {
54	node, err := NewLiteralNode(value, pos)
55	if err != nil {
56		panic(err)
57	}
58	return node
59}
60
61func (n *LiteralNode) Accept(v Visitor) Node {
62	return v(n)
63}
64
65func (n *LiteralNode) Pos() Pos {
66	return n.Posx
67}
68
69func (n *LiteralNode) GoString() string {
70	return fmt.Sprintf("*%#v", *n)
71}
72
73func (n *LiteralNode) String() string {
74	return fmt.Sprintf("Literal(%s, %v)", n.Typex, n.Value)
75}
76
77func (n *LiteralNode) Type(Scope) (Type, error) {
78	return n.Typex, nil
79}
80
81// IsUnknown returns true either if the node's value is itself unknown
82// of if it is a collection containing any unknown elements, deeply.
83func (n *LiteralNode) IsUnknown() bool {
84	return IsUnknown(Variable{
85		Type:  n.Typex,
86		Value: n.Value,
87	})
88}
89