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.
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
- if current_token && current_token[:type] == :operator && current_token[:value] == '.'
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
- name = expect(:identifier)
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
- # Parse function body until 'enddef'
1303
- body = parse_body_until('enddef')
1304
-
1305
- # Expect enddef
1306
- expect_end_keyword('enddef')
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
- # Parse parameters until we find a closing parenthesis
1328
- while @position < @tokens.length && current_token && current_token[:type] != :paren_close
1329
- # Check for variable args
1330
- if current_token && current_token[:type] == :ellipsis
1331
- ellipsis_token = advance
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
- if !current_token || current_token[:type] != :identifier
1428
- add_error("Expected variable name")
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
- initializer = parse_expression
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
- # Parse the "then" expression
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
- expr = parse_expression
2019
- expect(:paren_close) # Expect and skip ')'
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 !current_token || current_token[:type] != :identifier
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
- expect(:paren_open) # Skip '('
2122
-
2123
- # Parse arguments if any
2124
- unless current_token && current_token[:type] == :paren_close
2125
- loop do
2126
- arg = parse_expression
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
- # Collect arguments (if any) until the end of the line
2243
- args = []
2244
- while current_token && current_token[:type] != :comment && current_token[:value] != "\n"
2245
- args << current_token[:value]
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 && (current_token[:type] == :backslash || current_token[:type] == :whitespace || current_token[:type] == :line_continuation)
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 && (current_token[:type] == :string || current_token[:type] == :identifier)
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
- # Parse the argument
2816
- arg = parse_expression
2817
- args << arg if arg
2818
-
2819
- # Break if we hit the closing parenthesis
2820
- if current_token && current_token[:type] == :paren_close
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[:type] == :identifier && current_token[:value] == 'as'
2978
+ if current_token && current_token[:value] == 'as'
2949
2979
  advance # Skip 'as'
2950
- if current_token && current_token[:type] == :identifier
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
- # Handle class export when implemented
3007
- @errors << {
3008
- message: "Class export not implemented yet",
3009
- position: @position,
3010
- line: current_token[:line],
3011
- column: current_token[:column]
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]