plasma 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -7,12 +7,12 @@ require 'rake/gempackagetask'
7
7
 
8
8
  gemspec = Gem::Specification.new do |s|
9
9
  s.name = "plasma"
10
- s.version = "0.0.1"
10
+ s.version = "0.1.0"
11
11
  s.author = "Ryan Spangler"
12
12
  s.email = "patch_work8848@yahoo.com"
13
13
  s.homepage = "http://kaleidomedallion.com/plasma/"
14
14
  s.platform = Gem::Platform::RUBY
15
- s.summary = "plasma --- a lightweight interpreted templating language in ruby"
15
+ s.summary = "plasma --- a lightweight interpreted templating language in treetop and ruby"
16
16
  s.files = FileList['README', 'Rakefile', "{test,lib,bin,doc,examples}/**/*"].to_a
17
17
  s.bindir = 'bin'
18
18
  s.executables = ['plasma']
@@ -12,7 +12,13 @@ class PlasmaView
12
12
  end
13
13
  assigns.merge!(local_assigns)
14
14
 
15
- plasma = Plasma::Template::PlasmaTemplate.parse(template)
16
- plasma.render(assigns)
15
+ plasma = Plasma::Interpreter::PlasmaGrammarParser.new
16
+ env = Plasma::Interpreter::Env.new(assigns)
17
+
18
+ tree = plasma.parse(template)
19
+ tree.evaluate(env)
17
20
  end
18
21
  end
22
+
23
+
24
+
@@ -2,10 +2,12 @@ require 'rubygems'
2
2
 
3
3
  dir = File.dirname(__FILE__)
4
4
 
5
+ PLASMA_LIB = dir
5
6
  PLASMA_ROOT = File.join(dir, 'plasma')
6
7
  PLASMA_PACKAGE_ROOT = File.expand_path(dir + '/..')
8
+ PLASMA_TEST = File.join(PLASMA_PACKAGE_ROOT, 'test')
7
9
 
8
10
  require File.join(PLASMA_ROOT, 'interpreter')
9
- require File.join(PLASMA_ROOT, 'template')
11
+ require File.join(PLASMA_LIB, 'extras/plasma_view')
10
12
 
11
13
  $LOAD_PATH.unshift(dir)
@@ -17,6 +17,10 @@ module Plasma
17
17
  else
18
18
  interp.evaluate(quote)
19
19
  end
20
+ end,
21
+
22
+ :parse => RubyClosure.new('parse', interp) do |code|
23
+ interp.parse(code)
20
24
  end
21
25
  }
22
26
  end
@@ -4,7 +4,260 @@ module Plasma
4
4
  include Treetop::Runtime
5
5
 
6
6
  def root
