chelsy 0.0.6 → 0.0.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4878521c7b523d8c46ebc91d752c23af91616475
4
- data.tar.gz: e74c0550a0a40cc62d3956d2c6379d3c33ceed9c
3
+ metadata.gz: 129bcae8df6bfcf4cfd02feda9b21434f0e14995
4
+ data.tar.gz: 5cffbdf5d8eb95b8818f8787cb57e9600cae90ce
5
5
  SHA512:
6
- metadata.gz: edc3882ef58112153fe6af6817b0caba5dcfc1221d0cb080e164c58873431cca39677ec1b32f6df97271684c5cff35c8e1869b0413cdbf58e7f9c3236d99f7fe
7
- data.tar.gz: 87b5270bd4276f3ec3b5d9009dda2d34cf89c84efe28c2c3d8b17874884e39de0788a07b2828d6d0642b64a9e2f8c182f50ca5a861f543cc7f94b32a6ae7daf7
6
+ metadata.gz: 96b462cba28e4e094d5b7013a6f9ecda4076c25d00a6a4dded2b11e74d365923c50d14f9dd74f477406c709ca08408808f74e1c01539ffe4078eb3f18d9eb172
7
+ data.tar.gz: a2f7ed0df99110425279350a7c7771dd35ad7e77d409019f50877d59f2da95eadc44f9fb7bce76d80aa934de2854358fb9d2b35b47fbd92eccc0287518ede8f2
data/README.md CHANGED
@@ -44,8 +44,8 @@ doc = Document.new
44
44
  doc.fragments << Directive::Include.new("stdio.h", system: true)
45
45
 
46
46
  doc << Function.new(:main, Type::Int.new, [:void]) do |b|
47
- b << Operator::Call.new(:printf, [Constant::String.new("Hello, Chelsy!\n")])
48
- b << Return.new(Constant::Int.new(0))
47
+ b << Operator::Call.new(:printf, ["Hello, Chelsy!\n"])
48
+ b << Return.new(0)
49
49
  end
50
50
 
51
51
  puts Translator.new.translate(doc)
data/lib/chelsy/ast.rb CHANGED
@@ -523,7 +523,7 @@ module Chelsy
523
523
  attr_reader :value
524
524
 
525
525
  def initialize(str, wide: false, **rest)
526
- @value = str.dup.freeze
526
+ @value = immutable_stringify(str)
527
527
  @wide = !!wide
528
528
 
529
529
  super(**rest)
@@ -1145,6 +1145,27 @@ module Chelsy
1145
1145
  end
1146
1146
  end
1147
1147
 
1148
+ # AST node represents a macro invocation with or without arguments.
1149
+ class Macro < Expr
1150
+ attr_reader :name, :args
1151
+
1152
+ # @!attribute [r] name
1153
+ # @return [Symbol] Macro name
1154
+ # @!attribute [r] args
1155
+ # @return [Enumerable] Arguments
1156
+
1157
+ # initialize instance.
1158
+ #
1159
+ # @param [Symbol] name Macro name
1160
+ # @param [Enumerable] args Arguments. `nil` if no arguments supplied.
1161
+ def initialize(name, args=nil, **rest)
1162
+ @name = Syntax::Ident.ensure(name)
1163
+ @args = args.map {|a| Syntax::Expr.ensure(a) } if args
1164
+
1165
+ super **rest
1166
+ end
1167
+ end
1168
+
1148
1169
  # = 6.10 Preprocessing directives
1149
1170
  module Directive
1150
1171
  class Base < Fragment
@@ -1227,7 +1248,7 @@ module Chelsy
1227
1248
  attr_reader :lineno, :filename
1228
1249
 
1229
1250
  def initialize(lineno, filename=nil, **rest)
1230
- @lineno = Syntax::Int.ensure(lineno)
1251
+ @lineno = Syntax::Constant::Int.ensure(lineno)
1231
1252
  @filename = immutable_stringify(filename) if filename
1232
1253
 
1233
1254
  super **rest
@@ -1266,18 +1287,36 @@ end
1266
1287
 
1267
1288
  module Chelsy
1268
1289
  module Syntax
1290
+
1291
+ module Constant
1292
+ Int = Coercer.new(Chelsy::Constant::Int) do |value|
1293
+ Chelsy::Constant::Int.new(value) if ::Integer === value
1294
+ end
1295
+
1296
+ String = Coercer.new(Chelsy::Constant::String) do |value|
1297
+ Chelsy::Constant::String.new(value) if ::String === value
1298
+ end
1299
+ end
1300
+
1269
1301
  TopLevel = Any.new('TopLevel', [Declarative])
