diff options
| author | Mel <einebeere@gmail.com> | 2022-08-17 00:07:35 +0000 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2022-08-17 00:07:35 +0000 |
| commit | be6cd2217b6bb1bb411d46ebd9d003dfd928af96 (patch) | |
| tree | 94e5807aae0fb65d2768adce594e245052ecf578 | |
| parent | d84c0f36afcde4e5af2907d70931de75957d5277 (diff) | |
| download | jinx-be6cd2217b6bb1bb411d46ebd9d003dfd928af96.tar.zst jinx-be6cd2217b6bb1bb411d46ebd9d003dfd928af96.zip | |
Add different "say" outputs to VM
| -rw-r--r-- | cmd/lang/main.go | 26 | ||||
| -rw-r--r-- | cmd/vm/main.go | 9 | ||||
| -rw-r--r-- | pkg/bot/cmds.go | 32 | ||||
| -rw-r--r-- | pkg/bot/output.go | 19 | ||||
| -rw-r--r-- | pkg/lang/modules/core/natives.go | 14 | ||||
| -rw-r--r-- | pkg/lang/vm/exe.go | 4 | ||||
| -rw-r--r-- | pkg/lang/vm/executor/executor.go | 2 | ||||
| -rw-r--r-- | pkg/lang/vm/output.go | 45 | ||||
| -rw-r--r-- | pkg/lang/vm/vm.go | 6 | ||||
| -rw-r--r-- | pkg/lang/vm/vm_test.go | 28 |
10 files changed, 134 insertions, 51 deletions
diff --git a/cmd/lang/main.go b/cmd/lang/main.go index f5046a7..c5c0fe6 100644 --- a/cmd/lang/main.go +++ b/cmd/lang/main.go @@ -8,6 +8,8 @@ import ( "jinx/pkg/lang/scanner" "jinx/pkg/lang/vm" "os" + "os/user" + "path" ) func main() { @@ -20,12 +22,12 @@ func main() { exit("nothing to do, either -c or -r is required") } - path := flag.Arg(0) - if path == "" { + filePath := flag.Arg(0) + if filePath == "" { exit("no file specified") } - file, err := os.Open(path) + file, err := os.Open(filePath) if err != nil { exit("could not open file: %v", err) } @@ -43,7 +45,7 @@ func main() { exit("error during parsing: %v", err) } - comp := compiler.New("program", "noone", program) + comp := compiler.New(path.Base(filePath), getUsername(), program) module, err := comp.Compile() if err != nil { exit("compilation failed: %v", err) @@ -62,18 +64,20 @@ func main() { } if *run { - vm := vm.New(module) + vm := vm.New(module, vm.NewConsoleOutput()) if err := vm.Run(); err != nil { exit("execution failed: %v", err) } + } +} - res, err := vm.GetResult() - if err != nil { - exit("could not get result: %v", err) - } - - fmt.Println(res) +func getUsername() string { + me, err := user.Current() + if err != nil { + return "unknown" } + + return me.Username } func exit(format string, args ...any) { diff --git a/cmd/vm/main.go b/cmd/vm/main.go index ecebcbf..bb8f142 100644 --- a/cmd/vm/main.go +++ b/cmd/vm/main.go @@ -91,17 +91,10 @@ func main() { } if *run { - vm := vm.New(modules.NewUnknownModule(&bc)) + vm := vm.New(modules.NewUnknownModule(&bc), vm.NewConsoleOutput()) if err := vm.Run(); err != nil { exit("execution failed: %v", err) } - - res, err := vm.GetResult() - if err != nil { - exit("could not get result: %v", err) - } - - fmt.Println(res) } } diff --git a/pkg/bot/cmds.go b/pkg/bot/cmds.go index 32b1bfe..7d451a9 100644 --- a/pkg/bot/cmds.go +++ b/pkg/bot/cmds.go @@ -36,20 +36,23 @@ func vmCmd(b *Bot, content string, msg events.Message) error { return err } - vm := vm.New(modules.NewUnknownModule(&bc)) - - if err := vm.Run(); err != nil { - return err + output := &chatOutput{ + logger: b.logger, + client: b.client, + channel: msg.ChannelID, } - res, err := vm.GetResult() - if err != nil { + vm := vm.New(modules.NewUnknownModule(&bc), output) + + b.logger.Info().Msgf("executing vm bytecode from user %s...", msg.Author.Username) + + if err := vm.Run(); err != nil { return err } b.logger.Debug().Msg("executed code") - return b.client.SendMessage(msg.ChannelID, res) + return nil } func langCmd(b *Bot, content string, msg events.Message) error { @@ -81,20 +84,21 @@ func langCmd(b *Bot, content string, msg events.Message) error { b.client.SendMessage(msg.ChannelID, fmt.Sprintf("resulting decompiled bytecode:\n```\n%s\n```", decompRes)) - vm := vm.New(module) + output := &chatOutput{ + logger: b.logger, + client: b.client, + channel: msg.ChannelID, + } + vm := vm.New(module, output) + b.logger.Info().Msgf("executing code from user %s...", msg.Author.Username) b.client.SendMessage(msg.ChannelID, "executing code...") if err := vm.Run(); err != nil { return err } - res, err := vm.GetResult() - if err != nil { - return err - } - b.logger.Debug().Msg("executed code") - return b.client.SendMessage(msg.ChannelID, res) + return nil } diff --git a/pkg/bot/output.go b/pkg/bot/output.go new file mode 100644 index 0000000..d29a625 --- /dev/null +++ b/pkg/bot/output.go @@ -0,0 +1,19 @@ +package bot + +import ( + "jinx/pkg/discord" + "jinx/pkg/discord/entities" + + "github.com/rs/zerolog" +) + +type chatOutput struct { + logger *zerolog.Logger + client *discord.Discord + channel entities.Snowflake +} + +func (c *chatOutput) Write(p string) error { + c.logger.Info().Msgf("writing lang output: %s", p) + return c.client.SendMessage(c.channel, p) +} diff --git a/pkg/lang/modules/core/natives.go b/pkg/lang/modules/core/natives.go index c06b35c..8a24663 100644 --- a/pkg/lang/modules/core/natives.go +++ b/pkg/lang/modules/core/natives.go @@ -116,13 +116,21 @@ var Natives = []any{ n(":core:say", 1, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { message := args[0] - s, err := message.Data().String(exe.Mem()) + + // We don't want strings to have the "". + var err error + var s string + if message.Type() == value.StringType { + s, err = message.Data().(value.StringData).RawString(exe.Mem()) + } else { + s, err = message.Data().String(exe.Mem()) + } + if err != nil { return value.Value{}, err } - fmt.Println(s) - return value.Value{}, nil + return value.Value{}, exe.Write(s) }), } diff --git a/pkg/lang/vm/exe.go b/pkg/lang/vm/exe.go index 7d6fc61..5d40133 100644 --- a/pkg/lang/vm/exe.go +++ b/pkg/lang/vm/exe.go @@ -60,3 +60,7 @@ func (vm *VM) GetGlobal(name string) (value.Value, bool, error) { return v, true, nil } + +func (vm *VM) Write(message string) error { + return vm.output.Write(message) +} diff --git a/pkg/lang/vm/executor/executor.go b/pkg/lang/vm/executor/executor.go index 0b7ccef..1ab3773 100644 --- a/pkg/lang/vm/executor/executor.go +++ b/pkg/lang/vm/executor/executor.go @@ -14,4 +14,6 @@ type Exectutor interface { AddGlobal(name string, v value.Value) error GetGlobal(name string) (value.Value, bool, error) + + Write(message string) error } diff --git a/pkg/lang/vm/output.go b/pkg/lang/vm/output.go new file mode 100644 index 0000000..1ef2357 --- /dev/null +++ b/pkg/lang/vm/output.go @@ -0,0 +1,45 @@ +package vm + +type Output interface { + Write(message string) error +} + +type EmptyOutput struct{} + +func NewEmptyOutput() *EmptyOutput { + return &EmptyOutput{} +} + +func (o *EmptyOutput) Write(message string) error { + return nil +} + +type GatheringOutput struct { + messages []string +} + +func NewGatheringOutput() *GatheringOutput { + return &GatheringOutput{ + messages: make([]string, 0, 8), + } +} + +func (o *GatheringOutput) Messages() []string { + return o.messages +} + +func (o *GatheringOutput) Write(message string) error { + o.messages = append(o.messages, message) + return nil +} + +type ConsoleOutput struct{} + +func NewConsoleOutput() *ConsoleOutput { + return &ConsoleOutput{} +} + +func (o *ConsoleOutput) Write(message string) error { + println(message) + return nil +} diff --git a/pkg/lang/vm/vm.go b/pkg/lang/vm/vm.go index f24095d..4d4d5ca 100644 --- a/pkg/lang/vm/vm.go +++ b/pkg/lang/vm/vm.go @@ -21,9 +21,11 @@ type VM struct { globals map[string]mem.Ptr corePtrs value.CorePtrs + + output Output } -func New(main modules.Module) *VM { +func New(main modules.Module, output Output) *VM { vm := &VM{ pos: code.NewPos(-1, 0), @@ -37,6 +39,8 @@ func New(main modules.Module) *VM { globals: make(map[string]mem.Ptr), corePtrs: value.CorePtrs{}, + + output: output, } if err := vm.setup(); err != nil { diff --git a/pkg/lang/vm/vm_test.go b/pkg/lang/vm/vm_test.go index 8f961ef..8c31d1f 100644 --- a/pkg/lang/vm/vm_test.go +++ b/pkg/lang/vm/vm_test.go @@ -5,7 +5,6 @@ import ( "jinx/pkg/lang/vm" "jinx/pkg/lang/vm/code" "jinx/pkg/lang/vm/text" - "os" "strings" "testing" @@ -496,18 +495,7 @@ func TestCoreSay(t *testing.T) { halt ` - previous := os.Stdout - r, w, _ := os.Pipe() - defer w.Close() - os.Stdout = w - test(t, src, "0") - os.Stdout = previous - - result := make([]byte, 8) - _, err := r.Read(result) - require.NoError(t, err) - - require.Equal(t, "\"Meow!!\"", string(result)) + testOutput(t, src, "Meow!!") } func TestSetAtArray(t *testing.T) { @@ -539,7 +527,7 @@ func TestSetAtArray(t *testing.T) { func test(t *testing.T, src string, expected string) { bc := compile(t, src) - vm := vm.New(modules.NewUnknownModule(&bc)) + vm := vm.New(modules.NewUnknownModule(&bc), vm.NewEmptyOutput()) err := vm.Run() require.NoError(t, err) @@ -549,6 +537,18 @@ func test(t *testing.T, src string, expected string) { require.Equal(t, expected, res) } +func testOutput(t *testing.T, src string, expected string) { + output := vm.NewGatheringOutput() + + bc := compile(t, src) + vm := vm.New(modules.NewUnknownModule(&bc), output) + err := vm.Run() + require.NoError(t, err) + + lastMessage := output.Messages()[len(output.Messages())-1] + require.Equal(t, expected, lastMessage) +} + func compile(t *testing.T, src string) code.Code { comp := text.NewCompiler(strings.NewReader(src)) bc, err := comp.Compile() |
