class PosxmlCompiler::Parser
Constants
- LIMIT_DEFAULT
Attributes
bytecodes[RW]
limit[RW]
text[RW]
variables[RW]
xsd[RW]
Public Class Methods
new(source, xsd)
click to toggle source
# File lib/posxml_compiler/parser.rb, line 12 def initialize(source, xsd) @xsd = xsd @text = source @variables = PosxmlCompiler::Variable.new(xsd, PosxmlCompiler::Function.new) @bytecodes = parse(self.text) @limit = LIMIT_DEFAULT end
Public Instance Methods
posxml()
click to toggle source
# File lib/posxml_compiler/parser.rb, line 20 def posxml jump = PosxmlCompiler::Jump.new(self.bytecodes.dup) jump.persist! txt = jump.instructions.inject("") { |string, instruction| string << instruction[:line] } if txt.size > self.limit puts "Application size limit(#{self.limit}) exceed" end txt rescue => e raise e.class.new("#{number}:#{e.message}") end
Private Instance Methods
add_line_number(line, string)
click to toggle source
# File lib/posxml_compiler/parser.rb, line 79 def add_line_number(line, string) # necessary check to avoid add line on commands devide in two lines if string[0] == "<" "#{line+1}\x00#{string}" else string end end
instruction_check_close(str)
click to toggle source
# File lib/posxml_compiler/parser.rb, line 88 def instruction_check_close(str) if str[-1] == ">" "#{str[0..-2]}\n" else str end end
parse(txt)
click to toggle source
# File lib/posxml_compiler/parser.rb, line 96 def parse(txt) point = 0 number = 0 # Split in lines and remove nil's split_instructions(sanitize(txt)).inject([]) do |array, str| if str.include?("\x00") number, value = str.split("\x00", 2) else value = str end value = value.strip next(array) if value.empty? # => "if", {"variable" => "$(sKeyTouchScreen)", "operator" => "equalto", "value" => "KEY_CLEAR"} name, parameters = parse_line(value) # => "if", {"variable" => {:original => "$(sKeyTouchScreen)", :value => "$(1)", :type => :string}, "operator" => {:original => "equalto", :value => "equalto", :type => :string}, "value" => {:original => "KEY_CLEAR", :value => "KEY_CLEAR", :type => :string} parse_references(name, parameters) line = parse_instruction(name, parameters) size = line.size array << { :name => name, :parameters => parameters, :line => line, :size => size, :point => point, :line_number => number } point += size array end rescue => e raise e.class.new("#{number}:#{e.message}") end
parse_instruction(name, parameters)
click to toggle source
Receive:
("if", {"variable" => {:original => "$(sKeyTouchScreen)", :value => "$(1)", :type => :string}, "operator" => {:original => "equalto", :value => "equalto", :type => :string}, "value" => {:original => "KEY_CLEAR", :value => "KEY_CLEAR", :type => :string})
Return:
"I$(1)\nequalto\nKEY_CLEAR"
# File lib/posxml_compiler/parser.rb, line 131 def parse_instruction(name, parameters) self.xsd.to_bytecode(name, parameters) end
parse_line(str)
click to toggle source
Parse line and return instruction name and parameters from:
<if variable="$(sKeyTouchScreen)" operator="equalto" value="KEY_CLEAR"
to:
["if", {"variable" => "$(sKeyTouchScreen)", "operator" => "equalto", "value" => "KEY_CLEAR"}]
# File lib/posxml_compiler/parser.rb, line 155 def parse_line(str) command = (str.strip[-1] == "/") ? str.strip[0..-2] : str.strip index = command.index(" ") if index [command[1..(index - 1)], parse_parameters(command[index..-1])] else # Common to instruction without parameters [command[1..-1], {}] end end
parse_parameters(str)
click to toggle source
Parse only parameters from:
variable="$(sKeyTouchScreen)" operator="equalto" value="KEY_CLEAR"
to:
{"variable" => "$(sKeyTouchScreen)", "operator" => "equalto", "value" => "KEY_CLEAR"}
# File lib/posxml_compiler/parser.rb, line 172 def parse_parameters(str) value = "" variable = "" separator = nil bVariable = true bValue = false str.strip.chars.inject({}) do |hash, ch| if ch == separator separator = nil bVariable = true bValue = false hash[variable.strip] = replace_xml_constants(value) variable = "" value = "" elsif ! separator && (ch == "'" || ch == "\"") separator = ch bVariable = false bValue = true elsif bVariable && ch == "=" bVariable = false elsif bValue value << ch elsif bVariable variable << ch end hash end end
parse_references(name, parameters)
click to toggle source
Receive:
("if", {"variable" => "$(sKeyTouchScreen)", "operator" => "equalto", "value" => "KEY_CLEAR"}) ("function", {"name" => "dosomething"})
Return (changing parameter key value):
"if", {"variable" => {:original => "$(sKeyTouchScreen)", :value => "$(1)", :type => :string}, "operator" => {:original => "equalto", :value => "equalto", :type => :string}, "value" => {:original => "KEY_CLEAR", :value => "KEY_CLEAR", :type => :string}) "function", {"name" => {:original => "dosomething", :value => "1", :type => :string}})
# File lib/posxml_compiler/parser.rb, line 142 def parse_references(name, parameters) raise InstructionNotFoundError.new("Instruction #{name.inspect} not found") unless xsd.find(name) parameters.each do |param_name, value| parameters[param_name] = self.variables.get(name, param_name, value) end end
replace_xml_constants(str)
click to toggle source
# File lib/posxml_compiler/parser.rb, line 205 def replace_xml_constants(str) str.gsub(""", "\"").gsub("<", "<").gsub(">", ">").gsub("&", "&") end
sanitize(txt)
click to toggle source
Clean text from:
<if variable="$(sKeyTouchScreen)" operator="equalto" value="KEY_CLEAR"> <else /> </if>
to:
<if variable="$(sKeyTouchScreen)" operator="equalto" value="KEY_CLEAR" <else </if
# File lib/posxml_compiler/parser.rb, line 44 def sanitize(txt) string = txt.gsub("\r\n", "\n").gsub("\n\r", "\n").gsub("><", ">\n<") characters = ['ç', 'Ç', 'ã', 'Ã', 'â', 'Â', 'á', 'Á', 'à', 'À', 'é', 'É', 'è', 'È', 'ê', 'Ê', 'í', 'Í', 'ì', 'Ì', 'ó', 'Ò', 'ò', 'Ò', 'ô', 'Ô', 'ú', 'Ú', 'ù', 'Ù'] normalized = 'cCaAaAaAaAeEeEeEiIiIoOoOoOuUuU' characters.each_with_index do |char, index| str = normalized[index] string = string.gsub(char, str) if str end string end
split_instructions(txt)
click to toggle source
Check if an instruction end in the next line, then split by n
# File lib/posxml_compiler/parser.rb, line 56 def split_instructions(txt) txt_new = "" ignore = false txt.split("\n").compact.each_with_index do |str, number| line = str.strip if line[0..3] == "<!--" || ignore # Check comentaries ignore = true ignore = false if line.include?("-->") elsif line.include?("<!--") # Check end of comentaries line_without_comment = line.split("<!--")[0].strip txt_new << add_line_number(number, instruction_check_close(line_without_comment)) elsif line.include?("<") || line.include?(">") txt_new << add_line_number(number, instruction_check_close(line)) else !ignore # For middle of instruction between lines # Avoid this <pinpad.getpindukptmessage="$(sDisplayMsg)"type="3"pan="$(sPAN)"maxlen="12"variablereturnpin="$(sPIN)"variablereturnksn="$(sKSN)"variablereturn="$(iRet)" txt_new << " " if txt_new[-1] != " " txt_new << add_line_number(number, instruction_check_close(line)) end end #p txt_new txt_new.split("\n") end