Skip to content

Commit

Permalink
Improve cpp code generation (#51)
Browse files Browse the repository at this point in the history
Add the following effect during cpp code generation:

Properly generate field and methods with the right level of privacy (public/private/protected).
Generate .h file instead of .cpp
Add #include statement for other class in the puml file
Protect against multiple inclusion with preprocessor
  • Loading branch information
anliec authored Apr 13, 2020
1 parent eaa9e99 commit 9390c70
Show file tree
Hide file tree
Showing 6 changed files with 388 additions and 159 deletions.
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class PlantUmlToCode {
python: 'py',
ruby: 'rb',
typescript: 'ts',
cpp: 'cpp',
cpp: 'h',
};
}

Expand Down
17 changes: 11 additions & 6 deletions src/parser/plantuml.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ extends
/ connectorsize "|>" { var Extension = require("./Extension"); return new Extension(false) }
connectorsize
= ".."
/ "-up-"
/ "-down-"
/ "-left-"
/ "-right-"
/ [-]+ "up" [-]+
/ [-]+ "down" [-]+
/ [-]+ "left" [-]+
/ [-]+ "right" [-]+
/ "---"
/ "--"
/ [.]
Expand Down Expand Up @@ -110,11 +110,16 @@ methodparameter
= noise item:returntype membername:([ ] membername)? [=] defaultValue:(defaultvalue) [,]? { var Parameter = require("./Parameter"); return new Parameter(item, membername ? membername[1] : null, defaultValue); }
/ noise item:returntype membername:([ ] membername)? [,]? { var Parameter = require("./Parameter"); return new Parameter(item, membername ? membername[1] : null); }
returntype
= items:[^ ,\n\r\t(){}]+ { return items.join("") }
= items:[^ ,\n\r\t(){}<>]+ template:([<] templateargs [>])? typeinfo:[*\[\]&]* { return items.join("") + (template ? template.join("") : "") + typeinfo.join(""); }
templateargs
= items:templatearg+ { return items; }
templatearg
= noise item:returntype noise [,]? { return item; }
objectname
= objectname:([A-Za-z_][A-Za-z0-9.]*) { return [objectname[0], objectname[1].join("")].join("") }
membername
= items:([A-Za-z_\*][A-Za-z0-9_]*) { return [items[0], items[1].join("")].join("") }
= "operator" op:[+=*/<>!~^&|,\[\]]+ { return "operator" + op.join("") }
/ items:([A-Za-z_\*][A-Za-z0-9_]*) { return [items[0], items[1].join("")].join("")}
defaultvalue
= items:([{}\[\]A-Za-z0-9_\'\"]*) { return items.join("") }
accessortype
Expand Down
69 changes: 51 additions & 18 deletions src/templates/cpp.hbs
Original file line number Diff line number Diff line change
@@ -1,31 +1,64 @@
/**
* \file {{getFullName}}.cpp
* \file {{getFullName}}.h
*/

#ifndef {{getFullName}}_h
#define {{getFullName}}_h

{{#if getExtends}}#include "{{#with getExtends}}{{getFullName}}{{/with}}.h"{{/if}}


class {{getFullName}}{{#if getExtends}}: public {{#with getExtends}}{{getFullName}}{{/with}}{{/if}} {
{{#if hasPrivateFields}}
private:
{{#each getPrivateFields}}
{{this.getReturnType}} {{this.getName}};
{{/each}}{{/if}}
{{!#if hasPrivateFields}}
private:{{#each getPrivateFields}}
{{this.getReturnType}} {{this.getName}};{{/each}}{{!/if}}
protected:{{#each getFields}}{{#if this.isProtected}}
{{this.getReturnType}} {{this.getName}};{{/if}}{{/each}}
public:{{#each getFields}}{{#if this.isPublic}}
{{this.getReturnType}} {{this.getName}};{{/if}}{{/each}}

public:
{{getFullName}}({{#each getConstructorArgs}}{{#if @first}}{{else}}, {{/if}}{{#if getName}}{{getName}}{{else}}param{{@index}}{{/if}}{{/each}}) {
{{getFullName}}({{#each getConstructorArgs}}{{#if @first}}{{else}}, {{/if}}{{#if getName}}{{getName}}{{#if getDefaultValue}}={{SafeString this getDefaultValue}}{{/if}}{{else}}param{{@index}}{{/if}}{{/each}}){{#if getExtends}}: {{#with getExtends}}{{getFullName}}{{/with}}(){{/if}}
{
// @todo
}{{#if hasPublichMethods}}{{#each getPublichMethods}}{{#if isNotConstructor}}
{{this.getReturnType}} {{this.getName}}{{#if this.getParameters}}({{#each this.getParameters}}{{#if @first}}{{else}}, {{/if}}{{this.getReturnType}} {{#if this.getName}}{{this.getName}}{{else}}param{{@index}}{{/if}}{{/each}}){{else}}(){{/if}} {
{{#if this.needsReturnStatement}}
return null;{{/if}}
}
{{/if}}{{/each}}{{/if}}
{{#if hasPrivateMethods}}
private:{{#each getMethods}}{{#if isNotConstructor}}
// Public methods
{{#each getMethods}}{{#if isNotConstructor}}{{#if isPublic}}
/**{{#each this.getParameters}}
* @param {{getName}} TBD{{/each}}{{#if this.needsReturnStatement}}
* @return {{this.getReturnType}}{{/if}}
*/
{{this.getReturnType}} {{this.getName}}{{#if this.getParameters}}({{#each this.getParameters}}{{#if @first}}{{else}}, {{/if}}{{this.getReturnType}} {{#if this.getName}}{{this.getName}}{{else}}param{{@index}}{{/if}}{{/each}}){{else}}(){{/if}} {
{{#if this.needsReturnStatement}}
return null;{{/if}}
{{this.getReturnType}} {{this.getName}}{{#if this.getParameters}}({{#each this.getParameters}}{{#if @first}}{{else}}, {{/if}}{{this.getReturnType}} {{#if this.getName}}{{this.getName}}{{#if getDefaultValue}}={{SafeString this getDefaultValue}}{{/if}}{{else}}param{{@index}}{{/if}}{{/each}}){{else}}(){{/if}} {
// @todo {{#if this.needsReturnStatement}}
return {{this.getReturnType}}();{{/if}}
}
{{/if}}{{/each}}{{/if}}
{{/if}}{{/if}}{{/each}}

{{!#if hasProtectedMethods}}
// Protected methods
protected:{{#each getMethods}}{{#if isNotConstructor}}{{#if isProtected}}
/**{{#each this.getParameters}}
* @param {{getName}} TBD{{/each}}{{#if this.needsReturnStatement}}
* @return {{this.getReturnType}}{{/if}}
*/
{{this.getReturnType}} {{this.getName}}{{#if this.getParameters}}({{#each this.getParameters}}{{#if @first}}{{else}}, {{/if}}{{this.getReturnType}} {{#if this.getName}}{{this.getName}}{{#if getDefaultValue}}={{SafeString this getDefaultValue}}{{/if}}{{else}}param{{@index}}{{/if}}{{/each}}){{else}}(){{/if}} {
// @todo {{#if this.needsReturnStatement}}
return {{this.getReturnType}}();{{/if}}
}
{{/if}}{{/if}}{{/each}}{{!/if}}

{{!#if hasPrivateMethods}}
// Private methods
private:{{#each getMethods}}{{#if isNotConstructor}}{{#if isPrivate}}
/**{{#each this.getParameters}}
* @param {{getName}} TBD{{/each}}{{#if this.needsReturnStatement}}
* @return {{this.getReturnType}}{{/if}}
*/
{{this.getReturnType}} {{this.getName}}{{#if this.getParameters}}({{#each this.getParameters}}{{#if @first}}{{else}}, {{/if}}{{this.getReturnType}} {{#if this.getName}}{{this.getName}}{{#if getDefaultValue}}={{SafeString this getDefaultValue}}{{/if}}{{else}}param{{@index}}{{/if}}{{/each}}){{else}}(){{/if}} {
// @todo {{#if this.needsReturnStatement}}
return {{this.getReturnType}}();{{/if}}
}
{{/if}}{{/if}}{{/each}}{{!/if}}
}

#endif // {{getFullName}}_h
23 changes: 13 additions & 10 deletions test/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const chaiAsPromised = require('chai-as-promised');
// module under test
const cli = require('../src/cli');
const { languages, getExtension } = require('../src');
// list of files to use for test
const inputPumlList = ['./test/data/car'];

const { expect } = chai;
chai.use(chaiAsPromised);
Expand Down Expand Up @@ -41,16 +43,17 @@ describe('cli', () => {
cli(['node', 'puml2code', '-a']);
expect(process.exit.calledOnceWith(1)).to.be.true;
});
describe('input', () => {
languages.forEach((lang) => {
it(`${lang}`, async () => {
let stdout = '';
const input = './test/data/car.puml';
const printer = (data) => { stdout += `${data}\n`; };
const shoulFile = `./test/data/car.${lang}.${getExtension(lang)}`;
const retcode = await cli(['node', 'puml2code', '-l', lang, '-i', input], printer);
expect(stdout).to.be.equal(readFileSync(shoulFile).toString());
expect(retcode).to.be.equal(0);
inputPumlList.forEach((input) => {
describe(input, () => {
languages.forEach((lang) => {
it(`${lang}`, async () => {
let stdout = '';
const printer = (data) => { stdout += `${data}\n`; };
const shoulFile = `${input}.${lang}.${getExtension(lang)}`;
const retcode = await cli(['node', 'puml2code', '-l', lang, '-i', `${input}.puml`], printer);
expect(stdout).to.be.equal(readFileSync(shoulFile).toString());
expect(retcode).to.be.equal(0);
});
});
});
});
Expand Down
124 changes: 0 additions & 124 deletions test/data/car.cpp.cpp

This file was deleted.

Loading

0 comments on commit 9390c70

Please sign in to comment.