livetext 0.8.77 → 0.8.78

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,297 +1,322 @@
1
1
  class FormatLine
2
-
3
- EOL = :eol
4
- Alpha = /[a-z]/
5
- Alpha2 = /[a-z0-9_]/
6
- Other = Object
7
-
8
2
  SimpleFormats = {}
9
3
  SimpleFormats[:b] = %w[<b> </b>]
10
4
  SimpleFormats[:i] = %w[<i> </i>]
11
5
  SimpleFormats[:t] = ["<font size=+1><tt>", "</tt></font>"]
12
6
  SimpleFormats[:s] = %w[<strike> </strike>]
7
+
8
+ Null = ""
9
+ Space = " "
10
+ Alpha = /[A-Za-z]/
11
+ AlNum = /[A-Za-z0-9_]/
12
+ LF = "\n"
13
+ LBrack = "["
14
+
15
+ Blank = [" ", nil, "\n"]
16
+ Punc = [")", ",", ".", " ", "\n"]
17
+ NoAlpha = /[^A-Za-z0-9_]/
18
+ Param = ["]", "\n", nil]
19
+ Escape = "\\" # not an ESC char
13
20
 
14
- def initialize
15
- @buffer, @vname, @fname, @param, @substr = "", "", "", "", ""
21
+ def terminate?(terminators, ch)
22
+ if terminators.is_a? Regexp
23
+ terminators === ch
24
+ else
25
+ terminators.include?(ch)
26
+ end
16
27
  end
17
28
 
18
- def peek
19
- @enum.peek
20
- rescue StopIteration
21
- EOL
29
+ attr_reader :out
30
+
31
+ def initialize(line, context)
32
+ context ||= binding
33
+ @context = context
34
+ @line = line
35
+ @i = -1
36
+ @token = Null.dup
37
+ @tokenlist = []
22
38
  end
23
39
 
24
- def grab
25
- @enum.next
26
- rescue StopIteration
27
- EOL
40
+ def self.parse!(line, context = nil)
41
+ x = self.new(line.chomp, context)
42
+ x.tokenize(line)
43
+ x.evaluate # (context)
28
44
  end
29
45
 
30
- def skip
31
- @enum.next
32
- @enum.peek
33
- rescue StopIteration
34
- EOL
46
+ def tokenize(line)
47
+ grab
48
+ loop do
49
+ case curr
50
+ when Escape; go; add curr; grab
51
+ when "$"
52
+ _dollar
53
+ when "*", "_", "`", "~"
54
+ marker curr
55
+ add curr
56
+ when LF, nil
57
+ break
58
+ else
59
+ add curr
60
+ end
61
+ grab
62
+ end
63
+ add_token(:str)
64
+ @tokenlist
35
65
  end
36
66
 
37
- def keep(initial = "")
38
- @buffer << initial
39
- @buffer << @enum.next
40
- rescue StopIteration
41
- EOL
67
+ def embed(sym, str)
68
+ pre, post = SimpleFormats[sym]
69
+ pre + str + post
42
70
  end
43
71
 
44
- def emit(str = "")
45
- @buffer << str
72
+ def evaluate(tokens = @tokenlist)
73
+ @out = ""
74
+ return "" if tokens.empty?
75
+ gen = tokens.each
76
+ token = gen.next
77
+ loop do
78
+ break if token.nil?
79
+ sym, val = *token
80
+ case sym
81
+ when :str
82
+ @out << val unless val == "\n" # BUG
83
+ when :var
84
+ @out << varsub(val)
85
+ when :func
86
+ param = nil
87
+ arg = gen.peek
88
+ if [:colon, :brackets].include? arg[0]
89
+ arg = gen.next # for real
90
+ param = arg[1]
91
+ end
92
+ @out << funcall(val, param)
93
+ when :b, :i, :t, :s
94
+ @out << embed(sym, val)
95
+ else
96
+ add_token :str
97
+ end
98
+ token = gen.next
99
+ end
100
+ @out
46
101
  end
47
102
 
