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