Example #1
0
 /// <summary>
 /// Compile source text into compiled codeparts.
 /// </summary>
 /// <param name="filePath">The name that should get reported to the user on
 /// runtime errors in this compiled code. Even if the text is not from an
 /// actual file this should still be a pseudo-filename for reporting, for
 /// example "(commandline)" or "(socket stream)"
 /// </param>
 /// <param name="startLineNum">Assuming scriptText is a subset of some bigger buffer, line 1 of scripttext
 /// corresponds to line (what) of the more global something, for reporting numbers on errors.</param>
 /// <param name="scriptText">The text to be compiled.</param>
 /// <param name="contextId">The name of the runtime context (i.e. "interpreter").</param>
 /// <param name="options">settings for the compile</param>
 /// <returns>The CodeParts made from the scriptText</returns>
 public abstract List<CodePart> Compile(string filePath, int startLineNum, string scriptText, string contextId, CompilerOptions options);
Example #2
0
File: CPU.cs Project: CalebJ2/KOS
        public void Boot()
        {
            // break all running programs
            currentContext = null;
            contexts.Clear();
            PushInterpreterContext();
            currentStatus = Status.Running;
            currentTime = 0;
            maxUpdateTime = 0.0;
            maxExecutionTime = 0.0;
            // clear stack (which also orphans all local variables so they can get garbage collected)
            stack.Clear();
            // clear global variables
            globalVariables.Variables.Clear();
            // clear interpreter
            if (shared.Interpreter != null) shared.Interpreter.Reset();
            // load functions
            if (shared.FunctionManager != null) shared.FunctionManager.Load();
            // load bindings
            if (shared.BindingMgr != null) shared.BindingMgr.Load();
            // Booting message
            if (shared.Screen != null)
            {
                shared.Screen.ClearScreen();
                string bootMessage = string.Format("kOS Operating System\n" + "KerboScript v{0}\n(manual at {1})\n \n" + "Proceed.\n",
                                                   SafeHouse.Version, SafeHouse.DocumentationURL);
                List<string> nags = Debug.GetPendingNags();
                if (nags.Count > 0)
                {
                    bootMessage +=
                        "##################################################\n" +
                        "#               NAG MESSAGES                     #\n" +
                        "##################################################\n" +
                        "# Further details about these important messages #\n" +
                        "# can be found in the KSP error log.  If you see #\n" +
                        "# this, then read the error log.  It's important.#\n" +
                        "--------------------------------------------------\n";

                    bootMessage = nags.Aggregate(bootMessage, (current, msg) => current + (msg + "\n"));
                    bootMessage += "##################################################\n";
                    shared.Processor.SetMode(Module.ProcessorModes.OFF);
                }
                shared.Screen.Print(bootMessage);
            }

            if (!shared.Processor.CheckCanBoot()) return;

            string filename = shared.Processor.BootFilename;
            // Check to make sure the boot file name is valid, and then that the boot file exists.
            if (string.IsNullOrEmpty(filename)) { SafeHouse.Logger.Log("Boot file name is empty, skipping boot script"); }
            else if (filename.Equals("None", StringComparison.InvariantCultureIgnoreCase)) { SafeHouse.Logger.Log("Boot file name is \"None\", skipping boot script"); }
            else if (shared.VolumeMgr.CurrentVolume.Open(filename) == null) { SafeHouse.Logger.Log(string.Format("Boot file \"{0}\" is missing, skipping boot script", filename)); }
            else
            {
                var bootContext = "program";
                string bootCommand = string.Format("run {0}.", filename);

                var options = new CompilerOptions
                {
                    LoadProgramsInSameAddressSpace = true,
                    FuncManager = shared.FunctionManager,
                    IsCalledFromRun = false
                };

                shared.ScriptHandler.ClearContext(bootContext);
                List<CodePart> parts = shared.ScriptHandler.Compile(
                    "sys:boot", 1, bootCommand, bootContext, options);

                IProgramContext programContext = SwitchToProgramContext();
                programContext.Silent = true;
                programContext.AddParts(parts);
            }
        }