7
- @root || :plasma
7
+ @root || :template
8
+ end
9
+
10
+ module Template0
11
+ def macro
12
+ elements[0]
13
+ end
14
+
15
+ def tail
16
+ elements[1]
17
+ end
18
+ end
19
+
20
+ module Template1
21
+ def head
22
+ elements[0]
23
+ end
24
+
25
+ def body
26
+ elements[1]
27
+ end
28
+ end
29
+
30
+ def _nt_template
31
+ start_index = index
32
+ if node_cache[:template].has_key?(index)
33
+ cached = node_cache[:template][index]
34
+ @index = cached.interval.end if cached
35
+ return cached
36
+ end
37
+
38
+ i0, s0 = index, []
39
+ s1, i1 = [], index
40
+ loop do
41
+ r2 = _nt_plain
42
+ if r2
43
+ s1 << r2
44
+ else
45
+ break
46
+ end
47
+ end
48
+ r1 = SyntaxNode.new(input, i1...index, s1)
49
+ s0 << r1
50
+ if r1
51
+ s3, i3 = [], index
52
+ loop do
53
+ i4, s4 = index, []
54
+ r5 = _nt_macro
55
+ s4 << r5
56
+ if r5
57
+ s6, i6 = [], index
58
+ loop do
59
+ r7 = _nt_plain
60
+ if r7
61
+ s6 << r7
62
+ else
63
+ break
64
+ end
65
+ end
66
+ r6 = SyntaxNode.new(input, i6...index, s6)
67
+ s4 << r6
68
+ end
69
+ if s4.last
70
+ r4 = (SyntaxNode).new(input, i4...index, s4)
71
+ r4.extend(Template0)
72
+ else
73
+ self.index = i4
74
+ r4 = nil
75
+ end
76
+ if r4
77
+ s3 << r4
78
+ else
79
+ break
80
+ end
81
+ end
82
+ r3 = SyntaxNode.new(input, i3...index, s3)
83
+ s0 << r3
84
+ end
85
+ if s0.last
86
+ r0 = (TemplateNode).new(input, i0...index, s0)
87
+ r0.extend(Template1)
88
+ else
89
+ self.index = i0
90
+ r0 = nil
91
+ end
92
+
93
+ node_cache[:template][start_index] = r0
94
+
95
+ return r0
96
+ end
97
+
98
+ def _nt_plain
99
+ start_index = index
100
+ if node_cache[:plain].has_key?(index)
101
+ cached = node_cache[:plain][index]
102
+ @index = cached.interval.end if cached
103
+ return cached
104
+ end
105
+
106
+ if input.index(Regexp.new('[^\\[\\]`\']'), index) == index
107
+ r0 = (SyntaxNode).new(input, index...(index + 1))
108
+ @index += 1
109
+ else
110
+ r0 = nil
111
+ end
112
+
113
+ node_cache[:plain][start_index] = r0
114
+
115
+ return r0
116
+ end
117
+
118
+ def _nt_macro
119
+ start_index = index
120
+ if node_cache[:macro].has_key?(index)
121
+ cached = node_cache[:macro][index]
122
+ @index = cached.interval.end if cached
123
+ return cached
124
+ end
125
+
126
+ i0 = index
127
+ r1 = _nt_quote
128
+ if r1
129
+ r0 = r1
130
+ else
131
+ r2 = _nt_expansion
132
+ if r2
133
+ r0 = r2
134
+ else
135
+ self.index = i0
136
+ r0 = nil
137
+ end
138
+ end
139
+
140
+ node_cache[:macro][start_index] = r0
141
+
142
+ return r0
143
+ end
144
+
145
+ module Quote0
146
+ def template
147
+ elements[1]
148
+ end
149
+
150
+ end
151
+
152
+ def _nt_quote
153
+ start_index = index
154
+ if node_cache[:quote].has_key?(index)
155
+ cached = node_cache[:quote][index]
156
+ @index = cached.interval.end if cached
157
+ return cached
158
+ end
159
+
160
+ i0, s0 = index, []
161
+ if input.index('`', index) == index
162
+ r1 = (SyntaxNode).new(input, index...(index + 1))
163
+ @index += 1
164
+ else
165
+ terminal_parse_failure('`')
166
+ r1 = nil
167
+ end
168
+ s0 << r1
169
+ if r1
170
+ r2 = _nt_template
171
+ s0 << r2
172
+ if r2
173
+ if input.index('\'', index) == index
174
+ r3 = (SyntaxNode).new(input, index...(index + 1))
175
+ @index += 1
176
+ else
177
+ terminal_parse_failure('\'')
178
+ r3 = nil
179
+ end
180
+ s0 << r3
181
+ end
182
+ end
183
+ if s0.last
184
+ r0 = (QuoteNode).new(input, i0...index, s0)
185
+ r0.extend(Quote0)
186
+ else
187
+ self.index = i0
188
+ r0 = nil
189
+ end
190
+
191
+ node_cache[:quote][start_index] = r0
192
+
193
+ return r0
194
+ end
195
+
196
+ module Expansion0
197
+ def x
198
+ elements[1]
199
+ end
200
+
201
+ def plasma
202
+ elements[2]
203
+ end
204
+
205
+ def x
206
+ elements[3]
207
+ end
208
+
209
+ end
210
+
211
+ def _nt_expansion
212
+ start_index = index
213
+ if node_cache[:expansion].has_key?(index)
214
+ cached = node_cache[:expansion][index]
215
+ @index = cached.interval.end if cached
216
+ return cached
217
+ end
218
+
219
+ i0, s0 = index, []
220
+ if input.index('[', index) == index
221
+ r1 = (SyntaxNode).new(input, index...(index + 1))
222
+ @index += 1
223
+ else
224
+ terminal_parse_failure('[')
225
+ r1 = nil
226
+ end
227
+ s0 << r1
228
+ if r1
229
+ r2 = _nt_x
230
+ s0 << r2
231
+ if r2
232
+ r3 = _nt_plasma
233
+ s0 << r3
234
+ if r3
235
+ r4 = _nt_x
236
+ s0 << r4
237
+ if r4
238
+ if input.index(']', index) == index
239
+ r5 = (SyntaxNode).new(input, index...(index + 1))
240
+ @index += 1
241
+ else
242
+ terminal_parse_failure(']')
243
+ r5 = nil
244
+ end
245
+ s0 << r5
246
+ end
247
+ end
248
+ end
249
+ end
250
+ if s0.last
251
+ r0 = (ExpansionNode).new(input, i0...index, s0)
252
+ r0.extend(Expansion0)
253
+ else
254
+ self.index = i0
255
+ r0 = nil
256
+ end
257
+
258
+ node_cache[:expansion][start_index] = r0
259
+
260
+ return r0
8
261
  end
9
262
 
10
263
  def _nt_plasma
@@ -64,24 +317,29 @@ module Plasma
64
317
  if r12
65
318
  r0 = r12
66
319
  else
67
- r13 = _nt_date
320
+ r13 = _nt_regex
68
321
  if r13
69
322
  r0 = r13
70
323
  else
71
- r14 = _nt_time
324
+ r14 = _nt_date
72
325
  if r14
73
326
  r0 = r14
74
327
  else
75
- r15 = _nt_str
328
+ r15 = _nt_time
76
329
  if r15
77
330
  r0 = r15
78
331
  else
