rufus-lua-moon 0.2.0 → 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.
@@ -4,6 +4,8 @@ local util = require"moonscript.util"
4
4
 
5
5
  require"lpeg"
6
6
 
7
+ local debug_grammar = false
8
+
7
9
  local data = require"moonscript.data"
8
10
  local types = require"moonscript.types"
9
11
 
@@ -66,14 +68,47 @@ end
66
68
  -- auto declare Proper variables with lpeg.V
67
69
  local function wrap_env(fn)
68
70
  local env = getfenv(fn)
71
+ local wrap_name = V
72
+
73
+ if debug_grammar then
74
+ local indent = 0
75
+ local indent_char = " "
76
+
77
+ local function iprint(...)
78
+ local args = {...}
79
+ for i=1,#args do
80
+ args[i] = tostring(args[i])
81
+ end
82
+
83
+ io.stdout:write(indent_char:rep(indent) .. table.concat(args, ", ") .. "\n")
84
+ end
85
+
86
+ wrap_name = function(name)
87
+ local v = V(name)
88
+ v = Cmt("", function()
89
+ iprint("* " .. name)
90
+ indent = indent + 1
91
+ return true
92
+ end) * Cmt(v, function(str, pos, ...)
93
+ iprint(name, true)
94
+ indent = indent - 1
95
+ return true, ...
96
+ end) + Cmt("", function()
97
+ iprint(name, false)
98
+ indent = indent - 1
99
+ return false
100
+ end)
101
+ return v
102
+ end
103
+ end
69
104
 
