Skip to content

Commit

Permalink
Аннотации как значения параметров аннотаций.
Browse files Browse the repository at this point in the history
  • Loading branch information
dmpas committed Oct 28, 2023
1 parent a7eccac commit 4347720
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 52 deletions.
12 changes: 11 additions & 1 deletion src/ScriptEngine.HostedScript/Library/Reflector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,24 @@ private static ValueTable.ValueTable CreateAnnotationTable(AnnotationDefinition[
{
parameterRow.Set(parameterNameColumn, ValueFactory.Create(annotationParameter.Name));
}
parameterRow.Set(parameterValueColumn, annotationParameter.RuntimeValue);
parameterRow.Set(parameterValueColumn, ResolveAnnotaionParameterValue(annotationParameter.RuntimeValue));
}
}
}

return annotationsTable;
}

private static IValue ResolveAnnotaionParameterValue(IValue source)
{
if (source is InternalAnnotationDefinitionWrapper internalDefinition)
{
var result = CreateAnnotationTable(new []{ internalDefinition.AnnotationDefinition });
return result;
}
return source;
}

private static bool MethodExistsForType(TypeTypeValue type, string methodName)
{
var clrType = GetReflectableClrType(type);
Expand Down
41 changes: 34 additions & 7 deletions src/ScriptEngine/Compiler/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ private AnnotationParameter BuildAnnotationParameter()
NextToken();
if (_lastExtractedLexem.Token == Token.Equal)
{
result.ValueIndex = BuildDefaultParameterValue();
NextToken();
result.ValueIndex = BuildAnnotationParameterValue();
}
else
{
Expand All @@ -134,12 +135,23 @@ private AnnotationParameter BuildAnnotationParameter()
}
else
{
result.ValueIndex = BuildLiteralConstant();
result.ValueIndex = BuildAnnotationParameterValue();
}

return result;
}

private int BuildAnnotationParameterValue()
{
if (_lastExtractedLexem.Type == LexemType.Annotation)
{
var annotation = BuildAnnotationDefinition();
var constDefinition = CreateAnnotationConstDefinition(annotation);
return GetConstNumber(ref constDefinition);
}
return BuildLiteralConstant();
}

private IList<AnnotationParameter> BuildAnnotationParameters()
{
var parameters = new List<AnnotationParameter>();
Expand All @@ -166,15 +178,20 @@ private IList<AnnotationParameter> BuildAnnotationParameters()
return parameters;
}

private AnnotationDefinition BuildAnnotationDefinition()
{
var annotation = new AnnotationDefinition() {Name = _lastExtractedLexem.Content};

NextToken();
annotation.Parameters = BuildAnnotationParameters().ToArray();
return annotation;
}

private void BuildAnnotations()
{
while (_lastExtractedLexem.Type == LexemType.Annotation)
{
var annotation = new AnnotationDefinition() {Name = _lastExtractedLexem.Content};

NextToken();
annotation.Parameters = BuildAnnotationParameters().ToArray();
_annotations.Add(annotation);
_annotations.Add(BuildAnnotationDefinition());
}
}

Expand Down Expand Up @@ -2000,6 +2017,16 @@ private static OperationCode BuiltInFunctionCode(Token token)
return _tokenToOpCode[token];
}

private static ConstDefinition CreateAnnotationConstDefinition(AnnotationDefinition annotation)
{
var definition = new ConstDefinition()
{
Type = DataType.Object,
Presentation = annotation.ToConstValue()
};
return definition;
}

