chelsy 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/.yardopts +1 -0
- data/README.md +38 -6
- data/chelsy.gemspec +12 -11
- data/lib/chelsy/ast.rb +922 -91
- data/lib/chelsy/syntax.rb +23 -10
- data/lib/chelsy/translator.rb +562 -43
- data/lib/chelsy/version.rb +1 -1
- data/sample/hello_chelsy.rb +1 -2
- data/sample/temperature.c +17 -0
- data/sample/temperature.rb +39 -0
- metadata +21 -4
    
        data/lib/chelsy/translator.rb
    CHANGED
    
    | @@ -5,9 +5,9 @@ module Chelsy | |
| 5 5 |  | 
| 6 6 | 
             
                DEFAULT_INDENT_STRING = '    '.freeze
         | 
| 7 7 |  | 
| 8 | 
            -
                def initialize()
         | 
| 9 | 
            -
                  @indent_string =  | 
| 10 | 
            -
                  @indent_level =  | 
| 8 | 
            +
                def initialize(indent_string: DEFAULT_INDENT_STRING, indent_level: 0)
         | 
| 9 | 
            +
                  @indent_string = indent_string
         | 
| 10 | 
            +
                  @indent_level = indent_level
         | 
| 11 11 | 
             
                end
         | 
| 12 12 |  | 
| 13 13 | 
             
                def translate(node)
         | 
| @@ -41,8 +41,28 @@ module Chelsy | |
| 41 41 | 
             
                  case node
         | 
| 42 42 | 
             
                  when String
         | 
| 43 43 | 
             
                    node.to_s
         | 
| 44 | 
            +
                  when Comment::Multi
         | 
| 45 | 
            +
                    translate_comment_multi(node)
         | 
| 46 | 
            +
                  when Comment::Single
         | 
| 47 | 
            +
                    translate_comment_single(node)
         | 
| 44 48 | 
             
                  when Directive::Include
         | 
| 45 49 | 
             
                    translate_include(node)
         | 
| 50 | 
            +
                  when Directive::Define
         | 
| 51 | 
            +
                    translate_define(node)
         | 
| 52 | 
            +
                  when Directive::Undef
         | 
| 53 | 
            +
                    translate_undef(node)
         | 
| 54 | 
            +
                  when Directive::If
         | 
| 55 | 
            +
                    translate_if_directive(node)
         | 
| 56 | 
            +
                  when Directive::ElseIf
         | 
| 57 | 
            +
                    translate_elif_directive(node)
         | 
| 58 | 
            +
                  when Directive::Else
         | 
| 59 | 
            +
                    translate_else_directive(node)
         | 
| 60 | 
            +
                  when Directive::EndIf
         | 
| 61 | 
            +
                    translate_endif_directive(node)
         | 
| 62 | 
            +
                  when Directive::Line
         | 
| 63 | 
            +
                    translate_line_directive(node)
         | 
| 64 | 
            +
                  when Directive::Pragma
         | 
| 65 | 
            +
                    translate_pragma_directive(node)
         | 
| 46 66 | 
             
                  else
         | 
| 47 67 | 
             
                    raise ArgumentError, "Unrecognized AST fragment: #{node.inspect}"
         | 
| 48 68 | 
             
                  end
         | 
| @@ -63,25 +83,56 @@ module Chelsy | |
| 63 83 | 
             
                    translate_integral(node)
         | 
| 64 84 | 
             
                  when Constant::String
         | 
| 65 85 | 
             
                    translate_string(node)
         | 
| 66 | 
            -
                  when  | 
| 67 | 
            -
                     | 
| 86 | 
            +
                  when Operator::Unary
         | 
| 87 | 
            +
                    translate_unary_operator(node)
         | 
| 88 | 
            +
                  when Operator::Binary
         | 
| 89 | 
            +
                    translate_binary_operator(node)
         | 
| 90 | 
            +
                  when Operator::Conditional
         | 
| 91 | 
            +
                    translate_ternary_conditional(node)
         | 
| 68 92 |  | 
| 69 93 | 
             
                  # Statements
         | 
| 70 94 | 
             
                  when EmptyStmt
         | 
| 71 95 | 
             
                    translate_empty_stmt(node)
         | 
| 72 96 | 
             
                  when ExprStmt
         | 
| 73 97 | 
             
                    translate_expr_stmt(node)
         | 
| 98 | 
            +
                  when If
         | 
| 99 | 
            +
                    translate_if(node)
         | 
| 100 | 
            +
                  when Switch
         | 
| 101 | 
            +
                    translate_switch(node)
         | 
| 102 | 
            +
                  when While
         | 
| 103 | 
            +
                    translate_while(node)
         | 
| 104 | 
            +
                  when DoWhile
         | 
| 105 | 
            +
                    translate_do_while(node)
         | 
| 106 | 
            +
                  when For
         | 
| 107 | 
            +
                    translate_for(node)
         | 
| 108 | 
            +
                  when Break
         | 
| 109 | 
            +
                    translate_break(node)
         | 
| 110 | 
            +
                  when Continue
         | 
| 111 | 
            +
                    translate_continue(node)
         | 
| 112 | 
            +
                  when Case
         | 
| 113 | 
            +
                    translate_case(node)
         | 
| 114 | 
            +
                  when Labeled
         | 
| 115 | 
            +
                    translate_labeled(node)
         | 
