Пример #1
0
        public Unit CallFunction(Unit p_callable, List <Unit> p_args = null)
        {
            UnitType this_type = p_callable.Type;

            if (p_args != null)
            {
                for (int i = p_args.Count - 1; i >= 0; i--)
                {
                    stack.Push(p_args[i]);
                }
            }

            Operand before_call_IP = IP;

            if (this_type == UnitType.Function)
            {
                instructions.PushRET((Operand)(main.Body.Count - 1));
                FunctionUnit this_func = (FunctionUnit)(p_callable.heapUnitValue);
                instructions.PushFunction(this_func, Env, out instructionsCache);

                IP = 0;
            }
            else if (this_type == UnitType.Closure)
            {
                instructions.PushRET((Operand)(main.Body.Count - 1));
                ClosureUnit this_closure = (ClosureUnit)(p_callable.heapUnitValue);

                upValues.PushEnv();


                foreach (UpValueUnit u in this_closure.UpValues)
                {
                    upValues.Add(u);
                }
                instructions.PushFunction(this_closure.Function, Env, out instructionsCache);

                IP = 0;
            }
            else if (this_type == UnitType.Intrinsic)
            {
                IntrinsicUnit this_intrinsic   = (IntrinsicUnit)(p_callable.heapUnitValue);
                Unit          intrinsic_result = this_intrinsic.Function(this);
                stack.top -= this_intrinsic.Arity;
                return(intrinsic_result);
            }

            VMResult result = Run();

            IP = before_call_IP;
            if (result.status == VMResultType.OK)
            {
                return(result.value);
            }
            return(new Unit(UnitType.Null));
        }
