liquidscript 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/liquidscript/buffer.rb +2 -2
  3. data/lib/liquidscript/compiler/icr.rb +1 -0
  4. data/lib/liquidscript/compiler/icr/classes.rb +11 -3
  5. data/lib/liquidscript/compiler/icr/expressions.rb +56 -10
  6. data/lib/liquidscript/compiler/icr/functions.rb +7 -6
  7. data/lib/liquidscript/compiler/icr/heredoc.rb +28 -0
  8. data/lib/liquidscript/compiler/icr/literals.rb +102 -9
  9. data/lib/liquidscript/errors.rb +6 -0
  10. data/lib/liquidscript/generator/base.rb +1 -1
  11. data/lib/liquidscript/generator/base/replacements.rb +2 -2
  12. data/lib/liquidscript/generator/javascript.rb +21 -0
  13. data/lib/liquidscript/generator/javascript/exceptions.rb +42 -0
  14. data/lib/liquidscript/generator/javascript/literals.rb +71 -9
  15. data/lib/liquidscript/generator/javascript/metas.rb +14 -13
  16. data/lib/liquidscript/generator/javascript/objects.rb +21 -16
  17. data/lib/liquidscript/icr/set.rb +8 -0
  18. data/lib/liquidscript/scanner/base/lexer.rb +13 -10
  19. data/lib/liquidscript/scanner/liquidscript.rb +95 -17
  20. data/lib/liquidscript/template.rb +1 -2
  21. data/lib/liquidscript/version.rb +1 -1
  22. data/liquidscript.gemspec +1 -0
  23. data/spec/fixtures/class.compile.yml +12 -1
  24. data/spec/fixtures/class.generate.yml +4 -4
  25. data/spec/fixtures/combination.generate.yml +4 -4
  26. data/spec/fixtures/complex.generate.yml +5 -5
  27. data/spec/fixtures/expression.generate.yml +1 -1
  28. data/spec/fixtures/heredoc.generate.yml +9 -0
  29. data/spec/fixtures/literals.generate.yml +9 -1
  30. data/spec/fixtures/loop.generate.yml +16 -0
  31. data/spec/fixtures/main.compile.yml +19 -15
  32. data/spec/fixtures/operator.generate.yml +10 -2
  33. data/spec/fixtures/string.compile.yml +20 -1
  34. data/spec/fixtures/string.generate.yml +1 -1
  35. data/spec/fixtures/underscore.js +28 -0
  36. data/spec/fixtures/underscore.ls +2 -1
  37. data/spec/liquidscript/compiler/icr_spec.rb +2 -0
  38. data/spec/liquidscript/node_spec.rb +21 -0
  39. data/spec/liquidscript/scanner/lexer_spec.rb +23 -2
  40. data/spec/support/matchers/compile.rb +1 -1
  41. data/spec/support/matchers/generate.rb +6 -3
  42. data/spec/support/matchers/run.rb +12 -0
  43. metadata +28 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4f11281d148fb640ffc2e0f7e8620d90db902979
4
- data.tar.gz: 8e49e850af07a8d34d44595e2f8d550eb09e5a05
3
+ metadata.gz: 6fe5335e4dfdf4f906673f081655d77b96fbca14
4
+ data.tar.gz: 5c1ff4ce91cc20fa3ede9c4fc7dfe030e752fef6
5
5
  SHA512:
6
- metadata.gz: f7e8ba8419ac72d775682a35fd5f8acea5a8210e20d2279ef508b1008470eb8f737d9226c481bd35f9ce3bfb2f980e9c191cd47e1d86afb56148f5a7ddde1cb4
7
- data.tar.gz: 05d976029b24a986e993c40604ea57bd2034bd27dde7aa376e14db6db3a1bfc65e537009fab0bcac41612e44fed250c654a37571924bac12e8f80daa023874e6
6
+ metadata.gz: 051c175bba208e2cd9154d72722a55d31a2db037a17ed87dc4b8c7e275df81c6ec344fe35bd9f7bbae431b72c9c0f4789e8dfc9d54820a302360b759a92c777b
7
+ data.tar.gz: 8f4c51719dcc4dfa40856605796694cc3bd00f579eee32fd63056126e86269fcdb302ddc217bcc1643e3191b61159255a904a50381d94f79fb88af3992cea602
@@ -13,8 +13,8 @@ module Liquidscript
13
13
  self
14
14
  end
15
15
 