1270
1302
  Type = Any.new('TypeSpecifier', [Chelsy::Type::Base, :void])
1271
- Int = Any.new('Int', [::Integer])
1272
1303
  Ident = Any.new('Identifier', [Symbol])
1273
- Expr = Any.new('Expression', [Chelsy::Expr, Syntax::Ident])
1304
+ Expr = Any.new('Expression', [
1305
+ Chelsy::Expr,
1306
+ Syntax::Ident,
1307
+ Syntax::Constant::Int,
1308
+ Syntax::Constant::String,
1309
+ ])
1274
1310
  ExprOrType = Any.new('Expression-Or-Type', [Syntax::Expr, Syntax::Type])
1275
1311
  Fragment = Any.new('Fragment', [Fragment, String])
1276
1312
  Storage = Any.new('Storage-class specifiers', [:typedef, :extern, :static])
1277
1313
  Param = Any.new('Parameter', [Chelsy::Param, :void, :"..."])
1278
1314
  ProtoParam = Any.new('Prototype Parameter', [Syntax::Param, Symbol, Chelsy::Type::Base])
1279
1315
  ArraySize = Any.new('ArraySize', [Syntax::Expr])
1280
- BitField = Any.new('BitField', [Chelsy::Constant::Integral])
1316
+ BitField = Any.new('BitField', [
1317
+ Chelsy::Constant::Integral,
1318
+ Syntax::Constant::Int,
1319
+ ])
1281
1320
  StructOrUnionMember = Any.new('StructOrUnionMember', [Chelsy::Declaration, Chelsy::BitField])
1282
1321
  EnumMember = Any.new('EnumMember', [Chelsy::EnumMember, Symbol])
1283
1322
  Initializer = Any.new('Initializer', [Syntax::Expr, Chelsy::Initializer, Chelsy::InitializerList])
data/lib/chelsy/syntax.rb CHANGED
@@ -15,36 +15,82 @@ module Chelsy; module Syntax
15
15
  end
16
16
 
17
17
  def accept?(node)
18
- false
18
+ # Most C program uses C preprocessor, so we must accept any C code snippet.
19
+ case node
20
+ when Chelsy::Raw
21
+ true
22
+ else
23
+ false
24
+ end
25
+ end
26
+
27
+ # Try to coerce `obj` to acceptable node.
28
+ #
29
+ # @param obj Any object to coerce
30
+ # @return [Node] A node or `nil` if it can't be coerced.
31
+ def coerce(obj)
32
+ nil
19
33
  end
20
34
 
21
35
  def ensure(node)
22
36
  if accept?(node)
23
37
  node
24
38
  else
25
- raise ArgumentError, "#{node.class.name} is not one of #{@name}"
39
+ coerce(node).tap do |coerced|
40
+ raise ArgumentError, "#{node.class.name} is not one of #{@name}" unless coerced
41
+ end
26
42
  end
27
43
  end
28
44
  end
29
45
 
46
+ # This constraint accepts an instance of specific type of node, or
47
+ # can coerce some other type of objects to such a node.
48
+ class Coercer < Constraint
49
+ # Initialize an instance.
50
+ #
51
+ # @param [Class] klass type of acceptable node.
52
+ # @yieldparam value the value will be coerced.
53
+ # @yieldreturn [Node, nil] the coerced value of `nil`
54
+ def initialize(klass, &block)
55
+ @class = klass
56
+ @coercer_block = block
57
+
58
+ super klass.name
59
+ end
60
+
61
+ def accept?(node)
62
+ @class === node || super(node)
63
+ end
64
+
65
+ def coerce(node)
66
+ @coercer_block.call(node)
67
+ end
68
+ end
69
+
70
+ # This constraint instance is composed of multiple constraints.
30
71
  class Any < Constraint
72
+
73
+ # Initialize an instance with constraints.
74
+ #
75
+ # @param [String] name the name of this constraint
76
+ # @param [Array<Constraint>] constraints constraints
31
77
  def initialize(name, constraints)
32
78
  @constraints = constraints.dup
33
79
  super name
34
80
  end
35
81
 
36
- def accept?(node)
37
- # Most C program uses C preprocessor, so we must accept any C code snippet.
38
- case node
39
- when Chelsy::Raw
40
- true
41
- else
42
- @constraints.any? do |constraint|
43
- constraint === node
44
- end
45
- end
82
+ def coerce(node)
83
+ @constraints
84
+ .lazy
85
+ .find_all {|c| c.respond_to?(:coerce) }
86
+ .map {|c| c.coerce(node) }
87
+ .reject(&:nil?)
88
+ .first
46
89
  end
