mongo/buildscripts/idl/idl/common.py

122 lines
4.3 KiB
Python

# Copyright (C) 2018-present MongoDB, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the Server Side Public License, version 1,
# as published by MongoDB, Inc.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Server Side Public License for more details.
#
# You should have received a copy of the Server Side Public License
# along with this program. If not, see
# <http://www.mongodb.com/licensing/server-side-public-license>.
#
# As a special exception, the copyright holders give permission to link the
# code of portions of this program with the OpenSSL library under certain
# conditions as described in each individual source file and distribute
# linked combinations including the program with the OpenSSL library. You
# must comply with the Server Side Public License in all respects for
# all of the code used other than as permitted herein. If you modify file(s)
# with this exception, you may extend this exception to your version of the
# file(s), but you are not obligated to do so. If you do not wish to do so,
# delete this exception statement from your version. If you delete this
# exception statement from all source files in the program, then also delete
# it in the license file.
#
"""
IDL Common classes.
Classes which are shared among both the IDL idl.syntax and idl.AST trees.
"""
import os
import string
from typing import Mapping
COMMAND_NAMESPACE_CONCATENATE_WITH_DB = "concatenate_with_db"
COMMAND_NAMESPACE_CONCATENATE_WITH_DB_OR_UUID = "concatenate_with_db_or_uuid"
COMMAND_NAMESPACE_IGNORED = "ignored"
COMMAND_NAMESPACE_TYPE = "type"
def title_case(name):
# type: (str) -> str
"""Return a CapitalCased version of a string."""
# Only capitalize the last part of a fully-qualified name
pos = name.rfind("::")
if pos > -1:
return name[:pos + 2] + name[pos + 2:pos + 3].upper() + name[pos + 3:]
return name[0:1].upper() + name[1:]
def camel_case(name):
# type: (str) -> str
"""Return a camelCased version of a string."""
return name[0:1].lower() + name[1:]
def qualify_cpp_name(cpp_namespace, cpp_type_name):
# type: (str, str) -> str
"""Preprend a type name with a C++ namespace if cpp_namespace is not None."""
if cpp_namespace:
return cpp_namespace + "::" + cpp_type_name
return cpp_type_name
def _escape_template_string(template):
# type: (str) -> str
"""Escape the '$' in template strings unless followed by '{'."""
# See https://docs.python.org/2/library/string.html#template-strings
template = template.replace('${', '#{')
template = template.replace('$', '$$')
return template.replace('#{', '${')
def template_format(template, template_params=None):
# type: (str, Mapping[str,str]) -> str
"""Write a template to the stream."""
# Ignore the types since we use str literals and this expects str but works fine with
# str.
# See https://docs.python.org/2/library/string.html#template-strings
template = _escape_template_string(template)
# pylint: disable=too-many-function-args
return string.Template(template).substitute(template_params) # type: ignore
def template_args(template, **kwargs):
# type: (str, **str) -> str
"""Write a template to the stream."""
# Ignore the types since we use str literals and this expects str but works fine with
# str.
# See https://docs.python.org/2/library/string.html#template-strings
template = _escape_template_string(template)
# pylint: disable=too-many-function-args
return string.Template(template).substitute(kwargs) # type: ignore
class SourceLocation(object):
"""Source location information about an idl.syntax or idl.AST object."""
def __init__(self, file_name, line, column):
# type: (str, int, int) -> None
"""Construct a source location."""
self.file_name = file_name
self.line = line
self.column = column
def __str__(self):
# type: () -> str
"""
Return a formatted location.
Example location message:
test.idl: (17, 4)
"""
msg = "%s: (%d, %d)" % (os.path.basename(self.file_name), self.line, self.column)
return msg # type: ignore