Example #3
0
        public void Boot()
        {
            // break all running programs
            currentContext = null;
            contexts.Clear();
            PushInterpreterContext();
            currentStatus = Status.Running;
            currentTime = 0;
            timeWaitUntil = 0;
            maxUpdateTime = 0.0;
            maxTriggersTime = 0.0;
            maxExecutionTime = 0.0;
            // clear stack (which also orphans all local variables so they can get garbage collected)
            stack.Clear();
            // clear global variables
            globalVariables.Variables.Clear();
            // clear interpreter
            if (shared.Interpreter != null) shared.Interpreter.Reset();
            // load functions
            if (shared.FunctionManager != null) shared.FunctionManager.Load();
            // load bindings
            if (shared.BindingMgr != null) shared.BindingMgr.Load();
            // Booting message
            if (shared.Screen != null)
            {
                shared.Screen.ClearScreen();
                string bootMessage = string.Format("kOS Operating System\n" + "KerboScript v{0}\n \n" + "Proceed.\n", Core.VersionInfo);
                List<string> nags = Safe.Utilities.Debug.GetPendingNags();
                if (nags.Count > 0)
                {
                    bootMessage +=
                        "##################################################\n" +
                        "#               NAG MESSAGES                     #\n" +
                        "##################################################\n" +
                        "# Further details about these important messages #\n" +
                        "# can be found in the KSP error log.  If you see #\n" +
                        "# this, then read the error log.  It's important.#\n" +
                        "--------------------------------------------------\n";

                    bootMessage = nags.Aggregate(bootMessage, (current, msg) => current + (msg + "\n"));
                    bootMessage += "##################################################\n";
                }
                shared.Screen.Print(bootMessage);
            }

            if (shared.VolumeMgr == null) { SafeHouse.Logger.Log("No volume mgr"); }
            else if (!shared.VolumeMgr.CheckCurrentVolumeRange(shared.Vessel)) { SafeHouse.Logger.Log("Boot volume not in range"); }
            else if (shared.VolumeMgr.CurrentVolume == null) { SafeHouse.Logger.Log("No current volume"); }
            else if (shared.ScriptHandler == null) { SafeHouse.Logger.Log("No script handler"); }
            else
            {
                string filename = shared.Processor.BootFilename;
                // Check to make sure the boot file name is valid, and then that the boot file exists.
                if (String.IsNullOrEmpty(filename)) { SafeHouse.Logger.Log("Boot file name is empty, skipping boot script"); }
                else if (filename.Equals("None", StringComparison.InvariantCultureIgnoreCase)) { SafeHouse.Logger.Log("Boot file name is \"None\", skipping boot script"); }
                else if (shared.VolumeMgr.CurrentVolume.GetByName(filename) == null) { SafeHouse.Logger.Log(String.Format("Boot file \"{0}\" is missing, skipping boot script", filename)); }
                else
                {
                    string filePath = shared.VolumeMgr.GetVolumeRawIdentifier(shared.VolumeMgr.CurrentVolume) + "/" + filename;
                    shared.ScriptHandler.ClearContext("program");
                    var programContext = ((CPU)shared.Cpu).SwitchToProgramContext();
                    programContext.Silent = true;
                    var options = new CompilerOptions { LoadProgramsInSameAddressSpace = true };
                    List<CodePart> parts = shared.ScriptHandler.Compile(
                        filePath, 1, String.Format("run {0}.", filename), "program", options);
                    programContext.AddParts(parts);
                }
            }
        }
