예제 #1
0
 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"));
 }
예제 #2
0
        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]"));
        }
예제 #3
0
        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);
 }
예제 #6
0
        private static Value ApplyIfDefined(OsmiumEngine engine, Symbol sym, Value value)
        {
            if (engine.System.SPreRead.HasOwnValue())
            {
                value = engine.Evaluate(engine.Expr(sym, value));
            }

            return(value);
        }
예제 #7
0
        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"));
        }
예제 #8
0
        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);
        }
예제 #10
0
 private static void AddDownValue(OsmiumEngine engine, Symbol sym, Value value, params Value[] args)
 {
     sym.DownValues.Append((engine.PatternMatching.CompilePattern(engine.Expr(sym, args)), value));
 }
예제 #11
0
        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));
            }
        }
예제 #12
0
        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 ]");
        }
예제 #13
0
        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));
        }
예제 #14
0
 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'))
                      )
         );
 }