[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
|
||||
|
||||
class String
|
||||
def numeric?
|
||||
Float(self) != nil rescue false
|
||||
end
|
||||
end
|
||||
module Rpn
|
||||
class Parser
|
||||
def initialize; end
|
||||
|
||||
def parse_input( input )
|
||||
splitted_input = input.split(" ")
|
||||
parsed_tree = []
|
||||
|
||||
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"] )
|
||||
def numeric?( elt )
|
||||
!Float(elt).nil?
|
||||
rescue ArgumentError
|
||||
false
|
||||
end
|
||||
|
||||
regrouping = ( (parsed_entry["type"] == "NAME" && elt[-1] != "'") ||
|
||||
(parsed_entry["type"] == "STRING" && elt[-1] != "\"") ||
|
||||
(parsed_entry["type"] == "PROGRAM" && elt[-1] != "»") )
|
||||
def parse_input( input )
|
||||
splitted_input = input.split(' ')
|
||||
parsed_tree = []
|
||||
|
||||
parsed_entry["value"] = if ( (parsed_entry["type"] == "NAME" && elt[-1] == "'") ||
|
||||
(parsed_entry["type"] == "STRING" && elt[-1] == "\"") ||
|
||||
(parsed_entry["type"] == "PROGRAM" && elt[-1] == "»") )
|
||||
(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
|
||||
regrouping = false
|
||||
splitted_input.each do |elt|
|
||||
parsed_entry = { value: elt }
|
||||
|
||||
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
|
||||
|
||||
parsed_tree
|
||||
end
|
||||
|
|
100
repl.rb
100
repl.rb
|
@ -5,49 +5,65 @@ require "readline"
|
|||
|
||||
require "./lib/parser.rb"
|
||||
|
||||
def run_REPL( stack )
|
||||
Readline.completion_proc = proc do |s|
|
||||
directory_list = Dir.glob("#{s}*")
|
||||
if directory_list.positive?
|
||||
directory_list
|
||||
else
|
||||
Readline::HISTORY.grep(/^#{Regexp.escape(s)}/)
|
||||
module Rpn
|
||||
class Repl
|
||||
def initialize
|
||||
@parser = Parser.new
|
||||
@stack = []
|
||||
end
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
def process_input( stack, input )
|
||||
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 )
|
||||
Rpn::Repl.new.run
|
||||
|
|
|
@ -1,54 +1,67 @@
|
|||
# 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
|
||||
def test_parse_input_number
|
||||
result = parse_input( "1" )
|
||||
assert_equal [ { "value" => 1, "type" => "NUMBER" } ], result
|
||||
end
|
||||
def test_number
|
||||
result = Rpn::Parser.new.parse_input( '1' )
|
||||
assert_equal [{ value: 1, type: :numeric }], result
|
||||
end
|
||||
|
||||
def test_parse_input_word
|
||||
result = parse_input( "dup" )
|
||||
assert_equal [ { "value" => "dup", "type" => "WORD" } ], result
|
||||
end
|
||||
def test_word
|
||||
result = Rpn::Parser.new.parse_input( 'dup' )
|
||||
assert_equal [{ value: 'dup', type: :word }], result
|
||||
end
|
||||
|
||||
def test_parse_input_string
|
||||
result = parse_input( "\"test\"" )
|
||||
assert_equal [ { "value" => "test", "type" => "STRING" } ], result
|
||||
end
|
||||
def test_string
|
||||
result = Rpn::Parser.new.parse_input( '"test"' )
|
||||
assert_equal [{ value: '"test"', type: :string }], result
|
||||
|
||||
def test_parse_input_name
|
||||
result = parse_input( "'test'" )
|
||||
assert_equal [ { "value" => "test", "type" => "NAME" } ], result
|
||||
end
|
||||
result = Rpn::Parser.new.parse_input( '" test"' )
|
||||
assert_equal [{ value: '" test"', type: :string }], result
|
||||
|
||||
def test_parse_input_program
|
||||
result = parse_input( "« test »" )
|
||||
assert_equal [ { "value" => "test", "type" => "PROGRAM" } ], result
|
||||
result = Rpn::Parser.new.parse_input( '"test "' )
|
||||
assert_equal [{ value: '"test "', type: :string }], result
|
||||
|
||||
result = parse_input( "«test »" )
|
||||
assert_equal [ { "value" => "test", "type" => "PROGRAM" } ], result
|
||||
result = Rpn::Parser.new.parse_input( '" test "' )
|
||||
assert_equal [{ value: '" test "', type: :string }], result
|
||||
end
|
||||
|
||||
result = parse_input( "« test»" )
|
||||
assert_equal [ { "value" => "test", "type" => "PROGRAM" } ], result
|
||||
def test_name
|
||||
result = Rpn::Parser.new.parse_input( "'test'" )
|
||||
assert_equal [{ value: "'test'", type: :name }], result
|
||||
end
|
||||
|
||||
result = parse_input( "« test test »" )
|
||||
assert_equal [ { "value" => "test test", "type" => "PROGRAM" } ], result
|
||||
def test_program
|
||||
result = Rpn::Parser.new.parse_input( '« test »' )
|
||||
assert_equal [{ value: '« test »', type: :program }], result
|
||||
|
||||
result = parse_input( "« test \"test\" test »" )
|
||||
assert_equal [ { "value" => "test \"test\" test", "type" => "PROGRAM" } ], result
|
||||
end
|
||||
result = Rpn::Parser.new.parse_input( '«test »' )
|
||||
assert_equal [{ value: '«test »', type: :program }], result
|
||||
|
||||
def test_parse_input_number_number
|
||||
result = parse_input( "2 3" )
|
||||
assert_equal [ { "value" => 2, "type" => "NUMBER" }, { "value" => 3, "type" => "NUMBER" } ], result
|
||||
end
|
||||
result = Rpn::Parser.new.parse_input( '« test»' )
|
||||
assert_equal [{ value: '« test»', type: :program }], result
|
||||
|
||||
def test_parse_input_number_string
|
||||
result = parse_input( "4 \"test\"" )
|
||||
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 » »' )
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue