Skip to content

Instantly share code, notes, and snippets.

@JoeRobich
Created July 16, 2016 16:24
Show Gist options
  • Save JoeRobich/c787e8cbc265bbf5c0e1362e948292d8 to your computer and use it in GitHub Desktop.
Save JoeRobich/c787e8cbc265bbf5c0e1362e948292d8 to your computer and use it in GitHub Desktop.
Attempt at a MXML Lexer for the rouge ruby gem.
# -*- coding: utf-8 -*- #
module Rouge
module Lexers
class MXML < ActionScript
title "MXML"
desc "MXML"
tag 'mxml'
filenames '*.mxml'
mimetypes 'application/xv+xml'
def self.analyze_text(text)
return 0.9 if text.doctype?
return 0.8 if text =~ /\A<\?xml\b/
start = text[0..1000]
return 0.6 if start =~ %r(<xml\b)
return 0.3 if start =~ %r(<.+?>.*?</.+?>)m
end
state :root do
rule /[^<&]+/, Text
rule /&\S*?;/, Name::Entity
rule /<!\[CDATA\[/, Comment::Preproc, :actionscript_root
rule /<!--/, Comment, :comment
rule /<\?.*?\?>/, Comment::Preproc
rule /<![^>]*>/, Comment::Preproc
# open tags
rule %r(<\s*[\w:.-]+)m, Name::Tag, :tag
# self-closing tags
rule %r(<\s*/\s*[\w:.-]+\s*>)m, Name::Tag
end
state :comment do
rule /[^-]+/m, Comment
rule /-->/, Comment, :pop!
rule /-/, Comment
end
state :tag do
rule /\s+/m, Text
rule /[\w.:-]+\s*=/m, Name::Attribute, :attr
rule %r(/?\s*>), Name::Tag, :pop!
end
state :attr do
rule /\s+/m, Text
rule /".*?"|'.*?'|[^\s>]+/, Str, :pop!
end
state :actionscript_root do
rule /\]\]\>/, Comment::Preproc, :pop!
rule /\A\s*#!.*?\n/m, Comment::Preproc, :actionscript_statement
rule /\n/, Text, :actionscript_statement
rule %r((?<=\n)(?=\s|/|<!--)), Text, :actionscript_expr_start
mixin :actionscript_comments_and_whitespace
rule %r(\+\+ | -- | ~ | && | \|\| | \\(?=\n) | << | >>>? | ===
| !== )x,
Operator, :actionscript_expr_start
rule %r([:-<>+*%&|\^/!=]=?), Operator, :actionscript_expr_start
rule /[(\[,]/, Punctuation, :actionscript_expr_start
rule /;/, Punctuation, :actionscript_statement
rule /[)\].]/, Punctuation
rule /[?]/ do
token Punctuation
push :actionscript_ternary
push :actionscript_expr_start
end
rule /[{}]/, Punctuation, :actionscript_statement
rule id do |m|
if self.class.keywords.include? m[0]
token Keyword
push :actionscript_expr_start
elsif self.class.declarations.include? m[0]
token Keyword::Declaration
push :actionscript_expr_start
elsif self.class.reserved.include? m[0]
token Keyword::Reserved
elsif self.class.constants.include? m[0]
token Keyword::Constant
elsif self.class.builtins.include? m[0]
token Name::Builtin
else
token Name::Other
end
end
rule /\-[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?/, Num::Float
rule /0x[0-9a-fA-F]+/, Num::Hex
rule /\-[0-9]+/, Num::Integer
rule /"(\\\\|\\"|[^"])*"/, Str::Double
rule /'(\\\\|\\'|[^'])*'/, Str::Single
end
state :actionscript_comments_and_whitespace do
rule /\s+/, Text
rule %r(//.*?$), Comment::Single
rule %r(/\*.*?\*/)m, Comment::Multiline
end
state :actionscript_expr_start do
mixin :actionscript_comments_and_whitespace
rule %r(/) do
token Str::Regex
goto :actionscript_regex
end
rule /[{]/, Punctuation, :actionscript_object
rule //, Text, :pop!
end
state :actionscript_regex do
rule %r(/) do
token Str::Regex
goto :actionscript_regex_end
end
rule %r([^/]\n), Error, :pop!
rule /\n/, Error, :pop!
rule /\[\^/, Str::Escape, :actionscript_regex_group
rule /\[/, Str::Escape, :actionscript_regex_group
rule /\\./, Str::Escape
rule %r{[(][?][:=<!]}, Str::Escape
rule /[{][\d,]+[}]/, Str::Escape
rule /[()?]/, Str::Escape
rule /./, Str::Regex
end
state :actionscript_regex_end do
rule /[gim]+/, Str::Regex, :pop!
rule(//) { pop! }
end
state :actionscript_regex_group do
# specially highlight / in a group to indicate that it doesn't
# close the regex
rule /\//, Str::Escape
rule %r([^/]\n) do
token Error
pop! 2
end
rule /\]/, Str::Escape, :pop!
rule /\\./, Str::Escape
rule /./, Str::Regex
end
state :actionscript_bad_regex do
rule /[^\n]+/, Error, :pop!
end
def self.keywords
@keywords ||= Set.new %w(
for in while do break return continue switch case default
if else throw try catch finally new delete typeof is
this with
)
end
def self.declarations
@declarations ||= Set.new %w(var with function)
end
def self.reserved
@reserved ||= Set.new %w(
dynamic final internal native public protected private class const
override static package interface extends implements namespace
set get import include super flash_proxy object_proxy trace
)
end
def self.constants
@constants ||= Set.new %w(true false null NaN Infinity undefined)
end
def self.builtins
@builtins ||= %w(
void Function Math Class
Object RegExp decodeURI
decodeURIComponent encodeURI encodeURIComponent
eval isFinite isNaN parseFloat parseInt this
)
end
id = /[$a-zA-Z_][a-zA-Z0-9_]*/
# braced parts that aren't object literals
state :actionscript_statement do
rule /(#{id})(\s*)(:)/ do
groups Name::Label, Text, Punctuation
end
rule /[{}]/, Punctuation
mixin :actionscript_expr_start
end
# object literals
state :actionscript_object do
mixin :actionscript_comments_and_whitespace
rule /[}]/ do
token Punctuation
goto :actionscript_statement
end
rule /(#{id})(\s*)(:)/ do
groups Name::Attribute, Text, Punctuation
push :actionscript_expr_start
end
rule /:/, Punctuation
mixin :actionscript_root
end
# ternary expressions, where <id>: is not a label!
state :actionscript_ternary do
rule /:/ do
token Punctuation
goto :actionscript_expr_start
end
mixin :actionscript_root
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment