rpl.rb/lib/rpl/interpreter.rb
Gwenhael Le Moine edd0884f9d
s/display/frame_buffer/g
Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
2022-08-30 13:37:34 +02:00

107 lines
2 KiB
Ruby

# frozen_string_literal: true
require 'bigdecimal'
require 'bigdecimal/math'
require 'bigdecimal/util'
require 'rpl/dictionary'
require 'rpl/types'
class BitArray
def initialize
@mask = 0
end
def []=(position, value)
if value.zero?
@mask ^= (1 << position)
else
@mask |= (1 << position)
end
end
def [](position)
@mask[position]
end
end
class Interpreter
include BigMath
include Types
attr_reader :stack,
:frame_buffer,
:dictionary,
:version
attr_accessor :precision
def initialize( stack = [], dictionary = Rpl::Lang::Dictionary.new )
@version = 0.8
@dictionary = dictionary
@stack = stack
initialize_frame_buffer
end
def initialize_frame_buffer
@frame_buffer = BitArray.new
end
def run( input )
@dictionary.add_local_vars_layer
Parser.parse( input.to_s ).each do |elt|
if elt.instance_of?( RplName )
break if %w[break quit exit].include?( elt.value )
if elt.not_to_evaluate
@stack << elt
else
command = @dictionary.lookup( elt.value )
if command.nil?
@stack << elt
elsif command.is_a?( Proc )
command.call
else
if command.instance_of?( RplProgram )
run( command.value )
else
@stack << command
end
end
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
needs.each_with_index do |need, index|
stack_index = (index + 1) * -1
raise ArgumentError, "Type Error, needed #{need} got #{@stack[stack_index]}" unless need == :any || need.include?( @stack[stack_index].class )
end
args = []
needs.size.times do
args << @stack.pop
end
args
end
def export_stack
@stack.map(&:to_s).join(' ')
end
end