| 116 | 
            +
                  when Goto
         | 
| 117 | 
            +
                    translate_goto(node)
         | 
| 74 118 | 
             
                  when Return
         | 
| 75 119 | 
             
                    translate_return(node)
         | 
| 76 120 | 
             
                  when Block
         | 
| 77 121 | 
             
                    translate_block(node)
         | 
| 78 122 |  | 
| 79 123 | 
             
                  # Definition
         | 
| 124 | 
            +
                  when Declaration, Typedef
         | 
| 125 | 
            +
                    translate_declaration(node)
         | 
| 126 | 
            +
                  when BitField
         | 
| 127 | 
            +
                    translate_bit_field(node)
         | 
| 80 128 | 
             
                  when Function
         | 
| 81 129 | 
             
                    translate_function(node)
         | 
| 82 130 | 
             
                  when Param
         | 
| 83 | 
            -
                     | 
| 84 | 
            -
             | 
| 131 | 
            +
                    translate_param(node)
         | 
| 132 | 
            +
                  when Initializer
         | 
| 133 | 
            +
                    translate_initializer(node)
         | 
| 134 | 
            +
                  when InitializerList
         | 
| 135 | 
            +
                    translate_initializer_list(node)
         | 
| 85 136 | 
             
                  else
         | 
| 86 137 | 
             
                    raise ArgumentError, "Unrecognized AST element: #{node.inspect}"
         | 
| 87 138 | 
             
                  end
         | 
| @@ -99,7 +150,13 @@ module Chelsy | |
| 99 150 | 
             
                end
         | 
| 100 151 |  | 
| 101 152 | 
             
                def translate_document(node)
         | 
| 102 | 
            -
                  node.map {|nd| translate(nd) } | 
| 153 | 
            +
                  node.map {|nd| translate(nd) }
         | 
| 154 | 
            +
                  .join("\n\n")
         | 
| 155 | 
            +
                  .tap do |src|
         | 
| 156 | 
            +
                    # Document's fragments and body should be separated by empty line for
         | 
| 157 | 
            +
                    # source code readability.
         | 
| 158 | 
            +
                    src.insert(0, "\n") unless src.empty? || node.fragments.empty?
         | 
| 159 | 
            +
                  end
         | 
| 103 160 | 
             
                end
         | 
| 104 161 |  | 
| 105 162 | 
             
                def translate_ident(node)
         | 
| @@ -114,28 +171,100 @@ module Chelsy | |
| 114 171 |  | 
| 115 172 | 
             
                def translate_typed_name(ty, name=nil)
         | 
| 116 173 | 
             
                  case ty
         | 
| 174 | 
            +
                  when Type::Pointer
         | 
| 175 | 
            +
                    translate_pointer_type(ty, name)
         | 
| 176 | 
            +
                  when Type::Array
         | 
| 177 | 
            +
                    translate_array_type(ty, name)
         | 
| 178 | 
            +
                  when Type::Function
         | 
| 179 | 
            +
                    translate_function_type(ty, name)
         | 
| 180 | 
            +
                  when Type::Struct
         | 
| 181 | 
            +
                    translate_struct_type(ty, name)
         | 
| 182 | 
            +
                  when Type::Union
         | 
| 183 | 
            +
                    translate_union_type(ty, name)
         | 
| 184 | 
            +
                  when Type::Enum
         | 
| 185 | 
            +
                    translate_enum_type(ty, name)
         | 
| 117 186 | 
             
                  when Type::Derived
         | 
| 118 | 
            -
                    # TODO
         | 
| 119 187 | 
             
                    raise NotImplementedError
         | 
| 120 188 | 
             
                  else
         | 
| 121 | 
            -
                    translate_primitive_type(ty) | 
| 122 | 
            -
             | 
| 123 | 
            -
             | 
| 189 | 
            +
                    translate_primitive_type(ty, name)
         | 
| 190 | 
            +
                  end
         | 
| 191 | 
            +
                  .tap do |src|
         | 
| 192 | 
            +
                    src.strip!
         | 
| 193 | 
            +
                  end
         | 
| 194 | 
            +
                end
         | 
| 195 | 
            +
             | 
| 196 | 
            +
                def translate_pointer_type(ty, name=nil)
         | 
| 197 | 
            +
                  # qualifiers
         | 
| 198 | 
            +
                  src = ''.tap do |qualifier|
         | 
| 199 | 
            +
                    qualifier << '*'
         | 
| 200 | 
            +
                    qualifier << 'const '    if ty.const?
         | 
| 201 | 
            +
                    qualifier << 'volatile ' if ty.volatile?
         | 
| 202 | 
            +
                    qualifier << 'restrict ' if ty.restrict?
         | 
| 203 | 
            +
                  end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                  # name
         | 
| 206 | 
            +
                  src << name.to_s
         | 
| 207 | 
            +
             | 
| 208 | 
            +
                  # parenthesize if needed
         | 
| 209 | 
            +
                  case ty.pointee
         | 
| 210 | 
            +
                  when Type::Function, Type::Array
         | 
| 211 | 
            +
                    translate_typed_name(ty.pointee, "(#{src})")
         | 
| 212 | 
            +
                  else
         | 
| 213 | 
            +
                    translate_typed_name(ty.pointee, src)
         | 
| 214 | 
            +
                  end
         | 
