Skip to content

Commit

Permalink
Fixed an issue with Stack.Expect, added functions readNumber and stri…
Browse files Browse the repository at this point in the history
…p, added installation instructions
  • Loading branch information
voidwyrm-2 committed Jan 1, 2025
1 parent 8b8411e commit 2fe4ab7
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 13 deletions.
4 changes: 2 additions & 2 deletions examples/bytecode-test.bc
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"Velvet Scarlatina" 0 0 41

# instruction section
0 4 2 0 7 0 13 # push "Hello there.\n"
0 4 2 0 7 0 12 # push "Hello there."
0 3 0 0 0 0 7 # print string
0 2 0 0 0 0 0 # end program

# data section
"println" "Hello there.\n"
"println" "Hello there."
Binary file modified examples/bytecode-test.cvelv
Binary file not shown.
15 changes: 15 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,18 @@ The bytecode specification can be found in [bytecode.md](<./bytecode.md>)
Examples of the bytecode assembly can be found in [examples](<./examples>)

An example of what the bytecode itself looks like can be found in [bytecode-test.bc](<./examples/bytecode-test.bc>) and [bytecode-test.bin](<./examples/bytecode-test.bin>)

## Installation

You can either get an executable from the releases or compile it yourself

**Compiling it yourself**

Install Go if you don't have it, either from the [website](<https://go.dev>) or via a package manager(`brew install go`/`sudo port install go` on Mac, `choco install go` on Windows, you're on your own on Linux)

Next follow these instructions in your terminal:
1. Cd to a folder where you want the VM source folder to be
1. `git clone https://github.com/voidwyrm-2/velvet-vm`
3. `cd velvet-vm/velvet`
4. `go build -o velvet .`
5. `velvet ../examples/bytecode-test.cvelv`
35 changes: 34 additions & 1 deletion velvc/generation/emitter/emitter.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package emitter

import (
"fmt"
"os"
)

Expand Down Expand Up @@ -50,11 +51,12 @@ func writeFile(filename string, data []byte) error {
type VelvetAsm struct {
vars uint8
instructions [][7]byte
labels map[string]uint32
data []byte
}

func New(vars uint8) VelvetAsm {
return VelvetAsm{vars: vars, instructions: [][7]byte{}, data: []byte{}}
return VelvetAsm{vars: vars, instructions: [][7]byte{}, labels: map[string]uint32{}, data: []byte{}}
}

func (va VelvetAsm) Write(filename string) error {
Expand Down Expand Up @@ -94,6 +96,37 @@ func (va *VelvetAsm) EmitString(op Opcode, flag uint8, str string) {
va.Emit(op, flag, addr, length)
}

func (va *VelvetAsm) CreateLabel(name string) {
if _, ok := va.labels[name]; ok {
panic(fmt.Sprintf("label '%s' already exists", name))
}
va.labels[name] = uint32(20 + len(va.instructions)*7)
}

func (va *VelvetAsm) GetLabel(name string) uint32 {
if addr, ok := va.labels[name]; !ok {
panic(fmt.Sprintf("label '%s' does not exist", name))
} else {
return addr
}
}

func (va *VelvetAsm) EmitNF(op Opcode, one, two uint16) {
va.Emit(op, 0, one, two)
}

func (va *VelvetAsm) EmitNF32(op Opcode, both uint32) {
va.Emit32(op, 0, both)
}

func (va *VelvetAsm) EmitNA(op Opcode, flag uint8) {
va.Emit(op, flag, 0, 0)
}

func (va *VelvetAsm) EmitBasic(op Opcode) {
va.Emit(op, 0, 0, 0)
}

func (va *VelvetAsm) Halt(code int8) {
va.Emit(Halt, 0, uint16(code), 0)
}
Binary file added velvc/tests/fibemit/fibemit-test.cvelv
Binary file not shown.
23 changes: 23 additions & 0 deletions velvc/tests/fibemit/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"fmt"

"github.com/voidwyrm-2/velvet-vm/velvc/generation/emitter"
)

func main() {
ve := emitter.New(1)

ve.CreateLabel("numloop")
ve.EmitString(emitter.Push, 2, "please input a number: ")
ve.EmitString(emitter.Call, 0, "print")
ve.Emit32(emitter.Jump, 3, ve.GetLabel("numloop"))

ve.EmitString(emitter.Call, 0, "println")
ve.Halt(0)

if err := ve.Write("fibemit-test.cvelv"); err != nil {
fmt.Println(err.Error())
}
}
Binary file added velvc/tests/jumpemit/jumpemit-test.cvelv
Binary file not shown.
23 changes: 23 additions & 0 deletions velvc/tests/jumpemit/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"fmt"

"github.com/voidwyrm-2/velvet-vm/velvc/generation/emitter"
)