79
- r16 = _nt_num
332
+ r16 = _nt_str
80
333
  if r16
81
334
  r0 = r16
82
335
  else
83
- self.index = i0
84
- r0 = nil
336
+ r17 = _nt_num
337
+ if r17
338
+ r0 = r17
339
+ else
340
+ self.index = i0
341
+ r0 = nil
342
+ end
85
343
  end
86
344
  end
87
345
  end
@@ -364,46 +622,6 @@ module Plasma
364
622
  return r0
365
623
  end
366
624
 
367
- module Quote0
368
- def plasma
369
- elements[1]
370
- end
371
- end
372
-
373
- def _nt_quote
374
- start_index = index
375
- if node_cache[:quote].has_key?(index)
376
- cached = node_cache[:quote][index]
377
- @index = cached.interval.end if cached
378
- return cached
379
- end
380
-
381
- i0, s0 = index, []
382
- if input.index("'", index) == index
383
- r1 = (SyntaxNode).new(input, index...(index + 1))
384
- @index += 1
385
- else
386
- terminal_parse_failure("'")
387
- r1 = nil
388
- end
389
- s0 << r1
390
- if r1
391
- r2 = _nt_plasma
392
- s0 << r2
393
- end
394
- if s0.last
395
- r0 = (QuoteNode).new(input, i0...index, s0)
396
- r0.extend(Quote0)
397
- else
398
- self.index = i0
399
- r0 = nil
400
- end
401
-
402
- node_cache[:quote][start_index] = r0
403
-
404
- return r0
405
- end
406
-
407
625
  module Defun0
408
626
  def x
409
627
  elements[1]
@@ -1171,7 +1389,7 @@ module Plasma
1171
1389
 
1172
1390
  s0, i0 = [], index
1173
1391
  loop do
1174
- if input.index(Regexp.new('[a-z+!/\\^&@?*%<>=_-]'), index) == index
1392
+ if input.index(Regexp.new('[a-z+!\\^&@?*%<>=_-]'), index) == index
1175
1393
  r1 = (SyntaxNode).new(input, index...(index + 1))
1176
1394
  @index += 1
1177
1395
  else
@@ -1483,6 +1701,104 @@ module Plasma
1483
1701
  return r0
1484
1702
  end
1485
1703
 
1704
+ module Regex0
1705
+ def body
1706
+ elements[1]
1707
+ end
1708
+
1709
+ end
1710
+
1711
+ def _nt_regex
1712
+ start_index = index
1713
+ if node_cache[:regex].has_key?(index)
1714
+ cached = node_cache[:regex][index]
1715
+ @index = cached.interval.end if cached
1716
+ return cached
1717
+ end
1718
+
1719
+ i0, s0 = index, []
1720
+ if input.index('/', index) == index
1721
+ r1 = (SyntaxNode).new(input, index...(index + 1))
1722
+ @index += 1
1723
+ else
1724
+ terminal_parse_failure('/')
1725
+ r1 = nil
1726
+ end
1727
+ s0 << r1
1728
+ if r1
1729
+ s2, i2 = [], index
1730
+ loop do
1731
+ r3 = _nt_regex_char
1732
+ if r3
1733
+ s2 << r3
1734
+ else
1735
+ break
1736
+ end
1737
+ end
1738
+ r2 = SyntaxNode.new(input, i2...index, s2)
1739
+ s0 << r2
1740
+ if r2
1741
+ if input.index('/', index) == index
1742
+ r4 = (SyntaxNode).new(input, index...(index + 1))
1743
+ @index += 1
1744
+ else
1745
+ terminal_parse_failure('/')
1746
+ r4 = nil
1747
+ end
1748
+ s0 << r4
1749
+ end
1750
+ end
1751
+ if s0.last
1752
+ r0 = (RegexNode).new(input, i0...index, s0)
1753
+ r0.extend(Regex0)
1754
+ else
1755
+ self.index = i0
1756
+ r0 = nil
1757
+ end
1758
+
1759
+ node_cache[:regex][start_index] = r0
1760
+
1761
+ return r0
1762
+ end
1763
+
1764
+ def _nt_regex_char
1765
+ start_index = index
1766
+ if node_cache[:regex_char].has_key?(index)
1767
+ cached = node_cache[:regex_char][index]
1768
+ @index = cached.interval.end if cached
1769
+ return cached
1770
+ end
1771
+
1772
+ i0 = index
1773
+ if input.index('\\/', index) == index
1774
+ r1 = (SyntaxNode).new(input, index...(index + 2))
1775
+ @index += 2
1776
+ else
1777
+ terminal_parse_failure('\\/')
1778
+ r1 = nil
1779
+ end
1780
+ if r1
1781
+ r0 = r1
1782
+ else
1783
+ if input.index(Regexp.new('[^/]'), index) == index
1784
+ r2 = (SyntaxNode).new(input, index...(index + 1))
1785
+ @index += 1
1786
+ else
1787
+ r2 = nil
1788
+ end
1789
+ if r2
1790
+ r0 = r2
1791
+ else
1792
+ self.index = i0
1793
+ r0 = nil
1794
+ end
1795
+ end
1796
+
1797
+ node_cache[:regex_char][start_index] = r0
1798
+
1799
+ return r0
1800
+ end
1801
+
1486
1802
  module Date0