48
- def funcall(name, param)
49
- if self.respond_to?("func_" + name.to_s)
50
- self.send("func_" + name.to_s, param)
51
- else
52
- fobj = ::Livetext::Functions.new
53
- ::Livetext::Functions.param = param # is this
54
- ::Livetext::Functions.context = @context # screwed up???
55
- fobj.send(name)
103
+ def curr
104
+ @line[@i]
105
+ end
106
+
107
+ def prev
108
+ @line[@i-1]
109
+ end
110
+
111
+ def next!
112
+ @line[@i+1]
113
+ end
114
+
115
+ def grab
116
+ @line[@i+=1]
117
+ end
118
+
119
+ def grab_colon_param
120
+ grab # grab :
121
+ param = ""
122
+ loop do
123
+ case next!
124
+ when Escape
125
+ grab
126
+ param << next!
127
+ grab
128
+ when Space, LF, nil; break
129
+ else
130
+ param << next!
131
+ grab
132
+ end
133
+ end
134
+
135
+ param = nil if param.empty?
136
+ param
137
+ end
138
+
139
+ def grab_func_param
140
+ grab # [
141
+ param = ""
142
+ loop do
143
+ case next!
144
+ when Escape
145
+ grab
146
+ param << next!
147
+ grab
148
+ when "]", LF, nil; break
149
+ else
150
+ param << next!
151
+ grab
152
+ end
56
153
  end
154
+
155
+ add curr
156
+ grab
157
+ param = nil if param.empty?
158
+ param
159
+ end
160
+
161
+ def add(str)
162
+ @token << str unless str.nil?
57
163
  end
58
164
 
59
- def vsub
60
- @buffer << Livetext::Vars[@vname]
61
- @vname = ""
165
+ Syms = { "*" => :b, "_" => :i, "`" => :t, "~" => :s }
166
+
167
+ def add_token(kind, token = @token)
168
+ @tokenlist << [kind, token] unless token.empty?
169
+ @token = Null.dup
62
170
  end
63
171
 
64
- def fcall
65
- @buffer << funcall(@fname, @param)
66
- @fname, @param = "", ""
172
+ def grab_alpha
173
+ str = Null.dup
174
+ grab
175
+ loop do
176
+ break if curr.nil?
177
+ str << curr
178
+ break if terminate?(NoAlpha, next!)
179
+ grab
180
+ end
181
+ str
67
182
  end
68
183
 
69
- # FIXME Much of this should be done via CSS
70
- # FIXME In particular, strike is deprecated.
184
+ def _dollar
185
+ grab
186
+ case curr
187
+ when LF; add "$"; add_token :str
188
+ when " "; add "$ "; add_token :str
189
+ when nil; add "$"; add_token :str
190
+ when "$"; _double_dollar
191
+ when "."; _dollar_dot
192
+ when /[A-Za-z]/
193
+ add_token :str
194
+ var = curr + grab_alpha
195
+ add_token(:var, var)
196
+ else
197
+ add "$" + curr
198
+ add_token(:string)
199
+ end
200
+ end
71
201
 
72
- def bold
73
- d0, d1 = SimpleFormats[:b]
74
- @buffer << "#{d0}#@substr#{d1}"
75
- @substr = ""
202
+ def _double_dollar
203
+ case next!
204
+ when Space; add_token :string, "$$ "; grab; return
205
+ when LF, nil; add "$$"; add_token :str
206
+ when Alpha
207
+ add_token(:str, @token)
208
+ func = grab_alpha
209
+ add_token(:func, func)
210
+ case next!
211
+ when ":"; param = grab_colon_param; add_token(:colon, param)
212
+ when "["; param = grab_func_param; add_token(:brackets, param)
213
+ else # do nothing
214
+ end
215
+ else
216
+ grab; add_token :str, "$$" + curr; return
217
+ end
76
218
  end
77
219
 
78
- def ttype
79
- d0, d1 = SimpleFormats[:t]
80
- @buffer << "#{d0}#@substr#{d1}"
81
- @substr = ""
220
+ def dollar_dot
221
+ add_token :ddot, @line[@i..-1]
82
222
  end
