summaryrefslogtreecommitdiff
path: root/tool/ruby_vm/helpers/c_escape.rb
blob: 2a99e408daeb4b34bb70021968fa210eb3865e12 (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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#! /your/favourite/path/to/ruby
# -*- Ruby -*-
# -*- 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 'securerandom'

module RubyVM::CEscape
  module_function

  # generate comment, with escaps.
  def commentify str
    unless str = str.dump[/\A"\K.*(?="\z)/]
      raise Encoding::CompatibilityError, "must be ASCII-compatible (#{str.encoding})"
    end
    return "/* #{str.gsub('*/', '*\\/').gsub('/*', '/\\*')} */"
  end

  # Mimic gensym of CL.
  def gensym prefix = 'gensym_'
    return as_tr_cpp "#{prefix}#{SecureRandom.uuid}"
  end

  # Mimic AS_TR_CPP() of autoconf.
  def as_tr_cpp name
    q = name.b
    q.gsub! %r/[^a-zA-Z0-9_]/m, '_'
    q.gsub! %r/_+/, '_'
    return q
  end

  # Section 6.10.4 of  ISO/IEC 9899:1999 specifies that the file  name used for
  # #line directive shall be a "character string literal".  So this is needed.
  #
  # I'm  not sure  how  many  chars are  allowed  here,  though.  The  standard
  # specifies 4095 chars at most, after string concatenation (section 5.2.4.1).
  # But it is easy to have a path that is longer than that.
  #
  # Here  we ignore  the standard.  Just create  single string  literal of  any
  # needed length.
  def rstring2cstr str
    # I believe this is the fastest implementation done in pure-ruby.
    # Constants cached, gsub skips block evaluation, string literal optimized.
    buf = str.b
    buf.gsub! %r/./nm, RString2CStr
    return %'"#{buf}"'
  end

  RString2CStr = {
      "\x00"=>  "\\0", "\x01"=> "\\x1", "\x02"=> "\\x2", "\x03"=> "\\x3",
      "\x04"=> "\\x4", "\x05"=> "\\x5", "\x06"=> "\\x6",   "\a"=>  "\\a",
        "\b"=>  "\\b",   "\t"=>  "\\t",   "\n"=>  "\\n",   "\v"=>  "\\v",
        "\f"=>  "\\f",   "\r"=>  "\\r", "\x0E"=> "\\xe", "\x0F"=> "\\xf",
      "\x10"=>"\\x10", "\x11"=>"\\x11", "\x12"=>"\\x12", "\x13"=>"\\x13",
      "\x14"=>"\\x14", "\x15"=>"\\x15", "\x16"=>"\\x16", "\x17"=>"\\x17",
      "\x18"=>"\\x18", "\x19"=>"\\x19", "\x1A"=>"\\x1a",   "\e"=>"\\x1b",
      "\x1C"=>"\\x1c", "\x1D"=>"\\x1d", "\x1E"=>"\\x1e", "\x1F"=>"\\x1f",
         " "=>    " ",    "!"=>    "!",   "\""=> "\\\"",    "#"=>    "#",
         "$"=>    "$",    "%"=>    "%",    "&"=>    "&",    "'"=>    "'",
         "("=>    "(",    ")"=>    ")",    "*"=>    "*",    "+"=>    "+",
         ","=>    ",",    "-"=>    "-",    "."=>    ".",    "/"=>    "/",
         "0"=>    "0",    "1"=>    "1",    "2"=>    "2",    "3"=>    "3",
         "4"=>    "4",    "5"=>    "5",    "6"=>    "6",    "7"=>    "7",
         "8"=>    "8",    "9"=>    "9",    ":"=>    ":",    ";"=>    ";",
         "<"=>    "<",    "="=>    "=",    ">"=>    ">",    "?"=>    "?",
         "@"=>    "@",    "A"=>    "A",    "B"=>    "B",    "C"=>    "C",
         "D"=>    "D",    "E"=>    "E",    "F"=>    "F",    "G"=>    "G",
         "H"=>    "H",    "I"=>    "I",    "J"=>    "J",    "K"=>    "K",
         "L"=>    "L",    "M"=>    "M",    "N"=>    "N",    "O"=>    "O",
         "P"=>    "P",    "Q"=>    "Q",    "R"=>    "R",    "S"=>    "S",
         "T"=>    "T",    "U"=>    "U",    "V"=>    "V",    "W"=>    "W",
         "X"=>    "X",    "Y"=>    "Y",    "Z"=>    "Z",    "["=>    "[",
        "\\"=> "\\\\",    "]"=>    "]",    "^"=>    "^",    "_"=>    "_",
         "`"=>    "`",    "a"=>    "a",    "b"=>    "b",    "c"=>    "c",
         "d"=>    "d",    "e"=>    "e",    "f"=>    "f",    "g"=>    "g",
         "h"=>    "h",    "i"=>    "i",    "j"=>    "j",    "k"=>    "k",
         "l"=>    "l",    "m"=>    "m",    "n"=>    "n",    "o"=>    "o",
         "p"=>    "p",    "q"=>    "q",    "r"=>    "r",    "s"=>    "s",
         "t"=>    "t",    "u"=>    "u",    "v"=>    "v",    "w"=>    "w",
         "x"=>    "x",    "y"=>    "y",    "z"=>    "z",    "{"=>    "{",
         "|"=>    "|",    "}"=>    "}",    "~"=>    "~", "\x7F"=>"\\x7f",
      "\x80"=>"\\x80", "\x81"=>"\\x81", "\x82"=>"\\x82", "\x83"=>"\\x83",
      "\x84"=>"\\x84", "\x85"=>"\\x85", "\x86"=>"\\x86", "\x87"=>"\\x87",
      "\x88"=>"\\x88", "\x89"=>"\\x89", "\x8A"=>"\\x8a", "\x8B"=>"\\x8b",
      "\x8C"=>"\\x8c", "\x8D"=>"\\x8d", "\x8E"=>"\\x8e", "\x8F"=>"\\x8f",
      "\x90"=>"\\x90", "\x91"=>"\\x91", "\x92"=>"\\x92", "\x93"=>"\\x93",
      "\x94"=>"\\x94", "\x95"=>"\\x95", "\x96"=>"\\x96", "\x97"=>"\\x97",
      "\x98"=>"\\x98", "\x99"=>"\\x99", "\x9A"=>"\\x9a", "\x9B"=>"\\x9b",
      "\x9C"=>"\\x9c", "\x9D"=>"\\x9d", "\x9E"=>"\\x9e", "\x9F"=>"\\x9f",
      "\xA0"=>"\\xa0", "\xA1"=>"\\xa1", "\xA2"=>"\\xa2", "\xA3"=>"\\xa3",
      "\xA4"=>"\\xa4", "\xA5"=>"\\xa5", "\xA6"=>"\\xa6", "\xA7"=>"\\xa7",
      "\xA8"=>"\\xa8", "\xA9"=>"\\xa9", "\xAA"=>"\\xaa", "\xAB"=>"\\xab",
      "\xAC"=>"\\xac", "\xAD"=>"\\xad", "\xAE"=>"\\xae", "\xAF"=>"\\xaf",
      "\xB0"=>"\\xb0", "\xB1"=>"\\xb1", "\xB2"=>"\\xb2", "\xB3"=>"\\xb3",
      "\xB4"=>"\\xb4", "\xB5"=>"\\xb5", "\xB6"=>"\\xb6", "\xB7"=>"\\xb7",
      "\xB8"=>"\\xb8", "\xB9"=>"\\xb9", "\xBA"=>"\\xba", "\xBB"=>"\\xbb",
      "\xBC"=>"\\xbc", "\xBD"=>"\\xbd", "\xBE"=>"\\xbe", "\xBF"=>"\\xbf",
      "\xC0"=>"\\xc0", "\xC1"=>"\\xc1", "\xC2"=>"\\xc2", "\xC3"=>"\\xc3",
      "\xC4"=>"\\xc4", "\xC5"=>"\\xc5", "\xC6"=>"\\xc6", "\xC7"=>"\\xc7",
      "\xC8"=>"\\xc8", "\xC9"=>"\\xc9", "\xCA"=>"\\xca", "\xCB"=>"\\xcb",
      "\xCC"=>"\\xcc", "\xCD"=>"\\xcd", "\xCE"=>"\\xce", "\xCF"=>"\\xcf",
      "\xD0"=>"\\xd0", "\xD1"=>"\\xd1", "\xD2"=>"\\xd2", "\xD3"=>"\\xd3",
      "\xD4"=>"\\xd4", "\xD5"=>"\\xd5", "\xD6"=>"\\xd6", "\xD7"=>"\\xd7",
      "\xD8"=>"\\xd8", "\xD9"=>"\\xd9", "\xDA"=>"\\xda", "\xDB"=>"\\xdb",
      "\xDC"=>"\\xdc", "\xDD"=>"\\xdd", "\xDE"=>"\\xde", "\xDF"=>"\\xdf",
      "\xE0"=>"\\xe0", "\xE1"=>"\\xe1", "\xE2"=>"\\xe2", "\xE3"=>"\\xe3",
      "\xE4"=>"\\xe4", "\xE5"=>"\\xe5", "\xE6"=>"\\xe6", "\xE7"=>"\\xe7",
      "\xE8"=>"\\xe8", "\xE9"=>"\\xe9", "\xEA"=>"\\xea", "\xEB"=>"\\xeb",
      "\xEC"=>"\\xec", "\xED"=>"\\xed", "\xEE"=>"\\xee", "\xEF"=>"\\xef",
      "\xF0"=>"\\xf0", "\xF1"=>"\\xf1", "\xF2"=>"\\xf2", "\xF3"=>"\\xf3",
      "\xF4"=>"\\xf4", "\xF5"=>"\\xf5", "\xF6"=>"\\xf6", "\xF7"=>"\\xf7",
      "\xF8"=>"\\xf8", "\xF9"=>"\\xf9", "\xFA"=>"\\xfa", "\xFB"=>"\\xfb",
      "\xFC"=>"\\xfc", "\xFD"=>"\\xfd", "\xFE"=>"\\xfe", "\xFF"=>"\\xff",
  }.freeze
  private_constant :RString2CStr
end

unless defined? ''.b
  class String
    def b
      return dup.force_encoding 'binary'
    end
  end
end