70
105
  return setfenv(fn, setmetatable({}, {
71
106
  __index = function(self, name)
72
- local value = env[name]
107
+ local value = env[name]
73
108
  if value ~= nil then return value end
74
109
 
75
110
  if name:match"^[A-Z][A-Za-z0-9]*$" then
76
- local v = V(name)
111
+ local v = wrap_name(name)
77
112
  rawset(self, name, v)
78
113
  return v
79
114
  end
@@ -130,16 +165,52 @@ local function flatten_or_mark(name)
130
165
  end
131
166
 
132
167
  -- makes sure the last item in a chain is an index
133
- local _assignable = { index = true, dot = true, slice = true }
168
+ local _chain_assignable = { index = true, dot = true, slice = true }
169
+
170
+ local function is_assignable(node)
171
+ local t = ntype(node)
172
+ return t == "self" or t == "value" or t == "self_class" or
173
+ t == "chain" and _chain_assignable[ntype(node[#node])]
174
+ end
175
+
134
176
  local function check_assignable(str, pos, value)
135
- if ntype(value) == "chain" and _assignable[ntype(value[#value])]
136
- or type(value) == "string"
137
- then
177
+ if is_assignable(value) then
138
178
  return true, value
139
179
  end
140
180
  return false
141
181
  end
142
182
 
183
+ local flatten_explist = flatten_or_mark"explist"
184
+ local function format_assign(lhs_exps, assign)
185
+ if not assign then
186
+ return flatten_explist(lhs_exps)
187
+ end
188
+
189
+ for _, assign_exp in ipairs(lhs_exps) do
190
+ if not is_assignable(assign_exp) then
191
+ error {assign_exp, "left hand expression is not assignable"}
192
+ end
193
+ end
194
+
195
+ local t = ntype(assign)
196
+ if t == "assign" then
197
+ return {"assign", lhs_exps, unpack(assign, 2)}
198
+ elseif t == "update" then
199
+ return {"update", lhs_exps[1], unpack(assign, 2)}
200
+ end
201
+
202
+ error "unknown assign expression"
203
+ end
204
+
205
+ -- the if statement only takes a single lhs, so we wrap in table to git to
206
+ -- "assign" tuple format
207
+ local function format_single_assign(lhs, assign)
208
+ if assign then
209
+ return format_assign({lhs}, assign)
210
+ end
211
+ return lhs
212
+ end
213
+
143
214
  local function sym(chars)
144
215
  return Space * chars
145
216
  end
@@ -148,10 +219,17 @@ local function symx(chars)
148
219
  return chars
149
220
  end
150
221
 
151
- local function simple_string(delim, x)
152
- return C(symx(delim)) * C((P('\\'..delim) +
153
- "\\\\" +
154
- (1 - S('\r\n'..delim)))^0) * sym(delim) / mark"string"
222
+ local function simple_string(delim, allow_interpolation)
223
+ local inner = P('\\'..delim) + "\\\\" + (1 - S('\r\n'..delim))
224
+ if allow_interpolation then
225
+ inter = symx"#{" * V"Exp" * sym"}"
226
+ inner = (C((inner - inter)^1) + inter / mark"interpolate")^0
227
+ else
228
+ inner = C(inner^0)
229
+ end
230
+
231
+ return C(symx(delim)) *
232
+ inner * sym(delim) / mark"string"
155
233
  end
156
234
 
157
235
  local function wrap_func_arg(value)
@@ -179,22 +257,15 @@ local function flatten_func(callee, args)
179
257
  return {"chain", callee, args}
180
258
  end
181
259
 
182
- -- wraps a statement that has a line decorator
260
+ local function flatten_string_chain(str, chain, args)
261
+ if not chain then return str end
262
+ return flatten_func({"chain", str, unpack(chain)}, args)
263
+ end
264
+
265
+ -- transforms a statement that has a line decorator
183
266
  local function wrap_decorator(stm, dec)
184
267
  if not dec then return stm end
185
-
186
- local arg = {stm, dec}
187
-
188
- if dec[1] == "if" then
189
- local _, cond, fail = unpack(dec)
190
- if fail then fail = {"else", {fail}} end
191
- stm = {"if", cond, {stm}, fail}
192
- elseif dec[1] == "comprehension" then
193
- local _, clauses = unpack(dec)
194
- stm = {"comprehension", stm, clauses}
195
- end
196
-
197
- return stm
268
+ return { "decorated", stm, dec }
198
269
  end
199
270
 
200
271
  -- wrap if statement if there is a conditional decorator
@@ -213,13 +284,14 @@ end
213
284
 
214
285
  -- :name in table literal
215
286
  local function self_assign(name)
216
- return {name, name}
287
+ return {{"key_literal", name}, name}
217
288
  end
218
289
 
219
- local err_msg = "Failed to parse:\n [%d] >> %s (%d)"
290
+ local err_msg = "Failed to parse:%s\n [%d] >> %s"
220
291
 
221
292
  local build_grammar = wrap_env(function()
222
293
  local _indent = Stack(0) -- current indent
294
+ local _do_stack = Stack(0)
223
295
 
224
296
  local last_pos = 0 -- used to know where to report error
225
297
  local function check_indent(str, pos, indent)
@@ -245,6 +317,34 @@ local build_grammar = wrap_env(function()
245
317
  return true
246
318
  end
247
319
 
320
+
321
+ local function check_do(str, pos, do_node)
322
+ local top = _do_stack:top()
323
+ if top == nil or top then
324
+ return true, do_node
325
+ end
326
+ return false
327
+ end
328
+
329
+ local function disable_do(str_pos)
330
+ _do_stack:push(false)
331
+ return true
332
+ end
333
+
334
+ local function enable_do(str_pos)
335
+ _do_stack:push(true)
336
+ return true
337
+ end
338
+
339
+ local function pop_do(str, pos)
340
+ if nil == _do_stack:pop() then error("unexpected do pop") end
341
+ return true
342
+ end
343
+
344
+ local DisableDo = Cmt("", disable_do)
345
+ local EnableDo = Cmt("", enable_do)
346
+ local PopDo = Cmt("", pop_do)
347
+
248
348
  local keywords = {}
249
349
  local function key(chars)
250
350
  keywords[chars] = true
@@ -260,15 +360,19 @@ local build_grammar = wrap_env(function()
260
360
  return patt
261
361
  end
262
362
 
263
- local SimpleName = Name -- for table key
264
-
265
363
  -- make sure name is not a keyword
266
364
  local Name = Cmt(Name, function(str, pos, name)
267
365
  if keywords[name] then return false end
268
366
  return true
269
367
  end) / trim
270
368
 
271
- local Name = sym"@" * Name / mark"self" + Name + Space * "..." / trim
369
+ local SelfName = Space * "@" * (
370
+ "@" * (_Name / mark"self_class" + Cc"self.__class") +
371
+ _Name / mark"self" + Cc"self")
372
+
373
+ local KeyName = SelfName + Space * _Name / mark"key_literal"
374
+
375
+ local Name = SelfName + Name + Space * "..." / trim
272
376
 
273
377
  local g = lpeg.P{
274
378
  File,
@@ -277,10 +381,14 @@ local build_grammar = wrap_env(function()
277
381
  CheckIndent = Cmt(Indent, check_indent), -- validates line is in correct indent
278
382
  Line = (CheckIndent * Statement + Space * #Stop),
279
383
 
280
- Statement = (Import + While + With + For + ForEach + Switch + Return
281
- + ClassDecl + Export + BreakLoop + Ct(ExpList) / flatten_or_mark"explist" * Space) * ((
384
+ Statement = pos(
385
+ Import + While + With + For + ForEach + Switch + Return +
386
+ Local + Export + BreakLoop +
387
+ Ct(ExpList) * (Update + Assign)^-1 / format_assign
388
+ ) * Space * ((
282
389
  -- statement decorators
283
390
  key"if" * Exp * (key"else" * Exp)^-1 * Space / mark"if" +
391
+ key"unless" * Exp / mark"unless" +
284
392
  CompInner / mark"comprehension"
285
393
  ) * Space)^-1 / wrap_decorator,
286
394
 
@@ -292,45 +400,55 @@ local build_grammar = wrap_env(function()
292
400
  PopIndent = Cmt("", pop_indent),
293
401
  InBlock = Advance * Block * PopIndent,
294
402
 
295
- Import = key"import" * Ct(ImportNameList) * key"from" * Exp / mark"import",
403
+ Local = key"local" * Ct(NameList) / mark"declare_with_shadows",
404
+
405
+ Import = key"import" * Ct(ImportNameList) * key"from" * Exp / mark"import",
296
406
  ImportName = (sym"\\" * Ct(Cc"colon_stub" * Name) + Name),
297
407
  ImportNameList = ImportName * (sym"," * ImportName)^0,
298
408
 
299
409
  NameList = Name * (sym"," * Name)^0,
300
410
 
301
- BreakLoop = Ct(key"break"/trim),
411
+ BreakLoop = Ct(key"break"/trim) + Ct(key"continue"/trim),
302
412
 
303
413
  Return = key"return" * (ExpListLow/mark"explist" + C"") / mark"return",
304
414
 
305
- With = key"with" * Exp * key"do"^-1 * Body / mark"with",
415
+ WithExp = Ct(ExpList) * Assign^-1 / format_assign,
416
+ With = key"with" * DisableDo * ensure(WithExp, PopDo) * key"do"^-1 * Body / mark"with",
306
417
 
307
- Switch = key"switch" * Exp * key"do"^-1 * Space^-1 * Break * SwitchBlock / mark"switch",
418
+ Switch = key"switch" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Space^-1 * Break * SwitchBlock / mark"switch",
308
419
 
309
420
  SwitchBlock = EmptyLine^0 * Advance * Ct(SwitchCase * (Break^1 * SwitchCase)^0 * (Break^1 * SwitchElse)^-1) * PopIndent,
310
421
  SwitchCase = key"when" * Exp * key"then"^-1 * Body / mark"case",
311
422
  SwitchElse = key"else" * Body / mark"else",
312
423
 
313
- If = key"if" * Exp * key"then"^-1 * Body *
314
- ((Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * Exp * key"then"^-1 * Body / mark"elseif")^0 *
424
+ IfCond = Exp * Assign^-1 / format_single_assign,
425
+
426
+ If = key"if" * IfCond * key"then"^-1 * Body *
427
+ ((Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif")^0 *
315
428
  ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"if",
316
429
 
317
- While = key"while" * Exp * key"do"^-1 * Body / mark"while",
430
+ Unless = key"unless" * IfCond * key"then"^-1 * Body *
431
+ ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"unless",
318
432
 
319
- For = key"for" * (Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1)) *
433
+ While = key"while" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Body / mark"while",
434
+
435
+ For = key"for" * DisableDo * ensure(Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1), PopDo) *
320
436
  key"do"^-1 * Body / mark"for",
321
437
 
322
- ForEach = key"for" * Ct(NameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) * key"do"^-1 * Body / mark"foreach",
438
+ ForEach = key"for" * Ct(NameList) * key"in" * DisableDo * ensure(Ct(sym"*" * Exp / mark"unpack" + ExpList), PopDo) * key"do"^-1 * Body / mark"foreach",
439
+
440
+ Do = key"do" * Body / mark"do",
323
441
 
324
442
  Comprehension = sym"[" * Exp * CompInner * sym"]" / mark"comprehension",
325
443
 
326
- TblComprehension = sym"{" * Exp * (sym"," * Exp)^-1 * CompInner * sym"}" / mark"tblcomprehension",
444
+ TblComprehension = sym"{" * Ct(Exp * (sym"," * Exp)^-1) * CompInner * sym"}" / mark"tblcomprehension",
327
445
 
328
446
  CompInner = Ct(CompFor * CompClause^0),
329
447
  CompFor = key"for" * Ct(NameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) / mark"for",
330
448
  CompClause = CompFor + key"when" * Exp / mark"when",
331
449
 
332
- Assign = Ct(AssignableList) * sym"=" * (Ct(With + If + Switch) + Ct(TableBlock + ExpListLow)) / mark"assign",
333
- Update = Assignable * ((sym"..=" + sym"+=" + sym"-=" + sym"*=" + sym"/=" + sym"%=")/trim) * Exp / mark"update",
450
+ Assign = sym"=" * (Ct(With + If + Switch) + Ct(TableBlock + ExpListLow)) / mark"assign",
451
+ Update = ((sym"..=" + sym"+=" + sym"-=" + sym"*=" + sym"/=" + sym"%=" + sym"or=" + sym"and=") / trim) * Exp / mark"update",
334
452
 
335
453
  -- we can ignore precedence for now
336
454
  OtherOps = op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<" + op">",
@@ -345,20 +463,23 @@ local build_grammar = wrap_env(function()
345
463
  -- Term = Ct(Value * (TermOp * Value)^0) / flatten_or_mark"exp",
346
464
 
347
465
  SimpleValue =
348
- If +
466
+ If + Unless +
349
467
  Switch +
350
468
  With +
469
+ ClassDecl +
351
470
  ForEach + For + While +
471
+ Cmt(Do, check_do) +
352
472
  sym"-" * -SomeSpace * Exp / mark"minus" +
353
473
  sym"#" * Exp / mark"length" +
354
474
  key"not" * Exp / mark"not" +
355
475
  TblComprehension +
356
476
  TableLit +
357
477
  Comprehension +
358
- Assign + Update + FunLit + String +
478
+ FunLit +
359
479
  Num,
360
480
 
361
481
  ChainValue = -- a function call or an object access
482
+ StringChain +
362
483
  ((Chain + DotChain + Callable) * Ct(InvokeArgs^-1)) / flatten_func,
363
484
 
364
485
  Value = pos(
@@ -368,13 +489,16 @@ local build_grammar = wrap_env(function()
368
489
 
369
490
  SliceValue = SimpleValue + ChainValue,
370
491
 
492
+ StringChain = String *
493
+ (Ct((ColonCall + ColonSuffix) * ChainTail^-1) * Ct(InvokeArgs^-1))^-1 / flatten_string_chain,
494
+
371
495
  String = Space * DoubleString + Space * SingleString + LuaString,
372
496
  SingleString = simple_string("'"),
373
- DoubleString = simple_string('"'),
497
+ DoubleString = simple_string('"', true),
374
498
 
375
499
  LuaString = Cg(LuaStringOpen, "string_open") * Cb"string_open" * Break^-1 *
376
500
  C((1 - Cmt(C(LuaStringClose) * Cb"string_open", check_lua_string))^0) *
377
- C(LuaStringClose) / mark"string",
501
+ LuaStringClose / mark"string",
378
502
 
379
503
  LuaStringOpen = sym"[" * P"="^0 * "[" / trim,
380
504
  LuaStringClose = "]" * P"="^0 * "]",
@@ -384,10 +508,10 @@ local build_grammar = wrap_env(function()
384
508
 
385
509
  FnArgs = symx"(" * Ct(ExpList^-1) * sym")" + sym"!" * -P"=" * Ct"",
386
510
 
387
- ChainTail = (ChainItem^1 * ColonSuffix^-1 + ColonSuffix),
511
+ ChainTail = ChainItem^1 * ColonSuffix^-1 + ColonSuffix,
388
512
 
389
- -- a list of funcalls and indexs on a callable
390
- Chain = Callable * (ChainItem^1 * ColonSuffix^-1 + ColonSuffix) / mark"chain",
513
+ -- a list of funcalls and indexes on a callable
514
+ Chain = Callable * ChainTail / mark"chain",
391
515
 
392
516
  -- shorthand dot call for use in with statement
393
517
  DotChain =
@@ -397,8 +521,8 @@ local build_grammar = wrap_env(function()
397
521
  (_Name / mark"colon_stub")
398
522
  )) / mark"chain",
399
523
 
400
- ChainItem =
401
- Invoke +
524
+ ChainItem =
525
+ Invoke +
402
526
  Slice +
403
527
  symx"[" * Exp/mark"index" * sym"]" +
404
528
  symx"." * _Name/mark"dot" +
@@ -428,12 +552,13 @@ local build_grammar = wrap_env(function()
428
552
  TableBlockInner = Ct(KeyValueLine * (SpaceBreak^1 * KeyValueLine)^0),
429
553
  TableBlock = SpaceBreak^1 * Advance * ensure(TableBlockInner, PopIndent) / mark"table",
430
554
 
431
- ClassDecl = key"class" * Name * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * ClassBlock / mark"class",
555
+ ClassDecl = key"class" * (Assignable + Cc(nil)) * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * (ClassBlock + Ct("")) / mark"class",
432
556
 
433
557
  ClassBlock = SpaceBreak^1 * Advance *
434
- Ct(ClassLine * (SpaceBreak^1 * ClassLine)^0) * PopIndent,
558
+ Ct(ClassLine * (SpaceBreak^1 * ClassLine)^0) * PopIndent,
435
559
  ClassLine = CheckIndent * ((
436
560
  KeyValueList / mark"props" +
561
+ Statement / mark"stm" +
437
562
  Exp / mark"stm"
438
563
  ) * sym","^-1),
439
564
 
@@ -442,7 +567,7 @@ local build_grammar = wrap_env(function()
442
567
  op"*" + op"^" +
443
568
  Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export",
444
569
 
445
- KeyValue = (sym":" * Name) / self_assign + Ct((SimpleName + sym"[" * Exp * sym"]") * symx":" * (Exp + TableBlock)),
570
+ KeyValue = (sym":" * Name) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock)),
446
571
  KeyValueList = KeyValue * (sym"," * KeyValue)^0,
447
572
  KeyValueLine = CheckIndent * KeyValueList * sym","^-1,
448
573
 
@@ -479,21 +604,35 @@ local build_grammar = wrap_env(function()
479
604
  end
480
605
 
481
606
  local tree
482
- local args = {...}
483
- local pass, err = assert(pcall(function()
484
- tree = self._g:match(str, unpack(args))
485
- end))
607
+ local pass, err = pcall(function(...)
608
+ tree = self._g:match(str, ...)
609
+ end, ...)
610
+
611
+ -- regular error, let it bubble up
612
+ if type(err) == "string" then
613
+ error(err)
614
+ end
486
615
 
487
616
  if not tree then
488
- local line_no = pos_to_line(last_pos)
617
+ local pos = last_pos
618
+ local msg
619
+
620
+ if err then
621
+ local node
622
+ node, msg = unpack(err)
623
+ msg = msg and " " .. msg
624
+ pos = node[-1]
625
+ end
626
+
627
+ local line_no = pos_to_line(pos)
489
628
  local line_str = get_line(line_no) or ""
490
-
491
- return nil, err_msg:format(line_no, trim(line_str), _indent:top())
629
+
630
+ return nil, err_msg:format(msg or "", line_no, trim(line_str))
492
631
  end
493
632
  return tree
494
633
  end
495
634
  }
496
-
635
+
497
636
  end)
498
637
 
499
638
  -- parse a string