yay 0.0.1

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/lib/yay/errors.rb ADDED
@@ -0,0 +1,109 @@
1
+
2
+ class Yay
3
+ class Error < StandardError
4
+ attr :position
5
+
6
+ def printable_message
7
+ raise "Unimplemented printable error"
8
+ end
9
+
10
+ def printable_position
11
+ array = @position
12
+ return "" unless @position
13
+ length = array.length
14
+ return " at word #{array[0]}" if length == 1
15
+ return " on line #{array[1]}, word #{array[0]}" if length == 2
16
+ return " in file #{array[2]}, line #{array[1]}, word #{array[0]}" if length == 3
17
+ raise "junk position given to exception"
18
+ end
19
+ end
20
+
21
+ class AlreadyAssignedError < Error
22
+ attr :variable
23
+
24
+ def initialize variable
25
+ @variable = variable
26
+ end
27
+
28
+ def printable_message
29
+ return "The variable #{variable} has already been assigned a value#{printable_position}"
30
+ end
31
+ end
32
+
33
+ class CircularReferenceError < Error
34
+ attr :current
35
+ attr :path
36
+
37
+ def initialize current, path
38
+ @current = current
39
+ @path = path
40
+ end
41
+
42
+ def printable_message
43
+ return "There is a circular reference between variables: #{path.join(' => ')} => #{current}#{printable_position}"
44
+ end
45
+ end
46
+
47
+ class UnresolvedSubstitutionError < Error
48
+ attr :variable
49
+
50
+ def initialize variable
51
+ @variable = variable
52
+ end
53
+
54
+ def printable_message
55
+ return "The variable #{variable} is being used but hasn't been set #{printable_position}"
56
+ end
57
+ end
58
+
59
+ class CouldntFindFileError < Error
60
+ attr :filename
61
+ attr :tried
62
+
63
+ def initialize filename, tried
64
+ @filename = filename
65
+ @tried = tried
66
+ end
67
+
68
+ def printable_message
69
+ return "Failed to load file \"#{filename}\"#{printable_position}\nPlaced looked: #{tried.join(', ')}"
70
+ end
71
+ end
72
+
73
+ class TooManyColoursError < Error
74
+ attr :fg
75
+ attr :bg
76
+ attr :colour
77
+
78
+ def initialize fg, bg, colour, position
79
+ @fg = fg
80
+ @bg = bg
81
+ @colour = colour
82
+ @position = position
83
+ end
84
+
85
+ def printable_message
86
+ return "There were too many colours in your expression#{printable_position}.\nYou can't use #{colour} as you've already chosen a foreground and background colour"
87
+ end
88
+ end
89
+
90
+ class UnexpectedTokenError < Error
91
+ attr :type
92
+ attr :value
93
+
94
+ def initialize type, value, position
95
+ @type = type
96
+ @value = value
97
+ @position = position
98
+ end
99
+
100
+ def extra_message
101
+ return "Since #{value} has a special meaning, try enclosing it in quotes or a regex when searching for it" if type == "colour"
102
+ return ""
103
+ end
104
+
105
+ def printable_message
106
+ return "Unexpected #{type} \"#{value}\"#{printable_position}\n#{extra_message}"
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,12 @@
1
+
2
+ class Yay
3
+ class Installer
4
+ def initialize(url)
5
+ @url = url
6
+ end
7
+
8
+ def install
9
+ raise "installing files is not yet implemented! :-("
10
+ end
11
+ end
12
+ end
data/lib/yay/lexer.rb ADDED
@@ -0,0 +1,60 @@
1
+ require 'strscan'
2
+ require 'yay/lexer_regex'
3
+
4
+ class Yay
5
+ class Lexer
6
+
7
+ def initialize(string="")
8
+ @position = 0
9
+ @line = 1
10
+
11
+ # default to an empty string scanner. this provides us an endless number
12
+ # of eofs
13
+ use_string(string)
14
+ end
15
+
16
+ # take a string and begin scanning it
17
+ def use_string(string)
18
+ @scanner = StringScanner.new string
19
+ end
20
+
21
+ def position
22
+ @position
23
+ end
24
+
25
+ def line
26
+ @line
27
+ end
28
+
29
+ # get the next token in the file
30
+ def next_token
31
+ return nil if @scanner.empty?
32
+
33
+ unless @scanner.empty?
34
+ get_patterns.each { |token|
35
+ type = token[0]
36
+ value = @scanner.scan(token[1])
37
+ next unless value
38
+ return next_token if type == :whitespace
39
+ return next_token if type == :comment
40
+ @position += 1
41
+ return normalize_token type, value
42
+ }
43
+ end
44
+ return [:junk, @scanner.scan_until(/$/)]
45
+ end
46
+
47
+ # perform transformations on the values
48
+ def normalize_token type, value
49
+ case type
50
+ when nil
51
+ when :double_quoted
52
+ value = value[1, value.length - 2]
53
+ while value.sub!("\\\"", "\"") != nil
54
+ end
55
+ type = :literal
56
+ end
57
+ return [type, value]
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,38 @@
1
+ require 'yay/colour_wheel'
2
+
3
+ class Yay
4
+ class Lexer
5
+
6
+ # The expressions to match to find tokens
7
+ # Ensure the labels match up to tokens in grammar.y
8
+ BASE_PATTERNS = [
9
+ [:whitespace , /\s+/],
10
+ [:comment , /#.*$/],
11
+
12
+ # strings
13
+ [:double_quoted , /"[^"\\]*(?:\\.[^"\\]*)*"/],
14
+ [:single_quoted , /'[^'\\]*(?:\\.[^'\\]*)*'/],
15
+ [:regex , /\/[^\/\\\r\n]*(?:x.[^\/x\r\n]*)*\/[a-z]*/],
16
+ [:variable , /@\w+/],
17
+
18
+ # keywords
19
+ [:line , /\bline[s]?\b/i],
20
+ [:install , /\binstall\b/i],
21
+ [:installed , /\binstalled\b/i],
22
+ [:include , /\b(include|use|load)\b/i],
23
+ [:and , /(\b(and|but)\b)|,/i],
24
+ [:verb , /\b(is|are|a|an)\b/],
25
+
26
+ # everything else matched must be a plain old term
27
+ [:literal , /\b\S+\b/],
28
+ ]
29
+
30
+ def get_patterns
31
+ patterns = BASE_PATTERNS
32
+ # add the colour keywords. generate these from the colour wheel's constants
33
+ colours = Yay::ColourWheel::all_names.join('|')
34
+ patterns.unshift [:colour, Regexp.new("\\b(#{colours})\\b", Regexp::IGNORECASE)]
35
+ return patterns
36
+ end
37
+ end
38
+ end
data/lib/yay/loader.rb ADDED
@@ -0,0 +1,57 @@
1
+
2
+ class Yay
3
+ class Loader
4
+ def initialize filename
5
+ @filename = filename
6
+ end
7
+
8
+ # invoking a new parser and process a string of yay commands
9
+ # any variables inside the parser context will not affect our own
10
+ # this is particularly useful when loading files
11
+ def load_string string
12
+ # invoke a new parser and return the rules it finds
13
+ parser = Yay::Parser.new
14
+ return parser.parse string
15
+ end
16
+
17
+ #
18
+ def load_file full_path
19
+ file = File.open(full_path, "rb")
20
+ contents = file.read
21
+ return load_string(contents)
22
+ end
23
+
24
+ def resolve_targets filename
25
+ return [
26
+ "./#{filename}.yay",
27
+ "~/.yay/#{filename}.yay",
28
+ # "#{$GEM_HOME}/yay/#{filename}.yay"
29
+ ]
30
+ end
31
+
32
+ # stat for the file locally and globally
33
+ def resolve_file filename
34
+ paths = resolve_targets filename
35
+ paths.each { |file_name|
36
+ begin
37
+ stat = File.stat(file_name)
38
+ return file_name if stat
39
+ rescue Errno::ENOENT
40
+ end
41
+ }
42
+ return nil
43
+ end
44
+
45
+ # load a file
46
+ def load
47
+ resolved = resolve_file @filename
48
+ raise Yay::CouldntFindFileError.new @filename, resolve_targets(@filename) unless resolved
49
+ @rules = load_file resolved
50
+ return @rules
51
+ end
52
+
53
+ def get_rules
54
+ return @rules
55
+ end
56
+ end
57
+ end
data/lib/yay/parser.rb ADDED
@@ -0,0 +1,89 @@
1
+ require 'yay/parser_gen'
2
+ require 'yay/lexer'
3
+ require 'yay/colour_wheel'
4
+ require 'yay/rule_set'
5
+ require 'yay/loader'
6
+ require 'yay/installer'
7
+ require 'yay/errors'
8
+
9
+ class Yay
10
+ class Parser < Yay::ParserGen
11
+ def load_file filename
12
+ loader = Yay::Loader.new filename
13
+ loader.load
14
+ @ruleset.merge loader.get_rules
15
+ end
16
+
17
+ def install_file url
18
+ installer = Yay::Installer.new url
19
+ installer.install
20
+ end
21
+
22
+ def print_installed
23
+ # TODO
24
+ end
25
+
26
+ def handle_string string
27
+ string = Regexp::escape(string)
28
+ Regexp.new(string, Regexp::IGNORECASE)
29
+ end
30
+
31
+ def handle_regex string
32
+ string
33
+ end
34
+
35
+ # given an array of colour strings, create an array with the VT100 colour
36
+ # sequences inside
37
+ def handle_colours colours
38
+ fg = bg = nil
39
+ result = []
40
+ # iterate the colour list and try to find up to two colours (foreground,
41
+ # background) and unlimited miscellaneous colours (reset, invert, etc)
42
+ colours.each { |colour|
43
+ misc_val = ColourWheel::MISC[colour]
44
+ if !misc_val.nil?
45
+ result.push misc_val
46
+ elsif !fg
47
+ fg = ColourWheel::FG[colour]
48
+ result.push fg
49
+ elsif !bg
50
+ bg = ColourWheel::BG[colour]
51
+ result.push bg
52
+ else
53
+ raise Yay::TooManyColoursError.new fg, bg, colour, [@lexer.position, @lexer.line]
54
+ end
55
+ }
56
+ result
57
+ end
58
+
59
+ def get_rules
60
+ @ruleset.get_rules
61
+ end
62
+
63
+ # process commandline arguments as if they were from a yay file
64
+ def parse_array args
65
+ raise ArgumentError, "args" unless args.kind_of? Array
66
+ parse args.join(' ')
67
+ end
68
+
69
+ # parse a string
70
+ def parse(str)
71
+ @lexer = Yay::Lexer.new unless @lexer
72
+ @lexer.use_string(str)
73
+ @ruleset = Yay::RuleSet.new
74
+
75
+ do_parse
76
+ get_rules
77
+ end
78
+
79
+ # get the next token
80
+ def next_token
81
+ @lexer.next_token
82
+ end
83
+
84
+ def on_error error_token_id, error_value, value_stack
85
+ type = token_to_str error_token_id
86
+ raise Yay::UnexpectedTokenError.new type, error_value, [@lexer.position, @lexer.line]
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,319 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by racc 1.4.5
4
+ # from racc grammer file "scripts/../data/grammar.y".
5
+ #
6
+
7
+ require 'racc/parser'
8
+
9
+
10
+ class Yay
11
+
12
+ class ParserGen < Racc::Parser
13
+
14
+ ##### racc 1.4.5 generates ###
15
+
16
+ racc_reduce_table = [
17
+ 0, 0, :racc_error,
18
+ 1, 13, :_reduce_none,
19
+ 1, 13, :_reduce_2,
20
+ 2, 13, :_reduce_3,
21
+ 3, 13, :_reduce_4,
22
+ 0, 13, :_reduce_none,
23
+ 3, 14, :_reduce_none,
24
+ 1, 14, :_reduce_none,
25
+ 1, 15, :_reduce_none,
26
+ 1, 15, :_reduce_none,
27
+ 1, 15, :_reduce_none,
28
+ 1, 15, :_reduce_none,
29
+ 1, 15, :_reduce_none,
30
+ 4, 17, :_reduce_13,
31
+ 3, 18, :_reduce_14,
32
+ 4, 19, :_reduce_15,
33
+ 3, 20, :_reduce_16,
34
+ 2, 21, :_reduce_17,
35
+ 3, 22, :_reduce_18,
36
+ 1, 22, :_reduce_19,
37
+ 1, 26, :_reduce_20,
38
+ 1, 26, :_reduce_21,
39
+ 2, 24, :_reduce_22,
40
+ 1, 24, :_reduce_23,
41
+ 1, 16, :_reduce_24,
42
+ 0, 16, :_reduce_none,
43
+ 1, 25, :_reduce_26,
44
+ 0, 25, :_reduce_27,
45
+ 2, 23, :_reduce_28,
46
+ 0, 23, :_reduce_none ]
47
+
48
+ racc_reduce_n = 30
49
+
50
+ racc_shift_n = 41
51
+
52
+ racc_action_table = [
53
+ -7, -25, 33, 19, 16, 20, -25, 11, 22, 22,
54
+ 33, 25, 16, 8, 9, 11, 2, 4, 30, 8,
55
+ 9, 11, 36, 28, 31, 29, 29, 18, -2, 16,
56
+ 38, 29, 38 ]
57
+
58
+ racc_action_check = [
59
+ 7, 6, 21, 4, 16, 4, 6, 21, 6, 7,
60
+ 23, 9, 8, 23, 23, 23, 0, 0, 18, 0,
61
+ 0, 0, 24, 17, 20, 24, 17, 3, 2, 1,
62
+ 27, 29, 35 ]
63
+
64
+ racc_action_pointer = [
65
+ 14, 18, 28, 27, 1, nil, -1, 0, 1, 9,
66
+ nil, nil, nil, nil, nil, nil, -7, 18, 18, nil,
67
+ 22, 0, nil, 8, 17, nil, nil, 20, nil, 23,
68
+ nil, nil, nil, nil, nil, 22, nil, nil, nil, nil,
69
+ nil ]
70
+
71
+ racc_action_default = [
72
+ -5, -29, -20, -30, -30, -1, -19, -25, -29, -30,
73
+ -8, -21, -9, -10, -11, -12, -29, -30, -30, -3,
74
+ -30, -30, -24, -30, -30, -17, -28, -27, -14, -23,
75
+ 41, -4, -18, -20, -6, -27, -16, -13, -26, -22,
76
+ -15 ]
77
+
78
+ racc_goto_table = [
79
+ 5, 17, 27, 37, 21, 23, 32, 3, 24, 35,
80
+ nil, 40, nil, nil, 39, nil, 26, nil, nil, nil,
81
+ nil, nil, nil, 34 ]
82
+
83
+ racc_goto_check = [
84
+ 2, 11, 12, 13, 4, 4, 10, 1, 11, 12,
85
+ nil, 13, nil, nil, 12, nil, 11, nil, nil, nil,
86
+ nil, nil, nil, 2 ]
87
+
88
+ racc_goto_pointer = [
89
+ nil, 7, 0, nil, -2, nil, nil, nil, nil, nil,
90
+ -15, 0, -15, -24, nil ]
91
+
92
+ racc_goto_default = [
93
+ nil, nil, nil, 7, nil, 10, 12, 13, 14, 15,
94
+ 1, nil, nil, nil, 6 ]
95
+
96
+ racc_token_table = {
97
+ false => 0,
98
+ Object.new => 1,
99
+ :literal => 2,
100
+ :install => 3,
101
+ :local => 4,
102
+ :variable => 5,
103
+ :include => 6,
104
+ :regex => 7,
105
+ :colour => 8,
106
+ :and => 9,
107
+ :line => 10,
108
+ :verb => 11 }
109
+
110
+ racc_use_result_var = true
111
+
112
+ racc_nt_base = 12
113
+
114
+ Racc_arg = [
115
+ racc_action_table,
116
+ racc_action_check,
117
+ racc_action_default,
118
+ racc_action_pointer,
119
+ racc_goto_table,
120
+ racc_goto_check,
121
+ racc_goto_default,
122
+ racc_goto_pointer,
123
+ racc_nt_base,
124
+ racc_reduce_table,
125
+ racc_token_table,
126
+ racc_shift_n,
127
+ racc_reduce_n,
128
+ racc_use_result_var ]
129
+
130
+ Racc_token_to_s_table = [
131
+ '$end',
132
+ 'error',
133
+ 'literal',
134
+ 'install',
135
+ 'local',
136
+ 'variable',
137
+ 'include',
138
+ 'regex',
139
+ 'colour',
140
+ 'and',
141
+ 'line',
142
+ 'verb',
143
+ '$start',
144
+ 'body',
145
+ 'command_list',
146
+ 'command',
147
+ 'and_opt',
148
+ 'match',
149
+ 'assignment',
150
+ 'substitution',
151
+ 'equivalence',
152
+ 'include_file',
153
+ 'string_list',
154
+ 'verbs_opt',
155
+ 'colour_list',
156
+ 'line_opt',
157
+ 'string']
158
+
159
+ Racc_debug_parser = false
160
+
161
+ ##### racc system variables end #####
162
+
163
+ # reduce 0 omitted
164
+
165
+ # reduce 1 omitted
166
+
167
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 6
168
+ def _reduce_2( val, _values, result )
169
+ load_file val[0]
170
+ result
171
+ end
172
+ .,.,
173
+
174
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 7
175
+ def _reduce_3( val, _values, result )
176
+ install_file val[1], true
177
+ result
178
+ end
179
+ .,.,
180
+
181
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 8
182
+ def _reduce_4( val, _values, result )
183
+ install_file val[2], false
184
+ result
185
+ end
186
+ .,.,
187
+
188
+ # reduce 5 omitted
189
+
190
+ # reduce 6 omitted
191
+
192
+ # reduce 7 omitted
193
+
194
+ # reduce 8 omitted
195
+
196
+ # reduce 9 omitted
197
+
198
+ # reduce 10 omitted
199
+
200
+ # reduce 11 omitted
201
+
202
+ # reduce 12 omitted
203
+
204
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 20
205
+ def _reduce_13( val, _values, result )
206
+ @ruleset.add_match val[0], handle_colours(val[2]), val[3]
207
+ result
208
+ end
209
+ .,.,
210
+
211
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 22
212
+ def _reduce_14( val, _values, result )
213
+ @ruleset.add_assignment val[0], val[2]
214
+ result
215
+ end
216
+ .,.,
217
+
218
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 24
219
+ def _reduce_15( val, _values, result )
220
+ @ruleset.add_substitution val[0], handle_colours(val[2]), val[3]
221
+ result
222
+ end
223
+ .,.,
224
+
225
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 26
226
+ def _reduce_16( val, _values, result )
227
+ @ruleset.add_equivalence val[0], val[2]
228
+ result
229
+ end
230
+ .,.,
231
+
232
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 28
233
+ def _reduce_17( val, _values, result )
234
+ load_file val[0]
235
+ result
236
+ end
237
+ .,.,
238
+
239
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 30
240
+ def _reduce_18( val, _values, result )
241
+ val[2].unshift(val[0]); result = val[2]
242
+ result
243
+ end
244
+ .,.,
245
+
246
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 31
247
+ def _reduce_19( val, _values, result )
248
+ result = [val[0]]
249
+ result
250
+ end
251
+ .,.,
252
+
253
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 33
254
+ def _reduce_20( val, _values, result )
255
+ result = handle_string(val[0])
256
+ result
257
+ end
258
+ .,.,
259
+
260
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 34
261
+ def _reduce_21( val, _values, result )
262
+ result = handle_regex(val[0])
263
+ result
264
+ end
265
+ .,.,
266
+
267
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 36
268
+ def _reduce_22( val, _values, result )
269
+ val[1].unshift(val[0].to_sym); result = val[1]
270
+ result
271
+ end
272
+ .,.,
273
+
274
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 37
275
+ def _reduce_23( val, _values, result )
276
+ result = [val[0].to_sym]
277
+ result
278
+ end
279
+ .,.,
280
+
281
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 39
282
+ def _reduce_24( val, _values, result )
283
+ result = nil
284
+ result
285
+ end
286
+ .,.,
287
+
288
+ # reduce 25 omitted
289
+
290
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 42
291
+ def _reduce_26( val, _values, result )
292
+ result = true
293
+ result
294
+ end
295
+ .,.,
296
+
297
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 43
298
+ def _reduce_27( val, _values, result )
299
+ result = false
300
+ result
301
+ end
302
+ .,.,
303
+
304
+ module_eval <<'.,.,', 'scripts/../data/grammar.y', 45
305
+ def _reduce_28( val, _values, result )
306
+ result = nil
307
+ result
308
+ end
309
+ .,.,
310
+
311
+ # reduce 29 omitted
312
+
313
+ def _reduce_none( val, _values, result )
314
+ result
315
+ end
316
+
317
+ end # class ParserGen
318
+
319
+ end # class Yay