# Reduce the number of characters to switch on alias alpha : [a-zA-Z] alias num : [0-9] alias sp : [ \t] alias nl : [\r\n\u2028\u2029] @public var attrib_name: union handler: 'onload', 'onunload', 'onclick', 'ondblclick', 'onmousedown', 'onmouseup', 'onmouseover', 'onmousemove', 'onmouseout', 'onfocus', 'onblur', 'onkeypress', 'onkeydown', 'onkeyup', 'onsubmit', 'onreset', 'onselect', 'onchange', 'onresize' 'style' @start_state @valid_end @public pcdata: '<': tag_start tag_start: '?': app_dir '!': lt_bang alpha: tag_name, record(tag_name) '/': close_tag_start else as pcdata app_dir: '?': app_dir_qm app_dir_qm: '>': pcdata else as app_dir lt_bang: '-': html_start_comment alpha: directive else: error("': pcdata else: error("-- in comment") directive: '"': directive_dq '\'': directive_sq '>': pcdata directive_dq: '"': directive directive_sq: '\'': directive close_tag_start: alpha: tag_name # no need to record name for close tags else: error("expected letter after ' as end_tag, store(tag_name, 'i') else: error def end_tag(tag_name): 'xmp': cdata 'style': cdata_css, store(attrib_delim, '') 'script': cdata_js, store(attrib_delim, '') 'title': rcdata 'textarea': rcdata 'plaintext': plain_text else: pcdata @public tag_body: alpha: attrib_name, record(attrib_name) sp, nl: tag_body '>': end_tag else: error attrib_name: alpha: attrib_name num: attrib_name sp, nl: tag_after_attrib, store(attrib_name, 'i') '=': tag_after_eq, store(attrib_name, 'i') '>': end_tag else: error tag_after_attrib: '=': tag_after_eq else as tag_body @public tag_after_eq: sp, nl: tag_after_eq alpha, num: attrib_value, set(attrib_delim, ' ') '"': attrib_value, set(attrib_delim, '"') '\'': attrib_value, set(attrib_delim, '\'') '>': end_tag else: error def attrib_value(attrib_name): 'style' as css_attrib 'onload', 'onunload', 'onclick', 'ondblclick', 'onmousedown', 'onmouseup', 'onmouseover', 'onmousemove', 'onmouseout', 'onfocus', 'onblur', 'onkeypress', 'onkeydown', 'onkeyup', 'onsubmit', 'onreset', 'onselect', 'onchange', 'onresize' as js_attrib else: html_attrib_value def css_attrib(attrib_delim): '"': dq_css '\'': sq_css else: sp_css def js_attrib(attrib_delim): '"': dq_js '\'': sq_js else: sp_js def html_attrib_value(attrib_delim): '"': dq_attrib_value '\'': sq_attrib_value else: sp_attrib_value @public dq_attrib_value: '"': tag_body @public sq_attrib_value: '\'': tag_body @public sp_attrib_value: sp, nl: tag_body '>': end_tag '/': tag_body plain_text: else: plain_text @public cdata: '<': cdata_lt cdata_lt: '/': cdata_lt_slash else as cdata cdata_lt_slash: alpha: cdata_apparent_close_tag, record(apparent_tag_name) else as cdata cdata_apparent_close_tag: alpha: cdata_apparent_close_tag else as cdata_check_close_tag, store(apparent_tag_name, 'i') def cdata_check_close_tag(apparent_tag_name): tag_name as tag_body, clear(tag_name), clear(apparent_tag_name) else as cdata @public rcdata: '<': rcdata_lt rcdata_lt: '/': rcdata_lt_slash else as rcdata rcdata_lt_slash: alpha: rcdata_apparent_close_tag, record(apparent_tag_name) else as rcdata rcdata_apparent_close_tag: alpha: rcdata_apparent_close_tag else as rcdata_check_close_tag, store(apparent_tag_name, 'i') def rcdata_check_close_tag(apparent_tag_name): tag_name as tag_body, clear(tag_name), clear(apparent_tag_name) else as rcdata ################ CSS template instantiated in various flavors below template CSS: @public css: '/': css_slash '\'': css_sq '\"': css_dq css_slash: '*': css_comment else as css @public css_sq: '\\': css_sq_esc '\'': css css_sq_esc: else: css_sq @public css_dq: '\\': css_dq_esc '"': css css_dq_esc: else: css_dq css_comment: '*': css_comment_ast '/': css_comment_slash css_comment_ast: '/': css else as css_comment css_comment_slash: '*': error("Nested comment in CSS") else as css_comment ################ JS template instantiated in various flavors below template JS: @public js: '"': js_dq_string '\'': js_sq_string '/': js_slash else: js @public js_dq_string: '\\': js_dq_string_esc nl: error '"': js js_dq_string_esc: else: js_dq_string @public js_sq_string: '\\': js_sq_string_esc nl: error '\'': js js_sq_string_esc: else: js_sq_string js_slash: '*': js_block_comment '/': js_line_comment # TODO: handle regexp literals else as js js_block_comment: '*': js_block_comment_ast js_block_comment_ast: '/': js else as js_block_comment js_line_comment: nl: js ################ JS/CSS in a single quoted attribute namespace sq_: *: '\'': tag_body '&': gosub html_entity ################ JS/CSS in a double quoted attribute namespace dq_: *: '\"': tag_body '&': gosub html_entity ################ JS/CSS in an unquoted attribute namespace sp_: *: sp: tag_body nl: tag_body '/': tag_body '>' as end_tag '&': gosub html_entity ################ JS/CSS in a script or style tag namespace cdata_: *: '<': gosub cdata_possible_end_tag1 cdata_possible_end_tag1: '/': cdata_possible_end_tag2 # TODO: replace_return(js, js_regexp_literal) cdata_possible_end_tag2: alpha: cdata_possible_end_tag_name, record(apparent_tag_name) cdata_possible_end_tag_name: alpha: cdata_possible_end_tag_name else: cdata_check_end_tag, store(apparent_tag_name, 'i') def cdata_check_end_tag(apparent_tag_name): tag_name as tag_body, clear(apparent_tag_name), clear(tag_name) else: return ################ Handle HTML entities in attributes html_entity: alpha: html_entity_body, record(entity_name) '#': html_entity_body, record(entity_name) else: return html_entity_body: alpha, num: html_entity_body ';': return, decode(entity_name, 'decodeHtmlEntity') else: error