opal 0.3.44 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. data/.travis.yml +0 -1
  2. data/CHANGELOG.md +52 -0
  3. data/README.md +3 -3
  4. data/Rakefile +32 -8
  5. data/bin/opal +69 -16
  6. data/config.ru +1 -1
  7. data/examples/native/app/app.rb +28 -9
  8. data/examples/rack/app/app.rb +1 -1
  9. data/lib/opal.rb +0 -1
  10. data/lib/opal/cli.rb +106 -0
  11. data/lib/opal/lexer.rb +4 -2
  12. data/lib/opal/parser.rb +603 -360
  13. data/lib/opal/processor.rb +20 -8
  14. data/lib/opal/server.rb +47 -0
  15. data/lib/opal/source_map.rb +63 -0
  16. data/lib/opal/sprockets_parser.rb +77 -0
  17. data/lib/opal/sprockets_source_map_header.rb +21 -0
  18. data/lib/opal/target_scope.rb +14 -7
  19. data/lib/opal/version.rb +1 -1
  20. data/opal.gemspec +2 -0
  21. data/opal/opal-browser/script_loader.rb +7 -7
  22. data/opal/opal-parser.js.erb +2 -2
  23. data/opal/opal-source-maps.js.erb +2 -0
  24. data/opal/opal.rb +3 -4
  25. data/opal/opal/array.rb +31 -28
  26. data/opal/opal/boolean.rb +4 -0
  27. data/opal/opal/class.rb +14 -5
  28. data/opal/opal/enumerable.rb +68 -8
  29. data/opal/opal/error.rb +1 -1
  30. data/opal/opal/hash.rb +15 -18
  31. data/opal/opal/kernel.rb +24 -10
  32. data/opal/opal/native.rb +31 -0
  33. data/opal/opal/nil_class.rb +7 -2
  34. data/opal/opal/numeric.rb +10 -1
  35. data/opal/opal/proc.rb +4 -0
  36. data/opal/opal/range.rb +1 -1
  37. data/opal/opal/regexp.rb +13 -3
  38. data/opal/opal/runtime.js +134 -51
  39. data/opal/opal/string.rb +45 -22
  40. data/opal/opal/time.rb +25 -7
  41. data/opal/source_map.rb +63 -0
  42. data/opal/source_map/generator.rb +251 -0
  43. data/opal/source_map/parser.rb +102 -0
  44. data/opal/source_map/vlq.rb +122 -0
  45. data/opal/strscan.rb +30 -12
  46. data/spec/opal/class/_inherited_spec.rb +1 -1
  47. data/spec/{rubyspec/core → opal}/class/bridge_class_spec.rb +5 -3
  48. data/spec/{rubyspec/core → opal}/class/extend_spec.rb +0 -0
  49. data/spec/{rubyspec/core → opal}/class/instance_methods_spec.rb +0 -0
  50. data/spec/{rubyspec/core → opal}/class/last_value_spec.rb +0 -1
  51. data/spec/{rubyspec/core → opal}/json/parse_spec.rb +0 -0
  52. data/spec/{rubyspec/core/kernel/block_given.rb → opal/kernel/block_given_spec.rb} +0 -0
  53. data/spec/{rubyspec/core → opal}/kernel/class_spec.rb +0 -0
  54. data/spec/{rubyspec/core → opal}/kernel/extend_spec.rb +0 -0
  55. data/spec/{rubyspec/core → opal}/kernel/format_spec.rb +0 -0
  56. data/spec/opal/kernel/freeze_spec.rb +15 -0
  57. data/spec/{rubyspec/core → opal}/kernel/match_spec.rb +0 -0
  58. data/spec/{rubyspec/core → opal}/kernel/method_spec.rb +0 -0
  59. data/spec/{rubyspec/core → opal}/kernel/methods_spec.rb +0 -0
  60. data/spec/{rubyspec/core → opal}/kernel/nil_spec.rb +0 -0
  61. data/spec/{rubyspec/core → opal}/kernel/p_spec.rb +0 -0
  62. data/spec/{rubyspec/core → opal}/kernel/printf_spec.rb +0 -0
  63. data/spec/{rubyspec/core → opal}/kernel/proc_spec.rb +0 -0
  64. data/spec/{rubyspec/core → opal}/kernel/rand_spec.rb +0 -0
  65. data/spec/{rubyspec/core → opal}/kernel/respond_to_spec.rb +0 -0
  66. data/spec/{rubyspec/core → opal}/kernel/sprintf_spec.rb +0 -0
  67. data/spec/{rubyspec/core → opal}/kernel/to_json_spec.rb +0 -0
  68. data/spec/{rubyspec/core → opal}/module/alias_method_spec.rb +0 -0
  69. data/spec/{rubyspec/core → opal}/module/ancestors_spec.rb +0 -0
  70. data/spec/{rubyspec/core → opal}/module/append_features_spec.rb +0 -0
  71. data/spec/{rubyspec/core → opal}/module/constants_spec.rb +0 -0
  72. data/spec/{rubyspec/core → opal}/module/module_function_spec.rb +0 -1
  73. data/spec/opal/native_spec.rb +85 -3
  74. data/spec/opal/numeric/equal_spec.rb +9 -0
  75. data/spec/opal/parser/irb_spec.rb +43 -0
  76. data/spec/{rubyspec/core → opal}/proc/proc_tricks_spec.rb +0 -0
  77. data/spec/opal/runtime/block_send_spec.rb +28 -0
  78. data/spec/{rubyspec/core/runtime → opal/runtime2}/call_spec.rb +0 -0
  79. data/spec/{rubyspec/core/runtime → opal/runtime2}/class_hierarchy_spec.rb +0 -0
  80. data/spec/{rubyspec/core/runtime → opal/runtime2}/def_spec.rb +0 -0
  81. data/spec/{rubyspec/core/runtime → opal/runtime2}/defined_spec.rb +0 -0
  82. data/spec/{rubyspec/core/runtime → opal/runtime2}/super_spec.rb +0 -0
  83. data/spec/opal/source_map_spec.rb +19 -0
  84. data/spec/opal/string/freeze_spec.rb +15 -0
  85. data/spec/{rubyspec/core → opal}/string/to_json_spec.rb +0 -0
  86. data/spec/ospec/runner.rb +3 -0
  87. data/spec/parser/str_spec.rb +4 -0
  88. data/spec/rubyspec/core/enumerable/fixtures/classes.rb +2 -2
  89. data/spec/rubyspec/core/enumerable/none_spec.rb +68 -0
  90. data/spec/rubyspec/core/enumerable/sort_by_spec.rb +31 -0
  91. data/spec/rubyspec/core/hash/size_spec.rb +1 -1
  92. data/spec/rubyspec/core/hash/to_native_spec.rb +3 -3
  93. data/spec/rubyspec/core/string/fixtures/classes.rb +49 -0
  94. data/spec/rubyspec/core/string/index_spec.rb +405 -0
  95. data/spec/rubyspec/filters/bugs/language/class.rb +0 -2
  96. data/spec/rubyspec/filters/bugs/language/module.rb +3 -0
  97. data/spec/rubyspec/language/array_spec.rb +1 -1
  98. data/spec/rubyspec/language/block_spec.rb +1 -1
  99. data/spec/rubyspec/language/module_spec.rb +5 -5
  100. data/spec/rubyspec/language/predefined_spec.rb +1 -2
  101. data/spec/rubyspec/library/stringscanner/element_reference_spec.rb +29 -0
  102. data/spec/rubyspec/spec_helper.rb +31 -0
  103. metadata +130 -76
  104. data/lib/opal/erb.rb +0 -41
  105. data/opal/erb.rb +0 -19
  106. data/spec/opal/erb/erb_spec.rb +0 -31
  107. data/spec/simple_erb_template.opalerb +0 -1
  108. data/spec/templates/foo/bar.opalerb +0 -1
  109. data/spec/templates/prefixed.opalerb +0 -1