Example #4
0
File: CPU.cs Project: KSP-KOS/KOS
        public void Boot()
        {
            // break all running programs
            currentContext = null;
            contexts.Clear();
            PushInterpreterContext();
            currentRunSection = Section.Main;
            currentTime = 0;
            maxUpdateTime = 0.0;
            maxExecutionTime = 0.0;
            // clear stack (which also orphans all local variables so they can get garbage collected)
            stack.Clear();
            // clear global variables
            globalVariables.Variables.Clear();
            // clear interpreter
            if (shared.Interpreter != null) shared.Interpreter.Reset();
            // load functions
            if (shared.FunctionManager != null) shared.FunctionManager.Load();
            // load bindings
            if (shared.BindingMgr != null) shared.BindingMgr.Load();
            // Booting message
            if (shared.Screen != null)
            {
                shared.Screen.ClearScreen();
                string bootMessage = string.Format("kOS Operating System\n" + "KerboScript v{0}\n(manual at {1})\n \n" + "Proceed.\n",
                                                   SafeHouse.Version, SafeHouse.DocumentationURL);
                List<string> nags = Debug.GetPendingNags();
                if (nags.Count > 0)
                {
                    bootMessage +=
                        "##################################################\n" +
                        "#               NAG MESSAGES                     #\n" +
                        "##################################################\n" +
                        "# Further details about these important messages #\n" +
                        "# can be found in the KSP error log.  If you see #\n" +
                        "# this, then read the error log.  It's important.#\n" +
                        "--------------------------------------------------\n";

                    bootMessage = nags.Aggregate(bootMessage, (current, msg) => current + (msg + "\n"));
                    bootMessage += "##################################################\n";
                    shared.Processor.SetMode(Module.ProcessorModes.OFF);
                }
                shared.Screen.Print(bootMessage);
            }

            if (!shared.Processor.CheckCanBoot()) return;

            VolumePath path = shared.Processor.BootFilePath;
            // Check to make sure the boot file name is valid, and then that the boot file exists.
            if (path == null)
            {
                SafeHouse.Logger.Log("Boot file name is empty, skipping boot script");
            }
            else
            {
                // Boot is only called once right after turning the processor on,
                // the volume cannot yet have been changed from that set based on
                // Config.StartOnArchive, and Processor.CheckCanBoot() has already
                // handled the range check for the archive.
                Volume sourceVolume = shared.VolumeMgr.CurrentVolume;
                var file = shared.VolumeMgr.CurrentVolume.Open(path);
                if (file == null)
                {
                    SafeHouse.Logger.Log(string.Format("Boot file \"{0}\" is missing, skipping boot script", path));
                }
                else
                {
                    var bootContext = "program";

                    string bootCommand = string.Format("run \"{0}\".", file.Path);

                    var options = new CompilerOptions
                    {
                        LoadProgramsInSameAddressSpace = true,
                        FuncManager = shared.FunctionManager,
                        IsCalledFromRun = false
                    };

                    shared.ScriptHandler.ClearContext(bootContext);
                    List<CodePart> parts = shared.ScriptHandler.Compile(new BootGlobalPath(bootCommand),
                        1, bootCommand, bootContext, options);

                    IProgramContext programContext = SwitchToProgramContext();
                    programContext.Silent = true;
                    programContext.AddParts(parts);
                }
            }
        }
Example #5
0
        protected void CompileCommand(string commandText)
        {
            if (Shared.ScriptHandler == null) return;

            try
            {
                CompilerOptions options = new CompilerOptions
                {
                    LoadProgramsInSameAddressSpace = false,
                    FuncManager = Shared.FunctionManager,
                    IsCalledFromRun = false
                };

                List<CodePart> commandParts = Shared.ScriptHandler.Compile("interpreter history", commandHistoryIndex, commandText, "interpreter", options);
                if (commandParts == null) return;

                var interpreterContext = ((CPU)Shared.Cpu).GetInterpreterContext();
                interpreterContext.AddParts(commandParts);
            }
            catch (Exception e)
            {
                if (Shared.Logger != null)
                {
                    Shared.Logger.Log(e);
                }
            }
        }
