riml 0.2.1 → 0.2.2

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/README.md CHANGED
@@ -4,12 +4,13 @@ Riml, a relaxed version of Vimscript
4
4
  ====================================
5
5
 
6
6
  Riml aims to be a superset of VimL that includes some nice features that I
7
- enjoy in other scripting languages, including classes, string interpolation,
8
- heredocs, default case-sensitive string comparison and other things most
9
- programmers take for granted. Also, Riml takes some liberties and provides
10
- some syntactic sugar for lots of VimL constructs. To see how Riml constructs
11
- are compiled into VimL, just take a look in this README. The left side is Riml,
12
- and the right side is the equivalent VimL after compilation.
7
+ enjoy in other scripting languages: classes, string interpolation,
8
+ heredocs, default case-sensitive string comparison, default parameters
9
+ in functions, and other things programmers tend to take for granted. Also, Riml takes
10
+ some liberties and provides some syntactic sugar for lots of VimL constructs.
11
+ To see how Riml constructs are compiled to VimL, just take a look at this README.
12
+ The left side is Riml, and the right side is the VimL after compilation.
13
+
13
14
  Variables
14
15
  ---------
15
16
 
@@ -19,17 +20,30 @@ Variables
19
20
  count += 1 let s:count += 1
20
21
  end endwhile
21
22
 
22
- If you don't specify a scope modifier, it's script local by default in the
23
- global namespace. Within a function, variables without scope modifiers are plain
23
+ If you don't specify a scope modifier (or namespace in Vimspeak), it's script local (s:)
24
+ by default in the global scope. Within a function, variables without scope modifiers are plain
24
25
  old local variables.
25
26
 
26
27
  ###globally
27
28
 
28
29
  a = 3 let s:a = 3
29
30
 
30
- ###locally
31
+ ###locally (within function or for loop)
32
+
33
+ def exampleFunc(msg) function! s:exampleFunc(msg)
34
+ a = 3 let a = 3
35
+ echo msg echo a:msg
36
+ end endfunction
37
+
38
+ for i in expr() for i in s:expr()
39
+ echo i echo i
40
+ end endfor
31
41
 
32
- a = 3 let a = 3
42
+ Notice that within a function, it's unnecessary to prefix argument variables
43
+ with 'a:'. This is, of course, unless we shadow the argument variable by creating
44
+ our own local variable called 'msg'. In that case, we'd have to refer to the argument variable
45
+ as 'a:msg' explicitly. Shadowing variables in Riml is considered bad practice, as it's
46
+ much easier to just come up with unique variable names across a scope.
33
47
 
34
48
  ###Freeing memory
35
49
 
@@ -43,22 +57,82 @@ old local variables.
43
57
  callcount += 1 let s:callcount += 1
44
58
  echo "called #{callcount} times" echo "called " . s:callcount . " times"
45
59
 
46
- Comparisons
47
- -----------
60
+ Notice in the last line of Riml there's string interpolation. This works
61
+ in double-quoted strings and heredocs, which we'll encounter later.
62
+
63
+ In Riml, you can choose to end any block with 'end', or with whatever you used
64
+ to do in Vimscript ('endif', 'endfunction', etc...). Also, 'if' and 'unless' can
65
+ now be used as statement modifiers:
66
+
67
+ callcount = 0 unless s:callcount?
68
+ callcount += 1
69
+ echo "called #{callcount} times"
48
70
 
