syntax_tree 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -163,6 +163,13 @@ module SyntaxTree
163
163
  line_counts[lineno - 1][column]
164
164
  end
165
165
 
166
+ # This represents the current column we're in relative to the beginning of
167
+ # the current line.
168
+ def current_column
169
+ line = line_counts[lineno - 1]
170
+ line[column].to_i - line.start
171
+ end
172
+
166
173
  # As we build up a list of tokens, we'll periodically need to go backwards
167
174
  # and find the ones that we've already hit in order to determine the
168
175
  # location information for nodes that use them. For example, if you have a
@@ -251,10 +258,13 @@ module SyntaxTree
251
258
  def on_BEGIN(statements)
252
259
  lbrace = find_token(LBrace)
253
260
  rbrace = find_token(RBrace)
261
+ start_char = find_next_statement_start(lbrace.location.end_char)
254
262
 
255
263
  statements.bind(
256
- find_next_statement_start(lbrace.location.end_char),
257
- rbrace.location.start_char
264
+ start_char,
265
+ start_char - line_counts[lbrace.location.start_line - 1].start,
266
+ rbrace.location.start_char,
267
+ rbrace.location.start_column,
258
268
  )
259
269
 
260
270
  keyword = find_token(Kw, "BEGIN")
@@ -271,7 +281,7 @@ module SyntaxTree
271
281
  def on_CHAR(value)
272
282
  CHAR.new(
273
283
  value: value,
274
- location: Location.token(line: lineno, char: char_pos, size: value.size)
284
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
275
285
  )
276
286
  end
277
287
 
@@ -280,10 +290,13 @@ module SyntaxTree
280
290
  def on_END(statements)
281
291
  lbrace = find_token(LBrace)
282
292
  rbrace = find_token(RBrace)
293
+ start_char = find_next_statement_start(lbrace.location.end_char)
283
294
 
284
295
  statements.bind(
285
- find_next_statement_start(lbrace.location.end_char),
286
- rbrace.location.start_char
296
+ start_char,
297
+ start_char - line_counts[lbrace.location.start_line - 1].start,
298
+ rbrace.location.start_char,
299
+ rbrace.location.start_column
287
300
  )
288
301
 
289
302
  keyword = find_token(Kw, "END")
@@ -301,7 +314,7 @@ module SyntaxTree
301
314
  @__end__ =
302
315
  EndContent.new(
303
316
  value: source[(char_pos + value.length)..-1],
304
- location: Location.token(line: lineno, char: char_pos, size: value.size)
317
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
305
318
  )
306
319
  end
307
320
 
@@ -465,7 +478,7 @@ module SyntaxTree
465
478
  # :call-seq:
466
479
  # on_args_new: () -> Args
467
480
  def on_args_new
468
- Args.new(parts: [], location: Location.fixed(line: lineno, char: char_pos))
481
+ Args.new(parts: [], location: Location.fixed(line: lineno, column: current_column, char: char_pos))
469
482
  end
470
483
 
471
484
  # :call-seq:
@@ -551,7 +564,7 @@ module SyntaxTree
551
564
  def on_backref(value)
552
565
  Backref.new(
553
566
  value: value,
554
- location: Location.token(line: lineno, char: char_pos, size: value.size)
567
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
555
568
  )
556
569
  end
557
570
 
@@ -561,7 +574,7 @@ module SyntaxTree
561
574
  node =
562
575
  Backtick.new(
563
576
  value: value,
564
- location: Location.token(line: lineno, char: char_pos, size: value.size)
577
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
565
578
  )
566
579
 
567
580
  tokens << node
@@ -592,15 +605,20 @@ module SyntaxTree
592
605
  PinnedBegin.new(statement: bodystmt, location: location)
593
606
  else
594
607
  keyword = find_token(Kw, "begin")
595
- end_char =
608
+ end_location =
596
609
  if bodystmt.rescue_clause || bodystmt.ensure_clause ||
597
610
  bodystmt.else_clause
598
- bodystmt.location.end_char
611
+ bodystmt.location
599
612
  else
600
- find_token(Kw, "end").location.end_char
613
+ find_token(Kw, "end").location
601
614
  end
602
615
 
603
- bodystmt.bind(keyword.location.end_char, end_char)
616
+ bodystmt.bind(
617
+ keyword.location.end_char,
618
+ keyword.location.end_column,
619
+ end_location.end_char,
620
+ end_location.end_column
621
+ )
604
622
  location = keyword.location.to(bodystmt.location)
605
623
 
606
624
  Begin.new(bodystmt: bodystmt, location: location)
@@ -682,9 +700,10 @@ module SyntaxTree
682
700
  BodyStmt.new(
683
701
  statements: statements,
684
702
  rescue_clause: rescue_clause,
703
+ else_keyword: else_clause && find_token(Kw, "else"),
685
704
  else_clause: else_clause,
686
705
  ensure_clause: ensure_clause,
687
- location: Location.fixed(line: lineno, char: char_pos)
706
+ location: Location.fixed(line: lineno, char: char_pos, column: current_column)
688
707
  )
