Skip to content

Commit b08f4a2

Browse files
Add StringLiteral#to_utf16 (#14676)
Implements `{{ "hello".to_utf16 }}` by exposing `String#to_utf16` in the macro language. Co-authored-by: Quinton Miller <[email protected]>
1 parent 28342af commit b08f4a2

File tree

2 files changed

+20
-0
lines changed

2 files changed

+20
-0
lines changed

spec/compiler/macro/macro_methods_spec.cr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,11 @@ module Crystal
591591
assert_macro %({{"hello world".titleize}}), %("Hello World")
592592
end
593593

594+
it "executes to_utf16" do
595+
assert_macro %({{"hello".to_utf16}}), "(::Slice(::UInt16).literal(104_u16, 101_u16, 108_u16, 108_u16, 111_u16, 0_u16))[0, 5]"
596+
assert_macro %({{"TEST 😐🐙 ±∀ の".to_utf16}}), "(::Slice(::UInt16).literal(84_u16, 69_u16, 83_u16, 84_u16, 32_u16, 55357_u16, 56848_u16, 55357_u16, 56345_u16, 32_u16, 177_u16, 8704_u16, 32_u16, 12398_u16, 0_u16))[0, 14]"
597+
end
598+
594599
it "executes to_i" do
595600
assert_macro %({{"1234".to_i}}), %(1234)
596601
end

src/compiler/crystal/macros/methods.cr

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,21 @@ module Crystal
820820
else
821821
raise "StringLiteral#to_i: #{@value} is not an integer"
822822
end
823+
when "to_utf16"
824+
interpret_check_args do
825+
slice = @value.to_utf16
826+
827+
# include the trailing zero that isn't counted in the slice but was
828+
# generated by String#to_utf16 so the literal can be passed to C
829+
# functions that expect a null terminated UInt16*
830+
args = Slice(UInt16).new(slice.to_unsafe, slice.size + 1).to_a do |codepoint|
831+
NumberLiteral.new(codepoint).as(ASTNode)
832+
end
833+
literal_node = Call.new(Generic.new(Path.global("Slice"), [Path.global("UInt16")] of ASTNode), "literal", args)
834+
835+
# but keep the trailing zero hidden in the exposed slice
836+
Call.new(literal_node, "[]", [NumberLiteral.new("0", :i32), NumberLiteral.new(slice.size)] of ASTNode)
837+
end
823838
when "tr"
824839
interpret_check_args do |first, second|
825840
raise "first argument to StringLiteral#tr must be a string, not #{first.class_desc}" unless first.is_a?(StringLiteral)

0 commit comments

Comments
 (0)