// Copyright 2020 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package tokens

import "maps"

// Token represents a single Rego source code token
// for use by the Parser.
type Token uint8

func (t Token) String() string {
	if int(t) >= len(strings) {
		return "unknown"
	}
	return strings[t]
}

// All tokens must be defined here
const (
	Illegal Token = iota
	EOF
	Whitespace
	Ident
	Comment

	Package
	Import
	As
	Default
	Else
	Not
	Some
	With
	Null
	True
	False

	Number
	String
	TemplateStringPart
	TemplateStringEnd
	RawTemplateStringPart
	RawTemplateStringEnd

	LBrack
	RBrack
	LBrace
	RBrace
	LParen
	RParen
	Comma
	Colon

	Add
	Sub
	Mul
	Quo
	Rem
	And
	Or
	Unify
	Equal
	Assign
	In
	Neq
	Gt
	Lt
	Gte
	Lte
	Dot
	Semicolon
	Dollar

	Every
	Contains
	If
	LogicalAnd
	LogicalOr
)

var strings = [...]string{
	Illegal:               "illegal",
	EOF:                   "eof",
	Whitespace:            "whitespace",
	Comment:               "comment",
	Ident:                 "identifier",
	Package:               "package",
	Import:                "import",
	As:                    "as",
	Default:               "default",
	Else:                  "else",
	Not:                   "not",
	Some:                  "some",
	With:                  "with",
	Null:                  "null",
	True:                  "true",
	False:                 "false",
	Number:                "number",
	String:                "string",
	TemplateStringPart:    "template-string-part",
	TemplateStringEnd:     "template-string-end",
	RawTemplateStringPart: "raw-template-string-part",
	RawTemplateStringEnd:  "raw-template-string-end",
	LBrack:                "[",
	RBrack:                "]",
	LBrace:                "{",
	RBrace:                "}",
	LParen:                "(",
	RParen:                ")",
	Comma:                 ",",
	Colon:                 ":",
	Add:                   "plus",
	Sub:                   "minus",
	Mul:                   "mul",
	Quo:                   "div",
	Rem:                   "rem",
	And:                   "and",
	Or:                    "or",
	Unify:                 "eq",
	Equal:                 "equal",
	Assign:                "assign",
	In:                    "in",
	Neq:                   "neq",
	Gt:                    "gt",
	Lt:                    "lt",
	Gte:                   "gte",
	Lte:                   "lte",
	Dot:                   ".",
	Semicolon:             ";",
	Dollar:                "dollar",
	Every:                 "every",
	Contains:              "contains",
	If:                    "if",
	LogicalAnd:            "and",
	LogicalOr:             "or",
}

var keywords = map[string]Token{
	"package": Package,
	"import":  Import,
	"as":      As,
	"default": Default,
	"else":    Else,
	"not":     Not,
	"some":    Some,
	"with":    With,
	"null":    Null,
	"true":    True,
	"false":   False,
}

// Keywords returns a copy of the default string -> Token keyword map.
func Keywords() map[string]Token {
	return maps.Clone(keywords)
}

// IsKeyword returns if a token is a keyword
func IsKeyword(tok Token) bool {
	_, ok := keywords[strings[tok]]
	return ok
}

func KeywordFor(tok Token) string {
	return strings[tok]
}
