add runner and dictionary
This commit is contained in:
parent
94919db7a9
commit
ca315724ff
5 changed files with 72 additions and 34 deletions
24
lib/dictionary.rb
Normal file
24
lib/dictionary.rb
Normal 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
|
|
@ -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
26
lib/runner.rb
Normal 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
|
37
repl.rb
37
repl.rb
|
@ -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
|
elt[:value]
|
||||||
# case elt[:type]
|
|
||||||
# when :program
|
|
||||||
# "« #{elt[:value]} »"
|
|
||||||
# when :string
|
|
||||||
# "\"#{elt[:value]}\""
|
|
||||||
# when :name
|
|
||||||
# "'#{elt[:value]}'"
|
|
||||||
# else
|
|
||||||
elt[:value]
|
|
||||||
# end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def print_stack
|
def print_stack
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue