livetext 0.9.08 → 0.9.13
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.
- checksums.yaml +4 -4
- data/bin/livetext +0 -1
- data/lib/errors.rb +13 -0
- data/lib/formatline.rb +3 -5
- data/lib/functions.rb +6 -2
- data/lib/helpers.rb +21 -0
- data/lib/html.rb +32 -0
- data/lib/livetext/importable.rb +2 -0
- data/lib/livetext.rb +52 -46
- data/lib/parser/general.rb +38 -0
- data/lib/parser/import.rb +17 -0
- data/lib/parser/mixin.rb +46 -0
- data/lib/parser/set.rb +136 -0
- data/lib/parser/string.rb +55 -0
- data/lib/parser.rb +5 -0
- data/lib/processor.rb +26 -18
- data/lib/standard.rb +145 -292
- data/lib/userapi.rb +6 -5
- data/livetext.gemspec +1 -2
- data/test/all.rb +3 -0
- data/test/formatting.rb +2 -9
- data/test/{data → snapshots}/basic_formatting/expected-error.txt +0 -0
- data/test/{data → snapshots}/basic_formatting/expected-output.txt +0 -0
- data/test/{data → snapshots}/basic_formatting/source.lt3 +0 -0
- data/test/{data → snapshots}/block_comment/expected-error.txt +0 -0
- data/test/{data → snapshots}/block_comment/expected-output.txt +0 -0
- data/test/{data → snapshots}/block_comment/source.lt3 +0 -0
- data/test/{data → snapshots}/comments_ignored_1/expected-error.txt +0 -0
- data/test/{data → snapshots}/comments_ignored_1/expected-output.txt +0 -0
- data/test/{data → snapshots}/comments_ignored_1/source.lt3 +0 -0
- data/test/{data → snapshots}/copy_is_raw/expected-error.txt +0 -0
- data/test/{data → snapshots}/copy_is_raw/expected-output.txt +0 -0
- data/test/{data → snapshots}/copy_is_raw/rawtext.inc +0 -0
- data/test/{data → snapshots}/copy_is_raw/source.lt3 +0 -0
- data/test/{data → snapshots}/crap +0 -0
- data/test/{data → snapshots}/def_method/expected-error.txt +0 -0
- data/test/{data → snapshots}/def_method/expected-output.txt +0 -0
- data/test/{data → snapshots}/def_method/source.lt3 +0 -0
- data/test/{data/error_inc_line_num/expected-err-line1match.txt → snapshots/error_inc_line_num/actual-error.txt} +0 -0
- data/test/snapshots/error_inc_line_num/actual-output.txt +13 -0
- data/test/{data/error_line_num → snapshots/error_inc_line_num}/expected-err-line1match.txt +0 -0
- data/test/{data → snapshots}/error_inc_line_num/expected-output.txt +6 -0
- data/test/{data → snapshots}/error_inc_line_num/file2.lt3 +0 -0
- data/test/snapshots/error_inc_line_num/out-sdiff.txt +14 -0
- data/test/{data → snapshots}/error_inc_line_num/source.lt3 +0 -0
- data/test/snapshots/error_invalid_name/actual-error.txt +10 -0
- data/test/{data/error_no_such_mixin/expected-output.txt → snapshots/error_invalid_name/actual-output.txt} +0 -0
- data/test/{data → snapshots}/error_invalid_name/expected-err-line1match.txt +0 -0
- data/test/{data → snapshots}/error_invalid_name/expected-output.txt +0 -0
- data/test/snapshots/error_invalid_name/out-sdiff.txt +6 -0
- data/test/{data → snapshots}/error_invalid_name/source.lt3 +0 -0
- data/test/snapshots/error_line_num/actual-error.txt +1 -0
- data/test/snapshots/error_line_num/actual-output.txt +5 -0
- data/test/snapshots/error_line_num/expected-err-line1match.txt +1 -0
- data/test/{data → snapshots}/error_line_num/expected-output.txt +0 -0
- data/test/snapshots/error_line_num/out-sdiff.txt +6 -0
- data/test/{data → snapshots}/error_line_num/source.lt3 +0 -0
- data/test/snapshots/error_mismatched_end/actual-error.txt +1 -0
- data/test/snapshots/error_mismatched_end/actual-output.txt +8 -0
- data/test/{data → snapshots}/error_mismatched_end/expected-err-line1match.txt +0 -0
- data/test/{data → snapshots}/error_mismatched_end/expected-output.txt +2 -0
- data/test/snapshots/error_mismatched_end/out-sdiff.txt +9 -0
- data/test/{data → snapshots}/error_mismatched_end/source.lt3 +0 -0
- data/test/{data/error_missing_end/expected-err-line1match.txt → snapshots/error_missing_end/actual-error.txt} +0 -0
- data/test/snapshots/error_missing_end/actual-output.txt +5 -0
- data/test/snapshots/error_missing_end/expected-err-line1match.txt +1 -0
- data/test/{data → snapshots}/error_missing_end/expected-output.txt +1 -0
- data/test/snapshots/error_missing_end/out-sdiff.txt +6 -0
- data/test/{data → snapshots}/error_missing_end/source.lt3 +0 -0
- data/test/{data/error_name_not_permitted/expected-output.txt → snapshots/error_name_not_permitted/OLD-exp-out} +0 -0
- data/test/{data/example_alpha/expected-error.txt → snapshots/error_name_not_permitted/expected-output.txt} +0 -0
- data/test/snapshots/error_name_not_permitted/match-error.txt +1 -0
- data/test/{data → snapshots}/error_name_not_permitted/source.lt3 +0 -0
- data/test/snapshots/error_no_such_copy/actual-error.txt +10 -0
- data/test/{data/example_alpha2/expected-error.txt → snapshots/error_no_such_copy/actual-output.txt} +0 -0
- data/test/snapshots/error_no_such_copy/expected-err-line1match.txt +1 -0
- data/test/{data → snapshots}/error_no_such_copy/expected-output.txt +0 -1
- data/test/snapshots/error_no_such_copy/out-sdiff.txt +5 -0
- data/test/{data → snapshots}/error_no_such_copy/source.lt3 +1 -0
- data/test/snapshots/error_no_such_inc/actual-error.txt +10 -0
- data/test/{data/functions/expected-error.txt → snapshots/error_no_such_inc/actual-output.txt} +0 -0
- data/test/snapshots/error_no_such_inc/expected-err-line1match.txt +1 -0
- data/test/{data → snapshots}/error_no_such_inc/expected-output.txt +0 -0
- data/test/snapshots/error_no_such_inc/out-sdiff.txt +6 -0
- data/test/{data → snapshots}/error_no_such_inc/source.lt3 +0 -0
- data/test/snapshots/error_no_such_mixin/actual-error.txt +1 -0
- data/test/snapshots/error_no_such_mixin/actual-output.txt +11 -0
- data/test/{data → snapshots}/error_no_such_mixin/expected-err-line1match.txt +0 -0
- data/test/snapshots/error_no_such_mixin/expected-output.txt +5 -0
- data/test/snapshots/error_no_such_mixin/out-sdiff.txt +12 -0
- data/test/{data → snapshots}/error_no_such_mixin/source.lt3 +0 -0
- data/test/{data/hello_world → snapshots/example_alpha}/expected-error.txt +0 -0
- data/test/{data → snapshots}/example_alpha/expected-output.txt +0 -0
- data/test/{data → snapshots}/example_alpha/source.lt3 +0 -0
- data/test/{data/more_complex_vars → snapshots/example_alpha2}/expected-error.txt +0 -0
- data/test/{data → snapshots}/example_alpha2/expected-output.txt +0 -0
- data/test/{data → snapshots}/example_alpha2/source.lt3 +0 -0
- data/test/{data → snapshots}/fixit +0 -0
- data/test/{data/raw_lines → snapshots/functions}/expected-error.txt +0 -0
- data/test/{data → snapshots}/functions/expected-output.txt +0 -0
- data/test/{data → snapshots}/functions/source.lt3 +0 -0
- data/test/{data/raw_text_block → snapshots/hello_world}/expected-error.txt +0 -0
- data/test/{data → snapshots}/hello_world/expected-output.txt +0 -0
- data/test/{data → snapshots}/hello_world/source.lt3 +0 -0
- data/test/{data → snapshots}/lines.txt +4 -0
- data/test/{data/simple_copy → snapshots/more_complex_vars}/expected-error.txt +0 -0
- data/test/{data → snapshots}/more_complex_vars/expected-output.txt +0 -0
- data/test/{data → snapshots}/more_complex_vars/source.lt3 +0 -0
- data/test/{data/simple_include/expected-error.txt → snapshots/predef_vars/actual-error.txt} +0 -0
- data/test/snapshots/predef_vars/actual-output.txt +6 -0
- data/test/{data/simple_mixin → snapshots/predef_vars}/expected-error.txt +0 -0
- data/test/snapshots/predef_vars/expected-output.txt +6 -0
- data/test/snapshots/predef_vars/out-sdiff.txt +7 -0
- data/test/snapshots/predef_vars/source.lt3 +6 -0
- data/test/{data/simple_vars → snapshots/raw_lines}/expected-error.txt +0 -0
- data/test/{data → snapshots}/raw_lines/expected-output.txt +0 -0
- data/test/{data → snapshots}/raw_lines/source.lt3 +0 -0
- data/test/{data/single_raw_line → snapshots/raw_text_block}/expected-error.txt +0 -0
- data/test/{data → snapshots}/raw_text_block/expected-output.txt +0 -0
- data/test/{data → snapshots}/raw_text_block/rawtext.inc +0 -0
- data/test/{data → snapshots}/raw_text_block/source.lt3 +0 -0
- data/test/{data/table_with_heredocs → snapshots/simple_copy}/expected-error.txt +0 -0
- data/test/{data → snapshots}/simple_copy/expected-output.txt +0 -0
- data/test/{data → snapshots}/simple_copy/simplefile.inc +0 -0
- data/test/{data → snapshots}/simple_copy/source.lt3 +0 -0
- data/test/{data/subset.txt → snapshots/simple_include/expected-error.txt} +0 -0
- data/test/{data → snapshots}/simple_include/expected-output.txt +0 -0
- data/test/{data → snapshots}/simple_include/simplefile.inc +0 -0
- data/test/{data → snapshots}/simple_include/source.lt3 +0 -0
- data/test/snapshots/simple_mixin/actual-error.txt +2 -0
- data/test/snapshots/simple_mixin/actual-output.txt +4 -0
- data/test/snapshots/simple_mixin/expected-error.txt +0 -0
- data/test/{data → snapshots}/simple_mixin/expected-output.txt +0 -0
- data/test/snapshots/simple_mixin/out-sdiff.txt +6 -0
- data/test/{data → snapshots}/simple_mixin/simple_mixin.rb +0 -0
- data/test/{data → snapshots}/simple_mixin/source.lt3 +0 -0
- data/test/snapshots/simple_vars/expected-error.txt +0 -0
- data/test/{data → snapshots}/simple_vars/expected-output.txt +0 -0
- data/test/{data → snapshots}/simple_vars/source.lt3 +0 -0
- data/test/snapshots/single_raw_line/expected-error.txt +0 -0
- data/test/{data → snapshots}/single_raw_line/expected-output.txt +0 -0
- data/test/{data → snapshots}/single_raw_line/source.lt3 +0 -0
- data/test/snapshots/subset.txt +0 -0
- data/test/snapshots/table_with_heredocs/expected-error.txt +0 -0
- data/test/{data → snapshots}/table_with_heredocs/expected-output.txt +0 -0
- data/test/{data → snapshots}/table_with_heredocs/source.lt3 +0 -0
- data/test/snapshots.rb +219 -0
- data/test/testlines.rb +17 -7
- data/test/unit/all.rb +3 -0
- data/test/unit/html.rb +38 -0
- data/test/unit/parse_misc.rb +60 -0
- data/test/unit/parse_set.rb +157 -0
- data/test/unit/parser/all.rb +3 -0
- data/test/unit/parser/general.rb +59 -0
- data/test/unit/parser/importable.rb +19 -0
- data/test/unit/parser/mixin.rb +19 -0
- data/test/unit/parser/set.rb +157 -0
- data/test/unit/parser/string.rb +130 -0
- data/test/unit/parser.rb +4 -0
- data/test/unit/standard.rb +23 -0
- data/test/unit/stringparser.rb +140 -0
- metadata +152 -95
- data/test/data/error_name_not_permitted/expected-error.txt +0 -1
- data/test/data/error_no_such_copy/expected-err-line1match.txt +0 -1
- data/test/data/error_no_such_inc/expected-err-line1match.txt +0 -1
- data/test/extratests.txt +0 -20
- data/test/test.rb +0 -140
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8f9a5d4be00258f23687ca280b306794cb67f2e7c89ba1a453c60dfd59f4268d
|
|
4
|
+
data.tar.gz: 423d1901855f09e06f5448008e12095713110d1d4dc8ba4f31ddf871319d2bb3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dfd42d9206980d3819e45fc174baf74378c01d13e61c8a8ce58f00bc3d3b7889b1bace1b74076c5491657978e704b55e6f82543e57ffdaa128993f6ec584c5e9
|
|
7
|
+
data.tar.gz: 570a8c6f92f4baaadad6c946871910e7ae2107741bef4212e16e7a49e90e1f929a8149c9f99553319a811eb42a6ce37fff0e15b8985235b91858f800d3ca77be
|
data/bin/livetext
CHANGED
data/lib/errors.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
# More later?
|
|
3
|
+
|
|
4
|
+
def make_exception(sym, str, target_class = Object)
|
|
5
|
+
return if target_class.constants.include?(sym)
|
|
6
|
+
target_class.const_set(sym, StandardError.dup)
|
|
7
|
+
define_method(sym) do |*args|
|
|
8
|
+
msg = str.dup
|
|
9
|
+
args.each.with_index {|arg, i| msg.sub!("%#{i+1}", arg) }
|
|
10
|
+
target_class.class_eval(sym.to_s).new(msg)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
data/lib/formatline.rb
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# Class FormatLine handles the parsing of comments, dot commands, and
|
|
2
|
+
# simple formatting characters.
|
|
3
|
+
|
|
1
4
|
class FormatLine
|
|
2
5
|
SimpleFormats = {}
|
|
3
6
|
SimpleFormats[:b] = %w[<b> </b>]
|
|
@@ -395,11 +398,6 @@ class FormatLine
|
|
|
395
398
|
|
|
396
399
|
#####
|
|
397
400
|
|
|
398
|
-
def showme(tag)
|
|
399
|
-
char = @line[@cc]
|
|
400
|
-
puts "--- #{tag}: ch=#{@ch.inspect} next=#{@next.inspect} (cc=#@cc:#{char.inspect}) out=#{@out.inspect}"
|
|
401
|
-
end
|
|
402
|
-
|
|
403
401
|
def embedded?
|
|
404
402
|
! (['"', "'", " ", nil].include? prev)
|
|
405
403
|
end
|
data/lib/functions.rb
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
require 'standard' # FIXME
|
|
2
1
|
|
|
3
|
-
|
|
2
|
+
require_relative 'standard' # FIXME?
|
|
3
|
+
|
|
4
|
+
# Class Functions is where '$$func' functions are stored dynamically...
|
|
5
|
+
# user-def AND pre-def??
|
|
6
|
+
|
|
7
|
+
class Livetext::Functions
|
|
4
8
|
Formats = ::Livetext::Standard::SimpleFormats
|
|
5
9
|
|
|
6
10
|
@param = nil
|
data/lib/helpers.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
module Helpers
|
|
3
|
+
|
|
4
|
+
def check_disallowed(name)
|
|
5
|
+
# raise "Illegal name '#{name}'" if _disallowed?(name)
|
|
6
|
+
# FIXME use custom exception
|
|
7
|
+
raise DisallowedName, name if _disallowed?(name)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def check_file_exists(file)
|
|
11
|
+
raise FileNotFound(file) unless File.exist?(file)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def set_variables(pairs)
|
|
15
|
+
pairs.each do |pair|
|
|
16
|
+
var, value = *pair
|
|
17
|
+
@parent._setvar(var, value)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
data/lib/html.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module HTMLHelper
|
|
2
|
+
|
|
3
|
+
def wrapped(str, *tags) # helper
|
|
4
|
+
open, close = open_close_tags(*tags)
|
|
5
|
+
open + str + close
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def wrapped!(str, tag, **extras) # helper
|
|
9
|
+
open, close = open_close_tags(tag)
|
|
10
|
+
extras.each_pair do |name, value|
|
|
11
|
+
open.sub!(">", " #{name}='#{value}'>")
|
|
12
|
+
end
|
|
13
|
+
open + str + close
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def wrap(*tags) # helper
|
|
17
|
+
open, close = open_close_tags(*tags)
|
|
18
|
+
_out open
|
|
19
|
+
yield
|
|
20
|
+
_out close
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def open_close_tags(*tags)
|
|
24
|
+
open, close = "", ""
|
|
25
|
+
tags.each do |tag|
|
|
26
|
+
open << "<#{tag}>"
|
|
27
|
+
close.prepend("</#{tag}>")
|
|
28
|
+
end
|
|
29
|
+
[open, close]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
data/lib/livetext.rb
CHANGED
|
@@ -1,34 +1,48 @@
|
|
|
1
|
+
# Class Livetext skeleton (top level).
|
|
2
|
+
|
|
1
3
|
class Livetext
|
|
2
|
-
VERSION = "0.9.
|
|
4
|
+
VERSION = "0.9.13"
|
|
3
5
|
Path = File.expand_path(File.join(File.dirname(__FILE__)))
|
|
4
6
|
end
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
# $LOAD_PATH << Livetext::Path
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
require 'fileutils'
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
require_relative 'errors'
|
|
13
|
+
require_relative 'functions'
|
|
14
|
+
require_relative 'userapi'
|
|
15
|
+
require_relative 'standard'
|
|
16
|
+
require_relative 'formatline'
|
|
17
|
+
require_relative 'processor'
|
|
15
18
|
|
|
16
19
|
Plugins = File.expand_path(File.join(File.dirname(__FILE__), "../plugin"))
|
|
17
20
|
|
|
18
21
|
TTY = ::File.open("/dev/tty", "w")
|
|
19
22
|
|
|
23
|
+
# Class Livetext reopened (top level).
|
|
24
|
+
|
|
20
25
|
class Livetext
|
|
26
|
+
|
|
21
27
|
Vars = {}
|
|
22
28
|
|
|
29
|
+
Space = " "
|
|
30
|
+
Sigil = "." # Can't change yet
|
|
31
|
+
|
|
32
|
+
def self.rx(str, space=nil)
|
|
33
|
+
Regexp.compile("^" + Regexp.escape(str) + "#{space}")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Comment = rx(Sigil, Livetext::Space)
|
|
37
|
+
Dotcmd = rx(Sigil)
|
|
38
|
+
Ddotcmd = /^ *\$\.[A-Za-z]/
|
|
39
|
+
|
|
23
40
|
attr_reader :main
|
|
24
41
|
attr_accessor :no_puts
|
|
25
42
|
attr_accessor :body, :indentation
|
|
26
43
|
|
|
27
|
-
# FIXME - phase out stupid 'parameters' method
|
|
28
|
-
|
|
29
44
|
class << self
|
|
30
|
-
attr_accessor :
|
|
31
|
-
attr_accessor :output # both bad solutions?
|
|
45
|
+
attr_accessor :output # bad solution?
|
|
32
46
|
end
|
|
33
47
|
|
|
34
48
|
def vars
|
|
@@ -54,17 +68,6 @@ class Livetext
|
|
|
54
68
|
self
|
|
55
69
|
end
|
|
56
70
|
|
|
57
|
-
Space = " "
|
|
58
|
-
Sigil = "." # Can't change yet
|
|
59
|
-
|
|
60
|
-
def self.rx(str, space=nil)
|
|
61
|
-
Regexp.compile("^" + Regexp.escape(str) + "#{space}")
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
Comment = rx(Sigil, Livetext::Space)
|
|
65
|
-
Dotcmd = rx(Sigil)
|
|
66
|
-
Ddotcmd = /^ *\$\.[A-Za-z]/
|
|
67
|
-
|
|
68
71
|
def initialize(output = ::STDOUT)
|
|
69
72
|
@source = nil
|
|
70
73
|
@_mixins = []
|
|
@@ -74,6 +77,10 @@ class Livetext
|
|
|
74
77
|
@main = Processor.new(self, output)
|
|
75
78
|
@indentation = [0]
|
|
76
79
|
@_vars = Livetext::Vars
|
|
80
|
+
|
|
81
|
+
# Other predefined variables (see also _setfile)
|
|
82
|
+
_setvar(:User, `whoami`.chomp)
|
|
83
|
+
_setvar(:Version, Livetext::VERSION)
|
|
77
84
|
end
|
|
78
85
|
|
|
79
86
|
def _parse_colon_args(args, hash) # really belongs in livetext
|
|
@@ -111,9 +118,14 @@ class Livetext
|
|
|
111
118
|
end
|
|
112
119
|
|
|
113
120
|
def _setfile(file)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
121
|
+
if file
|
|
122
|
+
_setvar(:File, file)
|
|
123
|
+
dir = File.dirname(File.expand_path(file))
|
|
124
|
+
_setvar(:FileDir, dir)
|
|
125
|
+
else
|
|
126
|
+
_setvar(:File, "[no file]")
|
|
127
|
+
_setvar(:FileDir, "[no dir]")
|
|
128
|
+
end
|
|
117
129
|
end
|
|
118
130
|
|
|
119
131
|
def _setfile!(file)
|
|
@@ -126,7 +138,6 @@ class Livetext
|
|
|
126
138
|
when Comment
|
|
127
139
|
handle_scomment(line)
|
|
128
140
|
when Dotcmd
|
|
129
|
-
STDERR.puts "line = #{line.inspect}"
|
|
130
141
|
handle_dotcmd(line)
|
|
131
142
|
when Ddotcmd
|
|
132
143
|
indent = line.index("$") + 1
|
|
@@ -170,7 +181,7 @@ class Livetext
|
|
|
170
181
|
self.body
|
|
171
182
|
end
|
|
172
183
|
|
|
173
|
-
def xform_file(file
|
|
184
|
+
def xform_file(file, vars: nil)
|
|
174
185
|
Livetext::Vars.replace(vars) unless vars.nil?
|
|
175
186
|
@_vars.replace(vars) unless vars.nil?
|
|
176
187
|
self.process_file(file)
|
|
@@ -181,7 +192,7 @@ class Livetext
|
|
|
181
192
|
|
|
182
193
|
def process_file(fname, btrace=false)
|
|
183
194
|
_setfile(fname)
|
|
184
|
-
text = File.readlines(fname)
|
|
195
|
+
text = File.readlines(fname) # FIXME currently causes failure
|
|
185
196
|
enum = text.each
|
|
186
197
|
@backtrace = btrace
|
|
187
198
|
@main.source(enum, fname, 0)
|
|
@@ -193,28 +204,23 @@ class Livetext
|
|
|
193
204
|
end
|
|
194
205
|
val = @main.finalize if @main.respond_to? :finalize
|
|
195
206
|
@body
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
207
|
+
rescue => err
|
|
208
|
+
STDERR.puts "[process_file] fname = #{fname.inspect}\n line = #{line.inspect}"
|
|
209
|
+
STDERR.puts "ERROR #{err} in process_file"
|
|
210
|
+
err.backtrace.each {|x| STDERR.puts " " + x }
|
|
211
|
+
# @body = ""
|
|
201
212
|
end
|
|
202
213
|
|
|
203
214
|
def handle_scomment(line)
|
|
204
215
|
end
|
|
205
216
|
|
|
206
|
-
def _check_name(name)
|
|
207
|
-
@main._error! "Name '#{name}' is not permitted" if @main._disallowed?(name)
|
|
208
|
-
@main._error! "Mismatched 'end'" if name == "end"
|
|
209
|
-
name = "_" + name if %w[def include].include?(name)
|
|
210
|
-
name
|
|
211
|
-
end
|
|
212
|
-
|
|
213
217
|
def _get_name(line)
|
|
214
218
|
name, data = line.split(" ", 2)
|
|
215
219
|
name = name[1..-1] # chop off sigil
|
|
220
|
+
name = "_" + name if %w[include def].include?(name)
|
|
216
221
|
@main.data = data
|
|
217
|
-
|
|
222
|
+
@main.check_disallowed(name)
|
|
223
|
+
name
|
|
218
224
|
end
|
|
219
225
|
|
|
220
226
|
def handle_dotcmd(line, indent = 0)
|
|
@@ -230,10 +236,10 @@ class Livetext
|
|
|
230
236
|
end
|
|
231
237
|
result
|
|
232
238
|
rescue => err
|
|
233
|
-
STDERR.puts "Error
|
|
234
|
-
STDERR.puts err.backtrace
|
|
235
|
-
@main._error!(err)
|
|
236
|
-
|
|
239
|
+
STDERR.puts "Error: #{err.inspect}"
|
|
240
|
+
# STDERR.puts err.backtrace
|
|
241
|
+
# @main._error!(err)
|
|
242
|
+
puts @body
|
|
237
243
|
@body = ""
|
|
238
244
|
return @body
|
|
239
245
|
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
|
|
2
|
+
require_relative '../livetext'
|
|
3
|
+
require_relative 'string'
|
|
4
|
+
|
|
5
|
+
make_exception(:MismatchedQuotes, "Error: mismatched quotes")
|
|
6
|
+
make_exception(:NilValue, "Error: nil value")
|
|
7
|
+
make_exception(:NullString, "Error: null string")
|
|
8
|
+
make_exception(:ExpectedString, "Error: expected a string")
|
|
9
|
+
|
|
10
|
+
class Livetext::ParseMisc < StringParser
|
|
11
|
+
|
|
12
|
+
def initialize(str)
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def strip_quotes
|
|
17
|
+
raise NullString if @line.empty?
|
|
18
|
+
start, stop = @line[0], @line[-1]
|
|
19
|
+
return @line unless %['"].include?(start)
|
|
20
|
+
raise MismatchedQuotes if start != stop
|
|
21
|
+
@line[1..-2]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.parse_vars(lines, prefix: nil)
|
|
25
|
+
lines.map! {|line| line.sub(/# .*/, "").strip } # strip comments
|
|
26
|
+
pairs = []
|
|
27
|
+
lines.each do |line|
|
|
28
|
+
next if line.strip.empty?
|
|
29
|
+
var, value = line.split(" ", 2)
|
|
30
|
+
val = FormatLine.var_func_parse(value)
|
|
31
|
+
var = prefix + "." + var if prefix
|
|
32
|
+
pairs << [var, value]
|
|
33
|
+
end
|
|
34
|
+
pairs
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
require '../livetext/importable'
|
|
3
|
+
|
|
4
|
+
make_exception(:BadVariableName, "Error: invalid variable name")
|
|
5
|
+
make_exception(:NoEqualSign, "Error: no equal sign found")
|
|
6
|
+
|
|
7
|
+
# FIXME probably belongs elsewhere?
|
|
8
|
+
|
|
9
|
+
class Livetext::ParseImport
|
|
10
|
+
def use_import(name)
|
|
11
|
+
require name
|
|
12
|
+
include name
|
|
13
|
+
init = "init_#{name}"
|
|
14
|
+
self.send(init) if self.respond_to? init
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
data/lib/parser/mixin.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require_relative '../livetext'
|
|
2
|
+
require_relative 'string'
|
|
3
|
+
|
|
4
|
+
make_exception(:BadVariableName, "Error: invalid variable name")
|
|
5
|
+
make_exception(:NoEqualSign, "Error: no equal sign found")
|
|
6
|
+
|
|
7
|
+
# FIXME probably belongs elsewhere?
|
|
8
|
+
|
|
9
|
+
class Livetext::ParseMixin # < StringParser
|
|
10
|
+
|
|
11
|
+
# def self.parse(str)
|
|
12
|
+
# self.new(str).parse
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# def initialize(line)
|
|
16
|
+
# super
|
|
17
|
+
# end
|
|
18
|
+
|
|
19
|
+
def cwd_root?
|
|
20
|
+
File.dirname(File.expand_path(".")) == "/"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def find_mixin(name)
|
|
24
|
+
file = "#{Plugins}/" + name.downcase + ".rb"
|
|
25
|
+
return file if File.exist?(file)
|
|
26
|
+
|
|
27
|
+
file = "./#{name}.rb"
|
|
28
|
+
return file if File.exist?(file)
|
|
29
|
+
|
|
30
|
+
raise "No such mixin '#{name}'" if cwd_root?
|
|
31
|
+
Dir.chdir("..") { find_mixin(name) }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def use_mixin(name, file)
|
|
35
|
+
modname = name.gsub("/","_").capitalize
|
|
36
|
+
meths = grab_file(file)
|
|
37
|
+
string = "module ::#{modname}; #{meths}\nend"
|
|
38
|
+
eval(string)
|
|
39
|
+
newmod = Object.const_get("::" + modname)
|
|
40
|
+
self.extend(newmod)
|
|
41
|
+
init = "init_#{name}"
|
|
42
|
+
self.send(init) if self.respond_to? init
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
data/lib/parser/set.rb
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
|
|
2
|
+
require_relative '../livetext'
|
|
3
|
+
require_relative 'string'
|
|
4
|
+
|
|
5
|
+
make_exception(:BadVariableName, "Error: invalid variable name")
|
|
6
|
+
make_exception(:NoEqualSign, "Error: no equal sign found")
|
|
7
|
+
|
|
8
|
+
class Livetext::ParseSet < StringParser
|
|
9
|
+
|
|
10
|
+
attr_reader :line, :eos, :i, :len
|
|
11
|
+
|
|
12
|
+
def self.parse(str)
|
|
13
|
+
self.new(str).parse
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(line)
|
|
17
|
+
super
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def parse
|
|
21
|
+
pairs = []
|
|
22
|
+
|
|
23
|
+
loop do
|
|
24
|
+
skip_spaces
|
|
25
|
+
char = self.peek
|
|
26
|
+
break if eos? # end of string
|
|
27
|
+
raise "Expected alpha to start var name" unless char =~ /[a-z]/i
|
|
28
|
+
pairs << assignment
|
|
29
|
+
skip_spaces
|
|
30
|
+
char = self.peek
|
|
31
|
+
break if eos? # end of string
|
|
32
|
+
case char
|
|
33
|
+
when nil # end of string
|
|
34
|
+
when ","
|
|
35
|
+
self.next # skip comma
|
|
36
|
+
else
|
|
37
|
+
raise "Expected comma or end of string (found #{char.inspect})"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
pairs
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def assignment # one single var=value
|
|
44
|
+
pair = nil
|
|
45
|
+
var = value = nil
|
|
46
|
+
return if eos?
|
|
47
|
+
var = get_var
|
|
48
|
+
skip_equal
|
|
49
|
+
value = get_value
|
|
50
|
+
value = FormatLine.var_func_parse(value)
|
|
51
|
+
pair = [var, value]
|
|
52
|
+
pair
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def get_var
|
|
56
|
+
name = ""
|
|
57
|
+
loop do
|
|
58
|
+
char = self.peek
|
|
59
|
+
break if eos? # end of string
|
|
60
|
+
case char
|
|
61
|
+
when /[a-zA-Z_\.0-9]/
|
|
62
|
+
name << self.next
|
|
63
|
+
next
|
|
64
|
+
when /[ =]/
|
|
65
|
+
return name
|
|
66
|
+
else
|
|
67
|
+
raise BadVariableName, char, name
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
raise NoEqualSign
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def skip_equal
|
|
74
|
+
found = false
|
|
75
|
+
skip_spaces
|
|
76
|
+
raise NoEqualSign unless self.peek == "="
|
|
77
|
+
found = true
|
|
78
|
+
self.next # skip =... spaces too
|
|
79
|
+
self.skip_spaces
|
|
80
|
+
peek = self.peek
|
|
81
|
+
return peek # just for testing
|
|
82
|
+
rescue StopIteration
|
|
83
|
+
raise NoEqualSign unless found
|
|
84
|
+
return nil
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def escaped
|
|
88
|
+
self.next # skip backslash
|
|
89
|
+
self.next # return following char
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
make_exception(:BadQuotedString, "Bad quoted string: %1")
|
|
93
|
+
|
|
94
|
+
def quoted_value
|
|
95
|
+
quote = self.next # opening quote...
|
|
96
|
+
value = ""
|
|
97
|
+
char = nil
|
|
98
|
+
loop do
|
|
99
|
+
char = self.peek
|
|
100
|
+
break if self.eos?
|
|
101
|
+
break if char == quote
|
|
102
|
+
char = escaped if char == "\\"
|
|
103
|
+
value << char
|
|
104
|
+
char = self.next
|
|
105
|
+
end
|
|
106
|
+
if char == quote
|
|
107
|
+
char = self.next
|
|
108
|
+
return value
|
|
109
|
+
end
|
|
110
|
+
raise BadQuotedString, quote + value
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def unquoted_value
|
|
114
|
+
# puts "#{__method__}: #{@line.inspect} i = #@i peek = #{self.peek.inspect}"
|
|
115
|
+
value = ""
|
|
116
|
+
loop do
|
|
117
|
+
char = self.peek
|
|
118
|
+
break if self.eos?
|
|
119
|
+
break if char == " " || char == ","
|
|
120
|
+
value << char
|
|
121
|
+
char = self.next
|
|
122
|
+
end
|
|
123
|
+
value
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def quote?(char)
|
|
127
|
+
char == ?" || char == ?'
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def get_value
|
|
131
|
+
char = self.peek
|
|
132
|
+
value = quote?(char) ? quoted_value : unquoted_value
|
|
133
|
+
value
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
class StringParser
|
|
2
|
+
|
|
3
|
+
attr_reader :line, :eos, :i, :len
|
|
4
|
+
|
|
5
|
+
def initialize(line)
|
|
6
|
+
raise NilValue if line.nil?
|
|
7
|
+
raise ExpectedString unless String === line
|
|
8
|
+
# raise NullString if line.empty?
|
|
9
|
+
@line = line
|
|
10
|
+
@len = @line.length
|
|
11
|
+
@eos = @len == 0 ? true : false
|
|
12
|
+
@i = 0
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def next
|
|
16
|
+
return nil if @eos
|
|
17
|
+
char = @line[@i]
|
|
18
|
+
@i += 1
|
|
19
|
+
@eos = true if @i > @len
|
|
20
|
+
char
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def last?
|
|
24
|
+
@i > @len - 1
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def eos?
|
|
28
|
+
@eos = true if last? # duh?
|
|
29
|
+
@eos
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def peek
|
|
33
|
+
return nil if @eos
|
|
34
|
+
@line[@i]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def skip_spaces
|
|
38
|
+
loop do
|
|
39
|
+
break if peek != " "
|
|
40
|
+
break if eos?
|
|
41
|
+
self.next
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
=begin
|
|
48
|
+
skip
|
|
49
|
+
next! skip! peek!(?)
|
|
50
|
+
expect_alpha
|
|
51
|
+
expect_number
|
|
52
|
+
skip_spaces
|
|
53
|
+
expect_eos
|
|
54
|
+
=end
|
|
55
|
+
|
data/lib/parser.rb
ADDED
data/lib/processor.rb
CHANGED
|
@@ -1,21 +1,27 @@
|
|
|
1
|
+
# Class Livetext is the actual top-level class.
|
|
2
|
+
|
|
1
3
|
class Livetext
|
|
2
4
|
|
|
5
|
+
# Class Processor does the actual work of processing input.
|
|
6
|
+
|
|
3
7
|
class Processor
|
|
8
|
+
|
|
9
|
+
GenericError = Class.new(StandardError)
|
|
10
|
+
|
|
4
11
|
include Livetext::Standard
|
|
5
12
|
include Livetext::UserAPI
|
|
6
13
|
|
|
7
|
-
Disallowed = [
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
:instance_exec, :__send__, :__id__, :__binding__]
|
|
14
|
+
Disallowed = %i[ ! != !~ <=> == === =~ __binding__ __id__ __send__ class
|
|
15
|
+
clone define_singleton_method display dup enum_for eql?
|
|
16
|
+
equal? extend freeze frozen? hash inspect instance_eval
|
|
17
|
+
instance_exec instance_of? instance_variable_defined?
|
|
18
|
+
instance_variable_get instance_variable_set instance_variables is_a?
|
|
19
|
+
kind_of? method methods nil? object_id
|
|
20
|
+
pretty_inspect private_methods protected_methods public_method
|
|
21
|
+
public_methods public_send remove_instance_variable
|
|
22
|
+
respond_to? send singleton_class singleton_method
|
|
23
|
+
singleton_methods taint tainted? tap to_enum
|
|
24
|
+
to_s trust untaint untrust untrusted?]
|
|
19
25
|
|
|
20
26
|
def initialize(parent, output = nil)
|
|
21
27
|
@parent = parent
|
|
@@ -32,13 +38,15 @@ class Livetext
|
|
|
32
38
|
@output = io
|
|
33
39
|
end
|
|
34
40
|
|
|
35
|
-
def _error!(err,
|
|
41
|
+
def _error!(err, raise_error=false, trace=false) # FIXME much bullshit happens here
|
|
36
42
|
where = @sources.last || @save_location
|
|
37
|
-
puts @parent.body
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
# puts @parent.body
|
|
44
|
+
# puts "[lib/processor] Error: #{err}"
|
|
45
|
+
# puts err.backtrace.join("\n") if err.respond_to?(:backtrace)
|
|
46
|
+
STDERR.puts "Error: #{err}" # (at #{where[1]} line #{where[2]})"
|
|
40
47
|
STDERR.puts err.backtrace if err.respond_to?(:backtrace) # && trace
|
|
41
|
-
|
|
48
|
+
# raise "lib/processor error!" # FIXME
|
|
49
|
+
raise GenericError.new("Error: #{err}") if raise_error
|
|
42
50
|
end
|
|
43
51
|
|
|
44
52
|
def _disallowed?(name)
|
|
@@ -54,7 +62,7 @@ class Livetext
|
|
|
54
62
|
rescue StopIteration
|
|
55
63
|
@sources.pop
|
|
56
64
|
nil
|
|
57
|
-
rescue
|
|
65
|
+
rescue => err
|
|
58
66
|
nil
|
|
59
67
|
end
|
|
60
68
|
|