#!/usr/bin/ruby
$script_call = $0 + " " + ARGV.join(" ")
$indirs = [ "src/drc/drc/built-in-macros", "src/lvs/lvs/built-in-macros" ]
$loc = "about"
$outfiles = "src/lay/lay/doc"
def create_ref(mod, s)
if s =~ /(.*)::(.*)#(.*)/
"#{s}"
elsif s =~ /(.*)::(.*)/
"#{s}"
elsif s =~ /(.*)#(.*)/
if $2 != ""
"#{s}"
else
"#{$1}"
end
else
"#{s}"
end
end
def create_class_doc_ref(s)
"#{s}"
end
def escape(mod, s)
s.gsub("&", "&").
gsub("<", "<").
gsub(">", ">").
gsub(/\\([\w:#]+)/) { create_ref(mod, $1) }.
gsub(/RBA::([\w#]+)/) { create_class_doc_ref($1) }
end
def unescape(s)
s.gsub("&", "&").gsub("<", "<").gsub(">", ">")
end
class DocItem
attr_accessor :brief
attr_accessor :synopsis
attr_accessor :name
attr_accessor :doc
attr_accessor :mod
def initialize(mod, block)
@paragraphs = []
para = nil
self.synopsis = []
self.mod = mod
in_code = false
block.each do |b|
if in_code
if b =~ /@\/code/
in_code = false
end
para.push(b)
elsif b =~ /^@brief\s+(.*?)\s*$/
self.brief = $1
elsif b =~ /^@name\s+(.*?)\s*$/
self.name = $1
elsif b =~ /^@synopsis\s+(.*?)\s*$/
self.synopsis.push($1)
elsif b =~ /^@scope/
# ignore scope commands
elsif b =~ /^\s*$/
para && @paragraphs.push(para)
para = nil
else
para ||= []
para.push(b)
if b =~ /@code/
in_code = true
end
end
end
self.name || raise("Doc block without name")
para && @paragraphs.push(para)
end
def produce_doc
if @paragraphs.empty?
return ""
end
doc = "
\n"
@paragraphs.each_with_index do |p, i|
i > 0 && doc += "
\n"
p.each do |pp|
doc += escape(self.mod, pp).
gsub(/\\@/, "&at;").
gsub(/\s*@code\s*/, "
").
gsub(/\s*@\/code\s*/, "").
gsub(/@img\((.*)\)\s*/) { "
" }.
gsub(/@\/img\s*/, "").
gsub(/@(\w+)\s*/) { "<" + $1 + ">" }.
gsub(/@\/(\w+)\s*/) { "" + $1 + ">" }.
gsub(/&at;/, "@")
doc += "\n"
end
end
doc += "\n"
end
end
class Scope < DocItem
def initialize(mod, block)
super(mod, block)
@items = {}
end
def merge(other)
if !self.brief
self.brief = other.brief
self.doc = other.doc
self.synopsis = other.synopsis
end
end
def add_doc_item(mod, block)
item = DocItem::new(mod, block)
@items[item.name] = item
end
alias :super_produce_doc :produce_doc
def produce_doc
doc = <
HEAD
doc += "\n"
doc += "" + escape(self.mod, self.brief) + "\n"
doc += "\n"
doc += super_produce_doc
doc += "\n"
@items.keys.sort.each do |item_key|
item = @items[item_key]
item.name || raise("Missing @name for item #{item_key}")
item.brief || raise("Missing @brief for item #{item_key}")
doc += ""
doc += "\"" + escape(self.mod, item.name) + "\" - " + escape(self.mod, item.brief) + "
\n"
doc += "\n"
if ! item.synopsis.empty?
doc += "Usage:
\n"
doc += "\n"
item.synopsis.each do |s|
doc += "- " + escape(self.mod, s) + "
\n"
end
doc += "
\n"
end
doc += item.produce_doc
end
doc += "\n"
doc
end
end
class Collector
def initialize(mod, title)
@mod = mod
@title = title
end
def add_block(block)
if block.find { |l| l =~ /^@scope/ }
# is a scope block
@scopes ||= {}
scope = Scope::new(@mod, block)
if ! @scopes[scope.name]
@current_scope = scope
@scopes[scope.name] = scope
else
@current_scope = @scopes[scope.name]
@current_scope.merge(scope)
end
else
@current_scope && @current_scope.add_doc_item(@mod, block)
end
end
def produce_doc
@scopes.keys.sort.each do |k|
suffix = k.downcase
outfile = $outfiles + "/" + $loc + "/" + @mod + "_ref_" + suffix + ".xml"
File.open(outfile, "w") do |file|
file.write(@scopes[k].produce_doc)
puts "---> #{outfile} written."
end
end
end
def produce_index
outfile = $outfiles + "/" + $loc + "/" + @mod + "_ref.xml"
File.open(outfile, "w") do |file|
doc = <
HEAD
doc += "\n"
doc += "#{escape(@mod, @title)}\n"
doc += "\n"
doc += "\n"
@scopes.keys.sort.each do |k|
suffix = k.downcase
doc += "\n"
end
doc += "\n"
doc += "\n"
file.write(doc)
end
puts "---> Index file #{outfile} written."
end
end
collectors = {
"DRC" => Collector::new("drc", "DRC Reference"),
"LVS" => Collector::new("lvs", "LVS Reference")
}
$indirs.each do |indir|
Dir.entries(indir).each do |p|
if p !~ /\.rb$/
next
end
infile = File.join(indir, p)
puts "Extracting doc from #{infile} .."
File.open(infile, "r") do |file|
block = []
collector = nil
line = 0
file.each_line do |l|
line += 1
begin
l = unescape(l)
if ! collector
collectors.each do |k,c|
if l =~ /^\s*#\s*%#{k}%/
collector = c
l = nil
block = []
break
end
end
end
if l
if l =~ /^\s*#\s*(.*)\s*$/
collector && block.push($1)
elsif l =~ /^\s*$/
collector && collector.add_block(block)
collector = nil
end
end
rescue => ex
puts "ERROR in line #{line}:\n" + ex.to_s
puts ex.backtrace # @@@
exit 1
end
end
end
end
end
collectors.each do |k,collector|
collector.produce_doc
collector.produce_index
end