예제 #1
0
파일: NeoInt.cs 프로젝트: sci4me/Neo-old
 static NeoInt()
 {
     for (var i = 0; i < cache.Length; i++)
     {
         cache[i] = new NeoInt(i - HALF_CACHE_SIZE);
     }
 }
예제 #2
0
 public static NeoValue Int(NeoValue[] args)
 {
     if (args.Length != 1)
     {
         throw new NeoError("int expects a single numeric argument");                              // @TODO @Untested
     }
     return(NeoInt.ValueOf(args[0].CheckNumber().CastToInt()));
 }
예제 #3
0
        public void VisitForKeyValueIterator(ForKeyValueIteratorNode node)
        {
            UpdateLine(node);
            PushScope();

            asm.Declare(node.Key.Value, VariableFlags.NONE);
            asm.MarkLocal(node.Value.Value);
            asm.Declare(node.Value.Value, VariableFlags.NONE);
            asm.MarkLocal(node.Key.Value);

            var idx = "__idx_" + Guid.NewGuid().ToString("n");

            asm.Declare(idx, VariableFlags.NONE);
            asm.MarkLocal(idx);
            asm.PushConstant(NeoInt.ValueOf(0));
            asm.SetLocal(idx);

            var from = "__from_" + Guid.NewGuid().ToString("n");

            asm.Declare(from, VariableFlags.NONE);
            asm.MarkLocal(from);
            node.From.Accept(this);
            asm.SetLocal(from);

            var start = asm.NewLabel();

            asm.MarkLabel(start);
            asm.GetLocal(idx);
            asm.GetLocal(from);
            asm.Length();
            asm.Eq();
            var end = asm.NewLabel();

            PushLoop(start, end, start);
            asm.Branch(end);
            asm.GetLocal(from);
            asm.GetLocal(idx);
            asm.ObjectIndex();
            asm.SetLocal(node.Value.Value);
            asm.SetLocal(node.Key.Value);
            asm.GetLocal(idx);
            asm.Inc();
            asm.SetLocal(idx);
            PreLoopCode(node.Code);
            node.Code.Accept(this);
            PostLoopCode(node.Code);
            asm.Jump(start);
            asm.MarkLabel(end);
            PopLoop();

            PopScope();
        }
예제 #4
0
        public static NeoValue ToByte(NeoValue[] args)
        {
            if (args.Length != 1)
            {
                throw new NeoError("byte expects a single string parameter");                      // @TODO @Untested
            }
            var str = args[0].CheckString().Value;

            if (str.Length != 1)
            {
                throw new NeoError($"byte expects its parameter to be of length 1, got {str.Length}");                     // @TODO @Untested
            }
            return(NeoInt.ValueOf(str[0]));
        }
예제 #5
0
파일: FFILib.cs 프로젝트: sci4me/Neo-old
 public static NeoValue ToNeo(object v)
 {
     if (v == null)
     {
         return(NeoNil.NIL);
     }
     else if (v is Int32 i)
     {
         return(NeoInt.ValueOf(i));
     }
     else if (v is Int64 l)
     {
         return(NeoInt.ValueOf((int)l));
     }
     else if (v is Single f)
     {
         return(NeoFloat.ValueOf(f));
     }
     else if (v is Double d)
     {
         return(NeoFloat.ValueOf(d));
     }
     else if (v is Boolean b)
     {
         return(NeoBool.ValueOf(b));
     }
     else if (v is String s)
     {
         return(NeoString.ValueOf(s));
     }
     else if (v is object[] a)
     {
         // @TODO: is this where we want to do this? or do we just want an FFITypeProxy?
         var r = new NeoArray();
         foreach (object o in a)
         {
             r.Insert(ToNeo(o));
         }
         return(r);
     }
     else if (v is Dictionary <object, object> m)
     {
         throw new NotImplementedException();
     }
     else
     {
         return(new FFITypeProxy(v));
     }
 }
예제 #6
0
        public void VisitEnum(EnumNode node)
        {
            UpdateLine(node);
            asm.NewObject();

            var elements = node.Elements.ToArray();

            for (var i = 0; i < elements.Length; i++)
            {
                asm.Dup();
                asm.PushConstant(NeoString.ValueOf(elements[i]));
                asm.PushConstant(NeoInt.ValueOf(i));
                asm.Set();

                asm.Dup();
                asm.PushConstant(NeoInt.ValueOf(i));
                asm.PushConstant(NeoString.ValueOf(elements[i]));
                asm.Set();
            }

            asm.Frozen();
        }
