public static FileVariable Create(IScriptFile file, AccessModifier access, string @namespace, string name, TypeReference type, bool readOnly, int line, int column, int codeHash, VariableContainerAction resetter, VariableContainerAction creator, VariableContainerAction initializer) { var vcOwnerAccess = VariableContainer.Create(@namespace, name, type, readOnly); vcOwnerAccess.FileLine = line; vcOwnerAccess.FileColumn = column; vcOwnerAccess.CodeHash = codeHash; vcOwnerAccess.Tag = new Dictionary <Type, Object>(); if (resetter != null) { vcOwnerAccess.DataResetter = resetter; } if (creator != null) { vcOwnerAccess.DataCreator = creator; } if (initializer != null) { vcOwnerAccess.DataInitializer = initializer; } return(new FileVariable(file, access, line, null, @namespace, name, vcOwnerAccess, vcOwnerAccess.Container.UniqueID)); }
internal int CreateOrGetFileVariable( string @namespace, AccessModifier access, string name, TypeReference datatype, bool @readonly, int line, int column, int codeHash, VariableContainerAction resetter = null, VariableContainerAction creator = null, VariableContainerAction initializer = null, PropertyBlock customSetupData = null) { var existing = m_fileScopeVariablesBefore.FirstOrDefault( v => (String.Equals(v.VariableOwnerAccess.Container.Name, name, StringComparison.InvariantCulture) && v.VariableOwnerAccess.Container.DataType.Type == datatype.Type)); if (existing != null) { existing.VariableOwnerAccess.InitNeeded = (existing.VariableOwnerAccess.CodeHash != codeHash); m_fileScopeVariables.Add(existing); m_fileScopeVariablesBefore.RemoveAt(m_fileScopeVariablesBefore.IndexOf(existing)); if (resetter != null) { existing.VariableOwnerAccess.DataResetter = resetter; } if (creator != null) { existing.VariableOwnerAccess.DataCreator = creator; } if (initializer != null) { existing.VariableOwnerAccess.DataInitializer = initializer; } existing.VariableOwnerAccess.CodeHash = codeHash; if (customSetupData != null) { SetFileVariableCustomData(existing, customSetupData); } return(existing.ID); } var vc = FileVariable.Create(this, access, @namespace, name, datatype, @readonly, line, column, codeHash, resetter, creator, initializer); if (customSetupData != null) { SetFileVariableCustomData(vc, customSetupData); } m_fileScopeVariables.Add(vc); this.ObjectContainerListChanged?.Invoke(this, EventArgs.Empty); return(vc.ID); }
internal VariableContainerAction CreateVariableContainerObjectInitAction( Type objectType, PropertyBlock properties, ErrorCollector errors, IToken startToken) { VariableContainerAction action = null; var resolver = new DefaultContractResolver(); var contract = resolver.ResolveContract(objectType) as JsonObjectContract; var dataSetters = new List <Expression>(); var objectReference = Expression.Variable(objectType); foreach (var entry in properties) { if (entry.BlockEntryType == PropertyBlockEntryType.Value) { var valueEntry = entry as PropertyBlockValue; if (String.IsNullOrEmpty(valueEntry.SpecifiedTypeName)) { var objectProperty = contract.Properties.FirstOrDefault(p => String.Equals(entry.Name, p.PropertyName, StringComparison.InvariantCulture)); if (objectProperty != null) { entry.Tag = "Property"; bool dataError = false; System.Diagnostics.Debug.WriteLine($"Property type: {objectProperty.PropertyType.Name}"); Expression valueExpression = null; object value = valueEntry.Value; if (value != null) { if (objectProperty.PropertyType.IsEnum) { if (value is Identifier) { value = ((Identifier)value).Name; } if (value is string) { if (((string)value).StartsWith(objectProperty.PropertyType.Name + ".", StringComparison.InvariantCulture)) { value = ((string)value).Substring(objectProperty.PropertyType.Name.Length + 1); } try { value = Enum.Parse(objectProperty.PropertyType, (string)value); } catch { dataError = true; errors.SymanticError(startToken.Line, startToken.Column, false, $"Unknown value for property \"{entry.Name}\"."); } } else if (value is long) { } else { dataError = true; errors.SymanticError(startToken.Line, startToken.Column, false, $"Unsupported value for property \"{entry.Name}\"."); } } else if (objectProperty.PropertyType == typeof(string)) { if (value is Identifier) { value = ((Identifier)value).Name; } } else if (!objectProperty.PropertyType.IsPrimitive && objectProperty.PropertyType != typeof(TimeSpan) && objectProperty.PropertyType != typeof(DateTime)) { if (value is Identifier) { value = ((Identifier)value).Name; var resolved = this.ResolveIdentifierForGetOperation( (string)value, false, new TypeReference(objectProperty.PropertyType)); if (resolved != null) { if (objectProperty.PropertyType.IsAssignableFrom(resolved.DataType.Type)) { valueExpression = resolved.ExpressionCode; } else { dataError = true; errors.SymanticError(startToken.Line, startToken.Column, false, $"Unresolved value for property \"{entry.Name}\": '{(string)value}'."); } } else { dataError = true; errors.SymanticError(startToken.Line, startToken.Column, false, $"Unresolved value for property \"{entry.Name}\": '{(string)value}'."); } } else { dataError = true; errors.SymanticError(startToken.Line, startToken.Column, false, $"Unsupported value type for property \"{entry.Name}\": '{(string)value.GetType().Name}'."); } } } if (!dataError) { var vt = (valueExpression != null) ? valueExpression.Type : value?.GetType(); if (vt != null && !objectProperty.PropertyType.IsAssignableFrom(vt)) { errors.IncompatibleDataType(startToken.Line, startToken.Column, vt.Name, objectProperty.PropertyType.Name); } else { if (valueExpression == null) { valueExpression = Expression.Constant(value, objectProperty.PropertyType); } dataSetters.Add(Expression.Assign( Expression.Property(objectReference, objectProperty.UnderlyingName), valueExpression)); } } } else { errors.SymanticError(startToken.Line, startToken.Column, false, $"The object has no property named \"{entry.Name}\"."); } } else { throw new NotImplementedException(); } } else { // Not handled yet; just let it fall through. } } if (dataSetters.Count > 0) { try { LabelTarget returnLabel = Expression.Label(typeof(bool)); var parameterContainer = Expression.Parameter(typeof(IValueContainerOwnerAccess), "container"); var parameterLogger = Expression.Parameter(typeof(ILogger), "logger"); var getContainerReference = Expression.Property( parameterContainer, typeof(IValueContainerOwnerAccess).GetProperty(nameof(IValueContainerOwnerAccess.Container))); var getObjectReference = Expression.Call( getContainerReference, typeof(IValueContainer).GetMethod(nameof(IValueContainer.GetValue), new Type[] { typeof(ILogger) }), parameterLogger); var objectReferenceAssignment = Expression.Assign( objectReference, Expression.Convert(getObjectReference, objectType)); var expressions = new List <Expression>(dataSetters); expressions.Insert(0, objectReferenceAssignment); if (objectType.GetInterface(nameof(ISettableFromPropertyBlock)) != null) { var setterHelper = typeof(ExecutionHelperMethods).GetMethod( nameof(ExecutionHelperMethods.SetupObjectWithPropertyBlock)); var propertyBlockSetter = Expression.Call(setterHelper, parameterLogger, parameterContainer); expressions.Add(propertyBlockSetter); } expressions.Add(Expression.Label(returnLabel, Expression.Constant(true))); var lambdaExpr = Expression.Lambda( typeof(VariableContainerAction), Expression.Block(new ParameterExpression[] { objectReference }, expressions), parameterContainer, parameterLogger); var @delegate = lambdaExpr.Compile(); action = (VariableContainerAction)@delegate; } catch (Exception) { throw; } } return(action); }
public override void ExitFileVariableWithPropertyBlock([NotNull] SBP.FileVariableWithPropertyBlockContext context) { TypeReference type = m_variableType; if (type == null) { return; } var props = m_lastElementPropertyBlock; VariableContainerAction createAction = null; VariableContainerAction initAction = null; VariableContainerAction resetAction = null; if (m_variableType.Type.IsValueType || m_variableType.Type == typeof(string)) { var code = Expression.Constant(Activator.CreateInstance(type.Type), type.Type); createAction = CreateVariableContainerValueAssignAction(code); resetAction = createAction; } else { #region Creator Action var ctor = type.Type.GetConstructor(new Type[] { }); if (ctor != null) { var code = Expression.New(ctor); createAction = CreateVariableContainerValueAssignAction(code); } else { var createMethods = type.Type.GetMethods().Where( m => String.Equals(m.Name, "Create", StringComparison.InvariantCulture) && m.IsStatic).ToArray(); throw new NotImplementedException(); } #endregion #region Reset Action var resettable = type.Type.GetInterface(nameof(IResettable)); if (resettable != null) { LabelTarget returnLabel = Expression.Label(typeof(bool)); var parameterContainer = Expression.Parameter(typeof(IValueContainerOwnerAccess), "container"); var parameterLogger = Expression.Parameter(typeof(ILogger), "logger"); var callSetValue = Expression.Call( typeof(ExecutionHelperMethods).GetMethod(nameof(ExecutionHelperMethods.ResetFileVariable), new Type[] { typeof(IValueContainerOwnerAccess), typeof(ILogger) }), parameterContainer, parameterLogger); var lambdaExpr = Expression.Lambda( typeof(VariableContainerAction), Expression.Block( callSetValue, Expression.Label(returnLabel, Expression.Constant(true))), parameterContainer, parameterLogger); var @delegate = lambdaExpr.Compile(); resetAction = (VariableContainerAction)@delegate; } #endregion } PropertyBlock customProperties = null; if (props != null && props.Count > 0) { initAction = this.CreateVariableContainerObjectInitAction(type.Type, props, m_errors, context.Start); if (props.Count(e => e.Tag == null) > 0) { customProperties = new PropertyBlock(context.Start.Line); customProperties.AddRange(props.Where(e => e.Tag == null)); } } var codeHash = context.GetText().GetHashCode(); var id = m_file.CreateOrGetFileVariable( m_currentNamespace, m_fileElementModifier, m_variableName, type, true, context.Start.Line, context.Start.Column, codeHash, resetter: resetAction, creator: createAction, initializer: initAction, customSetupData: customProperties); m_file.SetFileVariableModifier(id, m_fileElementModifier); m_variableName = null; }