Example #1
0
        private GR.Memory.ByteBuffer TestAssembleC64Studio(string Source, out RetroDevStudio.Types.ASM.FileInfo Info)
        {
            RetroDevStudio.Parser.ASMFileParser parser = new RetroDevStudio.Parser.ASMFileParser();
            parser.SetAssemblerType(RetroDevStudio.Types.AssemblerType.C64_STUDIO);

            RetroDevStudio.Parser.CompileConfig config = new RetroDevStudio.Parser.CompileConfig();
            config.OutputFile = "test.prg";
            config.TargetType = RetroDevStudio.Types.CompileTargetType.PRG;
            config.Assembler  = RetroDevStudio.Types.AssemblerType.C64_STUDIO;

            bool parseResult = parser.Parse(Source, null, config, null);

            if (!parseResult)
            {
                Debug.Log("Testassemble failed:");
                foreach (var msg in parser.Messages.Values)
                {
                    Debug.Log(msg.Message);
                }
            }


            Assert.IsTrue(parseResult);
            Assert.IsTrue(parser.Assemble(config));

            Info = parser.ASMFileInfo;

            return(parser.AssembledOutput.Assembly);
        }
        bool BuildElement(DocumentInfo Doc, string ConfigSetting, string AdditionalPredefines, bool OutputMessages, out SingleBuildInfo BuildInfo, out Types.ASM.FileInfo FileInfo)
        {
            BuildInfo                       = new SingleBuildInfo();
            BuildInfo.TargetFile            = "";
            BuildInfo.TargetType            = Types.CompileTargetType.NONE;
            BuildInfo.TimeStampOfSourceFile = Core.Compiling.FileLastWriteTime(Doc.FullPath);
            BuildInfo.TimeStampOfTargetFile = default(DateTime);

            FileInfo          = null;
            Doc.LastBuildInfo = null;

            Types.ASM.FileInfo combinedFileInfo = null;

            try
            {
                if (Doc.Element != null)
                {
                    Doc.Element.CompileTarget     = Types.CompileTargetType.NONE;
                    Doc.Element.CompileTargetFile = null;

                    // check dependencies
                    foreach (var dependency in Doc.Element.ForcedDependency.DependentOnFile)
                    {
                        var project = Core.Navigating.Solution.GetProjectByName(dependency.Project);
                        if (project == null)
                        {
                            Core.AddToOutput("Could not find project \"" + dependency.Project + "\" for dependency \"" + dependency.Filename + "\" for \"" + Doc.DocumentFilename + "\"" + System.Environment.NewLine);
                            if (Core.Settings.PlaySoundOnBuildFailure)
                            {
                                System.Media.SystemSounds.Exclamation.Play();
                            }
                        }

                        ProjectElement elementDependency = project.GetElementByFilename(dependency.Filename);
                        if (elementDependency == null)
                        {
                            Core.AddToOutput("Could not find dependency \"" + dependency.Filename + "\" in project \"" + dependency.Project + "\" for \"" + Doc.DocumentFilename + "\"" + System.Environment.NewLine);
                            if (Core.Settings.PlaySoundOnBuildFailure)
                            {
                                System.Media.SystemSounds.Exclamation.Play();
                            }
                            return(false);
                        }

                        Types.ASM.FileInfo dependencyFileInfo = null;

                        // skip building if not required
                        if (!Core.Compiling.NeedsRebuild(elementDependency.DocumentInfo, ConfigSetting))
                        {
                            Core.AddToOutput("Dependency " + dependency.Filename + " is current for config " + ConfigSetting + System.Environment.NewLine);

                            if ((Doc.Type == ProjectElement.ElementType.ASM_SOURCE) ||
                                (Doc.Type == ProjectElement.ElementType.BASIC_SOURCE))
                            {
                                dependencyFileInfo = elementDependency.DocumentInfo.ASMFileInfo;
                                //Debug.Log( "Doc " + Doc.Text + " receives " + dependencyFileInfo.Labels.Count + " dependency labels from dependency " + dependency.Filename );
                            }
                        }
                        else
                        {
                            var tempInfo = new SingleBuildInfo();

                            if (!BuildElement(elementDependency.DocumentInfo, ConfigSetting, null, false, out tempInfo, out dependencyFileInfo))
                            {
                                return(false);
                            }
                        }
                        // include symbols from dependency
                        if (dependency.IncludeSymbols)
                        {
                            if (combinedFileInfo == null)
                            {
                                combinedFileInfo = new RetroDevStudio.Types.ASM.FileInfo();
                            }
                            // merge label info
                            if (dependencyFileInfo != null)
                            {
                                foreach (var entry in dependencyFileInfo.Labels)
                                {
                                    if (!combinedFileInfo.Labels.ContainsKey(entry.Key))
                                    {
                                        combinedFileInfo.Labels.Add(entry.Key, entry.Value);
                                    }
                                }
                                //Debug.Log( "Doc " + Doc.Text + " receives " + dependencyFileInfo.Labels.Count + " dependency labels from dependency " + dependency.Filename );
                            }
                        }
                    }
                }

                if (!Doc.Compilable)
                {
                    // not buildable
                    // TODO - Autoexport?
                    return(true);
                }

                ToolInfo tool = Core.DetermineTool(Doc, false);

                ProjectElement.PerConfigSettings configSetting = null;

                Parser.ParserBase parser = Core.DetermineParser(Doc);

                GR.Collections.Map <string, SingleBuildInfo> currentBuildState;

                if (ConfigSetting != null)
                {
                    lock (Doc.DeducedDependency)
                    {
                        if (!Doc.DeducedDependency.ContainsKey(ConfigSetting))
                        {
                            Doc.DeducedDependency.Add(ConfigSetting, new DependencyBuildState());
                        }
                        Doc.DeducedDependency[ConfigSetting].BuildState.Add(Doc.FullPath,
                                                                            new SingleBuildInfo()
                        {
                            TimeStampOfSourceFile = Core.Compiling.FileLastWriteTime(Doc.FullPath)
                        }
                                                                            );

                        currentBuildState = new GR.Collections.Map <string, SingleBuildInfo>(Doc.DeducedDependency[ConfigSetting].BuildState);

                        if (Doc.Element != null)
                        {
                            if (!Doc.Element.Settings.ContainsKey(ConfigSetting))
                            {
                                Doc.Element.Settings.Add(ConfigSetting, new ProjectElement.PerConfigSettings());
                            }
                            configSetting = Doc.Element.Settings[ConfigSetting];

                            if (!string.IsNullOrEmpty(configSetting.PreBuild))
                            {
                                Core.AddToOutput("Running pre build step on " + Doc.Element.Name + System.Environment.NewLine);
                                if (!Core.Executing.RunCommand(Doc, "pre build", configSetting.PreBuild))
                                {
                                    return(false);
                                }
                            }
                            if (configSetting.PreBuildChain.Active)
                            {
                                if (!BuildChain(configSetting.PreBuildChain, "pre build chain", ConfigSetting, OutputMessages))
                                {
                                    return(false);
                                }
                                AppendBuildStates(currentBuildState, Doc.DeducedDependency[ConfigSetting].BuildState);
                            }
                            Core.AddToOutput("Running build on " + Doc.Element.Name + " with configuration " + ConfigSetting + System.Environment.NewLine);
                        }
                        else
                        {
                            Core.AddToOutput("Running build on " + Doc.DocumentFilename + System.Environment.NewLine);
                        }
                    }
                }
                else
                {
                    currentBuildState = new GR.Collections.Map <string, SingleBuildInfo>();
                    Core.AddToOutput("Running build on " + Doc.DocumentFilename + System.Environment.NewLine);
                }

                // include previous symbols
                string additionalPredefines = null;
                if (parser is Parser.ASMFileParser)
                {
                    ((Parser.ASMFileParser)parser).InitialFileInfo = combinedFileInfo;
                    if (combinedFileInfo != null)
                    {
                        //Debug.Log( "Doc " + Doc.Text + " receives " + combinedFileInfo.Labels.Count + " initial labels" );
                    }
                    additionalPredefines = AdditionalPredefines;

                    /*
                     * // add pre/post build chain entries as externally included files to validate their time stamps
                     * if ( ( configSetting != null )
                     * &&   ( configSetting.PreBuildChain.Active ) )
                     * {
                     * foreach ( var chainEntry in configSetting.PreBuildChain.Entries )
                     * {
                     *  var chainProject = Core.Navigating.Solution.GetProjectByName( chainEntry.ProjectName );
                     *  if ( chainProject != null )
                     *  {
                     *    ( (Parser.ASMFileParser)parser ).ExternallyIncludedFiles.Add( chainProject.FullPath( chainEntry.DocumentFilename ) );
                     *  }
                     * }
                     * }
                     * if ( ( configSetting != null )
                     * &&   ( configSetting.PostBuildChain.Active ) )
                     * {
                     * foreach ( var chainEntry in configSetting.PostBuildChain.Entries )
                     * {
                     *  var chainProject = Core.Navigating.Solution.GetProjectByName( chainEntry.ProjectName );
                     *  if ( chainProject != null )
                     *  {
                     *    ( (Parser.ASMFileParser)parser ).ExternallyIncludedFiles.Add( chainProject.FullPath( chainEntry.DocumentFilename ) );
                     *  }
                     * }
                     * }*/
                }
                else if (parser is Parser.BasicFileParser)
                {
                    // BASIC may receive symbols from assembly
                    ((Parser.BasicFileParser)parser).InitialFileInfo = combinedFileInfo;
                    ((Parser.BasicFileParser)parser).SetBasicDialect(((Parser.BasicFileParser)parser).Settings.BASICDialect);
                    if (Doc.BaseDoc != null)
                    {
                        ((Parser.BasicFileParser)parser).Settings.UpperCaseMode = !((SourceBasicEx)Doc.BaseDoc).m_LowerCaseMode;
                    }
                    if (combinedFileInfo != null)
                    {
                        //Debug.Log( "Doc " + Doc.Text + " receives " + combinedFileInfo.Labels.Count + " initial labels" );
                    }
                    Doc.ASMFileInfo = combinedFileInfo;
                }

                parser.AssembledOutput = null;

                if ((configSetting != null) &&
                    (!string.IsNullOrEmpty(configSetting.CustomBuild)))
                {
                    Core.AddToOutput("Running custom build step on " + Doc.Element.Name + " with configuration " + ConfigSetting + System.Environment.NewLine);
                    if (!Core.Executing.RunCommand(Doc, "custom build", configSetting.CustomBuild))
                    {
                        return(false);
                    }
                    BuildInfo.TargetFile = Doc.Element.TargetFilename;
                    BuildInfo.TargetType = Doc.Element.TargetType;
                }
                else
                {
                    ProjectConfig config = null;
                    if (Doc.Project != null)
                    {
                        config = Doc.Project.Settings.Configuration(ConfigSetting);
                    }

                    int startAddress = -1;
                    if ((Doc.Type == ProjectElement.ElementType.BASIC_SOURCE) &&
                        (Doc.BaseDoc != null))
                    {
                        // BASIC files bring a start address
                        startAddress = ((SourceBasicEx)Doc.BaseDoc).StartAddress;
                        ((Parser.BasicFileParser)parser).SetBasicDialect(((SourceBasicEx)Doc.BaseDoc).BASICDialect);
                    }

                    if ((!Core.MainForm.ParseFile(parser, Doc, config, additionalPredefines, OutputMessages, CreatePreProcessedFile, CreateRelocationFile)) ||
                        (!parser.Assemble(new RetroDevStudio.Parser.CompileConfig()
                    {
                        TargetType = Core.DetermineTargetType(Doc, parser),
                        OutputFile = Core.DetermineTargetFilename(Doc, parser),
                        AutoTruncateLiteralValues = Core.Settings.ASMAutoTruncateLiteralValues,
                        StartAddress = startAddress,
                        EnabledHacks = Core.Settings.EnabledC64StudioHacks,
                        Encoding = Core.Settings.SourceFileEncoding
                    })) ||
                        (parser.Errors > 0))
                    {
                        Core.MainForm.AddOutputMessages(parser);

                        Core.AddToOutput("Build failed, " + parser.Warnings.ToString() + " warnings, " + parser.Errors.ToString() + " errors encountered" + System.Environment.NewLine);
                        // always show messages if we fail!
                        //if ( OutputMessages )
                        {
                            Core.Navigating.UpdateFromMessages(parser.Messages,
                                                               (parser is Parser.ASMFileParser) ? ((Parser.ASMFileParser)parser).ASMFileInfo : null,
                                                               Doc.Project);
                            Core.MainForm.m_CompileResult.UpdateFromMessages(parser, Doc.Project);
                        }
                        Core.ShowDocument(Core.MainForm.m_CompileResult);
                        Core.MainForm.AppState = Types.StudioState.NORMAL;

                        if (Core.Settings.PlaySoundOnBuildFailure)
                        {
                            System.Media.SystemSounds.Exclamation.Play();
                        }
                        return(false);
                    }

                    FileInfo = Doc.ASMFileInfo;

                    Core.MainForm.AddOutputMessages(parser);

                    var    compileTarget     = Core.DetermineTargetType(Doc, parser);
                    string compileTargetFile = Core.DetermineTargetFilename(Doc, parser);

                    if (ConfigSetting != null)
                    {
                        lock (Doc.DeducedDependency)
                        {
                            currentBuildState[Doc.FullPath].TargetFile = compileTargetFile;
                            currentBuildState[Doc.FullPath].TargetType = compileTarget;
                            AppendBuildStates(currentBuildState, Doc.DeducedDependency[ConfigSetting].BuildState);
                        }
                    }
                    if (Doc.Element != null)
                    {
                        Doc.Element.CompileTargetFile = compileTargetFile;
                    }


                    if (compileTargetFile == null)
                    {
                        if (parser is Parser.ASMFileParser)
                        {
                            parser.AddError(-1, Types.ErrorCode.E0001_NO_OUTPUT_FILENAME, "No output filename was given, missing element setting or !to <Filename>,<FileType> macro?");
                        }
                        else
                        {
                            parser.AddError(-1, Types.ErrorCode.E0001_NO_OUTPUT_FILENAME, "No output filename was given, missing element setting");
                        }
                        if (OutputMessages)
                        {
                            Core.Navigating.UpdateFromMessages(parser.Messages,
                                                               (parser is Parser.ASMFileParser) ? ((Parser.ASMFileParser)parser).ASMFileInfo : null,
                                                               Doc.Project);

                            Core.MainForm.m_CompileResult.UpdateFromMessages(parser, Doc.Project);
                        }
                        Core.ShowDocument(Core.MainForm.m_CompileResult);
                        Core.MainForm.AppState = Types.StudioState.NORMAL;

                        if (Core.Settings.PlaySoundOnBuildFailure)
                        {
                            System.Media.SystemSounds.Exclamation.Play();
                        }
                        return(false);
                    }
                    BuildInfo.TargetFile = compileTargetFile;
                    BuildInfo.TargetType = compileTarget;

                    Doc.LastBuildInfo = BuildInfo;

                    if (parser.Warnings > 0)
                    {
                        if (OutputMessages)
                        {
                            Core.Navigating.UpdateFromMessages(parser.Messages,
                                                               (parser is Parser.ASMFileParser) ? ((Parser.ASMFileParser)parser).ASMFileInfo : null,
                                                               Doc.Project);

                            Core.MainForm.m_CompileResult.UpdateFromMessages(parser, Doc.Project);
                        }
                        Core.ShowDocument(Core.MainForm.m_CompileResult);
                    }
                }

                if (string.IsNullOrEmpty(BuildInfo.TargetFile))
                {
                    Core.AddToOutput("No target file name specified" + System.Environment.NewLine);
                    Core.MainForm.AppState = Types.StudioState.NORMAL;
                    if (Core.Settings.PlaySoundOnBuildFailure)
                    {
                        System.Media.SystemSounds.Exclamation.Play();
                    }
                    return(false);
                }
                // write output if applicable
                if ((parser.AssembledOutput != null) &&
                    (parser.AssembledOutput.Assembly != null))
                {
                    try
                    {
                        System.IO.File.WriteAllBytes(BuildInfo.TargetFile, parser.AssembledOutput.Assembly.Data());
                    }
                    catch (System.Exception ex)
                    {
                        Core.AddToOutput("Build failed, Could not create output file " + parser.CompileTargetFile + System.Environment.NewLine);
                        Core.AddToOutput(ex.ToString() + System.Environment.NewLine);
                        Core.MainForm.AppState = Types.StudioState.NORMAL;
                        if (Core.Settings.PlaySoundOnBuildFailure)
                        {
                            System.Media.SystemSounds.Exclamation.Play();
                        }
                        return(false);
                    }

                    Core.AddToOutput("Build successful, " + parser.Warnings.ToString() + " warnings, 0 errors encountered" + System.Environment.NewLine);

                    int assemblyEndAddress = parser.AssembledOutput.OriginalAssemblyStartAddress + parser.AssembledOutput.OriginalAssemblySize - 1;
                    if (parser.AssembledOutput.OriginalAssemblySize == 0)
                    {
                        ++assemblyEndAddress;
                    }

                    Core.AddToOutput("Start address $" + parser.AssembledOutput.OriginalAssemblyStartAddress.ToString("X4")
                                     + " to $" + assemblyEndAddress.ToString("X4")
                                     + ", size " + parser.AssembledOutput.OriginalAssemblySize + " bytes" + System.Environment.NewLine);
                    Core.AddToOutput("Memory Map:" + System.Environment.NewLine);
                    if (parser.AssembledOutput.MemoryMap != null)
                    {
                        foreach (var mapEntry in parser.AssembledOutput.MemoryMap.Entries)
                        {
                            int endAddress = mapEntry.StartAddress + mapEntry.Length - 1;
                            if (mapEntry.Length == 0)
                            {
                                endAddress = mapEntry.StartAddress;
                            }
                            if (string.IsNullOrEmpty(mapEntry.Description))
                            {
                                Core.AddToOutput("  $" + mapEntry.StartAddress.ToString("X4") + " - $" + endAddress.ToString("X4") + " - unnamed section" + System.Environment.NewLine);
                            }
                            else
                            {
                                Core.AddToOutput("  $" + mapEntry.StartAddress.ToString("X4") + " - $" + endAddress.ToString("X4") + " - " + mapEntry.Description + System.Environment.NewLine);
                            }
                        }
                    }
                    Core.AddToOutput("Compiled to file " + BuildInfo.TargetFile + ", " + parser.AssembledOutput.Assembly.Length + " bytes" + System.Environment.NewLine);

                    //Debug.Log( "File " + Doc.DocumentFilename + " was rebuilt for config " + ConfigSetting + " this round" );
                }

                if ((configSetting != null) &&
                    (configSetting.PostBuildChain.Active))
                {
                    if (!BuildChain(configSetting.PostBuildChain, "post build chain", ConfigSetting, OutputMessages))
                    {
                        return(false);
                    }
                    lock (Doc.DeducedDependency)
                    {
                        AppendBuildStates(currentBuildState, Doc.DeducedDependency[ConfigSetting].BuildState);
                    }
                }

                // store combined build state info in document
                if (ConfigSetting != null)
                {
                    lock (Doc.DeducedDependency)
                    {
                        Doc.DeducedDependency[ConfigSetting].BuildState = currentBuildState;
                        Doc.DeducedDependency[ConfigSetting].BuildState.Remove(Doc.FullPath);
                    }
                }

                if ((configSetting != null) &&
                    (!string.IsNullOrEmpty(configSetting.PostBuild)))
                {
                    Core.ShowDocument(Core.MainForm.m_Output);
                    Core.AddToOutput("Running post build step on " + Doc.Element.Name + System.Environment.NewLine);
                    if (!Core.Executing.RunCommand(Doc, "post build", configSetting.PostBuild))
                    {
                        return(false);
                    }
                }

                BuildInfo.TimeStampOfTargetFile = Core.Compiling.FileLastWriteTime(BuildInfo.TargetFile);
                Doc.HasBeenSuccessfullyBuilt    = true;

                Types.ASM.FileInfo            fileInfo       = null;
                List <AutoCompleteItemInfo>   knownTokens    = null;
                MultiMap <string, SymbolInfo> knownTokenInfo = null;
                if (parser is Parser.ASMFileParser)
                {
                    fileInfo = ((Parser.ASMFileParser)parser).ASMFileInfo;
                    // update symbols in main asm file
                    knownTokens    = parser.KnownTokens();
                    knownTokenInfo = parser.KnownTokenInfo();
                }
                else if (parser is Parser.BasicFileParser)
                {
                    fileInfo = ((Parser.BasicFileParser)parser).ASMFileInfo;
                    // update symbols in main asm file
                    knownTokens    = parser.KnownTokens();
                    knownTokenInfo = parser.KnownTokenInfo();
                    //Doc.SetASMFileInfo( fileInfo, parser.KnownTokens(), parser.KnownTokenInfo() );
                }

                if (fileInfo != null)
                {
                    // spread asm info to all participating files
                    foreach (var document in Core.MainForm.DocumentInfos)
                    {
                        if (document != null)
                        {
                            if (fileInfo.ContainsFile(document.FullPath))
                            {
                                document.SetASMFileInfo(fileInfo, knownTokens, knownTokenInfo);
                            }
                        }
                    }
                }

                if (fileInfo != null)
                {
                    if (!string.IsNullOrEmpty(fileInfo.LabelDumpFile))
                    {
                        Core.MainForm.DumpLabelFile(fileInfo);
                    }
                }

                Core.Compiling.m_RebuiltFiles.Add(Doc.DocumentFilename);

                return(true);
            }
            catch (Exception ex)
            {
                Core.AddToOutput("An error occurred during building an element\r\n" + ex.ToString());
                return(false);
            }
        }