49
- a = "hi" == "hi" if ("hi" ==# "hi")
50
- let s:a = 1
51
- else
52
- let s:a = 0
53
- endif
71
+ Here, the compiled output is the same as the previous example's. Both 'if' and
72
+ 'unless' can be used this way.
73
+
74
+ Operators And Case Sensitivity
75
+ ------------------------------
76
+
77
+ if "hi" == greeting if "hi" ==# s:greeting
78
+ echo greeting echo s:greeting
79
+ end end
80
+
81
+ Comparisons compile to case-sensitive by default. To get case-insensitive
82
+ comparisons, you have to explicitly use the form ending in '?' (ex: '==?').
83
+ The only operators that don't add a '#' even though the forms exist are the
84
+ 'is' and 'isnot' operators. This is because 'is' is much different from its
85
+ cousin 'is#', and the same is true of 'isnot'.
54
86
 
55
87
  Heredocs
56
88
  --------
57
89
 
58
- msg = <<EOS let s:msg = "a vim heredoc! " . s:cryForJoy() . "!\n"
90
+ msg = <<EOS let s:msg = "a vim heredoc! " . s:cryForJoy() . "!\nHooray!\n"
59
91
  A vim heredoc! #{cryForJoy()}!
92
+ Hooray!
60
93
  EOS
61
94
 
95
+ Riml heredocs must have the ending pattern start at the beginning
96
+ of the line. Interpolating expressions is allowed in heredocs. Compiled
97
+ heredocs always end with a newline.
98
+
99
+ Functions
100
+ ---------
101
+
102
+ def fillSearchPat function! s:fillSearchPat()
103
+ @/ = getSearchPat() let @/ = s:getSearchPat()
104
+ return @/ return @/
105
+ end endfunction
106
+
107
+ When defining a function with no parameters, the parens after the function name are optional.
108
+
109
+ Functions are by default prepended by 's:' unless explicitly prepended with a
110
+ different scope modifier. Of course, you can use the old form ('function! Name()') for defining
111
+ functions if you want, as Riml aims to be a superset of VimL. There are a few exceptions
112
+ where Riml and VimL aren't compatible, and these differences are explained in
113
+ the section 'Incompatibilities with VimL'.
114
+
115
+ ###Default Arguments
116
+
117
+ def fillSearchPat(pat = getDefaultSearchPat()) function! s:fillSearchPat(...)
118
+ @/ = pat if get(a:000, 0, 'rimldefault') !=# 'rimldefault'
119
+ return @/ let pat = remove(a:000, 0)
120
+ end else
121
+ let pat = s:getDefaultSearchPat()
122
+ endif
123
+ @/ = pat
124
+ return @/
125
+ endfunction
126
+
127
+
128
+ Default arguments must be the last arguments given to a function, but there can be more
129
+ than one default argument. Also, a splat argument (... or \*argName) can come after default argument(s).
130
+ Splats will be explained in the next section.
131
+
132
+ We can now call the function 'fillSearchPat' without any arguments and it will use the default
133
+ argument. Also, if we pass the string 'rimldefault', it will use the default argument as well. This
134
+ is useful if a function has many default arguments.
135
+
62
136
  Classes
63
137
  -------
64
138
 
@@ -82,7 +156,17 @@ Classes
82
156
  return self.otherData
83
157
  endfunction
84
158
 
85
- ###Class with Inheritance
159
+ Classes can only be defined once, and cannot be reopened. Public member
160
+ functions are defined with 'defm'. If you want to create a non-public function
161
+ inside a class, use 'def'. To create an instance of this class, simply:
162
+
163
+ obj = new MyClass('someData', 'someOtherData')
164
+
165
+ In this basic example of a class, we see a \*splat variable. This is just a
166
+ convenient way to refer to 'a:000' in a function. Splat variables are optional
167
+ parameters and get compiled to '...'.
168
+
169
+ ###Class Inheritance
86
170
 
87
171
  class Translation function! g:TranslationConstructor(input)
88
172
  def initialize(input) let translationObj = {}
@@ -108,6 +192,178 @@ Classes
108
192
 
109
193
  let s:translation = g:TranslationConstructor("Bonjour!")
110
194
  call s:translation.translate()
195
+ => "Hello!"
196
+
197
+ Classes that inherit must have their superclass defined before inheritance takes place. In
198
+ this example, 'Translation' is defined first, which is legal. Since 'Translation'
199
+ has an initialize function and 'FrenchToEnglishTranslation' (referred to now as FET)
200
+ doesn't, FET instances use the initialize function from 'Translation', and new
201
+ instances must be provided with an 'input' argument on creation. Basically, if
202
+ a class doesn't provide an initialize function, it uses its superclass's.
203
+
204
+ If you look at the last line of Riml in the previous example, you'll see that
205
+ it doesn't use Vimscript's builtin 'call' function for calling the 'translate'
206
+ method on the translation object. Riml can figure out when 'call' is necessary,
207
+ and will add it to the compiled Vimscript.
208
+
209
+ ###Using 'super'
210
+
211
+ class Car function! g:CarConstructor(make, model, color)
212
+ def initialize(make, model, color) let carObj = {}
213
+ self.make = make let carObj.make = a:make
214
+ self.model = model let carObj.model = a:model
215
+ self.color = color let carObj.color = a:color
216
+ end endfunction
217
+ end
218
+
219
+ class HotRod < Car function! g:HotRodConstructor(make, model, color, topSpeed)
220
+ def initialize(make, model, color, topSpeed) let hotRodObj = {}
221
+ self.topSpeed = topSpeed let hotRodObj.topSpeed = a:topSpeed
222
+ super(make, model, color) let carObj = g:CarConstructor(a:make, a:model, a:color)
223
+ end call extend(hotRodObj, carObj)
224
+ let hotRodObj.drive = function('g:HotRod_drive')
225
+ defm drive return hotRodObj
226
+ if self.topSpeed > 140 endfunction
227
+ echo "Ahhhhhhh!"
228
+ else function! g:HotRod_drive() dict
229
+ echo "Nice" if self.topSpeed ># 140
230
+ end echo "Ahhhhhhh!"
231
+ end else
232
+ end echo "Nice"
233
+ endif
234
+ newCar = new HotRod("chevy", "mustang", "red", 160) endfunction
235
+ newCar.drive()
236
+ let s:newCar = g:HotRodConstructor("chevy", "mustang", "red", 160)
237
+ call s:newCar.drive()
238
+
239
+ Use of 'super' is legal only within subclasses. If arguments are given, these arguments are sent
240
+ to the superclass's function of the same name. If no arguments are given and parentheses are omitted,
241
+ ('super' as opposed to 'super()'), every single argument is passed to the superclass's function.
242
+ This mirrors Ruby's approach.
243
+
244
+ Super can be called from an initialize (constructor) function, a public member function
245
+ ('defm'), or a non-public function ('def'). An error is given during compilation if no
246
+ superclass function with that name is defined.
247
+
248
+ Compiling Riml
249
+ --------------
250
+
251
+ To compile a riml file named 'example.riml' that resides in the current
252
+ directory:
253
+
254
+ $ riml -c example.riml
255
+
256
+ This will create a new VimL file named 'example.vim'.
257
+
258
+ ###riml\_source
259
+
260
+ It's useful to split a project into many files. For example, imagine we're creating a plugin
261
+ called 'awesome' that does something totally awesome, and it relies on another library
262
+ we wrote called 'my\_framework' that's also written in Riml.
263
+
264
+ Somewhere in 'awesome.riml', we have the line:
265
+
266
+ riml_source 'my_framework.riml'
267
+
268
+ This will compile the file 'my\_framework.riml' and create a VimL file named
269
+ 'my\_framework.vim'.
270
+
271
+ In 'awesome.riml', that line will be compiled to:
272
+
273
+ source 'my_framework.vim'
274
+
275
+ This process is recursive, meaning that if 'my\_framework.riml' riml\_source's other
276
+ files, then those files will be compiled as well.
277
+
278
+ In 'awesome.riml', all the classes that were available by compiling 'my\_framework.riml'
279
+ are now available to it, so we can now subclass classes that were defined either
280
+ in 'my\_framework.riml' itself, or any files that it riml\_source'd either directly
281
+ or indirecty.
282
+
283
+
284
+ ###riml\_include
285
+
286
+ Sometimes it's useful to have many files in development, but to include a file's contents
287
+ into another file during the build process. This is much like the C preprocessor's #include
288
+ directive.
289
+
290
+ To include a file named 'my\_lib.riml':
291
+
292
+ riml_include 'my_lib.riml'
293
+
294
+ This compiles the file and includes its content in place of the riml\_include directive itself.
295
+ Much like riml\_sourcing, the process is recursive. If 'my\_lib.riml' includes files, these files
296
+ are also compiled and will be part of the inclusion. Note that riml\_include does not create a
297
+ new file like riml\_source does.
298
+
299
+ Incompatibilities with VimL
300
+ ---------------------------
301
+
302
+ Riml aims to be a superset of VimL, therefore any legal VimL should be legal
303
+ Riml as well. Unfortunately, this is not 100% possible as Vim is an old and
304
+ cryptic beast, and trying to create grammar for every possible Vim construct
305
+ would be a nightmare. In practice, however, when I've transformed plain old vim plugins
306
+ to be Riml-compatible, only a couple of ':' needed to be placed in strategic locations
307
+ for it to be valid Riml. This is explained below.
308
+
309
+ ###Ex-literals
310
+
311
+ Fortunately, there are some pretty simple rules to follow to get valid Riml.
312
+
313
+ When doing anything with autocommands, normal, commands, set, ranges, etc... simply do:
314
+
315
+ :autocmd BufEnter * blahblah...
316
+
317
+ That is, prepend ':' to the line. When a line starts with ':', it passes directly
318
+ through the compiler and no transformations occur. This includes string interpolation,
319
+ which is ignored as well.
320
+
321
+ In Riml, when a line starts with ':' it's called an ex-literal.
322
+
323
+ Ex-literals are necessary for the following:
324
+
325
+ * autocommands
326
+ * command definitions
327
+ * set
328
+ * ranges (:h cmdline-ranges)
329
+ * normal (:h normal)
330
+ * mappings
331
+ * augroups
332
+
333
+ Basically anything that isn't a class, number, string, list, dict, function call,
334
+ function definition, loop or if construct, variable definition or unlet, etc...
335
+ needs to be an ex-literal in Riml.
336
+
337
+ Note that, like 'echo' which isn't a builtin function (:h functions) but is still legal
338
+ Riml, 'execute' is also allowed as it takes a string. This is extremely useful, as we can
339
+ now use execute with a string that allows interpolation.
340
+
341
+ Imagine having to write a grammar rule for the following:
342
+
343
+ set statusline+=[%{strlen(&fenc)?&fenc:'none'}, " File encoding
344
+
345
+ Since there's no string after the '+=', it makes it very hard.
346
+ So when the compiler can't parse a file correctly, prepend those lines with
347
+ ':' and all should be well.
348
+
349
+ ###Abbreviations
350
+
351
+ In VimL, there are abbreviations for everything; even "keywords" like 'function' can be
352
+ abbreviated. In Riml, abbreviations are not allowed. This makes Riml much easier to read
353
+ and understand.
354
+
355
+ Everything Else That Works
356
+ --------------------------
111
357
 
358
+ Everything not mentioned above as illegal is legal Riml. Here's a short (non-comprehensive) list
359
+ of constructs which are legal Riml but not mentioned in any of the examples:
112
360
 
113
- Coming soon: for a full list of the language's rules complete with examples, check out the Wiki
361
+ * try/catch/finally blocks and throw
362
+ * curly-brace variable and function names
363
+ * while (and until) loops
364
+ * ternary operators
365
+ * exponents
366
+ * line continuations
367
+ * autoloadable variables and functions (:h autoload)
368
+ * let unpack (:h let-unpack)
369
+ * Much more!
data/bin/riml CHANGED
@@ -38,7 +38,7 @@ module Riml
38
38
  append_filenames_to_list_if_all_exist(options.check_syntax_files, *filenames)
39
39
  end
40
40
 
41
- opts.on("-t", "--source-path PATH", "Path riml uses for `riml_source` and `riml_include` to find files. Defaults to pwd.") do |path|
41
+ opts.on("-t", "--source-path PATH", "Colon-separated Path riml uses for `riml_source` and `riml_include` to find files. Defaults to pwd.") do |path|
42
42
  if Dir.exists?(path)
43
43
  Riml.source_path = path
44
44
  else
data/lib/ast_rewriter.rb CHANGED
@@ -150,9 +150,10 @@ module Riml
150
150
  AssignNode.new('=', GetVariableNode.new(nil, dict_name), DictionaryNode.new({}))
151
151
  )
152
152
 
153
- SuperToObjectExtension.new(constructor, classes, node).rewrite_on_match
153
+ InitializeSuperToObjectExtension.new(constructor, classes, node).rewrite_on_match
154
154
  ExtendObjectWithMethods.new(node, classes).rewrite_on_match
155
155
  SelfToDictName.new(dict_name).rewrite_on_match(constructor)
156
+ SuperToSuperclassFunction.new(node, classes).rewrite_on_match
156
157
 
157
158
  constructor.expressions.push(
158
159
  ReturnNode.new(GetVariableNode.new(nil, dict_name))
@@ -241,7 +242,7 @@ module Riml
241
242
  end
242
243
  end
243
244
 
244
- class SuperToObjectExtension < AST_Rewriter
245
+ class InitializeSuperToObjectExtension < AST_Rewriter
245
246
  attr_reader :class_node
246
247
  def initialize(constructor, classes, class_node)
247
248
  super(constructor, classes)
@@ -291,6 +292,64 @@ module Riml
291
292
  false
292
293
  end
293
294
  end
295
+
296
+ # rewrites calls to 'super' in non-initialize function
297
+ class SuperToSuperclassFunction < AST_Rewriter
298
+ def match?(node)
299
+ return false unless SuperNode === node
300
+ n = node
301
+ n = n.parent until DefNode === n || n.nil?
302
+ return false if n.nil? || ast.constructor == n
303
+ @function_node = n
304
+ end
305
+
306
+ def replace(node)
307
+ func_scope = @function_node.scope_modifier
308
+ superclass = classes[ast.superclass_name]
309
+ while superclass && !superclass.has_function?(func_scope, superclass_func_name(superclass)) && superclass.superclass?
310
+ superclass = classes[superclass.superclass_name]
311
+ end
312
+ if superclass.nil? || !superclass.has_function?(func_scope, superclass_func_name(superclass))
313
+ raise Riml::UserFunctionNotFoundError,
314
+ "super was called in class #{ast.name} in " \
315
+ "function #{@function_node.original_name}, but there are no " \
316
+ "functions with this name in that class's superclass hierarchy."
317
+ end
318
+ call_node = CallNode.new(
319
+ nil,
320
+ DictGetDotNode.new(
321
+ GetVariableNode.new(nil, 'self'),
322
+ [superclass_func_name(superclass)]
323
+ ),
324
+ node.arguments
325
+ )
326
+
327
+ node.replace_with(call_node)
328
+ add_superclass_func_ref_to_constructor(superclass)
329
+ reestablish_parents(@function_node)
330
+ end
331
+
332
+ def superclass_func_name(superclass)
333
+ "#{superclass.name}_#{@function_node.original_name}"
334
+ end
335
+
336
+ def add_superclass_func_ref_to_constructor(superclass)
337
+ super_func_name = superclass_func_name(superclass)
338
+ assign_node = AssignNode.new('=',
339
+ DictGetDotNode.new(
340
+ GetVariableNode.new(nil, ast.constructor_obj_name),
341
+ [super_func_name]
342
+ ),
343
+ CallNode.new(
344
+ nil,
345
+ 'function',
346
+ [StringNode.new("g:#{super_func_name}", :s)]
347
+ )
348
+ )
349
+ ast.constructor.expressions << assign_node
350
+ reestablish_parents(ast.constructor)
351
+ end
352
+ end
294
353
  end # ClassDefinitionToFunctions
295
354
 
296
355
  class ObjectInstantiationToCall < AST_Rewriter
data/lib/compiler.rb CHANGED
@@ -242,10 +242,15 @@ module Riml
242
242
  private
243
243
  def scope_modifier_for_node(node)
244
244
  if node.scope
245
- return "a:" if node.scope.argument_variable_names.include?(node.name)
246
- return "" unless node.is_a?(CallNode)
245
+ if node.scope.function && DefNode === node && !node.defined_on_dictionary?
246
+ return "s:"
247
+ elsif node.scope.argument_variable_names.include?(node.name)
248
+ return "a:"
249
+ elsif !node.is_a?(CallNode)
250
+ return ""
251
+ end
247
252
  end
248
- return "" if (node.is_a?(CallNode) || node.is_a?(DefNode)) && node.autoload?
253
+ return "" if node.respond_to?(:autoload?) && node.autoload?
249
254
  "s:"
250
255
  end
251
256
  end
@@ -376,7 +381,11 @@ module Riml
376
381
 
377
382
  class DefNodeVisitor < ScopedVisitor
378
383
  def visit(node)
379
- setup_local_scope_for_descendants(node)
384
+ options = {}
385
+ if node.nested_function?
386
+ options[:nested_function] = true
387
+ end
388
+ setup_local_scope_for_descendants(node, options)
380
389
  super
381
390
  end
382
391
 
@@ -406,8 +415,9 @@ module Riml
406
415
  end
407
416
 
408
417
  private
409
- def setup_local_scope_for_descendants(node)
410
- node.expressions.accept(EstablishScopeVisitor.new(:scope => node.to_scope))
418
+ def setup_local_scope_for_descendants(node, options)
419
+ options.merge!(:scope => node.to_scope)
420
+ node.expressions.accept(EstablishScopeVisitor.new(options))
411
421
  end
412
422
 
413
423
  def process_parameters!(node)
@@ -430,6 +440,7 @@ module Riml
430
440
  class EstablishScopeVisitor < DrillDownVisitor
431
441
  def initialize(options)
432
442
  @scope = options[:scope]
443
+ @nested_function = options[:nested_function]
433
444
  end
434
445
 
435
446
  def visit(node)
@@ -437,7 +448,7 @@ module Riml
437
448
  end
438
449
 
439
450
  def establish_scope(node)
440
- if node.scope
451
+ if node.scope && !@nested_function
441
452
  node.scope = node.scope.merge @scope
442
453
  else
443
454
  node.scope = @scope
data/lib/errors.rb CHANGED
@@ -10,6 +10,7 @@ module Riml
10
10
  IncludeNotTopLevel = Class.new(RimlError)
11
11
  # bad user arguments to Riml functions
12
12
  UserArgumentError = Class.new(RimlError)
13
+ UserFunctionNotFoundError = Class.new(RimlError)
13
14
 
14
15
  ClassNotFound = Class.new(RimlError)
15
16
  ClassRedefinitionError = Class.new(RimlError)
data/lib/lexer.rb CHANGED
@@ -33,7 +33,6 @@ module Riml
33
33
  @indent_pending = false
34
34
  @dedent_pending = false
35
35
  @one_line_conditional_end_pending = false
36
- @splat_allowed = false
37
36
  @in_function_declaration = false
38
37
  end
39
38
 
@@ -149,9 +148,7 @@ module Riml
149
148
  @in_function_declaration = false unless DEFINE_KEYWORDS.include?(identifier) && @token_buf.size == 1
150
149
  end
151
150
  elsif splat = chunk[/\A(\.{3}|\*[a-zA-Z_]\w*)/]
152
- raise SyntaxError, "unexpected splat, has to be enclosed in parentheses" unless @splat_allowed
153
151
  @token_buf << [:SPLAT, splat]
154
- @splat_allowed = false
155
152
  @i += splat.size
156
153
  # integer (octal)
157
154
  elsif octal = chunk[/\A0[0-7]+/]
@@ -201,13 +198,13 @@ module Riml
201
198
  pattern = $1
202
199
  @i += heredoc_pattern.size
203
200
  new_chunk = get_new_chunk
204
- heredoc_string = new_chunk[%r|(.+?\r?\n)(#{Regexp.escape(pattern)})|, 1]
201
+ heredoc_string = new_chunk[%r|(.+?\r?\n)(#{Regexp.escape(pattern)})|m, 1]
205
202
  @i += heredoc_string.size + pattern.size
206
203
  if ('"' + heredoc_string + '"') =~ INTERPOLATION_REGEX
207
204
  parts = heredoc_string.split(INTERPOLATION_SPLIT_REGEX)
208
205
  handle_interpolation(*parts)
209
206
  else
210
- @token_buf << [:STRING_D, escape_double_quotes(heredoc_string)]
207
+ @token_buf << [:STRING_D, escape_chars!(heredoc_string)]
211
208
  end
212
209
  @lineno += heredoc_string.each_line.to_a.size
213
210
  # operators of more than 1 char
@@ -227,8 +224,6 @@ module Riml
227
224
  else
228
225
  @token_buf << [value, value]
229
226
  end
230
- @splat_allowed = true if value == '('
231
- @splat_allowed = false if value == ')'
232
227
  @i += 1
233
228
  if value == ']' || value == ')' && chunk[1, 1] == '.'
234
229
  parse_dict_vals!
@@ -287,15 +282,17 @@ module Riml
287
282
  if part[0..1] == '#{' && part[-1] == '}'
288
283
  @token_buf.concat tokenize_without_moving_pos(part[2...-1])
289
284
  else
290
- @token_buf << [:STRING_D, escape_double_quotes(part)]
285
+ @token_buf << [:STRING_D, escape_chars!(part)]
291
286
  end
292
287
  # string-concatenate all the parts unless this is the last part
293
288
  @token_buf << ['.', '.'] unless parts[i + 1].nil?
294
289
  end
295
290
  end
296
291
 
297
- def escape_double_quotes(string)
298
- string.gsub(/"/, '\"')
292
+ def escape_chars!(string)
293
+ string.gsub!(/"/, '\"')
294
+ string.gsub!(/\n/, "\\n")
295
+ string
299
296
  end
300
297
 
301
298
  def tokenize_without_moving_pos(code)
data/lib/nodes.rb CHANGED
@@ -323,7 +323,7 @@ class RimlCommandNode < CallNode
323
323
  def initialize(*)
324
324
  super
325
325
  if arguments.empty? || !arguments.all? { |arg| arg.is_a?(StringNode) }
326
- raise Riml::UserArgumentError, "#{name.inspect} error: must pass string (name of file)"
326
+ raise Riml::UserArgumentError, "#{name.inspect} error: must pass string(s) (name of file(s))"
327
327
  end
328
328
  end
329
329
 
@@ -500,24 +500,38 @@ class DefNode < Struct.new(:bang, :scope_modifier, :name, :parameters, :keyword,
500
500
  include FullyNameable
501
501
  include Walkable
502
502
 
503
- attr_accessor :original_name
504
-
505
503
  def initialize(*args)
506
504
  super
507
505
  # max number of arguments in viml
508
506
  if parameters.reject(&DEFAULT_PARAMS).size > 20
509
507
  raise Riml::UserArgumentError, "can't have more than 20 parameters for #{full_name}"
510
508
  end
509
+ expressions.nodes.select { |node| DefNode === node}.each do |nested_func|
510
+ nested_func.nested_within.unshift(self)
511
+ end
511
512
  end
512
513
 
513
514
  SPLAT = lambda {|arg| arg == Riml::Constants::SPLAT_LITERAL || arg[0] == "*"}
514
515
  DEFAULT_PARAMS = lambda {|p| DefaultParamNode === p}
515
516
 
517
+ def original_name
518
+ @original_name ||= name
519
+ end
520
+ attr_writer :original_name
521
+
516
522
  # ["arg1", "arg2"}
517
523
  def argument_variable_names
518
524
  parameters.reject(&SPLAT)
519
525
  end
520
526
 
527
+ def nested_within
528
+ @nested_within ||= []
529
+ end
530
+
531
+ def nested_function?
532
+ not nested_within.empty?
533
+ end
534
+
521
535
  # returns the splat argument or nil
522
536
  def splat
523
537
  parameters.detect(&SPLAT)
@@ -531,12 +545,16 @@ class DefNode < Struct.new(:bang, :scope_modifier, :name, :parameters, :keyword,
531
545
  end
532
546
  end
533
547
 
548
+ def defined_on_dictionary?
549
+ keyword == 'dict'
550
+ end
551
+
534
552
  def autoload?
535
553
  name.include?('#')
536
554
  end
537
555
 
538
556
  def super_node
539
- expressions.detect {|n| SuperNode === n}
557
+ expressions.nodes.detect {|n| SuperNode === n}
540
558
  end
541
559
 
542
560
  def to_scope
@@ -604,7 +622,7 @@ class ScopeNode
604
622
  end
605
623
  self.for_node_variable_names += other.for_node_variable_names
606
624
  self.argument_variable_names -= for_node_variable_names
607
- self.function = other.function if function.nil? && other.function
625
+ self.function = other.function
608
626
  self
609
627
  end
610
628
  end
@@ -797,13 +815,15 @@ class ClassDefinitionNode < Struct.new(:name, :superclass_name, :expressions)
797
815
  include Visitable
798
816
  include Walkable
799
817
 
818
+ FUNCTIONS = lambda {|expr| DefNode === expr}
819
+
800
820
  def superclass?
801
821
  not superclass_name.nil?
802
822
  end
803
823
 
804
824
  def constructor
805
- expressions.detect do |n|
806
- next(false) unless DefNode === n && (n.name == 'initialize' || n.name.match(/Constructor\Z/))
825
+ expressions.nodes.detect do |n|
826
+ next(false) unless DefNode === n && (n.name == 'initialize' || n.name == constructor_name)
807
827
  if n.instance_of?(DefMethodNode)
808
828
  Riml.warn("class #{name.inspect} has an initialize function declared with 'defm'. Please use 'def'.")
809
829
  new_node = n.to_def_node
@@ -815,6 +835,13 @@ class ClassDefinitionNode < Struct.new(:name, :superclass_name, :expressions)
815
835
  end
816
836
  alias constructor? constructor
817
837
 
838
+ def find_function(scope_modifier, name)
839
+ expressions.nodes.select(&FUNCTIONS).detect do |def_node|
840
+ def_node.name == name && def_node.scope_modifier == scope_modifier
841
+ end
842
+ end
843
+ alias has_function? find_function
844
+
818
845
  def constructor_name
819
846
  "#{name}Constructor"
820
847
  end
data/lib/repl.rb CHANGED
@@ -69,7 +69,6 @@ module Riml
69
69
 
70
70
  def compile_unit!
71
71
  viml = Riml.compile(current_compilation_unit.join("\n"), parser, compiler).chomp
72
- escape_newlines_in_strings!(viml)
73
72
  puts viml, "\n"
74
73
  rescue => e
75
74
  raise unless e.kind_of?(RimlError)
@@ -92,10 +91,6 @@ module Riml
92
91
  puts "#{e.class}: #{e}"
93
92
  end
94
93
 
95
- def escape_newlines_in_strings!(viml)
96
- viml.gsub!(/("[^"]*?)\n+([^"]?")/, '\1\\n\2')
97
- end
98
-
99
94
  def exit_repl
100
95
  exit
101
96
  end
data/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Riml
2
- # last changed: Apr. 1, 2013
3
- VERSION = [0,2,1]
2
+ # last changed: Apr. 7, 2013
3
+ VERSION = [0,2,2]
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-01 00:00:00.000000000 Z
12
+ date: 2013-04-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: racc