diff --git a/mcs/class/Microsoft.CSharp/Assembly/AssemblyInfo.cs b/mcs/class/Microsoft.CSharp/Assembly/AssemblyInfo.cs index 6c7a223682f..606510322cd 100644 --- a/mcs/class/Microsoft.CSharp/Assembly/AssemblyInfo.cs +++ b/mcs/class/Microsoft.CSharp/Assembly/AssemblyInfo.cs @@ -59,3 +59,4 @@ [assembly: ComVisible (false)] +[assembly: InternalsVisibleTo ("PlayScript.Core, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")] diff --git a/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpBinaryOperationBinder.cs b/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpBinaryOperationBinder.cs index 374eb0d961f..951018f2ee5 100644 --- a/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpBinaryOperationBinder.cs +++ b/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpBinaryOperationBinder.cs @@ -41,9 +41,10 @@ class CSharpBinaryOperationBinder : BinaryOperationBinder IList argumentInfo; readonly CSharpBinderFlags flags; readonly Type context; + readonly ExpressionType operation; public CSharpBinaryOperationBinder (ExpressionType operation, CSharpBinderFlags flags, Type context, IEnumerable argumentInfo) - : base (operation) + : base (GetOperation (operation)) { this.argumentInfo = new ReadOnlyCollectionBuilder (argumentInfo); if (this.argumentInfo.Count != 2) @@ -51,12 +52,24 @@ public CSharpBinaryOperationBinder (ExpressionType operation, CSharpBinderFlags this.flags = flags; this.context = context; + this.operation = operation; + } + + static ExpressionType GetOperation (ExpressionType exprType) + { + switch (exprType) { + case (ExpressionType) 0x80000: + case (ExpressionType) 0x80001: + return ExpressionType.Extension; + default: + return exprType; + } } Compiler.Binary.Operator GetOperator (out bool isCompound) { isCompound = false; - switch (Operation) { + switch (operation) { case ExpressionType.Add: return Compiler.Binary.Operator.Addition; case ExpressionType.AddAssign: @@ -123,6 +136,10 @@ Compiler.Binary.Operator GetOperator (out bool isCompound) case ExpressionType.SubtractAssign: isCompound = true; return Compiler.Binary.Operator.Subtraction; + case (ExpressionType) 0x80000: + return Compiler.Binary.Operator.StrictEquality; + case (ExpressionType) 0x80001: + return Compiler.Binary.Operator.StrictInequality; default: throw new NotImplementedException (Operation.ToString ()); } diff --git a/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpBinder.cs b/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpBinder.cs index ab977fcffcb..37dc8c1801f 100644 --- a/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpBinder.cs +++ b/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpBinder.cs @@ -66,11 +66,14 @@ public void AddRestrictions (DynamicMetaObject[] args) } public DynamicMetaObject Bind (DynamicContext ctx, Type callingType) + { + return Bind (new Compiler.ResolveContext (new RuntimeBinderContext (ctx, callingType), ResolveOptions)); + } + + public DynamicMetaObject Bind (Compiler.ResolveContext rc) { Expression res; try { - var rc = new Compiler.ResolveContext (new RuntimeBinderContext (ctx, callingType), ResolveOptions); - // Static typemanager and internal caches are not thread-safe lock (resolver) { expr = expr.Resolve (rc, Compiler.ResolveFlags.VariableOrValue); diff --git a/mcs/class/Mono.CSharp/Mono.CSharp.dll.sources b/mcs/class/Mono.CSharp/Mono.CSharp.dll.sources index 0bbd93782ba..1be26a9399d 100644 --- a/mcs/class/Mono.CSharp/Mono.CSharp.dll.sources +++ b/mcs/class/Mono.CSharp/Mono.CSharp.dll.sources @@ -55,4 +55,7 @@ ../../build/common/Consts.cs ../../tools/monop/outline.cs ../../mcs/cs-parser.cs +../../mcs/ps-parser.cs +../../mcs/ps-tokenizer.cs +../../mcs/playscript.cs Assembly/AssemblyInfo.cs diff --git a/mcs/class/PlayScript.Core/ArgumentError.play b/mcs/class/PlayScript.Core/ArgumentError.play new file mode 100644 index 00000000000..05b5aff1b1f --- /dev/null +++ b/mcs/class/PlayScript.Core/ArgumentError.play @@ -0,0 +1,25 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + + public class ArgumentError extends Error { + + public function ArgumentError(message:String = "") { + super(message); + } + + } + +} diff --git a/mcs/class/PlayScript.Core/Array.play b/mcs/class/PlayScript.Core/Array.play new file mode 100644 index 00000000000..601ddc50f8c --- /dev/null +++ b/mcs/class/PlayScript.Core/Array.play @@ -0,0 +1,115 @@ +// +// Array.play +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +package { + public dynamic class Array + { + public static const CASEINSENSITIVE:uint = 1; + public static const DESCENDING:uint = 2; + public static const UNIQUESORT:uint = 4; + public static const RETURNINDEXEDARRAY:uint = 8; + public static const NUMERIC:uint = 16; + + private static const DELETED:Object = new Object (); + + var vector:Vector.; + + public function Array (numElements:int = 0) + { + vector = new Vector. (numElements); + } + + public function Array (...rest) + { + vector = new Vector. (rest); + } + + public function get length ():uint + { + return vector.length; + } + + public function set length (value:uint):void + { + vector.length = value; + } + + // TODO: + //public function push (...rest):uint + //{ + // throw new System.NotImplementedException (); + // // TODO: return vector.push (rest); + //} + + + public function splice (startIndex:int = 0, deleteCount:uint = 4294967295 /*uint.MAX_VALUE*/, ...values):Array + { + throw new System.NotImplementedException (); + } + + // + // Extensions to AS3 + // + public function push (value:Object):uint + { + return vector.push (value); + } + + internal function setValue (index:uint, value:Object):void + { + if (index < 0) + throw new System.NotImplementedException (); // TODO: Allowed but how to handle + + // + // Assigning out of array range + // + if (index >= vector.length) { +// while (length < index - 1) +// list.Add (default (T)); // TODO: Need better "invisible" value, perhaps DELETED would work ? + + vector.push (value); + return; + } + + vector.setValue (index, value); + } + + internal function getValue (index:uint):* + { + if (index < 0 || index > vector.length) + return undefined; + + return vector.getValue (index); + } + + internal function deleteValue (index:uint):void + { + setValue (index, DELETED); + } + } +} \ No newline at end of file diff --git a/mcs/class/PlayScript.Core/Assembly/AssemblyInfo.cs b/mcs/class/PlayScript.Core/Assembly/AssemblyInfo.cs new file mode 100644 index 00000000000..a5057c7abf7 --- /dev/null +++ b/mcs/class/PlayScript.Core/Assembly/AssemblyInfo.cs @@ -0,0 +1,56 @@ +// +// AssemblyInfo.cs +// +// Authors: +// Marek Safar (marek.safar@gmail.com) +// +// Copyright 2013 Xamarin Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Reflection; +using System.Resources; +using System.Security; +using System.Security.Permissions; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about the assembly + +[assembly: AssemblyTitle ("PlayScript.Core.dll")] +[assembly: AssemblyDescription ("PlayScript.Core.dll")] +[assembly: AssemblyDefaultAlias ("PlayScript.Core.dll")] + +[assembly: AssemblyCompany (Consts.MonoCompany)] +[assembly: AssemblyProduct (Consts.MonoProduct)] +[assembly: AssemblyCopyright (Consts.MonoCopyright)] +[assembly: AssemblyVersion (Consts.FxVersion)] +[assembly: SatelliteContractVersion (Consts.FxVersion)] +[assembly: AssemblyInformationalVersion (Consts.FxFileVersion)] +[assembly: AssemblyFileVersion (Consts.FxFileVersion)] + +[assembly: NeutralResourcesLanguage ("en-US")] +[assembly: CLSCompliant (false)] + +[assembly: ComVisible (false)] + diff --git a/mcs/class/PlayScript.Core/Boolean.cs b/mcs/class/PlayScript.Core/Boolean.cs new file mode 100644 index 00000000000..e49abc070fc --- /dev/null +++ b/mcs/class/PlayScript.Core/Boolean.cs @@ -0,0 +1,30 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; + +namespace _root +{ + public static class Boolean + { + public static string toString(this bool b) { + return b ? "true" : "false"; + } + + public static bool valueOf(this bool b) { + return b; + } + } +} + diff --git a/mcs/class/PlayScript.Core/Date.play b/mcs/class/PlayScript.Core/Date.play new file mode 100644 index 00000000000..91b712ea97d --- /dev/null +++ b/mcs/class/PlayScript.Core/Date.play @@ -0,0 +1,41 @@ +// +// Date.play +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +package { + public final dynamic class Date + { + public function Date (yearOrTimevalue:Object = null, month:Number = 1, date:Number = 1, hour:Number = 0, minute:Number = 0, second:Number = 0, millisecond:Number = 0) + { + } + + public static function UTC (year:Number, month:Number, date:Number = 1, hour:Number = 0, minute:Number = 0, second:Number = 0, millisecond:Number = 0):Number + { + return 0; + } + } +} \ No newline at end of file diff --git a/mcs/class/PlayScript.Core/DefinitionError.play b/mcs/class/PlayScript.Core/DefinitionError.play new file mode 100644 index 00000000000..57c9963504b --- /dev/null +++ b/mcs/class/PlayScript.Core/DefinitionError.play @@ -0,0 +1,26 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + + public class DefinitionError extends Error { + + public function DefinitionError(message:String = "") { + super(message); + } + + } + +} + diff --git a/mcs/class/PlayScript.Core/DeprecatedAttribute.cs b/mcs/class/PlayScript.Core/DeprecatedAttribute.cs new file mode 100644 index 00000000000..d27f70234bd --- /dev/null +++ b/mcs/class/PlayScript.Core/DeprecatedAttribute.cs @@ -0,0 +1,29 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; + +namespace _root +{ + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public class DeprecatedAttribute : Attribute + { + public DeprecatedAttribute() + { + } + + public string message {get;set;} + } +} + diff --git a/mcs/class/PlayScript.Core/EmbedAttribute.cs b/mcs/class/PlayScript.Core/EmbedAttribute.cs new file mode 100644 index 00000000000..ff8f7a901d1 --- /dev/null +++ b/mcs/class/PlayScript.Core/EmbedAttribute.cs @@ -0,0 +1,38 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; + +namespace _root +{ + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public class EmbedAttribute : Attribute + { + public string source { get; set; } + + public string mimeType { get; set; } + + public string embedAsCFF { get; set; } + + public string fontFamily { get; set; } + + public string symbol { get; set; } + + public EmbedAttribute (string _source = null) + { + source = _source; + } + } +} + diff --git a/mcs/class/PlayScript.Core/Error.play b/mcs/class/PlayScript.Core/Error.play new file mode 100644 index 00000000000..3f35ca98798 --- /dev/null +++ b/mcs/class/PlayScript.Core/Error.play @@ -0,0 +1,106 @@ +// +// Error.play +// +// Authors: +// Marek Safar +// +// Copyright 2013 Zynga Inc. +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +package { + + public dynamic class Error extends System.Exception + { + private var error_id : int; + + public function Error (message:String = "", id:int = 0) + { + super (message); + error_id = id; + } + + public function get errorID () : int + { + return error_id; + } + + public function get message () : String + { + return Message; + } + + public function set message (value:String): void + { + throw new System.NotImplementedException(); + } + + public function get name () : String + { + return GetType().Name; + } + + public function set name (value:String): void + { + throw new System.NotImplementedException(); + } + + public function getStackTrace () : String + { + return StackTrace; + } + + public static function getErrorMessage (index:int) : String + { + // TODO: Finish all error messages + var msg:String; + switch (index) { + case 1000: + msg = "The system is out of memory."; + break; + case 1001: + msg = "The method {0} is not implemented."; + break; + case 1002: + msg = "Number.toPrecision has a range of 1 to 21. Number.toFixed and Number.toExponential have a range of 0 to 20. Specified value is not within expected range."; + break; + case 1007: + msg = "Instantiation attempted on a non-constructor."; + break; + case 1009: + msg = "Cannot access a property or method of a null object reference."; + break; + } + + if (msg == null) + return System.String.Format ("#{0}", index); + + return System.String.Format ("#{0}: {1}", index, msg); + } + + public static function throwError (type:Class, index:uint, ...rest) : * + { + throw new System.NotImplementedException (); + } + } +} + diff --git a/mcs/class/PlayScript.Core/EventAttribute.cs b/mcs/class/PlayScript.Core/EventAttribute.cs new file mode 100644 index 00000000000..d9d94b355c0 --- /dev/null +++ b/mcs/class/PlayScript.Core/EventAttribute.cs @@ -0,0 +1,31 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; + +namespace _root +{ + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public class EventAttribute : Attribute + { + public string name { get; set; } + + public string type { get; set; } + + public EventAttribute () + { + } + } +} + diff --git a/mcs/class/PlayScript.Core/Extensions.cs b/mcs/class/PlayScript.Core/Extensions.cs new file mode 100644 index 00000000000..3bad9c3f80b --- /dev/null +++ b/mcs/class/PlayScript.Core/Extensions.cs @@ -0,0 +1,54 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections; + +namespace _root +{ + public static class Extensions + { +// public static string toString(this object o) +// { +// return o.ToString (); +// } + + public static string toLocaleString(this object o) + { + return o.ToString (); + } + + public static bool hasOwnProperty(this object o, string name) + { + var t = o.GetType (); + return t.GetProperty(name) != null || t.GetField(name) != null; + } + + public static string toString(this uint o, int radix = 10) + { + return Convert.ToString (o, radix); + } + + // + // IList extensions (for arrays, etc). + // + +// public static int get_length(this IList list) +// { +// return list.Count; +// } + + } +} + diff --git a/mcs/class/PlayScript.Core/FunctionExtensions.cs b/mcs/class/PlayScript.Core/FunctionExtensions.cs new file mode 100644 index 00000000000..3354b81518d --- /dev/null +++ b/mcs/class/PlayScript.Core/FunctionExtensions.cs @@ -0,0 +1,52 @@ +// +// FunctionExtensions.cs +// +// Authors: +// Marek Safar +// +// Copyright 2013 Zynga Inc. +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace _root { + + public static class FunctionExtensions { + + public static dynamic apply (this Delegate d, object thisArg = null, Array argArray = null) + { + return d.DynamicInvoke (argArray != null ? argArray.ToArray() : null); + } + + public static dynamic call (this Delegate d, object thisArg = null, params object[] rest) + { + return d.DynamicInvoke (rest); + } + + // this returns the number of arguments to the delegate method + //public static int get_length(this Delegate d) { + // return d.Method.GetParameters().Length; + //} + + } +} diff --git a/mcs/class/PlayScript.Core/JSON.play b/mcs/class/PlayScript.Core/JSON.play new file mode 100644 index 00000000000..f9cea4a7957 --- /dev/null +++ b/mcs/class/PlayScript.Core/JSON.play @@ -0,0 +1,29 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + + public class JSON { + + public static function parse(text:String, reviver:Function = null):Object { + throw new System.NotImplementedException(); + } + + public static function stringify(value:Object, replacer:* = null, space:* = null):String { + throw new System.NotImplementedException(); + } + + } + +} diff --git a/mcs/class/PlayScript.Core/Makefile b/mcs/class/PlayScript.Core/Makefile new file mode 100644 index 00000000000..6a8981262b7 --- /dev/null +++ b/mcs/class/PlayScript.Core/Makefile @@ -0,0 +1,12 @@ +thisdir = class/PlayScript.Core +include ../../build/rules.make + +LIBRARY = PlayScript.Core.dll +LIBRARY_SNK = ../mono.snk +LIBRARY_PACKAGE = none + +LIB_MCS_FLAGS = -d:DYNAMIC_SUPPORT -keyfile:$(LIBRARY_SNK) -delaysign -r:System.dll -r:System.Core.dll -r:System.Xml.dll -r:Microsoft.CSharp.dll -r:Mono.CSharp.dll + +NO_TEST = yes + +include ../../build/library.make diff --git a/mcs/class/PlayScript.Core/Math.play b/mcs/class/PlayScript.Core/Math.play new file mode 100644 index 00000000000..d1e58d569b1 --- /dev/null +++ b/mcs/class/PlayScript.Core/Math.play @@ -0,0 +1,127 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + + public class Math { + + // + // Constants + // + + public static const E : Number = 2.71828182845905; + + public static const LN10 : Number = 2.302585092994046; + + public static const LN2 : Number = 0.6931471805599453; + + public static const LOG10E : Number = 0.4342944819032518; + + public static const LOG2E : Number = 1.442695040888963387; + + public static const PI : Number = 3.141592653589793; + + public static const SQRT1_2 : Number = 0.7071067811865476; + + public static const SQRT2 : Number = 1.4142135623730951; + + // + // Methods + // + + public static function abs(val:Number):Number { + return System.Math.Abs(val); + } + + public static function acos(val:Number):Number { + return System.Math.Acos(val); + } + + public static function asin(val:Number):Number { + return System.Math.Asin(val); + } + + public static function atan(val:Number):Number { + return System.Math.Atan(val); + } + + public static function atan2(y:Number, x:Number):Number { + return System.Math.Atan2(y, x); + } + + public static function ceil(val:Number):Number { + return System.Math.Ceiling(val); + } + + public static function cos(angleRadians:Number):Number { + return System.Math.Cos(angleRadians); + } + + public static function exp(val:Number):Number { + return System.Math.Exp(val); + } + + public static function floor(val:Number):Number { + return System.Math.Floor(val); + } + + public static function log(val:Number):Number { + return System.Math.Log(val); + } + + public static function max(val1:Number, val2:Number):Number { + return System.Math.Max(val1, val2); + } + + public static function max(val1:Number, val2:Number, ... rest):Number { + throw new System.NotImplementedException(); + } + + public static function min(val1:Number, val2:Number):Number { + return System.Math.Min(val1, val2); + } + + public static function min(val1:Number, val2:Number, ... rest):Number { + throw new System.NotImplementedException(); + } + + public static function pow(base:Number, pow:Number):Number { + return System.Math.Pow(base, pow); + } + + private static var sRandom:System.Random = new System.Random(); + + public static function random():Number { + return sRandom.NextDouble(); + } + + public static function round(val:Number):Number { + return System.Math.Round(val); + } + + public static function sin(angleRadians:Number):Number { + return System.Math.Sin(angleRadians); + } + + public static function sqrt(val:Number):Number { + return System.Math.Sqrt(val); + } + + public static function tan(angleRadians:Number):Number { + return System.Math.Tan(angleRadians); + } + + } + +} diff --git a/mcs/class/PlayScript.Core/Namespace.play b/mcs/class/PlayScript.Core/Namespace.play new file mode 100644 index 00000000000..76475a0f06d --- /dev/null +++ b/mcs/class/PlayScript.Core/Namespace.play @@ -0,0 +1,61 @@ +// +// Namespace.play +// +// Authors: +// Marek Safar +// +// Copyright 2013 Zynga Inc. +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + + public final class Namespace + { + private var prefix_value:String; + private var uri_value:String; + + public function Namespace (prefix:*=null, uri:*=null) + { + prefix_value = prefix; + uri_value = uri; + } + + // + // Properties + // + public function get prefix () : String + { + return prefix_value; + } + + public function get uri () : String + { + return uri_value; + } + + // + // Methods + // + public function toString ():String + { + throw new System.NotImplementedException(); + } + + public function valueOf ():Object + { + throw new System.NotImplementedException(); + } + } +} diff --git a/mcs/class/PlayScript.Core/Number.cs b/mcs/class/PlayScript.Core/Number.cs new file mode 100644 index 00000000000..f57735524f8 --- /dev/null +++ b/mcs/class/PlayScript.Core/Number.cs @@ -0,0 +1,63 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace _root { + + public static class Number { + + // + // Extension Methods + // + + public static string toExponential(this double d, uint fractionDigits) { + throw new System.NotImplementedException(); + } + + public static string toFixed(this double d, uint fractionDigits) { + return d.ToString ( "F" + fractionDigits.ToString() ); + } + + public static string toPrecision(this double d, uint precision) { + throw new System.NotImplementedException(); + } + + public static string toString(this double d) { + return d.ToString(); + } + + public static string toString(this double d, double radix) { + throw new System.NotImplementedException(); + } + + public static double valueOf(this double d) { + return d; + } + + // + // Constants + // + + public const double MAX_VALUE = System.Double.MaxValue; + + public const double MIN_VALUE = System.Double.MinValue; + + public const double @NaN = System.Double.NaN; + + public const double NEGATIVE_INFINITY = System.Double.NegativeInfinity; + + public const double POSITIVE_INFINITY = System.Double.PositiveInfinity; + + } + +} diff --git a/mcs/class/PlayScript.Core/PlayScript.Core.dll.sources b/mcs/class/PlayScript.Core/PlayScript.Core.dll.sources new file mode 100644 index 00000000000..d94edce03cb --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Core.dll.sources @@ -0,0 +1,47 @@ +../../build/common/Consts.cs +./Assembly/AssemblyInfo.cs +./Array.play +./Boolean.cs +./Date.play +./DeprecatedAttribute.cs +./EmbedAttribute.cs +./EventAttribute.cs +./Extensions.cs +./FunctionExtensions.cs +./functions.cs +./int.cs +./Number.cs +./StringExtensions.cs +./ArgumentError.play +./DefinitionError.play +./Error.play +./JSON.play +./Math.play +./Namespace.play +./QName.play +./RangeError.play +./ReferenceError.play +./RegExp.play +./SecurityError.play +./SyntaxError.play +./SWFAttribute.cs +./toplevel.play +./TypeError.play +./URIError.play +./Vector.cs +./VerifyError.play +./XML.play +./XMLList.play + +./PlayScript.Runtime/BinaryOperator.cs +./PlayScript.Runtime/Binder.cs +./PlayScript.Runtime/DefaultObjectContext.cs +./PlayScript.Runtime/IsPropertyBinder.cs +./PlayScript.Runtime/PlayScriptGetMemberBinder.cs +./PlayScript.Runtime/Operations.cs +./PlayScript.Runtime/Undefined.cs +./PlayScript.Runtime.CompilerServices/ConstantFieldAttribute.cs +./PlayScript.Runtime.CompilerServices/DynamicClassAttribute.cs +./PlayScript.Runtime.CompilerServices/NamespaceFieldAttribute.cs +./PlayScript.Runtime.CompilerServices/PlayScriptAttribute.cs +./PlayScript.Runtime.CompilerServices/RestArrayParameterAttribute.cs diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/ConstantFieldAttribute.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/ConstantFieldAttribute.cs new file mode 100644 index 00000000000..b35e254d14a --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/ConstantFieldAttribute.cs @@ -0,0 +1,47 @@ +// +// ConstantFieldAttribute.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace PlayScript.Runtime.CompilerServices +{ + [AttributeUsage (AttributeTargets.Field)] + public sealed class ConstantFieldAttribute : Attribute + { + public ConstantFieldAttribute () + { + } + + public ConstantFieldAttribute (object value) + { + Value = value; + } + + public object Value { get; private set; } + } +} diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/DynamicClassAttribute.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/DynamicClassAttribute.cs new file mode 100644 index 00000000000..54af470d6c0 --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/DynamicClassAttribute.cs @@ -0,0 +1,37 @@ +// +// DynamicClassAttribute.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace PlayScript.Runtime.CompilerServices +{ + [AttributeUsage (AttributeTargets.Class)] + public sealed class DynamicClassAttribute : Attribute + { + } +} diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/NamespaceFieldAttribute.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/NamespaceFieldAttribute.cs new file mode 100644 index 00000000000..d5919fa5dee --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/NamespaceFieldAttribute.cs @@ -0,0 +1,43 @@ +// +// NamespaceFieldAttribute.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace PlayScript.Runtime.CompilerServices +{ + [AttributeUsage (AttributeTargets.Field)] + public sealed class NamespaceFieldAttribute : Attribute + { + public NamespaceFieldAttribute (string uri) + { + Uri = uri; + } + + public string Uri { get; private set; } + } +} diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/PlayScriptAttribute.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/PlayScriptAttribute.cs new file mode 100644 index 00000000000..7fc04c9ff1c --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/PlayScriptAttribute.cs @@ -0,0 +1,37 @@ +// +// PlayScriptAttribute.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace PlayScript.Runtime.CompilerServices +{ + [AttributeUsage (AttributeTargets.Class)] + public sealed class PlayScriptAttribute : Attribute + { + } +} diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/RestArrayParameterAttribute.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/RestArrayParameterAttribute.cs new file mode 100644 index 00000000000..959699d27a5 --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime.CompilerServices/RestArrayParameterAttribute.cs @@ -0,0 +1,37 @@ +// +// RestArrayAttribute.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace PlayScript.Runtime.CompilerServices +{ + [AttributeUsage (AttributeTargets.Parameter)] + public sealed class RestArrayParameterAttribute : Attribute + { + } +} diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime/BinaryOperator.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime/BinaryOperator.cs new file mode 100644 index 00000000000..4c2209d4195 --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime/BinaryOperator.cs @@ -0,0 +1,62 @@ +// +// BinaryOperator.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace PlayScript.Runtime +{ + public enum BinaryOperator + { + Multiply = 1, + Division = 2, + Modulus = 3, + Addition = 4, + Subtraction = 5, + + LeftShift = 10, + RightShift = 11, + UnsignedRightShift = 12, + + LessThan = 20, + GreaterThan = 21, + LessThanOrEqual = 22, + GreaterThanOrEqual = 23, + Equality = 24, + Inequality = 25, + + BitwiseAnd = 30, + ExclusiveOr = 31, + BitwiseOr = 32, + + LogicalAnd = 40, + LogicalOr = 41, + + StrictEquality = 50 | StrictMask, + StrictInequality = 51 | StrictMask, + + StrictMask = 1 >> 16 + } +} \ No newline at end of file diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime/Binder.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime/Binder.cs new file mode 100644 index 00000000000..7f17d7ec258 --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime/Binder.cs @@ -0,0 +1,286 @@ +// +// Binder.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Runtime.CompilerServices; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Microsoft.CSharp.RuntimeBinder; +using System.Globalization; + +namespace PlayScript.Runtime +{ + public static class Binder + { + static readonly ConditionalWeakTable> dynamic_classes = new ConditionalWeakTable> (); + + public static dynamic GetMember (object instance, Type context, object name) + { + if (instance == null) + throw GetNullObjectReferenceException (); + + // + // Use index getter when name can be converted to number on array instances + // + var array = instance as _root.Array; + if (array != null) { + var index = GetArrayIndex (name); + if (index != null) { + return array.getValue (index.Value); + } + } + + var sname = GetName (name); + + ConcurrentDictionary members; + if (dynamic_classes.TryGetValue (instance, out members)) { + object value; + if (members.TryGetValue (sname, out value)) + return value; + } + + var binder = Microsoft.CSharp.RuntimeBinder.Binder.GetMember (CSharpBinderFlags.None, sname, context, new[] { CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null) }); + var callsite = CallSite>.Create (binder); + + // TODO: Add caching to avoid expensive Resolve + return callsite.Target (callsite, instance); + } + + public static CallSiteBinder GetMember (string name, Type context, DefaultObjectContext objectContext) + { + return new PlayScriptGetMemberBinder (name, context, objectContext); + } + + public static void SetMember (object instance, Type context, object name, object value) + { + if (instance == null) + throw GetNullObjectReferenceException (); + + // + // Use index setter when name can be converted to number on array instances + // + var array = instance as _root.Array; + if (array != null) { + var index = GetArrayIndex (name); + if (index != null) { + array.setValue (index.Value, value); + return; + } + } + + var sname = GetName (name); + + var binder = Microsoft.CSharp.RuntimeBinder.Binder.SetMember (CSharpBinderFlags.None, sname, context, + new[] { CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null) }); + var callsite = CallSite>.Create (binder); + + // TODO: Better handling + try { + // TODO: Add caching to avoid expensive Resolve + callsite.Target (callsite, instance, value); + } catch (RuntimeBinderException) { + var members = dynamic_classes.GetOrCreateValue (instance); + + // TODO: Not thread safe + members[sname] = value; + } + } + + public static IEnumerable GetKeys (object instance) + { + if (instance == null) + return new string [0]; + + // + // Array's are different + // + var array = instance as _root.Array; + if (array != null) { + return CreateArrayKeysIterator (array.length); + } + + ConcurrentDictionary members; + if (dynamic_classes.TryGetValue (instance, out members)) { + return CreateMemberKeysIterator (members.Keys); + } + + return new string [0]; + } + + static IEnumerable CreateArrayKeysIterator (uint length) + { + for (uint i = 0; i < length; ++i) + yield return i.ToString (CultureInfo.InvariantCulture); + } + + static IEnumerable CreateMemberKeysIterator (ICollection keys) + { + foreach (var key in keys) + yield return key; + } + + public static IEnumerable GetValues (object instance) + { + if (instance == null) + return new dynamic [0]; + + // + // Array's are different + // + var array = instance as _root.Array; + if (array != null) { + return CreateArrayValuesIterator (array); + } + + ConcurrentDictionary members; + if (dynamic_classes.TryGetValue (instance, out members)) { + return CreateMemberValuesIterator (members.Values); + } + + return new dynamic [0]; + } + + static IEnumerable CreateArrayValuesIterator (_root.Array array) + { + for (uint i = 0; i < array.length; ++i) + yield return array [i]; + } + + static IEnumerable CreateMemberValuesIterator (ICollection values) + { + foreach (var value in values) + yield return value; + } + + public static bool HasProperty (object instance, Type context, object property) + { + if (instance == null) + throw GetNullObjectReferenceException (); + + // + // Calling in operator on Array instance means something different + // + var array = instance as _root.Array; + if (array != null) { + var index = GetArrayIndex (property); + if (index == null) + return false; + + return array.length > index; + } + + var type = instance as Type; + var sname = GetName (property); + bool static_only; + + // + // It's null when it's not static + // + if (type == null) { + ConcurrentDictionary members; + if (dynamic_classes.TryGetValue (instance, out members) && members.ContainsKey (sname)) { + return true; + } + + type = instance.GetType (); + static_only = false; + } else { + static_only = true; + } + + var binder = new IsPropertyBinder (sname, context, static_only); + + var callsite = CallSite>.Create (binder); + + // TODO: Better handling + try { + // TODO: Add caching to avoid expensive Resolve + return callsite.Target (callsite, type); + } catch (RuntimeBinderException) { + throw; + } + } + + public static bool DeleteProperty (object instance, object property) + { + // + // delete operator on Array instances + // + var array = instance as _root.Array; + if (array != null) { + var index = GetArrayIndex (property); + if (index != null) { + array.deleteValue (index.Value); + } + + return true; + } + + ConcurrentDictionary members; + if (dynamic_classes.TryGetValue (instance, out members)) { + var sname = GetName (property); + + object value; + members.TryRemove (sname, out value); + } + + return true; + } + + public static dynamic DelegateInvoke (Delegate instance, params object[] args) + { + if (instance == null) + throw new NotImplementedException (); + + return instance.DynamicInvoke (args); + } + + static uint? GetArrayIndex (object value) + { + try { + return Convert.ToUInt32 (value); + } catch { + return null; + } + } + + static string GetName (object name) + { + // TODO: Will be special token for null key enough? + if (name == null) + throw new NotImplementedException ("null name"); + + return name.ToString (); + } + + static Exception GetNullObjectReferenceException () + { + return new _root.Error ("Cannot access a property or method of a null object reference.", 1009); + } + } +} diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime/DefaultObjectContext.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime/DefaultObjectContext.cs new file mode 100644 index 00000000000..aa67e63e2de --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime/DefaultObjectContext.cs @@ -0,0 +1,74 @@ +// +// DefaultObjectContext.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Collections.Generic; +using Microsoft.CSharp.RuntimeBinder; +using Compiler = Mono.CSharp; +using PSCompiler = Mono.PlayScript; + +namespace PlayScript.Runtime +{ + public class DefaultObjectContext + { + readonly Stack stack; + + private DefaultObjectContext () + { + stack = new Stack (); + } + + internal Stack Context { + get { + return stack; + } + } + + public static DefaultObjectContext Create () + { + return new DefaultObjectContext (); + } + + // TODO: Will likely need extra argument for something similar to CSharpArgumentInfoFlags to correctly + // recreate source expression + public void Register (object instance) + { + if (instance == null) + throw new _root.TypeError (_root.Error.getErrorMessage (1009), 1009); + + var ctx = DynamicContext.Create (); + var expr = new PSCompiler.ObjectContextRuntimeExpression (ctx.ImportType (instance.GetType ())); + + stack.Push (expr); + } + + public void Unregister () + { + stack.Pop (); + } + } +} \ No newline at end of file diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime/IsPropertyBinder.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime/IsPropertyBinder.cs new file mode 100644 index 00000000000..f9842515ffd --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime/IsPropertyBinder.cs @@ -0,0 +1,77 @@ +// +// IsPropertyBinder.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2009 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Dynamic; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CSharp.RuntimeBinder; +using Compiler = Mono.CSharp; + +namespace PlayScript.Runtime +{ + class IsPropertyBinder : DynamicMetaObjectBinder + { + Type callingContext; + string name; + bool static_only; + + public IsPropertyBinder (string name, Type callingContext, bool staticOnly) + { + this.name = name; + this.callingContext = callingContext; + this.static_only = staticOnly; + } + + public override DynamicMetaObject Bind (DynamicMetaObject target, DynamicMetaObject[] args) + { + var ctx = DynamicContext.Create (); + var context_type = ctx.ImportType (callingContext); + var queried_type = ctx.ImportType ((Type) target.Value); + var rc = new Compiler.ResolveContext (new RuntimeBinderContext (ctx, context_type), 0); + + var expr = Compiler.Expression.MemberLookup (rc, false, queried_type, + name, 0, Compiler.Expression.MemberLookupRestrictions.ExactArity, Compiler.Location.Null); + + var pe = expr as Compiler.PropertyExpr; + var result = pe != null && pe.IsStatic == static_only; + + var binder = new CSharpBinder ( + this, new Compiler.BoolConstant (ctx.CompilerContext.BuiltinTypes, result, Compiler.Location.Null), null); + + binder.AddRestrictions (target); + return binder.Bind (ctx, callingContext); + } + + public override Type ReturnType { + get { + return typeof (bool); + } + } + } +} diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime/Operations.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime/Operations.cs new file mode 100644 index 00000000000..7986ec15ba0 --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime/Operations.cs @@ -0,0 +1,193 @@ +// +// Operations.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace PlayScript.Runtime +{ + public static class Operations + { + public static bool Comparison (BinaryOperator binaryOperator, object left, object right) + { + if (right is int) + return Comparison (binaryOperator, left, (int) right); + + if (right is string) + return Comparison (binaryOperator, left, (string) right); + + // TODO: uint, string, double, etc + + return false; + } + + public static bool Comparison (BinaryOperator binaryOperator, object left, int right) + { + if (left is int) { + var l = (int) left; + switch (binaryOperator) { + case BinaryOperator.Equality: + case BinaryOperator.StrictEquality: + return l == right; + case BinaryOperator.Inequality: + return l != right; + case BinaryOperator.GreaterThan: + return l > right; + case BinaryOperator.GreaterThanOrEqual: + return l >= right; + case BinaryOperator.LessThan: + return l < right; + case BinaryOperator.LessThanOrEqual: + return l <= right; + default: + throw new NotImplementedException (binaryOperator.ToString ()); + } + } + + if ((binaryOperator & BinaryOperator.StrictMask) != 0) + return binaryOperator == BinaryOperator.StrictInequality; + + // TODO: uint, string, double, etc + + return false; + } + + public static bool Comparison (BinaryOperator binaryOperator, int left, object right) + { + if (right is int) { + var r = (int) right; + switch (binaryOperator) { + case BinaryOperator.Equality: + case BinaryOperator.StrictEquality: + return left == r; + case BinaryOperator.Inequality: + case BinaryOperator.StrictInequality: + return left != r; + case BinaryOperator.GreaterThan: + return left > r; + case BinaryOperator.GreaterThanOrEqual: + return left >= r; + case BinaryOperator.LessThan: + return left < r; + case BinaryOperator.LessThanOrEqual: + return left <= r; + default: + throw new NotImplementedException (binaryOperator.ToString ()); + } + } + + if ((binaryOperator & BinaryOperator.StrictMask) != 0) + return binaryOperator == BinaryOperator.StrictInequality; + + // TODO: uint, string, double, etc + + return false; + } + + public static bool Comparison (BinaryOperator binaryOperator, object left, string right) + { + if (right is string) { + var l = (string) left; + switch (binaryOperator) { + case BinaryOperator.Equality: + case BinaryOperator.StrictEquality: + return l == right; + case BinaryOperator.Inequality: + case BinaryOperator.StrictInequality: + return l != right; +/* TODO: rules base on char comparison but how does it work with unicode + case BinaryOperator.GreaterThan: + return l > right; + case BinaryOperator.GreaterThanOrEqual: + return l >= right; + case BinaryOperator.LessThan: + return l < right; + case BinaryOperator.LessThanOrEqual: + return l <= right; + default: + throw new NotImplementedException (binaryOperator.ToString ()); +*/ + } + } + + if ((binaryOperator & BinaryOperator.StrictMask) != 0) + return binaryOperator == BinaryOperator.StrictInequality; + + // TODO: uint, string, double, etc + + return false; + } + + public static Type ClassOf (object instance) + { + var type = instance as Type; + if (type == null) + throw new _root.TypeError (_root.Error.getErrorMessage (1007), 1007); + + return type; + } + + public static bool IsOfType (ref T instance, Type expectedType) + { + if (expectedType == null) + throw new _root.TypeError (_root.Error.getErrorMessage (1009), 1009); + + if (instance == null) + return false; + + return expectedType.IsAssignableFrom (instance.GetType ()); + } + + public static string TypeOf (object instance) + { + if (instance == null) + return "object"; + + if (instance is string) + return "string"; + + if (instance is int || instance is uint || instance is double) + return "number"; + + if (instance is bool) + return "boolean"; + + // TODO: Wrong, it has to be of a special type + if (instance == Undefined.Value) + return "undefined"; + + // TODO: Wrong, it has to be of a special type + if (instance is _root.XML || instance is _root.XMLList) + return "xml"; + + if (instance is Delegate) + return "function"; + + return "object"; + } + } +} diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime/PlayScriptGetMemberBinder.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime/PlayScriptGetMemberBinder.cs new file mode 100644 index 00000000000..83da46c7889 --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime/PlayScriptGetMemberBinder.cs @@ -0,0 +1,69 @@ +// +// PlayScriptGetMemberBinder.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.Dynamic; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CSharp.RuntimeBinder; +using Compiler = Mono.CSharp; +using PSCompiler = Mono.PlayScript; + +namespace PlayScript.Runtime +{ + class PlayScriptGetMemberBinder : GetMemberBinder + { + Type callingContext; + DefaultObjectContext objectContext; + + public PlayScriptGetMemberBinder (string name, Type callingContext, DefaultObjectContext objectContext) + : base (name, false) + { + this.callingContext = callingContext; + this.objectContext = objectContext; + } + + public override DynamicMetaObject FallbackGetMember (DynamicMetaObject target, DynamicMetaObject errorSuggestion) + { + var ctx = DynamicContext.Create (); + + Compiler.Expression expr = new PSCompiler.SimpleName (Name, Compiler.Location.Null); + expr = new Compiler.Cast (new Compiler.TypeExpression (ctx.ImportType (ReturnType), Compiler.Location.Null), expr, Compiler.Location.Null); + + var binder = new CSharpBinder (this, expr, errorSuggestion); + binder.AddRestrictions (target); + + // TODO: RuntimeBinderContext is not enough, it won't search global extension methods for builtin types + var rc = new Compiler.ResolveContext (new RuntimeBinderContext (ctx, callingContext), binder.ResolveOptions); + rc.DefaultObjectContext = new PSCompiler.WithContext (objectContext.Context); + + return binder.Bind (rc); + } + } +} diff --git a/mcs/class/PlayScript.Core/PlayScript.Runtime/Undefined.cs b/mcs/class/PlayScript.Core/PlayScript.Runtime/Undefined.cs new file mode 100644 index 00000000000..4b6efda82e1 --- /dev/null +++ b/mcs/class/PlayScript.Core/PlayScript.Runtime/Undefined.cs @@ -0,0 +1,35 @@ +// +// Undefined.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace PlayScript.Runtime +{ + public static class Undefined + { + public static readonly object Value = new object (); + } +} \ No newline at end of file diff --git a/mcs/class/PlayScript.Core/QName.play b/mcs/class/PlayScript.Core/QName.play new file mode 100644 index 00000000000..f02cc383c8f --- /dev/null +++ b/mcs/class/PlayScript.Core/QName.play @@ -0,0 +1,61 @@ +// +// QName.play +// +// Authors: +// Marek Safar +// +// Copyright 2013 Zynga Inc. +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +package { + + public final class QName + { + private var mUri:String; + private var mLocalName:String; + + public function QName(@namespace:String=null, name:String=null) + { + mUri = uri; + mLocalName = localName; + } + + public function get localName () : String + { + return mLocalName; + } + + public function get uri () : String + { + return mUri; + } + + public function toString():String { + throw new System.NotImplementedException(); + } + + public function valueOf():Object { + throw new System.NotImplementedException(); + } + } +} diff --git a/mcs/class/PlayScript.Core/RangeError.play b/mcs/class/PlayScript.Core/RangeError.play new file mode 100644 index 00000000000..4d77e7ef3a7 --- /dev/null +++ b/mcs/class/PlayScript.Core/RangeError.play @@ -0,0 +1,45 @@ +// +// RangeError.play +// +// Authors: +// Marek Safar +// +// Copyright 2013 Zynga Inc. +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +package { + + public dynamic class RangeError extends Error { + + public function RangeError (message:String = "", id:int = 0) + { + super (message, id); + } + + internal static function CreateIndexError (index:uint, range:uint):RangeError + { + return new RangeError (System.String.Format ("The index {0} is out of range {1}.", index, range), 1125); + } + } +} + diff --git a/mcs/class/PlayScript.Core/ReferenceError.play b/mcs/class/PlayScript.Core/ReferenceError.play new file mode 100644 index 00000000000..bb2c3a3fe4c --- /dev/null +++ b/mcs/class/PlayScript.Core/ReferenceError.play @@ -0,0 +1,25 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + + public class ReferenceError extends Error { + + public function ReferenceError(message:String = "") { + super(message); + } + + } + +} diff --git a/mcs/class/PlayScript.Core/RegExp.play b/mcs/class/PlayScript.Core/RegExp.play new file mode 100644 index 00000000000..d57827cf348 --- /dev/null +++ b/mcs/class/PlayScript.Core/RegExp.play @@ -0,0 +1,164 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + import System.*; + import System.Text.RegularExpressions.*; + + public class RegExp { + + // + // Properties + // +/* + public property dotall : Boolean { + get { return mDoTail;} + } + public property extended : Boolean { + get { return mExtended;} + } + public property global : Boolean { + get { return mGlobal;} + } + public property ignoreCase : Boolean { + get { return (mRegex.Options & RegexOptions.IgnoreCase) != 0;} + } + public property lastIndex : Number { + get { throw new NotImplementedException();} + } + public property multiline : Boolean { + get { return (mRegex.Options & RegexOptions.Multiline) != 0;} + } + + public property source : String { + get { return mSource;} + } +*/ + // + // Methods + // + + public function RegExp(re:String, flags:String) { + var options:RegexOptions = RegexOptions.None; + for (var i:int=0; i < flags.Length; i++) { + switch (flags.charAt(i)) { + case "m": + options |= RegexOptions.Multiline; + break; + case "i": + options |= RegexOptions.IgnoreCase; + break; + case "g": + mGlobal = true; + break; + case "x": + mExtended = true; + break; + case "s": + mDoTail = true; + break; + default: + throw new NotImplementedException(); + } + } + + mSource = re; + mRegex = new Regex(re, options); + } + + public function exec(str:String):Object { + var m = mRegex.Match(str); + if (m.Success) { + var a:Array = []; + // a.push(m.Value); + for each (var g:Group in m.Groups) { + a.push(g.Value); + } + return a; + } else + { + return null; + } + } + + public function test(str:String):Boolean { + throw new NotImplementedException(); + } + + public function replace(str:String, replaceWith:String):String { + return mRegex.Replace(str, replaceWith); + } + + public function search(str:String):int { + var m = mRegex.Match(str); + if (!m.Success) { + return -1; + } + return m.Index; + } + + public function match(str:String):Array { + var a:Array = null; + var m = mRegex.Match(str); + while (m.Success) { + if (a == null) a = new Array(); + a.push( m.Value ); + m = m.NextMatch(); + } + return a; + } + + public function split(str:String):Array + { + var a:Array = new Array(); + + var lastIndex:int = 0; + + var m = mRegex.Match(str); + while (m.Success) { + + // get everything before the match + var before:String = str.Substring(lastIndex, m.Index - lastIndex); + + a.push(before); + + // push all matching groups + for (var i:int = 1; i < m.Groups.Count; i++) + { + a.push(m.Groups[i].Value); + } + + // set last index + lastIndex = m.Index + m.Length; + + // next match + m = m.NextMatch(); + } + + // push everything after last match + var end:String = str.Substring(lastIndex, str.Length - lastIndex); + a.push(end); + + return a; + } + + var mRegex:Regex; + var mSource:String; + var mGlobal:Boolean; + var mExtended:Boolean; + var mDoTail:Boolean; + + } + +} diff --git a/mcs/class/PlayScript.Core/SWFAttribute.cs b/mcs/class/PlayScript.Core/SWFAttribute.cs new file mode 100644 index 00000000000..c994e3b7a68 --- /dev/null +++ b/mcs/class/PlayScript.Core/SWFAttribute.cs @@ -0,0 +1,33 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; + +namespace _root +{ + [AttributeUsage(AttributeTargets.All, AllowMultiple = false)] + public class SWFAttribute : Attribute + { + public object width { get; set; } + public object height { get; set; } + public object frameRate { get; set; } + public object backgroundColor { get; set; } + public object quality {get;set;} + + public SWFAttribute () + { + } + } +} + diff --git a/mcs/class/PlayScript.Core/SecurityError.play b/mcs/class/PlayScript.Core/SecurityError.play new file mode 100644 index 00000000000..c596b30d37c --- /dev/null +++ b/mcs/class/PlayScript.Core/SecurityError.play @@ -0,0 +1,26 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + + public class SecurityError extends Error { + + public function SecurityError(message:String = "") { + super(message); + } + + } + +} + diff --git a/mcs/class/PlayScript.Core/StringExtensions.cs b/mcs/class/PlayScript.Core/StringExtensions.cs new file mode 100644 index 00000000000..d53fe81f0cd --- /dev/null +++ b/mcs/class/PlayScript.Core/StringExtensions.cs @@ -0,0 +1,186 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Text; + +namespace _root +{ + public static class StringExtensions + { + public static int get_length(this String s) { + return s.Length; + } + + public static String charAt (this String s, double index = 0) { + return s[ (int)index ].ToString(); + } + + public static int charCodeAt(this String s, double index) { + return s[(int)index]; + } + + public static String concat(this String s, params object[] args) { + foreach (object arg in args) + { + s += arg.ToString(); + } + return s; + } + + private static char objectToChar(object o) + { + if (o is int) { + return (char)(int)o; + } else if (o is uint) { + return (char)(uint)o; + } else if (o is char) { + return (char)o; + } else { + throw new NotImplementedException(); + } + } + + public static String fromCharCode (params object[] charCodes) + { + if (charCodes.Length == 1) + { + return new String(objectToChar(charCodes[0]), 1); + } + else + { + var chars = new char[charCodes.Length]; + for (int i=0; i < charCodes.Length; i++) { + chars[i] = objectToChar(charCodes[i]); + } + return new String(chars); + } + } + + public static int indexOf(this String s, String val, double startIndex = 0) { + if (s == null) return -1; + return s.IndexOf(val, (int)startIndex); + } + + public static int lastIndexOf(this String s, String val, double startIndex = 0x7FFFFFFF) { + throw new NotImplementedException(); + } + + public static int localeCompare(this String s, String other, params object[] values) { + throw new NotImplementedException(); + } + + public static Array match(this String s, object pattern) { + if (pattern is RegExp) { + // pattern is a regexp + var re = pattern as RegExp; + return re.match(s); + } else { + // pattern is a String or other object + throw new NotImplementedException(); + } + } + + public static String replace (this String s, object pattern, object repl) + { + if (pattern is RegExp) { + // pattern is a regexp + var re = pattern as RegExp; + return re.replace(s, repl.ToString()); + } else { + // pattern is a String or other object + return s.Replace(pattern.ToString (), repl.ToString()); + } + } + + public static int search(this String s, object pattern) { + if (pattern is RegExp) { + // pattern is a regexp + var re = pattern as RegExp; + return re.search(s); + } else { + // pattern is a String or other object + return s.IndexOf(pattern.ToString ()); + } + } + + public static String slice(this String s) { + throw new NotImplementedException(); + } + + public static String slice(this String s, int startIndex) { + return s.Substring(startIndex); + } + + public static String slice(this String s, int startIndex, int endIndex) { + return s.Substring(startIndex, endIndex - startIndex); + } + + public static Array split (this String s, object delimiter, int limit = 0x7fffffff) + { + if (limit != 0x7fffffff) { + throw new NotImplementedException (); + } + + if (delimiter is RegExp) { + var re = delimiter as RegExp; + return re.split(s); + } else if (delimiter is String) { + return new Array( s.Split(new String[] {(String)delimiter}, StringSplitOptions.None )); + } else { + throw new NotImplementedException (); + } + } + + public static String substr (this String s, double startIndex = 0, double len = 0x7fffffff) { + if (len == 0x7fffffff) { + return s.Substring((int)startIndex); + } else { + // TODO: should this throw or be silent if length exceeded? + return s.Substring((int)startIndex, (int)len); + } + } + + public static String substring (this String s, double startIndex = 0, double endIndex = 0x7fffffff) { + if (endIndex == 0x7fffffff) { + return s.Substring((int)startIndex); + } else { + // TODO: should this throw or be silent if length exceeded? + return s.Substring((int)startIndex, (int)endIndex - (int)startIndex); + } + } + + public static String toLocaleLowerCase(this String s) { + throw new NotImplementedException(); + } + + public static String toLocaleUpperCase(this String s) { + throw new NotImplementedException(); + } + + public static String toLowerCase(this String s) { + return s.ToLowerInvariant(); + } + + public static String toUpperCase(this String s) { + return s.ToUpperInvariant(); + } + + public static String valueOf(this String s) { + return s; + } + + } +} + diff --git a/mcs/class/PlayScript.Core/SyntaxError.play b/mcs/class/PlayScript.Core/SyntaxError.play new file mode 100644 index 00000000000..0c82410716f --- /dev/null +++ b/mcs/class/PlayScript.Core/SyntaxError.play @@ -0,0 +1,26 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + + public class SyntaxError extends Error { + + public function SyntaxError(message:String = "") { + super(message); + } + + } + +} + diff --git a/mcs/class/PlayScript.Core/TypeError.play b/mcs/class/PlayScript.Core/TypeError.play new file mode 100644 index 00000000000..c424231f548 --- /dev/null +++ b/mcs/class/PlayScript.Core/TypeError.play @@ -0,0 +1,39 @@ +// +// TypeError.play +// +// Authors: +// Marek Safar +// +// Copyright 2013 Zynga Inc. +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +package { + + public dynamic class TypeError extends Error { + + public function TypeError (message:String = "", id:int = 0) + { + super (message, id); + } + } +} diff --git a/mcs/class/PlayScript.Core/URIError.play b/mcs/class/PlayScript.Core/URIError.play new file mode 100644 index 00000000000..27c36e83b8b --- /dev/null +++ b/mcs/class/PlayScript.Core/URIError.play @@ -0,0 +1,26 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + + public class URIError extends Error { + + public function URIError(message:String = "") { + super(message); + } + + } + +} + diff --git a/mcs/class/PlayScript.Core/Vector.cs b/mcs/class/PlayScript.Core/Vector.cs new file mode 100644 index 00000000000..d28696c29f7 --- /dev/null +++ b/mcs/class/PlayScript.Core/Vector.cs @@ -0,0 +1,123 @@ +// +// Vector.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using PlayScript.Runtime.CompilerServices; + +namespace _root +{ + [DynamicClass] + public class Vector + { + readonly List list; + + public Vector (int length = 0, bool @fixed = false) + { + list = new List (length); + this.@fixed = @fixed; + } + + public Vector (params T[] values) + { + list = new List (values); + } + + private Vector (List list) + { + this.list = list; + } + + public bool @fixed { get; set; } + + public uint length { + get { + return (uint) list.Count; + } + set { + throw new NotImplementedException (); + } + } + + public Vector concat ([RestArrayParameter] Array args) + { + throw new NotImplementedException (); + } + + public Vector concat (params T[] args) + { + var res = new List (list); + res.AddRange (args); + return new Vector (res); + } + + public int indexOf (T searchElement, int fromIndex) + { + return list.IndexOf (searchElement, fromIndex); + } + + public int lastIndexOf (T searchElement, int fromIndex = 0x7fffffff) + { + return list.LastIndexOf (searchElement, fromIndex); + } + + public uint push (T value) + { + list.Add (value); + return length; + } + + public uint unshift ([RestArrayParameter] Array args) + { + throw new NotImplementedException (); + } + + public uint unshift (params T[] args) + { + list.InsertRange (0, args); + return length; + } + + internal void setValue (uint index, T value) + { + if (index < 0 || index >= length) + throw RangeError.CreateIndexError (index, length); + + list [(int) index] = value; + } + + internal T getValue (uint index) + { + if (index < 0 || index >= length) + throw RangeError.CreateIndexError (index, length); + + return list [(int) index]; + } + } +} + diff --git a/mcs/class/PlayScript.Core/VerifyError.play b/mcs/class/PlayScript.Core/VerifyError.play new file mode 100644 index 00000000000..0946ce7b32b --- /dev/null +++ b/mcs/class/PlayScript.Core/VerifyError.play @@ -0,0 +1,27 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + + public class VerifyError extends Error { + + public function VerifyError(message:String = "") { + super(message); + } + + } + +} + + diff --git a/mcs/class/PlayScript.Core/XML.play b/mcs/class/PlayScript.Core/XML.play new file mode 100644 index 00000000000..d5d16eb1be7 --- /dev/null +++ b/mcs/class/PlayScript.Core/XML.play @@ -0,0 +1,283 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + import System.*; + import System.Xml.*; + + public class XML { + + var mElement:XmlElement; + + // + // Properties + // +/* + public static property ignoreComments : Boolean { + get { throw new System.NotImplementedException(); } + set { throw new System.NotImplementedException(); } + } + + public static property ignoreProcessingInstructions : Boolean { + get { throw new System.NotImplementedException(); } + set { throw new System.NotImplementedException(); } + } + + public static property ignoreWhitespace : Boolean { + get { throw new System.NotImplementedException(); } + set { throw new System.NotImplementedException(); } + } + + public static property prettyIndent : int { + get { throw new System.NotImplementedException(); } + set { throw new System.NotImplementedException(); } + } + + public static property prettyPrinting : Boolean { + get { throw new System.NotImplementedException(); } + set { throw new System.NotImplementedException(); } + } +*/ + // + // Methods + // + + public function XML(value:Object) { +/* + if (value is XmlElement) + { + mElement = value as XmlElement; + } else if (value is flash.utils.ByteArray) + { + var ba:flash.utils.ByteArray = value as flash.utils.ByteArray; + + // read string from byte array + ba.position = 0; + var xmlString:String = ba.readAllUTF(); + + // parse xml document from string + var doc:XmlDocument = new XmlDocument(); + doc.LoadXml(xmlString); + mElement = doc.DocumentElement; + } else if (value is String) + { + // parse xml document from string + var doc:XmlDocument = new XmlDocument(); + doc.LoadXml(value as String); + mElement = doc.DocumentElement; + } + else + { + throw new System.NotImplementedException(); + } +*/ + } + + public function XML(value:XmlNode) + { + // TODO: mElement = value; + } + + public function addNamespace(ns:Object):XML { + throw new System.NotImplementedException(); + } + + public function appendChild(child:Object):XML { + throw new System.NotImplementedException(); + } + + /* + public function attribute(attributeName:String):XMLList { + throw new System.NotImplementedException(); + }*/ + + public function attribute(attributeName:String):String { + return mElement.HasAttribute(attributeName) ? mElement.GetAttribute(attributeName) : null; + } + + public function attributes():XMLList { + throw new System.NotImplementedException(); + } + + public function child(propertyName:Object):XMLList { + throw new System.NotImplementedException(); + } + + public function childIndex():int { + throw new System.NotImplementedException(); + } + + public function children():XMLList { + throw new System.NotImplementedException(); + } + + public function comments():XMLList { + throw new System.NotImplementedException(); + } + + public function contains(value:XML):Boolean { + throw new System.NotImplementedException(); + } + + public function copy():XML { + throw new System.NotImplementedException(); + } + + public static function defaultSettings():Object { + throw new System.NotImplementedException(); + } + + public function descendants():XMLList { + throw new System.NotImplementedException(); + } + + public function descendants(name:Object):XMLList { + throw new System.NotImplementedException(); + } + + public function elements():XMLList { + return new XMLList(mElement.GetElementsByTagName("*")); + } + + public function elements(name:String):XMLList { + return new XMLList(mElement.GetElementsByTagName(name)); + } + + public function hasComplexContent():Boolean { + throw new System.NotImplementedException(); + } + + public function hasOwnProperty(p:String):Boolean { + throw new System.NotImplementedException(); + } + + public function hasSimpleContent():Boolean { + throw new System.NotImplementedException(); + } + + public function inScopeNamespaces():Array { + throw new System.NotImplementedException(); + } + + public function insertChildAfter(child1:Object, child2:Object):* { + throw new System.NotImplementedException(); + } + + public function insertChildBefore(child1:Object, child2:Object):* { + throw new System.NotImplementedException(); + } + + public function length():int { + throw new System.NotImplementedException(); + } + + public function localName():String { + return mElement.LocalName; + } + + public function name():QName { + return new QName(mElement.NamespaceURI, mElement.Name); + } + + public function @namespace(prefix:String = null):* { + throw new System.NotImplementedException(); + } + + public function namespaceDeclarations():Array { + throw new System.NotImplementedException(); + } + + public function nodeKind():String { + throw new System.NotImplementedException(); + } + + public function normalize():XML { + throw new System.NotImplementedException(); + } + + public function parent():* { + throw new System.NotImplementedException(); + } + + public function prependChild(value:Object):XML { + throw new System.NotImplementedException(); + } + + public function processingInstructions(name:String):XMLList { + throw new System.NotImplementedException(); + } + + public function propertyIsEnumerable(p:String):Boolean { + throw new System.NotImplementedException(); + } + + public function removeNamespace(ns:Namespace):XML { + throw new System.NotImplementedException(); + } + + public function replace(propertyName:Object, value:XML):XML { + throw new System.NotImplementedException(); + } + + public function setChildren(value:Object):XML { + throw new System.NotImplementedException(); + } + + public function setLocalName(name:String):void { + throw new System.NotImplementedException(); + } + + public function setName(name:String):void { + throw new System.NotImplementedException(); + } + + public function setNamespace(ns:Namespace):void { + throw new System.NotImplementedException(); + } + + public function setSettings(... rest):void { + throw new System.NotImplementedException(); + } + + public function settings():Object { + throw new System.NotImplementedException(); + } + + public function text():XMLList { + throw new System.NotImplementedException(); + } + + public function toJSON(k:String):* { + throw new System.NotImplementedException(); + } + + public function toString():String { + throw new System.NotImplementedException(); + } + + public function toXMLString():String { + throw new System.NotImplementedException(); + } + + public function valueOf():Object { + throw new System.NotImplementedException(); + } +/* + public static implicit operator String (xml:XML) { + throw new System.NotImplementedException(); + } +*/ + } + +} diff --git a/mcs/class/PlayScript.Core/XMLList.play b/mcs/class/PlayScript.Core/XMLList.play new file mode 100644 index 00000000000..47e0b920c1c --- /dev/null +++ b/mcs/class/PlayScript.Core/XMLList.play @@ -0,0 +1,180 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + + public /*final*/ dynamic class XMLList + { + public function XMLList (value:*=null) + { + + } + } +/* + import System.Xml.*; + import System.Collections.*; + import System.Collections.Generic.*; + import System.Linq.*; + + public class XMLList implements IEnumerable. { + + var mList:List. = new List.(); + + // + // Methods + // + + public function XMLList(value:Object) { + if (value == null) { + // empty + } + else { + throw new System.NotImplementedException(); + } + } + + internal function XMLList(value:XmlNodeList) + { + // create list of XML from node list + + for each ( var node:XmlNode in value) { + if (node is XmlElement) { + mList.Add(new XML(node)); + } + } + } + + internal function XMLList () + { + } + + public function attribute(attributeName:String):String { + if (mList.Count != 1) + throw new System.NotImplementedException(); + + return mList[0].attribute(attributeName); + } + + public function attributes():XMLList { + throw new System.NotImplementedException(); + } + + public function child(propertyName:Object):XMLList { + throw new System.NotImplementedException(); + } + + public function children():XMLList { + throw new System.NotImplementedException(); + } + + public function comments():XMLList { + throw new System.NotImplementedException(); + } + + public function contains(value:XML):Boolean { + throw new System.NotImplementedException(); + } + + public function copy():XMLList { + throw new System.NotImplementedException(); + } + + public function descendants():XMLList { + throw new System.NotImplementedException(); + } + + public function descendants(name:Object):XMLList { + throw new System.NotImplementedException(); + } + + public function elements():XMLList { + throw new System.NotImplementedException(); + } + + public function elements(name:String):XMLList { + if (mList.Count == 0) + return new XMLList(); + + if (mList.Count != 1) + throw new System.NotImplementedException(); + + return mList[0].elements(name); + } + + public function hasComplexContent():Boolean { + throw new System.NotImplementedException(); + } + + public function hasOwnProperty(p:String):Boolean { + throw new System.NotImplementedException(); + } + + public function hasSimpleContent():Boolean { + throw new System.NotImplementedException(); + } + + public function length():int { + throw new System.NotImplementedException(); + } + + public function normalize():XMLList { + throw new System.NotImplementedException(); + } + + public function parent():Object { + throw new System.NotImplementedException(); + } + + public function processingInstructions(name:String = "*"):XMLList { + throw new System.NotImplementedException(); + } + + public function propertyIsEnumerable(p:String):Boolean { + throw new System.NotImplementedException(); + } + + public function text():XMLList { + throw new System.NotImplementedException(); + } + + public function toString():String { + throw new System.NotImplementedException(); + } + + public function toXMLString():String { + throw new System.NotImplementedException(); + } + + public function valueOf():Object { + throw new System.NotImplementedException(); + } + + public indexer this(index:int):XML { + get { throw new System.NotImplementedException(); } + } + + public static implicit operator String (list:XMLList) { + throw new System.NotImplementedException(); + } + + function IEnumerable..GetEnumerator() : IEnumerator. { + return mList.GetEnumerator(); + } + + function IEnumerable.GetEnumerator() : IEnumerator { + return mList.GetEnumerator(); + } + } +*/ +} diff --git a/mcs/class/PlayScript.Core/functions.cs b/mcs/class/PlayScript.Core/functions.cs new file mode 100644 index 00000000000..a528d125bea --- /dev/null +++ b/mcs/class/PlayScript.Core/functions.cs @@ -0,0 +1,148 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; + +namespace _root +{ + + // + // Conversions (must be in C# to avoid conflicts). + // + + public static class String_fn + { + public static string String (object o) + { + return o.ToString(); + } + + public static string String (string s) + { + return s; + } + + public static string String (int i) + { + return i.ToString (); + } + + public static string String (uint u) + { + return u.ToString (); + } + + public static string String (double d) + { + return d.ToString (); + } + + public static string String (bool b) + { + return b.ToString (); + } + + } + + public static class Number_fn + { + // Inlineable method + public static double Number (string s) + { + double d; + double.TryParse(s, out d); + return d; + } + + } + + public static class int_fn + { + // Inlineable method + public static int @int (string s) + { + int i; + int.TryParse(s, out i); + return i; + } + + } + + public static class uint_fn + { + + // Inlineable method + public static uint @uint (string s) + { + uint u; + uint.TryParse(s, out u); + return u; + } + + } + + public static class Boolean_fn + { + + // Not inlinable.. but required to get correct results in flash. + public static bool Boolean (object d) + { + if (d == null) return false; + + TypeCode tc = Type.GetTypeCode(d.GetType()); + switch (tc) { + case TypeCode.Boolean: + return (bool)d; + case TypeCode.SByte: + return (sbyte)d != 0; + case TypeCode.Byte: + return (byte)d != 0; + case TypeCode.Int16: + return (short)d != 0; + case TypeCode.UInt16: + return (ushort)d != 0; + case TypeCode.Int32: + return (int)d != 0; + case TypeCode.UInt32: + return (uint)d != 0; + case TypeCode.Int64: + return (long)d != 0; + case TypeCode.UInt64: + return (ulong)d != 0; + case TypeCode.Single: + return (float)d != 0.0f; + case TypeCode.Double: + return (double)d != 0.0; + case TypeCode.Decimal: + return (decimal)d != 0; + case TypeCode.String: + var s = (string)d; + return !string.IsNullOrEmpty(s) && s != "0" && s != "false"; + case TypeCode.Empty: + return false; + case TypeCode.Object: + return d != null; + } + return false; + } + + // Inlineable method + public static bool Boolean (string s) + { + throw new System.NotImplementedException(); + } + + } +} + diff --git a/mcs/class/PlayScript.Core/int.cs b/mcs/class/PlayScript.Core/int.cs new file mode 100644 index 00000000000..cf003dc274d --- /dev/null +++ b/mcs/class/PlayScript.Core/int.cs @@ -0,0 +1,65 @@ +// Copyright 2013 Zynga Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; + +namespace _root +{ + public static class @int + { + // + // Methods + // + + public static string toExponential(this int i, uint fractionDigits) { + throw new NotImplementedException(); + } + + public static string toFixed(this int i, uint fractionDigits) { + throw new NotImplementedException(); + } + + public static string toPrecision(this int i, uint precision) { + throw new NotImplementedException(); + } + + public static string toString(this int i) { + throw new NotImplementedException(); + } + + public static string toString(this int i, uint radix) { + return Convert.ToString(i, (int)radix); + } + + public static int valueOf(this int i) { + return i; + } + + // + // Constants + // + + public const int MAX_VALUE = 2147483647; + + public const int MIN_VALUE = -2147483648; + + } + + public static class @uint + { + public const uint MAX_VALUE = System.UInt32.MaxValue; + public const uint MIN_VALUE = System.UInt32.MinValue; + } +} + diff --git a/mcs/class/PlayScript.Core/toplevel.play b/mcs/class/PlayScript.Core/toplevel.play new file mode 100644 index 00000000000..7fd230fb110 --- /dev/null +++ b/mcs/class/PlayScript.Core/toplevel.play @@ -0,0 +1,123 @@ +// +// toplevel.play +// +// Authors: +// Marek Safar +// +// Copyright 2013 Zynga Inc. +// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + + public function isA(obj:*, cl:Class):Boolean { + throw new System.NotImplementedException(); + } + + public function decodeURI(uri:String):String { + throw new System.NotImplementedException(); + } + + public function decodeURIComponent(uri:String):String { + throw new System.NotImplementedException(); + } + + public function encodeURI(uri:String):String { + throw new System.NotImplementedException(); + } + + public function encodeURIComponent(uri:String):String { + throw new System.NotImplementedException(); + } + + public function escape(str:String):String { + throw new System.NotImplementedException(); + } + + public function isFinite(num:Number):Boolean { + throw new System.NotImplementedException(); + } + + public function isNaN (num:Number = NaN):Boolean + { + return System.Double.IsNaN (num); + } + + public function isXMLName(str:String):Boolean { + throw new System.NotImplementedException(); + } + + public function parseFloat(str:String):Number { + if (!System.String.IsNullOrEmpty(str)) + { + return System.Double.Parse(str); + } else { + return System.Double.NaN; + } + } + + public function trace(o:System.Object):void { +// System.Diagnostics.Debug.WriteLine(o); + System.Console.WriteLine(o); + } + + public function trace(o1:System.Object, o2:System.Object):void { +// System.Diagnostics.Debug.WriteLine("{0}{1}", o1, o2); + System.Console.WriteLine("{0} {1}", o1, o2); + } + + public function trace(o1:System.Object, o2:System.Object, o3:System.Object):void { +// System.Diagnostics.Debug.WriteLine("{0}{1}{2}", o1, o2, o3); + System.Console.WriteLine("{0} {1} {2}", o1, o2, o3); + } + + public function trace(o1:System.Object, o2:System.Object, o3:System.Object, ...args):void { + var argsStr = System.String.Concat(args); +// System.Diagnostics.Debug.WriteLine("{0}{1}{2}{3}", o1, o2, o3, argsStr); + System.Console.WriteLine("{0} {1} {2} {3}", o1, o2, o3, argsStr); + } + + public function parseInt(str:String, radix:uint = 0):int { + if (radix != 0 && radix != 10) + throw new System.NotImplementedException(); + + return System.Int32.Parse(str); + } + + public function unescape(str:String):String { + throw new System.NotImplementedException(); + } + + // + // Constants + // Non-static in AS but why not make them static + // + public static const undefined : * = PlayScript.Runtime.Undefined.Value; + public static const Infinity : Number = System.Double.PositiveInfinity; + public static const NaN : Number = System.Double.NaN; + +/* + public function loadEmbed(baseObject:Object, fieldName:String):Object + { + // pass this off to C# code + return PlayScript.Player.LoadEmbed(baseObject, fieldName); + } + + public function invokeStaticMethod(type:Class, methodName:String, args:Array):Object + { + // pass this off to C# code + return PlayScript.Player.InvokeStaticMethod(type, methodName, args); + } +*/ +} diff --git a/mcs/mcs/.gitignore b/mcs/mcs/.gitignore index 50b1dde31dc..d2ba32927b9 100644 --- a/mcs/mcs/.gitignore +++ b/mcs/mcs/.gitignore @@ -1,5 +1,5 @@ y.output -cs-parser.cs +*-parser.cs ?mcs.user ?mcs.csproj.user mcs.csproj.user diff --git a/mcs/mcs/Makefile b/mcs/mcs/Makefile index d2aa50e7a9c..82a75363f66 100644 --- a/mcs/mcs/Makefile +++ b/mcs/mcs/Makefile @@ -28,7 +28,7 @@ PROGRAM_INSTALL_DIR = $(mono_libdir)/mono/4.5 PROGRAM_COMPILE = $(BOOT_COMPILE) -BUILT_SOURCES = cs-parser.cs +BUILT_SOURCES = cs-parser.cs ps-parser.cs CLEAN_FILES += y.output diff --git a/mcs/mcs/anonymous.cs b/mcs/mcs/anonymous.cs index 66e4250e27a..7bd5a0cfe4f 100644 --- a/mcs/mcs/anonymous.cs +++ b/mcs/mcs/anonymous.cs @@ -1177,9 +1177,7 @@ public Expression Compatible (ResolveContext ec, TypeSpec type) // At this point its the first time we know the return type that is // needed for the anonymous method. We create the method here. // - - var invoke_mb = Delegate.GetInvokeMethod (delegate_type); - TypeSpec return_type = invoke_mb.ReturnType; + TypeSpec return_type = ResolveReturnType (ec, delegate_type); // // Second: the return type of the delegate must be compatible with @@ -1302,6 +1300,12 @@ protected virtual ParametersCompiled ResolveParameters (ResolveContext ec, TypeI return Parameters; } + protected virtual TypeSpec ResolveReturnType (ResolveContext rc, TypeSpec delegateType) + { + var invoke_mb = Delegate.GetInvokeMethod (delegateType); + return invoke_mb.ReturnType; + } + protected override Expression DoResolve (ResolveContext ec) { if (ec.HasSet (ResolveContext.Options.ConstantScope)) { @@ -1377,10 +1381,10 @@ AnonymousMethodBody CompatibleMethodBody (ResolveContext ec, TypeInferenceContex b = b.ConvertToAsyncTask (ec, ec.CurrentMemberDefinition.Parent.PartialContainer, p, return_type, delegate_type, loc); } - return CompatibleMethodFactory (return_type ?? InternalType.ErrorType, delegate_type, p, b); + return CompatibleMethodFactory (ec, return_type ?? InternalType.ErrorType, delegate_type, p, b); } - protected virtual AnonymousMethodBody CompatibleMethodFactory (TypeSpec return_type, TypeSpec delegate_type, ParametersCompiled p, ParametersBlock b) + protected virtual AnonymousMethodBody CompatibleMethodFactory (ResolveContext rc, TypeSpec return_type, TypeSpec delegate_type, ParametersCompiled p, ParametersBlock b) { return new AnonymousMethodBody (p, b, return_type, delegate_type, loc); } diff --git a/mcs/mcs/assign.cs b/mcs/mcs/assign.cs index 61cb8e23927..1f1dd4e00ae 100644 --- a/mcs/mcs/assign.cs +++ b/mcs/mcs/assign.cs @@ -353,7 +353,7 @@ protected override Expression DoResolve (ResolveContext ec) return null; } - if (target_type != source_type) { + if (target_type != source_type && source_type != InternalType.ErrorType) { Expression resolved = ResolveConversions (ec); if (resolved != this) @@ -392,9 +392,9 @@ public override System.Linq.Expressions.Expression MakeExpression (BuilderContex return System.Linq.Expressions.Expression.Assign (target_object, source_object); } #endif - protected virtual Expression ResolveConversions (ResolveContext ec) + protected virtual Expression ResolveConversions (ResolveContext rc) { - source = Convert.ImplicitConversionRequired (ec, source, target.Type, source.Location); + source = Convert.ImplicitConversionRequiredEnhanced (rc, source, target.Type, source.Location); if (source == null) return null; @@ -529,6 +529,7 @@ public FieldInitializerContext (IMemberContext mc, ResolveContext constructorCon : base (mc, Options.FieldInitializerScope | Options.ConstructorScope) { this.ctor_block = constructorContext.CurrentBlock.Explicit; + this.CurrentBlock = ctor_block; } public override ExplicitBlock ConstructorBlock { @@ -545,11 +546,17 @@ public override ExplicitBlock ConstructorBlock { FieldBase mc; public FieldInitializer (FieldBase mc, Expression expression, Location loc) - : base (new FieldExpr (mc.Spec, expression.Location), expression, loc) + : base (null, expression, loc) { this.mc = mc; - if (!mc.IsStatic) - ((FieldExpr)target).InstanceExpression = new CompilerGeneratedThis (mc.CurrentType, expression.Location); + } + + public bool InlineConstantInitialization { get; set; } + + public FieldBase Field { + get { + return mc; + } } public override Location StartLocation { @@ -565,13 +572,27 @@ protected override Expression DoResolve (ResolveContext ec) return null; if (resolved == null) { - var ctx = new FieldInitializerContext (mc, ec); - resolved = base.DoResolve (ctx) as ExpressionStatement; + if (target == null) { + var fe = new FieldExpr (mc.Spec, source.Location); + + if (!mc.IsStatic) + fe.InstanceExpression = new CompilerGeneratedThis (mc.CurrentType, source.Location); + + target = fe; + } + + resolved = ResolveInitializer (ec); } return resolved; } + protected virtual ExpressionStatement ResolveInitializer (ResolveContext rc) + { + var ctx = new FieldInitializerContext (mc, rc); + return base.DoResolve (ctx) as ExpressionStatement; + } + public override void EmitStatement (EmitContext ec) { if (resolved == null) @@ -588,10 +609,46 @@ public override void EmitStatement (EmitContext ec) } } - if (resolved != this) + if (resolved != this) { resolved.EmitStatement (ec); - else + } else { + if (InlineConstantInitialization) + InlineInitialization (); + base.EmitStatement (ec); + } + } + + // + // For PS only which has this weird behaviour where static + // initializer referencing another field is initialized not + // by reference but by value but only for 1st level dependency + // + void InlineInitialization () + { + var fe = ((FieldInitializer) resolved).Source as FieldExpr; + if (fe == null) + return; + + var fb = fe.Spec.MemberDefinition as FieldBase; + if (fb == null) + return; + + // TODO: Handle imported constants? + var init = ((TypeDefinition) mc.Parent).GetFieldInitializer (fb); + if (init == null) + return; + + var c = init.Source as Constant; + if (c == null) + return; + + // TODO: Probably too restrictive + if (!TypeSpecComparer.IsEqual (Field.MemberType, fb.MemberType)) + return; + + source = c; + return; } public bool IsDefaultInitializer { diff --git a/mcs/mcs/class.cs b/mcs/mcs/class.cs index d6e1e8ed2ce..0a7c44dd6d1 100644 --- a/mcs/mcs/class.cs +++ b/mcs/mcs/class.cs @@ -19,6 +19,7 @@ using System.Security.Permissions; using System.Text; using System.Diagnostics; +using System.Linq; using Mono.CompilerServices.SymbolWriter; #if NET_2_1 @@ -352,8 +353,13 @@ public override string GetSignatureForDocumentation () public override string GetSignatureForError () { - if (Parent != null && Parent.MemberName != null) - return Parent.GetSignatureForError () + "." + MemberName.GetSignatureForError (); + if (Parent != null && Parent.MemberName != null) { + var parent = Parent.GetSignatureForError (); + if (string.IsNullOrEmpty (parent)) + return MemberName.GetSignatureForError (); + + return parent + "." + MemberName.GetSignatureForError (); + } return MemberName.GetSignatureForError (); } @@ -491,8 +497,9 @@ enum CachedMethods // Holds a list of fields that have initializers protected List initialized_fields; - // Holds a list of static fields that have initializers - protected List initialized_static_fields; + // Holds a list of static initializers + // TODO: It's both Statement and ExpressionStatement + protected List static_initializers; Dictionary hoisted_base_call_proxies; @@ -682,6 +689,8 @@ public bool IsPartial { } } + public bool IsPlayScriptType { get; set; } + bool ITypeDefinition.IsTypeForwarder { get { return false; @@ -935,17 +944,22 @@ public bool IsComImport { } public virtual void RegisterFieldForInitialization (MemberCore field, FieldInitializer expression) + { + RegisterFieldForInitialization (field, expression, (field.ModFlags & Modifiers.STATIC) != 0); + } + + public void RegisterFieldForInitialization (MemberCore field, FieldInitializer expression, bool staticInitializer) { if (IsPartialPart) PartialContainer.RegisterFieldForInitialization (field, expression); - if ((field.ModFlags & Modifiers.STATIC) != 0){ - if (initialized_static_fields == null) { - HasStaticFieldInitializer = true; - initialized_static_fields = new List (4); + if (staticInitializer) { + if (static_initializers == null) { + HasStaticInitializer = true; + static_initializers = new List (); } - initialized_static_fields.Add (expression); + static_initializers.Add (expression); } else { if (initialized_fields == null) initialized_fields = new List (4); @@ -954,40 +968,91 @@ public virtual void RegisterFieldForInitialization (MemberCore field, FieldIniti } } - public void ResolveFieldInitializers (BlockContext ec) + public FieldInitializer GetFieldInitializer (MemberCore field) + { + if ((field.ModFlags & Modifiers.STATIC) != 0) { + if (static_initializers == null) + return null; + + foreach (var stmt in static_initializers) { + var fi = stmt as FieldInitializer; + if (fi == null) + continue; + + if (fi.Field == field) + return fi; + } + + return null; + } + + if (initialized_fields == null) + return null; + + return initialized_fields.Find (l => l.Field == field); + + } + + public virtual void RegisterInitialization (Statement statement, bool firstIfPossible = false) + { + if (static_initializers == null) + static_initializers = new List (); + + HasStaticInitializer = true; + if (firstIfPossible) + static_initializers.Insert (0, statement); + else + static_initializers.Add (statement); + } + + public void ResolveFieldInitializers (BlockContext bc) { Debug.Assert (!IsPartialPart); - if (ec.IsStatic) { - if (initialized_static_fields == null) + if (bc.IsStatic) { + if (static_initializers == null) return; - bool has_complex_initializer = !ec.Module.Compiler.Settings.Optimize; + bool has_complex_initializer = !bc.Module.Compiler.Settings.Optimize; int i; - ExpressionStatement [] init = new ExpressionStatement [initialized_static_fields.Count]; - for (i = 0; i < initialized_static_fields.Count; ++i) { - FieldInitializer fi = initialized_static_fields [i]; - ExpressionStatement s = fi.ResolveStatement (ec); - if (s == null) { - s = EmptyExpressionStatement.Instance; - } else if (!fi.IsSideEffectFree) { - has_complex_initializer |= true; + var init = new Statement [static_initializers.Count]; + for (i = 0; i < static_initializers.Count; ++i) { + var s = static_initializers[i]; + FieldInitializer fi = s as FieldInitializer; + Statement stmt; + + if (fi != null) { + var se = fi.ResolveStatement (bc); + if (se == null) { + stmt = new EmptyStatement (fi.Location); + } else { + stmt = new StatementExpression (se); + if (!fi.IsSideEffectFree) + has_complex_initializer |= true; + } + } else { + // It's safe to use current context no partial types support in PS + stmt = (Statement) s; + if (!stmt.Resolve (bc)) + stmt = new EmptyStatement (stmt.loc); } - init [i] = s; + init [i] = stmt; } - for (i = 0; i < initialized_static_fields.Count; ++i) { - FieldInitializer fi = initialized_static_fields [i]; - // - // Need special check to not optimize code like this - // static int a = b = 5; - // static int b = 0; - // - if (!has_complex_initializer && fi.IsDefaultInitializer) - continue; + for (i = 0; i < static_initializers.Count; ++i) { + FieldInitializer fi = static_initializers[i] as FieldInitializer; + if (fi != null) { + // + // Need special check to not optimize code like this + // static int a = b = 5; + // static int b = 0; + // + if (!has_complex_initializer && fi.IsDefaultInitializer) + continue; + } - ec.CurrentBlock.AddScopeStatement (new StatementExpression (init [i])); + bc.CurrentBlock.AddScopeStatement (init [i]); } return; @@ -998,17 +1063,17 @@ public void ResolveFieldInitializers (BlockContext ec) for (int i = 0; i < initialized_fields.Count; ++i) { FieldInitializer fi = initialized_fields [i]; - ExpressionStatement s = fi.ResolveStatement (ec); + ExpressionStatement s = fi.ResolveStatement (bc); if (s == null) continue; // // Field is re-initialized to its default value => removed // - if (fi.IsDefaultInitializer && ec.Module.Compiler.Settings.Optimize) + if (fi.IsDefaultInitializer && bc.Module.Compiler.Settings.Optimize) continue; - ec.CurrentBlock.AddScopeStatement (new StatementExpression (s)); + bc.CurrentBlock.AddScopeStatement (new StatementExpression (s)); } } @@ -1081,6 +1146,24 @@ public virtual void SetBaseTypes (List baseTypes) type_bases = baseTypes; } + public void AddBaseType (FullNamedExpression baseType) + { + if (type_bases == null) + type_bases = new List (); + + type_bases.Add (baseType); + } + + public virtual void AddBaseTypes (List baseTypes) + { + if (type_bases == null) { + type_bases = baseTypes; + return; + } + + type_bases.AddRange (baseTypes); + } + /// /// This function computes the Base class and also the /// list of interfaces that the class or struct @c implements. @@ -1242,6 +1325,11 @@ bool CreateTypeBuilder () // int type_size = Kind == MemberKind.Struct && first_nonstatic_field == null && !(this is StateMachine) ? 1 : 0; + if (IsPlayScriptType && Parent is CompilationSourceFile) { + // TODO: Package in this file could be missing + Parent = Parent.Containers.First (l => l is PlayScript.Package).Containers[0]; + } + var parent_def = Parent as TypeDefinition; if (parent_def == null) { var sb = new StringBuilder (); @@ -2199,7 +2287,7 @@ public override void CloseContainer () containers = null; initialized_fields = null; - initialized_static_fields = null; + static_initializers = null; type_bases = null; OptAttributes = null; } @@ -2451,7 +2539,7 @@ public bool HasGetHashCode { } } - public bool HasStaticFieldInitializer { + public bool HasStaticInitializer { get { return (cached_method & CachedMethods.HasStaticFieldInitializer) != 0; } @@ -2578,7 +2666,7 @@ protected override bool DoDefineMembers () public override void Emit () { - if (!has_static_constructor && HasStaticFieldInitializer) { + if (!has_static_constructor && HasStaticInitializer) { var c = DefineDefaultConstructor (true); c.Define (); } @@ -2600,22 +2688,28 @@ public override void Emit () public sealed class Class : ClassOrStruct { - const Modifiers AllowedModifiers = - Modifiers.NEW | - Modifiers.PUBLIC | - Modifiers.PROTECTED | - Modifiers.INTERNAL | - Modifiers.PRIVATE | - Modifiers.ABSTRACT | - Modifiers.SEALED | - Modifiers.STATIC | - Modifiers.UNSAFE; - - public Class (TypeContainer parent, MemberName name, Modifiers mod, Attributes attrs) + public Class (TypeContainer parent, MemberName name, Modifiers mod, Attributes attrs, bool playScriptType = false) : base (parent, name, attrs, MemberKind.Class) { + var allowed = + Modifiers.NEW | + Modifiers.PUBLIC | + Modifiers.PROTECTED | + Modifiers.INTERNAL | + Modifiers.PRIVATE | + Modifiers.ABSTRACT | + Modifiers.SEALED | + Modifiers.STATIC | + Modifiers.UNSAFE; + var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE; - this.ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod, accmods, Location, Report); + if (playScriptType) { + IsPlayScriptType = true; + allowed &= Modifiers.AccessibilityMask; + allowed |= Modifiers.DYNAMIC | Modifiers.SEALED; + } + + ModFlags = ModifiersExtensions.Check (allowed, mod, accmods, Location, Report); spec = new TypeSpec (Kind, null, this, null, ModFlags); } @@ -2721,7 +2815,13 @@ public override void Emit () if ((ModFlags & Modifiers.METHOD_EXTENSION) != 0) Module.PredefinedAttributes.Extension.EmitAttribute (TypeBuilder); - if (base_type != null && base_type.HasDynamicElement) { + if (IsPlayScriptType) { + if ((ModFlags & Modifiers.DYNAMIC) != 0) { + Module.PlayscriptAttributes.DynamicClass.EmitAttribute (TypeBuilder); + } else { + Module.PlayscriptAttributes.PlayScript.EmitAttribute (TypeBuilder); + } + } else if (base_type != null && base_type.HasDynamicElement) { Module.PredefinedAttributes.Dynamic.EmitAttribute (TypeBuilder, base_type, Location); } } @@ -3137,8 +3237,8 @@ public abstract class InterfaceMemberBase : MemberBase readonly Modifiers explicit_mod_flags; public MethodAttributes flags; - public InterfaceMemberBase (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, MemberName name, Attributes attrs) - : base (parent, type, mod, allowed_mod, Modifiers.PRIVATE, name, attrs) + public InterfaceMemberBase (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, Modifiers defaultModifiers, MemberName name, Attributes attrs) + : base (parent, type, mod, allowed_mod, defaultModifiers, name, attrs) { IsInterface = parent.Kind == MemberKind.Interface; IsExplicitImpl = (MemberName.ExplicitInterface != null); @@ -3168,27 +3268,7 @@ protected override bool CheckBase () if ((ModFlags & Modifiers.OVERRIDE) != 0) { if (base_member == null) { - if (candidate == null) { - if (this is Method && ((Method)this).ParameterInfo.IsEmpty && MemberName.Name == Destructor.MetadataName && MemberName.Arity == 0) { - Report.Error (249, Location, "Do not override `{0}'. Use destructor syntax instead", - "object.Finalize()"); - } else { - Report.Error (115, Location, "`{0}' is marked as an override but no suitable {1} found to override", - GetSignatureForError (), SimpleName.GetMemberType (this)); - } - } else { - Report.SymbolRelatedToPreviousError (candidate); - if (this is Event) - Report.Error (72, Location, "`{0}': cannot override because `{1}' is not an event", - GetSignatureForError (), TypeManager.GetFullNameSignature (candidate)); - else if (this is PropertyBase) - Report.Error (544, Location, "`{0}': cannot override because `{1}' is not a property", - GetSignatureForError (), TypeManager.GetFullNameSignature (candidate)); - else - Report.Error (505, Location, "`{0}': cannot override because `{1}' is not a method", - GetSignatureForError (), TypeManager.GetFullNameSignature (candidate)); - } - + Error_OverrideWithoutBase (candidate); return false; } @@ -3484,6 +3564,30 @@ protected void Error_CannotChangeAccessModifiers (MemberCore member, MemberSpec base_member.GetSignatureForError ()); } + protected virtual void Error_OverrideWithoutBase (MemberSpec candidate) + { + if (candidate == null) { + if (this is Method && ((Method) this).ParameterInfo.IsEmpty && MemberName.Name == Destructor.MetadataName && MemberName.Arity == 0) { + Report.Error (249, Location, "Do not override `{0}'. Use destructor syntax instead", + "object.Finalize()"); + } else { + Report.Error (115, Location, "`{0}' is marked as an override but no suitable {1} found to override", + GetSignatureForError (), SimpleName.GetMemberType (this)); + } + } else { + Report.SymbolRelatedToPreviousError (candidate); + if (this is Event) + Report.Error (72, Location, "`{0}': cannot override because `{1}' is not an event", + GetSignatureForError (), TypeManager.GetFullNameSignature (candidate)); + else if (this is PropertyBase) + Report.Error (544, Location, "`{0}': cannot override because `{1}' is not a property", + GetSignatureForError (), TypeManager.GetFullNameSignature (candidate)); + else + Report.Error (505, Location, "`{0}': cannot override because `{1}' is not a method", + GetSignatureForError (), TypeManager.GetFullNameSignature (candidate)); + } + } + protected void Error_StaticReturnType () { Report.Error (722, Location, @@ -3510,9 +3614,9 @@ public string ShortName { // // Returns full metadata method name // - public string GetFullName (MemberName name) + public override string GetFullName (MemberName name) { - return GetFullName (name.Name); + return GetFullName (base.GetFullName (name)); } public string GetFullName (string name) @@ -3578,6 +3682,9 @@ public TypeSpec MemberType { get { return member_type; } + set { + member_type = value; + } } public FullNamedExpression TypeExpression { @@ -3680,6 +3787,20 @@ protected virtual bool CheckBase () return true; } + // + // Returns full metadata method name + // + public virtual string GetFullName (MemberName name) + { + if (name.Left != null) { + StringBuilder sb = new StringBuilder (); + name.CreateMetadataName (sb); + return sb.ToString (); + } + + return name.Name; + } + public override string GetSignatureForDocumentation () { return Parent.GetSignatureForDocumentation () + "." + MemberName.Basename; @@ -3687,8 +3808,12 @@ public override string GetSignatureForDocumentation () protected virtual bool ResolveMemberType () { - if (member_type != null) + if (member_type != null) { + if (type_expr == null) + return true; + throw new InternalErrorException ("Multi-resolve"); + } member_type = type_expr.ResolveAsType (this); return member_type != null; diff --git a/mcs/mcs/const.cs b/mcs/mcs/const.cs index eef90b34603..8ae4e0a7507 100644 --- a/mcs/mcs/const.cs +++ b/mcs/mcs/const.cs @@ -9,6 +9,8 @@ // Copyright 2003-2008 Novell, Inc. // +using System; + #if STATIC using IKVM.Reflection; #else @@ -57,6 +59,7 @@ public override bool Define () Parent.MemberCache.AddMember (spec); + // TODO: I think this is too late for registration. Constant can be referenced before it's initialized if ((field_attr & FieldAttributes.InitOnly) != 0) Parent.PartialContainer.RegisterFieldForInitialization (this, new FieldInitializer (this, initializer, Location)); @@ -64,9 +67,11 @@ public override bool Define () if (declarators != null) { var t = new TypeExpression (MemberType, TypeExpression.Location); foreach (var d in declarators) { - var c = new Const (Parent, t, ModFlags & ~Modifiers.STATIC, new MemberName (d.Name.Value, d.Name.Location), OptAttributes); - c.initializer = d.Initializer; - ((ConstInitializer) c.initializer).Name = d.Name.Value; + var c = d.Field; + if (c.TypeExpression == null) + c.MemberType = member_type; + + ((ConstInitializer) c.Initializer).Name = d.Name.Value; c.Define (); Parent.PartialContainer.Members.Add (c); } @@ -120,6 +125,9 @@ public class ConstSpec : FieldSpec public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value) : base (declaringType, definition, memberType, fi, mod) { + if (value == null) + throw new ArgumentNullException ("value"); + this.value = value; } @@ -179,7 +187,7 @@ protected override Expression DoResolve (ResolveContext unused) return expr; } - protected virtual Expression DoResolveInitializer (ResolveContext rc) + Expression DoResolveInitializer (ResolveContext rc) { if (in_transit) { field.Compiler.Report.Error (110, expr.Location, diff --git a/mcs/mcs/constant.cs b/mcs/mcs/constant.cs index f51bfab6609..b3b44c6382f 100644 --- a/mcs/mcs/constant.cs +++ b/mcs/mcs/constant.cs @@ -458,6 +458,11 @@ public override System.Linq.Expressions.Expression MakeExpression (BuilderContex // It exists only as hint not to call Resolve on constants return true; } + + public override Constant ResolveAsPlayScriptConstant (ResolveContext rc) + { + return this; + } } public abstract class IntegralConstant : Constant @@ -2184,7 +2189,7 @@ public override Constant ConvertExplicitly (bool inCheckedContext, TypeSpec targ } // Exlude internal compiler types - if (targetType.Kind == MemberKind.InternalCompilerType && targetType.BuiltinType != BuiltinTypeSpec.Type.Dynamic) + if (targetType.Kind == MemberKind.InternalCompilerType && targetType.BuiltinType != BuiltinTypeSpec.Type.Dynamic && targetType.BuiltinType != BuiltinTypeSpec.Type.Object) return null; if (!IsLiteral && !Convert.ImplicitStandardConversionExists (this, targetType)) diff --git a/mcs/mcs/context.cs b/mcs/mcs/context.cs index f636ffdb0a0..c92ca63e7fe 100644 --- a/mcs/mcs/context.cs +++ b/mcs/mcs/context.cs @@ -440,6 +440,8 @@ public bool ConstantCheckState { get { return (flags & Options.ConstantCheckState) != 0; } } + public PlayScript.WithContext DefaultObjectContext { get; set; } + public bool DoFlowAnalysis { get { return (flags & Options.DoFlowAnalysis) != 0; } } @@ -457,6 +459,12 @@ public bool IsObsolete { } } + public bool IsPlayScriptType { + get { + return CurrentType.MemberDefinition.IsPlayScriptType; + } + } + public bool IsStatic { get { return MemberContext.IsStatic; diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs index 63e87ebc32c..df424cc3db1 100644 --- a/mcs/mcs/convert.cs +++ b/mcs/mcs/convert.cs @@ -227,7 +227,17 @@ public static bool ImplicitReferenceConversionExists (TypeSpec expr_type, TypeSp // // From any class-type S to any class-type T, provided S is derived from T // - return TypeSpec.IsBaseClass (expr_type, target_type, true); + if (TypeSpec.IsBaseClass (expr_type, target_type, true)) + return true; + + // PS builtin types erasure + switch (target_type.BuiltinType) { + case BuiltinTypeSpec.Type.String: + case BuiltinTypeSpec.Type.Type: + return target_type.BuiltinType == expr_type.BuiltinType; + default: + return false; + } } // @@ -336,9 +346,9 @@ public static bool ImplicitReferenceConversionExists (TypeSpec expr_type, TypeSp // from the null literal to any reference-type. // if (expr_type == InternalType.NullLiteral) { - // Exlude internal compiler types + // Exclude internal compiler types if (target_type.Kind == MemberKind.InternalCompilerType) - return target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic; + return target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || target_type.BuiltinType == BuiltinTypeSpec.Type.Object; return TypeSpec.IsReferenceType (target_type); } @@ -363,6 +373,9 @@ public static bool ImplicitReferenceConversionExists (TypeSpec expr_type, TypeSp return false; } + if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Object) + return target_type.BuiltinType == BuiltinTypeSpec.Type.Object || target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic; + break; } @@ -1347,25 +1360,35 @@ static Expression ImplicitConversionStandard (ResolveContext ec, Expression expr return null; } - if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { - switch (target_type.Kind) { - case MemberKind.ArrayType: - case MemberKind.Class: - if (target_type.BuiltinType == BuiltinTypeSpec.Type.Object) - return EmptyCast.Create (expr, target_type); + if (expr_type.BuiltinType != BuiltinTypeSpec.Type.None) { + switch (expr_type.BuiltinType) { + case BuiltinTypeSpec.Type.String: + case BuiltinTypeSpec.Type.Type: + if (expr_type.BuiltinType == target_type.BuiltinType) + return expr; - goto case MemberKind.Struct; - case MemberKind.Struct: - case MemberKind.Delegate: - case MemberKind.Enum: - case MemberKind.Interface: - case MemberKind.TypeParameter: - Arguments args = new Arguments (1); - args.Add (new Argument (expr)); - return new DynamicConversion (target_type, explicit_cast ? CSharpBinderFlags.ConvertExplicit : 0, args, loc).Resolve (ec); - } + break; - return null; + case BuiltinTypeSpec.Type.Dynamic: + switch (target_type.Kind) { + case MemberKind.ArrayType: + case MemberKind.Class: + if (target_type.BuiltinType == BuiltinTypeSpec.Type.Object) + return EmptyCast.Create (expr, target_type); + + goto case MemberKind.Struct; + case MemberKind.Struct: + case MemberKind.Delegate: + case MemberKind.Enum: + case MemberKind.Interface: + case MemberKind.TypeParameter: + Arguments args = new Arguments (1); + args.Add (new Argument (expr)); + return new DynamicConversion (target_type, explicit_cast ? CSharpBinderFlags.ConvertExplicit : 0, args, loc).Resolve (ec); + } + + return null; + } } if (target_type.IsNullableType) @@ -1452,6 +1475,18 @@ static Expression ImplicitConversionStandard (ResolveContext ec, Expression expr if (expr_type.IsStruct && TypeSpecComparer.IsEqual (expr_type, target_type)) return expr_type == target_type ? expr : EmptyCast.Create (expr, target_type); + // + // PS builtin types unification + // + switch (expr_type.BuiltinType) { + case BuiltinTypeSpec.Type.String: + case BuiltinTypeSpec.Type.Type: + if (expr_type.BuiltinType == target_type.BuiltinType) + return expr; + + break; + } + return null; } @@ -1471,6 +1506,22 @@ static public Expression ImplicitConversionRequired (ResolveContext ec, Expressi return null; } + public static Expression ImplicitConversionRequiredEnhanced (ResolveContext rc, Expression source, TypeSpec targetType, Location loc) + { + Expression e = ImplicitConversion (rc, source, targetType, loc); + if (e != null) + return e; + + if (rc.IsPlayScriptType) { + e = PlayScript.Convert.ImplicitConversion (rc, source, targetType); + if (e != null) + return e; + } + + source.Error_ValueCannotBeConverted (rc, targetType, false); + return null; + } + /// /// Performs the explicit numeric conversions /// diff --git a/mcs/mcs/cs-parser.jay b/mcs/mcs/cs-parser.jay index 2d2d60d3cf3..0097fc9d5d5 100644 --- a/mcs/mcs/cs-parser.jay +++ b/mcs/mcs/cs-parser.jay @@ -1043,7 +1043,9 @@ constant_declarator : COMMA IDENTIFIER constant_initializer { var lt = (LocatedToken) $2; - $$ = new FieldDeclarator (new SimpleMemberName (lt.Value, lt.Location), (ConstInitializer) $3); + var field = new Const (current_type, null, current_field.ModFlags, new MemberName (lt.Value, lt.Location), current_field.OptAttributes); + + $$ = new FieldDeclarator (field, new SimpleMemberName (lt.Value, lt.Location), (ConstInitializer) $3); lbag.AddLocation ($$, GetLocation ($1)); } ; @@ -1145,6 +1147,9 @@ opt_field_initializer { --lexer.parsing_block; current_field.Initializer = (Expression) $3; + current_type.RegisterFieldForInitialization (current_field, + new FieldInitializer (current_field, (Expression) $3, GetLocation ($1))); + lbag.AppendToMember (current_field, GetLocation ($1)); end_block (lexer.Location); current_local_parameters = null; @@ -1171,7 +1176,9 @@ field_declarator : COMMA IDENTIFIER { var lt = (LocatedToken) $2; - $$ = new FieldDeclarator (new SimpleMemberName (lt.Value, lt.Location), null); + var field = new Field (current_type, null, current_field.ModFlags, new MemberName (lt.Value, lt.Location), current_field.OptAttributes); + + $$ = new FieldDeclarator (field, new SimpleMemberName (lt.Value, lt.Location), null); lbag.AddLocation ($$, GetLocation ($1)); } | COMMA IDENTIFIER ASSIGN @@ -1181,9 +1188,14 @@ field_declarator variable_initializer { --lexer.parsing_block; - var lt = (LocatedToken) $2; - $$ = new FieldDeclarator (new SimpleMemberName (lt.Value, lt.Location), (Expression) $5); - lbag.AddLocation ($$, GetLocation ($1), GetLocation ($3)); + var lt = (LocatedToken) $2; + var field = new Field (current_type, null, current_field.ModFlags, new MemberName (lt.Value, lt.Location), current_field.OptAttributes); + var decl = new FieldDeclarator (field, new SimpleMemberName (lt.Value, lt.Location), (Expression) $5); + current_type.RegisterFieldForInitialization (field, + new FieldInitializer (field, (Expression) $5, GetLocation ($1))); + + lbag.AddLocation (decl, GetLocation ($1), GetLocation ($3)); + $$ = decl; } ; @@ -1206,8 +1218,10 @@ fixed_field_declarators fixed_field_declarator : COMMA IDENTIFIER fixed_field_size { - var lt = (LocatedToken) $2; - $$ = new FieldDeclarator (new SimpleMemberName (lt.Value, lt.Location), (ConstInitializer) $3); + var lt = (LocatedToken) $2; + var field = new FixedField (current_type, null, current_field.ModFlags, new MemberName (lt.Value, lt.Location), current_field.OptAttributes); + + $$ = new FieldDeclarator (field, new SimpleMemberName (lt.Value, lt.Location), (ConstInitializer) $3); lbag.AddLocation ($$, GetLocation ($1)); } ; @@ -2421,11 +2435,11 @@ opt_event_declarators event_declarators : event_declarator { - current_event_field.AddDeclarator ((FieldDeclarator) $1); + current_event_field.AddDeclarator ((EventDeclarator) $1); } | event_declarators event_declarator { - current_event_field.AddDeclarator ((FieldDeclarator) $2); + current_event_field.AddDeclarator ((EventDeclarator) $2); } ; @@ -2433,7 +2447,9 @@ event_declarator : COMMA IDENTIFIER { var lt = (LocatedToken) $2; - $$ = new FieldDeclarator (new SimpleMemberName (lt.Value, lt.Location), null); + var field = new EventField (current_type, null, current_event_field.ModFlags, new MemberName (lt.Value, lt.Location), current_event_field.OptAttributes); + + $$ = new EventDeclarator (field, new SimpleMemberName (lt.Value, lt.Location), null); lbag.AddLocation ($$, GetLocation ($1)); } | COMMA IDENTIFIER ASSIGN @@ -2444,7 +2460,9 @@ event_declarator { --lexer.parsing_block; var lt = (LocatedToken) $2; - $$ = new FieldDeclarator (new SimpleMemberName (lt.Value, lt.Location), (Expression) $5); + var field = new EventField (current_type, null, current_event_field.ModFlags, new MemberName (lt.Value, lt.Location), current_event_field.OptAttributes); + + $$ = new EventDeclarator (field, new SimpleMemberName (lt.Value, lt.Location), (Expression) $5); lbag.AddLocation ($$, GetLocation ($1), GetLocation ($3)); } ; diff --git a/mcs/mcs/decl.cs b/mcs/mcs/decl.cs index b48e147f5b6..b1c7f66f6a9 100644 --- a/mcs/mcs/decl.cs +++ b/mcs/mcs/decl.cs @@ -112,6 +112,12 @@ public string Basename { } } + public virtual string LookupName { + get { + return Name; + } + } + public void CreateMetadataName (StringBuilder sb) { if (Left != null) @@ -137,7 +143,7 @@ public string GetSignatureForDocumentation () return Left.GetSignatureForDocumentation () + "." + s; } - public string GetSignatureForError () + public virtual string GetSignatureForError () { string s = TypeParameters == null ? null : "<" + TypeParameters.GetSignatureForError () + ">"; s = Name + s; @@ -1294,4 +1300,54 @@ public interface IInterfaceMemberSpec { TypeSpec MemberType { get; } } + + class AliasMemberDefinition : IMemberDefinition + { + readonly string name; + readonly IMemberDefinition original; + + public AliasMemberDefinition (string name, IMemberDefinition original) + { + this.name = name; + this.original = original; + } + + public bool? CLSAttributeValue { + get { + return original.CLSAttributeValue; + } + } + + public string Name { + get { + return name; + } + } + + public bool IsImported { + get { + return original.IsImported; + } + } + + public string[] ConditionalConditions () + { + return original.ConditionalConditions (); + } + + public ObsoleteAttribute GetAttributeObsolete () + { + return original.GetAttributeObsolete (); + } + + public void SetIsAssigned () + { + original.SetIsAssigned (); + } + + public void SetIsUsed () + { + original.SetIsUsed (); + } + } } diff --git a/mcs/mcs/delegate.cs b/mcs/mcs/delegate.cs index afacc866e06..116afc7dfe4 100644 --- a/mcs/mcs/delegate.cs +++ b/mcs/mcs/delegate.cs @@ -804,7 +804,7 @@ protected override Expression DoResolve (ResolveContext ec) // class DelegateInvocation : ExpressionStatement { - readonly Expression InstanceExpr; + Expression InstanceExpr; Arguments arguments; MethodSpec method; @@ -834,11 +834,22 @@ protected override Expression DoResolve (ResolveContext ec) if (del_type == null) return null; + + if (del_type == ec.Module.PlayscriptTypes.Function) { + if (arguments == null) + arguments = new Arguments (1); + + arguments.Insert (0, new Argument (InstanceExpr)); + InstanceExpr = null; + method = ec.Module.PlayScriptMembers.BinderDelegateInvoke.Resolve (loc); + } else { + method = Delegate.GetInvokeMethod (del_type); + } + // // Do only core overload resolution the rest of the checks has been // done on primary expression // - method = Delegate.GetInvokeMethod (del_type); var res = new OverloadResolver (new MemberSpec[] { method }, OverloadResolver.Restrictions.DelegateInvoke, loc); var valid = res.ResolveMember (ec, ref arguments); if (valid == null && !res.BestCandidateIsDynamic) diff --git a/mcs/mcs/driver.cs b/mcs/mcs/driver.cs index 45c9719ea6a..17bc2a2444e 100644 --- a/mcs/mcs/driver.cs +++ b/mcs/mcs/driver.cs @@ -166,8 +166,13 @@ public static void Parse (SeekableStreamReader reader, SourceFile sourceFile, Mo var file = new CompilationSourceFile (module, sourceFile); module.AddTypeContainer (file); - CSharpParser parser = new CSharpParser (reader, file, report, session); - parser.parse (); + if (sourceFile.IsPlayScript) { + var parser = new PlayScript.PlayScriptParser (reader, file, report, session); + parser.parse (); + } else { + var parser = new CSharpParser (reader, file, report, session); + parser.parse (); + } } public static int Main (string[] args) diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index bb9c3cd251b..df6b68cdf51 100644 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -238,6 +238,11 @@ public virtual TypeSpec ResolveAsType (IMemberContext mc) return null; } + public virtual Constant ResolveAsPlayScriptConstant (ResolveContext rc) + { + return null; + } + public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc) { rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member); @@ -301,6 +306,13 @@ protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc return; } + if (ec.IsPlayScriptType) { + ec.Report.ErrorPlayScript (1067, loc, "Implicit coercion of a value of type `{0}' to an unrelated type `{1}'.", + from_type, to_type); + return; + } + + ec.Report.DisableReporting (); bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null; ec.Report.EnableReporting (); @@ -437,8 +449,7 @@ public Expression Resolve (ResolveContext ec, ResolveFlags flags) { if (eclass != ExprClass.Unresolved) { if ((flags & ExprClassToResolveFlags) == 0) { - Error_UnexpectedKind (ec, flags, loc); - return null; + return ResolveUnexpectedKind (ec, flags); } return this; @@ -452,8 +463,7 @@ public Expression Resolve (ResolveContext ec, ResolveFlags flags) return null; if ((flags & e.ExprClassToResolveFlags) == 0) { - e.Error_UnexpectedKind (ec, flags, loc); - return null; + return e.ResolveUnexpectedKind (ec, flags); } if (e.type == null) @@ -535,6 +545,12 @@ public Constant ResolveLabelConstant (ResolveContext rc) return c; } + protected virtual Expression ResolveUnexpectedKind (ResolveContext rc, ResolveFlags flags) + { + Error_UnexpectedKind (rc, flags, loc); + return null; + } + public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) { rc.Module.Compiler.Report.Error (182, loc, @@ -733,7 +749,8 @@ public enum MemberLookupRestrictions None = 0, InvocableOnly = 1, ExactArity = 1 << 2, - ReadAccess = 1 << 3 + ReadAccess = 1 << 3, + PlayScriptConversion = 1 << 4 } // @@ -2910,6 +2927,14 @@ public TypeExpression (TypeSpec t, Location l) loc = l; } + protected override Expression ResolveUnexpectedKind (ResolveContext rc, ResolveFlags flags) + { + if (rc.IsPlayScriptType) + return new PlayScript.ImplicitTypeOf (this, loc).Resolve (rc); + + return base.ResolveUnexpectedKind (rc, flags); + } + public sealed override TypeSpec ResolveAsType (IMemberContext ec) { return type; @@ -3211,7 +3236,7 @@ bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs) } InstanceExpression = new This (loc); - if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) { + if (this is FieldExpr && rc.CurrentBlock != null && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) { using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) { InstanceExpression = InstanceExpression.Resolve (rc); } @@ -4637,12 +4662,19 @@ int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref continue; } - if (p_mod != Parameter.Modifier.PARAMS) { - p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS); + if ((p_mod & Parameter.Modifier.VariableArgumentsMask) == 0) { + p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.VariableArgumentsMask) | + (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.VariableArgumentsMask); pt = ptypes [i]; } else if (!params_expanded_form) { params_expanded_form = true; - pt = ((ElementTypeSpec) pt).Element; + + var array = pt as ArrayContainer; + if (array != null) + pt = array.Element; + else + pt = ec.Module.PlayscriptTypes.Object; + i -= 2; continue; } @@ -4673,9 +4705,12 @@ int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref // // It can be applicable in expanded form (when not doing exact match like for delegates) // - if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) { + if (score != 0 && (p_mod & Parameter.Modifier.VariableArgumentsMask) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) { if (!params_expanded_form) { - pt = ((ElementTypeSpec) pt).Element; + if (p_mod == Parameter.Modifier.PARAMS) + pt = ((ArrayContainer) pt).Element; + else + pt = ec.Module.PlayscriptTypes.Object; } if (score > 0) @@ -4699,9 +4734,14 @@ int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref // // When params parameter has no argument it will be provided later if the method is the best candidate // - if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0) + // ActionScript has different logic for params style arguments when argument count matches. It still + // created an Array with 1 element even if argument type is convertible to array + // + if ((arg_count + 1 == pd.Count && cpd.HasParams) || + (arg_count > 0 && arg_count == param_count && pd.FixedParameters[param_count - 1].ModFlags == Parameter.Modifier.RestArray)) params_expanded_form = true; + // // Restore original arguments for dynamic binder to keep the intention of original source code // @@ -5283,18 +5323,22 @@ bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, ArrayInitializer params_initializers = null; bool has_unsafe_arg = pm.MemberType.IsPointer; int arg_count = args == null ? 0 : args.Count; + bool playscript_params = false; for (; a_idx < arg_count; a_idx++, ++a_pos) { a = args[a_idx]; - if (p_mod != Parameter.Modifier.PARAMS) { + if ((p_mod & Parameter.Modifier.VariableArgumentsMask) == 0) { p_mod = pd.FixedParameters[a_idx].ModFlags; pt = ptypes[a_idx]; has_unsafe_arg |= pt.IsPointer; - if (p_mod == Parameter.Modifier.PARAMS) { - if (chose_params_expanded) { - params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location); - pt = TypeManager.GetElementType (pt); + if (chose_params_expanded && (p_mod & Parameter.Modifier.VariableArgumentsMask) != 0) { + params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location); + if (p_mod == Parameter.Modifier.PARAMS) { + pt = ((ArrayContainer) pt).Element; + } else { + playscript_params = true; + pt = ec.Module.PlayscriptTypes.Object; } } } @@ -5393,8 +5437,14 @@ bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, args = new Arguments (1); pt = ptypes[pd.Count - 1]; - pt = TypeManager.GetElementType (pt); - has_unsafe_arg |= pt.IsPointer; + var array = pt as ArrayContainer; + if (array != null) { + pt = array.Element; + has_unsafe_arg |= pt.IsPointer; + } else { + playscript_params = true; + } + params_initializers = new ArrayInitializer (0, loc); } @@ -5402,8 +5452,13 @@ bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, // Append an array argument with all params arguments // if (params_initializers != null) { - args.Add (new Argument ( - new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec))); + Expression array_init; + if (playscript_params) + array_init = new PlayScript.ArrayCreation (params_initializers); + else + array_init = new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc); + + args.Add (new Argument (array_init.Resolve (ec))); arg_count++; } @@ -6022,7 +6077,6 @@ public override void SetTypeArguments (ResolveContext ec, TypeArguments ta) Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc); } } - // // Expression that evaluates to a Property. @@ -6030,7 +6084,7 @@ public override void SetTypeArguments (ResolveContext ec, TypeArguments ta) // This is not an LValue because we need to re-write the expression. We // can not take data from the stack and store it. // - sealed class PropertyExpr : PropertyOrIndexerExpr + public sealed class PropertyExpr : PropertyOrIndexerExpr { Arguments arguments; @@ -6289,13 +6343,22 @@ protected override Expression OverloadResolve (ResolveContext rc, Expression rig return this; } + public override Constant ResolveAsPlayScriptConstant (ResolveContext rc) + { + var prop = best_candidate.MemberDefinition as PlayScript.IConstantProperty; + if (prop != null) + return prop.Initializer.ResolveAsPlayScriptConstant (rc); + + return null; + } + public override void SetTypeArguments (ResolveContext ec, TypeArguments ta) { Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc); } } - abstract class PropertyOrIndexerExpr : MemberExpr, IDynamicAssign where T : PropertySpec + public abstract class PropertyOrIndexerExpr : MemberExpr, IDynamicAssign where T : PropertySpec { // getter and setter can be different for base calls MethodSpec getter, setter; diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index 0166d7ad5b5..3df0a0a6e18 100644 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -1339,27 +1339,32 @@ public override bool ContainsEmitWithAwait () protected override Expression DoResolve (ResolveContext ec) { - probe_type_expr = ProbeType.ResolveAsType (ec); - if (probe_type_expr == null) - return null; - expr = expr.Resolve (ec); if (expr == null) return null; + return ResolveProbeType (ec); + } + + protected virtual Expression ResolveProbeType (ResolveContext rc) + { + probe_type_expr = ProbeType.ResolveAsType (rc); + if (probe_type_expr == null) + return null; + if (probe_type_expr.IsStatic) { - ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type", + rc.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type", OperatorName); } - + if (expr.Type.IsPointer || probe_type_expr.IsPointer) { - ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type", + rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type", OperatorName); return null; } if (expr.Type == InternalType.AnonymousMethod) { - ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method", + rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method", OperatorName); return null; } @@ -1447,8 +1452,9 @@ Expression CreateConstantResult (ResolveContext ec, bool result) protected override Expression DoResolve (ResolveContext ec) { - if (base.DoResolve (ec) == null) - return null; + var pexpr = base.DoResolve (ec); + if (pexpr != this) + return pexpr; TypeSpec d = expr.Type; bool d_is_nullable = false; @@ -2281,20 +2287,24 @@ public enum Operator { LeftShift = 5 | ShiftMask, RightShift = 6 | ShiftMask, + UnsignedRightShift = 7 | ShiftMask, // PlayScript Unsigned Right Shift + + LessThan = 8 | ComparisonMask | RelationalMask, + GreaterThan = 9 | ComparisonMask | RelationalMask, + LessThanOrEqual = 10 | ComparisonMask | RelationalMask, + GreaterThanOrEqual = 11 | ComparisonMask | RelationalMask, + Equality = 12 | ComparisonMask | EqualityMask, + Inequality = 13 | ComparisonMask | EqualityMask, + StrictEquality = 14 | ComparisonMask | EqualityMask | NoUserVersion, // PlayScript Strict Equality + StrictInequality = 15 | ComparisonMask | EqualityMask | NoUserVersion, // PlayScript Strict Inequality - LessThan = 7 | ComparisonMask | RelationalMask, - GreaterThan = 8 | ComparisonMask | RelationalMask, - LessThanOrEqual = 9 | ComparisonMask | RelationalMask, - GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask, - Equality = 11 | ComparisonMask | EqualityMask, - Inequality = 12 | ComparisonMask | EqualityMask, - BitwiseAnd = 13 | BitwiseMask, - ExclusiveOr = 14 | BitwiseMask, - BitwiseOr = 15 | BitwiseMask, + BitwiseAnd = 16 | BitwiseMask, + ExclusiveOr = 17 | BitwiseMask, + BitwiseOr = 18 | BitwiseMask, - LogicalAnd = 16 | LogicalMask, - LogicalOr = 17 | LogicalMask, + LogicalAnd = 19 | LogicalMask, + LogicalOr = 20 | LogicalMask, // // Operator masks @@ -2312,6 +2322,7 @@ public enum Operator { DecomposedMask = 1 << 19, NullableMask = 1 << 20, + NoUserVersion = 1 << 21 } [Flags] @@ -2403,6 +2414,9 @@ string OperName (Operator oper) case Operator.RightShift: s = ">>"; break; + case Operator.UnsignedRightShift: + s = ">>>"; + break; case Operator.LessThan: s = "<"; break; @@ -2418,9 +2432,15 @@ string OperName (Operator oper) case Operator.Equality: s = "=="; break; + case Operator.StrictEquality: + s = "==="; + break; case Operator.Inequality: s = "!="; break; + case Operator.StrictInequality: + s = "!=="; + break; case Operator.BitwiseAnd: s = "&"; break; @@ -2513,7 +2533,7 @@ string GetOperatorExpressionTypeName () case Operator.Subtraction: return IsCompound ? "SubtractAssign" : "Subtract"; default: - throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ()); + return null; } } @@ -2642,10 +2662,12 @@ public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l break; case Operator.Equality: + case Operator.StrictEquality: opcode = OpCodes.Ceq; break; case Operator.Inequality: + case Operator.StrictInequality: ec.Emit (OpCodes.Ceq); ec.EmitInt (0); @@ -2756,9 +2778,11 @@ public Expression ResolveOperator (ResolveContext rc) return ResolveOperatorPointer (rc, l, r); // User operators - expr = ResolveUserOperator (rc, left, right); - if (expr != null) - return expr; + if ((oper & Operator.NoUserVersion) == 0) { + expr = ResolveUserOperator (rc, left, right); + if (expr != null) + return expr; + } bool lenum = l.IsEnum; @@ -2820,7 +2844,14 @@ public Expression ResolveOperator (ResolveContext rc) // Equality operators are more complicated // if ((oper & Operator.EqualityMask) != 0) { - return ResolveEquality (rc, l, r, primitives_only); + expr = ResolveEquality (rc, l, r, primitives_only); + if (primitives_only) + return expr; + + if (oper == Operator.StrictEquality || oper == Operator.StrictInequality) + return PlayScript.BinaryOperators.ResolveOperator (rc, this, left, right); + + return expr; } expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only); @@ -3336,8 +3367,15 @@ protected override Expression DoResolve (ResolveContext ec) Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig) { Expression expr = ResolveOperator (ec); - if (expr == null) + if (expr == null) { + if (ec.IsPlayScriptType) { + expr = PlayScript.BinaryOperators.ResolveOperator (ec, this, left_orig, right_orig); + if (expr != null) + return expr; + } + Error_OperatorCannotBeApplied (ec, left_orig, right_orig); + } if (left == null || right == null) throw new InternalErrorException ("Invalid conversion"); @@ -3396,6 +3434,10 @@ public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expre return SLE.Expression.RightShift (le, re); case Operator.Subtraction: return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re); + case Operator.StrictEquality: + return PlayScript.Expressions.StrictEqual (le, re); + case Operator.StrictInequality: + return PlayScript.Expressions.StrictNotEqual (le, re); default: throw new NotImplementedException (oper.ToString ()); } @@ -3798,7 +3840,7 @@ Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool prim if (TypeSpec.IsReferenceType (r)) return this; - if (r.Kind == MemberKind.InternalCompilerType) + if (r.Kind == MemberKind.InternalCompilerType && r.BuiltinType != BuiltinTypeSpec.Type.Object) return null; } @@ -3820,7 +3862,7 @@ Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool prim if (TypeSpec.IsReferenceType (l)) return this; - if (l.Kind == MemberKind.InternalCompilerType) + if (l.Kind == MemberKind.InternalCompilerType && l.BuiltinType != BuiltinTypeSpec.Type.Object) return null; } @@ -4432,6 +4474,7 @@ public override void EmitBranchable (EmitContext ec, Label target, bool on_true) switch (oper){ case Operator.Equality: + case Operator.StrictEquality: if (on_true) ec.Emit (OpCodes.Beq, target); else @@ -4439,6 +4482,7 @@ public override void EmitBranchable (EmitContext ec, Label target, bool on_true) break; case Operator.Inequality: + case Operator.StrictInequality: if (on_true) ec.Emit (OpCodes.Bne_Un, target); else @@ -4605,9 +4649,6 @@ public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args) { Arguments binder_args = new Arguments (4); - MemberAccess sle = new MemberAccess (new MemberAccess ( - new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc); - CSharpBinderFlags flags = 0; if (ec.HasSet (ResolveContext.Options.CheckedScope)) flags = CSharpBinderFlags.CheckedContext; @@ -4616,12 +4657,30 @@ public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args) flags |= CSharpBinderFlags.BinaryOperationLogical; binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ()))); - binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc))); + binder_args.Add (new Argument (CreateExpressionType (ec))); binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc))); binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc))); return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args); } + + Expression CreateExpressionType (ResolveContext rc) + { + var et = rc.Module.PredefinedTypes.ExpressionType.Resolve (); + var tname = GetOperatorExpressionTypeName (); + if (tname == null) { + switch (oper) { + case Operator.StrictEquality: + return new EnumConstant (new IntConstant (rc.BuiltinTypes, 0x80000, loc), et); + case Operator.StrictInequality: + return new EnumConstant (new IntConstant (rc.BuiltinTypes, 0x80001, loc), et); + default: + throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ()); + } + } + + return new MemberAccess (new TypeExpression (et, loc), GetOperatorExpressionTypeName (), loc); + } public override Expression CreateExpressionTree (ResolveContext ec) { @@ -5617,7 +5676,12 @@ public override void VerifyAssigned (ResolveContext rc) if (variable_info.IsAssigned (rc)) return; - rc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name); + // + // No flow-analysis for local variables in PS + // + if (!rc.IsPlayScriptType) + rc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name); + variable_info.SetAssigned (rc); } @@ -5692,6 +5756,10 @@ public override Expression DoResolveLValue (ResolveContext ec, Expression rhs) if (eclass == ExprClass.Unresolved) DoResolveBase (ec); + if (local_info.IsConstant) { + ec.Report.ErrorPlayScript (1049, loc, "Illegal assignment to a variable `{0}' specified as constant", Name); + } + return base.DoResolveLValue (ec, rhs); } @@ -6561,7 +6629,7 @@ public virtual bool Emit (EmitContext ec, IMemoryLocation target) } if (type is TypeParameterSpec) - return DoEmitTypeParameter (ec); + return DoEmitTypeParameter (ec); ec.MarkCallEntry (loc); ec.Emit (OpCodes.Newobj, method); @@ -8640,7 +8708,7 @@ public static bool IsValidDotExpression (TypeSpec type) const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum | MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType; - return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic; + return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || type.BuiltinType == BuiltinTypeSpec.Type.Object; } public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions) @@ -8656,7 +8724,7 @@ public override Expression LookupNameExpression (ResolveContext rc, MemberLookup // using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) { if (sn != null) { - expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity); + expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity | MemberLookupRestrictions.PlayScriptConversion); // // Resolve expression which does have type set as we need expression type @@ -8783,6 +8851,27 @@ public override Expression LookupNameExpression (ResolveContext rc, MemberLookup if (member_lookup != null) break; + if (expr_type.IsDynamicClass && !rc.IsRuntimeBinder) { + me = expr as MemberExpr; + if (me != null) + me.ResolveInstanceExpression (rc, null); + + // + // Run defined assigned checks on expressions resolved with + // disabled flow-analysis + // +/* + if (sn != null) { + var vr = expr as VariableReference; + if (vr != null) + vr.VerifyAssigned (rc); + } +*/ + Arguments args = new Arguments (1); + args.Add (new Argument (new StringLiteral (rc.BuiltinTypes, Name, loc))); + return new PlayScript.DynamicClassMemberAccess (expr, args, loc); + } + lookup_arity = 0; restrictions &= ~MemberLookupRestrictions.InvocableOnly; errorMode = true; @@ -9184,6 +9273,10 @@ Expression CreateAccessExpression (ResolveContext ec) return new IndexerExpr (indexers, type, this); } + if (type.IsDynamicClass) { + return new PlayScript.DynamicClassMemberAccess (this); + } + if (type != InternalType.ErrorType) { ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'", type.GetSignatureForError ()); @@ -10481,6 +10574,13 @@ protected override Expression DoResolve (ResolveContext ec) ErrorIsInaccesible (ec, member.GetSignatureForError (), loc); return null; } + + if (t.IsDynamicClass) { + Arguments args = new Arguments (1); + args.Add (new Argument (new StringLiteral (ec.BuiltinTypes, Name, loc))); + target = new PlayScript.DynamicClassMemberAccess (ec.CurrentInitializerVariable, args, loc); + return base.DoResolve (ec); + } } if (member == null) { @@ -10724,6 +10824,11 @@ protected override Expression DoResolve (ResolveContext ec) if (!is_collection_initialization) { if (element_names.Contains (element_initializer.Name)) { + if (ec.IsPlayScriptType) { + initializers.RemoveAt (i--); + continue; + } + ec.Report.Error (1912, element_initializer.Location, "An object initializer includes more than one member `{0}' initialization", element_initializer.Name); diff --git a/mcs/mcs/field.cs b/mcs/mcs/field.cs index f5603b4fae4..9abbcb7f37a 100644 --- a/mcs/mcs/field.cs +++ b/mcs/mcs/field.cs @@ -30,16 +30,22 @@ namespace Mono.CSharp { public class FieldDeclarator { - public FieldDeclarator (SimpleMemberName name, Expression initializer) + public FieldDeclarator (FieldBase field, SimpleMemberName name, Expression initializer) { this.Name = name; - this.Initializer = initializer; + this.Field = field; + this.Field.Initializer = initializer; } #region Properties + public FieldBase Field { get; private set; } public SimpleMemberName Name { get; private set; } - public Expression Initializer { get; private set; } + public Expression Initializer { + get { + return Field.Initializer; + } + } #endregion @@ -74,6 +80,12 @@ protected FieldBase (TypeDefinition parent, FullNamedExpression type, Modifiers Report.Error (681, Location, "The modifier 'abstract' is not valid on fields. Try using a property instead"); } + protected FieldBase (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, Modifiers defaultModifiers, + MemberName name, Attributes attrs) + : base (parent, type, mod, allowed_mod, defaultModifiers, name, attrs) + { + } + #region Properties public override AttributeTargets AttributeTargets { @@ -255,7 +267,8 @@ public override void Emit () Report.Error (625, Location, "`{0}': Instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute", GetSignatureForError ()); } - ConstraintChecker.Check (this, member_type, type_expr.Location); + if (type_expr != null) + ConstraintChecker.Check (this, member_type, type_expr.Location); base.Emit (); } @@ -285,7 +298,7 @@ protected override bool VerifyClsCompliance () // public class FieldSpec : MemberSpec, IInterfaceMemberSpec { - FieldInfo metaInfo; + protected FieldInfo metaInfo; TypeSpec memberType; public FieldSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo info, Modifiers modifiers) @@ -333,6 +346,14 @@ public FieldInfo GetMetaInfo () return metaInfo; } + public void SetMetaInfo (FieldInfo info) + { + if (this.metaInfo != null) + throw new InternalErrorException ("MetaInfo reset"); + + this.metaInfo = info; + } + public override MemberSpec InflateMember (TypeParameterInflator inflator) { var fs = (FieldSpec) base.InflateMember (inflator); @@ -414,9 +435,10 @@ public override bool Define () GetSignatureForError ()); } else if (declarators != null) { foreach (var d in declarators) { - var f = new FixedField (Parent, d.GetFieldTypeExpression (this), ModFlags, new MemberName (d.Name.Value, d.Name.Location), OptAttributes); - f.initializer = d.Initializer; - ((ConstInitializer) f.initializer).Name = d.Name.Value; + var f = d.Field; + f.MemberType = member_type; + + ((ConstInitializer) f.Initializer).Name = d.Name.Value; f.Define (); Parent.PartialContainer.Members.Add (f); } @@ -583,6 +605,12 @@ public Field (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Me { } + protected Field (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers amod, Modifiers defaultModifiers, + MemberName name, Attributes attrs) + : base (parent, type, mod, amod, defaultModifiers, name, attrs) + { + } + bool CanBeVolatile () { switch (MemberType.BuiltinType) { @@ -626,8 +654,9 @@ public override bool Define () required_modifier = new MetaType[] { mod.GetMetaInfo () }; } + var full_name = GetFullName (MemberName); FieldBuilder = Parent.TypeBuilder.DefineField ( - Name, member_type.GetMetaInfo (), required_modifier, null, ModifiersExtensions.FieldAttr (ModFlags)); + full_name, member_type.GetMetaInfo (), required_modifier, null, ModifiersExtensions.FieldAttr (ModFlags)); spec = new FieldSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags); @@ -636,18 +665,23 @@ public override bool Define () // need them for definitive assignment checks // if ((ModFlags & Modifiers.BACKING_FIELD) == 0 || Parent.Kind == MemberKind.Struct) { - Parent.MemberCache.AddMember (spec); + Parent.MemberCache.AddMember (spec, full_name); } - if (initializer != null) { - Parent.RegisterFieldForInitialization (this, new FieldInitializer (this, initializer, TypeExpression.Location)); + if (initializer == null && Parent.IsPlayScriptType && MemberType == Module.PlayscriptTypes.Number) { + var fi = new FieldInitializer (this, new DoubleConstant (Compiler.BuiltinTypes, double.NaN, Location.Null), Location.Null); + if (IsStatic) { + Parent.PartialContainer.RegisterInitialization (new StatementExpression (fi), true); + } else { + Parent.PartialContainer.RegisterFieldForInitialization (this, fi, false); + } } if (declarators != null) { foreach (var d in declarators) { - var f = new Field (Parent, d.GetFieldTypeExpression (this), ModFlags, new MemberName (d.Name.Value, d.Name.Location), OptAttributes); - if (d.Initializer != null) - f.initializer = d.Initializer; + var f = d.Field; + if (f.TypeExpression == null) + f.MemberType = member_type; f.Define (); Parent.PartialContainer.Members.Add (f); diff --git a/mcs/mcs/generic.cs b/mcs/mcs/generic.cs index dadcb035568..e0523fba1de 100644 --- a/mcs/mcs/generic.cs +++ b/mcs/mcs/generic.cs @@ -474,6 +474,12 @@ bool ITypeDefinition.IsPartial { } } + bool ITypeDefinition.IsPlayScriptType { + get { + return false; + } + } + public bool IsMethodTypeParameter { get { return spec.IsMethodOwned; diff --git a/mcs/mcs/ikvm.cs b/mcs/mcs/ikvm.cs index 12894a0cc75..56f2bfaa3ff 100644 --- a/mcs/mcs/ikvm.cs +++ b/mcs/mcs/ikvm.cs @@ -381,7 +381,7 @@ protected override string[] GetDefaultReferences () // For now the "default config" is harcoded into the compiler // we can move this outside later // - var default_references = new List (4); + var default_references = new List (8); default_references.Add ("System.dll"); default_references.Add ("System.Xml.dll"); @@ -389,6 +389,8 @@ protected override string[] GetDefaultReferences () if (corlib != null && corlib.GetName ().Version.Major >= 4) { default_references.Add ("Microsoft.CSharp.dll"); + + default_references.Add ("PlayScript.Core"); } return default_references.ToArray (); diff --git a/mcs/mcs/import.cs b/mcs/mcs/import.cs index 8e36932f4b9..8964c791256 100644 --- a/mcs/mcs/import.cs +++ b/mcs/mcs/import.cs @@ -6,7 +6,7 @@ // Dual licensed under the terms of the MIT X11 or GNU GPL // // Copyright 2009-2011 Novell, Inc -// Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com) +// Copyright 2011-2013 Xamarin, Inc (http://www.xamarin.com) // using System; @@ -123,6 +123,7 @@ void ReadAttribute (MetadataImporter importer) protected readonly ModuleContainer module; public static readonly string CompilerServicesNamespace = "System.Runtime.CompilerServices"; + public static readonly string PlayScriptCompilerNamespace = "PlayScript.Runtime.CompilerServices"; protected MetadataImporter (ModuleContainer module) { @@ -204,6 +205,16 @@ public FieldSpec CreateField (FieldInfo fi, TypeSpec declaringType) return new ConstSpec (declaringType, definition, field_type, fi, mod, dc); } + if (field_type == module.PlayscriptTypes.Namespace.TypeSpec) { + var attributes = CustomAttributeData.GetCustomAttributes (fi); + + var data = FindAttribute (attributes, "NamespaceFieldAttribute", PlayScriptCompilerNamespace); + if (data != null) { + string value = data.ConstructorArguments[0].Value as string; + return new PlayScript.NamespaceFieldSpec (declaringType, definition, field_type, fi, mod, value); + } + } + mod |= Modifiers.READONLY; } else { var req_mod = fi.GetRequiredCustomModifiers (); @@ -497,10 +508,15 @@ AParametersCollection CreateParameters (TypeSpec parent, ParameterInfo[] pi, Met } else { types[i] = ImportType (p.ParameterType, new DynamicTypeReader (p)); - if (i >= pi.Length - 2 && types[i] is ArrayContainer) { - if (HasAttribute (CustomAttributeData.GetCustomAttributes (p), "ParamArrayAttribute", "System")) { + if (i >= pi.Length - 2) { + var ti = types[i]; + + if (ti is ArrayContainer && HasAttribute (CustomAttributeData.GetCustomAttributes (p), "ParamArrayAttribute", "System")) { mod = Parameter.Modifier.PARAMS; is_params = true; + } else if (ti == module.PlayscriptTypes.Array.TypeSpec && HasAttribute (CustomAttributeData.GetCustomAttributes (p), "RestArrayParameterAttribute", PlayScriptCompilerNamespace)) { + mod = Parameter.Modifier.RestArray; + is_params = true; } } @@ -633,7 +649,24 @@ public PropertySpec CreateProperty (PropertyInfo pi, TypeSpec declaringType, Met } PropertySpec spec = null; - if (!param.IsEmpty) { + ImportedMemberDefinition imd = new ImportedMemberDefinition (pi, type, this); + + if (param.IsEmpty) { + if (get != null && set == null && declaringType.MemberDefinition.IsPlayScriptType) { + var attributes = CustomAttributeData.GetCustomAttributes (pi); + + var data = FindAttribute (attributes, "ConstantFieldAttribute", PlayScriptCompilerNamespace); + if (data != null) { + var pc = new PlayScript.ImportedPropertyConstant (pi, type, this); + if (data.ConstructorArguments.Count == 1) { + pc.Initializer = Constant.CreateConstantFromValue (type, + data.ConstructorArguments[0].Value, Location.Null); + } + + imd = pc; + } + } + } else { if (is_valid_property) { var index_name = declaringType.MemberDefinition.GetAttributeDefaultMember (); if (index_name == null) { @@ -672,7 +705,7 @@ public PropertySpec CreateProperty (PropertyInfo pi, TypeSpec declaringType, Met } if (spec == null) - spec = new PropertySpec (MemberKind.Property, declaringType, new ImportedMemberDefinition (pi, type, this), type, pi, mod); + spec = new PropertySpec (MemberKind.Property, declaringType, imd, type, pi, mod); if (!is_valid_property) { spec.IsNotCSharpCompatible = true; @@ -898,8 +931,21 @@ protected TypeSpec CreateType (MetaType type, TypeSpec declaringType, DynamicTyp bts.SetDefinition (definition, type, mod); } - if (spec == null) + if (spec == null) { + if (kind == MemberKind.Class && declaringType == null) { + var attributes = CustomAttributeData.GetCustomAttributes (type); + // TODO: Add assembly level attribute to speed this up? + + if (HasAttribute (attributes, "DynamicClassAttribute", PlayScriptCompilerNamespace)) { + definition.IsPlayScriptType = true; + mod |= Modifiers.DYNAMIC; + } else if (HasAttribute (attributes, "PlayScriptAttribute", PlayScriptCompilerNamespace)) { + definition.IsPlayScriptType = true; + } + } + spec = new TypeSpec (kind, declaringType, definition, type, mod); + } import_cache.Add (type, spec); @@ -988,17 +1034,22 @@ TypeParameterSpec CreateTypeParameter (MetaType type, TypeSpec declaringType) // they can be assembly specific therefore we do check based on names only // public static bool HasAttribute (IList attributesData, string attrName, string attrNamespace) + { + return FindAttribute (attributesData, attrName, attrNamespace) != null; + } + + static CustomAttributeData FindAttribute (IList attributesData, string attrName, string attrNamespace) { if (attributesData.Count == 0) - return false; + return null; foreach (var attr in attributesData) { var dt = attr.Constructor.DeclaringType; if (dt.Name == attrName && dt.Namespace == attrNamespace) - return true; + return attr; } - return false; + return null; } void ImportTypeBase (TypeSpec spec, MetaType type) @@ -1012,6 +1063,9 @@ void ImportTypeBase (TypeSpec spec, MetaType type) else base_type = CreateType (type.BaseType); + if (base_type == null && spec.MemberDefinition.IsPlayScriptType) + base_type = module.PlayscriptTypes.Object; + spec.BaseType = base_type; } @@ -1034,7 +1088,7 @@ protected void ImportTypes (MetaType[] types, Namespace targetNamespace, bool im if (t.MemberType == MemberTypes.NestedType) continue; - if (t.Name[0] == '<') + if (t.Name[0] == '<' && (t.Attributes & TypeAttributes.Public) == 0) continue; var it = CreateType (t, null, new DynamicTypeReader (t), true); @@ -1797,6 +1851,8 @@ bool ITypeDefinition.IsTypeForwarder { } } + public bool IsPlayScriptType { get; set; } + public override string Name { get { if (name == null) { @@ -2230,6 +2286,12 @@ bool ITypeDefinition.IsTypeForwarder { } } + bool ITypeDefinition.IsPlayScriptType { + get { + return false; + } + } + public string Namespace { get { return null; diff --git a/mcs/mcs/lambda.cs b/mcs/mcs/lambda.cs index 7868c6a2c9d..ce9961b066a 100644 --- a/mcs/mcs/lambda.cs +++ b/mcs/mcs/lambda.cs @@ -103,7 +103,7 @@ protected override ParametersCompiled ResolveParameters (ResolveContext ec, Type return Parameters; } - protected override AnonymousMethodBody CompatibleMethodFactory (TypeSpec returnType, TypeSpec delegateType, ParametersCompiled p, ParametersBlock b) + protected override AnonymousMethodBody CompatibleMethodFactory (ResolveContext rc, TypeSpec returnType, TypeSpec delegateType, ParametersCompiled p, ParametersBlock b) { return new LambdaMethod (p, b, returnType, delegateType, loc); } diff --git a/mcs/mcs/literal.cs b/mcs/mcs/literal.cs index 1af2d0c9e37..31de3d608f4 100644 --- a/mcs/mcs/literal.cs +++ b/mcs/mcs/literal.cs @@ -329,5 +329,13 @@ public override object Accept (StructuralVisitor visitor) { return visitor.Visit (this); } + + public override Constant ConvertImplicitly (TypeSpec type) + { + if (this.type.BuiltinType == type.BuiltinType) + return this; + + return base.ConvertImplicitly (type); + } } } diff --git a/mcs/mcs/location.cs b/mcs/mcs/location.cs index 10afaa1cc26..0e0d2da2989 100644 --- a/mcs/mcs/location.cs +++ b/mcs/mcs/location.cs @@ -18,6 +18,12 @@ namespace Mono.CSharp { + public enum SourceFileType + { + CSharp = 0, + PlayScript + } + // // This is one single source file. // @@ -58,6 +64,7 @@ public override string ToString () public readonly string FullPathName; public readonly int Index; public bool AutoGenerated; + readonly SourceFileType FileType; SourceFileEntry file; byte[] algGuid, checksum; @@ -68,6 +75,9 @@ public SourceFile (string name, string path, int index) this.Index = index; this.Name = name; this.FullPathName = path; + + if (name.EndsWith (".play", StringComparison.Ordinal) || name.EndsWith (".as", StringComparison.Ordinal)) + FileType = SourceFileType.PlayScript; } public byte[] Checksum { @@ -82,6 +92,12 @@ public bool HasChecksum { } } + public bool IsPlayScript { + get { + return FileType == SourceFileType.PlayScript; + } + } + public SourceFileEntry SourceFileEntry { get { return file; diff --git a/mcs/mcs/mcs.csproj b/mcs/mcs/mcs.csproj index 3c7ae4027b6..06b3ba36d08 100644 --- a/mcs/mcs/mcs.csproj +++ b/mcs/mcs/mcs.csproj @@ -139,7 +139,10 @@ + + + diff --git a/mcs/mcs/mcs.exe.sources b/mcs/mcs/mcs.exe.sources index dec804804cb..c88502f8d9c 100644 --- a/mcs/mcs/mcs.exe.sources +++ b/mcs/mcs/mcs.exe.sources @@ -6,6 +6,7 @@ assembly.cs async.cs attribute.cs cs-tokenizer.cs +ps-tokenizer.cs cfold.cs class.cs codegen.cs @@ -40,6 +41,7 @@ namespace.cs nullable.cs parameter.cs pending.cs +playscript.cs property.cs reflection.cs report.cs diff --git a/mcs/mcs/membercache.cs b/mcs/mcs/membercache.cs index 841ad5dc31b..e553bd1ebda 100644 --- a/mcs/mcs/membercache.cs +++ b/mcs/mcs/membercache.cs @@ -187,9 +187,16 @@ public MemberCache (int capacity) member_hash = new Dictionary> (capacity); } - public MemberCache (MemberCache cache) - : this (cache.member_hash.Count) + public MemberCache (MemberCache cache, bool copyMembers = false) { + var mh = cache.member_hash; + + if (copyMembers) { + member_hash = new Dictionary> (mh); + } else { + member_hash = new Dictionary> (mh.Count); + } + this.state = cache.state; } @@ -280,7 +287,7 @@ public void AddMember (InterfaceMemberBase imb, string exlicitName, MemberSpec m { // Explicit names cannot be looked-up but can be used for // collision checking (no name mangling needed) - if (imb.IsExplicitImpl) + if (imb.IsExplicitImpl || imb.MemberName.Left != null) AddMember (exlicitName, ms, false); else AddMember (ms); @@ -294,6 +301,11 @@ public void AddMember (MemberSpec ms) AddMember (GetLookupName (ms), ms, false); } + public void AddMember (MemberSpec member, string name) + { + AddMember (name, member, false); + } + void AddMember (string name, MemberSpec member, bool removeHiddenMembers) { if (member.Kind == MemberKind.Operator) { @@ -901,7 +913,7 @@ static string GetLookupName (MemberCore mc) if (mc is Constructor) return mc.IsStatic ? Constructor.TypeConstructorName : Constructor.ConstructorName; - return mc.MemberName.Name; + return mc.MemberName.LookupName; } // diff --git a/mcs/mcs/method.cs b/mcs/mcs/method.cs index fe08a9bfbc7..3a0a2773721 100644 --- a/mcs/mcs/method.cs +++ b/mcs/mcs/method.cs @@ -47,9 +47,9 @@ public abstract class MethodCore : InterfaceMemberBase, IParametersMember protected ToplevelBlock block; protected MethodSpec spec; - public MethodCore (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, + public MethodCore (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, Modifiers defaultModifiers, MemberName name, Attributes attrs, ParametersCompiled parameters) - : base (parent, type, mod, allowed_mod, name, attrs) + : base (parent, type, mod, allowed_mod, defaultModifiers, name, attrs) { this.parameters = parameters; } @@ -535,7 +535,13 @@ public abstract class MethodOrOperator : MethodCore, IMethodData, IMethodDefinit protected MethodOrOperator (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, MemberName name, Attributes attrs, ParametersCompiled parameters) - : base (parent, type, mod, allowed_mod, name, attrs, parameters) + : base (parent, type, mod, allowed_mod, Modifiers.PRIVATE, name, attrs, parameters) + { + } + + protected MethodOrOperator (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, Modifiers defaultModifiers, MemberName name, + Attributes attrs, ParametersCompiled parameters) + : base (parent, type, mod, allowed_mod, defaultModifiers, name, attrs, parameters) { } @@ -848,9 +854,9 @@ public Method (TypeDefinition parent, FullNamedExpression return_type, Modifiers { } - protected Method (TypeDefinition parent, FullNamedExpression return_type, Modifiers mod, Modifiers amod, + protected Method (TypeDefinition parent, FullNamedExpression return_type, Modifiers mod, Modifiers amod, Modifiers defaultModifiers, MemberName name, ParametersCompiled parameters, Attributes attrs) - : base (parent, return_type, mod, amod, name, attrs, parameters) + : base (parent, return_type, mod, amod, defaultModifiers, name, attrs, parameters) { } @@ -1522,7 +1528,7 @@ public ConstructorThisInitializer (Arguments argument_list, Location l) : public class Constructor : MethodCore, IMethodData, IMethodDefinition { public ConstructorBuilder ConstructorBuilder; - public ConstructorInitializer Initializer; + public ExpressionStatement Initializer; SecurityType declarative_security; bool has_compliant_args; SourceMethodBuilder debug_builder; @@ -1545,7 +1551,12 @@ public class Constructor : MethodCore, IMethodData, IMethodDefinition public static readonly string TypeConstructorName = ".cctor"; public Constructor (TypeDefinition parent, string name, Modifiers mod, Attributes attrs, ParametersCompiled args, Location loc) - : base (parent, null, mod, AllowedModifiers, new MemberName (name, loc), attrs, args) + : this (parent, name, mod, Modifiers.PRIVATE, attrs, args, loc) + { + } + + public Constructor (TypeDefinition parent, string name, Modifiers mod, Modifiers defaultModifiers, Attributes attrs, ParametersCompiled args, Location loc) + : base (parent, null, mod, AllowedModifiers, defaultModifiers, new MemberName (name, loc), attrs, args) { } @@ -1582,9 +1593,11 @@ public bool IsDefault () if ((ModFlags & Modifiers.STATIC) != 0) return parameters.IsEmpty; - return parameters.IsEmpty && - (Initializer is ConstructorBaseInitializer) && - (Initializer.Arguments == null); + if (!parameters.IsEmpty) + return false; + + var init = Initializer as ConstructorBaseInitializer; + return init != null && init.Arguments == null; } public override void Accept (StructuralVisitor visitor) diff --git a/mcs/mcs/modifiers.cs b/mcs/mcs/modifiers.cs index f842410c7f7..2cd17770bea 100644 --- a/mcs/mcs/modifiers.cs +++ b/mcs/mcs/modifiers.cs @@ -38,7 +38,8 @@ public enum Modifiers VOLATILE = 0x1000, UNSAFE = 0x2000, ASYNC = 0x4000, - TOP = 0x8000, + DYNAMIC = 0x8000, // Playscript only + TOP = 0x10000, // // Compiler specific flags @@ -111,6 +112,8 @@ static public string Name (Modifiers i) s = "unsafe"; break; case Modifiers.ASYNC: s = "async"; break; + case Modifiers.DYNAMIC: + s = "dynamic"; break; } return s; diff --git a/mcs/mcs/module.cs b/mcs/mcs/module.cs index ceb73afc743..b2bc07ecbb1 100644 --- a/mcs/mcs/module.cs +++ b/mcs/mcs/module.cs @@ -121,12 +121,16 @@ public FieldSpec MakeStaticData (byte[] data, Location loc) readonly Dictionary alias_ns; ModuleBuilder builder; + ConstructorBuilder initializer; bool has_extenstion_method; PredefinedAttributes predefined_attributes; PredefinedTypes predefined_types; PredefinedMembers predefined_members; + PlayScript.PredefinedAttributes playscript_attributes; + PlayScript.PredefinedTypes playscript_types; + PlayScript.PredefinedMembers playscript_members; public Binary.PredefinedOperator[] OperatorsBinaryEqualityLifted; public Binary.PredefinedOperator[] OperatorsBinaryLifted; @@ -269,6 +273,24 @@ internal PredefinedTypes PredefinedTypes { } } + internal PlayScript.PredefinedAttributes PlayscriptAttributes { + get { + return playscript_attributes; + } + } + + internal PlayScript.PredefinedTypes PlayscriptTypes { + get { + return playscript_types; + } + } + + internal PlayScript.PredefinedMembers PlayScriptMembers { + get { + return playscript_members; + } + } + internal Dictionary ReferenceTypesCache { get { return reference_types; @@ -412,6 +434,18 @@ public override bool Define () return true; } + public ConstructorBuilder DefineModuleInitializer () + { +#if STATIC + if (initializer == null) + initializer = builder.__DefineModuleInitializer (MethodAttributes.Assembly); + + return initializer; +#else + throw new NotImplementedException (); +#endif + } + public override bool DefineContainer () { DefineNamespace (); @@ -449,6 +483,9 @@ public override void EmitContainer () foreach (var at in atypes.Value) at.EmitContainer (); } + + if (initializer != null) + builder.CreateGlobalFunctions (); } internal override void GenerateDocComment (DocumentationBuilder builder) @@ -563,6 +600,11 @@ public void InitializePredefinedTypes () OperatorsBinaryEqualityLifted = Binary.CreateEqualityLiftedOperatorsTable (this); OperatorsBinaryLifted = Binary.CreateStandardLiftedOperatorsTable (this); + + playscript_attributes = new PlayScript.PredefinedAttributes (this); + playscript_types = new PlayScript.PredefinedTypes (this); + playscript_types.PopulateImplicitMembers (this); + playscript_members = new PlayScript.PredefinedMembers (this); } public override bool IsClsComplianceRequired () diff --git a/mcs/mcs/namespace.cs b/mcs/mcs/namespace.cs index 4e7c58472f4..4bd49be7280 100644 --- a/mcs/mcs/namespace.cs +++ b/mcs/mcs/namespace.cs @@ -427,6 +427,24 @@ public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string nam return texpr; } + // TODO: REMOVE me + public ATypeNameExpression MakeTypeNameExpression (Location loc) + { + string[] names = Name.Split (new[] { '.' }); + + ATypeNameExpression exp = null; + for (var i = 0; i < names.Length; i++) { + var name = names[i]; + if (exp == null) { + exp = new SimpleName (name, loc); + } else { + exp = new MemberAccess (exp, name, loc); + } + } + + return exp; + } + // // Completes types with the given `prefix' // @@ -821,6 +839,9 @@ public List Usings { get { return clauses; } + protected set { + clauses = value; + } } public override string[] ValidAttributeTargets { @@ -831,7 +852,7 @@ public override string[] ValidAttributeTargets { #endregion - public void AddUsing (UsingNamespace un) + public void AddUsing (UsingNamespace un, bool forceAppend = false) // TODO: remove the change { if (DeclarationFound){ Compiler.Report.Error (1529, un.Location, "A using clause must precede all other namespace elements except extern alias declarations"); @@ -880,6 +901,10 @@ public override void AddPartial (TypeDefinition next_part) public override void AddTypeContainer (TypeContainer tc) { string name = tc.Basename; + if (name == null) { + containers.Add (tc); + return; + } var mn = tc.MemberName; while (mn.Left != null) { diff --git a/mcs/mcs/parameter.cs b/mcs/mcs/parameter.cs index fb940b4c226..2d88536ed9e 100644 --- a/mcs/mcs/parameter.cs +++ b/mcs/mcs/parameter.cs @@ -216,10 +216,12 @@ public enum Modifier : byte { CallerMemberName = 1 << 4, CallerLineNumber = 1 << 5, CallerFilePath = 1 << 6, + RestArray = 1 << 7, RefOutMask = REF | OUT, - ModifierMask = PARAMS | REF | OUT | This, - CallerMask = CallerMemberName | CallerLineNumber | CallerFilePath + ModifierMask = PARAMS | REF | OUT | This | RestArray, + CallerMask = CallerMemberName | CallerLineNumber | CallerFilePath, + VariableArgumentsMask = PARAMS | RestArray } static readonly string[] attribute_targets = new string[] { "param" }; @@ -303,6 +305,9 @@ public FullNamedExpression TypeExpression { get { return texpr; } + protected set { + texpr = value; + } } public override string[] ValidAttributeTargets { @@ -604,6 +609,8 @@ public static string GetModifierSignature (Modifier mod) return "ref"; case Modifier.This: return "this"; + case Modifier.RestArray: + return "..."; default: return ""; } @@ -1066,7 +1073,7 @@ public ParametersCompiled (params Parameter[] parameters) int count = parameters.Length; for (int i = 0; i < count; i++){ - has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0; + has_params |= (parameters [i].ModFlags & Parameter.Modifier.VariableArgumentsMask) != 0; } } @@ -1328,35 +1335,49 @@ public ParametersCompiled Clone () // public class DefaultParameterValueExpression : CompositeExpression { + bool resolved; + public DefaultParameterValueExpression (Expression expr) : base (expr) { } - protected override Expression DoResolve (ResolveContext rc) - { - return base.DoResolve (rc); - } - public void Resolve (ResolveContext rc, Parameter p) { + if (resolved) + return; + + resolved = true; + var expr = Resolve (rc); if (expr == null) return; expr = Child; - if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsDefaultStruct))) { - rc.Report.Error (1736, Location, - "The expression being assigned to optional parameter `{0}' must be a constant or default value", - p.Name); + if (!(expr is Constant || (expr is New && ((New) expr).IsDefaultStruct))) { + if (rc.IsPlayScriptType) { + expr = expr.ResolveAsPlayScriptConstant (rc); + if (expr == null) { + rc.Report.ErrorPlayScript (1047, Location, + "Parameter initializer is not a compile-time constant."); - return; + return; + } + } else if (!(expr is DefaultValueExpression)) { + rc.Report.Error (1736, Location, + "The expression being assigned to optional parameter `{0}' must be a constant or default value", + p.Name); + + return; + } } var parameter_type = p.Type; - if (type == parameter_type) + if (type == parameter_type) { + this.expr = expr; return; + } var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location); if (res != null) { diff --git a/mcs/mcs/playscript.cs b/mcs/mcs/playscript.cs new file mode 100644 index 00000000000..f8778787e88 --- /dev/null +++ b/mcs/mcs/playscript.cs @@ -0,0 +1,3172 @@ +// +// playscript.cs: PlayScript expressions and support +// +// Authors: Marek Safar (marek.safar@gmail.com) +// +// Dual licensed under the terms of the MIT X11 or Apache License, Version 2.0 +// +// Copyright 2013 Zynga Inc. +// Copyright 2013 Xamarin Inc +// + +using System; +using System.Collections.Generic; +using Mono.CSharp; +using SLE = System.Linq.Expressions; + +#if STATIC +using IKVM.Reflection; +using IKVM.Reflection.Emit; +#else +using System.Reflection; +using System.Reflection.Emit; +#endif + +namespace Mono.PlayScript +{ + public abstract class PlayScriptExpression : Expression + { + public override Expression CreateExpressionTree (ResolveContext ec) + { + throw new NotImplementedException ("Expression trees conversion not implemented in PlayScript"); + } + } + + static class ExpressionExtension + { + public static TypeSpec TryToResolveAsType (this Expression expr, IMemberContext mc) + { + // + // TODO: Don't have probing type resolver yet + // + var errors_printer = new SessionReportPrinter (); + var old = mc.Module.Compiler.Report.SetPrinter (errors_printer); + TypeSpec t; + + try { + t = expr.ResolveAsType (mc); + } finally { + mc.Module.Compiler.Report.SetPrinter (old); + } + + if (t != null && errors_printer.ErrorsCount == 0) + return t; + + return null; + } + } + + public class ExpressionSeries : PlayScriptExpression + { + public ExpressionSeries (List expressions, Location loc) + { + Expressions = expressions; + this.loc = loc; + } + + public List Expressions { get; private set; } + + protected override Expression DoResolve (ResolveContext rc) + { + int i; + for (i = 0; i < Expressions.Count; ++i) { + Expressions[i] = Expressions[i].Resolve (rc); + } + + --i; + type = Expressions[i].Type; + eclass = Expressions[i].eclass; + return this; + } + + public override void Emit (EmitContext ec) + { + int i; + for (i = 0; i < Expressions.Count - 1; ++i) { + var expr = Expressions [i]; + if (expr.IsSideEffectFree) + continue; + + var expr_stmt = expr as ExpressionStatement; + if (expr_stmt != null) { + expr_stmt.EmitStatement (ec); + continue; + } + + expr.Emit (ec); + ec.Emit (OpCodes.Pop); + } + + Expressions[i].Emit (ec); + } + } + + public abstract class CollectionInitialization : PlayScriptExpression + { + protected Expression ctor; + protected TemporaryVariableReference instance; + protected List inserts; + + protected CollectionInitialization (ArrayInitializer initializer) + { + this.Initializer = initializer; + loc = Initializer.Location; + } + + public ArrayInitializer Initializer { get; private set; } + + protected List ResolveInitializations (ResolveContext rc, Expression instance, MethodSpec pushMethod) + { + List all = new List (Initializer.Count); + foreach (var expr in Initializer.Elements) { + + var call_args = new Arguments (1); + call_args.Add (new Argument (expr)); + + var mg = MethodGroupExpr.CreatePredefined (pushMethod, rc.CurrentType, loc); + mg.InstanceExpression = instance; + + var inv = new Invocation (mg, call_args); + inv.Resolve (rc); + + all.Add (inv); + } + + return all; + } + + public override void Emit (EmitContext ec) + { + if (instance != null) { + instance.EmitAssign (ec, ctor); + foreach (var insert in inserts) + insert.EmitStatement (ec); + + instance.EmitLoad (ec); + } else { + ctor.Emit (ec); + } + } + } + + public class ArrayCreation : CollectionInitialization + { + public ArrayCreation (ArrayInitializer initializer) + : base (initializer) + { + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = rc.Module.PlayscriptTypes.Array.Resolve (); + if (type == null) + return null; + + var count = Initializer.Elements == null ? 0 : Initializer.Count; + + var ctor_args = new Arguments (1); + ctor_args.Add (new Argument (new IntLiteral (rc.BuiltinTypes, count, loc))); + + ctor = new New (new TypeExpression (type, loc), ctor_args, loc).Resolve (rc); + + if (count != 0) { + instance = TemporaryVariableReference.Create (type, rc.CurrentBlock, loc); + + var push = rc.Module.PlayScriptMembers.ArrayPush.Resolve (loc); + if (push == null) + return null; + + inserts = ResolveInitializations (rc, instance, push); + } + + eclass = ExprClass.Value; + return this; + } + + + public override object Accept (StructuralVisitor visitor) + { + return visitor.Visit (this); + } + } + + class BinaryOperators + { + public static Expression ResolveOperator (ResolveContext rc, Binary op, Expression left, Expression right) + { + string method = "Comparison"; + string oper; + switch (op.Oper) { + case Binary.Operator.Equality: + oper = "Equality"; + break; + case Binary.Operator.Inequality: + oper = "Inequality"; + break; + case Binary.Operator.GreaterThan: + oper = "GreaterThan"; + break; + case Binary.Operator.GreaterThanOrEqual: + oper = "GreaterThanOrEqual"; + break; + case Binary.Operator.LessThan: + oper = "LessThan"; + break; + case Binary.Operator.LessThanOrEqual: + oper = "LessThanOrEqual"; + break; + case Binary.Operator.StrictEquality: + oper = "StrictEquality"; + break; + case Binary.Operator.StrictInequality: + oper = "StrictInequality"; + break; + default: + throw new NotImplementedException (); + } + + var loc = op.Location; + + var ps = new MemberAccess (new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "PlayScript", loc), "Runtime", loc); + + var args = new Arguments (3); + args.Add (new Argument (new MemberAccess (new MemberAccess (ps, "BinaryOperator", loc), oper, loc))); + args.Add (new Argument (left)); + args.Add (new Argument (right)); + + + // + // ActionScript does not really care about types for this for example following cases are all valid + // 1.0 == 1 + // "3" > null + // We defer to runtime to do the complex coercion + // + return new Invocation (new MemberAccess (new TypeExpression (rc.Module.PlayscriptTypes.Operations.Resolve (), loc), method, loc), args).Resolve (rc); + } + } + + public class New : CSharp.New + { + public New (Expression requestedType, Arguments arguments, Location loc) + : base (requestedType, arguments, loc) + { + } + + protected override Expression DoResolve (ResolveContext rc) + { + var te = RequestedType.TryToResolveAsType (rc); + if (te != null) { + return base.DoResolve (rc); + } + + var expr = RequestedType.Resolve (rc); + if (expr == null) + return null; + + if (expr.Type != rc.Module.PlayscriptTypes.Class && expr.Type != rc.Module.PlayscriptTypes.Object) { + rc.Report.ErrorPlayScript (1180, RequestedType.Location, "Call to a possibly undefined method `{0}'", expr.GetSignatureForError ()); + return null; + } + + if (arguments == null) { + arguments = new Arguments (1); + } else { + bool dynamic; + arguments.Resolve (rc, out dynamic); + } + + var ms = rc.Module.PlayScriptMembers.OperationsClassOf.Resolve (loc); + if (ms == null) + return null; + + var mg = MethodGroupExpr.CreatePredefined (ms, ms.DeclaringType, loc); + var call_args = new Arguments (1); + call_args.Add (new Argument (expr)); + + arguments.Insert (0, new Argument (new Invocation (mg, call_args).Resolve (rc), Argument.AType.DynamicTypeName)); + return new DynamicConstructorBinder (type, arguments, loc).Resolve (rc); + } + } + + public class NewVector : CollectionInitialization + { + FullNamedExpression elementType; + + public NewVector (FullNamedExpression elementType, ArrayInitializer initializer, Location loc) + : base (initializer) + { + this.elementType = elementType; + this.loc = loc; + } + + protected override Expression DoResolve (ResolveContext rc) + { + var element = elementType.ResolveAsType (rc); + type = rc.Module.PlayscriptTypes.Vector.Resolve (); + if (type == null || element == null) + return null; + + type = type.MakeGenericType (rc, new [] { element }); + + var count = Initializer.Elements == null ? 0 : Initializer.Count; + + var ctor_args = new Arguments (1); + ctor_args.Add (new Argument (new IntLiteral (rc.BuiltinTypes, count, loc))); + + ctor = new New (new TypeExpression (type, loc), ctor_args, loc).Resolve (rc); + + if (count != 0) { + instance = TemporaryVariableReference.Create (type, rc.CurrentBlock, loc); + + var push = rc.Module.PlayScriptMembers.VectorPush.Resolve (loc); + if (push == null) + return null; + + push = MemberCache.GetMember (type, push); + + inserts = ResolveInitializations (rc, instance, push); + } + + eclass = ExprClass.Value; + return this; + } + + public override object Accept (StructuralVisitor visitor) + { + return visitor.Visit (this); + } + } + + public class UntypedTypeExpression : TypeExpr + { + public UntypedTypeExpression (Location loc) + { + this.loc = loc; + } + + public override string GetSignatureForError () + { + return "*"; + } + + public override TypeSpec ResolveAsType (IMemberContext mc) + { + // + // An untyped variable is not the same as a variable of type Object. + // The key difference is that untyped variables can hold the special value + // undefined, while a variable of type Object cannot hold that value, + // any conversion is done at runtime. + // + return mc.Module.PlayscriptTypes.UndefinedType; + } + } + + public class UntypedBlockVariable : BlockVariable + { + public UntypedBlockVariable (LocalVariable li, Location loc) + : base (li, loc) + { + } + + public new FullNamedExpression TypeExpression { + get { + return type_expr; + } + set { + type_expr = value; + } + } + + public override TypeSpec ResolveType (BlockContext bc) + { + if (type_expr == null) { + if (Initializer is LocalFunction) + type_expr = new TypeExpression (bc.Module.PlayscriptTypes.Function, loc); + else + type_expr = new UntypedTypeExpression (loc); + } + + return base.ResolveType (bc); + } + } + + public class ObjectInitializer : PlayScriptExpression + { + public ObjectInitializer (List initializer, Location loc) + { + Initializer = initializer; + this.loc = loc; + } + + public List Initializer { get; private set; } + + protected override Expression DoResolve (ResolveContext rc) + { + var type = new TypeExpression (rc.Module.PlayscriptTypes.Object, loc); + + var expr = Initializer == null ? + new CSharp.New (type, null, loc) : + new NewInitialize (type, null, new CollectionOrObjectInitializers (Initializer, loc), loc); + + return expr.Resolve (rc); + } + + public override void Emit (EmitContext ec) + { + throw new NotSupportedException (); + } + + public override object Accept (StructuralVisitor visitor) + { + return visitor.Visit (this); + } + } + + public class SuperBaseInitializer : CSharp.ConstructorBaseInitializer + { + public SuperBaseInitializer (Arguments args, Location loc) + : base (args, loc) + { + } + + protected override Expression DoResolve (ResolveContext ec) + { + // TODO: PS1201: A super statement cannot occur after a this, super, return, or throw statement. + + return base.DoResolve (ec); + } + + public override object Accept (StructuralVisitor visitor) + { + return visitor.Visit (this); + } + } + + public class Catch : CSharp.Catch + { + public Catch (Block block, Location loc) + : base (block, loc) + { + } + + public override bool IsGeneral { + get { + return false; + } + } + + protected override bool ResolveType (BlockContext bc) + { + if (TypeExpression == null) { + type = bc.Module.PlayscriptTypes.Error.Resolve (); + return true; + } + + type = TypeExpression.ResolveAsType (bc); + if (type == null) + return false; + + // TODO: It's probably incorrect + if (type == bc.Module.PlayscriptTypes.UndefinedType) { + type = bc.Module.PlayscriptTypes.Error.Resolve (); + return true; + } + + if (!TypeSpec.IsBaseClass (type, bc.BuiltinTypes.Exception, false)) { + // TODO: Somehow need to wrap user type to Exception + + throw new NotImplementedException (); + } + + return true; + } + } + + public class Delete : ExpressionStatement + { + public Delete (Expression expr, Location l) + { + this.Expression = expr; + loc = l; + } + + public Expression Expression { get; private set; } + + public override Expression CreateExpressionTree (ResolveContext ec) + { + throw new NotImplementedException ("Expression trees conversion not implemented in PlayScript"); + } + + protected override Expression DoResolve (ResolveContext rc) + { + var expr = Expression.Resolve (rc); + + var dcma = expr as DynamicClassMemberAccess; + if (dcma != null) { + var ms = rc.Module.PlayScriptMembers.BinderDeleteProperty.Resolve (loc); + if (ms == null) + return null; + + var mg = MethodGroupExpr.CreatePredefined (ms, ms.DeclaringType, loc); + var call_args = new Arguments (2); + call_args.Add (new Argument (dcma.Instance)); + call_args.Add (dcma.Arguments [0]); + + return new Invocation (mg, call_args).Resolve (rc); + } + + // + // Fixed properties cannot be deleted but it can be used with delete operator + // + var pe = expr as PropertyExpr; + if (pe != null) { + rc.Report.WarningPlayScript (3601, loc, "The declared property `{0}' cannot be deleted. To free associated memory, set its value to null", + pe.GetSignatureForError ()); + + expr = new BoolConstant (rc.BuiltinTypes, false, loc); + return expr.Resolve (rc); + } + + Expression = expr; + eclass = ExprClass.Value; + type = rc.BuiltinTypes.Bool; + return this; + } + + public override void Emit (EmitContext ec) + { + Expression.Emit (ec); + + // Always returns true + ec.EmitInt (1); + } + + public override void EmitStatement (EmitContext ec) + { + Expression.Emit (ec); + if (Expression.Type.Kind != MemberKind.Void) + ec.Emit (OpCodes.Pop); + } + + public override object Accept (StructuralVisitor visitor) + { + return visitor.Visit (this); + } + } + + public class TypeOf : PlayScriptExpression + { + public TypeOf (Expression expr, Location l) + { + Expression = expr; + loc = l; + } + + public Expression Expression { get; private set; } + + protected override Expression DoResolve (ResolveContext rc) + { + var expr = Expression.Resolve (rc); + if (expr == null) + return null; + + var ms = rc.Module.PlayScriptMembers.OperationsTypeOf.Resolve (loc); + if (ms == null) + return null; + + var mg = MethodGroupExpr.CreatePredefined (ms, ms.DeclaringType, loc); + var call_args = new Arguments (1); + call_args.Add (new Argument (expr)); + + return new Invocation (mg, call_args).Resolve (rc); + } + + public override void Emit (EmitContext ec) + { + throw new NotSupportedException (); + } + + public override object Accept (StructuralVisitor visitor) + { + return visitor.Visit (this); + } + } + + public class RestArrayParameter : Parameter + { + PredefinedAttribute attr; + + public RestArrayParameter (string name, Attributes attrs, Location loc) + : base (null, name, Modifier.RestArray, attrs, loc) + { + } + + public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, CSharp.PredefinedAttributes pa) + { + base.ApplyAttributes (mb, cb, index, pa); + + attr.EmitAttribute (builder); + } + + public override string GetSignatureForError () + { + return GetModifierSignature (ModFlags); + } + + public override TypeSpec Resolve (IMemberContext rc, int index) + { + TypeExpression = new TypeExpression (rc.Module.PlayscriptTypes.Array.Resolve (), Location); + attr = rc.Module.PlayscriptAttributes.RestArrayParameter; + attr.Define (); + + return base.Resolve (rc, index); + } + } + + public class RegexLiteral : Constant, ILiteralConstant + { + readonly public string Regex; + readonly public string Options; + + public RegexLiteral (string regex, string options, Location loc) + : base (loc) + { + Regex = regex; + Options = options ?? ""; + } + + public override bool IsLiteral { + get { return true; } + } + + public override object GetValue () + { + return "/" + Regex + "/" + Options; + } + + public override string GetValueAsLiteral () + { + return GetValue () as String; + } + + public override long GetValueAsLong () + { + throw new NotSupportedException (); + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + throw new NotSupportedException (); + } + + public override bool IsDefaultValue { + get { + return Regex == null && Options == ""; + } + } + + public override bool IsNegative { + get { + return false; + } + } + + public override bool IsNull { + get { + return IsDefaultValue; + } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + return null; + } + + protected override Expression DoResolve (ResolveContext rc) + { +/* + if (rc.Target == Target.JavaScript) { + type = rc.Module.PredefinedTypes.AsRegExp.Resolve(); + eclass = ExprClass.Value; + return this; + } +*/ + var args = new Arguments(2); + args.Add (new Argument(new StringLiteral(rc.BuiltinTypes, Regex, this.Location))); + args.Add (new Argument(new StringLiteral(rc.BuiltinTypes, Options, this.Location))); + + return new New(new TypeExpression(rc.Module.PlayscriptTypes.RegExp.Resolve(), this.Location), + args, this.Location).Resolve (rc); + } + + public override void Emit (EmitContext ec) + { + throw new NotSupportedException (); + } +/* + public override void EmitJs (JsEmitContext jec) + { + jec.Buf.Write (GetValue () as String, Location); + } +*/ +#if FULL_AST + public char[] ParsedValue { get; set; } +#endif + + public override object Accept (StructuralVisitor visitor) + { + return visitor.Visit (this); + } + } + + public class XmlLiteral : Constant, ILiteralConstant + { + readonly public string Xml; + + public XmlLiteral (string xml, Location loc) + : base (loc) + { + Xml = xml; + } + + public override bool IsLiteral { + get { return true; } + } + + public override object GetValue () + { + return Xml; + } + + public override string GetValueAsLiteral () + { + return GetValue () as String; + } + + public override long GetValueAsLong () + { + throw new NotSupportedException (); + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + throw new NotSupportedException (); + } + + public override bool IsDefaultValue { + get { + return Xml == null; + } + } + + public override bool IsNegative { + get { + return false; + } + } + + public override bool IsNull { + get { + return IsDefaultValue; + } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + return null; + } + + protected override Expression DoResolve (ResolveContext rc) + { + var args = new Arguments(1); + args.Add (new Argument(new StringLiteral(rc.BuiltinTypes, Xml, this.Location))); + + return new New(new TypeExpression(rc.Module.PlayscriptTypes.Xml.Resolve(), this.Location), + args, this.Location).Resolve (rc); + } + + public override void Emit (EmitContext ec) + { + throw new NotSupportedException (); + } +/* + public override void EmitJs (JsEmitContext jec) + { + jec.Buf.Write (GetValue () as String, Location); + } +*/ +#if FULL_AST + public char[] ParsedValue { get; set; } +#endif + + public override object Accept (StructuralVisitor visitor) + { + return visitor.Visit (this); + } + } + + public class In : PlayScriptExpression + { + public In (Expression propertyExpr, Expression expression, Location loc) + { + this.PropertyExpression = propertyExpr; + this.Expression = expression; + this.loc = loc; + } + + public Expression Expression { get; private set; } + + public Expression PropertyExpression { get; private set; } + + protected override Expression DoResolve (ResolveContext rc) + { + PropertyExpression = PropertyExpression.Resolve (rc); + Expression = Expression.Resolve (rc); + if (PropertyExpression == null || Expression == null) + return null; + + if (Expression is MethodGroupExpr) { + var res = new BoolConstant (rc.BuiltinTypes, false, Location); + res.Resolve (rc); + return res; + } + + var ms = rc.Module.PlayScriptMembers.BinderHasProperty.Resolve (loc); + if (ms == null) + return null; + + var args = new Arguments (3); + args.Add (new Argument (Expression)); + args.Add (new Argument (new CSharp.TypeOf (rc.CurrentType, loc))); + args.Add (new Argument (PropertyExpression)); + + var mg = MethodGroupExpr.CreatePredefined (ms, ms.DeclaringType, loc); + return new Invocation (mg, args).Resolve (rc); + } + + public override void Emit (EmitContext ec) + { + throw new NotSupportedException (); + } + + public override object Accept (StructuralVisitor visitor) + { + return visitor.Visit (this); + } + } + + public class Is : CSharp.Is + { + public Is (Expression expr, Expression probeType, Location loc) + : base (expr, probeType, loc) + { + } + + protected override Expression ResolveProbeType (ResolveContext rc) + { + probe_type_expr = ProbeType.TryToResolveAsType (rc); + if (probe_type_expr != null) + return this; + + var probe_type = ProbeType.Resolve (rc); + if (probe_type == null) + return null; + + probe_type = CSharp.Convert.ImplicitConversionRequired (rc, probe_type, rc.Module.PlayscriptTypes.Class, loc); + if (probe_type == null) + return null; + + var ms = rc.Module.PlayScriptMembers.OperationsIsOfType.Resolve (loc); + if (ms == null) + return null; + + var mg = MethodGroupExpr.CreatePredefined (ms, ms.DeclaringType, loc); + var targs = new TypeArguments ( + new TypeExpression (expr.Type, loc)); + targs.Resolve (rc); + mg.SetTypeArguments (rc, targs); + + var call_args = new Arguments (1); + call_args.Add (new Argument (expr, Argument.AType.Ref)); + call_args.Add (new Argument (probe_type)); + + return new Invocation (mg, call_args).Resolve (rc); + } + } + + class ImplicitTypeOf : CSharp.TypeOf + { + public ImplicitTypeOf (TypeExpression expr, Location loc) + : base (expr, loc) + { + } + + public new TypeExpression TypeExpression { + get { + return (TypeExpression) base.TypeExpression; + } + } + } + + public class LocalFunction : AnonymousMethodExpression + { + TypeSpec return_type; + + public LocalFunction (FullNamedExpression returnType, Location loc) + : base (loc) + { + ReturnType = returnType; + } + + public FullNamedExpression ReturnType { get; private set; } + + protected override AnonymousMethodBody CompatibleMethodFactory (ResolveContext rc, TypeSpec return_type, TypeSpec delegate_type, ParametersCompiled p, ParametersBlock b) + { + string d_name; + int arity = p.Count; + TypeSpec[] targs; + + if (return_type.Kind == MemberKind.Void) { + d_name = "Action"; + targs = p.Types; + } else { + d_name = "Func"; + ++arity; + + targs = new TypeSpec [arity]; + Array.Copy (p.Types, targs, p.Types.Length); + targs [arity - 1] = return_type; + } + + TypeExpr te = null; + Namespace type_ns = rc.Module.GlobalRootNamespace.GetNamespace ("System", true); + if (type_ns != null) { + te = type_ns.LookupType (rc, d_name, arity, LookupMode.Normal, loc); + if (te != null) { + delegate_type = te.Type.MakeGenericType (rc, targs); + } + } + + return base.CompatibleMethodFactory (rc, return_type, delegate_type, p, b); + } + + protected override TypeSpec ResolveReturnType (ResolveContext rc, TypeSpec delegateType) + { + if (return_type == null) { + return_type = ReturnType.ResolveAsType (rc); + } + + return return_type; + } + + protected override ParametersCompiled ResolveParameters (ResolveContext rc, TypeInferenceContext tic, TypeSpec delegate_type) + { + return Parameters; + } + } + + public class LocalFunctionDeclaration : Statement + { + public LocalFunctionDeclaration (string name, Location loc) + { + Name = name; + this.loc = loc; + } + + public LocalFunction Function { get; set; } + + public Location Location { + get { + return loc; + } + } + + public string Name { get; private set; } + + protected override void DoEmit (EmitContext ec) + { + // + // This is only AST declaration there is nothing to emit. The initialization + // has been moved to block initializer because the function needs to be available + // anywhere in the block. + // + } + + protected override void CloneTo (CloneContext clonectx, Statement target) + { + var t = target as LocalFunctionDeclaration; + t.Function = (LocalFunction) Function.Clone (clonectx); + } + } + + public class UseNamespace : Statement + { + public UseNamespace (string ns, Location loc) + { + Namespace = ns; + this.loc = loc; + } + + public string Namespace { get; private set; } + + public override bool Resolve (BlockContext bc) + { + // TODO: Implement by adding the name to BlockContext namespaces list. Then when + // doing the namespace lookup get the list and do search with prefixes from the list + // It looks like once the name is added (used) it's never removed even if the scope + // is different + return true; + } + + public override bool ResolveUnreachable (BlockContext bc, bool warn) + { + return true; + } + + public override void Emit (EmitContext ec) + { + // Nothing, not even sequence point + } + + protected override void DoEmit (EmitContext ec) + { + } + + protected override void CloneTo (CloneContext clonectx, Statement target) + { + } + + public override object Accept (StructuralVisitor visitor) + { + return visitor.Visit (this); + } + } + + public class StatementFromExpression : Statement + { + public StatementFromExpression (Expression expr) + { + this.Expr = expr; + } + + public Expression Expr { get; private set; } + + public override bool Resolve (BlockContext bc) + { + // + // Any expression can act as a statement in PS, we need to wrap it to make + // the inheritance chain clean + // + Expr = Expr.Resolve (bc); + return Expr != null; + } + + protected override void DoEmit (EmitContext ec) + { + if (Expr.IsSideEffectFree) + return; + + Expr.Emit (ec); + ec.Emit (OpCodes.Pop); + } + + protected override void CloneTo (CloneContext clonectx, Statement target) + { + var t = target as StatementFromExpression; + t.Expr = Expr.Clone (clonectx); + } + } + + public class WithContext + { + Stack object_context; + Assign initialization; + + public WithContext () + { + } + + public WithContext (Stack context) + { + this.object_context = context; + } + + public bool IsInitialized { + get { + return initialization != null; + } + } + + public Stack ObjectContext { + get { + return object_context; + } + } + + public MethodGroupExpr RegisterMethod { get; private set; } + public MethodGroupExpr UnregisterMethod { get; private set; } + + public TemporaryVariableReference Variable { get; private set; } + + public Assign Initialize (BlockContext bc, Location loc) + { + var doc = bc.Module.PlayscriptTypes.DefaultObjectContext.Resolve (); + if (doc == null) + return null; + + Variable = TemporaryVariableReference.Create (doc, bc.CurrentBlock, loc); + if (Variable.Resolve (bc) == null) + return null; + + var ms = bc.Module.PlayScriptMembers.DefaultObjectContextCreate.Resolve (loc); + if (ms == null) + return null; + + var mg = MethodGroupExpr.CreatePredefined (ms, doc, loc); + var inv = new Invocation (mg, new Arguments (0)).Resolve (bc); + initialization = new CompilerAssign (Variable, inv, loc); + initialization.Resolve (bc); + + ms = bc.Module.PlayScriptMembers.DefaultObjectContextRegister.Resolve (loc); + if (ms == null) + return null; + + RegisterMethod = MethodGroupExpr.CreatePredefined (ms, doc, loc); + RegisterMethod.InstanceExpression = Variable; + + ms = bc.Module.PlayScriptMembers.DefaultObjectContextUnregister.Resolve (loc); + if (ms == null) + return null; + + UnregisterMethod = MethodGroupExpr.CreatePredefined (ms, doc, loc); + UnregisterMethod.InstanceExpression = Variable; + + return initialization; + } + + public void SetObjectContext (Expression expr) + { + if (object_context == null) + object_context = new Stack (); + + object_context.Push (expr); + } + } + + public class ObjectContextRuntimeExpression : PlayScriptExpression + { + public ObjectContextRuntimeExpression (TypeSpec type) + { + this.eclass = ExprClass.Variable; + this.type = type; + this.loc = Location.Null; + } + + protected override Expression DoResolve (ResolveContext rc) + { + return this; + } + + public override void Emit (EmitContext ec) + { + throw new NotSupportedException (); + } + } + + class ObjectContextMemberBinder : DynamicMemberAssignable + { + readonly string name; + readonly Expression context; + + public ObjectContextMemberBinder (string name, Expression context, Location loc) + : base (CreateFakeArgument (context), loc) + { + this.name = name; + this.context = context; + } + + static Arguments CreateFakeArgument (Expression context) + { + Arguments args = new Arguments (1); + args.Add (new Argument (context)); + return args; + } + + protected override Expression CreateCallSiteBinder (ResolveContext rc, Arguments args, bool isSet) + { + Arguments binder_args = new Arguments (3); + + binder_args.Add (new Argument (new StringLiteral (rc.BuiltinTypes, name, loc))); + binder_args.Add (new Argument (new CSharp.TypeOf (rc.CurrentType, loc))); + binder_args.Add (new Argument (context)); + + isSet |= (flags & CSharpBinderFlags.ValueFromCompoundAssignment) != 0; + return new Invocation (GetPlayScriptBinder (rc, isSet ? "SetMember" : "GetMember", loc), binder_args); + } + + protected MemberAccess GetPlayScriptBinder (ResolveContext rc, string name, Location loc) + { + var binder_type = rc.Module.PlayscriptTypes.Binder.Resolve (); + return new MemberAccess (new TypeExpression (binder_type, loc), name, loc); + } + } + + public class With : Statement + { + Assign initialization; + MethodGroupExpr register, unregister; + + public With (Expression expr, Block block, Location loc) + { + this.Expr = expr; + this.Block = block; + this.loc = loc; + } + + public Block Block { get; private set; } + public Expression Expr { get; private set; } + + protected override void CloneTo (CloneContext clonectx, Statement target) + { + var t = target as With; + t.Expr = Expr.Clone (clonectx); + t.Block = clonectx.LookupBlock (Block); + } + + protected override void DoEmit (EmitContext ec) + { + if (initialization != null) + initialization.EmitStatement (ec); + + if (register != null) { + // TODO: Should be inside try-finally but need to check which + // expressions then won't be allowed + + var args = new Arguments (1); + args.Add (new Argument (Expr)); + register.EmitCall (ec, args); + } + + Block.Emit (ec); + + if (unregister != null) + unregister.EmitCall (ec, new Arguments (0)); + } + + public override bool Resolve (BlockContext bc) + { + Expression expr; + + var t = Expr.TryToResolveAsType (bc); + if (t != null) { + expr = new TypeExpression (t, loc); + } else { + expr = Expr.Resolve (bc); + if (expr == null) + return false; + + Expr = expr; + } + + var ctx = bc.DefaultObjectContext; + if (ctx == null) { + bc.DefaultObjectContext = ctx = new WithContext (); + } + + if (expr.eclass == ExprClass.Type || expr.Type.IsSealed) { + // + // All member lookups can be done during compilation + // + ctx.SetObjectContext (expr); + } else { + if (!ctx.IsInitialized) { + initialization = ctx.Initialize (bc, loc); + if (initialization == null) + return false; + } + + ctx.SetObjectContext (ctx.Variable); + register = ctx.RegisterMethod; + unregister = ctx.UnregisterMethod; + } + + Block.Resolve (bc); + + ctx.ObjectContext.Pop (); + return true; + } + } + + /// + /// Implementation of the ActionScript E4X xml query. + /// + public class AsXmlQueryExpression : Expression + { + protected Expression expr; + protected Expression query; + + public AsXmlQueryExpression (Expression expr, Expression query, Location l) + { + this.expr = expr; + this.query = query; + loc = l; + } + + public Expression Expr { + get { + return expr; + } + } + + public Expression Query { + get { + return query; + } + } + + public override bool ContainsEmitWithAwait () + { + throw new NotSupportedException (); + } + + public override Expression CreateExpressionTree (ResolveContext ec) + { + throw new NotSupportedException ("ET"); + } + + protected override Expression DoResolve (ResolveContext ec) + { + // TODO: Implement XML query expression. + return null; + } + + protected override void CloneTo (CloneContext clonectx, Expression t) + { + AsXmlQueryExpression target = (AsXmlQueryExpression) t; + + target.expr = expr.Clone (clonectx); + target.query = query.Clone (clonectx); + } + + public override void Emit (EmitContext ec) + { + throw new InternalErrorException ("Missing Resolve call"); + } + + public override object Accept (StructuralVisitor visitor) + { + return visitor.Visit (this); + } + + } + + public class SimpleName : CSharp.SimpleName + { + public SimpleName (string name, Location loc) + : base (name, loc) + { + } + + // TODO: targs should be always null + public SimpleName (string name, TypeArguments targs, Location loc) + : base (name, targs, loc) + { + } + + public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions) + { + int lookup_arity = Arity; + bool errorMode = false; + Expression e; + Block current_block = rc.CurrentBlock; + INamedBlockVariable variable = null; + bool variable_found = false; + + if (rc.DefaultObjectContext != null) { + e = LookupObjectContext (rc, Name, restrictions); + if (e != null) + return e; + } + + // + // Stage 1: binding to local variables or parameters + // + if (current_block != null && lookup_arity == 0) { + if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) { + if (!variable.IsDeclared) { +// rc.Report.Warning (7156, 1, loc, "Use of local variable before declaration"); + if (variable is LocalVariable) { + var locVar = variable as LocalVariable; +// if (locVar.Type == null && locVar.TypeExpr != null) { +// locVar.DeclFlags |= LocalVariable.Flags.AsIgnoreMultiple; +// locVar.Type = locVar.TypeExpr.ResolveAsType (rc); +// } + } + e = variable.CreateReferenceExpression (rc, loc); + if (e != null) { + if (Arity > 0) + Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc); + + return e; + } + } else { + e = variable.CreateReferenceExpression (rc, loc); + if (e != null) { + if (Arity > 0) + Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc); + + return e; + } + } + } + } + + // + // Stage 2: Lookup members if we are inside a type up to top level type for nested types + // + TypeSpec member_type = rc.CurrentType; + for (; member_type != null; member_type = member_type.DeclaringType) { + e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc); + if (e == null) + continue; + + var me = e as MemberExpr; + if (me == null) { + // The name matches a type, defer to ResolveAsTypeStep + if (e is TypeExpr) + break; + + continue; + } + + me = me.ResolveMemberAccess (rc, null, null); + + if (Arity > 0) { + targs.Resolve (rc); + me.SetTypeArguments (rc, targs); + } + + return me; + } + + // Stage 3: Global names lookup + e = LookupGlobalName (rc, Name, restrictions); + if (e != null) + return e; + + // + // Stage 3: Lookup nested types, namespaces and type parameters in the context + // + if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) { + if (IsPossibleTypeOrNamespace (rc)) { + if (variable != null) { + rc.Report.SymbolRelatedToPreviousError (variable.Location, Name); + rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name); + } + + var fne = ResolveAsTypeOrNamespace (rc); + if (fne != null && (restrictions & MemberLookupRestrictions.PlayScriptConversion) == 0) { + var te = fne as TypeExpression; + if (te != null) + return new ImplicitTypeOf (te, loc); + } + + return fne; + } + } + + // TODO: Use C# rules too? + + // TODO: Handle errors + throw new NotImplementedException (); + } + + public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc) + { + var fne = ResolveKnownTypes (mc); + if (fne != null) + return fne; + + return base.ResolveAsTypeOrNamespace (mc); + } + + // TODO: Add ambiguity checks + // PS1000: var:Number:Number = 0; is ambiguous between local variable and global type + TypeExpression ResolveKnownTypes (IMemberContext mc) + { + var types = mc.Module.Compiler.BuiltinTypes; + switch (Name) { +// case "Object": +// return new TypeExpression (mc.Module.PlayscriptTypes.Object, loc); + case "Boolean": + return new TypeExpression (types.Bool, loc); + case "Number": + return new TypeExpression (types.Double, loc); + default: + return null; + } + } + + Expression LookupObjectContext (ResolveContext rc, string name, MemberLookupRestrictions restrictions) + { + var ctx = rc.DefaultObjectContext; + foreach (var expr in ctx.ObjectContext) { + if (expr == ctx.Variable) { + return new ObjectContextMemberBinder (name, expr, loc).Resolve (rc); + } + + var type = expr.Type; + + var me = MemberLookup (rc, false, type, name, 0, restrictions, loc) as MemberExpr; + if (me == null) { + // + // Try to look for extension method when member lookup failed + // + if (MethodGroupExpr.IsExtensionMethodArgument (expr)) { + var methods = rc.LookupExtensionMethod (type, Name, 0); + if (methods != null) { + var emg = new ExtensionMethodGroupExpr (methods, expr, loc); + //if (HasTypeArguments) { + // if (!targs.Resolve (rc)) + // return null; + // + // emg.SetTypeArguments (rc, targs); + //} + + // + // Run defined assigned checks on expressions resolved with + // disabled flow-analysis + // + //if (sn != null && !errorMode) { + // var vr = expr as VariableReference; + // if (vr != null) + // vr.VerifyAssigned (rc); + //} + + // TODO: it should really skip the checks bellow + return emg.Resolve (rc); + } + } + + continue; + } + + return me.ResolveMemberAccess (rc, null, null); + } + + return null; + } + + Expression LookupGlobalName (ResolveContext rc, string name, MemberLookupRestrictions restrictions) + { + var ns = rc.Module.GlobalRootNamespace.GetNamespace (PredefinedTypes.RootNamespace, false); + if (ns == null) + return null; + + var types = ns.GetAllTypes (PackageGlobalContainer.Name); + if (types == null) + return null; + + MemberExpr me = null; + foreach (var type in types) { + var e = MemberLookup (rc, false, type, name, 0, restrictions, loc) as MemberExpr; + if (e == null) + continue; + + // + // Compiled names have always priority over imported names + // + if (!type.MemberDefinition.IsImported) { + me = e; + break; + } + + if (me == null) { + me = e; + continue; + } + + // TODO: Figure out how to handle + throw new NotImplementedException ("Imported package name collision"); + } + + if (me == null) + return null; + + return me.ResolveMemberAccess (rc, null, null); + } + } + + public class QualifiedMemberAccess : MemberAccess + { + public QualifiedMemberAccess (Expression expr, string namespaceName, string identifier, Location l) + : base (expr, identifier, l) + { + this.Namespace = namespaceName; + } + + public string Namespace { get; private set; } + + public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions) + { + TypeSpec expr_type; + var tne = expr as ATypeNameExpression; + if (tne == null) { + expr_type = rc.CurrentType; + } else { + var res = tne.LookupNameExpression (rc, MemberLookupRestrictions.None); + if (res == null) + return null; + + res = res.Resolve (rc); + if (res == null) + return null; + + expr_type = res.Type; + } + + var name = Namespace + "." + Name; + var member_lookup = MemberLookup (rc, false, expr_type, name, 0, restrictions, loc); + + // TODO: Implement correct rules for out of context namespaces + if (member_lookup == null) + return null; + + var me = (MemberExpr) member_lookup; + return me.ResolveMemberAccess (rc, expr, null); + } + } + + public class NamespaceMemberName : MemberName + { + public NamespaceMemberName (string namespaceName, string name, Location loc) + : base (new MemberName (namespaceName, loc), name, loc) + { + } + + public override string LookupName { + get { + return Left.LookupName + "." + base.LookupName; + } + } + + public override string GetSignatureForError () + { + return Left.GetSignatureForError () + "::" + Name; + } + } + + public class NamespaceField : FieldBase + { + public class NamespaceInitializer : FieldInitializer + { + readonly NamespaceField field; + + public NamespaceInitializer (NamespaceField field, Expression value, Location loc) + : base (field, value, loc) + { + this.field = field; + } + + protected override ExpressionStatement ResolveInitializer (ResolveContext rc) + { + if (source == null) + return null; + + source = source.Resolve (rc); + if (source == null) + return null; + + source = GetStringValue (rc, source); + if (source == null) { + rc.Report.ErrorPlayScript (1171, loc, "A namespace initializer must be either a literal string or another namespace."); + return null; + } + + var args = new Arguments (2); + args.Add (new Argument (new NullLiteral (loc))); + args.Add (new Argument (source)); + source = new New (new TypeExpression (field.MemberType, loc), args, loc); + + return base.ResolveInitializer (rc); + } + + public static StringConstant GetStringValue (IMemberContext mc, Expression source) + { + var sc = source as StringConstant; + if (sc != null) + return sc; + + var fe = source as FieldExpr; + if (fe == null) + return null; + + var nf = fe.Spec as NamespaceFieldSpec; + if (nf == null) + return null; + + return new StringConstant (mc.Module.Compiler.BuiltinTypes, nf.GetValue (), Location.Null); + } + } + + const Modifiers AllowedModifiers = + Modifiers.PUBLIC | + Modifiers.PROTECTED | + Modifiers.INTERNAL | + Modifiers.PRIVATE; + + public NamespaceField (TypeDefinition parent, Modifiers mod, MemberName name, Expression initializer, Attributes attrs) + : base (parent, null, mod, AllowedModifiers, name, attrs) + { + Initializer = initializer; + } + + public override bool Define () + { + if (!base.Define ()) + return false; + + ModFlags |= Modifiers.STATIC; + + FieldAttributes field_attr = FieldAttributes.InitOnly | ModifiersExtensions.FieldAttr (ModFlags); + FieldBuilder = Parent.TypeBuilder.DefineField (GetFullName (MemberName), MemberType.GetMetaInfo (), field_attr); + + spec = new NamespaceFieldSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags); + Parent.MemberCache.AddMember (spec); + + return true; + } + + public override void Emit () + { + base.Emit (); + + Module.PlayscriptAttributes.NamespaceField.EmitAttribute (FieldBuilder, GetValue ()); + } + + public string GetValue () + { + if (initializer == null) + return null; + + var sc = NamespaceInitializer.GetStringValue (this, initializer); + if (sc == null) + return null; + + return sc.Value; + } + + protected override bool ResolveMemberType () + { + member_type = Module.PlayscriptTypes.Namespace.Resolve (); + return true; + } + } + + class NamespaceFieldSpec : FieldSpec + { + string value; + + public NamespaceFieldSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo info, Modifiers modifiers) + : base (declaringType, definition, memberType, info, modifiers) + { + } + + public NamespaceFieldSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo info, Modifiers modifiers, string value) + : this (declaringType, definition, memberType, info, modifiers) + { + this.value = value; + } + + public string GetValue () + { + var def = MemberDefinition as NamespaceField; + if (def != null) + return def.GetValue (); + + return value; + } + } + + interface IConstantProperty + { + Expression Initializer { get; } + } + + class ImportedPropertyConstant : ImportedMemberDefinition, IConstantProperty + { + public ImportedPropertyConstant (MemberInfo member, TypeSpec type, MetadataImporter importer) + : base (member, type, importer) + { + } + + public Expression Initializer { get; set; } + } + + public class ConstantField : FieldBase + { + public class Property : CSharp.Property, IConstantProperty + { + public Property (TypeDefinition parent, FullNamedExpression type, Modifiers mod, MemberName name, Attributes attrs) + : base (parent, type, mod, name, attrs) + { + } + + public Expression Initializer { get; set; } + + public override void Emit () + { + var init = Initializer.Resolve (null); + if (init == null) + return; + + var c = init as Constant; + if (c == null) { + var set_field = new Field (Parent, new TypeExpression (Compiler.BuiltinTypes.Bool, Location), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED | (ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)), + new MemberName ("<" + GetFullName (MemberName) + ">__SetField", Location), null); + + var lazy_field = new Field (Parent, type_expr, Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED | (ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)), + new MemberName ("<" + GetFullName (MemberName) + ">__LazyField", Location), null); + + set_field.Define (); + lazy_field.Define (); + + Parent.AddField (set_field); + Parent.AddField (lazy_field); + + // + // if (!SetField) { + // SetField = true; + // LazyField = Initializer; + // } + // + var set_f_expr = new FieldExpr (set_field, Location); + var lazy_f_expr = new FieldExpr (lazy_field, Location); + if (!IsStatic) { + set_f_expr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location); + lazy_f_expr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location); + } + + var expl = new ExplicitBlock (Get.Block, Location, Location); + Get.Block.AddScopeStatement (new If (new Unary (Unary.Operator.LogicalNot, set_f_expr, Location), expl, Location)); + + expl.AddStatement (new StatementExpression (new CompilerAssign (lazy_f_expr, init, Location))); + Get.Block.AddStatement (new Return (lazy_f_expr, Location)); + + Module.PlayscriptAttributes.ConstantField.EmitAttribute (PropertyBuilder); + } else { + // + // Simple constant, just return a value + // + Get.Block.AddStatement (new Return (init, Location)); + + var expr = CSharp.Convert.ImplicitConversionStandard (null, c, Compiler.BuiltinTypes.Object, Location); + if (expr == null) + throw new NotImplementedException (); + + // + // Store compile time constant to attribute for easier import + // + Module.PlayscriptAttributes.ConstantField.EmitAttribute (this, PropertyBuilder, expr); + } + + base.Emit (); + } + } + + class ConstInitializer : PlayScriptExpression + { + bool in_transit; + readonly Property prop; + Expression expr; + + public ConstInitializer (Property prop, Expression expr, Location loc) + { + this.loc = loc; + this.prop = prop; + this.expr = expr; + } + + protected override Expression DoResolve (ResolveContext unused) + { + if (type != null) + return expr; + + // + // Use a context in which the constant was declared and + // not the one in which is referenced + // + var bc = new BlockContext (prop, prop.Get.Block, prop.MemberType); + bc.Set (ResolveContext.Options.ConstantScope); + + expr = DoResolveInitializer (bc); + type = expr.Type; + + return expr; + } + + public override Constant ResolveAsPlayScriptConstant (ResolveContext rc) + { + return DoResolve (rc) as Constant; + } + + Expression DoResolveInitializer (ResolveContext rc) + { + if (in_transit) { + // PS seems to use default value but how to get the right order + throw new NotImplementedException ("Constant circular definition"); + } else { + in_transit = true; + expr = expr.Resolve (rc); + } + + in_transit = false; + + if (expr != null) { + var res = CSharp.Convert.ImplicitConversion (rc, expr, prop.MemberType, expr.Location); + if (res == null) { + rc.Report.ErrorPlayScript (1184, expr.Location, "Incompatible default value of type `{0}' where `{1}' is expected", + expr.Type.GetSignatureForError (), prop.MemberType.GetSignatureForError ()); + } else { + expr = res; + } + } + + if (expr == null) { + expr = New.Constantify (prop.MemberType, Location); + if (expr == null) + expr = Constant.CreateConstantFromValue (prop.MemberType, null, Location); + expr = expr.Resolve (rc); + } + + return expr; + } + + public override void Emit (EmitContext ec) + { + throw new NotSupportedException (); + } + } + + const Modifiers AllowedModifiers = + Modifiers.STATIC | + Modifiers.PUBLIC | + Modifiers.PROTECTED | + Modifiers.INTERNAL | + Modifiers.PRIVATE; + + public ConstantField (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs) + : base (parent, type, mod_flags, AllowedModifiers, name, attrs) + { + } + + public override bool Define () + { + if (!base.Define ()) + return false; + + if (Parent is PackageGlobalContainer) + ModFlags |= Modifiers.STATIC; + + var t = new TypeExpression (MemberType, TypeExpression.Location); + var init = Initializer ?? ImplicitVariableInitializer.GetConstantValue (this, MemberType, Location); + + var prop = new Property (Parent, t, ModFlags, MemberName, attributes); + prop.Initializer = new ConstInitializer (prop, init, init.Location); + prop.Get = new Property.GetMethod (prop, 0, null, prop.Location); + prop.Get.Block = new ToplevelBlock (Compiler, Location); + + if (!prop.Define ()) + return false; + + var idx = Parent.Members.IndexOf (this); + Parent.Members[idx] = prop; + + if (declarators != null) { + foreach (var d in declarators) { + init = d.Initializer ?? new DefaultValueExpression (t, Location); + + prop = new Property (Parent, t, ModFlags, new MemberName (d.Name.Value, d.Name.Location), attributes); + prop.Initializer = new ConstInitializer (prop, init, init.Location); + + prop.Get = new Property.GetMethod (prop, 0, null, prop.Location); + prop.Get.Block = new ToplevelBlock (Compiler, Location); ; + + prop.Define (); + Parent.PartialContainer.Members.Add (prop); + } + } + + return true; + } + } + + public class FieldDeclarator : CSharp.FieldDeclarator + { + public FieldDeclarator (FieldBase field, SimpleMemberName name, Expression initializer, FullNamedExpression typeExpr) + : base (field, name, initializer) + { + this.TypeExpression = typeExpr; + } + + public FieldDeclarator (FieldBase field, SimpleMemberName name, Expression initializer) + : base (field, name, initializer) + { + } + + public FullNamedExpression TypeExpression { get; private set; } + + public override FullNamedExpression GetFieldTypeExpression (FieldBase field) + { + return TypeExpression; + } + } + + public class BlockVariableDeclarator : CSharp.BlockVariableDeclarator + { + TypeSpec type; + + public BlockVariableDeclarator (LocalVariable li, Expression initializer, FullNamedExpression typeExpr, Location loc) + : base (li, initializer) + { + this.TypeExpression = typeExpr; + this.Location = loc; + } + + public BlockVariableDeclarator (LocalVariable li, Expression initializer, Location loc) + : base (li, initializer) + { + this.Location = loc; + } + + public Location Location { get; private set; } + public FullNamedExpression TypeExpression { get; private set; } + + public override TypeSpec ResolveType (BlockContext bc, TypeSpec unused) + { + if (type != null) + return type; + + if (TypeExpression == null) { + if (Initializer is LocalFunction) + TypeExpression = new TypeExpression (bc.Module.PlayscriptTypes.Function, Location); + else + TypeExpression = new UntypedTypeExpression (Location); + } + + type = TypeExpression.ResolveAsType (bc); + if (type == null) + return null; + + Variable.Type = type; + return type; + } + } + + // + // When variable is used before it's declared it has to be initialized + // to correct PS value which in some cases does not match CIL default + // values + // + public class ImplicitVariableInitializer : Statement + { + BlockVariable variable; + + public ImplicitVariableInitializer (BlockVariable variable) + { + this.variable = variable; + } + + public override bool Resolve (BlockContext bc) + { + var existing = variable.Variable.Type; + + var type = variable.ResolveType (bc); + if (type == null) + return false; + + bool constant = variable.Variable.IsConstant; + if (existing != null) { + if (constant) { + Error_NameConflict (bc, variable.loc, variable.Variable.Name); + } else { + var undefined = bc.Module.PlayscriptTypes.UndefinedType; + if (type == undefined) { + variable.Variable.Type = existing; + } else if (existing == undefined) { + // Nothing to do + } else if (!TypeSpecComparer.IsEqual (existing, type)) { + Error_NameConflict (bc, variable.loc, variable.Variable.Name); + } + } + } + + if (type == bc.Module.PlayscriptTypes.UndefinedType) { + bc.Module.PlayScriptMembers.UndefinedValue.Resolve (variable.loc); + } + + if (variable.Declarators != null) { + foreach (BlockVariableDeclarator d in variable.Declarators) { + existing = d.Variable.Type; + type = d.ResolveType (bc, null); + if (type == null) + continue; + + if (existing != null) { + if (constant) { + Error_NameConflict (bc, d.Location, d.Variable.Name); + } else { + var undefined = bc.Module.PlayscriptTypes.UndefinedType; + if (type == undefined) { + variable.Variable.Type = existing; + } else if (existing == undefined) { + // Nothing to do + } else if (!TypeSpecComparer.IsEqual (existing, type)) { + Error_NameConflict (bc, d.Location, d.Variable.Name); + } + } + } + + if (type == bc.Module.PlayscriptTypes.UndefinedType) { + bc.Module.PlayScriptMembers.UndefinedValue.Resolve (d.Variable.Location); + } + } + } + + return true; + } + + static void Error_NameConflict (BlockContext bc, Location loc, string name) + { + bc.Report.ErrorPlayScript (1151, loc, "A conflict exists with definition `{0}'", name); + } + + protected override void DoEmit (EmitContext ec) + { + if (variable.Variable.IsConstant) + return; + + EmitVariableInitialization (ec, variable.Variable); + + if (variable.Declarators != null) { + foreach (BlockVariableDeclarator d in variable.Declarators) { + EmitVariableInitialization (ec, d.Variable); + } + } + } + + static void EmitVariableInitialization (EmitContext ec, LocalVariable li) + { + li.CreateBuilder (ec); + + // TOOD: Optimize to initialize only when read before assignment + if (li.Type == ec.Module.PlayscriptTypes.Number) { + ec.Emit (OpCodes.Ldc_R8, double.NaN); + li.EmitAssign (ec); + return; + } + + if (li.Type == ec.Module.PlayscriptTypes.UndefinedType) { + var spec = ec.Module.PlayScriptMembers.UndefinedValue.Get (); + var fe = new FieldExpr (spec, Location.Null); + + fe.Emit (ec); + li.EmitAssign (ec); + return; + } + } + + public static Constant GetConstantValue (IMemberContext mc, TypeSpec type, Location loc) + { + if (type == mc.Module.PlayscriptTypes.Number) { + return new DoubleConstant (type, double.NaN, loc); + } + + if (TypeSpec.IsReferenceType (type)) + return new NullConstant (type, loc); + + return New.Constantify (type, loc); + } + + protected override void CloneTo (CloneContext clonectx, Statement target) + { + } + } + + public class Field : CSharp.Field + { + const Modifiers AllowedModifiers = + Modifiers.PUBLIC | + Modifiers.PROTECTED | + Modifiers.INTERNAL | + Modifiers.PRIVATE | + Modifiers.STATIC; + + public Field (TypeDefinition parent, FullNamedExpression type, Modifiers mod, MemberName name, Attributes attrs) + : base (parent, type, mod, AllowedModifiers, Modifiers.INTERNAL, name, attrs) + { + } + + public override bool Define () + { + if (Parent is PackageGlobalContainer) + ModFlags |= Modifiers.STATIC; + + return base.Define (); + } + } + + public class Method : CSharp.Method + { + const Modifiers AllowedModifiers = + Modifiers.STATIC | + Modifiers.PUBLIC | + Modifiers.PROTECTED | + Modifiers.INTERNAL | + Modifiers.PRIVATE | + Modifiers.OVERRIDE | + Modifiers.VIRTUAL | // virtual should be no-op but we extend AS here to have better metadata + Modifiers.SEALED; // TODO: FINAL + + private Method (TypeDefinition parent, FullNamedExpression return_type, Modifiers mod, + MemberName name, ParametersCompiled parameters, Attributes attrs) + : base (parent, return_type, mod, AllowedModifiers, Modifiers.INTERNAL, name, parameters, attrs) + { + } + + public bool HasNoReturnType { get; set; } + + public static new Method Create (TypeDefinition parent, FullNamedExpression returnType, Modifiers mod, + MemberName name, ParametersCompiled parameters, Attributes attrs) + { + var m = new Method (parent, returnType, mod, name, parameters, attrs); + + if (parent is PackageGlobalContainer) { + if ((mod & Modifiers.OVERRIDE) != 0) { + m.Report.ErrorPlayScript (1010, m.Location, "`{0}': The override attribute may be used only on definitions inside a class", + m.GetSignatureForError ()); + } + + if ((mod & Modifiers.VIRTUAL) != 0) { + m.Report.ErrorPlayScript (1011, m.Location, "`{0}': The override attribute may be used only on definitions inside a class", + m.GetSignatureForError ()); + } + + if ((mod & Modifiers.STATIC) != 0) { + m.Report.ErrorPlayScript (1012, m.Location, "`{0}': The static attribute may be used only on definitions inside a class", + m.GetSignatureForError ()); + } + } + + if ((mod & Modifiers.AccessibilityMask) == 0) { + m.Report.WarningPlayScript (1085, m.Location, "`{0}': will be scoped to the default namespace `internal'", + m.GetSignatureForError ()); + } + + return m; + } + + protected override bool CheckOverrideAgainstBase (MemberSpec base_member) + { + bool ok = true; + + if ((base_member.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) == 0) { + ModFlags &= ~Modifiers.OVERRIDE; + ModFlags |= Modifiers.VIRTUAL; + } + + if ((base_member.Modifiers & Modifiers.SEALED) != 0) { + Report.SymbolRelatedToPreviousError (base_member); + Report.ErrorPlayScript (1025, Location, "`{0}': Cannot redefine a final method", GetSignatureForError ()); + ok = false; + } + + var base_member_type = ((IInterfaceMemberSpec) base_member).MemberType; + if (!TypeSpecComparer.Override.IsEqual (MemberType, base_member_type)) { + Report.SymbolRelatedToPreviousError (base_member); + + // TODO: Add all not matching incompatibilites as PS1023 + Report.ErrorPlayScript (1023, Location, "`{0}': Incompatible override: Return type must be `{1}' to match overridden member `{2}'", + GetSignatureForError (), base_member_type.GetSignatureForError (), base_member.GetSignatureForError ()); + ok = false; + } + + return ok; + } + + public override bool Define () + { + if (Parent is PackageGlobalContainer) { + ModFlags |= Modifiers.STATIC; + } + + // + // Allowed but makes no sense + // + if ((ModFlags & (Modifiers.VIRTUAL | Modifiers.PRIVATE)) == (Modifiers.VIRTUAL | Modifiers.PRIVATE)) + ModFlags &= ~Modifiers.VIRTUAL; + + return base.Define (); + } + + protected override void Error_OverrideWithoutBase (MemberSpec candidate) + { + if (candidate == null) { + Report.ErrorPlayScript (1020, Location, "`{0}': Method marked override must override another method", GetSignatureForError ()); + return; + } + + base.Error_OverrideWithoutBase (candidate); + } + } + + public class E4XIndexer : PlayScriptExpression + { + public enum Operator + { + Attribute, // .@ + Namespace // :: + } + + readonly Operator oper; + readonly Arguments args; + Expression expr; + + public E4XIndexer (Operator oper, Expression expr, Arguments args, Location loc) + { + this.oper = oper; + this.expr = expr; + this.args = args; + this.loc = loc; + } + + protected override Expression DoResolve (ResolveContext rc) + { + switch (oper) { + case Operator.Attribute: + return MakeInvocation ("attribute").Resolve (rc); + case Operator.Namespace: + return MakeInvocation ("namespace").Resolve (rc); + } + + throw new NotImplementedException (); + } + + Expression MakeInvocation (string method) + { + return new Invocation (new MemberAccess (expr, method, loc), args); + } + + public override void Emit (EmitContext ec) + { + throw new NotSupportedException (); + } + } + + public class E4XOperator : PlayScriptExpression + { + public enum Operator + { + Descendant, // .. + ChildAll, // .* + ChildAttribute, // .@ + DescendantAll, // ..* + Namespace // :: + } + + readonly Operator oper; + readonly string name; + Expression expr; + + public E4XOperator (Operator oper, Expression expr, string name, Location loc) + { + this.oper = oper; + this.expr = expr; + this.name = name; + this.loc = loc; + } + + protected override Expression DoResolve (ResolveContext rc) + { + switch (oper) { + case Operator.ChildAll: + return MakeInvocation (rc, "children").Resolve (rc); + case Operator.DescendantAll: + return MakeInvocation (rc, "descendants").Resolve (rc); + case Operator.ChildAttribute: + return MakeInvocation (rc, "attribute", name).Resolve (rc); + case Operator.Descendant: + return MakeInvocation (rc, "descendants", name).Resolve (rc); + case Operator.Namespace: + return MakeInvocation (rc, "namespace", name).Resolve (rc); + } + + throw new NotImplementedException (); + } + + Expression MakeInvocation (ResolveContext rc, string method, string arg = null) + { + Arguments args = null; + if (arg != null) { + args = new Arguments (1); + args.Add (new Argument (new StringLiteral (rc.BuiltinTypes, arg, loc))); + } + + return new Invocation (new MemberAccess (expr, method, loc), args); + } + + public override void Emit (EmitContext ec) + { + throw new NotSupportedException (); + } + } + + public class ForIn : ForIterator + { + public ForIn (Statement variableIterant, Expression expr, Statement stmt, Block body, Location loc) + : base (variableIterant, expr, stmt, body, loc) + { + } + + protected override PredefinedMember GetValuesMethod (BlockContext bc) + { + return bc.Module.PlayScriptMembers.BinderGetKeys; + } + + protected override TypeSpec GetUntypedIterantType (BlockContext bc) + { + return bc.BuiltinTypes.String; + } + } + + public class ForEach : ForIterator + { + public ForEach (Statement variableIterant, Expression expr, Statement stmt, Block body, Location loc) + : base (variableIterant, expr, stmt, body, loc) + { + } + + protected override PredefinedMember GetValuesMethod (BlockContext bc) + { + return bc.Module.PlayScriptMembers.BinderGetValues; + } + + protected override TypeSpec GetUntypedIterantType (BlockContext bc) + { + return bc.BuiltinTypes.Dynamic; + } + } + + public abstract class ForIterator : CSharp.Foreach + { + public ForIterator (Statement variableIterant, Expression expr, Statement stmt, Block body, Location loc) + : base (null, null, expr, stmt, body, loc) + { + this.Iterant = variableIterant; + } + + public Statement Iterant { get; private set; } + + protected abstract PredefinedMember GetValuesMethod (BlockContext bc); + protected abstract TypeSpec GetUntypedIterantType (BlockContext bc); + + public override bool Resolve (BlockContext bc) + { + expr = expr.Resolve (bc); + if (expr == null) + return false; + + body.AddStatement (Statement); + + // TODO: ? + //if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) { + // ec.Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'", + // expr.ExprClassName); + // return false; + //} + + var ms = GetValuesMethod (bc).Resolve (loc); + if (ms == null) + return false; + + var mg = MethodGroupExpr.CreatePredefined (ms, ms.DeclaringType, loc); + var call_args = new Arguments (1); + call_args.Add (new Argument (Expr)); + + expr = new Invocation (mg, call_args).Resolve (bc); + if (expr == null) + return false; + + var untyped = Iterant as UntypedBlockVariable; + if (untyped != null) { + untyped.TypeExpression = new TypeExpression (GetUntypedIterantType (bc), loc); + } + + if (!Iterant.Resolve (bc)) + return false; + + var var = Iterant as BlockVariable; + if (var != null) { + type = var.TypeExpression; + variable = var.Variable; + + statement = new CollectionForeach (this, variable, Expr); + } else { + LocalVariableReference lvr = null; + var sfe = Iterant as StatementFromExpression; + if (sfe != null) { + if (!sfe.Resolve (bc)) + return false; + + lvr = sfe.Expr as LocalVariableReference; + } + + if (lvr == null) { + bc.Report.ErrorPlayScript (1105, Iterant.loc, "Target of assignment must be a reference value"); + return false; + } + + statement = new CollectionForeach (this, lvr, Expr); + } + + return statement.Resolve (bc); + } + } + + public class UsingType : UsingNamespace + { + protected TypeSpec resolvedType; + + public UsingType (ATypeNameExpression expr, Location loc) + : base (expr, loc) + { + } + + public override void Define (NamespaceContainer ctx) + { + resolved = NamespaceExpression.ResolveAsTypeOrNamespace (ctx); + if (resolved != null) { + resolvedType = resolved.ResolveAsType (ctx); + } + } + + public TypeSpec ResolvedType + { + get { return resolvedType; } + } + } + + class DynamicClassMemberAccess : PlayScriptExpression, IAssignMethod + { + Expression invocation; + + public DynamicClassMemberAccess (ElementAccess ea) + : this (ea.Expr, ea.Arguments, ea.Location) + { + } + + public DynamicClassMemberAccess (Expression instance, Arguments args, Location loc) + { + this.Instance = instance; + this.Arguments = args; + this.loc = loc; + } + + public Arguments Arguments { get; private set; } + + public Expression Instance { get; private set; } + + protected override Expression DoResolve (ResolveContext rc) + { + var ms = rc.Module.PlayScriptMembers.BinderGetMember.Resolve (loc); + if (ms == null) + return null; + + // TODO: Figure out what value = dc["a", "b"] is supposed to do + + var mg = MethodGroupExpr.CreatePredefined (ms, ms.DeclaringType, loc); + var call_args = new Arguments (3); + call_args.Add (new Argument (Instance)); + call_args.Add (new Argument (new CSharp.TypeOf (rc.CurrentType, loc))); + call_args.Add (Arguments [0]); + + invocation = new Invocation (mg, call_args).Resolve (rc); + if (invocation == null) + return null; + + eclass = ExprClass.Variable; + type = invocation.Type; + return this; + } + + public override Expression DoResolveLValue (ResolveContext rc, Expression rhs) + { + var ms = rc.Module.PlayScriptMembers.BinderSetMember.Resolve (loc); + if (ms == null) + return null; + + // TODO: Figure out what dc["a", "b"] = value is supposed to do + + var mg = MethodGroupExpr.CreatePredefined (ms, ms.DeclaringType, loc); + var call_args = new Arguments (3); + call_args.Add (new Argument (Instance)); + call_args.Add (new Argument (new CSharp.TypeOf (rc.CurrentType, loc))); + call_args.Add (Arguments [0]); + call_args.Add (new Argument (rhs)); + + invocation = new Invocation (mg, call_args).Resolve (rc); + + eclass = ExprClass.Variable; + type = rhs.Type; + return this; + } + + public override void Emit (EmitContext ec) + { + invocation.Emit (ec); + } + + public void Emit (EmitContext ec, bool leave_copy) + { + throw new NotImplementedException (); + } + + public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound) + { + if (leave_copy || isCompound) + throw new NotImplementedException (); + + invocation.Emit (ec); + } + } + + class Package : NamespaceContainer + { + static readonly MemberName DefaultPackageName = new MemberName (PredefinedTypes.RootNamespace, Location.Null); + TypeDefinition globals; + ToplevelBlock block; + + private Package (MemberName name, NamespaceContainer parent) + : base (name, parent) + { + } + + public static Package Create (MemberName name, NamespaceContainer parent) + { + if (name == null) + return new Package (DefaultPackageName, parent); + + return new Package (name, parent) { + Usings = new List () { + new UsingNamespace (new SimpleName (PredefinedTypes.RootNamespace, name.Location), name.Location) + } + }; + } + + public override TypeSpec CurrentType { + get { + return globals == null ? null : globals.CurrentType; + } + } + + public bool IsTopLevel { + get { + return MemberName == DefaultPackageName; + } + } + + public ToplevelBlock GetBlock () + { + if (block == null) + block = new ToplevelBlock (Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location); + + return block; + } + + public override string GetSignatureForError () + { + if (IsTopLevel) + return ""; + + return base.GetSignatureForError (); + } + + public TypeDefinition GetGlobalsTypeDefinition () + { + if (globals == null) { + globals = new PackageGlobalContainer (this); + AddTypeContainer (globals); + } + + return globals; + } + + public override void EmitContainer () + { + if (block != null) { + var bc = new BlockContext (this, block, Compiler.BuiltinTypes.Void); + bc.Set (ResolveContext.Options.ConstructorScope); + + if (block.Resolve (null, bc, null)) { + var cb = Module.DefineModuleInitializer (); + + EmitContext ec = new EmitContext (this, cb.GetILGenerator (), bc.ReturnType, null); + ec.With (EmitContext.Options.ConstructorScope, true); + + block.Emit (ec); + } + } + + base.EmitContainer (); + } + } + + class PackageGlobalContainer : CompilerGeneratedContainer + { + public const string Name = ""; + + public PackageGlobalContainer (TypeContainer parent) + : base (parent, new MemberName (Name), Modifiers.PUBLIC | Modifiers.STATIC) + { + IsPlayScriptType = true; + } + + public override void Emit () + { + base.Emit (); + + Module.PlayscriptAttributes.PlayScript.EmitAttribute (TypeBuilder); + } + + public override string GetSignatureForError () + { + return null; + } + } + + class PredefinedTypes + { + public readonly BuiltinTypeSpec Object; + public readonly BuiltinTypeSpec Function; + public readonly BuiltinTypeSpec Class; + public readonly BuiltinTypeSpec Number; + public readonly BuiltinTypeSpec String; + + public readonly PredefinedType Vector; + public readonly PredefinedType Array; + public readonly PredefinedType Error; + public readonly PredefinedType RegExp; + public readonly PredefinedType Xml; + public readonly PredefinedType Namespace; + + public readonly PredefinedType Binder; + public readonly PredefinedType Operations; + public readonly PredefinedType DefaultObjectContext; + public readonly PredefinedType UndefinedValueType; + + + // + // Internal type used for undefined type comparisons + // + public readonly BuiltinTypeSpec UndefinedType; + + // + // The namespace used for the root package. + // + public const string RootNamespace = "_root"; + + public PredefinedTypes (ModuleContainer module) + { + var root_ns = module.GlobalRootNamespace.GetNamespace (RootNamespace, true); + var builtin_types = module.Compiler.BuiltinTypes; + + // Setup type aliases + + Object = new BuiltinTypeSpec ("Object", BuiltinTypeSpec.Type.Object); + Object.SetDefinition (builtin_types.Object); + Object.Modifiers |= Modifiers.DYNAMIC; + root_ns.AddType (module, Object); + + Function = new BuiltinTypeSpec (MemberKind.Delegate, RootNamespace, "Function", BuiltinTypeSpec.Type.Delegate); + Function.SetDefinition (builtin_types.Delegate); + Function.Modifiers |= Modifiers.SEALED; + root_ns.AddType (module, Function); + + Class = new BuiltinTypeSpec (MemberKind.Class, RootNamespace, "Class", BuiltinTypeSpec.Type.Type); + Class.SetDefinition (builtin_types.Type); + Class.Modifiers |= Modifiers.DYNAMIC; + root_ns.AddType (module, Class); + + String = new BuiltinTypeSpec (MemberKind.Class, RootNamespace, "String", BuiltinTypeSpec.Type.String); + String.SetDefinition (module.Compiler.BuiltinTypes.String); + String.Modifiers |= Modifiers.SEALED; + root_ns.AddType (module, String); + + // For now use same instance + UndefinedType = builtin_types.Dynamic; + Number = builtin_types.Double; + + // Known predefined types + Array = new PredefinedType (module, MemberKind.Class, RootNamespace, "Array"); + Vector = new PredefinedType (module, MemberKind.Class, RootNamespace, "Vector", 1); + Error = new PredefinedType (module, MemberKind.Class, RootNamespace, "Error"); + RegExp = new PredefinedType (module, MemberKind.Class, RootNamespace, "RegExp"); + Xml = new PredefinedType (module, MemberKind.Class, RootNamespace, "XML"); + Namespace = new PredefinedType (module, MemberKind.Class, RootNamespace, "Namespace"); + + Binder = new PredefinedType (module, MemberKind.Class, "PlayScript.Runtime", "Binder"); + Operations = new PredefinedType (module, MemberKind.Class, "PlayScript.Runtime", "Operations"); + DefaultObjectContext = new PredefinedType (module, MemberKind.Class, "PlayScript.Runtime", "DefaultObjectContext"); + UndefinedValueType = new PredefinedType (module, MemberKind.Class, "PlayScript.Runtime", "Undefined"); + + // Define types which are used for early comparisons + Array.Define (); + } + + public void PopulateImplicitMembers (ModuleContainer module) + { + var builtin_types = module.Compiler.BuiltinTypes; + + Object.MemberCache = new MemberCache (builtin_types.Object.MemberCache, true); + + var tostring_filter = CSharp.MemberFilter.Method ("ToString", 0, ParametersCompiled.EmptyReadOnlyParameters, null); + var tostring = MemberCache.FindMember (Object, tostring_filter, BindingRestriction.DeclaredOnly) as MethodSpec; + if (tostring != null) { + Object.MemberCache.AddMember ( + new MethodSpec (MemberKind.Method, Object, tostring.MemberDefinition, tostring.ReturnType, tostring.Parameters, tostring.Modifiers), + "toString"); + } + + String.MemberCache = new MemberCache (builtin_types.String.MemberCache, true); + + var length = MemberCache.FindMember (String, CSharp.MemberFilter.Property ("Length", null), BindingRestriction.DeclaredOnly) as PropertySpec; + if (length != null) { + String.MemberCache.AddMember ( + new PropertySpec (MemberKind.Property, String, length.MemberDefinition, length.MemberType, length.MetaInfo, length.Modifiers) { + Get = length.Get + }, "length"); + } + + if (Error.Define () && tostring != null) { + Error.TypeSpec.MemberCache.AddMember ( + new MethodSpec (MemberKind.Method, Error.TypeSpec, tostring.MemberDefinition, tostring.ReturnType, tostring.Parameters, tostring.Modifiers), + "toString"); + } + } + } + + class PredefinedMembers + { + public readonly PredefinedMember ArrayPush; + public readonly PredefinedMember VectorPush; + public readonly PredefinedMember BinderGetMember; + public readonly PredefinedMember BinderGetKeys; + public readonly PredefinedMember BinderGetValues; + public readonly PredefinedMember BinderSetMember; + public readonly PredefinedMember BinderHasProperty; + public readonly PredefinedMember BinderDeleteProperty; + public readonly PredefinedMember BinderDelegateInvoke; + public readonly PredefinedMember OperationsTypeOf; + public readonly PredefinedMember OperationsClassOf; + public readonly PredefinedMember OperationsIsOfType; + public readonly PredefinedMember DefaultObjectContextCreate; + public readonly PredefinedMember DefaultObjectContextRegister; + public readonly PredefinedMember DefaultObjectContextUnregister; + public readonly PredefinedMember UndefinedValue; + + public PredefinedMembers (ModuleContainer module) + { + var types = module.PredefinedTypes; + var btypes = module.Compiler.BuiltinTypes; + var ptypes = module.PlayscriptTypes; + + var tp = new TypeParameter (0, new MemberName ("T"), null, null, Variance.None); + + ArrayPush = new PredefinedMember (module, ptypes.Array, "push", btypes.Object); + VectorPush = new PredefinedMember (module, ptypes.Vector, "push", new TypeParameterSpec (0, tp, SpecialConstraint.None, Variance.None, null)); + BinderGetMember = new PredefinedMember (module, ptypes.Binder, "GetMember", btypes.Object, btypes.Type, btypes.Object); + BinderGetKeys = new PredefinedMember (module, ptypes.Binder, "GetKeys", btypes.Object); + BinderGetValues = new PredefinedMember (module, ptypes.Binder, "GetValues", btypes.Object); + BinderSetMember = new PredefinedMember (module, ptypes.Binder, "SetMember", btypes.Object, btypes.Type, btypes.Object, btypes.Object); + BinderDeleteProperty = new PredefinedMember (module, ptypes.Binder, "DeleteProperty", btypes.Object, btypes.Object); + BinderDelegateInvoke = new PredefinedMember (module, ptypes.Binder, "DelegateInvoke", btypes.Delegate, ArrayContainer.MakeType (module, btypes.Object)); + BinderHasProperty = new PredefinedMember (module, ptypes.Binder, "HasProperty", btypes.Object, btypes.Type, btypes.Object); + OperationsTypeOf = new PredefinedMember (module, ptypes.Operations, "TypeOf", btypes.Object); + OperationsClassOf = new PredefinedMember (module, ptypes.Operations, "ClassOf", btypes.Object); + OperationsIsOfType = new PredefinedMember (module, ptypes.Operations, CSharp.MemberFilter.Method ("IsOfType", 1, null, null)); + DefaultObjectContextCreate = new PredefinedMember (module, ptypes.DefaultObjectContext, "Create"); + DefaultObjectContextRegister = new PredefinedMember (module, ptypes.DefaultObjectContext, "Register", btypes.Object); + DefaultObjectContextUnregister = new PredefinedMember (module, ptypes.DefaultObjectContext, "Unregister"); + UndefinedValue = new PredefinedMember (module, ptypes.UndefinedValueType, CSharp.MemberFilter.Field ("Value", btypes.Object)); + } + } + + class PredefinedAttributes + { + public class PredefinedConstantAttribute : PredefinedAttribute + { + PredefinedMember ctor_definition; + + public PredefinedConstantAttribute (ModuleContainer module, string ns, string name) + : base (module, ns, name) + { + } + + public void EmitAttribute (IMemberContext mc, PropertyBuilder builder, Expression constant) + { + if (ctor_definition == null) { + if (!Define ()) + return; + + ctor_definition = new PredefinedMember (module, type, CSharp.MemberFilter.Constructor ( + ParametersCompiled.CreateFullyResolved (module.Compiler.BuiltinTypes.Object))); + } + + var ctor = ctor_definition.Get (); + if (ctor == null) + return; + + AttributeEncoder encoder = new AttributeEncoder (); + constant.EncodeAttributeValue (mc, encoder, ctor.Parameters.Types [0]); + encoder.EncodeEmptyNamedArguments (); + + builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray ()); + } + } + + public class PredefinedNamespaceAttribute : PredefinedAttribute + { + PredefinedMember ctor_definition; + + public PredefinedNamespaceAttribute (ModuleContainer module, string ns, string name) + : base (module, ns, name) + { + } + + public void EmitAttribute (FieldBuilder builder, string value) + { + if (ctor_definition == null) { + if (!Define ()) + return; + + ctor_definition = new PredefinedMember (module, type, CSharp.MemberFilter.Constructor ( + ParametersCompiled.CreateFullyResolved (module.Compiler.BuiltinTypes.String))); + } + + var ctor = ctor_definition.Get (); + if (ctor == null) + return; + + AttributeEncoder encoder = new AttributeEncoder (); + encoder.Encode (value); + encoder.EncodeEmptyNamedArguments (); + + builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray ()); + } + } + + public readonly PredefinedConstantAttribute ConstantField; + public readonly PredefinedNamespaceAttribute NamespaceField; + public readonly PredefinedAttribute DynamicClass; + public readonly PredefinedAttribute PlayScript; + public readonly PredefinedAttribute RestArrayParameter; + + public PredefinedAttributes (ModuleContainer module) + { + var ns = "PlayScript.Runtime.CompilerServices"; + ConstantField = new PredefinedConstantAttribute (module, ns, "ConstantFieldAttribute"); + NamespaceField = new PredefinedNamespaceAttribute (module, ns, "NamespaceFieldAttribute"); + DynamicClass = new PredefinedAttribute (module, ns, "DynamicClassAttribute"); + PlayScript = new PredefinedAttribute (module, ns, "PlayScriptAttribute"); + RestArrayParameter = new PredefinedAttribute (module, ns, "RestArrayParameterAttribute"); + } + } + + static class Convert + { + public static Expression ImplicitConversion (ResolveContext rc, Expression expr, TypeSpec target) + { + Expression e; + + e = ImplicitReferenceConversion (rc, expr, expr.Type, target); + if (e != null) + return e; + + e = ImplicitNumericConversion (expr, expr.Type, target); + if (e != null) + return e; + + return null; + } + + static Expression ImplicitReferenceConversion (ResolveContext rc, Expression expr, TypeSpec exprType, TypeSpec targetType) + { + if (targetType == rc.Module.PlayscriptTypes.Class && exprType == rc.BuiltinTypes.Type) + return expr; + + if (exprType.BuiltinType == BuiltinTypeSpec.Type.Dynamic && targetType == rc.Module.PlayscriptTypes.Object) + return expr; + + return null; + } + + static Expression ImplicitNumericConversion (Expression expr, TypeSpec expr_type, TypeSpec target_type) + { + switch (expr_type.BuiltinType) { + case BuiltinTypeSpec.Type.Int: + // + // From int to uint + // + switch (target_type.BuiltinType) { + case BuiltinTypeSpec.Type.UInt: + return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4); + } + + break; + + case BuiltinTypeSpec.Type.UInt: + // + // From uint to int + // + switch (target_type.BuiltinType) { + case BuiltinTypeSpec.Type.Int: + return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4); + } + + break; + case BuiltinTypeSpec.Type.Double: + // + // From double to int + // + switch (target_type.BuiltinType) { + case BuiltinTypeSpec.Type.Int: + return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4); + } + break; + } + + return null; + } + } + + sealed class ErrorMessage : AbstractMessage + { + public ErrorMessage (int code, Location loc, string message, List extraInfo) + : base (code, loc, message, extraInfo) + { + } + + public ErrorMessage (AbstractMessage aMsg) + : base (aMsg) + { + } + + public override bool IsWarning { + get { + return false; + } + } + + public override string LanguagePrefix { + get { + return "PS"; + } + } + + public override string MessageType { + get { + return "error"; + } + } + } + + sealed class WarningMessage : AbstractMessage + { + public WarningMessage (int code, Location loc, string message, List extra_info) + : base (code, loc, message, extra_info) + { + } + + public override bool IsWarning { + get { + return true; + } + } + + public override string MessageType { + get { + return "warning"; + } + } + + public override string LanguagePrefix { + get { + return "PS"; + } + } + } + +#region SLE support + + static class Expressions + { + public static SLE.Expression StrictEqual (SLE.Expression left, SLE.Expression right) + { + return new BinaryExpression (50 | 1 >> 16, left, right); + } + + public static SLE.Expression StrictNotEqual (SLE.Expression left, SLE.Expression right) + { + return new BinaryExpression (51 | 1 >> 16, left, right); + } + } + + class BinaryExpression : SLE.Expression + { + readonly SLE.Expression left, right; + readonly int oper; + + public BinaryExpression (int oper, SLE.Expression left, SLE.Expression right) + { + this.oper = oper; + this.left = left; + this.right = right; + } + + public override bool CanReduce { + get { + return true; + } + } + + public override SLE.ExpressionType NodeType { + get { + return SLE.ExpressionType.Extension; + } + } + + public override System.Type Type { + get { + return typeof (bool); + } + } + + public override SLE.Expression Reduce () + { + // TODO: Do something about it + // Probably need to move the comparison code to avoid cyclic dependency + var asm = System.Reflection.Assembly.Load (new System.Reflection.AssemblyName ("PlayScript.Core")); + var t = asm.GetType ("PlayScript.Runtime.Operations", true); + var tt = asm.GetType ("PlayScript.Runtime.BinaryOperator", true); + var m = t.GetMethod ("Comparison", new [] { tt, typeof (object), typeof (object) }); + + return SLE.Expression.Call (m, SLE.Expression.Constant (System.Enum.ToObject (tt, oper)), + SLE.Expression.Convert (left, typeof (object)), + SLE.Expression.Convert (right, typeof (object))); + } + } + + +#endregion + +} diff --git a/mcs/mcs/property.cs b/mcs/mcs/property.cs index 0c8b3c52973..242691a97cc 100644 --- a/mcs/mcs/property.cs +++ b/mcs/mcs/property.cs @@ -36,7 +36,7 @@ namespace Mono.CSharp public abstract class PropertyBasedMember : InterfaceMemberBase { protected PropertyBasedMember (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, MemberName name, Attributes attrs) - : base (parent, type, mod, allowed_mod, name, attrs) + : base (parent, type, mod, allowed_mod, Modifiers.PRIVATE, name, attrs) { } @@ -406,7 +406,7 @@ void CheckModifiers (Modifiers modflags) } PropertyMethod get, set, first; - PropertyBuilder PropertyBuilder; + protected PropertyBuilder PropertyBuilder; public PropertyBase (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, Modifiers allowed_mod, MemberName name, Attributes attrs) : base (parent, type, mod_flags, allowed_mod, name, attrs) @@ -915,6 +915,28 @@ public override string[] ValidAttributeTargets { } } + public class EventDeclarator + { + public EventDeclarator (EventField field, SimpleMemberName name, Expression initializer) + { + this.Name = name; + this.Field = field; + this.Field.Initializer = Initializer; + } + + #region Properties + + public EventField Field { get; private set; } + public SimpleMemberName Name { get; private set; } + public Expression Initializer { + get { + return Field.Initializer; + } + } + + #endregion + } + /// /// Event is declared like field. /// @@ -1027,7 +1049,7 @@ protected override MethodSpec GetOperation (Location loc) Expression initializer; Field backing_field; - List declarators; + List declarators; public EventField (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs) : base (parent, type, mod_flags, name, attrs) @@ -1038,7 +1060,7 @@ public EventField (TypeDefinition parent, FullNamedExpression type, Modifiers mo #region Properties - public List Declarators { + public List Declarators { get { return this.declarators; } @@ -1073,10 +1095,10 @@ public override void Accept (StructuralVisitor visitor) visitor.Visit (this); } - public void AddDeclarator (FieldDeclarator declarator) + public void AddDeclarator (EventDeclarator declarator) { if (declarators == null) - declarators = new List (2); + declarators = new List (2); declarators.Add (declarator); @@ -1114,10 +1136,8 @@ public override bool Define() var t = new TypeExpression (MemberType, TypeExpression.Location); foreach (var d in declarators) { - var ef = new EventField (Parent, t, mod_flags_src, new MemberName (d.Name.Value, d.Name.Location), OptAttributes); - - if (d.Initializer != null) - ef.initializer = d.Initializer; + var ef = d.Field; + ef.member_type = member_type; ef.Define (); Parent.PartialContainer.Members.Add (ef); diff --git a/mcs/mcs/ps-parser.jay b/mcs/mcs/ps-parser.jay new file mode 100644 index 00000000000..12fb7eb557a --- /dev/null +++ b/mcs/mcs/ps-parser.jay @@ -0,0 +1,7110 @@ +%{ +// +// ps-parser.jay: The Parser for the PlayScript language +// Authors: Miguel de Icaza (miguel@gnome.org) +// Ravi Pratap (ravi@ximian.com) +// Marek Safar (marek.safar@gmail.com) +// Ben Cooley (bcooley@zynga.com) +// Dual Licensed under the terms of the GNU GPL and the MIT X11 license +// +// (C) 2001 Ximian, Inc (http://www.ximian.com) +// (C) 2004-2011 Novell, Inc +// Copyright 2011-2012 Xamarin Inc. +// + +using System.Text; +using System.IO; +using System; +using System.Collections.Generic; +using Mono.CSharp; +using Linq = Mono.CSharp.Linq; +using Enum = Mono.CSharp.Enum; +using Attribute = Mono.CSharp.Attribute; +using Delegate = Mono.CSharp.Delegate; +using Nullable = Mono.CSharp.Nullable; + +namespace Mono.PlayScript +{ + /// + /// The PlayScript Parser + /// + public class PlayScriptParser + { + [Flags] + enum ParameterModifierType + { + Ref = 1 << 1, + Out = 1 << 2, + This = 1 << 3, + Params = 1 << 4, + Arglist = 1 << 5, + DefaultValue = 1 << 6, + + All = Ref | Out | This | Params | Arglist | DefaultValue + } + + public const bool parsing_playscript = true; + + static readonly object ModifierNone = 0; + + LocatedToken namespace_modifier; + +// const string RootNs = PredefinedTypes.RootNamespace; + + NamespaceContainer current_namespace; + NamespaceContainer prev_namespace; + NamespaceContainer private_namespace; + TypeContainer current_container; + TypeDefinition current_type; + PropertyBase current_property; + FieldBase current_field; + Constructor current_constructor; + + // Set by config params to enable/disable inclusion of methods, fields, consts, classes, structs, etc. + bool is_config_enabled = true; + + bool is_package_function = false; + + /// + /// Current block is used to add statements as we find + /// them. + /// + Block current_block; + + BlockVariable current_variable; + + Delegate current_delegate; + + AnonymousMethodExpression current_anonymous_method; + + /// + /// This is used by the unary_expression code to resolve + /// a name against a parameter. + /// + + // FIXME: This is very ugly and it's very hard to reset it correctly + // on all places, especially when some parameters are autogenerated. + ParametersCompiled current_local_parameters; + + bool parsing_anonymous_method; + + bool async_block; + + /// + /// An out-of-band stack. + /// + Stack oob_stack; + + /// + /// Controls the verbosity of the errors produced by the parser + /// + int yacc_verbose_flag; + + /// + /// Used by the interactive shell, flags whether EOF was reached + /// and an error was produced + /// + public bool UnexpectedEOF; + + /// + /// The current file. + /// + readonly CompilationSourceFile file; + + /// + /// Temporary Xml documentation cache. + /// For enum types, we need one more temporary store. + /// + string tmpComment; + string enumTypeComment; + + /// Current attribute target + string current_attr_target; + + ParameterModifierType valid_param_mod; + + bool default_parameter_used; + + /// When using the interactive parser, this holds the + /// resulting expression + public Class InteractiveResult; + + // Current modifier namespace identifier + public string ns_modifier; + + // + // Keeps track of global data changes to undo on parser error + // + public Undo undo; + + Stack linq_clause_blocks; + + ModuleContainer module; + + readonly CompilerContext compiler; + readonly LanguageVersion lang_version; + readonly bool doc_support; + readonly CompilerSettings settings; + readonly Report report; + + // + // Instead of allocating carrier array everytime we + // share the bucket for very common constructs which can never + // be recursive + // + List parameters_bucket; + + // + // Full AST support members + // + LocationsBag lbag; + List> mod_locations; +%} + +%token EOF +%token NONE /* This token is never returned by our lexer */ +%token ERROR // This is used not by the parser, but by the tokenizer. + // do not remove. + +/* + *These are the C# keywords + */ +%token FIRST_KEYWORD +%token ABSTRACT +%token AS +%token SUPER +%token BOOL +%token BOOLEAN +%token BREAK +%token BYTE +%token CASE +%token CATCH +%token CHAR +%token CLASS +%token CONST +%token CONTINUE +%token DECIMAL +%token DEFAULT +%token DELETE +%token DO +%token DOUBLE +%token DOUBLE2 +%token DOUBLE3 +%token DOUBLE4 +%token DYNAMIC +%token EACH +%token ELSE +%token EXPLICIT +%token EXTENDS +%token FALSE +%token FINAL +%token FINALLY +%token FIXED +%token FLOAT +%token FLOAT2 +%token FLOAT3 +%token FLOAT4 +%token FOR +%token FOR_EACH +%token FUNCTION +%token FUNCTION_GET +%token FUNCTION_SET +%token FUNCTION_BLOCK +%token GOTO +%token IF +%token IMPLICIT +%token IMPLEMENTS +%token IMPORT +%token IN +%token INDEXER +%token INSTANCEOF +%token INT +%token INTERFACE +%token INTERNAL +%token IS +%token LONG +%token NAMESPACE +%token NATIVE +%token NEW +%token NULL +%token OBJECT +%token OPERATOR +%token OUT +%token OVERRIDE +%token OVERLOAD +%token PACKAGE +%token PRIVATE +%token PROPERTY +%token PROTECTED +%token PUBLIC +%token READONLY +%token REF +%token RETURN +%token SBYTE +%token SHORT +%token STATIC +%token STRING +%token STRUCT +%token SWITCH +%token THIS +%token THROW +%token TRUE +%token TRY +%token TYPEOF +%token UINT +%token ULONG +%token UNSAFE +%token USE +%token USHORT +%token USING +%token VAR +%token VIRTUAL +%token VOID +%token VOLATILE +%token WHERE +%token WHILE +%token WITH +%token PARTIAL +%token ARROW +%token FROM +%token FROM_FIRST +%token JOIN +%token ON +%token EQUALS +%token SELECT +%token GROUP +%token BY +%token LET +%token ORDERBY +%token ASCENDING +%token DESCENDING +%token INTO +%token INTERR_NULLABLE +%token EXTERN +%token ASYNC +%token AWAIT + +/* C# keywords which are not really keywords */ +%token GET +%token SET + +%left LAST_KEYWORD + +/* C# single character operators/punctuation. */ +%token OPEN_BRACE +%token CLOSE_BRACE +%token OPEN_BRACKET +%token CLOSE_BRACKET +%token OPEN_PARENS +%token CLOSE_PARENS + +%token DOT +%token DOT_AT +%token DOT_STAR +%token DOTDOT +%token DOTDOT_AT +%token DOTDOT_STAR +%token DOTDOTDOT +%token DOT_OPEN_PARENS +%token CLOSE_PARENS_DOT +%token COMMA +%token COLON +%token SEMICOLON +%token TILDE + +%token PLUS +%token MINUS +%token BANG +%token ASSIGN +%token OP_LT +%token OP_GT +%token BITWISE_AND +%token BITWISE_OR +%token LOGICAL_AND_ASSIGN +%token LOGICAL_OR_ASSIGN +%token STAR +%token PERCENT +%token DIV +%token CARRET +%token INTERR + +/* C# multi-character operators. */ +%token DOUBLE_COLON +%token OP_INC +%token OP_DEC +%token OP_SHIFT_LEFT +%token OP_SHIFT_RIGHT +%token OP_USHIFT_RIGHT +%token OP_LE +%token OP_GE +%token OP_EQ +%token OP_REF_EQ +%token OP_NE +%token OP_REF_NE +%token OP_AND +%token OP_OR +%token OP_MULT_ASSIGN +%token OP_DIV_ASSIGN +%token OP_MOD_ASSIGN +%token OP_ADD_ASSIGN +%token OP_SUB_ASSIGN +%token OP_SHIFT_LEFT_ASSIGN +%token OP_SHIFT_RIGHT_ASSIGN +%token OP_USHIFT_RIGHT_ASSIGN +%token OP_AND_ASSIGN +%token OP_XOR_ASSIGN +%token OP_OR_ASSIGN +%token OP_PTR +%token OP_COALESCING +%token OP_IN +%token OP_AT + +/* Generics <,> tokens */ +%token OP_GENERICS_LT +%token OP_GENERICS_LT_DECL +%token OP_GENERICS_GT + +%token LITERAL + +%token IDENTIFIER +%token IDENTIFIER_MODIFIER +%token IDENTIFIER_CONFIG +%token OPEN_PARENS_EXPR_LIST +%token GENERIC_DIMENSION +%token DEFAULT_COLON +%token OPEN_BRACKET_EXPR +%token OPEN_BRACE_INIT + +// Make the parser go into eval mode parsing (statements and compilation units). +%token EVAL_STATEMENT_PARSER +%token EVAL_COMPILATION_UNIT_PARSER +%token EVAL_USING_DECLARATIONS_UNIT_PARSER + +%token DOC_SEE + +// +// This token is generated to trigger the completion engine at this point +// +%token GENERATE_COMPLETION + +// +// This token is return repeatedly after the first GENERATE_COMPLETION +// token is produced and before the final EOF +// +%token COMPLETE_COMPLETION + +/* Add precedence rules to solve dangling else s/r conflict */ +%nonassoc IF +%nonassoc ELSE + +/* Define the operator tokens and their precedences */ +%right ASSIGN +%right OP_COALESCING +%right INTERR +%left OP_OR +%left OP_AND +%left BITWISE_OR +%left BITWISE_AND +%left OP_SHIFT_LEFT OP_SHIFT_RIGHT +%left PLUS MINUS +%left STAR DIV PERCENT +%right BANG CARRET UMINUS +%nonassoc OP_INC OP_DEC +%left OPEN_PARENS +%left NEW +%left OPEN_BRACKET OPEN_BRACE +%left DOT + +%start compilation_unit +%% + +compilation_unit + : outer_declaration opt_EOF + { + Lexer.check_incorrect_doc_comment (); + } + | interactive_parsing { Lexer.CompleteOnEOF = false; } opt_EOF + | documentation_parsing + ; + +outer_declaration + : opt_extern_alias_directives opt_package_directives + | opt_extern_alias_directives opt_package_directives package_declaration opt_attributes + { + if ($4 != null) { + Attributes attrs = (Attributes) $4; + report.Error (1730, attrs.Attrs [0].Location, + "Assembly and module attributes must precede all other elements except using clauses and extern alias declarations"); + + current_namespace.UnattachedAttributes = attrs; + } + } + | opt_extern_alias_directives opt_package_directives attribute_sections + { + module.AddAttributes ((Attributes) $3, current_namespace); + } + | error + { + if (yyToken == Token.EXTERN) + report.Error (439, lexer.Location, "An extern alias declaration must precede all other elements"); + else + Error_SyntaxError (yyToken); + } + ; + +opt_EOF + : /* empty */ + | EOF + ; + +extern_alias_directives + : extern_alias_directive + | extern_alias_directives extern_alias_directive + ; + +extern_alias_directive + : EXTERN IDENTIFIER IDENTIFIER SEMICOLON + { + var lt = (LocatedToken) $2; + string s = lt.Value; + if (s != "alias") { + syntax_error (lt.Location, "`alias' expected"); + } else { + if (lang_version == LanguageVersion.ISO_1) + FeatureIsNotAvailable (lt.Location, "external alias"); + + lt = (LocatedToken) $3; + if (lt.Value == QualifiedAliasMember.GlobalAlias) { + RootNamespace.Error_GlobalNamespaceRedefined (report, lt.Location); + } + + var na = new UsingExternAlias (new SimpleMemberName (lt.Value, lt.Location), GetLocation ($1)); + current_namespace.AddUsing (na); + + lbag.AddLocation (na, GetLocation ($2), GetLocation ($4)); + } + } + | EXTERN error + { + Error_SyntaxError (yyToken); + } + ; + +no_config_package_directive + : import_directive +// | use_namespace_directive + ; + +package_directive + : no_config_package_directive + | config_package_directive + ; + +config_package_directive + : IDENTIFIER_CONFIG + { + var lt = (LocatedToken) $1; + is_config_enabled = file.IsConditionalDefined (lt.Value.Replace("::","_")); + } + no_config_package_directive + { + is_config_enabled = true; + $$ = $3; + } + | IDENTIFIER_CONFIG + { + var lt = (LocatedToken) $1; + is_config_enabled = file.IsConditionalDefined (lt.Value.Replace("::","_")); + } + OPEN_BRACE opt_package_directives CLOSE_BRACE + { + is_config_enabled = true; + $$ = $4; + } + ; + +package_directives + : package_directive + | package_directives package_directive + ; + +use_namespace_directive + : use_namespace + { + if (doc_support) + Lexer.doc_state = XmlCommentState.Allowed; + } + ; + +use_namespace + : USE NAMESPACE IDENTIFIER stmnt_end_semicolon + ; + +import_directive + : import_package + { + if (doc_support) + Lexer.doc_state = XmlCommentState.Allowed; + } + ; + +import_package + : IMPORT namespace_or_type_expr + { + Lexer.AllowAutoSemiAfterToken(Token.DOT_STAR, true); + } + DOT_STAR opt_semicolon + { + if (is_config_enabled) { + var un = new UsingNamespace ((ATypeNameExpression) $2, GetLocation ($1)); + current_namespace.AddUsing (un); + + lbag.AddLocation (un, GetLocation ($5)); + + Lexer.AllowAutoSemiAfterToken(Token.DOT_STAR, false); + } + } + | IMPORT typeof_type_expression opt_semicolon + { + if (is_config_enabled) { + var ut = new UsingType ((ATypeNameExpression) $2, GetLocation ($1)); + current_namespace.AddUsing (ut); + + lbag.AddLocation (ut, GetLocation ($3)); + } + } +/* + | IMPORT IDENTIFIER ASSIGN namespace_or_type_expr SEMICOLON + { + if (is_config_enabled) { + var lt = (LocatedToken) $2; + if (lang_version != LanguageVersion.ISO_1 && lt.Value == "global") { + report.Warning (440, 2, lt.Location, + "An alias named `global' will not be used when resolving `global::'. The global namespace will be used instead"); + } + + var un = new UsingAliasNamespace (new SimpleMemberName (lt.Value, lt.Location), (ATypeNameExpression) $4, GetLocation ($1)); + current_namespace.AddUsing (un); + + lbag.AddLocation (un, GetLocation ($3), GetLocation ($5)); + } + } +*/ + ; + +// +// Strictly speaking, namespaces don't have attributes but +// we parse global attributes along with namespace declarations and then +// detach them +// +package_declaration + : opt_attributes PACKAGE + { + Lexer.AutoSemiInsertion = false; + } + opt_package_name + { + Attributes attrs = (Attributes) $1; + var name = $4 as MemberName; +/* + if (attrs != null) { + bool valid_global_attrs = true; + if ((current_namespace.DeclarationFound || current_namespace != file)) { + valid_global_attrs = false; + } else { + foreach (var a in attrs.Attrs) { + if (a.ExplicitTarget == "assembly" || a.ExplicitTarget == "module") + continue; + + valid_global_attrs = false; + break; + } + } + + if (!valid_global_attrs) + report.Error (1671, name.Location, "A namespace declaration cannot have modifiers or attributes"); + } + + module.AddAttributes (attrs, current_namespace); +*/ + // Close the private package namespace (if it's active) + if (current_namespace == private_namespace) { + if (private_namespace.Containers.Count > 0) { + prev_namespace.AddTypeContainer(private_namespace); + var priv_un = new UsingNamespace ( + private_namespace.NS.MakeTypeNameExpression(GetLocation($1)), GetLocation ($1)); + prev_namespace.AddUsing(priv_un, true); + } + current_container = current_namespace = prev_namespace.Parent; + prev_namespace = private_namespace = null; + } + + var ns = Package.Create (name, current_namespace); + current_namespace.AddTypeContainer (ns); + current_container = current_namespace = ns; +// var un = new UsingNamespace (new SimpleName (RootNs, GetLocation ($1)), GetLocation ($1)); +// current_namespace.AddUsing(un, true); + } + OPEN_BRACE + { + if (doc_support) + Lexer.doc_state = XmlCommentState.Allowed; + + Lexer.AutoSemiInsertion = true; + } + opt_package_body CLOSE_BRACE opt_semicolon + { + lbag.AddLocation (current_container, GetLocation ($2), GetLocation ($6), GetLocation ($8)); + current_container = current_namespace = current_namespace.Parent; + + lexer.parsing_modifiers = false; + } + opt_package_body + { + // Close the private package namespace (if it's active) + if (current_namespace == private_namespace) { +/* + if (private_namespace.Containers.Count > 0) { + prev_namespace.AddTypeContainer(private_namespace); + var priv_un = new UsingNamespace ( + private_namespace.NS.MakeTypeNameExpression(GetLocation($1)), GetLocation ($1)); + prev_namespace.AddUsing(priv_un, true); + } +*/ + current_container = current_namespace = prev_namespace.Parent; + prev_namespace = private_namespace = null; + } + +// lbag.AddLocation (current_container, GetLocation ($2), GetLocation ($6), GetLocation ($11)); + } + ; + +opt_package_name + : /* empty */ + | package_name + ; + +package_name + : IDENTIFIER + { + var lt = (LocatedToken) $1; + $$ = new MemberName (lt.Value, lt.Location); + } + | package_name DOT IDENTIFIER + { + var lt = (LocatedToken) $3; + $$ = new MemberName ((MemberName) $1, lt.Value, lt.Location); + } + | error + { + Error_SyntaxError (yyToken); + $$ = new MemberName ("", lexer.Location); + } + ; + +opt_semicolon + : /* empty */ + | SEMICOLON + ; + +opt_comma + : /* empty */ + | COMMA + ; + +opt_package_directives + : /* empty */ + | package_directives + ; + +opt_extern_alias_directives + : /* empty */ + | extern_alias_directives + ; + +opt_package_body + : /* empty */ + | package_body + ; + +package_body + : package_statement + | package_body package_statement + ; + +package_statement + : type_declaration + { + if (is_config_enabled) { + if ($1 != null) { + TypeContainer ds = (TypeContainer)$1; + + if ((ds.ModFlags & (Modifiers.PRIVATE | Modifiers.PROTECTED)) != 0){ + report.Error (1527, ds.Location, + "Namespace elements cannot be explicitly declared as private, protected or protected internal"); + } + + // Here is a trick, for explicit attributes we don't know where they belong to until + // we parse succeeding declaration hence we parse them as normal and re-attach them + // when we know whether they are global (assembly:, module:) or local (type:). + if (ds.OptAttributes != null) { + ds.OptAttributes.ConvertGlobalAttributes (ds, current_namespace, !current_namespace.DeclarationFound && current_namespace == file); + } + } + current_namespace.DeclarationFound = true; + } + } + | constant_declaration + | field_declaration + | no_config_package_directive + | valid_declaration_statement + { + var stmt = $1 as Statement; + if (stmt != null) { + var package = (Package) current_container; + package.GetBlock ().AddStatement (stmt); + } + } + | namespace_declaration + ; + +type_declaration + : class_declaration + | interface_declaration + ; + +// +// Enable this when we have handled all errors, because this acts as a generic fallback +// +// | error { +// Console.WriteLine ("Token=" + yyToken); +// report.Error (1518, GetLocation ($1), "Expected class, struct, interface, enum or delegate"); +// } + ; + +// +// Attributes +// + +opt_attributes + : /* empty */ + | attribute_sections + ; + +attribute_sections + : attribute_section + { + var sect = $1 as List; + if (sect != null) { + $$ = new Attributes (sect); + } + } + | attribute_sections attribute_section + { + Attributes attrs = $1 as Attributes; + var sect = $2 as List; + if (sect != null) { + if (attrs == null) + attrs = new Attributes (sect); + else + attrs.AddAttributes (sect); + } + $$ = attrs; + } + ; + +attribute_section + : OPEN_BRACKET + { + lexer.parsing_attribute_section = true; + } + attribute_section_cont + { + lexer.parsing_attribute_section = false; + $$ = $3; + } + ; + +attribute_section_cont + : attribute_target COLON + { + current_attr_target = (string) $1; + if (current_attr_target == "assembly" || current_attr_target == "module") { + Lexer.check_incorrect_doc_comment (); + } + } + attribute_list opt_comma CLOSE_BRACKET + { + // when attribute target is invalid + if (current_attr_target == string.Empty) + $$ = new List (0); + else + $$ = $4; + + current_attr_target = null; + lexer.parsing_attribute_section = false; + lexer.AutoSemiInsertionAfter = 1; + } + | attribute_list opt_comma CLOSE_BRACKET + { + lexer.AutoSemiInsertionAfter = 1; + $$ = $1; + } + ; + +attribute_target + : IDENTIFIER + { + var lt = (LocatedToken) $1; + $$ = CheckAttributeTarget (lt.Value, lt.Location); + } + | RETURN { $$ = "return"; } + | error + { + if (yyToken == Token.IDENTIFIER) { + Error_SyntaxError (yyToken); + $$ = null; + } else { + string name = GetTokenName (yyToken); + $$ = CheckAttributeTarget (name, GetLocation ($1)); + } + } + ; + +attribute_list + : attribute + { + $$ = new List (4) { (Attribute) $1 }; + } + | attribute_list COMMA attribute + { + var attrs = (List) $1; + attrs.Add ((Attribute) $3); + + $$ = attrs; + } + ; + +attribute + : attribute_name + { + ++lexer.parsing_block; + } + opt_attribute_arguments + { + --lexer.parsing_block; + + var tne = (ATypeNameExpression) $1; + if (tne.HasTypeArguments) { + report.Error (404, tne.Location, "Attributes cannot be generic"); + } + + $$ = new Attribute (current_attr_target, tne, (Arguments[]) $3, GetLocation ($1), lexer.IsEscapedIdentifier (tne)); + } + ; + +attribute_name + : namespace_or_type_expr + ; + +opt_attribute_arguments + : /* empty */ { $$ = null; } + | OPEN_PARENS attribute_arguments CLOSE_PARENS + { + lexer.AutoSemiInsertionAfter = 1; + $$ = $2; + } + ; + + +attribute_arguments + : /* empty */ { $$ = null; } + | positional_or_named_argument + { + Arguments a = new Arguments (4); + a.Add ((Argument) $1); + $$ = new Arguments [] { a, null }; + } + | named_attribute_argument + { + Arguments a = new Arguments (4); + a.Add ((Argument) $1); + $$ = new Arguments [] { null, a }; + } + | attribute_arguments COMMA positional_or_named_argument + { + Arguments[] o = (Arguments[]) $1; + if (o [1] != null) { + report.Error (1016, ((Argument) $3).Expr.Location, "Named attribute arguments must appear after the positional arguments"); + o [0] = new Arguments (4); + } + + Arguments args = ((Arguments) o [0]); + if (args.Count > 0 && !($3 is NamedArgument) && args [args.Count - 1] is NamedArgument) + Error_NamedArgumentExpected ((NamedArgument) args [args.Count - 1]); + + args.Add ((Argument) $3); + } + | attribute_arguments COMMA named_attribute_argument + { + Arguments[] o = (Arguments[]) $1; + if (o [1] == null) { + o [1] = new Arguments (4); + } + + ((Arguments) o [1]).Add ((Argument) $3); + } + ; + +positional_or_named_argument + : expression + { + $$ = new Argument ((Expression) $1); + } +// | named_argument + ; + +named_attribute_argument + : IDENTIFIER ASSIGN + { + ++lexer.parsing_block; + } + expression + { + --lexer.parsing_block; + var lt = (LocatedToken) $1; + $$ = new NamedArgument (lt.Value, lt.Location, (Expression) $4); + lbag.AddLocation ($$, GetLocation($2)); + } + ; + +/* +named_argument + : identifier_inside_body COLON opt_named_modifier expression + { + if (lang_version <= LanguageVersion.V_3) + FeatureIsNotAvailable (GetLocation ($1), "named argument"); + + // Avoid boxing in common case (no modifier) + var arg_mod = $3 == null ? Argument.AType.None : (Argument.AType) $3; + + var lt = (LocatedToken) $1; + $$ = new NamedArgument (lt.Value, lt.Location, (Expression) $4, arg_mod); + lbag.AddLocation ($$, GetLocation($2)); + } + ; +*/ + +opt_named_modifier + : /* empty */ { $$ = null; } + | REF + { + CheckIsPlayScript("ref parameters", GetLocation($1)); + $$ = Argument.AType.Ref; + } + | OUT + { + CheckIsPlayScript("out parameters", GetLocation($1)); + $$ = Argument.AType.Out; + } + ; + +opt_class_member_declarations + : /* empty */ + | class_member_declarations + ; + +class_member_declarations + : class_member_declaration + { + lexer.parsing_modifiers = true; + } + | class_member_declarations class_member_declaration + { + lexer.parsing_modifiers = true; + } + ; + +class_member_declaration + : constant_declaration + | field_declaration + | namespace_declaration + | indexer_declaration + | type_declaration + | attributes_without_members + | import_class_directive + | valid_declaration_statement + { + var stmt = $1 as Statement; + if (stmt != null) { + if (!(current_type is Class)) + report.ErrorPlayScript (-20, stmt.loc, "`{0}': Only class containers can contain type initializers"); + + current_type.RegisterInitialization (stmt); + } + } + | error + { + report.Error (1519, lexer.Location, "Unexpected symbol `{0}' in class, struct, or interface member declaration", + GetSymbolName (yyToken)); + $$ = null; + lexer.parsing_generic_declaration = false; + } + ; + +import_class_directive + : opt_attributes + opt_modifiers + import_directive + { + if ($1 != null || (Modifiers) $2 != 0) { + report.Error (7058, GetLocation($1 ?? $2), "Modifiers and attributes not allowed"); + } + } + ; +/* +config_member_declaration + : IDENTIFIER_CONFIG + { + var lt = (LocatedToken) $1; + is_config_enabled = file.IsConditionalDefined (lt.Value.Replace("::","_")); + } + class_member_declaration + { + is_config_enabled = true; + $$ = $3; + } + ; + + +member_config_block + : IDENTIFIER_CONFIG + { + var lt = (LocatedToken) $1; + is_config_enabled = file.IsConditionalDefined (lt.Value.Replace("::","_")); + } + OPEN_BRACE opt_class_member_declarations CLOSE_BRACE + { + is_config_enabled = true; + $$ = $4; + } + ; +*/ +namespace_declaration + : opt_attributes + opt_modifiers + NAMESPACE IDENTIFIER opt_namespace_initializer SEMICOLON + { + var lt = (LocatedToken) $4; + var td = GetTypeDefinition (current_container); + + var ns = new NamespaceField (td, (Modifiers) $2, CreateFullMemberName (lt), (Expression) $5, (Attributes) $1); + td.AddMember (ns); + + if ($5 != null) { + td.RegisterFieldForInitialization (ns, new NamespaceField.NamespaceInitializer (ns, (Expression) $5, GetLocation ($5)), true); + } + } + ; + +opt_namespace_initializer + : /* empty */ + | ASSIGN constant_initializer_expr + { + $$ = $2; + } + ; + +constant_declaration + : opt_attributes + opt_modifiers + CONST IDENTIFIER opt_member_type + { + var lt = (LocatedToken) $4; + var td = GetTypeDefinition (current_container); + if ($5 == null) { + Warning_NoTypeDeclaration (GetLocation ($4), string.Format ("Constant `{0}'", lt.Value)); + $5 = new UntypedTypeExpression (GetLocation ($2)); + } + + current_field = new ConstantField (td, (FullNamedExpression) $5, (Modifiers) $2, CreateFullMemberName (lt), (Attributes) $1); + if (is_config_enabled) { + td.AddMember (current_field); + } + is_config_enabled = true; + + $$ = current_field; + } + opt_const_initializer opt_field_declarators opt_semicolon + { + if (doc_support) { + current_field.DocComment = Lexer.consume_doc_comment (); + Lexer.doc_state = XmlCommentState.Allowed; + } + + lbag.AddMember (current_field, mod_locations, GetLocation ($3), GetLocation ($9)); + current_field = null; + } + ; + +opt_const_initializer + : { + Warning_UninitializedConstant (current_field.Location); + $$ = null; + } + | field_initializer + ; + +field_initializer + : ASSIGN + { + ++lexer.parsing_block; + current_local_parameters = ParametersCompiled.EmptyReadOnlyParameters; + start_block (GetLocation ($1)); + } + variable_initializer + { + --lexer.parsing_block; + current_field.Initializer = (Expression) $3; + + if (!(current_field is ConstantField)) { + var td = GetTypeDefinition (current_container); + td.RegisterFieldForInitialization (current_field, + new FieldInitializer (current_field, (Expression) $3, GetLocation ($1)) { + InlineConstantInitialization = true + }); + } + + end_block (lexer.Location); + current_local_parameters = null; + } + ; + +constant_initializer_expr + : constant_expression + ; + +field_declaration + : opt_attributes + opt_modifiers + VAR IDENTIFIER opt_member_type + { + lexer.parsing_generic_declaration = false; + + var lt = (LocatedToken) $4; + var td = GetTypeDefinition (current_container); + + FullNamedExpression type = (FullNamedExpression) $5; + if (type == null) { + Warning_NoTypeDeclaration (GetLocation ($4), string.Format ("Field `{0}'", lt.Value)); + type = new UntypedTypeExpression (GetLocation ($4)); + } else if (type.Type != null && type.Type.Kind == MemberKind.Void) + report.ErrorPlayScript (1135, GetLocation ($5), "Fields cannot have void type"); + + current_field = new Field (td, type, (Modifiers) $2, CreateFullMemberName (lt), (Attributes) $1); + if (is_config_enabled) { + td.AddField (current_field); + } + is_config_enabled = true; + $$ = current_field; + } + opt_field_initializer + opt_field_declarators + opt_semicolon + { + if (doc_support) { + current_field.DocComment = Lexer.consume_doc_comment (); + Lexer.doc_state = XmlCommentState.Allowed; + } + + lbag.AddMember (current_field, mod_locations, GetLocation ($9)); + $$ = current_field; + current_field = null; + } + ; + +opt_member_type + : /* empty */ + { + $$ = null; + } + | COLON member_type + { + $$ = $2; + } + ; + +opt_field_initializer + : /* empty */ + | field_initializer + ; + +opt_field_declarators + : /* empty */ + | field_declarators + ; + +field_declarators + : field_declarator + { + current_field.AddDeclarator ((FieldDeclarator) $1); + } + | field_declarators field_declarator + { + current_field.AddDeclarator ((FieldDeclarator) $2); + } + ; + +field_declarator + : COMMA IDENTIFIER opt_member_type + { + var lt = (LocatedToken) $2; + var td = GetTypeDefinition (current_container); + if ($3 == null) { + Warning_NoTypeDeclaration (GetLocation ($2), string.Format ("Field `{0}'", lt.Value)); + $3 = new UntypedTypeExpression (GetLocation ($2)); + } + + var field = new Field (td, (TypeExpression) $3, current_field.ModFlags, new MemberName (lt.Value, lt.Location), current_field.OptAttributes); + $$ = new FieldDeclarator (field, new SimpleMemberName (lt.Value, lt.Location), null); + lbag.AddLocation ($$, GetLocation ($1)); + } + | COMMA IDENTIFIER opt_member_type ASSIGN + { + ++lexer.parsing_block; + } + variable_initializer + { + --lexer.parsing_block; + var lt = (LocatedToken) $2; + if ($3 == null) { + Warning_NoTypeDeclaration (GetLocation ($2), string.Format ("Field `{0}'", lt.Value)); + $3 = new UntypedTypeExpression (GetLocation ($2)); + } + + var field = new Field (current_type, (TypeExpression) $3, current_field.ModFlags, new MemberName (lt.Value, lt.Location), current_field.OptAttributes); + $$ = new FieldDeclarator (field, new SimpleMemberName (lt.Value, lt.Location), (Expression) $6); + if (!(current_field is ConstantField)) { + current_type.RegisterFieldForInitialization (field, + new FieldInitializer (field, (Expression) $6, GetLocation ($4)) { + InlineConstantInitialization = true + }); + } + + lbag.AddLocation ($$, GetLocation ($1), GetLocation ($5)); + } + ; + +variable_initializer + : expression + | error + { + // It has to be here for the parent to safely restore artificial block + Error_SyntaxError (yyToken); + $$ = null; + } + ; + +method_declaration + : method_header + { + if (doc_support) + Lexer.doc_state = XmlCommentState.NotAllowed; + + // Add it early in the case of body being eof for full ast + Method m = $1 as Method; + if (m != null) { + async_block = (m.ModFlags & Modifiers.ASYNC) != 0; + if (is_config_enabled) { + GetTypeDefinition (current_container).AddMember (m); + } + is_config_enabled = true; + } + + Constructor c = $1 as Constructor; + if (c != null) { + if (is_config_enabled) { + current_type.AddConstructor (c); + } + is_config_enabled = true; + current_constructor = c; + } + + if (is_package_function) + lexer.DynamicParsing = false; + + } + method_body opt_semicolon + { + if (is_package_function) + lexer.DynamicParsing = true; + + async_block = false; + var top_block = $3 as ToplevelBlock; + + if ($1 is Method) { + var method = (Method) $1; + if ($3 == null) { + method.ParameterInfo.CheckParameters (method); + + if ((method.ModFlags & Modifiers.ASYNC) != 0) { + report.Error (1994, method.Location, "`{0}': The async modifier can only be used with methods that have a body", + method.GetSignatureForError ()); + } + } else { + method.Block = top_block; + + if (current_container.Kind == MemberKind.Interface) { + report.Error (531, method.Location, "`{0}': interface members cannot have a definition", + method.GetSignatureForError ()); + } + } + } else if ($1 is Constructor) { + + Constructor c = (Constructor) $1; + c.Block = top_block; + + if (doc_support) + c.DocComment = ConsumeStoredComment (); + + } else if ($1 is Property.PropertyMethod) { + + Property.PropertyMethod propMethod = (Property.PropertyMethod) $1; + + if ($3 != null) { + propMethod.Block = (ToplevelBlock) $3; + + if (current_container.Kind == MemberKind.Interface) { + report.Error (531, propMethod.Block.StartLocation, + "`{0}': interface members cannot have a definition", propMethod.GetSignatureForError ()); + } + } + } else if ($1 is LocalFunctionDeclaration) { + var lfd = (LocalFunctionDeclaration) $1; + + lfd.Function = (LocalFunction) end_anonymous ((ParametersBlock) $3); + + var li = new LocalVariable (current_block, lfd.Name, 0, lfd.Location); + + INamedBlockVariable existing = null; + if (current_block.ParametersBlock.TopBlock.GetLocalName (lfd.Name, current_block, ref existing)) { + report.ErrorPlayScript (1021, lfd.Location, "Duplicate function `{0}' definition", lfd.Name); + } else { + current_block.AddLocalName (li); + } + + current_block.AddScopeStatement (new UntypedBlockVariable (li, lfd.Location) { + Initializer = lfd.Function + }); + + $$ = lfd; + } + + current_local_parameters = null; + current_property = null; + current_constructor = null; + + is_package_function = false; + + if (doc_support) + Lexer.doc_state = XmlCommentState.Allowed; + } + ; + +method_header + : opt_attributes + opt_modifiers + FUNCTION + method_declaration_name OPEN_PARENS + { + valid_param_mod = ParameterModifierType.All; + + if (current_container is Package) { + is_package_function = true; + } + + } + opt_formal_parameter_list CLOSE_PARENS opt_method_return_type + { + lexer.ConstraintsParsing = true; + } + opt_type_parameter_constraints_clauses + { + lexer.ConstraintsParsing = false; + valid_param_mod = 0; + MemberName name = (MemberName) $4; + current_local_parameters = (ParametersCompiled) $7; + + var modifiers = (Modifiers) $2; + + if (current_type != null && name.Name == current_type.MemberName.Name) { + + if ((modifiers & Modifiers.STATIC) != 0) { + report.ErrorPlayScript (1026, GetLocation ($3), "Constructor functions must be instance methods"); + } + + if ($9 != null && !($9 is UntypedTypeExpression)) { + var rt = $9 as TypeExpression; + if (rt == null || rt.Type.Kind != MemberKind.Void) + report.ErrorPlayScript (1030, GetLocation ($3), "A constructor cannot specify a return type"); + } + + if ((modifiers & (Modifiers.AccessibilityMask & ~Modifiers.PUBLIC)) != 0) { + report.ErrorPlayScript (1153, GetLocation ($3), "A constructor can only be declared public"); + } + + var c = new Constructor (current_type, name.Name, modifiers, Modifiers.PUBLIC, (Attributes) $1, current_local_parameters, name.Location); + + if ($11 != null) { + report.Error (7011, c.Location, + "`{0}': constructor can not have type constraints.", + c.GetSignatureForError ()); + } + + if (doc_support) + c.DocComment = Lexer.consume_doc_comment (); + + lbag.AddMember (c, mod_locations, GetLocation ($5), GetLocation ($8)); + $$ = c; + + } else { + + if ($9 == null) { + Warning_NoTypeDeclaration (GetLocation ($3), string.Format ("Function `{0}'", name.GetSignatureForError ())); + $9 = new UntypedTypeExpression (GetLocation ($3)); + } + + if (current_block != null) { + start_anonymous ((ParametersCompiled) $7, (FullNamedExpression) $9, GetLocation ($3)); + $$ = new LocalFunctionDeclaration (name.Name, name.Location); + + if ((modifiers & Modifiers.OVERRIDE) != 0) { + report.ErrorPlayScript (1010, GetLocation ($3), "The override attribute may be used only on class property definitions"); + } + + if ((modifiers & Modifiers.VIRTUAL) != 0) { + report.ErrorPlayScript (1011, GetLocation ($3), "The virtual attribute may be used only on class property definitions"); + } + + if ((modifiers & Modifiers.STATIC) != 0) { + report.ErrorPlayScript (1012, GetLocation ($3), "The static attribute may be used only on definitions inside a class"); + } + + if ((modifiers & Modifiers.PRIVATE) != 0) { + report.ErrorPlayScript (1013, GetLocation ($3), "The private attribute may be used only on class property definitions"); + } + + if ((modifiers & Modifiers.PUBLIC) != 0) { + report.ErrorPlayScript (1014, GetLocation ($3), "The public attribute may be used only on class or package definitions"); + } + + if ((modifiers & Modifiers.INTERNAL) != 0) { + report.ErrorPlayScript (1015, GetLocation ($3), "The internal attribute may be used only on class or package definitions"); + } + } else { + var method = Method.Create (GetTypeDefinition (current_container), (FullNamedExpression) $9, modifiers, + name, current_local_parameters, (Attributes) $1); + + if ($11 != null) + method.SetConstraints ((List) $11); + + if (doc_support) + method.DocComment = Lexer.consume_doc_comment (); + + lbag.AddMember (method, mod_locations, GetLocation ($5), GetLocation ($8)); + $$ = method; + } + } + } + | opt_attributes + opt_modifiers + FUNCTION_GET method_declaration_name OPEN_PARENS + { + valid_param_mod = ParameterModifierType.All; + } + opt_formal_parameter_list CLOSE_PARENS opt_method_return_type + { + var type = (FullNamedExpression) $9; + var name = (MemberName) $4; + var modifiers = (Modifiers) $2; + var parameters = (ParametersCompiled) $7; + + if (current_container.Kind == MemberKind.Class && name.ExplicitInterface == null && + (modifiers & (Modifiers.NEW | Modifiers.SEALED | Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) == 0) + modifiers |= Modifiers.VIRTUAL; + + if (parameters != null && parameters.Count > 0) + report.Error (7016, GetLocation ($3), "Property getter functions may not have parameters"); + + current_property = null; + + MemberCore member; + if (current_type.DefinedNames.TryGetValue(name.Name, out member)) { + current_property = member as Property; + } + + if (current_property == null) { + current_property = new Property (current_type, type, modifiers, name, (Attributes) $1); + if (is_config_enabled) { + current_type.AddMember (current_property); + } + is_config_enabled = true; + modifiers = (Modifiers) 0; + } else { +// if (!type.Equals(current_property.TypeExpression)) { +// report.Error (7002, GetLocation ($10), "Type of property getter and setter must match", current_property.GetSignatureForError ()); +// } + if (current_property.Set != null && ModifiersExtensions.IsRestrictedModifier (current_property.ModFlags & Modifiers.AccessibilityMask, modifiers & Modifiers.AccessibilityMask)) { + current_property.Set.ModFlags |= current_property.ModFlags & Modifiers.AccessibilityMask; + current_property.ModFlags = (current_property.ModFlags & ~Modifiers.AccessibilityMask) | (modifiers & Modifiers.AccessibilityMask); + modifiers = (Modifiers) 0; + } else if ((modifiers & Modifiers.AccessibilityMask) == (current_property.ModFlags & Modifiers.AccessibilityMask)) { + modifiers = (Modifiers) 0; + } + } + + if (type.Type != null && type.Type.Kind == MemberKind.Void) + report.Error (547, GetLocation ($3), "`{0}': property or indexer cannot have void type", current_property.GetSignatureForError ()); + + if (current_property.Get != null) { + report.Error (1007, GetLocation ($3), "Property accessor already defined"); + } + + current_property.Get = new Property.GetMethod (current_property, + modifiers & Modifiers.AccessibilityMask, (Attributes) $1, GetLocation ($3)); + + lbag.AddMember (current_property, mod_locations, GetLocation ($9)); + current_local_parameters = current_property.Get.ParameterInfo; + $$ = current_property.Get; + } + | opt_attributes + opt_modifiers + FUNCTION_SET method_declaration_name OPEN_PARENS + { + valid_param_mod = ParameterModifierType.All; + } + opt_formal_parameter_list CLOSE_PARENS opt_method_return_type + { + var void_type = (FullNamedExpression) $9; + var name = (MemberName) $4; + var modifiers = (Modifiers) $2; + var parameters = (ParametersCompiled) $7; + + if (current_container.Kind == MemberKind.Class && name.ExplicitInterface == null && + (modifiers & (Modifiers.NEW | Modifiers.SEALED | Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) == 0) + modifiers |= Modifiers.VIRTUAL; + + if (void_type.Type != null && void_type.Type.Kind != MemberKind.Void) + report.Error (7003, GetLocation ($3), "Property setter function must not be of type void"); + + current_property = null; + + MemberCore member; + if (current_type.DefinedNames.TryGetValue(name.Name, out member)) { + current_property = member as Property; + } + + FullNamedExpression type; + + if (parameters == null || parameters.Count != 1 || parameters.FixedParameters.Length != parameters.Count) { + report.Error (7001, GetLocation ($7), "Property setter must have a single parameter"); + type = new TypeExpression (compiler.BuiltinTypes.Int, GetLocation ($7)); + } else { + type = ((Parameter)parameters.FixedParameters[0]).TypeExpression; + } + + if (current_property == null) { + current_property = new Property (current_type, type, modifiers, name, (Attributes) $1); + if (is_config_enabled) { + current_type.AddMember (current_property); + } + is_config_enabled = true; + modifiers = (Modifiers) 0; + } else { +// if (!type.Equals(current_property.TypeExpression)) { +// report.Error (7002, GetLocation ($10), "Type of property getter and setter must match", current_property.GetSignatureForError ()); +// } + if (current_property.Get != null && ModifiersExtensions.IsRestrictedModifier (current_property.ModFlags & Modifiers.AccessibilityMask, modifiers & Modifiers.AccessibilityMask)) { + current_property.Get.ModFlags |= current_property.ModFlags & Modifiers.AccessibilityMask; + current_property.ModFlags = (current_property.ModFlags & ~Modifiers.AccessibilityMask) | (modifiers & Modifiers.AccessibilityMask); + modifiers = (Modifiers) 0; + } else if ((modifiers & Modifiers.AccessibilityMask) == (current_property.ModFlags & Modifiers.AccessibilityMask)) { + modifiers = (Modifiers) 0; + } + } + + if (current_property.Set != null) { + report.Error (1007, GetLocation ($3), "Property accessor already defined"); + } + + current_property.Set = new Property.SetMethod (current_property, + modifiers & Modifiers.AccessibilityMask, (ParametersCompiled) $7, (Attributes) $1, GetLocation ($3)); + + lbag.AddMember (current_property, mod_locations, GetLocation ($9)); + current_local_parameters = parameters; + $$ = current_property.Set; + } + | opt_attributes + opt_modifiers + FUNCTION + modifiers method_declaration_name OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS opt_method_return_type + { + MemberName name = (MemberName) $5; + report.Error (1585, name.Location, + "Member modifier `{0}' must precede the member type and name", ModifiersExtensions.Name ((Modifiers) $4)); + + var method = Method.Create (GetTypeDefinition (current_container), (FullNamedExpression) $1, + 0, name, (ParametersCompiled) $7, (Attributes) $1); + + current_local_parameters = (ParametersCompiled) $7; + + if (doc_support) + method.DocComment = Lexer.consume_doc_comment (); + + $$ = method; + } + | opt_attributes + opt_modifiers + FUNCTION + method_declaration_name error + { + Error_SyntaxError (yyToken); + current_local_parameters = ParametersCompiled.Undefined; + + MemberName name = (MemberName) $4; + var method = Method.Create (GetTypeDefinition (current_container), new TypeExpression (compiler.BuiltinTypes.Void, GetLocation ($4)), (Modifiers) $2, + name, current_local_parameters, (Attributes) $1); + + if (doc_support) + method.DocComment = Lexer.consume_doc_comment (); + + $$ = method; + } + ; + +opt_method_return_type + : /* empty */ + | method_colon member_type + { + $$ = $2; + } + ; + +method_colon + : COLON + { + if (current_container.Kind == MemberKind.Interface) + Lexer.AutoSemiInsertion = true; + } + ; + +method_body + : block + | SEMICOLON + { + // method body. + $$ = null; + } + ; + +opt_formal_parameter_list + : /* empty */ { $$ = ParametersCompiled.EmptyReadOnlyParameters; } + | formal_parameter_list + ; + +formal_parameter_list + : fixed_parameters + { + var pars_list = (List) $1; + $$ = new ParametersCompiled (pars_list.ToArray ()); + } + | fixed_parameters COMMA parameter_array + { + var pars_list = (List) $1; + pars_list.Add ((Parameter) $3); + + $$ = new ParametersCompiled (pars_list.ToArray ()); + } + | parameter_array COMMA error + { + if ($1 != null) + report.Error (231, ((Parameter) $1).Location, "A params parameter must be the last parameter in a formal parameter list"); + + $$ = new ParametersCompiled (new Parameter[] { (Parameter) $1 } ); + } + | fixed_parameters COMMA parameter_array COMMA error + { + if ($3 != null) + report.Error (231, ((Parameter) $3).Location, "A params parameter must be the last parameter in a formal parameter list"); + + var pars_list = (List) $1; + pars_list.Add (new ArglistParameter (GetLocation ($3))); + + $$ = new ParametersCompiled (pars_list.ToArray (), true); + } + | parameter_array + { + $$ = new ParametersCompiled (new Parameter[] { (Parameter) $1 } ); + } + | error + { + Error_SyntaxError (yyToken); + $$ = ParametersCompiled.EmptyReadOnlyParameters; + } + ; + +fixed_parameters + : fixed_parameter + { + parameters_bucket.Clear (); + Parameter p = (Parameter) $1; + parameters_bucket.Add (p); + + default_parameter_used = p.HasDefaultValue; + $$ = parameters_bucket; + } + | fixed_parameters COMMA fixed_parameter + { + var pars = (List) $1; + Parameter p = (Parameter) $3; + if (p != null) { + if (p.HasExtensionMethodModifier) + report.Error (1100, p.Location, "The parameter modifier `this' can only be used on the first parameter"); + else if (!p.HasDefaultValue && default_parameter_used) + report.Error (1737, p.Location, "Optional parameter cannot precede required parameters"); + + default_parameter_used |= p.HasDefaultValue; + pars.Add (p); + + lbag.AddLocation (p, GetLocation ($2)); + } + + $$ = $1; + } + ; + +fixed_parameter + : opt_attributes + opt_parameter_modifier + IDENTIFIER + opt_parameter_type + { + var lt = (LocatedToken) $3; + if ($4 == null) { + Warning_NoTypeDeclaration (GetLocation ($3), string.Format ("Parameter `{0}'", lt.Value)); + $4 = new UntypedTypeExpression (GetLocation ($3)); + } + + $$ = new Parameter ((FullNamedExpression) $4, lt.Value, (Parameter.Modifier) $2, (Attributes) $1, lt.Location); + } + | attribute_sections error + { + Error_SyntaxError (yyToken); + Location l = GetLocation ($2); + $$ = new Parameter (null, null, Parameter.Modifier.NONE, (Attributes) $1, l); + } + | opt_attributes + opt_parameter_modifier + IDENTIFIER + COLON + error + { + Error_SyntaxError (yyToken); + Location l = GetLocation ($5); + var lt = (LocatedToken) $3; + $$ = new Parameter (new TypeExpression (compiler.BuiltinTypes.Object, GetLocation ($5)), lt.Value, (Parameter.Modifier) $2, (Attributes) $1, l); + } + | opt_attributes + opt_parameter_modifier + IDENTIFIER + opt_parameter_type + ASSIGN + { + ++lexer.parsing_block; + } + constant_expression + { + --lexer.parsing_block; + + Parameter.Modifier mod = (Parameter.Modifier) $2; + if (mod != Parameter.Modifier.NONE) { + switch (mod) { + case Parameter.Modifier.REF: + case Parameter.Modifier.OUT: + report.Error (1741, GetLocation ($2), "Cannot specify a default value for the `{0}' parameter", + Parameter.GetModifierSignature (mod)); + break; + + case Parameter.Modifier.This: + report.Error (1743, GetLocation ($2), "Cannot specify a default value for the `{0}' parameter", + Parameter.GetModifierSignature (mod)); + break; + default: + throw new NotImplementedException (mod.ToString ()); + } + + mod = Parameter.Modifier.NONE; + } + + if ((valid_param_mod & ParameterModifierType.DefaultValue) == 0) + report.Error (1065, GetLocation ($6), "Optional parameter is not valid in this context"); + + var lt = (LocatedToken) $3; + if ($4 == null) { + Warning_NoTypeDeclaration (GetLocation ($3), string.Format ("Parameter `{0}'", lt.Value)); + $4 = new UntypedTypeExpression (GetLocation ($3)); + } + + $$ = new Parameter ((FullNamedExpression) $4, lt.Value, mod, (Attributes) $1, lt.Location); + lbag.AddLocation ($$, GetLocation ($6)); + + if ($7 != null) + ((Parameter) $$).DefaultValue = new DefaultParameterValueExpression ((Expression) $7); + } + ; + +opt_parameter_modifier + : /* empty */ { $$ = Parameter.Modifier.NONE; } + | parameter_modifiers + ; + +parameter_modifiers + : parameter_modifier + { + $$ = $1; + } + | parameter_modifiers parameter_modifier + { + Parameter.Modifier p2 = (Parameter.Modifier)$2; + Parameter.Modifier mod = (Parameter.Modifier)$1 | p2; + if (((Parameter.Modifier)$1 & p2) == p2) { + Error_DuplicateParameterModifier (lexer.Location, p2); + } else { + switch (mod & ~Parameter.Modifier.This) { + case Parameter.Modifier.REF: + report.Error (1101, lexer.Location, "The parameter modifiers `this' and `ref' cannot be used altogether"); + break; + case Parameter.Modifier.OUT: + report.Error (1102, lexer.Location, "The parameter modifiers `this' and `out' cannot be used altogether"); + break; + default: + report.Error (1108, lexer.Location, "A parameter cannot have specified more than one modifier"); + break; + } + } + $$ = mod; + } + ; + +parameter_modifier + : REF + { + if ((valid_param_mod & ParameterModifierType.Ref) == 0) + Error_ParameterModifierNotValid ("ref", GetLocation ($1)); + + $$ = Parameter.Modifier.REF; + } + | OUT + { + if ((valid_param_mod & ParameterModifierType.Out) == 0) + Error_ParameterModifierNotValid ("out", GetLocation ($1)); + + $$ = Parameter.Modifier.OUT; + } + | THIS + { + if ((valid_param_mod & ParameterModifierType.This) == 0) + Error_ParameterModifierNotValid ("this", GetLocation ($1)); + + if (lang_version <= LanguageVersion.ISO_2) + FeatureIsNotAvailable (GetLocation ($1), "extension methods"); + + $$ = Parameter.Modifier.This; + } + ; + +parameter_array + : opt_attributes DOTDOTDOT IDENTIFIER opt_rest_parameter_type + { + var lt = (LocatedToken) $3; + $$ = new RestArrayParameter (lt.Value, (Attributes) $1, lt.Location); + } + | opt_attributes DOTDOTDOT error + { + Error_SyntaxError (yyToken); + $$ = null; + } + ; + +opt_parameter_type + : /* empty */ + | COLON parameter_type + { + $$ = $2; + } + ; + +opt_rest_parameter_type + : /* empty */ + | COLON IDENTIFIER + { + var lt = (LocatedToken) $2; + + // TODO: Do I need to resolve the type for correct checking + if (lt.Value != "Array") + report.ErrorPlayScript (1140, GetLocation ($2), "Parameters specified after the ...rest parameter definition keyword can only be an Array data type"); + } + ; + +indexer_declaration + : opt_attributes opt_modifiers + INDEXER indexer_declaration_name OPEN_PARENS + { + valid_param_mod = ParameterModifierType.Params | ParameterModifierType.DefaultValue; + } + opt_formal_parameter_list CLOSE_PARENS COLON member_type OPEN_BRACE + { + valid_param_mod = 0; + var type = (FullNamedExpression) $10; + + var modifiers = (Modifiers) $2; + + var name = (MemberName) $4; + + if (current_container.Kind == MemberKind.Class && name.ExplicitInterface == null && + (modifiers & (Modifiers.NEW | Modifiers.SEALED | Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) == 0) + modifiers |= Modifiers.VIRTUAL; + + Indexer indexer = new Indexer (current_type, type, name, modifiers, (ParametersCompiled) $7, (Attributes) $1); + + current_property = indexer; + + if (is_config_enabled) { + current_type.AddIndexer (indexer); + } + is_config_enabled = true; + lbag.AddMember (current_property, mod_locations, GetLocation ($5), GetLocation ($8)); + + if (type.Type != null && type.Type.Kind == MemberKind.Void) + report.Error (620, GetLocation ($3), "`{0}': indexer return type cannot be `void'", indexer.GetSignatureForError ()); + + if (indexer.ParameterInfo.IsEmpty) { + report.Error (1551, GetLocation ($5), "Indexers must have at least one parameter"); + } + + if (doc_support) { + tmpComment = Lexer.consume_doc_comment (); + Lexer.doc_state = XmlCommentState.Allowed; + } + + lexer.PropertyParsing = true; + } + accessor_declarations + { + lexer.PropertyParsing = false; + } + CLOSE_BRACE + { + CheckIsPlayScript("indexer", GetLocation($3)); + + if (current_property.AccessorFirst != null && current_property.AccessorFirst.Block == null) + ((Indexer) current_property).ParameterInfo.CheckParameters (current_property); + + if (doc_support) + current_property.DocComment = ConsumeStoredComment (); + + lbag.AppendToMember (current_property, GetLocation ($12)); + current_property = null; + } + ; + + +accessor_declarations + : get_accessor_declaration + | get_accessor_declaration accessor_declarations + | set_accessor_declaration + | set_accessor_declaration accessor_declarations + | error + { + if (yyToken == Token.CLOSE_BRACE) { + report.Error (548, lexer.Location, "`{0}': property or indexer must have at least one accessor", current_property.GetSignatureForError ()); + } else { + if (yyToken == Token.SEMICOLON) + report.Error (1597, lexer.Location, "Semicolon after method or accessor block is not valid"); + else + report.Error (1014, GetLocation ($1), "A get or set accessor expected"); + } + } + ; + +get_accessor_declaration + : opt_attributes opt_modifiers GET + { + if ($2 != ModifierNone && lang_version == LanguageVersion.ISO_1) { + FeatureIsNotAvailable (GetLocation ($2), "access modifiers on properties"); + } + + if (current_property.Get != null) { + report.Error (1007, GetLocation ($3), "Property accessor already defined"); + } + + if (current_property is Indexer) { + current_property.Get = new Indexer.GetIndexerMethod (current_property, (Modifiers) $2, ((Indexer)current_property).ParameterInfo.Clone (), + (Attributes) $1, GetLocation ($3)); + } else { + current_property.Get = new Property.GetMethod (current_property, + (Modifiers) $2, (Attributes) $1, GetLocation ($3)); + } + + current_local_parameters = current_property.Get.ParameterInfo; + lbag.AddMember (current_property.Get, mod_locations); + lexer.PropertyParsing = false; + } + accessor_body + { + if ($5 != null) { + current_property.Get.Block = (ToplevelBlock) $5; + + if (current_container.Kind == MemberKind.Interface) { + report.Error (531, current_property.Get.Block.StartLocation, + "`{0}': interface members cannot have a definition", current_property.Get.GetSignatureForError ()); + } + } + + current_local_parameters = null; + lexer.PropertyParsing = true; + + if (doc_support) + if (Lexer.doc_state == XmlCommentState.Error) + Lexer.doc_state = XmlCommentState.NotAllowed; + } + ; + +set_accessor_declaration + : opt_attributes opt_modifiers SET + { + if ($2 != ModifierNone && lang_version == LanguageVersion.ISO_1) { + FeatureIsNotAvailable (GetLocation ($2), "access modifiers on properties"); + } + + if (current_property.Set != null) { + report.Error (1007, GetLocation ($3), "Property accessor already defined"); + } + + if (current_property is Indexer) { + current_property.Set = new Indexer.SetIndexerMethod (current_property, (Modifiers) $2, + ParametersCompiled.MergeGenerated (compiler, + ((Indexer)current_property).ParameterInfo, true, new Parameter ( + current_property.TypeExpression, "value", Parameter.Modifier.NONE, null, GetLocation ($3)), + null), + (Attributes) $1, GetLocation ($3)); + } else { + current_property.Set = new Property.SetMethod (current_property, (Modifiers) $2, + ParametersCompiled.CreateImplicitParameter (current_property.TypeExpression, GetLocation ($3)), + (Attributes) $1, GetLocation ($3)); + } + + current_local_parameters = current_property.Set.ParameterInfo; + lbag.AddMember (current_property.Set, mod_locations); + lexer.PropertyParsing = false; + } + accessor_body + { + if ($5 != null) { + current_property.Set.Block = (ToplevelBlock) $5; + + if (current_container.Kind == MemberKind.Interface) { + report.Error (531, current_property.Set.Block.StartLocation, + "`{0}': interface members cannot have a definition", current_property.Set.GetSignatureForError ()); + } + } + + current_local_parameters = null; + lexer.PropertyParsing = true; + + if (doc_support + && Lexer.doc_state == XmlCommentState.Error) + Lexer.doc_state = XmlCommentState.NotAllowed; + } + ; + +accessor_body + : block + | SEMICOLON + { + // TODO: lbag + $$ = null; + } + | error + { + Error_SyntaxError (1043, yyToken, "Invalid accessor body"); + $$ = null; + } + ; + +interface_declaration + : opt_attributes + opt_modifiers + opt_partial + INTERFACE + { + lexer.ConstraintsParsing = true; + Lexer.AutoSemiInsertion = false; + } + type_declaration_name + { + bool is_partial = IsPartial($1) || $3 != null; + push_current_container (new Interface (current_container, (MemberName) $6, (Modifiers) $2, (Attributes) $1), is_partial); + lbag.AddMember (current_container, mod_locations, GetLocation ($4)); + } + opt_class_extends + opt_class_implements + opt_type_parameter_constraints_clauses + { + lexer.ConstraintsParsing = false; + + if ($10 != null) + current_container.SetConstraints ((List) $10); + + if (doc_support) { + current_container.PartialContainer.DocComment = Lexer.consume_doc_comment (); + Lexer.doc_state = XmlCommentState.Allowed; + } + + lexer.parsing_modifiers = true; + } + OPEN_BRACE + { + Lexer.AutoSemiInsertion = true; + } + opt_interface_member_declarations CLOSE_BRACE opt_semicolon + { + --lexer.parsing_declaration; + if (doc_support) + Lexer.doc_state = XmlCommentState.Allowed; + + lbag.AppendToMember (current_container, GetLocation ($12), GetLocation ($15)); + $$ = pop_current_class (); + } + | opt_attributes opt_modifiers opt_partial INTERFACE error + { + Error_SyntaxError (yyToken); + } + ; + +opt_interface_member_declarations + : /* empty */ + | interface_member_declarations + ; + +interface_member_declarations + : interface_member_declaration + { + lexer.parsing_modifiers = true; + } + | interface_member_declarations interface_member_declaration + { + lexer.parsing_modifiers = true; + } + ; + +interface_member_declaration + : constant_declaration + { + report.Error (525, GetLocation ($1), "Interfaces cannot contain fields or constants"); + } + | field_declaration + { + report.Error (525, GetLocation ($1), "Interfaces cannot contain fields or constants"); + } + | method_declaration + | indexer_declaration + | type_declaration + { + report.Error (524, GetLocation ($1), "Interfaces cannot declare classes, structs, interfaces, delegates, or enumerations"); + } + ; + +conversion_operator_declarator + : IMPLICIT OPERATOR type OPEN_PARENS + { + valid_param_mod = ParameterModifierType.DefaultValue; + } + opt_formal_parameter_list CLOSE_PARENS + { + valid_param_mod = 0; + + Location loc = GetLocation ($2); + current_local_parameters = (ParametersCompiled)$6; + + if (doc_support) { + tmpComment = Lexer.consume_doc_comment (); + Lexer.doc_state = XmlCommentState.NotAllowed; + } + + $$ = new OperatorDeclaration (Operator.OpType.Implicit, (FullNamedExpression) $3, loc); + lbag.AddLocation ($$, GetLocation ($1), GetLocation ($2), GetLocation ($4), GetLocation ($7)); + } + | EXPLICIT OPERATOR type OPEN_PARENS + { + valid_param_mod = ParameterModifierType.DefaultValue; + } + opt_formal_parameter_list CLOSE_PARENS + { + valid_param_mod = 0; + + Location loc = GetLocation ($2); + current_local_parameters = (ParametersCompiled)$6; + + if (doc_support) { + tmpComment = Lexer.consume_doc_comment (); + Lexer.doc_state = XmlCommentState.NotAllowed; + } + + $$ = new OperatorDeclaration (Operator.OpType.Explicit, (FullNamedExpression) $3, loc); + lbag.AddLocation ($$, GetLocation ($1), GetLocation ($2), GetLocation ($4), GetLocation ($7)); + } + | IMPLICIT error + { + Error_SyntaxError (yyToken); + current_local_parameters = ParametersCompiled.EmptyReadOnlyParameters; + $$ = new OperatorDeclaration (Operator.OpType.Implicit, null, GetLocation ($1)); + } + | EXPLICIT error + { + Error_SyntaxError (yyToken); + current_local_parameters = ParametersCompiled.EmptyReadOnlyParameters; + $$ = new OperatorDeclaration (Operator.OpType.Explicit, null, GetLocation ($1)); + } + ; + + +attributes_without_members + : attribute_sections CLOSE_BRACE + { + current_type.UnattachedAttributes = (Attributes) $1; + report.Error (1519, GetLocation ($1), "An attribute is missing member declaration"); + lexer.putback ('}'); + } + ; + +opt_nullable + : /* empty */ + | INTERR_NULLABLE + { + if (lang_version < LanguageVersion.ISO_2) + FeatureIsNotAvailable (GetLocation ($1), "nullable types"); + + $$ = ComposedTypeSpecifier.CreateNullable (GetLocation ($1)); + } + ; + +namespace_or_type_expr + : member_name +/* + | qualified_identifier IDENTIFIER opt_type_argument_list + { + var lt1 = (LocatedToken) $1; + var lt2 = (LocatedToken) $2; + + $$ = new QualifiedMemberAccess (lt1.Value, lt2.Value, lt1.Location); + lbag.AddLocation ($$, GetLocation ($2)); + } +*/ + ; + +member_name + : simple_name_expr + | namespace_or_type_expr DOT IDENTIFIER opt_type_argument_list + { + // member_name + var lt = (LocatedToken) $3; + $$ = new MemberAccess ((Expression) $1, lt.Value, (TypeArguments) $4, lt.Location); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +simple_name_expr + : IDENTIFIER opt_type_argument_list + { + // simple_name_expr + var lt = (LocatedToken) $1; + $$ = new SimpleName (lt.Value, (TypeArguments)$2, lt.Location); + } + ; + +// +// Generics arguments (any type, without attributes) +// +opt_type_argument_list + : /* empty */ + | OP_GENERICS_LT type_arguments OP_GENERICS_GT + { + if (lang_version < LanguageVersion.ISO_2) + FeatureIsNotAvailable (GetLocation ($1), "generics"); + + $$ = $2; + } + | OP_GENERICS_LT error + { + Error_TypeExpected (lexer.Location); + $$ = new TypeArguments (); + } + ; + +type_arguments + : type + { + TypeArguments type_args = new TypeArguments (); + type_args.Add ((FullNamedExpression) $1); + $$ = type_args; + } + | type_arguments COMMA type + { + TypeArguments type_args = (TypeArguments) $1; + type_args.Add ((FullNamedExpression) $3); + $$ = type_args; + } + ; + +// +// Generics parameters (identifiers only, with attributes), used in type or method declarations +// +type_declaration_name + : IDENTIFIER + { +// lexer.parsing_generic_declaration = true; +// } +// opt_type_parameter_list +// { +// lexer.parsing_generic_declaration = false; + var lt = (LocatedToken) $1; + $$ = CreateFullMemberName (lt, null); + } + ; + +member_declaration_name + : method_declaration_name + { + MemberName mn = (MemberName)$1; + if (mn.TypeParameters != null) + syntax_error (mn.Location, string.Format ("Member `{0}' cannot declare type arguments", + mn.GetSignatureForError ())); + } + ; + +method_declaration_name + : type_declaration_name +/* + | explicit_interface IDENTIFIER opt_type_parameter_list + { + lexer.parsing_generic_declaration = false; + var lt = (LocatedToken) $2; + $$ = new MemberName (lt.Value, (TypeParameters) $3, (ATypeNameExpression) $1, lt.Location); + } +*/ + ; + +indexer_declaration_name + : THIS + { + lexer.parsing_generic_declaration = false; + $$ = new MemberName (TypeDefinition.DefaultIndexerName, GetLocation ($1)); + } +/* + | explicit_interface THIS + { + lexer.parsing_generic_declaration = false; + $$ = new MemberName (TypeDefinition.DefaultIndexerName, null, (ATypeNameExpression) $1, GetLocation ($2)); + } +*/ + ; + +// +// All types where void is allowed +// +type_and_void + : type_expression_or_array + | VOID + { + $$ = new TypeExpression (compiler.BuiltinTypes.Void, GetLocation ($1)); + } + ; + +member_type + : type_and_void + { + lexer.parsing_generic_declaration = true; + } + ; + +// +// A type which does not allow `void' to be used +// +type + : type_expression_or_array + | VOID + { + Expression.Error_VoidInvalidInTheContext (GetLocation ($1), report); + $$ = new TypeExpression (compiler.BuiltinTypes.Void, GetLocation ($1)); + } + ; + +simple_type + : type_expression + | VOID + { + Expression.Error_VoidInvalidInTheContext (GetLocation ($1), report); + $$ = new TypeExpression (compiler.BuiltinTypes.Void, GetLocation ($1)); + } + ; + +parameter_type + : type_expression_or_array + | VOID + { + report.Error (1536, GetLocation ($1), "Invalid parameter type `void'"); + $$ = new TypeExpression (compiler.BuiltinTypes.Void, GetLocation ($1)); + } + ; + +type_expression_or_array + : type_expression + | type_expression rank_specifiers + { + CheckIsPlayScript("arrays", GetLocation($2)); + $$ = new ComposedCast ((FullNamedExpression) $1, (ComposedTypeSpecifier) $2); + } + ; + +type_expression + : namespace_or_type_expr opt_nullable + { + if ($2 != null) { + $$ = new ComposedCast ((ATypeNameExpression) $1, (ComposedTypeSpecifier) $2); + } else { +// var sn = $1 as SimpleName; +// if (sn != null) +// $$ = ConvertAsType(sn, $1); +// else + $$ = $1; + } + } + | STAR + { + $$ = new UntypedTypeExpression (GetLocation ($1)); + } +// | namespace_or_type_expr pointer_stars +// { +// $$ = new ComposedCast ((ATypeNameExpression) $1, (ComposedTypeSpecifier) $2); +// } + | builtin_types opt_nullable + { + if ($2 != null) + $$ = new ComposedCast ((FullNamedExpression) $1, (ComposedTypeSpecifier) $2); + } +// | builtin_types pointer_stars +// { +// $$ = new ComposedCast ((FullNamedExpression) $1, (ComposedTypeSpecifier) $2); +// } +// | VOID pointer_stars +// { +// $$ = new ComposedCast (new TypeExpression (compiler.BuiltinTypes.Void, GetLocation ($1)), (ComposedTypeSpecifier) $2); +// } + ; + +type_list + : base_type_name + { + var types = new List (2); + types.Add ((FullNamedExpression) $1); + $$ = types; + } + | type_list COMMA base_type_name + { + var types = (List) $1; + types.Add ((FullNamedExpression) $3); + $$ = types; + } + ; + +base_type_name + : type + { + if ($1 is ComposedCast) { + report.Error (1521, GetLocation ($1), "Invalid base type `{0}'", ((ComposedCast)$1).GetSignatureForError ()); + } + $$ = $1; + } + ; + +/* + * replaces all the productions for isolating the various + * simple types, but we need this to reuse it easily in variable_type + */ +builtin_types + : INT { $$ = new TypeExpression (compiler.BuiltinTypes.Int, GetLocation ($1)); } + | UINT { $$ = new TypeExpression (compiler.BuiltinTypes.UInt, GetLocation ($1)); } + ; + +// +// Expressions, section 7.5 +// + + +primary_expression + : primary_expression_or_type + | literal +// | array_creation_expression + | parenthesized_expression + | default_value_expression + | invocation_expression + | element_access + | this_access + | base_access + | post_increment_expression + | post_decrement_expression + | new_expression + | function_block + | array_creation + | object_initializer + | e4x_operators + | expression_series + | builtin_types + ; + +expression_series + : OPEN_PARENS_EXPR_LIST expression_list CLOSE_PARENS + { + $$ = new ExpressionSeries ((List)$2, GetLocation ($1)); + } + ; + +primary_expression_or_type + : IDENTIFIER opt_type_argument_list + { + // primary_expression_or_type + var lt = (LocatedToken) $1; + $$ = new SimpleName (lt.Value, (TypeArguments)$2, lt.Location); + } + | IDENTIFIER GENERATE_COMPLETION { + var lt = (LocatedToken) $1; + $$ = new CompletionSimpleName (MemberName.MakeName (lt.Value, null), lt.Location); + } + | member_access + ; + +literal + : boolean_literal + | LITERAL + | NULL { $$ = new NullLiteral (GetLocation ($1)); } + ; + +boolean_literal + : TRUE { $$ = new BoolLiteral (compiler.BuiltinTypes, true, GetLocation ($1)); } + | FALSE { $$ = new BoolLiteral (compiler.BuiltinTypes, false, GetLocation ($1)); } + ; + + +// +// Here is the trick, tokenizer may think that parens is a special but +// parser is interested in open parens only, so we merge them. +// Consider: if (a)foo (); +// +open_parens_any + : OPEN_PARENS +// | OPEN_PARENS_EXPR_LIST + ; + +// +// Use this production to accept closing parenthesis or +// performing completion +// +close_parens + : CLOSE_PARENS + | COMPLETE_COMPLETION + ; + + +parenthesized_expression + : OPEN_PARENS expression CLOSE_PARENS + { + $$ = new ParenthesizedExpression ((Expression) $2, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($1), GetLocation ($3)); + } + | OPEN_PARENS expression COMPLETE_COMPLETION + { + $$ = new ParenthesizedExpression ((Expression) $2, GetLocation ($1)); + } + ; + +member_access + : primary_expression DOT identifier_inside_body opt_type_argument_list + { + var lt = (LocatedToken) $3; + $$ = new MemberAccess ((Expression) $1, lt.Value, (TypeArguments) $4, lt.Location); + lbag.AddLocation ($$, GetLocation ($2)); + } +// | builtin_types DOT identifier_inside_body opt_type_argument_list +// { +// var lt = (LocatedToken) $3; +// $$ = new MemberAccess ((Expression) $1, lt.Value, (TypeArguments) $4, lt.Location); +// lbag.AddLocation ($$, GetLocation ($2)); +// } + | SUPER DOT IDENTIFIER opt_type_argument_list + { + var lt = (LocatedToken) $3; + $$ = new MemberAccess (new BaseThis (GetLocation ($1)), lt.Value, (TypeArguments) $4, lt.Location); + lbag.AddLocation ($$, GetLocation ($2)); + } + | IDENTIFIER DOUBLE_COLON identifier_inside_body + { + var lt1 = (LocatedToken) $1; + var lt2 = (LocatedToken) $3; + + $$ = new QualifiedMemberAccess (null, lt1.Value, lt2.Value, lt1.Location); + lbag.AddLocation ($$, GetLocation ($2)); + } + | primary_expression DOT identifier_inside_body DOUBLE_COLON identifier_inside_body + { + var lt1 = (LocatedToken) $3; + var lt2 = (LocatedToken) $5; + + $$ = new QualifiedMemberAccess ((Expression) $1, lt1.Value, lt2.Value, lt1.Location); + lbag.AddLocation ($$, GetLocation ($2)); + } + | primary_expression DOT GENERATE_COMPLETION { + $$ = new CompletionMemberAccess ((Expression) $1, null,GetLocation ($3)); + } + | primary_expression DOT IDENTIFIER GENERATE_COMPLETION { + var lt = (LocatedToken) $3; + $$ = new CompletionMemberAccess ((Expression) $1, lt.Value, lt.Location); + } +// | builtin_types DOT GENERATE_COMPLETION +// { +// $$ = new CompletionMemberAccess ((Expression) $1, null, lexer.Location); +// } +// | builtin_types DOT IDENTIFIER GENERATE_COMPLETION { +// var lt = (LocatedToken) $3; +// $$ = new CompletionMemberAccess ((Expression) $1, lt.Value, lt.Location); +// } + ; + +e4x_operators + : primary_expression DOT_AT IDENTIFIER + { + var lt = (LocatedToken) $3; + var ma = new E4XOperator (E4XOperator.Operator.ChildAttribute, (Expression) $1, lt.Value, lt.Location); + lbag.AddLocation ($$, GetLocation ($2)); + $$ = ma; + } + | primary_expression DOT_STAR + { + var ma = new E4XOperator (E4XOperator.Operator.ChildAll, (Expression) $1, "any", GetLocation ($2)); + lbag.AddLocation ($$, GetLocation ($2)); + $$ = ma; + } + | primary_expression DOTDOT IDENTIFIER + { + var lt = (LocatedToken) $3; + var ma = new E4XOperator (E4XOperator.Operator.Descendant, (Expression) $1, lt.Value, lt.Location); + lbag.AddLocation ($$, GetLocation ($2)); + $$ = ma; + } + | primary_expression DOTDOT_STAR + { + var ma = new E4XOperator (E4XOperator.Operator.DescendantAll, (Expression) $1, "any", GetLocation ($2)); + lbag.AddLocation ($$, GetLocation ($2)); + $$ = ma; + } +/* + | primary_expression DOUBLE_COLON IDENTIFIER + { + var lt = (LocatedToken) $3; + var ma = new E4XOperator (E4XOperator.Operator.Namespace, (Expression) $1, lt.Value, lt.Location); + lbag.AddLocation ($$, GetLocation ($2)); + $$ = ma; + } + | primary_expression DOUBLE_COLON OPEN_BRACKET_EXPR expression_list_arguments CLOSE_BRACKET + { + var ea = new E4XIndexer (E4XIndexer.Operator.Namespace, (Expression) $1, (Arguments) $4, GetLocation ($3)); + lbag.AddLocation (GetLocation ($3), GetLocation ($5)); + $$ = ea; + } +*/ + | primary_expression DOT_AT OPEN_BRACKET_EXPR expression_list_arguments CLOSE_BRACKET + { + var ea = new E4XIndexer (E4XIndexer.Operator.Attribute, (Expression) $1, (Arguments) $4, GetLocation ($3)); + lbag.AddLocation (GetLocation ($3), GetLocation ($5)); + $$ = ea; + } + | primary_expression DOT open_parens_any expression CLOSE_PARENS + { + var lt = (LocatedToken) $3; + var ma = new AsXmlQueryExpression ((Expression) $1, (Expression) $4, lt.Location); + lbag.AddLocation ($$, GetLocation ($2)); + $$ = ma; + } + ; + +invocation_expression + : SUPER open_parens_any opt_argument_list close_parens + { + if (current_constructor == null) { + report.ErrorPlayScript (1007, GetLocation ($1), "A super statement can be used only inside class instance constructors"); + } else { + current_constructor.Initializer = EmptyExpressionStatement.Instance; + } + + $$ = new SuperBaseInitializer ((Arguments) $3, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4)); + } +// | builtin_types open_parens_any opt_argument_list close_parens +// { +// $$ = new Invocation ((Expression) $1, (Arguments) $3); +// lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4)); +// } + | primary_expression open_parens_any opt_argument_list close_parens + { + $$ = new Invocation ((Expression) $1, (Arguments) $3); + lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4)); + } + | primary_expression open_parens_any argument_list error + { + Error_SyntaxError (yyToken); + + $$ = new Invocation ((Expression) $1, (Arguments) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +object_initializer + : init_open_brace opt_member_initializer_list init_close_brace + { + $$ = new ObjectInitializer ((List) $2, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($1), GetLocation ($3)); + } + ; + +init_open_brace + : OPEN_BRACE_INIT + { + oob_stack.Push (Lexer.AutoSemiInsertion); + Lexer.AutoSemiInsertion = false; + } + ; + +init_close_brace + : CLOSE_BRACE + { + Lexer.AutoSemiInsertion = (bool) oob_stack.Pop (); + if (Lexer.AutoSemiInsertion) + Lexer.AllowAutoSemiAfterToken(Token.CLOSE_BRACE, true); + } + ; + +init_close_brace_or_complete_completion + : CLOSE_BRACE + { + Lexer.AutoSemiInsertion = (bool) oob_stack.Pop (); + if (Lexer.AutoSemiInsertion) + Lexer.AllowAutoSemiAfterToken(Token.CLOSE_BRACE, true); + } + | COMPLETE_COMPLETION + ; + +opt_member_initializer_list + : /* empty */ { $$ = null; } + | member_initializer_list + { + $$ = $1; + } + ; + +member_initializer_list + : member_initializer + { + var a = new List (); + a.Add ((Expression) $1); + $$ = a; + } + | member_initializer_list COMMA member_initializer + { + var a = (List)$1; + a.Add ((Expression) $3); + $$ = a; + } + | member_initializer_list error { + Error_SyntaxError (yyToken); + $$ = $1; + } + ; + +member_initializer + : IDENTIFIER COLON initializer_value + { + var lt = (LocatedToken) $1; + $$ = new ElementInitializer (lt.Value, (Expression)$3, lt.Location); + lbag.AddLocation ($$, GetLocation ($2)); + } + | AWAIT ASSIGN initializer_value + { + var lt = (LocatedToken) Error_AwaitAsIdentifier ($1); + $$ = new ElementInitializer (lt.Value, (Expression)$3, lt.Location); + lbag.AddLocation ($$, GetLocation ($2)); + } + | LITERAL COLON initializer_value + { + ILiteralConstant lit = $1 as ILiteralConstant; + string nm; + if (lit is StringLiteral) { + nm = ((StringLiteral)lit).Value; + } else { + if (parsing_playscript || !(lit is IntLiteral || lit is DoubleLiteral || lit is BoolLiteral)) { + report.Error (7019, GetLocation ($1), "Must be identifier or string literal"); + nm = "err"; + } else { + nm = ((Constant)$1).GetValueAsLiteral(); + } + } + + $$ = new ElementInitializer (nm, (Expression)$3, GetLocation($1)); + lbag.AddLocation ($$, GetLocation ($2)); + } + | GENERATE_COMPLETION + { + $$ = new CompletionElementInitializer (null, GetLocation ($1)); + } + /* | non_assignment_expression opt_COMPLETE_COMPLETION { + CompletionSimpleName csn = $1 as CompletionSimpleName; + if (csn == null) + $$ = new CollectionElementInitializer ((Expression)$1); + else + $$ = new CompletionElementInitializer (csn.Prefix, csn.Location); + } + | OPEN_BRACE expression_list CLOSE_BRACE + { + if ($2 == null) + $$ = null; + else + $$ = new CollectionElementInitializer ((List)$2, GetLocation ($1)); + } + | OPEN_BRACE CLOSE_BRACE + { + report.Error (1920, GetLocation ($1), "An element initializer cannot be empty"); + $$ = null; + } */ + ; + +initializer_value + : expression + ; + +opt_argument_list + : /* empty */ { $$ = null; } + | argument_list + ; + +argument_list + : argument_or_named_argument + { + Arguments list = new Arguments (4); + list.Add ((Argument) $1); + $$ = list; + } + | argument_list COMMA argument + { + Arguments list = (Arguments) $1; + if (list [list.Count - 1] is NamedArgument) + Error_NamedArgumentExpected ((NamedArgument) list [list.Count - 1]); + + list.Add ((Argument) $3); + $$ = list; + } +/* + | argument_list COMMA named_argument + { + Arguments list = (Arguments) $1; + NamedArgument a = (NamedArgument) $3; + for (int i = 0; i < list.Count; ++i) { + NamedArgument na = list [i] as NamedArgument; + if (na != null && na.Name == a.Name) + report.Error (1740, na.Location, "Named argument `{0}' specified multiple times", + na.Name); + } + + list.Add (a); + $$ = list; + } +*/ + | argument_list COMMA error + { + lexer.putback (')'); // TODO: Wrong but what can I do + Error_SyntaxError (yyToken); + $$ = $1; + } + | COMMA error + { + report.Error (839, GetLocation ($1), "An argument is missing"); + $$ = null; + } + ; + +argument + : expression + { + $$ = new Argument ((Expression) $1); + } + | non_simple_argument + ; + +argument_or_named_argument + : argument +// | named_argument + ; + +non_simple_argument + : REF variable_reference + { + $$ = new Argument ((Expression) $2, Argument.AType.Ref); + lbag.AddLocation ($$, GetLocation ($1)); + } + | OUT variable_reference + { + $$ = new Argument ((Expression) $2, Argument.AType.Out); + lbag.AddLocation ($$, GetLocation ($1)); + } + ; + +variable_reference + : expression + ; + +element_access + : primary_expression OPEN_BRACKET_EXPR expression_list_arguments CLOSE_BRACKET + { + $$ = new ElementAccess ((Expression) $1, (Arguments) $3, GetLocation ($2)); + lbag.AddLocation ($$, GetLocation ($4)); + } + | primary_expression OPEN_BRACKET_EXPR expression_list_arguments error + { + Error_SyntaxError (yyToken); + $$ = new ElementAccess ((Expression) $1, (Arguments) $3, GetLocation ($2)); + } + | primary_expression OPEN_BRACKET_EXPR error + { + Error_SyntaxError (yyToken); + $$ = new ElementAccess ((Expression) $1, null, GetLocation ($2)); + } +// | builtin_types OPEN_BRACKET_EXPR expression_list_arguments CLOSE_BRACKET +// { +// $$ = new ElementAccess ((Expression) $1, (Arguments) $3, GetLocation ($2)); +// lbag.AddLocation ($$, GetLocation ($4)); +// } +// | builtin_types OPEN_BRACKET_EXPR expression_list_arguments error +// { +// Error_SyntaxError (yyToken); +// $$ = new ElementAccess ((Expression) $1, (Arguments) $3, GetLocation ($2)); +// } +// | builtin_types OPEN_BRACKET_EXPR error +// { +// Error_SyntaxError (yyToken); +// $$ = new ElementAccess ((Expression) $1, null, GetLocation ($2)); +// } + ; + +expression_list + : expression + { + var list = new List (4); + list.Add ((Expression) $1); + $$ = list; + } + | expression_list COMMA expression + { + var list = (List) $1; + list.Add ((Expression) $3); + $$ = list; + } + | expression_list error { + Error_SyntaxError (yyToken); + $$ = $1; + } + ; + +expression_list_arguments + : expression_list_argument + { + Arguments args = new Arguments (4); + args.Add ((Argument) $1); + $$ = args; + } + | expression_list_arguments COMMA expression_list_argument + { + Arguments args = (Arguments) $1; + if (args [args.Count - 1] is NamedArgument && !($3 is NamedArgument)) + Error_NamedArgumentExpected ((NamedArgument) args [args.Count - 1]); + + args.Add ((Argument) $3); + $$ = args; + } + ; + +expression_list_argument + : expression + { + $$ = new Argument ((Expression) $1); + } +// | named_argument + ; + +this_access + : THIS + { + $$ = new This (GetLocation ($1)); + } + ; + +base_access + : SUPER OPEN_BRACKET_EXPR expression_list_arguments CLOSE_BRACKET + { + $$ = new ElementAccess (new BaseThis (GetLocation ($1)), (Arguments) $3, GetLocation ($2)); + lbag.AddLocation ($$, GetLocation ($4)); + } + | SUPER OPEN_BRACKET error + { + Error_SyntaxError (yyToken); + $$ = new ElementAccess (null, null, GetLocation ($2)); + } + ; + +post_increment_expression + : primary_expression OP_INC + { + $$ = new UnaryMutator (UnaryMutator.Mode.PostIncrement, (Expression) $1, GetLocation ($2)); + } + ; + +post_decrement_expression + : primary_expression OP_DEC + { + $$ = new UnaryMutator (UnaryMutator.Mode.PostDecrement, (Expression) $1, GetLocation ($2)); + } + ; + +new_expression + : NEW type_expression opt_new_args + { + $$ = new New ((Expression) $2, (Arguments) $3, GetLocation ($1)); +// lbag.AddLocation ($$, GetLocation ($3), GetLocation ($5)); + } + | NEW OP_LT type_expression OP_GT array_initializer + { + $$ = new NewVector ((FullNamedExpression) $3, (ArrayInitializer) $5, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4)); + } + ; + +opt_new_args + : /* empty */ + { + $$ = null; + } + | OPEN_PARENS opt_argument_list CLOSE_PARENS + { + $$ = $2; + } + ; + +//anonymous_type_expression +// : NEW OPEN_BRACE anonymous_type_parameters_opt_comma CLOSE_BRACE +// { +// if (lang_version <= LanguageVersion.ISO_2) +// FeatureIsNotAvailable (GetLocation ($1), "anonymous types"); +// +// $$ = new NewAnonymousType ((List) $3, current_container, GetLocation ($1)); +// +// // TODO: lbag comma location +// lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4)); +// } +// ; + +//anonymous_type_parameters_opt_comma +// : anonymous_type_parameters_opt +// | anonymous_type_parameters COMMA +// ; + +//anonymous_type_parameters_opt +// : { $$ = null; } +// | anonymous_type_parameters +// ; + +//anonymous_type_parameters +// : anonymous_type_parameter +// { +// var a = new List (4); +// a.Add ((AnonymousTypeParameter) $1); +// $$ = a; +// } +// | anonymous_type_parameters COMMA anonymous_type_parameter +// { +// var a = (List) $1; +// a.Add ((AnonymousTypeParameter) $3); +// $$ = a; +// } +// ; + +//anonymous_type_parameter +// : IDENTIFIER ASSIGN variable_initializer +// { +// var lt = (LocatedToken)$1; +// $$ = new AnonymousTypeParameter ((Expression)$3, lt.Value, lt.Location); +// lbag.AddLocation ($$, GetLocation ($2)); +// } +// | IDENTIFIER +// { +// var lt = (LocatedToken)$1; +// $$ = new AnonymousTypeParameter (new SimpleName (lt.Value, lt.Location), +// lt.Value, lt.Location); +// } +// | member_access +// { +// MemberAccess ma = (MemberAccess) $1; +// $$ = new AnonymousTypeParameter (ma, ma.Name, ma.Location); +// } +// | error +// { +// report.Error (746, lexer.Location, +// "Invalid anonymous type member declarator. Anonymous type members must be a member assignment, simple name or member access expression"); +// $$ = null; +// } +// ; + +//opt_rank_specifier +// : /* empty */ +// | rank_specifiers +// ; + +rank_specifiers + : rank_specifier + | rank_specifier rank_specifiers + { + ((ComposedTypeSpecifier) $1).Next = (ComposedTypeSpecifier) $2; + $$ = $1; + } + ; + +rank_specifier + : OPEN_BRACKET CLOSE_BRACKET + { + $$ = ComposedTypeSpecifier.CreateArrayDimension (1, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($2)); + } + | OPEN_BRACKET dim_separators CLOSE_BRACKET + { + $$ = ComposedTypeSpecifier.CreateArrayDimension ((int)$2, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($3)); + } + ; + +dim_separators + : COMMA + { + $$ = 2; + } + | dim_separators COMMA + { + $$ = ((int) $1) + 1; + } + ; + +array_creation + : array_initializer + { + $$ = new ArrayCreation ((ArrayInitializer) $1); + } + ; + +array_initializer + : init_open_bracket init_close_bracket + { + $$ = new ArrayInitializer (null, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($2)); + } + | init_open_bracket_expr variable_initializer_list opt_comma init_close_bracket + { + $$ = new ArrayInitializer ((List) $2, GetLocation ($1)); + if ($3 != null) { + lbag.AddLocation ($$, GetLocation ($3), GetLocation ($4)); + } else { + lbag.AddLocation ($$, GetLocation ($4)); + } + } + ; + +init_open_bracket + : OPEN_BRACKET + { + oob_stack.Push (Lexer.AutoSemiInsertion); + Lexer.AutoSemiInsertion = false; + } + ; + +init_open_bracket_expr + : OPEN_BRACKET_EXPR + { + oob_stack.Push (Lexer.AutoSemiInsertion); + Lexer.AutoSemiInsertion = false; + } + ; + +init_close_bracket + : CLOSE_BRACKET + { + Lexer.AutoSemiInsertion = (bool) oob_stack.Pop (); + } + ; + +variable_initializer_list + : variable_initializer + { + var list = new List (4); + list.Add ((Expression) $1); + $$ = list; + } + | variable_initializer_list COMMA variable_initializer + { + var list = (List) $1; + list.Add ((Expression) $3); + $$ = list; + } + ; + +typeof_type_expression + : type_and_void + | error + { + Error_TypeExpected (lexer.Location); + $$ = null; + } + ; + +function_block + : FUNCTION_BLOCK OPEN_PARENS + { + valid_param_mod = 0; + } + opt_formal_parameter_list CLOSE_PARENS opt_anomymous_method_type + { + valid_param_mod = 0; + start_anonymous ((ParametersCompiled) $4, (FullNamedExpression) $6, GetLocation ($1)); + } + block + { + $$ = end_anonymous ((ParametersBlock) $8); + } + ; + +opt_anomymous_method_type + : + { + Warning_NoTypeDeclaration (lexer.Location, "Anonymous function"); + $$ = new UntypedTypeExpression (lexer.Location); + } + | COLON member_type + { + $$ = $2; + } + ; + +with_statement + : WITH open_parens_any expression CLOSE_PARENS block + { + $$ = new With ((Expression) $3, (Block) $5, GetLocation ($1)); + } + ; + +default_value_expression + : DEFAULT open_parens_any type CLOSE_PARENS + { + CheckIsPlayScript("default values", GetLocation($1)); + + if (lang_version < LanguageVersion.ISO_2) + FeatureIsNotAvailable (GetLocation ($1), "default value expression"); + + $$ = new DefaultValueExpression ((Expression) $3, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4)); + } + ; + +unary_expression + : primary_expression + | BANG prefixed_unary_expression + { + $$ = new Unary (Unary.Operator.LogicalNot, (Expression) $2, GetLocation ($1)); + } + | TILDE prefixed_unary_expression + { + $$ = new Unary (Unary.Operator.OnesComplement, (Expression) $2, GetLocation ($1)); + } + | AWAIT prefixed_unary_expression + { + CheckIsPlayScript("await", GetLocation($1)); + + if (!async_block) { + if (current_anonymous_method is LambdaExpression) { + report.Error (4034, GetLocation ($1), + "The `await' operator can only be used when its containing lambda expression is marked with the `async' modifier"); + } else if (current_anonymous_method is AnonymousMethodExpression) { + report.Error (4035, GetLocation ($1), + "The `await' operator can only be used when its containing anonymous method is marked with the `async' modifier"); + } else { + report.Error (4033, GetLocation ($1), + "The `await' operator can only be used when its containing method is marked with the `async' modifier"); + } + } else { + current_block.Explicit.RegisterAsyncAwait (); + } + + $$ = new Await ((Expression) $2, GetLocation ($1)); + } + | OP_AT prefixed_unary_expression + { +// TODO: $$ = new Unary (Unary.Operator.AsE4xAttribute, (Expression) $2, GetLocation ($1)); + } + | TYPEOF prefixed_unary_expression + { + $$ = new TypeOf ((Expression) $2, GetLocation ($1)); + } + | DELETE prefixed_unary_expression + { + $$ = new Delete ((Expression) $2, GetLocation ($1)); + } + | BANG error + { + Error_SyntaxError (yyToken); + + $$ = new Unary (Unary.Operator.LogicalNot, null, GetLocation ($1)); + } + | TILDE error + { + Error_SyntaxError (yyToken); + + $$ = new Unary (Unary.Operator.OnesComplement, null, GetLocation ($1)); + } +// | OPEN_PARENS_CAST type CLOSE_PARENS error +// { +// Error_SyntaxError (yyToken); +// +// $$ = new Cast ((FullNamedExpression) $2, null, GetLocation ($1)); +// lbag.AddLocation ($$, GetLocation ($3)); +// } + | AWAIT error + { + Error_SyntaxError (yyToken); + + $$ = new Await (null, GetLocation ($1)); + } +// | OP_AT error +// { +// Error_SyntaxError (yyToken); + +// $$ = new Unary (Unary.Operator.AsE4xAttribute, null, GetLocation ($1)); +// } + | DELETE error + { + Error_SyntaxError (yyToken); + + $$ = new Delete (null, GetLocation ($1)); + } + ; + + // + // The idea to split this out is from Rhys' grammar + // to solve the problem with casts. + // +prefixed_unary_expression + : unary_expression + | PLUS prefixed_unary_expression + { + $$ = new Unary (Unary.Operator.UnaryPlus, (Expression) $2, GetLocation ($1)); + } + | MINUS prefixed_unary_expression + { + $$ = new Unary (Unary.Operator.UnaryNegation, (Expression) $2, GetLocation ($1)); + } + | OP_INC prefixed_unary_expression + { + $$ = new UnaryMutator (UnaryMutator.Mode.PreIncrement, (Expression) $2, GetLocation ($1)); + } + | OP_DEC prefixed_unary_expression + { + $$ = new UnaryMutator (UnaryMutator.Mode.PreDecrement, (Expression) $2, GetLocation ($1)); + } +// | STAR prefixed_unary_expression +// { +// $$ = new Indirection ((Expression) $2, GetLocation ($1)); +// } + | BITWISE_AND prefixed_unary_expression + { + $$ = new Unary (Unary.Operator.AddressOf, (Expression) $2, GetLocation ($1)); + } + | PLUS error + { + Error_SyntaxError (yyToken); + + $$ = new Unary (Unary.Operator.UnaryPlus, null, GetLocation ($1)); + } + | MINUS error + { + Error_SyntaxError (yyToken); + + $$ = new Unary (Unary.Operator.UnaryNegation, null, GetLocation ($1)); + } + | OP_INC error + { + Error_SyntaxError (yyToken); + + $$ = new UnaryMutator (UnaryMutator.Mode.PreIncrement, null, GetLocation ($1)); + } + | OP_DEC error + { + Error_SyntaxError (yyToken); + + $$ = new UnaryMutator (UnaryMutator.Mode.PreDecrement, null, GetLocation ($1)); + } +// | STAR error +// { +// Error_SyntaxError (yyToken); +// +// $$ = new Indirection (null, GetLocation ($1)); +// } + | BITWISE_AND error + { + Error_SyntaxError (yyToken); + + $$ = new Unary (Unary.Operator.AddressOf, null, GetLocation ($1)); + } + ; + +multiplicative_expression + : prefixed_unary_expression + | multiplicative_expression STAR prefixed_unary_expression + { + $$ = new Binary (Binary.Operator.Multiply, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | multiplicative_expression DIV prefixed_unary_expression + { + $$ = new Binary (Binary.Operator.Division, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | multiplicative_expression PERCENT prefixed_unary_expression + { + $$ = new Binary (Binary.Operator.Modulus, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | multiplicative_expression STAR error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.Multiply, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + | multiplicative_expression DIV error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.Division, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + | multiplicative_expression PERCENT error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.Modulus, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +additive_expression + : multiplicative_expression + | additive_expression PLUS multiplicative_expression + { + $$ = new Binary (Binary.Operator.Addition, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | additive_expression MINUS multiplicative_expression + { + $$ = new Binary (Binary.Operator.Subtraction, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | additive_expression OP_IN multiplicative_expression + { + $$ = new In ((Expression) $1, (Expression) $3, GetLocation ($2)); + } + | additive_expression AS type + { + $$ = new As ((Expression) $1, (Expression) $3, GetLocation ($2)); + } + | additive_expression IS type + { + $$ = new Is ((Expression) $1, (Expression) $3, GetLocation ($2)); + } + | additive_expression PLUS error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.Addition, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + | additive_expression MINUS error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.Subtraction, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + | additive_expression OP_IN error + { + Error_SyntaxError (yyToken); + + $$ = new In ((Expression) $1, null, GetLocation ($2)); + } + | additive_expression AS error + { + Error_SyntaxError (yyToken); + + $$ = new As ((Expression) $1, null, GetLocation ($2)); + } + | additive_expression IS error + { + Error_SyntaxError (yyToken); + + $$ = new Is ((Expression) $1, null, GetLocation ($2)); + } + ; + +shift_expression + : additive_expression + | shift_expression OP_SHIFT_LEFT additive_expression + { + $$ = new Binary (Binary.Operator.LeftShift, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | shift_expression OP_SHIFT_RIGHT additive_expression + { + $$ = new Binary (Binary.Operator.RightShift, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | shift_expression OP_USHIFT_RIGHT additive_expression + { + $$ = new Binary (Binary.Operator.UnsignedRightShift, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | shift_expression OP_SHIFT_LEFT error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.LeftShift, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + | shift_expression OP_SHIFT_RIGHT error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.RightShift, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + | shift_expression OP_USHIFT_RIGHT error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.UnsignedRightShift, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +relational_expression + : shift_expression + | relational_expression OP_LT shift_expression + { + $$ = new Binary (Binary.Operator.LessThan, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | relational_expression OP_GT shift_expression + { + $$ = new Binary (Binary.Operator.GreaterThan, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | relational_expression OP_LE shift_expression + { + $$ = new Binary (Binary.Operator.LessThanOrEqual, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | relational_expression OP_GE shift_expression + { + $$ = new Binary (Binary.Operator.GreaterThanOrEqual, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | relational_expression OP_LT error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.LessThan, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + | relational_expression OP_GT error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.GreaterThan, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + | relational_expression OP_LE error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.LessThanOrEqual, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + | relational_expression OP_GE error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.GreaterThanOrEqual, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +equality_expression + : relational_expression + | equality_expression OP_EQ relational_expression + { + $$ = new Binary (Binary.Operator.Equality, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | equality_expression OP_NE relational_expression + { + $$ = new Binary (Binary.Operator.Inequality, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | equality_expression OP_REF_EQ relational_expression + { + $$ = new Binary (Binary.Operator.StrictEquality, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | equality_expression OP_REF_NE relational_expression + { + $$ = new Binary (Binary.Operator.StrictInequality, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +and_expression + : equality_expression + | and_expression BITWISE_AND equality_expression + { + $$ = new Binary (Binary.Operator.BitwiseAnd, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | and_expression BITWISE_AND error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.BitwiseAnd, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +exclusive_or_expression + : and_expression + | exclusive_or_expression CARRET and_expression + { + $$ = new Binary (Binary.Operator.ExclusiveOr, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | exclusive_or_expression CARRET error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.ExclusiveOr, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +inclusive_or_expression + : exclusive_or_expression + | inclusive_or_expression BITWISE_OR exclusive_or_expression + { + $$ = new Binary (Binary.Operator.BitwiseOr, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | inclusive_or_expression BITWISE_OR error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.BitwiseOr, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +conditional_and_expression + : inclusive_or_expression + | conditional_and_expression OP_AND inclusive_or_expression + { + $$ = new Binary (Binary.Operator.LogicalAnd, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | conditional_and_expression OP_AND error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.LogicalAnd, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +conditional_or_expression + : conditional_and_expression + | conditional_or_expression OP_OR conditional_and_expression + { + $$ = new Binary (Binary.Operator.LogicalOr, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | conditional_or_expression OP_OR error + { + Error_SyntaxError (yyToken); + + $$ = new Binary (Binary.Operator.LogicalOr, (Expression) $1, null); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +null_coalescing_expression + : conditional_or_expression + | conditional_or_expression OP_COALESCING null_coalescing_expression + { + CheckIsPlayScript("?? operator", GetLocation($2)); + + if (lang_version < LanguageVersion.ISO_2) + FeatureIsNotAvailable (GetLocation ($2), "null coalescing operator"); + + $$ = new Nullable.NullCoalescingOperator ((Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +conditional_expression + : null_coalescing_expression + | null_coalescing_expression INTERR expression COLON expression + { + $$ = new Conditional (new BooleanExpression ((Expression) $1), (Expression) $3, (Expression) $5, GetLocation ($2)); + lbag.AddLocation ($$, GetLocation ($4)); + } + | null_coalescing_expression INTERR expression error + { + Error_SyntaxError (yyToken); + + $$ = new Conditional (new BooleanExpression ((Expression) $1), (Expression) $3, null, GetLocation ($2)); + } + | null_coalescing_expression INTERR expression COLON error + { + Error_SyntaxError (yyToken); + + $$ = new Conditional (new BooleanExpression ((Expression) $1), (Expression) $3, null, GetLocation ($2)); + lbag.AddLocation ($$, GetLocation ($4)); + } + ; + +assignment_expression + : prefixed_unary_expression ASSIGN expression + { + Expression target = (Expression) $1; + Expression source = (Expression) $3; + + $$ = new SimpleAssign (target, source); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression OP_MULT_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.Multiply, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression OP_DIV_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.Division, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression OP_MOD_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.Modulus, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression OP_ADD_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.Addition, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression OP_SUB_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.Subtraction, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression OP_SHIFT_LEFT_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.LeftShift, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression OP_SHIFT_RIGHT_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.RightShift, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression OP_USHIFT_RIGHT_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.UnsignedRightShift, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression OP_AND_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.BitwiseAnd, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression LOGICAL_AND_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.LogicalAnd, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression OP_OR_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.BitwiseOr, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression LOGICAL_OR_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.LogicalOr, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + | prefixed_unary_expression OP_XOR_ASSIGN expression + { + $$ = new CompoundAssign (Binary.Operator.ExclusiveOr, (Expression) $1, (Expression) $3); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +expression_or_error + : expression + | error + { + Error_SyntaxError (yyToken); + $$ = null; + } + ; + +expression + : assignment_expression + | non_assignment_expression + ; + +non_assignment_expression + : conditional_expression + | query_expression + ; + +constant_expression + : expression + ; + +boolean_expression + : expression + { + $$ = new BooleanExpression ((Expression) $1); + } + ; + +// +// 10 classes +// +class_declaration + : opt_attributes + opt_modifiers + opt_partial + CLASS + { + lexer.ConstraintsParsing = true; + lexer.AutoSemiInsertion = false; + } + type_declaration_name + { + Class c = new Class (current_container, (MemberName) $6, (Modifiers) $2, (Attributes) $1, true); + + if (((c.ModFlags & Modifiers.STATIC) != 0) && lang_version == LanguageVersion.ISO_1) { + FeatureIsNotAvailable (c.Location, "static classes"); + } + + bool is_partial = IsPartial($1) || $3 != null; + push_current_container (c, is_partial); + } + opt_class_extends + opt_class_implements + opt_type_parameter_constraints_clauses + { + lexer.ConstraintsParsing = false; + + if ($10 != null) + current_container.SetConstraints ((List) $10); + lbag.AddMember (current_container, mod_locations, GetLocation ($4)); + + if (doc_support) { + current_container.PartialContainer.DocComment = Lexer.consume_doc_comment (); + Lexer.doc_state = XmlCommentState.Allowed; + } + + lexer.parsing_modifiers = true; + lexer.DynamicParsing = false; + } + OPEN_BRACE + { + lexer.AutoSemiInsertion = true; + } + opt_class_member_declarations CLOSE_BRACE opt_semicolon + { + lexer.DynamicParsing = true; + --lexer.parsing_declaration; + if (doc_support) + Lexer.doc_state = XmlCommentState.Allowed; + + lbag.AppendToMember (current_container, GetLocation ($12), GetLocation ($15), GetLocation ($16)); + $$ = pop_current_class (); + } + ; + +opt_partial + : /* empty */ + { $$ = null; } + | PARTIAL + { $$ = $1; } // location + ; + +opt_modifiers + : /* empty */ + { + mod_locations = null; + $$ = ModifierNone; + lexer.parsing_modifiers = false; + } + | modifiers + { + lexer.parsing_modifiers = false; + } + ; + +modifiers + : modifier + { + $$ = $1 ?? ModifierNone; + } + | modifiers modifier + { + if ($2 == null) { + var m1 = (Modifiers) $1; + + if ((m1 & Modifiers.AccessibilityMask) != 0) { + report.ErrorPlayScript (1003, GetLocation ($2), + "Access specifiers are not allowed with namespace attributes."); + } + } else { + var m1 = (Modifiers) $1; + var m2 = (Modifiers) $2; + + if ((m1 & m2) != 0) { + report.ErrorPlayScript (1127, lexer.Location - ModifiersExtensions.Name (m2).Length, + "Attribute `{0}' was specified multiple times.", ModifiersExtensions.Name (m2)); + } else if ((m2 & Modifiers.AccessibilityMask) != 0 && (m1 & Modifiers.AccessibilityMask) != 0 && + ((m2 | m1 & Modifiers.AccessibilityMask) != (Modifiers.PROTECTED | Modifiers.INTERNAL))) { + report.ErrorPlayScript (1154, lexer.Location - ModifiersExtensions.Name (m2).Length, + "Only one of public, private, protected, or internal can be specified on a definition."); + } + + $$ = m1 | m2; + } + } + ; + +modifier + : PUBLIC + { + $$ = Modifiers.PUBLIC; + StoreModifierLocation ($$, GetLocation ($1)); + } + | PROTECTED + { + $$ = Modifiers.PROTECTED; + StoreModifierLocation ($$, GetLocation ($1)); + } + | INTERNAL + { + $$ = Modifiers.INTERNAL; + StoreModifierLocation ($$, GetLocation ($1)); + } + | PRIVATE + { + $$ = Modifiers.PRIVATE; + StoreModifierLocation ($$, GetLocation ($1)); + } + | ABSTRACT + { + $$ = Modifiers.ABSTRACT; + StoreModifierLocation ($$, GetLocation ($1)); + } + | FINAL + { + $$ = (Modifiers)0; // Modifiers.SEALED; // The semantics for SEALED and FINAL don't quite match. Ignore FINAL for right now. (BEN) + StoreModifierLocation ($$, GetLocation ($1)); + } + | STATIC + { + $$ = Modifiers.STATIC; + StoreModifierLocation ($$, GetLocation ($1)); + } + | VIRTUAL + { + $$ = Modifiers.VIRTUAL; + StoreModifierLocation ($$, GetLocation ($1)); + } + | OVERRIDE + { + $$ = Modifiers.OVERRIDE; + StoreModifierLocation ($$, GetLocation ($1)); + } + | NATIVE + { + $$ = Modifiers.EXTERN; + StoreModifierLocation ($$, GetLocation ($1)); + } + | DYNAMIC + { + $$ = Modifiers.DYNAMIC; + StoreModifierLocation ($$, GetLocation ($1)); + } + | IDENTIFIER_MODIFIER + { + if (current_block != null) + report.ErrorPlayScript (1116, GetLocation ($1), "A user-defined namespace attribute can only be used at the top level of a class definition"); + + if (namespace_modifier != null) + report.ErrorPlayScript (1162, GetLocation ($1), "Only one namespace attribute can be used per definition"); + else + namespace_modifier = (LocatedToken) $1; + + $$ = null; + } + ; + +opt_class_extends + : /* empty */ + | EXTENDS base_type_name + { + current_type.AddBaseType ((FullNamedExpression) $2); + } + | EXTENDS base_type_name error + { + Error_SyntaxError (yyToken); + + current_type.AddBaseType ((FullNamedExpression) $2); + } + ; + +opt_class_implements + : /* empty */ + | IMPLEMENTS type_list + { + current_type.AddBaseTypes ((List) $2); + } + | IMPLEMENTS type_list error + { + Error_SyntaxError (yyToken); + + current_type.AddBaseTypes ((List) $2); + } + ; + +opt_type_parameter_constraints_clauses + : /* empty */ + | type_parameter_constraints_clauses + { + $$ = $1; + } + ; + +type_parameter_constraints_clauses + : type_parameter_constraints_clause + { + var constraints = new List (1); + constraints.Add ((Constraints) $1); + $$ = constraints; + } + | type_parameter_constraints_clauses type_parameter_constraints_clause + { + var constraints = (List) $1; + Constraints new_constraint = (Constraints)$2; + + foreach (Constraints c in constraints) { + if (new_constraint.TypeParameter.Value == c.TypeParameter.Value) { + report.Error (409, new_constraint.Location, + "A constraint clause has already been specified for type parameter `{0}'", + new_constraint.TypeParameter.Value); + } + } + + constraints.Add (new_constraint); + $$ = constraints; + } + ; + +type_parameter_constraints_clause + : WHERE IDENTIFIER COLON type_parameter_constraints + { + var lt = (LocatedToken) $2; + $$ = new Constraints (new SimpleMemberName (lt.Value, lt.Location), (List) $4, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($3)); + } + | WHERE IDENTIFIER error + { + Error_SyntaxError (yyToken); + + var lt = (LocatedToken) $2; + $$ = new Constraints (new SimpleMemberName (lt.Value, lt.Location), null, GetLocation ($1)); + } + ; + +type_parameter_constraints + : type_parameter_constraint + { + var constraints = new List (1); + constraints.Add ((FullNamedExpression) $1); + $$ = constraints; + } + | type_parameter_constraints COMMA type_parameter_constraint + { + var constraints = (List) $1; + var prev = constraints [constraints.Count - 1] as SpecialContraintExpr; + if (prev != null && (prev.Constraint & SpecialConstraint.Constructor) != 0) { + report.Error (401, GetLocation ($2), "The `new()' constraint must be the last constraint specified"); + } + + prev = $3 as SpecialContraintExpr; + if (prev != null) { + if ((prev.Constraint & (SpecialConstraint.Class | SpecialConstraint.Struct)) != 0) { + report.Error (449, prev.Location, "The `class' or `struct' constraint must be the first constraint specified"); + } else { + prev = constraints [0] as SpecialContraintExpr; + if (prev != null && (prev.Constraint & SpecialConstraint.Struct) != 0) { + report.Error (451, GetLocation ($3), "The `new()' constraint cannot be used with the `struct' constraint"); + } + } + } + + constraints.Add ((FullNamedExpression) $3); + $$ = constraints; + } + ; + +type_parameter_constraint + : type + { + if ($1 is ComposedCast) + report.Error (706, GetLocation ($1), "Invalid constraint type `{0}'", ((ComposedCast)$1).GetSignatureForError ()); + + $$ = $1; + } + | NEW OPEN_PARENS CLOSE_PARENS + { + $$ = new SpecialContraintExpr (SpecialConstraint.Constructor, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($2), GetLocation ($3)); + } + | CLASS + { + $$ = new SpecialContraintExpr (SpecialConstraint.Class, GetLocation ($1)); + } + | STRUCT + { + $$ = new SpecialContraintExpr (SpecialConstraint.Struct, GetLocation ($1)); + } + ; + +// +// Statements (8.2) +// + +block + : OPEN_BRACE + { + ++lexer.parsing_block; + lexer.AutoSemiInsertion = true; + start_block (GetLocation ($1)); + } + opt_statement_list block_end + { + $$ = $4; + } + ; + +block_end + : CLOSE_BRACE + { + Lexer.AutoSemiInsertion = true; + --lexer.parsing_block; + $$ = end_block (GetLocation ($1)); + } + | COMPLETE_COMPLETION + { + Lexer.AutoSemiInsertion = true; + --lexer.parsing_block; + $$ = end_block (lexer.Location); + } + ; + + +block_prepared + : OPEN_BRACE + { + ++lexer.parsing_block; + current_block.StartLocation = GetLocation ($1); + } + opt_statement_list CLOSE_BRACE + { + Lexer.AutoSemiInsertion = true; + --lexer.parsing_block; + $$ = end_block (GetLocation ($4)); + } + ; + +opt_statement_list + : /* empty */ + | statement_list + ; + +statement_list + : statement + | statement_list statement + ; + +statement + : block_variable_declaration + { + current_block.AddStatement ((Statement) $1); + } + | valid_declaration_statement + { + current_block.AddStatement ((Statement) $1); + } + | labeled_statement + | error + { + Error_SyntaxError (yyToken); + $$ = null; + } + ; + +// +// The interactive_statement and its derivatives are only +// used to provide a special version of `expression_statement' +// that has a side effect of assigning the expression to +// $retval +// +interactive_statement_list + : interactive_statement + | interactive_statement_list interactive_statement + ; + +interactive_statement + : block_variable_declaration + { + current_block.AddStatement ((Statement) $1); + } + | interactive_valid_declaration_statement + { + current_block.AddStatement ((Statement) $1); + } + | labeled_statement + ; + +valid_declaration_statement + : block + | empty_statement + | expression_statement + | selection_statement + | iteration_statement + | jump_statement + | try_statement + | method_declaration + | with_statement + ; + +interactive_valid_declaration_statement + : block + | empty_statement + | interactive_expression_statement + | selection_statement + | iteration_statement + | jump_statement + | try_statement + ; + +embedded_statement + : valid_declaration_statement + | block_variable_declaration + { + if (parsing_playscript) { + report.Error (1023, GetLocation ($1), "An embedded statement may not be a declaration or labeled statement"); + $$ = null; + } else { + // NOTE: This is actually allowed in PlayScript. We'll turn it off in ASX though as it's error prone. + $$ = $1; + } + } + | labeled_statement + { + report.Error (1023, GetLocation ($1), "An embedded statement may not be a declaration or labeled statement"); + $$ = null; + } + | error + { + Error_SyntaxError (yyToken); + $$ = new EmptyStatement (GetLocation ($1)); + } + ; + +empty_statement + : SEMICOLON + { + Lexer.AutoSemiInsertion = true; + // Uses lexer.Location because semicolon location is not kept in quick mode + $$ = new EmptyStatement (lexer.Location); + } + ; + +labeled_statement + : identifier_inside_body COLON + { + var lt = (LocatedToken) $1; + LabeledStatement labeled = new LabeledStatement (lt.Value, current_block, lt.Location); + lbag.AddLocation (labeled, GetLocation ($2)); + current_block.AddLabel (labeled); + current_block.AddStatement (labeled); + } + statement + ; + +use_namespace_statement + : USE NAMESPACE IDENTIFIER stmnt_end_semicolon + { + var lt = (LocatedToken) $3; + $$ = new UseNamespace (lt.Value, GetLocation ($1)); + } + ; + +variable_type + : variable_type_simple + | variable_type_simple rank_specifiers + { + if ($1 is VarExpr) + $1 = new SimpleName ("var", ((VarExpr) $1).Location); + + $$ = new ComposedCast ((FullNamedExpression) $1, (ComposedTypeSpecifier) $2); + } + ; + +/* + * The following is from Rhys' grammar: + * > Types in local variable declarations must be recognized as + * > expressions to prevent reduce/reduce errors in the grammar. + * > The expressions are converted into types during semantic analysis. + */ +variable_type_simple + : primary_expression_or_type opt_nullable + { + // Ok, the above "primary_expression" is there to get rid of + // both reduce/reduce and shift/reduces in the grammar, it should + // really just be "type_name". If you use type_name, a reduce/reduce + // creeps up. If you use namespace_or_type_name (which is all we need + // really) two shift/reduces appear. + // + + // So the super-trick is that primary_expression + // can only be either a SimpleName or a MemberAccess. + // The MemberAccess case arises when you have a fully qualified type-name like : + // Foo.Bar.Blah i; + // SimpleName is when you have + // Blah i; + + Expression expr = (Expression) $1; + if ($2 == null) { +// SimpleName sn = expr as SimpleName; +// if (sn != null) +// $$ = ConvertAsType(sn, $1); +// else + $$ = $1; + } else if (expr is ATypeNameExpression) { + $$ = new ComposedCast ((ATypeNameExpression)expr, (ComposedTypeSpecifier) $2); + } else { + Error_ExpectingTypeName (expr); + $$ = null; + } + } +// | primary_expression_or_type pointer_stars +// { +// ATypeNameExpression expr = $1 as ATypeNameExpression; +// +// if (expr != null) { +// $$ = new ComposedCast (expr, (ComposedTypeSpecifier) $2); +// } else { +// Error_ExpectingTypeName ((Expression)$1); +// $$ = expr; +// } +// } + | builtin_types opt_nullable + { + if ($2 == null) + $$ = $1; + else + $$ = new ComposedCast ((FullNamedExpression) $1, (ComposedTypeSpecifier) $2); + } +// | builtin_types pointer_stars +// { +// $$ = new ComposedCast ((FullNamedExpression) $1, (ComposedTypeSpecifier) $2); +// } +// | VOID pointer_stars +// { +// $$ = new ComposedCast (new TypeExpression (compiler.BuiltinTypes.Void, GetLocation ($1)), (ComposedTypeSpecifier) $2); +// } + | VOID + { + Expression.Error_VoidInvalidInTheContext (GetLocation ($1), report); + $$ = new TypeExpression (compiler.BuiltinTypes.Void, GetLocation ($1)); + } + ; + +//pointer_stars +// : pointer_star +// | pointer_star pointer_stars +// { +// ((ComposedTypeSpecifier) $1).Next = (ComposedTypeSpecifier) $2; +// $$ = $1; +// } +// ; + +//pointer_star +// : STAR +// { +// $$ = ComposedTypeSpecifier.CreatePointer (GetLocation ($1)); +// } +// ; + +identifier_inside_body + : IDENTIFIER + | AWAIT + { + if (async_block) { + report.Error (4003, GetLocation ($1), "`await' cannot be used as an identifier within an async method or lambda expression"); + $$ = new LocatedToken ("await", GetLocation ($1)); + } + } + ; + +stmnt_end_semicolon + : SEMICOLON + { + Lexer.AutoSemiInsertion = true; + } + ; + +block_variable_declaration + : variable_declaration stmnt_end_semicolon + | block_constant_declaration stmnt_end_semicolon + ; + +variable_declaration + : VAR identifier_inside_body COLON type + { + var lt = (LocatedToken) $2; + var li = RegisterLocalVariable (current_block, lt.Value, 0, lt.Location); + current_variable = new BlockVariable ((FullNamedExpression) $4, li); + current_block.ParametersBlock.TopBlock.AddScopeStatement (new ImplicitVariableInitializer (current_variable)); + } + opt_local_variable_initializer opt_variable_declarators + { + $$ = current_variable; + current_variable = null; + } + | VAR identifier_inside_body + { + var lt = (LocatedToken) $2; + var li = RegisterLocalVariable (current_block, lt.Value, 0, lt.Location); + current_variable = new UntypedBlockVariable (li, lt.Location); + current_block.ParametersBlock.TopBlock.AddScopeStatement (new ImplicitVariableInitializer (current_variable)); + + Warning_NoTypeDeclaration (lt.Location, string.Format ("Variable `{0}'", lt.Value)); + } + opt_local_variable_initializer opt_variable_declarators + { + $$ = current_variable; + current_variable = null; + } + ; + +block_constant_declaration + : CONST identifier_inside_body COLON type + { + var lt = (LocatedToken) $2; + var li = RegisterLocalVariable (current_block, lt.Value, LocalVariable.Flags.Constant, lt.Location); + current_variable = new BlockConstant ((FullNamedExpression) $4, li); + current_block.ParametersBlock.TopBlock.AddScopeStatement (new ImplicitVariableInitializer (current_variable)); + } + opt_const_variable_initializer opt_const_declarators + { + $$ = current_variable; + current_variable = null; + lbag.AddLocation ($$, GetLocation ($1)); + } + | CONST identifier_inside_body + { + var lt = (LocatedToken) $2; + var li = RegisterLocalVariable (current_block, lt.Value, LocalVariable.Flags.Constant, lt.Location); + current_variable = new UntypedBlockVariable (li, lt.Location); + current_block.ParametersBlock.TopBlock.AddScopeStatement (new ImplicitVariableInitializer (current_variable)); + + Warning_NoTypeDeclaration (lt.Location, string.Format ("Constant `{0}'", lt.Value)); + } + opt_const_variable_initializer opt_const_declarators + { + $$ = current_variable; + current_variable = null; + lbag.AddLocation ($$, GetLocation ($1)); + } + ; + +opt_local_variable_initializer + : /* empty */ + | ASSIGN block_variable_initializer + { + current_variable.Initializer = (Expression) $2; + // TODO: lbag + } + | error + { + if (yyToken == Token.OPEN_BRACKET_EXPR) { + report.Error (650, lexer.Location, + "Syntax error, bad array declarator. To declare a managed array the rank specifier precedes the variable's identifier. To declare a fixed size buffer field, use the fixed keyword before the field type"); + } else { + Error_SyntaxError (yyToken); + } + } + ; + +opt_variable_declarators + : /* empty */ + | variable_declarators + ; + +opt_using_or_fixed_variable_declarators + : /* empty */ + | variable_declarators + { + foreach (var d in current_variable.Declarators) { + if (d.Initializer == null) + Error_MissingInitializer (d.Variable.Location); + } + } + ; + +variable_declarators + : variable_declarator + | variable_declarators variable_declarator + ; + +variable_declarator + : COMMA identifier_inside_body + { + var lt = (LocatedToken) $2; + var li = RegisterLocalVariable (current_variable.Variable.Block, lt.Value, 0, lt.Location); + var d = new BlockVariableDeclarator (li, null, lt.Location); + current_variable.AddDeclarator (d); + + Warning_NoTypeDeclaration (lt.Location, string.Format ("Variable `{0}'", lt.Value)); + + lbag.AddLocation (d, GetLocation ($1)); + } + | COMMA identifier_inside_body ASSIGN block_variable_initializer + { + var lt = (LocatedToken) $2; + var li = RegisterLocalVariable (current_variable.Variable.Block, lt.Value, 0, lt.Location); + var d = new BlockVariableDeclarator (li, (Expression) $4, lt.Location); + current_variable.AddDeclarator (d); + + Warning_NoTypeDeclaration (lt.Location, string.Format ("Variable `{0}'", lt.Value)); + + lbag.AddLocation (d, GetLocation ($1), GetLocation ($3)); + } + | COMMA identifier_inside_body COLON type + { + var lt = (LocatedToken) $2; + var li = RegisterLocalVariable (current_variable.Variable.Block, lt.Value, 0, lt.Location); + var d = new BlockVariableDeclarator (li, null, (FullNamedExpression) $4, lt.Location); + current_variable.AddDeclarator (d); + + lbag.AddLocation (d, GetLocation ($1)); + } + | COMMA identifier_inside_body COLON type ASSIGN block_variable_initializer + { + var lt = (LocatedToken) $2; + var li = RegisterLocalVariable (current_variable.Variable.Block, lt.Value, 0, lt.Location); + var d = new BlockVariableDeclarator (li, (Expression) $6, (FullNamedExpression) $4, lt.Location); + current_variable.AddDeclarator (d); + + lbag.AddLocation (d, GetLocation ($1), GetLocation ($5)); + } + ; + +opt_const_variable_initializer + : /* empty */ + { + Warning_UninitializedConstant (current_variable.Location); + $$ = null; + } + | ASSIGN constant_initializer_expr + { + current_variable.Initializer = (Expression) $2; + } + ; + +opt_const_declarators + : /* empty */ + | const_declarators + ; + +const_declarators + : const_declarator + | const_declarators const_declarator + ; + +const_declarator + : COMMA identifier_inside_body + { + var lt = (LocatedToken) $2; + var li = RegisterLocalVariable (current_variable.Variable.Block, lt.Value, LocalVariable.Flags.Constant, lt.Location); + var d = new BlockVariableDeclarator (li, null, lt.Location); + current_variable.AddDeclarator (d); + + Warning_NoTypeDeclaration (lt.Location, string.Format ("Constant `{0}'", lt.Value)); + Warning_UninitializedConstant (lexer.Location); + + lbag.AddLocation (d, GetLocation ($1)); + } + | COMMA identifier_inside_body ASSIGN constant_initializer_expr + { + var lt = (LocatedToken) $2; + var li = RegisterLocalVariable (current_variable.Variable.Block, lt.Value, LocalVariable.Flags.Constant, lt.Location); + var d = new BlockVariableDeclarator (li, (Expression) $4, lt.Location); + current_variable.AddDeclarator (d); + + Warning_NoTypeDeclaration (lt.Location, string.Format ("Constant `{0}'", lt.Value)); + + lbag.AddLocation (d, GetLocation ($1), GetLocation ($3)); + } + | COMMA identifier_inside_body COLON type + { + var lt = (LocatedToken) $2; + var li = RegisterLocalVariable (current_variable.Variable.Block, lt.Value, LocalVariable.Flags.Constant, lt.Location); + var d = new BlockVariableDeclarator (li, null, (FullNamedExpression) $4, lt.Location); + current_variable.AddDeclarator (d); + + Warning_UninitializedConstant (lexer.Location); + + lbag.AddLocation (d, GetLocation ($1)); + } + | COMMA identifier_inside_body COLON type ASSIGN block_variable_initializer + { + var lt = (LocatedToken) $2; + var li = RegisterLocalVariable (current_variable.Variable.Block, lt.Value, LocalVariable.Flags.Constant, lt.Location); + var d = new BlockVariableDeclarator (li, (Expression) $6, (FullNamedExpression) $4, lt.Location); + current_variable.AddDeclarator (d); + + lbag.AddLocation (d, GetLocation ($1), GetLocation ($5)); + } + ; + +block_variable_initializer + : variable_initializer +// | STACKALLOC simple_type OPEN_BRACKET_EXPR expression CLOSE_BRACKET +// { +// $$ = new StackAlloc ((Expression) $2, (Expression) $4, GetLocation ($1)); +// lbag.AddLocation ($$, GetLocation ($3), GetLocation ($5)); +// } +// | STACKALLOC simple_type +// { +// report.Error (1575, GetLocation ($1), "A stackalloc expression requires [] after type"); +// $$ = new StackAlloc ((Expression) $2, null, GetLocation ($1)); +// } + ; + +expression_statement + : statement_expression stmnt_end_semicolon + { + $$ = $1; + lbag.AddStatement ($$, GetLocation ($2)); + } + | statement_expression COMPLETE_COMPLETION { $$ = $1; } +// | statement_expression CLOSE_BRACE +// { +// $$ = $1; +// report.Error (1002, GetLocation ($2), "; expected"); +// lexer.putback ('}'); +// } + ; + +interactive_expression_statement + : interactive_statement_expression SEMICOLON { $$ = $1; } + | interactive_statement_expression COMPLETE_COMPLETION { $$ = $1; } + ; + + // + // We have to do the wrapping here and not in the case above, + // because statement_expression is used for example in for_statement + // +statement_expression + : expression + { + ExpressionStatement s = $1 as ExpressionStatement; + if (s == null) { + var expr = $1 as Expression; + if (expr == null) { + $$ = new StatementErrorExpression (expr); + } else { + // Expressions as statements are allowed + $$ = new StatementFromExpression (expr); + } + } else { + $$ = new StatementExpression (s); + } + } + ; + +interactive_statement_expression + : expression + { + Expression expr = (Expression) $1; + $$ = new StatementExpression (new OptionalAssign (expr, lexer.Location)); + } + | error + { + Error_SyntaxError (yyToken); + $$ = new EmptyStatement (GetLocation ($1)); + } + ; + +selection_statement + : if_statement + | switch_statement + ; + +stmnt_close_parens + : CLOSE_PARENS + { + Lexer.AutoSemiInsertionAfter = 1; + } + ; + +stmnt_else + : ELSE + { + Lexer.AutoSemiInsertionAfter = 1; + } + ; + +if_statement + : IF open_parens_any boolean_expression stmnt_close_parens + embedded_statement + { + if ($5 is EmptyStatement) + Warning_EmptyStatement (GetLocation ($5)); + + $$ = new If ((BooleanExpression) $3, (Statement) $5, GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($2), GetLocation ($4)); + } + | IF open_parens_any boolean_expression stmnt_close_parens + embedded_statement stmnt_else embedded_statement + { + $$ = new If ((BooleanExpression) $3, (Statement) $5, (Statement) $7, GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($2), GetLocation ($4), GetLocation ($6)); + + if ($5 is EmptyStatement) + Warning_EmptyStatement (GetLocation ($5)); + if ($7 is EmptyStatement) + Warning_EmptyStatement (GetLocation ($7)); + } + | IF open_parens_any boolean_expression error + { + Error_SyntaxError (yyToken); + + $$ = new If ((BooleanExpression) $3, null, GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($2)); + } + ; + +switch_statement + : SWITCH open_parens_any expression CLOSE_PARENS OPEN_BRACE + { + Lexer.AutoSemiInsertion = true; + start_block (GetLocation ($5)); + } + opt_switch_sections CLOSE_BRACE + { + $$ = new Switch ((Expression) $3, (ExplicitBlock) current_block.Explicit, GetLocation ($1)); + end_block (GetLocation ($8)); + lbag.AddStatement ($$, GetLocation ($2), GetLocation ($4)); + } + | SWITCH open_parens_any expression error + { + Error_SyntaxError (yyToken); + + $$ = new Switch ((Expression) $3, null, GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($2)); + } + ; + +opt_switch_sections + : /* empty */ + { + report.Warning (1522, 1, current_block.StartLocation, "Empty switch block"); + } + | switch_labels + { + report.Warning (1522, 1, current_block.StartLocation, "Empty switch block"); + } + | switch_sections opt_switch_labels + ; + +switch_sections + : switch_section + | switch_sections switch_section + | error + { + Error_SyntaxError (yyToken); + } + ; + +switch_section + : switch_labels statement_list + ; + +opt_switch_labels + : /* empty */ + | switch_labels + ; + +switch_labels + : switch_label + { + var label = (SwitchLabel) $1; + label.SectionStart = true; + current_block.AddStatement (label); + } + | switch_labels switch_label + { + current_block.AddStatement ((Statement) $2); + } + ; + +switch_label + : CASE constant_expression COLON + { + $$ = new SwitchLabel ((Expression) $2, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($3)); + Lexer.AutoSemiInsertionAfter = 1; + } + | CASE constant_expression error + { + Error_SyntaxError (yyToken); + $$ = new SwitchLabel ((Expression) $2, GetLocation ($1)); + } + | DEFAULT_COLON + { + $$ = new SwitchLabel (null, GetLocation ($1)); + Lexer.AutoSemiInsertionAfter = 1; + } + ; + +iteration_statement + : while_statement + | do_statement + | for_statement + | foreach_statement + ; + +while_statement + : WHILE open_parens_any boolean_expression stmnt_close_parens embedded_statement + { + if ($5 is EmptyStatement && lexer.peek_token () == Token.OPEN_BRACE) + Warning_EmptyStatement (GetLocation ($5)); + + $$ = new While ((BooleanExpression) $3, (Statement) $5, GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($2), GetLocation ($4)); + } + | WHILE open_parens_any boolean_expression error + { + Error_SyntaxError (yyToken); + + $$ = new While ((BooleanExpression) $3, null, GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($2)); + } + ; + +stmnt_do + : DO + { + Lexer.AutoSemiInsertionAfter = 1; + } + ; + +do_while_stmnt_close_parens + : CLOSE_PARENS + { + Lexer.AutoSemiInsertion = true; + } + ; + +do_statement + : stmnt_do embedded_statement WHILE open_parens_any boolean_expression do_while_stmnt_close_parens stmnt_end_semicolon + { + Lexer.AutoSemiInsertion = true; + + $$ = new Do ((Statement) $2, (BooleanExpression) $5, GetLocation ($1), GetLocation ($3)); + lbag.AddStatement ($$, GetLocation ($3), GetLocation ($4), GetLocation ($6), GetLocation ($7)); + } + | stmnt_do embedded_statement error + { + Lexer.AutoSemiInsertion = true; + + Error_SyntaxError (yyToken); + $$ = new Do ((Statement) $2, null, GetLocation ($1), Location.Null); + } + | stmnt_do embedded_statement WHILE open_parens_any boolean_expression error + { + Lexer.AutoSemiInsertion = true; + + Error_SyntaxError (yyToken); + + $$ = new Do ((Statement) $2, (BooleanExpression) $5, GetLocation ($1), GetLocation ($3)); + lbag.AddStatement ($$, GetLocation ($3), GetLocation ($4)); + } + ; + +for_statement + : FOR open_parens_any + { + start_block (GetLocation ($2)); + current_block.IsCompilerGenerated = true; + lexer.ForInParsing = true; + $$ = new Tuple(GetLocation($0), GetLocation($1)); + } + for_statement_cont + { + $$ = $4; + } + ; + +// Has to use be extra rule to recover started block +for_statement_cont + : for_initializer IN + { + lexer.ForInParsing = false; + } + expression stmnt_close_parens embedded_statement + { + if ($6 is EmptyStatement && lexer.peek_token () == Token.OPEN_BRACE) + Warning_EmptyStatement (GetLocation ($6)); + + var locations = (Tuple) $0; + + if ($1 is StatementList) { + report.ErrorPlayScript (1200, GetLocation ($1), "Invalid for-in initializer, only 1 expression expected"); + } + + $$ = new ForIn ((Statement) $1, (Expression) $4, (Statement) $6, current_block, locations.Item1); + lbag.AddStatement ($$, locations.Item2, GetLocation ($2), GetLocation ($5)); + + end_block (GetLocation ($5)); + } + | opt_for_initializer SEMICOLON + { + lexer.ForInParsing = false; + + var locations = (Tuple) $0; + + For f = new For (locations.Item1); + current_block.AddStatement (f); + + f.Initializer = (Statement) $1; + + // Pass the "For" object to the iterator_part4 + oob_stack.Push (f); + + $$ = f; + } + for_condition_and_iterator_part + embedded_statement + { + var locations = (Tuple) $4; + oob_stack.Pop (); + if ($5 is EmptyStatement && lexer.peek_token () == Token.OPEN_BRACE) + Warning_EmptyStatement (GetLocation ($5)); + + For f = ((For) $3); + f.Statement = (Statement) $5; + lbag.AddStatement (f, current_block.StartLocation, GetLocation ($2), GetLocation (locations.Item1), GetLocation (locations.Item2)); + + $$ = end_block (GetLocation ($2)); + } + | error + { + lexer.ForInParsing = false; + Lexer.AutoSemiInsertion = true; + Error_SyntaxError (yyToken); + $$ = end_block (current_block.StartLocation); + } + ; + +for_condition_and_iterator_part + : opt_for_condition SEMICOLON + { + For f = (For) oob_stack.Peek (); + f.Condition = (BooleanExpression) $1; + } + for_iterator_part { + $$ = new Tuple (GetLocation ($2), (Location) $4); + } + + // Handle errors in the case of opt_for_condition being followed by + // a close parenthesis + | opt_for_condition close_parens_close_brace { + Lexer.AutoSemiInsertion = true; + report.Error (1525, GetLocation ($2), "Unexpected symbol `}'"); + For f = (For) oob_stack.Peek (); + f.Condition = (BooleanExpression) $1; + $$ = new Tuple (GetLocation ($2), GetLocation ($2)); + } + ; + +for_iterator_part + : opt_for_iterator stmnt_close_parens { + For f = (For) oob_stack.Peek (); + f.Iterator = (Statement) $1; + $$ = GetLocation ($2); + } + | opt_for_iterator CLOSE_BRACE { + Lexer.AutoSemiInsertion = true; + report.Error (1525, GetLocation ($2), "Unexpected symbol expected ')'"); + For f = (For) oob_stack.Peek (); + f.Iterator = (Statement) $1; + $$ = GetLocation ($2); + } + ; + +close_parens_close_brace + : CLOSE_PARENS + | CLOSE_BRACE { lexer.putback ('}'); } + ; + +opt_for_initializer + : /* empty */ { $$ = new EmptyStatement (lexer.Location); } + | for_initializer + ; + +for_initializer + : variable_declaration + | statement_expression_list + ; + +opt_for_condition + : /* empty */ { $$ = null; } + | boolean_expression + ; + +opt_for_iterator + : /* empty */ { $$ = new EmptyStatement (lexer.Location); } + | for_iterator + ; + +for_iterator + : statement_expression_list + ; + +statement_expression_list + : statement_expression + | statement_expression_list COMMA statement_expression + { + var sl = $1 as StatementList; + if (sl == null) { + sl = new StatementList ((Statement) $1, (Statement) $3); + lbag.AddStatement (sl, GetLocation ($2)); + } else { + sl.Add ((Statement) $3); + lbag.AppendTo (sl, GetLocation ($2)); + } + + $$ = sl; + } + ; + +foreach_statement + : FOR_EACH + { + lexer.ForInParsing = true; + } + open_parens_any for_initializer IN + { + lexer.ForInParsing = false; + } + expression stmnt_close_parens + { + start_block (GetLocation ($3)); + current_block.IsCompilerGenerated = true; + } + embedded_statement + { + if ($10 is EmptyStatement && lexer.peek_token () == Token.OPEN_BRACE) + Warning_EmptyStatement (GetLocation ($10)); + + if ($4 is StatementList) { + report.ErrorPlayScript (1200, GetLocation ($4), "Invalid for-in initializer, only 1 expression expected"); + } + + $$ = new ForEach ((Statement) $4, (Expression) $7, (Statement) $10, current_block, GetLocation ($1)); + + end_block (GetLocation ($5)); + } + ; + +jump_statement + : break_statement + | continue_statement + | goto_statement + | return_statement + | throw_statement + | yield_statement + | use_namespace_statement + ; + +break_statement + : BREAK stmnt_end_semicolon + { + $$ = new Break (GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($2)); + } + ; + +continue_statement + : CONTINUE stmnt_end_semicolon + { + $$ = new Continue (GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($2)); + } + | CONTINUE error + { + Error_SyntaxError (yyToken); + $$ = new Continue (GetLocation ($1)); + } + ; + +goto_statement + : GOTO identifier_inside_body stmnt_end_semicolon + { + var lt = (LocatedToken) $2; + $$ = new Goto (lt.Value, GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($2), GetLocation ($3)); + } + | GOTO CASE constant_expression stmnt_end_semicolon + { + $$ = new GotoCase ((Expression) $3, GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($2), GetLocation ($4)); + } + | GOTO DEFAULT stmnt_end_semicolon + { + $$ = new GotoDefault (GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($2), GetLocation ($3)); + } + ; + +return_statement + : RETURN opt_expression stmnt_end_semicolon + { + $$ = new Return ((Expression) $2, GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($3)); + } + | RETURN expression error + { + Lexer.AutoSemiInsertion = true; + Error_SyntaxError (yyToken); + $$ = new Return ((Expression) $2, GetLocation ($1)); + } + | RETURN error + { + Lexer.AutoSemiInsertion = true; + Error_SyntaxError (yyToken); + $$ = new Return (null, GetLocation ($1)); + } + ; + +throw_statement + : THROW opt_expression stmnt_end_semicolon + { + $$ = new Throw ((Expression) $2, GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($3)); + } + | THROW error + { + Lexer.AutoSemiInsertion = true; + Error_SyntaxError (yyToken); + $$ = new Throw (null, GetLocation ($1)); + } + ; + +yield_statement + : identifier_inside_body RETURN opt_expression stmnt_end_semicolon + { + var lt = (LocatedToken) $1; + string s = lt.Value; + if (s != "yield"){ + report.Error (1003, lt.Location, "; expected"); + } else if ($3 == null) { + report.Error (1627, GetLocation ($4), "Expression expected after yield return"); + } else if (lang_version == LanguageVersion.ISO_1){ + FeatureIsNotAvailable (lt.Location, "iterators"); + } + + current_block.Explicit.RegisterIteratorYield (); + $$ = new Yield ((Expression) $3, lt.Location); + lbag.AddStatement ($$, GetLocation ($2), GetLocation ($4)); + } + | identifier_inside_body RETURN expression error + { + Lexer.AutoSemiInsertion = true; + + Error_SyntaxError (yyToken); + + var lt = (LocatedToken) $1; + string s = lt.Value; + if (s != "yield"){ + report.Error (1003, lt.Location, "; expected"); + } else if ($3 == null) { + report.Error (1627, GetLocation ($4), "Expression expected after yield return"); + } else if (lang_version == LanguageVersion.ISO_1){ + FeatureIsNotAvailable (lt.Location, "iterators"); + } + + current_block.Explicit.RegisterIteratorYield (); + $$ = new Yield ((Expression) $3, lt.Location); + lbag.AddStatement ($$, GetLocation ($2)); + } + | identifier_inside_body BREAK stmnt_end_semicolon + { + var lt = (LocatedToken) $1; + string s = lt.Value; + if (s != "yield"){ + report.Error (1003, lt.Location, "; expected"); + } else if (lang_version == LanguageVersion.ISO_1){ + FeatureIsNotAvailable (lt.Location, "iterators"); + } + + current_block.Explicit.RegisterIteratorYield (); + $$ = new YieldBreak (lt.Location); + lbag.AddStatement ($$, GetLocation ($2), GetLocation ($3)); + } + ; + +opt_expression + : /* empty */ + | expression + ; + +try_statement + : TRY block catch_clauses + { + $$ = new TryCatch ((Block) $2, (List) $3, GetLocation ($1), false); + } + | TRY block FINALLY block + { + $$ = new TryFinally ((Statement) $2, (Block) $4, GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($3)); + } + | TRY block catch_clauses FINALLY block + { + $$ = new TryFinally (new TryCatch ((Block) $2, (List) $3, Location.Null, true), (Block) $5, GetLocation ($1)); + lbag.AddStatement ($$, GetLocation ($4)); + } + | TRY block error + { + Error_SyntaxError (1524, yyToken); + $$ = new TryCatch ((Block) $2, null, GetLocation ($1), false); + } + ; + +catch_clauses + : catch_clause + { + var l = new List (2); + + l.Add ((CSharp.Catch) $1); + $$ = l; + } + | catch_clauses catch_clause + { + var l = (List) $1; + + var c = (CSharp.Catch) $2; + if (l [l.Count - 1].IsGeneral) { + report.Error (1017, c.loc, "Try statement already has an empty catch block"); + } + + l.Add (c); + $$ = l; + } + ; + +opt_identifier + : /* empty */ + | identifier_inside_body + ; + +opt_catch_type + : + { + Warning_NoTypeDeclaration (lexer.Location, "Catch variable"); + $$ = new UntypedTypeExpression (lexer.Location); + } + | COLON type + { + $$ = $2; + } + ; + +catch_clause + : CATCH open_parens_any IDENTIFIER COLON type CLOSE_PARENS + { + start_block (GetLocation ($2)); + var c = new Catch (current_block, GetLocation ($1)); + + var lt = (LocatedToken) $3; + c.TypeExpression = (FullNamedExpression) $5; + c.Variable = new LocalVariable (current_block, lt.Value, lt.Location); + current_block.AddLocalName (c.Variable); + + lbag.AddLocation (c, GetLocation ($2), GetLocation ($6)); + $$ = c; + } + block_prepared + { + $$ = $7; + } + | CATCH open_parens_any IDENTIFIER CLOSE_PARENS + { + Warning_NoTypeDeclaration (GetLocation ($1), "Catch variable"); + + start_block (GetLocation ($2)); + var c = new Catch (current_block, GetLocation ($1)); + + var lt = (LocatedToken) $3; + c.Variable = new LocalVariable (current_block, lt.Value, lt.Location); + current_block.AddLocalName (c.Variable); + + lbag.AddLocation (c, GetLocation ($2), GetLocation ($4)); + $$ = c; + } + block_prepared + { + $$ = $5; + } + | CATCH open_parens_any error + { + if (yyToken == Token.CLOSE_PARENS) { + report.Error (1015, lexer.Location, + "A type that derives from `System.Exception', `object', or `string' expected"); + } else { + Error_SyntaxError (yyToken); + } + + $$ = new Catch (null, GetLocation ($1)); + } + | CATCH open_parens_any type opt_identifier CLOSE_PARENS error + { + Error_SyntaxError (yyToken); + + // Required otherwise missing block could not be detected because + // start_block is run early + var c = new Catch (null, GetLocation ($1)); + c.TypeExpression = (FullNamedExpression) $3; + + if ($4 != null) { + var lt = (LocatedToken) $4; + c.Variable = new LocalVariable (current_block, lt.Value, lt.Location); + } + + lbag.AddLocation (c, GetLocation ($2), GetLocation ($5)); + + $$ = c; + } + ; + +// LINQ + +query_expression + : first_from_clause query_body + { + lexer.query_parsing = false; + + Linq.AQueryClause from = $1 as Linq.AQueryClause; + + from.Tail.Next = (Linq.AQueryClause)$2; + $$ = from; + + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + } + | nested_from_clause query_body + { + Linq.AQueryClause from = $1 as Linq.AQueryClause; + + from.Tail.Next = (Linq.AQueryClause)$2; + $$ = from; + + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + } + + // Bubble up COMPLETE_COMPLETION productions + | first_from_clause COMPLETE_COMPLETION { + lexer.query_parsing = false; + $$ = $1; + + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + } + | nested_from_clause COMPLETE_COMPLETION { + $$ = $1; + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + } + ; + +first_from_clause + : FROM_FIRST identifier_inside_body IN expression + { + current_block = new Linq.QueryBlock (current_block, lexer.Location); + + var lt = (LocatedToken) $2; + var rv = new Linq.RangeVariable (lt.Value, lt.Location); + $$ = new Linq.QueryExpression (new Linq.QueryStartClause ((Linq.QueryBlock)current_block, (Expression)$4, rv, GetLocation ($1))); + } + | FROM_FIRST type identifier_inside_body IN expression + { + current_block = new Linq.QueryBlock (current_block, lexer.Location); + + var lt = (LocatedToken) $3; + var rv = new Linq.RangeVariable (lt.Value, lt.Location); + $$ = new Linq.QueryExpression ( + new Linq.QueryStartClause ((Linq.QueryBlock)current_block, (Expression)$5, rv, GetLocation ($1)) { + IdentifierType = (FullNamedExpression)$2 + } + ); + } + ; + +nested_from_clause + : FROM identifier_inside_body IN expression + { + current_block = new Linq.QueryBlock (current_block, lexer.Location); + + var lt = (LocatedToken) $2; + var rv = new Linq.RangeVariable (lt.Value, lt.Location); + $$ = new Linq.QueryExpression (new Linq.QueryStartClause ((Linq.QueryBlock)current_block, (Expression)$4, rv, GetLocation ($1))); + } + | FROM type identifier_inside_body IN expression + { + current_block = new Linq.QueryBlock (current_block, lexer.Location); + + var lt = (LocatedToken) $3; + var rv = new Linq.RangeVariable (lt.Value, lt.Location); + $$ = new Linq.QueryExpression ( + new Linq.QueryStartClause ((Linq.QueryBlock)current_block, (Expression)$5, rv, GetLocation ($1)) { + IdentifierType = (FullNamedExpression)$2 + } + ); + } + ; + +from_clause + : FROM identifier_inside_body IN + { + current_block = new Linq.QueryBlock (current_block, lexer.Location); + } + expression_or_error + { + var lt = (LocatedToken) $2; + var sn = new Linq.RangeVariable (lt.Value, lt.Location); + $$ = new Linq.SelectMany ((Linq.QueryBlock)current_block, sn, (Expression)$5, GetLocation ($1)); + + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + + ((Linq.QueryBlock)current_block).AddRangeVariable (sn); + } + | FROM type identifier_inside_body IN + { + current_block = new Linq.QueryBlock (current_block, lexer.Location); + } + expression_or_error + { + var lt = (LocatedToken) $3; + var sn = new Linq.RangeVariable (lt.Value, lt.Location); + + $$ = new Linq.SelectMany ((Linq.QueryBlock)current_block, sn, (Expression)$6, GetLocation ($1)) { + IdentifierType = (FullNamedExpression)$2 + }; + + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + + ((Linq.QueryBlock)current_block).AddRangeVariable (sn); + } + ; + +query_body + : query_body_clauses select_or_group_clause opt_query_continuation + { + Linq.AQueryClause head = (Linq.AQueryClause)$2; + + if ($3 != null) + head.Next = (Linq.AQueryClause)$3; + + if ($1 != null) { + Linq.AQueryClause clause = (Linq.AQueryClause)$1; + clause.Tail.Next = head; + head = clause; + } + + $$ = head; + } + | select_or_group_clause opt_query_continuation + { + Linq.AQueryClause head = (Linq.AQueryClause)$2; + + if ($1 != null) { + Linq.AQueryClause clause = (Linq.AQueryClause)$1; + clause.Tail.Next = head; + head = clause; + } + + $$ = head; + } + | query_body_clauses COMPLETE_COMPLETION + | query_body_clauses error + { + report.Error (742, GetLocation ($2), "Unexpected symbol `{0}'. A query body must end with select or group clause", GetSymbolName (yyToken)); + $$ = $1; + } + | error + { + Error_SyntaxError (yyToken); + $$ = null; + } + ; + +select_or_group_clause + : SELECT + { + current_block = new Linq.QueryBlock (current_block, lexer.Location); + } + expression_or_error + { + $$ = new Linq.Select ((Linq.QueryBlock)current_block, (Expression)$3, GetLocation ($1)); + + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + } + | GROUP + { + if (linq_clause_blocks == null) + linq_clause_blocks = new Stack (); + + current_block = new Linq.QueryBlock (current_block, lexer.Location); + linq_clause_blocks.Push ((Linq.QueryBlock)current_block); + } + expression_or_error + { + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + + current_block = new Linq.QueryBlock (current_block, lexer.Location); + } + BY expression_or_error + { + $$ = new Linq.GroupBy ((Linq.QueryBlock)current_block, (Expression)$3, linq_clause_blocks.Pop (), (Expression)$6, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($5)); + + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + } + ; + +query_body_clauses + : query_body_clause + | query_body_clauses query_body_clause + { + ((Linq.AQueryClause)$1).Tail.Next = (Linq.AQueryClause)$2; + $$ = $1; + } + ; + +query_body_clause + : from_clause + | let_clause + | where_clause + | join_clause + | orderby_clause + ; + +let_clause + : LET identifier_inside_body ASSIGN + { + current_block = new Linq.QueryBlock (current_block, lexer.Location); + } + expression_or_error + { + var lt = (LocatedToken) $2; + var sn = new Linq.RangeVariable (lt.Value, lt.Location); + $$ = new Linq.Let ((Linq.QueryBlock) current_block, sn, (Expression)$5, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($3)); + + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + + ((Linq.QueryBlock)current_block).AddRangeVariable (sn); + } + ; + +where_clause + : WHERE + { + current_block = new Linq.QueryBlock (current_block, lexer.Location); + } + expression_or_error + { + $$ = new Linq.Where ((Linq.QueryBlock)current_block, (Expression)$3, GetLocation ($1)); + + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + } + ; + +join_clause + : JOIN identifier_inside_body IN + { + if (linq_clause_blocks == null) + linq_clause_blocks = new Stack (); + + current_block = new Linq.QueryBlock (current_block, lexer.Location); + linq_clause_blocks.Push ((Linq.QueryBlock) current_block); + } + expression_or_error ON + { + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + + current_block = new Linq.QueryBlock (current_block, lexer.Location); + linq_clause_blocks.Push ((Linq.QueryBlock) current_block); + } + expression_or_error EQUALS + { + current_block.AddStatement (new ContextualReturn ((Expression) $8)); + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + + current_block = new Linq.QueryBlock (current_block, lexer.Location); + } + expression_or_error opt_join_into + { + current_block.AddStatement (new ContextualReturn ((Expression) $11)); + current_block.SetEndLocation (lexer.Location); + + var outer_selector = linq_clause_blocks.Pop (); + var block = linq_clause_blocks.Pop (); + + var lt = (LocatedToken) $2; + var sn = new Linq.RangeVariable (lt.Value, lt.Location); + Linq.RangeVariable into; + + if ($12 == null) { + into = sn; + $$ = new Linq.Join (block, sn, (Expression)$5, outer_selector, (Linq.QueryBlock) current_block, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($3), GetLocation ($6), GetLocation ($9)); + } else { + // + // Set equals right side parent to beginning of linq query, it is not accessible therefore cannot cause name collisions + // + var parent = block.Parent; + while (parent is Linq.QueryBlock) { + parent = parent.Parent; + } + current_block.Parent = parent; + + ((Linq.QueryBlock)current_block).AddRangeVariable (sn); + + lt = (LocatedToken) $12; + into = new Linq.RangeVariable (lt.Value, lt.Location); + + $$ = new Linq.GroupJoin (block, sn, (Expression)$5, outer_selector, (Linq.QueryBlock) current_block, into, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($3), GetLocation ($6), GetLocation ($9), GetLocation ($12)); + } + + current_block = block.Parent; + ((Linq.QueryBlock)current_block).AddRangeVariable (into); + } + | JOIN type identifier_inside_body IN + { + if (linq_clause_blocks == null) + linq_clause_blocks = new Stack (); + + current_block = new Linq.QueryBlock (current_block, lexer.Location); + linq_clause_blocks.Push ((Linq.QueryBlock) current_block); + } + expression_or_error ON + { + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + + current_block = new Linq.QueryBlock (current_block, lexer.Location); + linq_clause_blocks.Push ((Linq.QueryBlock) current_block); + } + expression_or_error EQUALS + { + current_block.AddStatement (new ContextualReturn ((Expression) $9)); + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + + current_block = new Linq.QueryBlock (current_block, lexer.Location); + } + expression_or_error opt_join_into + { + current_block.AddStatement (new ContextualReturn ((Expression) $12)); + current_block.SetEndLocation (lexer.Location); + + var outer_selector = linq_clause_blocks.Pop (); + var block = linq_clause_blocks.Pop (); + + var lt = (LocatedToken) $3; + var sn = new Linq.RangeVariable (lt.Value, lt.Location); + Linq.RangeVariable into; + + if ($13 == null) { + into = sn; + $$ = new Linq.Join (block, sn, (Expression)$6, outer_selector, (Linq.QueryBlock) current_block, GetLocation ($1)) { + IdentifierType = (FullNamedExpression)$2 + }; + } else { + // + // Set equals right side parent to beginning of linq query, it is not accessible therefore cannot cause name collisions + // + var parent = block.Parent; + while (parent is Linq.QueryBlock) { + parent = parent.Parent; + } + current_block.Parent = parent; + + ((Linq.QueryBlock)current_block).AddRangeVariable (sn); + + lt = (LocatedToken) $13; + into = new Linq.RangeVariable (lt.Value, lt.Location); // TODO: + + $$ = new Linq.GroupJoin (block, sn, (Expression)$6, outer_selector, (Linq.QueryBlock) current_block, into, GetLocation ($1)) { + IdentifierType = (FullNamedExpression)$2 + }; + } + + current_block = block.Parent; + ((Linq.QueryBlock)current_block).AddRangeVariable (into); + } + ; + +opt_join_into + : /* empty */ + | INTO identifier_inside_body + { + $$ = $2; + } + ; + +orderby_clause + : ORDERBY + { + current_block = new Linq.QueryBlock (current_block, lexer.Location); + } + orderings + { + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + + $$ = $3; + } + ; + +orderings + : order_by + | order_by COMMA + { + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + + current_block = new Linq.QueryBlock (current_block, lexer.Location); + } + orderings_then_by + { + ((Linq.AQueryClause)$1).Next = (Linq.AQueryClause)$4; + $$ = $1; + } + ; + +orderings_then_by + : then_by + | orderings_then_by COMMA + { + current_block.SetEndLocation (lexer.Location); + current_block = current_block.Parent; + + current_block = new Linq.QueryBlock ((Linq.QueryBlock) current_block, lexer.Location); + } + then_by + { + ((Linq.AQueryClause)$1).Tail.Next = (Linq.AQueryClause)$4; + $$ = $1; + } + ; + +order_by + : expression + { + $$ = new Linq.OrderByAscending ((Linq.QueryBlock) current_block, (Expression)$1); + } + | expression ASCENDING + { + $$ = new Linq.OrderByAscending ((Linq.QueryBlock) current_block, (Expression)$1); + lbag.AddLocation ($$, GetLocation ($2)); + } + | expression DESCENDING + { + $$ = new Linq.OrderByDescending ((Linq.QueryBlock) current_block, (Expression)$1); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + +then_by + : expression + { + $$ = new Linq.ThenByAscending ((Linq.QueryBlock) current_block, (Expression)$1); + } + | expression ASCENDING + { + $$ = new Linq.ThenByAscending ((Linq.QueryBlock) current_block, (Expression)$1); + lbag.AddLocation ($$, GetLocation ($2)); + } + | expression DESCENDING + { + $$ = new Linq.ThenByDescending ((Linq.QueryBlock) current_block, (Expression)$1); + lbag.AddLocation ($$, GetLocation ($2)); + } + ; + + +opt_query_continuation + : /* empty */ + | INTO identifier_inside_body + { + // query continuation block is not linked with query block but with block + // before. This means each query can use same range variable names for + // different identifiers. + + current_block.SetEndLocation (GetLocation ($1)); + current_block = current_block.Parent; + + current_block = new Linq.QueryBlock (current_block, lexer.Location); + + if (linq_clause_blocks == null) + linq_clause_blocks = new Stack (); + + linq_clause_blocks.Push ((Linq.QueryBlock) current_block); + } + query_body + { + var current_block = linq_clause_blocks.Pop (); + var lt = (LocatedToken) $2; + var rv = new Linq.RangeVariable (lt.Value, lt.Location); + $$ = new Linq.QueryStartClause ((Linq.QueryBlock)current_block, null, rv, GetLocation ($1)) { + next = (Linq.AQueryClause)$4 + }; + } + ; + +// +// Support for using the compiler as an interactive parser +// +// The INTERACTIVE_PARSER token is first sent to parse our +// productions; If the result is a Statement, the parsing +// is repeated, this time with INTERACTIVE_PARSE_WITH_BLOCK +// to setup the blocks in advance. +// +// This setup is here so that in the future we can add +// support for other constructs (type parsing, namespaces, etc) +// that do not require a block to be setup in advance +// + +interactive_parsing + : EVAL_STATEMENT_PARSER EOF + | EVAL_USING_DECLARATIONS_UNIT_PARSER package_directives opt_COMPLETE_COMPLETION + | EVAL_STATEMENT_PARSER + { + current_container = current_type = new Class (current_container, new MemberName (""), Modifiers.PUBLIC, null); + + // (ref object retval) + Parameter [] mpar = new Parameter [1]; + mpar [0] = new Parameter (new TypeExpression (compiler.BuiltinTypes.Object, Location.Null), "$retval", Parameter.Modifier.REF, null, Location.Null); + + ParametersCompiled pars = new ParametersCompiled (mpar); + var mods = Modifiers.PUBLIC | Modifiers.STATIC; + if (settings.Unsafe) + mods |= Modifiers.UNSAFE; + + current_local_parameters = pars; + var method = new CSharp.Method ( + current_type, + new TypeExpression (compiler.BuiltinTypes.Void, Location.Null), + mods, + new MemberName ("Host"), + pars, + null /* attributes */); + + current_type.AddMember (method); + + // Always set to true when in ineractive mode + is_config_enabled = true; + + oob_stack.Push (method); + ++lexer.parsing_block; + start_block (lexer.Location); + } + interactive_statement_list opt_COMPLETE_COMPLETION + { + --lexer.parsing_block; + Method method = (Method) oob_stack.Pop (); + + method.Block = (ToplevelBlock) end_block(lexer.Location); + + InteractiveResult = (Class) pop_current_class (); + current_local_parameters = null; + } + | EVAL_COMPILATION_UNIT_PARSER interactive_compilation_unit + ; + +interactive_compilation_unit + : opt_extern_alias_directives opt_package_directives + | opt_extern_alias_directives opt_package_directives package_declaration + ; + +opt_COMPLETE_COMPLETION + : /* nothing */ + | COMPLETE_COMPLETION + ; + +//close_brace_or_complete_completion +// : CLOSE_BRACE +// | COMPLETE_COMPLETION +// ; + +// +// XML documentation code references micro parser +// +documentation_parsing + : DOC_SEE doc_cref + { + module.DocumentationBuilder.ParsedName = (MemberName) $2; + } + ; + +doc_cref + : doc_type_declaration_name opt_doc_method_sig + { + module.DocumentationBuilder.ParsedParameters = (List)$2; + } + | builtin_types opt_doc_method_sig + { + module.DocumentationBuilder.ParsedBuiltinType = (TypeExpression)$1; + module.DocumentationBuilder.ParsedParameters = (List)$2; + $$ = null; + } + | builtin_types DOT IDENTIFIER opt_doc_method_sig + { + module.DocumentationBuilder.ParsedBuiltinType = (TypeExpression)$1; + module.DocumentationBuilder.ParsedParameters = (List)$4; + var lt = (LocatedToken) $3; + $$ = new MemberName (lt.Value); + } + | doc_type_declaration_name DOT THIS + { + $$ = new MemberName ((MemberName) $1, MemberCache.IndexerNameAlias, Location.Null); + } + | doc_type_declaration_name DOT THIS OPEN_BRACKET + { + valid_param_mod = ParameterModifierType.Ref | ParameterModifierType.Out; + } + opt_doc_parameters CLOSE_BRACKET + { + module.DocumentationBuilder.ParsedParameters = (List)$6; + $$ = new MemberName ((MemberName) $1, MemberCache.IndexerNameAlias, Location.Null); + } + | EXPLICIT OPERATOR type opt_doc_method_sig + { + var p = (List)$4 ?? new List (1); + p.Add (new DocumentationParameter ((FullNamedExpression) $3)); + module.DocumentationBuilder.ParsedParameters = p; + module.DocumentationBuilder.ParsedOperator = Operator.OpType.Explicit; + $$ = null; + } + | IMPLICIT OPERATOR type opt_doc_method_sig + { + var p = (List)$4 ?? new List (1); + p.Add (new DocumentationParameter ((FullNamedExpression) $3)); + module.DocumentationBuilder.ParsedParameters = p; + module.DocumentationBuilder.ParsedOperator = Operator.OpType.Implicit; + $$ = null; + } + ; + +doc_type_declaration_name + : type_declaration_name + | doc_type_declaration_name DOT type_declaration_name + { + $$ = new MemberName (((MemberName) $1), (MemberName) $3); + } + ; + +opt_doc_method_sig + : /* empty */ + | OPEN_PARENS + { + valid_param_mod = ParameterModifierType.Ref | ParameterModifierType.Out; + } + opt_doc_parameters CLOSE_PARENS + { + $$ = $3; + } + ; + +opt_doc_parameters + : /* empty */ + { + $$ = new List (0); + } + | doc_parameters + ; + +doc_parameters + : doc_parameter + { + var parameters = new List (); + parameters.Add ((DocumentationParameter) $1); + $$ = parameters; + } + | doc_parameters COMMA doc_parameter + { + var parameters = $1 as List; + parameters.Add ((DocumentationParameter) $3); + $$ = parameters; + } + ; + +doc_parameter + : opt_parameter_modifier parameter_type + { + if ($1 != null) + $$ = new DocumentationParameter ((Parameter.Modifier) $1, (FullNamedExpression) $2); + else + $$ = new DocumentationParameter ((FullNamedExpression) $2); + } + ; + +%% + +// +// A class used to hold info about an operator declarator +// +class OperatorDeclaration { + public readonly Operator.OpType optype; + public readonly FullNamedExpression ret_type; + public readonly Location location; + + public OperatorDeclaration (Operator.OpType op, FullNamedExpression ret_type, Location location) + { + optype = op; + this.ret_type = ret_type; + this.location = location; + } +} + +void Error_ExpectingTypeName (Expression expr) +{ + if (expr is Invocation){ + report.Error (1002, expr.Location, "Expecting `;'"); + } else { + expr.Error_InvalidExpressionStatement (report); + } +} + +void Error_ParameterModifierNotValid (string modifier, Location loc) +{ + report.Error (631, loc, "The parameter modifier `{0}' is not valid in this context", + modifier); +} + +void Error_DuplicateParameterModifier (Location loc, Parameter.Modifier mod) +{ + report.Error (1107, loc, "Duplicate parameter modifier `{0}'", + Parameter.GetModifierSignature (mod)); +} + +void Error_TypeExpected (Location loc) +{ + report.Error (1031, loc, "Type expected"); +} + +void Error_UnsafeCodeNotAllowed (Location loc) +{ + report.Error (227, loc, "Unsafe code requires the `unsafe' command line option to be specified"); +} + +void Warning_EmptyStatement (Location loc) +{ + report.Warning (642, 3, loc, "Possible mistaken empty statement"); +} + +void Warning_NoTypeDeclaration (Location loc, string member) +{ + report.WarningPlayScript (1009, loc, "{0} has no type declaration", member); +} + +void Warning_UninitializedConstant (Location loc) +{ + report.WarningPlayScript (1111, loc, "The constant was not initialized"); +} + +void Error_NamedArgumentExpected (NamedArgument a) +{ + report.Error (1738, a.Location, "Named arguments must appear after the positional arguments"); +} + +void Error_MissingInitializer (Location loc) +{ + report.Error (210, loc, "You must provide an initializer in a fixed or using statement declaration"); +} + +object Error_AwaitAsIdentifier (object token) +{ + if (async_block) { + report.Error (4003, GetLocation (token), "`await' cannot be used as an identifier within an async method or lambda expression"); + return new LocatedToken ("await", GetLocation (token)); + } + + return token; +} + +void push_current_container (TypeDefinition tc, object partial_token) +{ + if (module.Evaluator != null){ + tc.Definition.Modifiers = tc.ModFlags = (tc.ModFlags & ~Modifiers.AccessibilityMask) | Modifiers.PUBLIC; + if (undo == null) + undo = new Undo (); + + undo.AddTypeContainer (current_container, tc); + } + + if (is_config_enabled) { + if (partial_token != null) + current_container.AddPartial (tc); + else + current_container.AddTypeContainer (tc); + } + + is_config_enabled = true; + + ++lexer.parsing_declaration; + current_container = tc; + current_type = tc; +} + +TypeContainer pop_current_class () +{ + var retval = current_container; + + current_container = current_container.Parent; + current_type = current_type.Parent as TypeDefinition; + + return retval; +} + +[System.Diagnostics.Conditional ("FULL_AST")] +void StoreModifierLocation (object token, Location loc) +{ + if (lbag == null) + return; + + if (mod_locations == null) + mod_locations = new List> (); + + mod_locations.Add (Tuple.Create ((Modifiers) token, loc)); +} + +string CheckAttributeTarget (string a, Location l) +{ + switch (a) { + case "assembly" : case "module" : case "field" : case "method" : case "param" : case "property" : case "type" : + return a; + } + + report.Warning (658, 1, l, + "`{0}' is invalid attribute target. All attributes in this attribute section will be ignored", a); + return string.Empty; +} + +bool IsPartial (object a) +{ + var attrs = a as Attributes; + if (attrs == null) + return false; + foreach (var attr in attrs.Attrs) { + if (attr.TypeExpression.Name == "Partial") + return true; + } + return false; +} + +static bool IsUnaryOperator (Operator.OpType op) +{ + switch (op) { + + case Operator.OpType.LogicalNot: + case Operator.OpType.OnesComplement: + case Operator.OpType.Increment: + case Operator.OpType.Decrement: + case Operator.OpType.True: + case Operator.OpType.False: + case Operator.OpType.UnaryPlus: + case Operator.OpType.UnaryNegation: + return true; + } + return false; +} + +void syntax_error (Location l, string msg) +{ + report.Error (1003, l, "Syntax error, " + msg); +} + +Tokenizer lexer; + +public Tokenizer Lexer { + get { + return lexer; + } +} + +public PlayScriptParser (SeekableStreamReader reader, CompilationSourceFile file, ParserSession session) + : this (reader, file, file.Compiler.Report, session) +{ +} + +public PlayScriptParser (SeekableStreamReader reader, CompilationSourceFile file, Report report, ParserSession session) +{ + this.file = file; + current_container = current_namespace = file; + + this.module = file.Module; + this.compiler = file.Compiler; + this.settings = compiler.Settings; + this.report = report; + + lang_version = settings.Version; + yacc_verbose_flag = settings.VerboseParserFlag; + doc_support = settings.DocumentationFile != null; + lexer = new Tokenizer (reader, file, session); + oob_stack = new Stack (); + lbag = session.LocationsBag; + use_global_stacks = session.UseJayGlobalArrays; + parameters_bucket = session.ParametersStack; +} + +public void parse () +{ + eof_token = Token.EOF; + + try { + if (yacc_verbose_flag > 1) + yyparse (lexer, new yydebug.yyDebugSimple ()); + else + yyparse (lexer); + + Tokenizer tokenizer = lexer as Tokenizer; + tokenizer.cleanup (); + } catch (Exception e){ + if (e is yyParser.yyUnexpectedEof) { + Error_SyntaxError (yyToken); + UnexpectedEOF = true; + return; + } + + if (e is yyParser.yyException) { + if (report.Errors == 0) + report.Error (-25, lexer.Location, "Parsing error"); + } else { + // Used by compiler-tester to test internal errors + if (yacc_verbose_flag > 0 || e is FatalException) + throw; + + report.Error (589, lexer.Location, "Internal compiler error during parsing" + e); + } + } +} + +void CheckToken (int error, int yyToken, string msg, Location loc) +{ + if (yyToken >= Token.FIRST_KEYWORD && yyToken <= Token.LAST_KEYWORD) + report.Error (error, loc, "{0}: `{1}' is a keyword", msg, GetTokenName (yyToken)); + else + report.Error (error, loc, msg); +} + +string ConsumeStoredComment () +{ + string s = tmpComment; + tmpComment = null; + Lexer.doc_state = XmlCommentState.Allowed; + return s; +} + +void FeatureIsNotAvailable (Location loc, string feature) +{ + report.FeatureIsNotAvailable (compiler, loc, feature); +} + +Location GetLocation (object obj) +{ + var lt = obj as LocatedToken; + if (lt != null) + return lt.Location; + + var mn = obj as MemberName; + if (mn != null) + return mn.Location; + + var expr = obj as Expression; + if (expr != null) + return expr.Location; + + return lexer.Location; +} + +void start_block (Location loc) +{ + if (current_block == null) { + var package = current_container as Package; + if (package != null && current_local_parameters == null) { + current_block = package.GetBlock (); + current_block = new ExplicitBlock (current_block, loc, Location.Null); + } else { + current_block = new ToplevelBlock (compiler, current_local_parameters ?? ParametersCompiled.EmptyReadOnlyParameters, loc); + } + + parsing_anonymous_method = false; + } else if (parsing_anonymous_method) { + current_block = new ParametersBlock (current_block, current_local_parameters, loc); + parsing_anonymous_method = false; + } else { + current_block = new ExplicitBlock (current_block, loc, Location.Null); + } +} + +Block +end_block (Location loc) +{ + Block retval = current_block.Explicit; + retval.SetEndLocation (loc); + current_block = retval.Parent; + return retval; +} + +void start_anonymous (ParametersCompiled parameters, FullNamedExpression returnType, Location loc) +{ + oob_stack.Push (current_anonymous_method); + oob_stack.Push (current_local_parameters); + oob_stack.Push (current_variable); + oob_stack.Push (Lexer.AutoSemiInsertion); + + current_local_parameters = parameters; + current_anonymous_method = new LocalFunction (returnType, loc); + + // Force the next block to be created as a ParametersBlock + parsing_anonymous_method = true; +} + +/* + * Completes the anonymous method processing, if lambda_expr is null, this + * means that we have a Statement instead of an Expression embedded + */ +AnonymousMethodExpression end_anonymous (ParametersBlock anon_block) +{ + AnonymousMethodExpression retval; + + current_anonymous_method.Block = anon_block; + retval = current_anonymous_method; + + Lexer.AutoSemiInsertion = (bool) oob_stack.Pop (); + current_variable = (BlockVariable) oob_stack.Pop (); + current_local_parameters = (ParametersCompiled) oob_stack.Pop (); + current_anonymous_method = (AnonymousMethodExpression) oob_stack.Pop (); + + return retval; +} + +static TypeDefinition GetTypeDefinition (TypeContainer container) +{ + var td = container as TypeDefinition; + if (td != null) + return td; + + Package pkg = (Package) container; + return pkg.GetGlobalsTypeDefinition (); + +} + +void Error_SyntaxError (int token) +{ + Error_SyntaxError (0, token); +} + +void Error_SyntaxError (int error_code, int token) +{ + Error_SyntaxError (error_code, token, "Unexpected symbol"); +} + +void Error_SyntaxError (int error_code, int token, string msg) +{ + Lexer.CompleteOnEOF = false; + + // An error message has been reported by tokenizer + if (token == Token.ERROR) + return; + + // Avoid duplicit error message after unterminated string literals + if (token == Token.LITERAL && lexer.Location.Column == 0) + return; + + string symbol = GetSymbolName (token); + string expecting = GetExpecting (); + var loc = lexer.Location - symbol.Length; + + if (error_code == 0) { + if (expecting == "`identifier'") { + if (token > Token.FIRST_KEYWORD && token < Token.LAST_KEYWORD) { + report.Error (1041, loc, "Identifier expected, `{0}' is a keyword", symbol); + return; + } + + error_code = 1001; + expecting = "identifier"; + } else if (expecting == "`)'") { + error_code = 1026; + } else { + error_code = 1525; + } + } + + if (string.IsNullOrEmpty (expecting)) + report.Error (error_code, loc, "{1} `{0}'", symbol, msg); + else + report.Error (error_code, loc, "{2} `{0}', expecting {1}", symbol, expecting, msg); +} + +void CheckIsPlayScript(string elem, Location loc) +{ + if (!parsing_playscript) { + report.Error (7035, loc, "`{0}' only supported in PlayScript", elem); + } + +} + +MemberName CreateFullMemberName (LocatedToken lt, TypeParameters tparams = null) +{ + if (namespace_modifier != null) { + var res = new NamespaceMemberName (namespace_modifier.Value, lt.Value, lt.Location); + namespace_modifier = null; + return res; + } + + return new MemberName (lt.Value, tparams, lt.Location); +} + +/* +object ConvertAsType(SimpleName sn, object e) +{ + if (sn.Name == "Object") + return new TypeExpression (compiler.BuiltinTypes.Dynamic, GetLocation (e)); + else if (sn.Name == "Boolean") + return new TypeExpression (compiler.BuiltinTypes.Bool, GetLocation (e)); + else if (sn.Name == "Number") + return new TypeExpression (compiler.BuiltinTypes.Double, GetLocation (e)); + else if (sn.Name == "String") + return new TypeExpression (compiler.BuiltinTypes.String, GetLocation (e)); + else if (sn.Name == "void") + return new TypeExpression (compiler.BuiltinTypes.Void, GetLocation (e)); + else if (sn.Name == "Function") + return new TypeExpression (compiler.BuiltinTypes.Delegate, GetLocation (e)); + else if (sn.Name == "Class") + return new TypeExpression (compiler.BuiltinTypes.Type, GetLocation (e)); + else + return e; +} +*/ + +Expression MakeMonoSimdType(string typeName, Location loc) +{ + return new MemberAccess(new MemberAccess(new SimpleName("Mono", loc), "Simd", loc), typeName, loc); +} + +LocalVariable RegisterLocalVariable (Block block, string name, LocalVariable.Flags flags, Location loc) +{ + INamedBlockVariable existing = null; + var top = block.ParametersBlock.TopBlock; + top.GetLocalName (name, block, ref existing); + + var li = existing as LocalVariable; + if (li != null) { + report.WarningPlayScript (3596, loc, "Duplicate variable `{0}' definition", name); + return li; + } + + li = new LocalVariable (top, name, flags | LocalVariable.Flags.GlobalScope, loc); + top.AddLocalName (li); + return li; +} + +string GetExpecting () +{ + int [] tokens = yyExpectingTokens (yyExpectingState); + var names = new List (tokens.Length); + bool has_type = false; + bool has_identifier = false; + for (int i = 0; i < tokens.Length; i++){ + int token = tokens [i]; + has_identifier |= token == Token.IDENTIFIER; + + string name = GetTokenName (token); + if (name == "") + continue; + + has_type |= name == "type"; + if (names.Contains (name)) + continue; + + names.Add (name); + } + + // + // Too many tokens to enumerate + // + if (names.Count > 8) + return null; + + if (has_type && has_identifier) + names.Remove ("identifier"); + + if (names.Count == 1) + return "`" + GetTokenName (tokens [0]) + "'"; + + StringBuilder sb = new StringBuilder (); + names.Sort (); + int count = names.Count; + for (int i = 0; i < count; i++){ + bool last = i + 1 == count; + if (last) + sb.Append ("or "); + sb.Append ('`'); + sb.Append (names [i]); + sb.Append (last ? "'" : count < 3 ? "' " : "', "); + } + return sb.ToString (); +} + + +string GetSymbolName (int token) +{ + switch (token){ + case Token.LITERAL: + return "Literal " + ((Constant)lexer.Value).GetValue ().ToString (); + case Token.IDENTIFIER: + case Token.IDENTIFIER_CONFIG: + return "Identifier " + ((LocatedToken)lexer.Value).Value ?? ""; + case Token.BOOL: + return "bool"; + case Token.BOOLEAN: + return "boolean"; + case Token.BYTE: + return "byte"; + case Token.CHAR: + return "char"; + case Token.VOID: + return "void"; + case Token.DECIMAL: + return "decimal"; + case Token.DOUBLE: + return "double"; + case Token.DOUBLE2: + return "double2"; + case Token.DOUBLE3: + return "double3"; + case Token.DOUBLE4: + return "double4"; + case Token.DYNAMIC: + return "dynamic"; + case Token.FLOAT: + return "float"; + case Token.FLOAT2: + return "float2"; + case Token.FLOAT3: + return "float3"; + case Token.FLOAT4: + return "float4"; + case Token.INT: + return "int"; + case Token.LONG: + return "long"; + case Token.SBYTE: + return "sbyte"; + case Token.SHORT: + return "short"; + case Token.STRING: + return "string"; + case Token.UINT: + return "uint"; + case Token.ULONG: + return "ulong"; + case Token.USHORT: + return "ushort"; + case Token.OBJECT: + return "object"; + + case Token.PLUS: + return "+"; + case Token.UMINUS: + case Token.MINUS: + return "-"; + case Token.BANG: + return "!"; + case Token.BITWISE_AND: + return "&"; + case Token.BITWISE_OR: + return "|"; + case Token.LOGICAL_AND_ASSIGN: + return "&&="; + case Token.LOGICAL_OR_ASSIGN: + return "||="; + case Token.STAR: + return "*"; + case Token.PERCENT: + return "%"; + case Token.DIV: + return "/"; + case Token.CARRET: + return "^"; + case Token.OP_INC: + return "++"; + case Token.OP_DEC: + return "--"; + case Token.OP_SHIFT_LEFT: + return "<<"; + case Token.OP_SHIFT_RIGHT: + return ">>"; + case Token.OP_USHIFT_RIGHT: + return ">>>"; + case Token.OP_LT: + return "<"; + case Token.OP_GT: + return ">"; + case Token.OP_LE: + return "<="; + case Token.OP_GE: + return ">="; + case Token.OP_EQ: + return "=="; + case Token.OP_REF_EQ: + return "==="; + case Token.OP_NE: + return "!="; + case Token.OP_AND: + return "&&"; + case Token.OP_OR: + return "||"; + case Token.OP_PTR: + return "->"; + case Token.OP_IN: + return "in"; + case Token.OP_COALESCING: + return "??"; + case Token.OP_MULT_ASSIGN: + return "*="; + case Token.OP_DIV_ASSIGN: + return "/="; + case Token.OP_MOD_ASSIGN: + return "%="; + case Token.OP_ADD_ASSIGN: + return "+="; + case Token.OP_SUB_ASSIGN: + return "-="; + case Token.OP_SHIFT_LEFT_ASSIGN: + return "<<="; + case Token.OP_SHIFT_RIGHT_ASSIGN: + return ">>="; + case Token.OP_USHIFT_RIGHT_ASSIGN: + return ">>>="; + case Token.OP_AND_ASSIGN: + return "&="; + case Token.OP_XOR_ASSIGN: + return "^="; + case Token.OP_OR_ASSIGN: + return "|="; + } + + return GetTokenName (token); +} + +static string GetTokenName (int token) +{ + switch (token){ + case Token.ABSTRACT: + return "abstract"; + case Token.AS: + return "as"; + case Token.ASYNC: + return "async"; + case Token.SUPER: + return "super"; + case Token.BREAK: + return "break"; + case Token.CASE: + return "case"; + case Token.CATCH: + return "catch"; + case Token.CLASS: + return "class"; + case Token.CONST: + return "const"; + case Token.CONTINUE: + return "continue"; + case Token.DEFAULT: + return "default"; + case Token.DELETE: + return "delete"; + case Token.DO: + return "do"; + case Token.EACH: + return "each"; + case Token.ELSE: + return "else"; + case Token.EXPLICIT: + return "explicit"; + case Token.EXTENDS: + return "extends"; + case Token.EXTERN: + return "extern"; + case Token.FALSE: + return "false"; + case Token.FINAL: + return "final"; + case Token.FINALLY: + return "finally"; + case Token.FIXED: + return "fixed"; + case Token.FOR: + return "for"; + case Token.FOR_EACH: + return "for each"; + case Token.FUNCTION: + case Token.FUNCTION_BLOCK: + return "function"; + case Token.FUNCTION_GET: + return "function get"; + case Token.FUNCTION_SET: + return "function set"; + case Token.GOTO: + return "goto"; + case Token.IF: + return "if"; + case Token.IMPLEMENTS: + return "implements"; + case Token.IMPLICIT: + return "implicit"; + case Token.IMPORT: + return "import"; + case Token.IN: + return "in"; + case Token.INDEXER: + return "indexer"; + case Token.INSTANCEOF: + return "instanceof"; + case Token.INTERFACE: + return "interface"; + case Token.INTERNAL: + return "internal"; + case Token.IS: + return "is"; + case Token.NAMESPACE: + return "namespace"; + case Token.NATIVE: + return "native"; + case Token.NEW: + return "new"; + case Token.NULL: + return "null"; + case Token.OPERATOR: + return "operator"; + case Token.OUT: + return "out"; + case Token.OVERRIDE: + return "override"; + case Token.OVERLOAD: + return "overload"; + case Token.PACKAGE: + return "package"; + case Token.PRIVATE: + return "private"; + case Token.PROPERTY: + return "property"; + case Token.PROTECTED: + return "protected"; + case Token.PUBLIC: + return "public"; + case Token.READONLY: + return "readonly"; + case Token.REF: + return "ref"; + case Token.RETURN: + return "return"; + case Token.STATIC: + return "static"; + case Token.STRUCT: + return "struct"; + case Token.SWITCH: + return "switch"; + case Token.THIS: + return "this"; + case Token.THROW: + return "throw"; + case Token.TRUE: + return "true"; + case Token.TRY: + return "try"; + case Token.TYPEOF: + return "typeof"; + case Token.UNSAFE: + return "unsafe"; + case Token.USE: + return "use"; + case Token.USING: + return "using"; + case Token.VAR: + return "var"; + case Token.VIRTUAL: + return "virtual"; + case Token.VOLATILE: + return "volatile"; + case Token.WHERE: + return "where"; + case Token.WHILE: + return "while"; + case Token.PARTIAL: + return "partial"; + case Token.ARROW: + return "=>"; + case Token.FROM: + case Token.FROM_FIRST: + return "from"; + case Token.JOIN: + return "join"; + case Token.ON: + return "on"; + case Token.EQUALS: + return "equals"; + case Token.SELECT: + return "select"; + case Token.GROUP: + return "group"; + case Token.BY: + return "by"; + case Token.LET: + return "let"; + case Token.ORDERBY: + return "orderby"; + case Token.ASCENDING: + return "ascending"; + case Token.DESCENDING: + return "descending"; + case Token.INTO: + return "into"; + case Token.GET: + return "get"; + case Token.SET: + return "set"; + case Token.OPEN_BRACE: + case Token.OPEN_BRACE_INIT: + return "{"; + case Token.CLOSE_BRACE: + return "}"; + case Token.OPEN_BRACKET: + case Token.OPEN_BRACKET_EXPR: + return "["; + case Token.CLOSE_BRACKET: + return "]"; + case Token.OPEN_PARENS_EXPR_LIST: + case Token.OPEN_PARENS: + return "("; + case Token.CLOSE_PARENS: + return ")"; + case Token.DOT: + return "."; + case Token.DOT_AT: + return ".@"; + case Token.DOT_STAR: + return ".*"; + case Token.DOTDOT: + return ".."; + case Token.DOTDOT_AT: + return "..@"; + case Token.DOTDOT_STAR: + return "..*"; + case Token.DOTDOTDOT: + return "..."; + case Token.COMMA: + return ","; + case Token.DEFAULT_COLON: + return "default:"; + case Token.COLON: + return ":"; + case Token.SEMICOLON: + return ";"; + case Token.TILDE: + return "~"; + + case Token.PLUS: + case Token.UMINUS: + case Token.MINUS: + case Token.BANG: + case Token.OP_LT: + case Token.OP_GT: + case Token.BITWISE_AND: + case Token.BITWISE_OR: + case Token.STAR: + case Token.PERCENT: + case Token.DIV: + case Token.CARRET: + case Token.OP_INC: + case Token.OP_DEC: + case Token.OP_SHIFT_LEFT: + case Token.OP_SHIFT_RIGHT: + case Token.OP_LE: + case Token.OP_GE: + case Token.OP_EQ: + case Token.OP_NE: + case Token.OP_AND: + case Token.OP_OR: + case Token.OP_PTR: + case Token.OP_COALESCING: + case Token.OP_MULT_ASSIGN: + case Token.OP_DIV_ASSIGN: + case Token.OP_MOD_ASSIGN: + case Token.OP_ADD_ASSIGN: + case Token.OP_SUB_ASSIGN: + case Token.OP_SHIFT_LEFT_ASSIGN: + case Token.OP_SHIFT_RIGHT_ASSIGN: + case Token.OP_AND_ASSIGN: + case Token.OP_XOR_ASSIGN: + case Token.OP_OR_ASSIGN: + case Token.OP_AT: + return ""; + + case Token.BOOL: + case Token.BYTE: + case Token.CHAR: + case Token.VOID: + case Token.DECIMAL: + case Token.DOUBLE: + case Token.FLOAT: + case Token.INT: + case Token.LONG: + case Token.SBYTE: + case Token.SHORT: + case Token.STRING: + case Token.UINT: + case Token.ULONG: + case Token.USHORT: + case Token.OBJECT: + return "type"; + + case Token.ASSIGN: + return "="; + case Token.OP_GENERICS_LT: + case Token.GENERIC_DIMENSION: + return ".<"; + case Token.OP_GENERICS_GT: + return ">"; + case Token.INTERR: + case Token.INTERR_NULLABLE: + return "?"; + case Token.DOUBLE_COLON: + return "::"; + case Token.LITERAL: + return "value"; + case Token.IDENTIFIER: + case Token.AWAIT: + return "identifier"; + + case Token.EOF: + return "end-of-file"; + + // All of these are internal. + case Token.NONE: + case Token.ERROR: + case Token.FIRST_KEYWORD: + case Token.EVAL_COMPILATION_UNIT_PARSER: + case Token.EVAL_USING_DECLARATIONS_UNIT_PARSER: + case Token.EVAL_STATEMENT_PARSER: + case Token.LAST_KEYWORD: + case Token.GENERATE_COMPLETION: + case Token.COMPLETE_COMPLETION: + return ""; + + // A bit more robust. + default: + return yyNames [token]; + } +} + +/* end end end */ +} diff --git a/mcs/mcs/ps-tokenizer.cs b/mcs/mcs/ps-tokenizer.cs new file mode 100644 index 00000000000..e33e4ea92a5 --- /dev/null +++ b/mcs/mcs/ps-tokenizer.cs @@ -0,0 +1,4246 @@ +// +// ps-tokenizer.cs: The Tokenizer for the PlayScript compiler +// This also implements the preprocessor +// +// Authors: Miguel de Icaza (miguel@gnu.org) +// Marek Safar (marek.safar@gmail.com) +// Ben Cooley (bcooley@zynga.com) +// +// Dual licensed under the terms of the MIT X11 or GNU GPL +// +// Copyright 2001, 2002 Ximian, Inc (http://www.ximian.com) +// Copyright 2004-2008 Novell, Inc +// Copyright 2011 Xamarin, Inc (http://www.xamarin.com) +// + +using System; +using System.Text; +using System.Collections.Generic; +using System.Globalization; +using System.Diagnostics; +using System.Collections; +using Mono.CSharp; + +namespace Mono.PlayScript +{ + /// + /// Tokenizer for C# source code. + /// + + public class Tokenizer : yyParser.yyInput + { + class KeywordEntry + { + public readonly T Token; + public KeywordEntry Next; + public readonly char[] Value; + + public KeywordEntry (string value, T token) + { + this.Value = value.ToCharArray (); + this.Token = token; + } + } + + sealed class IdentifiersComparer : IEqualityComparer + { + readonly int length; + + public IdentifiersComparer (int length) + { + this.length = length; + } + + public bool Equals (char[] x, char[] y) + { + for (int i = 0; i < length; ++i) + if (x [i] != y [i]) + return false; + + return true; + } + + public int GetHashCode (char[] obj) + { + int h = 0; + for (int i = 0; i < length; ++i) + h = (h << 5) - h + obj [i]; + + return h; + } + } +/* + // + // This class has to be used by parser only, it reuses token + // details after each file parse completion + // + public class LocatedToken : CSharp.Tokenizer.LocatedToken + { + public LocatedToken () + { + } + + public LocatedToken (string value, Location loc) + : base (value, loc) + { + } + } +*/ + public class LocatedTokenBuffer : CSharp.Tokenizer.LocatedTokenBuffer + { + public LocatedTokenBuffer () + { + } + + public LocatedTokenBuffer (LocatedToken[] buffer) + : base (buffer) + { + } + } + + public enum PreprocessorDirective + { + Invalid = 0, + + Region = 1, + Endregion = 2, + If = 3 | RequiresArgument, + Endif = 4, + Elif = 5 | RequiresArgument, + Else = 6, + Define = 7 | RequiresArgument, + Undef = 8 | RequiresArgument, + Error = 9, + Warning = 10, + Pragma = 11 | CustomArgumentsParsing, + Line = 12 | CustomArgumentsParsing, + + CustomArgumentsParsing = 1 << 10, + RequiresArgument = 1 << 11 + } + + readonly SeekableStreamReader reader; + readonly CompilationSourceFile source_file; + readonly CompilerContext context; + + SourceFile current_source; + Location hidden_block_start; + int ref_line = 1; + int line = 1; + int col = 0; + int previous_col; + int prev_token; + int prev_token_line; + int current_token; + int current_token_line; + int putback_token = -1; + int parse_regex_xml = 0; + int parse_colon = 0; + bool allow_auto_semi = true; + int allow_auto_semi_after = 0; + bool has_temp_auto_semi_after_tokens = false; + List temp_auto_semi_after_tokens = new List(); + readonly int tab_size; + bool parsing_playscript = true; + bool handle_get_set = false; + bool handle_dynamic = true; + bool handle_each = false; + bool handle_remove_add = false; + bool handle_where = false; + bool handle_typeof = false; + bool handle_for_in = false; +// bool lambda_arguments_parsing; + List escaped_identifiers; + int parsing_generic_less_than; + readonly bool doc_processing; + readonly LocatedTokenBuffer ltb; + + private static BitArray allowed_auto_semi_tokens = new BitArray(750, false); + private static BitArray disallowed_next_auto_semi_tokens = new BitArray(750, false); + + // + // Used mainly for parser optimizations. Some expressions for instance + // can appear only in block (including initializer, base initializer) + // scope only + // + public int parsing_block; + internal bool query_parsing; + + // + // When parsing type only, useful for ambiguous nullable types + // + public int parsing_type; + + // + // Set when parsing generic declaration (type or method header) + // + public bool parsing_generic_declaration; + public bool parsing_generic_declaration_doc; + + // + // The value indicates that we have not reach any declaration or + // namespace yet + // + public int parsing_declaration; + + public bool parsing_attribute_section; + + public bool parsing_modifiers; + + // + // The special characters to inject on streams to run the unit parser + // in the special expression mode. Using private characters from + // Plane Sixteen (U+100000 to U+10FFFD) + // + // This character is only tested just before the tokenizer is about to report + // an error; So on the regular operation mode, this addition will have no + // impact on the tokenizer's performance. + // + + public const int EvalStatementParserCharacter = 0x100000; + public const int EvalCompilationUnitParserCharacter = 0x100001; + public const int EvalUsingDeclarationsParserCharacter = 0x100002; + public const int DocumentationXref = 0x100003; + + // + // XML documentation buffer. The save point is used to divide + // comments on types and comments on members. + // + StringBuilder xml_comment_buffer; + + // + // See comment on XmlCommentState enumeration. + // + XmlCommentState xml_doc_state = XmlCommentState.Allowed; + + // + // Whether tokens have been seen on this line + // + bool tokens_seen = false; + + // + // Set to true once the GENERATE_COMPLETION token has bee + // returned. This helps produce one GENERATE_COMPLETION, + // as many COMPLETE_COMPLETION as necessary to complete the + // AST tree and one final EOF. + // + bool generated; + + // + // Whether a token has been seen on the file + // This is needed because `define' is not allowed to be used + // after a token has been seen. + // + bool any_token_seen; + + // + // Class variables + // + static readonly KeywordEntry[][] keywords; + static readonly KeywordEntry[][] keywords_preprocessor; + static readonly HashSet keyword_strings; + static readonly NumberStyles styles; + static readonly NumberFormatInfo csharp_format_info; + + // Pragma arguments + static readonly char[] pragma_warning = "warning".ToCharArray (); + static readonly char[] pragma_warning_disable = "disable".ToCharArray (); + static readonly char[] pragma_warning_restore = "restore".ToCharArray (); + static readonly char[] pragma_checksum = "checksum".ToCharArray (); + static readonly char[] line_hidden = "hidden".ToCharArray (); + static readonly char[] line_default = "default".ToCharArray (); + + static readonly char[] simple_whitespaces = new char[] { ' ', '\t' }; + + public bool ParsingPlayScript { + get { return parsing_playscript; } + set { parsing_playscript = value; } + } + + public bool PropertyParsing { + get { return handle_get_set; } + set { handle_get_set = value; } + } + + public bool ConstraintsParsing { + get { return handle_where; } + set { handle_where = value; } + } + + public bool TypeOfParsing { + get { return handle_typeof; } + set { handle_typeof = value; } + } + + public bool ForInParsing { + get { return handle_for_in; } + set { handle_for_in = value; } + } + + public bool DynamicParsing { + get { return handle_dynamic; } + set { handle_dynamic = value; } + } + + public bool AutoSemiInsertion { + get { return allow_auto_semi; } + set { + allow_auto_semi = value; + allow_auto_semi_after = 0; + } + } + + public int AutoSemiInsertionAfter + { + get { return allow_auto_semi_after; } + set { + allow_auto_semi = true; + allow_auto_semi_after = value + 1; + } + } + + public void AllowAutoSemiAfterToken (int token, bool allow) + { + allowed_auto_semi_tokens.Set (token, allow); + if (true) { + has_temp_auto_semi_after_tokens = true; + temp_auto_semi_after_tokens.Add (token); + } + } + + public bool RegexXmlParsing { + get { return parse_regex_xml > 0; } + } + + public XmlCommentState doc_state { + get { return xml_doc_state; } + set { + if (value == XmlCommentState.Allowed) { + check_incorrect_doc_comment (); + reset_doc_comment (); + } + xml_doc_state = value; + } + } + + // + // This is used to trigger completion generation on the parser + public bool CompleteOnEOF; + + void AddEscapedIdentifier (Location loc) + { + if (escaped_identifiers == null) + escaped_identifiers = new List (); + + escaped_identifiers.Add (loc); + } + + public bool IsEscapedIdentifier (ATypeNameExpression name) + { + return escaped_identifiers != null && escaped_identifiers.Contains (name.Location); + } + + // + // Values for the associated token returned + // + internal int putback_char; // Used by repl only + object val; + + // + // Pre-processor + // + const int TAKING = 1; + const int ELSE_SEEN = 4; + const int PARENT_TAKING = 8; + const int REGION = 16; + + // + // pre-processor if stack state: + // + Stack ifstack; + + public const int MaxIdentifierLength = 512; + public const int MaxNumberLength = 512; + + readonly char[] id_builder; + readonly Dictionary[] identifiers; + readonly char[] number_builder; + int number_pos; + + char[] value_builder = new char[64]; + + public int Line { + get { + return ref_line; + } + } + + // + // This is used when the tokenizer needs to save + // the current position as it needs to do some parsing + // on its own to deamiguate a token in behalf of the + // parser. + // + Stack position_stack = new Stack (2); + + class Position { + public int position; + public int line; + public int ref_line; + public int col; + public Location hidden; + public int putback_char; + public int previous_col; + public Stack ifstack; + public int parsing_generic_less_than; + public int parse_regex_xml; + public int parse_colon; + public bool allow_auto_semi; + public int allow_auto_semi_after; + public object val; + public int prev_token; + public int prev_token_line; + public int current_token; + public int current_token_line; + public int putback_token; + + public Position (Tokenizer t) + { + position = t.reader.Position; + line = t.line; + ref_line = t.ref_line; + col = t.col; + hidden = t.hidden_block_start; + putback_char = t.putback_char; + previous_col = t.previous_col; + if (t.ifstack != null && t.ifstack.Count != 0) { + // There is no simple way to clone Stack all + // methods reverse the order + var clone = t.ifstack.ToArray (); + Array.Reverse (clone); + ifstack = new Stack (clone); + } + parsing_generic_less_than = t.parsing_generic_less_than; + parse_regex_xml = t.parse_regex_xml; + parse_colon = t.parse_colon; + allow_auto_semi = t.allow_auto_semi; + allow_auto_semi_after = t.allow_auto_semi_after; + prev_token = t.prev_token; + prev_token_line = t.prev_token_line; + current_token = t.current_token; + current_token_line = t.current_token_line; + putback_token = t.putback_token; + val = t.val; + } + } + + public Tokenizer (SeekableStreamReader input, CompilationSourceFile file, ParserSession session) + { + this.source_file = file; + this.parsing_playscript = true; // file.SourceFile.PsExtended; + this.context = file.Compiler; + this.current_source = file.SourceFile; + this.identifiers = session.Identifiers; + this.id_builder = session.IDBuilder; + this.number_builder = session.NumberBuilder; + this.ltb = new LocatedTokenBuffer (session.LocatedTokens); + + reader = input; + + putback_char = -1; + + xml_comment_buffer = new StringBuilder (); + doc_processing = context.Settings.DocumentationFile != null; + + tab_size = context.Settings.TabSize; + } + + public void PushPosition () + { + position_stack.Push (new Position (this)); + } + + public void PopPosition () + { + Position p = position_stack.Pop (); + + reader.Position = p.position; + ref_line = p.ref_line; + line = p.line; + col = p.col; + hidden_block_start = p.hidden; + putback_char = p.putback_char; + previous_col = p.previous_col; + ifstack = p.ifstack; + parsing_generic_less_than = p.parsing_generic_less_than; + parse_regex_xml = p.parse_regex_xml; + parse_colon = p.parse_colon; + prev_token = p.prev_token; + prev_token_line = p.prev_token_line; + allow_auto_semi = p.allow_auto_semi; + allow_auto_semi_after = p.allow_auto_semi_after; + current_token = p.current_token; + current_token_line = p.current_token_line; + putback_token = p.putback_token; + val = p.val; + } + + // Do not reset the position, ignore it. + public void DiscardPosition () + { + position_stack.Pop (); + } + + static void AddKeyword (string kw, int token) + { + keyword_strings.Add (kw); + + AddKeyword (keywords, kw, token); + } + + static void AddPreprocessorKeyword (string kw, PreprocessorDirective directive) + { + AddKeyword (keywords_preprocessor, kw, directive); + } + + static void AddKeyword (KeywordEntry[][] keywords, string kw, T token) + { + int length = kw.Length; + if (keywords[length] == null) { + keywords[length] = new KeywordEntry['z' - '_' + 1]; + } + + int char_index = kw[0] - '_'; + var kwe = keywords[length][char_index]; + if (kwe == null) { + keywords[length][char_index] = new KeywordEntry (kw, token); + return; + } + + while (kwe.Next != null) { + kwe = kwe.Next; + } + + kwe.Next = new KeywordEntry (kw, token); + } + + static void AddAllowedAutoSemiTokens(int[] tokens) { + var len = tokens.Length; + for (var i = 0; i < len; i++) { + allowed_auto_semi_tokens.Set (tokens[i], true); + } + } + + static void AddDisallowedNextAutoSemiTokens(int[] tokens) { + var len = tokens.Length; + for (var i = 0; i < len; i++) { + disallowed_next_auto_semi_tokens.Set (tokens[i], true); + } + } + + // + // Class initializer + // + static Tokenizer () + { + keyword_strings = new HashSet (); + + // 13 is the length of the longest keyword for now + keywords = new KeywordEntry[13][]; + + AddKeyword ("abstract", Token.ABSTRACT); + AddKeyword ("as", Token.AS); + AddKeyword ("bool", Token.BOOL); + AddKeyword ("boolean", Token.BOOLEAN); + AddKeyword ("break", Token.BREAK); + AddKeyword ("byte", Token.BYTE); + AddKeyword ("case", Token.CASE); + AddKeyword ("catch", Token.CATCH); + AddKeyword ("char", Token.CHAR); + AddKeyword ("class", Token.CLASS); + AddKeyword ("const", Token.CONST); + AddKeyword ("continue", Token.CONTINUE); + AddKeyword ("decimal", Token.DECIMAL); + AddKeyword ("default", Token.DEFAULT); + AddKeyword ("delete", Token.DELETE); + AddKeyword ("do", Token.DO); + AddKeyword ("double", Token.DOUBLE); + AddKeyword ("double2", Token.DOUBLE2); + AddKeyword ("double3", Token.DOUBLE3); + AddKeyword ("double4", Token.DOUBLE4); + AddKeyword ("dynamic", Token.DYNAMIC); + AddKeyword ("each", Token.EACH); + AddKeyword ("else", Token.ELSE); + AddKeyword ("explicit", Token.EXPLICIT); + AddKeyword ("extends", Token.EXTENDS); + AddKeyword ("extern", Token.EXTERN); + AddKeyword ("false", Token.FALSE); + AddKeyword ("final", Token.FINAL); + AddKeyword ("finally", Token.FINALLY); + AddKeyword ("fixed", Token.FIXED); + AddKeyword ("float", Token.FLOAT); + AddKeyword ("float2", Token.FLOAT2); + AddKeyword ("float3", Token.FLOAT3); + AddKeyword ("float4", Token.FLOAT4); + AddKeyword ("for", Token.FOR); + AddKeyword ("function", Token.FUNCTION); + AddKeyword ("goto", Token.GOTO); + AddKeyword ("get", Token.GET); + AddKeyword ("if", Token.IF); + AddKeyword ("implements", Token.IMPLEMENTS); + AddKeyword ("implicit", Token.IMPLICIT); + AddKeyword ("import", Token.IMPORT); + AddKeyword ("in", Token.IN); + AddKeyword ("indexer", Token.INDEXER); + AddKeyword ("instanceof", Token.INSTANCEOF); + AddKeyword ("int", Token.INT); + AddKeyword ("interface", Token.INTERFACE); + AddKeyword ("internal", Token.INTERNAL); + AddKeyword ("is", Token.IS); + AddKeyword ("long", Token.LONG); + AddKeyword ("namespace", Token.NAMESPACE); + AddKeyword ("native", Token.NATIVE); + AddKeyword ("new", Token.NEW); + AddKeyword ("null", Token.NULL); + AddKeyword ("object", Token.OBJECT); + AddKeyword ("operator", Token.OPERATOR); + AddKeyword ("out", Token.OUT); + AddKeyword ("override", Token.OVERRIDE); + AddKeyword ("overload", Token.OVERLOAD); + AddKeyword ("package", Token.PACKAGE); + AddKeyword ("property", Token.PROPERTY); + AddKeyword ("private", Token.PRIVATE); + AddKeyword ("protected", Token.PROTECTED); + AddKeyword ("public", Token.PUBLIC); + AddKeyword ("readonly", Token.READONLY); + AddKeyword ("ref", Token.REF); + AddKeyword ("return", Token.RETURN); + AddKeyword ("sbyte", Token.SBYTE); + AddKeyword ("set", Token.SET); + AddKeyword ("short", Token.SHORT); + AddKeyword ("static", Token.STATIC); + AddKeyword ("string", Token.STRING); + AddKeyword ("struct", Token.STRUCT); + AddKeyword ("super", Token.SUPER); + AddKeyword ("switch", Token.SWITCH); + AddKeyword ("this", Token.THIS); + AddKeyword ("throw", Token.THROW); + AddKeyword ("true", Token.TRUE); + AddKeyword ("try", Token.TRY); + AddKeyword ("typeof", Token.TYPEOF); + AddKeyword ("uint", Token.UINT); + AddKeyword ("ulong", Token.ULONG); + AddKeyword ("unsafe", Token.UNSAFE); + AddKeyword ("use", Token.USE); + AddKeyword ("ushort", Token.USHORT); + AddKeyword ("using", Token.USING); + AddKeyword ("var", Token.VAR); + AddKeyword ("virtual", Token.VIRTUAL); + AddKeyword ("void", Token.VOID); + AddKeyword ("volatile", Token.VOLATILE); + AddKeyword ("while", Token.WHILE); + AddKeyword ("with", Token.WITH); + AddKeyword ("partial", Token.PARTIAL); + AddKeyword ("where", Token.WHERE); + + // LINQ keywords + AddKeyword ("from", Token.FROM); + AddKeyword ("join", Token.JOIN); + AddKeyword ("on", Token.ON); + AddKeyword ("equals", Token.EQUALS); + AddKeyword ("select", Token.SELECT); + AddKeyword ("group", Token.GROUP); + AddKeyword ("by", Token.BY); + AddKeyword ("let", Token.LET); + AddKeyword ("orderby", Token.ORDERBY); + AddKeyword ("ascending", Token.ASCENDING); + AddKeyword ("descending", Token.DESCENDING); + AddKeyword ("into", Token.INTO); + + // Contextual async keywords + AddKeyword ("async", Token.ASYNC); + AddKeyword ("await", Token.AWAIT); + + keywords_preprocessor = new KeywordEntry[10][]; + + AddPreprocessorKeyword ("region", PreprocessorDirective.Region); + AddPreprocessorKeyword ("endregion", PreprocessorDirective.Endregion); + AddPreprocessorKeyword ("if", PreprocessorDirective.If); + AddPreprocessorKeyword ("endif", PreprocessorDirective.Endif); + AddPreprocessorKeyword ("elif", PreprocessorDirective.Elif); + AddPreprocessorKeyword ("else", PreprocessorDirective.Else); + AddPreprocessorKeyword ("define", PreprocessorDirective.Define); + AddPreprocessorKeyword ("undef", PreprocessorDirective.Undef); + AddPreprocessorKeyword ("error", PreprocessorDirective.Error); + AddPreprocessorKeyword ("warning", PreprocessorDirective.Warning); + AddPreprocessorKeyword ("pragma", PreprocessorDirective.Pragma); + AddPreprocessorKeyword ("line", PreprocessorDirective.Line); + + // Semicolons will be auto-inserted after these tokens by default (unless manually disabled by the parser). + AddAllowedAutoSemiTokens(new int [] { + Token.CLOSE_BRACKET, + Token.CLOSE_PARENS, + Token.IDENTIFIER, + Token.LITERAL, + Token.OP_INC, + Token.OP_DEC, + Token.TRUE, + Token.FALSE, + Token.NULL, + Token.CHAR, + Token.INT, + Token.UINT, + Token.OBJECT, + Token.DECIMAL, + Token.BYTE, + Token.SBYTE, + Token.LONG, + Token.ULONG, + Token.VOID, + Token.DOUBLE, + Token.DOUBLE2, + Token.DOUBLE3, + Token.DOUBLE4, + Token.FLOAT, + Token.FLOAT2, + Token.FLOAT3, + Token.FLOAT4, + Token.STRING, + Token.BOOL, + Token.BOOLEAN, + Token.SHORT, + Token.USHORT, + Token.BREAK, + Token.CONTINUE, + Token.RETURN, + Token.STAR + }); + + AddDisallowedNextAutoSemiTokens(new int [] { + Token.MINUS, + Token.DIV, + Token.PERCENT, + Token.STAR, + Token.DOT, + Token.DOT_AT, + Token.DOT_STAR, + Token.DOTDOT, + Token.DOTDOT_AT, + Token.DOTDOT_STAR, + Token.OP_SHIFT_LEFT, + Token.OP_SHIFT_RIGHT, + Token.OP_USHIFT_RIGHT, + Token.LOGICAL_AND_ASSIGN, + Token.LOGICAL_OR_ASSIGN, + Token.CLOSE_BRACKET, + Token.CLOSE_PARENS, + Token.OP_ADD_ASSIGN, + Token.OP_AT, + Token.OP_IN, + Token.AS, + Token.IN, + Token.ARROW, + Token.ASSIGN, + Token.COLON, + Token.COMMA, + Token.OP_ADD_ASSIGN, + Token.OP_SUB_ASSIGN, + Token.OP_MOD_ASSIGN, + Token.OP_MULT_ASSIGN, + Token.OP_DIV_ASSIGN, + Token.OP_COALESCING, + Token.OP_AND_ASSIGN, + Token.OP_OR_ASSIGN, + Token.OP_XOR_ASSIGN, + Token.OP_SHIFT_LEFT_ASSIGN, + Token.OP_SHIFT_RIGHT_ASSIGN, + Token.OP_USHIFT_RIGHT_ASSIGN, + Token.OP_EQ, + Token.OP_NE, + Token.OP_REF_EQ, + Token.OP_REF_NE, + Token.OP_LT, + Token.OP_GT, + Token.OP_GE, + Token.OP_LE, + Token.OP_AND, + Token.OP_OR, + Token.BITWISE_AND, + Token.BITWISE_OR, + Token.CARRET, + Token.INTERR, + + }); + + csharp_format_info = NumberFormatInfo.InvariantInfo; + styles = NumberStyles.Float; + } + + int GetKeyword (char[] id, int id_len) + { + // + // Keywords are stored in an array of arrays grouped by their + // length and then by the first character + // + if (id_len >= keywords.Length || keywords [id_len] == null) + return -1; + + int first_index = id [0] - '_'; + if (first_index > 'z' - '_') + return -1; + + var kwe = keywords [id_len] [first_index]; + if (kwe == null) + return -1; + + int res; + do { + res = kwe.Token; + for (int i = 1; i < id_len; ++i) { + if (id [i] != kwe.Value [i]) { + res = 0; + kwe = kwe.Next; + break; + } + } + } while (res == 0 && kwe != null); + + if (res == 0) + return -1; + + int next_token; + switch (res) { + case Token.FOR: + this.handle_each = true; + next_token = peek_token (); + if (next_token == Token.EACH) { + token (); + res = Token.FOR_EACH; + } + this.handle_each = false; + break; + case Token.FUNCTION: + parsing_modifiers = false; + allow_auto_semi = false; + allow_auto_semi_after = 0; + PushPosition(); + var fn_token = token (); + if (fn_token == Token.IDENTIFIER) + { + var get_set = (string)((LocatedToken)val).Value; + if (get_set == "get" || get_set == "set") { + fn_token = token (); + if (fn_token == Token.IDENTIFIER) { + res = (get_set == "get") ? Token.FUNCTION_GET : Token.FUNCTION_SET; + } + } + PopPosition (); + if (res != Token.FUNCTION) + token (); + } else { + if (fn_token == Token.OPEN_PARENS) + res = Token.FUNCTION_BLOCK; + + PopPosition (); + } + + break; + case Token.GET: + case Token.SET: + if (!handle_get_set) + res = -1; + break; + case Token.IF: + case Token.WHILE: + case Token.DO: + case Token.TRY: + case Token.CATCH: + case Token.SWITCH: + case Token.CASE: + allow_auto_semi = false; + allow_auto_semi_after = 0; + break; + case Token.DYNAMIC: + if (!handle_dynamic) + res = -1; + break; + case Token.EACH: + if (!handle_each) + res = -1; + break; + case Token.EXTERN: + if (parsing_declaration != 0 || !parsing_playscript) + res = -1; + break; + case Token.DEFAULT: + if (peek_token () == Token.COLON) { + token (); + res = Token.DEFAULT_COLON; + } + break; + case Token.WHERE: + if (!handle_where && !query_parsing || !parsing_playscript) + res = -1; + break; + case Token.FROM: + // + // A query expression is any expression that starts with `from identifier' + // followed by any token except ; , = + // + if (!parsing_playscript) { + res = -1; + } else if (!query_parsing) { +// if (lambda_arguments_parsing) { +// res = -1; +// break; +// } + + PushPosition (); + // HACK: to disable generics micro-parser, because PushPosition does not + // store identifiers array + parsing_generic_less_than = 1; + switch (xtoken ()) { + case Token.IDENTIFIER: + case Token.INT: + case Token.BOOL: + case Token.BYTE: + case Token.CHAR: + case Token.DECIMAL: + case Token.FLOAT: + case Token.LONG: + case Token.OBJECT: + case Token.STRING: + case Token.UINT: + case Token.ULONG: + next_token = xtoken (); + if (next_token == Token.SEMICOLON || next_token == Token.COMMA || next_token == Token.EQUALS) + goto default; + + res = Token.FROM_FIRST; + query_parsing = true; + if (context.Settings.Version <= LanguageVersion.ISO_2) + Report.FeatureIsNotAvailable (context, Location, "query expressions"); + break; + case Token.VOID: + Expression.Error_VoidInvalidInTheContext (Location, Report); + break; + default: + PopPosition (); + // HACK: A token is not a keyword so we need to restore identifiers buffer + // which has been overwritten before we grabbed the identifier + id_builder [0] = 'f'; id_builder [1] = 'r'; id_builder [2] = 'o'; id_builder [3] = 'm'; + return -1; + } + PopPosition (); + } + break; + case Token.JOIN: + case Token.ON: + case Token.EQUALS: + case Token.SELECT: + case Token.GROUP: + case Token.BY: + case Token.LET: + case Token.ORDERBY: + case Token.ASCENDING: + case Token.DESCENDING: + case Token.INTO: + if (!query_parsing || !parsing_playscript) + res = -1; + break; + + case Token.IN: + if (!handle_for_in) + res = Token.OP_IN; + break; + + case Token.USING: + // TODO: some explanation needed + check_incorrect_doc_comment (); + break; + + case Token.PARTIAL: + if (parsing_block > 0 || !parsing_playscript) { + res = -1; + break; + } + + // Save current position and parse next token. + PushPosition (); + + next_token = token (); + bool ok = (next_token == Token.CLASS) || + (next_token == Token.STRUCT) || + (next_token == Token.INTERFACE) || + (next_token == Token.VOID); + + PopPosition (); + + if (ok) { + if (next_token == Token.VOID) { + if (context.Settings.Version <= LanguageVersion.ISO_2) + Report.FeatureIsNotAvailable (context, Location, "partial methods"); + } else if (context.Settings.Version == LanguageVersion.ISO_1) + Report.FeatureIsNotAvailable (context, Location, "partial types"); + + return res; + } + + if (next_token < Token.LAST_KEYWORD) { + Report.Error (267, Location, + "The `partial' modifier can be used only immediately before `class', `struct', `interface', or `void' keyword"); + return token (); + } + + res = -1; + break; + + case Token.ASYNC: + if (!parsing_playscript) { + return -1; + } else if (parsing_modifiers) { + // + // Skip attributes section or constructor called async + // + if (parsing_attribute_section || peek_token () == Token.OPEN_PARENS) { + res = -1; + } else { + // async is keyword + } + } else if (parsing_block > 0) { + switch (peek_token ()) { +// case Token.OPEN_PARENS_LAMBDA: +// // async is keyword +// break; + case Token.IDENTIFIER: + PushPosition (); + xtoken (); + if (xtoken () != Token.ARROW) + res = -1; + + PopPosition (); + break; + default: + res = -1; + break; + } + } else { + res = -1; + } + + if (res == Token.ASYNC && context.Settings.Version <= LanguageVersion.V_4) { + Report.FeatureIsNotAvailable (context, Location, "asynchronous functions"); + } + + break; + + case Token.AWAIT: + if (parsing_block == 0 || !parsing_playscript) + res = -1; + + break; + + // PLAYSCRIPT Extension Type keywords + case Token.BOOL: + case Token.CHAR: + case Token.BYTE: + case Token.SBYTE: + case Token.DECIMAL: + case Token.OBJECT: + case Token.STRING: + case Token.LONG: + case Token.ULONG: + case Token.SHORT: + case Token.USHORT: + case Token.FLOAT: + case Token.FLOAT2: + case Token.FLOAT3: + case Token.FLOAT4: + case Token.DOUBLE: + case Token.DOUBLE2: + case Token.DOUBLE3: + case Token.DOUBLE4: + if (!parsing_playscript) + res = -1; + + break; + + // PLAYSCRIPT Extension keywords + case Token.EXPLICIT: + case Token.IMPLICIT: + case Token.OVERLOAD: + case Token.OUT: + case Token.READONLY: + case Token.REF: + case Token.UNSAFE: + case Token.FIXED: + case Token.GOTO: + if (!parsing_playscript) + res = -1; + + break; + + case Token.INDEXER: + case Token.OPERATOR: + case Token.PROPERTY: + if (!parsing_playscript) + res = -1; + else + parsing_modifiers = false; + + break; + + case Token.STRUCT: + if (!parsing_playscript) + res = -1; + else + parsing_modifiers = false; + + break; + + case Token.CLASS: + case Token.INTERFACE: + parsing_modifiers = false; + break; + + } + + + return res; + } + + static PreprocessorDirective GetPreprocessorDirective (char[] id, int id_len) + { + // + // Keywords are stored in an array of arrays grouped by their + // length and then by the first character + // + if (id_len >= keywords_preprocessor.Length || keywords_preprocessor[id_len] == null) + return PreprocessorDirective.Invalid; + + int first_index = id[0] - '_'; + if (first_index > 'z' - '_') + return PreprocessorDirective.Invalid; + + var kwe = keywords_preprocessor[id_len][first_index]; + if (kwe == null) + return PreprocessorDirective.Invalid; + + PreprocessorDirective res = PreprocessorDirective.Invalid; + do { + res = kwe.Token; + for (int i = 1; i < id_len; ++i) { + if (id[i] != kwe.Value[i]) { + res = 0; + kwe = kwe.Next; + break; + } + } + } while (res == PreprocessorDirective.Invalid && kwe != null); + + return res; + } + + public Location Location { + get { + return new Location (current_source, ref_line, col); + } + } + + static bool is_identifier_start_character (int c) + { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || Char.IsLetter ((char)c); + } + + static bool is_identifier_part_character (char c) + { + if (c >= 'a' && c <= 'z') + return true; + + if (c >= 'A' && c <= 'Z') + return true; + + if (c == '_' || c == '$' || (c >= '0' && c <= '9')) + return true; + + if (c < 0x80) + return false; + + return Char.IsLetter (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation; + } + + public static bool IsKeyword (string s) + { + return keyword_strings.Contains (s); + } + + // + // Open parens micro parser. Detects both simple open parens and open parens for expression series + // + int TokenizeOpenParens () + { + int ptoken; + current_token = -1; + current_token_line = 0; + + int parens_level = 0; + + while (true) { + ptoken = current_token; + token (); + + switch (current_token) { + case Token.OPEN_PARENS: + ++parens_level; + continue; + + case Token.CLOSE_PARENS: + if (parens_level > 0) { + --parens_level; + continue; + } + + return Token.OPEN_PARENS; + + case Token.COLON: + if (parens_level == 0) + return Token.OPEN_PARENS; + + continue; + case Token.COMMA: + if (parens_level == 0) + return Token.OPEN_PARENS_EXPR_LIST; + + continue; + } + } + } + + public static bool IsValidIdentifier (string s) + { + if (s == null || s.Length == 0) + return false; + + if (!is_identifier_start_character (s [0])) + return false; + + for (int i = 1; i < s.Length; i ++) + if (! is_identifier_part_character (s [i])) + return false; + + return true; + } + + bool parse_less_than () + { + start: + int the_token = token (); + if (the_token == Token.OPEN_BRACKET) { + do { + the_token = token (); + } while (the_token != Token.CLOSE_BRACKET); + the_token = token (); + } else if (the_token == Token.IN || the_token == Token.OUT) { + the_token = token (); + } + switch (the_token) { + case Token.IDENTIFIER: + case Token.OBJECT: + case Token.STRING: + case Token.BOOL: + case Token.DECIMAL: + case Token.FLOAT: + case Token.DOUBLE: + case Token.SBYTE: + case Token.BYTE: + case Token.SHORT: + case Token.USHORT: + case Token.INT: + case Token.UINT: + case Token.LONG: + case Token.ULONG: + case Token.CHAR: + case Token.VOID: + break; + case Token.OP_GENERICS_GT: + case Token.IN: + case Token.OUT: + return true; + + default: + return false; + } + again: + the_token = token (); + + if (the_token == Token.OP_GENERICS_GT) + return true; + else if (the_token == Token.COMMA || the_token == Token.DOT || the_token == Token.DOUBLE_COLON) + goto start; + else if (the_token == Token.INTERR_NULLABLE || the_token == Token.STAR) + goto again; + else if (the_token == Token.OP_GENERICS_LT) { + if (!parse_less_than ()) + return false; + goto again; + } else if (the_token == Token.OPEN_BRACKET) { + rank_specifiers: + the_token = token (); + if (the_token == Token.CLOSE_BRACKET) + goto again; + else if (the_token == Token.COMMA) + goto rank_specifiers; + return false; + } + + return false; + } + + bool parse_generic_dimension (out int dimension) + { + dimension = 1; + + again: + int the_token = token (); + if (the_token == Token.OP_GENERICS_GT) + return true; + else if (the_token == Token.COMMA) { + dimension++; + goto again; + } + + return false; + } + + public int peek_token () + { + int the_token; + + PushPosition (); + the_token = token (); + PopPosition (); + + return the_token; + } + + // + // Tonizes `?' using custom disambiguous rules to return one + // of following tokens: INTERR_NULLABLE, OP_COALESCING, INTERR + // + // Tricky expression look like: + // + // Foo ? a = x ? b : c; + // + int TokenizePossibleNullableType () + { + if (parsing_block == 0 || parsing_type > 0) + return Token.INTERR_NULLABLE; + + int d = peek_char (); + if (d == '?') { + get_char (); + return Token.OP_COALESCING; + } + + switch (current_token) { + case Token.CLOSE_PARENS: + case Token.TRUE: + case Token.FALSE: + case Token.NULL: + case Token.LITERAL: + return Token.INTERR; + } + + if (d != ' ') { + if (d == ',' || d == ';' || d == '>') + return Token.INTERR_NULLABLE; + if (d == '*' || (d >= '0' && d <= '9')) + return Token.INTERR; + } + + PushPosition (); +// current_token = Token.NONE; // Doesn't work with auto semi-insertion - needs prev token history always + int next_token; + switch (xtoken ()) { + case Token.LITERAL: + case Token.TRUE: + case Token.FALSE: + case Token.NULL: + case Token.THIS: + case Token.NEW: + next_token = Token.INTERR; + break; + + case Token.SEMICOLON: + case Token.COMMA: + case Token.CLOSE_PARENS: + case Token.OPEN_BRACKET: + case Token.OP_GENERICS_GT: + case Token.INTERR: + next_token = Token.INTERR_NULLABLE; + break; + + default: + next_token = -1; + break; + } + + if (next_token == -1) { + switch (xtoken ()) { + case Token.COMMA: + case Token.SEMICOLON: + case Token.OPEN_BRACE: + case Token.CLOSE_PARENS: + case Token.IN: + next_token = Token.INTERR_NULLABLE; + break; + + case Token.COLON: + next_token = Token.INTERR; + break; + + default: + int ntoken; + int interrs = 1; + int colons = 0; + int braces = 0; + // + // All shorcuts failed, do it hard way + // + while ((ntoken = xtoken ()) != Token.EOF) { + if (ntoken == Token.OPEN_BRACE) { + ++braces; + continue; + } + + if (ntoken == Token.CLOSE_BRACE) { + --braces; + continue; + } + + if (braces != 0) + continue; + + if (ntoken == Token.SEMICOLON) + break; + + if (ntoken == Token.COLON) { + if (++colons == interrs) + break; + continue; + } + + if (ntoken == Token.INTERR) { + ++interrs; + continue; + } + } + + next_token = colons != interrs && braces == 0 ? Token.INTERR_NULLABLE : Token.INTERR; + break; + } + } + + PopPosition (); + return next_token; + } + + bool decimal_digits (int c) + { + int d; + bool seen_digits = false; + + if (c != -1){ + if (number_pos == MaxNumberLength) + Error_NumericConstantTooLong (); + number_builder [number_pos++] = (char) c; + } + + // + // We use peek_char2, because decimal_digits needs to do a + // 2-character look-ahead (5.ToString for example). + // + while ((d = peek_char2 ()) != -1){ + if (d >= '0' && d <= '9'){ + if (number_pos == MaxNumberLength) + Error_NumericConstantTooLong (); + number_builder [number_pos++] = (char) d; + get_char (); + seen_digits = true; + } else + break; + } + + return seen_digits; + } + + static bool is_hex (int e) + { + return (e >= '0' && e <= '9') || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f'); + } + + static TypeCode real_type_suffix (int c) + { + switch (c){ + case 'F': case 'f': + return TypeCode.Single; + case 'D': case 'd': + return TypeCode.Double; + case 'M': case 'm': + return TypeCode.Decimal; + default: + return TypeCode.Empty; + } + } + + ILiteralConstant integer_type_suffix (ulong ul, int c, Location loc) + { + bool is_unsigned = false; + bool is_long = false; + + if (c != -1){ + bool scanning = true; + do { + switch (c){ + case 'U': case 'u': + if (is_unsigned) + scanning = false; + is_unsigned = true; + get_char (); + break; + + case 'l': + if (!is_unsigned){ + // + // if we have not seen anything in between + // report this error + // + Report.Warning (78, 4, Location, "The 'l' suffix is easily confused with the digit '1' (use 'L' for clarity)"); + } + + goto case 'L'; + + case 'L': + if (is_long) + scanning = false; + is_long = true; + get_char (); + break; + + default: + scanning = false; + break; + } + c = peek_char (); + } while (scanning); + } + + if (is_long && is_unsigned){ + return new ULongLiteral (context.BuiltinTypes, ul, loc); + } + + if (is_unsigned){ + // uint if possible, or ulong else. + + if ((ul & 0xffffffff00000000) == 0) + return new UIntLiteral (context.BuiltinTypes, (uint) ul, loc); + else + return new ULongLiteral (context.BuiltinTypes, ul, loc); + } else if (is_long){ + // long if possible, ulong otherwise + if ((ul & 0x8000000000000000) != 0) + return new ULongLiteral (context.BuiltinTypes, ul, loc); + else + return new LongLiteral (context.BuiltinTypes, (long) ul, loc); + } else { + // int, uint, long or ulong in that order + if ((ul & 0xffffffff00000000) == 0){ + uint ui = (uint) ul; + + if ((ui & 0x80000000) != 0) + return new UIntLiteral (context.BuiltinTypes, ui, loc); + else + return new IntLiteral (context.BuiltinTypes, (int) ui, loc); + } else { + if ((ul & 0x8000000000000000) != 0) + return new ULongLiteral (context.BuiltinTypes, ul, loc); + else + return new LongLiteral (context.BuiltinTypes, (long) ul, loc); + } + } + } + + // + // given `c' as the next char in the input decide whether + // we need to convert to a special type, and then choose + // the best representation for the integer + // + ILiteralConstant adjust_int (int c, Location loc) + { + try { + if (number_pos > 9){ + ulong ul = (uint) (number_builder [0] - '0'); + + for (int i = 1; i < number_pos; i++){ + ul = checked ((ul * 10) + ((uint)(number_builder [i] - '0'))); + } + + return integer_type_suffix (ul, c, loc); + } else { + uint ui = (uint) (number_builder [0] - '0'); + + for (int i = 1; i < number_pos; i++){ + ui = checked ((ui * 10) + ((uint)(number_builder [i] - '0'))); + } + + return integer_type_suffix (ui, c, loc); + } + } catch (OverflowException) { + Error_NumericConstantTooLong (); + return new IntLiteral (context.BuiltinTypes, 0, loc); + } + catch (FormatException) { + Report.Error (1013, Location, "Invalid number"); + return new IntLiteral (context.BuiltinTypes, 0, loc); + } + } + + ILiteralConstant adjust_real (TypeCode t, Location loc) + { + string s = new string (number_builder, 0, number_pos); + const string error_details = "Floating-point constant is outside the range of type `{0}'"; + + switch (t){ + case TypeCode.Decimal: + try { + return new DecimalLiteral (context.BuiltinTypes, decimal.Parse (s, styles, csharp_format_info), loc); + } catch (OverflowException) { + Report.Error (594, Location, error_details, "decimal"); + return new DecimalLiteral (context.BuiltinTypes, 0, loc); + } + case TypeCode.Single: + try { + return new FloatLiteral (context.BuiltinTypes, float.Parse (s, styles, csharp_format_info), loc); + } catch (OverflowException) { + Report.Error (594, Location, error_details, "float"); + return new FloatLiteral (context.BuiltinTypes, 0, loc); + } + default: + try { + return new DoubleLiteral (context.BuiltinTypes, double.Parse (s, styles, csharp_format_info), loc); + } catch (OverflowException) { + Report.Error (594, loc, error_details, "double"); + return new DoubleLiteral (context.BuiltinTypes, 0, loc); + } + } + } + + ILiteralConstant handle_hex (Location loc) + { + int d; + ulong ul; + + get_char (); + while ((d = peek_char ()) != -1){ + if (is_hex (d)){ + number_builder [number_pos++] = (char) d; + get_char (); + } else + break; + } + + string s = new String (number_builder, 0, number_pos); + + try { + if (number_pos <= 8) + ul = System.UInt32.Parse (s, NumberStyles.HexNumber); + else + ul = System.UInt64.Parse (s, NumberStyles.HexNumber); + + return integer_type_suffix (ul, peek_char (), loc); + } catch (OverflowException){ + Error_NumericConstantTooLong (); + return new IntLiteral (context.BuiltinTypes, 0, loc); + } + catch (FormatException) { + Report.Error (1013, Location, "Invalid number"); + return new IntLiteral (context.BuiltinTypes, 0, loc); + } + } + + // + // Invoked if we know we have .digits or digits + // + int is_number (int c) + { + ILiteralConstant res; + +#if FULL_AST + int read_start = reader.Position - 1; + if (c == '.') { + // + // Caller did peek_char + // + --read_start; + } +#endif + number_pos = 0; + var loc = Location; + + if (c >= '0' && c <= '9'){ + if (c == '0'){ + int peek = peek_char (); + + if (peek == 'x' || peek == 'X') { + val = res = handle_hex (loc); +#if FULL_AST + res.ParsedValue = reader.ReadChars (read_start, reader.Position - 1); +#endif + + return Token.LITERAL; + } + } + decimal_digits (c); + c = get_char (); + } + + // + // We need to handle the case of + // "1.1" vs "1.string" (LITERAL_FLOAT vs NUMBER DOT IDENTIFIER) + // + bool is_real = false; + if (c == '.'){ + if (decimal_digits ('.')){ + is_real = true; + c = get_char (); + } else { + putback ('.'); + number_pos--; + val = res = adjust_int (-1, loc); + +#if FULL_AST + res.ParsedValue = reader.ReadChars (read_start, reader.Position - 1); +#endif + return Token.LITERAL; + } + } + + if (c == 'e' || c == 'E'){ + is_real = true; + if (number_pos == MaxNumberLength) + Error_NumericConstantTooLong (); + number_builder [number_pos++] = (char) c; + c = get_char (); + + if (c == '+'){ + if (number_pos == MaxNumberLength) + Error_NumericConstantTooLong (); + number_builder [number_pos++] = '+'; + c = -1; + } else if (c == '-') { + if (number_pos == MaxNumberLength) + Error_NumericConstantTooLong (); + number_builder [number_pos++] = '-'; + c = -1; + } else { + if (number_pos == MaxNumberLength) + Error_NumericConstantTooLong (); + number_builder [number_pos++] = '+'; + } + + decimal_digits (c); + c = get_char (); + } + + var type = real_type_suffix (c); + if (type == TypeCode.Empty && !is_real) { + putback (c); + res = adjust_int (c, loc); + } else { + is_real = true; + + if (type == TypeCode.Empty) { + putback (c); + } + + res = adjust_real (type, loc); + } + + val = res; + +#if FULL_AST + var chars = reader.ReadChars (read_start, reader.Position - (type == TypeCode.Empty && c > 0 ? 1 : 0)); + if (chars[chars.Length - 1] == '\r') + Array.Resize (ref chars, chars.Length - 1); + res.ParsedValue = chars; +#endif + + return Token.LITERAL; + } + + // + // Accepts exactly count (4 or 8) hex, no more no less + // + int getHex (int count, out int surrogate, out bool error) + { + int i; + int total = 0; + int c; + int top = count != -1 ? count : 4; + + get_char (); + error = false; + surrogate = 0; + for (i = 0; i < top; i++){ + c = get_char (); + + if (c >= '0' && c <= '9') + c = (int) c - (int) '0'; + else if (c >= 'A' && c <= 'F') + c = (int) c - (int) 'A' + 10; + else if (c >= 'a' && c <= 'f') + c = (int) c - (int) 'a' + 10; + else { + error = true; + return 0; + } + + total = (total * 16) + c; + if (count == -1){ + int p = peek_char (); + if (p == -1) + break; + if (!is_hex ((char)p)) + break; + } + } + + if (top == 8) { + if (total > 0x0010FFFF) { + error = true; + return 0; + } + + if (total >= 0x00010000) { + surrogate = ((total - 0x00010000) % 0x0400 + 0xDC00); + total = ((total - 0x00010000) / 0x0400 + 0xD800); + } + } + + return total; + } + + int escape (int c, out int surrogate) + { + bool error; + int d; + int v; + + d = peek_char (); + if (c != '\\') { + surrogate = 0; + return c; + } + + switch (d){ + case 'a': + v = '\a'; break; + case 'b': + v = '\b'; break; + case 'n': + v = '\n'; break; + case 't': + v = '\t'; break; + case 'v': + v = '\v'; break; + case 'r': + v = '\r'; break; + case '\\': + v = '\\'; break; + case '/': + v = '/'; break; + case 'f': + v = '\f'; break; + case '0': + v = 0; break; + case '"': + v = '"'; break; + case '\'': + v = '\''; break; + case 'x': + v = getHex (-1, out surrogate, out error); + if (error) + goto default; + return v; + case 'u': + case 'U': + return EscapeUnicode (d, out surrogate); + default: + surrogate = 0; + Report.Error (1009, Location, "Unrecognized escape sequence `\\{0}'", ((char)d).ToString ()); + return d; + } + + get_char (); + surrogate = 0; + return v; + } + + int EscapeUnicode (int ch, out int surrogate) + { + bool error; + if (ch == 'U') { + ch = getHex (8, out surrogate, out error); + } else { + ch = getHex (4, out surrogate, out error); + } + + if (error) + Report.Error (1009, Location, "Unrecognized escape sequence"); + + return ch; + } + + int get_char () + { + int x; + if (putback_char != -1) { + x = putback_char; + putback_char = -1; + } else { + x = reader.Read (); + } + + if (x == '\r') { + if (peek_char () == '\n') { + putback_char = -1; + } + + x = '\n'; + advance_line (); + } else if (x == '\n') { + advance_line (); + } else { + col++; + } + return x; + } + + void advance_line () + { + line++; + ref_line++; + previous_col = col; + col = 0; + } + + int peek_char () + { + if (putback_char == -1) + putback_char = reader.Read (); + return putback_char; + } + + int peek_char2 () + { + if (putback_char != -1) + return putback_char; + return reader.Peek (); + } + + public void putback (int c) + { + if (putback_char != -1) { + throw new InternalErrorException (string.Format ("Secondary putback [{0}] putting back [{1}] is not allowed", (char)putback_char, (char) c), Location); + } + + if (c == '\n' || col == 0) { + // It won't happen though. + line--; + ref_line--; + col = previous_col; + } + else + col--; + putback_char = c; + } + + public bool advance () + { + return peek_char () != -1 || CompleteOnEOF; + } + + public Object Value { + get { + return val; + } + } + + public Object value () + { + return val; + } + + public int token () + { + prev_token = current_token; + prev_token_line = current_token_line; + + current_token = xtoken (true); + current_token_line = line; + + return current_token; + } + + public void token_putback (int token) + { + if (putback_token != -1) + throw new Exception("Can't put back token twice.'"); + putback_token = token; + } + + int TokenizePreprocessorIdentifier (out int c) + { + // skip over white space + do { + c = get_char (); + } while (c == ' ' || c == '\t'); + + + int pos = 0; + while (c != -1 && c >= 'a' && c <= 'z') { + id_builder[pos++] = (char) c; + c = get_char (); + if (c == '\\') { + int peek = peek_char (); + if (peek == 'U' || peek == 'u') { + int surrogate; + c = EscapeUnicode (c, out surrogate); + if (surrogate != 0) { + if (is_identifier_part_character ((char) c)) { + id_builder[pos++] = (char) c; + } + c = surrogate; + } + } + } + } + + return pos; + } + + PreprocessorDirective get_cmd_arg (out string arg) + { + int c; + + tokens_seen = false; + arg = ""; + + var cmd = GetPreprocessorDirective (id_builder, TokenizePreprocessorIdentifier (out c)); + + if ((cmd & PreprocessorDirective.CustomArgumentsParsing) != 0) + return cmd; + + // skip over white space + while (c == ' ' || c == '\t') + c = get_char (); + + int has_identifier_argument = (int)(cmd & PreprocessorDirective.RequiresArgument); + int pos = 0; + + while (c != -1 && c != '\n') { + if (c == '\\' && has_identifier_argument >= 0) { + if (has_identifier_argument != 0) { + has_identifier_argument = 1; + + int peek = peek_char (); + if (peek == 'U' || peek == 'u') { + int surrogate; + c = EscapeUnicode (c, out surrogate); + if (surrogate != 0) { + if (is_identifier_part_character ((char) c)) { + if (pos == value_builder.Length) + Array.Resize (ref value_builder, pos * 2); + + value_builder[pos++] = (char) c; + } + c = surrogate; + } + } + } else { + has_identifier_argument = -1; + } + } else if (c == '/' && peek_char () == '/') { + // + // Eat single-line comments + // + get_char (); + do { + c = get_char (); + } while (c != -1 && c != '\n'); + + break; + } + + if (pos == value_builder.Length) + Array.Resize (ref value_builder, pos * 2); + + value_builder[pos++] = (char) c; + c = get_char (); + } + + if (pos != 0) { + if (pos > MaxIdentifierLength) + arg = new string (value_builder, 0, pos); + else + arg = InternIdentifier (value_builder, pos); + + // Eat any trailing whitespaces + arg = arg.Trim (simple_whitespaces); + } + + return cmd; + } + + // + // Handles the #line directive + // + bool PreProcessLine () + { + Location loc = Location; + + int c; + + int length = TokenizePreprocessorIdentifier (out c); + if (length == line_default.Length) { + if (!IsTokenIdentifierEqual (line_default)) + return false; + + current_source = source_file.SourceFile; + if (!hidden_block_start.IsNull) { + current_source.RegisterHiddenScope (hidden_block_start, loc); + hidden_block_start = Location.Null; + } + + ref_line = line; + return true; + } + + if (length == line_hidden.Length) { + if (!IsTokenIdentifierEqual (line_hidden)) + return false; + + if (hidden_block_start.IsNull) + hidden_block_start = loc; + + return true; + } + + if (length != 0 || c < '0' || c > '9') { + // + // Eat any remaining characters to continue parsing on next line + // + while (c != -1 && c != '\n') { + c = get_char (); + } + + return false; + } + + int new_line = TokenizeNumber (c); + if (new_line < 1) { + // + // Eat any remaining characters to continue parsing on next line + // + while (c != -1 && c != '\n') { + c = get_char (); + } + + return new_line != 0; + } + + c = get_char (); + if (c == ' ') { + // skip over white space + do { + c = get_char (); + } while (c == ' ' || c == '\t'); + } else if (c == '"') { + c = 0; + } + + if (c != '\n' && c != '/' && c != '"') { + // + // Eat any remaining characters to continue parsing on next line + // + while (c != -1 && c != '\n') { + c = get_char (); + } + + Report.Error (1578, loc, "Filename, single-line comment or end-of-line expected"); + return true; + } + + string new_file_name = null; + if (c == '"') { + new_file_name = TokenizeFileName (ref c); + + // skip over white space + while (c == ' ' || c == '\t') { + c = get_char (); + } + } + + if (c == '\n') { + } else if (c == '/') { + ReadSingleLineComment (); + } else { + // + // Eat any remaining characters to continue parsing on next line + // + while (c != -1 && c != '\n') { + c = get_char (); + } + + Error_EndLineExpected (); + return true; + } + + if (new_file_name != null) { + current_source = context.LookupFile (source_file, new_file_name); + source_file.AddIncludeFile (current_source); + } + + if (!hidden_block_start.IsNull) { + current_source.RegisterHiddenScope (hidden_block_start, loc); + hidden_block_start = Location.Null; + } + + ref_line = new_line; + return true; + } + + // + // Handles #define and #undef + // + void PreProcessDefinition (bool is_define, string ident, bool caller_is_taking) + { + if (ident.Length == 0 || ident == "true" || ident == "false"){ + Report.Error (1001, Location, "Missing identifier to pre-processor directive"); + return; + } + + if (ident.IndexOfAny (simple_whitespaces) != -1){ + Error_EndLineExpected (); + return; + } + + if (!is_identifier_start_character (ident [0])) + Report.Error (1001, Location, "Identifier expected: {0}", ident); + + foreach (char c in ident.Substring (1)){ + if (!is_identifier_part_character (c)){ + Report.Error (1001, Location, "Identifier expected: {0}", ident); + return; + } + } + + if (!caller_is_taking) + return; + + if (is_define) { + // + // #define ident + // + if (context.Settings.IsConditionalSymbolDefined (ident)) + return; + + source_file.AddDefine (ident); + } else { + // + // #undef ident + // + source_file.AddUndefine (ident); + } + } + + byte read_hex (out bool error) + { + int total; + int c = get_char (); + + if ((c >= '0') && (c <= '9')) + total = (int) c - (int) '0'; + else if ((c >= 'A') && (c <= 'F')) + total = (int) c - (int) 'A' + 10; + else if ((c >= 'a') && (c <= 'f')) + total = (int) c - (int) 'a' + 10; + else { + error = true; + return 0; + } + + total *= 16; + c = get_char (); + + if ((c >= '0') && (c <= '9')) + total += (int) c - (int) '0'; + else if ((c >= 'A') && (c <= 'F')) + total += (int) c - (int) 'A' + 10; + else if ((c >= 'a') && (c <= 'f')) + total += (int) c - (int) 'a' + 10; + else { + error = true; + return 0; + } + + error = false; + return (byte) total; + } + + // + // Parses #pragma checksum + // + bool ParsePragmaChecksum () + { + // + // The syntax is ` "foo.txt" "{guid}" "hash"' + // + // guid is predefined hash algorithm guid {406ea660-64cf-4c82-b6f0-42d48172a799} for md5 + // + int c = get_char (); + + if (c != '"') + return false; + + string file_name = TokenizeFileName (ref c); + + // TODO: Any white-spaces count + if (c != ' ') + return false; + + SourceFile file = context.LookupFile (source_file, file_name); + + if (get_char () != '"' || get_char () != '{') + return false; + + bool error; + byte[] guid_bytes = new byte [16]; + int i = 0; + + for (; i < 4; i++) { + guid_bytes [i] = read_hex (out error); + if (error) + return false; + } + + if (get_char () != '-') + return false; + + for (; i < 10; i++) { + guid_bytes [i] = read_hex (out error); + if (error) + return false; + + guid_bytes [i++] = read_hex (out error); + if (error) + return false; + + if (get_char () != '-') + return false; + } + + for (; i < 16; i++) { + guid_bytes [i] = read_hex (out error); + if (error) + return false; + } + + if (get_char () != '}' || get_char () != '"') + return false; + + // TODO: Any white-spaces count + c = get_char (); + if (c != ' ') + return false; + + if (get_char () != '"') + return false; + + // Any length of checksum + List checksum_bytes = new List (16); + + var checksum_location = Location; + c = peek_char (); + while (c != '"' && c != -1) { + checksum_bytes.Add (read_hex (out error)); + if (error) + return false; + + c = peek_char (); + } + + if (c == '/') { + ReadSingleLineComment (); + } else if (get_char () != '"') { + return false; + } + + if (context.Settings.GenerateDebugInfo) { + var chsum = checksum_bytes.ToArray (); + + if (file.HasChecksum) { + if (!ArrayComparer.IsEqual (file.Checksum, chsum)) { + // TODO: Report.SymbolRelatedToPreviousError + Report.Warning (1697, 1, checksum_location, "Different checksum values specified for file `{0}'", file.Name); + } + } + + file.SetChecksum (guid_bytes, chsum); + current_source.AutoGenerated = true; + } + + return true; + } + + bool IsTokenIdentifierEqual (char[] identifier) + { + for (int i = 0; i < identifier.Length; ++i) { + if (identifier[i] != id_builder[i]) + return false; + } + + return true; + } + + int TokenizeNumber (int value) + { + number_pos = 0; + + decimal_digits (value); + uint ui = (uint) (number_builder[0] - '0'); + + try { + for (int i = 1; i < number_pos; i++) { + ui = checked ((ui * 10) + ((uint) (number_builder[i] - '0'))); + } + + return (int) ui; + } catch (OverflowException) { + Error_NumericConstantTooLong (); + return -1; + } + } + + string TokenizeFileName (ref int c) + { + var string_builder = new StringBuilder (); + while (c != -1 && c != '\n') { + c = get_char (); + if (c == '"') { + c = get_char (); + break; + } + + string_builder.Append ((char) c); + } + + if (string_builder.Length == 0) { + Report.Warning (1709, 1, Location, "Filename specified for preprocessor directive is empty"); + } + + + return string_builder.ToString (); + } + + int TokenizePragmaNumber (ref int c) + { + number_pos = 0; + + int number; + + if (c >= '0' && c <= '9') { + number = TokenizeNumber (c); + + c = get_char (); + + // skip over white space + while (c == ' ' || c == '\t') + c = get_char (); + + if (c == ',') { + c = get_char (); + } + + // skip over white space + while (c == ' ' || c == '\t') + c = get_char (); + } else { + number = -1; + if (c == '/') { + ReadSingleLineComment (); + } else { + Report.Warning (1692, 1, Location, "Invalid number"); + + // Read everything till the end of the line or file + do { + c = get_char (); + } while (c != -1 && c != '\n'); + } + } + + return number; + } + + void ReadSingleLineComment () + { + if (peek_char () != '/') + Report.Warning (1696, 1, Location, "Single-line comment or end-of-line expected"); + + // Read everything till the end of the line or file + int c; + do { + c = get_char (); + } while (c != -1 && c != '\n'); + } + + /// + /// Handles #pragma directive + /// + void ParsePragmaDirective (string arg) + { + int c; + int length = TokenizePreprocessorIdentifier (out c); + if (length == pragma_warning.Length && IsTokenIdentifierEqual (pragma_warning)) { + length = TokenizePreprocessorIdentifier (out c); + + // + // #pragma warning disable + // #pragma warning restore + // + if (length == pragma_warning_disable.Length) { + bool disable = IsTokenIdentifierEqual (pragma_warning_disable); + if (disable || IsTokenIdentifierEqual (pragma_warning_restore)) { + // skip over white space + while (c == ' ' || c == '\t') + c = get_char (); + + var loc = Location; + + if (c == '\n' || c == '/') { + if (c == '/') + ReadSingleLineComment (); + + // + // Disable/Restore all warnings + // + if (disable) { + Report.RegisterWarningRegion (loc).WarningDisable (loc.Row); + } else { + Report.RegisterWarningRegion (loc).WarningEnable (loc.Row); + } + } else { + // + // Disable/Restore a warning or group of warnings + // + int code; + do { + code = TokenizePragmaNumber (ref c); + if (code > 0) { + if (disable) { + Report.RegisterWarningRegion (loc).WarningDisable (loc, code, context.Report); + } else { + Report.RegisterWarningRegion (loc).WarningEnable (loc, code, context); + } + } + } while (code >= 0 && c != '\n' && c != -1); + } + + return; + } + } + + Report.Warning (1634, 1, Location, "Expected disable or restore"); + return; + } + + // + // #pragma checksum + // + if (length == pragma_checksum.Length && IsTokenIdentifierEqual (pragma_checksum)) { + if (c != ' ' || !ParsePragmaChecksum ()) { + Report.Warning (1695, 1, Location, + "Invalid #pragma checksum syntax. Expected \"filename\" \"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\" \"XXXX...\""); + } + + return; + } + + Report.Warning (1633, 1, Location, "Unrecognized #pragma directive"); + } + + bool eval_val (string s) + { + if (s == "true") + return true; + if (s == "false") + return false; + + return source_file.IsConditionalDefined (s); + } + + bool pp_primary (ref string s) + { + s = s.Trim (); + int len = s.Length; + + if (len > 0){ + char c = s [0]; + + if (c == '('){ + s = s.Substring (1); + bool val = pp_expr (ref s, false); + if (s.Length > 0 && s [0] == ')'){ + s = s.Substring (1); + return val; + } + Error_InvalidDirective (); + return false; + } + + if (is_identifier_start_character (c)){ + int j = 1; + + while (j < len){ + c = s [j]; + + if (is_identifier_part_character (c)){ + j++; + continue; + } + bool v = eval_val (s.Substring (0, j)); + s = s.Substring (j); + return v; + } + bool vv = eval_val (s); + s = ""; + return vv; + } + } + Error_InvalidDirective (); + return false; + } + + bool pp_unary (ref string s) + { + s = s.Trim (); + int len = s.Length; + + if (len > 0){ + if (s [0] == '!'){ + if (len > 1 && s [1] == '='){ + Error_InvalidDirective (); + return false; + } + s = s.Substring (1); + return ! pp_primary (ref s); + } else + return pp_primary (ref s); + } else { + Error_InvalidDirective (); + return false; + } + } + + bool pp_eq (ref string s) + { + bool va = pp_unary (ref s); + + s = s.Trim (); + int len = s.Length; + if (len > 0){ + if (s [0] == '='){ + if (len > 2 && s [1] == '='){ + s = s.Substring (2); + return va == pp_unary (ref s); + } else { + Error_InvalidDirective (); + return false; + } + } else if (s [0] == '!' && len > 1 && s [1] == '='){ + s = s.Substring (2); + + return va != pp_unary (ref s); + + } + } + + return va; + + } + + bool pp_and (ref string s) + { + bool va = pp_eq (ref s); + + s = s.Trim (); + int len = s.Length; + if (len > 0){ + if (s [0] == '&'){ + if (len > 2 && s [1] == '&'){ + s = s.Substring (2); + return (va & pp_and (ref s)); + } else { + Error_InvalidDirective (); + return false; + } + } + } + return va; + } + + // + // Evaluates an expression for `#if' or `#elif' + // + bool pp_expr (ref string s, bool isTerm) + { + bool va = pp_and (ref s); + s = s.Trim (); + int len = s.Length; + if (len > 0){ + char c = s [0]; + + if (c == '|'){ + if (len > 2 && s [1] == '|'){ + s = s.Substring (2); + return va | pp_expr (ref s, isTerm); + } else { + Error_InvalidDirective (); + return false; + } + } + if (isTerm) { + Error_EndLineExpected (); + return false; + } + } + + return va; + } + + bool eval (string s) + { + bool v = pp_expr (ref s, true); + s = s.Trim (); + if (s.Length != 0){ + return false; + } + + return v; + } + + void Error_NumericConstantTooLong () + { + Report.Error (1021, Location, "Integral constant is too large"); + } + + void Error_InvalidDirective () + { + Report.Error (1517, Location, "Invalid preprocessor directive"); + } + + void Error_UnexpectedDirective (string extra) + { + Report.Error ( + 1028, Location, + "Unexpected processor directive ({0})", extra); + } + + void Error_TokensSeen () + { + Report.Error (1032, Location, + "Cannot define or undefine preprocessor symbols after first token in file"); + } + + void Eror_WrongPreprocessorLocation () + { + Report.Error (1040, Location, + "Preprocessor directives must appear as the first non-whitespace character on a line"); + } + + void Error_EndLineExpected () + { + Report.Error (1025, Location, "Single-line comment or end-of-line expected"); + } + + // + // Raises a warning when tokenizer found documentation comment + // on unexpected place + // + void WarningMisplacedComment (Location loc) + { + if (doc_state != XmlCommentState.Error) { + doc_state = XmlCommentState.Error; + Report.Warning (1587, 2, loc, "XML comment is not placed on a valid language element"); + } + } + + // + // if true, then the code continues processing the code + // if false, the code stays in a loop until another directive is + // reached. + // When caller_is_taking is false we ignore all directives except the ones + // which can help us to identify where the #if block ends + bool ParsePreprocessingDirective (bool caller_is_taking) + { + string arg; + bool region_directive = false; + + var directive = get_cmd_arg (out arg); + + // + // The first group of pre-processing instructions is always processed + // + switch (directive) { + case PreprocessorDirective.Region: + region_directive = true; + arg = "true"; + goto case PreprocessorDirective.If; + + case PreprocessorDirective.Endregion: + if (ifstack == null || ifstack.Count == 0){ + Error_UnexpectedDirective ("no #region for this #endregion"); + return true; + } + int pop = ifstack.Pop (); + + if ((pop & REGION) == 0) + Report.Error (1027, Location, "Expected `#endif' directive"); + + return caller_is_taking; + + case PreprocessorDirective.If: + if (ifstack == null) + ifstack = new Stack (2); + + int flags = region_directive ? REGION : 0; + if (ifstack.Count == 0){ + flags |= PARENT_TAKING; + } else { + int state = ifstack.Peek (); + if ((state & TAKING) != 0) { + flags |= PARENT_TAKING; + } + } + + if (eval (arg) && caller_is_taking) { + ifstack.Push (flags | TAKING); + return true; + } + ifstack.Push (flags); + return false; + + case PreprocessorDirective.Endif: + if (ifstack == null || ifstack.Count == 0){ + Error_UnexpectedDirective ("no #if for this #endif"); + return true; + } else { + pop = ifstack.Pop (); + + if ((pop & REGION) != 0) + Report.Error (1038, Location, "#endregion directive expected"); + + if (arg.Length != 0) { + Error_EndLineExpected (); + } + + if (ifstack.Count == 0) + return true; + + int state = ifstack.Peek (); + return (state & TAKING) != 0; + } + + case PreprocessorDirective.Elif: + if (ifstack == null || ifstack.Count == 0){ + Error_UnexpectedDirective ("no #if for this #elif"); + return true; + } else { + int state = ifstack.Pop (); + + if ((state & REGION) != 0) { + Report.Error (1038, Location, "#endregion directive expected"); + return true; + } + + if ((state & ELSE_SEEN) != 0){ + Error_UnexpectedDirective ("#elif not valid after #else"); + return true; + } + + if ((state & TAKING) != 0) { + ifstack.Push (0); + return false; + } + + if (eval (arg) && ((state & PARENT_TAKING) != 0)){ + ifstack.Push (state | TAKING); + return true; + } + + ifstack.Push (state); + return false; + } + + case PreprocessorDirective.Else: + if (ifstack == null || ifstack.Count == 0){ + Error_UnexpectedDirective ("no #if for this #else"); + return true; + } else { + int state = ifstack.Peek (); + + if ((state & REGION) != 0) { + Report.Error (1038, Location, "#endregion directive expected"); + return true; + } + + if ((state & ELSE_SEEN) != 0){ + Error_UnexpectedDirective ("#else within #else"); + return true; + } + + ifstack.Pop (); + + if (arg.Length != 0) { + Error_EndLineExpected (); + return true; + } + + bool ret = false; + if ((state & PARENT_TAKING) != 0) { + ret = (state & TAKING) == 0; + + if (ret) + state |= TAKING; + else + state &= ~TAKING; + } + + ifstack.Push (state | ELSE_SEEN); + + return ret; + } + case PreprocessorDirective.Define: + if (any_token_seen){ + Error_TokensSeen (); + return caller_is_taking; + } + PreProcessDefinition (true, arg, caller_is_taking); + return caller_is_taking; + + case PreprocessorDirective.Undef: + if (any_token_seen){ + Error_TokensSeen (); + return caller_is_taking; + } + PreProcessDefinition (false, arg, caller_is_taking); + return caller_is_taking; + + case PreprocessorDirective.Invalid: + Report.Error (1024, Location, "Wrong preprocessor directive"); + return true; + } + + // + // These are only processed if we are in a `taking' block + // + if (!caller_is_taking) + return false; + + switch (directive){ + case PreprocessorDirective.Error: + Report.Error (1029, Location, "#error: '{0}'", arg); + return true; + + case PreprocessorDirective.Warning: + Report.Warning (1030, 1, Location, "#warning: `{0}'", arg); + return true; + + case PreprocessorDirective.Pragma: + if (context.Settings.Version == LanguageVersion.ISO_1) { + Report.FeatureIsNotAvailable (context, Location, "#pragma"); + } + + ParsePragmaDirective (arg); + return true; + + case PreprocessorDirective.Line: + Location loc = Location; + if (!PreProcessLine ()) + Report.Error (1576, loc, "The line number specified for #line directive is missing or invalid"); + + return caller_is_taking; + } + + throw new NotImplementedException (directive.ToString ()); + } + + private int consume_string (bool quoted, char quoteChar = '"') + { + int c; + int pos = 0; + Location start_location = Location; + if (quoted) + start_location = start_location - 1; + +#if FULL_AST + int reader_pos = reader.Position; +#endif + + while (true) { + c = get_char (); + if (c == quoteChar) { + if (quoted && peek_char () == quoteChar) { + if (pos == value_builder.Length) + Array.Resize (ref value_builder, pos * 2); + + value_builder[pos++] = (char) c; + get_char (); + continue; + } + + string s; + if (pos == 0) + s = string.Empty; + else if (pos <= 4) + s = InternIdentifier (value_builder, pos); + else + s = new string (value_builder, 0, pos); + + ILiteralConstant res = new StringLiteral (context.BuiltinTypes, s, start_location); + val = res; +#if FULL_AST + res.ParsedValue = quoted ? + reader.ReadChars (reader_pos - 2, reader.Position - 1) : + reader.ReadChars (reader_pos - 1, reader.Position); +#endif + + return Token.LITERAL; + } + + if (c == '\n') { + if (!quoted) { + Report.Error (1010, Location, "Newline in constant"); + val = new StringLiteral (context.BuiltinTypes, new string (value_builder, 0, pos), start_location); + return Token.LITERAL; + } + } else if (c == '\\' && !quoted) { + int surrogate; + c = escape (c, out surrogate); + if (c == -1) + return Token.ERROR; + if (surrogate != 0) { + if (pos == value_builder.Length) + Array.Resize (ref value_builder, pos * 2); + + value_builder[pos++] = (char) c; + c = surrogate; + } + } else if (c == -1) { + Report.Error (1039, Location, "Unterminated string literal"); + return Token.EOF; + } + + if (pos == value_builder.Length) + Array.Resize (ref value_builder, pos * 2); + + value_builder[pos++] = (char) c; + } + } + + private int consume_regex () + { + int c; + int pos = 0; + Location start_location = Location; + +#if FULL_AST + int reader_pos = reader.Position; +#endif + + StringBuilder opt_builder = null; + + while (true) { + c = get_char (); + if (c == '\\') { + if (pos == value_builder.Length) + Array.Resize (ref value_builder, pos * 2); + value_builder[pos++] = (char) c; + c = get_char (); + // c will be added automatically at the end of this block + } else if (c == '/') { + + c = peek_char(); + while (c == 'g' || c == 'i' || c == 'm' || c == 's' || c == 'x') { + if (opt_builder == null) + opt_builder = new StringBuilder(); + opt_builder.Append((char) get_char ()); + c = peek_char (); + } + + string s; + if (pos == 0) + s = string.Empty; + else + s = new string (value_builder, 0, pos); + + ILiteralConstant res = new RegexLiteral (s, + opt_builder != null ? opt_builder.ToString() : null, + start_location); + val = res; +#if FULL_AST + res.ParsedValue = quoted ? + reader.ReadChars (reader_pos - 2, reader.Position - 1) : + reader.ReadChars (reader_pos - 1, reader.Position); +#endif + + return Token.LITERAL; + } + + if (c == '\n') { + Report.Error (7027, Location, "Newline in regex constant"); + val = new StringLiteral (context.BuiltinTypes, new string (value_builder, 0, pos), start_location); + return Token.LITERAL; + } /* else if (c == '\\') { + c = get_char(); + if (c != -1) { + if (pos == value_builder.Length) + Array.Resize (ref value_builder, pos * 2); + value_builder[pos++] = (char) c; + } + } */ + + if (c == -1) { + Report.Error (7028, Location, "Unterminated regex literal"); + return Token.EOF; + } + + if (pos == value_builder.Length) + Array.Resize (ref value_builder, pos * 2); + + value_builder[pos++] = (char) c; + } + } + + private int consume_xml () + { + int c; + int pos = 0; + Location start_location = Location; + +#if FULL_AST + int reader_pos = reader.Position; +#endif + + if (pos == value_builder.Length) + Array.Resize (ref value_builder, pos * 2); + value_builder[pos++] = (char) '<'; + + while (true) { + + c = get_char (); + if (c == '>') { + + if (pos == value_builder.Length) + Array.Resize (ref value_builder, pos * 2); + value_builder[pos++] = (char) c; + + c = peek_char(); + while (c == ' ' || c == '\t') { + c = get_char (); + if (pos == value_builder.Length) + Array.Resize (ref value_builder, pos * 2); + value_builder[pos++] = (char) c; + } + + // TODO: This is a pretty ghetto way to identify the end of the xml literal. Probably will + // work most of the time, but is not a general solution. FIXME + if (c == ';' || c == '.' || c == ',' || c == ')' || c == '}' || c == ']') { + + string s; + if (pos == 0) + s = string.Empty; + else + s = new string (value_builder, 0, pos); + + ILiteralConstant res = new XmlLiteral (s, start_location); + val = res; +#if FULL_AST + res.ParsedValue = quoted ? + reader.ReadChars (reader_pos - 2, reader.Position - 1) : + reader.ReadChars (reader_pos - 1, reader.Position); +#endif + + return Token.LITERAL; + } + } + + if (c == -1) { + Report.Error (7029, Location, "Unterminated xml literal"); + return Token.EOF; + } + + if (pos == value_builder.Length) + Array.Resize (ref value_builder, pos * 2); + value_builder[pos++] = (char) c; + } + } + + private int consume_identifier (bool parse_token, int s) + { + int res = consume_identifier (parse_token, s, false); + + if (doc_state == XmlCommentState.Allowed) + doc_state = XmlCommentState.NotAllowed; + + // + // Very bad grammar rule. Identifier can be start of declaration or block statement + // we don't know without checking next token(s) and this is on hot path + // + if (res == Token.IDENTIFIER) { + var start_line = ref_line; + + PushPosition (); + var next_token = token (); + // Statement separators are optional + if (start_line != ref_line) + next_token = 0; + + PopPosition (); + + var pt = peek_token (); + + switch (next_token) { + // Stop tokens + case Token.FUNCTION: + case Token.VAR: + case Token.CONST: + case Token.CLASS: + case Token.NAMESPACE: + case Token.INTERFACE: + + // Modifiers tokens + case Token.PUBLIC: + case Token.PROPERTY: + case Token.INTERNAL: + case Token.PRIVATE: + case Token.ABSTRACT: + case Token.FINAL: + case Token.STATIC: + case Token.VIRTUAL: + case Token.OVERRIDE: + case Token.NATIVE: + case Token.IDENTIFIER_MODIFIER: + return Token.IDENTIFIER_MODIFIER; + } + } + + return res; + } + + int consume_identifier (bool parse_token, int c, bool quoted) + { + // + // This method is very performance sensitive. It accounts + // for approximately 25% of all parser time + // + + int pos = 0; + int column = col; + if (quoted) + --column; + + if (c == '\\') { + int surrogate; + c = escape (c, out surrogate); + if (surrogate != 0) { + id_builder [pos++] = (char) c; + c = surrogate; + } + } + + id_builder [pos++] = (char) c; + + bool is_config_ident = false; + + try { + while (true) { + c = reader.Read (); + + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || c == '$') { + id_builder [pos++] = (char) c; + continue; + } + + if (parsing_block == 0 && c == ':' && !is_config_ident) { + var colonPos = reader.Position; + c = reader.Read (); + if (c == ':') { + c = reader.Read (); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$') { + is_config_ident = true; + id_builder [pos++] = ':'; + id_builder [pos++] = ':'; + id_builder [pos++] = (char) c; + continue; + } + } + if (!is_config_ident) { + reader.Position = colonPos; + c = ':'; + } + } + + if (c < 0x80) { + if (c == '\\') { + int surrogate; + c = escape (c, out surrogate); + if (is_identifier_part_character ((char) c)) + id_builder[pos++] = (char) c; + + if (surrogate != 0) { + c = surrogate; + } + + continue; + } + } else if (Char.IsLetter ((char) c) || Char.GetUnicodeCategory ((char) c) == UnicodeCategory.ConnectorPunctuation) { + id_builder [pos++] = (char) c; + continue; + } + + putback_char = c; + break; + } + } catch (IndexOutOfRangeException) { + Report.Error (645, Location, "Identifier too long (limit is 512 chars)"); + --pos; + col += pos; + } + + col += pos - 1; + + // + // Optimization: avoids doing the keyword lookup + // on uppercase letters + // + if (!quoted && !is_config_ident && id_builder [0] >= '_') { + int keyword = GetKeyword (id_builder, pos); + if (keyword != -1) { + val = ltb.Create (keyword == Token.AWAIT ? "await" : null, current_source, ref_line, column); + if (keyword == Token.ELSE && do_auto_semi_insertion(parse_token, line, -1, keyword)) + return Token.SEMICOLON; + return keyword; + } + } + + string s = InternIdentifier (id_builder, pos); + + val = ltb.Create (s, current_source, ref_line, column); + if (quoted && parsing_attribute_section) + AddEscapedIdentifier (((LocatedToken) val).Location); + + return is_config_ident ? Token.IDENTIFIER_CONFIG : Token.IDENTIFIER; + } + + string InternIdentifier (char[] charBuffer, int length) + { + // + // Keep identifiers in an array of hashtables to avoid needless + // allocations + // + var identifiers_group = identifiers[length]; + string s; + if (identifiers_group != null) { + if (identifiers_group.TryGetValue (charBuffer, out s)) { + return s; + } + } else { + // TODO: this should be number of files dependant + // corlib compilation peaks at 1000 and System.Core at 150 + int capacity = length > 20 ? 10 : 100; + identifiers_group = new Dictionary (capacity, new IdentifiersComparer (length)); + identifiers[length] = identifiers_group; + } + + char[] chars = new char[length]; + Array.Copy (charBuffer, chars, length); + + s = new string (charBuffer, 0, length); + identifiers_group.Add (chars, s); + return s; + } + + public int xtoken (bool parse_token = false) + { + int d, c, next; + + // Allow next token to be pushed back if we insert semicolons + if (putback_token != -1) { + next = putback_token; + putback_token = -1; + return next; + } + + // Decrement parse regex counter (allows regex literals to follow 1 token after + // symbols '=', ':', '(', '[', and ',') + if (parse_regex_xml > 0) + parse_regex_xml--; + + // Decrement parse colon counter (allows us to disambiguate ident:*=value from *= operator) + if (parse_colon > 0) + parse_colon--; + + // Decrement allow auto semi counter (allows us to allow semicolon insertion only after next x symbols) + if (allow_auto_semi_after > 0) + allow_auto_semi_after--; + + // Whether we have seen comments on the current line + bool comments_seen = false; + while ((c = get_char ()) != -1) { + switch (c) { + case '\t': + col = ((col - 1 + tab_size) / tab_size) * tab_size; + continue; + + case ' ': + case '\f': + case '\v': + case 0xa0: + case 0: + case 0xFEFF: // Ignore BOM anywhere in the file + continue; + +/* This is required for compatibility with .NET + case 0xEF: + if (peek_char () == 0xBB) { + PushPosition (); + get_char (); + if (get_char () == 0xBF) + continue; + PopPosition (); + } + break; +*/ + case '\\': + tokens_seen = true; + return consume_identifier (parse_token, c); + + case '{': + val = ltb.Create (current_source, ref_line, col); + if (current_token == Token.OPEN_PARENS || + current_token == Token.ASSIGN || + current_token == Token.COMMA || + current_token == Token.COLON || + current_token == Token.OPEN_BRACKET || + current_token == Token.OPEN_BRACKET_EXPR || + current_token == Token.RETURN) { + bool isInit = true; + PushPosition(); + next = token (); + if (next != Token.CLOSE_BRACE) { + if (next != Token.IDENTIFIER && next != Token.LITERAL) { + isInit = false; + } else { + next = token (); + if (next != Token.COLON) { + isInit = false; + } + } + } + PopPosition(); + if (isInit) + return Token.OPEN_BRACE_INIT; + } + return Token.OPEN_BRACE; + case '}': + if (do_auto_semi_insertion (parse_token, line, c, -1)) + return Token.SEMICOLON; + val = ltb.Create (current_source, ref_line, col); + return Token.CLOSE_BRACE; + case '[': + // To block doccomment inside attribute declaration. + if (doc_state == XmlCommentState.Allowed) + doc_state = XmlCommentState.NotAllowed; + + val = ltb.Create (current_source, ref_line, col); + + parse_regex_xml = 2; // regex literals may be included in array initializers. + + if (parsing_block == 0/* || lambda_arguments_parsing*/) + return Token.OPEN_BRACKET; + + next = peek_char (); + switch (next) { + case ']': + case ',': + return Token.OPEN_BRACKET; + + case ' ': + case '\f': + case '\v': + case '\r': + case '\n': + case '/': + next = peek_token (); + if (next == Token.COMMA || next == Token.CLOSE_BRACKET) + return Token.OPEN_BRACKET; + + return Token.OPEN_BRACKET_EXPR; + default: + return Token.OPEN_BRACKET_EXPR; + } + case ']': + ltb.CreateOptional (current_source, ref_line, col, ref val); + return Token.CLOSE_BRACKET; + case '(': + val = ltb.Create (current_source, ref_line, col); + parse_regex_xml = 2; // regex literals may follow open parens (method param, expressions). + // + // An expression versions of parens can appear in block context only + // + if (parsing_block != 0) { // && !lambda_arguments_parsing) { + + // + // Optmize most common case where we know that parens + // is not special + // + switch (current_token) { + case Token.NEW: + case Token.SUPER: + case Token.THIS: + case Token.IDENTIFIER: + case Token.FUNCTION_BLOCK: + case Token.FUNCTION: + case Token.IF: + case Token.WHILE: + case Token.DO: + case Token.FOR: + case Token.FOR_EACH: + case Token.SWITCH: + case Token.CATCH: + case Token.WITH: + return Token.OPEN_PARENS; + } + + //lambda_arguments_parsing = true; + PushPosition (); + d = TokenizeOpenParens (); + PopPosition (); + //lambda_arguments_parsing = false; + return d; + } + + return Token.OPEN_PARENS; + case ')': +// d = peek_char (); +// if (d == '.') { +// get_char (); +// return Token.CLOSE_PARENS_DOT; +// } + ltb.CreateOptional (current_source, ref_line, col, ref val); + return Token.CLOSE_PARENS; + case ',': + ltb.CreateOptional (current_source, ref_line, col, ref val); + parse_regex_xml = 2; // Regex literals may follow commas, (method param, initializer element) + return Token.COMMA; + case ';': + ltb.CreateOptional (current_source, ref_line, col, ref val); + return Token.SEMICOLON; + case '~': + val = ltb.Create (current_source, ref_line, col); + return Token.TILDE; + case '?': + val = ltb.Create (current_source, ref_line, col); + return TokenizePossibleNullableType (); + + case '<': + val = ltb.Create (current_source, ref_line, col); + d = peek_char (); + + if (d == '=') { + get_char (); + return Token.OP_LE; + } + + if (d == '<') { + get_char (); + d = peek_char (); + + if (d == '=') { + get_char (); + return Token.OP_SHIFT_LEFT_ASSIGN; + } + return Token.OP_SHIFT_LEFT; + } + + if (parse_regex_xml > 0 && char.IsLetter ((char)d)) { + return consume_xml(); + } + + return Token.OP_LT; + + case '>': + val = ltb.Create (current_source, ref_line, col); + d = peek_char (); + + if (parsing_generic_less_than > 1 || (parsing_generic_less_than == 1 && d != '>')) { + parsing_generic_less_than--; + return Token.OP_GENERICS_GT; + } + + if (d == '=') { + get_char (); + return Token.OP_GE; + } + + if (d == '>') { + get_char (); + d = peek_char (); + + if (d == '=') { + get_char (); + return Token.OP_SHIFT_RIGHT_ASSIGN; + } + + if (d == '>') { + get_char (); + d = peek_char (); + + if (d == '=') { + get_char (); + return Token.OP_USHIFT_RIGHT_ASSIGN; + } + + return Token.OP_USHIFT_RIGHT; + } + return Token.OP_SHIFT_RIGHT; + } + + return Token.OP_GT; + + case '+': + val = ltb.Create (current_source, ref_line, col); + d = peek_char (); + if (d == '+') { + d = Token.OP_INC; + } else if (d == '=') { + d = Token.OP_ADD_ASSIGN; + } else { + return Token.PLUS; + } + get_char (); + return d; + + case '-': + val = ltb.Create (current_source, ref_line, col); + d = peek_char (); + if (d == '-') { + d = Token.OP_DEC; + } else if (d == '=') + d = Token.OP_SUB_ASSIGN; + else if (d == '>') + d = Token.OP_PTR; + else { + return Token.MINUS; + } + get_char (); + return d; + + case '!': + val = ltb.Create (current_source, ref_line, col); + if (peek_char () == '=') { + get_char (); + if (peek_char () == '=') { + get_char (); + return Token.OP_REF_NE; + } + return Token.OP_NE; + } + return Token.BANG; + + case '=': + val = ltb.Create (current_source, ref_line, col); + d = peek_char (); + if (d == '=') { + parse_regex_xml = 2; // Regex literals may follow equality test operators. + get_char (); + d = peek_char (); + if (d == '=') { + get_char (); + return Token.OP_REF_EQ; + } + return Token.OP_EQ; + } + if (d == '>' && parsing_playscript) { + get_char (); + return Token.ARROW; + } + + parse_regex_xml = 2; // Regex literals may follow assignment op '=' + return Token.ASSIGN; + + case '&': + val = ltb.Create (current_source, ref_line, col); + d = peek_char (); + if (d == '&') { + get_char (); + d = peek_char (); + if (d == '=') { + get_char (); + return Token.LOGICAL_AND_ASSIGN; + } + return Token.OP_AND; + } + if (d == '=') { + get_char (); + return Token.OP_AND_ASSIGN; + } + return Token.BITWISE_AND; + + case '|': + val = ltb.Create (current_source, ref_line, col); + d = peek_char (); + if (d == '|') { + get_char (); + d = peek_char (); + if (d == '=') { + get_char (); + return Token.LOGICAL_OR_ASSIGN; + } + return Token.OP_OR; + } + if (d == '=') { + get_char (); + return Token.OP_OR_ASSIGN; + } + return Token.BITWISE_OR; + + case '*': + val = ltb.Create (current_source, ref_line, col); + if (peek_char () == '=' && parse_colon == 0) { + get_char (); + return Token.OP_MULT_ASSIGN; + } + return Token.STAR; + + case '/': + d = peek_char (); + if (d == '=') { + val = ltb.Create (current_source, ref_line, col); + get_char (); + return Token.OP_DIV_ASSIGN; + } + + // Handle double-slash comments. + if (d == '/') { + get_char (); + if (doc_processing) { + if (peek_char () == '/') { + get_char (); + // Don't allow ////. + if ((d = peek_char ()) != '/') { + if (doc_state == XmlCommentState.Allowed) + handle_one_line_xml_comment (); + else if (doc_state == XmlCommentState.NotAllowed) + WarningMisplacedComment (Location - 3); + } + } else { + if (xml_comment_buffer.Length > 0) + doc_state = XmlCommentState.NotAllowed; + } + } + + while ((d = get_char ()) != -1 && d != '\n'); + + if (d == '\n') + putback (d); + + any_token_seen |= tokens_seen; + tokens_seen = false; + comments_seen = false; + continue; + } else if (d == '*') { + get_char (); + // Handle /*@asx conditional comment + if (peek_char () == '@') { + PushPosition(); + get_char (); + if (peek_char() == 'a') { + get_char (); + if (peek_char () == 's') { + get_char (); + if (peek_char () == 'x') { + get_char (); + DiscardPosition(); + continue; + } + } + } + PopPosition(); + } + bool docAppend = false; + if (doc_processing && peek_char () == '*') { + get_char (); + // But when it is /**/, just do nothing. + if (peek_char () == '/') { + get_char (); + continue; + } + if (doc_state == XmlCommentState.Allowed) + docAppend = true; + else if (doc_state == XmlCommentState.NotAllowed) { + WarningMisplacedComment (Location - 2); + } + } + + int current_comment_start = 0; + if (docAppend) { + current_comment_start = xml_comment_buffer.Length; + xml_comment_buffer.Append (Environment.NewLine); + } + + while ((d = get_char ()) != -1) { + if (d == '*' && peek_char () == '/') { + get_char (); + comments_seen = true; + break; + } + if (docAppend) + xml_comment_buffer.Append ((char)d); + + if (d == '\n') { + any_token_seen |= tokens_seen; + tokens_seen = false; + // + // Reset 'comments_seen' just to be consistent. + // It doesn't matter either way, here. + // + comments_seen = false; + } + } + if (!comments_seen) + Report.Error (1035, Location, "End-of-file found, '*/' expected"); + + if (docAppend) + update_formatted_doc_comment (current_comment_start); + continue; + } else if (parse_regex_xml > 0) { + // A regex literal may follow an '=', '==', '===' '(' ',' ':' or '['. + return consume_regex(); + } + val = ltb.Create (current_source, ref_line, col); + return Token.DIV; + + case '%': + val = ltb.Create (current_source, ref_line, col); + if (peek_char () == '=') { + get_char (); + return Token.OP_MOD_ASSIGN; + } + return Token.PERCENT; + + case '^': + val = ltb.Create (current_source, ref_line, col); + if (peek_char () == '=') { + get_char (); + return Token.OP_XOR_ASSIGN; + } + return Token.CARRET; + + case ':': + val = ltb.Create (current_source, ref_line, col); + if (peek_char () == ':') { + get_char (); + return Token.DOUBLE_COLON; + } + parse_regex_xml = 2; // Regex literals may follow colons in object initializers. + parse_colon = 2; // Don't parse *= after a colon + return Token.COLON; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + tokens_seen = true; + return is_number (c); + + case '\n': // white space + if (do_auto_semi_insertion (parse_token, line - 1, c, -1)) + return Token.SEMICOLON; + any_token_seen |= tokens_seen; + tokens_seen = false; + comments_seen = false; + continue; + + case '.': + tokens_seen = true; + d = peek_char (); + if (d >= '0' && d <= '9') + return is_number (c); + + if (d == '@') { + get_char (); + return Token.DOT_AT; + } + + if (d == '*') { + get_char (); + return Token.DOT_STAR; + } + +// if (d == '(') { +// get_char (); +// return Token.DOT_OPEN_PARENS; +// } + + if (d == '.') { + get_char (); + d = peek_char (); + if (d == '.') { + get_char (); + return Token.DOTDOTDOT; + } + if (d == '@') { + get_char (); + return Token.DOTDOT_AT; + } + if (d == '*') { + get_char (); + return Token.DOTDOT_STAR; + } + return Token.DOTDOT; + } + + ltb.CreateOptional (current_source, ref_line, col, ref val); + if (d != '<') { + return Token.DOT; + } + get_char (); + parsing_generic_less_than++; + int dim; + PushPosition (); + if (parse_generic_dimension (out dim)) { + val = dim; + DiscardPosition (); + return Token.GENERIC_DIMENSION; + } + PopPosition (); + return Token.OP_GENERICS_LT; + + case '#': + if (tokens_seen || comments_seen) { + Eror_WrongPreprocessorLocation (); + return Token.ERROR; + } + + if (ParsePreprocessingDirective (true)) + continue; + + bool directive_expected = false; + while ((c = get_char ()) != -1) { + if (col == 1) { + directive_expected = true; + } else if (!directive_expected) { + // TODO: Implement comment support for disabled code and uncomment this code +// if (c == '#') { +// Eror_WrongPreprocessorLocation (); +// return Token.ERROR; +// } + continue; + } + + if (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\v') + continue; + + if (c == '#') { + if (ParsePreprocessingDirective (false)) + break; + } + directive_expected = false; + } + + if (c != -1) { + tokens_seen = false; + continue; + } + + return Token.EOF; + + case '"': + return consume_string (false, '"'); + case '\'': + return consume_string (false, '\''); + +// case '\'': +// return TokenizeBackslash (); + + case '@': + if (!parsing_playscript) + return Token.OP_AT; + + c = get_char (); + if (c == '"') { + tokens_seen = true; + return consume_string (true); + } + + // Handle end @asx*/ conditional comment + PushPosition(); + if (c == 'a') { + if (peek_char () == 's') { + get_char (); + if (peek_char () == 'x') { + get_char (); + if (peek_char () == '*') { + get_char (); + if (peek_char () == '/') { + get_char (); + DiscardPosition(); + continue; + } + } + } + } + } + PopPosition(); + + if (is_identifier_start_character (c)){ + return consume_identifier (parse_token, c, true); + } + + Report.Error (1646, Location, "Keyword, identifier, or string expected after verbatim specifier: @"); + return Token.ERROR; + + case EvalStatementParserCharacter: + return Token.EVAL_STATEMENT_PARSER; + case EvalCompilationUnitParserCharacter: + return Token.EVAL_COMPILATION_UNIT_PARSER; + case EvalUsingDeclarationsParserCharacter: + return Token.EVAL_USING_DECLARATIONS_UNIT_PARSER; + case DocumentationXref: + return Token.DOC_SEE; + } + + if (is_identifier_start_character (c)) { + tokens_seen = true; + return consume_identifier (parse_token, c); + } + + if (char.IsWhiteSpace ((char) c)) + continue; + + Report.Error (1056, Location, "Unexpected character `{0}'", ((char) c).ToString ()); + } + + if (CompleteOnEOF){ + if (generated) + return Token.COMPLETE_COMPLETION; + + generated = true; + return Token.GENERATE_COMPLETION; + } + + + return Token.EOF; + } + +// int TokenizeBackslash () +// { +//#if FULL_AST +// int read_start = reader.Position; +//#endif +// Location start_location = Location; +// int c = get_char (); +// tokens_seen = true; +// if (c == '\'') { +// val = new CharLiteral (context.BuiltinTypes, (char) c, start_location); +// Report.Error (1011, start_location, "Empty character literal"); +// return Token.LITERAL; +// } +// +// if (c == '\n') { +// Report.Error (1010, start_location, "Newline in constant"); +// return Token.ERROR; +// } +// +// int d; +// c = escape (c, out d); +// if (c == -1) +// return Token.ERROR; +// if (d != 0) +// throw new NotImplementedException (); +// +// ILiteralConstant res = new CharLiteral (context.BuiltinTypes, (char) c, start_location); +// val = res; +// c = get_char (); +// +// if (c != '\'') { +// Report.Error (1012, start_location, "Too many characters in character literal"); +// +// // Try to recover, read until newline or next "'" +// while ((c = get_char ()) != -1) { +// if (c == '\n' || c == '\'') +// break; +// } +// } +// +//#if FULL_AST +// res.ParsedValue = reader.ReadChars (read_start - 1, reader.Position); +//#endif +// +// return Token.LITERAL; +// } + + + // + // Handles one line xml comment + // + private void handle_one_line_xml_comment () + { + int c; + while ((c = peek_char ()) == ' ') + get_char (); // skip heading whitespaces. + while ((c = peek_char ()) != -1 && c != '\n' && c != '\r') { + xml_comment_buffer.Append ((char) get_char ()); + } + if (c == '\r' || c == '\n') + xml_comment_buffer.Append (Environment.NewLine); + } + + // + // Remove heading "*" in Javadoc-like xml documentation. + // + private void update_formatted_doc_comment (int current_comment_start) + { + int length = xml_comment_buffer.Length - current_comment_start; + string [] lines = xml_comment_buffer.ToString ( + current_comment_start, + length).Replace ("\r", "").Split ('\n'); + + // The first line starts with /**, thus it is not target + // for the format check. + for (int i = 1; i < lines.Length; i++) { + string s = lines [i]; + int idx = s.IndexOf ('*'); + string head = null; + if (idx < 0) { + if (i < lines.Length - 1) + return; + head = s; + } else + head = s.Substring (0, idx); + foreach (char c in head) + if (c != ' ') + return; + lines [i] = s.Substring (idx + 1); + } + xml_comment_buffer.Remove (current_comment_start, length); + xml_comment_buffer.Insert (current_comment_start, String.Join (Environment.NewLine, lines)); + } + + // + // Checks if there was incorrect doc comments and raise + // warnings. + // + public void check_incorrect_doc_comment () + { + if (xml_comment_buffer.Length > 0) + WarningMisplacedComment (Location); + } + + // + // Consumes the saved xml comment lines (if any) + // as for current target member or type. + // + public string consume_doc_comment () + { + if (xml_comment_buffer.Length > 0) { + string ret = xml_comment_buffer.ToString (); + reset_doc_comment (); + return ret; + } + return null; + } + + Report Report { + get { return context.Report; } + } + + void reset_doc_comment () + { + xml_comment_buffer.Length = 0; + } + + bool do_auto_semi_insertion (bool parse_token, int line, int c, int t) + { + bool insert_semi = false; + if (parse_token && prev_token_line == line && prev_token != Token.SEMICOLON && !parsing_playscript && allow_auto_semi && + allow_auto_semi_after == 0 && allowed_auto_semi_tokens[prev_token]) { + PushPosition (); + int next = xtoken (); + PopPosition (); + if (!disallowed_next_auto_semi_tokens[next]) { + if (c != -1) + putback (c); + else + token_putback (t); + warn_semi_inserted (Location); + insert_semi = true; + } + } + if (parse_token && has_temp_auto_semi_after_tokens) + clear_temp_auto_semi_tokens (); + return insert_semi; + } + + void warn_semi_inserted (Location loc) + { + Report.Warning (7093, 1, loc, "Semicolon automatically inserted on unterminated line."); + } + + void clear_temp_auto_semi_tokens () + { + var len = temp_auto_semi_after_tokens.Count; + for (var i = 0; i < len; i++) { + int token = temp_auto_semi_after_tokens[i]; + allowed_auto_semi_tokens.Set (token, false); + } + has_temp_auto_semi_after_tokens = false; + } + + public void cleanup () + { + if (ifstack != null && ifstack.Count >= 1) { + int state = ifstack.Pop (); + if ((state & REGION) != 0) + Report.Error (1038, Location, "#endregion directive expected"); + else + Report.Error (1027, Location, "Expected `#endif' directive"); + } + } + } + + // + // Indicates whether it accepts XML documentation or not. + // + public enum XmlCommentState { + // comment is allowed in this state. + Allowed, + // comment is not allowed in this state. + NotAllowed, + // once comments appeared when it is NotAllowed, then the + // state is changed to it, until the state is changed to + // .Allowed. + Error + } +} + diff --git a/mcs/mcs/report.cs b/mcs/mcs/report.cs index f49a2980d7a..09b4effbc50 100644 --- a/mcs/mcs/report.cs +++ b/mcs/mcs/report.cs @@ -231,6 +231,22 @@ public void Warning (int code, int level, Location loc, string message) printer.Print (msg, settings.ShowFullPaths); } + public void WarningPlayScript (int code, Location loc, string format, string arg) + { + WarningPlayScript (code, loc, string.Format (format, arg)); + } + + public void WarningPlayScript (int code, Location loc, string error) + { + if (reporting_disabled > 0) + return; + + var msg = new PlayScript.WarningMessage (code, loc, error, extra_information); + extra_information.Clear (); + + printer.Print (msg, settings.ShowFullPaths); + } + public void Warning (int code, int level, Location loc, string format, string arg) { Warning (code, level, loc, String.Format (format, arg)); @@ -278,9 +294,35 @@ public void Error (int code, Location loc, string error) if (reporting_disabled > 0) return; - ErrorMessage msg = new ErrorMessage (code, loc, error, extra_information); + var msg = new ErrorMessage (code, loc, error, extra_information); extra_information.Clear (); + ProcessErrorMessage (msg); + } + + public void ErrorPlayScript (int code, Location loc, string format, params string[] args) + { + ErrorPlayScript (code, loc, string.Format (format, args)); + } + + public void ErrorPlayScript (int code, Location loc, string format, string arg) + { + ErrorPlayScript (code, loc, string.Format (format, arg)); + } + + public void ErrorPlayScript (int code, Location loc, string error) + { + if (reporting_disabled > 0) + return; + + var msg = new PlayScript.ErrorMessage (code, loc, error, extra_information); + extra_information.Clear (); + + ProcessErrorMessage (msg); + } + + void ProcessErrorMessage (AbstractMessage msg) + { printer.Print (msg, settings.ShowFullPaths); if (settings.Stacktrace) @@ -489,6 +531,12 @@ public override int GetHashCode () public abstract bool IsWarning { get; } + public virtual string LanguagePrefix { + get { + return "CS"; + } + } + public Location Location { get { return location; } } @@ -594,7 +642,7 @@ protected void Print (AbstractMessage msg, TextWriter output, bool showFullPath) txt.Append (" "); } - txt.AppendFormat ("{0} CS{1:0000}: {2}", msg.MessageType, msg.Code, msg.Text); + txt.AppendFormat ("{0} {3}{1:0000}: {2}", msg.MessageType, msg.Code, msg.Text, msg.LanguagePrefix); if (!msg.IsWarning) output.WriteLine (FormatText (txt.ToString ())); diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index 5bf69e6a40b..cfba55cfd7e 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -866,6 +866,11 @@ protected override bool DoResolve (BlockContext ec) if (ec.CurrentIterator != null) { Error_ReturnFromIterator (ec); } else if (ec.ReturnType != InternalType.ErrorType) { + if (ec.ReturnType == ec.Module.PlayscriptTypes.UndefinedType) { + expr = new PlayScript.SimpleName ("undefined", loc).Resolve (ec); + return true; + } + ec.Report.Error (126, loc, "An object of a type convertible to `{0}' is required for the return statement", ec.ReturnType.GetSignatureForError ()); @@ -973,7 +978,7 @@ protected override bool DoResolve (BlockContext ec) return false; if (expr.Type != block_return_type && expr.Type != InternalType.ErrorType) { - expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc); + expr = Convert.ImplicitConversionRequiredEnhanced (ec, expr, block_return_type, loc); if (expr == null) { if (am != null && block_return_type == ec.ReturnType) { @@ -1475,6 +1480,12 @@ public virtual BlockVariableDeclarator Clone (CloneContext cloneCtx) return t; } + + public virtual TypeSpec ResolveType (BlockContext bc, TypeSpec type) + { + Variable.Type = type; + return type; + } } public class BlockVariable : Statement @@ -1492,9 +1503,10 @@ public BlockVariable (FullNamedExpression type, LocalVariable li) this.loc = type_expr.Location; } - protected BlockVariable (LocalVariable li) + protected BlockVariable (LocalVariable li, Location loc) { this.li = li; + this.loc = loc; } #region Properties @@ -1514,6 +1526,12 @@ public Expression Initializer { } } + public Location Location { + get { + return loc; + } + } + public FullNamedExpression TypeExpression { get { return type_expr; @@ -1606,13 +1624,14 @@ public bool Resolve (BlockContext bc, bool resolveDeclaratorInitializers) } if (type == null) { - type = type_expr.ResolveAsType (bc); + type = ResolveType (bc); if (type == null) return false; + } - if (li.IsConstant && !type.IsConstantCompatible) { - Const.Error_InvalidConstantType (type, loc, bc.Report); - } + + if (li.IsConstant && !type.IsConstantCompatible) { + Const.Error_InvalidConstantType (type, loc, bc.Report); } if (type.IsStatic) @@ -1635,7 +1654,8 @@ public bool Resolve (BlockContext bc, bool resolveDeclaratorInitializers) if (declarators != null) { foreach (var d in declarators) { - d.Variable.Type = li.Type; + d.ResolveType (bc, li.Type); + if (eval_global) { CreateEvaluatorVariable (bc, d.Variable); } else if (type != InternalType.ErrorType) { @@ -1645,7 +1665,7 @@ public bool Resolve (BlockContext bc, bool resolveDeclaratorInitializers) if (d.Initializer != null && resolveDeclaratorInitializers) { d.Initializer = ResolveInitializer (bc, d.Variable, d.Initializer); // d.Variable.DefinitelyAssigned - } + } } } @@ -1658,6 +1678,16 @@ protected virtual Expression ResolveInitializer (BlockContext bc, LocalVariable return a.ResolveStatement (bc); } + public virtual TypeSpec ResolveType (BlockContext bc) + { + type = TypeExpression.ResolveAsType (bc); + if (type == null) + return null; + + li.Type = type; + return type; + } + protected override void DoEmit (EmitContext ec) { li.CreateBuilder (ec); @@ -1761,6 +1791,7 @@ public enum Flags UsingVariable = 1 << 7, // DefinitelyAssigned = 1 << 8, IsLocked = 1 << 9, + GlobalScope = 1 << 10, ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable } @@ -1919,13 +1950,15 @@ public void CreateBuilder (EmitContext ec) ec.Report.Warning (219, 3, Location, "The variable `{0}' is assigned but its value is never used", Name); else ec.Report.Warning (168, 3, Location, "The variable `{0}' is declared but never used", Name); + + flags |= Flags.Used; } if (HoistedVariant != null) return; if (builder != null) { - if ((flags & Flags.CompilerGenerated) != 0) + if ((flags & (Flags.CompilerGenerated | Flags.GlobalScope)) != 0) return; // To avoid Used warning duplicates @@ -1949,8 +1982,19 @@ public static LocalVariable CreateCompilerGenerated (TypeSpec type, Block block, public Expression CreateReferenceExpression (ResolveContext rc, Location loc) { - if (IsConstant && const_value != null) - return Constant.CreateConstantFromValue (Type, const_value.GetValue (), loc); + if (IsConstant) { + if (const_value != null) + return Constant.CreateConstantFromValue (Type, const_value.GetValue (), loc); + + // + // Constant is still uninitializer need to get PS specific default value + // + if (rc.IsPlayScriptType) { + var expr = PlayScript.ImplicitVariableInitializer.GetConstantValue (rc, type, loc); + if (expr != null) + return expr; + } + } return new LocalVariableReference (this, loc); } @@ -3119,6 +3163,14 @@ public bool Resolve (FlowBranching parent, BlockContext rc, IMethodData md) if (md is StateMachineMethod) { unreachable = true; } else { + + if (rc.ReturnType == rc.Module.PlayscriptTypes.UndefinedType) { + var ret = new Return (null, EndLocation); + ret.Resolve (rc); + statements.Add (ret); + return true; + } + rc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ()); return false; } @@ -5362,7 +5414,7 @@ public class Catch : Statement LocalVariable li; FullNamedExpression type_expr; CompilerAssign assign; - TypeSpec type; + protected TypeSpec type; public Catch (Block block, Location loc) { @@ -5384,7 +5436,7 @@ public TypeSpec CatchType { } } - public bool IsGeneral { + public virtual bool IsGeneral { get { return type_expr == null; } @@ -5442,34 +5494,46 @@ protected override void DoEmit (EmitContext ec) public override bool Resolve (BlockContext ec) { using (ec.With (ResolveContext.Options.CatchScope, true)) { - if (type_expr != null) { - type = type_expr.ResolveAsType (ec); - if (type == null) - return false; + if (!ResolveType (ec)) + return false; - if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, ec.BuiltinTypes.Exception, false)) { - ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception"); - } else if (li != null) { - li.Type = type; - li.PrepareForFlowAnalysis (ec); + if (li != null) { + li.Type = type; + li.PrepareForFlowAnalysis (ec); - // source variable is at the top of the stack - Expression source = new EmptyExpression (li.Type); - if (li.Type.IsGenericParameter) - source = new UnboxCast (source, li.Type); + // source variable is at the top of the stack + Expression source = new EmptyExpression (li.Type); + if (li.Type.IsGenericParameter) + source = new UnboxCast (source, li.Type); - // - // Uses Location.Null to hide from symbol file - // - assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null); - Block.AddScopeStatement (new StatementExpression (assign, Location.Null)); - } - } + // + // Uses Location.Null to hide from symbol file + // + assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null); + Block.AddScopeStatement (new StatementExpression (assign, Location.Null)); + } return Block.Resolve (ec); } } + protected virtual bool ResolveType (BlockContext bc) + { + if (type_expr == null) + return true; + + type = type_expr.ResolveAsType (bc); + if (type == null) + return false; + + if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, bc.BuiltinTypes.Exception, false)) { + bc.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception"); + type = bc.Module.Compiler.BuiltinTypes.Exception; + } + + return true; + } + protected override void CloneTo (CloneContext clonectx, Statement t) { Catch target = (Catch) t; @@ -5619,6 +5683,12 @@ public override bool Resolve (BlockContext ec) continue; if (resolved_type == ct || TypeSpec.IsBaseClass (resolved_type, ct, true)) { + // + // All sort of weird things are allowed in PS + // + if (clauses[ii] is PlayScript.Catch) + continue; + ec.Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", ct.GetSignatureForError ()); @@ -5676,15 +5746,13 @@ public VariableDeclaration (FullNamedExpression type, LocalVariable li) } public VariableDeclaration (LocalVariable li, Location loc) - : base (li) + : base (li, loc) { - this.loc = loc; } public VariableDeclaration (Expression expr) - : base (null) + : base (null, expr.Location) { - loc = expr.Location; Initializer = expr; } @@ -5936,7 +6004,7 @@ public override object Accept (StructuralVisitor visitor) /// public class Foreach : Statement { - abstract class IteratorStatement : Statement + protected abstract class IteratorStatement : Statement { protected readonly Foreach for_each; @@ -6105,7 +6173,7 @@ protected override void DoEmit (EmitContext ec) } } - sealed class CollectionForeach : IteratorStatement, OverloadResolver.IErrorHandler + protected sealed class CollectionForeach : IteratorStatement, OverloadResolver.IErrorHandler { class RuntimeDispose : Using.VariableDeclaration { @@ -6147,6 +6215,7 @@ protected override Statement CreateDisposeCall (BlockContext bc, LocalVariable l } LocalVariable variable; + Expression variable_ref; Expression expr; Statement statement; ExpressionStatement init; @@ -6160,6 +6229,13 @@ public CollectionForeach (Foreach @foreach, LocalVariable var, Expression expr) this.expr = expr; } + public CollectionForeach (Foreach @foreach, LocalVariableReference variableReference, Expression expr) + : base (@foreach) + { + this.variable_ref = variableReference; + this.expr = expr; + } + void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator) { rc.Report.SymbolRelatedToPreviousError (enumerator); @@ -6290,7 +6366,7 @@ public override bool Resolve (BlockContext ec) } var get_enumerator = get_enumerator_mg.BestCandidate; - enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc); + enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, for_each.body, loc); enumerator_variable.Resolve (ec); // Prepare bool MoveNext () @@ -6311,37 +6387,39 @@ public override bool Resolve (BlockContext ec) if (current_pe == null) return false; - VarExpr ve = for_each.type as VarExpr; + if (variable != null) { + VarExpr ve = for_each.type as VarExpr; - if (ve != null) { - if (is_dynamic) { - // Source type is dynamic, set element type to dynamic too - variable.Type = ec.BuiltinTypes.Dynamic; + if (ve != null) { + if (is_dynamic) { + // Source type is dynamic, set element type to dynamic too + variable.Type = ec.BuiltinTypes.Dynamic; + } else { + // Infer implicitly typed local variable from foreach enumerable type + variable.Type = current_pe.Type; + } } else { - // Infer implicitly typed local variable from foreach enumerable type - variable.Type = current_pe.Type; - } - } else { - if (is_dynamic) { - // Explicit cast of dynamic collection elements has to be done at runtime - current_pe = EmptyCast.Create (current_pe, ec.BuiltinTypes.Dynamic); - } + if (is_dynamic) { + // Explicit cast of dynamic collection elements has to be done at runtime + current_pe = EmptyCast.Create (current_pe, ec.BuiltinTypes.Dynamic); + } - variable.Type = for_each.type.ResolveAsType (ec); + variable.Type = for_each.type.ResolveAsType (ec); - if (variable.Type == null) - return false; + if (variable.Type == null) + return false; - current_pe = Convert.ExplicitConversion (ec, current_pe, variable.Type, loc); - if (current_pe == null) + current_pe = Convert.ExplicitConversion (ec, current_pe, variable.Type, loc); + if (current_pe == null) + return false; + } + + variable_ref = new LocalVariableReference (variable, loc).Resolve (ec); + if (variable_ref == null) return false; } - var variable_ref = new LocalVariableReference (variable, loc).Resolve (ec); - if (variable_ref == null) - return false; - - for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, current_pe, Location.Null), for_each.type.Location)); + for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, current_pe, Location.Null), Location.Null)); var init = new Invocation (get_enumerator_mg, null); @@ -6422,11 +6500,11 @@ bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, Memb #endregion } - Expression type; - LocalVariable variable; - Expression expr; - Statement statement; - Block body; + protected Expression type; + protected LocalVariable variable; + protected Expression expr; + protected Statement statement; + protected Block body; public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Block body, Location l) { @@ -6493,7 +6571,8 @@ protected override void DoEmit (EmitContext ec) if (!(statement is Block)) ec.BeginCompilerScope (); - variable.CreateBuilder (ec); + if (variable != null) + variable.CreateBuilder (ec); statement.Emit (ec); diff --git a/mcs/mcs/typemanager.cs b/mcs/mcs/typemanager.cs index 870b7be2a75..266944d290e 100644 --- a/mcs/mcs/typemanager.cs +++ b/mcs/mcs/typemanager.cs @@ -220,6 +220,7 @@ class PredefinedTypes public readonly PredefinedType CallSite; public readonly PredefinedType CallSiteGeneric; public readonly PredefinedType BinderFlags; + public readonly PredefinedType ExpressionType; // // C# 5.0 @@ -276,6 +277,7 @@ public PredefinedTypes (ModuleContainer module) CallSiteGeneric = new PredefinedType (module, MemberKind.Class, "System.Runtime.CompilerServices", "CallSite", 1); Binder = new PredefinedType (module, MemberKind.Class, "Microsoft.CSharp.RuntimeBinder", "Binder"); BinderFlags = new PredefinedType (module, MemberKind.Enum, "Microsoft.CSharp.RuntimeBinder", "CSharpBinderFlags"); + ExpressionType = new PredefinedType (module, MemberKind.Enum, "System.Linq.Expressions", "ExpressionType"); Action = new PredefinedType (module, MemberKind.Delegate, "System", "Action"); AsyncVoidMethodBuilder = new PredefinedType (module, MemberKind.Struct, "System.Runtime.CompilerServices", "AsyncVoidMethodBuilder"); @@ -318,6 +320,8 @@ public PredefinedTypes (ModuleContainer module) if (ExpressionGeneric.Define ()) ExpressionGeneric.TypeSpec.IsExpressionTreeType = true; + ExpressionType.Define (); + Task.Define (); if (TaskGeneric.Define ()) TaskGeneric.TypeSpec.IsGenericTask = true; diff --git a/mcs/mcs/typespec.cs b/mcs/mcs/typespec.cs index a36033926bd..aafa1ae768d 100644 --- a/mcs/mcs/typespec.cs +++ b/mcs/mcs/typespec.cs @@ -190,6 +190,15 @@ public bool IsDelegate { } } + // + // Only used by PlayScript dynamic classes + // + public bool IsDynamicClass { + get { + return (Modifiers & Modifiers.DYNAMIC) != 0; + } + } + // // Returns true for instances of Expression // @@ -647,7 +656,7 @@ public static bool IsReferenceType (TypeSpec t) // // Null is considered to be a reference type // - return t == InternalType.NullLiteral || t.BuiltinType == BuiltinTypeSpec.Type.Dynamic; + return t == InternalType.NullLiteral || t.BuiltinType == BuiltinTypeSpec.Type.Dynamic || t.BuiltinType == BuiltinTypeSpec.Type.Object; default: return true; } @@ -942,10 +951,10 @@ public override string GetSignatureForError () switch (Name) { case "Int32": return "int"; case "Int64": return "long"; - case "String": return "string"; + case "String": return ns.Length == 0 ? name : "string"; case "Boolean": return "bool"; case "Void": return "void"; - case "Object": return "object"; + case "Object": return ns.Length == 0 ? name : "object"; case "UInt32": return "uint"; case "Int16": return "short"; case "UInt16": return "ushort"; @@ -1413,6 +1422,7 @@ public interface ITypeDefinition : IMemberDefinition bool IsPartial { get; } bool IsComImport { get; } bool IsTypeForwarder { get; } + bool IsPlayScriptType { get; } int TypeParametersCount { get; } TypeParameterSpec[] TypeParameters { get; } @@ -1478,6 +1488,12 @@ bool ITypeDefinition.IsPartial { } } + bool ITypeDefinition.IsPlayScriptType { + get { + return false; + } + } + bool ITypeDefinition.IsTypeForwarder { get { return false; @@ -1614,6 +1630,12 @@ bool ITypeDefinition.IsTypeForwarder { } } + bool ITypeDefinition.IsPlayScriptType { + get { + return false; + } + } + public override string Name { get { throw new NotSupportedException (); diff --git a/mcs/tests/Makefile b/mcs/tests/Makefile index b0a932eb4f9..a9d9c112017 100644 --- a/mcs/tests/Makefile +++ b/mcs/tests/Makefile @@ -68,6 +68,9 @@ qcheck2: gen-mt-tests: $(TESTER) -mode:nunit -files:'v2' -compiler:$(COMPILER) -issues:known-issues-mt -compiler-options:"-lib:$(topdir)/class/lib/monotouch projects/MonoTouch/ivt.cs" +playscript: + $(TESTER) -mode:pos -files:'*-???.play' -compiler:$(COMPILER) -issues:known-issues-$(PROFILE) -log:$(PROFILE).log -il:ver-il-$(PROFILE).xml $(DEFINES) $(TOPTIONS) + test-local: @: diff --git a/mcs/tests/test-ps-001.play b/mcs/tests/test-ps-001.play new file mode 100644 index 00000000000..81e30188160 --- /dev/null +++ b/mcs/tests/test-ps-001.play @@ -0,0 +1,10 @@ +package +{ + public class HelloWorld + { + public static function Main():void + { + trace ("Hello World!"); + } + } +} diff --git a/mcs/tests/test-ps-002-2.play b/mcs/tests/test-ps-002-2.play new file mode 100644 index 00000000000..50960c0d6cd --- /dev/null +++ b/mcs/tests/test-ps-002-2.play @@ -0,0 +1,6 @@ +package { + public function testFunction (obj:*, cl:Class):Boolean + { + return false; + } +} diff --git a/mcs/tests/test-ps-002.play b/mcs/tests/test-ps-002.play new file mode 100644 index 00000000000..f8bc1d123e3 --- /dev/null +++ b/mcs/tests/test-ps-002.play @@ -0,0 +1,13 @@ +// Compiler options: test-ps-002-2.play + +package +{ + public class Test + { + public static function Main():int + { + testFunction ("arg", null); + return 0; + } + } +} diff --git a/mcs/tests/test-ps-003.play b/mcs/tests/test-ps-003.play new file mode 100644 index 00000000000..3a8f2ba24b8 --- /dev/null +++ b/mcs/tests/test-ps-003.play @@ -0,0 +1,24 @@ +package +{ + public class BasicTypes + { + var f_obj:Object = null; + var f_str:String = "string"; + var f_n:Number = 9.3; + var f_i:int = -3; + var f_ui:uint = 44; + var f_b:Boolean = true; + var f_any:* = 9; + + public static function Main():void + { + var obj:Object = null; + var str1:String = "string"; + var n:Number = 9.3; + var i:int = -3; + var ui:uint = 44; + var b:Boolean = true; + var any:* = null; + } + } +} diff --git a/mcs/tests/test-ps-004.play b/mcs/tests/test-ps-004.play new file mode 100644 index 00000000000..88877db94cb --- /dev/null +++ b/mcs/tests/test-ps-004.play @@ -0,0 +1,33 @@ +package +{ + public function Main():int + { + var a:BaseClass = new TestClass (); + if (a.p != 15) + return 1; + + a = new BaseClass (); + if (a.p != 3) + return 2; + + return 0; + } +} + +class BaseClass +{ + public var p:int; + + function BaseClass () + { + p = 3; + } +} + +class TestClass extends BaseClass +{ + function TestClass () + { + p *= 5; + } +} \ No newline at end of file diff --git a/mcs/tests/test-ps-005.play b/mcs/tests/test-ps-005.play new file mode 100644 index 00000000000..74e8a9b2d5d --- /dev/null +++ b/mcs/tests/test-ps-005.play @@ -0,0 +1,18 @@ +package +{ + internal class test + { + public static function Main():int + { + if (max (4, 30) != 30) + return 1; + + return 0; + } + + internal static function max (n1:Number, n2:Number): Number + { + return System.Math.Max (n1, n2); + } + } +} diff --git a/mcs/tests/test-ps-006-2.play b/mcs/tests/test-ps-006-2.play new file mode 100644 index 00000000000..d8cac884bd7 --- /dev/null +++ b/mcs/tests/test-ps-006-2.play @@ -0,0 +1,20 @@ +package +{ + public dynamic class TestClass + { + public function TestClass() + { + } + + private var ui:uint; + + internal function get Prop():uint { + return ui; + } + + internal function set Prop(value:uint):void { + ui = value; + } + + } +} diff --git a/mcs/tests/test-ps-006.play b/mcs/tests/test-ps-006.play new file mode 100644 index 00000000000..b65711b9110 --- /dev/null +++ b/mcs/tests/test-ps-006.play @@ -0,0 +1,39 @@ +// Compiler options: test-ps-006-2.play + +package +{ + public class test + { + public static function Main():int + { + //Prop = 3; + //if (Prop != 3) + // return 1; + + var m:TestClass = new TestClass (); + m.Prop = 300; + if (m.Prop != 300) + return 2; + + m["Prop"] = 500; + if (m.Prop != 500) + return 3; + + if (m["Prop"] != 500) + return 4; + + return 0; + } + } +} +/* +var n:Number = 4; + +function get Prop():Number { + return n; +} + +function set Prop(value:Number):void { + n = value; +} +*/ diff --git a/mcs/tests/test-ps-007.play b/mcs/tests/test-ps-007.play new file mode 100644 index 00000000000..0bd724c56aa --- /dev/null +++ b/mcs/tests/test-ps-007.play @@ -0,0 +1,21 @@ +package +{ + public dynamic class test + { + public static function Main():int + { + var dynamic:int = 0; + + return 0; + } + + private function foo():void + { + dynamic (9); + } + + private function dynamic(dynamic:int):void + { + } + } +} diff --git a/mcs/tests/test-ps-008.play b/mcs/tests/test-ps-008.play new file mode 100644 index 00000000000..158293edbc6 --- /dev/null +++ b/mcs/tests/test-ps-008.play @@ -0,0 +1,59 @@ +package +{ + public dynamic class test + { + public static function Main():int + { + var res:int; + res = Local (); + if (res != 0) + return res + 10; + + res = Imported (); + if (res != 0) + return res + 20; + + return 0; + } + + static function Local ():int + { + var m:test = new test (); + m["Prop"] = 500; + if (m.Prop != 500) + return 1; + + if (m["Prop"] != 500) + return 2; + + if (m.Prop != 500) + return 3; + + m.Prop = 300; + if (m.Prop != 300) + return 4; + + return 0; + } + + static function Imported ():int + { + var m:Array = new Array (); + m["Prop"] = 500; + if (m.Prop != 500) + return 1; + + if (m["Prop"] != 500) + return 2; + + if (m.Prop != 500) + return 3; + + m.Prop = 300; + if (m.Prop != 300) + return 4; + + return 0; + } + } +} diff --git a/mcs/tests/test-ps-009-2.play b/mcs/tests/test-ps-009-2.play new file mode 100644 index 00000000000..381ff26afd3 --- /dev/null +++ b/mcs/tests/test-ps-009-2.play @@ -0,0 +1,14 @@ +package +{ + public class base + { + public function base() + { + } + + public virtual function F1 () : String + { + return "a"; + } + } +} diff --git a/mcs/tests/test-ps-009.play b/mcs/tests/test-ps-009.play new file mode 100644 index 00000000000..c922d227b87 --- /dev/null +++ b/mcs/tests/test-ps-009.play @@ -0,0 +1,21 @@ +// Compiler options: test-ps-009-2.play + +package +{ + public class inheritance extends base + { + public static function Main():int + { + var b:base = new inheritance (); + if (b.F1 () != "b") + return 1; + + return 0; + } + + public override function F1 () : String + { + return "b"; + } + } +} diff --git a/mcs/tests/test-ps-010.play b/mcs/tests/test-ps-010.play new file mode 100644 index 00000000000..f8455358c0c --- /dev/null +++ b/mcs/tests/test-ps-010.play @@ -0,0 +1,60 @@ +package +{ + public class conversions + { + static function NumberToInt():int + { + var d:Number = 4; + var i:int; + + i = d; + if (i != 4) + return 1; + + d = uint.MaxValue; + i = d; + if (i != -1) + return 2; + + d = int.MinValue; + i = d; + if (i != -2147483648) + return 3; + + d = NaN; + i = d; + if (i != 0) + return 4; + + return 0; + } + + static function IntToUInt ():int + { + var i:int = -1; + var u:uint = i; + if (u != 4294967295) + return 1; + + i = u - 1; + if (i != -2) + return 2; + + return 0; + } + + public static function Main():int + { + var res:int; + res = IntToUInt (); + if (res != 0) + return res + 10; + + res = NumberToInt (); + if (res != 0) + return res + 20; + + return 0; + } + } +} diff --git a/mcs/tests/test-ps-011.play b/mcs/tests/test-ps-011.play new file mode 100644 index 00000000000..5fa48df608a --- /dev/null +++ b/mcs/tests/test-ps-011.play @@ -0,0 +1,48 @@ +package +{ + public class TestClass extends BaseClass + { + internal var local:Number = 4.5; + + public function TestClass(a:uint, b:String):* + { + var b_ui:uint = ui; + var b_s:* = s; + var b_local:Number = local; + + super (a, b + "X"); + + if (b_ui != 0) + throw new ArgumentError ("1"); + + if (b_local != 4.5) + throw new ArgumentError ("2"); + + if (b_s != null) + throw new ArgumentError ("3"); + + if (ui != a) + throw new ArgumentError ("4"); + + if (s != b + "X") + throw new ArgumentError ("5"); + } + + public static function Main ():void + { + new TestClass (1, null); + } + } + + public class BaseClass + { + public var ui:uint = 9; + public var s:String; + + public function BaseClass(a:uint, b:String) + { + ui = a; + s = b; + } + } +} \ No newline at end of file diff --git a/mcs/tests/test-ps-012.play b/mcs/tests/test-ps-012.play new file mode 100644 index 00000000000..79003eac13e --- /dev/null +++ b/mcs/tests/test-ps-012.play @@ -0,0 +1,19 @@ +package +{ + public class ArrayInitialization + { + public static function Main ():int + { + var a:Object = []; + if (!(a is Array)) + return 1; + + var b:* = ["1", "2", "3" ]; + if (!(b is Array)) + return 2; + + return 0; + } + } + +} \ No newline at end of file diff --git a/mcs/tests/test-ps-013.play b/mcs/tests/test-ps-013.play new file mode 100644 index 00000000000..555a742bc79 --- /dev/null +++ b/mcs/tests/test-ps-013.play @@ -0,0 +1,29 @@ +package +{ + public class TestVector + { + public static function Main ():int + { + var v1:* = new [9, 0]; + if (!(v1 is Vector.)) + return 1; + if (v1.length != 2) + return 2; + + var v2:Vector. = new []; + if (!(v2 is Vector.)) + return 3; + if (v2.length != 0) + return 4; + + var v3:Object = new [0.0, 0.1,]; + if (!(v3 is Vector.)) + return 5; + if (v3.length != 2) + return 6; + + return 0; + } + } + +} \ No newline at end of file diff --git a/mcs/tests/test-ps-014.play b/mcs/tests/test-ps-014.play new file mode 100644 index 00000000000..f056e3af63f --- /dev/null +++ b/mcs/tests/test-ps-014.play @@ -0,0 +1,90 @@ +package +{ + public class BinaryOperations + { + static function MixedTypes ():int + { + var a:Object = 400; + if (a != 400) + return 1; + + if (400 != a) + return 2; + + return 0; + } + + static function StrictEquality ():int + { + var i:int = 4; + var i2:int = 4; + + if (!(i == i2)) + return 1; + if (!(i === i2)) + return 2; + + var s:String = "x"; + var s2:String = "x"; + + if (!(s == s2)) + return 3; + if (!(s === s2)) + return 4; + + var d:Number = 2.0; + var di2:int = 2; + + if (!(d == di2)) + return 5; + + var o:Object = new Object (); + var o2:Object = new Object (); + if (o == o2) + return 6; + if (o === o2) + return 7; + + var o3:Object = 6; + var o4:Object = 6; + if (!(o3 == o4)) + return 8; + if (!(o3 === o4)) + return 9; + + var os:Object = "oo"; + var os2:Object = "oo"; + if (!(os == os2)) + return 10; + if (!(os === os2)) + return 11; + + + // Untyped + var ou1 = 6; + var ou2:Object = 6; + if (!(ou1 == ou2)) + return 20; + if (!(ou1 === ou2)) + return 21; + + return 0; + } + + public static function Main ():int + { + var r:int; + r = MixedTypes (); + if (r != 0) + return r + 100; + + r = StrictEquality (); + if (r != 0) + return r + 200; + + trace ("ok"); + return 0; + } + } + +} \ No newline at end of file diff --git a/mcs/tests/test-ps-015.play b/mcs/tests/test-ps-015.play new file mode 100644 index 00000000000..97aa0de8390 --- /dev/null +++ b/mcs/tests/test-ps-015.play @@ -0,0 +1,38 @@ +package +{ + public class TestClass + { + public static function Main ():int + { + if (test1 () != 0) + return 1; + + if (test1 (1, "2", 3.0) != 3) + return 2; + + if (test1(null) != 1) + return 3; + + if (test1(new Array ()) != 1) + return 4; + + test2(); + + trace ("ok"); + return 0; + } + + public static function test1 (...rest) : int + { + if (!(rest is Array)) + throw new ArgumentError ("Argument is not an array"); + + return rest.length; + } + + public static function test2 (...rest:Array) : void + { + } + } + +} \ No newline at end of file diff --git a/mcs/tests/test-ps-016.play b/mcs/tests/test-ps-016.play new file mode 100644 index 00000000000..b51654d017d --- /dev/null +++ b/mcs/tests/test-ps-016.play @@ -0,0 +1,19 @@ +package +{ + public class ObjectInitializer + { + public static function Main ():int + { + var o:Object = { type:"Flat Panel", resolution:"1600x1200", value:3, value:5 }; + if (o.value != 3) + return 1; + + if (o.type != "Flat Panel") + return 2; + + var o2:* = { }; + + return 0; + } + } +} \ No newline at end of file diff --git a/mcs/tests/test-ps-017.play b/mcs/tests/test-ps-017.play new file mode 100644 index 00000000000..328c2d2f501 --- /dev/null +++ b/mcs/tests/test-ps-017.play @@ -0,0 +1,20 @@ +package +{ + public class NewExpression + { + public static function Main ():int + { + var o:Object = new Object (); + if (o == null) + return 1; + + o = new NewExpression; + o = new Object; + o = new int (); + o = new int; + o = new Array (new Object); + + return 0; + } + } +} \ No newline at end of file diff --git a/mcs/tests/test-ps-018.play b/mcs/tests/test-ps-018.play new file mode 100644 index 00000000000..c8433893afd --- /dev/null +++ b/mcs/tests/test-ps-018.play @@ -0,0 +1,86 @@ +package +{ + public const cg1:Object = new Object (); + internal const cg2:int = -9; + + public class ConstantFields + { + public static const cs1:Object = new Object (); + public static const cs2:* = undefined; + internal static const cs3:Object = 8; + public static const cs4:Array = [1, 2, 3]; + public static const cs5:int = 2, cs6:uint = 7; + public static const cs8:int = vs8; + private static const cs9:String; + public static const cs10:Number; + static const cs11; + + static var vs8:int = 8; + + public const c1:Object = cs1; + public const c2:* = undefined; + public const c3:Object = null; + public const c4:Array = [5]; + public const c5:int = 20, c6:uint = 70; + public const c8:int = v8; + private const c9:String; + const c11; + + static var v8:int = 8; + + public static function Main ():int + { + if (cg1 == null) + return 1; + if (cg2 != -9) + return 2; + + if (cs1 == null) + return 10; + if (cs3 != 8) + return 11; + if (cs4.length != 3) + return 12; + if (cs5 != 2) + return 13; + if (cs6 != 7) + return 14; + + vs8 = 80; + if (cs8 != 80) + return 15; + if (cs9 != null) + return 16; + if (!isNaN (cs10)) + return 17; + + var c = new ConstantFields (); + if (c.c1 == null) + return 20; + if (c.c3 != null) + return 21; + if (c.c4.length != 1) + return 22; + if (c.c5 != 20) + return 23; + if (c.c6 != 70) + return 24; + if (c.c8 != 8) + return 25; + if (c.c9 != null) + return 25; + + if (c.MM () != 40) + return 30; + + trace ("ok"); + + return 0; + } + + function MM (arg1:int = cs5, arg2:int = c5):int + { + return arg1 * arg2; + } + } +} \ No newline at end of file diff --git a/mcs/tests/test-ps-019.play b/mcs/tests/test-ps-019.play new file mode 100644 index 00000000000..b52754fb84a --- /dev/null +++ b/mcs/tests/test-ps-019.play @@ -0,0 +1,57 @@ +package +{ + public class TypeofExpression + { + public static function Main ():int + { + if (typeof "s" != "string") + return 1; + + if (typeof 1 != "number") + return 2; + + if (typeof -9.3 != "number") + return 3; + + var ui:uint = 9; + if (typeof ui != "number") + return 4; + + if (typeof true != "boolean") + return 5; + + if (typeof XML != "object") + return 6; + + var x:Object = ; + if (typeof x != "xml") + return 7; + + x = 2; + + if (typeof x != "xml") + return 8; + +// var u:* = undefined; + +// if (typeof u != "undefined") +// return 9; + +// if (typeof undefined != "undefined") +// return 10; + +// var uo:Object = u; +// if (typeof uo != "object") +// return 11; + + if (typeof null != "object") + return 12; + + if (typeof Infinity != "number") + return 14; + + trace ("ok"); + return 0; + } + } +} \ No newline at end of file diff --git a/mcs/tests/test-ps-020.play b/mcs/tests/test-ps-020.play new file mode 100644 index 00000000000..15e0eb40302 --- /dev/null +++ b/mcs/tests/test-ps-020.play @@ -0,0 +1,60 @@ +package +{ + public class InOperator + { + public static function Main ():int + { + if (!("PI" in Math)) + return 1; + + var o:Object = "PI"; + if (!(o in Math)) + return 2; + + o = Math; + if (!("PI" in o)) + return 21; + + if ("test" in Main) + return 3; + + if ("PropI" in TestClass) + return 4; + + if (!("PropI" in new TestClass ())) + return 5; + + if ("PropS" in new TestClass ()) + return 6; + + if (!("PropS" in TestClass)) + return 7; + + if ("PropS2" in TestClass) + return 8; + + var a_i:Object = [1, 4]; + var o_i:Object = -0; + if (!(o_i in a_i)) + return 20; + + if (3 in a_i) + return 21; + + trace ("ok"); + return 0; + } + } + + public class TestClass + { + public static function set PropS(value:Number):void { + } + + protected static function set PropS2(value:Number):void { + } + + public function set PropI(value:Number):void { + } + } +} \ No newline at end of file diff --git a/mcs/tests/test-ps-021.play b/mcs/tests/test-ps-021.play new file mode 100644 index 00000000000..89482bc47f7 --- /dev/null +++ b/mcs/tests/test-ps-021.play @@ -0,0 +1,77 @@ +package +{ + public class DeleteOperator + { + static var s:int; + + public static function Main ():int + { + var account:Object = new Object(); + + if (!(delete account.name)) + return 1; + + account.name = "Jon"; + + if (!(delete account.name)) + return 2; + +// if (account.name != undefined) +// return 3; + + var tc:TestClass = new TestClass (); + + if (delete tc.PropI) + return 10; + + if (!delete Foo ()) + return 11; + + if (s != 1) + return 12; + + delete 5; + + var my_array:Array = new Array(); + my_array[0] = "a"; + my_array["1"] = "b"; + my_array[2] = "c"; + + if (!(delete my_array[2])) + return 20; + + if (my_array.length != 3) + return 21; + + if (!(delete my_array[2])) + return 22; + + if (!(delete my_array[-2])) + return 23; + + if (my_array.length != 3) + return 24; + + trace ("ok"); + return 0; + } + + private static function Foo ():void + { + s++; + } + } + + public dynamic class TestClass + { + public static function set PropS(value:Number):void { + } + + protected static function set PropS2(value:Number):void { + } + + public function get PropI():Number { + return 4; + } + } +} \ No newline at end of file diff --git a/mcs/tests/test-ps-022.play b/mcs/tests/test-ps-022.play new file mode 100644 index 00000000000..db2f03fea23 --- /dev/null +++ b/mcs/tests/test-ps-022.play @@ -0,0 +1,30 @@ +package +{ + public class NamespaceDeclarationTest + { + public namespace French = "f"; + internal namespace Hawaiian; + private namespace Latin = "text/hoo"; + private namespace French2 = French; + Latin namespace Nested = ""; + + Hawaiian function hello():String { + return "aloha"; + } + + French var v:Object; + French const c:Object = null; + + public static function Main():int + { + if (Latin.uri != "text/hoo") + return 1; + + if (French2.uri != "f") + return 2; + + return 0; + } + } +} + diff --git a/mcs/tests/test-ps-023.play b/mcs/tests/test-ps-023.play new file mode 100644 index 00000000000..881052a73fa --- /dev/null +++ b/mcs/tests/test-ps-023.play @@ -0,0 +1,40 @@ +package +{ + namespace nsp; + + public class UseNamespaceTest + { + private namespace Test; + private namespace Test2; + + nsp var field:String = "namespace field"; + + Test static function Foo ():int + { + trace (1); + return 1; + } + + Test2 static function Foo ():int + { + trace (2); + return 2; + } + + public static function Main():int + { + if (Test::Foo () != 1) + return 1; + + if (Test2::Foo () != 2) + return 2; + + var unt:UseNamespaceTest = new UseNamespaceTest (); + if (unt.nsp::field != "namespace field") + return 3; + + return 0; + } + } +} + diff --git a/mcs/tests/test-ps-024.play b/mcs/tests/test-ps-024.play new file mode 100644 index 00000000000..89f6788d962 --- /dev/null +++ b/mcs/tests/test-ps-024.play @@ -0,0 +1,39 @@ +package +{ + public class ForStatementTest + { + public static function Main():int + { + var my_array:Array = new Array (); + for (var i:int = 0; i < 5; i++) { + my_array[i] = (i + 5) * 10; + } + + if (my_array [4] != 90) + return 1; + + for (var i1:Number = 0, i2:uint; i1 < 2; i1++) { + trace (i2); + } + + var mn:Number; + for (mn = -3; mn < 5; mn++) { + trace (mn); + } + + if (mn != 5) + return 2; + + for (1 + 1; false; ) { + } + + for (var i, j, k; i < 2; i++) { + trace (i, j, k); + throw new Error ("Should not be reached"); + } + + return 0; + } + } +} + diff --git a/mcs/tests/test-ps-025.play b/mcs/tests/test-ps-025.play new file mode 100644 index 00000000000..cd4685ec553 --- /dev/null +++ b/mcs/tests/test-ps-025.play @@ -0,0 +1,47 @@ +package +{ + public class ForInStatementTest + { + public static function Main():int + { + var myObject:Object = { + firstName:"Tara", + age:27, + city:"San Francisco" + }; + + var counter:int = 0; + for (var prop in myObject) { + counter++; + } + + if (counter != 3) + return 1; + + var s:String; + var k2:Array = [ 1, 2, 3 ]; + for (var p in k2) { + s += p; + } + + if (s != "012") + return 2; + + var local:Object; + for (local in myObject) { + } + + if (local == null) + return 3; + + for (var prop2 = null in myObject) { + } + + for (local in 1) { + } + + return 0; + } + } +} + diff --git a/mcs/tests/test-ps-026.play b/mcs/tests/test-ps-026.play new file mode 100644 index 00000000000..462a7a966bf --- /dev/null +++ b/mcs/tests/test-ps-026.play @@ -0,0 +1,53 @@ +package +{ + public class ForeEachTest + { + public static function Main():int + { + var myObject:Object = { + firstName:"Tara", + age:27, + city:"San Francisco" + }; + + var counter:int = 0; + for each (var prop in myObject) { + if (prop is Number) { + if (prop != 27) + return 1; + } + + counter++; + } + + if (counter != 3) + return 2; + + var s:int = 0; + var k2:Array = [ 1, 2, 3 ]; + for each (var p in k2) { + s += p; + } + + if (s != 6) + return 3; + + var each:Object; + for each (each in myObject) { + } + + if (each == null) + return 4; + + for + each (var prop2 = null in myObject) { + } + + for each (each in 2) { + } + + return 0; + } + } +} + diff --git a/mcs/tests/test-ps-027.play b/mcs/tests/test-ps-027.play new file mode 100644 index 00000000000..f8c02b0e598 --- /dev/null +++ b/mcs/tests/test-ps-027.play @@ -0,0 +1,21 @@ +package +{ + public class OptionalSemicolonsTest + { + public var x:String + public const xg:int = 0 + + public function get F2 (): int + { + return 1; + }; + + public static function Main():void + { + }; + }; + + internal interface Test + { + }; +}; diff --git a/mcs/tests/test-ps-028.play b/mcs/tests/test-ps-028.play new file mode 100644 index 00000000000..e9edce67cfd --- /dev/null +++ b/mcs/tests/test-ps-028.play @@ -0,0 +1,47 @@ +package +{ + public class OverrideTest extends BaseClass + { + public override function run():String + { + return super.run () + "-Main"; + } + + public override function get Prop():int + { + return super.Prop + 40; + } + + public static function Main():int + { + var v:OverrideTest = new OverrideTest (); + if (v.run () != "Base-Main") + return 1; + + if (v.Prop != 44) + return 2; + + var v2:* = new OverrideTest (); + // TODO: broken virtual lookup, v2:BaseClass fails too + //if (v2.run () != "Base-Main") + // return 3; + + trace ("ok"); + return 0; + } + } + + public class BaseClass + { + public function run():String + { + return "Base"; + } + + public function get Prop():int + { + return 4; + } + } +} + diff --git a/mcs/tests/test-ps-029.play b/mcs/tests/test-ps-029.play new file mode 100644 index 00000000000..64a66f62ba2 --- /dev/null +++ b/mcs/tests/test-ps-029.play @@ -0,0 +1,52 @@ +package +{ + public class UntypedReturnTypeTest + { + public static function F1 () + { + } + + public static function F2 (arg:int) + { + if (arg > 0) + return 1; + + return; + } + + public static function F3 (arg:int) + { + if (arg > 0) + return 1; + } + + public static function F4 (arg:int):* + { + if (arg > 0) + return 1; + } + + public static function Main():int + { + F1 (); + if (F2 (0) != undefined) + return 1; + if (F2 (1) != 1) + return 2; + + if (F3 (0) != undefined) + return 3; + if (F3 (1) != 1) + return 4; + + if (F4 (0) != undefined) + return 5; + if (F4 (1) != 1) + return 6; + + trace ("ok"); + return 0; + } + } +} + diff --git a/mcs/tests/test-ps-030.play b/mcs/tests/test-ps-030.play new file mode 100644 index 00000000000..0a088f00d44 --- /dev/null +++ b/mcs/tests/test-ps-030.play @@ -0,0 +1,96 @@ +package +{ + public class LocalFunctionTest + { + public static function F1 ():int + { + var n:Number = sqr (3); + if (n != 9) + return 1; + + function sqr (xNum:Number):Number { + return Math.pow(xNum, 2); + }; + + return 0; + } + + public static function F2 ():int + { + var sqr:Function = function(xNum:Number):Number { + return Math.pow (xNum, 2); + }; + + if (sqr (4) != 16) + return 1; + + if (sqr.call (null, 4) != 16) + return 2; + + var sqr2 = function(xNum:Number) { + return xNum + 3; + }; + + if (sqr2 (2) != 5) + return 3; + + var lstr:String; + var sfunc:Function = function(str:String):void { + lstr = str; + }; + + sfunc ("test"); + if (lstr != "test") + return 4; + + return 0; + } + + public static function F3 ():int + { + var f:Function = function (xNum:Number):Number { + return Math.pow(xNum, 2); + }; + + f = function (s:String, b:Boolean):int { + return 5; + }; + + if (f (null, false) != 5) + return 1; + + return 0; + } + + public static function F4 ():int + { + var f:Function = function ():Number { + return 1; + }; + + if (f () != 1) + return 1; + + return 0; + } + + public static function Main():int + { + if (F1 () != 0) + return 2; + + if (F2 () != 0) + return 2; + + if (F3 () != 0) + return 3; + + if (F4 () != 0) + return 4; + + trace ("ok"); + return 0; + } + } +} + diff --git a/mcs/tests/test-ps-031.play b/mcs/tests/test-ps-031.play new file mode 100644 index 00000000000..d7feab9d560 --- /dev/null +++ b/mcs/tests/test-ps-031.play @@ -0,0 +1,31 @@ +package +{ + public class InterfaceTest implements Interface + { + public function M1():String + { + return null; + } + + public function get P1():int + { + return 2; + } + + public static function Main():int + { + var i:InterfaceTest = new InterfaceTest (); + i.M1 (); + trace (i.P1); + + return 0; + } + } + + public interface Interface + { + function M1():String; + function get P1():int; + } +} + diff --git a/mcs/tests/test-ps-032.play b/mcs/tests/test-ps-032.play new file mode 100644 index 00000000000..7ed6289da72 --- /dev/null +++ b/mcs/tests/test-ps-032.play @@ -0,0 +1,42 @@ +package +{ + public class ExpressionConstructorTest + { + public static function Main():int + { + var classToConstruct:Class; + var classToConstructObject:Object; + var classInstance:Object; + + classToConstruct = ClassA; + classInstance = new classToConstruct (6); + if (!(classInstance is ClassA)) + return 1; + + classToConstruct = ClassB; + classInstance = new classToConstruct (); + if (!(classInstance is ClassB)) + return 2; + + classToConstructObject = classToConstruct; + classInstance = new classToConstructObject (); + if (!(classInstance is ClassB)) + return 3; + + return 0; + } + } + + public class ClassA + { + public function ClassA (arg:int):void + { + + } + } + + public class ClassB + { + } +} + diff --git a/mcs/tests/test-ps-033.play b/mcs/tests/test-ps-033.play new file mode 100644 index 00000000000..2b5790af907 --- /dev/null +++ b/mcs/tests/test-ps-033.play @@ -0,0 +1,46 @@ +package +{ + public class WithStatementTest + { + public static function cos ():int + { + return 0; + } + + public static function Main():int + { + var r:Number = 0.3; + var a:Number, x:Number; + var PI:Number = 99; + with (Math) { + a = PI; + x = r * cos(PI); + } + + if (a != 3.141592653589793) + return 1; + + if (PI != 99) + return 2; + + if (x != -0.3) + return 3; + + with ("abcd") { + if (charAt (2) != 'c') + return 4; + } + + var o:Object = "XyZ"; + var res:Object; + with (o) { + // TODO: Extension methods lookup in runtime context + //if (toLowerCase () != "xyz") + // return 5; + } + + return 0; + } + } +} + diff --git a/mcs/tests/test-ps-034.play b/mcs/tests/test-ps-034.play new file mode 100644 index 00000000000..25f2695f987 --- /dev/null +++ b/mcs/tests/test-ps-034.play @@ -0,0 +1,251 @@ +package +{ + public class UninitializedValuesTest + { + static function Test1 ():int + { + var v1:Boolean; + if (v1 != false) + return 1; + + var v2:int; + if (v2 != 0) + return 2; + + var v3:Number; + if (!isNaN (v3)) + return 3; + + var v4:String; + if (v4 != null) + return 4; + + var v5:*; + if (v5 != undefined) + return 5; + + var v6; + if (v6 != undefined) + return 6; + + return 0; + } + + static function Test2 ():int + { + var v1:Boolean; + if (v1 != false) + return 1; + + v1 = true; + if (v1 != true) + return 2; + + var v2:int; + if (v2 != 0) + return 3; + + v2 = 2; + if (v2 != 2) + return 4; + + var v3:Number; + if (!isNaN (v3)) + return 5; + + v3 = 5; + if (v3 != 5) + return 6; + + var v4:String; + if (v4 != null) + return 7; + + v4 = "s"; + if (v4 != "s") + return 8; + + var v5:*; + if (v5 != undefined) + return 9; + + v5 = null; + if (v5 != null) + return 10; + + return 0; + } + + static function Test3 ():int + { + if (v1 != false) + return 1; + + if (v2 != 0) + return 2; + + if (!isNaN (v3)) + return 3; + + if (v4 != null) + return 4; + + if (v5 != undefined) + return 5; + + var v1:Boolean = true; + var v2:int = 3; + var v3:Number = -9; + var v4:String = "--"; + var v5:* = 3; + + return 0; + } + + static function TestConst3 ():int + { + if (v1 != false) + return 1; + + if (v2 != 0) + return 2; + + if (!isNaN (v3)) + return 3; + + if (v4 != null) + return 4; + + // TODO: Some odd constant default + //if (v5 != namespace) + // return 5; + +//TODO: if (v6 != undefined) +// return 6; + + const v1:Boolean = true; + const v2:int = 3; + const v3:Number = -9; + const v4:String = "--"; +// TODO: const v5:* = 3; +// const v6; + + return 0; + } + + static function Test4 ():int + { + if (v11 != 0) + return 1; + + if (v12 != null) + return 1; + + var v11:int = 4; + if (v11 != 4) + return 2; + + var v11:int = 5; + if (v11 != 5) + return 3; + + var v12:* = "4"; + if (v12 != "4") + return 4; + + var v12:String = "s"; + if (v12 != "s") + return 5; + + return 0; + } + + static function Test5 ():int + { + if (!isNaN (v1)) + return 1; + if (!isNaN (v2)) + return 2; + if (!isNaN (v3)) + return 3; + + var v1:Number,v2:Number = 4.3,v3:Number; + + if (!isNaN (v1)) + return 4; + if (isNaN (v2)) + return 5; + if (!isNaN (v3)) + return 6; + + return 0; + } + + static function TestConst5 ():int + { + if (!isNaN (v1)) + return 1; + if (!isNaN (v2)) + return 2; + if (!isNaN (v3)) + return 3; + + const v1:Number,v2:Number = 4.3,v3:Number; + + if (!isNaN (v1)) + return 4; + if (isNaN (v2)) + return 5; + if (!isNaN (v3)) + return 6; + + return 0; + } + + static function Test6 (): int + { + var i1:String; + var i1:*; + + var i2; + var i2:String; + return 0; + } + + public static function Main():int + { + var r:int; + r = Test1 (); + if (r != 0) + return r; + + r = Test2 (); + if (r != 0) + return r + 10; + + r = Test3 (); + if (r != 0) + return r + 20; + + r = Test4 (); + if (r != 0) + return r + 30; + + r = Test5 (); + if (r != 0) + return r + 40; + + r = TestConst3 (); + if (r != 0) + return r + 100; + + r = TestConst5 (); + if (r != 0) + return r + 100; + + trace ("ok"); + return 0; + } + } +} + diff --git a/mcs/tests/test-ps-035.play b/mcs/tests/test-ps-035.play new file mode 100644 index 00000000000..a0891494545 --- /dev/null +++ b/mcs/tests/test-ps-035.play @@ -0,0 +1,28 @@ +package +{ + public class ConstantComplexValueTest + { + public static function isNaN (num:Number = NaN2):Boolean + { + return System.Double.IsNaN (num); + } + + public static const NaN2 : Number = System.Double.NaN; + + public static function isNaN2 (num:Number = NaN):Boolean + { + return System.Double.IsNaN (num); + } + + public static function Main ():int + { + if (!isNaN ()) + return 1; + + if (!isNaN2 ()) + return 2; + + return 0; + } + } +} \ No newline at end of file diff --git a/mcs/tests/test-ps-036.play b/mcs/tests/test-ps-036.play new file mode 100644 index 00000000000..ab36d26a970 --- /dev/null +++ b/mcs/tests/test-ps-036.play @@ -0,0 +1,80 @@ +package +{ + public class Fields + { + public static var cs1:Object = new Object (); + public static var cs2:* = undefined; + internal static var cs3:Object = 8; + public static var cs4:Array = [1, 2, 3]; + public static var cs5:int = 2, cs6:uint = 7; + public static var cs8:int = vs8; + private static var cs9:String; + public static var cs10:Number; + static var cs11; + + static var vs8:int = 8; + + public var c1:Object = cs1; + public var c2:* = undefined; + public var c3:Object = null; + public var c4:Array = [5]; + public var c5:int = 20, c6:uint = 70; + public var c8:int = v8; + private var c9:String; + public var c10:Number; + internal var c11; + + static var v8:int = 8; + + public static function Main ():int + { + if (cs1 == null) + return 10; + if (cs3 != 8) + return 11; + if (cs4.length != 3) + return 12; + if (cs5 != 2) + return 13; + if (cs6 != 7) + return 14; + + vs8 = 80; + if (cs8 != 8) { + trace (cs8); + return 15; + } + if (cs9 != null) + return 16; + if (!isNaN (cs10)) + return 17; + // TODO: undefined + //if (cs11 != undefined) + // return 18; + + var c:Fields = new Fields (); + if (c.c1 == null) + return 20; + if (c.c3 != null) + return 21; + if (c.c4.length != 1) + return 22; + if (c.c5 != 20) + return 23; + if (c.c6 != 70) + return 24; + if (c.c8 != 8) + return 25; + if (c.c9 != null) + return 25; + if (!isNaN (c.c10)) + return 26; + // TODO: undefined + //if (c.c11 != undefined) + // return 27; + + trace ("ok"); + return 0; + } + } +} \ No newline at end of file diff --git a/mcs/tests/test-ps-037.play b/mcs/tests/test-ps-037.play new file mode 100644 index 00000000000..6294baa438e --- /dev/null +++ b/mcs/tests/test-ps-037.play @@ -0,0 +1,29 @@ +package +{ + var SECTION:String = "Class Prototype"; + trace (SECTION); + PackageInitializers.Test (4); + + public class PackageInitializers + { + private static var field:int; + + public static function Main():int + { + if (field != 4) + return 1; + + return 0; + } + + public static function Test (arg:int):void + { + field = arg; + trace ("called"); + } + } + + { + trace ("end"); + } +}; diff --git a/mcs/tests/test-ps-038.play b/mcs/tests/test-ps-038.play new file mode 100644 index 00000000000..65222a2e99c --- /dev/null +++ b/mcs/tests/test-ps-038.play @@ -0,0 +1,19 @@ +package +{ + public class DefaultAccessModifiers + { + public static function Main():int + { + var t:Test = new Test (); + t.F1 (); + return 0; + } + } + + public class Test + { + function F1 ():void + { + } + } +} diff --git a/mcs/tests/test-ps-039.play b/mcs/tests/test-ps-039.play new file mode 100644 index 00000000000..48cae1fd8cc --- /dev/null +++ b/mcs/tests/test-ps-039.play @@ -0,0 +1,13 @@ +package +{ + public class PrivateVirtual + { + private virtual function M1 ():void + { + } + + public static function Main():void + { + } + } +} diff --git a/mcs/tests/test-ps-040.play b/mcs/tests/test-ps-040.play new file mode 100644 index 00000000000..1e43b590b75 --- /dev/null +++ b/mcs/tests/test-ps-040.play @@ -0,0 +1,41 @@ +package +{ + public class ClassInitializer + { + public static function Main():void + { + new ClassA (); + new ClassA (); + } + } + + public class ClassA + { + public static var field:int = 4; + + Go (); + field -= 6; + + public function ClassA () + { + if (field != -2) + throw new Error ("2"); + } + + public static var j:Number=1; + public static var k:Number=0; + public static var l:Number=0; + public static var m:Number=0; + + // TODO: Flow-analysis +// for (j=1;j<2;j++) { +// k=j; +// } + + public static function Go ():void + { + if (field != 4) + throw new Error ("1"); + } + } +} diff --git a/mcs/tests/test-ps-041.play b/mcs/tests/test-ps-041.play new file mode 100644 index 00000000000..0c744cefcc3 --- /dev/null +++ b/mcs/tests/test-ps-041.play @@ -0,0 +1,67 @@ +package +{ + public class TryCatchTest + { + public static function Main():int + { + var c:int; + + try { + throw new Error (); + return 1; + } catch (e) { + trace (typeof (e)); + trace (e); + c++; + } + + if (c != 1) + return 2; + + try { + throw new ArgumentError (); + } catch (e:ArgumentError) { + ++c; + } catch (e:ArgumentError) { + return 3; + } + + if (c != 2) + return 4; + + try { + throw new Error (); + } catch (e:*) { + ++c; + } + + if (c != 3) + return 5; + +// TODO: +/* + try { + throw new String ("aa"); + } catch (e:String) { + ++c; + } catch (e:Number) { + return 5; + } + + if (c != 2) + return 6; + + try { + throw null; // TODO: Need to wrap it + } catch (e:*) { + ++c; + } + + if (c != 3) + return 5; +*/ + + return 0; + } + } +} diff --git a/mcs/tests/test-ps-042.play b/mcs/tests/test-ps-042.play new file mode 100644 index 00000000000..6085e04efe6 --- /dev/null +++ b/mcs/tests/test-ps-042.play @@ -0,0 +1,26 @@ +package +{ + public class ExpressionSeriesTest + { + static function Foo (arg:int):int + { + return arg; + } + + public static function Main ():int + { + var s:Class = (String); + + var x:int = (1, 3, 4); + if (x != 4) + return 1; + + var a:int = 2; + var b:int = 3; + if (Foo ((a++, b++, a + b)) != 7) + return 2; + + return 0; + } + } +} diff --git a/mcs/tests/test-ps-043.play b/mcs/tests/test-ps-043.play new file mode 100644 index 00000000000..3ef7afc64e3 --- /dev/null +++ b/mcs/tests/test-ps-043.play @@ -0,0 +1,26 @@ +package +{ + class UntypedParameter + { + public static function Test1 (str) + { +// TODO: trace (str); + } + + public static function Test2 (str = null) + { +// TODO: trace (str); + } + + public static function Main ():int + { + Test1 (1); + Test1 (null); + Test1 (""); + + Test2 (2); + Test2 (); + return 0; + } + } +} diff --git a/mcs/tests/test-ps-044.play b/mcs/tests/test-ps-044.play new file mode 100644 index 00000000000..eeb0d692bb1 --- /dev/null +++ b/mcs/tests/test-ps-044.play @@ -0,0 +1,18 @@ +package +{ + class ImplicitTypeConversion + { + public static function Test (expectedType:*):void + { + } + + public static function Main ():int + { + var v1:Class = int; + var c:Class = String; + Test (int); + + return 0; + } + } +} diff --git a/mcs/tests/test-ps-045.play b/mcs/tests/test-ps-045.play new file mode 100644 index 00000000000..814a6e80edb --- /dev/null +++ b/mcs/tests/test-ps-045.play @@ -0,0 +1,55 @@ +package +{ + class ProbingIsOperator + { + public static function expectType1 (expectedType:*, actualObject:*):Boolean + { + var result:Boolean = (actualObject is expectedType); + return result; + } + + public static function expectType2 (expectedType:Class, actualObject:Object):Boolean + { + return actualObject is expectedType; + } + + public static function Main():int + { + if (!expectType1 (int, 1)) + return 1; + + if (expectType1 (int, "1")) + return 2; + + if (!expectType1 (String, "1")) + return 3; + + if (!expectType1 (Object, "1")) + return 4; + + if (!expectType1 (Object, 4.3)) + return 5; + + if (expectType1 (Object, null)) + return 6; + + if (!expectType2 (int, 1)) + return 10; + + if (expectType2 (int, "1")) + return 11; + + if (!expectType2 (String, "1")) + return 12; + + if (!expectType2 (Object, "1")) + return 13; + + if (!expectType2 (Object, 4.3)) + return 14; + + return 0; + } + } +} +