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.
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,18 @@
1
+ require "liquidscript/icr/representable"
2
+ require "liquidscript/icr/code"
3
+ require "liquidscript/icr/set"
4
+ require "liquidscript/icr/sexp"
5
+ require "liquidscript/icr/context"
6
+ require "liquidscript/icr/variable"
7
+
8
+ module Liquidscript
9
+
10
+ # The ICR (rather, Intermediate Code Representation)
11
+ # is a method used to transform compiled code into
12
+ # the corresponding javascript code. It can be used
13
+ # to optimize the code first, ensuring that the
14
+ # resultant code is fast. The point here is to
15
+ # represent the code, and make it seem nice.
16
+ module ICR
17
+ end
18
+ end
@@ -0,0 +1,68 @@
1
+ module Liquidscript
2
+ module ICR
3
+
4
+ # An individual code point. This is normally in
5
+ # a set. A code will have an action, and arguments
6
+ # that accompany that action. The arguments list
7
+ # can be however long.
8
+ class Code
9
+
10
+ # The action that this code is associated with.
11
+ # This should be a symbol.
12
+ #
13
+ # @return [Symbol]
14
+ attr_reader :action
15
+
16
+ # The arguments that are used for this action.
17
+ # This is an array.
18
+ #
19
+ # @return [Array]
20
+ attr_reader :arguments
21
+
22
+ alias_method :type, :action
23
+
24
+ include Representable
25
+
26
+ # Initializes the code. It takes an action and
27
+ # an argument as its arguments. The action
28
+ # should not change from this point forward.
29
+ #
30
+ # @param action [Symbol]
31
+ # @param arguments [Array]
32
+ def initialize(action, *arguments)
33
+ @action = action
34
+ @arguments = arguments
35
+ end
36
+
37
+ # Turns the code into an array, containing the
38
+ # action and the arguments. Note that changing
39
+ # this array will not change the code.
40
+ #
41
+ # @return [Array]
42
+ def to_a
43
+ [@action, *@arguments]
44
+ end
45
+
46
+ # If we don't respond to it, the @arguments array
47
+ # might. Ask them if they do, and if they don't,
48
+ # respond accordingly.
49
+ #
50
+ # @param method [Symbol] the method to check.
51
+ # @param include_private [Boolean] whether or not to
52
+ # include private methods.
53
+ # @return [Boolean]
54
+ def respond_to_missing?(method, include_private = false)
55
+ @arguments.respond_to?(method)
56
+ end
57
+
58
+ # Send the method to @arguments if it doesn't
59
+ # exist here.
60
+ #
61
+ # @return [Object]
62
+ def method_missing(method, *args, &block)
63
+ @arguments.public_send(method, *args, &block)
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,94 @@
1
+ module Liquidscript
2
+ module ICR
3
+
4
+ # Handles variables within blocks. Each variable will get a
5
+ # reference in each context. When retrieving the value of
6
+ # a variable, if the variable was not introduced in the scope,
7
+ # it will look to its parent for the value of the variable.
8
+ # When setting the value of a variable, a new variable is
9
+ # forcibly created.
10
+ class Context
11
+
12
+ # The variables that are allowed to be used as a global scope,
13
+ # i.e. used in a `get` context without a previous `set`.
14
+ DEFAULT_ALLOWED_VARIABLES = [
15
+ :window, :global, :exports, :console, :this
16
+ ]
17
+
18
+ # The parent of the current context.
19
+ #
20
+ # @return [Parent]
21
+ attr_accessor :parent
22
+
23
+ # The variables that are a part of this context.
24
+ #
25
+ # @return [Hash<Symbol, Variable>]
26
+ attr_reader :variables
27
+
28
+ # The variables that are allowed to be used as a global scope,
29
+ # i.e. used in a `get` context without a previous set.
30
+ #
31
+ # @see [DEFAULT_ALLOWED_VARIABLES]
32
+ # @return [Array<Symbol>]
33
+ attr_reader :allowed_variables
34
+
35
+ include Representable
36
+
37
+ # Initializes the context.
38
+ def initialize
39
+ @variables = {}
40
+ @allowed_variables = [DEFAULT_ALLOWED_VARIABLES].flatten
41
+ end
42
+
43
+ # Returns a variable reference. If checks the local variables
44
+ # first; if it doesn't exist there, then if the type is `:get`,
45
+ # checks the parent; otherwise, sets the value of the variable.
46
+ # If there is no parent and the type is `:get`, it raises an
47
+ # {InvalidReferenceError}.
48
+ #
49
+ # @param name [Symbol] the name of the variable.
50
+ # @param type [Symbol] the type of use. Should be `:get` or
51
+ # `:set`.
52
+ # @return [Variable]
53
+ def variable(name, type)
54
+ @variables.fetch(name) do
55
+ if type == :set
56
+ @variables[name] = Variable.new(self, name)
57
+ elsif allowed_variables.include?(name)
58
+ Variable.new(self, name)
59
+ elsif type == :get && parent
60
+ parent.get(name)
61
+ else
62
+ raise InvalidReferenceError.new(name)
63
+ end
64
+ end
65
+ end
66
+
67
+ # All of the parameter variables.
68
+ #
69
+ # @return [Array<Variable>]
70
+ def parameters
71
+ @variables.values.select(&:parameter?)
72
+ end
73
+
74
+ # (see #variable).
75
+ #
76
+ # Passes `:get` as type.
77
+ def get(name)
78
+ variable(name, :get)
79
+ end
80
+
81
+ # (see #variable).
82
+ #
83
+ # Passes `:set` as type.
84
+ def set(name)
85
+ variable(name, :set)
86
+ end
87
+
88
+ def to_a
89
+ @variables.keys
90
+ end
91
+
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,39 @@
1
+ module Liquidscript
2
+ module ICR
3
+
4
+ # Used to show that a specific element of the ICR is representable
5
+ # as an array. It will forward the methods #to_s and #inspect to
6
+ # the #to_a method, expecting the including module to define it.
7
+ module Representable
8
+
9
+ extend Forwardable
10
+ include Comparable
11
+
12
+ def_delegators :to_a, :to_s, :inspect, :[], :each, :'<=>'
13
+
14
+
15
+ def to_ary
16
+ to_a
17
+ end
18
+
19
+ def to_yaml
20
+ to_a!.to_yaml
21
+ end
22
+
23
+ def to_a!
24
+ do_map = proc do |e|
25
+ if e.is_a?(Representable)
26
+ e.to_a!
27
+ elsif e.is_a? Array
28
+ e.map(&do_map)
29
+ else
30
+ e
31
+ end
32
+ end
33
+
34
+ to_a.map(&do_map)
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,147 @@
1
+ module Liquidscript
2
+ module ICR
3
+
4
+ # Represents a set of instruction codes. Can contain
5
+ # metadata about the set, like whether or not it can
6
+ # be inlined, if a new context needs to be applied,
7
+ # etc.
8
+ class Set < Code
9
+
10
+ # The metadata that is applied to the set.
11
+ #
12
+ # @return [Hash]
13
+ attr_reader :metadata
14
+
15
+ include Representable
16
+
17
+ # Initialize the set.
18
+ def initialize
19
+ @metadata = {}
20
+ @code = []
21
+ @action = :exec
22
+ end
23
+
24
+ #
25
+ def context
26
+ @metadata.fetch(:context) do
27
+ @metadata.fetch(:parent).context
28
+ end
29
+ end
30
+
31
+ #
32
+ def context=(new_context)
33
+ @metadata[:context] = new_context
34
+ end
35
+
36
+ # Adds a code to the code list. This is just a
37
+ # convienince method.
38
+ #
39
+ # @param action [Symbol] a symbol representing
40
+ # the action.
41
+ # @param arguments the arguments for the code.
42
+ def add(action, *arguments)
43
+ @code << Code.new(action, arguments)
44
+ end
45
+
46
+ # A list of all the local variables in the
47
+ # current scope. Local variables are defined
48
+ # as variables that were a) not passed in by
49
+ # function execution as arguments and b) are
50
+ # set within the current context.
51
+ #
52
+ # @return [Array<Symbol>]
53
+ def locals
54
+ variables - parameters
55
+ end
56
+
57
+ # A list of components (or arguments) that are
58
+ # in the current scope. Defined as variables
59
+ # that were passed in by function execution as
60
+ # arguments.
61
+ #
62
+ # @return [Array<Symbol>]
63
+ def parameters
64
+ context.parameters.map(&:name)
65
+ end
66
+
67
+ # A list of _all_ variables in the current
68
+ # scope.
69
+ #
70
+ # @return [Array<Symbol>]
71
+ def variables
72
+ context.variables.keys - context.allowed_variables
73
+ end
74
+
75
+ # Turns the set into an array. Includes the
76
+ # metadata information and the actual internal
77
+ # array.
78
+ # Note that this is _not_ the array used in
79
+ # {#method_missing} - that actually operates on
80
+ # the internal array.
81
+ #
82
+ # @return [Array]
83
+ def to_a
84
+ [
85
+ @action,
86
+ *@metadata.to_a.map { |(m, i)| [:"_#{m}", i] },
87
+ *@code
88
+ ]
89
+ end
90
+
91
+ # Outputs the codes in this set.
92
+ #
93
+ # @return [Array<Code>]
94
+ def codes
95
+ @code
96
+ end
97
+
98
+ # Access either the metadata or the codes. If
99
+ # the accessor is a Symbol, it access the metadata;
100
+ # if it the accessor is a Numeric, it access the
101
+ # codes.
102
+ #
103
+ # @param key [Symbol, Numeric] the key.
104
+ # @return [Object]
105
+ def [](key)
106
+ if key.is_a? Numeric
107
+ @code[key]
108
+ else
109
+ @metadata[key]
110
+ end
111
+ end
112
+
113
+ # Sets something from the metadata. Unlike the
114
+ # accessor, it does not distinguish between
115
+ # Numeric and Symbol keys.
116
+ #
117
+ # @param key [Object] the key.
118
+ # @param value [Object] the value.
119
+ # @return [Object]
120
+ def []=(key, value)
121
+ @metadata[key] = value
122
+ end
123
+
124
+ # Tells ruby that we respond to some methods.
125
+ # Passes the method name to the internal
126
+ # array, asking if it responds to it.
127
+ #
128
+ # @param method [Symbol] the method to check.
129
+ # @param include_private [Boolean] whether or not
130
+ # to include private methods.
131
+ # @return [Boolean] whether or not we respond
132
+ # to that method.
133
+ def respond_to_missing?(method, include_private = false)
134
+ @code.respond_to?(method, include_private)
135
+ end
136
+
137
+ # For methods that we don't respond to, send
138
+ # them to the interal array.
139
+ #
140
+ # @return [Object]
141
+ def method_missing(method, *args, &block)
142
+ @code.public_send(method, *args, &block)
143
+ end
144
+
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,41 @@
1
+ module Liquidscript
2
+ module ICR
3
+
4
+ class ::Array; def to_sexp; Sexp.new(self).output; end; end
5
+
6
+ # @private
7
+ class Sexp
8
+
9
+ def initialize(compiler)
10
+ @compiler = compiler
11
+ @depth = 0
12
+ end
13
+
14
+ def output
15
+ out(@compiler).strip
16
+ end
17
+
18
+ private
19
+
20
+ def out(v)
21
+ if v.is_a?(Representable) || v.is_a?(Array)
22
+ @depth += 1
23
+ body = ["\n", " " * @depth, "(",
24
+ v.to_a.map {|d| out d }.join(' '),
25
+ ")"].join
26
+ @depth -= 1
27
+ body
28
+ else
29
+ body = v.to_s.gsub(/\"/, "\\\"")
30
+
31
+ if body.include? " "
32
+ "\"#{body}\""
33
+ else
34
+ body
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,68 @@
1
+ module Liquidscript
2
+ module ICR
3
+
4
+ # Represents a variable. It can hold a value, but it will not
5
+ # be used to reconstruct the variable itself.
6
+ class Variable
7
+
8
+ # The context in which this variable exists. The variable
9
+ # should exist in one and only one context, but can be used
10
+ # in contexts other than its own.
11
+ #
12
+ # @return [Context]
13
+ attr_reader :context
14
+
15
+ # The name of the variable that this represents. This will
16
+ # be used in both ICR and in the final output.
17
+ #
18
+ # @return [Symbol]
19
+ attr_reader :name
20
+
21
+ # The set that describes the value of this variable. The
22
+ # set just so happens to describe the value of the variable;
23
+ # it is not used to define the variable's value.
24
+ #
25
+ # @return [Code]
26
+ attr_accessor :value
27
+
28
+ include Representable
29
+
30
+ def initialize(context, name)
31
+ @context = context
32
+ @name = name
33
+ @value = nil
34
+ end
35
+
36
+ # Make this class compatible with the #type based system.
37
+ #
38
+ # @return [Symbol]
39
+ def type
40
+ :variable
41
+ end
42
+
43
+ # Marks this variable as an argument to a function. This is to
44
+ # let the context know not to show it in certain cases.
45
+ #
46
+ # @return [self]
47
+ def parameter!
48
+ @parameter = true
49
+ self
50
+ end
51
+
52
+ # Whether or not the variable is an argument to a function.
53
+ #
54
+ # @see {#parameter!}
55
+ # @return [Boolean]
56
+ def parameter?
57
+ @parameter
58
+ end
59
+
60
+ # Turns the variable into an array.
61
+ #
62
+ # @return [Array<(Symbol, Symbol)>]
63
+ def to_a
64
+ [:_variable, @name]
65
+ end
66
+ end
67
+ end
68
+ end