Exemple #1
0
        internal static ScriptFile ParseFile(IAddonManager addonManager, string content)
        {
            if (addonManager == null)
            {
                addonManager = AddonManager.Create();
                addonManager.AddAssembly(typeof(Math).Assembly, false);
                addonManager.AddAssembly(typeof(Enumerable).Assembly, false);
            }
            addonManager.AddAssembly(AddonManager.StepBroCoreAssembly, true);   // Add StepBro.Core always.
            ITokenSource lexer  = new Grammar.StepBroLexer(new AntlrInputStream(content));
            ITokenStream tokens = new CommonTokenStream(lexer);
            var          parser = new SBP(tokens);
            var          file   = new ScriptFile();

            parser.RemoveErrorListeners();
            parser.AddErrorListener(file.Errors as ErrorCollector);
            parser.BuildParseTree = true;
            var listener = new StepBroListener(file.Errors as ErrorCollector, addonManager, file);
            var context  = parser.compilationUnit();

            var walker = new ParseTreeWalker();

            walker.Walk(listener, context);

            if (file.Errors.ErrorCount > 0)
            {
                throw new Exception("PARSING ERRORS: " + file.Errors[0].ToString());
            }

            //file?.InitializeFileVariables();
            return(file);
        }
Exemple #2
0
        internal static SBExpressionData ParsePrimary(string content, ScriptFile file = null)
        {
            ITokenSource   lexer  = new Grammar.StepBroLexer(new AntlrInputStream(content));
            ITokenStream   tokens = new CommonTokenStream(lexer);
            var            parser = new SBP(tokens);
            ErrorCollector errors = (file != null) ? file.Errors as ErrorCollector : new ErrorCollector(null, false);

            parser.AddErrorListener(errors);
            parser.BuildParseTree = true;
            StepBroListener listener = new StepBroListener(errors, null, file ?? new ScriptFile());

            listener.PrepareForExpressionParsing("StepBroFileBuilder.ParsePrimary");
            var context = parser.primary();

            ParseTreeWalker walker = new ParseTreeWalker();

            walker.Walk(listener, context);

            if (errors.ErrorCount > 0)
            {
                throw new Exception("PARSING ERRORS");
            }

            return(listener.GetExpressionResult());
        }
Exemple #3
0
        internal FileBuilder(AntlrInputStream code, IAddonManager addons = null, ScriptFile file = null)
        {
            m_file   = file;
            m_errors = new ErrorCollector(file, false);
            var lexer = new Grammar.StepBroLexer(code);

            lexer.RemoveErrorListeners();
            lexer.AddErrorListener(m_errors);
            ITokenStream tokens = new CommonTokenStream(lexer);

            m_parser = new SBP(tokens);
            m_parser.RemoveErrorListeners();
            m_parser.AddErrorListener(m_errors);
#if DEBUG
            m_parser.Interpreter.PredictionMode = PredictionMode.LL_EXACT_AMBIG_DETECTION;
#endif
            m_parser.BuildParseTree = true;
            m_listener = new StepBroListener(m_errors, addons, file);
        }
Exemple #4
0
        internal static SBExpressionData ParseLiteral(string content)
        {
            ITokenSource lexer  = new Grammar.StepBroLexer(new AntlrInputStream(content));
            ITokenStream tokens = new CommonTokenStream(lexer);
            var          parser = new SBP(tokens);
            var          errors = new ErrorCollector(null);

            parser.AddErrorListener(errors);
            parser.BuildParseTree = true;
            StepBroListener listener = new StepBroListener(errors);

            listener.PrepareForExpressionParsing("StepBroFileBuilder.ParseLiteral");
            var context = parser.literal();

            var walker = new ParseTreeWalker();

            walker.Walk(listener, context);

            return(listener.GetExpressionResult());
        }
        public override void ExitDatatableRowCell([NotNull] SBP.DatatableRowCellContext context)
        {
            var           text  = context.GetText().Trim();
            TypeReference type  = null;
            object        value = null;

            if (!String.IsNullOrEmpty(text))
            {
                // TODO: It MUST be possible to make this simpler... (e.g. re-use tokens)
                Antlr4.Runtime.ITokenSource lexer  = new Lexer(new Antlr4.Runtime.AntlrInputStream(text));
                Antlr4.Runtime.ITokenStream tokens = new Antlr4.Runtime.CommonTokenStream(lexer);
                var parser = new SBP(tokens);
                parser.RemoveErrorListeners();
                parser.AddErrorListener(m_errors);
                parser.BuildParseTree = true;
                var cellContext = parser.datatableRowCellContent();
                var walker      = new Antlr4.Runtime.Tree.ParseTreeWalker();
                m_expressionData.PushStackLevel("VariableType");
                walker.Walk(this, cellContext);
                var stack           = m_expressionData.PopStackLevel();
                var expressionValue = stack.Pop();
                if (expressionValue.IsConstant)
                {
                    type  = expressionValue.DataType;
                    value = expressionValue.Value;
                }
                else if (expressionValue.IsUnresolvedIdentifier)
                {
                    type  = new TypeReference(typeof(StepBro.Core.Data.Identifier));
                    value = expressionValue.Value;
                }
                else
                {
                    m_errors.SymanticError(context.Start.Line, context.Start.Column, false, "Error parsing cell value.");
                }
            }

            m_currentDatatableRowData.Add(new Tuple <string, TypeReference, object>(text, type, value));
        }