| 215 | 
            +
                end
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                def translate_array_type(ty, name=nil)
         | 
| 218 | 
            +
                  src = name.to_s.tap do |subscript|
         | 
| 219 | 
            +
                    subscript << '['
         | 
| 220 | 
            +
                    subscript << 'const ' if ty.const?
         | 
| 221 | 
            +
                    subscript << 'volatile ' if ty.volatile?
         | 
| 222 | 
            +
                    subscript << 'static ' if ty.static?
         | 
| 223 | 
            +
                    subscript << translate(ty.size) if ty.size
         | 
| 224 | 
            +
                    subscript << ']'
         | 
| 225 | 
            +
                  end
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                  translate_typed_name(coerce_func_ptr(ty.element_type), src)
         | 
| 228 | 
            +
                end
         | 
| 229 | 
            +
             | 
| 230 | 
            +
                def translate_function_type(ty, name=nil)
         | 
| 231 | 
            +
                  src = name.to_s.tap do |params|
         | 
| 232 | 
            +
                    params << '('
         | 
| 233 | 
            +
                    params << ty.params.map {|p| translate(coerce_func_ptr(p)) }.join(', ')
         | 
| 234 | 
            +
                    params << ')'
         | 
| 124 235 | 
             
                  end
         | 
| 236 | 
            +
             | 
| 237 | 
            +
                  translate_typed_name(coerce_func_ptr(ty.return_type), src)
         | 
| 238 | 
            +
                end
         | 
| 239 | 
            +
             | 
| 240 | 
            +
                def translate_struct_type(ty, name=nil)
         | 
| 241 | 
            +
                  translate_taggable_type_members(ty, name)
         | 
| 125 242 | 
             
                end
         | 
| 126 243 |  | 
| 127 | 
            -
                def  | 
| 244 | 
            +
                def translate_union_type(ty, name=nil)
         | 
| 245 | 
            +
                  translate_taggable_type_members(ty, name)
         | 
| 246 | 
            +
                end
         | 
| 247 | 
            +
             | 
| 248 | 
            +
                def translate_enum_type(ty, name=nil)
         | 
| 249 | 
            +
                  translate_taggable_type_members(ty, name)
         | 
| 250 | 
            +
                end
         | 
| 251 | 
            +
             | 
| 252 | 
            +
                def translate_primitive_type(ty, name=nil)
         | 
| 253 | 
            +
                  src = case ty
         | 
| 254 | 
            +
                        when :void; 'void'
         | 
| 255 | 
            +
                        when Type::Integral
         | 
| 256 | 
            +
                          translate_integral_type(ty)
         | 
| 257 | 
            +
                        else
         | 
| 258 | 
            +
                          translate_numeric_type(ty)
         | 
| 259 | 
            +
                        end
         | 
| 128 260 | 
             
                  case ty
         | 
| 129 | 
            -
                  when  | 
| 130 | 
            -
                  when Type::Char; 'char'
         | 
| 131 | 
            -
                  when Type::Short; 'short'
         | 
| 132 | 
            -
                  when Type::Integral
         | 
| 133 | 
            -
                    translate_integral_type(ty)
         | 
| 134 | 
            -
                  end.tap do |src|
         | 
| 135 | 
            -
                    # qualifiers
         | 
| 261 | 
            +
                  when Type::Base;
         | 
| 136 262 | 
             
                    src.insert(0, 'const ') if ty.const?
         | 
| 137 263 | 
             
                    src.insert(0, 'volatile ') if ty.volatile?
         | 
| 138 | 
            -
             | 
| 264 | 
            +
                  end
         | 
| 265 | 
            +
             | 
| 266 | 
            +
                  src.tap do |src|
         | 
| 267 | 
            +
                    src << " #{name}" if name
         | 
| 139 268 | 
             
                  end
         | 
| 140 269 | 
             
                end
         | 
| 141 270 |  | 
| @@ -151,6 +280,21 @@ module Chelsy | |
| 151 280 | 
             
                  end
         | 
| 152 281 | 
             
                end
         | 
| 153 282 |  | 
| 283 | 
            +
                def translate_numeric_type(ty)
         | 
| 284 | 
            +
                  case ty
         | 
| 285 | 
            +
                  when Type::Bool;              '_Bool'
         | 
| 286 | 
            +
                  when Type::Float;             'float'
         | 
| 287 | 
            +
                  when Type::Double;            'double'
         | 
| 288 | 
            +
                  when Type::LongDouble;        'long double'
         | 
| 289 | 
            +
                  when Type::Complex;           '_Complex'
         | 
| 290 | 
            +
                  when Type::FloatComplex;      'float _Complex'
         | 
| 291 | 
            +
                  when Type::DoubleComplex;     'double _Complex'
         | 
| 292 | 
            +
                  when Type::LongDoubleComplex; 'long double _Complex'
         | 
| 293 | 
            +
                  else
         | 
| 294 | 
            +
                    raise NotImplementedError
         | 
| 295 | 
            +
                  end
         | 
| 296 | 
            +
                end
         | 
| 297 | 
            +
             | 
| 154 298 | 
             
                # = Expressions
         | 
| 155 299 |  | 
| 156 300 | 
             
                def translate_integral(node)
         | 
| @@ -165,37 +309,266 @@ module Chelsy | |
| 165 309 | 
             
                  end
         | 