예제 #7
0
파일: Procedure.cs 프로젝트: sci4me/Neo-old
        internal Procedure(BinaryReader reader)
        {
            Name     = reader.ReadString();
            Exported = reader.ReadBoolean();

            UpValues = new string[reader.ReadInt32()];
            for (var i = 0; i < UpValues.Length; i++)
            {
                UpValues[i] = reader.ReadString();
            }

            Parameters = new Parameter[reader.ReadInt32()];
            for (var i = 0; i < Parameters.Length; i++)
            {
                Parameters[i] = new Parameter(reader.ReadString(), reader.ReadBoolean());
            }

            Varargs = reader.ReadBoolean();

            Lines = new LineRange[reader.ReadInt32()];
            for (var i = 0; i < Lines.Length; i++)
            {
                Lines[i] = new LineRange(reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32());
            }

            Line = reader.ReadInt32();

            Instructions = new byte[reader.ReadInt32()];
            for (var i = 0; i < Instructions.Length; i++)
            {
                Instructions[i] = reader.ReadByte();
            }

            Constants = new NeoValue[reader.ReadInt32()];
            for (var i = 0; i < Constants.Length; i++)
            {
                var type = reader.ReadByte();
                switch (type)
                {
                case (byte)ConstantType.STRING:
                    Constants[i] = NeoString.ValueOf(reader.ReadString());
                    break;

                case (byte)ConstantType.INT:
                    Constants[i] = NeoInt.ValueOf(reader.ReadInt32());
                    break;

                case (byte)ConstantType.FLOAT:
                    Constants[i] = NeoFloat.ValueOf(reader.ReadDouble());
                    break;

                default:
                    throw new Exception("invalid chunk");
                }
            }

            Procedures = new Procedure[reader.ReadInt32()];
            for (var i = 0; i < Procedures.Length; i++)
            {
                Procedures[i] = new Procedure(reader);
            }
        }
예제 #8
0
 public static NeoValue Read(NeoValue[] args)
 {
     return(NeoInt.ValueOf(Console.Read()));
 }
예제 #9
0
 public void VisitInt(IntNode node)
 {
     UpdateLine(node);
     asm.PushConstant(NeoInt.ValueOf(node.Value));
 }
예제 #10
0
        public void VisitForRange(ForRangeNode node)
        {
            UpdateLine(node);
            PushScope();

            asm.Declare(node.Iterator.Value, VariableFlags.NONE);
            node.Start.Accept(this);
            asm.MarkLocal(node.Iterator.Value);
            asm.SetLocal(node.Iterator.Value);

            var endValue = "__end_" + Guid.NewGuid().ToString("n");

            asm.Declare(endValue, VariableFlags.FINAL);
            node.End.Accept(this);
            asm.MarkLocal(endValue);
            asm.SetLocal(endValue);

            var byValue = "__by_" + Guid.NewGuid().ToString("n");

            asm.Declare(byValue, VariableFlags.FINAL);
            if (node.By != null)
            {
                node.By.Accept(this);
            }
            else
            {
                asm.PushConstant(NeoInt.ValueOf(1));
            }
            asm.MarkLocal(byValue);
            asm.SetLocal(byValue);

            var cmpValue = "__cmp_" + Guid.NewGuid().ToString("n");

            asm.Declare(cmpValue, VariableFlags.NONE);
            asm.MarkLocal(cmpValue);
            asm.PushConstant(NeoInt.ValueOf(1));
            asm.SetLocal(cmpValue);

            var skip = asm.NewLabel();

            asm.GetLocal(byValue);
            asm.PushConstant(NeoInt.ValueOf(0));
            asm.Lte();
            asm.Branch(skip);
            asm.PushConstant(NeoInt.ValueOf(-1));
            asm.SetLocal(cmpValue);
            asm.MarkLabel(skip);

            var start = asm.NewLabel();

            asm.MarkLabel(start);
            asm.GetLocal(node.Iterator.Value);
            asm.GetLocal(endValue);
            asm.Cmp();
            asm.GetLocal(cmpValue);
            asm.Eq();
            var end     = asm.NewLabel();
            var codeEnd = asm.NewLabel();

            PushLoop(start, end, codeEnd);
            asm.Branch(end);
            PreLoopCode(node.Code);
            node.Code.Accept(this);
            asm.MarkLabel(codeEnd);
            PostLoopCode(node.Code);
            asm.GetLocal(node.Iterator.Value);
            asm.GetLocal(byValue);
            asm.Add();
            asm.SetLocal(node.Iterator.Value);
            asm.Jump(start);
            asm.MarkLabel(end);
            PopLoop();

            PopScope();
        }
