jsrb 0.1.0

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.
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsrb
4
+ class JSStatementContext
5
+ attr_reader :stacks
6
+
7
+ def initialize
8
+ @var_count = 0
9
+ @stacks = [[]]
10
+ end
11
+
12
+ def gen_var_name!
13
+ @var_count += 1
14
+ "_v#{@var_count}"
15
+ end
16
+
17
+ def push(*stmt)
18
+ @stacks.last.push(*stmt)
19
+ nil
20
+ end
21
+
22
+ def new_expression(object = nil)
23
+ ExprChain.new(self, object)
24
+ end
25
+
26
+ def new_block
27
+ _result, statements = in_new_context { yield }
28
+ {
29
+ type: 'BlockStatement',
30
+ body: statements
31
+ }
32
+ end
33
+
34
+ # rubocop:disable Metrics/MethodLength
35
+ # rubocop:disable Metrics/CyclomaticComplexity
36
+ # rubocop:disable Metrics/AbcSize
37
+ def ruby_to_js_ast(rbv)
38
+ case rbv
39
+ when ExprChain
40
+ rbv.unwrap!
41
+ when Proc
42
+ chainables = rbv.parameters.map do |_type, name|
43
+ new_expression.member!(name.to_s)
44
+ end
45
+ result, statements = in_new_context { rbv.call(*chainables) }
46
+ if result
47
+ statements.push(
48
+ type: 'ReturnStatement',
49
+ argument: ruby_to_js_ast(result)
50
+ )
51
+ end
52
+ {
53
+ type: 'FunctionExpression',
54
+ id: nil,
55
+ params: chainables.map { |arg| ruby_to_js_ast(arg) },
56
+ body: {
57
+ type: 'BlockStatement',
58
+ body: statements
59
+ }
60
+ }
61
+ when Hash
62
+ var_name = gen_var_name!
63
+ statements = rbv.map do |key, v|
64
+ {
65
+ type: 'ExpressionStatement',
66
+ expression: new_expression.member!(var_name).member!(key).assign!(v).unwrap!
67
+ }
68
+ end
69
+ {
70
+ type: 'CallExpression',
71
+ callee: {
72
+ type: 'FunctionExpression',
73
+ id: nil,
74
+ params: [new_expression.member!(var_name).unwrap!],
75
+ body: {
76
+ type: 'BlockStatement',
77
+ body: statements.concat(
78
+ [
79
+ {
80
+ type: 'ReturnStatement',
81
+ argument: new_expression.member!(var_name).unwrap!
82
+ }
83
+ ]
84
+ )
85
+ }
86
+ },
87
+ arguments: [
88
+ {
89
+ type: 'ObjectExpression',
90
+ properties: []
91
+ }
92
+ ]
93
+ }
94
+ when Array
95
+ {
96
+ type: 'ArrayExpression',
97
+ elements: rbv.map { |v| ruby_to_js_ast(v) }
98
+ }
99
+ when TrueClass, FalseClass, String, NilClass
100
+ build_literal_ast(rbv)
101
+ when Float::INFINITY
102
+ new_expression.member!('Number').member!('POSITIVE_INFINITY').unwrap!
103
+ when -Float::INFINITY
104
+ new_expression.member!('Number').member!('NEGATIVE_INFINITY').unwrap!
105
+ when Float
106
+ if rbv.nan?
107
+ new_expression.member!('Number').member!('NaN').unwrap!
108
+ else
109
+ build_finite_number_ast(rbv)
110
+ end
111
+ when Integer
112
+ build_finite_number_ast(rbv)
113
+ when Symbol
114
+ ruby_to_js_ast(rbv.to_s)
115
+ else
116
+ raise "Can't convert to JavaScript AST from: #{rbv.inspect}"
117
+ end
118
+ end
119
+ # rubocop:enable Metrics/MethodLength
120
+ # rubocop:enable Metrics/CyclomaticComplexity
121
+ # rubocop:enable Metrics/AbcSize
122
+
123
+ private
124
+
125
+ def in_new_context
126
+ @stacks.push([])
127
+ result = yield
128
+ statements = @stacks.pop
129
+ [result, statements]
130
+ end
131
+
132
+ def build_finite_number_ast(value)
133
+ if value < 0
134
+ {
135
+ type: 'UnaryExpression',
136
+ operator: '-',
137
+ argument: build_literal_ast(-value)
138
+ }
139
+ else
140
+ build_literal_ast(value)
141
+ end
142
+ end
143
+
144
+ def build_literal_ast(value)
145
+ {
146
+ type: 'Literal',
147
+ value: value
148
+ }
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'execjs'
4
+ require 'stitch'
5
+
6
+ module Jsrb
7
+ class NotFastGenerator
8
+ def call(node)
9
+ self.class.context.call('this.escodegen.generate', node)
10
+ end
11
+
12
+ class << self
13
+ def context
14
+ @context ||= begin
15
+ code = Stitch::Package.new(root: "#{source_path}/", dependencies: "#{source_path}/escodegen.browser.js").compile
16
+ ExecJS.compile(code)
17
+ end
18
+ end
19
+
20
+ def source_path
21
+ File.expand_path(File.join(File.dirname(__FILE__), './vendor'))
22
+ end
23
+ end
24
+ end
25
+ end