private AST walkEnumNode(
     final Compiler.Context context,
     final AST node,
     final String namespace,
     final MessageDefinition outerMessage) {
   final List<AST> children = node.getChildNodes();
   final AST identifier = children.get(0);
   final String fullIdentifier = namespace + "." + identifier.getNodeValue();
   final EnumDefinition enumDefinition =
       outerMessage.createEnumDefinition(
           fullIdentifier,
           identifier.getCodePosition(),
           identifier.getCodePosition().getSource().isCompilationTarget());
   context.addDefinition(enumDefinition);
   children.set(0, new ASTNode(identifier, fullIdentifier));
   for (int i = 1; i < children.size(); i++) {
     final AST element = children.get(i);
     if (element.getNodeLabel() == ProtoLexer.BINDING) {
       walkBindingNode(context, element, enumDefinition);
       children.remove(i);
       i--;
     }
   }
   return new ASTNode(node, children);
 }
 private AST walkTaxonomyNode(
     final Compiler.Context context, final AST node, final String parentNamespace) {
   final List<AST> children = node.getChildNodes();
   AST identifier = fixupFullIdentifier(children.get(0));
   if (parentNamespace.length() != 0) {
     identifier = new ASTNode(identifier, parentNamespace + "." + identifier.getNodeValue());
   }
   final TaxonomyDefinition taxonomyDefinition =
       new TaxonomyDefinition(
           identifier.getNodeValue(),
           identifier.getCodePosition(),
           identifier.getCodePosition().getSource().isCompilationTarget());
   context.addDefinition(taxonomyDefinition);
   children.set(0, identifier);
   for (int i = 1; i < children.size(); i++) {
     final AST element = children.get(i);
     switch (element.getNodeLabel()) {
       case ProtoLexer.BINDING:
         walkBindingNode(context, element, taxonomyDefinition);
         children.remove(i);
         i--;
         break;
       case ProtoLexer.IMPORT:
         children.set(i, fixupFullIdentifierList(element));
         break;
     }
   }
   return new ASTNode(node, children);
 }
 private AST walkMessageNode(
     final Compiler.Context context,
     final AST node,
     final String namespace,
     final MessageDefinition outerMessage) {
   final List<AST> children = node.getChildNodes();
   final String localNamespace;
   AST identifier = children.get(0);
   boolean isAbstract = false;
   if (identifier.getNodeLabel() == ProtoLexer.ABSTRACT) {
     isAbstract = true;
     children.remove(0);
     identifier = children.get(0);
   }
   if (namespace.length() != 0) {
     children.set(
         0, new ASTNode(identifier, localNamespace = namespace + "." + identifier.getNodeValue()));
   } else {
     localNamespace = identifier.getNodeValue();
   }
   final MessageDefinition messageDefinition =
       outerMessage.createMessageDefinition(
           localNamespace,
           identifier.getCodePosition(),
           identifier.getCodePosition().getSource().isCompilationTarget());
   context.addDefinition(messageDefinition);
   if (isAbstract) {
     messageDefinition.setAbstract();
   }
   for (int i = 1; i < children.size(); i++) {
     final AST element = children.get(i);
     switch (element.getNodeLabel()) {
       case ProtoLexer.BINDING:
         walkBindingNode(context, element, messageDefinition);
         children.remove(i);
         i--;
         break;
       case ProtoLexer.ENUM:
         children.set(i, walkEnumNode(context, element, localNamespace, messageDefinition));
         break;
       case ProtoLexer.EXTENDS:
         children.set(i, fixupFullIdentifierList(element));
         break;
       case ProtoLexer.FIELD:
         children.set(i, walkFieldNode(element));
         break;
       case ProtoLexer.MESSAGE:
         children.set(i, walkMessageNode(context, element, localNamespace, messageDefinition));
         break;
       case ProtoLexer.TYPEDEF:
         walkTypedefNode(context, element, localNamespace, true);
         break;
       case ProtoLexer.USES:
         children.set(i, fixupFullIdentifierList(element));
         break;
     }
   }
   return new ASTNode(node, children);
 }
 private void walkExternNode(
     final Compiler.Context context,
     final AST node,
     final String namespace,
     final MessageDefinition outerMessage) {
   final List<AST> children = node.getChildNodes();
   final AST what = children.get(0);
   switch (what.getNodeLabel()) {
     case ProtoLexer.TYPEDEF:
       {
         final AST typedef = walkTypedefNode(context, what, namespace, true);
         children.set(0, typedef);
         context.addExpandedRoot(new ASTNode(node, children));
         return;
       }
   }
   final String localNamespace;
   final AST identifier = fixupFullIdentifier(children.get(1));
   if (namespace.length() != 0) {
     localNamespace = namespace + "." + identifier.getNodeValue();
   } else {
     localNamespace = identifier.getNodeValue();
   }
   switch (what.getNodeLabel()) {
     case ProtoLexer.ENUM:
       context.addDefinition(
           outerMessage.createEnumDefinition(localNamespace, identifier.getCodePosition(), false));
       break;
     case ProtoLexer.MESSAGE:
       final MessageDefinition messageDefinition =
           outerMessage.createMessageDefinition(
               localNamespace, identifier.getCodePosition(), false);
       if (children.size() < 3) {
         messageDefinition.setExternal();
       }
       context.addDefinition(messageDefinition);
       break;
     case ProtoLexer.TAXONOMY:
       context.addDefinition(
           new TaxonomyDefinition(localNamespace, identifier.getCodePosition(), false));
       break;
     default:
       throw new IllegalStateException("unexpected extern type '" + node.getNodeLabel() + "'");
   }
 }
 private AST walkTypedefNode(
     final Compiler.Context context,
     final AST node,
     final String namespace,
     final boolean isExtern) {
   List<AST> children = node.getChildNodes();
   final AST identifier = fixupFullIdentifier(children.get(0));
   final String fullIdentifier;
   if (namespace.length() != 0) {
     children.set(
         0, new ASTNode(identifier, fullIdentifier = namespace + "." + identifier.getNodeValue()));
   } else {
     children.set(0, identifier);
     fullIdentifier = identifier.getNodeValue();
   }
   final TypeDefinition typedef =
       new TypeDefinition(fullIdentifier, node.getCodePosition(), !isExtern);
   if (isExtern) {
     typedef.setExternal();
   }
   context.addDefinition(typedef);
   children.set(1, walkFieldTypeNode(children.get(1)));
   return new ASTNode(node, children);
 }