summaryrefslogtreecommitdiff
path: root/tool/ruby_vm/loaders/insns_def.rb
blob: 58748c3ca6360301a8cd42ffe2a60e52aad5283f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#! /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 '../helpers/scanner'

json    = []
scanner = RubyVM::Scanner.new '../../../insns.def'
path    = scanner.__FILE__
grammar = %r'
    (?<comment>  /[*] [^*]* [*]+ (?: [^*/] [^*]* [*]+ )* /         ){0}
    (?<keyword>  typedef | extern | static | auto | register |
                 struct  | union  | enum                           ){0}
    (?<C>        (?: \g<block> | [^{}]+ )*                         ){0}
    (?<block>    \{ \g<ws>* ^ \g<C> $ \g<ws>* \}                   ){0}
    (?<ws>       \g<comment> | \s                                  ){0}
    (?<ident>    [_a-zA-Z] [0-9_a-zA-Z]*                           ){0}
    (?<type>     (?: \g<keyword> \g<ws>+ )* \g<ident>              ){0}
    (?<arg>      \g<type> \g<ws>+ \g<ident> | \.\.\.               ){0}
    (?<argv>     (?# empty ) |
                 void        |
                 \g<arg> (?: \g<ws>* , \g<ws>* \g<arg> \g<ws>* )*  ){0}
    (?<pragma>   \g<ws>* // \s* attr \g<ws>+
                 (?<pragma:type> \g<type>   )              \g<ws>+
                 (?<pragma:name> \g<ident>  )              \g<ws>*
                 =                                         \g<ws>*
                 (?<pragma:expr> .+?;       )              \g<ws>* ){0}
    (?<insn>     DEFINE_INSN                               \g<ws>+
                 (?<insn:name>   \g<ident>  )              \g<ws>*
     [(] \g<ws>* (?<insn:opes>   \g<argv>   ) \g<ws>* [)]  \g<ws>*
     [(] \g<ws>* (?<insn:pops>   \g<argv>   ) \g<ws>* [)]  \g<ws>*
     [(] \g<ws>* (?<insn:rets>   \g<argv>   ) \g<ws>* [)]  \g<ws>* ){0}
'x

until scanner.eos? do
  next if scanner.scan(/#{grammar}\g<ws>+/o)
  split = -> (v) {
    case v when /\Avoid\z/ then
      []
    else
      v.split(/, */)
    end
  }

  l1   = scanner.scan!(/#{grammar}\g<insn>/o)
  name = scanner["insn:name"]
  ope  = split.(scanner["insn:opes"])
  pop  = split.(scanner["insn:pops"])
  ret  = split.(scanner["insn:rets"])

  attrs = []
  while l2 = scanner.scan(/#{grammar}\g<pragma>/o) do
    attrs << {
      location: [path, l2],
      name: scanner["pragma:name"],
      type: scanner["pragma:type"],
      expr: scanner["pragma:expr"],
    }
  end

  l3 = scanner.scan!(/#{grammar}\g<block>/o)
  json << {
    name: name,
    location: [path, l1],
    signature: {
      name: name,
      ope: ope,
      pop: pop,
      ret: ret,
    },
    attributes: attrs,
    expr: {
      location: [path, l3],
      expr: scanner["block"],
    },
  }
end

RubyVM::InsnsDef = json

if __FILE__ == $0 then
  require 'json'
  JSON.dump RubyVM::InsnsDef, STDOUT
end