# -*- coding: utf-8 -*- # # vim: set ts=2 sw=2 et: # TODO: Implement format list support. module Rouge module Lexers class Fortran < RegexLexer title "Fortran" desc "Fortran 95 Programming Language" tag 'fortran' filenames '*.f90', '*.f95', '*.F90', '*.F95' mimetypes 'text/x-fortran' name = /[A-Z][_A-Z0-9]*/i kind_param = /(\d+|#{name})/ exponent = /[ED][+-]\d+/ def self.keywords # Fortran allows to omit whitespace between certain keywords... @keywords ||= Set.new %w( allocatable allocate assignment backspace block blockdata call case close common contains continue cycle data deallocate default dimension do elemental else elseif elsewhere end endblockdata enddo endfile endforall endfunction endif endinterface endmodule endprogram endselect endsubroutine endtype endwhere entry equivalence exit external forall format function go goto if implicit in include inout inquire intent interface intrinsic module namelist none nullify only open operator optional out parameter pointer print private procedure program public pure read recursive result return rewind save select selectcase sequence stop subroutine target then to type use where while write ) end def self.types @types ||= Set.new %w( character complex double precision doubleprecision integer logical real ) end def self.intrinsics @intrinsics ||= Set.new %w( abs achar acos adjustl adjustr aimag aint all allocated anint any asin associated atan atan2 bit_size btest ceiling char cmplx conjg cos cosh count cpu_time cshift date_and_time dble digits dim dot_product dprod eoshift epsilon exp exponent floor fraction huge iachar iand ibclr ibits ibset ichar ieor index int ior ishift ishiftc kind lbound len len_trim lge lgt lle llt log log10 logical matmul max maxexponent maxloc maxval merge min minexponent minloc minval mod modulo mvbits nearest nint not null pack precision present product radix random_number random_seed range real repeat reshape rrspacing scale scan selected_int_kind selected_real_kind set_exponent shape sign sin sinh size spacing spread sqrt sum system_clock tan tanh tiny transfer transpose trim ubound unpack verify ) end state :root do rule /[\s\n]+/, Text::Whitespace rule /!.*$/, Comment::Single rule /^#.*$/, Comment::Preproc rule /::|[()\/;,:&]/, Punctuation # TODO: This does not take into account line continuation. rule /^(\s*)([0-9]+)\b/m do |m| token Text::Whitespace, m[1] token Name::Label, m[2] end # Format statements are quite a strange beast. # Better process them in their own state. rule /\b(FORMAT)(\s*)(\()/mi do |m| token Keyword, m[1] token Text::Whitespace, m[2] token Punctuation, m[3] push :format_spec end rule %r( [+-]? # sign ( (\d+[.]\d*|[.]\d+)(#{exponent})? | \d+#{exponent} # exponent is mandatory ) (_#{kind_param})? # kind parameter )xi, Num::Float rule /[+-]?\d+(_#{kind_param})?/i, Num::Integer rule /B'[01]+'|B"[01]+"/i, Num::Bin rule /O'[0-7]+'|O"[0-7]+"/i, Num::Oct rule /Z'[0-9A-F]+'|Z"[0-9A-F]+"/i, Num::Hex rule /(#{kind_param}_)?'/, Str::Single, :string_single rule /(#{kind_param}_)?"/, Str::Double, :string_double rule /[.](TRUE|FALSE)[.](_#{kind_param})?/i, Keyword::Constant rule %r{\*\*|//|==|/=|<=|>=|=>|[-+*/<>=%]}, Operator rule /\.(?:EQ|NE|LT|LE|GT|GE|NOT|AND|OR|EQV|NEQV|[A-Z]+)\./i, Operator::Word rule /#{name}/m do |m| match = m[0].downcase if self.class.keywords.include? match token Keyword elsif self.class.types.include? match token Keyword::Type elsif self.class.intrinsics.include? match token Name::Builtin else token Name end end end state :string_single do rule /[^']+/, Str::Single rule /''/, Str::Escape rule /'/, Str::Single, :pop! end state :string_double do rule /[^"]+/, Str::Double rule /""/, Str::Escape rule /"/, Str::Double, :pop! end state :format_spec do rule /'/, Str::Single, :string_single rule /"/, Str::Double, :string_double rule /\(/, Punctuation, :format_spec rule /\)/, Punctuation, :pop! rule /,/, Punctuation rule /[\s\n]+/, Text::Whitespace # Edit descriptors could be seen as a kind of "format literal". rule /[^\s'"(),]+/, Literal end end end end