// Clyx programming language interpreter, Go implementation // Created by Luxferre in 2026, released into the public domain package clyx import ( "bufio" "fmt" "io" "math" "math/rand" "net" "os" "strconv" "strings" "unicode/utf8" ) var stdinReader = bufio.NewReader(os.Stdin) type ClyxFile interface { Read() (string, error) Write(string) (int, error) Close() error Accept() (ClyxFile, error) } type StdinFile struct{} func (f *StdinFile) Read() (string, error) { line, err := stdinReader.ReadString('\n'); return strings.TrimRight(line, "\r\n"), err } func (f *StdinFile) Write(string) (int, error) { return 0, nil } func (f *StdinFile) Close() error { return nil } func (f *StdinFile) Accept() (ClyxFile, error) { return nil, fmt.Errorf("not server") } type RealFile struct { f *os.File m string } func (f *RealFile) Read() (string, error) { if f.m == "r" { d, err := io.ReadAll(f.f); return strings.TrimRight(string(d), "\r\n"), err } return "", fmt.Errorf("not reading") } func (f *RealFile) Write(s string) (int, error) { return f.f.WriteString(s) } func (f *RealFile) Close() error { return f.f.Close() } func (f *RealFile) Accept() (ClyxFile, error) { return nil, fmt.Errorf("not server") } type ServerSocket struct{ l net.Listener } func (s *ServerSocket) Read() (string, error) { return "", fmt.Errorf("no read") } func (s *ServerSocket) Write(string) (int, error) { return 0, fmt.Errorf("no write") } func (s *ServerSocket) Close() error { return s.l.Close() } func (s *ServerSocket) Accept() (ClyxFile, error) { c, err := s.l.Accept() if err != nil { return nil, err } return &ClientSocket{conn: c, r: bufio.NewReader(c)}, nil } type ClientSocket struct { conn net.Conn r *bufio.Reader } func (c *ClientSocket) Read() (string, error) { line, err := c.r.ReadString('\n'); return strings.TrimRight(line, "\r\n"), err } func (c *ClientSocket) Write(s string) (int, error) { return c.conn.Write([]byte(s)) } func (c *ClientSocket) Close() error { return c.conn.Close() } func (c *ClientSocket) Accept() (ClyxFile, error) { return nil, fmt.Errorf("not server") } func toFloat(v any) float64 { if ix, ok := v.(int64); ok { return float64(ix) } if fx, ok := v.(float64); ok { return fx } return 0 } func toInt(v any) int64 { if ix, ok := v.(int64); ok { return ix } if fx, ok := v.(float64); ok { return int64(fx) } return 0 } func isFloat(v any) bool { _, ok := v.(float64); return ok } func formatFloat(v float64) string { if v == math.Floor(v) { return fmt.Sprintf("%.1f", v) }; return fmt.Sprintf("%g", v) } func repr(v any) string { switch val := v.(type) { case int64: return fmt.Sprintf("%d", val) case float64: return formatFloat(val) case string: escaped := strconv.Quote(val) if !strings.Contains(val, "'") { return "'" + escaped[1:len(escaped)-1] + "'" } return escaped case []any: var parts []string for _, item := range val { parts = append(parts, repr(item)) } return "[" + strings.Join(parts, ", ") + "]" case nil: return "None" default: return "" } } func isTruthy(v any) bool { switch val := v.(type) { case int64: return val != 0 case float64: return val != 0.0 case bool: return val case string: return val != "" case []any: return len(val) > 0 default: return val != nil } } func opDivmod(x, y any) (any, any) { if ix, okx := x.(int64); okx { if iy, oky := y.(int64); oky { if iy == 0 { panic("division by zero") } q, r := ix/iy, ix%iy if (r < 0 && iy > 0) || (r > 0 && iy < 0) { q--; r += iy } return q, r } } fx, fy := toFloat(x), toFloat(y) if fy == 0 { panic("division by zero") } q := math.Floor(fx / fy) return q, fx - q*fy } func opShl(x, f any) any { xv, fv := toInt(x), toInt(f) if fv >= 0 { return xv << fv } return xv >> (-fv) } func opPow(x, y any) any { if ix, okx := x.(int64); okx { if iy, oky := y.(int64); oky && iy >= 0 { res := int64(1) for base, exp := ix, iy; exp > 0; exp >>= 1 { if exp&1 == 1 { res *= base } base *= base } return res } } return math.Pow(toFloat(x), toFloat(y)) } func tokenize(code string) []string { var tokens []string code = strings.ReplaceAll(strings.ReplaceAll(code, "\\\\", "\x01"), "\\\"", "\x02") for _, l := range strings.Split(code, "\n") { for i, p := range strings.Split(l, "\"") { if i%2 != 0 { p = strings.ReplaceAll(strings.ReplaceAll(p, "\x02", "\""), "\x01", "\\") tokens = append(tokens, "\""+p+"\"") } else { commentIdx := strings.Index(p, "#") if commentIdx != -1 { p = p[:commentIdx] } p = strings.ReplaceAll(strings.ReplaceAll(p, "[", " [ "), "]", " ] ") tokens = append(tokens, strings.Fields(p)...) if commentIdx != -1 { break } } } } return tokens } func normToken(t string) any { if strings.Contains(t, ".") && t != "." { if f, err := strconv.ParseFloat(strings.TrimSpace(t), 64); err == nil { return f } } if i, err := strconv.ParseInt(strings.TrimSpace(t), 10, 64); err == nil { return i } if len(t) >= 2 && t[0] == '"' && t[len(t)-1] == '"' { s := t[1 : len(t)-1] s = strings.ReplaceAll(s, "\\\\", "\x01") s = strings.ReplaceAll(s, "\\n", "\n") s = strings.ReplaceAll(s, "\\t", "\t") s = strings.ReplaceAll(s, "\\r", "\r") s = strings.ReplaceAll(s, "\\s", " ") s = strings.ReplaceAll(s, "\\b", "\b") s = strings.ReplaceAll(s, "\\f", "\f") s = strings.ReplaceAll(s, "\\\"", "\"") return strings.ReplaceAll(s, "\x01", "\\") } return t } func parseQuot(tokens *[]any) ([]any, error) { var quot []any for { if len(*tokens) == 0 { return nil, fmt.Errorf("Syntax error: unbalanced brackets") } t := (*tokens)[0] *tokens = (*tokens)[1:] if s, ok := t.(string); ok && s == "]" { return quot, nil } if s, ok := t.(string); ok && s == "[" { sub, err := parseQuot(tokens) if err != nil { return nil, err } quot = append(quot, sub) } else { if s, ok := t.(string); ok { quot = append(quot, normToken(s)) } else { quot = append(quot, t) } } } } func toAnySlice(strs []string) []any { res := make([]any, len(strs)) for i, s := range strs { res[i] = s } return res } type Clyx struct { stack []any tokens []any tokenStreams [][]any words map[string]any } func (c *Clyx) pop() any { if len(c.stack) == 0 { panic("stack underflow") } val := c.stack[len(c.stack)-1] c.stack = c.stack[:len(c.stack)-1] return val } func (c *Clyx) reprStack() string { var parts []string for _, item := range c.stack { parts = append(parts, repr(item)) } return "[" + strings.Join(parts, ", ") + "]" } func (c *Clyx) execQuot(q []any) { c.tokenStreams = append(c.tokenStreams, c.tokens) c.tokens = make([]any, len(q)) copy(c.tokens, q) for len(c.tokens) > 0 { t := c.tokens[0] c.tokens = c.tokens[1:] if listVal, ok := t.([]any); ok { c.stack = append(c.stack, listVal) } else if s, ok := t.(string); ok && s == "[" { qParsed, err := parseQuot(&c.tokens) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err); break } c.stack = append(c.stack, qParsed) } else { normT := t if s, ok := t.(string); ok { normT = normToken(s) } var v any var isWord bool if sNorm, ok := normT.(string); ok { v, isWord = c.words[sNorm] } if isWord { switch val := v.(type) { case func(): val() case []any: c.execQuot(val) default: c.stack = append(c.stack, val) } } else { c.stack = append(c.stack, normT) } } } c.tokens = c.tokenStreams[len(c.tokenStreams)-1] c.tokenStreams = c.tokenStreams[:len(c.tokenStreams)-1] } func (c *Clyx) popCallerToken() any { var stream *[]any if len(c.tokenStreams) > 0 { stream = &c.tokenStreams[len(c.tokenStreams)-1] } else { stream = &c.tokens } if len(*stream) == 0 { return nil } t := (*stream)[0] *stream = (*stream)[1:] if s, ok := t.(string); ok && s == "[" { qParsed, err := parseQuot(stream) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err); return nil } return qParsed } return t } func (c *Clyx) cmdDefw() { var stream *[]any if len(c.tokenStreams) > 0 { stream = &c.tokenStreams[len(c.tokenStreams)-1] } else { stream = &c.tokens } var val any if len(*stream) > 0 { t0 := (*stream)[0] isQuot := false if s, ok := t0.(string); ok && s == "[" { isQuot = true } else if _, ok := t0.([]any); ok { isQuot = true } if isQuot { val = c.popCallerToken() } } if val == nil { val = c.pop() } name := c.pop().(string) c.words[name] = val } func (c *Clyx) cmdType() { val := c.stack[len(c.stack)-1] var t int64 = 0 switch val.(type) { case []any: t = 2 case string: t = 1 } c.stack = append(c.stack, t) } func (c *Clyx) Run(code string) { c.execQuot(toAnySlice(tokenize(code))) } func (c *Clyx) Eval(q any) { defer func() { if r := recover(); r != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", r) } }() if s, ok := q.(string); ok { c.execQuot(toAnySlice(tokenize(s))) } else if slice, ok := q.([]any); ok { c.execQuot(slice) } else { panic("eval expects string/quotation") } } func (c *Clyx) HasWord(name string) bool { _, ok := c.words[name] return ok } func printVal(v any) { switch val := v.(type) { case int64: fmt.Printf("%d\n", val) case float64: fmt.Println(formatFloat(val)) case string: fmt.Println(val) case []any: fmt.Println(repr(val)) case nil: fmt.Println("None") default: fmt.Printf("%v\n", val) } } func NewClyx(libfname string, libCode string) *Clyx { c := &Clyx{ words: make(map[string]any), } c.words["dup"] = func() { c.stack = append(c.stack, c.stack[len(c.stack)-1]) } c.words["drop"] = func() { c.pop() } c.words["swap"] = func() { v1, v2 := c.pop(), c.pop(); c.stack = append(c.stack, v1, v2) } c.words["i"] = func() { c.Eval(c.pop()) } c.words["cond"] = func() { cVal, tVal, fVal := c.pop(), c.pop(), c.pop() runVal := fVal if isTruthy(cVal) { runVal = tVal } if listVal, ok := runVal.([]any); ok { c.execQuot(listVal) } else { c.execQuot([]any{runVal}) } } c.words["cons"] = func() { q, x := c.pop().([]any), c.pop(); c.stack = append(c.stack, append([]any{x}, q...)) } c.words["uncons"] = func() { qVal := c.pop() var l []any if s, ok := qVal.(string); ok { l = make([]any, len(s)) for i := 0; i < len(s); i++ { l[i] = int64(s[i]) } } else { l = qVal.([]any) } if len(l) == 0 { c.stack = append(c.stack, l, int64(0)) } else { c.stack = append(c.stack, l[1:], l[0], int64(1)) } } c.words["qpop"] = func() { q := c.pop().([]any); c.stack = append(c.stack, q[:len(q)-1], q[len(q)-1]) } c.words["qlen"] = func() { if l, ok := c.pop().([]any); ok { c.stack = append(c.stack, int64(len(l))) } else { c.stack = append(c.stack, int64(0)) } } c.words["qget"] = func() { idx, v := toInt(c.pop()), c.pop(); if l, ok := v.([]any); ok && idx >= 0 && idx < int64(len(l)) { c.stack = append(c.stack, l[idx]) } else { c.stack = append(c.stack, nil) } } c.words["qset"] = func() { idx, v, x := toInt(c.pop()), c.pop(), c.pop(); if l, ok := v.([]any); ok && idx >= 0 && idx < int64(len(l)) { l[idx] = x; c.stack = append(c.stack, l) } else { c.stack = append(c.stack, nil) } } c.words["slen"] = func() { if s, ok := c.pop().(string); ok { c.stack = append(c.stack, int64(utf8.RuneCountInString(s))) } else { c.stack = append(c.stack, int64(0)) } } c.words["+"] = func() { y, x := c.pop(), c.pop() if yL, okY := y.([]any); okY { if xL, okX := x.([]any); okX { c.stack = append(c.stack, append(yL, xL...)); return } } if yS, okY := y.(string); okY { if xS, okX := x.(string); okX { c.stack = append(c.stack, yS+xS); return } } if isFloat(y) || isFloat(x) { c.stack = append(c.stack, toFloat(y)+toFloat(x)) } else { c.stack = append(c.stack, toInt(y)+toInt(x)) } } c.words["*"] = func() { y, x := c.pop(), c.pop() if yS, okY := y.(string); okY { if xI, okX := x.(int64); okX { if xI < 0 { xI = 0 }; c.stack = append(c.stack, strings.Repeat(yS, int(xI))); return } } if xS, okX := x.(string); okX { if yI, okY := y.(int64); okY { if yI < 0 { yI = 0 }; c.stack = append(c.stack, strings.Repeat(xS, int(yI))); return } } if yL, okY := y.([]any); okY { if xI, okX := x.(int64); okX { if xI < 0 { xI = 0 }; var res []any; for i := int64(0); i < xI; i++ { res = append(res, yL...) }; c.stack = append(c.stack, res); return } } if xL, okX := x.([]any); okX { if yI, okY := y.(int64); okY { if yI < 0 { yI = 0 }; var res []any; for i := int64(0); i < yI; i++ { res = append(res, xL...) }; c.stack = append(c.stack, res); return } } if isFloat(y) || isFloat(x) { c.stack = append(c.stack, toFloat(y)*toFloat(x)) } else { c.stack = append(c.stack, toInt(y)*toInt(x)) } } c.words["-"] = func() { y, x := c.pop(), c.pop(); if isFloat(y) || isFloat(x) { c.stack = append(c.stack, toFloat(x)-toFloat(y)) } else { c.stack = append(c.stack, toInt(x)-toInt(y)) } } c.words["/"] = func() { y, x := c.pop(), c.pop(); c.stack = append(c.stack, toFloat(x)/toFloat(y)) } c.words["divmod"] = func() { y, x := c.pop(), c.pop(); q, r := opDivmod(x, y); c.stack = append(c.stack, q, r) } c.words["shl"] = func() { f, x := c.pop(), c.pop(); c.stack = append(c.stack, opShl(x, f)) } c.words["^"] = func() { y, x := c.pop(), c.pop(); c.stack = append(c.stack, opPow(x, y)) } c.words["0="] = func() { v := c.pop(); if v == int64(0) || v == 0.0 { c.stack = append(c.stack, int64(1)) } else { c.stack = append(c.stack, int64(0)) } } c.words["0<"] = func() { v := c.pop(); isNeg := false; if ix, ok := v.(int64); ok { isNeg = ix < 0 } else if fx, ok := v.(float64); ok { isNeg = fx < 0 }; if isNeg { c.stack = append(c.stack, int64(1)) } else { c.stack = append(c.stack, int64(0)) } } c.words["nand"] = func() { y, x := c.pop(), c.pop(); c.stack = append(c.stack, ^(toInt(x) & toInt(y))) } c.words["defw"] = func() { c.cmdDefw() } c.words["type"] = func() { c.cmdType() } c.words["next"] = func() { c.stack = append(c.stack, c.popCallerToken()) } c.words["."] = func() { printVal(c.pop()) } c.words["emit"] = func() { fmt.Printf("%c", rune(toInt(c.pop()))) } c.words["fopen"] = func() { mode, fileVal := c.pop().(string), c.pop() isStdin := false if ix, ok := fileVal.(int64); ok && ix == 0 { isStdin = true } else if sx, ok := fileVal.(string); ok && sx == "0" { isStdin = true } if isStdin { c.stack = append(c.stack, &StdinFile{}) } else { var file *os.File var err error if mode == "r" { file, err = os.Open(fileVal.(string)) } else if mode == "w" { file, err = os.Create(fileVal.(string)) } else if mode == "a" { file, err = os.OpenFile(fileVal.(string), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) } if err != nil { panic(err) } c.stack = append(c.stack, &RealFile{f: file, m: mode}) } } c.words["nopen"] = func() { portStr, host := fmt.Sprintf("%v", c.pop()), c.pop().(string) if host == "0.0.0.0" { l, err := net.Listen("tcp", host+":"+portStr) if err != nil { panic(err) } c.stack = append(c.stack, &ServerSocket{l: l}) } else { conn, err := net.Dial("tcp", host+":"+portStr) if err != nil { panic(err) } c.stack = append(c.stack, &ClientSocket{conn: conn, r: bufio.NewReader(conn)}) } } c.words["write"] = func() { data, fd := c.pop(), c.pop() var toWrite string if listVal, ok := data.([]any); ok { var sb strings.Builder for _, val := range listVal { sb.WriteByte(byte(toInt(val))) } toWrite = sb.String() } else if strVal, ok := data.(string); ok { toWrite = strVal } else { panic("write expects string or list") } n, err := fd.(ClyxFile).Write(toWrite) if err != nil { panic(err) } c.stack = append(c.stack, int64(n)) } c.words["read"] = func() { fd := c.pop().(ClyxFile) if srv, ok := fd.(*ServerSocket); ok { client, err := srv.Accept() if err != nil { panic(err) } c.stack = append(c.stack, client) } else { res, err := fd.Read() if err != nil { panic(err) } var list []any for i := 0; i < len(res); i++ { list = append(list, int64(res[i])) } c.stack = append(c.stack, list) } } c.words["close"] = func() { if fd, ok := c.pop().(ClyxFile); ok { fd.Close() } } c.words["delf"] = func() { if err := os.Remove(c.pop().(string)); err != nil { panic(err) } } c.words["maked"] = func() { if err := os.Mkdir(c.pop().(string), 0755); err != nil { panic(err) } } c.words["listd"] = func() { entries, err := os.ReadDir(c.pop().(string)); if err != nil { panic(err) }; var names []any; for _, entry := range entries { names = append(names, entry.Name()) }; c.stack = append(c.stack, names) } c.words["deld"] = func() { if err := os.Remove(c.pop().(string)); err != nil { panic(err) } } c.words["rand"] = func() { limit := toInt(c.pop()); if limit <= 0 { c.stack = append(c.stack, int64(0)) } else { c.stack = append(c.stack, rand.Int63n(limit)) } } c.words[".s"] = func() { printVal(c.reprStack()) } c.words["dip"] = func() { q, y := c.pop().([]any), c.pop(); c.execQuot(q); c.stack = append(c.stack, y) } c.words["loop"] = func() { body, cond := c.pop().([]any), c.pop().([]any); for { c.execQuot(cond); if !isTruthy(c.pop()) { break }; c.execQuot(body) } } c.words["hsargs"] = func() { c.stack = append(c.stack, toAnySlice(os.Args)) } c.words["hsexit"] = func() { os.Exit(int(toInt(c.pop()))) } c.words["l2s"] = func() { l := c.pop().([]any) var sb strings.Builder for _, val := range l { sb.WriteByte(byte(toInt(val))) } c.stack = append(c.stack, sb.String()) } c.words["hseval"] = func() { fmt.Fprintln(os.Stderr, "Error: unsupported word"); os.Exit(1) } c.words["chr"] = func() { c.stack = append(c.stack, string(rune(toInt(c.pop())))) } regMath := func(name string, f func(float64) float64) { c.words[name] = func() { c.stack = append(c.stack, f(toFloat(c.pop()))) } } regMath("sin", math.Sin) regMath("cos", math.Cos) regMath("atan", math.Atan) regMath("exp", math.Exp) regMath("log", math.Log) c.Run(`"::" [ next defw ] defw :: readf [ "r" fopen dup read swap close ] :: src [ readf l2s i ]`) if libfname == "" { c.Run(libCode) } else { c.Run(fmt.Sprintf(`"%s" src`, libfname)) } return c } func RunFile(filePath string, libCode string) { content, err := os.ReadFile(filePath) if err != nil { fmt.Fprintf(os.Stderr, "Error executing %s: %v\n", filePath, err) os.Exit(1) } defer func() { if r := recover(); r != nil { fmt.Fprintf(os.Stderr, "Error executing %s: %v\n", filePath, r); os.Exit(1) } }() c := NewClyx("", libCode) c.Run(string(content)) if c.HasWord("_main") { c.Run("_main") } }