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( '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( '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( '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
|
# PROGRAM
|
||||||
@dictionary.add( 'eval', proc { |stack, dictionary| Rpl::Lang::Core.eval( stack, dictionary ) } )
|
@dictionary.add( 'eval', proc { |stack, dictionary| Rpl::Lang::Core.eval( stack, dictionary ) } )
|
||||||
|
|
|
@ -23,6 +23,24 @@ module Rpl
|
||||||
[stack, dictionary]
|
[stack, dictionary]
|
||||||
end
|
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
|
# recall a variable. ex: 'name' rcl
|
||||||
def rcl( stack, dictionary )
|
def rcl( stack, dictionary )
|
||||||
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[name]] )
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[name]] )
|
||||||
|
@ -46,7 +64,7 @@ module Rpl
|
||||||
# list all variables
|
# list all variables
|
||||||
def vars( stack, dictionary )
|
def vars( stack, dictionary )
|
||||||
stack << { type: :list,
|
stack << { type: :list,
|
||||||
value: dictionary.vars.keys }
|
value: dictionary.vars.keys + dictionary.local_vars_layers.reduce([]) { |memo, layer| memo + layer.keys } }
|
||||||
|
|
||||||
[stack, dictionary]
|
[stack, dictionary]
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,12 +3,63 @@
|
||||||
module Rpl
|
module Rpl
|
||||||
module Lang
|
module Lang
|
||||||
class Dictionary
|
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
|
def initialize
|
||||||
@parser = Parser.new
|
@parser = Parser.new
|
||||||
@words = {}
|
@words = {}
|
||||||
@vars = {}
|
@vars = {}
|
||||||
|
@local_vars_layers = []
|
||||||
|
|
||||||
# GENERAL
|
# GENERAL
|
||||||
add( 'nop', proc { |stack, dictionary| Rpl::Lang::Core.nop( stack, dictionary ) } )
|
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( '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, …)
|
# add( 'fwrite', proc { |stack, dictionary| Rpl::Lang::Core.__todo( stack, dictionary ) } ) # ( content filename mode -- ) write content into filename using mode (w, a, …)
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,8 @@ module Rpl
|
||||||
def initialize; end
|
def initialize; end
|
||||||
|
|
||||||
def run_input( input, stack, dictionary )
|
def run_input( input, stack, dictionary )
|
||||||
|
dictionary.add_local_vars_layer
|
||||||
|
|
||||||
input.each do |elt|
|
input.each do |elt|
|
||||||
case elt[:type]
|
case elt[:type]
|
||||||
when :word
|
when :word
|
||||||
|
@ -24,6 +26,8 @@ module Rpl
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
dictionary.remove_local_vars_layer
|
||||||
|
|
||||||
[stack, dictionary]
|
[stack, dictionary]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,22 @@ class TestLanguageProgram < Test::Unit::TestCase
|
||||||
lang.stack
|
lang.stack
|
||||||
end
|
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
|
def test_rcl
|
||||||
lang = Rpl::Language.new
|
lang = Rpl::Language.new
|
||||||
lang.run '« 2 dup * » \'quatre\' sto \'quatre\' rcl'
|
lang.run '« 2 dup * » \'quatre\' sto \'quatre\' rcl'
|
||||||
|
|
Loading…
Add table
Reference in a new issue