Skip to content

Commit

Permalink
implement autogeneration of getter/setter
Browse files Browse the repository at this point in the history
implement autogeneration of getter/setter
  • Loading branch information
jyoo980 committed Oct 13, 2019
2 parents 4f2a9d5 + 1fdc41e commit 71c377f
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 5 deletions.
6 changes: 6 additions & 0 deletions README.md
Expand Up @@ -6,6 +6,12 @@ This is a repository for CPSC 410: Advanced Software Engineering. The TS-DSL sho
* yarn (>= v1.17.3)
* tsc (>= 3.6.3)

## Demo

1. Navigate to `ts-dsl/ui`
2. Run `tsc TypeScript.ts`
3. Run `node TypeScript.js simpleProgramClass.txt`

## Working with ts-dsl

* To build: `yarn build`
Expand Down
41 changes: 41 additions & 0 deletions src/ast/ClassDecl.ts
Expand Up @@ -5,6 +5,10 @@ import {ImplementsDecl} from "./ImplementsDecl";
import CommentDecl from "./CommentDecl";
import FuncDecl from "./FuncDecl";
import {Tokenizer} from "../util/Tokenizer";
import StaticDecl from "./StaticDecl";
import AsyncDecl from "./AsyncDecl";
import {VarList} from "./VarList";
import Func = Mocha.Func;