예제 #11
0
        public NeoValue Call(NeoValue[] arguments)
        {
            var scope = new Scope(ParentScope);
            var level = scope.Level;

            var pargs = new List <NeoValue>();

            foreach (var arg in arguments)
            {
                if (arg is NeoSpreadValue va)
                {
                    for (var i = 0; i < va.Array.Count; i++)
                    {
                        pargs.Add(va.Array[i]);
                    }
                }
                else
                {
                    pargs.Add(arg);
                }
            }

            var varargs   = new NeoArray();
            var extraArgs = pargs.Count - Procedure.Parameters.Length;

            if (extraArgs > 0)
            {
                for (var i = 0; i < extraArgs; i++)
                {
                    varargs.Insert(pargs[Procedure.Parameters.Length + i]);
                }
            }

            for (var i = 0; i < Procedure.Parameters.Length; i++)
            {
                var name = Procedure.Parameters[i].Name;
                scope.Declare(name, VariableFlags.NONE);

                var value = i < pargs.Count ? pargs[i] : NeoNil.NIL;

                if (Procedure.Parameters[i].Frozen)
                {
                    value = value.Frozen();
                }

                scope.Set(name, value);
            }

            var code  = Procedure.Instructions;
            var ip    = 4;
            var stack = new Stack <NeoValue>();

            var rootScopeLevel = scope.Level;

            var openUps = new Dictionary <string, UpValue>();

            var defers = new Stack <NeoProcedure>();

            byte ReadByte() => code[ip++];
            OpCode ReadOpCode() => (OpCode)ReadByte();
            short ReadShort() => (short)(ReadByte() | (ReadByte() << 8));
            int ReadInt() => ReadByte() | (ReadByte() << 8) | (ReadByte() << 16) | (ReadByte() << 24);
            NeoValue ReadConstant() => Procedure.Constants[ReadInt()];

            while (ip < code.Length)
            {
                var op = ReadOpCode();

                try {
                    switch (op)
                    {
                    case OpCode.NOP:
                        break;

                    case OpCode.INC: {
                        stack.Push(stack.Pop().Inc());
                    }
                    break;

                    case OpCode.DEC: {
                        stack.Push(stack.Pop().Dec());
                    }
                    break;

                    case OpCode.ADD: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Add(b));
                    }
                    break;

                    case OpCode.SUB: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Sub(b));
                    }
                    break;

                    case OpCode.MUL: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Mul(b));
                    }
                    break;

                    case OpCode.DIV: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Div(b));
                    }
                    break;

                    case OpCode.POW: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Pow(b));
                    }
                    break;

                    case OpCode.MOD: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Mod(b));
                    }
                    break;

                    case OpCode.LSH: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Lsh(b));
                    }
                    break;

                    case OpCode.RSH: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Rsh(b));
                    }
                    break;

                    case OpCode.BIT_NOT: {
                        stack.Push(stack.Pop().BitNot());
                    }
                    break;

                    case OpCode.BIT_AND: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.BitAnd(b));
                    }
                    break;

                    case OpCode.BIT_OR: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.BitOr(b));
                    }
                    break;

                    case OpCode.BIT_XOR: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.BitXor(b));
                    }
                    break;

                    case OpCode.NOT: {
                        stack.Push(stack.Pop().Not());
                    }
                    break;

                    case OpCode.NEG: {
                        stack.Push(stack.Pop().Neg());
                    }
                    break;

                    case OpCode.CONCAT: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Concat(b));
                    }
                    break;

                    case OpCode.LENGTH: {
                        stack.Push(stack.Pop().Length());
                    }
                    break;

                    case OpCode.ARRAY_NEW: {
                        stack.Push(new NeoArray());
                    }
                    break;

                    case OpCode.ARRAY_ADD: {
                        var element = stack.Pop();
                        var array   = stack.Pop().CheckArray();
                        array.Insert(element);
                    }
                    break;

                    case OpCode.OBJECT_NEW: {
                        stack.Push(new NeoObject());
                    }
                    break;

                    case OpCode.OBJECT_INDEX: {
                        var index = stack.Pop().CheckInt();
                        var obj   = stack.Pop().CheckObject();
                        stack.Push(obj.Index(index.Value));
                        stack.Push(obj.Get(obj.Index(index.Value)));
                    }
                    break;

                    case OpCode.GET: {
                        var key = stack.Pop();
                        var obj = stack.Pop();
                        stack.Push(obj.Get(key));
                    }
                    break;

                    case OpCode.SET: {
                        var value = stack.Pop();
                        var key   = stack.Pop();
                        var obj   = stack.Pop();
                        obj.Set(key, value);
                    }
                    break;

                    case OpCode.SLICE: {
                        var end   = stack.Pop();
                        var start = stack.Pop();
                        stack.Push(stack.Pop().Slice(start, end));
                    }
                    break;

                    case OpCode.EQ: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Eq(b));
                    }
                    break;

                    case OpCode.NE: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Ne(b));
                    }
                    break;

                    case OpCode.DEEP_EQ: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.DeepEq(b));
                    }
                    break;

                    case OpCode.DEEP_NE: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.DeepNe(b));
                    }
                    break;

                    case OpCode.LT: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Lt(b));
                    }
                    break;

                    case OpCode.GT: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Gt(b));
                    }
                    break;

                    case OpCode.LTE: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Lte(b));
                    }
                    break;

                    case OpCode.GTE: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(a.Gte(b));
                    }
                    break;

                    case OpCode.CMP: {
                        var b = stack.Pop();
                        var a = stack.Pop();
                        stack.Push(NeoInt.ValueOf(a.Compare(b)));
                    }
                    break;

                    case OpCode.JUMP: {
                        ip = ReadInt();
                    }
                    break;

                    case OpCode.JUMP_IF: {
                        var addr = ReadInt();
                        if (stack.Pop().CheckBool().Value)
                        {
                            ip = addr;
                        }
                    }
                    break;

                    case OpCode.CALL: {
                        var line  = Procedure.FindLine(ip);
                        var nargs = ReadShort();

                        var args = new NeoValue[nargs];
                        for (var i = nargs - 1; i >= 0; i--)
                        {
                            args[i] = stack.Pop();
                        }

                        var callee = stack.Pop();
                        if (callee.IsProcedure)
                        {
                            var proc = callee.CheckProcedure();
                            VM.PushFrame(proc.ChunkName(), proc.Name(), line);
                            stack.Push(proc.Call(args));
                            VM.PopFrame();
                        }
                        else
                        {
                            VM.PushFrame("<unknown>", "<unknown>", line);
                            stack.Push(callee.Call(args));
                            VM.PopFrame();
                        }
                    }
                    break;

                    case OpCode.RETURN: {
                        foreach (var up in openUps.Values)
                        {
                            up.Close();
                        }

                        NeoValue rvalue = null;
                        if (ReadByte() == 1)
                        {
                            rvalue = stack.Pop();
                        }
                        else
                        {
                            if (stack.Count > 0)
                            {
                                throw new Exception("VM error: stack not empty");
                            }

                            rvalue = NeoNil.NIL;
                        }

                        while (defers.Count > 0)
                        {
                            defers.Pop().Call(new NeoValue[0]);
                        }

                        return(rvalue);
                    }

                    case OpCode.DEFER: {
                        defers.Push(stack.Pop().CheckProcedure());
                    }
                    break;

                    case OpCode.VARARGS: {
                        if (!Procedure.Varargs)
                        {
                            stack.Push(NeoNil.NIL);
                        }
                        else
                        {
                            stack.Push(varargs);
                        }
                    }
                    break;

                    case OpCode.PUSH_TRUE: {
                        stack.Push(NeoBool.TRUE);
                    }
                    break;

                    case OpCode.PUSH_FALSE: {
                        stack.Push(NeoBool.FALSE);
                    }
                    break;

                    case OpCode.PUSH_NIL: {
                        stack.Push(NeoNil.NIL);
                    }
                    break;

                    case OpCode.PUSH_CONSTANT: {
                        stack.Push(ReadConstant());
                    }
                    break;

                    case OpCode.DUP: {
                        var a = stack.Pop();
                        stack.Push(a);
                        stack.Push(a);
                    }
                    break;

                    case OpCode.SWAP: {
                        var a = stack.Pop();
                        var b = stack.Pop();
                        stack.Push(a);
                        stack.Push(b);
                    }
                    break;

                    case OpCode.POP: {
                        stack.Pop();
                    }
                    break;

                    case OpCode.CLOSURE: {
                        var name = ReadConstant().CheckString().Value;
                        var proc = Procedure.Procedures.First(p => p.Name == name);

                        var upvalues = new UpValue[proc.UpValues.Length];
                        for (var i = 0; i < upvalues.Length; i++)
                        {
                            var pop = ReadOpCode();
                            if (pop != OpCode.GET_LOCAL && pop != OpCode.GET_UPVALUE)
                            {
                                throw new Exception(pop.ToString());
                            }

                            var upname = ReadConstant().CheckString().Value;

                            switch (pop)
                            {
                            case OpCode.GET_LOCAL: {
                                if (!openUps.ContainsKey(upname))
                                {
                                    openUps[upname] = new UpValue(scope, upname);
                                }
                                upvalues[i] = openUps[upname];
                            }
                            break;

                            case OpCode.GET_UPVALUE: {
                                upvalues[i] = this.upvalues.First(up => up.Name == upname);
                            }
                            break;
                            }
                        }

                        stack.Push(new NeoBackendProcedure(VM, VM.Interpreter.Compile(scope, Chunk, proc, upvalues)));
                    }
                    break;

                    case OpCode.CLOSE: {
                        var name = ReadConstant().CheckString().Value;
                        if (openUps.ContainsKey(name))
                        {
                            openUps[name].Close();
                            openUps.Remove(name);
                        }
                    }
                    break;

                    case OpCode.GET_LOCAL: {;
                                            stack.Push(scope.Get(ReadConstant().CheckString().Value)); }
                                            break;

                    case OpCode.SET_LOCAL: {
                        var name  = ReadConstant().CheckString().Value;
                        var value = stack.Pop();
                        scope.Set(name, value);
                    }
                    break;

                    case OpCode.GET_GLOBAL: {
                        stack.Push(ParentScope.Get(ReadConstant().CheckString().Value));
                    }
                    break;

                    case OpCode.SET_GLOBAL: {
                        ParentScope.Set(ReadConstant().CheckString().Value, stack.Pop());
                    }
                    break;

                    case OpCode.GET_UPVALUE: {
                        var name = ReadConstant().CheckString().Value;
                        var up   = upvalues.First(u => u.Name == name);
                        stack.Push(up.Get());
                    }
                    break;

                    case OpCode.SET_UPVALUE: {
                        var name = ReadConstant().CheckString().Value;

                        var index = 0;
                        for (var i = 0; i < upvalues.Length; i++)
                        {
                            if (upvalues[i].Name == name)
                            {
                                index = i;
                                break;
                            }
                        }

                        upvalues[index].Set(stack.Pop());
                    }
                    break;

                    case OpCode.SPREAD: {
                        stack.Push(new NeoSpreadValue(stack.Pop().CheckArray()));
                    }
                    break;

                    case OpCode.FROZEN: {
                        stack.Push(stack.Pop().Frozen());
                    }
                    break;

                    case OpCode.TRY: {
                        var @catch = stack.Pop().CheckProcedure();
                        var @try   = stack.Pop().CheckProcedure();

                        NeoValue r;

                        try {
                            r = @try.Call(new NeoValue[0]);
                        } catch (NeoError e) {
                            r = @catch.Call(new[] { NeoString.ValueOf(e.Message) });
                        }

                        if (!r.IsNil)
                        {
                            foreach (var up in openUps.Values)
                            {
                                up.Close();
                            }

                            while (defers.Count > 0)
                            {
                                defers.Pop().Call(new NeoValue[0]);
                            }

                            return(r);
                        }
                    }
                    break;

                    case OpCode.THROW: {
                        var line = Procedure.FindLine(ip);
                        throw new NeoError(stack.Pop().CheckString().Value, line);
                    }

                    case OpCode.DECLARE: {
                        var name  = ReadConstant().CheckString().Value;
                        var flags = ReadByte();
                        scope.Declare(name, (VariableFlags)flags);
                    }
                    break;

                    case OpCode.PUSH_SCOPE: {
                        scope = new Scope(scope);
                    }
                    break;

                    case OpCode.POP_SCOPE: {
                        scope = scope.Parent;
                    }
                    break;

                    default: {
                        throw new Exception($"Unexpected opcode: {op}");
                    }
                    }
                } catch (NeoError e) {
                    if (e.Line == -1)
                    {
                        e.Line = Procedure.FindLine(ip);
                    }
                    throw e;
                }
            }

            throw new Exception("VM error");
        }
예제 #12
0
 public override NeoValue Length() => NeoInt.ValueOf(Value.Length);