234 lines
6.6 KiB
Ruby
234 lines
6.6 KiB
Ruby
class Generator
|
|
def self.filter_key
|
|
nil
|
|
end
|
|
|
|
def initialize
|
|
@type_size_map = {
|
|
"uint8_t" => 1,
|
|
"uint16_t" => 2,
|
|
"uint32_t" => 4,
|
|
"uint64_t" => 8,
|
|
"int8_t" => 1,
|
|
"int16_t" => 2,
|
|
"int32_t" => 4,
|
|
"int64_t" => 8,
|
|
"char" => 1,
|
|
"Point" => 4,
|
|
"ProcPtr" => 8,
|
|
"void" => 0,
|
|
"double" => 8
|
|
}
|
|
@fancy_comments = false
|
|
@expand_common = true
|
|
end
|
|
def size_of_type(type)
|
|
return nil if not type
|
|
return @type_size_map[type] if @type_size_map[type]
|
|
return 4 if type =~ /[*\[\]]/
|
|
return nil
|
|
end
|
|
|
|
def starredtext(str, align, lchar:'*', rchar:'*')
|
|
maxlinelen = str.lines.map{|s| s.rstrip.length}.max
|
|
|
|
str.each_line do |s|
|
|
s.rstrip!
|
|
c = (75 - s.length)
|
|
b = case align
|
|
when "center" then c/2
|
|
when "left" then c - 1
|
|
when "right" then 1
|
|
end
|
|
a = c - b
|
|
a = 0 if a < 0
|
|
b = 0 if b < 0
|
|
@out << " #{lchar}#{' '*a}#{s}#{' '*b}#{rchar}\n"
|
|
end
|
|
|
|
end
|
|
|
|
def starline
|
|
@out << "/#{'*'*77}/\n"
|
|
end
|
|
|
|
def box(title, comment=nil, order:1)
|
|
if title or comment then
|
|
@out << "/#{'*'*77}\n"
|
|
#print " *#{' '*75}*\n"
|
|
starredtext(title, 'center') if title
|
|
@out << " *#{' '*75}*\n" if title and comment
|
|
starredtext(comment, 'left') if comment
|
|
|
|
@out << " #{'*'*77}/\n"
|
|
else
|
|
starline
|
|
end
|
|
end
|
|
|
|
|
|
def document_dependencies(header)
|
|
out = ""
|
|
if header.included.size > 0 then
|
|
out << "Needs:\n"
|
|
|
|
colwidth = header.included.map(&:size).max + 4 + 2 + 4
|
|
maxlinelen = 70
|
|
|
|
header.included.each do |inc|
|
|
line = " " * 4 + inc + ".h"
|
|
line << " " * (colwidth - line.length)
|
|
indent = line.length
|
|
whys = header.included_why[inc].to_a
|
|
whys.each_index do |idx|
|
|
why = whys[idx]
|
|
last = (idx == whys.size - 1)
|
|
if line.length + why.size + (last ? 0 : 1) > maxlinelen
|
|
out << line << "\n"
|
|
line = " " * indent
|
|
end
|
|
line << why
|
|
line << ", " unless last
|
|
end
|
|
out << line << "\n"
|
|
end
|
|
end
|
|
return out
|
|
end
|
|
|
|
def declare_members(members)
|
|
members.each do |member|
|
|
sub = (member["struct"] or member["union"])
|
|
if sub then
|
|
@out << (if member["struct"] then "struct" else "union" end) << "{"
|
|
declare_members sub
|
|
@out << "} " << member["name"] << ";"
|
|
elsif member["common"]
|
|
if @expand_common then
|
|
declare_members($global_name_map[member["common"]]["common"]["members"])
|
|
else
|
|
@out << member["common"] << ";"
|
|
end
|
|
else
|
|
@out << decl(member["type"], member["name"]) << ";"
|
|
@out << " // " << member["comment"].rstrip << "\n" if member["comment"]
|
|
end
|
|
end
|
|
end
|
|
|
|
def convert_expression(expr)
|
|
return expr
|
|
end
|
|
|
|
def declare_enum(value)
|
|
@out << "typedef " if value["name"]
|
|
@out << "enum {"
|
|
value["values"].each do |val|
|
|
@out << val["name"]
|
|
if val["value"] then
|
|
@out << " = " << convert_expression(val["value"].to_s) << ","
|
|
else
|
|
@out << ","
|
|
end
|
|
@out << " // " << val["comment"].rstrip if val["comment"]
|
|
@out << "\n"
|
|
end
|
|
@out << "}"
|
|
@out << value["name"] if value["name"]
|
|
@out << ";"
|
|
end
|
|
|
|
def declare_typedef(value)
|
|
@out << "typedef "
|
|
@out << decl(value["type"], value["name"])
|
|
@out << ";"
|
|
|
|
sz = size_of_type(value["type"])
|
|
@type_size_map[value["name"]] = sz if sz
|
|
end
|
|
|
|
def generate_preamble(header)
|
|
title = "\n" + header.name + ".h\n" + "="*(header.name.length+2) + "\n"
|
|
titlecomment = nil
|
|
if header.included.size > 0 then
|
|
titlecomment = document_dependencies(header)
|
|
titlecomment << "\n\n"
|
|
else
|
|
title << "\n"
|
|
end
|
|
box(title, titlecomment)
|
|
@out << "\n\n"
|
|
end
|
|
def generate_postamble(header)
|
|
end
|
|
def generate_comment(key, value)
|
|
if @fancy_comments then
|
|
box(value["name"], value["comment"])
|
|
else
|
|
return unless value["comment"]
|
|
value["comment"].each_line do |l|
|
|
@out << "// " << l.rstrip << "\n"
|
|
end
|
|
end
|
|
end
|
|
|
|
def declare_executor_only(value)
|
|
end
|
|
|
|
def generate_header(header)
|
|
@out = ""
|
|
@impl_out = ""
|
|
|
|
generate_preamble(header)
|
|
|
|
header.data.each do |item|
|
|
key, value = first_elem(item)
|
|
generate_comment(key, value)
|
|
|
|
case key
|
|
when "enum"
|
|
declare_enum(value)
|
|
|
|
when "struct", "union"
|
|
declare_struct_union(key, value)
|
|
|
|
when "dispatcher"
|
|
declare_dispatcher(value)
|
|
|
|
when "typedef"
|
|
declare_typedef(value)
|
|
|
|
when "function"
|
|
declare_function(value)
|
|
|
|
when "lowmem"
|
|
declare_lowmem(value)
|
|
|
|
when "funptr"
|
|
declare_funptr(value)
|
|
|
|
when "executor_only"
|
|
declare_executor_only(value)
|
|
end
|
|
|
|
@out << "\n\n"
|
|
end
|
|
generate_postamble(header)
|
|
return @out
|
|
end
|
|
|
|
def formatted_file(name, &block)
|
|
if not @format_command then
|
|
if system('which clang-format > /dev/null') then
|
|
@format_command = "clang-format | grep -v \"// clang-format o\""
|
|
elsif system('which uncrustify > /dev/null') then
|
|
@format_command = "uncrustify -q -c uncrustify.cfg | grep -v \"// clang-format o\""
|
|
elsif system('which astyle > /dev/null') then
|
|
@format_command = "astyle --style=allman --max-code-length=79 --mode=c | grep -v \"// clang-format o\""
|
|
else
|
|
@format_command = "grep -v \"// clang-format o\""
|
|
end
|
|
end
|
|
IO.popen("#{@format_command} > \"#{name}\"", "w", &block)
|
|
end
|
|
end
|