modl 0.3.26 → 0.3.28

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -149
  3. data/Gemfile +4 -2
  4. data/LICENSE.txt +1 -1
  5. data/README.md +19 -11
  6. data/Rakefile +5 -3
  7. data/lib/modl/interpreter.rb +38 -0
  8. data/lib/modl/model/model.rb +264 -0
  9. data/lib/modl/parser/parser.rb +280 -59
  10. data/lib/modl/tokeniser/context.rb +113 -0
  11. data/lib/modl/tokeniser/tokeniser.rb +28 -0
  12. data/lib/modl/util/functions.rb +74 -0
  13. data/lib/modl/util/unicode.rb +44 -0
  14. data/lib/modl/version.rb +5 -0
  15. data/lib/modl.rb +7 -32
  16. data/modl.gemspec +8 -11
  17. metadata +16 -75
  18. data/.DS_Store +0 -0
  19. data/.idea/vcs.xml +0 -6
  20. data/.rspec +0 -3
  21. data/.rubocop.yml +0 -5
  22. data/.travis.yml +0 -7
  23. data/bin/console +0 -14
  24. data/bin/setup +0 -8
  25. data/lib/modl/parser/MODLLexer.interp +0 -132
  26. data/lib/modl/parser/MODLLexer.rb +0 -324
  27. data/lib/modl/parser/MODLLexer.tokens +0 -40
  28. data/lib/modl/parser/MODLParser.interp +0 -93
  29. data/lib/modl/parser/MODLParser.rb +0 -2492
  30. data/lib/modl/parser/MODLParser.tokens +0 -40
  31. data/lib/modl/parser/MODLParserBaseListener.rb +0 -164
  32. data/lib/modl/parser/MODLParserBaseVisitor.rb +0 -107
  33. data/lib/modl/parser/MODLParserListener.rb +0 -151
  34. data/lib/modl/parser/MODLParserVisitor.rb +0 -56
  35. data/lib/modl/parser/class_processor.rb +0 -411
  36. data/lib/modl/parser/evaluator.rb +0 -125
  37. data/lib/modl/parser/file_importer.rb +0 -101
  38. data/lib/modl/parser/global_parse_context.rb +0 -318
  39. data/lib/modl/parser/instruction_processor.rb +0 -82
  40. data/lib/modl/parser/interpreter.rb +0 -75
  41. data/lib/modl/parser/modl_class.rb +0 -138
  42. data/lib/modl/parser/modl_index.rb +0 -54
  43. data/lib/modl/parser/modl_keylist.rb +0 -81
  44. data/lib/modl/parser/modl_method.rb +0 -172
  45. data/lib/modl/parser/object_cache.rb +0 -88
  46. data/lib/modl/parser/orphan_handler.rb +0 -98
  47. data/lib/modl/parser/parsed.rb +0 -1469
  48. data/lib/modl/parser/ref_processor.rb +0 -258
  49. data/lib/modl/parser/substitutions.rb +0 -101
  50. data/lib/modl/parser/sutil.rb +0 -108
  51. data/lib/modl/parser/throwing_error_listener.rb +0 -44
  52. data/lib/modl/parser/unicode_escape_replacer.rb +0 -148
  53. data/lib/modl/parser/unicode_escapes.rb +0 -112
  54. data/lib/modl/parser/version.rb +0 -29
@@ -1,72 +1,293 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # The MIT License (MIT)
4
- #
5
- # Copyright (c) 2019 NUM Technology Ltd
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining a copy
8
- # of this software and associated documentation files (the "Software"), to deal
9
- # in the Software without restriction, including without limitation the rights
10
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- # copies of the Software, and to permit persons to whom the Software is
12
- # furnished to do so, subject to the following conditions:
13
- #
14
- # The above copyright notice and this permission notice shall be included in
15
- # all copies or substantial portions of the Software.
16
- #
17
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- # THE SOFTWARE.
24
-
25
- require 'modl/parser/throwing_error_listener'
26
- require 'modl/parser/parsed'
27
-
28
3
  module MODL
