public void Setup() { _engine = new OsmiumEngine(); _blank = _engine.Expr(_engine.Sym("System`Blank")); _blankSeq = _engine.Expr(_engine.Sym("System`BlankSequence")); _blankNullSeq = _engine.Expr(_engine.Sym("System`BlankNullSequence")); }
public void TestFullForm() { var f = _engine.Sym("f"); var x = _engine.Sym("x"); var nul = _engine.Null; Assert.AreEqual(_engine.Expr(f), _engine.Evaluate("f[]")); Assert.AreEqual(_engine.Expr(f, x), _engine.Evaluate("f[x]")); Assert.AreEqual(_engine.Expr(f, x, x), _engine.Evaluate("f[x, x]")); Assert.AreEqual(_engine.Expr(f, x, nul, x), _engine.Evaluate("f[x, , x]")); }
private static (Value, bool)? NumericOp(OsmiumEngine engine, ExpressionValue value, NumberValue identity, NumericOperations.NumericFunction op) { NumberValue nv = null; int numCount = 0; var nonNum = new List <Value>(); foreach (var part in value) { if (!(part is NumberValue numPart)) { nonNum.Add(part); continue; } numCount++; nv = nv == null ? numPart : op(nv, numPart); } if (nonNum.Count == 0) // there were no non-numbers ( 1 + 2 ) -> 3 { return(nv, true); } if (nv == null) // no number was found (x + y) { return(value, false); } if (nv.Equals(identity)) // total of numbers was the identity element ( x + y + 1 - 1 ) -> ( x + y ) { if (nonNum.Count == 1) // exactly one non-number ( x + 1 - 1 ) -> x { return(nonNum[0], true); } // multiple non-numbers, keep the Plus head return(engine.Expr(value.Head, nonNum.ToArray()), true); } if (numCount == 1) // there was exactly one number, nothing changed (x + 1) -> (x + 1) { return(value, false); } // there were multiple numbers, add the result and keep the rest (x + y + 1 + 2) -> (x + y + 3) nonNum.Add(nv); return(engine.Expr(value.Head, nonNum.ToArray()), true); }
public static (Value, bool)? Append(OsmiumEngine engine, ExpressionValue expr) { if (!expr.Head.Equals(engine.System.Append)) { return(null); } if (expr.Count != 2) { // TODO: message return(null); } var list = expr[0]; var toAppend = expr[1]; if (list is ExpressionValue e) { var newParts = new Value[e.Count + 1]; Array.Copy(e.Parts.ToArray(), newParts, e.Count); newParts[e.Count] = toAppend; return(engine.Expr(e.Head, newParts), true); } return(null); }
private static Value DoApply(OsmiumEngine engine, Value f, Value target, int lvlFrom, int lvlTo) { if (target is ExpressionValue expr) { return(engine.Expr(f, expr.Parts.ToArray())); } return(target); }
private static Value ApplyIfDefined(OsmiumEngine engine, Symbol sym, Value value) { if (engine.System.SPreRead.HasOwnValue()) { value = engine.Evaluate(engine.Expr(sym, value)); } return(value); }
public void TestSetOwnValue() { void DoSet(string lhs, string rhs) { _e.Evaluate(_e.Expr(_e.Sym("Set"), _e.Sym(lhs), _e.Sym(rhs))); } // b = x DoSet("b", "x"); Assert.AreEqual(_e.Sym("x"), ValOf("b")); // a = b DoSet("a", "b"); Assert.AreEqual(_e.Sym("x"), ValOf("a")); // b = y (* a should stay == x) DoSet("b", "y"); Assert.AreEqual(_e.Sym("x"), ValOf("a")); Assert.AreEqual(_e.Sym("y"), ValOf("b")); }
public override IEnumerable <MatchResult> Match(Value v, MatchContext context) { if (!(v is ExpressionValue expr)) { return(new MatchResult[0]); } return(_head.Match(expr.Head, context) .SelectMany(res => PatternMatching.SequenceMatch(_parts, expr.Parts, res.Context) .Select(partRes => partRes.Context.WithMatch(_engine.Expr( _engine.PatternMatching.ToSingle(res.SequenceMatch), partRes.SequenceMatch ))))); }
public static (Value, bool)? And(OsmiumEngine engine, ExpressionValue expr) { var pts = new List <Value>(); bool noChange = true; foreach (var part in expr.Parts) { var epart = engine.Evaluate(part); if (epart is Symbol sv) { if (sv == engine.System.False) { return(epart, false); } if (sv == engine.System.True) { continue; } } noChange = noChange && epart.Equals(part); pts.Add(epart); } if (pts.Count == 0) { return(engine.System.True, false); } if (pts.Count == 1) { return(pts[0], false); } return(engine.Expr(engine.System.And, pts.ToArray() ), false); }
private static void AddDownValue(OsmiumEngine engine, Symbol sym, Value value, params Value[] args) { sym.DownValues.Append((engine.PatternMatching.CompilePattern(engine.Expr(sym, args)), value)); }
static void Main(string[] args) { var prompt = true; if (prompt) { Console.WriteLine("Osmium Kernel"); } var engine = new OsmiumEngine(); while (true) { if (!engine.System.SLine.HasOwnValue()) { // $Line = 1 engine.Set(engine.System.SLine, engine.One); } if (prompt) { Console.WriteLine(); Console.Write("In[{0}]:= ", engine.System.SLine.GetValue()); } var input = Console.ReadLine(); input = (ApplyIfDefined(engine, engine.System.SPreRead, engine.Str(input)) as StringValue)?.Value ?? ""; var parsed = engine.Parse(input); if (parsed == null) { continue; } AddDownValue(engine, engine.System.InString, engine.Str(input), engine.System.SLine); AddDownValue(engine, engine.System.In, parsed, engine.System.SLine); var output = engine.Evaluate(engine.System.SPre.HasOwnValue() ? engine.Expr(engine.System.SPre, parsed) : parsed); output = ApplyIfDefined(engine, engine.System.SPost, output); AddDownValue(engine, engine.System.Out, output); engine.SetDelayed( engine.Expr(engine.System.MessageList, engine.System.SLine), engine.System.SMessageList.HasOwnValue() ? engine.System.SMessageList.GetValue() : engine.List() ); if (!output.Equals(engine.Null)) { output = ApplyIfDefined(engine, engine.System.SPrePrint, output); if (prompt) { Console.WriteLine(); Console.WriteLine("Out[{0}]= {1}", engine.System.SLine.GetValue(), output); } else { Console.WriteLine(output); } } engine.Evaluate(engine.Expr(engine.System.Increment, engine.System.SLine)); } }
public void TestBlankPattern() { // Blank[x] var form1 = _engine.Expr(_engine.Sym("Blank"), _engine.Sym("x")); // Blank[] var form2 = _blank; // x[] var expr1 = _engine.Expr(_engine.Sym("x")); // y[] var expr2 = _engine.Expr(_engine.Sym("y")); // MatchQ[ x[], _x ] -> True Assert.True(_engine.IsMatch(form1, expr1), "MatchQ[ x[], _x ]"); // MatchQ[ x[], _ ] -> True Assert.True(_engine.IsMatch(form2, expr1), "MatchQ[ x[], _ ]"); // MatchQ[ y[], _x ] -> False Assert.False(_engine.IsMatch(form1, expr2), "MatchQ[ y[], _x ]"); }
private (Value, bool) EvaluateExpression(ExpressionValue expr) { var head = Evaluate(expr.Head); // sym is just the head, if it's a symbol var sym = head as Symbol; var attrs = sym?.Attributes ?? 0; var evalFirst = true; var evalRest = true; if (attrs.HasFlag(SymbolAttributes.HoldAll) || attrs.HasFlag(SymbolAttributes.HoldAllComplete)) { evalFirst = false; evalRest = false; } if (attrs.HasFlag(SymbolAttributes.HoldFirst)) { evalFirst = false; } if (attrs.HasFlag(SymbolAttributes.HoldRest)) { evalRest = false; } var parts = new Value[expr.Count]; for (var i = 0; i < expr.Count; i++) { if ((i == 0 && evalFirst) || (i > 0 && evalRest)) { parts[i] = Evaluate(expr[i]); } else { parts[i] = expr[i]; } } ExpressionValue evaluated; if (!attrs.HasFlag(SymbolAttributes.HoldAllComplete)) { if (!attrs.HasFlag(SymbolAttributes.SequenceHold)) { parts = parts.SelectMany(FlattenHeads(_engine.System.Sequence)).ToArray(); } if (attrs.HasFlag(SymbolAttributes.Flat)) { parts = parts.SelectMany(FlattenHeads(sym)).ToArray(); } // TODO: if Listable .... // TODO: if Orderless ... evaluated = _engine.Expr(head, parts); foreach (var part in parts) { var partSym = part.AtomHead as Symbol; if (partSym == null) { continue; } var upValued = _engine.PatternMatching.FindAndApplyRule(evaluated, partSym.UpValues); if (upValued != null) { return(upValued, true); } } foreach (var part in parts) { var partSym = part.AtomHead as Symbol; var value = partSym?.UpCode?.Invoke(_engine, evaluated); if (value.HasValue) { return(value.Value); } } } else { evaluated = _engine.Expr(head, parts); } // headsym is used for *value lookup // it's the leftmost atom in the expression // (head of head of .... till we get to atom) // THIS IS DIFFERENT FROM sym DECLARED AT THE START var headsym = head.AtomHead as Symbol; if (headsym == null) { return(evaluated, false); } var downValued = _engine.PatternMatching.FindAndApplyRule(evaluated, headsym.DownValues); if (downValued != null) { return(downValued, true); } var coded = headsym.DownCode?.Invoke(_engine, evaluated); return(coded ?? (evaluated, false)); }
public override void ExitAtomGet(WolframLanguageParser.AtomGetContext context) { Push( _engine.Expr(_engine.System.Get, _engine.Str(context.GETFORM().GetText().Substring(2).TrimStart(' ', '\n', '\t', '\v', '\f')) ) ); }