liquidscript 0.0.1
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.
- 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
|