minjs 0.1.2

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,45 @@
1
+ module Minjs
2
+ module Literal
3
+ #
4
+ # 7.8
5
+ #
6
+ def literal(lex, context)
7
+ lex.eval_lit{
8
+ a = lex.fwd_lit(:hint => :regexp)
9
+ if a.kind_of?(ECMA262::ECMA262Numeric) || a.kind_of?(ECMA262::ECMA262String) || a.kind_of?(ECMA262::ECMA262RegExp)
10
+ a
11
+ else
12
+ nil
13
+ end
14
+ } or lex.eval_lit{
15
+ null_literal(lex, context)
16
+ } or lex.eval_lit{
17
+ boolean_literal(lex, context)
18
+ }
19
+ end
20
+
21
+ #
22
+ # 7.8.1
23
+ #
24
+ def null_literal(lex, context)
25
+ if lex.match_lit(ECMA262::ID_NULL)
26
+ ECMA262::Null.get
27
+ else
28
+ nil
29
+ end
30
+ end
31
+
32
+ #
33
+ # 7.8.2
34
+ #
35
+ def boolean_literal(lex, context)
36
+ if lex.match_lit(ECMA262::ID_TRUE)
37
+ ECMA262::Boolean.new(:true)
38
+ elsif lex.match_lit(ECMA262::ID_FALSE)
39
+ ECMA262::Boolean.new(:false)
40
+ else
41
+ nil
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,47 @@
1
+ require 'tilt'
2
+
3
+ module Minjs
4
+ class MinjsCompressor < Tilt::Template
5
+ DEBUG = false
6
+
7
+ def self.engine_initialized?
8
+ defined?(::Minjs)
9
+ end
10
+
11
+ def initialize_engine
12
+ end
13
+
14
+ def prepare
15
+ end
16
+
17
+ def evaluate(context, locals, &block)
18
+ case context.content_type
19
+ when 'application/javascript'
20
+ if DEBUG
21
+ @@c = 0 unless defined?(@@c)
22
+ puts "start: compressing"
23
+ file = "tmp#{@@c}.js"
24
+ output = "tmp#{@@c}.js.min"
25
+ @@c += 1
26
+ puts "source: #{file}"
27
+ puts "output: #{output}"
28
+ tmp = open(file, "w")
29
+ tmp.write(data)
30
+ tmp.close
31
+ end
32
+ t = Minjs::Compressor.new.compress(data)
33
+ if DEBUG
34
+ tmp = open(output, "w")
35
+ tmp.write(t)
36
+ tmp.close
37
+ end
38
+ t
39
+ else
40
+ data
41
+ end
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+
@@ -0,0 +1,32 @@
1
+ module Minjs
2
+ #
3
+ # 14 Program
4
+ #
5
+ module Program
6
+ def source_elements(lex, context, options = {})
7
+ prog = []
8
+ while !lex.eof?
9
+ t = source_element(lex, context)
10
+ if t
11
+ prog.push(t)
12
+ # elsif !options[:no_exception]
13
+ # lex.debug_lit
14
+ # raise 'error'
15
+ # return nil
16
+ else
17
+ break
18
+ end
19
+ end
20
+ ECMA262::Prog.new(context, prog)
21
+ end
22
+
23
+ def source_element(lex, context)
24
+ lex.eval_lit{
25
+ statement(lex, context)
26
+ } or lex.eval_lit{
27
+ func_declaration(lex, context)
28
+ }
29
+ end
30
+ end
31
+ end
32
+
@@ -0,0 +1,438 @@
1
+ module Minjs
2
+ #
3
+ # 12
4
+ #
5
+ module Statement
6
+ #
7
+ # check next literal is ';' or '}' or LT
8
+ #
9
+ def semicolon(lex, context)
10
+ lex.eval_lit{
11
+ a = lex.fwd_lit(:nolt => true)
12
+ if a == ECMA262::PUNC_SEMICOLON
13
+ a
14
+ elsif a == ECMA262::PUNC_RCURLYBRAC
15
+ lex.rewind_pos
16
+ a
17
+ elsif a == ECMA262::LIT_LINE_FEED
18
+ a
19
+ elsif a.lt?
20
+ a
21
+ else
22
+ nil
23
+ end
24
+ }
25
+ end
26
+
27
+ #12
28
+ def statement(lex, context)
29
+ [:block,
30
+ :var_statement,
31
+ :exp_statement,
32
+ :if_statement,
33
+ :iteration_statement,
34
+ :continue_statement,
35
+ :break_statement,
36
+ :return_statement,
37
+ :with_statement,
38
+ :labelled_statement,
39
+ :switch_statement,
40
+ :throw_statement,
41
+ :try_statement,
42
+ :debugger_statement,
43
+ #
44
+ # function declaration in statement(block) is not permitted by ECMA262.
45
+ # however, almost all implementation permit it.
46
+ #
47
+ :func_declaration,
48
+ :empty_statement,
49
+ ].each do |f|
50
+ puts "* checking #{f.to_s}" if @debug
51
+ t = lex.eval_lit {
52
+ __send__(f, lex, context)
53
+ }
54
+ return t if t
55
+ end
56
+ nil
57
+ end
58
+ #
59
+ #12.1
60
+ # block
61
+ def block(lex, context)
62
+ pos0 = lex.pos
63
+ return nil unless lex.match_lit(ECMA262::PUNC_LCURLYBRAC)
64
+ if lex.match_lit(ECMA262::PUNC_RCURLYBRAC)
65
+ return ECMA262::StBlock.new(ECMA262::StList.new([]))
66
+ end
67
+ lex.eval_lit {
68
+ if s = statement_list(lex, context) and lex.match_lit(ECMA262::PUNC_RCURLYBRAC)
69
+ ECMA262::StBlock.new(s)
70
+ else
71
+ if s
72
+ lex.debug_lit
73
+ puts lex.debug_code(pos0, lex.pos)
74
+ raise 'no "}" end of block'
75
+ else
76
+ lex.debug_lit
77
+ raise "bad block"
78
+ end
79
+ end
80
+ }
81
+ end
82
+
83
+ def statement_list(lex, context)
84
+ lex.eval_lit {
85
+ t = []
86
+ while !lex.eof?
87
+ if s = statement(lex, context)
88
+ t.push(s)
89
+ else
90
+ break
91
+ end
92
+ end
93
+ ECMA262::StList.new(t)
94
+ }
95
+ end
96
+ #
97
+ #12.2
98
+ # variable_statement
99
+ #
100
+ def var_statement(lex, context)
101
+ raise 'error' if context.nil?
102
+ return nil unless lex.match_lit(ECMA262::ID_VAR)
103
+ lex.eval_lit {
104
+ if vl = var_decl_list(lex, context, {}) and semicolon(lex, context)
105
+ #10.5
106
+ vl.each do |v|
107
+ dn = v[0]
108
+ context.var_env.record.create_mutable_binding(dn, nil)
109
+ context.var_env.record.set_mutable_binding(dn, :undefined, nil)
110
+ end
111
+ ECMA262::StVar.new(context, vl)
112
+ else
113
+ lex.debug_lit
114
+ raise Minjs::ParseError.new("var_statement")
115
+ end
116
+ }
117
+ end
118
+
119
+ def var_decl_list(lex, context, options)
120
+ lex.eval_lit {
121
+ a = var_decl(lex, context, options)
122
+ next nil if !a
123
+
124
+ if lex.match_lit(ECMA262::PUNC_COMMA) and b = var_decl_list(lex, context, options)
125
+ next [a] + b
126
+ else
127
+ next [a]
128
+ end
129
+ }
130
+ end
131
+
132
+ def var_decl(lex, context, options)
133
+ lex.eval_lit {
134
+ a = lex.fwd_lit
135
+ if !a
136
+ nil
137
+ elsif !a.kind_of?(ECMA262::IdentifierName)
138
+ nil
139
+ else
140
+ b = initialiser(lex, context, options)
141
+ [a, b]
142
+ end
143
+ }
144
+ end
145
+
146
+ def initialiser(lex, context, options)
147
+ if lex.match_lit(ECMA262::PUNC_LET) and a = assignment_exp(lex, context, options)
148
+ return a
149
+ end
150
+
151
+ nil
152
+ end
153
+ #
154
+ #12.3
155
+ #
156
+ def empty_statement(lex, context)
157
+ lex.eval_lit{
158
+ a = lex.fwd_lit(:nolt => true)
159
+ if a == ECMA262::PUNC_SEMICOLON
160
+ ECMA262::StEmpty.new
161
+ elsif a == ECMA262::LIT_LINE_FEED
162
+ ECMA262::StEmpty.new
163
+ elsif a.lt?
164
+ ECMA262::StEmpty.new
165
+ else
166
+ nil
167
+ end
168
+ }
169
+ end
170
+ #
171
+ #12.4
172
+ #
173
+ def exp_statement(lex, context)
174
+ return false if lex.next_lit == ECMA262::PUNC_LCURLYBRAC
175
+ return false if lex.next_lit == ECMA262::ID_FUNCTION
176
+ lex.eval_lit{
177
+ if a=exp(lex, context, {}) and semicolon(lex, context)
178
+ ECMA262::StExp.new(a)
179
+ else
180
+ nil
181
+ end
182
+ }
183
+ end
184
+ #
185
+ #12.5
186
+ #
187
+ def if_statement(lex, context)
188
+ lex.eval_lit {
189
+ unless lex.match_lit(ECMA262::ID_IF) and lex.match_lit(ECMA262::PUNC_LPARENTHESIS) and cond=exp(lex, context, {}) and lex.match_lit(ECMA262::PUNC_RPARENTHESIS) and s=statement(lex, context)
190
+ next nil
191
+ end
192
+ if lex.match_lit(ECMA262::ID_ELSE) and e=statement(lex, context)
193
+ ECMA262::StIf.new(cond, s, e)
194
+ else
195
+ ECMA262::StIf.new(cond, s, nil)
196
+ end
197
+ }
198
+ end
199
+ #
200
+ # 12.6
201
+ #
202
+ def iteration_statement(lex, context)
203
+ for_statement(lex, context) or while_statement(lex, context) or do_while_statement(lex, context)
204
+ end
205
+
206
+ def while_statement(lex, context)
207
+ return nil unless lex.match_lit(ECMA262::ID_WHILE)
208
+ if lex.match_lit(ECMA262::PUNC_LPARENTHESIS) and e=exp(lex, context, {}) and lex.match_lit(ECMA262::PUNC_RPARENTHESIS) and s=statement(lex, context)
209
+ ECMA262::StWhile.new(e, s)
210
+ else
211
+ lex.debug_lit
212
+ raise ParseError.new("while_statement")
213
+ end
214
+ end
215
+
216
+ def do_while_statement(lex, context)
217
+ return nil unless lex.match_lit(ECMA262::ID_DO)
218
+ if s=statement(lex, context) and lex.match_lit(ECMA262::ID_WHILE) and lex.match_lit(ECMA262::PUNC_LPARENTHESIS) and e=exp(lex, context, {}) and lex.match_lit(ECMA262::PUNC_RPARENTHESIS) and semicolon(lex, context)
219
+ ECMA262::StDoWhile.new(e, s)
220
+ else
221
+ lex.debug_lit
222
+ raise ParseError.new("do_while_statement")
223
+ end
224
+ end
225
+
226
+ def for_statement(lex, context)
227
+ return nil unless lex.match_lit(ECMA262::ID_FOR)
228
+ lex.eval_lit{
229
+ # for(var i in a)
230
+ next nil unless lex.match_lit(ECMA262::PUNC_LPARENTHESIS)
231
+ if lex.match_lit(ECMA262::ID_VAR) and v=var_decl(lex, context, :no_in => true) and lex.match_lit(ECMA262::ID_IN) and e=exp(lex, context, {}) and lex.match_lit(ECMA262::PUNC_RPARENTHESIS) and s=statement(lex, context)
232
+ #10.5
233
+ context.var_env.record.create_mutable_binding(v[0], nil)
234
+ context.var_env.record.set_mutable_binding(v[0], :undefined, nil)
235
+ ECMA262::StForInVar.new(context, v, e, s)
236
+ else
237
+ nil
238
+ end
239
+ } or lex.eval_lit {
240
+ # for(var i ; cond ; exp)
241
+ next nil unless lex.match_lit(ECMA262::PUNC_LPARENTHESIS)
242
+ if lex.match_lit(ECMA262::ID_VAR) and vl=var_decl_list(lex, context, :no_in =>true) and lex.match_lit(ECMA262::PUNC_SEMICOLON) and (e=exp(lex, context, {})||true) and lex.match_lit(ECMA262::PUNC_SEMICOLON) and (e2=exp(lex, context, {})||true) and lex.match_lit(ECMA262::PUNC_RPARENTHESIS) and s=statement(lex, context)
243
+ e = ECMA262::ExpEmpty.new if e == true
244
+ e2 = ECMA262::ExpEmpty.new if e2 == true
245
+ #10.5
246
+ vl.each do |v|
247
+ dn = v[0]
248
+ context.var_env.record.create_mutable_binding(dn, nil)
249
+ context.var_env.record.set_mutable_binding(dn, :undefined, nil)
250
+ end
251
+ ECMA262::StForVar.new(context, vl, e, e2, s)
252
+ else
253
+ nil
254
+ end
255
+ } or lex.eval_lit{
256
+ # for(i in exp)
257
+ next nil unless lex.match_lit(ECMA262::PUNC_LPARENTHESIS)
258
+ if v=left_hand_side_exp(lex, context, {}) and lex.match_lit(ECMA262::ID_IN) and e=exp(lex, context, {}) and lex.match_lit(ECMA262::PUNC_RPARENTHESIS) and s=statement(lex, context)
259
+ ECMA262::StForIn.new(v, e, s)
260
+ else
261
+ nil
262
+ end
263
+ } or lex.eval_lit{
264
+ # for(i ; cond; exp)
265
+ next nil unless lex.match_lit(ECMA262::PUNC_LPARENTHESIS)
266
+ if (v=exp(lex, context, :no_in => true) || true) and lex.match_lit(ECMA262::PUNC_SEMICOLON) and (e=exp(lex, context, {}) || true) and lex.match_lit(ECMA262::PUNC_SEMICOLON) and (e2=exp(lex, context, {})||true) and lex.match_lit(ECMA262::PUNC_RPARENTHESIS) and s=statement(lex, context)
267
+ v = ECMA262::ExpEmpty.new if v == true
268
+ e = ECMA262::ExpEmpty.new if e == true
269
+ e2 = ECMA262::ExpEmpty.new if e2 == true
270
+ ECMA262::StFor.new(v, e, e2, s)
271
+ else
272
+ nil
273
+ end
274
+ }
275
+ end
276
+ #
277
+ # 12.7
278
+ #
279
+ def continue_statement(lex, context)
280
+ return nil unless lex.match_lit(ECMA262::ID_CONTINUE)
281
+ lex.eval_lit {
282
+ if semicolon(lex, context)
283
+ ECMA262::StContinue.new
284
+ elsif e=exp(lex, context, {}) and semicolon(lex, context)
285
+ ECMA262::StContinue.new(e)
286
+ end
287
+ }
288
+ end
289
+ #
290
+ # 12.8
291
+ #
292
+ def break_statement(lex, context)
293
+ return nil unless lex.match_lit(ECMA262::ID_BREAK)
294
+ lex.eval_lit {
295
+ if semicolon(lex, context)
296
+ ECMA262::StBreak.new
297
+ elsif e=exp(lex, context, {}) and semicolon(lex, context)
298
+ ECMA262::StBreak.new(e)
299
+ end
300
+ }
301
+ end
302
+ #
303
+ # 12.9
304
+ #
305
+ def return_statement(lex, context)
306
+ return nil unless lex.match_lit(ECMA262::ID_RETURN)
307
+ lex.eval_lit {
308
+ if semicolon(lex, context)
309
+ ECMA262::StReturn.new
310
+ elsif e=exp(lex, context, {}) and semicolon(lex, context)
311
+ ECMA262::StReturn.new(e)
312
+ else
313
+ nil
314
+ end
315
+ }
316
+ end
317
+ #
318
+ # 12.10
319
+ #
320
+ def with_statement(lex, context)
321
+ return nil unless lex.match_lit(ECMA262::ID_WITH)
322
+ lex.eval_lit {
323
+ if lex.match_lit(ECMA262::PUNC_LPARENTHESIS) and e=exp(lex, context, {}) and lex.match_lit(ECMA262::PUNC_RPARENTHESIS) and s=statement(lex, context)
324
+ ECMA262::StWith.new(e, s)
325
+ else
326
+ lex.debug_lit
327
+ raise ParseError.new("switch_statement")
328
+ end
329
+ }
330
+ end
331
+ #
332
+ # 12.11
333
+ #
334
+ def switch_statement(lex, context)
335
+ return nil unless lex.match_lit(ECMA262::ID_SWITCH)
336
+ lex.eval_lit {
337
+ if lex.match_lit(ECMA262::PUNC_LPARENTHESIS) and e=exp(lex, context, {}) and lex.match_lit(ECMA262::PUNC_RPARENTHESIS) and c = case_block(lex, context)
338
+ ECMA262::StSwitch.new(e, c)
339
+ else
340
+ lex.debug_lit
341
+ raise ParseError.new("switch_statement")
342
+ end
343
+ }
344
+ end
345
+
346
+ def case_block(lex, context)
347
+ return nil unless lex.match_lit(ECMA262::PUNC_LCURLYBRAC)
348
+ _case_block = []
349
+ while true
350
+ t = lex.eval_lit{
351
+ break unless lex.match_lit(ECMA262::ID_CASE) and e=exp(lex, context, {}) and lex.match_lit(ECMA262::PUNC_COLON)
352
+ sl = statement_list(lex, context)
353
+ [e, sl]
354
+ } || lex.eval_lit{
355
+ break unless lex.match_lit(ECMA262::ID_DEFAULT) and lex.match_lit(ECMA262::PUNC_COLON)
356
+ sl = statement_list(lex, context)
357
+ [nil, sl]
358
+ }
359
+ break if t.nil?
360
+ _case_block.push(t)
361
+ end
362
+ return nil unless lex.match_lit(ECMA262::PUNC_RCURLYBRAC)
363
+ _case_block
364
+ end
365
+ #
366
+ # 12.12
367
+ #
368
+ def labelled_statement(lex, context)
369
+ lex.eval_lit {
370
+ if i=identifier(lex, context) and lex.match_lit(ECMA262::PUNC_COLON) and s=statement(lex, context)
371
+ ECMA262::StLabelled.new(i, s)
372
+ else
373
+ nil
374
+ end
375
+ }
376
+ end
377
+ #
378
+ # 12.13
379
+ #
380
+ def throw_statement(lex, context)
381
+ return nil unless lex.match_lit(ECMA262::ID_THROW)
382
+ lex.eval_lit{
383
+ if e=exp(lex, context, {}) and semicolon(lex, context)
384
+ ECMA262::StThrow.new(e)
385
+ else
386
+ lex.debug_lit
387
+ raise ParseError.new("throw_statement")
388
+ end
389
+ }
390
+ end
391
+ #
392
+ # 12.14
393
+ #
394
+ def try_statement(lex, context)
395
+ return nil unless lex.match_lit(ECMA262::ID_TRY)
396
+ lex.eval_lit {
397
+ t = block(lex, context)
398
+ break nil unless t
399
+
400
+ lex.eval_lit{
401
+ c = try_catch(lex, context)
402
+ break nil unless c
403
+
404
+ f = try_finally(lex, context)
405
+ ECMA262::StTry.new(t, c, f)
406
+ } || lex.eval_lit{
407
+ f = try_finally(lex, context)
408
+ break nil unless f
409
+ ECMA262::StTry.new(t, nil, f)
410
+ }
411
+ }
412
+ end
413
+ def try_catch(lex, context)
414
+ return nil unless lex.match_lit(ECMA262::ID_CATCH)
415
+ if lex.match_lit(ECMA262::PUNC_LPARENTHESIS) and i=identifier(lex, context) and lex.match_lit(ECMA262::PUNC_RPARENTHESIS) and b=block(lex, context)
416
+ [i, b]
417
+ else
418
+ nil
419
+ end
420
+ end
421
+
422
+ def try_finally(lex, context)
423
+ return nil unless lex.match_lit(ECMA262::ID_FINALLY)
424
+ block(lex, context)
425
+ end
426
+
427
+ #
428
+ # 12.15
429
+ #
430
+ def debugger_statement(lex, context)
431
+ if lex.match_lit(ECMA262::ID_DEBUGGER) and semicolon(lex, context)
432
+ t = ECMA262::StDebugger.new
433
+ end
434
+ end
435
+
436
+ end
437
+ end
438
+
@@ -0,0 +1,3 @@
1
+ module Minjs
2
+ VERSION = "0.1.2"
3
+ end
data/lib/minjs.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "minjs/version"
2
+ require "minjs/expression"
3
+ require "minjs/func"
4
+ require "minjs/lex"
5
+ require "minjs/literal"
6
+ require "minjs/program"
7
+ require "minjs/statement"
8
+ require "minjs/compressor"
9
+ require "minjs/ecma262"
10
+ require "minjs/minjs_compressor"
11
+ require "minjs/ctype"
12
+ require "minjs/exceptions"
13
+
14
+ module Minjs
15
+ # Your code goes here...
16
+ end
data/minjs.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'minjs/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "minjs"
8
+ spec.version = Minjs::VERSION
9
+ spec.authors = ["Issei Numata"]
10
+ spec.email = ["issei@heart-s.com"]
11
+
12
+ # if spec.respond_to?(:metadata)
13
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com' to prevent pushes to rubygems.org, or delete to allow pushes to any server."
14
+ # end
15
+
16
+ spec.summary = %q{JavaScript compressor in pure Ruby}
17
+ spec.description = %q{Minjs is a JavaScript compressor written in pure Ruby}
18
+ spec.homepage = "https://github.com/i10a/minjs"
19
+ spec.license = "MIT"
20
+
21
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.8"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rspec"
29
+ #spec.add_dependency 'sprockets', '~> 3.0.0'
30
+ spec.add_dependency 'tilt', '~> 1.4.0'
31
+ end