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.
Files changed (74) hide show
  1. data/.autotest +9 -0
  2. data/.document +5 -0
  3. data/.gitignore +5 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +31 -0
  6. data/Rakefile +65 -0
  7. data/VERSION +1 -0
  8. data/bin/webidl2ruby +13 -0
  9. data/examples/html5.rb +6 -0
  10. data/lib/webidl.rb +47 -0
  11. data/lib/webidl/ast/argument.rb +25 -0
  12. data/lib/webidl/ast/attribute.rb +29 -0
  13. data/lib/webidl/ast/const.rb +17 -0
  14. data/lib/webidl/ast/exception.rb +15 -0
  15. data/lib/webidl/ast/extended_attribute.rb +14 -0
  16. data/lib/webidl/ast/field.rb +14 -0
  17. data/lib/webidl/ast/implements_statement.rb +14 -0
  18. data/lib/webidl/ast/interface.rb +24 -0
  19. data/lib/webidl/ast/module.rb +17 -0
  20. data/lib/webidl/ast/node.rb +29 -0
  21. data/lib/webidl/ast/operation.rb +43 -0
  22. data/lib/webidl/ast/scoped_name.rb +28 -0
  23. data/lib/webidl/ast/type.rb +20 -0
  24. data/lib/webidl/ast/typedef.rb +15 -0
  25. data/lib/webidl/extensions/string.rb +22 -0
  26. data/lib/webidl/extensions/syntax_node.rb +5 -0
  27. data/lib/webidl/generator.rb +38 -0
  28. data/lib/webidl/generator/ruby_sexp_visitor.rb +118 -0
  29. data/lib/webidl/parse_tree/absolute_scoped_name.rb +11 -0
  30. data/lib/webidl/parse_tree/argument.rb +20 -0
  31. data/lib/webidl/parse_tree/argument_list.rb +14 -0
  32. data/lib/webidl/parse_tree/attribute.rb +17 -0
  33. data/lib/webidl/parse_tree/const.rb +9 -0
  34. data/lib/webidl/parse_tree/definitions.rb +25 -0
  35. data/lib/webidl/parse_tree/exception.rb +15 -0
  36. data/lib/webidl/parse_tree/exception_field.rb +11 -0
  37. data/lib/webidl/parse_tree/extended_attributes.rb +41 -0
  38. data/lib/webidl/parse_tree/implements_statement.rb +20 -0
  39. data/lib/webidl/parse_tree/interface.rb +21 -0
  40. data/lib/webidl/parse_tree/interface_inheritance.rb +11 -0
  41. data/lib/webidl/parse_tree/interface_members.rb +21 -0
  42. data/lib/webidl/parse_tree/module.rb +15 -0
  43. data/lib/webidl/parse_tree/nullable_type.rb +11 -0
  44. data/lib/webidl/parse_tree/operation.rb +30 -0
  45. data/lib/webidl/parse_tree/relative_scoped_name.rb +15 -0
  46. data/lib/webidl/parse_tree/scoped_name_list.rb +16 -0
  47. data/lib/webidl/parse_tree/specials.rb +17 -0
  48. data/lib/webidl/parse_tree/stringifier_attribute_or_operation.rb +16 -0
  49. data/lib/webidl/parse_tree/typedef.rb +11 -0
  50. data/lib/webidl/parser/debug_helper.rb +17 -0
  51. data/lib/webidl/parser/idl.treetop +369 -0
  52. data/spec/ast_spec.rb +218 -0
  53. data/spec/fixtures/empty_interface.idl +3 -0
  54. data/spec/fixtures/empty_module.idl +3 -0
  55. data/spec/fixtures/framework.idl +48 -0
  56. data/spec/fixtures/html5.idl +1440 -0
  57. data/spec/fixtures/interface_with_attribute.idl +7 -0
  58. data/spec/fixtures/interface_with_inheritance.idl +9 -0
  59. data/spec/fixtures/interface_with_members.idl +5 -0
  60. data/spec/fixtures/interface_with_stringifiers.idl +5 -0
  61. data/spec/fixtures/module_with_exception.idl +13 -0
  62. data/spec/fixtures/module_with_implements_statement.idl +6 -0
  63. data/spec/fixtures/module_with_typedef.idl +4 -0
  64. data/spec/fixtures/module_with_xattr_ident.idl +4 -0
  65. data/spec/fixtures/module_with_xattr_named_args.idl +5 -0
  66. data/spec/fixtures/module_with_xattr_no_arg.idl +5 -0
  67. data/spec/fixtures/module_with_xattr_scoped.idl +4 -0
  68. data/spec/fixtures/module_with_xattr_two_args.idl +4 -0
  69. data/spec/fixtures/nested.idl +4 -0
  70. data/spec/fixtures/websocket.idl +19 -0
  71. data/spec/generator_spec.rb +92 -0
  72. data/spec/parser_spec.rb +64 -0
  73. data/spec/spec_helper.rb +45 -0
  74. 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,15 @@
1
+ module WebIDL
2
+ module Ast
3
+ class TypeDef < Node
4
+
5
+ attr_reader :type, :name
6
+
7
+ def initialize(parent, type, name)
8
+ @parent = parent
9
+ @type = type
10
+ @name = name
11
+ end
12
+
13
+ end # TypeDef
14
+ end # Ast
15
+ 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,5 @@
1
+ class Treetop::Runtime::SyntaxNode
2
+ def any?
3
+ !empty?
4
+ end
5
+ 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,11 @@
1
+ module WebIDL
2
+ module ParseTree
3
+ class AbsoluteScopedName < Treetop::Runtime::SyntaxNode
4
+
5
+ def build(parent)
6
+ raise NotImplementedError
7
+ end
8
+
9
+ end # RelativeScopedName
10
+ end # ParseTree
11
+ 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,9 @@
1
+ module WebIDL
2
+ module ParseTree
3
+ class Const < Treetop::Runtime::SyntaxNode
4
+ def build(parent)
5
+ Ast::Const.new(parent, type.build(parent), name.text_value, const_expr.build)
6
+ end
7
+ end # Const
8
+ end # ParseTree
9
+ 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,11 @@
1
+ module WebIDL
2
+ module ParseTree
3
+ class ExceptionField < Treetop::Runtime::SyntaxNode
4
+
5
+ def build(parent)
6
+ Ast::Field.new(parent, type.build(parent), id.text_value)
7
+ end
8
+
9
+ end # ExceptionField
10
+ end # ParseTree
11
+ 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