Internal change

PiperOrigin-RevId: 521040659
Change-Id: I1f9a62f6894d98e95e76d4ec1078b118dce81e71
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..653d61b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+# Ignore all bazel related directories
+
+bazel-bin
+bazel-mpact-sim
+bazel-out
+bazel-testlogs
diff --git a/mpact/sim/decoder/antlr_cc.bzl b/mpact/sim/decoder/antlr_cc.bzl
new file mode 100644
index 0000000..2457742
--- /dev/null
+++ b/mpact/sim/decoder/antlr_cc.bzl
@@ -0,0 +1,189 @@
+# Copyright 2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Build rules to create C++ code from an Antlr4 grammar."""
+
+def antlr4_cc_lexer(
+        name,
+        src,
+        namespaces = None,
+        deps = None):
+    """Generates the C++ source corresponding to an antlr4 lexer definition.
+
+    Args:
+      name: The name of the package to use for the cc_library.
+      src: The antlr4 g4 file containing the lexer rules.
+      namespaces: The namespace used by the generated files. Uses an array to
+        support nested namespaces. Defaults to [name].
+      deps: Dependencies for the generated code.
+    """
+    namespaces = namespaces or [name]
+    deps = deps or []
+    if not src.endswith(".g4"):
+        fail("Grammar must end with .g4", "src")
+    file_prefix = _label_basename(src[:-3])
+    base_file_prefix = _strip_end(file_prefix, "Lexer")
+    out_files = [
+        "%sLexer.h" % base_file_prefix,
+        "%sLexer.cpp" % base_file_prefix,
+    ]
+    command = ";\n".join([
+        # Use the first namespace, we'll add the others afterwards.
+        _make_tool_invocation_command(namespaces[0]),
+        _make_namespace_adjustment_command(namespaces, out_files),
+        _make_google3_cleanup_command(out_files),
+    ])
+    native.genrule(
+        name = name + "_source",
+        srcs = [src],
+        outs = out_files,
+        cmd = command,
+        heuristic_label_expansion = 0,
+        tools = [Label("@org_antlr_tool//file")],
+    )
+    native.cc_library(
+        name = name,
+        srcs = [f for f in out_files if f.endswith(".cpp")],
+        hdrs = [f for f in out_files if f.endswith(".h")],
+        deps = [Label("@org_antlr4_cpp_runtime//:antlr4")] + deps,
+        copts = [
+            "-fexceptions",
+            "-iquote $(BINDIR)/external/org_antlr4_cpp_runtime/antlr4/include/antlr4-runtime",
+        ],
+        features = ["-use_header_modules"],  # Incompatible with -fexceptions.
+    )
+
+def antlr4_cc_parser(
+        name,
+        src,
+        namespaces = None,
+        listener = True,
+        visitor = False,
+        deps = None):
+    """Generates the C++ source corresponding to an antlr4 parser definition.
+
+    Args:
+      name: The name of the package to use for the cc_library.
+      src: The antlr4 g4 file containing the parser rules.
+      namespaces: The namespace used by the generated files. Uses an array to
+        support nested namespaces. Defaults to [name].
+      listener: Whether or not to include listener generated files.
+      visitor: Whether or not to include visitor generated files.
+      deps: Dependencies for the generated code.
+    """
+    suffixes = ()
+    if listener:
+        suffixes += (
+            "%sBaseListener.cpp",
+            "%sListener.cpp",
+            "%sBaseListener.h",
+            "%sListener.h",
+        )
+    if visitor:
+        suffixes += (
+            "%sBaseVisitor.cpp",
+            "%sVisitor.cpp",
+            "%sBaseVisitor.h",
+            "%sVisitor.h",
+        )
+    namespaces = namespaces or [name]
+    deps = deps or []
+    if not src.endswith(".g4"):
+        fail("Grammar must end with .g4", "src")
+    file_prefix = _label_basename(src[:-3])
+    base_file_prefix = _strip_end(file_prefix, "Parser")
+    out_files = [
+        "%sParser.h" % base_file_prefix,
+        "%sParser.cpp" % base_file_prefix,
+    ] + _make_outs(file_prefix, suffixes)
+    command = ";\n".join([
+        # Use the first namespace, we'll add the others afterward.
+        _make_tool_invocation_command(namespaces[0], listener, visitor),
+        _make_namespace_adjustment_command(namespaces, out_files),
+        _make_google3_cleanup_command(out_files),
+    ])
+    native.genrule(
+        name = name + "_source",
+        srcs = [src],
+        outs = out_files,
+        cmd = command,
+        heuristic_label_expansion = 0,
+        tools = [Label("@org_antlr_tool//file")],
+    )
+    native.cc_library(
+        name = name,
+        srcs = [f for f in out_files if f.endswith(".cpp")],
+        hdrs = [f for f in out_files if f.endswith(".h")],
+        deps = [Label("@org_antlr4_cpp_runtime//:antlr4")] + deps,
+        copts = [
+            "-fexceptions",
+            "-Wno-nonnull",
+            "-iquote $(BINDIR)/external/org_antlr4_cpp_runtime/antlr4/include/antlr4-runtime",
+        ],
+        features = ["-use_header_modules"],
+    )
+
+def _make_tool_invocation_command(package, listener = False, visitor = False):
+    return "java -jar $(location @org_antlr_tool//file) " + \
+           "$(SRCS)" + \
+           (" -visitor" if visitor else " -no-visitor") + \
+           (" -listener" if listener else " -no-listener") + \
+           " -Dlanguage=Cpp" + \
+           " -package " + package + \
+           " -o $(@D)" + \
+           " -Xexact-output-dir"
+
+def _make_google3_cleanup_command(out_files):
+    # Clean up imports and usage of the #pragma once directive.
+    return ";\n".join([
+        ";\n".join([
+            "sed -i '0,/antlr4-runtime.h/s//antlr4-runtime\\/antlr4-runtime.h/' $(@D)/%s" % filepath,
+            "grep -q '^#pragma once' $(@D)/%s && echo '\n#endif  // %s\n' >> $(@D)/%s" % (filepath, _to_c_macro_name(filepath), filepath),
+            "sed -i '0,/#pragma once/s//#ifndef %s\\n#define %s/' $(@D)/%s" % (_to_c_macro_name(filepath), _to_c_macro_name(filepath), filepath),
+        ])
+        for filepath in out_files
+    ])
+
+def _make_namespace_adjustment_command(namespaces, out_files):
+    if len(namespaces) == 1:
+        return "true"
+    commands = []
+    extra_header_namespaces = "\\\n".join(["namespace %s {" % namespace for namespace in namespaces[1:]])
+    for filepath in out_files:
+        if filepath.endswith(".h"):
+            commands.append("sed -i '/namespace %s {/ a%s' $(@D)/%s" % (namespaces[0], extra_header_namespaces, filepath))
+            for namespace in namespaces[1:]:
+                commands.append("sed -i '/}  \\/\\/ namespace %s/i}  \\/\\/ namespace %s' $(@D)/%s" % (namespaces[0], namespace, filepath))
+        else:
+            commands.append("sed -i 's/using namespace %s;/using namespace %s;/' $(@D)/%s" % (namespaces[0], "::".join(namespaces), filepath))
+    return ";\n".join(commands)
+
+def _make_outs(file_prefix, suffixes):
+    return [file_suffix % file_prefix for file_suffix in suffixes]
+
+def _strip_end(text, suffix):
+    if not text.endswith(suffix):
+        return text
+    return text[:len(text) - len(suffix)]
+
+def _to_c_macro_name(filename):
+    # Convert the filenames to a format suitable for C preprocessor definitions.
+    char_list = [filename[i].upper() for i in range(len(filename))]
+    return "ANTLR4_GEN_" + "".join(
+        [a if (("A" <= a) and (a <= "Z")) else "_" for a in char_list],
+    )
+
+def _label_basename(label):
+    """Returns the basename of a Blaze label."""
+    return label.split(":")[-1]