/
EvilBeaver
/
OneScript
Обзор
Документация
Войти
/
EvilBeaver
/
OneScript
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
v2.0.2
src/OneScript.StandardLibrary/Native/CompiledBlock.cs
244 строки
9 KB
EvilBeaver
Удален вызов IValue.AsString во всем коде
20 май 2025, 19:25
20 май 2025, 19:25
f254dc9
Код
Авторство
О чём код?
/*---------------------------------------------------------- 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.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using OneScript.Commons; using OneScript.Compilation.Binding; using OneScript.Contexts; using OneScript.DependencyInjection; using OneScript.Exceptions; using OneScript.Execution; using OneScript.Language; using OneScript.Language.LexicalAnalysis; using OneScript.Language.SyntaxAnalysis; using OneScript.Language.SyntaxAnalysis.AstNodes; using OneScript.Native.Compiler; using OneScript.Native.Runtime; using OneScript.Sources; using OneScript.StandardLibrary.Collections; using OneScript.Types; using OneScript.Values; using ScriptEngine.Machine; using ScriptEngine.Machine.Contexts; namespace OneScript.StandardLibrary.Native { [ContextClass("СкомпилированныйФрагмент", "CompiledCodeBlock")] public class CompiledBlock : AutoContext<CompiledBlock> { private readonly IServiceContainer _services; private string _codeBlock; private BslSyntaxNode _ast; private IErrorSink _errors; private SourceCode _codeLinesReferences; public CompiledBlock(IServiceContainer services) { _services = services; } public SymbolTable Symbols { get; set; } [ContextProperty("Параметры", "Parameters")] public StructureImpl Parameters { get; set; } = new StructureImpl(); [ContextProperty("ФрагментКода", "CodeFragment")] public string CodeBlock { get => _codeBlock ?? string.Empty; set { _codeBlock = value; ParseCode(); } } private void ParseCode() { var lexer = new DefaultLexer(); var source = SourceCodeBuilder.Create() .FromString(CodeBlock) .WithName($"Compiled source {CodeBlock.GetHashCode():X8}") .Build(); lexer.Iterator = source.CreateIterator(); _codeLinesReferences = source; _errors = new ListErrorSink(); var parser = new DefaultBslParser(lexer, _errors, new PreprocessorHandlers()); try { _ast = parser.ParseCodeBatch(true); } catch (ScriptException e) { _errors.AddError(new CodeError { Description = e.Message, Position = e.GetPosition() }); } if (_errors.HasErrors) { var prefix = Locale.NStr("ru = 'Ошибка комиляции модуля'; en = 'Module compilation error'"); var text = string.Join('\n', (new[] {prefix}).Concat(_errors.Errors.Select(x => x.ToString(CodeError.ErrorDetails.Position)))); throw new RuntimeException(text); } } [ContextMethod("Скомпилировать", "Compile")] public DelegateAction Compile() { var method = CreateDelegate(); return new DelegateAction(method); } public Func<IBslProcess, BslValue[], BslValue> CreateDelegate() { var l = MakeExpression(); var arrayOfValuesParam = Expression.Parameter(typeof(BslValue[])); var convertedAccessList = new List<Expression>(); convertedAccessList.Add(l.Parameters.First()); int index = 0; foreach (var parameter in Parameters) { var targetType = parameter.Value as BslTypeValue; var arrayAccess = Expression.ArrayIndex(arrayOfValuesParam, Expression.Constant(index)); var convertedParam = ExpressionHelpers.ConvertToType(arrayAccess, ConvertTypeToClrType(targetType)); convertedAccessList.Add(convertedParam); ++index; } var lambdaInvocation = Expression.Invoke(l, convertedAccessList); var func = Expression.Lambda<Func<IBslProcess, BslValue[], BslValue>>(lambdaInvocation, (ParameterExpression)convertedAccessList[0], arrayOfValuesParam); return func.Compile(); } public T CreateDelegate<T>() where T:class { var l = MakeExpression(); var methodInfo = typeof(T).GetMethod("Invoke") ?? throw new ArgumentException("T must be a delegate type"); var firstParam = methodInfo.GetParameters().FirstOrDefault(); var mockProcess = firstParam == null || firstParam.ParameterType != typeof(IBslProcess); IEnumerable<Expression> invocationParameters; IEnumerable<ParameterExpression> delegateParameters; if (mockProcess) { var invocationParametersLst = new List<Expression>(); delegateParameters = l.Parameters.Skip(1).ToList(); invocationParametersLst.Add(Expression.Constant(ForbiddenBslProcess.Instance)); invocationParametersLst.AddRange(delegateParameters); invocationParameters = invocationParametersLst; } else { invocationParameters = l.Parameters; delegateParameters = l.Parameters; } var call = Expression.Invoke(l, invocationParameters); var func = Expression.Lambda<T>(call, delegateParameters); return func.Compile(); } public LambdaExpression MakeExpression() { if(_ast == default) ParseCode(); var expression = ReduceAst(_ast); if (_errors.HasErrors) { var prefix = Locale.NStr("ru = 'Ошибка комиляции модуля'; en = 'Module compilation error'"); var sb = new StringBuilder(); sb.AppendLine(prefix); foreach (var error in _errors.Errors) { sb.AppendLine(error.ToString(CodeError.ErrorDetails.Position)); } throw new RuntimeException(sb.ToString()); } return expression; } private LambdaExpression ReduceAst(BslSyntaxNode ast) { // в параметрах лежат соответствия имени переменной и ее типа // блок кода надо скомпилировтаь в лямбду с параметрами по количеству в коллекции Parameters и с типами параметров, как там // пробежать по аст 1С и превратить в BlockExpression<IValue> if (Symbols == null) Symbols = new SymbolTable(); Symbols.PushObject(new StandardGlobalContext()); var methodInfo = CreateMethodInfo(); var methodCompiler = new MethodCompiler(new BslWalkerContext { Errors = _errors, Source = _codeLinesReferences, Symbols = Symbols, Services = _services }, methodInfo); methodCompiler.CompileModuleBody(_ast.Children.FirstOrDefault(x => x.Kind == NodeKind.ModuleBody)); return methodInfo.Implementation; } private BslNativeMethodInfo CreateMethodInfo() { var methodInfo = new BslMethodInfoFactory<BslNativeMethodInfo>(()=>new BslNativeMethodInfo()) .NewMethod() .Name("$__compiled") .ReturnType(typeof(IValue)); foreach (var parameter in Parameters) { methodInfo.NewParameter() .Name(parameter.Key.ToString()) .ParameterType(ConvertTypeToClrType(parameter.Value as BslTypeValue)); } return methodInfo.Build(); } private static Type ConvertTypeToClrType(BslTypeValue typeVal) { var type = typeVal.TypeValue; return GetClrType(type); } private static Type GetClrType(TypeDescriptor type) { return CompilerHelpers.GetClrType(type); } [ScriptConstructor] public static CompiledBlock Create(TypeActivationContext context) { return new CompiledBlock(context.Services); } } }