예제 #1
0
        private static IExpression CreateDefaultOfTypeExpression(CompilationContext compilationContext, DataType type)
        {
            var result = new ConstantValueExpression();

            result.ValueType = type;

            // Добавляем константу (если еще нет), означающую дефолтное значение этого типа. null - значит что возьмется значение null из кода (не реальное значение dotnet объекта),
            // а это значит что будет просто дефолтное значение этого типа
            // ToDo: надо удостовериться что все дефолтные значения безопасны для копирования.
            // То есть проверить что не будет такого что дефолтное значение это какая нибудь ссылка с готовым объектом
            // (тогда можно будет изменить его через вызов метода и это сломает константу для всех мест где ее используют)
            compilationContext.CompilationUnit.AddConstant(Constant.CreateAsDotnetValue(result.ValueType, null));

            // Определяем выходное значение
            result.ReturnOutputSlot = new ExpressionSlot(result.ValueType, result);

            return(result);
        }
예제 #2
0
        private IExpression HandleTypeOfExpressionNode(TypeOfExpressionNode node)
        {
            if (!node.Type.ExternalType.DeclaredAsTypeNode)
            {
                throw _compilationContext.ThrowCompilationError("specified type cannot be used in typeof() operator");
            }

            var result = new ConstantValueExpression();

            var constant = Constant.CreateAsDotnetTypeString(node.Type.ExternalType.DotnetTypeString, _compilationContext.TypeLibrary);

            result.ValueType        = constant.Type;
            result.DotnetTypeString = constant.DotnetTypeString;

            _compilationContext.CompilationUnit.AddConstant(constant);

            result.ReturnOutputSlot = new ExpressionSlot(result.ValueType, result);

            return(result);
        }
예제 #3
0
        private IExpression HandleMethodCallExpressionNode(MethodCallExpressionNode node)
        {
            // Встроенные функции:

            if (node.MethodCallData.Name == "GetThis" && node.MethodCallData.TypeArguments.Count == 1 && node.MethodCallData.Parameters.Count == 0)
            {
                // Если это вызов GetThis<T>() - возвращаем константу this типа T

                var type = node.MethodCallData.TypeArguments[0];

                // UdonBehaviour -> private bool ResolveUdonHeapReference(IUdonHeap heap, uint symbolAddress, UdonBaseHeapReference udonBaseHeapReference)
                if (
                    type != _compilationContext.TypeLibrary.FindTypeByCodeNameString("UnityEngine::GameObject").DataType&&
                    type != _compilationContext.TypeLibrary.FindTypeByCodeNameString("UnityEngine::Transform").DataType&&
                    type != _compilationContext.TypeLibrary.FindTypeByCodeNameString("VRCUdon::UdonBehaviour").DataType
                    )
                {
                    throw _compilationContext.ThrowCompilationError("Type argument for GetThis<T>() must be UnityEngine::GameObject, UnityEngine::Transform, or VRCUdon::UdonBehaviour");
                }

                var result = new ConstantValueExpression();

                result.ValueType = type;

                result.IsThis = true;

                _compilationContext.CompilationUnit.AddConstant(Constant.CreateAsThis(type));

                // Определяем выходное значение
                result.ReturnOutputSlot = new ExpressionSlot(result.ValueType, result);

                return(result);
            }

            // Если не нашло во встроенных, ищем в определенных юзером
            // (ToDo: когда я реализую юзерские функции, возможно надо будет сначала искать в них, а если
            // не нашло то искать во встроенных)

            throw _compilationContext.ThrowCompilationError("user defined method calls are not supported yet");
        }
예제 #4
0
        private IExpression HandleLiteralExpressionNode(LiteralExpressionNode node)
        {
            var       result = new ConstantValueExpression();
            KnownType knownType;

            switch (node.LiteralType)
            {
            case LiteralExpressionNode.LiteralTypeOption.Int:
            {
                var literalValue = node.LiteralValue;

                if (int.TryParse(literalValue, NumberStyles.None, CultureInfo.InvariantCulture, out int intResult))
                {
                    knownType          = KnownType.Int32;
                    result.DotnetValue = intResult;
                }
                else if (long.TryParse(literalValue, NumberStyles.None, CultureInfo.InvariantCulture, out long longResult))
                {
                    knownType          = KnownType.Int64;
                    result.DotnetValue = longResult;
                }
                else
                {
                    throw _compilationContext.ThrowCompilationError("integer constant is too large");
                }
            }
            break;

            case LiteralExpressionNode.LiteralTypeOption.IntHex:
            {
                // Удаляем '0x'
                var literalValue = node.LiteralValue.Remove(0, 2);

                if (int.TryParse(literalValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out int intResult))
                {
                    knownType          = KnownType.Int32;
                    result.DotnetValue = intResult;
                }
                else if (long.TryParse(literalValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out long longResult))
                {
                    knownType          = KnownType.Int64;
                    result.DotnetValue = longResult;
                }
                else
                {
                    throw _compilationContext.ThrowCompilationError("integer constant is too large");
                }
            }
            break;

            case LiteralExpressionNode.LiteralTypeOption.Float:
            {
                var  literalValue = node.LiteralValue;
                bool isFloatLiteral;

                if (literalValue.EndsWith("f"))
                {
                    isFloatLiteral = true;
                    literalValue   = literalValue.Remove(literalValue.Length - 1, 1);
                }
                else
                {
                    isFloatLiteral = false;

                    if (literalValue.EndsWith("d"))
                    {
                        literalValue = literalValue.Remove(literalValue.Length - 1, 1);
                    }
                }

                if (isFloatLiteral)
                {
                    if (float.TryParse(literalValue, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out float floatResult))
                    {
                        knownType          = KnownType.Single;
                        result.DotnetValue = floatResult;
                    }
                    else
                    {
                        throw _compilationContext.ThrowCompilationError("cannot parse float literal");
                    }
                }
                else
                {
                    if (double.TryParse(literalValue, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out double doubleResult))
                    {
                        knownType          = KnownType.Double;
                        result.DotnetValue = doubleResult;
                    }
                    else
                    {
                        throw _compilationContext.ThrowCompilationError("cannot parse double literal");
                    }
                }
            }
            break;

            case LiteralExpressionNode.LiteralTypeOption.String:
            {
                knownType = KnownType.String;

                var literalValue = node.LiteralValue;

                // Удаляем кавычки по краям

                literalValue = literalValue.Remove(0, 1);
                literalValue = literalValue.Remove(literalValue.Length - 1, 1);

                // unescape

                // ToDo: в этом месте делаем undescape, то есть находим в строке обратный слеш плюс код и заменяем эти места на соответствующие символы (например \n меняем на символ новой строки и тд)
                // В парсере это не определено и не будет определено

                result.DotnetValue = literalValue;
            }
            break;

            case LiteralExpressionNode.LiteralTypeOption.Bool:
            {
                knownType          = KnownType.Boolean;
                result.DotnetValue = bool.Parse(node.LiteralValue);
            }
            break;

            case LiteralExpressionNode.LiteralTypeOption.Null:
            {
                knownType          = KnownType.Object;
                result.DotnetValue = null;
            }
            break;

            default:
                throw new NotImplementedException();
            }

            result.ValueType = _compilationContext.TypeLibrary.FindByKnownType(knownType);

            _compilationContext.CompilationUnit.AddConstant(Constant.CreateAsDotnetValue(result.ValueType, result.DotnetValue));

            // Определяем выходное значение
            result.ReturnOutputSlot = new ExpressionSlot(result.ValueType, result);

            return(result);
        }