class RbScheme::VM

Constants

CLOSURE_OFFSET

Public Class Methods

new() click to toggle source
# File lib/rb-scheme/vm.rb, line 9
def initialize
  @stack = Stack.new
end

Public Instance Methods

add_empty_list_as_argument(stack_p, arg_count) click to toggle source
# File lib/rb-scheme/vm.rb, line 179
def add_empty_list_as_argument(stack_p, arg_count)
  last = arg_count - 1
  0.upto(last) do |n|
    v = index(stack_p, n)
    index_set!(stack_p, n - 1, v)
  end
  index_set!(stack_p, last, list)
end
apply_compound(acc, stack_p) click to toggle source
# File lib/rb-scheme/vm.rb, line 204
def apply_compound(acc, stack_p)
  # [exp, frame_p, cls]
  [closure_body(acc), stack_p, acc]
end
apply_primitive(prim_proc, arg_count, stack_p) click to toggle source
# File lib/rb-scheme/vm.rb, line 188
def apply_primitive(prim_proc, arg_count, stack_p)
  i = 0
  args = []
  arg_count.times do
    args.push(index(stack_p, i))
    i += 1
  end
  prim_proc.call(args)
end
check_parameter!(expect, got, variadic) click to toggle source
# File lib/rb-scheme/vm.rb, line 258
def check_parameter!(expect, got, variadic)
  if variadic
    unless (expect - 1) <= got
      raise ArgumentError,
        "closure: required at least #{expect} arguments, got #{got}"
    end
  else
    unless expect == got
      raise ArgumentError,
        "closure: required #{expect} arguments, got #{got}"
    end
  end
end
closure(body, param_count, variadic, free_count, stack_p) click to toggle source
# File lib/rb-scheme/vm.rb, line 227
def closure(body, param_count, variadic, free_count, stack_p)
  v = Array.new(free_count + CLOSURE_OFFSET)
  v[0] = body
  v[1] = param_count
  v[2] = variadic

  i = 0
  until i == free_count
    v[i + CLOSURE_OFFSET] = index(stack_p, i)
    i += 1
  end
  v
end
closure_body(cls) click to toggle source
# File lib/rb-scheme/vm.rb, line 241
def closure_body(cls)
  cls[0]
end
closure_param_count(cls) click to toggle source
# File lib/rb-scheme/vm.rb, line 245
def closure_param_count(cls)
  cls[1]
end
collect_arguments(stack_p, cls_param_count, arg_count) click to toggle source
# File lib/rb-scheme/vm.rb, line 146
def collect_arguments(stack_p, cls_param_count, arg_count)
  req = cls_param_count - 1
  list_length = arg_count - req
  unless list_length == 0
    collect_arguments_as_list(stack_p, arg_count, list_length)
    shift_required_variables(stack_p, req, arg_count)
    stack_p - arg_count + cls_param_count
  else
    add_empty_list_as_argument(stack_p, arg_count)
    stack_p + 1
  end
end
collect_arguments_as_list(stack_p, arg_count, length) click to toggle source
# File lib/rb-scheme/vm.rb, line 159
def collect_arguments_as_list(stack_p, arg_count, length)
  lst = list
  i = arg_count
  length.times do
    lst = cons(index(stack_p, i - 1), lst)
    i -= 1
  end
  index_set!(stack_p, arg_count - 1, lst)
end
compound_procedure?(procedure) click to toggle source
# File lib/rb-scheme/vm.rb, line 213
def compound_procedure?(procedure)
  procedure.is_a?(Array)
end
continuation(stack_p) click to toggle source
# File lib/rb-scheme/vm.rb, line 272
def continuation(stack_p)
  body = list(intern("refer-local"),
              0,
              list(intern("nuate"),
                   save_stack(stack_p),
                   list(intern("return"), 0)))
  closure(body, 1, 0, 0, stack_p)
