Class: Ppr::Macro
- Inherits:
-
Object
- Object
- Ppr::Macro
- Defined in:
- lib/ppr/ppr_core.rb
Overview
Describes a macro of the ruby preprocessor.
Direct Known Subclasses
Constant Summary collapse
- E_NUMBER =
Regular expression for identifying a line number inside an exception message.
/:[1-9][0-9]*:/
- E_TYPE =
Type of exception which correspond to a macro execution.
/\(eval\)\s*/
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
The name of the macro.
Class Method Summary collapse
-
.e_message(name, message, i_number, number = nil) ⇒ Object
Update an exception
message
to refer macroname
invoked at line numberi_number
and adds a possible macro linenumber
.
Instance Method Summary collapse
-
#add(line) ⇒ Object
(also: #<<)
Adds a
line
to the macro. -
#apply(i_number, *arguments) ⇒ Object
Applies the macro invoked at line number
i_number
witharguments
. -
#e_message(message, i_number, number = nil) ⇒ Object
Update an exception
message
to refer the macro invoked at line numberi_number
and adds a possible macro linenumber
. -
#e_number(message) ⇒ Object
Tells if an exception
message
includes a line number. -
#e_shift_number(message, sh) ⇒ Object
Shifts the line number inside an exception
message
bysh
. -
#e_type?(message, type) ⇒ Boolean
Tells if an exception message is of a given
type
. -
#empty? ⇒ Boolean
Checks if the macro is empty (no code line yet).
-
#final? ⇒ Boolean
Tells if the maco expansion result is final (i.e., it is not preprocessed again) or not.
-
#generate(i_number, *values) ⇒ Object
Generates the code of the macro invoked at line number
i_number
usingvalues
for the variables. -
#initialize(name, num, ppr, *variables, expand: ":<", final: true) ⇒ Macro
constructor
Creates a new macro named
name
, starting at line numbernum
, generated from preprocessorppr
and with possiblevariables
. -
#to_quoted(string) ⇒ Object
Converts a
string
to a quoted string.
Constructor Details
#initialize(name, num, ppr, *variables, expand: ":<", final: true) ⇒ Macro
Creates a new macro named name
, starting at line number num
, generated from preprocessor ppr
and with possible variables
.
Other parameters:
expand
-
used to redefine the expand operator
final
-
indicates that the result of the macro expansion
shall not be preprocessed again.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/ppr/ppr_core.rb', line 48 def initialize(name, num, ppr, *variables, expand: ":<", final: true) # Check and set the name. @name = name.to_str # Check and set the line number of the begining of the macro. @start_num = num.to_i # Check and set the preprocessor unless ppr.is_a?(Preprocessor) then raise "Invalid class for a preprocessor: #{ppr.class}" end @ppr = ppr # The start of the macro code is unknown at first (will be known # when generating the code). @code_num = nil # Check and set the variables. # print "variables=#{variables}\n" @variables = variables.map do |variable| variable = variable.to_str unless variable.match(/^[a-z_][a-z0-9_]*$/) raise "Invalid string for a macro variable: #{variable}" end variable end # Initialize the content of the macro as an array of lines. @lines = [] # Set the default expansion operator string. @expand = # Set the macro code expansion result status: when final, no # other macro is applied on it, otherwise, it is preprocessed again. @final = final ? true : false end |
Instance Attribute Details
#name ⇒ Object (readonly)
The name of the macro.
39 40 41 |
# File 'lib/ppr/ppr_core.rb', line 39 def name @name end |
Class Method Details
.e_message(name, message, i_number, number = nil) ⇒ Object
Update an exception message
to refer macro name
invoked at line number i_number
and adds a possible macro line number
.
191 192 193 194 195 196 |
# File 'lib/ppr/ppr_core.rb', line 191 def Macro.(name, , i_number, number = nil) result = "Ppr error (#{name}:#{i_number})" result << ":#{number}: " if number result << return result end |
Instance Method Details
#add(line) ⇒ Object Also known as: <<
Adds a line
to the macro.
97 98 99 100 101 |
# File 'lib/ppr/ppr_core.rb', line 97 def add(line) # Process the line. # Remove the ending newline if any. @lines << line.chomp end |
#apply(i_number, *arguments) ⇒ Object
Applies the macro invoked at line number i_number
with arguments
.
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/ppr/ppr_core.rb', line 205 def apply(i_number,*arguments) # Generate the code of the macro. code = self.generate(i_number,*arguments) # Evaluate the code in the safe context of ppr. # print "code=#{code}\n" begin return @ppr.run do |__stream__| __ppr__ = @ppr begin __stream__ << eval(code) # rescue Exception => e # raise e end end rescue Exception => e if e.is_a?(SaferGenerator::SaferException) then # An exception happened while executing the macro code, # get the cause (which contains the exception which has # been raised while executing the macro). cause = e.cause = cause. # Update the line number in the message if any. if e_number() then # There is a line number, update it in the context of # the processed file. = e_shift_number(, @start_num - @code_num) # Raise the exception again with the updated message. raise cause, (.gsub(E_TYPE,""),i_number) else # There was not any line number in the message, look # for it into the backtrack message. number = cause.backtrace.find do |trace| found = e_number(trace) if found and e_type?(trace,E_TYPE) break found else next nil end end if number then # Update the line number in the context of the processed # file. number += @start_num - @code_num # The number found, raise the exception again with # the message updated with the number. raise cause, (.gsub(E_TYPE,""),i_number,number) else # No number, use the macro start instead for # raising the exception. raise cause, (,i_number,@start_num) end end else # An exception happened due to an internal error of the # SaferGenerator class, raise it as is. raise e end end end |
#e_message(message, i_number, number = nil) ⇒ Object
Update an exception message
to refer the macro invoked at line number i_number
and adds a possible macro line number
.
200 201 202 |
# File 'lib/ppr/ppr_core.rb', line 200 def (, i_number, number = nil) Macro.(@name,,i_number,number) end |
#e_number(message) ⇒ Object
Tells if an exception message
includes a line number.
155 156 157 158 159 160 161 162 163 164 |
# File 'lib/ppr/ppr_core.rb', line 155 def e_number() found = E_NUMBER.match() if found then # The number is found, return it. return found.to_s[1..-2].to_i else # The number is not found. return nil end end |
#e_shift_number(message, sh) ⇒ Object
Shifts the line number inside an exception message
by sh
.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/ppr/ppr_core.rb', line 172 def e_shift_number(,sh) # Edit the message to fix the line number and raise then. return .gsub(E_NUMBER) { |str| # Remove the ':' str = str[1..-2] # Get and check the line number. num = str.to_i # print "num=#{num}\n" if num.to_s == str then # This is really a line number. ":#{num+sh}:" else ":#{str}:" end } end |
#e_type?(message, type) ⇒ Boolean
Tells if an exception message is of a given type
.
167 168 169 |
# File 'lib/ppr/ppr_core.rb', line 167 def e_type?(,type) return =~ Regexp.new(type) end |
#empty? ⇒ Boolean
Checks if the macro is empty (no code line yet).
105 106 107 |
# File 'lib/ppr/ppr_core.rb', line 105 def empty? return @lines.empty? end |
#final? ⇒ Boolean
Tells if the maco expansion result is final (i.e., it is not preprocessed again) or not.
92 93 94 |
# File 'lib/ppr/ppr_core.rb', line 92 def final? return @final end |
#generate(i_number, *values) ⇒ Object
Generates the code of the macro invoked at line number i_number
using values
for the variables.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/ppr/ppr_core.rb', line 111 def generate(i_number,*values) # First generate a variable for the resulting text. result = "result_" count = 0 # Ensure the variable is not used in the code. count += 1 while (@lines.find {|line| line.include?(name + count.to_s)}) result = result + count.to_s # The process the lines and join them into the resulting string code. buffer = StringIO.new("") # Adds the prologue initializing the result text string and setting # the values. buffer << result + " = StringIO.new(\"\")\n" # Update the macro code start line. @code_num = 1 unless @variables.size == values.size raise Macro.(@name, "invalid number of argument: got #{values.size}, but expecting #{@variables.size}.",i_number,@start_num) end @variables.each.with_index do |var,i| buffer << "#{var} = #{to_quoted(values[i])}\n" @code_num += 1 end # Add each line of the macros. @lines.each do |line| # If any, replace the expand command by a concatenation to the # resulting string buffer. line = line.sub(@expand,"#{result} << ") # Add the line buffer << line << "\n" end # Adds the epilogue buffer << result << ".string" return buffer.string end |
#to_quoted(string) ⇒ Object
Converts a string
to a quoted string.
83 84 85 86 87 88 |
# File 'lib/ppr/ppr_core.rb', line 83 def to_quoted(string) return "\"" + string.gsub(/[\"]|#\{/, "\"" => "\\\"", "\#{" => "\\\#{") + "\"" #}}} This comment is just to avoid confusing the text editor. end |