From a0722ac2a697542cb1e2df9007003501af201227 Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Sat, 3 Jun 2023 21:35:25 +0900 Subject: [PATCH] replace RubyVM::AbstractSyntaxTree --- lib/vaporware/compiler/generator.rb | 52 ++++++++++++++--------------- sig/vaporware.rbs | 5 +-- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/lib/vaporware/compiler/generator.rb b/lib/vaporware/compiler/generator.rb index 39787ba..3a15d85 100644 --- a/lib/vaporware/compiler/generator.rb +++ b/lib/vaporware/compiler/generator.rb @@ -1,34 +1,35 @@ # frozen_string_literal: true -require "parser/current" module Vaporware class Compiler class Generator + REGISTER = %w(rdi rsi rdx rcx r8 r9) attr_accessor :main attr_reader :ast, :precompile, :debug, :seq, :defined_variables, :doned, :shared, :defined_methods def initialize(source, precompile:, debug:, shared:) @precompile, @debug, @shared = precompile, debug, shared @doned, @defined_methods, @defined_variables = Set.new, Set.new, Set.new @seq, @main = 0, false - src = File.read(File.expand_path(source)) - @ast = Parser::CurrentRuby.parse(src) + @ast = RubyVM::AbstractSyntaxTree.parse_file(source) end def compile_shared_option = %w(-shared -fPIC) def register_var_and_method(node) - return unless node.kind_of?(Parser::AST::Node) + return unless node.kind_of?(RubyVM::AbstractSyntaxTree::Node) type = node.type - if variable_or_method?(type) - name, _ = node.children - name = [:lvasgn, :arg].include?(type) ? "lvar_#{name}".to_sym : name - type == :def ? @defined_methods << name : @defined_variables << name + variables, *_ = node.children + case type + when :SCOPE + variables.each { |v| @defined_variables << v } + when :DEFN + @defined_methods << variables end node.children.each { |n| register_var_and_method(n) } + nil end def already_build_methods? = defined_methods.sort == @doned.to_a.sort - def variable_or_method?(type) = [:lvasgn, :arg, :def].include?(type) def call_compiler(output: precompile, compiler: "gcc", compiler_options: ["-O0"]) base_name = File.basename(output, ".*") @@ -69,7 +70,7 @@ def method(method, node, output) output.puts "#{method}:" define_method_prologue(node, output) node.children.each do |child| - next unless child.kind_of?(Parser::AST::Node) + next unless child.kind_of?(RubyVM::AbstractSyntaxTree::Node) to_asm(child, output, true) end ret(output) @@ -79,7 +80,7 @@ def method(method, node, output) def args(node, output) node.children.each do |child| - name = "arg_#{child.children.first}".to_sym + name = "arg_#{child.children.first}".to_sym rescue binding.irb lvar(name, output) output.puts " pop rax" output.puts " mov rax, [rax]" @@ -147,13 +148,16 @@ def ret(output) end def to_asm(node, output, method_tree = false) - return unless node.kind_of?(Parser::AST::Node) + return unless node.kind_of?(RubyVM::AbstractSyntaxTree::Node) type = node.type center = case type - when :int + when :LIT output.puts " push #{node.children.last}" return - when :begin + when :LIST, :BLOCK + node.children.each { |n| to_asm(n, output, method_tree) } + return + when :SCOPE node.children.each do |child| if already_build_methods? && !@main return if shared @@ -167,27 +171,23 @@ def to_asm(node, output, method_tree = false) to_asm(child, output) end return - when :def + when :DEFN name, _ = node.children method(name, node, output) return - when :args - args(node, output) - return - when :lvar + when :LVAR return if method_tree - name = "lvar_#{node.children.last}".to_sym + name = node.children.last lvar(name, output) # lvar output.puts " pop rax" output.puts " mov rax, [rax]" output.puts " push rax" return - when :lvasgn - left, right = node.children + when :LASGN + name, right = node.children # rvar - name = "lvar_#{left}".to_sym lvar(name, output) to_asm(right, output, method_tree) @@ -197,7 +197,7 @@ def to_asm(node, output, method_tree = false) output.puts " push rdi" output.puts " pop rax" return - when :if + when :IF cond, tblock, fblock = node.children to_asm(cond, output) output.puts " pop rax" @@ -220,7 +220,7 @@ def to_asm(node, output, method_tree = false) end @seq += 1 return - when :while + when :WHILE cond, tblock = node.children output.puts ".Lbegin#{seq}:" to_asm(cond, output, method_tree) @@ -233,7 +233,7 @@ def to_asm(node, output, method_tree = false) output.puts ".Lend#{seq}:" @seq += 1 return - when :send + when :OPCALL left, center, right = node.children to_asm(left, output, method_tree) unless left.nil? if left.nil? diff --git a/sig/vaporware.rbs b/sig/vaporware.rbs index 4bc9481..95de99f 100644 --- a/sig/vaporware.rbs +++ b/sig/vaporware.rbs @@ -7,6 +7,7 @@ module Vaporware # class methods def self.compile: (String, ?compiler: String, ?dest: String, ?debug: bool, ?compiler_options: Array[String], ?shared: bool) -> nil def initialize: (String, ?_precompile: String, ?debug: bool, ?shared: bool) -> untyped + @generator: Vaporware::Compiler::Generator # instance methods def compile: (?compiler: String, ?compiler_options: Array[String]) -> nil @@ -27,7 +28,7 @@ module Vaporware attr_reader shared: bool # temporarily using untyped types since parser.gem's rbs information is unchecked. - attr_reader ast: untyped + attr_reader ast: RubyVM::AbstractSyntaxTree::Node # class methods def initialize: (String, precompile: String, debug: bool, shared: bool) -> untyped @@ -46,7 +47,7 @@ module Vaporware def method: (Symbol, untyped, File) -> nil def prologue: (untyped, File) -> nil def prologue_methods: (File) -> nil - def register_var_and_method: (untyped) -> nil + def register_var_and_method: (RubyVM::AbstractSyntaxTree::Node) -> nil def ret: (File) -> nil def to_asm: (untyped, File, ?bool) -> nil def variable_or_method?: (Symbol) -> bool