-- lx syntax
local syntax = require("core.syntax")
local patterns = require("core.syntax.patterns")
local quotes = require("core.quotes")

syntax.add({
	name = "Perl Script",
	shortname = "Perl",
	author = "liqube",

	extensions = {
		"pl",
		"pm",
		"t",
		"pod",
		"cgi",
		"psgi",
	},

	headers = {
		"^#!.*[ /]perl",
	},

	comment = "#",

	patterns = {
		patterns.shebang_line(),

		-- POD block that starts at line start
		{ pattern = { "^=%w[^\n]*\n", "\n=cut[^\n]*\n?" }, type = "comment" },

		-- Line comments
		{ pattern = "#.-\n", type = "comment" },

		-- Substitution regex with slash delimiters
		{ pattern = "s/.-/.-/[a-z]*", type = "string" },

		-- Match regex with slash delimiters
		{ pattern = "m/.-/[a-z]*", type = "string" },

		-- Bare slash regex after =~
		{ pattern = "/.-/[a-z]*", type = "string" },

		-- Quoted strings
		{ pattern = { '"', '"', "\\" }, type = "string" },
		{ pattern = { "'", "'", "\\" }, type = "string" },

		-- Match regex with slash delimiters
		{ pattern = { "m/", "/", "\\" }, type = "string" },

		-- Quote regex with slash delimiters
		{ pattern = { "qr/", "/", "\\" }, type = "string" },

		-- Backtick command strings
		{ pattern = { "`", "`", "\\" }, type = "string" },

		-- Common q-style strings
		{ pattern = { "q%(", "%)", "\\" }, type = "string" },
		{ pattern = { "q%[", "%]", "\\" }, type = "string" },
		{ pattern = { "q%{", "%}", "\\" }, type = "string" },
		{ pattern = { "q%<", "%>", "\\" }, type = "string" },
		{ pattern = { "q/", "/", "\\" }, type = "string" },

		-- Common qq-style strings
		{ pattern = { "qq%(", "%)", "\\" }, type = "string" },
		{ pattern = { "qq%[", "%]", "\\" }, type = "string" },
		{ pattern = { "qq%{", "%}", "\\" }, type = "string" },
		{ pattern = { "qq%<", "%>", "\\" }, type = "string" },
		{ pattern = { "qq/", "/", "\\" }, type = "string" },

		-- Word-list strings
		{ pattern = { "qw%(", "%)", "\\" }, type = "string" },
		{ pattern = { "qw%[", "%]", "\\" }, type = "string" },
		{ pattern = { "qw%{", "%}", "\\" }, type = "string" },
		{ pattern = { "qw%<", "%>", "\\" }, type = "string" },
		{ pattern = { "qw/", "/", "\\" }, type = "string" },

		-- Transliteration-like forms, treated broadly as strings
		{ pattern = { "tr%(", "%)", "\\" }, type = "string" },
		{ pattern = { "tr%[", "%]", "\\" }, type = "string" },
		{ pattern = { "tr%{", "%}", "\\" }, type = "string" },
		{ pattern = { "tr%<", "%>", "\\" }, type = "string" },
		{ pattern = { "tr/", "/", "\\" }, type = "string" },

		-- y/// alias forms, treated broadly as strings
		{ pattern = { "y%(", "%)", "\\" }, type = "string" },
		{ pattern = { "y%[", "%]", "\\" }, type = "string" },
		{ pattern = { "y%{", "%}", "\\" }, type = "string" },
		{ pattern = { "y%<", "%>", "\\" }, type = "string" },
		{ pattern = { "y/", "/", "\\" }, type = "string" },

		-- Sub declaration name
		{
			pattern = "(sub)(%s+)([%a_][%w_]*)",
			type = { "keyword", "normal", "function" },
		},

		-- Package declaration name
		{
			pattern = "(package)(%s+)([%a_][%w_:]*)",
			type = { "keyword", "normal", "keyword2" },
		},

		-- Use and no module names
		{
			pattern = "(use)(%s+)([%a_][%w_:]*)",
			type = { "keyword", "normal", "keyword2" },
		},
		{
			pattern = "(no)(%s+)([%a_][%w_:]*)",
			type = { "keyword", "normal", "keyword2" },
		},

		-- Perl dereference head with repeated sigils
		{
			pattern = "([%$@%%%*][%$@%%%*]+)([%a_][%w_]*)",
			type = { "operator", "variable" },
		},

		-- Perl scalar variables
		{ pattern = "%$[%a_][%w_]*", type = "variable" },

		-- Perl array variables
		{ pattern = "@[%a_][%w_]*", type = "variable" },

		-- Perl hash variables
		{ pattern = "%%[%a_][%w_]*", type = "variable" },

		-- Perl typeglob variables
		{ pattern = "%*[%a_][%w_]*", type = "variable" },

		-- Perl special variables with punctuation
		{ pattern = "%$[%d%*%#%?%!%$%-%^%&%+%./,:;@<=>%[%]_%|~`]", type = "keyword2" },
		{ pattern = "@[%d%*]", type = "keyword2" },
		{ pattern = "%%[%d%*]", type = "keyword2" },

		-- Namespaced identifiers
		{ pattern = "[%a_][%w_]*::[%a_][%w_:]*", type = "keyword2" },

		-- Hex numbers
		{ pattern = "0[xX][%da-fA-F]+", type = "hex" },

		-- Binary numbers
		{ pattern = "0[bB][01]+", type = "number" },

		-- Octal numbers
		{ pattern = "0[0-7]+", type = "number" },

		-- Decimal numbers with optional exponent
		{ pattern = "-?%d+%.%d+([eE][%+%-]?%d+)?", type = "number" },
		{ pattern = "-?%d+[eE][%+%-]?%d+", type = "number" },
		{ pattern = "-?%.%d+([eE][%+%-]?%d+)?", type = "number" },
		{ pattern = "-?%d+", type = "number" },

		-- Function calls
		{ pattern = "[%a_][%w_]*%f[(]", type = "function" },

		-- Arrow dereference
		{ pattern = "%-%>", type = "operator" },

		-- Double colon package separator
		{ pattern = "::", type = "operator" },

		-- Compound comparison operators
		{ pattern = "[!=<>]=", type = "operator" },

		-- Repeated symbolic operators
		{ pattern = "%*%*", type = "operator" },
		{ pattern = "%.%.*", type = "operator" },
		{ pattern = "%|%|", type = "operator" },
		{ pattern = "&&", type = "operator" },
		{ pattern = "<<", type = "operator" },
		{ pattern = ">>", type = "operator" },
		{ pattern = "%+%+", type = "operator" },
		{ pattern = "%-%-", type = "operator" },

		-- Single-character operators and punctuation
		{ pattern = "[%+%-=/%*%^%%<>!~|&%?%.:;,()%[%]{}]", type = "operator" },

		-- Generic identifiers
		{ pattern = "[%a_][%w_]*", type = "symbol" },
	},

	outline_patterns = {
		-- Package declaration
		{ pattern = "%s*package%s+[%a_][%w_:]*", line_start = true },

		-- Named sub declaration
		{ pattern = "%s*sub%s+[%a_][%w_]*", line_start = true },
	},

	quotes = {
		primary = "double",
		secondary = "single",
		profiles = {
			double = quotes.profile.c_style_double(),
			single = quotes.profile.c_style_single(),
		},
	},

	symbols = {
		-- Control flow
		["if"] = "control",
		["elsif"] = "control",
		["else"] = "control",
		["unless"] = "control",
		["while"] = "control",
		["until"] = "control",
		["for"] = "control",
		["foreach"] = "control",
		["given"] = "control",
		["when"] = "control",
		["continue"] = "control",
		["last"] = "control",
		["next"] = "control",
		["redo"] = "control",
		["goto"] = "control",
		["return"] = "control",

		-- Declarations and structure
		["sub"] = "keyword",
		["package"] = "keyword",
		["use"] = "keyword",
		["no"] = "keyword",
		["require"] = "keyword",
		["my"] = "keyword",
		["our"] = "keyword",
		["local"] = "keyword",
		["state"] = "keyword",
		["format"] = "keyword",

		-- Exception and eval
		["eval"] = "keyword",
		["die"] = "keyword",
		["warn"] = "keyword",

		-- Logic words
		["and"] = "keyword",
		["or"] = "keyword",
		["not"] = "keyword",
		["xor"] = "keyword",

		-- String comparison words
		["eq"] = "operator",
		["ne"] = "operator",
		["lt"] = "operator",
		["gt"] = "operator",
		["le"] = "operator",
		["ge"] = "operator",
		["cmp"] = "operator",

		-- Literals and common special values
		["undef"] = "literal",
		["__FILE__"] = "literal",
		["__LINE__"] = "literal",
		["__PACKAGE__"] = "literal",
		["__SUB__"] = "literal",

		-- Special modules and handles
		["strict"] = "keyword2",
		["warnings"] = "keyword2",
		["STDIN"] = "keyword2",
		["STDOUT"] = "keyword2",
		["STDERR"] = "keyword2",
		["ARGV"] = "keyword2",
		["ARGVOUT"] = "keyword2",

		-- Common Perl builtins
		["abs"] = "keyword",
		["bless"] = "keyword",
		["caller"] = "keyword",
		["chdir"] = "keyword",
		["chomp"] = "keyword",
		["chop"] = "keyword",
		["close"] = "keyword",
		["closedir"] = "keyword",
		["defined"] = "keyword",
		["delete"] = "keyword",
		["each"] = "keyword",
		["exists"] = "keyword",
		["exit"] = "keyword",
		["grep"] = "keyword",
		["join"] = "keyword",
		["keys"] = "keyword",
		["map"] = "keyword",
		["open"] = "keyword",
		["opendir"] = "keyword",
		["pop"] = "keyword",
		["print"] = "keyword",
		["printf"] = "keyword",
		["push"] = "keyword",
		["read"] = "keyword",
		["readdir"] = "keyword",
		["ref"] = "keyword",
		["reverse"] = "keyword",
		["say"] = "keyword",
		["scalar"] = "keyword",
		["seek"] = "keyword",
		["select"] = "keyword",
		["shift"] = "keyword",
		["sort"] = "keyword",
		["split"] = "keyword",
		["splice"] = "keyword",
		["sprintf"] = "keyword",
		["substr"] = "keyword",
		["system"] = "keyword",
		["tie"] = "keyword",
		["tied"] = "keyword",
		["time"] = "keyword",
		["unlink"] = "keyword",
		["unpack"] = "keyword",
		["unshift"] = "keyword",
		["untie"] = "keyword",
		["values"] = "keyword",
	},
})