private static ConstDefinition CreateConstDefinition(ref Lexem lex)
{
DataType constType = DataType.Undefined;
Expand Down
61 changes: 61 additions & 0 deletions src/ScriptEngine/Machine/AnnotationDefinition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*----------------------------------------------------------
This Source Code Form is subject to the terms of the
Mozilla Public License, v.2.0. If a copy of the MPL
was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.
----------------------------------------------------------*/
using System;
using System.Text;

namespace ScriptEngine.Machine
{
[Serializable]
public struct AnnotationDefinition
{
public string Name;
public AnnotationParameter[] Parameters;

public int ParamCount => Parameters?.Length ?? 0;

public string ToConstValue()
{
var builder = new StringBuilder("&");
builder.Append(Name);
builder.Append("(");

foreach (var parameter in Parameters)
{
builder.Append(parameter);
}
builder.Append(")");

return builder.ToString();
}

/// <summary>
/// Разбирает объект из сериализованного представления значения аннотации.
/// </summary>
/// <param name="constValuePresentation">Сериализованная аннотация. Строка вида `&ИмяАннотации(ИмяПараметра=ЗначениеПараметра,...)`</param>
/// <returns></returns>
public static AnnotationDefinition FromConstValue(string constValuePresentation)
{
var result = new AnnotationDefinition();

var nameEnd = constValuePresentation.IndexOf("(", StringComparison.Ordinal);
const int prefixLength = 1; // Длина строки &
result.Name = constValuePresentation.Substring(prefixLength, nameEnd - prefixLength);

var paramsEnd = constValuePresentation.LastIndexOf(")", StringComparison.Ordinal);
var paramsPresentation = constValuePresentation.Substring(nameEnd + 1, paramsEnd - nameEnd - 1);

var paramsSplitted = paramsPresentation.Split(',');
result.Parameters = new AnnotationParameter[paramsSplitted.Length];
for (var i = 0; i < paramsSplitted.Length; i++)
{
result.Parameters[i] = AnnotationParameter.FromString(paramsSplitted[i]);
}

return result;
}
}
}
67 changes: 67 additions & 0 deletions src/ScriptEngine/Machine/AnnotationParameter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*----------------------------------------------------------
This Source Code Form is subject to the terms of the
Mozilla Public License, v.2.0. If a copy of the MPL
was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.
----------------------------------------------------------*/

using System;

namespace ScriptEngine.Machine
{
[Serializable]
public struct AnnotationParameter
{
public string Name;
public int ValueIndex;

[NonSerialized]
public IValue RuntimeValue;

public const int UNDEFINED_VALUE_INDEX = -1;

public override string ToString()
{
if (string.IsNullOrEmpty(Name))
{
return $"[{ValueIndex}]";
}
if (ValueIndex == UNDEFINED_VALUE_INDEX)
{
return Name;
}
return $"{Name}=[{ValueIndex}]";
}

public static AnnotationParameter FromString(string presentation)
{
var result = new AnnotationParameter();
var parts = presentation.Split(',');
if (parts.Length == 1)
{
if (parts[0].StartsWith("["))
{
result.ValueIndex = AnnotationValueConstIndex(parts[0]);
}
else
{
result.Name = parts[0];
}
}
else
{
result.Name = parts[0];
result.ValueIndex = AnnotationValueConstIndex(parts[1]);
}

return result;
}

private static int AnnotationValueConstIndex(string valuePresentation)
{
// убираем [] по краям
var intPresentation = valuePresentation.Substring(1, valuePresentation.Length - 2);
return int.Parse(intPresentation);
}
}
}
36 changes: 1 addition & 35 deletions src/ScriptEngine/Machine/Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,41 +231,7 @@ public bool IsDefaultValueDefined()
return HasDefaultValue && DefaultValueIndex != UNDEFINED_VALUE_INDEX;
}
}

[Serializable]
public struct AnnotationDefinition
{
public string Name;
public AnnotationParameter[] Parameters;

public int ParamCount => Parameters?.Length ?? 0;
}

[Serializable]
public struct AnnotationParameter
{
public string Name;
public int ValueIndex;

[NonSerialized]
public IValue RuntimeValue;

public const int UNDEFINED_VALUE_INDEX = -1;

public override string ToString()
{
if (string.IsNullOrEmpty(Name))
{
return string.Format("[{0}]", ValueIndex);
}
if (ValueIndex == UNDEFINED_VALUE_INDEX)
{
return Name;
}
return String.Format("{0}=[{1}]", Name, ValueIndex);
}
}