1487
1803
  def s
1488
1804
  elements[0]
@@ -1747,14 +2063,10 @@ module Plasma
1747
2063
  end
1748
2064
 
1749
2065
  module Str0
1750
- def first
2066
+ def body
1751
2067
  elements[1]
1752
2068
  end
1753
2069
 
1754
- def rest
1755
- elements[2]
1756
- end
1757
-
1758
2070
  end
1759
2071
 
1760
2072
  def _nt_str
@@ -1775,45 +2087,26 @@ module Plasma
1775
2087
  end
1776
2088
  s0 << r1
1777
2089
  if r1
1778
- if input.index(Regexp.new('[^"]'), index) == index
1779
- r3 = (SyntaxNode).new(input, index...(index + 1))
1780
- @index += 1
1781
- else
1782
- r3 = nil
1783
- end
1784
- if r3
1785
- r2 = r3
1786
- else
1787
- r2 = SyntaxNode.new(input, index...index)
2090
+ s2, i2 = [], index
2091
+ loop do
2092
+ r3 = _nt_str_char
2093
+ if r3
2094
+ s2 << r3
2095
+ else
2096
+ break
2097
+ end
1788
2098
  end
2099
+ r2 = SyntaxNode.new(input, i2...index, s2)
1789
2100
  s0 << r2
1790
2101
  if r2
1791
- s4, i4 = [], index
1792
- loop do
1793
- if input.index(Regexp.new('[^"]'), index) == index
1794
- r5 = (SyntaxNode).new(input, index...(index + 1))
1795
- @index += 1
1796
- else
1797
- r5 = nil
1798
- end
1799
- if r5
1800
- s4 << r5
1801
- else
1802
- break
1803
- end
2102
+ if input.index('"', index) == index
2103
+ r4 = (SyntaxNode).new(input, index...(index + 1))
2104
+ @index += 1
2105
+ else
2106
+ terminal_parse_failure('"')
2107
+ r4 = nil
1804
2108
  end
1805
- r4 = SyntaxNode.new(input, i4...index, s4)
1806
2109
  s0 << r4
1807
- if r4
1808
- if input.index('"', index) == index
1809
- r6 = (SyntaxNode).new(input, index...(index + 1))
1810
- @index += 1
1811
- else
1812
- terminal_parse_failure('"')
1813
- r6 = nil
1814
- end
1815
- s0 << r6
1816
- end
1817
2110
  end
1818
2111
  end
1819
2112
  if s0.last
@@ -1829,6 +2122,44 @@ module Plasma
1829
2122
  return r0
1830
2123
  end
1831
2124
 
2125
+ def _nt_str_char
2126
+ start_index = index
2127
+ if node_cache[:str_char].has_key?(index)
2128
+ cached = node_cache[:str_char][index]
2129
+ @index = cached.interval.end if cached
2130
+ return cached
2131
+ end
2132
+
2133
+ i0 = index
2134
+ if input.index('\\"', index) == index
2135
+ r1 = (SyntaxNode).new(input, index...(index + 2))
2136
+ @index += 2
2137
+ else
2138
+ terminal_parse_failure('\\"')
2139
+ r1 = nil
2140
+ end
2141
+ if r1
2142
+ r0 = r1
2143
+ else
2144
+ if input.index(Regexp.new('[^"]'), index) == index
2145
+ r2 = (SyntaxNode).new(input, index...(index + 1))
2146
+ @index += 1
2147
+ else
2148
+ r2 = nil
2149
+ end
2150
+ if r2
2151
+ r0 = r2
2152
+ else
2153
+ self.index = i0
2154
+ r0 = nil
2155
+ end
2156
+ end
2157
+
2158
+ node_cache[:str_char][start_index] = r0
2159
+
2160
+ return r0
2161
+ end
2162
+
1832
2163
  module Num0
1833
2164
  end
1834
2165
 
@@ -1837,7 +2168,7 @@ module Plasma
1837
2168
  elements[0]
1838
2169
  end
1839
2170
 
1840
- def expansion
2171
+ def decimal
1841
2172
  elements[1]
1842
2173
  end
1843
2174
  end
@@ -1,8 +1,28 @@
1
1
  module Plasma
2
2
  module Interpreter
3
3
  grammar PlasmaGrammar