16
- def block(str)
17
- append str.gsub(/^[ \t]+/, '')
16
+ def block(indent, str)
17
+ append str.gsub(/^[ \t]{#{indent*2}}/, '')
18
18
  end
19
19
 
20
20
  def set_join!(to)
@@ -3,6 +3,7 @@ require "liquidscript/compiler/icr/functions"
3
3
  require "liquidscript/compiler/icr/literals"
4
4
  require "liquidscript/compiler/icr/classes"
5
5
  require "liquidscript/compiler/icr/helpers"
6
+ require "liquidscript/compiler/icr/heredoc"
6
7
 
7
8
  module Liquidscript
8
9
  module Compiler
@@ -6,10 +6,18 @@ module Liquidscript
6
6
  def compile_class
7
7
  shift :class
8
8
  name = shift :identifier
9
+ inherit = nil
9
10
  set name
11
+ # Inheritance ftw!
12
+ if peek?(:colon)
13
+ shift :colon
14
+ inherit = shift :identifier
15
+ ref inherit
16
+ end
17
+
10
18
  body = _compile_class_body(false)
11
19
 
12
- code :class, name, body
20
+ code :class, name, inherit, body
13
21
  end
14
22
 
15
23
  def compile_module
@@ -22,7 +30,7 @@ module Liquidscript
22
30
  end
23
31
 
24
32
  def _compile_class_body(mod = false)
25
- shift :lbrack
33
+ shift :lbrace
26
34
 
27
35
  components = []
28
36
 
@@ -34,7 +42,7 @@ module Liquidscript
34
42
  end
35
43
 
36
44
  loop do
37
- expect :newline, :rbrack => action.end_loop,
45
+ expect :newline, :rbrace => action.end_loop,
38
46
  :comma => action.shift,
39
47
  :module => action { components << compile_module },
40
48
  :class => action { components << compile_class },
@@ -8,7 +8,8 @@ module Liquidscript
8
8
  #
9
9
  # @return [ICR::Code]
10
10
  def compile_expression
11
- expect :if, :unless, :class, :module, :_ => :vexpression
11
+ expect :if, :unless, :class, :module, :loop, :for,
12
+ :while, :action, :try, :_ => :vexpression
12
13
  end
13
14
 
14
15
  # Compiles an expression that returns a value.
@@ -19,11 +20,19 @@ module Liquidscript
19
20
  :istring, :lparen,
20
21
  :sstring, :operator,
21
22
  :keyword, :unop,
23
+ :regex,
22
24
  :newline,
23
25
  :istring_begin,
24
- :lbrack => :object,
25
- :lbrace => :array,
26
- :arrow => :function
26
+ :iheredoc_begin,
27
+ :lbrace => :object,
28
+ :lbrack => :array,
29
+ :arrow => :function,
30
+ [
31
+ :heredoc_ref, :iheredoc_ref
32
+ ] => :href,
33
+ [
34
+ :heredoc, :iheredoc
35
+ ] => :heredoc
27
36
 
28
37
  if peek? :binop
29
38
  compile_binop(out)
@@ -120,9 +129,9 @@ module Liquidscript
120
129
  shift :lparen
121
130
  conditional = compile_vexpression
122
131
  shift :rparen
123
- shift :lbrack
132
+ shift :lbrace
124
133
 
125
- body = collect_compiles(:expression, :rbrack)
134
+ body = collect_compiles(:expression, :rbrace)
126
135
 
127
136
  if peek?(:elsif, :else)
128
137
  code key, conditional, body, expect(:elsif, :else)
@@ -137,21 +146,58 @@ module Liquidscript
137
146
  shift :lparen
138
147
  conditional = compile_vexpression
139
148
  shift :rparen
140
- shift :lbrack
149
+ shift :lbrace
141
150
 
142
- body = collect_compiles(:expression, :rbrack)
151
+ body = collect_compiles(:expression, :rbrace)
143
152
  code :unless, conditional, body
144
153
  end
145
154
 
146
155
  def compile_else
147
156
  shift :else
148
- shift :lbrack
157
+ shift :lbrace
149
158
 
150
- body = collect_compiles(:expression, :rbrack)
159
+ body = collect_compiles(:expression, :rbrace)
151
160
 
152
161
  code :else, body
153
162
  end
154
163
 
164
+ def compile_try
165
+ shift :try
166
+ shift :lbrace
167
+ try_body = collect_compiles(:expression, :rbrace)
168
+
169
+ next_part = if peek?(:catch)
170
+ _compile_catch
171
+ elsif peek?(:finally)
172
+ _compile_finally
173
+ end
174
+
175
+ code :try, try_body, next_part
176
+ end
177
+
178
+ def _compile_catch
179
+ shift :catch
180
+ shift :lparen
181
+ var = shift :identifier
182
+ shift :rparen
183
+ shift :lbrace
184
+ catch_body = collect_compiles(:expression, :rbrace)
185
+
186
+ next_part = if peek?(:finally)
187
+ _compile_finally
188
+ end
189
+
190
+ code :catch, var, catch_body, next_part
191
+ end
192
+
193
+ def _compile_finally
194
+ shift :finally
195
+ shift :lbrace
196
+ finally_body = collect_compiles(:expression, :rbrace)
197
+
198
+ code :finally, finally_body
199
+ end
200
+
155
201
  end
156
202
  end
157
203
  end
@@ -7,16 +7,17 @@ module Liquidscript
7
7
  shift :prop
8
8
 
9
9
  property = action do |ident|
10
- code :property, prop, ident
10
+ code :property, prop, (ident.value || ident.type)
11
11
  end
12
12
 
13
13
  # Just in case there is a property named 'class' or 'module'
14
- code = expect [:identifier, :class, :module] => property
14
+ v = expect [:identifier, :class, :module] => property
15
15
 
16
- expect :lparen => action { compile_call(code) },
17
- :equal => action { compile_assignment(code) },
18
- :prop => action { compile_property(code) },
19
- :_ => action { code }
16
+ expect :lparen => action { compile_call(v) },
17
+ :equal => action { compile_assignment(v) },
18
+ :prop => action { compile_property(v) },
19
+ :unop => action { |o| code :op, v, o },
20
+ :_ => action { v }
20
21
  end
21
22
 
22
23
  def compile_call(subject)
@@ -0,0 +1,28 @@
1
+ module Liquidscript
2
+ module Compiler
3
+ class ICR < Base
4
+ class Heredoc
5
+
6
+ attr_reader :name
7
+ attr_accessor :body
8
+
9
+ include Liquidscript::ICR::Representable
10
+
11
+ def initialize(name, interpolate)
12
+ @name = name
13
+ @interpolate = interpolate
14
+ @body = []
15
+ end
16
+
17
+ def interpolate?
18
+ !!@interpolate
19
+ end
20
+
21
+ def to_a
22
+ [:heredoc, @name, @body]
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -7,17 +7,110 @@ module Liquidscript
7
7
  code :number, pop.value
8
8
  end
9
9
 
10
+ def compile_action
11
+ code :action, shift(:action)
12
+ end
13
+
14
+ def compile_while
15
+ shift :while
16
+ shift :lparen
17
+ conditional = compile_vexpression
18
+ shift :rparen
19
+ shift :lbrace
20
+ body = collect_compiles(:expression, :rbrace)
21
+ code :while, conditional, body
22
+ end
23
+
24
+ def compile_for
25
+ shift :for
26
+ shift :lparen
27
+ if peek?(:identifier)
28
+ ident = shift :identifier
29
+ if peek?(:identifier)
30
+ _compile_for_in(ident)
31
+ else
32
+ _compile_for_seg(compile_identifier(ident))
33
+ end
34
+ else
35
+ compile_for_seg compile_vexpression
36
+ end
37
+ end
38
+
39
+ def _compile_for_in(ident)
40
+ content = shift :identifier
41
+ unless content.value == "in"
42
+ raise CompileError, "Expected `in', got #{content.value}"
43
+ end
44
+
45
+ obj = shift :identifier
46
+ shift :rparen
47
+ shift :lbrace
48
+
49
+ set ident
50
+ body = collect_compiles(:expression, :rbrace)
51
+ code :for_in, ident, ref(obj), body
52
+ end
53
+
54
+ def _compile_for_seg(first)
55
+ shift :comma
56
+ second = compile_vexpression
57
+ shift :comma
58
+ third = compile_vexpression
59
+ shift :rparen
60
+ shift :lbrace
61
+
62
+ body = collect_compiles(:expression, :rbrace)
63
+ code :for_seg, first, second, third, body
64
+ end
65
+
10
66
  def compile_identifier(identifier)
11
67
  default = action do
12
68
  code :get, ref(identifier)
13
69
  end
14
70
 
15
- expect :equal => action { compile_assignment(identifier) },
16
- :prop => action { compile_property(identifier) },
17
- :lparen => action { compile_call(identifier) },
71
+ expect :equal => action { compile_assignment(identifier) },
72
+ :prop => action { compile_property(identifier) },
73
+ :lparen => action { compile_call(identifier) },
74
+ :unop => action { |o| code :op, ref(identifier), o },
18
75
  :_ => default
19
76
  end
20
77
 
78
+ def compile_regex
79
+ code :regex, shift(:regex)
80
+ end
81
+
82
+ def compile_href
83
+ ref = shift :heredoc_ref, :iheredoc_ref
84
+ heredoc = Heredoc.new(ref.value, ref.type == :iheredoc_ref)
85
+ top[:heredocs] ||= []
86
+ top[:herenum] ||= 0
87
+ top[:heredocs] << heredoc
88
+ code :href, heredoc
89
+ end
90
+
91
+ def compile_heredoc
92
+ h = shift(:heredoc, :iheredoc)
93
+
94
+ top[:heredocs][top[:herenum]].body = [h]
95
+ top[:herenum] += 1
96
+ nil
97
+ end
98
+
99
+ def compile_iheredoc_begin
100
+ start = shift :iheredoc_begin
101
+ contents = [start]
102
+
103
+ loop do
104
+ contents << compile_vexpression
105
+ contents << shift(:iheredoc)
106
+ peek?(:istring_begin)
107
+ end
108
+
109
+ top[:heredocs][top[:herenum]].body = contents
110
+ top[:herenum] += 1
111
+ nil
112
+ end
113
+
21
114
  def compile_istring_begin
22
115
  start = shift :istring_begin
23
116
  contents = [start]
@@ -49,9 +142,9 @@ module Liquidscript
49
142
  end
50
143
 
51
144
  def compile_object
52
- shift :lbrack
145
+ shift :lbrace
53
146
 
54
- objects = collect_compiles :rbrack,
147
+ objects = collect_compiles :rbrace,
55
148
  :comma => action.shift,
56
149
  :newline => action.shift do
57
150
  [compile_object_key, compile_vexpression]
@@ -61,9 +154,9 @@ module Liquidscript
61
154
  end
62
155
 
63
156
  def compile_array
64
- shift :lbrace
157
+ shift :lbrack
65
158
 
66
- parts = collect_compiles(:vexpression, :rbrace,
159
+ parts = collect_compiles(:vexpression, :rbrack,
67
160
  :comma => action.shift)
68
161
 
69
162
  code :array, parts
@@ -89,7 +182,7 @@ module Liquidscript
89
182
 
90
183
  def compile_function_with_parameters(parameters)
91
184
  shift :arrow
92
- shift :lbrack
185
+ shift :lbrace
93
186
 
94
187
  expressions = Liquidscript::ICR::Set.new
95
188
  expressions.context = Liquidscript::ICR::Context.new
@@ -107,7 +200,7 @@ module Liquidscript
107
200
  end
108
201
 
109
202
  loop do
110
- expect :rbrack => action.end_loop,
203
+ expect :rbrace => action.end_loop,
111
204
  :_ => expression
112
205
  end
113
206
 
@@ -49,4 +49,10 @@ module Liquidscript
49
49
  end
50
50
  end
51
51
 
52
+ class NoContextError < SyntaxError
53
+ def initialize(context)
54
+ super "Could not find context named #{context.inspect}"
55
+ end
56
+ end
57
+
52
58
  end
@@ -13,7 +13,7 @@ module Liquidscript
13
13
  end
14
14
 
15
15
  def generate
16
- replace(@top, {}).to_s
16
+ replace(@top).to_s
17
17
  end
18
18
 
19
19
  def buffer
@@ -8,12 +8,12 @@ module Liquidscript
8
8
  #
9
9
  # @param code [ICR::Code, #type]
10
10
  # @param context [Hash]
11
- def replace(code, context = {})
11
+ def replace(code)
12
12
  send(:"generate_#{code.type}",
13
13
  code)
14
14
 
15
15
  rescue NoMethodError => e
16
- if e.name == :"_generate_code_#{code.type}"
16
+ if e.name == :"generate_#{code.type}"
17
17
  raise InvalidCodeError.new(code.type)
18
18
  else
19
19
  raise
@@ -1,6 +1,7 @@
1
1
  require "liquidscript/generator/javascript/literals"
2
2
  require "liquidscript/generator/javascript/metas"
3
3
  require "liquidscript/generator/javascript/objects"
4
+ require "liquidscript/generator/javascript/exceptions"
4
5
 
5
6
  module Liquidscript
6
7
  module Generator
@@ -27,11 +28,31 @@ module Liquidscript
27
28
  include Literals
28
29
  include Metas
29
30
  include Objects
31
+ include Exceptions
30
32
 
31
33
  def initialize(top)
32
34
  @modules = []
35
+ @indent = 0
33
36
  super
34
37
  end
38
+
39
+ def indent_level
40
+ " " * @indent
41
+ end
42
+
43
+ def indent!
44
+ @indent += 1
45
+ end
46
+
47
+ def unindent!
48
+ @indent -= 1
49
+ end
50
+
51
+ def insert_into(area, buffer)
52
+ area.inject(buffer) do |m, c|
53
+ m << indent_level << replace(c) << ";\n"
54
+ end
55
+ end
35
56
  end
36
57
  end
37
58
  end