# Barebones Dockerfile syntax for JOE.  Doesn't handle more sophisticated sh syntax.

=Idle
=Command	+Statement +Keyword
=Comment
=Constant
=String		+Constant
=Ident
=Escape
=Brace
=StringEscape	+Escape
=Variable	+DefinedIdent

# Start of line is special
:start Idle
	*		idle
	" \t"		start
	"#"		comment				noeat
	"A-Za-z"	command				buffer noeat
	"\n"		start

# Comments between commands
:comment Comment comment
	*		comment
	"BFHNTX"	comment				noeat call=comment_todo.comment_todo()
	"\n"		start

# Comments in the middle of a command
:comment_idle Comment comment
	*		comment_idle
	"\n"		idle

# Start of line in the middle of "idle" mode (skips command recognition in case a comment
# comes in the middle of a RUN)
:start_idle Idle
	*		idle				noeat
	"#"		comment_idle			recolor=-1

# Generic middle-of-a-command
:idle Idle
	*		idle
	"$"		idle				recolor=-1 call=.variable()
	"\n"		start
	"\\"		escape				recolor=-1

:escape Escape
	*		idle				recolor=-2 noeat
	"\\\""		idle
	"\r"		escape
	"\n"		start_idle

:command Idle
	*		idle				noeat istrings
	"FROM"		from
	"MAINTAINER"	string_command
	"RUN"		list_command
	"CMD"		list_command
	"LABEL"		label
	"EXPOSE"	generic_command
	"ENV"		generic_command
	"ADD"		list_command
	"COPY"		list_command
	"ENTRYPOINT"	list_command
	"VOLUME"	list_command
	"USER"		string_command
	"WORKDIR"	string_command
	"ARG"		generic_command
	"ONBUILD"	generic_command
	"STOPSIGNAL"	generic_command
done
	"a-zA-Z"	command

# EXPOSE, ENV, ARG, ONBUILD, STOPSIGNAL
:generic_command Command
	*		idle

# MAINTAINER, USER, WORKDIR
:string_command Command
	*		string_command_data

:string_command_data Constant
	*		string_command_data
	"$"		string_command_data		recolor=-1 call=.variable()
	"\n"		start

# FROM
:from Command
	*		from_image			noeat

:from_image Constant
	*		from_image
	":@"		from_tag			noeat
	"\n"		start

:from_tag Idle
	*		from_tag
	"\n"		start

# RUN, CMD, ADD, COPY, ENTRYPOINT, VOLUME
:list_command Command
	*		idle				noeat
	" \t"		list_command
	"["		array				noeat
	"\n"		start

:array Idle
	*		array
	"[]"		bracket				noeat
	"\"'"		array				recolor=-1 call=.string() save_c
	"\n"		start

:comma Idle
	*		array				noeat

:bracket Brace
	"]"		idle
	"["		array

# LABEL
:label Command
	*		label_key
	"\n"		start

:label_key Variable
	*		label_key
	"="		label_value			noeat
	"\n"		start

:label_value Constant
	*		label_value
	"\""		label_value			recolor=-1 call=.string() save_c
	"\n"		start

.subr variable

:variable Variable
	*		variable			recolor=-2 return noeat
	"A-Za-z_"	variable_name
	"{"		variable_long

:variable_name Variable
	*		variable_name			return noeat
	"A-Za-z0-9_"	variable_name

:variable_long Variable
	*		variable_long
	&		variable			return noeat
	"\n"		variable			return noeat
	"}"		variable			return
	":"		variable_after

:variable_after Idle
	*		variable_after
	&		variable_after			return noeat
	"}"		variable_long			noeat

.end

.subr string

:string String string
	*		string
	&		string				return
	"\n"		string				return noeat
	"\\"		string_escape			recolor=-1
	"$"		string				recolor=-1 call=.variable()

:string_escape StringEscape string
	*		string

.end