4
+ rule template
5
+ head:(plain)* body:(macro tail:(plain)*)* <TemplateNode>
6
+ end
7
+
8
+ rule plain
9
+ [^\[\]`'] #`
10
+ end
11
+
12
+ rule macro
13
+ quote / expansion
14
+ end
15
+
16
+ rule quote
17
+ '`' template '\'' <QuoteNode>
18
+ end
19
+
20
+ rule expansion
21
+ '[' x plasma x ']' <ExpansionNode>
22
+ end
23
+
4
24
  rule plasma
5
- decl / seq / quote / defun / def / fun / if / apply / bool / sym / hash / list / date / time / str / num
25
+ decl / seq / quote / defun / def / fun / if / apply / bool / sym / hash / list / regex / date / time / str / num
6
26
  end
7
27
 
8
28
  rule decl
@@ -13,10 +33,6 @@ module Plasma
13
33
  '(' x first:plasma? rest:(s '|' s plasma)* x ')' <SeqNode>
14
34
  end
15
35
 
16
- rule quote
17
- "'" plasma <QuoteNode>
18
- end
19
-
20
36
  rule defun
21
37
  '(' x 'defun' s params s plasma x ')' <DefunNode>
22
38
  end
@@ -46,7 +62,7 @@ module Plasma
46
62
  end
47
63
 
48
64
  rule sym
49
- [a-z+!/\^&@?*%<>=_-]+ <SymNode>
65
+ [a-z+!\^&@?*%<>=_-]+ <SymNode>
50
66
  end
51
67
 
52
68
  rule hash
@@ -61,6 +77,14 @@ module Plasma
61
77
  '[' x first:plasma? rest:(s plasma)* x ']' <ListNode>
62
78
  end
63
79
 
80
+ rule regex
81
+ '/' body:(regex_char)* '/' <RegexNode>
82
+ end
83
+
84
+ rule regex_char
85
+ '\\/' / [^/]
86
+ end
87
+
64
88
  rule date
65
89
  year [-] month:dual [-] day:dual (s time)? <DateNode>
66
90
  end
@@ -78,11 +102,15 @@ module Plasma
78
102
  end
79
103
 
80
104
  rule str
81
- '"' first:([^"])? rest:([^"])* '"' <StrNode>
105
+ '"' body:(str_char)* '"' <StrNode>
106
+ end
107
+
108
+ rule str_char
109
+ '\\"' / [^"] #"
82
110
  end
83
111
 
84
112
  rule num
85
- whole:([0-9]+) expansion:('.' [0-9]+)? <NumNode>
113
+ whole:([0-9]+) decimal:('.' [0-9]+)? <NumNode>
86
114
  end
87
115
 
88
116
  rule x
@@ -37,6 +37,20 @@ module Plasma
37
37
  self
38
38
  end
39
39
 
40
+ def scope(inner={})
41
+ self.scope!(inner)
42
+
43
+ begin
44
+ value = yield self
45
+ self.release!
46
+
47
+ return value
48
+ rescue => detail
49
+ self.release!
50
+ detail
51
+ end
52
+ end
53
+
40
54
  def resolve(key)
41
55
  @state.reverse_each do |layer|
42
56
  return layer[key] if layer.include?(key)
@@ -55,11 +69,11 @@ module Plasma
55
69
  end
56
70
 
57
71
  def unquote(env)
58
- @unevaluated.eval(env)
72
+ @unevaluated.evaluate(env)
59
73
  end
60
74
 
61
75
  def to_plasma
62
- "'#{@unevaluated.text_value}"
76
+ "`#{@unevaluated.text_value}'"
63
77
  end
64
78
  end
65
79
 
@@ -80,11 +94,9 @@ module Plasma
80
94
  zipped.merge!(:env => @env)
81
95
 
82
96
  if left.empty?
83
- @env.scope!(zipped)
84
- value = @body.evaluate(@env)
85
- @env.release!()
86
-
87
- return value
97
+ @env.scope(zipped) do |env|
98
+ @body.evaluate(env)
99
+ end
88
100
  else
89
101
  return Closure.new(@env.dup.merge!(zipped), left, body)
90
102
  end
@@ -121,7 +133,7 @@ module Plasma
121
133
  keys = fresh.keys.join(' ')
122
134
  env = Env.new(fresh.merge(@name => self))
123
135
 
124
- interp.interpret("fun (#{params}) ((#{@name} #{keys} #{params}))", env)
136
+ interp.interpret("fun (#{params}) (#{@name} #{keys} #{params})", env)
125
137
  end
126
138
  end
127
139
  end
@@ -174,30 +186,57 @@ module Plasma
174
186
  end
175
187
  end
176
188
 
177
- class DeclNode < ColNode
189
+ class Treetop::Runtime::SyntaxNode
190
+ def to_s
191
+ text_value
192
+ end
193
+ end
194
+
195
+ class TemplateNode < PlasmaNode
178
196
  def evaluate(env)
179
- value = col.inject(nil) do |value, statement|
180
- statement.evaluate(env)
197
+ value = body.empty? ? '' : body.elements.inject('') do |so_far, el|
198
+ macro_value = el.macro.is_a?(ExpansionNode) ? el.macro.evaluate(env).to_s : el.macro.template.text_value
199
+ tail_value = el.respond_to?(:tail) ? el.tail.text_value : ''
200
+
201
+ so_far + macro_value + tail_value
181
202
  end
182
- value
203
+ head.text_value + value
183
204
  end
184
205
  end
185
206
 
186
- class SeqNode < ColNode
207
+ class PlainNode < PlasmaNode
187
208
  def evaluate(env)
188
- env.scope!
189
- value = col.inject(nil) do |value, statement|
209
+ self.text_value
210
+ end
211
+ end
212
+
213
+ class QuoteNode < PlasmaNode
214
+ def evaluate(env)
215
+ template.evaluate(env)
216
+ end
217
+ end
218
+
219
+ class ExpansionNode < PlasmaNode
220
+ def evaluate(env)
221
+ plasma.evaluate(env)
222
+ end
223
+ end
224
+
225
+ class DeclNode < ColNode
226
+ def evaluate(env)
227
+ col.inject(nil) do |value, statement|
190
228
  statement.evaluate(env)
191
229
  end
192
- env.release!
193
-
194
- value
195
230
  end
196
231
  end
197
232
 
198
- class QuoteNode < PlasmaNode
233
+ class SeqNode < ColNode
199
234
  def evaluate(env)
200
- plasma
235
+ env.scope do |env|
236
+ col.inject(nil) do |value, statement|
237
+ statement.evaluate(env)
238
+ end
239
+ end
201
240
  end
202
241
  end
203
242
 
@@ -207,7 +246,7 @@ module Plasma
207
246
  closure = Closure.new(env, syms.slice(1..syms.length), plasma)
208
247
  closure.env.merge!(syms[0] => closure)
209
248
  env.bind!(syms[0], closure)
210
- closure
249
+ ''
211
250
  end
212
251
  end
213
252
 
@@ -215,7 +254,7 @@ module Plasma
215
254
  def evaluate(env)
216
255
  value = plasma.evaluate(env)
217
256
  env.bind!(sym.text_value.to_sym, value)
218
- value
257
+ ''
219
258
  end
220
259
  end
221
260
 
@@ -305,6 +344,12 @@ module Plasma
305
344
  end
306
345
  end
307
346
 
347
+ class RegexNode < PlasmaNode
348
+ def evaluate(env)
349
+ Regexp.new(body.text_value)
350
+ end
351
+ end
352
+
308
353
  class DateNode < PlasmaNode
309
354
  def evaluate(env)
310
355
  end
@@ -315,15 +360,19 @@ module Plasma
315
360
  end
316
361
  end
317
362
 
318
- class StrNode < ColNode
363
+ class StrNode < PlasmaNode
319
364
  def evaluate(env)
320
- self.text_value.slice(1...self.text_value.length-1)
365
+ body.text_value
321
366
  end
322
367
  end
323
368
 
324
369
  class NumNode < PlasmaNode
325
370
  def evaluate(env)
326
- text_value.to_f
371
+ if self.respond_to?(:decimal)
372
+ text_value.to_f
373
+ else
374
+ text_value.to_i
375
+ end
327
376
  end
328
377
  end
329
378
  end
@@ -5,6 +5,8 @@ module Plasma
5
5
 
6
6
  def initialize
7
7
  @prompt = "-----| "
8
+ @comment = /##*[^#]+##*/
9
+
8
10
  @dir = File.dirname(__FILE__)
9
11
  @load_path = [File.join(PLASMA_ROOT, 'include'), PLASMA_PACKAGE_ROOT, @dir]
10
12
 
@@ -67,6 +69,10 @@ module Plasma
67
69
  raise NoSuchSourceException.new(plasma), "no such source #{plasma}", caller
68
70
  end
69
71
 
72
+ def strip(code)
73
+ code.gsub(@comment, '').strip
74
+ end
75
+
70
76
  def parse(code)
71
77
  tree = @plasma.parse(code)
72
78
  raise FailedToParseException.new, "failed to parse #{code}", caller if tree.nil?
@@ -75,12 +81,12 @@ module Plasma
75
81
  end
76
82
 
77
83
  def evaluate(tree, env=nil)
78
- env = @env if env.nil?
84
+ env ||= @env
79
85
  tree.evaluate(env)
80
86
  end
81
87
 
82
88
  def interpret(code, env=nil)
83
- tree = parse(code)
89
+ tree = parse(strip(code))
84
90
  evaluate(tree, env)
85
91
  end
86
92
 
@@ -88,14 +94,18 @@ module Plasma
88
94
  while true
89
95
  begin
90
96
  STDOUT.write(@prompt)
97
+
91
98
  input = STDIN.readline.strip
92
- break if input == 'quit' or input == 'exit'
99
+ unless input.empty?
93
100
 
94
- value = interpret input
101
+ value = interpret input
95
102
 
96
- STDOUT.write(" #{value.to_plasma}\n")
103
+ STDOUT.write(" #{value.to_plasma}\n")
104
+ end
105
+ rescue EOFError => e
106
+ break
97
107
  rescue Exception => e
98
- STDOUT.write(" #{e.to_s}\n")
108
+ STDOUT.write(" #{e}\n")
99
109
  end
100
110
  end
101
111
  end
@@ -0,0 +1,19 @@
1
+ module Plasma
2
+ module Interpreter
3
+ grammar PolychoronGrammar
4
+ include plasma
5
+
6
+ rule template
7
+ first:plain? rest:('[' s body:polychoron s ']' tail:plain?)* <TemplateNode>
8
+ end
9
+
10
+ rule plain
11
+ [^[`]+ <PlainNode> #`
12
+ end
13
+
14
+ rule polychoron
15
+ plasma
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,7 +1,9 @@
1
1
  module Plasma
2
2
  module Template
3
3
  class PlasmaTemplate
4
- @@separator = /\|\|/
4
+ attr_accessor :plasma
5
+
6
+ @@separator = /##*[^#]+##*/
5
7
 
6
8
  def self.parse(template)
7
9
  return PlasmaTemplate.new(template)
@@ -40,8 +42,8 @@ module Plasma
40
42
  end
41
43
  end
42
44
 
43
- def render(env={})
44
- @plasma.env.merge!(env)
45
+ def render(rel={})
46
+ @plasma.env.merge!(rel)
45
47
  evaluated = @plasmic.map{|p| @plasma.evaluate(p)}
46
48
 
47
49
  rendered = ''
@@ -55,3 +57,5 @@ module Plasma
55
57
  end
56
58
  end
57
59
  end
60
+
61
+
@@ -0,0 +1,18 @@
1
+ [(def move
2
+ (fun (a b) `move disk from [a] to [b]
3
+ ' ))]
4
+
5
+ [(def do_hanoi
6
+ (fun (a b c d)
7
+ (if (<= a 1)
8
+ then (move b c)
9
+ else `[(do_hanoi (- a 1) b d c)][(move b c)][(do_hanoi (- a 1) d c b)]')))]
10
+
11
+ [(def hanoi
12
+ (fun (n)
13
+ (do_hanoi n "source" "destination" "auxillary"))) ]
14
+
15
+ [(def levels 5)]
16
+
17
+ Tower of Hanoi ([levels] levels)
18
+ [(hanoi 5)]
@@ -0,0 +1,49 @@
1
+ require 'lib/plasma.rb'
2
+
3
+ plasma = Plasma::Interpreter::PlasmaGrammarParser.new
4
+
5
+ decl = "[| `eiii' | 1233333 | def xxx 5 |]"
6
+ declb = "[xxx]"
7
+ seq = "[(`oeheo' | 238 | 11)]"
8
+ quote = "[`(333333)']"
9
+ define = "[(def a 2121212 | a)]"
10
+ defun = "[(defun (ff x) (* x 13) | (ff 14))]"
11
+ fun = "[(fun (x c) (+ x c))]"
12
+ apply1 = "[(+ 11 14)]"
13
+ apply2 = "[((fun (x c) (+ x c)) 11 14)]"
14
+ curry = "[(def aaa ((fun (a b) (* a b)) 3) | (aaa 11))]"
15
+ sym = "[(def tatao+ht-o*he<>i==== 555 | tatao+ht-o*he<>i====)]"
16
+ hash = "[{yayay:77777 rrr:111}]"
17
+ list = "[[11 33 449]]"
18
+ regex = "[/[^7]*777\\/88?/]"
19
+ date = "[3409-65-22]"
20
+ time = "[55:32:18]"
21
+ str = '["yaodui iw\"fhoeo"]'
22
+ num = "[444.22]"
23
+ test = "[| def yar (fun (x) (* 3 x)) |
24
+ def peanut (fun (y z) (/ (- y z) z)) |
25
+ (peanut (yar 66) 12) |]"
26
+ bad = "[(999)(888)]"
27
+ cond = "[(if (> xxx 13) then 12 else [3 3 5 3])]"
28
+
29
+ template = "ol[(* 3 8)] weee! [(* \"okok\" 5)] okoko NO no way okay but [\"how about now\"] yes?" #"
30
+ template2 = "yayayay``nonono'ya'yayay"
31
+
32
+ env = Plasma::Interpreter::Env.new
33
+
34
+
35
+ statements = []
36
+ statements += [seq, quote, define, defun, fun, apply1, apply2,
37
+ sym, hash, list, regex, date, time, str, num, test,
38
+ decl, declb, defun, bad, curry, cond]
39
+
40
+ statements += [template, template2]
41
+
42
+
43
+
44
+ statements.each do |statement|
45
+ parsed = plasma.parse(statement)
46
+ evaluated = parsed.nil? ? "does not parse" : parsed.evaluate(env).to_plasma
47
+
48
+ puts "#{statement} -> #{parsed.class} : #{evaluated}"
49
+ end
@@ -0,0 +1,42 @@
1
+ okay so we are starting out clear
2
+
3
+ [( def fi 3 )]
4
+ [( def ya (fun (x) (* x 3)) )]
5
+ [( def ikik (map ["rrr" "uiowoyqpp i " fi "nogo deetdelowu"] ya) )]
6
+ [( * 55 12 )]
7
+ [( join ikik " " )]
8
+
9
+ continuing on now... maybe I will throw in a [(* 3 5)] just for fun. Yes?
10
+ what about Ifs, and loops? All about control flow.
11
+
12
+ [( if (true)
13
+ then `what?? [(* "yes" 14)] Really?'
14
+ else `yes really.' )]
15
+
16
+ So that almost makes sense. The grouping should really be more clear though.
17
+ maybe something with a directional brace, something like {{ maybe? }}
18
+
19
+ no.
20
+
21
+ [( def new (fun (x) (x "lalala")) )]
22
+ [( def thing (fun (y) (concat (* y 3) " dogono")) )]
23
+ [( def x "palatial" )]
24
+
25
+ So it will go like this... [( new thing )] and maybe another
26
+ [( if (> x "borox")
27
+ then `this could happen if [ x ] was defined they would all be substit[`u']ted'
28
+ else (* 3 11) )]
29
+ And maybe a function could go
30
+ [( def follow (fun (x) `okay now this is plain text again? How did [x] that happen? I guess in the quote???') )]
31
+ now we go along for a while and end up with a call to [( follow 3 )] and end up with something significant? So the scopes switch back and forth? That cant be right!
32
+
33
+ Okay, calling the macro and quoting are two different things. They must be treated differently. Okay
34
+
35
+
36
+ Now for some tricky shit:
37
+
38
+ [( def dog `now a thing for [( thing `yes maybe just [x] ' )] and some more' )]
39
+ [( dog )]
40
+
41
+
42
+
@@ -0,0 +1,9 @@
1
+ require 'lib/plasma.rb'
2
+
3
+ template = File.open(File.join(PLASMA_TEST, ARGV[0])).read
4
+ plasma = Plasma::Interpreter::PlasmaGrammarParser.new
5
+
6
+ env = Plasma::Interpreter::Env.new
7
+
8
+ p = plasma.parse template
9
+ puts p.evaluate(env)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plasma
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Spangler
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-08-04 00:00:00 -07:00
12
+ date: 2008-08-18 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -32,9 +32,12 @@ extra_rdoc_files: []
32
32
  files:
33
33
  - README
34
34
  - Rakefile
35
+ - test/hanoi.plasma
35
36
  - test/import_test.plasma
36
- - test/plasmatest.rb
37
+ - test/parse_test.rb
37
38
  - test/plasmic.plasma
39
+ - test/template_test.plasma
40
+ - test/template_test.rb
38
41
  - lib/extras
39
42
  - lib/extras/plasma_view.rb
40
43
  - lib/plasma
@@ -47,6 +50,7 @@ files:
47
50
  - lib/plasma/interpreter/plasma_grammar.treetop
48
51
  - lib/plasma/interpreter/plasma_grammarnode.rb
49
52
  - lib/plasma/interpreter/plasma_interpreter.rb
53
+ - lib/plasma/interpreter/polychoron_grammar.treetop
50
54
  - lib/plasma/interpreter.rb
51
55
  - lib/plasma/template
52
56
  - lib/plasma/template/plasma_template.rb
@@ -78,6 +82,6 @@ rubyforge_project: plasma
78
82
  rubygems_version: 1.0.1
79
83
  signing_key:
80
84
  specification_version: 2
81
- summary: plasma --- a lightweight interpreted templating language in ruby
85
+ summary: plasma --- a lightweight interpreted templating language in treetop and ruby
82
86
  test_files: []
83
87
 
@@ -1,37 +0,0 @@
1
- require 'lib/plasma.rb'
2
-
3
- plasma = Plasma::Interpreter::PlasmaGrammarParser.new
4
-
5
- decl = "| 'eiii | 1233333 | (def xxx 5) |"
6
- declb = "xxx"
7
- seq = "('oeheo | 238 | 11)"
8
- quote = "'(333333)"
9
- define = "((def a 2121212) | a)"
10
- defun = "(defun (ff x) (* x 13))"
11
- fun = "(fun (x c) (+ x c))"
12
- apply1 = "(+ 11 14)"
13
- apply2 = "((fun (x c) (+ x c)) 11 14)"
14
- curry = "((def aaa ((fun (a b) (* a b)) 3)) | (aaa 11))"
15
- sym = "((def tatao+ht-o*he<>i==== 555) | tatao+ht-o*he<>i====)"
16
- hash = "{yayay:77777 rrr:111}"
17
- list = "[11 33 449]"
18
- date = "3409-65-22"
19
- time = "55:32:18"
20
- str = '"yaodui iwfhoeo"'
21
- num = "444.22"
22
- test = "| (def yar (fun (x) (* 3 x))) |
23
- (def peanut (fun (y z) (/ (- y z) z))) |
24
- (peanut (yar 66) 12) |"
25
- bad = "(999)(888)"
26
- env = Plasma::Interpreter::Env.new
27
-
28
-
29
- statements = [seq, quote, define, defun, fun, apply1, apply2,
30
- sym, hash, list, date, time, str, num, test,
31
- decl, declb, defun, bad, curry]
32
- statements.each do |statement|
33
- parsed = plasma.parse(statement)
34
- evaluated = parsed.nil? ? "does not parse" : parsed.evaluate(env).to_plasma
35
-
36
- puts "#{statement} -> #{parsed} : #{evaluated}"
37
- end