83
223
 
84
- def italics
85
- d0, d1 = SimpleFormats[:i]
86
- @buffer << "#{d0}#@substr#{d1}"
87
- @substr = ""
224
+ def marker(char)
225
+ add_token :str
226
+ sym = Syms[char]
227
+ if embedded?
228
+ add char # ??? add_token "*", :string
229
+ return
230
+ end
231
+ grab
232
+ case curr
233
+ when Space
234
+ add char + " "
235
+ add_token :str
236
+ grab
237
+ when LF, nil
238
+ add char
239
+ add_token :str
240
+ when char; double_marker(char)
241
+ when LBrack; long_marker(char)
242
+ else
243
+ add curr
244
+ str = collect!(sym, Blank)
245
+ add_token sym, str
246
+ add curr # next char onto next token...
247
+ end
88
248
  end
89
249
 
90
- def strike
91
- d0, d1 = SimpleFormats[:s]
92
- @buffer << "#{d0}#@substr#{d1}"
93
- @substr = ""
250
+ def double_marker(char)
251
+ sym = Syms[char]
252
+ grab
253
+ kind = sym # "string_#{char}".to_sym
254
+ case next! # first char after **
255
+ when Space, LF, nil
256
+ pre, post = SimpleFormats[sym]
257
+ add_token kind
258
+ else
259
+ str = collect!(sym, Punc)
260
+ grab unless next!.nil?
261
+ add_token kind, str
262
+ end
94
263
  end
95
264
 