Example #6
0
File: Misc.cs Project: gisikw/KOS
        public override void Execute(SharedObjects shared)
        {
            // run() is strange.  It needs two levels of args - the args to itself, and the args it is meant to
            // pass on to the program it's invoking.  First, these are the args to run itself:
            object volumeId = PopValueAssert(shared, true);
            string fileName = PopValueAssert(shared, true).ToString();
            AssertArgBottomAndConsume(shared);

            // Now the args it is going to be passing on to the program:
            var progArgs = new List<Object>();
            int argc = CountRemainingArgs(shared);
            for (int i = 0; i < argc; ++i)
                progArgs.Add(PopValueAssert(shared, true));
            AssertArgBottomAndConsume(shared);

            if (shared.VolumeMgr == null) return;
            if (shared.VolumeMgr.CurrentVolume == null) throw new Exception("Volume not found");

            ProgramFile file = shared.VolumeMgr.CurrentVolume.GetByName(fileName, true);
            if (file == null) throw new Exception(string.Format("File '{0}' not found", fileName));
            if (shared.ScriptHandler == null) return;

            if (volumeId != null)
            {
                Volume targetVolume = shared.VolumeMgr.GetVolume(volumeId);
                if (targetVolume != null)
                {
                    if (shared.ProcessorMgr != null)
                    {
                        string filePath = string.Format("{0}/{1}", shared.VolumeMgr.GetVolumeRawIdentifier(targetVolume), fileName);
                        var options = new CompilerOptions { LoadProgramsInSameAddressSpace = true, FuncManager = shared.FunctionManager };
                        List<CodePart> parts = shared.ScriptHandler.Compile(filePath, 1, file.StringContent, "program", options);
                        var builder = new ProgramBuilder();
                        builder.AddRange(parts);
                        List<Opcode> program = builder.BuildProgram();
                        shared.ProcessorMgr.RunProgramOn(program, targetVolume);
                    }
                }
                else
                {
                    throw new KOSFileException("Volume not found");
                }
            }
            else
            {
                // clear the "program" compilation context
                shared.ScriptHandler.ClearContext("program");
                string filePath = shared.VolumeMgr.GetVolumeRawIdentifier(shared.VolumeMgr.CurrentVolume) + "/" + fileName;
                var options = new CompilerOptions { LoadProgramsInSameAddressSpace = true, FuncManager = shared.FunctionManager };
                var programContext = ((CPU)shared.Cpu).SwitchToProgramContext();

                List<CodePart> codeParts;
                if (file.Category == FileCategory.KSM)
                {
                    string prefix = programContext.Program.Count.ToString();
                    codeParts = shared.VolumeMgr.CurrentVolume.LoadObjectFile(filePath, prefix, file.BinaryContent);
                }
                else
                {
                    try
                    {
                        codeParts = shared.ScriptHandler.Compile(filePath, 1, file.StringContent, "program", options);
                    }
                    catch (Exception)
                    {
                        // If it died due to a compile error, then we won't really be able to switch to program context
                        // as was implied by calling Cpu.SwitchToProgramContext() up above.  The CPU needs to be
                        // told that it's still in interpreter context, or else it fails to advance the interpreter's
                        // instruction pointer and it will just try the "call run()" instruction again:
                        shared.Cpu.BreakExecution(false);
                        throw;
                    }
                }
                programContext.AddParts(codeParts);
            }

            // Because run() returns FIRST, and THEN the CPU jumps to the new program's first instruction that it set up,
            // it needs to put the return stack in a weird order.  Its return value needs to be buried UNDER the args to the
            // program it's calling:
            UsesAutoReturn = false;

            shared.Cpu.PushStack(0); // dummy return that all functions have.

            // Put the args for the program being called back on in the same order they were in before (so read the list backward):
            shared.Cpu.PushStack(new KOSArgMarkerType());
            for (int i = argc - 1; i >= 0; --i)
                shared.Cpu.PushStack(progArgs[i]);
        }
