private void EnterProcedureParsing(string name)
        {
            if (m_file != null && m_file.TypeScanIncluded)
            {
                var proc = m_file.ListElements().FirstOrDefault(e => e.ElementType == FileElementType.ProcedureDeclaration && e.Name == name);
                if (proc != null)
                {
                    m_currentProcedure   = proc as FileProcedure;
                    m_currentFileElement = proc as FileElement;
                    if (((m_currentProcedure.Flags & ProcedureFlags.IsFunction) == ProcedureFlags.IsFunction) != m_procedureIsFunction)
                    {
                        throw new Exception("Procedure from type scanning is different type (procedure/function) than in the current parsing.");
                    }
                }
                else
                {
                    throw new Exception("");    // TODO: convert to parsing error (internal error).
                }
            }
            else
            {
                m_currentProcedure = new FileProcedure(m_file, m_fileElementModifier, m_elementStart.Line, null, m_currentNamespace, name);
            }
            m_currentProcedure.ReturnType = m_procedureReturnType;
            m_currentProcedure.Flags      = (m_currentProcedure.Flags & ~ProcedureFlags.IsFunction) | (m_procedureIsFunction ? ProcedureFlags.IsFunction : ProcedureFlags.None);

            m_currentFileElement = m_currentProcedure;
            m_lastProcedure      = m_currentProcedure;
            m_procedureStack.Push(m_currentProcedure);
        }
 private void ExitProcedureParsing()
 {
     m_lastProcedure = m_currentProcedure;
     if (m_file != null)
     {
         if (!m_file.TypeScanIncluded)
         {
             m_file.AddProcedure(m_currentProcedure);
         }
         m_currentProcedure.Compile(); // TODO: Maybe not called here ( and runtime code needs to be added).
     }
     m_procedureStack.Pop();           // Pop current. New current is the at the top.
     m_currentProcedure = (m_procedureStack.Count > 0) ? m_procedureStack.Peek() : null;
 }
