dms-parser 0.5.1 → 0.5.2

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dms/tier1.rb +61 -28
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ff6c29cfa7778eda9199a9b532ea2af36616977b1f4d839c39b7a6816e61b9c
4
- data.tar.gz: '0049b496c4f68647eaf9078bdba8e165b67d049e51c194f9119142bc5e3e9769'
3
+ metadata.gz: 356dcaecf022100fac1eeae5350a76ecfc417f831f64084ffe912cd4da486a80
4
+ data.tar.gz: 74e4bd7721ac3f5c7325ada5145c98ad5eccb7723c6e0eed45fcd99dd0a61b9e
5
5
  SHA512:
6
- metadata.gz: 5be4558f18b436cd0d5c943bc829b98547a724e5c10a214238f4fcadf24c4b24c3e3812b6b0f2b12912f08981e29c394d79d8208fa009151374271c473fa95f6
7
- data.tar.gz: 491cab0c32eaa8d224ded077cafddd7f4d7fbefd4a50ce6a9e6000594058c40da8020798706e24ceb70ec0ad3fea982f7374dd45f471f4c88c9237ae1c8df15f
6
+ metadata.gz: 39ef8d91e5fdb82746a03ddc8e3b367970b60ff2291021b7a33ed922d3fc93a377f6e0a4c4ddd9093d52f9c7aae87bf3d674ca089bd18c6d6a42fcde2c58358a
7
+ data.tar.gz: d95fec6634f7049576d56e93195eb47f772e54daa49e270ea7afeace93c2ea3021747c9b8e4a8baa17e54779e1d687198f58462da5a7fd1531d6baf05f521cc8
data/lib/dms/tier1.rb CHANGED
@@ -217,7 +217,7 @@ module Dms
217
217
  # params: Array of ParamGroup
218
218
  # params_dec: Array (always empty in this implementation)
219
219
  # sigil: String (the literal sigil string)
220
- DecoratorCall = Struct.new(:sigil, :family, :fn_name, :ns, :position, :params, :params_dec)
220
+ DecoratorCall = Struct.new(:sigil, :family, :fn_name, :ns, :position, :params, :params_dec, :call_style)
221
221
 
222
222
  # kind: :named or :positional
223
223
  # value: Hash (for named) or Array (for positional)
@@ -463,7 +463,8 @@ module Dms
463
463
  # Resolve a decorator call's family from imports.
464
464
  # Returns [family_name, canonical_fn_name] or raises.
465
465
  # Also applies deny-list check.
466
- def self.resolve_family(sigil, fn_name, ns, imports)
466
+ # call_style: :named or :nameless
467
+ def self.resolve_family(sigil, fn_name, ns, imports, call_style: :named)
467
468
  # Filter imports by ns if specified
468
469
  candidate_imports = if ns
469
470
  filtered = imports.select { |imp| imp.ns == ns }
@@ -475,6 +476,24 @@ module Dms
475
476
  imports
476
477
  end
477
478
 
479
+ # Nameless call: fn_name is empty; resolve to the single bound family name
480
+ if call_style == :nameless
481
+ bound_families = []
482
+ candidate_imports.each do |imp|
483
+ (imp.bind[sigil] || []).each { |fam| bound_families << fam }
484
+ end
485
+ if bound_families.empty?
486
+ raise DecodeError.new(0, 0, "unbound sigil '#{sigil}'")
487
+ end
488
+ if bound_families.size > 1
489
+ raise DecodeError.new(0, 0,
490
+ "nameless call on sigil '#{sigil}' is ambiguous between families " \
491
+ + bound_families.map { |f| "'#{f}'" }.join(", "))
492
+ end
493
+ family = bound_families.first
494
+ return [family, family]
495
+ end
496
+
478
497
  # For each import, check families bound to this sigil
479
498
  # Apply aliases and allow/deny rules
480
499
  accepted = [] # [family_name, canonical_fn_name]
@@ -773,8 +792,8 @@ module Dms
773
792
  # But we don't know the next key yet — so we store them as pending.
774
793
  def collect_leading_decorators(path_prefix)
775
794
  while !eof? && sigil_at?(@pos)
