public override string PrettyPrint() { string obj = objInfo == null ? "" : objInfo.PrettyPrint(); var doesNotRequireParens = new NodeType[] { NodeType.MemberExpr, NodeType.RegExpLiteral, NodeType.ValueNode, NodeType.ThisExpr, NodeType.IdNode, NodeType.IdRefExpr, NodeType.FunctionCallExpr }; if ((objInfo.NodeType == NodeType.ValueNode && obj.StartsWith("-")) || !doesNotRequireParens.Contains(objInfo.NodeType)) { obj = "(" + obj + ")"; } string member = ""; if (IsValidIdentifier(memberInfo.Item1)) { member = "." + memberInfo.Item1; } else { // Prettier format for array indexing. ["1"] becomes [1]. // http://stackoverflow.com/questions/27537677/is-javascript-array-index-a-string-or-integer int numericalIndex; if (Int32.TryParse(memberInfo.Item1, out numericalIndex)) { member = "[" + memberInfo.Item1 + "]"; } else { member = "[\"" + memberInfo.Item1 + "\"]"; } } return(obj + member); }
protected override void WorkspaceCallback(Workspace workspace) { Microsoft.OData.Client.ODataProtocolVersion maxProtocolVersion = Microsoft.OData.Client.ODataProtocolVersion.V4; if (workspace.Settings.MaxProtocolVersion.HasValue) { maxProtocolVersion = workspace.Settings.MaxProtocolVersion.Value; } workspace.GenerateCallOrderInterceptors = true; // use custom concurrency provider for workspaces that can if(workspace.DataLayerProviderKind == DataLayerProviderKind.InMemoryLinq) { if (workspace.Settings.UpdatableImplementation == UpdatableImplementation.DataServiceUpdateProvider) { workspace.ServiceModifications.Interfaces.IServiceProvider.Services[typeof(Microsoft.OData.Service.Providers.IDataServiceUpdateProvider)] = "new UpdateProviderWrapper(this.CurrentDataSource)"; } else { workspace.ServiceModifications.Interfaces.IServiceProvider.Services[typeof(Microsoft.OData.Service.IUpdatable)] = "new UpdatableWrapper(this.CurrentDataSource)"; } } else if (workspace.DataLayerProviderKind == DataLayerProviderKind.NonClr) { workspace.Settings.UpdatableImplementation = UpdatableImplementation.DataServiceUpdateProvider; workspace.Settings.UseLazyPropertyLoading = false; // do this NOW instead of later, so that we can refer to these settings (workspace as NonClrWorkspace).DefineClrProperties(); if (AstoriaTestProperties.UseOpenTypes) { OpenTypesUtil.SetupDefaultOpenTypeAttributes(workspace); } } workspace.ServiceContainer.ResourceContainers.Remove("Invoices"); #region set up etags if (workspace.DataLayerProviderKind != DataLayerProviderKind.LinqToSql) { HashSet<ResourceType> typesWithETags = new HashSet<ResourceType>(); foreach (ResourceContainer container in workspace.ServiceContainer.ResourceContainers) { ResourceType baseType = container.BaseType; if (!typesWithETags.Add(baseType)) continue; // set up ETags NodeType[] etagTypes = new NodeType[] { Clr.Types.String, Clr.Types.Int16, Clr.Types.Int32, Clr.Types.Int64, Clr.Types.Guid }; List<ResourceProperty> possibleETagProperties = baseType.Properties.OfType<ResourceProperty>() .Where(p => etagTypes.Contains(p.Type) && !p.IsComplexType && !p.IsNavigation && p.PrimaryKey == null && p.Facets.IsDeclaredProperty && !p.Facets.FixedLength && p.ResourceType == baseType && p.Facets.UnderlyingType == UnderlyingType.Same && !p.Facets.IsStoreBlob && (p.Type != Clr.Types.String || (p.Facets.MaxSize.HasValue && p.Facets.MaxSize.Value < 512))) .ToList(); if (possibleETagProperties.Any()) baseType.Facets.Add(NodeFacet.Attribute(new ConcurrencyAttribute(baseType, possibleETagProperties.Choose(2).Select(p => p.Name).ToArray()))); } } #endregion #region set up blobs if (Versioning.Server.SupportsLiveFeatures && workspace.DataLayerProviderKind != DataLayerProviderKind.LinqToSql) { var edmWorkspace = workspace as EdmWorkspace; if (edmWorkspace != null) { edmWorkspace.CsdlCallbacks.Add(delegate(XmlDocument doc) { doc.InnerXml = doc.InnerXml.Replace(TestUtil.TestNamespaceManager.LookupNamespace("csdl"), TestUtil.TestNamespaceManager.LookupNamespace("csdl2")); }); edmWorkspace.SsdlCallbacks.Add(delegate(XmlDocument doc) { doc.InnerXml = doc.InnerXml.Replace("http://schemas.microsoft.com/ado/2006/04/edm/ssdl", "http://schemas.microsoft.com/ado/2009/02/edm/ssdl"); }); edmWorkspace.MslCallbacks.Add(delegate(XmlDocument doc) { doc.InnerXml = doc.InnerXml.Replace("urn:schemas-microsoft-com:windows:storage:mapping:CS", "http://schemas.microsoft.com/ado/2008/09/mapping/cs"); }); } foreach(ResourceContainer container in workspace.ServiceContainer.ResourceContainers.Where(rc => !(rc is ServiceOperation))) { if (workspace.DataLayerProviderKind == DataLayerProviderKind.Edm) { // After named-stream redesign, adding streams to EF is non-trivial continue; } if (container.ResourceTypes.Any(rt => rt.Facets.NamedStreams.Any())) { continue; } // because we don't represent streams as properties, having streams appear on anything other than the absolute base type // makes call order prediction very hard if (container.BaseType.BaseTypes.Any()) { continue; } var type = container.BaseType; switch(AstoriaTestProperties.Random.Next(3)) { case 0: type.Facets.Add(NodeFacet.Attribute(new NamedStreamResourceAttribute(type, "PhotoStream"))); break; case 1: type.Facets.Add(NodeFacet.Attribute(new NamedStreamResourceAttribute(type, "PhotoStream"))); type.Facets.Add(NodeFacet.Attribute(new NamedStreamResourceAttribute(type, "ThumbnailStream"))); type.Facets.Add(NodeFacet.Attribute(new NamedStreamResourceAttribute(type, "HighResolutionStream"))); break; } } } if (workspace.DataLayerProviderKind != DataLayerProviderKind.LinqToSql) { string streamProviderComparerTypeName = typeof(ReferenceEqualityComparer).FullName; if (workspace.DataLayerProviderKind == DataLayerProviderKind.Edm) { streamProviderComparerTypeName = workspace.Name + "EqualityComparer"; List<string> equalityComparerCode = new List<string>() { "public class " + streamProviderComparerTypeName + " : System.Data.Test.Astoria.KeyBasedEqualityComparerBase", "{", " protected override string[] GetKeyPropertyNames(Type entityType)", " {", " entityType = ObjectContext.GetObjectType(entityType);", " var fullTypeName = entityType.FullName;", }; foreach (var type in workspace.ServiceContainer.ResourceTypes) { equalityComparerCode.Add(string.Join(Environment.NewLine, new string[] { " if(fullTypeName == \"" + type.FullName + "\")", " {", " return new string[] { " + string.Join(", ", type.Properties.Where(p => p.PrimaryKey != null).Select(p => '"' + p.Name + '"').ToArray()) + " };", " }", })); } equalityComparerCode.Add(" throw new Exception(\"Unrecognized type\");"); equalityComparerCode.Add(" }"); equalityComparerCode.Add("}"); workspace.GlobalAdditionalCode += string.Join(Environment.NewLine, equalityComparerCode); } #region for inmemory/nonclr, make all int key properties server generated if (workspace.DataLayerProviderKind == DataLayerProviderKind.NonClr || workspace.DataLayerProviderKind == DataLayerProviderKind.InMemoryLinq) { foreach (ResourceType type in workspace.ServiceContainer.ResourceTypes) foreach (NodeProperty property in type.Key.Properties) if (property.Type == Clr.Types.Int32) property.Facets.ServerGenerated = true; } #endregion #region find possible blob types, and set up stream provider List<ResourceType> possibleBlobTypes = new List<ResourceType>(); foreach (ResourceType type in workspace.ServiceContainer.ResourceContainers.Where(rc => !(rc is ServiceOperation)).Select(rc => rc.BaseType)) { // need to find one that has only generated keys, all other propeties nullable, and no nav props if (type.Key.Properties.Any(p => !p.Facets.ServerGenerated)) continue; if (type.Properties.OfType<ResourceProperty>().Any(p => p.PrimaryKey == null && !p.IsNavigation && !p.Facets.Nullable)) continue; if (type.Properties.OfType<ResourceProperty>().Any(p => p.IsNavigation)) continue; possibleBlobTypes.Add(type); } if (possibleBlobTypes.Any()) { List<ResourceType> blobTypes = new List<ResourceType>(); // want one with etags, and one without ResourceType blobType = possibleBlobTypes.Where(rt => rt.Properties.Any(p => p.Facets.ConcurrencyModeFixed)).Choose(); if (blobType != null) { blobType.Facets.Add(NodeFacet.Attribute(new BlobsAttribute(blobType))); blobTypes.Add(blobType); } blobType = possibleBlobTypes.Where(rt => !rt.Properties.Any(p => p.Facets.ConcurrencyModeFixed)).Choose(); if (blobType != null) { blobType.Facets.Add(NodeFacet.Attribute(new BlobsAttribute(blobType))); blobTypes.Add(blobType); } workspace.ServiceModifications.Interfaces.IServiceProvider.Services[typeof(Microsoft.OData.Service.Providers.IDataServiceStreamProvider)] = "new StreamProviderWrapper(new System.Data.Test.Astoria.InMemoryStreamProvider<" + streamProviderComparerTypeName + ">())"; workspace.Settings.StreamProviderImplementation = StreamProviderImplementation.DataServiceStreamProvider; if (Versioning.Server.SupportsLiveFeatures && workspace.DataLayerProviderKind != DataLayerProviderKind.Edm) { workspace.ServiceModifications.Interfaces.IServiceProvider.Services[typeof(Microsoft.OData.Service.Providers.IDataServiceStreamProvider2)] = "new StreamProvider2Wrapper(new System.Data.Test.Astoria.InMemoryStreamProvider<" + streamProviderComparerTypeName + ">())"; workspace.Settings.StreamProviderImplementation = StreamProviderImplementation.DataServiceStreamProvider2; var blobTypesWithoutNamedStreams = blobTypes.Where(t => !t.Facets.NamedStreams.Any()).ToList(); if (blobTypesWithoutNamedStreams.Count != 0) { var blobTypeWithNamedStreams = blobTypesWithoutNamedStreams.Choose(); blobTypeWithNamedStreams.Facets.Add(NodeFacet.Attribute(new NamedStreamResourceAttribute(blobTypeWithNamedStreams, "Thumbnail"))); } } List<string> typeResolverLines = new List<string>(); foreach (ResourceType rt in blobTypes) { // safe because we know the types are disjoint (either do or do not have etags) and that they were the basetypes of their containers IEnumerable<ResourceContainer> containers = workspace.ServiceContainer.ResourceContainers.Where(rc => rc.BaseType == rt); foreach (ResourceContainer rc in containers) { typeResolverLines.Add(" if(entitySetName == \"" + rc.Name + "\")"); typeResolverLines.Add(" return \"" + rt.Namespace + "." + rt.Name + "\";"); } } typeResolverLines.Add(" return null;"); string typeResolverCode = string.Join(Environment.NewLine, typeResolverLines.ToArray()); workspace.RequiredFrameworkSources.Add("InMemoryStreamProvider.cs"); workspace.RequiredFrameworkSources.Add("KeyBasedEqualityComparerBase.cs"); workspace.RequiredFrameworkSources.Add("ReferenceEqualityComparer.cs"); var streamProviderFile = new ConstructedFile("InMemoryStreamProvider.cs"); workspace.ServiceModifications.Files.Add(streamProviderFile); streamProviderFile.AddMethod("ResolveType", new NewMethodInfo() { MethodSignature = "string ResolveType(string entitySetName, DataServiceOperationContext operationContext)", BodyText = typeResolverCode, }); } #endregion } #endregion #region set up service operations List<ServiceOperation> serviceOperations = new List<ServiceOperation>(); foreach(ResourceContainer container in workspace.ServiceContainer.ResourceContainers) { // no MEST yet for service ops!! if (!workspace.ServiceContainer.ResourceContainers.Any(c => c != container && c.BaseType == container.BaseType)) { foreach (RequestVerb verb in new RequestVerb[] { RequestVerb.Get, RequestVerb.Post }) { ServiceOperation serviceOp = Resource.ServiceOperation(verb.ToString() + "_" + container.Name, container, container.BaseType, container.ResourceTypes.ToArray()); serviceOp.Verb = verb; string fullTypeName = container.BaseType.Namespace + "." + container.BaseType.Name; if (workspace.DataLayerProviderKind == DataLayerProviderKind.NonClr && !container.BaseType.Facets.IsClrType) fullTypeName = typeof(NonClr.RowEntityType).FullName; serviceOp.ServiceOpCode = string.Join(Environment.NewLine, new string[] { (verb == RequestVerb.Get ? "[WebGet]" : "[WebInvoke(Method = \"POST\")]"), "public IQueryable<" + fullTypeName + "> " + serviceOp.Name + "()", "{", " return GetEntitySet<" + fullTypeName + ">(\"" + container.Name + "\");", "}" }); serviceOp.ServiceOperationResultKind = Microsoft.OData.Service.Providers.ServiceOperationResultKind.QueryWithMultipleResults; serviceOp.ExpectedTypeName = fullTypeName; serviceOperations.Add(serviceOp); } } } workspace.ServiceContainer.AddNodes(serviceOperations); workspace.AddServiceOperationCode(); #endregion }
//--------------------------------------------------------------------- // Adds concurrency attributes to resource types. //--------------------------------------------------------------------- protected virtual void AddConcurrencyAttributes(Workspace w) { if (!GetType().Name.Contains("Concurrency")) return; HashSet<ResourceType> typesWithETags = new HashSet<ResourceType>(); foreach (ResourceContainer container in w.ServiceContainer.ResourceContainers) { ResourceType baseType = container.BaseType; if (!typesWithETags.Add(baseType)) continue; // set up ETags NodeType[] etagTypes = new NodeType[] { Clr.Types.String, Clr.Types.Int16, Clr.Types.Int32, Clr.Types.Int64, Clr.Types.Guid }; List<ResourceProperty> possibleETagProperties = baseType.Properties.OfType<ResourceProperty>() .Where(p => etagTypes.Contains(p.Type) && !p.IsComplexType && !p.IsNavigation && p.PrimaryKey == null && p.Facets.IsDeclaredProperty && !p.Facets.FixedLength && p.ResourceType == baseType && p.Facets.UnderlyingType == UnderlyingType.Same && !p.Facets.IsStoreBlob && (p.Type != Clr.Types.String || (p.Facets.MaxSize.HasValue && p.Facets.MaxSize.Value < 512))) .ToList(); if (possibleETagProperties.Any()) baseType.Facets.Add(NodeFacet.Attribute(new ConcurrencyAttribute(baseType, possibleETagProperties.Choose(2).Select(p => p.Name).ToArray()))); } }
private void Generate(AbstractNode node) { var debugNodeTypes = new NodeType[] { /*NodeType.Block, * NodeType.Literal, * NodeType.Identifier, * NodeType.Loop, * NodeType.Operation,*/ }; if (debugNodeTypes.Contains(node.Type)) { Debug(node.ToString()); } switch (node.Type) { case NodeType.Block: ((BlockNode)node).Statements.ForEach(Generate); break; case NodeType.Operation: var operation = (OperationNode)node; // Operations that require two integer as input var integerOperations = new[] { OperatorType.BitwiseAnd, OperatorType.AndAlso, OperatorType.BitwiseOr, OperatorType.OrElse }; var outputIntegerOperations = new[] { OperatorType.Equals, OperatorType.Greater, OperatorType.NotGreater, OperatorType.Less, OperatorType.NotLess, OperatorType.NotEquals }; /* * We accept floating only, sometimes we need integer (logical and/or) * In this case, we cast the floating into an integer and cast back the result into a floating one. */ var requireInteger = integerOperations.Contains(operation.Operator); var requireOutputTransform = outputIntegerOperations.Contains(operation.Operator); Generate(operation.LeftOperand); if (requireInteger) { Write("ftoi"); } Generate(operation.RightOperand); if (requireInteger) { Write("ftoi"); } switch (operation.Operator) { case OperatorType.Add: Write("add.f"); break; case OperatorType.Sub: Write("sub.f"); break; case OperatorType.Mul: Write("mul.f"); break; case OperatorType.Div: Write("div.f"); break; case OperatorType.BitwiseAnd: case OperatorType.AndAlso: Write("and"); break; case OperatorType.BitwiseOr: case OperatorType.OrElse: Write("or"); break; case OperatorType.Equals: Write("cmpeq.f"); break; case OperatorType.NotEquals: Write("cmpne.f"); break; case OperatorType.NotGreater: Write("cmple.f"); break; case OperatorType.Less: Write("cmplt.f"); break; case OperatorType.NotLess: Write("cmpge.f"); break; case OperatorType.Greater: Write("cmpgt.f"); break; case OperatorType.EuclidianDiv: Write(Drop()); Write(Drop()); Generate(BuiltinFunctions.EuclidianDiv(operation.LeftOperand, operation.RightOperand)); break; case OperatorType.Mod: Write(Drop()); Write(Drop()); Generate(BuiltinFunctions.Mod(operation.LeftOperand, operation.RightOperand)); break; case OperatorType.Pow: Write(Drop()); Write(Drop()); Generate(BuiltinFunctions.Pow(operation.LeftOperand, operation.RightOperand)); break; } if (requireInteger || requireOutputTransform) { Write("itof"); } break; case NodeType.Declaration: var dcl = (AddressableDeclarationNode)node; switch (dcl.Identifier.Symbol.Type) { case ObjectType.Floating: Generate(dcl.Expression); Write ( Set(dcl.Identifier.Symbol.Pointer) ); break; case ObjectType.Pointer: var indexExpressions = ((MultiExpressionNode)dcl.Expression).Expressions; indexExpressions.Reverse(); AbstractExpressionNode finalExpression = LiteralNode.One; for (var i = 0; i < indexExpressions.Count - 1; i++) { finalExpression = new OperationNode ( OperatorType.Mul, new OperationNode ( OperatorType.Add, LiteralNode.One, indexExpressions[i] ), finalExpression ); } finalExpression = new OperationNode ( OperatorType.Mul, indexExpressions.Last(), finalExpression ); Generate(BuiltinFunctions.BorrowMemory(finalExpression)); Write(Set(dcl.Identifier.Symbol.Pointer)); var tempVar = new AddressableIdentifierNode(new PrimitiveVariableSymbol("", PointerIndex + 1)); Write(Pushf()); Generate(BuiltinFunctions.BorrowMemory(new LiteralNode(indexExpressions.Count))); Write(Set(tempVar.Symbol.Pointer)); indexExpressions.Reverse(); for (var i = 0; i < indexExpressions.Count; i++) { Generate ( new PointerAssignationNode ( new OperationNode ( OperatorType.Add, tempVar, new LiteralNode(i) ), indexExpressions[i] ) ); } /* * var a = bmem(6); * var b = bmem(2); * :b = 2; * :b + 1 = 2; * init_array(a, b, 2); */ Generate(BuiltinFunctions.InitArray(dcl.Identifier, tempVar, new LiteralNode(indexExpressions.Count))); Write(Get(tempVar.Symbol.Pointer)); Generate(BuiltinFunctions.RecoverMemory(tempVar)); break; } break; case NodeType.Reference: var refnode = (ReferenceNode)node; Write ( Pushf(refnode.Identifier.Symbol.Pointer) ); break; case NodeType.Dereference: var deref = (DereferenceNode)node; Generate(deref.Expression); Writes ( Ftoi(), MemRead(), Itof() ); break; case NodeType.Assignation: var assign = (AssignationNode)node; Generate(assign.ValueExpression); Write ( Set(assign.Identifier.Symbol.Pointer) ); break; case NodeType.Drop: Write(Drop()); break; case NodeType.PointerAssignation: var ptrAssign = (PointerAssignationNode)node; Generate(ptrAssign.AddressExpression); Write ( Ftoi() ); Generate(ptrAssign.ValueExpression); Writes ( Ftoi(), MemWrite() ); break; case NodeType.Literal: var lit = (LiteralNode)node; Write(Pushf(lit.Value)); break; case NodeType.Identifier: var ident = (AddressableIdentifierNode)node; Write ( Get(ident.Symbol.Pointer) ); break; case NodeType.Crash: Write("halt"); break; case NodeType.Print: if (node is PrintExpressionNode) { var printe = (PrintExpressionNode)node; Generate(printe.Expression); Write("out.f"); } else { var prints = (PrintStringNode)node; foreach (var c in prints.Content) { Write($"push.i {(int)c}"); Write("out.c"); } } Write("push.i 10"); Write("out.c"); break; case NodeType.Loop: var loop = (LoopNode)node; { Write(DeclareLabel(BeginLoop(loop.UniqueId))); Generate(loop.Conditional); Write(DeclareLabel(IterationLoop(loop.UniqueId))); Generate(loop.Iteration); Write(Jump(BeginLoop(loop.UniqueId))); Write(DeclareLabel(EndLoop(loop.UniqueId))); } break; case NodeType.Break: var breakNode = (BreakNode)node; Write(Jump(EndLoop(breakNode.LoopId))); break; case NodeType.Continue: var cont = (ContinueNode)node; Write(Jump(EndIf(cont.CondId))); break; case NodeType.Conditional: var cond = (ConditionalNode)node; { Generate(cond.Expression); Write(JumpFalse(Else(cond.UniqueId))); Generate(cond.TrueStatement); Write(Jump(EndIf(cond.UniqueId))); Write(DeclareLabel(Else(cond.UniqueId))); Generate(cond.FalseStatement); Write(DeclareLabel(EndIf(cond.UniqueId))); } break; case NodeType.MultiExpression: var multi = (MultiExpressionNode)node; foreach (var expression in multi.Expressions) { Generate(expression); } break; case NodeType.Function: var fun = (FunctionNode)node; Write(DeclareLabel(fun.Identifier.Symbol.Name)); PointerIndex = fun.Arguments.Count - 1; PreGenerate(fun.Statement); Generate(fun.Statement); if (fun.Identifier.Symbol.Name != "start") { Write(Pushf()); Write(Ret()); } else { Write(Halt()); } break; case NodeType.Return: var ret = (ReturnNode)node; Generate(ret.Expression); Write(Ret()); break; case NodeType.Call: var call = (CallNode)node; Write(Prep(call.Target.Symbol.Name)); foreach (var arg in call.Parameters) { Generate(arg); } Write(Call(call.Parameters.Count)); break; case NodeType.Root: var root = (RootNode)node; foreach (var f in root.Functions) { Generate(f); } break; } }