# -*- coding: utf-8 -*- # # frozen_string_literal: true module Rouge module Lexers class Ada < RegexLexer tag 'ada' filenames '*.ada', '*.ads', '*.adb', '*.gpr' mimetypes 'text/x-ada' title 'Ada' desc 'The Ada 2012 programming language' # Ada identifiers are Unicode with underscores only allowed as separators. ID = /\b[[:alpha:]](?:\p{Pc}?[[:alnum:]])*\b/ # Numerals can also contain underscores. NUM = /\d(_?\d)*/ XNUM = /\h(_?\h)*/ EXP = /(E[-+]?#{NUM})?/i # Return a hash mapping lower-case identifiers to token classes. def self.idents @idents ||= Hash.new(Name).tap do |h| %w( abort abstract accept access aliased all array at begin body case constant declare delay delta digits do else elsif end exception exit for generic goto if in interface is limited loop new null of others out overriding pragma private protected raise range record renames requeue return reverse select separate some synchronized tagged task terminate then until use when while with ).each {|w| h[w] = Keyword} %w(abs and mod not or rem xor).each {|w| h[w] = Operator::Word} %w( entry function package procedure subtype type ).each {|w| h[w] = Keyword::Declaration} %w( boolean character constraint_error duration float integer natural positive long_float long_integer long_long_float long_long_integer program_error short_float short_integer short_short_integer storage_error string tasking_error wide_character wide_string wide_wide_character wide_wide_string ).each {|w| h[w] = Name::Builtin} end end state :whitespace do rule %r{\s+}m, Text rule %r{--.*$}, Comment::Single end state :dquote_string do rule %r{[^"\n]+}, Literal::String::Double rule %r{""}, Literal::String::Escape rule %r{"}, Literal::String::Double, :pop! rule %r{\n}, Error, :pop! end state :attr do mixin :whitespace rule ID, Name::Attribute, :pop! rule %r{}, Text, :pop! end # Handle a dotted name immediately following a declaration keyword. state :decl_name do mixin :whitespace rule %r{body\b}i, Keyword::Declaration # package body Foo.Bar is... rule %r{(#{ID})(\.)} do groups Name::Namespace, Punctuation end # function "<=" (Left, Right: Type) is ... rule %r{#{ID}|"(and|or|xor|/?=|<=?|>=?|\+|–|&\|/|mod|rem|\*?\*|abs|not)"}, Name::Function, :pop! rule %r{}, Text, :pop! end # Handle a sequence of library unit names: with Ada.Foo, Ada.Bar; # # There's a chance we entered this state mistakenly since 'with' # has multiple other uses in Ada (none of which are likely to # appear at the beginning of a line). Try to bail as soon as # possible if we see something suspicious like keywords. # # See ada_spec.rb for some examples. state :libunit_name do mixin :whitespace rule ID do |m| t = self.class.idents[m[0].downcase] if t <= Name # Convert all kinds of Name to namespaces in this context. token Name::Namespace else # Yikes, we're not supposed to get a keyword in a library unit name! # We probably entered this state by mistake, so try to fix it. token t if t == Keyword::Declaration goto :decl_name else pop! end end end rule %r{[.,]}, Punctuation rule %r{}, Text, :pop! end state :root do mixin :whitespace # String literals. rule %r{'.'}, Literal::String::Char rule %r{"[^"\n]*}, Literal::String::Double, :dquote_string # Real literals. rule %r{#{NUM}\.#{NUM}#{EXP}}, Literal::Number::Float rule %r{#{NUM}##{XNUM}\.#{XNUM}##{EXP}}, Literal::Number::Float # Integer literals. rule %r{2#[01](_?[01])*##{EXP}}, Literal::Number::Bin rule %r{8#[0-7](_?[0-7])*##{EXP}}, Literal::Number::Oct rule %r{16##{XNUM}*##{EXP}}, Literal::Number::Hex rule %r{#{NUM}##{XNUM}##{EXP}}, Literal::Number::Integer rule %r{#{NUM}#\w+#}, Error rule %r{#{NUM}#{EXP}}, Literal::Number::Integer # Special constructs. rule %r{'}, Punctuation, :attr rule %r{<<#{ID}>>}, Name::Label # Context clauses are tricky because the 'with' keyword is used # for many purposes. Detect at beginning of the line only. rule %r{^(?:(limited)(\s+))?(?:(private)(\s+))?(with)\b}i do groups Keyword::Namespace, Text, Keyword::Namespace, Text, Keyword::Namespace push :libunit_name end # Operators and punctuation characters. rule %r{[+*/&<=>|]|-|=>|\.\.|\*\*|[:>>|<>}, Operator rule %r{[.,:;()]}, Punctuation rule ID do |m| t = self.class.idents[m[0].downcase] token t if t == Keyword::Declaration push :decl_name end end # Flag word-like things that don't match the ID pattern. rule %r{\b(\p{Pc}|[[alpha]])\p{Word}*}, Error end end end end