776
- sigil, fn_name, ns, params = parse_decorator_call
777
- @pending_leading << { sigil: sigil, fn_name: fn_name, ns: ns, params: params }
795
+ sigil, fn_name, ns, params, cs = parse_decorator_call
796
+ @pending_leading << { sigil: sigil, fn_name: fn_name, ns: ns, params: params, call_style: cs }
778
797
  skip_trivia_no_consume_leading
779
798
  break if eof?
780
799
  # Check if next line also starts with a sigil
@@ -824,8 +843,8 @@ module Dms
824
843
  if sigil_at?(@pos)
825
844
  # Collect leading decorators for next value
826
845
  loop do
827
- sigil, fn_name, ns, params = parse_decorator_call
828
- @pending_leading << { sigil: sigil, fn_name: fn_name, ns: ns, params: params }
846
+ sigil, fn_name, ns, params, cs = parse_decorator_call
847
+ @pending_leading << { sigil: sigil, fn_name: fn_name, ns: ns, params: params, call_style: cs }
829
848
  # After decorator call, consume rest of line
830
849
  skip_inline_ws
831
850
  if consume_eol || eof?
@@ -860,8 +879,8 @@ module Dms
860
879
  pending = @pending_leading.dup
861
880
  @pending_leading.clear
862
881
  pending.each do |dec|
863
- family, canonical_fn = resolve_call(dec[:sigil], dec[:fn_name], dec[:ns])
864
- add_decorator_call(current_path, dec[:sigil], family, canonical_fn, dec[:ns], :leading, dec[:params])
882
+ family, canonical_fn = resolve_call(dec[:sigil], dec[:fn_name], dec[:ns], call_style: dec[:call_style] || :named)
883
+ add_decorator_call(current_path, dec[:sigil], family, canonical_fn, dec[:ns], :leading, dec[:params], call_style: dec[:call_style] || :named)
865
884
  end
866
885
  end
867
886
 
@@ -1029,9 +1048,9 @@ module Dms
1029
1048
  def parse_t1_inner_and_value(path)
1030
1049
  # Collect all consecutive inner decorator calls
1031
1050
  while !eof? && sigil_at?(@pos)
1032
- sigil, fn_name, ns, params = parse_decorator_call
1033
- family, canonical_fn = resolve_call(sigil, fn_name, ns)
1034
- add_decorator_call(path, sigil, family, canonical_fn, ns, :inner, params)
1051
+ sigil, fn_name, ns, params, cs = parse_decorator_call
1052
+ family, canonical_fn = resolve_call(sigil, fn_name, ns, call_style: cs || :named)
1053
+ add_decorator_call(path, sigil, family, canonical_fn, ns, :inner, params, call_style: cs || :named)
1035
1054
  skip_inline_ws
1036
1055
  end
1037
1056
 
@@ -1059,9 +1078,9 @@ module Dms
1059
1078
 
1060
1079
  def parse_t1_trailing_decorators(path)
1061
1080
  while !eof? && sigil_at?(@pos)
1062
- sigil, fn_name, ns, params = parse_decorator_call
1063
- family, canonical_fn = resolve_call(sigil, fn_name, ns)
1064
- add_decorator_call(path, sigil, family, canonical_fn, ns, :trailing, params)
1081
+ sigil, fn_name, ns, params, cs = parse_decorator_call
1082
+ family, canonical_fn = resolve_call(sigil, fn_name, ns, call_style: cs || :named)
1083
+ add_decorator_call(path, sigil, family, canonical_fn, ns, :trailing, params, call_style: cs || :named)
1065
1084
  skip_inline_ws
1066
1085
  end
1067
1086
  end
@@ -1081,15 +1100,28 @@ module Dms
1081
1100
 
1082
1101
  raise DecodeError.new(@line, col, "empty decorator sigil") if sigil.empty?
1083
1102
 