public struct TypeDescriptor : IEquatable<TypeDescriptor>
{
public int ID;
Expand Down
22 changes: 22 additions & 0 deletions src/ScriptEngine/Machine/InternalAnnotationDefinitionWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*----------------------------------------------------------
This Source Code Form is subject to the terms of the
Mozilla Public License, v.2.0. If a copy of the MPL
was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.
----------------------------------------------------------*/

using ScriptEngine.Machine.Contexts;

namespace ScriptEngine.Machine
{
[ContextClass("ОпределениеАннотацииИсходногоКода", "AnnotationDefinitionWrapper")]
public class InternalAnnotationDefinitionWrapper: AutoContext<InternalAnnotationDefinitionWrapper>
{
public InternalAnnotationDefinitionWrapper(AnnotationDefinition annotationDefinition)
{
AnnotationDefinition = annotationDefinition;
}

public AnnotationDefinition AnnotationDefinition { get; }
}
}
29 changes: 21 additions & 8 deletions src/ScriptEngine/Machine/LoadedModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,16 @@ public LoadedModule(ModuleImage image)
for (int i = 0; i < image.Constants.Count; i++)
{
var def = image.Constants[i];
Constants[i] = ValueFactory.Parse(def.Presentation, def.Type);
if (def.Type == DataType.Object)
{
var unresolved = AnnotationDefinition.FromConstValue(def.Presentation);
EvaluateSingleAnnotationParametersValues(unresolved);
Constants[i] = new InternalAnnotationDefinitionWrapper(unresolved);
}
else
{
Constants[i] = ValueFactory.Parse(def.Presentation, def.Type);
}
}

ResolveAnnotationConstants();
Expand Down Expand Up @@ -74,14 +83,18 @@ private void EvaluateAnnotationParametersValues(AnnotationDefinition[] annotatio
{
for (int i = 0; i < annotations?.Length; i++)
{
var parameters = annotations[i].Parameters;
for (int j = 0; j < parameters?.Length; j++)
EvaluateSingleAnnotationParametersValues(annotations[i]);
}
}
private void EvaluateSingleAnnotationParametersValues(AnnotationDefinition annotation)
{
var parameters = annotation.Parameters;
for (int j = 0; j < parameters?.Length; j++)
{
var pa = parameters[j];
if (pa.ValueIndex != AnnotationParameter.UNDEFINED_VALUE_INDEX)
{
var pa = parameters[j];
if (pa.ValueIndex != AnnotationParameter.UNDEFINED_VALUE_INDEX)
{
annotations[i].Parameters[j].RuntimeValue = Constants[pa.ValueIndex];
}
annotation.Parameters[j].RuntimeValue = Constants[pa.ValueIndex];
}
}
}
Expand Down
26 changes: 25 additions & 1 deletion tests/annotations.os
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,34 @@
ВсеТесты.Добавить("ТестДолжен_ПроверитьАннотацииПолейЗагрузитьСценарий");
ВсеТесты.Добавить("ТестДолжен_ПроверитьАннотацииПолейЗагрузитьСценарийИзСтроки");

ВсеТесты.Добавить("ТестДолжен_ПроверитьАннотациюКакЗначениеПараметраАннотации");

Возврат ВсеТесты;

КонецФункции

&Аннотация(Параметр = &ТожеАннотация(&СТожеПараметромАннотацией))
Процедура ТестДолжен_ПроверитьАннотациюКакЗначениеПараметраАннотации() Экспорт

Рефлектор = Новый Рефлектор;
ТаблицаМетодов = Рефлектор.ПолучитьТаблицуМетодов(ЭтотОбъект);

юТест.ПроверитьНеРавенство(ТаблицаМетодов.Колонки.Найти("Аннотации"), Неопределено, "Есть колонка Аннотации");

СтрокаМетода = ТаблицаМетодов.Найти("ТестДолжен_ПроверитьАннотациюКакЗначениеПараметраАннотации", "Имя");
ПерваяАннотация = СтрокаМетода.Аннотации[0];
ПервыйПараметрПервойАннотации = ПерваяАннотация.Параметры[0];

юТест.ПроверитьТип(ПервыйПараметрПервойАннотации.Значение, Тип("ТаблицаЗначений"));

юТест.ПроверитьРавенство(ПервыйПараметрПервойАннотации.Значение[0].Имя, "ТожеАннотация");
юТест.ПроверитьТип(ПервыйПараметрПервойАннотации.Значение[0].Параметры, Тип("ТаблицаЗначений"));

юТест.ПроверитьТип(ПервыйПараметрПервойАннотации.Значение[0].Параметры[0].Значение, Тип("ТаблицаЗначений"));
юТест.ПроверитьРавенство(ПервыйПараметрПервойАннотации.Значение[0].Параметры[0].Значение[0].Имя, "СТожеПараметромАннотацией");

КонецПроцедуры

Процедура САннотированнымиПараметрами(

&АннотацияДляПараметра
Expand Down Expand Up @@ -197,4 +221,4 @@

КонецЕсли;

КонецПроцедуры
КонецПроцедуры

0 comments on commit 4347720

Please sign in to comment.