Esempio n. 3
0
        private SBExpressionData ResolveDotIdentifierInstanceReference(SBExpressionData left, SBExpressionData right, bool includeBaseAndInterfaces)
        {
            var leftType = left.DataType.Type;
            var rightString = right.Value as string;
            if (left.DataType.DynamicType is IFileElement)
            {
                FileElement element = left.DataType.DynamicType as FileElement;
                var partner = element.ListPartners().FirstOrDefault(p => p.Name.Equals(rightString, StringComparison.InvariantCulture));

                if (partner != null)
                {
                    FileProcedure partnerProcedure = partner.ProcedureReference as FileProcedure;
                    var procType = partnerProcedure.ProcedureReferenceType;

                    MethodInfo getPartnerTyped;
                    Expression elementReference;
                    if (left.DataType.DynamicType is IFileProcedure)
                    {
                        getPartnerTyped = s_GetPartnerFromProcedure.MakeGenericMethod(partnerProcedure.DelegateType);
                        elementReference = Expression.Convert(left.ExpressionCode, typeof(IProcedureReference));
                    }
                    else
                    {
                        getPartnerTyped = s_GetPartner.MakeGenericMethod(partnerProcedure.DelegateType);
                        elementReference = Expression.Convert(left.ExpressionCode, typeof(IFileElement));
                    }

                    var getPartnerProc = Expression.Call(
                        getPartnerTyped,
                        m_currentProcedure.ContextReferenceInternal,
                        elementReference,
                        Expression.Constant(rightString));

                    return new SBExpressionData(
                        HomeType.Immediate,
                        SBExpressionType.Expression,
                        partnerProcedure.DataType,
                        getPartnerProc,
                        instance: left.ExpressionCode);     // Reference to the procedure reference
                }
            }

            foreach (var type in left.DataType.Type.SelfBasesAndInterfaces(includeBaseAndInterfaces, includeBaseAndInterfaces))
            {
                var methods = type.GetMethods().Where(mi => mi.Name == rightString).ToList();
                methods.AddRange(m_addonManager.ListExtensionMethods(left.DataType.Type, mi => mi.Name == rightString));
                var properties = type.GetProperties().Where(pi => pi.Name == rightString).ToList();

                //if (methods.Count > 0 && properties.Count > 1)
                //{
                //    throw new NotImplementedException("No handling when both methods and props are matching.");
                //}

                if (properties.Count == 1)
                {
                    return new SBExpressionData(
                        HomeType.Immediate,
                        SBExpressionType.PropertyReference,                         // Expression type
                        (TypeReference)properties[0].PropertyType,                  // Data type
                        Expression.Property(left.ExpressionCode, properties[0]),    // The property access expression
                        properties[0]);                                             // Reference to the found properties
                }
                else if (properties.Count > 1)
                {
                    throw new NotImplementedException("More than one property with same name !!!?");
                }

                if (methods.Count > 0)
                {
                    return new SBExpressionData(
                        left.ExpressionCode,                // The instance expression
                        methods);                           // Reference to the found methods
                }
            }

            if (typeof(IDynamicStepBroObject).IsAssignableFrom(left.DataType.Type))
            {
                //if (left.Value != null)
                //{
                //    var variable = left.Value as IValueContainer;
                //    IDynamicStepBroObject dynamicObject = (IDynamicStepBroObject)variable.GetValue(null);
                //    if (dynamicObject != null)
                //    {
                //        Type propType;
                //        bool isReadonly;
                //        var propSupport = dynamicObject.HasProperty(rightString, out propType, out isReadonly);
                //        if (propSupport == DynamicSupport.Yes)
                //        {
                //            return new SBExpressionData(
                //                HomeType.Immediate,
                //                isReadonly ? SBExpressionType.DynamicObjectPropertyReadonly : SBExpressionType.DynamicObjectProperty,
                //                value: rightString,                 // Name of property
                //                instance: left.ExpressionCode,      // Instance reference
                //                token: right.Token);
                //        }

                //        NamedData<Type>[] parameters;
                //        Type returnType;
                //        var methodSupport = dynamicObject.HasMethod(rightString, out parameters, out returnType);
                //        if (methodSupport == DynamicSupport.Yes)
                //        {
                //            return new SBExpressionData(
                //                HomeType.Immediate,
                //                SBExpressionType.DynamicObjectProcedure,
                //                value: rightString,                 // Name of method
                //                instance: left.ExpressionCode,      // Instance reference
                //                token: right.Token);
                //        }

                //        if (propSupport == DynamicSupport.No && methodSupport == DynamicSupport.No)
                //        {
                //            m_errors.SymanticError(right.Token.Line, right.Token.Column, false, "");
                //            // Just leave with 'unknown' to enable parsing to finish without troubles.
                //        }
                //    }
                //}

                return new SBExpressionData(
                    HomeType.Immediate,
                    SBExpressionType.DynamicObjectMember,
                    value: rightString,                 // Name of method
                    instance: left.ExpressionCode,      // Instance reference
                    token: right.Token);
            }
            if (typeof(IDynamicAsyncStepBroObject).IsAssignableFrom(left.DataType.Type))
            {
                return new SBExpressionData(
                    HomeType.Immediate,
                    SBExpressionType.DynamicAsyncObjectMember,
                    value: rightString,                 // Name of method
                    instance: left.ExpressionCode,      // Instance reference
                    token: right.Token);
            }
            return null;
        }