1084
- # Parse name (bare identifier)
1085
- # Could be: name OR ns.name
1086
- name1 = parse_bare_ident
1087
- raise DecodeError.new(@line, col, "expected decorator name after sigil '#{sigil}'") if name1.empty?
1103
+ # Parse name (bare identifier) — may be empty for nameless calls
1104
+ # Nameless: sigil followed by '(', whitespace, EOL, ',', ']', '}'
1105
+ # Error: sigil followed by '.' (dotted form requires name before '.')
1106
+ next_byte = @src.getbyte(@pos)
1107
+ call_style = :named
1108
+ if next_byte == DOT
1109
+ raise DecodeError.new(@line, col, "dotted form requires a name before '.'")
1110
+ elsif next_byte == LPAREN || next_byte == SP || next_byte == TAB ||
1111
+ next_byte == LF || next_byte == CR || next_byte == COMMA ||
1112
+ next_byte == RBRACK || next_byte == RBRACE || next_byte.nil? || @pos >= @src.bytesize
1113
+ # Nameless call
1114
+ call_style = :nameless
1115
+ name1 = ""
1116
+ else
1117
+ name1 = parse_bare_ident
1118
+ raise DecodeError.new(@line, col, "expected decorator name after sigil '#{sigil}'") if name1.empty?
1119
+ end
1088
1120
 
1089
1121
  # Check for '.' => namespace qualifier
1090
1122
  ns = nil
1091
1123
  fn_name = name1
1092
- if @src.getbyte(@pos) == DOT
1124
+ if call_style == :named && @src.getbyte(@pos) == DOT
1093
1125
  @pos += 1 # consume '.'
1094
1126
  name2 = parse_bare_ident
1095
1127
  if name2.empty?
@@ -1122,7 +1154,7 @@ module Dms
1122
1154
  # If no params at all, treat as one empty named group
1123
1155
  params << ParamGroup.new(:named, {}) if params.empty?
1124
1156
 
1125
- [sigil, fn_name, ns, params]
1157
+ [sigil, fn_name, ns, params, call_style]
1126
1158
  end
1127
1159
 
1128
1160
  # Parse a param group (between parens, after '(' was consumed).
@@ -1244,9 +1276,9 @@ module Dms
1244
1276
  # Inner decorator in flow array
1245
1277
  loop do
1246
1278
  break unless sigil_at?(@pos)
1247
- sigil, fn_name, ns, params = parse_decorator_call
1248
- family, canonical_fn = resolve_call(sigil, fn_name, ns)
1249
- add_decorator_call(current_path, sigil, family, canonical_fn, ns, :inner, params)
1279
+ sigil, fn_name, ns, params, cs = parse_decorator_call
1280
+ family, canonical_fn = resolve_call(sigil, fn_name, ns, call_style: cs || :named)
1281
+ add_decorator_call(current_path, sigil, family, canonical_fn, ns, :inner, params, call_style: cs || :named)
1250
1282
  skip_inline_ws
1251
1283
  end
1252
1284
  # Now parse the actual value
@@ -1326,20 +1358,20 @@ module Dms
1326
1358
  val
1327
1359
  end
1328
1360
 
1329
- def add_decorator_call(path, sigil, family, fn_name, ns, position, params)
1361
+ def add_decorator_call(path, sigil, family, fn_name, ns, position, params, call_style: :named)
1330
1362
  path_key = path_to_key(path)
1331
1363
  entry = @dec_entries[path_key]
1332
1364
  if entry.nil?
1333
1365
  entry = DecoratorEntry.new(path.dup, {}, [])
1334
1366
  @dec_entries[path_key] = entry
1335
1367
  end
1336
- call = DecoratorCall.new(sigil, family, fn_name, ns, position, params, [])
1368
+ call = DecoratorCall.new(sigil, family, fn_name, ns, position, params, [], call_style)
1337
1369
  entry.calls[sigil] ||= []
1338
1370
  entry.calls[sigil] << call
1339
1371
  end
1340
1372
 
1341
- def resolve_call(sigil, fn_name, ns)
1342
- Tier1.resolve_family(sigil, fn_name, ns, @imports)
1373
+ def resolve_call(sigil, fn_name, ns, call_style: :named)
1374
+ Tier1.resolve_family(sigil, fn_name, ns, @imports, call_style: call_style)
1343
1375
  end
1344
1376
 
1345
1377
  def path_to_key(path)
@@ -1732,7 +1764,8 @@ module Dms
1732
1764
  "ns" => call.ns,
1733
1765
  "position" => call.position.to_s,
1734
1766
  "params" => params_json,
1735
- "params_dec" => []
1767
+ "params_dec" => [],
1768
+ "call_style" => (call.call_style || :named).to_s
1736
1769
  }
1737
1770
  end
1738
1771
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dms-parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Filip Lopes