riml 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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