Skip to content

Instantly share code, notes, and snippets.

@ovechkin-dm
Last active July 11, 2021 19:53
Show Gist options
  • Save ovechkin-dm/6bed684db43d64a948440c96c137b08e to your computer and use it in GitHub Desktop.
Save ovechkin-dm/6bed684db43d64a948440c96c137b08e to your computer and use it in GitHub Desktop.
Gofuck
package main
import (
"bufio"
"errors"
"fmt"
"io"
"strings"
)
type State struct {
mem []byte
pos int
r io.Reader
}
type Op func(*State) error
func Right(state *State) error {
state.pos += 1
if state.pos >= len(state.mem) {
return errors.New("out of bounds")
}
return nil
}
func Left(state *State) error {
state.pos -= 1
if state.pos < 0 {
return errors.New("out of bounds")
}
return nil
}
func Print(state *State) error {
fmt.Print(string(state.mem[state.pos]))
return nil
}
func Read(state *State) error {
b := make([]byte, 1)
_, err := state.r.Read(b)
if err == io.EOF {
return nil
}
state.mem[state.pos] = b[0]
return err
}
func Plus(state *State) error {
state.mem[state.pos]++
return nil
}
func Minus(state *State) error {
state.mem[state.pos]--
return nil
}
type MyBufferedReader struct {
buf []byte
underlying io.Reader
pos int
}
func (r *MyBufferedReader) ReadToken() (byte, error) {
if r.pos < len(r.buf) {
result := r.buf[r.pos]
r.pos++
return result, nil
}
token := make([]byte, 1)
_, err := r.underlying.Read(token)
if err != nil {
return 0, err
}
r.pos++
r.buf = append(r.buf, token[0])
return token[0], nil
}
type MyStack struct {
data []*StackContext
}
type StackContext struct {
pos int
condition bool
root bool
}
func (s *MyStack) pop() *StackContext {
elem := s.data[len(s.data)-1]
s.data = s.data[:len(s.data)-1]
return elem
}
func (s *MyStack) push(ctx *StackContext) {
s.data = append(s.data, ctx)
}
func (s *MyStack) get() (*StackContext, error) {
if s.len() == 0 {
return nil, errors.New("stack is empty")
}
return s.data[len(s.data)-1], nil
}
func (s *MyStack) len() int {
return len(s.data)
}
func Exec(reader *MyBufferedReader, state *State, ops map[string]Op) error {
stack := MyStack{
data: make([]*StackContext, 0),
}
root := &StackContext{
pos: 0,
condition: true,
root: true,
}
stack.push(root)
for {
token, err := reader.ReadToken()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
tok := string(token)
err = validate(tok, ops)
if err != nil {
return err
}
c, err := stack.get()
if err != nil {
return err
}
if tok == "]" {
if c.root {
return errors.New("unexpected ]")
}
if state.mem[state.pos] != 0 {
reader.pos = c.pos - 1
}
_ = stack.pop()
} else if tok == "[" {
ctx := StackContext{
pos: reader.pos,
condition: state.mem[state.pos] != 0,
root: false,
}
stack.push(&ctx)
} else {
if !c.condition {
continue
}
op, ok := ops[tok]
if !ok {
continue
}
err = op(state)
if err != nil {
return err
}
}
}
}
func validate(tok string, ops map[string]Op) error {
//TODO: actually validate!
return nil
}
func Run(reader io.Reader, input io.Reader) error {
r := MyBufferedReader{
buf: make([]byte, 0),
underlying: reader,
pos: 0,
}
state := State{
mem: make([]byte, 30000),
pos: 0,
r: input,
}
ops := make(map[string]Op)
ops["+"] = Plus
ops["-"] = Minus
ops[">"] = Right
ops["<"] = Left
ops["."] = Print
ops[","] = Read
err := Exec(&r, &state, ops)
return err
}
func main() {
//prog := "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.+++++++++++++++++++++++++++++.+++++++..+++.-------------------------------------------------------------------------------.+++++++++++++++++++++++++++++++++++++++++++++++++++++++.++++++++++++++++++++++++.+++.------.--------.-------------------------------------------------------------------.-----------------------."
//prog := "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."
prog := ">>>+>>>>>+>>+>>+[<<],[\n -[-[-[-[-[-[-[-[<+>-[>+<-[>-<-[-[-[<++[<++++++>-]<\n [>>[-<]<[>]<-]>>[<+>-[<->[-]]]]]]]]]]]]]]]]\n <[-<<[-]+>]<<[>>>>>>+<<<<<<-]>[>]>>>>>>>+>[\n <+[\n >+++++++++<-[>-<-]++>[<+++++++>-[<->-]+[+>>>>>>]]\n <[>+<-]>[>>>>>++>[-]]+<\n ]>[-<<<<<<]>>>>\n ],\n ]+<++>>>[[+++++>>>>>>]<+>+[[<++++++++>-]<.<<<<<]>>>>>>>>]"
input := "test1 test2\ntest3 tttt"
reader := bufio.NewReader(strings.NewReader(prog))
err := Run(reader, strings.NewReader(input))
if err != nil {
panic(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment