webidl 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +9 -0
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +31 -0
- data/Rakefile +65 -0
- data/VERSION +1 -0
- data/bin/webidl2ruby +13 -0
- data/examples/html5.rb +6 -0
- data/lib/webidl.rb +47 -0
- data/lib/webidl/ast/argument.rb +25 -0
- data/lib/webidl/ast/attribute.rb +29 -0
- data/lib/webidl/ast/const.rb +17 -0
- data/lib/webidl/ast/exception.rb +15 -0
- data/lib/webidl/ast/extended_attribute.rb +14 -0
- data/lib/webidl/ast/field.rb +14 -0
- data/lib/webidl/ast/implements_statement.rb +14 -0
- data/lib/webidl/ast/interface.rb +24 -0
- data/lib/webidl/ast/module.rb +17 -0
- data/lib/webidl/ast/node.rb +29 -0
- data/lib/webidl/ast/operation.rb +43 -0
- data/lib/webidl/ast/scoped_name.rb +28 -0
- data/lib/webidl/ast/type.rb +20 -0
- data/lib/webidl/ast/typedef.rb +15 -0
- data/lib/webidl/extensions/string.rb +22 -0
- data/lib/webidl/extensions/syntax_node.rb +5 -0
- data/lib/webidl/generator.rb +38 -0
- data/lib/webidl/generator/ruby_sexp_visitor.rb +118 -0
- data/lib/webidl/parse_tree/absolute_scoped_name.rb +11 -0
- data/lib/webidl/parse_tree/argument.rb +20 -0
- data/lib/webidl/parse_tree/argument_list.rb +14 -0
- data/lib/webidl/parse_tree/attribute.rb +17 -0
- data/lib/webidl/parse_tree/const.rb +9 -0
- data/lib/webidl/parse_tree/definitions.rb +25 -0
- data/lib/webidl/parse_tree/exception.rb +15 -0
- data/lib/webidl/parse_tree/exception_field.rb +11 -0
- data/lib/webidl/parse_tree/extended_attributes.rb +41 -0
- data/lib/webidl/parse_tree/implements_statement.rb +20 -0
- data/lib/webidl/parse_tree/interface.rb +21 -0
- data/lib/webidl/parse_tree/interface_inheritance.rb +11 -0
- data/lib/webidl/parse_tree/interface_members.rb +21 -0
- data/lib/webidl/parse_tree/module.rb +15 -0
- data/lib/webidl/parse_tree/nullable_type.rb +11 -0
- data/lib/webidl/parse_tree/operation.rb +30 -0
- data/lib/webidl/parse_tree/relative_scoped_name.rb +15 -0
- data/lib/webidl/parse_tree/scoped_name_list.rb +16 -0
- data/lib/webidl/parse_tree/specials.rb +17 -0
- data/lib/webidl/parse_tree/stringifier_attribute_or_operation.rb +16 -0
- data/lib/webidl/parse_tree/typedef.rb +11 -0
- data/lib/webidl/parser/debug_helper.rb +17 -0
- data/lib/webidl/parser/idl.treetop +369 -0
- data/spec/ast_spec.rb +218 -0
- data/spec/fixtures/empty_interface.idl +3 -0
- data/spec/fixtures/empty_module.idl +3 -0
- data/spec/fixtures/framework.idl +48 -0
- data/spec/fixtures/html5.idl +1440 -0
- data/spec/fixtures/interface_with_attribute.idl +7 -0
- data/spec/fixtures/interface_with_inheritance.idl +9 -0
- data/spec/fixtures/interface_with_members.idl +5 -0
- data/spec/fixtures/interface_with_stringifiers.idl +5 -0
- data/spec/fixtures/module_with_exception.idl +13 -0
- data/spec/fixtures/module_with_implements_statement.idl +6 -0
- data/spec/fixtures/module_with_typedef.idl +4 -0
- data/spec/fixtures/module_with_xattr_ident.idl +4 -0
- data/spec/fixtures/module_with_xattr_named_args.idl +5 -0
- data/spec/fixtures/module_with_xattr_no_arg.idl +5 -0
- data/spec/fixtures/module_with_xattr_scoped.idl +4 -0
- data/spec/fixtures/module_with_xattr_two_args.idl +4 -0
- data/spec/fixtures/nested.idl +4 -0
- data/spec/fixtures/websocket.idl +19 -0
- data/spec/generator_spec.rb +92 -0
- data/spec/parser_spec.rb +64 -0
- data/spec/spec_helper.rb +45 -0
- metadata +161 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
module WebIDL
|
2
|
+
module Ast
|
3
|
+
class ScopedName < Node
|
4
|
+
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(parent, name, opts = {})
|
8
|
+
super(parent)
|
9
|
+
|
10
|
+
@name = name
|
11
|
+
@relative = !!opts[:relative]
|
12
|
+
end
|
13
|
+
|
14
|
+
def qualified_name
|
15
|
+
if relative? && @parent
|
16
|
+
"#{@parent.qualified_name}::#{@name}"
|
17
|
+
else
|
18
|
+
"::#{@name}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def relative?
|
23
|
+
@relative
|
24
|
+
end
|
25
|
+
|
26
|
+
end # ScopedName
|
27
|
+
end # Ast
|
28
|
+
end # WebIDL
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module WebIDL
|
2
|
+
module Ast
|
3
|
+
class Type < Node
|
4
|
+
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(parent, name, opts = {})
|
8
|
+
super(parent)
|
9
|
+
|
10
|
+
@name = name.strip.to_sym
|
11
|
+
@nullable = !!opts[:nullable]
|
12
|
+
end
|
13
|
+
|
14
|
+
def nullable?
|
15
|
+
@nullable
|
16
|
+
end
|
17
|
+
|
18
|
+
end # Type
|
19
|
+
end # Ast
|
20
|
+
end # WebIDL
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class String
|
2
|
+
#
|
3
|
+
# Convert from camel case to snake case
|
4
|
+
#
|
5
|
+
# 'FooBar'.snake_case # => "foo_bar"
|
6
|
+
#
|
7
|
+
|
8
|
+
def snake_case
|
9
|
+
gsub(/\B[A-Z][^A-Z]/, '_\&').downcase.gsub(' ', '_')
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# Convert from snake case to camel case
|
14
|
+
#
|
15
|
+
# 'foo_bar'.camel_case # => "FooBar"
|
16
|
+
#
|
17
|
+
|
18
|
+
def camel_case
|
19
|
+
split('_').map { |e| e.capitalize }.join
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "webidl/generator/ruby_sexp_visitor"
|
2
|
+
module WebIDL
|
3
|
+
class Generator
|
4
|
+
|
5
|
+
class ParseError < StandardError; end
|
6
|
+
|
7
|
+
def initialize(visitor = nil)
|
8
|
+
@visitor = visitor
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate(str)
|
12
|
+
parse_tree = parser.parse(str)
|
13
|
+
|
14
|
+
if parse_tree.nil?
|
15
|
+
raise ParseError, parser.failure_reason
|
16
|
+
end
|
17
|
+
|
18
|
+
ast_defs = parse_tree.build
|
19
|
+
strings = ast_defs.map { |definition| ruby2ruby.process definition.accept(visitor) }
|
20
|
+
strings.join("\n\n")
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def ruby2ruby
|
26
|
+
@ruby2ruby ||= Ruby2Ruby.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def parser
|
30
|
+
@parser ||= WebIDL::Parser::IDLParser.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def visitor
|
34
|
+
@visitor ||= RubySexpVisitor.new
|
35
|
+
end
|
36
|
+
|
37
|
+
end # Generator
|
38
|
+
end # WebIDL
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module WebIDL
|
2
|
+
class RubySexpVisitor
|
3
|
+
|
4
|
+
def visit_module(mod)
|
5
|
+
[:block,
|
6
|
+
[:module, classify(mod.name),
|
7
|
+
[:scope,
|
8
|
+
[:block] + mod.definitions.map { |d| d.accept(self) }
|
9
|
+
]
|
10
|
+
]
|
11
|
+
]
|
12
|
+
end
|
13
|
+
|
14
|
+
def visit_interface(intf)
|
15
|
+
[:module, classify(intf.name),
|
16
|
+
([:scope, [:block] + intf.inherits.map { |inherit| [:call, nil, :include, [:arglist, inherit.accept(self)]] }] unless intf.inherits.empty?),
|
17
|
+
[:scope,
|
18
|
+
[:block] + intf.members.map { |m| m.accept(self) }
|
19
|
+
]
|
20
|
+
].compact
|
21
|
+
end
|
22
|
+
|
23
|
+
def visit_exception(ex)
|
24
|
+
[:class, classify(ex.name), [:const, :StandardError],
|
25
|
+
[:scope,
|
26
|
+
[:block] + ex.members.map { |m| m.accept(self)}
|
27
|
+
]
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
def visit_const(const)
|
32
|
+
[:cdecl, const.name, [:lit, const.value]] # FIXME: won't always be literals - need Literal AST node?
|
33
|
+
end
|
34
|
+
|
35
|
+
def visit_field(field)
|
36
|
+
[:call, nil, :attr_accessor, [:arglist, [:lit, field.name.to_sym]]]
|
37
|
+
end
|
38
|
+
|
39
|
+
def visit_attribute(attribute)
|
40
|
+
func = attribute.readonly? ? :attr_reader : :attr_accessor
|
41
|
+
[:call, nil, func, [:arglist, [:lit, attribute.name.snake_case.to_sym]]]
|
42
|
+
end
|
43
|
+
|
44
|
+
def visit_operation(operation)
|
45
|
+
if operation.name.empty?
|
46
|
+
if operation.setter?
|
47
|
+
meth = :[]=
|
48
|
+
elsif operation.getter?
|
49
|
+
meth = :[]
|
50
|
+
elsif operation.creator?
|
51
|
+
meth = :initialize
|
52
|
+
elsif operation.stringifier?
|
53
|
+
meth = :to_s
|
54
|
+
elsif operation.deleter?
|
55
|
+
meth = :delete!
|
56
|
+
else
|
57
|
+
raise "no name for operation #{operation.pretty_inspect}"
|
58
|
+
end
|
59
|
+
else
|
60
|
+
meth = operation.name.snake_case
|
61
|
+
meth << "=" if operation.setter?
|
62
|
+
end
|
63
|
+
|
64
|
+
[:defn, meth.to_sym,
|
65
|
+
[:args] + operation.args.map { |a| a.accept(self) },
|
66
|
+
[:scope,
|
67
|
+
[:block,
|
68
|
+
[:call, nil, :raise,
|
69
|
+
[:arglist,
|
70
|
+
[:const, :NotImplementedError]
|
71
|
+
]
|
72
|
+
]
|
73
|
+
]
|
74
|
+
]
|
75
|
+
]
|
76
|
+
end
|
77
|
+
|
78
|
+
def visit_argument(argument)
|
79
|
+
name = argument.name.snake_case
|
80
|
+
arg = argument.variadic? ? "*#{name}" : name
|
81
|
+
|
82
|
+
arg.to_sym
|
83
|
+
end
|
84
|
+
|
85
|
+
def visit_type_def(typedef)
|
86
|
+
# don't care
|
87
|
+
end
|
88
|
+
|
89
|
+
def visit_implements_statement(impls)
|
90
|
+
[:module, classify(impls.implementor),
|
91
|
+
[:scope,
|
92
|
+
[:call, nil, :include,
|
93
|
+
[:arglist,
|
94
|
+
[:const, classify(impls.implementee)]
|
95
|
+
]
|
96
|
+
]
|
97
|
+
]
|
98
|
+
]
|
99
|
+
end
|
100
|
+
|
101
|
+
def visit_scoped_name(sn)
|
102
|
+
[:const, classify(sn.qualified_name)]
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def classify(string)
|
108
|
+
s = string.to_s
|
109
|
+
|
110
|
+
if s.include?("::")
|
111
|
+
s.split("::").map { |e| classify(e) unless e.empty? }.compact.join("::").to_sym
|
112
|
+
else
|
113
|
+
"#{s.slice(0,1).upcase}#{s[1..-1]}".to_sym
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end # RubySexpVisitor
|
118
|
+
end # WebIDL
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module WebIDL
|
2
|
+
module ParseTree
|
3
|
+
class Argument < Treetop::Runtime::SyntaxNode
|
4
|
+
|
5
|
+
def build(parent)
|
6
|
+
arg = Ast::Argument.new(
|
7
|
+
id.build,
|
8
|
+
type.build(parent),
|
9
|
+
:optional => optional.any?,
|
10
|
+
:variadic => variadic.any?
|
11
|
+
)
|
12
|
+
|
13
|
+
arg.extended_attributes = eal.build unless eal.empty?
|
14
|
+
|
15
|
+
arg
|
16
|
+
end
|
17
|
+
|
18
|
+
end # Argument
|
19
|
+
end # ParseTree
|
20
|
+
end # WebIDL
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module WebIDL
|
2
|
+
module ParseTree
|
3
|
+
class ArgumentList < Treetop::Runtime::SyntaxNode
|
4
|
+
|
5
|
+
def build(parent)
|
6
|
+
list = [arg.build(parent)]
|
7
|
+
list += args.build(parent) unless args.empty?
|
8
|
+
|
9
|
+
list
|
10
|
+
end
|
11
|
+
|
12
|
+
end # ArgumentList
|
13
|
+
end # ParseTree
|
14
|
+
end # WebIDL
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module WebIDL
|
2
|
+
module ParseTree
|
3
|
+
class Attribute < Treetop::Runtime::SyntaxNode
|
4
|
+
|
5
|
+
def build(parent)
|
6
|
+
options = {
|
7
|
+
:readonly => readonly.any?,
|
8
|
+
:getraises => (getraises.build unless getraises.empty?),
|
9
|
+
:setraises => (setraises.build unless setraises.empty?)
|
10
|
+
}
|
11
|
+
|
12
|
+
Ast::Attribute.new parent, type.build(parent), name.build, options
|
13
|
+
end
|
14
|
+
|
15
|
+
end # Attribute
|
16
|
+
end # ParseTree
|
17
|
+
end # WebIDL
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module WebIDL
|
2
|
+
module ParseTree
|
3
|
+
class Definitions < Treetop::Runtime::SyntaxNode
|
4
|
+
|
5
|
+
def build(parent = nil)
|
6
|
+
return [] if metadef.empty?
|
7
|
+
|
8
|
+
unless metadef.d.empty?
|
9
|
+
definition = metadef.d.build(parent)
|
10
|
+
definition.extended_attributes = metadef.eal.build(parent) unless metadef.eal.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
result = [definition]
|
14
|
+
result += metadef.defs.build(parent) unless metadef.defs.empty?
|
15
|
+
|
16
|
+
if parent
|
17
|
+
parent.definitions = result
|
18
|
+
end
|
19
|
+
|
20
|
+
result.compact
|
21
|
+
end
|
22
|
+
|
23
|
+
end # Definitions
|
24
|
+
end # ParseTree
|
25
|
+
end # WebIDL
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module WebIDL
|
2
|
+
module ParseTree
|
3
|
+
class Exception < Treetop::Runtime::SyntaxNode
|
4
|
+
|
5
|
+
def build(parent)
|
6
|
+
ex = Ast::Exception.new(parent, name.text_value)
|
7
|
+
|
8
|
+
members.build(ex) unless members.empty?
|
9
|
+
|
10
|
+
ex
|
11
|
+
end
|
12
|
+
|
13
|
+
end # Exception
|
14
|
+
end # ParseTree
|
15
|
+
end # WebIDL
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module WebIDL
|
2
|
+
module ParseTree
|
3
|
+
|
4
|
+
class ExtendedAttributeList < Treetop::Runtime::SyntaxNode
|
5
|
+
def build(parent)
|
6
|
+
list = [attribute.build(parent)]
|
7
|
+
list += attributes.build(parent) unless attributes.empty?
|
8
|
+
|
9
|
+
list
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ExtendedAttributeArgList < Treetop::Runtime::SyntaxNode
|
14
|
+
def build(parent)
|
15
|
+
unless args.empty?
|
16
|
+
arguments = args.build(parent)
|
17
|
+
end
|
18
|
+
Ast::ExtendedAttribute.new(name.text_value, arguments)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class ExtendedAttributeIdent < Treetop::Runtime::SyntaxNode
|
23
|
+
def build(parent)
|
24
|
+
[key, value].map { |e| e.text_value }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class ExtendedAttributeNamedArgList < Treetop::Runtime::SyntaxNode
|
29
|
+
def build(parent)
|
30
|
+
[key.text_value, value.build(parent)]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class ExtendedAttributeScopedName < Treetop::Runtime::SyntaxNode
|
35
|
+
def build(parent)
|
36
|
+
[key.text_value, scoped_name.build(parent)]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end # ParseTree
|
41
|
+
end # WebIDL
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module WebIDL
|
2
|
+
module ParseTree
|
3
|
+
class ImplementsStatement < Treetop::Runtime::SyntaxNode
|
4
|
+
|
5
|
+
def build(parent)
|
6
|
+
# not sure how this should be handled
|
7
|
+
# currently keep a global list of interfaces, find the implementor and put the implementee in its 'implements' list
|
8
|
+
# perhaps this is too early to do the resolving?
|
9
|
+
implor_name = implementor.build(parent).qualified_name
|
10
|
+
implee_name = implementee.build(parent).qualified_name
|
11
|
+
|
12
|
+
# implor = Ast::Interface.list[implor_name]
|
13
|
+
# implee = Ast::Interface.list[implee_name]
|
14
|
+
|
15
|
+
Ast::ImplementsStatement.new(parent, implor_name, implee_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
end # ImplementsStatement
|
19
|
+
end # ParseTree
|
20
|
+
end # WebIDL
|