Exemple #6
0
        internal static void ParseKeywordProcedureCall(string content)
        {
            ITokenSource lexer  = new Grammar.StepBroLexer(new AntlrInputStream(content));
            ITokenStream tokens = new CommonTokenStream(lexer);
            var          parser = new SBP(tokens);
            var          errors = new ErrorCollector(null);

            parser.AddErrorListener(errors);
            parser.BuildParseTree = true;
            var listener = new StepBroListener(errors);
            //listener.PrepareForExpressionParsing("StepBroFileBuilder.ParseFunction");
            var context = parser.keywordProcedureCall();

            var walker = new ParseTreeWalker();

            walker.Walk(listener, context);

            if (errors.ErrorCount > 0)
            {
                throw new Exception("PARSING ERRORS");
            }
        }
Exemple #7
0
        internal static StepBroTypeScanListener.FileContent TypeScanFile(string content)
        {
            ITokenSource lexer  = new Grammar.StepBroLexer(new AntlrInputStream(content));
            ITokenStream tokens = new CommonTokenStream(lexer);
            var          parser = new SBP(tokens);
            var          errors = new ErrorCollector(null);

            parser.AddErrorListener(errors);
            parser.BuildParseTree = true;
            var listener = new StepBroTypeScanListener("Angus");     // Some random default namespace
            var context  = parser.compilationUnit();

            var walker = new ParseTreeWalker();

            walker.Walk(listener, context);

            if (errors.ErrorCount > 0)
            {
                throw new Exception("PARSING ERRORS");
            }

            return(listener.GetContent());
        }
Exemple #8
0
        internal static List <Tuple <string, TypeReference, object> > ParseDatatableRow(string content)
        {
            ErrorCollector errors = new ErrorCollector(null);
            ITokenSource   lexer  = new Grammar.StepBroLexer(new AntlrInputStream(content));
            ITokenStream   tokens = new CommonTokenStream(lexer);
            var            parser = new SBP(tokens);

            parser.AddErrorListener(errors);
            parser.BuildParseTree = true;
            StepBroListener listener = new StepBroListener(errors);
            var             context  = parser.datatableRow();

            ParseTreeWalker walker = new ParseTreeWalker();

            walker.Walk(listener, context);

            if (errors.ErrorCount > 0)
            {
                throw new Exception("PARSING ERRORS");
            }

            return(listener.GetLastDatatableRow());
        }
Exemple #9
0
        internal static Data.PropertyBlock ParsePropertyBlock(string content)
        {
            ErrorCollector errors = new ErrorCollector(null);
            ITokenSource   lexer  = new Grammar.StepBroLexer(new AntlrInputStream(content));
            ITokenStream   tokens = new CommonTokenStream(lexer);
            var            parser = new SBP(tokens);

            parser.AddErrorListener(errors);
            parser.BuildParseTree = true;
            StepBroListener listener = new StepBroListener(errors);
            var             context  = parser.elementPropertyblock();

            ParseTreeWalker walker = new ParseTreeWalker();

            walker.Walk(listener, context);

            if (errors.ErrorCount > 0)
            {
                throw new Exception("PARSING ERRORS");
            }

            return(listener.PopPropertyBlockData());
        }
Exemple #10
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);
        }