From f983239b5a331551da5fa6e34198ea7dd3566371 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Thu, 29 Nov 2018 18:09:08 +0100 Subject: [PATCH] Bind indexing of userdata --- .../BaseTypes/UserData/UserDataTypeHandler.cs | 2 + Upsilon/Binder/Binder.cs | 30 ++++++++++++- Upsilon/Binder/VariableSymbol.cs | 20 +++------ Upsilon/BoundTypes/BoundTypeDefinition.cs | 22 ++++++++++ Upsilon/BoundTypes/BoundTypeHandler.cs | 44 ++++++++++++------- .../BoundTypes/UserDataBoundTypeDefinition.cs | 32 ++++++++++++++ 6 files changed, 118 insertions(+), 32 deletions(-) create mode 100644 Upsilon/BoundTypes/BoundTypeDefinition.cs create mode 100644 Upsilon/BoundTypes/UserDataBoundTypeDefinition.cs diff --git a/Upsilon/BaseTypes/UserData/UserDataTypeHandler.cs b/Upsilon/BaseTypes/UserData/UserDataTypeHandler.cs index ef0e111..eb35bec 100644 --- a/Upsilon/BaseTypes/UserData/UserDataTypeHandler.cs +++ b/Upsilon/BaseTypes/UserData/UserDataTypeHandler.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Upsilon.BoundTypes; namespace Upsilon.BaseTypes.UserData { @@ -10,6 +11,7 @@ namespace Upsilon.BaseTypes.UserData { var info = new UserDataType(t); _types.Add(t, info); + BoundTypeHandler.LoadUserDataTypeDefinition(new UserDataBoundTypeDefinition(t)); } public static void LoadType() diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index ac0c197..02c3329 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -47,7 +47,8 @@ namespace Upsilon.Binder foreach (var valueParameter in unboundFunctionStatement.Value.Parameters) { Scope.AssignToNearest(valueParameter.VariableSymbol); - _diagnostics.LogUnknownVariableType(valueParameter.VariableSymbol.Name, valueParameter.Span); + if (valueParameter.VariableSymbol.Type == Type.Unknown) + _diagnostics.LogUnknownVariableType(valueParameter.VariableSymbol.Name, valueParameter.Span); } unboundFunctionStatement.Value.Block = (BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.Value.UnboundBlock); @@ -458,7 +459,15 @@ namespace Upsilon.Binder if (variable.TypeName != null) { var type = BoundTypeHandler.GetTypeDefinition(variable.TypeName.Name); - variableSymbol = new FunctionParameterSymbol(variable.IdentifierName.Name, type); + if (type == null) + { + _diagnostics.LogError($"Unknown type name '{variable.TypeName.Name}'", variable.Span); + variableSymbol = new FunctionParameterSymbol(variable.IdentifierName.Name, Type.Unknown); + } + else + { + variableSymbol = new FunctionParameterSymbol(variable.IdentifierName.Name, type); + } } else { @@ -688,6 +697,23 @@ namespace Upsilon.Binder } return new BoundFullStopIndexExpression(expression, index, Type.Unknown, e.Span); case Type.UserData: + if (isAssignment) + { + return new BoundFullStopIndexExpression(expression, index, Type.Unknown, e.Span); + } + + if (expression.Kind == BoundKind.VariableExpression) + { + var variableExpression = (BoundVariableExpression)expression; + var obj = variableExpression.Variable; + var functionParameter = (FunctionParameterSymbol) obj.VariableSymbol; + var udBoundDef = (UserDataBoundTypeDefinition)functionParameter.BoundTypeDefinition; + if (udBoundDef.Properties.TryGetValue(index, out var property)) + { + return new BoundFullStopIndexExpression(expression, index, property.Type, e.Span); + } + } + return new BoundFullStopIndexExpression(expression, index, Type.Unknown, e.Span); case Type.Unknown: return new BoundFullStopIndexExpression(expression, index, Type.Unknown, e.Span); case Type.String: diff --git a/Upsilon/Binder/VariableSymbol.cs b/Upsilon/Binder/VariableSymbol.cs index befa8e5..6356b42 100644 --- a/Upsilon/Binder/VariableSymbol.cs +++ b/Upsilon/Binder/VariableSymbol.cs @@ -14,7 +14,7 @@ namespace Upsilon.Binder Name = name; } - public Type Type { get; set; } + public virtual Type Type { get; set; } public bool Local { get; } public string Name { get; } public string[] CommentValue { get; set; } @@ -51,6 +51,12 @@ namespace Upsilon.Binder BoundTypeDefinition = type; } + private Type _type; + public override Type Type + { + get => BoundTypeDefinition?.ScriptType ?? _type; + set => _type = Type; + } } public class TableVariableSymbol : VariableSymbol @@ -63,16 +69,4 @@ namespace Upsilon.Binder Variables = variables; } } - - public class UserDataVariableSymbol : VariableSymbol - { - public BoundTypeDefinition BoundTypeDefinition { get; } - - public UserDataVariableSymbol(string name, bool local, BoundTypeDefinition boundTypeDefinition) - :base (name, Type.UserData, local) - { - BoundTypeDefinition = boundTypeDefinition; - } - } - } \ No newline at end of file diff --git a/Upsilon/BoundTypes/BoundTypeDefinition.cs b/Upsilon/BoundTypes/BoundTypeDefinition.cs new file mode 100644 index 0000000..22883be --- /dev/null +++ b/Upsilon/BoundTypes/BoundTypeDefinition.cs @@ -0,0 +1,22 @@ +using Upsilon.BaseTypes; + +namespace Upsilon.BoundTypes +{ + public class BoundTypeDefinition + { + public BoundTypeDefinition(Type scriptType, System.Type[] validInternalTypes) + { + ScriptType = scriptType; + ValidInternalTypes = validInternalTypes; + } + + public BoundTypeDefinition(Type scriptType, System.Type backingType) + { + ScriptType = scriptType; + ValidInternalTypes = new []{backingType}; + } + + public Type ScriptType { get; } + public System.Type[] ValidInternalTypes { get; } + } +} \ No newline at end of file diff --git a/Upsilon/BoundTypes/BoundTypeHandler.cs b/Upsilon/BoundTypes/BoundTypeHandler.cs index 8a234c1..e4f5182 100644 --- a/Upsilon/BoundTypes/BoundTypeHandler.cs +++ b/Upsilon/BoundTypes/BoundTypeHandler.cs @@ -6,7 +6,8 @@ namespace Upsilon.BoundTypes { public static class BoundTypeHandler { - private static readonly Dictionary TypeDefinitions = new Dictionary + private static readonly Dictionary DefaultTypeDefinitions = + new Dictionary { {"string", new BoundTypeDefinition(Type.String, typeof(string))}, { @@ -19,27 +20,36 @@ namespace Upsilon.BoundTypes {"function", new BoundTypeDefinition(Type.Function, new System.Type[0])}, }; + private static Dictionary _typeDefinitions = + new Dictionary(DefaultTypeDefinitions); + + public static void Reset() + { + _typeDefinitions = + new Dictionary(DefaultTypeDefinitions); + } + public static BoundTypeDefinition GetTypeDefinition(string key) { - return TypeDefinitions[key.ToLowerInvariant()]; + var normalizedName = key.ToLowerInvariant(); + if (_typeDefinitions.TryGetValue(normalizedName, out var bt)) + { + return bt; + } + return null; } - } - public class BoundTypeDefinition - { - public BoundTypeDefinition(Type scriptType, System.Type[] validInternalTypes) + public static void LoadUserDataTypeDefinition(UserDataBoundTypeDefinition def) { - ScriptType = scriptType; - ValidInternalTypes = validInternalTypes; + var key = def.Name.ToLowerInvariant(); + if (_typeDefinitions.ContainsKey(key)) + { + _typeDefinitions[key] = def; + } + else + { + _typeDefinitions.Add(key, def); + } } - - public BoundTypeDefinition(Type scriptType, System.Type validInternalType) - { - ScriptType = scriptType; - ValidInternalTypes = new []{validInternalType}; - } - - public Type ScriptType { get; } - public System.Type[] ValidInternalTypes { get; } } } \ No newline at end of file diff --git a/Upsilon/BoundTypes/UserDataBoundTypeDefinition.cs b/Upsilon/BoundTypes/UserDataBoundTypeDefinition.cs new file mode 100644 index 0000000..98b60ab --- /dev/null +++ b/Upsilon/BoundTypes/UserDataBoundTypeDefinition.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Upsilon.BaseTypes; + +namespace Upsilon.BoundTypes +{ + public class UserDataBoundTypeDefinition : BoundTypeDefinition + { + public string Name { get; } + public Dictionary Properties { get; } + + public UserDataBoundTypeDefinition(System.Type backingType) + : base(Type.UserData, backingType) + { + Name = backingType.Name; + } + + public UserDataBoundTypeDefinition(string name, Dictionary properties) + : base(Type.UserData, new System.Type[0]) + { + Name = name; + Properties = properties; + } + } + + public class UserDataBoundProperty + { + public string Name { get; set; } + public Type Type { get; set; } + public string ActualType { get; set; } + public string Comment { get; set; } + } +} \ No newline at end of file