Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add warning macro #13262

Merged
merged 2 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions spec/compiler/macro/macro_methods_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1694,6 +1694,18 @@ module Crystal
end
end

describe "#warning" do
it "emits a warning at a specific node" do
assert_warning <<-CRYSTAL, "Oh noes"
macro test(node)
{% node.warning "Oh noes" %}
end

test 10
CRYSTAL
end
end

it "executes instance_vars" do
assert_macro("{{x.instance_vars.map &.stringify}}", %(["bytesize", "length", "c"])) do |program|
{x: TypeNode.new(program.string)}
Expand Down Expand Up @@ -3066,6 +3078,18 @@ module Crystal
assert_macro %({{compare_versions("1.10.3", "1.2.3")}}), %(1)
end

describe "#warning" do
it "emits a top level warning" do
assert_warning <<-CRYSTAL, "Oh noes"
macro test
{% warning "Oh noes" %}
end

test
CRYSTAL
end
end

describe "#parse_type" do
it "path" do
assert_type(%[class Bar; end; {{ parse_type("Bar").is_a?(Path) ? 1 : 'a'}}]) { int32 }
Expand Down
13 changes: 11 additions & 2 deletions src/compiler/crystal/macros.cr
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ module Crystal::Macros
def raise(message) : NoReturn
end

# Emits a compile-time warning with the given *message*.
def warning(message : StringLiteral) : NilLiteral
end

# Returns `true` if the given *filename* exists, `false` otherwise.
def file_exists?(filename) : BoolLiteral
end
Expand Down Expand Up @@ -413,11 +417,16 @@ module Crystal::Macros
def !=(other : ASTNode) : BoolLiteral
end

# Gives a compile-time error with the given *message*. This will
# highlight this node in the error message.
# Gives a compile-time error with the given *message*.
# This will highlight this node in the error message.
def raise(message) : NoReturn
end

# Emits a compile-time warning with the given *message*.
# This will highlight this node in the warning message.
def warning(message : StringLiteral) : NilLiteral
end

# Returns `true` if this node's type is the given *type* or any of its
# subclasses.
#
Expand Down
20 changes: 20 additions & 0 deletions src/compiler/crystal/macros/methods.cr
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ module Crystal
interpret_system(node)
when "raise"
interpret_raise(node)
when "warning"
interpret_warning(node)
when "file_exists?"
interpret_file_exists?(node)
when "read_file"
Expand Down Expand Up @@ -255,6 +257,10 @@ module Crystal
macro_raise(node, node.args, self)
end

def interpret_warning(node)
macro_warning(node, node.args, self)
end

def interpret_file_exists?(node)
interpret_check_args_toplevel do |arg|
arg.accept self
Expand Down Expand Up @@ -382,6 +388,8 @@ module Crystal
interpret_check_args { class_name }
when "raise"
macro_raise self, args, interpreter
when "warning"
macro_warning self, args, interpreter
when "filename"
interpret_check_args do
filename = location.try &.original_filename
Expand Down Expand Up @@ -2678,6 +2686,18 @@ private def macro_raise(node, args, interpreter)
node.raise msg, exception_type: Crystal::MacroRaiseException
end

private def macro_warning(node, args, interpreter)
msg = args.map do |arg|
arg.accept interpreter
interpreter.last.to_macro_id
end
msg = msg.join " "
Comment on lines +2690 to +2694
Copy link
Member Author

@Blacksmoke16 Blacksmoke16 Apr 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While playing with the other macro error stuff I noticed that you can actually pass a variadic amount of arguments to macro raise? This keeps that behavior for consistency, but could also do a follow up to make it an error if are 0 or more than 1 arguments passed to #warning and add a deprecation to #raise.

$ crystal run --error-trace test.cr 
In test.cr:1:1

 1 | {% raise "foo", "bar", 123 %}
     ^
Error: foo bar 123


interpreter.warnings.add_warning_at(node.location, msg)

Crystal::NilLiteral.new
end

private def empty_no_return_array
Crystal::ArrayLiteral.new(of: Crystal::Path.global("NoReturn"))
end
Expand Down