]> git.lizzy.rs Git - metalua.git/blob - src/compiler/gg.lua
d237d28f1939f4fecc66df3ae42e707a5b02e479
[metalua.git] / src / compiler / gg.lua
1 ----------------------------------------------------------------------
2 -- Metalua.
3 --
4 -- Summary: parser generator. Collection of higher order functors,
5 --   which allow to build and combine parsers. Relies on a lexer
6 --   that supports the same API as the one exposed in mll.lua.
7 --
8 ----------------------------------------------------------------------
9 --
10 -- Copyright (c) 2006-2008, Fabien Fleutot <metalua@gmail.com>.
11 --
12 -- This software is released under the MIT Licence, see licence.txt
13 -- for details.
14 --
15 ----------------------------------------------------------------------
16
17 --------------------------------------------------------------------------------
18 --
19 -- Exported API:
20 --
21 -- Parser generators:
22 -- * [gg.sequence()]
23 -- * [gg.multisequence()]
24 -- * [gg.expr()]
25 -- * [gg.list()]
26 -- * [gg.onkeyword()]
27 -- * [gg.optkeyword()]
28 --
29 -- Other functions: 
30 -- * [gg.parse_error()]
31 -- * [gg.make_parser()]
32 -- * [gg.is_parser()]
33 --
34 --------------------------------------------------------------------------------
35
36 module("gg", package.seeall)
37
38 -------------------------------------------------------------------------------
39 -- parser metatable, which maps __call to method parse, and adds some
40 -- error tracing boilerplate.
41 -------------------------------------------------------------------------------
42 local parser_metatable = { }
43 function parser_metatable.__call (parser, lx, ...)
44    --printf ("Call parser %q of type %q", parser.name or "?", parser.kind)
45    if mlc.metabugs then 
46       return parser:parse (lx, ...) 
47       --local x = parser:parse (lx, ...) 
48       --printf ("Result of parser %q: %s", 
49       --        parser.name or "?",
50       --        _G.table.tostring(x, "nohash", 80))
51       --return x
52    else
53       local li = lx:lineinfo_right() or { "?", "?", "?", "?" }
54       local status, ast = pcall (parser.parse, parser, lx, ...)      
55       if status then return ast else
56          error (string.format ("%s\n - (l.%s, c.%s, k.%s) in parser %s", 
57                                ast:strmatch "gg.lua:%d+: (.*)" or ast,
58                                li[1], li[2], li[3], parser.name or parser.kind))
59       end
60    end
61 end
62
63 -------------------------------------------------------------------------------
64 -- Turn a table into a parser, mainly by setting the metatable.
65 -------------------------------------------------------------------------------
66 function make_parser(kind, p)
67    p.kind = kind
68    if not p.transformers then p.transformers = { } end
69    function p.transformers:add (x)
70       table.insert (self, x)
71    end
72    setmetatable (p, parser_metatable)
73    return p
74 end
75
76 -------------------------------------------------------------------------------
77 -- Return true iff [x] is a parser.
78 -- If it's a gg-generated parser, return the name of its kind.
79 -------------------------------------------------------------------------------
80 function is_parser (x)
81    return type(x)=="function" or getmetatable(x)==parser_metatable and x.kind
82 end
83
84 -------------------------------------------------------------------------------
85 -- Parse a sequence, without applying builder nor transformers
86 -------------------------------------------------------------------------------
87 local function raw_parse_sequence (lx, p)
88    local r = { }
89    for i=1, #p do
90       e=p[i]
91       if type(e) == "string" then 
92          if not lx:is_keyword (lx:next(), e) then
93             parse_error (lx, "Keyword '%s' expected", e) end
94       elseif is_parser (e) then
95          table.insert (r, e (lx)) 
96       else 
97          gg.parse_error (lx,"Sequence `%s': element #%i is not a string "..
98                          "nor a parser: %s", 
99                          p.name, i, table.tostring(e))
100       end
101    end
102    return r
103 end
104
105 -------------------------------------------------------------------------------
106 -- Parse a multisequence, without applying multisequence transformers.
107 -- The sequences are completely parsed.
108 -------------------------------------------------------------------------------
109 local function raw_parse_multisequence (lx, sequence_table, default)
110    local seq_parser = sequence_table[lx:is_keyword(lx:peek())]
111    if seq_parser  then return seq_parser (lx)
112    elseif default then return default (lx)
113    else return false end
114 end
115
116 -------------------------------------------------------------------------------
117 -- Applies all transformers listed in parser on ast.
118 -------------------------------------------------------------------------------
119 local function transform (ast, parser, fli, lli)
120    if parser.transformers then
121       for _, t in ipairs (parser.transformers) do ast = t(ast) or ast end
122    end
123    if type(ast) == 'table'then
124       local ali = ast.lineinfo
125       if not ali or ali.first~=fli or ali.last~=lli then
126          ast.lineinfo = { first = fli, last = lli }
127       end
128    end
129    return ast
130 end
131
132 -------------------------------------------------------------------------------
133 -- Generate a tracable parsing error (not implemented yet)
134 -------------------------------------------------------------------------------
135 function parse_error(lx, fmt, ...)
136    local li = lx:lineinfo_left() or {-1,-1,-1, "<unknown file>"}
137    local msg  = string.format("line %i, char %i: "..fmt, li[1], li[2], ...)   
138    local src = lx.src
139    if li[3]>0 and src then
140       local i, j = li[3], li[3]
141       while src:sub(i,i) ~= '\n' and i>=0    do i=i-1 end
142       while src:sub(j,j) ~= '\n' and j<=#src do j=j+1 end      
143       local srcline = src:sub (i+1, j-1)
144       local idx  = string.rep (" ", li[2]).."^"
145       msg = string.format("%s\n>>> %s\n>>> %s", msg, srcline, idx)
146    end
147    error(msg)
148 end
149    
150 -------------------------------------------------------------------------------
151 --
152 -- Sequence parser generator
153 --
154 -------------------------------------------------------------------------------
155 -- Input fields:
156 --
157 -- * [builder]: how to build an AST out of sequence parts. let [x] be the list
158 --   of subparser results (keywords are simply omitted). [builder] can be:
159 --    - [nil], in which case the result of parsing is simply [x]
160 --    - a string, which is then put as a tag on [x]
161 --    - a function, which takes [x] as a parameter and returns an AST.
162 --
163 -- * [name]: the name of the parser. Used for debug messages
164 --
165 -- * [transformers]: a list of AST->AST functions, applied in order on ASTs
166 --   returned by the parser.
167 --
168 -- * Table-part entries corresponds to keywords (strings) and subparsers 
169 --   (function and callable objects).
170 --
171 -- After creation, the following fields are added:
172 -- * [parse] the parsing function lexer->AST
173 -- * [kind] == "sequence"
174 -- * [name] is set, if it wasn't in the input.
175 --
176 -------------------------------------------------------------------------------
177 function sequence (p)
178    make_parser ("sequence", p)
179
180    -------------------------------------------------------------------
181    -- Parsing method
182    -------------------------------------------------------------------
183    function p:parse (lx)
184       -- Raw parsing:
185       local fli = lx:lineinfo_right()
186       local seq = raw_parse_sequence (lx, self)
187       local lli = lx:lineinfo_left()
188
189       -- Builder application:
190       local builder, tb = self.builder, type (self.builder)
191       if tb == "string" then seq.tag = builder
192       elseif tb == "function" or builder and builder.__call then seq = builder(seq)
193       elseif builder == nil then -- nothing
194       else error ("Invalid builder of type "..tb.." in sequence") end
195       seq = transform (seq, self, fli, lli)
196       assert (not seq or seq.lineinfo)
197       return seq
198    end
199
200    -------------------------------------------------------------------
201    -- Construction
202    -------------------------------------------------------------------
203    -- Try to build a proper name
204    if not p.name and type(p[1])=="string" then 
205       p.name = p[1].." ..." 
206       if type(p[#p])=="string" then p.name = p.name .. " " .. p[#p] end
207    else
208       p.name = "<anonymous>"
209    end
210
211    return p
212 end --</sequence>
213
214
215 -------------------------------------------------------------------------------
216 --
217 -- Multiple, keyword-driven, sequence parser generator
218 --
219 -------------------------------------------------------------------------------
220 -- in [p], useful fields are:
221 --
222 -- * [transformers]: as usual
223 --
224 -- * [name]: as usual
225 --
226 -- * Table-part entries must be sequence parsers, or tables which can
227 --   be turned into a sequence parser by [gg.sequence]. These
228 --   sequences must start with a keyword, and this initial keyword
229 --   must be different for each sequence.  The table-part entries will
230 --   be removed after [gg.multisequence] returns.
231 --
232 -- * [default]: the parser to run if the next keyword in the lexer is
233 --   none of the registered initial keywords. If there's no default
234 --   parser and no suitable initial keyword, the multisequence parser
235 --   simply returns [false].
236 --
237 -- After creation, the following fields are added:
238 --
239 -- * [parse] the parsing function lexer->AST
240 --
241 -- * [sequences] the table of sequences, indexed by initial keywords.
242 --
243 -- * [add] method takes a sequence parser or a config table for
244 --   [gg.sequence], and adds/replaces the corresponding sequence
245 --   parser. If the keyword was already used, the former sequence is
246 --   removed and a warning is issued.
247 --
248 -- * [get] method returns a sequence by its initial keyword
249 --
250 -- * [kind] == "multisequence"
251 --
252 -------------------------------------------------------------------------------
253 function multisequence (p)   
254    make_parser ("multisequence", p)
255
256    -------------------------------------------------------------------
257    -- Add a sequence (might be just a config table for [gg.sequence])
258    -------------------------------------------------------------------
259    function p:add (s)
260       -- compile if necessary:
261       if not is_parser(s) then sequence(s) end
262       if is_parser(s) ~= 'sequence' or type(s[1]) ~= "string" then 
263          if self.default then -- two defaults
264             error ("In a multisequence parser, all but one sequences "..
265                    "must start with a keyword")
266          else self.default = s end -- first default
267       elseif self.sequences[s[1]] then -- duplicate keyword
268          eprintf (" *** Warning: keyword %q overloaded in multisequence ***", s[1])
269          self.sequences[s[1]] = s
270       else -- newly caught keyword
271          self.sequences[s[1]] = s
272       end
273    end -- </multisequence.add>
274
275    -------------------------------------------------------------------
276    -- Get the sequence starting with this keyword. [kw :: string]
277    -------------------------------------------------------------------
278    function p:get (kw) return self.sequences [kw] end
279
280    -------------------------------------------------------------------
281    -- Remove the sequence starting with keyword [kw :: string]
282    -------------------------------------------------------------------
283    function p:del (kw) 
284       if not self.sequences[kw] then 
285          eprintf("*** Warning: trying to delete sequence starting "..
286                  "with %q from a multisequence having no such "..
287                  "entry ***", kw) end
288       local removed = self.sequences[kw]
289       self.sequences[kw] = nil 
290       return removed
291    end
292
293    -------------------------------------------------------------------
294    -- Parsing method
295    -------------------------------------------------------------------
296    function p:parse (lx)
297       local fli = lx:lineinfo_right()
298       local x = raw_parse_multisequence (lx, self.sequences, self.default)
299       local lli = lx:lineinfo_left()
300       return transform (x, self, fli, lli)
301    end
302
303    -------------------------------------------------------------------
304    -- Construction
305    -------------------------------------------------------------------
306    -- Register the sequences passed to the constructor. They're going
307    -- from the array part of the parser to the hash part of field
308    -- [sequences]
309    p.sequences = { }
310    for i=1, #p do p:add (p[i]); p[i] = nil end
311
312    -- FIXME: why is this commented out?
313    --if p.default and not is_parser(p.default) then sequence(p.default) end
314    return p
315 end --</multisequence>
316
317
318 -------------------------------------------------------------------------------
319 --
320 -- Expression parser generator
321 --
322 -------------------------------------------------------------------------------
323 --
324 -- Expression configuration relies on three tables: [prefix], [infix]
325 -- and [suffix]. Moreover, the primary parser can be replaced by a
326 -- table: in this case the [primary] table will be passed to
327 -- [gg.multisequence] to create a parser.
328 --
329 -- Each of these tables is a modified multisequence parser: the
330 -- differences with respect to regular multisequence config tables are:
331 --
332 -- * the builder takes specific parameters:
333 --   - for [prefix], it takes the result of the prefix sequence parser,
334 --     and the prefixed expression
335 --   - for [infix], it takes the left-hand-side expression, the results 
336 --     of the infix sequence parser, and the right-hand-side expression.
337 --   - for [suffix], it takes the suffixed expression, and theresult 
338 --     of the suffix sequence parser.
339 --
340 -- * the default field is a list, with parameters:
341 --   - [parser] the raw parsing function
342 --   - [transformers], as usual
343 --   - [prec], the operator's precedence
344 --   - [assoc] for [infix] table, the operator's associativity, which
345 --     can be "left", "right" or "flat" (default to left)
346 --
347 -- In [p], useful fields are:
348 -- * [transformers]: as usual
349 -- * [name]: as usual
350 -- * [primary]: the atomic expression parser, or a multisequence config 
351 --   table (mandatory)
352 -- * [prefix]:  prefix  operators config table, see above.
353 -- * [infix]:   infix   operators config table, see above.
354 -- * [suffix]: suffix operators config table, see above.
355 --
356 -- After creation, these fields are added:
357 -- * [kind] == "expr"
358 -- * [parse] as usual
359 -- * each table is turned into a multisequence, and therefore has an 
360 --   [add] method
361 --
362 -------------------------------------------------------------------------------
363 function expr (p)
364    make_parser ("expr", p)
365
366    -------------------------------------------------------------------
367    -- parser method.
368    -- In addition to the lexer, it takes an optional precedence:
369    -- it won't read expressions whose precedence is lower or equal
370    -- to [prec].
371    -------------------------------------------------------------------
372    function p:parse (lx, prec)
373       prec = prec or 0
374
375       ------------------------------------------------------
376       -- Extract the right parser and the corresponding
377       -- options table, for (pre|in|suff)fix operators.
378       -- Options include prec, assoc, transformers.
379       ------------------------------------------------------
380       local function get_parser_info (tab)
381          local p2 = tab:get (lx:is_keyword (lx:peek()))
382          if p2 then -- keyword-based sequence found
383             local function parser(lx) return raw_parse_sequence(lx, p2) end
384             return parser, p2
385          else -- Got to use the default parser
386             local d = tab.default
387             if d then return d.parse or d.parser, d
388             else return false, false end
389          end
390       end
391
392       ------------------------------------------------------
393       -- Look for a prefix sequence. Multiple prefixes are
394       -- handled through the recursive [p.parse] call.
395       -- Notice the double-transform: one for the primary
396       -- expr, and one for the one with the prefix op.
397       ------------------------------------------------------
398       local function handle_prefix ()
399          local fli = lx:lineinfo_right()
400          local p2_func, p2 = get_parser_info (self.prefix)
401          local op = p2_func and p2_func (lx)
402          if op then -- Keyword-based sequence found
403             local ili = lx:lineinfo_right() -- Intermediate LineInfo
404             local e = p2.builder (op, self:parse (lx, p2.prec))
405             local lli = lx:lineinfo_left()
406             return transform (transform (e, p2, ili, lli), self, fli, lli)
407          else -- No prefix found, get a primary expression         
408             local e = self.primary(lx)
409             local lli = lx:lineinfo_left()
410             return transform (e, self, fli, lli)
411          end
412       end --</expr.parse.handle_prefix>
413
414       ------------------------------------------------------
415       -- Look for an infix sequence+right-hand-side operand.
416       -- Return the whole binary expression result,
417       -- or false if no operator was found.
418       ------------------------------------------------------
419       local function handle_infix (e)
420          local p2_func, p2 = get_parser_info (self.infix)
421          if not p2 then return false end
422
423          -----------------------------------------
424          -- Handle flattening operators: gather all operands
425          -- of the series in [list]; when a different operator 
426          -- is found, stop, build from [list], [transform] and
427          -- return.
428          -----------------------------------------
429          if (not p2.prec or p2.prec>prec) and p2.assoc=="flat" then
430             local fli = lx:lineinfo_right()
431             local pflat, list = p2, { e }
432             repeat
433                local op = p2_func(lx)
434                if not op then break end
435                table.insert (list, self:parse (lx, p2.prec))
436                local _ -- We only care about checking that p2==pflat
437                _, p2 = get_parser_info (self.infix)
438             until p2 ~= pflat
439             local e2 = pflat.builder (list)
440             local lli = lx:lineinfo_left()
441             return transform (transform (e2, pflat, fli, lli), self, fli, lli)
442  
443          -----------------------------------------
444          -- Handle regular infix operators: [e] the LHS is known,
445          -- just gather the operator and [e2] the RHS.
446          -- Result goes in [e3].
447          -----------------------------------------
448          elseif p2.prec and p2.prec>prec or 
449                 p2.prec==prec and p2.assoc=="right" then
450             local fli = e.lineinfo.first -- lx:lineinfo_right()
451             local op = p2_func(lx)
452             if not op then return false end
453             local e2 = self:parse (lx, p2.prec)
454             local e3 = p2.builder (e, op, e2)
455             local lli = lx:lineinfo_left()
456             return transform (transform (e3, p2, fli, lli), self, fli, lli)
457
458          -----------------------------------------
459          -- Check for non-associative operators, and complain if applicable. 
460          -----------------------------------------
461          elseif p2.assoc=="none" and p2.prec==prec then
462             parser_error (lx, "non-associative operator!")
463
464          -----------------------------------------
465          -- No infix operator suitable at that precedence
466          -----------------------------------------
467          else return false end
468
469       end --</expr.parse.handle_infix>
470
471       ------------------------------------------------------
472       -- Look for a suffix sequence.
473       -- Return the result of suffix operator on [e],
474       -- or false if no operator was found.
475       ------------------------------------------------------
476       local function handle_suffix (e)
477          -- FIXME bad fli, must take e.lineinfo.first
478          local p2_func, p2 = get_parser_info (self.suffix)
479          if not p2 then return false end
480          if not p2.prec or p2.prec>=prec then
481             --local fli = lx:lineinfo_right()
482             local fli = e.lineinfo.first
483             local op = p2_func(lx)
484             if not op then return false end
485             local lli = lx:lineinfo_left()
486             e = p2.builder (e, op)
487             e = transform (transform (e, p2, fli, lli), self, fli, lli)
488             return e
489          end
490          return false
491       end --</expr.parse.handle_suffix>
492
493       ------------------------------------------------------
494       -- Parser body: read suffix and (infix+operand) 
495       -- extensions as long as we're able to fetch more at
496       -- this precedence level.
497       ------------------------------------------------------
498       local e = handle_prefix()
499       repeat
500          local x = handle_suffix (e); e = x or e
501          local y = handle_infix   (e); e = y or e
502       until not (x or y)
503
504       -- No transform: it already happened in operators handling
505       return e
506    end --</expr.parse>
507
508    -------------------------------------------------------------------
509    -- Construction
510    -------------------------------------------------------------------
511    if not p.primary then p.primary=p[1]; p[1]=nil end
512    for _, t in ipairs{ "primary", "prefix", "infix", "suffix" } do
513       if not p[t] then p[t] = { } end
514       if not is_parser(p[t]) then multisequence(p[t]) end
515    end
516    function p:add(...) return self.primary:add(...) end
517    return p
518 end --</expr>
519
520
521 -------------------------------------------------------------------------------
522 --
523 -- List parser generator
524 --
525 -------------------------------------------------------------------------------
526 -- In [p], the following fields can be provided in input:
527 --
528 -- * [builder]: takes list of subparser results, returns AST
529 -- * [transformers]: as usual
530 -- * [name]: as usual
531 --
532 -- * [terminators]: list of strings representing the keywords which
533 --   might mark the end of the list. When non-empty, the list is
534 --   allowed to be empty. A string is treated as a single-element
535 --   table, whose element is that string, e.g. ["do"] is the same as
536 --   [{"do"}].
537 --
538 -- * [separators]: list of strings representing the keywords which can
539 --   separate elements of the list. When non-empty, one of these
540 --   keyword has to be found between each element. Lack of a separator
541 --   indicates the end of the list. A string is treated as a
542 --   single-element table, whose element is that string, e.g. ["do"]
543 --   is the same as [{"do"}]. If [terminators] is empty/nil, then
544 --   [separators] has to be non-empty.
545 --
546 -- After creation, the following fields are added:
547 -- * [parse] the parsing function lexer->AST
548 -- * [kind] == "list"
549 --
550 -------------------------------------------------------------------------------
551 function list (p)
552    make_parser ("list", p)
553
554    -------------------------------------------------------------------
555    -- Parsing method
556    -------------------------------------------------------------------
557    function p:parse (lx)
558
559       ------------------------------------------------------
560       -- Used to quickly check whether there's a terminator 
561       -- or a separator immediately ahead
562       ------------------------------------------------------
563       local function peek_is_in (keywords) 
564          return keywords and lx:is_keyword(lx:peek(), unpack(keywords)) end
565
566       local x = { }
567       local fli = lx:lineinfo_right()
568
569       -- if there's a terminator to start with, don't bother trying
570       if not peek_is_in (self.terminators) then 
571          repeat table.insert (x, self.primary (lx)) -- read one element
572          until
573             -- First reason to stop: There's a separator list specified,
574             -- and next token isn't one. Otherwise, consume it with [lx:next()]
575             self.separators and not(peek_is_in (self.separators) and lx:next()) or
576             -- Other reason to stop: terminator token ahead
577             peek_is_in (self.terminators) or
578             -- Last reason: end of file reached
579             lx:peek().tag=="Eof"
580       end
581
582       local lli = lx:lineinfo_left()
583       
584       -- Apply the builder. It can be a string, or a callable value, 
585       -- or simply nothing.
586       local b = self.builder
587       if b then
588          if type(b)=="string" then x.tag = b -- b is a string, use it as a tag
589          elseif type(b)=="function" then x=b(x)
590          else
591             local bmt = getmetatable(b)
592             if bmt and bmt.__call then x=b(x) end
593          end
594       end
595       return transform (x, self, fli, lli)
596    end --</list.parse>
597
598    -------------------------------------------------------------------
599    -- Construction
600    -------------------------------------------------------------------
601    if not p.primary then p.primary = p[1]; p[1] = nil end
602    if type(p.terminators) == "string" then p.terminators = { p.terminators }
603    elseif p.terminators and #p.terminators == 0 then p.terminators = nil end
604    if type(p.separators) == "string" then p.separators = { p.separators }
605    elseif p.separators and #p.separators == 0 then p.separators = nil end
606
607    return p
608 end --</list>
609
610
611 -------------------------------------------------------------------------------
612 --
613 -- Keyword-conditionned parser generator
614 --
615 -------------------------------------------------------------------------------
616 -- 
617 -- Only apply a parser if a given keyword is found. The result of
618 -- [gg.onkeyword] parser is the result of the subparser (modulo
619 -- [transformers] applications).
620 --
621 -- lineinfo: the keyword is *not* included in the boundaries of the
622 -- resulting lineinfo. A review of all usages of gg.onkeyword() in the
623 -- implementation of metalua has shown that it was the appropriate choice
624 -- in every case.
625 --
626 -- Input fields:
627 --
628 -- * [name]: as usual
629 --
630 -- * [transformers]: as usual
631 --
632 -- * [peek]: if non-nil, the conditionning keyword is left in the lexeme
633 --   stream instead of being consumed.
634 --
635 -- * [primary]: the subparser. 
636 --
637 -- * [keywords]: list of strings representing triggering keywords.
638 --
639 -- * Table-part entries can contain strings, and/or exactly one parser.
640 --   Strings are put in [keywords], and the parser is put in [primary].
641 --
642 -- After the call, the following fields will be set:
643 --   
644 -- * [parse] the parsing method
645 -- * [kind] == "onkeyword"
646 -- * [primary]
647 -- * [keywords]
648 --
649 -------------------------------------------------------------------------------
650 function onkeyword (p)
651    make_parser ("onkeyword", p)
652
653    -------------------------------------------------------------------
654    -- Parsing method
655    -------------------------------------------------------------------
656    function p:parse(lx)
657       if lx:is_keyword (lx:peek(), unpack(self.keywords)) then
658          --local fli = lx:lineinfo_right()
659          if not self.peek then lx:next() end
660          local content = self.primary (lx)
661          --local lli = lx:lineinfo_left()
662          local fli, lli = content.lineinfo.first, content.lineinfo.last
663          return transform (content, p, fli, lli)
664       else return false end
665    end
666
667    -------------------------------------------------------------------
668    -- Construction
669    -------------------------------------------------------------------
670    if not p.keywords then p.keywords = { } end
671    for _, x in ipairs(p) do
672       if type(x)=="string" then table.insert (p.keywords, x)
673       else assert (not p.primary and is_parser (x)); p.primary = x end
674    end
675    if not next (p.keywords) then 
676       eprintf("Warning, no keyword to trigger gg.onkeyword") end
677    assert (p.primary, 'no primary parser in gg.onkeyword')
678    return p
679 end --</onkeyword>
680
681
682 -------------------------------------------------------------------------------
683 --
684 -- Optional keyword consummer pseudo-parser generator
685 --
686 -------------------------------------------------------------------------------
687 --
688 -- This doesn't return a real parser, just a function. That function parses
689 -- one of the keywords passed as parameters, and returns it. It returns 
690 -- [false] if no matching keyword is found.
691 --
692 -- Notice that tokens returned by lexer already carry lineinfo, therefore
693 -- there's no need to add them, as done usually through transform() calls.
694 -------------------------------------------------------------------------------
695 function optkeyword (...)
696    local args = {...}
697    if type (args[1]) == "table" then 
698       assert (#args == 1)
699       args = args[1]
700    end
701    for _, v in ipairs(args) do assert (type(v)=="string") end
702    return function (lx)
703       local x = lx:is_keyword (lx:peek(), unpack (args))
704       if x then lx:next(); return x
705       else return false end
706    end
707 end
708
709
710 -------------------------------------------------------------------------------
711 --
712 -- Run a parser with a special lexer
713 --
714 -------------------------------------------------------------------------------
715 --
716 -- This doesn't return a real parser, just a function.
717 -- First argument is the lexer class to be used with the parser,
718 -- 2nd is the parser itself.
719 -- The resulting parser returns whatever the argument parser does.
720 --
721 -------------------------------------------------------------------------------
722 function with_lexer(new_lexer, parser)
723
724    -------------------------------------------------------------------
725    -- Most gg functions take their parameters in a table, so it's 
726    -- better to silently accept when with_lexer{ } is called with
727    -- its arguments in a list:
728    -------------------------------------------------------------------
729    if not parser and #new_lexer==2 and type(new_lexer[1])=='table' then
730       return with_lexer(unpack(new_lexer))
731    end
732
733    -------------------------------------------------------------------
734    -- Save the current lexer, switch it for the new one, run the parser,
735    -- restore the previous lexer, even if the parser caused an error.
736    -------------------------------------------------------------------
737    return function (lx)
738       local old_lexer = getmetatable(lx)
739       lx:sync()
740       setmetatable(lx, new_lexer)
741       local status, result = pcall(parser, lx)
742       lx:sync()
743       setmetatable(lx, old_lexer)
744       if status then return result else error(result) end
745    end
746 end