// Generate a flatbuffer schema from the Parser's internal representation. std::string GenerateFBS(const Parser &parser, const std::string &file_name, const GeneratorOptions &opts) { std::string schema; schema += "// Generated from " + file_name + ".proto\n\n"; if (opts.include_dependence_headers) { int num_includes = 0; for (auto it = parser.included_files_.begin(); it != parser.included_files_.end(); ++it) { auto basename = flatbuffers::StripPath( flatbuffers::StripExtension(it->first)); if (basename != file_name) { schema += "include \"" + basename + ".fbs\";\n"; num_includes++; } } if (num_includes) schema += "\n"; } schema += "namespace "; auto name_space = parser.namespaces_.back(); for (auto it = name_space->components.begin(); it != name_space->components.end(); ++it) { if (it != name_space->components.begin()) schema += "."; schema += *it; } schema += ";\n\n"; // Generate code for all the enum declarations. for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); ++it) { EnumDef &enum_def = **it; schema += "enum " + enum_def.name + " : "; schema += GenType(enum_def.underlying_type) + " {\n"; for (auto itTmp = enum_def.vals.vec.begin(); itTmp != enum_def.vals.vec.end(); ++itTmp) { auto &ev = **itTmp; schema += " " + ev.name + " = " + NumToString(ev.value) + ",\n"; } schema += "}\n\n"; } // Generate code for all structs/tables. for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); ++it) { StructDef &struct_def = **it; schema += "table " + struct_def.name + " {\n"; for (auto itTmp = struct_def.fields.vec.begin(); itTmp != struct_def.fields.vec.end(); ++itTmp) { auto &field = **itTmp; schema += " " + field.name + ":" + GenType(field.value.type); if (field.value.constant != "0") schema += " = " + field.value.constant; if (field.required) schema += " (required)"; schema += ";\n"; } schema += "}\n\n"; } return schema; }
void GEndSubScr( itnode *arr ) { //================================= // Finish off a subscripting operation. itnode *arg; int dim_cnt; if( arr->opn.us & USOPN_FLD ) { PushOpn( arr ); EmitOp( FC_FIELD_SUBSCRIPT ); OutPtr( arr->sym_ptr ); dim_cnt = _DimCount( arr->sym_ptr->u.fd.dim_ext->dim_flags ); } else { EmitOp( FC_SUBSCRIPT ); OutPtr( arr->sym_ptr ); dim_cnt = _DimCount( arr->sym_ptr->u.ns.si.va.u.dim_ext->dim_flags ); } arg = arr->list; while( dim_cnt-- > 0 ) { GenType( arg ); arg = arg->link; } if( ( arr->opn.us & USOPN_FLD ) == 0 ) { if( ( StmtSw & SS_DATA_INIT ) == 0 ) { if( arr->sym_ptr->u.ns.u1.s.typ == FT_CHAR ) { OutPtr( GTempString( 0 ) ); } } } SetOpn( arr, USOPN_SAFE ); }
void GForceHiBound( int ss, sym_id sym ) { //======================================================= // Generate code to fill in ADV subscript element (hi bound). // The hi bound is constant and the low bound is not. // We have to force the filling in of the high bound so that the number of // of elements gets computed. // // Scenario: SUBROUTINE SAM( A, J ) // DIMENSION A(J:3) // // GInitADV() fills in the lo bound and # of elements in the dimension at // compile-time. The lo bound is unknown so the ADV does not contain the // correct information. The lo bound gets filled in at run-time but // since the hi bound is not dumped into the ADV at compile time we // must fill it in at run-time and compute the correct number of elements // in the dimension. AddConst( CITNode ); PushOpn( CITNode ); EmitOp( FC_ADV_FILL_HI ); OutPtr( sym ); OutU16( (uint_16)ss ); GenType( CITNode ); }
static std::string GenType(const Type &type) { switch (type.base_type) { case BASE_TYPE_STRUCT: return type.struct_def->name; case BASE_TYPE_UNION: return type.enum_def->name; case BASE_TYPE_VECTOR: return "[" + GenType(type.VectorType()) + "]"; default: return kTypeNames[type.base_type]; } }
void GRetIdx( void ) { //================= // Generate an alternate return. PushOpn( CITNode ); EmitOp( FC_ASSIGN_ALT_RET ); GenType( CITNode ); }
std::string GenType(const Type &type) { if (type.enum_def != nullptr && !type.enum_def->is_union) { // it is a reference to an enum type return GenTypeRef(type.enum_def); } switch (type.base_type) { case BASE_TYPE_VECTOR: { std::string typeline; typeline.append("\"type\" : \"array\", \"items\" : { "); if (type.element == BASE_TYPE_STRUCT) { typeline.append(GenTypeRef(type.struct_def)); } else { typeline.append(GenType(GenNativeType(type.element))); } typeline.append(" }"); return typeline; } case BASE_TYPE_STRUCT: { return GenTypeRef(type.struct_def); } case BASE_TYPE_UNION: { std::string union_type_string("\"anyOf\": ["); const auto &union_types = type.enum_def->vals.vec; for (auto ut = union_types.cbegin(); ut < union_types.cend(); ++ut) { auto &union_type = *ut; if (union_type->union_type.base_type == BASE_TYPE_NONE) { continue; } if (union_type->union_type.base_type == BASE_TYPE_STRUCT) { union_type_string.append("{ " + GenTypeRef(union_type->union_type.struct_def) + " }"); } if (union_type != *type.enum_def->vals.vec.rbegin()) { union_type_string.append(","); } } union_type_string.append("]"); return union_type_string; } case BASE_TYPE_UTYPE: return GenTypeRef(type.enum_def); default: return GenType(GenNativeType(type.base_type)); } }
void GSLoBound( int ss, sym_id sym ) { //=================================================== // Generate code to fill in ADV subscript element (lo bound). PushOpn( CITNode ); EmitOp( FC_ADV_FILL_LO ); OutPtr( sym ); OutU16( (uint_16)ss ); GenType( CITNode ); }
void GPassValue( FCODE rtn ) { //=============================== // Pass the value of CITNode on the stack and emit fcode for routine. PushOpn( CITNode ); EmitOp( rtn ); if( ( rtn == FC_SET_UNIT ) || ( rtn == FC_SET_REC ) || ( rtn == FC_SET_RECL ) || ( rtn == FC_SET_BLOCKSIZE ) ) { GenType( CITNode ); } }
void GSHiBoundLo1( int ss, sym_id sym ) { //====================================================== // Generate code to fill in ADV subscript element (hi bound). // Set the low bound to 1. // push high bound value PushOpn( CITNode ); EmitOp( FC_ADV_FILL_HI_LO_1 ); // general information OutPtr( sym ); OutU16( (uint_16)ss ); GenType( CITNode ); }
static std::string GenType(const Type &type, bool underlying = false) { switch (type.base_type) { case BASE_TYPE_STRUCT: return type.struct_def->defined_namespace->GetFullyQualifiedName( type.struct_def->name); case BASE_TYPE_VECTOR: return "[" + GenType(type.VectorType()) + "]"; default: if (type.enum_def && !underlying) { return type.enum_def->defined_namespace->GetFullyQualifiedName( type.enum_def->name); } else { return kTypeNames[type.base_type]; } } }
void ExpOp( TYPE typ1, TYPE typ2, OPTR opr ) { //=============================================== // Generate code to perform exponentiation. if( UnaryMul( typ1, typ2 ) ) { PushOpn( CITNode ); EmitOp( FC_UNARY_MUL ); GenType( CITNode ); OutU16( ITIntValue( CITNode->link ) ); SetOpn( CITNode, USOPN_SAFE ); } else { BinOp( typ1, typ2, opr ); } }
static void Unary( TYPE typ, OPTR opr ) { //======================================= // Generate code for unary plus or unary minus. PushOpn( CITNode->link ); if( opr == OPTR_SUB ) { // unary minus if( TypeCmplx( typ ) ) { EmitOp( FC_CUMINUS ); } else { EmitOp( FC_UMINUS ); } GenType( CITNode->link ); } else if( ( _IsTypeInteger( CITNode->link->typ ) ) && ( CITNode->link->size < sizeof( intstar4 ) ) ) { // convert INTEGER*1 or INTEGER*2 to INTEGER*4 EmitOp( FC_CONVERT ); DumpTypes( CITNode->link->typ, CITNode->link->size, FT_INTEGER, sizeof( intstar4 ) ); } SetOpn( CITNode, USOPN_SAFE ); }
void GDataItem( itnode *rpt ) { //================================ // Generate a data item. sym_id data; intstar4 one; if( rpt == NULL ) { one = 1; data = STConst( &one, FT_INTEGER, TypeSize( FT_INTEGER ) ); } else { data = rpt->sym_ptr; } OutPtr( data ); if( CITNode->typ == FT_HEX ) { OutU16( PT_NOTYPE ); } else { GenType( CITNode ); } OutPtr( CITNode->sym_ptr ); }
void LogOp( TYPE typ1, TYPE typ2, OPTR op ) { //============================================== // Generate code for a relational operator. bool flip; op -= OPTR_FIRST_LOGOP; flip = FALSE; if( ( ( CITNode->opn.us & USOPN_WHERE ) == USOPN_SAFE ) && ( ( CITNode->link->opn.us & USOPN_WHERE ) != USOPN_SAFE ) ) { flip = TRUE; } PushOpn( CITNode->link ); if( typ1 == TY_NO_TYPE ) { // unary if( _IsTypeInteger( typ2 ) ) { EmitOp( FC_BIT_NOT ); } else { EmitOp( FC_NOT ); } GenType( CITNode->link ); SetOpn( CITNode, USOPN_SAFE ); } else { PushOpn( CITNode ); if( _IsTypeInteger( typ2 ) ) { EmitOp( FC_BITOPS + op ); } else { EmitOp( FC_LOGOPS + op ); } if( flip ) { GenTypes( CITNode->link, CITNode ); } else { GenTypes( CITNode, CITNode->link ); } } }
inline bool isOne(GenType a) { return areEqual<GenType>(a, GenType(1.0)); }
// Generate a flatbuffer schema from the Parser's internal representation. std::string GenerateFBS(const Parser &parser, const std::string &file_name) { // Proto namespaces may clash with table names, escape the ones that were // generated from a table: for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end(); ++it) { auto &ns = **it; for (size_t i = 0; i < ns.from_table; i++) { ns.components[ns.components.size() - 1 - i] += "_"; } } std::string schema; schema += "// Generated from " + file_name + ".proto\n\n"; if (parser.opts.include_dependence_headers) { // clang-format off #ifdef FBS_GEN_INCLUDES // TODO: currently all in one file. int num_includes = 0; for (auto it = parser.included_files_.begin(); it != parser.included_files_.end(); ++it) { if (it->second.empty()) continue; auto basename = flatbuffers::StripPath( flatbuffers::StripExtension(it->second)); schema += "include \"" + basename + ".fbs\";\n"; num_includes++; } if (num_includes) schema += "\n"; #endif // clang-format on } // Generate code for all the enum declarations. const Namespace *last_namespace = nullptr; for (auto enum_def_it = parser.enums_.vec.begin(); enum_def_it != parser.enums_.vec.end(); ++enum_def_it) { EnumDef &enum_def = **enum_def_it; GenNameSpace(*enum_def.defined_namespace, &schema, &last_namespace); GenComment(enum_def.doc_comment, &schema, nullptr); schema += "enum " + enum_def.name + " : "; schema += GenType(enum_def.underlying_type, true) + " {\n"; for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); ++it) { auto &ev = **it; GenComment(ev.doc_comment, &schema, nullptr, " "); schema += " " + ev.name + " = " + NumToString(ev.value) + ",\n"; } schema += "}\n\n"; } // Generate code for all structs/tables. for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); ++it) { StructDef &struct_def = **it; GenNameSpace(*struct_def.defined_namespace, &schema, &last_namespace); GenComment(struct_def.doc_comment, &schema, nullptr); schema += "table " + struct_def.name + " {\n"; for (auto field_it = struct_def.fields.vec.begin(); field_it != struct_def.fields.vec.end(); ++field_it) { auto &field = **field_it; if (field.value.type.base_type != BASE_TYPE_UTYPE) { GenComment(field.doc_comment, &schema, nullptr, " "); schema += " " + field.name + ":" + GenType(field.value.type); if (field.value.constant != "0") schema += " = " + field.value.constant; if (field.required) schema += " (required)"; schema += ";\n"; } } schema += "}\n\n"; } return schema; }
static void DoLoop( TYPE do_type ) { //===================================== // Generate code for DO statement or implied-DO. do_entry *doptr; uint do_size; intstar4 incr; intstar4 limit; sym_id loop_ctrl; TYPE e1_type; uint e1_size; itnode *e2_node; itnode *e3_node; bool e2_const; doptr = CSHead->cs_info.do_parms; do_size = CITNode->sym_ptr->u.ns.xt.size; doptr->do_parm = CITNode->sym_ptr; // save ptr to do variable AdvanceITPtr(); // bump past the '=' EatDoParm(); // process e1 PushOpn( CITNode ); e1_type = CITNode->typ; e1_size = CITNode->size; AdvanceITPtr(); if( ReqComma() ) { EatDoParm(); // process e2 e2_const = CITNode->opn.us == USOPN_CON; PushOpn( CITNode ); e2_node = CITNode; AdvanceITPtr(); e3_node = NULL; if( RecComma() ) { EatDoParm(); // process e3 e3_node = CITNode; if( !AError ) { if( (CITNode->opn.us == USOPN_CON) && _IsTypeInteger( do_type ) ) { incr = GetIntValue( CITNode ); doptr->incr_value = incr; doptr->increment = NULL; if( (OZOpts & OZOPT_O_FASTDO) == 0 ) { if( e2_const ) { limit = GetIntValue( e2_node ); if( NeedIncrement( limit, incr, do_type ) ) { PushOpn( CITNode ); doptr->increment = StaticAlloc( do_size, do_type ); } } else { PushOpn( CITNode ); doptr->increment = StaticAlloc( do_size, do_type ); } } } else { PushOpn( CITNode ); doptr->increment = StaticAlloc( do_size, do_type ); } AdvanceITPtr(); } } else { if( _IsTypeInteger( do_type ) ) { doptr->increment = NULL; doptr->incr_value = 1; if( (OZOpts & OZOPT_O_FASTDO) == 0 ) { if( e2_const ) { limit = GetIntValue( e2_node ); if( NeedIncrement( limit, 1, do_type ) ) { PushConst( 1 ); doptr->increment = StaticAlloc( do_size, do_type ); } } else { PushConst( 1 ); doptr->increment = StaticAlloc( do_size, do_type ); } } } else { PushConst( 1 ); doptr->increment = StaticAlloc( do_size, do_type ); } } EmitOp( FC_DO_BEGIN ); OutPtr( doptr->do_parm ); OutPtr( doptr->increment ); if( doptr->increment == NULL ) { // INTEGER do-loop with constant incr loop_ctrl = StaticAlloc( do_size, do_type ); OutConst32( doptr->incr_value ); OutPtr( loop_ctrl ); } else { if( _IsTypeInteger( do_type ) ) { loop_ctrl = StaticAlloc( do_size, do_type ); } else { loop_ctrl = StaticAlloc( sizeof( intstar4 ), FT_INTEGER ); } doptr->iteration = loop_ctrl; OutPtr( loop_ctrl ); if( e3_node == NULL ) { DumpType( FT_INTEGER, TypeSize( FT_INTEGER ) ); } else { GenType( e3_node ); } } GenType( e2_node ); DumpType( e1_type, e1_size ); OutU16( CSHead->branch ); OutU16( CSHead->bottom ); } }
int main() { llvm::InitializeNativeTarget(); // Make the module, which holds all the code. llvm::Module *TheModule = new llvm::Module("my cool jit", llvm::getGlobalContext()); // Create the JIT. This takes ownership of the module. std::string ErrStr; llvm::ExecutionEngine *TheExecutionEngine = llvm::EngineBuilder(TheModule).setErrorStr(&ErrStr).create(); if (!TheExecutionEngine) { fprintf(stderr, "Could not create ExecutionEngine: %s\n", ErrStr.c_str()); exit(1); } llvm::FunctionPassManager OurFPM(TheModule); // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new llvm::TargetData(*TheExecutionEngine->getTargetData())); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(llvm::createInstructionCombiningPass()); // Reassociate expressions. OurFPM.add(llvm::createReassociatePass()); // Eliminate Common SubExpressions. OurFPM.add(llvm::createGVNPass()); // Simplify the control flow graph (deleting unreachable blocks, etc). OurFPM.add(llvm::createCFGSimplificationPass()); OurFPM.doInitialization(); // Set the global so the code gen can use this. llvm::FunctionPassManager *TheFPM = &OurFPM; // Single argument std::vector<const llvm::Type*> unaryArg(1,llvm::Type::getDoubleTy(llvm::getGlobalContext())); // Two arguments std::vector<const llvm::Type*> binaryArg(2,llvm::Type::getDoubleTy(llvm::getGlobalContext())); // Two arguments in and two references std::vector<const llvm::Type*> genArg(4); genArg[0] = genArg[1] = llvm::Type::getDoubleTy(llvm::getGlobalContext()); genArg[2] = genArg[3] = llvm::Type::getDoublePtrTy(llvm::getGlobalContext()); // Unary operation llvm::FunctionType *unaryFun = llvm::FunctionType::get(llvm::Type::getDoubleTy(llvm::getGlobalContext()),unaryArg, false); // Binary operation llvm::FunctionType *binaryFun = llvm::FunctionType::get(llvm::Type::getDoubleTy(llvm::getGlobalContext()),binaryArg, false); // More generic operation, return by reference llvm::FunctionType *genFun = llvm::FunctionType::get(llvm::Type::getVoidTy(llvm::getGlobalContext()),genArg, false); // Declare sin llvm::Function *sin_ = llvm::Function::Create(unaryFun, llvm::Function::ExternalLinkage, "sin", TheModule); // Declare my function llvm::Function *myfun = llvm::Function::Create(genFun, llvm::Function::ExternalLinkage, "myfcn", TheModule); // Create a new basic block to start insertion into. llvm::BasicBlock *BB = llvm::BasicBlock::Create(llvm::getGlobalContext(), "entry", myfun); Builder.SetInsertPoint(BB); // Set names for all arguments. llvm::Function::arg_iterator AI = myfun->arg_begin(); AI->setName("x1"); llvm::Value *x1 = AI; AI++; AI->setName("x2"); llvm::Value *x2 = AI; AI++; AI->setName("r1"); llvm::Value *r1 = AI; AI++; AI->setName("r2"); llvm::Value *r2 = AI; llvm::Value *five = llvm::ConstantFP::get(llvm::getGlobalContext(), llvm::APFloat(5.0)); llvm::Value *x1_plus_5 = Builder.CreateFAdd(x1, five, "x1_plus_5"); // Call the sine function std::vector<llvm::Value*> sinarg(1,x2); llvm::Value* sin_x2 = Builder.CreateCall(sin_, sinarg.begin(), sinarg.end(), "callsin"); // Set values llvm::StoreInst *what_is_this1 = Builder.CreateStore(sin_x2,r1); llvm::StoreInst *what_is_this2 = Builder.CreateStore(x1_plus_5,r2); // Finish off the function. Builder.CreateRetVoid(); // Validate the generated code, checking for consistency. verifyFunction(*myfun); // Optimize the function. TheFPM->run(*myfun); // Print out all of the generated code. TheModule->dump(); // JIT the function double x1_val = 10; double x2_val = 20; double r1_val = -1; double r2_val = -1; typedef void (*GenType)(double,double,double*,double*); GenType FP = GenType(intptr_t(TheExecutionEngine->getPointerToFunction(myfun))); FP(x1_val,x2_val,&r1_val,&r2_val); printf("r1 = %g\n", r1_val); printf("r2 = %g\n", r2_val); return 0; }
// Generate a flatbuffer schema from the Parser's internal representation. std::string GenerateFBS(const Parser &parser, const std::string &file_name, const GeneratorOptions &opts) { // Proto namespaces may clash with table names, so we have to prefix all: for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end(); ++it) { for (auto comp = (*it)->components.begin(); comp != (*it)->components.end(); ++comp) { (*comp) = "_" + (*comp); } } std::string schema; schema += "// Generated from " + file_name + ".proto\n\n"; if (opts.include_dependence_headers) { #ifdef FBS_GEN_INCLUDES // TODO: currently all in one file. int num_includes = 0; for (auto it = parser.included_files_.begin(); it != parser.included_files_.end(); ++it) { auto basename = flatbuffers::StripPath( flatbuffers::StripExtension(it->first)); if (basename != file_name) { schema += "include \"" + basename + ".fbs\";\n"; num_includes++; } } if (num_includes) schema += "\n"; #endif } // Generate code for all the enum declarations. const Namespace *last_namespace = nullptr; for (auto enum_def_it = parser.enums_.vec.begin(); enum_def_it != parser.enums_.vec.end(); ++enum_def_it) { EnumDef &enum_def = **enum_def_it; GenNameSpace(*enum_def.defined_namespace, &schema, &last_namespace); GenComment(enum_def.doc_comment, &schema, nullptr); schema += "enum " + enum_def.name + " : "; schema += GenType(enum_def.underlying_type) + " {\n"; for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); ++it) { auto &ev = **it; GenComment(ev.doc_comment, &schema, nullptr, " "); schema += " " + ev.name + " = " + NumToString(ev.value) + ",\n"; } schema += "}\n\n"; } // Generate code for all structs/tables. for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); ++it) { StructDef &struct_def = **it; GenNameSpace(*struct_def.defined_namespace, &schema, &last_namespace); GenComment(struct_def.doc_comment, &schema, nullptr); schema += "table " + struct_def.name + " {\n"; for (auto field_it = struct_def.fields.vec.begin(); field_it != struct_def.fields.vec.end(); ++field_it) { auto &field = **field_it; GenComment(field.doc_comment, &schema, nullptr, " "); schema += " " + field.name + ":" + GenType(field.value.type); if (field.value.constant != "0") schema += " = " + field.value.constant; if (field.required) schema += " (required)"; schema += ";\n"; } schema += "}\n\n"; } return schema; }
void GParenExpr( void ) { //==================== EmitOp( FC_DONE_PAREN_EXPR ); GenType( CITNode ); }
inline bool isZero(GenType a) { return areEqual<GenType>(a, GenType(0.0)); }
inline bool areEqual(GenType a, GenType b) { // FIXME Ambiguous call to absolute value const GenType scale = (std::abs(a) + std::abs(b)) / GenType(2.0); return (std::abs(a - b) <= epsilon<GenType>() * scale); }
bool generate() { code_.Clear(); code_ += "{"; code_ += " \"$schema\": \"http://json-schema.org/draft-04/schema#\","; code_ += " \"definitions\": {"; for (auto e = parser_.enums_.vec.cbegin(); e != parser_.enums_.vec.cend(); ++e) { code_ += " \"" + GenFullName(*e) + "\" : {"; code_ += " " + GenType("string") + ","; std::string enumdef(" \"enum\": ["); for (auto enum_value = (*e)->vals.vec.begin(); enum_value != (*e)->vals.vec.end(); ++enum_value) { enumdef.append("\"" + (*enum_value)->name + "\""); if (*enum_value != (*e)->vals.vec.back()) { enumdef.append(", "); } } enumdef.append("]"); code_ += enumdef; code_ += " },"; // close type } for (auto s = parser_.structs_.vec.cbegin(); s != parser_.structs_.vec.cend(); ++s) { const auto &structure = *s; code_ += " \"" + GenFullName(structure) + "\" : {"; code_ += " " + GenType("object") + ","; std::string comment; const auto &comment_lines = structure->doc_comment; for (auto comment_line = comment_lines.cbegin(); comment_line != comment_lines.cend(); ++comment_line) { comment.append(*comment_line); } if (comment.size() > 0) { code_ += " \"description\" : \"" + comment + "\","; } code_ += " \"properties\" : {"; const auto &properties = structure->fields.vec; for (auto prop = properties.cbegin(); prop != properties.cend(); ++prop) { const auto &property = *prop; std::string typeLine(" \"" + property->name + "\" : { " + GenType(property->value.type) + " }"); if (property != properties.back()) { typeLine.append(","); } code_ += typeLine; } code_ += " },"; // close properties std::vector<FieldDef *> requiredProperties; std::copy_if(properties.begin(), properties.end(), back_inserter(requiredProperties), [](FieldDef const *prop) { return prop->required; }); if (requiredProperties.size() > 0) { std::string required_string(" \"required\" : ["); for (auto req_prop = requiredProperties.cbegin(); req_prop != requiredProperties.cend(); ++req_prop) { required_string.append("\"" + (*req_prop)->name + "\""); if (*req_prop != requiredProperties.back()) { required_string.append(", "); } } required_string.append("],"); code_ += required_string; } code_ += " \"additionalProperties\" : false"; std::string closeType(" }"); if (*s != parser_.structs_.vec.back()) { closeType.append(","); } code_ += closeType; // close type } code_ += " },"; // close definitions // mark root type code_ += " \"$ref\" : \"#/definitions/" + GenFullName(parser_.root_struct_def_) + "\""; code_ += "}"; // close schema root const std::string file_path = GeneratedFileName(path_, file_name_); const std::string final_code = code_.ToString(); return SaveFile(file_path.c_str(), final_code, false); }