//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // Note: Simple Singularity test program. // using System; using ProtoLisp; using Microsoft.Singularity.Channels; using Microsoft.Contracts; using Microsoft.SingSharp.Reflection; using Microsoft.Singularity.Applications; using Microsoft.Singularity.Io; using Microsoft.Singularity.Configuration; [assembly: Transform(typeof(ApplicationResourceTransform))] namespace Microsoft.Singularity.Applications { [ConsoleCategory(DefaultAction=true)] internal class Parameters { [InputEndpoint("data")] public readonly TRef Stdin; [OutputEndpoint("data")] public readonly TRef Stdout; [BoolParameter("d", Default=false, HelpMessage="Dump to debugger, no console pause")] public bool debugMode; [StringArrayParameter( "args", HelpMessage="arg bucket")] internal string[] args; reflective internal Parameters(); internal int AppMain() { return Lisp.AppMain(this); } } public class Lisp { private static bool debugMode; // Returns true if the arguments were valid, false for illegal args private static bool GetLispArgs(string[]! args, out bool helpArg, out bool traceArg, out string exprArg) { traceArg = false; helpArg = false; exprArg = ""; for (int i = 0; i < args.Length; ++i) { string! args_i = (!)args[i]; if ((args_i.Length > 0) && (args_i[0] == '/')) { string arg = args_i.Substring(1); if (arg.Equals("trace")) { traceArg = true; continue; } else if (arg.Equals("help") || arg.Equals("?")) { helpArg = true; continue; } } else { // A non-switch must be the last argument if (i == (args.Length - 1)) { exprArg = args_i; continue; } } // If we fall out, we have illegal arguments. return false; } // If we didn't abort, everything was OK return true; } internal static int AppMain(Parameters! config) { bool trace, help; string expr; debugMode = config.debugMode; string[] args = config.args; if (args == null || args.Length <= 0) { WriteLine("ProtoLisp interpreter."); WriteLine("Usage: lisp [flags] "); WriteLine("Run \"lisp /help\" or \"lisp /?\" for more details"); return 0; } bool validUsage = GetLispArgs(args, out help, out trace, out expr); if ((!validUsage) || (help)) { WriteLine("ProtoLisp is an extremely basic Lisp-like interpreter.\n"); WriteLine("Usage: lisp [flags] LISPEXPRESSION\n"); WriteLine("Flags:"); WriteLine(" /? or /help : Print this message"); WriteLine(" /trace : Print verbose traces from the interpreter\n"); WriteLine("The following classic Lisp primitives are available:\n"); WriteLine(" atom, eq, car, cdr, cons, cond\n"); WriteLine("In addition,"); WriteLine(" - Variables are lexically scoped, not dynamically scoped."); WriteLine(" - (define X Y) binds the name \"X\" to the value \"Y\""); WriteLine(" in the global context"); WriteLine(" - (lambda (ARGLIST) (BODYEXPRESSION)) creates a \"closure\" by"); WriteLine(" capturing the ambient lexical scope."); WriteLine(" - (defun NAME (ARGLIST) (BODYEXPR) is sugar for"); WriteLine(" (define NAME (lambda (ARGLIST) (BODYEXPR)))\n"); WriteLine(" - The arithmetic operators *, +, -, / are available. Math is"); WriteLine(" performed with integers."); } else { ProtoLisp.Engine engine = new ProtoLisp.Engine(); WriteLine(engine.EvalAll(expr, true, trace)); } return 0; } private static void WriteLine(string s) { Console.WriteLine(s); if (debugMode) { DebugStub.WriteLine(s); } } } }