func main() {
ve := emitter.New(0)

ve.EmitNF32(emitter.Push, 10)
ve.CreateLabel("loop")
ve.EmitString(emitter.Push, 2, "Hello there.")
ve.EmitString(emitter.Call, 0, "println")
ve.Emit32(emitter.Jump, 0, ve.GetLabel("loop"))

ve.Halt(0)

if err := ve.Write("jumpemit-test.cvelv"); err != nil {
fmt.Println(err.Error())
}
}
16 changes: 8 additions & 8 deletions velvet/vm/stack/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@ func (s *Stack) TryPop() (StackValue, bool) {
return s.Pop(), true
}

func (s Stack) ExpectErr(k ...ValueKind) error {
for i, v := range s {
if i >= len(k) {
return fmt.Errorf("expected '%s' on the stack, but the stack is not large enough", k[i].Type())
} else if !v.Is(k[i]) && k[i] != Any {
return fmt.Errorf("expected '%s' on the stack, but found '%s' instead", k[i].Type(), v.GetKind().Type())
func (s Stack) ExpectErr(kinds ...ValueKind) error {
for i, k := range kinds {
if i >= len(s) {
return fmt.Errorf("expected '%s' on the stack, but the stack is not large enough", k.Type())
} else if !s[i].Is(k) && k != Any {
return fmt.Errorf("expected '%s' on the stack, but found '%s' instead", k.Type(), s[i].GetKind().Type())
}
}
return nil
}

func (s Stack) Expect(k ...ValueKind) {
if err := s.ExpectErr(k...); err != nil {
func (s Stack) Expect(kinds ...ValueKind) {
if err := s.ExpectErr(kinds...); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
Expand Down
33 changes: 31 additions & 2 deletions velvet/vm/stdfn.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package vm

import (
"bufio"
"fmt"
"math"
"os"
"strconv"
"strings"

"github.com/voidwyrm-2/velvet-vm/velvet/vm/stack"
)
Expand All @@ -15,7 +19,8 @@ var stdfn = map[string]func(st stack.Stack) bool{
return false
},

"eq": func(st stack.Stack) bool { // operator functions
// operator functions
"eq": func(st stack.Stack) bool {
st.Expect(stack.Any, stack.Any)
y, x := st.Pop(), st.Pop()
st.Push(stack.NewBoolValue(x.Equals(y)))
Expand Down Expand Up @@ -108,8 +113,10 @@ var stdfn = map[string]func(st stack.Stack) bool{
y, x := st.Pop(), st.Pop()
st.Push(stack.NewNumberValue(float32(int(x.GetNum()) ^ int(y.GetNum()))))
return false
}, // end operator functions
},
// end operator functions

// IO functions
"print": func(st stack.Stack) bool {
st.Expect(stack.Any)
fmt.Print(st.Pop().GetAny())
Expand All @@ -120,4 +127,26 @@ var stdfn = map[string]func(st stack.Stack) bool{
fmt.Printf("%v\n", st.Pop().GetAny())
return false
},
"readNumber": func(st stack.Stack) bool {
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
if err := scanner.Err(); err != nil {
return true
}

if num, err := strconv.ParseFloat(scanner.Text(), 32); err != nil {
return true
} else {
st.Push(stack.NewNumberValue(float32(num)))
}

return false
},
// end IO functions

"strip": func(st stack.Stack) bool {
st.Expect(stack.String)
st.Push(stack.NewStringValue(strings.TrimSpace(st.Pop().GetString())))
return false
},
}
1 change: 1 addition & 0 deletions velvet/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ func (vm VelvetVM) Run(bytes []uint8) error {
vars []stack.StackValue
dataAddr int
errFlag bool
// errReg string // might be used to hold the error message from functions that errored out
)

if _vars, _dataAddr, ok := vm.VerifyBytecode(bytes); !ok {
Expand Down

0 comments on commit 2fe4ab7

Please sign in to comment.