twig_ruby 0.0.1 → 0.0.2
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 +4 -4
- data/lib/tasks/twig_parity.rake +278 -0
- data/lib/twig/auto_hash.rb +7 -1
- data/lib/twig/callable.rb +28 -1
- data/lib/twig/compiler.rb +35 -3
- data/lib/twig/environment.rb +198 -41
- data/lib/twig/error/base.rb +81 -16
- data/lib/twig/error/loader.rb +8 -0
- data/lib/twig/error/logic.rb +8 -0
- data/lib/twig/error/runtime.rb +8 -0
- data/lib/twig/expression_parser/base.rb +30 -0
- data/lib/twig/expression_parser/expression_parsers.rb +57 -0
- data/lib/twig/expression_parser/infix/arrow.rb +31 -0
- data/lib/twig/expression_parser/infix/binary.rb +34 -0
- data/lib/twig/expression_parser/infix/conditional_ternary.rb +39 -0
- data/lib/twig/expression_parser/infix/dot.rb +72 -0
- data/lib/twig/expression_parser/infix/filter.rb +43 -0
- data/lib/twig/expression_parser/infix/function.rb +67 -0
- data/lib/twig/expression_parser/infix/is.rb +53 -0
- data/lib/twig/expression_parser/infix/is_not.rb +19 -0
- data/lib/twig/expression_parser/infix/parses_arguments.rb +84 -0
- data/lib/twig/expression_parser/infix/square_bracket.rb +66 -0
- data/lib/twig/expression_parser/infix_expression_parser.rb +34 -0
- data/lib/twig/expression_parser/prefix/grouping.rb +60 -0
- data/lib/twig/expression_parser/prefix/literal.rb +244 -0
- data/lib/twig/expression_parser/prefix/unary.rb +29 -0
- data/lib/twig/expression_parser/prefix_expression_parser.rb +18 -0
- data/lib/twig/extension/base.rb +26 -4
- data/lib/twig/extension/core.rb +1076 -48
- data/lib/twig/extension/debug.rb +25 -0
- data/lib/twig/extension/escaper.rb +73 -0
- data/lib/twig/extension/rails.rb +10 -57
- data/lib/twig/extension/string_loader.rb +19 -0
- data/lib/twig/extension_set.rb +117 -20
- data/lib/twig/file_extension_escaping_strategy.rb +35 -0
- data/lib/twig/lexer.rb +225 -81
- data/lib/twig/loader/array.rb +25 -8
- data/lib/twig/loader/chain.rb +93 -0
- data/lib/twig/loader/filesystem.rb +106 -7
- data/lib/twig/node/auto_escape.rb +18 -0
- data/lib/twig/node/base.rb +58 -2
- data/lib/twig/node/block.rb +2 -0
- data/lib/twig/node/block_reference.rb +5 -1
- data/lib/twig/node/body.rb +7 -0
- data/lib/twig/node/cache.rb +50 -0
- data/lib/twig/node/capture.rb +22 -0
- data/lib/twig/node/deprecated.rb +53 -0
- data/lib/twig/node/do.rb +19 -0
- data/lib/twig/node/embed.rb +43 -0
- data/lib/twig/node/expression/array.rb +29 -20
- data/lib/twig/node/expression/arrow_function.rb +55 -0
- data/lib/twig/node/expression/assign_name.rb +1 -1
- data/lib/twig/node/expression/binary/and.rb +17 -0
- data/lib/twig/node/expression/binary/base.rb +6 -4
- data/lib/twig/node/expression/binary/boolean.rb +24 -0
- data/lib/twig/node/expression/binary/concat.rb +20 -0
- data/lib/twig/node/expression/binary/elvis.rb +35 -0
- data/lib/twig/node/expression/binary/ends_with.rb +24 -0
- data/lib/twig/node/expression/binary/floor_div.rb +21 -0
- data/lib/twig/node/expression/binary/has_every.rb +20 -0
- data/lib/twig/node/expression/binary/has_some.rb +20 -0
- data/lib/twig/node/expression/binary/in.rb +20 -0
- data/lib/twig/node/expression/binary/matches.rb +24 -0
- data/lib/twig/node/expression/binary/not_in.rb +20 -0
- data/lib/twig/node/expression/binary/null_coalesce.rb +49 -0
- data/lib/twig/node/expression/binary/or.rb +15 -0
- data/lib/twig/node/expression/binary/starts_with.rb +24 -0
- data/lib/twig/node/expression/binary/xor.rb +17 -0
- data/lib/twig/node/expression/block_reference.rb +62 -0
- data/lib/twig/node/expression/call.rb +126 -6
- data/lib/twig/node/expression/constant.rb +3 -1
- data/lib/twig/node/expression/filter/default.rb +37 -0
- data/lib/twig/node/expression/filter/raw.rb +31 -0
- data/lib/twig/node/expression/filter.rb +2 -2
- data/lib/twig/node/expression/function.rb +37 -0
- data/lib/twig/node/expression/get_attribute.rb +51 -7
- data/lib/twig/node/expression/hash.rb +75 -0
- data/lib/twig/node/expression/helper_method.rb +6 -18
- data/lib/twig/node/expression/macro_reference.rb +43 -0
- data/lib/twig/node/expression/name.rb +42 -8
- data/lib/twig/node/expression/operator_escape.rb +13 -0
- data/lib/twig/node/expression/parent.rb +28 -0
- data/lib/twig/node/expression/support_defined_test.rb +23 -0
- data/lib/twig/node/expression/ternary.rb +7 -1
- data/lib/twig/node/expression/test/base.rb +26 -0
- data/lib/twig/node/expression/test/constant.rb +35 -0
- data/lib/twig/node/expression/test/defined.rb +33 -0
- data/lib/twig/node/expression/test/divisible_by.rb +23 -0
- data/lib/twig/node/expression/test/even.rb +21 -0
- data/lib/twig/node/expression/test/iterable.rb +21 -0
- data/lib/twig/node/expression/test/mapping.rb +21 -0
- data/lib/twig/node/expression/test/null.rb +21 -0
- data/lib/twig/node/expression/test/odd.rb +21 -0
- data/lib/twig/node/expression/test/same_as.rb +23 -0
- data/lib/twig/node/expression/test/sequence.rb +21 -0
- data/lib/twig/node/expression/unary/base.rb +3 -1
- data/lib/twig/node/expression/unary/not.rb +18 -0
- data/lib/twig/node/expression/unary/spread.rb +18 -0
- data/lib/twig/node/expression/unary/string_cast.rb +18 -0
- data/lib/twig/node/expression/variable/assign_template.rb +35 -0
- data/lib/twig/node/expression/variable/local.rb +35 -0
- data/lib/twig/node/expression/variable/template.rb +54 -0
- data/lib/twig/node/for.rb +38 -8
- data/lib/twig/node/for_loop.rb +0 -22
- data/lib/twig/node/if.rb +4 -1
- data/lib/twig/node/import.rb +32 -0
- data/lib/twig/node/include.rb +38 -8
- data/lib/twig/node/macro.rb +79 -0
- data/lib/twig/node/module.rb +278 -23
- data/lib/twig/node/output.rb +7 -0
- data/lib/twig/node/print.rb +4 -1
- data/lib/twig/node/set.rb +72 -0
- data/lib/twig/node/text.rb +4 -1
- data/lib/twig/node/with.rb +50 -0
- data/lib/twig/node/yield.rb +6 -1
- data/lib/twig/node_traverser.rb +50 -0
- data/lib/twig/node_visitor/base.rb +30 -0
- data/lib/twig/node_visitor/escaper.rb +165 -0
- data/lib/twig/node_visitor/safe_analysis.rb +127 -0
- data/lib/twig/node_visitor/spreader.rb +39 -0
- data/lib/twig/output_buffer.rb +14 -12
- data/lib/twig/parser.rb +281 -8
- data/lib/twig/rails/config.rb +33 -0
- data/lib/twig/rails/engine.rb +44 -0
- data/lib/twig/rails/renderer.rb +41 -0
- data/lib/twig/runtime/argument_spreader.rb +46 -0
- data/lib/twig/runtime/context.rb +154 -0
- data/lib/twig/runtime/enumerable_hash.rb +51 -0
- data/lib/twig/runtime/escaper.rb +155 -0
- data/lib/twig/runtime/loop_context.rb +81 -0
- data/lib/twig/runtime/loop_iterator.rb +60 -0
- data/lib/twig/runtime/spread.rb +21 -0
- data/lib/twig/runtime_loader/base.rb +12 -0
- data/lib/twig/runtime_loader/factory.rb +23 -0
- data/lib/twig/template.rb +267 -14
- data/lib/twig/template_wrapper.rb +42 -0
- data/lib/twig/token.rb +28 -2
- data/lib/twig/token_parser/apply.rb +48 -0
- data/lib/twig/token_parser/auto_escape.rb +45 -0
- data/lib/twig/token_parser/base.rb +26 -0
- data/lib/twig/token_parser/block.rb +4 -4
- data/lib/twig/token_parser/cache.rb +31 -0
- data/lib/twig/token_parser/deprecated.rb +40 -0
- data/lib/twig/token_parser/do.rb +19 -0
- data/lib/twig/token_parser/embed.rb +62 -0
- data/lib/twig/token_parser/extends.rb +4 -3
- data/lib/twig/token_parser/for.rb +14 -9
- data/lib/twig/token_parser/from.rb +57 -0
- data/lib/twig/token_parser/guard.rb +65 -0
- data/lib/twig/token_parser/if.rb +9 -9
- data/lib/twig/token_parser/import.rb +29 -0
- data/lib/twig/token_parser/include.rb +2 -2
- data/lib/twig/token_parser/macro.rb +109 -0
- data/lib/twig/token_parser/set.rb +76 -0
- data/lib/twig/token_parser/use.rb +54 -0
- data/lib/twig/token_parser/with.rb +36 -0
- data/lib/twig/token_parser/yield.rb +7 -7
- data/lib/twig/token_stream.rb +23 -3
- data/lib/twig/twig_filter.rb +20 -0
- data/lib/twig/twig_function.rb +37 -0
- data/lib/twig/twig_test.rb +31 -0
- data/lib/twig/util/callable_arguments_extractor.rb +227 -0
- data/lib/twig_ruby.rb +21 -2
- metadata +145 -6
- data/lib/twig/context.rb +0 -64
- data/lib/twig/expression_parser.rb +0 -517
- data/lib/twig/railtie.rb +0 -60
|
@@ -3,19 +3,71 @@
|
|
|
3
3
|
module Twig
|
|
4
4
|
module Loader
|
|
5
5
|
class Filesystem < Loader::Base
|
|
6
|
+
MAIN_NAMESPACE = '__main__'
|
|
7
|
+
|
|
6
8
|
def initialize(root_path, paths = [])
|
|
7
9
|
super()
|
|
8
10
|
|
|
9
11
|
@root_path = root_path.to_s
|
|
10
|
-
@paths =
|
|
12
|
+
@paths = {}
|
|
13
|
+
@cache = {}
|
|
14
|
+
@error_cache = {}
|
|
15
|
+
|
|
16
|
+
set_paths(paths)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def exists?(name)
|
|
20
|
+
return true if @cache.key?(name)
|
|
21
|
+
|
|
22
|
+
!find_template(name, throw: false).nil?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def paths(namespace = MAIN_NAMESPACE)
|
|
26
|
+
@paths[namespace] || []
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def set_paths(paths, namespace = MAIN_NAMESPACE)
|
|
30
|
+
paths = [paths] unless paths.is_a?(::Array)
|
|
31
|
+
|
|
32
|
+
@paths[namespace] = []
|
|
33
|
+
|
|
34
|
+
paths.each do |path|
|
|
35
|
+
add_path(path, namespace)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def add_path(path, namespace = MAIN_NAMESPACE)
|
|
40
|
+
@cache = {}
|
|
41
|
+
@error_cache = {}
|
|
42
|
+
check_path = path[0] == '/' ? path : File.join(@root_path, path)
|
|
43
|
+
|
|
44
|
+
unless File.directory?(check_path)
|
|
45
|
+
raise Error::Loader, "The \"#{path}\" directory does not exist (#{check_path})."
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
@paths[namespace] ||= []
|
|
49
|
+
@paths[namespace] << path
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def prepend_path(path, namespace = MAIN_NAMESPACE)
|
|
53
|
+
@cache = {}
|
|
54
|
+
@error_cache = {}
|
|
55
|
+
check_path = path[0] == '/' ? path : File.join(@root_path, path)
|
|
56
|
+
|
|
57
|
+
unless File.directory?(check_path)
|
|
58
|
+
raise Error::Loader, "The \"#{path}\" directory does not exist (#{check_path})."
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@paths[namespace] ||= []
|
|
62
|
+
@paths[namespace].unshift(path)
|
|
11
63
|
end
|
|
12
64
|
|
|
13
65
|
def get_source_context(name)
|
|
14
66
|
if (file = find_template(name))
|
|
15
|
-
return Source.new(File.read(file), name)
|
|
67
|
+
return Source.new(File.read(file), name, file)
|
|
16
68
|
end
|
|
17
69
|
|
|
18
|
-
raise "Unable to find
|
|
70
|
+
raise Error::Loader, "Unable to find template \"#{name}\" (looked into: #{@paths.inspect})."
|
|
19
71
|
end
|
|
20
72
|
|
|
21
73
|
def get_cache_key(name)
|
|
@@ -34,11 +86,58 @@ module Twig
|
|
|
34
86
|
|
|
35
87
|
private
|
|
36
88
|
|
|
37
|
-
def find_template(name)
|
|
38
|
-
@
|
|
39
|
-
|
|
40
|
-
|
|
89
|
+
def find_template(name, throw: true)
|
|
90
|
+
return @cache[name] if @cache.key?(name)
|
|
91
|
+
|
|
92
|
+
begin
|
|
93
|
+
namespace, shortname = parse_name(name)
|
|
94
|
+
rescue Error::Loader => e
|
|
95
|
+
return nil unless throw
|
|
96
|
+
raise e if throw
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
unless @paths.key?(namespace)
|
|
100
|
+
@error_cache[name] = "There are no registered paths for namespace \"#{namespace}\"."
|
|
101
|
+
|
|
102
|
+
unless throw
|
|
103
|
+
return nil
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
raise Error::Loader, @error_cache[name]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
paths(namespace).each do |path|
|
|
110
|
+
absolute = File.join(path, shortname)
|
|
111
|
+
|
|
112
|
+
unless path[0] == '/'
|
|
113
|
+
absolute = File.join(@root_path, absolute)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
if File.file?(absolute)
|
|
117
|
+
return @cache[name] = absolute
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
@error_cache[name] = "Unable to find template \"#{name}\" (looked into: #{@paths.inspect})."
|
|
122
|
+
|
|
123
|
+
unless throw
|
|
124
|
+
return nil
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
raise Error::Loader, @error_cache[name]
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def parse_name(name)
|
|
131
|
+
if name[0] == '@'
|
|
132
|
+
if (pos = name.index('/')).nil?
|
|
133
|
+
raise Error::Loader, "Malformed namespaced template name \"#{name}\" " \
|
|
134
|
+
'(expecting "@namespace/template_name").'
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
return [name[1...pos], name[(pos + 1)..]]
|
|
41
138
|
end
|
|
139
|
+
|
|
140
|
+
[MAIN_NAMESPACE, name]
|
|
42
141
|
end
|
|
43
142
|
end
|
|
44
143
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
class AutoEscape < Node::Base
|
|
6
|
+
# @param [String, FalseClass] value
|
|
7
|
+
# @param [Node::Base] body
|
|
8
|
+
# @param [Integer] lineno
|
|
9
|
+
def initialize(value, body, lineno)
|
|
10
|
+
super({ body: }, { value: }, lineno)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def compile(compiler)
|
|
14
|
+
compiler.subcompile(nodes[:body])
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/twig/node/base.rb
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'output'
|
|
4
|
+
|
|
3
5
|
module Twig
|
|
4
6
|
module Node
|
|
5
7
|
class Base
|
|
6
|
-
attr_reader :tag
|
|
8
|
+
attr_reader :tag
|
|
9
|
+
|
|
10
|
+
# @return [Integer]
|
|
11
|
+
attr_reader :lineno
|
|
7
12
|
|
|
8
13
|
# @return [Hash]
|
|
9
14
|
attr_reader :attributes
|
|
@@ -11,7 +16,7 @@ module Twig
|
|
|
11
16
|
# @return [Source]
|
|
12
17
|
attr_reader :source_context
|
|
13
18
|
|
|
14
|
-
# @return [AutoHash
|
|
19
|
+
# @return [AutoHash{[Symbol, Integer] => Node::Base}]
|
|
15
20
|
attr_reader :nodes
|
|
16
21
|
|
|
17
22
|
# @param [Hash<Node::Base>] nodes
|
|
@@ -56,6 +61,57 @@ module Twig
|
|
|
56
61
|
def template_name
|
|
57
62
|
source_context.name
|
|
58
63
|
end
|
|
64
|
+
|
|
65
|
+
# @return [Integer]
|
|
66
|
+
def length
|
|
67
|
+
nodes.length
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def empty?
|
|
71
|
+
nodes.empty?
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def to_s
|
|
75
|
+
repr = +''
|
|
76
|
+
repr << self.class.name
|
|
77
|
+
|
|
78
|
+
if @tag
|
|
79
|
+
repr << "\n tag: #{@tag}"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
attr = attributes.map do |name, value|
|
|
83
|
+
v = if value.is_a?(Proc) || value.is_a?(Method)
|
|
84
|
+
'\Closure'
|
|
85
|
+
elsif value.is_a?(String)
|
|
86
|
+
value
|
|
87
|
+
else
|
|
88
|
+
value.inspect
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
"#{name}: #{v}"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
unless attr.empty?
|
|
95
|
+
repr << "\n attributes:\n #{attr.join("\n ")}"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
unless empty?
|
|
99
|
+
repr << "\n nodes:"
|
|
100
|
+
|
|
101
|
+
nodes.each do |name, node|
|
|
102
|
+
len = name.to_s.length + 6
|
|
103
|
+
node_repr = []
|
|
104
|
+
|
|
105
|
+
node.to_s.each_line do |line|
|
|
106
|
+
node_repr << ((' ' * len) + line.rstrip)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
repr << "\n #{name}: #{node_repr.join("\n").lstrip}"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
repr
|
|
114
|
+
end
|
|
59
115
|
end
|
|
60
116
|
end
|
|
61
117
|
end
|
data/lib/twig/node/block.rb
CHANGED
|
@@ -3,13 +3,17 @@
|
|
|
3
3
|
module Twig
|
|
4
4
|
module Node
|
|
5
5
|
class BlockReference < Node::Base
|
|
6
|
+
include Output
|
|
7
|
+
|
|
6
8
|
def initialize(name, lineno)
|
|
7
9
|
super({}, { name: }, lineno)
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
def compile(compiler)
|
|
11
13
|
compiler.
|
|
12
|
-
|
|
14
|
+
add_debug_info(self).
|
|
15
|
+
write('context.output_buffer.safe_append = ').
|
|
16
|
+
raw("render_block(:#{attributes[:name]}, context, blocks)").
|
|
13
17
|
raw("\n")
|
|
14
18
|
end
|
|
15
19
|
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
class Cache < Node::Base
|
|
6
|
+
def initialize(arguments, body, lineno)
|
|
7
|
+
super({ arguments:, body: }, {}, lineno)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def compile(compiler)
|
|
11
|
+
compiler.
|
|
12
|
+
add_debug_info(self).
|
|
13
|
+
# Cache method just writes strings onto the buffer, it doesn't return the fragment
|
|
14
|
+
# so we can capture any output to the main buffer and output that instead
|
|
15
|
+
write("context.output_buffer.safe_append = context.call_context.capture do\n").
|
|
16
|
+
indent.
|
|
17
|
+
write('context.call_context.cache(')
|
|
18
|
+
|
|
19
|
+
first = true
|
|
20
|
+
nodes[:arguments].nodes.each_value do |argument|
|
|
21
|
+
compiler.raw(', ') unless first
|
|
22
|
+
first = false
|
|
23
|
+
|
|
24
|
+
compiler.subcompile(argument)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
compiler.
|
|
28
|
+
raw(") do\n").
|
|
29
|
+
indent.
|
|
30
|
+
# inside a capture block the original buffer is capturing so it's OK if we push strings there
|
|
31
|
+
write("context.original_buffer.safe_append = context.buffer_and_return do\n").
|
|
32
|
+
indent
|
|
33
|
+
|
|
34
|
+
compiler.
|
|
35
|
+
write("context.push_stack\n").
|
|
36
|
+
subcompile(nodes[:body]).
|
|
37
|
+
raw("\n").
|
|
38
|
+
write("context.pop_stack\n")
|
|
39
|
+
|
|
40
|
+
compiler.
|
|
41
|
+
write("end.to_s\n").
|
|
42
|
+
outdent.
|
|
43
|
+
write("end\n").
|
|
44
|
+
outdent.
|
|
45
|
+
write("end\n").
|
|
46
|
+
outdent
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
class Capture < Node::Base
|
|
6
|
+
# @param [Node::Base] body
|
|
7
|
+
# @param [Integer] lineno
|
|
8
|
+
def initialize(body, lineno)
|
|
9
|
+
super({ body: }, { raw: false }, lineno)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def compile(compiler)
|
|
13
|
+
compiler.
|
|
14
|
+
raw("context.buffer_and_return do\n").
|
|
15
|
+
indent.
|
|
16
|
+
subcompile(nodes[:body]).
|
|
17
|
+
outdent.
|
|
18
|
+
write("end.to_s.html_safe\n")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
class Deprecated < Base
|
|
6
|
+
def initialize(expr, lineno)
|
|
7
|
+
super({ expr: }, {}, lineno)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def compile(compiler)
|
|
11
|
+
compiler.add_debug_info(self)
|
|
12
|
+
|
|
13
|
+
expr = nodes[:expr]
|
|
14
|
+
|
|
15
|
+
unless expr.is_a?(Expression::Constant)
|
|
16
|
+
var_name = compiler.var_name
|
|
17
|
+
compiler.
|
|
18
|
+
write("#{var_name} = ").
|
|
19
|
+
subcompile(expr).
|
|
20
|
+
raw("\n")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
compiler.write('::Twig::Extension::Core.deprecation_notice(')
|
|
24
|
+
|
|
25
|
+
if expr.is_a?(Expression::Constant)
|
|
26
|
+
compiler.subcompile(expr)
|
|
27
|
+
else
|
|
28
|
+
compiler.write(var_name)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
compiler.
|
|
32
|
+
raw(', ').
|
|
33
|
+
repr(template_name).
|
|
34
|
+
raw(', ').
|
|
35
|
+
repr(lineno)
|
|
36
|
+
|
|
37
|
+
if (package = nodes.fetch(:package, nil))
|
|
38
|
+
compiler.
|
|
39
|
+
raw(', package: ').
|
|
40
|
+
subcompile(package)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if (version = nodes.fetch(:version, nil))
|
|
44
|
+
compiler.
|
|
45
|
+
raw(', version: ').
|
|
46
|
+
subcompile(version)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
compiler.raw(")\n")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/twig/node/do.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
class Do < Node::Base
|
|
6
|
+
# @param [Node::Expression::Base] expr
|
|
7
|
+
# @param [Integer] lineno
|
|
8
|
+
def initialize(expr, lineno)
|
|
9
|
+
super({ expr: }, {}, lineno)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def compile(compiler)
|
|
13
|
+
compiler.
|
|
14
|
+
subcompile(nodes[:expr], raw: false).
|
|
15
|
+
raw("\n")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'include'
|
|
4
|
+
|
|
5
|
+
module Twig
|
|
6
|
+
module Node
|
|
7
|
+
class Embed < Include
|
|
8
|
+
# we don't inject the module to avoid node visitors to traverse it twice (as it will
|
|
9
|
+
# be already visited in the main module)
|
|
10
|
+
def initialize(name, index, variables, only, ignore_missing, lineno)
|
|
11
|
+
super(
|
|
12
|
+
Expression::Constant.new('not_used', lineno),
|
|
13
|
+
variables,
|
|
14
|
+
only,
|
|
15
|
+
ignore_missing,
|
|
16
|
+
lineno
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
attributes[:name] = name
|
|
20
|
+
attributes[:index] = index
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def add_get_template(compiler, template = '')
|
|
26
|
+
compiler.
|
|
27
|
+
raw('load(').
|
|
28
|
+
string(attributes[:name]).
|
|
29
|
+
raw(', ').
|
|
30
|
+
repr(lineno).
|
|
31
|
+
raw(', ').
|
|
32
|
+
string(attributes[:index]).
|
|
33
|
+
raw(')')
|
|
34
|
+
|
|
35
|
+
if attributes[:ignore_missing]
|
|
36
|
+
compiler.
|
|
37
|
+
raw("\n").
|
|
38
|
+
write("#{template}.get_parent(context)\n")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -1,48 +1,57 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'support_defined_test'
|
|
4
|
+
|
|
3
5
|
module Twig
|
|
4
6
|
module Node
|
|
5
7
|
module Expression
|
|
6
8
|
class Array < Expression::Base
|
|
9
|
+
include Expression::SupportDefinedTest
|
|
10
|
+
|
|
11
|
+
# @param [AutoHash] elements
|
|
12
|
+
# @param [Integer] lineno
|
|
7
13
|
def initialize(elements, lineno)
|
|
8
14
|
super(elements, {}, lineno)
|
|
9
|
-
|
|
10
|
-
@index = -1
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
# @param [Expression::Base] value
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if key.nil?
|
|
17
|
-
@index += 1
|
|
18
|
-
key = Constant.new(@index, value.lineno)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
nodes.add(key, value)
|
|
18
|
+
def add_element(value)
|
|
19
|
+
nodes.add(value)
|
|
22
20
|
end
|
|
23
21
|
|
|
24
22
|
def compile(compiler)
|
|
23
|
+
if define_test_enabled?
|
|
24
|
+
return compiler.repr(true)
|
|
25
|
+
end
|
|
26
|
+
|
|
25
27
|
compiler.
|
|
26
|
-
raw('
|
|
28
|
+
raw('[').
|
|
27
29
|
indent
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
first = true
|
|
32
|
+
|
|
33
|
+
values.each do |value|
|
|
34
|
+
unless first
|
|
35
|
+
compiler.raw(', ')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
first = false
|
|
39
|
+
|
|
30
40
|
compiler.
|
|
31
|
-
subcompile(
|
|
32
|
-
raw(' => ').
|
|
33
|
-
subcompile(value).
|
|
34
|
-
raw(', ')
|
|
41
|
+
subcompile(value)
|
|
35
42
|
end
|
|
36
43
|
|
|
37
44
|
compiler.
|
|
38
45
|
outdent.
|
|
39
|
-
raw('
|
|
46
|
+
raw(']')
|
|
40
47
|
end
|
|
41
48
|
|
|
42
|
-
|
|
49
|
+
def values
|
|
50
|
+
nodes.values
|
|
51
|
+
end
|
|
43
52
|
|
|
44
|
-
def
|
|
45
|
-
|
|
53
|
+
def each_value(&)
|
|
54
|
+
values.each(&)
|
|
46
55
|
end
|
|
47
56
|
end
|
|
48
57
|
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
class ArrowFunction < Expression::Base
|
|
7
|
+
# @param [Expression::Base] expr
|
|
8
|
+
# @param [Node::Nodes] names
|
|
9
|
+
# @param [Integer] lineno
|
|
10
|
+
def initialize(expr, names, lineno)
|
|
11
|
+
if !names.is_a?(Expression::Array) && !names.is_a?(Expression::Variable::Context)
|
|
12
|
+
raise Error::Syntax.new(
|
|
13
|
+
'The arrow function argument must be a list of variables or a single variable.',
|
|
14
|
+
names.lineno,
|
|
15
|
+
names.source_context
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if names.is_a?(Expression::Variable::Context)
|
|
20
|
+
names = Expression::Array.new(AutoHash.new.add(
|
|
21
|
+
Expression::Variable::AssignContext.new(names.attributes[:name], names.lineno)
|
|
22
|
+
), names.lineno)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
super({ expr:, names: }, {}, lineno)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def compile(compiler)
|
|
29
|
+
compiler.
|
|
30
|
+
add_debug_info(self).
|
|
31
|
+
raw('-> (')
|
|
32
|
+
|
|
33
|
+
first = true
|
|
34
|
+
nodes[:names].each_value do |name|
|
|
35
|
+
compiler.raw(', ') unless first
|
|
36
|
+
compiler.raw("__#{name.attributes[:name]}__")
|
|
37
|
+
first = false
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
compiler.raw(') { ')
|
|
41
|
+
|
|
42
|
+
nodes[:names].nodes.each_value do |name|
|
|
43
|
+
compiler.
|
|
44
|
+
raw("context[:#{name.attributes[:name]}] = ").
|
|
45
|
+
raw("__#{name.attributes[:name]}__; ")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
compiler.
|
|
49
|
+
subcompile(nodes[:expr]).
|
|
50
|
+
raw('}')
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -10,7 +10,7 @@ module Twig
|
|
|
10
10
|
# @param [Integer] lineno
|
|
11
11
|
def initialize(name, lineno)
|
|
12
12
|
if %w[true false none null nil].include?(name.downcase)
|
|
13
|
-
raise Error::Syntax.new("You cannot assign a value to #{name}", lineno)
|
|
13
|
+
raise Error::Syntax.new("You cannot assign a value to \"#{name}\".", lineno, source_context)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
super
|
|
@@ -31,6 +31,9 @@ module Twig
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
OPERATORS = {
|
|
34
|
+
BitwiseOr: '|',
|
|
35
|
+
BitwiseXor: '^',
|
|
36
|
+
BitwiseAnd: '&',
|
|
34
37
|
Equal: '==',
|
|
35
38
|
NotEqual: '!=',
|
|
36
39
|
Spaceship: '<=>',
|
|
@@ -39,14 +42,13 @@ module Twig
|
|
|
39
42
|
LessEqual: '<=',
|
|
40
43
|
GreaterEqual: '>=',
|
|
41
44
|
|
|
42
|
-
|
|
43
|
-
Xor: '^',
|
|
44
|
-
And: '&&',
|
|
45
|
+
Range: '..',
|
|
45
46
|
Add: '+',
|
|
46
47
|
Sub: '-',
|
|
47
|
-
Concat: '+',
|
|
48
48
|
Mul: '*',
|
|
49
49
|
Div: '/',
|
|
50
|
+
Mod: '%',
|
|
51
|
+
Power: '**',
|
|
50
52
|
}.freeze
|
|
51
53
|
|
|
52
54
|
# Lots of simple operator classes can just be generated dynamically
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
module Binary
|
|
7
|
+
class Boolean < Binary::Base
|
|
8
|
+
def compile(compiler)
|
|
9
|
+
compiler.
|
|
10
|
+
raw('(::Twig::Extension::Core.bool(').
|
|
11
|
+
subcompile(nodes[:left]).
|
|
12
|
+
raw(') ')
|
|
13
|
+
|
|
14
|
+
operator(compiler)
|
|
15
|
+
|
|
16
|
+
compiler.raw(' ::Twig::Extension::Core.bool(').
|
|
17
|
+
subcompile(nodes[:right]).
|
|
18
|
+
raw('))')
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|