689
708
  end
690
709
 
@@ -696,18 +715,24 @@ module SyntaxTree
696
715
  def on_brace_block(block_var, statements)
697
716
  lbrace = find_token(LBrace)
698
717
  rbrace = find_token(RBrace)
718
+ location = (block_var || lbrace).location
719
+ start_char = find_next_statement_start(location.end_char)
699
720
 
700
721
  statements.bind(
701
- find_next_statement_start((block_var || lbrace).location.end_char),
702
- rbrace.location.start_char
722
+ start_char,
723
+ start_char - line_counts[location.start_line - 1].start,
724
+ rbrace.location.start_char,
725
+ rbrace.location.start_column
703
726
  )
704
727
 
705
728
  location =
706
729
  Location.new(
707
730
  start_line: lbrace.location.start_line,
708
731
  start_char: lbrace.location.start_char,
732
+ start_column: lbrace.location.start_column,
709
733
  end_line: [rbrace.location.end_line, statements.location.end_line].max,
710
- end_char: rbrace.location.end_char
734
+ end_char: rbrace.location.end_char,
735
+ end_column: rbrace.location.end_column
711
736
  )
712
737
 
713
738
  BraceBlock.new(
@@ -781,10 +806,14 @@ module SyntaxTree
781
806
  def on_class(constant, superclass, bodystmt)
782
807
  beginning = find_token(Kw, "class")
783
808
  ending = find_token(Kw, "end")
809
+ location = (superclass || constant).location
810
+ start_char = find_next_statement_start(location.end_char)
784
811
 
785
812
  bodystmt.bind(
786
- find_next_statement_start((superclass || constant).location.end_char),
787
- ending.location.start_char
813
+ start_char,
814
+ start_char - line_counts[location.start_line - 1].start,
815
+ ending.location.start_char,
816
+ ending.location.start_column
788
817
  )
789
818
 
790
819
  ClassDeclaration.new(
@@ -801,7 +830,7 @@ module SyntaxTree
801
830
  node =
802
831
  Comma.new(
803
832
  value: value,
804
- location: Location.token(line: lineno, char: char_pos, size: value.size)
833
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
805
834
  )
806
835
 
807
836
  tokens << node
@@ -846,7 +875,7 @@ module SyntaxTree
846
875
  value: value.chomp,
847
876
  inline: value.strip != lines[line - 1].strip,
848
877
  location:
849
- Location.token(line: line, char: char_pos, size: value.size - 1)
878
+ Location.token(line: line, char: char_pos, column: current_column, size: value.size - 1)
850
879
  )
851
880
 
852
881
  @comments << comment
@@ -858,7 +887,7 @@ module SyntaxTree
858
887
  def on_const(value)
859
888
  Const.new(
860
889
  value: value,
861
- location: Location.token(line: lineno, char: char_pos, size: value.size)
890
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
862
891
  )
863
892
  end
864
893
 
@@ -893,7 +922,7 @@ module SyntaxTree
893
922
  def on_cvar(value)
894
923
  CVar.new(
895
924
  value: value,
896
- location: Location.token(line: lineno, char: char_pos, size: value.size)
925
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
897
926
  )
898
927
  end
899
928
 
@@ -917,12 +946,15 @@ module SyntaxTree
917
946
  # location information
918
947
  if params.is_a?(Params) && params.empty?
919
948
  end_char = name.location.end_char
949
+ end_column = name.location.end_column
920
950
  location =
921
951
  Location.new(
922
952
  start_line: params.location.start_line,
923
953
  start_char: end_char,
954
+ start_column: end_column,
924
955
  end_line: params.location.end_line,
925
- end_char: end_char
956
+ end_char: end_char,
957
+ end_column: end_column
926
958
  )
927
959
 
928
960
  params = Params.new(location: location)
@@ -932,9 +964,13 @@ module SyntaxTree
932
964
 
933
965
  if ending
934
966
  tokens.delete(ending)
967
+ start_char = find_next_statement_start(params.location.end_char)
968
+
935
969
  bodystmt.bind(
936
- find_next_statement_start(params.location.end_char),
937
- ending.location.start_char
970
+ start_char,
971
+ start_char - line_counts[params.location.start_line - 1].start,
972
+ ending.location.start_char,
973
+ ending.location.start_column
938
974
  )
939
975
 
940
976
  Def.new(
@@ -992,12 +1028,15 @@ module SyntaxTree
992
1028
  # location information
993
1029
  if params.is_a?(Params) && params.empty?
994
1030
  end_char = name.location.end_char
1031
+ end_column = name.location.end_column
995
1032
  location =
996
1033
  Location.new(
997
1034
  start_line: params.location.start_line,
998
1035
  start_char: end_char,
1036
+ start_column: end_column,
999
1037
  end_line: params.location.end_line,
1000
- end_char: end_char
1038
+ end_char: end_char,
1039
+ end_column: end_column
1001
1040
  )
1002
1041
 
1003
1042
  params = Params.new(location: location)
@@ -1008,9 +1047,13 @@ module SyntaxTree
1008
1047
 
1009
1048
  if ending
1010
1049
  tokens.delete(ending)
1050
+ start_char = find_next_statement_start(params.location.end_char)
1051
+
1011
1052
  bodystmt.bind(
1012
- find_next_statement_start(params.location.end_char),
1013
- ending.location.start_char
1053
+ start_char,
1054
+ start_char - line_counts[params.location.start_line - 1].start,
1055
+ ending.location.start_char,
1056
+ ending.location.start_column
1014
1057
  )
1015
1058
 
1016
1059
  Defs.new(
@@ -1042,10 +1085,14 @@ module SyntaxTree
1042
1085
  def on_do_block(block_var, bodystmt)
1043
1086
  beginning = find_token(Kw, "do")
1044
1087
  ending = find_token(Kw, "end")
1088
+ location = (block_var || beginning).location
1089
+ start_char = find_next_statement_start(location.end_char)
1045
1090
 
1046
1091
  bodystmt.bind(
1047
- find_next_statement_start((block_var || beginning).location.end_char),
1048
- ending.location.start_char
1092
+ start_char,
1093
+ start_char - line_counts[location.start_line - 1].start,
1094
+ ending.location.start_char,
1095
+ ending.location.start_column
1049
1096
  )
1050
1097
 
1051
1098
  DoBlock.new(
@@ -1115,7 +1162,7 @@ module SyntaxTree
1115
1162
  # :call-seq:
1116
1163
  # on_else: (Statements statements) -> Else
1117
1164
  def on_else(statements)
1118
- beginning = find_token(Kw, "else")
1165
+ keyword = find_token(Kw, "else")
1119
1166
 
1120
1167
  # else can either end with an end keyword (in which case we'll want to
1121
1168
  # consume that event) or it can end with an ensure keyword (in which case
@@ -1127,13 +1174,19 @@ module SyntaxTree
1127
1174
 
1128
1175
  node = tokens[index]
1129
1176
  ending = node.value == "end" ? tokens.delete_at(index) : node
1130
- # ending = node
1177
+ start_char = find_next_statement_start(keyword.location.end_char)
1131
1178
 
1132
- statements.bind(beginning.location.end_char, ending.location.start_char)
1179
+ statements.bind(
1180
+ start_char,
1181
+ start_char - line_counts[keyword.location.start_line - 1].start,
1182
+ ending.location.start_char,
1183
+ ending.location.start_column
1184
+ )
1133
1185
 
1134
1186
  Else.new(
1187
+ keyword: keyword,
1135
1188
  statements: statements,
1136
- location: beginning.location.to(ending.location)
1189
+ location: keyword.location.to(ending.location)
1137
1190
  )
1138
1191
  end
1139
1192
 
@@ -1147,7 +1200,12 @@ module SyntaxTree
1147
1200
  beginning = find_token(Kw, "elsif")
1148
1201
  ending = consequent || find_token(Kw, "end")
1149
1202
 
1150
- statements.bind(predicate.location.end_char, ending.location.start_char)
1203
+ statements.bind(
1204
+ predicate.location.end_char,
1205
+ predicate.location.end_column,
1206
+ ending.location.start_char,
1207
+ ending.location.start_column
1208
+ )
1151
1209
 
1152
1210
  Elsif.new(
1153
1211
  predicate: predicate,
@@ -1170,7 +1228,7 @@ module SyntaxTree
1170
1228
  @embdoc =
1171
1229
  EmbDoc.new(
1172
1230
  value: value,
1173
- location: Location.fixed(line: lineno, char: char_pos)
1231
+ location: Location.fixed(line: lineno, column: current_column, char: char_pos)
1174
1232
  )
1175
1233
  end
1176
1234
 
@@ -1185,8 +1243,10 @@ module SyntaxTree
1185
1243
  Location.new(
1186
1244
  start_line: location.start_line,
1187
1245
  start_char: location.start_char,
1246
+ start_column: location.start_column,
1188
1247
  end_line: lineno,
1189
- end_char: char_pos + value.length - 1
1248
+ end_char: char_pos + value.length - 1,
1249
+ end_column: current_column + value.length - 1
1190
1250
  )
1191
1251
  )
1192
1252
 
@@ -1202,7 +1262,7 @@ module SyntaxTree
1202
1262
  node =
1203
1263
  EmbExprBeg.new(
1204
1264
  value: value,
1205
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1265
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1206
1266
  )
1207
1267
 
1208
1268
  tokens << node
@@ -1215,7 +1275,7 @@ module SyntaxTree
1215
1275
  node =
1216
1276
  EmbExprEnd.new(
1217
1277
  value: value,
1218
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1278
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1219
1279
  )
1220
1280
 
1221
1281
  tokens << node
@@ -1228,7 +1288,7 @@ module SyntaxTree
1228
1288
  node =
1229
1289
  EmbVar.new(
1230
1290
  value: value,
1231
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1291
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1232
1292
  )
1233
1293
 
1234
1294
  tokens << node
@@ -1243,9 +1303,12 @@ module SyntaxTree
1243
1303
  # We don't want to consume the :@kw event, because that would break
1244
1304
  # def..ensure..end chains.
1245
1305
  ending = find_token(Kw, "end", consume: false)
1306
+ start_char = find_next_statement_start(keyword.location.end_char)
1246
1307
  statements.bind(
1247
- find_next_statement_start(keyword.location.end_char),
1248
- ending.location.start_char
1308
+ start_char,
1309
+ start_char - line_counts[keyword.location.start_line - 1].start,
1310
+ ending.location.start_char,
1311
+ ending.location.start_column
1249
1312
  )
1250
1313
 
1251
1314
  Ensure.new(
@@ -1292,7 +1355,7 @@ module SyntaxTree
1292
1355
  def on_float(value)
1293
1356
  FloatLiteral.new(
1294
1357
  value: value,
1295
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1358
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1296
1359
  )
1297
1360
  end
1298
1361
 
@@ -1337,7 +1400,9 @@ module SyntaxTree
1337
1400
 
1338
1401
  statements.bind(
1339
1402
  (keyword || collection).location.end_char,
1340
- ending.location.start_char
1403
+ (keyword || collection).location.end_column,
1404
+ ending.location.start_char,
1405
+ ending.location.start_column
1341
1406
  )
1342
1407
 
1343
1408
  if index.is_a?(MLHS)
@@ -1358,7 +1423,7 @@ module SyntaxTree
1358
1423
  def on_gvar(value)
1359
1424
  GVar.new(
1360
1425
  value: value,
1361
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1426
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1362
1427
  )
1363
1428
  end
1364
1429
 
@@ -1379,7 +1444,7 @@ module SyntaxTree
1379
1444
  # on_heredoc_beg: (String value) -> HeredocBeg
1380
1445
  def on_heredoc_beg(value)
1381
1446
  location =
1382
- Location.token(line: lineno, char: char_pos, size: value.size + 1)
1447
+ Location.token(line: lineno, char: char_pos, column: current_column, size: value.size + 1)
1383
1448
 
1384
1449
  # Here we're going to artificially create an extra node type so that if
1385
1450
  # there are comments after the declaration of a heredoc, they get printed.
@@ -1415,8 +1480,10 @@ module SyntaxTree
1415
1480
  Location.new(
1416
1481
  start_line: heredoc.location.start_line,
1417
1482
  start_char: heredoc.location.start_char,
1483
+ start_column: heredoc.location.start_column,
1418
1484
  end_line: lineno,
1419
- end_char: char_pos
1485
+ end_char: char_pos,
1486
+ end_column: current_column,
1420
1487
  )
1421
1488
  )
1422
1489
  end
@@ -1443,7 +1510,7 @@ module SyntaxTree
1443
1510
  def on_ident(value)
1444
1511
  Ident.new(
1445
1512
  value: value,
1446
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1513
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1447
1514
  )
1448
1515
  end
1449
1516
 
@@ -1457,7 +1524,12 @@ module SyntaxTree
1457
1524
  beginning = find_token(Kw, "if")
1458
1525
  ending = consequent || find_token(Kw, "end")
1459
1526
 
1460
- statements.bind(predicate.location.end_char, ending.location.start_char)
1527
+ statements.bind(
1528
+ predicate.location.end_char,
1529
+ predicate.location.end_column,
1530
+ ending.location.start_char,
1531
+ ending.location.start_column
1532
+ )
1461
1533
 
1462
1534
  If.new(
1463
1535
  predicate: predicate,
@@ -1503,7 +1575,7 @@ module SyntaxTree
1503
1575
  def on_imaginary(value)
1504
1576
  Imaginary.new(
1505
1577
  value: value,
1506
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1578
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1507
1579
  )
1508
1580
  end
1509
1581
 
@@ -1527,9 +1599,12 @@ module SyntaxTree
1527
1599
  statements_start = token
1528
1600
  end
1529
1601
 
1602
+ start_char = find_next_statement_start(statements_start.location.end_char)
1530
1603
  statements.bind(
1531
- find_next_statement_start(statements_start.location.end_char),
1532
- ending.location.start_char
1604
+ start_char,
1605
+ start_char - line_counts[statements_start.location.start_line - 1].start,
1606
+ ending.location.start_char,
1607
+ ending.location.start_column
1533
1608
  )
1534
1609
 
1535
1610
  In.new(
@@ -1545,7 +1620,7 @@ module SyntaxTree
1545
1620
  def on_int(value)
1546
1621
  Int.new(
1547
1622
  value: value,
1548
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1623
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1549
1624
  )
1550
1625
  end
1551
1626
 
@@ -1554,7 +1629,7 @@ module SyntaxTree
1554
1629
  def on_ivar(value)
1555
1630
  IVar.new(
1556
1631
  value: value,
1557
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1632
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1558
1633
  )
1559
1634
  end
1560
1635
 
@@ -1564,7 +1639,7 @@ module SyntaxTree
1564
1639
  node =
1565
1640
  Kw.new(
1566
1641
  value: value,
1567
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1642
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1568
1643
  )
1569
1644
 
1570
1645
  tokens << node
@@ -1585,7 +1660,7 @@ module SyntaxTree
1585
1660
  def on_label(value)
1586
1661
  Label.new(
1587
1662
  value: value,
1588
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1663
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1589
1664
  )
1590
1665
  end
1591
1666
 
@@ -1595,7 +1670,7 @@ module SyntaxTree
1595
1670
  node =
1596
1671
  LabelEnd.new(
1597
1672
  value: value,
1598
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1673
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1599
1674
  )
1600
1675
 
1601
1676
  tokens << node
@@ -1621,7 +1696,12 @@ module SyntaxTree
1621
1696
  closing = find_token(Kw, "end")
1622
1697
  end
1623
1698
 
1624
- statements.bind(opening.location.end_char, closing.location.start_char)
1699
+ statements.bind(
1700
+ opening.location.end_char,
1701
+ opening.location.end_column,
1702
+ closing.location.start_char,
1703
+ closing.location.start_column
1704
+ )
1625
1705
 
1626
1706
  Lambda.new(
1627
1707
  params: params,
@@ -1636,7 +1716,7 @@ module SyntaxTree
1636
1716
  node =
1637
1717
  LBrace.new(
1638
1718
  value: value,
1639
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1719
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1640
1720
  )
1641
1721
 
1642
1722
  tokens << node
@@ -1649,7 +1729,7 @@ module SyntaxTree
1649
1729
  node =
1650
1730
  LBracket.new(
1651
1731
  value: value,
1652
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1732
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1653
1733
  )
1654
1734
 
1655
1735
  tokens << node
@@ -1662,7 +1742,7 @@ module SyntaxTree
1662
1742
  node =
1663
1743
  LParen.new(
1664
1744
  value: value,
1665
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1745
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1666
1746
  )
1667
1747
 
1668
1748
  tokens << node
@@ -1761,7 +1841,7 @@ module SyntaxTree
1761
1841
  # :call-seq:
1762
1842
  # on_mlhs_new: () -> MLHS
1763
1843
  def on_mlhs_new
1764
- MLHS.new(parts: [], location: Location.fixed(line: lineno, char: char_pos))
1844
+ MLHS.new(parts: [], location: Location.fixed(line: lineno, char: char_pos, column: current_column))
1765
1845
  end
1766
1846
 
1767
1847
  # :call-seq:
@@ -1787,10 +1867,13 @@ module SyntaxTree
1787
1867
  def on_module(constant, bodystmt)
1788
1868
  beginning = find_token(Kw, "module")
1789
1869
  ending = find_token(Kw, "end")
1870
+ start_char = find_next_statement_start(constant.location.end_char)
1790
1871
 
1791
1872
  bodystmt.bind(
1792
- find_next_statement_start(constant.location.end_char),
1793
- ending.location.start_char
1873
+ start_char,
1874
+ start_char - line_counts[constant.location.start_line - 1].start,
1875
+ ending.location.start_char,
1876
+ ending.location.start_column
1794
1877
  )
1795
1878
 
1796
1879
  ModuleDeclaration.new(
@@ -1803,7 +1886,7 @@ module SyntaxTree
1803
1886
  # :call-seq:
1804
1887
  # on_mrhs_new: () -> MRHS
1805
1888
  def on_mrhs_new
1806
- MRHS.new(parts: [], location: Location.fixed(line: lineno, char: char_pos))
1889
+ MRHS.new(parts: [], location: Location.fixed(line: lineno, char: char_pos, column: current_column))
1807
1890
  end
1808
1891
 
1809
1892
  # :call-seq:
@@ -1872,7 +1955,7 @@ module SyntaxTree
1872
1955
  node =
1873
1956
  Op.new(
1874
1957
  value: value,
1875
- location: Location.token(line: lineno, char: char_pos, size: value.size)
1958
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
1876
1959
  )
1877
1960
 
1878
1961
  tokens << node
@@ -1931,7 +2014,7 @@ module SyntaxTree
1931
2014
  if parts.any?
1932
2015
  parts[0].location.to(parts[-1].location)
1933
2016
  else
1934
- Location.fixed(line: lineno, char: char_pos)
2017
+ Location.fixed(line: lineno, char: char_pos, column: current_column)
1935
2018
  end
1936
2019
 
1937
2020
  Params.new(
@@ -1954,12 +2037,15 @@ module SyntaxTree
1954
2037
 
1955
2038
  if contents && contents.is_a?(Params)
1956
2039
  location = contents.location
2040
+ start_char = find_next_statement_start(lparen.location.end_char)
1957
2041
  location =
1958
2042
  Location.new(
1959
2043
  start_line: location.start_line,
1960
- start_char: find_next_statement_start(lparen.location.end_char),
2044
+ start_char: start_char,
2045
+ start_column: start_char - line_counts[lparen.location.start_line - 1].start,
1961
2046
  end_line: location.end_line,
1962
- end_char: rparen.location.start_char
2047
+ end_char: rparen.location.start_char,
2048
+ end_column: rparen.location.start_column
1963
2049
  )
1964
2050
 
1965
2051
  contents =
@@ -1997,23 +2083,26 @@ module SyntaxTree
1997
2083
  def on_period(value)
1998
2084
  Period.new(
1999
2085
  value: value,
2000
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2086
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2001
2087
  )
2002
2088
  end
2003
2089
 
2004
2090
  # :call-seq:
2005
2091
  # on_program: (Statements statements) -> Program
2006
2092
  def on_program(statements)
2093
+ last_column = source.length - line_counts[lines.length - 1].start
2007
2094
  location =
2008
2095
  Location.new(
2009
2096
  start_line: 1,
2010
2097
  start_char: 0,
2098
+ start_column: 0,
2011
2099
  end_line: lines.length,
2012
- end_char: source.length
2100
+ end_char: source.length,
2101
+ end_column: last_column
2013
2102
  )
2014
2103
 
2015
2104
  statements.body << @__end__ if @__end__
2016
- statements.bind(0, source.length)
2105
+ statements.bind(0, 0, source.length, last_column)
2017
2106
 
2018
2107
  program = Program.new(statements: statements, location: location)
2019
2108
  attach_comments(program, @comments)
@@ -2126,7 +2215,7 @@ module SyntaxTree
2126
2215
  node =
2127
2216
  QSymbolsBeg.new(
2128
2217
  value: value,
2129
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2218
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2130
2219
  )
2131
2220
 
2132
2221
  tokens << node
@@ -2161,7 +2250,7 @@ module SyntaxTree
2161
2250
  node =
2162
2251
  QWordsBeg.new(
2163
2252
  value: value,
2164
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2253
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2165
2254
  )
2166
2255
 
2167
2256
  tokens << node
@@ -2181,7 +2270,7 @@ module SyntaxTree
2181
2270
  def on_rational(value)
2182
2271
  RationalLiteral.new(
2183
2272
  value: value,
2184
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2273
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2185
2274
  )
2186
2275
  end
2187
2276
 
@@ -2191,7 +2280,7 @@ module SyntaxTree
2191
2280
  node =
2192
2281
  RBrace.new(
2193
2282
  value: value,
2194
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2283
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2195
2284
  )
2196
2285
 
2197
2286
  tokens << node
@@ -2204,7 +2293,7 @@ module SyntaxTree
2204
2293
  node =
2205
2294
  RBracket.new(
2206
2295
  value: value,
2207
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2296
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2208
2297
  )
2209
2298
 
2210
2299
  tokens << node
@@ -2238,7 +2327,7 @@ module SyntaxTree
2238
2327
  node =
2239
2328
  RegexpBeg.new(
2240
2329
  value: value,
2241
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2330
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2242
2331
  )
2243
2332
 
2244
2333
  tokens << node
@@ -2250,7 +2339,7 @@ module SyntaxTree
2250
2339
  def on_regexp_end(value)
2251
2340
  RegexpEnd.new(
2252
2341
  value: value,
2253
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2342
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2254
2343
  )
2255
2344
  end
2256
2345
 
@@ -2292,9 +2381,12 @@ module SyntaxTree
2292
2381
  exceptions = exceptions[0] if exceptions.is_a?(Array)
2293
2382
 
2294
2383
  last_node = variable || exceptions || keyword
2384
+ start_char = find_next_statement_start(last_node.location.end_char)
2295
2385
  statements.bind(
2296
- find_next_statement_start(last_node.location.end_char),
2297
- char_pos
2386
+ start_char,
2387
+ start_char - line_counts[last_node.location.start_line - 1].start,
2388
+ char_pos,
2389
+ current_column
2298
2390
  )
2299
2391
 
2300
2392
  # We add an additional inner node here that ripper doesn't provide so that
@@ -2309,13 +2401,16 @@ module SyntaxTree
2309
2401
  Location.new(
2310
2402
  start_line: keyword.location.start_line,
2311
2403
  start_char: keyword.location.end_char + 1,
2404
+ start_column: keyword.location.end_column + 1,
2312
2405
  end_line: last_node.location.end_line,
2313
- end_char: last_node.location.end_char
2406
+ end_char: last_node.location.end_char,
2407
+ end_column: last_node.location.end_column
2314
2408
  )
2315
2409
  )
2316
2410
  end
2317
2411
 
2318
2412
  Rescue.new(
2413
+ keyword: keyword,
2319
2414
  exception: rescue_ex,
2320
2415
  statements: statements,
2321
2416
  consequent: consequent,
@@ -2323,8 +2418,10 @@ module SyntaxTree
2323
2418
  Location.new(
2324
2419
  start_line: keyword.location.start_line,
2325
2420
  start_char: keyword.location.start_char,
2421
+ start_column: keyword.location.start_column,
2326
2422
  end_line: lineno,
2327
- end_char: char_pos
2423
+ end_char: char_pos,
2424
+ end_column: current_column
2328
2425
  )
2329
2426
  )
2330
2427
  end
@@ -2383,7 +2480,7 @@ module SyntaxTree
2383
2480
  node =
2384
2481
  RParen.new(
2385
2482
  value: value,
2386
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2483
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2387
2484
  )
2388
2485
 
2389
2486
  tokens << node
@@ -2395,10 +2492,13 @@ module SyntaxTree
2395
2492
  def on_sclass(target, bodystmt)
2396
2493
  beginning = find_token(Kw, "class")
2397
2494
  ending = find_token(Kw, "end")
2495
+ start_char = find_next_statement_start(target.location.end_char)
2398
2496
 
2399
2497
  bodystmt.bind(
2400
- find_next_statement_start(target.location.end_char),
2401
- ending.location.start_char
2498
+ start_char,
2499
+ start_char - line_counts[target.location.start_line - 1].start,
2500
+ ending.location.start_char,
2501
+ ending.location.start_column
2402
2502
  )
2403
2503
 
2404
2504
  SClass.new(
@@ -2437,7 +2537,7 @@ module SyntaxTree
2437
2537
  Statements.new(
2438
2538
  self,
2439
2539
  body: [],
2440
- location: Location.fixed(line: lineno, char: char_pos)
2540
+ location: Location.fixed(line: lineno, char: char_pos, column: current_column)
2441
2541
  )
2442
2542
  end
2443
2543
 
@@ -2471,7 +2571,7 @@ module SyntaxTree
2471
2571
  def on_string_content
2472
2572
  StringContent.new(
2473
2573
  parts: [],
2474
- location: Location.fixed(line: lineno, char: char_pos)
2574
+ location: Location.fixed(line: lineno, char: char_pos, column: current_column)
2475
2575
  )
2476
2576
  end
2477
2577
 
@@ -2494,18 +2594,22 @@ module SyntaxTree
2494
2594
 
2495
2595
  statements.bind(
2496
2596
  embexpr_beg.location.end_char,
2497
- embexpr_end.location.start_char
2597
+ embexpr_beg.location.end_column,
2598
+ embexpr_end.location.start_char,
2599
+ embexpr_end.location.start_column
2498
2600
  )
2499
2601
 
2500
2602
  location =
2501
2603
  Location.new(
2502
2604
  start_line: embexpr_beg.location.start_line,
2503
2605
  start_char: embexpr_beg.location.start_char,
2606
+ start_column: embexpr_beg.location.start_column,
2504
2607
  end_line: [
2505
2608
  embexpr_end.location.end_line,
2506
2609
  statements.location.end_line
2507
2610
  ].max,
2508
- end_char: embexpr_end.location.end_char
2611
+ end_char: embexpr_end.location.end_char,
2612
+ end_column: embexpr_end.location.end_column
2509
2613
  )
2510
2614
 
2511
2615
  StringEmbExpr.new(statements: statements, location: location)
@@ -2533,11 +2637,13 @@ module SyntaxTree
2533
2637
  Location.new(
2534
2638
  start_line: tstring_beg.location.start_line,
2535
2639
  start_char: tstring_beg.location.start_char,
2640
+ start_column: tstring_beg.location.start_column,
2536
2641
  end_line: [
2537
2642
  tstring_end.location.end_line,
2538
2643
  string.location.end_line
2539
2644
  ].max,
2540
- end_char: tstring_end.location.end_char
2645
+ end_char: tstring_end.location.end_char,
2646
+ end_column: tstring_end.location.end_column
2541
2647
  )
2542
2648
 
2543
2649
  StringLiteral.new(
@@ -2566,7 +2672,7 @@ module SyntaxTree
2566
2672
  node =
2567
2673
  SymBeg.new(
2568
2674
  value: value,
2569
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2675
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2570
2676
  )
2571
2677
 
2572
2678
  tokens << node
@@ -2620,7 +2726,7 @@ module SyntaxTree
2620
2726
  node =
2621
2727
  SymbolsBeg.new(
2622
2728
  value: value,
2623
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2729
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2624
2730
  )
2625
2731
 
2626
2732
  tokens << node
@@ -2645,7 +2751,7 @@ module SyntaxTree
2645
2751
  node =
2646
2752
  TLambda.new(
2647
2753
  value: value,
2648
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2754
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2649
2755
  )
2650
2756
 
2651
2757
  tokens << node
@@ -2658,7 +2764,7 @@ module SyntaxTree
2658
2764
  node =
2659
2765
  TLamBeg.new(
2660
2766
  value: value,
2661
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2767
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2662
2768
  )
2663
2769
 
2664
2770
  tokens << node
@@ -2693,7 +2799,7 @@ module SyntaxTree
2693
2799
  node =
2694
2800
  TStringBeg.new(
2695
2801
  value: value,
2696
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2802
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2697
2803
  )
2698
2804
 
2699
2805
  tokens << node
@@ -2705,7 +2811,7 @@ module SyntaxTree
2705
2811
  def on_tstring_content(value)
2706
2812
  TStringContent.new(
2707
2813
  value: value,
2708
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2814
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2709
2815
  )
2710
2816
  end
2711
2817
 
@@ -2715,7 +2821,7 @@ module SyntaxTree
2715
2821
  node =
2716
2822
  TStringEnd.new(
2717
2823
  value: value,
2718
- location: Location.token(line: lineno, char: char_pos, size: value.size)
2824
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
2719
2825
  )
2720
2826
 
2721
2827
  tokens << node
@@ -2789,7 +2895,12 @@ module SyntaxTree
2789
2895
  beginning = find_token(Kw, "unless")
2790
2896
  ending = consequent || find_token(Kw, "end")
2791
2897
 
2792
- statements.bind(predicate.location.end_char, ending.location.start_char)
2898
+ statements.bind(
2899
+ predicate.location.end_char,
2900
+ predicate.location.end_column,
2901
+ ending.location.start_char,
2902
+ ending.location.start_column
2903
+ )
2793
2904
 
2794
2905
  Unless.new(
2795
2906
  predicate: predicate,
@@ -2826,7 +2937,12 @@ module SyntaxTree
2826
2937
  end
2827
2938
 
2828
2939
  # Update the Statements location information
2829
- statements.bind(predicate.location.end_char, ending.location.start_char)
2940
+ statements.bind(
2941
+ predicate.location.end_char,
2942
+ predicate.location.end_column,
2943
+ ending.location.start_char,
2944
+ ending.location.start_column
2945
+ )
2830
2946
 
2831
2947
  Until.new(
2832
2948
  predicate: predicate,
@@ -2870,7 +2986,7 @@ module SyntaxTree
2870
2986
  else
2871
2987
  # You can hit this pattern if you're assigning to a splat using
2872
2988
  # pattern matching syntax in Ruby 2.7+
2873
- Location.fixed(line: lineno, char: char_pos)
2989
+ Location.fixed(line: lineno, char: char_pos, column: current_column)
2874
2990
  end
2875
2991
 
2876
2992
  VarField.new(value: value, location: location)
@@ -2898,7 +3014,7 @@ module SyntaxTree
2898
3014
  # :call-seq:
2899
3015
  # on_void_stmt: () -> VoidStmt
2900
3016
  def on_void_stmt
2901
- VoidStmt.new(location: Location.fixed(line: lineno, char: char_pos))
3017
+ VoidStmt.new(location: Location.fixed(line: lineno, char: char_pos, column: current_column))
2902
3018
  end
2903
3019
 
2904
3020
  # :call-seq:
@@ -2917,9 +3033,13 @@ module SyntaxTree
2917
3033
  statements_start = token
2918
3034
  end
2919
3035
 
3036
+ start_char = find_next_statement_start(statements_start.location.end_char)
3037
+
2920
3038
  statements.bind(
2921
- find_next_statement_start(statements_start.location.end_char),
2922
- ending.location.start_char
3039
+ start_char,
3040
+ start_char - line_counts[statements_start.location.start_line - 1].start,
3041
+ ending.location.start_char,
3042
+ ending.location.start_column
2923
3043
  )
2924
3044
 
2925
3045
  When.new(
@@ -2945,7 +3065,12 @@ module SyntaxTree
2945
3065
  end
2946
3066
 
2947
3067
  # Update the Statements location information
2948
- statements.bind(predicate.location.end_char, ending.location.start_char)
3068
+ statements.bind(
3069
+ predicate.location.end_char,
3070
+ predicate.location.end_column,
3071
+ ending.location.start_char,
3072
+ ending.location.start_column
3073
+ )
2949
3074
 
2950
3075
  While.new(
2951
3076
  predicate: predicate,
@@ -2981,7 +3106,7 @@ module SyntaxTree
2981
3106
  # :call-seq:
2982
3107
  # on_word_new: () -> Word
2983
3108
  def on_word_new
2984
- Word.new(parts: [], location: Location.fixed(line: lineno, char: char_pos))
3109
+ Word.new(parts: [], location: Location.fixed(line: lineno, char: char_pos, column: current_column))
2985
3110
  end
2986
3111
 
2987
3112
  # :call-seq:
@@ -3000,7 +3125,7 @@ module SyntaxTree
3000
3125
  node =
3001
3126
  WordsBeg.new(
3002
3127
  value: value,
3003
- location: Location.token(line: lineno, char: char_pos, size: value.size)
3128
+ location: Location.token(line: lineno, char: char_pos, column: current_column, size: value.size)
3004
3129
  )
3005
3130
 
3006
3131
  tokens << node