Skip to content

Commit e77d41d

Browse files
committed
feat(isc): support function targets (upcase/downcase), any(alias), empty fields
- Add upcase/downcase/title_case/reverse/strip/swapcase as function_call item atoms (used as to: value) - any() now accepts bare identifier (alias_arg) inside parens, e.g. before any(upper) - generic_field accepts empty fields (just identifier, no value) - Add comment handling in tests_block converter Verification: 172/289 maps equivalent (60%).
1 parent c31f503 commit e77d41d

5 files changed

Lines changed: 40 additions & 3 deletions

File tree

exe/codemod-imp-to-isc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,9 @@ module Interscript
376376
elsif @scanner.scan(/\}/)
377377
depth -= 1
378378
@out << "}"
379+
elsif @scanner.scan(/#[^\n]*/)
380+
# Preserve comment lines verbatim
381+
@out << @scanner.matched
379382
elsif @scanner.scan(/\btest\b/)
380383
# `test "X", "Y"` -> `"X" -> "Y"`
381384
@out << ""

lib/interscript/isc/grammar/concerns/items.rb

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,18 @@ module Items
1717
any_constructor |
1818
capture_constructor |
1919
maybe_constructor |
20+
function_call |
2021
capture_reference |
2122
alias_reference
2223
end
2324

25+
# Function call: upcase, downcase, title_case, reverse, etc.
26+
# These appear as the `to` value in sub rules: `sub "X" upcase`.
27+
rule(:function_call) do
28+
(str("upcase") | str("downcase") | str("title_case") |
29+
str("reverse") | str("strip") | str("swapcase")).as(:function)
30+
end
31+
2432
rule(:zero_width_primitive) do
2533
(
2634
str("boundary") |
@@ -34,10 +42,15 @@ module Items
3442

3543
rule(:any_constructor) do
3644
str("any") >> str("(") >> whitespace? >>
37-
(range_arg | set_arg).as(:any) >>
45+
(range_arg | set_arg | alias_arg).as(:any) >>
3846
whitespace? >> str(")")
3947
end
4048

49+
# `any(identifier)` — accept a bare alias reference inside any().
50+
rule(:alias_arg) do
51+
(keyword.absent? >> identifier).as(:alias_ref)
52+
end
53+
4154
# capture(...) — wraps a sub-expression with a capture group.
4255
# The captured value can be referenced in the target via `ref(N)`.
4356
rule(:capture_constructor) do

lib/interscript/isc/grammar/concerns/metadata.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,19 @@ module Metadata
113113
# field additions; semantic validation happens in DocumentBuilder.
114114
rule(:generic_field) do
115115
identifier.as(:field_name) >> whitespace? >>
116-
field_value.as(:field_value)
116+
(empty_field | field_value.as(:field_value))
117117
end
118118

119119
rule(:field_value) do
120120
quoted_string |
121-
(newline.absent? >> (str("}").absent? >> any)).repeat(0).as(:raw)
121+
(newline.absent? >> (str("}").absent? >> any)).repeat(1).as(:raw)
122+
end
123+
124+
rule(:empty_field) do
125+
# An identifier with no value (just newline or `}` after). The
126+
# separate rule prevents the generic_field's value rule from
127+
# consuming into the next field.
128+
(newline.present? | str("}").present?).as(:empty)
122129
end
123130

124131
# Raw text inside `{ ... }` — for description blocks. Consumes any

lib/interscript/isc/items.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,19 @@ def inspect
4848
end
4949
end
5050

51+
# Function call: upcase, downcase, etc. Used as `to` value in sub rules.
52+
class Function
53+
attr_reader :name
54+
55+
def initialize(name)
56+
@name = name
57+
end
58+
59+
def inspect
60+
"Function(#{@name})"
61+
end
62+
end
63+
5164
class AliasRef
5265
attr_reader :name
5366

lib/interscript/isc/transform.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class Transform < Parslet::Transform
5252

5353
rule(none: simple(:_)) { Items::None.new }
5454
rule(primitive: simple(:p)) { Items::Primitive.new(p.to_s) }
55+
rule(function: simple(:f)) { Items::Function.new(f.to_s) }
5556
rule(alias: simple(:n)) { Items::AliasRef.new(n.to_s) }
5657
rule(ref: subtree(:h)) { Items::Capture.new(h[:digit].to_s.to_i) }
5758
rule(capture_inner: subtree(:inner)) { Items::CaptureGroup.new(materialize_item(inner)) }

0 commit comments

Comments
 (0)