implement LSTO
This commit is contained in:
parent
e96c3f94de
commit
a8dec5f2a4
5 changed files with 93 additions and 25 deletions
|
@ -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 ) } )
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
Loading…
Add table
Reference in a new issue