rf-web/vendor/bundle/gems/rouge-3.12.0/lib/rouge/lexers/bbcbasic.rb
2019-10-21 10:18:17 +02:00

113 lines
4.2 KiB
Ruby

# -*- coding: utf-8 -*- #
# frozen_string_literal: true
module Rouge
module Lexers
class BBCBASIC < RegexLexer
title "BBCBASIC"
desc "BBC BASIC syntax"
tag 'bbcbasic'
filenames '*,fd1'
def self.punctuation
@punctuation ||= %w(
[,;'~] SPC TAB
)
end
def self.function
@function ||= %w(
ABS ACS ADVAL ASC ASN ATN BEATS BEAT BGET# CHR\$ COS COUNT DEG DIM
EOF# ERL ERR EVAL EXP EXT# FN GET\$# GET\$ GET HIMEM INKEY\$ INKEY
INSTR INT LEFT\$ LEN LN LOG LOMEM MID\$ OPENIN OPENOUT OPENUP PAGE
POINT POS PTR# RAD REPORT\$ RIGHT\$ RND SGN SIN SQR STR\$ STRING\$ SUM
SUMLEN TAN TEMPO TIME\$ TIME TOP USR VAL VPOS
)
end
def self.statement
@statement ||= %w(
BEATS BPUT# CALL CASE CHAIN CLEAR CLG CLOSE# CLS COLOR COLOUR DATA
ELSE ENDCASE ENDIF ENDPROC ENDWHILE END ENVELOPE FOR GCOL GOSUB GOTO
IF INSTALL LET LIBRARY MODE NEXT OFF OF ON ORIGIN OSCI OTHERWISE
OVERLAY PLOT PRINT# PRINT PROC QUIT READ REPEAT REPORT RETURN SOUND
STEP STEREO STOP SWAP SYS THEN TINT TO VDU VOICES VOICE UNTIL WAIT
WHEN WHILE WIDTH
)
end
def self.operator
@operator ||= %w(
<< <= <> < >= >>> >> > [-!$()*+/=?^|] AND DIV EOR MOD NOT OR
)
end
def self.constant
@constant ||= %w(
FALSE TRUE
)
end
state :expression do
rule %r/#{BBCBASIC.function.join('|')}/o, Name::Builtin # function or pseudo-variable
rule %r/#{BBCBASIC.operator.join('|')}/o, Operator
rule %r/#{BBCBASIC.constant.join('|')}/o, Name::Constant
rule %r/"[^"]*"/o, Literal::String
rule %r/[a-z_`][\w`]*[$%]?/io, Name::Variable
rule %r/@%/o, Name::Variable
rule %r/[\d.]+/o, Literal::Number
rule %r/%[01]+/o, Literal::Number::Bin
rule %r/&[\h]+/o, Literal::Number::Hex
end
state :root do
rule %r/(:+)( *)(\*)(.*)/ do
groups Punctuation, Text, Keyword, Text # CLI command
end
rule %r/(\n+ *)(\*)(.*)/ do
groups Text, Keyword, Text # CLI command
end
rule %r/(ELSE|OTHERWISE|REPEAT|THEN)( *)(\*)(.*)/ do
groups Keyword, Text, Keyword, Text # CLI command
end
rule %r/[ \n]+/o, Text
rule %r/:+/o, Punctuation
rule %r/[\[]/o, Keyword, :assembly1
rule %r/REM *>.*/o, Comment::Special
rule %r/REM.*/o, Comment
rule %r/(?:#{BBCBASIC.statement.join('|')}|CIRCLE(?: *FILL)?|DEF *(?:FN|PROC)|DRAW(?: *BY)?|DIM(?!\()|ELLIPSE(?: *FILL)?|ERROR(?: *EXT)?|FILL(?: *BY)?|INPUT(?:#| *LINE)?|LINE(?: *INPUT)?|LOCAL(?: *DATA| *ERROR)?|MOUSE(?: *COLOUR| *OFF| *ON| *RECTANGLE| *STEP| *TO)?|MOVE(?: *BY)?|ON(?! *ERROR)|ON *ERROR *(?:LOCAL|OFF)?|POINT(?: *BY)?(?!\()|RECTANGE(?: *FILL)?|RESTORE(?: *DATA| *ERROR)?|TRACE(?: *CLOSE| *ENDPROC| *OFF| *STEP(?: *FN| *ON| *PROC)?| *TO)?)/o, Keyword
mixin :expression
rule %r/#{BBCBASIC.punctuation.join('|')}/o, Punctuation
end
# Assembly statements are parsed as
# {label} {directive|opcode |']' {expressions}} {comment}
# Technically, you don't need whitespace between opcodes and arguments,
# but this is rare in uncrunched source and trying to enumerate all
# possible opcodes here is impractical so we colour it as though
# the whitespace is required. Opcodes and directives can only easily be
# distinguished from the symbols that make up expressions by looking at
# their position within the statement. Similarly, ']' is treated as a
# keyword at the start of a statement or as punctuation elsewhere. This
# requires a two-state state machine.
state :assembly1 do
rule %r/ +/o, Text
rule %r/]/o, Keyword, :pop!
rule %r/[:\n]/o, Punctuation
rule %r/\.[a-z_`][\w`]*%? */io, Name::Label
rule %r/(?:REM|;)[^:\n]*/o, Comment
rule %r/[^ :\n]+/o, Keyword, :assembly2
end
state :assembly2 do
rule %r/ +/o, Text
rule %r/[:\n]/o, Punctuation, :pop!
rule %r/(?:REM|;)[^:\n]*/o, Comment, :pop!
mixin :expression
rule %r/[!#,@\[\]^{}]/, Punctuation
end
end
end
end