| 166 310 | 
             
                end
         | 
| 167 311 |  | 
| 312 | 
            +
                def translate_unary_operator(node)
         | 
| 313 | 
            +
                  case node
         | 
| 314 | 
            +
                  when Operator::Subscription
         | 
| 315 | 
            +
                    translate_subscription(node)
         | 
| 316 | 
            +
                  when Operator::Call
         | 
| 317 | 
            +
                    translate_function_call(node)
         | 
| 318 | 
            +
                  when Operator::Access
         | 
| 319 | 
            +
                    translate_member_access(node)
         | 
| 320 | 
            +
                  when Operator::Cast
         | 
| 321 | 
            +
                    translate_type_cast(node)
         | 
| 322 | 
            +
                  when Operator::SizeOf
         | 
| 323 | 
            +
                    translate_size_of(node)
         | 
| 324 | 
            +
                  when Operator::Postfix
         | 
| 325 | 
            +
                    translate_postfix_operator(node)
         | 
| 326 | 
            +
                  when Operator::Prefix
         | 
| 327 | 
            +
                    translate_prefix_operator(node)
         | 
| 328 | 
            +
                  when Operator::Defined
         | 
| 329 | 
            +
                    translate_defined_operator(node)
         | 
| 330 | 
            +
                  else
         | 
| 331 | 
            +
                    raise NotImplementedError, "Unrecognized unary operator: #{node.inspect}"
         | 
| 332 | 
            +
                  end
         | 
| 333 | 
            +
                end
         | 
| 334 | 
            +
             | 
| 335 | 
            +
                def translate_subscription(node)
         | 
| 336 | 
            +
                  subscriptee = expr(node.subscriptee, node)
         | 
| 337 | 
            +
                  index = translate(node.index)
         | 
| 338 | 
            +
             | 
| 339 | 
            +
                  "#{subscriptee}[#{index}]"
         | 
| 340 | 
            +
                end
         | 
| 341 | 
            +
             | 
| 168 342 | 
             
                def translate_function_call(node)
         | 
| 169 | 
            -
                  callee = expr(node.callee)
         | 