@@ -53,7 +53,9 @@ class Time
53
53
  to_f <=> other.to_f
54
54
  end
55
55
 
56
- alias_native :day, :getDate
56
+ def day
57
+ `#{self}.getDate()`
58
+ end
57
59
 
58
60
  def eql?(other)
59
61
  other.is_a?(Time) && (self <=> other).zero?
@@ -63,13 +65,19 @@ class Time
63
65
  `#{self}.getDay() === 5`
64
66
  end
65
67
 
66
- alias_native :hour, :getHours
68
+ def hour
69
+ `#{self}.getHours()`
70
+ end
67
71
 
68
- alias_native :inspect, :toString
72
+ def inspect
73
+ `#{self}.toString()`
74
+ end
69
75
 
70
76
  alias mday day
71
77
 
72
- alias_native :min, :getMinutes
78
+ def min
79
+ `#{self}.getMinutes()`
80
+ end
73
81
 
74
82
  def mon
75
83
  `#{self}.getMonth() + 1`
@@ -85,7 +93,9 @@ class Time
85
93
  `#{self}.getDay() === 6`
86
94
  end
87
95
 
88
- alias_native :sec, :getSeconds
96
+ def sec
97
+ `#{self}.getSeconds()`
98
+ end
89
99
 
90
100
  def strftime(format = '')
