1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

add RustGenerator

This commit is contained in:
Victor Bargachev 2023-05-31 22:51:21 +02:00 committed by Ilyar
parent 961d870ece
commit 81499c275f
No known key found for this signature in database
GPG key ID: BE9A3D099DFEF330
2 changed files with 251 additions and 0 deletions

View file

@ -20,6 +20,8 @@
#include "td/utils/bits.h"
#include "td/utils/filesystem.h"
#define DISABLE_CPP_OUTPUT
namespace tlbc {
/*
@ -3149,8 +3151,13 @@ void CppTypeCode::generate_header(std::ostream& os, int options) {
}
}
#include "tlbc-gen-rust.hpp"
void CppTypeCode::generate_body(std::ostream& os, int options) {
generate_cons_tag_info(os, "", 2);
#ifndef DISABLE_CPP_OUTPUT
if (!inline_get_tag) {
os << "\nint " << cpp_type_class_name << "::get_tag(const vm::CellSlice& cs) const {";
generate_get_tag_body(os, "\n ");
@ -3197,6 +3204,7 @@ void CppTypeCode::generate_body(std::ostream& os, int options) {
os << "\nconst " << cpp_type_class_name << " " << cpp_type_var_name << ";";
}
os << std::endl;
#endif
}
void CppTypeCode::generate(std::ostream& os, int options) {
@ -3204,6 +3212,7 @@ void CppTypeCode::generate(std::ostream& os, int options) {
if (!type.type_name && type.is_auto) {
type_name = cpp_type_class_name;
}
#ifndef DISABLE_CPP_OUTPUT
if (options & 1) {
os << "\n//\n// headers for " << (type.is_auto ? "auxiliary " : "") << "type `" << type_name << "`\n//\n";
generate_header(os, options);
@ -3215,6 +3224,8 @@ void CppTypeCode::generate(std::ostream& os, int options) {
os << "\n//\n// code for " << (type.is_auto ? "auxiliary " : "") << "type `" << type_name << "`\n//\n";
generate_body(os, options);
}
#endif
if (options & 2) generate_rust(os, type);
}
void generate_type_constant(std::ostream& os, int i, TypeExpr* expr, std::string cpp_name, int mode) {
@ -3377,6 +3388,7 @@ void generate_cpp_output_to(std::ostream& os, int options = 0, std::vector<std::
prepare_generate_cpp(options);
generate_prepared = true;
}
#ifndef DISABLE_CPP_OUTPUT
if (options & 1) {
os << "#pragma once\n";
}
@ -3412,19 +3424,24 @@ void generate_cpp_output_to(std::ostream& os, int options = 0, std::vector<std::
<< "using vm::CellSlice;\n"
<< "using vm::Cell;\n"
<< "using td::RefInt256;\n";
#endif // DISABLE_CPP_OUTPUT
for (int pass = 1; pass <= 2; pass++) {
if (options & pass) {
for (int i : type_gen_order) {
CppTypeCode& cc = *cpp_type[i];
cc.generate(os, (options & -4) | pass);
}
#ifndef DISABLE_CPP_OUTPUT
generate_type_constants(os, pass - 1);
generate_register_function(os, pass - 1);
#endif // DISABLE_CPP_OUTPUT
}
}
#ifndef DISABLE_CPP_OUTPUT
for (auto it = cpp_namespace_list.rbegin(); it != cpp_namespace_list.rend(); ++it) {
os << "\n} // namespace " << *it << std::endl;
}
#endif // DISABLE_CPP_OUTPUT
}
void generate_cpp_output_to(std::string filename, int options = 0, std::vector<std::string> include_files = {}) {

234
crypto/tl/tlbc-gen-rust.hpp Normal file
View file

@ -0,0 +1,234 @@
struct RustGenerator {
std::string to_string(int value) {
std::ostringstream ss;
ss << value;
return ss.str();
}
std::string tabs2spaces(std::string inp) {
std::string outp;
for (auto ch : inp) {
if (ch == '\t') outp += " ";
else outp += ch;
}
return outp;
}
std::set<std::string> user_defined_types;
std::string rust_rename(const std::string s) {
if (s == "anycast_info") return "AnycastInfo";
if (s == "Anycast") return "AnycastInfo";
if (s == "addr_extern") return "MsgAddrExt";
if (s == "addr_std") return "MsgAddrStd";
if (s == "addr_var") return "MsgAddrVar";
return s;
}
std::string rust_rename2(const std::string s) {
if (s == "addr_none") return "AddrNone";
if (s == "addr_extern") {
if (_current_type->get_name() == "MsgAddress") return "AddrExt";
else return "AddrExtern";
}
if (s == "addr_std") return "AddrStd";
if (s == "addr_var") return "AddrVar";
return s;
}
std::string to_rust_type(const TypeExpr* expr) {
const Type* ta = expr->type_applied;
if (!ta) {
return "UnknownType:ta=0";
}
if (expr->tp == TypeExpr::te_Apply && ta == NatWidth_type) {
if (expr->args.at(0)->tp == TypeExpr::te_IntConst) {
return "Number" + to_string(expr->args[0]->value);
}
}
if (ta == Bits_type) {
return "SliceData";
}
auto tname = ta->get_name();
if (tname == "Maybe") {
return "Option<" + to_rust_type(expr->args[0]) + ">";
}
if (tname == "VarInteger" || tname == "VarUInteger") {
return tname + "<" + to_string(expr->args[0]->value) + ">";
}
if (tname == "int8") return "i8";
if (tname == "int32") return "i32";
if (tname == "bits256") return "AccountId";
if (user_defined_types.count(tname) > 0) {
return rust_rename(tname);
}
// std::cout << "[3181] " << expr->tp << ":";
// expr->show(std::cout);
return "UnknownType:" + ta->get_name() + ",tp=" + to_string(expr->tp);
}
std::string rust_output_expr(const TypeExpr* expr, const std::vector<std::string>& field_vars) {
switch (expr->tp) {
case TypeExpr::te_Apply: {
return rust_output_expr(expr->args[0], field_vars);
}
case TypeExpr::te_Param: {
return "self." + field_vars.at(expr->value);
}
}
return "???";
}
std::string rust_get_field(const Field& field, const std::vector<std::string>& field_vars) {
auto fname = get_name(field.name);
const Type* ta = field.type->type_applied;
std::string s = "self." + fname;
if (ta == Bits_type) {
s += " = cell.get_next_slice(" + rust_output_expr(field.type, field_vars) + ".0 as usize)?;";
} else if (ta->get_name() == "Maybe") {
s += " = " + to_rust_type(field.type->args[0]) + "::read_maybe_from(cell)?;";
} else if (ta->get_name() == "bits256") {
s += " = cell.get_next_slice(256)?;";
} else {
s += ".read_from(cell)?;";
}
return s + "\n";
}
std::string get_name(sym_idx_t name) {
return sym::symbols.get_name(name);
}
int get_constr_tag(Constructor* constr) {
return int(constr->tag >> (64 - constr->tag_bits));
}
const Type* _current_type = nullptr;
void generate_rust(std::ostream& os, const Type& type) {
// os << "Addding " << type.get_name() << "\n";
user_defined_types.insert(type.get_name());
if (type.get_name() == "Maybe") return;
if (type.get_name() == "VarInteger") return;
if (type.get_name() == "VarUInteger") return;
_current_type = &type;
for (auto& constr : type.constructors) {
auto constr_name = get_name(constr->constr_name);
if (constr_name == "_") continue;
// os << "// [" << type.get_name() << "-" << constr_name << "]\n\n";
if (constr->fields.empty()) continue;
auto class_name = rust_rename(constr_name);
std::string s = "#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]\n";
s += "pub struct " + class_name + " {\n";
for (auto& field : constr->fields) {
auto fname = get_name(field.name);
if (fname == "_") continue;
s += "\tpub " + fname + ": " + to_rust_type(field.type) + ",\n";
}
s += "}\n\n";
std::vector<std::string> field_vars;
for (auto& field : constr->fields) {
auto fname = get_name(field.name);
field_vars.push_back(fname);
}
s += "impl Deserializable for " + class_name + " {\n"
+ "\tfn read_from(&mut self, cell: &mut SliceData) -> BlockResult<()> {\n";
for (auto& field : constr->fields) {
auto fname = get_name(field.name);
if (fname == "_") continue;
s += "\t\t" + rust_get_field(field, field_vars);
}
s += "\t\tOk(())\n";
s += "\t}\n";
s += "}\n\n";
os << tabs2spaces(s);
}
// os << type.useful_depth << type.is_pfx_determ << "\n";
std::map<const Constructor*, const Type*> owner;
std::vector<Constructor*> constructors;
for (auto& constr : type.constructors) {
if (get_name(constr->constr_name) == "_") {
Type* type = constr->fields[0].type->type_applied;
for (auto& constr2 : type->constructors) {
owner[constr2] = type;
constructors.push_back(constr2);
}
} else {
owner[constr] = &type;
constructors.push_back(constr);
}
}
std::sort(constructors.begin(), constructors.end(), [this] (Constructor* a, Constructor* b) {
return get_constr_tag(a) < get_constr_tag(b);
});
if (constructors.size() > 1) {
std::string s = "#[derive(Clone, Debug, PartialEq, Eq, Hash)]\n";
s += "pub enum " + type.get_name() + " {\n";
int tag_bits = 0;
for (auto& constr : constructors) {
s += "\t" + rust_rename2(get_name(constr->constr_name));
if (!constr->fields.empty())
s += "(" + rust_rename(get_name(constr->constr_name)) + ")";
s += ",\n";
// os << "[" << constr->tag_bits << "," << (constr->tag >> (64 - constr->tag_bits)) << "]";
tag_bits = constr->tag_bits;
}
s += "}\n\n";
s += "impl Deserializable for " + type.get_name() + " {\n";
s += "\tfn read_from(&mut self, cell: &mut SliceData) -> BlockResult<()> {\n";
s += "\t\tlet bits = cell.get_next_bits(" + to_string(tag_bits) +")?[0] >> " + to_string(8-tag_bits) + ";\n";
// TODO: add error checking for invalid bits!
for (auto& constr : constructors) {
s += "\t\tif bits == " + to_string(get_constr_tag(constr)) + " {\n";
if (constr->fields.empty()) {
s += "\t\t\t*self = " + type.get_name() + "::" + rust_rename2(get_name(constr->constr_name)) + ";\n";
} else {
auto tname = get_name(constr->constr_name);
s += "\t\t\tlet mut data = " + rust_rename(tname) + "::default();\n";
s += "\t\t\tdata.read_from(cell)?;\n";
s += "\t\t\t*self = " + type.get_name() + "::" + rust_rename2(tname) + "(data);\n";
}
s += "\t\t}\n";
}
s += "\t\tOk(())\n";
s += "\t}\n";
s += "}\n\n";
os << tabs2spaces(s);
}
}
};
void generate_rust(std::ostream& os, const Type& type) {
static RustGenerator rg;
rg.generate_rust(os, type);
}