%{
  # -*- mode: C++ -*-
  from gyb_syntax_support import *
  NODE_MAP = create_node_map()
  # Ignore the following admonition; it applies to the resulting .cpp file only
}%
//// Automatically Generated From SyntaxNodes.cpp.gyb.
//// Do Not Edit Directly!
//===---------------- SyntaxNodes.cpp - Syntax Node definitions -----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//


#include "swift/Syntax/SyntaxNodes.h"

using namespace swift;
using namespace swift::syntax;

% for node in SYNTAX_NODES:
%   if node.requires_validation():
void ${node.name}::validate() const {
  if (!Data || !Data->Raw) return;
  auto raw = Data->Raw;
  if (isMissing()) return;
  assert(raw->Layout.size() == ${len(node.children)});
%     for child in node.children:
%       if child.token_choices:
%         choices = ", ".join("tok::" + choice.kind
%                             for choice in child.token_choices)
  syntax_assert_child_token(raw, ${child.name}, ${choices});
%       end
%       if child.main_token() and child.text_choices:
%         token_kind = child.main_token().kind
%         choices = ", ".join("\"%s\"" % choice
%                             for choice in child.text_choices)
  syntax_assert_child_token_text(raw, ${child.name}, 
                                 tok::${token_kind}, ${choices});
%       end
%     end
}
%   end

%   for child in node.children:
%     if child.is_optional:
llvm::Optional<${child.type_name}> ${node.name}::get${child.name}() {
  if (getRaw()->getChild(Cursor::${child.name})->isMissing()) {
    return llvm::None;
  }
  return llvm::Optional<${child.type_name}> {
    ${child.type_name} { Root, Data->getChild(Cursor::${child.name}).get() }
  };
}
%     else:
${child.type_name} ${node.name}::get${child.name}() {
  return ${child.type_name} { Root, Data->getChild(Cursor::${child.name}).get() };
}
%     end

%     child_node = NODE_MAP.get(child.syntax_kind)
%     if child_node and child_node.is_syntax_collection():
%       child_elt = child_node.collection_element_name
%       child_elt_type = child_node.collection_element_type
${node.name} ${node.name}::add${child_elt}(${child_elt_type} ${child_elt}) {
  auto childRaw = getRaw()->getChild(Cursor::${child.name})
                          ->append(${child_elt}.getRaw());
  return Data->replaceChild<${node.name}>(childRaw, Cursor::${child.name});
}
%     end

${node.name} ${node.name}::with${child.name}(
  llvm::Optional<${child.type_name}> New${child.type_name}) {
  RC<RawSyntax> raw;
  if (New${child.type_name}.hasValue()) {
    raw = New${child.type_name}->getRaw();
  } else {
    raw = ${make_missing_child(child)};
  }
  return Data->replaceChild<${node.name}>(raw, Cursor::${child.name});
}

%   end
% end