implement LSTO

This commit is contained in:
Gwenhael Le Moine 2022-02-02 15:20:24 +01:00
parent e96c3f94de
commit a8dec5f2a4
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
5 changed files with 93 additions and 25 deletions

View file

@ -167,6 +167,8 @@ module Rpl
@dictionary.add( 'sneg', proc { |stack, dictionary| Rpl::Lang::Core.sto_negate( stack, dictionary ) } )
@dictionary.add( 'sinv', proc { |stack, dictionary| Rpl::Lang::Core.sto_inverse( stack, dictionary ) } )
# @dictionary.add( 'edit', proc { |stack, dictionary| Rpl::Lang::Core.__todo( stack, dictionary ) } ) # edit a variable content
@dictionary.add( 'lsto', proc { |stack, dictionary| Rpl::Lang::Core.lsto( stack, dictionary ) } ) # store to local variable
@dictionary.add( '↴', proc { |stack, dictionary| Rpl::Lang::Core.lsto( stack, dictionary ) } ) # alias
# PROGRAM
@dictionary.add( 'eval', proc { |stack, dictionary| Rpl::Lang::Core.eval( stack, dictionary ) } )

View file

@ -23,6 +23,24 @@ module Rpl
[stack, dictionary]
end
# store a local variable
def lsto( stack, dictionary )
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[name], :any] )
dictionary.add_local_var( args[0][:value],
proc { |stk, dict, rcl_only = false|
stk << args[1]
if rcl_only
[stk, dict]
else
Rpl::Lang::Core.eval( stk, dict )
end
} )
[stack, dictionary]
end
# recall a variable. ex: 'name' rcl
def rcl( stack, dictionary )
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[name]] )
@ -46,7 +64,7 @@ module Rpl
# list all variables
def vars( stack, dictionary )
stack << { type: :list,
value: dictionary.vars.keys }
value: dictionary.vars.keys + dictionary.local_vars_layers.reduce([]) { |memo, layer| memo + layer.keys } }
[stack, dictionary]
end

View file

@ -3,12 +3,63 @@
module Rpl
module Lang
class Dictionary
attr_reader :vars
attr_reader :vars,
:local_vars_layers
def add( name, implementation )
@words[ name ] = implementation
end
def add_var( name, implementation )
@vars[ name ] = implementation
end
def remove_vars( names )
names.each { |name| @vars.delete( name ) }
end
def remove_var( name )
remove_vars( [name] )
end
def remove_all_vars
@vars = {}
end
def add_local_vars_layer
@local_vars_layers << {}
end
def add_local_var( name, implementation )
@local_vars_layers.last[ name ] = implementation
end
def remove_local_vars( names )
names.each { |name| @local_vars_layers.last.delete( name ) }
end
def remove_local_var( name )
remove_local_vars( [name] )
end
def remove_local_vars_layer
@local_vars_layers.pop
end
def lookup( name )
local_var = @local_vars_layers.reverse.find { |layer| layer[ name ] }
word = local_var.nil? ? nil : local_var[name]
word ||= @vars[ name ]
word ||= @words[ name ]
word
end
def initialize
@parser = Parser.new
@words = {}
@vars = {}
@local_vars_layers = []
# GENERAL
add( 'nop', proc { |stack, dictionary| Rpl::Lang::Core.nop( stack, dictionary ) } )
@ -212,29 +263,6 @@ module Rpl
# add( 'fload', proc { |stack, dictionary| Rpl::Lang::Core.__todo( stack, dictionary ) } ) # ( filename -- … ) « FREAD EVAL »
# add( 'fwrite', proc { |stack, dictionary| Rpl::Lang::Core.__todo( stack, dictionary ) } ) # ( content filename mode -- ) write content into filename using mode (w, a, …)
end
def add( name, implementation )
@words[ name ] = implementation
end
def add_var( name, implementation )
@vars[ name ] = implementation
end
def remove_var( name )
@vars.delete( name )
end
def remove_all_vars
@vars = {}
end
def lookup( name )
word = @words[ name ]
word ||= @vars[ name ]
word
end
end
end
end

View file

@ -6,6 +6,8 @@ module Rpl
def initialize; end
def run_input( input, stack, dictionary )
dictionary.add_local_vars_layer
input.each do |elt|
case elt[:type]
when :word
@ -24,6 +26,8 @@ module Rpl
end
end
dictionary.remove_local_vars_layer
[stack, dictionary]
end
end

View file

@ -15,6 +15,22 @@ class TestLanguageProgram < Test::Unit::TestCase
lang.stack
end
def test_lsto
lang = Rpl::Language.new
lang.run "« 2 'deux' lsto deux dup * » eval 'deux' rcl"
assert_empty lang.dictionary.local_vars_layers
assert_equal [{ value: 4, type: :numeric, base: 10 }],
lang.stack
lang = Rpl::Language.new
lang.run "« 2 'deux' lsto « 3 'trois' lsto trois drop » eval deux dup * » eval 'deux' rcl 'trois' rcl"
assert_empty lang.dictionary.local_vars_layers
assert_equal [{ value: 4, type: :numeric, base: 10 }],
lang.stack
end
def test_rcl
lang = Rpl::Language.new
lang.run '« 2 dup * » \'quatre\' sto \'quatre\' rcl'