Example #7
0
File: Misc.cs Project: gisikw/KOS
        public override void Execute(SharedObjects shared)
        {
            bool defaultOutput = false;
            bool justCompiling = false; // is this load() happening to compile, or to run?
            string fileNameOut = null;
            object topStack = PopValueAssert(shared, true); // null if there's no output file (output file means compile, not run).
            if (topStack != null)
            {
                justCompiling = true;
                string outputArg = topStack.ToString();
                if (outputArg.Equals("-default-compile-out-"))
                    defaultOutput = true;
                else
                    fileNameOut = PersistenceUtilities.CookedFilename(outputArg, Volume.KOS_MACHINELANGUAGE_EXTENSION);
            }

            string fileName = null;
            topStack = PopValueAssert(shared, true);
            if (topStack != null)
                fileName = topStack.ToString();

            AssertArgBottomAndConsume(shared);

            if (fileName == null)
                throw new KOSFileException("No filename to load was given.");

            ProgramFile file = shared.VolumeMgr.CurrentVolume.GetByName(fileName, (!justCompiling)); // if running, look for KSM first.  If compiling look for KS first.
            if (file == null) throw new KOSFileException(string.Format("Can't find file '{0}'.", fileName));
            fileName = file.Filename; // just in case GetByName picked an extension that changed it.

            // filename is now guaranteed to have an extension.  To make default output name, replace the extension with KSM:
            if (defaultOutput)
                fileNameOut = fileName.Substring(0, fileName.LastIndexOf('.')) + "." + Volume.KOS_MACHINELANGUAGE_EXTENSION;

            if (fileNameOut != null && fileName == fileNameOut)
                throw new KOSFileException("Input and output filenames must differ.");

            if (shared.VolumeMgr == null) return;
            if (shared.VolumeMgr.CurrentVolume == null) throw new KOSFileException("Volume not found");

            if (shared.ScriptHandler != null)
            {
                var options = new CompilerOptions { LoadProgramsInSameAddressSpace = true, FuncManager = shared.FunctionManager };
                string filePath = shared.VolumeMgr.GetVolumeRawIdentifier(shared.VolumeMgr.CurrentVolume) + "/" + fileName;
                // add this program to the address space of the parent program,
                // or to a file to save:
                if (justCompiling)
                {
                    List<CodePart> compileParts = shared.ScriptHandler.Compile(filePath, 1, file.StringContent, String.Empty, options);
                    bool success = shared.VolumeMgr.CurrentVolume.SaveObjectFile(fileNameOut, compileParts);
                    if (!success)
                    {
                        throw new KOSFileException("Can't save compiled file: not enough space or access forbidden");
                    }
                }
                else
                {
                    var programContext = ((CPU)shared.Cpu).SwitchToProgramContext();
                    List<CodePart> parts;
                    if (file.Category == FileCategory.KSM)
                    {
                        string prefix = programContext.Program.Count.ToString();
                        parts = shared.VolumeMgr.CurrentVolume.LoadObjectFile(filePath, prefix, file.BinaryContent);
                    }
                    else
                    {
                        parts = shared.ScriptHandler.Compile(filePath, 1, file.StringContent, "program", options);
                    }
                    int programAddress = programContext.AddObjectParts(parts);
                    // push the entry point address of the new program onto the stack
                    shared.Cpu.PushStack(programAddress);
                }
            }
        }
