# Copyright 2022 Mattia Giambirtone & All Contributors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ## The Peon runtime environment import types import ../config import ../frontend/meta/bytecode type PeonVM* = ref object ## The Peon Virtual Machine stack: seq[PeonObject] ip: int # Instruction pointer sp: int # Stack pointer cache: array[6, PeonObject] # Singletons cache chunk: Chunk # Piece of bytecode to execute proc newPeonVM*: PeonVM = ## Initializes a new, blank VM ## for executing Peon bytecode new(result) result.ip = 0 result.sp = 0 result.stack = newSeqOfCap[PeonObject](INITIAL_STACK_SIZE) result.cache[0] = newNil() result.cache[1] = newBool(true) result.cache[2] = newBool(false) result.cache[3] = newInf(true) result.cache[4] = newInf(false) result.cache[5] = newNan() for _ in 0..= self.stack.high(): for _ in 0..self.stack.len(): self.stack.add(newNil()) self.stack[self.sp] = obj inc(self.sp) proc pop(self: PeonVM): PeonObject = dec(self.sp) return self.stack[self.sp] proc readByte(self: PeonVM, chunk: Chunk): uint8 = inc(self.ip) return chunk.code[self.ip - 1] proc dispatch*(self: PeonVM) = ## Main bytecode dispatch loop var instruction: OpCode while true: stdout.write("[") for i, e in self.stack: stdout.write($(e[])) if i < self.stack.high(): stdout.write(", ") echo "]" instruction = OpCode(self.readByte(self.chunk)) echo instruction case instruction: of OpCode.True: self.push(self.getBool(true)) of OpCode.False: self.push(self.getBool(false)) of OpCode.Nan: self.push(self.getNan()) of OpCode.Nil: self.push(self.getNil()) of OpCode.Inf: self.push(self.getInf(true)) of UnaryPlus: self.push(self.pop()) of OpCode.Return: return else: discard proc run*(self: PeonVM, chunk: Chunk) = ## Executes a piece of Peon bytecode. self.chunk = chunk self.sp = 0 self.ip = 0 self.dispatch()