Re-landing:
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 19 Aug 2016 02:53:58 +0000 (02:53 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 19 Aug 2016 02:53:58 +0000 (02:53 +0000)
Support WebIDL unions (Part 1)
https://bugs.webkit.org/show_bug.cgi?id=160769

Reviewed by Chris Dumez.

This is the first part of an effort to add support for union types
in our code generators. This change:
- Adds a domType struct to hold the parsed type information. For now, we only
  use it temporarily while parsing, and don't expose it to the code generators,
  but that will change in a later patch.
- Remove support for scoped identifiers for types. They are not supported by WebIDL.
- Make debugging the parser easier by providing backtraces when asserting.

There should be no observable changes.

* bindings/scripts/IDLParser.pm:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@204626 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/bindings/scripts/IDLParser.pm

index 7fc4578..caf56cc 100644 (file)
@@ -1,3 +1,24 @@
+2016-08-18  Sam Weinig  <sam@webkit.org>
+
+        Re-landing:
+
+        Support WebIDL unions (Part 1)
+        https://bugs.webkit.org/show_bug.cgi?id=160769
+
+        Reviewed by Chris Dumez.
+
+        This is the first part of an effort to add support for union types
+        in our code generators. This change:
+        - Adds a domType struct to hold the parsed type information. For now, we only
+          use it temporarily while parsing, and don't expose it to the code generators,
+          but that will change in a later patch.
+        - Remove support for scoped identifiers for types. They are not supported by WebIDL.
+        - Make debugging the parser easier by providing backtraces when asserting.
+
+        There should be no observable changes.
+
+        * bindings/scripts/IDLParser.pm:
+
 2016-08-18  Chris Dumez  <cdumez@apple.com>
 
         Move prefix / namespaceURI / localName attributes from Node to Attr / Element
index ea4d621..db7cecf 100644 (file)
@@ -23,6 +23,9 @@ package IDLParser;
 
 use strict;
 
+use Carp qw<longmess>;
+use Data::Dumper;
+
 use preprocessor;
 use Class::Struct;
 
@@ -74,17 +77,24 @@ struct( domAttribute => {
     signature => '$',         # Attribute signature
 });
 
+struct( domType => {
+    name =>         '$', # Type identifier
+    isNullable =>   '$', # Is the type Nullable (T?)
+    isUnion =>      '$', # Is the type a union (T or U)
+    subtypes =>     '@', # Array of subtypes, only valid if isUnion or sequence
+});
+
 # Used to represent a map of 'variable name' <-> 'variable type'
 struct( domSignature => {
-    direction => '$', # Variable direction (in or out)
-    name => '$',      # Variable name
-    type => '$',      # Variable type
-    specials => '@',  # Specials
+    direction => '$',   # Variable direction (in or out)
+    name => '$',        # Variable name
+    type => '$'      ,  # Variable type
+    specials => '@',    # Specials
     extendedAttributes => '$', # Extended attributes
-    isNullable => '$', # Is variable type Nullable (T?)
-    isVariadic => '$', # Is variable variadic (long... numbers)
-    isOptional => '$', # Is variable optional (optional T)
-    default => '$', # Default value for parameters
+    isNullable => '$',  # Is variable type Nullable (T?)
+    isVariadic => '$',  # Is variable variadic (long... numbers)
+    isOptional => '$',  # Is variable optional (optional T)
+    default => '$',     # Default value for parameters
 });
 
 # Used to represent Iterable interfaces
@@ -96,12 +106,11 @@ struct( domIterable => {
     extendedAttributes => '$', # Extended attributes
 });
 
-
 # Used to represent string constants
 struct( domConstant => {
-    name => '$',      # DOM Constant identifier
-    type => '$',      # Type of data
-    value => '$',      # Constant value
+    name => '$',        # DOM Constant identifier
+    type => '$',        # Type of data
+    value => '$',       # Constant value
     extendedAttributes => '$', # Extended attributes
 });
 
@@ -149,17 +158,28 @@ sub new {
     return bless $self, $class;
 }
 
+sub assert
+{
+    my $message = shift;
+    
+    my $mess = longmess();
+    print Dumper($mess);
+
+    die $message;
+}
+
 sub assertTokenValue
 {
     my $self = shift;
     my $token = shift;
     my $value = shift;
     my $line = shift;
-    my $msg = "Next token should be " . $value . ", but " . $token->value() . " at " . $self->{Line};
+    my $msg = "Next token should be " . $value . ", but " . $token->value() . " on line " . $self->{Line};
     if (defined ($line)) {
         $msg .= " IDLParser.pm:" . $line;
     }
-    die $msg unless $token->value() eq $value;
+
+    assert $msg unless $token->value() eq $value;
 }
 
 sub assertTokenType
@@ -167,7 +187,8 @@ sub assertTokenType
     my $self = shift;
     my $token = shift;
     my $type = shift;
-    die "Next token's type should be " . $type . ", but " . $token->type() . " at " . $self->{Line} unless $token->type() eq $type;
+    
+    assert "Next token's type should be " . $type . ", but " . $token->type() . " on line " . $self->{Line} unless $token->type() eq $type;
 }
 
 sub assertUnexpectedToken
