1 // Package token defines constants representing the lexical tokens for HCL
2 // (HashiCorp Configuration Language)
10 hclstrconv "github.com/hashicorp/hcl/hcl/strconv"
13 // Token defines a single HCL token which can be obtained via the Scanner
21 // Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language)
37 HEREDOC // <<FOO\nbar\nFOO
56 var tokens = [...]string{
82 // String returns the string corresponding to the token tok.
83 func (t Type) String() string {
85 if 0 <= t && t < Type(len(tokens)) {
89 s = "token(" + strconv.Itoa(int(t)) + ")"
94 // IsIdentifier returns true for tokens corresponding to identifiers and basic
95 // type literals; it returns false otherwise.
96 func (t Type) IsIdentifier() bool { return identifier_beg < t && t < identifier_end }
98 // IsLiteral returns true for tokens corresponding to basic type literals; it
99 // returns false otherwise.
100 func (t Type) IsLiteral() bool { return literal_beg < t && t < literal_end }
102 // IsOperator returns true for tokens corresponding to operators and
103 // delimiters; it returns false otherwise.
104 func (t Type) IsOperator() bool { return operator_beg < t && t < operator_end }
106 // String returns the token's literal text. Note that this is only
107 // applicable for certain token types, such as token.IDENT,
108 // token.STRING, etc..
109 func (t Token) String() string {
110 return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text)
113 // Value returns the properly typed value for this token. The type of
114 // the returned interface{} is guaranteed based on the Type field.
116 // This can only be called for literal types. If it is called for any other
117 // type, this will panic.
118 func (t Token) Value() interface{} {
121 if t.Text == "true" {
123 } else if t.Text == "false" {
127 panic("unknown bool value: " + t.Text)
129 v, err := strconv.ParseFloat(t.Text, 64)
136 v, err := strconv.ParseInt(t.Text, 0, 64)
145 return unindentHeredoc(t.Text)
147 // Determine the Unquote method to use. If it came from JSON,
148 // then we need to use the built-in unquote since we have to
149 // escape interpolations there.
150 f := hclstrconv.Unquote
155 // This case occurs if json null is used
162 panic(fmt.Sprintf("unquote %s err: %s", t.Text, err))
167 panic(fmt.Sprintf("unimplemented Value for type: %s", t.Type))
171 // unindentHeredoc returns the string content of a HEREDOC if it is started with <<
172 // and the content of a HEREDOC with the hanging indent removed if it is started with
173 // a <<-, and the terminating line is at least as indented as the least indented line.
174 func unindentHeredoc(heredoc string) string {
175 // We need to find the end of the marker
176 idx := strings.IndexByte(heredoc, '\n')
178 panic("heredoc doesn't contain newline")
181 unindent := heredoc[2] == '-'
183 // We can optimize if the heredoc isn't marked for indentation
185 return string(heredoc[idx+1 : len(heredoc)-idx+1])
188 // We need to unindent each line based on the indentation level of the marker
189 lines := strings.Split(string(heredoc[idx+1:len(heredoc)-idx+2]), "\n")
190 whitespacePrefix := lines[len(lines)-1]
193 for _, v := range lines {
194 if strings.HasPrefix(v, whitespacePrefix) {
202 // If all lines are not at least as indented as the terminating mark, return the
203 // heredoc as is, but trim the leading space from the marker on the final line.
205 return strings.TrimRight(string(heredoc[idx+1:len(heredoc)-idx+1]), " \t")
208 unindentedLines := make([]string, len(lines))
209 for k, v := range lines {
210 if k == len(lines)-1 {
211 unindentedLines[k] = ""
215 unindentedLines[k] = strings.TrimPrefix(v, whitespacePrefix)
218 return strings.Join(unindentedLines, "\n")