public static Compilation Compile(string src, string path = "test.sc", IUsingSourceResolver?sourceResolver = null) { var c = new Compilation { SourceResolver = sourceResolver }; using var r = new StringReader(src); c.SetMainModule(r, path); c.Compile(); return(c); }
public ICodeblock Compile(string macro) { Compilation <object, RuntimeCodeblockDelegate> compiler = GetCompiler(true); var m = compiler.Compile(macro); if (m.Diagnostic != null) { throw m.Diagnostic; } return(new RuntimeCodeblock(m.Macro, m.ParamCount)); }
internal static void EmitCorLibWithAssemblyReferences( Compilation comp, string pdbPath, Func <CommonPEModuleBuilder, EmitOptions, CommonPEModuleBuilder> getModuleBuilder, out ImmutableArray <byte> peBytes, out ImmutableArray <byte> pdbBytes) { var diagnostics = DiagnosticBag.GetInstance(); var emitOptions = EmitOptions.Default.WithRuntimeMetadataVersion("0.0.0.0").WithDebugInformationFormat(DebugInformationFormat.PortablePdb); var moduleBuilder = comp.CheckOptionsAndCreateModuleBuilder( diagnostics, null, emitOptions, null, null, null, null, default(CancellationToken)); // Wrap the module builder in a module builder that // reports the "System.Object" type as having no base type. moduleBuilder = getModuleBuilder(moduleBuilder, emitOptions); bool result = comp.Compile( moduleBuilder, emittingPdb: pdbPath != null, diagnostics: diagnostics, filterOpt: null, cancellationToken: default(CancellationToken)); using (var peStream = new MemoryStream()) { using (var pdbStream = new MemoryStream()) { PeWriter.WritePeToStream( new EmitContext(moduleBuilder, null, diagnostics, metadataOnly: false, includePrivateMembers: true), comp.MessageProvider, () => peStream, () => pdbStream, null, null, metadataOnly: true, isDeterministic: false, emitTestCoverageData: false, privateKeyOpt: null, cancellationToken: default(CancellationToken)); peBytes = peStream.ToImmutable(); pdbBytes = pdbStream.ToImmutable(); } } diagnostics.Verify(); diagnostics.Free(); }
public static void DoTest() { //NativeDB.Fetch(new Uri("https://raw.githubusercontent.com/alloc8or/gta5-nativedb-data/master/natives.json"), "ScriptHookV_1.0.2060.1.zip") // .ContinueWith(t => File.WriteAllText("nativedb.json", t.Result.ToJson())) // .Wait(); var nativeDB = NativeDB.FromJson(File.ReadAllText("nativedb.json")); using var reader = new StringReader(Code); var comp = new Compilation { NativeDB = nativeDB }; comp.SetMainModule(reader); comp.Compile(); File.WriteAllText("test_script.ast.txt", comp.MainModule.GetAstDotGraph()); var d = comp.GetAllDiagnostics(); var symbols = comp.MainModule.SymbolTable; Console.WriteLine($"Errors: {d.HasErrors} ({d.Errors.Count()})"); Console.WriteLine($"Warnings: {d.HasWarnings} ({d.Warnings.Count()})"); foreach (var diagnostic in d.AllDiagnostics) { diagnostic.Print(Console.Out); } foreach (var s in symbols.Symbols) { if (s is TypeSymbol t && t.Type is StructType struc) { Console.WriteLine($" > '{t.Name}' Size = {struc.SizeOf}"); } } Console.WriteLine(); new Dumper(comp.CompiledScript).Dump(Console.Out, true, true, true, true, true); YscFile ysc = new YscFile { Script = comp.CompiledScript }; string outputPath = "test_script.ysc"; byte[] data = ysc.Save(Path.GetFileName(outputPath)); File.WriteAllBytes(outputPath, data); outputPath = Path.ChangeExtension(outputPath, "unencrypted.ysc"); data = ysc.Save(); File.WriteAllBytes(outputPath, data); ; }
public ICodeblock Compile(string macro, bool lAllowSingleQuotes, Module module, out bool isCodeblock, out bool addsMemVars) { isCodeblock = macro.Replace(" ", "").StartsWith("{|"); addsMemVars = false; Compilation <object, RuntimeCodeblockDelegate> compiler = GetCompiler(lAllowSingleQuotes); var m = compiler.Compile(macro); if (m.Diagnostic != null) { throw m.Diagnostic; } addsMemVars = m.CreatesAutoVars; return(new RuntimeCodeblock(m.Macro, m.ParamCount)); }
public void TestComplexExpression() { const bool Expected = (-5 * 3 + 2 * (2 | 4)) == 4 && 3.0f != (8.0f / 2.0f); var comp = new Compilation(); comp.SetMainModule(new StringReader(@" BOOL dummy = (-5 * 3 + 2 * (2 | 4)) == 4 AND 3.0 <> (8.0 / 2.0) PROC MAIN() ENDPROC ")); comp.Compile(); var diagnostics = comp.GetAllDiagnostics(); Assert.False(diagnostics.HasErrors); Assert.NotNull(comp.CompiledScript.Statics); Assert.Single(comp.CompiledScript.Statics); Assert.Equal(Expected, comp.CompiledScript.Statics[0].AsInt64 == 1); }
public static int Main(string[] args) { var outputPath = (string)null; var moduleName = (string)null; var referencePaths = new List <string>(); var sourcePaths = new List <string>(); var printTree = false; var needsHelp = false; var options = new OptionSet() { "usage: gsc <source-paths> [options]", "", { "r=", "The {path} of a assembly to referenc", r => referencePaths.Add(r) }, { "o=", "The {path} of the output file", o => outputPath = o }, { "m=", "The {name} of the module", m => moduleName = m }, { "d|dump", "Displays the bound tree in the console", d => printTree = true }, { "<>", s => sourcePaths.Add(s) }, { "?|h|help", "Displays Help", h => needsHelp = true }, "", }; try { options.Parse(args); } catch (OptionException e) { WriteError(e.Message); return(5); } if (needsHelp) { options.WriteOptionDescriptions(Console.Out); return(0); } var paths = ValidatePaths(sourcePaths); if (paths is null) { return(5); } if (paths.Length == 0) { WriteError("No source files are provided."); return(5); } if (outputPath is null) { outputPath = Path.ChangeExtension(paths[0], ".exe"); } if (moduleName is null) { moduleName = Path.GetFileNameWithoutExtension(outputPath); } var sourceTexts = paths.Select(p => new SourceText(File.ReadAllText(p), p)).ToArray(); var compilation = Compilation.Compile(sourceTexts, moduleName, referencePaths.ToArray()); var diagnostics = compilation.Emit(outputPath); diagnostics.WriteTo(Console.Out); if (printTree) { Console.WriteLine(); compilation.WriteBoundTree(Console.Out); } if (!diagnostics.HasErrors) { Console.Out.ColorWrite($"Sucessfully created {outputPath}\n", ConsoleColor.Green); } return(0); }
/* * identity : (a:*) -> a -> a * identity [a] x = x * * echo : !((a:P) -> a -> ?a) * echo [a] x = return x * * forward : !((a:N) -> !a -> a) * forward [a] x = force x * * echo/cps : ~(a:*, a, ~a) * echo/cps ([a], x, return) = return x * * forward/cps : ~(a:*, ~a, a) * forward/cps ([a], thunk, k) = thunk k * */ public static void Main(string[] args) { var identity = Identity(); var echo = Echo(Guid.NewGuid(), Guid.NewGuid()); // TypeChecking.VerifyClosed(echo); var forward = Forward(Guid.NewGuid(), Guid.NewGuid()); // TypeChecking.VerifyClosed(forward); var echoN = new Expression <Unit, uint, ITerm <Unit, uint> >( universe: new Universe(0, Polarity.Exists), type: new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Type(new Class <Unit, uint, ITerm <Unit, uint> > .Shift( content: new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Type(new Class <Unit, uint, ITerm <Unit, uint> > .Quantifier( dependency: new Expression <Unit, uint, Unit>(new Universe(1, null), new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Universe(new Universe(0, Polarity.Exists))), Unit.Singleton), dependent: new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Type(new Class <Unit, uint, ITerm <Unit, uint> > .Quantifier( dependency: new Expression <Unit, uint, Unit>(new Universe(0, Polarity.Exists), new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Variable(0)), Unit.Singleton), dependent: new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Type(new Class <Unit, uint, ITerm <Unit, uint> > .Shift( content: new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Variable(1)))))))))))))), term: new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Constructor( initialization: new Initialization <Unit, ITerm <Unit, uint> > .Exists.Shift( body: new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Constructor( initialization: new Initialization <Unit, ITerm <Unit, uint> > .Forall.Quantifier(Unit.Singleton, body: new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Constructor( initialization: new Initialization <Unit, ITerm <Unit, uint> > .Forall.Quantifier(Unit.Singleton, body: new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Constructor( initialization: new Initialization <Unit, ITerm <Unit, uint> > .Forall.Shift( body: new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Variable(0))))))))))))))); var computation = (Value <int> .Continuation)Evaluation.Evaluate <int>(echoN); var number = computation.Content.Throw( argument: new Value <int> .Continuation(new Continuation <int>( throwF: result => { var delayed = (Value <int> .Continuation)result; return(delayed.Content.Throw( argument: new Value <int> .Pair( left: new Value <int> .Builtin <int>(4), right: new Value <int> .Continuation(Returning <int>())))); }))); Console.WriteLine("Result: " + number); Console.WriteLine(); var serializer = new Serialization <Unit, uint>( useDeclarationF: unit => new Term <Unit, uint>(new TermF <Unit, uint, ITerm <Unit, uint> > .Variable(0)), serializeBinding: _ => new Bits[0], serializeIdentifier: annotated => { return(Encoding.EncodeNumber(annotated.Expression.Term)); }); var serializer2 = new Serialization <Guid, Guid>( useDeclarationF: identifier => new Term <Guid, Guid>(new TermF <Guid, Guid, ITerm <Guid, Guid> > .Variable(identifier)), serializeBinding: identifier => new Bits[0], serializeIdentifier: annotated => { var identifier = annotated.Expression.Term; var index = annotated.Environment.IndexOf( selector: binding => { return(binding.Term.Equals(identifier) ? Match.Yes : Match.Potentially); }); return(Encoding.EncodeNumber(index)); }); var serializer3 = new Serialization <Guid, Guid>( useDeclarationF: identifier => new Term <Guid, Guid>(new TermF <Guid, Guid, ITerm <Guid, Guid> > .Variable(identifier)), serializeBinding: identifier => new Bits[0], serializeIdentifier: annotated => { var identifier = annotated.Expression.Term; var index = annotated.Environment.IndexOf( selector: binding => { if (binding.Universe.Rank != annotated.Expression.Universe.Rank) { return(Match.No); } return(binding.Term.Equals(identifier) ? Match.Yes : Match.Potentially); }); return(Encoding.EncodeNumber(index)); }); var bits = serializer.SerializeFully(echoN).ToArray(); Console.WriteLine("Size: " + bits.Length); foreach (var bit in bits) { Console.Write(bit + ", "); } Console.WriteLine(); Console.WriteLine(); var bits2 = serializer2.SerializeFully(echo).ToArray(); Console.WriteLine("Size: " + bits2.Length); foreach (var bit in bits2) { Console.Write(bit + ", "); } Console.WriteLine(); Console.WriteLine(); var bits3 = serializer3.SerializeFully(echo).ToArray(); Console.WriteLine("Size: " + bits3.Length); foreach (var bit in bits3) { Console.Write(bit + ", "); } Console.WriteLine(); Console.WriteLine(); var cps = Compilation.Compile(echo); var display = new TypeTheory.ContinuationPassing.Display <Guid>(id => id.ToString("D")[0].ToString()); Console.WriteLine(display.ToString(cps)); Console.ReadLine(); }
/// <summary> /// Emits the compilation into given <see cref="ModuleBuilder"/> using Reflection.Emit APIs. /// </summary> /// <param name="compilation">Compilation.</param> /// <param name="moduleBuilder"> /// The module builder to add the types into. Can be reused for multiple compilation units. /// </param> /// <param name="assemblyLoader"> /// Loads an assembly given an <see cref="AssemblyIdentity"/>. /// This callback is used for loading assemblies referenced by the compilation. /// <see cref="System.Reflection.Assembly.Load(AssemblyName)"/> is used if not specified. /// </param> /// <param name="assemblySymbolMapper"> /// Applied when converting assembly symbols to assembly references. /// <see cref="IAssemblySymbol"/> is mapped to its <see cref="IAssemblySymbol.Identity"/> by default. /// </param> /// <param name="cancellationToken">Can be used to cancel the emit process.</param> /// <param name="recoverOnError">If false the method returns an unsuccessful result instead of falling back to CCI writer.</param> /// <param name="compiledAssemblyImage">Assembly image, returned only if we fallback to CCI writer.</param> /// <param name="entryPoint">An entry point or null if not applicable or on failure.</param> /// <param name="diagnostics">Diagnostics.</param> /// <returns>True on success, false if a compilation error occurred or the compilation doesn't contain any code or declarations.</returns> /// <remarks> /// Reflection.Emit doesn't support all metadata constructs. If an unsupported construct is /// encountered a metadata writer that procudes uncollectible code is used instead. This is /// indicated by /// <see cref="ReflectionEmitResult.IsUncollectible"/> flag on the result. /// /// Reusing <see cref="System.Reflection.Emit.ModuleBuilder"/> may be beneficial in certain /// scenarios. For example, when emitting a sequence of code snippets one at a time (like in /// REPL). All the snippets can be compiled into a single module as long as the types being /// emitted have unique names. Reusing a single module/assembly reduces memory overhead. On /// the other hand, collectible assemblies are units of collection. Defining too many /// unrelated types in a single assemly might prevent the unused types to be collected. /// /// No need to provide a name override when using Reflection.Emit, since the assembly already /// exists. /// </remarks> /// <exception cref="InvalidOperationException">Referenced assembly can't be resolved.</exception> internal static bool Emit( this Compilation compilation, ModuleBuilder moduleBuilder, AssemblyLoader assemblyLoader, Func <IAssemblySymbol, AssemblyIdentity> assemblySymbolMapper, bool recoverOnError, DiagnosticBag diagnostics, CancellationToken cancellationToken, out MethodInfo entryPoint, out byte[] compiledAssemblyImage) { compiledAssemblyImage = default(byte[]); var moduleBeingBuilt = compilation.CreateModuleBuilder( emitOptions: EmitOptions.Default, manifestResources: null, assemblySymbolMapper: assemblySymbolMapper, testData: null, diagnostics: diagnostics, cancellationToken: cancellationToken); if (moduleBeingBuilt == null) { entryPoint = null; return(false); } if (!compilation.Compile( moduleBeingBuilt, win32Resources: null, xmlDocStream: null, generateDebugInfo: false, diagnostics: diagnostics, filterOpt: null, cancellationToken: cancellationToken)) { entryPoint = null; return(false); } Cci.IMethodReference cciEntryPoint = moduleBeingBuilt.EntryPoint; cancellationToken.ThrowIfCancellationRequested(); DiagnosticBag metadataDiagnostics = DiagnosticBag.GetInstance(); var context = new EmitContext((Cci.IModule)moduleBeingBuilt, null, metadataDiagnostics); // try emit via Reflection.Emit try { var referencedAssemblies = from referencedAssembly in compilation.GetBoundReferenceManager().GetReferencedAssemblies() let peReference = referencedAssembly.Key as PortableExecutableReference select KeyValuePair.Create( moduleBeingBuilt.Translate(referencedAssembly.Value, metadataDiagnostics), (peReference != null)?peReference.FilePath : null); entryPoint = ReflectionEmitter.Emit( context, referencedAssemblies, moduleBuilder, assemblyLoader ?? AssemblyLoader.Default, cciEntryPoint, cancellationToken); // translate metadata errors. return(compilation.FilterAndAppendAndFreeDiagnostics(diagnostics, ref metadataDiagnostics)); } catch (TypeLoadException) { // attempted to emit reference to a type that can't be loaded (has invalid metadata) } catch (NotSupportedException) { // nop } // TODO (tomat): // // Another possible approach would be to just return an error, that we can't emit via // Ref.Emit and let the user choose another method of emitting. For that we would want // to preserve the state of the Emit.Assembly object with all the compiled methods so // that the subsequent emit doesn't need to compile method bodies again. // TODO (tomat): // // If Ref.Emit fails to emit the code the type builders already created will stay // defined on the module builder. Ideally we would clean them up but Ref.Emit doesn't // provide any API to do so. In fact it also keeps baked TypeBuilders alive as well. if (!recoverOnError) { metadataDiagnostics.Free(); entryPoint = null; return(false); } using (var stream = new System.IO.MemoryStream()) { Cci.PeWriter.WritePeToStream( context, compilation.MessageProvider, stream, pdbWriterOpt: null, allowMissingMethodBodies: false, deterministic: false, cancellationToken: cancellationToken); compiledAssemblyImage = stream.ToArray(); } var compiledAssembly = Assembly.Load(compiledAssemblyImage); entryPoint = (cciEntryPoint != null) ? ReflectionEmitter.ResolveEntryPoint(compiledAssembly, cciEntryPoint, context) : null; // translate metadata errors. return(compilation.FilterAndAppendAndFreeDiagnostics(diagnostics, ref metadataDiagnostics)); }
/// <summary> /// Emits the compilation into given <see cref="ModuleBuilder"/> using Reflection.Emit APIs. /// </summary> /// <param name="compilation">Compilation.</param> /// <param name="cancellationToken">Can be used to cancel the emit process.</param> /// <param name="compiledAssemblyImage">Assembly image, returned only if we fallback to CCI writer.</param> /// <param name="entryPointTypeName">An entry point or null on failure.</param> /// <param name="entryPointMethodName">An entry point or null on failure.</param> /// <param name="diagnostics">Diagnostics.</param> /// <returns>True on success, false if a compilation error occurred or the compilation doesn't contain any code or declarations.</returns> /// <exception cref="InvalidOperationException">Referenced assembly can't be resolved.</exception> internal static bool Emit( this Compilation compilation, DiagnosticBag diagnostics, out string entryPointTypeName, out string entryPointMethodName, out byte[] compiledAssemblyImage, CancellationToken cancellationToken) { compiledAssemblyImage = null; var moduleBeingBuilt = compilation.CreateModuleBuilder( emitOptions: EmitOptions.Default, manifestResources: null, testData: null, diagnostics: diagnostics, cancellationToken: cancellationToken); if (moduleBeingBuilt == null) { entryPointTypeName = null; entryPointMethodName = null; return(false); } if (!compilation.Compile( moduleBeingBuilt, win32Resources: null, xmlDocStream: null, emittingPdb: false, diagnostics: diagnostics, filterOpt: null, cancellationToken: cancellationToken)) { entryPointTypeName = null; entryPointMethodName = null; return(false); } cancellationToken.ThrowIfCancellationRequested(); DiagnosticBag metadataDiagnostics = DiagnosticBag.GetInstance(); var context = new EmitContext((Cci.IModule)moduleBeingBuilt, null, metadataDiagnostics); using (var stream = new System.IO.MemoryStream()) { Cci.PeWriter.WritePeToStream( context, compilation.MessageProvider, () => stream, nativePdbWriterOpt: null, pdbPathOpt: null, allowMissingMethodBodies: false, deterministic: false, cancellationToken: cancellationToken); compiledAssemblyImage = stream.ToArray(); } var containingType = (Cci.INamespaceTypeReference)moduleBeingBuilt.EntryPoint.GetContainingType(context); entryPointTypeName = MetadataHelpers.BuildQualifiedName(containingType.NamespaceName, Cci.MetadataWriter.GetMangledName(containingType)); entryPointMethodName = moduleBeingBuilt.EntryPoint.Name; // translate metadata errors. return(compilation.FilterAndAppendAndFreeDiagnostics(diagnostics, ref metadataDiagnostics)); }
static int Main(string[] args) { // // Start loading in the background // Library.LoadStandardLibrariesAsync(); // // Inputs // var files = new List <string> (); var extraArgs = new List <string> (); var outName = ""; var safeMemory = false; var showHelp = false; var showVersion = false; // // Parse command line // for (int i = 0; i < args.Length;) { var a = args[i]; if (a[0] == '-') { if (a == "-o") { if (i + 1 < args.Length) { outName = args[i + 1]; i += 2; } else { i++; } } else if (a == "-h" || a == "--help" || a == "-?") { showHelp = true; i++; } else if (a == "-v" || a == "--version") { showVersion = true; i++; } else if (a == "--safe-memory") { safeMemory = true; i++; } else { extraArgs.Add(a); i++; } } else { files.Add(a); i++; } } if (showVersion) { var version = typeof(Program).Assembly.GetName().Version; Console.WriteLine($"Krueger Systems IRIL {version}"); if (!showHelp) { return(0); } } if (showHelp) { Console.WriteLine($"OVERVIEW: C/C++ to .NET assembly compiler by Frank A. Krueger"); Console.WriteLine(); Console.WriteLine($"USAGE: iril [options] <inputs>"); Console.WriteLine(); Console.WriteLine($"INPUTS: .c and .ll files"); Console.WriteLine(); Console.WriteLine($"OPTIONS:"); Console.WriteLine($" -o <asm file> Path to the assembly .dll to output"); Console.WriteLine($" -h, -?, --help Display this help"); Console.WriteLine($" -v, --version Display the version"); Console.WriteLine($" --safe-memory Verify memory accesses to make code safe from crashes"); return(0); } // // Cleanup input // if (string.IsNullOrWhiteSpace(outName) && files.Count > 0) { outName = Path.ChangeExtension(Path.GetFileName(files[0]), ".dll"); } // // Compile C Files // var clang = new ClangTool(); var cfiles = files.Where(x => clang.InputExtensions.Contains(Path.GetExtension(x))); var context = new ToolContext { InputFiles = cfiles.ToArray(), ExtraArguments = extraArgs.ToArray(), OutputFile = outName, }; var cllfiles = clang.Run(context); var llfiles = (from f in files let e = Path.GetExtension(f) where e == ".ll" || e == ".o" select f) .Concat(cllfiles) .ToList(); // // Early out // if (llfiles.Count == 0) { if (context.ExtraArguments.Contains("-c")) { return(0); } Error("No inputs"); return(1); } try { // // Parse // Info($"Parsing {llfiles.Count} files..."); var modules = llfiles.AsParallel().Select(x => { var code = File.ReadAllText(x); return(Module.Parse(code, x)); }).ToList(); // // Compile // Info("Compiling..."); var comp = new Compilation(new CompilationOptions(modules, outName, safeMemory: safeMemory)); comp.Compile(); // // Show errors // var errors = (from m in modules from e in m.Errors select e) .Concat(comp.Messages) .OrderBy(x => x.FilePath).ThenBy(x => x.Text) .ToList(); foreach (var e in errors) { Console.Write("iril: "); if (e.Type == MessageType.Error) { Console.ForegroundColor = ConsoleColor.Red; Console.Write("error: "); } else { Console.ForegroundColor = ConsoleColor.Yellow; Console.Write("warning: "); } Console.ResetColor(); if (!string.IsNullOrEmpty(e.FilePath)) { Console.ForegroundColor = ConsoleColor.Gray; Console.Write(e.FilePath); Console.Write(": "); Console.ResetColor(); } Console.WriteLine(e.Text); if (!string.IsNullOrEmpty(e.Surrounding)) { Console.WriteLine(e.Surrounding); } #if DEBUG if (e.Exception != null) { Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine(e.Exception); Console.ResetColor(); } #endif } // // Output // Info($"Writing {outName}..."); comp.WriteAssembly(outName); if (errors.Count > 0) { Info($"{errors.Count(x => x.Type == MessageType.Error)} errors, {errors.Count (x => x.Type == MessageType.Warning)} warnings"); } return(modules.Any(m => m.HasErrors) ? 3 : 0); } catch (Exception ex) { Error(ex.ToString()); return(2); } }