@@ -175,11 +196,12 @@ sub assertUnexpectedToken
     my $self = shift;
     my $token = shift;
     my $line = shift;
-    my $msg = "Unexpected token " . $token . " at " . $self->{Line};
+    my $msg = "Unexpected token " . $token . " on line " . $self->{Line};
     if (defined ($line)) {
         $msg .= " IDLParser.pm:" . $line;
     }
-    die $msg;
+
+    assert $msg;
 }
 
 sub assertNoExtendedAttributesInTypedef
@@ -188,11 +210,12 @@ sub assertNoExtendedAttributesInTypedef
     my $name = shift;
     my $line = shift;
     my $typedef = $typedefs{$name};
-    my $msg = "Unexpected extendedAttributeList in typedef \"$name\" at " . $self->{Line};
+    my $msg = "Unexpected extendedAttributeList in typedef \"$name\" on line " . $self->{Line};
     if (defined ($line)) {
         $msg .= " IDLParser.pm:" . $line;
     }
-    die $msg if %{$typedef->extendedAttributes};
+
+    assert $msg if %{$typedef->extendedAttributes};
 }
 
 sub Parse
@@ -216,7 +239,7 @@ sub Parse
         my $next = $self->nextToken();
         $self->assertTokenType($next, EmptyToken);
     };
-    die $@ . " in $fileName" if $@;
+    assert $@ . " in $fileName" if $@;
 
     my $document = idlDocument->new();
     $document->fileName($fileName);
@@ -253,7 +276,7 @@ my $floatTokenPattern = '^(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|
 my $integerTokenPattern = '^(-?[1-9][0-9]*|-?0[Xx][0-9A-Fa-f]+|-?0[0-7]*)';
 my $stringTokenPattern = '^(\"[^\"]*\")';
 my $identifierTokenPattern = '^([A-Z_a-z][0-9A-Z_a-z]*)';
-my $otherTokenPattern = '^(::|\.\.\.|[^\t\n\r 0-9A-Z_a-z])';
+my $otherTokenPattern = '^(\.\.\.|[^\t\n\r 0-9A-Z_a-z])';
 
 sub getTokenInternal
 {
@@ -318,21 +341,6 @@ sub unquoteString
     die "Failed to parse string (" . $quotedString . ") at " . $self->{Line};
 }
 
-sub typeHasNullableSuffix
-{
-    my $type = shift;
-    return $type ? $type =~ /\?$/ : 0;
-}
-
-sub typeRemoveNullableSuffix
-{
-    my $type = shift;
-    if ($type) {
-        $type =~ s/\?//g;
-    }
-    return $type;
-}
-
 sub identifierRemoveNullablePrefix
 {
     my $type = shift;
@@ -343,26 +351,26 @@ sub identifierRemoveNullablePrefix
 my $nextAttribute_1 = '^(attribute|inherit|readonly)$';
 my $nextPrimitiveType_1 = '^(int|long|short|unsigned)$';
 my $nextPrimitiveType_2 = '^(double|float|unrestricted)$';
-my $nextArgumentList_1 = '^(\(|::|ByteString|DOMString|USVString|Date|\[|any|boolean|byte|double|float|in|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
+my $nextArgumentList_1 = '^(\(|ByteString|DOMString|USVString|Date|\[|any|boolean|byte|double|float|in|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
 my $nextNonAnyType_1 = '^(boolean|byte|double|float|long|octet|short|unrestricted|unsigned)$';
-my $nextInterfaceMember_1 = '^(\(|::|ByteString|DOMString|USVString|Date|any|attribute|boolean|byte|creator|deleter|double|float|getter|inherit|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$';
+my $nextInterfaceMember_1 = '^(\(|ByteString|DOMString|USVString|Date|any|attribute|boolean|byte|creator|deleter|double|float|getter|inherit|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$';
 my $nextAttributeOrOperation_1 = '^(static|stringifier)$';
-my $nextAttributeOrOperation_2 = '^(\(|::|ByteString|DOMString|USVString|Date|any|boolean|byte|creator|deleter|double|float|getter|legacycaller|long|object|octet|sequence|setter|short|unrestricted|unsigned|void)$';
+my $nextAttributeOrOperation_2 = '^(\(|ByteString|DOMString|USVString|Date|any|boolean|byte|creator|deleter|double|float|getter|legacycaller|long|object|octet|sequence|setter|short|unrestricted|unsigned|void)$';
 my $nextUnrestrictedFloatType_1 = '^(double|float)$';
-my $nextExtendedAttributeRest3_1 = '^(\,|::|\])$';
-my $nextExceptionField_1 = '^(\(|::|ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$';
-my $nextType_1 = '^(::|ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$';
+my $nextExtendedAttributeRest3_1 = '^(\,|\])$';
+my $nextExceptionField_1 = '^(\(|ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$';
+my $nextType_1 = '^(ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$';
 my $nextSpecials_1 = '^(creator|deleter|getter|legacycaller|setter)$';
-my $nextDefinitions_1 = '^(::|callback|dictionary|enum|exception|interface|partial|typedef)$';
-my $nextExceptionMembers_1 = '^(\(|::|ByteString|DOMString|USVString|Date|\[|any|boolean|byte|const|double|float|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
+my $nextDefinitions_1 = '^(callback|dictionary|enum|exception|interface|partial|typedef)$';
+my $nextExceptionMembers_1 = '^(\(|ByteString|DOMString|USVString|Date|\[|any|boolean|byte|const|double|float|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
 my $nextAttributeRest_1 = '^(attribute|readonly)$';
-my $nextInterfaceMembers_1 = '^(\(|::|ByteString|DOMString|USVString|Date|any|attribute|boolean|byte|const|creator|deleter|double|float|getter|inherit|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$';
-my $nextSingleType_1 = '^(::|ByteString|DOMString|USVString|Date|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$';
+my $nextInterfaceMembers_1 = '^(\(|ByteString|DOMString|USVString|Date|any|attribute|boolean|byte|const|creator|deleter|double|float|getter|inherit|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$';
+my $nextSingleType_1 = '^(ByteString|DOMString|USVString|Date|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$';
 my $nextArgumentName_1 = '^(attribute|callback|const|creator|deleter|dictionary|enum|exception|getter|implements|inherit|interface|legacycaller|partial|serializer|setter|static|stringifier|typedef|unrestricted)$';
 my $nextConstValue_1 = '^(false|true)$';
 my $nextConstValue_2 = '^(-|Infinity|NaN)$';
 my $nextDefinition_1 = '^(callback|interface)$';
-my $nextAttributeOrOperationRest_1 = '^(\(|::|ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned|void)$';
+my $nextAttributeOrOperationRest_1 = '^(\(|ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned|void)$';
 my $nextUnsignedIntegerType_1 = '^(long|short)$';
 my $nextDefaultValue_1 = '^(-|Infinity|NaN|false|null|true)$';
 
@@ -480,7 +488,7 @@ sub parseDefinition
     if ($next->value() eq "typedef") {
         return $self->parseTypedef($extendedAttributeList);
     }
-    if ($next->type() == IdentifierToken || $next->value() eq "::") {
+    if ($next->type() == IdentifierToken) {
         return $self->parseImplementsStatement($extendedAttributeList);
     }
     $self->assertUnexpectedToken($next->value(), __LINE__);
@@ -687,13 +695,10 @@ sub parseDictionaryMember
             $member->isOptional(0);
         }
         $member->extendedAttributes($extendedAttributeList);
+
         my $type = $self->parseType();
-        if (typeHasNullableSuffix($type)) {
-            $member->isNullable(1);
-        } else {
-            $member->isNullable(0);
-        }
-        $member->type(typeRemoveNullableSuffix($type));
+        $member->type($type->name);
+        $member->isNullable($type->isNullable);
 
         my $nameToken = $self->getToken();
         $self->assertTokenType($nameToken, IdentifierToken);
@@ -806,9 +811,10 @@ sub parseInheritance
     my $next = $self->nextToken();
     if ($next->value() eq ":") {
         $self->assertTokenValue($self->getToken(), ":", __LINE__);
-        my $scopedName = $self->parseScopedName();
-        push(@parent, $scopedName);
-        # Multiple inheritance (needed for ObjC bindings).
+        my $name = $self->parseName();
+        push(@parent, $name);
+
+        # FIXME: Remove. Was needed for needed for ObjC bindings.
         push(@parent, @{$self->parseIdentifiers()});
     }
     return \@parent;
@@ -900,7 +906,10 @@ sub parseTypedef
         $self->assertTokenValue($self->getToken(), "typedef", __LINE__);
         my $typedef = Typedef->new();
         $typedef->extendedAttributes($self->parseExtendedAttributeListAllowEmpty());
-        $typedef->type($self->parseType());
+
+        my $type = $self->parseType();
+        $typedef->type($type->name);
+
         my $nameToken = $self->getToken();
         $self->assertTokenType($nameToken, IdentifierToken);
         $self->assertTokenValue($self->getToken(), ";", __LINE__);
@@ -919,9 +928,9 @@ sub parseImplementsStatement
 
     my $next = $self->nextToken();
     if ($next->type() == IdentifierToken) {
-        $self->parseScopedName();
+        $self->parseName();
         $self->assertTokenValue($self->getToken(), "implements", __LINE__);
-        $self->parseScopedName();
+        $self->parseName();
         $self->assertTokenValue($self->getToken(), ";", __LINE__);
         return;
     }
@@ -937,7 +946,10 @@ sub parseConst
     if ($next->value() eq "const") {
         my $newDataNode = domConstant->new();
         $self->assertTokenValue($self->getToken(), "const", __LINE__);
-        $newDataNode->type($self->parseConstType());
+        
+        my $type = $self->parseConstType();
+        $newDataNode->type($type->name);
+
         my $constNameToken = $self->getToken();
         $self->assertTokenType($constNameToken, IdentifierToken);
         $newDataNode->name(identifierRemoveNullablePrefix($constNameToken->value()));
@@ -1185,12 +1197,8 @@ sub parseAttributeOrOperationRest
         my $returnType = $self->parseReturnType();
         my $interface = $self->parseOperationRest($extendedAttributeList);
         if (defined ($interface)) {
-            if (typeHasNullableSuffix($returnType)) {
-                $interface->signature->isNullable(1);
-            } else {
-                $interface->signature->isNullable(0);
-            }
-            $interface->signature->type(typeRemoveNullableSuffix($returnType));
+            $interface->signature->type($returnType->name);
+            $interface->signature->isNullable($returnType->isNullable);
         }
         return $interface;
     }
@@ -1226,14 +1234,11 @@ sub parseAttributeRest
         }
         $self->assertTokenValue($self->getToken(), "attribute", __LINE__);
         $newDataNode->signature(domSignature->new());
+        
         my $type = $self->parseType();
-        if (typeHasNullableSuffix($type)) {
-            $newDataNode->signature->isNullable(1);
-        } else {
-            $newDataNode->signature->isNullable(0);
-        }
-        # Remove all "?" in the type declaration, e.g. "double?" -> "double".
-        $newDataNode->signature->type(typeRemoveNullableSuffix($type));
+        $newDataNode->signature->type($type->name);
+        $newDataNode->signature->isNullable($type->isNullable);
+
         my $token = $self->getToken();
         $self->assertTokenType($token, IdentifierToken);
         $newDataNode->signature->name(identifierRemoveNullablePrefix($token->value()));
@@ -1288,12 +1293,8 @@ sub parseOperationOrIterator
         my $next = $self->nextToken();
         if ($next->type() == IdentifierToken || $next->value() eq "(") {
             my $operation = $self->parseOperationRest($extendedAttributeList);
-            if (typeHasNullableSuffix($returnType)) {
-                $operation->signature->isNullable(1);
-            } else {
-                $operation->signature->isNullable(0);
-            }
-            $operation->signature->type(typeRemoveNullableSuffix($returnType));
+            $operation->signature->type($returnType->name);
+            $operation->signature->isNullable($returnType->isNullable);
 
             return $operation;
         }
@@ -1313,13 +1314,8 @@ sub parseSpecialOperation
         my $returnType = $self->parseReturnType();
         my $interface = $self->parseOperationRest($extendedAttributeList);
         if (defined ($interface)) {
-            if (typeHasNullableSuffix($returnType)) {
-                $interface->signature->isNullable(1);
-            } else {
-                $interface->signature->isNullable(0);
-            }
-            $interface->signature->type(typeRemoveNullableSuffix($returnType));
-
+            $interface->signature->type($returnType->name);
+            $interface->signature->isNullable($returnType->isNullable);
             $interface->signature->specials(\@specials);
         }
         return $interface;
