CIRCT  20.0.0git
JSON.cpp
Go to the documentation of this file.
1 //===- Json.cpp - Json Utilities --------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "circt/Support/JSON.h"
10 #include "mlir/IR/BuiltinAttributes.h"
11 #include "mlir/IR/BuiltinTypes.h"
12 #include "mlir/IR/Diagnostics.h"
13 #include "mlir/IR/OperationSupport.h"
14 #include "llvm/ADT/ScopeExit.h"
15 #include "llvm/ADT/StringSwitch.h"
16 #include "llvm/ADT/TypeSwitch.h"
17 
18 namespace json = llvm::json;
19 
20 using namespace circt;
21 using llvm::make_scope_exit;
22 using mlir::UnitAttr;
23 
24 // NOLINTBEGIN(misc-no-recursion)
25 LogicalResult circt::convertAttributeToJSON(llvm::json::OStream &json,
26  Attribute attr) {
27  return TypeSwitch<Attribute, LogicalResult>(attr)
28  .Case<DictionaryAttr>([&](auto attr) {
29  json.objectBegin();
30  auto guard = make_scope_exit([&] { json.objectEnd(); });
31  for (auto subAttr : attr) {
32  json.attributeBegin(subAttr.getName());
33  auto guard = make_scope_exit([&] { json.attributeEnd(); });
34  if (failed(convertAttributeToJSON(json, subAttr.getValue())))
35  return failure();
36  }
37  return success();
38  })
39  .Case<ArrayAttr>([&](auto attr) {
40  json.arrayBegin();
41  auto guard = make_scope_exit([&] { json.arrayEnd(); });
42  for (auto subAttr : attr)
43  if (failed(convertAttributeToJSON(json, subAttr)))
44  return failure();
45  return success();
46  })
47  .Case<BoolAttr, StringAttr>([&](auto attr) {
48  json.value(attr.getValue());
49  return success();
50  })
51  .Case<IntegerAttr>([&](auto attr) -> LogicalResult {
52  // If the integer can be accurately represented by a double, print
53  // it as an integer. Otherwise, convert it to an exact decimal string.
54  const auto &apint = attr.getValue();
55  if (!apint.isSignedIntN(64)) {
56  json.value(nullptr);
57  return failure();
58  }
59  json.value(apint.getSExtValue());
60  return success();
61  })
62  .Case<FloatAttr>([&](auto attr) -> LogicalResult {
63  const auto &apfloat = attr.getValue();
64  json.value(apfloat.convertToDouble());
65  return success();
66  })
67  .Default([&](auto) -> LogicalResult {
68  json.value(nullptr);
69  return failure();
70  });
71 }
72 // NOLINTEND(misc-no-recursion)
73 
74 // NOLINTBEGIN(misc-no-recursion)
75 Attribute circt::convertJSONToAttribute(MLIRContext *context,
76  json::Value &value, json::Path p) {
77  // String or quoted JSON
78  if (auto a = value.getAsString()) {
79  // Test to see if this might be quoted JSON (a string that is actually
80  // JSON). Sometimes FIRRTL developers will do this to serialize objects
81  // that the Scala FIRRTL Compiler doesn't know about.
82  auto unquotedValue = json::parse(*a);
83  auto err = unquotedValue.takeError();
84  // If this parsed without an error and we didn't just unquote a number, then
85  // it's more JSON and recurse on that.
86  //
87  // We intentionally do not want to unquote a number as, in JSON, the string
88  // "0" is different from the number 0. If we conflate these, then later
89  // expectations about annotation structure may be broken. I.e., an
90  // annotation expecting a string may see a number.
91  if (!err && !unquotedValue.get().getAsNumber())
92  return convertJSONToAttribute(context, unquotedValue.get(), p);
93  // If there was an error, then swallow it and handle this as a string.
94  handleAllErrors(std::move(err), [&](const json::ParseError &a) {});
95  return StringAttr::get(context, *a);
96  }
97 
98  // Integer
99  if (auto a = value.getAsInteger())
100  return IntegerAttr::get(IntegerType::get(context, 64), *a);
101 
102  // Float
103  if (auto a = value.getAsNumber())
104  return FloatAttr::get(mlir::FloatType::getF64(context), *a);
105 
106  // Boolean
107  if (auto a = value.getAsBoolean())
108  return BoolAttr::get(context, *a);
109 
110  // Null
111  if (auto a = value.getAsNull())
112  return mlir::UnitAttr::get(context);
113 
114  // Object
115  if (auto *a = value.getAsObject()) {
116  NamedAttrList metadata;
117  for (auto b : *a)
118  metadata.append(
119  b.first, convertJSONToAttribute(context, b.second, p.field(b.first)));
120  return DictionaryAttr::get(context, metadata);
121  }
122 
123  // Array
124  if (auto *a = value.getAsArray()) {
125  SmallVector<Attribute> metadata;
126  for (size_t i = 0, e = (*a).size(); i != e; ++i)
127  metadata.push_back(convertJSONToAttribute(context, (*a)[i], p.index(i)));
128  return ArrayAttr::get(context, metadata);
129  }
130 
131  llvm_unreachable("Impossible unhandled JSON type");
132 }
133 // NOLINTEND(misc-no-recursion)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:55
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Attribute convertJSONToAttribute(MLIRContext *context, llvm::json::Value &value, llvm::json::Path p)
Convert arbitrary JSON to an MLIR Attribute.
LogicalResult convertAttributeToJSON(llvm::json::OStream &json, Attribute attr)
Convert a simple attribute to JSON.
Definition: JSON.cpp:25