4
+ # A Parser module
29
5
  module Parser
6
+ REPLACEMENTS = {
7
+ '\t' => "\t",
8
+ '\n' => "\n",
9
+ '\b' => "\b",
10
+ '\f' => "\f",
11
+ '\r' => "\r",
12
+ '~t' => "\t",
13
+ '~n' => "\n",
14
+ '~b' => "\b",
15
+ '~f' => "\f",
16
+ '~r' => "\r",
17
+ '~\\' => '\\',
18
+ '\\\\' => '\\',
19
+ '~~' => '~',
20
+ '\~' => '~',
21
+ '~(' => '(',
22
+ '\(' => '(',
23
+ '~)' => ')',
24
+ '\)' => ')',
25
+ '~[' => '[',
26
+ '\[' => '[',
27
+ '~]' => ']',
28
+ '\]' => ']',
29
+ '~;' => ';',
30
+ '\;' => ';',
31
+ '~`' => '`',
32
+ '\`' => '`',
33
+ '~"' => '"',
34
+ '"' => '"',
35
+ '~=' => '=',
36
+ '\=' => '='
37
+ }.freeze
38
+
39
+ def self.parse_modl(str)
40
+ tokens = MODL::Tokeniser.tokenise str
41
+ if tokens.nil? || tokens.empty?
42
+ MODL::Model::Modl.new nil
43
+ elsif root_primitive? tokens[0]
44
+ MODL::Model::Modl.new tokens[0].value
45
+ else
46
+ result = parse_structures(tokens)
47
+ return MODL::Model::Modl.new result[0] if result.length == 1
48
+
49
+ return MODL::Model::Modl.new MODL::Model::ModlMap.new(result) if all_pairs?(result)
50
+
51
+ MODL::Model::Modl.new MODL::Model::ModlArray.new(result)
52
+ end
53
+ end
54
+
55
+ def self.root_primitive?(token)
56
+ %i[string quoted null true false integer float].include?(token)
57
+ end
58
+
59
+ def self.parse_structures(tokens)
60
+ result = []
61
+ until tokens.empty?
62
+ result.push parse_modl_value(tokens)
63
+ expect_separator = tokens.shift
64
+ if !expect_separator.nil? && expect_separator.type != :struct_sep
65
+ raise ParserError, "Expected ';' near #{tokens}"
66
+ end
67
+ end
68
+ result
69
+ end
70
+
71
+ def self.parse_modl_value(tokens)
72
+ first_token = tokens.shift
73
+
74
+ case first_token.type
75
+ when :lbracket
76
+ tokens.unshift first_token
77
+ return parse_modl_array tokens
78
+ when :lparen
79
+ tokens.unshift first_token
80
+ return parse_modl_map tokens
81
+ when :string || :quoted
82
+ peek = tokens[0]
83
+ key = first_token.value
84
+ if !peek.nil? && peek.type == :equals
85
+ tokens.shift
86
+ return MODL::Model::ModlPair.new replace_escapes(unquote(key)), parse_pair_value(tokens)
87
+ end
88
+
89
+ if !peek.nil? && (peek.type == :lbracket || peek.type == :lparen)
90
+ return MODL::Model::ModlPair.new replace_escapes(unquote(key)), parse_pair_value(tokens)
91
+ end
92
+
93
+ if peek.nil? || peek.type == :struct_sep || peek.type == :rparen || peek.type == :rbracket
94
+ return MODL::Model::ModlString.new(replace_escapes(first_token.value)) if first_token.type == :string
30
95
 
31
- # This class converts the input string into a Modl:Parser::Parsed object for further processing.
32
- class Parser
33
- def self.parse(str, global = nil)
34
- begin
35
- lexer = MODL::Parser::MODLLexer.new(Antlr4::Runtime::CharStreams.from_string(str, 'String'))
36
- lexer.remove_error_listeners
37
- lexer.add_error_listener ThrowingErrorListener.instance
38
-
39
- tokens = Antlr4::Runtime::CommonTokenStream.new(lexer)
40
-
41
- parser = MODL::Parser::MODLParser.new(tokens)
42
- parser.remove_error_listeners
43
- parser.add_error_listener ThrowingErrorListener.instance
44
-
45
- global = GlobalParseContext.new if global.nil?
46
-
47
- parsed = Parsed.new(global)
48
- parser.modl.enter_rule(parsed)
49
- parsed
50
- rescue Antlr4::Runtime::ParseCancellationException => e
51
- check_modl_version(global, e)
52
- raise ParserError, 'Parser Error: ' + e.message
53
- rescue StandardError => e
54
- check_modl_version(global, e)
55
- raise InterpreterError, 'Interpreter Error: ' + e.message
56
- rescue InterpreterError => e
57
- check_modl_version(global, e)
58
- raise InterpreterError, 'Interpreter Error: ' + e.message
96
+ return MODL::Model::ModlQuoted.new(replace_escapes(unquote(first_token.value)))
59
97
  end
98
+ when :integer
99
+ return MODL::Model::ModlInteger.new first_token.value
100
+ when :float
101
+ return MODL::Model::ModlFloat.new first_token.value
102
+ when :null
103
+ return MODL::Model::ModlBoolNull::MODL_NULL
104
+ when true
105
+ return MODL::Model::ModlBoolNull::MODL_TRUE
106
+ when false
107
+ return MODL::Model::ModlBoolNull::MODL_FALSE
108
+ else
109
+ tokens.unshift first_token
110
+ maybe_primitive = parse_primitive tokens
111
+ return maybe_primitive unless maybe_primitive.nil?
60
112
  end
113
+ raise ParserError, "Unexpected token: \'#{first_token}\'"
114
+ end
115
+
116
+ def self.parse_pair_value(tokens)
117
+ first_token = tokens.shift
118
+ case first_token.type
119
+ when :lbracket
120
+ tokens.unshift first_token
121
+ return parse_modl_array tokens
122
+ when :lparen
123
+ tokens.unshift first_token
124
+ return parse_modl_map tokens
125
+ when :string || :quoted
126
+ peek = tokens[0]
127
+
128
+ raise ParserError, "Unexpected token: \'#{first_token}\'" if !peek.nil? && peek.type == :equals
129
+
130
+ if !peek.nil? && (peek.type == :lbracket || peek.type == :lparen)
131
+ raise ParserError, "Unexpected token: \'#{first_token}\'"
132
+ end
133
+
134
+ if peek.nil? || peek.type == :struct_sep || peek.type == :rparen || peek.type == :rbracket
135
+ return MODL::Model::ModlString.new replace_escapes(first_token.value) if first_token.type == :string
61
136
 
62
- def self.check_modl_version(global, e)
63
- if global.syntax_version > global.interpreter_syntax_version
64
- raise InterpreterError, 'Interpreter Error: ' + e.message + ' - MODL Version ' +
65
- global.interpreter_syntax_version.to_s +
66
- ' interpreter cannot process this MODL Version ' +
67
- global.syntax_version.to_s + ' file.'
137
+ return MODL::Model::ModlQuoted.new replace_escapes(unquote(first_token.value))
68
138
  end
139
+ raise ParserError, "Unexpected token: \'#{first_token}\'"
140
+ when :integer
141
+ return MODL::Model::ModlInteger.new first_token.value
142
+ when :float
143
+ return MODL::Model::ModlFloat.new first_token.value
144
+ when :null
145
+ return MODL::Model::ModlBoolNull::MODL_NULL
146
+ when true
147
+ return MODL::Model::ModlBoolNull::MODL_TRUE
148
+ when false
149
+ return MODL::Model::ModlBoolNull::MODL_FALSE
150
+ else
151
+ tokens.unshift first_token
152
+ maybe_primitive = parse_primitive tokens
153
+ return maybe_primitive unless maybe_primitive.nil?
154
+ end
155
+ raise ParserError, "Unexpected token: \'#{first_token}\'"
156
+ end
157
+
158
+ def self.parse_primitive(tokens)
159
+ result = nil
160
+ tok = tokens.shift
161
+
162
+ case tok.type
163
+ when :lparen || :rparen || :lbracket || :rbracket || :equals
164
+ raise ParserError, "Unexpected token: \'#{tok}\'" if tokens.empty?
165
+
166
+ tokens.unshift tok
167
+ return nil
168
+ when :null
169
+ result = MODL::Model::ModlBoolNull::MODL_NULL
170
+ when true
171
+ result = MODL::Model::ModlBoolNull::MODL_TRUE
172
+ when false
173
+ result = MODL::Model::ModlBoolNull::MODL_FALSE
174
+ when :quoted
175
+ result = MODL::Model::ModlQuoted.new replace_escapes(unquote(tok.value))
176
+ when :string
177
+ result = MODL::Model::ModlString.new replace_escapes(tok.value)
178
+ when :integer
179
+ result = MODL::Model::ModlInteger.new tok.value
180
+ when :float
181
+ result = MODL::Model::ModlFloat.new tok.value
182
+ else
183
+ raise ParserError, "Unknown token type in: \'#{tok}\'"
184
+ end
185
+
186
+ peek = tokens[0]
187
+ raise ParserError, 'Only one primitive allowed at the root.' if !peek.nil? && peek.type == :struct_sep
188
+
189
+ if !peek.nil? && (peek.type == :lparen || peek.type == :lbracket || peek.type == :equals)
190
+ s.unshift tok
191
+ return nil
192
+ elsif !peek.nil?
193
+ raise ParserError, "Unexpected token: \'#{peek}\'"
69
194
  end
195
+ result
196
+ end
197
+
198
+ def self.parse_modl_map(tokens)
199
+ first_token = tokens.shift
200
+ entries = []
201
+
202
+ until tokens.empty?
203
+ peek = tokens[0]
204
+ if !peek.nil? && peek.type == :rparen
205
+ tokens.shift
206
+ break
207
+ end
208
+
209
+ mp = parse_modl_value tokens
210
+ entries.push mp
211
+
212
+ peek = tokens[0]
213
+
214
+ raise ParserError, "Expected ')' near #{first_token}" if peek.nil?
215
+
216
+ case peek.type
217
+ when :rparen
218
+ tokens.shift
219
+ break
220
+ when :struct_sep
221
+ tokens.shift
222
+ peek = tokens[0]
223
+ raise ParserError, "Unexpected ; before ] at #{peek}" if !peek.nil? && peek.type == :rparen
224
+ end
225
+ end
226
+ MODL::Model::ModlMap.new entries
227
+ end
228
+
229
+ def self.parse_modl_array(tokens)
230
+ first_token = tokens.shift
231
+ entries = []
232
+
233
+ until tokens.empty?
234
+ peek = tokens[0]
235
+ if !peek.nil? && peek.type == :rbracket
236
+ tokens.shift
237
+ break
238
+ end
239
+
240
+ mp = parse_modl_value tokens
241
+ entries.push mp
242
+
243
+ peek = tokens[0]
244
+
245
+ raise ParserError, "Expected ']' near #{first_token}" if peek.nil?
246
+
247
+ case peek.type
248
+ when :rbracket
249
+ tokens.shift
250
+ break
251
+ when :struct_sep
252
+ tokens.shift
253
+ peek = tokens[0]
254
+ raise ParserError, "Unexpected ; before ] at #{peek}" if !peek.nil? && peek.type == :rparen
255
+ end
256
+ end
257
+ MODL::Model::ModlArray.new entries
258
+ end
259
+
260
+ def self.unquote(str)
261
+ return str unless str.instance_of?(String)
262
+
263
+ if (str.start_with?('`') && str.end_with?('`')) || (str.start_with?('"') && str.end_with?('"'))
264
+ str[1..-2]
265
+ else
266
+ str
267
+ end
268
+ end
269
+
270
+ def self.replace_escapes(str)
271
+ return str unless str.instance_of?(String)
272
+
273
+ result = str
274
+ i = 0
275
+ while i < str.length
276
+ REPLACEMENTS.each_pair do |key, value|
277
+ if result.slice(i..).start_with?(key)
278
+ result = result.sub(key, value)
279
+ break
280
+ end
281
+ end
282
+ i += 1
283
+ end
284
+ result
285
+ end
286
+
287
+ def self.all_pairs?(arr)
288
+ result = true
289
+ arr.each { |i| result = false unless i.instance_of? MODL::Model::ModlPair }
290
+ result
70
291
  end
