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.
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
- if current_token && current_token[:type] == :operator && current_token[:value] == '.'
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
- name = expect(:identifier)
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
- # Parse function body until 'enddef'
1303
- body = parse_body_until('enddef')
1304
-
1305
- # Expect enddef
1306
- expect_end_keyword('enddef')
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
- # 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
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
- if !current_token || current_token[:type] != :identifier
1428
- add_error("Expected variable name")
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
- initializer = parse_expression
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
- # 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
- }
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
- expr = parse_expression
2019
- expect(:paren_close) # Expect and skip ')'
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 !current_token || current_token[:type] != :identifier
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
- 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
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
- # 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]
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 && (current_token[:type] == :backslash || current_token[:type] == :whitespace || current_token[:type] == :line_continuation)
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 && (current_token[:type] == :string || current_token[:type] == :identifier)
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
- # 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
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[:type] == :identifier && current_token[:value] == 'as'
2977
+ if current_token && current_token[:value] == 'as'
2949
2978
  advance # Skip 'as'
2950
- if current_token && current_token[:type] == :identifier
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
- # 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
- }
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]