erle 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ module ERLE
2
+
3
+ class List < Enum
4
+ enclosure /\[/, /\]/
5
+ @delimeter = ','
6
+
7
+ end
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+ module ERLE
2
+
3
+ class Map < Enum
4
+ enclosure /\#\{/, /\}/
5
+ @delimeter = ','
6
+
7
+ end
8
+
9
+ end
@@ -0,0 +1,26 @@
1
+ module ERLE
2
+
3
+ class Number < Term
4
+
5
+ end
6
+
7
+ class Float < Number
8
+ pattern %r{[-0-9]\.[0-9]+}
9
+
10
+ def to_ruby
11
+ @output ||= @input.to_f
12
+ end
13
+
14
+ end
15
+
16
+ class Integer < Number
17
+
18
+ pattern %r{(-?0|-?[1-9]\d*)}
19
+
20
+ def to_ruby
21
+ @output ||= @input.to_i
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,22 @@
1
+ module ERLE
2
+
3
+ # http://erlang.org/doc/reference_manual/data_types.html#id68255
4
+ class Pid < Term
5
+
6
+ class Data < ::String
7
+
8
+ def to_erl
9
+ "<#{self}>"
10
+ end
11
+ end
12
+
13
+ enclosure /</, />/
14
+ pattern %r{[-0-9](\.[0-9])+}
15
+ # @delimeter = '.'
16
+
17
+ def to_ruby
18
+ @output ||= Data.new(@input)
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,37 @@
1
+ module ERLE
2
+
3
+ class Ref < Term
4
+ enclosure /\#Ref</, />/
5
+
6
+ @delimeter = "."
7
+
8
+ @pattern = %r{(?:(\d+)\.?)+}
9
+
10
+ def initialize(input)
11
+ @input = input
12
+ end
13
+
14
+ # TODO: Leverage Enum, and refactor (Enum) to handle conflicting delimiters
15
+ # e.g. a "." delimeter is preempted by the "float" pattern.
16
+ def to_ruby
17
+ @output ||= @input.split(".")
18
+ end
19
+
20
+ def self.parse(parser)
21
+
22
+ result = parser.scan(@pattern)
23
+
24
+ if close && !parser.scan(close)
25
+ raise parser.raise_unexpected_token("Expected term closure \" #{close.source} \"")
26
+ end
27
+
28
+ # Make sure we kill any trailing close
29
+ # TODO: Consider raising if no match?
30
+ # TODO: Consider doing only if we started with an opening...
31
+ # parser.scan(ERLE::Registry.closings_regex)
32
+ new(result)
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,33 @@
1
+ module ERLE
2
+
3
+ class String < Term
4
+ enclosure /\"/
5
+ # pattern %r{((?:[^\x0-\x1f'\\] |
6
+ # # escaped special characters:
7
+ # \\["/bfnrt] |
8
+ # \\u[0-9a-fA-F]{4} |
9
+ # # match all but escaped special characters:
10
+ # \\[\x20-\x21\x23-\x2e\x30-\x5b\x5d-\x61\x63-\x65\x67-\x6d\x6f-\x71\x73\x75-\xff])*)
11
+ # }nx
12
+
13
+ PATTERN = %r{[^\"]*}nx
14
+
15
+ def to_ruby
16
+ # self.str.gsub(/"/,"")
17
+ @output ||= @input
18
+ end
19
+
20
+ def self.parse(parser)
21
+ opener = parser.matched == "\""
22
+
23
+ parser.scan(PATTERN)
24
+ result = parser.matched
25
+
26
+ parser.scan(close) if opener
27
+
28
+ new(result)
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,71 @@
1
+ module ERLE
2
+
3
+ class Term
4
+
5
+ class << self
6
+ attr_accessor :open, :close, :patterns
7
+ end
8
+
9
+ attr_accessor :input
10
+ attr_accessor :output
11
+
12
+
13
+ def self.patterns
14
+ @patterns ||= Set.new
15
+ end
16
+
17
+ def self.pattern(p)
18
+ patterns.add(p)
19
+ ERLE::Registry.pattern(self, p)
20
+ end
21
+
22
+ def self.enclosure(one, two=one)
23
+ @open = one.freeze
24
+ @close = two.freeze
25
+ ERLE::Registry.enclosure(self, one, two)
26
+ end
27
+
28
+ def initialize(input)
29
+ @input = input
30
+ end
31
+
32
+ def to_ruby
33
+ @input
34
+ end
35
+
36
+ def self.to_ruby(value)
37
+ case value
38
+ when Term
39
+ value.to_ruby
40
+ else
41
+ value
42
+ end
43
+ end
44
+
45
+ def self.until_any_closing
46
+ @until_any_closing ||= Regexp.new("[^#{ERLE::Registry.closings_regex.source}]*")
47
+ end
48
+
49
+ def self.parse(parser)
50
+
51
+ patterns.find do |pattern|
52
+ parser.scan(pattern)
53
+ end
54
+
55
+ result = parser.matched
56
+
57
+ if close && !parser.scan(close)
58
+ raise parser.raise_unexpected_token("Expected term closure \" #{close.source} \"")
59
+ end
60
+
61
+ # # Make sure we kill any trailing close
62
+ # # TODO: Consider raising if no match?
63
+ # # TODO: Consider doing only if we started with an opening...
64
+ # parser.scan(ERLE::Registry.closings_regex)
65
+ # # binding.pry
66
+ new(result)
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,37 @@
1
+ module ERLE
2
+
3
+ class Tuple < Enum
4
+ enclosure /\{/, /\}/
5
+ @delimeter = ','
6
+
7
+ attr_accessor :key
8
+
9
+ def initialize(elements)
10
+ super
11
+ @key = Term.to_ruby(@terms.shift)
12
+ end
13
+
14
+ def to_ruby
15
+ @output ||= { @key => one_or_all(terms_to_ruby) }
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+
22
+ module ERLE
23
+
24
+ class Luple < Enum
25
+ # register "[{", "}]"
26
+
27
+ def to_ruby
28
+ # @output = Enum.split("},{")
29
+ # arr = @output.map {|el|
30
+ # el.is_a?(Term) ? el.to_ruby : el
31
+ # }
32
+ # key = arr.delete_at(0)
33
+ # hash = {key => ( arr.length>1 ? arr: arr[0])}
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,12 @@
1
+ module ERLE
2
+
3
+ class Error < StandardError
4
+ end
5
+
6
+ class ParserError < ERLE::Error
7
+ end
8
+
9
+ class NestingError < ParserError
10
+ end
11
+
12
+ end
@@ -0,0 +1,122 @@
1
+
2
+ require 'erle/registry'
3
+
4
+ module ERLE
5
+
6
+ class Parser < StringScanner
7
+
8
+ UNPARSED = Object.new.freeze
9
+ IGNORE = %r(
10
+ (?:
11
+ //[^\n\r]*[\n\r]| # line comments
12
+ /\* # c-style comments
13
+ (?:
14
+ [^*/]| # normal chars
15
+ /[^*]| # slashes that do not start a nested comment
16
+ \*[^/]| # asterisks that do not end this comment
17
+ /(?=\*/) # single slash before this comment's end
18
+ )*
19
+ \*/ # the End of this comment
20
+ |[ \t\r\n]+ # whitespaces: space, horicontal tab, lf, cr
21
+ )+
22
+ )mx
23
+
24
+ INTEGER = /(-?0|-?[1-9]\d*)/
25
+ FLOAT = /(-?
26
+ (?:0|[1-9]\d*)
27
+ (?:
28
+ \.\d+(?i:e[+-]?\d+) |
29
+ \.\d+ |
30
+ (?i:e[+-]?\d+)
31
+ )
32
+ )/x
33
+ TRUE = /true/
34
+ FALSE = /false/
35
+
36
+ def initialize(source, opts = {})
37
+ opts ||= {}
38
+ # source = convert_encoding source
39
+ super source
40
+ end
41
+
42
+ alias source string
43
+
44
+ def parse
45
+ reset
46
+ obj = nil
47
+
48
+ until_done do
49
+ if eos?
50
+ raise_parsing_error
51
+ else
52
+ obj = parse_value
53
+ UNPARSED.equal?(obj) and raise_parsing_error
54
+ end
55
+ end
56
+
57
+ eos? or raise_parsing_error
58
+ obj
59
+ end
60
+
61
+ def skip_ignore
62
+ skip(IGNORE)
63
+ end
64
+
65
+ def until_done
66
+ result = nil
67
+ while !eos?
68
+ skip_ignore
69
+ result = yield if block_given?
70
+ skip_ignore
71
+ end
72
+ result
73
+ end
74
+
75
+ def peekaboo(peek = 30, back = 30)
76
+ string[pos-back, peek+back]
77
+ end
78
+
79
+ def raise_parsing_error(message = "source is not valid Erlang!")
80
+ # warn "Parsing =>\n#{string}"
81
+ raise ParserError, "Parsing =>\n#{string}\n#{message}"
82
+ end
83
+
84
+ def whereami?(peek = 30, back = 30)
85
+ back = [back, string.length - pos].sort[0]
86
+ "#{peekaboo(peek, back)}'\n#{"─" * (back)}┘"
87
+ end
88
+
89
+ def raise_unexpected_token(followup=nil)
90
+ message = "Unexpected token at:\n#{whereami?}"
91
+ message += "\n#{followup}" if followup
92
+ raise ParserError, message
93
+ end
94
+
95
+ def parse_value
96
+ # TODO: handle symbols
97
+ skip_ignore
98
+
99
+ case
100
+ when scan(TRUE)
101
+ true
102
+ when scan(FALSE)
103
+ false
104
+ when !eos? && scan(ERLE::Registry.openings_regex) # TODO: Take out !eos?
105
+ regex, term_class = ERLE::Registry.open_find(matched)
106
+ term_str = term_class.parse(self)
107
+ else
108
+ term_class, regex = ERLE::Registry.pattern_find do |p|
109
+ match?(p)
110
+ end
111
+
112
+ if term_class
113
+ term_class.parse(self)
114
+ else
115
+ UNPARSED
116
+ end
117
+ end
118
+ end
119
+
120
+ end
121
+
122
+ end
@@ -0,0 +1,71 @@
1
+ module ERLE
2
+
3
+ module Registry
4
+ class << self
5
+ attr_accessor :_enclosures
6
+ attr_accessor :_patterns
7
+ end
8
+
9
+ @_enclosures = {}
10
+ @_patterns = {}
11
+
12
+ def self.enclosure(klass, one, two)
13
+ @_enclosures[one] = klass
14
+ end
15
+
16
+ def self.pattern(klass, pat)
17
+ (@_patterns[klass] ||= Set.new).add(pat)
18
+ end
19
+
20
+ def self.pattern_find
21
+ return unless block_given?
22
+ @_patterns.each do |klass, patterns|
23
+ pattern = patterns.find do |pattern|
24
+ yield(pattern)
25
+ end
26
+ return [klass, pattern] if pattern
27
+ end
28
+ nil
29
+ end
30
+
31
+ def self.open_find(str)
32
+ sorted_encolsures.find do |k, v|
33
+ str =~ k
34
+ end
35
+ end
36
+
37
+ def self.sorted_encolsures
38
+ @sorted_encolsures ||= @_enclosures.sort_by { |pattern, klass| pattern.source.length }.reverse.to_h
39
+ end
40
+
41
+ def self.openings
42
+ @openings ||= sorted_encolsures.keys
43
+ end
44
+
45
+ def self.openings_source
46
+ @openings_source ||= openings.map(&:source)
47
+ end
48
+
49
+ def self.openings_regex
50
+ @openings_regex ||= Regexp.new("(#{openings_source.join('|')})")
51
+ end
52
+
53
+ # def self.close_find(str)
54
+ # @_enclosures.values.find do |klass|
55
+ # str =~ klass.close
56
+ # end
57
+ # end
58
+
59
+ # def self.closings
60
+ # @closings ||= @_enclosures.values.collect(&:close).sort { |a, b| b.source.length <=> a.source.length }
61
+ # end
62
+
63
+ # def self.closings_source
64
+ # @closings_source ||= closings.map(&:source)
65
+ # end
66
+
67
+ # def self.closings_regex
68
+ # @closings_regex ||= Regexp.new("(#{closings_source.join('|')})")
69
+ # end
70
+ end
71
+ end