[WIP] refactoring in classes, parsing
This commit is contained in:
parent
edccbf1bda
commit
a4cfed2cc4
3 changed files with 168 additions and 133 deletions
112
lib/parser.rb
112
lib/parser.rb
|
@ -1,62 +1,68 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
class String
|
module Rpn
|
||||||
def numeric?
|
class Parser
|
||||||
Float(self) != nil rescue false
|
def initialize; end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_input( input )
|
def numeric?( elt )
|
||||||
splitted_input = input.split(" ")
|
!Float(elt).nil?
|
||||||
parsed_tree = []
|
rescue ArgumentError
|
||||||
|
false
|
||||||
regrouping = false
|
|
||||||
splitted_input.each do |elt|
|
|
||||||
next if elt.length == 1 && elt[0] == "»"
|
|
||||||
|
|
||||||
parsed_entry = { "value" => elt }
|
|
||||||
|
|
||||||
if regrouping
|
|
||||||
parsed_entry = parsed_tree.pop
|
|
||||||
|
|
||||||
parsed_entry["value"] = "#{parsed_entry["value"]} #{elt}".strip
|
|
||||||
else
|
|
||||||
parsed_entry["type"] = case elt[0]
|
|
||||||
when "«"
|
|
||||||
"PROGRAM"
|
|
||||||
when "\""
|
|
||||||
"STRING"
|
|
||||||
when "'"
|
|
||||||
"NAME"
|
|
||||||
else
|
|
||||||
if elt.numeric?
|
|
||||||
"NUMBER"
|
|
||||||
else
|
|
||||||
"WORD" # TODO: if word isn"t known then it"s a NAME
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
parsed_entry["value"] = elt[1..] if %W[PROGRAM STRING NAME].include?( parsed_entry["type"] )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
regrouping = ( (parsed_entry["type"] == "NAME" && elt[-1] != "'") ||
|
def parse_input( input )
|
||||||
(parsed_entry["type"] == "STRING" && elt[-1] != "\"") ||
|
splitted_input = input.split(' ')
|
||||||
(parsed_entry["type"] == "PROGRAM" && elt[-1] != "»") )
|
parsed_tree = []
|
||||||
|
|
||||||
parsed_entry["value"] = if ( (parsed_entry["type"] == "NAME" && elt[-1] == "'") ||
|
regrouping = false
|
||||||
(parsed_entry["type"] == "STRING" && elt[-1] == "\"") ||
|
splitted_input.each do |elt|
|
||||||
(parsed_entry["type"] == "PROGRAM" && elt[-1] == "»") )
|
parsed_entry = { value: elt }
|
||||||
(parsed_entry["value"][..-2]).strip
|
|
||||||
elsif parsed_entry["type"] == "NUMBER"
|
|
||||||
parsed_entry["value"].to_f
|
|
||||||
elsif parsed_entry["type"] == "WORD"
|
|
||||||
parsed_entry["value"]
|
|
||||||
else
|
|
||||||
parsed_entry["value"]
|
|
||||||
end
|
|
||||||
|
|
||||||
parsed_tree << parsed_entry
|
if regrouping
|
||||||
|
parsed_entry = parsed_tree.pop
|
||||||
|
|
||||||
|
parsed_entry[:value] = "#{parsed_entry[:value]} #{elt}".strip
|
||||||
|
else
|
||||||
|
parsed_entry[:type] = case elt[0]
|
||||||
|
when '«'
|
||||||
|
:program
|
||||||
|
when '"'
|
||||||
|
:string
|
||||||
|
when "'"
|
||||||
|
:name # TODO: check for forbidden space
|
||||||
|
else
|
||||||
|
if numeric?( elt )
|
||||||
|
:numeric
|
||||||
|
else
|
||||||
|
:word
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if parsed_entry[:type] == :word
|
||||||
|
if false
|
||||||
|
# TODO: run word if known
|
||||||
|
else
|
||||||
|
parsed_entry[:type] = :name
|
||||||
|
parsed_entry[:value] = "'#{parsed_entry[:value]}'" if parsed_entry[:value][0] != "'"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# parsed_entry[:value] = elt[1..] if [:program, :string, :name].include?( parsed_entry[:type] )
|
||||||
|
end
|
||||||
|
|
||||||
|
regrouping = ( (parsed_entry[:type] == :string && elt.size == 1 && elt[-1] != '"') ||
|
||||||
|
(parsed_entry[:type] == :program && elt[-1] != '»') )
|
||||||
|
|
||||||
|
if parsed_entry[:type] == :numeric
|
||||||
|
i = parsed_entry[:value].to_i
|
||||||
|
f = parsed_entry[:value].to_f
|
||||||
|
|
||||||
|
parsed_entry[:value] = i == f ? i : f
|
||||||
|
end
|
||||||
|
|
||||||
|
parsed_tree << parsed_entry
|
||||||
|
end
|
||||||
|
|
||||||
|
parsed_tree
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
parsed_tree
|
|
||||||
end
|
end
|
||||||
|
|
100
repl.rb
100
repl.rb
|
@ -5,49 +5,65 @@ require "readline"
|
||||||
|
|
||||||
require "./lib/parser.rb"
|
require "./lib/parser.rb"
|
||||||
|
|
||||||
def run_REPL( stack )
|
module Rpn
|
||||||
Readline.completion_proc = proc do |s|
|
class Repl
|
||||||
directory_list = Dir.glob("#{s}*")
|
def initialize
|
||||||
if directory_list.positive?
|
@parser = Parser.new
|
||||||
directory_list
|
@stack = []
|
||||||
else
|
end
|
||||||
Readline::HISTORY.grep(/^#{Regexp.escape(s)}/)
|
|
||||||
|
def run
|
||||||
|
Readline.completion_proc = proc do |s|
|
||||||
|
directory_list = Dir.glob("#{s}*")
|
||||||
|
if directory_list.positive?
|
||||||
|
directory_list
|
||||||
|
else
|
||||||
|
Readline::HISTORY.grep(/^#{Regexp.escape(s)}/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Readline.completion_append_character = " "
|
||||||
|
|
||||||
|
loop do
|
||||||
|
input = Readline.readline( " ", true )
|
||||||
|
break if input.nil? || input == "exit"
|
||||||
|
|
||||||
|
# Remove blank lines from history
|
||||||
|
Readline::HISTORY.pop if input.empty?
|
||||||
|
|
||||||
|
process_input( input )
|
||||||
|
|
||||||
|
print_stack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_input( input )
|
||||||
|
@parser.parse_input( input ).each do |elt|
|
||||||
|
@stack << elt
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def format_element( elt )
|
||||||
|
pp elt
|
||||||
|
# case elt[:type]
|
||||||
|
# when :program
|
||||||
|
# "« #{elt[:value]} »"
|
||||||
|
# when :string
|
||||||
|
# "\"#{elt[:value]}\""
|
||||||
|
# when :name
|
||||||
|
# "'#{elt[:value]}'"
|
||||||
|
# else
|
||||||
|
elt[:value]
|
||||||
|
# end
|
||||||
|
end
|
||||||
|
|
||||||
|
def print_stack
|
||||||
|
stack_size = @stack.size
|
||||||
|
|
||||||
|
@stack.each_with_index do |elt, i|
|
||||||
|
puts "#{stack_size - i}: #{format_element( elt )}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Readline.completion_append_character = " "
|
|
||||||
|
|
||||||
loop do
|
|
||||||
input = Readline.readline( " ", true )
|
|
||||||
break if input == "exit"
|
|
||||||
|
|
||||||
# Remove blank lines from history
|
|
||||||
Readline::HISTORY.pop if input.empty?
|
|
||||||
|
|
||||||
stack = process_input( stack, input )
|
|
||||||
|
|
||||||
stack = display_stack( stack )
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_input( stack, input )
|
Rpn::Repl.new.run
|
||||||
parse_input( input ).each do |elt|
|
|
||||||
stack << elt
|
|
||||||
end
|
|
||||||
|
|
||||||
stack
|
|
||||||
end
|
|
||||||
|
|
||||||
def display_stack( stack )
|
|
||||||
stack_size = stack.size
|
|
||||||
stack.each_with_index { |elt, i| puts "#{stack_size - i}: #{elt["value"]}"}
|
|
||||||
|
|
||||||
stack
|
|
||||||
end
|
|
||||||
|
|
||||||
def stack_init
|
|
||||||
stack = []
|
|
||||||
|
|
||||||
stack
|
|
||||||
end
|
|
||||||
|
|
||||||
run_REPL( stack_init )
|
|
||||||
|
|
|
@ -1,54 +1,67 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "test/unit"
|
require 'test/unit'
|
||||||
|
|
||||||
require_relative "../lib/parser"
|
require_relative '../lib/parser'
|
||||||
|
|
||||||
class TestParser < Test::Unit::TestCase
|
class TestParser < Test::Unit::TestCase
|
||||||
def test_parse_input_number
|
def test_number
|
||||||
result = parse_input( "1" )
|
result = Rpn::Parser.new.parse_input( '1' )
|
||||||
assert_equal [ { "value" => 1, "type" => "NUMBER" } ], result
|
assert_equal [{ value: 1, type: :numeric }], result
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_parse_input_word
|
def test_word
|
||||||
result = parse_input( "dup" )
|
result = Rpn::Parser.new.parse_input( 'dup' )
|
||||||
assert_equal [ { "value" => "dup", "type" => "WORD" } ], result
|
assert_equal [{ value: 'dup', type: :word }], result
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_parse_input_string
|
def test_string
|
||||||
result = parse_input( "\"test\"" )
|
result = Rpn::Parser.new.parse_input( '"test"' )
|
||||||
assert_equal [ { "value" => "test", "type" => "STRING" } ], result
|
assert_equal [{ value: '"test"', type: :string }], result
|
||||||
end
|
|
||||||
|
|
||||||
def test_parse_input_name
|
result = Rpn::Parser.new.parse_input( '" test"' )
|
||||||
result = parse_input( "'test'" )
|
assert_equal [{ value: '" test"', type: :string }], result
|
||||||
assert_equal [ { "value" => "test", "type" => "NAME" } ], result
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_parse_input_program
|
result = Rpn::Parser.new.parse_input( '"test "' )
|
||||||
result = parse_input( "« test »" )
|
assert_equal [{ value: '"test "', type: :string }], result
|
||||||
assert_equal [ { "value" => "test", "type" => "PROGRAM" } ], result
|
|
||||||
|
|
||||||
result = parse_input( "«test »" )
|
result = Rpn::Parser.new.parse_input( '" test "' )
|
||||||
assert_equal [ { "value" => "test", "type" => "PROGRAM" } ], result
|
assert_equal [{ value: '" test "', type: :string }], result
|
||||||
|
end
|
||||||
|
|
||||||
result = parse_input( "« test»" )
|
def test_name
|
||||||
assert_equal [ { "value" => "test", "type" => "PROGRAM" } ], result
|
result = Rpn::Parser.new.parse_input( "'test'" )
|
||||||
|
assert_equal [{ value: "'test'", type: :name }], result
|
||||||
|
end
|
||||||
|
|
||||||
result = parse_input( "« test test »" )
|
def test_program
|
||||||
assert_equal [ { "value" => "test test", "type" => "PROGRAM" } ], result
|
result = Rpn::Parser.new.parse_input( '« test »' )
|
||||||
|
assert_equal [{ value: '« test »', type: :program }], result
|
||||||
|
|
||||||
result = parse_input( "« test \"test\" test »" )
|
result = Rpn::Parser.new.parse_input( '«test »' )
|
||||||
assert_equal [ { "value" => "test \"test\" test", "type" => "PROGRAM" } ], result
|
assert_equal [{ value: '«test »', type: :program }], result
|
||||||
end
|
|
||||||
|
|
||||||
def test_parse_input_number_number
|
result = Rpn::Parser.new.parse_input( '« test»' )
|
||||||
result = parse_input( "2 3" )
|
assert_equal [{ value: '« test»', type: :program }], result
|
||||||
assert_equal [ { "value" => 2, "type" => "NUMBER" }, { "value" => 3, "type" => "NUMBER" } ], result
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_parse_input_number_string
|
result = Rpn::Parser.new.parse_input( '« test test »' )
|
||||||
result = parse_input( "4 \"test\"" )
|
assert_equal [{ value: '« test test »', type: :program }], result
|
||||||
assert_equal [ { "value" => 4, "type" => "NUMBER" }, { "value" => "test", "type" => "STRING" } ], result
|
|
||||||
end
|
result = Rpn::Parser.new.parse_input( '« test « test » »' )
|
||||||
|
assert_equal [{ value: '« test « test » »', type: :program }], result
|
||||||
|
|
||||||
|
result = Rpn::Parser.new.parse_input( '« test "test" test »' )
|
||||||
|
assert_equal [{ value: '« test "test" test »', type: :program }], result
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_number_number
|
||||||
|
result = Rpn::Parser.new.parse_input( '2 3' )
|
||||||
|
assert_equal [{ value: 2, type: :numeric }, { value: 3, type: :numeric }], result
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_number_string
|
||||||
|
result = Rpn::Parser.new.parse_input( '4 "test"' )
|
||||||
|
assert_equal [{ value: 4, type: :numeric }, { value: '"test"', type: :string }], result
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue