hotcell 0.1.0 → 0.2.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/README.md +102 -84
- data/Rakefile +2 -2
- data/ext/lexerc/lexerc.c +350 -308
- data/ext/lexerc/lexerc.h +2 -7
- data/ext/lexerc/lexerc.rl +9 -90
- data/lib/hotcell/commands/for.rb +7 -2
- data/lib/hotcell/config.rb +2 -1
- data/lib/hotcell/extensions.rb +13 -1
- data/lib/hotcell/lexer.rb +5 -10
- data/lib/hotcell/lexer.rl +95 -0
- data/lib/hotcell/lexerr.rb +256 -215
- data/lib/hotcell/lexerr.rl +7 -91
- data/lib/hotcell/manipulator.rb +20 -2
- data/lib/hotcell/node/{calculator.rb → expression.rb} +4 -2
- data/lib/hotcell/node/tag.rb +5 -3
- data/lib/hotcell/node.rb +1 -1
- data/lib/hotcell/parser.rb +565 -514
- data/lib/hotcell/parser.y +46 -24
- data/lib/hotcell/template.rb +3 -2
- data/lib/hotcell/version.rb +1 -1
- data/lib/hotcell.rb +1 -1
- data/spec/lib/hotcell/commands/for_spec.rb +3 -0
- data/spec/lib/hotcell/config_spec.rb +6 -0
- data/spec/lib/hotcell/lexer_spec.rb +28 -17
- data/spec/lib/hotcell/manipulator_spec.rb +16 -11
- data/spec/lib/hotcell/node/block_spec.rb +2 -2
- data/spec/lib/hotcell/parser_spec.rb +113 -30
- data/spec/lib/hotcell/template_spec.rb +51 -1
- data/spec/lib/hotcell_spec.rb +1 -0
- metadata +4 -3
data/ext/lexerc/lexerc.h
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
#define regexp_possible rb_funcall(self, rb_intern("regexp_possible"), 0)
|
2
|
+
|
1
3
|
#define emit_tag rb_funcall(self, rb_intern("emit_tag"), 0)
|
2
4
|
#define emit_operator rb_funcall(self, rb_intern("emit_operator"), 0)
|
3
5
|
#define emit_numeric rb_funcall(self, rb_intern("emit_numeric"), 0)
|
@@ -11,10 +13,3 @@
|
|
11
13
|
#define raise_unterminated_string rb_funcall(self, rb_intern("raise_unterminated_string"), 0)
|
12
14
|
#define raise_unterminated_regexp rb_funcall(self, rb_intern("raise_unterminated_regexp"), 0)
|
13
15
|
#define raise_unexpected_symbol rb_funcall(self, rb_intern("raise_unexpected_symbol"), 0)
|
14
|
-
|
15
|
-
#define regexp_ambiguity(block) { \
|
16
|
-
if (rb_funcall(self, rb_intern("regexp_possible?"), 0) == Qfalse) { \
|
17
|
-
emit_operator; \
|
18
|
-
block; \
|
19
|
-
} \
|
20
|
-
}
|
data/ext/lexerc/lexerc.rl
CHANGED
@@ -1,98 +1,17 @@
|
|
1
1
|
%%{
|
2
2
|
machine puffer_lexer;
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
and = '&&';
|
13
|
-
or = '||';
|
14
|
-
not = '!';
|
15
|
-
equal = '==';
|
16
|
-
inequal = '!=';
|
17
|
-
gt = '>';
|
18
|
-
gte = '>=';
|
19
|
-
lt = '<';
|
20
|
-
lte = '<=';
|
21
|
-
logic = and | or | not | equal | inequal | gt | gte | lt | lte;
|
22
|
-
|
23
|
-
assign = '=';
|
24
|
-
comma = ',';
|
25
|
-
period = '.';
|
26
|
-
colon = ':';
|
27
|
-
question = '?';
|
28
|
-
semicolon = ';';
|
29
|
-
newline = '\n';
|
30
|
-
flow = assign | comma | period | colon | question | semicolon | newline;
|
31
|
-
|
32
|
-
array_open = '[';
|
33
|
-
array_close = ']';
|
34
|
-
hash_open = '{';
|
35
|
-
hash_close = '}';
|
36
|
-
bracket_open = '(';
|
37
|
-
bracket_close = ')';
|
38
|
-
structure = array_open | array_close | hash_open | hash_close | bracket_open | bracket_close;
|
39
|
-
|
40
|
-
|
41
|
-
escaped_symbol = '\\' any;
|
42
|
-
|
43
|
-
squote = "'";
|
44
|
-
snon_quote = [^\\'];
|
45
|
-
sstring = squote (snon_quote | escaped_symbol)* squote @lerr{ raise_unterminated_string; };
|
46
|
-
|
47
|
-
dquote = '"';
|
48
|
-
dnon_quote = [^\\"];
|
49
|
-
dstring = dquote (dnon_quote | escaped_symbol)* dquote @lerr{ raise_unterminated_string; };
|
50
|
-
|
51
|
-
rquote = '/';
|
52
|
-
rnon_quote = [^\\/];
|
53
|
-
regexp = rquote @{ regexp_ambiguity(fgoto expression;) }
|
54
|
-
(rnon_quote | escaped_symbol)* rquote alpha* @lerr{ raise_unterminated_regexp; };
|
55
|
-
|
56
|
-
|
57
|
-
numeric = '-'? digit* ('.' digit+)?;
|
58
|
-
identifer = (alpha | '_') (alnum | '_')* [?!]?;
|
59
|
-
operator = arithmetic | logic | flow | structure;
|
60
|
-
comment = '#' ([^\n}]+ | '}' [^}])*;
|
61
|
-
blank = [\t\v\f\r ];
|
62
|
-
|
63
|
-
tag_open = '{{' '!'?;
|
64
|
-
tag_close = '}}';
|
65
|
-
template = [^{]+ | '{';
|
66
|
-
|
67
|
-
template_comment_open = '{{#';
|
68
|
-
template_comment_close = '#}}';
|
69
|
-
template_comment_body = [^\#]+ | '#';
|
70
|
-
|
71
|
-
|
72
|
-
expression := |*
|
73
|
-
tag_close => { emit_tag; fret; };
|
74
|
-
operator => { emit_operator; };
|
75
|
-
numeric => { emit_numeric; };
|
76
|
-
identifer => { emit_identifer; };
|
77
|
-
sstring => { emit_sstring; };
|
78
|
-
dstring => { emit_dstring; };
|
79
|
-
regexp => { emit_regexp; };
|
80
|
-
comment => { emit_comment; };
|
81
|
-
blank;
|
82
|
-
*|;
|
83
|
-
|
84
|
-
template_comment := |*
|
85
|
-
template_comment_close => { emit_comment; fret; };
|
86
|
-
template_comment_body => { emit_comment; };
|
87
|
-
*|;
|
88
|
-
|
89
|
-
main := |*
|
90
|
-
tag_open => { emit_tag; fcall expression; };
|
91
|
-
template_comment_open => { emit_comment; fcall template_comment; };
|
92
|
-
template => { emit_template; };
|
93
|
-
*|;
|
4
|
+
action RegexpCheck {
|
5
|
+
if (regexp_possible == Qfalse) {
|
6
|
+
emit_operator;
|
7
|
+
fgoto expression;
|
8
|
+
}
|
9
|
+
}
|
10
|
+
|
11
|
+
include "lexer.rl";
|
94
12
|
}%%
|
95
13
|
|
14
|
+
|
96
15
|
#include <ruby.h>
|
97
16
|
#include <lexerc.h>
|
98
17
|
|
data/lib/hotcell/commands/for.rb
CHANGED
@@ -15,7 +15,12 @@ module Hotcell
|
|
15
15
|
|
16
16
|
def process context, variable, options
|
17
17
|
forloop = options['loop'] == true ? 'loop' : options['loop']
|
18
|
-
items =
|
18
|
+
items = case options['in']
|
19
|
+
when Range, Hash
|
20
|
+
options['in'].to_a
|
21
|
+
else
|
22
|
+
Array.wrap(options['in'])
|
23
|
+
end
|
19
24
|
length = items.size
|
20
25
|
|
21
26
|
items.map.with_index do |item, index|
|
@@ -25,7 +30,7 @@ module Hotcell
|
|
25
30
|
context.scoped scope do
|
26
31
|
subnodes.first.try(:render, context)
|
27
32
|
end
|
28
|
-
end
|
33
|
+
end.join
|
29
34
|
end
|
30
35
|
|
31
36
|
class Forloop < Hotcell::Manipulator
|
data/lib/hotcell/config.rb
CHANGED
@@ -5,13 +5,14 @@ module Hotcell
|
|
5
5
|
include Singleton
|
6
6
|
|
7
7
|
attr_reader :commands, :blocks, :helpers
|
8
|
-
attr_accessor :resolver
|
8
|
+
attr_accessor :resolver, :escape_tags
|
9
9
|
|
10
10
|
def initialize
|
11
11
|
@commands = {}
|
12
12
|
@blocks = {}
|
13
13
|
@helpers = []
|
14
14
|
@resolver = Hotcell::Resolver.new
|
15
|
+
@escape_tags = false
|
15
16
|
end
|
16
17
|
|
17
18
|
# Adds command or block to the list of default commands or blocks returned
|
data/lib/hotcell/extensions.rb
CHANGED
@@ -16,6 +16,8 @@ end
|
|
16
16
|
|
17
17
|
String.class_eval do
|
18
18
|
include Hotcell::Manipulator::Mixin
|
19
|
+
|
20
|
+
manipulate :size, :length
|
19
21
|
end
|
20
22
|
|
21
23
|
Regexp.class_eval do
|
@@ -32,13 +34,23 @@ end
|
|
32
34
|
|
33
35
|
Array.class_eval do
|
34
36
|
include Hotcell::Manipulator::Mixin
|
37
|
+
|
38
|
+
manipulate :first, :last, :count, :size, :length
|
35
39
|
end
|
36
40
|
|
37
41
|
Hash.class_eval do
|
38
42
|
include Hotcell::Manipulator::Mixin
|
39
43
|
|
44
|
+
manipulate :keys, :values, :count, :size, :length
|
45
|
+
|
40
46
|
def manipulator_invoke method, *arguments
|
41
|
-
|
47
|
+
if method == '[]'
|
48
|
+
manipulator_invoke_brackets *arguments
|
49
|
+
elsif manipulator_invokable? method
|
50
|
+
send(method, *arguments)
|
51
|
+
elsif arguments.count == 0
|
52
|
+
self[method]
|
53
|
+
end
|
42
54
|
end
|
43
55
|
end
|
44
56
|
|
data/lib/hotcell/lexer.rb
CHANGED
@@ -6,8 +6,8 @@ module Hotcell
|
|
6
6
|
'&&' => :AND, '||' => :OR, '!' => :NOT, '==' => :EQUAL, '!=' => :INEQUAL,
|
7
7
|
'>' => :GT, '>=' => :GTE, '<' => :LT, '<=' => :LTE,
|
8
8
|
|
9
|
-
'=' => :ASSIGN, ',' => :COMMA, '.' => :PERIOD, '
|
10
|
-
';' => :SEMICOLON
|
9
|
+
'=' => :ASSIGN, ',' => :COMMA, '.' => :PERIOD, '..' => :RANGE, '...' => :RANGE,
|
10
|
+
':' => :COLON, '?' => :QUESTION, ';' => :SEMICOLON
|
11
11
|
}
|
12
12
|
|
13
13
|
BOPEN = { '[' => :AOPEN, '{' => :HOPEN, '(' => :POPEN }
|
@@ -30,11 +30,6 @@ module Hotcell
|
|
30
30
|
'\s' => "\s", '\r' => "\r", '\t' => "\t"
|
31
31
|
}
|
32
32
|
|
33
|
-
TAGS = {
|
34
|
-
'{{' => :TOPEN, '{{!' => :TOPEN,
|
35
|
-
'}}' => :TCLOSE
|
36
|
-
}
|
37
|
-
|
38
33
|
PREREGEXP = Set.new [
|
39
34
|
:TOPEN, :NEWLINE, :SEMICOLON,
|
40
35
|
:COLON, :COMMA, :PERIOD,
|
@@ -83,13 +78,13 @@ module Hotcell
|
|
83
78
|
end
|
84
79
|
|
85
80
|
def regexp_ambiguity
|
86
|
-
unless regexp_possible
|
81
|
+
unless regexp_possible
|
87
82
|
emit_operator
|
88
83
|
yield
|
89
84
|
end
|
90
85
|
end
|
91
86
|
|
92
|
-
def regexp_possible
|
87
|
+
def regexp_possible
|
93
88
|
last = @token_array[-1]
|
94
89
|
# Need more rules!
|
95
90
|
!last || PREREGEXP.include?(last[0])
|
@@ -120,7 +115,7 @@ module Hotcell
|
|
120
115
|
|
121
116
|
def emit_tag
|
122
117
|
value = current_value
|
123
|
-
emit
|
118
|
+
emit (value == '}}' ? :TCLOSE : :TOPEN), value
|
124
119
|
end
|
125
120
|
|
126
121
|
def emit_comment
|
@@ -0,0 +1,95 @@
|
|
1
|
+
%%{
|
2
|
+
machine puffer_lexer;
|
3
|
+
|
4
|
+
plus = '+';
|
5
|
+
minus = '-';
|
6
|
+
multiply = '*';
|
7
|
+
power = '**';
|
8
|
+
divide = '/';
|
9
|
+
modulo = '%';
|
10
|
+
arithmetic = plus | minus | multiply | power | divide | modulo;
|
11
|
+
|
12
|
+
and = '&&';
|
13
|
+
or = '||';
|
14
|
+
not = '!';
|
15
|
+
equal = '==';
|
16
|
+
inequal = '!=';
|
17
|
+
gt = '>';
|
18
|
+
gte = '>=';
|
19
|
+
lt = '<';
|
20
|
+
lte = '<=';
|
21
|
+
logic = and | or | not | equal | inequal | gt | gte | lt | lte;
|
22
|
+
|
23
|
+
assign = '=';
|
24
|
+
comma = ',';
|
25
|
+
period = '.';
|
26
|
+
range = '..' '.'?;
|
27
|
+
colon = ':';
|
28
|
+
question = '?';
|
29
|
+
semicolon = ';';
|
30
|
+
newline = '\n';
|
31
|
+
flow = assign | comma | period | range | colon | question | semicolon | newline;
|
32
|
+
|
33
|
+
array_open = '[';
|
34
|
+
array_close = ']';
|
35
|
+
hash_open = '{';
|
36
|
+
hash_close = '}';
|
37
|
+
bracket_open = '(';
|
38
|
+
bracket_close = ')';
|
39
|
+
structure = array_open | array_close | hash_open | hash_close | bracket_open | bracket_close;
|
40
|
+
|
41
|
+
|
42
|
+
escaped_symbol = '\\' any;
|
43
|
+
|
44
|
+
squote = "'";
|
45
|
+
snon_quote = [^\\'];
|
46
|
+
sstring = squote (snon_quote | escaped_symbol)* squote @lerr{ raise_unterminated_string; };
|
47
|
+
|
48
|
+
dquote = '"';
|
49
|
+
dnon_quote = [^\\"];
|
50
|
+
dstring = dquote (dnon_quote | escaped_symbol)* dquote @lerr{ raise_unterminated_string; };
|
51
|
+
|
52
|
+
rquote = '/';
|
53
|
+
rnon_quote = [^\\/];
|
54
|
+
regexp = rquote @RegexpCheck
|
55
|
+
(rnon_quote | escaped_symbol)* rquote alpha* @lerr{ raise_unterminated_regexp; };
|
56
|
+
|
57
|
+
|
58
|
+
numeric = '-'? digit* ('.' digit+)?;
|
59
|
+
identifer = (alpha | '_') (alnum | '_')* [?!]?;
|
60
|
+
operator = arithmetic | logic | flow | structure;
|
61
|
+
comment = '#' ([^\n}]+ | '}' [^}])*;
|
62
|
+
blank = [\t\v\f\r ];
|
63
|
+
|
64
|
+
tag_open = '{{' ([!~^] | [re] ' ')?;
|
65
|
+
tag_close = '}}';
|
66
|
+
template = [^{]+ | '{';
|
67
|
+
|
68
|
+
template_comment_open = '{{#';
|
69
|
+
template_comment_close = '#}}';
|
70
|
+
template_comment_body = [^\#]+ | '#';
|
71
|
+
|
72
|
+
|
73
|
+
expression := |*
|
74
|
+
tag_close => { emit_tag; fret; };
|
75
|
+
operator => { emit_operator; };
|
76
|
+
numeric => { emit_numeric; };
|
77
|
+
identifer => { emit_identifer; };
|
78
|
+
sstring => { emit_sstring; };
|
79
|
+
dstring => { emit_dstring; };
|
80
|
+
regexp => { emit_regexp; };
|
81
|
+
comment => { emit_comment; };
|
82
|
+
blank;
|
83
|
+
*|;
|
84
|
+
|
85
|
+
template_comment := |*
|
86
|
+
template_comment_close => { emit_comment; fret; };
|
87
|
+
template_comment_body => { emit_comment; };
|
88
|
+
*|;
|
89
|
+
|
90
|
+
main := |*
|
91
|
+
tag_open => { emit_tag; fcall expression; };
|
92
|
+
template_comment_open => { emit_comment; fcall template_comment; };
|
93
|
+
template => { emit_template; };
|
94
|
+
*|;
|
95
|
+
}%%
|