| 170 | 
            -
                  args = node.args.map {|a|  | 
| 343 | 
            +
                  callee = expr(node.callee, node)
         | 
| 344 | 
            +
                  args = node.args.map {|a| translate(a) }.join(', ')
         | 
| 171 345 |  | 
| 172 346 | 
             
                  "#{callee}(#{args})"
         | 
| 173 347 | 
             
                end
         | 
| 174 348 |  | 
| 349 | 
            +
                def translate_member_access(node)
         | 
| 350 | 
            +
                  object = expr(node.object, node)
         | 
| 351 | 
            +
                  name = translate(node.name)
         | 
| 352 | 
            +
             | 
| 353 | 
            +
                  "#{object}#{node.class.operator}#{name}"
         | 
| 354 | 
            +
                end
         | 
| 355 | 
            +
             | 
| 356 | 
            +
                def translate_prefix_operator(node)
         | 
| 357 | 
            +
                  operand = expr(node.operand, node)
         | 
| 358 | 
            +
                  "#{node.class.operator}#{operand}"
         | 
| 359 | 
            +
                end
         | 
| 360 | 
            +
             | 
| 361 | 
            +
                def translate_postfix_operator(node)
         | 
| 362 | 
            +
                  operand = expr(node.operand, node)
         | 
| 363 | 
            +
                  "#{operand}#{node.class.operator}"
         | 
| 364 | 
            +
                end
         | 
| 365 | 
            +
             | 
| 366 | 
            +
                def translate_type_cast(node)
         | 
| 367 | 
            +
                  operand = expr(node.operand, node)
         | 
| 368 | 
            +
                  "(#{translate node.type})#{operand}"
         | 
| 369 | 
            +
                end
         | 
| 370 | 
            +
             | 
| 371 | 
            +
                def translate_size_of(node)
         | 
| 372 | 
            +
                  operand = translate(node.operand)
         | 
| 373 | 
            +
                  "sizeof(#{operand})"
         | 
| 374 | 
            +
                end
         | 
| 375 | 
            +
             | 
| 376 | 
            +
                def translate_defined_operator(node)
         | 
| 377 | 
            +
                  operand = translate(node.operand)
         | 
| 378 | 
            +
                  "defined #{operand}"
         | 
| 379 | 
            +
                end
         | 
| 380 | 
            +
             | 
| 381 | 
            +
                def translate_binary_operator(node)
         | 
| 382 | 
            +
                  lhs = expr(node.lhs, node)
         | 
| 383 | 
            +
                  rhs = expr(node.rhs, node)
         | 
| 384 | 
            +
             | 
| 385 | 
            +
                  case node
         | 
| 386 | 
            +
                  when Operator::Comma
         | 
| 387 | 
            +
                    "#{lhs}#{node.class.operator} #{rhs}"
         | 
| 388 | 
            +
                  else
         | 
| 389 | 
            +
                    "#{lhs} #{node.class.operator} #{rhs}"
         | 
| 390 | 
            +
                  end
         | 
| 391 | 
            +
                end
         | 
| 392 | 
            +
             | 
| 393 | 
            +
                def translate_ternary_conditional(node)
         | 
| 394 | 
            +
                  condition_expr = expr(node.condition, node)
         | 
| 395 | 
            +
             | 
| 396 | 
            +
                  # Expression between `?` and `:` must be parenthesized.
         | 
| 397 | 
            +
                  then_expr = case node.then
         | 
| 398 | 
            +
                              when Operator::Binary, Operator::Conditional
         | 
| 399 | 
            +
                                "(#{translate(node.then)})"
         | 
| 400 | 
            +
                              else
         | 
| 401 | 
            +
                                expr(node.then, node)
         | 
| 402 | 
            +
                              end
         | 
| 403 | 
            +
                  else_expr = expr(node.else, node)
         | 
| 404 | 
            +
             | 
| 405 | 
            +
                  "#{condition_expr} ? #{then_expr} : #{else_expr}"
         | 
| 406 | 
            +
                end
         | 
| 407 | 
            +
             | 
| 175 408 | 
             
                # = Statements
         | 
| 176 409 |  | 
| 177 410 | 
             
                def translate_empty_stmt(node)
         | 
| 178 | 
            -
                   | 
| 411 | 
            +
                  ''
         | 
| 179 412 | 
             
                end
         | 
| 180 413 |  | 
| 181 414 | 
             
                def translate_expr_stmt(node)
         | 
| 182 | 
            -
                   | 
| 415 | 
            +
                  translate(node.expr)
         | 
| 416 | 
            +
                end
         | 
| 417 | 
            +
             | 
| 418 | 
            +
                def translate_if(node)
         | 
| 419 | 
            +
                  "if (#{translate node.condition}) #{translate node.then}".tap do |src|
         | 
| 420 | 
            +
                    src << " else #{translate node.else}" if node.else
         | 
| 421 | 
            +
                  end
         | 
| 422 | 
            +
                end
         | 
| 423 | 
            +
             | 
| 424 | 
            +
                def translate_switch(node)
         | 
| 425 | 
            +
                  "switch (#{translate node.expr}) #{translate node.stmt}"
         | 
| 426 | 
            +
                end
         | 
| 427 | 
            +
             | 
| 428 | 
            +
                def translate_while(node)
         | 
| 429 | 
            +
                  "while (#{translate node.condition}) #{translate node.body}"
         | 
| 430 | 
            +
                end
         | 
| 431 | 
            +
             | 
| 432 | 
            +
                def translate_do_while(node)
         | 
| 433 | 
            +
                  "do #{translate node.body} while (#{translate node.condition})"
         | 
| 434 | 
            +
                end
         | 
| 435 | 
            +
             | 
| 436 | 
            +
                def translate_for(node)
         | 
| 437 | 
            +
                  init = node.init ? translate(node.init) : ''
         | 
| 438 | 
            +
                  cond = node.condition ? ' ' + translate(node.condition) : ''
         | 
| 439 | 
            +
                  loop_expr = node.loop ? ' ' + translate(node.loop) : ''
         | 
| 440 | 
            +
             | 
| 441 | 
            +
                  "for (#{init};#{cond};#{loop_expr}) #{translate node.body}"
         | 
| 442 | 
            +
                end
         | 
| 443 | 
            +
             | 
| 444 | 
            +
                def translate_break(node); 'break' end
         | 
| 445 | 
            +
                def translate_continue(node); 'continue' end
         | 
| 446 | 
            +
             | 
| 447 | 
            +
                def translate_goto(node)
         | 
| 448 | 
            +
                  "goto #{node.label}"
         | 
| 449 | 
            +
                end
         | 
| 450 | 
            +
             | 
| 451 | 
            +
                # We need labeled statement to indent differently.
         | 
| 452 | 
            +
                def translate_case(node)
         | 
| 453 | 
            +
                  [
         | 
| 454 | 
            +
                    "case #{translate(node.expr)}",
         | 
| 455 | 
            +
                    translate(node.stmt),
         | 
| 456 | 
            +
                  ]
         | 
| 457 | 
            +
                end
         | 
| 458 | 
            +
             | 
| 459 | 
            +
                def translate_labeled(node)
         | 
| 460 | 
            +
                  [
         | 
| 461 | 
            +
                    node.label.to_s,
         | 
| 462 | 
            +
                    translate(node.stmt),
         | 
| 463 | 
            +
                  ]
         | 
| 183 464 | 
             
                end
         | 
| 184 465 |  | 
| 185 466 | 
             
                def translate_return(node)
         | 
| 186 467 | 
             
                  if node.expr
         | 
| 187 | 
            -
                     | 
| 468 | 
            +
                    'return ' << translate(node.expr)
         | 
| 188 469 | 
             
                  else
         | 
| 189 | 
            -
                     | 
| 470 | 
            +
                    'return'
         | 
| 190 471 | 
             
                  end
         | 
| 191 472 | 
             
                end
         | 
| 192 473 |  | 
| 193 474 | 
             
                def translate_block(node)
         | 
| 194 | 
            -
                   | 
| 195 | 
            -
             | 
| 196 | 
            -
             | 
| 475 | 
            +
                  translate_stmts_with_indent(node)
         | 
| 476 | 
            +
                end
         | 
| 477 | 
            +
             | 
| 478 | 
            +
                # = Declaration
         | 
| 479 | 
            +
                def translate_declaration(node)
         | 
| 480 | 
            +
                  [
         | 
| 481 | 
            +
                    node.storage.to_s,
         | 
| 482 | 
            +
                    translate_typed_name(node.type, node.name),
         | 
| 483 | 
            +
                  ]
         | 
| 484 | 
            +
                  .tap {|src|
         | 
| 485 | 
            +
                    unless node.init.nil?
         | 
| 486 | 
            +
                      src << '='
         | 
| 487 | 
            +
                      src << translate(node.init)
         | 
| 488 | 
            +
                    end
         | 
| 489 | 
            +
                  }
         | 
| 490 | 
            +
                  .join(' ')
         | 
| 491 | 
            +
                  .strip
         | 
| 492 | 
            +
                end
         | 
| 493 | 
            +
             | 
| 494 | 
            +
                def translate_designator(node)
         | 
| 495 | 
            +
                  case node
         | 
| 496 | 
            +
                  when IndexDesignator
         | 
| 497 | 
            +
                    "[#{node.index}]"
         | 
| 498 | 
            +
                  when MemberDesignator
         | 
| 499 | 
            +
                    ".#{node.name}"
         | 
| 500 | 
            +
                  else
         | 
| 501 | 
            +
                    raise NotImplementedError, 'designator must be Index or Member'
         | 
| 502 | 
            +
                  end
         | 
| 503 | 
            +
                end
         | 
| 504 | 
            +
             | 
| 505 | 
            +
                def translate_initializer(node)
         | 
| 506 | 
            +
                  if node.designator
         | 
| 507 | 
            +
                    [
         | 
| 508 | 
            +
                      translate_designator(node.designator),
         | 
| 509 | 
            +
                      '=',
         | 
| 510 | 
            +
                      translate(node.value),
         | 
| 511 | 
            +
                    ]
         | 
| 512 | 
            +
                    .join(' ')
         | 
| 513 | 
            +
                  else
         | 
| 514 | 
            +
                    translate(node.value)
         | 
| 515 | 
            +
                  end
         | 
| 516 | 
            +
                end
         | 
| 517 | 
            +
             | 
| 518 | 
            +
                def translate_initializer_list(node)
         | 
| 519 | 
            +
                  node
         | 
| 520 | 
            +
                  .map {|m| translate(m)}
         | 
| 521 | 
            +
                  .join(', ')
         | 
| 522 | 
            +
                  .insert( 0, '{ ')
         | 
| 523 | 
            +
                  .insert(-1, ' }')
         | 
| 524 | 
            +
                end
         | 
| 197 525 |  | 
| 198 | 
            -
             | 
| 526 | 
            +
                def translate_bit_field(node)
         | 
| 527 | 
            +
                  if node.declaration
         | 
| 528 | 
            +
                    "#{translate node.declaration} : #{translate node.bits}"
         | 
| 529 | 
            +
                  else
         | 
| 530 | 
            +
                    ": #{translate node.bits}"
         | 
| 531 | 
            +
                  end
         | 
| 532 | 
            +
                end
         | 
| 533 | 
            +
             | 
| 534 | 
            +
                # = Function
         | 
| 535 | 
            +
                def translate_function(node)
         | 
| 536 | 
            +
                  params = node.params.map {|p| translate(p) }.join(', ')
         | 
| 537 | 
            +
             | 
| 538 | 
            +
                  [
         | 
| 539 | 
            +
                    node.storage.to_s,
         | 
| 540 | 
            +
                    translate(node.return_type),
         | 
| 541 | 
            +
                    "#{translate node.name}(#{params})",
         | 
| 542 | 
            +
                    translate(node.body),
         | 
| 543 | 
            +
                  ]
         | 
| 544 | 
            +
                  .join(' ')
         | 
| 545 | 
            +
                  .strip
         | 
| 546 | 
            +
                end
         | 
| 547 | 
            +
             | 
| 548 | 
            +
                def translate_param(node)
         | 
| 549 | 
            +
                  ty = coerce_func_ptr(node.type)
         | 
| 550 | 
            +
                  translate_typed_name(ty, node.name)
         | 
| 551 | 
            +
                end
         | 
| 552 | 
            +
             | 
| 553 | 
            +
                # = Comment
         | 
| 554 | 
            +
                def translate_comment_multi(node)
         | 
| 555 | 
            +
                  case node.lines.size
         | 
| 556 | 
            +
                  when 0
         | 
| 557 | 
            +
                    ""
         | 
| 558 | 
            +
                  when 1
         | 
| 559 | 
            +
                    "/* #{node.lines[0]} */"
         | 
| 560 | 
            +
                  else
         | 
| 561 | 
            +
                    src =
         | 
| 562 | 
            +
                      node
         | 
| 563 | 
            +
                        .lines
         | 
| 564 | 
            +
                        .map {|line| "#{indent} * #{line}"}
         | 
| 565 | 
            +
                        .join("\n")
         | 
| 566 | 
            +
                    "/*\n#{src}\n#{indent} */"
         | 
| 567 | 
            +
                  end
         | 
| 568 | 
            +
                end
         | 
| 569 | 
            +
             | 
| 570 | 
            +
                def translate_comment_single(node)
         | 
| 571 | 
            +
                  "// #{node.body}"
         | 
| 199 572 | 
             
                end
         | 
| 200 573 |  | 
| 201 574 | 
             
                # = Directives
         | 
| @@ -207,27 +580,172 @@ module Chelsy | |
| 207 580 | 
             
                  end
         | 
| 208 581 | 
             
                end
         | 
| 209 582 |  | 
| 210 | 
            -
                 | 
| 583 | 
            +
                def translate_define(node)
         | 
| 584 | 
            +
                  "#define #{node.name}".tap do |src|
         | 
| 585 | 
            +
                    if node.params
         | 
| 586 | 
            +
                      src << '('
         | 
| 587 | 
            +
                      src << node.params.map(&:to_s).join(", ")
         | 
| 588 | 
            +
                      src << ')'
         | 
| 589 | 
            +
                    end
         | 
| 211 590 |  | 
| 212 | 
            -
             | 
| 213 | 
            -
             | 
| 214 | 
            -
             | 
| 591 | 
            +
                    unless node.replacement.empty?
         | 
| 592 | 
            +
                      src << ' '
         | 
| 593 | 
            +
                      src << node.replacement.to_s
         | 
| 594 | 
            +
                    end
         | 
| 595 | 
            +
                  end
         | 
| 596 | 
            +
                end
         | 
| 597 | 
            +
             | 
| 598 | 
            +
                def translate_undef(node)
         | 
| 599 | 
            +
                  "#undef #{node.name}"
         | 
| 215 600 | 
             
                end
         | 
| 216 601 |  | 
| 217 | 
            -
                def  | 
| 218 | 
            -
                   | 
| 602 | 
            +
                def translate_if_directive(node)
         | 
| 603 | 
            +
                  "#if #{translate node.condition}"
         | 
| 604 | 
            +
                end
         | 
| 605 | 
            +
             | 
| 606 | 
            +
                def translate_elif_directive(node)
         | 
| 607 | 
            +
                  "#elif #{translate node.condition}"
         | 
| 608 | 
            +
                end
         | 
| 609 | 
            +
             | 
| 610 | 
            +
                def translate_else_directive(node); "#else" end
         | 
| 611 | 
            +
             | 
| 612 | 
            +
                def translate_endif_directive(node); "#endif" end
         | 
| 613 | 
            +
             | 
| 614 | 
            +
                def translate_line_directive(node)
         | 
| 615 | 
            +
                  "#line #{node.lineno}".tap do |src|
         | 
| 616 | 
            +
                    src << " \"#{node.filename}\"" if node.filename
         | 
| 617 | 
            +
                  end
         | 
| 618 | 
            +
                end
         | 
| 619 | 
            +
             | 
| 620 | 
            +
                def translate_pragma_directive(node)
         | 
| 621 | 
            +
                  "#pragma #{node.pragma}"
         | 
| 219 622 | 
             
                end
         | 
| 220 623 |  | 
| 221 624 | 
             
                private
         | 
| 222 625 |  | 
| 223 | 
            -
                def indent
         | 
| 224 | 
            -
                   | 
| 626 | 
            +
                def indent(indent_level=nil)
         | 
| 627 | 
            +
                  indent_level = @indent_level if indent_level.nil?
         | 
| 628 | 
            +
                  @indent_string * indent_level
         | 
| 225 629 | 
             
                end
         | 
| 226 630 |  | 
| 227 | 
            -
                #  | 
| 228 | 
            -
                def expr(node)
         | 
| 229 | 
            -
                   | 
| 230 | 
            -
             | 
| 631 | 
            +
                # Parenthesize if `node` has lower precedence than `parent` node.
         | 
| 632 | 
            +
                def expr(node, parent)
         | 
| 633 | 
            +
                  expr = translate(node)
         | 
| 634 | 
            +
             | 
| 635 | 
            +
                  if node.is_a?(Operator::Base) && node.class.precedence < parent.class.precedence
         | 
| 636 | 
            +
                    "(#{expr})"
         | 
| 637 | 
            +
                  else
         | 
| 638 | 
            +
                    expr
         | 
| 639 | 
            +
                  end
         | 
| 640 | 
            +
                end
         | 
| 641 | 
            +
             | 
| 642 | 
            +
                def translate_taggable_type_members(ty, name=nil)
         | 
| 643 | 
            +
                  [].tap do |buffer|
         | 
| 644 | 
            +
                    buffer << 'const ' if ty.const?
         | 
| 645 | 
            +
                    buffer << 'volatile ' if ty.volatile?
         | 
| 646 | 
            +
                    buffer << case ty
         | 
| 647 | 
            +
                              when Type::Struct; 'struct'
         | 
| 648 | 
            +
                              when Type::Union;  'union'
         | 
| 649 | 
            +
                              when Type::Enum;   'enum'
         | 
| 650 | 
            +
                              end
         | 
| 651 | 
            +
                    buffer << ty.tag if ty.tag
         | 
| 652 | 
            +
                    buffer << name if name
         | 
| 653 | 
            +
                  end
         | 
| 654 | 
            +
                  .join(' ')
         | 
| 655 | 
            +
                  .tap do |src|
         | 
| 656 | 
            +
                    if ty.members
         | 
| 657 | 
            +
                      src << ' ' << translate_taggable_members(ty.members)
         | 
| 658 | 
            +
                    end
         | 
| 659 | 
            +
                  end
         | 
| 660 | 
            +
                end
         | 
| 661 | 
            +
             | 
| 662 | 
            +
                def translate_taggable_members(members)
         | 
| 663 | 
            +
                  case members
         | 
| 664 | 
            +
                  when StructOrUnionMemberList
         | 
| 665 | 
            +
                    translate_stmts_with_indent(members)
         | 
| 666 | 
            +
                  when EnumMemberList
         | 
| 667 | 
            +
                    translate_enum_members(members)
         | 
| 668 | 
            +
                  else
         | 
| 669 | 
            +
                    raise "Unrecognized members: #{members.inspect}"
         | 
| 670 | 
            +
                  end
         | 
| 671 | 
            +
                end
         | 
| 672 | 
            +
             | 
| 673 | 
            +
                def translate_enum_members(members)
         | 
| 674 | 
            +
                  @indent_level += 1
         | 
| 675 | 
            +
             | 
| 676 | 
            +
                  lines = members.map do |item|
         | 
| 677 | 
            +
                    case item
         | 
| 678 | 
            +
                    when EnumMember
         | 
| 679 | 
            +
                      if item.init
         | 
| 680 | 
            +
                        "#{translate item.name} = #{translate item.init}"
         | 
| 681 | 
            +
                      else
         | 
| 682 | 
            +
                        "#{translate item.name}"
         | 
| 683 | 
            +
                      end
         | 
| 684 | 
            +
                    when Symbol
         | 
| 685 | 
            +
                      "#{translate item}"
         | 
| 686 | 
            +
                    else
         | 
| 687 | 
            +
                      raise "Unrecognized enum member: #{item.inspect}"
         | 
| 688 | 
            +
                    end
         | 
| 689 | 
            +
                  end
         | 
| 690 | 
            +
             | 
| 691 | 
            +
                  body = lines.map {|line| indent << line }.join(",\n")
         | 
| 692 | 
            +
                  @indent_level -= 1
         | 
| 693 | 
            +
             | 
| 694 | 
            +
                  "{\n#{body}\n#{indent}}"
         | 
| 695 | 
            +
                end
         | 
| 696 | 
            +
             | 
| 697 | 
            +
                def should_terminate_with_semicolon(node)
         | 
| 698 | 
            +
                  case node
         | 
| 699 | 
            +
                  when If
         | 
| 700 | 
            +
                    if node.else
         | 
| 701 | 
            +
                      should_terminate_with_semicolon(node.else)
         | 
| 702 | 
            +
                    else
         | 
| 703 | 
            +
                      should_terminate_with_semicolon(node.then)
         | 
| 704 | 
            +
                    end
         | 
| 705 | 
            +
                  when While, For
         | 
| 706 | 
            +
                    should_terminate_with_semicolon(node.body)
         | 
| 707 | 
            +
                  when Block
         | 
| 708 | 
            +
                    false
         | 
| 709 | 
            +
                  else
         | 
| 710 | 
            +
                    true
         | 
| 711 | 
            +
                  end
         | 
| 712 | 
            +
                end
         | 
| 713 | 
            +
             | 
| 714 | 
            +
                def translate_stmts_with_indent(node)
         | 
| 715 | 
            +
                  @indent_level += 1
         | 
| 716 | 
            +
             | 
| 717 | 
            +
                  lines = node.map do |item|
         | 
| 718 | 
            +
                    src = translate(item)
         | 
| 719 | 
            +
             | 
| 720 | 
            +
                    if Array === src && src.size == 2
         | 
| 721 | 
            +
                      (label, stmt) = *src
         | 
| 722 | 
            +
             | 
| 723 | 
            +
                      src = "#{indent(@indent_level-1)}#{label}:\n"
         | 
| 724 | 
            +
                      src << "#{indent}#{stmt}"
         | 
| 725 | 
            +
                    else
         | 
| 726 | 
            +
                      src.insert 0, indent
         | 
| 727 | 
            +
                    end
         | 
| 728 | 
            +
             | 
| 729 | 
            +
                    # terminate ';' if needed
         | 
| 730 | 
            +
                    src << ';' if should_terminate_with_semicolon(item)
         | 
| 731 | 
            +
                    src
         | 
| 732 | 
            +
                  end
         | 
| 733 | 
            +
             | 
| 734 | 
            +
                  @indent_level -= 1
         | 
| 735 | 
            +
             | 
| 736 | 
            +
                  body = lines.join("\n")
         | 
| 737 | 
            +
             | 
| 738 | 
            +
                  "{\n#{body}\n#{indent}}"
         | 
| 739 | 
            +
                end
         | 
| 740 | 
            +
             | 
| 741 | 
            +
                # In some situation, function type shall be pointer to function type
         | 
| 742 | 
            +
                def coerce_func_ptr(node)
         | 
| 743 | 
            +
                  case node
         | 
| 744 | 
            +
                  when Type::Function
         | 
| 745 | 
            +
                    Type::Pointer.new(node)
         | 
| 746 | 
            +
                  else
         | 
| 747 | 
            +
                    node
         | 
| 748 | 
            +
                  end
         | 
| 231 749 | 
             
                end
         | 
| 232 750 |  | 
| 233 751 | 
             
                def integer_prefix(node)
         | 
| @@ -259,6 +777,7 @@ module Chelsy | |
| 259 777 | 
             
                    suffix
         | 
| 260 778 | 
             
                  end
         | 
| 261 779 | 
             
                end
         | 
| 780 | 
            +
             | 
| 262 781 | 
             
              end
         | 
| 263 782 |  | 
| 264 783 | 
             
            end
         |