summaryrefslogtreecommitdiffstats
path: root/lib/puppet/parser/ast/leaf.rb
blob: 7743862d703fa7e4321eba25cdd298b3a225ee70 (plain)
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
class Puppet::Parser::AST
    # The base class for all of the leaves of the parse trees.  These
    # basically just have types and values.  Both of these parameters
    # are simple values, not AST objects.
    class Leaf < AST
        attr_accessor :value, :type

        # Return our value.
        def evaluate(scope)
            return @value
        end

        # evaluate ourselves, and match
        def evaluate_match(value, scope, options = {})
            obj = self.safeevaluate(scope)
            if ! options[:sensitive] && obj.respond_to?(:downcase)
                obj = obj.downcase
            end
            obj == value
        end

        def to_s
            return @value.to_s unless @value.nil?
        end
    end

    # The boolean class.  True or false.  Converts the string it receives
    # to a Ruby boolean.
    class Boolean < AST::Leaf

        # Use the parent method, but then convert to a real boolean.
        def initialize(hash)
            super

            unless @value == true or @value == false
                raise Puppet::DevError,
                    "'%s' is not a boolean" % @value
            end
            @value
        end

        def to_s
            @value ? "true" : "false"
        end
    end

    # The base string class.
    class String < AST::Leaf
        # Interpolate the string looking for variables, and then return
        # the result.
        def evaluate(scope)
            return scope.strinterp(@value, file, line)
        end

        def to_s
            "\"#{@value}\""
        end
    end

    # An uninterpreted string.
    class FlatString < AST::Leaf
        def evaluate(scope)
            return @value
        end

        def to_s
            "\"#{@value}\""
        end
    end

    # The 'default' option on case statements and selectors.
    class Default < AST::Leaf; end

    # Capitalized words; used mostly for type-defaults, but also
    # get returned by the lexer any other time an unquoted capitalized
    # word is found.
    class Type < AST::Leaf; end

    # Lower-case words.
    class Name < AST::Leaf; end

    # double-colon separated class names
    class ClassName < AST::Leaf; end

    # undef values; equiv to nil
    class Undef < AST::Leaf; end

    # Host names, either fully qualified or just the short name
    class HostName < AST::Leaf
        def initialize(hash)
            super

            unless @value =~ %r{^[0-9a-zA-Z\-]+(\.[0-9a-zA-Z\-]+)*$}
                raise Puppet::DevError,
                    "'%s' is not a valid hostname" % @value
            end
        end
    end

    # A simple variable.  This object is only used during interpolation;
    # the VarDef class is used for assignment.
    class Variable < Name
        # Looks up the value of the object in the scope tree (does
        # not include syntactical constructs, like '$' and '{}').
        def evaluate(scope)
            parsewrap do
                return scope.lookupvar(@value)
            end
        end
    end

    class Regex < AST::Leaf
        def initialize(hash)
            super
            @value = Regexp.new(@value) unless @value.is_a?(Regexp)
        end

        # we're returning self here to wrap the regexp and to be used in places
        # where a string would have been used, without modifying any client code.
        # For instance, in many places we have the following code snippet:
        #  val = @val.safeevaluate(@scope)
        #  if val.match(otherval)
        #      ...
        #  end
        # this way, we don't have to modify this test specifically for handling
        # regexes.
        def evaluate(scope)
            return self
        end

        def evaluate_match(value, scope, options = {})
            value = value.is_a?(String) ? value : value.to_s

            if matched = @value.match(value)
                scope.ephemeral_from(matched, options[:file], options[:line])
            end
            matched
        end

        def to_s
            return "/#{@value.source}/"
        end
    end
end