Skip to content

Commit c064b32

Browse files
committed
Added support for self keyword
1 parent 0fa51ca commit c064b32

File tree

7 files changed

+278
-58
lines changed

7 files changed

+278
-58
lines changed

samples/dci/js/Dijkstra/CalculateShortestPath.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ var CalculateShortestPath = DCI.Context.extend(function() {
4545
role Initial {}
4646

4747
role Neighbor {
48-
visited() {
48+
visited() {
4949
return !Unvisited.has(this);
5050
}
5151
}
@@ -64,10 +64,10 @@ var CalculateShortestPath = DCI.Context.extend(function() {
6464
Neighbor <- node;
6565
if (Neighbor.visited()) return;
6666

67-
var alternate = Tentative.get(Current) + Current.distanceTo(Neighbor);
67+
var alternate = Tentative.get(self) + self.distanceTo(Neighbor);
6868
if (alternate < Tentative.get(Neighbor)) {
6969
Tentative.add(Neighbor, alternate);
70-
Path.add(Neighbor, Current);
70+
Path.add(Neighbor, self);
7171
}
7272
});
7373
}
@@ -91,7 +91,8 @@ var CalculateShortestPath = DCI.Context.extend(function() {
9191
role Tentative {}
9292

9393
role Unvisited {
94-
findNearest() {
94+
95+
findNearest() {
9596
var nearest = undefined,
9697
distance = Infinity;
9798
this.each(function(node) {
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
2+
3+
"use strict";
4+
5+
/*
6+
HashMap
7+
8+
Features include:
9+
* support for object keys
10+
* fast keys or values iteration using for (;;) instead of for in syntax (http://jsperf.com/array-keys-vs-object-keys-iteration/3 )
11+
(thanks to https://gist.github.com/alaa-eddine/6317515)
12+
*/
13+
var HashMap = (function () {
14+
function HashMap() {
15+
this.length = 0;
16+
//Keys will be stored here giving fast iteration through keys with a for loop
17+
this.keys = [];
18+
//Values will be stored here giving fast iteration with a for loop
19+
this.values = [];
20+
}
21+
HashMap.prototype.indexOf = function (key) {
22+
for (var i = 0, len = this.keys.length; i < len; i++) {
23+
if (this.keys[i] == key)
24+
return i;
25+
}
26+
return -1;
27+
};
28+
29+
HashMap.prototype.add = function (key, value) {
30+
if (key === undefined && value === undefined)
31+
return undefined;
32+
33+
var previous = undefined;
34+
35+
//Are we replacing an existing element ?
36+
var index = this.indexOf(key);
37+
if (index != -1) {
38+
previous = this.values[index];
39+
this.values[index] = value;
40+
this.keys[index] = key;
41+
} else {
42+
this.values.push(value);
43+
this.keys.push(key);
44+
this.length++;
45+
}
46+
47+
return previous;
48+
};
49+
50+
HashMap.prototype.get = function (key) {
51+
if (this.has(key))
52+
return this.values[this.indexOf(key)];
53+
};
54+
55+
HashMap.prototype.has = function (key) {
56+
return (this.indexOf(key) != -1);
57+
};
58+
59+
HashMap.prototype.remove = function (key) {
60+
var index = this.indexOf(key);
61+
if (index != -1) {
62+
var previous = this.values[index];
63+
delete this.values[index];
64+
delete this.keys[index];
65+
66+
this.length--;
67+
return previous;
68+
} else {
69+
return undefined;
70+
}
71+
//TODO : clean this.keys and this.values from undefined values when their size becomes too big
72+
};
73+
74+
//helper function to iterate through all values
75+
HashMap.prototype.each = function (fn) {
76+
for (var i = 0; i < this.keys.length; i++) {
77+
fn(this.keys[i], this.values[i]);
78+
}
79+
};
80+
81+
HashMap.prototype.map = function (fn) {
82+
if (typeof fn != 'function')
83+
return;
84+
var result = [];
85+
for (var i = 0; i < this.keys.length; i++) {
86+
result[i] = fn(this.keys[i], this.values[i]);
87+
}
88+
return result;
89+
};
90+
91+
HashMap.prototype.clear = function () {
92+
this.values = [];
93+
this.keys = [];
94+
this.length = 0;
95+
};
96+
97+
HashMap.prototype.isEmpty = function () {
98+
return this.length == 0;
99+
};
100+
return HashMap;
101+
})();
102+
module.exports = HashMap;
103+
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
export = HashMap;
2+
3+
"use strict";
4+
5+
/*
6+
HashMap
7+
8+
Features include:
9+
* support for object keys
10+
* fast keys or values iteration using for (;;) instead of for in syntax (http://jsperf.com/array-keys-vs-object-keys-iteration/3 )
11+
(thanks to https://gist.github.com/alaa-eddine/6317515)
12+
*/
13+
14+
class HashMap {
15+
public length: number = 0;
16+
17+
//Keys will be stored here giving fast iteration through keys with a for loop
18+
public keys: any[] = [];
19+
20+
//Values will be stored here giving fast iteration with a for loop
21+
public values: any[] = [];
22+
23+
indexOf(key) {
24+
for (var i = 0, len = this.keys.length; i < len; i++){
25+
if (this.keys[i] == key)
26+
return i;
27+
}
28+
return -1;
29+
}
30+
31+
add(key, value) {
32+
if (key === undefined && value === undefined) return undefined;
33+
34+
var previous = undefined;
35+
36+
//Are we replacing an existing element ?
37+
var index = this.indexOf(key);
38+
if (index != -1) {
39+
previous = this.values[index];
40+
this.values[index] = value;
41+
this.keys[index] = key;
42+
}
43+
else {
44+
this.values.push(value);
45+
this.keys.push(key);
46+
this.length++;
47+
}
48+
49+
return previous;
50+
}
51+
52+
get (key) {
53+
if (this.has(key))
54+
return this.values[this.indexOf(key)];
55+
}
56+
57+
has(key) {
58+
return (this.indexOf(key) != -1);
59+
}
60+
61+
remove(key) {
62+
var index = this.indexOf(key);
63+
if (index != -1) {
64+
var previous = this.values[index];
65+
delete this.values[index];
66+
delete this.keys[index];
67+
68+
this.length--;
69+
return previous;
70+
}
71+
else {
72+
return undefined;
73+
}
74+
75+
//TODO : clean this.keys and this.values from undefined values when their size becomes too big
76+
}
77+
78+
//helper function to iterate through all values
79+
each(fn) {
80+
for(var i = 0; i < this.keys.length; i++){
81+
fn(this.keys[i], this.values[i]);
82+
}
83+
}
84+
85+
map(fn) {
86+
if (typeof fn != 'function') return;
87+
var result = [];
88+
for(var i = 0; i < this.keys.length; i++){
89+
result[i] = fn(this.keys[i], this.values[i]);
90+
}
91+
return result;
92+
}
93+
94+
clear() {
95+
this.values = [];
96+
this.keys = [];
97+
this.length = 0;
98+
}
99+
100+
isEmpty() {
101+
return this.length == 0;
102+
}
103+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import DCI = require('../../DCI');
2+
3+
export class TransferMoney extends DCI.Context
4+
{
5+
/**
6+
* @param {Account} sourceAcct
7+
* @param {Account} destinationAcct
8+
* @param {number} amount
9+
*/
10+
bindRoles(sourceAcct, destinationAcct, amount) {
11+
SourceAccount <- sourceAcct;
12+
DestinationAccount <- destinationAcct;
13+
Amount <- amount;
14+
}
15+
16+
role SourceAccount {
17+
transferOut() {
18+
this.withdraw();
19+
DestinationAccount.deposit();
20+
}
21+
22+
withdraw() {
23+
this.decreaseBalance(Amount);
24+
}
25+
}
26+
27+
role DestinationAccount {
28+
deposit() {
29+
this.increaseBalance(Amount);
30+
}
31+
}
32+
33+
role Amount {}
34+
}

src/compiler/ast.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,11 @@ module TypeScript {
251251
//DCI
252252
//If we're inside a DCI context
253253
if (emitter.thisDCIContextNode) {
254-
if (this.actualText in emitter.thisDCIContextNode.roleDeclarations) {
254+
if (emitter.thisRoleNode && this.actualText == 'self') {
255+
emitter.writeToOutput("__context." + emitter.thisRoleNode.name.actualText);
256+
return;
257+
}
258+
else if (this.actualText in emitter.thisDCIContextNode.roleDeclarations) {
255259
emitter.writeToOutput("__context.");
256260
}
257261
}

src/compiler/emitter.ts

Lines changed: 22 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -569,32 +569,13 @@ module TypeScript {
569569
operand2: Identifier,
570570
dciContext: DCIContext,
571571
isCallToRoleMethod = false,
572-
isCallToSelf = false,
572+
//isCallToSelf = false,
573573
roleName: string;
574574

575575
//DCI
576576
//Determine whether it's a call to a role method
577577
if (this.thisFunctionNode && target instanceof BinaryExpression) {
578578

579-
/*
580-
if (this.thisFunctionNode.isDCIContext) {
581-
dciContext = this.thisFunctionNode;
582-
}
583-
else {
584-
//Check to see if any of the parent functions to which this function belongs are a DCI context
585-
var declStack = this.declStack;
586-
for (var i=0; i < declStack.length; i++) {
587-
if (declStack[i] instanceof PullFunctionExpressionDecl) {
588-
var funcDecl = <FunctionDeclaration>declStack[i].ast;
589-
if (funcDecl.isDCIContext) {
590-
dciContext = funcDecl;
591-
break;
592-
}
593-
}
594-
}
595-
}
596-
*/
597-
598579
//If we're currently inside a DCI context
599580
if (this.thisDCIContextNode) {
600581
dciContext = this.thisDCIContextNode;
@@ -604,50 +585,42 @@ module TypeScript {
604585

605586
//if currently inside a role
606587
if (this.thisRoleNode) {
607-
if (this.thisRoleNode && operand1 instanceof ThisExpression) {
588+
if (this.thisRoleNode && (operand1 instanceof ThisExpression || operand1.actualText == 'self') ) {
608589
roleName = this.thisRoleNode.name.actualText;
609-
isCallToSelf = true;
590+
//isCallToSelf = true;
610591
}
611592
}
612593

613-
if (!isCallToSelf) {
614-
roleName = operand1.actualText;
615-
if (roleName in dciContext.roleDeclarations) {
616-
//Check whether the method exists on the role - if not, it's a data object method, not a role method
617-
var methodName = operand2.actualText;
618-
var roleDecl: RoleDeclaration = dciContext.roleDeclarations[roleName];
619-
roleDecl.members.members.forEach(function(member) {
620-
if ((<FunctionDeclaration>member).name.actualText == methodName) {
621-
isCallToRoleMethod = true;
622-
return false; //exit loop
623-
}
624-
});
625-
}
594+
if (!roleName) roleName = operand1.actualText;
595+
596+
//if (!isCallToSelf) {
597+
//roleName = operand1.actualText;
598+
if (roleName && roleName in dciContext.roleDeclarations) {
599+
//Check whether the method exists on the role - if not, it's a data object method, not a role method
600+
var methodName = operand2.actualText;
601+
var roleDecl: RoleDeclaration = dciContext.roleDeclarations[roleName];
602+
roleDecl.members.members.forEach(function(member) {
603+
if ((<FunctionDeclaration>member).name.actualText == methodName) {
604+
isCallToRoleMethod = true;
605+
return false; //exit loop
606+
}
607+
});
626608
}
609+
//}
627610
}
628611
}
629612

630613
//DCI
631-
if (isCallToRoleMethod || isCallToSelf) {
632-
//If the call is within a role and begins with `this.`
633-
if (isCallToSelf) {
634-
this.writeToOutput("__dci_internal__.callMethodOnSelf");
635-
//this.writeToOutput("DCI.callMethodOnSelf");
636-
this.writeToOutput("(__context, this, '" + roleName + "'");
637-
this.writeToOutput(", '" + operand2.actualText + "'");
638-
}
639-
else {
640-
this.writeToOutput("__context.__$" + roleName + "." + operand2.actualText + ".");
641-
this.writeToOutput("call(__context." + roleName);
642-
}
614+
if (isCallToRoleMethod) {
615+
this.writeToOutput("__context.__$" + roleName + "." + operand2.actualText + ".");
616+
this.writeToOutput("call(__context." + roleName);
617+
643618
if (args && args.members.length) this.writeToOutput(", ");
644619

645620
this.recordSourceMappingStart(args);
646621

647622
if (args && args.members.length) {
648-
if (isCallToSelf) this.writeToOutput("[");
649623
this.emitCommaSeparatedList(args);
650-
if (isCallToSelf) this.writeToOutput("]");
651624
}
652625
}
653626
else {

0 commit comments

Comments
 (0)