Esempio n. 4
0
        internal static int ParseFiles(ServiceManager services, ILogger logger, ScriptFile topfile = null)
        {
            var addons       = services.Get <IAddonManager>();
            var filesManager = services.Get <ILoadedFilesManager>();

            var filesToParse = new List <ScriptFile>();

            if (topfile != null)
            {
                filesToParse.Add(topfile);
            }
            else
            {
                filesToParse = filesManager.ListFiles <ScriptFile>().ToList();
            }
            var fileListeners  = new Dictionary <ScriptFile, StepBroListener>();
            var fileContexts   = new Dictionary <ScriptFile, SBP.CompilationUnitContext>();
            var namespaceFiles = new Dictionary <string, IdentifierInfo>();

            //==============================================================//
            #region STEP 1: PRE-SCAN ALL FILES TO OPEN ALL DEPENDENCY FILES //
            //==============================================================//
            var fileParsingStack = new Queue <ScriptFile>(filesToParse);
            while (fileParsingStack.Count > 0)
            {
                var file = fileParsingStack.Dequeue();
                file.MarkForTypeScanning();
                ITokenSource lexer  = new Grammar.StepBroLexer(file.GetParserFileStream());
                ITokenStream tokens = new CommonTokenStream(lexer);
                var          parser = new SBP(tokens);
                parser.RemoveErrorListeners();
                (file.Errors as ErrorCollector).Clear();
                parser.AddErrorListener(file.Errors as ErrorCollector);
                parser.BuildParseTree = true;
                var context = parser.compilationUnit();
                fileContexts.Add(file, context);

                if (String.IsNullOrEmpty(file.Namespace))
                {
                    file.SetNamespace(System.IO.Path.GetFileNameWithoutExtension(file.FileName));
                }

                var visitor = new StepBroTypeVisitor();
                visitor.Visit(context);

                var scanListener = new StepBroTypeScanListener(file.Namespace);
                var walker       = new ParseTreeWalker();
                walker.Walk(scanListener, context);

                if (file.Errors.ErrorCount > 0)
                {
                    continue;                               // Stop parsing this file
                }
                var parserListener = new StepBroListener(file.Errors as ErrorCollector, addons, file);
                fileListeners.Add(file, parserListener);
                var fileScanData = scanListener.GetContent();
                file.PreScanFileContent = fileScanData;

                System.Diagnostics.Debug.Assert(!String.IsNullOrEmpty(fileScanData.TopElement.Name));
                file.SetNamespace(fileScanData.TopElement.Name);    // Update the namespace from the scanning.

                foreach (var @using in fileScanData.ListUsings())
                {
                    var line = @using.Line;
                    var type = @using.Type;
                    var name = @using.Name;
                    if (type == "i" || type == "I")
                    {
                        if (!file.AddNamespaceUsing(line, name))
                        {
                            throw new Exception($"Namespace using already added ({name}).");
                        }
                    }
                    else if (type == "p" || type == "P")
                    {
                        if (!file.AddFileUsing(line, name))
                        {
                            throw new Exception($"File using already added ({name}).");
                        }
                    }
                    else
                    {
                        throw new Exception($"Unhandled using type: {type}");
                    }
                }

                file.ResolveFileUsings(
                    fu =>
                {
                    string basefolder = Path.GetDirectoryName(file.GetFullPath());
                    var fuName        = Path.GetFileName(fu);

                    // Check the already parsed or loaded files first.
                    foreach (var f in filesToParse)
                    {
                        if (!Object.ReferenceEquals(file, f) && String.Equals(fuName, f.FileName, StringComparison.InvariantCulture))
                        {
                            return(f);
                        }
                    }
                    foreach (var f in filesManager.ListFiles <ScriptFile>())
                    {
                        if (!Object.ReferenceEquals(file, f) && String.Equals(fuName, f.FileName, StringComparison.InvariantCulture))
                        {
                            fileParsingStack.Enqueue(f);
                            filesToParse.Insert(0, f);          // Put in front
                            return(f);
                        }
                    }

                    // File was not found among the already loaded files. Try loading the file.

                    string foundMatchingFile = null;

                    if (fu.Contains("["))         // It's a path using a folder shortcut.
                    {
                        throw new NotImplementedException();
                    }
                    else if (fu.Contains("\\"))         // It's a relative or absolute path
                    {
                        string path = Path.GetFullPath(Path.Combine(basefolder, fu));
                        if (System.IO.File.Exists(path))
                        {
                            foundMatchingFile = path;
                        }
                    }
                    else
                    {
                        // Start at the location of this file.
                        while (basefolder != Path.GetPathRoot(basefolder))
                        {
                            string path = Path.GetFullPath(Path.Combine(basefolder, fu));
                            if (System.IO.File.Exists(path))
                            {
                                foundMatchingFile = path;
                                break;
                            }

                            // Not found yet; try the parent folder.
                            basefolder = Path.GetDirectoryName(basefolder);
                        }
                    }

                    if (foundMatchingFile != null)
                    {
                        // Load and add file to fileParsingStack
                        object dummyUser = new object();        // The parser will set the current scriptfile as a dependant.
                        if (Main.LoadScriptFile(user: dummyUser, filepath: foundMatchingFile) is ScriptFile loadedFile)
                        {
                            loadedFile.UnregisterDependant(dummyUser);
                            fileParsingStack.Enqueue(loadedFile);
                            filesToParse.Add(loadedFile);
                            return(loadedFile);
                        }
                    }

                    return(null);       // Not found!
                }
                    );
                file.ResolveNamespaceUsings(
                    id =>
                {
                    var foundIdentifier = addons.Lookup(null, id);
                    if (foundIdentifier != null)
                    {
                        return(foundIdentifier);
                    }
                    var scriptFilesInNamespace = new List <ScriptFile>();
                    foreach (var f in filesToParse)
                    {
                        if (f.Namespace.Equals(id, StringComparison.InvariantCulture))
                        {
                            if (foundIdentifier == null)
                            {
                                foundIdentifier = new IdentifierInfo(id, id, IdentifierType.FileNamespace, null, scriptFilesInNamespace);
                            }
                            scriptFilesInNamespace.Add(f);      // More files can have same namespace.
                        }
                    }
                    if (foundIdentifier != null)
                    {
                        return(foundIdentifier);
                    }
                    foreach (var f in filesManager.ListFiles <ScriptFile>())
                    {
                        if (f.Namespace.Equals(id, StringComparison.InvariantCulture))
                        {
                            if (foundIdentifier == null)
                            {
                                foundIdentifier = new IdentifierInfo(id, id, IdentifierType.FileNamespace, null, scriptFilesInNamespace);
                            }
                            scriptFilesInNamespace.Add(f);      // Different files can have the same namespace.
                            fileParsingStack.Enqueue(f);
                            filesToParse.Insert(0, f);          // Put in front
                        }
                    }

                    return(foundIdentifier);        // Is null if not found
                }
                    );
            }
            #endregion

            //===================================================//
            #region STEP 2: COLLECT ALL THE PROCEDURE SIGNATURES //
            //===================================================//
            // TODO: Sort files after dependencies (usings)

            var beforeSorting = filesToParse;
            List <ScriptFile> sortedAfterDependencies = new List <ScriptFile>();
            var filesToCheck = new Queue <ScriptFile>(filesToParse);
            while (filesToCheck.Count > 0)
            {
                var  file   = filesToCheck.Dequeue();
                bool addNow = true;
                foreach (var fu in file.ListReferencedScriptFiles())
                {
                    if (!sortedAfterDependencies.Contains(fu))
                    {
                        filesToCheck.Enqueue(file); // Put back in queue.
                        addNow = false;
                        break;
                    }
                }
                if (addNow)
                {
                    sortedAfterDependencies.Add(file);
                }
            }
            filesToParse = sortedAfterDependencies;

            foreach (var file in filesToParse)
            {
                var fileScanData = file.PreScanFileContent;
                if (fileScanData != null)
                {
                    foreach (var element in fileScanData.TopElement.Childs)
                    {
                        var firstPropFlag  = (element.PropertyFlags != null) ? element.PropertyFlags[0] : null;
                        var accessModifier = (element.Modifiers != null && element.Modifiers.Count > 0) ? (AccessModifier)Enum.Parse(typeof(AccessModifier), element.Modifiers[0], true) : DefaultAccess;
                        switch (element.Type)
                        {
                        case FileElementType.Using:
                            break;

                        case FileElementType.Namespace:
                            file.SetNamespace(element.Name);
                            throw new Exception();

                        //break;
                        case FileElementType.EnumDeclaration:
                            break;

                        case FileElementType.ProcedureDeclaration:
                        {
                            var procedure = new FileProcedure(file, accessModifier, element.Line, null, file.Namespace, element.Name)
                            {
                                Flags           = (element.IsFunction ? ProcedureFlags.IsFunction : ProcedureFlags.None),
                                HasBody         = element.HasBody,
                                BaseElementName = firstPropFlag
                            };
                            file.AddProcedure(procedure);
                            procedure.CheckForPrototypeChange(element.Parameters, element.ReturnTypeData);
                        }
                        break;

                        case FileElementType.FileVariable:
                            break;

                        case FileElementType.TestList:
                        {
                            var testlist = new FileTestList(file, accessModifier, element.Line, null, file.Namespace, element.Name)
                            {
                                BaseElementName = firstPropFlag
                            };
                            file.AddTestList(testlist);
                        }
                        break;

                        case FileElementType.Datatable:
                            break;

                        default:
                            break;
                        }
                    }
                    file.LastTypeScan = DateTime.Now;
                }
            }
            #endregion

            //=================================================//
            #region STEP 3: PARSE ALL THE PROCEDURE SIGNATURES //
            //=================================================//
            var signaturesToParseNow = new List <Tuple <FileElement, StepBroListener> >();
            // Collect file elements to parse from _all_ files
            foreach (var file in filesToParse)
            {
                StepBroListener listener;
                if (fileListeners.TryGetValue(file, out listener))
                {
                    signaturesToParseNow.AddRange(
                        file.ListElements().Cast <FileElement>().Select(e => new Tuple <FileElement, StepBroListener>(e, listener)));
                }
            }

            // Update the lookup tables before further parsing.
            foreach (var file in filesToParse)
            {
                file.UpdateRootIdentifiers();
            }

            var numberToParse          = signaturesToParseNow.Count;
            var numberParsedLast       = int.MaxValue;
            var signaturesToParseAgain = new List <Tuple <FileElement, StepBroListener> >();
            // Continue parsing signatures until no more elements can be resolved
            while (numberToParse > 0 && numberToParse < numberParsedLast)
            {
                foreach (var d in signaturesToParseNow)
                {
                    d.Item1.ParseBaseElement();
                    if (d.Item1.ParseSignature(d.Item2, false) > 0)
                    {
                        signaturesToParseAgain.Add(d);
                    }
                }
                numberParsedLast       = signaturesToParseNow.Count;
                signaturesToParseNow   = signaturesToParseAgain;
                numberToParse          = signaturesToParseNow.Count;
                signaturesToParseAgain = new List <Tuple <FileElement, StepBroListener> >();
            }

            if (numberToParse > 0)
            {
                foreach (var d in signaturesToParseNow)
                {
                    d.Item1.ParseSignature(d.Item2, true);  // Parse again and report the errors
                }
                //throw new Exception("Not all signatures could be parsed.");     // TBD
                return(signaturesToParseNow.Count);
            }
            #endregion

            //=================================//
            #region STEP 4: PARSE ALL THE FILES #
            //=================================//
            int totalErrors = 0;
            try
            {
                foreach (var file in filesToParse)
                {
                    file.SaveCurrentFileVariables();
                    StepBroListener listener;
                    if (file.Errors.ErrorCount == 0)
                    {
                        if (fileListeners.TryGetValue(file, out listener))
                        {
                            var context = fileContexts[file];

                            try
                            {
                                var walker = new ParseTreeWalker();
                                walker.Walk(listener, context);
                            }
                            finally { }
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }
                    }
                    totalErrors += file.Errors.ErrorCount;
                    if (file.Errors.ErrorCount == 0)
                    {
                        file.InitializeFileVariables(logger);
                        file.LastParsing = DateTime.Now;
                        file.DisposeUnusedFileVariables(logger);
                    }
                }
            }
            finally
            {
                foreach (var file in filesToParse)
                {
                    file.DisposeFileStream();
                }
            }
            #endregion

            return(totalErrors);
        }