jsrb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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