-- lx format

local format = require("core.format")
local quotes = require("core.text.quotes")

format.register({
	name = "Cmajor Source",
	shortname = "Cmajor",
	author = "liqube",

	extensions = {
		"cmajor",
	},

	headers = {
		"^%s*processor%s+[%a][%w_]*",
		"^%s*graph%s+[%a][%w_]*",
		"^%s*namespace%s+[%a][%w_:]*",
	},

	comment = "//",

	patterns = {
		-- Highlight long comment separators as function-style headers
		{ pattern = "%s*//%-%-%-%-%-%-%-%-+%s*\n", type = "separator", line_start = true },
		{ pattern = "%s*//========+%s*\n", type = "separator", line_start = true },
		{ pattern = "%s*//////////+%s*\n", type = "separator", line_start = true },

		-- Comments
		{ pattern = "//.-\n", type = "comment" },
		{ pattern = { "/%*", "%*/" }, type = "comment" },

		-- Annotations: [[ main ]] or [[ name: "gain", min: 0.0, max: 1.0 ]]
		{ pattern = { "%[%[", "%]%]" }, type = "keyword" },

		-- Tokenize quote delimiters as operators (same behavior used in JSON)
		{ pattern = { '"', '"', "\\" }, type = "string", delim_type = "operator" },

		-- Namespace qualifiers, including the built-in std namespace
		{ pattern = "([%a][%w_]*)(::)", type = { "keyword2", "operator" } },

		-- Built-in processor properties
		{ pattern = "(processor)(%.)(frequency)", type = { "keyword2", "operator", "literal" } },
		{ pattern = "(processor)(%.)(period)", type = { "keyword2", "operator", "literal" } },
		{ pattern = "(processor)(%.)(id)", type = { "keyword2", "operator", "literal" } },
		{ pattern = "(processor)(%.)(session)", type = { "keyword2", "operator", "literal" } },
		{ pattern = "(processor)(%.)(maxFrequency)", type = { "keyword2", "operator", "literal" } },
		{ pattern = "(processor)(%.)(maxBlockSize)", type = { "keyword2", "operator", "literal" } },
		{ pattern = "(processor)(%.)(eventBufferSize)", type = { "keyword2", "operator", "literal" } },
		{ pattern = "(processor)(%.)(debug)", type = { "keyword2", "operator", "literal" } },
		{ pattern = "(processor)(%.)(latency)", type = { "keyword2", "operator", "literal" } },

		-- Directional data-flow operators are important in Cmajor graphs/processors
		{ pattern = "<%-", type = "operator" },
		{ pattern = "%-%>", type = "operator" },
		{ pattern = "%*%*", type = "operator" },

		-- Numeric literals. Cmajor suffixes such as f, f32, f64, i64, L and
		-- imaginary suffixes are kept in the same token when directly attached.
		-- The language also allows whitespace before some suffixes; in that case
		-- the number and suffix are highlighted separately to avoid swallowing
		-- ordinary following identifiers.
		{ pattern = "0x%x+[%a%d_]*", type = "number" },
		{ pattern = "0b[01]+[%a%d_]*", type = "number" },
		{ pattern = "%d+%.%d*[eE][%+%-]%d+[%a%d_]*", type = "number" },
		{ pattern = "%d+%.%d*[eE]%d+[%a%d_]*", type = "number" },
		{ pattern = "%d+%.%d*[%a%d_]*", type = "number" },
		{ pattern = "%.%d+[eE][%+%-]%d+[%a%d_]*", type = "number" },
		{ pattern = "%.%d+[eE]%d+[%a%d_]*", type = "number" },
		{ pattern = "%.%d+[%a%d_]*", type = "number" },
		{ pattern = "%d+[%a%d_]*", type = "number" },

		-- Labels used by break/continue targets
		{ pattern = "^%s*([%a][%w_]*)(:)%s*", type = { "symbol", "operator" }, line_start = true },

		-- Broad delimiter/operator tokenization for Cmajor punctuation
		{ pattern = "[%+%-=/%*%^%%<>!~|&%?%:%.,;%(%)%[%]{}]", type = "operator" },

		-- Function-like calls/declarations. Put after keywords/special forms, before plain symbols.
		{ pattern = "[%a][%w_]*%f[(]", type = "function" },
		{ pattern = "[%a][%w_]*", type = "symbol" },
	},

	outline_patterns = {
		-- Top-level and nested containers
		{ pattern = "%s*namespace%s+[%a][%w_:]*", line_start = true },
		{ pattern = "%s*processor%s+[%a][%w_]*", line_start = true },
		{ pattern = "%s*graph%s+[%a][%w_]*", line_start = true },
		{ pattern = "%s*struct%s+[%a][%w_]*", line_start = true },
		{ pattern = "%s*enum%s+[%a][%w_]*", line_start = true },
		{ pattern = "%s*using%s+[%a][%w_]*%s*=", line_start = true },

		-- Graph/processor endpoint and node declarations
		{ pattern = "%s*input%s+.+;%s*$", line_start = true, dividers = false, jumps = false },
		{ pattern = "%s*output%s+.+;%s*$", line_start = true, dividers = false, jumps = false },
		{ pattern = "%s*node%s+.+;%s*$", line_start = true, dividers = false, jumps = false },
		{ pattern = "%s*connection%s+.+;%s*$", line_start = true, dividers = false, jumps = false },

		-- Event handlers and ordinary function definitions/declarations
		{ pattern = "%s*event%s+[%a][%w_]*%s*%b().*$", line_start = true },
		{ pattern = "%s*[%a][%w_:<>%[%],%s&]-[%s&]+[%a][%w_]*%s*%b().*$", line_start = true },
		{ pattern = "%s*[%a][%w_:<>%[%],%s&]-[%s&]+[%a][%w_]*%s*%([^%)]*$", line_start = true },
	},

	block_comment = {
		block_open = "/*",
		block_close = "*/",
		block_line_prefix = " * ",
		close_line_prefix = " ",
		open_on_own_line = false,
		close_on_own_line = true,
		strip_line_prefix = "^%s*%*%s*",
		allow_nested = false,
	},

	guard_comment = {
		guard_open = "/* if false",
		guard_close = "*/",
		guard_align_to_indent = false,
		allow_nested = false,
	},

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

	symbols = {
		-- Control flow
		["break"] = "control",
		["case"] = "keyword2",
		["continue"] = "control",
		["default"] = "keyword",
		["do"] = "keyword",
		["else"] = "keyword",
		["for"] = "keyword",
		["if"] = "keyword",
		["loop"] = "keyword",
		["return"] = "control",
		["switch"] = "keyword",
		["while"] = "keyword",

		-- Error handling / reserved future constructs
		["catch"] = "keyword",
		["throw"] = "keyword",
		["try"] = "keyword",

		-- Declarations and structure
		["connection"] = "keyword2",
		["enum"] = "keyword2",
		["event"] = "keyword2",
		["external"] = "keyword",
		["graph"] = "keyword2",
		["import"] = "keyword",
		["input"] = "keyword2",
		["let"] = "keyword",
		["namespace"] = "keyword2",
		["node"] = "keyword2",
		["output"] = "keyword2",
		["processor"] = "keyword2",
		["struct"] = "keyword2",
		["using"] = "keyword",
		["var"] = "keyword",

		-- Endpoint kinds
		["stream"] = "keyword",
		["value"] = "keyword",

		-- Qualifiers / access / generics
		["const"] = "keyword",
		["fixed"] = "keyword",
		["operator"] = "keyword",
		["private"] = "keyword",
		["public"] = "keyword",

		-- Primitive and built-in types
		["bool"] = "keyword2",
		["clamp"] = "keyword2",
		["complex"] = "keyword2",
		["complex32"] = "keyword2",
		["complex64"] = "keyword2",
		["double"] = "keyword2",
		["float"] = "keyword2",
		["float32"] = "keyword2",
		["float64"] = "keyword2",
		["int"] = "keyword2",
		["int32"] = "keyword2",
		["int64"] = "keyword2",
		["string"] = "keyword2",
		["void"] = "keyword2",
		["wrap"] = "keyword2",

		-- Literals and built-in constants
		["false"] = "literal",
		["true"] = "literal",
		["nan"] = "literal",
		["inf"] = "literal",
		["pi"] = "literal",
		["twoPi"] = "literal",

		-- Built-in endpoints/functions/properties commonly used like language features
		["advance"] = "function",
		["console"] = "literal",
		["main"] = "function",
		["init"] = "function",
		["latency"] = "literal",

		-- Type trait pseudo-properties used in generic code
		["primitiveType"] = "literal",
		["isStruct"] = "literal",
		["isArray"] = "literal",
		["isFloat"] = "literal",
		["isFloat32"] = "literal",
		["isFloat64"] = "literal",
		["isInt"] = "literal",
		["isInt32"] = "literal",
		["isInt64"] = "literal",
		["isScalar"] = "literal",
		["isString"] = "literal",
		["isBool"] = "literal",
		["isComplex"] = "literal",
		["isReference"] = "literal",
		["isConst"] = "literal",
	},
})
