From 54c8821219fc2c5d56305ee2d11638be2bc1bcf7 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 10 Jun 2016 10:39:31 -0300 Subject: [PATCH] Add `read_file` macro method --- spec/compiler/macro/macro_methods_spec.cr | 14 ++++++++++++++ src/compiler/crystal/macros.cr | 11 +++++++++++ src/compiler/crystal/macros/methods.cr | 16 ++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/spec/compiler/macro/macro_methods_spec.cr b/spec/compiler/macro/macro_methods_spec.cr index 9f346ba3d50f..8b78f71bb0df 100644 --- a/spec/compiler/macro/macro_methods_spec.cr +++ b/spec/compiler/macro/macro_methods_spec.cr @@ -1039,4 +1039,18 @@ describe "macro methods" do assert_macro "", %({{flag?(:foo)}}), [] of ASTNode, %(false) end end + + describe "read_file" do + it "reads file (exists)" do + run(%q< + {{read_file("#{__DIR__}/../data/build")}} + >, filename = __FILE__).to_string.should eq(File.read("#{__DIR__}/../data/build")) + end + + it "reads file (doesn't exists)" do + run(%q< + {{read_file("#{__DIR__}/../data/build_foo")}} ? 10 : 20 + >, filename = __FILE__).to_i.should eq(20) + end + end end diff --git a/src/compiler/crystal/macros.cr b/src/compiler/crystal/macros.cr index 72d0de639d0b..1a9f6468c19f 100644 --- a/src/compiler/crystal/macros.cr +++ b/src/compiler/crystal/macros.cr @@ -39,6 +39,17 @@ module Crystal::Macros def raise(message) : NoReturn end + # Reads a file: if it exists, returns a StringLiteral with its contents; + # otherwise `nil` is returned. + # + # To read a file relative to where the macro is defined, use: + # + # ``` + # read_file("#{__DIR__}/some_file.txt") + # ``` + def read_file(filename) : StringLiteral | NilLiteral + end + # Compiles and execute a Crystal program and returns its output # as a `MacroId`. # diff --git a/src/compiler/crystal/macros/methods.cr b/src/compiler/crystal/macros/methods.cr index 900521973dfa..fb227887dbfc 100644 --- a/src/compiler/crystal/macros/methods.cr +++ b/src/compiler/crystal/macros/methods.cr @@ -19,6 +19,8 @@ module Crystal interpret_system(node) when "raise" interpret_raise(node) + when "read_file" + interpret_read_file(node) when "run" interpret_run(node) else @@ -94,6 +96,20 @@ module Crystal @last = Nop.new end + def interpret_read_file(node) + if node.args.size == 1 + node.args[0].accept self + filename = @last.to_macro_id + if File.exists?(filename) + @last = StringLiteral.new(File.read(filename)) + else + @last = NilLiteral.new + end + else + node.wrong_number_of_arguments "macro call 'read_file'", node.args.size, 1 + end + end + def interpret_system(node) cmd = node.args.map do |arg| arg.accept self