<?xml version="1.0" encoding="UTF-8"?>
<syntax name="language-root.python">
	<zones>
		<include collection="comments" />
		<include collection="strings" />
		<include collection="item-blocks" />
		<include collection="keywords" />
		<include collection="variables" />
		<include collection="punctuation" />
	</zones>

	<library>
		<!-- Comments -->
		<collection name="comments">
			<zone name="comment.shebang">
				<expression>^(#!).*?\bpython\b.*?$[\n\r]*</expression>
				<capture number="1" name="punctuation.definition.begin"/>
			</zone>
			<zone name="comment.line">
				<starts-with>
					<expression>(#)</expression>
					<capture number="1" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>$[\n\r]*</ends-with>
			</zone>
		</collection>
		
		<!-- Strings -->
		<collection name="strings">
			<zone name="string.long.quoted">
				<starts-with>
					<expression>(?i)(u|b)?('{3})</expression>
					<capture number="1" name="punctuation.modifier"/>
					<capture number="2" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>'{3}</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
				<subzones>
					<include collection="character-escapes" />
				</subzones>
			</zone>
			<zone name="string.long.quoted">
				<starts-with>
					<expression>(?i)(u|b)?("{3})</expression>
					<capture number="1" name="punctuation.modifier"/>
					<capture number="2" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>"{3}</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
				<subzones>
					<include collection="character-escapes" />
				</subzones>
			</zone>
			<zone name="string.quoted">
				<starts-with>
					<expression>(?i)(u|b)?(')</expression>
					<capture number="1" name="punctuation.modifier"/>
					<capture number="2" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>'</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
				<subzones>
					<include collection="character-escapes" />
				</subzones>
			</zone>
			<zone name="string.quoted">
				<starts-with>
					<expression>(?i)(u|b)?(")</expression>
					<capture number="1" name="punctuation.modifier"/>
					<capture number="2" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>"</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
				<subzones>
					<include collection="character-escapes" />
				</subzones>
			</zone>
			<!-- Raw strings; they don't need character escapes -->
			<zone name="string.quoted">
				<starts-with>
					<expression>(?i)((?:u|b)?r)(')</expression>
					<capture number="1" name="punctuation.modifier"/>
					<capture number="2" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>'</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
				<subzones>
					<zone name="constant.character.escape">
						<expression>(\\)'</expression>
						<capture number="1" name="punctuation.escape.backslash"/>
					</zone>
				</subzones>
			</zone>
			<zone name="string.quoted">
				<starts-with>
					<expression>(?i)((?:u|b)?r)(")</expression>
					<capture number="1" name="punctuation.modifier"/>
					<capture number="2" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>"</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
				<subzones>
					<zone name="constant.character.escape">
						<expression>(\\)"</expression>
						<capture number="1" name="punctuation.escape.backslash"/>
					</zone>
				</subzones>
			</zone>
		</collection>
		<collection name="character-escapes">
			<zone name="constant.character.escape">
				<expression>(\\)(x\h{2}|u\h{4}|U\h{8}|N\{[^\}]+\}|[0-2][0-7]{2}|.)</expression>
				<capture number="1" name="punctuation.escape.backslash"/>
			</zone>
		</collection>
		
		<!-- Itemizer blocks -->
		<collection name="item-blocks">
			<!-- Function and class decorators; these precede item blocks and I can't think of anywhere better to put them -->
			<include collection="decorators"/>
			
			<!--
			These must be defined as blocks because Python has no closing delimiters (which makes it impossible to set up hierarchy solely in the itemizers).
			
			THIS IS A NASTY HACK. DO NOT EMULATE IT! It is only necessary in this instance thanks to Python's complete lack of delimiters.
			-->
			<zone name="x-item-block.x-item-body">
				<starts-with>
					<expression>^(?:(class\b|def\b)|((elif|else|finally|for|if|try|except|while)(.*?)(?:(:)(?=\s*(?:$|#))|(\\$))))</expression>
					<capture number="1" name="keyword.control"/>
					<capture number="2" name="x-item-start"/>
					<capture number="3" name="keyword.control"/>
					<capture number="4" name="parameters">
						<subzones>
							<include collection="comments" />
							<include collection="strings" />
							<include collection="keywords" />
							<include collection="variables" />
							<include collection="punctuation" />
						</subzones>
					</capture>
					<capture number="5" name="punctuation.colon"/>
					<capture number="6" name="punctuation.continuation.backslash"/>
				</starts-with>
				<!--
				The item block ends if the next line is not:
				1) More indentation than the starting indent for the zone
				2) Nothing but indentation
				-->
				<ends-with>^(?![ \t]|[ \t]*$)</ends-with>
				<subzones>
					<!-- A bit of zone duplication here, but it's preferable to have the keyword in the class definition (possible in nested items, but not at root without the regex going into an infinite loop) -->
					<zone name="class.definition">
						<starts-with>
							<!-- Of necessity, the keyword unfortunately gets captured by the itemizer block, hence our lookbehind -->
							<expression>(?&lt;=class)[ \t]+([\w\_]+)(\(?)</expression>
							<capture number="1" name="name"/>
							<capture number="2" name="punctuation.brace.curly.open" />
						</starts-with>
						<ends-with>
							<expression>(\)?)(:)(?=\s*(?:$|#))</expression>
							<capture number="1" name="punctuation.brace.curly.close" />
							<capture number="2" name="punctuation.colon" />
						</ends-with>
						<subzones>
							<include collection="comments" />
							<include collection="strings" />
							<include collection="keywords" />
							<include collection="variables" />
							<include collection="punctuation" />
						</subzones>
					</zone>
					<zone name="function.definition">
						<starts-with>
							<expression>(?&lt;=def)[ \t]+([\w\_]+)(\()</expression>
							<capture number="1" name="name"/>
							<capture number="2" name="punctuation.brace.curly.open" />
						</starts-with>
						<ends-with>
							<expression>(\))(:)(?=\s*(?:$|#))</expression>
							<capture number="1" name="punctuation.brace.curly.close" />
							<capture number="2" name="punctuation.colon" />
						</ends-with>
						<subzones>
							<include collection="comments" />
							<include collection="strings" />
							<include collection="keywords" />
							<include collection="variables" />
							<include collection="punctuation" />
						</subzones>
					</zone>
					
					<include collection="nested-blocks" />
				</subzones>
			</zone>
		</collection>
		<collection name="nested-blocks">
			<!-- This pattern of different definitions for root zones vs. nested ones is necessary because if we combine them (with a * instead of a + for the leading whitespace, for instance) the lookahead causes an infinite loop. We can sort of get around this by using a lookbehind for the "class" and "def" keywords, but then we end up needing to capture the leading whitespace as part of the itemized block. Which sucks. -->
			<include collection="decorators"/>
			<zone name="x-item-block">
				<starts-with>
					<expression>^([ \t]+)(?:(?=class\b|def\b)|((elif|else|finally|for|if|try|except|while)\b(.*?)(?:(:)\s*(?=$|#)|(\\$))))</expression>
					<capture number="2" name="x-item-start"/>
					<capture number="3" name="keyword.control"/>
					<capture number="4" name="parameters">
						<subzones>
							<include collection="comments" />
							<include collection="strings" />
							<include collection="keywords" />
							<include collection="variables" />
							<include collection="punctuation" />
						</subzones>
					</capture>
					<capture number="5" name="punctuation.colon"/>
					<capture number="6" name="punctuation.continuation.backslash"/>
				</starts-with>
				<ends-with>^(?!\1[ \t]|[ \t]*$)</ends-with>
				<subzones name="x-item-body">
					<!-- These definition zones allow for multiline parameter lists -->
					<zone name="class.definition">
						<starts-with>
							<expression>(class)[ \t]+([\w\_]+)(\(?)</expression>
							<capture number="1" name="keyword.control"/>
							<capture number="2" name="name"/>
							<capture number="3" name="punctuation.brace.curly.open" />
						</starts-with>
						<ends-with>
							<expression>(\)?)(:)(?=\s*(?:$|#))</expression>
							<capture number="1" name="punctuation.brace.curly.close" />
							<capture number="2" name="punctuation.colon" />
						</ends-with>
						<subzones>
							<include collection="comments" />
							<include collection="strings" />
							<include collection="keywords" />
							<include collection="variables" />
							<include collection="punctuation" />
						</subzones>
					</zone>
					<zone name="function.definition">
						<starts-with>
							<expression>(def)[ \t]+([\w\_]+)(\()</expression>
							<capture number="1" name="keyword.control"/>
							<capture number="2" name="name"/>
							<capture number="3" name="punctuation.brace.curly.open" />
						</starts-with>
						<ends-with>
							<expression>(\))(:)(?=\s*(?:$|#))</expression>
							<capture number="1" name="punctuation.brace.curly.close" />
							<capture number="2" name="punctuation.colon" />
						</ends-with>
						<subzones>
							<include collection="comments" />
							<include collection="strings" />
							<include collection="keywords" />
							<include collection="variables" />
							<include collection="punctuation" />
						</subzones>
					</zone>
					<include collection="nested-blocks" />
				</subzones>
			</zone>
			
			<include collection="comments" />
			<include collection="strings" />
			<include collection="keywords" />
			<include collection="variables" />
			<include collection="punctuation" />
		</collection>
		<collection name="decorators">
			<zone name="meta.decorator">
				<expression>((@)[\w_]+).*$</expression>
				<capture number="1" name="name"/>
				<capture number="2" name="punctuation.definition.at-symbol"/>
			</zone>
		</collection>
		
		<!-- Keywords, constants, and operators -->
		<collection name="keywords">
			<zone>
				<expression>\b(?:(as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|if|import|lambda|pass|print|print|raise|return|try|while|with|yield)|(and|in|is|not|or)|(super|self)|(True)|(False)|(None)|(0[oO]?[0-7]+[lL]?|0[xX][0-9a-fA-F]+[lL]?|0[bB][01]+|(?:(?:(?:[0-9]+)?\.[0-9]+(?:[eE]-?[0-9]+)?)|(?:[0-9]+[eE]-?[0-9]+))[jJ]?|[0-9]+[lL]?))\b|(\+=|-=|\*\*=|\*=|//=|/=|%=|&amp;=|\|=|\^=|>>=|&lt;&lt;=|\+|-|\*\*|\*|//|/|%|&lt;&lt;|>>|==|!=|&lt;>|>=|>|&lt;=|&lt;|=|&amp;|\||\^|~)</expression>
				<capture number="1" name="keyword.control"/>
				<capture number="2" name="keyword.operator.comparison"/>
				<capture number="3" name="keyword.variable.language"/>
				<capture number="4" name="constant.language.boolean.true"/>
				<capture number="5" name="constant.language.boolean.false"/>
				<capture number="6" name="constant.language.null"/>
				<capture number="7" name="constant.numeric"/>
				<capture number="8" name="operator"/>
			</zone>
		</collection>
		
		<!-- Variables -->
		<collection name="variables">
			<!--Function Invocation-->
			<zone>
				<expression>(\.)([a-zA-Z0-9_]+)\s*(\()|([a-zA-Z0-9_]+)\s*(\()|(\.)([a-zA-Z0-9_]+)|([a-zA-Z0-9_]+)</expression>
				<!-- Method function -->
				<capture number="1" name="punctuation.delimiter.period"/>
				<capture number="2" name="variable.function.method"/>
				<capture number="3" name="punctuation.brace.round.open"/>
				<!-- Normal function -->
				<capture number="4" name="variable.function"/>
				<capture number="5" name="punctuation.brace.round.open"/>
				<!-- Property -->
				<capture number="6" name="punctuation.delimiter.period"/>
				<capture number="7" name="variable.property"/>
				<!-- Variable -->
				<capture number="8" name="variable"/>
			</zone>
		</collection>
		
		<!--Punctuation-->
		<collection name="punctuation">
			<zone>
				<expression>(,|:|\.|;)|(\\$)|(\()|(\))|(\{)|(\})|(\[)|(\])</expression>
				<capture number="1" name="punctuation"/>
				<capture number="2" name="punctuation.continuation.backslash"/>
				<capture number="3" name="punctuation.brace.round.open"/>
				<capture number="4" name="punctuation.brace.round.close"/>
				<capture number="5" name="punctuation.brace.curly.open"/>
				<capture number="6" name="punctuation.brace.curly.close"/>
				<capture number="7" name="punctuation.brace.square.open"/>
				<capture number="8" name="punctuation.brace.square.close"/>
			</zone>
		</collection>
	</library>
</syntax>
