livetext 0.9.21 → 0.9.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.lt3 +8 -8
- data/bin/livetext +57 -40
- data/imports/bookish.rb +89 -90
- data/imports/calibre.rb +3 -3
- data/imports/livemagick.rb +17 -17
- data/imports/markdown.rb +10 -10
- data/imports/pyggish.rb +15 -47
- data/imports/tutorial.rb +18 -18
- data/lib/cmdargs.rb +10 -6
- data/lib/{errors.rb → livetext/errors.rb} +1 -1
- data/lib/{formatline.rb → livetext/formatline.rb} +69 -125
- data/lib/livetext/funcall.rb +84 -0
- data/lib/{functions.rb → livetext/functions.rb} +16 -3
- data/lib/livetext/global_helpers.rb +37 -0
- data/lib/livetext/handler/import.rb +44 -0
- data/lib/livetext/handler/mixin.rb +37 -0
- data/lib/livetext/handler.rb +3 -0
- data/lib/{helpers.rb → livetext/helpers.rb} +89 -67
- data/lib/{html.rb → livetext/html.rb} +3 -2
- data/lib/{parser → livetext/parser}/general.rb +0 -3
- data/lib/{parser → livetext/parser}/set.rb +1 -6
- data/lib/{parser → livetext/parser}/string.rb +2 -2
- data/lib/{parser.rb → livetext/parser.rb} +0 -1
- data/lib/livetext/parsing.rb +29 -0
- data/lib/livetext/paths.rb +13 -0
- data/lib/livetext/processor.rb +89 -0
- data/lib/livetext/reopen.rb +12 -0
- data/lib/livetext/skeleton.rb +17 -0
- data/lib/{standard.rb → livetext/standard.rb} +152 -122
- data/lib/livetext/userapi.rb +153 -0
- data/lib/livetext/version.rb +6 -0
- data/lib/livetext.rb +66 -27
- data/plugin/bookish.rb +85 -85
- data/plugin/calibre.rb +3 -3
- data/plugin/livemagick.rb +17 -17
- data/plugin/markdown.rb +10 -10
- data/plugin/pyggish.rb +131 -162
- data/plugin/tutorial.rb +15 -16
- data/test/all.rb +6 -0
- data/test/snapshots/def_method/expected-output.txt +2 -0
- data/test/snapshots/def_method/source.lt3 +4 -2
- data/test/snapshots/error_inc_line_num/OUT +17 -0
- data/test/snapshots/error_inc_line_num/README.txt +20 -0
- data/test/snapshots/error_inc_line_num/expected-output.txt +0 -6
- data/test/snapshots/error_inc_line_num/match-error.txt +1 -1
- data/test/snapshots/error_line_num/match-error.txt +1 -1
- data/test/snapshots/error_missing_end/expected-output.txt +0 -1
- data/test/snapshots/error_name_not_permitted/expected-output.txt +4 -0
- data/test/snapshots/error_name_not_permitted/match-error.txt +1 -1
- data/test/snapshots/error_no_such_copy/duh +26 -0
- data/test/snapshots/error_no_such_copy/expected-output.txt +1 -0
- data/test/snapshots/error_no_such_copy/match-error.txt +1 -1
- data/test/snapshots/error_no_such_copy/mystery.txt +36 -0
- data/test/snapshots/error_no_such_inc/match-error.txt +1 -1
- data/test/snapshots/error_no_such_mixin/expected-output.txt +1 -0
- data/test/snapshots/error_no_such_mixin/match-error.txt +1 -1
- data/test/snapshots/error_no_such_mixin/source.lt3 +1 -1
- data/test/snapshots/example_alpha/source.lt3 +2 -2
- data/test/snapshots/example_alpha2/expected-output.txt +0 -2
- data/test/snapshots/example_alpha2/source.lt3 +5 -4
- data/test/snapshots/{icanhaz → import}/expected-output.txt +2 -1
- data/test/snapshots/import/match-error.txt +1 -0
- data/test/snapshots/{icanhaz → import}/simple_import.rb +1 -1
- data/test/snapshots/{icanhaz → import}/source.lt3 +2 -2
- data/test/snapshots/{icanhaz2 → import2}/expected-error.txt +0 -0
- data/test/snapshots/{icanhaz2 → import2}/expected-output.txt +3 -1
- data/test/snapshots/{icanhaz2/simple_canhaz.rb → import2/simple_import.rb} +1 -1
- data/test/snapshots/import2/source.lt3 +8 -0
- data/test/snapshots/import_bookish/expected-error.txt +0 -0
- data/test/snapshots/import_bookish/expected-output.txt +10 -0
- data/test/snapshots/import_bookish/source.lt3 +7 -0
- data/test/snapshots/import_bookish/toc.tmp +0 -0
- data/test/snapshots/mixin_bookish/expected-error.txt +0 -0
- data/test/snapshots/mixin_bookish/expected-output.txt +10 -0
- data/test/snapshots/mixin_bookish/source.lt3 +7 -0
- data/test/snapshots/mixin_bookish/toc.tmp +0 -0
- data/test/snapshots/more_functions/expected-error.txt +0 -0
- data/test/snapshots/more_functions/expected-output.txt +37 -0
- data/test/snapshots/more_functions/source.lt3 +40 -0
- data/test/snapshots/raw_lines/expected-output.txt +0 -2
- data/test/snapshots/simple_import/expected-output.txt +2 -0
- data/test/snapshots/simple_import/simple_import.rb +1 -1
- data/test/snapshots/simple_import/source.lt3 +3 -1
- data/test/snapshots/simple_mixin/simple_mixin.rb +1 -1
- data/test/snapshots/single_raw_line/expected-output.txt +0 -2
- data/test/snapshots/subset.txt +14 -14
- data/test/snapshots.rb +30 -13
- data/test/unit/formatline.rb +253 -134
- data/test/unit/html.rb +2 -3
- data/test/unit/parser/general.rb +1 -2
- data/test/unit/parser/mixin.rb +1 -3
- data/test/unit/parser/set.rb +8 -12
- data/test/unit/parser/string.rb +6 -6
- data/test/unit/parser.rb +0 -1
- data/test/unit/standard.rb +0 -2
- metadata +47 -30
- data/imports/markdown_importable.rb +0 -45
- data/lib/handler/icanhaz.rb +0 -35
- data/lib/handler.rb +0 -1
- data/lib/livetext/importable.rb +0 -2
- data/lib/parser/file.rb +0 -8
- data/lib/parser/import.rb +0 -15
- data/lib/parser/mixin.rb +0 -38
- data/lib/processor.rb +0 -83
- data/lib/userapi.rb +0 -160
- data/test/snapshots/icanhaz/match-error.txt +0 -1
- data/test/snapshots/icanhaz2/source.lt3 +0 -6
- data/test/unit/parser/importable.rb +0 -19
@@ -1,6 +1,4 @@
|
|
1
1
|
|
2
|
-
require_relative 'standard' # FIXME umm, why is this necessary??
|
3
|
-
|
4
2
|
# Class Functions is where '$$func' functions are stored dynamically...
|
5
3
|
# user-def AND pre-def??
|
6
4
|
|
@@ -13,6 +11,21 @@ class Livetext::Functions
|
|
13
11
|
attr_accessor :param # kill this?
|
14
12
|
end
|
15
13
|
|
14
|
+
# FIXME Function parameters need to be fixed...
|
15
|
+
|
16
|
+
def isqrt(param = nil) # "integer square root" - Just for testing
|
17
|
+
arg = num = param # Takes any number
|
18
|
+
if num.nil? || num.empty?
|
19
|
+
arg = "NO PARAM" # Just for error text
|
20
|
+
end
|
21
|
+
# Integer()/Float() can raise error
|
22
|
+
num = num.include?(".") ? Float(num) : Integer(num)
|
23
|
+
# Returns truncated integer
|
24
|
+
Math.sqrt(num).to_i # user need not do to_s
|
25
|
+
rescue => err # Malformed number? negative?
|
26
|
+
"[Error evaluating $$isqrt(#{arg})]"
|
27
|
+
end
|
28
|
+
|
16
29
|
def date(param=nil)
|
17
30
|
Time.now.strftime("%F")
|
18
31
|
end
|
@@ -40,7 +53,7 @@ class Livetext::Functions
|
|
40
53
|
"<br>"*n
|
41
54
|
end
|
42
55
|
|
43
|
-
def yt(param)
|
56
|
+
def yt(param) # FIXME uh, this is crap
|
44
57
|
param = self.class.param
|
45
58
|
"https://www.youtube.com/watch?v=#{param}"
|
46
59
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
module GlobalHelpers
|
3
|
+
|
4
|
+
def check_disallowed(name)
|
5
|
+
raise DisallowedName(name) if disallowed?(name)
|
6
|
+
end
|
7
|
+
|
8
|
+
def check_file_exists(file)
|
9
|
+
graceful_error FileNotFound(file) unless File.exist?(file)
|
10
|
+
end
|
11
|
+
|
12
|
+
def grab_file(fname)
|
13
|
+
File.read(fname)
|
14
|
+
end
|
15
|
+
|
16
|
+
def search_upward(file)
|
17
|
+
value = nil
|
18
|
+
return file if File.exist?(file)
|
19
|
+
|
20
|
+
count = 1
|
21
|
+
loop do
|
22
|
+
front = "../" * count
|
23
|
+
count += 1
|
24
|
+
here = Pathname.new(front).expand_path.dirname.to_s
|
25
|
+
break if here == "/"
|
26
|
+
path = front + file
|
27
|
+
value = path if File.exist?(path)
|
28
|
+
break if value
|
29
|
+
end
|
30
|
+
::STDERR.puts "Cannot find #{file.inspect} from #{Dir.pwd}" unless value
|
31
|
+
return value
|
32
|
+
rescue
|
33
|
+
::STDERR.puts "Can't find #{file.inspect} from #{Dir.pwd}"
|
34
|
+
return nil
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
require_relative '../helpers'
|
3
|
+
|
4
|
+
class Livetext::Handler::Import
|
5
|
+
include Livetext::Helpers
|
6
|
+
include GlobalHelpers
|
7
|
+
|
8
|
+
attr_reader :file
|
9
|
+
|
10
|
+
def initialize(name)
|
11
|
+
@name = name
|
12
|
+
@file = find_file(name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.get_mod_name
|
16
|
+
file = File.new(@file + ".rb")
|
17
|
+
str = nil
|
18
|
+
file.each_line do |line|
|
19
|
+
str = line
|
20
|
+
break if str =~ /^module /
|
21
|
+
end
|
22
|
+
junk, name, junk2 = str.split
|
23
|
+
name
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.get_module(filename, parent)
|
27
|
+
# TTY.puts "#{__method__}: filename = #{filename.inspect}"
|
28
|
+
handler = self.new(filename)
|
29
|
+
parent.graceful_error FileNotFound(filename) if handler.file.nil?
|
30
|
+
@file = handler.file.sub(/.rb$/, "")
|
31
|
+
require @file # + ".rb"
|
32
|
+
modname = get_mod_name
|
33
|
+
newmod = Object.const_get("::" + modname)
|
34
|
+
newmod # return actual module
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def cwd_root?
|
40
|
+
File.dirname(File.expand_path(".")) == "/"
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
require_relative '../helpers'
|
3
|
+
|
4
|
+
class Livetext::Handler::Mixin
|
5
|
+
include Livetext::Helpers
|
6
|
+
include GlobalHelpers
|
7
|
+
|
8
|
+
attr_reader :file
|
9
|
+
|
10
|
+
def initialize(name, parent)
|
11
|
+
@name = name
|
12
|
+
@file = find_file(name, ".rb", "plugin")
|
13
|
+
parent.graceful_error FileNotFound(name) if @file.nil?
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.get_module(filename, parent)
|
17
|
+
handler = self.new(filename, parent)
|
18
|
+
modname, code = handler.read_mixin
|
19
|
+
eval(code) # Avoid in the future
|
20
|
+
newmod = Object.const_get("::" + modname)
|
21
|
+
newmod # return actual module
|
22
|
+
end
|
23
|
+
|
24
|
+
def read_mixin
|
25
|
+
modname = @name.gsub("/","_").capitalize
|
26
|
+
meths = grab_file(@file) # already has .rb?
|
27
|
+
[modname, "module ::#{modname}; #{meths}\nend"]
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def cwd_root?
|
33
|
+
File.dirname(File.expand_path(".")) == "/"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
@@ -1,5 +1,7 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
require_relative 'global_helpers'
|
3
|
+
|
4
|
+
module Livetext::Helpers
|
3
5
|
|
4
6
|
Space = " "
|
5
7
|
Sigil = "." # Can't change yet
|
@@ -7,6 +9,14 @@ module Helpers
|
|
7
9
|
ESCAPING = { "'" => ''', '&' => '&', '"' => '"',
|
8
10
|
'<' => '<', '>' => '>' }
|
9
11
|
|
12
|
+
def friendly_error(err)
|
13
|
+
return graceful_error(err) if self.respond_to?(:graceful_error)
|
14
|
+
return self.parent.graceful_error(err) if self.respond_to?(:parent)
|
15
|
+
raise err
|
16
|
+
rescue => myerr
|
17
|
+
TTY.puts "--- Warning: friendly_error #{myerr.inspect}"
|
18
|
+
end
|
19
|
+
|
10
20
|
def escape_html(string)
|
11
21
|
enc = string.encoding
|
12
22
|
unless enc.ascii_compatible?
|
@@ -23,108 +33,115 @@ module Helpers
|
|
23
33
|
string.gsub(/['&\"<>]/, ESCAPING)
|
24
34
|
end
|
25
35
|
|
26
|
-
def
|
27
|
-
|
36
|
+
def showme(obj, tag = "")
|
37
|
+
whence = caller[0]
|
38
|
+
file, line, meth = whence.split(":")
|
39
|
+
file = File.basename(file)
|
40
|
+
meth = meth[4..-2]
|
41
|
+
tag << " =" if tag
|
42
|
+
hide_class = [true, false, nil].include?(obj)
|
43
|
+
klass = hide_class ? "" : "(#{obj.class}) "
|
44
|
+
puts " #{tag} #{klass}#{obj.inspect} in ##{meth} [#{file} line #{line}]"
|
45
|
+
end
|
46
|
+
|
47
|
+
def debug(*args)
|
48
|
+
puts(*args) if ENV['debug']
|
49
|
+
end
|
50
|
+
|
51
|
+
def find_file(name, ext=".rb", which="imports")
|
52
|
+
failed = "#{__method__}: expected 'imports' or 'plugin'"
|
53
|
+
raise failed unless %w[imports plugin].include?(which)
|
54
|
+
paths = [Livetext::Path.sub(/lib.livetext/, "#{which}/"), "./"]
|
28
55
|
base = "#{name}#{ext}"
|
29
56
|
paths.each do |path|
|
30
57
|
file = path + base
|
31
58
|
return file if File.exist?(file)
|
32
59
|
end
|
33
|
-
|
34
|
-
raise "No such mixin '#{name}'"
|
35
|
-
|
36
|
-
# # Really want to search upward??
|
37
|
-
# raise "No such mixin '#{name}'" if cwd_root?
|
38
|
-
# Dir.chdir("..") { find_file(name) }
|
60
|
+
return nil
|
39
61
|
end
|
40
62
|
|
41
63
|
def self.rx(str, space=nil)
|
42
64
|
Regexp.compile("^" + Regexp.escape(str) + "#{space}")
|
43
65
|
end
|
44
66
|
|
45
|
-
Comment
|
46
|
-
|
47
|
-
|
67
|
+
Comment = rx(Sigil, Space)
|
68
|
+
DotCmd = rx(Sigil)
|
69
|
+
DollarDot = /^ *\$\.[A-Za-z]/
|
48
70
|
|
49
|
-
## FIXME process_file[!] should call process[_text]
|
71
|
+
## FIXME process_file[!] should call process[_text] ?
|
50
72
|
|
51
73
|
def process_file(fname, btrace=false)
|
74
|
+
graceful_error FileNotFound(fname) unless File.exist?(fname)
|
52
75
|
setfile(fname)
|
53
76
|
text = File.readlines(fname)
|
54
77
|
enum = text.each
|
55
78
|
@backtrace = btrace
|
56
79
|
@main.source(enum, fname, 0)
|
57
80
|
line = nil
|
58
|
-
loop do
|
81
|
+
loop do
|
59
82
|
line = @main.nextline
|
60
83
|
break if line.nil?
|
61
|
-
process_line(line)
|
84
|
+
success = process_line(line)
|
85
|
+
break unless success
|
62
86
|
end
|
63
|
-
val = @main.finalize
|
64
|
-
@body
|
87
|
+
val = @main.finalize rescue nil
|
88
|
+
@body # FIXME? @body.join("\n") # array
|
89
|
+
return true
|
65
90
|
end
|
66
91
|
|
67
92
|
def process_line(line)
|
68
|
-
|
93
|
+
success = true
|
69
94
|
case line # must apply these in order
|
70
95
|
when Comment
|
71
|
-
handle_scomment(line)
|
72
|
-
when
|
73
|
-
handle_dotcmd(line)
|
74
|
-
when
|
75
|
-
|
76
|
-
@indentation.push(indent)
|
77
|
-
line.sub!(/^ *\$/, "")
|
78
|
-
handle_dotcmd(line)
|
79
|
-
indentation.pop
|
96
|
+
success = handle_scomment(line)
|
97
|
+
when DotCmd
|
98
|
+
success = handle_dotcmd(line)
|
99
|
+
when DollarDot
|
100
|
+
success = handle_dollar_dot
|
80
101
|
else
|
81
|
-
|
102
|
+
api.passthru(line) # must succeed?
|
82
103
|
end
|
104
|
+
success
|
105
|
+
end
|
106
|
+
|
107
|
+
def handle_dollar_dot
|
108
|
+
indent = line.index("$") + 1
|
109
|
+
@indentation.push(indent)
|
110
|
+
line.sub!(/^ *\$/, "")
|
111
|
+
success = handle_dotcmd(line)
|
112
|
+
indentation.pop
|
113
|
+
success
|
114
|
+
end
|
115
|
+
|
116
|
+
def invoke_dotcmd(name)
|
117
|
+
# FIXME Add cmdargs stuff... depends on name, etc.
|
118
|
+
retval = @main.send(name)
|
119
|
+
retval
|
120
|
+
# rescue NoMethodError => err
|
121
|
+
# graceful_error(err)
|
122
|
+
rescue => err
|
123
|
+
graceful_error(err)
|
83
124
|
end
|
84
125
|
|
85
126
|
def handle_dotcmd(line, indent = 0)
|
127
|
+
# TTY.puts ">>> #{__method__} in #{__FILE__}" # if ENV['debug']
|
86
128
|
indent = @indentation.last # top of stack
|
87
|
-
line = line.sub(/# .*$/, "")
|
88
|
-
name = get_name(line)
|
89
|
-
|
129
|
+
line = line.sub(/# .*$/, "") # FIXME Could be problematic?
|
130
|
+
name = get_name(line)
|
131
|
+
success = true # Be optimistic... :P
|
90
132
|
case
|
91
133
|
when name == :end # special case
|
92
|
-
|
93
|
-
raise EndWithoutOpening()
|
134
|
+
graceful_error EndWithoutOpening()
|
94
135
|
when @main.respond_to?(name)
|
95
|
-
|
96
|
-
|
97
|
-
# NOTE: The above line is where the magic happens!
|
98
|
-
# A name like 'foobar' results in an invocation of
|
99
|
-
# @main.foobar (where @main is a Processor, and any
|
100
|
-
# new methods (e.g. from a mixin) are added to @main
|
101
|
-
#
|
102
|
-
# So all the functionality from _args and _raw_args
|
103
|
-
# and _data (among others?) will be encapsulated in
|
104
|
-
# 'some' kind of PORO which handles access to all
|
105
|
-
# these things as well as the 'body' between the
|
106
|
-
# command and its corresponding .end
|
107
|
-
#
|
108
|
-
# The 'body' functionality is so commonly used, I plan
|
109
|
-
# to pass it in separately as needed (even though the
|
110
|
-
# args object should make it available also).
|
111
|
-
#
|
112
|
-
# Every method corresponding to a dot commmand will
|
113
|
-
# get args and body passed in as needed. Every one of
|
114
|
-
# the signatures already has (args = nil, body = nil)
|
115
|
-
# but nothing is being passed in that way yet.
|
116
|
-
#
|
117
|
-
# Refer to lib/cmdargs.rb for more! This is *strictly*
|
118
|
-
# experimental and a "work in progress."
|
136
|
+
success = invoke_dotcmd(name)
|
119
137
|
else
|
120
|
-
|
121
|
-
raise "Name '#{name}' is unknown"
|
122
|
-
return
|
138
|
+
graceful_error UnknownMethod(name)
|
123
139
|
end
|
124
|
-
|
140
|
+
success
|
125
141
|
end
|
126
142
|
|
127
143
|
def handle_scomment(line)
|
144
|
+
return true
|
128
145
|
end
|
129
146
|
|
130
147
|
def get_name(line)
|
@@ -133,15 +150,17 @@ module Helpers
|
|
133
150
|
name = "dot_" + name if %w[include def].include?(name)
|
134
151
|
@main.check_disallowed(name)
|
135
152
|
@main.data = data
|
136
|
-
|
153
|
+
@main.api.data = data
|
154
|
+
name.to_sym
|
137
155
|
end
|
138
156
|
|
139
157
|
def check_disallowed(name)
|
140
|
-
|
158
|
+
friendly_error DisallowedName(name) if disallowed?(name)
|
141
159
|
end
|
142
160
|
|
143
161
|
def check_file_exists(file)
|
144
|
-
|
162
|
+
# raise FileNotFound(file) unless File.exist?(file)
|
163
|
+
return File.exist?(file)
|
145
164
|
end
|
146
165
|
|
147
166
|
def set_variables(pairs)
|
@@ -153,6 +172,9 @@ module Helpers
|
|
153
172
|
|
154
173
|
def grab_file(fname)
|
155
174
|
File.read(fname)
|
175
|
+
rescue
|
176
|
+
::STDERR.puts "Can't find #{fname.inspect} \n "
|
177
|
+
return nil
|
156
178
|
end
|
157
179
|
|
158
180
|
def search_upward(file)
|
@@ -169,15 +191,15 @@ module Helpers
|
|
169
191
|
value = path if File.exist?(path)
|
170
192
|
break if value
|
171
193
|
end
|
172
|
-
STDERR.puts "Cannot find #{file.inspect} from #{Dir.pwd}" unless value
|
194
|
+
::STDERR.puts "Cannot find #{file.inspect} from #{Dir.pwd}" unless value
|
173
195
|
return value
|
174
196
|
rescue
|
175
|
-
STDERR.puts "Can't find #{file.inspect} from #{Dir.pwd}"
|
197
|
+
::STDERR.puts "Can't find #{file.inspect} from #{Dir.pwd}"
|
176
198
|
return nil
|
177
199
|
end
|
178
200
|
|
179
201
|
def include_file(file)
|
180
|
-
|
202
|
+
api.args = [file]
|
181
203
|
dot_include
|
182
204
|
end
|
183
205
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
module HTMLHelper
|
2
3
|
|
3
4
|
def wrapped(str, *tags) # helper
|
@@ -15,9 +16,9 @@ module HTMLHelper
|
|
15
16
|
|
16
17
|
def wrap(*tags) # helper
|
17
18
|
open, close = open_close_tags(*tags)
|
18
|
-
|
19
|
+
api.out open
|
19
20
|
yield
|
20
|
-
|
21
|
+
api.out close
|
21
22
|
end
|
22
23
|
|
23
24
|
def open_close_tags(*tags)
|
@@ -1,7 +1,4 @@
|
|
1
1
|
|
2
|
-
require_relative '../livetext'
|
3
|
-
require_relative 'string'
|
4
|
-
|
5
2
|
make_exception(:BadVariableName, "Error: invalid variable name")
|
6
3
|
make_exception(:NoEqualSign, "Error: no equal sign found")
|
7
4
|
|
@@ -107,7 +104,6 @@ class Livetext::ParseSet < StringParser
|
|
107
104
|
char = grab
|
108
105
|
break if eos?
|
109
106
|
break if char == quote
|
110
|
-
# break if char.nil?
|
111
107
|
char = escaped if char == "\\"
|
112
108
|
value << char
|
113
109
|
end
|
@@ -123,8 +119,7 @@ class Livetext::ParseSet < StringParser
|
|
123
119
|
value = ""
|
124
120
|
loop do
|
125
121
|
char = peek
|
126
|
-
break if eos?
|
127
|
-
# break if char.nil?
|
122
|
+
break if eos?
|
128
123
|
break if char == " " || char == ","
|
129
124
|
value << char
|
130
125
|
char = grab
|
@@ -24,7 +24,7 @@ class StringParser
|
|
24
24
|
check_eos
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
27
|
+
def lookahead
|
28
28
|
@line[@i + 1]
|
29
29
|
end
|
30
30
|
|
@@ -62,7 +62,7 @@ end
|
|
62
62
|
|
63
63
|
=begin
|
64
64
|
skip
|
65
|
-
|
65
|
+
lookahead skip! peek!(?)
|
66
66
|
expect_alpha
|
67
67
|
expect_number
|
68
68
|
skip_spaces
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
# Constants for parsing
|
3
|
+
|
4
|
+
module Livetext::ParsingConstants
|
5
|
+
SimpleFormats = {}
|
6
|
+
SimpleFormats[:b] = %w[<b> </b>]
|
7
|
+
SimpleFormats[:i] = %w[<i> </i>]
|
8
|
+
SimpleFormats[:t] = ["<font size=+1><tt>", "</tt></font>"]
|
9
|
+
SimpleFormats[:s] = %w[<strike> </strike>]
|
10
|
+
|
11
|
+
BITS = SimpleFormats.keys
|
12
|
+
|
13
|
+
Null = ""
|
14
|
+
Space = " "
|
15
|
+
Alpha = /[A-Za-z]/
|
16
|
+
AlNum = /[A-Za-z0-9_]/
|
17
|
+
LF = "\n"
|
18
|
+
LBrack = "["
|
19
|
+
|
20
|
+
Blank = [" ", nil, "\n"]
|
21
|
+
Punc = [")", ",", ".", " ", "\n"]
|
22
|
+
NoAlpha = /[^A-Za-z0-9_]/
|
23
|
+
NoAlphaDot = /[^.A-Za-z0-9_]/
|
24
|
+
Param = ["]", "\n", nil]
|
25
|
+
Escape = "\\" # not an ESC char
|
26
|
+
|
27
|
+
Syms = { "*" => :b, "_" => :i, "`" => :t, "~" => :s }
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Reopening for paths... do differently?
|
2
|
+
|
3
|
+
class Livetext
|
4
|
+
def self.get_path(dir = "")
|
5
|
+
path = File.join(File.dirname(__FILE__), dir)
|
6
|
+
File.expand_path(path)
|
7
|
+
end
|
8
|
+
|
9
|
+
Path = self.get_path
|
10
|
+
Plugins = self.get_path("../plugin")
|
11
|
+
Imports = self.get_path("../imports")
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
|
2
|
+
# Class Processor does the actual work of processing input.
|
3
|
+
|
4
|
+
class Processor
|
5
|
+
|
6
|
+
GenericError = Class.new(StandardError)
|
7
|
+
|
8
|
+
include Livetext::Standard
|
9
|
+
|
10
|
+
Disallowed =
|
11
|
+
%i[ __binding__ __id__ __send__ class
|
12
|
+
clone display dup enum_for
|
13
|
+
eql? equal? extend freeze
|
14
|
+
frozen? hash inspect instance_eval
|
15
|
+
instance_exec instance_of? is_a? kind_of?
|
16
|
+
method methods nil? object_id
|
17
|
+
pretty_inspect private_methods protected_methods public_method
|
18
|
+
public_methods public_send respond_to? send
|
19
|
+
singleton_class singleton_method singleton_methods taint
|
20
|
+
tainted? tap to_enum to_s
|
21
|
+
trust untaint untrust untrusted?
|
22
|
+
define_singleton_method instance_variable_defined?
|
23
|
+
instance_variable_get instance_variable_set
|
24
|
+
remove_instance_variable instance_variables ]
|
25
|
+
|
26
|
+
attr_reader :parent, :sources
|
27
|
+
|
28
|
+
def initialize(parent, output = nil)
|
29
|
+
@parent = parent
|
30
|
+
@nopass = false
|
31
|
+
@nopara = false
|
32
|
+
# Meh?
|
33
|
+
@output = ::Livetext.output = (output || File.open("/dev/null", "w"))
|
34
|
+
@sources = []
|
35
|
+
@indentation = @parent.indentation
|
36
|
+
@_mixins = []
|
37
|
+
@_imports = []
|
38
|
+
end
|
39
|
+
|
40
|
+
def api
|
41
|
+
@parent.api # FIXME Is this weird??
|
42
|
+
end
|
43
|
+
|
44
|
+
def output=(io)
|
45
|
+
@output = io
|
46
|
+
end
|
47
|
+
|
48
|
+
def error(*args)
|
49
|
+
::STDERR.puts *args
|
50
|
+
end
|
51
|
+
|
52
|
+
def _error!(err, raise_error=false, trace=false) # FIXME much bullshit happens here
|
53
|
+
where = @sources.last || @live.save_location
|
54
|
+
error "Error: #{err} (at #{where[1]} line #{where[2]})"
|
55
|
+
error(err.backtrace) rescue nil
|
56
|
+
raise GenericError.new("Error: #{err}") if raise_error
|
57
|
+
end
|
58
|
+
|
59
|
+
def disallowed?(name)
|
60
|
+
Disallowed.include?(name.to_sym)
|
61
|
+
end
|
62
|
+
|
63
|
+
def source(enum, file, line)
|
64
|
+
@sources.push([enum, file, line])
|
65
|
+
end
|
66
|
+
|
67
|
+
def peek_nextline
|
68
|
+
return nil if @sources.empty?
|
69
|
+
source = @sources.last
|
70
|
+
line = source[0].peek
|
71
|
+
line
|
72
|
+
rescue StopIteration
|
73
|
+
@sources.pop
|
74
|
+
nil
|
75
|
+
rescue => err
|
76
|
+
TTY.puts "#{__method__}: RESCUE err = #{err.inspect}"
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
|
80
|
+
def nextline
|
81
|
+
return nil if @sources.empty?
|
82
|
+
line = @sources.last[0].next
|
83
|
+
@sources.last[2] += 1
|
84
|
+
line
|
85
|
+
rescue StopIteration
|
86
|
+
@sources.pop
|
87
|
+
nil
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'parser/string' # FIXME eh, should fix this
|
2
|
+
|
3
|
+
# Class Livetext skeleton (top level).
|
4
|
+
|
5
|
+
class Livetext
|
6
|
+
module Handler
|
7
|
+
end
|
8
|
+
|
9
|
+
module ParsingConstants
|
10
|
+
end
|
11
|
+
|
12
|
+
class FormatLine < StringParser
|
13
|
+
module FunCall
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|