riml 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Build Status](https://travis-ci.org/luke-gru/riml.png)](https://travis-ci.org/luke-gru/riml)
1
+ [![Build Status](https://secure.travis-ci.org/luke-gru/riml.png?branch=master)](https://travis-ci.org/luke-gru/riml)
2
2
 
3
3
  Riml, a relaxed version of Vimscript
4
4
  ====================================
@@ -10,7 +10,6 @@ programmers take for granted. Also, Riml takes some liberties and provides
10
10
  some syntactic sugar for lots of VimL constructs. To see how Riml constructs
11
11
  are compiled into VimL, just take a look in this README. The left side is Riml,
12
12
  and the right side is the equivalent VimL after compilation.
13
-
14
13
  Variables
15
14
  ---------
16
15
 
@@ -38,11 +37,11 @@ old local variables.
38
37
 
39
38
  ###Checking for existence
40
39
 
41
- unless s:callcount? if !exists("s:callcount")
42
- callcount = 0 let s:callcount = 0
43
- end endif
44
- callcount += 1 let s:callcount += 1
45
- puts "called #{callcount} times" echo "called " . s:callcount . " times"
40
+ unless s:callcount? if !exists("s:callcount")
41
+ callcount = 0 let s:callcount = 0
42
+ end endif
43
+ callcount += 1 let s:callcount += 1
44
+ echo "called #{callcount} times" echo "called " . s:callcount . " times"
46
45
 
47
46
  Comparisons
48
47
  -----------
@@ -56,93 +55,59 @@ Comparisons
56
55
  Heredocs
57
56
  --------
58
57
 
59
- msg = <<EOS let s:msg = "a vim heredoc!\n"
60
- a vim heredoc!
58
+ msg = <<EOS let s:msg = "a vim heredoc! " . s:cryForJoy() . "!\n"
59
+ A vim heredoc! #{cryForJoy()}!
61
60
  EOS
62
61
 
63
62
  Classes
64
63
  -------
65
64
 
66
- ###Riml example 1
67
-
68
- class MyClass
69
- def initialize(arg1, arg2, *args)
65
+ ###Basic Class
66
+
67
+ class MyClass function! g:MyClassConstructor(data, otherData, ...)
68
+ def initialize(data, otherData, *options) let myClassObj = {}
69
+ self.data = data let myClassObj.data = a:data
70
+ self.otherData = otherData let myClassObj.otherData = a:otherData
71
+ self.options = options let myClassObj.options = a:000
72
+ end let myClassObj.getData = function('g:MyClass_getData')
73
+ let myClassObj.getOtherData = function('g:MyClass_getOtherData')
74
+ defm getData return myClassObj
75
+ return self.data endfunction
70
76
  end
71
-
72
- defm getData
73
- return self.data
77
+ function! g:MyClass_getdata() dict
78
+ defm getOtherData return self.data
79
+ return self.otherData endfunction
74
80
  end
75
-
76
- defm getOtherData
77
- return self.otherData
81
+ end function! g:MyClass_getOtherData() dict
82
+ return self.otherData
83
+ endfunction
84
+
85
+ ###Class with Inheritance
86
+
87
+ class Translation function! g:TranslationConstructor(input)
88
+ def initialize(input) let translationObj = {}
89
+ self.input = input let translationObj.input = a:input
90
+ end return translationObj
91
+ end endfunction
92
+
93
+ class FrenchToEnglishTranslation < Translation function! g:FrenchToEnglishTranslationConstructor(input)
94
+ defm translate let frenchToEnglishTranslationObj = {}
95
+ if (self.input == "Bonjour!") let translationObj = g:TranslationConstructor(a:input)
96
+ echo "Hello!" call extend(frenchToEnglishTranslationObj, translationObj)
97
+ else let translationObj.translate = function('g:FrenchToEnglishTranslation_translate')
98
+ echo "Sorry, I don't know that word." return frenchToEnglishTranslationObj
99
+ end endfunction
78
100
  end
79
- end
80
-
81
- ###Viml example 1
82
-
101
+ end function! g:FrenchToEnglishTranslation_translate() dict
102
+ if (self.input ==# "Bonjour!")
103
+ translation = new echo "Hello!"
104
+ \ FrenchToEnglishTranslation("Bonjour!") else
105
+ translation.translate() echo "Sorry, I don't know that word."
106
+ endif
107
+ endfunction
83
108
 
84
- function! g:MyClassConstructor(arg1, arg2, ...)
85
- let myClassObj = {}
86
- function! myClassObj.getData() dict
87
- return self.data
88
- endfunction
89
- function! myClassObj.getOtherData() dict
90
- return self.otherData
91
- endfunction
92
- return myClassObj
93
- endfunction
94
-
95
- ###Riml example 2
96
-
97
- class Translation
98
- def initialize(input)
99
- self.input = input
100
- end
101
- end
102
-
103
- class FrenchToEnglishTranslation < Translation
104
- defm translate
105
- if (self.input == "Bonjour!")
106
- echo "Hello!"
107
- else
108
- echo "Sorry, I don't know that word."
109
- end
110
- end
111
- end
112
-
113
- translation = new FrenchToEnglishTranslation("Bonjour!")
114
- translation.translate()
115
-
116
- ###VimL example 2
117
-
118
- function! g:TranslationConstructor(input)
119
- let translationObj = {}
120
- let translationObj.input = a:input
121
- return translationObj
122
- endfunction
123
-
124
- function! g:FrenchToEnglishTranslationConstructor(input)
125
- let frenchToEnglishTranslationObj = {}
126
- let translationObj = g:TranslationConstructor(a:input)
127
- call extend(frenchToEnglishTranslationObj, translationObj)
128
- function! frenchToEnglishTranslationObj.translate() dict
129
- if (self.input ==# "Bonjour!")
130
- echo "Hello!"
131
- else
132
- echo "Sorry, I don't know that word."
133
- endif
134
- endfunction
135
- return frenchToEnglishTranslationObj
136
- endfunction
137
-
138
- let s:translation = g:FrenchToEnglishTranslationConstructor("Bonjour!")
139
- call s:translation.translate()
140
-
141
- Hacking
142
- -------
109
+ let s:translation = g:TranslationConstructor("Bonjour!")
110
+ call s:translation.translate()
143
111
 
144
- Make sure to generate the parser before running tests or developing on Riml.
145
- Also, make sure to regenerate the parser after modifiying the grammar file.
146
112
 
147
- 1. `bundle install`
148
- 2. Go to the lib directory and enter `racc -o parser.rb grammar.y`
113
+ Coming soon: for a full list of the language's rules complete with examples, check out the Wiki
@@ -79,8 +79,8 @@ module Riml
79
79
  def replace(node)
80
80
  binary_op = node.nodes[0].rhs
81
81
  old_set_var = node.nodes[0]
82
- assign_true = old_set_var.clone.tap {|assign_t| assign_t.rhs = TrueNode.new }
83
- assign_false = old_set_var.clone.tap {|assign_f| assign_f.rhs = FalseNode.new }
82
+ assign_true = old_set_var.dup.tap {|assign_t| assign_t.rhs = TrueNode.new}
83
+ assign_false = old_set_var.dup.tap {|assign_f| assign_f.rhs = FalseNode.new}
84
84
  node.nodes = [
85
85
  IfNode.new(binary_op, Nodes.new([
86
86
  assign_true, ElseNode.new(Nodes.new([
@@ -112,7 +112,7 @@ module Riml
112
112
  )
113
113
 
114
114
  SuperToObjectExtension.new(constructor, classes, node).rewrite_on_match
115
- MethodToNestedFunction.new(node, classes, constructor, dict_name).rewrite_on_match
115
+ ExtendObjectWithMethods.new(node, classes).rewrite_on_match
116
116
  SelfToDictName.new(dict_name).rewrite_on_match(constructor)
117
117
 
118
118
  constructor.expressions.push(
@@ -121,26 +121,39 @@ module Riml
121
121
  reestablish_parents(constructor)
122
122
  end
123
123
 
124
- class MethodToNestedFunction < AST_Rewriter
125
- attr_reader :constructor, :dict_name
126
- def initialize(class_node, classes, constructor, dict_name)
127
- super(class_node, classes)
128
- @dict_name, @constructor = dict_name, constructor
129
- end
130
-
124
+ class ExtendObjectWithMethods < AST_Rewriter
131
125
  def match?(node)
132
126
  DefMethodNode === node
133
127
  end
134
128
 
135
129
  def replace(node)
136
130
  def_node = node.to_def_node
137
- node.parent_node = ast.expressions
138
- def_node.parent_node = ast.expressions
131
+ class_expressions = ast.expressions
132
+ class_expressions.insert_after(class_expressions.last, def_node)
133
+ def_node.parent = class_expressions
134
+ # to remove it
135
+ node.parent = class_expressions
139
136
  node.remove
140
- def_node.name.insert(0, "#{dict_name}.")
141
- def_node.parent_node = constructor.expressions
142
- constructor.expressions << def_node
137
+ def_node.original_name = def_node.name.dup
138
+ def_node.name.insert(0, "#{ast.name}_")
143
139
  reestablish_parents(def_node)
140
+ extend_obj_with_methods(def_node)
141
+ end
142
+
143
+ def extend_obj_with_methods(def_node)
144
+ constructor = ast.constructor
145
+ extension =
146
+ AssignNode.new('=',
147
+ DictGetDotNode.new(
148
+ GetVariableNode.new(nil, ast.constructor_obj_name),
149
+ [def_node.original_name]
150
+ ),
151
+ CallNode.new(
152
+ nil, 'function', [StringNode.new("#{def_node.scope_modifier}#{def_node.name}", :s)]
153
+ )
154
+ )
155
+ constructor.expressions << extension
156
+ extension.parent = constructor.expressions
144
157
  end
145
158
  end
146
159
 
@@ -159,7 +159,7 @@ module Riml
159
159
 
160
160
  private
161
161
  def string_surround(string_node)
162
- case string_node.type
162
+ case string_node.type.to_sym
163
163
  when :d
164
164
  '"' << string_node.value << '"'
165
165
  when :s
@@ -283,16 +283,45 @@ module Riml
283
283
  def compile(node)
284
284
  set_modifier(node)
285
285
  node.compiled_output = node.scope_modifier
286
- node.variable.parts.each do |part|
287
- node.compiled_output <<
288
- if part.interpolated?
286
+ node.compiled_output << compile_parts(node.variable.parts)
287
+ end
288
+
289
+ def compile_parts(parts)
290
+ compiled = ""
291
+ parts.each do |part|
292
+ output = if CurlyBraceVariable === part
293
+ compile_parts(part)
294
+ elsif part.nested?
295
+ compile_nested_parts(part.value, part)
296
+ part.compiled_output
297
+ elsif part.interpolated?
289
298
  part.value.accept(visitor_for_node(part.value))
290
299
  "{#{part.value.compiled_output}}"
291
300
  else
292
301
  "#{part.value}"
293
302
  end
303
+ compiled << output
294
304
  end
295
- node.compiled_output
305
+ compiled
306
+ end
307
+
308
+ def compile_nested_parts(parts, root_part)
309
+ nested = 0
310
+ parts.each do |part|
311
+ if !part.respond_to?(:value)
312
+ part.accept(visitor_for_node(part, :propagate_up_tree => false))
313
+ root_part.compiled_output << "{#{part.compiled_output}"
314
+ nested += 1
315
+ next
316
+ end
317
+ if part.value.is_a?(Array)
318
+ compile_nested_parts(part.value, root_part)
319
+ next
320
+ end
321
+ part.value.accept(visitor_for_node(part.value, :propagate_up_tree => false))
322
+ root_part.compiled_output << "{#{part.value.compiled_output}}"
323
+ end
324
+ root_part.compiled_output << ('}' * nested)
296
325
  end
297
326
  end
298
327
 
@@ -76,7 +76,7 @@ rule
76
76
  | Assign { result = val[0] }
77
77
  | DictGet { result = val[0] }
78
78
  | ListOrDictGet { result = val[0] }
79
- | VariableRetrieval { result = val[0] }
79
+ | AllVariableRetrieval { result = val[0] }
80
80
  | Literal { result = val[0] }
81
81
  | Call { result = val[0] }
82
82
  | Ternary { result = val[0] }
@@ -164,7 +164,7 @@ rule
164
164
 
165
165
  DictGet:
166
166
  Dictionary DictGetWithDotLiteral { result = DictGetDotNode.new(val[0], val[1]) }
167
- | VariableRetrieval DictGetWithDot { result = DictGetDotNode.new(val[0], val[1]) }
167
+ | AllVariableRetrieval DictGetWithDot { result = DictGetDotNode.new(val[0], val[1]) }
168
168
  | ListOrDictGet DictGetWithDot { result = DictGetDotNode.new(val[0], val[1]) }
169
169
  ;
170
170
 
@@ -295,7 +295,7 @@ rule
295
295
  ;
296
296
 
297
297
  AssignLHS:
298
- VariableRetrieval { result = val[0] }
298
+ AllVariableRetrieval { result = val[0] }
299
299
  | DictGet { result = val[0] }
300
300
  | List { result = val[0] }
301
301
  | ListUnpack { result = val[0] }
@@ -306,6 +306,10 @@ rule
306
306
  VariableRetrieval:
307
307
  Scope IDENTIFIER { result = GetVariableNode.new(val[0], val[1]) }
308
308
  | SPECIAL_VAR_PREFIX IDENTIFIER { result = GetSpecialVariableNode.new(val[0], val[1]) }
309
+ ;
310
+
311
+ AllVariableRetrieval:
312
+ VariableRetrieval { result = val[0] }
309
313
  | Scope CurlyBraceName { result = GetCurlyBraceNameNode.new(val[0], val[1]) }
310
314
  ;
311
315
 
@@ -316,18 +320,25 @@ rule
316
320
  ;
317
321
 
318
322
  CurlyBraceName:
319
- IDENTIFIER '{' VariableRetrieval '}' { result = CurlyBraceVariable.new([ CurlyBracePart.new(val[0]), CurlyBracePart.new(val[2]) ]) }
320
- | '{' VariableRetrieval '}' IDENTIFIER { result = CurlyBraceVariable.new([ CurlyBracePart.new(val[1]), CurlyBracePart.new(val[3]) ]) }
323
+ CurlyBraceVarPart { result = CurlyBraceVariable.new([ val[0] ]) }
324
+ | IDENTIFIER CurlyBraceName { result = CurlyBraceVariable.new([ CurlyBracePart.new(val[0]), val[1] ]) }
321
325
  | CurlyBraceName IDENTIFIER { result = val[0] << CurlyBracePart.new(val[1]) }
326
+ | CurlyBraceName CurlyBraceVarPart { result = val[0] << val[1] }
327
+ ;
328
+
329
+ CurlyBraceVarPart:
330
+ '{' VariableRetrieval '}' { result = CurlyBracePart.new(val[1]) }
331
+ | '{' VariableRetrieval CurlyBraceVarPart '}' { result = CurlyBracePart.new([val[1], val[2]]) }
332
+ | '{' CurlyBraceVarPart VariableRetrieval '}' { result = CurlyBracePart.new([val[1], val[2]]) }
322
333
  ;
323
334
 
324
335
  # Method definition
325
336
  # [scope_modifier, name, parameters, keyword, expressions]
326
337
  Def:
327
- FunctionType Scope DefCallIdentifier Keyword Block END { result = Object.const_get(val[0]).new('!', val[1], val[2], [], val[3], val[4]) }
328
- | FunctionType Scope DefCallIdentifier '(' ParamList ')' Keyword Block END { result = Object.const_get(val[0]).new('!', val[1], val[2], val[4], val[6], val[7]) }
329
- | FunctionType Scope DefCallIdentifier '(' SPLAT ')' Keyword Block END { result = Object.const_get(val[0]).new('!', val[1], val[2], [val[4]], val[6], val[7]) }
330
- | FunctionType Scope DefCallIdentifier '(' ParamList ',' SPLAT ')' Keyword Block END { result = Object.const_get(val[0]).new('!', val[1], val[2], val[4] << val[6], val[8], val[9]) }
338
+ FunctionType Scope DefCallIdentifier DefKeyword Block END { result = Object.const_get(val[0]).new('!', val[1], val[2], [], val[3], val[4]) }
339
+ | FunctionType Scope DefCallIdentifier '(' ParamList ')' DefKeyword Block END { result = Object.const_get(val[0]).new('!', val[1], val[2], val[4], val[6], val[7]) }
340
+ | FunctionType Scope DefCallIdentifier '(' SPLAT ')' DefKeyword Block END { result = Object.const_get(val[0]).new('!', val[1], val[2], [val[4]], val[6], val[7]) }
341
+ | FunctionType Scope DefCallIdentifier '(' ParamList ',' SPLAT ')' DefKeyword Block END { result = Object.const_get(val[0]).new('!', val[1], val[2], val[4] << val[6], val[8], val[9]) }
331
342
  ;
332
343
 
333
344
  FunctionType:
@@ -343,7 +354,7 @@ rule
343
354
  ;
344
355
 
345
356
  # Example: 'range', 'dict' or 'abort' after function definition
346
- Keyword:
357
+ DefKeyword:
347
358
  IDENTIFIER { result = val[0] }
348
359
  | /* nothing */ { result = nil }
349
360
  ;
@@ -71,19 +71,19 @@ module Riml
71
71
  @i += splat_var.size
72
72
  @token_buf << [:SCOPE_MODIFIER, 'a:'] << [:IDENTIFIER, splat_var[2..-1]]
73
73
  # the 'n' scope modifier is added by riml
74
- elsif scope_modifier = chunk[/\A([bwtglsavn]:)[\w]/]
74
+ elsif scope_modifier = chunk[/\A([bwtglsavn]:)\w/, 1]
75
75
  @i += 2
76
- @token_buf << [:SCOPE_MODIFIER, $1]
76
+ @token_buf << [:SCOPE_MODIFIER, scope_modifier]
77
77
  elsif scope_modifier_literal = chunk[/\A([bwtglsavn]:)/]
78
- @i += 2
79
- @token_buf << [:SCOPE_MODIFIER_LITERAL, $1]
78
+ @i += scope_modifier_literal.size
79
+ @token_buf << [:SCOPE_MODIFIER_LITERAL, scope_modifier_literal]
80
80
  elsif special_var_prefix = chunk[/\A(&(\w:)?(?!&)|\$|@)/]
81
81
  @token_buf << [:SPECIAL_VAR_PREFIX, special_var_prefix.strip]
82
82
  @expecting_identifier = true
83
83
  @i += special_var_prefix.size
84
- elsif function_method = chunk[/\A(function)\(/]
85
- @token_buf << [:IDENTIFIER, $1]
86
- @i += $1.size
84
+ elsif function_method = chunk[/\A(function)\(/, 1]
85
+ @token_buf << [:IDENTIFIER, function_method]
86
+ @i += function_method.size
87
87
  elsif identifier = chunk[/\A[a-zA-Z_][\w#]*(\?|!)?/]
88
88
  # keyword identifiers
89
89
  if KEYWORDS.include?(identifier)
@@ -130,15 +130,15 @@ module Riml
130
130
  @i += splat.size
131
131
  # integer (octal)
132
132
  elsif octal = chunk[/\A0[0-7]+/]
133
- @token_buf << [:NUMBER, octal.to_s]
133
+ @token_buf << [:NUMBER, octal]
134
134
  @i += octal.size
135
135
  # integer (hex)
136
136
  elsif hex = chunk[/\A0[xX]\h+/]
137
- @token_buf << [:NUMBER, hex.to_s]
137
+ @token_buf << [:NUMBER, hex]
138
138
  @i += hex.size
139
139
  # integer or float (decimal)
140
140
  elsif decimal = chunk[/\A[0-9]+(\.[0-9]+)?/]
141
- @token_buf << [:NUMBER, decimal.to_s]
141
+ @token_buf << [:NUMBER, decimal]
142
142
  @i += decimal.size
143
143
  elsif interpolation = chunk[INTERPOLATION_REGEX]
144
144
  # "hey there, #{name}" = "hey there, " . name
@@ -221,7 +221,7 @@ module Riml
221
221
  when :if, :unless
222
222
  if one_line_conditional?(chunk)
223
223
  @one_line_conditional_end_pending = true
224
- elsif !statement_modifier?(chunk)
224
+ elsif !statement_modifier?
225
225
  @current_indent += 2
226
226
  @indent_pending = true
227
227
  end
@@ -274,7 +274,7 @@ module Riml
274
274
  Lexer.new(code).tokenize
275
275
  end
276
276
 
277
- def statement_modifier?(chunk)
277
+ def statement_modifier?
278
278
  old_i = @i
279
279
  # backtrack until the beginning of the line
280
280
  @i -= 1 while @code[@i-1] =~ /[^\n\r]/ && !@code[@i-1].empty?
@@ -391,27 +391,49 @@ class GetSpecialVariableNode < Struct.new(:prefix, :name)
391
391
  include FullyNameable
392
392
  end
393
393
 
394
- class CurlyBracePart < Struct.new(:value)
395
- def interpolated?
396
- GetVariableNode === value || GetSpecialVariableNode === value
397
- end
394
+ class GetCurlyBraceNameNode < Struct.new(:scope_modifier, :variable)
395
+ include Visitable
396
+ include Walkable
398
397
 
399
- def regular?
400
- not interpolated?
398
+ def children
399
+ [variable]
401
400
  end
402
401
  end
402
+
403
403
  class CurlyBraceVariable < Struct.new(:parts)
404
+ include Visitable
405
+ include Walkable
406
+
404
407
  def <<(part)
405
408
  parts << part
406
409
  self
407
410
  end
411
+
412
+ def children
413
+ parts
414
+ end
408
415
  end
409
- class GetCurlyBraceNameNode < Struct.new(:scope_modifier, :variable)
416
+
417
+ class CurlyBracePart < Struct.new(:value)
410
418
  include Visitable
411
419
  include Walkable
412
420
 
421
+ def interpolated?
422
+ GetVariableNode === value || GetSpecialVariableNode === value || nested?
423
+ end
424
+
425
+ def nested?
426
+ value.is_a?(Array) && value.detect {|part| part.is_a?(CurlyBracePart)}
427
+ end
428
+
429
+ def regular?
430
+ not interpolated?
431
+ end
432
+
413
433
  def children
414
- [variable]
434
+ return [] if regular?
435
+ return value if nested?
436
+ [value]
415
437
  end
416
438
  end
417
439
 
@@ -436,6 +458,8 @@ class DefNode < Struct.new(:bang, :scope_modifier, :name, :parameters, :keyword,
436
458
  include FullyNameable
437
459
  include Walkable
438
460
 
461
+ attr_accessor :original_name
462
+
439
463
  def initialize(*args)
440
464
  super
441
465
  # max number of arguments in viml
@@ -529,7 +553,7 @@ end
529
553
 
530
554
  class DefMethodNode < DefNode
531
555
  def to_def_node
532
- def_node = DefNode.new(bang, scope_modifier, name, parameters, keyword, expressions)
556
+ def_node = DefNode.new(bang, 'g:', name, parameters, 'dict', expressions)
533
557
  def_node.parent = parent
534
558
  def_node
535
559
  end
@@ -652,22 +676,6 @@ class ForNode < Struct.new(:variable, :in_expression, :expressions)
652
676
  end
653
677
  end
654
678
 
655
- # lines: [5, 6, 8, 9]
656
- # This means the continuation has 4 lines (line.size is 4) and each line
657
- # preserves the amt of whitespace specified as the value in the array.
658
- # Ex: 1st line preserves 5 spaces, 2nd line preserves 6 spaces, etc...
659
- class LineContinuation < Struct.new(:lines)
660
- include Visitable
661
-
662
- def size
663
- lines.size
664
- end
665
-
666
- def [](idx)
667
- lines[idx]
668
- end
669
- end
670
-
671
679
  class DictGetNode < Struct.new(:dict, :keys)
672
680
  include Visitable
673
681
  include Walkable