Upsilon-VsCode/UpsilonLanguageServer/UpsilonLanguageServer/BoundTypeParser.cs

181 lines
8.8 KiB
C#

using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using Upsilon.Binder.VariableSymbols;
using Upsilon.BoundTypes;
using Upsilon.StandardLibraries;
using Type = Upsilon.BaseTypes.Type;
namespace UpsilonLanguageServer
{
public static class BoundTypeParser
{
public static void LoadBoundTypes(string fileContent)
{
BoundTypeHandler.Reset();
var json = JObject.Parse(fileContent);
foreach (var prop in json.Properties())
{
var typeName = prop.Name;
if (!(prop.Value is JObject obj))
continue;
var dic = new Dictionary<string, UserDataBoundProperty>();
var specialMod = obj.GetValue("__type", StringComparison.InvariantCultureIgnoreCase)?.ToString();
if (string.Equals(specialMod, "enum", StringComparison.InvariantCultureIgnoreCase))
{
var values = obj.GetValue("values", StringComparison.InvariantCultureIgnoreCase)?.ToObject<string[]>();
if (values == null)
continue;
BoundTypeHandler.LoadUserDataTypeDefinition(new UserDataBoundEnumDefinition(values, typeName));
continue;
}
var innerProperties = obj.Properties();
foreach (var innerProperty in innerProperties)
{
var propertyName = innerProperty.Name;
if (!(innerProperty.Value is JObject value))
continue;
var type = value.GetValue("type", StringComparison.InvariantCultureIgnoreCase)?.ToString();
var comment = value.GetValue("comment", StringComparison.InvariantCultureIgnoreCase)?.ToString();
if (string.Equals("function", type, StringComparison.InvariantCultureIgnoreCase))
{
ParseMethod(value, dic, propertyName, type, comment);
}
else
{
dic.Add(propertyName.ToLowerInvariant(), new UserDataBoundProperty()
{
Name = propertyName,
ActualType = type,
Comment = comment,
Type = ParseType(type)
});
}
}
BoundTypeHandler.LoadUserDataTypeDefinition(new UserDataBoundTypeDefinition(typeName, dic));
}
}
private static void ParseMethod(JObject value, IDictionary<string, UserDataBoundProperty> dic, string propertyName, string type, string comment)
{
var returnType = value.GetValue("returns", StringComparison.InvariantCultureIgnoreCase)?.ToString();
var parameters = new List<UserDataBoundFunctionParameter>();
if (value.GetValue("Parameters", StringComparison.InvariantCultureIgnoreCase) is JObject parameterJson)
{
var properties = parameterJson.Properties();
foreach (var property in properties)
{
var parameterName = property.Name;
var parameterValue = (JObject) property.Value;
var parType = parameterValue.GetValue("type", StringComparison.InvariantCultureIgnoreCase)
?.ToString();
var parComment = parameterValue.GetValue("comment", StringComparison.InvariantCultureIgnoreCase)
?.ToString();
var isOptional = parameterValue.GetValue("IsOptional", StringComparison.InvariantCultureIgnoreCase)
?.ToObject<bool>();
parameters.Add(new UserDataBoundFunctionParameter()
{
Name = parameterName,
Type = ParseType(parType),
Comment = parComment,
IsOptional = isOptional.HasValue && isOptional.Value
});
}
}
dic.Add(propertyName.ToLowerInvariant(), new UserDataBoundMethod()
{
Name = propertyName,
ActualType = type,
Comment = comment,
Type = ParseType(type),
ResultType = ParseType(returnType),
Parameters = parameters.ToArray()
});
}
public static void LoadStaticVariables(string fileContent)
{
// We call the evaluation scope so that it initializes, and won't overwrite the bound scope later on
// DONT REMOVE
var _ = StaticScope.Scope;
StaticScope.BoundScope = StaticScope.CreateStandardLibrary().Item2;
var json = JObject.Parse(fileContent);
foreach (var property in json.Properties())
{
var name = property.Name;
var obj = (JObject)property.Value;
var stringType = obj.GetValue("type", StringComparison.InvariantCultureIgnoreCase).ToString().ToLowerInvariant();
var comments = obj.GetValue("comment", StringComparison.InvariantCultureIgnoreCase)?.ToString()
.Split('\n');
var type = ParseType(stringType);
if (type == Type.UserData)
{
var boundType = BoundTypeHandler.GetTypeDefinition(stringType);
if (boundType != null)
{
StaticScope.BoundScope.AssignToNearest(new UserDataVariableSymbol(name, boundType){CommentValue = comments});
}
else
{
StaticScope.BoundScope.AssignToNearest(new UserDataVariableSymbol(name, Type.Unknown){CommentValue = comments});
}
}
else if (type == Type.Function)
{
var returnType = obj.GetValue("returns", StringComparison.InvariantCultureIgnoreCase).ToString().ToLowerInvariant();
var parameters = new List<InternalFunctionVariableSymbol.InternalFunctionParameter>();
if (obj.GetValue("Parameters", StringComparison.InvariantCultureIgnoreCase) is JObject parameterJson)
{
var properties = parameterJson.Properties();
foreach (var prop in properties)
{
var parameterValue = (JObject) prop.Value;
var parName = parameterValue.GetValue("name", StringComparison.InvariantCultureIgnoreCase)
?.ToString();
var parType = parameterValue.GetValue("type", StringComparison.InvariantCultureIgnoreCase)
?.ToString();
var parsedType = ParseType(parType);
var isOptional = parameterValue.GetValue("IsOptional", StringComparison.InvariantCultureIgnoreCase)
?.ToObject<bool>();
parameters.Add(new InternalFunctionVariableSymbol.InternalFunctionParameter(parName, parsedType,
isOptional.HasValue && isOptional.Value));
}
}
var parsedReturnType = ParseType(returnType);
StaticScope.BoundScope.AssignToNearest(new InternalFunctionVariableSymbol(name, false,
parsedReturnType, parameters.ToArray())
{
CommentValue = comments
});
}
else
{
StaticScope.BoundScope.AssignToNearest(new VariableSymbol(property.Name,
type, false)
{
CommentValue = comments
});
}
}
}
private static Type ParseType(string input)
{
if (string.Equals(input, "string", StringComparison.InvariantCultureIgnoreCase))
return Type.String;
if (string.Equals(input, "number", StringComparison.InvariantCultureIgnoreCase))
return Type.Number;
if (string.Equals(input, "bool", StringComparison.InvariantCultureIgnoreCase))
return Type.Boolean;
if (string.Equals(input, "table", StringComparison.InvariantCultureIgnoreCase))
return Type.Table;
if (string.Equals(input, "function", StringComparison.InvariantCultureIgnoreCase))
return Type.Function;
return Type.UserData;
}
}
}