liquidscript 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +11 -0
  6. data/Guardfile +9 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +59 -0
  9. data/Rakefile +25 -0
  10. data/lib/liquidscript.rb +11 -0
  11. data/lib/liquidscript/buffer.rb +34 -0
  12. data/lib/liquidscript/compiler.rb +9 -0
  13. data/lib/liquidscript/compiler/base.rb +101 -0
  14. data/lib/liquidscript/compiler/base/action.rb +39 -0
  15. data/lib/liquidscript/compiler/base/blank.rb +24 -0
  16. data/lib/liquidscript/compiler/base/callable.rb +51 -0
  17. data/lib/liquidscript/compiler/base/helpers.rb +207 -0
  18. data/lib/liquidscript/compiler/icr.rb +40 -0
  19. data/lib/liquidscript/compiler/icr/classes.rb +59 -0
  20. data/lib/liquidscript/compiler/icr/expressions.rb +94 -0
  21. data/lib/liquidscript/compiler/icr/functions.rb +42 -0
  22. data/lib/liquidscript/compiler/icr/helpers.rb +20 -0
  23. data/lib/liquidscript/compiler/icr/literals.rb +106 -0
  24. data/lib/liquidscript/errors.rb +51 -0
  25. data/lib/liquidscript/generator.rb +11 -0
  26. data/lib/liquidscript/generator/base.rb +25 -0
  27. data/lib/liquidscript/generator/base/dsl.rb +19 -0
  28. data/lib/liquidscript/generator/base/replacements.rb +33 -0
  29. data/lib/liquidscript/generator/context.rb +7 -0
  30. data/lib/liquidscript/generator/javascript.rb +37 -0
  31. data/lib/liquidscript/generator/javascript/literals.rb +63 -0
  32. data/lib/liquidscript/generator/javascript/metas.rb +41 -0
  33. data/lib/liquidscript/generator/javascript/objects.rb +137 -0
  34. data/lib/liquidscript/icr.rb +18 -0
  35. data/lib/liquidscript/icr/code.rb +68 -0
  36. data/lib/liquidscript/icr/context.rb +94 -0
  37. data/lib/liquidscript/icr/representable.rb +39 -0
  38. data/lib/liquidscript/icr/set.rb +147 -0
  39. data/lib/liquidscript/icr/sexp.rb +41 -0
  40. data/lib/liquidscript/icr/variable.rb +68 -0
  41. data/lib/liquidscript/scanner.rb +40 -0
  42. data/lib/liquidscript/scanner/lexer.rl +106 -0
  43. data/lib/liquidscript/scanner/token.rb +37 -0
  44. data/lib/liquidscript/template.rb +16 -0
  45. data/lib/liquidscript/version.rb +5 -0
  46. data/liquidscript.gemspec +27 -0
  47. data/spec/fixtures/class.compile.yml +26 -0
  48. data/spec/fixtures/class.generate.yml +31 -0
  49. data/spec/fixtures/combination.generate.yml +33 -0
  50. data/spec/fixtures/complex.generate.yml +20 -0
  51. data/spec/fixtures/expression.generate.yml +4 -0
  52. data/spec/fixtures/function.generate.yml +11 -0
  53. data/spec/fixtures/get.generate.yml +5 -0
  54. data/spec/fixtures/literals.generate.yml +8 -0
  55. data/spec/fixtures/main.compile.yml +32 -0
  56. data/spec/fixtures/set.generate.yml +4 -0
  57. data/spec/fixtures/string.generate.yml +6 -0
  58. data/spec/lib/liquidscript/buffer_spec.rb +14 -0
  59. data/spec/lib/liquidscript/compiler/icr_spec.rb +139 -0
  60. data/spec/lib/liquidscript/generator/javascript_spec.rb +15 -0
  61. data/spec/lib/liquidscript/icr/code_spec.rb +0 -0
  62. data/spec/lib/liquidscript/icr/context_spec.rb +36 -0
  63. data/spec/lib/liquidscript/icr/set_spec.rb +59 -0
  64. data/spec/lib/liquidscript/scanner/lexer_spec.rb +58 -0
  65. data/spec/lib/liquidscript/scanner/token_spec.rb +0 -0
  66. data/spec/lib/liquidscript/scanner_spec.rb +21 -0
  67. data/spec/spec_helper.rb +30 -0
  68. data/spec/support/helpers/lexer_helper.rb +5 -0
  69. data/spec/support/matchers/be_token.rb +9 -0
  70. data/spec/support/matchers/compile.rb +41 -0
  71. data/spec/support/matchers/generate.rb +46 -0
  72. metadata +210 -0
