diff --git a/core-lib/TestSuite/Minitest.ns b/core-lib/TestSuite/Minitest.ns index 8398c2d44..2585f9442 100644 --- a/core-lib/TestSuite/Minitest.ns +++ b/core-lib/TestSuite/Minitest.ns @@ -436,9 +436,9 @@ OTHER DEALINGS IN THE SOFTWARE. *) immediately garbage-collectable, which is an important property for large test suites. *) cleanUp. promisePair resolve: testSuccess ] - onError: [:e | + onError: [:ex | | exClass | - exClass:: (ClassMirror reflecting: e) classObject. + exClass:: (ClassMirror reflecting: ex) classObject. exClass == TestFailureException ifTrue: [ promisePair resolve: (testContextInstance ifNil: [ TestFailure case: self description: ex messageText] diff --git a/core-lib/TestSuite/applicationsTests/InstantMessengerAppTest.ns b/core-lib/TestSuite/applicationsTests/InstantMessengerAppTest.ns new file mode 100644 index 000000000..735c880d3 --- /dev/null +++ b/core-lib/TestSuite/applicationsTests/InstantMessengerAppTest.ns @@ -0,0 +1,64 @@ +class InstantMessengerAppTest usingPlatform: platform testFramework: minitest = Value ( +| private AsyncTestContext = minitest AsyncTestContext. + private actors = platform actors. + private messengerApp = (platform system + loadModule: '../../demos/applications/InstantMessengerApplication.ns' nextTo: self) + usingPlatform: platform. + private InstantMessenger = messengerApp InstantMessenger. +|)( + + public class MessengerTest = AsyncTestContext ()( + + public testAsyncAddMessenger = ( + | messenger1 messenger2 pMessenger pName pp | + pp:: actors createPromisePair. + + messenger1:: (actors createActorFromValue: InstantMessenger) <-: new: 'Joe' total: 2. + messenger2:: (actors createActorFromValue: InstantMessenger) <-: new: 'Marie' total: 2. + + pMessenger:: messenger2 <-: addMessenger: messenger1. + + pMessenger whenResolved:[: farRefRemoteMessenger | + pName:: farRefRemoteMessenger <-: name. + + pName whenResolved: [: r | + pp resolver resolve: r + ]. + ]. + + ^ assert: pp promise resolvedWith: 'Joe' + ) + + public testAsyncSendMessage = ( + | messenger1 messenger2 pDiscover pp pName msg pSend | + pp:: actors createPromisePair. + + messenger1:: (actors createActorFromValue: InstantMessenger) <-: new: 'Joe' total: 2. + messenger2:: (actors createActorFromValue: InstantMessenger) <-: new: 'Marie' total: 2. + + pDiscover:: messenger1 <-: addMessenger: messenger2. + + pName:: pDiscover <-: name. + pName whenResolved: [: remoteName | + msg:: ('Hello ' + remoteName). + pSend:: messenger1 <-: sendMessage: remoteName contentMsg: msg. + + pSend whenResolved: [: r | + pp resolver resolve: r ] ]. + + ^ assert: pp promise resolvedWith: #ok + ) + + public testAsyncChat = ( + | messenger1 messenger2 p array | + messenger1:: (actors createActorFromValue: InstantMessenger) <-: new: 'Joe' total: 2. + messenger2:: (actors createActorFromValue: InstantMessenger) <-: new: 'Marie' total: 2. + + p:: messenger1 <-: startChat: messenger2. + ^ p whenResolved: [: result | + result ifNotNil: [ + assert: (result sender) equals:'Joe'. + assert: (result content) equals:'Hello Marie' ] ]. + ) + ) : ( TEST_CONTEXT = () ) +) diff --git a/core-lib/TestSuite/applicationsTests/InternetCafeAppTest.ns b/core-lib/TestSuite/applicationsTests/InternetCafeAppTest.ns new file mode 100644 index 000000000..18cb840b7 --- /dev/null +++ b/core-lib/TestSuite/applicationsTests/InternetCafeAppTest.ns @@ -0,0 +1,98 @@ +class InternetCafeAppTest usingPlatform: platform testFramework: minitest = Value ( +| private AsyncTestContext = minitest AsyncTestContext. + private actors = platform actors. + private Exception = platform kernel Exception. + private cafeApp = (platform system + loadModule: '../../demos/applications/InternetCafeApplication.ns' nextTo: self) + usingPlatform: platform. + private InternetCafe = cafeApp InternetCafe. +| +)( + + public class CafeTest = AsyncTestContext ()( + + public testAsyncAskComputer = ( + | cafeActor numberComputers numberCustomers pCustomer pResult | + + numberComputers:: 3. + numberCustomers:: 1. + + cafeActor:: (actors createActorFromValue: InternetCafe) <-: new: numberComputers totalCustomers: numberCustomers. + + pCustomer:: cafeActor <-: createCustomer: 'Paul' room: cafeActor. + + pResult:: pCustomer <-: askComputer. + + ^ pResult whenResolved:[: array | + assert: (array at: 1) equals:'Paul'. + assert: (array at: 2) equals: 1. + ]. + ) + + public testAsyncFullRoom = ( + | cafeActor numberComputers numberCustomers pResult1 pResult2 pResult3 pCustomer1 pCustomer2 pCustomer3 pp | + + numberComputers:: 2. + numberCustomers:: 3. + + cafeActor:: (actors createActorFromValue: InternetCafe) <-: new: numberComputers totalCustomers: numberCustomers. + + pCustomer1:: cafeActor <-: createCustomer: 'Paul' room: cafeActor. + pCustomer2:: cafeActor <-: createCustomer: 'Jane' room: cafeActor. + pCustomer3:: cafeActor <-: createCustomer: 'Julia' room: cafeActor. + + pResult1:: pCustomer1 <-: askComputer. + pResult2:: pCustomer2 <-: askComputer. + pResult3:: pCustomer3 <-: askComputer. + + ^ pResult1 whenResolved:[:r1 | + assert: (r1 at: 1) equals:'Paul'. + assert: (r1 at: 2) equals: 1. + + pResult2 whenResolved:[:r2 | + assert: (r2 at: 1) equals:'Jane'. + assert: (r2 at: 2) equals: 2. + + pResult3 whenResolved:[:r3 | + assert: (r3 at: 1) equals:'Julia'. + assert: ((r3 at: 2) asString) equals:'instance of FarReference'. + (* far reference that represents the promise pair created because there is no computer availability *) + ]. + ]. + ]. + ) + + public testAsyncReleaseComputer = ( + | cafeActor numberComputers numberCustomers pResult1 pResult2 pCustomer1 pCustomer2 completionPP pReleased | + + completionPP:: actors createPromisePair. + + numberComputers:: 1. + numberCustomers:: 2. + + cafeActor:: (actors createActorFromValue: InternetCafe) <-: new: numberComputers totalCustomers: numberCustomers. + + pCustomer1:: cafeActor <-: createCustomer: 'Paul' room: cafeActor. + pCustomer2:: cafeActor <-: createCustomer: 'Jane' room: cafeActor. + + pResult1:: pCustomer1 <-: askComputer. + + actors after: 10 do: [ + pReleased:: pCustomer1 <-: releaseComputer: 1. + pReleased whenResolved: [:r7 | + cafeActor <-: resolvePendingPromise: 1. + ]. + + pResult2:: pCustomer2 <-: askComputer. + pResult2 whenResolved:[:r | + assert: (r at: 1) equals:'Jane'. + completionPP resolver resolve: (r at: 2). + ]. + ]. + + ^ assert: completionPP promise resolvedWith: 1 + ) + + ) : ( + TEST_CONTEXT = () ) +) \ No newline at end of file diff --git a/core-lib/TestSuite/applicationsTests/MusicPlayerAppTest.ns b/core-lib/TestSuite/applicationsTests/MusicPlayerAppTest.ns new file mode 100644 index 000000000..8b6573a66 --- /dev/null +++ b/core-lib/TestSuite/applicationsTests/MusicPlayerAppTest.ns @@ -0,0 +1,105 @@ +class MusicPlayerAppTest usingPlatform: platform testFramework: minitest = Value ( +| private actors = platform actors. + private AsyncTestContext = minitest AsyncTestContext. + private musicApp = (platform system + loadModule: '../../demos/applications/MusicPlayerApplication.ns' nextTo: self) + usingPlatform: platform. + private MusicPlayer = musicApp MusicPlayer. + private Song = musicApp Song. + private TransferArray = platform kernel TransferArray. +| +)( + + public class MusicPlayerTest = AsyncTestContext ()( + + public testAsyncAddUser = ( + | pp users mplayerActor1 mplayerActor2 songlist1 songlist2 + s1 s2 s3 s4 s5 s6 pPlayer pName | + + pp:: actors createPromisePair. + + s1:: Song new. + s1 init: 'S1' artist: 'A1'. + s2:: Song new. + s2 init: 'S2' artist: 'A2'. + s3:: Song new. + s3 init: 'S3' artist: 'A3'. + s4:: Song new. + s4 init: 'S4' artist: 'A4'. + s5:: Song new. + s5 init: 'S5' artist: 'A5'. + s6:: Song new. + s6 init: 'S6' artist: 'A6'. + + songlist1:: TransferArray new: 3. + songlist1 at: 1 put: s1. + songlist1 at: 2 put: s2. + songlist1 at: 3 put: s3. + + songlist2:: TransferArray new: 5. + songlist2 at: 1 put: s4. + songlist2 at: 2 put: s5. + songlist2 at: 3 put: s2. + songlist2 at: 4 put: s3. + songlist2 at: 5 put: s6. + + mplayerActor1:: (actors createActorFromValue: MusicPlayer) <-: new: 'Joe' songlist: songlist1. + mplayerActor2:: (actors createActorFromValue: MusicPlayer) <-: new: 'Marie' songlist: songlist2. + + pPlayer:: mplayerActor1 <-: addPlayer: mplayerActor2. + + pName:: pPlayer <-: getName. + + pName whenResolved: [:r | + pp resolver resolve: r + ]. + + ^ assert: pp promise resolvedWith: 'Marie' + ) + + public testAsyncExchangeSongs = ( + | pp users mplayerActor1 mplayerActor2 songlist1 songlist2 + s1 s2 s3 s4 s5 s6 resultPromise1 resultPromise2 | + + pp:: actors createPromisePair. + + s1:: Song new. + s1 init: 'S1' artist: 'A1'. + s2:: Song new. + s2 init: 'S2' artist: 'A2'. + s3:: Song new. + s3 init: 'S3' artist: 'A3'. + s4:: Song new. + s4 init: 'S4' artist: 'A4'. + s5:: Song new. + s5 init: 'S5' artist: 'A5'. + s6:: Song new. + s6 init: 'S6' artist: 'A6'. + + songlist1:: TransferArray new: 3. + songlist1 at: 1 put: s1. + songlist1 at: 2 put: s2. + songlist1 at: 3 put: s3. + + songlist2:: TransferArray new: 5. + songlist2 at: 1 put: s4. + songlist2 at: 2 put: s5. + songlist2 at: 3 put: s2. + songlist2 at: 4 put: s3. + songlist2 at: 5 put: s6. + + mplayerActor1:: (actors createActorFromValue: MusicPlayer) <-: new: 'Joe' songlist: songlist1. + mplayerActor2:: (actors createActorFromValue: MusicPlayer) <-: new: 'Marie' songlist: songlist2. + + resultPromise1:: mplayerActor1 <-: startExchange: mplayerActor2. + resultPromise2:: mplayerActor2 <-: startExchange: mplayerActor1. + + ^ (assert: resultPromise1 resolvedWith: 'Marie has different musical taste than Joe -> 40%'), + (assert: resultPromise2 resolvedWith: 'Joe has similar musical taste to Marie -> 66%') + ) + + + ) : ( TEST_CONTEXT = () ) + + ) + diff --git a/core-lib/TestSuite/applicationsTests/PaperScissorStoneTest.ns b/core-lib/TestSuite/applicationsTests/PaperScissorStoneTest.ns new file mode 100644 index 000000000..34a513555 --- /dev/null +++ b/core-lib/TestSuite/applicationsTests/PaperScissorStoneTest.ns @@ -0,0 +1,136 @@ +class PaperScissorStoneTest usingPlatform: platform testFramework: minitest = Value ( +| private actors = platform actors. + private TestContext = minitest TestContext. + private AsyncTestContext = minitest AsyncTestContext. + private paperScissorStoneApp = (platform system + loadModule: '../../demos/applications/PaperScissorStoneApplication.ns' nextTo: self) + usingPlatform: platform. + private Peer = paperScissorStoneApp Peer. + private TransferArray = platform kernel TransferArray. +|)( + public class PaperScissorStoneTests = AsyncTestContext ()( + + public testAsyncPlay = ( + | completionPP players peerActors firstCoordinator gameFinish numberPlayers | + + completionPP:: actors createPromisePair. + + numberPlayers:: 2. + + players:: TransferArray new: numberPlayers. + players at: 1 put: 'Joe'. + players at: 2 put: 'Marie'. + + peerActors:: TransferArray new: numberPlayers. + + players doIndexes:[: i | + | peer | + peer:: (actors createActorFromValue: Peer) <-: new: i name: (players at: i) resolver: completionPP resolver iterations: 1. + peerActors at: i put: peer. + ]. + + firstCoordinator:: peerActors at: peerActors size. + firstCoordinator <-: setCoordinatorPeer. + + gameFinish:: firstCoordinator <-: play: (peerActors at: 1) andPlayer: (peerActors at: 2). + + ^ assert: gameFinish resolvedWith: 'ok'. + ) + + public testAsyncGame = ( + | completionPP players peerActors firstCoordinator playPromise gamePromise answerPromise numberPlayers | + + completionPP:: actors createPromisePair. + + numberPlayers:: 2. + + players:: TransferArray new: numberPlayers. + players at: 1 put: 'Joe'. + players at: 2 put: 'Marie'. + + peerActors:: TransferArray new: numberPlayers. + + players doIndexes:[: i | + | peer | + peer:: (actors createActorFromValue: Peer) <-: new: i name: (players at: i) resolver: completionPP resolver iterations: 1. + peerActors at: i put: peer. + ]. + + firstCoordinator:: peerActors at: peerActors size. + firstCoordinator <-: setCoordinatorPeer. + + playPromise:: firstCoordinator <-: play: (peerActors at: 1) andPlayer: (peerActors at: 2). + + ^ playPromise whenResolved:[: finished | + + finished = #ok + ifTrue:[ + gamePromise:: firstCoordinator <-: getLastGame. + + gamePromise whenResolved:[: game | + answerPromise:: firstCoordinator <-: isFirstAnswerWinner: (game getFirstAnswer) andAnswer: (game getSecondAnswer). + answerPromise whenResolved:[: answer| + answer = true + ifTrue:[ + (game getWinner <-: getName) whenResolved:[: name | + (game getFirstPlayer <-: getName) whenResolved: [: player | + assert: name equals: player. + ]. + ]. + ] + ifFalse:[ + assert: (game getWinner) equals: nil. + ]. + ]. + ]. + ]. + ]. + ) + + + public testAsyncJoinRequest = ( + | completionPP players peerActors firstCoordinator gameFinish numberPlayers p1 p2 assertPromise allGamesPromise gamePromise1 gamePromise2 | + + completionPP:: actors createPromisePair. + + numberPlayers:: 2. + + players:: TransferArray new: numberPlayers. + players at: 1 put: 'Joe'. + players at: 2 put: 'Marie'. + + peerActors:: TransferArray new: numberPlayers. + + players doIndexes:[: i | + | peer | + peer:: (actors createActorFromValue: Peer) <-: new: i name: (players at: i) resolver: completionPP resolver iterations: 2. + peerActors at: i put: peer. + ]. + + firstCoordinator:: peerActors at: peerActors size. + firstCoordinator <-: setCoordinatorPeer. + + firstCoordinator <-: startGame: peerActors gameNumber: 1. + + firstCoordinator <-: joinRequest: ((actors createActorFromValue: Peer) <-: new: (players size + 1) name: 'Mike' resolver: completionPP resolver iterations: 2). + + ^ completionPP promise whenResolved:[: r | + allGamesPromise:: firstCoordinator <-: getAllGames. + + allGamesPromise whenResolved:[: all | + gamePromise1:: (all <-: at: 1). + gamePromise2:: (all <-: at: 2). + + gamePromise1 whenResolved:[: gp1 | + assert: gp1 getTotal equals: 2. + ]. + + gamePromise2 whenResolved:[: gp2 | + assert: gp2 getTotal equals: 3. + ]. + ]. + ]. + ) + + ) : ( TEST_CONTEXT = () ) +) \ No newline at end of file diff --git a/core-lib/TestSuite/applicationsTests/ShoppingAppTest.ns b/core-lib/TestSuite/applicationsTests/ShoppingAppTest.ns new file mode 100644 index 000000000..133f3c8f8 --- /dev/null +++ b/core-lib/TestSuite/applicationsTests/ShoppingAppTest.ns @@ -0,0 +1,80 @@ +class ShoppingAppTest usingPlatform: platform testFramework: minitest = Value ( +| private TestContext = minitest TestContext. + private AsyncTestContext = minitest AsyncTestContext. + private actors = platform actors. + private Exception = platform kernel Exception. + private shoppingApp = (platform system loadModule: '../../demos/applications/ShoppingApplication.ns' nextTo: self) usingPlatform: platform. + private Product = shoppingApp Product. + private Listener = shoppingApp Listener. + private Teller = shoppingApp Teller. + private Account = shoppingApp Account. + private Shipper = shoppingApp Shipper. + private Buyer = shoppingApp Buyer. + private Vector = platform kernel Vector. +|)( + + public class ShoppingTests = AsyncTestContext ()( + + public testAsyncAnd = ( + | p1 p2 p3 listener teller product account shipper shoppingCart | + + product:: (actors createActorFromValue: Product) <-: new. + account:: (actors createActorFromValue: Account) <-: new. + shipper:: (actors createActorFromValue: Shipper) <-: new. + + listener:: Listener new: [:p1 | 'execute block in listener' println.]. + + shoppingCart:: Vector new. + shoppingCart append: 'phone'. + shoppingCart append: 'laptop'. + shoppingCart append: 'screen'. + + teller:: Teller new: (shoppingCart size + 2) listener: listener. + + shoppingCart doIndexes:[:i | + | partNo | + partNo:: shoppingCart at: i. + p1:: product <-: partInStock: partNo teller: teller. + p1 whenResolved:[: r| + assert: r equals: false. + ]. + ]. + + p2:: account <-: checkCredit: 'customer' teller: teller. + p3:: shipper <-: canDeliver: 'profile' teller: teller. + + ^ (assert: p2 resolvedWith: false), + (assert: p3 resolvedWith: true) + ) + + public testAsyncFullProgram = ( + | p product account shipper buyer shoppingCart asyncPromise finalPromise | + + product:: (actors createActorFromValue: Product) <-: new. + account:: (actors createActorFromValue: Account) <-: new. + shipper:: (actors createActorFromValue: Shipper) <-: new. + buyer:: (actors createActorFromValue: Buyer) <-: new. + + shoppingCart:: Vector new. + shoppingCart append: 'phone'. + shoppingCart append: 'laptop'. + shoppingCart append: 'screen'. + + asyncPromise:: actors async: shoppingCart do:[: i | + (buyer <-: addItem: i) whenResolved: [: r | + r = #ok + ifTrue:[ + ('-items added in shopping cart: ' + i) println. + ]. + ]. + ]. + + finalPromise:: asyncPromise whenResolved:[: r | + buyer <-: checkoutShoppingCart: product account: account shipper: shipper. + ]. + + ^ assert: finalPromise resolvedWith: 'The order has been placed successfully'. + ) + + ) : ( TEST_CONTEXT = () ) +) diff --git a/core-lib/demos/applications/InstantMessengerApplication.ns b/core-lib/demos/applications/InstantMessengerApplication.ns new file mode 100644 index 000000000..6a0cf19e6 --- /dev/null +++ b/core-lib/demos/applications/InstantMessengerApplication.ns @@ -0,0 +1,121 @@ +class InstantMessengerApplication usingPlatform: platform = Value ( +| private actors = platform actors. + private Array = platform kernel Array. + private Dictionary = platform collections Dictionary. +|)( + class TextMessage new: content sender: senderName = Value ( + | public content = content. + public sender = senderName. + |)() + + public class InstantMessenger new: name total: size = ( + | private buddyMap = Dictionary new: size. + public name = name. + private textMessage ::= nil. + |)( + + public startChat: remoteMessenger = ( + | pDiscover pName pSend msg pp array | + pp:: actors createPromisePair. + + (* returns a far reference of the remote messenger *) + pDiscover:: self addMessenger: remoteMessenger. + + pName:: pDiscover <-: name. + pName whenResolved: [:remoteName | + msg:: 'Hello ' + remoteName. + pSend:: sendMessage: remoteName contentMsg: msg. + + pSend whenResolved: [:result | + result = #ok + ifTrue: [ + pp resolver resolve: (TextMessage new: msg sender: name) ] + ifFalse:[ + pp resolver resolve: nil ] ] ]. + + ^ pp promise + ) + + public sendMessage: receiverName contentMsg: content = ( + | pp receiverActor pReceive | + textMessage:: TextMessage new: content sender: name. + + receiverActor:: buddyMap at: receiverName. + pReceive:: receiverActor <-: receive: textMessage. + + ^ pReceive + ) + + public displayMessage: msg = ( + (name + ' screen> ' + msg) println + ) + + public addMessenger: messenger = ( + | p pName buddy | + p:: actors createPromisePair. + + pName:: messenger <-: name. + pName whenResolved: [:n | + (buddyMap containsKey: n) + ifTrue: [ + buddyMap at: n put: messenger. (* update el far reference *) + (name + ' updated the far reference to buddy: ' + n) println. ] + ifFalse: [ + buddyMap at: n put: messenger. + (name + ' discovered a new messenger buddy: ' + n) println ]. + + p resolver resolve: (buddyMap at: n). + ] onError: [:e | + ('-Error adding the messenger: ' + e) println. + p resolver resolve: nil. + ]. + + ^ p promise + ) + + public receive: textMessage = ( + | sender content p | + content:: textMessage content. + sender:: textMessage sender. + + (* print message to the screen *) + self displayMessage: sender + ': ' + content. + + (* acknowledgement notification of message received *) + ^ #ok + ) + ) + + public main: args = ( + | completionPP1 completionPP2 users messenger1 messenger2 pResult1 pResult2 | + completionPP1:: actors createPromisePair. + completionPP2:: actors createPromisePair. + + '[INSTANT MESSENGER APPLICATION] Starting' println. + + users:: Array new: 2. + users at: 1 put: 'Joe'. + users at: 2 put: 'Marie'. + + messenger1:: (actors createActorFromValue: InstantMessenger) <-: new: (users at: 1) total: users size. + messenger2:: (actors createActorFromValue: InstantMessenger) <-: new: (users at: 2) total: users size. + + pResult1:: messenger1 <-: startChat: messenger2. + pResult1 whenResolved: [:result | + result ifNotNil: [ + messenger1 <-: displayMessage: result sender + ': ' + result content. + completionPP1 resolver resolve: 0. (* end application *) + ] ]. + + pResult2:: messenger2 <-: startChat: messenger1. + pResult2 whenResolved: [:result | + result ifNotNil:[ + messenger2 <-: displayMessage: result sender + ': ' + result content. + completionPP2 resolver resolve: 0. (* end application *) + ] ]. + + ^ completionPP1 promise whenResolved: [:result1 | + completionPP2 promise whenResolved: [:result2 | + '\n\n[INSTANT MESSENGER APPLICATION] Ending' println ] ]. + ) +) diff --git a/core-lib/demos/applications/InternetCafeApplication.ns b/core-lib/demos/applications/InternetCafeApplication.ns new file mode 100644 index 000000000..fea8d22e4 --- /dev/null +++ b/core-lib/demos/applications/InternetCafeApplication.ns @@ -0,0 +1,237 @@ +class InternetCafeApplication usingPlatform: platform = Value ( +| private actors = platform actors. + private Array = platform kernel Array. + private Vector = platform kernel Vector. + private TransferArray = platform kernel TransferArray. +|)( + + public class Customer new: newName room: room = ( + | private name = newName. + private computerRoom = room. + private left ::= false. + |)( + + public askComputer = ( + | p | + p:: computerRoom <-: getComputer: name. + ^ p + ) + + public leaveRoom: timeout resolver: resolver = ( + left:: true. + + (timeout = true) + ifTrue: [ + ('-> Customer '+ name + ' left the room due to TIMEOUT') println. + ] + ifFalse: [ + ('-> Customer '+ name + ' worked and left the room') println. + ]. + + ^ computerRoom <-: notifyCustomerDone: resolver. + ) + + public releaseComputer: id = ( + ^ computerRoom <-: freeComputer: id. + ) +) + + public class InternetCafe new: capacity totalCustomers: totalCustomers = ( + | private computers = Array new: capacity. + private totalCustomers = totalCustomers. + private counter ::= 0. + private pendingCustomers = Vector new: totalCustomers. + | + )( + + public createCustomer: name room: cafeActor = ( + | c | + c:: (actors createActorFromValue: Customer) <-: new: name room: cafeActor. + + ^ c + ) + + public getComputer: customer = ( + | computerId ::= getAvailability. + waitingPromisePair ::= nil. + transferArray = TransferArray new: 2. + | + + ((computerId notNil) and: (computerId > -1)) + ifTrue: [ + computers at: computerId put: customer. + transferArray at: 1 put: customer. + transferArray at: 2 put: computerId. + ]. + + (computerId = -1) + ifTrue: [ + waitingPromisePair:: actors createPromisePair. + addPendingCustomerPromise: waitingPromisePair. + transferArray at: 1 put: customer. + transferArray at: 2 put: waitingPromisePair. + ]. + + ^ transferArray + ) + + private getAvailability = ( + | value | + computers doIndexes: [:i | + value:: computers at: i. + (value = nil) + ifTrue: [ ^ i ] + ]. + + ^ -1 + ) + + public freeComputer: id = ( + | cust | + cust:: computers at: id. + (' -- Computer '+ id + ' has been released by customer ' + cust) println. + + computers at: id put: nil. + ) + + public notifyCustomerDone: resolver = ( + counter:: counter + 1. + counter println. + counter = totalCustomers + ifTrue: [ + resolver resolve: 0. + ^ true + ]. + + ^ false + ) + + public addPendingCustomerPromise: pair = ( + | c | + pendingCustomers append: pair. + ) + + public removePendingCustomerPromise: pair = ( + ^ pendingCustomers remove: pair. + ) + + public resolvePendingPromise: computerId = ( + | p | + + p:: pendingCustomers first. + p notNil + ifTrue: [ + (* ('--resolved pending promise with id ' + computerId) println. *) + p resolver resolve: computerId. + + removePendingCustomerPromise: p. + ^ true + ] + ifFalse: [ + ^ nil + ]. + ) +) + + public main: args = ( + | completionPP cafeActor numberComputers numberCustomers customersNames | + + '[INTERNET_CAFE] Starting' println. + + completionPP:: actors createPromisePair. + + numberComputers:: 3. + numberCustomers:: 5. + + cafeActor:: (actors createActorFromValue: InternetCafe) <-: new: numberComputers totalCustomers: numberCustomers. + + customersNames:: Array new: numberCustomers. + customersNames at: 1 put: 'Joe'. + customersNames at: 2 put: 'Marie'. + customersNames at: 3 put: 'Tom'. + customersNames at: 4 put: 'Alan'. + customersNames at: 5 put: 'Julia'. + + customersNames doIndexes: [:i | + | p | + p:: cafeActor <-: createCustomer: (customersNames at: i) room: cafeActor. + p whenResolved: [:customerActor | + start: customerActor room: cafeActor resolver: completionPP resolver. + ]. + ]. + + ^ completionPP promise whenResolved: [:r7 | + '\n\n[INTERNET_CAFE] Ended' println. + r7 ]. + ) + + public start: customerActor room: cafeActor resolver: resolver = ( + | pResult computerId customerName str flagResolved | + + pResult:: customerActor <-: askComputer. + + pResult whenResolved: [:array | + + customerName:: array at: 1. + computerId:: array at: 2. + str:: computerId asString. + + (str = 'instance of FarReference') + ifTrue: [ + ('There is no computer available for '+ customerName + ' - waiting ...') println. + + (* waiting timeout *) + actors after: 100 do: [ + flagResolved = true (* indicates if the computerId promise has already been resolved, it avoids resolving the promise more than once *) + ifFalse: [ + (computerId <-: resolver) whenResolved: [:r | + r resolve: 0. + ('Timeout for customer '+ customerName) println. + + (* remove the computerId pair because it has been resolved *) + cafeActor <-: removePendingCustomerPromise: computerId. + ]. + ] + ]. + + (computerId <-: promise) whenResolved: [:id | + flagResolved:: true. + + (id = 0) + ifTrue: [ + customerActor <-: leaveRoom: true resolver: resolver. + ] + ifFalse: [ + (* ('w- Customer '+ customerName + ' waited and will be assigned to computer ' + id) println. *) + + (* call start method again for the current actor, because the computerId promise has been resolved with an id, not with a timeout. + Then the customer will get a computer to work. *) + + start: customerActor room: cafeActor resolver: resolver. + ] + ]. + ] + + ifFalse: [ + ('Customer '+ customerName + ' has been assigned to computer ' + computerId) println. + + addWorkingTimeout: customerActor cafeActor: cafeActor id: computerId resolver: resolver. + ] + + ]. + ) + + public addWorkingTimeout: customerActor cafeActor: cafeActor id: computerId resolver: resolver = ( + | pReleased | + (* working timeout *) + actors after: 500 do: [ + pReleased:: customerActor <-: releaseComputer: computerId. + pReleased whenResolved: [:r7 | + cafeActor <-: resolvePendingPromise: computerId. + ]. + + customerActor <-: leaveRoom: false resolver: resolver. + ]. + ) + +) \ No newline at end of file diff --git a/core-lib/demos/applications/MusicPlayerApplication.ns b/core-lib/demos/applications/MusicPlayerApplication.ns new file mode 100644 index 000000000..f672ca2bd --- /dev/null +++ b/core-lib/demos/applications/MusicPlayerApplication.ns @@ -0,0 +1,272 @@ +class MusicPlayerApplication usingPlatform: platform = Value ( +| private actors = platform actors. + private TransferArray = platform kernel TransferArray. + private Array = platform kernel Array. + private TransferObject = platform kernel TransferObject. +|)( + +public class MusicPlayer new: name songlist: list = ( + | private mySongList = list. + private username = name. + private session = Session new: name songlist: list. + |)( + + public startExchange: remotePlayer = ( + | pDiscover pSession pp | + + pp:: actors createPromisePair. + + pDiscover:: self addPlayer: remotePlayer. (* returns a far reference of the remote messenger *) + + pSession:: pDiscover <-: openSession. + pSession whenResolved:[: session | + | i | + i:: 1. + + (* async loop for sending the songs to the remotePlayer *) + (actors async: getLibraryList do: [:song | + | p songPromise promisefinalMsg | + + p:: actors createPromisePair. + + songPromise:: session <-: receiveSong: song index: i. + songPromise whenResolved:[: result | + result = 'ok' + ifTrue:[ + (getLibraryList size) = i + ifTrue:[ + promisefinalMsg:: session <-: endExchange: getName. + promisefinalMsg whenResolved:[:endMsg | + pp resolve: endMsg. + ]. + ] + ifFalse:[ + i:: i + 1. + p resolve: i. + ]. + ] + ifFalse: [ + ('Problem when uploading song at index '+ i) println. + p resolve: i. + ]. + ]. + + p promise + ]). + ]. + + ^ pp promise + ) + + public getLibraryList = ( + ^ mySongList + ) + + public getName = ( + ^ username + ) + + public addPlayer: remoteUser = ( + ^ session addPlayer: remoteUser. + ) + + public openSession = ( + ^ session + ) +) + +public class Session new: name songlist: list = ( + | private mySongList = list. + private username = name. + private remoteSongList ::= nil. + |)( + (* discover the new player and initialize the list of songs that the player will send *) + public addPlayer: otherPlayer = ( + | plist pp pRemoteName | + + pp:: actors createPromisePair. + + plist:: otherPlayer <-: getLibraryList. + + pRemoteName:: otherPlayer <-: getName. + + plist whenResolved: [: secondSongList| + remoteSongList:: TransferArray new: secondSongList size. + + pRemoteName whenResolved:[: remotePlayerName | + (username +' has discovered player '+ remotePlayerName ) println. + pp resolver resolve: otherPlayer. + ]. + ] + onError:[:e| + ('-Error getting the list of the remote player: ' + e) println. + pp resolver resolve: nil. + ]. + + + ^ pp promise + ) + + public receiveSong: song index: i = ( + remoteSongList at: i put: song. + + ^ 'ok' + ) + + public endExchange: senderName = ( + | percentage threshold | + + threshold:: 40. + + percentage:: getPercentageCommonSongs. + (percentage > threshold) + ifTrue:[ + ^ username +' has similar musical taste to '+ senderName + ' -> ' + percentage +'%'. + ] + ifFalse:[ + ^ username + ' has different musical taste than '+ senderName +' -> '+ percentage +'%'. + ]. + ) + + public getPercentageCommonSongs = ( + | percentage commonSongs | + + percentage:: 0. + + remoteSongList size > 0 + ifTrue:[ + commonSongs:: getCommonSongs: mySongList remoteList: remoteSongList. + ('- Common songs: ' + commonSongs) println. + + commonSongs > 0 + ifTrue:[ + percentage:: (commonSongs * 100) / (mySongList size). + ] + ]. + + ^ percentage + ) + + private getCommonSongs: list remoteList: remoteList = ( + | song flagContains commonSongs | + + commonSongs:: 0. + + list doIndexes: [:i | + song:: list at: i. + + flagContains:: containsSong: song remoteList: remoteList. + flagContains + ifTrue:[ + commonSongs:: commonSongs + 1. + ]. + + ]. + + ^ commonSongs + ) + + public containsSong: songToCompare remoteList: remoteList = ( + | song flag | + + flag:: false. + + remoteList doIndexes: [:i | + song:: remoteList at: i. + + flag:: song equal: songToCompare. + flag + ifTrue:[ + ^ true + ]. + ]. + + ^ false + ) +) + +public class Song = TransferObject ( + | private array = TransferArray new: 2. + |)( + + public init: title artist: artist = ( + array at: 1 put: title. + array at: 2 put: artist. + ) + + public getTitle = ( + ^ array at: 1. + ) + + public getArtist = ( + ^ array at: 2. + ) + + public equal: song = ( + | title artist | + + title:: song getTitle. + artist:: song getArtist. + + ((artist = getArtist) and: (title = getTitle)) + ifTrue:[ + ^ true + ]. + + ^ false + ) +) + + public main: args = ( + | resultPromise1 resultPromise2 users mplayerActor1 mplayerActor2 songlist1 songlist2 + s1 s2 s3 s4 s5 s6 + | + + '[MUSIC PLAYER APPLICATION] Starting' println. + + users:: Array new: 2. + users at: 1 put: 'Joe'. + users at: 2 put: 'Marie'. + + s1:: Song new. + s1 init: 'S1' artist: 'A1'. + s2:: Song new. + s2 init: 'S2' artist: 'A2'. + s3:: Song new. + s3 init: 'S3' artist: 'A3'. + s4:: Song new. + s4 init: 'S4' artist: 'A4'. + s5:: Song new. + s5 init: 'S5' artist: 'A5'. + s6:: Song new. + s6 init: 'S6' artist: 'A6'. + + songlist1:: TransferArray new: 3. + songlist1 at: 1 put: s1. + songlist1 at: 2 put: s2. + songlist1 at: 3 put: s3. + + songlist2:: TransferArray new: 5. + songlist2 at: 1 put: s4. + songlist2 at: 2 put: s5. + songlist2 at: 3 put: s2. + songlist2 at: 4 put: s3. + songlist2 at: 5 put: s6. + + mplayerActor1:: (actors createActorFromValue: MusicPlayer) <-: new: (users at: 1) songlist: songlist1. + mplayerActor2:: (actors createActorFromValue: MusicPlayer) <-: new: (users at: 2) songlist: songlist2. + + resultPromise1:: mplayerActor1 <-: startExchange: mplayerActor2. + resultPromise2:: mplayerActor2 <-: startExchange: mplayerActor1. + + ^ resultPromise1 whenResolved: [: result1| + result1 println. + + resultPromise2 whenResolved: [: result2| + result2 println. + '\n\n''[MUSIC PLAYER APPLICATION] Ending' println. + ]. + ]. + ) + +) \ No newline at end of file diff --git a/core-lib/demos/applications/PaperScissorStoneApplication.ns b/core-lib/demos/applications/PaperScissorStoneApplication.ns new file mode 100644 index 000000000..5bb18c8a2 --- /dev/null +++ b/core-lib/demos/applications/PaperScissorStoneApplication.ns @@ -0,0 +1,418 @@ +class PaperScissorStoneApplication usingPlatform: platform = Value ( +| private actors = platform actors. + private TransferArray = platform kernel TransferArray. + private Array = platform kernel Array. + private harness = (platform system loadModule: '../../Benchmarks/Harness.ns' nextTo: self) usingPlatform: platform. + private Random = harness Random. + private Vector = platform kernel Vector. + private TransferObject = platform kernel TransferObject. +|)( + +public class Peer new: id name: name resolver: resolver iterations: size = ( + | private resolver = resolver. + private games ::= Vector new: size. + private counter ::= 0. + private playerActors ::= nil. + private score ::= 0. + private flagCoordinator ::= false. + private name = name. + private id = id. + private myLastGame ::= nil. + private requests ::= nil. + |)( + + (* invoked only by the coordinator which selects randomly two peers to play a game *) + public startGame: peerActors gameNumber: gameNumber = ( + | player1 player2 gameFinish playerId1 playerId2 randomPair randomValue1 randomValue2 | + + playerActors:: peerActors. + ('Total players: '+ playerActors size ) println. + + (* select players and play *) + randomPair:: getRandomPair: playerActors size gameNumber: gameNumber. + + randomValue1:: randomPair at: 1. + randomValue2:: randomPair at: 2. + + player1:: playerActors at: randomValue1. + player2:: playerActors at: randomValue2. + + gameFinish:: play: player1 andPlayer: player2. + gameFinish whenResolved:[: finished | + + finished = #ok + ifTrue:[ + + ('* Game: '+ counter) println. + player1 <-: displayGameResults. + player2 <-: displayGameResults. + + counter:: counter + 1. + + counter = games capacity + ifTrue:[ + (* endApplication.*) + printAllGameResults: 1 players: playerActors winner: nil winnerScore: 0 msg: '----Final Games Result----- \n'. + ] + ifFalse:[ + (* check for new join requests *) + (requests notNil) + ifTrue: [ + playerActors:: TransferArray new: (peerActors size + requests size). + + peerActors doIndexes:[: i | + playerActors at: i put: (peerActors at: i). + ]. + + requests doIndexes:[: i | + playerActors at: (peerActors size + i) put: (requests at: i). + ]. + + ('Total players: '+ playerActors size + ' - Added '+ requests size +' peers to the game.') println. + + requests:: nil. (* reset the array *) + ]. + + startGame: playerActors gameNumber: counter. + ]. + ]. + ]. + ) + + public getId = ( + ^ id + ) + + public getScore = ( + ^ score + ) + + public getName = ( + ^ name + ) + + public getNumberPlayers = ( + | size | + + (playerActors isNil) + ifTrue:[ + size:: 0. + ] + ifFalse:[ + size:: (playerActors size). + ]. + + ^ size + ) + + public getAllGames = ( + ^ games + ) + + (* if the case did not exist then none score is updated, no winners *) + public updateScore: existedCase winner: winnerFlag = ( + existedCase + ifTrue:[ + winnerFlag + ifTrue:[ + score:: score + 1. + ] + ifFalse:[ + score > 0 + ifTrue:[ + score:: score - 1. + ] + ifFalse: [ + score:: 0. + ]. + ]. + ]. + + ^ score + ) + + public getAnswer = ( + | r a options position | + + options:: Array new: 3. + options at: 1 put: 'scissor'. + options at: 2 put: 'paper'. + options at: 3 put: 'stone'. + + position:: getRandomNumber: options size. + + ^ options at: position + ) + + private getRandomNumber: totalItems = ( + | val random | + + random:: Random new: getId + 73425. + + val:: 1 + (random next % totalItems). + + ^ val + ) + + public getRandomPair: totalItems gameNumber: gameNumber = ( + | selection random | + + selection:: TransferArray new: 2. + + 1 to: 2 do: [:i | + | random val | + + random:: Random new: i + 73425 + gameNumber. + + val:: 1 + (random next % totalItems). + selection at: i put: val. + ]. + + ^ selection + ) + + public updateLastGame: game = ( + myLastGame:: game. + ) + + public getLastGame = ( + ^ myLastGame + ) + + public play: player1 andPlayer: player2 = ( + | game a1 a2 p1 p2 winner pp firstWin total | + + pp:: actors createPromisePair. + + p1:: player1 <-: getAnswer. + p2:: player2 <-: getAnswer. + + total:: getNumberPlayers. + + p1 whenResolved:[: answer1 | + a1:: answer1. + + p2 whenResolved:[: answer2 | + a2:: answer2. + + firstWin:: isFirstAnswerWinner: a1 andAnswer: a2. + game:: Game new. (* game object with the results *) + + (* update score *) + firstWin + ifTrue:[ + winner:: player1. + player1 <-: updateScore: true winner: true. + player2 <-: updateScore: true winner: false. + game createGame: player1 player2: player2 answer1: a1 answer2: a2 winner: winner total: total. + ] + ifFalse:[ + winner:: player2. + player1 <-: updateScore: false winner: false. + player2 <-: updateScore: false winner: false. + game createGame: player1 player2: player2 answer1: a1 answer2: a2 winner: nil total: total. + ]. + + games append: game. + + player1 <-: updateLastGame: game. + player2 <-: updateLastGame: game. + + pp resolver resolve: #ok. + + ]. + ]. + + ^ pp promise + ) + + (* returns true if a1 wins over a2, returns false otherwise *) + public isFirstAnswerWinner: a1 andAnswer: a2 = ( + | flag | + + flag:: (((a1 = 'scissor') and: (a2 = 'paper')) or: [(a1 = 'paper') and: (a2 = 'stone')]) or: [(a1 = 'stone') and: (a2 = 'scissor')] . + + flag + ifTrue:[ + ^ true + ] + ifFalse:[ + ^ false + ]. + ) + + public printAllGameResults: index players: playerList winner: winnerName winnerScore: winnerScore msg: msg = ( + | player name score pName pScore result | + + result:: msg. + player:: playerList at: index. + pName:: player <-: getName. + pScore:: player <-: getScore. + + pName whenResolved:[:name | + pScore whenResolved:[:score | + + result:: result concatenate: (' - Player: '+ name + ' score: '+ score + '\n'). + + playerList size = index + ifTrue:[ + result:: result concatenate: (' * Winner * '+ winnerName). + resolver resolve: result. + ] + ifFalse:[ + score > winnerScore + ifTrue:[ + printAllGameResults: index + 1 players: playerList winner: name winnerScore: score msg: result. + ] + ifFalse:[ + printAllGameResults: index + 1 players: playerList winner: winnerName winnerScore: winnerScore msg: result. + ]. + ]. + ]. + ]. + ) + + (* in a distributed language the following methods can be implemented in a separate remote object contained by the actor *) + public setCoordinatorPeer = ( + flagCoordinator:: true. + ('Peer '+ getName + ' has been set as new coordinator.') println. + ) + + public isCoordinatorPeer = ( + ^ flagCoordinator + ) + + (* print the results of a last game played *) + public displayGameResults = ( + | player1 player2 answer1 answer2 winner lastGame name1 name2 winnerName total | + + lastGame:: getLastGame. + + player1:: lastGame getFirstPlayer. + player2:: lastGame getSecondPlayer. + winner:: lastGame getWinner. + total:: lastGame getTotal. + + name1:: player1 <-: getName. + name2:: player2 <-: getName. + + name1 whenResolved:[:n1 | + name2 whenResolved:[:n2 | + + winner asString = 'instance of Promise' + ifTrue:[ + winnerName:: winner <-: getName. + winnerName whenResolved:[: wn| + answer1:: lastGame getFirstAnswer. + answer2:: lastGame getSecondAnswer. + + ('- '+getName+' screen>> '+n1 + ' says '+ answer1+ ', and '+ n2 + ' says '+ answer2 + ' : Winner -> '+ wn + ' - Total: '+ total) println. + ]. + ] + ifFalse:[ + answer1:: lastGame getFirstAnswer. + answer2:: lastGame getSecondAnswer. + + ('- '+getName+' screen>> '+n1 + ' says '+ answer1+ ', and '+ n2 + ' says '+ answer2 + ' : No winner' + ' - Total: '+ total) println. + ]. + ]. + ]. + ) + + public joinRequest: newPeerActor = ( + | index newcoll | + requests isNil + ifTrue:[ + index:: 1. + requests:: TransferArray new: index. + requests at: index put: newPeerActor. + ] + ifFalse:[ + index:: requests size + 1. + newcoll:: TransferArray new: index. + + requests doIndexes:[:i | + newcoll at: i put: (requests at: i). + ]. + newcoll at: index put: newPeerActor. + + requests:: newcoll. + ]. + ) + +) + +public class Game = TransferObject ( + | player1 player2 answer1 answer2 winner total | + )( + public createGame: p1 player2: p2 answer1: a1 answer2: a2 winner: win total: t = ( + player1:: p1. + player2:: p2. + answer1:: a1. + answer2:: a2. + winner:: win. + total:: t. + ) + + public getFirstPlayer = ( + ^ player1 + ) + + public getSecondPlayer = ( + ^ player2 + ) + + public getFirstAnswer = ( + ^ answer1 + ) + + public getSecondAnswer = ( + ^ answer2 + ) + + public getWinner = ( + ^ winner + ) + + public getTotal = ( + ^ total + ) +) + + public main: args = ( + | completionPP players peerActors firstCoordinator | + + completionPP:: actors createPromisePair. + + '[PAPER SCISSOR STONE Game] Starting' println. + + players:: TransferArray new: 5. + players at: 1 put: 'Joe'. + players at: 2 put: 'Marie'. + players at: 3 put: 'Tim'. + players at: 4 put: 'Jane'. + players at: 5 put: 'Bob'. + + peerActors:: TransferArray new: 5. + + players doIndexes:[: i | + | peer | + peer:: (actors createActorFromValue: Peer) <-: new: i name: (players at: i) resolver: completionPP resolver iterations: 10. + peerActors at: i put: peer. + ]. + + (* set last peer as first coordinator *) + firstCoordinator:: peerActors at: peerActors size. + firstCoordinator <-: setCoordinatorPeer. + + firstCoordinator <-: startGame: peerActors gameNumber: 1. + + firstCoordinator <-: joinRequest: ((actors createActorFromValue: Peer) <-: new: (players size + 1) name: 'Mike' resolver: completionPP resolver iterations: 10). + + ^ completionPP promise whenResolved: [: result| + result println. + '\n\n''[PAPER SCISSOR STONE Game] Ending' println. + ]. + ) + +) diff --git a/core-lib/demos/applications/ShoppingApplication.ns b/core-lib/demos/applications/ShoppingApplication.ns new file mode 100644 index 000000000..c3bd854df --- /dev/null +++ b/core-lib/demos/applications/ShoppingApplication.ns @@ -0,0 +1,142 @@ +class ShoppingApplication usingPlatform: platform = Value ( +| private actors = platform actors. + private Vector = platform kernel Vector. +|)( + + public class Buyer = ( + | private customerInfo = 'West Coast Buyers'. + private profileInfo = 'West Coast Buyers Profile'. + private shoppingCart = Vector new. + |)( + + (* Create the teller and send the validation messages to the services *) + public checkoutShoppingCart: product account: account shipper: shipper = ( + | teller listener completionPP pConnection | + + completionPP:: actors createPromisePair. + + (* object to notify when the replies are received. It uses as argument a block to execute. *) + listener:: Listener new: [:p1 | self placeOrder: completionPP resolver.]. + + teller:: Teller new: (shoppingCart size + 2) listener: listener. + + shoppingCart doIndexes:[:i | + | partNo | + partNo:: shoppingCart at: i. + product <-: partInStock: partNo teller: teller. + ]. + + account <-: checkCredit: customerInfo teller: teller. + shipper <-: canDeliver: profileInfo teller: teller. + + ^ completionPP promise + ) + + public placeOrder: resolver = ( + resolver resolve: 'The order has been placed successfully'. + ) + + public addItem: item = ( + shoppingCart append: item. + ^ #ok + ) + + ) + + public class Listener new: block = ( + | private block = block. | + )( + public run = ( + ('- All conditions has been met. ' ) println. + + block value: true. + ) + ) + + public class Teller new: limit listener: listener = ( + | public limit = limit. + public listener = listener. + private localCounter ::= 1. + |)( + + (* All conditions must be met before an order is placed. *) + public asyncAnd: answer = ( + + answer + ifTrue: [ + (localCounter = limit) + ifTrue: [ + listener <-: run. + ^ true + ] + ifFalse: [ + localCounter:: localCounter + 1. + ^ false + ]. + ] + ifFalse: [ + ^ false + ]. + ) + ) + + (* Inventory *) + public class Product = ()( + + public partInStock: itemNo teller: teller = ( + ('partInStock true for ' + itemNo) println. + ^ teller <-: asyncAnd: true. + ) + ) + + (* Check customer payment info *) + public class Account = ()( + + public checkCredit: customerName teller: teller = ( + ('checkCredit true') println. + ^ teller <-: asyncAnd: true. + ) + ) + + (* Check availability of shipper *) + public class Shipper = ()( + + public canDeliver: address teller: teller = ( + ('canDeliver true') println. + ^ teller <-: asyncAnd: true. + ) + ) + + public main: args = ( + | buyer product account shipper cart items asyncPromise finalPromise | + + '[SHOPPING APPLICATION] Starting' println. + items:: Vector new. + items append: 'phone'. + items append: 'laptop'. + items append: 'screen'. + + product:: (actors createActorFromValue: Product) <-: new. + account:: (actors createActorFromValue: Account) <-: new. + shipper:: (actors createActorFromValue: Shipper) <-: new. + buyer:: (actors createActorFromValue: Buyer) <-: new. + + asyncPromise:: actors async: items do:[: i | + (buyer <-: addItem: i) whenResolved: [: r | + r = #ok + ifTrue:[ + ('-items added in shopping cart: ' + i) println. + ]. + ]. + ]. + + finalPromise:: asyncPromise whenResolved:[: r | + buyer <-: checkoutShoppingCart: product account: account shipper: shipper. + ]. + + ^ finalPromise whenResolved: [: r2| + r2 println. + '\n\n[SHOPPING APPLICATION] Ending' println. + ]. + ) +)