[WIP] refactoring in classes, parsing

This commit is contained in:
Gwenhael Le Moine 2021-11-09 16:50:01 +01:00
parent edccbf1bda
commit a4cfed2cc4
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
3 changed files with 168 additions and 133 deletions

View file

@ -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?
rescue ArgumentError
false
end
def parse_input( input )
splitted_input = input.split(' ')
parsed_tree = [] parsed_tree = []
regrouping = false regrouping = false
splitted_input.each do |elt| splitted_input.each do |elt|
next if elt.length == 1 && elt[0] == "»" parsed_entry = { value: elt }
parsed_entry = { "value" => elt }
if regrouping if regrouping
parsed_entry = parsed_tree.pop parsed_entry = parsed_tree.pop
parsed_entry["value"] = "#{parsed_entry["value"]} #{elt}".strip parsed_entry[:value] = "#{parsed_entry[:value]} #{elt}".strip
else else
parsed_entry["type"] = case elt[0] parsed_entry[:type] = case elt[0]
when "«" when '«'
"PROGRAM" :program
when "\"" when '"'
"STRING" :string
when "'" when "'"
"NAME" :name # TODO: check for forbidden space
else else
if elt.numeric? if numeric?( elt )
"NUMBER" :numeric
else else
"WORD" # TODO: if word isn"t known then it"s a NAME :word
end end
end end
parsed_entry["value"] = elt[1..] if %W[PROGRAM STRING NAME].include?( parsed_entry["type"] ) 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 end
regrouping = ( (parsed_entry["type"] == "NAME" && elt[-1] != "'") || regrouping = ( (parsed_entry[:type] == :string && elt.size == 1 && elt[-1] != '"') ||
(parsed_entry["type"] == "STRING" && elt[-1] != "\"") || (parsed_entry[:type] == :program && elt[-1] != '»') )
(parsed_entry["type"] == "PROGRAM" && elt[-1] != "»") )
parsed_entry["value"] = if ( (parsed_entry["type"] == "NAME" && elt[-1] == "'") || if parsed_entry[:type] == :numeric
(parsed_entry["type"] == "STRING" && elt[-1] == "\"") || i = parsed_entry[:value].to_i
(parsed_entry["type"] == "PROGRAM" && elt[-1] == "»") ) f = parsed_entry[:value].to_f
(parsed_entry["value"][..-2]).strip
elsif parsed_entry["type"] == "NUMBER" parsed_entry[:value] = i == f ? i : f
parsed_entry["value"].to_f
elsif parsed_entry["type"] == "WORD"
parsed_entry["value"]
else
parsed_entry["value"]
end end
parsed_tree << parsed_entry parsed_tree << parsed_entry
end end
parsed_tree parsed_tree
end
end
end end

68
repl.rb
View file

@ -5,7 +5,14 @@ require "readline"
require "./lib/parser.rb" require "./lib/parser.rb"
def run_REPL( stack ) module Rpn
class Repl
def initialize
@parser = Parser.new
@stack = []
end
def run
Readline.completion_proc = proc do |s| Readline.completion_proc = proc do |s|
directory_list = Dir.glob("#{s}*") directory_list = Dir.glob("#{s}*")
if directory_list.positive? if directory_list.positive?
@ -18,36 +25,45 @@ def run_REPL( stack )
loop do loop do
input = Readline.readline( "", true ) input = Readline.readline( "", true )
break if input == "exit" break if input.nil? || input == "exit"
# Remove blank lines from history # Remove blank lines from history
Readline::HISTORY.pop if input.empty? Readline::HISTORY.pop if input.empty?
stack = process_input( stack, input ) process_input( input )
stack = display_stack( stack ) 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 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 )

View file

@ -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
result = Rpn::Parser.new.parse_input( '" test"' )
assert_equal [{ value: '" test"', type: :string }], result
result = Rpn::Parser.new.parse_input( '"test "' )
assert_equal [{ value: '"test "', type: :string }], result
result = Rpn::Parser.new.parse_input( '" test "' )
assert_equal [{ value: '" test "', type: :string }], result
end end
def test_parse_input_name def test_name
result = parse_input( "'test'" ) result = Rpn::Parser.new.parse_input( "'test'" )
assert_equal [ { "value" => "test", "type" => "NAME" } ], result assert_equal [{ value: "'test'", type: :name }], result
end end
def test_parse_input_program def test_program
result = parse_input( "« test »" ) result = Rpn::Parser.new.parse_input( '« test »' )
assert_equal [ { "value" => "test", "type" => "PROGRAM" } ], 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: :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: :program }], result
result = parse_input( "« test test »" ) result = Rpn::Parser.new.parse_input( '« test test »' )
assert_equal [ { "value" => "test test", "type" => "PROGRAM" } ], result assert_equal [{ value: '« test test »', type: :program }], result
result = parse_input( "« test \"test\" test »" ) result = Rpn::Parser.new.parse_input( '« test « test » »' )
assert_equal [ { "value" => "test \"test\" test", "type" => "PROGRAM" } ], result 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 end
def test_parse_input_number_number def test_number_number
result = parse_input( "2 3" ) result = Rpn::Parser.new.parse_input( '2 3' )
assert_equal [ { "value" => 2, "type" => "NUMBER" }, { "value" => 3, "type" => "NUMBER" } ], result assert_equal [{ value: 2, type: :numeric }, { value: 3, type: :numeric }], result
end end
def test_parse_input_number_string def test_number_string
result = parse_input( "4 \"test\"" ) result = Rpn::Parser.new.parse_input( '4 "test"' )
assert_equal [ { "value" => 4, "type" => "NUMBER" }, { "value" => "test", "type" => "STRING" } ], result assert_equal [{ value: 4, type: :numeric }, { value: '"test"', type: :string }], result
end end
end end