modl 0.3.26 → 0.3.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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