end
exec(acc, exp, frame_p, cls, stack_p) click to toggle source
# File lib/rb-scheme/vm.rb, line 13
def exec(acc, exp, frame_p, cls, stack_p)
  loop do
    case exp.car
    when intern("halt")
      check_length!(exp.cdr, 0, "halt")
      return acc
    when intern("refer-local")
      check_length!(exp.cdr, 2, "refer-local")
      n, x = exp.cdr.to_a

      acc = index(frame_p, n)
      exp = x
    when intern("refer-free")
      check_length!(exp.cdr, 2, "refer-free")
      n, x = exp.cdr.to_a

      acc = index_closure(cls, n)
      exp = x
    when intern("refer-global")
      check_length!(exp.cdr, 2, "refer-free")
      key, x = exp.cdr.to_a

      acc = Global.get(key)
      exp = x
    when intern("indirect")
      check_length!(exp.cdr, 1, "indirect")
      x = exp.cadr

      acc = acc.unbox
      exp = x
    when intern("constant")
      check_length!(exp.cdr, 2, "constant")
      obj, x = exp.cdr.to_a

      acc = obj
      exp = x
    when intern("close")
      check_length!(exp.cdr, 5, "close")
      param_count, variadic, free_count, body, x = exp.cdr.to_a

      acc = closure(body, param_count, variadic, free_count, stack_p)
      exp = x
      stack_p = stack_p - free_count
    when intern("box")
      check_length!(exp.cdr, 2, "box")
      n, x = exp.cdr.to_a

      index_set!(stack_p, n, Box.new(index(stack_p, n)))
      exp = x
    when intern("test")
      check_length!(exp.cdr, 2, "test")
      thenx, elsex = exp.cdr.to_a

      exp = LFalse === acc ? elsex : thenx
    when intern("assign-local")
      check_length!(exp.cdr, 2, "assign-local")
      n, x = exp.cdr.to_a

      index(frame_p, n).set_box!(acc)
      exp = x
    when intern("assign-free")
      check_length!(exp.cdr, 2, "assign-free")
      n, x = exp.cdr.to_a

      index_closure(cls, n).set_box!(acc)
      exp = x
    when intern("assign-global")
      check_length!(exp.cdr, 2, "assign-global")
      key, x = exp.cdr.to_a

      Global.put(key, acc)
      exp = x
    when intern("conti")
      check_length!(exp.cdr, 1, "conti")
      x = exp.cadr

      acc = continuation(stack_p)
      exp = x
    when intern("nuate")
      check_length!(exp.cdr, 2, "nuate")
      saved_stack, x = exp.cdr.to_a

      exp = x
      stack_p = restore_stack(saved_stack)
    when intern("frame")
      check_length!(exp.cdr, 2, "frame")
      ret, x = exp.cdr.to_a

      exp = x
      stack_p = push(ret, push(frame_p, push(cls, stack_p)))
    when intern("argument")
      check_length!(exp.cdr, 1, "argument")
      x = exp.cadr

      exp = x
      stack_p = push(acc, stack_p)
    when intern("shift")
      check_length!(exp.cdr, 3, "shift")
      n, m, x = exp.cdr.to_a

      exp = x
      stack_p = shift_args(n, m, stack_p)
    when intern("apply")
      check_length!(exp.cdr, 1, "apply")
      arg_count = exp.cadr

      if primitive_procedure?(acc)
        acc = apply_primitive(acc, arg_count, stack_p)
        exp, frame_p, cls, stack_p = return_primitive(stack_p, arg_count)
      elsif compound_procedure?(acc)
        check_parameter!(closure_param_count(acc), arg_count, variadic_closure?(acc))
        if variadic_closure?(acc)
          stack_p = collect_arguments(stack_p, closure_param_count(acc), arg_count)
        end
        exp, frame_p, cls = apply_compound(acc, stack_p)
      else
        raise "invalid application"
      end
    when intern("return")
      check_length!(exp.cdr, 1, "return")
      n = exp.cadr
      s = stack_p - n

      exp = index(s, 0)
      frame_p = index(s, 1)
      cls = index(s, 2)
      stack_p = s - 3
    else
      raise "Unknown instruction - #{exp.car}"
    end
  end
end
index_closure(cls, n) click to toggle source
# File lib/rb-scheme/vm.rb, line 254
def index_closure(cls, n)
  cls[n + CLOSURE_OFFSET]
end
primitive_procedure?(procedure) click to toggle source
# File lib/rb-scheme/vm.rb, line 209
def primitive_procedure?(procedure)
  procedure.is_a?(Primitive::Procedure)
end
return_primitive(stack_p, arg_count) click to toggle source
# File lib/rb-scheme/vm.rb, line 198
def return_primitive(stack_p, arg_count)
  s = stack_p - arg_count
  # [exp, frame_p, cls, stack_p]
  [index(s, 0), index(s, 1), index(s, 2), s -3]
end
shift_args(n, m, s) click to toggle source
# File lib/rb-scheme/vm.rb, line 217
def shift_args(n, m, s)
  i = n - 1
  until i < 0
    index_set!(s, i + m, index(s, i))
    i -= 1
  end
  s - m
end
shift_required_variables(stack_p, required_count, arg_count) click to toggle source
# File lib/rb-scheme/vm.rb, line 169
def shift_required_variables(stack_p, required_count, arg_count)
  j = required_count
  k = arg_count - 2
  required_count.times do
    index_set!(stack_p, k, index(stack_p, j - 1))
    j -= 1
    k -= 1
  end
end
variadic_closure?(cls) click to toggle source
# File lib/rb-scheme/vm.rb, line 249
def variadic_closure?(cls)
  # 1: true, 0: false
  cls[2] == 1
end