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); }
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); }
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"); }
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); }