name: "Lex"
scopeName: "source.lex"
fileTypes: ["l", "lex", "flex"]
patterns: [include: "#main"]
firstLineMatch: """(?ix)

	# Emacs modeline
	-\\*-(?:\\s*(?=[^:;\\s]+\\s*-\\*-)|(?:.*?[;\\s]|(?<=-\\*-))mode\\s*:\\s*)
		f?lex
	(?=[\\s;]|(?<![-*])-\\*-).*?-\\*-
	
	|
		
	# Vim modeline
	(?:(?:\\s|^)vi(?:m[<=>]?\\d+|m)?|\\sex)(?=:(?=\\s*set?\\s[^\\n:]+:)|:(?!\\s* set?\\s))(?:(?:\\s|\\s*:\\s*)\\w*(?:\\s*=(?:[^\\n\\\\\\s]|\\\\.)*)?)*[\\s:](?:filetype|ft|syntax)\\s*=
		f?lex
	(?=\\s|:|$)
"""

repository:
	main:
		patterns: [
			{include: "#jflex"}
			{include: "#comments"}
			{include: "#definitions"}
			{include: "#rules"}
			{include: "source.cpp"}
		]
	
	
	comments:
		patterns: [{
			# Multi-line comment regions
			name:  "comment.block.lex"
			begin: "/\\*"
			end:   "\\*/"
			beginCaptures: 0: name: "punctuation.definition.begin.comment.lex"
			endCaptures:   0: name: "punctuation.definition.end.comment.lex"
		},{
			# Single-line comments (C++ and Java only)
			name:  "comment.line.double-slash.lex"
			begin: "//"
			end:   "(?=$)"
			beginCaptures:
				0: name: "punctuation.definition.comment.lex"
		}]


	# Initial grammar section
	definitions:
		name:  "meta.definitions.lex"
		begin: "\\A(?!\\s*%%)"
		end:   "^(?=\\s*(?:%%|(?:package|import)\\s+\\w))"
		patterns: [
			{include: "#comments"}
			{include: "#directives"}
			{include: "#passthrough"}
			{include: "#definition"}
		]
	
	# Individual definition
	definition:
		name:  "meta.definition.lex"
		begin: "^\\s*([A-Za-z_][A-Za-z0-9_-]*)"
		end:   "$"
		beginCaptures:
			1: name: "entity.name.definition.lex"
		patterns: [{
			name:  "meta.pattern.lex"
			match: "(?<=\\s)\\S.*"
			captures:
				0: patterns: [include: "source.lex.regexp"]
		}]
	
	
	# Hack for JFlex grammars (Java-flavoured Lex)
	jflex:
		name:  "meta.jflex.lex"
		begin: "^(?=\\s*(?:package|import)\\s+\\w)"
		end:   "(?=A)B" # Swallow whole document
		patterns: [include: "source.jflex"]
	
	
	# Directives of the form `%option', etc
	directives:
		name:  "meta.directive.lex"
		begin: "^\\s*((%)\\w+)(?=\\s|$)"
		end:   "(?=$)"
		captures:
			1: name: "keyword.control.directive.lex"
			2: name: "punctuation.definition.directive.lex"
		patterns: [
			{include: "#comments"}
			{match: "\\S+", name: "constant.language.other.lex"}
		]
	
	
	# Chunk of text copied verbatim to output
	passthrough:
		name:  "meta.code-chunk.lex"
		begin: "^%{"
		end:   "^%}"
		beginCaptures: 0: name: "punctuation.section.embedded.begin.lex"
		endCaptures:   0: name: "punctuation.section.embedded.end.lex"
		patterns: [include: "source.cpp"]
	
	
	# Second grammar section
	rules:
		begin: "^\\s*(%%)\\s*(?:$\\s*|(?=/\\*))"
		end:   "^\\s*(%%)\\s*(?:$\\s*|(?=/\\*))"
		beginCaptures: 1: name: "keyword.control.section.begin.lex"
		endCaptures:   1: name: "keyword.control.section.end.lex"
		patterns: [
			{include: "#passthrough"}
			{include: "#rule.pattern"}
			{include: "#rule.action"}
		]

	"rule.pattern":
		name:  "meta.pattern.lex"
		begin: "(?<=^|\\n)(?=\\S)"
		end:   "(?=\\s|$)"
		patterns: [include: "source.lex.regexp"]
	
	# Wrapper for embedded C/C++ blocks.
	# Patterns are handled carefully to avoid runaway issues.
	"rule.action":
		name:  "meta.action.lex"
		begin: "(?<!^)(?=\\S)"
		end:   "(?=\\s*$|^)"
		patterns: [{
			include: "#comments"
		},{
			# { Block }
			begin: "(?={)"
			end:   "(?<=})"
			patterns: [include: "source.cpp"]
		},{
			# Plain C string (one-line only)
			match: "([^{\\s][^{]*?)\\s*$"
			captures:
				1: patterns: [include: "source.cpp"]
		}]


	# Arbitrary code tacked onto the end of the grammar
	"user-code":
		name:  "meta.user-code.lex"
		begin: "(?<=^%%|\\s%%)"
		end:   "(?=A)B" # Remainder of document
		contentName: "source.embedded.cpp"
		patterns: [include: "source.cpp"]