Пример #2
0
        private VMResult Run()
        {
            Instruction instruction;

            while (true)
            {
                instruction = instructionsCache[IP];

                switch (instruction.opCode)
                {
                case OpCode.POP:
                    IP++;
                    stack.Pop();
                    break;

                case OpCode.DUP:
                    IP++;
                    stack.Push(stack.Peek());
                    break;

                case OpCode.LOAD_DATA:
                    IP++;
                    stack.Push(data[instruction.opA]);
                    break;

                case OpCode.LOAD_VARIABLE:
                    IP++;
                    stack.Push(variables.GetAt(instruction.opA, CalculateEnvShift(instruction.opB)));
                    break;

                case OpCode.LOAD_GLOBAL:
                    IP++;
                    if (parallelVM == true)
                    {
                        lock (globals.Get(instruction.opA).heapUnitValue)    // needed because global may be loaded from parallel functions
                            stack.Push(globals.Get(instruction.opA));
                    }
                    else
                    {
                        stack.Push(globals.Get(instruction.opA));
                    }
                    break;

                case OpCode.LOAD_IMPORTED_GLOBAL:
                    IP++;
                    stack.Push(modules[instruction.opB].GetGlobal(instruction.opA));
                    break;

                case OpCode.LOAD_IMPORTED_DATA:
                    IP++;
                    stack.Push(modules[instruction.opB].GetData(instruction.opA));
                    break;

                case OpCode.LOAD_UPVALUE:
                    IP++;
                    if (parallelVM == true)
                    {
                        lock (upValues.GetAt(instruction.opA))    // needed because upvalue may be loaded from parallel functions
                            stack.Push(upValues.GetAt(instruction.opA).UpValue);
                    }
                    else
                    {
                        stack.Push(upValues.GetAt(instruction.opA).UpValue);
                    }
                    break;

                case OpCode.LOAD_NIL:
                    IP++;
                    stack.Push(new Unit(UnitType.Null));
                    break;

                case OpCode.LOAD_TRUE:
                    IP++;
                    stack.Push(new Unit(true));
                    break;

                case OpCode.LOAD_FALSE:
                    IP++;
                    stack.Push(new Unit(false));
                    break;

                case OpCode.LOAD_INTRINSIC:
                    IP++;
                    stack.Push(new Unit(Intrinsics[instruction.opA]));
                    break;

                case OpCode.DECLARE_VARIABLE:
                    IP++;
                    variables.Add(stack.Pop());
                    break;

                case OpCode.DECLARE_GLOBAL:
                    IP++;
                    // lock(globals) // not needed because global declaration can not happen inside parallel functions
                    globals.Add(stack.Pop());
                    break;

                case OpCode.DECLARE_FUNCTION:
                {
                    IP++;
                    Operand env = instruction.opA;
                    Operand is_function_expression = instruction.opB;
                    Operand new_fun_address        = instruction.opC;
                    Unit    this_callable          = data[new_fun_address];
                    if (this_callable.Type == UnitType.Function)
                    {
                        if (is_function_expression == 0)
                        {
                            if (env == 0)        // Global
                            {
                                // lock(globals) // not needed because global declaration can not happen inside parallel functions
                                globals.Add(this_callable);
                            }
                            else
                            {
                                variables.Add(this_callable);
                            }
                        }
                        else
                        {
                            stack.Push(this_callable);
                        }
                    }
                    else
                    {
                        ClosureUnit this_closure = (ClosureUnit)(this_callable.heapUnitValue);

                        // new upvalues
                        List <UpValueUnit> new_upValues = new List <UpValueUnit>();
                        foreach (UpValueUnit u in this_closure.UpValues)
                        {
                            // here we convert env from shift based to absolute based
                            UpValueUnit new_upvalue = registeredUpValues.Get(u.Address, CalculateEnvShiftUpVal(u.Env));
                            new_upValues.Add(new_upvalue);
                        }
                        ClosureUnit new_closure = new ClosureUnit(this_closure.Function, new_upValues);

                        Unit new_closure_unit = new Unit(new_closure);
                        if (is_function_expression == 0)
                        {
                            if (env == 0)        // yes they exist!
                            {
                                // lock(globals) // not needed because global declaration can not happen inside parallel functions
                                globals.Add(new_closure_unit);
                            }
                            else
                            {
                                variables.Add(new_closure_unit);
                            }
                        }
                        else
                        {
                            stack.Push(new_closure_unit);
                        }
                    }
                    break;
                }

                case OpCode.ASSIGN_VARIABLE:
                {
                    IP++;

                    Unit old_value = variables.GetAt(instruction.opA, CalculateEnvShift(instruction.opB));
                    Unit result;
                    switch (instruction.opC)
                    {
                    case ASSIGN:
                        variables.SetAt(stack.Peek(), instruction.opA, CalculateEnvShift(instruction.opB));
                        break;

                    case ADDITION_ASSIGN:
                        result = old_value + stack.Peek();
                        variables.SetAt(result, instruction.opA, CalculateEnvShift(instruction.opB));
                        break;

                    case SUBTRACTION_ASSIGN:
                        result = old_value - stack.Peek();
                        variables.SetAt(result, instruction.opA, CalculateEnvShift(instruction.opB));
                        break;

                    case MULTIPLICATION_ASSIGN:
                        result = old_value * stack.Peek();
                        variables.SetAt(result, instruction.opA, CalculateEnvShift(instruction.opB));
                        break;

                    case DIVISION_ASSIGN:
                        result = old_value / stack.Peek();
                        variables.SetAt(result, instruction.opA, CalculateEnvShift(instruction.opB));
                        break;

                    default:
                        throw new Exception("Unknown operator");
                    }
                    break;
                }

                case OpCode.ASSIGN_GLOBAL:
                {
                    IP++;
                    Operand address   = instruction.opA;
                    Operand op        = instruction.opB;
                    Unit    new_value = stack.Peek();
                    if (parallelVM == true)
                    {
                        switch (op)
                        {
                        case ASSIGN:
                            lock (globals.Get(address).heapUnitValue)
                                globals.Set(new_value, address);
                            break;

                        case ADDITION_ASSIGN:
                            lock (globals.Get(address).heapUnitValue){
                                Unit result = globals.Get(address) + new_value;
                                globals.Set(result, address);
                            }
                            break;

                        case SUBTRACTION_ASSIGN:
                            lock (globals.Get(address).heapUnitValue){
                                Unit result = globals.Get(address) - new_value;
                                globals.Set(result, address);
                            }
                            break;

                        case MULTIPLICATION_ASSIGN:
                            lock (globals.Get(address).heapUnitValue){
                                Unit result = globals.Get(address) * new_value;
                                globals.Set(result, address);
                            }
                            break;

                        case DIVISION_ASSIGN:
                            lock (globals.Get(address).heapUnitValue){
                                Unit result = globals.Get(address) / new_value;
                                globals.Set(result, address);
                            }
                            break;

                        default:
                            throw new Exception("Unknown operator");
                        }
                    }
                    else
                    {
                        Unit result;
                        switch (op)
                        {
                        case ASSIGN:
                            globals.Set(new_value, address);
                            break;

                        case ADDITION_ASSIGN:
                            result = globals.Get(address) + new_value;
                            globals.Set(result, address);
                            break;

                        case SUBTRACTION_ASSIGN:
                            result = globals.Get(address) - new_value;
                            globals.Set(result, address);
                            break;

                        case MULTIPLICATION_ASSIGN:
                            result = globals.Get(address) * new_value;
                            globals.Set(result, address);
                            break;

                        case DIVISION_ASSIGN:
                            result = globals.Get(address) / new_value;
                            globals.Set(result, address);
                            break;

                        default:
                            throw new Exception("Unknown operator");
                        }
                    }
                    break;
                }

                case OpCode.ASSIGN_IMPORTED_GLOBAL:
                    IP++;
                    modules[instruction.opB].SetOpGlobal(stack.Peek(), instruction.opC, instruction.opA);
                    break;

                case OpCode.ASSIGN_UPVALUE:
                    IP++;
                    if (parallelVM == true)
                    {
                        UpValueUnit this_upValue;
                        this_upValue = upValues.GetAt(instruction.opA);
                        switch (instruction.opB)
                        {
                        case ASSIGN:
                            lock (this_upValue)
                                this_upValue.UpValue = stack.Peek();
                            break;

                        case ADDITION_ASSIGN:
                            lock (this_upValue)
                                this_upValue.UpValue = upValues.GetAt(instruction.opA).UpValue + stack.Peek();
                            break;

                        case SUBTRACTION_ASSIGN:
                            lock (this_upValue)
                                this_upValue.UpValue = upValues.GetAt(instruction.opA).UpValue - stack.Peek();
                            break;

                        case MULTIPLICATION_ASSIGN:
                            lock (this_upValue)
                                this_upValue.UpValue = upValues.GetAt(instruction.opA).UpValue *stack.Peek();
                            break;

                        case DIVISION_ASSIGN:
                            lock (this_upValue)
                                this_upValue.UpValue = upValues.GetAt(instruction.opA).UpValue / stack.Peek();
                            break;

                        default:
                            throw new Exception("Unknown operator");
                        }
                    }
                    else
                    {
                        UpValueUnit this_upValue = upValues.GetAt(instruction.opA);
                        switch (instruction.opB)
                        {
                        case ASSIGN:
                            this_upValue.UpValue = stack.Peek();
                            break;

                        case ADDITION_ASSIGN:
                            this_upValue.UpValue = this_upValue.UpValue + stack.Peek();
                            break;

                        case SUBTRACTION_ASSIGN:
                            this_upValue.UpValue = this_upValue.UpValue - stack.Peek();
                            break;

                        case MULTIPLICATION_ASSIGN:
                            this_upValue.UpValue = this_upValue.UpValue * stack.Peek();
                            break;

                        case DIVISION_ASSIGN:
                            this_upValue.UpValue = this_upValue.UpValue / stack.Peek();
                            break;

                        default:
                            throw new Exception("Unknown operator");
                        }
                    }
                    break;

                case OpCode.GET:
                {
                    IP++;
                    Operand indexes_counter = instruction.opA;

                    Unit[] indexes = new Unit[indexes_counter];
                    for (int i = indexes_counter - 1; i >= 0; i--)
                    {
                        indexes[i] = stack.Pop();
                    }

                    Unit value = stack.Pop();
                    foreach (Unit v in indexes)
                    {
                        value = (value.heapUnitValue).Get(v);
                    }
                    stack.Push(value);
                    break;
                }

                case OpCode.SET:
                {
                    IP++;
                    Operand indexes_counter = instruction.opA;
                    Operand op = instruction.opB;

                    Unit[] indexes = new Unit[indexes_counter];
                    for (int i = indexes_counter - 1; i >= 0; i--)
                    {
                        indexes[i] = stack.Pop();
                    }

                    Unit this_table = stack.Pop();

                    for (int i = 0; i < indexes_counter - 1; i++)
                    {
                        Unit v = indexes[i];
                        this_table = (this_table.heapUnitValue).Get(v);
                    }
                    Unit     new_value  = stack.Peek();
                    Unit     index      = indexes[indexes_counter - 1];
                    UnitType index_type = indexes[indexes_counter - 1].Type;
                    if (op == ASSIGN)
                    {
                        ((this_table.heapUnitValue)).Set(index, new_value);
                    }
                    else if (parallelVM == true)
                    {
                        Unit old_value;
                        Unit result;
                        switch (op)
                        {
                        case ADDITION_ASSIGN:
                            lock (this_table.heapUnitValue){
                                old_value = ((TableUnit)(this_table.heapUnitValue)).Get(index);
                                result    = old_value + new_value;
                                (this_table.heapUnitValue).Set(index, result);
                            }
                            break;

                        case SUBTRACTION_ASSIGN:
                            lock (this_table.heapUnitValue){
                                old_value = ((TableUnit)(this_table.heapUnitValue)).Get(index);
                                result    = old_value - new_value;
                                (this_table.heapUnitValue).Set(index, result);
                            }
                            break;

                        case MULTIPLICATION_ASSIGN:
                            lock (this_table.heapUnitValue){
                                old_value = ((TableUnit)(this_table.heapUnitValue)).Get(index);
                                result    = old_value * new_value;
                                (this_table.heapUnitValue).Set(index, result);
                            }
                            break;

                        case DIVISION_ASSIGN:
                            lock (this_table.heapUnitValue){
                                old_value = ((TableUnit)(this_table.heapUnitValue)).Get(index);
                                result    = old_value / new_value;
                                (this_table.heapUnitValue).Set(index, result);
                            }
                            break;

                        default:
                            throw new Exception("Unknown operator");
                        }
                    }
                    else
                    {
                        Unit old_value = (this_table.heapUnitValue).Get(index);
                        Unit result;
                        switch (op)
                        {
                        case ADDITION_ASSIGN:
                            result = old_value + new_value;
                            break;

                        case SUBTRACTION_ASSIGN:
                            result = old_value - new_value;
                            break;

                        case MULTIPLICATION_ASSIGN:
                            result = old_value * new_value;
                            break;

                        case DIVISION_ASSIGN:
                            result = old_value / new_value;
                            break;

                        default:
                            throw new Exception("Unknown operator");
                        }
                        (this_table.heapUnitValue).Set(index, result);
                    }
                    break;
                }

                case OpCode.JUMP:
                    IP += instruction.opA;
                    break;

                case OpCode.JUMP_IF_NOT_TRUE:
                    if (stack.Pop().ToBool() == false)
                    {
                        IP += instruction.opA;
                    }
                    else
                    {
                        IP++;
                    }
                    break;

                case OpCode.JUMP_BACK:
                    IP -= instruction.opA;
                    break;

                case OpCode.OPEN_ENV:
                    IP++;
                    EnvPush();
                    break;

                case OpCode.CLOSE_ENV:
                    IP++;
                    EnvPop();
                    break;

                case OpCode.RETURN:
                    IP = instructions.PopRET();
                    break;

                case OpCode.RETURN_SET:
                    instructions.PushRET((Operand)(instruction.opA + IP));
                    IP++;
                    break;

                case OpCode.ADD:
                {
                    IP++;
                    Unit opB = stack.Pop();
                    stack.Push(stack.Pop() + opB);

                    break;
                }

                case OpCode.APPEND:
                {
                    IP++;
                    Unit   opB    = stack.Pop();
                    string result = stack.Pop().ToString() + opB.ToString();
                    stack.Push(new Unit(result));
                    break;
                }

                case OpCode.SUBTRACT:
                {
                    IP++;
                    Unit opB = stack.Pop();
                    stack.Push(stack.Pop() - opB);
                    break;
                }

                case OpCode.MULTIPLY:
                    IP++;
                    stack.Push(stack.Pop() * stack.Pop());
                    break;

                case OpCode.DIVIDE:
                {
                    IP++;
                    Unit opB = stack.Pop();
                    stack.Push(stack.Pop() / opB);
                    break;
                }

                case OpCode.NEGATE:
                    IP++;
                    stack.Push(-stack.Pop());
                    break;

                case OpCode.INCREMENT:
                    IP++;
                    stack.Push(stack.Pop() + 1);
                    break;

                case OpCode.DECREMENT:
                    IP++;
                    stack.Push(stack.Pop() - 1);
                    break;

                case OpCode.EQUALS:
                    IP++;
                    stack.Push(new Unit(stack.Pop().Equals(stack.Pop())));
                    break;

                case OpCode.NOT_EQUALS:
                    IP++;
                    stack.Push(new Unit(!stack.Pop().Equals(stack.Pop())));
                    break;

                case OpCode.GREATER_EQUALS:
                    IP++;
                    // the values are popped out of order from stack, so the logic is inverted!
                    stack.Push(new Unit(stack.Pop().floatValue <= stack.Pop().floatValue));
                    break;

                case OpCode.LESS_EQUALS:
                    IP++;
                    // the values are popped out of order from stack, so the logic is inverted!
                    stack.Push(new Unit(stack.Pop().floatValue >= stack.Pop().floatValue));
                    break;

                case OpCode.GREATER:
                    IP++;
                    // the values are popped out of order from stack, so the logic is inverted!
                    stack.Push(new Unit(stack.Pop().floatValue < stack.Pop().floatValue));
                    break;

                case OpCode.LESS:
                    IP++;
                    // the values are popped out of order from stack, so the logic is inverted!
                    stack.Push(new Unit(stack.Pop().floatValue > stack.Pop().floatValue));
                    break;

                case OpCode.NOT:
                    IP++;
                    stack.Push(new Unit(!stack.Pop().ToBool()));
                    break;

                case OpCode.AND:
                {
                    IP++;
                    Unit opB = stack.Pop();
                    stack.Push(new Unit(stack.Pop().ToBool() && opB.ToBool()));
                    break;
                }

                case OpCode.OR:
                {
                    IP++;
                    Unit opB = stack.Pop();
                    stack.Push(new Unit(stack.Pop().ToBool() || opB.ToBool()));
                    break;
                }

                case OpCode.XOR:
                {
                    IP++;
                    Unit opB = stack.Pop();
                    stack.Push(new Unit(stack.Pop().ToBool() ^ opB.ToBool()));
                    break;
                }

                case OpCode.NAND:
                {
                    IP++;
                    Unit opB = stack.Pop();
                    stack.Push(new Unit(!(stack.Pop().ToBool() && opB.ToBool())));
                    break;
                }

                case OpCode.NOR:
                {
                    IP++;
                    Unit opB = stack.Pop();
                    stack.Push(new Unit(!(stack.Pop().ToBool() || opB.ToBool())));
                    break;
                }

                case OpCode.XNOR:
                {
                    IP++;
                    Unit opB = stack.Pop();
                    stack.Push(new Unit(!(stack.Pop().ToBool() ^ opB.ToBool())));
                    break;
                }

                case OpCode.CLOSE_CLOSURE:
                    upValues.PopEnv();
                    EnvSet(instructions.TargetEnv);
                    IP = instructions.PopFunction(out instructionsCache);

                    break;

                case OpCode.CLOSE_FUNCTION:
                    EnvSet(instructions.TargetEnv);
                    IP = instructions.PopFunction(out instructionsCache);

                    break;

                case OpCode.NEW_TABLE:
                {
                    IP++;

                    TableUnit new_table = new TableUnit(null);

                    int n_table = instruction.opA;
                    for (int i = 0; i < n_table; i++)
                    {
                        Unit val = stack.Pop();
                        Unit key = stack.Pop();
                        new_table.Map.Add(key, val);
                    }

                    stack.Push(new Unit(new_table));
                    break;
                }

                case OpCode.NEW_LIST:
                {
                    IP++;

                    ListUnit new_list = new ListUnit(null);

                    int n_table = instruction.opA;
                    for (int i = 0; i < n_table; i++)
                    {
                        Unit val = stack.Pop();
                        new_list.Elements.Add(val);
                    }

                    stack.Push(new Unit(new_list));
                    break;
                }

                case OpCode.CALL:
                {
                    IP++;

                    Unit     this_callable = stack.Pop();
                    UnitType this_type     = this_callable.Type;

                    if (this_type == UnitType.Function)
                    {
                        FunctionUnit this_func = (FunctionUnit)this_callable.heapUnitValue;

                        instructions.PushRET(IP);
                        instructions.PushFunction(this_func, Env, out instructionsCache);

                        IP = 0;
                    }
                    else if (this_type == UnitType.Closure)
                    {
                        ClosureUnit this_closure = (ClosureUnit)this_callable.heapUnitValue;

                        upValues.PushEnv();

                        foreach (UpValueUnit u in this_closure.UpValues)
                        {
                            upValues.Add(u);
                        }

                        instructions.PushRET(IP);
                        instructions.PushFunction(this_closure.Function, Env, out instructionsCache);

                        IP = 0;
                    }
                    else if (this_type == UnitType.Intrinsic)
                    {
                        IntrinsicUnit this_intrinsic = (IntrinsicUnit)this_callable.heapUnitValue;
                        Unit          result         = this_intrinsic.Function(this);
                        stack.top -= this_intrinsic.Arity;
                        stack.Push(result);
                    }
                    else
                    {
                        Error("Trying to call a " + this_callable.Type);
                        return(new VMResult(VMResultType.OK, new Unit(UnitType.Null)));
                    }
                    break;
                }

                case OpCode.PUSH_STASH:
                    IP++;
                    stack.PushStash();
                    break;

                case OpCode.POP_STASH:
                    IP++;
                    stack.PopStash();
                    break;

                case OpCode.EXIT:
                    if (stack.top > 0)
                    {
                        return(new VMResult(VMResultType.OK, stack.Pop()));
                    }
                    return(new VMResult(VMResultType.OK, new Unit(UnitType.Null)));

                default:
                    Error("Unkown OpCode: " + instruction.opCode);
                    return(new VMResult(VMResultType.ERROR, new Unit(UnitType.Null)));
                }
            }
        }