@@ -0,0 +1,106 @@
1
+ module Liquidscript
2
+ module Compiler
3
+ class ICR < Base
4
+ module Literals
5
+
6
+ def compile_number
7
+ code :number, pop.value
8
+ end
9
+
10
+ def compile_identifier(identifier)
11
+ default = action do
12
+ code :get, ref(identifier)
13
+ end
14
+
15
+ expect :equal => action { compile_assignment(identifier) },
16
+ :prop => action { compile_property(identifier) },
17
+ :lparen => action { compile_call(identifier) },
18
+ :_ => default
19
+ end
20
+
21
+ def compile_dstring
22
+ code :dstring, pop.value[1..-2]
23
+ end
24
+
25
+ def compile_sstring
26
+ code :sstring, pop.value[1..-1]
27
+ end
28
+
29
+ def compile_keyword
30
+ code :keyword, shift(:keyword), compile_expression
31
+ end
32
+
33
+ def compile_object
34
+ shift :lbrack
35
+
36
+ objects = []
37
+ compile_object = action do
38
+ objects << [compile_object_key, compile_expression]
39
+ end
40
+
41
+ loop do
42
+ expect :rbrack => action.end_loop,
43
+ :comma => action.shift,
44
+ [:identifier, :dstring] => compile_object
45
+ end
46
+
47
+ code :object, objects
48
+ end
49
+
50
+ def compile_array
51
+ shift :lbrace
52
+
53
+ parts = []
54
+ compile_part = action { parts << compile_expression }
55
+
56
+ loop do
57
+ expect :rbrace => action.end_loop,
58
+ :comma => action.shift,
59
+ :_ => compile_part
60
+ end
61
+
62
+ code :array, parts
63
+ end
64
+
65
+ def compile_object_key
66
+ key = shift :identifier, :dstring
67
+ shift :colon
68
+
69
+ key
70
+ end
71
+
72
+ def compile_function
73
+ compile_function_with_parameters([])
74
+ end
75
+
76
+ def compile_function_with_parameters(parameter)
77
+ shift :arrow
78
+ shift :lbrack
79
+
80
+ expressions = Liquidscript::ICR::Set.new
81
+ expressions.context = Liquidscript::ICR::Context.new
82
+ expressions.context.parent = top.context
83
+ expressions[:arguments] = parameter
84
+ @set << expressions
85
+
86
+ parameter.each do |parameter|
87
+ set(parameter).parameter!
88
+ end
89
+
90
+
91
+ expression = action do
92
+ expressions << compile_expression
93
+ end
94
+
95
+ loop do
96
+ expect :rbrack => action.end_loop,
97
+ :_ => expression
98
+ end
99
+
100
+ code :function, @set.pop
101
+ end
102
+
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,51 @@
1
+ module Liquidscript
2
+
3
+ class Error < ::StandardError; end
4
+
5
+ class SyntaxError < Error; end
6
+ class CompileError < Error; end
7
+ class GeneratorError < Error; end
8
+
9
+ class UnexpectedEndError < CompileError; end
10
+ class InvalidReferenceError < CompileError
11
+
12
+ def initialize(name)
13
+ super "No variable named #{name}"
14
+ end
15
+ end
16
+ class UnexpectedError < CompileError
17
+ def initialize(expected, got)
18
+ @expected = expected
19
+ @got = got
20
+
21
+ super build_error_message
22
+ end
23
+
24
+ private
25
+
26
+ def build_error_message
27
+ str = "Expected one of %{expected}, got %{type}"
28
+ hash = {
29
+ :expected => @expected.map { |e| e.to_s.upcase }.join(', ')
30
+ }
31
+
32
+ if @got.is_a? Symbol
33
+ hash[:type] = @got.to_s.upcase
34
+ else
35
+ str << " (line %{line}, column %{column})"
36
+ hash.merge! :type => @got.type.to_s.upcase,
37
+ :line => @got.line,
38
+ :column => @got.column
39
+ end
40
+
41
+ sprintf(str, hash)
42
+ end
43
+ end
44
+
45
+ class InvalidCodeError < GeneratorError
46
+ def initialize(code)
47
+ super "Could not generate code for `#{code.to_s.upcase}`"
48
+ end
49
+ end
50
+
51
+ end
@@ -0,0 +1,11 @@
1
+ require "hashie"
2
+ require "liquidscript/generator/base"
3
+ require "liquidscript/generator/context"
4
+ require "liquidscript/generator/javascript"
5
+
6
+ module Liquidscript
7
+
8
+ module Generator
9
+
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ require "liquidscript/generator/base/dsl"
2
+ require "liquidscript/generator/base/replacements"
3
+
4
+ module Liquidscript
5
+ module Generator
6
+
7
+ class Base
8
+
9
+ include Replacements
10
+
11
+ def initialize(top)
12
+ @top = top
13
+ end
14
+
15
+ def generate
16
+ replace(@top, {}).to_s
17
+ end
18
+
19
+ def buffer
20
+ Buffer.new
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module Liquidscript
2
+ module Generator
3
+ class Base
4
+ module DSL
5
+ module ClassMethods
6
+
7
+ def to_generate(code, &block)
8
+ define_method(:"generate_#{code}", &block)
9
+ protected :"generate_#{code}"
10
+ end
11
+ end
12
+
13
+ def self.included(base)
14
+ base.extend ClassMethods
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,33 @@
1
+ module Liquidscript
2
+ module Generator
3
+ class Base
4
+ module Replacements
5
+
6
+ # Replace a code with a string. This uses the replacement
7
+ # definitions that are a part of the class.
8
+ #
9
+ # @param code [ICR::Code, #type]
10
+ # @param context [Hash]
11
+ def replace(code, context = {})
12
+ send(:"generate_#{code.type}",
13
+ code)
14
+
15
+ rescue NoMethodError => e
16
+ if e.name == :"_generate_code_#{code.type}"
17
+ raise InvalidCodeError.new(code.type)
18
+ else
19
+ raise
20
+ end
21
+ end
22
+
23
+ # Access to the replacements method on the class.
24
+ #
25
+ # @see [ClassMethods#replacements]
26
+ # @return [Hash]
27
+ def replacements
28
+ self.class.replacements
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,7 @@
1
+ module Liquidscript
2
+ module Generator
3
+ class Context < Hashie::Mash
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,37 @@
1
+ require "liquidscript/generator/javascript/literals"
2
+ require "liquidscript/generator/javascript/metas"
3
+ require "liquidscript/generator/javascript/objects"
4
+
5
+ module Liquidscript
6
+ module Generator
7
+
8
+ # A list of all of the possible codes for javascript:
9
+ #
10
+ # - `:set` ✔
11
+ # - `:get` ✔
12
+ # - `:exec` ✔
13
+ # - `:expression` ✔
14
+ # - `:class` ✔
15
+ # - `:module` ✔
16
+ # - `:property` ✔
17
+ # - `:call` ✔
18
+ # - `:number` ✔
19
+ # - `:sstring` ✔
20
+ # - `:dstring` ✔
21
+ # - `:object` ✔
22
+ # - `:array` ✔
23
+ # - `:function` ✔
24
+ #
25
+ # Each one of these must have a generate function.
26
+ class Javascript < Base
27
+ include Literals
28
+ include Metas
29
+ include Objects
30
+
31
+ def initialize(top)
32
+ @modules = []
33
+ super
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,63 @@
1
+ module Liquidscript
2
+ module Generator
3
+ class Javascript < Base
4
+ module Literals
5
+
6
+ def generate_number(code)
7
+
8
+ "#{code.first}"
9
+ end
10
+
11
+ def generate_dstring(code)
12
+
13
+ "\"#{code.first.gsub(/"/, '\\"')}\""
14
+ end
15
+
16
+ def generate_sstring(code)
17
+
18
+ "'#{code.first.gsub(/'/, "\\'")}'"
19
+ end
20
+
21
+ def generate_keyword(code)
22
+ " #{code[1].value} #{replace(code[2])}"
23
+ end
24
+
25
+ def generate_object(code)
26
+
27
+ object = buffer
28
+ object.set_join! ', '
29
+
30
+ code[1].inject(object) do |buf, part|
31
+ buf << "\"#{part[0].value}\": #{replace(part[1])}"
32
+ end
33
+
34
+ "{#{object}}"
35
+ end
36
+
37
+ def generate_array(code)
38
+
39
+ array = buffer
40
+ array.set_join! ', '
41
+
42
+ code[1].inject(array) do |a, p|
43
+ a << replace(p)
44
+ end
45
+
46
+ "[#{array}]"
47
+ end
48
+
49
+ def generate_function(code)
50
+
51
+ function = buffer
52
+
53
+ function <<
54
+ "function(" <<
55
+ code[1].parameters.join(',') <<
56
+ ') {' <<
57
+ replace(code[1]) <<
58
+ '}'
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,41 @@
1
+ module Liquidscript
2
+ module Generator
3
+ class Javascript
4
+ module Metas
5
+
6
+ def generate_exec(code)
7
+
8
+ exec = buffer
9
+ exec << _exec_context(code)
10
+ code.codes.inject(exec) do |m, c|
11
+ m << replace(c)
12
+ m
13
+ end
14
+ end
15
+
16
+ def generate_set(code)
17
+ case code[1].type
18
+ when :variable
19
+ "#{code[1].name} = #{replace code[2]};"
20
+ when :property
21
+ "#{replace code[1]} = #{replace code[2]};"
22
+ end
23
+ end
24
+
25
+ def generate_get(code)
26
+
27
+ "#{code[1].name}"
28
+ end
29
+
30
+ protected
31
+
32
+ def _exec_context(code)
33
+
34
+ unless code.locals.empty?
35
+ "var #{code.locals.join(',')}; "
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,137 @@
1
+ module Liquidscript
2
+ module Generator
3
+ class Javascript
4
+ module Objects
5
+
6
+ def generate_expression(code)
7
+ "(#{replace(code[1].first)})"
8
+ end
9
+
10
+ def generate_call(code)
11
+ call = buffer
12
+ args = buffer
13
+ args.set_join! ','
14
+
15
+ case code[1].type
16
+ when :identifier
17
+ call << "#{code[1].value}"
18
+ else
19
+ call << "#{replace(code[1])}"
20
+ end
21
+
22
+ code[2..-1].inject(args) do |b, arg|
23
+ b << replace(arg)
24
+ end
25
+
26
+ call << "(" << args << ")"
27
+ end
28
+
29
+ def generate_property(code)
30
+ prop = buffer
31
+
32
+ case code[1].type
33
+ when :identifier
34
+ prop << code[1].value
35
+ when :variable
36
+ prop << code[1].name
37
+ else
38
+ prop << replace(code[1])
39
+ end
40
+
41
+ prop << "." << code[2].value
42
+ end
43
+
44
+ def generate_class(code)
45
+ body = buffer
46
+ class_name = code[1].value
47
+
48
+ in_module(class_name) do |last_module|
49
+ body <<
50
+ "#{class_name} = function #{class_name}(){" <<
51
+ "if(this.initialize) {" <<
52
+ "this.initialize.apply(this, arguments);" <<
53
+ "}};"
54
+
55
+ code[2].each do |(k, v)|
56
+ case k.type
57
+ when :identifier
58
+ body <<
59
+ "#{class_name}.prototype.#{k.value} =" <<
60
+ replace(v) << ";"
61
+ when :dstring
62
+ body <<
63
+ "#{class_name}.prototype[#{k.value}] =" <<
64
+ replace(v) << ";"
65
+ when :prop
66
+ if k[1].name != :this
67
+ raise InvalidCodeError.new(v[1].name)
68
+ end
69
+
70
+ body <<
71
+ "#{class_name}.#{k[2].value} = " <<
72
+ replace(v) << ";"
73
+ end
74
+ end
75
+
76
+ if last_module
77
+ body <<
78
+ "#{last_module}.#{class_name} = " <<
79
+ "#{class_name};"
80
+ end
81
+
82
+ end
83
+
84
+ body
85
+ end
86
+
87
+ def generate_module(code)
88
+ body = buffer
89
+ module_name = code[1].value
90
+
91
+ in_module(module_name) do |last_module|
92
+ body << "#{module_name} = {};"
93
+
94
+ code[2].each do |part|
95
+ k = part[0]
96
+ v = part[1]
97
+ case k
98
+ when :identifier
99
+ body <<
100
+ "#{module_name}.#{k.value} = " <<
101
+ replace(v) << ";"
102
+ when :dstring
103
+ body <<
104
+ "#{module_name}[#{k.value}] = " <<
105
+ replace(v) << ";"
106
+ when :class
107
+ body << generate_class(part)
108
+ end
109
+ end
110
+
111
+ if last_module
112
+ body <<
113
+ "#{last_module}.#{module_name} = " <<
114
+ "#{module_name};"
115
+ end
116
+ end
117
+
118
+ body
119
+ end
120
+
121
+ protected
122
+
123
+ def current_module
124
+ @modules.last
125
+ end
126
+
127
+ def in_module(module_name)
128
+ @modules << module_name
129
+ out = yield @modules[-2]
130
+ @modules.pop
131
+ out
132
+ end
133
+
134
+ end
135
+ end
136
+ end
137
+ end