96
- def parse(line, context = nil)
97
- context ||= binding
98
- @context = context
99
- @enum = line.chomp.each_char
100
- @buffer = ""
101
- @substr = ""
102
- @fname = ""
103
- @vname = ""
104
- @param = ""
105
-
106
- # FIXME - refactor, generalize, clarify
107
-
108
- loop do # starting state
109
- char = peek
110
- case char
111
- when "\\"
112
- char = skip
113
- case char
114
- when "$", "*", "_", "`", "~"
115
- emit(char)
116
- skip
117
- when " "
118
- emit("\\ ")
119
- skip
120
- when EOL
121
- emit("\\")
122
- break
123
- when Other
124
- emit("\\") # logic??
125
- end
126
- when EOL
127
- break
128
- when "$" # var or func or $
129
- case skip
130
- when EOL
131
- emit("$")
132
- break
133
- when Alpha
134
- loop { ch = peek; break if ch == EOL; @vname << grab; break unless Alpha2 === peek }
135
- vsub
136
- when "$"
137
- case skip
138
- when EOL
139
- emit("$$")
140
- break
141
- when Alpha
142
- loop { ch = peek; break if ch == EOL; @fname << grab; break unless Alpha2 === peek }
143
- case peek
144
- when " " # no param - just call
145
- @param = nil
146
- fcall # no param? Hmm
147
- when "[" # long param
148
- skip
149
- loop do
150
- if peek == "\\"
151
- skip
152
- @param << grab
153
- end
154
- break if ["]", EOL].include?(peek)
155
- @param << grab
156
- end
157
- skip
158
- fcall
159
- when ":" # param (single token or to-eol)
160
- case skip
161
- when ":" # param to eol
162
- skip
163
- loop { break if peek == EOL; @param << grab }
164
- when Other # grab until space or eol
165
- loop { @param << grab; break if [" ", EOL].include?(peek) }
166
- fcall
167
- end
168
- when Other # no param - just call
169
- fcall
170
- end
171
- when Other
172
- emit "$$"
173
- end
174
- when Other
175
- emit "$"
176
- end
177
- when "*"
178
- case skip
179
- when EOL
180
- emit "*"
181
- when " "
182
- emit "*"
183
- when "["
184
- skip
185
- loop do
186
- if peek == "\\"
187
- skip
188
- @substr << grab
189
- next
190
- end
191
- break if ["]", EOL].include?(peek)
192
- @substr << grab
193
- end
194
- skip
195
- bold
196
- when Other
197
- loop { @substr << grab; break if [" ", EOL].include?(peek) }
198
- bold
199
- end
200
- when "_"
201
- case skip
202
- when EOL
203
- emit "_"
204
- when " "
205
- emit "_"
206
- when "["
207
- skip
208
- loop do
209
- if peek == "\\"
210
- skip
211
- @substr << grab
212
- next
213
- end
214
- break if ["]", EOL].include?(peek)
215
- @substr << grab
216
- end
217
- skip
218
- italics
219
- when "_" # doubled...
220
- skip
221
- loop do
222
- if peek == "\\"
223
- skip
224
- @substr << grab
225
- next
226
- end
227
- break if [".", ",", ")", EOL].include?(peek)
228
- @substr << grab
229
- end
230
- italics
231
- when Other
232
- loop { @substr << grab; break if [" ", EOL].include?(peek) }
233
- italics
234
- end
235
- when "`"
236
- case skip
237
- when EOL
238
- emit "`"
239
- when " "
240
- emit "`"
241
- when "["
242
- skip
243
- loop do
244
- if peek == "\\"
245
- skip
246
- @substr << grab
247
- next
248
- end
249
- break if ["]", EOL].include?(peek)
250
- @substr << grab
251
- end
252
- skip
253
- ttype
254
- when "`" # doubled...
255
- skip
256
- loop { break if [".", ",", ")", EOL].include?(peek); @substr << grab } # ";" ?? FIXME
257
- ttype
258
- when Other
259
- loop { @substr << grab; break if [" ", EOL].include?(peek) }
260
- ttype
261
- end
262
- when "~"
263
- case skip
264
- when EOL
265
- emit "~"
266
- when " "
267
- emit "~"
268
- when "["
269
- skip
270
- loop do
271
- if peek == "\\"
272
- skip
273
- @substr << grab
274
- next
275
- end
276
- break if ["]", EOL].include?(peek)
277
- @substr << grab
278
- end
279
- skip
280
- strike
281
- when "~" # doubled...
282
- skip
283
- loop { break if [".", ",", ")", EOL].include?(peek); @substr << grab } # ";" ?? FIXME
284
- strike
285
- when Other
286
- loop { @substr << grab; break if [" ", EOL].include?(peek) }
287
- strike
288
- end
289
- when Other
290
- keep
265
+ def long_marker(char)
266
+ sym = Syms[char]
267
+ # grab # skip left bracket
268
+ kind = sym # "param_#{sym}".to_sym
269
+ arg = collect!(sym, Param, true)
270
+ add_token kind, arg
271
+ end
272
+
273
+ def collect!(sym, terminators, param=false)
274
+ str = Null.dup # next is not " ","*","["
275
+ grab
276
+ loop do
277
+ if curr == Escape
278
+ str << grab # ch = escaped char
279
+ grab
280
+ next
291
281
  end
282
+ break if terminate?(terminators, curr)
283
+ str << curr # not a terminator
284
+ grab
292
285
  end
286
+ grab if param && curr == "]" # skip right bracket
287
+ add str
288
+ end
293
289
 
294
- @buffer
290
+ ############
291
+
292
+ ### From FormatLine:
293
+
294
+ def funcall(name, param)
295
+ result =
296
+ if self.respond_to?("func_" + name.to_s)
297
+ self.send("func_" + name.to_s, param)
298
+ else
299
+ fobj = ::Livetext::Functions.new
300
+ ::Livetext::Functions.param = param # is this
301
+ ::Livetext::Functions.context = @context # screwed up???
302
+ fobj.send(name)
303
+ end
304
+ result
295
305
  end
296
- end
297
306
 
307
+ def varsub(name)
308
+ result = Livetext::Vars[name]
309
+ result
310
+ end
311
+
312
+ #####
313
+
314
+ def showme(tag)
315
+ char = @line[@cc]
316
+ puts "--- #{tag}: ch=#{@ch.inspect} next=#{@next.inspect} (cc=#@cc:#{char.inspect}) out=#{@out.inspect}"
317
+ end
318
+
319
+ def embedded?
320
+ ! (['"', "'", " ", nil].include? prev)
321
+ end
322
+ end