From 6a3693ffd6dcc1702742d23943cecb4686c7aa4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20=27Bubu=27=20Busi?= Date: Tue, 10 Jul 2018 09:19:09 +0200 Subject: [PATCH 1/4] feat(build): Also support python3 --- CMakeLists.txt | 5 +- ast/ast.py | 7 + ast/c_impl_py3.py | 61 +++++++++ ast/c_py3.py | 100 +++++++++++++++ ast/c_visitor_impl_py3.py | 39 ++++++ ast/cxx_impl_py3.py | 61 +++++++++ ast/cxx_json_visitor_header_py3.py | 42 ++++++ ast/cxx_json_visitor_impl_py3.py | 80 ++++++++++++ ast/cxx_py3.py | 197 +++++++++++++++++++++++++++++ ast/cxx_visitor_py3.py | 64 ++++++++++ ast/js_py3.py | 65 ++++++++++ 11 files changed, 717 insertions(+), 4 deletions(-) create mode 100644 ast/c_impl_py3.py create mode 100644 ast/c_py3.py create mode 100644 ast/c_visitor_impl_py3.py create mode 100644 ast/cxx_impl_py3.py create mode 100644 ast/cxx_json_visitor_header_py3.py create mode 100644 ast/cxx_json_visitor_impl_py3.py create mode 100644 ast/cxx_py3.py create mode 100644 ast/cxx_visitor_py3.py create mode 100644 ast/js_py3.py diff --git a/CMakeLists.txt b/CMakeLists.txt index c4c8b3e..d07a05d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,10 +7,7 @@ INCLUDE(version) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") -FIND_PACKAGE(PythonInterp 2 REQUIRED) -IF (NOT PYTHON_VERSION_MAJOR EQUAL 2) - MESSAGE(FATAL_ERROR "Python 2 is required.") -ENDIF() +FIND_PACKAGE(PythonInterp 2) FIND_PROGRAM(CTYPESGEN_FOUND ctypesgen.py) diff --git a/ast/ast.py b/ast/ast.py index dbe539c..99ce1d9 100644 --- a/ast/ast.py +++ b/ast/ast.py @@ -54,6 +54,13 @@ def print_ast(lang_module, input_file): if __name__ == '__main__': import sys lang = sys.argv[1] + + try: + if sys.version_info >= (3,0): + lang = "%s_py3" % lang + except: + pass + filename = sys.argv[2] lang_module = load_lang(lang) diff --git a/ast/c_impl_py3.py b/ast/c_impl_py3.py new file mode 100644 index 0000000..aa17765 --- /dev/null +++ b/ast/c_impl_py3.py @@ -0,0 +1,61 @@ +# Copyright (c) 2015-present, Facebook, Inc. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from c_py3 import field_prototype, return_type, struct_name +from casing import title +from license import C_LICENSE_COMMENT + +class Printer(object): + '''Printer for the implementation of the pure C interface to the AST. + ''' + + def __init__(self): + self._current_type = None + + def start_file(self): + print(C_LICENSE_COMMENT + '''/** @generated */ + +#include "GraphQLAst.h" +#include "../Ast.h" + +using namespace facebook::graphql::ast; // NOLINT +''') + + def end_file(self): + pass + + def start_type(self, name): + self._current_type = name + + def field(self, type, name, nullable, plural): + print(field_prototype(self._current_type, type, name, nullable, plural) + ' {') + print(' const auto *realNode = reinterpret_cast(node);' % self._current_type) + title_name = title(name) + call_get = 'realNode->get%s()' % title_name + if plural: + if nullable: + print(' return %s ? %s->size() : 0;' % (call_get, call_get)) + else: + print(' return %s.size();' % call_get) + else: + if type in ['string', 'OperationKind', 'boolean']: + print(' return %s;' % call_get) + else: + fmt = ' return reinterpret_cast(%s%s);' + print(fmt % (struct_name(type), '' if nullable else '&', call_get)) + + print('}') + + def end_type(self, name): + pass + + def start_union(self, name): + pass + + def union_option(self, option): + pass + + def end_union(self, name): + pass diff --git a/ast/c_py3.py b/ast/c_py3.py new file mode 100644 index 0000000..bbcb653 --- /dev/null +++ b/ast/c_py3.py @@ -0,0 +1,100 @@ +# Copyright (c) 2015-present, Facebook, Inc. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from casing import snake + +from license import C_LICENSE_COMMENT + +def struct_name(type): + return 'GraphQLAst' + type + + +def return_type(type): + if type == 'OperationKind' or type == 'string': + return 'const char *' + + if type == 'boolean': + return 'int' + + return 'const struct %s *' % struct_name(type) + + +def field_prototype(owning_type, type, name, nullable, plural): + st_name = struct_name(owning_type) + if plural: + return 'int %s_get_%s_size(const struct %s *node)' % ( + st_name, snake(name), st_name) + else: + ret_type = return_type(type) + return '%s %s_get_%s(const struct %s *node)' % ( + ret_type, st_name, snake(name), st_name) + + +class Printer(object): + '''Printer for the pure C interface to the AST. + + Merely a set of wrappers around the C++ interface; makes it possible + to use the AST from C code and simplifies the task of writing + bindings for other langugages. + + The mapping is as follows: + + - For each concrete type, you get an opaque C struct type, + accessible only by pointer. + + - For each singular field of a concrete type, you get an accessor + function, returning said field in the obvious way. + + - For each plural field of a concrete type, you get an accessor + function telling you its size. For access to elements of a plural + field, you can use the visitor API. + + - For each union type, you get nothing specific (REVIEW), but you + can use the visitor API to work around this entirely. + + ''' + + def __init__(self): + self._current_type = None + + def start_file(self): + print(C_LICENSE_COMMENT + '''/** @generated */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +''') + + def end_file(self): + print(''' + +#ifdef __cplusplus +} +#endif +''') + + def start_type(self, name): + # Forward declarations for AST nodes. + st_name = struct_name(name) + print('struct ' + st_name + ';') + self._current_type = name + + def field(self, type, name, nullable, plural): + print(field_prototype(self._current_type, type, name, nullable, plural) + ';') + + def end_type(self, name): + print() + + def start_union(self, name): + print('struct ' + struct_name(name) + ';') + + def union_option(self, option): + pass + + def end_union(self, name): + print() diff --git a/ast/c_visitor_impl_py3.py b/ast/c_visitor_impl_py3.py new file mode 100644 index 0000000..bbf84f0 --- /dev/null +++ b/ast/c_visitor_impl_py3.py @@ -0,0 +1,39 @@ +# Copyright (c) 2015-present, Facebook, Inc. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from casing import snake +from license import C_LICENSE_COMMENT + +class Printer(object): + '''Printer for a simple list of types to be visited by the C visitor. + ''' + + def __init__(self): + self._types = [] + + def start_file(self): + print(C_LICENSE_COMMENT + '/** @generated */') + print('#define FOR_EACH_CONCRETE_TYPE(MACRO) \\') + + def start_type(self, name): + self._types.append(name) + + def field(self, type, name, nullable, plural): + pass + + def end_type(self, name): + pass + + def end_file(self): + print(' \\\n'.join('MACRO(%s, %s)' % (name, snake(name)) for name in self._types)) + + def start_union(self, name): + pass + + def union_option(self, option): + pass + + def end_union(self, name): + pass diff --git a/ast/cxx_impl_py3.py b/ast/cxx_impl_py3.py new file mode 100644 index 0000000..299ed74 --- /dev/null +++ b/ast/cxx_impl_py3.py @@ -0,0 +1,61 @@ +# Copyright (c) 2015-present, Facebook, Inc. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from license import C_LICENSE_COMMENT + +class Printer(object): + def __init__(self): + pass + + def start_file(self): + print(C_LICENSE_COMMENT + '''/** @generated */ + +#include "Ast.h" +#include "AstVisitor.h" + +namespace facebook { +namespace graphql { +namespace ast { +''') + + def end_file(self): + print('} // namespace ast') + print('} // namespace graphql') + print('} // namespace facebook') + + def start_type(self, name): + print('''void %s::accept(visitor::AstVisitor *visitor) const { + if (visitor->visit%s(*this)) { +''' % (name, name)) + + def field(self, type, name, nullable, plural): + if type in ['OperationKind', 'string', 'boolean']: + return + + if plural: + accept = '{ for (const auto &x : *%s_) { x->accept(visitor); } }' % name + if nullable: + accept = 'if (%s_) %s' % (name, accept) + print(' ' + accept) + else: + accept = '%s_->accept(visitor);' % name + if nullable: + accept = 'if (%s_) { %s }' % (name, accept) + print(' ' + accept) + + def end_type(self, name): + print(''' } + visitor->endVisit%s(*this); +} +''' % name) + + def start_union(self, name): + pass + + def union_option(self, option): + pass + + def end_union(self, name): + pass diff --git a/ast/cxx_json_visitor_header_py3.py b/ast/cxx_json_visitor_header_py3.py new file mode 100644 index 0000000..8ce7349 --- /dev/null +++ b/ast/cxx_json_visitor_header_py3.py @@ -0,0 +1,42 @@ +# Copyright (c) 2016-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from casing import title +from license import C_LICENSE_COMMENT + +class Printer(object): + def __init__(self): + self._anyFieldIsANode = False + + def start_file(self): + print(C_LICENSE_COMMENT + '/** @generated */') + + def end_file(self): + pass + + def start_type(self, name): + self._anyFieldIsANode = False + + def end_type(self, name): + titleName = title(name) + if self._anyFieldIsANode: + print('bool visit%s(const %s &node) override;' % (titleName, titleName)) + print('void endVisit%s(const %s &node) override;' % (titleName, titleName)) + print() + + def field(self, type, name, nullable, plural): + if (not self._anyFieldIsANode and + type not in ('OperationKind', 'string', 'boolean')): + self._anyFieldIsANode = True + + def start_union(self, name): + pass + + def union_option(self, option): + pass + + def end_union(self, name): + pass diff --git a/ast/cxx_json_visitor_impl_py3.py b/ast/cxx_json_visitor_impl_py3.py new file mode 100644 index 0000000..c96efdf --- /dev/null +++ b/ast/cxx_json_visitor_impl_py3.py @@ -0,0 +1,80 @@ +# Copyright (c) 2016-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from casing import title +from license import C_LICENSE_COMMENT + +class Printer(object): + def __init__(self): + self._fields = [] + + def start_file(self): + print(C_LICENSE_COMMENT + '/** @generated */') + + def end_file(self): + pass + + def start_type(self, name): + self._fields = [] + + def field(self, type, name, nullable, plural): + if type == 'OperationKind': + type = 'string' + self._fields.append((type, name, nullable, plural)) + + def end_type(self, name): + titleName = title(name) + anyFieldIsANode = any(type not in ('string, boolean') + for (type, _, _ ,_) in self._fields) + if anyFieldIsANode: + print('''bool JsonVisitor::visit%s(const %s &node) { + visitNode(); + return true; +} +''' % (titleName, titleName)) + print('''void JsonVisitor::endVisit%(tn)s(const %(tn)s &node) { + NodeFieldPrinter fields(*this, "%(tn)s", node);''' % {'tn': titleName}) + + for (type, fieldName, nullable, plural) in self._fields: + funcName = None + if type == 'string': + assert not plural, 'plural string fields not supported yet' + funcName = 'printSingularPrimitiveField' + elif type == 'boolean': + assert not plural, 'plural boolean fields not supported yet' + funcName = 'printSingularBooleanField' + elif not nullable and not plural: + # Special case: singular object fields don't need the value passed. + print(' fields.printSingularObjectField("%s");' % fieldName) + continue + else: + nullable_str = 'Nullable' if nullable else '' + plural_str = 'Plural' if plural else 'SingularObject' + funcName = 'print%s%sField' % (nullable_str, plural_str) + + assert funcName is not None + print(' fields.%s("%s", node.get%s());' % ( + funcName, fieldName, title(fieldName))) + + if anyFieldIsANode: + print(''' + endVisitNode(fields.finishPrinting()); +} +''') + else: + print(''' + printed_.back().emplace_back(fields.finishPrinting()); +} +''') + + def start_union(self, name): + pass + + def union_option(self, option): + pass + + def end_union(self, name): + pass diff --git a/ast/cxx_py3.py b/ast/cxx_py3.py new file mode 100644 index 0000000..cd868be --- /dev/null +++ b/ast/cxx_py3.py @@ -0,0 +1,197 @@ +# Copyright (c) 2015-present, Facebook, Inc. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import io as StringIO + +from casing import title +from license import C_LICENSE_COMMENT + +class Printer(object): + def __init__(self): + self._type_name = None + # Map concrete type to base class + self._bases = {} + # HACK: Defer everything we print so that forward declarations for + # all classes come first. Avoids having to do 2 passes over the + # input file. + self._deferredOutput = StringIO.StringIO() + + self._fields = [] + + def start_file(self): + print(C_LICENSE_COMMENT + '''/** @generated */ +#pragma once + +#include "AstNode.h" + +#include +#include +#include +#include + +namespace facebook { +namespace graphql { +namespace ast { + +// The parser uses strdup to move from yytext to the heap, so we need +// to use free instead of delete. +struct CDeleter { + void operator()(const char *p) const { free((void *)p); } +}; +''') + + def end_file(self): + print() + print(self._deferredOutput.getvalue()) + print('}') + print('}') + print('}') + + def _base_class(self, type): + return self._bases.get(type, 'Node') + + def start_type(self, name): + self._type_name = name + base = self._base_class(name) + # non-deferred! + print('class %s;' % name) + print('class %s : public %s {' % (name, base), file=self._deferredOutput) + self._fields = [] + + def field(self, type, name, nullable, plural): + if type == 'OperationKind': + type = 'string' + self._fields.append((type, name, nullable, plural)) + + def end_type(self, name): + self._print_fields() + print(' public:', file=self._deferredOutput) + self._print_constructor() + print(file=self._deferredOutput) + self._print_destructor_prototype() + print(file=self._deferredOutput) + self._print_noncopyable() + print(file=self._deferredOutput) + self._print_getters() + print(' void accept(visitor::AstVisitor *visitor) const override;', file=self._deferredOutput) + print('};', file=self._deferredOutput) + print(file=self._deferredOutput) + print(file=self._deferredOutput) + self._type_name = None + self._fields = [] + + def _storage_type(self, type): + if type == 'string': + return 'std::unique_ptr' + elif type == 'boolean': + return 'bool' + else: + return 'std::unique_ptr<%s>' % type + + def _print_fields(self): + for (type, name, nullable, plural) in self._fields: + storage_type = self._storage_type(type) + if plural: + storage_type = 'std::unique_ptr>' % storage_type + print(' %s %s_;' % (storage_type, name), file=self._deferredOutput) + + def _ctor_singular_type(self, type): + if type == 'string': + return 'const char *' + elif type == 'boolean': + return 'bool' + else: + return '%s *' % type + + def _ctor_plural_type(self, type): + return 'std::vector<%s> *' % self._storage_type(type) + + def _print_constructor(self): + print(' explicit %s(' % self._type_name, file=self._deferredOutput) + print(' const yy::location &location%s' % (',' if self._fields else ''), file=self._deferredOutput) + def ctor_arg(type, name, plural): + if plural: + ctor_type = self._ctor_plural_type(type) + else: + ctor_type = self._ctor_singular_type(type) + return ' %s %s' % (ctor_type, name) + print(',\n'.join(ctor_arg(type, name, plural) + for (type, name, nullable, plural) in self._fields), file=self._deferredOutput) + print(' )', file=self._deferredOutput) + def ctor_init(type, name, plural): + # Strings are const char *, just pass. + # Vectors are passed by pointer and we take ownership. + # Node types are passed in by pointer and we take ownership. + value = name + return ' %s_(%s)' % (name, value) + print(' : %s(location)%s' % (self._base_class(self._type_name), ',' if self._fields else ''), file=self._deferredOutput) + print(',\n'.join(ctor_init(type, name, plural) + for (type, name, nullable, plural) + in self._fields), file=self._deferredOutput) + print(' {}', file=self._deferredOutput) + + def _getter_type(self, type, nullable, plural): + if plural and nullable: + return 'const std::vector<%s>*' % self._storage_type(type) + elif plural: + return 'const std::vector<%s>&' % self._storage_type(type) + + if type == 'string': + assert not nullable + return 'const char *' + elif type == 'boolean': + assert not nullable + return 'bool' + elif nullable: + return 'const %s*' % type + else: + return 'const %s&' % type + + def _getter_value_to_return(self, raw_value, type, nullable, plural): + if plural and nullable: + return raw_value + '.get()' + elif plural: + return '*%s' % raw_value + elif type == 'boolean': + return raw_value + elif nullable or type == 'string': + return '%s.get()' % raw_value + else: + return '*%s' % raw_value + + def _print_getters(self): + for (type, name, nullable, plural) in self._fields: + print(' %s get%s() const' % ( + self._getter_type(type, nullable, plural), + title(name)), file=self._deferredOutput) + print(' { return %s; }' % ( + self._getter_value_to_return(name + '_', type, nullable, plural)), file=self._deferredOutput) + print(file=self._deferredOutput) + + def _print_destructor_prototype(self): + print(' ~%s() {}' % self._type_name, file=self._deferredOutput) + + def _print_noncopyable(self): + print(' %s(const %s&) = delete;' % ( + self._type_name, self._type_name), file=self._deferredOutput) + print(' %s& operator=(const %s&) = delete;' % ( + self._type_name, self._type_name), file=self._deferredOutput) + + def start_union(self, name): + self._type_name = name + # non-deferred! + print('class %s;' % name) + print('class %s : public Node {' % name, file=self._deferredOutput) + print(' public:', file=self._deferredOutput) + self._print_constructor() + print('};', file=self._deferredOutput) + print(file=self._deferredOutput) + + def union_option(self, type): + assert type not in self._bases, '%s cannot appear in more than one union!' % type + self._bases[type] = self._type_name + + def end_union(self, name): + pass diff --git a/ast/cxx_visitor_py3.py b/ast/cxx_visitor_py3.py new file mode 100644 index 0000000..ac15cae --- /dev/null +++ b/ast/cxx_visitor_py3.py @@ -0,0 +1,64 @@ +# Copyright (c) 2015-present, Facebook, Inc. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from casing import camel, title +from license import C_LICENSE_COMMENT + +class Printer(object): + def __init__(self): + pass + + def start_file(self): + print(C_LICENSE_COMMENT + '''/** @generated */ + +#pragma once + +#include "Ast.h" + +namespace facebook { +namespace graphql { +namespace ast { +namespace visitor { + +class AstVisitor { +public: + virtual ~AstVisitor() {} +''') + + def end_file(self): + print('};') # end AstVisitor + print() + print('}') + print('}') + print('}') + print('}') + + def start_type(self, name): + titleName = title(name) + camelName = camel(titleName) + print(' virtual bool visit%s(const %s &%s) { return true; }' % ( + titleName, + titleName, + camelName)) + print(' virtual void endVisit%s(const %s &%s) { }' % ( + titleName, + titleName, + camelName)) + print() + + def end_type(self, name): + pass + + def field(self, type, name, nullable, plural): + pass + + def start_union(self, name): + pass + + def union_option(self, option): + pass + + def end_union(self, name): + pass diff --git a/ast/js_py3.py b/ast/js_py3.py new file mode 100644 index 0000000..68aee6e --- /dev/null +++ b/ast/js_py3.py @@ -0,0 +1,65 @@ +# Copyright (c) 2015-present, Facebook, Inc. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +class Printer(object): + def __init__(self): + pass + + def start_file(self): + print('''/* @flow */ +/* @generated */ +/* jshint ignore:start */ + +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +type Node = { + kind: string; + start?: ?number; + end?: ?number; +}; + +type OperationKind = 'query' | 'mutation' | 'subscription';''') + + def end_file(self): + pass + + def start_type(self, name): + print() + print('type %s = Node & {' % name) + kind = name + if kind == 'GenericType': + kind = 'Type' + print(' kind: \'%s\';' % kind) + + def end_type(self, name): + print('}') + + def _js_type(self, type, plural): + if plural: + type = 'Array<%s>' % type + return type + + def field(self, type, name, nullable, plural): + nullable_char = '?' if nullable else '' + js_type = self._js_type(type, plural) + print(' %(name)s%(nullable_char)s: %(nullable_char)s%(js_type)s;' % locals()) + + def start_union(self, name): + print(('type %s = ' % name), end=' ') + self._current_options = [] + + def union_option(self, type): + self._current_options.append(type) + + def end_union(self, name): + print('\n | '.join(self._current_options)) + print() + self._current_options = None From f42c7bc6564e66253348058e8c66696d3b6e9dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20=27Bubu=27=20Busi?= Date: Tue, 10 Jul 2018 09:42:28 +0200 Subject: [PATCH 2/4] fix(ident): fix mismatch identation. --- ast/ast.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ast/ast.py b/ast/ast.py index 99ce1d9..39c6471 100644 --- a/ast/ast.py +++ b/ast/ast.py @@ -56,10 +56,10 @@ def print_ast(lang_module, input_file): lang = sys.argv[1] try: - if sys.version_info >= (3,0): - lang = "%s_py3" % lang + if sys.version_info >= (3,0): + lang = "%s_py3" % lang except: - pass + pass filename = sys.argv[2] From 3e6d39401b23889615eaecfa8ae98fe3cd0f04df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20=27Bubu=27=20Busi?= Date: Thu, 6 Sep 2018 10:47:50 +0200 Subject: [PATCH 3/4] Make ast python code usable in python2 or python3 --- ast/ast.py | 8 +- ast/c.py | 20 +-- ast/c_impl.py | 19 +-- ast/c_impl_py3.py | 61 --------- ast/c_py3.py | 100 --------------- ast/c_visitor_impl.py | 8 +- ast/c_visitor_impl_py3.py | 39 ------ ast/cxx.py | 93 +++++++------- ast/cxx_impl.py | 26 ++-- ast/cxx_impl_py3.py | 61 --------- ast/cxx_json_visitor_header.py | 10 +- ast/cxx_json_visitor_header_py3.py | 42 ------ ast/cxx_json_visitor_impl.py | 26 ++-- ast/cxx_json_visitor_impl_py3.py | 80 ------------ ast/cxx_py3.py | 197 ----------------------------- ast/cxx_visitor.py | 28 ++-- ast/cxx_visitor_py3.py | 64 ---------- ast/js.py | 22 ++-- ast/js_py3.py | 65 ---------- 19 files changed, 129 insertions(+), 840 deletions(-) delete mode 100644 ast/c_impl_py3.py delete mode 100644 ast/c_py3.py delete mode 100644 ast/c_visitor_impl_py3.py delete mode 100644 ast/cxx_impl_py3.py delete mode 100644 ast/cxx_json_visitor_header_py3.py delete mode 100644 ast/cxx_json_visitor_impl_py3.py delete mode 100644 ast/cxx_py3.py delete mode 100644 ast/cxx_visitor_py3.py delete mode 100644 ast/js_py3.py diff --git a/ast/ast.py b/ast/ast.py index 39c6471..1ba028e 100644 --- a/ast/ast.py +++ b/ast/ast.py @@ -53,14 +53,8 @@ def print_ast(lang_module, input_file): lang_module.end_file() if __name__ == '__main__': import sys - lang = sys.argv[1] - - try: - if sys.version_info >= (3,0): - lang = "%s_py3" % lang - except: - pass + lang = sys.argv[1] filename = sys.argv[2] lang_module = load_lang(lang) diff --git a/ast/c.py b/ast/c.py index 836a67d..5d2b6ac 100644 --- a/ast/c.py +++ b/ast/c.py @@ -2,7 +2,7 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. - +from __future__ import print_function from casing import snake from license import C_LICENSE_COMMENT @@ -60,7 +60,7 @@ def __init__(self): self._current_type = None def start_file(self): - print C_LICENSE_COMMENT + '''/** @generated */ + print(C_LICENSE_COMMENT + '''/** @generated */ #pragma once @@ -68,33 +68,33 @@ def start_file(self): extern "C" { #endif -''' +''') def end_file(self): - print ''' + print(''' #ifdef __cplusplus } #endif -''' +''') def start_type(self, name): # Forward declarations for AST nodes. st_name = struct_name(name) - print 'struct ' + st_name + ';' + print('struct ' + st_name + ';') self._current_type = name def field(self, type, name, nullable, plural): - print field_prototype(self._current_type, type, name, nullable, plural) + ';' + print(field_prototype(self._current_type, type, name, nullable, plural) + ';') def end_type(self, name): - print + print() def start_union(self, name): - print 'struct ' + struct_name(name) + ';' + print('struct ' + struct_name(name) + ';') def union_option(self, option): pass def end_union(self, name): - print + print() diff --git a/ast/c_impl.py b/ast/c_impl.py index 5ff3c30..bfc1d68 100644 --- a/ast/c_impl.py +++ b/ast/c_impl.py @@ -2,6 +2,7 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from __future__ import print_function from c import field_prototype, return_type, struct_name from casing import title @@ -15,13 +16,13 @@ def __init__(self): self._current_type = None def start_file(self): - print C_LICENSE_COMMENT + '''/** @generated */ + print(C_LICENSE_COMMENT + '''/** @generated */ #include "GraphQLAst.h" #include "../Ast.h" using namespace facebook::graphql::ast; // NOLINT -''' +''') def end_file(self): pass @@ -30,23 +31,23 @@ def start_type(self, name): self._current_type = name def field(self, type, name, nullable, plural): - print field_prototype(self._current_type, type, name, nullable, plural) + ' {' - print ' const auto *realNode = reinterpret_cast(node);' % self._current_type + print(field_prototype(self._current_type, type, name, nullable, plural) + ' {') + print(' const auto *realNode = reinterpret_cast(node);' % self._current_type) title_name = title(name) call_get = 'realNode->get%s()' % title_name if plural: if nullable: - print ' return %s ? %s->size() : 0;' % (call_get, call_get) + print(' return %s ? %s->size() : 0;' % (call_get, call_get)) else: - print ' return %s.size();' % call_get + print(' return %s.size();' % call_get) else: if type in ['string', 'OperationKind', 'boolean']: - print ' return %s;' % call_get + print(' return %s;' % call_get) else: fmt = ' return reinterpret_cast(%s%s);' - print fmt % (struct_name(type), '' if nullable else '&', call_get) + print(fmt % (struct_name(type), '' if nullable else '&', call_get)) - print '}' + print('}') def end_type(self, name): pass diff --git a/ast/c_impl_py3.py b/ast/c_impl_py3.py deleted file mode 100644 index aa17765..0000000 --- a/ast/c_impl_py3.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (c) 2015-present, Facebook, Inc. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -from c_py3 import field_prototype, return_type, struct_name -from casing import title -from license import C_LICENSE_COMMENT - -class Printer(object): - '''Printer for the implementation of the pure C interface to the AST. - ''' - - def __init__(self): - self._current_type = None - - def start_file(self): - print(C_LICENSE_COMMENT + '''/** @generated */ - -#include "GraphQLAst.h" -#include "../Ast.h" - -using namespace facebook::graphql::ast; // NOLINT -''') - - def end_file(self): - pass - - def start_type(self, name): - self._current_type = name - - def field(self, type, name, nullable, plural): - print(field_prototype(self._current_type, type, name, nullable, plural) + ' {') - print(' const auto *realNode = reinterpret_cast(node);' % self._current_type) - title_name = title(name) - call_get = 'realNode->get%s()' % title_name - if plural: - if nullable: - print(' return %s ? %s->size() : 0;' % (call_get, call_get)) - else: - print(' return %s.size();' % call_get) - else: - if type in ['string', 'OperationKind', 'boolean']: - print(' return %s;' % call_get) - else: - fmt = ' return reinterpret_cast(%s%s);' - print(fmt % (struct_name(type), '' if nullable else '&', call_get)) - - print('}') - - def end_type(self, name): - pass - - def start_union(self, name): - pass - - def union_option(self, option): - pass - - def end_union(self, name): - pass diff --git a/ast/c_py3.py b/ast/c_py3.py deleted file mode 100644 index bbcb653..0000000 --- a/ast/c_py3.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright (c) 2015-present, Facebook, Inc. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -from casing import snake - -from license import C_LICENSE_COMMENT - -def struct_name(type): - return 'GraphQLAst' + type - - -def return_type(type): - if type == 'OperationKind' or type == 'string': - return 'const char *' - - if type == 'boolean': - return 'int' - - return 'const struct %s *' % struct_name(type) - - -def field_prototype(owning_type, type, name, nullable, plural): - st_name = struct_name(owning_type) - if plural: - return 'int %s_get_%s_size(const struct %s *node)' % ( - st_name, snake(name), st_name) - else: - ret_type = return_type(type) - return '%s %s_get_%s(const struct %s *node)' % ( - ret_type, st_name, snake(name), st_name) - - -class Printer(object): - '''Printer for the pure C interface to the AST. - - Merely a set of wrappers around the C++ interface; makes it possible - to use the AST from C code and simplifies the task of writing - bindings for other langugages. - - The mapping is as follows: - - - For each concrete type, you get an opaque C struct type, - accessible only by pointer. - - - For each singular field of a concrete type, you get an accessor - function, returning said field in the obvious way. - - - For each plural field of a concrete type, you get an accessor - function telling you its size. For access to elements of a plural - field, you can use the visitor API. - - - For each union type, you get nothing specific (REVIEW), but you - can use the visitor API to work around this entirely. - - ''' - - def __init__(self): - self._current_type = None - - def start_file(self): - print(C_LICENSE_COMMENT + '''/** @generated */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -''') - - def end_file(self): - print(''' - -#ifdef __cplusplus -} -#endif -''') - - def start_type(self, name): - # Forward declarations for AST nodes. - st_name = struct_name(name) - print('struct ' + st_name + ';') - self._current_type = name - - def field(self, type, name, nullable, plural): - print(field_prototype(self._current_type, type, name, nullable, plural) + ';') - - def end_type(self, name): - print() - - def start_union(self, name): - print('struct ' + struct_name(name) + ';') - - def union_option(self, option): - pass - - def end_union(self, name): - print() diff --git a/ast/c_visitor_impl.py b/ast/c_visitor_impl.py index aac56b2..ff91a30 100644 --- a/ast/c_visitor_impl.py +++ b/ast/c_visitor_impl.py @@ -2,7 +2,7 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. - +from __future__ import print_function from casing import snake from license import C_LICENSE_COMMENT @@ -14,8 +14,8 @@ def __init__(self): self._types = [] def start_file(self): - print C_LICENSE_COMMENT + '/** @generated */' - print '#define FOR_EACH_CONCRETE_TYPE(MACRO) \\' + print(C_LICENSE_COMMENT + '/** @generated */') + print('#define FOR_EACH_CONCRETE_TYPE(MACRO) \\') def start_type(self, name): self._types.append(name) @@ -27,7 +27,7 @@ def end_type(self, name): pass def end_file(self): - print ' \\\n'.join('MACRO(%s, %s)' % (name, snake(name)) for name in self._types) + print(' \\\n'.join('MACRO(%s, %s)' % (name, snake(name)) for name in self._types)) def start_union(self, name): pass diff --git a/ast/c_visitor_impl_py3.py b/ast/c_visitor_impl_py3.py deleted file mode 100644 index bbf84f0..0000000 --- a/ast/c_visitor_impl_py3.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2015-present, Facebook, Inc. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -from casing import snake -from license import C_LICENSE_COMMENT - -class Printer(object): - '''Printer for a simple list of types to be visited by the C visitor. - ''' - - def __init__(self): - self._types = [] - - def start_file(self): - print(C_LICENSE_COMMENT + '/** @generated */') - print('#define FOR_EACH_CONCRETE_TYPE(MACRO) \\') - - def start_type(self, name): - self._types.append(name) - - def field(self, type, name, nullable, plural): - pass - - def end_type(self, name): - pass - - def end_file(self): - print(' \\\n'.join('MACRO(%s, %s)' % (name, snake(name)) for name in self._types)) - - def start_union(self, name): - pass - - def union_option(self, option): - pass - - def end_union(self, name): - pass diff --git a/ast/cxx.py b/ast/cxx.py index 81a1bf5..aa0f9c1 100644 --- a/ast/cxx.py +++ b/ast/cxx.py @@ -2,8 +2,11 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. - -import cStringIO as StringIO +from __future__ import print_function +try: + import cStringIO as StringIO +except ImportError: + import io as StringIO from casing import title from license import C_LICENSE_COMMENT @@ -21,7 +24,7 @@ def __init__(self): self._fields = [] def start_file(self): - print C_LICENSE_COMMENT + '''/** @generated */ + print(C_LICENSE_COMMENT + '''/** @generated */ #pragma once #include "AstNode.h" @@ -40,14 +43,14 @@ def start_file(self): struct CDeleter { void operator()(const char *p) const { free((void *)p); } }; -''' +''') def end_file(self): - print - print self._deferredOutput.getvalue() - print '}' - print '}' - print '}' + print() + print(self._deferredOutput.getvalue()) + print('}') + print('}') + print('}') def _base_class(self, type): return self._bases.get(type, 'Node') @@ -56,8 +59,8 @@ def start_type(self, name): self._type_name = name base = self._base_class(name) # non-deferred! - print 'class %s;' % name - print >> self._deferredOutput, 'class %s : public %s {' % (name, base) + print('class %s;' % name) + print('class %s : public %s {' % (name, base), file=self._deferredOutput) self._fields = [] def field(self, type, name, nullable, plural): @@ -67,18 +70,18 @@ def field(self, type, name, nullable, plural): def end_type(self, name): self._print_fields() - print >> self._deferredOutput, ' public:' + print(' public:', file=self._deferredOutput) self._print_constructor() - print >> self._deferredOutput + print(file=self._deferredOutput) self._print_destructor_prototype() - print >> self._deferredOutput + print(file=self._deferredOutput) self._print_noncopyable() - print >> self._deferredOutput + print(file=self._deferredOutput) self._print_getters() - print >> self._deferredOutput, ' void accept(visitor::AstVisitor *visitor) const override;' - print >> self._deferredOutput, '};' - print >> self._deferredOutput - print >> self._deferredOutput + print(' void accept(visitor::AstVisitor *visitor) const override;', file=self._deferredOutput) + print('};', file=self._deferredOutput) + print(file=self._deferredOutput) + print(file=self._deferredOutput) self._type_name = None self._fields = [] @@ -95,7 +98,7 @@ def _print_fields(self): storage_type = self._storage_type(type) if plural: storage_type = 'std::unique_ptr>' % storage_type - print >> self._deferredOutput, ' %s %s_;' % (storage_type, name) + print(' %s %s_;' % (storage_type, name), file=self._deferredOutput) def _ctor_singular_type(self, type): if type == 'string': @@ -109,28 +112,28 @@ def _ctor_plural_type(self, type): return 'std::vector<%s> *' % self._storage_type(type) def _print_constructor(self): - print >> self._deferredOutput, ' explicit %s(' % self._type_name - print >> self._deferredOutput, ' const yy::location &location%s' % (',' if self._fields else '') + print(' explicit %s(' % self._type_name, file=self._deferredOutput) + print(' const yy::location &location%s' % (',' if self._fields else ''), file=self._deferredOutput) def ctor_arg(type, name, plural): if plural: ctor_type = self._ctor_plural_type(type) else: ctor_type = self._ctor_singular_type(type) return ' %s %s' % (ctor_type, name) - print >> self._deferredOutput, ',\n'.join(ctor_arg(type, name, plural) - for (type, name, nullable, plural) in self._fields) - print >> self._deferredOutput, ' )' + print(',\n'.join(ctor_arg(type, name, plural) + for (type, name, nullable, plural) in self._fields), file=self._deferredOutput) + print(' )', file=self._deferredOutput) def ctor_init(type, name, plural): # Strings are const char *, just pass. # Vectors are passed by pointer and we take ownership. # Node types are passed in by pointer and we take ownership. value = name return ' %s_(%s)' % (name, value) - print >> self._deferredOutput, ' : %s(location)%s' % (self._base_class(self._type_name), ',' if self._fields else '') - print >> self._deferredOutput, ',\n'.join(ctor_init(type, name, plural) + print(' : %s(location)%s' % (self._base_class(self._type_name), ',' if self._fields else ''), file=self._deferredOutput) + print(',\n'.join(ctor_init(type, name, plural) for (type, name, nullable, plural) - in self._fields) - print >> self._deferredOutput, ' {}' + in self._fields), file=self._deferredOutput) + print(' {}', file=self._deferredOutput) def _getter_type(self, type, nullable, plural): if plural and nullable: @@ -163,31 +166,31 @@ def _getter_value_to_return(self, raw_value, type, nullable, plural): def _print_getters(self): for (type, name, nullable, plural) in self._fields: - print >> self._deferredOutput, ' %s get%s() const' % ( + print(' %s get%s() const' % ( self._getter_type(type, nullable, plural), - title(name)) - print >> self._deferredOutput, ' { return %s; }' % ( - self._getter_value_to_return(name + '_', type, nullable, plural)) - print >> self._deferredOutput + title(name)), file=self._deferredOutput) + print(' { return %s; }' % ( + self._getter_value_to_return(name + '_', type, nullable, plural)), file=self._deferredOutput) + print(file=self._deferredOutput) def _print_destructor_prototype(self): - print >> self._deferredOutput, ' ~%s() {}' % self._type_name + print(' ~%s() {}' % self._type_name, file=self._deferredOutput) def _print_noncopyable(self): - print >> self._deferredOutput, ' %s(const %s&) = delete;' % ( - self._type_name, self._type_name) - print >> self._deferredOutput, ' %s& operator=(const %s&) = delete;' % ( - self._type_name, self._type_name) - + print(' %s(const %s&) = delete;' % ( + self._type_name, self._type_name), file=self._deferredOutput) + print(' %s& operator=(const %s&) = delete;' % ( + self._type_name, self._type_name), file=self._deferredOutput) + def start_union(self, name): self._type_name = name # non-deferred! - print 'class %s;' % name - print >> self._deferredOutput, 'class %s : public Node {' % name - print >> self._deferredOutput, ' public:' + print('class %s;' % name) + print('class %s : public Node {' % name, file=self._deferredOutput) + print(' public:', file=self._deferredOutput) self._print_constructor() - print >> self._deferredOutput, '};' - print >> self._deferredOutput + print('};', file=self._deferredOutput) + print(file=self._deferredOutput) def union_option(self, type): assert type not in self._bases, '%s cannot appear in more than one union!' % type diff --git a/ast/cxx_impl.py b/ast/cxx_impl.py index 7f1b989..60ea325 100644 --- a/ast/cxx_impl.py +++ b/ast/cxx_impl.py @@ -2,7 +2,7 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. - +from __future__ import print_function from license import C_LICENSE_COMMENT class Printer(object): @@ -10,7 +10,7 @@ def __init__(self): pass def start_file(self): - print C_LICENSE_COMMENT + '''/** @generated */ + print(C_LICENSE_COMMENT + '''/** @generated */ #include "Ast.h" #include "AstVisitor.h" @@ -18,38 +18,38 @@ def start_file(self): namespace facebook { namespace graphql { namespace ast { -''' +''') def end_file(self): - print '} // namespace ast' - print '} // namespace graphql' - print '} // namespace facebook' + print('} // namespace ast') + print('} // namespace graphql') + print('} // namespace facebook') def start_type(self, name): - print '''void %s::accept(visitor::AstVisitor *visitor) const { + print('''void %s::accept(visitor::AstVisitor *visitor) const { if (visitor->visit%s(*this)) { -''' % (name, name) +''' % (name, name)) def field(self, type, name, nullable, plural): if type in ['OperationKind', 'string', 'boolean']: return - + if plural: accept = '{ for (const auto &x : *%s_) { x->accept(visitor); } }' % name if nullable: accept = 'if (%s_) %s' % (name, accept) - print ' ' + accept + print(' ' + accept) else: accept = '%s_->accept(visitor);' % name if nullable: accept = 'if (%s_) { %s }' % (name, accept) - print ' ' + accept + print(' ' + accept) def end_type(self, name): - print ''' } + print(''' } visitor->endVisit%s(*this); } -''' % name +''' % name) def start_union(self, name): pass diff --git a/ast/cxx_impl_py3.py b/ast/cxx_impl_py3.py deleted file mode 100644 index 299ed74..0000000 --- a/ast/cxx_impl_py3.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (c) 2015-present, Facebook, Inc. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -from license import C_LICENSE_COMMENT - -class Printer(object): - def __init__(self): - pass - - def start_file(self): - print(C_LICENSE_COMMENT + '''/** @generated */ - -#include "Ast.h" -#include "AstVisitor.h" - -namespace facebook { -namespace graphql { -namespace ast { -''') - - def end_file(self): - print('} // namespace ast') - print('} // namespace graphql') - print('} // namespace facebook') - - def start_type(self, name): - print('''void %s::accept(visitor::AstVisitor *visitor) const { - if (visitor->visit%s(*this)) { -''' % (name, name)) - - def field(self, type, name, nullable, plural): - if type in ['OperationKind', 'string', 'boolean']: - return - - if plural: - accept = '{ for (const auto &x : *%s_) { x->accept(visitor); } }' % name - if nullable: - accept = 'if (%s_) %s' % (name, accept) - print(' ' + accept) - else: - accept = '%s_->accept(visitor);' % name - if nullable: - accept = 'if (%s_) { %s }' % (name, accept) - print(' ' + accept) - - def end_type(self, name): - print(''' } - visitor->endVisit%s(*this); -} -''' % name) - - def start_union(self, name): - pass - - def union_option(self, option): - pass - - def end_union(self, name): - pass diff --git a/ast/cxx_json_visitor_header.py b/ast/cxx_json_visitor_header.py index 2f8a02a..0e37679 100644 --- a/ast/cxx_json_visitor_header.py +++ b/ast/cxx_json_visitor_header.py @@ -3,7 +3,7 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. - +from __future__ import print_function from casing import title from license import C_LICENSE_COMMENT @@ -12,7 +12,7 @@ def __init__(self): self._anyFieldIsANode = False def start_file(self): - print C_LICENSE_COMMENT + '/** @generated */' + print(C_LICENSE_COMMENT + '/** @generated */') def end_file(self): pass @@ -23,9 +23,9 @@ def start_type(self, name): def end_type(self, name): titleName = title(name) if self._anyFieldIsANode: - print 'bool visit%s(const %s &node) override;' % (titleName, titleName) - print 'void endVisit%s(const %s &node) override;' % (titleName, titleName) - print + print('bool visit%s(const %s &node) override;' % (titleName, titleName)) + print('void endVisit%s(const %s &node) override;' % (titleName, titleName)) + print() def field(self, type, name, nullable, plural): if (not self._anyFieldIsANode and diff --git a/ast/cxx_json_visitor_header_py3.py b/ast/cxx_json_visitor_header_py3.py deleted file mode 100644 index 8ce7349..0000000 --- a/ast/cxx_json_visitor_header_py3.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2016-present, Facebook, Inc. -# All rights reserved. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -from casing import title -from license import C_LICENSE_COMMENT - -class Printer(object): - def __init__(self): - self._anyFieldIsANode = False - - def start_file(self): - print(C_LICENSE_COMMENT + '/** @generated */') - - def end_file(self): - pass - - def start_type(self, name): - self._anyFieldIsANode = False - - def end_type(self, name): - titleName = title(name) - if self._anyFieldIsANode: - print('bool visit%s(const %s &node) override;' % (titleName, titleName)) - print('void endVisit%s(const %s &node) override;' % (titleName, titleName)) - print() - - def field(self, type, name, nullable, plural): - if (not self._anyFieldIsANode and - type not in ('OperationKind', 'string', 'boolean')): - self._anyFieldIsANode = True - - def start_union(self, name): - pass - - def union_option(self, option): - pass - - def end_union(self, name): - pass diff --git a/ast/cxx_json_visitor_impl.py b/ast/cxx_json_visitor_impl.py index db8f9ab..91d2548 100644 --- a/ast/cxx_json_visitor_impl.py +++ b/ast/cxx_json_visitor_impl.py @@ -3,7 +3,7 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. - +from __future__ import print_function from casing import title from license import C_LICENSE_COMMENT @@ -12,7 +12,7 @@ def __init__(self): self._fields = [] def start_file(self): - print C_LICENSE_COMMENT + '/** @generated */' + print(C_LICENSE_COMMENT + '/** @generated */') def end_file(self): pass @@ -30,13 +30,13 @@ def end_type(self, name): anyFieldIsANode = any(type not in ('string, boolean') for (type, _, _ ,_) in self._fields) if anyFieldIsANode: - print '''bool JsonVisitor::visit%s(const %s &node) { + print('''bool JsonVisitor::visit%s(const %s &node) { visitNode(); return true; } -''' % (titleName, titleName) - print '''void JsonVisitor::endVisit%(tn)s(const %(tn)s &node) { - NodeFieldPrinter fields(*this, "%(tn)s", node);''' % {'tn': titleName} +''' % (titleName, titleName)) + print('''void JsonVisitor::endVisit%(tn)s(const %(tn)s &node) { + NodeFieldPrinter fields(*this, "%(tn)s", node);''' % {'tn': titleName}) for (type, fieldName, nullable, plural) in self._fields: funcName = None @@ -48,7 +48,7 @@ def end_type(self, name): funcName = 'printSingularBooleanField' elif not nullable and not plural: # Special case: singular object fields don't need the value passed. - print ' fields.printSingularObjectField("%s");' % fieldName + print(' fields.printSingularObjectField("%s");' % fieldName) continue else: nullable_str = 'Nullable' if nullable else '' @@ -56,19 +56,19 @@ def end_type(self, name): funcName = 'print%s%sField' % (nullable_str, plural_str) assert funcName is not None - print ' fields.%s("%s", node.get%s());' % ( - funcName, fieldName, title(fieldName)) + print(' fields.%s("%s", node.get%s());' % ( + funcName, fieldName, title(fieldName))) if anyFieldIsANode: - print ''' + print(''' endVisitNode(fields.finishPrinting()); } -''' +''') else: - print ''' + print(''' printed_.back().emplace_back(fields.finishPrinting()); } -''' +''') def start_union(self, name): pass diff --git a/ast/cxx_json_visitor_impl_py3.py b/ast/cxx_json_visitor_impl_py3.py deleted file mode 100644 index c96efdf..0000000 --- a/ast/cxx_json_visitor_impl_py3.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (c) 2016-present, Facebook, Inc. -# All rights reserved. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -from casing import title -from license import C_LICENSE_COMMENT - -class Printer(object): - def __init__(self): - self._fields = [] - - def start_file(self): - print(C_LICENSE_COMMENT + '/** @generated */') - - def end_file(self): - pass - - def start_type(self, name): - self._fields = [] - - def field(self, type, name, nullable, plural): - if type == 'OperationKind': - type = 'string' - self._fields.append((type, name, nullable, plural)) - - def end_type(self, name): - titleName = title(name) - anyFieldIsANode = any(type not in ('string, boolean') - for (type, _, _ ,_) in self._fields) - if anyFieldIsANode: - print('''bool JsonVisitor::visit%s(const %s &node) { - visitNode(); - return true; -} -''' % (titleName, titleName)) - print('''void JsonVisitor::endVisit%(tn)s(const %(tn)s &node) { - NodeFieldPrinter fields(*this, "%(tn)s", node);''' % {'tn': titleName}) - - for (type, fieldName, nullable, plural) in self._fields: - funcName = None - if type == 'string': - assert not plural, 'plural string fields not supported yet' - funcName = 'printSingularPrimitiveField' - elif type == 'boolean': - assert not plural, 'plural boolean fields not supported yet' - funcName = 'printSingularBooleanField' - elif not nullable and not plural: - # Special case: singular object fields don't need the value passed. - print(' fields.printSingularObjectField("%s");' % fieldName) - continue - else: - nullable_str = 'Nullable' if nullable else '' - plural_str = 'Plural' if plural else 'SingularObject' - funcName = 'print%s%sField' % (nullable_str, plural_str) - - assert funcName is not None - print(' fields.%s("%s", node.get%s());' % ( - funcName, fieldName, title(fieldName))) - - if anyFieldIsANode: - print(''' - endVisitNode(fields.finishPrinting()); -} -''') - else: - print(''' - printed_.back().emplace_back(fields.finishPrinting()); -} -''') - - def start_union(self, name): - pass - - def union_option(self, option): - pass - - def end_union(self, name): - pass diff --git a/ast/cxx_py3.py b/ast/cxx_py3.py deleted file mode 100644 index cd868be..0000000 --- a/ast/cxx_py3.py +++ /dev/null @@ -1,197 +0,0 @@ -# Copyright (c) 2015-present, Facebook, Inc. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import io as StringIO - -from casing import title -from license import C_LICENSE_COMMENT - -class Printer(object): - def __init__(self): - self._type_name = None - # Map concrete type to base class - self._bases = {} - # HACK: Defer everything we print so that forward declarations for - # all classes come first. Avoids having to do 2 passes over the - # input file. - self._deferredOutput = StringIO.StringIO() - - self._fields = [] - - def start_file(self): - print(C_LICENSE_COMMENT + '''/** @generated */ -#pragma once - -#include "AstNode.h" - -#include -#include -#include -#include - -namespace facebook { -namespace graphql { -namespace ast { - -// The parser uses strdup to move from yytext to the heap, so we need -// to use free instead of delete. -struct CDeleter { - void operator()(const char *p) const { free((void *)p); } -}; -''') - - def end_file(self): - print() - print(self._deferredOutput.getvalue()) - print('}') - print('}') - print('}') - - def _base_class(self, type): - return self._bases.get(type, 'Node') - - def start_type(self, name): - self._type_name = name - base = self._base_class(name) - # non-deferred! - print('class %s;' % name) - print('class %s : public %s {' % (name, base), file=self._deferredOutput) - self._fields = [] - - def field(self, type, name, nullable, plural): - if type == 'OperationKind': - type = 'string' - self._fields.append((type, name, nullable, plural)) - - def end_type(self, name): - self._print_fields() - print(' public:', file=self._deferredOutput) - self._print_constructor() - print(file=self._deferredOutput) - self._print_destructor_prototype() - print(file=self._deferredOutput) - self._print_noncopyable() - print(file=self._deferredOutput) - self._print_getters() - print(' void accept(visitor::AstVisitor *visitor) const override;', file=self._deferredOutput) - print('};', file=self._deferredOutput) - print(file=self._deferredOutput) - print(file=self._deferredOutput) - self._type_name = None - self._fields = [] - - def _storage_type(self, type): - if type == 'string': - return 'std::unique_ptr' - elif type == 'boolean': - return 'bool' - else: - return 'std::unique_ptr<%s>' % type - - def _print_fields(self): - for (type, name, nullable, plural) in self._fields: - storage_type = self._storage_type(type) - if plural: - storage_type = 'std::unique_ptr>' % storage_type - print(' %s %s_;' % (storage_type, name), file=self._deferredOutput) - - def _ctor_singular_type(self, type): - if type == 'string': - return 'const char *' - elif type == 'boolean': - return 'bool' - else: - return '%s *' % type - - def _ctor_plural_type(self, type): - return 'std::vector<%s> *' % self._storage_type(type) - - def _print_constructor(self): - print(' explicit %s(' % self._type_name, file=self._deferredOutput) - print(' const yy::location &location%s' % (',' if self._fields else ''), file=self._deferredOutput) - def ctor_arg(type, name, plural): - if plural: - ctor_type = self._ctor_plural_type(type) - else: - ctor_type = self._ctor_singular_type(type) - return ' %s %s' % (ctor_type, name) - print(',\n'.join(ctor_arg(type, name, plural) - for (type, name, nullable, plural) in self._fields), file=self._deferredOutput) - print(' )', file=self._deferredOutput) - def ctor_init(type, name, plural): - # Strings are const char *, just pass. - # Vectors are passed by pointer and we take ownership. - # Node types are passed in by pointer and we take ownership. - value = name - return ' %s_(%s)' % (name, value) - print(' : %s(location)%s' % (self._base_class(self._type_name), ',' if self._fields else ''), file=self._deferredOutput) - print(',\n'.join(ctor_init(type, name, plural) - for (type, name, nullable, plural) - in self._fields), file=self._deferredOutput) - print(' {}', file=self._deferredOutput) - - def _getter_type(self, type, nullable, plural): - if plural and nullable: - return 'const std::vector<%s>*' % self._storage_type(type) - elif plural: - return 'const std::vector<%s>&' % self._storage_type(type) - - if type == 'string': - assert not nullable - return 'const char *' - elif type == 'boolean': - assert not nullable - return 'bool' - elif nullable: - return 'const %s*' % type - else: - return 'const %s&' % type - - def _getter_value_to_return(self, raw_value, type, nullable, plural): - if plural and nullable: - return raw_value + '.get()' - elif plural: - return '*%s' % raw_value - elif type == 'boolean': - return raw_value - elif nullable or type == 'string': - return '%s.get()' % raw_value - else: - return '*%s' % raw_value - - def _print_getters(self): - for (type, name, nullable, plural) in self._fields: - print(' %s get%s() const' % ( - self._getter_type(type, nullable, plural), - title(name)), file=self._deferredOutput) - print(' { return %s; }' % ( - self._getter_value_to_return(name + '_', type, nullable, plural)), file=self._deferredOutput) - print(file=self._deferredOutput) - - def _print_destructor_prototype(self): - print(' ~%s() {}' % self._type_name, file=self._deferredOutput) - - def _print_noncopyable(self): - print(' %s(const %s&) = delete;' % ( - self._type_name, self._type_name), file=self._deferredOutput) - print(' %s& operator=(const %s&) = delete;' % ( - self._type_name, self._type_name), file=self._deferredOutput) - - def start_union(self, name): - self._type_name = name - # non-deferred! - print('class %s;' % name) - print('class %s : public Node {' % name, file=self._deferredOutput) - print(' public:', file=self._deferredOutput) - self._print_constructor() - print('};', file=self._deferredOutput) - print(file=self._deferredOutput) - - def union_option(self, type): - assert type not in self._bases, '%s cannot appear in more than one union!' % type - self._bases[type] = self._type_name - - def end_union(self, name): - pass diff --git a/ast/cxx_visitor.py b/ast/cxx_visitor.py index 91aa0b5..cbbfbc0 100644 --- a/ast/cxx_visitor.py +++ b/ast/cxx_visitor.py @@ -2,7 +2,7 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. - +from __future__ import print_function from casing import camel, title from license import C_LICENSE_COMMENT @@ -11,7 +11,7 @@ def __init__(self): pass def start_file(self): - print C_LICENSE_COMMENT + '''/** @generated */ + print(C_LICENSE_COMMENT + '''/** @generated */ #pragma once @@ -25,28 +25,28 @@ def start_file(self): class AstVisitor { public: virtual ~AstVisitor() {} -''' +''') def end_file(self): - print '};' # end AstVisitor - print - print '}' - print '}' - print '}' - print '}' + print('};') # end AstVisitor + print() + print('}') + print('}') + print('}') + print('}') def start_type(self, name): titleName = title(name) camelName = camel(titleName) - print ' virtual bool visit%s(const %s &%s) { return true; }' % ( + print(' virtual bool visit%s(const %s &%s) { return true; }' % ( titleName, titleName, - camelName) - print ' virtual void endVisit%s(const %s &%s) { }' % ( + camelName)) + print(' virtual void endVisit%s(const %s &%s) { }' % ( titleName, titleName, - camelName) - print + camelName)) + print() def end_type(self, name): pass diff --git a/ast/cxx_visitor_py3.py b/ast/cxx_visitor_py3.py deleted file mode 100644 index ac15cae..0000000 --- a/ast/cxx_visitor_py3.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright (c) 2015-present, Facebook, Inc. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -from casing import camel, title -from license import C_LICENSE_COMMENT - -class Printer(object): - def __init__(self): - pass - - def start_file(self): - print(C_LICENSE_COMMENT + '''/** @generated */ - -#pragma once - -#include "Ast.h" - -namespace facebook { -namespace graphql { -namespace ast { -namespace visitor { - -class AstVisitor { -public: - virtual ~AstVisitor() {} -''') - - def end_file(self): - print('};') # end AstVisitor - print() - print('}') - print('}') - print('}') - print('}') - - def start_type(self, name): - titleName = title(name) - camelName = camel(titleName) - print(' virtual bool visit%s(const %s &%s) { return true; }' % ( - titleName, - titleName, - camelName)) - print(' virtual void endVisit%s(const %s &%s) { }' % ( - titleName, - titleName, - camelName)) - print() - - def end_type(self, name): - pass - - def field(self, type, name, nullable, plural): - pass - - def start_union(self, name): - pass - - def union_option(self, option): - pass - - def end_union(self, name): - pass diff --git a/ast/js.py b/ast/js.py index cb6c023..143d828 100644 --- a/ast/js.py +++ b/ast/js.py @@ -3,13 +3,13 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. - +from __future__ import print_function class Printer(object): def __init__(self): pass def start_file(self): - print '''/* @flow */ + print('''/* @flow */ /* @generated */ /* jshint ignore:start */ @@ -26,21 +26,21 @@ def start_file(self): end?: ?number; }; -type OperationKind = 'query' | 'mutation' | 'subscription';''' +type OperationKind = 'query' | 'mutation' | 'subscription';''') def end_file(self): pass def start_type(self, name): - print - print 'type %s = Node & {' % name + print() + print('type %s = Node & {' % name) kind = name if kind == 'GenericType': kind = 'Type' - print ' kind: \'%s\';' % kind + print(' kind: \'%s\';' % kind) def end_type(self, name): - print '}' + print('}') def _js_type(self, type, plural): if plural: @@ -50,16 +50,16 @@ def _js_type(self, type, plural): def field(self, type, name, nullable, plural): nullable_char = '?' if nullable else '' js_type = self._js_type(type, plural) - print ' %(name)s%(nullable_char)s: %(nullable_char)s%(js_type)s;' % locals() + print(' %(name)s%(nullable_char)s: %(nullable_char)s%(js_type)s;' % locals()) def start_union(self, name): - print ('type %s = ' % name), + print(('type %s = ' % name), end=' ') self._current_options = [] def union_option(self, type): self._current_options.append(type) def end_union(self, name): - print '\n | '.join(self._current_options) - print + print('\n | '.join(self._current_options)) + print() self._current_options = None diff --git a/ast/js_py3.py b/ast/js_py3.py deleted file mode 100644 index 68aee6e..0000000 --- a/ast/js_py3.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2015-present, Facebook, Inc. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - - -class Printer(object): - def __init__(self): - pass - - def start_file(self): - print('''/* @flow */ -/* @generated */ -/* jshint ignore:start */ - -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -type Node = { - kind: string; - start?: ?number; - end?: ?number; -}; - -type OperationKind = 'query' | 'mutation' | 'subscription';''') - - def end_file(self): - pass - - def start_type(self, name): - print() - print('type %s = Node & {' % name) - kind = name - if kind == 'GenericType': - kind = 'Type' - print(' kind: \'%s\';' % kind) - - def end_type(self, name): - print('}') - - def _js_type(self, type, plural): - if plural: - type = 'Array<%s>' % type - return type - - def field(self, type, name, nullable, plural): - nullable_char = '?' if nullable else '' - js_type = self._js_type(type, plural) - print(' %(name)s%(nullable_char)s: %(nullable_char)s%(js_type)s;' % locals()) - - def start_union(self, name): - print(('type %s = ' % name), end=' ') - self._current_options = [] - - def union_option(self, type): - self._current_options.append(type) - - def end_union(self, name): - print('\n | '.join(self._current_options)) - print() - self._current_options = None From b5e381f67c04147fbbbc014db37298d2fb1510ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Busi?= Date: Wed, 28 Aug 2019 13:54:23 +0200 Subject: [PATCH 4/4] Update to the latest of libgraphql parser --- parser.ypp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parser.ypp b/parser.ypp index 591e885..b425926 100644 --- a/parser.ypp +++ b/parser.ypp @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -%require "3" +/* %require "3" */ %skeleton "lalr1.cc" @@ -278,7 +278,7 @@ union yystype { \ %type union_members; %type field_definition; %type field_definition_list; -%type arguments_definition_opt; +%type arguments_definition_opt; %type arguments_definition; %type input_value_definition_list; %type input_value_definition; @@ -333,7 +333,7 @@ name_opt: document: definition_list { $$ = new Document(@$, $1); } ; - + definition_list:definition { $$ = new std::vector>(); $$->emplace_back($1); } | definition_list definition { $1->emplace_back($2); $$ = $1; } ;