@@ -1530,15 +1526,10 @@ sub parseOptionalOrRequiredArgument
     my $next = $self->nextToken();
     if ($next->value() eq "optional") {
         $self->assertTokenValue($self->getToken(), "optional", __LINE__);
+
         my $type = $self->parseType();
-        # domDataNode can only consider last "?".
-        if (typeHasNullableSuffix($type)) {
-            $paramDataNode->isNullable(1);
-        } else {
-            $paramDataNode->isNullable(0);
-        }
-        # Remove "?" if exists, e.g. "object?" -> "object".
-        $paramDataNode->type(identifierRemoveNullablePrefix(typeRemoveNullableSuffix($type)));
+        $paramDataNode->type(identifierRemoveNullablePrefix($type->name));
+        $paramDataNode->isNullable($type->isNullable);
         $paramDataNode->isOptional(1);
         $paramDataNode->name($self->parseArgumentName());
         $paramDataNode->default($self->parseDefault());
@@ -1546,14 +1537,8 @@ sub parseOptionalOrRequiredArgument
     }
     if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
         my $type = $self->parseType();
-        # domDataNode can only consider last "?".
-        if (typeHasNullableSuffix($type)) {
-            $paramDataNode->isNullable(1);
-        } else {
-            $paramDataNode->isNullable(0);
-        }
-        # Remove "?" if exists, e.g. "object?" -> "object".
-        $paramDataNode->type(typeRemoveNullableSuffix($type));
+        $paramDataNode->type($type->name);
+        $paramDataNode->isNullable($type->isNullable);
         $paramDataNode->isOptional(0);
         $paramDataNode->isVariadic($self->parseEllipsis());
         $paramDataNode->name($self->parseArgumentName());
@@ -1612,7 +1597,11 @@ sub parseExceptionField
         $newDataNode->type("attribute");
         $newDataNode->isReadOnly(1);
         $newDataNode->signature(domSignature->new());
-        $newDataNode->signature->type($self->parseType());
+
+        my $type = $self->parseType();
+        $newDataNode->signature->type($type->name);
+        $newDataNode->signature->isNullable($type->isNullable);
+        
         my $token = $self->getToken();
         $self->assertTokenType($token, IdentifierToken);
         $newDataNode->signature->name(identifierRemoveNullablePrefix($token->value()));
