vinter 0.6.4 → 0.6.6
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.
- checksums.yaml +4 -4
- data/lib/vinter/lexer.rb +603 -25
- data/lib/vinter/parser.rb +268 -212
- data/lib/vinter.rb +1 -1
- metadata +2 -2
data/lib/vinter/parser.rb
CHANGED
|
@@ -383,6 +383,12 @@ module Vinter
|
|
|
383
383
|
parse_sleep_command
|
|
384
384
|
when 'source'
|
|
385
385
|
parse_source_command
|
|
386
|
+
when 'elseif'
|
|
387
|
+
advance
|
|
388
|
+
when 'else'
|
|
389
|
+
advance
|
|
390
|
+
when 'class'
|
|
391
|
+
parse_class_definition
|
|
386
392
|
else
|
|
387
393
|
@warnings << {
|
|
388
394
|
message: "Unexpected keyword: #{current_token[:value]}",
|
|
@@ -409,14 +415,8 @@ module Vinter
|
|
|
409
415
|
end
|
|
410
416
|
elsif current_token[:type] == :comment
|
|
411
417
|
parse_comment
|
|
412
|
-
elsif current_token[:type] == :string && current_token[:value].start_with?('"')
|
|
413
|
-
parse_comment
|
|
414
|
-
# token = current_token
|
|
415
|
-
# line = token[:line]
|
|
416
|
-
# column = token[:column]
|
|
417
|
-
# value = token[:value]
|
|
418
|
-
# advance
|
|
419
|
-
# { type: :comment, value: value, line: line, column: column }
|
|
418
|
+
#elsif current_token[:type] == :string && current_token[:value].start_with?('"')
|
|
419
|
+
#parse_comment
|
|
420
420
|
elsif current_token[:type] == :silent_bang
|
|
421
421
|
parse_silent_command
|
|
422
422
|
elsif current_token[:type] == :identifier && current_token[:value] == 'delete'
|
|
@@ -441,6 +441,26 @@ module Vinter
|
|
|
441
441
|
advance
|
|
442
442
|
elsif current_token[:type] == :colon
|
|
443
443
|
parse_command_line_call
|
|
444
|
+
elsif current_token[:type] == :number
|
|
445
|
+
advance
|
|
446
|
+
elsif current_token[:type] == :paren_close
|
|
447
|
+
advance
|
|
448
|
+
elsif current_token[:type] == :brace_close
|
|
449
|
+
advance
|
|
450
|
+
elsif current_token[:type] == :interpolated_string
|
|
451
|
+
advance
|
|
452
|
+
elsif current_token[:type] == :heredoc
|
|
453
|
+
# TODO: parse_herdoc
|
|
454
|
+
advance # move past =<<
|
|
455
|
+
while ["trim", "eval"].include?(current_token[:value])
|
|
456
|
+
advance
|
|
457
|
+
end
|
|
458
|
+
stop_token = advance
|
|
459
|
+
while current_token && current_token[:value] != stop_token
|
|
460
|
+
advance
|
|
461
|
+
end
|
|
462
|
+
elsif [:bracket_open, :bracket_close, :operator, :question_mark].include?(current_token[:type])
|
|
463
|
+
advance
|
|
444
464
|
else
|
|
445
465
|
@warnings << {
|
|
446
466
|
message: "Unexpected token type: #{current_token[:type]}",
|
|
@@ -566,6 +586,12 @@ module Vinter
|
|
|
566
586
|
name = token[:value]
|
|
567
587
|
advance # Skip the global variable token
|
|
568
588
|
|
|
589
|
+
# handle vars that include #
|
|
590
|
+
while current_token && (current_token[:type] == :comment || current_token[:type] == :identifier)
|
|
591
|
+
name += current_token[:value]
|
|
592
|
+
advance
|
|
593
|
+
end
|
|
594
|
+
|
|
569
595
|
# Handle property access (e.g., g:foo.bar)
|
|
570
596
|
target = {
|
|
571
597
|
type: :global_variable,
|
|
@@ -575,7 +601,7 @@ module Vinter
|
|
|
575
601
|
}
|
|
576
602
|
|
|
577
603
|
# Property access (dot notation)
|
|
578
|
-
|
|
604
|
+
while current_token && current_token[:type] == :operator && current_token[:value] == '.'
|
|
579
605
|
dot_token = advance
|
|
580
606
|
if current_token && (current_token[:type] == :identifier || current_token[:type] == :keyword)
|
|
581
607
|
property_token = advance
|
|
@@ -613,7 +639,7 @@ module Vinter
|
|
|
613
639
|
operator = current_token[:value]
|
|
614
640
|
advance
|
|
615
641
|
else
|
|
616
|
-
add_error("Expected assignment operator after global variable")
|
|
642
|
+
add_error("Expected assignment operator after global variable: #{current_token[:type]}")
|
|
617
643
|
end
|
|
618
644
|
|
|
619
645
|
# Value expression
|
|
@@ -787,7 +813,6 @@ module Vinter
|
|
|
787
813
|
end
|
|
788
814
|
|
|
789
815
|
def parse_let_statement
|
|
790
|
-
# binding.pry
|
|
791
816
|
token = advance # Skip 'let'
|
|
792
817
|
line = token[:line]
|
|
793
818
|
column = token[:column]
|
|
@@ -1245,7 +1270,8 @@ module Vinter
|
|
|
1245
1270
|
if current_token && (current_token[:type] == :identifier ||
|
|
1246
1271
|
current_token[:type] == :local_variable ||
|
|
1247
1272
|
current_token[:type] == :global_variable ||
|
|
1248
|
-
current_token[:type] == :script_local
|
|
1273
|
+
current_token[:type] == :script_local ||
|
|
1274
|
+
current_token[:type] == :builtin_funcs)
|
|
1249
1275
|
loop_var = advance
|
|
1250
1276
|
else
|
|
1251
1277
|
add_error("Expected identifier as for loop variable")
|
|
@@ -1285,12 +1311,18 @@ module Vinter
|
|
|
1285
1311
|
line = token[:line]
|
|
1286
1312
|
column = token[:column]
|
|
1287
1313
|
|
|
1288
|
-
|
|
1314
|
+
if current_token && current_token[:value] == "!"
|
|
1315
|
+
advance
|
|
1316
|
+
end
|
|
1317
|
+
|
|
1318
|
+
if current_token && [:identifier, :global_variable].include?(current_token[:type])
|
|
1319
|
+
name = advance
|
|
1320
|
+
end
|
|
1321
|
+
#name = expect(:identifier)
|
|
1289
1322
|
|
|
1290
1323
|
# Parse parameter list
|
|
1291
1324
|
expect(:paren_open)
|
|
1292
1325
|
params = parse_parameter_list
|
|
1293
|
-
expect(:paren_close)
|
|
1294
1326
|
|
|
1295
1327
|
# Parse optional return type
|
|
1296
1328
|
return_type = nil
|
|
@@ -1298,12 +1330,12 @@ module Vinter
|
|
|
1298
1330
|
advance # Skip ':'
|
|
1299
1331
|
return_type = parse_type
|
|
1300
1332
|
end
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1333
|
+
body = []
|
|
1334
|
+
while current_token && current_token[:value] != 'enddef'
|
|
1335
|
+
stmt = parse_statement
|
|
1336
|
+
body << stmt if stmt
|
|
1337
|
+
end
|
|
1338
|
+
advance
|
|
1307
1339
|
|
|
1308
1340
|
{
|
|
1309
1341
|
type: :def_function,
|
|
@@ -1321,78 +1353,89 @@ module Vinter
|
|
|
1321
1353
|
|
|
1322
1354
|
# Empty parameter list
|
|
1323
1355
|
if current_token && current_token[:type] == :paren_close
|
|
1356
|
+
advance
|
|
1324
1357
|
return params
|
|
1325
1358
|
end
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
while
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
# Parse type for variable args if present
|
|
1334
|
-
param_type = nil
|
|
1335
|
-
if current_token && current_token[:type] == :colon
|
|
1336
|
-
advance # Skip ':'
|
|
1337
|
-
param_type = parse_type
|
|
1338
|
-
end
|
|
1339
|
-
|
|
1340
|
-
params << {
|
|
1341
|
-
type: :var_args,
|
|
1342
|
-
param_type: param_type,
|
|
1343
|
-
line: ellipsis_token[:line],
|
|
1344
|
-
column: ellipsis_token[:column]
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
|
-
# After varargs, we expect closing paren
|
|
1348
|
-
if current_token && current_token[:type] != :paren_close
|
|
1349
|
-
add_error("Expected closing parenthesis after varargs", current_token)
|
|
1350
|
-
end
|
|
1351
|
-
|
|
1352
|
-
break
|
|
1353
|
-
end
|
|
1354
|
-
|
|
1355
|
-
param_name = advance
|
|
1356
|
-
|
|
1357
|
-
# Check for type annotation
|
|
1358
|
-
param_type = nil
|
|
1359
|
-
if current_token && current_token[:type] == :colon
|
|
1360
|
-
advance # Skip ':'
|
|
1361
|
-
param_type = parse_type
|
|
1362
|
-
end
|
|
1363
|
-
|
|
1364
|
-
# Check for default value
|
|
1365
|
-
default_value = nil
|
|
1366
|
-
if current_token && current_token[:type] == :operator && current_token[:value] == '='
|
|
1367
|
-
advance # Skip '='
|
|
1368
|
-
default_value = parse_expression
|
|
1369
|
-
end
|
|
1370
|
-
|
|
1371
|
-
params << {
|
|
1372
|
-
type: :parameter,
|
|
1373
|
-
name: param_name[:value],
|
|
1374
|
-
param_type: param_type,
|
|
1375
|
-
optional: default_value != nil,
|
|
1376
|
-
default_value: default_value,
|
|
1377
|
-
line: param_name[:line],
|
|
1378
|
-
column: param_name[:column]
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
# If we have a comma, advance past it and continue
|
|
1382
|
-
if current_token && current_token[:type] == :comma
|
|
1383
|
-
advance
|
|
1384
|
-
# If we don't have a comma, we should have a closing paren
|
|
1385
|
-
elsif current_token && current_token[:type] != :paren_close
|
|
1386
|
-
add_error("Expected comma or closing parenthesis after parameter", current_token)
|
|
1387
|
-
break
|
|
1359
|
+
# TODO actually save params
|
|
1360
|
+
required_parens = 1
|
|
1361
|
+
while current_token && required_parens > 0
|
|
1362
|
+
if current_token[:type] == :paren_open
|
|
1363
|
+
required_parens += 1
|
|
1364
|
+
elsif current_token[:type] == :paren_close
|
|
1365
|
+
required_parens -= 1
|
|
1388
1366
|
end
|
|
1367
|
+
advance
|
|
1389
1368
|
end
|
|
1390
1369
|
|
|
1370
|
+
# Parse parameters until we find a closing parenthesis
|
|
1371
|
+
#while @position < @tokens.length && current_token && current_token[:type] != :paren_close
|
|
1372
|
+
## Check for variable args
|
|
1373
|
+
#if current_token && current_token[:type] == :ellipsis
|
|
1374
|
+
#ellipsis_token = advance
|
|
1375
|
+
|
|
1376
|
+
## Parse type for variable args if present
|
|
1377
|
+
#param_type = nil
|
|
1378
|
+
#if current_token && current_token[:type] == :colon
|
|
1379
|
+
#advance # Skip ':'
|
|
1380
|
+
#param_type = parse_type
|
|
1381
|
+
#end
|
|
1382
|
+
|
|
1383
|
+
#params << {
|
|
1384
|
+
#type: :var_args,
|
|
1385
|
+
#param_type: param_type,
|
|
1386
|
+
#line: ellipsis_token[:line],
|
|
1387
|
+
#column: ellipsis_token[:column]
|
|
1388
|
+
#}
|
|
1389
|
+
|
|
1390
|
+
## After varargs, we expect closing paren
|
|
1391
|
+
#if current_token && current_token[:type] != :paren_close
|
|
1392
|
+
#add_error("Expected closing parenthesis after varargs", current_token)
|
|
1393
|
+
#end
|
|
1394
|
+
|
|
1395
|
+
#break
|
|
1396
|
+
#end
|
|
1397
|
+
|
|
1398
|
+
#param_name = advance
|
|
1399
|
+
|
|
1400
|
+
## Check for type annotation
|
|
1401
|
+
#param_type = nil
|
|
1402
|
+
#if current_token && current_token[:type] == :colon
|
|
1403
|
+
#advance # Skip ':'
|
|
1404
|
+
#param_type = parse_type
|
|
1405
|
+
#end
|
|
1406
|
+
|
|
1407
|
+
## Check for default value
|
|
1408
|
+
#default_value = nil
|
|
1409
|
+
#if current_token && current_token[:type] == :operator && current_token[:value] == '='
|
|
1410
|
+
#advance # Skip '='
|
|
1411
|
+
#default_value = parse_expression
|
|
1412
|
+
#end
|
|
1413
|
+
|
|
1414
|
+
#params << {
|
|
1415
|
+
#type: :parameter,
|
|
1416
|
+
#name: param_name[:value],
|
|
1417
|
+
#param_type: param_type,
|
|
1418
|
+
#optional: default_value != nil,
|
|
1419
|
+
#default_value: default_value,
|
|
1420
|
+
#line: param_name[:line],
|
|
1421
|
+
#column: param_name[:column]
|
|
1422
|
+
#}
|
|
1423
|
+
|
|
1424
|
+
## If we have a comma, advance past it and continue
|
|
1425
|
+
#if current_token && current_token[:type] == :comma
|
|
1426
|
+
#advance
|
|
1427
|
+
## If we don't have a comma, we should have a closing paren
|
|
1428
|
+
#elsif current_token && current_token[:type] != :paren_close
|
|
1429
|
+
#add_error("Expected comma or closing parenthesis after parameter", current_token)
|
|
1430
|
+
#break
|
|
1431
|
+
#end
|
|
1432
|
+
#end
|
|
1433
|
+
|
|
1391
1434
|
params
|
|
1392
1435
|
end
|
|
1393
1436
|
|
|
1394
1437
|
def parse_type
|
|
1395
|
-
if current_token && [:identifier, :keyword].include?(current_token[:type])
|
|
1438
|
+
if current_token && [:identifier, :keyword, :type].include?(current_token[:type])
|
|
1396
1439
|
type_name = advance
|
|
1397
1440
|
|
|
1398
1441
|
# Handle generic types like list<string>
|
|
@@ -1412,7 +1455,7 @@ module Vinter
|
|
|
1412
1455
|
|
|
1413
1456
|
return type_name[:value]
|
|
1414
1457
|
else
|
|
1415
|
-
add_error("Expected type identifier")
|
|
1458
|
+
add_error("Expected type identifier: #{current_token[:value]}, #{current_token[:type]}")
|
|
1416
1459
|
advance
|
|
1417
1460
|
return "unknown"
|
|
1418
1461
|
end
|
|
@@ -1424,14 +1467,22 @@ module Vinter
|
|
|
1424
1467
|
line = var_type_token[:line]
|
|
1425
1468
|
column = var_type_token[:column]
|
|
1426
1469
|
|
|
1427
|
-
|
|
1428
|
-
|
|
1470
|
+
# TODO: also handle the variable declration with [a,b]
|
|
1471
|
+
if current_token[:type] == :bracket_open
|
|
1472
|
+
advance
|
|
1473
|
+
name = "[#{current_token[:value]}"
|
|
1474
|
+
while current_token && current_token[:type] != :bracket_close
|
|
1475
|
+
advance
|
|
1476
|
+
name += current_token[:value]
|
|
1477
|
+
end
|
|
1478
|
+
elsif !current_token || ![:identifier, :keyword].include?(current_token[:type])
|
|
1479
|
+
add_error("Expected variable name: #{current_token[:type]}")
|
|
1429
1480
|
return nil
|
|
1481
|
+
else
|
|
1482
|
+
name_token = advance
|
|
1483
|
+
name = name_token[:value]
|
|
1430
1484
|
end
|
|
1431
1485
|
|
|
1432
|
-
name_token = advance
|
|
1433
|
-
name = name_token[:value]
|
|
1434
|
-
|
|
1435
1486
|
# Parse optional type annotation
|
|
1436
1487
|
var_type_annotation = nil
|
|
1437
1488
|
if current_token && current_token[:type] == :colon
|
|
@@ -1443,7 +1494,10 @@ module Vinter
|
|
|
1443
1494
|
initializer = nil
|
|
1444
1495
|
if current_token && (current_token[:type] == :operator && current_token[:value] == '=')
|
|
1445
1496
|
advance # Skip '='
|
|
1446
|
-
|
|
1497
|
+
assignment_line = current_token[:line]
|
|
1498
|
+
while current_token[:line] == assignment_line
|
|
1499
|
+
advance
|
|
1500
|
+
end
|
|
1447
1501
|
end
|
|
1448
1502
|
|
|
1449
1503
|
{
|
|
@@ -1524,14 +1578,13 @@ module Vinter
|
|
|
1524
1578
|
end
|
|
1525
1579
|
|
|
1526
1580
|
def parse_expression
|
|
1527
|
-
# binding.pry
|
|
1528
1581
|
# Special case for empty return statements or standalone keywords that shouldn't be expressions
|
|
1529
1582
|
if current_token && current_token[:type] == :keyword &&
|
|
1530
1583
|
['return', 'endif', 'endwhile', 'endfor', 'endfunction', 'endfunc'].include?(current_token[:value])
|
|
1531
1584
|
return nil
|
|
1532
1585
|
end
|
|
1533
1586
|
|
|
1534
|
-
if current_token[:type] == :string
|
|
1587
|
+
if current_token && current_token[:type] == :string
|
|
1535
1588
|
string_value = current_token[:value]
|
|
1536
1589
|
while current_token && peek_token && [:line_continuation, :identifier].include?(peek_token[:type])
|
|
1537
1590
|
# Handle strings with line continuation
|
|
@@ -1557,36 +1610,14 @@ module Vinter
|
|
|
1557
1610
|
expr = parse_binary_expression
|
|
1558
1611
|
|
|
1559
1612
|
# Check if this is a ternary expression
|
|
1560
|
-
if current_token && (current_token[:type] == :question_mark || (current_token[:type] == :operator && current_token[:value] == '?'))
|
|
1613
|
+
if current_token && (current_token[:type] == :question_mark && peek_token[:type] != :question_mark || (current_token[:type] == :operator && current_token[:value] == '?'))
|
|
1561
1614
|
question_token = advance # Skip '?'
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
then_expr = parse_expression
|
|
1565
|
-
|
|
1566
|
-
# Expect the colon
|
|
1567
|
-
if current_token && current_token[:type] == :colon
|
|
1568
|
-
colon_token = advance # Skip ':'
|
|
1569
|
-
|
|
1570
|
-
# Parse the "else" expression
|
|
1571
|
-
else_expr = parse_expression
|
|
1572
|
-
|
|
1573
|
-
# Return the ternary expression
|
|
1574
|
-
return {
|
|
1575
|
-
type: :ternary_expression,
|
|
1576
|
-
condition: expr,
|
|
1577
|
-
then_expr: then_expr,
|
|
1578
|
-
else_expr: else_expr,
|
|
1579
|
-
line: question_token[:line],
|
|
1580
|
-
column: question_token[:column]
|
|
1581
|
-
}
|
|
1582
|
-
else
|
|
1583
|
-
@errors << {
|
|
1584
|
-
message: "Expected ':' in ternary expression",
|
|
1585
|
-
position: @position,
|
|
1586
|
-
line: current_token ? current_token[:line] : 0,
|
|
1587
|
-
column: current_token ? current_token[:column] : 0
|
|
1588
|
-
}
|
|
1615
|
+
while current_token[:value] != ':'
|
|
1616
|
+
advance
|
|
1589
1617
|
end
|
|
1618
|
+
advance # skip :
|
|
1619
|
+
|
|
1620
|
+
parse_expression
|
|
1590
1621
|
end
|
|
1591
1622
|
|
|
1592
1623
|
return expr
|
|
@@ -1793,9 +1824,18 @@ module Vinter
|
|
|
1793
1824
|
line: line,
|
|
1794
1825
|
column: column
|
|
1795
1826
|
}
|
|
1827
|
+
elsif current_token && current_token[:type] == :option_variable
|
|
1828
|
+
option_var = advance
|
|
1829
|
+
expect(:paren_close)
|
|
1830
|
+
return {
|
|
1831
|
+
type: :function_reference,
|
|
1832
|
+
function_body: option_var[:value],
|
|
1833
|
+
line: line,
|
|
1834
|
+
column: column
|
|
1835
|
+
}
|
|
1796
1836
|
else
|
|
1797
1837
|
@errors << {
|
|
1798
|
-
message: "Expected string or arrow function definition in function() call",
|
|
1838
|
+
message: "Expected string or arrow function definition in function() call: #{current_token}",
|
|
1799
1839
|
position: @position,
|
|
1800
1840
|
line: current_token ? current_token[:line] : 0,
|
|
1801
1841
|
column: current_token ? current_token[:column] : 0
|
|
@@ -1812,29 +1852,12 @@ module Vinter
|
|
|
1812
1852
|
column: column
|
|
1813
1853
|
}
|
|
1814
1854
|
end
|
|
1815
|
-
# Legacy Vim allows certain keywords as identifiers in expressions
|
|
1816
|
-
elsif ['return', 'type'].include?(token[:value])
|
|
1817
|
-
# Handle 'return' keyword specially when it appears in an expression context
|
|
1818
|
-
advance
|
|
1819
|
-
@warnings << {
|
|
1820
|
-
message: "Keyword '#{token[:value]}' used in an expression context",
|
|
1821
|
-
position: @position,
|
|
1822
|
-
line: line,
|
|
1823
|
-
column: column
|
|
1824
|
-
}
|
|
1825
|
-
# Check if this is a function call for 'type'
|
|
1826
|
-
if token[:value] == 'type' && current_token && current_token[:type] == :paren_open
|
|
1827
|
-
return parse_function_call(token[:value], line, column)
|
|
1828
|
-
end
|
|
1829
|
-
|
|
1830
|
-
expr = {
|
|
1831
|
-
type: :identifier,
|
|
1832
|
-
name: token[:value],
|
|
1833
|
-
line: line,
|
|
1834
|
-
column: column
|
|
1835
|
-
}
|
|
1836
1855
|
elsif token[:value] == 'command'
|
|
1837
1856
|
advance
|
|
1857
|
+
elsif token[:value] == 'return'
|
|
1858
|
+
advance
|
|
1859
|
+
elsif token[:value] == 'elseif'
|
|
1860
|
+
advance
|
|
1838
1861
|
else
|
|
1839
1862
|
@errors << {
|
|
1840
1863
|
message: "Unexpected keyword in expression: #{token[:value]}",
|
|
@@ -2015,8 +2038,18 @@ module Vinter
|
|
|
2015
2038
|
return parse_lambda_expression(line, column)
|
|
2016
2039
|
else
|
|
2017
2040
|
advance # Skip '('
|
|
2018
|
-
|
|
2019
|
-
|
|
2041
|
+
required_parens = 1
|
|
2042
|
+
while current_token && required_parens > 0
|
|
2043
|
+
if current_token[:type] == :paren_open
|
|
2044
|
+
required_parens += 1
|
|
2045
|
+
elsif current_token[:type] == :paren_close
|
|
2046
|
+
required_parens -= 1
|
|
2047
|
+
end
|
|
2048
|
+
advance
|
|
2049
|
+
end
|
|
2050
|
+
#expr = parse_expression
|
|
2051
|
+
#binding.pry
|
|
2052
|
+
#expect(:paren_close) # Expect and skip ')'
|
|
2020
2053
|
end
|
|
2021
2054
|
when :bracket_open
|
|
2022
2055
|
expr = parse_list_literal(line, column)
|
|
@@ -2044,9 +2077,23 @@ module Vinter
|
|
|
2044
2077
|
type: :interpolated_string,
|
|
2045
2078
|
value: token[:value],
|
|
2046
2079
|
}
|
|
2080
|
+
when :builtin_funcs
|
|
2081
|
+
expr = parse_builtin_function_call
|
|
2082
|
+
when :type
|
|
2083
|
+
advance
|
|
2084
|
+
when :colon
|
|
2085
|
+
advance
|
|
2086
|
+
when :operator
|
|
2087
|
+
advance
|
|
2088
|
+
when :silent_bang
|
|
2089
|
+
advance
|
|
2090
|
+
when :question_mark
|
|
2091
|
+
advance
|
|
2092
|
+
when :comment, :compound_operator, :bracket_close
|
|
2093
|
+
advance
|
|
2047
2094
|
else
|
|
2048
2095
|
@errors << {
|
|
2049
|
-
message: "Unexpected token in expression: #{token[:type]}",
|
|
2096
|
+
message: "Unexpected token in expression: #{token[:type]} | #{token[:value]}",
|
|
2050
2097
|
position: @position,
|
|
2051
2098
|
line: line,
|
|
2052
2099
|
column: column
|
|
@@ -2103,7 +2150,9 @@ module Vinter
|
|
|
2103
2150
|
advance if current_token[:type] == :line_continuation
|
|
2104
2151
|
|
|
2105
2152
|
# Next token should be an identifier (method name)
|
|
2106
|
-
if
|
|
2153
|
+
if current_token && current_token[:type] == :builtin_funcs
|
|
2154
|
+
parse_builtin_function_call
|
|
2155
|
+
elsif !current_token || current_token[:type] != :identifier
|
|
2107
2156
|
@errors << {
|
|
2108
2157
|
message: "Expected method name after '->'",
|
|
2109
2158
|
position: @position,
|
|
@@ -2118,23 +2167,15 @@ module Vinter
|
|
|
2118
2167
|
# Check for arguments
|
|
2119
2168
|
args = []
|
|
2120
2169
|
if current_token && current_token[:type] == :paren_open
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
args << arg if arg
|
|
2128
|
-
|
|
2129
|
-
if current_token && current_token[:type] == :comma
|
|
2130
|
-
advance # Skip comma
|
|
2131
|
-
else
|
|
2132
|
-
break
|
|
2133
|
-
end
|
|
2170
|
+
paren_count = 1
|
|
2171
|
+
while current_token && paren_count > 0
|
|
2172
|
+
if current_token[:type] == :paren_open
|
|
2173
|
+
paren_count += 1
|
|
2174
|
+
elsif current_token[:type] == :paren_close
|
|
2175
|
+
paren_count -= 1
|
|
2134
2176
|
end
|
|
2177
|
+
advance
|
|
2135
2178
|
end
|
|
2136
|
-
|
|
2137
|
-
expect(:paren_close) # Skip ')'
|
|
2138
2179
|
end
|
|
2139
2180
|
|
|
2140
2181
|
expr = {
|
|
@@ -2239,17 +2280,29 @@ module Vinter
|
|
|
2239
2280
|
column = token[:column]
|
|
2240
2281
|
name = token[:value]
|
|
2241
2282
|
|
|
2242
|
-
#
|
|
2243
|
-
|
|
2244
|
-
while current_token &&
|
|
2245
|
-
|
|
2283
|
+
#expect(:paren_open)
|
|
2284
|
+
required_parens = 1
|
|
2285
|
+
while current_token && required_parens > 0
|
|
2286
|
+
if current_token[:type] == :paren_close
|
|
2287
|
+
required_parens -= 1
|
|
2288
|
+
elsif current_token[:type] == :paren_open
|
|
2289
|
+
required_parens += 1
|
|
2290
|
+
end
|
|
2246
2291
|
advance
|
|
2247
2292
|
end
|
|
2248
2293
|
|
|
2294
|
+
# Collect arguments (if any) until the end of the line
|
|
2295
|
+
#args = []
|
|
2296
|
+
#while current_token && current_token[:type] != :comment && current_token[:value] != "\n"
|
|
2297
|
+
#puts current_token[:value]
|
|
2298
|
+
#args << current_token[:value]
|
|
2299
|
+
#advance
|
|
2300
|
+
#end
|
|
2301
|
+
|
|
2249
2302
|
{
|
|
2250
2303
|
type: :builtin_function_call,
|
|
2251
2304
|
name: name,
|
|
2252
|
-
arguments: args,
|
|
2305
|
+
#arguments: args,
|
|
2253
2306
|
line: line,
|
|
2254
2307
|
column: column
|
|
2255
2308
|
}
|
|
@@ -2563,7 +2616,7 @@ module Vinter
|
|
|
2563
2616
|
# Parse dictionary entries
|
|
2564
2617
|
while current_token && current_token[:type] != :brace_close
|
|
2565
2618
|
# Skip any backslash line continuation markers and whitespace
|
|
2566
|
-
while current_token &&
|
|
2619
|
+
while current_token && [:backslash, :whitespace, :line_continuation, :comment].include?(current_token[:type])
|
|
2567
2620
|
advance
|
|
2568
2621
|
end
|
|
2569
2622
|
|
|
@@ -2574,12 +2627,12 @@ module Vinter
|
|
|
2574
2627
|
|
|
2575
2628
|
# Parse key (string or identifier)
|
|
2576
2629
|
key = nil
|
|
2577
|
-
if current_token &&
|
|
2630
|
+
if current_token && [:string, :identifier, :keyword].include?(current_token[:type])
|
|
2578
2631
|
key = current_token[:value]
|
|
2579
2632
|
advance # Skip key
|
|
2580
2633
|
else
|
|
2581
2634
|
@errors << {
|
|
2582
|
-
message: "Expected string or identifier as dictionary key",
|
|
2635
|
+
message: "Expected string or identifier as dictionary key #{current_token}",
|
|
2583
2636
|
position: @position,
|
|
2584
2637
|
line: current_token ? current_token[:line] : 0,
|
|
2585
2638
|
column: current_token ? current_token[:column] : 0
|
|
@@ -2639,7 +2692,7 @@ module Vinter
|
|
|
2639
2692
|
# Skip any line continuations and whitespace after comma
|
|
2640
2693
|
while current_token && (current_token[:type] == :whitespace ||
|
|
2641
2694
|
current_token[:type] == :backslash ||
|
|
2642
|
-
current_token[:type] == :line_continuation)
|
|
2695
|
+
current_token[:type] == :line_continuation || current_token[:type] == :comment)
|
|
2643
2696
|
advance
|
|
2644
2697
|
end
|
|
2645
2698
|
else
|
|
@@ -2805,41 +2858,17 @@ module Vinter
|
|
|
2805
2858
|
args = []
|
|
2806
2859
|
|
|
2807
2860
|
# Parse arguments until we find a closing parenthesis
|
|
2808
|
-
while @position < @tokens.length && current_token && current_token[:type] != :paren_close
|
|
2809
|
-
# Skip line continuations
|
|
2810
|
-
if current_token[:type] == :line_continuation
|
|
2811
|
-
advance
|
|
2812
|
-
next
|
|
2813
|
-
end
|
|
2814
2861
|
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
break
|
|
2822
|
-
end
|
|
2823
|
-
|
|
2824
|
-
# If we have a comma, advance past it and continue
|
|
2825
|
-
if current_token && current_token[:type] == :comma
|
|
2826
|
-
advance
|
|
2827
|
-
elsif current_token[:type] == :line_continuation
|
|
2828
|
-
advance
|
|
2829
|
-
# If we don't have a comma and we're not at the end, it's an error
|
|
2830
|
-
elsif current_token && current_token[:type] != :paren_close
|
|
2831
|
-
@errors << {
|
|
2832
|
-
message: "Expected comma or closing parenthesis after argument",
|
|
2833
|
-
position: @position,
|
|
2834
|
-
line: current_token[:line],
|
|
2835
|
-
column: current_token[:column]
|
|
2836
|
-
}
|
|
2837
|
-
break
|
|
2862
|
+
required_parens = 1
|
|
2863
|
+
while current_token && required_parens > 0
|
|
2864
|
+
if current_token[:type] == :paren_open
|
|
2865
|
+
required_parens += 1
|
|
2866
|
+
elsif current_token[:type] == :paren_close
|
|
2867
|
+
required_parens -= 1
|
|
2838
2868
|
end
|
|
2869
|
+
advance
|
|
2839
2870
|
end
|
|
2840
2871
|
|
|
2841
|
-
expect(:paren_close)
|
|
2842
|
-
|
|
2843
2872
|
{
|
|
2844
2873
|
type: :function_call,
|
|
2845
2874
|
name: name,
|
|
@@ -2945,9 +2974,10 @@ module Vinter
|
|
|
2945
2974
|
|
|
2946
2975
|
# Handle 'as name'
|
|
2947
2976
|
as_name = nil
|
|
2948
|
-
if current_token && current_token[:
|
|
2977
|
+
if current_token && current_token[:value] == 'as'
|
|
2949
2978
|
advance # Skip 'as'
|
|
2950
|
-
|
|
2979
|
+
|
|
2980
|
+
if current_token && [:identifier, :keyword].include?(current_token[:type])
|
|
2951
2981
|
as_name = advance[:value]
|
|
2952
2982
|
else
|
|
2953
2983
|
@errors << {
|
|
@@ -2994,7 +3024,7 @@ module Vinter
|
|
|
2994
3024
|
|
|
2995
3025
|
exported_item = nil
|
|
2996
3026
|
|
|
2997
|
-
if current_token[:type] == :keyword
|
|
3027
|
+
if current_token[:type] == :keyword || current_token[:type] == :identifier
|
|
2998
3028
|
case current_token[:value]
|
|
2999
3029
|
when 'def'
|
|
3000
3030
|
exported_item = parse_def_function
|
|
@@ -3003,15 +3033,13 @@ module Vinter
|
|
|
3003
3033
|
when 'var', 'const', 'final'
|
|
3004
3034
|
exported_item = parse_variable_declaration
|
|
3005
3035
|
when 'class'
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
}
|
|
3036
|
+
exported_item = parse_class_definition
|
|
3037
|
+
when 'interface'
|
|
3038
|
+
exported_item = parse_interface_definition
|
|
3039
|
+
when 'enum'
|
|
3040
|
+
exported_item = parse_enum_definition
|
|
3041
|
+
when 'abstract'
|
|
3013
3042
|
advance
|
|
3014
|
-
return nil
|
|
3015
3043
|
else
|
|
3016
3044
|
@errors << {
|
|
3017
3045
|
message: "Unexpected keyword after export: #{current_token[:value]}",
|
|
@@ -3041,6 +3069,34 @@ module Vinter
|
|
|
3041
3069
|
}
|
|
3042
3070
|
end
|
|
3043
3071
|
|
|
3072
|
+
def parse_enum_definition
|
|
3073
|
+
while current_token && current_token[:value] != "endenum"
|
|
3074
|
+
advance
|
|
3075
|
+
end
|
|
3076
|
+
{
|
|
3077
|
+
type: :enum_definition,
|
|
3078
|
+
}
|
|
3079
|
+
end
|
|
3080
|
+
|
|
3081
|
+
def parse_interface_definition
|
|
3082
|
+
while current_token && current_token[:value] != "endinterface"
|
|
3083
|
+
advance
|
|
3084
|
+
end
|
|
3085
|
+
{
|
|
3086
|
+
type: :interface_definition,
|
|
3087
|
+
}
|
|
3088
|
+
end
|
|
3089
|
+
|
|
3090
|
+
def parse_class_definition
|
|
3091
|
+
# TODO: do this properly.. for now we will just look for endclass
|
|
3092
|
+
while current_token && current_token[:value] != "endclass"
|
|
3093
|
+
advance
|
|
3094
|
+
end
|
|
3095
|
+
{
|
|
3096
|
+
type: :class_definition,
|
|
3097
|
+
}
|
|
3098
|
+
end
|
|
3099
|
+
|
|
3044
3100
|
def parse_command_definition
|
|
3045
3101
|
token = advance # Skip 'command' or 'command!'
|
|
3046
3102
|
line = token[:line]
|