Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ANTLR #1955

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions lib/rouge/demos/antlr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
grammar GrammarName;
options { anOption = optionValue; }
program: item_list item? EOF;
param_list /* multi-line
comment */ : name (',' name)* ;
terminated_statement:
IF '(' expr ')' newline_opt terminated_statement (
ELSE newline_opt terminated_statement
)? # if_stmt
| WHILE '(' expr ')' newline_opt terminated_statement #while_stmt
| FOR '(' simple_statement_opt ';' expr_opt ';' simple_statement_opt ')' newline_opt
terminated_statement # for_stmt;
COMMENT: '#' .*? NEWLINE -> channel(HIDDEN);
ESC_NEWLINE: '\\' NEWLINE -> skip;
STRING: '"' (~["\\\r\n] | ESCAPE_SEQUENCE)* '"';
mode WORD_MODE;
WORD: [A-Za-z_] [A-Za-z_0-9]*; // single line comment
fragment EXPONENT_PART: [eE] [+\-]? DIGIT_SEQUENCE;
fragment HEX_CONSTANT: '0' [xX] [0-9A-Fa-f]+;
114 changes: 114 additions & 0 deletions lib/rouge/lexers/antlr.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

module Rouge
module Lexers
class ANTLR < RegexLexer
title "ANTLR"
desc "ANother Tool for Language Recognition"
tag 'antlr'
filenames '*.g4'
def self.keywords
@keywords ||= Set.new %w(
catch channel channels finally fragment grammar import lexer locals
mode more options parser popMode private protected public pushMode
returns skip throws tokens type
)
end
get_label = true
identifier = %r/[A-Za-z][a-zA-Z0-9_]*/
integer = %r/0|[1-9][0-9]*/
lowercase_name = %r/[a-z][a-zA-Z0-9_]*/
uppercase_name = %r/[A-Z][a-zA-Z0-9_]*/
state :whitespace do
rule %r/\s+/, Text
end
state :comment_and_whitespace do
mixin :whitespace
rule %r(//.*?$), Comment::Single
rule %r(/\*.*?\*/)m, Comment::Multiline
end
state :escape_sequence do
rule %r/\\./, Str::Escape
end
state :string do
mixin :escape_sequence
rule %r/'/, Str, :pop!
rule %r/[^\\'\n]+/, Str
end
state :options_spec do
mixin :comment_and_whitespace
rule %r/{/, Punctuation
rule %r/}/, Punctuation, :pop!
rule %r/=/, Operator, :option_value
rule identifier, Name::Attribute
end
state :option_value do
mixin :comment_and_whitespace
rule %r/;/, Punctuation, :pop!
rule %r/./, Punctuation
rule %r/'/, Str, :string
rule %r/{/, Punctuation, :action_block
rule identifier, Name::Constant
rule integer, Num::Integer
end
state :action_block do
mixin :escape_sequence
mixin :whitespace
rule %r/[^\\{}\s]+/, Name::Function
rule %r/{/, Punctuation, :action_block
rule %r/}/, Punctuation, :pop!
end
state :arg_action_block do
mixin :escape_sequence
mixin :whitespace
rule %r/[^\\\[\]]+/, Str
rule %r/\]/, Str, :pop!
end
state :label do
mixin :comment_and_whitespace
rule lowercase_name, Name::Label, :pop!
end
state :root do
mixin :comment_and_whitespace
rule %r/'/, Str, :string
rule %r/[@<>=~\-+?*]/, Operator
rule %r/[|,.()]/, Punctuation
rule %r/{/, Punctuation, :action_block
rule %r/\[/, Str, :arg_action_block
rule %r/#/, Name::Label, :label
rule integer, Num::Integer
rule %r/:/ do
token Punctuation
get_label = false
end
rule %r/;/ do
token Punctuation
get_label = true
end
rule uppercase_name do
if get_label
token Name::Label
else
token Name::Class
end
end
rule lowercase_name do |m|
if self.class.keywords.include? m[0]
token Keyword
case m[0]
when 'options'
push :options_spec
when 'throws'
get_label = false
end
elsif get_label
token Name::Label
else
token Name::Variable
end
end
end
end
end
end
15 changes: 15 additions & 0 deletions spec/lexers/antlr_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

describe Rouge::Lexers::ANTLR do
let(:subject) { Rouge::Lexers::ANTLR.new }

describe 'guessing' do
include Support::Guessing

it 'guesses by filename' do
assert_guess :filename => 'foo.g4'
end

end
end
37 changes: 37 additions & 0 deletions spec/visual/samples/antlr
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
grammar MyGrammar;
options {
language = Ruby;
output = AST;
backtrack = true;
}
@header {
require 'strscan'
}
@lexer::members {
def scan_number
# implementation here
end
}
mode COMMAND_MODE;
WORD: [a-zA-Z]+;
NUMBER: [0-9]+;
parse: expr+; // single line comment
expr: WORD (PLUS | MINUS) expr | NUMBER;
expr
returns[int value]
@init {
$value = 0
}:
WORD { $value = lookup_word($WORD.text) } /* multi-line
comment */
| NUMBER { $value = $NUMBER.text.to_i };
WORD:
[a-zA-Z]+ {
# option example: sets the token type
$type = $options.myToken
# lexer command example: calls the method defined in @lexer::members
scan_number
};
COMMAND: '/' -> pushMode(COMMAND_MODE);
mode COMMAND_MODE;
COMMAND_MODE_COMMAND: ~[\r\n]+ -> type(COMMAND);