@@ -1698,9 +1687,9 @@ sub parseExtendedAttribute
 {
     my $self = shift;
     my $next = $self->nextToken();
-    if ($next->type() == IdentifierToken || $next->value() eq "::") {
-        my $scopedName = $self->parseScopedName();
-        return $self->parseExtendedAttributeRest($scopedName);
+    if ($next->type() == IdentifierToken) {
+        my $name = $self->parseName();
+        return $self->parseExtendedAttributeRest($name);
     }
     # backward compatibility. Spec doesn' allow "[]". But WebKit requires.
     if ($next->value() eq ']') {
@@ -1713,9 +1702,9 @@ sub parseExtendedAttribute2
 {
     my $self = shift;
     my $next = $self->nextToken();
-    if ($next->type() == IdentifierToken || $next->value() eq "::") {
-        my $scopedName = $self->parseScopedName();
-        return $self->parseExtendedAttributeRest($scopedName);
+    if ($next->type() == IdentifierToken) {
+        my $name = $self->parseName();
+        return $self->parseExtendedAttributeRest($name);
     }
     return {};
 }
@@ -1757,9 +1746,9 @@ sub parseExtendedAttributeRest2
         $self->assertTokenValue($self->getToken(), ")", __LINE__);
         return @arguments;
     }
-    if ($next->type() == IdentifierToken || $next->value() eq "::") {
-        my $scopedName = $self->parseScopedName();
-        return $self->parseExtendedAttributeRest3($scopedName);
+    if ($next->type() == IdentifierToken) {
+        my $name = $self->parseName();
+        return $self->parseExtendedAttributeRest3($name);
     }
     if ($next->type() == IntegerToken) {
         my $token = $self->getToken();
@@ -1776,12 +1765,12 @@ sub parseExtendedAttributeRest3
     my $next = $self->nextToken();
     if ($next->value() eq "&") {
         $self->assertTokenValue($self->getToken(), "&", __LINE__);
-        my $rightValue = $self->parseScopedName();
+        my $rightValue = $self->parseName();
         return $name . "&" . $rightValue;
     }
     if ($next->value() eq "|") {
         $self->assertTokenValue($self->getToken(), "|", __LINE__);
-        my $rightValue = $self->parseScopedName();
+        my $rightValue = $self->parseName();
         return $name . "|" . $rightValue;
     }
     if ($next->value() eq "(") {
@@ -1792,30 +1781,12 @@ sub parseExtendedAttributeRest3
         return $attr;
     }
     if ($next->type() == IdentifierToken || $next->value() =~ /$nextExtendedAttributeRest3_1/) {
-        my @names = ();
-        push(@names, $name);
-        push(@names, @{$self->parseScopedNameListNoComma()});
-        return join(' ', @names);
+        $self->parseNameNoComma();
+        return $name;
     }
     $self->assertUnexpectedToken($next->value());
 }
 
-sub parseScopedNameListNoComma
-{
-    my $self = shift;
-    my @names = ();
-
-    while (1) {
-        my $next = $self->nextToken();
-        if ($next->type() == IdentifierToken || $next->value() eq "::") {
-            push(@names, $self->parseScopedName());
-        } else {
-            last;
-        }
-    }
-    return \@names;
-}
-
 sub parseArgumentNameKeyword
 {
     my $self = shift;
@@ -1888,9 +1859,7 @@ sub parseType
     my $self = shift;
     my $next = $self->nextToken();
     if ($next->value() eq "(") {
-        $self->parseUnionType();
-        $self->parseTypeSuffix();
-        return;
+        return $self->parseUnionType();
     }
     if ($next->type() == IdentifierToken || $next->value() =~ /$nextType_1/) {
         return $self->parseSingleType();
@@ -1904,10 +1873,15 @@ sub parseSingleType
     my $next = $self->nextToken();
     if ($next->value() eq "any") {
         $self->assertTokenValue($self->getToken(), "any", __LINE__);
-        return "any";
+        
+        my $anyType = domType->new();
+        $anyType->name("any");
+        return $anyType;
     }
     if ($next->type() == IdentifierToken || $next->value() =~ /$nextSingleType_1/) {
-        return $self->parseNonAnyType();
+        my $nonAnyType = $self->parseNonAnyType();
+        $nonAnyType->isNullable($self->parseNull());
+        return $nonAnyType;
     }
     $self->assertUnexpectedToken($next->value(), __LINE__);
 }
@@ -1916,14 +1890,24 @@ sub parseUnionType
 {
     my $self = shift;
     my $next = $self->nextToken();
+
+    my $unionType = domType->new();
+    $unionType->name("UNION");
+    $unionType->isUnion(1);
+
     if ($next->value() eq "(") {
         $self->assertTokenValue($self->getToken(), "(", __LINE__);
-        $self->parseUnionMemberType();
+        
+        push(@{$unionType->subtypes}, $self->parseUnionMemberType());
+        
         $self->assertTokenValue($self->getToken(), "or", __LINE__);
-        $self->parseUnionMemberType();
-        $self->parseUnionMemberTypes();
+        
+        push(@{$unionType->subtypes}, $self->parseUnionMemberType());
+        push(@{$unionType->subtypes}, $self->parseUnionMemberTypes());
+        
         $self->assertTokenValue($self->getToken(), ")", __LINE__);
-        return;
+
+        return $unionType;
     }
     $self->assertUnexpectedToken($next->value(), __LINE__);
 }
@@ -1933,20 +1917,14 @@ sub parseUnionMemberType
     my $self = shift;
     my $next = $self->nextToken();
     if ($next->value() eq "(") {
-        $self->parseUnionType();
-        $self->parseTypeSuffix();
-        return;
-    }
-    if ($next->value() eq "any") {
-        $self->assertTokenValue($self->getToken(), "any", __LINE__);
-        $self->assertTokenValue($self->getToken(), "[", __LINE__);
-        $self->assertTokenValue($self->getToken(), "]", __LINE__);
-        $self->parseTypeSuffix();
-        return;
+        my $unionType = $self->parseUnionType();
+        $unionType->isNullable($self->parseNull());
+        return $unionType;
     }
     if ($next->type() == IdentifierToken || $next->value() =~ /$nextSingleType_1/) {
-        $self->parseNonAnyType();
-        return;
+        my $nonAnyType = $self->parseNonAnyType();
+        $nonAnyType->isNullable($self->parseNull());
+        return $nonAnyType;
     }
     $self->assertUnexpectedToken($next->value(), __LINE__);
 }
@@ -1955,51 +1933,97 @@ sub parseUnionMemberTypes
 {
     my $self = shift;
     my $next = $self->nextToken();
+
+    my @subtypes = ();
+
     if ($next->value() eq "or") {
         $self->assertTokenValue($self->getToken(), "or", __LINE__);
-        $self->parseUnionMemberType();
-        $self->parseUnionMemberTypes();
+        push(@subtypes, $self->parseUnionMemberType());
+        push(@subtypes, $self->parseUnionMemberTypes());
     }
+
+    return @subtypes;
 }
 
 sub parseNonAnyType
 {
     my $self = shift;
     my $next = $self->nextToken();
+
+    my $type = domType->new();
+
     if ($next->value() =~ /$nextNonAnyType_1/) {
-        return $self->parsePrimitiveType() . $self->parseTypeSuffix();
+        $type->name($self->parsePrimitiveType());
+        return $type;
     }
     if ($next->value() eq "ByteString") {
         $self->assertTokenValue($self->getToken(), "ByteString", __LINE__);
-        return "ByteString" . $self->parseTypeSuffix();
+
+        $type->name("ByteString");
+        return $type;
     }
     if ($next->value() eq "DOMString") {
         $self->assertTokenValue($self->getToken(), "DOMString", __LINE__);
-        return "DOMString" . $self->parseTypeSuffix();
+
+        $type->name("DOMString");
+        return $type;
     }
     if ($next->value() eq "USVString") {
         $self->assertTokenValue($self->getToken(), "USVString", __LINE__);
-        return "USVString" . $self->parseTypeSuffix();
-    }
-    
-    if ($next->value() eq "sequence") {
-        $self->assertTokenValue($self->getToken(), "sequence", __LINE__);
-        $self->assertTokenValue($self->getToken(), "<", __LINE__);
-        my $type = $self->parseType();
-        $self->assertTokenValue($self->getToken(), ">", __LINE__);
-        return "sequence<" . $type . ">" . $self->parseNull();
+
+        $type->name("USVString");
+        return $type;
     }
     if ($next->value() eq "object") {
         $self->assertTokenValue($self->getToken(), "object", __LINE__);
-        return "object" . $self->parseTypeSuffix();
+
+        $type->name("object");
+        return $type;
+    }
+    if ($next->value() eq "RegExp") {
+        $self->assertTokenValue($self->getToken(), "RegExp", __LINE__);
+
+        $type->name("RegExp");
+        return $type;
+    }
+    if ($next->value() eq "Error") {
+        $self->assertTokenValue($self->getToken(), "Error", __LINE__);
+
+        $type->name("Error");
+        return $type;
+    }
+    if ($next->value() eq "DOMException") {
+        $self->assertTokenValue($self->getToken(), "DOMException", __LINE__);
+
+        $type->name("DOMException");
+        return $type;
     }
     if ($next->value() eq "Date") {
         $self->assertTokenValue($self->getToken(), "Date", __LINE__);
-        return "Date" . $self->parseTypeSuffix();
+
+        $type->name("Date");
+        return $type;
+    }
+    if ($next->value() eq "sequence") {
+        $self->assertTokenValue($self->getToken(), "sequence", __LINE__);
+        $self->assertTokenValue($self->getToken(), "<", __LINE__);
+
+        my $subtype = $self->parseType();
+        my $subtypeName = $subtype->name;
+
+        $self->assertTokenValue($self->getToken(), ">", __LINE__);
+
+        # FIXME: This should just be "sequence" when we start using domTypes in the CodeGenerators
+        $type->name("sequence<${subtypeName}>");
+        push(@{$type->subtypes}, $subtype);
+
+        return $type;
     }
-    if ($next->type() == IdentifierToken || $next->value() eq "::") {
-        my $name = identifierRemoveNullablePrefix($self->parseScopedName());
-        return $name . $self->parseTypeSuffix();
+    if ($next->type() == IdentifierToken) {
+        my $identifier = $self->getToken();
+
+        $type->name(identifierRemoveNullablePrefix($identifier->value()));
+        return $type;
     }
     $self->assertUnexpectedToken($next->value(), __LINE__);
 }
@@ -2008,12 +2032,21 @@ sub parseConstType
 {
     my $self = shift;
     my $next = $self->nextToken();
+
+    my $type = domType->new();
+
     if ($next->value() =~ /$nextNonAnyType_1/) {
-        return $self->parsePrimitiveType() . $self->parseNull();
+        $type->name($self->parsePrimitiveType());
+        $type->isNullable($self->parseNull());
+        return $type;
     }
     if ($next->type() == IdentifierToken) {
-        my $token = $self->getToken();
-        return $token->value() . $self->parseNull();
+        my $identifier = $self->getToken();
+        
+        $type->name($identifier->value());
+        $type->isNullable($self->parseNull());
+
+        return $type;
     }
     $self->assertUnexpectedToken($next->value(), __LINE__);
 }
@@ -2119,26 +2152,15 @@ sub parseOptionalLong
     return 0;
 }
 
-sub parseTypeSuffix
-{
-    my $self = shift;
-    my $next = $self->nextToken();
-    if ($next->value() eq "?") {
-        $self->assertTokenValue($self->getToken(), "?", __LINE__);
-        return "?";
-    }
-    return "";
-}
-
 sub parseNull
 {
     my $self = shift;
     my $next = $self->nextToken();
     if ($next->value() eq "?") {
         $self->assertTokenValue($self->getToken(), "?", __LINE__);
-        return "?";
+        return 1;
     }
-    return "";
+    return 0;
 }
 
 sub parseReturnType
@@ -2147,7 +2169,10 @@ sub parseReturnType
     my $next = $self->nextToken();
     if ($next->value() eq "void") {
         $self->assertTokenValue($self->getToken(), "void", __LINE__);
-        return "void";
+        
+        my $voidType = domType->new();
+        $voidType->name("void");
+        return $voidType;
     }
     if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
         return $self->parseType();
@@ -2175,92 +2200,29 @@ sub parseOptionalSemicolon
     }
 }
 
-sub parseScopedName
+sub parseNameNoComma
 {
     my $self = shift;
     my $next = $self->nextToken();
-    if ($next->value() eq "::") {
-        return $self->parseAbsoluteScopedName();
-    }
     if ($next->type() == IdentifierToken) {
-        return $self->parseRelativeScopedName();
+        my $identifier = $self->getToken();
+        return ($identifier->value());
     }
-    $self->assertUnexpectedToken($next->value());
-}
 
-sub parseAbsoluteScopedName
-{
-    my $self = shift;
-    my $next = $self->nextToken();
-    if ($next->value() eq "::") {
-        $self->assertTokenValue($self->getToken(), "::");
-        my $token = $self->getToken();
-        $self->assertTokenType($token, IdentifierToken);
-        return "::" . $token->value() . $self->parseScopedNameParts();
-    }
-    $self->assertUnexpectedToken($next->value());
+    return ();
 }
 
-sub parseRelativeScopedName
+sub parseName
 {
     my $self = shift;
     my $next = $self->nextToken();
     if ($next->type() == IdentifierToken) {
-        my $token = $self->getToken();
-        return $token->value() . $self->parseScopedNameParts();
+        my $identifier = $self->getToken();
+        return $identifier->value();
     }
     $self->assertUnexpectedToken($next->value());
 }
 
-sub parseScopedNameParts
-{
-    my $self = shift;
-    my @names = ();
-
-    while (1) {
-        my $next = $self->nextToken();
-        if ($next->value() eq "::") {
-            $self->assertTokenValue($self->getToken(), "::");
-            push(@names, "::");
-            my $token = $self->getToken();
-            $self->assertTokenType($token, IdentifierToken);
-            push(@names, $token->value());
-        } else {
-            last;
-        }
-    }
-    return join("", @names);
-}
-
-sub parseScopedNameList
-{
-    my $self = shift;
-    my $next = $self->nextToken();
-    if ($next->type() == IdentifierToken || $next->value() eq "::") {
-        my @names = ();
-        push(@names, $self->parseScopedName());
-        push(@names, @{$self->parseScopedNames()});
-        return \@names;
-    }
-    $self->assertUnexpectedToken($next->value(), __LINE__);
-}
-
-sub parseScopedNames
-{
-    my $self = shift;
-    my @names = ();
-
-    while (1) {
-        my $next = $self->nextToken();
-        if ($next->value() eq ",") {
-            $self->assertTokenValue($self->getToken(), ",");
-            push(@names, $self->parseScopedName());
-        } else {
-            last;
-        }
-    }
-    return \@names;
-}
 
 sub applyMemberList
 {