antlers 0.8.2 → 0.9.0
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/antlers/elements.rb +9 -4
- data/lib/antlers/lexer.rb +17 -25
- data/lib/antlers/parser.rb +7 -4
- data/lib/antlers/version.rb +1 -1
- data/lib/antlers.rb +2 -4
- data/lib/interfaces/lexeme.rb +24 -1
- data/lib/lexemes/prop_lexeme.rb +0 -23
- data/lib/lexemes/var_lexeme.rb +26 -0
- data/lib/nodes/prop_node.rb +1 -1
- data/lib/nodes/slot_node.rb +2 -2
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f16d22b587d7dbdc07a0a51fc19032271be9347e90eb09c77541a56099f8088f
|
|
4
|
+
data.tar.gz: b1437b4cac8a748fc23fc6eaf06c07e5d3111d63d5100651afb9195f488dacfb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ecc5de204a45f9cda60f03aeefc49aee735fc9aa3da5fd20b1d12959497bfb4683ab299bd64d4ae8795b3296ab9e018c8b8eb70672f3788aeeeaf8355f03d07e
|
|
7
|
+
data.tar.gz: 0b14edede169971914c9958f4b3369c361271566d36c883dd3c1774ef968e8299d2d95c58a90e921ea2bbae5d70f4a2634c8ce00217e058c2ee6c71a9ec3a42f
|
data/lib/antlers/elements.rb
CHANGED
|
@@ -8,10 +8,8 @@ module Antlers
|
|
|
8
8
|
|
|
9
9
|
plug(:root) do
|
|
10
10
|
plug(:node) do
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
RootNode
|
|
14
|
-
end
|
|
11
|
+
require_relative '../nodes/root_node'
|
|
12
|
+
RootNode
|
|
15
13
|
end
|
|
16
14
|
end
|
|
17
15
|
|
|
@@ -127,6 +125,13 @@ module Antlers
|
|
|
127
125
|
VarNode
|
|
128
126
|
end
|
|
129
127
|
end
|
|
128
|
+
|
|
129
|
+
plug(:lexeme) do
|
|
130
|
+
lazy do
|
|
131
|
+
require_relative '../lexemes/var_lexeme'
|
|
132
|
+
VarLexeme
|
|
133
|
+
end
|
|
134
|
+
end
|
|
130
135
|
end
|
|
131
136
|
end
|
|
132
137
|
end
|
data/lib/antlers/lexer.rb
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../
|
|
3
|
+
require_relative '../lexemes/var_lexeme'
|
|
4
4
|
|
|
5
5
|
module Antlers
|
|
6
|
-
extend Queries
|
|
7
|
-
|
|
8
6
|
class LexerError < StandardError; end
|
|
9
7
|
|
|
10
8
|
class Lexer
|
|
11
9
|
def initialize(lexeme_types:)
|
|
12
|
-
@
|
|
13
|
-
@
|
|
10
|
+
@lexeme_types = lexeme_types.to_a
|
|
11
|
+
@var_lexeme = @lexeme_types.find { it == VarLexeme }
|
|
12
|
+
|
|
13
|
+
@delimiters = ['<{', '}>']
|
|
14
|
+
@delimiters = [*@delimiters, '{', '}'] if @var_lexeme
|
|
15
|
+
|
|
14
16
|
@keywords = @lexeme_types.flat_map { |lexeme| lexeme.const_get(:KEYWORDS) }
|
|
15
17
|
@cursor = 0
|
|
16
18
|
end
|
|
@@ -23,8 +25,8 @@ module Antlers
|
|
|
23
25
|
segments = template.split(/(#{Regexp.union(@delimiters)})/).map(&:strip)
|
|
24
26
|
|
|
25
27
|
until segments[@cursor].nil?
|
|
26
|
-
if (
|
|
27
|
-
sequence << antlers_lexeme(
|
|
28
|
+
if (segment = antlers_segment(segments:))
|
|
29
|
+
sequence << antlers_lexeme(segment:, segments:)
|
|
28
30
|
# Skipping: ['{', 'expression', '}']
|
|
29
31
|
# Skipping: ['<{', 'name + props + keywords', '}>']
|
|
30
32
|
@cursor += 3
|
|
@@ -47,20 +49,21 @@ module Antlers
|
|
|
47
49
|
next_segment
|
|
48
50
|
end
|
|
49
51
|
|
|
50
|
-
def antlers_lexeme(
|
|
51
|
-
|
|
52
|
+
def antlers_lexeme(segment:, segments:)
|
|
53
|
+
name, props, keywords = parse_antlers_segment(segment:)
|
|
52
54
|
|
|
53
|
-
|
|
55
|
+
return @var_lexeme.lexeme(segment:, raw: false) if @var_lexeme && brackets?(segments:)
|
|
54
56
|
|
|
55
57
|
lexeme = @lexeme_types.find { it.match?(name:, keywords:) }
|
|
56
58
|
return lexeme.lexeme(name:, props:, keywords:) if lexeme
|
|
57
|
-
return var(antlers_segment:, raw: true) if deerheads?(segments:)
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
return @var_lexeme.lexeme(segment:, raw: true) if @var_lexeme && deerheads?(segments:)
|
|
61
|
+
|
|
62
|
+
raise LexerError, "Unrecognised syntax: '#{segment}'"
|
|
60
63
|
end
|
|
61
64
|
|
|
62
|
-
def
|
|
63
|
-
name_and_props, *keywords =
|
|
65
|
+
def parse_antlers_segment(segment:)
|
|
66
|
+
name_and_props, *keywords = segment.split(/(#{Regexp.union(@keywords)})/)
|
|
64
67
|
name, *props = name_and_props.split(' ')
|
|
65
68
|
[name, props, parse_keywords(keywords:)]
|
|
66
69
|
end
|
|
@@ -81,8 +84,6 @@ module Antlers
|
|
|
81
84
|
!(string.start_with?(':') || string.end_with?(':'))
|
|
82
85
|
end
|
|
83
86
|
|
|
84
|
-
# TODO: Refactor every constant, match and result method into its own class. Loop through every class and return the first match.
|
|
85
|
-
|
|
86
87
|
def brackets?(segments:)
|
|
87
88
|
first, _, last = segments[@cursor..@cursor + 3].map(&:strip)
|
|
88
89
|
first == '{' && last == '}'
|
|
@@ -92,14 +93,5 @@ module Antlers
|
|
|
92
93
|
first, _, last = segments[@cursor..@cursor + 3].map(&:strip)
|
|
93
94
|
first == '<{' && last == '}>'
|
|
94
95
|
end
|
|
95
|
-
|
|
96
|
-
def var(antlers_segment:, raw: false)
|
|
97
|
-
# String is already interpolated or not depending on user input on the template layer, now we store it without those template quotes.
|
|
98
|
-
antlers_segment = antlers_segment[1..-2] if Queries.user_defined_string?(antlers_segment)
|
|
99
|
-
|
|
100
|
-
return { raw_var: antlers_segment } if raw
|
|
101
|
-
|
|
102
|
-
{ var: antlers_segment }
|
|
103
|
-
end
|
|
104
96
|
end
|
|
105
97
|
end
|
data/lib/antlers/parser.rb
CHANGED
|
@@ -4,12 +4,15 @@ module Antlers
|
|
|
4
4
|
class Parser
|
|
5
5
|
class ParserError < StandardError; end
|
|
6
6
|
|
|
7
|
-
def initialize(namespace: nil
|
|
7
|
+
def initialize(node_types:, namespace: nil)
|
|
8
|
+
@node_types = node_types.to_a
|
|
8
9
|
@namespace = namespace
|
|
9
|
-
@
|
|
10
|
+
@template = nil
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
def parse(sequence:, id: :root_node)
|
|
13
|
+
def parse(sequence:, template: nil, id: :root_node)
|
|
14
|
+
@template = template
|
|
15
|
+
|
|
13
16
|
branch(node: RootNode.new(name: id), sequence:)
|
|
14
17
|
end
|
|
15
18
|
|
|
@@ -20,7 +23,7 @@ module Antlers
|
|
|
20
23
|
child_class = @node_types.find { |n| n.match?(segment:) }
|
|
21
24
|
raise(ParserError, "No node matches #{segment}") unless child_class
|
|
22
25
|
|
|
23
|
-
child = child_class.build(segment:, namespace: @namespace)
|
|
26
|
+
child = child_class.build(segment:, namespace: @namespace, template: @template)
|
|
24
27
|
node.children << child
|
|
25
28
|
|
|
26
29
|
if (end_key = child_class::END_KEY)
|
data/lib/antlers/version.rb
CHANGED
data/lib/antlers.rb
CHANGED
|
@@ -13,10 +13,8 @@ module Antlers
|
|
|
13
13
|
|
|
14
14
|
class << self
|
|
15
15
|
def ast(template:, namespace: nil, elements: Elements[*DEFAULT_ELEMENTS])
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
sequence = Lexer.new(lexeme_types: elements[:lexeme].to_a).parse(template:)
|
|
19
|
-
Parser.new(namespace:, node_types: elements[:node].to_a).parse(sequence:)
|
|
16
|
+
sequence = Lexer.new(lexeme_types: elements[:lexeme]).parse(template:)
|
|
17
|
+
Parser.new(namespace:, node_types: elements[:node]).parse(sequence:, template:)
|
|
20
18
|
end
|
|
21
19
|
|
|
22
20
|
def render(ast:, current_binding:, parent_binding: nil, slot_node: nil)
|
data/lib/interfaces/lexeme.rb
CHANGED
|
@@ -6,8 +6,31 @@ module Antlers
|
|
|
6
6
|
|
|
7
7
|
def match?(name: nil, keywords: {}) = false
|
|
8
8
|
|
|
9
|
-
def lexeme(name:, props:, keywords:)
|
|
9
|
+
def lexeme(name:, props:, keywords:, segment: nil, raw: false)
|
|
10
10
|
raise NotImplementedError
|
|
11
11
|
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def props(props)
|
|
16
|
+
odd_props = props.join(' ').split(/(=)|\s/)
|
|
17
|
+
|
|
18
|
+
return {} unless odd_props.any?
|
|
19
|
+
|
|
20
|
+
props = {}
|
|
21
|
+
until odd_props.empty?
|
|
22
|
+
prop = odd_props.shift
|
|
23
|
+
value = nil
|
|
24
|
+
|
|
25
|
+
if odd_props.first == '='
|
|
26
|
+
odd_props.shift
|
|
27
|
+
value = odd_props.shift
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
props[prop.to_sym] = value
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
props
|
|
34
|
+
end
|
|
12
35
|
end
|
|
13
36
|
end
|
data/lib/lexemes/prop_lexeme.rb
CHANGED
|
@@ -16,28 +16,5 @@ module Antlers
|
|
|
16
16
|
prop[:props] = props(props) unless props.empty?
|
|
17
17
|
prop
|
|
18
18
|
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def props(props)
|
|
23
|
-
odd_props = props.join(' ').split(/(=)|\s/)
|
|
24
|
-
|
|
25
|
-
return {} unless odd_props.any?
|
|
26
|
-
|
|
27
|
-
props = {}
|
|
28
|
-
until odd_props.empty?
|
|
29
|
-
prop = odd_props.shift
|
|
30
|
-
value = nil
|
|
31
|
-
|
|
32
|
-
if odd_props.first == '='
|
|
33
|
-
odd_props.shift
|
|
34
|
-
value = odd_props.shift
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
props[prop.to_sym] = value
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
props
|
|
41
|
-
end
|
|
42
19
|
end
|
|
43
20
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../interfaces/lexeme'
|
|
4
|
+
require_relative '../support/queries'
|
|
5
|
+
|
|
6
|
+
module Antlers
|
|
7
|
+
module VarLexeme
|
|
8
|
+
include Lexeme
|
|
9
|
+
extend Queries
|
|
10
|
+
extend self
|
|
11
|
+
|
|
12
|
+
# Variables are special and are matched by the lexer.
|
|
13
|
+
def match?(**)
|
|
14
|
+
false
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def lexeme(segment:, raw:, **)
|
|
18
|
+
# String is already interpolated or not depending on user input on the template layer, now we store it without those template quotes.
|
|
19
|
+
segment = segment[1..-2] if Queries.user_defined_string?(segment)
|
|
20
|
+
|
|
21
|
+
return { raw_var: segment } if raw
|
|
22
|
+
|
|
23
|
+
{ var: segment }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/nodes/prop_node.rb
CHANGED
data/lib/nodes/slot_node.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Antlers
|
|
|
14
14
|
|
|
15
15
|
attr_accessor :children
|
|
16
16
|
|
|
17
|
-
def initialize(name:, namespace:, props:
|
|
17
|
+
def initialize(name:, namespace:, props: {}, children: [], **)
|
|
18
18
|
super(name:, props:, children:)
|
|
19
19
|
|
|
20
20
|
@namespace = namespace
|
|
@@ -43,7 +43,7 @@ module Antlers
|
|
|
43
43
|
segment[DEF_KEY]
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
def build(segment:, namespace
|
|
46
|
+
def build(segment:, namespace:, **)
|
|
47
47
|
new(name: segment[DEF_KEY], props: segment[:props], namespace:)
|
|
48
48
|
end
|
|
49
49
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: antlers
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- maedi
|
|
@@ -87,6 +87,7 @@ files:
|
|
|
87
87
|
- lib/lexemes/if_lexeme.rb
|
|
88
88
|
- lib/lexemes/prop_lexeme.rb
|
|
89
89
|
- lib/lexemes/slot_lexeme.rb
|
|
90
|
+
- lib/lexemes/var_lexeme.rb
|
|
90
91
|
- lib/lexemes/yield_lexeme.rb
|
|
91
92
|
- lib/modules/namespace.rb
|
|
92
93
|
- lib/modules/props.rb
|