add runner and dictionary

This commit is contained in:
Gwenhael Le Moine 2021-11-10 11:01:26 +01:00
parent 94919db7a9
commit ca315724ff
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
5 changed files with 72 additions and 34 deletions

24
lib/dictionary.rb Normal file
View file

@ -0,0 +1,24 @@
# coding: utf-8
module Rpn
class Dictionary
def initialize
@parser = Parser.new
@words = {
'+' => proc { |stack|
stack + @parser.parse_input( (stack.pop[:value] + stack.pop[:value]).to_s )
},
}
end
def add( word )
@words[ word[:name] ] = word[:value]
end
def lookup( name )
@words[ name ] if @words.include?( name )
end
# TODO: alias
end
end

View file

@ -19,6 +19,7 @@ module Rpn
closed_programs = 0 closed_programs = 0
string_delimiters = 0 string_delimiters = 0
regrouping = false regrouping = false
regrouped_input = [] regrouped_input = []
splitted_input.each do |elt| splitted_input.each do |elt|
# TODO: handle buried-in-elt « and » (surround by ' ' and re-split) # TODO: handle buried-in-elt « and » (surround by ' ' and re-split)
@ -64,15 +65,6 @@ module Rpn
end end
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
if parsed_entry[:type] == :numeric if parsed_entry[:type] == :numeric
i = parsed_entry[:value].to_i i = parsed_entry[:value].to_i
f = parsed_entry[:value].to_f f = parsed_entry[:value].to_f

26
lib/runner.rb Normal file
View file

@ -0,0 +1,26 @@
# coding: utf-8
module Rpn
class Runner
def initialize; end
def run_input( stack, dictionary, input )
input.each do |elt|
case elt[:type]
when :word
command = dictionary.lookup( elt[:value] )
if command.nil?
stack << { type: :name, value: "'#{elt[:value]}'" }
else
stack = command.call( stack )
end
else
stack << elt
end
end
[stack, dictionary]
end
end
end

35
repl.rb
View file

@ -1,15 +1,19 @@
# coding: utf-8 # coding: utf-8
# frozen_string_literal: true # frozen_string_literal: true
require "readline" require 'readline'
require "./lib/parser.rb" require './lib/dictionary'
require './lib/parser'
require './lib/runner'
module Rpn module Rpn
class Repl class Repl
def initialize def initialize
@parser = Parser.new
@stack = [] @stack = []
@dictionary = Dictionary.new
@parser = Parser.new
@runner = Runner.new
end end
def run def run
@ -21,39 +25,24 @@ module Rpn
Readline::HISTORY.grep(/^#{Regexp.escape(s)}/) Readline::HISTORY.grep(/^#{Regexp.escape(s)}/)
end end
end end
Readline.completion_append_character = " " Readline.completion_append_character = ' '
loop do loop do
input = Readline.readline( "", true ) input = Readline.readline( ' ', true )
break if input.nil? || 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?
process_input( input ) @stack, @dictionary = @runner.run_input( @stack, @dictionary,
@parser.parse_input( input ) )
print_stack print_stack
end end
end end
def process_input( input )
@parser.parse_input( input ).each do |elt|
@stack << elt # TODO: (parse and) evaluate elt if needed
end
end
def format_element( elt ) def format_element( elt )
pp elt
# case elt[:type]
# when :program
# "« #{elt[:value]} »"
# when :string
# "\"#{elt[:value]}\""
# when :name
# "'#{elt[:value]}'"
# else
elt[:value] elt[:value]
# end
end end
def print_stack def print_stack

View file

@ -13,7 +13,7 @@ class TestParser < Test::Unit::TestCase
def test_word def test_word
result = Rpn::Parser.new.parse_input( 'dup' ) result = Rpn::Parser.new.parse_input( 'dup' )
assert_equal [{ value: "'dup'", type: :name }], result assert_equal [{ value: 'dup', type: :word }], result
end end
def test_string def test_string
@ -63,6 +63,13 @@ class TestParser < Test::Unit::TestCase
assert_equal [{ value: 2, type: :numeric }, { value: 3, type: :numeric }], result assert_equal [{ value: 2, type: :numeric }, { value: 3, type: :numeric }], result
end end
def test_number_number_word
result = Rpn::Parser.new.parse_input( '2 3 +' )
assert_equal [{ value: 2, type: :numeric },
{ value: 3, type: :numeric },
{ value: '+', type: :word }], result
end
def test_number_string def test_number_string
result = Rpn::Parser.new.parse_input( '4 "test"' ) result = Rpn::Parser.new.parse_input( '4 "test"' )
assert_equal [{ value: 4, type: :numeric }, { value: '"test"', type: :string }], result assert_equal [{ value: 4, type: :numeric }, { value: '"test"', type: :string }], result