71
292
  end
72
293
  end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MODL
4
+ module Tokeniser
5
+ # A parsing context for a MODL String
6
+ class Context
7
+ WS = " \t\r\n"
8
+ INTEGER_REGEX = '^-?(?:0|[1-9]\d*)$'
9
+ FLOAT_REGEX = '^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$'
10
+ NON_STRING_TOKENS = '[]();"=`'
11
+
12
+ def initialize(str)
13
+ @str = str
14
+ @tokens = []
15
+ @tok_start = 0
16
+ end
17
+
18
+ def parse
19
+ while next_token
20
+ end
21
+ @tokens
22
+ end
23
+
24
+ def next_token
25
+ while @tok_start < @str.length
26
+ break unless WS.include?(@str[@tok_start])
27
+
28
+ @tok_start += 1
29
+ end
30
+
31
+ return false if @tok_start >= @str.length
32
+
33
+ case @str[@tok_start]
34
+ when '('
35
+ tok_type = :lparen
36
+ tok_end = @tok_start + 1
37
+ when ')'
38
+ tok_type = :rparen
39
+ tok_end = @tok_start + 1
40
+ when '['
41
+ tok_type = :lbracket
42
+ tok_end = @tok_start + 1
43
+ when ']'
44
+ tok_type = :rbracket
45
+ tok_end = @tok_start + 1
46
+ when ';'
47
+ tok_type = :struct_sep
48
+ tok_end = @tok_start + 1
49
+ when '='
50
+ tok_type = :equals
51
+ tok_end = @tok_start + 1
52
+ when '"'
53
+ tok_type = :quoted
54
+ tok_end = scan_to_end_of_quoted(@str, @tok_start, '"')
55
+ when '`'
56
+ tok_type = :quoted
57
+ tok_end = scan_to_end_of_quoted(@str, @tok_start, '`')
58
+ else
59
+ tok_type = :string
60
+ tok_end = scan_to_end_of_string(@str, @tok_start)
61
+ end
62
+
63
+ tok_value = @str[@tok_start..(tok_end - 1)].strip
64
+
65
+ if tok_value.match? INTEGER_REGEX
66
+ number = tok_value.to_i
67
+ @tokens.push Token.new(:integer, number, @tok_start, tok_end)
68
+ elsif tok_value.match? FLOAT_REGEX
69
+ number = tok_value.to_f
70
+ @tokens.push Token.new(:float, number, @tok_start, tok_end)
71
+ elsif tok_value == 'null'
72
+ @tokens.push Token.new(:null, nil, @tok_start, tok_end)
73
+ elsif tok_value == 'true'
74
+ @tokens.push Token.new(true, true, @tok_start, tok_end)
75
+ elsif tok_value == 'false'
76
+ @tokens.push Token.new(false, false, @tok_start, tok_end)
77
+ else
78
+ @tokens.push Token.new(tok_type, tok_value, @tok_start, tok_end)
79
+ end
80
+
81
+ @tok_start = tok_end
82
+ tok_end < @str.length
83
+ end
84
+
85
+ def scan_to_end_of_quoted(str, start, quote_char)
86
+ end_str = start + 1
87
+ while end_str < str.length
88
+ end_char = str[end_str]
89
+ prev_char = str[end_str - 1]
90
+
91
+ break if end_char == quote_char && prev_char != '\\' && prev_char != '~'
92
+
93
+ end_str += 1
94
+ end
95
+ end_str + 1
96
+ end
97
+
98
+ def scan_to_end_of_string(str, start)
99
+ end_str = start + 1
100
+ while end_str < str.length
101
+ break if NON_STRING_TOKENS.include?(str[end_str]) && !escaped?(str, end_str - 1)
102
+
103
+ end_str += 1
104
+ end
105
+ end_str
106
+ end
107
+
108
+ def escaped?(str, pos)
109
+ pos >= 0 && (str[pos] == '~' || str[pos] == '\\')
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'modl/tokeniser/context'
4
+
5
+ module MODL
6
+ # A MODL Tokeniser module
7
+ module Tokeniser
8
+ # A class to represent MODL tokens
9
+ class Token
10
+ attr_reader :type, :value, :from, :to
11
+
12
+ def initialize(type, value, from, to)
13
+ @type = type
14
+ @value = value
15
+ @from = from
16
+ @to = to
17
+ end
18
+
19
+ def to_s
20
+ "type: #{@type}, from: #{@from}, to: #{@to}, value: \"#{@value}\""
21
+ end
22
+ end
23
+
24
+ def self.tokenise(str)
25
+ Context.new(str).parse
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MODL
4
+ # Helper functions for MODL.generate
5
+ module UTIL
6
+ SHOULD_BE_GRAVE_QUOTED = /.*[()\[\];{}="].*/.freeze
7
+ IS_NUMERIC = /^-?[0-9]*\.?[0-9]+(?:[Ee][+-]?[0-9]+)?$/.freeze
8
+
9
+ def self.escape_graves(str)
10
+ return str unless str
11
+
12
+ str.gsub(/`/, '~`')
13
+ end
14
+
15
+ def self.escape_double_quotes(str)
16
+ return str unless str
17
+
18
+ i = str.index('"', 1) # ignore the initial quote
19
+ result = str
20
+ # Don't affect the final quote in the string
21
+ while !i.nil? && i < (result.length - 1)
22
+ result = result.slice(0..(i - 1)) + '~u0022' + result.slice((i + 1)..)
23
+ i = result.index('"', 1)
24
+ end
25
+ result
26
+ end
27
+
28
+ def self.grave_quote_if_necessary(str)
29
+ return str unless str
30
+
31
+ if str.match?(SHOULD_BE_GRAVE_QUOTED) ||
32
+ (str.match?(IS_NUMERIC) && str != '00' && str != '01' && str != '000') ||
33
+ (str.strip.empty? ||
34
+ str.match?(IS_NUMERIC) ||
35
+ str == 'true' ||
36
+ str == 'false' ||
37
+ str == 'null')
38
+ "`#{str}`"
39
+ else
40
+ str
41
+ end
42
+ end
43
+
44
+ def self.double_quote_if_necessary(str)
45
+ if str && str.include?('~`')
46
+ "\"#{str}\""
47
+ else
48
+ str
49
+ end
50
+ end
51
+
52
+ def self.replace_nbsp(str)
53
+ str.gsub('\u00a0', ' ')
54
+ end
55
+
56
+ def self.escape_and_quote(str)
57
+ double_quote_if_necessary(
58
+ grave_quote_if_necessary(
59
+ escape_graves(
60
+ UNICODE.escape(
61
+ replace_nbsp(
62
+ escape_double_quotes(str)
63
+ )
64
+ )
65
+ )
66
+ )
67
+ )
68
+ end
69
+
70
+ def self.non_string_primitive?(str)
71
+ str == 'true' || str == 'false' || str == 'null' || str.match?(IS_NUMERIC)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: false
2
+
3
+ module MODL
4
+ # Handle escaping of unicode characters.
5
+ module UNICODE
6
+ VERTICAL_TAB = 0x0b
7
+ BACKSPACE = 0x08
8
+ FORMFEED = 0x0c
9
+ LINEFEED = 0x0a
10
+ CARRIAGE_RETURN = 0x0d
11
+ TAB = 0x09
12
+
13
+ def self.escape_char(chr)
14
+ return '' unless chr
15
+
16
+ if chr >= 32 && chr <= 127
17
+ '' << chr
18
+ elsif chr == VERTICAL_TAB
19
+ '~u000B'
20
+ elsif chr == BACKSPACE
21
+ '\\b'
22
+ elsif chr == FORMFEED
23
+ '\\f'
24
+ elsif chr == LINEFEED
25
+ '\\n'
26
+ elsif chr == CARRIAGE_RETURN
27
+ '\\r'
28
+ elsif chr == TAB
29
+ '\\t'
30
+ else
31
+ '' << chr
32
+ end
33
+ end
34
+
35
+ def self.escape(str)
36
+ result = ''
37
+
38
+ str.each_codepoint do |c|
39
+ result << escape_char(c)
40
+ end
41
+ result
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MODL
4
+ VERSION = '0.3.28'
5
+ end
data/lib/modl.rb CHANGED
@@ -1,34 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # The MIT License (MIT)
4
- #
5
- # Copyright (c) 2019 NUM Technology Ltd
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining a copy
8
- # of this software and associated documentation files (the "Software"), to deal
9
- # in the Software without restriction, including without limitation the rights
10
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- # copies of the Software, and to permit persons to whom the Software is
12
- # furnished to do so, subject to the following conditions:
13
- #
14
- # The above copyright notice and this permission notice shall be included in
15
- # all copies or substantial portions of the Software.
16
- #
17
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- # THE SOFTWARE.
24
-
25
- require "antlr4/runtime"
26
- require "modl/parser/version"
27
- require 'modl/parser/MODLParserListener'
28
- require 'modl/parser/MODLParserVisitor'
29
- require 'modl/parser/MODLParserBaseListener'
30
- require 'modl/parser/MODLParserBaseVisitor'
31
- require 'modl/parser/MODLLexer'
32
- require 'modl/parser/MODLParser'
33
- require 'modl/parser/interpreter'
34
- require 'modl/parser/instruction_processor'
3
+ require 'modl/version'
4
+ require 'modl/model/model'
5
+ require 'modl/tokeniser/tokeniser'
6
+ require 'modl/parser/parser'
7
+ require 'modl/util/unicode'
8
+ require 'modl/util/functions'
9
+ require 'modl/interpreter'
data/modl.gemspec CHANGED
@@ -1,30 +1,27 @@
1
-
2
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'modl/parser/version'
3
+ require 'modl/version'
5
4
 
6
5
  Gem::Specification.new do |spec|
7
6
  spec.name = 'modl'
8
- spec.version = MODL::Parser::VERSION
7
+ spec.version = MODL::VERSION
9
8
  spec.authors = ['Tony Walmsley']
10
9
  spec.email = ['tony@aosd.co.uk']
11
10
 
12
- spec.summary = 'The ANTLR4 Lexer and Parser for MODL generated using the Ruby language target.'
13
- spec.description = 'Contains the base Lexer, Parser, and supporting classes for a MODL parser.'
14
- spec.homepage = 'https://github.com/MODLanguage/ruby-interpreter'
11
+ spec.summary = 'A Ruby inretpreter for the MODL data serialisation language.'
12
+ spec.description = 'A command line program for interpreting MODL objects.'
13
+ spec.homepage = 'https://github.com/MODLanguage/ruby-modl'
15
14
  spec.license = 'MIT'
16
15
 
17
16
  # Specify which files should be added to the gem when it is released.
18
17
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
18
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
20
19
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
20
  end
22
21
  spec.bindir = 'exe'
23
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
23
  spec.require_paths = ['lib']
25
24
 
26
- spec.add_development_dependency "rake", ">= 12.3.3"
25
+ spec.add_development_dependency 'rake', '>= 12.3.3'
27
26
  spec.add_development_dependency 'rspec', '~> 3.0'
28
- spec.add_runtime_dependency 'antlr4-runtime', '= 0.2.10'
29
- spec.add_runtime_dependency 'punycode4r', '>= 0.2.0'
30
27
  end