# -*- coding: utf-8 -*- # # frozen_string_literal: true module Rouge module Lexers class VisualBasic < RegexLexer title "Visual Basic" desc "Visual Basic" tag 'vb' aliases 'visualbasic' filenames '*.vbs', '*.vb' mimetypes 'text/x-visualbasic', 'application/x-visualbasic' def self.keywords @keywords ||= Set.new %w( AddHandler Alias ByRef ByVal CBool CByte CChar CDate CDbl CDec CInt CLng CObj CSByte CShort CSng CStr CType CUInt CULng CUShort Call Case Catch Class Const Continue Declare Default Delegate Dim DirectCast Do Each Else ElseIf End EndIf Enum Erase Error Event Exit False Finally For Friend Function Get Global GoSub GoTo Handles If Implements Imports Inherits Interface Let Lib Loop Me Module MustInherit MustOverride MyBase MyClass Namespace Narrowing New Next Not NotInheritable NotOverridable Nothing Of On Operator Option Optional Overloads Overridable Overrides ParamArray Partial Private Property Protected Public RaiseEvent ReDim ReadOnly RemoveHandler Resume Return Select Set Shadows Shared Single Static Step Stop Structure Sub SyncLock Then Throw To True Try TryCast Using Wend When While Widening With WithEvents WriteOnly ) end def self.keywords_type @keywords_type ||= Set.new %w( Boolean Byte Char Date Decimal Double Integer Long Object SByte Short Single String Variant UInteger ULong UShort ) end def self.operator_words @operator_words ||= Set.new %w( AddressOf And AndAlso As GetType In Is IsNot Like Mod Or OrElse TypeOf Xor ) end def self.builtins @builtins ||= Set.new %w( Console ConsoleColor ) end id = /[a-z_]\w*/i upper_id = /[A-Z]\w*/ state :whitespace do rule %r/\s+/, Text rule %r/\n/, Text, :bol rule %r/rem\b.*?$/i, Comment::Single rule %r(%\{.*?%\})m, Comment::Multiline rule %r/'.*$/, Comment::Single end state :bol do rule %r/\s+/, Text rule %r/<.*?>/, Name::Attribute rule(//) { :pop! } end state :root do mixin :whitespace rule %r( [#]If\b .*? \bThen | [#]ElseIf\b .*? \bThen | [#]End \s+ If | [#]Const | [#]ExternalSource .*? \n | [#]End \s+ ExternalSource | [#]Region .*? \n | [#]End \s+ Region | [#]ExternalChecksum )x, Comment::Preproc rule %r/[.]/, Punctuation, :dotted rule %r/[(){}!#,:]/, Punctuation rule %r/Option\s+(Strict|Explicit|Compare)\s+(On|Off|Binary|Text)/, Keyword::Declaration rule %r/End\b/, Keyword, :end rule %r/(Dim|Const)\b/, Keyword, :dim rule %r/(Function|Sub|Property)\b/, Keyword, :funcname rule %r/(Class|Structure|Enum)\b/, Keyword, :classname rule %r/(Module|Namespace|Imports)\b/, Keyword, :namespace rule upper_id do |m| match = m[0] if self.class.keywords.include? match token Keyword elsif self.class.keywords_type.include? match token Keyword::Type elsif self.class.operator_words.include? match token Operator::Word elsif self.class.builtins.include? match token Name::Builtin else token Name end end rule( %r(&=|[*]=|/=|\\=|\^=|\+=|-=|<<=|>>=|<<|>>|:=|<=|>=|<>|[-&*/\\^+=<>.]), Operator ) rule %r/"/, Str, :string rule %r/#{id}[%&@!#\$]?/, Name rule %r/#.*?#/, Literal::Date rule %r/(\d+\.\d*|\d*\.\d+)(f[+-]?\d+)?/i, Num::Float rule %r/\d+([SILDFR]|US|UI|UL)?/, Num::Integer rule %r/&H[0-9a-f]+([SILDFR]|US|UI|UL)?/, Num::Integer rule %r/&O[0-7]+([SILDFR]|US|UI|UL)?/, Num::Integer rule %r/_\n/, Keyword end state :dotted do mixin :whitespace rule id, Name, :pop! end state :string do rule %r/""/, Str::Escape rule %r/"C?/, Str, :pop! rule %r/[^"]+/, Str end state :dim do mixin :whitespace rule id, Name::Variable, :pop! rule(//) { pop! } end state :funcname do mixin :whitespace rule id, Name::Function, :pop! end state :classname do mixin :whitespace rule id, Name::Class, :pop! end state :namespace do mixin :whitespace rule %r/#{id}([.]#{id})*/, Name::Namespace, :pop! end state :end do mixin :whitespace rule %r/(Function|Sub|Property|Class|Structure|Enum|Module|Namespace)\b/, Keyword, :pop! rule(//) { pop! } end end end end