/**
* Represents a Class a TypeScript project may have.
Expand Down Expand Up @@ -48,6 +52,17 @@ export class ClassDecl extends Content {
while(context.getCurrentLineTabLevel() > indentLevel && context.checkToken("fields")) {
let field: FieldDecl = new FieldDecl();
field.parse(context);
if (field.generateGetter) {
field.fields.nameTypeMap.forEach((type: string, name: string) => {
this.functions.push(this.createGetter(name, type));
});

}
if (field.generateSetter) {
field.fields.nameTypeMap.forEach((type: string, name: string) => {
this.functions.push(this.createSetter(name, type));
});
}
this.fields.push(field);
}

Expand Down Expand Up @@ -79,4 +94,30 @@ export class ClassDecl extends Content {
public getAbsolutePath(): string {
return `${this.parentPath}/${this.className}.ts`;
}

private createGetter(name: string, type: string): FuncDecl {
let funcGetter: FuncDecl = new FuncDecl();
funcGetter.name = "get" + name.charAt(0).toUpperCase() + name.slice(1);
funcGetter.returnDecl.returnType = type;
funcGetter.modifier = "public";
funcGetter.maybeStatic = new StaticDecl(); // not static
funcGetter.maybeAsync = new AsyncDecl(); // not async
funcGetter.params = new VarList();
funcGetter.comments = new CommentDecl();
return funcGetter;
}

private createSetter(name: string, type: string): FuncDecl {
let funcSetter: FuncDecl = new FuncDecl();
// setName
funcSetter.name = "set" + name.charAt(0).toUpperCase() + name.slice(1);
funcSetter.returnDecl.returnType = "void";
funcSetter.modifier = "public";
funcSetter.maybeStatic = new StaticDecl(); // not static
funcSetter.maybeAsync = new AsyncDecl(); // not async
funcSetter.params = new VarList();
funcSetter.params.addPair(name, type);
funcSetter.comments = new CommentDecl();
return funcSetter;
}
}
1 change: 1 addition & 0 deletions src/ast/FuncDecl.ts
Expand Up @@ -22,6 +22,7 @@ export default class FuncDecl extends AstNode {
name: string;
params: VarList;
comments: CommentDecl;
body: string = null; // only used in getter/setter
returnDecl: ReturnDecl = new ReturnDecl();

public parse(context: Tokenizer): any {
Expand Down
45 changes: 45 additions & 0 deletions src/ast/InterfaceDecl.ts
Expand Up @@ -4,6 +4,9 @@ import {FieldDecl} from "./FieldDecl";
import CommentDecl from "./CommentDecl";
import FuncDecl from "./FuncDecl";
import {Tokenizer} from "../util/Tokenizer";
import StaticDecl from "./StaticDecl";
import AsyncDecl from "./AsyncDecl";
import {VarList} from "./VarList";

/**
* Represents an Interface a TypeScript project may have.
Expand Down Expand Up @@ -36,6 +39,19 @@ export class InterfaceDecl extends Content {
this.fieldDecl = new FieldDecl();
this.fieldDecl.isInterfaceField = true;
this.fieldDecl.parse(context);

// handle getter/setter functions
if (this.fieldDecl.generateGetter) {
this.fieldDecl.fields.nameTypeMap.forEach((name: string, type: string) => {
this.functions.push(this.createGetter(name, type));
});

}
if (this.fieldDecl.generateSetter) {
this.fieldDecl.fields.nameTypeMap.forEach((name: string, type: string) => {
this.functions.push(this.createSetter(name, type));
});
}
}

while(context.getCurrentLineTabLevel() > indentLevel && context.checkToken("function")) {
Expand Down Expand Up @@ -72,4 +88,33 @@ export class InterfaceDecl extends Content {
public getAbsolutePath(): string {
return this.parentPath + "/" + this.interfaceName + ".ts";
}

private createGetter(name: string, type: string): FuncDecl {
let funcGetter: FuncDecl = new FuncDecl();
// getName
funcGetter.name = "get" + name.charAt(0).toUpperCase() + name.slice(1);
funcGetter.returnDecl.returnType = type;
funcGetter.modifier = "public";
funcGetter.maybeStatic = new StaticDecl(); // not static
funcGetter.maybeAsync = new AsyncDecl(); // not async
// no params
funcGetter.params = new VarList();
funcGetter.comments = new CommentDecl();
return funcGetter;
}

private createSetter(name: string, type: string): FuncDecl {
let funcSetter: FuncDecl = new FuncDecl();
// setName
funcSetter.name = "set" + name.charAt(0).toUpperCase() + name.slice(1);
funcSetter.returnDecl.returnType = "void";
funcSetter.modifier = "public";
funcSetter.maybeStatic = new StaticDecl(); // not static
funcSetter.maybeAsync = new AsyncDecl(); // not async
// one param
funcSetter.params = new VarList();
funcSetter.params.addPair(name, type);
funcSetter.comments = new CommentDecl();
return funcSetter;
}
}
28 changes: 26 additions & 2 deletions src/codegen/TypeScriptEngine.ts
Expand Up @@ -7,7 +7,9 @@ import {FunctionDeclaration,
ClassDeclaration,
InterfaceDeclaration,
ClassElement,
TypeElement} from "typescript";
TypeElement,
Block,
Statement} from "typescript";
import {VarList} from "../ast/VarList";
import {TypeTable} from "../ast/symbols/TypeTable";
import FuncDecl from "../ast/FuncDecl";
Expand Down Expand Up @@ -122,12 +124,34 @@ export default class TypeScriptEngine {
undefined,
tsParams,
tsReturnType,
ts.createBlock(retStatement, false)
this.makeBody(funcDecl, retStatement)
);
this.addLeadingComment(methodSig, funcDecl.comments);
return methodSig;
}

private makeBody(funcDecl: FuncDecl, defaultRetStatement: Statement[]): Block {
const funcName: string = funcDecl.name;
if (funcName.includes("get")) {
const nameOfField: string = funcName.split("get")[1];
const fieldAsLowercase: string = nameOfField.charAt(0).toLowerCase() + nameOfField.slice(1);
const statements: Statement[] = [ts.createReturn(ts.createIdentifier(`this.${fieldAsLowercase}`))];
return ts.createBlock(statements, false);
} else if (funcName.includes("set")) {
const nameOfField: string = funcName.split("set")[1];
const fieldAsLowercase: string = nameOfField.charAt(0).toLowerCase() + nameOfField.slice(1);
const setterBody: Statement[] = [ts.createExpressionStatement(ts.createBinary(
ts.createIdentifier(`this.${fieldAsLowercase}`),
ts.SyntaxKind.EqualsToken,
ts.createIdentifier(fieldAsLowercase))
)];
return ts.createBlock(setterBody, false);
} else {
return ts.createBlock(defaultRetStatement, false);
}

}

private makeMethodModifiers(funcDecl: FuncDecl): Modifier[] {
if (funcDecl.modifier) {
return this.makeModifierNodes([funcDecl.modifier]);
Expand Down
4 changes: 1 addition & 3 deletions test/testFiles/simpleProgramClass.txt
Expand Up @@ -7,8 +7,6 @@ project TestProject
generate setters
fields public [ number date ]
generate getters
function private getDate
function private makeDate
params [ string id, string content, string kind ]
returns string


13 changes: 13 additions & 0 deletions ui/simpleProgramClass.txt
@@ -0,0 +1,13 @@
project TestProject
modules [ ]
dir src/model
class Time
fields private [ number dayOfWeek, number hour, number minute ]
generate getters
generate setters
fields public [ number date ]
generate getters
function private formatDate
params [ string id, string content, string kind ]
returns string

0 comments on commit 71c377f

Please sign in to comment.