Skip to content

Commit 05555e6

Browse files
jneenjneen
andauthored
Add ArrayLiteral#* and StringLiteral#* (#16154)
Co-authored-by: jneen <[email protected]>
1 parent ab68668 commit 05555e6

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

spec/compiler/macro/macro_methods_spec.cr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,10 @@ module Crystal
422422
assert_macro %({{"foo" != "bar"}}), %(true)
423423
end
424424

425+
it "executes string * number" do
426+
assert_macro %({{"odelay" * 3}}), "\"odelayodelayodelay\""
427+
end
428+
425429
it "executes split without arguments" do
426430
assert_macro %({{"1 2 3".split}}), %(["1", "2", "3"] of ::String)
427431
end
@@ -768,6 +772,10 @@ module Crystal
768772
assert_macro %({{[1, 2, 3].map { |e| e == 2 }}}), "[false, true, false]"
769773
end
770774

775+
it "executes *" do
776+
assert_macro %({{["na"] * 5}}), %(["na", "na", "na", "na", "na"])
777+
end
778+
771779
it "executes reduce with no initial value" do
772780
assert_macro %({{[1, 2, 3].reduce { |acc, val| acc * val }}}), "6"
773781
end

src/compiler/crystal/macros.cr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,10 @@ module Crystal::Macros
653653
# Similar to `String#<`
654654
def <(other : StringLiteral | MacroId) : BoolLiteral
655655
end
656+
657+
# Similar to `String#*`.
658+
def *(other : NumberLiteral) : StringLiteral
659+
end
656660
end
657661

658662
# An interpolated string like `"Hello, #{name}!"`.
@@ -802,6 +806,10 @@ module Crystal::Macros
802806
def -(other : ArrayLiteral) : ArrayLiteral
803807
end
804808

809+
# Similar to `Array#*`
810+
def *(other : NumberLiteral) : ArrayLiteral
811+
end
812+
805813
# Returns the type specified at the end of the array literal, if any.
806814
#
807815
# This refers to the part after brackets in `[] of String`.

src/compiler/crystal/macros/methods.cr

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,20 @@ module Crystal
691691
end
692692
StringLiteral.new(@value + piece)
693693
end
694+
when "*"
695+
interpret_check_args do |arg|
696+
unless arg.is_a?(Crystal::NumberLiteral)
697+
arg.raise "argument to StringLiteral#* must be a number, not #{arg.class_desc}"
698+
end
699+
700+
num = arg.to_number
701+
702+
unless num.is_a?(Int)
703+
arg.raise "argument to StringLiteral#* cannot be a float"
704+
end
705+
706+
StringLiteral.new(@value * num)
707+
end
694708
when "camelcase"
695709
interpret_check_args(named_params: ["lower"]) do
696710
lower = if named_args && (lower_arg = named_args["lower"]?)
@@ -3169,6 +3183,20 @@ private def interpret_array_or_tuple_method(object, klass, method, args, named_a
31693183
end
31703184
klass.new(object.elements - other_elements)
31713185
end
3186+
when "*"
3187+
interpret_check_args(node: object) do |arg|
3188+
unless arg.is_a?(Crystal::NumberLiteral)
3189+
arg.raise "argument to ArrayLiteral#* must be a number, not #{arg.class_desc}"
3190+
end
3191+
3192+
num = arg.to_number
3193+
3194+
unless num.is_a?(Int)
3195+
arg.raise "argument to ArrayLiteral#* cannot be a float"
3196+
end
3197+
3198+
klass.new(object.elements * num)
3199+
end
31723200
else
31733201
nil
31743202
end

0 commit comments

Comments
 (0)