lib/webidl/generator/ruby_sexp_visitor.rb
module WebIDL
class RubySexpVisitor
def visit_module(mod)
[:block,
[:module, classify(mod.name),
[:scope,
[:block] + mod.definitions.map { |d| d.accept(self) }
]
]
]
end
def visit_interface(intf)
[:module, classify(intf.name),
([:scope, [:block] + intf.inherits.map { |inherit| [:call, nil, :include, [:arglist, inherit.accept(self)]] }] unless intf.inherits.empty?),
[:scope,
[:block] + intf.members.map { |m| m.accept(self) }
]
].compact
end
def visit_dictionary(dict)
[:module, classify(dict.name),
([:scope, [:block] + dict.inherits.map { |inherit| [:call, nil, :include, [:arglist, inherit.accept(self)]] }] unless dict.inherits.empty?),
[:scope,
[:block] + dict.members.map { |m| m.accept(self) }
]
].compact
end
def visit_exception(ex)
[:class, classify(ex.name), [:const, :StandardError],
[:scope,
[:block] + ex.members.map { |m| m.accept(self)}
]
]
end
def visit_const(const)
[:cdecl, const.name, [:lit, const.value]] # FIXME: won't always be literals - need Literal AST node?
end
def visit_enum(enum)
[:cdecl, enum.name, [:lit, enum.values]]
end
def visit_field(field)
[:call, nil, :attr_accessor, [:arglist, [:lit, field.name.to_sym]]]
end
def visit_attribute(attribute)
func = attribute.readonly? ? :attr_reader : :attr_accessor
[:call, nil, func, [:arglist, [:lit, attrify(attribute.name).to_sym]]]
end
def visit_dictionary_member(mem)
[:call, nil, :attr_accessor, [:arglist, [:lit, attrify(mem.name).to_sym]]]
end
def visit_callback(callback)
arguments = callback.arguments.map { |a| [:lit, attrify(a.name).to_sym] }
[:defn, callback.name,
[:args] + callback.arguments.map { |a| a.accept(self) },
[:scope,
[:block,
[:call, nil, :raise,
[:arglist,
[:const, :NotImplementedError]
]
]
]
]
]
end
def visit_operation(operation)
if operation.name.empty?
if operation.setter?
meth = :[]=
elsif operation.getter?
meth = :[]
elsif operation.creator?
meth = :initialize
elsif operation.stringifier?
meth = :to_s
elsif operation.deleter?
meth = :delete!
elsif operation.legacycaller?
meth = operation.parent.name
else
raise "no name for operation #{operation.inspect}"
end
else
meth = attrify(operation.name)
meth << "=" if operation.setter?
end
[:defn, meth.to_sym,
[:args] + operation.args.map { |a| a.accept(self) },
[:scope,
[:block,
[:call, nil, :raise,
[:arglist,
[:const, :NotImplementedError]
]
]
]
]
]
end
def visit_argument(argument)
name = attrify(argument.name)
arg = argument.variadic? ? "*#{name}" : name
arg.to_sym
end
def visit_type_def(typedef)
# don't care
end
def visit_implements_statement(impls)
[:module, classify(impls.implementor),
[:scope,
[:call, nil, :include,
[:arglist,
[:const, classify(impls.implementee)]
]
]
]
]
end
def visit_includes_statement(incls)
[:module, classify(incls.includer),
[:scope,
[:call, nil, :include,
[:arglist,
[:const, classify(impls.includee)]
]
]
]
]
end
def visit_scoped_name(sn)
[:const, classify(sn.qualified_name)]
end
private
def classify(string)
s = string.to_s
if s.include?("::")
s.split("::").map { |e| classify(e) unless e.empty? }.compact.join("::").to_sym
else
"#{s.slice(0,1).upcase}#{s[1..-1]}".to_sym
end
end
RESERVED = %w[
BEGIN do next then
END else nil true
alias elsif not undef
and end or unless
begin ensure redo until
break false rescue when
case for retry while
class if return while
def in self __FILE__
defined? module super __LINE__
]
def attrify(string)
attr = string.snake_case
attr += '_' if RESERVED.include?(attr)
attr
end
end # RubySexpVisitor
end # WebIDL