91
101
  %x{
@@ -127,11 +137,19 @@ class Time
127
137
  `#{self}.getDay() === 2`
128
138
  end
129
139
 
130
- alias_native :wday, :getDay
140
+ def wday
141
+ `#{self}.getDay()`
142
+ end
131
143
 
132
144
  def wednesday?
133
145
  `#{self}.getDay() === 3`
134
146
  end
135
147
 
136
- alias_native :year, :getFullYear
148
+ def year
149
+ `#{self}.getFullYear()`
150
+ end
151
+
152
+ def to_n
153
+ self
154
+ end
137
155
  end
@@ -0,0 +1,63 @@
1
+ require 'opal/json'
2
+
3
+ require 'source_map/vlq.rb'
4
+ require 'source_map/generator.rb'
5
+ require 'source_map/parser.rb'
6
+
7
+ class SourceMap
8
+ include SourceMap::Generator
9
+ include SourceMap::Parser
10
+
11
+ # Create a new blank SourceMap
12
+ #
13
+ # Options may include:
14
+ #
15
+ # :file => String # See {#file}
16
+ # :source_root => String # See {#source_root}
17
+ # :generated_output => IO # See {#generated_output}
18
+ #
19
+ # :sources => Array[String] # See {#sources}
20
+ # :names => Array[String] # See {#names}
21
+ #
22
+ # :version => 3 # Which version of SourceMap to use (only 3 is allowed)
23
+ #
24
+ def initialize(opts={})
25
+ unless (remain = opts.keys - [:generated_output, :file, :source_root, :sources, :names, :version]).empty?
26
+ raise ArgumentError, "Unsupported options to SourceMap.new: #{remain.inspect}"
27
+ end
28
+ self.generated_output = opts[:generated_output]
29
+ self.file = opts[:file] || ''
30
+ self.source_root = opts[:source_root] || ''
31
+ self.version = opts[:version] || 3
32
+ self.sources = opts[:sources] || []
33
+ self.names = opts[:names] || []
34
+ self.mappings = []
35
+ raise "version #{opts[:version]} not supported" if version != 3
36
+ end
37
+
38
+ # The name of the file containing the code that this SourceMap describes.
39
+ # (default "")
40
+ attr_accessor :file
41
+
42
+ # The URL/directory that contains the original source files.
43
+ #
44
+ # This is prefixed to the entries in ['sources']
45
+ # (default "")
46
+ attr_accessor :source_root
47
+
48
+ # The version of the SourceMap spec we're using.
49
+ # (default 3)
50
+ attr_accessor :version
51
+
52
+ # The list of sources (used during parsing/generating)
53
+ # These are relative to the source_root.
54
+ # (default [])
55
+ attr_accessor :sources
56
+
57
+ # A list of names (used during parsing/generating)
58
+ # (default [])
59
+ attr_accessor :names
60
+
61
+ # A list of mapping objects.
62
+ attr_accessor :mappings
63
+ end
@@ -0,0 +1,251 @@
1
+ class SourceMap
2
+ module Generator
3
+
4
+ # An object (responding to <<) that will be written to whenever
5
+ # {add_generated} is called.
6
+ #
7
+ # @example
8
+ #
9
+ # File.open("/var/www/a.js.min"){ |f|
10
+ # map = SourceMap.new(:generated_output => f)
11
+ # map.add_generated('function(a,b,c){minified=1}\n', :source => 'a.js')
12
+ # map.save('/var/www/a.js.map')
13
+ # }
14
+ # File.read('/var/www/a.js.min') == 'function(a,b,c){minified=1}\n'
15
+ #
16
+ attr_accessor :generated_output
17
+
18
+ # Add the mapping for generated code to this source map.
19
+ #
20
+ # The first parameter is the generated text that you're going to add to the output, if
21
+ # it contains multiple lines of code then it will be added to the source map as
22
+ # several mappings.
23
+ #
24
+ # If present, the second parameter represents the original source of the generated
25
+ # fragment, and may contain:
26
+ #
27
+ # :source => String, # The filename of the source fille that contains this fragment.
28
+ # :source_line => Integer, # The line in that file that contains this fragment
29
+ # :source_col => Integer, # The column in that line at which this fragment starts
30
+ # :name => String # The original name for this variable.
31
+ # :exact_position => Bool # Whether all lines in the generated fragment came from
32
+ # the same position in the source.
33
+ #
34
+ # The :source key is required to set :source_line, :source_col or :name.
35
+ #
36
+ # If unset :source_line and :source_col default to 1,0 for the first line of the
37
+ # generated fragment.
38
+ #
39
+ # Normally :source_line is incremented and :source_col reset at every line break in
40
+ # the generated code (because we assume that you're copying a verbatim fragment from
41
+ # the source into the generated code). If that is not the case, you can set
42
+ # :exact_position => true, and then all lines in the generated output will be given
43
+ # the same :source_line and :source_col.
44
+ #
45
+ # The :name property is used if the fragment you are adding contains only a name that
46
+ # you have renamed in the source transformation.
47
+ #
48
+ # If you'd like to ensure that the source map stays in sync with the generated
49
+ # source, consider calling {source_map.generated_output = StringIO.new} and then
50
+ # accessing your generated javascript with {source_map.generated_output.string},
51
+ # otherwise be careful to always write to both.
52
+ #
53
+ # NOTE: By long-standing convention, the first line of a file is numbered 1, not 0.
54
+ #
55
+ # NOTE: when generating a source map, you should either use this method always, or use
56
+ # the {#add_mapping} method always.
57
+ #
58
+ def add_generated(text, opts={})
59
+ if !opts[:source] && (opts[:name] || opts[:source_line] || opts[:source_col])
60
+ raise "mapping must have :source to have :source_line, :source_col or :name"
61
+ elsif opts[:source_line] && opts[:source_line] < 1
62
+ raise "files start on line 1 (got :source_line => #{opts[:source_line]})"
63
+ elsif !(remain = opts.keys - [:source, :source_line, :source_col, :name, :exact_position]).empty?
64
+ raise "mapping had unexpected keys: #{remain.inspect}"
65
+ end
66
+
67
+ source_line = opts[:source_line] || 1
68
+ source_col = opts[:source_col] || 0
69
+ self.generated_line ||= 1
70
+ self.generated_col ||= 0
71
+
72
+ text.split(/(\n)/).each do |line|
73
+ if line == "\n"
74
+ self.generated_line += 1
75
+ self.generated_col = 0
76
+ unless opts[:exact_position]
77
+ source_line += 1
78
+ source_col = 0
79
+ end
80
+ elsif line != ""
81
+ mapping = {
82
+ :generated_line => generated_line,
83
+ :generated_col => generated_col,
84
+ }
85
+ if opts[:source]
86
+ mapping[:source] = opts[:source]
87
+ mapping[:source_line] = source_line
88
+ mapping[:source_col] = source_col
89
+ mapping[:name] = opts[:name] if opts[:name]
90
+ end
91
+
92
+ mappings << mapping
93
+
94
+ self.generated_col += line.size
95
+ source_col += line.size unless opts[:exact_position]
96
+ end
97
+ end
98
+
99
+ generated_output += text if generated_output
100
+ end
101
+
102
+ # Add a mapping to the list for this object.
103
+ #
104
+ # A mapping identifies a fragment of code that has been moved around during
105
+ # transformation from the source file to the generated file. The fragment should
106
+ # be contiguous and not contain any line breaks.
107
+ #
108
+ # Mappings are Hashes with a valid subset of the following 6 keys:
109
+ #
110
+ # :generated_line => Integer, # The line in the generated file that contains this fragment.
111
+ # :generated_col => Integer, # The column in the generated_line that this mapping starts on
112
+ # :source => String, # The filename of the source fille that contains this fragment.
113
+ # :source_line => Integer, # The line in that file that contains this fragment.
114
+ # :source_col => Integer, # The column in that line at which this fragment starts.
115
+ # :name => String # The original name for this variable (if applicable).
116
+ #
117
+ #
118
+ # The only 3 valid subsets of keys are:
119
+ # [:generated_line, :generated_col] To indicate that this is a fragment in the
120
+ # output file that you don't have the source for.
121
+ #
122
+ # [:generated_line, :generated_col, :source, :source_line, :source_col] To indicate
123
+ # that this is a fragment in the output file that you do have the source for.
124
+ #
125
+ # [:generated_line, :generated_col, :source, :source_line, :source_col, :name] To
126
+ # indicate that this is a particular identifier at a particular location in the original.
127
+ #
128
+ # Any other combination of keys would produce an invalid source map.
129
+ #
130
+ # NOTE: By long-standing convention, the first line of a file is numbered 1, not 0.
131
+ #
132
+ # NOTE: when generating a source map, you should either use this method always,
133
+ # or use the {#add_generated} method always.
134
+ #
135
+ def add_mapping(map)
136
+ if !map[:generated_line] || !map[:generated_col]
137
+ raise "mapping must have :generated_line and :generated_col"
138
+ elsif map[:source] && !(map[:source_line] && map[:source_col])
139
+ raise "mapping must have :source_line and :source_col if it has :source"
140
+ elsif !map[:source] && (map[:source_line] || map[:source_col])
141
+ raise "mapping may not have a :source_line or :source_col without a :source"
142
+ elsif map[:name] && !map[:source]
143
+ raise "mapping may not have a :name without a :source"
144
+ elsif map[:source_line] && map[:source_line] < 1
145
+ raise "files start on line 1 (got :source_line => #{map[:source_line]})"
146
+ elsif map[:generated_line] < 1
147
+ raise "files start on line 1 (got :generated_line => #{map[:generated_line]})"
148
+ elsif !(remain = map.keys - [:generated_line, :generated_col, :source, :source_line, :source_col, :name]).empty?
149
+ raise "mapping had unexpected keys: #{remain.inspect}"
150
+ end
151
+
152
+ mappings << map
153
+ end
154
+
155
+ # Convert the map into an object suitable for direct serialisation.
156
+ def as_json
157
+ serialized_mappings = serialize_mappings!
158
+
159
+ {
160
+ 'version' => version,
161
+ 'file' => file,
162
+ 'sourceRoot' => source_root,
163
+ 'sources' => sources,
164
+ 'names' => names,
165
+ 'mappings' => serialized_mappings
166
+ }
167
+ end
168
+
169
+ # Convert the map to a string.
170
+ def to_s
171
+ as_json.to_json
172
+ end
173
+
174
+ # Write this map to a file.
175
+ def save(file)
176
+ File.open(file, "w"){ |f| f << to_s }
177
+ end
178
+
179
+ protected
180
+
181
+ attr_reader :source_ids, :name_ids
182
+ attr_accessor :generated_line, :generated_col
183
+
184
+ # Get the id for the given file. If we've not
185
+ # seen this file before, add it to the list.
186
+ def source_id(file)
187
+ if (cached = source_ids[file])
188
+ cached
189
+ else
190
+ sources << file
191
+ source_ids[file] = sources.size - 1
192
+ end
193
+ end
194
+
195
+ # Get the id for the given name. If we've not
196
+ # seen this name before, add it to the list.
197
+ def name_id(name)
198
+ if (cached = name_ids[file])
199
+ cached
200
+ else
201
+ names << name
202
+ name_ids[file] = names.size - 1
203
+ end
204
+ end
205
+
206
+ # Encode a vlq. As each field in the output should be relative to the
207
+ # previous occurance of that field, we keep track of each one.
208
+ def vlq(num, type)
209
+ ret = num - @previous_vlq[type]
210
+ @previous_vlq[type] = num
211
+ VLQ.encode(ret)
212
+ end
213
+
214
+ # Serialize the list of mappings into the string of base64 variable length
215
+ # quanities. As a side-effect, regenerate the sources and names arrays.
216
+ def serialize_mappings!
217
+ # clear all internals as we're about to re-generate them.
218
+ @sources = []
219
+ @source_ids = {}
220
+ @names = []
221
+ @name_ids = {}
222
+ @previous_vlq = Hash.new{ 0 }
223
+
224
+ return "" if mappings.empty?
225
+
226
+ by_lines = mappings.group_by{ |x| x[:generated_line] }
227
+
228
+ (1..by_lines.keys.max).map do |line|
229
+ # reset the generated_col on each line as indicated by the VLQ spec.
230
+ # (the other values continue to be relative)
231
+ @previous_vlq[:generated_col] = 0
232
+
233
+ fragments = (by_lines[line] || []).sort_by{ |x| x[:generated_col] }
234
+ fragments.map do |map|
235
+ serialize_mapping(map)
236
+ end.join(",")
237
+ end.join(";")
238
+ end
239
+
240
+ def serialize_mapping(map)
241
+ item = vlq(map[:generated_col], :generated_col)
242
+ if map[:source]
243
+ item += vlq(source_id(map[:source]), :source)
244
+ item += vlq(map[:source_line] - 1, :source_line)
245
+ item += vlq(map[:source_col], :source_col)
246
+ item += vlq(name_id(map[:name]), :name) if map[:name]
247
+ end
248
+ item
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,102 @@
1
+ class SourceMap
2
+
3
+ class ParserError < RuntimeError; end
4
+
5
+ # Load a SourceMap from a Hash such as might be returned by
6
+ # {SourceMap#as_json}.
7
+ #
8
+ def self.from_json(json)
9
+ raise ParserError, "Cannot parse version: #{json['version']} of SourceMap" unless json['version'] == 3
10
+
11
+ map = new(:file => json['file'],
12
+ :source_root => json['sourceRoot'],
13
+ :sources => json['sources'],
14
+ :names => json['names'])
15
+
16
+ map.parse_mappings(json['mappings'] || '')
17
+ map
18
+ end
19
+
20
+ # Load a SourceMap from a String.
21
+ def self.from_s(str)
22
+ from_json JSON.parse(str)
23
+ end
24
+
25
+ # Load a SourceMap from a file.
26
+ def self.load(filename)
27
+ from_s File.read(filename)
28
+ end
29
+
30
+ module Parser
31
+ # Parse the mapping string from a SourceMap.
32
+ #
33
+ # The mappings string contains one comma-separated list of segments per line
34
+ # in the output file, these lists are joined by semi-colons.
35
+ #
36
+ def parse_mappings(string)
37
+ @previous = Hash.new{ 0 }
38
+
39
+ string.split(";").each_with_index do |line, line_idx|
40
+ # The generated_col resets to 0 at the start of every line, though
41
+ # all the other differences are maintained.
42
+ @previous[:generated_col] = 0
43
+ line.split(",").each do |segment|
44
+ mappings << parse_mapping(segment, line_idx + 1)
45
+ end
46
+ end
47
+
48
+ self.mappings = self.mappings.sort_by{ |x| [x[:generated_line], x[:generated_col]] }
49
+ end
50
+
51
+ # All the numbers in SourceMaps are stored as differences from each other,
52
+ # so we need to remove the difference every time we read a number.
53
+ def undiff(int, type)
54
+ @previous[type] += int
55
+ end
56
+
57
+ # Parse an individual mapping.
58
+ #
59
+ # This is a list of variable-length-quanitity, with 1, 4 or 5 items. See the spec
60
+ # https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
61
+ # for more details.
62
+ def parse_mapping(segment, line_num)
63
+ item = VLQ.decode_array(segment)
64
+
65
+ unless [1, 4, 5].include?(item.size)
66
+ raise ParserError, "In map for #{file}:#{line_num}: unparseable item: #{segment}"
67
+ end
68
+
69
+ map = {
70
+ :generated_line => line_num,
71
+ :generated_col => undiff(item[0], :generated_col),
72
+ }
73
+
74
+ if item.size >= 4
75
+ map[:source] = sources[undiff(item[1], :source_id)]
76
+ map[:source_line] = undiff(item[2], :source_line) + 1 # line numbers are stored starting from 0
77
+ map[:source_col] = undiff(item[3], :source_col)
78
+ map[:name] = names[undiff(item[4], :name_id)] if item[4]
79
+ end
80
+
81
+ if map[:generated_col] < 0
82
+ raise ParserError, "In map for #{file}:#{line_num}: unexpected generated_col: #{map[:generated_col]}"
83
+
84
+ elsif map.key?(:source) && (map[:source].nil? || @previous[:source_id] < 0)
85
+ raise ParserError, "In map for #{file}:#{line_num}: unknown source id: #{@previous[:source_id]}"
86
+
87
+ elsif map.key?(:source_line) && map[:source_line] < 1
88
+ raise ParserError, "In map for #{file}:#{line_num}: unexpected source_line: #{map[:source_line]}"
89
+
90
+ elsif map.key?(:source_col) && map[:source_col] < 0
91
+ raise ParserError, "In map for #{file}:#{line_num}: unexpected source_col: #{map[:source_col]}"
92
+
93
+ elsif map.key?(:name) && (map[:name].nil? || @previous[:name_id] < 0)
94
+ raise ParserError, "In map for #{file}:#{line_num}: unknown name id: #{@previous[:name_id]}"
95
+
96
+ else
97
+ map
98
+
99
+ end
100
+ end
101
+ end
102
+ end