rip-parser 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +15 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/LICENSE.md +9 -0
- data/README.md +13 -0
- data/Rakefile +1 -0
- data/bin/console +8 -0
- data/bin/setup +8 -0
- data/legacy/normalizer.rb +279 -0
- data/legacy/parser_spec.rb +999 -0
- data/legacy/rules.rb +250 -0
- data/legacy/rules_spec.rb +1700 -0
- data/rip-parser.gemspec +20 -0
- data/source/rip/parser/about.rb +9 -0
- data/source/rip/parser/error.rb +36 -0
- data/source/rip/parser/grammar.rb +23 -0
- data/source/rip/parser/keywords.rb +84 -0
- data/source/rip/parser/location.rb +47 -0
- data/source/rip/parser/node.rb +115 -0
- data/source/rip/parser/rules/assignment.rb +23 -0
- data/source/rip/parser/rules/binary_condition.rb +24 -0
- data/source/rip/parser/rules/character.rb +40 -0
- data/source/rip/parser/rules/class.rb +60 -0
- data/source/rip/parser/rules/common.rb +47 -0
- data/source/rip/parser/rules/date_time.rb +31 -0
- data/source/rip/parser/rules/expression.rb +122 -0
- data/source/rip/parser/rules/import.rb +23 -0
- data/source/rip/parser/rules/invocation.rb +15 -0
- data/source/rip/parser/rules/invocation_index.rb +15 -0
- data/source/rip/parser/rules/keyword.rb +12 -0
- data/source/rip/parser/rules/lambda.rb +45 -0
- data/source/rip/parser/rules/list.rb +18 -0
- data/source/rip/parser/rules/map.rb +15 -0
- data/source/rip/parser/rules/module.rb +29 -0
- data/source/rip/parser/rules/number.rb +21 -0
- data/source/rip/parser/rules/pair.rb +13 -0
- data/source/rip/parser/rules/property.rb +33 -0
- data/source/rip/parser/rules/range.rb +15 -0
- data/source/rip/parser/rules/reference.rb +16 -0
- data/source/rip/parser/rules/string.rb +41 -0
- data/source/rip/parser/rules/unit.rb +17 -0
- data/source/rip/parser/rules.rb +7 -0
- data/source/rip/parser/utilities/normalizer.rb +638 -0
- data/source/rip/parser.rb +24 -0
- data/source/rip-parser.rb +1 -0
- data/spec/fixtures/syntax_sample.rip +96 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/helpers.rb +57 -0
- data/spec/support/parslet.rb +1 -0
- data/spec/support/shared_examples.rb +9 -0
- data/spec/unit/rip/parser/grammar_spec.rb +8 -0
- data/spec/unit/rip/parser/location_spec.rb +89 -0
- data/spec/unit/rip/parser/node_spec.rb +157 -0
- data/spec/unit/rip/parser/rules/assignment_spec.rb +59 -0
- data/spec/unit/rip/parser/rules/binary_condition_spec.rb +41 -0
- data/spec/unit/rip/parser/rules/character_spec.rb +29 -0
- data/spec/unit/rip/parser/rules/class_spec.rb +181 -0
- data/spec/unit/rip/parser/rules/common_spec.rb +88 -0
- data/spec/unit/rip/parser/rules/date_time_spec.rb +61 -0
- data/spec/unit/rip/parser/rules/expression_spec.rb +95 -0
- data/spec/unit/rip/parser/rules/import_spec.rb +64 -0
- data/spec/unit/rip/parser/rules/invocation_index_spec.rb +46 -0
- data/spec/unit/rip/parser/rules/invocation_spec.rb +46 -0
- data/spec/unit/rip/parser/rules/keyword_spec.rb +17 -0
- data/spec/unit/rip/parser/rules/lambda_spec.rb +174 -0
- data/spec/unit/rip/parser/rules/list_spec.rb +45 -0
- data/spec/unit/rip/parser/rules/map_spec.rb +36 -0
- data/spec/unit/rip/parser/rules/module_spec.rb +63 -0
- data/spec/unit/rip/parser/rules/number_spec.rb +40 -0
- data/spec/unit/rip/parser/rules/pair_spec.rb +25 -0
- data/spec/unit/rip/parser/rules/property_spec.rb +27 -0
- data/spec/unit/rip/parser/rules/range_spec.rb +37 -0
- data/spec/unit/rip/parser/rules/reference_spec.rb +43 -0
- data/spec/unit/rip/parser/rules/string_spec.rb +166 -0
- data/spec/unit/rip/parser/rules/unit_spec.rb +17 -0
- data/spec/unit/rip/parser_spec.rb +106 -0
- metadata +192 -0
data/rip-parser.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative './source/rip/parser/about'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'rip-parser'
|
5
|
+
spec.version = Rip::Parser::About.version
|
6
|
+
spec.author = 'Thomas Ingram'
|
7
|
+
spec.license = 'MIT'
|
8
|
+
spec.summary = 'Composable parser for Rip'
|
9
|
+
spec.homepage = 'http://www.rip-lang.org/'
|
10
|
+
|
11
|
+
spec.files = `git ls-files -z`.split("\x0")
|
12
|
+
spec.require_paths = [ 'source' ]
|
13
|
+
|
14
|
+
spec.add_runtime_dependency 'parslet', '~> 1.7.0'
|
15
|
+
|
16
|
+
spec.add_development_dependency 'pry'
|
17
|
+
spec.add_development_dependency 'pry-doc'
|
18
|
+
spec.add_development_dependency 'rake'
|
19
|
+
spec.add_development_dependency 'rspec'
|
20
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Rip::Parser
|
2
|
+
class Error < StandardError
|
3
|
+
attr_reader :code
|
4
|
+
|
5
|
+
def initialize(message)
|
6
|
+
super
|
7
|
+
@code = 10
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class SyntaxError < Error
|
12
|
+
attr_reader :location
|
13
|
+
attr_reader :cause
|
14
|
+
|
15
|
+
def initialize(message, location, cause)
|
16
|
+
super(message)
|
17
|
+
|
18
|
+
@location = location
|
19
|
+
@cause = cause
|
20
|
+
@code = 11
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class NormalizeError < Error
|
25
|
+
attr_reader :origin
|
26
|
+
attr_reader :tree
|
27
|
+
|
28
|
+
def initialize(message, origin, tree = nil)
|
29
|
+
super(message)
|
30
|
+
|
31
|
+
@origin = origin
|
32
|
+
@tree = tree
|
33
|
+
@code = 12
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
require_relative './rules'
|
4
|
+
|
5
|
+
module Rip::Parser
|
6
|
+
class Grammar
|
7
|
+
include Rip::Parser::Rules::Module
|
8
|
+
|
9
|
+
def self.parse(origin, source_code)
|
10
|
+
begin
|
11
|
+
raw_tree = new.module.parse(source_code)
|
12
|
+
Rip::Parser::Utilities::Normalizer.apply(origin, raw_tree)
|
13
|
+
rescue Parslet::ParseFailed => e
|
14
|
+
match = /\A.+ at line (\d+) char (\d+)\.\z/.match(e.message)
|
15
|
+
line, column = match ? match.values_at(1, 2).map(&:to_i) : [ 0, 0 ]
|
16
|
+
location = Rip::Parser::Location.new(origin, e.cause.pos.charpos, line, column)
|
17
|
+
raise Rip::Parser::SyntaxError.new(e.message, location, e.cause)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
require_relative './utilities/normalizer'
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Rip::Parser
|
2
|
+
class Keyword
|
3
|
+
attr_reader :name
|
4
|
+
attr_reader :source_text
|
5
|
+
|
6
|
+
def initialize(name, source_text = name)
|
7
|
+
@name = name.to_sym
|
8
|
+
@source_text = source_text.to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
def ==(other)
|
12
|
+
name == other.name
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_debug
|
16
|
+
name
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.[](name)
|
20
|
+
Keywords.all.detect do |keyword|
|
21
|
+
keyword.name == name
|
22
|
+
end.tap do |keyword|
|
23
|
+
raise "Unknown keyword: `#{name}`" if keyword.nil?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module Keywords
|
29
|
+
def self.all
|
30
|
+
[
|
31
|
+
conditional,
|
32
|
+
dependency,
|
33
|
+
exceptional,
|
34
|
+
object,
|
35
|
+
pseudo,
|
36
|
+
query,
|
37
|
+
transfer
|
38
|
+
].inject(&:+)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.conditional
|
42
|
+
make_keywords(:if, :switch, :case, :else)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.dependency
|
46
|
+
make_keywords(:import)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.exceptional
|
50
|
+
make_keywords(:try, :catch, :finally)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.object
|
54
|
+
[
|
55
|
+
*make_keywords(:class, :enum, :interface),
|
56
|
+
Keyword.new(:swerve_rocket, '~>'),
|
57
|
+
Keyword.new(:dash_rocket, '->'),
|
58
|
+
Keyword.new(:fat_rocket, '=>')
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.pseudo
|
63
|
+
[
|
64
|
+
Keyword.new(:class_self, 'self'),
|
65
|
+
Keyword.new(:class_prototype, '@'),
|
66
|
+
Keyword.new(:lambda_receiver, '@')
|
67
|
+
]
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.query
|
71
|
+
make_keywords(:from, :as, :join, :union, :on, :where, :order, :select, :limit, :take)
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.transfer
|
75
|
+
make_keywords(:exit, :return, :throw)
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
80
|
+
def self.make_keywords(*names)
|
81
|
+
names.map { |name| Keyword.new(name) }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Rip::Parser
|
2
|
+
class Location
|
3
|
+
attr_reader :origin # label where source code is coming from
|
4
|
+
attr_reader :offset # zero-based offset from begining of file
|
5
|
+
attr_reader :line # one-based line number
|
6
|
+
attr_reader :column # one-based character on line
|
7
|
+
attr_reader :length # how many characters are covered
|
8
|
+
|
9
|
+
def initialize(origin, offset, line, column, length = 0)
|
10
|
+
@origin = origin
|
11
|
+
@offset = offset
|
12
|
+
@line = line
|
13
|
+
@column = column
|
14
|
+
@length = length
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
(origin == other.origin) &&
|
19
|
+
(offset == other.offset)
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_character(count = 1)
|
23
|
+
self.class.new(origin, offset + count, line, column + count, length)
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_line(count = 1)
|
27
|
+
self.class.new(origin, offset + count, line + count, 1, length)
|
28
|
+
end
|
29
|
+
|
30
|
+
def inspect
|
31
|
+
"#<#{self.class.name} #{self}>"
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
"#{origin}:#{to_debug}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_debug
|
39
|
+
offset_length = length.zero? ? offset : (offset..(offset + length - 1))
|
40
|
+
"#{line}:#{column}(#{offset_length})"
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.from_slice(origin, slice, length = slice.length)
|
44
|
+
new(origin, slice.offset, *slice.line_and_column, length)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Rip::Parser
|
2
|
+
class Node
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_reader :location
|
6
|
+
attr_reader :type
|
7
|
+
attr_reader :extra
|
8
|
+
|
9
|
+
def initialize(location:, type:, **extra)
|
10
|
+
@location = location
|
11
|
+
@type = type
|
12
|
+
@extra = extra.inject({}) do |memo, (key, value)|
|
13
|
+
memo.merge(key => self.class.try_convert(value))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
to_h == other.to_h
|
19
|
+
end
|
20
|
+
|
21
|
+
def [](key)
|
22
|
+
case key.to_sym
|
23
|
+
when :location then location
|
24
|
+
when :type then type
|
25
|
+
else extra[key.to_sym]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def each(&block)
|
30
|
+
to_h.each(&block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def key?(key)
|
34
|
+
extra.key?(key.to_sym)
|
35
|
+
end
|
36
|
+
|
37
|
+
def keys
|
38
|
+
extra.keys
|
39
|
+
end
|
40
|
+
|
41
|
+
def length
|
42
|
+
location.length
|
43
|
+
end
|
44
|
+
|
45
|
+
def merge(other)
|
46
|
+
self.class.new(extra.merge(other.to_h).merge(location: location, type: other[:type] || type))
|
47
|
+
end
|
48
|
+
|
49
|
+
def s_expression
|
50
|
+
_extra = extra.map do |key, value|
|
51
|
+
[ key, self.class.try_convert_s_expression(value) ]
|
52
|
+
end.to_h
|
53
|
+
|
54
|
+
{ type: type }.merge(_extra)
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_h
|
58
|
+
_extra = extra.map do |key, value|
|
59
|
+
[ key, self.class.try_convert_to_h(value) ]
|
60
|
+
end.to_h
|
61
|
+
|
62
|
+
{ location: location, type: type }.merge(_extra)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def method_missing(missing_method, *args, &block)
|
68
|
+
case
|
69
|
+
when key?(missing_method)
|
70
|
+
extra[missing_method]
|
71
|
+
when missing_method.to_s.end_with?('?')
|
72
|
+
missing_method.to_s.sub(/\?\z/, '').to_sym == type
|
73
|
+
else
|
74
|
+
super
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def respond_to_missing?(name, include_all)
|
79
|
+
key?(name) || name.to_s.end_with?('?')
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.try_convert(value)
|
83
|
+
case value
|
84
|
+
when Array
|
85
|
+
value.map(&method(:try_convert))
|
86
|
+
when Hash
|
87
|
+
new(value)
|
88
|
+
else
|
89
|
+
value
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.try_convert_to_h(value)
|
94
|
+
case value
|
95
|
+
when Array
|
96
|
+
value.map(&method(:try_convert_to_h))
|
97
|
+
when self
|
98
|
+
value.to_h
|
99
|
+
else
|
100
|
+
value
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.try_convert_s_expression(value)
|
105
|
+
case value
|
106
|
+
when Array
|
107
|
+
value.map(&method(:try_convert_s_expression))
|
108
|
+
when self
|
109
|
+
value.s_expression
|
110
|
+
else
|
111
|
+
value
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
require_relative './common'
|
4
|
+
require_relative './expression'
|
5
|
+
require_relative './property'
|
6
|
+
require_relative './reference'
|
7
|
+
|
8
|
+
module Rip::Parser::Rules
|
9
|
+
module Assignment
|
10
|
+
include ::Parslet
|
11
|
+
|
12
|
+
include Rip::Parser::Rules::Common
|
13
|
+
include Rip::Parser::Rules::Expression
|
14
|
+
include Rip::Parser::Rules::Property
|
15
|
+
include Rip::Parser::Rules::Reference
|
16
|
+
|
17
|
+
rule(:reference_assignment) { reference.as(:lhs) >> assignment_rhs }
|
18
|
+
|
19
|
+
rule(:property_assignment) { (reference.as(:object) >> property).as(:lhs) >> assignment_rhs }
|
20
|
+
|
21
|
+
rule(:assignment_rhs) { spaces >> equals.as(:location) >> whitespaces >> expression.as(:rhs) }
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
require_relative './common'
|
4
|
+
require_relative './lambda'
|
5
|
+
require_relative './keyword'
|
6
|
+
|
7
|
+
module Rip::Parser::Rules
|
8
|
+
module BinaryCondition
|
9
|
+
include ::Parslet
|
10
|
+
|
11
|
+
include Rip::Parser::Rules::Common
|
12
|
+
include Rip::Parser::Rules::Lambda
|
13
|
+
include Rip::Parser::Rules::Keyword
|
14
|
+
|
15
|
+
rule(:binary_condition) do
|
16
|
+
keyword(:if) >> whitespaces? >>
|
17
|
+
parenthesis_open >> whitespaces? >>
|
18
|
+
expression.as(:condition) >>
|
19
|
+
parenthesis_close >> whitespaces? >>
|
20
|
+
block_body(:consequence) >> whitespaces? >>
|
21
|
+
keyword(:else) >> whitespaces? >> block_body(:alternative)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
require_relative './common'
|
4
|
+
require_relative './number'
|
5
|
+
require_relative './reference'
|
6
|
+
|
7
|
+
module Rip::Parser::Rules
|
8
|
+
module Character
|
9
|
+
include ::Parslet
|
10
|
+
|
11
|
+
include Rip::Parser::Rules::Common
|
12
|
+
include Rip::Parser::Rules::Number
|
13
|
+
include Rip::Parser::Rules::Reference
|
14
|
+
|
15
|
+
SPECIAL_ESCAPES = {
|
16
|
+
quote_single: "'",
|
17
|
+
quote_double: '"',
|
18
|
+
backslash: '\\',
|
19
|
+
bell: 'a',
|
20
|
+
backspace: 'b',
|
21
|
+
form_feed: 'f',
|
22
|
+
new_line: 'n',
|
23
|
+
carriage_return: 'r',
|
24
|
+
tab_horizontal: 't',
|
25
|
+
tab_vertical: 'v'
|
26
|
+
}
|
27
|
+
|
28
|
+
rule(:character) { backtick.as(:location) >> (escape_sequence | character_legal.as(:character)) }
|
29
|
+
|
30
|
+
rule(:character_legal) { digit | word_legal }
|
31
|
+
|
32
|
+
rule(:backtick) { str('`') }
|
33
|
+
|
34
|
+
rule(:escape_sequence) { slash_back.as(:escape_location) >> (escape_sequence_unicode | escape_sequence_special | escape_sequence_any) }
|
35
|
+
|
36
|
+
rule(:escape_sequence_unicode) { str('u') >> match['0-9a-f'].repeat(4, 4).as(:escape_unicode) }
|
37
|
+
rule(:escape_sequence_special) { SPECIAL_ESCAPES.values.map(&method(:str)).inject(&:|).as(:escape_special) }
|
38
|
+
rule(:escape_sequence_any) { match['\S'].as(:escape_any) }
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
require_relative './common'
|
4
|
+
require_relative './keyword'
|
5
|
+
require_relative './lambda'
|
6
|
+
require_relative './property'
|
7
|
+
require_relative './reference'
|
8
|
+
|
9
|
+
module Rip::Parser::Rules
|
10
|
+
module Class
|
11
|
+
include ::Parslet
|
12
|
+
|
13
|
+
include Rip::Parser::Rules::Common
|
14
|
+
include Rip::Parser::Rules::Keyword
|
15
|
+
include Rip::Parser::Rules::Lambda
|
16
|
+
include Rip::Parser::Rules::Property
|
17
|
+
include Rip::Parser::Rules::Reference
|
18
|
+
|
19
|
+
rule(:class_block) do
|
20
|
+
keyword(:class) >> spaces? >> class_ancestors.maybe >> whitespaces? >> brace_open >>
|
21
|
+
class_body.maybe.as(:body) >>
|
22
|
+
whitespaces? >> brace_close
|
23
|
+
end
|
24
|
+
|
25
|
+
rule(:class_ancestors) do
|
26
|
+
parenthesis_open >> whitespaces? >>
|
27
|
+
csv(reference).as(:ancestors) >>
|
28
|
+
whitespaces? >> parenthesis_close
|
29
|
+
end
|
30
|
+
|
31
|
+
rule(:class_body) do
|
32
|
+
whitespaces? >> class_property_assignment >> spaces? >> (
|
33
|
+
(semicolon | line_break) >> whitespaces? >> class_body
|
34
|
+
).repeat(0) >> whitespaces?
|
35
|
+
end
|
36
|
+
|
37
|
+
rule(:class_property_assignment) do
|
38
|
+
class_property.as(:property) >> spaces >>
|
39
|
+
equals.as(:location) >> whitespaces >>
|
40
|
+
property_value.as(:property_value)
|
41
|
+
end
|
42
|
+
|
43
|
+
rule(:class_property) do
|
44
|
+
keyword(:class_prototype) >> property |
|
45
|
+
keyword(:class_self) >> property |
|
46
|
+
word.as(:property_name)
|
47
|
+
end
|
48
|
+
|
49
|
+
rule(:property_value) do
|
50
|
+
import |
|
51
|
+
class_block |
|
52
|
+
lambda_block |
|
53
|
+
overload_block |
|
54
|
+
property_block |
|
55
|
+
expression
|
56
|
+
end
|
57
|
+
|
58
|
+
rule(:property_block) { keyword(:swerve_rocket) >> whitespaces? >> block_body }
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
module Rip::Parser::Rules
|
4
|
+
module Common
|
5
|
+
include ::Parslet
|
6
|
+
|
7
|
+
rule(:whitespace) { space | line_break | comment }
|
8
|
+
rule(:whitespaces) { whitespace.repeat(1) }
|
9
|
+
rule(:whitespaces?) { whitespaces.maybe }
|
10
|
+
|
11
|
+
rule(:space) { str(' ') | str("\t") }
|
12
|
+
rule(:spaces) { space.repeat(1) }
|
13
|
+
rule(:spaces?) { spaces.maybe }
|
14
|
+
|
15
|
+
rule(:line_break) { str("\r\n") | str("\n") | str("\r") }
|
16
|
+
rule(:line_breaks) { line_break.repeat(1) }
|
17
|
+
rule(:line_breaks?) { line_breaks.maybe }
|
18
|
+
|
19
|
+
rule(:comment) { pound >> (line_break.absent? >> any).repeat >> (line_break | eof) }
|
20
|
+
|
21
|
+
rule(:eof) { any.absent? }
|
22
|
+
|
23
|
+
rule(:dot) { str('.') }
|
24
|
+
rule(:comma) { str(',') }
|
25
|
+
rule(:semicolon) { str(';') }
|
26
|
+
rule(:colon) { str(':') }
|
27
|
+
rule(:pound) { str('#') }
|
28
|
+
rule(:dash) { str('-') }
|
29
|
+
rule(:underscore) { str('_') }
|
30
|
+
rule(:equals) { str('=') }
|
31
|
+
|
32
|
+
rule(:slash_back) { str('\\') }
|
33
|
+
rule(:slash_forward) { str('/') }
|
34
|
+
|
35
|
+
rule(:angled_open) { str('<') }
|
36
|
+
rule(:angled_close) { str('>') }
|
37
|
+
|
38
|
+
rule(:brace_open) { str('{') }
|
39
|
+
rule(:brace_close) { str('}') }
|
40
|
+
|
41
|
+
rule(:bracket_open) { str('[') }
|
42
|
+
rule(:bracket_close) { str(']') }
|
43
|
+
|
44
|
+
rule(:parenthesis_open) { str('(') }
|
45
|
+
rule(:parenthesis_close) { str(')') }
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
require_relative './common'
|
4
|
+
require_relative './number'
|
5
|
+
|
6
|
+
module Rip::Parser::Rules
|
7
|
+
module DateTime
|
8
|
+
include ::Parslet
|
9
|
+
|
10
|
+
include Rip::Parser::Rules::Common
|
11
|
+
include Rip::Parser::Rules::Number
|
12
|
+
|
13
|
+
rule(:date_time) { date.as(:date) >> str('T') >> time.as(:time) }
|
14
|
+
|
15
|
+
rule(:date) do
|
16
|
+
digit.repeat(4, 4).as(:year) >> dash >>
|
17
|
+
digit.repeat(2, 2).as(:month) >> dash >>
|
18
|
+
digit.repeat(2, 2).as(:day)
|
19
|
+
end
|
20
|
+
|
21
|
+
rule(:time) do
|
22
|
+
digit.repeat(2, 2).as(:hour) >> colon >>
|
23
|
+
digit.repeat(2, 2).as(:minute) >> colon >>
|
24
|
+
digit.repeat(2, 2).as(:second) >>
|
25
|
+
(dot >> digits.as(:sub_second)).maybe >>
|
26
|
+
(
|
27
|
+
sign >> digit.repeat(2, 2).as(:hour) >> digit.repeat(2, 2).as(:minute)
|
28
|
+
).as(:offset).maybe
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
require_relative './binary_condition'
|
4
|
+
require_relative './class'
|
5
|
+
require_relative './character'
|
6
|
+
require_relative './common'
|
7
|
+
require_relative './date_time'
|
8
|
+
require_relative './import'
|
9
|
+
require_relative './invocation'
|
10
|
+
require_relative './invocation_index'
|
11
|
+
require_relative './keyword'
|
12
|
+
require_relative './lambda'
|
13
|
+
require_relative './list'
|
14
|
+
require_relative './map'
|
15
|
+
require_relative './number'
|
16
|
+
require_relative './pair'
|
17
|
+
require_relative './property'
|
18
|
+
require_relative './range'
|
19
|
+
require_relative './reference'
|
20
|
+
require_relative './string'
|
21
|
+
require_relative './unit'
|
22
|
+
|
23
|
+
module Rip::Parser::Rules
|
24
|
+
module Expression
|
25
|
+
include ::Parslet
|
26
|
+
|
27
|
+
include Rip::Parser::Rules::BinaryCondition
|
28
|
+
|
29
|
+
include Rip::Parser::Rules::Common
|
30
|
+
|
31
|
+
include Rip::Parser::Rules::Class
|
32
|
+
|
33
|
+
include Rip::Parser::Rules::DateTime
|
34
|
+
|
35
|
+
include Rip::Parser::Rules::Number
|
36
|
+
|
37
|
+
include Rip::Parser::Rules::Character
|
38
|
+
include Rip::Parser::Rules::String
|
39
|
+
|
40
|
+
include Rip::Parser::Rules::Lambda
|
41
|
+
|
42
|
+
include Rip::Parser::Rules::List
|
43
|
+
|
44
|
+
include Rip::Parser::Rules::Keyword
|
45
|
+
|
46
|
+
include Rip::Parser::Rules::Import
|
47
|
+
|
48
|
+
include Rip::Parser::Rules::Invocation
|
49
|
+
include Rip::Parser::Rules::InvocationIndex
|
50
|
+
|
51
|
+
include Rip::Parser::Rules::Map
|
52
|
+
|
53
|
+
include Rip::Parser::Rules::Pair
|
54
|
+
|
55
|
+
include Rip::Parser::Rules::Property
|
56
|
+
|
57
|
+
include Rip::Parser::Rules::Range
|
58
|
+
|
59
|
+
include Rip::Parser::Rules::Reference
|
60
|
+
|
61
|
+
include Rip::Parser::Rules::Unit
|
62
|
+
|
63
|
+
rule(:expression) { expression_chain }
|
64
|
+
|
65
|
+
rule(:expression_chain) do
|
66
|
+
(
|
67
|
+
(
|
68
|
+
expression_base |
|
69
|
+
(parenthesis_open >> whitespaces? >> expression_chain >> whitespaces? >> parenthesis_close)
|
70
|
+
) >> expression_link.repeat
|
71
|
+
).as(:expression_chain)
|
72
|
+
end
|
73
|
+
|
74
|
+
rule(:expression_base) do
|
75
|
+
import |
|
76
|
+
|
77
|
+
class_block |
|
78
|
+
|
79
|
+
lambda_block |
|
80
|
+
overload_block |
|
81
|
+
|
82
|
+
# enum_block |
|
83
|
+
|
84
|
+
binary_condition |
|
85
|
+
|
86
|
+
# switch_block |
|
87
|
+
|
88
|
+
# exception_block_sequence |
|
89
|
+
|
90
|
+
date_time |
|
91
|
+
date |
|
92
|
+
time |
|
93
|
+
|
94
|
+
unit |
|
95
|
+
|
96
|
+
# version | # maybe
|
97
|
+
|
98
|
+
number |
|
99
|
+
|
100
|
+
character |
|
101
|
+
|
102
|
+
string |
|
103
|
+
regular_expression |
|
104
|
+
|
105
|
+
# markup_fragment |
|
106
|
+
|
107
|
+
list |
|
108
|
+
|
109
|
+
map |
|
110
|
+
|
111
|
+
reference
|
112
|
+
end
|
113
|
+
|
114
|
+
rule(:expression_link) do
|
115
|
+
property |
|
116
|
+
pair_value |
|
117
|
+
range_end |
|
118
|
+
invocation |
|
119
|
+
invocation_index
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|