plasma 0.0.1 → 0.1.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.
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