Example #8
0
File: Misc.cs Project: KSP-KOS/KOS
        public override void Execute(SharedObjects shared)
        {
            // NOTE: The built-in load() function actually ends up returning
            // two things on the stack: on top is a boolean for whether the program
            // was already loaded, and under that is an integer for where to jump to
            // to call it.  The load() function is NOT meant to be called directly from
            // a user script.
            // (unless it's being called in compile-only mode, in which case it
            // returns the default dummy zero on the stack like everything else does).

            bool defaultOutput = false;
            bool justCompiling = false; // is this load() happening to compile, or to run?
            GlobalPath outPath = null;
            object topStack = PopValueAssert(shared, true); // null if there's no output file (output file means compile, not run).
            if (topStack != null)
            {
                justCompiling = true;
                string outputArg = topStack.ToString();
                if (outputArg.Equals("-default-compile-out-"))
                    defaultOutput = true;
                else
                    outPath = shared.VolumeMgr.GlobalPathFromObject(outputArg);
            }

            object skipAlreadyObject = PopValueAssert(shared, false);
            bool skipIfAlreadyCompiled = (skipAlreadyObject is bool) ? (bool)skipAlreadyObject : false;

            object pathObject = PopValueAssert(shared, true);

            AssertArgBottomAndConsume(shared);

            if (pathObject == null)
                throw new KOSFileException("No filename to load was given.");

            GlobalPath path = shared.VolumeMgr.GlobalPathFromObject(pathObject);
            Volume volume = shared.VolumeMgr.GetVolumeFromPath(path);

            VolumeFile file = volume.Open(path, !justCompiling) as VolumeFile; // if running, look for KSM first.  If compiling look for KS first.
            if (file == null) throw new KOSFileException(string.Format("Can't find file '{0}'.", path));
            path = GlobalPath.FromVolumePath(file.Path, shared.VolumeMgr.GetVolumeId(volume));

            if (skipIfAlreadyCompiled && !justCompiling)
            {
                var programContext = ((CPU)shared.Cpu).SwitchToProgramContext();
                int programAddress = programContext.GetAlreadyCompiledEntryPoint(path.ToString());
                if (programAddress >= 0)
                {
                    // TODO - The check could also have some dependancy on whether the file content changed on
                    //     disk since last time, but that would also mean having to have a way to clear out the old
                    //     copy of the compiled file from the program context, which right now doesn't exist. (Without
                    //     that, doing something like a loop that re-wrote a file and re-ran it 100 times would leave
                    //     100 old dead copies of the compiled opcodes in memory, only the lastmost copy being really used.)

                    // We're done here.  Skip the compile.  Point the caller at the already-compiled version.
                    shared.Cpu.PushStack(programAddress);
                    this.ReturnValue = true; // tell caller that it already existed.
                    return;
                }
            }

            FileContent fileContent = file.ReadAll();

            // filename is now guaranteed to have an extension.  To make default output name, replace the extension with KSM:
            if (defaultOutput)
                outPath = path.ChangeExtension(Volume.KOS_MACHINELANGUAGE_EXTENSION);

            if (path.Equals(outPath))
                throw new KOSFileException("Input and output paths must differ.");

            if (shared.VolumeMgr == null) return;
            if (shared.VolumeMgr.CurrentVolume == null) throw new KOSFileException("Volume not found");

            if (shared.ScriptHandler != null)
            {
                shared.Cpu.StartCompileStopwatch();
                var options = new CompilerOptions { LoadProgramsInSameAddressSpace = true, FuncManager = shared.FunctionManager };
                // add this program to the address space of the parent program,
                // or to a file to save:
                if (justCompiling)
                {
                    // since we've already read the file content, use the volume from outPath instead of the source path
                    volume = shared.VolumeMgr.GetVolumeFromPath(outPath);
                    List<CodePart> compileParts = shared.ScriptHandler.Compile(path, 1, fileContent.String, string.Empty, options);
                    VolumeFile written = volume.SaveFile(outPath, new FileContent(compileParts));
                    if (written == null)
                    {
                        throw new KOSFileException("Can't save compiled file: not enough space or access forbidden");
                    }
                }
                else
                {
                    var programContext = ((CPU)shared.Cpu).SwitchToProgramContext();
                    List<CodePart> parts;
                    if (fileContent.Category == FileCategory.KSM)
                    {
                        string prefix = programContext.Program.Count.ToString();
                        parts = fileContent.AsParts(path, prefix);
                    }
                    else
                    {
                        parts = shared.ScriptHandler.Compile(path, 1, fileContent.String, "program", options);
                    }
                    int programAddress = programContext.AddObjectParts(parts, path.ToString());
                    // push the entry point address of the new program onto the stack
                    shared.Cpu.PushStack(programAddress);
                    this.ReturnValue = false; // did not already exist.
                }
                shared.Cpu.StopCompileStopwatch();
            }
        }
Example #9
0
 /// <summary>
 /// Compile source text into compiled codeparts.
 /// </summary>
 /// <param name="filePath">The name that should get reported to the user on
 /// runtime errors in this compiled code. Even if the text is not from an
 /// actual file this should still be a pseudo-filename for reporting, for
 /// example "(commandline)" or "(socket stream)"
 /// </param>
 /// <param name="startLineNum">Assuming scriptText is a subset of some bigger buffer, line 1 of scripttext
 /// corresponds to line (what) of the more global something, for reporting numbers on errors.</param>
 /// <param name="scriptText">The text to be compiled.</param>
 /// <param name="contextId">The name of the runtime context (i.e. "interpreter").</param>
 /// <param name="options">settings for the compile</param>
 /// <returns>The CodeParts made from the scriptText</returns>
 public abstract List <CodePart> Compile(string filePath, int startLineNum, string scriptText, string contextId, CompilerOptions options);