# @Opulent module Opulent # @Tokens module Tokens # @Token # # Structure holding matching data for each Opulent token # # @param regex [RegEx] Regular expression for matching the token # @param extra [FixNum] Extra characters around the first capture group # Token = Struct.new :regex, :extra # @Singleton class << self # Token knowledgebase @@tokens = {} # Opulent Keywords KEYWORDS = %w(def theme block yield if else elsif unless case when each while until) def keyword(word) KEYWORDS.include? word end # Shorthand Attributes @@shorthand_lookahead = [] Opulent::Engine[:shorthand].each do |key, value| @@tokens["shorthand@#{key}".to_sym] = Token.new /\A(#{value})/ @@shorthand_lookahead << "#{value}[a-zA-Z\"(]" end # Node identifier @@tokens[:identifier] = Token.new /\A([a-zA-Z]([\-\_]?[a-zA-Z0-9]+)*)/ @@tokens[:identifier_lookahead] = Token.new /\A([a-zA-Z]\w*\:\:)?(?<capture>([a-zA-Z]([\-\_]?[a-zA-Z0-9]+)*|#{@@shorthand_lookahead.join '|'}))/ # Attribute lookahead @@tokens[:attribute_lookahead] = Token.new /\A([a-zA-Z]([\-\_]?[a-zA-Z0-9]+)*)/ # Self enclosing nodes @@tokens[:self_enclosing] = Token.new /\A\/(.*)/, 1 # Node assignments @@tokens[:assignment] = Token.new /\A(\:|\=)/ @@tokens[:assignment_unescaped] = Token.new /\A(\~)/ @@tokens[:assignment_terminator] = Token.new /\A((\,|\;)\s*)/ @@tokens[:assignment_lookahead] = Token.new /\A *(?<capture>[a-zA-Z]([\-\_]?[a-zA-Z0-9]+)* *[\:\=])/ # Node extension @@tokens[:extend_attributes] = Token.new /\A(\+)/ # Node inline child @@tokens[:inline_child] = Token.new /\A(\>)/ # Node output whitespace @@tokens[:leading_whitespace] = Token.new /\A(\<\-)/ @@tokens[:leading_trailing_whitespace] = Token.new /\A(\>)/ @@tokens[:trailing_whitespace] = Token.new /\A(\-\>)/ # Comments @@tokens[:comment] = Token.new /\A\/(.*)/, 1 @@tokens[:comment_lookahead] = Token.new /\A *(?<capture>\/)/ # Intepreted filters @@tokens[:filter] = Token.new /\A\:([a-zA-Z]([\-\_]?[a-zA-Z0-9]+)*)/, 1 @@tokens[:filter_lookahead] = Token.new /\A *\:(?<capture>[a-zA-Z]([\-\_]?[a-zA-Z0-9]+)*)/ # Text @@tokens[:escaped_text] = Token.new /\A(.*)/ @@tokens[:unescaped_text] = Token.new /\A\~(.*)/, 1 # Print @@tokens[:escaped_print] = Token.new /\A\=(.*)/, 1 @@tokens[:unescaped_print] = Token.new /\A\=\~(.*)/, 2 @@tokens[:print_lookahead] = Token.new /\A *(?<capture>\=)/ # Multiline Text @@tokens[:multiline] = Token.new /\A(\|)/ # HTML Text @@tokens[:html_text] = Token.new /\A(\<.+\>.*)/ # Definitions @@tokens[:def] = Token.new /\A(def +)/ @@tokens[:def_lookahead] = Token.new /\A *(?<capture>def )/ # Yield @@tokens[:yield] = Token.new /\A(yield)/ @@tokens[:yield_lookahead] = Token.new /\A *(?<capture>yield)/ @@tokens[:yield_identifier] = Token.new /\A( +[a-zA-Z]([\_]?[a-zA-Z0-9]+)*)/ # Yield @@tokens[:block] = Token.new /\A(block)/ @@tokens[:block_lookahead] = Token.new /\A *(?<capture>block)/ # Theme @@tokens[:theme] = Token.new /\A(theme +)/ @@tokens[:theme_lookahead] = Token.new /\A *(?<capture>theme )/ @@tokens[:theme_identifier] = Token.new /\A([a-zA-Z]\w*)/ @@tokens[:theme_node] = Token.new /\A([a-zA-Z]\w*)\:\:/, 2 # Conditional Structures @@tokens[:control] = Token.new /\A(if|elsif|else|unless|case|when|each|while|until)/ @@tokens[:control_lookahead] = Token.new /\A *(?<capture>if|elsif|else|unless|case|when|each|while|until)/ @@tokens[:each_pattern] = Token.new /\A(\w+( *, *\w+)? +)?in +.+/ # Brackets @@tokens[:round_bracket_open] = Token.new /\A(\()/ @@tokens[:round_bracket_close] = Token.new /\A(\))/ @@tokens[:square_bracket_open] = Token.new /\A(\[)/ @@tokens[:square_bracket_close] = Token.new /\A(\])/ @@tokens[:curly_bracket_open] = Token.new /\A(\{)/ @@tokens[:curly_bracket_close] = Token.new /\A(\})/ @@tokens[:angular_bracket_open] = Token.new /\A(\<)/ @@tokens[:angular_bracket_close] = Token.new /\A(\>)/ # Receive matching brackets for allowing multiple bracket types for # element attributes @@tokens[:brackets] = Token.new /\A([\(\[\{])/ @@tokens[:'('] = @@tokens[:round_bracket_close] @@tokens[:'['] = @@tokens[:square_bracket_close] @@tokens[:'{'] = @@tokens[:curly_bracket_close] @@tokens[:'<'] = @@tokens[:angular_bracket_close] # Terminators @@tokens[:comma] = Token.new /\A(\s*\,\s*)/ @@tokens[:colon] = Token.new /\A(\s*\:\s*)/ @@tokens[:semicolon] = Token.new /\A(\s*\;\s*)/ # Array @@tokens[:array_open] = @@tokens[:square_bracket_open] @@tokens[:array_terminator] = @@tokens[:comma] @@tokens[:array_close] = @@tokens[:square_bracket_close] # Hash @@tokens[:hash_open] = @@tokens[:curly_bracket_open] @@tokens[:hash_terminator] = Token.new /\A(\s*(\,)\s*)/ @@tokens[:hash_assignment] = Token.new /\A(\s*(\=\>)\s*)/ @@tokens[:hash_symbol] = Token.new /\A([a-zA-Z\_][a-zA-Z0-9\_]*\:(?!\:))/ @@tokens[:hash_close] = @@tokens[:curly_bracket_close] # Expressions @@tokens[:exp_context] = Token.new /\A(\$(.|\-.)?|\@|\@\@)/ @@tokens[:exp_method_call] = Token.new /\A(\.[a-zA-Z\_][a-zA-Z0-9\_]*[\!\?]?)/ @@tokens[:exp_module] = Token.new /\A(\:\:)/ @@tokens[:exp_identifier] = Token.new /\A([a-zA-Z\_][a-zA-Z0-9\_]*[\!\?]?)/ @@tokens[:exp_assignment] = Token.new /\A(\=)/ @@tokens[:exp_operation] = Token.new /\A( *(\+|\-|\*\*|\*|\/|\<\<|\>\>|\.\.|\%|\<\=\>|\<\=|\^|\<|\>\=|\>|\=\~|\!\~|\=\=\=|\=\=|\=~|\!|not|\&\&|\&|and|\|\||\||or) *)/ @@tokens[:exp_regex] = Token.new /\A(\/((?:[^\/\\]|\\.)*?)\/)/ @@tokens[:exp_string] = Token.new /\A(("((?:[^"\\]|\\.)*?)")|('(?:[^'\\]|\\.)*?'))/ @@tokens[:exp_percent] = Token.new /\A(\%[wWqQrxsiI]?.)/ @@tokens[:exp_double] = Token.new /\A([0-9]+\.[0-9]+([eE][-+]?[0-9]+)?)/ @@tokens[:exp_fixnum] = Token.new /\A([0-9]+)/ @@tokens[:exp_nil] = Token.new /\A(nil)/ @@tokens[:exp_boolean] = Token.new /\A(true|false)/ @@tokens[:exp_ternary] = Token.new /\A( *\? *)/ @@tokens[:exp_ternary_else] = Token.new /\A( *\: *)/ # Expression identifier lookahead @@tokens[:exp_identifier_lookahead] = Token.new /\A(?<capture>[a-zA-Z\_][a-zA-Z0-9\_]*[\!\?]?)/ # Evaluation @@tokens[:eval] = Token.new /\A\-(.*)/, 1 @@tokens[:eval_multiline] = Token.new /\A\+(.*)/, 1 # Whitespace @@tokens[:newline] = Token.new /\A(\n+)/ @@tokens[:whitespace] = Token.new /\A( +)/ @@tokens[:whitespace_lookahead] = Token.new /\A(?<capture> +)/ # Indentation @@tokens[:indent] = Token.new /\A( *)/ @@tokens[:indent_lookahead] = Token.new /\A\n?(?<capture> *)/ # Feed @@tokens[:line_feed] = Token.new /\A(.*)/ # Return the matching closing bracket # # @param bracket [String] Opening bracket for the capture group # def bracket(bracket) case bracket when '(' then return ')' when '[' then return ']' when '{' then return '}' when '<' then return '>' end end # Return the requested token to the parser # # @param name [Symbol] Token requested by the parser accept method # def [](name) @@tokens[name] end # Set a new token at runtime # # @param name [Symboidentifierl] Identifier for the token # @param token [Token] Token data to be set # def []=(name, token) @@tokens[name] = token end # # # Control structures # T_IF = /\A(if)/ # T_ELSIF = /\A(elsif)/ # T_ELSE = /\A(else)/ # T_EACH = /\A(each)/ # T_IN = /\A(in)/ # # # Punctuation # T_COLON = /\A(\:)/ # T_SEMICOLON = /\A(\;)/ # # # Assignments terminator # T_TERMINATOR = /\A(\,|\;)/ # # # Assignments identifier # T_ASSIGNMENT = /\A(\:|=)/ # # # Paranthesis # T_SQUARE_BRACKET_OPEN = /\A(\[)/ # T_SQUARE_BRACKET_CLOSE = /\A(\])/ # T_CURLY_BRACKET_OPEN = /\A(\{)/ # T_CURLY_BRACKET_CLOSE = /\A(\})/ # T_PARANTHESIS_OPEN = /\A(\()/ # T_PARANTHESIS_CLOSE = /\A(\))/ # # # Embedded Ruby # T_RUBY_CONTEXT = /\A(\$[0-9]*?|\@|\@\@)/ # T_RUBY_CONSTANT = /\A([a-zA-Z\_][a-zA-Z0-9\_]*)/ # T_RUBY_INDEX = /\A(\[\s*\:?(([0-9]+)|([a-zA-Z\_][a-zA-Z0-9\-\_]*)|("((?:[^"\\]|\\.)*?)")|('(?:[^'\\]|\\.)*?')|(.+\.\..+))\s*\])/ # T_RUBY_MODULES = /\A(\:\:[a-zA-Z\_][a-zA-Z0-9\_]*)/ # T_RUBY_METHOD = /\A(\.[a-zA-Z\_][a-zA-Z0-9\_]*[\!\?]?)/ # # # Literals # T_STRING = /\A(("((?:[^"\\]|\\.)*?)")|('(?:[^'\\]|\\.)*?'))/ # T_DOUBLE = /\A([0-9]+\.[0-9]+([eE][-+]?[0-9]+)?)/ # T_INTEGER = /\A([0-9]+)/ # T_UNDEFINED = /\A(nil)/ # T_BOOLEAN_TRUE = /\A(true)/ # T_BOOLEAN_FALSE = /\A(false)/ # # # Operation Signs # T_MULTIPLICATIVE = /\A(\*\*|\*|\/)/ # T_ADDITIVE = /\A(\<\<|\+|\-)/ # T_EQUALITY = /\A(\<\=|\<|\>\=|\>|\=\=)/ # T_BOOLEAN_NOT = /\A(\!|not)/ # T_BOOLEAN_AND = /\A(\&\&|and)/ # T_BOOLEAN_OR = /\A(\|\||or)/ # # # Operation Signs Lookahead # T_SIGN_LOOKAHEAD = /\A\*\*|\*|\/|\+|\-|\<\<|\<\=|\<|\>\=|\>|\=\=|\=|\!|not|\&\&|and|\|\||or/ # # # Whitespace # T_WHITESPACE = /\A( +)/ # T_NEWLINE = /\A(\n*)/ # T_INDENT = /\A( *)/ # # # Whitespace Lookahead # T_INDENT_LOOKAHEAD = /\A\n?( *)/ # # # Line and char feeds # T_LINE_FEED = /\A(.*)/ # T_CHAR_FEED = /\A([\s\S])/ # T_UNESCAPED_TEXT = /\A\!(.*)/ # T_UNESCAPED_MULTILINE_TEXT = /\A(\!\=)/ # T_ESCAPED_MULTILINE_TEXT = /\A(\=)/ end end end