rpl.rb/lib/rpl/interpreter.rb

85 lines
1.8 KiB
Ruby
Raw Normal View History

2022-02-10 14:50:59 +01:00
# frozen_string_literal: true
2022-02-22 15:54:53 +01:00
require 'bigdecimal'
2022-02-10 14:50:59 +01:00
require 'bigdecimal/math'
2022-02-22 15:54:53 +01:00
require 'bigdecimal/util'
2022-02-10 14:50:59 +01:00
2022-02-15 17:06:19 +01:00
require 'rpl/dictionary'
2022-02-26 18:53:39 +01:00
require 'rpl/types'
2022-02-10 14:50:59 +01:00
class Interpreter
include BigMath
2022-02-26 18:53:39 +01:00
include Types
2022-02-10 14:50:59 +01:00
attr_reader :stack,
:dictionary,
:version
attr_accessor :precision
def initialize( stack = [], dictionary = Rpl::Lang::Dictionary.new )
2022-03-02 14:06:26 +01:00
@version = 0.7
2022-02-10 14:50:59 +01:00
@dictionary = dictionary
@stack = stack
end
def run( input )
@dictionary.add_local_vars_layer
2022-02-26 18:53:39 +01:00
Parser.parse( input.to_s ).each do |elt|
if elt.instance_of?( RplName )
break if %w[break quit exit].include?( elt.value )
2022-02-10 14:50:59 +01:00
2022-02-26 18:53:39 +01:00
if elt.not_to_evaluate
2022-02-10 14:50:59 +01:00
@stack << elt
else
2022-02-26 18:53:39 +01:00
command = @dictionary.lookup( elt.value )
if command.nil?
# if there isn't a command by that name then it's a name
# elt[:type] = :name
@stack << elt
elsif command.is_a?( Proc )
command.call
else
2022-02-26 19:57:38 +01:00
if command.instance_of?( RplProgram )
run( command.value )
else
@stack << command
end
2022-02-26 18:53:39 +01:00
end
2022-02-10 14:50:59 +01:00
end
else
@stack << elt
end
end
@dictionary.remove_local_vars_layer
# superfluous but feels nice
@stack
end
def stack_extract( needs )
raise ArgumentError, 'Not enough elements' if @stack.size < needs.size
2022-02-10 18:37:44 +01:00
needs.each_with_index do |need, index|
stack_index = (index + 1) * -1
2022-02-26 18:53:39 +01:00
raise ArgumentError, "Type Error, needed #{need} got #{@stack[stack_index]}" unless need == :any || need.include?( @stack[stack_index].class )
end
2022-02-10 18:37:44 +01:00
args = []
needs.size.times do
2022-02-10 14:50:59 +01:00
args << @stack.pop
end
args
end
2022-02-26 18:53:39 +01:00
def export_stack
@stack.map(&:to_s).join(' ')
2022-02-10 14:50:59 +01:00
end
end