| 
									
										
										
										
											2014-11-24 12:28:54 +01:00
										 |  |  | import { | 
					
						
							|  |  |  |   ProtoRecord, | 
					
						
							|  |  |  |   Record, | 
					
						
							| 
									
										
										
										
											2014-11-24 18:42:53 +01:00
										 |  |  |   RECORD_FLAG_COLLECTION, | 
					
						
							| 
									
										
										
										
											2014-11-24 15:32:25 +01:00
										 |  |  |   RECORD_FLAG_IMPLICIT_RECEIVER, | 
					
						
							| 
									
										
										
										
											2014-11-24 12:28:54 +01:00
										 |  |  |   RECORD_TYPE_CONST, | 
					
						
							|  |  |  |   RECORD_TYPE_INVOKE_CLOSURE, | 
					
						
							|  |  |  |   RECORD_TYPE_INVOKE_FORMATTER, | 
					
						
							|  |  |  |   RECORD_TYPE_INVOKE_METHOD, | 
					
						
							|  |  |  |   RECORD_TYPE_INVOKE_PURE_FUNCTION, | 
					
						
							|  |  |  |   RECORD_TYPE_PROPERTY | 
					
						
							|  |  |  | } from './record'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-02 13:14:07 +01:00
										 |  |  | import {FIELD, IMPLEMENTS, isBlank, isPresent, int, toBool, autoConvertAdd, BaseException, | 
					
						
							|  |  |  |   NumberWrapper} from 'facade/lang'; | 
					
						
							| 
									
										
										
										
											2014-11-21 21:19:23 -08:00
										 |  |  | import {List, Map, ListWrapper, MapWrapper} from 'facade/collection'; | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  | import {ContextWithVariableBindings} from './parser/context_with_variable_bindings'; | 
					
						
							| 
									
										
										
										
											2014-11-24 18:42:53 +01:00
										 |  |  | import { | 
					
						
							|  |  |  |   AccessMember, | 
					
						
							|  |  |  |   Assignment, | 
					
						
							|  |  |  |   AST, | 
					
						
							|  |  |  |   AstVisitor, | 
					
						
							|  |  |  |   Binary, | 
					
						
							|  |  |  |   Chain, | 
					
						
							|  |  |  |   Collection, | 
					
						
							|  |  |  |   Conditional, | 
					
						
							|  |  |  |   Formatter, | 
					
						
							|  |  |  |   FunctionCall, | 
					
						
							|  |  |  |   ImplicitReceiver, | 
					
						
							|  |  |  |   KeyedAccess, | 
					
						
							|  |  |  |   LiteralArray, | 
					
						
							|  |  |  |   LiteralMap, | 
					
						
							|  |  |  |   LiteralPrimitive, | 
					
						
							|  |  |  |   MethodCall, | 
					
						
							|  |  |  |   PrefixNot | 
					
						
							|  |  |  | } from './parser/ast'; | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export class ProtoRecordRange { | 
					
						
							| 
									
										
										
										
											2014-12-03 11:04:46 +01:00
										 |  |  |   recordCreator: ProtoRecordCreator; | 
					
						
							| 
									
										
										
										
											2014-11-14 12:34:35 -08:00
										 |  |  |   constructor() { | 
					
						
							| 
									
										
										
										
											2014-12-03 11:04:46 +01:00
										 |  |  |     this.recordCreator = null; | 
					
						
							| 
									
										
										
										
											2014-09-26 11:20:08 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-30 15:50:20 -07:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |    * Parses [ast] into [ProtoRecord]s and adds them to [ProtoRecordRange]. | 
					
						
							| 
									
										
										
										
											2014-09-30 15:50:20 -07:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2014-10-28 12:22:38 -04:00
										 |  |  |    * @param ast The expression to watch | 
					
						
							| 
									
										
										
										
											2014-12-02 17:09:46 -08:00
										 |  |  |    * @param expressionMemento an opaque object which will be passed to WatchGroupDispatcher on | 
					
						
							| 
									
										
										
										
											2014-09-30 15:50:20 -07:00
										 |  |  |    *        detecting a change. | 
					
						
							| 
									
										
										
										
											2014-11-24 18:42:53 +01:00
										 |  |  |    * @param content Wether to watch collection content (true) or reference (false, default) | 
					
						
							| 
									
										
										
										
											2014-09-30 15:50:20 -07:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |   addRecordsFromAST(ast:AST, | 
					
						
							| 
									
										
										
										
											2014-12-02 17:09:46 -08:00
										 |  |  |         expressionMemento, | 
					
						
							|  |  |  |         groupMemento, | 
					
						
							| 
									
										
										
										
											2014-11-24 18:42:53 +01:00
										 |  |  |         content:boolean = false) | 
					
						
							| 
									
										
										
										
											2014-09-26 11:20:08 -07:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2014-12-03 11:04:46 +01:00
										 |  |  |     if (this.recordCreator === null) { | 
					
						
							|  |  |  |       this.recordCreator = new ProtoRecordCreator(this); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-12-02 17:09:46 -08:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2014-11-24 18:42:53 +01:00
										 |  |  |     if (content) { | 
					
						
							|  |  |  |       ast = new Collection(ast); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-12-02 17:09:46 -08:00
										 |  |  |      | 
					
						
							|  |  |  |     this.recordCreator.createRecordsFromAST(ast, expressionMemento, groupMemento); | 
					
						
							| 
									
										
										
										
											2014-09-26 11:20:08 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-29 15:41:50 -07:00
										 |  |  |   // TODO(rado): the type annotation should be dispatcher:WatchGroupDispatcher.
 | 
					
						
							|  |  |  |   // but @Implements is not ready yet.
 | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |   instantiate(dispatcher, formatters:Map):RecordRange { | 
					
						
							|  |  |  |     var recordRange:RecordRange = new RecordRange(this, dispatcher); | 
					
						
							| 
									
										
										
										
											2014-12-03 11:04:46 +01:00
										 |  |  |     if (this.recordCreator !== null) { | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |       this._createRecords(recordRange, formatters); | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  |       this._setDestination(); | 
					
						
							| 
									
										
										
										
											2014-09-26 11:20:08 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |     return recordRange; | 
					
						
							| 
									
										
										
										
											2014-09-26 11:20:08 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-09-30 15:50:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |   _createRecords(recordRange:RecordRange, formatters:Map) { | 
					
						
							| 
									
										
										
										
											2014-12-03 11:04:46 +01:00
										 |  |  |     for (var proto = this.recordCreator.headRecord; proto != null; proto = proto.next) { | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |       var record = new Record(recordRange, proto, formatters); | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  |       proto.recordInConstruction = record; | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |       recordRange.addRecord(record); | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _setDestination() { | 
					
						
							| 
									
										
										
										
											2014-12-03 11:04:46 +01:00
										 |  |  |     for (var proto = this.recordCreator.headRecord; proto != null; proto = proto.next) { | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  |       if (proto.dest instanceof Destination) { | 
					
						
							|  |  |  |         proto.recordInConstruction.dest = proto.dest.record.recordInConstruction; | 
					
						
							| 
									
										
										
										
											2014-12-02 17:09:46 -08:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         proto.recordInConstruction.dest = proto.dest; | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  |       } | 
					
						
							|  |  |  |       proto.recordInConstruction = null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-09-26 11:20:08 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  | export class RecordRange { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:19:23 -08:00
										 |  |  |   protoRecordRange:ProtoRecordRange; | 
					
						
							|  |  |  |   dispatcher:any; //WatchGroupDispatcher
 | 
					
						
							|  |  |  |   headRecord:Record; | 
					
						
							|  |  |  |   tailRecord:Record; | 
					
						
							|  |  |  |   disabled:boolean; | 
					
						
							| 
									
										
										
										
											2014-10-29 15:41:50 -07:00
										 |  |  |   // TODO(rado): the type annotation should be dispatcher:WatchGroupDispatcher.
 | 
					
						
							|  |  |  |   // but @Implements is not ready yet.
 | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |   constructor(protoRecordRange:ProtoRecordRange, dispatcher) { | 
					
						
							|  |  |  |     this.protoRecordRange = protoRecordRange; | 
					
						
							| 
									
										
										
										
											2014-09-26 11:20:08 -07:00
										 |  |  |     this.dispatcher = dispatcher; | 
					
						
							| 
									
										
										
										
											2014-10-31 11:49:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  |     this.disabled = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this.headRecord = Record.createMarker(this); | 
					
						
							|  |  |  |     this.tailRecord = Record.createMarker(this); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |     _link(this.headRecord, this.tailRecord); | 
					
						
							| 
									
										
										
										
											2014-09-26 11:20:08 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |   /// addRecord assumes that the record is newly created, so it is enabled.
 | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  |   addRecord(record:Record) { | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  |     var lastRecord = this.tailRecord.prev; | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |     _link(lastRecord, record); | 
					
						
							|  |  |  |     if (!lastRecord.disabled) { | 
					
						
							|  |  |  |       _linkEnabled(lastRecord, record); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _link(record, this.tailRecord); | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |   addRange(child:RecordRange) { | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  |     var lastRecord = this.tailRecord.prev; | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |     var prevEnabledRecord = RecordRange._prevEnabled(this.tailRecord); | 
					
						
							|  |  |  |     var nextEnabledRerord = RecordRange._nextEnabled(this.tailRecord); | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  |     var firstEnabledChildRecord = child.findFirstEnabledRecord(); | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |     var lastEnabledChildRecord = child.findLastEnabledRecord(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _link(lastRecord, child.headRecord); | 
					
						
							|  |  |  |     _link(child.tailRecord, this.tailRecord); | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |     if (isPresent(prevEnabledRecord) && isPresent(firstEnabledChildRecord)) { | 
					
						
							|  |  |  |       _linkEnabled(prevEnabledRecord, firstEnabledChildRecord); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |     if (isPresent(nextEnabledRerord) && isPresent(lastEnabledChildRecord)) { | 
					
						
							|  |  |  |       _linkEnabled(lastEnabledChildRecord, nextEnabledRerord); | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |   remove() { | 
					
						
							|  |  |  |     var firstEnabledChildRecord = this.findFirstEnabledRecord(); | 
					
						
							|  |  |  |     var lastEnabledChildRecord = this.findLastEnabledRecord(); | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |     var next = this.tailRecord.next; | 
					
						
							|  |  |  |     var prev = this.headRecord.prev; | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |     _link(prev, next); | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |     if (isPresent(firstEnabledChildRecord)) { | 
					
						
							|  |  |  |       var nextEnabled = lastEnabledChildRecord.nextEnabled; | 
					
						
							|  |  |  |       var prevEnabled = firstEnabledChildRecord.prevEnabled; | 
					
						
							|  |  |  |       if (isPresent(nextEnabled)) nextEnabled.prevEnabled = prevEnabled; | 
					
						
							|  |  |  |       if (isPresent(prevEnabled)) prevEnabled.nextEnabled = nextEnabled; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   disableRecord(record:Record) { | 
					
						
							|  |  |  |     var prevEnabled = record.prevEnabled; | 
					
						
							|  |  |  |     var nextEnabled = record.nextEnabled; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (isPresent(prevEnabled)) prevEnabled.nextEnabled = nextEnabled; | 
					
						
							|  |  |  |     if (isPresent(nextEnabled)) nextEnabled.prevEnabled = prevEnabled; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     record.disabled = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  |   enableRecord(record:Record) { | 
					
						
							|  |  |  |     if (!record.disabled) return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |     var prevEnabled = RecordRange._prevEnabled(record); | 
					
						
							|  |  |  |     var nextEnabled = RecordRange._nextEnabled(record); | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  |     record.prevEnabled = prevEnabled; | 
					
						
							|  |  |  |     record.nextEnabled = nextEnabled; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (isPresent(prevEnabled)) prevEnabled.nextEnabled = record; | 
					
						
							|  |  |  |     if (isPresent(nextEnabled)) nextEnabled.prevEnabled = record; | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     record.disabled = false; | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |   disable() { | 
					
						
							|  |  |  |     var firstEnabledChildRecord = this.findFirstEnabledRecord(); | 
					
						
							|  |  |  |     var lastEnabledChildRecord = this.findLastEnabledRecord(); | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-03 11:59:50 -08:00
										 |  |  |     var nextEnabled = isPresent(lastEnabledChildRecord) ? | 
					
						
							|  |  |  |         lastEnabledChildRecord.nextEnabled : null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var prevEnabled = isPresent(firstEnabledChildRecord) ? | 
					
						
							|  |  |  |         firstEnabledChildRecord.prevEnabled : null; | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (isPresent(nextEnabled)) nextEnabled.prevEnabled = prevEnabled; | 
					
						
							|  |  |  |     if (isPresent(prevEnabled)) prevEnabled.nextEnabled = nextEnabled; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |     this.disabled = true; | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |   enable() { | 
					
						
							|  |  |  |     var prevEnabledRecord = RecordRange._prevEnabled(this.headRecord); | 
					
						
							|  |  |  |     var nextEnabledRecord = RecordRange._nextEnabled(this.tailRecord); | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |     var firstEnabledthisRecord = this.findFirstEnabledRecord(); | 
					
						
							|  |  |  |     var lastEnabledthisRecord = this.findLastEnabledRecord(); | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |     if (isPresent(firstEnabledthisRecord) && isPresent(prevEnabledRecord)){ | 
					
						
							|  |  |  |       _linkEnabled(prevEnabledRecord, firstEnabledthisRecord); | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |     if (isPresent(lastEnabledthisRecord) && isPresent(nextEnabledRecord)){ | 
					
						
							|  |  |  |       _linkEnabled(lastEnabledthisRecord, nextEnabledRecord); | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |     this.disabled = false; | 
					
						
							| 
									
										
										
										
											2014-11-14 15:35:41 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Returns the first enabled record in the current range. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * [H ER1 ER2 R3 T] returns ER1 | 
					
						
							|  |  |  |    * [H R1 ER2 R3 T] returns ER2 | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * If no enabled records, returns null. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * [H R1 R2 R3 T] returns null | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * The function skips disabled sub ranges. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   findFirstEnabledRecord() { | 
					
						
							|  |  |  |     var record = this.headRecord.next; | 
					
						
							|  |  |  |     while (record !== this.tailRecord && record.disabled) { | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |       if (record.isMarkerRecord && record.recordRange.disabled) { | 
					
						
							|  |  |  |         record = record.recordRange.tailRecord.next; | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         record = record.next; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2014-10-31 11:49:55 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  |     return record === this.tailRecord ? null : record; | 
					
						
							| 
									
										
										
										
											2014-09-26 11:20:08 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Returns the last enabled record in the current range. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * [H ER1 ER2 R3 T] returns ER2 | 
					
						
							|  |  |  |    * [H R1 ER2 R3 T] returns ER2 | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * If no enabled records, returns null. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * [H R1 R2 R3 T] returns null | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * The function skips disabled sub ranges. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   findLastEnabledRecord() { | 
					
						
							|  |  |  |     var record = this.tailRecord.prev; | 
					
						
							|  |  |  |     while (record !== this.headRecord && record.disabled) { | 
					
						
							|  |  |  |       if (record.isMarkerRecord && record.recordRange.disabled) { | 
					
						
							|  |  |  |         record = record.recordRange.headRecord.prev; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         record = record.prev; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return record === this.headRecord ? null : record; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Returns the next enabled record. This search is not limited to the current range. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * [H ER1 T] [H ER2 T] _nextEnable(ER1) will return ER2 | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * The function skips disabled sub ranges. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |   static _nextEnabled(record:Record) { | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |     record = record.next; | 
					
						
							|  |  |  |     while (isPresent(record) && record.disabled) { | 
					
						
							|  |  |  |       if (record.isMarkerRecord && record.recordRange.disabled) { | 
					
						
							|  |  |  |         record = record.recordRange.tailRecord.next; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         record = record.next; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return record; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Returns the prev enabled record. This search is not limited to the current range. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * [H ER1 T] [H ER2 T] _nextEnable(ER2) will return ER1 | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * The function skips disabled sub ranges. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2014-11-25 14:25:12 -08:00
										 |  |  |   static _prevEnabled(record:Record) { | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  |     record = record.prev; | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |     while (isPresent(record) && record.disabled) { | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |       if (record.isMarkerRecord && record.recordRange.disabled) { | 
					
						
							|  |  |  |         record = record.recordRange.headRecord.prev; | 
					
						
							| 
									
										
										
										
											2014-11-18 17:26:38 -08:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         record = record.prev; | 
					
						
							| 
									
										
										
										
											2014-10-31 11:49:55 +01:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  |     return record; | 
					
						
							| 
									
										
										
										
											2014-09-26 11:20:08 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-30 16:39:37 -07:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Sets the context (the object) on which the change detection expressions will | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |    * dereference themselves on. Since the RecordRange can be reused the context | 
					
						
							|  |  |  |    * can be re-set many times during the lifetime of the RecordRange. | 
					
						
							| 
									
										
										
										
											2014-09-30 16:39:37 -07:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |    * @param context the new context for change detection for the current RecordRange | 
					
						
							| 
									
										
										
										
											2014-09-30 16:39:37 -07:00
										 |  |  |    */ | 
					
						
							|  |  |  |   setContext(context) { | 
					
						
							| 
									
										
										
										
											2014-10-02 15:14:32 +02:00
										 |  |  |     for (var record:Record = this.headRecord; | 
					
						
							|  |  |  |          record != null; | 
					
						
							|  |  |  |          record = record.next) { | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-24 15:32:25 +01:00
										 |  |  |       if (record.isImplicitReceiver) { | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |         this._setContextForRecord(context, record); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _setContextForRecord(context, record:Record) { | 
					
						
							|  |  |  |     var proto = record.protoRecord; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (context instanceof ContextWithVariableBindings) { | 
					
						
							|  |  |  |       if (context.hasBinding(proto.name)) { | 
					
						
							|  |  |  |         this._setVarBindingGetter(context, record, proto); | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2014-11-24 15:32:25 +01:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |       context = context.parent; | 
					
						
							| 
									
										
										
										
											2014-10-02 15:14:32 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     this._setRegularGetter(context, record, proto); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _setVarBindingGetter(context, record:Record, proto:ProtoRecord) { | 
					
						
							|  |  |  |     record.funcOrValue = _mapGetter(proto.name); | 
					
						
							|  |  |  |     record.updateContext(context.varBindings); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _setRegularGetter(context, record:Record, proto:ProtoRecord) { | 
					
						
							|  |  |  |     record.funcOrValue = proto.funcOrValue; | 
					
						
							|  |  |  |     record.updateContext(context); | 
					
						
							| 
									
										
										
										
											2014-09-30 16:39:37 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-09-26 11:20:08 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-09-28 16:29:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  | function _link(a:Record, b:Record) { | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |   a.next = b; | 
					
						
							|  |  |  |   b.prev = a; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 16:26:59 -08:00
										 |  |  | function _linkEnabled(a:Record, b:Record) { | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |   a.nextEnabled = b; | 
					
						
							|  |  |  |   b.prevEnabled = a; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-28 16:29:11 -07:00
										 |  |  | export class WatchGroupDispatcher { | 
					
						
							| 
									
										
										
										
											2014-10-02 15:14:32 +02:00
										 |  |  |   // The record holds the previous value at the time of the call
 | 
					
						
							| 
									
										
										
										
											2014-09-28 16:29:11 -07:00
										 |  |  |   onRecordChange(record:Record, context) {} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-10-28 12:22:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  | //todo: vsavkin: Create Array and Context destinations?
 | 
					
						
							|  |  |  | class Destination { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:19:23 -08:00
										 |  |  |   record:ProtoRecord; | 
					
						
							|  |  |  |   position:int; | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  |   constructor(record:ProtoRecord, position:int) { | 
					
						
							|  |  |  |     this.record = record; | 
					
						
							|  |  |  |     this.position = position; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-28 12:22:38 -04:00
										 |  |  | @IMPLEMENTS(AstVisitor) | 
					
						
							|  |  |  | class ProtoRecordCreator { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:19:23 -08:00
										 |  |  |   protoRecordRange:ProtoRecordRange; | 
					
						
							|  |  |  |   headRecord:ProtoRecord; | 
					
						
							|  |  |  |   tailRecord:ProtoRecord; | 
					
						
							| 
									
										
										
										
											2014-12-02 17:09:46 -08:00
										 |  |  |   groupMemento:any; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-19 15:52:01 -08:00
										 |  |  |   constructor(protoRecordRange) { | 
					
						
							|  |  |  |     this.protoRecordRange = protoRecordRange; | 
					
						
							| 
									
										
										
										
											2014-10-28 12:22:38 -04:00
										 |  |  |     this.headRecord = null; | 
					
						
							|  |  |  |     this.tailRecord = null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  |   visitImplicitReceiver(ast:ImplicitReceiver, args) { | 
					
						
							| 
									
										
										
										
											2014-11-24 15:32:25 +01:00
										 |  |  |     throw new BaseException('Should never visit an implicit receiver'); | 
					
						
							| 
									
										
										
										
											2014-10-28 12:22:38 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  |   visitLiteralPrimitive(ast:LiteralPrimitive, dest) { | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |     this.add(this.construct(RECORD_TYPE_CONST, ast.value, 0, null, dest)); | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   visitBinary(ast:Binary, dest) { | 
					
						
							| 
									
										
										
										
											2014-11-24 12:28:54 +01:00
										 |  |  |     var record = this.construct(RECORD_TYPE_INVOKE_PURE_FUNCTION, | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |                                 _operationToFunction(ast.operation), 2, null, dest); | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  |     ast.left.visit(this, new Destination(record, 0)); | 
					
						
							|  |  |  |     ast.right.visit(this, new Destination(record, 1)); | 
					
						
							| 
									
										
										
										
											2014-11-11 17:02:59 -08:00
										 |  |  |     this.add(record); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-11 17:02:59 -08:00
										 |  |  |   visitPrefixNot(ast:PrefixNot, dest) { | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |     var record = this.construct(RECORD_TYPE_INVOKE_PURE_FUNCTION, _operation_negate, 1, null, dest); | 
					
						
							| 
									
										
										
										
											2014-11-11 17:02:59 -08:00
										 |  |  |     ast.expression.visit(this, new Destination(record, 0)); | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  |     this.add(record); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   visitAccessMember(ast:AccessMember, dest) { | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |     var record = this.construct(RECORD_TYPE_PROPERTY, ast.getter, 0, ast.name, dest); | 
					
						
							| 
									
										
										
										
											2014-11-24 15:32:25 +01:00
										 |  |  |     if (ast.receiver instanceof ImplicitReceiver) { | 
					
						
							|  |  |  |       record.setIsImplicitReceiver(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       ast.receiver.visit(this, new Destination(record, null)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  |     this.add(record); | 
					
						
							| 
									
										
										
										
											2014-10-28 12:22:38 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-11 16:30:54 -08:00
										 |  |  |   visitFormatter(ast:Formatter, dest) { | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |     var record = this.construct(RECORD_TYPE_INVOKE_FORMATTER, ast.name, ast.allArgs.length, null, dest); | 
					
						
							| 
									
										
										
										
											2014-11-11 16:30:54 -08:00
										 |  |  |     for (var i = 0; i < ast.allArgs.length; ++i) { | 
					
						
							|  |  |  |       ast.allArgs[i].visit(this, new Destination(record, i)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.add(record); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-11 16:54:15 -08:00
										 |  |  |   visitMethodCall(ast:MethodCall, dest) { | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |     var record = this.construct(RECORD_TYPE_INVOKE_METHOD, ast.fn, ast.args.length, null, dest); | 
					
						
							| 
									
										
										
										
											2014-11-11 16:54:15 -08:00
										 |  |  |     for (var i = 0; i < ast.args.length; ++i) { | 
					
						
							|  |  |  |       ast.args[i].visit(this, new Destination(record, i)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-11-24 15:32:25 +01:00
										 |  |  |     if (ast.receiver instanceof ImplicitReceiver) { | 
					
						
							|  |  |  |       record.setIsImplicitReceiver(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       ast.receiver.visit(this, new Destination(record, null)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-11-11 16:54:15 -08:00
										 |  |  |     this.add(record); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   visitFunctionCall(ast:FunctionCall, dest) { | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |     var record = this.construct(RECORD_TYPE_INVOKE_CLOSURE, null, ast.args.length, null, dest); | 
					
						
							| 
									
										
										
										
											2014-11-11 16:54:15 -08:00
										 |  |  |     ast.target.visit(this, new Destination(record, null)); | 
					
						
							|  |  |  |     for (var i = 0; i < ast.args.length; ++i) { | 
					
						
							|  |  |  |       ast.args[i].visit(this, new Destination(record, i)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.add(record); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-24 18:42:53 +01:00
										 |  |  |   visitCollection(ast: Collection, dest) { | 
					
						
							|  |  |  |     var record = this.construct(RECORD_FLAG_COLLECTION, null, null, null, dest); | 
					
						
							|  |  |  |     ast.value.visit(this, new Destination(record, null)); | 
					
						
							|  |  |  |     this.add(record); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-11 17:18:09 -08:00
										 |  |  |   visitConditional(ast:Conditional, dest) { | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |     var record = this.construct(RECORD_TYPE_INVOKE_PURE_FUNCTION, _cond, 3, null, dest); | 
					
						
							| 
									
										
										
										
											2014-11-11 17:18:09 -08:00
										 |  |  |     ast.condition.visit(this, new Destination(record, 0)); | 
					
						
							|  |  |  |     ast.trueExp.visit(this, new Destination(record, 1)); | 
					
						
							|  |  |  |     ast.falseExp.visit(this, new Destination(record, 2)); | 
					
						
							|  |  |  |     this.add(record); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-02 13:14:07 +01:00
										 |  |  |   visitKeyedAccess(ast:KeyedAccess, dest) { | 
					
						
							|  |  |  |     var record = this.construct(RECORD_TYPE_INVOKE_METHOD, _keyedAccess, 1, null, dest); | 
					
						
							|  |  |  |     ast.obj.visit(this, new Destination(record, null)); | 
					
						
							|  |  |  |     ast.key.visit(this, new Destination(record, 0)); | 
					
						
							|  |  |  |     this.add(record); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-11-11 17:39:40 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   visitLiteralArray(ast:LiteralArray, dest) { | 
					
						
							|  |  |  |     var length = ast.expressions.length; | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |     var record = this.construct(RECORD_TYPE_INVOKE_PURE_FUNCTION, _arrayFn(length), length, null, dest); | 
					
						
							| 
									
										
										
										
											2014-11-11 17:39:40 -08:00
										 |  |  |     for (var i = 0; i < length; ++i) { | 
					
						
							|  |  |  |       ast.expressions[i].visit(this, new Destination(record, i)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.add(record); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-11 17:47:45 -08:00
										 |  |  |   visitLiteralMap(ast:LiteralMap, dest) { | 
					
						
							|  |  |  |     var length = ast.values.length; | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |     var record = this.construct(RECORD_TYPE_INVOKE_PURE_FUNCTION, _mapFn(ast.keys, length), length, null, dest); | 
					
						
							| 
									
										
										
										
											2014-11-11 17:47:45 -08:00
										 |  |  |     for (var i = 0; i < length; ++i) { | 
					
						
							|  |  |  |       ast.values[i].visit(this, new Destination(record, i)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.add(record); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-11-11 17:39:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-24 12:28:54 +01:00
										 |  |  |   visitChain(ast:Chain, dest){this._unsupported();} | 
					
						
							| 
									
										
										
										
											2014-11-11 17:39:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-24 12:28:54 +01:00
										 |  |  |   visitAssignment(ast:Assignment, dest) {this._unsupported();} | 
					
						
							| 
									
										
										
										
											2014-11-11 17:39:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-24 12:28:54 +01:00
										 |  |  |   visitTemplateBindings(ast, dest) {this._unsupported();} | 
					
						
							| 
									
										
										
										
											2014-11-18 16:38:36 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-02 17:09:46 -08:00
										 |  |  |   createRecordsFromAST(ast:AST, expressionMemento:any, groupMemento:any){ | 
					
						
							|  |  |  |     this.groupMemento = groupMemento; | 
					
						
							|  |  |  |     ast.visit(this, expressionMemento); | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  |   construct(recordType, funcOrValue, arity, name, dest) { | 
					
						
							| 
									
										
										
										
											2014-12-02 17:09:46 -08:00
										 |  |  |     return new ProtoRecord(this.protoRecordRange, recordType, funcOrValue, arity, name, dest, this.groupMemento); | 
					
						
							| 
									
										
										
										
											2014-10-28 12:22:38 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   add(protoRecord:ProtoRecord) { | 
					
						
							|  |  |  |     if (this.headRecord === null) { | 
					
						
							|  |  |  |       this.headRecord = this.tailRecord = protoRecord; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       this.tailRecord.next = protoRecord; | 
					
						
							|  |  |  |       this.tailRecord = protoRecord; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-11-11 17:39:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-24 12:28:54 +01:00
										 |  |  |   _unsupported() { | 
					
						
							| 
									
										
										
										
											2014-11-11 17:39:40 -08:00
										 |  |  |     throw new BaseException("Unsupported"); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-11-10 16:11:29 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _operationToFunction(operation:string):Function { | 
					
						
							|  |  |  |   switch(operation) { | 
					
						
							|  |  |  |     case '+'  : return _operation_add; | 
					
						
							|  |  |  |     case '-'  : return _operation_subtract; | 
					
						
							|  |  |  |     case '*'  : return _operation_multiply; | 
					
						
							|  |  |  |     case '/'  : return _operation_divide; | 
					
						
							|  |  |  |     case '%'  : return _operation_remainder; | 
					
						
							|  |  |  |     case '==' : return _operation_equals; | 
					
						
							|  |  |  |     case '!=' : return _operation_not_equals; | 
					
						
							|  |  |  |     case '<'  : return _operation_less_then; | 
					
						
							|  |  |  |     case '>'  : return _operation_greater_then; | 
					
						
							|  |  |  |     case '<=' : return _operation_less_or_equals_then; | 
					
						
							|  |  |  |     case '>=' : return _operation_greater_or_equals_then; | 
					
						
							|  |  |  |     case '&&' : return _operation_logical_and; | 
					
						
							|  |  |  |     case '||' : return _operation_logical_or; | 
					
						
							|  |  |  |     default: throw new BaseException(`Unsupported operation ${operation}`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _operation_negate(value)                       {return !value;} | 
					
						
							|  |  |  | function _operation_add(left, right)                    {return left + right;} | 
					
						
							|  |  |  | function _operation_subtract(left, right)               {return left - right;} | 
					
						
							|  |  |  | function _operation_multiply(left, right)               {return left * right;} | 
					
						
							|  |  |  | function _operation_divide(left, right)                 {return left / right;} | 
					
						
							|  |  |  | function _operation_remainder(left, right)              {return left % right;} | 
					
						
							|  |  |  | function _operation_equals(left, right)                 {return left == right;} | 
					
						
							|  |  |  | function _operation_not_equals(left, right)             {return left != right;} | 
					
						
							|  |  |  | function _operation_less_then(left, right)              {return left < right;} | 
					
						
							|  |  |  | function _operation_greater_then(left, right)           {return left > right;} | 
					
						
							|  |  |  | function _operation_less_or_equals_then(left, right)    {return left <= right;} | 
					
						
							|  |  |  | function _operation_greater_or_equals_then(left, right) {return left >= right;} | 
					
						
							|  |  |  | function _operation_logical_and(left, right)            {return left && right;} | 
					
						
							|  |  |  | function _operation_logical_or(left, right)             {return left || right;} | 
					
						
							| 
									
										
										
										
											2014-11-11 17:39:40 -08:00
										 |  |  | function _cond(cond, trueVal, falseVal)                 {return cond ? trueVal : falseVal;} | 
					
						
							| 
									
										
										
										
											2014-12-02 13:14:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-11 17:47:45 -08:00
										 |  |  | function _arrayFn(length:int) { | 
					
						
							| 
									
										
										
										
											2014-11-11 17:39:40 -08:00
										 |  |  |   switch (length) { | 
					
						
							|  |  |  |     case 0: return () => []; | 
					
						
							|  |  |  |     case 1: return (a1) => [a1]; | 
					
						
							|  |  |  |     case 2: return (a1, a2) => [a1, a2]; | 
					
						
							|  |  |  |     case 3: return (a1, a2, a3) => [a1, a2, a3]; | 
					
						
							|  |  |  |     case 4: return (a1, a2, a3, a4) => [a1, a2, a3, a4]; | 
					
						
							|  |  |  |     case 5: return (a1, a2, a3, a4, a5) => [a1, a2, a3, a4, a5]; | 
					
						
							|  |  |  |     case 6: return (a1, a2, a3, a4, a5, a6) => [a1, a2, a3, a4, a5, a6]; | 
					
						
							|  |  |  |     case 7: return (a1, a2, a3, a4, a5, a6, a7) => [a1, a2, a3, a4, a5, a6, a7]; | 
					
						
							|  |  |  |     case 8: return (a1, a2, a3, a4, a5, a6, a7, a8) => [a1, a2, a3, a4, a5, a6, a7, a8]; | 
					
						
							|  |  |  |     case 9: return (a1, a2, a3, a4, a5, a6, a7, a8, a9) => [a1, a2, a3, a4, a5, a6, a7, a8, a9]; | 
					
						
							|  |  |  |     default: throw new BaseException(`Does not support literal arrays with more than 9 elements`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-12-02 13:14:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-11 17:47:45 -08:00
										 |  |  | function _mapFn(keys:List, length:int) { | 
					
						
							|  |  |  |   function buildMap(values) { | 
					
						
							|  |  |  |     var res = MapWrapper.create(); | 
					
						
							|  |  |  |     for(var i = 0; i < keys.length; ++i) { | 
					
						
							|  |  |  |       MapWrapper.set(res, keys[i], values[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return res; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (length) { | 
					
						
							|  |  |  |     case 0: return () => []; | 
					
						
							|  |  |  |     case 1: return (a1) => buildMap([a1]); | 
					
						
							|  |  |  |     case 2: return (a1, a2) => buildMap([a1, a2]); | 
					
						
							|  |  |  |     case 3: return (a1, a2, a3) => buildMap([a1, a2, a3]); | 
					
						
							|  |  |  |     case 4: return (a1, a2, a3, a4) => buildMap([a1, a2, a3, a4]); | 
					
						
							|  |  |  |     case 5: return (a1, a2, a3, a4, a5) => buildMap([a1, a2, a3, a4, a5]); | 
					
						
							|  |  |  |     case 6: return (a1, a2, a3, a4, a5, a6) => buildMap([a1, a2, a3, a4, a5, a6]); | 
					
						
							|  |  |  |     case 7: return (a1, a2, a3, a4, a5, a6, a7) => buildMap([a1, a2, a3, a4, a5, a6, a7]); | 
					
						
							|  |  |  |     case 8: return (a1, a2, a3, a4, a5, a6, a7, a8) => buildMap([a1, a2, a3, a4, a5, a6, a7, a8]); | 
					
						
							|  |  |  |     case 9: return (a1, a2, a3, a4, a5, a6, a7, a8, a9) => buildMap([a1, a2, a3, a4, a5, a6, a7, a8, a9]); | 
					
						
							|  |  |  |     default: throw new BaseException(`Does not support literal maps with more than 9 elements`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-11-26 09:44:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | //TODO: cache the getters
 | 
					
						
							|  |  |  | function _mapGetter(key) { | 
					
						
							|  |  |  |   return function(map) { | 
					
						
							|  |  |  |     return MapWrapper.get(map, key); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-12-02 13:14:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _keyedAccess(obj, args) { | 
					
						
							|  |  |  |   var key = args[0]; | 
					
						
							|  |  |  |   return obj instanceof Map ? MapWrapper.get(obj, key):obj[key]; | 
					
						
							|  |  |  | } |