rufus-lua-moon 0.2.0 → 0.2.2

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