148 lines
6.8 KiB
Ruby
148 lines
6.8 KiB
Ruby
# -*- coding: utf-8 -*- #
|
|
# frozen_string_literal: true
|
|
|
|
module Rouge
|
|
module Lexers
|
|
class Brightscript < RegexLexer
|
|
title "BrightScript"
|
|
desc "BrightScript Programming Language (https://developer.roku.com/en-ca/docs/references/brightscript/language/brightscript-language-reference.md)"
|
|
tag 'brightscript'
|
|
aliases 'bs', 'brs'
|
|
filenames '*.brs'
|
|
|
|
# https://developer.roku.com/en-ca/docs/references/brightscript/language/global-utility-functions.md
|
|
# https://developer.roku.com/en-ca/docs/references/brightscript/language/global-string-functions.md
|
|
# https://developer.roku.com/en-ca/docs/references/brightscript/language/global-math-functions.md
|
|
def self.name_builtin
|
|
@name_builtin ||= Set.new %w(
|
|
ABS ASC ATN CDBL CHR CINT CONTROL COPYFILE COS CREATEDIRECTORY CSNG
|
|
DELETEDIRECTORY DELETEFILE EXP FINDMEMBERFUNCTION FINDNODE FIX
|
|
FORMATDRIVEFORMATJSON GETINTERFACE INSTR INT LCASE LEFT LEN LISTDIR
|
|
LOG MATCHFILES MID MOVEFILE OBSERVEFIELD PARSEJSON PARSEXML
|
|
READASCIIFILE REBOOTSYSTEM RIGHT RND RUNGARBAGECOLLECTOR SGN SIN
|
|
SLEEP SQR STR STRI STRING STRINGI STRTOI SUBSTITUTE TANTEXTTOP TEXT
|
|
TRUCASE UPTIME VALVISIBLE VISIBLE WAIT
|
|
)
|
|
end
|
|
|
|
# https://developer.roku.com/en-ca/docs/references/brightscript/language/reserved-words.md
|
|
def self.keyword_reserved
|
|
@keyword_reserved ||= Set.new %w(
|
|
BOX CREATEOBJECT DIM EACH ELSE ELSEIF END ENDFUNCTION ENDIF ENDSUB
|
|
ENDWHILE EVAL EXIT EXITWHILE FALSE FOR FUNCTION GETGLOBALAA
|
|
GETLASTRUNCOMPILEERROR GETLASTRUNRUNTIMEERROR GOTO IF IN INVALID LET
|
|
LINE_NUM M NEXT OBJFUN POS PRINT REM RETURN RUN STEP STOP SUB TAB TO
|
|
TRUE TYPE WHILE
|
|
)
|
|
end
|
|
|
|
# These keywords are present in BrightScript, but not supported in standard .brs files
|
|
def self.keyword_reserved_unsupported
|
|
@keyword_reserved_unsupported ||= Set.new %w(
|
|
CLASS CONST IMPORT LIBRARY NAMESPACE PRIVATE PROTECTED PUBLIC
|
|
)
|
|
end
|
|
|
|
# https://developer.roku.com/en-ca/docs/references/brightscript/language/expressions-variables-types.md
|
|
def self.keyword_type
|
|
@keyword_type ||= Set.new %w(
|
|
BOOLEAN DIM DOUBLE DYNAMIC FLOAT FUNCTION INTEGER INTERFACE INVALID
|
|
LONGINTEGER OBJECT STRING VOID
|
|
)
|
|
end
|
|
|
|
# https://developer.roku.com/en-ca/docs/references/brightscript/language/expressions-variables-types.md#operators
|
|
def self.operator_word
|
|
@operator_word ||= Set.new %w(
|
|
AND AS MOD NOT OR THEN
|
|
)
|
|
end
|
|
|
|
# Scene graph components configured as builtins. See BrightScript component documentation e.g.
|
|
# https://developer.roku.com/en-ca/docs/references/brightscript/components/roappinfo.md
|
|
def self.builtins
|
|
@builtins ||= Set.new %w(
|
|
roAppendFile roAppInfo roAppManager roArray roAssociativeArray
|
|
roAudioGuide roAudioMetadata roAudioPlayer roAudioPlayerEvent
|
|
roAudioResourceroBitmap roBoolean roBoolean roBrightPackage roBrSub
|
|
roButton roByteArray roCaptionRenderer roCaptionRendererEvent
|
|
roCecInterface roCECStatusEvent roChannelStore roChannelStoreEvent
|
|
roClockWidget roCodeRegistrationScreen
|
|
roCodeRegistrationScreenEventroCompositor roControlDown roControlPort
|
|
roControlPort roControlUp roCreateFile roDatagramReceiver
|
|
roDatagramSender roDataGramSocket roDateTime roDeviceInfo
|
|
roDeviceInfoEvent roDoubleroEVPCipher roEVPDigest roFileSystem
|
|
roFileSystemEvent roFloat roFont roFontMetrics roFontRegistry
|
|
roFunction roGlobal roGpio roGridScreen roGridScreenEvent
|
|
roHdmiHotPlugEventroHdmiStatus roHdmiStatusEvent roHMAC roHttpAgent
|
|
roImageCanvas roImageCanvasEvent roImageMetadata roImagePlayer
|
|
roImageWidgetroInput roInputEvent roInt roInt roInvalid roInvalid
|
|
roIRRemote roKeyboard roKeyboardPress roKeyboardScreen
|
|
roKeyboardScreenEventroList roListScreen roListScreenEvent
|
|
roLocalization roLongInteger roMessageDialog roMessageDialogEvent
|
|
roMessagePort roMicrophone roMicrophoneEvent roNetworkConfiguration
|
|
roOneLineDialog roOneLineDialogEventroParagraphScreen
|
|
roParagraphScreenEvent roPath roPinEntryDialog roPinEntryDialogEvent
|
|
roPinentryScreen roPosterScreen roPosterScreenEventroProgramGuide
|
|
roQuadravoxButton roReadFile roRectangleroRegexroRegion roRegistry
|
|
roRegistrySection roResourceManager roRSA roRssArticle roRssParser
|
|
roScreen roSearchHistory roSearchScreen roSearchScreenEvent
|
|
roSerialPort roSGNode roSGNodeEvent roSGScreenroSGScreenEvent
|
|
roSlideShowroSlideShowEvent roSNS5 roSocketAddress roSocketEvent
|
|
roSpringboardScreen roSpringboardScreenEventroSprite roStorageInfo
|
|
roStreamSocket roStringroSystemLogroSystemLogEvent roSystemTime
|
|
roTextFieldroTextScreen roTextScreenEvent roTextToSpeech
|
|
roTextToSpeechEvent roTextureManager roTextureRequest
|
|
roTextureRequestEventroTextWidget roTimer roTimespan roTouchScreen
|
|
roTunerroTunerEvent roUniversalControlEvent roUrlEvent roUrlTransfer
|
|
roVideoEvent roVideoInput roVideoMode roVideoPlayer roVideoPlayerEvent
|
|
roVideoScreen roVideoScreenEventroWriteFile roXMLElement roXMLList
|
|
)
|
|
end
|
|
|
|
id = /[$a-z_][a-z0-9_]*/io
|
|
|
|
state :root do
|
|
rule %r/\s+/m, Text::Whitespace
|
|
|
|
# https://developer.roku.com/en-ca/docs/references/brightscript/language/expressions-variables-types.md#comments
|
|
rule %r/\'.*/, Comment::Single
|
|
rule %r/REM.*/i, Comment::Single
|
|
|
|
# https://developer.roku.com/en-ca/docs/references/brightscript/language/expressions-variables-types.md#operators
|
|
rule %r([~!%^&*+=\|?:<>/-]), Operator
|
|
|
|
rule %r/\d*\.\d+(e-?\d+)?/i, Num::Float
|
|
rule %r/\d+[lu]*/i, Num::Integer
|
|
|
|
rule %r/".*?"/, Str::Double
|
|
|
|
rule %r/#{id}(?=\s*[(])/, Name::Function
|
|
|
|
rule %r/[()\[\],.;{}]/, Punctuation
|
|
|
|
rule id do |m|
|
|
caseSensitiveChunk = m[0]
|
|
caseInsensitiveChunk = m[0].upcase
|
|
|
|
if self.class.builtins.include?(caseSensitiveChunk)
|
|
token Keyword::Reserved
|
|
elsif self.class.keyword_reserved.include?(caseInsensitiveChunk)
|
|
token Keyword::Reserved
|
|
elsif self.class.keyword_reserved_unsupported.include?(caseInsensitiveChunk)
|
|
token Keyword::Reserved
|
|
elsif self.class.keyword_type.include?(caseInsensitiveChunk)
|
|
token Keyword::Type
|
|
elsif self.class.name_builtin.include?(caseInsensitiveChunk)
|
|
token Name::Builtin
|
|
elsif self.class.operator_word.include?(caseInsensitiveChunk)
|
|
token Operator::Word
|
|
else
|
|
token Name
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|