/// <summary>The built-in Grace "print" method</summary> public GraceObject Print(EvaluationContext ctx, GraceObject arg) { Object obj = arg; var gop = arg as GraceObjectProxy; if (gop != null) { obj = gop.Object; } var go = obj as GraceObject; if (go != null) { var req = new MethodRequest(); var part = RequestPart.Nullary("asString"); req.AddPart(part); if (go.RespondsTo(req)) { obj = go.Request(ctx, req); } } GraceString gs = null; go = obj as GraceObject; if (go != null) { gs = go.FindNativeParent <GraceString>(); } if (gs != null) { obj = gs.Value.Replace("\u2028", Environment.NewLine); } sink.WriteLine("" + obj); return(GraceObject.Done); }
/// <inheritdoc /> public Method AddMinorDef(string name, GraceObject val) { var m = scope.scope as LocalScope; if (m == null) { var s = scope.next; while (s != null) { if (s.minor) { m = s.scope as LocalScope; } if (m != null) { break; } s = s.next; } if (m == null) { return(null); } } return(m.AddLocalDef(name, val)); }
private GraceObject mYieldFor(EvaluationContext ctx, GraceObject arg) { var n = arg.FindNativeParent <GraceNumber>(); if (n == null) { return(GraceObject.Done); } var sw = System.Diagnostics.Stopwatch.StartNew(); GraceObject block; object[] args; var ms = (int)(n.Double); while (sw.ElapsedMilliseconds < ms) { var delay = (int)(ms - sw.ElapsedMilliseconds); if (delay < 0) { delay = 0; } if (sink.AwaitRemoteCallback(delay, out block, out args)) { processCallback(ctx, block, args); } } return(GraceObject.Done); }
/// <inheritdoc /> public GraceObject FindReceiver(MethodRequest req, int skipRedirects) { ScopeLink sl = scope; GraceObject capture = null; while (sl != null && sl.scope != null) { if (skipRedirects > 0 && sl.scope.HasFlag(GraceObject.Flags.ObjectConstructor)) { sl = sl.next; skipRedirects--; continue; } if (sl.scope.RespondsTo(req)) { return(capture ?? sl.scope); } capture = null; var ls = sl.scope as LocalScope; if (ls != null) { if (ls.RedirectSurrounding != null) { capture = ls.RedirectSurrounding; } } sl = sl.next; } return(null); }
private static GraceObject objectFromElement(XElement root) { GraceObject obj = GraceObject.Done; var stringEl = root.XPathSelectElement("//string"); if (stringEl != null) { obj = GraceString.Create(stringEl.Value); } var numberEl = root.XPathSelectElement("//number"); if (numberEl != null) { double d; if (double.TryParse(numberEl.Value, out d)) { obj = GraceNumber.Create(d); } } var objectEl = root.XPathSelectElement("//object"); if (objectEl != null) { int objKey; if (int.TryParse(objectEl.Value, out objKey)) { obj = new GraceForeignObject(objKey); } } return(obj); }
/// <param name="next">Next element in the list, or null</param> /// <param name="scope">Grace object to be used as a scope</param> /// <param name="minor">True if this link represents a "minor" /// scope that is used for internal names</param> public ScopeLink(ScopeLink next, GraceObject scope, bool minor) { this.next = next; this.scope = scope; this.minor = minor; }
private GraceObject mAlloc(GraceObject arg) { var num = arg.FindNativeParent <GraceNumber>(); var i = (int)num.Double; return(new FixedSizeArray(i)); }
/// <summary> /// Load extensions to builtins from traits in an /// existing object. /// </summary> /// <param name="ext">Object containing extension traits.</param> public void LoadExtensionsFromObject(GraceObject ext) { var req = MethodRequest.Nullary("ObjectExtension"); req.IsInherits = true; if (ext.RespondsTo(req)) { var uo = new UserObject(); req.InheritingObject = uo; ext.Request(this, req); GraceObject.ExtendDefaultMethods(req.InheritedMethods); } req = MethodRequest.Nullary("NumberExtension"); req.IsInherits = true; if (ext.RespondsTo(req)) { var uo = new UserObject(); req.InheritingObject = uo; ext.Request(this, req); GraceNumber.ExtendWith(req.InheritedMethods); } req = MethodRequest.Nullary("StringExtension"); req.IsInherits = true; if (ext.RespondsTo(req)) { var uo = new UserObject(); req.InheritingObject = uo; ext.Request(this, req); GraceString.ExtendWith(req.InheritedMethods); } }
/// <summary>Finds the standard prelude file, loads and /// interprets it, and places the created module in scope</summary> public void LoadPrelude() { if (loadedPrelude) { return; } if (JSIL && loadedPreludeObject != null) { Extend(loadedPreludeObject); return; } string dir = Path.GetDirectoryName(typeof(Interpreter).Assembly.Location); string preludePath = Path.Combine(dir, "prelude.grace"); using (StreamReader preludeReader = File.OpenText(preludePath)) { var parser = new Parser("prelude", preludeReader.ReadToEnd()); var pt = parser.Parse() as ObjectParseNode; var eMod = new ExecutionTreeTranslator().Translate(pt); prelude = eMod.Evaluate(this); Extend(prelude); loadedPrelude = true; loadedPreludeObject = prelude; Interpreter.Debug("========== END PRELUDE =========="); } }
/// <summary>Performs set-up behaviour shared by multiple /// constructors</summary> private void initialise() { var s = new LocalScope(); scope.scope = s; majorScope = s; s.AddMethod("print(_)", new DelegateMethod1Ctx(Print)); s.AddLocalDef("true", GraceBoolean.True); s.AddLocalDef("false", GraceBoolean.False); s.AddMethod("_base_while_do(_,_)", new DelegateMethodReq(BaseWhileDo)); s.AddMethod("_base_try_catch_finally(_,_)", new DelegateMethodReq(BaseTryCatchFinally)); s.AddMethod("_base_try_catch_finally(_,_,_)", new DelegateMethodReq(BaseTryCatchFinally)); s.AddMethod("_base_try_catch_finally(_,_,_,_)", new DelegateMethodReq(BaseTryCatchFinally)); s.AddMethod("_base_try_catch_finally(_,_,_,_,_)", new DelegateMethodReq(BaseTryCatchFinally)); s.AddMethod("_base_try_catch_finally(_,_,_,_,_,_)", new DelegateMethodReq(BaseTryCatchFinally)); s.AddMethod("_base_try_catch_finally(_,_,_,_,_,_,_)", new DelegateMethodReq(BaseTryCatchFinally)); s.AddMethod("Exception", new ConstantMethod( new GraceExceptionKind("Exception"))); }
private GraceObject mParse(GraceObject code) { GraceString gs = code.FindNativeParent <GraceString>(); string s = gs.Value; var p = new Parser(s); return(new GraceObjectProxy(p.Parse())); }
/// <inheritdoc /> public Method AddDef(string name, GraceObject val) { var m = majorScope as LocalScope; if (m == null) { return(null); } return(m.AddLocalDef(name, val)); }
/// <summary>Set the majorScope field to the closest non-minor /// scope</summary> private void restoreMajor() { ScopeLink s = scope; while (s.minor) { s = s.next; } majorScope = s.scope; }
private GraceObject mSleep(GraceObject arg) { var n = arg.FindNativeParent <GraceNumber>(); if (n == null) { return(GraceObject.Done); } Thread.Sleep((int)(n.Double)); return(GraceObject.Done); }
private GraceObject mParseFile(GraceObject code) { GraceString gs = code.FindNativeParent <GraceString>(); string path = gs.Value; using (StreamReader reader = File.OpenText(path)) { var p = new Parser(reader.ReadToEnd()); return(new GraceObjectProxy(p.Parse())); } }
/// <inheritdoc /> public ReaderWriterPair AddVar(string name, GraceObject val) { var m = majorScope as LocalScope; if (m == null) { return(new ReaderWriterPair()); } var pair = m.AddLocalVar(name, val); return(pair); }
/// <summary>Native version of the built-in Grace "while-do" method /// </summary> /// <remarks>This while-do is more efficient than is possible to /// implement in bare Grace without it.</remarks> public static GraceObject BaseWhileDo(EvaluationContext ctx, MethodRequest req) { GraceObject cond = req[0].Arguments[0]; GraceObject block = req[0].Arguments[1]; MethodRequest apply = MethodRequest.Nullary("apply"); while (cond.Request(ctx, apply) == GraceBoolean.True) { block.Request(ctx, apply); } return(GraceObject.Done); }
/// <summary>Native method for Grace match</summary> /// <param name="ctx">Current interpreter</param> /// <param name="target">Target of the match</param> private GraceObject mMatch(EvaluationContext ctx, GraceObject target) { var gop = target as GraceObjectProxy; if (gop == null) { return(Matching.FailedMatch(ctx, target)); } if (gop.Object is T) { return(Matching.SuccessfulMatch(ctx, target)); } return(Matching.FailedMatch(ctx, target)); }
private GraceObject mTranslateFile(GraceObject code) { GraceString gs = code.FindNativeParent <GraceString>(); string path = gs.Value; using (StreamReader reader = File.OpenText(path)) { var p = new Parser(reader.ReadToEnd()); var module = p.Parse(); ExecutionTreeTranslator ett = new ExecutionTreeTranslator(); Node eModule = ett.Translate(module as ObjectParseNode); return(eModule); } }
/// <inheritdoc /> public void InsertOuter(GraceObject obj) { var s = scope; while (s != null) { if (s.scope.HasFlag(GraceObject.Flags.ObjectConstructor)) { break; } s = s.next; } var newScope = new ScopeLink(s.next, obj); s.next = newScope; }
/// <inheritdoc/> public bool AwaitRemoteCallback(int time, out GraceObject block, out object[] args) { Callback c; if (!callbacks.TryTake(out c, time)) { block = null; args = new object[0]; return(false); } block = c.block; args = c.args; return(true); }
private static void processResponse(XElement root) { var keyEl = root.XPathSelectElement("//key"); if (keyEl == null) { return; } int key; int.TryParse(keyEl.Value, out key); GraceObject obj = objectFromElement(root); responses[key] = obj; eventWaitHandlers[key].Set(); }
private GraceObject mAt(EvaluationContext ctx, GraceObject index) { var num = index.FindNativeParent <GraceNumber>(); var i = (int)num.Double; checkIndex(ctx, i, data); var ret = data[i]; if (ret == null) { ErrorReporting.RaiseError(ctx, "R2008", new Dictionary <string, string> { { "name", "index " + i }, { "receiver", ToString() } }, "UninitialisedReadError: Cannot read from index " + i ); } return(ret); }
private void processCallback(EvaluationContext ctx, GraceObject block, object[] args) { var lArgs = new List <GraceObject>(); foreach (var arg in args) { var gfo = arg as GraceForeignObject; if (gfo != null) { lArgs.Add(new DomObject((int)gfo.IdentifyingData, sink)); } else { lArgs.Add((GraceObject)arg); } } var req = MethodRequest.WithArgs("apply", lArgs); block.Request(ctx, req); }
private static IList <Editor.Completion> completion( GraceObject obj, string line) { var ret = new List <Editor.Completion>(); var lparenIndex = line.LastIndexOf("("); var commaIndex = line.LastIndexOf(","); var lbraceIndex = line.LastIndexOf("["); var spaceIndex = line.LastIndexOf(" "); var dotIndex = line.LastIndexOf("."); var last = Math.Max(Math.Max(Math.Max(lparenIndex, commaIndex), Math.Max(lbraceIndex, dotIndex)), spaceIndex); if (last == -1) { // Nothing to look at foreach (var k in obj.DotMethods) { if (k == "asString") { continue; } if (k.StartsWith(line)) { var append = k; var space = k.IndexOf(' '); if (space != -1) { append = k.Substring(0, space); } append = append.Substring(line.Length); ret.Add(Editor.CreateCompletion(append, k, "")); } } } else if (commaIndex == last || lbraceIndex == last || lparenIndex == last || spaceIndex == last) { // If we found one of these, ignore everything leading // up to it and make base completions for the rest. ret.AddRange(completion(obj, line.Substring(last + 1).Trim())); } else { // We end with a dot. Check for a preceding // bracket, comma, or space, and perform the // same truncation as above if applicable. var untilDot = dotIndex >= 0 ? line.Substring(0, dotIndex) : ""; var rbraceIndex = untilDot.LastIndexOf(']'); var commaIndex2 = untilDot.LastIndexOf(','); var spaceIndex2 = untilDot.LastIndexOf(' '); var rparenIndex = untilDot.LastIndexOf(')'); var m = Math.Max(Math.Max(rbraceIndex, spaceIndex2), Math.Max(commaIndex2, rparenIndex)); if (m != -1 && (m == commaIndex2 || m == spaceIndex2)) { // Rudimentary quote check - if we find one of these // with an odd number of quotation marks before it, // we retry from before the quote. if (countChars(untilDot.Substring(0, m), '"') % 2 == 1) { // Assume it's inside a quote var qIndex = untilDot.LastIndexOf('"', m); rparenIndex = untilDot.LastIndexOf(")", qIndex); commaIndex2 = untilDot.LastIndexOf(",", qIndex); rbraceIndex = untilDot.LastIndexOf("]", qIndex); spaceIndex2 = untilDot.LastIndexOf(" ", qIndex); m = Math.Max(Math.Max(rbraceIndex, spaceIndex2), Math.Max(commaIndex2, rparenIndex)); } // Update untilDot to include only the now-relevant // part of the line. if (m != -1 && (m == commaIndex2 || m == spaceIndex2)) { untilDot = untilDot.Substring(m + 1); } else if (m < lbraceIndex || m < lparenIndex) { untilDot = untilDot.Substring( Math.Max(lbraceIndex, lparenIndex) + 1); } } else if (m < lbraceIndex || m < lparenIndex) { // Start after a still-open bracket. untilDot = untilDot.Substring( Math.Max(lbraceIndex, lparenIndex) + 1); } // We will speculatively parse and execute the code, // and then examine the actual object that comes of // it. The code may have side effects, which will be // visible; it would be better to detect such code, // but the information is not presently available. if (untilDot != "") { ErrorReporting.SuppressAllErrors = true; try { var p = new Parser("tab completion", untilDot); var module = p.Parse(); var trans = new ExecutionTreeTranslator(); var mod = (ObjectConstructorNode) trans.Translate((ObjectParseNode)module); if (mod.Body.Count > 0) { var element = mod.Body[0]; var interp = new Interpreter(); interp.Extend(obj); var o = element.Evaluate(interp); // Re-run completion with the rest of the // string and the obtained object. ret.AddRange(completion(o, line.Substring(dotIndex + 1))); } } catch (Exception) { // Eat everything silently - the code isn't meant // to be running, so we don't want to report any // errors. } finally { ErrorReporting.SuppressAllErrors = false; } } } return(ret); }
/// <inheritdoc /> public void ExtendMinor(GraceObject o) { scope = new ScopeLink(scope, o, true); }
/// <inheritdoc /> public void Unextend(GraceObject o) { scope = scope.next; restoreMajor(); }
public override GraceObject Request(EvaluationContext ctx, MethodRequest req, GraceObject receiver) { var part = req[0]; var isAssign = false; if (req.Count > 1) { if (req[1].Name == ":=(_)") { part = req[1]; isAssign = true; } } object[] args = new object[part.Arguments.Count]; int i = 0; foreach (var a in part.Arguments) { var d = a as DomObject; var s = a as GraceString; if (d != null) { args[i++] = new int[1] { d.key } } ; else if (s != null) { args[i++] = s.Value; } else { args[i++] = a; } } // Request names include arities, which // the DOM doesn't understand. var name = req.Name; var idx = name.IndexOf('('); if (idx != -1) { name = name.Substring(0, idx); } if (isAssign) { return(sink.SendRPCNoResult(key, name, args)); } if (ignoredMethodResults != null) { if (ignoredMethodResults.Contains(name)) { return(sink.SendRPCNoResult(key, name, args)); } } var ret = sink.SendRPC(key, name, args); var gfo = ret as GraceForeignObject; if (gfo == null) { return(ret); } int okey = (int)gfo.IdentifyingData; return(new DomObject(okey, sink)); }
/// <summary> /// REPL-execute a given line in an interpreter, /// indicating whether it was incomplete, and /// restoring the interpreter afterwards. /// </summary> /// <param name="interp"> /// Interpreter to use /// </param> /// <param name="obj"> /// Module object where method declarations will be added. /// </param> /// <param name="memo"> /// Restoration point for the interpreter context. /// </param> /// <param name="line"> /// Line of code to execute. /// </param> /// <param name="unfinished"> /// Set to true if this line was incomplete and could not /// be executed for that reason. /// </param> /// <param name="result"> /// Result of the executed expression. /// </param> public static int RunLine(Interpreter interp, UserObject obj, Interpreter.ScopeMemo memo, string line, out bool unfinished, out GraceObject result) { result = null; ParseNode module; ObjectConstructorNode mod = null; var isExtensionTrait = false; try { var p = new Parser("source code", line); module = p.Parse(); var opm = (ObjectParseNode)module; if (opm.Body.Count == 1) { // Tricky hack to let extensions be defined interactively. var trait = opm.Body[0] as TraitDeclarationParseNode; isExtensionTrait = (trait != null && trait.Signature.Name.EndsWith("Extension")); } var trans = new ExecutionTreeTranslator(); mod = (ObjectConstructorNode)trans.Translate(opm); } catch (StaticErrorException ex) { if (ex.Code == "P1001") { // "Unexpected end of file" is expected in the // repl for unfinished statements. unfinished = true; return(1); } else { // All other errors are errors. unfinished = false; return(1); } } unfinished = false; if (mod != null) { try { // The "module" object can only really have // a single element, but we don't know whether // it's a method, statement, or expression yet. foreach (var meth in mod.Methods.Values) { obj.AddMethod(meth.Name, new Method(meth, memo)); } foreach (var node in mod.Body) { var inherits = node as InheritsNode; if (inherits != null) { var ms = inherits.Inherit(interp, obj); obj.AddMethods(ms); obj.RunInitialisers(interp); } var v = node as VarDeclarationNode; var d = node as DefDeclarationNode; Cell cell; var meths = new Dictionary <string, Method>(); if (v != null) { obj.CreateVar(v.Name, meths, v.Readable, v.Writable, out cell); obj.AddMethods(meths); if (v.Value != null) { cell.Value = v.Value.Evaluate(interp); } result = GraceObject.Done; continue; } if (d != null) { obj.CreateDef(d.Name, meths, d.Public, out cell); obj.AddMethods(meths); cell.Value = d.Value.Evaluate(interp); result = GraceObject.Done; continue; } var ret = node.Evaluate(interp); if (ret != null && ret != GraceObject.Done && ret != GraceObject.Uninitialised) { interp.Print(interp, ret); } result = ret; } if (isExtensionTrait) { interp.LoadExtensionsFromObject(obj); } } catch (GraceExceptionPacketException e) { ErrorReporting.WriteLine("Uncaught exception:"); ErrorReporting.WriteException(e.ExceptionPacket); if (e.ExceptionPacket.StackTrace != null) { foreach (var l in e.ExceptionPacket.StackTrace) { ErrorReporting.WriteLine(" from " + l); } } return(1); } finally { // No matter what happened, restore the interpreter // to as pristine a state as we can manage before // the next time. interp.RestoreExactly(memo); interp.PopCallStackTo(0); mod = null; } } return(0); }
public Callback(GraceObject _block, object[] _args) { block = _block; args = _args; }