492 | 492 |
return ret
|
493 | 493 |
end
|
494 | 494 |
|
|
495 |
local build_arg_list, split_iden -- forward declaration
|
|
496 |
|
495 | 497 |
|
496 | 498 |
function Item:finish()
|
497 | 499 |
local tags = self.tags
|
|
537 | 539 |
self.modifiers.field = self.modifiers.param
|
538 | 540 |
end
|
539 | 541 |
end
|
540 | |
local names, comments = List(), List()
|
|
542 |
local param_names, comments = List(), List()
|
541 | 543 |
if params then
|
542 | 544 |
for line in params:iter() do
|
543 | |
local name, comment = line :match('%s*([%w_%.:]+)(.*)')
|
|
545 |
local name, comment = line:match('%s*([%w_%.:]+)(.*)')
|
544 | 546 |
if not name then
|
545 | 547 |
self:error("bad param name format '"..line.."'. Are you missing a parameter name?")
|
546 | 548 |
end
|
547 | |
names:append(name)
|
|
549 |
param_names:append(name)
|
548 | 550 |
comments:append(comment)
|
549 | 551 |
end
|
550 | 552 |
end
|
551 | 553 |
self.modifiers['return'] = self.modifiers['return'] or List()
|
552 | 554 |
self.modifiers[field] = self.modifiers[field] or List()
|
553 | |
-- not all arguments may be commented: we use the formal arguments
|
554 | |
-- if available as the authoritative list, and warn if there's an inconsistency.
|
555 | |
if self.formal_args then
|
556 | |
local fargs = self.formal_args
|
557 | |
if not self.ret and fargs.return_comment then
|
558 | |
local retc = fargs.return_comment
|
559 | |
local type,rest = retc:match '([^:]+):(.*)'
|
560 | |
if type then
|
561 | |
self.modifiers['return']:append{type=type}
|
562 | |
retc = rest
|
563 | |
end
|
564 | |
self.ret = List{retc}
|
565 | |
end
|
566 | |
if #fargs ~= 0 then
|
567 | |
local pnames, pcomments = names, comments
|
568 | |
names, comments = List(),List()
|
|
555 |
-- we use the formal arguments (if available) as the authoritative list.
|
|
556 |
-- If there are both params and formal args, then they must match;
|
|
557 |
-- (A formal argument of ... may match any number of params at the end, however.)
|
|
558 |
-- If there are formal args and no params, we see if the args have any suitable comments.
|
|
559 |
-- Params may have subfields.
|
|
560 |
local fargs, formal = self.formal_args
|
|
561 |
if fargs then
|
|
562 |
if #param_names == 0 then
|
|
563 |
--docs may be embedded in argument comments; in either case, use formal arg names
|
|
564 |
formal = List()
|
|
565 |
if fargs.return_comment then
|
|
566 |
local retc = self:parse_argument_comment(fargs.return_comment,'return')
|
|
567 |
self.ret = List{retc}
|
|
568 |
end
|
|
569 |
for i, name in ipairs(fargs) do
|
|
570 |
formal:append(name)
|
|
571 |
comments:append(self:parse_argument_comment(fargs.comments[name],self.parameter))
|
|
572 |
end
|
|
573 |
elseif #fargs > 0 then
|
569 | 574 |
local varargs = fargs[#fargs] == '...'
|
570 | |
for i,name in ipairs(fargs) do
|
571 | |
if params then -- explicit set of param tags
|
572 | |
if pnames[i] ~= name and not varargs then
|
573 | |
if pnames[i] then
|
574 | |
self:warning("param and formal argument name mismatch: "..quote(name).." "..quote(pnames[i]))
|
575 | |
else
|
576 | |
self:warning("undocumented formal argument: "..quote(name))
|
|
575 |
if varargs then table.remove(fargs) end
|
|
576 |
local k = 0
|
|
577 |
for _,pname in ipairs(param_names) do
|
|
578 |
local _,field = split_iden(pname)
|
|
579 |
if not field then
|
|
580 |
k = k + 1
|
|
581 |
if k > #fargs then
|
|
582 |
if not varargs then
|
|
583 |
self:warning("extra param with no formal argument: "..quote(pname))
|
577 | 584 |
end
|
578 | |
elseif varargs then
|
579 | |
name = pnames[i]
|
|
585 |
elseif pname ~= fargs[k] then
|
|
586 |
self:warning("param and formal argument name mismatch: "..quote(pname).." "..quote(fargs[k]))
|
580 | 587 |
end
|
581 | 588 |
end
|
582 | |
names:append(name)
|
583 | |
local comment = pcomments[i]
|
584 | |
if not comment then
|
585 | |
-- ldoc allows comments in the formal arg list to be used, if they aren't specified with @param
|
586 | |
-- Further, these comments may start with a type followed by a colon, and are then equivalent
|
587 | |
-- to a @tparam
|
588 | |
comment = fargs.comments[name]
|
589 | |
if comment then
|
590 | |
comment = comment:gsub('^%-+%s*','')
|
591 | |
local type,rest = comment:match '([^:]+):(.*)'
|
592 | |
if type then
|
593 | |
self.modifiers[field]:append {type = type}
|
594 | |
comment = rest
|
595 | |
end
|
596 | |
end
|
597 | |
end
|
598 | |
comments:append (comment or '')
|
599 | |
end
|
600 | |
-- A formal argument of ... may match any number of params, however.
|
601 | |
if #pnames > #fargs then
|
602 | |
for i = #fargs+1,#pnames do
|
603 | |
if not varargs then
|
604 | |
self:warning("extra param with no formal argument: "..quote(pnames[i]))
|
605 | |
else
|
606 | |
names:append(pnames[i])
|
607 | |
comments:append(pcomments[i] or '')
|
|
589 |
end
|
|
590 |
if k < #fargs then
|
|
591 |
for i = k+1,#fargs do
|
|
592 |
if fargs[i] ~= '...' then
|
|
593 |
self:warning("undocumented formal argument: "..quote(fargs[i]))
|
608 | 594 |
end
|
609 | 595 |
end
|
610 | 596 |
end
|
|
614 | 600 |
-- the comments are associated with each parameter by
|
615 | 601 |
-- adding name-value pairs to the params list (this is
|
616 | 602 |
-- also done for any associated modifiers)
|
617 | |
self.params = names
|
|
603 |
-- (At this point we patch up any subparameter references)
|
618 | 604 |
local pmods = self.modifiers[field]
|
619 | |
for i,name in ipairs(self.params) do
|
620 | |
self.params[name] = comments[i]
|
|
605 |
local params, fields = List()
|
|
606 |
local original_names = formal and formal or param_names
|
|
607 |
local names = List()
|
|
608 |
self.subparams = {}
|
|
609 |
for i,name in ipairs(original_names) do
|
|
610 |
local pname,field = split_iden(name)
|
|
611 |
if field then
|
|
612 |
if not fields then
|
|
613 |
fields = List()
|
|
614 |
self.subparams[pname] = fields
|
|
615 |
end
|
|
616 |
fields:append(name)
|
|
617 |
else
|
|
618 |
names:append(name)
|
|
619 |
params:append(name)
|
|
620 |
fields = nil
|
|
621 |
end
|
|
622 |
|
|
623 |
params[name] = comments[i]
|
621 | 624 |
if pmods then
|
622 | 625 |
pmods[name] = pmods[i]
|
623 | 626 |
end
|
624 | 627 |
end
|
625 | |
|
626 | |
-- build up the string representation of the argument list,
|
627 | |
-- using any opt and optchain modifiers if present.
|
628 | |
-- For instance, '(a [, b])' if b is marked as optional
|
629 | |
-- with @param[opt] b
|
630 | |
local buffer, npending = { }, 0
|
631 | |
local function acc(x) table.insert(buffer, x) end
|
632 | |
for i = 1, #names do
|
633 | |
local m = pmods and pmods[i]
|
634 | |
if m then
|
635 | |
if not m.optchain then
|
636 | |
acc ((']'):rep(npending))
|
637 | |
npending=0
|
638 | |
end
|
639 | |
if m.opt or m.optchain then acc(' ['); npending=npending+1 end
|
640 | |
end
|
641 | |
if i>1 then acc (', ') end
|
642 | |
acc(names[i])
|
643 | |
end
|
644 | |
acc ((']'):rep(npending))
|
645 | |
self.args = '('..table.concat(buffer)..')'
|
646 | |
end
|
|
628 |
self.params = params
|
|
629 |
self.args = build_arg_list (names,pmods)
|
|
630 |
end
|
|
631 |
end
|
|
632 |
|
|
633 |
-- ldoc allows comments in the formal arg list to be used, if they aren't specified with @param
|
|
634 |
-- Further, these comments may start with a type followed by a colon, and are then equivalent
|
|
635 |
-- to a @tparam
|
|
636 |
function Item:parse_argument_comment (comment,field)
|
|
637 |
if comment then
|
|
638 |
comment = comment:gsub('^%-+%s*','')
|
|
639 |
local type,rest = comment:match '([^:]+):(.*)'
|
|
640 |
if type then
|
|
641 |
self.modifiers[field]:append {type = type}
|
|
642 |
comment = rest
|
|
643 |
end
|
|
644 |
end
|
|
645 |
return comment or ''
|
|
646 |
end
|
|
647 |
|
|
648 |
function split_iden (name)
|
|
649 |
if name == '...' then return name end
|
|
650 |
local pname,field = name:match('(.-)%.(.+)')
|
|
651 |
if not pname then
|
|
652 |
return name
|
|
653 |
else
|
|
654 |
return pname,field
|
|
655 |
end
|
|
656 |
end
|
|
657 |
|
|
658 |
function build_arg_list (names,pmods)
|
|
659 |
-- build up the string representation of the argument list,
|
|
660 |
-- using any opt and optchain modifiers if present.
|
|
661 |
-- For instance, '(a [, b])' if b is marked as optional
|
|
662 |
-- with @param[opt] b
|
|
663 |
local buffer, npending = { }, 0
|
|
664 |
local function acc(x) table.insert(buffer, x) end
|
|
665 |
for i = 1, #names do
|
|
666 |
local m = pmods and pmods[i]
|
|
667 |
if m then
|
|
668 |
if not m.optchain then
|
|
669 |
acc ((']'):rep(npending))
|
|
670 |
npending=0
|
|
671 |
end
|
|
672 |
if m.opt or m.optchain then acc(' ['); npending=npending+1 end
|
|
673 |
end
|
|
674 |
if i>1 then acc (', ') end
|
|
675 |
acc(names[i])
|
|
676 |
end
|
|
677 |
acc ((']'):rep(npending))
|
|
678 |
return '('..table.concat(buffer)..')'
|
647 | 679 |
end
|
648 | 680 |
|
649 | 681 |
function Item:type_of_param(p)
|
|
656 | 688 |
function Item:type_of_ret(idx)
|
657 | 689 |
local rparam = self.modifiers['return'][idx]
|
658 | 690 |
return rparam and rparam.type or ''
|
|
691 |
end
|
|
692 |
|
|
693 |
function Item:subparam(p)
|
|
694 |
if self.subparams[p] then
|
|
695 |
return self.subparams[p],p
|
|
696 |
else
|
|
697 |
return {p},nil
|
|
698 |
end
|
|
699 |
end
|
|
700 |
|
|
701 |
function Item:display_name_of(p)
|
|
702 |
local pname,field = split_iden(p)
|
|
703 |
if field then
|
|
704 |
return field
|
|
705 |
else
|
|
706 |
return pname
|
|
707 |
end
|
659 | 708 |
end
|
660 | 709 |
|
661 | 710 |
|
|
673 | 722 |
end
|
674 | 723 |
|
675 | 724 |
Module.warning, Module.error = Item.warning, Item.error
|
|
725 |
|
|
726 |
|
|
727 |
-------- Resolving References -----------------
|
676 | 728 |
|
677 | 729 |
function Module:hunt_for_reference (packmod, modules)
|
678 | 730 |
local mod_ref
|