liquidscript 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/Gemfile +11 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +59 -0
- data/Rakefile +25 -0
- data/lib/liquidscript.rb +11 -0
- data/lib/liquidscript/buffer.rb +34 -0
- data/lib/liquidscript/compiler.rb +9 -0
- data/lib/liquidscript/compiler/base.rb +101 -0
- data/lib/liquidscript/compiler/base/action.rb +39 -0
- data/lib/liquidscript/compiler/base/blank.rb +24 -0
- data/lib/liquidscript/compiler/base/callable.rb +51 -0
- data/lib/liquidscript/compiler/base/helpers.rb +207 -0
- data/lib/liquidscript/compiler/icr.rb +40 -0
- data/lib/liquidscript/compiler/icr/classes.rb +59 -0
- data/lib/liquidscript/compiler/icr/expressions.rb +94 -0
- data/lib/liquidscript/compiler/icr/functions.rb +42 -0
- data/lib/liquidscript/compiler/icr/helpers.rb +20 -0
- data/lib/liquidscript/compiler/icr/literals.rb +106 -0
- data/lib/liquidscript/errors.rb +51 -0
- data/lib/liquidscript/generator.rb +11 -0
- data/lib/liquidscript/generator/base.rb +25 -0
- data/lib/liquidscript/generator/base/dsl.rb +19 -0
- data/lib/liquidscript/generator/base/replacements.rb +33 -0
- data/lib/liquidscript/generator/context.rb +7 -0
- data/lib/liquidscript/generator/javascript.rb +37 -0
- data/lib/liquidscript/generator/javascript/literals.rb +63 -0
- data/lib/liquidscript/generator/javascript/metas.rb +41 -0
- data/lib/liquidscript/generator/javascript/objects.rb +137 -0
- data/lib/liquidscript/icr.rb +18 -0
- data/lib/liquidscript/icr/code.rb +68 -0
- data/lib/liquidscript/icr/context.rb +94 -0
- data/lib/liquidscript/icr/representable.rb +39 -0
- data/lib/liquidscript/icr/set.rb +147 -0
- data/lib/liquidscript/icr/sexp.rb +41 -0
- data/lib/liquidscript/icr/variable.rb +68 -0
- data/lib/liquidscript/scanner.rb +40 -0
- data/lib/liquidscript/scanner/lexer.rl +106 -0
- data/lib/liquidscript/scanner/token.rb +37 -0
- data/lib/liquidscript/template.rb +16 -0
- data/lib/liquidscript/version.rb +5 -0
- data/liquidscript.gemspec +27 -0
- data/spec/fixtures/class.compile.yml +26 -0
- data/spec/fixtures/class.generate.yml +31 -0
- data/spec/fixtures/combination.generate.yml +33 -0
- data/spec/fixtures/complex.generate.yml +20 -0
- data/spec/fixtures/expression.generate.yml +4 -0
- data/spec/fixtures/function.generate.yml +11 -0
- data/spec/fixtures/get.generate.yml +5 -0
- data/spec/fixtures/literals.generate.yml +8 -0
- data/spec/fixtures/main.compile.yml +32 -0
- data/spec/fixtures/set.generate.yml +4 -0
- data/spec/fixtures/string.generate.yml +6 -0
- data/spec/lib/liquidscript/buffer_spec.rb +14 -0
- data/spec/lib/liquidscript/compiler/icr_spec.rb +139 -0
- data/spec/lib/liquidscript/generator/javascript_spec.rb +15 -0
- data/spec/lib/liquidscript/icr/code_spec.rb +0 -0
- data/spec/lib/liquidscript/icr/context_spec.rb +36 -0
- data/spec/lib/liquidscript/icr/set_spec.rb +59 -0
- data/spec/lib/liquidscript/scanner/lexer_spec.rb +58 -0
- data/spec/lib/liquidscript/scanner/token_spec.rb +0 -0
- data/spec/lib/liquidscript/scanner_spec.rb +21 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/helpers/lexer_helper.rb +5 -0
- data/spec/support/matchers/be_token.rb +9 -0
- data/spec/support/matchers/compile.rb +41 -0
- data/spec/support/matchers/generate.rb +46 -0
- 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,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,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
|