hotcell 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}%%
|