Module: Smacro
- Defined in:
- lib/smacro.rb,
lib/smacro/cli.rb,
lib/smacro/version.rb
Defined Under Namespace
Modules: CLI Classes: Collector
Constant Summary collapse
- MACROS =
{}
- VERSION =
"0.1.0"
Class Method Summary collapse
-
.const_value(node) ⇒ Object
AST literal -> Ruby value.
- .define(name, &blk) ⇒ Object
- .expand(src) ⇒ Object
Class Method Details
.const_value(node) ⇒ Object
AST literal -> Ruby value. Anything not known at build time is an error.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/smacro.rb', line 16 def self.const_value(node) case node when Prism::SymbolNode then node.unescaped.to_sym when Prism::StringNode then node.unescaped when Prism::IntegerNode then node.value when Prism::TrueNode then true when Prism::FalseNode then false when Prism::NilNode then nil when Prism::ArrayNode then node.elements.map { |e| const_value(e) } else raise ArgumentError, "macro arg is not a compile-time literal (#{node.class}) at line #{node.location.start_line}" end end |
.define(name, &blk) ⇒ Object
11 12 13 |
# File 'lib/smacro.rb', line 11 def self.define(name, &blk) MACROS[name] = blk end |
.expand(src) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/smacro.rb', line 47 def self.(src) collector = Collector.new Prism.parse(src).value.accept(collector) bytes = src.b # Prism offsets are byte offsets collector.hits.sort_by { |n| -n.location.start_offset }.each do |n| args = (n.arguments ? n.arguments.arguments : []).map { |a| const_value(a) } code = MACROS[n.name].call(*args).to_s # Collapse to one line with ";" so every line number stays identical # to the original file (free source map for error messages). oneline = code.lines.map(&:strip).reject(&:empty?).join("; ") bytes[n.location.start_offset, n.location.length] = oneline.b end bytes.force_encoding(Encoding::UTF_8) end |