From 4dfe9554cb35b27da983251a6599a4f9455a8bf0 Mon Sep 17 00:00:00 2001 From: Gwenhael Le Moine Date: Tue, 4 Oct 2022 16:49:24 +0200 Subject: [PATCH] Persist stack and variable in ~/.local/state/rpl.rb/machine --- README.md | 4 ---- bin/rpl | 32 +++++++++++++++++++++++--------- lib/rpl.rb | 39 +++++++++++++++++++++++++++++++++++++-- lib/rpl/interpreter.rb | 17 ++++++++++++----- 4 files changed, 72 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 42de832..5857b05 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,6 @@ To build gem: `rake gem` - # TODO-list - * REPL: - * autosave/autoload stack and vars from ~/.rplenv on start/exit - . autoload is just « '~/.rplenv' feval » - . autosave on exit overwrites * Language: * pseudo filesystem: subdir/namespace for variables . 'a dir' crdir 'a dir' cd vars diff --git a/bin/rpl b/bin/rpl index a40164c..e5cd4ce 100755 --- a/bin/rpl +++ b/bin/rpl @@ -8,9 +8,7 @@ require 'readline' require 'rpl' class RplRepl - def initialize( interpreter ) - interpreter ||= Rpl.new - + def initialize( interpreter: Rpl.new ) @interpreter = interpreter end @@ -51,11 +49,25 @@ class RplRepl end options = { run_REPL: ARGV.empty?, + persistence_filename: File.expand_path( '~/.local/state/rpl.rb/machine' ), + live_persistence: true, files: [], programs: [] } OptionParser.new do |opts| - opts.on('-c', '--code "program"', ' ') do |program| + opts.on('-s', "--state filename", "persist state in filename (default: #{options[:persistence_filename]}) (will be created if needed)") do |filename| + options[:persistence_filename] = File.expand_path( filename ) + end + + opts.on('-q', '--no-state', 'Do not load persisted state') do + options[:persistence_filename] = nil + end + + opts.on('-d', '--no-persist', 'Do not persist state') do + options[:live_persistence] = false + end + + opts.on('-c', '--code "program"', 'run provided "program"') do |program| options[:programs] << program end @@ -69,7 +81,8 @@ OptionParser.new do |opts| end.parse! # Instantiate interpreter -interpreter = Rpl.new +interpreter = Rpl.new( persistence_filename: options[:persistence_filename], + live_persistence: options[:live_persistence] ) # first run provided files if any options[:files].each do |filename| @@ -82,7 +95,8 @@ options[:programs].each do |program| end # third launch REPL if (explicitely or implicitely) asked -RplRepl.new( interpreter ).run if options[:run_REPL] - -# last print defined vars and resulting stack on exit (formatted so that it can be fed back later to interpreter) -pp "#{interpreter.export_vars} #{interpreter.export_stack}" +if options[:run_REPL] + RplRepl.new( interpreter: interpreter ).run +else + interpreter.persist_state +end diff --git a/lib/rpl.rb b/lib/rpl.rb index 762118b..387c6e8 100644 --- a/lib/rpl.rb +++ b/lib/rpl.rb @@ -7,10 +7,45 @@ require 'rpl/words' class Rpl < Interpreter include Types - def initialize( stack = [], dictionary = Dictionary.new ) - super + attr_accessor :live_persistence + + def initialize( stack: [], + dictionary: Dictionary.new, + persistence_filename: nil, + live_persistence: true ) + super( stack: stack, dictionary: dictionary ) + + @persistence_filename = persistence_filename + @live_persistence = live_persistence populate_dictionary if @dictionary.words.empty? + + load_persisted_state + end + + def load_persisted_state + return if @persistence_filename.nil? + + FileUtils.mkdir_p( File.dirname( @persistence_filename ) ) + FileUtils.touch( @persistence_filename ) + + run "\"#{@persistence_filename}\" feval" + end + + def persist_state + return if @persistence_filename.nil? + + File.open( @persistence_filename, 'w' ) do |persistence_file| + persistence_file.write "#{export_vars}\n#{export_stack}" + end + end + + def run( input ) + stack = super + + persist_state if @live_persistence + + stack end prepend RplLang::Words::Branch diff --git a/lib/rpl/interpreter.rb b/lib/rpl/interpreter.rb index a36eb83..df22768 100644 --- a/lib/rpl/interpreter.rb +++ b/lib/rpl/interpreter.rb @@ -36,7 +36,7 @@ class Interpreter attr_accessor :precision - def initialize( stack = [], dictionary = Rpl::Lang::Dictionary.new ) + def initialize( stack: [], dictionary: Dictionary.new ) @version = 0.91 @dictionary = dictionary @@ -100,12 +100,19 @@ class Interpreter end def export_vars - @dictionary.vars - .map { |name, value| "#{value} '#{name}' sto" } - .join(' ') + vars_as_string = "@ variables:\n" + vars_as_string += @dictionary.vars + .map { |name, value| "#{value}\n'#{name}' sto\n" } + .join("\n") + + vars_as_string end def export_stack - @stack.map(&:to_s).join(' ') + stack_as_string = "@ stack:\n" + stack_as_string += @stack.map(&:to_s) + .join("\n") + + stack_as_string end end