ass_line    = (ass_chunk / plain_text)*
plain_text  = ~'[^{}]+'
ass_chunk   = '{' (ass_tag / ass_comment)+ '}'
ass_comment = ~'(([^{}\\\\]*\\\\[Nnh\\\\])+[^{}\\\\]*)|[^{}\\\\]+'

ass_tag = (
    ass_tag_italics
    / ass_tag_bold
    / ass_tag_underline
    / ass_tag_strikeout
    / ass_tag_border
    / ass_tag_border_x
    / ass_tag_border_y
    / ass_tag_shadow
    / ass_tag_shadow_x
    / ass_tag_shadow_y
    / ass_tag_blur_edges
    / ass_tag_blur_edges_gauss
    / ass_tag_font_name
    / ass_tag_font_encoding
    / ass_tag_font_size
    / ass_tag_font_scale_x
    / ass_tag_font_scale_y
    / ass_tag_letter_spacing
    / ass_tag_rotation_x
    / ass_tag_rotation_y
    / ass_tag_rotation_z
    / ass_tag_shear_x
    / ass_tag_shear_y
    / ass_tag_color_primary
    / ass_tag_color_secondary
    / ass_tag_color_border
    / ass_tag_color_shadow
    / ass_tag_alpha_all
    / ass_tag_alpha_primary
    / ass_tag_alpha_secondary
    / ass_tag_alpha_border
    / ass_tag_alpha_shadow
    / ass_tag_alignment
    / ass_tag_alignment_legacy
    / ass_tag_karaoke_1
    / ass_tag_karaoke_2
    / ass_tag_karaoke_3
    / ass_tag_karaoke_4
    / ass_tag_wrap_style
    / ass_tag_reset_style
    / ass_tag_position
    / ass_tag_movement
    / ass_tag_rotation_origin
    / ass_tag_fade_simple
    / ass_tag_fade_complex
    / ass_tag_animation
    / ass_tag_clip_rectangle
    / ass_tag_clip_vector
    / ass_tag_drawing_mode
    / ass_tag_baseline_offset)

ass_tag_animable = (
    ass_tag_border
    / ass_tag_border_x
    / ass_tag_border_y
    / ass_tag_shadow
    / ass_tag_shadow_x
    / ass_tag_shadow_y
    / ass_tag_blur_edges
    / ass_tag_blur_edges_gauss
    / ass_tag_font_size
    / ass_tag_font_scale_x
    / ass_tag_font_scale_y
    / ass_tag_letter_spacing
    / ass_tag_rotation_x
    / ass_tag_rotation_y
    / ass_tag_rotation_z
    / ass_tag_shear_x
    / ass_tag_shear_y
    / ass_tag_color_primary
    / ass_tag_color_secondary
    / ass_tag_color_border
    / ass_tag_color_shadow
    / ass_tag_alpha_all
    / ass_tag_alpha_primary
    / ass_tag_alpha_secondary
    / ass_tag_alpha_border
    / ass_tag_alpha_shadow
    / ass_tag_clip_rectangle)

ass_text         = ~'[^{}()\\\\]+'
boolean          = ~'[0-1](?!\\d)'
integer          = ~'-?\\d+'
integer_positive = ~'\\d+'
float            = ~'-?\\d+(\\.\\d+)?'
float_positive   = ~'\\d+(\\.\\d+)?'
byte_value_int   = ~'25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9]'
byte_value_hex   = ~'[0-9A-Fa-f][0-9A-Fa-f]'
pos              = integer
duration_cs      = integer_positive
duration_ms      = integer_positive
color_value      = '&H' byte_value_hex byte_value_hex byte_value_hex '&'
alpha_value      = '&H' byte_value_hex '&'

ass_tag_italics   = '\\i' boolean
ass_tag_bold      = '\\b' (boolean / integer_positive)
ass_tag_underline = '\\u' boolean
ass_tag_strikeout = '\\s' boolean

ass_tag_border   = '\\bord' float_positive
ass_tag_border_x = '\\xbord' float_positive
ass_tag_border_y = '\\ybord' float_positive
ass_tag_shadow   = '\\shad' float_positive
ass_tag_shadow_x = '\\xshad' float_positive
ass_tag_shadow_y = '\\yshad' float_positive

ass_tag_blur_edges       = '\\be' integer_positive
ass_tag_blur_edges_gauss = '\\blur' float_positive

ass_tag_font_name      = ('\\fn(' ass_text ')') / ('\\fn' ass_text)
ass_tag_font_encoding  = '\\fe' integer_positive
ass_tag_font_size      = '\\fs' integer_positive
ass_tag_font_scale_x   = '\\fscx' float_positive
ass_tag_font_scale_y   = '\\fscy' float_positive
ass_tag_letter_spacing = '\\fsp' float

ass_tag_rotation_x      = '\\frx' float
ass_tag_rotation_y      = '\\fry' float
ass_tag_rotation_z      = ('\\frz' float) / ('\\fr' float)
ass_tag_rotation_origin = '\\org(' pos ',' pos ')'
ass_tag_shear_x         = '\\fax' float
ass_tag_shear_y         = '\\fay' float

ass_tag_color_primary   = ('\\1c' / '\\c') color_value
ass_tag_color_secondary = '\\2c' color_value
ass_tag_color_border    = '\\3c' color_value
ass_tag_color_shadow    = '\\4c' color_value

ass_tag_alpha_all       = '\\alpha' alpha_value
ass_tag_alpha_primary   = '\\1a' alpha_value
ass_tag_alpha_secondary = '\\2a' alpha_value
ass_tag_alpha_border    = '\\3a' alpha_value
ass_tag_alpha_shadow    = '\\4a' alpha_value

ass_tag_karaoke_1 = '\\k' duration_cs
ass_tag_karaoke_2 = '\\K' duration_cs
ass_tag_karaoke_3 = '\\kf' duration_cs
ass_tag_karaoke_4 = '\\ko' duration_cs

ass_tag_alignment        = '\\an' integer_positive
ass_tag_alignment_legacy = '\\a' integer_positive
ass_tag_wrap_style       = '\\q' ('0' / '1' / '2' / '3')
ass_tag_reset_style      = '\\r' ass_text?

ass_tag_position = '\\pos(' pos ',' pos ')'
ass_tag_movement =
    '\\move(' pos ',' pos ',' pos ',' pos (',' duration_ms ',' duration_ms)? ')'

ass_tag_fade_simple  = '\\fad(' duration_ms ',' duration_ms ')'
ass_tag_fade_complex =
    '\\fade('
    byte_value_int ',' byte_value_int ',' byte_value_int ','
    duration_ms ',' duration_ms ',' duration_ms ',' duration_ms ')'

ass_tag_animation =
    '\\t('
    (duration_ms ',' duration_ms ',')?
    (float ',')?
    (ass_tag_animable+)
    ')'

ass_tag_clip_rectangle  =
    ('\\clip' / '\\iclip')
    '(' pos ','  pos ',' pos ',' pos ')'
ass_tag_clip_vector =
    ('\\clip' / '\\iclip')
    '(' (float ',')? ass_text ')'

ass_tag_drawing_mode    = '\\p' integer_positive
ass_tag_baseline_offset = '\\pbo' integer