47
90
 
91
+ def accept?(node)
92
+ @constraints.any? {|constraint| constraint === node} || super(node)
93
+ end
48
94
  end
49
95
 
50
96
  end; end
@@ -92,6 +92,8 @@ module Chelsy
92
92
  translate_binary_operator(node)
93
93
  when Operator::Conditional
94
94
  translate_ternary_conditional(node)
95
+ when Macro
96
+ translate_macro(node)
95
97
 
96
98
  # Statements
97
99
  when EmptyStmt
@@ -406,6 +408,18 @@ module Chelsy
406
408
  "#{condition_expr} ? #{then_expr} : #{else_expr}"
407
409
  end
408
410
 
411
+ def translate_macro(node)
412
+ if node.args.nil?
413
+ node.name.to_s
414
+ else
415
+ node.name.to_s.tap do |src|
416
+ src << '('
417
+ src << node.args.map(&method(:translate)).join(', ')
418
+ src << ')'
419
+ end
420
+ end
421
+ end
422
+
409
423
  # = Statements
410
424
 
411
425
  def translate_empty_stmt(node)
@@ -614,7 +628,7 @@ module Chelsy
614
628
  def translate_endif_directive(node); "#endif" end
615
629
 
616
630
  def translate_line_directive(node)
617
- "#line #{node.lineno}".tap do |src|
631
+ "#line #{translate node.lineno}".tap do |src|
618
632
  src << " \"#{translate node.filename}\"" if node.filename
619
633
  end
620
634
  end
@@ -1,3 +1,3 @@
1
1
  module Chelsy
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
@@ -7,8 +7,8 @@ doc = Document.new
7
7
  doc.fragments << Directive::Include.new("stdio.h", system: true)
8
8
 
9
9
  doc << Function.new(:main, Type::Int.new, [:void]) do |b|
10
- b << Operator::Call.new(:printf, [Constant::String.new("Hello, Chelsy!\n")])
11
- b << Return.new(Constant::Int.new(0))
10
+ b << Operator::Call.new(:printf, ["Hello, Chelsy!\n"])
11
+ b << Return.new(0)
12
12
  end
13
13
 
14
14
  puts Translator.new.translate(doc)
@@ -10,9 +10,9 @@ doc.fragments << Comment::Multi.new([
10
10
  "Print Fahrenheit to Celsius table",
11
11
  "(fahr = 0, 20, ..., 300)"
12
12
  ])
13
- doc.fragments << Directive::Define.new(:LOWER, Constant::Int.new(0))
14
- doc.fragments << Directive::Define.new(:UPPER, Constant::Int.new(300))
15
- doc.fragments << Directive::Define.new(:STEP, Constant::Int.new(20))
13
+ doc.fragments << Directive::Define.new(:LOWER, 0)
14
+ doc.fragments << Directive::Define.new(:UPPER, 300)
15
+ doc.fragments << Directive::Define.new(:STEP, 20)
16
16
 
17
17
  doc << Function.new(:main,
18
18
  Type::Int.new, [
@@ -24,15 +24,15 @@ doc << Function.new(:main,
24
24
  step = Operator::AssignAdd.new(:fahr, :STEP)
25
25
 
26
26
  b << For.new(init, cond, step) do |body|
27
- celsius = Operator::Sub.new(:fahr, Constant::Int.new(32))
28
- celsius = Operator::Mul.new(Constant::Int.new(5), celsius)
29
- celsius = Operator::Div.new(celsius, Constant::Int.new(9))
27
+ celsius = Operator::Sub.new(:fahr, 32)
28
+ celsius = Operator::Mul.new(5, celsius)
29
+ celsius = Operator::Div.new(celsius, 9)
30
30
 
31
31
  body << Declaration.new(:celsius, Type::Int.new, celsius)
32
- body << Operator::Call.new(:printf, [Constant::String.new("%d\t%d\n"), :fahr, :celsius])
32
+ body << Operator::Call.new(:printf, ["%d\t%d\n", :fahr, :celsius])
33
33
  end
34
34
 
35
- b << Return.new(Constant::Int.new(0))
35
+ b << Return.new(0)
36
36
  end
37
37
 
38
38
  puts Translator.new(indent_string: ' ').translate(doc)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chelsy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takanori Ishikawa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-29 00:00:00.000000000 Z
11
+ date: 2016-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler