summaryrefslogtreecommitdiff
path: root/tool/ruby_vm/models/bare_instructions.rb
diff options
context:
space:
mode:
Diffstat (limited to 'tool/ruby_vm/models/bare_instructions.rb')
-rw-r--r--tool/ruby_vm/models/bare_instructions.rb162
1 files changed, 162 insertions, 0 deletions
diff --git a/tool/ruby_vm/models/bare_instructions.rb b/tool/ruby_vm/models/bare_instructions.rb
new file mode 100644
index 0000000000..c3a96b8f08
--- /dev/null
+++ b/tool/ruby_vm/models/bare_instructions.rb
@@ -0,0 +1,162 @@
+#! /your/favourite/path/to/ruby
+# -*- mode: ruby; coding: utf-8; indent-tabs-mode: nil; ruby-indent-level: 2 -*-
+# -*- frozen_string_literal: true; -*-
+# -*- warn_indent: true; -*-
+#
+# Copyright (c) 2017 Urabe, Shyouhei. All rights reserved.
+#
+# This file is a part of the programming language Ruby. Permission is hereby
+# granted, to either redistribute and/or modify this file, provided that the
+# conditions mentioned in the file COPYING are met. Consult the file for
+# details.
+
+require_relative '../loaders/insns_def'
+require_relative 'c_expr'
+require_relative 'typemap'
+require_relative 'attribute'
+
+class RubyVM::BareInstructions
+ attr_reader :template, :name, :opes, :pops, :rets, :decls, :expr
+
+ def initialize template:, name:, location:, signature:, attributes:, expr:
+ @template = template
+ @name = name
+ @loc = location
+ @sig = signature
+ @expr = RubyVM::CExpr.new expr
+ @opes = typesplit @sig[:ope]
+ @pops = typesplit @sig[:pop].reject {|i| i == '...' }
+ @rets = typesplit @sig[:ret].reject {|i| i == '...' }
+ @attrs = attributes.map {|i|
+ RubyVM::Attribute.new insn: self, **i
+ }.each_with_object({}) {|a, h|
+ h[a.key] = a
+ }
+ @attrs_orig = @attrs.dup
+ end
+
+ def pretty_name
+ n = @sig[:name]
+ o = @sig[:ope].map{|i| i[/\S+$/] }.join ', '
+ p = @sig[:pop].map{|i| i[/\S+$/] }.join ', '
+ r = @sig[:ret].map{|i| i[/\S+$/] }.join ', '
+ return sprintf "%s(%s)(%s)(%s)", n, o, p, r
+ end
+
+ def bin
+ return "BIN(#{name})"
+ end
+
+ def call_attribute name
+ return sprintf 'CALL_ATTRIBUTE(%s)', [
+ name, @name, @opes.map {|i| i[:name] }
+ ].flatten.compact.join(', ')
+ end
+
+ def sp_inc
+ return @attrs.fetch "sp_inc" do |k|
+ return generate_attribute k, 'rb_snum_t', rets.size - pops.size
+ end
+ end
+
+ def has_attribute? k
+ @attrs_orig.has_key? k
+ end
+
+ def attributes
+ # need to generate predefined attribute defaults
+ sp_inc
+ # other_attribute
+ # ...
+ return @attrs.values
+ end
+
+ def width
+ return 1 + opes.size
+ end
+
+ def declarations
+ return @variables \
+ . values \
+ . group_by {|h| h[:type] } \
+ . map {|t, v| [t, v.map {|i| i[:name] }.sort ] } \
+ . map {|t, v| sprintf("%s %s", t, v.join(', ')) } \
+ . sort
+ end
+
+ def preamble
+ # preamble makes sense for operand unifications
+ return []
+ end
+
+ def sc?
+ # sc stands for stack caching.
+ return false
+ end
+
+ def cast_to_VALUE var, expr = var[:name]
+ RubyVM::Typemap.typecast_to_VALUE var[:type], expr
+ end
+
+ def cast_from_VALUE var, expr = var[:name]
+ RubyVM::Typemap.typecast_from_VALUE var[:type], expr
+ end
+
+ def operands_info
+ opes.map {|o|
+ c, _ = RubyVM::Typemap.fetch o[:type]
+ next c
+ }.join
+ end
+
+ def pushs_frame?
+ opes.any? {|o| /CALL_INFO/ =~ o[:type] }
+ end
+
+ def inspect
+ sprintf "#<%s@%s:%d>", @name, @loc[0], @loc[1]
+ end
+
+ private
+
+ def generate_attribute k, t, v
+ attr = RubyVM::Attribute.new \
+ insn: self, \
+ name: k, \
+ type: t, \
+ location: [], \
+ expr: v.to_s + ';'
+ return @attrs[k] = attr
+ end
+
+ def typesplit a
+ @variables ||= {}
+ a.map do |decl|
+ md = %r'
+ (?<comment> /[*] [^*]* [*]+ (?: [^*/] [^*]* [*]+ )* / ){0}
+ (?<ws> \g<comment> | \s ){0}
+ (?<ident> [_a-zA-Z] [0-9_a-zA-Z]* ){0}
+ (?<type> (?: \g<ident> \g<ws>+ )* \g<ident> ){0}
+ (?<var> \g<ident> ){0}
+ \G \g<ws>* \g<type> \g<ws>+ \g<var>
+ 'x.match(decl)
+ @variables[md['var']] ||= {
+ decl: decl,
+ type: md['type'],
+ name: md['var'],
+ }
+ end
+ end
+
+ @instances = RubyVM::InsnsDef.map {|h| new template: h, **h }
+
+ def self.fetch name
+ @instances.find do |insn|
+ insn.name == name
+ end or raise IndexError, "instruction not found: #{name}"
+ end
+
+ def self.to_a
+ @instances
+ end
+end